瀏覽代碼

知识库

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 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 76
 - 标题:`dialogAdd` / `dialogEdit`;`:key="formKey"` 重置表单。
77 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 79
 - 提交 Body:`standardName`、`standardType`、`introduction`、`contentFileUrl`、`contentFilePath`、`contentFileName`、`coverFileUrl`、`coverFilePath`;编辑带 `id`。
80 80
 
81 81
 ### 3.4 查看弹窗
@@ -112,7 +112,7 @@
112 112
 | 组合 | 编辑 | 同步 | 移出 | 发布 | 下架 | 删除 |
113 113
 | --- | --- | --- | --- | --- | --- | --- |
114 114
 | 未发布 + 未同步 | ✓ | ✓ | — | — | — | ✓ |
115
-| 未发布 + 已同步 |  | — | ✓ | ✓ | — | ✗ |
115
+| 未发布 + 已同步 |  | — | ✓ | ✓ | — | ✗ |
116 116
 | 已发布 + 已同步 | ✗ | — | — | — | ✓ | ✗ |
117 117
 
118 118
 **`can*` 方法**(均 `Number()` 比较)+ **`v-hasPermi`** + **`v-if`** 控制按钮。
@@ -129,8 +129,9 @@
129 129
 **交互提示**
130 130
 
131 131
 - 已发布点编辑:`rulePublishedNoEdit`
132
-- 已同步点编辑:`ruleSyncedNoEdit`(或等价提示)
132
+- 已同步点编辑:`ruleSyncedNoEdit`
133 133
 - 已同步点删除:`ruleDeleteNeedRemoveKb`
134
+- 标准类型加载失败:`errStdTypeLoad`
134 135
 - 同步/移出/发布/下架/删除:二次确认后调接口,成功 `getList()` 刷新
135 136
 
136 137
 **状态文案**:`breedingStdLocaleMixin.publishStatusText` / `kbSyncStatusText`;历史 `publishStatus=2` 按「未发布」展示。
@@ -178,7 +179,7 @@
178 179
 
179 180
 1. 标准类型下拉与保存编码(如 `001001`)一致。
180 181
 2. 未发布+未同步:可新增、同步、编辑、删除。
181
-3. 未发布+已同步:不可编辑,可移出、发布;不可删。
182
+3. 未发布+已同步:不可编辑(前端拦截),可移出、发布;不可删。
182 183
 4. 已发布:仅查看、下架;下架后回到未发布+已同步。
183 184
 5. 正文 `contentFileName` 在列表与详情正确展示;双语切换正常。
184 185
 
@@ -201,3 +202,4 @@
201 202
 | 版本 | 说明 |
202 203
 | --- | --- |
203 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 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 11
 | **Vue 路径** | `ruoyi-ui/src/views/breedingStandards/diseaseTreatment/epidemicTreatment/index.vue` |
12 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 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 75
 | 正文附件 | `el-upload` → `/common/upload` | 必填(以 `contentFilePath` 为校验 prop);后缀白名单、≤**30MB**、文件名不含英文逗号 |
76 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 80
 **提交 Body(小驼峰)**
81 81
 
@@ -116,7 +116,7 @@
116 116
 | 查看 | `equipment:workStandard:query` | 有权限即显 |
117 117
 | 同步知识库 | `equipment:workStandard:syncKb` | `publishStatus === 0` 且 `kbSyncStatus === 0` |
118 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 120
 | 删除 | `equipment:workStandard:remove` | `publishStatus === 0` 且 `kbSyncStatus === 0` |
121 121
 | 发布 | `equipment:workStandard:publish` | `publishStatus === 0` 且 `kbSyncStatus === 1` |
122 122
 | 下架 | `equipment:workStandard:offline` | `publishStatus === 1` |
@@ -138,7 +138,7 @@ import { listInformationCategoryChildren } from '@/api/category/informationCateg
138 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 201
 | 列表/表单接口非 200 | 走全局 `request` 拦截器提示(若依默认) |
202
+| 标准类型选项加载失败 | `loadStandardTypeOptions` 捕获异常,`msgError(errStdTypeLoad)`,下拉为空 |
203
+| 已同步记录点编辑 | `msgWarning(ruleSyncedNoEdit)`,不请求详情 |
204
+| 已发布记录点编辑 | `msgWarning(rulePublishedNoEdit)` |
202 205
 | 上传失败 | `msgError`,关闭 loading |
203 206
 | 删除 | 单行传 `id` 至 `delEquipmentWorkStandard`(与总方案 `{ids}` 兼容) |
204 207
 
@@ -208,10 +211,13 @@ import { listInformationCategoryChildren } from '@/api/category/informationCateg
208 211
 
209 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 216
 - [ ] 后端 `/equipment/workStandard/**` 与总方案 **§3** 对齐,分页字段 `rows` / `total`  
217
+- [ ] 存量环境执行 `sql/biz_equipment_work_standard_alter_standard_type.sql` 后列表类型展示正常  
213 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 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 3
 > 依据:`饲喂标准管理技术方案.md`(同目录,下称**总方案**)。本文描述 **Vue 管理端页面**、**接口封装**、**权限字**、**交互与校验**与总方案 **§2 / §3** 的对应关系;库表、状态机与知识库编排以后端总方案为准。
6 4
 
7
-
8
-
9 5
 ---
10 6
 
11
-
12
-
13 7
 ## 1. 技术架构
14 8
 
15
-
16
-
17 9
 | 项 | 说明 |
18
-
19 10
 | --- | --- |
20
-
21 11
 | **工程** | 若依 **RuoYi-Vue** 前端(Vue **2.x** + **Element UI** + **Vue Router** + **Vuex**) |
22
-
23 12
 | **页面路径** | `ruoyi-ui/src/views/breedingStandards/feeding/index.vue` |
24
-
25 13
 | **组件名** | `FeedingManageStandard` |
26
-
27 14
 | **布局参考** | `ruoyi-ui/src/views/breedingStandards/breedingManage/index.vue`(双 `el-card`:查询区 + 表格区;新增/编辑弹窗 + 查看弹窗) |
28
-
29 15
 | **HTTP** | `@/utils/request` 封装 Axios,自动拼接 `VUE_APP_BASE_API`、携带 `Authorization` |
30
-
31 16
 | **时间格式化** | 全局 `parseTime`(若依 `utils/ruoyi` 注入) |
32
-
33 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 23
 ## 2. 源码与路由
46 24
 
47
-
48
-
49 25
 | 类型 | 路径 |
50
-
51 26
 | --- | --- |
52
-
53 27
 | 页面 | `ruoyi-ui/src/views/breedingStandards/feeding/index.vue` |
54
-
55 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 34
 | 组件路径 | `breedingStandards/feeding/index`(与 `views` 下相对路径一致,无前缀 `@/`) |
68
-
69 35
 | 路由名 | 自定,不与现有路由冲突即可 |
70
-
71 36
 | 权限标识 | 与 **§5** 表一致,子菜单按钮 SQL 与总方案交付清单对齐 |
72 37
 
73
-
74
-
75 38
 ---
76 39
 
77
-
78
-
79 40
 ## 3. 页面结构
80 41
 
81
-
82
-
83 42
 ### 3.1 查询区(首卡片)
84 43
 
85
-
86
-
87 44
 | UI | 绑定/说明 |
88
-
89 45
 | --- | --- |
90
-
91 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 50
 ### 3.2 列表区(次卡片)
104 51
 
105
-
106
-
107 52
 | 列 | 数据来源 | 备注 |
108
-
109 53
 | --- | --- | --- |
110
-
111 54
 | 标准名称 | `standardName` | `show-overflow-tooltip` |
112
-
113
-| 标准类型 | `standardType` | `typeLabel`:由 `standardTypeOptions` 按编码映射名称 |
114
-
55
+| 标准类型 | `standardType` | `typeLabel(code)`:由 `standardTypeOptions`(**§6.1**)按编码映射名称 |
115 56
 | 简介 | `introduction` | — |
116
-
117 57
 | 正文附件 | `contentFileUrl` / `contentFileName` | `el-link` 新窗口打开 |
118
-
119 58
 | 上架状态 | `publishStatus` | `publishStatusText` |
120
-
121 59
 | 知识库同步 | `kbSyncStatus` | `kbSyncStatusText` |
122
-
123 60
 | 发布日期 | `publishTime` | `parseTime(..., '{y}-{m}-{d}')`,空为「—」 |
124
-
125 61
 | 创建时间 | `createTime` | `parseTime` 完整格式 |
126
-
127 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 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 72
 | `introduction` | 多行文本,`maxlength=50` | 选填;最多 **50** 字 |
148
-
149
-| 正文附件 | `el-upload` → `/common/upload` | 必填(以 `contentFilePath` 为校验 prop);后缀白名单、≤**30MB**、文件名不含英文逗号 |
150
-
73
+| 正文附件 | `el-upload` → `/common/upload` | 必填;后缀白名单、≤**30MB**、文件名不含英文逗号 |
151 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 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 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 92
 ## 5. 操作按钮与权限
216 93
 
217
-
218
-
219 94
 权限字与总方案 **§3** 一致;按钮同时受 **`v-hasPermi`** 与 **行状态方法** 控制。
220 95
 
221
-
222
-
223 96
 | 按钮 | 权限标识 | 显示条件(与行数据) |
224
-
225 97
 | --- | --- | --- |
226
-
227
-| 查看 | `feeding:standard:query` | 始终(有权限即显) |
228
-
98
+| 查看 | `feeding:standard:query` | 有权限即显 |
229 99
 | 同步知识库 | `feeding:standard:syncKb` | `publishStatus === 0` 且 `kbSyncStatus === 0` |
230
-
231 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 102
 | 删除 | `feeding:standard:remove` | `publishStatus === 0` 且 `kbSyncStatus === 0` |
236
-
237 103
 | 发布 | `feeding:standard:publish` | `publishStatus === 0` 且 `kbSyncStatus === 1` |
238
-
239 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 110
 ## 6. 枚举与展示映射
256 111
 
257
-
258
-
259 112
 ### 6.1 `standardType`(标准类型)
260 113
 
261 114
 页面维护 `standardTypeOptions: []`,`created` 调用 `loadStandardTypeOptions()`:
262 115
 
263 116
 ```javascript
264 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 125
 | `001005` | 饲料配方 |
271 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 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 148
 | 方法(导出) | HTTP | URI |
316
-
317 149
 | --- | --- | --- |
318
-
319 150
 | `listFeedingStandard` | GET | `/feeding/standard/list` |
320
-
321 151
 | `getFeedingStandard` | GET | `/feeding/standard/{id}` |
322
-
323 152
 | `addFeedingStandard` | POST | `/feeding/standard` |
324
-
325 153
 | `updateFeedingStandard` | PUT | `/feeding/standard` |
326
-
327 154
 | `delFeedingStandard` | DELETE | `/feeding/standard/{ids}` |
328
-
329 155
 | `syncKbFeedingStandard` | POST | `/feeding/standard/syncKb/{id}` |
330
-
331 156
 | `removeKbFeedingStandard` | POST | `/feeding/standard/removeKb/{id}` |
332
-
333 157
 | `publishFeedingStandard` | POST | `/feeding/standard/publish/{id}` |
334
-
335 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 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 172
 | 上传失败 | `msgError`,关闭 loading |
360 173
 
361
-| 删除 | 单行传 `id` 至 `delFeedingStandard`(与总方案 `{ids}` 兼容) |
362
-
363
-
364
-
365
-不在前端重复实现知识库重试;失败以后端 `msg` 为准。
366
-
367
-
368
-
369 174
 ---
370 175
 
371
-
372
-
373 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 187
 ## 10. 文档修订记录
392 188
 
393
-
394
-
395 189
 | 版本 | 日期 | 说明 |
396
-
397 190
 | --- | --- | --- |
398
-
399 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 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 13
 export function listInformationCategoryChildren(parentCode, categoryType) {
5 14
   return request({

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

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

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

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

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

@@ -43,7 +43,7 @@
43 43
     <el-card shadow="never">
44 44
       <el-table v-loading="loading" :data="tableList" border>
45 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 47
           <template slot-scope="scope">
48 48
             <span>{{ typeLabel(scope.row.standardType) }}</span>
49 49
           </template>
@@ -146,11 +146,22 @@
146 146
       <el-form :key="formKey" ref="form" :model="form" label-width="100px">
147 147
         <el-form-item prop="standardName" :rules="formRules.standardName">
148 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 156
         </el-form-item>
151 157
         <el-form-item prop="standardType" :rules="formRules.standardType">
152 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 165
             <el-option
155 166
               v-for="item in standardTypeOptions"
156 167
               :key="item.value"
@@ -168,6 +179,7 @@
168 179
             :placeholder="stdT('phFileIntro')"
169 180
             maxlength="50"
170 181
             show-word-limit
182
+            :disabled="dialogEdit && !canEditFormRow"
171 183
           />
172 184
         </el-form-item>
173 185
         <el-form-item prop="contentFilePath" :rules="formRules.contentFilePath">
@@ -180,9 +192,9 @@
180 192
             :on-success="handleContentUploadSuccess"
181 193
             :on-error="handleUploadHttpError"
182 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 198
           </el-upload>
187 199
           <div class="el-upload__tip">
188 200
             {{ $t('breedingStd.common.tipBody') }}
@@ -193,7 +205,7 @@
193 205
                 <span class="el-icon-document"> {{ form.contentFileName }} </span>
194 206
               </el-link>
195 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 209
               </div>
198 210
             </li>
199 211
           </ul>
@@ -211,7 +223,7 @@
211 223
             :on-remove="handleCoverRemove"
212 224
             :limit="1"
213 225
             :file-list="coverFileList"
214
-            :disabled="dialogEdit && !canEditUploadRow"
226
+            :disabled="dialogEdit && !canEditFormRow"
215 227
           >
216 228
             <i class="el-icon-plus"></i>
217 229
           </el-upload>
@@ -308,7 +320,7 @@ export default {
308 320
       viewOpen: false,
309 321
       viewRow: {},
310 322
       dialogEdit: false,
311
-      canEditUploadRow: true,
323
+      canEditFormRow: true,
312 324
       formKey: 0,
313 325
       total: 0,
314 326
       tableList: [],
@@ -371,10 +383,15 @@ export default {
371 383
       }
372 384
     },
373 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 396
     typeLabel(val) {
380 397
       if (val == null || val === "") {
@@ -392,7 +409,10 @@ export default {
392 409
       return key
393 410
     },
394 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 417
     canSyncKb(row) {
398 418
       return (
@@ -460,13 +480,26 @@ export default {
460 480
       this.formKey += 1
461 481
       this.resetFormModel()
462 482
       this.dialogEdit = false
463
-      this.canEditUploadRow = true
483
+      this.canEditFormRow = true
464 484
       this.open = true
465 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 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 502
       if (!this.canEdit(row)) {
469
-        this.$modal.msgWarning(this.$t("breedingStd.bm.rulePublishedNoEdit"))
470 503
         return
471 504
       }
472 505
       const id = row.id
@@ -474,7 +507,7 @@ export default {
474 507
         const data = res.data || {}
475 508
         this.formKey += 1
476 509
         this.dialogEdit = true
477
-        this.canEditUploadRow = Number(data.publishStatus) === PUBLISH_STATUS.UNPUBLISHED
510
+        this.canEditFormRow = this.resolveCanEditFormRow(data)
478 511
         this.form = {
479 512
           id: data.id,
480 513
           standardName: data.standardName,
@@ -523,11 +556,11 @@ export default {
523 556
     },
524 557
     handleDelete(row) {
525 558
       if (!this.canDelete(row)) {
526
-        this.$modal.msgWarning(this.$t("breedingStd.bm.ruleDeleteNeedRemoveKb"))
559
+        this.$modal.msgWarning(this.stdT("ruleDeleteNeedRemoveKb"))
527 560
         return
528 561
       }
529 562
       this.$modal
530
-        .confirm(this.$t("breedingStd.bm.confirmDelete", { id: row.id }))
563
+        .confirm(this.stdT("confirmDelete", { id: row.id }))
531 564
         .then(() => delBreedingStandard(row.id))
532 565
         .then(() => {
533 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 279
     canEdit(row) {
280
-      return row.kbSyncStatus === KB_SYNC_STATUS.UNSYNCED
280
+      return Number(row.kbSyncStatus) === KB_SYNC_STATUS.UNSYNCED
281 281
     },
282 282
     canDelete(row) {
283
-      return row.kbSyncStatus === KB_SYNC_STATUS.UNSYNCED
283
+      return Number(row.kbSyncStatus) === KB_SYNC_STATUS.UNSYNCED
284 284
     },
285 285
     canSyncKb(row) {
286
-      return row.kbSyncStatus === KB_SYNC_STATUS.UNSYNCED
286
+      return Number(row.kbSyncStatus) === KB_SYNC_STATUS.UNSYNCED
287 287
     },
288 288
     canRemoveKb(row) {
289
-      return row.kbSyncStatus === KB_SYNC_STATUS.SYNCED
289
+      return Number(row.kbSyncStatus) === KB_SYNC_STATUS.SYNCED
290 290
     },
291 291
     getList() {
292 292
       this.loading = true
@@ -335,6 +335,10 @@ export default {
335 335
       this.$nextTick(() => this.resetForm("form"))
336 336
     },
337 337
     handleEdit(row) {
338
+      if (Number(row.kbSyncStatus) === KB_SYNC_STATUS.SYNCED) {
339
+        this.$modal.msgWarning(this.stdT("ruleSyncedNoEdit"))
340
+        return
341
+      }
338 342
       if (!this.canEdit(row)) {
339 343
         return
340 344
       }
@@ -386,8 +390,12 @@ export default {
386 390
         .catch(() => {})
387 391
     },
388 392
     handleDelete(row) {
393
+      if (!this.canDelete(row)) {
394
+        this.$modal.msgWarning(this.stdT("ruleDeleteNeedRemoveKb"))
395
+        return
396
+      }
389 397
       this.$modal
390
-        .confirm(this.$t("breedingStd.dic.confirmDelete", { id: row.id }))
398
+        .confirm(this.stdT("confirmDelete", { id: row.id }))
391 399
         .then(() => delDrugIncompatibilityStandard(row.id))
392 400
         .then(() => {
393 401
           this.$modal.msgSuccess(this.stdT("msgDelOk"))

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

@@ -43,7 +43,7 @@
43 43
     <el-card shadow="never">
44 44
       <el-table v-loading="loading" :data="tableList" border>
45 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 47
           <template slot-scope="scope">
48 48
             <span>{{ typeLabel(scope.row.standardType) }}</span>
49 49
           </template>
@@ -146,11 +146,22 @@
146 146
       <el-form :key="formKey" ref="form" :model="form" label-width="100px">
147 147
         <el-form-item prop="standardName" :rules="formRules.standardName">
148 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 156
         </el-form-item>
151 157
         <el-form-item prop="standardType" :rules="formRules.standardType">
152 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 165
             <el-option
155 166
               v-for="item in standardTypeOptions"
156 167
               :key="item.value"
@@ -168,6 +179,7 @@
168 179
             :placeholder="$t('breedingStd.common.phIntroOptional')"
169 180
             maxlength="50"
170 181
             show-word-limit
182
+            :disabled="dialogEdit && !canEditFormRow"
171 183
           />
172 184
         </el-form-item>
173 185
         <el-form-item prop="contentFilePath" :rules="formRules.contentFilePath">
@@ -180,9 +192,9 @@
180 192
             :on-success="handleContentUploadSuccess"
181 193
             :on-error="handleUploadHttpError"
182 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 198
           </el-upload>
187 199
           <div class="el-upload__tip">{{ $t('breedingStd.common.tipBody') }}</div>
188 200
           <ul v-if="form.contentFilePath" class="upload-file-list el-upload-list el-upload-list--text">
@@ -191,7 +203,7 @@
191 203
                 <span class="el-icon-document"> {{ form.contentFileName }} </span>
192 204
               </el-link>
193 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 207
               </div>
196 208
             </li>
197 209
           </ul>
@@ -209,7 +221,7 @@
209 221
             :on-remove="handleCoverRemove"
210 222
             :limit="1"
211 223
             :file-list="coverFileList"
212
-            :disabled="dialogEdit && !canEditUploadRow"
224
+            :disabled="dialogEdit && !canEditFormRow"
213 225
           >
214 226
             <i class="el-icon-plus"></i>
215 227
           </el-upload>
@@ -303,7 +315,7 @@ export default {
303 315
       viewOpen: false,
304 316
       viewRow: {},
305 317
       dialogEdit: false,
306
-      canEditUploadRow: true,
318
+      canEditFormRow: true,
307 319
       formKey: 0,
308 320
       total: 0,
309 321
       tableList: [],
@@ -365,10 +377,15 @@ export default {
365 377
       }
366 378
     },
367 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 390
     typeLabel(val) {
374 391
       if (val == null || val === "") {
@@ -386,7 +403,10 @@ export default {
386 403
       return key
387 404
     },
388 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 411
     canSyncKb(row) {
392 412
       return (
@@ -454,13 +474,26 @@ export default {
454 474
       this.formKey += 1
455 475
       this.resetFormModel()
456 476
       this.dialogEdit = false
457
-      this.canEditUploadRow = true
477
+      this.canEditFormRow = true
458 478
       this.open = true
459 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 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 496
       if (!this.canEdit(row)) {
463
-        this.$modal.msgWarning(this.$t("breedingStd.ep.rulePublishedNoEdit"))
464 497
         return
465 498
       }
466 499
       const id = row.id
@@ -468,7 +501,7 @@ export default {
468 501
         const data = res.data || {}
469 502
         this.formKey += 1
470 503
         this.dialogEdit = true
471
-        this.canEditUploadRow = Number(data.publishStatus) === PUBLISH_STATUS.UNPUBLISHED
504
+        this.canEditFormRow = this.resolveCanEditFormRow(data)
472 505
         this.form = {
473 506
           id: data.id,
474 507
           standardName: data.standardName,
@@ -517,11 +550,11 @@ export default {
517 550
     },
518 551
     handleDelete(row) {
519 552
       if (!this.canDelete(row)) {
520
-        this.$modal.msgWarning(this.$t("breedingStd.ep.ruleDeleteNeedRemoveKb"))
553
+        this.$modal.msgWarning(this.stdT("ruleDeleteNeedRemoveKb"))
521 554
         return
522 555
       }
523 556
       this.$modal
524
-        .confirm(this.$t("breedingStd.ep.confirmDelete", { id: row.id }))
557
+        .confirm(this.stdT("confirmDelete", { id: row.id }))
525 558
         .then(() => delEpidemicTreatmentStandard(row.id))
526 559
         .then(() => {
527 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 294
   methods: {
295 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 303
     canEdit(row) {
300
-      return row.kbSyncStatus === KB_SYNC_STATUS.UNSYNCED
304
+      return Number(row.kbSyncStatus) === KB_SYNC_STATUS.UNSYNCED
301 305
     },
302 306
     canDelete(row) {
303
-      return row.kbSyncStatus === KB_SYNC_STATUS.UNSYNCED
307
+      return Number(row.kbSyncStatus) === KB_SYNC_STATUS.UNSYNCED
304 308
     },
305 309
     canSyncKb(row) {
306
-      return row.kbSyncStatus === KB_SYNC_STATUS.UNSYNCED
310
+      return Number(row.kbSyncStatus) === KB_SYNC_STATUS.UNSYNCED
307 311
     },
308 312
     canRemoveKb(row) {
309
-      return row.kbSyncStatus === KB_SYNC_STATUS.SYNCED
313
+      return Number(row.kbSyncStatus) === KB_SYNC_STATUS.SYNCED
310 314
     },
311 315
     getList() {
312 316
       this.loading = true
@@ -347,6 +351,10 @@ export default {
347 351
       this.$nextTick(() => this.resetForm("form"))
348 352
     },
349 353
     handleEdit(row) {
354
+      if (Number(row.kbSyncStatus) === KB_SYNC_STATUS.SYNCED) {
355
+        this.$modal.msgWarning(this.stdT("ruleSyncedNoEdit"))
356
+        return
357
+      }
350 358
       if (!this.canEdit(row)) {
351 359
         return
352 360
       }
@@ -397,8 +405,12 @@ export default {
397 405
         .catch(() => {})
398 406
     },
399 407
     handleDelete(row) {
408
+      if (!this.canDelete(row)) {
409
+        this.$modal.msgWarning(this.stdT("ruleDeleteNeedRemoveKb"))
410
+        return
411
+      }
400 412
       this.$modal
401
-        .confirm(this.$t("breedingStd.wp.confirmDelete", { id: row.id }))
413
+        .confirm(this.stdT("confirmDelete", { id: row.id }))
402 414
         .then(() => delWithdrawalPeriodStandard(row.id))
403 415
         .then(() => {
404 416
           this.$modal.msgSuccess(this.stdT("msgDelOk"))
@@ -411,8 +423,9 @@ export default {
411 423
         if (!valid) {
412 424
           return
413 425
         }
426
+        const drugName = typeof this.form.drugName === "string" ? this.form.drugName.trim() : this.form.drugName
414 427
         const payload = {
415
-          drugName: this.form.drugName,
428
+          drugName,
416 429
           drugType: this.form.drugType,
417 430
           withdrawalDays: this.form.withdrawalDays,
418 431
           usageGuide: this.form.usageGuide,

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

@@ -43,7 +43,7 @@
43 43
     <el-card shadow="never">
44 44
       <el-table v-loading="loading" :data="tableList" border>
45 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 47
           <template slot-scope="scope">
48 48
             <span>{{ typeLabel(scope.row.standardType) }}</span>
49 49
           </template>
@@ -146,11 +146,22 @@
146 146
       <el-form :key="formKey" ref="form" :model="form" label-width="100px">
147 147
         <el-form-item prop="standardName" :rules="formRules.standardName">
148 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 156
         </el-form-item>
151 157
         <el-form-item prop="standardType" :rules="formRules.standardType">
152 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 165
             <el-option
155 166
               v-for="item in standardTypeOptions"
156 167
               :key="item.value"
@@ -168,6 +179,7 @@
168 179
             :placeholder="$t('breedingStd.common.phIntroOptional')"
169 180
             maxlength="50"
170 181
             show-word-limit
182
+            :disabled="dialogEdit && !canEditFormRow"
171 183
           />
172 184
         </el-form-item>
173 185
         <el-form-item prop="contentFilePath" :rules="formRules.contentFilePath">
@@ -180,9 +192,9 @@
180 192
             :on-success="handleContentUploadSuccess"
181 193
             :on-error="handleUploadHttpError"
182 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 198
           </el-upload>
187 199
           <div class="el-upload__tip">{{ $t('breedingStd.common.tipBody') }}</div>
188 200
           <ul v-if="form.contentFilePath" class="upload-file-list el-upload-list el-upload-list--text">
@@ -191,7 +203,7 @@
191 203
                 <span class="el-icon-document"> {{ form.contentFileName }} </span>
192 204
               </el-link>
193 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 207
               </div>
196 208
             </li>
197 209
           </ul>
@@ -209,7 +221,7 @@
209 221
             :on-remove="handleCoverRemove"
210 222
             :limit="1"
211 223
             :file-list="coverFileList"
212
-            :disabled="dialogEdit && !canEditUploadRow"
224
+            :disabled="dialogEdit && !canEditFormRow"
213 225
           >
214 226
             <i class="el-icon-plus"></i>
215 227
           </el-upload>
@@ -306,7 +318,7 @@ export default {
306 318
       viewOpen: false,
307 319
       viewRow: {},
308 320
       dialogEdit: false,
309
-      canEditUploadRow: true,
321
+      canEditFormRow: true,
310 322
       formKey: 0,
311 323
       total: 0,
312 324
       tableList: [],
@@ -368,10 +380,15 @@ export default {
368 380
       }
369 381
     },
370 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 393
     typeLabel(val) {
377 394
       if (val == null || val === "") {
@@ -389,7 +406,10 @@ export default {
389 406
       return key
390 407
     },
391 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 414
     canSyncKb(row) {
395 415
       return (
@@ -457,21 +477,34 @@ export default {
457 477
       this.formKey += 1
458 478
       this.resetFormModel()
459 479
       this.dialogEdit = false
460
-      this.canEditUploadRow = true
480
+      this.canEditFormRow = true
461 481
       this.open = true
462 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 490
     handleEdit(row) {
465
-      if (!this.canEdit(row)) {
491
+      if (Number(row.publishStatus) === PUBLISH_STATUS.PUBLISHED) {
466 492
         this.$modal.msgWarning(this.$t("breedingStd.eqp.rulePublishedNoEdit"))
467 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 502
       const id = row.id
470 503
       getEquipmentWorkStandard(id).then((res) => {
471 504
         const data = res.data || {}
472 505
         this.formKey += 1
473 506
         this.dialogEdit = true
474
-        this.canEditUploadRow = Number(data.publishStatus) === PUBLISH_STATUS.UNPUBLISHED
507
+        this.canEditFormRow = this.resolveCanEditFormRow(data)
475 508
         this.form = {
476 509
           id: data.id,
477 510
           standardName: data.standardName,

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

@@ -43,7 +43,7 @@
43 43
     <el-card shadow="never">
44 44
       <el-table v-loading="loading" :data="tableList" border>
45 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 47
           <template slot-scope="scope">
48 48
             <span>{{ typeLabel(scope.row.standardType) }}</span>
49 49
           </template>
@@ -146,11 +146,22 @@
146 146
       <el-form :key="formKey" ref="form" :model="form" label-width="100px">
147 147
         <el-form-item prop="standardName" :rules="formRules.standardName">
148 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 156
         </el-form-item>
151 157
         <el-form-item prop="standardType" :rules="formRules.standardType">
152 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 165
             <el-option
155 166
               v-for="item in standardTypeOptions"
156 167
               :key="item.value"
@@ -168,6 +179,7 @@
168 179
             :placeholder="$t('breedingStd.common.phIntroOptional')"
169 180
             maxlength="50"
170 181
             show-word-limit
182
+            :disabled="dialogEdit && !canEditFormRow"
171 183
           />
172 184
         </el-form-item>
173 185
         <el-form-item prop="contentFilePath" :rules="formRules.contentFilePath">
@@ -180,9 +192,9 @@
180 192
             :on-success="handleContentUploadSuccess"
181 193
             :on-error="handleUploadHttpError"
182 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 198
           </el-upload>
187 199
           <div class="el-upload__tip">{{ $t('breedingStd.common.tipBody') }}</div>
188 200
           <ul v-if="form.contentFilePath" class="upload-file-list el-upload-list el-upload-list--text">
@@ -191,7 +203,7 @@
191 203
                 <span class="el-icon-document"> {{ form.contentFileName }} </span>
192 204
               </el-link>
193 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 207
               </div>
196 208
             </li>
197 209
           </ul>
@@ -209,7 +221,7 @@
209 221
             :on-remove="handleCoverRemove"
210 222
             :limit="1"
211 223
             :file-list="coverFileList"
212
-            :disabled="dialogEdit && !canEditUploadRow"
224
+            :disabled="dialogEdit && !canEditFormRow"
213 225
           >
214 226
             <i class="el-icon-plus"></i>
215 227
           </el-upload>
@@ -304,7 +316,7 @@ export default {
304 316
       viewOpen: false,
305 317
       viewRow: {},
306 318
       dialogEdit: false,
307
-      canEditUploadRow: true,
319
+      canEditFormRow: true,
308 320
       formKey: 0,
309 321
       total: 0,
310 322
       tableList: [],
@@ -366,10 +378,15 @@ export default {
366 378
       }
367 379
     },
368 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 391
     typeLabel(val) {
375 392
       if (val == null || val === "") {
@@ -387,7 +404,10 @@ export default {
387 404
       return key
388 405
     },
389 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 412
     canSyncKb(row) {
393 413
       return (
@@ -455,21 +475,34 @@ export default {
455 475
       this.formKey += 1
456 476
       this.resetFormModel()
457 477
       this.dialogEdit = false
458
-      this.canEditUploadRow = true
478
+      this.canEditFormRow = true
459 479
       this.open = true
460 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 488
     handleEdit(row) {
463
-      if (!this.canEdit(row)) {
489
+      if (Number(row.publishStatus) === PUBLISH_STATUS.PUBLISHED) {
464 490
         this.$modal.msgWarning(this.$t("breedingStd.feed.rulePublishedNoEdit"))
465 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 500
       const id = row.id
468 501
       getFeedingStandard(id).then((res) => {
469 502
         const data = res.data || {}
470 503
         this.formKey += 1
471 504
         this.dialogEdit = true
472
-        this.canEditUploadRow = Number(data.publishStatus) === PUBLISH_STATUS.UNPUBLISHED
505
+        this.canEditFormRow = this.resolveCanEditFormRow(data)
473 506
         this.form = {
474 507
           id: data.id,
475 508
           standardName: data.standardName,

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

@@ -43,7 +43,7 @@
43 43
     <el-card shadow="never">
44 44
       <el-table v-loading="loading" :data="tableList" border>
45 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 47
           <template slot-scope="scope">
48 48
             <span>{{ typeLabel(scope.row.standardType) }}</span>
49 49
           </template>
@@ -146,11 +146,22 @@
146 146
       <el-form :key="formKey" ref="form" :model="form" label-width="100px">
147 147
         <el-form-item prop="standardName" :rules="formRules.standardName">
148 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 156
         </el-form-item>
151 157
         <el-form-item prop="standardType" :rules="formRules.standardType">
152 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 165
             <el-option
155 166
               v-for="item in standardTypeOptions"
156 167
               :key="item.value"
@@ -168,6 +179,7 @@
168 179
             :placeholder="$t('breedingStd.common.phIntroOptional')"
169 180
             maxlength="50"
170 181
             show-word-limit
182
+            :disabled="dialogEdit && !canEditFormRow"
171 183
           />
172 184
         </el-form-item>
173 185
         <el-form-item prop="contentFilePath" :rules="formRules.contentFilePath">
@@ -180,9 +192,9 @@
180 192
             :on-success="handleContentUploadSuccess"
181 193
             :on-error="handleUploadHttpError"
182 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 198
           </el-upload>
187 199
           <div class="el-upload__tip">{{ $t('breedingStd.common.tipBody') }}</div>
188 200
           <ul v-if="form.contentFilePath" class="upload-file-list el-upload-list el-upload-list--text">
@@ -191,7 +203,7 @@
191 203
                 <span class="el-icon-document"> {{ form.contentFileName }} </span>
192 204
               </el-link>
193 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 207
               </div>
196 208
             </li>
197 209
           </ul>
@@ -209,7 +221,7 @@
209 221
             :on-remove="handleCoverRemove"
210 222
             :limit="1"
211 223
             :file-list="coverFileList"
212
-            :disabled="dialogEdit && !canEditUploadRow"
224
+            :disabled="dialogEdit && !canEditFormRow"
213 225
           >
214 226
             <i class="el-icon-plus"></i>
215 227
           </el-upload>
@@ -304,7 +316,7 @@ export default {
304 316
       viewOpen: false,
305 317
       viewRow: {},
306 318
       dialogEdit: false,
307
-      canEditUploadRow: true,
319
+      canEditFormRow: true,
308 320
       formKey: 0,
309 321
       total: 0,
310 322
       tableList: [],
@@ -366,10 +378,15 @@ export default {
366 378
       }
367 379
     },
368 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 391
     typeLabel(val) {
375 392
       if (val == null || val === "") {
@@ -387,7 +404,10 @@ export default {
387 404
       return key
388 405
     },
389 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 412
     canSyncKb(row) {
393 413
       return (
@@ -455,21 +475,34 @@ export default {
455 475
       this.formKey += 1
456 476
       this.resetFormModel()
457 477
       this.dialogEdit = false
458
-      this.canEditUploadRow = true
478
+      this.canEditFormRow = true
459 479
       this.open = true
460 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 488
     handleEdit(row) {
463
-      if (!this.canEdit(row)) {
489
+      if (Number(row.publishStatus) === PUBLISH_STATUS.PUBLISHED) {
464 490
         this.$modal.msgWarning(this.$t("breedingStd.growth.rulePublishedNoEdit"))
465 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 500
       const id = row.id
468 501
       getGrowthSlaughterStandard(id).then((res) => {
469 502
         const data = res.data || {}
470 503
         this.formKey += 1
471 504
         this.dialogEdit = true
472
-        this.canEditUploadRow = Number(data.publishStatus) === PUBLISH_STATUS.UNPUBLISHED
505
+        this.canEditFormRow = this.resolveCanEditFormRow(data)
473 506
         this.form = {
474 507
           id: data.id,
475 508
           standardName: data.standardName,