Java 重构与运营后台 · 实施计划
结论:门店端前端不动,只换后端;运营后台新写。 六个阶段,每阶段都能独立跑起来看效果, 总计约 48 人日 / 10–11 周(单人)。期间现有 Python 版继续对外演示和试跑,不停摆。
进度:P0 ✅ · P1 ✅ · P2 ✅ · 门店端页面已接 ✅ · P4 后台可管 ✅(2026-11-10)。
P0 = 骨架(登录 / 租户隔离 / 订阅状态 / 到期策略 / 后台只读);
P1 = 核心(客户 / 车辆 / 价目表 / 工单 / 状态机 / 结算 / 交车 / 提醒);
P2 = 增值(配件库存与领料、成本毛利、员工提成、营业大屏、客户看板、预约、打印数据、客户导入);
门店端 16 个页面已指向 Java 后端并逐页走查(开单 → 开工 → 完工 → 收款 → 交车、领料退料、打印、提成、大屏、看板、预约、设置);
P4 = 运营后台写操作(建店 / 续费换套餐 / 到期策略 / 停用恢复 / 冒充登录 / 收款 / 审计 / 套餐改价)。
接口验收 136 项全绿(P0 27 + P1 33 + P2 46 + P4 30),线上
qxdemo.agent2.0755xzb.club 跑通。
剩下:车主端公开页(预约 / 查进度 / 报价)与短信验证码。
1 这份文档要你确认什么
| 要确认的 | 我的建议 |
|---|---|
| 语言与框架 | Java 21 + Spring Boot 3.3 + MyBatis-Plus + PostgreSQL 16 |
| 前端怎么办 | 不重写。现有 Vue3 手机端只改 API 地址,页面一行不动 |
| 分几步做 | 6 步(P0 骨架 → P5 上线),每步有可验收的产物 |
| 三档套餐 | 按你给的报价:6800/12800/39800 建设 + 1800/2800/9800 年费,功能开关见第 6 节 |
| 到期怎么处理 | 后台按租户配:正常 + 横幅提醒 / 只读 / 禁止登录;默认「只读 + 7 天宽限」 |
2 原则:是重构,不是翻译
最省事的做法是把 Python 的 2000 行逐段翻成 Java——那会得到一套更重、更慢、更难改的系统。这次换语言的价值在于三件事,只有这三件事值得做:
- 订阅体系进内核。Python 版没有任何「套餐/到期」概念,现在只能在外部用表格管。Java 版把租户生命周期做成一等公民,到期自动限权。
- 并发与数据安全。PostgreSQL + 连接池 + 事务,替代单机 SQLite 的串行写;租户隔离用拦截器强制注入,而不是每个 SQL 手写
tenant_id=?。 - 可交付性。jar + docker compose 一键部署,甲方 IT 看得懂;迁移脚本、审计日志、接口文档齐全。
明确不做:不换前端、不做微服务、不上 Redis/MQ、不做多活。单店规模用不上,加了只会让运维更难。
3 技术选型(已定)
| 层 | 选择 | 为什么 |
|---|---|---|
| 语言 / 运行时 | Java 21 LTS | 长期支持,虚拟线程可用,Spring Boot 3 要求 17+ |
| 框架 | Spring Boot 3.3.x | 生态最全,招人最容易 |
| 持久层 | MyBatis-Plus | 现有逻辑全是手写 SQL,迁过来几乎能照抄;JPA 反而要重写映射 |
| 数据库 | PostgreSQL 16 | 免费、JSONB 存功能开关、并发好;比 MySQL 更适合多租户 |
| 迁移 | Flyway | 版本化 DDL,甲方环境升级可追溯 |
| 鉴权 | Spring Security + JWT | access 2 小时 / refresh 30 天;门店端与运营端两套密钥 |
| 门店前端 | 现有 Vue3(不动) | 只把 baseURL 指向 Java 服务 |
| 运营后台前端 | Vue3 + Element Plus | 表格/表单/筛选是后台的主场景,Element 最省时间 |
| 部署 | docker compose(app + pg + nginx) | 单机可跑,连锁也能横向加一节点 |
| 监控 | Actuator + 日志轮转 + pg_dump 定时 | 够用,不引入 Prometheus |
4 六个阶段的实施计划
每一阶段结束都有能点开看的东西,不是等到最后才联调。工期为单人净开发日。
| 阶段 | 交付物 | 范围与验收 | 工期 |
|---|---|---|---|
| P0 骨架 |
工程骨架、数据库、鉴权、OpenAPI | 多模块 Maven(core / store-api / admin-api);Flyway 建表;JWT 登录打通;
租户解析拦截器(tenant 只从 token 取,绝不从 URL 取);统一响应 {ok,data,error};
Swagger 可访问。验收:登录拿 token → 调 /me 返回租户列表 |
4 天 |
| P1 核心业务 |
客户、车辆、项目、工单、结算 | 开单(车牌自动带客户)、状态机 created→in_progress→pending_pay→done、 结算事务(写工单+客户累计+保养提醒)、提醒列表、价目表 CRUD。 验收:用现有演示数据走完「开单→开工→完工→收款」,金额与 Python 版逐分对齐 | 12 天 |
| P2 增值业务 |
配件、提成、大屏、客户看板、预约、交车、打印、导入 | 领料扣库存与成本进毛利;提成规则与结算计提;大屏 5 指标 + 7 天趋势; 客户看板脱敏;预约到店与转工单;交车与「待交车」阶段;A5/A4 打印数据;CSV 导入。 验收:与 Python 版同一套截图逐项对照,数字一致 | 10 天 |
| P3 公开端 |
报价页、H5 预约、查进度、openid | 无登录接口 /pub/**:门店信息、自助预约(限频)、车牌+尾号查进度(无金额)、
报价 token 页与确认回写、openid 绑定。
验收:手机微信里打开能约、能查,抓包里看不到任何金额 |
6 天 |
| P4 运营后台 |
租户/套餐/订阅/收款/到期策略/审计 | 见第 8 节页面清单。核心是订阅校验拦截器:到期后门店端按策略返回 402/403 并在页面顶部挂横幅。 验收:后台把某店改成「到期 + 只读」,该店立刻不能开单但能查;改回正常立刻恢复 | 10 天 |
| P5 迁移上线 |
数据迁移、双跑、压测、文档 | SQLite → PG 迁移脚本(客户/车辆/工单/明细/配件/提成/预约);两套并行 1 周对账; 50 并发压测;备份与恢复演练;部署手册 + 运维手册。 验收:迁移后订单数、金额合计、客户数三项完全一致;恢复演练能在 10 分钟内还原 | 6 天 |
| 合计(不含缓冲) | 48 天 | ||
按每周 5 天计 = 9.6 周;加上联调、评审、甲方反馈,现实排期 10–11 周。若并行招一个前端做后台页面,可压到 8 周。
5 多租户与订阅模型
沿用「共享库 + tenant_id」——门店数量在几十的量级,分库是负担。关键是隔离由框架保证,不靠人记得写。
| 表 | 关键字段 | 说明 |
|---|---|---|
| tenant | id, name, city, phone, address, bays, status, created_at | status: trial / active / grace / readonly / suspended |
| plan | code, name, build_fee_cents, year_fee_cents, max_bays, max_staff, features(jsonb) | 三档套餐,功能开关放 JSONB |
| subscription | tenant_id, plan_id, started_at, expires_at, grace_days, expire_policy, auto_renew | expire_policy: warn / readonly / block |
| tenant_contact | tenant_id, owner_name, phone, wechat, address, signer, note | 你要的「客户联系方式」 |
| payment | tenant_id, amount_cents, period_from, period_to, method, paid_at, note | 先手工记账,不接支付 |
| audit_log | actor, action, target, before, after, ip, created_at | 谁改了谁的套餐,可追溯 |
租户隔离怎么保证:MyBatis-Plus 的 TenantLineInnerInterceptor 自动给每条 SQL 追加 tenant_id = ?,
值来自 JWT 解析出的上下文;URL 里出现的 tenantId 只用于校验是否属于该用户,不参与取数。
这样即使某个新接口忘了写条件,也不会串店。
6 三档套餐与功能开关
按你给的报价,建设费一次性、年费按年。功能按「店里真的会用到的」划,不要用虚的功能数量区分。
| 项目 | 轻量版 | 标准版 | 连锁版(3 店) |
|---|---|---|---|
| 建设费 | ¥6,800 | ¥12,800 | ¥39,800 |
| 年费 | ¥1,800 / 年 | ¥2,800 / 年 | ¥9,800 / 年 |
| 门店数 | 1 | 1 | 3 |
| 工位上限 | 6 | 12 | 12 / 店 |
| 员工账号 | 5 | 15 | 不限 |
| 工单 / 结算 / 提醒 | ✓ | ✓ | ✓ |
| 打印接车单 / 结算单 | ✓ | ✓ | ✓ |
| 客户导入 | ✓ | ✓ | ✓ |
| 配件库与领料 | — | ✓ | ✓ |
| 员工提成 | — | ✓ | ✓ |
| 客户看板(挂墙) | — | ✓ | ✓ |
| 客户 H5(预约 / 查进度) | — | ✓ | ✓ |
| 老板营业大屏 | — | ✓ | ✓ + 总部看板 |
| 跨店客户 / 统一价目表 | — | — | ✓ |
功能开关存在 plan.features(JSONB),门店请求到未开通的接口返回 403 FEATURE_LOCKED,
页面按提示「该功能在标准版及以上可用」。这样升级套餐不用改代码,后台点一下即可。
7 到期策略(后台可配)
你要求「后台配置型」,所以策略是租户级字段,不是硬编码。三档行为:
| 策略 | 门店端表现 | 接口行为 | 适用 |
|---|---|---|---|
| warn 提示 | 功能全开,页面顶部常驻黄条「服务已到期,请续费,否则 X 天后停用」 | 全部 200,但响应带 subscription: {expired:true, days_left:-N, policy:'warn'} | 刚到期、在谈续费 |
| readonly 只读(默认) | 能看能查,所有「保存/开工/收款/交车」按钮置灰并说明原因 | GET 200;写操作 402 PAYMENT_REQUIRED,body 说明到期日与续费入口 | 到期默认策略 |
| block 禁止登录 | 登录页提示「账号已停用,请联系门店管理员」,不给验证码入口 | 登录 403 ACCOUNT_SUSPENDED;已登录的 token 立即失效 | 欠费久拖、主动停服 |
另外两个配套开关:
- 宽限期(
grace_days,默认 7):到期后先进入 grace,行为同 warn,7 天后再落到配置策略。避免客户月底忘交钱就直接不能用。 - 到期提醒:后台列表按「剩 30 / 7 / 1 天」分组,支持一键复制催费话术;后续接短信或微信模板消息(需公众号资质)。
一定要做对的一点:限权必须在服务端。前端把按钮藏起来只是体验,接口仍要拦。
Python 版现在没有这层,所以这次把「订阅检查」做成拦截器,放在业务逻辑之前——绕过它的唯一办法是改代码。
8 运营后台页面清单
| 页面 | 内容 |
|---|---|
| 1. 登录 | 运营人员账号(与店主账号两套体系),支持二次验证(预留) |
| 2. 租户列表 | 搜索(店名/城市/电话)、状态筛选、到期倒计时(剩 ≤7 天标红)、套餐、客户数、最近登录 |
| 3. 租户详情 | 门店信息 + 联系人 + 套餐与到期 + 用量(客户/工单/员工/工位数)+ 订阅历史; 操作:续费、换套餐、延长试用、改到期策略、停用/恢复、冒充登录看数据、重置店主密码 |
| 4. 新建租户 | 填店名/城市/电话 + 选套餐 + 设试用天数 → 一键生成店主账号并初始化价目表 |
| 5. 套餐管理 | 三档的价格、工位/员工上限、功能开关(勾选式),改完即时对所有新订阅生效 |
| 6. 到期提醒 | 按剩余天数分组,显示负责人与电话,一键复制催费话术 |
| 7. 收款记录 | 手工登记:金额、期间、方式、经手人;租户详情里能看到累计实收 |
| 8. 审计日志 | 谁在什么时候改了哪个租户的什么字段,前后值对比 |
9 数据迁移与上线
- 迁移脚本:SQLite 导出 → 字段映射 → 灌入 PG。规则:租户 id 保留(t1/t2/t3),工单号保留, 金额(分)原样,时间保留;自增 id 重新生成并建映射表,供迁移报告核对。
- 对账三项:工单数、收款合计、客户数。三项一致才算迁移成功,缺一不可。
- 双跑一周:新系统只读,旧系统继续写;每天跑一次增量同步 + 对账,观察差异。
- 切换窗口:选门店打烊后 1 小时,冻结旧系统写入 → 最后一次增量 → 切 DNS/反代到 Java 服务 → 冒烟测试 10 项。
- 回滚方案:反代配置保留旧服务 7 天,出问题 5 分钟内切回。
10 风险、工期与报价
| 风险 | 影响 | 应对 |
|---|---|---|
| 工期滑点 | 3 个月没有新单 | 每阶段可演示;P1 结束就能替换核心业务,不必等全部完成 |
| Java 无人维护 | 后续改动变慢 | 只用主流组合,不写自研框架;接口与表结构文档随代码走 |
| 迁移丢数据 | 客户信任崩塌 | 三项对账 + 双跑一周 + 7 天回滚窗口 |
| 过度设计 | 成本膨胀 | 不做微服务、不上 Redis/MQ、不做多活 |
| 口径 | 金额 | 说明 |
|---|---|---|
| 开发总量 | 48 人日(10–11 周) | 单人;含后台前端 |
| 对外报价(自建) | ¥90,000 – ¥130,000 | 按 1,800–2,600 元/人日,含迁移与上线 |
| 只做客制化后台(不动后端) | ¥15,000 – ¥25,000 | 2 周,作为对比项给你参考 |
| 私有化部署(甲方机房) | +¥20,000 – ¥40,000 | 含安装、数据迁移、培训、一年远程支持 |
11 待你拍板的 5 件事
- 前端不重写(现有 Vue3 只改 API 地址)——同意 / 不同意
- MyBatis-Plus 而非 JPA(迁移更快,逻辑可照抄)——同意 / 不同意
- 套餐功能划分(第 6 节表格):轻量不含配件/提成/看板/H5,标准全含,连锁加总部能力——照此执行 / 需要调整
- 到期默认策略:只读 + 7 天宽限,后台可改——照此执行 / 改成别的默认
- 连锁版的「总部看板」要不要放进 P4(会多 2–3 天)——要 / 不要
这 5 条定了,P0 当天就能开工:先把工程骨架、数据库、登录和租户拦截器做出来给你看。