diff --git a/.gitmodules b/.gitmodules index 588e4fc..e69de29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "rlz"] - path = rlz - url = https://gitee.com/renjianbo0118/ruoyi.git diff --git a/docs/后台管理功能模块规划.md b/docs/后台管理功能模块规划.md new file mode 100644 index 0000000..e289449 --- /dev/null +++ b/docs/后台管理功能模块规划.md @@ -0,0 +1,257 @@ +# 后台管理功能模块规划 + +> 基于 PRD 文档 (v1.0, 2026-05-12) 第 3.3 节「后台管理系统功能需求」 +> 对照现有 RuoYi 框架 + 已开发页面,梳理差距并规划改进 + +--- + +## 一、现状总览 + +### 已有模块(RuoYi 自带 + 项目扩展) + +| 模块 | 路由 | 状态 | 说明 | +|------|------|------|------| +| 用户管理 | `/system/user` | 已有 | 含患者(C)和陪护(B),但无类型筛选增强 | +| 角色管理 | `/system/role` | 已有 | RuoYi 标准 | +| 菜单管理 | `/system/menu` | 已有 | RuoYi 标准 | +| 部门管理 | `/system/dept` | 已有 | RuoYi 标准 | +| 岗位管理 | `/system/post` | 已有 | RuoYi 标准 | +| 字典管理 | `/system/dict` | 已有 | RuoYi 标准 | +| 参数配置 | `/system/config` | 已有 | 含 price / priceType 配置 | +| 通知公告 | `/system/notice` | 已有 | RuoYi 标准 | +| 医院管理 | `/system/hospital` | **需增强** | 字段与 PRD 不一致 | +| 订单管理 | `/system/order` | **需增强** | 缺状态筛选、退款审核、结算 | +| 认证管理 | `/system/renzheng` | **需增强** | 陪护实名认证审核 | +| 仪表盘 | `/index` | **需增强** | 缺业务统计图表 | +| 在线用户 | `/monitor/online` | 已有 | RuoYi 标准 | +| 操作日志 | `/monitor/operlog` | 已有 | RuoYi 标准 | +| 登录日志 | `/monitor/logininfor` | 已有 | RuoYi 标准 | +| 定时任务 | `/monitor/job` | 已有 | RuoYi 标准 | +| 服务监控 | `/monitor/server` | 已有 | RuoYi 标准 | +| 缓存监控 | `/monitor/cache` | 已有 | RuoYi 标准 | +| 代码生成 | `/tool/gen` | 已有 | RuoYi 标准 | + +### 后端已有 Controller(业务相关) + +| Controller | 路由前缀 | 说明 | +|-----------|---------|------| +| `RlzOrderController` | `/system/order` | 订单 CRUD + 微信支付 + 退款 + 取消 | +| `OrderViewController` | `/system/view` | 订单视图(join 查询),含接单/拒单/开始/完成 | +| `SysHospitalController` | `/system/hospital` | 医院 CRUD | +| `SysUserRenzhengController` | `/system/renzheng` | 认证审核 CRUD | +| `JiaoyiDetailController` | `/system/detail` | 交易明细 CRUD | +| `SysUserController` | `/system/user` | 用户 CRUD(含患者/陪护) | + +--- + +## 二、差距分析:PRD 要求 vs 现有实现 + +| PRD 模块 (3.3.x) | 完成度 | 差距 | +|-----------------|--------|------| +| 3.3.1 用户管理 | 60% | 缺患者/陪护类型筛选、患者订单统计、陪护服务统计、陪护等级 | +| 3.3.2 订单管理 | 40% | 缺状态筛选、服务类型筛选、订单搜索、退款审核流程、结算流程、订单统计 | +| 3.3.3 医院管理 | 50% | 字段不匹配(现有字段偏旧,PRD 要求医院等级/简介/图片) | +| 3.3.4 服务类型管理 | **0%** | 完全缺失,无服务类型和价格管理页面 | +| 3.3.5 财务管理 | 20% | 仅交易明细 CRUD,缺收入统计、退款审核、结算管理 | +| 3.3.6 数据统计 | 30% | 仅 RuoYi 通用仪表盘,缺业务数据统计 | +| 3.3.7 系统配置 | 90% | 基本完整 | +| 3.3.8 权限管理 | 90% | 基本完整(角色+菜单+用户) | + +--- + +## 三、改进方案:模块划分与实施计划 + +### 第一优先级(核心业务闭环) + +#### A. 订单管理增强 (`/system/order`) + +**目标**:让管理员能完整管理订单生命周期 + +| 功能 | 具体改动 | 前端 | 后端 | +|------|---------|------|------| +| 状态筛选增强 | 添加状态下拉选择(全部/待接单/待付款/待服务/服务中/已完成/已取消/退款中/已退款/已结算) | 改 `order/index.vue` 搜索表单 | `RlzOrderController.list()` 已支持 status 参数 | +| 服务类型筛选 | 添加订单类别(yuliu9)和类型(yuliu10)下拉筛选 | 同上 | 已支持 | +| 订单搜索 | 支持按订单号、患者姓名、患者手机号搜索 | 添加搜索输入框 | 需增强 `list()` 支持多字段模糊搜索 | +| 订单详情增强 | 显示关联的患者姓名/电话、陪护姓名/电话、医院名称(JOIN 查询) | 改用 `OrderViewController` 数据源 | `OrderViewController` 已有 join 视图 | +| 状态手动变更 | 管理员可手动修改订单状态(如强制取消、标记完成) | 添加状态变更按钮+确认弹窗 | `RlzOrderController.update()` 需增加状态校验 | +| 退款审核 | 退款申请列表 + 审核通过/驳回操作 + 驳回原因填写 | 新增退款审核区域或子页面 | 已有 `refundOrder` 接口,需增加审核逻辑 | +| 订单结算 | 手动/批量结算已完成订单 | 添加结算按钮 | 新增 `settlementOrder` 接口 | + +**数据来源切换**:当前 order 页面查询 `rlz_order` 原始表,字段名晦涩(yuliu1/yuliu9/yuliu10 等)。建议改用 `order_view` 视图,已 JOIN 了用户姓名、手机号、医院名称。 + +#### B. 服务类型与价格管理(新增 `/system/serviceType`) + +**目标**:让管理员能配置服务类型和价格,取代硬编码 + +| 功能 | 说明 | +|------|------| +| 服务类型列表 | 展示 4 种服务类型(全程陪诊/诊前约号/取送结果/代办问诊),含名称、价格、描述、状态 | +| 新增/编辑服务类型 | 配置服务名称、价格、服务内容描述、类别(陪诊/陪护) | +| 价格历史 | 记录价格变更历史,支持回溯 | +| 状态管理 | 启用/停用某项服务类型 | + +**数据表设计**: +```sql +-- 服务类型表 +CREATE TABLE rlz_service_type ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + name VARCHAR(50) NOT NULL COMMENT '服务名称', + category VARCHAR(10) COMMENT '类别: 1=陪护 2=陪诊', + type_code VARCHAR(10) COMMENT '类型编码: 1=全程陪诊 2=诊前约号 3=取送结果 4=代办问诊', + price DECIMAL(10,2) NOT NULL COMMENT '价格', + description TEXT COMMENT '服务内容描述', + status CHAR(1) DEFAULT '0' COMMENT '0=启用 1=停用', + sort_order INT DEFAULT 0 COMMENT '排序', + create_time DATETIME, + update_time DATETIME +); + +-- 价格变更历史表 +CREATE TABLE rlz_price_history ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + service_type_id BIGINT COMMENT '服务类型ID', + old_price DECIMAL(10,2) COMMENT '旧价格', + new_price DECIMAL(10,2) COMMENT '新价格', + change_reason VARCHAR(200) COMMENT '变更原因', + operator_id BIGINT COMMENT '操作人', + create_time DATETIME +); +``` + +--- + +### 第二优先级(运营管理增强) + +#### C. 用户管理增强 + +| 功能 | 具体改动 | 说明 | +|------|---------|------| +| 用户类型筛选 | 添加下拉:全部/系统用户/患者(C)/陪护(B) | `SysUserController.list()` 已支持 userType 参数 | +| 患者订单统计 | 用户详情页展示该患者的订单数量、总金额 | 前端增强 `user/profile` 或新增 tab | +| 陪护服务统计 | 用户详情页展示该陪护的接单数量、完成率、收入 | 同上 | +| 陪护等级 | 字段 `userLevel` 设置等级(初级/中级/高级) | 需 sys_user 增加字段或在字典中维护 | + +#### D. 医院管理增强 + +| 功能 | 具体改动 | 说明 | +|------|---------|------| +| 字段对齐 PRD | 增加:医院等级(hospitalLevel)、医院简介(hospitalDesc)、医院图片 | 前端表单 + 后端 domain 同步 | +| 图片上传 | 支持医院图片上传(复用 OSS 组件) | 使用已有 `/system/oss/uploadMinio` | +| 冗余字段清理 | 隐藏/删除 hospitalcode(编码)、hospitalshortname(简称)、省市区编码等非核心字段 | 前端搜索/列表精简 | + +#### E. 认证管理增强 + +| 功能 | 具体改动 | 说明 | +|------|---------|------| +| 审核操作优化 | 通过/驳回按钮 + 弹窗填写驳回原因 | 现有 `renzheng/index.vue` 仅有基础 CRUD | +| 认证图片查看 | 点击查看身份证等认证图片 | 前端增加图片预览组件 | +| 认证状态颜色 | 待审核(黄色)/已通过(绿色)/已驳回(红色) | 表格列使用 el-tag | + +--- + +### 第三优先级(数据与财务) + +#### F. 财务管理(新增菜单组) + +| 子模块 | 路由 | 说明 | +|--------|------|------| +| 交易明细 | `/finance/detail` | 已有 `JiaoyiDetailController`,迁移到财务菜单下 | +| 收入统计 | `/finance/income` | 按日/月/年统计平台收入,图表展示 | +| 退款管理 | `/finance/refund` | 退款申请审核列表(status=5,6,7 的订单) | +| 结算管理 | `/finance/settlement` | 陪护结算列表(status=8 的订单),支持批量结算 | + +#### G. 数据统计仪表盘增强 + +| 统计项 | 图表类型 | 数据来源 | +|--------|---------|---------| +| 订单量趋势 | 折线图 | `rlz_order` 按日聚合 | +| 订单状态分布 | 饼图 | `rlz_order` 按 status 分组 | +| 服务类型占比 | 饼图 | `rlz_order` 按 yuliu10 分组 | +| 医院服务量排名 | 柱状图 | `rlz_order` JOIN `sys_hospital` | +| 收入趋势 | 折线图 | `rlz_order` 按日 sum(yuguMoney) | +| 陪护服务排名 | 柱状图 | `rlz_order` 按 b_id 分组 count | + +--- + +## 四、菜单结构调整建议 + +``` +陪诊管理系统 +├── 首页 (仪表盘增强) +├── 业务管理 (新菜单组) +│ ├── 订单管理 /system/order [增强] +│ ├── 医院管理 /system/hospital [增强] +│ ├── 服务类型 /system/serviceType [新增] +│ └── 认证审核 /system/renzheng [增强] +├── 用户管理 (增强筛选) +│ ├── 用户列表 /system/user +│ ├── 角色管理 /system/role +│ └── 部门管理 /system/dept +├── 财务管理 (新菜单组) +│ ├── 交易明细 /finance/detail [迁移] +│ ├── 收入统计 /finance/income [新增] +│ ├── 退款管理 /finance/refund [新增] +│ └── 结算管理 /finance/settlement [新增] +├── 系统管理 +│ ├── 菜单管理 /system/menu +│ ├── 岗位管理 /system/post +│ ├── 字典管理 /system/dict +│ ├── 参数配置 /system/config +│ └── 通知公告 /system/notice +├── 系统监控 +│ ├── 在线用户 /monitor/online +│ ├── 操作日志 /monitor/operlog +│ ├── 登录日志 /monitor/logininfor +│ ├── 定时任务 /monitor/job +│ ├── 服务监控 /monitor/server +│ └── 缓存监控 /monitor/cache +└── 开发工具 + ├── 代码生成 /tool/gen + ├── Swagger文档 /tool/swagger + └── 表单构建 /tool/build +``` + +--- + +## 五、实施估算 + +| 优先级 | 模块 | 工作量 | 说明 | +|--------|------|--------|------| +| P0 | 订单管理增强 | 2-3 天 | 状态筛选+搜索+详情+退款审核,前端为主 | +| P0 | 服务类型管理 | 1-2 天 | 新建表+前后端 CRUD+字典联动 | +| P1 | 医院管理增强 | 0.5-1 天 | 字段调整+图片上传 | +| P1 | 用户管理增强 | 0.5-1 天 | 类型筛选+统计展示 | +| P1 | 认证管理增强 | 0.5 天 | 审核操作+图片预览 | +| P2 | 财务管理 | 2-3 天 | 4 个子模块,含统计图表 | +| P2 | 仪表盘增强 | 1-2 天 | ECharts 图表开发 | +| P2 | 菜单结构调整 | 0.5 天 | 数据库菜单表 UPDATE | + +--- + +## 六、服务类型数据初始化 + +当前 4 种服务类型通过 `yuliu9`(大类) 和 `yuliu10`(类型) 编码存储在订单中,建议纳入字典管理: + +```sql +-- 字典类型 +INSERT INTO sys_dict_type VALUES (NULL, 'order_category', '订单大类', '0', 'admin', NOW(), '', NULL); +INSERT INTO sys_dict_type VALUES (NULL, 'order_service_type', '服务类型', '0', 'admin', NOW(), '', NULL); + +-- 字典数据 - 订单大类 +INSERT INTO sys_dict_data VALUES (NULL, 1, '陪护', '1', 'order_category', '', '', 'N', '0', 'admin', NOW(), '', NULL); +INSERT INTO sys_dict_data VALUES (NULL, 2, '陪诊', '2', 'order_category', '', '', 'N', '0', 'admin', NOW(), '', NULL); + +-- 字典数据 - 服务类型 +INSERT INTO sys_dict_data VALUES (NULL, 3, '全程陪诊', '1', 'order_service_type', '', '200.00', 'N', '0', 'admin', NOW(), '', NULL); +INSERT INTO sys_dict_data VALUES (NULL, 4, '诊前约号', '2', 'order_service_type', '', '20.00', 'N', '0', 'admin', NOW(), '', NULL); +INSERT INTO sys_dict_data VALUES (NULL, 5, '取送结果', '3', 'order_service_type', '', '50.00', 'N', '0', 'admin', NOW(), '', NULL); +INSERT INTO sys_dict_data VALUES (NULL, 6, '代办问诊', '4', 'order_service_type', '', '100.00', 'N', '0', 'admin', NOW(), '', NULL); +``` + +--- + +> **相关文档**: +> - PRD 文档:`D:\androidPj\rlz\项目功能的prd文档.md` +> - 需求文档:`D:\androidPj\rlz\陪诊项目需求文档.txt` +> - 项目技术文档:`D:\androidPj\rlz\项目文档0511.md` +> - 改进记录:`D:\androidPj\rlz\docs\改进完成记录.md` diff --git a/docs/改进完成记录.md b/docs/改进完成记录.md new file mode 100644 index 0000000..eb25f9a --- /dev/null +++ b/docs/改进完成记录.md @@ -0,0 +1,96 @@ +# 开发环境改进完成记录 + +> 日期:2026-05-14 + +--- + +## 已完成的改进 + +### 1. Git 分支策略 + +- 创建 `dev` 分支并推送到 Gitea (`origin/dev`) +- `main` 保持稳定,日常开发在 `dev` 上进行 + +### 2. 数据库环境隔离 + +- 在腾讯云 CynosDB 创建 `rlz_dev` 开发库(28 张表,结构与生产 `rlz` 一致) +- 开发环境连 `rlz_dev`,生产环境连 `rlz`,数据互不污染 + +### 3. 后端配置分离 + +**application-dev.yml** (本地开发): +- 端口 8039,关闭 SSL +- 数据库 → `rlz_dev` (云 MySQL) +- Redis → localhost:6379 (需本地启动 Redis) +- 密码通过 `${MYSQL_PASSWORD:"!Rjb12191"}` 注入,有默认值 + +**application-docker.yml** (生产): +- 所有配置通过环境变量注入,保持现有方式 + +### 4. Drone CI 自动部署 + +创建 `.drone.yml`:`git push main` → Drone 自动 `mvn package` → `docker build` → `docker compose up -d` + +> 需要在 Gitea Drone 面板激活 `admin/rlz` 仓库后生效 + +### 5. Android API 地址自动切换 + +- `app/build.gradle` 添加 `buildConfigField "API_BASE_URL"` + - Debug → `http://192.168.1.100:8039`(需改为本机IP) + - Release → `http://101.43.95.130:8039` +- `MyApi.java` 和 `HttpConstants.java` 改用 `BuildConfig.API_BASE_URL` + +### 6. 微信小程序环境配置 + +- 新建 `coupon/utils/config.js` 集中管理 API 地址 +- `coupon/app.js` 引用 `config.baseUrl`,同时修复 `domain`/`domaintwo` 未赋值问题 + +### 7. 后端代码本地化 + +- 移除失效的 Gitee 子模块引用 +- 从服务器复制后端代码 → `rlz/` 目录(作为普通目录纳入 Git) +- 删除 `.gitmodules` + +--- + +## 后续需要手动完成的 + +| 事项 | 操作 | +|------|------| +| 修改 Android debug IP | `peizhen/app/build.gradle` → 将 `192.168.1.100` 改为本机实际 IP | +| 修改小程序 debug URL | `coupon/utils/config.js` → 取消注释开发环境 URL | +| 激活 Drone CI | Gitea → Drone 面板 → 激活 `admin/rlz` 仓库 | +| 本地启动 Redis | `docker run -d --name redis-dev -p 6379:6379 redis:7-alpine` | +| 提交代码到 Gitea | `git add -A && git commit && git push origin dev` | + +--- + +## 环境对照表 + +| 项目 | 开发环境 | 生产环境 | +|------|----------|----------| +| 数据库 | `rlz_dev` (云MySQL) | `rlz` (云MySQL) | +| 后端端口 | 8039 (本地) | 8039 (Docker) | +| 后端 profile | `dev` | `docker` | +| Android API | Debug: 本机IP | Release: 101.43.95.130 | +| 小程序 API | 可切换 config.js | 101.43.95.130 | +| Git 分支 | `dev` | `main` | +| 部署方式 | 手动 `mvn spring-boot:run` | Drone CI 自动部署 | + +--- + +## 文件变更清单 + +| 文件 | 变更类型 | +|------|----------| +| `.drone.yml` | 新增 | +| `.gitmodules` | 删除 | +| `rlz/` (整个后端) | 新增(从子模块改为普通目录) | +| `rlz/.../application-dev.yml` | 修改(指向 rlz_dev) | +| `peizhen/app/build.gradle` | 修改(添加 BuildConfig) | +| `peizhen/.../MyApi.java` | 修改(使用 BuildConfig) | +| `peizhen/.../HttpConstants.java` | 修改(使用 BuildConfig) | +| `coupon/utils/config.js` | 新增 | +| `coupon/app.js` | 修改(引用 config,修复 domain) | +| `docs/开发环境方案.md` | 新增 | +| `docs/改进完成记录.md` | 新增 | diff --git a/rlz b/rlz deleted file mode 160000 index 28e0b6f..0000000 --- a/rlz +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 28e0b6fc9fea01bfaf44bd76d79370dc8fc5167b diff --git a/rlz-ui/src/api/system/serviceType.js b/rlz-ui/src/api/system/serviceType.js new file mode 100644 index 0000000..edd6307 --- /dev/null +++ b/rlz-ui/src/api/system/serviceType.js @@ -0,0 +1,61 @@ +import request from '@/utils/request' + +// 查询服务类型列表 +export function listServiceType(query) { + return request({ + url: '/system/serviceType/list', + method: 'get', + params: query + }) +} + +// 查询服务类型详细 +export function getServiceType(id) { + return request({ + url: '/system/serviceType/' + id, + method: 'get' + }) +} + +// 新增服务类型 +export function addServiceType(data) { + return request({ + url: '/system/serviceType', + method: 'post', + data: data + }) +} + +// 修改服务类型 +export function updateServiceType(data) { + return request({ + url: '/system/serviceType', + method: 'put', + data: data + }) +} + +// 删除服务类型 +export function delServiceType(id) { + return request({ + url: '/system/serviceType/' + id, + method: 'delete' + }) +} + +// 更新价格(记录变更历史) +export function updatePrice(id, data) { + return request({ + url: '/system/serviceType/price/' + id, + method: 'put', + data: data + }) +} + +// 查询价格变更历史 +export function getPriceHistory(serviceTypeId) { + return request({ + url: '/system/serviceType/priceHistory/' + serviceTypeId, + method: 'get' + }) +} diff --git a/rlz-ui/src/views/system/serviceType/index.vue b/rlz-ui/src/views/system/serviceType/index.vue new file mode 100644 index 0000000..a8ac809 --- /dev/null +++ b/rlz-ui/src/views/system/serviceType/index.vue @@ -0,0 +1,413 @@ + + + diff --git a/rlz/ruoyi-system/src/main/java/com/ruoyi/system/controller/RlzServiceTypeController.java b/rlz/ruoyi-system/src/main/java/com/ruoyi/system/controller/RlzServiceTypeController.java new file mode 100644 index 0000000..4dce46c --- /dev/null +++ b/rlz/ruoyi-system/src/main/java/com/ruoyi/system/controller/RlzServiceTypeController.java @@ -0,0 +1,133 @@ +package com.ruoyi.system.controller; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; +import javax.servlet.http.HttpServletResponse; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.system.domain.RlzServiceType; +import com.ruoyi.system.domain.RlzPriceHistory; +import com.ruoyi.system.service.IRlzServiceTypeService; +import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.common.core.page.TableDataInfo; + +/** + * 服务类型Controller + * + * @author ruoyi + * @date 2026-05-14 + */ +@RestController +@RequestMapping("/system/serviceType") +public class RlzServiceTypeController extends BaseController +{ + @Autowired + private IRlzServiceTypeService rlzServiceTypeService; + + /** + * 查询服务类型列表 + */ + @PreAuthorize("@ss.hasPermi('system:serviceType:list')") + @GetMapping("/list") + public TableDataInfo list(RlzServiceType rlzServiceType) + { + startPage(); + List list = rlzServiceTypeService.selectRlzServiceTypeList(rlzServiceType); + return getDataTable(list); + } + + /** + * 导出服务类型列表 + */ + @PreAuthorize("@ss.hasPermi('system:serviceType:export')") + @Log(title = "服务类型", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, RlzServiceType rlzServiceType) + { + List list = rlzServiceTypeService.selectRlzServiceTypeList(rlzServiceType); + ExcelUtil util = new ExcelUtil(RlzServiceType.class); + util.exportExcel(response, list, "服务类型数据"); + } + + /** + * 获取服务类型详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:serviceType:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) + { + return AjaxResult.success(rlzServiceTypeService.selectRlzServiceTypeById(id)); + } + + /** + * 新增服务类型 + */ + @PreAuthorize("@ss.hasPermi('system:serviceType:add')") + @Log(title = "服务类型", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody RlzServiceType rlzServiceType) + { + return toAjax(rlzServiceTypeService.insertRlzServiceType(rlzServiceType)); + } + + /** + * 修改服务类型 + */ + @PreAuthorize("@ss.hasPermi('system:serviceType:edit')") + @Log(title = "服务类型", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody RlzServiceType rlzServiceType) + { + return toAjax(rlzServiceTypeService.updateRlzServiceType(rlzServiceType)); + } + + /** + * 删除服务类型 + */ + @PreAuthorize("@ss.hasPermi('system:serviceType:remove')") + @Log(title = "服务类型", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) + { + return toAjax(rlzServiceTypeService.deleteRlzServiceTypeByIds(ids)); + } + + /** + * 更新服务类型价格(自动记录变更历史) + */ + @PreAuthorize("@ss.hasPermi('system:serviceType:edit')") + @Log(title = "服务类型价格", businessType = BusinessType.UPDATE) + @PutMapping("/price/{id}") + public AjaxResult updatePrice(@PathVariable Long id, @RequestBody Map params) + { + BigDecimal newPrice = new BigDecimal(params.get("price").toString()); + String reason = params.get("reason") != null ? params.get("reason").toString() : ""; + Long operatorId = this.getLoginUser().getUserId(); + String operatorName = this.getLoginUser().getUsername(); + return toAjax(rlzServiceTypeService.updatePrice(id, newPrice, reason, operatorId, operatorName)); + } + + /** + * 查询价格变更历史 + */ + @PreAuthorize("@ss.hasPermi('system:serviceType:query')") + @GetMapping("/priceHistory/{serviceTypeId}") + public AjaxResult priceHistory(@PathVariable Long serviceTypeId) + { + List list = rlzServiceTypeService.selectPriceHistoryByServiceTypeId(serviceTypeId); + return AjaxResult.success(list); + } +} diff --git a/rlz/ruoyi-system/src/main/java/com/ruoyi/system/domain/RlzPriceHistory.java b/rlz/ruoyi-system/src/main/java/com/ruoyi/system/domain/RlzPriceHistory.java new file mode 100644 index 0000000..84afa43 --- /dev/null +++ b/rlz/ruoyi-system/src/main/java/com/ruoyi/system/domain/RlzPriceHistory.java @@ -0,0 +1,127 @@ +package com.ruoyi.system.domain; + +import java.math.BigDecimal; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.ruoyi.common.annotation.Excel; + +/** + * 价格变更历史对象 rlz_price_history + * + * @author ruoyi + * @date 2026-05-14 + */ +public class RlzPriceHistory +{ + private static final long serialVersionUID = 1L; + + /** 主键 */ + private Long id; + + /** 服务类型ID */ + private Long serviceTypeId; + + /** 旧价格 */ + @Excel(name = "旧价格") + private BigDecimal oldPrice; + + /** 新价格 */ + @Excel(name = "新价格") + private BigDecimal newPrice; + + /** 变更原因 */ + @Excel(name = "变更原因") + private String changeReason; + + /** 操作人ID */ + private Long operatorId; + + /** 操作人名称 */ + @Excel(name = "操作人名称") + private String operatorName; + + /** 创建时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + public void setId(Long id) + { + this.id = id; + } + + public Long getId() + { + return id; + } + + public void setServiceTypeId(Long serviceTypeId) + { + this.serviceTypeId = serviceTypeId; + } + + public Long getServiceTypeId() + { + return serviceTypeId; + } + + public void setOldPrice(BigDecimal oldPrice) + { + this.oldPrice = oldPrice; + } + + public BigDecimal getOldPrice() + { + return oldPrice; + } + + public void setNewPrice(BigDecimal newPrice) + { + this.newPrice = newPrice; + } + + public BigDecimal getNewPrice() + { + return newPrice; + } + + public void setChangeReason(String changeReason) + { + this.changeReason = changeReason; + } + + public String getChangeReason() + { + return changeReason; + } + + public void setOperatorId(Long operatorId) + { + this.operatorId = operatorId; + } + + public Long getOperatorId() + { + return operatorId; + } + + public void setOperatorName(String operatorName) + { + this.operatorName = operatorName; + } + + public String getOperatorName() + { + return operatorName; + } + + public void setCreateTime(Date createTime) + { + this.createTime = createTime; + } + + public Date getCreateTime() + { + return createTime; + } +} diff --git a/rlz/ruoyi-system/src/main/java/com/ruoyi/system/domain/RlzServiceType.java b/rlz/ruoyi-system/src/main/java/com/ruoyi/system/domain/RlzServiceType.java new file mode 100644 index 0000000..20cb6c8 --- /dev/null +++ b/rlz/ruoyi-system/src/main/java/com/ruoyi/system/domain/RlzServiceType.java @@ -0,0 +1,147 @@ +package com.ruoyi.system.domain; + +import java.math.BigDecimal; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.ruoyi.common.annotation.Excel; +import com.ruoyi.common.core.domain.BaseEntity; + +/** + * 服务类型对象 rlz_service_type + * + * @author ruoyi + * @date 2026-05-14 + */ +public class RlzServiceType extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 主键 */ + private Long id; + + /** 服务名称 */ + @Excel(name = "服务名称") + private String name; + + /** 类别: 1=陪护 2=陪诊 */ + @Excel(name = "类别", readConverterExp = "1=陪护,2=陪诊") + private String category; + + /** 类型编码: 1=全程陪诊 2=诊前约号 3=取送结果 4=代办问诊 */ + @Excel(name = "类型编码") + private String typeCode; + + /** 价格 */ + @Excel(name = "价格") + private BigDecimal price; + + /** 服务内容描述 */ + @Excel(name = "服务内容描述") + private String description; + + /** 状态: 0=启用 1=停用 */ + @Excel(name = "状态", readConverterExp = "0=启用,1=停用") + private String status; + + /** 排序 */ + private Integer sortOrder; + + public void setId(Long id) + { + this.id = id; + } + + public Long getId() + { + return id; + } + + public void setName(String name) + { + this.name = name; + } + + public String getName() + { + return name; + } + + public void setCategory(String category) + { + this.category = category; + } + + public String getCategory() + { + return category; + } + + public void setTypeCode(String typeCode) + { + this.typeCode = typeCode; + } + + public String getTypeCode() + { + return typeCode; + } + + public void setPrice(BigDecimal price) + { + this.price = price; + } + + public BigDecimal getPrice() + { + return price; + } + + public void setDescription(String description) + { + this.description = description; + } + + public String getDescription() + { + return description; + } + + public void setStatus(String status) + { + this.status = status; + } + + public String getStatus() + { + return status; + } + + public void setSortOrder(Integer sortOrder) + { + this.sortOrder = sortOrder; + } + + public Integer getSortOrder() + { + return sortOrder; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("id", getId()) + .append("name", getName()) + .append("category", getCategory()) + .append("typeCode", getTypeCode()) + .append("price", getPrice()) + .append("description", getDescription()) + .append("status", getStatus()) + .append("sortOrder", getSortOrder()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/rlz/ruoyi-system/src/main/java/com/ruoyi/system/mapper/RlzPriceHistoryMapper.java b/rlz/ruoyi-system/src/main/java/com/ruoyi/system/mapper/RlzPriceHistoryMapper.java new file mode 100644 index 0000000..39fb7d0 --- /dev/null +++ b/rlz/ruoyi-system/src/main/java/com/ruoyi/system/mapper/RlzPriceHistoryMapper.java @@ -0,0 +1,17 @@ +package com.ruoyi.system.mapper; + +import java.util.List; +import com.ruoyi.system.domain.RlzPriceHistory; + +/** + * 价格变更历史Mapper接口 + * + * @author ruoyi + * @date 2026-05-14 + */ +public interface RlzPriceHistoryMapper +{ + public List selectRlzPriceHistoryList(RlzPriceHistory rlzPriceHistory); + + public int insertRlzPriceHistory(RlzPriceHistory rlzPriceHistory); +} diff --git a/rlz/ruoyi-system/src/main/java/com/ruoyi/system/mapper/RlzServiceTypeMapper.java b/rlz/ruoyi-system/src/main/java/com/ruoyi/system/mapper/RlzServiceTypeMapper.java new file mode 100644 index 0000000..bb1026e --- /dev/null +++ b/rlz/ruoyi-system/src/main/java/com/ruoyi/system/mapper/RlzServiceTypeMapper.java @@ -0,0 +1,25 @@ +package com.ruoyi.system.mapper; + +import java.util.List; +import com.ruoyi.system.domain.RlzServiceType; + +/** + * 服务类型Mapper接口 + * + * @author ruoyi + * @date 2026-05-14 + */ +public interface RlzServiceTypeMapper +{ + public RlzServiceType selectRlzServiceTypeById(Long id); + + public List selectRlzServiceTypeList(RlzServiceType rlzServiceType); + + public int insertRlzServiceType(RlzServiceType rlzServiceType); + + public int updateRlzServiceType(RlzServiceType rlzServiceType); + + public int deleteRlzServiceTypeById(Long id); + + public int deleteRlzServiceTypeByIds(Long[] ids); +} diff --git a/rlz/ruoyi-system/src/main/java/com/ruoyi/system/service/IRlzServiceTypeService.java b/rlz/ruoyi-system/src/main/java/com/ruoyi/system/service/IRlzServiceTypeService.java new file mode 100644 index 0000000..2bdc2d9 --- /dev/null +++ b/rlz/ruoyi-system/src/main/java/com/ruoyi/system/service/IRlzServiceTypeService.java @@ -0,0 +1,37 @@ +package com.ruoyi.system.service; + +import java.math.BigDecimal; +import java.util.List; +import com.ruoyi.system.domain.RlzServiceType; +import com.ruoyi.system.domain.RlzPriceHistory; + +/** + * 服务类型Service接口 + * + * @author ruoyi + * @date 2026-05-14 + */ +public interface IRlzServiceTypeService +{ + public RlzServiceType selectRlzServiceTypeById(Long id); + + public List selectRlzServiceTypeList(RlzServiceType rlzServiceType); + + public int insertRlzServiceType(RlzServiceType rlzServiceType); + + public int updateRlzServiceType(RlzServiceType rlzServiceType); + + public int deleteRlzServiceTypeByIds(Long[] ids); + + public int deleteRlzServiceTypeById(Long id); + + /** + * 更新服务类型价格(自动记录价格变更历史) + */ + public int updatePrice(Long id, BigDecimal newPrice, String reason, Long operatorId, String operatorName); + + /** + * 查询指定服务类型的价格变更历史 + */ + public List selectPriceHistoryByServiceTypeId(Long serviceTypeId); +} diff --git a/rlz/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/RlzServiceTypeServiceImpl.java b/rlz/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/RlzServiceTypeServiceImpl.java new file mode 100644 index 0000000..f989a48 --- /dev/null +++ b/rlz/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/RlzServiceTypeServiceImpl.java @@ -0,0 +1,107 @@ +package com.ruoyi.system.service.impl; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; +import com.ruoyi.common.utils.DateUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import com.ruoyi.system.mapper.RlzServiceTypeMapper; +import com.ruoyi.system.mapper.RlzPriceHistoryMapper; +import com.ruoyi.system.domain.RlzServiceType; +import com.ruoyi.system.domain.RlzPriceHistory; +import com.ruoyi.system.service.IRlzServiceTypeService; + +/** + * 服务类型Service业务层处理 + * + * @author ruoyi + * @date 2026-05-14 + */ +@Service +public class RlzServiceTypeServiceImpl implements IRlzServiceTypeService +{ + @Autowired + private RlzServiceTypeMapper rlzServiceTypeMapper; + + @Autowired + private RlzPriceHistoryMapper rlzPriceHistoryMapper; + + @Override + public RlzServiceType selectRlzServiceTypeById(Long id) + { + return rlzServiceTypeMapper.selectRlzServiceTypeById(id); + } + + @Override + public List selectRlzServiceTypeList(RlzServiceType rlzServiceType) + { + return rlzServiceTypeMapper.selectRlzServiceTypeList(rlzServiceType); + } + + @Override + public int insertRlzServiceType(RlzServiceType rlzServiceType) + { + rlzServiceType.setCreateTime(DateUtils.getNowDate()); + return rlzServiceTypeMapper.insertRlzServiceType(rlzServiceType); + } + + @Override + public int updateRlzServiceType(RlzServiceType rlzServiceType) + { + rlzServiceType.setUpdateTime(DateUtils.getNowDate()); + return rlzServiceTypeMapper.updateRlzServiceType(rlzServiceType); + } + + @Override + public int deleteRlzServiceTypeByIds(Long[] ids) + { + return rlzServiceTypeMapper.deleteRlzServiceTypeByIds(ids); + } + + @Override + public int deleteRlzServiceTypeById(Long id) + { + return rlzServiceTypeMapper.deleteRlzServiceTypeById(id); + } + + @Override + @Transactional + public int updatePrice(Long id, BigDecimal newPrice, String reason, Long operatorId, String operatorName) + { + RlzServiceType serviceType = rlzServiceTypeMapper.selectRlzServiceTypeById(id); + if (serviceType == null) { + return 0; + } + BigDecimal oldPrice = serviceType.getPrice(); + + // 更新价格 + RlzServiceType update = new RlzServiceType(); + update.setId(id); + update.setPrice(newPrice); + update.setUpdateTime(DateUtils.getNowDate()); + int rows = rlzServiceTypeMapper.updateRlzServiceType(update); + + // 记录价格变更历史 + RlzPriceHistory history = new RlzPriceHistory(); + history.setServiceTypeId(id); + history.setOldPrice(oldPrice); + history.setNewPrice(newPrice); + history.setChangeReason(reason); + history.setOperatorId(operatorId); + history.setOperatorName(operatorName); + history.setCreateTime(new Date()); + rlzPriceHistoryMapper.insertRlzPriceHistory(history); + + return rows; + } + + @Override + public List selectPriceHistoryByServiceTypeId(Long serviceTypeId) + { + RlzPriceHistory query = new RlzPriceHistory(); + query.setServiceTypeId(serviceTypeId); + return rlzPriceHistoryMapper.selectRlzPriceHistoryList(query); + } +} diff --git a/rlz/ruoyi-system/src/main/resources/mapper/system/RlzPriceHistoryMapper.xml b/rlz/ruoyi-system/src/main/resources/mapper/system/RlzPriceHistoryMapper.xml new file mode 100644 index 0000000..c28df7d --- /dev/null +++ b/rlz/ruoyi-system/src/main/resources/mapper/system/RlzPriceHistoryMapper.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + select id, service_type_id, old_price, new_price, change_reason, + operator_id, operator_name, create_time + from rlz_price_history + + + + + + insert into rlz_price_history + + service_type_id, + old_price, + new_price, + change_reason, + operator_id, + operator_name, + create_time, + + + #{serviceTypeId}, + #{oldPrice}, + #{newPrice}, + #{changeReason}, + #{operatorId}, + #{operatorName}, + #{createTime}, + + + diff --git a/rlz/ruoyi-system/src/main/resources/mapper/system/RlzServiceTypeMapper.xml b/rlz/ruoyi-system/src/main/resources/mapper/system/RlzServiceTypeMapper.xml new file mode 100644 index 0000000..327a882 --- /dev/null +++ b/rlz/ruoyi-system/src/main/resources/mapper/system/RlzServiceTypeMapper.xml @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + select id, name, category, type_code, price, description, status, sort_order, + create_by, create_time, update_by, update_time, remark + from rlz_service_type + + + + + + + + insert into rlz_service_type + + name, + category, + type_code, + price, + description, + status, + sort_order, + create_by, + create_time, + remark, + + + #{name}, + #{category}, + #{typeCode}, + #{price}, + #{description}, + #{status}, + #{sortOrder}, + #{createBy}, + #{createTime}, + #{remark}, + + + + + update rlz_service_type + + name = #{name}, + category = #{category}, + type_code = #{typeCode}, + price = #{price}, + description = #{description}, + status = #{status}, + sort_order = #{sortOrder}, + update_by = #{updateBy}, + update_time = #{updateTime}, + remark = #{remark}, + + where id = #{id} + + + + delete from rlz_service_type where id = #{id} + + + + delete from rlz_service_type where id in + + #{id} + + +