504 lines
18 KiB
Markdown
504 lines
18 KiB
Markdown
# 中试服务申请单 Phase 1 设计文档
|
||
|
||
> 日期:2026-05-24
|
||
> 模块:中试服务管理 > 中试服务申请单
|
||
> 阶段:Phase 1(核心骨架)
|
||
> 需求来源:`docs/中科兴皖需求V0.3.md` §2.3.9
|
||
|
||
## 1. 概述
|
||
|
||
实现中试服务申请单的完整 CRUD、患者信息管理、输注方案管理、输注计划管理。采用独立后端模块方案(方案A),与现有 `pilot_service.py` 分离。
|
||
|
||
### 分期规划
|
||
|
||
| 阶段 | 范围 | 状态 |
|
||
|------|------|------|
|
||
| Phase 1 | 申请单+患者+输注方案+输注计划 | 本文档 |
|
||
| Phase 2 | 体检管理+交付交接+费用扣减 | 后续 |
|
||
| Phase 3 | 出库生产/质检/放行审核联动 | 后续 |
|
||
|
||
### Phase 1 范围
|
||
|
||
- ✅ 中试申请单 CRUD + 状态流转(开始/完成/作废)
|
||
- ✅ 患者信息(关联客户管理表 biz_customer,选填+新建模式)
|
||
- ✅ 输注方案 CRUD
|
||
- ✅ 输注计划(按疗程数自动生成 + 手动增删调整 + 标记完成)
|
||
- ✅ 申请单列表页 + 详情 Tab 页
|
||
- ❌ 体检管理(Phase 2)
|
||
- ❌ 交付/交接模块(Phase 2)
|
||
- ❌ 出库生产/质检/放行联动(Phase 3)
|
||
- ❌ 费用扣减逻辑(Phase 2 交付模块中实现)
|
||
|
||
---
|
||
|
||
## 2. 数据库变更
|
||
|
||
### 2.1 ALTER biz_pilot_application
|
||
|
||
现有表仅含 `channel_service_order_id` + 公共字段,需增强:
|
||
|
||
```sql
|
||
-- 迁移文件: docs/sql/pilot-application-migration.sql
|
||
|
||
ALTER TABLE biz_pilot_application
|
||
ADD COLUMN application_no VARCHAR(64) DEFAULT NULL
|
||
COMMENT '申请单号(自动生成,前缀ZSSQ)' AFTER id,
|
||
ADD COLUMN application_status VARCHAR(16) NOT NULL DEFAULT 'dks'
|
||
COMMENT 'dks待开始 jxz进行中 ywc已完成 yzf已作废' AFTER application_no,
|
||
ADD COLUMN channel_id VARCHAR(64) DEFAULT NULL
|
||
COMMENT '渠道ID(缓存自服务订单)' AFTER channel_service_order_id,
|
||
ADD COLUMN channel_name VARCHAR(200) DEFAULT NULL
|
||
COMMENT '渠道名称(缓存)' AFTER channel_id;
|
||
|
||
ALTER TABLE biz_pilot_application
|
||
ADD UNIQUE KEY uk_application_no (application_no, del_flag);
|
||
```
|
||
|
||
### 2.2 现有表不变
|
||
|
||
以下 3 张表结构已满足 Phase 1 需求,无需变更:
|
||
|
||
| 表 | 说明 |
|
||
|---|---|
|
||
| `biz_pilot_patient` | 患者信息,含 customer_id 关联 + 完整个人字段 |
|
||
| `biz_pilot_infusion_plan` | 输注方案,含 cell_type/spec/total_course_count 等 |
|
||
| `biz_pilot_infusion_schedule` | 输注计划,含 schedule_status/infusion_time 等 |
|
||
|
||
### 2.3 输注计划状态约定(Phase 1)
|
||
|
||
`biz_pilot_infusion_schedule.schedule_status` 已有值域:dsc/ysc/yjf/yqx。
|
||
|
||
Phase 1 简化使用:
|
||
- 创建时 `schedule_status` 留空(前端显示"-")
|
||
- 用户点击"完成"按钮后更新为 `ywc`(已完成)
|
||
- Phase 3 出库联动时再启用 dsc/ysc/yjf/yqx 等详细状态
|
||
|
||
---
|
||
|
||
## 3. 后端架构
|
||
|
||
### 3.1 Model(models.py 新增)
|
||
|
||
在 `backend/app/models/models.py` 中新增 4 个 SQLAlchemy model:
|
||
|
||
| Model | 表 | 关键字段 |
|
||
|-------|---|---------|
|
||
| `BizPilotApplication` | biz_pilot_application | application_no, application_status, channel_service_order_id, channel_id, channel_name |
|
||
| `BizPilotPatient` | biz_pilot_patient | pilot_application_id, customer_id, patient_name, sex, age, id_card_no, phone_no, emergency_contact, emergency_phone, clinical_diagnosis, diagnosis_attachments, need_checkup |
|
||
| `BizPilotInfusionPlan` | biz_pilot_infusion_plan | pilot_application_id, cell_type, spec_text, total_course_count, course_interval, infusion_route, infusion_start_date |
|
||
| `BizPilotInfusionSchedule` | biz_pilot_infusion_schedule | infusion_plan_id, cell_type, spec_text, infusion_time, schedule_status, attachments |
|
||
|
||
### 3.2 CRUD(新文件:backend/app/crud/pilot_application.py)
|
||
|
||
#### _row_to_dict 函数
|
||
|
||
每个实体一个 `_row_to_dict_*` 函数,作为可读字段的单一事实来源:
|
||
|
||
- `_row_to_dict_application(row)` — 含 channel_name、patient_name(子查询)、infusion_plan_count(子查询)
|
||
- `_row_to_dict_patient(row)`
|
||
- `_row_to_dict_infusion_plan(row)` — 含 schedule_count(子查询)
|
||
- `_row_to_dict_infusion_schedule(row)`
|
||
|
||
#### CRUD 函数清单
|
||
|
||
**Application:**
|
||
|
||
| 函数 | 说明 |
|
||
|------|------|
|
||
| `list_applications(db, tenant_no, filters)` | 分页列表,支持按渠道/状态/服务订单筛选 |
|
||
| `get_application(db, app_id, tenant_no)` | 获取单个申请单详情 |
|
||
| `create_application(db, data, tenant_no, user_id)` | 创建申请单,校验服务订单存在且生效,缓存渠道信息,生成申请单号 |
|
||
| `update_application(db, app_id, data, tenant_no)` | 更新申请单(仅 dks 状态可编辑) |
|
||
| `soft_delete_application(db, app_id, tenant_no)` | 软删除(仅 dks 状态) |
|
||
| `start_application(db, app_id, tenant_no, user_id)` | 状态:dks→jxz |
|
||
| `complete_application(db, app_id, tenant_no, user_id)` | 状态:jxz→ywc |
|
||
| `void_application(db, app_id, tenant_no, user_id)` | 状态:任意→yzf |
|
||
|
||
**Patient:**
|
||
|
||
| 函数 | 说明 |
|
||
|------|------|
|
||
| `get_patient_by_application(db, app_id, tenant_no)` | 获取某申请单的患者信息 |
|
||
| `save_patient(db, app_id, data, tenant_no, user_id)` | 保存/替换患者信息,同步更新 biz_customer 表 |
|
||
|
||
**InfusionPlan:**
|
||
|
||
| 函数 | 说明 |
|
||
|------|------|
|
||
| `list_infusion_plans(db, app_id, tenant_no)` | 获取某申请单的输注方案列表 |
|
||
| `create_infusion_plan(db, app_id, data, tenant_no, user_id)` | 创建输注方案 |
|
||
| `update_infusion_plan(db, plan_id, data, tenant_no)` | 更新输注方案 |
|
||
| `soft_delete_infusion_plan(db, plan_id, tenant_no)` | 软删除输注方案(级联删除其下所有计划) |
|
||
|
||
**InfusionSchedule:**
|
||
|
||
| 函数 | 说明 |
|
||
|------|------|
|
||
| `list_schedules_by_plan(db, plan_id, tenant_no)` | 获取某方案下的输注计划列表 |
|
||
| `auto_generate_schedules(db, plan_id, tenant_no, user_id)` | 按方案的 total_course_count 批量生成计划记录 |
|
||
| `create_schedule(db, plan_id, data, tenant_no, user_id)` | 手动添加单条计划 |
|
||
| `update_schedule(db, schedule_id, data, tenant_no)` | 更新计划(时间/备注等) |
|
||
| `soft_delete_schedule(db, schedule_id, tenant_no)` | 软删除单条计划 |
|
||
| `mark_schedule_complete(db, schedule_id, tenant_no, user_id)` | 标记计划为已完成(schedule_status='ywc') |
|
||
|
||
#### 核心业务逻辑
|
||
|
||
**create_application:**
|
||
1. 查询 `channel_service_order_id` 对应的服务订单,校验存在且状态为生效中(status='sxz')
|
||
2. 从服务订单关联的渠道信息缓存 `channel_id` / `channel_name` 到申请单
|
||
3. 生成 `application_no`:前缀 ZSSQ + YYYYMMDD + 4位序列号
|
||
4. 默认 `application_status = 'dks'`
|
||
|
||
**save_patient(客户关联逻辑):**
|
||
1. 如果传入 `customer_id`,从 `biz_customer` 表读取客户信息填充到患者字段
|
||
2. 用户可修改已填充的字段
|
||
3. 保存时:如果 `customer_id` 存在则更新 `biz_customer` 对应记录;如果不存在则新建 `biz_customer` 记录并回填 `customer_id`
|
||
4. 与采集协议单的母亲信息模式一致
|
||
|
||
**auto_generate_schedules:**
|
||
1. 读取方案的 `total_course_count`
|
||
2. 批量插入 N 条 `biz_pilot_infusion_schedule` 记录
|
||
3. 每条记录继承方案的 `cell_type` / `spec_text`
|
||
4. `schedule_status` 留空,`infusion_time` 留空(用户后续手动填写)
|
||
5. `order_num` 按序号 1, 2, 3... 排列
|
||
6. 返回生成数量
|
||
|
||
### 3.3 API(新文件:backend/app/api/pilot_application.py)
|
||
|
||
**路由前缀:** `/web/admin`
|
||
**Tag:** `中试服务申请单管理`
|
||
|
||
#### Pydantic Schemas(内联定义)
|
||
|
||
```
|
||
ApplicationCreateBody:
|
||
channel_service_order_id: str
|
||
remark: Optional[str]
|
||
|
||
ApplicationUpdateBody:
|
||
remark: Optional[str]
|
||
|
||
PatientSaveBody:
|
||
customer_id: Optional[str]
|
||
patient_name: str
|
||
sex: Optional[str]
|
||
age: Optional[int]
|
||
id_card_no: Optional[str]
|
||
phone_no: Optional[str]
|
||
emergency_contact: Optional[str]
|
||
emergency_phone: Optional[str]
|
||
clinical_diagnosis: Optional[str]
|
||
diagnosis_attachments: Optional[str]
|
||
need_checkup: int = 1
|
||
|
||
InfusionPlanCreateBody:
|
||
pilot_application_id: str
|
||
cell_type: str
|
||
spec_text: Optional[str]
|
||
total_course_count: int
|
||
course_interval: Optional[str]
|
||
infusion_route: Optional[str]
|
||
infusion_start_date: Optional[str]
|
||
|
||
InfusionPlanUpdateBody:
|
||
cell_type: Optional[str]
|
||
spec_text: Optional[str]
|
||
total_course_count: Optional[int]
|
||
course_interval: Optional[str]
|
||
infusion_route: Optional[str]
|
||
infusion_start_date: Optional[str]
|
||
|
||
InfusionScheduleUpdateBody:
|
||
infusion_time: Optional[str]
|
||
remark: Optional[str]
|
||
attachments: Optional[str]
|
||
```
|
||
|
||
#### API 路由清单
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| GET | `/pilot-application/list` | 申请单分页列表 |
|
||
| GET | `/pilot-application/detail` | 申请单详情(含患者+方案+计划) |
|
||
| POST | `/pilot-application/create` | 创建申请单 |
|
||
| PUT | `/pilot-application/update` | 更新申请单 |
|
||
| DELETE | `/pilot-application/delete` | 删除申请单 |
|
||
| POST | `/pilot-application/start` | 开始(dks→jxz) |
|
||
| POST | `/pilot-application/complete` | 完成(jxz→ywc) |
|
||
| POST | `/pilot-application/void` | 作废(→yzf) |
|
||
| GET | `/pilot-patient/detail` | 获取患者信息 |
|
||
| POST | `/pilot-patient/save` | 保存患者信息 |
|
||
| GET | `/pilot-infusion-plan/list` | 输注方案列表 |
|
||
| POST | `/pilot-infusion-plan/create` | 创建输注方案 |
|
||
| PUT | `/pilot-infusion-plan/update` | 更新输注方案 |
|
||
| DELETE | `/pilot-infusion-plan/delete` | 删除输注方案 |
|
||
| POST | `/pilot-infusion-schedule/auto-generate` | 自动生成计划 |
|
||
| POST | `/pilot-infusion-schedule/create` | 手动添加计划 |
|
||
| PUT | `/pilot-infusion-schedule/update` | 更新计划 |
|
||
| DELETE | `/pilot-infusion-schedule/delete` | 删除计划 |
|
||
| POST | `/pilot-infusion-schedule/mark-complete` | 标记计划完成 |
|
||
|
||
**路由注册:** 在 `app/api/__init__.py` 和 `app/main.py` 中追加 `pilot_application` router。
|
||
|
||
**权限:** 使用 `require_admin_or_super_admin` 装饰器(与现有 pilot_service 一致)。
|
||
|
||
---
|
||
|
||
## 4. 前端架构
|
||
|
||
### 4.1 路由(sqxp.ts 追加)
|
||
|
||
```typescript
|
||
{
|
||
path: 'pilot-application',
|
||
name: 'PilotApplication',
|
||
component: () => import('@views/pilot-service/pilot-application/index.vue'),
|
||
meta: { title: '中试服务申请单', icon: '...' }
|
||
},
|
||
{
|
||
path: 'pilot-application/detail',
|
||
name: 'PilotApplicationDetail',
|
||
component: () => import('@views/pilot-service/pilot-application/ApplicationDetail.vue'),
|
||
meta: { title: '申请单详情', hidden: true }
|
||
}
|
||
```
|
||
|
||
### 4.2 页面文件
|
||
|
||
```
|
||
web-admin/src/views/pilot-service/pilot-application/
|
||
├── index.vue ← 申请单列表页
|
||
└── ApplicationDetail.vue ← 详情页(Tab布局)
|
||
```
|
||
|
||
### 4.3 列表页 index.vue
|
||
|
||
**参考模板页:** `src/views/system/order/index.vue`(复杂列表页)
|
||
|
||
**筛选条件:**
|
||
- 申请单号(文本输入)
|
||
- 渠道(下拉选择,数据源:已有渠道 API)
|
||
- 服务订单(下拉选择,联动渠道筛选)
|
||
- 状态(Tag 筛选按钮组)
|
||
|
||
**表格列:**
|
||
|
||
| 列名 | 字段 | 宽度 | 说明 |
|
||
|------|------|------|------|
|
||
| 申请单号 | application_no | 180 | |
|
||
| 渠道名称 | channel_name | 150 | |
|
||
| 关联服务订单 | service_order_no | 180 | 显示订单号 + 类型标签 |
|
||
| 患者姓名 | patient_name | 100 | |
|
||
| 输注方案数 | infusion_plan_count | 100 | |
|
||
| 状态 | application_status | 100 | el-tag:dks(info) / jxz(primary) / ywc(success) / yzf(danger) |
|
||
| 创建时间 | create_time | 160 | |
|
||
| 操作 | — | 260+ | 查看/编辑/删除 + 状态按钮 |
|
||
|
||
**操作按钮逻辑:**
|
||
- 新增:弹窗选择渠道 + 服务订单 → 创建成功后跳转详情页
|
||
- 状态按钮动态显示:
|
||
- dks(待开始):显示"开始"按钮
|
||
- jxz(进行中):显示"完成"和"作废"按钮
|
||
- ywc(已完成) / yzf(已作废):无状态按钮
|
||
- 点击行 → router.push 跳转详情页(携带 application_id 参数)
|
||
|
||
### 4.4 详情页 ApplicationDetail.vue
|
||
|
||
**参考模板页:** `src/views/system/product/index.vue`(含 ViewDialog 的详情展示)
|
||
|
||
**Tab 布局:**
|
||
|
||
| Tab | 内容 | 阶段 |
|
||
|-----|------|------|
|
||
| 基本信息 | 申请单信息 + 患者信息 | Phase 1 ✅ |
|
||
| 输注方案 | 方案列表 + 计划管理 | Phase 1 ✅ |
|
||
| 体检信息 | 占位(Phase 2 实现) | Phase 2 🔒 |
|
||
| 交付信息 | 占位(Phase 2 实现) | Phase 2 🔒 |
|
||
|
||
#### 基本信息 Tab
|
||
|
||
**上半区 — 申请单信息(只读):**
|
||
- 申请单号、渠道名称、关联服务订单、状态、备注
|
||
- 状态以 el-tag 展示
|
||
|
||
**下半区 — 患者信息面板(可编辑):**
|
||
- "选择客户"按钮 → 弹窗从客户管理表(biz_customer)选取
|
||
- 弹窗展示客户列表,支持搜索(姓名/手机号)
|
||
- 选中后自动填充:姓名、性别、年龄、身份证号、联系电话、紧急联系人、紧急联系人电话
|
||
- 已填充字段可手动修改
|
||
- "是否需要体检"开关(need_checkup)
|
||
- 临床诊断文本框 + 诊断附件上传
|
||
- "保存患者信息"按钮
|
||
- 保存时同步更新 biz_customer 表(与采集协议单母亲信息模式一致)
|
||
|
||
#### 输注方案 Tab
|
||
|
||
**方案列表(表格或卡片):**
|
||
|
||
每行显示:
|
||
- 细胞类型(cell_type)
|
||
- 规格(spec_text)
|
||
- 总疗程数(total_course_count)
|
||
- 疗程间隔(course_interval)
|
||
- 输注途径(infusion_route)
|
||
- 输注开始日期(infusion_start_date)
|
||
- 计划数 / 已完成数(如 3/5)
|
||
- 操作:编辑 / 删除
|
||
|
||
**展开行 — 输注计划列表:**
|
||
|
||
每个方案可展开显示其下的输注计划:
|
||
|
||
| 列 | 说明 |
|
||
|---|---|
|
||
| 序号 | order_num |
|
||
| 细胞类型 | cell_type |
|
||
| 规格 | spec_text |
|
||
| 输注时间 | infusion_time(可编辑) |
|
||
| 状态 | "-" 或 "已完成"(el-tag) |
|
||
| 操作 | 编辑 / 删除 / 标记完成 |
|
||
|
||
**操作流程:**
|
||
1. 点击"新增输注方案" → 弹窗填写方案信息 → 保存
|
||
2. 保存方案后**自动弹出提示**:"是否立即生成 X 条输注计划?"
|
||
3. 确认后调用 auto_generate 接口批量生成
|
||
4. 生成后可手动编辑每条计划的时间/备注
|
||
5. 可手动新增/删除计划
|
||
6. 每条计划有"标记完成"按钮
|
||
|
||
### 4.5 API 函数(admin.ts 追加)
|
||
|
||
在 `web-admin/src/api/admin.ts` 末尾追加以下函数:
|
||
|
||
```typescript
|
||
// 中试申请单
|
||
fetchPilotApplicationList(params)
|
||
fetchPilotApplicationDetail(params)
|
||
createPilotApplication(data)
|
||
updatePilotApplication(data)
|
||
deletePilotApplication(data)
|
||
startPilotApplication(data)
|
||
completePilotApplication(data)
|
||
voidPilotApplication(data)
|
||
|
||
// 患者信息
|
||
fetchPilotPatient(params)
|
||
savePilotPatient(data)
|
||
|
||
// 输注方案
|
||
fetchPilotInfusionPlanList(params)
|
||
createPilotInfusionPlan(data)
|
||
updatePilotInfusionPlan(data)
|
||
deletePilotInfusionPlan(data)
|
||
|
||
// 输注计划
|
||
fetchPilotInfusionScheduleList(params)
|
||
autoGenerateSchedules(data)
|
||
updatePilotInfusionSchedule(data)
|
||
deletePilotInfusionSchedule(data)
|
||
markScheduleComplete(data)
|
||
```
|
||
|
||
### 4.6 状态标签注册
|
||
|
||
在 `web-admin/src/utils/status-tag-registry.ts` 追加:
|
||
|
||
```typescript
|
||
// 申请单状态
|
||
applicationStatusLabel(status) → '待开始'/'进行中'/'已完成'/'已作废'
|
||
applicationStatusTagType(status) → 'info'/'primary'/'success'/'danger'
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 关键交互流程
|
||
|
||
### 5.1 创建申请单流程
|
||
|
||
```
|
||
列表页 → 点击"新增"
|
||
→ 弹窗:选择渠道(下拉)→ 联动加载该渠道的服务订单(下拉)
|
||
→ 选择服务订单 → 填写备注
|
||
→ 提交 → 后端校验订单状态 → 生成申请单号 → 创建成功
|
||
→ 跳转详情页
|
||
```
|
||
|
||
### 5.2 患者信息录入流程
|
||
|
||
```
|
||
详情页基本信息Tab → 点击"选择客户"
|
||
→ 弹窗展示客户列表(姓名/手机搜索)
|
||
→ 选中客户 → 自动填充患者字段
|
||
→ 可手动修改字段
|
||
→ 填写临床诊断 + 上传诊断附件
|
||
→ 点击"保存" → 后端同步更新 biz_customer
|
||
```
|
||
|
||
### 5.3 输注方案+计划管理流程
|
||
|
||
```
|
||
详情页输注方案Tab → 点击"新增输注方案"
|
||
→ 弹窗填写:细胞类型、规格、总疗程数(N)、疗程间隔、输注途径、开始日期
|
||
→ 保存 → ElMessageBox.confirm("是否立即生成 N 条输注计划?")
|
||
→ 确认 → 调用 auto_generate → 生成 N 条计划
|
||
→ 取消 → 仅创建方案,后续手动添加
|
||
→ 展开方案 → 查看/编辑每条计划
|
||
→ 手动新增/删除/编辑计划
|
||
→ 标记计划完成
|
||
```
|
||
|
||
### 5.4 申请单状态流转
|
||
|
||
```
|
||
dks(待开始) ──开始──→ jxz(进行中) ──完成──→ ywc(已完成)
|
||
│ │
|
||
└────作废──→ yzf(已作废) ←──作废──┘
|
||
|
||
约束:
|
||
- 编辑/删除:仅 dks 状态可操作
|
||
- 开始:仅 dks → jxz
|
||
- 完成:仅 jxz → ywc
|
||
- 作废:dks 或 jxz → yzf
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 文件清单
|
||
|
||
### 新增文件
|
||
|
||
| # | 文件路径 | 说明 |
|
||
|---|---------|------|
|
||
| 1 | `docs/sql/pilot-application-migration.sql` | 数据库迁移 SQL |
|
||
| 2 | `backend/app/crud/pilot_application.py` | 后端 CRUD |
|
||
| 3 | `backend/app/api/pilot_application.py` | 后端 API 路由 |
|
||
| 4 | `web-admin/src/views/pilot-service/pilot-application/index.vue` | 列表页 |
|
||
| 5 | `web-admin/src/views/pilot-service/pilot-application/ApplicationDetail.vue` | 详情页 |
|
||
|
||
### 修改文件
|
||
|
||
| # | 文件路径 | 变更 |
|
||
|---|---------|------|
|
||
| 6 | `backend/app/models/models.py` | 新增 4 个 Model 类 |
|
||
| 7 | `backend/app/api/__init__.py` | 注册新 router |
|
||
| 8 | `backend/app/main.py` | 引入新 router |
|
||
| 9 | `web-admin/src/api/admin.ts` | 追加 19 个 API 函数 |
|
||
| 10 | `web-admin/src/utils/status-tag-registry.ts` | 追加申请单状态标签函数 |
|
||
| 11 | `web-admin/src/router/modules/sqxp.ts` | 追加 2 个路由 |
|
||
|
||
---
|
||
|
||
## 7. 不在范围内
|
||
|
||
以下内容不在 Phase 1 中:
|
||
|
||
- 体检预约/报告/费用管理(biz_pilot_checkup + reserve_item + actual_item)
|
||
- 交付信息/物料清单/交付方式(biz_pilot_delivery + delivery_material + delivery_method)
|
||
- 应用确认(biz_pilot_infusion_confirm)
|
||
- 输注计划→出库生产工单自动联动
|
||
- 出库质检工单
|
||
- 出库放行审核
|
||
- 费用/份数扣减逻辑
|
||
- 工作流集成
|
||
- 数据权限(使用 require_admin_or_super_admin)
|