ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Vue+Node.js+微信小程序校园跑腿点餐系统全栈开发实战

Vue+Node.js+微信小程序校园跑腿点餐系统全栈开发实战 几周前帮朋友捣鼓了一个校园跑腿点餐的小项目前后端加小程序端折腾了大概三天。最近后台数据涨得不错顺手把整套实现思路整理出来。这篇文章不会讲太多花哨的架构设计全是实际能跑通的代码路径和踩坑记录希望对正在做类似毕业设计或者个人项目的朋友有帮助。这个项目说白了就是三件事小程序端给用户点餐Vue后台给商家管菜单和订单Node.js做中间的数据中转和业务处理。说真的这套组合在目前的个人项目和中小型公司里太常见了因为每一环都有大量成熟方案可以抄组合起来又没有什么明显的硬伤。如果你正准备做网上订餐类的系统或者手头有个小程序项目不知道怎么管理后台这篇文章可以当作一份完整的地图来参考。就算你不是做订餐的里面关于VueNode.js小程序的配合方式、鉴权思路、订单状态机设计也能直接搬到其他业务场景。1. 项目整体设计与技术选型思路1.1 为什么是 Vue Node.js 小程序 这套组合先说选型。我之前也纠结过要不要用Java后端加Vue全家桶后来发现Node.js的优势在这个项目里特别明显前后端都是JavaScript数据格式自然就是JSON完全不需要做任何序列化转换。这对于快速开发太关键了尤其是订单、菜品这类嵌套结构比较多的数据用JavaScript对象直接传递省掉了一大堆DTO转换的样板代码。Vue这边我选的是Vue 2 Element UI没上Vue 3原因很简单Element UI对Vue 2的支持最成熟网上案例最多遇到问题一搜就有答案。对个人项目来说能快速解决问题比用什么新特性更重要。当然如果你打算长期维护Vue 3 Element Plus也不差API更现代类型推导更好但开发效率上提升不大。小程序端就是微信原生小程序没有用uni-app或者Taro。原因是这个项目的页面结构比较简单就一个点餐首页、商品详情、购物车、订单列这几个页面原生的写法完全够用。而且原生小程序调试起来最方便而且踩坑资料最多没必要引入一层跨端框架增加心智负担。1.2 系统整体架构与模块划分整个系统分成三部分对应三个独立的项目工程小程序端用户下单入口负责菜单浏览、商品加购、下单支付、订单查询Vue管理后台商家运营入口负责菜品管理、订单处理、配送状态更新Node.js后端提供RESTful API负责用户身份认证、订单业务逻辑、数据持久化这三者之间的数据流向是小程序调用后端接口后端操作数据库Vue后台也调用后端接口。后端是整个系统的核心枢纽所有业务逻辑都收敛在这里。数据库我选了MySQL没有上MongoDB。客观讲订单这类事务性强的数据确实需要关系型数据库来保证一致性。虽然MongoDB在开发时不用建表很爽但后面做订单统计、按时间查询这些需求时SQL的灵活性和性能都不错。项目早期用MySQL长期维护也放心。1.3 开发环境准备的三个关键坑环境配置这一节我放在最前面讲因为估计有很多人卡在这一步。这几个问题我在配环境时几乎全踩了一遍而且群里也有不少朋友反复问。第一个坑Node.js版本选择。我刚开始装的是最新的Node.js 20结果发现有些老项目跑不起来。后来看了下npm官方支持说明果断换成了Node.js 16 LTS版本。对于个人项目尽量选LTS版本不要追新因为很多依赖包还没有适配最新版折腾半天都是依赖兼容问题。第二个坑npm权限问题。Windows系统上经常遇到“npm无法加载文件npm.ps1因为在此系统上禁止运行脚本”的报错这其实是PowerShell执行策略的限制。解决方案是以管理员身份打开PowerShell运行Set-ExecutionPolicy RemoteSigned命令然后选择“Y”确认。这个问题在Windows下太典型了几乎每个用npm的人都会遇到。第三个坑微信小程序开发者工具的AppID。注册小程序需要企业资质或个人资质如果没有AppID可以使用测试号。用测试号有很多限制比如不能使用微信支付所以如果是要做完整系统建议提前申请好AppID。我在开发初期为了省事儿用的测试号结果后面做支付联调时又得重新配置白白浪费了一些时间。1.4 Vue后台管理端的脚手架选择Vue后台我用的vue-element-admin这个开源模板准确说是基于它的精简版。这个框架网上一抓一大把用来做后台管理非常顺手已经集成了登录、权限验证、动态路由、面包屑、标签页这些常用功能比自己从零开始搭要快太多了。不过要注意的是vue-element-admin本身集成的功能很多直接拿来用会有很多用不上的模块我当时就花了一晚上做减法把不相关的页面删掉只保留登录、Dashboard、商品管理、订单管理这几个核心模块。做减法这步一定不能省否则后台页面会非常臃肿自己后面维护也会很累。2. 数据库设计订单系统的地基2.1 核心数据表结构详解订餐系统的数据库设计是整个项目最需要动脑子的部分。我先梳理一下实体关系用户要能下单商家要能管理菜品每个菜品要归属于某个商家订单要有菜品明细订单还要有配送地址和状态变化记录。我设计了以下这几张核心表users用户表id主键自增openid微信openid唯一索引nickname用户昵称avatar头像URLphone手机号create_time创建时间restaurants商家表id主键name店名address地址logo店铺logostatus营业状态0打烊1营业notice公告信息dishes菜品表id主键restaurant_id所属商家ID外键name菜名price价格用Decimal(10,2)image图片URLcategory分类如热菜、凉菜、饮品status上架状态description描述stock库存orders订单表id主键order_no订单编号唯一user_id用户IDrestaurant_id商家IDtotal_amount订单总金额address收货地址contact_name联系人contact_phone联系电话status订单状态0待支付1已支付2制作中3配送中4已完成5已取消remark备注信息create_time下单时间order_items订单明细表id主键order_id订单IDdish_id菜品IDdish_name菜品名称冗余存储防止菜品信息变化后无法追溯price购买时的单价quantity购买数量subtotal小计金额delivery_records配送记录表id主键order_id订单IDdelivery_user_id配送员IDstatus配送状态update_time更新时间location位置信息2.2 为什么订单明细要冗余字段这里有一个值得展开说说的地方就是订单明细表里为什么还要存dish_name和price快照。刚开始做的时候我天真地以为直接关联菜品表查名字和价格就行结果后来发现了一个问题如果商家改了菜品的价格或者菜品名称历史订单就会显示出错误的数据。举个例子用户周三下单时红烧肉是38元周四商家涨到45元。等用户周五查看订单记录如果实时关联菜品表看到的就是45元而实际他支付的是38元。这个坑很隐蔽如果不处理后面查账会对不上。解决方案就是在下单时把菜品的名称、单价复制一份存入订单明细表用空间换正确性。用户下单后商家菜品如何变化历史订单都不会受影响。这也是正规电商系统的通用做法不是我这个项目独有的。2.3 订单状态机的流转设计订单状态是我这个系统里逻辑最复杂的部分一定要在设计阶段就规划好。我在项目里定义了一组状态流转规则各端严格按照这个规则来更新数据待支付 → 已支付 → 制作中 → 配送中 → 已完成每个状态之间的跳转都必须通过后端接口完成前端不管直接写死状态值。例如用户点击支付前端只调用后端接口由后端判断当前状态是否为“待支付”如果是才允许更新为“已支付”否则直接返回错误。这里我还有一个加料的设计状态变更记录表。每次订单状态变化就插入一条记录记录订单编号、旧状态、新状态、操作人和操作时间。这个表看起来简单但后面出问题追责或者用户投诉时就是最好的排查依据。3. Node.js后端接口与业务逻辑实现3.1 项目初始化和核心依赖后端我用的Express框架没有用NestJS这种重型框架。原因是项目规模不大Express的中间件机制足够灵活社区教程也多。初始化一个Node.js项目很简单几步就搞定mkdir delivery-backend cd delivery-backend npm init -y npm install express mysql2 sequelize jsonwebtoken bcryptjs cors npm install nodemon --save-dev这些依赖各自的用途expressweb框架路由和中间件核心mysql2连接MySQL数据库的驱动支持PromisesequelizeORM框架避免手写SQLjsonwebtoken生成和验证JWT登录令牌bcryptjs密码加密管理端用户要用cors解决跨域问题nodemon开发时热重载改完代码不用手动重启3.2 数据库连接与模型定义我用Sequelize作为ORM它最大的好处是不用写原生SQL。定义模型的代码看起来是这样的const { DataTypes } require(sequelize); const sequelize new Sequelize(delivery_db, root, password, { host: localhost, dialect: mysql, timezone: 08:00 }); const Dish sequelize.define(Dish, { name: { type: DataTypes.STRING(100), allowNull: false }, price: { type: DataTypes.DECIMAL(10, 2), allowNull: false }, category: { type: DataTypes.STRING(50) }, image: { type: DataTypes.STRING(255) }, status: { type: DataTypes.INTEGER, defaultValue: 1 }, stock: { type: DataTypes.INTEGER, defaultValue: 0 } });有几点值得注意。第一时间戳字段要设置timezone: 08:00否则Sequelize默认使用UTC时区存入数据库的时间会比北京时间少8个小时后面查订单时间会对不上。第二价格字段一定要用DECIMAL不能用FLOAT浮点数计算金额时会有精度丢失的问题这属于常识级别的问题了。3.3 JWT用户鉴权流程小程序的用户登录流程和普通网站不一样没有密码这一说。流程是这样的小程序调用wx.login获取一个code然后把code发给后端后端拿着这个code去微信接口换取openid再用openid作为唯一标识去查找或创建用户最后返回一个JWT令牌给小程序。router.post(/login, async (req, res) { const { code, nickname, avatar } req.body; // 用code换取openid const appid 你的appid; const secret 你的secret; const url https://api.weixin.qq.com/sns/jscode2session?appid${appid}secret${secret}js_code${code}grant_typeauthorization_code; const result await axios.get(url); const { openid } result.data; // 查找或创建用户 let user await User.findOne({ where: { openid } }); if (!user) { user await User.create({ openid, nickname, avatar }); } // 生成JWT令牌 const token jwt.sign({ id: user.id }, your-secret-key, { expiresIn: 7d }); res.json({ token, user }); });JWT令牌有效期我设置的7天这样用户不用每次都重新登录体验比较好。密钥一定要放到环境变量里不要写死在代码中虽然个人项目影响不大但养成好习惯总没错。3.4 下单与支付的核心接口实现下单接口是整个系统的核心里面涉及事务处理。什么场景下必须用事务就是同时写多张表的场景。下单这个操作要写订单表、订单明细表还要更新菜品库存这三个操作必须绑在一起要么全部成功要么全部失败否则就会出现订单建了但库存没扣或者库存扣了但订单没成的脏数据。const transaction await sequelize.transaction(); try { // 创建订单 const order await Order.create({ order_no: generateOrderNo(), user_id: userId, restaurant_id: restaurantId, total_amount: totalAmount, status: 0 }, { transaction }); // 批量创建订单明细 const items cartItems.map(item ({ order_id: order.id, dish_id: item.dishId, dish_name: item.dishName, price: item.price, quantity: item.quantity })); await OrderItem.bulkCreate(items, { transaction }); // 扣减库存 for (const item of cartItems) { await Dish.decrement(stock, { by: item.quantity, where: { id: item.dishId } }); } await transaction.commit(); } catch (error) { await transaction.rollback(); res.status(500).json({ message: 下单失败 }); }订单号生成这块也有讲究。我用的是时间戳加随机数的方式yyyyMMddHHmmss 4位随机数基本保证唯一。当然如果要更严谨可以加一个用户ID的片段进一步降低重复概率。千万不要用自增ID当订单号一是容易暴露订单量二是多表关联时凭订单号看不出时间信息。真实支付我做了个模拟接口直接让用户选择模拟支付成功然后后端把订单状态从“待支付”改为“已支付”。如果要接入微信支付需要企业资质、商户号开通流程比较长个人项目建议先用模拟支付把整个流程跑通后面有条件再替换。3.5 配送状态更新的实现配送功能是订餐系统区别于普通商城的一个重点。我在设计与逻辑上比较倾向于简化角色把配送员和商家统一成后台管理端的角色即商家自己处理接单和配送。这样在小规模试点时可以省掉一个配送员的角色等业务大了再把配送员拆出来。配送状态更新接口的业务规则是这样的只有订单当前状态为“已支付”时商家才能点“开始制作”把状态改成“制作中”只有“制作中”才能改成“配送中”只有“配送中”才能改成“已完成”。这其实就是前面说的状态机每个接口进来先校验当前状态不满足条件直接返回错误信息。4. 小程序端点餐流程与购物车实现4.1 项目目录结构与页面规划小程序端我按照业务模块划分目录每个页面独立文件夹结构清晰miniprogram/ ├── pages/ │ ├── index/ // 首页店铺列表、菜品列表 │ ├── detail/ // 菜品详情页 │ ├── cart/ // 购物车页面 │ ├── order/ // 订单确认页 │ ├── order-list/ // 订单列表 │ ├── order-detail/ // 订单详情页 │ └── user/ // 个人中心 ├── utils/ │ ├── request.js // 封装wx.request请求 │ ├── auth.js // 登录鉴权相关 │ └── cart.js // 购物车本地缓存管理 ├── app.js // 小程序入口文件 ├── app.json // 全局配置 └── app.wxss // 全局样式首页的逻辑是进入后先请求后端接口获取所有营业中的商家点击某个商家后再获取该商家的菜品列表按照分类显示。我用的是九宫格式布局菜品以卡片形式展示点击进入详情页。4.2 购物车状态管理的两种方案购物车是小程序端的核心状态我用了本地缓存全局数据的组合方案。具体来说用wx.setStorageSync把购物车数据持久化到本地这样即使小程序被杀掉重新打开购物车数据也不会丢用app.globalData.cart保存内存中的购物车数据这样页面切换时不需要反复读缓存性能更好每次增删商品时同时更新内存数据和本地缓存两个地方保持同步购物车的数据结构是这样的{ restaurantId: 1, items: [ { dishId: 10, name: 回锅肉, price: 28, quantity: 2, image: ... } ] }这里有一个很重要的规则购物车只能同时包含一个商家的菜品。用户如果加了A商家的菜再去加B商家的菜我会弹窗提示他“购物车已有其他商家的商品是否清空并重新添加”。因为一次配送只能对应一个商家如果跨商家下单配送费用和配送逻辑都会变得非常麻烦。这个限制从用户视角看也完全合理。4.3 小程序端请求封装与登录流程串联小程序的wx.request每次都要写一大堆参数所以我封装了一个request工具函数把公共逻辑抽出来const request (url, method GET, data {}) { return new Promise((resolve, reject) { wx.request({ url: BASE_URL url, method, data, header: { Content-Type: application/json, Authorization: getToken() // 从storage中取token }, success: (res) { if (res.statusCode 401) { // token过期重新登录 loginAndRequest(url, method, data).then(resolve).catch(reject); } else { resolve(res.data); } }, fail: (err) reject(err) }); }); };登录时序是小程序端最容易疏忽的地方。正确的流程是小程序启动时先检查storage里有没有token有就直接用没有的话调用wx.login获取code发给后端换token然后存起来。这个流程要在app.js的onLaunch里执行并且要确保在后续接口调用前登录完成。我用了Promise把登录包装成异步操作所有请求先等待登录状态就绪再发出。具体实现思想是假如用户第一次打开就快速点击点餐此时登录还没完成我们不能直接发未带token的请求。我的方案是维护一个loginPromise变量初始为null第一次调用login时赋值Promise后续的调用都复用同一个Promise保证登录请求只发一次。4.4 订单确认页与支付流程的细节订单确认页需要展示以下内容收货人信息姓名、电话、详细地址商品清单从购物车数据读取这里数据不重新请求后端直接用本地缓存配送费按距离或固定金额计算我这边做的是满30元免配送费不满收5元订单备注用户填写的备注信息一起传到后端用户点击“提交订单”后先调用后端创建订单接口拿到订单号和订单ID然后进入支付环节。我做的模拟支付是弹出一个确认框点击确认后调用支付接口模拟成功然后跳转到订单列表并把购物车清空。这个环节容易出的问题是重复点击提交按钮。网络慢的情况下用户连续点两次可能创建两个一模一样的订单。我处理的方式是按钮点击后立即置disabled状态并显示“提交中...”等接口返回后再恢复。这属于前端交互的基本功但很多人会忽略。4.5 订单状态轮询实现用户下单后订单状态的更新是由商家在后台操作的。小程序端如何及时感知状态变化我用了简单的轮询机制在订单详情页每10秒请求一次订单详情接口如果状态发生变化就刷新页面数据。轮询实现很简单在onShow里启动定时器onShow() { this.startPolling(); }, onHide() { this.stopPolling(); }, methods: { startPolling() { this.pollingTimer setInterval(() { this.fetchOrderDetail(); }, 10000); }, stopPolling() { if (this.pollingTimer) { clearInterval(this.pollingTimer); } } }定时器的启动和停止一定要记得绑定页面的onShow和onHide生命周期。有一次我就是只开了定时器忘记在onHide里关掉页面退回列表后定时器还在跑一直在疯狂请求接口被同事笑称为“内存泄漏教科书案例”。如果追求更好的实时性可以用微信小程序的WebSocket能力服务端主动推送状态变化。但WebSocket会增加后端复杂度对个人项目来说没必要10秒轮询完全够用。5. Vue后台管理端的实现5.1 路由和权限控制Vue后台我基于vue-element-admin模板改造路由表分为两部分一部分是固定的路由登录页、404页另一部分是动态路由需要登录后根据角色权限动态添加。我这边给后台做了一个简单的管理员表没有做路由级权限控制默认只有一种“管理员”角色登录后所有管理页面都可以访问。如果你需要更细致的权限控制可以在前端定义好页面和角色的映射关系登录后根据后台返回的角色信息过滤出可见路由再用router.addRoutes动态添加。这个设计方案是vue-element-admin的经典思路网上的资料很多。5.2 菜品管理页面的表格和表单校验菜品管理页是典型的表格弹窗表单组合页面主体是一个表格展示所有菜品信息每行有“编辑”和“下架”按钮点击“新增”或“编辑”按钮时弹出一个弹窗表单填写菜品信息。表单校验我用了Element UI自带的校验规则比如菜名必填长度2~20个字符价格必填且必须是大于0的数字保留两位小数库存必填且必须是大于等于0的整数分类必须选择价格和库存的校验要用自定义函数实现Element UI自带的type: number在某些版本下存在bug会无法正确校验小数。图片上传用Element UI的el-upload组件通过action属性指定后端的上传接口。后端用multer中间件处理文件上传把图片保存到本地目录然后返回图片访问URL。要注意的是Nginx部署时要配置好静态文件的访问路径不然图片是上传成功了但前端访问不了。5.3 订单处理的操作流转设计后台订单管理页面的核心功能是处理订单状态流转。我设计的是每行订单都显示一个操作按钮根据当前状态显示可执行的操作待支付状态显示“取消订单”已支付状态显示“开始制作”和“取消订单”制作中状态显示“开始配送”配送中状态显示“确认完成”每次操作前先调用后端接口更新状态成功后再刷新表格数据。在操作按钮的地方加了二次确认的MessageBox避免误操作导致订单状态错误。对于商家来说订单列表要支持按状态筛选因为订单量大了以后如果所有订单都混在一起处理效率会非常低。我用的是el-tabs的方式把不同状态的订单分开展示待处理的放前面已完成的折叠起来。5.4 数据统计与可视化这个项目我还加了一个简单的数据统计页面用ECharts展示几个关键指标近7天订单量折线图菜品销量排行TOP10柱状图订单状态分布饼状图统计功能的后端接口用SQL的GROUP BY和DATE_FORMAT函数就能实现。比如近7天订单量只需要分组聚合SELECT DATE(create_time) as date, COUNT(*) as count FROM orders WHERE create_time DATE_SUB(NOW(), INTERVAL 7 DAY) GROUP BY DATE(create_time) ORDER BY date ASC;这个统计页面对商家的参考价值挺高的可以看出哪些菜卖得最好哪些时间段订单最多方便调整备货和营业时间。6. 前后端联调与部署上线的常见问题6.1 跨域问题的一劳永逸解决方案前后端分离开发时Vue后台跑在http://localhost:9527后端跑在http://localhost:3000两者端口不同就会遇到跨域问题。我的方案是后端使用cors中间件全局开启跨域支持const cors require(cors); app.use(cors());这样配置后开发环境和生产环境都不需要额外处理跨域。当然这只适用于没有敏感凭证的API场景。如果涉及Cookie会话就需要配置CORS的credentials选项并指定白名单域名要复杂一些。小程序的请求不存在浏览器跨域问题因为小程序是原生客户端请求不受浏览器同源策略限制。但在微信开发者工具里需要勾选“不校验合法域名、web-view业务域名、TLS版本以及HTTPS证书”选项否则会报域名校验错误。6.2 小程序预览时接口地址怎么配开发小程序时会遇到一个经典问题API请求地址怎么配。开发阶段小程序跑在微信开发者工具里手机预览时请求要发到本机电脑的Node.js服务。这时候要注意如果使用微信开发者工具的模拟器可以直接用http://localhost:3000访问本机服务如果使用真机预览手机不能直接访问电脑的localhost需要换成电脑在局域网中的IP地址同时要保证手机和电脑连接的是同一个WiFi更麻烦的是微信小程序正式版本要求所有请求地址必须是HTTPS域名且域名要备案并在小程序后台配置为合法域名。个人开发阶段用开发者工具的“不校验域名”选项跳过校验没关系但要上线的话必须解决域名和HTTPS证书的问题。我建议的路径是开发阶段用局域网IP测试阶段用测试域名加自签名证书上线前再切换正式HTTPS域名。6.3 两个部署场景的方案参考部署后端我提供了两种方案方案一本机直接跑。适合个人开发和内网测试。用pm2管理Node.js进程确保进程崩溃后自动重启开机自启动可以用pm2-windows-service或pm2 startup命令实现。数据库直接用本机安装的MySQL。方案二云服务器部署。我是用一台Linux服务器nginx做反向代理把/api路径转发到Node.js的3000端口。MySQL装在同一台服务器上方便管理。部署脚本可以写成这样的格式cd /var/www/delivery-backend git pull origin main npm install --production pm2 restart ecosystem.config.js前端Vue后台打包后把dist目录下的静态文件放到nginx的web目录通过nginx直接服务。小程序端不用部署微信审核通过后会自动发布到微信服务器。6.4 开发过程中最容易踩的几个坑这一节我专门整理一下开发过程中反复踩到的坑按出现频率排序第一npm相关的问题。除了前面说到的PowerShell脚本执行策略问题外还有npm install时经常遇到权限错误或网络超时。我的经验是先把npm registry切到国内镜像源安装速度会快很多也基本不会出现timeout问题npm config set registry https://registry.npmmirror.com第二微信开发者工具提示“开发版小程序已过期”。这个提示通常是因为上一次的预览码过期了重新点击开发者工具工具栏的“预览”按钮生成新的预览码扫码即可。如果在手机上还是打不开关掉小程序后台进程重新进入。第三小程序动态设置顶部标题。如果需要在页面运行过程中修改导航栏标题不能直接修改app.json里的navigationBarTitleText而要在页面的onLoad或onShow生命周期里调用wx.setNavigationBarTitle接口动态修改标题。第四前后端字段名不一致。我有一个惨痛教训后端返回的字段是createTime驼峰命名前端表单提交时用了create_time下划线命名结果数据一直绑定不上。后来在Sequelize配置里加了underscored: true自动把模型属性转换为下划线风格这个问题才算解决。前端联调时一定要先确认好字段命名规范最好有一个统一的对照文档。第五Node.js进程挂了。开发阶段我用nodemon但上线部署后nodemon就不合适了。至少有两次线上服务挂了是因为没有用pm2守护进程。后来在pm2的配置文件里配置了监听模式才能解决。6.5 接口响应速度优化心得最后聊一下接口性能优化。订餐系统虽然不算高并发场景但接口响应快慢直接影响用户体验。我做的优化主要有几点数据库查询一定要加索引。orders表的user_id、restaurant_id、status字段order_items表的order_id字段都要建索引。没有索引的时候订单量过千就明显变慢加了索引后查询基本在毫秒级。列表接口用分页。菜品列表和订单列表都实现分页每页限制20条。后端用Sequelize的limit和offset实现前端加一个加载更多的按钮。图片走CDN。菜品图如果自己服务器带宽不够前端加载会特别慢。我是把图片传到对象存储服务上然后通过CDN加速访问效果立竿见影。首页数据做缓存。菜单列表和商家列表这种变化不频繁的数据在后端加一个简单的内存缓存5分钟刷新一次能显著减少数据库压力。7. 写在最后的经验总结项目做完之后我最大的感受是快捷交付的真正技术难点不在于某一个单独技术的深挖而在于把三个端口的业务逻辑串起来。数据从什么页面开始、走到哪个接口、改变什么状态这些链条一旦打通整个系统就活了。我个人在Node.js后端加了一个日志中间件每次有接口请求都打印请求路径、参数、响应耗时调试时候反馈非常快。也强烈建议你加一个类似的东西。还有一个习惯就是每次接口写完先用Postman把边界情况测一遍比如菜品库存为0时下单、订单状态异常时流转等接口稳定了再对接前端这样可以少走很多弯路。这个项目后续要扩展的话方向也蛮清晰一是接入真实微信支付替换掉模拟支付二是增加配送员角色和订单派单逻辑三是做一个基于位置的门店推荐用wx.getLocation获取用户位置后按距离排序。希望这套思路能帮到你。
返回列表