瀏覽代碼

知识库

xsh_1997 2 月之前
父節點
當前提交
1dd83f5969
共有 18 個文件被更改,包括 962 次插入567 次删除
  1. 111 47
      doc/养殖标准体系/休药期标准/休药期标准管理前端技术方案.md
  2. 6 4
      doc/养殖标准体系/养殖标准/养殖标准管理前端技术方案.md
  3. 148 45
      doc/养殖标准体系/生长与出栏标准/生长与出栏标准管理前端技术方案.md
  4. 155 38
      doc/养殖标准体系/疫病诊疗标准/疫病诊疗标准管理前端技术方案.md
  5. 154 0
      doc/养殖标准体系/药物禁配标准/药物禁配标准管理前端技术方案.md
  6. 11 4
      doc/养殖标准体系/设备实施作业标准/设备实施作业标准管理前端技术方案.md
  7. 39 248
      doc/养殖标准体系/饲喂标准/饲喂标准管理前端技术方案.md
  8. 6 72
      ruoyi-ui/doc/药物禁配标准/药物禁配标准管理前端技术方案.md
  9. 9 0
      ruoyi-ui/src/api/category/informationCategory.js
  10. 19 5
      ruoyi-ui/src/lang/bo/breedingStd.js
  11. 21 7
      ruoyi-ui/src/lang/zh/breedingStd.js
  12. 51 18
      ruoyi-ui/src/views/breedingStandards/breedingManage/index.vue
  13. 13 5
      ruoyi-ui/src/views/breedingStandards/diseaseTreatment/drugIncompatibility/index.vue
  14. 51 18
      ruoyi-ui/src/views/breedingStandards/diseaseTreatment/epidemicTreatment/index.vue
  15. 21 8
      ruoyi-ui/src/views/breedingStandards/diseaseTreatment/withdrawalPeriod/index.vue
  16. 49 16
      ruoyi-ui/src/views/breedingStandards/equipmentOperation/index.vue
  17. 49 16
      ruoyi-ui/src/views/breedingStandards/feeding/index.vue
  18. 49 16
      ruoyi-ui/src/views/breedingStandards/growthOutbound/index.vue

+ 111 - 47
doc/养殖标准体系/休药期标准/休药期标准管理前端技术方案.md

@@ -1,93 +1,157 @@
1
 # 休药期标准管理 — 前端技术方案
1
 # 休药期标准管理 — 前端技术方案
2
 
2
 
3
-> 依据:`doc/休药期标准/休药期标准管理技术方案.md`;列表与卡片布局对齐 `ruoyi-ui/src/views/breedingStandards/breedingManage/index.vue`(本模块无附件上传、无发布/下架);请求与表单字段统一 **小驼峰**,与后端 `BizWithdrawalPeriodStandard` 及 Jackson 序列化一致。
3
+> 依据:`休药期标准管理技术方案.md`(同目录,下称**总方案**)。本模块**无发布/下架**、无附件上传;仅 **知识库同步** 单维状态机。请求与表单字段统一 **小驼峰**,与后端 `BizWithdrawalPeriodStandard` 及 Jackson 序列化一致。
4
 
4
 
5
 ---
5
 ---
6
 
6
 
7
-## 1. 页面与路由
7
+## 1. 技术架构
8
 
8
 
9
 | 项 | 说明 |
9
 | 项 | 说明 |
10
 | --- | --- |
10
 | --- | --- |
11
-| **Vue 路径** | `ruoyi-ui/src/views/breedingStandards/diseaseTreatment/withdrawalPeriod/index.vue` |
11
+| **工程** | 若依 **RuoYi-Vue** 前端(Vue **2.x** + **Element UI**) |
12
+| **页面路径** | `ruoyi-ui/src/views/breedingStandards/diseaseTreatment/withdrawalPeriod/index.vue` |
12
 | **组件名** | `WithdrawalPeriodStandard` |
13
 | **组件名** | `WithdrawalPeriodStandard` |
13
-| **菜单配置** | 若依「菜单管理」组件路径:`breedingStandards/diseaseTreatment/withdrawalPeriod/index` |
14
-| **权限前缀** | `withdrawalPeriod:standard:`(**无** `publish`、`offline`) |
14
+| **布局参考** | 双 `el-card`(查询区 + 表格区);新增/编辑弹窗 + 查看弹窗 |
15
+| **国际化** | `breedingStdLocaleMixin`,命名空间 `breedingStd.wp` |
15
 
16
 
16
 ---
17
 ---
17
 
18
 
18
-## 2. API 模块
19
+## 2. 源码与路由
19
 
20
 
20
-| 项 | 说明 |
21
+| 类型 | 路径 |
21
 | --- | --- |
22
 | --- | --- |
22
-| **文件** | `ruoyi-ui/src/api/breedingStandards/withdrawalPeriod.js` |
23
-| **Base Path** | `/withdrawalPeriod/standard` |
23
+| 页面 | `ruoyi-ui/src/views/breedingStandards/diseaseTreatment/withdrawalPeriod/index.vue` |
24
+| API 模块 | `ruoyi-ui/src/api/breedingStandards/withdrawalPeriod.js` |
24
 
25
 
25
-封装方法:`listWithdrawalPeriodStandard`、`getWithdrawalPeriodStandard`、`addWithdrawalPeriodStandard`、`updateWithdrawalPeriodStandard`、`delWithdrawalPeriodStandard`、`syncKbWithdrawalPeriodStandard`、`removeKbWithdrawalPeriodStandard`
26
+**菜单配置**:组件路径 `breedingStandards/diseaseTreatment/withdrawalPeriod/index`;权限前缀 `withdrawalPeriod:standard:`(**无** `publish`、`offline`)
26
 
27
 
27
 ---
28
 ---
28
 
29
 
29
-## 3. 列表与查询
30
+## 3. 页面结构
31
+
32
+### 3.1 查询区
33
+
34
+| UI | 绑定/说明 |
35
+| --- | --- |
36
+| 药物名称 | `queryParams.keyword`,**仅** `drug_name` 模糊匹配(总方案 **§3.1**) |
37
+| 药物类型 | `queryParams.drugType`,`1`~`4` 精确筛选,可清空 |
38
+| 新增 | 权限 `withdrawalPeriod:standard:add` |
39
+
40
+### 3.2 列表区
41
+
42
+| 列 | 字段 | 备注 |
43
+| --- | --- | --- |
44
+| 药物名称 | `drugName` | — |
45
+| 药物类型 | `drugType` | `drugTypeLabel` |
46
+| 休药期(天) | `withdrawalDays` | — |
47
+| 使用指南 | `usageGuide` | 溢出省略 |
48
+| 药物作用 | `drugEffect` | 溢出省略 |
49
+| 知识库同步 | `kbSyncStatus` | `kbSyncStatusText` |
50
+| 创建时间 | `createTime` | `parseTime` |
51
+| 操作 | — | 见 **§5** |
30
 
52
 
31
-- **分页**:`pageNum`、`pageSize`(默认 20)。
32
-- **筛选**:`keyword`(**仅**药物名称模糊);`drugType`(1~4 精确匹配,可清空)。
33
-- **表格列**:药物名称、药物类型文案、休药期天数、使用指南、药物作用(溢出省略)、知识库同步状态、创建时间、操作列。
34
-- **行字段**:`drugName`、`drugType`、`withdrawalDays`、`usageGuide`、`drugEffect`、`kbSyncStatus`、`kbDocId`(详情/查看可展示)等,均为小驼峰。
53
+**分页**:默认 `pageNum=1`、`pageSize=20`。
35
 
54
 
36
-**药物类型枚举(与后端一致)**:`1` 抗生素、`2` 抗原虫、`3` 抗病毒、`4` 激素。
55
+### 3.3 新增 / 编辑弹窗
56
+
57
+| 字段 | 控件 | 校验 |
58
+| --- | --- | --- |
59
+| `drugName` | 输入框,`maxlength=20` | 必填 1~20;提交前 **trim**;全表唯一由后端校验 |
60
+| `drugType` | 下拉 | 必填,`1`~`4` |
61
+| `withdrawalDays` | `el-input-number` | 必填整数 **1~999** |
62
+| `usageGuide` | 多行文本 | 必填 1~200 字 |
63
+| `drugEffect` | 多行文本 | 必填 1~200 字 |
64
+
65
+**编辑条件**:仅 `kbSyncStatus === 0`(总方案 **§3.4**)。已同步点编辑提示 `ruleSyncedNoEdit`,不打开弹窗。
66
+
67
+### 3.4 查看弹窗
68
+
69
+展示 **§3.3** 全部字段 + `kbSyncStatus`、`kbDocId`(便于验收占位 ID)、`createTime`、`updateTime`。
37
 
70
 
38
 ---
71
 ---
39
 
72
 
40
-## 4. 表单校验(与后端 Bean / `WithdrawalPeriodStandardValidation` 对齐)
73
+## 4. 药物类型枚举(总方案 §2.2)
74
+
75
+页面 `drugTypeOptions` 由 `1`~`4` 映射国际化文案,**非**资讯类别接口:
41
 
76
 
42
-| 字段 | 规则 |
77
+| 值 | 文案(示例) |
43
 | --- | --- |
78
 | --- | --- |
44
-| `drugName` | 必填,长度 1~20(`String.length` 口径);**全表唯一**(保存失败时展示后端「药物名称已存在」) |
45
-| `drugType` | 必填,`1`~`4` |
46
-| `withdrawalDays` | 必填,整数 **1~999** |
47
-| `usageGuide` | 必填,长度 1~200 |
48
-| `drugEffect` | 必填,长度 1~200 |
79
+| `1` | 抗生素 |
80
+| `2` | 抗原虫 |
81
+| `3` | 抗病毒 |
82
+| `4` | 激素 |
49
 
83
 
50
-编辑弹窗使用 `el-input-number` 约束休药期范围,并辅以自定义校验器保证为整数且在 1~999。
84
+---
85
+
86
+## 5. 操作按钮与权限
87
+
88
+本模块**仅有**知识库同步维度(功能需求 **§5** 操作矩阵)。
89
+
90
+| 按钮 | 权限标识 | 显示条件 |
91
+| --- | --- | --- |
92
+| 查看 | `withdrawalPeriod:standard:query` | 有权限即显 |
93
+| 同步知识库 | `withdrawalPeriod:standard:syncKb` | `kbSyncStatus === 0` |
94
+| 移出知识库 | `withdrawalPeriod:standard:removeKb` | `kbSyncStatus === 1` |
95
+| 编辑 | `withdrawalPeriod:standard:edit` | `kbSyncStatus === 0` |
96
+| 删除 | `withdrawalPeriod:standard:remove` | `kbSyncStatus === 0` |
97
+
98
+已同步记录点编辑/删除时前端提示 `ruleSyncedNoEdit` / `ruleDeleteNeedRemoveKb`(双重守卫,与按钮 `v-if` 一致)。
51
 
99
 
52
 ---
100
 ---
53
 
101
 
54
-## 5. 操作按钮与知识库状态
102
+## 6. API 模块(总方案 §3)
55
 
103
 
56
-本模块**仅有**知识库同步维度,无发布状态。
104
+文件:`ruoyi-ui/src/api/breedingStandards/withdrawalPeriod.js`,Base Path `/withdrawalPeriod/standard`
57
 
105
 
58
-| 按钮 | 显示条件 | 权限标识 |
106
+| 方法 | HTTP | URI |
59
 | --- | --- | --- |
107
 | --- | --- | --- |
60
-| 查看 | 有 `query` 权限 | `withdrawalPeriod:standard:query` |
61
-| 同步知识库 | `kbSyncStatus === 0` | `withdrawalPeriod:standard:syncKb` |
62
-| 移出知识库 | `kbSyncStatus === 1` | `withdrawalPeriod:standard:removeKb` |
63
-| 编辑 | `kbSyncStatus === 0` | `withdrawalPeriod:standard:edit` |
64
-| 删除 | `kbSyncStatus === 0` | `withdrawalPeriod:standard:remove` |
108
+| `listWithdrawalPeriodStandard` | GET | `/list` |
109
+| `getWithdrawalPeriodStandard` | GET | `/{id}` |
110
+| `addWithdrawalPeriodStandard` | POST | `/` |
111
+| `updateWithdrawalPeriodStandard` | PUT | `/` |
112
+| `delWithdrawalPeriodStandard` | DELETE | `/{ids}` |
113
+| `syncKbWithdrawalPeriodStandard` | POST | `/syncKb/{id}` |
114
+| `removeKbWithdrawalPeriodStandard` | POST | `/removeKb/{id}` |
65
 
115
 
66
-已同步记录须先「移出知识库」后再允许编辑、删除(与需求 **4.6**、技术方案 **3.4** 一致)。
116
+**列表查询参数**:`pageNum`、`pageSize`、`keyword`、`drugType`
67
 
117
 
68
 ---
118
 ---
69
 
119
 
70
-## 6. 与养殖标准页的差异摘要
120
+## 7. 错误与交互约定
71
 
121
 
72
-| 项 | 养殖标准(breedingManage) | 休药期标准 |
122
+| 场景 | 前端行为 |
123
+| --- | --- |
124
+| 药物名称重复 | 展示后端 `msg`(如「药物名称已存在」) |
125
+| 已同步点编辑 | `msgWarning(ruleSyncedNoEdit)` |
126
+| 已同步点删除 | `msgWarning(ruleDeleteNeedRemoveKb)` |
127
+| 同步 / 移出 / 删除 | `this.$modal.confirm` 二次确认 |
128
+
129
+---
130
+
131
+## 8. 与养殖标准页的差异
132
+
133
+| 项 | 养殖标准 | 休药期标准 |
73
 | --- | --- | --- |
134
 | --- | --- | --- |
74
-| 正文/封面上传 | 有 | 无 |
75
-| 发布/下架 | 有 | 无 |
76
-| 列表筛选维度 | 关键词 + `standardType` | 药物名称 + `drugType` |
77
-| 知识库 | 同步 / 移出 + 发布链路 | 仅同步 / 移出 |
135
+| 正文/封面上传 | 有 | **** |
136
+| 发布/下架 | 有 | **** |
137
+| 状态机 | 上架 × 知识库 | **仅知识库** |
138
+| 列表筛选 | 关键词 + `standardType`(资讯类别编码) | 药物名称 + `drugType`(`1`~`4`) |
78
 
139
 
79
 ---
140
 ---
80
 
141
 
81
-## 7. 联调说明
142
+## 9. 交付与联调清单
82
 
143
 
83
-1. 部署含 `BizWithdrawalPeriodStandardController` 的后端,确认代理 `VUE_APP_BASE_API` 可达。
84
-2. 菜单与按钮权限与 `sql/biz_withdrawal_period_standard.sql` 注释中的标识一致后,用不同权限账号验证列表与写操作。
85
-3. 同步成功后后端可能写入占位 `kbDocId`(如 `LOCAL-{id}`),查看弹窗可展示该字段便于验收。
144
+- [x] 菜单路由指向 `breedingStandards/diseaseTreatment/withdrawalPeriod/index`  
145
+- [x] 无 `publish` / `offline` 按钮与权限  
146
+- [ ] 后端 `/withdrawalPeriod/standard/**` 与总方案 **§3** 对齐  
147
+- [ ] 联调:新增 → 同步 → 移出 → 编辑 → 再同步 → 删除  
148
+- [ ] 联调:已同步编辑/删除被前端拦截;药物名称唯一性后端校验  
86
 
149
 
87
 ---
150
 ---
88
 
151
 
89
-## 8. 修订记录
152
+## 10. 文档修订记录
90
 
153
 
91
-| 日期 | 说明 |
92
-| --- | --- |
93
-| 2026-05-13 | 初稿:页面、API、权限与后端 Controller 对齐 |
154
+| 版本 | 日期 | 说明 |
155
+| --- | --- | --- |
156
+| v1.0 | 2026-05-13 | 初稿:页面、API、权限与后端 Controller 对齐 |
157
+| **v1.1** | **2026-06-01** | 对齐总方案/功能需求:**无发布下架**单维知识库状态机;`keyword` 仅药物名称;提交 `drugName` trim;已同步编辑/删除提示;查看弹窗展示 `kbDocId` |

+ 6 - 4
doc/养殖标准体系/养殖标准/养殖标准管理前端技术方案.md

@@ -75,7 +75,7 @@
75
 
75
 
76
 - 标题:`dialogAdd` / `dialogEdit`;`:key="formKey"` 重置表单。
76
 - 标题:`dialogAdd` / `dialogEdit`;`:key="formKey"` 重置表单。
77
 - 字段:`standardName`(1~20)、`standardType`、`introduction`(≤50)、正文上传、封面上传(`picture-card`,`:limit="1"`)。
77
 - 字段:`standardName`(1~20)、`standardType`、`introduction`(≤50)、正文上传、封面上传(`picture-card`,`:limit="1"`)。
78
-- 编辑时 `canEditUploadRow`:仅 `publishStatus=0` 且 `kbSyncStatus=0` 可换附件。
78
+- 编辑时 `canEditFormRow`:仅 `publishStatus=0` 且 `kbSyncStatus=0` 可改字段及换附件;已同步点编辑提示 `ruleSyncedNoEdit`
79
 - 提交 Body:`standardName`、`standardType`、`introduction`、`contentFileUrl`、`contentFilePath`、`contentFileName`、`coverFileUrl`、`coverFilePath`;编辑带 `id`。
79
 - 提交 Body:`standardName`、`standardType`、`introduction`、`contentFileUrl`、`contentFilePath`、`contentFileName`、`coverFileUrl`、`coverFilePath`;编辑带 `id`。
80
 
80
 
81
 ### 3.4 查看弹窗
81
 ### 3.4 查看弹窗
@@ -112,7 +112,7 @@
112
 | 组合 | 编辑 | 同步 | 移出 | 发布 | 下架 | 删除 |
112
 | 组合 | 编辑 | 同步 | 移出 | 发布 | 下架 | 删除 |
113
 | --- | --- | --- | --- | --- | --- | --- |
113
 | --- | --- | --- | --- | --- | --- | --- |
114
 | 未发布 + 未同步 | ✓ | ✓ | — | — | — | ✓ |
114
 | 未发布 + 未同步 | ✓ | ✓ | — | — | — | ✓ |
115
-| 未发布 + 已同步 |  | — | ✓ | ✓ | — | ✗ |
115
+| 未发布 + 已同步 |  | — | ✓ | ✓ | — | ✗ |
116
 | 已发布 + 已同步 | ✗ | — | — | — | ✓ | ✗ |
116
 | 已发布 + 已同步 | ✗ | — | — | — | ✓ | ✗ |
117
 
117
 
118
 **`can*` 方法**(均 `Number()` 比较)+ **`v-hasPermi`** + **`v-if`** 控制按钮。
118
 **`can*` 方法**(均 `Number()` 比较)+ **`v-hasPermi`** + **`v-if`** 控制按钮。
@@ -129,8 +129,9 @@
129
 **交互提示**
129
 **交互提示**
130
 
130
 
131
 - 已发布点编辑:`rulePublishedNoEdit`
131
 - 已发布点编辑:`rulePublishedNoEdit`
132
-- 已同步点编辑:`ruleSyncedNoEdit`(或等价提示)
132
+- 已同步点编辑:`ruleSyncedNoEdit`
133
 - 已同步点删除:`ruleDeleteNeedRemoveKb`
133
 - 已同步点删除:`ruleDeleteNeedRemoveKb`
134
+- 标准类型加载失败:`errStdTypeLoad`
134
 - 同步/移出/发布/下架/删除:二次确认后调接口,成功 `getList()` 刷新
135
 - 同步/移出/发布/下架/删除:二次确认后调接口,成功 `getList()` 刷新
135
 
136
 
136
 **状态文案**:`breedingStdLocaleMixin.publishStatusText` / `kbSyncStatusText`;历史 `publishStatus=2` 按「未发布」展示。
137
 **状态文案**:`breedingStdLocaleMixin.publishStatusText` / `kbSyncStatusText`;历史 `publishStatus=2` 按「未发布」展示。
@@ -178,7 +179,7 @@
178
 
179
 
179
 1. 标准类型下拉与保存编码(如 `001001`)一致。
180
 1. 标准类型下拉与保存编码(如 `001001`)一致。
180
 2. 未发布+未同步:可新增、同步、编辑、删除。
181
 2. 未发布+未同步:可新增、同步、编辑、删除。
181
-3. 未发布+已同步:不可编辑,可移出、发布;不可删。
182
+3. 未发布+已同步:不可编辑(前端拦截),可移出、发布;不可删。
182
 4. 已发布:仅查看、下架;下架后回到未发布+已同步。
183
 4. 已发布:仅查看、下架;下架后回到未发布+已同步。
183
 5. 正文 `contentFileName` 在列表与详情正确展示;双语切换正常。
184
 5. 正文 `contentFileName` 在列表与详情正确展示;双语切换正常。
184
 
185
 
@@ -201,3 +202,4 @@
201
 | 版本 | 说明 |
202
 | 版本 | 说明 |
202
 | --- | --- |
203
 | --- | --- |
203
 | 1.0 | 根据 `breedingManage/index.vue` 生成:双卡片 CRUD、资讯类别编码、双维状态机、附件上传、知识库与发布/下架 |
204
 | 1.0 | 根据 `breedingManage/index.vue` 生成:双卡片 CRUD、资讯类别编码、双维状态机、附件上传、知识库与发布/下架 |
205
+| **1.1** | **2026-06-01**:标准类型改资讯类别编码(`parentCode=001&categoryType=1`);存量 `1`~`4` 回退展示;编辑/上传仅 **未发布+未同步**;类型加载失败与已同步编辑提示;下架回流 **(0,1)** 操作矩阵修正 |

+ 148 - 45
doc/养殖标准体系/生长与出栏标准/生长与出栏标准管理前端技术方案.md

@@ -1,89 +1,192 @@
1
 # 生长与出栏标准管理 — 前端技术方案
1
 # 生长与出栏标准管理 — 前端技术方案
2
 
2
 
3
-> 依据:`doc/生长与出栏标准/生长与出栏标准管理技术方案.md`;页面布局对齐 `ruoyi-ui/src/views/breedingStandards/breedingManage/index.vue`;请求与表单字段统一 **小驼峰**,与后端 `BizGrowthSlaughterStandard` 及 Jackson 序列化一致
3
+> 依据:`生长与出栏标准管理技术方案.md`(同目录,下称**总方案**)。本文描述 **Vue 管理端页面**、**接口封装**、**权限字**、**交互与校验**与总方案 **§2 / §3** 的对应关系;库表、状态机与知识库编排以后端总方案为准
4
 
4
 
5
 ---
5
 ---
6
 
6
 
7
-## 1. 页面与路由
7
+## 1. 技术架构
8
 
8
 
9
 | 项 | 说明 |
9
 | 项 | 说明 |
10
 | --- | --- |
10
 | --- | --- |
11
-| **Vue 路径** | `ruoyi-ui/src/views/breedingStandards/growthOutbound/index.vue` |
11
+| **工程** | 若依 **RuoYi-Vue** 前端(Vue **2.x** + **Element UI** + **Vue Router** + **Vuex**) |
12
+| **页面路径** | `ruoyi-ui/src/views/breedingStandards/growthOutbound/index.vue` |
12
 | **组件名** | `GrowthOutboundStandard` |
13
 | **组件名** | `GrowthOutboundStandard` |
13
-| **菜单配置** | 若依「菜单管理」组件路径:`breedingStandards/growthOutbound/index` |
14
-| **权限前缀** | `growthSlaughter:standard:` |
14
+| **布局参考** | `ruoyi-ui/src/views/breedingStandards/breedingManage/index.vue`(双 `el-card`:查询区 + 表格区;新增/编辑弹窗 + 查看弹窗) |
15
+| **HTTP** | `@/utils/request` 封装 Axios,自动拼接 `VUE_APP_BASE_API`、携带 `Authorization` |
16
+| **时间格式化** | 全局 `parseTime`(若依 `utils/ruoyi` 注入) |
17
+| **分页** | 公共组件 `pagination`,与列表 `TableDataInfo` 的 `total`、`rows` 对齐 |
18
+
19
+**与总方案关系**:列表/详情/写操作均调用总方案 **§3** 所列 REST;行内操作显隐与 `publish_status`、`kb_sync_status` 合法组合一致(总方案 **§2.1** 合法组合)。
15
 
20
 
16
 ---
21
 ---
17
 
22
 
18
-## 2. API 模块
23
+## 2. 源码与路由
19
 
24
 
20
-| 项 | 说明 |
25
+| 类型 | 路径 |
21
 | --- | --- |
26
 | --- | --- |
22
-| **文件** | `ruoyi-ui/src/api/breedingStandards/growthSlaughter.js` |
23
-| **Base Path** | `/growthSlaughter/standard` |
27
+| 页面 | `ruoyi-ui/src/views/breedingStandards/growthOutbound/index.vue` |
28
+| API 模块 | `ruoyi-ui/src/api/breedingStandards/growthSlaughter.js` |
24
 
29
 
25
-封装方法:`listGrowthSlaughterStandard`、`getGrowthSlaughterStandard`、`addGrowthSlaughterStandard`、`updateGrowthSlaughterStandard`、`delGrowthSlaughterStandard`、`syncKbGrowthSlaughterStandard`、`removeKbGrowthSlaughterStandard`、`publishGrowthSlaughterStandard`、`offlineGrowthSlaughterStandard`。
30
+**菜单(若依后台配置)**
31
+
32
+| 配置项 | 建议值 |
33
+| --- | --- |
34
+| 组件路径 | `breedingStandards/growthOutbound/index`(与 `views` 下相对路径一致,无前缀 `@/`) |
35
+| 路由名 | 自定,不与现有路由冲突即可 |
36
+| 权限标识 | 与 **§5** 表一致,子菜单按钮 SQL 与总方案交付清单对齐 |
26
 
37
 
27
 ---
38
 ---
28
 
39
 
29
-## 3. 列表与查询
40
+## 3. 页面结构
41
+
42
+### 3.1 查询区(首卡片)
43
+
44
+| UI | 绑定/说明 |
45
+| --- | --- |
46
+| 关键词 | `queryParams.keyword`,占位「标准名称或简介」,回车触发搜索 |
47
+| 标准类型 | `queryParams.standardType`,下拉可清空;选项在 `created` 中调用 **§7.1** 接口动态加载 |
48
+| 搜索 / 重置 / 新增 | 与设备实施作业标准页一致;新增权限 `growthSlaughter:standard:add` |
49
+
50
+### 3.2 列表区(次卡片)
51
+
52
+| 列 | 数据来源 | 备注 |
53
+| --- | --- | --- |
54
+| 标准名称 | `standardName` | `show-overflow-tooltip` |
55
+| 标准类型 | `standardType` | `typeLabel(code)`:由 `standardTypeOptions`(**§6.1**)按编码映射名称 |
56
+| 简介 | `introduction` | — |
57
+| 正文附件 | `contentFileUrl` / `contentFileName` | `el-link` 新窗口打开 |
58
+| 上架状态 | `publishStatus` | `publishStatusText` |
59
+| 知识库同步 | `kbSyncStatus` | `kbSyncStatusText` |
60
+| 发布日期 | `publishTime` | `parseTime(..., '{y}-{m}-{d}')`,空为「—」 |
61
+| 创建时间 | `createTime` | `parseTime` 完整格式 |
62
+| 操作 | 多个 `el-button type="text"` | 权限 + 行状态双条件,见 **§5** |
63
+
64
+**分页**:`pageNum`、`pageSize` 默认 **1 / 20**,与总方案 **§3.1** 一致。
65
+
66
+### 3.3 新增 / 编辑弹窗
67
+
68
+| 字段 | 表单控件 | 校验(前端) |
69
+| --- | --- | --- |
70
+| `standardName` | 输入框,`maxlength=20` | 必填;长度 **1~20** |
71
+| `standardType` | 下拉 | 必填;选项来自 `listInformationCategoryChildren('001', 4)`,`value`=`code`,`label`=`name` |
72
+| `introduction` | 多行文本,`maxlength=50` | 选填;最多 **50** 字 |
73
+| 正文附件 | `el-upload` → `/common/upload` | 必填;后缀白名单、≤**30MB**、文件名不含英文逗号 |
74
+| 封面 | `picture-card` 上传,最多 1 张 | 选填;`jpg/jpeg/png`、≤**10MB** |
75
+
76
+**编辑态**:仅当详情返回 `publishStatus === 0` 且 `kbSyncStatus === 0` 时允许修改表单字段及替换/删除正文与封面(`canEditFormRow`);与总方案 **§3.4** 一致。已同步记录点击编辑时提示 `ruleSyncedNoEdit`,不打开弹窗。
30
 
77
 
31
-- **分页**:`pageNum`、`pageSize`(默认 20)。
32
-- **筛选**:`keyword`(标准名称或简介模糊);`standardType`(精确,可空)。
33
-- **标准类型**:`created` 调用 `listInformationCategoryChildren('001', 4)` 动态加载;`value`=`code`,`label`=`name`。
34
-- **表格列**:标准名称、标准类型、简介、正文附件链接、`publishStatus`、`kbSyncStatus`、发布日期、创建时间、操作列。
78
+弹窗标题:`[新增]生长与出栏标准` / `[编辑]生长与出栏标准`。
79
+
80
+### 3.4 查看弹窗
81
+
82
+调 `GET /growthSlaughter/standard/{id}` 拉全量展示:标准名称、类型、简介、正文链接、封面、上架状态、知识库同步、发布时间、下架时间。
35
 
83
 
36
 ---
84
 ---
37
 
85
 
38
-## 4. 表单与上传
86
+## 4. 上传与鉴权
39
 
87
 
40
-- **新增/编辑**:标准名称(1~20)、标准类型、简介(≤50 字,选填)、正文附件(必填)、封面(选填)。
41
-- **上传**:`POST /common/upload`,Header `Authorization: Bearer <token>`;映射 `url` → `contentFileUrl`、`fileName` → `contentFilePath`、`originalFilename`/文件名 → `contentFileName`。
42
-- **前端校验**:正文扩展名与大小(≤30MB)、封面 jpg/jpeg/png(≤10MB)、文件名不含英文逗号,与疫病诊疗/养殖标准页一致。
43
-- **编辑态**:仅 `publishStatus === 0`(未发布)时可替换正文与封面。
88
+与设备实施作业标准页一致:`VUE_APP_BASE_API + '/common/upload'`,Header `Authorization: Bearer <token>`;成功取 `url`、`fileName`、`originalFilename`。正文后缀:`pdf`、`md`、`doc`、`docx`、`xls`、`xlsx`、`ppt`、`pptx`。
44
 
89
 
45
 ---
90
 ---
46
 
91
 
47
-## 5. 操作按钮与状态机
92
+## 5. 操作按钮与权限
48
 
93
 
49
-与《养殖标准管理技术方案》双维模型一致:**未发布/已发布** × **未同步/已同步**。
94
+权限字与总方案 **§3** 一致;按钮同时受 **`v-hasPermi`** 与 **行状态方法** 控制
50
 
95
 
51
-| 按钮 | 显示条件 | 权限标识 |
96
+| 按钮 | 权限标识 | 显示条件(与行数据) |
52
 | --- | --- | --- |
97
 | --- | --- | --- |
53
-| 查看 | 有 query 权限 | `growthSlaughter:standard:query` |
54
-| 同步知识库 | 未发布且未同步 | `growthSlaughter:standard:syncKb` |
55
-| 移出知识库 | 未发布且已同步 | `growthSlaughter:standard:removeKb` |
56
-| 编辑 | 未发布 | `growthSlaughter:standard:edit` |
57
-| 删除 | 未发布且未同步 | `growthSlaughter:standard:remove` |
58
-| 发布 | 未发布且已同步 | `growthSlaughter:standard:publish` |
59
-| 下架 | 已发布 | `growthSlaughter:standard:offline` |
98
+| 查看 | `growthSlaughter:standard:query` | 有权限即显 |
99
+| 同步知识库 | `growthSlaughter:standard:syncKb` | `publishStatus === 0` 且 `kbSyncStatus === 0` |
100
+| 移出知识库 | `growthSlaughter:standard:removeKb` | `publishStatus === 0` 且 `kbSyncStatus === 1` |
101
+| 编辑 | `growthSlaughter:standard:edit` | `publishStatus === 0` 且 `kbSyncStatus === 0`(与总方案 **§3.4** 一致) |
102
+| 删除 | `growthSlaughter:standard:remove` | `publishStatus === 0` 且 `kbSyncStatus === 0` |
103
+| 发布 | `growthSlaughter:standard:publish` | `publishStatus === 0` 且 `kbSyncStatus === 1` |
104
+| 下架 | `growthSlaughter:standard:offline` | `publishStatus === 1` |
60
 
105
 
61
-下架完成后业务稳态为 **未发布 + 已同步**,可再次发布;改内容须先移出(与功能需求 **4.8** 一致)。
106
+下架完成后业务稳态为 **未发布 + 已同步**,可再次发布;改内容须先移出(与功能需求一致)。
62
 
107
 
63
 ---
108
 ---
64
 
109
 
65
-## 6. 与疫病诊疗标准前端的差异
110
+## 6. 枚举与展示映射
66
 
111
 
67
-| 项 | 疫病诊疗 | 生长与出栏 |
68
-| --- | --- | --- |
69
-| API 文件 | `epidemicTreatment.js` | `growthSlaughter.js` |
70
-| Base Path | `/epidemicTreatment/standard` | `/growthSlaughter/standard` |
71
-| 标准类型选项 | 资讯类别接口 | `001011` 牦牛生长、`001012` 牦牛出栏(`parentCode=001`,`categoryType=4`) |
112
+### 6.1 `standardType`(标准类型)
113
+
114
+页面维护 `standardTypeOptions: []`,`created` 调用 `loadStandardTypeOptions()`:
115
+
116
+```javascript
117
+import { listInformationCategoryChildren } from '@/api/category/informationCategory'
118
+// listInformationCategoryChildren('001', 4) → data[],项字段 code、name
119
+```
72
 
120
 
73
-页面结构、上传组件与权限粒度与疫病诊疗标准页保持一致,便于维护。
121
+列表/详情展示:`typeLabel(code)` 在 `standardTypeOptions` 中查找后取 `name`;找不到时回退 **存量迁移** 映射 `LEGACY_STANDARD_TYPE_LABELS`(`1`~`2` → 国际化 `breedingStd.growth.type1`~`type2`,对应总方案 **§2.2** 迁移脚本 `1`→`001011`,`2`→`001012`);仍无则回显编码。
122
+
123
+| 编码(示例) | 界面文案 |
124
+| --- | --- |
125
+| `001011` | 牦牛生长 |
126
+| `001012` | 牦牛出栏 |
127
+
128
+### 6.2 `publishStatus` / `kbSyncStatus`
129
+
130
+与养殖标准模块一致:`0` 未发布/未同步,`1` 已发布/已同步。
74
 
131
 
75
 ---
132
 ---
76
 
133
 
77
-## 7. 联调说明
134
+## 7. API 模块与后端 URI 对应
135
+
136
+### 7.1 标准类型选项(资讯类别)
78
 
137
 
79
-1. 确认后端 `BizGrowthSlaughterStandardController` 已部署,`VUE_APP_BASE_API` 代理正确。
80
-2. 菜单与按钮权限与 `sql/biz_growth_slaughter_standard.sql` 注释中的标识一致。
81
-3. 新增前可先调用 `/common/upload` 验证 Token 与跨域;再提交 `POST /growthSlaughter/standard` 全量合法 Body。
138
+文件:`ruoyi-ui/src/api/category/informationCategory.js`
139
+
140
+| 方法 | HTTP | URI | 参数 |
141
+| --- | --- | --- | --- |
142
+| `listInformationCategoryChildren` | GET | `/category/informationCategory/children` | `parentCode=001`,`categoryType=4` |
143
+
144
+### 7.2 生长与出栏标准 CRUD
145
+
146
+文件:`ruoyi-ui/src/api/breedingStandards/growthSlaughter.js`。请求/响应字段采用 **小驼峰**。
147
+
148
+| 方法(导出) | HTTP | URI |
149
+| --- | --- | --- |
150
+| `listGrowthSlaughterStandard` | GET | `/growthSlaughter/standard/list` |
151
+| `getGrowthSlaughterStandard` | GET | `/growthSlaughter/standard/{id}` |
152
+| `addGrowthSlaughterStandard` | POST | `/growthSlaughter/standard` |
153
+| `updateGrowthSlaughterStandard` | PUT | `/growthSlaughter/standard` |
154
+| `delGrowthSlaughterStandard` | DELETE | `/growthSlaughter/standard/{ids}` |
155
+| `syncKbGrowthSlaughterStandard` | POST | `/growthSlaughter/standard/syncKb/{id}` |
156
+| `removeKbGrowthSlaughterStandard` | POST | `/growthSlaughter/standard/removeKb/{id}` |
157
+| `publishGrowthSlaughterStandard` | POST | `/growthSlaughter/standard/publish/{id}` |
158
+| `offlineGrowthSlaughterStandard` | POST | `/growthSlaughter/standard/offline/{id}` |
159
+
160
+**列表查询参数**:`pageNum`、`pageSize`、`keyword`、`standardType`。
82
 
161
 
83
 ---
162
 ---
84
 
163
 
85
-## 8. 修订记录
164
+## 8. 错误与交互约定
86
 
165
 
87
-| 日期 | 说明 |
166
+| 场景 | 前端行为 |
88
 | --- | --- |
167
 | --- | --- |
89
-| 2026-05-13 | 初稿:页面、API、权限与后端 Controller 对齐 |
168
+| 列表/表单接口非 200 | 走全局 `request` 拦截器提示 |
169
+| 标准类型选项加载失败 | `msgError(errStdTypeLoad)`,下拉为空 |
170
+| 已同步记录点编辑 | `msgWarning(ruleSyncedNoEdit)`,不请求详情 |
171
+| 已发布记录点编辑 | `msgWarning(rulePublishedNoEdit)` |
172
+| 上传失败 | `msgError`,关闭 loading |
173
+
174
+---
175
+
176
+## 9. 交付与联调清单
177
+
178
+- [x] 菜单路由指向 `breedingStandards/growthOutbound/index`,按钮权限与 **§5** 一致  
179
+- [x] 标准类型下拉:`GET /category/informationCategory/children?parentCode=001&categoryType=4`  
180
+- [ ] 后端 `/growthSlaughter/standard/**` 与总方案 **§3** 对齐  
181
+- [ ] 存量环境执行 `sql/biz_growth_slaughter_standard_alter_standard_type.sql` 后列表类型展示正常  
182
+- [ ] 联调:新增 → 同步 → 发布 → 下架 → 移出 → 删除  
183
+- [ ] 联调:已同步记录编辑被前端拦截;未同步修改成功
184
+
185
+---
186
+
187
+## 10. 文档修订记录
188
+
189
+| 版本 | 日期 | 说明 |
190
+| --- | --- | --- |
191
+| v1.0 | 2026-05-13 | 初稿:页面、API、权限与后端 Controller 对齐 |
192
+| **v1.1** | **2026-06-01** | **标准类型改资讯类别编码**:动态加载 `parentCode=001&categoryType=4`;筛选/表单传 `code`;存量 `1`~`2` 回退展示;编辑/上传仅 **未发布+未同步**;补充类型加载失败与已同步编辑提示 |

+ 155 - 38
doc/养殖标准体系/疫病诊疗标准/疫病诊疗标准管理前端技术方案.md

@@ -1,6 +1,6 @@
1
 # 疫病诊疗标准管理 — 前端技术方案
1
 # 疫病诊疗标准管理 — 前端技术方案
2
 
2
 
3
-> 依据:`doc/疫病诊疗标准/疫病诊疗标准管理技术方案.md`;页面布局对齐 `ruoyi-ui/src/views/breedingStandards/breedingManage/index.vue`;请求/表单字段统一 **小驼峰**,与后端 `BizEpidemicTreatmentStandard` 及 RuoYi 序列化一致。
3
+> 依据:`疫病诊疗标准管理技术方案.md`(同目录,下称**总方案**)、`疫病诊疗标准管理功能需求.md`。页面布局对齐 `ruoyi-ui/src/views/breedingStandards/breedingManage/index.vue`;请求与表单字段统一 **小驼峰**,与后端 `BizEpidemicTreatmentStandard` 及 Jackson 序列化一致。
4
 
4
 
5
 ---
5
 ---
6
 
6
 
@@ -10,75 +10,192 @@
10
 | --- | --- |
10
 | --- | --- |
11
 | **Vue 路径** | `ruoyi-ui/src/views/breedingStandards/diseaseTreatment/epidemicTreatment/index.vue` |
11
 | **Vue 路径** | `ruoyi-ui/src/views/breedingStandards/diseaseTreatment/epidemicTreatment/index.vue` |
12
 | **组件名** | `EpidemicTreatmentStandard` |
12
 | **组件名** | `EpidemicTreatmentStandard` |
13
-| **菜单配置** | 若依后台「菜单管理」中配置组件路径为 `breedingStandards/diseaseTreatment/epidemicTreatment/index`(与项目其它养殖标准页一致,无 `views/`、`src/` 前缀) |
14
-| **权限前缀** | `epidemicTreatment:standard:` |
13
+| **菜单配置** | 若依「菜单管理」组件路径:`breedingStandards/diseaseTreatment/epidemicTreatment/index` |
14
+| **Mixin** | `breedingStdLocaleMixin`(`stdNs = "ep"` → `breedingStd.ep.*`) |
15
+| **权限前缀** | `epidemicTreatment:standard:list|query|add|edit|remove|syncKb|removeKb|publish|offline` |
15
 
16
 
16
 ---
17
 ---
17
 
18
 
18
 ## 2. API 模块
19
 ## 2. API 模块
19
 
20
 
20
-| 项 | 说明 |
21
+| 文件 | Base Path |
21
 | --- | --- |
22
 | --- | --- |
22
-| **文件** | `ruoyi-ui/src/api/breedingStandards/epidemicTreatment.js` |
23
-| **Base Path** | `/epidemicTreatment/standard`(经 `VUE_APP_BASE_API` 代理到后端) |
23
+| `ruoyi-ui/src/api/breedingStandards/epidemicTreatment.js` | `/epidemicTreatment/standard` |
24
+| `ruoyi-ui/src/api/category/informationCategory.js` | `/category/informationCategory/children` |
25
+
26
+| 方法 | HTTP | URI | 说明 |
27
+| --- | --- | --- | --- |
28
+| `listEpidemicTreatmentStandard` | GET | `/list` | 分页列表 |
29
+| `getEpidemicTreatmentStandard` | GET | `/{id}` | 详情 |
30
+| `addEpidemicTreatmentStandard` | POST | `/` | 新增 |
31
+| `updateEpidemicTreatmentStandard` | PUT | `/` | 修改(仅未发布+未同步) |
32
+| `delEpidemicTreatmentStandard` | DELETE | `/{ids}` | 删除 |
33
+| `syncKbEpidemicTreatmentStandard` | POST | `/syncKb/{id}` | 同步知识库 |
34
+| `removeKbEpidemicTreatmentStandard` | POST | `/removeKb/{id}` | 移出知识库 |
35
+| `publishEpidemicTreatmentStandard` | POST | `/publish/{id}` | 发布 |
36
+| `offlineEpidemicTreatmentStandard` | POST | `/offline/{id}` | 下架 |
37
+
38
+**标准类型下拉**:`listInformationCategoryChildren('001', '5')`,与后端 `EpidemicTreatmentStandardTypeValidator` 一致。
24
 
39
 
25
-封装方法:`listEpidemicTreatmentStandard`、`getEpidemicTreatmentStandard`、`addEpidemicTreatmentStandard`、`updateEpidemicTreatmentStandard`、`delEpidemicTreatmentStandard`、`syncKbEpidemicTreatmentStandard`、`removeKbEpidemicTreatmentStandard`、`publishEpidemicTreatmentStandard`、`offlineEpidemicTreatmentStandard`。
40
+**上传**:`POST /common/upload` → 正文 `contentFileUrl` / `contentFilePath` / `contentFileName`;封面 `coverFileUrl` / `coverFilePath`。
26
 
41
 
27
 ---
42
 ---
28
 
43
 
29
-## 3. 列表与查询
44
+## 3. 页面结构
45
+
46
+布局为双 `el-card`(筛选 + 列表),中间 `<br />` 分隔。
47
+
48
+### 3.1 筛选区
49
+
50
+| 绑定字段 | 说明 |
51
+| --- | --- |
52
+| `queryParams.keyword` | 名称/简介模糊(总方案 **§3.1**) |
53
+| `queryParams.standardType` | 资讯类别编码精确匹配,可清空 |
54
+| `queryParams.pageNum` / `pageSize` | 默认 1 / 20 |
55
+
56
+### 3.2 列表列
57
+
58
+| 列 | 字段 / 展示 |
59
+| --- | --- |
60
+| 标准名称 | `standardName` |
61
+| 标准类型 | `typeLabel(standardType)`,列宽 112 |
62
+| 简介 | `introduction` |
63
+| 正文附件 | `contentFileName` 链至 `contentFileUrl` |
64
+| 上架状态 | `publishStatusText(publishStatus)` |
65
+| 知识库同步 | `kbSyncStatusText(kbSyncStatus)` |
66
+| 发布日期 | `publishTime`(`yyyy-MM-dd`) |
67
+| 创建时间 | `createTime` |
68
+| 操作 | 见 **§5** |
69
+
70
+### 3.3 新增/编辑弹窗
30
 
71
 
31
-- **分页参数**:`pageNum`、`pageSize`(默认 20,与后端默认一致)。
32
-- **筛选**:`keyword`(名称/简介模糊);`standardType`(精确,可清空);选项在 `created` 中调用 `listInformationCategoryChildren('001', 5)` 动态加载。
33
-- **表格列**:标准名称、标准类型、简介、正文附件链接、`publishStatus` / `kbSyncStatus` 文案、发布日期、创建时间、操作列。
34
-- **数据字段**:列表行与详情均为小驼峰,如 `contentFileUrl`、`contentFileName`、`publishStatus`、`kbSyncStatus`、`publishTime`、`offlineTime`。
72
+- 标题:`dialogAdd` / `dialogEdit`;`:key="formKey"` 重置表单。
73
+- 字段:`standardName`(1~20)、`standardType`、`introduction`(≤50)、正文上传、封面上传。
74
+- 编辑时 `canEditFormRow`:仅 `publishStatus=0` 且 `kbSyncStatus=0` 可改字段及换附件;已发布/已同步点编辑分别提示 `rulePublishedNoEdit` / `ruleSyncedNoEdit`。
75
+- 提交 Body 不含 `publishStatus`、`kbSyncStatus`、`kbDocId`;编辑带 `id`。
76
+
77
+### 3.4 查看弹窗
78
+
79
+只读展示主字段、封面(`image-preview`)、上架/同步状态、发布时间、下架时间。
35
 
80
 
36
 ---
81
 ---
37
 
82
 
38
-## 4. 表单与上传
83
+## 4. 标准类型
84
+
85
+`created` 调用 `loadStandardTypeOptions()`;失败时 `errStdTypeLoad` 提示。
86
+
87
+`mapCategoryItem` 将接口项映射为 `{ value: code, label: name }`。
88
+
89
+`typeLabel` 优先匹配 `standardTypeOptions`;存量值 `1` 回退 `stdT('type1')`(疾病决策);仍无则回显编码。
39
 
90
 
40
-- **新增/编辑弹窗**:标准名称(1~20 字)、标准类型(资讯类别下拉,`value`=`code`、`label`=`name`)、简介(≤50 字,选填)、正文附件(必填)、封面(选填)。
91
+| 编码(示例) | 界面文案 |
92
+| --- | --- |
93
+| `001013` | 疾病决策(资讯类别,总方案 **§2.2**) |
41
 
94
 
42
-**标准类型接口**:`ruoyi-ui/src/api/category/informationCategory.js` — `GET /category/informationCategory/children?parentCode=001&categoryType=5`。
43
-- **上传**:`POST /common/upload`,请求头携带 `Authorization: Bearer <token>`;成功后将 `url` → `contentFileUrl`、`fileName` → `contentFilePath`、`originalFilename`(或本地文件名)→ `contentFileName`。
44
-- **前端校验**:正文扩展名 pdf/md/doc/docx/xls/xlsx/ppt/pptx,≤30MB;封面 jpg/jpeg/png,≤10MB;文件名不含英文逗号(与养殖标准页一致)。
45
-- **编辑态附件**:仅当 `publishStatus === 0`(未发布)时可替换正文与封面;已发布记录仅可查看。
95
+迁移脚本:`biz_epidemic_treatment_standard_alter_standard_type.sql`(`1` → `001013`)。
46
 
96
 
47
 ---
97
 ---
48
 
98
 
49
-## 5. 操作按钮与状态机(与后端前置条件一致)
99
+## 5. 状态常量与操作矩阵
100
+
101
+**脚本常量**
50
 
102
 
51
-| 按钮 | 显示条件(行数据) | 权限标识 |
103
+| 常量 | 值 | 含义 |
52
 | --- | --- | --- |
104
 | --- | --- | --- |
53
-| 查看 | 始终(有 query 权限时) | `epidemicTreatment:standard:query` |
54
-| 同步知识库 | 未发布且未同步 | `epidemicTreatment:standard:syncKb` |
55
-| 移出知识库 | 未发布且已同步 | `epidemicTreatment:standard:removeKb` |
56
-| 编辑 | 未发布 | `epidemicTreatment:standard:edit` |
57
-| 删除 | 未发布且未同步 | `epidemicTreatment:standard:remove` |
58
-| 发布 | 未发布且已同步 | `epidemicTreatment:standard:publish` |
59
-| 下架 | 已发布 | `epidemicTreatment:standard:offline` |
105
+| `PUBLISH_STATUS.UNPUBLISHED` | 0 | 未发布(含下架回流) |
106
+| `PUBLISH_STATUS.PUBLISHED` | 1 | 已发布 |
107
+| `KB_SYNC_STATUS.UNSYNCED` | 0 | 未同步 |
108
+| `KB_SYNC_STATUS.SYNCED` | 1 | 已同步 |
109
+
110
+合法稳态:`(0,0)`、`(0,1)`、`(1,1)`。下架成功后为 **未发布 + 已同步**(知识库保留副本,≠ 移出)。
111
+
112
+| 组合 | 编辑 | 同步 | 移出 | 发布 | 下架 | 删除 |
113
+| --- | --- | --- | --- | --- | --- | --- |
114
+| 未发布 + 未同步 | ✓ | ✓ | — | — | — | ✓ |
115
+| 未发布 + 已同步 | ✗ | — | ✓ | ✓ | — | ✗ |
116
+| 已发布 + 已同步 | ✗ | — | — | — | ✓ | ✗ |
117
+
118
+**`can*` 方法**(均 `Number()` 比较)+ **`v-hasPermi`** + **`v-if`** 控制按钮。
60
 
119
 
61
-说明:已发布且已同步等组合下,删除/编辑等由后端拦截;前端通过按钮隐藏减少误操作。下架后界面展示为未发布 + 已同步(与《疫病诊疗标准管理技术方案》一致)。
120
+| 方法 | 条件 |
121
+| --- | --- |
122
+| `canEdit` | `publishStatus === 0` 且 `kbSyncStatus === 0` |
123
+| `canSyncKb` | 未发布且未同步 |
124
+| `canRemoveKb` | 未发布且已同步 |
125
+| `canPublish` | 未发布且已同步 |
126
+| `canOffline` | 已发布 |
127
+| `canDelete` | 未发布且未同步 |
128
+
129
+**交互提示**
130
+
131
+- 已发布点编辑:`rulePublishedNoEdit`
132
+- 已同步点编辑:`ruleSyncedNoEdit`
133
+- 已同步点删除:`ruleDeleteNeedRemoveKb`
134
+- 标准类型加载失败:`errStdTypeLoad`
135
+- 同步/移出/发布/下架/删除:二次确认后调接口,成功 `getList()` 刷新
62
 
136
 
63
 ---
137
 ---
64
 
138
 
65
-## 6. 依赖与复用
139
+## 6. 表单与上传校验
66
 
140
 
67
-- **全局**:`pagination`、`parseTime`、`resetForm`、`v-hasPermi`、`$modal` 等与若依 Vue2 工程一致。
68
-- **组件**:`image-preview`(封面预览,与养殖标准页一致)。
141
+| 项 | 前端规则 |
142
+| --- | --- |
143
+| 标准名称 | 必填,1~20 字 |
144
+| 标准类型 | 必选(资讯类别编码) |
145
+| 简介 | 选填,≤50 字 |
146
+| 正文 | 必填;后缀 `pdf/md/doc/docx/xls/xlsx/ppt/pptx`;≤30MB;文件名不含英文逗号 |
147
+| 封面 | 选填;`jpg/jpeg/png`;≤10MB |
148
+
149
+已同步记录为只读;改内容须先移出知识库后再编辑、同步。
69
 
150
 
70
 ---
151
 ---
71
 
152
 
72
-## 7. 联调说明
153
+## 7. 国际化
73
 
154
 
74
-1. 确认后端 `BizEpidemicTreatmentStandardController` 已部署且上下文路径与前端代理一致。
75
-2. 在「菜单管理」中挂好菜单与上述按钮权限后,用具备各权限的账号验证列表、CRUD、同步/移出/发布/下架全链路。
76
-3. 若列表无数据,先通过新增 + 上传正文走通 `POST /epidemicTreatment/standard`。
155
+| 命名空间 | 路径 |
156
+| --- | --- |
157
+| 模块文案 | `breedingStd.ep.*`(`lang/zh/breedingStd.js`、`lang/bo/breedingStd.js`) |
158
+| 公共文案 | `breedingStd.common.*`、`breedingStd.status.*` |
159
+
160
+---
161
+
162
+## 8. 依赖组件与工具
163
+
164
+| 项 | 说明 |
165
+| --- | --- |
166
+| `pagination` | 分页 |
167
+| `parseTime` | 时间格式化 |
168
+| `image-preview` | 查看弹窗封面预览 |
169
+| `resetForm` | 重置查询表单 |
170
+| `$modal` | confirm / msgSuccess / msgWarning / msgError / loading |
171
+
172
+---
173
+
174
+## 9. 联调检查项
175
+
176
+1. 标准类型下拉与保存编码(如 `001013`)一致。
177
+2. 未发布+未同步:可新增、同步、编辑、删除。
178
+3. 未发布+已同步:不可编辑(前端拦截),可移出、发布;不可删。
179
+4. 已发布:仅查看、下架;下架后回到未发布+已同步。
180
+5. 正文 `contentFileName` 在列表与详情正确展示;双语切换正常。
181
+
182
+---
183
+
184
+## 10. 文件清单
185
+
186
+| 类型 | 路径 |
187
+| --- | --- |
188
+| 页面 | `ruoyi-ui/src/views/breedingStandards/diseaseTreatment/epidemicTreatment/index.vue` |
189
+| 业务 API | `ruoyi-ui/src/api/breedingStandards/epidemicTreatment.js` |
190
+| 类别 API | `ruoyi-ui/src/api/category/informationCategory.js` |
191
+| Mixin | `ruoyi-ui/src/mixins/breedingStdLocaleMixin.js` |
192
+| i18n | `ruoyi-ui/src/lang/zh/breedingStd.js`、`lang/bo/breedingStd.js` |
77
 
193
 
78
 ---
194
 ---
79
 
195
 
80
-## 8. 修订记录
196
+## 11. 修订记录
81
 
197
 
82
-| 日期 | 说明 |
198
+| 版本 | 说明 |
83
 | --- | --- |
199
 | --- | --- |
84
-| 2026-05-13 | 初稿:页面、API 路径与权限与后端 Controller 对齐;字段小驼峰 |
200
+| 1.0 | 初稿:双卡片 CRUD、资讯类别编码、双维状态机、附件上传、知识库与发布/下架 |
201
+| **1.1** | **2026-06-01**:标准类型改资讯类别编码(`parentCode=001&categoryType=5`);存量 `1` 回退展示;编辑/上传仅 **未发布+未同步**;类型加载失败与已同步编辑提示;下架回流 **(0,1)** 操作矩阵修正 |

+ 154 - 0
doc/养殖标准体系/药物禁配标准/药物禁配标准管理前端技术方案.md

@@ -0,0 +1,154 @@
1
+# 药物禁配标准管理 — 前端技术方案
2
+
3
+> 依据:`药物禁配标准管理技术方案.md`(同目录,下称**总方案**)、`药物禁配标准管理功能需求.md`。本模块**无发布/下架**、无附件上传;仅 **知识库同步** 单维状态机;**主表 + 配伍子表** 一对多。请求与表单字段统一 **小驼峰**,与后端 `BizDrugIncompatibilityStandard` / `BizDrugIncompatibilityCompanion` 及 Jackson 序列化一致。
4
+
5
+---
6
+
7
+## 1. 技术架构
8
+
9
+| 项 | 说明 |
10
+| --- | --- |
11
+| **工程** | 若依 **RuoYi-Vue** 前端(Vue **2.x** + **Element UI**) |
12
+| **页面路径** | `ruoyi-ui/src/views/breedingStandards/diseaseTreatment/drugIncompatibility/index.vue` |
13
+| **组件名** | `DrugIncompatibilityStandard` |
14
+| **布局参考** | 双 `el-card`(查询区 + 表格区);新增/编辑弹窗 + 查看弹窗 |
15
+| **国际化** | `breedingStdLocaleMixin`,命名空间 `breedingStd.dic` |
16
+
17
+---
18
+
19
+## 2. 源码与路由
20
+
21
+| 类型 | 路径 |
22
+| --- | --- |
23
+| 页面 | `ruoyi-ui/src/views/breedingStandards/diseaseTreatment/drugIncompatibility/index.vue` |
24
+| API 模块 | `ruoyi-ui/src/api/breedingStandards/drugIncompatibility.js` |
25
+
26
+**菜单配置**:组件路径 `breedingStandards/diseaseTreatment/drugIncompatibility/index`;权限前缀 `drugIncompatibility:standard:`(**无** `publish`、`offline`)。
27
+
28
+---
29
+
30
+## 3. 页面结构
31
+
32
+### 3.1 查询区
33
+
34
+| UI | 绑定/说明 |
35
+| --- | --- |
36
+| 主药名称 | `queryParams.keyword`,**仅** `main_drug_name` 模糊匹配(总方案 **§3.1**) |
37
+| 新增 | 权限 `drugIncompatibility:standard:add` |
38
+
39
+### 3.2 列表区
40
+
41
+| 列 | 字段 | 备注 |
42
+| --- | --- | --- |
43
+| 主药名称 | `mainDrugName` | — |
44
+| 配伍结果 | `compatResult` | 空显示「—」 |
45
+| 配伍药物数 | `companionCount` | 列表聚合字段,非持久化 |
46
+| 知识库同步 | `kbSyncStatus` | `kbSyncStatusText` |
47
+| 创建时间 | `createTime` | `parseTime` |
48
+| 操作 | — | 见 **§5** |
49
+
50
+**分页**:默认 `pageNum=1`、`pageSize=20`。列表行**不含** `companions` 明细。
51
+
52
+### 3.3 新增 / 编辑弹窗
53
+
54
+| 字段 | 控件 | 校验 |
55
+| --- | --- | --- |
56
+| `mainDrugName` | 输入框,`maxlength=20` | 必填 1~20;提交前 **trim**;全表唯一由后端校验 |
57
+| `compatResult` | 输入框,`maxlength=20` | 选填 ≤20;空串省略(后端存 `NULL`) |
58
+| `companions` | 动态行列表 | 至少 1 条;每项 `companionDrugName` 1~20;trim 后互不相同且均不等于主药名 |
59
+
60
+配伍校验器 `validateCompanionsField` 与后端 `DrugIncompatibilityStandardValidation` 规则一致。编辑时由详情接口拉取有序 `companions`;**不**向前端暴露或提交 `kbSyncStatus`、`kbDocId`。
61
+
62
+**编辑条件**:仅 `kbSyncStatus === 0`(总方案 **§3.4**)。已同步点编辑提示 `ruleSyncedNoEdit`,不打开弹窗。
63
+
64
+### 3.4 查看弹窗
65
+
66
+展示主药、配伍药物有序列表、配伍结果 + `kbSyncStatus`、`kbDocId`(便于验收占位 ID)、`createTime`、`updateTime`。
67
+
68
+---
69
+
70
+## 4. 配伍子表编辑(本模块特有)
71
+
72
+- 动态 **增加 / 减少** 配伍药物行;至少保留 1 行。
73
+- 保存时按请求数组顺序提交 `companions`(仅 `companionDrugName`),对应后端子表全量替换(总方案 **§1**、**§3.4**)。
74
+- 主药 `blur` 或配伍名 `input` 时触发 `companions` 字段重校验(主药与配伍互斥规则)。
75
+
76
+---
77
+
78
+## 5. 操作按钮与权限
79
+
80
+本模块**仅有**知识库同步维度(功能需求 **§5** 操作矩阵)。
81
+
82
+| 按钮 | 权限标识 | 显示条件 |
83
+| --- | --- | --- |
84
+| 查看 | `drugIncompatibility:standard:query` | 有权限即显 |
85
+| 同步知识库 | `drugIncompatibility:standard:syncKb` | `kbSyncStatus === 0` |
86
+| 移出知识库 | `drugIncompatibility:standard:removeKb` | `kbSyncStatus === 1` |
87
+| 编辑 | `drugIncompatibility:standard:edit` | `kbSyncStatus === 0` |
88
+| 删除 | `drugIncompatibility:standard:remove` | `kbSyncStatus === 0` |
89
+
90
+`canEdit` / `canDelete` / `canSyncKb` / `canRemoveKb` 使用 `Number(kbSyncStatus)` 比较。已同步记录点编辑/删除时前端提示 `ruleSyncedNoEdit` / `ruleDeleteNeedRemoveKb`(双重守卫,与按钮 `v-if` 一致)。
91
+
92
+---
93
+
94
+## 6. API 模块(总方案 §3)
95
+
96
+文件:`ruoyi-ui/src/api/breedingStandards/drugIncompatibility.js`,Base Path `/drugIncompatibility/standard`。
97
+
98
+| 方法 | HTTP | URI |
99
+| --- | --- | --- |
100
+| `listDrugIncompatibilityStandard` | GET | `/list` |
101
+| `getDrugIncompatibilityStandard` | GET | `/{id}` |
102
+| `addDrugIncompatibilityStandard` | POST | `/` |
103
+| `updateDrugIncompatibilityStandard` | PUT | `/` |
104
+| `delDrugIncompatibilityStandard` | DELETE | `/{ids}` |
105
+| `syncKbDrugIncompatibilityStandard` | POST | `/syncKb/{id}` |
106
+| `removeKbDrugIncompatibilityStandard` | POST | `/removeKb/{id}` |
107
+
108
+**列表查询参数**:`pageNum`、`pageSize`、`keyword`。
109
+
110
+**请求体(新增/修改)**:`mainDrugName`、`compatResult`(可空)、`companions`(≥1 条,每项 `companionDrugName`);修改时含 `id`。
111
+
112
+---
113
+
114
+## 7. 错误与交互约定
115
+
116
+| 场景 | 前端行为 |
117
+| --- | --- |
118
+| 主药名称重复 | 展示后端 `msg`(如「主药名称已存在」) |
119
+| 配伍校验失败 | 表单字段错误(重名、与主药相同、条数不足等) |
120
+| 已同步点编辑 | `msgWarning(ruleSyncedNoEdit)` |
121
+| 已同步点删除 | `msgWarning(ruleDeleteNeedRemoveKb)` |
122
+| 同步 / 移出 / 删除 | `this.$modal.confirm` 二次确认 |
123
+
124
+---
125
+
126
+## 8. 与养殖标准页的差异
127
+
128
+| 项 | 养殖标准 | 药物禁配标准 |
129
+| --- | --- | --- |
130
+| 正文/封面上传 | 有 | **无** |
131
+| 发布/下架 | 有 | **无** |
132
+| 状态机 | 上架 × 知识库 | **仅知识库** |
133
+| 数据结构 | 单表 + 附件 | **主表 + 配伍子表** 一对多 |
134
+| 列表筛选 | 关键词 + `standardType`(资讯类别编码) | **仅**主药名称 `keyword` |
135
+
136
+---
137
+
138
+## 9. 交付与联调清单
139
+
140
+- [x] 菜单路由指向 `breedingStandards/diseaseTreatment/drugIncompatibility/index`
141
+- [x] 无 `publish` / `offline` 按钮与权限
142
+- [x] 配伍动态行与 `companions` 校验
143
+- [ ] 后端 `/drugIncompatibility/standard/**` 与总方案 **§3** 对齐
144
+- [ ] 联调:新增 → 同步 → 移出 → 编辑配伍列表 → 再同步 → 删除
145
+- [ ] 联调:已同步编辑/删除被前端拦截;主药名称唯一性后端校验
146
+
147
+---
148
+
149
+## 10. 文档修订记录
150
+
151
+| 版本 | 日期 | 说明 |
152
+| --- | --- | --- |
153
+| v1.0 | 2026-05-13 | 初稿:双卡片 CRUD、主表+配伍子表、知识库同步/移出 |
154
+| **v1.1** | **2026-06-01** | 对齐总方案/功能需求:**无发布下架**单维知识库状态机;`keyword` 仅主药名称;`Number(kbSyncStatus)` 判断;已同步编辑/删除提示;提交字段 trim;查看弹窗展示 `kbDocId` |

+ 11 - 4
doc/养殖标准体系/设备实施作业标准/设备实施作业标准管理前端技术方案.md

@@ -75,7 +75,7 @@
75
 | 正文附件 | `el-upload` → `/common/upload` | 必填(以 `contentFilePath` 为校验 prop);后缀白名单、≤**30MB**、文件名不含英文逗号 |
75
 | 正文附件 | `el-upload` → `/common/upload` | 必填(以 `contentFilePath` 为校验 prop);后缀白名单、≤**30MB**、文件名不含英文逗号 |
76
 | 封面 | `picture-card` 上传,最多 1 张 | 选填;`jpg/jpeg/png`、≤**10MB** |
76
 | 封面 | `picture-card` 上传,最多 1 张 | 选填;`jpg/jpeg/png`、≤**10MB** |
77
 
77
 
78
-**编辑态附件**:仅当详情返回 `publishStatus === 0` 且 `kbSyncStatus === 0` 时允许替换/删除正文与封面(`canEditUploadRow`);与总方案「仅未发布未同步可改」一致
78
+**编辑态**:仅当详情返回 `publishStatus === 0` 且 `kbSyncStatus === 0` 时允许修改表单字段及替换/删除正文与封面(`canEditFormRow`);与总方案 **§3.4**「仅未发布未同步可改」一致。已同步记录点击编辑时提示 `ruleSyncedNoEdit`,不打开弹窗
79
 
79
 
80
 **提交 Body(小驼峰)**
80
 **提交 Body(小驼峰)**
81
 
81
 
@@ -116,7 +116,7 @@
116
 | 查看 | `equipment:workStandard:query` | 有权限即显 |
116
 | 查看 | `equipment:workStandard:query` | 有权限即显 |
117
 | 同步知识库 | `equipment:workStandard:syncKb` | `publishStatus === 0` 且 `kbSyncStatus === 0` |
117
 | 同步知识库 | `equipment:workStandard:syncKb` | `publishStatus === 0` 且 `kbSyncStatus === 0` |
118
 | 移出知识库 | `equipment:workStandard:removeKb` | `publishStatus === 0` 且 `kbSyncStatus === 1` |
118
 | 移出知识库 | `equipment:workStandard:removeKb` | `publishStatus === 0` 且 `kbSyncStatus === 1` |
119
-| 编辑 | `equipment:workStandard:edit` | `publishStatus === 0` |
119
+| 编辑 | `equipment:workStandard:edit` | `publishStatus === 0` 且 `kbSyncStatus === 0`(与总方案 **§3.4** 一致) |
120
 | 删除 | `equipment:workStandard:remove` | `publishStatus === 0` 且 `kbSyncStatus === 0` |
120
 | 删除 | `equipment:workStandard:remove` | `publishStatus === 0` 且 `kbSyncStatus === 0` |
121
 | 发布 | `equipment:workStandard:publish` | `publishStatus === 0` 且 `kbSyncStatus === 1` |
121
 | 发布 | `equipment:workStandard:publish` | `publishStatus === 0` 且 `kbSyncStatus === 1` |
122
 | 下架 | `equipment:workStandard:offline` | `publishStatus === 1` |
122
 | 下架 | `equipment:workStandard:offline` | `publishStatus === 1` |
@@ -138,7 +138,7 @@ import { listInformationCategoryChildren } from '@/api/category/informationCateg
138
 // listInformationCategoryChildren('001', 3) → data[],项字段 code、name
138
 // listInformationCategoryChildren('001', 3) → data[],项字段 code、name
139
 ```
139
 ```
140
 
140
 
141
-列表/详情展示:`typeLabel(code)` 在 `standardTypeOptions` 中查找 `item.code === code` 后取 `item.name`,找不到则回显编码。
141
+列表/详情展示:`typeLabel(code)` 在 `standardTypeOptions` 中查找 `item.code === code` 后取 `item.name`;找不到时回退 **存量迁移** 映射 `LEGACY_STANDARD_TYPE_LABELS`(`1`~`4` → 国际化 `breedingStd.eqp.type1`~`type4`,对应总方案 **§2.2** 迁移脚本 `1`→`001007` … `4`→`001010`);仍无则回显编码。
142
 
142
 
143
 | 编码(示例) | 界面文案 |
143
 | 编码(示例) | 界面文案 |
144
 | --- | --- |
144
 | --- | --- |
@@ -199,6 +199,9 @@ import { listInformationCategoryChildren } from '@/api/category/informationCateg
199
 | 场景 | 前端行为 |
199
 | 场景 | 前端行为 |
200
 | --- | --- |
200
 | --- | --- |
201
 | 列表/表单接口非 200 | 走全局 `request` 拦截器提示(若依默认) |
201
 | 列表/表单接口非 200 | 走全局 `request` 拦截器提示(若依默认) |
202
+| 标准类型选项加载失败 | `loadStandardTypeOptions` 捕获异常,`msgError(errStdTypeLoad)`,下拉为空 |
203
+| 已同步记录点编辑 | `msgWarning(ruleSyncedNoEdit)`,不请求详情 |
204
+| 已发布记录点编辑 | `msgWarning(rulePublishedNoEdit)` |
202
 | 上传失败 | `msgError`,关闭 loading |
205
 | 上传失败 | `msgError`,关闭 loading |
203
 | 删除 | 单行传 `id` 至 `delEquipmentWorkStandard`(与总方案 `{ids}` 兼容) |
206
 | 删除 | 单行传 `id` 至 `delEquipmentWorkStandard`(与总方案 `{ids}` 兼容) |
204
 
207
 
@@ -208,10 +211,13 @@ import { listInformationCategoryChildren } from '@/api/category/informationCateg
208
 
211
 
209
 ## 9. 交付与联调清单
212
 ## 9. 交付与联调清单
210
 
213
 
211
-- [ ] 菜单路由指向 `breedingStandards/equipmentOperation/index`,按钮权限 SQL 与 **§5** 一致  
214
+- [x] 菜单路由指向 `breedingStandards/equipmentOperation/index`,按钮权限 SQL 与 **§5** 一致  
215
+- [x] 标准类型下拉:`GET /category/informationCategory/children?parentCode=001&categoryType=3`  
212
 - [ ] 后端 `/equipment/workStandard/**` 与总方案 **§3** 对齐,分页字段 `rows` / `total`  
216
 - [ ] 后端 `/equipment/workStandard/**` 与总方案 **§3** 对齐,分页字段 `rows` / `total`  
217
+- [ ] 存量环境执行 `sql/biz_equipment_work_standard_alter_standard_type.sql` 后列表类型展示正常  
213
 - [ ] `/common/upload` 可访问且返回 `url`、`fileName`、`originalFilename`  
218
 - [ ] `/common/upload` 可访问且返回 `url`、`fileName`、`originalFilename`  
214
 - [ ] 联调:新增 → 同步知识库 → 发布 → 下架 → 移出 → 删除(及未发布仅本地删除等路径)  
219
 - [ ] 联调:新增 → 同步知识库 → 发布 → 下架 → 移出 → 删除(及未发布仅本地删除等路径)  
220
+- [ ] 联调:已同步记录编辑被前端拦截;未同步修改成功;已同步修改被后端拒绝(双端一致)
215
 
221
 
216
 ---
222
 ---
217
 
223
 
@@ -220,3 +226,4 @@ import { listInformationCategoryChildren } from '@/api/category/informationCateg
220
 | 版本 | 日期 | 说明 |
226
 | 版本 | 日期 | 说明 |
221
 | --- | --- | --- |
227
 | --- | --- | --- |
222
 | v1.0 | 2026-05-11 | 初稿,与 `equipmentOperation/index.vue`、`equipmentWorkStandard.js` 及总方案 **§2~§3** 对齐 |
228
 | v1.0 | 2026-05-11 | 初稿,与 `equipmentOperation/index.vue`、`equipmentWorkStandard.js` 及总方案 **§2~§3** 对齐 |
229
+| **v1.1** | **2026-06-01** | **标准类型改资讯类别编码**:动态加载 `parentCode=001&categoryType=3`;筛选/表单传 `code`;存量 `1`~`4` 回退展示;编辑/上传仅 **未发布+未同步**;补充类型加载失败与已同步编辑提示 |

+ 39 - 248
doc/养殖标准体系/饲喂标准/饲喂标准管理前端技术方案.md

@@ -1,401 +1,192 @@
1
 # 饲喂标准管理 — 前端技术方案
1
 # 饲喂标准管理 — 前端技术方案
2
 
2
 
3
-
4
-
5
 > 依据:`饲喂标准管理技术方案.md`(同目录,下称**总方案**)。本文描述 **Vue 管理端页面**、**接口封装**、**权限字**、**交互与校验**与总方案 **§2 / §3** 的对应关系;库表、状态机与知识库编排以后端总方案为准。
3
 > 依据:`饲喂标准管理技术方案.md`(同目录,下称**总方案**)。本文描述 **Vue 管理端页面**、**接口封装**、**权限字**、**交互与校验**与总方案 **§2 / §3** 的对应关系;库表、状态机与知识库编排以后端总方案为准。
6
 
4
 
7
-
8
-
9
 ---
5
 ---
10
 
6
 
11
-
12
-
13
 ## 1. 技术架构
7
 ## 1. 技术架构
14
 
8
 
15
-
16
-
17
 | 项 | 说明 |
9
 | 项 | 说明 |
18
-
19
 | --- | --- |
10
 | --- | --- |
20
-
21
 | **工程** | 若依 **RuoYi-Vue** 前端(Vue **2.x** + **Element UI** + **Vue Router** + **Vuex**) |
11
 | **工程** | 若依 **RuoYi-Vue** 前端(Vue **2.x** + **Element UI** + **Vue Router** + **Vuex**) |
22
-
23
 | **页面路径** | `ruoyi-ui/src/views/breedingStandards/feeding/index.vue` |
12
 | **页面路径** | `ruoyi-ui/src/views/breedingStandards/feeding/index.vue` |
24
-
25
 | **组件名** | `FeedingManageStandard` |
13
 | **组件名** | `FeedingManageStandard` |
26
-
27
 | **布局参考** | `ruoyi-ui/src/views/breedingStandards/breedingManage/index.vue`(双 `el-card`:查询区 + 表格区;新增/编辑弹窗 + 查看弹窗) |
14
 | **布局参考** | `ruoyi-ui/src/views/breedingStandards/breedingManage/index.vue`(双 `el-card`:查询区 + 表格区;新增/编辑弹窗 + 查看弹窗) |
28
-
29
 | **HTTP** | `@/utils/request` 封装 Axios,自动拼接 `VUE_APP_BASE_API`、携带 `Authorization` |
15
 | **HTTP** | `@/utils/request` 封装 Axios,自动拼接 `VUE_APP_BASE_API`、携带 `Authorization` |
30
-
31
 | **时间格式化** | 全局 `parseTime`(若依 `utils/ruoyi` 注入) |
16
 | **时间格式化** | 全局 `parseTime`(若依 `utils/ruoyi` 注入) |
32
-
33
 | **分页** | 公共组件 `pagination`,与列表 `TableDataInfo` 的 `total`、`rows` 对齐 |
17
 | **分页** | 公共组件 `pagination`,与列表 `TableDataInfo` 的 `total`、`rows` 对齐 |
34
 
18
 
35
-
36
-
37
-**与总方案关系**:列表/详情/写操作均调用总方案 **§3** 所列 REST;行内操作显隐与 `publish_status`、`kb_sync_status` 合法组合一致(见 **§4**)。
38
-
39
-
19
+**与总方案关系**:列表/详情/写操作均调用总方案 **§3** 所列 REST;行内操作显隐与 `publish_status`、`kb_sync_status` 合法组合一致(总方案 **§2.1** 合法组合)。
40
 
20
 
41
 ---
21
 ---
42
 
22
 
43
-
44
-
45
 ## 2. 源码与路由
23
 ## 2. 源码与路由
46
 
24
 
47
-
48
-
49
 | 类型 | 路径 |
25
 | 类型 | 路径 |
50
-
51
 | --- | --- |
26
 | --- | --- |
52
-
53
 | 页面 | `ruoyi-ui/src/views/breedingStandards/feeding/index.vue` |
27
 | 页面 | `ruoyi-ui/src/views/breedingStandards/feeding/index.vue` |
54
-
55
 | API 模块 | `ruoyi-ui/src/api/breedingStandards/feedingManage.js` |
28
 | API 模块 | `ruoyi-ui/src/api/breedingStandards/feedingManage.js` |
56
 
29
 
57
-
58
-
59
 **菜单(若依后台配置)**
30
 **菜单(若依后台配置)**
60
 
31
 
61
-
62
-
63
 | 配置项 | 建议值 |
32
 | 配置项 | 建议值 |
64
-
65
 | --- | --- |
33
 | --- | --- |
66
-
67
 | 组件路径 | `breedingStandards/feeding/index`(与 `views` 下相对路径一致,无前缀 `@/`) |
34
 | 组件路径 | `breedingStandards/feeding/index`(与 `views` 下相对路径一致,无前缀 `@/`) |
68
-
69
 | 路由名 | 自定,不与现有路由冲突即可 |
35
 | 路由名 | 自定,不与现有路由冲突即可 |
70
-
71
 | 权限标识 | 与 **§5** 表一致,子菜单按钮 SQL 与总方案交付清单对齐 |
36
 | 权限标识 | 与 **§5** 表一致,子菜单按钮 SQL 与总方案交付清单对齐 |
72
 
37
 
73
-
74
-
75
 ---
38
 ---
76
 
39
 
77
-
78
-
79
 ## 3. 页面结构
40
 ## 3. 页面结构
80
 
41
 
81
-
82
-
83
 ### 3.1 查询区(首卡片)
42
 ### 3.1 查询区(首卡片)
84
 
43
 
85
-
86
-
87
 | UI | 绑定/说明 |
44
 | UI | 绑定/说明 |
88
-
89
 | --- | --- |
45
 | --- | --- |
90
-
91
 | 关键词 | `queryParams.keyword`,占位「名称或简介模糊查询」,回车触发搜索 |
46
 | 关键词 | `queryParams.keyword`,占位「名称或简介模糊查询」,回车触发搜索 |
92
-
93
-| 标准类型 | `queryParams.standardType`,下拉可清空;选项见 **§6** |
94
-
95
-| 搜索 | `handleQuery`:`pageNum = 1` 后 `getList` |
96
-
97
-| 重置 | `resetQuery`:清空 `keyword`、`standardType`,`resetForm('queryForm')` 后再查询 |
98
-
99
-| 新增 | `v-hasPermi="['feeding:standard:add']"` → `handleAdd` |
100
-
101
-
47
+| 标准类型 | `queryParams.standardType`,下拉可清空;选项在 `created` 中调用 **§7.1** 接口动态加载 |
48
+| 搜索 / 重置 / 新增 | 与养殖标准页一致;新增权限 `feeding:standard:add` |
102
 
49
 
103
 ### 3.2 列表区(次卡片)
50
 ### 3.2 列表区(次卡片)
104
 
51
 
105
-
106
-
107
 | 列 | 数据来源 | 备注 |
52
 | 列 | 数据来源 | 备注 |
108
-
109
 | --- | --- | --- |
53
 | --- | --- | --- |
110
-
111
 | 标准名称 | `standardName` | `show-overflow-tooltip` |
54
 | 标准名称 | `standardName` | `show-overflow-tooltip` |
112
-
113
-| 标准类型 | `standardType` | `typeLabel`:由 `standardTypeOptions` 按编码映射名称 |
114
-
55
+| 标准类型 | `standardType` | `typeLabel(code)`:由 `standardTypeOptions`(**§6.1**)按编码映射名称 |
115
 | 简介 | `introduction` | — |
56
 | 简介 | `introduction` | — |
116
-
117
 | 正文附件 | `contentFileUrl` / `contentFileName` | `el-link` 新窗口打开 |
57
 | 正文附件 | `contentFileUrl` / `contentFileName` | `el-link` 新窗口打开 |
118
-
119
 | 上架状态 | `publishStatus` | `publishStatusText` |
58
 | 上架状态 | `publishStatus` | `publishStatusText` |
120
-
121
 | 知识库同步 | `kbSyncStatus` | `kbSyncStatusText` |
59
 | 知识库同步 | `kbSyncStatus` | `kbSyncStatusText` |
122
-
123
 | 发布日期 | `publishTime` | `parseTime(..., '{y}-{m}-{d}')`,空为「—」 |
60
 | 发布日期 | `publishTime` | `parseTime(..., '{y}-{m}-{d}')`,空为「—」 |
124
-
125
 | 创建时间 | `createTime` | `parseTime` 完整格式 |
61
 | 创建时间 | `createTime` | `parseTime` 完整格式 |
126
-
127
 | 操作 | 多个 `el-button type="text"` | 权限 + 行状态双条件,见 **§5** |
62
 | 操作 | 多个 `el-button type="text"` | 权限 + 行状态双条件,见 **§5** |
128
 
63
 
129
-
130
-
131
-**分页**:`pageNum`、`pageSize` 默认 **1 / 20**,与总方案 **§3.1** 一致;`v-show="total > 0"`。
132
-
133
-
64
+**分页**:`pageNum`、`pageSize` 默认 **1 / 20**,与总方案 **§3.1** 一致。
134
 
65
 
135
 ### 3.3 新增 / 编辑弹窗
66
 ### 3.3 新增 / 编辑弹窗
136
 
67
 
137
-
138
-
139
 | 字段 | 表单控件 | 校验(前端) |
68
 | 字段 | 表单控件 | 校验(前端) |
140
-
141
 | --- | --- | --- |
69
 | --- | --- | --- |
142
-
143
-| `standardName` | 输入框,`maxlength=20`,字数统计 | 必填;长度 **1~20**(与总方案校验摘要一致) |
144
-
145
-| `standardType` | 下拉 | 必填 |
146
-
70
+| `standardName` | 输入框,`maxlength=20` | 必填;长度 **1~20** |
71
+| `standardType` | 下拉 | 必填;选项来自 `listInformationCategoryChildren('001', 2)`,`value`=`code`,`label`=`name` |
147
 | `introduction` | 多行文本,`maxlength=50` | 选填;最多 **50** 字 |
72
 | `introduction` | 多行文本,`maxlength=50` | 选填;最多 **50** 字 |
148
-
149
-| 正文附件 | `el-upload` → `/common/upload` | 必填(以 `contentFilePath` 为校验 prop);后缀白名单、≤**30MB**、文件名不含英文逗号 |
150
-
73
+| 正文附件 | `el-upload` → `/common/upload` | 必填;后缀白名单、≤**30MB**、文件名不含英文逗号 |
151
 | 封面 | `picture-card` 上传,最多 1 张 | 选填;`jpg/jpeg/png`、≤**10MB** |
74
 | 封面 | `picture-card` 上传,最多 1 张 | 选填;`jpg/jpeg/png`、≤**10MB** |
152
 
75
 
76
+**编辑态**:仅当详情返回 `publishStatus === 0` 且 `kbSyncStatus === 0` 时允许修改表单字段及替换/删除正文与封面(`canEditFormRow`);与总方案 **§3.4** 一致。已同步记录点击编辑时提示 `ruleSyncedNoEdit`,不打开弹窗。
153
 
77
 
154
-
155
-**编辑态附件**:仅当详情返回 `publishStatus === 0` 且 `kbSyncStatus === 0` 时允许替换/删除正文与封面(`canEditUploadRow`);与总方案「仅未发布未同步可改」一致。
156
-
157
-
158
-
159
-**提交 Body(小驼峰)**
160
-
161
-
162
-
163
-| 键 | 说明 |
164
-
165
-| --- | --- |
166
-
167
-| `standardName` / `standardType` / `introduction` | 与总方案 **§3.3 / §3.4** 一致;`introduction` 可省略或 `undefined` |
168
-
169
-| `contentFileUrl` / `contentFilePath` / `contentFileName` | 上传成功回写 |
170
-
171
-| `coverFileUrl` / `coverFilePath` | 可选 |
172
-
173
-| `id` | 仅修改时携带 |
174
-
175
-
78
+弹窗标题:`[新增]饲喂标准` / `[编辑]饲喂标准`。
176
 
79
 
177
 ### 3.4 查看弹窗
80
 ### 3.4 查看弹窗
178
 
81
 
179
-
180
-
181
-调 `GET /feeding/standard/{id}` 拉全量展示:标准名称、类型、简介、正文链接、封面(`image-preview`)、上架状态、知识库同步、发布时间、下架时间。
182
-
183
-
82
+调 `GET /feeding/standard/{id}` 拉全量展示:标准名称、类型、简介、正文链接、封面、上架状态、知识库同步、发布时间、下架时间。
184
 
83
 
185
 ---
84
 ---
186
 
85
 
187
-
188
-
189
 ## 4. 上传与鉴权
86
 ## 4. 上传与鉴权
190
 
87
 
191
-
192
-
193
-| 项 | 说明 |
194
-
195
-| --- | --- |
196
-
197
-| 上传地址 | `VUE_APP_BASE_API + '/common/upload'` |
198
-
199
-| 请求头 | `Authorization: Bearer <token>`(`@/utils/auth` `getToken`) |
200
-
201
-| 成功回调 | `code === 200` 时取 `url`、`fileName`、`originalFilename`(正文名优先 `originalFilename`,否则取本地 `file.name`) |
202
-
203
-| 失败 | `on-error` 关闭 loading 并 `msgError` |
204
-
205
-
206
-
207
-物理文件删除、知识库联动由**后端**在修改/删除等接口内完成(总方案 **§4**),前端不直接调用知识库 HTTP。
208
-
209
-
88
+与养殖标准模块一致:`VUE_APP_BASE_API + '/common/upload'`,Header `Authorization: Bearer <token>`;成功取 `url`、`fileName`、`originalFilename`。正文后缀:`pdf`、`md`、`doc`、`docx`、`xls`、`xlsx`、`ppt`、`pptx`。
210
 
89
 
211
 ---
90
 ---
212
 
91
 
213
-
214
-
215
 ## 5. 操作按钮与权限
92
 ## 5. 操作按钮与权限
216
 
93
 
217
-
218
-
219
 权限字与总方案 **§3** 一致;按钮同时受 **`v-hasPermi`** 与 **行状态方法** 控制。
94
 权限字与总方案 **§3** 一致;按钮同时受 **`v-hasPermi`** 与 **行状态方法** 控制。
220
 
95
 
221
-
222
-
223
 | 按钮 | 权限标识 | 显示条件(与行数据) |
96
 | 按钮 | 权限标识 | 显示条件(与行数据) |
224
-
225
 | --- | --- | --- |
97
 | --- | --- | --- |
226
-
227
-| 查看 | `feeding:standard:query` | 始终(有权限即显) |
228
-
98
+| 查看 | `feeding:standard:query` | 有权限即显 |
229
 | 同步知识库 | `feeding:standard:syncKb` | `publishStatus === 0` 且 `kbSyncStatus === 0` |
99
 | 同步知识库 | `feeding:standard:syncKb` | `publishStatus === 0` 且 `kbSyncStatus === 0` |
230
-
231
 | 移出知识库 | `feeding:standard:removeKb` | `publishStatus === 0` 且 `kbSyncStatus === 1` |
100
 | 移出知识库 | `feeding:standard:removeKb` | `publishStatus === 0` 且 `kbSyncStatus === 1` |
232
-
233
-| 编辑 | `feeding:standard:edit` | `publishStatus === 0` |
234
-
101
+| 编辑 | `feeding:standard:edit` | `publishStatus === 0` 且 `kbSyncStatus === 0`(与总方案 **§3.4** 一致) |
235
 | 删除 | `feeding:standard:remove` | `publishStatus === 0` 且 `kbSyncStatus === 0` |
102
 | 删除 | `feeding:standard:remove` | `publishStatus === 0` 且 `kbSyncStatus === 0` |
236
-
237
 | 发布 | `feeding:standard:publish` | `publishStatus === 0` 且 `kbSyncStatus === 1` |
103
 | 发布 | `feeding:standard:publish` | `publishStatus === 0` 且 `kbSyncStatus === 1` |
238
-
239
 | 下架 | `feeding:standard:offline` | `publishStatus === 1` |
104
 | 下架 | `feeding:standard:offline` | `publishStatus === 1` |
240
 
105
 
241
-
242
-
243
-**说明**:`publishStatus === 1` 且 `kbSyncStatus === 0` 为非法组合,前端不单独分支;若后端脏数据,以接口报错为准。
244
-
245
-
246
-
247
-**二次确认文案**:同步、移出、删除、发布、下架均使用 `this.$modal.confirm`,下架说明与总方案「下架 vs 移出」语义一致。
248
-
249
-
106
+下架完成后业务稳态为 **未发布 + 已同步**,可再次发布;改内容须先移出。
250
 
107
 
251
 ---
108
 ---
252
 
109
 
253
-
254
-
255
 ## 6. 枚举与展示映射
110
 ## 6. 枚举与展示映射
256
 
111
 
257
-
258
-
259
 ### 6.1 `standardType`(标准类型)
112
 ### 6.1 `standardType`(标准类型)
260
 
113
 
261
 页面维护 `standardTypeOptions: []`,`created` 调用 `loadStandardTypeOptions()`:
114
 页面维护 `standardTypeOptions: []`,`created` 调用 `loadStandardTypeOptions()`:
262
 
115
 
263
 ```javascript
116
 ```javascript
264
 import { listInformationCategoryChildren } from '@/api/category/informationCategory'
117
 import { listInformationCategoryChildren } from '@/api/category/informationCategory'
265
-// listInformationCategoryChildren('001', '2') → data[],项字段 code、name
118
+// listInformationCategoryChildren('001', 2) → data[],项字段 code、name
266
 ```
119
 ```
267
 
120
 
121
+列表/详情展示:`typeLabel(code)` 在 `standardTypeOptions` 中查找后取 `name`;找不到时回退 **存量迁移** 映射 `LEGACY_STANDARD_TYPE_LABELS`(`1`~`2` → 国际化 `breedingStd.feed.type1`~`type2`,对应总方案 **§2.2** 迁移脚本 `1`→`001005`,`2`→`001006`);仍无则回显编码。
122
+
268
 | 编码(示例) | 界面文案 |
123
 | 编码(示例) | 界面文案 |
269
 | --- | --- |
124
 | --- | --- |
270
 | `001005` | 饲料配方 |
125
 | `001005` | 饲料配方 |
271
 | `001006` | 牦牛投喂 |
126
 | `001006` | 牦牛投喂 |
272
 
127
 
128
+### 6.2 `publishStatus` / `kbSyncStatus`
273
 
129
 
274
-
275
-### 6.2 `publishStatus`(上架状态)
276
-
277
-
278
-
279
-| 值 | 界面文案 |
280
-
281
-| --- | --- |
282
-
283
-| `0` | 未发布 |
284
-
285
-| `1` | 已发布 |
286
-
287
-
288
-
289
-### 6.3 `kbSyncStatus`(知识库同步)
290
-
291
-
292
-
293
-| 值 | 界面文案 |
294
-
295
-| --- | --- |
296
-
297
-| `0` | 未同步 |
298
-
299
-| `1` | 已同步 |
300
-
301
-
130
+与养殖标准模块一致:`0` 未发布/未同步,`1` 已发布/已同步。
302
 
131
 
303
 ---
132
 ---
304
 
133
 
305
-
306
-
307
 ## 7. API 模块与后端 URI 对应
134
 ## 7. API 模块与后端 URI 对应
308
 
135
 
136
+### 7.1 标准类型选项(资讯类别)
309
 
137
 
138
+文件:`ruoyi-ui/src/api/category/informationCategory.js`
310
 
139
 
311
-文件:`ruoyi-ui/src/api/breedingStandards/feedingManage.js`。请求/响应字段采用 **小驼峰**(与若依 JSON 惯例及总方案示例一致)。
140
+| 方法 | HTTP | URI | 参数 |
141
+| --- | --- | --- | --- |
142
+| `listInformationCategoryChildren` | GET | `/category/informationCategory/children` | `parentCode=001`,`categoryType=2` |
312
 
143
 
144
+### 7.2 饲喂标准 CRUD
313
 
145
 
146
+文件:`ruoyi-ui/src/api/breedingStandards/feedingManage.js`。请求/响应字段采用 **小驼峰**。
314
 
147
 
315
 | 方法(导出) | HTTP | URI |
148
 | 方法(导出) | HTTP | URI |
316
-
317
 | --- | --- | --- |
149
 | --- | --- | --- |
318
-
319
 | `listFeedingStandard` | GET | `/feeding/standard/list` |
150
 | `listFeedingStandard` | GET | `/feeding/standard/list` |
320
-
321
 | `getFeedingStandard` | GET | `/feeding/standard/{id}` |
151
 | `getFeedingStandard` | GET | `/feeding/standard/{id}` |
322
-
323
 | `addFeedingStandard` | POST | `/feeding/standard` |
152
 | `addFeedingStandard` | POST | `/feeding/standard` |
324
-
325
 | `updateFeedingStandard` | PUT | `/feeding/standard` |
153
 | `updateFeedingStandard` | PUT | `/feeding/standard` |
326
-
327
 | `delFeedingStandard` | DELETE | `/feeding/standard/{ids}` |
154
 | `delFeedingStandard` | DELETE | `/feeding/standard/{ids}` |
328
-
329
 | `syncKbFeedingStandard` | POST | `/feeding/standard/syncKb/{id}` |
155
 | `syncKbFeedingStandard` | POST | `/feeding/standard/syncKb/{id}` |
330
-
331
 | `removeKbFeedingStandard` | POST | `/feeding/standard/removeKb/{id}` |
156
 | `removeKbFeedingStandard` | POST | `/feeding/standard/removeKb/{id}` |
332
-
333
 | `publishFeedingStandard` | POST | `/feeding/standard/publish/{id}` |
157
 | `publishFeedingStandard` | POST | `/feeding/standard/publish/{id}` |
334
-
335
 | `offlineFeedingStandard` | POST | `/feeding/standard/offline/{id}` |
158
 | `offlineFeedingStandard` | POST | `/feeding/standard/offline/{id}` |
336
 
159
 
337
-
338
-
339
-**列表查询参数**:`pageNum`、`pageSize`、`keyword`、`standardType`(与页面 `queryParams` 一致)。
340
-
341
-**标准类型选项**:`ruoyi-ui/src/api/category/informationCategory.js` — `listInformationCategoryChildren('001', '2')`。
342
-
343
-
160
+**列表查询参数**:`pageNum`、`pageSize`、`keyword`、`standardType`。
344
 
161
 
345
 ---
162
 ---
346
 
163
 
347
-
348
-
349
 ## 8. 错误与交互约定
164
 ## 8. 错误与交互约定
350
 
165
 
351
-
352
-
353
 | 场景 | 前端行为 |
166
 | 场景 | 前端行为 |
354
-
355
 | --- | --- |
167
 | --- | --- |
356
-
357
-| 列表/表单接口非 200 | 走全局 `request` 拦截器提示(若依默认) |
358
-
168
+| 列表/表单接口非 200 | 走全局 `request` 拦截器提示 |
169
+| 标准类型选项加载失败 | `msgError(errStdTypeLoad)`,下拉为空 |
170
+| 已同步记录点编辑 | `msgWarning(ruleSyncedNoEdit)`,不请求详情 |
171
+| 已发布记录点编辑 | `msgWarning(rulePublishedNoEdit)` |
359
 | 上传失败 | `msgError`,关闭 loading |
172
 | 上传失败 | `msgError`,关闭 loading |
360
 
173
 
361
-| 删除 | 单行传 `id` 至 `delFeedingStandard`(与总方案 `{ids}` 兼容) |
362
-
363
-
364
-
365
-不在前端重复实现知识库重试;失败以后端 `msg` 为准。
366
-
367
-
368
-
369
 ---
174
 ---
370
 
175
 
371
-
372
-
373
 ## 9. 交付与联调清单
176
 ## 9. 交付与联调清单
374
 
177
 
375
-
376
-
377
-- [ ] 菜单路由指向 `breedingStandards/feeding/index`,按钮权限 SQL 与 **§5** 一致  
378
-
379
-- [ ] 后端 `/feeding/standard/**` 与总方案 **§3** 对齐,分页字段 `rows` / `total`  
380
-
381
-- [ ] `/common/upload` 可访问且返回 `url`、`fileName`、`originalFilename`  
382
-
383
-- [ ] 联调:新增 → 同步知识库 → 发布 → 下架 → 移出 → 删除(及未发布仅本地删除)  
384
-
385
-
178
+- [x] 菜单路由指向 `breedingStandards/feeding/index`,按钮权限与 **§5** 一致  
179
+- [x] 标准类型下拉:`GET /category/informationCategory/children?parentCode=001&categoryType=2`  
180
+- [ ] 后端 `/feeding/standard/**` 与总方案 **§3** 对齐  
181
+- [ ] 存量环境执行 `sql/biz_feeding_standard_alter_standard_type.sql` 后列表类型展示正常  
182
+- [ ] 联调:新增 → 同步 → 发布 → 下架 → 移出 → 删除  
183
+- [ ] 联调:已同步记录编辑被前端拦截;未同步修改成功
386
 
184
 
387
 ---
185
 ---
388
 
186
 
389
-
390
-
391
 ## 10. 文档修订记录
187
 ## 10. 文档修订记录
392
 
188
 
393
-
394
-
395
 | 版本 | 日期 | 说明 |
189
 | 版本 | 日期 | 说明 |
396
-
397
 | --- | --- | --- |
190
 | --- | --- | --- |
398
-
399
 | v1.0 | 2026-05-11 | 初稿,与 `feeding/index.vue`、`feedingManage.js` 及总方案 **§2~§3** 对齐 |
191
 | v1.0 | 2026-05-11 | 初稿,与 `feeding/index.vue`、`feedingManage.js` 及总方案 **§2~§3** 对齐 |
400
-
401
-
192
+| **v1.1** | **2026-06-01** | **标准类型改资讯类别编码**:动态加载 `parentCode=001&categoryType=2`;筛选/表单传 `code`;存量 `1`~`2` 回退展示;编辑/上传仅 **未发布+未同步**;补充类型加载失败与已同步编辑提示 |

+ 6 - 72
ruoyi-ui/doc/药物禁配标准/药物禁配标准管理前端技术方案.md

@@ -1,76 +1,10 @@
1
 # 药物禁配标准管理 — 前端技术方案
1
 # 药物禁配标准管理 — 前端技术方案
2
 
2
 
3
-> 依据:`doc/药物禁配标准/药物禁配标准管理技术方案.md`、`ruoyi-ui/doc/药物禁配标准.md`;列表与卡片布局对齐 `ruoyi-ui/src/views/breedingStandards/breedingManage/index.vue`(本模块无附件上传、无发布/下架);请求与表单字段统一 **小驼峰**,与后端 `BizDrugIncompatibilityStandard` / `BizDrugIncompatibilityCompanion` 及 Jackson 序列化一致。
3
+> **主文档**(与总方案同目录维护):`doc/养殖标准体系/药物禁配标准/药物禁配标准管理前端技术方案.md`  
4
+> 依据:`doc/养殖标准体系/药物禁配标准/药物禁配标准管理技术方案.md`。
4
 
5
 
5
----
6
+页面路径:`ruoyi-ui/src/views/breedingStandards/diseaseTreatment/drugIncompatibility/index.vue`  
7
+API:`ruoyi-ui/src/api/breedingStandards/drugIncompatibility.js`  
8
+国际化命名空间:`breedingStd.dic`
6
 
9
 
7
-## 1. 页面与路由
8
-
9
-| 项 | 说明 |
10
-| --- | --- |
11
-| **Vue 路径** | `ruoyi-ui/src/views/breedingStandards/diseaseTreatment/drugIncompatibility/index.vue` |
12
-| **组件名** | `DrugIncompatibilityStandard` |
13
-| **菜单配置** | 若依「菜单管理」组件路径:`breedingStandards/diseaseTreatment/drugIncompatibility/index` |
14
-| **权限前缀** | `drugIncompatibility:standard:`(**无** `publish`、`offline`) |
15
-
16
----
17
-
18
-## 2. API 模块
19
-
20
-| 项 | 说明 |
21
-| --- | --- |
22
-| **文件** | `ruoyi-ui/src/api/breedingStandards/drugIncompatibility.js` |
23
-| **Base Path** | `/drugIncompatibility/standard` |
24
-
25
-封装方法:`listDrugIncompatibilityStandard`、`getDrugIncompatibilityStandard`、`addDrugIncompatibilityStandard`、`updateDrugIncompatibilityStandard`、`delDrugIncompatibilityStandard`、`syncKbDrugIncompatibilityStandard`、`removeKbDrugIncompatibilityStandard`。
26
-
27
----
28
-
29
-## 3. 列表与查询
30
-
31
-- **分页**:`pageNum`、`pageSize`(默认 20)。
32
-- **筛选**:`keyword`(**仅**主药名称 `mainDrugName` 模糊,与后端查询对象 `keyword` 一致)。
33
-- **表格列**:主药名称、配伍结果(空显示「—」)、配伍药物数(`companionCount`)、知识库同步、创建时间、操作列。
34
-- **列表行**:不含 `companions` 明细;详情接口返回主表 + 有序 `companions`。
35
-
36
----
37
-
38
-## 4. 表单与请求体
39
-
40
-| 字段 | 说明 |
41
-| --- | --- |
42
-| `mainDrugName` | 必填,1~20 字;**全表唯一**(保存失败展示「主药名称已存在」) |
43
-| `compatResult` | 选填,≤20 字;空串提交时省略(由后端存 `NULL`) |
44
-| `companions` | 至少 1 条;每项仅提交 `companionDrugName`(1~20 字);顺序即展示/落库顺序 |
45
-
46
-前端对配伍列表做与 `DrugIncompatibilityStandardValidation` 一致的校验:非空、长度、与主药去重后不相等、配伍名互不重复(trim 后)。
47
-
48
-编辑时由详情接口拉取 `companions` 填入动态行;**不**向前端暴露或提交 `kbSyncStatus`、`kbDocId`(由服务端维护)。
49
-
50
----
51
-
52
-## 5. 操作按钮与知识库状态
53
-
54
-| 按钮 | 显示条件 | 权限标识 |
55
-| --- | --- | --- |
56
-| 查看 | 有 `query` 权限 | `drugIncompatibility:standard:query` |
57
-| 同步知识库 | `kbSyncStatus === 0` | `drugIncompatibility:standard:syncKb` |
58
-| 移出知识库 | `kbSyncStatus === 1` | `drugIncompatibility:standard:removeKb` |
59
-| 编辑 | `kbSyncStatus === 0` | `drugIncompatibility:standard:edit` |
60
-| 删除 | `kbSyncStatus === 0` | `drugIncompatibility:standard:remove` |
61
-
62
----
63
-
64
-## 6. 国际化
65
-
66
-文案命名空间:`breedingStd.dic`(`stdNs: "dic"`,`breedingStdLocaleMixin` 的 `stdT`)。
67
-
68
-语言文件:`ruoyi-ui/src/lang/zh/breedingStd.js`、`ruoyi-ui/src/lang/bo/breedingStd.js` 中新增 `dic` 节点。
69
-
70
----
71
-
72
-## 7. 与休药期标准页的共性
73
-
74
-同属「疾病诊疗」子目录下的标准 CRUD 页:双卡片、表格 + 分页、`v-hasPermi`、知识库同步/移出确认弹窗、无发布/下架。
75
-
76
-本模块特有:**主表 + 配伍子表** 一对多编辑(动态增删行、自定义 `companions` 校验器)。
10
+**v1.1(2026-06-01)**:无发布/下架,仅知识库单维状态机;主药 `keyword` 检索;配伍子表动态编辑;已同步编辑/删除前端拦截(`ruleSyncedNoEdit` / `ruleDeleteNeedRemoveKb`)。详见主文档 **§5**、**§7**、**§10**。

+ 9 - 0
ruoyi-ui/src/api/category/informationCategory.js

@@ -1,5 +1,14 @@
1
 import request from "@/utils/request"
1
 import request from "@/utils/request"
2
 
2
 
3
+/** 资讯类别 — 树形列表(可选 categoryType 过滤) */
4
+export function listInformationCategoryTree(categoryType) {
5
+  return request({
6
+    url: "/category/informationCategory/tree",
7
+    method: "get",
8
+    params: categoryType != null ? { categoryType } : {}
9
+  })
10
+}
11
+
3
 /** 资讯类别 — 按上级编码、类型查询直接下级(编号、名称) */
12
 /** 资讯类别 — 按上级编码、类型查询直接下级(编号、名称) */
4
 export function listInformationCategoryChildren(parentCode, categoryType) {
13
 export function listInformationCategoryChildren(parentCode, categoryType) {
5
   return request({
14
   return request({

+ 19 - 5
ruoyi-ui/src/lang/bo/breedingStd.js

@@ -104,7 +104,9 @@ export default {
104
     confirmOffline:
104
     confirmOffline:
105
       "འཚོ་བཅུད་ཚད་གཞི་འོག་ཏུ་བཀག་བྱེད་དམ།ཕྱི་རོལ་མངོན་འཆར་མཚམས་འཇོག་རྗེས་ཁྱབ་བསྒྲགས་མེད་དུ་ལོག་ཅིང་ཤེས་མཛོད་ནང་དཔེ་ཆ་སོར་འཇོག་བྱེད།",
105
       "འཚོ་བཅུད་ཚད་གཞི་འོག་ཏུ་བཀག་བྱེད་དམ།ཕྱི་རོལ་མངོན་འཆར་མཚམས་འཇོག་རྗེས་ཁྱབ་བསྒྲགས་མེད་དུ་ལོག་ཅིང་ཤེས་མཛོད་ནང་དཔེ་ཆ་སོར་འཇོག་བྱེད།",
106
     rulePublishedNoEdit: "ཁྱབ་བསྒྲགས་རྗེས་བཟོ་བཅོས་མི་ཆོག།སྔོན་དུ་འོག་ཏུ་བཀག",
106
     rulePublishedNoEdit: "ཁྱབ་བསྒྲགས་རྗེས་བཟོ་བཅོས་མི་ཆོག།སྔོན་དུ་འོག་ཏུ་བཀག",
107
-    ruleDeleteNeedRemoveKb: "ཤེས་མཛོད་དུ་བསྡུས་ཟིན་པ་ན་སྔོན་དུ་ཤེས་མཛོད་ནས་ཕྱིར་འདོན་བྱོས"
107
+    ruleSyncedNoEdit: "ཤེས་མཛོད་དུ་མཉམ་འགྲོས་ཟིན་པའི་ཐོ་གཞུང་བཟོ་བཅོས་མི་ཆོགས།སྔོན་ལ་ཤེས་མཛོད་ནས་ཕྱིར་འདོན་དགོས",
108
+    ruleDeleteNeedRemoveKb: "ཤེས་མཛོད་དུ་བསྡུས་ཟིན་པ་ན་སྔོན་དུ་ཤེས་མཛོད་ནས་ཕྱིར་འདོན་བྱོས",
109
+    errStdTypeLoad: "ཚད་གཞིའི་རིགས་འཇུག་མ་ཐུབ།ཤོག་ངོས་གསར་འདོན་བྱོས།"
108
   },
110
   },
109
   feed: {
111
   feed: {
110
     queryKeyword: "གནད་ཚིག",
112
     queryKeyword: "གནད་ཚིག",
@@ -121,7 +123,9 @@ export default {
121
     confirmOffline:
123
     confirmOffline:
122
       "འཚོ་བསྐྱལ་ཚད་གཞི་འོག་ཏུ་བཀག་བྱེད་དམ།ཕྱི་རོལ་མངོན་འཆར་མཚམས་འཇོག་རྗེས་ཁྱབ་བསྒྲགས་མེད་དུ་ལོག་ཅིང་ཤེས་མཛོད་ནང་དཔེ་ཆ་སོར་འཇོག་བྱེད།",
124
       "འཚོ་བསྐྱལ་ཚད་གཞི་འོག་ཏུ་བཀག་བྱེད་དམ།ཕྱི་རོལ་མངོན་འཆར་མཚམས་འཇོག་རྗེས་ཁྱབ་བསྒྲགས་མེད་དུ་ལོག་ཅིང་ཤེས་མཛོད་ནང་དཔེ་ཆ་སོར་འཇོག་བྱེད།",
123
     rulePublishedNoEdit: "ཁྱབ་བསྒྲགས་ཟིན་པའི་ཐོ་གཞུང་བཟོ་བཅོས་མི་ཆོགས།སྔོན་ལ་འོག་ཏུ་བཀག",
125
     rulePublishedNoEdit: "ཁྱབ་བསྒྲགས་ཟིན་པའི་ཐོ་གཞུང་བཟོ་བཅོས་མི་ཆོགས།སྔོན་ལ་འོག་ཏུ་བཀག",
124
-    ruleDeleteNeedRemoveKb: "ཤེས་མཛོད་དུ་མཉམ་འགྲོས་ཟིན་པའི་ཐོ་གཞུང་སྔོན་ལ་ཤེས་མཛོད་ནས་ཕྱིར་འདོན་རྗེས་སུབ་དགོས"
126
+    ruleSyncedNoEdit: "ཤེས་མཛོད་དུ་མཉམ་འགྲོས་ཟིན་པའི་ཐོ་གཞུང་བཟོ་བཅོས་མི་ཆོགས།སྔོན་ལ་ཤེས་མཛོད་ནས་ཕྱིར་འདོན་དགོས",
127
+    ruleDeleteNeedRemoveKb: "ཤེས་མཛོད་དུ་མཉམ་འགྲོས་ཟིན་པའི་ཐོ་གཞུང་སྔོན་ལ་ཤེས་མཛོད་ནས་ཕྱིར་འདོན་རྗེས་སུབ་དགོས",
128
+    errStdTypeLoad: "ཚད་གཞིའི་རིགས་འཇུག་མ་ཐུབ།ཤོག་ངོས་གསར་འདོན་བྱོས།"
125
   },
129
   },
126
   eqp: {
130
   eqp: {
127
     queryKeyword: "གནད་ཚིག",
131
     queryKeyword: "གནད་ཚིག",
@@ -140,7 +144,9 @@ export default {
140
     confirmOffline:
144
     confirmOffline:
141
       "སྒྲིག་ཆས་ལག་ལེན་ཚད་གཞི་འོག་ཏུ་བཀག་བྱེད་དམ།ཕྱི་རོལ་མངོན་འཆར་མཚམས་འཇོག་རྗེས་ཁྱབ་བསྒྲགས་མེད་དུ་ལོག་ཅིང་ཤེས་མཛོད་ནང་དཔེ་ཆ་སོར་འཇོག་བྱེད།",
145
       "སྒྲིག་ཆས་ལག་ལེན་ཚད་གཞི་འོག་ཏུ་བཀག་བྱེད་དམ།ཕྱི་རོལ་མངོན་འཆར་མཚམས་འཇོག་རྗེས་ཁྱབ་བསྒྲགས་མེད་དུ་ལོག་ཅིང་ཤེས་མཛོད་ནང་དཔེ་ཆ་སོར་འཇོག་བྱེད།",
142
     rulePublishedNoEdit: "ཁྱབ་བསྒྲགས་ཟིན་པའི་ཐོ་གཞུང་བཟོ་བཅོས་མི་ཆོགས།སྔོན་ལ་འོག་ཏུ་བཀག",
146
     rulePublishedNoEdit: "ཁྱབ་བསྒྲགས་ཟིན་པའི་ཐོ་གཞུང་བཟོ་བཅོས་མི་ཆོགས།སྔོན་ལ་འོག་ཏུ་བཀག",
143
-    ruleDeleteNeedRemoveKb: "ཤེས་མཛོད་དུ་མཉམ་འགྲོས་ཟིན་པའི་ཐོ་གཞུང་སྔོན་ལ་ཤེས་མཛོད་ནས་ཕྱིར་འདོན་རྗེས་སུབ་དགོས"
147
+    ruleSyncedNoEdit: "ཤེས་མཛོད་དུ་མཉམ་འགྲོས་ཟིན་པའི་ཐོ་གཞུང་བཟོ་བཅོས་མི་ཆོགས།སྔོན་ལ་ཤེས་མཛོད་ནས་ཕྱིར་འདོན་དགོས",
148
+    ruleDeleteNeedRemoveKb: "ཤེས་མཛོད་དུ་མཉམ་འགྲོས་ཟིན་པའི་ཐོ་གཞུང་སྔོན་ལ་ཤེས་མཛོད་ནས་ཕྱིར་འདོན་རྗེས་སུབ་དགོས",
149
+    errStdTypeLoad: "ཚད་གཞིའི་རིགས་འཇུག་མ་ཐུབ།ཤོག་ངོས་གསར་འདོན་བྱོས།"
144
   },
150
   },
145
   growth: {
151
   growth: {
146
     queryKeyword: "གནད་ཚིག",
152
     queryKeyword: "གནད་ཚིག",
@@ -157,7 +163,9 @@ export default {
157
     confirmOffline:
163
     confirmOffline:
158
       "དེ་འོག་ཏུ་བཀག་བྱེད་དམ།ཕྱི་རོལ་མངོན་འཆར་མཚམས་འཇོག་རྗེས་ཁྱབ་བསྒྲགས་མེད་དུ་ལོག་ཅིང་ཤེས་མཛོད་ནང་དཔེ་ཆ་སོར་འཇོག་བྱེད།",
164
       "དེ་འོག་ཏུ་བཀག་བྱེད་དམ།ཕྱི་རོལ་མངོན་འཆར་མཚམས་འཇོག་རྗེས་ཁྱབ་བསྒྲགས་མེད་དུ་ལོག་ཅིང་ཤེས་མཛོད་ནང་དཔེ་ཆ་སོར་འཇོག་བྱེད།",
159
     rulePublishedNoEdit: "ཁྱབ་བསྒྲགས་ཟིན་པའི་ཐོ་གཞུང་བཟོ་བཅོས་མི་ཆོགས།སྔོན་ལ་འོག་ཏུ་བཀག",
165
     rulePublishedNoEdit: "ཁྱབ་བསྒྲགས་ཟིན་པའི་ཐོ་གཞུང་བཟོ་བཅོས་མི་ཆོགས།སྔོན་ལ་འོག་ཏུ་བཀག",
160
-    ruleDeleteNeedRemoveKb: "ཤེས་མཛོད་དུ་མཉམ་འགྲོས་ཟིན་པའི་ཐོ་གཞུང་སྔོན་ལ་ཤེས་མཛོད་ནས་ཕྱིར་འདོན་རྗེས་སུབ་དགོས"
166
+    ruleSyncedNoEdit: "ཤེས་མཛོད་དུ་མཉམ་འགྲོས་ཟིན་པའི་ཐོ་གཞུང་བཟོ་བཅོས་མི་ཆོགས།སྔོན་ལ་ཤེས་མཛོད་ནས་ཕྱིར་འདོན་དགོས",
167
+    ruleDeleteNeedRemoveKb: "ཤེས་མཛོད་དུ་མཉམ་འགྲོས་ཟིན་པའི་ཐོ་གཞུང་སྔོན་ལ་ཤེས་མཛོད་ནས་ཕྱིར་འདོན་རྗེས་སུབ་དགོས",
168
+    errStdTypeLoad: "ཚད་གཞིའི་རིགས་འཇུག་མ་ཐུབ།ཤོག་ངོས་གསར་འདོན་བྱོས།"
161
   },
169
   },
162
   ep: {
170
   ep: {
163
     queryKeyword: "གནད་ཚིག",
171
     queryKeyword: "གནད་ཚིག",
@@ -173,7 +181,9 @@ export default {
173
     confirmOffline:
181
     confirmOffline:
174
       "དེ་འོག་ཏུ་བཀག་བྱེད་དམ།ཕྱི་རོལ་མངོན་འཆར་མཚམས་འཇོག་རྗེས་ཁྱབ་བསྒྲགས་མེད་དུ་ལོག་ཅིང་ཤེས་མཛོད་ནང་དཔེ་ཆ་སོར་འཇོག་བྱེད།",
182
       "དེ་འོག་ཏུ་བཀག་བྱེད་དམ།ཕྱི་རོལ་མངོན་འཆར་མཚམས་འཇོག་རྗེས་ཁྱབ་བསྒྲགས་མེད་དུ་ལོག་ཅིང་ཤེས་མཛོད་ནང་དཔེ་ཆ་སོར་འཇོག་བྱེད།",
175
     rulePublishedNoEdit: "ཁྱབ་བསྒྲགས་ཟིན་པའི་ཐོ་གཞུང་བཟོ་བཅོས་མི་ཆོགས།སྔོན་ལ་འོག་ཏུ་བཀག",
183
     rulePublishedNoEdit: "ཁྱབ་བསྒྲགས་ཟིན་པའི་ཐོ་གཞུང་བཟོ་བཅོས་མི་ཆོགས།སྔོན་ལ་འོག་ཏུ་བཀག",
176
-    ruleDeleteNeedRemoveKb: "ཤེས་མཛོད་དུ་མཉམ་འགྲོས་ཟིན་པའི་ཐོ་གཞུང་སྔོན་ལ་ཤེས་མཛོད་ནས་ཕྱིར་འདོན་རྗེས་སུབ་དགོས"
184
+    ruleSyncedNoEdit: "ཤེས་མཛོད་དུ་མཉམ་འགྲོས་ཟིན་པའི་ཐོ་གཞུང་བཟོ་བཅོས་མི་ཆོགས།སྔོན་ལ་ཤེས་མཛོད་ནས་ཕྱིར་འདོན་དགོས",
185
+    ruleDeleteNeedRemoveKb: "ཤེས་མཛོད་དུ་མཉམ་འགྲོས་ཟིན་པའི་ཐོ་གཞུང་སྔོན་ལ་ཤེས་མཛོད་ནས་ཕྱིར་འདོན་རྗེས་སུབ་དགོས",
186
+    errStdTypeLoad: "ཚད་གཞིའི་རིགས་འཇུག་མ་ཐུབ།ཤོག་ངོས་གསར་འདོན་བྱོས།"
177
   },
187
   },
178
   wp: {
188
   wp: {
179
     drugName: "སྨན་མིང་།",
189
     drugName: "སྨན་མིང་།",
@@ -219,6 +229,8 @@ export default {
219
     confirmSync: "སྨན་འཇོག་ཚད་གཞི་ཤེས་མཛོད་དུ་མཉམ་འགྲོས་བྱེད་དམ།",
229
     confirmSync: "སྨན་འཇོག་ཚད་གཞི་ཤེས་མཛོད་དུ་མཉམ་འགྲོས་བྱེད་དམ།",
220
     confirmRemoveKb: "ཤེས་མཛོད་ནས་ཕྱིར་འདོན་རྗེས་བསྐྱར་དུ་རྩོམ་སྒྲིག་དང་སུབ་ཆོག",
230
     confirmRemoveKb: "ཤེས་མཛོད་ནས་ཕྱིར་འདོན་རྗེས་བསྐྱར་དུ་རྩོམ་སྒྲིག་དང་སུབ་ཆོག",
221
     confirmDelete: "སྨན་འཇོག་ཚད་གཞི་ཨང་གྲངས་{id}སུབ་པ་གཏན་འཁེལ་ཡིན་ནམ།",
231
     confirmDelete: "སྨན་འཇོག་ཚད་གཞི་ཨང་གྲངས་{id}སུབ་པ་གཏན་འཁེལ་ཡིན་ནམ།",
232
+    ruleSyncedNoEdit: "ཤེས་མཛོད་དུ་མཉམ་འགྲོས་ཟིན་པའི་ཐོ་གཞུང་བཟོ་བཅོས་མི་ཆོགས།སྔོན་ལ་ཤེས་མཛོད་ནས་ཕྱིར་འདོན་དགོས",
233
+    ruleDeleteNeedRemoveKb: "ཤེས་མཛོད་དུ་མཉམ་འགྲོས་ཟིན་པའི་ཐོ་གཞུང་སྔོན་ལ་ཤེས་མཛོད་ནས་ཕྱིར་འདོན་རྗེས་སུབ་དགོས",
222
     msgSyncOk: "མཉམ་འགྲོས་ལེགས།",
234
     msgSyncOk: "མཉམ་འགྲོས་ལེགས།",
223
     msgOpOk: "ལས་དོན་ལེགས།",
235
     msgOpOk: "ལས་དོན་ལེགས།",
224
     msgDelOk: "སུབ་པ་ལེགས།",
236
     msgDelOk: "སུབ་པ་ལེགས།",
@@ -259,6 +271,8 @@ export default {
259
     confirmSync: "སྨན་འགོག་སྦྱོར་ཚད་གཞི་ཤེས་མཛོད་དུ་མཉམ་འགྲོས་བྱེད་དམ།",
271
     confirmSync: "སྨན་འགོག་སྦྱོར་ཚད་གཞི་ཤེས་མཛོད་དུ་མཉམ་འགྲོས་བྱེད་དམ།",
260
     confirmRemoveKb: "ཤེས་མཛོད་ནས་ཕྱིར་འདོན་རྗེས་བསྐྱར་དུ་རྩོམ་སྒྲིག་དང་སུབ་ཆོག",
272
     confirmRemoveKb: "ཤེས་མཛོད་ནས་ཕྱིར་འདོན་རྗེས་བསྐྱར་དུ་རྩོམ་སྒྲིག་དང་སུབ་ཆོག",
261
     confirmDelete: "སྨན་འགོག་སྦྱོར་ཚད་གཞི་ཨང་གྲངས་{id}སུབ་པ་གཏན་འཁེལ་ཡིན་ནམ།",
273
     confirmDelete: "སྨན་འགོག་སྦྱོར་ཚད་གཞི་ཨང་གྲངས་{id}སུབ་པ་གཏན་འཁེལ་ཡིན་ནམ།",
274
+    ruleSyncedNoEdit: "ཤེས་མཛོད་དུ་མཉམ་འགྲོས་ཟིན་པའི་ཐོ་གཞུང་བཟོ་བཅོས་མི་ཆོགས།སྔོན་ལ་ཤེས་མཛོད་ནས་ཕྱིར་འདོན་དགོས",
275
+    ruleDeleteNeedRemoveKb: "ཤེས་མཛོད་དུ་མཉམ་འགྲོས་ཟིན་པའི་ཐོ་གཞུང་སྔོན་ལ་ཤེས་མཛོད་ནས་ཕྱིར་འདོན་རྗེས་སུབ་དགོས",
262
     msgSyncOk: "མཉམ་འགྲོས་ལེགས།",
276
     msgSyncOk: "མཉམ་འགྲོས་ལེགས།",
263
     msgOpOk: "ལས་དོན་ལེགས།",
277
     msgOpOk: "ལས་དོན་ལེགས།",
264
     msgDelOk: "སུབ་པ་ལེགས།",
278
     msgDelOk: "སུབ་པ་ལེགས།",

+ 21 - 7
ruoyi-ui/src/lang/zh/breedingStd.js

@@ -104,7 +104,9 @@ export default {
104
     confirmOffline:
104
     confirmOffline:
105
       "确认下架该养殖标准吗?下架后结束对外发布/检索可见,本地将回流为「未发布」,知识库侧保留副本(与「移出知识库」不同)。",
105
       "确认下架该养殖标准吗?下架后结束对外发布/检索可见,本地将回流为「未发布」,知识库侧保留副本(与「移出知识库」不同)。",
106
     rulePublishedNoEdit: "已发布记录不可修改,请先下架",
106
     rulePublishedNoEdit: "已发布记录不可修改,请先下架",
107
-    ruleDeleteNeedRemoveKb: "已同步至知识库的记录须先移出知识库后再删除"
107
+    ruleSyncedNoEdit: "已同步至知识库的记录不可修改,请先移出知识库",
108
+    ruleDeleteNeedRemoveKb: "已同步至知识库的记录须先移出知识库后再删除",
109
+    errStdTypeLoad: "标准类型加载失败,请刷新页面或联系管理员"
108
   },
110
   },
109
   feed: {
111
   feed: {
110
     queryKeyword: "关键词",
112
     queryKeyword: "关键词",
@@ -112,7 +114,7 @@ export default {
112
     queryStdType: "标准类型",
114
     queryStdType: "标准类型",
113
     dialogAdd: "[新增]饲喂标准",
115
     dialogAdd: "[新增]饲喂标准",
114
     dialogEdit: "[编辑]饲喂标准",
116
     dialogEdit: "[编辑]饲喂标准",
115
-    type1: "饲配方",
117
+    type1: "饲配方",
116
     type2: "牦牛投喂",
118
     type2: "牦牛投喂",
117
     confirmSync: "确认将该饲喂标准同步至知识库吗?",
119
     confirmSync: "确认将该饲喂标准同步至知识库吗?",
118
     confirmRemoveKb: "确认将该饲喂标准从知识库移出吗?",
120
     confirmRemoveKb: "确认将该饲喂标准从知识库移出吗?",
@@ -121,7 +123,9 @@ export default {
121
     confirmOffline:
123
     confirmOffline:
122
       "确认下架该饲喂标准吗?下架后结束对外发布/检索可见,本地将回流为「未发布」,知识库侧保留副本(与「移出知识库」不同)。",
124
       "确认下架该饲喂标准吗?下架后结束对外发布/检索可见,本地将回流为「未发布」,知识库侧保留副本(与「移出知识库」不同)。",
123
     rulePublishedNoEdit: "已发布记录不可修改,请先下架",
125
     rulePublishedNoEdit: "已发布记录不可修改,请先下架",
124
-    ruleDeleteNeedRemoveKb: "已同步至知识库的记录须先移出知识库后再删除"
126
+    ruleSyncedNoEdit: "已同步至知识库的记录不可修改,请先移出知识库",
127
+    ruleDeleteNeedRemoveKb: "已同步至知识库的记录须先移出知识库后再删除",
128
+    errStdTypeLoad: "标准类型加载失败,请刷新页面或联系管理员"
125
   },
129
   },
126
   eqp: {
130
   eqp: {
127
     queryKeyword: "关键词",
131
     queryKeyword: "关键词",
@@ -130,7 +134,7 @@ export default {
130
     dialogAdd: "[新增]设备实施作业标准",
134
     dialogAdd: "[新增]设备实施作业标准",
131
     dialogEdit: "[编辑]设备实施作业标准",
135
     dialogEdit: "[编辑]设备实施作业标准",
132
     type1: "设备操作",
136
     type1: "设备操作",
133
-    type2: "设备维护",
137
+    type2: "设备保养",
134
     type3: "设备排障",
138
     type3: "设备排障",
135
     type4: "设备维修",
139
     type4: "设备维修",
136
     confirmSync: "确认将该设备实施作业标准同步至知识库吗?",
140
     confirmSync: "确认将该设备实施作业标准同步至知识库吗?",
@@ -140,7 +144,9 @@ export default {
140
     confirmOffline:
144
     confirmOffline:
141
       "确认下架该设备实施作业标准吗?下架后结束对外发布/检索可见,本地将回流为「未发布」,知识库侧保留副本(与「移出知识库」不同)。",
145
       "确认下架该设备实施作业标准吗?下架后结束对外发布/检索可见,本地将回流为「未发布」,知识库侧保留副本(与「移出知识库」不同)。",
142
     rulePublishedNoEdit: "已发布记录不可修改,请先下架",
146
     rulePublishedNoEdit: "已发布记录不可修改,请先下架",
143
-    ruleDeleteNeedRemoveKb: "已同步至知识库的记录须先移出知识库后再删除"
147
+    ruleSyncedNoEdit: "已同步至知识库的记录不可修改,请先移出知识库",
148
+    ruleDeleteNeedRemoveKb: "已同步至知识库的记录须先移出知识库后再删除",
149
+    errStdTypeLoad: "标准类型加载失败,请刷新页面或联系管理员"
144
   },
150
   },
145
   growth: {
151
   growth: {
146
     queryKeyword: "关键词",
152
     queryKeyword: "关键词",
@@ -157,7 +163,9 @@ export default {
157
     confirmOffline:
163
     confirmOffline:
158
       "确认下架该生长与出栏标准吗?下架后结束对外发布/检索可见,本地将回流为「未发布」,知识库侧保留副本(与「移出知识库」不同)。",
164
       "确认下架该生长与出栏标准吗?下架后结束对外发布/检索可见,本地将回流为「未发布」,知识库侧保留副本(与「移出知识库」不同)。",
159
     rulePublishedNoEdit: "已发布记录不可修改,请先下架",
165
     rulePublishedNoEdit: "已发布记录不可修改,请先下架",
160
-    ruleDeleteNeedRemoveKb: "已同步至知识库的记录须先移出知识库后再删除"
166
+    ruleSyncedNoEdit: "已同步至知识库的记录不可修改,请先移出知识库",
167
+    ruleDeleteNeedRemoveKb: "已同步至知识库的记录须先移出知识库后再删除",
168
+    errStdTypeLoad: "标准类型加载失败,请刷新页面或联系管理员"
161
   },
169
   },
162
   ep: {
170
   ep: {
163
     queryKeyword: "关键词",
171
     queryKeyword: "关键词",
@@ -173,7 +181,9 @@ export default {
173
     confirmOffline:
181
     confirmOffline:
174
       "确认下架该疫病诊疗标准吗?下架后结束对外发布/检索可见,本地将回流为「未发布」,知识库侧保留副本(与「移出知识库」不同)。",
182
       "确认下架该疫病诊疗标准吗?下架后结束对外发布/检索可见,本地将回流为「未发布」,知识库侧保留副本(与「移出知识库」不同)。",
175
     rulePublishedNoEdit: "已发布记录不可修改,请先下架",
183
     rulePublishedNoEdit: "已发布记录不可修改,请先下架",
176
-    ruleDeleteNeedRemoveKb: "已同步至知识库的记录须先移出知识库后再删除"
184
+    ruleSyncedNoEdit: "已同步至知识库的记录不可修改,请先移出知识库",
185
+    ruleDeleteNeedRemoveKb: "已同步至知识库的记录须先移出知识库后再删除",
186
+    errStdTypeLoad: "标准类型加载失败,请刷新页面"
177
   },
187
   },
178
   wp: {
188
   wp: {
179
     drugName: "药物名称",
189
     drugName: "药物名称",
@@ -219,6 +229,8 @@ export default {
219
     confirmSync: "确认将该休药期标准同步至知识库吗?",
229
     confirmSync: "确认将该休药期标准同步至知识库吗?",
220
     confirmRemoveKb: "确认将该休药期标准从知识库移出吗?移出后可再次编辑或删除。",
230
     confirmRemoveKb: "确认将该休药期标准从知识库移出吗?移出后可再次编辑或删除。",
221
     confirmDelete: "是否确认删除休药期标准编号为{id}的数据项?",
231
     confirmDelete: "是否确认删除休药期标准编号为{id}的数据项?",
232
+    ruleSyncedNoEdit: "已同步至知识库的记录不可修改,请先移出知识库",
233
+    ruleDeleteNeedRemoveKb: "已同步至知识库的记录须先移出知识库后再删除",
222
     msgSyncOk: "同步成功",
234
     msgSyncOk: "同步成功",
223
     msgOpOk: "操作成功",
235
     msgOpOk: "操作成功",
224
     msgDelOk: "删除成功",
236
     msgDelOk: "删除成功",
@@ -259,6 +271,8 @@ export default {
259
     confirmSync: "确认将该药物禁配标准同步至知识库吗?",
271
     confirmSync: "确认将该药物禁配标准同步至知识库吗?",
260
     confirmRemoveKb: "确认将该标准从知识库移出吗?移出后可再次编辑或删除。",
272
     confirmRemoveKb: "确认将该标准从知识库移出吗?移出后可再次编辑或删除。",
261
     confirmDelete: "是否确认删除药物禁配标准编号为{id}的数据项?",
273
     confirmDelete: "是否确认删除药物禁配标准编号为{id}的数据项?",
274
+    ruleSyncedNoEdit: "已同步至知识库的记录不可修改,请先移出知识库",
275
+    ruleDeleteNeedRemoveKb: "已同步至知识库的记录须先移出知识库后再删除",
262
     msgSyncOk: "同步成功",
276
     msgSyncOk: "同步成功",
263
     msgOpOk: "操作成功",
277
     msgOpOk: "操作成功",
264
     msgDelOk: "删除成功",
278
     msgDelOk: "删除成功",

+ 51 - 18
ruoyi-ui/src/views/breedingStandards/breedingManage/index.vue

@@ -43,7 +43,7 @@
43
     <el-card shadow="never">
43
     <el-card shadow="never">
44
       <el-table v-loading="loading" :data="tableList" border>
44
       <el-table v-loading="loading" :data="tableList" border>
45
         <el-table-column :label="stdT('colFileName')" prop="standardName" align="center" min-width="120" :show-overflow-tooltip="true" />
45
         <el-table-column :label="stdT('colFileName')" prop="standardName" align="center" min-width="120" :show-overflow-tooltip="true" />
46
-        <el-table-column :label="stdT('colFileType')" align="center" width="100">
46
+        <el-table-column :label="stdT('colFileType')" align="center" width="112">
47
           <template slot-scope="scope">
47
           <template slot-scope="scope">
48
             <span>{{ typeLabel(scope.row.standardType) }}</span>
48
             <span>{{ typeLabel(scope.row.standardType) }}</span>
49
           </template>
49
           </template>
@@ -146,11 +146,22 @@
146
       <el-form :key="formKey" ref="form" :model="form" label-width="100px">
146
       <el-form :key="formKey" ref="form" :model="form" label-width="100px">
147
         <el-form-item prop="standardName" :rules="formRules.standardName">
147
         <el-form-item prop="standardName" :rules="formRules.standardName">
148
           <template slot="label">{{ stdT('formFileName') }}</template>
148
           <template slot="label">{{ stdT('formFileName') }}</template>
149
-          <el-input v-model="form.standardName" :placeholder="stdT('phFileName')" maxlength="20" show-word-limit />
149
+          <el-input
150
+            v-model="form.standardName"
151
+            :placeholder="stdT('phFileName')"
152
+            maxlength="20"
153
+            show-word-limit
154
+            :disabled="dialogEdit && !canEditFormRow"
155
+          />
150
         </el-form-item>
156
         </el-form-item>
151
         <el-form-item prop="standardType" :rules="formRules.standardType">
157
         <el-form-item prop="standardType" :rules="formRules.standardType">
152
           <template slot="label">{{ stdT('formFileType') }}</template>
158
           <template slot="label">{{ stdT('formFileType') }}</template>
153
-          <el-select v-model="form.standardType" :placeholder="$t('breedingStd.common.pleaseSelect')" style="width: 100%">
159
+          <el-select
160
+            v-model="form.standardType"
161
+            :placeholder="$t('breedingStd.common.pleaseSelect')"
162
+            style="width: 100%"
163
+            :disabled="dialogEdit && !canEditFormRow"
164
+          >
154
             <el-option
165
             <el-option
155
               v-for="item in standardTypeOptions"
166
               v-for="item in standardTypeOptions"
156
               :key="item.value"
167
               :key="item.value"
@@ -168,6 +179,7 @@
168
             :placeholder="stdT('phFileIntro')"
179
             :placeholder="stdT('phFileIntro')"
169
             maxlength="50"
180
             maxlength="50"
170
             show-word-limit
181
             show-word-limit
182
+            :disabled="dialogEdit && !canEditFormRow"
171
           />
183
           />
172
         </el-form-item>
184
         </el-form-item>
173
         <el-form-item prop="contentFilePath" :rules="formRules.contentFilePath">
185
         <el-form-item prop="contentFilePath" :rules="formRules.contentFilePath">
@@ -180,9 +192,9 @@
180
             :on-success="handleContentUploadSuccess"
192
             :on-success="handleContentUploadSuccess"
181
             :on-error="handleUploadHttpError"
193
             :on-error="handleUploadHttpError"
182
             :show-file-list="false"
194
             :show-file-list="false"
183
-            :disabled="dialogEdit && !canEditUploadRow"
195
+            :disabled="dialogEdit && !canEditFormRow"
184
           >
196
           >
185
-            <el-button size="mini" type="primary" :disabled="dialogEdit && !canEditUploadRow">{{ $t('breedingStd.common.pickFile') }}</el-button>
197
+            <el-button size="mini" type="primary" :disabled="dialogEdit && !canEditFormRow">{{ $t('breedingStd.common.pickFile') }}</el-button>
186
           </el-upload>
198
           </el-upload>
187
           <div class="el-upload__tip">
199
           <div class="el-upload__tip">
188
             {{ $t('breedingStd.common.tipBody') }}
200
             {{ $t('breedingStd.common.tipBody') }}
@@ -193,7 +205,7 @@
193
                 <span class="el-icon-document"> {{ form.contentFileName }} </span>
205
                 <span class="el-icon-document"> {{ form.contentFileName }} </span>
194
               </el-link>
206
               </el-link>
195
               <div class="ele-upload-list__item-content-action">
207
               <div class="ele-upload-list__item-content-action">
196
-                <el-link v-if="!(dialogEdit && !canEditUploadRow)" type="danger" :underline="false" @click="clearContentFile">{{ $t('breedingStd.common.del') }}</el-link>
208
+                <el-link v-if="!(dialogEdit && !canEditFormRow)" type="danger" :underline="false" @click="clearContentFile">{{ $t('breedingStd.common.del') }}</el-link>
197
               </div>
209
               </div>
198
             </li>
210
             </li>
199
           </ul>
211
           </ul>
@@ -211,7 +223,7 @@
211
             :on-remove="handleCoverRemove"
223
             :on-remove="handleCoverRemove"
212
             :limit="1"
224
             :limit="1"
213
             :file-list="coverFileList"
225
             :file-list="coverFileList"
214
-            :disabled="dialogEdit && !canEditUploadRow"
226
+            :disabled="dialogEdit && !canEditFormRow"
215
           >
227
           >
216
             <i class="el-icon-plus"></i>
228
             <i class="el-icon-plus"></i>
217
           </el-upload>
229
           </el-upload>
@@ -308,7 +320,7 @@ export default {
308
       viewOpen: false,
320
       viewOpen: false,
309
       viewRow: {},
321
       viewRow: {},
310
       dialogEdit: false,
322
       dialogEdit: false,
311
-      canEditUploadRow: true,
323
+      canEditFormRow: true,
312
       formKey: 0,
324
       formKey: 0,
313
       total: 0,
325
       total: 0,
314
       tableList: [],
326
       tableList: [],
@@ -371,10 +383,15 @@ export default {
371
       }
383
       }
372
     },
384
     },
373
     loadStandardTypeOptions() {
385
     loadStandardTypeOptions() {
374
-      return listInformationCategoryChildren(STD_TYPE_PARENT_CODE, STD_TYPE_CATEGORY_TYPE).then((res) => {
375
-        const list = res.data || []
376
-        this.standardTypeOptions = list.map((item) => this.mapCategoryItem(item)).filter((o) => o.value)
377
-      })
386
+      return listInformationCategoryChildren(STD_TYPE_PARENT_CODE, STD_TYPE_CATEGORY_TYPE)
387
+        .then((res) => {
388
+          const list = res.data || []
389
+          this.standardTypeOptions = list.map((item) => this.mapCategoryItem(item)).filter((o) => o.value)
390
+        })
391
+        .catch(() => {
392
+          this.standardTypeOptions = []
393
+          this.$modal.msgError(this.stdT("errStdTypeLoad"))
394
+        })
378
     },
395
     },
379
     typeLabel(val) {
396
     typeLabel(val) {
380
       if (val == null || val === "") {
397
       if (val == null || val === "") {
@@ -392,7 +409,10 @@ export default {
392
       return key
409
       return key
393
     },
410
     },
394
     canEdit(row) {
411
     canEdit(row) {
395
-      return Number(row.publishStatus) === PUBLISH_STATUS.UNPUBLISHED
412
+      return (
413
+        Number(row.publishStatus) === PUBLISH_STATUS.UNPUBLISHED &&
414
+        Number(row.kbSyncStatus) === KB_SYNC_STATUS.UNSYNCED
415
+      )
396
     },
416
     },
397
     canSyncKb(row) {
417
     canSyncKb(row) {
398
       return (
418
       return (
@@ -460,13 +480,26 @@ export default {
460
       this.formKey += 1
480
       this.formKey += 1
461
       this.resetFormModel()
481
       this.resetFormModel()
462
       this.dialogEdit = false
482
       this.dialogEdit = false
463
-      this.canEditUploadRow = true
483
+      this.canEditFormRow = true
464
       this.open = true
484
       this.open = true
465
       this.$nextTick(() => this.resetForm("form"))
485
       this.$nextTick(() => this.resetForm("form"))
466
     },
486
     },
487
+    resolveCanEditFormRow(data) {
488
+      return (
489
+        Number(data.publishStatus) === PUBLISH_STATUS.UNPUBLISHED &&
490
+        Number(data.kbSyncStatus) === KB_SYNC_STATUS.UNSYNCED
491
+      )
492
+    },
467
     handleEdit(row) {
493
     handleEdit(row) {
494
+      if (Number(row.publishStatus) === PUBLISH_STATUS.PUBLISHED) {
495
+        this.$modal.msgWarning(this.stdT("rulePublishedNoEdit"))
496
+        return
497
+      }
498
+      if (Number(row.kbSyncStatus) === KB_SYNC_STATUS.SYNCED) {
499
+        this.$modal.msgWarning(this.stdT("ruleSyncedNoEdit"))
500
+        return
501
+      }
468
       if (!this.canEdit(row)) {
502
       if (!this.canEdit(row)) {
469
-        this.$modal.msgWarning(this.$t("breedingStd.bm.rulePublishedNoEdit"))
470
         return
503
         return
471
       }
504
       }
472
       const id = row.id
505
       const id = row.id
@@ -474,7 +507,7 @@ export default {
474
         const data = res.data || {}
507
         const data = res.data || {}
475
         this.formKey += 1
508
         this.formKey += 1
476
         this.dialogEdit = true
509
         this.dialogEdit = true
477
-        this.canEditUploadRow = Number(data.publishStatus) === PUBLISH_STATUS.UNPUBLISHED
510
+        this.canEditFormRow = this.resolveCanEditFormRow(data)
478
         this.form = {
511
         this.form = {
479
           id: data.id,
512
           id: data.id,
480
           standardName: data.standardName,
513
           standardName: data.standardName,
@@ -523,11 +556,11 @@ export default {
523
     },
556
     },
524
     handleDelete(row) {
557
     handleDelete(row) {
525
       if (!this.canDelete(row)) {
558
       if (!this.canDelete(row)) {
526
-        this.$modal.msgWarning(this.$t("breedingStd.bm.ruleDeleteNeedRemoveKb"))
559
+        this.$modal.msgWarning(this.stdT("ruleDeleteNeedRemoveKb"))
527
         return
560
         return
528
       }
561
       }
529
       this.$modal
562
       this.$modal
530
-        .confirm(this.$t("breedingStd.bm.confirmDelete", { id: row.id }))
563
+        .confirm(this.stdT("confirmDelete", { id: row.id }))
531
         .then(() => delBreedingStandard(row.id))
564
         .then(() => delBreedingStandard(row.id))
532
         .then(() => {
565
         .then(() => {
533
           this.$modal.msgSuccess(this.$t("breedingStd.common.msgDelOk"))
566
           this.$modal.msgSuccess(this.$t("breedingStd.common.msgDelOk"))

+ 13 - 5
ruoyi-ui/src/views/breedingStandards/diseaseTreatment/drugIncompatibility/index.vue

@@ -277,16 +277,16 @@ export default {
277
       })
277
       })
278
     },
278
     },
279
     canEdit(row) {
279
     canEdit(row) {
280
-      return row.kbSyncStatus === KB_SYNC_STATUS.UNSYNCED
280
+      return Number(row.kbSyncStatus) === KB_SYNC_STATUS.UNSYNCED
281
     },
281
     },
282
     canDelete(row) {
282
     canDelete(row) {
283
-      return row.kbSyncStatus === KB_SYNC_STATUS.UNSYNCED
283
+      return Number(row.kbSyncStatus) === KB_SYNC_STATUS.UNSYNCED
284
     },
284
     },
285
     canSyncKb(row) {
285
     canSyncKb(row) {
286
-      return row.kbSyncStatus === KB_SYNC_STATUS.UNSYNCED
286
+      return Number(row.kbSyncStatus) === KB_SYNC_STATUS.UNSYNCED
287
     },
287
     },
288
     canRemoveKb(row) {
288
     canRemoveKb(row) {
289
-      return row.kbSyncStatus === KB_SYNC_STATUS.SYNCED
289
+      return Number(row.kbSyncStatus) === KB_SYNC_STATUS.SYNCED
290
     },
290
     },
291
     getList() {
291
     getList() {
292
       this.loading = true
292
       this.loading = true
@@ -335,6 +335,10 @@ export default {
335
       this.$nextTick(() => this.resetForm("form"))
335
       this.$nextTick(() => this.resetForm("form"))
336
     },
336
     },
337
     handleEdit(row) {
337
     handleEdit(row) {
338
+      if (Number(row.kbSyncStatus) === KB_SYNC_STATUS.SYNCED) {
339
+        this.$modal.msgWarning(this.stdT("ruleSyncedNoEdit"))
340
+        return
341
+      }
338
       if (!this.canEdit(row)) {
342
       if (!this.canEdit(row)) {
339
         return
343
         return
340
       }
344
       }
@@ -386,8 +390,12 @@ export default {
386
         .catch(() => {})
390
         .catch(() => {})
387
     },
391
     },
388
     handleDelete(row) {
392
     handleDelete(row) {
393
+      if (!this.canDelete(row)) {
394
+        this.$modal.msgWarning(this.stdT("ruleDeleteNeedRemoveKb"))
395
+        return
396
+      }
389
       this.$modal
397
       this.$modal
390
-        .confirm(this.$t("breedingStd.dic.confirmDelete", { id: row.id }))
398
+        .confirm(this.stdT("confirmDelete", { id: row.id }))
391
         .then(() => delDrugIncompatibilityStandard(row.id))
399
         .then(() => delDrugIncompatibilityStandard(row.id))
392
         .then(() => {
400
         .then(() => {
393
           this.$modal.msgSuccess(this.stdT("msgDelOk"))
401
           this.$modal.msgSuccess(this.stdT("msgDelOk"))

+ 51 - 18
ruoyi-ui/src/views/breedingStandards/diseaseTreatment/epidemicTreatment/index.vue

@@ -43,7 +43,7 @@
43
     <el-card shadow="never">
43
     <el-card shadow="never">
44
       <el-table v-loading="loading" :data="tableList" border>
44
       <el-table v-loading="loading" :data="tableList" border>
45
         <el-table-column :label="$t('breedingStd.common.colStdName')" prop="standardName" align="center" min-width="120" :show-overflow-tooltip="true" />
45
         <el-table-column :label="$t('breedingStd.common.colStdName')" prop="standardName" align="center" min-width="120" :show-overflow-tooltip="true" />
46
-        <el-table-column :label="$t('breedingStd.common.colStdType')" align="center" width="100">
46
+        <el-table-column :label="$t('breedingStd.common.colStdType')" align="center" width="112">
47
           <template slot-scope="scope">
47
           <template slot-scope="scope">
48
             <span>{{ typeLabel(scope.row.standardType) }}</span>
48
             <span>{{ typeLabel(scope.row.standardType) }}</span>
49
           </template>
49
           </template>
@@ -146,11 +146,22 @@
146
       <el-form :key="formKey" ref="form" :model="form" label-width="100px">
146
       <el-form :key="formKey" ref="form" :model="form" label-width="100px">
147
         <el-form-item prop="standardName" :rules="formRules.standardName">
147
         <el-form-item prop="standardName" :rules="formRules.standardName">
148
           <template slot="label">{{ $t('breedingStd.common.formStdName') }}</template>
148
           <template slot="label">{{ $t('breedingStd.common.formStdName') }}</template>
149
-          <el-input v-model="form.standardName" :placeholder="$t('breedingStd.common.phStdName')" maxlength="20" show-word-limit />
149
+          <el-input
150
+            v-model="form.standardName"
151
+            :placeholder="$t('breedingStd.common.phStdName')"
152
+            maxlength="20"
153
+            show-word-limit
154
+            :disabled="dialogEdit && !canEditFormRow"
155
+          />
150
         </el-form-item>
156
         </el-form-item>
151
         <el-form-item prop="standardType" :rules="formRules.standardType">
157
         <el-form-item prop="standardType" :rules="formRules.standardType">
152
           <template slot="label">{{ $t('breedingStd.common.formStdType') }}</template>
158
           <template slot="label">{{ $t('breedingStd.common.formStdType') }}</template>
153
-          <el-select v-model="form.standardType" :placeholder="$t('breedingStd.common.pleaseSelect')" style="width: 100%">
159
+          <el-select
160
+            v-model="form.standardType"
161
+            :placeholder="$t('breedingStd.common.pleaseSelect')"
162
+            style="width: 100%"
163
+            :disabled="dialogEdit && !canEditFormRow"
164
+          >
154
             <el-option
165
             <el-option
155
               v-for="item in standardTypeOptions"
166
               v-for="item in standardTypeOptions"
156
               :key="item.value"
167
               :key="item.value"
@@ -168,6 +179,7 @@
168
             :placeholder="$t('breedingStd.common.phIntroOptional')"
179
             :placeholder="$t('breedingStd.common.phIntroOptional')"
169
             maxlength="50"
180
             maxlength="50"
170
             show-word-limit
181
             show-word-limit
182
+            :disabled="dialogEdit && !canEditFormRow"
171
           />
183
           />
172
         </el-form-item>
184
         </el-form-item>
173
         <el-form-item prop="contentFilePath" :rules="formRules.contentFilePath">
185
         <el-form-item prop="contentFilePath" :rules="formRules.contentFilePath">
@@ -180,9 +192,9 @@
180
             :on-success="handleContentUploadSuccess"
192
             :on-success="handleContentUploadSuccess"
181
             :on-error="handleUploadHttpError"
193
             :on-error="handleUploadHttpError"
182
             :show-file-list="false"
194
             :show-file-list="false"
183
-            :disabled="dialogEdit && !canEditUploadRow"
195
+            :disabled="dialogEdit && !canEditFormRow"
184
           >
196
           >
185
-            <el-button size="mini" type="primary" :disabled="dialogEdit && !canEditUploadRow">{{ $t('breedingStd.common.pickFile') }}</el-button>
197
+            <el-button size="mini" type="primary" :disabled="dialogEdit && !canEditFormRow">{{ $t('breedingStd.common.pickFile') }}</el-button>
186
           </el-upload>
198
           </el-upload>
187
           <div class="el-upload__tip">{{ $t('breedingStd.common.tipBody') }}</div>
199
           <div class="el-upload__tip">{{ $t('breedingStd.common.tipBody') }}</div>
188
           <ul v-if="form.contentFilePath" class="upload-file-list el-upload-list el-upload-list--text">
200
           <ul v-if="form.contentFilePath" class="upload-file-list el-upload-list el-upload-list--text">
@@ -191,7 +203,7 @@
191
                 <span class="el-icon-document"> {{ form.contentFileName }} </span>
203
                 <span class="el-icon-document"> {{ form.contentFileName }} </span>
192
               </el-link>
204
               </el-link>
193
               <div class="ele-upload-list__item-content-action">
205
               <div class="ele-upload-list__item-content-action">
194
-                <el-link v-if="!(dialogEdit && !canEditUploadRow)" type="danger" :underline="false" @click="clearContentFile">{{ $t('breedingStd.common.del') }}</el-link>
206
+                <el-link v-if="!(dialogEdit && !canEditFormRow)" type="danger" :underline="false" @click="clearContentFile">{{ $t('breedingStd.common.del') }}</el-link>
195
               </div>
207
               </div>
196
             </li>
208
             </li>
197
           </ul>
209
           </ul>
@@ -209,7 +221,7 @@
209
             :on-remove="handleCoverRemove"
221
             :on-remove="handleCoverRemove"
210
             :limit="1"
222
             :limit="1"
211
             :file-list="coverFileList"
223
             :file-list="coverFileList"
212
-            :disabled="dialogEdit && !canEditUploadRow"
224
+            :disabled="dialogEdit && !canEditFormRow"
213
           >
225
           >
214
             <i class="el-icon-plus"></i>
226
             <i class="el-icon-plus"></i>
215
           </el-upload>
227
           </el-upload>
@@ -303,7 +315,7 @@ export default {
303
       viewOpen: false,
315
       viewOpen: false,
304
       viewRow: {},
316
       viewRow: {},
305
       dialogEdit: false,
317
       dialogEdit: false,
306
-      canEditUploadRow: true,
318
+      canEditFormRow: true,
307
       formKey: 0,
319
       formKey: 0,
308
       total: 0,
320
       total: 0,
309
       tableList: [],
321
       tableList: [],
@@ -365,10 +377,15 @@ export default {
365
       }
377
       }
366
     },
378
     },
367
     loadStandardTypeOptions() {
379
     loadStandardTypeOptions() {
368
-      return listInformationCategoryChildren(STD_TYPE_PARENT_CODE, STD_TYPE_CATEGORY_TYPE).then((res) => {
369
-        const list = res.data || []
370
-        this.standardTypeOptions = list.map((item) => this.mapCategoryItem(item)).filter((o) => o.value)
371
-      })
380
+      return listInformationCategoryChildren(STD_TYPE_PARENT_CODE, STD_TYPE_CATEGORY_TYPE)
381
+        .then((res) => {
382
+          const list = res.data || []
383
+          this.standardTypeOptions = list.map((item) => this.mapCategoryItem(item)).filter((o) => o.value)
384
+        })
385
+        .catch(() => {
386
+          this.standardTypeOptions = []
387
+          this.$modal.msgError(this.stdT("errStdTypeLoad"))
388
+        })
372
     },
389
     },
373
     typeLabel(val) {
390
     typeLabel(val) {
374
       if (val == null || val === "") {
391
       if (val == null || val === "") {
@@ -386,7 +403,10 @@ export default {
386
       return key
403
       return key
387
     },
404
     },
388
     canEdit(row) {
405
     canEdit(row) {
389
-      return Number(row.publishStatus) === PUBLISH_STATUS.UNPUBLISHED
406
+      return (
407
+        Number(row.publishStatus) === PUBLISH_STATUS.UNPUBLISHED &&
408
+        Number(row.kbSyncStatus) === KB_SYNC_STATUS.UNSYNCED
409
+      )
390
     },
410
     },
391
     canSyncKb(row) {
411
     canSyncKb(row) {
392
       return (
412
       return (
@@ -454,13 +474,26 @@ export default {
454
       this.formKey += 1
474
       this.formKey += 1
455
       this.resetFormModel()
475
       this.resetFormModel()
456
       this.dialogEdit = false
476
       this.dialogEdit = false
457
-      this.canEditUploadRow = true
477
+      this.canEditFormRow = true
458
       this.open = true
478
       this.open = true
459
       this.$nextTick(() => this.resetForm("form"))
479
       this.$nextTick(() => this.resetForm("form"))
460
     },
480
     },
481
+    resolveCanEditFormRow(data) {
482
+      return (
483
+        Number(data.publishStatus) === PUBLISH_STATUS.UNPUBLISHED &&
484
+        Number(data.kbSyncStatus) === KB_SYNC_STATUS.UNSYNCED
485
+      )
486
+    },
461
     handleEdit(row) {
487
     handleEdit(row) {
488
+      if (Number(row.publishStatus) === PUBLISH_STATUS.PUBLISHED) {
489
+        this.$modal.msgWarning(this.stdT("rulePublishedNoEdit"))
490
+        return
491
+      }
492
+      if (Number(row.kbSyncStatus) === KB_SYNC_STATUS.SYNCED) {
493
+        this.$modal.msgWarning(this.stdT("ruleSyncedNoEdit"))
494
+        return
495
+      }
462
       if (!this.canEdit(row)) {
496
       if (!this.canEdit(row)) {
463
-        this.$modal.msgWarning(this.$t("breedingStd.ep.rulePublishedNoEdit"))
464
         return
497
         return
465
       }
498
       }
466
       const id = row.id
499
       const id = row.id
@@ -468,7 +501,7 @@ export default {
468
         const data = res.data || {}
501
         const data = res.data || {}
469
         this.formKey += 1
502
         this.formKey += 1
470
         this.dialogEdit = true
503
         this.dialogEdit = true
471
-        this.canEditUploadRow = Number(data.publishStatus) === PUBLISH_STATUS.UNPUBLISHED
504
+        this.canEditFormRow = this.resolveCanEditFormRow(data)
472
         this.form = {
505
         this.form = {
473
           id: data.id,
506
           id: data.id,
474
           standardName: data.standardName,
507
           standardName: data.standardName,
@@ -517,11 +550,11 @@ export default {
517
     },
550
     },
518
     handleDelete(row) {
551
     handleDelete(row) {
519
       if (!this.canDelete(row)) {
552
       if (!this.canDelete(row)) {
520
-        this.$modal.msgWarning(this.$t("breedingStd.ep.ruleDeleteNeedRemoveKb"))
553
+        this.$modal.msgWarning(this.stdT("ruleDeleteNeedRemoveKb"))
521
         return
554
         return
522
       }
555
       }
523
       this.$modal
556
       this.$modal
524
-        .confirm(this.$t("breedingStd.ep.confirmDelete", { id: row.id }))
557
+        .confirm(this.stdT("confirmDelete", { id: row.id }))
525
         .then(() => delEpidemicTreatmentStandard(row.id))
558
         .then(() => delEpidemicTreatmentStandard(row.id))
526
         .then(() => {
559
         .then(() => {
527
           this.$modal.msgSuccess(this.$t("breedingStd.common.msgDelOk"))
560
           this.$modal.msgSuccess(this.$t("breedingStd.common.msgDelOk"))

+ 21 - 8
ruoyi-ui/src/views/breedingStandards/diseaseTreatment/withdrawalPeriod/index.vue

@@ -293,20 +293,24 @@ export default {
293
   },
293
   },
294
   methods: {
294
   methods: {
295
     drugTypeLabel(val) {
295
     drugTypeLabel(val) {
296
-      const item = this.drugTypeOptions.find((o) => o.value === val)
297
-      return item ? item.label : this.$t("breedingStd.status.dash")
296
+      if (val == null || val === "") {
297
+        return ""
298
+      }
299
+      const n = Number(val)
300
+      const item = this.drugTypeOptions.find((o) => o.value === n)
301
+      return item ? item.label : String(val)
298
     },
302
     },
299
     canEdit(row) {
303
     canEdit(row) {
300
-      return row.kbSyncStatus === KB_SYNC_STATUS.UNSYNCED
304
+      return Number(row.kbSyncStatus) === KB_SYNC_STATUS.UNSYNCED
301
     },
305
     },
302
     canDelete(row) {
306
     canDelete(row) {
303
-      return row.kbSyncStatus === KB_SYNC_STATUS.UNSYNCED
307
+      return Number(row.kbSyncStatus) === KB_SYNC_STATUS.UNSYNCED
304
     },
308
     },
305
     canSyncKb(row) {
309
     canSyncKb(row) {
306
-      return row.kbSyncStatus === KB_SYNC_STATUS.UNSYNCED
310
+      return Number(row.kbSyncStatus) === KB_SYNC_STATUS.UNSYNCED
307
     },
311
     },
308
     canRemoveKb(row) {
312
     canRemoveKb(row) {
309
-      return row.kbSyncStatus === KB_SYNC_STATUS.SYNCED
313
+      return Number(row.kbSyncStatus) === KB_SYNC_STATUS.SYNCED
310
     },
314
     },
311
     getList() {
315
     getList() {
312
       this.loading = true
316
       this.loading = true
@@ -347,6 +351,10 @@ export default {
347
       this.$nextTick(() => this.resetForm("form"))
351
       this.$nextTick(() => this.resetForm("form"))
348
     },
352
     },
349
     handleEdit(row) {
353
     handleEdit(row) {
354
+      if (Number(row.kbSyncStatus) === KB_SYNC_STATUS.SYNCED) {
355
+        this.$modal.msgWarning(this.stdT("ruleSyncedNoEdit"))
356
+        return
357
+      }
350
       if (!this.canEdit(row)) {
358
       if (!this.canEdit(row)) {
351
         return
359
         return
352
       }
360
       }
@@ -397,8 +405,12 @@ export default {
397
         .catch(() => {})
405
         .catch(() => {})
398
     },
406
     },
399
     handleDelete(row) {
407
     handleDelete(row) {
408
+      if (!this.canDelete(row)) {
409
+        this.$modal.msgWarning(this.stdT("ruleDeleteNeedRemoveKb"))
410
+        return
411
+      }
400
       this.$modal
412
       this.$modal
401
-        .confirm(this.$t("breedingStd.wp.confirmDelete", { id: row.id }))
413
+        .confirm(this.stdT("confirmDelete", { id: row.id }))
402
         .then(() => delWithdrawalPeriodStandard(row.id))
414
         .then(() => delWithdrawalPeriodStandard(row.id))
403
         .then(() => {
415
         .then(() => {
404
           this.$modal.msgSuccess(this.stdT("msgDelOk"))
416
           this.$modal.msgSuccess(this.stdT("msgDelOk"))
@@ -411,8 +423,9 @@ export default {
411
         if (!valid) {
423
         if (!valid) {
412
           return
424
           return
413
         }
425
         }
426
+        const drugName = typeof this.form.drugName === "string" ? this.form.drugName.trim() : this.form.drugName
414
         const payload = {
427
         const payload = {
415
-          drugName: this.form.drugName,
428
+          drugName,
416
           drugType: this.form.drugType,
429
           drugType: this.form.drugType,
417
           withdrawalDays: this.form.withdrawalDays,
430
           withdrawalDays: this.form.withdrawalDays,
418
           usageGuide: this.form.usageGuide,
431
           usageGuide: this.form.usageGuide,

+ 49 - 16
ruoyi-ui/src/views/breedingStandards/equipmentOperation/index.vue

@@ -43,7 +43,7 @@
43
     <el-card shadow="never">
43
     <el-card shadow="never">
44
       <el-table v-loading="loading" :data="tableList" border>
44
       <el-table v-loading="loading" :data="tableList" border>
45
         <el-table-column :label="$t('breedingStd.common.colStdName')" prop="standardName" align="center" min-width="120" :show-overflow-tooltip="true" />
45
         <el-table-column :label="$t('breedingStd.common.colStdName')" prop="standardName" align="center" min-width="120" :show-overflow-tooltip="true" />
46
-        <el-table-column :label="$t('breedingStd.common.colStdType')" align="center" width="100">
46
+        <el-table-column :label="$t('breedingStd.common.colStdType')" align="center" width="112">
47
           <template slot-scope="scope">
47
           <template slot-scope="scope">
48
             <span>{{ typeLabel(scope.row.standardType) }}</span>
48
             <span>{{ typeLabel(scope.row.standardType) }}</span>
49
           </template>
49
           </template>
@@ -146,11 +146,22 @@
146
       <el-form :key="formKey" ref="form" :model="form" label-width="100px">
146
       <el-form :key="formKey" ref="form" :model="form" label-width="100px">
147
         <el-form-item prop="standardName" :rules="formRules.standardName">
147
         <el-form-item prop="standardName" :rules="formRules.standardName">
148
           <template slot="label">{{ $t('breedingStd.common.formStdName') }}</template>
148
           <template slot="label">{{ $t('breedingStd.common.formStdName') }}</template>
149
-          <el-input v-model="form.standardName" :placeholder="$t('breedingStd.common.phStdName')" maxlength="20" show-word-limit />
149
+          <el-input
150
+            v-model="form.standardName"
151
+            :placeholder="$t('breedingStd.common.phStdName')"
152
+            maxlength="20"
153
+            show-word-limit
154
+            :disabled="dialogEdit && !canEditFormRow"
155
+          />
150
         </el-form-item>
156
         </el-form-item>
151
         <el-form-item prop="standardType" :rules="formRules.standardType">
157
         <el-form-item prop="standardType" :rules="formRules.standardType">
152
           <template slot="label">{{ $t('breedingStd.common.formStdType') }}</template>
158
           <template slot="label">{{ $t('breedingStd.common.formStdType') }}</template>
153
-          <el-select v-model="form.standardType" :placeholder="$t('breedingStd.common.pleaseSelect')" style="width: 100%">
159
+          <el-select
160
+            v-model="form.standardType"
161
+            :placeholder="$t('breedingStd.common.pleaseSelect')"
162
+            style="width: 100%"
163
+            :disabled="dialogEdit && !canEditFormRow"
164
+          >
154
             <el-option
165
             <el-option
155
               v-for="item in standardTypeOptions"
166
               v-for="item in standardTypeOptions"
156
               :key="item.value"
167
               :key="item.value"
@@ -168,6 +179,7 @@
168
             :placeholder="$t('breedingStd.common.phIntroOptional')"
179
             :placeholder="$t('breedingStd.common.phIntroOptional')"
169
             maxlength="50"
180
             maxlength="50"
170
             show-word-limit
181
             show-word-limit
182
+            :disabled="dialogEdit && !canEditFormRow"
171
           />
183
           />
172
         </el-form-item>
184
         </el-form-item>
173
         <el-form-item prop="contentFilePath" :rules="formRules.contentFilePath">
185
         <el-form-item prop="contentFilePath" :rules="formRules.contentFilePath">
@@ -180,9 +192,9 @@
180
             :on-success="handleContentUploadSuccess"
192
             :on-success="handleContentUploadSuccess"
181
             :on-error="handleUploadHttpError"
193
             :on-error="handleUploadHttpError"
182
             :show-file-list="false"
194
             :show-file-list="false"
183
-            :disabled="dialogEdit && !canEditUploadRow"
195
+            :disabled="dialogEdit && !canEditFormRow"
184
           >
196
           >
185
-            <el-button size="mini" type="primary" :disabled="dialogEdit && !canEditUploadRow">{{ $t('breedingStd.common.pickFile') }}</el-button>
197
+            <el-button size="mini" type="primary" :disabled="dialogEdit && !canEditFormRow">{{ $t('breedingStd.common.pickFile') }}</el-button>
186
           </el-upload>
198
           </el-upload>
187
           <div class="el-upload__tip">{{ $t('breedingStd.common.tipBody') }}</div>
199
           <div class="el-upload__tip">{{ $t('breedingStd.common.tipBody') }}</div>
188
           <ul v-if="form.contentFilePath" class="upload-file-list el-upload-list el-upload-list--text">
200
           <ul v-if="form.contentFilePath" class="upload-file-list el-upload-list el-upload-list--text">
@@ -191,7 +203,7 @@
191
                 <span class="el-icon-document"> {{ form.contentFileName }} </span>
203
                 <span class="el-icon-document"> {{ form.contentFileName }} </span>
192
               </el-link>
204
               </el-link>
193
               <div class="ele-upload-list__item-content-action">
205
               <div class="ele-upload-list__item-content-action">
194
-                <el-link v-if="!(dialogEdit && !canEditUploadRow)" type="danger" :underline="false" @click="clearContentFile">{{ $t('breedingStd.common.del') }}</el-link>
206
+                <el-link v-if="!(dialogEdit && !canEditFormRow)" type="danger" :underline="false" @click="clearContentFile">{{ $t('breedingStd.common.del') }}</el-link>
195
               </div>
207
               </div>
196
             </li>
208
             </li>
197
           </ul>
209
           </ul>
@@ -209,7 +221,7 @@
209
             :on-remove="handleCoverRemove"
221
             :on-remove="handleCoverRemove"
210
             :limit="1"
222
             :limit="1"
211
             :file-list="coverFileList"
223
             :file-list="coverFileList"
212
-            :disabled="dialogEdit && !canEditUploadRow"
224
+            :disabled="dialogEdit && !canEditFormRow"
213
           >
225
           >
214
             <i class="el-icon-plus"></i>
226
             <i class="el-icon-plus"></i>
215
           </el-upload>
227
           </el-upload>
@@ -306,7 +318,7 @@ export default {
306
       viewOpen: false,
318
       viewOpen: false,
307
       viewRow: {},
319
       viewRow: {},
308
       dialogEdit: false,
320
       dialogEdit: false,
309
-      canEditUploadRow: true,
321
+      canEditFormRow: true,
310
       formKey: 0,
322
       formKey: 0,
311
       total: 0,
323
       total: 0,
312
       tableList: [],
324
       tableList: [],
@@ -368,10 +380,15 @@ export default {
368
       }
380
       }
369
     },
381
     },
370
     loadStandardTypeOptions() {
382
     loadStandardTypeOptions() {
371
-      return listInformationCategoryChildren(STD_TYPE_PARENT_CODE, STD_TYPE_CATEGORY_TYPE).then((res) => {
372
-        const list = res.data || []
373
-        this.standardTypeOptions = list.map((item) => this.mapCategoryItem(item)).filter((o) => o.value)
374
-      })
383
+      return listInformationCategoryChildren(STD_TYPE_PARENT_CODE, STD_TYPE_CATEGORY_TYPE)
384
+        .then((res) => {
385
+          const list = res.data || []
386
+          this.standardTypeOptions = list.map((item) => this.mapCategoryItem(item)).filter((o) => o.value)
387
+        })
388
+        .catch(() => {
389
+          this.standardTypeOptions = []
390
+          this.$modal.msgError(this.$t("breedingStd.eqp.errStdTypeLoad"))
391
+        })
375
     },
392
     },
376
     typeLabel(val) {
393
     typeLabel(val) {
377
       if (val == null || val === "") {
394
       if (val == null || val === "") {
@@ -389,7 +406,10 @@ export default {
389
       return key
406
       return key
390
     },
407
     },
391
     canEdit(row) {
408
     canEdit(row) {
392
-      return Number(row.publishStatus) === PUBLISH_STATUS.UNPUBLISHED
409
+      return (
410
+        Number(row.publishStatus) === PUBLISH_STATUS.UNPUBLISHED &&
411
+        Number(row.kbSyncStatus) === KB_SYNC_STATUS.UNSYNCED
412
+      )
393
     },
413
     },
394
     canSyncKb(row) {
414
     canSyncKb(row) {
395
       return (
415
       return (
@@ -457,21 +477,34 @@ export default {
457
       this.formKey += 1
477
       this.formKey += 1
458
       this.resetFormModel()
478
       this.resetFormModel()
459
       this.dialogEdit = false
479
       this.dialogEdit = false
460
-      this.canEditUploadRow = true
480
+      this.canEditFormRow = true
461
       this.open = true
481
       this.open = true
462
       this.$nextTick(() => this.resetForm("form"))
482
       this.$nextTick(() => this.resetForm("form"))
463
     },
483
     },
484
+    resolveCanEditFormRow(data) {
485
+      return (
486
+        Number(data.publishStatus) === PUBLISH_STATUS.UNPUBLISHED &&
487
+        Number(data.kbSyncStatus) === KB_SYNC_STATUS.UNSYNCED
488
+      )
489
+    },
464
     handleEdit(row) {
490
     handleEdit(row) {
465
-      if (!this.canEdit(row)) {
491
+      if (Number(row.publishStatus) === PUBLISH_STATUS.PUBLISHED) {
466
         this.$modal.msgWarning(this.$t("breedingStd.eqp.rulePublishedNoEdit"))
492
         this.$modal.msgWarning(this.$t("breedingStd.eqp.rulePublishedNoEdit"))
467
         return
493
         return
468
       }
494
       }
495
+      if (Number(row.kbSyncStatus) === KB_SYNC_STATUS.SYNCED) {
496
+        this.$modal.msgWarning(this.$t("breedingStd.eqp.ruleSyncedNoEdit"))
497
+        return
498
+      }
499
+      if (!this.canEdit(row)) {
500
+        return
501
+      }
469
       const id = row.id
502
       const id = row.id
470
       getEquipmentWorkStandard(id).then((res) => {
503
       getEquipmentWorkStandard(id).then((res) => {
471
         const data = res.data || {}
504
         const data = res.data || {}
472
         this.formKey += 1
505
         this.formKey += 1
473
         this.dialogEdit = true
506
         this.dialogEdit = true
474
-        this.canEditUploadRow = Number(data.publishStatus) === PUBLISH_STATUS.UNPUBLISHED
507
+        this.canEditFormRow = this.resolveCanEditFormRow(data)
475
         this.form = {
508
         this.form = {
476
           id: data.id,
509
           id: data.id,
477
           standardName: data.standardName,
510
           standardName: data.standardName,

+ 49 - 16
ruoyi-ui/src/views/breedingStandards/feeding/index.vue

@@ -43,7 +43,7 @@
43
     <el-card shadow="never">
43
     <el-card shadow="never">
44
       <el-table v-loading="loading" :data="tableList" border>
44
       <el-table v-loading="loading" :data="tableList" border>
45
         <el-table-column :label="$t('breedingStd.common.colStdName')" prop="standardName" align="center" min-width="120" :show-overflow-tooltip="true" />
45
         <el-table-column :label="$t('breedingStd.common.colStdName')" prop="standardName" align="center" min-width="120" :show-overflow-tooltip="true" />
46
-        <el-table-column :label="$t('breedingStd.common.colStdType')" align="center" width="100">
46
+        <el-table-column :label="$t('breedingStd.common.colStdType')" align="center" width="112">
47
           <template slot-scope="scope">
47
           <template slot-scope="scope">
48
             <span>{{ typeLabel(scope.row.standardType) }}</span>
48
             <span>{{ typeLabel(scope.row.standardType) }}</span>
49
           </template>
49
           </template>
@@ -146,11 +146,22 @@
146
       <el-form :key="formKey" ref="form" :model="form" label-width="100px">
146
       <el-form :key="formKey" ref="form" :model="form" label-width="100px">
147
         <el-form-item prop="standardName" :rules="formRules.standardName">
147
         <el-form-item prop="standardName" :rules="formRules.standardName">
148
           <template slot="label">{{ $t('breedingStd.common.formStdName') }}</template>
148
           <template slot="label">{{ $t('breedingStd.common.formStdName') }}</template>
149
-          <el-input v-model="form.standardName" :placeholder="$t('breedingStd.common.phStdName')" maxlength="20" show-word-limit />
149
+          <el-input
150
+            v-model="form.standardName"
151
+            :placeholder="$t('breedingStd.common.phStdName')"
152
+            maxlength="20"
153
+            show-word-limit
154
+            :disabled="dialogEdit && !canEditFormRow"
155
+          />
150
         </el-form-item>
156
         </el-form-item>
151
         <el-form-item prop="standardType" :rules="formRules.standardType">
157
         <el-form-item prop="standardType" :rules="formRules.standardType">
152
           <template slot="label">{{ $t('breedingStd.common.formStdType') }}</template>
158
           <template slot="label">{{ $t('breedingStd.common.formStdType') }}</template>
153
-          <el-select v-model="form.standardType" :placeholder="$t('breedingStd.common.pleaseSelect')" style="width: 100%">
159
+          <el-select
160
+            v-model="form.standardType"
161
+            :placeholder="$t('breedingStd.common.pleaseSelect')"
162
+            style="width: 100%"
163
+            :disabled="dialogEdit && !canEditFormRow"
164
+          >
154
             <el-option
165
             <el-option
155
               v-for="item in standardTypeOptions"
166
               v-for="item in standardTypeOptions"
156
               :key="item.value"
167
               :key="item.value"
@@ -168,6 +179,7 @@
168
             :placeholder="$t('breedingStd.common.phIntroOptional')"
179
             :placeholder="$t('breedingStd.common.phIntroOptional')"
169
             maxlength="50"
180
             maxlength="50"
170
             show-word-limit
181
             show-word-limit
182
+            :disabled="dialogEdit && !canEditFormRow"
171
           />
183
           />
172
         </el-form-item>
184
         </el-form-item>
173
         <el-form-item prop="contentFilePath" :rules="formRules.contentFilePath">
185
         <el-form-item prop="contentFilePath" :rules="formRules.contentFilePath">
@@ -180,9 +192,9 @@
180
             :on-success="handleContentUploadSuccess"
192
             :on-success="handleContentUploadSuccess"
181
             :on-error="handleUploadHttpError"
193
             :on-error="handleUploadHttpError"
182
             :show-file-list="false"
194
             :show-file-list="false"
183
-            :disabled="dialogEdit && !canEditUploadRow"
195
+            :disabled="dialogEdit && !canEditFormRow"
184
           >
196
           >
185
-            <el-button size="mini" type="primary" :disabled="dialogEdit && !canEditUploadRow">{{ $t('breedingStd.common.pickFile') }}</el-button>
197
+            <el-button size="mini" type="primary" :disabled="dialogEdit && !canEditFormRow">{{ $t('breedingStd.common.pickFile') }}</el-button>
186
           </el-upload>
198
           </el-upload>
187
           <div class="el-upload__tip">{{ $t('breedingStd.common.tipBody') }}</div>
199
           <div class="el-upload__tip">{{ $t('breedingStd.common.tipBody') }}</div>
188
           <ul v-if="form.contentFilePath" class="upload-file-list el-upload-list el-upload-list--text">
200
           <ul v-if="form.contentFilePath" class="upload-file-list el-upload-list el-upload-list--text">
@@ -191,7 +203,7 @@
191
                 <span class="el-icon-document"> {{ form.contentFileName }} </span>
203
                 <span class="el-icon-document"> {{ form.contentFileName }} </span>
192
               </el-link>
204
               </el-link>
193
               <div class="ele-upload-list__item-content-action">
205
               <div class="ele-upload-list__item-content-action">
194
-                <el-link v-if="!(dialogEdit && !canEditUploadRow)" type="danger" :underline="false" @click="clearContentFile">{{ $t('breedingStd.common.del') }}</el-link>
206
+                <el-link v-if="!(dialogEdit && !canEditFormRow)" type="danger" :underline="false" @click="clearContentFile">{{ $t('breedingStd.common.del') }}</el-link>
195
               </div>
207
               </div>
196
             </li>
208
             </li>
197
           </ul>
209
           </ul>
@@ -209,7 +221,7 @@
209
             :on-remove="handleCoverRemove"
221
             :on-remove="handleCoverRemove"
210
             :limit="1"
222
             :limit="1"
211
             :file-list="coverFileList"
223
             :file-list="coverFileList"
212
-            :disabled="dialogEdit && !canEditUploadRow"
224
+            :disabled="dialogEdit && !canEditFormRow"
213
           >
225
           >
214
             <i class="el-icon-plus"></i>
226
             <i class="el-icon-plus"></i>
215
           </el-upload>
227
           </el-upload>
@@ -304,7 +316,7 @@ export default {
304
       viewOpen: false,
316
       viewOpen: false,
305
       viewRow: {},
317
       viewRow: {},
306
       dialogEdit: false,
318
       dialogEdit: false,
307
-      canEditUploadRow: true,
319
+      canEditFormRow: true,
308
       formKey: 0,
320
       formKey: 0,
309
       total: 0,
321
       total: 0,
310
       tableList: [],
322
       tableList: [],
@@ -366,10 +378,15 @@ export default {
366
       }
378
       }
367
     },
379
     },
368
     loadStandardTypeOptions() {
380
     loadStandardTypeOptions() {
369
-      return listInformationCategoryChildren(STD_TYPE_PARENT_CODE, STD_TYPE_CATEGORY_TYPE).then((res) => {
370
-        const list = res.data || []
371
-        this.standardTypeOptions = list.map((item) => this.mapCategoryItem(item)).filter((o) => o.value)
372
-      })
381
+      return listInformationCategoryChildren(STD_TYPE_PARENT_CODE, STD_TYPE_CATEGORY_TYPE)
382
+        .then((res) => {
383
+          const list = res.data || []
384
+          this.standardTypeOptions = list.map((item) => this.mapCategoryItem(item)).filter((o) => o.value)
385
+        })
386
+        .catch(() => {
387
+          this.standardTypeOptions = []
388
+          this.$modal.msgError(this.$t("breedingStd.feed.errStdTypeLoad"))
389
+        })
373
     },
390
     },
374
     typeLabel(val) {
391
     typeLabel(val) {
375
       if (val == null || val === "") {
392
       if (val == null || val === "") {
@@ -387,7 +404,10 @@ export default {
387
       return key
404
       return key
388
     },
405
     },
389
     canEdit(row) {
406
     canEdit(row) {
390
-      return Number(row.publishStatus) === PUBLISH_STATUS.UNPUBLISHED
407
+      return (
408
+        Number(row.publishStatus) === PUBLISH_STATUS.UNPUBLISHED &&
409
+        Number(row.kbSyncStatus) === KB_SYNC_STATUS.UNSYNCED
410
+      )
391
     },
411
     },
392
     canSyncKb(row) {
412
     canSyncKb(row) {
393
       return (
413
       return (
@@ -455,21 +475,34 @@ export default {
455
       this.formKey += 1
475
       this.formKey += 1
456
       this.resetFormModel()
476
       this.resetFormModel()
457
       this.dialogEdit = false
477
       this.dialogEdit = false
458
-      this.canEditUploadRow = true
478
+      this.canEditFormRow = true
459
       this.open = true
479
       this.open = true
460
       this.$nextTick(() => this.resetForm("form"))
480
       this.$nextTick(() => this.resetForm("form"))
461
     },
481
     },
482
+    resolveCanEditFormRow(data) {
483
+      return (
484
+        Number(data.publishStatus) === PUBLISH_STATUS.UNPUBLISHED &&
485
+        Number(data.kbSyncStatus) === KB_SYNC_STATUS.UNSYNCED
486
+      )
487
+    },
462
     handleEdit(row) {
488
     handleEdit(row) {
463
-      if (!this.canEdit(row)) {
489
+      if (Number(row.publishStatus) === PUBLISH_STATUS.PUBLISHED) {
464
         this.$modal.msgWarning(this.$t("breedingStd.feed.rulePublishedNoEdit"))
490
         this.$modal.msgWarning(this.$t("breedingStd.feed.rulePublishedNoEdit"))
465
         return
491
         return
466
       }
492
       }
493
+      if (Number(row.kbSyncStatus) === KB_SYNC_STATUS.SYNCED) {
494
+        this.$modal.msgWarning(this.$t("breedingStd.feed.ruleSyncedNoEdit"))
495
+        return
496
+      }
497
+      if (!this.canEdit(row)) {
498
+        return
499
+      }
467
       const id = row.id
500
       const id = row.id
468
       getFeedingStandard(id).then((res) => {
501
       getFeedingStandard(id).then((res) => {
469
         const data = res.data || {}
502
         const data = res.data || {}
470
         this.formKey += 1
503
         this.formKey += 1
471
         this.dialogEdit = true
504
         this.dialogEdit = true
472
-        this.canEditUploadRow = Number(data.publishStatus) === PUBLISH_STATUS.UNPUBLISHED
505
+        this.canEditFormRow = this.resolveCanEditFormRow(data)
473
         this.form = {
506
         this.form = {
474
           id: data.id,
507
           id: data.id,
475
           standardName: data.standardName,
508
           standardName: data.standardName,

+ 49 - 16
ruoyi-ui/src/views/breedingStandards/growthOutbound/index.vue

@@ -43,7 +43,7 @@
43
     <el-card shadow="never">
43
     <el-card shadow="never">
44
       <el-table v-loading="loading" :data="tableList" border>
44
       <el-table v-loading="loading" :data="tableList" border>
45
         <el-table-column :label="$t('breedingStd.common.colStdName')" prop="standardName" align="center" min-width="120" :show-overflow-tooltip="true" />
45
         <el-table-column :label="$t('breedingStd.common.colStdName')" prop="standardName" align="center" min-width="120" :show-overflow-tooltip="true" />
46
-        <el-table-column :label="$t('breedingStd.common.colStdType')" align="center" width="100">
46
+        <el-table-column :label="$t('breedingStd.common.colStdType')" align="center" width="112">
47
           <template slot-scope="scope">
47
           <template slot-scope="scope">
48
             <span>{{ typeLabel(scope.row.standardType) }}</span>
48
             <span>{{ typeLabel(scope.row.standardType) }}</span>
49
           </template>
49
           </template>
@@ -146,11 +146,22 @@
146
       <el-form :key="formKey" ref="form" :model="form" label-width="100px">
146
       <el-form :key="formKey" ref="form" :model="form" label-width="100px">
147
         <el-form-item prop="standardName" :rules="formRules.standardName">
147
         <el-form-item prop="standardName" :rules="formRules.standardName">
148
           <template slot="label">{{ $t('breedingStd.common.formStdName') }}</template>
148
           <template slot="label">{{ $t('breedingStd.common.formStdName') }}</template>
149
-          <el-input v-model="form.standardName" :placeholder="$t('breedingStd.common.phStdName')" maxlength="20" show-word-limit />
149
+          <el-input
150
+            v-model="form.standardName"
151
+            :placeholder="$t('breedingStd.common.phStdName')"
152
+            maxlength="20"
153
+            show-word-limit
154
+            :disabled="dialogEdit && !canEditFormRow"
155
+          />
150
         </el-form-item>
156
         </el-form-item>
151
         <el-form-item prop="standardType" :rules="formRules.standardType">
157
         <el-form-item prop="standardType" :rules="formRules.standardType">
152
           <template slot="label">{{ $t('breedingStd.common.formStdType') }}</template>
158
           <template slot="label">{{ $t('breedingStd.common.formStdType') }}</template>
153
-          <el-select v-model="form.standardType" :placeholder="$t('breedingStd.common.pleaseSelect')" style="width: 100%">
159
+          <el-select
160
+            v-model="form.standardType"
161
+            :placeholder="$t('breedingStd.common.pleaseSelect')"
162
+            style="width: 100%"
163
+            :disabled="dialogEdit && !canEditFormRow"
164
+          >
154
             <el-option
165
             <el-option
155
               v-for="item in standardTypeOptions"
166
               v-for="item in standardTypeOptions"
156
               :key="item.value"
167
               :key="item.value"
@@ -168,6 +179,7 @@
168
             :placeholder="$t('breedingStd.common.phIntroOptional')"
179
             :placeholder="$t('breedingStd.common.phIntroOptional')"
169
             maxlength="50"
180
             maxlength="50"
170
             show-word-limit
181
             show-word-limit
182
+            :disabled="dialogEdit && !canEditFormRow"
171
           />
183
           />
172
         </el-form-item>
184
         </el-form-item>
173
         <el-form-item prop="contentFilePath" :rules="formRules.contentFilePath">
185
         <el-form-item prop="contentFilePath" :rules="formRules.contentFilePath">
@@ -180,9 +192,9 @@
180
             :on-success="handleContentUploadSuccess"
192
             :on-success="handleContentUploadSuccess"
181
             :on-error="handleUploadHttpError"
193
             :on-error="handleUploadHttpError"
182
             :show-file-list="false"
194
             :show-file-list="false"
183
-            :disabled="dialogEdit && !canEditUploadRow"
195
+            :disabled="dialogEdit && !canEditFormRow"
184
           >
196
           >
185
-            <el-button size="mini" type="primary" :disabled="dialogEdit && !canEditUploadRow">{{ $t('breedingStd.common.pickFile') }}</el-button>
197
+            <el-button size="mini" type="primary" :disabled="dialogEdit && !canEditFormRow">{{ $t('breedingStd.common.pickFile') }}</el-button>
186
           </el-upload>
198
           </el-upload>
187
           <div class="el-upload__tip">{{ $t('breedingStd.common.tipBody') }}</div>
199
           <div class="el-upload__tip">{{ $t('breedingStd.common.tipBody') }}</div>
188
           <ul v-if="form.contentFilePath" class="upload-file-list el-upload-list el-upload-list--text">
200
           <ul v-if="form.contentFilePath" class="upload-file-list el-upload-list el-upload-list--text">
@@ -191,7 +203,7 @@
191
                 <span class="el-icon-document"> {{ form.contentFileName }} </span>
203
                 <span class="el-icon-document"> {{ form.contentFileName }} </span>
192
               </el-link>
204
               </el-link>
193
               <div class="ele-upload-list__item-content-action">
205
               <div class="ele-upload-list__item-content-action">
194
-                <el-link v-if="!(dialogEdit && !canEditUploadRow)" type="danger" :underline="false" @click="clearContentFile">{{ $t('breedingStd.common.del') }}</el-link>
206
+                <el-link v-if="!(dialogEdit && !canEditFormRow)" type="danger" :underline="false" @click="clearContentFile">{{ $t('breedingStd.common.del') }}</el-link>
195
               </div>
207
               </div>
196
             </li>
208
             </li>
197
           </ul>
209
           </ul>
@@ -209,7 +221,7 @@
209
             :on-remove="handleCoverRemove"
221
             :on-remove="handleCoverRemove"
210
             :limit="1"
222
             :limit="1"
211
             :file-list="coverFileList"
223
             :file-list="coverFileList"
212
-            :disabled="dialogEdit && !canEditUploadRow"
224
+            :disabled="dialogEdit && !canEditFormRow"
213
           >
225
           >
214
             <i class="el-icon-plus"></i>
226
             <i class="el-icon-plus"></i>
215
           </el-upload>
227
           </el-upload>
@@ -304,7 +316,7 @@ export default {
304
       viewOpen: false,
316
       viewOpen: false,
305
       viewRow: {},
317
       viewRow: {},
306
       dialogEdit: false,
318
       dialogEdit: false,
307
-      canEditUploadRow: true,
319
+      canEditFormRow: true,
308
       formKey: 0,
320
       formKey: 0,
309
       total: 0,
321
       total: 0,
310
       tableList: [],
322
       tableList: [],
@@ -366,10 +378,15 @@ export default {
366
       }
378
       }
367
     },
379
     },
368
     loadStandardTypeOptions() {
380
     loadStandardTypeOptions() {
369
-      return listInformationCategoryChildren(STD_TYPE_PARENT_CODE, STD_TYPE_CATEGORY_TYPE).then((res) => {
370
-        const list = res.data || []
371
-        this.standardTypeOptions = list.map((item) => this.mapCategoryItem(item)).filter((o) => o.value)
372
-      })
381
+      return listInformationCategoryChildren(STD_TYPE_PARENT_CODE, STD_TYPE_CATEGORY_TYPE)
382
+        .then((res) => {
383
+          const list = res.data || []
384
+          this.standardTypeOptions = list.map((item) => this.mapCategoryItem(item)).filter((o) => o.value)
385
+        })
386
+        .catch(() => {
387
+          this.standardTypeOptions = []
388
+          this.$modal.msgError(this.$t("breedingStd.growth.errStdTypeLoad"))
389
+        })
373
     },
390
     },
374
     typeLabel(val) {
391
     typeLabel(val) {
375
       if (val == null || val === "") {
392
       if (val == null || val === "") {
@@ -387,7 +404,10 @@ export default {
387
       return key
404
       return key
388
     },
405
     },
389
     canEdit(row) {
406
     canEdit(row) {
390
-      return Number(row.publishStatus) === PUBLISH_STATUS.UNPUBLISHED
407
+      return (
408
+        Number(row.publishStatus) === PUBLISH_STATUS.UNPUBLISHED &&
409
+        Number(row.kbSyncStatus) === KB_SYNC_STATUS.UNSYNCED
410
+      )
391
     },
411
     },
392
     canSyncKb(row) {
412
     canSyncKb(row) {
393
       return (
413
       return (
@@ -455,21 +475,34 @@ export default {
455
       this.formKey += 1
475
       this.formKey += 1
456
       this.resetFormModel()
476
       this.resetFormModel()
457
       this.dialogEdit = false
477
       this.dialogEdit = false
458
-      this.canEditUploadRow = true
478
+      this.canEditFormRow = true
459
       this.open = true
479
       this.open = true
460
       this.$nextTick(() => this.resetForm("form"))
480
       this.$nextTick(() => this.resetForm("form"))
461
     },
481
     },
482
+    resolveCanEditFormRow(data) {
483
+      return (
484
+        Number(data.publishStatus) === PUBLISH_STATUS.UNPUBLISHED &&
485
+        Number(data.kbSyncStatus) === KB_SYNC_STATUS.UNSYNCED
486
+      )
487
+    },
462
     handleEdit(row) {
488
     handleEdit(row) {
463
-      if (!this.canEdit(row)) {
489
+      if (Number(row.publishStatus) === PUBLISH_STATUS.PUBLISHED) {
464
         this.$modal.msgWarning(this.$t("breedingStd.growth.rulePublishedNoEdit"))
490
         this.$modal.msgWarning(this.$t("breedingStd.growth.rulePublishedNoEdit"))
465
         return
491
         return
466
       }
492
       }
493
+      if (Number(row.kbSyncStatus) === KB_SYNC_STATUS.SYNCED) {
494
+        this.$modal.msgWarning(this.$t("breedingStd.growth.ruleSyncedNoEdit"))
495
+        return
496
+      }
497
+      if (!this.canEdit(row)) {
498
+        return
499
+      }
467
       const id = row.id
500
       const id = row.id
468
       getGrowthSlaughterStandard(id).then((res) => {
501
       getGrowthSlaughterStandard(id).then((res) => {
469
         const data = res.data || {}
502
         const data = res.data || {}
470
         this.formKey += 1
503
         this.formKey += 1
471
         this.dialogEdit = true
504
         this.dialogEdit = true
472
-        this.canEditUploadRow = Number(data.publishStatus) === PUBLISH_STATUS.UNPUBLISHED
505
+        this.canEditFormRow = this.resolveCanEditFormRow(data)
473
         this.form = {
506
         this.form = {
474
           id: data.id,
507
           id: data.id,
475
           standardName: data.standardName,
508
           standardName: data.standardName,