feat: add request.js utility, service page, and fix hospital image URLs
- Add request.js for unified API calls with loading/error handling - Add service page (service type listing) - Fix hospital list to load from API with proper image URL construction - Add service types dynamic loading on index page - Various mini program improvements (order, care, wallet pages) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
68
docs/SpringSecurity权限配置踩坑记录.md
Normal file
68
docs/SpringSecurity权限配置踩坑记录.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# Spring Security anonymous() vs permitAll() 踩坑记录
|
||||
|
||||
## 现象
|
||||
|
||||
后台管理系统登录后,访问 `业务管理 > 医院管理` 页面提示"系统接口异常",后端返回:
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "2026-05-25T03:08:28.944+08:00",
|
||||
"status": 403,
|
||||
"error": "Forbidden",
|
||||
"path": "/system/hospital/list"
|
||||
}
|
||||
```
|
||||
|
||||
直接用 curl 不带 token 调用接口正常返回 200,但带上 JWT token 就返回 403。
|
||||
|
||||
## 根因
|
||||
|
||||
`SecurityConfig.java` 中 `/system/hospital/list` 被配置为 `.anonymous()`:
|
||||
|
||||
```java
|
||||
.antMatchers("/login", ..., "/system/hospital/list", ...).anonymous()
|
||||
```
|
||||
|
||||
**Spring Security 中两种访问控制的区别:**
|
||||
|
||||
| 配置 | 含义 | 匿名用户 | 已认证用户 |
|
||||
|------|------|----------|------------|
|
||||
| `.permitAll()` | 所有用户均可访问 | 允许 | 允许 |
|
||||
| `.anonymous()` | 仅匿名用户可访问 | 允许 | **拒绝(403)** |
|
||||
|
||||
当后台管理员登录后,JWT 过滤器为请求注入了认证信息(不再是匿名用户),Spring Security 判定已认证用户无权访问 `.anonymous()` 资源,返回 403。
|
||||
|
||||
而小程序端调用该接口时不带 token(匿名),所以一直正常。
|
||||
|
||||
## 修复
|
||||
|
||||
将需要同时被"小程序(匿名)"和"后台(已认证)"访问的接口,从 `.anonymous()` 移至 `.permitAll()`:
|
||||
|
||||
```java
|
||||
// 仅匿名用户 —— 登录、注册、验证码等
|
||||
.antMatchers("/login","/appLogin","/system/msm","/smsLogin",
|
||||
"/register","/captchaImage","/weixinLogin","/getUserToken",
|
||||
"/system/weixin/wxPayNotify","/system/weixin/wxRefundNotify")
|
||||
.anonymous()
|
||||
|
||||
// 所有用户均可访问 —— 被小程序和后台共同使用的数据接口
|
||||
.antMatchers("/system/user/getAppIndexInfo","/system/hospital/list",
|
||||
"/system/config/configKey/**","/system/nursing/published",
|
||||
"/system/nursing/view/**","/system/serviceType/enabled")
|
||||
.permitAll()
|
||||
```
|
||||
|
||||
## 经验总结
|
||||
|
||||
1. **`.anonymous()` 是排他性的** —— 已登录用户访问会直接 403,不要用于需要同时支持前台和后台的 API
|
||||
2. **`.permitAll()` vs `.anonymous()`** 选择标准:
|
||||
- 登录/注册页面等"仅限未登录用户" → `.anonymous()`
|
||||
- 公开数据接口(小程序+后台共用) → `.permitAll()`
|
||||
3. **排查 403 时先看 SecurityConfig** —— 即使 API 直接 curl 正常,带 token 就可能因认证状态不同而变化
|
||||
4. **排查思路**:逐层验证 API → 数据库 → 菜单路由 → Nginx 代理 → Security 权限配置
|
||||
|
||||
## 相关文件
|
||||
|
||||
- `rlz/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java`
|
||||
- `rlz-ui/src/views/system/hospital/index.vue`
|
||||
- `rlz-ui/src/utils/request.js` (前端错误拦截器)
|
||||
19
docs/service_type_migration.sql
Normal file
19
docs/service_type_migration.sql
Normal file
@@ -0,0 +1,19 @@
|
||||
-- 服务类型表增加 icon 字段
|
||||
ALTER TABLE rlz_service_type ADD COLUMN IF NOT EXISTS icon VARCHAR(255) DEFAULT '' COMMENT '服务图标URL';
|
||||
|
||||
-- 插入默认服务数据(如无数据)
|
||||
INSERT INTO rlz_service_type (name, category, type_code, price, description, status, sort_order)
|
||||
SELECT '全程陪诊', '2', '1', 200.00, '服务内容:排队 预约 挂号 缴费 取药 记录医嘱', '0', 1
|
||||
WHERE NOT EXISTS (SELECT 1 FROM rlz_service_type WHERE type_code = '1');
|
||||
|
||||
INSERT INTO rlz_service_type (name, category, type_code, price, description, status, sort_order)
|
||||
SELECT '诊前约号', '2', '2', 20.00, '服务内容:协助办理完成挂号', '0', 2
|
||||
WHERE NOT EXISTS (SELECT 1 FROM rlz_service_type WHERE type_code = '2');
|
||||
|
||||
INSERT INTO rlz_service_type (name, category, type_code, price, description, status, sort_order)
|
||||
SELECT '取送结果', '2', '3', 50.00, '服务内容:包括给病人或者家属取检查报告化验单等', '0', 3
|
||||
WHERE NOT EXISTS (SELECT 1 FROM rlz_service_type WHERE type_code = '3');
|
||||
|
||||
INSERT INTO rlz_service_type (name, category, type_code, price, description, status, sort_order)
|
||||
SELECT '代办问诊', '2', '4', 100.00, '服务内容:使用病人或者家属取检查报告化验单向医生问明情况', '0', 4
|
||||
WHERE NOT EXISTS (SELECT 1 FROM rlz_service_type WHERE type_code = '4');
|
||||
195
docs/商业化评估报告.md
Normal file
195
docs/商业化评估报告.md
Normal file
@@ -0,0 +1,195 @@
|
||||
# 瑞来健康陪诊平台 — 商业化评估报告
|
||||
|
||||
> 评估日期:2026-05-25
|
||||
> 评估范围:后端(Spring Boot)、管理后台(Vue2)、Android App、微信小程序
|
||||
|
||||
---
|
||||
|
||||
## 一、项目现状总览
|
||||
|
||||
| 维度 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 技术栈 | 可维护 | Java 8 / Spring Boot 2.5.14 / Vue 2.6 / MyBatis / MySQL / 微信原生小程序 / Android Java |
|
||||
| 部署 | 已跑通 | Tencent Cloud CVM + CynosDB + Docker Compose + Nginx |
|
||||
| 后台管理 | 较完整 | RuoYi-Vue 框架,含医院/订单/财务/服务类型/护理资讯管理 |
|
||||
| 微信小程序 | 部分完成 | 14 页面 + 3 Tab,核心流程可走,但存在假数据和空壳页面 |
|
||||
| Android App | 需重构 | 从家装项目改造而来,遗留大量无关代码 |
|
||||
| 安全性 | **不达标** | 支付密钥硬编码、JWT 弱密钥、手机号明文存储等多项致命问题 |
|
||||
|
||||
---
|
||||
|
||||
## 二、安全问题(P0 — 商用前必须解决)
|
||||
|
||||
### 2.1 致命级
|
||||
|
||||
| # | 问题 | 位置 | 风险 |
|
||||
|---|------|------|------|
|
||||
| 1 | 微信支付 RSA 私钥 + APIv3 Key 硬编码在源码中 | `WXPayConstantsAAA.java:23-50`、`PaySign.java:25-52`、`SysWeixinPayControllerNewBBBBB.java:34-42` | 源码泄露 = 资金被盗 |
|
||||
| 2 | JWT 签名密钥 `abcdefghijklmnopqrstuvwxyz` | `application.yml:96` | 可暴力破解,伪造任意用户 Token |
|
||||
| 3 | 短信接口无限流保护 | `MsmController.java` — 全平台零限流 | 可被刷短信,造成资损 |
|
||||
|
||||
### 2.2 高级
|
||||
|
||||
| # | 问题 | 位置 | 风险 |
|
||||
|---|------|------|------|
|
||||
| 4 | 手机号明文存储 + API 返回明文 + `System.out.print` 打印 | `sys_user.phonenumber`、`SysLoginController.java:76,123`、`MsmController.java:34` | 用户隐私泄露 |
|
||||
| 5 | SMS 验证码明文打印到控制台 | `MsmController.java:46` | 验证码泄露 |
|
||||
| 6 | 操作日志表 `sys_oper_log` 记录完整请求体(含密码、手机号) | `LogAspect.java:142-154` | 日志库成为敏感数据泄露源 |
|
||||
| 7 | WeChat AppSecret 硬编码在 URL 参数中 | `SysLoginController.java:178,226` | AppSecret 泄露 |
|
||||
| 8 | Android WeChat AppSecret 硬编码 | `WXEntryActivity.java:46` | AppSecret 泄露 |
|
||||
|
||||
### 2.3 中级
|
||||
|
||||
| # | 问题 | 位置 | 风险 |
|
||||
|---|------|------|------|
|
||||
| 9 | Druid 监控面板生产环境公开可访问(无 IP 白名单) | `SecurityConfig.java:116`、`application-docker.yml:53` | 数据库连接池信息暴露 |
|
||||
| 10 | Swagger API 文档生产环境公开 | `application.yml:118`、`SecurityConfig.java:116` | API 结构暴露 |
|
||||
| 11 | CSRF 全局关闭 + `X-Frame-Options` 关闭 | `SecurityConfig.java:104,120` | CSRF / 点击劫持风险 |
|
||||
| 12 | ~95% 接口 `@PreAuthorize` 被注释 | 全平台 Controller | 任意认证用户可调用任意接口,无细粒度权限控制 |
|
||||
|
||||
---
|
||||
|
||||
## 三、小程序功能缺陷(P1)
|
||||
|
||||
| # | 页面 | 问题 | 影响 |
|
||||
|---|------|------|------|
|
||||
| 1 | `reforderdetail` 退款订单详情 | **全假数据**,真实 API 调用被整段注释 | 退款流程完全不可用 |
|
||||
| 2 | `tuiguang/extensionInfor` 推广页 | **完全空壳**,所有生命周期函数为空 | 推广模块不存在 |
|
||||
| 3 | `guanyu/guanyu` 关于/反馈页 | 表单提交调用不存在的函数 `this.payment()` | 反馈功能不可用 |
|
||||
| 4 | `mechanism/mechanism` 机构页 | 机构详情跳转到不存在的 `pages/institutions/institutions` | 机构详情 404 |
|
||||
| 5 | `peizhen/peizhen` + `peihu/peihu` | 医院选择器数据硬编码(不从后台接口读取) | 数据不实时 |
|
||||
| 6 | `index/index` | 服务价格硬编码(200/20/100/50) | 调价需改代码发版 |
|
||||
| 7 | `myshoucang/myshoucang_index` | 收藏列表全假数据 | 收藏功能不可用 |
|
||||
| 8 | `my/my` | 砍价功能写死"暂无开放" | 营销功能缺失 |
|
||||
| 9 | `orderdetail/orderdetail` | 客服电话硬编码 `18133233292` | 换号需改代码 |
|
||||
| 10 | 全页面 | 错误处理均为 `.catch(() => {})` 静默吞错 | 用户无错误反馈 |
|
||||
|
||||
---
|
||||
|
||||
## 四、Android App 问题(P2)
|
||||
|
||||
| # | 问题 |
|
||||
|---|------|
|
||||
| 1 | 含大量原家装项目遗留代码(`DesignActivity`、`StyleActivity`、`Douyin` 接口等) |
|
||||
| 2 | 两套并行网络层:Retrofit(`MyApi.java`)+ OkHttp(`NetApi.java`),架构混乱 |
|
||||
| 3 | `API.java` 引用已废弃的 Bmob 云后端,含硬编码测试密钥 |
|
||||
| 4 | 引用 `/device/AppCustomer/*`、`/device/AppDouyin/*` 等可能不存在的接口 |
|
||||
| 5 | 包名和类名仍保留原产品命名(`kehu`、`find`、`goddess` 等) |
|
||||
|
||||
---
|
||||
|
||||
## 五、基础设施缺失(P3)
|
||||
|
||||
| # | 问题 |
|
||||
|---|------|
|
||||
| 1 | 无自动化数据库备份策略 |
|
||||
| 2 | 无日志聚合 / 监控告警系统 |
|
||||
| 3 | 自定义建表 SQL(`rlz_order`、`sys_hospital` 等)未入仓 |
|
||||
| 4 | 无 Staging 测试环境 |
|
||||
| 5 | CI/CD 仅覆盖后端 Docker 构建,小程序和 Android 无自动化 |
|
||||
| 6 | 数据库 `rlz_order` 表使用 20 个通用字段 `yuliu1~20`,Schema 不透明 |
|
||||
|
||||
---
|
||||
|
||||
## 六、数据库问题
|
||||
|
||||
| # | 表 | 问题 |
|
||||
|---|------|------|
|
||||
| 1 | `rlz_order` | 20 个 `yuliu1`~`yuliu20` 通用 varchar 列,无文档说明 |
|
||||
| 2 | `rlz_order` / `sys_hospital` / `rlz_service_type` 等 | 建表 DDL 未入仓(仅 `ry_20220625.sql` + `nursing_article.sql` 在 repo 中) |
|
||||
| 3 | `order_view` / `hospital_user_view` / `user_hospital_view` | 视图 DDL 未入仓 |
|
||||
| 4 | `sys_user.phonenumber` | 手机号明文存储,无加密 |
|
||||
| 5 | `sys_oper_log` | 存储完整请求/响应 JSON,含密码和手机号 |
|
||||
|
||||
---
|
||||
|
||||
## 七、开发工作量估算
|
||||
|
||||
### 方案 A:最小可用方案(安全整改 + 关键缺陷修复)— 3~4 个月
|
||||
|
||||
| 阶段 | 工作内容 | 人月 |
|
||||
|------|----------|------|
|
||||
| 安全整改 | 密钥迁移环境变量、JWT 加固、全接口限流、日志脱敏、Druid/Swagger 生产关闭 | 1.5 |
|
||||
| 小程序修复 | 退款页/推广页/关于页/机构页修复、硬编码改为接口调用、错误状态完善 | 1.5 |
|
||||
| 基础设施 | 备份策略、基础监控告警 | 0.5 |
|
||||
| 全流程测试 | 回归测试 | 0.5 |
|
||||
| **合计** | | **4 人月** |
|
||||
|
||||
> 2 人团队 × 2 个月,费用约 **8~15 万 RMB**
|
||||
|
||||
---
|
||||
|
||||
### 方案 B:完整商用方案 — 6~8 个月
|
||||
|
||||
| 阶段 | 工作内容 | 人月 |
|
||||
|------|----------|------|
|
||||
| 安全整改 | 同上 + 敏感数据加密存储 + 渗透测试 + 等保咨询 | 2 |
|
||||
| 小程序完整修复 | 全部页面真实接口、通知推送、图文混排优化 | 2 |
|
||||
| 功能补全 | 营销模块(砍价/拼团)、收藏、反馈系统、CMS 完善 | 1.5 |
|
||||
| Android 重构 | 移除遗留代码、统一网络层、端到端测试 | 2 |
|
||||
| 基础设施 | CI/CD 全流程、监控告警、日志平台、多环境管理、灾备方案 | 1 |
|
||||
| 合规 + 文档 | 隐私政策、用户协议、数据删除/导出、运维文档 | 1 |
|
||||
| 测试 | 全平台回归 + 性能压测 | 1 |
|
||||
| **合计** | | **10.5 人月** |
|
||||
|
||||
> 2~3 人团队 × 4~6 个月,费用约 **25~50 万 RMB**
|
||||
|
||||
---
|
||||
|
||||
## 八、运维费用估算(月度)
|
||||
|
||||
| 项目 | 规格 | 费用(元/月) |
|
||||
|------|------|---------------|
|
||||
| 腾讯云 CVM | 4C8G | 300 ~ 600 |
|
||||
| CynosDB MySQL | 按量 | 500 ~ 2,000 |
|
||||
| 带宽 + CDN | 按量 | 200 ~ 800 |
|
||||
| 域名 | ruilaizipj.com | ~10 |
|
||||
| 微信小程序认证 | 年付 300 | 25 |
|
||||
| 微信商户手续费 | 0.6% 交易额 | 按交易量 |
|
||||
| 短信服务 | 验证码 + 通知 | 100 ~ 500 |
|
||||
| SSL 证书 | Let's Encrypt | 0 |
|
||||
| 云监控基础版 | - | 200 ~ 500 |
|
||||
| 对象存储 COS | 图片/文件 | 50 ~ 300 |
|
||||
| **月度合计** | | **约 1,500 ~ 5,000** |
|
||||
|
||||
---
|
||||
|
||||
## 九、数据合规要求(中国法律)
|
||||
|
||||
陪诊平台属于医疗健康相关服务,涉及用户敏感个人信息,需关注:
|
||||
|
||||
| 法规 | 要求 | 当前状态 |
|
||||
|------|------|----------|
|
||||
| 《个人信息保护法》 | 收集用户信息需明确告知 + 获取同意 | 小程序无隐私弹窗 |
|
||||
| 《个人信息保护法》 | 敏感个人信息(医疗健康、行踪轨迹)需单独同意 | 未实现 |
|
||||
| 《个人信息保护法》 | 用户有权查阅/更正/删除/导出其个人信息 | 未实现 |
|
||||
| 《网络安全法》 | 网络运营者应采取技术措施保障信息安全 | 多项安全问题未解决 |
|
||||
| 《数据安全法》 | 重要数据处理者需定期风险评估 | 无 |
|
||||
| 等保 2.0 | 医疗健康类系统至少等保二级 | 未做 |
|
||||
| 微信小程序运营规范 | 涉及医疗健康需提供相关资质 | 需确认 |
|
||||
|
||||
---
|
||||
|
||||
## 十、建议实施路径
|
||||
|
||||
```
|
||||
第 1 个月 ─── 安全整改(密钥管理 + 限流 + 日志脱敏 + 生产配置加固)
|
||||
第 2 个月 ─── 小程序缺陷修复(假数据 → 真接口 + 空壳页面补全)
|
||||
第 3 个月 ─── 基础设施(备份 + 监控 + CI/CD)+ 全流程测试
|
||||
第 4 个月 ─── 上线试运营,收集用户反馈
|
||||
第 5-6 个月 ─ 功能增强(营销模块、通知推送、数据看板)
|
||||
第 7-8 个月 ─ Android 重构 + 合规材料准备
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十一、总结
|
||||
|
||||
| | 方案 A(最小可用) | 方案 B(完整商用) |
|
||||
|------|------|------|
|
||||
| 开发周期 | 3 ~ 4 个月 | 6 ~ 8 个月 |
|
||||
| 开发费用 | 8 ~ 15 万 | 25 ~ 50 万 |
|
||||
| 月度运维 | 1,500 ~ 5,000 元 | 1,500 ~ 5,000 元 |
|
||||
| 交付水平 | 核心业务流程可运转 | 具备完整 SaaS 商业化能力 |
|
||||
|
||||
**最紧迫事项**:安全漏洞修复(支付密钥、JWT、限流)必须在任何商用推广前完成。源码一旦泄露,攻击者可直接操作微信支付。
|
||||
201
docs/域名与nginx配置方案.md
Normal file
201
docs/域名与nginx配置方案.md
Normal file
@@ -0,0 +1,201 @@
|
||||
# 瑞来健康 — 域名与 Nginx 配置方案
|
||||
|
||||
> 日期:2026-05-24
|
||||
> 服务器:101.43.95.130
|
||||
> 现状:与"生长激素预测模型"项目共用服务器和域名 ruilaizipj.com
|
||||
|
||||
---
|
||||
|
||||
## 一、现状分析
|
||||
|
||||
### 1.1 域名占用
|
||||
|
||||
```
|
||||
ruilaizipj.com / www.ruilaizipj.com (80/443)
|
||||
└── host nginx (/etc/nginx/conf.d/default.conf)
|
||||
├── / → /www/wwwroot/code/public (ThinkPHP - 生长激素项目)
|
||||
└── /adminghd/ → ThinkPHP 后台管理
|
||||
```
|
||||
|
||||
### 1.2 RLZ 服务(Docker 内部)
|
||||
|
||||
| 服务 | 容器 | 内部端口 | 外部访问 |
|
||||
|------|------|---------|---------|
|
||||
| 后端 API | rlz-backend | 8039 | `http://101.43.95.130:8039` |
|
||||
| 管理后台 | rlz-ui-server | 80 | `http://101.43.95.130:8050` |
|
||||
| Redis | rlz-redis | 6379 | 127.0.0.1:6379 |
|
||||
|
||||
### 1.3 微信小程序约束
|
||||
|
||||
微信小程序已在微信后台登记 `https://ruilaizipj.com` 作为合法 API 域名,不能更改。
|
||||
|
||||
### 1.4 RLZ API 路径前缀
|
||||
|
||||
- 后台管理:`/dev-api/`(由前端 `VUE_APP_BASE_API` 控制)
|
||||
- 微信小程序/Android:`/prod-api/`(直接请求后端路径)
|
||||
|
||||
---
|
||||
|
||||
## 二、方案设计
|
||||
|
||||
### 2.1 核心思路
|
||||
|
||||
**API 走主域名路径代理,管理后台走子域名。**
|
||||
|
||||
- 小程序 API → 主域名路径 `/prod-api/*`(不改微信登记,与 ThinkPHP 无冲突)
|
||||
- 管理后台 → 子域名 `admin.ruilaizipj.com`(SPA 路由清爽,独立 server 块)
|
||||
|
||||
### 2.2 目标架构
|
||||
|
||||
```
|
||||
101.43.95.130 (host nginx 80/443)
|
||||
│
|
||||
┌─────────────────────────┼─────────────────────────┐
|
||||
│ │ │
|
||||
ruilaizipj.com ruilaizipj.com admin.ruilaizipj.com
|
||||
(生长激素) (RLZ API) (RLZ 管理后台)
|
||||
│ │ │
|
||||
/ → code/public /prod-api/* / → rlz-ui-server
|
||||
/adminghd/ /dev-api/* (127.0.0.1:8050)
|
||||
│ (127.0.0.1:8039)
|
||||
▼ │
|
||||
ThinkPHP 5.0 ▼
|
||||
(PHP-FPM) rlz-backend
|
||||
(Spring Boot)
|
||||
```
|
||||
|
||||
### 2.3 SSL 证书
|
||||
|
||||
当前 Let's Encrypt 证书覆盖 `ruilaizipj.com` + `www.ruilaizipj.com`。
|
||||
|
||||
需要新增 `admin.ruilaizipj.com` 的 SAN 覆盖。两种方式:
|
||||
- **方式 A**:宝塔面板 → 网站 → SSL → 重新签发(添加子域名)
|
||||
- **方式 B**:手动 certbot 扩展
|
||||
|
||||
推荐方式 A,宝塔自动续期。
|
||||
|
||||
---
|
||||
|
||||
## 三、实施步骤
|
||||
|
||||
### Step 1:DNS 添加子域名
|
||||
|
||||
在域名 DNS 管理后台添加记录:
|
||||
```
|
||||
admin.ruilaizipj.com → A → 101.43.95.130
|
||||
```
|
||||
|
||||
### Step 2:扩展 SSL 证书
|
||||
|
||||
通过宝塔面板重新签发证书,添加 `admin.ruilaizipj.com` 到域名列表。
|
||||
|
||||
### Step 3:修改 host nginx 配置
|
||||
|
||||
编辑 `/etc/nginx/conf.d/default.conf`,在现有 server 块中新增:
|
||||
|
||||
```nginx
|
||||
# === 现有 ThinkPHP 配置保持不变 ===
|
||||
|
||||
# 新增:RLZ 后端 API 代理
|
||||
location /prod-api/ {
|
||||
proxy_pass http://127.0.0.1:8039/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_connect_timeout 30s;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
|
||||
location /dev-api/ {
|
||||
proxy_pass http://127.0.0.1:8039/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_connect_timeout 30s;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
```
|
||||
|
||||
新建 `/etc/nginx/conf.d/rlz-admin.conf`:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name admin.ruilaizipj.com;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name admin.ruilaizipj.com;
|
||||
|
||||
ssl_certificate /www/server/panel/vhost/cert/101.43.95.130/fullchain.pem;
|
||||
ssl_certificate_key /www/server/panel/vhost/cert/101.43.95.130/privkey.pem;
|
||||
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:!MD5;
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
charset utf-8;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8050;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_connect_timeout 30s;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
|
||||
location /prod-api/ {
|
||||
proxy_pass http://127.0.0.1:8039/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4:验证
|
||||
|
||||
```bash
|
||||
# 重载 nginx
|
||||
nginx -t && nginx -s reload
|
||||
|
||||
# 测试 API
|
||||
curl -s https://ruilaizipj.com/prod-api/captchaImage
|
||||
|
||||
# 测试管理后台
|
||||
curl -s -o /dev/null -w "%{http_code}" https://admin.ruilaizipj.com/
|
||||
```
|
||||
|
||||
### Step 5:更新前端配置
|
||||
|
||||
- `rlz-ui/.env.production`:`VUE_APP_BASE_API` 改为 `/prod-api`
|
||||
- 微信小程序 `config.js`:`baseUrl` 改为 `https://ruilaizipj.com/prod-api`
|
||||
- Android `BuildConfig`:Release 的 `API_BASE_URL` 改为 `https://ruilaizipj.com/prod-api`
|
||||
|
||||
---
|
||||
|
||||
## 四、访问地址总览(实施后)
|
||||
|
||||
| 端 | 地址 |
|
||||
|------|------|
|
||||
| 管理后台 | `https://admin.ruilaizipj.com` |
|
||||
| 后端 API | `https://ruilaizipj.com/prod-api/` |
|
||||
| 微信小程序 API | `https://ruilaizipj.com/prod-api/` |
|
||||
| 生长激素项目(不变) | `https://www.ruilaizipj.com` |
|
||||
| 生长激素后台(不变) | `https://www.ruilaizipj.com/adminghd/` |
|
||||
|
||||
---
|
||||
|
||||
## 五、注意事项
|
||||
|
||||
1. **不要改 `server_name` 的 ThinkPHP 部分**,否则影响生长激素项目正常运行
|
||||
2. **nginx 修改前备份**:`cp /etc/nginx/conf.d/default.conf /tmp/default.conf.bak`
|
||||
3. **宝塔可能覆盖 nginx 配置**,修改后注意观察
|
||||
4. **API 路径冲突检查**:确认 ThinkPHP 项目没有 `/prod-api/` 或 `/dev-api/` 路由
|
||||
5. **RLZ 前端的 `VUE_APP_BASE_API` 需要同步更新**为 `/prod-api` 并重新构建部署
|
||||
235
docs/服务项目管理动态化方案.md
Normal file
235
docs/服务项目管理动态化方案.md
Normal file
@@ -0,0 +1,235 @@
|
||||
# 服务项目管理动态化方案
|
||||
|
||||
> 日期:2026-05-25
|
||||
> 目标:将小程序端硬编码的服务项目改为后台动态配置,支持上架/下架/调价/排序
|
||||
|
||||
---
|
||||
|
||||
## 一、现状分析
|
||||
|
||||
### 1.1 现有基础设施(已存在,可直接使用)
|
||||
|
||||
| 组件 | 状态 | 位置 |
|
||||
|------|------|------|
|
||||
| 数据库表 `rlz_service_type` | 已有 | MySQL |
|
||||
| 实体类 `RlzServiceType` | 已有 | `ruoyi-system/.../domain/RlzServiceType.java` |
|
||||
| Mapper / Service / Controller | 已有 | CRUD + 分页 + Excel 导出 |
|
||||
| 价格变更历史 `rlz_price_history` | 已有 | 调价自动记录操作人/时间/原因 |
|
||||
| 管理后台 Vue 页面 | 已有 | `rlz-ui/src/views/system/serviceType/index.vue` |
|
||||
|
||||
### 1.2 现有字段
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | Long | 主键 |
|
||||
| name | String | 服务名称 |
|
||||
| category | String | 类别: 1=陪护, 2=陪诊 |
|
||||
| typeCode | String | 类型编码 |
|
||||
| price | BigDecimal | 价格 |
|
||||
| description | String | 服务内容描述 |
|
||||
| status | String | 0=启用, 1=停用 |
|
||||
| sortOrder | Integer | 排序(越小越靠前) |
|
||||
| createBy/createTime | - | 创建信息 |
|
||||
| updateBy/updateTime | - | 更新信息 |
|
||||
| remark | String | 备注 |
|
||||
|
||||
### 1.3 当前问题
|
||||
|
||||
小程序端服务项目全部硬编码:
|
||||
|
||||
- `pages/index/index.js:13-41` — 4 个服务项,价格写死(200/20/100/50)
|
||||
- `pages/peizhen/peizhen.js:26-56` — 陪诊服务列表写死
|
||||
- `pages/peihu/peihu.js` — 陪护服务列表写死
|
||||
- 图标通过 `../image/home/{{item.icon}}.png` 本地引用,无法动态配置
|
||||
|
||||
---
|
||||
|
||||
## 二、改造方案
|
||||
|
||||
### 2.1 数据库变更
|
||||
|
||||
`rlz_service_type` 表新增 `icon` 字段:
|
||||
|
||||
```sql
|
||||
ALTER TABLE rlz_service_type ADD COLUMN icon VARCHAR(255) DEFAULT '' COMMENT '服务图标URL';
|
||||
```
|
||||
|
||||
### 2.2 后端变更
|
||||
|
||||
#### a) 实体新增 icon 字段
|
||||
|
||||
`RlzServiceType.java` 增加 `private String icon;` 及 getter/setter。
|
||||
|
||||
#### b) Mapper XML 更新
|
||||
|
||||
`RlzServiceTypeMapper.xml` 的 resultMap / SQL / insert / update 中增加 icon 字段。
|
||||
|
||||
#### c) 新增小程序公开接口
|
||||
|
||||
```java
|
||||
// 无需登录,返回所有启用状态的服务
|
||||
@GetMapping("/enabled")
|
||||
public AjaxResult enabled(RlzServiceType rlzServiceType)
|
||||
{
|
||||
rlzServiceType.setStatus("0"); // 只查启用的
|
||||
List<RlzServiceType> list = rlzServiceTypeService
|
||||
.selectRlzServiceTypeList(rlzServiceType);
|
||||
return AjaxResult.success(list);
|
||||
}
|
||||
```
|
||||
|
||||
#### d) SecurityConfig 白名单
|
||||
|
||||
```java
|
||||
.antMatchers("/system/serviceType/enabled").permitAll()
|
||||
```
|
||||
|
||||
### 2.3 管理后台变更
|
||||
|
||||
`rlz-ui/src/views/system/serviceType/index.vue`:
|
||||
|
||||
- 表格增加"图标"列(显示缩略图)
|
||||
- 新增/编辑表单增加图标上传组件
|
||||
- 增加"上架/下架"快捷操作按钮
|
||||
|
||||
### 2.4 小程序变更
|
||||
|
||||
#### index.js(首页 4 个服务卡片)
|
||||
|
||||
```
|
||||
修改前:data.itemView = [{ icon: "全程陪诊", title: "全程陪诊", price: "200", ... }]
|
||||
修改后:onShow 调用 /system/serviceType/enabled?category=2 获取陪诊服务列表
|
||||
```
|
||||
|
||||
#### peizhen.js(陪诊页)
|
||||
|
||||
```
|
||||
修改前:services = [{ name: "全程陪诊", price: "200" }, ...]
|
||||
修改后:调用 /system/serviceType/enabled?category=2 动态加载
|
||||
```
|
||||
|
||||
#### peihu.js(陪护页)
|
||||
|
||||
```
|
||||
修改前:services 硬编码
|
||||
修改后:调用 /system/serviceType/enabled?category=1 动态加载
|
||||
```
|
||||
|
||||
#### WXML 图标引用
|
||||
|
||||
```xml
|
||||
<!-- 修改前(本地图片) -->
|
||||
<image src="../image/home/{{item.icon}}.png" mode="aspectFit"></image>
|
||||
|
||||
<!-- 修改后(远程URL) -->
|
||||
<image src="{{item.icon}}" mode="aspectFit"></image>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、数据流
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ 管理后台 (Vue Admin) │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ 服务类型管理 │ │
|
||||
│ │ [新增] [编辑] [删除] [调价] [上架/下架] │ │
|
||||
│ │ ┌──────┬──────┬──────┬──────┬──────┐ │ │
|
||||
│ │ │ 图标 │ 名称 │ 类别 │ 价格 │ 状态 │ │ │
|
||||
│ │ ├──────┼──────┼──────┼──────┼──────┤ │ │
|
||||
│ │ │ 🏥 │全程陪诊│陪诊 │ 200 │ 启用 │ │ │
|
||||
│ │ │ 📋 │诊前约号│陪诊 │ 20 │ 启用 │ │ │
|
||||
│ │ │ 💊 │代办买药│陪诊 │ 80 │ 停用 │ │ │
|
||||
│ │ └──────┴──────┴──────┴──────┴──────┘ │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │ POST/PUT/DELETE │
|
||||
│ ▼ (需登录 + 权限) │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ 后端 Controller: /system/serviceType/* │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ 微信小程序 │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ /system/serviceType/enabled?category=2 │ │
|
||||
│ │ [公开接口,无需登录] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │ GET │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ 返回: [{ name:"全程陪诊", price:200, icon:"...", │ │
|
||||
│ │ description:"排队预约挂号...", status:"0" │ │
|
||||
│ │ sortOrder:1 }, ...] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ 首页服务卡片区域 动态渲染 │ │
|
||||
│ │ [全程陪诊] [诊前约号] [代办买药] [取送结果] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、实现步骤
|
||||
|
||||
| 步骤 | 内容 | 涉及文件 |
|
||||
|------|------|----------|
|
||||
| 1 | 数据库加 `icon` 字段 | DDL |
|
||||
| 2 | 实体 + Mapper 更新 | `RlzServiceType.java`, `RlzServiceTypeMapper.xml` |
|
||||
| 3 | Controller 增加 `/enabled` 公开接口 | `RlzServiceTypeController.java` |
|
||||
| 4 | SecurityConfig 加白名单 | `SecurityConfig.java` |
|
||||
| 5 | 管理后台增加图标字段 | `serviceType/index.vue` |
|
||||
| 6 | 小程序首页改为 API 加载 | `index.js`, `index.wxml` |
|
||||
| 7 | 小程序陪诊页改为 API 加载 | `peizhen.js`, `peizhen.wxml` |
|
||||
| 8 | 小程序陪护页改为 API 加载 | `peihu.js`, `peihu.wxml` |
|
||||
| 9 | 部署后端 + 测试 | Docker 构建部署 |
|
||||
|
||||
---
|
||||
|
||||
## 五、接口设计
|
||||
|
||||
### GET /system/serviceType/enabled
|
||||
|
||||
无需登录,根据 category 返回已启用的服务列表。
|
||||
|
||||
**请求参数:**
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| category | String | 否 | 1=陪护, 2=陪诊,不传则返回全部 |
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "全程陪诊",
|
||||
"category": "2",
|
||||
"typeCode": "1",
|
||||
"price": 200.00,
|
||||
"description": "排队预约挂号缴费取药记录医嘱",
|
||||
"icon": "https://ruilaizipj.com/profile/upload/icon_peizhen.png",
|
||||
"status": "0",
|
||||
"sortOrder": 1
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "诊前约号",
|
||||
"category": "2",
|
||||
"typeCode": "2",
|
||||
"price": 20.00,
|
||||
"description": "协助办理完成挂号",
|
||||
"icon": "https://ruilaizipj.com/profile/upload/icon_yuehao.png",
|
||||
"status": "0",
|
||||
"sortOrder": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
256
docs/陪诊员服务费分账方案.md
Normal file
256
docs/陪诊员服务费分账方案.md
Normal file
@@ -0,0 +1,256 @@
|
||||
# 陪诊员服务费分账方案(A+B 结合)
|
||||
|
||||
## 一、需求概述
|
||||
|
||||
订单完成后,将服务费按比例分配给平台和陪诊员,实现自动计算 + 人工审核确认的结算流程。
|
||||
|
||||
## 二、业务流程
|
||||
|
||||
```
|
||||
订单完成(status=3,待支付)
|
||||
→ 患者微信支付
|
||||
→ 支付成功(status=4,已完成)
|
||||
→ 系统自动计算分账金额(根据配置的抽成比例)
|
||||
→ 写入结算金额到订单字段
|
||||
→ 管理员后台审核确认
|
||||
→ 陪诊员余额增加(yue)、累计收益更新(leijijine)
|
||||
→ 生成交易记录(jiaoyi_detail)
|
||||
→ 订单标记为已结算(status=8)
|
||||
```
|
||||
|
||||
## 三、数据库改动
|
||||
|
||||
### 3.1 新增平台配置表 `rlz_platform_config`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `id` | bigint | PK |
|
||||
| `config_key` | varchar(50) | 配置键 |
|
||||
| `config_value` | varchar(255) | 配置值 |
|
||||
| `description` | varchar(200) | 描述 |
|
||||
| `create_time` | datetime | 创建时间 |
|
||||
| `update_time` | datetime | 更新时间 |
|
||||
|
||||
初始化数据:
|
||||
```sql
|
||||
INSERT INTO rlz_platform_config (config_key, config_value, description) VALUES
|
||||
('commission_rate', '20', '平台抽成比例(%)'),
|
||||
('auto_settle', 'false', '是否自动结算(true/false)');
|
||||
```
|
||||
|
||||
### 3.2 现有表字段利用
|
||||
|
||||
`rlz_order` 表已有字段(无需改动):
|
||||
- `jiesuan_money` — 结算金额(订单总金额)
|
||||
- `kouchu_money` — 平台抽成金额
|
||||
- `fanxian_money` — 陪诊员所得金额
|
||||
- `fanxian_tax` — 抽成比例(%)
|
||||
- `is_zhifu` — 打款状态(0=未打款, 1=已打款)
|
||||
|
||||
`sys_user` 表已有字段(无需改动):
|
||||
- `yue` — 余额(陪诊员可用余额)
|
||||
- `leijijine` — 累计收益
|
||||
|
||||
`jiaoyi_detail` 表已有字段(无需改动):
|
||||
- `type` — 1=收入, 2=支出
|
||||
- `jine` — 金额
|
||||
- `name` — 交易名称
|
||||
- `yue` — 交易后余额
|
||||
- `user_id` — 用户ID
|
||||
|
||||
## 四、后端实现
|
||||
|
||||
### 4.1 新增类文件
|
||||
|
||||
| 类 | 路径 | 职责 |
|
||||
|----|------|------|
|
||||
| `RlzPlatformConfig.java` | `domain/` | 平台配置实体 |
|
||||
| `RlzPlatformConfigMapper.java` | `mapper/` | 配置 Mapper |
|
||||
| `RlzPlatformConfigMapper.xml` | `mapper/system/` | 配置 SQL |
|
||||
| `IRlzPlatformConfigService.java` | `service/` | 配置服务接口 |
|
||||
| `RlzPlatformConfigServiceImpl.java` | `service/impl/` | 配置服务实现 |
|
||||
| `RlzSettlementService.java` | `service/` | 结算服务(核心逻辑) |
|
||||
| `RlzSettlementController.java` | `controller/` | 结算接口 |
|
||||
| `RlzTransactionController.java` | `controller/` | 交易记录查询接口 |
|
||||
|
||||
### 4.2 核心服务 RlzSettlementService
|
||||
|
||||
```java
|
||||
@Service
|
||||
public class RlzSettlementService {
|
||||
|
||||
// 获取抽成比例(默认20%)
|
||||
public BigDecimal getCommissionRate() {
|
||||
String rate = platformConfigService.getConfigValue("commission_rate", "20");
|
||||
return new BigDecimal(rate);
|
||||
}
|
||||
|
||||
// 订单支付成功后自动计算分账
|
||||
public void calculateOrderFee(RlzOrder order) {
|
||||
BigDecimal totalAmount = new BigDecimal(order.getYuguMoney());
|
||||
BigDecimal rate = getCommissionRate(); // 20%
|
||||
BigDecimal kouchu = totalAmount.multiply(rate).divide(new BigDecimal("100")); // 平台抽成
|
||||
BigDecimal fanxian = totalAmount.subtract(kouchu); // 陪诊员所得
|
||||
|
||||
order.setJiesuanMoney(order.getYuguMoney()); // 结算金额=订单金额
|
||||
order.setKouchuMoney(kouchu.toString()); // 平台抽成
|
||||
order.setFanxianMoney(fanxian.toString()); // 陪诊员所得
|
||||
order.setFanxianTax(rate.toString()); // 抽成比例
|
||||
order.setIsZhifu("0"); // 未打款
|
||||
rlzOrderService.updateOrder(order);
|
||||
}
|
||||
|
||||
// 管理员确认结算(打款给陪诊员)
|
||||
@Transactional
|
||||
public void settleOrder(Long orderId) {
|
||||
RlzOrder order = rlzOrderService.selectRlzOrderById(orderId);
|
||||
if (!"4".equals(order.getStatus())) {
|
||||
throw new BusinessException("订单未支付,无法结算");
|
||||
}
|
||||
if ("1".equals(order.getIsZhifu())) {
|
||||
throw new BusinessException("已打款,请勿重复操作");
|
||||
}
|
||||
|
||||
Long caregiverId = order.getBId(); // 陪诊员ID
|
||||
BigDecimal fanxianMoney = new BigDecimal(order.getFanxianMoney());
|
||||
|
||||
// 1. 更新订单打款状态
|
||||
order.setIsZhifu("1");
|
||||
order.setStatus("8"); // 已结算
|
||||
rlzOrderService.updateOrder(order);
|
||||
|
||||
// 2. 更新陪诊员余额和累计收益
|
||||
SysUser caregiver = sysUserService.selectUserById(caregiverId);
|
||||
BigDecimal oldBalance = new BigDecimal(caregiver.getYue() != null ? caregiver.getYue() : "0");
|
||||
BigDecimal newBalance = oldBalance.add(fanxianMoney);
|
||||
caregiver.setYue(newBalance.toString());
|
||||
|
||||
BigDecimal oldTotal = new BigDecimal(caregiver.getLeijijine() != null ? caregiver.getLeijijine() : "0");
|
||||
caregiver.setLeijijine(oldTotal.add(fanxianMoney).toString());
|
||||
sysUserService.updateUser(caregiver);
|
||||
|
||||
// 3. 生成交易记录
|
||||
insertTransaction(caregiverId, fanxianMoney, newBalance, order.getYuliu1());
|
||||
}
|
||||
|
||||
private void insertTransaction(Long userId, BigDecimal jine, BigDecimal newBalance, String orderNo) {
|
||||
JiaoyiDetail detail = new JiaoyiDetail();
|
||||
detail.setUserId(userId);
|
||||
detail.setType("1"); // 收入
|
||||
detail.setJine(jine.toString());
|
||||
detail.setYue(newBalance.toString());
|
||||
detail.setName("订单结算 - " + orderNo);
|
||||
jiaoyiDetailService.insertJiaoyiDetail(detail);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 结算接口 RlzSettlementController
|
||||
|
||||
```java
|
||||
@RestController
|
||||
@RequestMapping("/system/settlement")
|
||||
public class RlzSettlementController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private RlzSettlementService settlementService;
|
||||
|
||||
// 支付回调中自动触发计算(在 WxPayNotify 中调用)
|
||||
// 此处提供手动重新计算的接口
|
||||
|
||||
// 管理员确认结算
|
||||
@PostMapping("/settle/{orderId}")
|
||||
public AjaxResult settle(@PathVariable Long orderId) {
|
||||
settlementService.settleOrder(orderId);
|
||||
return AjaxResult.success("结算完成");
|
||||
}
|
||||
|
||||
// 批量结算
|
||||
@PostMapping("/batchSettle")
|
||||
public AjaxResult batchSettle(@RequestBody Long[] orderIds) {
|
||||
for (Long id : orderIds) {
|
||||
settlementService.settleOrder(id);
|
||||
}
|
||||
return AjaxResult.success("批量结算完成");
|
||||
}
|
||||
|
||||
// 查询待结算订单列表(status=4 已支付但未打款)
|
||||
@GetMapping("/pending")
|
||||
public TableDataInfo pending() {
|
||||
// 查询 status=4 AND is_zhifu='0' 的订单
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 支付回调中自动触发计算
|
||||
|
||||
在 `WxPayNotify` 处理中增加一行调用:
|
||||
|
||||
```java
|
||||
// 支付成功,更新 status=4
|
||||
order.setStatus("4");
|
||||
// ... 存储微信交易号 ...
|
||||
rlzOrderService.updateOrder(order);
|
||||
|
||||
// === 新增:自动计算分账金额 ===
|
||||
settlementService.calculateOrderFee(order);
|
||||
```
|
||||
|
||||
## 五、后台管理面板改动
|
||||
|
||||
### 5.1 新增菜单
|
||||
|
||||
| 父菜单 | 菜单名称 | 路径 | 组件 |
|
||||
|--------|----------|------|------|
|
||||
| 财务管理(3000) | 结算管理 | `settlement` | `finance/settlement/index` |
|
||||
| 财务管理(3000) | 交易明细 | `transaction` | `finance/transaction/index` |
|
||||
| 财务管理(3000) | 平台配置 | `platformConfig` | `finance/platformConfig/index` |
|
||||
|
||||
### 5.2 结算管理页面 `finance/settlement/index.vue`
|
||||
|
||||
功能:
|
||||
- 列表展示已支付待结算订单
|
||||
- 搜索:订单号、陪诊员姓名、日期范围
|
||||
- 列:订单号、陪诊员、订单金额、平台抽成、应发金额、支付时间、状态
|
||||
- 操作:单个结算 / 批量结算
|
||||
- 点击结算弹出确认框,显示分账明细预览
|
||||
|
||||
### 5.3 平台配置页面 `finance/platformConfig/index.vue`
|
||||
|
||||
功能:
|
||||
- 平台抽成比例设置(默认20%)
|
||||
- 自动结算开关(暂不启用)
|
||||
|
||||
## 六、SecurityConfig 更新
|
||||
|
||||
```java
|
||||
// 新增匿名访问(若小程序也需要查询余额/交易记录)
|
||||
// 结算接口需要认证(仅后台管理员操作)
|
||||
.antMatchers("/system/settlement/**", "/system/transaction/**").authenticated()
|
||||
```
|
||||
|
||||
## 七、实施步骤
|
||||
|
||||
| 步骤 | 内容 | 预估 |
|
||||
|------|------|------|
|
||||
| 1 | 创建 `rlz_platform_config` 表 + 初始化数据 | 10min |
|
||||
| 2 | 创建配置管理后端代码(CRUD) | 20min |
|
||||
| 3 | 实现 `RlzSettlementService` 核心分账逻辑 | 30min |
|
||||
| 4 | 在支付回调中集成自动计算 | 10min |
|
||||
| 5 | 创建结算管理后台页面 | 30min |
|
||||
| 6 | 创建平台配置后台页面 | 20min |
|
||||
| 7 | 部署、测试完整流程 | 20min |
|
||||
|
||||
## 八、分账示例
|
||||
|
||||
假设平台抽成比例 20%,订单金额 500 元:
|
||||
|
||||
| 项目 | 金额 | 计算 |
|
||||
|------|------|------|
|
||||
| 订单金额 | 500.00 | 患者支付 |
|
||||
| 平台抽成(20%) | 100.00 | 500 × 20% |
|
||||
| 陪诊员所得 | 400.00 | 500 × 80% |
|
||||
| 陪诊员余额变化 | +400.00 | yue += 400 |
|
||||
|
||||
管理员可在后台"平台配置"中调整抽成比例,新比例对后续订单生效。
|
||||
Reference in New Issue
Block a user