
简介小玄猪商城是一套基于前后端分离架构的B2B2C商城系统面向中小型电商团队、独立开发者及需要快速搭建多端商城的创业者支持微信小程序、支付宝小程序、H5商城与APP商城多端覆盖。系统支持多商户入驻可承载直播商城、社交电商、团购拼团、秒杀砍价、活动报名、客户管理、知识付费、积分商城、抽奖、会员卡、权益卡、成长值、预售与任务中心等丰富业务场景采用TP6、VUE、element-vue-admin与uniapp技术栈代码结构简洁便于二次开发与功能扩展。资源包共约2000个文件以715个PHP后端逻辑、284个Vue前端组件、209个JS脚本为主另含Java、Go、SQL及大量PNG、SVG、GIF等静态资源与Markdown说明文档压缩包约42.39MB目录分层清晰。目前已有534人学习下载适合希望研究多商户商城架构、快速搭建自有电商平台或进行二次开发的开发者参考借鉴。1. 小玄猪商城的多端 B2B2C 架构一套后端怎么同时喂饱四个前端小玄猪商城是一套基于前后端分离的 B2B2C 商城系统支持微信小程序、支付宝小程序、H5 商城、APP 商城四个端。这个标题背后其实藏着一个很现实的问题多端商城最怕的不是功能少而是同一套业务逻辑被复制四遍改一个价格规则要动四个仓库。前后端分离在这里不是一句口号而是把「交易、库存、订单、支付、结算」这些核心能力收敛到一套 API 里四个端只负责渲染和调用。它适合正在做多端商城选型的技术负责人、需要把现有单端商城扩成多端的团队以及想搞清楚 B2B2C 和普通 B2C 在数据模型上差在哪的开发者。B2B2C 的关键在于平台、商家、用户三层角色共存订单要拆、结算要分账这决定了后端不能按单商户思路设计。2. 前后端分离下的 B2B2C 数据模型平台、商家、用户三层怎么落表2.1 为什么 B2B2C 不能照搬 B2C 的表结构普通 B2C 商城只有「用户-订单-商品」三条主线平台自己卖货钱进一个账户。B2B2C 多了一层商家商品归属商家、订单要按商家拆单、支付后要分账给商家、退款要按子订单退。如果直接把 B2C 的表拿来用最常见的翻车是订单表里塞一个shop_id就以为搞定了结果一个用户下单买了三个商家的商品支付一次、退款一次库存和结算全乱。正确的做法是把订单拆成两层主订单order记录用户、支付金额、支付状态子订单order_item或sub_order记录每个商家的商品、金额、发货状态、结算状态。支付回调只改主订单状态然后按子订单分发。这样分账时每个商家拿自己子订单的钱退款时也只影响对应子订单。商品侧同理goods表要有shop_id但分类、品牌这些公共维度可以平台统一维护商家只挂自己的商品。用户侧要区分平台用户和商家后台账号通常用同一张user表加role字段或者拆成user和merchant_account两张表看商家是否需要独立登录体系。2.2 核心表结构与字段说明下面这套表结构是我在多端商城里反复用过的精简版够跑通主流程字段按需扩展。-- 商家表 CREATE TABLE shop ( id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(64) NOT NULL COMMENT 店铺名称, status TINYINT DEFAULT 1 COMMENT 1正常 0关闭, settle_rate DECIMAL(5,4) DEFAULT 0.0500 COMMENT 平台抽成比例, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 商品表归属商家 CREATE TABLE goods ( id BIGINT PRIMARY KEY AUTO_INCREMENT, shop_id BIGINT NOT NULL COMMENT 所属商家, title VARCHAR(128) NOT NULL, price DECIMAL(10,2) NOT NULL, stock INT NOT NULL DEFAULT 0, status TINYINT DEFAULT 1 COMMENT 1上架 0下架, KEY idx_shop (shop_id) ); -- 主订单一次支付对应一条 CREATE TABLE order ( id BIGINT PRIMARY KEY AUTO_INCREMENT, order_no VARCHAR(32) NOT NULL UNIQUE, user_id BIGINT NOT NULL, total_amount DECIMAL(10,2) NOT NULL, pay_status TINYINT DEFAULT 0 COMMENT 0待支付 1已支付 2已退款, pay_channel VARCHAR(16) COMMENT wxpay/alipay, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 子订单按商家拆分 CREATE TABLE sub_order ( id BIGINT PRIMARY KEY AUTO_INCREMENT, order_id BIGINT NOT NULL, shop_id BIGINT NOT NULL, amount DECIMAL(10,2) NOT NULL, settle_status TINYINT DEFAULT 0 COMMENT 0未结算 1已结算, ship_status TINYINT DEFAULT 0 COMMENT 0待发货 1已发货 2已收货, KEY idx_order (order_id), KEY idx_shop (shop_id) );逻辑说明主订单只关心「用户付了多少钱、付没付」子订单关心「每个商家该发什么货、该拿多少钱」。支付回调进来先更新order.pay_status再遍历子订单把settle_status置为待结算。参数上settle_rate放在商家表分账时用sub_order.amount * (1 - settle_rate)算商家实收平台留抽成。order_no用时间戳加随机数生成别用自增 ID 暴露给前端。提示子订单金额之和必须等于主订单金额下单时就要校验否则支付回调对不上账。3. 一套 API 喂四个端微信小程序、支付宝小程序、H5、APP 的接口复用策略3.1 端差异到底差在哪哪些能复用四个端的差异集中在三块登录鉴权、支付调用、UI 渲染。业务逻辑商品、购物车、订单、结算几乎完全一致所以 API 设计的目标是让业务接口对端无感把端差异收敛到登录和支付两个适配层。登录方面微信小程序走wx.login拿 code 换 openid支付宝小程序走my.getAuthCodeH5 走账号密码或短信APP 走原生登录后拿 token。这四种最终都要换成一个平台统一的token后续接口只认这个 token。常见做法是后端提供一个/auth/login接口入参带platform字段wx/alipay/h5/app和对应凭证后端按 platform 分发到不同校验逻辑统一签发 JWT。支付方面微信小程序用wx.requestPayment支付宝小程序用my.tradePayH5 用微信 JSAPI 或支付宝网页支付APP 用 SDK。后端下单接口统一返回一个「支付参数包」前端按自己平台取对应字段。这样业务代码只写一次。3.2 统一登录接口的实现# 伪代码框架无关 def login(platform, credential): if platform wx: # credential 是 wx.login 拿到的 code openid wx_code2session(credential)[openid] user find_or_create_user(wx, openid) elif platform alipay: # credential 是 my.getAuthCode 拿到的 auth_code user_id alipay_auth(credential)[user_id] user find_or_create_user(alipay, user_id) elif platform h5: user verify_sms_or_password(credential) elif platform app: user verify_app_token(credential) else: raise BizError(unsupported platform) token sign_jwt(user.id, expire7*24*3600) return {token: token, user_id: user.id}逻辑说明platform是分发键credential是各端原始凭证。find_or_create_user按(platform, openid)唯一索引查没有就建保证同一微信用户多次登录不重复建号。JWT 里放user_id和过期时间别放敏感信息。参数上expire设 7 天是商城类常见值太长有安全风险太短用户频繁重登。注意微信小程序登录获取手机号是单独接口需要button open-typegetPhoneNumber触发拿到的是加密数据后端解密后才能用别和登录 code 混在一起。3.3 支付参数包的统一返回// 后端返回结构前端按 platform 取 { order_no: 202501011200001234, platform: wx, pay_params: { wx: { timeStamp: ..., nonceStr: ..., package: ..., signType: RSA, paySign: ... }, alipay: { tradeNO: ... }, h5: { redirect_url: ... }, app: { orderInfo: ... } } }逻辑说明后端一次生成所有平台的支付参数前端只取自己需要的。这样新增一个端时后端不用改接口只加一个字段。参数上pay_params里的字段名要和各端 SDK 要求严格一致微信的package是固定格式prepay_idxxx支付宝的tradeNO是预下单返回的。4. 多端商城的避坑与排查那些上线后才暴露的问题4.1 库存超卖并发下单时 stock 扣成负数现象秒杀或促销时同一商品被下单次数超过库存出现负库存。原因UPDATE goods SET stock stock - 1 WHERE id ?在并发下读到相同旧值。解决用UPDATE goods SET stock stock - 1 WHERE id ? AND stock 1判断影响行数为 0 就回滚。更稳的做法是库存放 Redis下单先扣 Redis异步落库。4.2 支付回调重复同一笔订单被处理两次现象用户支付后订单状态被改两次分账重复。原因支付平台会重试回调网络抖动时同一通知发多次。解决回调入口用order_no做幂等先查订单状态已支付就直接返回成功不再处理。数据库层面给order_no加唯一约束重复插入直接失败。4.3 小程序包体积超限uniapp 打包 source size 超过 2MB现象微信小程序上传时报source size 2612kb exceed max limit 2mb。原因主包塞了太多页面和图片。解决把非首屏页面拆到分包图片走 CDNuni-app里在pages.json配subPackages。主包只留 tabBar 页面和登录。4.4 多端 token 不通用H5 登录后小程序不认现象用户在 H5 登录切到小程序要重新登录。原因各端 token 存储和签发不统一。解决统一用后端签发的 JWT各端存本地请求头统一Authorization: Bearer xxx。别用各端自己的 session 机制。4.5 分账金额对不上子订单之和与主订单差几分钱现象分账时商家实收加起来比用户支付少或多几分。原因浮点计算或抽成四舍五入方式不一致。解决金额全用整数分存储抽成用floor或round统一规则最后一个商家用「总额减前面之和」兜底保证分账总和等于主订单。5. 多端商城的进阶技巧用一套配置驱动四个端的差异5.1 端能力配置表与其在代码里到处写if platform wx不如做一张端能力配置表把差异数据化。能力项微信小程序支付宝小程序H5APP登录方式wx.loginmy.getAuthCode短信/密码原生 token支付方式requestPaymenttradePayJSAPI/网页SDK分享onShareAppMessageonShareAppMessage复制链接原生分享推送订阅消息模板消息无厂商推送包体积限制2MB 主包2MB 主包无无前端启动时拉这张表按当前 platform 决定走哪条分支。新增端只加一列不改逻辑。5.2 用环境变量区分端构建# 微信小程序构建 UNI_PLATFORMmp-weixin npm run build # 支付宝小程序构建 UNI_PLATFORMmp-alipay npm run build # H5 构建 UNI_PLATFORMh5 npm run build逻辑说明UNI_PLATFORM是 uniapp 的编译目标构建时注入不同常量代码里用process.env.UNI_PLATFORM判断。参数上各端构建产物目录不同CI 里按端分别打包上传别混在一起。5.3 接口版本与端灰度多端上线节奏不一致时接口要支持版本。URL 里带/api/v1/新端用 v2 时老端不受影响。灰度时按platform加version做路由比如微信小程序先切 v2H5 继续 v1观察一周再全量。我自己的习惯是任何多端项目先把登录和支付两个适配层写死、写透再动业务代码。这两个地方翻车后面全是血泪。库存和分账的幂等上线前必须用脚本压一遍别等用户投诉才发现。希望帮到你。本文还有配套的精品资源点击获取