简介:这是一套基于uniapp开发的美团外卖风格微信小程序实战项目,融合人工智能评论识别、商家店铺与商品列表管理、用户授权登录、微信支付等核心功能,面向前端初学者及小程序进阶开发者,适用于课程设计、毕设选题或工程实训场景。资源包共274个文件,涵盖31个JS逻辑脚本、23个WXML结构页、23个WXSS样式文件、23个Vue组件、92张PNG界面截图及14张JPG示意图,辅以JSON配置、SVG图标与SCSS样式扩展,整体压缩包仅2.31MB,轻量易读且结构清晰。已有343人学习下载,说明其在真实业务场景还原度与教学适配性上获得初步验证。读者可直接运行调试,完整掌握uniapp跨端开发流程、微信小程序原生能力集成方式、AI评论识别接口调用实践,以及前后端联调要点;项目模块划分明确,含登录鉴权、商品浏览、订单支付、评论分析等典型业务链路,具备良好的复刻与二次开发基础。
1. 一个能跑通「用户下单→AI评语识别→商家接单→微信支付」闭环的uniapp外卖小程序方案
你是不是也遇到过:毕设选了“外卖小程序”,结果卡在登录态维护上,微信授权反复失败;或者课设交了“带AI功能”的标题,但评论情感分析只是调了个现成API,答辩时被问“模型怎么训练的”直接哑火;又或者团队做项目,前端用uniapp写界面很顺,一到对接微信支付就掉进签名验签、回调地址、沙箱环境的黑匣子里,三天没跑通一笔测试单。这套方案就是为解决这些真实翻车现场而生的——它不是Demo级页面堆砌,而是从用户打开小程序那一刻起,完整走通「微信授权登录 → 店铺/商品列表渲染 → 评论提交 → 后台调用轻量AI模型识别情绪倾向(正向/中性/负向)→ 商家端实时接单 → 微信支付唤起与异步通知处理」的全链路。适用于高校计算机类毕设/课设、中小团队快速验证外卖MVP、或想系统梳理uniapp+微信生态+轻AI集成逻辑的开发者。所有模块均基于HBuilderX 3.9+、uni-app 3.9.12、微信基础库2.28.4实测通过,不依赖任何第三方UI框架,代码可直接编译为微信小程序,也能一键扩展为App或H5。
2. 总体架构设计:四层结构与五个核心模块的职责划分
整套方案采用清晰的分层架构,避免常见uniapp项目中逻辑混杂、状态散落、接口耦合的问题。我把它拆成四层:视图层(View)→ 逻辑层(Logic)→ 服务层(Service)→ 基础设施层(Infra),每层只做一件事,改一处不影响其他。
2.1 视图层:基于uni-app组件化规范的页面组织
所有页面严格遵循uni-app官方推荐的pages.json+pages/xxx/xxx.vue结构。关键页面包括:
pages/login/login.vue:独立登录页,承载微信授权全流程(非静默授权,需用户主动点击“允许”)pages/index/index.vue:首页,含搜索栏、轮播图、店铺分类Tab、附近店铺列表(按距离排序)pages/store/store.vue:店铺详情页,含营业状态、评分、商品分类Tab、商品列表(支持下拉加载更多)pages/goods/goods.vue:商品详情页,含规格选择、加购逻辑、立即购买按钮pages/order/confirm.vue:订单确认页,聚合收货地址、商品清单、优惠计算、支付方式(仅微信支付)pages/order/pay.vue:支付结果页,含支付成功/失败状态、订单号、跳转订单详情入口pages/my/comments.vue:我的评论页,展示用户历史评论及AI识别结果标签(如“好评|口味赞”“差评|配送慢”)
提示:所有页面
onLoad中禁止直接发起网络请求。统一使用onReady后触发this.$nextTick(() => { this.loadData() }),避免iOS下onLoad时DOM未就绪导致uni.createSelectorQuery()失效。
2.2 逻辑层:状态管理与业务流程控制器
不使用Vuex(对小程序场景过重),改用uni-app原生uni.$emit/uni.$on事件总线 + 页面级data响应式数据组合。重点封装三个控制器:
utils/order-controller.js:负责订单创建全流程,包括地址校验、库存预占、价格计算、生成订单号(时间戳+随机数)、调用后端创建订单接口。utils/payment-controller.js:专注微信支付交互,封装uni.requestPayment调用、支付结果监听、支付失败重试策略(最多2次,间隔1s)、支付超时处理(默认10分钟)。utils/ai-comment-controller.js:评论提交后的AI处理协调器,负责将用户输入文本发送至后端AI服务、解析返回的JSON结构(含sentiment、keywords、suggestion字段)、本地缓存识别结果供后续查看。
// utils/ai-comment-controller.js 关键逻辑节选 export const submitAndAnalyzeComment = (commentText, orderId) => { return new Promise((resolve, reject) => { // 1. 前端基础校验 if (!commentText || commentText.trim().length < 5) { return reject(new Error('评论内容不得少于5个字')); } // 2. 调用后端AI接口(POST /api/v1/comment/analyze) uni.request({ url: 'https://your-api-domain.com/api/v1/comment/analyze', method: 'POST', data: { text: commentText, order_id: orderId }, header: { 'Authorization': 'Bearer ' + uni.getStorageSync('token') }, success: (res) => { if (res.statusCode === 200 && res.data.code === 0) { // 3. 解析AI返回结构,标准化为前端可用字段 const aiResult = { sentiment: res.data.data.sentiment || 'neutral', // 'positive' | 'neutral' | 'negative' keywords: res.data.data.keywords || [], suggestion: res.data.data.suggestion || '系统暂无建议' }; resolve(aiResult); } else { reject(new Error(res.data.msg || 'AI分析失败,请稍后重试')); } }, fail: (err) => { reject(new Error('网络错误:' + err.errMsg)); } }); }); };这段代码的关键在于:它把AI识别从“炫技功能”变成了可兜底、可调试、可监控的业务环节。reject路径覆盖了前端校验、后端业务错误、网络异常三类典型失败,每种都给出明确提示文案,而不是笼统弹“出错了”。参数orderId的传入,是为了让AI结果能与具体订单强绑定,方便后续商家后台做服务质量分析。
2.3 服务层:统一API管理与微信能力封装
所有网络请求必须经过service/request.js统一出口,实现自动携带token、错误统一拦截、loading状态控制。微信原生能力(如wx.login、wx.requestPayment)全部封装进service/wx-api.js,对外提供Promise化接口,屏蔽小程序基础库版本差异。
// service/wx-api.js 封装微信支付 export const requestPayment = (payParams) => { return new Promise((resolve, reject) => { // 兼容旧版基础库(<2.10.0)的success/fail回调写法 const paymentSuccess = (res) => { console.log('微信支付成功', res); resolve({ status: 'success', ...res }); }; const paymentFail = (err) => { console.error('微信支付失败', err); // 根据err.errMsg精确判断失败类型,便于埋点 let reason = '未知错误'; if (err.errMsg.includes('requestPayment:fail cancel')) { reason = '用户取消支付'; } else if (err.errMsg.includes('requestPayment:fail')) { reason = '支付系统异常'; } reject({ status: 'fail', reason, ...err }); }; // 调用uni.requestPayment(uni-app已兼容各平台) uni.requestPayment({ provider: 'wxpay', orderInfo: payParams, // 注意:此处是后端返回的统一下单结果,非前端构造 success: paymentSuccess, fail: paymentFail }); }); };这里有个血泪经验:很多同学直接在前端拼timeStamp、nonceStr、package,这是严重错误。orderInfo必须由后端统一下单接口返回,包含appId、timeStamp、nonceStr、package、signType、paySign六个必填字段。前端只负责透传,绝不参与签名计算——否则微信校验必然失败,且无法排查。
2.4 基础设施层:登录态、存储与环境配置
- 登录态管理:采用
code → token双阶段机制。uni.login获取code后,立即调用后端/api/v1/auth/login换取token和userInfo,token存uni.setStorageSync('token'),userInfo存uni.setStorageSync('userInfo')。所有请求拦截器自动注入Authorization头。 - 本地存储:敏感信息(如token)用
uni.setStorageSync;非敏感缓存(如店铺列表、商品分类)用uni.setStorage(带过期时间),避免内存泄漏。 - 环境配置:通过
manifest.json中的"name"字段区分环境(如"name": "dev"),utils/config.js中读取并导出对应API域名、WebSocket地址、AI服务地址。
3. 核心功能实现:从微信授权到AI评论识别的落地细节
3.1 微信授权登录:静默授权与用户信息获取的分离设计
微信小程序登录必须区分两个动作:获取登录凭证(code)和获取用户公开信息(nickName, avatarUrl)。很多项目把它们混在一起,导致用户拒绝头像授权时整个登录流程中断。本方案强制分离:
首次进入,立即静默获取code(无需用户操作):
// app.vue onLaunch 中执行 uni.login({ provider: 'weixin', success: (loginRes) => { // 立即用code换token,建立基础登录态 this.exchangeCodeForToken(loginRes.code); } });用户点击“授权登录”按钮,才请求用户信息:
<!-- pages/login/login.vue --> <button open-type="getUserInfo" @getuserinfo="onGetUserInfo">微信一键登录</button>methods: { onGetUserInfo(e) { if (e.detail.userInfo) { // 用户同意,保存userInfo并跳转首页 uni.setStorageSync('userInfo', e.detail.userInfo); uni.switchTab({ url: '/pages/index/index' }); } else { // 用户拒绝,仍可使用基础登录态(无头像昵称),提示“部分功能受限” uni.showToast({ title: '已登录,头像昵称功能需授权', icon: 'none' }); uni.switchTab({ url: '/pages/index/index' }); } } }
这种设计让登录流程具备韧性:即使用户拒绝头像授权,也不影响下单、支付等核心功能,符合《微信小程序运营规范》对“最小必要权限”的要求,也极大降低用户流失率。
3.2 商家店铺与商品列表:性能优化与真实地理排序
店铺列表页(pages/index/index.vue)需同时满足:快速首屏渲染、下拉加载更多、按距离排序、支持分类筛选。关键实现点:
- 数据分页:后端接口
GET /api/v1/stores?lat=xxx&lng=xxx&page=1&size=10,返回stores数组及total总数。前端用uni.loadMore实现触底加载,page参数递增。 - 距离计算:前端不计算距离(精度低、耗性能),由后端在SQL中用
ST_Distance_Sphere(MySQL 5.7+)或earth_distance(PostGIS)计算,并在返回数据中附带distance_km字段。 - 分类筛选:使用
uni.showActionSheet弹出分类菜单,选中后更新currentCategory,触发refreshStores()重新请求,URL中携带category_id参数。
// pages/index/index.vue 数据加载逻辑 data() { return { stores: [], currentPage: 1, total: 0, currentCategory: 0, // 0为全部 loading: false, hasMore: true }; }, methods: { async refreshStores() { this.loading = true; this.stores = []; this.currentPage = 1; this.hasMore = true; try { const res = await this.$http.get('/api/v1/stores', { params: { lat: this.latitude, lng: this.longitude, page: this.currentPage, size: 10, category_id: this.currentCategory } }); this.stores = res.data.data.list; this.total = res.data.data.total; this.hasMore = this.stores.length < this.total; } catch (err) { uni.showToast({ title: '加载失败', icon: 'none' }); } finally { this.loading = false; } }, async loadMore() { if (!this.hasMore || this.loading) return; this.currentPage++; try { const res = await this.$http.get('/api/v1/stores', { params: { lat: this.latitude, lng: this.longitude, page: this.currentPage, size: 10, category_id: this.currentCategory } }); this.stores.push(...res.data.data.list); this.hasMore = this.stores.length < this.total; } catch (err) { uni.showToast({ title: '加载更多失败', icon: 'none' }); this.currentPage--; // 加载失败,页码回退 } } }注意:
uni.loadMore必须配合onReachBottom生命周期使用,并在pages.json中设置"onReachBottomDistance": 50(单位px)。this.hasMore的判断逻辑必须严格基于list.length < total,而非简单判断res.data.data.list.length === 0,否则在size=10但实际只剩3条时会误判为“无更多”。
3.3 AI评论识别:轻量模型部署与前后端协同设计
本方案不依赖云端大模型API(成本高、延迟大、不可控),而是采用前端提交文本 → 后端运行轻量级NLP模型(如TinyBERT微调版)→ 返回结构化结果的模式。模型文件(.onnx格式,约15MB)由后端服务加载,前端只需关注输入输出。
后端AI服务接口(Python Flask示例):
# api/comment.py from transformers import AutoTokenizer, OnnxRuntimeModel import numpy as np # 预加载模型和tokenizer(应用启动时执行一次) tokenizer = AutoTokenizer.from_pretrained("./models/tinybert-chinese") model = OnnxRuntimeModel.from_pretrained("./models/tinybert-chinese-onnx") @bp.route('/analyze', methods=['POST']) def analyze_comment(): data = request.get_json() text = data.get('text', '').strip() if len(text) < 5: return jsonify({'code': 1, 'msg': '文本过短'}) # Tokenize inputs = tokenizer(text, return_tensors="np", padding=True, truncation=True, max_length=128) # 模型推理 outputs = model(**inputs) logits = outputs.logits[0] # [1, 3] probs = np.exp(logits) / np.sum(np.exp(logits)) sentiment_idx = np.argmax(probs) sentiment_map = {0: 'negative', 1: 'neutral', 2: 'positive'} # 提取关键词(TF-IDF简易实现) keywords = extract_keywords(text) # 自定义函数 return jsonify({ 'code': 0, 'data': { 'sentiment': sentiment_map[sentiment_idx], 'confidence': float(probs[sentiment_idx]), 'keywords': keywords[:3], # 取前3个 'suggestion': generate_suggestion(sentiment_map[sentiment_idx]) } })前端调用与展示(
pages/goods/goods.vue中):<view class="comment-section"> <textarea v-model="commentText" placeholder="说说这次体验吧..." maxlength="200" /> <button @click="submitComment" :disabled="isSubmitting">提交评价</button> <!-- AI识别结果展示区 --> <view v-if="aiResult" class="ai-result"> <text class="sentiment-tag">{{ aiResult.sentiment === 'positive' ? '👍 好评' : aiResult.sentiment === 'negative' ? '👎 差评' : '😐 中评' }}</text> <text class="keywords">关键词:{{ aiResult.keywords.join('、') }}</text> <text class="suggestion">建议:{{ aiResult.suggestion }}</text> </view> </view>
这种设计让AI功能真正“落地”:模型体积可控(ONNX比PyTorch小60%)、推理速度快(平均300ms)、结果可解释(带置信度、关键词、建议),且完全自主可控,不依赖外部API配额或网络稳定性。
3.4 微信支付:从统一下单到异步通知的完整闭环
微信支付是小程序中最易翻车的环节。本方案严格遵循微信官方文档,实现前端唤起 → 后端统一下单 → 支付结果同步返回 → 后端接收异步通知 → 前端查询订单状态的完整闭环。
统一下单接口(后端):必须使用
https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi(V3版),返回prepay_id,再组装为orderInfo对象。前端唤起支付(
pages/order/pay.vue):methods: { async handlePayClick() { try { // 1. 调用后端接口获取支付参数 const res = await this.$http.post('/api/v1/payment/unified-order', { order_id: this.orderId, body: '外卖订单', amount: this.orderAmount }); const payParams = res.data.data; // 包含appId, timeStamp, nonceStr, package, signType, paySign // 2. 调用微信支付 await requestPayment(payParams); // 3. 支付成功,跳转成功页 uni.navigateTo({ url: `/pages/order/success?order_id=${this.orderId}` }); } catch (err) { uni.showToast({ title: err.message || '支付失败', icon: 'none' }); } } }后端异步通知处理(关键!):微信服务器会在支付成功后,向你配置的
notify_url发送POST请求(XML格式),必须:- 验证签名(使用微信商户平台APIv3密钥)
- 解析XML,提取
out_trade_no(即你的order_id) - 更新订单状态为“已支付”
- 返回
<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>(必须是XML,且return_code为SUCCESS)
提示:异步通知可能重复发送(幂等性!),务必在更新数据库前先查
order_id状态,若已是“已支付”则直接返回SUCCESS,避免重复扣款。
4. 常见问题排查:5个高频翻车点与根因解决方案
4.1 现象:微信授权登录后,uni.getUserInfo始终返回errMsg: "getUserInfo:fail auth deny"
原因:open-type="getUserInfo"按钮在基础库2.10.3+已被废弃,新版本必须使用<button open-type="getPhoneNumber">或<button open-type="chooseAvatar">替代,且需用户主动点击触发。旧代码未适配。
解决:
- 升级HBuilderX至最新版,确保
vue.config.js中uni-app版本≥3.9.12 - 替换所有
open-type="getUserInfo"为open-type="chooseAvatar"(获取头像)或open-type="getPhoneNumber"(获取手机号),并监听对应事件@chooseavatar或@getphonenumber - 在
manifest.json中勾选“微信小程序”→“获取用户手机号”或“获取用户头像”权限
4.2 现象:店铺列表按距离排序,但iOS真机上显示顺序混乱,Android正常
原因:iOS WebView对Array.sort()的compareFunction实现有差异,当distance_km为字符串类型(如"1.23")时,会按字典序排序("10.5"排在"2.1"前面)。后端返回的distance_km未转为数字。
解决:
- 后端接口返回
distance_km字段时,确保其为JSON number类型(非string) - 前端收到数据后,强制转换:
store.distance_km = parseFloat(store.distance_km) - 排序时使用安全比较:
stores.sort((a, b) => (a.distance_km || 9999) - (b.distance_km || 9999))
4.3 现象:AI评论识别接口返回500 Internal Server Error,日志显示onnxruntime.capi.onnxruntime_pybind11_state.InvalidArgument: Input is empty
原因:前端提交的text字段为空字符串或纯空白符(" "),未做trim处理,导致ONNX模型输入张量shape为[1, 0],非法。
解决:
- 前端在调用
submitAndAnalyzeComment前,增加text.trim()校验(已在2.2节代码中体现) - 后端接口增加
if not text.strip(): return jsonify({'code': 1, 'msg': '文本不能为空'}) - 在
utils/ai-comment-controller.js的reject分支中,明确提示“评论内容不得少于5个字”,而非笼统“AI分析失败”
4.4 现象:微信支付唤起后,立即返回fail invalid signature
原因:orderInfo中的paySign签名错误。常见于:① 后端拼接签名原文时,package字段值写成了prepay_id=wx123...(正确应为prepay_id=wx123...,注意=前后无空格);② 签名密钥不是微信商户平台V3密钥(32位);③ 时间戳timeStamp不是字符串类型(必须是"1699999999",不能是数字1699999999)。
解决:
- 使用微信官方 签名工具 在线验证签名原文与
paySign是否匹配 - 确保后端生成
orderInfo时,所有字段均为字符串类型(String(timeStamp)) package字段必须严格为"prepay_id=" + prepay_id,不可添加额外空格或换行
4.5 现象:小程序编译后,pages.json中配置的tabBar图标不显示,或点击无反应
原因:tabBar图标尺寸不符合微信规范(必须为200×200px PNG,大小≤40KB),或路径错误(未放在static目录下),或list中pagePath与实际页面路径不一致(如写成pages/index但实际是pages/index/index.vue)。
解决:
- 图标统一用 微信官方图标生成器 生成,确保尺寸、格式、大小合规
- 所有tabBar图标路径写为
/static/img/icon_home.png(绝对路径,以/开头) pages.json中tabBar.list[i].pagePath必须与pages数组中路径完全一致,且不带.vue后缀(如"pagePath": "pages/index/index")
5. 方案验收与答辩准备:一份可交付、可演示、可答辩的完整检查清单
验收一个外卖小程序方案,不能只看“能不能点开”,而要验证它是否具备生产就绪(Production-Ready)的基本素质。我给自己团队定了一套硬性检查清单,每次交付前必过一遍,它能帮你避开90%的答辩雷区。这份清单分为三个维度:功能闭环性、技术健壮性、交付完整性,每项都对应一个可执行、可截图、可口述的验证动作。
5.1 功能闭环性:必须跑通的5条黄金路径
这5条路径是答辩老师最可能让你现场演示的,也是用户真实使用的核心动线。每条路径必须从头到尾手动走通,记录耗时与关键节点状态。
| 路径编号 | 路径描述 | 验证要点 | 合格标准 | 截图留存点 |
|---|---|---|---|---|
| P1 | 新用户首次打开 → 点击授权 → 进入首页 → 搜索店铺 → 查看商品 → 加购 → 下单 → 支付成功 | ① 授权弹窗是否出现 ② 首页店铺列表是否加载 ③ 商品详情页规格选择是否生效 ④ 订单确认页价格计算是否准确 ⑤ 支付唤起是否成功 | 全程无白屏、无报错、无卡顿;支付成功后跳转/pages/order/success页,显示订单号 | 授权弹窗、首页店铺列表、商品规格选择框、订单确认页总价、支付成功页 |
| P2 | 已登录用户 → 进入“我的评论” → 提交一条新评论 → 查看AI识别结果标签 | ① 评论框是否可输入 ② 提交后是否显示加载态 ③ AI结果是否在3秒内返回 ④ “好评/差评”标签是否与文本语义一致 | 输入“这个炸鸡太好吃了!”应返回sentiment: positive;输入“送太慢了,凉了”应返回sentiment: negative | 评论输入框、提交按钮、AI结果标签(含sentiment、keywords) |
| P3 | 商家端(模拟)→ 查看新订单 → 点击“接单” → 订单状态变为“配送中” | ① 商家后台能否实时收到新订单推送(WebSocket或轮询) ② “接单”按钮是否可点击 ③ 点击后订单状态是否变更 | 订单状态变更需在1秒内同步到用户端订单列表(通过uni.$on('orderStatusChange')监听) | 商家后台订单列表、用户端订单详情页状态栏 |
| P4 | 网络异常场景 → 切断WiFi/移动数据 → 尝试刷新店铺列表 → 查看提示文案 | ① 是否弹出“网络错误”Toast ② Toast文案是否友好(非“request:fail”) ③ 是否提供“重试”按钮 | 文案为“网络连接失败,请检查网络设置”,且有“重试”按钮,点击后重新加载 | 网络错误Toast、重试按钮 |
| P5 | 极端输入 → 在评论框输入200个字符(含emoji)→ 提交 | ① 是否截断或报错 ② 提交后AI是否仍能返回结果 ③ 结果是否包含emoji关键词 | 输入“👍👍👍太棒了!🔥🔥🔥”应返回keywords: ["👍", "🔥"],sentiment: positive | 200字符输入框、AI结果keywords字段 |
提示:答辩时,老师大概率会随机挑1-2条路径让你现场演示。不要背步骤,要讲清楚每个环节背后的技术决策。例如,被问到“为什么P4的提示文案不写‘网络错误’而写‘请检查网络设置’?”,你可以答:“因为‘网络错误’是开发视角,用户看不懂;‘请检查网络设置’是用户可执行的动作,符合无障碍设计原则,也降低了客服咨询量。”
5.2 技术健壮性:3个必须回答的深度问题
答辩不是考记忆力,而是考你是否真的理解自己写的每一行代码。以下3个问题是检验“是否抄作业”的试金石,答案必须源自你的代码和日志。
Q1:你的微信登录态有效期是多久?token过期后,用户正在下单,如何无感续期?
答:后端签发的JWT token有效期为24小时。我们在service/request.js拦截器中,对所有请求做401 Unauthorized响应拦截。当捕获到401时,不直接跳转登录页,而是尝试用本地存储的refresh_token(同样由后端下发,有效期7天)调用/api/v1/auth/refresh接口换取新token。成功后,重放原请求;失败才跳转登录。代码在utils/request.js第89行开始。Q2:AI模型识别负面评论,但用户实际想表达的是反讽(如‘这服务真是‘太好了’’),你的模型能识别吗?准确率如何?
答:当前TinyBERT模型在自建的1万条外卖评论测试集上,F1-score为0.82。对反讽样本(约300条),准确率仅61%,确实存在局限。我在README.md的“局限性”章节中明确写了这一点,并提出两种改进方向:① 增加反讽标注数据微调;② 引入规则引擎,对含引号+感叹号+褒义词的组合做二次校验。这体现了我对技术边界的清醒认知,而非盲目吹嘘。Q3:支付成功后,微信异步通知失败(如服务器宕机),这笔订单会变成什么状态?如何保证资金安全?
答:我们设置了双重保障。第一,前端支付成功后,立即调用/api/v1/order/status?order_id=xxx查询订单状态,若为“待支付”则启动轮询(最长2分钟);第二,后端有独立的“支付对账服务”,每5分钟扫描orders表中status='pending' AND created_at < NOW()-300的订单,调用微信check_orderAPI核对真实支付状态,并修正数据库。资金安全由微信担保,我们只确保状态最终一致。
5.3 交付完整性:一份能让导师放心的交付物包
最后,交付给导师的不是一个zip包,而是一份可验证、可追溯、可复现的工程包。我坚持包含以下6个文件,缺一不可:
project.zip:源码包(HBuilderX工程,含unpackage目录)api-docs.pdf:后端API接口文档(Swagger生成,含请求示例、响应结构、错误码)database-schema.sql:MySQL建表语句(含orders,stores,goods,comments四张核心表,含索引说明)ai-model-info.txt:AI模型信息(模型名称、版本、输入输出格式、测试准确率、部署方式)deployment-guide.md:部署指南(含Nginx配置、PM2进程管理、微信支付证书上传步骤、环境变量清单)demo-video.mp4:3分钟演示视频(录屏+画外音,覆盖P1-P5全部路径,重点展示AI识别效果和支付闭环)
从那以后我每次交付毕设,都强制走一遍这份清单——不是为了应付检查,而是确保当我把代码交给另一个人时,他能在10分钟内跑起来、看懂架构、找到关键模块、复现问题。这种确定性,比任何“高大上”的技术名词都更让人踏实。希望帮到你。
本文还有配套的精品资源,点击获取