# 养殖标准管理 — 技术方案 > 依据:`养殖标准管理功能需求.md`(同目录) --- ## 1. 技术架构 | 层级 | 说明 | | --- | --- | | **整体** | RuoYi **v3.9.2**(**springboot2** 分支)单体后端 + 若依 **Vue2** 前端(与分支配套) | | **运行时** | JDK 8、Spring Boot 2.x、Spring MVC、MyBatis、Druid | | **数据库** | MySQL **5.7.39**,存储引擎 InnoDB,字符集 **utf8mb4** | | **文件** | 复用 RuoYi 既有上传能力(本地/MinIO 等以项目现有配置为准);业务表存访问 URL、**存储路径**、**正文附件名称**(见 **2.1**,不落库文件大小) | | **外部系统** | **知识库后台管理服务**(HTTP):养殖标准在同步、发布、下架等环节调用其接口完成 **知识库变更通知**;用户侧问答另走其 **提示词查询接口**(见 **第 4 章**)。URL、鉴权、报文另附《知识库接口对接说明》。 | **后端分层(与若依一致)** - `Controller`:参数校验、权限注解、返回 `AjaxResult` / `TableDataInfo` - `Service`:状态机校验、事务、知识库编排、删文件 - `Mapper` + XML:持久化 - `domain`:实体与枚举常量 **一致性策略(与需求对齐,`养殖标准管理功能需求.md` §4.7~4.8)** - 修改:**仅** `publish_status=0` 且 `kb_sync_status=0`;**不**在 `kb_sync_status=1` 时自动推库(与需求「已同步不可改」一致,改内容须先移出)。 - **下架(与「移出」区分):** 业务侧 **`publish_status` 置回 `0`(未发布)**,**`kb_sync_status` 保持 `1`(已同步)**;知识库侧 **不删除**文档条目,仅完成「结束对外发布/对外检索可见」等(具体 HTTP 语义见 **§4.2(5)**,可为可见性变更、`DELETE` 的对端否定操作由对接文档约定)。**禁止**将下架实现为与「移出」相同的库条目物理删除并再把本地 `kb_sync` 置 0(除非产品另行变更需求)。 - **移出知识库:** 通知知识库删除/下线条目后,本地 **`kb_sync_status=0`**,清空 `kb_doc_id`(与下架不同)。 - **删除:** **`kb_sync_status=0`** 允许删(删库 + 删附件 + 通知知识库删除,见 **3.5**);**未发布且已同步**须先移出或接口内原子联动删库条目再删本地;**已发布**禁止删除。 --- ## 2. 数据库设计 ### 2.1 表:`biz_breeding_standard`(养殖标准主表) 单表承载业务字段 + 双维状态 + 知识库侧关联键(若有)。 | 字段名 | 类型 | 非空 | 默认值 | 说明 | | --- | --- | --- | --- | --- | | `id` | `bigint(20)` | Y | 自增 | 主键 | | `standard_name` | `varchar(64)` | Y | — | 标准名称,需求 1~20 字符,库宽略放大 | | `standard_type` | `varchar(32)` | Y | — | 资讯类别编码,见 **2.3** | | `introduction` | `varchar(200)` | N | NULL | 简介,选填,≤50 字 | | `content_file_url` | `varchar(512)` | Y | — | 正文附件访问 URL(与若依上传返回 `url` 等对齐,用于下载/预览) | | `content_file_path` | `varchar(512)` | Y | — | 正文文件在存储侧的**存储路径**(与若依上传返回 `fileName` 等对齐) | | `content_file_name` | `varchar(256)` | Y | — | **正文附件名称**(用户上传时的原始文件名,用于列表/详情展示与下载展示名) | | `cover_file_url` | `varchar(512)` | N | NULL | 封面访问 URL,选填 | | `cover_file_path` | `varchar(512)` | N | NULL | 封面在存储侧的**存储路径**,选填 | | `publish_status` | `tinyint(4)` | Y | `0` | 上架状态,见 **2.4** | | `kb_sync_status` | `tinyint(4)` | Y | `0` | 知识库同步状态,见 **2.5** | | `kb_doc_id` | `varchar(128)` | N | NULL | 知识库文档/条目 ID,未同步可空 | | `publish_time` | `datetime` | N | NULL | 发布时间 | | `offline_time` | `datetime` | N | NULL | 下架时间 | | `create_by` | `varchar(64)` | N | — | 若依惯例 | | `create_time` | `datetime` | N | — | 若依惯例 | | `update_by` | `varchar(64)` | N | — | 若依惯例 | | `update_time` | `datetime` | N | — | 若依惯例 | | `remark` | `varchar(500)` | N | NULL | 备注(可选) | **索引** - `PRIMARY KEY (id)` - `KEY idx_create_time (create_time)` — 列表 `ORDER BY create_time DESC` - `KEY idx_type (standard_type)` - `KEY idx_pub_kb (publish_status, kb_sync_status)` — 后台筛选 **DDL 示例(MySQL 5.7)** ```sql CREATE TABLE `biz_breeding_standard` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', `standard_name` varchar(64) NOT NULL COMMENT '标准名称(业务1~20字符)', `standard_type` varchar(32) NOT NULL COMMENT '标准类型编码,对应资讯类别 parentCode=001&categoryType=1', `introduction` varchar(200) DEFAULT NULL COMMENT '简介', `content_file_url` varchar(512) NOT NULL COMMENT '正文附件访问URL', `content_file_path` varchar(512) NOT NULL COMMENT '正文文件存储路径', `content_file_name` varchar(256) NOT NULL COMMENT '正文附件名称', `cover_file_url` varchar(512) DEFAULT NULL COMMENT '封面访问URL', `cover_file_path` varchar(512) DEFAULT NULL COMMENT '封面文件存储路径', `publish_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '上架 0未发布 1已发布(下架回流写回0,不用2作稳态)', `kb_sync_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '知识库 0未同步 1已同步', `kb_doc_id` varchar(128) DEFAULT NULL COMMENT '知识库文档ID', `publish_time` datetime DEFAULT NULL COMMENT '发布时间', `offline_time` datetime DEFAULT NULL COMMENT '下架时间', `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`), KEY `idx_create_time` (`create_time`), KEY `idx_type` (`standard_type`), KEY `idx_pub_kb` (`publish_status`,`kb_sync_status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='养殖标准'; ``` **已有表升级(示例)**:先增加可空列并回填,再改为非空。 ```sql ALTER TABLE `biz_breeding_standard` ADD COLUMN `content_file_name` varchar(256) DEFAULT NULL COMMENT '正文附件名称' AFTER `content_file_path`; -- 按 `content_file_path` 或业务规则 UPDATE 回填后: ALTER TABLE `biz_breeding_standard` MODIFY COLUMN `content_file_name` varchar(256) NOT NULL COMMENT '正文附件名称'; ``` **合法组合(应用层强校验,与需求 §2.2.3 一致;禁止非法落库)** | publish_status | kb_sync_status | 说明 | | --- | --- | --- | | 0 未发布 | 0 未同步 | ✓(含新建、移出后) | | 0 未发布 | 1 已同步 | ✓(含手动同步、**已发布下架回流**,库内保留副本) | | 1 已发布 | 1 已同步 | ✓ | | 其余(如 **1+0** 等) | — | ✗ | 应用层校验 **仅允许上表三行** 合法组合落库与流转。 ### 2.3 标准类型与资讯类别 - **数据来源**:`GET /category/informationCategory/children?parentCode=001&categoryType=1`;响应字段 `code`(编码)、`name`(展示名)。`GET /category/informationCategory/tree` 树节点字段同为 `code`、`name`、`categoryType`、`children`。 - **落库值**:`standard_type` 存编码(如 `001001`)。 - **校验**:`BreedingStandardTypeValidator`;非法编码返回「标准类型无效,请选择资讯类别中的类型」。 | 编码(示例) | 名称 | | --- | --- | | `001001` | 繁育作业 | | `001002` | 饲养工作 | | `001003` | 免疫程序 | | `001004` | 环境调控 | **存量库迁移**:执行 `sql/biz_breeding_standard_alter_standard_type.sql`(`1`→`001001` … `4`→`001004`)。 ### 2.4 上架状态 `publish_status` | 值 | 含义 | | --- | --- | | `0` | 未发布(含草稿、下架回流) | | `1` | 已发布 | **下架:** 操作完成后须将本字段置 **`0`**,与需求「未发布 + 已同步」一致。 ### 2.5 知识库同步 `kb_sync_status` | 值 | 含义 | | --- | --- | | `0` | 未同步 | | `1` | 已同步 | --- ## 3. 接口设计 统一响应:**RuoYi 惯例** `AjaxResult`(`code` / `msg` / `data`)或分页 `TableDataInfo`;错误码与文案区分参数校验、状态非法、文件非法、知识库失败等。 **权限标识建议(示例)**:`breeding:standard:list|query|add|edit|remove|syncKb|removeKb|publish|offline` **Base Path(示例)**:`/breeding/standard`(实际前缀与若依 `context-path`、模块路由对齐) ### 3.1 分页列表 | 项 | 说明 | | --- | --- | | **Method / URI** | `GET /breeding/standard/list` | | **权限** | `breeding:standard:list` | | **Query** | `pageNum`(默认 1)、`pageSize`(默认 **20**)、`keyword`(名称/简介 OR 模糊)、`standardType`(精确,可空) | | **排序** | 默认 `create_time DESC`, `id DESC` | | **响应** | `TableDataInfo` 行内字段:id、standardName、standardType、introduction、`contentFileName`(可选展示)、publishStatus、kbSyncStatus、createTime 等 | ### 3.2 详情 | 项 | 说明 | | --- | --- | | **Method / URI** | `GET /breeding/standard/{id}` | | **权限** | `breeding:standard:query` | | **响应** | 含 `standardName`、`introduction`、`contentFileUrl`、`contentFilePath`、`contentFileName`、`coverFileUrl`、`coverFilePath`、双维状态、时间等;附件下载可走若依 `/common/download` 或直链(需鉴权) | ### 3.3 新增 | 项 | 说明 | | --- | --- | | **Method / URI** | `POST /breeding/standard` | | **权限** | `breeding:standard:add` | | **Body** | JSON:`standardName`、`standardType`、`introduction`(可空)、`contentFileUrl`、`contentFilePath`、`contentFileName`(正文附件名称,与上传返回 `originalFilename` 对齐)、`coverFileUrl`、`coverFilePath`(封面可空);正文须先上传 | | **校验** | 名称长度 **1~20**;`standard_type` 为资讯类别有效编码(**2.3**);简介字数、正文后缀白名单 **`pdf`/`md`/`doc`/`docx`/`xls`/`xlsx`/`pptx`** 与 ≤30MB、封面后缀 **`jpg`/`jpeg`/`png`** 与 ≤10MB(`BreedingStandardRules.isContentExtensionAllowed`) | | **落库** | `publish_status=0`,`kb_sync_status=0`,时间字段由若依填充 | ### 3.4 修改 | 项 | 说明 | | --- | --- | | **Method / URI** | `PUT /breeding/standard` | | **权限** | `breeding:standard:edit` | | **前置** | 仅 `publish_status=0` 且 `kb_sync_status=0`;否则返回业务错误(如「知识库已同步状态不允许修改」) | | **Body** | 含 `id`;可替换正文/封面的 `Url`、`Path` 及正文 `contentFileName` | | **逻辑** | 更新库表;**不**自动调用知识库(改内容须先移出后再手动同步) | ### 3.5 删除 | 项 | 说明 | | --- | --- | | **Method / URI** | `DELETE /breeding/standard/{ids}` | | **权限** | `breeding:standard:remove` | | **规则** | **`publish_status=1` 禁止**;**`kb_sync_status=0`** 允许删除;**`publish_status=0` 且 `kb_sync_status=1`** 须先移出(**3.7**)或本接口内 **原子联动删知识库条目再删本地** | | **副作用** | 物理删记录 + 删除 OSS/磁盘上正文与封面文件 + **通知知识库删除**对应条目(与需求 §4.4) | ### 3.6 同步知识库(手动) | 项 | 说明 | | --- | --- | | **Method / URI** | `POST /breeding/standard/syncKb/{id}` | | **权限** | `breeding:standard:syncKb` | | **前置** | `publish_status=0` 且 `kb_sync_status=0` | | **结果** | 调知识库入库,`kb_sync_status=1`,写入 `kb_doc_id` | ### 3.7 移出知识库 | 项 | 说明 | | --- | --- | | **Method / URI** | `POST /breeding/standard/removeKb/{id}` | | **权限** | `breeding:standard:removeKb` | | **前置** | `publish_status=0` 且 `kb_sync_status=1` | | **结果** | 调知识库删除,`kb_sync_status=0`,`kb_doc_id` 清空 | ### 3.8 发布 | 项 | 说明 | | --- | --- | | **Method / URI** | `POST /breeding/standard/publish/{id}` | | **权限** | `breeding:standard:publish` | | **前置** | `publish_status=0` 且 `kb_sync_status=1` | | **结果** | `publish_status=1`,`publish_time=now()` | ### 3.9 下架 | 项 | 说明 | | --- | --- | | **Method / URI** | `POST /breeding/standard/offline/{id}` | | **权限** | `breeding:standard:offline` | | **前置** | `publish_status=1` | | **结果** | 调知识库完成「对外下架」语义(**非**移出删条目,见 **§4.2(5)**);本地 **`publish_status=0`**,**`kb_sync_status=1`**(保留 `kb_doc_id`);**`offline_time=now()`**(审计下架时刻);**可选**清空 `publish_time` 或由产品约定是否保留上次发布时间 | --- ## 4. 与知识库后台管理服务交互(流程) 本章约定:**养殖标准业务服务**(RuoYi 后端)与 **知识库后台管理服务** 之间通过 **HTTP** 交互;具体路径、Header(如 `Authorization`/`X-Api-Key`)、请求体字段以《知识库后台管理服务接口文档》为准,此处描述 **调用时机、顺序职责与失败策略**。 ### 4.1 交互角色 | 角色 | 说明 | | --- | --- | | **养殖标准业务服务** | 在本模块内完成鉴权、状态机、落库后,**按需调用**知识库后台管理服务接口,驱动知识库侧文档/索引/可见性变更 | | **知识库后台管理服务** | 接收变更通知,执行入库、更新、发布可见、下架移除等;可提供 **提示词查询** 能力供终端提问 | | **终端用户(提问)** | 一般 **不经过** 养殖标准 CRUD 接口;通过前端或统一网关 **直接调用** 知识库后台管理服务的 **提示词查询接口** 完成问答(与养殖标准数据是否已发布、是否仍在库内等业务规则由知识库侧检索策略决定) | ### 4.2 养殖标准触发的 HTTP 调用(知识库变更通知) 下列步骤中「调用知识库接口」均指 **知识库后台管理服务** 暴露的管理类 HTTP API(命名示例:`/kb/admin/doc/...`,以对接文档为准)。 #### 变更通知统一必填语义(报文体) 每次调用变更通知接口时,须告知以下字段(字段名可与对接文档对齐,语义不变): | 字段语义 | 说明 | | --- | --- | | **操作类型** | **`添加`**:首次同步入库、已同步后的保存更新(内容替换)、发布等对「库内需保留/更新该标准正文」的通知;**`删除`**:**移出知识库**、业务**删除**等对「库内需移除该标准条目」的通知。**下架**不等于删除条目:下架走「可见性/发布态」类接口(可能仍归类为扩展字段或单独 API,见 **§4.2(5)**),不应默认使用本表的 **`删除`** 语义清掉副本。(若对端要求枚举值为英文,可约定 `ADD` / `DELETE`) | | **标准名称** | 当前养殖标准 **`standard_name`**,与业务侧一致 | | **标准 HTTP 下载地址** | 正文附件 **`content_file_url`**(可被浏览器或服务端拉取的 **HTTP(S)** 下载地址;对内下载网关则需对外亦为可达或可再由知识库回源拉取) | **说明:** - **`添加`** 类:`content_file_url` 指向 **最新** 可下载的正文;若同一业务反复推送更新,均为 **`添加`** 语义下的版本刷新(对端实现幂等或覆盖策略)。 - **`删除`** 类:仍携带 **标准名称** 与 **当时的 `content_file_url`(库内留存值)**,便于对端定位;若记录已删仅存快照,以对端约定为准。 - 其余扩展字段(业务主键 `id`、`kb_doc_id`、类型、简介等)可按《知识库接口对接说明》选填,**不得弱化**上述三项必填语义。 #### (1)同步至知识库(手动首次) ```text 用户点击「同步」→ Service 校验 publish_status=0 且 kb_sync_status=0 → HTTP:变更通知(操作类型=添加,标准名称,标准 HTTP 下载地址=content_file_url) ← 成功返回知识库文档 ID(写入 kb_doc_id) → 本地 kb_sync_status=1;失败则不打勾成功态,提示重试 ``` #### (2)修改保存(仅未同步) ```text 用户保存修改 → Service 校验 publish_status=0 且 kb_sync_status=0 → 仅更新本地库表;不调用知识库 ← 成功则提交;kb_sync_status=1 时接口拒绝 ``` **说明:** 已同步记录须先 **移出知识库**((3))后再走本流程,改完须再 **手动同步**((1))。 #### (3)移出知识库(仅未发布且已同步) ```text 用户点击「移出」→ HTTP:变更通知(操作类型=删除,标准名称,content_file_url) ← 成功 → 本地 kb_sync_status=0,清空 kb_doc_id ``` #### (4)发布 ```text 用户点击「发布」→ Service 校验未发布且已同步 → HTTP:变更通知(操作类型=添加,标准名称,content_file_url;语义上可附带「发布可见」,以对端扩展字段为准) ← 成功 → 本地 publish_status=1,publish_time 落库 ``` #### (5)下架(与「移出」区分) ```text 用户点击「下架」→ Service 校验 publish_status=1 → HTTP:按对接文档通知知识库「结束对外发布/检索可见」(语义可为 UPDATE 可见性、撤销发布位等;需求明确库内保留可编辑副本,不得等同于「移出」的 DELETE 整条) ← 成功 → 本地 publish_status=0,kb_sync_status=1,offline_time=now();kb_doc_id 保留 ``` 若对端 **仅支持**「删除类」接口表达下架,须在《对接说明》中约定 **二次入库/副本保留** 策略,否则与需求「下架后仍为已同步」冲突,须产品书面确认。 #### (6)删除(未发布且已同步时的联动) 若删除流程内需先清库:在删本地记录前 **HTTP:变更通知(操作类型=删除,标准名称,content_file_url)**,成功后再删库与删附件(与 **3.5** 规则一致)。 ### 4.3 提示词查询接口(用户提问) | 项 | 说明 | | --- | --- | | **调用方** | 业务前端、移动端或统一 API 网关(**非** 养殖标准 Module 内必选依赖) | | **被调服务** | 知识库后台管理服务(或其对外的查询子域,以部署为准)提供的 **提示词查询 / 对话检索** 类 **HTTP** 接口 | | **请求必填语义** | **`用户标识`**:调用方传入当前提问用户的唯一标识(如用户 ID、统一账号 `sub`、企微 `openid` 等,格式与对端约定一致);**`问题内容`**:用户输入的自然语言问题正文 | | **用途** | 携带上述字段发起提问,返回基于知识库检索与模型编排的答案;可检索范围是否包含「仅已发布的养殖标准」等 **由知识库侧策略与标签过滤** 实现 | | **与养殖标准的关系** | 养殖标准通过 **4.2** 保证入库、发布、下架时知识库内容与状态一致;问答链路 **独立调用** 查询接口,无需养殖标准 Controller 再转发(若产品要求经网关统一鉴权,可在网关层聚合) | ### 4.4 实现要点(研发) - **客户端封装**:`KbAdminClient`(或同名 Bean),封装变更通知(**操作类型 / 标准名称 / content_file_url**)与查询请求(**用户标识 / 问题内容**);超时、重试策略(慎用)、幂等键(若对端要求)、结构化日志(bizId、kbDocId、接口名、耗时)。 - **配置**:`kb.admin.base-url`、`kb.admin.token`(或 OAuth 客户端配置)等写入 `application-*.yml`,区分环境。 - **安全**:管理接口仅限服务端调用,**禁止** 把管理密钥下发浏览器;提示词查询接口按产品要求做用户鉴权与限流。 - **联调**:以对接文档中的错误码映射到前端 `msg`,与 **3.x** 业务接口返回风格一致。 --- ## 5. 附件与上传(实现提示) - 前端:先调若依现有 **`/common/upload`**(或项目封装接口),得到 **`url`**(写入 `content_file_url` / `cover_file_url`)、**存储路径**(写入 `content_file_path` / `cover_file_path`,一般为返回的 `fileName` 或项目约定字段)、**原始文件名**(写入 `content_file_name`,对应返回 `originalFilename`);**大小**仅在提交前用于校验 **≤30MB / ≤10MB**,**不入库**。 - 服务端:对白名单后缀与大小 **二次校验**(大小可由上传接口或临时读取流获取);替换附件时按 **path** 删除旧物理文件避免残留。 --- ## 6. 交付清单(研发勾选) - [ ] 表 `biz_breeding_standard` DDL 与初始化脚本 - [ ] Domain / Mapper / Service / Controller - [ ] 菜单与按钮权限 SQL - [ ] **知识库后台管理服务** Client(变更通知类接口)+ 配置项(**§4**);对接文档中单列「提示词查询」接口供前端/网关引用 - [ ] 核心场景集成测试:同步、发布、下架、移出、删除与非法状态拦截;**已同步修改被拒绝**;与知识库后台 **HTTP** 联调记录 --- ## 7. 修订记录 | 日期 | 说明 | | --- | --- | | — | 初稿,对齐 `养殖标准管理功能需求.md` | | — | 库表:删除 `content_file_size`、`cover_file_size`;正文侧增加 `content_file_path`(存储路径);`cover_file_name`→`cover_file_path`(封面存储路径);接口 Body 同步调整 | | — | 库表:新增 `content_file_name`(正文附件名称);接口增加 `contentFileName` | | — | 新增 **第 4 章**:与 **知识库后台管理服务** HTTP 交互流程(同步、移出、发布、下架、删除联动);**已同步禁止修改**;**提示词查询接口** 供用户独立调用说明;原 §4~§6 顺延为 §5~§7 | | — | **§4.2** 变更通知统一携带:**操作类型(添加/删除)**、**标准名称**、**标准 HTTP 下载地址(content_file_url)**;**§4.3** 提问携带:**用户标识**、**问题内容** | | — | 对齐需求修订:**下架**回流为 `publish_status=0` + `kb_sync_status=1`,库内保留副本;**下架 ≠ 移出**;合法组合仅 **(0,0)(0,1)(1,1)**;删除规则与 **3.5 / 3.9** 同步更新 | | — | 正文附件白名单:`pdf/md/doc/docx/xls/xlsx/pptx`(不含 `ppt`);`md` 经 `/common/upload` 全局白名单放行 |