feat: add service type management module (#15)
- Add rlz_service_type and rlz_price_history tables - Add backend entities, mapper, service, and controller for /system/serviceType - Add frontend Vue page with list/create/edit/price update/price history - Add sys_menu entries and role permissions for admin role - Add admin backend module planning document Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
||||
[submodule "rlz"]
|
||||
path = rlz
|
||||
url = https://gitee.com/renjianbo0118/ruoyi.git
|
||||
|
||||
257
docs/后台管理功能模块规划.md
Normal file
257
docs/后台管理功能模块规划.md
Normal file
@@ -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`
|
||||
96
docs/改进完成记录.md
Normal file
96
docs/改进完成记录.md
Normal file
@@ -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` | 新增 |
|
||||
1
rlz
1
rlz
Submodule rlz deleted from 28e0b6fc9f
61
rlz-ui/src/api/system/serviceType.js
Normal file
61
rlz-ui/src/api/system/serviceType.js
Normal file
@@ -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'
|
||||
})
|
||||
}
|
||||
413
rlz-ui/src/views/system/serviceType/index.vue
Normal file
413
rlz-ui/src/views/system/serviceType/index.vue
Normal file
@@ -0,0 +1,413 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="服务名称" prop="name">
|
||||
<el-input
|
||||
v-model="queryParams.name"
|
||||
placeholder="请输入服务名称"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="类别" prop="category">
|
||||
<el-select v-model="queryParams.category" placeholder="请选择类别" clearable>
|
||||
<el-option label="陪护" value="1" />
|
||||
<el-option label="陪诊" value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
|
||||
<el-option label="启用" value="0" />
|
||||
<el-option label="停用" value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-plus"
|
||||
size="mini"
|
||||
@click="handleAdd"
|
||||
v-hasPermi="['system:serviceType:add']"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
icon="el-icon-edit"
|
||||
size="mini"
|
||||
:disabled="single"
|
||||
@click="handleUpdate"
|
||||
v-hasPermi="['system:serviceType:edit']"
|
||||
>修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
v-hasPermi="['system:serviceType:remove']"
|
||||
>删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
v-hasPermi="['system:serviceType:export']"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="serviceTypeList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="排序" align="center" prop="sortOrder" width="60" />
|
||||
<el-table-column label="服务名称" align="center" prop="name" />
|
||||
<el-table-column label="类别" align="center" prop="category" width="80">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.category == '2' ? 'success' : 'warning'" size="small">
|
||||
{{ scope.row.category == '2' ? '陪诊' : scope.row.category == '1' ? '陪护' : '-' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="类型编码" align="center" prop="typeCode" width="80">
|
||||
<template slot-scope="scope">
|
||||
{{ serviceTypeMap[scope.row.typeCode] || scope.row.typeCode }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="价格(元)" align="center" prop="price" width="100">
|
||||
<template slot-scope="scope">
|
||||
<span style="color: #f56c6c; font-weight: bold;">{{ scope.row.price }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="服务描述" align="center" prop="description" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="状态" align="center" prop="status" width="80">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.status == '0' ? 'success' : 'danger'" size="small">
|
||||
{{ scope.row.status == '0' ? '启用' : '停用' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="280">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['system:serviceType:edit']"
|
||||
>修改</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-s-order"
|
||||
@click="handlePriceUpdate(scope.row)"
|
||||
v-hasPermi="['system:serviceType:edit']"
|
||||
>调价</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-time"
|
||||
@click="handlePriceHistory(scope.row)"
|
||||
v-hasPermi="['system:serviceType:query']"
|
||||
>价格历史</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
v-hasPermi="['system:serviceType:remove']"
|
||||
>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 新增/修改对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="580px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="90px">
|
||||
<el-form-item label="服务名称" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入服务名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="类别" prop="category">
|
||||
<el-select v-model="form.category" placeholder="请选择类别" style="width: 100%">
|
||||
<el-option label="陪护" value="1" />
|
||||
<el-option label="陪诊" value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型编码" prop="typeCode">
|
||||
<el-select v-model="form.typeCode" placeholder="请选择类型编码" style="width: 100%">
|
||||
<el-option label="全程陪诊" value="1" />
|
||||
<el-option label="诊前约号" value="2" />
|
||||
<el-option label="取送结果" value="3" />
|
||||
<el-option label="代办问诊" value="4" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="价格(元)" prop="price">
|
||||
<el-input-number v-model="form.price" :min="0" :precision="2" style="width: 100%" placeholder="请输入价格" />
|
||||
</el-form-item>
|
||||
<el-form-item label="服务描述" prop="description">
|
||||
<el-input v-model="form.description" type="textarea" :rows="3" placeholder="请输入服务内容描述" />
|
||||
</el-form-item>
|
||||
<el-form-item label="排序" prop="sortOrder">
|
||||
<el-input-number v-model="form.sortOrder" :min="0" style="width: 100%" placeholder="请输入排序号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio label="0">启用</el-radio>
|
||||
<el-radio label="1">停用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 调价对话框 -->
|
||||
<el-dialog title="调整价格" :visible.sync="priceOpen" width="450px" append-to-body>
|
||||
<el-form ref="priceForm" :model="priceForm" :rules="priceRules" label-width="90px">
|
||||
<el-form-item label="服务名称">
|
||||
<span>{{ currentServiceType.name }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="当前价格">
|
||||
<span style="color: #f56c6c; font-weight: bold;">{{ currentServiceType.price }} 元</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="新价格" prop="price">
|
||||
<el-input-number v-model="priceForm.price" :min="0" :precision="2" style="width: 100%" placeholder="请输入新价格" />
|
||||
</el-form-item>
|
||||
<el-form-item label="变更原因" prop="reason">
|
||||
<el-input v-model="priceForm.reason" type="textarea" :rows="2" placeholder="请输入变更原因" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitPriceUpdate">确 定</el-button>
|
||||
<el-button @click="priceOpen = false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 价格历史对话框 -->
|
||||
<el-dialog title="价格变更历史" :visible.sync="historyOpen" width="700px" append-to-body>
|
||||
<el-table :data="priceHistoryList" v-loading="historyLoading">
|
||||
<el-table-column label="旧价格(元)" align="center" prop="oldPrice" />
|
||||
<el-table-column label="新价格(元)" align="center" prop="newPrice">
|
||||
<template slot-scope="scope">
|
||||
<span style="color: #f56c6c; font-weight: bold;">{{ scope.row.newPrice }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="变更原因" align="center" prop="changeReason" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="操作人" align="center" prop="operatorName" />
|
||||
<el-table-column label="操作时间" align="center" prop="createTime" width="160" />
|
||||
</el-table>
|
||||
<div v-if="priceHistoryList.length === 0 && !historyLoading" style="text-align: center; padding: 20px; color: #999;">
|
||||
暂无价格变更记录
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listServiceType, getServiceType, delServiceType, addServiceType, updateServiceType, updatePrice, getPriceHistory } from "@/api/system/serviceType";
|
||||
|
||||
export default {
|
||||
name: "ServiceType",
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
ids: [],
|
||||
single: true,
|
||||
multiple: true,
|
||||
showSearch: true,
|
||||
total: 0,
|
||||
serviceTypeList: [],
|
||||
title: "",
|
||||
open: false,
|
||||
priceOpen: false,
|
||||
historyOpen: false,
|
||||
historyLoading: false,
|
||||
priceHistoryList: [],
|
||||
currentServiceType: {},
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
name: null,
|
||||
category: null,
|
||||
status: null,
|
||||
},
|
||||
form: {},
|
||||
priceForm: {
|
||||
price: null,
|
||||
reason: ''
|
||||
},
|
||||
rules: {
|
||||
name: [
|
||||
{ required: true, message: "服务名称不能为空", trigger: "blur" }
|
||||
],
|
||||
category: [
|
||||
{ required: true, message: "请选择类别", trigger: "change" }
|
||||
],
|
||||
price: [
|
||||
{ required: true, message: "价格不能为空", trigger: "blur" }
|
||||
],
|
||||
status: [
|
||||
{ required: true, message: "请选择状态", trigger: "change" }
|
||||
],
|
||||
},
|
||||
priceRules: {
|
||||
price: [
|
||||
{ required: true, message: "新价格不能为空", trigger: "blur" }
|
||||
],
|
||||
},
|
||||
serviceTypeMap: {
|
||||
'1': '全程陪诊',
|
||||
'2': '诊前约号',
|
||||
'3': '取送结果',
|
||||
'4': '代办问诊',
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.loading = true;
|
||||
listServiceType(this.queryParams).then(response => {
|
||||
this.serviceTypeList = response.data;
|
||||
this.total = response.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
cancel() {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
},
|
||||
reset() {
|
||||
this.form = {
|
||||
id: null,
|
||||
name: null,
|
||||
category: null,
|
||||
typeCode: null,
|
||||
price: null,
|
||||
description: null,
|
||||
status: '0',
|
||||
sortOrder: 0,
|
||||
remark: null,
|
||||
};
|
||||
this.resetForm("form");
|
||||
},
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.getList();
|
||||
},
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.id)
|
||||
this.single = selection.length !== 1
|
||||
this.multiple = !selection.length
|
||||
},
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.open = true;
|
||||
this.title = "新增服务类型";
|
||||
},
|
||||
handleUpdate(row) {
|
||||
this.reset();
|
||||
const id = row.id || this.ids
|
||||
getServiceType(id).then(response => {
|
||||
this.form = response.data;
|
||||
this.open = true;
|
||||
this.title = "修改服务类型";
|
||||
});
|
||||
},
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
if (this.form.id != null) {
|
||||
updateServiceType(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
} else {
|
||||
addServiceType(this.form).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
handleDelete(row) {
|
||||
const ids = row.id || this.ids.join(',');
|
||||
this.$modal.confirm('是否确认删除该服务类型?').then(function() {
|
||||
return delServiceType(ids);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {});
|
||||
},
|
||||
handleExport() {
|
||||
this.download('system/serviceType/export', {
|
||||
...this.queryParams
|
||||
}, `serviceType_${new Date().getTime()}.xlsx`)
|
||||
},
|
||||
// 调价
|
||||
handlePriceUpdate(row) {
|
||||
this.currentServiceType = row;
|
||||
this.priceForm = { price: null, reason: '' };
|
||||
this.priceOpen = true;
|
||||
},
|
||||
submitPriceUpdate() {
|
||||
this.$refs["priceForm"].validate(valid => {
|
||||
if (valid) {
|
||||
updatePrice(this.currentServiceType.id, this.priceForm).then(response => {
|
||||
this.$modal.msgSuccess("价格更新成功");
|
||||
this.priceOpen = false;
|
||||
this.getList();
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
// 价格历史
|
||||
handlePriceHistory(row) {
|
||||
this.currentServiceType = row;
|
||||
this.historyOpen = true;
|
||||
this.historyLoading = true;
|
||||
getPriceHistory(row.id).then(response => {
|
||||
this.priceHistoryList = response.data;
|
||||
this.historyLoading = false;
|
||||
});
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -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<RlzServiceType> 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<RlzServiceType> list = rlzServiceTypeService.selectRlzServiceTypeList(rlzServiceType);
|
||||
ExcelUtil<RlzServiceType> util = new ExcelUtil<RlzServiceType>(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<String, Object> 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<RlzPriceHistory> list = rlzServiceTypeService.selectPriceHistoryByServiceTypeId(serviceTypeId);
|
||||
return AjaxResult.success(list);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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<RlzPriceHistory> selectRlzPriceHistoryList(RlzPriceHistory rlzPriceHistory);
|
||||
|
||||
public int insertRlzPriceHistory(RlzPriceHistory rlzPriceHistory);
|
||||
}
|
||||
@@ -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<RlzServiceType> selectRlzServiceTypeList(RlzServiceType rlzServiceType);
|
||||
|
||||
public int insertRlzServiceType(RlzServiceType rlzServiceType);
|
||||
|
||||
public int updateRlzServiceType(RlzServiceType rlzServiceType);
|
||||
|
||||
public int deleteRlzServiceTypeById(Long id);
|
||||
|
||||
public int deleteRlzServiceTypeByIds(Long[] ids);
|
||||
}
|
||||
@@ -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<RlzServiceType> 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<RlzPriceHistory> selectPriceHistoryByServiceTypeId(Long serviceTypeId);
|
||||
}
|
||||
@@ -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<RlzServiceType> 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<RlzPriceHistory> selectPriceHistoryByServiceTypeId(Long serviceTypeId)
|
||||
{
|
||||
RlzPriceHistory query = new RlzPriceHistory();
|
||||
query.setServiceTypeId(serviceTypeId);
|
||||
return rlzPriceHistoryMapper.selectRlzPriceHistoryList(query);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.system.mapper.RlzPriceHistoryMapper">
|
||||
|
||||
<resultMap type="RlzPriceHistory" id="RlzPriceHistoryResult">
|
||||
<result property="id" column="id" />
|
||||
<result property="serviceTypeId" column="service_type_id" />
|
||||
<result property="oldPrice" column="old_price" />
|
||||
<result property="newPrice" column="new_price" />
|
||||
<result property="changeReason" column="change_reason" />
|
||||
<result property="operatorId" column="operator_id" />
|
||||
<result property="operatorName" column="operator_name" />
|
||||
<result property="createTime" column="create_time" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectRlzPriceHistoryVo">
|
||||
select id, service_type_id, old_price, new_price, change_reason,
|
||||
operator_id, operator_name, create_time
|
||||
from rlz_price_history
|
||||
</sql>
|
||||
|
||||
<select id="selectRlzPriceHistoryList" parameterType="RlzPriceHistory" resultMap="RlzPriceHistoryResult">
|
||||
<include refid="selectRlzPriceHistoryVo"/>
|
||||
<where>
|
||||
<if test="serviceTypeId != null"> and service_type_id = #{serviceTypeId}</if>
|
||||
</where>
|
||||
order by create_time desc
|
||||
</select>
|
||||
|
||||
<insert id="insertRlzPriceHistory" parameterType="RlzPriceHistory" useGeneratedKeys="true" keyProperty="id">
|
||||
insert into rlz_price_history
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="serviceTypeId != null">service_type_id,</if>
|
||||
<if test="oldPrice != null">old_price,</if>
|
||||
<if test="newPrice != null">new_price,</if>
|
||||
<if test="changeReason != null">change_reason,</if>
|
||||
<if test="operatorId != null">operator_id,</if>
|
||||
<if test="operatorName != null">operator_name,</if>
|
||||
<if test="createTime != null">create_time,</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="serviceTypeId != null">#{serviceTypeId},</if>
|
||||
<if test="oldPrice != null">#{oldPrice},</if>
|
||||
<if test="newPrice != null">#{newPrice},</if>
|
||||
<if test="changeReason != null">#{changeReason},</if>
|
||||
<if test="operatorId != null">#{operatorId},</if>
|
||||
<if test="operatorName != null">#{operatorName},</if>
|
||||
<if test="createTime != null">#{createTime},</if>
|
||||
</trim>
|
||||
</insert>
|
||||
</mapper>
|
||||
@@ -0,0 +1,100 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.system.mapper.RlzServiceTypeMapper">
|
||||
|
||||
<resultMap type="RlzServiceType" id="RlzServiceTypeResult">
|
||||
<result property="id" column="id" />
|
||||
<result property="name" column="name" />
|
||||
<result property="category" column="category" />
|
||||
<result property="typeCode" column="type_code" />
|
||||
<result property="price" column="price" />
|
||||
<result property="description" column="description" />
|
||||
<result property="status" column="status" />
|
||||
<result property="sortOrder" column="sort_order" />
|
||||
<result property="createBy" column="create_by" />
|
||||
<result property="createTime" column="create_time" />
|
||||
<result property="updateBy" column="update_by" />
|
||||
<result property="updateTime" column="update_time" />
|
||||
<result property="remark" column="remark" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectRlzServiceTypeVo">
|
||||
select id, name, category, type_code, price, description, status, sort_order,
|
||||
create_by, create_time, update_by, update_time, remark
|
||||
from rlz_service_type
|
||||
</sql>
|
||||
|
||||
<select id="selectRlzServiceTypeList" parameterType="RlzServiceType" resultMap="RlzServiceTypeResult">
|
||||
<include refid="selectRlzServiceTypeVo"/>
|
||||
<where>
|
||||
<if test="name != null and name != ''"> and name like concat('%', #{name}, '%')</if>
|
||||
<if test="category != null and category != ''"> and category = #{category}</if>
|
||||
<if test="typeCode != null and typeCode != ''"> and type_code = #{typeCode}</if>
|
||||
<if test="status != null and status != ''"> and status = #{status}</if>
|
||||
</where>
|
||||
order by sort_order asc
|
||||
</select>
|
||||
|
||||
<select id="selectRlzServiceTypeById" parameterType="Long" resultMap="RlzServiceTypeResult">
|
||||
<include refid="selectRlzServiceTypeVo"/>
|
||||
where id = #{id}
|
||||
</select>
|
||||
|
||||
<insert id="insertRlzServiceType" parameterType="RlzServiceType" useGeneratedKeys="true" keyProperty="id">
|
||||
insert into rlz_service_type
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="name != null">name,</if>
|
||||
<if test="category != null">category,</if>
|
||||
<if test="typeCode != null">type_code,</if>
|
||||
<if test="price != null">price,</if>
|
||||
<if test="description != null">description,</if>
|
||||
<if test="status != null">status,</if>
|
||||
<if test="sortOrder != null">sort_order,</if>
|
||||
<if test="createBy != null">create_by,</if>
|
||||
<if test="createTime != null">create_time,</if>
|
||||
<if test="remark != null">remark,</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="name != null">#{name},</if>
|
||||
<if test="category != null">#{category},</if>
|
||||
<if test="typeCode != null">#{typeCode},</if>
|
||||
<if test="price != null">#{price},</if>
|
||||
<if test="description != null">#{description},</if>
|
||||
<if test="status != null">#{status},</if>
|
||||
<if test="sortOrder != null">#{sortOrder},</if>
|
||||
<if test="createBy != null">#{createBy},</if>
|
||||
<if test="createTime != null">#{createTime},</if>
|
||||
<if test="remark != null">#{remark},</if>
|
||||
</trim>
|
||||
</insert>
|
||||
|
||||
<update id="updateRlzServiceType" parameterType="RlzServiceType">
|
||||
update rlz_service_type
|
||||
<trim prefix="SET" suffixOverrides=",">
|
||||
<if test="name != null">name = #{name},</if>
|
||||
<if test="category != null">category = #{category},</if>
|
||||
<if test="typeCode != null">type_code = #{typeCode},</if>
|
||||
<if test="price != null">price = #{price},</if>
|
||||
<if test="description != null">description = #{description},</if>
|
||||
<if test="status != null">status = #{status},</if>
|
||||
<if test="sortOrder != null">sort_order = #{sortOrder},</if>
|
||||
<if test="updateBy != null">update_by = #{updateBy},</if>
|
||||
<if test="updateTime != null">update_time = #{updateTime},</if>
|
||||
<if test="remark != null">remark = #{remark},</if>
|
||||
</trim>
|
||||
where id = #{id}
|
||||
</update>
|
||||
|
||||
<delete id="deleteRlzServiceTypeById" parameterType="Long">
|
||||
delete from rlz_service_type where id = #{id}
|
||||
</delete>
|
||||
|
||||
<delete id="deleteRlzServiceTypeByIds" parameterType="String">
|
||||
delete from rlz_service_type where id in
|
||||
<foreach item="id" collection="array" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</delete>
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user