1. 项目背景与技术选型
果蔬到家这类生鲜电商平台在近几年呈现爆发式增长,特别是在疫情后,线上购买水果蔬菜已成为城市家庭的日常习惯。我们团队决定开发一个全栈式的果蔬商城应用,包含APP、小程序和Web端,以满足不同用户群体的需求。
在技术选型上,我们采用了以下方案:
- 前端:Vue.js 3 + Vant UI
- 后端:Node.js + Koa2
- 数据库:MySQL + Redis
- 小程序:原生微信小程序 + Taro框架
这个技术栈组合主要基于以下考虑:
-
Vue.js的渐进式特性非常适合电商这类交互复杂的应用,其响应式系统和组件化开发能显著提升开发效率。我们选择Vant UI是因为它提供了丰富的移动端组件,特别适合商品展示、购物车等电商场景。
-
Node.js作为后端服务有几个优势:首先,JavaScript全栈开发可以降低团队技术栈复杂度;其次,Node.js的非阻塞I/O模型很适合电商这类I/O密集型的应用;最后,丰富的npm生态可以快速集成支付、短信等各种第三方服务。
-
使用Taro框架可以实现小程序代码与H5的复用,大大减少了多端开发的工作量。实测显示,业务逻辑代码的复用率能达到70%以上。
2. 项目架构设计
2.1 整体架构
项目采用典型的前后端分离架构:
code复制├── 前端项目
│ ├── web (Vue3 + Vant)
│ └── mini-program (Taro)
├── 后端服务
│ ├── api-service (主业务逻辑)
│ ├── admin-service (管理后台)
│ └── job-service (定时任务)
├── 基础设施
│ ├── MySQL (主库+从库)
│ └── Redis (缓存+会话)
2.2 数据库设计
核心表结构设计要点:
-
商品系统采用SPU+SKU模型:
- spu表存储商品基本信息(名称、描述、分类等)
- sku表存储具体规格(如500g装、1kg装等)
- 特别设计了fresh_degree字段表示新鲜度,这是生鲜电商的特色
-
订单系统考虑生鲜商品的特殊性:
- 增加了expected_delivery_time预计送达时间
- 设计了refund_policy退款策略字段
- 订单状态机比普通电商更复杂,包含"配送中"、"已送达待确认"等状态
-
库存系统实现:
- 采用Redis预扣库存+MySQL最终一致的方案
- 特别处理了生鲜商品的日结库存机制
- 实现了库存预警功能
3. 核心功能实现
3.1 商品展示与搜索
生鲜商品展示有几个特殊需求:
-
新鲜度标识:我们在商品卡片上设计了明显的保鲜期提示,使用颜色区分(绿色代表当天新到货,黄色代表次日将下架)
-
智能推荐算法:
javascript复制// 基于用户历史购买记录的推荐逻辑
function getRecommendations(userId) {
// 1. 获取用户常买品类
const favCategories = await getUserFavorites(userId);
// 2. 结合时令因素调整权重
const seasonAdjustment = getSeasonFactor();
// 3. 排除用户明确不喜欢的商品
const blacklist = getUserBlacklist(userId);
// 4. 综合排序返回结果
return finalRecommendations;
}
- 搜索功能优化:
- 针对生鲜商品特点,增加了"当季热销"、"有机专区"等筛选条件
- 实现拼音搜索功能,方便用户输入
- 搜索结果按新鲜度+销量综合排序
3.2 购物车与下单流程
生鲜电商的购物车有特殊逻辑:
-
商品有效性检查:
- 加入购物车时检查库存
- 下单前再次确认库存和价格
- 对临期商品给出明确提示
-
配送时间选择:
javascript复制// 配送时段计算逻辑
function getDeliveryTimeSlots() {
const now = new Date();
const currentHour = now.getHours();
// 生鲜配送一般分三个时段
if (currentHour < 10) {
return ['11:00-13:00', '13:00-15:00', '15:00-18:00'];
} else if (currentHour < 14) {
return ['15:00-18:00', '18:00-21:00'];
} else {
return ['次日11:00-13:00'];
}
}
- 订单创建流程:
- 预扣库存
- 生成订单号(包含日期和业务类型标识)
- 分配配送员
- 发送订单确认通知
4. 关键技术实现
4.1 微信小程序登录集成
小程序登录流程优化:
-
传统方案的问题:
- 每次打开小程序都需要重新登录
- 用户信息获取流程复杂
-
我们的优化方案:
javascript复制// 改进后的登录逻辑
async function wxLogin() {
try {
// 1. 检查本地是否有有效token
const token = storage.get('token');
if (token && await checkTokenValid(token)) {
return token;
}
// 2. 微信静默登录获取code
const { code } = await wx.login();
// 3. 后端交换openid和session
const { token } = await api.loginByWechat(code);
// 4. 存储token并返回
storage.set('token', token);
return token;
} catch (err) {
console.error('登录失败', err);
throw err;
}
}
4.2 高并发库存控制
生鲜商品的秒杀场景需要特殊处理:
-
解决方案:
- Redis原子计数器预扣减
- 异步队列处理实际库存变更
- 定期对账保证数据一致性
-
核心代码:
javascript复制// 库存扣减逻辑
async function deductStock(productId, quantity) {
const redisKey = `stock:${productId}`;
// 使用Redis的原子操作
const remaining = await redis.decrby(redisKey, quantity);
if (remaining < 0) {
// 库存不足,回滚
await redis.incrby(redisKey, quantity);
throw new Error('库存不足');
}
// 发送消息到队列异步处理数据库
await mq.send({
type: 'stock_deduction',
productId,
quantity
});
return true;
}
4.3 实时配送追踪
我们实现了配送员实时位置更新功能:
-
技术方案:
- 小程序端每15秒上报位置
- WebSocket推送位置信息给用户
- 地理围栏触发状态变更
-
性能优化点:
- 位置信息使用GeoHash编码存储
- 采用增量更新策略
- 客户端做轨迹平滑处理
5. 项目部署与优化
5.1 性能优化实践
-
前端优化:
- 图片懒加载和WebP格式转换
- 组件级代码分割
- 关键路径资源预加载
-
后端优化:
- 接口响应缓存
- 数据库查询优化
- 热点数据Redis缓存
-
小程序优化:
- 分包加载策略
- 减少setData调用
- 使用自定义组件
5.2 监控与运维
我们建立了完整的监控体系:
-
前端监控:
- 使用Sentry捕获错误
- 性能指标采集
- 用户行为分析
-
后端监控:
- 接口性能监控
- 异常报警
- 日志集中管理
-
业务监控:
- 订单异常检测
- 库存预警
- 配送超时监控
6. 开发经验与教训
在实际开发中,我们积累了一些宝贵经验:
-
生鲜商品管理的特殊性:
- 必须建立严格的商品上下架流程
- 需要设计灵活的定价策略
- 库存管理要考虑损耗率
-
配送环节的注意事项:
- 配送区域要精确到小区级别
- 要考虑天气因素的影响
- 建立完善的异常处理流程
-
技术上的经验:
- 小程序分包大小要严格控制
- 地理位置服务要考虑iOS/Android差异
- 支付接口要做充分的异常处理
这个项目从零开始到上线共耗时4个月,目前日均订单量超过2000单,系统运行稳定。最大的收获是深入理解了生鲜电商与传统电商在技术和业务上的差异,特别是在库存管理、配送时效等方面的特殊需求。
