ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Python+uniapp微信小程序药品商城开发:多商家拆单与发票模块设计

Python+uniapp微信小程序药品商城开发:多商家拆单与发票模块设计 先聊点实际的。药品这类商品跟普通零售完全不同它涉及库存批次、处方限制、效期管理还要处理发票和多商家入驻光这几个点就能把大部分毕设项目的复杂度拉高一个档次。如果你正准备做一个“Python uniapp 微信小程序”的自助购药商城而且还要写论文那这篇文章就是给你准备的我会把项目拆成业务逻辑、系统设计、代码落地、论文写作四个维度讲清楚全部基于真实开发中会遇到的场景。1. 项目整体设计与核心需求拆解1.1 药品商城不只是“商城”表面上看这是一个电商小程序但“药品”和“多商家”这两个词决定了它不能照搬通用商城方案。先说药品本身。药品 SKU 有“一品一码”的追溯要求在部分场景下需要保留但实际开发中更常见的是batch_no批次号和expiry_date有效期两个字段必须存。比如同一款布洛芬缓释胶囊不同批次、不同效期的价格可以一样但库存必须分开管理这直接影响到下单减库存的逻辑。后面在订单模块里我会给出具体建表思路。再说“多商家”这三个字。多商家意味着商品数据不能全局一张表查到底每件商品必须挂merchant_id用户下了一单可能涉及多个商家这就牵扯出订单拆分的问题——用户购物车里同时加了A药店和B药店的药结算时系统要自动拆成两个子订单各自独立发货、独立结算、独立开票。这是整个系统里最容易翻车的点没有之一。至于“发票”功能实际药品场景里主要开电子普通发票个别场景要支持企业抬头和税号。发票模块不要一开始就对接百望、航信这些第三方税控接口——成本高、审核麻烦论文阶段先用“开票申请 系统生成发票编号 PDF模板落库”的方式打通流程论文里写明生产环境可替换为税控服务即可。1.2 论文场景下的题目切入点这个项目带“论文”二字大概率是本科或硕士的毕业设计。论文撰写时不要只写“我做了什么”而是要突出“我遇到了什么问题、为什么这么设计、对比其他方案有什么优劣势”。举个例子技术选型章节里前端框架选 uniapp 而不是原生微信小程序你可以这样论证原生小程序不能一套代码同时覆盖App Store和Android应用市场而 uniapp 基于 Vue 语法生态做跨端时业务代码复用率可以到 85% 以上并且它支持条件编译可以针对微信小程序平台单独定制导航栏和登录逻辑。后端选 Python Flask/Django 而不选 Spring Boot理由可以是 Python 在数据分析和接口开发上的开发效率高且作为毕设项目团队维护成本低此外 Python 有非常成熟的微信支付和 MySQL 操作库支撑。这些内容写进论文“需求分析”和“技术选型”两章逻辑上是闭环的。2. 技术栈选型与架构设计2.1 前后端分离的完整结构整个项目分为三层uniapp 小程序端、Python API 服务端、MySQL 数据库。配合 Redis 做会话缓存和购物车缓存配合 OSS/COS 做商品图片存储。nginx 直接作为反向代理把接口转发到后端服务默认监听 80 端口。配置文件里我习惯这样组织server { listen 80; server_name yourdomain.com; client_max_body_size 50m; location /api/ { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }移动端和小程序端统一通过https://yourdomain.com/api/访问接口。这里要注意微信小程序要求配置的 request 合法域名必须是 HTTPS 且备案开发阶段可以在开发者工具里勾选“不校验合法域名”来调试但上线前必须换成正式 HTTPS 域名。2.2 Python 后端框架选择与项目目录专门对比一下 Flask 和 Django。Flask 轻量、灵活适合接口不多的小项目但多商家、多角色权限这类业务Django 的 admin 后台和 ORM 自带分页、事务、中间件能少写很多代码。我用的是 Django Django REST FrameworkDRF。标准的项目目录结构pharmacy_backend/ ├── manage.py ├── config/ # 配置文件 │ ├── settings.py │ └── urls.py ├── apps/ │ ├── users/ # 用户、地址、会员 │ ├── merchants/ # 商家入驻、审核、店铺信息 │ ├── products/ # 药品分类、商品、SKU、库存 │ ├── orders/ # 购物车、订单、退款 │ ├── invoices/ # 发票申请、发票记录 │ └── payments/ # 微信支付、支付回调 └── utils/ # 通用工具加密、分页、响应封装Django 里多 app 的好处是隔离业务边界论文画架构图的时候会很清晰而且每个 app 都可以单独拆出去做成微服务——这又是一个可以写进论文“未来展望”的亮点。2.3 数据库设计多商家药品库存是核心直接给出核心表结构方便你建库时少走弯路。用户表CREATE TABLE user ( id int NOT NULL AUTO_INCREMENT, openid varchar(64) NOT NULL, nickname varchar(64) DEFAULT , avatar varchar(255) DEFAULT , phone varchar(20) DEFAULT , role tinyint NOT NULL DEFAULT 0 COMMENT 0-普通用户 1-商家 2-管理员, created_at datetime NOT NULL, PRIMARY KEY (id), UNIQUE KEY uk_openid (openid) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;商家表核心是status字段用于入驻审核balance用于财务结算。CREATE TABLE merchant ( id int NOT NULL AUTO_INCREMENT, user_id int NOT NULL, shop_name varchar(100) NOT NULL, license_no varchar(64) DEFAULT COMMENT 营业执照号, contact_name varchar(32) DEFAULT , contact_phone varchar(20) DEFAULT , status tinyint NOT NULL DEFAULT 0 COMMENT 0-待审核 1-正常 2-已驳回 3-已冻结, balance decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT 结算余额, created_at datetime NOT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;药品商品表merchant_id决定商品归属need_prescription决定是否进入处方药流程。CREATE TABLE product ( id int NOT NULL AUTO_INCREMENT, merchant_id int NOT NULL, category_id int NOT NULL, name varchar(128) NOT NULL, generic_name varchar(128) DEFAULT COMMENT 通用名, spec varchar(64) NOT NULL COMMENT 规格, unit varchar(16) NOT NULL DEFAULT 盒, price decimal(10,2) NOT NULL COMMENT 零售价, stock int NOT NULL DEFAULT 0, need_prescription tinyint NOT NULL DEFAULT 0 COMMENT 0-OTC 1-处方药, detail text, status tinyint NOT NULL DEFAULT 1 COMMENT 1-上架 0-下架, created_at datetime NOT NULL, PRIMARY KEY (id), KEY idx_merchant (merchant_id), KEY idx_category (category_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;批次库存表CREATE TABLE product_batch ( id int NOT NULL AUTO_INCREMENT, product_id int NOT NULL, batch_no varchar(64) NOT NULL COMMENT 批次号, expiry_date date NOT NULL COMMENT 有效期, quantity int NOT NULL DEFAULT 0, PRIMARY KEY (id), KEY idx_product (product_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;订单表与订单商品表CREATE TABLE order ( id int NOT NULL AUTO_INCREMENT, order_no varchar(32) NOT NULL, user_id int NOT NULL, merchant_id int NOT NULL COMMENT 子订单对应商家, parent_order_no varchar(32) DEFAULT NULL COMMENT 拆单前的父订单号, total_amount decimal(10,2) NOT NULL, freight_amount decimal(10,2) DEFAULT 0.00, pay_status tinyint NOT NULL DEFAULT 0 COMMENT 0-未支付 1-已支付 2-已退款, order_status tinyint NOT NULL DEFAULT 0 COMMENT 0-待付款 1-待发货 2-待收货 3-已完成 4-售后中, address_id int NOT NULL, created_at datetime NOT NULL, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE order_item ( id int NOT NULL AUTO_INCREMENT, order_id int NOT NULL, product_id int NOT NULL, product_name varchar(128) NOT NULL, spec varchar(64) DEFAULT , price decimal(10,2) NOT NULL, quantity int NOT NULL, batch_no varchar(64) DEFAULT COMMENT 锁定批次, expiry_date date DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这里有一个容易踩的坑order在 MySQL 里是关键字我建表时用反引号包住但为了保险更建议直接用trade_order或orders作为表名否则后续写 SQL 容易冷不丁报语法错误。发票表CREATE TABLE invoice ( id int NOT NULL AUTO_INCREMENT, user_id int NOT NULL, order_id int NOT NULL, type tinyint NOT NULL DEFAULT 0 COMMENT 0-电子普通发票 1-增值税专用发票, title_type tinyint NOT NULL DEFAULT 0 COMMENT 0-个人 1-企业, title varchar(128) NOT NULL, tax_no varchar(64) DEFAULT COMMENT 税号, amount decimal(10,2) NOT NULL, status tinyint NOT NULL DEFAULT 0 COMMENT 0-待开 1-已开 2-已作废, invoice_no varchar(32) DEFAULT , pdf_url varchar(255) DEFAULT , created_at datetime NOT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;数据库是订单一致性的地基不理解表之间的关系后面所有代码都是空转。我见过太多人表还没建清楚就开始写接口最后在拆单逻辑里被 JOIN 来回折磨。3. 微信登录、支付与隐私合规3.1 微信登录获取手机号的完整流程小程序端登录必须走微信官方大一统流程用户点击“微信一键登录” →uni.login拿到code→ 前端把code发给后端 → 后端调jscode2session接口换openid和session_key→ 后端生成自定义token比如 JWT返回给前端 → 前端把token存入uni.setStorageSync后续请求全部带上。后端 Django 视图核心代码import requests import jwt import time from django.conf import settings def wx_login(request): code request.data.get(code) appid settings.WX_APPID secret settings.WX_SECRET url ( https://api.weixin.qq.com/sns/jscode2session f?appid{appid}secret{secret}js_code{code}grant_typeauthorization_code ) resp requests.get(url, timeout5).json() if openid not in resp: return JsonResponse({code: 400, msg: 微信登录失败}) openid resp[openid] user, _ User.objects.get_or_create(openidopenid) payload {user_id: user.id, exp: int(time.time()) 86400 * 7} token jwt.encode(payload, settings.SECRET_KEY, algorithmHS256) return JsonResponse({code: 0, data: {token: token, user_id: user.id}})获取手机号getPhoneNumber在新版本微信里已改为通过code换取不直接返回明文手机号。前端的按钮button open-typegetPhoneNumber getphonenumberonGetPhone 获取手机号 /button后端拿到code后调https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_tokenACCESS_TOKEN用code换pure_phone_number。注意access_token需要先用appidsecret换取并缓存建议存 Redis 并设置 7200 秒过期。3.2 微信支付流程和回调处理支付环节后端先生成统一下单需要的参数——订单号order_no、金额total_amount、描述body用商户证书私钥签名后调微信支付接口拿到prepay_id再把timeStamp、nonceStr、package、signType这些参数返回给小程序前端前端用uni.requestPayment拉起支付面板。关键代码像这样// 前端拉起支付 uni.requestPayment({ provider: wxpay, timeStamp: res.data.timeStamp, nonceStr: res.data.nonceStr, package: res.data.package, signType: MD5, paySign: res.data.paySign, success: (payRes) { // 轮询后端确认支付结果 this.confirmPay(orderNo); }, fail: (err) { uni.showToast({ title: 支付取消, icon: none }); } });后端支付回调是重中之重一定要验签别直接信参数。回调通知里包含out_trade_no和transaction_id验签通过后先查询订单状态是不是“未支付”再执行“支付成功”的动作改订单状态、扣库存、生成发票待办通知。用 Django 写的时候要用csrf_exempt装饰回调视图因为微信回调不是带 CSRF 的普通表单请求。库存扣减我专门说一下支付回调里扣库存比下单时减库存更稳。如果下单就减库存用户迟迟不付款库存被锁死如果下单不减、支付后扣要注意超高并发下可能超卖。药品商城场景建议用 Redis 的DECRBY原子操作from django_redis import get_redis_connection def deduct_stock(product_id, batch_no, quantity): conn get_redis_connection(default) key fstock:{product_id}:{batch_no} if conn.decrby(key, quantity) 0: conn.incrby(key, quantity) raise CustomException(库存不足)支付回调完结后再异步把 Redis 扣减结果同步回 MySQL。这个“缓存写、回调扣、异步同步”的经典套路可以写进论文高并发设计章节评审老师会非常买账。3.3 隐私协议与用户授权合规2023年后微信小程序审核对隐私协议查得很严。你的小程序在收集用户手机号、位置信息如果有配送范围判断之前必须在小程序管理后台配置《用户隐私保护指引》同时代码里要通过wx.requirePrivacyAuthorize或者首次打开时的弹窗获得授权合规。我的项目里是做了一个首次启动弹窗用户点击“同意并继续”之后才调用登录和定位接口。这个逻辑别看简单审核被拒时会让你改到怀疑人生。另外开发阶段别用手机号快速填写的测试号直接提审——换了正式 appid 后很多行为不一致容易产生“正式环境登录失败”这种定位半天的 bug。4. 多商家拆单和发票模块落地4.1 购物车如何支持多商家商品购物车表设计时天然要给商品带上merchant_id这样前端展示购物车列表时可以按商家分组用户勾选结算时后端按商家维度对所有商品分组from collections import OrderedDict def build_order_groups(cart_item_ids): items CartItem.objects.filter(id__incart_item_ids, status1) groups OrderedDict() for item in items: merchant_id item.product.merchant_id groups.setdefault(merchant_id, []).append(item) return groups前端 uniapp 里用uni.setStorageSync存购物车时我建议钥匙结构直接用merchantId_productId避免跨商家商品在本地端混算金额。UI 上每个商家区块渲染一个“店铺头”显示商家名和运费规则这就是标准的电商多店聚合页逻辑。4.2 拆单算法与平衡后端拆单的关键是父单和子单不能丢关联。流程如下用户提交结算包含一组购物车商品。后端按商家分组生成多个子订单每个子订单生成自己的订单号如SO202506011230001001。生成一个父订单号如PO202506011230并把所有子订单号挂到父单下。前端支付时其实是一次支付全部子单的总金额此时用父单号调微信支付预下单。支付成功回调通过out_trade_no找到父单再把父单下所有子单统一标记为已支付。这里有个逻辑细节prepay_id生成时不要拿多个子订单一个个调支付接口小程序端一次只能拉起一个支付面板。一定是“一次支付多单分摊”。实现时可以让父单记录总金额支付回调里针对每个子单做分账记录这也能顺理成章引出后面的商家结算功能。4.3 发票模块的实现细节发票模块我的实现思路是订单完成支付后用户可以在订单详情页选择一个订单或合并多个订单申请开票。开票信息包括抬头发票类型个人/企业、企业抬头、税号。用户提交后系统生成一条invoice记录状态为待开。生产环境如果要对接税控需要准备税控盘和商户资质这里不展开。我建议论文环节用一个“发票生成器”模拟import uuid from reportlab.pdfgen import canvas def generate_invoice_pdf(invoice): filename finvoice_{invoice.invoice_no}.pdf c canvas.Canvas(filename) c.drawString(72, 800, fInvoice No: {invoice.invoice_no}) c.drawString(72, 780, fTitle: {invoice.title}) c.drawString(72, 760, fAmount: {invoice.amount}) c.drawString(72, 740, fTaxNo: {invoice.tax_no}) c.save() return filename上面这段是简化示例正式版你还需要考虑加表格、二维码查验、发票专用章图片以及把 PDF 上传到对象存储。发票状态从“待开”变为“已开”时把pdf_url回填到数据库用户在“我的发票”列表里可以直接预览下载。这个模块还有个细节容易被忽略发票金额必须和订单实付金额一致不能出现订单 100 元发票只开 80 元的情况。你可以在后端加一个校验开票列表只展示已经支付完成的订单并且相同订单不能重复开“未红冲”状态的发票。如果需要部分开票比如订单里包含多件商品但只开其中几件那就要引入“开票明细”表复杂度会明显提高论文里可以作为可选扩展。4.4 商家端管理功能建议管理端给商家账号登录后能看“我的店铺数据”最核心的是三块商品管理上架、下架、改库存、传图订单管理发货、查看售后结算管理查看已结算金额和待结算金额这个后台可以用 Django admin 快速实现论文截图好看演示也方便。真正写代码时你可以用 DRF 的ModelViewSet快速出接口配合 uniapp 再做一个商家版小程序或者干脆只做一个 Web 管理后台用 Vue 或直接 Django 模板都行——毕设评审关键看业务闭环通不通不是看端有多少。我见过不少项目做到最后学生连商家后台都没有演示时全靠手动改数据库非常被动。答辩时老师一定会问“商家怎么入驻谁审核”你说“还没做”青春就结束了。至少把入驻申请 管理员审核 冻结/解冻这三个接口做出来能演示就基本稳了。5. 小程序端核心页面与uniapp实战5.1 页面结构uniapp 项目在pages.json里这样配置页面{ pages: [ { path: pages/index/index, style: { navigationBarTitleText: 首页 } }, { path: pages/category/category, style: { navigationBarTitleText: 药品分类 } }, { path: pages/cart/cart, style: { navigationBarTitleText: 购物车 } }, { path: pages/order/list/list, style: { navigationBarTitleText: 我的订单 } }, { path: pages/invoice/list/list, style: { navigationBarTitleText: 发票列表 } } ], tabBar: { list: [ { pagePath: pages/index/index, text: 首页 }, { pagePath: pages/category/category, text: 分类 }, { pagePath: pages/cart/cart, text: 购物车 }, { pagePath: pages/user/user, text: 我的 } ] } }前端请求统一封装// utils/request.js const BASE_URL https://yourdomain.com/api; export function request(path, method GET, data {}) { return new Promise((resolve, reject) { uni.request({ url: ${BASE_URL}${path}, method, data, header: { Content-Type: application/json, Authorization: uni.getStorageSync(token) || }, success: (res) { if (res.data.code 0) { resolve(res.data.data); } else if (res.data.code 401) { uni.navigateTo({ url: /pages/login/login }); reject(res.data); } else { uni.showToast({ title: res.data.msg, icon: none }); reject(res.data); } }, fail: (err) reject(err) }); }); }这里有个提醒code别混用业务码 0 代表成功401 代表 token 过期。很多新手直接把 HTTP 状态码当成业务码用结果微信开发者工具里 200 和 0 乱成一团混沌世界。前后端约定统一 response 规范写进论文“接口设计规范”一节加分不少。5.2 搜索、分类和首页。首页可以放搜索框、轮播图、快捷分类入口和药品推荐列表。搜索接口建议用title模糊搜索同时关联到generic_name通用名。很多用户记不住商品名但记得“布洛芬”或者“感冒灵”所以 SQL 搜的时候用 OR 条件WHERE name LIKE %keyword% OR generic_name LIKE %keyword% OR spec LIKE %keyword%前端搜索页防抖是必须的。onSearch事件触发后 400ms 内不重复请求避免每个 keydown 都打一次后端。uniapp 里用clearTimeout和setTimeout简单实现即可。5.3 商品详情与处方药提示OTC 药品直接加购物车。need_prescription为 1 的处方药商品详情页要展示“处方药需凭处方购买”的提示提交订单时后端要校验用户是否已上传处方笺。如果论文要更完整处方笺可以是图片上传到对象存储由“药师”角色在后台审核审核通过后订单才能进入支付环节。前端在商品卡上可以用text标签展示“处方药”徽标单品购买按钮变成“立即问诊开方”点击后跳到上传处方页。这块设计能体现你对医药电商合规的思考是论文里的特色亮点。5.4 uniapp 微信小程序打包常见坑项目做完要发布到微信小程序HBuilderX 里点“发行 → 小程序-微信”会生成一个dist/dev/mp-weixin目录然后导入微信开发者工具。这里有几个高频问题包体积超过 2MB开发模式经常遇到主包超过 2MB 上限。解决办法一是使用分包加载pages/下无关紧要的页面比如发票详情、售后申请、商家入驻全部放进去subPackages二是图片资源走网络 URL不要本地 base64 塞一堆。配置文件里加{ subPackages: [ { root: packageA, pages: [ { path: pages/order/detail/detail, style: { navigationBarTitleText: 订单详情 } } ] } ] }调试麻烦HBuilderX 运行到小程序模拟器后会发现 uniapp 里console.log在开发者工具的 Console 面板不一定全打印那是因为 dist 代码被编译过。解决方式是打开开发工具的“ES6转ES5”和“增强编译”以及在manifest.json里打开“开发环境不压缩”选项。顶部导航栏高度不同机型胶囊按钮位置不同自定义导航栏时用uni.getSystemInfoSync()拿statusBarHeight再通过uni.getMenuButtonBoundingClientRect()拿胶囊按钮位置动态计算导航栏高度。这块不坑是不可能的2024 年了还是有不少机型适配差异。6. 常见问题与项目排错实录开发这种全栈项目遇到问题很正常。我把自己和身边人踩过频率最高的坑整理成速查表你直接对照排错。问题现象可能原因排查解决微信登录提示 code 无效后台appid/secret配错或code已过期确认小程序后台绑定了正确 appidcode有效期只有 5 分钟生成后立刻使用手机号获取失败 code not exist基础库版本过低或者不是真机环境基础库 2.21.2 以上才支持getPhoneNumber新接口模拟器有时不准上真机测支付成功但订单状态没变支付回调没写验签逻辑或回调地址没外网可达本地开发用内网穿透把回调 URL 暴露出去正式环境检查回调域名是否备案且在合法域名里多商家拆单后金额不对前端算总价时跨商家商品被合并计税前端按商家分组展示小计后端重新计算订单金额以前端展示为准以后端校验为准发票已申请但下拉为空status过滤器写错或者用户 ID 没传确认查询条件user_id status避免普通用户查到其他用户发票小程序发布后接口 404域名没在公众平台配置 request 合法域名小程序管理后台“开发管理→开发设置→服务器域名”里加白名单同时必须是 HTTPSuniapp 编译到微信小程序白屏可能是async/await被打包后不兼容在manifest.json里关掉“es6 转 es5”或改为 Promise 链式写法打开“编译时转换es5”还有一个容易被忽略的点微信开发者工具里默认的不校验合法域名勾选项会导致你本地调通但在真机上直接失败。养成一个好习惯——每次真机预览前先看一眼设置里这个勾选到底是开还是关。比如订单列表页用onShow刷新uniapp 里是这样onShow() { this.loadOrders(); }这个函数里写死async请求和排序逻辑就可能导致页面闪白。实际开发我可以给你建议onShow里只做轻量刷新最好加个锁变量避免重复请求onShow() { if (this.loading) return; this.loading true; this.loadOrders().finally(() { this.loading false; }); }7. 论文写作结构与答辩亮点规划7.1 论文章节大纲参考如果你需要论文大纲我建议这样安排第一章绪论。写药品电商行业背景、微信小程序生态发展、课题研究意义。这部分引用数据可以说“中国网上药店市场规模持续增长”之类但一定要找真实资料不能乱编。第二章相关技术介绍。Python、Django/Flask、uniapp、微信小程序、MySQL、Redis每项技术写两三段重点写“为什么选它”。第三章系统需求分析。功能性需求用户端浏览、搜索、购物车、下单、支付、发票商家端商品管理、订单管理、对账管理员端商家入驻审核、类目管理、平台监控非功能性需求安全性支付加密、HTTPS、越权拦截、稳定性。第四章系统设计。架构图、功能模块图、数据库 E-R 图、接口设计规范。第五章系统实现。每个模块放核心代码片段功能截图注意不要把整个文件代码贴进去会查重直接红了。第六章系统测试。测试环境、测试用例表登录测试、搜索测试、拆单测试、支付回调测试、发票生成测试、并发库存测试。第七章总结与展望。7.2 答辩高频问题准备答辩老师最爱问的四个问题提前自测问题一你这个系统的权限控制是怎么设计的答JWT 实现身份认证中间件对商家端接口校验role是否为商家管理员接口校验role是否为管理员。商家只能操作自己店铺下的商品和订单数据库查询强制加merchant_id条件避免水平越权。问题二如何处理库存并发扣减答Redis 原子操作 支付完成才扣减库存 同步 MySQL 记录事务里用SELECT ... FOR UPDATE做兜底。可以现场展示压测工具的测试结果这就是加分项。问题三发票功能是模拟的还是真实的答当前实现为模拟开票流程生成发票编号和 PDF 文件接口层已抽象了开票服务生产环境可替换为第三方税控 API。这个答法既诚实又能体现出可扩展性。问题四多商家拆单是怎么设计的答父子订单模型一次支付回调自动触发子订单同步支付每个商家独立结算。顺带回答结算周期和分账逻辑证明你想过这个问题。7.3 论文中的图表呈现建议论文里必须有三张图系统架构图、功能模块图、数据库 E-R 图。不需要用花哨的绘图工具不然生成的图会带水印或者格式混乱。我推荐用 ProcessOn 或者 draw.io 这类在线工具导出 PNG 透明背景。E-R 图重点标清楚用户与订单一对多、订单与商品多对多通过 order_item、商家与商品一对多、订单与发票一对一。运行截图不要只用模拟器截图要有真机截图、微信开发者工具控制台截图、Django admin 后端截图、MySQL 数据库表数据截图。截图里不要出现本地 IP 或未打码的手机号答辩时会显得很野路子。8. 项目后续的合理扩展方向如果时间充足这个商城系统可以朝这几个方向延展论文和答辩都会更丰满一是加“药品过期预警”模块。定时任务每天查expiry_date - today 90的商品给商家推送效期预警列表。这个功能对药品商城非常贴切实现也不复杂Django-celery-beat 配置一个每日任务查出来写一张预警表商家后台轮询即可。二是加“会员积分与优惠券”模块。积分来源是完成订单和评价优惠券分为满减券和折扣券下单结算时校验可用范围。这个能体现你对营销模型的理解跟通用商城拉开差距。三是加“商家结算账单”模块。每周/每月自动汇总商家子订单的应收、退款、实收生成结算单财务管理员确认后打入商家余额。这块业务价值高而且天然和发票模块呼应。数据库层面就是新增settlement表和settlement_item表代码量不大但故事完整。不过这几个方向有一个算一个都需要额外 2-3 周时间别一上来全加。先保证主流程跑通、答辩能用再根据自身时间挑选 1-2 个增强模块来加论文里放“系统扩展”一节写清楚设计思路就算赢。另外时间充裕的话把 MySQL 的慢查询日志开一下压测时看接口响应时间挑一两个超过 200ms 的优化下索引写进论文系统测试章节数据翔实图文并茂效果比空谈“系统稳定性很好”好一百倍。最后分享两个实在的经验。第一个经验是这个项目的难点其实不在写代码而在“你不知道你不知道什么”。多商家拆单、发票抬头校验、微信支付回调验签、处方药流程每一个模块都是独立的知识体系如果之前没接触过第一次做至少需要两周时间踩坑。所以建表阶段就要想清楚不要着急动手写接口。第二个经验是演示 demo 的前一天一定不要把时间花在加新功能上而是把主流程从注册、登录、搜索、加购、下单、支付、开票完整走三遍。新功能永远有 bugdemo 跑不通之前宁可砍功能也别赌临场发挥。这行干久了会发现项目能给人留下好印象的永远是稳定跑通的核心闭环而不是多少花哨功能。希望这篇分享能让你少走一些弯路项目顺利交差、答辩顺利过关。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进