Nexora · ERP 架构现场审计 · 2026-06-09
两脉 ERP,只有一条真的会多租户。
本机 ~/repos/ 实证对比:pyerp 是唯一具备运行时多租户的 ERP;囍铺主线虽然代码里有大量 aid 字段,但控制器里那个开关从来没有打开。
实证来源:本机源码 + git log + md5
文档基线:Nexora 代码架构总览(已同步更新)
一、两脉对比
文档原本写"四套 ERP 同源",但实际只有两条不同源的代码主线,能力差距很大。
真 · 运行时多租户
pyerp 主线
单仓库 · 自带租户上下文 · 已在 prod 跑通多年
pyerp_php
pyerp_php_api
pyerp_web
pyerp_app
- ✓aid(顶级租户)+ bid(业务方)双层注入,BaseController 自动从 URL/header 取,全局常量。
- ✓admin 表 = 租户表,带 endtime 订阅过期、status 启停、domain 多域名。
- ✓pt_type 三档行业版本:金属版 / 料部 / 企业版,菜单按版本切。
- ✓独有贵金属子系统:
Ymetal* 系列 34 个 controller + 40+ 张表。
伪多租户 · 字段空跑
囍铺主线
三仓库分叉 + 一仓库直接复用 · 每来一个客户拷一份代码
xipu_erp_php
baijian_php
xylferp_php
hxerp(共用 xipu)
- ✗BaseController 不注入 aid / bid。代码里 1896 处
where('aid', aid) 全程拿到空常量,过滤等于没写。
- ~前端有
$base.defaultPath.indexOf('xylf') 这种客户名硬编码 if,控制字段显隐——是想做多租户但只做到一半的证据。
- ✗"支持多客户"的现实方法:拷代码 + 拷 docker + 一个独立 MySQL 库(hxerp / 周锦记 / 张家界全是这模式)。
- ✗无贵金属子系统,无订阅过期机制。
二、囍铺脉真实血缘
md5 + git log 实证表明,xylferp 才是起源,xipu 和 baijian 都是后来一次性 squash 拷出来的。
xylferp_php · 仙游龙凤
2025-11-22 起源 · 113 commits
保留完整 git 历史,至今仍在迭代。前端定制最深,独有"产品标识码、模具号、证书编码"等字段。
xipu_erp_php · 囍铺
2026-02-09 squash · 11 commits
囍铺主仓 + 鸿星黄金共用此代码(仅换库)。新增 Aliyunimagesearch.php 是多客户改造起点。
baijian_php · 摆件
2026-02-09 squash · 4 commits
controller 全是 xipu/xylferp 的子集,没有自己独特的功能。
字节级证据:三个仓库的 BaseController.php md5 完全一致(b0c3ff0c…),74 个 controller 中 56 个三方字节相同,剩下 18 个核心业务 controller(Goods / Buy / Goodsoutbound / Retreat 等)已被各自改过。
三、客户独有定制
每个分叉沉淀了什么客户特有的东西。
起源仓 · 定制最深
xylferp_php
仙游龙凤
- 独有
Config.php 系统参数 controller
- 独有
ScoreConfig.php 积分配置 controller
- 前端独有字段:产品标识码、模具号、证书编码、副编码
- "标签价 / 预售价"称呼按 xylf 切换
主仓 · 多客户改造起点
xipu_erp_php
囍铺(+ 鸿星 + 周锦记)
- 独有
Aliyunimagesearch.php:以图搜图按客户读 AK
- 新增
xipunum_aliyun_imagesearch 配置表
- 鸿星黄金不另开仓库,docker 直接挂这份代码连不同库
- 周锦记/张家界部署同模式:拷代码 + 独立 docker + 独立库
子集仓 · 无独特功能
baijian_php
摆件
- 无独有 controller
- 是 xipu / xylferp 的子集
- 同名 controller 也被微调过(Goods / Buy 行数都不同)
- 合计只有 4 个 commit,几乎只做最小适配
四、三家客户从业务上加了什么
不看代码看业务——主线是"黄金珠宝零售"的标准 ERP,三家在各自实际经营中往里塞了哪些主线没有的功能。每条配上线时间,并标注来自哪个仓库。
业务上比主线多出来的功能 (过去 8 个月,按业务模块归类)
财务报表 · 多门店化
-
2026-06-07
财务报表查询加速,筛选条件 + 样式重做(销售员 App)
-
2026-06-05
财务页面整体改版,连续 5 天 12 次提交(Kotlin 后端 + 销售员 App)
-
2026-06-01
多门店财务报表,原来只能单店看,现在按门店汇总(Kotlin 后端)
-
2026-05-31
多门店导购业绩汇总,跨门店导购排名(Kotlin 后端 + 销售员 App)
-
2026-04-03 → 04-08
订单财务数据后台定时汇总,从手动算改后台跑批,首页直接看(Kotlin 后端)
单据打印 · 全链路改造
-
2026-05-27
云打印机门店级配置,判断门店有没配云打印机决定打印路径(Kotlin 后端)
-
2026-05-27
打印 PDF 操作日志,记录谁在哪台打印什么(Kotlin 后端)
-
2026-05-22 → 05-28
自定义单据模板系统,连续一周 8 次提交做完整个模板引擎(Kotlin 后端)
-
2026-05-24 → 05-25
手机端单据打印 + 导出 PDF + 预览,移动端打印从无到有(销售员 App)
-
2025-10-27
批量打印标签,支持正序倒序(PC 前端)
销售 / 置换 / 回收 三大单据扩展
-
2026-05-13
新增"是否开发票"字段,单据带发票标记(Kotlin 后端)
-
2026-05-11 / 05-12
销售订单"优惠金额"字段,公式 = 应收 − 实收(Kotlin 后端)
-
2026-05-09
销售/置换/回收 操作日志,单据级日志(Kotlin 后端)
-
2026-05-08
销售/回收单"其他费用"字段,应对杂费场景(Kotlin 后端)
-
2026-05-07
置换/回收"折旧费/克 + 折旧金额"字段,旧金抵换计价(Kotlin 后端)
-
2025-11-09
回收并入销售单子菜单,工作流重组(PC 前端)
盘点 · 入库审批 · 库存
-
2026-06-02
手机盘点按盘点员筛选,门店主管做盘点责任追溯(PC 前端 + PC 后端)
-
2026-05-30 / 05-31
临时盘点单 + 盘点货品问题修复(Kotlin 后端 + 销售员 App)
-
2026-05-15
入库订单审批流,订单要审核才入库(Kotlin 后端)
-
2026-04-15
多库房经营改造,商品/调拨/销售全链路加库房筛选(PC 后端 + PC 前端)
会员 · 销售员 App · 收银
-
2026-04-22
会员"结料 / 结款 / 充值"功能,会员账户从只读变可操作(销售员 App)
-
2026-04-22
销售价/回收价拆开维护,金价波动期灵活定价(PC 前端)
-
2026-06-07
销售员 App 上线 H5 版,容器化部署,#ifdef H5 隔离不影响原生 APP(销售员 App)
-
2025-11-17
用户级开启微信小程序码,给会员发个人专属码(PC 前端)
-
2025-11-17
收银输入框点击全选,小优化提速收银(PC 前端)
安全 · 多客户基建(最近开始的方向)
-
2026-06-09
按客户走以图搜图配置,每家客户用自己的阿里云图像搜索账号 —— 是囍铺脉真正第一次尝试"配置化多客户"(PC 前端 + PC 后端)
-
2025-12-23
用户类型加"股东"身份,对应不同查看权限范围(PC 前端)
-
2025-11-25
登录加谷歌验证器,二次验证(PC 前端)
-
2026-05-29
清除 ThinkPHP webshell 后门,三家都做了同一动作(PC 后端)
业务上比主线多出来的功能
无。从 2026-02-09 拷出来到今天一个业务功能都没加 —— 前端仓 4 个月零提交,后端只有"清后门"和"配 CI"这种维护性 commit。
推断:当年想给摆件业务留代码位置,但实际项目没启动或被搁置。这份代码相当于一份过期半年的囍铺骨架快照,如果以后真要做摆件 ERP,应该基于最新 xipu 重新分一份,或直接走多租户复用。
业务上比主线多出来的功能 (2025-11 → 2026-01 开发期,按业务模块归类)
工厂体系 · 仙游龙凤最大特色
-
2025-12-09 / 12-10
工厂管理上线,连续两天 4 次提交,把"工厂"做成独立维度(PC 前端 + PC 后端)
-
2026-01-07
修复工厂相关逻辑(PC 后端)
-
起源就有
以工厂为核心的代加工链路。整个采购 / 结算 / 对账以"工厂"为维度:维护工厂档案、工厂金价成色、工厂简写、工厂分类、欠款情况、按工厂筛选所有单据。这是零售 ERP 没有的工厂端能力。
一物一码追溯
-
2026-01-08
副编码功能,给商品加流转辅助标识(PC 前端 + PC 后端)
-
起源就有
追溯四件套:产品标识码 (出厂) + 模具号 (生产模具) + 证书编码 (鉴定证书) + 副编码 (流转)。证书号支持检索,可反查到生产工厂和模具批次。
-
起源就有
镶嵌作为独立业务字段。"是否镶嵌"开关 + 主石数量 / 主石重量 / 纯度,参与计价和品质追溯。零售 ERP 里这些只是商品备注。
回收 / 销售 / 积分
-
2025-12-01
回收名称改用 id,回收业务字段规范化(PC 前端)
-
2026-01-07
回收统计页,专门的回收数据汇总(PC 前端)
-
2025-11-23 / 11-24
积分系统起步,按时间段查询积分规则(PC 前端)
-
2025-12-12 / 12-13
积分配置后台,连续 2 天 3 次提交完成(PC 前端)
-
2025-12-16
分类层级支持积分配置,按品类设积分(PC 前端)
-
2025-12-10
销售价改造(PC 前端)
-
2025-12-30 / 12-31
计算公式更新(金价计价相关)(PC 前端)
-
2026-01-12
计算逻辑更新(PC 后端)
-
起源就有
历史采购老数据导入,专门的"老数据"页面把上一代系统的采购单导进新系统。
基础配置 · 权限 · 安全
-
2025-11-23
店铺、岗位管理(PC 前端)
-
2025-11-23
商品分类增删改(PC 前端)
-
2025-12-07
分类排序(PC 前端)
-
2025-12-01
登录加谷歌验证器,比囍铺早 25 天(囍铺 2025-12-26 才上)(PC 前端)
-
2025-12-10
权限认证改造(PC 前端)
-
2025-12-27
统一"导购"和"业务员"概念,组织角色简化(PC 后端)
-
2026-05-29
清除 ThinkPHP webshell 后门,与囍铺 / 摆件同步做的安全补丁(PC 后端)
打印 · 入库 · 商品图片
-
2025-11-23
商品图片上传 + 以图搜图。2025 年 11 月就做过一版"上传图片找相似商品"。注意——比囍铺 2026-06 才做的同名功能早 7 个月,但这套实现没回流到囍铺,囍铺 6 月又从头做了一遍。
-
2025-11-29
打印模块上线(PC 前端)
-
2025-12-02
更新打印 + 更新入库(PC 后端)
-
2025-12-15
打印细节调整(PC 前端)
-
2026-01-09
点击聚焦优化(PC 前端)
-
2026-01-21
显示保存按钮(PC 前端)
📌 业务视角下的核心问题
囍铺生态过去 8 个月真的很活跃 —— 仅 Kotlin 后端 + 销售员 App 就 100+ 个业务 commit,覆盖财务、打印、销售单据、盘点、会员、移动端 6 大模块。但这些好功能没回流到仙游龙凤 / 摆件。反过来仙游龙凤在 2025-11 ~ 2026-01 那 2.5 个月密集开发期沉淀的"工厂体系 / 追溯四件套 / 回收业务 / 积分系统"对囍铺接 OEM 客户也用得上,也没回流过来。最戏剧的是以图搜图——仙游龙凤 2025-11 就做过,囍铺 2026-06 又从头做了一遍。谷歌验证器也是仙游龙凤 12-01 先上,囍铺 12-26 又自己做了一版。三个分叉之间谁都拿不到对方的好东西,这是"拷代码"模式最致命的副作用。
五、多租户演进路线
给囍铺主线接上真正的多租户能力,按风险从低到高分四档。每一档都可以独立交付。
P0
通管道
把 pyerp 那 8 行 aid/bid 注入逻辑搬进囍铺主线 BaseController。不传 aid 时默认 1,单租户用户行为完全不变,但拿到了往下走的基础。
1 天 · 零风险
P1
配置按租户
OSS、ImageSearch 等配置表加 aid 字段,按 Host 头自动选对应客户的配置。解决"每装一个客户改一处代码"的问题。
1 周 · 低风险
P2
同库加客户
用户、菜单、角色三张表的 aid 引用接通。新增客户从此不再需要新开机器和新建库,控制台 INSERT 一行 admin 即可。
2–3 周 · 中风险
P3
业务全隔离
单据、库存、商品、客户等业务表全部按 aid 隔离,完全等同 pyerp 已经跑通的方案。等真有客户规模再做。
数月 · 大改
⚠ 风险提示
pyerp 现有的 8000+ 处 where('aid', aid) 是行级隔离的反面教材——一旦某处漏写就会跨租户串数据。囍铺主线接多租户时应该用 ThinkPHP model 全局 scope 一次性挂上 aid 过滤,不要靠人肉守纪律每处都写。
⚠ 配套建议
不要再继续"每来一个客户就拷一份代码"。三个分叉已经分化到 56/74 一致率,再分下去同步成本爆炸——昨天周锦记以图搜图的补丁就只打到了 xipu 一个仓库,baijian / xylferp 没动。
六、手机端多租户
PC 后台是同源相对路径,装哪个域名就连哪个,天然适配多客户。手机端不一样——原生 APK 的后端候选清单硬编码在前端,永远只能连这 3 个囍铺地址,所以周锦记目前只能走 H5 浏览器,发原生 APK 给周锦记是连不上的。
🔍 现状(app_xiao_shou_kotlin/src/uilts/login/loginUtils.js:7)
export const LOGIN_HOST_CANDIDATES = [
'erp.xipugold.com',
'rjerp.xipugold.com',
'47.119.139.162:25231',
];
最终方案 · 登录时选择服务器
实现步骤
-
阶段 1 · 前端
服务器清单先写死在前端 JSON 数组里(因为后端还没分多租户,做接口不顺手)。直接在 loginUtils.js 里维护一份 SERVER_LIST = [{name:'囍铺集团',host:'erp.xipugold.com'},{name:'周锦记',host:'zjj.py99999.com'},...],登录页拿来填下拉框。
-
阶段 1 · 前端
登录页加下拉「选择服务器」,用户选完把 host 写本地存储 (uni.storage),后续 LOGIN_HOST_CANDIDATES 直接读本地存储里那一项。老用户升级 App 后没选过 → 默认走囍铺第一个地址,行为不变。
-
阶段 1 · 运维
新增客户走代码改动:在 SERVER_LIST 里加一行 → 重发 APK。虽然要重打包,但每个客户共用同一个 APK,比"每家定制打包"省得多。
-
阶段 2 · 等多租户后端
将来后端按本文档第五节走完 P0/P1 后,把写死的 JSON 改成调后端 /api/servers 接口,由后端返回当前可用客户清单。新增客户从此后端配一行即可,APK 不动。
📌 与第五节多租户路线的关系
这套手机端方案跟后端多租户改造解耦推进——阶段 1 (前端写死) 今天就能落,不依赖后端任何改动;阶段 2 接后端接口要等 P1「配置按租户」做完。所以可以马上把周锦记的原生 APK 这条路打通,不卡后端进度。