# 药物禁配标准管理 — 技术方案

> 依据：同目录 `药物禁配标准管理功能需求.md`。本模块**不设发布/下架**；仅 **知识库同步** 维度与 CRUD；**主表 + 配伍子表** 一对多。库表、接口与其它标准模块实现相互独立。

---

## 1. 技术架构

| 项 | 说明 |
| --- | --- |
| **后端** | RuoYi **v3.9.2**（**springboot2** 分支）：JDK 8、Spring Boot 2.x、Spring MVC、MyBatis、Druid |
| **数据库** | MySQL **5.7.39**，InnoDB，`utf8mb4` |
| **前端** | 若依 Vue2（与分支配套；路由、权限、字典按项目惯例） |
| **知识库** | HTTP 调用知识库后台管理服务；鉴权、URL、报文见《知识库接口对接说明》；本模块涉及**添加/更新/删除（幂等）**类变更，**不涉及**发布/下架可见性接口 |

**分层**：`Controller` → `Service`（状态校验、事务、子表全量替换、知识库编排）→ `Mapper`/XML → `domain`（小驼峰 JSON 与 Jackson 一致）。

**实现包路径（当前仓库）**：`com.ruoyi.web.modules.architecture` 下 `controller` / `service` / `mapper` / `domain`；校验辅助类 `support/DrugIncompatibilityStandardValidation`、`support/DrugIncompatibilityStandardRules`。

**一致性（摘要）**

- **删除**：本地删除前须 `kb_sync_status=0`；删除流程中按需求对知识库发**幂等删除**通知（无条目则对端忽略），失败策略（阻断本地删 vs 异步补偿）由与知识库约定二选一并在实现中固定；当前占位实现可无远程调用。  
- **移出**：前置 `kb_sync_status=1`；成功后 `kb_sync_status=0`，清空 `kb_doc_id`。  
- **同步**：前置 `kb_sync_status=0`；成功后 `kb_sync_status=1`，写入 `kb_doc_id`（未对接 HTTP 时可占位 `LOCAL-{id}`，与其它标准模块占位策略一致）。  
- **修改**：仅 `kb_sync_status=0`；保存时**删除该标准下全部子行再按请求顺序插入**（全量替换），`kb_sync_status` / `kb_doc_id` 不以客户端提交为准（编辑时锁定为库内原值）。

---

## 2. 数据库设计

### 2.1 表 `biz_drug_incompatibility_standard`（主表）

| 字段 | 类型 | 非空 | 默认值 | 说明 |
| --- | --- | --- | --- | --- |
| `id` | `bigint(20)` | Y | 自增 | 主键 |
| `main_drug_name` | `varchar(64)` | Y | — | 主药名称（业务 1～20 字符；**全表唯一**，保存前 trim） |
| `compat_result` | `varchar(64)` | N | NULL | 配伍结果（选填，业务 ≤20 字符） |
| `kb_sync_status` | `tinyint(4)` | Y | `0` | `0` 未同步，`1` 已同步 |
| `kb_doc_id` | `varchar(128)` | N | NULL | 知识库文档 ID |
| `create_by` / `create_time` / `update_by` / `update_time` | 若依惯例 | — | — | — |
| `remark` | `varchar(500)` | N | NULL | 备注 |

**索引**：`PRIMARY KEY (id)`；`UNIQUE KEY uk_main_drug_name (main_drug_name)`；`KEY idx_create_time (create_time)`；`KEY idx_kb (kb_sync_status)`。

**合法 `kb_sync_status`**：仅 `0`、`1`；应用层禁止写入其它值。

**DDL 示例**

```sql
CREATE TABLE `biz_drug_incompatibility_standard` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `main_drug_name` varchar(64) NOT NULL COMMENT '主药名称1～20字',
  `compat_result` varchar(64) DEFAULT NULL COMMENT '配伍结果选填≤20字',
  `kb_sync_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0未同步1已同步',
  `kb_doc_id` varchar(128) DEFAULT NULL COMMENT '知识库文档ID',
  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_main_drug_name` (`main_drug_name`),
  KEY `idx_create_time` (`create_time`),
  KEY `idx_kb` (`kb_sync_status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='药物禁配标准主表';
```

### 2.2 表 `biz_drug_incompatibility_companion`（配伍子表）

| 字段 | 类型 | 非空 | 默认值 | 说明 |
| --- | --- | --- | --- | --- |
| `id` | `bigint(20)` | Y | 自增 | 主键 |
| `standard_id` | `bigint(20)` | Y | — | 外键 → 主表 `id` |
| `companion_drug_name` | `varchar(64)` | Y | — | 配伍药物名称（业务 1～20 字符） |
| `sort_order` | `int(11)` | Y | `0` | 展示顺序；保存时按请求数组下标写入 |

**索引与约束**：`KEY idx_standard_id (standard_id)`；`UNIQUE uk_std_companion (standard_id, companion_drug_name)`（同标准下药名物理唯一）；`FOREIGN KEY (standard_id) REFERENCES biz_drug_incompatibility_standard(id) ON DELETE CASCADE`。

**DDL 示例**

```sql
CREATE TABLE `biz_drug_incompatibility_companion` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `standard_id` bigint(20) NOT NULL COMMENT '标准主表ID',
  `companion_drug_name` varchar(64) NOT NULL COMMENT '配伍药物名称1～20字',
  `sort_order` int(11) NOT NULL DEFAULT '0' COMMENT '展示顺序',
  PRIMARY KEY (`id`),
  KEY `idx_standard_id` (`standard_id`),
  UNIQUE KEY `uk_std_companion` (`standard_id`,`companion_drug_name`),
  CONSTRAINT `fk_dic_standard` FOREIGN KEY (`standard_id`) REFERENCES `biz_drug_incompatibility_standard` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='药物禁配标准配伍子表';
```

### 2.3 枚举（后端/字典建议）

| 字段 | 值 | 含义 |
| --- | --- | --- |
| `kb_sync_status` | `0` | 未同步 |
| | `1` | 已同步 |

**列表聚合**：列表 SQL 可子查询 `companion_count`（条数），**非持久化列**，仅用于表格展示。

---

## 3. 接口设计

**统一响应**：`AjaxResult` / 分页 `TableDataInfo`（与 RuoYi 一致）。

**Base Path**：`/drugIncompatibility/standard`（若项目有全局 `context-path` 或网关前缀，实际 URL 需拼接）。

**权限标识（建议）**：`drugIncompatibility:standard:list|query|add|edit|remove|syncKb|removeKb`（**无** `publish` / `offline`）

| # | 说明 | Method | URI | 权限 | 要点 |
| --- | --- | --- | --- | --- | --- |
| 3.1 | 分页列表 | GET | `/drugIncompatibility/standard/list` | `drugIncompatibility:standard:list` | Query：`pageNum`、`pageSize`（与项目列表默认一致）、`keyword`（**仅** `main_drug_name` 模糊）；返回行含 `companionCount`，**不含** `companions` 明细；排序建议 `create_time DESC, id DESC` |
| 3.2 | 详情 | GET | `/drugIncompatibility/standard/{id}` | `drugIncompatibility:standard:query` | 返回主表字段 + `companions` 数组（按 `sort_order` 有序） |
| 3.3 | 新增 | POST | `/drugIncompatibility/standard` | `drugIncompatibility:standard:add` | Body：`mainDrugName`、`compatResult`（可空）、`companions`（≥1 条，每项 `companionDrugName`）；落库 `kb_sync_status=0`，`kb_doc_id` 空；同事务写子表 |
| 3.4 | 修改 | PUT | `/drugIncompatibility/standard` | `drugIncompatibility:standard:edit` | Body 含 `id`；**仅** `kb_sync_status=0`；子表全量替换；**不**接受客户端篡改 `kb_sync_status` / `kb_doc_id`（服务端锁定库内值后更新主表与其它字段） |
| 3.5 | 删除 | DELETE | `/drugIncompatibility/standard/{ids}` | `drugIncompatibility:standard:remove` | **仅** `kb_sync_status=0`；`ids` 逗号分隔；**任一** id 为已同步则整单失败；删前/删后按约定调知识库**幂等删除**；子表随主表级联删除 |
| 3.6 | 同步知识库 | POST | `/drugIncompatibility/standard/syncKb/{id}` | `drugIncompatibility:standard:syncKb` | 前置 `kb_sync_status=0`；成功则 `kb_sync_status=1`，写入 `kb_doc_id` |
| 3.7 | 移出知识库 | POST | `/drugIncompatibility/standard/removeKb/{id}` | `drugIncompatibility:standard:removeKb` | 前置 `kb_sync_status=1`；成功则 `kb_sync_status=0`，清空 `kb_doc_id` |

**请求体（3.3 / 3.4）摘要**：`mainDrugName` 1～20 且**全表唯一**（`countByMainDrugNameExcludeId`，修改时传 `excludeId`；重复提示「主药名称已存在」）；`compatResult` 选填 ≤20（空串存 `NULL`）；`companions` 至少 1 条；每条 `companionDrugName` 1～20；trim 后**互不相同**且**均不等于** `mainDrugName`（`DrugIncompatibilityStandardValidation` + `BizDrugIncompatibilityStandardServiceImpl`）。

---

## 4. 与功能需求的对应（便于验收）

| 需求章节 | 技术落点 |
| --- | --- |
| 4.1 新增 | 表 **2.1**、**2.2** + POST **3.3** |
| 4.2 列表 | GET **3.1**（`keyword`→`main_drug_name`） |
| 4.3 修改 | PUT **3.4**（`kb_sync_status=0`、子表替换） |
| 4.4 删除 | DELETE **3.5** + 知识库幂等删除（对接后） |
| 4.5 / 4.6 知识库 | POST **3.6** / **3.7** |
| 4.7 详情 | GET **3.2** |
| 无发布/下架 | 无对应接口与表字段 |

---

## 5. 交付清单（勾选）

- [ ] DDL：`sql/biz_drug_incompatibility_standard.sql`（与 **2.1**、**2.2** 一致）及菜单按钮权限 SQL  
- [ ] Domain / Mapper / XML / Service / Controller（包路径与项目 `architecture` 模块惯例一致即可）  
- [ ] 单测：校验类、状态规则、Service 状态守卫；接口测试：MockMvc 或集成环境  
- [ ] 与知识库真实 HTTP 对接（或占位策略）按《知识库接口对接说明》排期
