2 Коммиты ef65fad876 ... f26dd7b185

Автор SHA1 Сообщение Дата
  xsh_1997 f26dd7b185 123 недель назад: 2
  xsh_1997 f6a4d94d65 123 недель назад: 2
29 измененных файлов с 5625 добавлено и 325 удалено
  1. 121 0
      doc/产业数据模型及服务/养殖大户数据填报/养殖大户数据填报前端技术方案.md
  2. 2 1
      doc/产业数据模型及服务/养殖大户数据填报/养殖大户数据填报技术方案.md
  3. 114 0
      doc/产业数据模型及服务/农牧户数据填报/农牧户数据填报前端技术方案.md
  4. 1 0
      doc/产业数据模型及服务/农牧户数据填报/农牧户数据填报技术方案.md
  5. 2 1
      doc/产业数据模型及服务/可支配收入数据填报/可支配收入数据填报前端技术方案.md
  6. 226 0
      doc/产业数据模型及服务/疫苗接种数据填报/疫苗接种数据填报前端技术方案.md
  7. 5 0
      doc/产业数据模型及服务/疫苗接种数据填报/疫苗接种数据填报功能需求.md
  8. 2 0
      doc/产业数据模型及服务/疫苗接种数据填报/疫苗接种数据填报技术方案.md
  9. 1 0
      doc/产业数据模型及服务/疫苗接种数据填报/疫苗接种数据填报测试用例.md
  10. 120 0
      ruoyi-ui/src/api/dataModel/farmerHousehold.js
  11. 120 0
      ruoyi-ui/src/api/dataModel/largeLivestockFarmer.js
  12. 120 0
      ruoyi-ui/src/api/dataModel/vaccinationData.js
  13. 7 0
      ruoyi-ui/src/assets/styles/data-model.scss
  14. 1 0
      ruoyi-ui/src/assets/styles/index.scss
  15. 17 15
      ruoyi-ui/src/lang/bo/commonProsperity.js
  16. 323 46
      ruoyi-ui/src/lang/bo/dataModel.js
  17. 17 15
      ruoyi-ui/src/lang/zh/commonProsperity.js
  18. 324 47
      ruoyi-ui/src/lang/zh/dataModel.js
  19. 3 1
      ruoyi-ui/src/mixins/dataModelLocaleMixin.js
  20. 79 43
      ruoyi-ui/src/views/commonProsperity/project/index.vue
  21. 163 51
      ruoyi-ui/src/views/dataModel/cooperativeDevelopment/index.vue
  22. 24 10
      ruoyi-ui/src/views/dataModel/disposableIncome/index.vue
  23. 222 54
      ruoyi-ui/src/views/dataModel/familyRanch/index.vue
  24. 1030 0
      ruoyi-ui/src/views/dataModel/farmerHousehold/index.vue
  25. 1365 0
      ruoyi-ui/src/views/dataModel/largeLivestockFarmer/index.vue
  26. 12 1
      ruoyi-ui/src/views/dataModel/livestockProductOutput/index.vue
  27. 834 0
      ruoyi-ui/src/views/dataModel/vaccinationData/index.vue
  28. 316 31
      ruoyi-ui/src/views/dataModel/yakHerdInventory/index.vue
  29. 54 9
      ruoyi-ui/src/views/dataModel/yakOutboundReport/index.vue

+ 121 - 0
doc/产业数据模型及服务/养殖大户数据填报/养殖大户数据填报前端技术方案.md

@@ -0,0 +1,121 @@
1
+# 养殖大户数据填报 — 前端技术方案
2
+
3
+> 依据:同目录功能需求、技术方案;交互对齐家庭牧场村级填报;字段 **小驼峰**。
4
+
5
+---
6
+
7
+## 1. 页面与路由
8
+
9
+| 项 | 说明 |
10
+| --- | --- |
11
+| **Vue 路径** | `ruoyi-ui/src/views/dataModel/largeLivestockFarmer/index.vue` |
12
+| **组件名** | `LargeLivestockFarmer` |
13
+| **菜单配置** | 组件路径:`dataModel/largeLivestockFarmer/index` |
14
+| **权限前缀** | `dataModel:largeLivestockFarmer:list\|query\|add\|edit\|remove\|import\|export` |
15
+
16
+---
17
+
18
+## 2. API 模块
19
+
20
+| 项 | 说明 |
21
+| --- | --- |
22
+| **文件** | `ruoyi-ui/src/api/dataModel/largeLivestockFarmer.js` |
23
+| **Base** | `/dataModel/largeLivestockFarmer` |
24
+
25
+CRUD、`yearOptions` / `monthOptions` / `townOptions` / `villageTree`、导入 `importData`、模板 `importTemplate`、导出 `export`(可选 `townDeptId`)与家庭牧场模块同构;模板/导出均为 **GET + blob**。
26
+
27
+| 方法 | 路径 | 说明 |
28
+| --- | --- | --- |
29
+| `listLargeLivestockFarmer` | GET `/list` | 分页;筛选年、月、乡镇、企业名称 |
30
+| `getLargeLivestockFarmer` | GET `/{id}` | 详情 |
31
+| `addLargeLivestockFarmer` | POST `/` | 新增 |
32
+| `updateLargeLivestockFarmer` | PUT `/` | 修改 |
33
+| `delLargeLivestockFarmer` | DELETE `/{ids}` | 删除 |
34
+| `listLargeLivestockFarmerYearOptions` | GET `/yearOptions` | 年份下拉 |
35
+| `listLargeLivestockFarmerMonthOptions` | GET `/monthOptions` | 月份下拉 |
36
+| `listLargeLivestockFarmerTownOptions` | GET `/townOptions` | 乡镇下拉 |
37
+| `listLargeLivestockFarmerVillageTree` | GET `/villageTree` | 县→乡镇→村树 |
38
+| `importLargeLivestockFarmer` | POST `/importData` | FormData:`file` + `statYear` + `statMonth` |
39
+| `downloadLargeLivestockFarmerTemplate` | GET `/importTemplate` | 模板 blob |
40
+| `exportLargeLivestockFarmer` | GET `/export` | 参数:`statYear`、`statMonth`、可选 `townDeptId` |
41
+
42
+---
43
+
44
+## 3. 页面结构
45
+
46
+1. **筛选**:年、月、乡镇、企业名称(无村筛选,与需求一致)。  
47
+2. **列表**:年、月、乡镇、村、企业、法人、类型、注册资本、成立时间、牛存栏、牛出栏、草场面积(`grasslandAreaSubtotal`)、操作。  
48
+3. **新增/编辑**:选村(可搜索,标签「乡镇 / 村」);企业类型默认「个体工商户」、销售渠道默认「其他」;成立时间 `el-date-picker`(`yyyy-MM-dd`);补助资金年份 `type="year"`(`yyyy`);派生字段只读展示。  
49
+4. **详情**:全部字段含派生 + 乡镇只读;数值用 `formatWithUnit` 带单位。  
50
+5. **导入**:选年月 → upsert 摘要(insert/update/fail)。  
51
+6. **导出**:选年月;所属乡镇与列表共用选项与文案,打开时带入列表当前乡镇,清空=全部。
52
+
53
+### 表单分区
54
+
55
+| 分区 | 内容 |
56
+| --- | --- |
57
+| 基本信息 | 年月、村、企业名称、法人、类型、注册资本、成立时间、劳力人数 |
58
+| 存栏与出栏 | 牛/羊存栏与能繁、牛/羊出栏;只读存栏小计 |
59
+| 草场与草畜平衡 | 草畜平衡面积、流转面积、核定载畜量、存栏绵羊单位;只读草场面积小计、是否草畜平衡户 |
60
+| 经营与补助 | 收入、支出、只读利润;补助年份/是否/金额 |
61
+| 其他 | 商标、质量认证、销售渠道、带动人数、工资、备注 |
62
+
63
+---
64
+
65
+## 4. 业务规则
66
+
67
+| 规则 | 实现 |
68
+| --- | --- |
69
+| 必填 | 年、月、村、企业名称 |
70
+| 提交 | 只传 `villageDeptId` 与录入项;乡镇与派生由后端计算 |
71
+| 前端只读派生 | 存栏小计、草场面积小计、利润、是否草畜平衡户(与后端公式一致,便于预览) |
72
+| 是/否 | `hasSubsidy` / `hasTrademark` / `hasQualityCert` 单选「是」「否」 |
73
+| 枚举 | 企业类型、销售渠道与后端 `LargeLivestockFarmerValidation` 一致 |
74
+| 不可未来月 | 表单 / 导入 / 导出校验 |
75
+| 草畜失衡预警 | 由后端写入 `biz_yak_disease_warning`;前端不单独处理 |
76
+
77
+### 枚举取值
78
+
79
+- **企业类型**:个体工商户 / 个人独资企业 / 有限责任公司 / 合伙企业 / 其他(默认个体工商户)  
80
+- **销售渠道**:其他 / 线上销售 / 线下集市 / 企事业单位 / 商超门店(默认其他)
81
+
82
+### 派生预览公式(与后端一致)
83
+
84
+- 存栏小计 = 牛年底存栏 + 羊年底存栏  
85
+- 草场面积小计 = 草畜平衡面积 + 流转经营草地面积  
86
+- 利润 = 收入 − 支出(任一侧为空则不展示)  
87
+- 是否草畜平衡户:核定载畜量 ≥ 年底存栏绵羊单位 →「是」,否则「否」(缺一侧则「—」)
88
+
89
+---
90
+
91
+## 5. 国际化
92
+
93
+`dataModel.largeLivestockFarmer`(`lang/zh|bo/dataModel.js`);页面 `dmNs = 'largeLivestockFarmer'`,复用 `dataModelLocaleMixin`(`dmT` / `dmCommon` / `formatWithUnit`)。
94
+
95
+---
96
+
97
+## 6. 联调说明
98
+
99
+1. 执行 `sql/biz_large_livestock_farmer.sql`。  
100
+2. 菜单组件 `dataModel/largeLivestockFarmer/index`,权限见 §1。  
101
+3. 验证:默认类型/渠道、派生只读、导出乡镇带入列表筛选、草畜失衡写入疾病预警(后端)。
102
+
103
+---
104
+
105
+## 7. 文件清单
106
+
107
+| 类型 | 路径 |
108
+| --- | --- |
109
+| 页面 | `ruoyi-ui/src/views/dataModel/largeLivestockFarmer/index.vue` |
110
+| API | `ruoyi-ui/src/api/dataModel/largeLivestockFarmer.js` |
111
+| i18n | `lang/zh/dataModel.js`、`lang/bo/dataModel.js` → `largeLivestockFarmer` |
112
+| 前端技术方案 | 本文档 |
113
+
114
+---
115
+
116
+## 8. 修订记录
117
+
118
+| 版本 | 说明 |
119
+| --- | --- |
120
+| 1.0 | 初版:村×年月×企业;CRUD + 导入 upsert + 导出乡镇与列表联动;对齐家庭牧场前端交互 |
121
+| 1.1 | 与需求 1.1 一致:导出所属乡镇打开带入列表筛选、可清空表示全部 |

+ 2 - 1
doc/产业数据模型及服务/养殖大户数据填报/养殖大户数据填报技术方案.md

@@ -43,7 +43,8 @@ Base Path:`/dataModel/largeLivestockFarmer`
43 43
 - 页面:`ruoyi-ui/src/views/dataModel/largeLivestockFarmer/index.vue`
44 44
 - API:`ruoyi-ui/src/api/dataModel/largeLivestockFarmer.js`
45 45
 - 菜单组件:`dataModel/largeLivestockFarmer/index`
46
-- 村选择:级联树(县→乡镇→村),仅选叶子村
46
+- i18n:`dataModel.largeLivestockFarmer`(详见同目录《养殖大户数据填报前端技术方案》)
47
+- 村选择:可搜索下拉(县→乡镇→村树展平),仅选叶子村
47 48
 - **导出弹窗所属乡镇**:
48 49
   - 与列表共用 `townOptions`、文案「所属乡镇」、占位「请选择」
49 50
   - 打开导出时带入列表当前 `queryParams.townDeptId`;清空则不传 `townDeptId`(导出全部乡镇)

+ 114 - 0
doc/产业数据模型及服务/农牧户数据填报/农牧户数据填报前端技术方案.md

@@ -0,0 +1,114 @@
1
+# 农牧户数据填报 — 前端技术方案
2
+
3
+> 依据:同目录功能需求、技术方案;交互对齐畜牧产品产量等村×年月填报;字段 **小驼峰**。
4
+
5
+---
6
+
7
+## 1. 页面与路由
8
+
9
+| 项 | 说明 |
10
+| --- | --- |
11
+| **Vue 路径** | `ruoyi-ui/src/views/dataModel/farmerHousehold/index.vue` |
12
+| **组件名** | `FarmerHousehold` |
13
+| **菜单配置** | 组件路径:`dataModel/farmerHousehold/index` |
14
+| **权限前缀** | `dataModel:farmerHousehold:list\|query\|add\|edit\|remove\|import\|export` |
15
+
16
+---
17
+
18
+## 2. API 模块
19
+
20
+| 项 | 说明 |
21
+| --- | --- |
22
+| **文件** | `ruoyi-ui/src/api/dataModel/farmerHousehold.js` |
23
+| **Base** | `/dataModel/farmerHousehold` |
24
+
25
+CRUD、`yearOptions` / `monthOptions` / `townOptions` / `villageTree`、导入 `importData`、模板 `importTemplate`、导出 `export`(可选 `townDeptId`)与同类村级填报模块同构;模板/导出均为 **GET + blob**。
26
+
27
+| 方法 | 路径 | 说明 |
28
+| --- | --- | --- |
29
+| `listFarmerHousehold` | GET `/list` | 分页;筛选年、月、乡镇 |
30
+| `getFarmerHousehold` | GET `/{id}` | 详情(含派生) |
31
+| `addFarmerHousehold` | POST `/` | 新增 |
32
+| `updateFarmerHousehold` | PUT `/` | 修改 |
33
+| `delFarmerHousehold` | DELETE `/{ids}` | 删除 |
34
+| `listFarmerHouseholdYearOptions` | GET `/yearOptions` | 年份下拉 |
35
+| `listFarmerHouseholdMonthOptions` | GET `/monthOptions` | 月份下拉 |
36
+| `listFarmerHouseholdTownOptions` | GET `/townOptions` | 乡镇下拉 |
37
+| `listFarmerHouseholdVillageTree` | GET `/villageTree` | 县→乡镇→村树 |
38
+| `importFarmerHousehold` | POST `/importData` | FormData:`file` + `statYear` + `statMonth` |
39
+| `downloadFarmerHouseholdTemplate` | GET `/importTemplate` | 模板 blob |
40
+| `exportFarmerHousehold` | GET `/export` | 参数:`statYear`、`statMonth`、可选 `townDeptId` |
41
+
42
+---
43
+
44
+## 3. 页面结构
45
+
46
+1. **筛选**:年、月、乡镇(与需求一致,无村筛选)。  
47
+2. **列表**:年、月、乡镇、村、农牧户数、农牧人数、草场承包总面积(`pastureContractArea`)、操作。  
48
+3. **新增/编辑**:选村(可搜索,标签「乡镇 / 村」);新增默认本年本月;派生字段只读展示。  
49
+4. **详情**:与表单同分区标题;含派生只读值 + 乡镇;数值用 `formatWithUnit` 带单位。  
50
+5. **导入**:选年月 → upsert 摘要(insert/update/fail);任一行失败整批不写(后端)。  
51
+6. **导出**:选年月;所属乡镇与列表共用选项,打开时带入列表当前乡镇,清空=全部。
52
+
53
+### 表单 / 查看分区
54
+
55
+| 分区 | 内容 |
56
+| --- | --- |
57
+| 基本信息 | 年月、村(查看含乡镇);农牧户数、农牧人数 |
58
+| 草畜平衡情况 | 禁牧面积、草畜平衡面积;只读草场承包总面积(=禁牧+草畜平衡);核定载畜量、年底存栏绵羊单位 |
59
+| 封顶保底情况 | 纯牧户 / 无畜户 / 绝户 / 超载 / 需封顶 / 需保底(是/否) |
60
+| 本年受助情况 | 禁牧补助、草畜平衡奖励;只读补助奖励总资金(=二者之和);封顶保底后补助、村级监督员补助;只读补助合计金额(=封顶保底后+村级监督员);备注 |
61
+
62
+---
63
+
64
+## 4. 业务规则
65
+
66
+| 规则 | 实现 |
67
+| --- | --- |
68
+| 唯一键 | 年 + 月 + 村(前端提交只传 `villageDeptId`;乡镇由后端反推) |
69
+| 必填 | 年、月、村 |
70
+| 前端只读派生 | 草场承包总面积、补助奖励总资金、补助合计金额(表单禁用预览;详情同公式) |
71
+| 是/否 | 六项封顶保底字段单选「是」「否」 |
72
+| 不可未来月 | 表单 / 导入 / 导出校验 |
73
+| 草畜失衡预警 | 后端写入 `biz_yak_disease_warning`(type=6);前端不单独处理 |
74
+
75
+### 派生预览公式
76
+
77
+- 草场承包总面积 = 禁牧面积 + 草畜平衡面积  
78
+- 补助奖励总资金 = 禁牧补助 + 草畜平衡奖励  
79
+- 补助合计金额(前端展示)= 封顶保底后享受补助奖励总资金 + 村级草原监督员补助  
80
+
81
+> 说明:后端落库的 `subsidyTotal` 另含「补助奖励总资金」三项合计;前端「补助合计金额」按本次产品口径仅展示后两项之和。
82
+
83
+---
84
+
85
+## 5. 国际化
86
+
87
+`dataModel.farmerHousehold`(`lang/zh|bo/dataModel.js`);页面 `dmNs = 'farmerHousehold'`,复用 `dataModelLocaleMixin`(`dmT` / `dmCommon` / `formatWithUnit`)。查看表单使用 `dm-view-form` 高亮。
88
+
89
+---
90
+
91
+## 6. 联调说明
92
+
93
+1. 执行 `sql/biz_farmer_household.sql`。  
94
+2. 菜单组件 `dataModel/farmerHousehold/index`,权限见 §1。  
95
+3. 验证:新增默认年月、表单无派生列、详情有派生、导出乡镇带入列表筛选、草畜失衡写入疾病预警(后端)。
96
+
97
+---
98
+
99
+## 7. 文件清单
100
+
101
+| 类型 | 路径 |
102
+| --- | --- |
103
+| 页面 | `ruoyi-ui/src/views/dataModel/farmerHousehold/index.vue` |
104
+| API | `ruoyi-ui/src/api/dataModel/farmerHousehold.js` |
105
+| i18n | `lang/zh/dataModel.js`、`lang/bo/dataModel.js` → `farmerHousehold` |
106
+| 前端技术方案 | 本文档 |
107
+
108
+---
109
+
110
+## 8. 修订记录
111
+
112
+| 版本 | 说明 |
113
+| --- | --- |
114
+| 1.0 | 初版:村×年月;CRUD + upsert 导入 + 导出乡镇与列表联动;表单不展示派生、详情展示;分区对齐其它产业填报页 |

+ 1 - 0
doc/产业数据模型及服务/农牧户数据填报/农牧户数据填报技术方案.md

@@ -47,6 +47,7 @@ Base Path:`/dataModel/farmerHousehold`
47 47
 - 菜单组件:`dataModel/farmerHousehold/index`
48 48
 - 村选择:级联树(县→乡镇→村),仅选叶子村;提交只传 `villageDeptId`
49 49
 - 导出弹窗所属乡镇:与列表共用选项;打开时带入列表 `townDeptId`;清空则不传
50
+- 前端技术方案:同目录 `农牧户数据填报前端技术方案.md`
50 51
 
51 52
 ## 5. 主要类
52 53
 

+ 2 - 1
doc/产业数据模型及服务/可支配收入数据填报/可支配收入数据填报前端技术方案.md

@@ -53,7 +53,7 @@
53 53
 | 必填 | `statYear`、`ruralDisposableIncome`、`povertyNetIncome`(≥0) |
54 54
 | 增幅 / 增速表单 | **普通 `el-input`**(非 `el-input-number`),支持空值;提交空 → 不传/后端按 `null` 补齐 |
55 55
 | 改年份或人均可支配收入 | 编辑态清空增幅、增速输入,与后端 `recalculateGrowth` 一致 |
56
-| 列表 / 详情展示 | `formatIncrease`:`null` → `0.00`;`formatGrowthRate`:`null` → `0.00%`,有值则按小数×100 显示百分比 |
56
+| 列表 / 详情展示 | `formatIncrease`:`null` → `0.00`;`formatGrowthRate`:`null` → `0.00%`,有值则按库值直接 `toFixed(2)+%`(不再 ×100) |
57 57
 | 收入金额展示 | `formatMoney` → 两位小数;空值 `—` |
58 58
 | 唯一性 | 同年重复由后端拦截「该年份数据已存在」 |
59 59
 | 删除 | `$modal.confirm` 后物理删除 |
@@ -106,3 +106,4 @@
106 106
 | --- | --- |
107 107
 | 1.0 | 初版:县级年度 CRUD;增幅/增速选填;列表详情 null 显示为 0;无导入导出 |
108 108
 | 1.2 | 与需求对齐:改年份/可支配收入清空增幅增速;增速百分比展示 |
109
+| 1.3 | 增速展示不再 ×100,按库值直接显示 |

+ 226 - 0
doc/产业数据模型及服务/疫苗接种数据填报/疫苗接种数据填报前端技术方案.md

@@ -0,0 +1,226 @@
1
+# 疫苗接种数据填报 — 前端技术方案
2
+
3
+
4
+
5
+> 依据:同目录功能需求、技术方案;交互对齐畜牧产品产量等村×年月填报;字段 **小驼峰**。
6
+
7
+
8
+
9
+---
10
+
11
+
12
+
13
+## 1. 页面与路由
14
+
15
+
16
+
17
+| 项 | 说明 |
18
+
19
+| --- | --- |
20
+
21
+| **Vue 路径** | `ruoyi-ui/src/views/dataModel/vaccinationData/index.vue` |
22
+
23
+| **组件名** | `VaccinationData` |
24
+
25
+| **菜单配置** | 组件路径:`dataModel/vaccinationData/index` |
26
+
27
+| **权限前缀** | `dataModel:vaccinationData:list\|query\|add\|edit\|remove\|import\|export` |
28
+
29
+
30
+
31
+---
32
+
33
+
34
+
35
+## 2. API 模块
36
+
37
+
38
+
39
+| 项 | 说明 |
40
+
41
+| --- | --- |
42
+
43
+| **文件** | `ruoyi-ui/src/api/dataModel/vaccinationData.js` |
44
+
45
+| **Base** | `/dataModel/vaccinationData` |
46
+
47
+
48
+
49
+CRUD、`yearOptions` / `monthOptions` / `townOptions` / `villageTree`、导入 `importData`、模板 `importTemplate`、导出 `export`(可选 `townDeptId`)与同类村级填报模块同构;模板/导出均为 **GET + blob**。
50
+
51
+
52
+
53
+| 方法 | 路径 | 说明 |
54
+
55
+| --- | --- | --- |
56
+
57
+| `listVaccinationData` | GET `/list` | 分页;筛选年、月、乡镇、村 |
58
+
59
+| `getVaccinationData` | GET `/{id}` | 详情(含免疫率) |
60
+
61
+| `addVaccinationData` | POST `/` | 新增 |
62
+
63
+| `updateVaccinationData` | PUT `/` | 修改 |
64
+
65
+| `delVaccinationData` | DELETE `/{ids}` | 删除 |
66
+
67
+| `listVaccinationDataYearOptions` | GET `/yearOptions` | 年份下拉 |
68
+
69
+| `listVaccinationDataMonthOptions` | GET `/monthOptions` | 月份下拉 |
70
+
71
+| `listVaccinationDataTownOptions` | GET `/townOptions` | 乡镇下拉 |
72
+
73
+| `listVaccinationDataVillageTree` | GET `/villageTree` | 县→乡镇→村树 |
74
+
75
+| `importVaccinationData` | POST `/importData` | FormData:`file` + `statYear` + `statMonth` |
76
+
77
+| `downloadVaccinationDataTemplate` | GET `/importTemplate` | 模板 blob |
78
+
79
+| `exportVaccinationData` | GET `/export` | 参数:`statYear`、`statMonth`、可选 `townDeptId` |
80
+
81
+
82
+
83
+---
84
+
85
+
86
+
87
+## 3. 页面结构
88
+
89
+
90
+
91
+1. **筛选**:年、月、乡镇、村(村为可搜索下拉,选项来自村树扁平化)。  
92
+
93
+2. **列表**:年、月、乡镇、村、应免数、实免数、免疫率(`xx.xx%`)、操作。  
94
+
95
+3. **新增/编辑**:选村(可搜索,标签「乡镇 / 村」);新增默认本年本月;免疫率只读预览。  
96
+
97
+4. **详情**:与表单同分区;含乡镇与免疫率;数量用 `formatWithUnit` 带「头」。  
98
+
99
+5. **导入**:选年月 → upsert 摘要(insert/update/fail);免疫率列由后端跳过;软警告弹窗展示。  
100
+
101
+6. **导出**:选年月;所属乡镇与列表共用选项,打开时带入列表当前乡镇,清空=全部。
102
+
103
+
104
+
105
+### 表单 / 查看分区
106
+
107
+
108
+
109
+| 分区 | 内容 |
110
+
111
+| --- | --- |
112
+
113
+| 基本信息 | 年月、村(查看含乡镇) |
114
+
115
+| 疫苗接种情况 | 应免数、实免数;只读免疫率;备注 |
116
+
117
+
118
+
119
+---
120
+
121
+
122
+
123
+## 4. 业务规则
124
+
125
+
126
+
127
+| 规则 | 实现 |
128
+
129
+| --- | --- |
130
+
131
+| 唯一键 | 年 + 月 + 村(前端提交只传 `villageDeptId`;乡镇由后端反推) |
132
+
133
+| 必填 | 年、月、村 |
134
+
135
+| 数量 | 应免数、实免数:可选;非负整数;单位「头」;实免数 ≤ 应免数(前端) |
136
+
137
+| 免疫率预览 | 应免数 > 0 且实免数非空时:`(实免/应免)×100`,保留 2 位小数,展示为 `98.33%`;否则「—」 |
138
+
139
+| 实免 > 应免 | 新增/编辑表单拦截;导入仍由后端软警告(不阻断) |
140
+
141
+| 不可未来月 | 表单 / 导入 / 导出校验 |
142
+
143
+
144
+
145
+### 免疫率公式(与后端 `VaccinationDataDerivedSupport` 对齐)
146
+
147
+
148
+
149
+```
150
+
151
+immunityRate = round((actualVaccinateCount * 10000) / shouldVaccinateCount) / 100
152
+
153
+```
154
+
155
+
156
+
157
+前端仅作表单预览;落库与列表/详情以接口返回的 `immunityRate` 为准。
158
+
159
+
160
+
161
+---
162
+
163
+
164
+
165
+## 5. 国际化
166
+
167
+
168
+
169
+`dataModel.vaccinationData`(`lang/zh|bo/dataModel.js`);页面 `dmNs = 'vaccinationData'`,复用 `dataModelLocaleMixin`(`dmT` / `dmCommon` / `formatWithUnit`)。查看表单使用 `dm-view-form` 高亮。
170
+
171
+
172
+
173
+---
174
+
175
+
176
+
177
+## 6. 联调说明
178
+
179
+
180
+
181
+1. 执行 `sql/biz_vaccination_data.sql`。  
182
+
183
+2. 菜单组件 `dataModel/vaccinationData/index`,权限见 §1。  
184
+
185
+3. 验证:新增默认年月、免疫率只读预览与保存后一致、列表筛选村、导出乡镇带入列表筛选、实免>应免拦截、导入 upsert。
186
+
187
+
188
+
189
+---
190
+
191
+
192
+
193
+## 7. 文件清单
194
+
195
+
196
+
197
+| 类型 | 路径 |
198
+
199
+| --- | --- |
200
+
201
+| 页面 | `ruoyi-ui/src/views/dataModel/vaccinationData/index.vue` |
202
+
203
+| API | `ruoyi-ui/src/api/dataModel/vaccinationData.js` |
204
+
205
+| i18n | `lang/zh/dataModel.js`、`lang/bo/dataModel.js` → `vaccinationData` |
206
+
207
+| 前端技术方案 | 本文档 |
208
+
209
+
210
+
211
+---
212
+
213
+
214
+
215
+## 8. 修订记录
216
+
217
+
218
+
219
+| 版本 | 说明 |
220
+
221
+| --- | --- |
222
+
223
+| 1.0 | 初版:村×年月;CRUD + upsert 导入 + 导出乡镇与列表联动;免疫率前端预览 |
224
+| 1.1 | 实免数须 ≤ 应免数(仅前端表单校验) |
225
+
226
+

+ 5 - 0
doc/产业数据模型及服务/疫苗接种数据填报/疫苗接种数据填报功能需求.md

@@ -18,6 +18,7 @@
18 18
 - 唯一键:所属年份 + 所属月份 + 所属村。
19 19
 - 导入:存在则更新、不存在则插入(不按年月先删后插)。
20 20
 - 派生(保存时计算并落库):**免疫率 = (实免数 / 应免数) × 100**,保留 2 位小数(应免数 > 0 且实免数非空;如 98.33;界面/导出展示为 `98.33%`)。
21
+
21 22
 - **约束:实免数 ≤ 应免数**(两者均填写时;保存与导入均硬拦截,不允许超过)。
22 23
 
23 24
 ---
@@ -49,4 +50,8 @@
49 50
 | --- | --- |
50 51
 | 1.0 | 首版:CRUD + upsert 导入 + 导出 |
51 52
 | 1.1 | 免疫率改为 (实免数/应免数)×100,保留 2 位小数落库 |
53
+<<<<<<< HEAD
54
+| 1.2 | 页面填报约束实免数 ≤ 应免数(前端校验) |
55
+=======
52 56
 | 1.2 | 约束:实免数 ≤ 应免数(硬校验) |
57
+>>>>>>> ef65fad8763e393adf8cf1e918e4eec407e1b967

+ 2 - 0
doc/产业数据模型及服务/疫苗接种数据填报/疫苗接种数据填报技术方案.md

@@ -56,6 +56,8 @@ Excel 列:0 序号、1 乡镇、2 村、3 应免数、4 实免数、5 免疫
56 56
 
57 57
 ## 5. 前端
58 58
 
59
+详见同目录 **[疫苗接种数据填报前端技术方案.md](./疫苗接种数据填报前端技术方案.md)**。
60
+
59 61
 - 页面:`ruoyi-ui/src/views/dataModel/vaccinationData/index.vue`
60 62
 - API:`ruoyi-ui/src/api/dataModel/vaccinationData.js`
61 63
 - i18n:`dataModel.vaccinationData`(zh/bo)

+ 1 - 0
doc/产业数据模型及服务/疫苗接种数据填报/疫苗接种数据填报测试用例.md

@@ -10,6 +10,7 @@
10 10
 | VD-04 | 修改 | 改应免/实免 | 免疫率重算 |
11 11
 | VD-05 | 删除 | 删除一条 | 物理删除成功 |
12 12
 | VD-06 | 未来月 | 选未来年月保存 | 拒绝 |
13
+
13 14
 | VD-07 | 实免&gt;应免 | 保存/导入 | 拒绝(硬校验) |
14 15
 | VD-08 | 下载模板 | 点下载模板 | 得到官方 xlsx |
15 16
 | VD-09 | 导入 upsert | 上传模板示例行,再导入同村改数 | 首次新增、再次更新 |

+ 120 - 0
ruoyi-ui/src/api/dataModel/farmerHousehold.js

@@ -0,0 +1,120 @@
1
+import request from "@/utils/request"
2
+
3
+/** 分页列表 */
4
+export function listFarmerHousehold(query) {
5
+  return request({
6
+    url: "/dataModel/farmerHousehold/list",
7
+    method: "get",
8
+    params: query
9
+  })
10
+}
11
+
12
+/** 详情 */
13
+export function getFarmerHousehold(id) {
14
+  return request({
15
+    url: "/dataModel/farmerHousehold/" + id,
16
+    method: "get"
17
+  })
18
+}
19
+
20
+/** 新增 */
21
+export function addFarmerHousehold(data) {
22
+  return request({
23
+    url: "/dataModel/farmerHousehold",
24
+    method: "post",
25
+    data
26
+  })
27
+}
28
+
29
+/** 修改 */
30
+export function updateFarmerHousehold(data) {
31
+  return request({
32
+    url: "/dataModel/farmerHousehold",
33
+    method: "put",
34
+    data
35
+  })
36
+}
37
+
38
+/** 删除 */
39
+export function delFarmerHousehold(ids) {
40
+  return request({
41
+    url: "/dataModel/farmerHousehold/" + ids,
42
+    method: "delete"
43
+  })
44
+}
45
+
46
+/** 可选年份 */
47
+export function listFarmerHouseholdYearOptions() {
48
+  return request({
49
+    url: "/dataModel/farmerHousehold/yearOptions",
50
+    method: "get"
51
+  })
52
+}
53
+
54
+/** 可选月份(1~12) */
55
+export function listFarmerHouseholdMonthOptions() {
56
+  return request({
57
+    url: "/dataModel/farmerHousehold/monthOptions",
58
+    method: "get"
59
+  })
60
+}
61
+
62
+/** 乡镇下拉 */
63
+export function listFarmerHouseholdTownOptions() {
64
+  return request({
65
+    url: "/dataModel/farmerHousehold/townOptions",
66
+    method: "get"
67
+  })
68
+}
69
+
70
+/** 县→乡镇→村树 */
71
+export function listFarmerHouseholdVillageTree() {
72
+  return request({
73
+    url: "/dataModel/farmerHousehold/villageTree",
74
+    method: "get"
75
+  })
76
+}
77
+
78
+/** Excel 导入 */
79
+export function importFarmerHousehold(file, statYear, statMonth) {
80
+  const formData = new FormData()
81
+  formData.append("file", file, file.name)
82
+  formData.append("statYear", String(statYear))
83
+  formData.append("statMonth", String(statMonth))
84
+  return request({
85
+    url: "/dataModel/farmerHousehold/importData",
86
+    method: "post",
87
+    headers: {
88
+      repeatSubmit: false
89
+    },
90
+    data: formData
91
+  })
92
+}
93
+
94
+/** 下载导入模板(GET) */
95
+export function downloadFarmerHouseholdTemplate() {
96
+  return request({
97
+    url: "/dataModel/farmerHousehold/importTemplate",
98
+    method: "get",
99
+    responseType: "blob"
100
+  })
101
+}
102
+
103
+/**
104
+ * 按年月导出(GET)
105
+ * @param {number} statYear
106
+ * @param {number} statMonth
107
+ * @param {number} [townDeptId] 可选乡镇
108
+ */
109
+export function exportFarmerHousehold(statYear, statMonth, townDeptId) {
110
+  const params = { statYear, statMonth }
111
+  if (townDeptId != null && townDeptId !== "") {
112
+    params.townDeptId = townDeptId
113
+  }
114
+  return request({
115
+    url: "/dataModel/farmerHousehold/export",
116
+    method: "get",
117
+    params,
118
+    responseType: "blob"
119
+  })
120
+}

+ 120 - 0
ruoyi-ui/src/api/dataModel/largeLivestockFarmer.js

@@ -0,0 +1,120 @@
1
+import request from "@/utils/request"
2
+
3
+/** 分页列表 */
4
+export function listLargeLivestockFarmer(query) {
5
+  return request({
6
+    url: "/dataModel/largeLivestockFarmer/list",
7
+    method: "get",
8
+    params: query
9
+  })
10
+}
11
+
12
+/** 详情 */
13
+export function getLargeLivestockFarmer(id) {
14
+  return request({
15
+    url: "/dataModel/largeLivestockFarmer/" + id,
16
+    method: "get"
17
+  })
18
+}
19
+
20
+/** 新增 */
21
+export function addLargeLivestockFarmer(data) {
22
+  return request({
23
+    url: "/dataModel/largeLivestockFarmer",
24
+    method: "post",
25
+    data
26
+  })
27
+}
28
+
29
+/** 修改 */
30
+export function updateLargeLivestockFarmer(data) {
31
+  return request({
32
+    url: "/dataModel/largeLivestockFarmer",
33
+    method: "put",
34
+    data
35
+  })
36
+}
37
+
38
+/** 删除 */
39
+export function delLargeLivestockFarmer(ids) {
40
+  return request({
41
+    url: "/dataModel/largeLivestockFarmer/" + ids,
42
+    method: "delete"
43
+  })
44
+}
45
+
46
+/** 可选年份 */
47
+export function listLargeLivestockFarmerYearOptions() {
48
+  return request({
49
+    url: "/dataModel/largeLivestockFarmer/yearOptions",
50
+    method: "get"
51
+  })
52
+}
53
+
54
+/** 可选月份(1~12) */
55
+export function listLargeLivestockFarmerMonthOptions() {
56
+  return request({
57
+    url: "/dataModel/largeLivestockFarmer/monthOptions",
58
+    method: "get"
59
+  })
60
+}
61
+
62
+/** 乡镇下拉 */
63
+export function listLargeLivestockFarmerTownOptions() {
64
+  return request({
65
+    url: "/dataModel/largeLivestockFarmer/townOptions",
66
+    method: "get"
67
+  })
68
+}
69
+
70
+/** 县→乡镇→村树 */
71
+export function listLargeLivestockFarmerVillageTree() {
72
+  return request({
73
+    url: "/dataModel/largeLivestockFarmer/villageTree",
74
+    method: "get"
75
+  })
76
+}
77
+
78
+/** Excel 导入 */
79
+export function importLargeLivestockFarmer(file, statYear, statMonth) {
80
+  const formData = new FormData()
81
+  formData.append("file", file, file.name)
82
+  formData.append("statYear", String(statYear))
83
+  formData.append("statMonth", String(statMonth))
84
+  return request({
85
+    url: "/dataModel/largeLivestockFarmer/importData",
86
+    method: "post",
87
+    headers: {
88
+      repeatSubmit: false
89
+    },
90
+    data: formData
91
+  })
92
+}
93
+
94
+/** 下载导入模板(GET) */
95
+export function downloadLargeLivestockFarmerTemplate() {
96
+  return request({
97
+    url: "/dataModel/largeLivestockFarmer/importTemplate",
98
+    method: "get",
99
+    responseType: "blob"
100
+  })
101
+}
102
+
103
+/**
104
+ * 按年月导出(GET)
105
+ * @param {number} statYear
106
+ * @param {number} statMonth
107
+ * @param {number} [townDeptId] 可选乡镇
108
+ */
109
+export function exportLargeLivestockFarmer(statYear, statMonth, townDeptId) {
110
+  const params = { statYear, statMonth }
111
+  if (townDeptId != null && townDeptId !== "") {
112
+    params.townDeptId = townDeptId
113
+  }
114
+  return request({
115
+    url: "/dataModel/largeLivestockFarmer/export",
116
+    method: "get",
117
+    params,
118
+    responseType: "blob"
119
+  })
120
+}

+ 120 - 0
ruoyi-ui/src/api/dataModel/vaccinationData.js

@@ -0,0 +1,120 @@
1
+import request from "@/utils/request"
2
+
3
+/** 分页列表 */
4
+export function listVaccinationData(query) {
5
+  return request({
6
+    url: "/dataModel/vaccinationData/list",
7
+    method: "get",
8
+    params: query
9
+  })
10
+}
11
+
12
+/** 详情 */
13
+export function getVaccinationData(id) {
14
+  return request({
15
+    url: "/dataModel/vaccinationData/" + id,
16
+    method: "get"
17
+  })
18
+}
19
+
20
+/** 新增 */
21
+export function addVaccinationData(data) {
22
+  return request({
23
+    url: "/dataModel/vaccinationData",
24
+    method: "post",
25
+    data
26
+  })
27
+}
28
+
29
+/** 修改 */
30
+export function updateVaccinationData(data) {
31
+  return request({
32
+    url: "/dataModel/vaccinationData",
33
+    method: "put",
34
+    data
35
+  })
36
+}
37
+
38
+/** 删除 */
39
+export function delVaccinationData(ids) {
40
+  return request({
41
+    url: "/dataModel/vaccinationData/" + ids,
42
+    method: "delete"
43
+  })
44
+}
45
+
46
+/** 可选年份 */
47
+export function listVaccinationDataYearOptions() {
48
+  return request({
49
+    url: "/dataModel/vaccinationData/yearOptions",
50
+    method: "get"
51
+  })
52
+}
53
+
54
+/** 可选月份(1~12) */
55
+export function listVaccinationDataMonthOptions() {
56
+  return request({
57
+    url: "/dataModel/vaccinationData/monthOptions",
58
+    method: "get"
59
+  })
60
+}
61
+
62
+/** 乡镇下拉 */
63
+export function listVaccinationDataTownOptions() {
64
+  return request({
65
+    url: "/dataModel/vaccinationData/townOptions",
66
+    method: "get"
67
+  })
68
+}
69
+
70
+/** 县→乡镇→村树 */
71
+export function listVaccinationDataVillageTree() {
72
+  return request({
73
+    url: "/dataModel/vaccinationData/villageTree",
74
+    method: "get"
75
+  })
76
+}
77
+
78
+/** Excel 导入 */
79
+export function importVaccinationData(file, statYear, statMonth) {
80
+  const formData = new FormData()
81
+  formData.append("file", file, file.name)
82
+  formData.append("statYear", String(statYear))
83
+  formData.append("statMonth", String(statMonth))
84
+  return request({
85
+    url: "/dataModel/vaccinationData/importData",
86
+    method: "post",
87
+    headers: {
88
+      repeatSubmit: false
89
+    },
90
+    data: formData
91
+  })
92
+}
93
+
94
+/** 下载导入模板(GET) */
95
+export function downloadVaccinationDataTemplate() {
96
+  return request({
97
+    url: "/dataModel/vaccinationData/importTemplate",
98
+    method: "get",
99
+    responseType: "blob"
100
+  })
101
+}
102
+
103
+/**
104
+ * 按年月导出(GET)
105
+ * @param {number} statYear
106
+ * @param {number} statMonth
107
+ * @param {number} [townDeptId] 可选乡镇
108
+ */
109
+export function exportVaccinationData(statYear, statMonth, townDeptId) {
110
+  const params = { statYear, statMonth }
111
+  if (townDeptId != null && townDeptId !== "") {
112
+    params.townDeptId = townDeptId
113
+  }
114
+  return request({
115
+    url: "/dataModel/vaccinationData/export",
116
+    method: "get",
117
+    params,
118
+    responseType: "blob"
119
+  })
120
+}

+ 7 - 0
ruoyi-ui/src/assets/styles/data-model.scss

@@ -0,0 +1,7 @@
1
+/* 产业数据模型填报 — 查看弹框值高亮(Element 主题色) */
2
+.dm-view-form {
3
+  .el-form-item__content {
4
+    color: #409EFF;
5
+    font-weight: 500;
6
+  }
7
+}

+ 1 - 0
ruoyi-ui/src/assets/styles/index.scss

@@ -4,6 +4,7 @@
4 4
 @import './element-ui.scss';
5 5
 @import './sidebar.scss';
6 6
 @import './btn.scss';
7
+@import './data-model.scss';
7 8
 
8 9
 body {
9 10
   height: 100%;

+ 17 - 15
ruoyi-ui/src/lang/bo/commonProsperity.js

@@ -43,7 +43,9 @@ export default {
43 43
     viewOfflineTime: "འོག་ཏུ་བཀག་དུས་ཚོད།",
44 44
     ruleLen120: "ལས་གོང་མིང་1-20",
45 45
     ruleLen150: "1-50ཡིག",
46
+    ruleLen50Optional: "ཡིག་ཆ་50ལས་མི་ཆོག",
46 47
     ruleLen1500: "1-500ཡིག",
48
+    ruleLen500Optional: "ཡིག་ཆ་500ལས་མི་ཆོག",
47 49
     ruleImplEndBeforeStart: "མཇུག་ཚེས་འགོ་ཚེས་ལས་སྔ་མི་ཆོག",
48 50
     ruleRateRange: "འབྲི་ལུང་0-1",
49 51
     ruleNonNegativeInteger: "ཡིག་གྲངས་མི་ཆག",
@@ -66,40 +68,40 @@ export default {
66 68
     queryProjectName: "ལས་གོང་མིང་།",
67 69
     queryProjectNamePh: "མིང་ནས་འཚོལ།",
68 70
     queryProjectType: "ལས་གོང་རིགས།",
71
+    queryImplYear: "ལག་བསྟར་ལོ།",
69 72
     queryPublishStatus: "ཁྱབ་བསྒྲགས་གནས་བབ།",
70 73
     colProjectName: "ལས་གོང་མིང་།",
71 74
     colProjectType: "ལས་གོང་རིགས།",
72 75
     colIntro: "མདོར་བརྗོད།",
73
-    colImplDate: "ལག་བསྟར་ཚེས་གྲངས།",
76
+    colImplYear: "ལག་བསྟར་ལོ།",
74 77
     colOpImageCount: "ལས་གཉེར་པར།",
75 78
     colCover: "ཁ་བརྒྱབ།",
76
-    colContent: "ནང་དོན།",
79
+    colContent: "འཛུགས་སྐྲུན་རྒྱ་ཁྱོན་དང་ནང་དོན།",
77 80
     colVideo: "ལས་གཉེར་བརྙན།",
78 81
     formProjectName: "ལས་གོང་མིང་།",
79 82
     formProjectType: "ལས་གོང་རིགས།",
80 83
     formIntro: "མདོར་བརྗོད།",
81
-    formContent: "ནང་དོན།",
82
-    formImplDate: "ལག་བསྟར་ཚེས་གྲངས།",
83
-    implRangeSeparator: "ནས",
84
-    implRangeStartPh: "འགོ་ཚེས།",
85
-    implRangeEndPh: "མཇུག་ཚེས།",
84
+    formContent: "འཛུགས་སྐྲུན་རྒྱ་ཁྱོན་དང་ནང་དོན།",
85
+    formInvestmentAmount: "མ་དངུལ་གྲངས།",
86
+    formImplYear: "ལག་བསྟར་ལོ།",
87
+    formImplStatus: "ལག་བསྟར་གནས་ཚུལ།",
86 88
     formOpImages: "ལས་གཉེར་པར།",
87 89
     formVideo: "ལས་གཉེར་བརྙན།",
88 90
     formCover: "ཁ་བརྒྱབ།",
89 91
     phProjectName: "ལས་གོང་མིང་འབྲི་རོགས།",
90
-    phIntro: "མདོར་བརྗོད་འབྲི་རོགས།",
91
-    phContent: "ནང་དོན་འབྲི་རོགས།",
92
+    phIntro: "འདེམས་འབྲི,ཡིག་ཆ་50ལས་མི་ཆོག",
93
+    phContent: "འཛུགས་སྐྲུན་རྒྱ་ཁྱོན་དང་ནང་དོན་འབྲི་རོགས།",
94
+    phImplStatus: "འདེམས་འབྲི,ཡིག་ཆ་500ལས་མི་ཆོག",
92 95
     ruleProjectNameRequired: "ལས་གོང་མིང་འབྲི་རོགས།",
93 96
     ruleProjectTypeRequired: "རིགས་འདེམས་རོགས།",
94
-    ruleIntroRequired: "མདོར་བརྗོད་འབྲི་རོགས།",
95
-    ruleContentRequired: "ནང་དོན་འབྲི་རོགས།",
96
-    ruleImplDateRequired: "ལག་བསྟར་ཚེས་གྲངས་འདེམས་རོགས།",
97
+    ruleContentRequired: "འཛུགས་སྐྲུན་རྒྱ་ཁྱོན་དང་ནང་དོན་འབྲི་རོགས།",
98
+    ruleImplYearRequired: "ལག་བསྟར་ལོ་འདེམས་རོགས།",
97 99
     ruleOpImagesRequired: "ལས་གཉེར་པར་1འཇུག་རོགས།",
98 100
     dialogAdd: "[གསར་སྣོན]མཉམ་སྤྱི་འཕྲོག་པ།",
99 101
     dialogEdit: "[རྩོམ་སྒྲིག]མཉམ་སྤྱི་འཕྲོག་པ།",
100
-    type1: "མཉམ་ལས་གཉེར་འགྲོ།",
101
-    type2: "ཞིང་ལས་ཡུལ་སྤྱོད།",
102
-    type3: "རྟེན་འཛིན་ཞིང་ལས།",
102
+    type1: "མཛེས་སྡུག་གྲོང་གསེབ་འཛུགས་སྐྲུན་ལས་གཞི།",
103
+    type2: "མི་སྡོད་ཁོར་ཡུག་བཟོ་བཅོས་ཡར་རྒྱས་ལས་གཞི།",
104
+    type3: "གཞན་ལས་གཞི་མ་དངུལ།",
103 105
     confirmDelete: "ཐོ་གཞུང་འདི་སུབ་རྒྱུ་གཏན་ཁེལ་ལམ?",
104 106
     confirmPublish: "ཁྱབ་བསྒྲགས་བྱེད་དམ།ཁྱབ་བསྒྲགས་རྗེས་བཟོ་བཅོས་མི་ཆོག",
105 107
     confirmOffline: "འོག་ཏུ་བཀག་བྱེད་དམ།བཟོ་བཅོས་བསྐྱར་དུ་ཆོག",

+ 323 - 46
ruoyi-ui/src/lang/bo/dataModel.js

@@ -286,9 +286,13 @@ export default {
286 286
     statMonthLabel: "{month}ཟླ།",
287 287
     colVillageCount: "གྲོང་ཚོ་གྲངས།",
288 288
     colHerdsmanHouseholdCount: "འབྲོག་ཁྱིམ་གྲངས།",
289
-    colYakTotal: "གནས་ཚད་གྲངས།",
290
-    colBullTotal: "གླང་གནས་ཚད།",
291
-    colCowTotal: "བ་མོ་གནས་ཚད།",
289
+    colBullTotal: "གླང་སྤྱི་གནས་ཚད།",
290
+    colCowTotal: "བ་མོ་སྤྱི་གནས་ཚད།",
291
+    colDairyTotal: "འོ་མ་བཞོ་བ་སྤྱི་གནས་ཚད།",
292
+    colSheepTotal: "ལུག་སྤྱི་གནས་ཚད།",
293
+    colInsuredYakCount: "འགན་བཅོལ་གཡག་གནས་ཚད།",
294
+    colYakTotal: "གཡག་སྤྱི་གནས་ཚད།",
295
+    colGrandTotal: "སྤྱི་གནས་ཚད།",
292 296
     formStatYear: "གཏོགས་ལོ།",
293 297
     formStatMonth: "གཏོགས་ཟླ།",
294 298
     formTown: "ཤང་གྲོང།",
@@ -297,22 +301,28 @@ export default {
297 301
     formHerdsmanHouseholdCount: "འབྲོག་ཁྱིམ་གྲངས།",
298 302
     formBreedingBullCount: "ས་བོན་གླང་གནས་ཚད།",
299 303
     formBullCastratedCount: "གླང་/རླིག་ཕྱུགས་གནས་ཚད།",
300
-    formCowYoungCount: "ལོ་0~1.5 ཕྲུ་གུ་གནས་ཚད།",
301
-    formCowAdultCount: "ལོ་1.5་ཡན་དར་ཕྱུགསགནས་ཚད།",
304
+    formCowYoungCount: "ལོ་0~1.5 ཕྲུ་གུ(1.5མིཚུད)གནས་ཚད།",
305
+    formCowAdultCount: "ལོ་1.5་ཡན་དར་ཕྱུགས(1.5ཚུད)གནས་ཚད།",
302 306
     formMilkingCowCount: "འོ་མ་བཞོ་བ་མོ་གནས་ཚད།",
303 307
     formFertileCowCount: "འཕེལ་ནུས་བ་མོ་གནས་ཚད།",
304 308
     formSheepTotal: "ལུག་སྤྱི་གནས་ཚད།",
305 309
     formMilkingSheepCount: "འོ་མ་བཞོ་ལུག་གནས་ཚད།",
306 310
     formInsuredYakCount: "འགན་བཅོལ་གཡག་གནས་ཚད།",
307
-    formBullTotal: "གླང་བསྡོམས།",
308
-    formCowTotal: "བ་མོ་བསྡོམས།",
309
-    formDairyTotal: "འོ་མ་བཞོ་བ་བསྡོམས།",
311
+    formBullTotal: "གླང་སྤྱི་གནས་ཚད།",
312
+    formCowTotal: "བ་མོ་སྤྱི་གནས་ཚད།",
313
+    formDairyTotal: "འོ་མ་བཞོ་བ་སྤྱི་གནས་ཚད།",
310 314
     formYakTotal: "གཡག་སྤྱི་གནས་ཚད།",
311
-    formGrandTotal: "སྤྱི་བསྡོམས།",
315
+    formGrandTotal: "སྤྱི་གནས་ཚད།",
312 316
     formYakSheepTotal: "སྤྱི་ཚད(གཡག+ལུག)",
313 317
     formRemark: "ཟིན་བྲིས།",
314 318
     phRemark: "འདེམས་འབྲི,ཡིག་ཆ་500ལས་མི་ཆོག",
315 319
     sectionBasic: "གཞི་རྩའི་གནས་ཚུལ།",
320
+    sectionFarmer: "ཞིང་འབྲོག་ཁྱིམ་གནས་ཚུལ།",
321
+    sectionBull: "གླང་གནས་ཚད་གནས་ཚུལ།",
322
+    sectionCow: "བ་མོ་གནས་ཚད་གནས་ཚུལ།",
323
+    sectionDairy: "འོ་མ་བཞོ་བ་གནས་ཚད་གནས་ཚུལ།",
324
+    sectionSheep: "ལུག་གནས་ཚད་གནས་ཚུལ།",
325
+    sectionSummary: "བསྡོམས་རྩིས།",
316 326
     sectionInventory: "གནས་ཚད་དཔྱད་གཞི།",
317 327
     btnImport: "ནང་འདྲེན།",
318 328
     btnDownloadTemplate: "དཔེ་ཡིག་ཕབ་ལེན།",
@@ -392,7 +402,7 @@ export default {
392 402
     phRemark: "འདེམས་འབྲི,ཡིག་ཆ་500ལས་མི་ཆོག",
393 403
     sectionBasic: "གཞི་རྩའི་གནས་ཚུལ།",
394 404
     sectionFarmer: "ཞིང་འབྲོག་ཁྱིམ་གནས་ཚུལ།",
395
-    sectionOutbound: "ཕྱིར་ཐོན་གནས་ཚུལ།",
405
+    sectionOutbound: "ཕྱུགས་ཕྱིར་ཐོན་གནས་ཚུལ།",
396 406
     sectionSelfConsumption: "རང་ཟ་གནས་ཚུལ།",
397 407
     btnImport: "ནང་འདྲེན།",
398 408
     btnDownloadTemplate: "དཔེ་ཡིག་ཕབ་ལེན།",
@@ -427,6 +437,7 @@ export default {
427 437
     unitHead: "ཨ།",
428 438
     unitSheep: "ཐོག",
429 439
     unitHorse: "རྟ།",
440
+    unitHeadSheepHorse: "ཨ་ཐོག་རྟ།",
430 441
     ruleStatYearRequired: "གཏོགས་ལོ་འདེམས་རོགས།",
431 442
     ruleStatMonthRequired: "གཏོགས་ཟླ་འདེམས་རོགས།",
432 443
     ruleStatMonthFuture: "མ་འོངས་ཟླ་འབྲི་མི་ཆོག",
@@ -467,12 +478,12 @@ export default {
467 478
     formEstablishDate: "འཛུགས་དུས།",
468 479
     formRegisteredCapital: "ཐོ་འགོད་མ་རྩ།",
469 480
     formYearEndTotalAssets: "ལོ་མཇུག་རྒྱུ་ནོར་སྤྱི།",
470
-    formMemberHouseholdCount: "ཞུགས་ཁྱིམ་གྲངས།",
471
-    formMemberPopulationCount: "ཞུགས་མི་གྲངས།",
472
-    formPovertyMonitorCount: "དབུལ་ལོག་སྔོན་འགོག་ལྟ་ཞིབ་མི་གྲངས།",
481
+    formMemberHouseholdCount: "ཁྱིམ་གྲངས།",
482
+    formMemberPopulationCount: "མི་གྲངས།",
483
+    formPovertyMonitorCount: "དབུལ་ལོག་སྔོན་འགོག་ལྟ་ཞིབ།",
473 484
     formCattleShareCount: "གླང་ཤ་སྒོར་གྲངས།",
474 485
     formSheepShareCount: "ལུག་ཤ་སྒོར་གྲངས།",
475
-    formLivestockShareTotal: "ཕྱུགས་ཤ་སྒོར་ཆུང་བསྡོམས།",
486
+    formLivestockShareTotal: "ཕྱུགས་ཤ་སྒོར་སྤྱི་གྲངས།",
476 487
     formGrasslandShareArea: "རྩྭ་ཐང་ཤ་སྒོར།",
477 488
     formLaborShareCount: "ངལ་རྩོལ་ཤ་སྒོར།",
478 489
     formCashShareAmount: "དངུལ་ཤ་སྒོར།",
@@ -487,25 +498,29 @@ export default {
487 498
     formCollegeGraduateWage: "སློབ་ཆེན་གླ་ཕོགས་ཡོང་འབབ།",
488 499
     formFarmerTransferEmploymentCount: "ཞིང་འབྲོག་པ་ལས་གནས་སྤོ།",
489 500
     formFarmerTransferWage: "ཞིང་འབྲོག་པ་གླ་ཕོགས་ཡོང་འབབ།",
490
-    formCattleInventoryCount: "གླང་གནས་ཚད།",
491
-    formCattleOutboundCount: "གླང་ཕྱིར་ཐོན།",
492
-    formSheepInventoryCount: "ལུག་གནས་ཚད།",
493
-    formSheepOutboundCount: "ལུག་ཕྱིར་ཐོན།",
501
+    formCattleInventoryCount: "གླང་གནས་ཚད་གྲངས།",
502
+    formCattleOutboundCount: "གླང་ཕྱིར་ཐོན་གྲངས།",
503
+    formSheepInventoryCount: "ལུག་གནས་ཚད་གྲངས།",
504
+    formSheepOutboundCount: "ལུག་ཕྱིར་ཐོན་གྲངས།",
494 505
     formTrademarkProductCount: "ཐོ་འགོད་ཐོབ་རྟགས་ཐོན་རྫས་གྲངས།",
495 506
     formQualityCertProductCount: "སྤུས་ཚད་ངོས་འཛིན་ཐོན་རྫས་གྲངས།",
496
-    formTrainingManageCount: "སློབ་སྦྱོང-དོ་དམ་ནུས་པ།",
497
-    formTrainingSkillCount: "སློབ་སྦྱོང-ཆེད་ལས་ལག་རྩལ།",
498
-    formTrainingOtherCount: "སློབ་སྦྱོང-གཞན།",
507
+    formTrainingManageCount: "དོ་དམ་ནུས་པ།",
508
+    formTrainingSkillCount: "ཆེད་ལས་ལག་རྩལ།",
509
+    formTrainingOtherCount: "གཞན།",
499 510
     formBusinessScope: "གཙོ་བོ་ཚོང་གཉེར་ཁྱབ་ཁོངས།",
500 511
     formBusinessModel: "ཚོང་གཉེར་རྣམ་པ།",
501
-    formOperationStatus: "འཁོར་སྐྱོད་གནས་ཚུལ།",
512
+    formOperationStatus: "མཉམ་ལས་ཁང་འཁོར་སྐྱོད་གནས་ཚུལ།",
502 513
     formRemark: "ཟིན་བྲིས།",
503 514
     sectionBasic: "གཞི་རྩའི་གནས་ཚུལ།",
504
-    sectionMemberShare: "ཞུགས་པ་དང་ཤ་སྒོར།",
505
-    sectionBenefit: "ཕན་འབྲས་གནས་ཚུལ།",
506
-    sectionEmploymentLivestock: "ལས་ཞུགས་དང་གནས་ཕྱིར་ཐོན།",
507
-    sectionProductTraining: "ཐོན་རྫས་ངོས་འཛིན་དང་སློབ་སྦྱོང།",
508
-    sectionOperation: "ཚོང་གཉེར་གནས་ཚུལ།",
515
+    sectionCooperativeInfo: "མཉམ་ལས་ཁང་གནས་ཚུལ།",
516
+    sectionMemberShare: "ཞིང་འབྲོག་པ་ཞུགས་གནས་ཚུལ།",
517
+    sectionBenefit: "ལོ་རེའི་ཕན་འབྲས་འདོན་སྤེལ་གནས་ཚུལ།",
518
+    sectionEmployment: "མཉམ་ལས་ཁང་ཁྱབ་ཁོངས་ལས་ཞུགས་བསྡུ་གནས་ཚུལ།",
519
+    sectionLivestockInout: "མཉམ་ལས་ཁང་ཕྱུགས་གནས་ཕྱིར་ཐོན་གནས་ཚུལ།",
520
+    sectionProductCert: "ཐོན་རྫས་ངོས་འཛིན་གནས་ཚུལ།",
521
+    sectionTraining: "མཉམ་ལས་ཁང་ཁོངས་མི་སློབ་སྦྱོང་གནས་ཚུལ།",
522
+    sectionOperation: "མཉམ་ལས་ཁང་ཚོང་གཉེར་ཁྱབ་ཁོངས་དང་རྣམ་པ།",
523
+    sectionOperationStatus: "མཉམ་ལས་ཁང་འཁོར་སྐྱོད་གནས་ཚུལ།",
509 524
     btnImport: "ནང་འདྲེན།",
510 525
     btnChooseFile: "ཡིག་ཆ་འདེམས།",
511 526
     btnDownloadTemplate: "དཔེ་ཡིག་ཕབ་ལེན།",
@@ -538,6 +553,7 @@ export default {
538 553
     unitHousehold: "ཁྱིམ།",
539 554
     unitPerson: "མི།",
540 555
     unitHead: "ཨ།",
556
+    unitHeadSheepHorse: "ཨ་ཐོག་རྟ།",
541 557
     unitGe: "གྲངས།",
542 558
     unitWanYuan: "ཁྲི་སྒོར།",
543 559
     unitWanMu: "ཁྲི་མུ།",
@@ -561,11 +577,13 @@ export default {
561 577
     colIncomeGrowthRate: "འཕེལ་མྱུར།",
562 578
     colPovertyNetIncome: "དབུལ་སྐྱོབ་མི་མང་མི་རེའི་དག་ཡོང་།",
563 579
     formStatYear: "གཏོགས་ལོ།",
564
-    formRuralDisposableIncome: "གྲོང་གསེབ་མི་དམངས་མི་རེའི་སྤྱོད་ཆོག་ཡོང་འབབ།",
580
+    formRuralDisposableIncome: "མི་རེའི་སྤྱོད་ཆོག་ཡོང་འབབ།",
565 581
     formIncomeIncrease: "འཕར་ཚད།",
566 582
     formIncomeGrowthRate: "འཕེལ་མྱུར།",
567
-    formPovertyNetIncome: "དབུལ་སྐྱོབ་མི་མང་མི་རེའི་དག་ཡོང་།",
583
+    formPovertyNetIncome: "མི་རེའི་དག་ཡོང་།",
568 584
     formRemark: "ཟིན་བྲིས།",
585
+    sectionRuralResident: "གྲོང་གསེབ་མི་དམངས།",
586
+    sectionPovertyPopulation: "དབུལ་སྐྱོབ་མི་མང་།",
569 587
     phIncomeIncrease: "འདེམས་འབྲི,སྒོར;མ་འབྲི་ན་སྔོན་ལོ་ལྟར་རང་རྩིས།",
570 588
     phIncomeGrowthRate: "འདེམས་འབྲི,ཆ་ཤས་དཔེར་ན་ 0.1228;མ་འབྲི་ན་རང་རྩིས།",
571 589
     phRemark: "འདེམས་འབྲི,ཡིག་ཆ་500ལས་མི་ཆོག",
@@ -574,9 +592,10 @@ export default {
574 592
     confirmDelete: "ཐོ་གཞུང་འདི་སུབ་རྒྱུ་གཏན་ཁེལ་ལམ?",
575 593
     emptyList: "འབྲི་གཞི་གྲངས་མེད།",
576 594
     unitYuan: "སྒོར།",
595
+    unitPercent: "%",
577 596
     ruleStatYearRequired: "གཏོགས་ལོ་འདེམས་རོགས།",
578
-    ruleRuralIncomeRequired: "གྲོང་གསེབ་མི་དམངས་མི་རེའི་སྤྱོད་ཆོག་ཡོང་འབབ་འབྲི་རོགས།",
579
-    rulePovertyIncomeRequired: "དབུལ་སྐྱོབ་མི་མང་མི་རེའི་དག་ཡོང་འབྲི་རོགས།",
597
+    ruleRuralIncomeRequired: "མི་རེའི་སྤྱོད་ཆོག་ཡོང་འབབ་འབྲི་རོགས།",
598
+    rulePovertyIncomeRequired: "མི་རེའི་དག་ཡོང་འབྲི་རོགས།",
580 599
     ruleMoneyNonNegative: "0་ཡན་གྱི་གྲངས་དགོས།",
581 600
     ruleNumberInvalid: "ནུས་ལྡན་གྲངས་འབྲི་རོགས།"
582 601
   },
@@ -601,6 +620,8 @@ export default {
601 620
     formMeatOutput: "ཤ་ཐོན་ཚད།",
602 621
     formMilkOutput: "འོ་མ་ཐོན་ཚད།",
603 622
     formRemark: "ཟིན་བྲིས།",
623
+    sectionBasic: "གཞི་རྩའི་གནས་ཚུལ།",
624
+    sectionOutput: "ཕྱུགས་ལས་ཐོན་རྫས་ཐོན་ཚད་གནས་ཚུལ།",
604 625
     btnImport: "ནང་འདྲེན།",
605 626
     btnDownloadTemplate: "དཔེ་ཡིག་ཕབ་ལེན།",
606 627
     exportTitle: "Excel ཕྱིར་འདྲེན།",
@@ -655,8 +676,8 @@ export default {
655 676
     colEnterpriseType: "ཁེ་ལས་རིགས།",
656 677
     colRegisteredCapital: "ཐོ་འགོད་མ་རྩ།",
657 678
     colEstablishDate: "འཛུགས་དུས།",
658
-    colCattleYearEndStock: "གླང་གནས་ཚད།",
659
-    colCattleOutbound: "གླང་ཕྱིར་ཐོན།",
679
+    colCattleYearEndStock: "ལོ་མཇུག་གླང་གནས་ཚད་གྲངས།",
680
+    colCattleOutbound: "ལོ་མཇུག་གླང་ཕྱིར་ཐོན་གྲངས།",
660 681
     colGrasslandArea: "རྩྭ་ཐང་རྒྱ་ཁྱོན།",
661 682
     formStatYear: "གཏོགས་ལོ།",
662 683
     formStatMonth: "གཏོགས་ཟླ།",
@@ -667,14 +688,15 @@ export default {
667 688
     formEnterpriseType: "ཁེ་ལས་རིགས།",
668 689
     formRegisteredCapital: "ཐོ་འགོད་མ་རྩ།",
669 690
     formEstablishDate: "འཛུགས་དུས།",
670
-    formLivestockLaborCount: "ཕྱུགས་ལས་ངལ་རྩོལ་མི་སྣ།",
671
-    formCattleYearEndStock: "གླང་ལོ་མཇུག་གནས་ཚད།",
672
-    formCattleBreedingFemaleStock: "གླང་འཕེལ་ནུས་མོ་ཕྱུགས།",
673
-    formSheepYearEndStock: "ལུག་ལོ་མཇུག་གནས་ཚད།",
674
-    formSheepBreedingFemaleStock: "ལུག་འཕེལ་ནུས་མོ་ཕྱུགས།",
675
-    formCattleOutbound: "གླང་ཕྱིར་ཐོན།",
676
-    formSheepOutbound: "ལུག་ཕྱིར་ཐོན།",
677
-    formStockSubtotal: "ལོ་མཇུག་ཕྱུགས་གནས་ཚད་ཆུང་བསྡོམས།",
691
+    formLivestockLaborCount: "ཕྱུགས་ལས་ཐོན་སྐྱེད་ཚོང་གཉེར་ངལ་རྩོལ་མི་སྣ།",
692
+    formCattleYearEndStock: "ལོ་མཇུག་གླང་གནས་ཚད་གྲངས།",
693
+    formCattleBreedingFemaleStock: "ལོ་མཇུག་འཕེལ་ནུས་མོ་གླང་གནས་ཚད་གྲངས།",
694
+    formSheepYearEndStock: "ལོ་མཇུག་ལུག་གནས་ཚད་གྲངས།",
695
+    formSheepBreedingFemaleStock: "ལོ་མཇུག་འཕེལ་ནུས་མོ་ལུག་གནས་ཚད་གྲངས།",
696
+    formCattleOutbound: "ལོ་མཇུག་གླང་ཕྱིར་ཐོན་གྲངས།",
697
+    formSheepOutbound: "ལོ་མཇུག་ལུག་ཕྱིར་ཐོན་གྲངས།",
698
+    formStockSubtotal: "ལོ་མཇུག་ཕྱུགས་གནས་ཚད་སྤྱི་གྲངས།",
699
+    formOutboundSubtotal: "ལོ་མཇུག་ཕྱུགས་ཕྱིར་ཐོན་སྤྱི་གྲངས།",
678 700
     formGrassBalanceArea: "རྩྭ་ཕྱུགས་སྙོམས་རྒྱ་ཁྱོན།",
679 701
     formTransferGrassArea: "བརྗེ་སྤོ་ཚོང་གཉེར་རྩྭ་ས་རྒྱ་ཁྱོན།",
680 702
     formGrasslandAreaSubtotal: "རྩྭ་ཐང་རྒྱ་ཁྱོན་ཆུང་བསྡོམས།",
@@ -684,7 +706,7 @@ export default {
684 706
     formIncome: "ལོ་རེའི་ཚོང་གཉེར་ཡོང་འབབ་སྤྱི།",
685 707
     formExpense: "ལོ་རེའི་ཚོང་གཉེར་འགྲོ་སོང་སྤྱི།",
686 708
     formProfit: "ཁེ་བཟང་།",
687
-    formSubsidyYear: "རོགས་དངུལ་ལོ།",
709
+    formSubsidyYear: "རོགས་ཐོབ་ལོ།",
688 710
     formHasSubsidy: "རོགས་དངུལ་ཐོབ་ཡོད་དམ།",
689 711
     formSubsidyAmount: "རོགས་དངུལ།",
690 712
     formHasTrademark: "ཐོ་འགོད་ཐོབ་རྟགས་ཡོད་དམ།",
@@ -694,10 +716,13 @@ export default {
694 716
     formWagePaid: "གླ་ཕོགས་སྤྲོད།",
695 717
     formRemark: "ཟིན་བྲིས།",
696 718
     sectionBasic: "གཞི་རྩའི་གནས་ཚུལ།",
697
-    sectionStock: "གནས་ཚད་དང་ཕྱིར་ཐོན།",
698
-    sectionGrassland: "རྩྭ་ཐང་དང་རྩྭ་ཕྱུགས་སྙོམས།",
699
-    sectionFinance: "ཚོང་གཉེར་དང་རོགས་དངུལ།",
700
-    sectionOther: "གཞན།",
719
+    sectionRanchInfo: "ཁྱིམ་ཚང་འབྲོག་ར་གནས་ཚུལ།",
720
+    sectionStock: "ལོ་མཇུག་ཕྱུགས་གནས་ཚད་གནས་ཚུལ།",
721
+    sectionOutbound: "ལོ་མཇུག་ཕྱུགས་ཕྱིར་ཐོན་གནས་ཚུལ།",
722
+    sectionGrassland: "རྩྭ་ཕྱུགས་སྙོམས་གནས་ཚུལ།",
723
+    sectionFinance: "ལོ་རེའི་ཚོང་གཉེར་ཡོང་འབབ་སྤྱི།",
724
+    sectionSubsidy: "ཁྱིམ་ཚང་འབྲོག་ར་རོགས་དངུལ་ཐོབ་གནས་ཚུལ།",
725
+    sectionOther: "ཁྱིམ་ཚང་འབྲོག་ར་འཁོར་སྐྱོད་གནས་ཚུལ།",
701 726
     btnImport: "ནང་འདྲེན།",
702 727
     btnDownloadTemplate: "དཔེ་ཡིག་ཕབ་ལེན།",
703 728
     exportTitle: "Excel ཕྱིར་འདྲེན།",
@@ -726,6 +751,7 @@ export default {
726 751
     emptyList: "འབྲི་གཞི་གྲངས་མེད།",
727 752
     unitPerson: "མི།",
728 753
     unitHead: "ཨ།",
754
+    unitHeadSheepHorse: "ཨ་ཐོག་རྟ།",
729 755
     unitMu: "མུ།",
730 756
     unitWanYuan: "ཁྲི་སྒོར།",
731 757
     unitSheepUnit: "ལུག་རིམ།",
@@ -739,5 +765,256 @@ export default {
739 765
     ruleCountNonNegative: "0་ཡན་གྱི་ཧྲིལ་གྲངས་དགོས།",
740 766
     ruleDecimalNonNegative: "0་ཡན་གྱི་གྲངས་དགོས།",
741 767
     villageTreeEmpty: "གྲོང་ཚོའི་སྒྲིག་འཛུགས་མ་ལོན,ལས་ཁུངས་ནང་「ཤང་གྲོང→གྲོང་ཚོ」ཡོད་མེད་ཞིབ་རོགས།"
768
+  },
769
+  largeLivestockFarmer: {
770
+    queryStatYear: "གཏོགས་ལོ།",
771
+    queryStatMonth: "གཏོགས་ཟླ།",
772
+    queryTown: "ཤང་གྲོང།",
773
+    queryEnterpriseName: "ཁེ་ལས་མིང་།",
774
+    phVillageSearch: "འདེམས་པའམ་འཚོལ་འཇུག་རོགས།",
775
+    phEnterpriseName: "ཁེ་ལས་མིང་འབྲི་རོགས།",
776
+    phRemark: "འདེམས་འབྲི,ཡིག་ཆ་500ལས་མི་ཆོག",
777
+    colStatYear: "གཏོགས་ལོ།",
778
+    colStatMonth: "གཏོགས་ཟླ།",
779
+    statMonthLabel: "{month}ཟླ།",
780
+    colTownName: "ཤང་གྲོང།",
781
+    colVillageName: "གྲོང་ཚོ།",
782
+    colEnterpriseName: "ཁེ་ལས་མིང་།",
783
+    colLegalRepresentative: "ཁྲིམས་མིའི་ངོ་ཚབ།",
784
+    colEnterpriseType: "ཁེ་ལས་རིགས།",
785
+    colRegisteredCapital: "ཐོ་འགོད་མ་རྩ།",
786
+    colEstablishDate: "འཛུགས་དུས།",
787
+    colCattleYearEndStock: "ལོ་མཇུག་གླང་གནས་ཚད་གྲངས།",
788
+    colCattleOutbound: "ལོ་མཇུག་གླང་ཕྱིར་ཐོན་གྲངས།",
789
+    colGrasslandArea: "རྩྭ་ཐང་རྒྱ་ཁྱོན།",
790
+    formStatYear: "གཏོགས་ལོ།",
791
+    formStatMonth: "གཏོགས་ཟླ།",
792
+    formTown: "ཤང་གྲོང།",
793
+    formVillage: "གྲོང་ཚོ།",
794
+    formEnterpriseName: "ཁེ་ལས་མིང་།",
795
+    formLegalRepresentative: "ཁྲིམས་མིའི་ངོ་ཚབ།",
796
+    formEnterpriseType: "ཁེ་ལས་རིགས།",
797
+    formRegisteredCapital: "ཐོ་འགོད་མ་རྩ།",
798
+    formEstablishDate: "འཛུགས་དུས།",
799
+    formLivestockLaborCount: "ཕྱུགས་ལས་ཐོན་སྐྱེད་ཚོང་གཉེར་ངལ་རྩོལ་མི་སྣ།",
800
+    formCattleYearEndStock: "ལོ་མཇུག་གླང་གནས་ཚད་གྲངས།",
801
+    formCattleBreedingFemaleStock: "ལོ་མཇུག་འཕེལ་ནུས་མོ་གླང་གནས་ཚད་གྲངས།",
802
+    formSheepYearEndStock: "ལོ་མཇུག་ལུག་གནས་ཚད་གྲངས།",
803
+    formSheepBreedingFemaleStock: "ལོ་མཇུག་འཕེལ་ནུས་མོ་ལུག་གནས་ཚད་གྲངས།",
804
+    formCattleOutbound: "ལོ་མཇུག་གླང་ཕྱིར་ཐོན་གྲངས།",
805
+    formSheepOutbound: "ལོ་མཇུག་ལུག་ཕྱིར་ཐོན་གྲངས།",
806
+    formStockSubtotal: "ལོ་མཇུག་ཕྱུགས་གནས་ཚད་སྤྱི་གྲངས།",
807
+    formOutboundSubtotal: "ལོ་མཇུག་ཕྱུགས་ཕྱིར་ཐོན་སྤྱི་གྲངས།",
808
+    formGrassBalanceArea: "རྩྭ་ཕྱུགས་སྙོམས་རྒྱ་ཁྱོན།",
809
+    formTransferGrassArea: "བརྗེ་སྤོ་ཚོང་གཉེར་རྩྭ་ས་རྒྱ་ཁྱོན།",
810
+    formGrasslandAreaSubtotal: "རྩྭ་ཐང་རྒྱ་ཁྱོན་ཆུང་བསྡོམས།",
811
+    formApprovedCarryingCapacity: "གཏན་འཁེལ་ལོ་མཇུག་རྩྭ་ཕྱུགས་སྙོམས་ཁུར་ཚད།",
812
+    formYearEndStockSheepUnit: "ལོ་མཇུག་ཕྱུགས་གནས་ཚད།",
813
+    formIsGrassBalanced: "རྩྭ་ཕྱུགས་སྙོམས་ཁྱིམ་ཡིན་ནམ།",
814
+    formIncome: "ལོ་རེའི་ཚོང་གཉེར་ཡོང་འབབ་སྤྱི།",
815
+    formExpense: "ལོ་རེའི་ཚོང་གཉེར་འགྲོ་སོང་སྤྱི།",
816
+    formProfit: "ཁེ་བཟང་།",
817
+    formSubsidyYear: "རོགས་ཐོབ་ལོ།",
818
+    formHasSubsidy: "རོགས་དངུལ་ཐོབ་ཡོད་དམ།",
819
+    formSubsidyAmount: "རོགས་དངུལ།",
820
+    formHasTrademark: "ཐོ་འགོད་ཐོབ་རྟགས་ཡོད་དམ།",
821
+    formHasQualityCert: "ཞིང་ཐོན་སྤུས་ཚད་ངོས་འཛིན་བརྒྱུད་ཡོད་དམ།",
822
+    formSalesChannel: "ཐོན་རྫས་བཙོང་ལམ།",
823
+    formDrivenPopulation: "སྐུལ་འདེད་མི་གྲངས།",
824
+    formWagePaid: "གླ་ཕོགས་སྤྲོད།",
825
+    formRemark: "ཟིན་བྲིས།",
826
+    sectionBasic: "གཞི་རྩའི་གནས་ཚུལ།",
827
+    sectionFarmerInfo: "འཚོ་སྐྱོང་ཁེ་ལས་ཆེན་གནས་ཚུལ།",
828
+    sectionStock: "ལོ་མཇུག་ཕྱུགས་གནས་ཚད་གནས་ཚུལ།",
829
+    sectionOutbound: "ལོ་མཇུག་ཕྱུགས་ཕྱིར་ཐོན་གནས་ཚུལ།",
830
+    sectionGrassland: "རྩྭ་ཕྱུགས་སྙོམས་གནས་ཚུལ།",
831
+    sectionFinance: "ལོ་རེའི་ཚོང་གཉེར་ཡོང་འབབ་སྤྱི།",
832
+    sectionSubsidy: "འཚོ་སྐྱོང་ཁེ་ལས་ཆེན་རོགས་དངུལ་ཐོབ་གནས་ཚུལ།",
833
+    sectionOther: "འཚོ་སྐྱོང་ཁེ་ལས་ཆེན་འཁོར་སྐྱོད་གནས་ཚུལ།",
834
+    btnImport: "ནང་འདྲེན།",
835
+    btnDownloadTemplate: "དཔེ་ཡིག་ཕབ་ལེན།",
836
+    exportTitle: "Excel ཕྱིར་འདྲེན།",
837
+    exportStatYear: "གཏོགས་ལོ།",
838
+    exportStatYearPh: "གཏོགས་ལོ་འདེམས་རོགས།",
839
+    exportStatMonth: "གཏོགས་ཟླ།",
840
+    exportStatMonthPh: "གཏོགས་ཟླ་འདེམས་རོགས།",
841
+    exportStatYearRequired: "གཏོགས་ལོ་འདེམས་རོགས།",
842
+    exportStatMonthRequired: "གཏོགས་ཟླ་འདེམས་རོགས།",
843
+    exportStatYearInvalid: "ཕྱིར་འདྲེན་ལོ་ཟླ་འདེམས་ཁོངས་ནང་མེད།",
844
+    exportLoading: "ཕྱིར་འདྲེན་བཞིན... སྒུག་རོགས།",
845
+    exportFail: "ཕྱིར་འདྲེན་ཕམ།",
846
+    importTitle: "Excel ནང་འདྲེན།",
847
+    importStatYear: "འབྲི་ལོ།",
848
+    importStatYearPh: "འབྲི་ལོ་འདེམས་རོགས།",
849
+    importStatMonth: "འབྲི་ཟླ།",
850
+    importStatMonthPh: "འབྲི་ཟླ་འདེམས་རོགས།",
851
+    importTip: "སྔོན་ལ་འབྲི་ལོ་ཟླ་འདེམས,དེ་ནས་དཔེ་ཡིག་དང་མཐུན་པའི .xlsx ཡར་འཇུག;ལོ་ཟླ་གྲོང་ཚོ་ཁེ་ལས་མིང་གཅིག་པ་ཡོད་ན་རྩོམ་སྒྲིག",
852
+    importLoading: "ནང་འདྲེན་བཞིན... སྒུག་རོགས།",
853
+    importSummary: "ནང་འདྲེན་ཟིན:གསར་{insert} རྩོམ་{update} ཕམ་{fail}",
854
+    importWarnTitle: "ནང་འདྲེན་ཉེན་བརྡ།",
855
+    importFailTitle: "ནང་འདྲེན་ཕམ་ཞིབ།",
856
+    dialogAdd: "[གསར་སྣོན]འཚོ་སྐྱོང་ཁེ་ལས་ཆེན་གཞི་གྲངས།",
857
+    dialogEdit: "[རྩོམ་སྒྲིག]འཚོ་སྐྱོང་ཁེ་ལས་ཆེན་གཞི་གྲངས།",
858
+    confirmDelete: "ཐོ་གཞུང་འདི་སུབ་རྒྱུ་གཏན་ཁེལ་ལམ?",
859
+    emptyList: "འབྲི་གཞི་གྲངས་མེད།",
860
+    unitPerson: "མི།",
861
+    unitHead: "ཨ།",
862
+    unitHeadSheepHorse: "ཨ་ཐོག་རྟ།",
863
+    unitMu: "མུ།",
864
+    unitWanYuan: "ཁྲི་སྒོར།",
865
+    unitSheepUnit: "ལུག་རིམ།",
866
+    ruleStatYearRequired: "གཏོགས་ལོ་འདེམས་རོགས།",
867
+    ruleStatMonthRequired: "གཏོགས་ཟླ་འདེམས་རོགས།",
868
+    ruleStatMonthFuture: "མ་འོངས་ཟླ་འབྲི་མི་ཆོག",
869
+    ruleVillageRequired: "གྲོང་ཚོ་འདེམས་རོགས།",
870
+    ruleEnterpriseNameRequired: "ཁེ་ལས་མིང་འབྲི་རོགས།",
871
+    ruleEnterpriseNameLen: "ཁེ་ལས་མིང་ཡིག་ཆ་200ལས་མི་ཆོག",
872
+    ruleLegalRepLen: "ཁྲིམས་མིའི་ངོ་ཚབ་ཡིག་ཆ་64ལས་མི་ཆོག",
873
+    ruleCountNonNegative: "0་ཡན་གྱི་ཧྲིལ་གྲངས་དགོས།",
874
+    ruleDecimalNonNegative: "0་ཡན་གྱི་གྲངས་དགོས།",
875
+    villageTreeEmpty: "གྲོང་ཚོའི་སྒྲིག་འཛུགས་མ་ལོན,ལས་ཁུངས་ནང་「ཤང་གྲོང→གྲོང་ཚོ」ཡོད་མེད་ཞིབ་རོགས།"
876
+  },
877
+  farmerHousehold: {
878
+    queryStatYear: "གཏོགས་ལོ།",
879
+    queryStatMonth: "གཏོགས་ཟླ།",
880
+    queryTown: "ཤང་གྲོང།",
881
+    phVillageSearch: "འདེམས་པའམ་འཚོལ་འཇུག་རོགས།",
882
+    phRemark: "འདེམས་འབྲི,ཡིག་ཆ་500ལས་མི་ཆོག",
883
+    colStatYear: "གཏོགས་ལོ།",
884
+    colStatMonth: "གཏོགས་ཟླ།",
885
+    statMonthLabel: "{month}ཟླ།",
886
+    colTownName: "ཤང་གྲོང།",
887
+    colVillageName: "གྲོང་ཚོ།",
888
+    colHouseholdCount: "ཞིང་འབྲོག་ཁྱིམ་གྲངས།",
889
+    colPopulationCount: "ཞིང་འབྲོག་མི་གྲངས།",
890
+    colPastureContractArea: "རྩྭ་ཐང་གཉེར་ལེན་རྒྱ་ཁྱོན་སྤྱི།",
891
+    formStatYear: "གཏོགས་ལོ།",
892
+    formStatMonth: "གཏོགས་ཟླ།",
893
+    formTown: "ཤང་གྲོང།",
894
+    formVillage: "གྲོང་ཚོ།",
895
+    formHouseholdCount: "ཞིང་འབྲོག་ཁྱིམ་གྲངས།",
896
+    formPopulationCount: "ཞིང་འབྲོག་མི་གྲངས།",
897
+    formPastureContractArea: "རྩྭ་ཐང་གཉེར་ལེན་རྒྱ་ཁྱོན་སྤྱི།",
898
+    formGrazingBanArea: "འཚོ་བཀག་རྒྱ་ཁྱོན།",
899
+    formGrassBalanceArea: "རྩྭ་ཕྱུགས་སྙོམས་རྒྱ་ཁྱོན།",
900
+    formApprovedCarryingCapacity: "གཏན་འཁེལ་ལོ་མཇུག་རྩྭ་ཕྱུགས་སྙོམས་ཁུར་ཚད།",
901
+    formYearEndStockSheepUnit: "ལོ་མཇུག་ཕྱུགས་གནས་ཚད།",
902
+    formIsPureHerder: "འབྲོག་པ་དག་པ་ཡིན་ནམ།",
903
+    formIsNoLivestock: "ཕྱུགས་མེད་ཁྱིམ་ཡིན་ནམ།",
904
+    formIsExtinctHousehold: "ཁྱིམ་ཆད་ཡིན་ནམ།",
905
+    formIsOverloadHerder: "ཁུར་བརྒལ་འབྲོག་པ་ཡིན་ནམ།",
906
+    formNeedCap: "རྩེ་གཅོད་དགོས་སམ།",
907
+    formNeedFloor: "རྨང་སྲུང་དགོས་སམ།",
908
+    formGrazingBanSubsidy: "འཚོ་བཀག་རོགས་དངུལ།",
909
+    formGrassBalanceReward: "རྩྭ་ཕྱུགས་སྙོམས་བྱ་དགའ།",
910
+    formSubsidyRewardSubtotal: "རོགས་དངུལ་བྱ་དགའ་སྤྱི།",
911
+    formAfterCapFloorSubsidy: "རྩེ་གཅོད་རྨང་སྲུང་རྗེས་རོགས་དངུལ་སྤྱི།",
912
+    formVillageSupervisorSubsidy: "གྲོང་ཚོའི་རྩྭ་ཐང་ལྟ་རྟོག་པ་རོགས་དངུལ།",
913
+    formSubsidyTotal: "རོགས་དངུལ་བསྡོམས།",
914
+    formRemark: "ཟིན་བྲིས།",
915
+    sectionBasic: "གཞི་རྩའི་གནས་ཚུལ།",
916
+    sectionPasture: "རྩྭ་ཕྱུགས་སྙོམས་གནས་ཚུལ།",
917
+    sectionCapFloor: "རྩེ་གཅོད་རྨང་སྲུང་གནས་ཚུལ།",
918
+    sectionSubsidy: "ད་ལོ་རོགས་ཐོབ་གནས་ཚུལ།",
919
+    btnImport: "ནང་འདྲེན།",
920
+    btnDownloadTemplate: "དཔེ་ཡིག་ཕབ་ལེན།",
921
+    exportTitle: "Excel ཕྱིར་འདྲེན།",
922
+    exportStatYear: "གཏོགས་ལོ།",
923
+    exportStatYearPh: "གཏོགས་ལོ་འདེམས་རོགས།",
924
+    exportStatMonth: "གཏོགས་ཟླ།",
925
+    exportStatMonthPh: "གཏོགས་ཟླ་འདེམས་རོགས།",
926
+    exportTown: "ཤང་གྲོང།",
927
+    exportTownPh: "མ་འདེམས་ན་ལོ་ཟླ་དེའི་ཤང་གྲོང་ཚང་མ་ཕྱིར་འདྲེན།",
928
+    exportStatYearRequired: "གཏོགས་ལོ་འདེམས་རོགས།",
929
+    exportStatMonthRequired: "གཏོགས་ཟླ་འདེམས་རོགས།",
930
+    exportLoading: "ཕྱིར་འདྲེན་བཞིན... སྒུག་རོགས།",
931
+    exportFail: "ཕྱིར་འདྲེན་ཕམ།",
932
+    importTitle: "Excel ནང་འདྲེན།",
933
+    importStatYear: "འབྲི་ལོ།",
934
+    importStatYearPh: "འབྲི་ལོ་འདེམས་རོགས།",
935
+    importStatMonth: "འབྲི་ཟླ།",
936
+    importStatMonthPh: "འབྲི་ཟླ་འདེམས་རོགས།",
937
+    importTip: "སྔོན་ལ་འབྲི་ལོ་ཟླ་འདེམས,དེ་ནས་དཔེ་ཡིག་དང་མཐུན་པའི .xlsx ཡར་འཇུག;ལོ་ཟླ་གྲོང་ཚོ་གཅིག་པ་ཡོད་ན་རྩོམ་སྒྲིག",
938
+    importLoading: "ནང་འདྲེན་བཞིན... སྒུག་རོགས།",
939
+    importSummary: "ནང་འདྲེན་ཟིན:གསར་{insert} རྩོམ་{update} ཕམ་{fail}",
940
+    importWarnTitle: "ནང་འདྲེན་ཉེན་བརྡ།",
941
+    importFailTitle: "ནང་འདྲེན་ཕམ་ཞིབ།",
942
+    dialogAdd: "[གསར་སྣོན]ཞིང་འབྲོག་ཁྱིམ་གཞི་གྲངས།",
943
+    dialogEdit: "[རྩོམ་སྒྲིག]ཞིང་འབྲོག་ཁྱིམ་གཞི་གྲངས།",
944
+    confirmDelete: "ཐོ་གཞུང་འདི་སུབ་རྒྱུ་གཏན་ཁེལ་ལམ?",
945
+    emptyList: "འབྲི་གཞི་གྲངས་མེད།",
946
+    unitHousehold: "ཁྱིམ།",
947
+    unitPerson: "མི།",
948
+    unitMu: "མུ།",
949
+    unitYuan: "སྒོར།",
950
+    unitSheepUnit: "ལུག་རིམ།",
951
+    ruleStatYearRequired: "གཏོགས་ལོ་འདེམས་རོགས།",
952
+    ruleStatMonthRequired: "གཏོགས་ཟླ་འདེམས་རོགས།",
953
+    ruleStatMonthFuture: "མ་འོངས་ཟླ་འབྲི་མི་ཆོག",
954
+    ruleVillageRequired: "གྲོང་ཚོ་འདེམས་རོགས།",
955
+    ruleCountNonNegative: "0་ཡན་གྱི་ཧྲིལ་གྲངས་དགོས།",
956
+    ruleDecimalNonNegative: "0་ཡན་གྱི་གྲངས་དགོས།",
957
+    villageTreeEmpty: "གྲོང་ཚོའི་སྒྲིག་འཛུགས་མ་ལོན,ལས་ཁུངས་ནང་「ཤང་གྲོང→གྲོང་ཚོ」ཡོད་མེད་ཞིབ་རོགས།"
958
+  },
959
+  vaccinationData: {
960
+    queryStatYear: "གཏོགས་ལོ།",
961
+    queryStatMonth: "གཏོགས་ཟླ།",
962
+    queryTown: "ཤང་གྲོང།",
963
+    queryVillage: "གྲོང་ཚོ།",
964
+    phVillageSearch: "འདེམས་པའམ་འཚོལ་འཇུག་རོགས།",
965
+    phRemark: "འདེམས་འབྲི,ཡིག་ཆ་500ལས་མི་ཆོག",
966
+    colStatYear: "གཏོགས་ལོ།",
967
+    colStatMonth: "གཏོགས་ཟླ།",
968
+    statMonthLabel: "{month}ཟླ།",
969
+    colTownName: "ཤང་གྲོང།",
970
+    colVillageName: "གྲོང་ཚོ།",
971
+    colShouldVaccinateCount: "འགོག་དགོས་གྲངས།",
972
+    colActualVaccinateCount: "དངོས་འགོག་གྲངས།",
973
+    colImmunityRate: "འགོག་ནད་ཕྱོད།",
974
+    formStatYear: "གཏོགས་ལོ།",
975
+    formStatMonth: "གཏོགས་ཟླ།",
976
+    formTown: "ཤང་གྲོང།",
977
+    formVillage: "གྲོང་ཚོ།",
978
+    formShouldVaccinateCount: "འགོག་དགོས་གྲངས།",
979
+    formActualVaccinateCount: "དངོས་འགོག་གྲངས།",
980
+    formImmunityRate: "འགོག་ནད་ཕྱོད།",
981
+    formRemark: "ཟིན་བྲིས།",
982
+    sectionBasic: "གཞི་རྩའི་གནས་ཚུལ།",
983
+    sectionVaccination: "སྨན་ཁབ་འགོག་ནད་གནས་ཚུལ།",
984
+    btnImport: "ནང་འདྲེན།",
985
+    btnDownloadTemplate: "དཔེ་ཡིག་ཕབ་ལེན།",
986
+    exportTitle: "Excel ཕྱིར་འདྲེན།",
987
+    exportStatYear: "གཏོགས་ལོ།",
988
+    exportStatYearPh: "གཏོགས་ལོ་འདེམས་རོགས།",
989
+    exportStatMonth: "གཏོགས་ཟླ།",
990
+    exportStatMonthPh: "གཏོགས་ཟླ་འདེམས་རོགས།",
991
+    exportTown: "ཤང་གྲོང།",
992
+    exportTownPh: "མ་འདེམས་ན་ལོ་ཟླ་དེའི་ཤང་གྲོང་ཚང་མ་ཕྱིར་འདྲེན།",
993
+    exportStatYearRequired: "གཏོགས་ལོ་འདེམས་རོགས།",
994
+    exportStatMonthRequired: "གཏོགས་ཟླ་འདེམས་རོགས།",
995
+    exportLoading: "ཕྱིར་འདྲེན་བཞིན... སྒུག་རོགས།",
996
+    exportFail: "ཕྱིར་འདྲེན་ཕམ།",
997
+    importTitle: "Excel ནང་འདྲེན།",
998
+    importStatYear: "འབྲི་ལོ།",
999
+    importStatYearPh: "འབྲི་ལོ་འདེམས་རོགས།",
1000
+    importStatMonth: "འབྲི་ཟླ།",
1001
+    importStatMonthPh: "འབྲི་ཟླ་འདེམས་རོགས།",
1002
+    importTip: "སྔོན་ལ་འབྲི་ལོ་ཟླ་འདེམས,དེ་ནས་དཔེ་ཡིག་དང་མཐུན་པའི .xlsx ཡར་འཇུག;ལོ་ཟླ་གྲོང་ཚོ་གཅིག་པ་ཡོད་ན་རྩོམ་སྒྲིག",
1003
+    importLoading: "ནང་འདྲེན་བཞིན... སྒུག་རོགས།",
1004
+    importSummary: "ནང་འདྲེན་ཟིན:གསར་{insert} རྩོམ་{update} ཕམ་{fail}",
1005
+    importWarnTitle: "ནང་འདྲེན་ཉེན་བརྡ།",
1006
+    importFailTitle: "ནང་འདྲེན་ཕམ་ཞིབ།",
1007
+    dialogAdd: "[གསར་སྣོན]སྨན་ཁབ་འགོག་ནད་གཞི་གྲངས།",
1008
+    dialogEdit: "[རྩོམ་སྒྲིག]སྨན་ཁབ་འགོག་ནད་གཞི་གྲངས།",
1009
+    confirmDelete: "ཐོ་གཞུང་འདི་སུབ་རྒྱུ་གཏན་ཁེལ་ལམ?",
1010
+    emptyList: "འབྲི་གཞི་གྲངས་མེད།",
1011
+    unitHead: "མགོ།",
1012
+    ruleStatYearRequired: "གཏོགས་ལོ་འདེམས་རོགས།",
1013
+    ruleStatMonthRequired: "གཏོགས་ཟླ་འདེམས་རོགས།",
1014
+    ruleStatMonthFuture: "མ་འོངས་ཟླ་འབྲི་མི་ཆོག",
1015
+    ruleVillageRequired: "གྲོང་ཚོ་འདེམས་རོགས།",
1016
+    ruleCountNonNegative: "0་ཡན་གྱི་ཧྲིལ་གྲངས་དགོས།",
1017
+    ruleActualLeShould: "དངོས་འགོག་གྲངས་འགོག་དགོས་གྲངས་ལས་མང་མི་ཆོག",
1018
+    villageTreeEmpty: "གྲོང་ཚོའི་སྒྲིག་འཛུགས་མ་ལོན,ལས་ཁུངས་ནང་「ཤང་གྲོང→གྲོང་ཚོ」ཡོད་མེད་ཞིབ་རོགས།"
742 1019
   }
743 1020
 }

+ 17 - 15
ruoyi-ui/src/lang/zh/commonProsperity.js

@@ -43,7 +43,9 @@ export default {
43 43
     viewOfflineTime: "下架时间",
44 44
     ruleLen120: "项目名称长度在 1 到 20 个字符",
45 45
     ruleLen150: "长度在 1 到 50 个字符",
46
+    ruleLen50Optional: "长度不能超过 50 个字符",
46 47
     ruleLen1500: "长度在 1 到 500 个字符",
48
+    ruleLen500Optional: "长度不能超过 500 个字符",
47 49
     ruleImplEndBeforeStart: "实施结束日期不能早于开始日期",
48 50
     ruleRateRange: "比率须在 0~1 之间",
49 51
     ruleNonNegativeInteger: "须为非负整数",
@@ -66,40 +68,40 @@ export default {
66 68
     queryProjectName: "项目名称",
67 69
     queryProjectNamePh: "项目名称模糊查询",
68 70
     queryProjectType: "项目类型",
71
+    queryImplYear: "实施年限",
69 72
     queryPublishStatus: "发布状态",
70 73
     colProjectName: "项目名称",
71 74
     colProjectType: "项目类型",
72 75
     colIntro: "项目简介",
73
-    colImplDate: "实施日期",
76
+    colImplYear: "实施年限",
74 77
     colOpImageCount: "运营图片",
75 78
     colCover: "封面",
76
-    colContent: "项目内容",
79
+    colContent: "建设规模及内容",
77 80
     colVideo: "运营视频",
78 81
     formProjectName: "项目名称",
79 82
     formProjectType: "项目类型",
80 83
     formIntro: "项目简介",
81
-    formContent: "项目内容",
82
-    formImplDate: "实施日期",
83
-    implRangeSeparator: "至",
84
-    implRangeStartPh: "开始日期",
85
-    implRangeEndPh: "结束日期",
84
+    formContent: "建设规模及内容",
85
+    formInvestmentAmount: "投资金额",
86
+    formImplYear: "实施年限",
87
+    formImplStatus: "实施情况",
86 88
     formOpImages: "运营图片",
87 89
     formVideo: "运营视频",
88 90
     formCover: "封面",
89 91
     phProjectName: "请输入项目名称",
90
-    phIntro: "请输入项目简介",
91
-    phContent: "请输入项目内容",
92
+    phIntro: "选填,不超过 50 字",
93
+    phContent: "请输入建设规模及内容",
94
+    phImplStatus: "选填,不超过 500 字",
92 95
     ruleProjectNameRequired: "请输入项目名称",
93 96
     ruleProjectTypeRequired: "请选择项目类型",
94
-    ruleIntroRequired: "请输入项目简介",
95
-    ruleContentRequired: "请输入项目内容",
96
-    ruleImplDateRequired: "请选择实施日期",
97
+    ruleContentRequired: "请输入建设规模及内容",
98
+    ruleImplYearRequired: "请选择实施年限",
97 99
     ruleOpImagesRequired: "请上传至少 1 张运营图片",
98 100
     dialogAdd: "[新增]共同富裕项目",
99 101
     dialogEdit: "[编辑]共同富裕项目",
100
-    type1: "合作共赢",
101
-    type2: "农文旅融合",
102
-    type3: "认养农业",
102
+    type1: "和美乡村建设项目",
103
+    type2: "人居环境整治提升项目",
104
+    type3: "其他项目投入",
103 105
     confirmDelete: "是否确认删除这条数据?",
104 106
     confirmPublish: "确认发布该共同富裕项目吗?发布后不可修改。",
105 107
     confirmOffline: "确认下架该共同富裕项目吗?下架后可再次编辑并发布。",

+ 324 - 47
ruoyi-ui/src/lang/zh/dataModel.js

@@ -286,9 +286,13 @@ export default {
286 286
     statMonthLabel: "{month}月",
287 287
     colVillageCount: "村居数",
288 288
     colHerdsmanHouseholdCount: "牧户数",
289
-    colYakTotal: "存栏数",
290
-    colBullTotal: "公牛存栏数",
291
-    colCowTotal: "母牛存栏数",
289
+    colBullTotal: "公牛总存栏数",
290
+    colCowTotal: "母牛总存栏数",
291
+    colDairyTotal: "奶牛总存栏数",
292
+    colSheepTotal: "羊总存栏数",
293
+    colInsuredYakCount: "保险牦牛存栏数",
294
+    colYakTotal: "牦牛总存栏数",
295
+    colGrandTotal: "总存栏数",
292 296
     formStatYear: "所属年份",
293 297
     formStatMonth: "所属月份",
294 298
     formTown: "所属乡镇",
@@ -297,22 +301,28 @@ export default {
297 301
     formHerdsmanHouseholdCount: "牧户数",
298 302
     formBreedingBullCount: "种公牛存栏数",
299 303
     formBullCastratedCount: "公牛/阉畜存栏数",
300
-    formCowYoungCount: "0~1.5岁幼畜存栏数",
301
-    formCowAdultCount: "1.5岁以上成畜存栏数",
304
+    formCowYoungCount: "0~1.5岁幼畜(不包括1.5岁)存栏数",
305
+    formCowAdultCount: "1.5岁以上成畜(包括1.5岁)存栏数",
302 306
     formMilkingCowCount: "产奶母牛存栏数",
303 307
     formFertileCowCount: "能繁母牛存栏数",
304 308
     formSheepTotal: "羊总存栏数",
305 309
     formMilkingSheepCount: "产奶羊存栏数",
306 310
     formInsuredYakCount: "保险牦牛存栏数",
307
-    formBullTotal: "公牛合计",
308
-    formCowTotal: "母牛合计",
309
-    formDairyTotal: "奶牛合计",
310
-    formYakTotal: "牦牛总存栏",
311
-    formGrandTotal: "总合计",
311
+    formBullTotal: "公牛总存栏数",
312
+    formCowTotal: "母牛总存栏数",
313
+    formDairyTotal: "奶牛总存栏数",
314
+    formYakTotal: "牦牛总存栏",
315
+    formGrandTotal: "总存栏数",
312 316
     formYakSheepTotal: "总量(牦牛+羊)",
313 317
     formRemark: "备注",
314 318
     phRemark: "选填,不超过 500 字",
315 319
     sectionBasic: "基本信息",
320
+    sectionFarmer: "农牧户情况",
321
+    sectionBull: "公牛存栏情况",
322
+    sectionCow: "母牛存栏情况",
323
+    sectionDairy: "奶牛存栏情况",
324
+    sectionSheep: "羊存栏情况",
325
+    sectionSummary: "汇总",
316 326
     sectionInventory: "存栏指标",
317 327
     btnImport: "导入",
318 328
     btnDownloadTemplate: "下载模板",
@@ -392,7 +402,7 @@ export default {
392 402
     phRemark: "选填,不超过 500 字",
393 403
     sectionBasic: "基本信息",
394 404
     sectionFarmer: "农牧户情况",
395
-    sectionOutbound: "出栏情况",
405
+    sectionOutbound: "牲畜出栏情况",
396 406
     sectionSelfConsumption: "自食情况",
397 407
     btnImport: "导入",
398 408
     btnDownloadTemplate: "下载模板",
@@ -427,6 +437,7 @@ export default {
427 437
     unitHead: "头",
428 438
     unitSheep: "只",
429 439
     unitHorse: "匹",
440
+    unitHeadSheepHorse: "头只匹",
430 441
     ruleStatYearRequired: "请选择所属年份",
431 442
     ruleStatMonthRequired: "请选择所属月份",
432 443
     ruleStatMonthFuture: "不可填报未来月份",
@@ -467,12 +478,12 @@ export default {
467 478
     formEstablishDate: "成立时间",
468 479
     formRegisteredCapital: "注册资本",
469 480
     formYearEndTotalAssets: "截止年底总资产",
470
-    formMemberHouseholdCount: "入社户数",
471
-    formMemberPopulationCount: "入社人数",
472
-    formPovertyMonitorCount: "防返贫监测人数",
481
+    formMemberHouseholdCount: "户数",
482
+    formMemberPopulationCount: "人数",
483
+    formPovertyMonitorCount: "防返贫监测",
473 484
     formCattleShareCount: "牛入股数量",
474 485
     formSheepShareCount: "羊入股数量",
475
-    formLivestockShareTotal: "牲畜入股小计",
486
+    formLivestockShareTotal: "牲畜总入股数量",
476 487
     formGrasslandShareArea: "草场入股",
477 488
     formLaborShareCount: "劳动力入股",
478 489
     formCashShareAmount: "现金入股",
@@ -487,25 +498,29 @@ export default {
487 498
     formCollegeGraduateWage: "大学生工资性收入",
488 499
     formFarmerTransferEmploymentCount: "农牧民转移就业",
489 500
     formFarmerTransferWage: "农牧民工资性收入",
490
-    formCattleInventoryCount: "牛存栏",
491
-    formCattleOutboundCount: "牛出栏",
492
-    formSheepInventoryCount: "羊存栏",
493
-    formSheepOutboundCount: "羊出栏",
501
+    formCattleInventoryCount: "牛存栏",
502
+    formCattleOutboundCount: "牛出栏",
503
+    formSheepInventoryCount: "羊存栏",
504
+    formSheepOutboundCount: "羊出栏",
494 505
     formTrademarkProductCount: "注册商标产品数量",
495 506
     formQualityCertProductCount: "质量认证产品数量",
496
-    formTrainingManageCount: "培训-管理能力",
497
-    formTrainingSkillCount: "培训-专业技能",
498
-    formTrainingOtherCount: "培训-其他",
507
+    formTrainingManageCount: "管理能力",
508
+    formTrainingSkillCount: "专业技能",
509
+    formTrainingOtherCount: "其他",
499 510
     formBusinessScope: "主要经营范围",
500 511
     formBusinessModel: "经营模式分类",
501
-    formOperationStatus: "运营情况",
512
+    formOperationStatus: "合作社运营情况",
502 513
     formRemark: "备注",
503 514
     sectionBasic: "基本信息",
504
-    sectionMemberShare: "入社与入股",
505
-    sectionBenefit: "效益情况",
506
-    sectionEmploymentLivestock: "就业与存出栏",
507
-    sectionProductTraining: "产品认证与培训",
508
-    sectionOperation: "经营情况",
515
+    sectionCooperativeInfo: "合作社信息",
516
+    sectionMemberShare: "农牧民入社情况",
517
+    sectionBenefit: "年度效益发挥情况",
518
+    sectionEmployment: "合作社领域吸纳就业情况",
519
+    sectionLivestockInout: "合作社牲畜存出栏情况",
520
+    sectionProductCert: "产品认证情况",
521
+    sectionTraining: "合作社社员培训情况",
522
+    sectionOperation: "合作社经营范围及模式",
523
+    sectionOperationStatus: "合作社运营情况",
509 524
     btnImport: "导入",
510 525
     btnChooseFile: "选取文件",
511 526
     btnDownloadTemplate: "下载模板",
@@ -538,6 +553,7 @@ export default {
538 553
     unitHousehold: "户",
539 554
     unitPerson: "人",
540 555
     unitHead: "头",
556
+    unitHeadSheepHorse: "头只匹",
541 557
     unitGe: "个",
542 558
     unitWanYuan: "万元",
543 559
     unitWanMu: "万亩",
@@ -561,11 +577,13 @@ export default {
561 577
     colIncomeGrowthRate: "增速",
562 578
     colPovertyNetIncome: "脱贫人口人均纯收入",
563 579
     formStatYear: "所属年份",
564
-    formRuralDisposableIncome: "农村居民人均可支配收入",
580
+    formRuralDisposableIncome: "人均可支配收入",
565 581
     formIncomeIncrease: "增幅",
566 582
     formIncomeGrowthRate: "增速",
567
-    formPovertyNetIncome: "脱贫人口人均纯收入",
583
+    formPovertyNetIncome: "人均纯收入",
568 584
     formRemark: "备注",
585
+    sectionRuralResident: "农村居民",
586
+    sectionPovertyPopulation: "脱贫人口",
569 587
     phIncomeIncrease: "选填,元;不填则按上年自动计算",
570 588
     phIncomeGrowthRate: "选填,小数如 0.1228;不填则自动计算",
571 589
     phRemark: "选填,不超过 500 字",
@@ -574,9 +592,10 @@ export default {
574 592
     confirmDelete: "是否确认删除这条数据?",
575 593
     emptyList: "暂无填报数据",
576 594
     unitYuan: "元",
595
+    unitPercent: "%",
577 596
     ruleStatYearRequired: "请选择所属年份",
578
-    ruleRuralIncomeRequired: "请输入农村居民人均可支配收入",
579
-    rulePovertyIncomeRequired: "请输入脱贫人口人均纯收入",
597
+    ruleRuralIncomeRequired: "请输入人均可支配收入",
598
+    rulePovertyIncomeRequired: "请输入人均纯收入",
580 599
     ruleMoneyNonNegative: "须为大于等于 0 的数字",
581 600
     ruleNumberInvalid: "请输入有效数字"
582 601
   },
@@ -601,6 +620,8 @@ export default {
601 620
     formMeatOutput: "肉产量",
602 621
     formMilkOutput: "奶产量",
603 622
     formRemark: "备注",
623
+    sectionBasic: "基本信息",
624
+    sectionOutput: "畜牧产品产量信息",
604 625
     btnImport: "导入",
605 626
     btnDownloadTemplate: "下载模板",
606 627
     exportTitle: "Excel 导出",
@@ -655,8 +676,8 @@ export default {
655 676
     colEnterpriseType: "企业类型",
656 677
     colRegisteredCapital: "注册资本",
657 678
     colEstablishDate: "成立时间",
658
-    colCattleYearEndStock: "牛存栏",
659
-    colCattleOutbound: "牛出栏",
679
+    colCattleYearEndStock: "年底牛存栏",
680
+    colCattleOutbound: "年底牛出栏",
660 681
     colGrasslandArea: "草场面积",
661 682
     formStatYear: "所属年份",
662 683
     formStatMonth: "所属月份",
@@ -667,14 +688,15 @@ export default {
667 688
     formEnterpriseType: "企业类型",
668 689
     formRegisteredCapital: "注册资本",
669 690
     formEstablishDate: "成立时间",
670
-    formLivestockLaborCount: "从事畜牧业劳力人员",
671
-    formCattleYearEndStock: "牛年底存栏",
672
-    formCattleBreedingFemaleStock: "牛能繁母畜",
673
-    formSheepYearEndStock: "羊年底存栏",
674
-    formSheepBreedingFemaleStock: "羊能繁母畜",
675
-    formCattleOutbound: "牛出栏",
676
-    formSheepOutbound: "羊出栏",
677
-    formStockSubtotal: "年底牲畜存栏小计",
691
+    formLivestockLaborCount: "从事畜牧业生产经营劳力人员",
692
+    formCattleYearEndStock: "年底牛存栏数",
693
+    formCattleBreedingFemaleStock: "年底能繁母牛存栏数",
694
+    formSheepYearEndStock: "年底羊存栏数",
695
+    formSheepBreedingFemaleStock: "年底能繁母羊存栏数",
696
+    formCattleOutbound: "年底牛出栏数",
697
+    formSheepOutbound: "年底羊出栏数",
698
+    formStockSubtotal: "年底牲畜总存栏数",
699
+    formOutboundSubtotal: "年底牲畜总出栏数",
678 700
     formGrassBalanceArea: "草畜平衡面积",
679 701
     formTransferGrassArea: "流转经营草地面积",
680 702
     formGrasslandAreaSubtotal: "草场面积小计",
@@ -684,7 +706,7 @@ export default {
684 706
     formIncome: "年度经营总收入",
685 707
     formExpense: "年度经营总支出",
686 708
     formProfit: "利润",
687
-    formSubsidyYear: "补助资金年份",
709
+    formSubsidyYear: "受助年份",
688 710
     formHasSubsidy: "是否享受补助",
689 711
     formSubsidyAmount: "补贴资金",
690 712
     formHasTrademark: "是否有注册商标",
@@ -694,10 +716,13 @@ export default {
694 716
     formWagePaid: "发放工资",
695 717
     formRemark: "备注",
696 718
     sectionBasic: "基本信息",
697
-    sectionStock: "存栏与出栏",
698
-    sectionGrassland: "草场与草畜平衡",
699
-    sectionFinance: "经营与补助",
700
-    sectionOther: "其他",
719
+    sectionRanchInfo: "家庭牧场信息",
720
+    sectionStock: "年底牲畜存栏情况",
721
+    sectionOutbound: "年底牲畜出栏情况",
722
+    sectionGrassland: "草畜平衡情况",
723
+    sectionFinance: "年度经营总收入",
724
+    sectionSubsidy: "家庭牧场补助资金享受情况",
725
+    sectionOther: "家庭牧场运营情况",
701 726
     btnImport: "导入",
702 727
     btnDownloadTemplate: "下载模板",
703 728
     exportTitle: "Excel 导出",
@@ -726,6 +751,7 @@ export default {
726 751
     emptyList: "暂无填报数据",
727 752
     unitPerson: "人",
728 753
     unitHead: "头",
754
+    unitHeadSheepHorse: "头只匹",
729 755
     unitMu: "亩",
730 756
     unitWanYuan: "万元",
731 757
     unitSheepUnit: "绵羊单位",
@@ -739,5 +765,256 @@ export default {
739 765
     ruleCountNonNegative: "须为大于等于 0 的整数",
740 766
     ruleDecimalNonNegative: "须为大于等于 0 的数字",
741 767
     villageTreeEmpty: "未加载到村级组织数据,请确认系统部门已维护「乡镇→村」"
768
+  },
769
+  largeLivestockFarmer: {
770
+    queryStatYear: "所属年份",
771
+    queryStatMonth: "所属月份",
772
+    queryTown: "所属乡镇",
773
+    queryEnterpriseName: "企业名称",
774
+    phVillageSearch: "请选择或输入搜索",
775
+    phEnterpriseName: "请输入企业名称",
776
+    phRemark: "选填,不超过 500 字",
777
+    colStatYear: "所属年份",
778
+    colStatMonth: "所属月份",
779
+    statMonthLabel: "{month}月",
780
+    colTownName: "所属乡镇",
781
+    colVillageName: "所属村",
782
+    colEnterpriseName: "企业名称",
783
+    colLegalRepresentative: "法定代表人",
784
+    colEnterpriseType: "企业类型",
785
+    colRegisteredCapital: "注册资本",
786
+    colEstablishDate: "成立时间",
787
+    colCattleYearEndStock: "年底牛存栏数",
788
+    colCattleOutbound: "年底牛出栏数",
789
+    colGrasslandArea: "草场面积",
790
+    formStatYear: "所属年份",
791
+    formStatMonth: "所属月份",
792
+    formTown: "所属乡镇",
793
+    formVillage: "所属村",
794
+    formEnterpriseName: "企业名称",
795
+    formLegalRepresentative: "法定代表人",
796
+    formEnterpriseType: "企业类型",
797
+    formRegisteredCapital: "注册资本",
798
+    formEstablishDate: "成立时间",
799
+    formLivestockLaborCount: "从事畜牧业生产经营劳力人员",
800
+    formCattleYearEndStock: "年底牛存栏数",
801
+    formCattleBreedingFemaleStock: "年底能繁母牛存栏数",
802
+    formSheepYearEndStock: "年底羊存栏数",
803
+    formSheepBreedingFemaleStock: "年底能繁母羊存栏数",
804
+    formCattleOutbound: "年底牛出栏数",
805
+    formSheepOutbound: "年底羊出栏数",
806
+    formStockSubtotal: "年底牲畜总存栏数",
807
+    formOutboundSubtotal: "年底牲畜总出栏数",
808
+    formGrassBalanceArea: "草畜平衡面积",
809
+    formTransferGrassArea: "流转经营草地面积",
810
+    formGrasslandAreaSubtotal: "草场面积小计",
811
+    formApprovedCarryingCapacity: "核定年末草畜平衡载畜量",
812
+    formYearEndStockSheepUnit: "年底牲畜存栏",
813
+    formIsGrassBalanced: "是否草畜平衡户",
814
+    formIncome: "年度经营总收入",
815
+    formExpense: "年度经营总支出",
816
+    formProfit: "利润",
817
+    formSubsidyYear: "受助年份",
818
+    formHasSubsidy: "是否享受补助",
819
+    formSubsidyAmount: "补贴资金",
820
+    formHasTrademark: "是否有注册商标",
821
+    formHasQualityCert: "是否通过农产品质量认证",
822
+    formSalesChannel: "产品销售渠道",
823
+    formDrivenPopulation: "带动人数",
824
+    formWagePaid: "发放工资",
825
+    formRemark: "备注",
826
+    sectionBasic: "基本信息",
827
+    sectionFarmerInfo: "养殖大户信息",
828
+    sectionStock: "年底牲畜存栏情况",
829
+    sectionOutbound: "年底牲畜出栏情况",
830
+    sectionGrassland: "草畜平衡情况",
831
+    sectionFinance: "年度经营总收入",
832
+    sectionSubsidy: "养殖大户补助资金享受情况",
833
+    sectionOther: "养殖大户运营情况",
834
+    btnImport: "导入",
835
+    btnDownloadTemplate: "下载模板",
836
+    exportTitle: "Excel 导出",
837
+    exportStatYear: "所属年份",
838
+    exportStatYearPh: "请选择所属年份",
839
+    exportStatMonth: "所属月份",
840
+    exportStatMonthPh: "请选择所属月份",
841
+    exportStatYearRequired: "请选择所属年份",
842
+    exportStatMonthRequired: "请选择所属月份",
843
+    exportStatYearInvalid: "导出年月不在可选范围内",
844
+    exportLoading: "正在导出,请稍候...",
845
+    exportFail: "导出失败",
846
+    importTitle: "Excel 导入",
847
+    importStatYear: "填报年份",
848
+    importStatYearPh: "请选择填报年份",
849
+    importStatMonth: "填报月份",
850
+    importStatMonthPh: "请选择填报月份",
851
+    importTip: "请先选择填报年月,再上传与模板格式一致的 .xlsx 文件;同年同月同村同企业名称已存在则更新",
852
+    importLoading: "正在导入,请稍候...",
853
+    importSummary: "导入完成:新增 {insert} 条,更新 {update} 条,失败 {fail} 条",
854
+    importWarnTitle: "导入警告",
855
+    importFailTitle: "导入失败明细",
856
+    dialogAdd: "[新增]养殖大户数据",
857
+    dialogEdit: "[编辑]养殖大户数据",
858
+    confirmDelete: "是否确认删除这条数据?",
859
+    emptyList: "暂无填报数据",
860
+    unitPerson: "人",
861
+    unitHead: "头",
862
+    unitHeadSheepHorse: "头只匹",
863
+    unitMu: "亩",
864
+    unitWanYuan: "万元",
865
+    unitSheepUnit: "绵羊单位",
866
+    ruleStatYearRequired: "请选择所属年份",
867
+    ruleStatMonthRequired: "请选择所属月份",
868
+    ruleStatMonthFuture: "不可填报未来月份",
869
+    ruleVillageRequired: "请选择所属村",
870
+    ruleEnterpriseNameRequired: "请输入企业名称",
871
+    ruleEnterpriseNameLen: "企业名称不能超过 200 字",
872
+    ruleLegalRepLen: "法定代表人不能超过 64 字",
873
+    ruleCountNonNegative: "须为大于等于 0 的整数",
874
+    ruleDecimalNonNegative: "须为大于等于 0 的数字",
875
+    villageTreeEmpty: "未加载到村级组织数据,请确认系统部门已维护「乡镇→村」"
876
+  },
877
+  farmerHousehold: {
878
+    queryStatYear: "所属年份",
879
+    queryStatMonth: "所属月份",
880
+    queryTown: "所属乡镇",
881
+    phVillageSearch: "请选择或输入搜索",
882
+    phRemark: "选填,不超过 500 字",
883
+    colStatYear: "所属年份",
884
+    colStatMonth: "所属月份",
885
+    statMonthLabel: "{month}月",
886
+    colTownName: "所属乡镇",
887
+    colVillageName: "所属村",
888
+    colHouseholdCount: "农牧户数",
889
+    colPopulationCount: "农牧人数",
890
+    colPastureContractArea: "草场承包总面积",
891
+    formStatYear: "所属年份",
892
+    formStatMonth: "所属月份",
893
+    formTown: "所属乡镇",
894
+    formVillage: "所属村",
895
+    formHouseholdCount: "农牧户数",
896
+    formPopulationCount: "农牧人数",
897
+    formPastureContractArea: "草场承包总面积",
898
+    formGrazingBanArea: "禁牧面积",
899
+    formGrassBalanceArea: "草畜平衡面积",
900
+    formApprovedCarryingCapacity: "核定年末草畜平衡载畜量",
901
+    formYearEndStockSheepUnit: "年底牲畜存栏",
902
+    formIsPureHerder: "是否是纯牧户",
903
+    formIsNoLivestock: "是否无畜户",
904
+    formIsExtinctHousehold: "是否绝户",
905
+    formIsOverloadHerder: "是否超载牧户",
906
+    formNeedCap: "是否需要封顶",
907
+    formNeedFloor: "是否需要保底",
908
+    formGrazingBanSubsidy: "禁牧补助",
909
+    formGrassBalanceReward: "草畜平衡奖励",
910
+    formSubsidyRewardSubtotal: "补助奖励总资金",
911
+    formAfterCapFloorSubsidy: "封顶保底后享受补助奖励总资金",
912
+    formVillageSupervisorSubsidy: "村级草原监督员补助",
913
+    formSubsidyTotal: "补助合计金额",
914
+    formRemark: "备注",
915
+    sectionBasic: "基本信息",
916
+    sectionPasture: "草畜平衡情况",
917
+    sectionCapFloor: "封顶保底情况",
918
+    sectionSubsidy: "本年受助情况",
919
+    btnImport: "导入",
920
+    btnDownloadTemplate: "下载模板",
921
+    exportTitle: "Excel 导出",
922
+    exportStatYear: "所属年份",
923
+    exportStatYearPh: "请选择所属年份",
924
+    exportStatMonth: "所属月份",
925
+    exportStatMonthPh: "请选择所属月份",
926
+    exportTown: "所属乡镇",
927
+    exportTownPh: "不选则导出该年月全部乡镇",
928
+    exportStatYearRequired: "请选择所属年份",
929
+    exportStatMonthRequired: "请选择所属月份",
930
+    exportLoading: "正在导出,请稍候...",
931
+    exportFail: "导出失败",
932
+    importTitle: "Excel 导入",
933
+    importStatYear: "填报年份",
934
+    importStatYearPh: "请选择填报年份",
935
+    importStatMonth: "填报月份",
936
+    importStatMonthPh: "请选择填报月份",
937
+    importTip: "请先选择填报年月,再上传与模板格式一致的 .xlsx 文件;同年同月同村已存在则更新",
938
+    importLoading: "正在导入,请稍候...",
939
+    importSummary: "导入完成:新增 {insert} 条,更新 {update} 条,失败 {fail} 条",
940
+    importWarnTitle: "导入警告",
941
+    importFailTitle: "导入失败明细",
942
+    dialogAdd: "[新增]农牧户数据",
943
+    dialogEdit: "[编辑]农牧户数据",
944
+    confirmDelete: "是否确认删除这条数据?",
945
+    emptyList: "暂无填报数据",
946
+    unitHousehold: "户",
947
+    unitPerson: "人",
948
+    unitMu: "亩",
949
+    unitYuan: "元",
950
+    unitSheepUnit: "绵羊单位",
951
+    ruleStatYearRequired: "请选择所属年份",
952
+    ruleStatMonthRequired: "请选择所属月份",
953
+    ruleStatMonthFuture: "不可填报未来月份",
954
+    ruleVillageRequired: "请选择所属村",
955
+    ruleCountNonNegative: "须为大于等于 0 的整数",
956
+    ruleDecimalNonNegative: "须为大于等于 0 的数字",
957
+    villageTreeEmpty: "未加载到村级组织数据,请确认系统部门已维护「乡镇→村」"
958
+  },
959
+  vaccinationData: {
960
+    queryStatYear: "所属年份",
961
+    queryStatMonth: "所属月份",
962
+    queryTown: "所属乡镇",
963
+    queryVillage: "所属村",
964
+    phVillageSearch: "请选择或输入搜索",
965
+    phRemark: "选填,不超过 500 字",
966
+    colStatYear: "所属年份",
967
+    colStatMonth: "所属月份",
968
+    statMonthLabel: "{month}月",
969
+    colTownName: "所属乡镇",
970
+    colVillageName: "所属村",
971
+    colShouldVaccinateCount: "应免数",
972
+    colActualVaccinateCount: "实免数",
973
+    colImmunityRate: "免疫率",
974
+    formStatYear: "所属年份",
975
+    formStatMonth: "所属月份",
976
+    formTown: "所属乡镇",
977
+    formVillage: "所属村",
978
+    formShouldVaccinateCount: "应免数",
979
+    formActualVaccinateCount: "实免数",
980
+    formImmunityRate: "免疫率",
981
+    formRemark: "备注",
982
+    sectionBasic: "基本信息",
983
+    sectionVaccination: "疫苗接种情况",
984
+    btnImport: "导入",
985
+    btnDownloadTemplate: "下载模板",
986
+    exportTitle: "Excel 导出",
987
+    exportStatYear: "所属年份",
988
+    exportStatYearPh: "请选择所属年份",
989
+    exportStatMonth: "所属月份",
990
+    exportStatMonthPh: "请选择所属月份",
991
+    exportTown: "所属乡镇",
992
+    exportTownPh: "不选则导出该年月全部乡镇",
993
+    exportStatYearRequired: "请选择所属年份",
994
+    exportStatMonthRequired: "请选择所属月份",
995
+    exportLoading: "正在导出,请稍候...",
996
+    exportFail: "导出失败",
997
+    importTitle: "Excel 导入",
998
+    importStatYear: "填报年份",
999
+    importStatYearPh: "请选择填报年份",
1000
+    importStatMonth: "填报月份",
1001
+    importStatMonthPh: "请选择填报月份",
1002
+    importTip: "请先选择填报年月,再上传与模板格式一致的 .xlsx 文件;同年同月同村已存在则更新",
1003
+    importLoading: "正在导入,请稍候...",
1004
+    importSummary: "导入完成:新增 {insert} 条,更新 {update} 条,失败 {fail} 条",
1005
+    importWarnTitle: "导入警告",
1006
+    importFailTitle: "导入失败明细",
1007
+    dialogAdd: "[新增]疫苗接种数据",
1008
+    dialogEdit: "[编辑]疫苗接种数据",
1009
+    confirmDelete: "是否确认删除这条数据?",
1010
+    emptyList: "暂无填报数据",
1011
+    unitHead: "头",
1012
+    ruleStatYearRequired: "请选择所属年份",
1013
+    ruleStatMonthRequired: "请选择所属月份",
1014
+    ruleStatMonthFuture: "不可填报未来月份",
1015
+    ruleVillageRequired: "请选择所属村",
1016
+    ruleCountNonNegative: "须为大于等于 0 的整数",
1017
+    ruleActualLeShould: "实免数不能大于应免数",
1018
+    villageTreeEmpty: "未加载到村级组织数据,请确认系统部门已维护「乡镇→村」"
742 1019
   }
743 1020
 }

+ 3 - 1
ruoyi-ui/src/mixins/dataModelLocaleMixin.js

@@ -1,7 +1,9 @@
1 1
 /**
2 2
  * 产业数据模型及体系:dmT(data.dmNs)、dmCommon(通用按钮/校验)
3 3
  *
4
- * 查看弹窗约定:数值类字段须用 formatWithUnit 展示单位(与表单后缀一致)。
4
+ * 查看弹窗约定:
5
+ * 1. 数值类字段须用 formatWithUnit 展示单位(与表单后缀一致)。
6
+ * 2. 查看表单根节点加 class="dm-view-form",值文本使用主题高亮色(见 assets/styles/data-model.scss)。
5 7
  */
6 8
 export default {
7 9
   methods: {

+ 79 - 43
ruoyi-ui/src/views/commonProsperity/project/index.vue

@@ -14,10 +14,16 @@
14 14
         </el-form-item>
15 15
         <el-form-item prop="projectType">
16 16
           <template slot="label">{{ cpT("queryProjectType") }}</template>
17
-          <el-select v-model="queryParams.projectType" :placeholder="cpCommon('pleaseSelect')" clearable style="width: 160px">
17
+          <el-select v-model="queryParams.projectType" :placeholder="cpCommon('pleaseSelect')" clearable style="width: 200px">
18 18
             <el-option v-for="item in projectTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
19 19
           </el-select>
20 20
         </el-form-item>
21
+        <el-form-item prop="implYear">
22
+          <template slot="label">{{ cpT("queryImplYear") }}</template>
23
+          <el-select v-model="queryParams.implYear" :placeholder="cpCommon('pleaseSelect')" clearable style="width: 140px">
24
+            <el-option v-for="y in yearOptions" :key="'q-' + y" :label="String(y)" :value="y" />
25
+          </el-select>
26
+        </el-form-item>
21 27
         <el-form-item prop="publishStatus">
22 28
           <template slot="label">{{ cpT("queryPublishStatus") }}</template>
23 29
           <el-select v-model="queryParams.publishStatus" :placeholder="cpCommon('pleaseSelect')" clearable style="width: 140px">
@@ -45,17 +51,13 @@
45 51
     <el-card shadow="never">
46 52
       <el-table v-loading="loading" :data="tableList" border>
47 53
         <el-table-column :label="cpT('colProjectName')" prop="projectName" align="center" min-width="120" :show-overflow-tooltip="true" />
48
-        <el-table-column :label="cpT('colProjectType')" align="center" width="110">
54
+        <el-table-column :label="cpT('colProjectType')" align="center" min-width="160">
49 55
           <template slot-scope="scope">
50 56
             <span>{{ typeLabel(scope.row.projectType) }}</span>
51 57
           </template>
52 58
         </el-table-column>
53 59
         <el-table-column :label="cpT('colIntro')" prop="introduction" align="center" min-width="120" :show-overflow-tooltip="true" />
54
-        <el-table-column :label="cpT('colImplDate')" align="center" width="200">
55
-          <template slot-scope="scope">
56
-            <span>{{ implDateRangeText(scope.row) }}</span>
57
-          </template>
58
-        </el-table-column>
60
+        <el-table-column :label="cpT('colImplYear')" prop="implYear" align="center" width="100" />
59 61
         <el-table-column :label="cpT('colOpImageCount')" align="center" width="88">
60 62
           <template slot-scope="scope">
61 63
             <span>{{ scope.row.opImageCount != null ? scope.row.opImageCount + cpT("opImageUnit") : $t("commonProsperity.status.dash") }}</span>
@@ -126,7 +128,7 @@
126 128
     </el-card>
127 129
 
128 130
     <el-dialog :title="dialogTitle" :visible.sync="open" width="720px" append-to-body @close="cancel">
129
-      <el-form :key="formKey" ref="form" :model="form" label-width="110px">
131
+      <el-form :key="formKey" ref="form" :model="form" label-width="130px">
130 132
         <el-form-item prop="projectName" :rules="formRules.projectName">
131 133
           <template slot="label">{{ cpT("formProjectName") }}</template>
132 134
           <el-input v-model="form.projectName" :placeholder="cpT('phProjectName')" maxlength="20" show-word-limit />
@@ -145,17 +147,26 @@
145 147
           <template slot="label">{{ cpT("formContent") }}</template>
146 148
           <el-input v-model="form.projectContent" type="textarea" :rows="4" :placeholder="cpT('phContent')" maxlength="500" show-word-limit />
147 149
         </el-form-item>
148
-        <el-form-item prop="implDateRange" :rules="formRules.implDateRange">
149
-          <template slot="label">{{ cpT("formImplDate") }}</template>
150
-          <el-date-picker
151
-            v-model="form.implDateRange"
152
-            type="daterange"
153
-            value-format="yyyy-MM-dd"
154
-            :range-separator="cpT('implRangeSeparator')"
155
-            :start-placeholder="cpT('implRangeStartPh')"
156
-            :end-placeholder="cpT('implRangeEndPh')"
157
-            style="width: 100%"
150
+        <el-form-item prop="investmentAmount" :rules="formRules.investmentAmount">
151
+          <template slot="label">{{ cpT("formInvestmentAmount") }}</template>
152
+          <el-input-number
153
+            v-model="form.investmentAmount"
154
+            :min="0"
155
+            :precision="2"
156
+            :controls="false"
157
+            style="width: 220px"
158 158
           />
159
+          <span class="form-unit">{{ cpCommon("unitWanYuan") }}</span>
160
+        </el-form-item>
161
+        <el-form-item prop="implYear" :rules="formRules.implYear">
162
+          <template slot="label">{{ cpT("formImplYear") }}</template>
163
+          <el-select v-model="form.implYear" :placeholder="cpCommon('pleaseSelect')" style="width: 220px">
164
+            <el-option v-for="y in yearOptions" :key="'f-' + y" :label="String(y)" :value="y" />
165
+          </el-select>
166
+        </el-form-item>
167
+        <el-form-item prop="implStatus" :rules="formRules.implStatus">
168
+          <template slot="label">{{ cpT("formImplStatus") }}</template>
169
+          <el-input v-model="form.implStatus" type="textarea" :rows="3" :placeholder="cpT('phImplStatus')" maxlength="500" show-word-limit />
159 170
         </el-form-item>
160 171
         <el-form-item prop="operationImages">
161 172
           <template slot="label">{{ cpT("formOpImages") }}</template>
@@ -229,7 +240,7 @@
229 240
     </el-dialog>
230 241
 
231 242
     <el-dialog :title="cpCommon('viewTitle')" :visible.sync="viewOpen" width="680px" append-to-body>
232
-      <el-form label-width="110px" size="small">
243
+      <el-form label-width="130px" size="small">
233 244
         <el-form-item :label="cpT('formProjectName')">
234 245
           <span>{{ viewRow.projectName }}</span>
235 246
         </el-form-item>
@@ -242,8 +253,14 @@
242 253
         <el-form-item :label="cpT('formContent')">
243 254
           <span class="view-content-text">{{ viewRow.projectContent || $t("commonProsperity.status.dash") }}</span>
244 255
         </el-form-item>
245
-        <el-form-item :label="cpT('formImplDate')">
246
-          <span>{{ implDateRangeText(viewRow) }}</span>
256
+        <el-form-item :label="cpT('formInvestmentAmount')">
257
+          <span>{{ investmentAmountText(viewRow.investmentAmount) }}</span>
258
+        </el-form-item>
259
+        <el-form-item :label="cpT('formImplYear')">
260
+          <span>{{ viewRow.implYear != null ? viewRow.implYear : $t("commonProsperity.status.dash") }}</span>
261
+        </el-form-item>
262
+        <el-form-item :label="cpT('formImplStatus')">
263
+          <span class="view-content-text">{{ viewRow.implStatus || $t("commonProsperity.status.dash") }}</span>
247 264
         </el-form-item>
248 265
         <el-form-item :label="cpT('viewOpImages')">
249 266
           <template v-if="viewOpImages.length">
@@ -319,9 +336,11 @@ export default {
319 336
         pageSize: 20,
320 337
         projectName: undefined,
321 338
         projectType: undefined,
339
+        implYear: undefined,
322 340
         publishStatus: undefined
323 341
       },
324 342
       form: {},
343
+      yearOptions: [],
325 344
       /** 运营图片 el-upload 展示列表 */
326 345
       opImageFileList: [],
327 346
       imageFileExts: ["jpg", "jpeg", "png"],
@@ -343,18 +362,14 @@ export default {
343 362
           { min: 1, max: 20, message: this.cpCommon("ruleLen120"), trigger: "blur" }
344 363
         ],
345 364
         projectType: [{ required: true, message: this.cpT("ruleProjectTypeRequired"), trigger: "change" }],
346
-        introduction: [
347
-          { required: true, message: this.cpT("ruleIntroRequired"), trigger: "blur" },
348
-          { min: 1, max: 50, message: this.cpCommon("ruleLen150"), trigger: "blur" }
349
-        ],
365
+        introduction: [{ max: 50, message: this.cpCommon("ruleLen50Optional"), trigger: "blur" }],
350 366
         projectContent: [
351 367
           { required: true, message: this.cpT("ruleContentRequired"), trigger: "blur" },
352 368
           { min: 1, max: 500, message: this.cpCommon("ruleLen1500"), trigger: "blur" }
353 369
         ],
354
-        implDateRange: [
355
-          { required: true, message: this.cpT("ruleImplDateRequired"), trigger: "change" },
356
-          { validator: this.validateImplDateRange, trigger: "change" }
357
-        ]
370
+        investmentAmount: [{ validator: this.validateInvestmentAmount, trigger: "blur" }],
371
+        implYear: [{ required: true, message: this.cpT("ruleImplYearRequired"), trigger: "change" }],
372
+        implStatus: [{ max: 500, message: this.cpCommon("ruleLen500Optional"), trigger: "blur" }]
358 373
       }
359 374
     },
360 375
     uploadAction() {
@@ -381,26 +396,35 @@ export default {
381 396
     }
382 397
   },
383 398
   created() {
399
+    this.buildYearOptions()
384 400
     this.getList()
385 401
   },
386 402
   methods: {
403
+    buildYearOptions() {
404
+      const current = new Date().getFullYear()
405
+      const years = []
406
+      for (let y = current; y >= current - 5; y--) {
407
+        years.push(y)
408
+      }
409
+      this.yearOptions = years
410
+    },
387 411
     typeLabel(val) {
388 412
       const item = this.projectTypeOptions.find((o) => o.value === val)
389 413
       return item ? item.label : ""
390 414
     },
391
-    implDateRangeText(row) {
392
-      if (row && row.implStartDate && row.implEndDate) {
393
-        return row.implStartDate + this.cpT("implRangeSeparator") + row.implEndDate
415
+    investmentAmountText(val) {
416
+      if (val === null || val === undefined || val === "") {
417
+        return this.$t("commonProsperity.status.dash")
394 418
       }
395
-      return this.$t("commonProsperity.status.dash")
419
+      return val + " " + this.cpCommon("unitWanYuan")
396 420
     },
397
-    validateImplDateRange(rule, value, callback) {
398
-      if (!value || value.length !== 2 || !value[0] || !value[1]) {
399
-        callback(new Error(this.cpT("ruleImplDateRequired")))
421
+    validateInvestmentAmount(rule, value, callback) {
422
+      if (value === null || value === undefined || value === "") {
423
+        callback()
400 424
         return
401 425
       }
402
-      if (value[0] > value[1]) {
403
-        callback(new Error(this.cpCommon("ruleImplEndBeforeStart")))
426
+      if (Number(value) < 0) {
427
+        callback(new Error(this.cpCommon("ruleNonNegativeNumber")))
404 428
         return
405 429
       }
406 430
       callback()
@@ -435,6 +459,7 @@ export default {
435 459
     resetQuery() {
436 460
       this.queryParams.projectName = undefined
437 461
       this.queryParams.projectType = undefined
462
+      this.queryParams.implYear = undefined
438 463
       this.queryParams.publishStatus = undefined
439 464
       this.resetForm("queryForm")
440 465
       this.handleQuery()
@@ -446,7 +471,9 @@ export default {
446 471
         projectType: undefined,
447 472
         introduction: undefined,
448 473
         projectContent: undefined,
449
-        implDateRange: null,
474
+        investmentAmount: undefined,
475
+        implYear: new Date().getFullYear(),
476
+        implStatus: undefined,
450 477
         videoFileUrl: undefined,
451 478
         videoFilePath: undefined,
452 479
         coverFileUrl: undefined,
@@ -495,7 +522,9 @@ export default {
495 522
           projectType: data.projectType,
496 523
           introduction: data.introduction,
497 524
           projectContent: data.projectContent,
498
-          implDateRange: data.implStartDate && data.implEndDate ? [data.implStartDate, data.implEndDate] : null,
525
+          investmentAmount: data.investmentAmount,
526
+          implYear: data.implYear,
527
+          implStatus: data.implStatus,
499 528
           videoFileUrl: data.videoFileUrl,
500 529
           videoFilePath: data.videoFilePath,
501 530
           coverFileUrl: data.coverFileUrl,
@@ -661,13 +690,16 @@ export default {
661 690
     },
662 691
     buildSubmitPayload() {
663 692
       this.syncOpImagesFromFileList()
693
+      const intro = this.form.introduction != null ? String(this.form.introduction).trim() : ""
694
+      const implStatus = this.form.implStatus != null ? String(this.form.implStatus).trim() : ""
664 695
       return {
665 696
         projectName: this.form.projectName,
666 697
         projectType: this.form.projectType,
667
-        introduction: this.form.introduction,
698
+        introduction: intro || undefined,
668 699
         projectContent: this.form.projectContent,
669
-        implStartDate: this.form.implDateRange[0],
670
-        implEndDate: this.form.implDateRange[1],
700
+        investmentAmount: this.form.investmentAmount,
701
+        implYear: this.form.implYear,
702
+        implStatus: implStatus || undefined,
671 703
         operationImages: this.form.operationImages || [],
672 704
         videoFileUrl: this.form.videoFileUrl,
673 705
         videoFilePath: this.form.videoFilePath,
@@ -742,4 +774,8 @@ export default {
742 774
   white-space: pre-wrap;
743 775
   word-break: break-word;
744 776
 }
777
+.form-unit {
778
+  margin-left: 8px;
779
+  color: #606266;
780
+}
745 781
 </style>

+ 163 - 51
ruoyi-ui/src/views/dataModel/cooperativeDevelopment/index.vue

@@ -168,6 +168,10 @@
168 168
               </el-select>
169 169
             </el-form-item>
170 170
           </el-col>
171
+        </el-row>
172
+
173
+        <div class="cd-section-title">{{ dmT("sectionCooperativeInfo") }}</div>
174
+        <el-row :gutter="16">
171 175
           <el-col :span="12">
172 176
             <el-form-item prop="cooperativeName" :rules="formRules.cooperativeName">
173 177
               <template slot="label">{{ dmT("formCooperativeName") }}</template>
@@ -233,8 +237,8 @@
233 237
             <el-form-item>
234 238
               <template slot="label">{{ dmT("formLivestockShareTotal") }}</template>
235 239
               <div class="dm-input-with-unit">
236
-                <el-input :value="livestockShareTotalDisplay" disabled class="dm-input-with-unit__input" />
237
-                <span class="dm-input-with-unit__suffix">{{ dmT("unitHead") }}</span>
240
+                <el-input-number :value="livestockShareTotalDisplay" :controls="false" disabled class="dm-input-with-unit__input" />
241
+                <span class="dm-input-with-unit__suffix">{{ dmT("unitHeadSheepHorse") }}</span>
238 242
               </div>
239 243
             </el-form-item>
240 244
           </el-col>
@@ -292,9 +296,9 @@
292 296
           </el-col>
293 297
         </el-row>
294 298
 
295
-        <div class="cd-section-title">{{ dmT("sectionEmploymentLivestock") }}</div>
299
+        <div class="cd-section-title">{{ dmT("sectionEmployment") }}</div>
296 300
         <el-row :gutter="16">
297
-          <el-col v-for="field in employmentLivestockFields" :key="field.prop" :span="12">
301
+          <el-col v-for="field in employmentFields" :key="field.prop" :span="12">
298 302
             <el-form-item :prop="field.prop" :rules="field.type === 'decimal' ? formRules.decimal : formRules.count">
299 303
               <template slot="label">{{ dmT(field.labelKey) }}</template>
300 304
               <div class="dm-input-with-unit">
@@ -312,9 +316,49 @@
312 316
           </el-col>
313 317
         </el-row>
314 318
 
315
-        <div class="cd-section-title">{{ dmT("sectionProductTraining") }}</div>
319
+        <div class="cd-section-title">{{ dmT("sectionLivestockInout") }}</div>
320
+        <el-row :gutter="16">
321
+          <el-col v-for="field in livestockInoutFields" :key="field.prop" :span="12">
322
+            <el-form-item :prop="field.prop" :rules="formRules.count">
323
+              <template slot="label">{{ dmT(field.labelKey) }}</template>
324
+              <div class="dm-input-with-unit">
325
+                <el-input-number
326
+                  v-model="form[field.prop]"
327
+                  :min="0"
328
+                  :precision="0"
329
+                  :controls="true"
330
+                  controls-position="right"
331
+                  class="dm-input-with-unit__input"
332
+                />
333
+                <span class="dm-input-with-unit__suffix">{{ dmT(field.unitKey) }}</span>
334
+              </div>
335
+            </el-form-item>
336
+          </el-col>
337
+        </el-row>
338
+
339
+        <div class="cd-section-title">{{ dmT("sectionProductCert") }}</div>
340
+        <el-row :gutter="16">
341
+          <el-col v-for="field in productCertFields" :key="field.prop" :span="12">
342
+            <el-form-item :prop="field.prop" :rules="formRules.count">
343
+              <template slot="label">{{ dmT(field.labelKey) }}</template>
344
+              <div class="dm-input-with-unit">
345
+                <el-input-number
346
+                  v-model="form[field.prop]"
347
+                  :min="0"
348
+                  :precision="0"
349
+                  :controls="true"
350
+                  controls-position="right"
351
+                  class="dm-input-with-unit__input"
352
+                />
353
+                <span class="dm-input-with-unit__suffix">{{ dmT(field.unitKey) }}</span>
354
+              </div>
355
+            </el-form-item>
356
+          </el-col>
357
+        </el-row>
358
+
359
+        <div class="cd-section-title">{{ dmT("sectionTraining") }}</div>
316 360
         <el-row :gutter="16">
317
-          <el-col v-for="field in productTrainingFields" :key="field.prop" :span="12">
361
+          <el-col v-for="field in trainingFields" :key="field.prop" :span="12">
318 362
             <el-form-item :prop="field.prop" :rules="formRules.count">
319 363
               <template slot="label">{{ dmT(field.labelKey) }}</template>
320 364
               <div class="dm-input-with-unit">
@@ -345,6 +389,8 @@
345 389
             <el-radio v-for="item in businessModelOptions" :key="item" :label="item">{{ item }}</el-radio>
346 390
           </el-radio-group>
347 391
         </el-form-item>
392
+
393
+        <div class="cd-section-title">{{ dmT("sectionOperationStatus") }}</div>
348 394
         <el-form-item>
349 395
           <template slot="label">{{ dmT("formOperationStatus") }}</template>
350 396
           <el-radio-group v-model="form.operationStatus">
@@ -363,7 +409,8 @@
363 409
     </el-dialog>
364 410
 
365 411
     <el-dialog :title="dmCommon('viewTitle')" :visible.sync="viewOpen" width="980px" append-to-body>
366
-      <el-form label-width="150px" size="small">
412
+      <el-form class="dm-view-form" label-width="150px" size="small">
413
+        <div class="cd-section-title">{{ dmT("sectionBasic") }}</div>
367 414
         <el-row :gutter="16">
368 415
           <el-col :span="12">
369 416
             <el-form-item :label="dmT('formStatYear')">
@@ -385,6 +432,10 @@
385 432
               <span>{{ viewRow.villageName || dash }}</span>
386 433
             </el-form-item>
387 434
           </el-col>
435
+        </el-row>
436
+
437
+        <div class="cd-section-title">{{ dmT("sectionCooperativeInfo") }}</div>
438
+        <el-row :gutter="16">
388 439
           <el-col :span="12">
389 440
             <el-form-item :label="dmT('formCooperativeName')">
390 441
               <span>{{ viewRow.cooperativeName || dash }}</span>
@@ -400,11 +451,84 @@
400 451
               <span>{{ viewRow.establishDate || dash }}</span>
401 452
             </el-form-item>
402 453
           </el-col>
403
-          <el-col v-for="field in allViewFields" :key="'v-' + field.prop" :span="12">
454
+          <el-col v-for="field in basicDecimalFields" :key="'vc-' + field.prop" :span="12">
455
+            <el-form-item :label="dmT(field.labelKey)">
456
+              <span>{{ formatWithUnit(formatDecimal(viewRow[field.prop]), field.unitKey) }}</span>
457
+            </el-form-item>
458
+          </el-col>
459
+        </el-row>
460
+
461
+        <div class="cd-section-title">{{ dmT("sectionMemberShare") }}</div>
462
+        <el-row :gutter="16">
463
+          <el-col v-for="field in memberCountFields" :key="'vm-' + field.prop" :span="12">
464
+            <el-form-item :label="dmT(field.labelKey)">
465
+              <span>{{ formatWithUnit(formatCount(viewRow[field.prop]), field.unitKey) }}</span>
466
+            </el-form-item>
467
+          </el-col>
468
+          <el-col :span="12">
469
+            <el-form-item :label="dmT('formLivestockShareTotal')">
470
+              <span>{{ formatWithUnit(formatCount(livestockShareTotalOf(viewRow)), "unitHeadSheepHorse") }}</span>
471
+            </el-form-item>
472
+          </el-col>
473
+          <el-col v-for="field in shareDecimalFields" :key="'vsd-' + field.prop" :span="12">
474
+            <el-form-item :label="dmT(field.labelKey)">
475
+              <span>{{ formatWithUnit(formatDecimal(viewRow[field.prop]), field.unitKey) }}</span>
476
+            </el-form-item>
477
+          </el-col>
478
+          <el-col :span="12">
479
+            <el-form-item :label="dmT('formLaborShareCount')">
480
+              <span>{{ formatWithUnit(formatCount(viewRow.laborShareCount), "unitPerson") }}</span>
481
+            </el-form-item>
482
+          </el-col>
483
+        </el-row>
484
+
485
+        <div class="cd-section-title">{{ dmT("sectionBenefit") }}</div>
486
+        <el-row :gutter="16">
487
+          <el-col v-for="field in benefitDecimalFields" :key="'vb-' + field.prop" :span="12">
488
+            <el-form-item :label="dmT(field.labelKey)">
489
+              <span>{{ formatWithUnit(formatDecimal(viewRow[field.prop]), field.unitKey) }}</span>
490
+            </el-form-item>
491
+          </el-col>
492
+        </el-row>
493
+
494
+        <div class="cd-section-title">{{ dmT("sectionEmployment") }}</div>
495
+        <el-row :gutter="16">
496
+          <el-col v-for="field in employmentFields" :key="'ve-' + field.prop" :span="12">
404 497
             <el-form-item :label="dmT(field.labelKey)">
405 498
               <span>{{ formatWithUnit(field.type === 'decimal' ? formatDecimal(viewRow[field.prop]) : formatCount(viewRow[field.prop]), field.unitKey) }}</span>
406 499
             </el-form-item>
407 500
           </el-col>
501
+        </el-row>
502
+
503
+        <div class="cd-section-title">{{ dmT("sectionLivestockInout") }}</div>
504
+        <el-row :gutter="16">
505
+          <el-col v-for="field in livestockInoutFields" :key="'vl-' + field.prop" :span="12">
506
+            <el-form-item :label="dmT(field.labelKey)">
507
+              <span>{{ formatWithUnit(formatCount(viewRow[field.prop]), field.unitKey) }}</span>
508
+            </el-form-item>
509
+          </el-col>
510
+        </el-row>
511
+
512
+        <div class="cd-section-title">{{ dmT("sectionProductCert") }}</div>
513
+        <el-row :gutter="16">
514
+          <el-col v-for="field in productCertFields" :key="'vp-' + field.prop" :span="12">
515
+            <el-form-item :label="dmT(field.labelKey)">
516
+              <span>{{ formatWithUnit(formatCount(viewRow[field.prop]), field.unitKey) }}</span>
517
+            </el-form-item>
518
+          </el-col>
519
+        </el-row>
520
+
521
+        <div class="cd-section-title">{{ dmT("sectionTraining") }}</div>
522
+        <el-row :gutter="16">
523
+          <el-col v-for="field in trainingFields" :key="'vt-' + field.prop" :span="12">
524
+            <el-form-item :label="dmT(field.labelKey)">
525
+              <span>{{ formatWithUnit(formatCount(viewRow[field.prop]), field.unitKey) }}</span>
526
+            </el-form-item>
527
+          </el-col>
528
+        </el-row>
529
+
530
+        <div class="cd-section-title">{{ dmT("sectionOperation") }}</div>
531
+        <el-row :gutter="16">
408 532
           <el-col :span="24">
409 533
             <el-form-item :label="dmT('formBusinessScope')">
410 534
               <span class="cd-view-text">{{ viewRow.businessScope || dash }}</span>
@@ -415,6 +539,10 @@
415 539
               <span>{{ viewRow.businessModel || dash }}</span>
416 540
             </el-form-item>
417 541
           </el-col>
542
+        </el-row>
543
+
544
+        <div class="cd-section-title">{{ dmT("sectionOperationStatus") }}</div>
545
+        <el-row :gutter="16">
418 546
           <el-col :span="12">
419 547
             <el-form-item :label="dmT('formOperationStatus')">
420 548
               <span>{{ viewRow.operationStatus || dash }}</span>
@@ -564,67 +692,41 @@ const BENEFIT_DECIMAL_FIELDS = [
564 692
   { prop: "lossAmount", labelKey: "formLossAmount", unitKey: "unitWanYuan" }
565 693
 ]
566 694
 
567
-const EMPLOYMENT_LIVESTOCK_FIELDS = [
695
+const EMPLOYMENT_FIELDS = [
568 696
   { prop: "collegeGraduateCount", labelKey: "formCollegeGraduateCount", unitKey: "unitPerson", type: "count" },
569 697
   { prop: "collegeGraduateWage", labelKey: "formCollegeGraduateWage", unitKey: "unitWanYuan", type: "decimal" },
570 698
   { prop: "farmerTransferEmploymentCount", labelKey: "formFarmerTransferEmploymentCount", unitKey: "unitPerson", type: "count" },
571
-  { prop: "farmerTransferWage", labelKey: "formFarmerTransferWage", unitKey: "unitWanYuan", type: "decimal" },
699
+  { prop: "farmerTransferWage", labelKey: "formFarmerTransferWage", unitKey: "unitWanYuan", type: "decimal" }
700
+]
701
+
702
+const LIVESTOCK_INOUT_FIELDS = [
572 703
   { prop: "cattleInventoryCount", labelKey: "formCattleInventoryCount", unitKey: "unitHead", type: "count" },
573 704
   { prop: "cattleOutboundCount", labelKey: "formCattleOutboundCount", unitKey: "unitHead", type: "count" },
574 705
   { prop: "sheepInventoryCount", labelKey: "formSheepInventoryCount", unitKey: "unitHead", type: "count" },
575 706
   { prop: "sheepOutboundCount", labelKey: "formSheepOutboundCount", unitKey: "unitHead", type: "count" }
576 707
 ]
577 708
 
578
-const PRODUCT_TRAINING_FIELDS = [
709
+const PRODUCT_CERT_FIELDS = [
579 710
   { prop: "trademarkProductCount", labelKey: "formTrademarkProductCount", unitKey: "unitGe" },
580
-  { prop: "qualityCertProductCount", labelKey: "formQualityCertProductCount", unitKey: "unitGe" },
711
+  { prop: "qualityCertProductCount", labelKey: "formQualityCertProductCount", unitKey: "unitGe" }
712
+]
713
+
714
+const TRAINING_FIELDS = [
581 715
   { prop: "trainingManageCount", labelKey: "formTrainingManageCount", unitKey: "unitPerson" },
582 716
   { prop: "trainingSkillCount", labelKey: "formTrainingSkillCount", unitKey: "unitPerson" },
583 717
   { prop: "trainingOtherCount", labelKey: "formTrainingOtherCount", unitKey: "unitPerson" }
584 718
 ]
585 719
 
586
-const VIEW_EXTRA_FIELDS = [
587
-  { prop: "registeredCapital", labelKey: "formRegisteredCapital", type: "decimal", unitKey: "unitWanYuan" },
588
-  { prop: "yearEndTotalAssets", labelKey: "formYearEndTotalAssets", type: "decimal", unitKey: "unitWanYuan" },
589
-  { prop: "memberHouseholdCount", labelKey: "formMemberHouseholdCount", type: "count", unitKey: "unitHousehold" },
590
-  { prop: "memberPopulationCount", labelKey: "formMemberPopulationCount", type: "count", unitKey: "unitPerson" },
591
-  { prop: "povertyMonitorCount", labelKey: "formPovertyMonitorCount", type: "count", unitKey: "unitPerson" },
592
-  { prop: "cattleShareCount", labelKey: "formCattleShareCount", type: "count", unitKey: "unitHead" },
593
-  { prop: "sheepShareCount", labelKey: "formSheepShareCount", type: "count", unitKey: "unitHead" },
594
-  { prop: "livestockShareTotal", labelKey: "formLivestockShareTotal", type: "count", unitKey: "unitHead" },
595
-  { prop: "grasslandShareArea", labelKey: "formGrasslandShareArea", type: "decimal", unitKey: "unitWanMu" },
596
-  { prop: "laborShareCount", labelKey: "formLaborShareCount", type: "count", unitKey: "unitPerson" },
597
-  { prop: "cashShareAmount", labelKey: "formCashShareAmount", type: "decimal", unitKey: "unitWanYuan" },
598
-  { prop: "otherShareAmount", labelKey: "formOtherShareAmount", type: "decimal", unitKey: "unitWanYuan" },
599
-  { prop: "totalIncome", labelKey: "formTotalIncome", type: "decimal", unitKey: "unitWanYuan" },
600
-  { prop: "netIncome", labelKey: "formNetIncome", type: "decimal", unitKey: "unitWanYuan" },
601
-  { prop: "cashDividend", labelKey: "formCashDividend", type: "decimal", unitKey: "unitWanYuan" },
602
-  { prop: "inKindDividend", labelKey: "formInKindDividend", type: "decimal", unitKey: "unitWanYuan" },
603
-  { prop: "revolvingFund", labelKey: "formRevolvingFund", type: "decimal", unitKey: "unitWanYuan" },
604
-  { prop: "lossAmount", labelKey: "formLossAmount", type: "decimal", unitKey: "unitWanYuan" },
605
-  { prop: "collegeGraduateCount", labelKey: "formCollegeGraduateCount", type: "count", unitKey: "unitPerson" },
606
-  { prop: "collegeGraduateWage", labelKey: "formCollegeGraduateWage", type: "decimal", unitKey: "unitWanYuan" },
607
-  { prop: "farmerTransferEmploymentCount", labelKey: "formFarmerTransferEmploymentCount", type: "count", unitKey: "unitPerson" },
608
-  { prop: "farmerTransferWage", labelKey: "formFarmerTransferWage", type: "decimal", unitKey: "unitWanYuan" },
609
-  { prop: "cattleInventoryCount", labelKey: "formCattleInventoryCount", type: "count", unitKey: "unitHead" },
610
-  { prop: "cattleOutboundCount", labelKey: "formCattleOutboundCount", type: "count", unitKey: "unitHead" },
611
-  { prop: "sheepInventoryCount", labelKey: "formSheepInventoryCount", type: "count", unitKey: "unitHead" },
612
-  { prop: "sheepOutboundCount", labelKey: "formSheepOutboundCount", type: "count", unitKey: "unitHead" },
613
-  { prop: "trademarkProductCount", labelKey: "formTrademarkProductCount", type: "count", unitKey: "unitGe" },
614
-  { prop: "qualityCertProductCount", labelKey: "formQualityCertProductCount", type: "count", unitKey: "unitGe" },
615
-  { prop: "trainingManageCount", labelKey: "formTrainingManageCount", type: "count", unitKey: "unitPerson" },
616
-  { prop: "trainingSkillCount", labelKey: "formTrainingSkillCount", type: "count", unitKey: "unitPerson" },
617
-  { prop: "trainingOtherCount", labelKey: "formTrainingOtherCount", type: "count", unitKey: "unitPerson" }
618
-]
619
-
620 720
 const NUMERIC_PROPS = [
621 721
   ...BASIC_DECIMAL_FIELDS.map((f) => f.prop),
622 722
   ...MEMBER_COUNT_FIELDS.map((f) => f.prop),
623 723
   ...SHARE_DECIMAL_FIELDS.map((f) => f.prop),
624 724
   "laborShareCount",
625 725
   ...BENEFIT_DECIMAL_FIELDS.map((f) => f.prop),
626
-  ...EMPLOYMENT_LIVESTOCK_FIELDS.map((f) => f.prop),
627
-  ...PRODUCT_TRAINING_FIELDS.map((f) => f.prop)
726
+  ...EMPLOYMENT_FIELDS.map((f) => f.prop),
727
+  ...LIVESTOCK_INOUT_FIELDS.map((f) => f.prop),
728
+  ...PRODUCT_CERT_FIELDS.map((f) => f.prop),
729
+  ...TRAINING_FIELDS.map((f) => f.prop)
628 730
 ]
629 731
 
630 732
 function getCurrentYearMonth() {
@@ -736,9 +838,10 @@ export default {
736 838
       memberCountFields: MEMBER_COUNT_FIELDS,
737 839
       shareDecimalFields: SHARE_DECIMAL_FIELDS,
738 840
       benefitDecimalFields: BENEFIT_DECIMAL_FIELDS,
739
-      employmentLivestockFields: EMPLOYMENT_LIVESTOCK_FIELDS,
740
-      productTrainingFields: PRODUCT_TRAINING_FIELDS,
741
-      allViewFields: VIEW_EXTRA_FIELDS,
841
+      employmentFields: EMPLOYMENT_FIELDS,
842
+      livestockInoutFields: LIVESTOCK_INOUT_FIELDS,
843
+      productCertFields: PRODUCT_CERT_FIELDS,
844
+      trainingFields: TRAINING_FIELDS,
742 845
       viewRow: {},
743 846
       importForm: {
744 847
         statYear: undefined,
@@ -847,6 +950,15 @@ export default {
847 950
       }
848 951
       return this.dmT("statMonthLabel", { month })
849 952
     },
953
+    livestockShareTotalOf(row) {
954
+      if (!row) {
955
+        return 0
956
+      }
957
+      if (row.livestockShareTotal != null && row.livestockShareTotal !== "") {
958
+        return row.livestockShareTotal
959
+      }
960
+      return safeInt(row.cattleShareCount) + safeInt(row.sheepShareCount)
961
+    },
850 962
     formatCount(val) {
851 963
       if (val == null || val === "") {
852 964
         return this.dash

+ 24 - 10
ruoyi-ui/src/views/dataModel/disposableIncome/index.vue

@@ -61,7 +61,8 @@
61 61
     </el-card>
62 62
 
63 63
     <el-dialog :title="dialogTitle" :visible.sync="open" width="640px" append-to-body @close="cancel">
64
-      <el-form :key="formKey" ref="form" :model="form" label-width="180px" size="small">
64
+      <el-form :key="formKey" ref="form" :model="form" label-width="140px" size="small">
65
+        <div class="di-section-title">{{ dmT("sectionRuralResident") }}</div>
65 66
         <el-form-item prop="statYear" :rules="formRules.statYear">
66 67
           <template slot="label">{{ dmT("formStatYear") }}</template>
67 68
           <el-select v-model="form.statYear" :placeholder="dmCommon('pleaseSelect')" style="width: 100%" @change="onStatYearOrIncomeChange">
@@ -97,13 +98,18 @@
97 98
         </el-form-item>
98 99
         <el-form-item prop="incomeGrowthRate" :rules="formRules.optionalNumber">
99 100
           <template slot="label">{{ dmT("formIncomeGrowthRate") }}</template>
100
-          <el-input
101
-            v-model="form.incomeGrowthRate"
102
-            :placeholder="dmT('phIncomeGrowthRate')"
103
-            clearable
104
-            style="width: 100%"
105
-          />
101
+          <div class="dm-input-with-unit">
102
+            <el-input
103
+              v-model="form.incomeGrowthRate"
104
+              :placeholder="dmT('phIncomeGrowthRate')"
105
+              clearable
106
+              class="dm-input-with-unit__input"
107
+            />
108
+            <span class="dm-input-with-unit__suffix">{{ dmT("unitPercent") }}</span>
109
+          </div>
106 110
         </el-form-item>
111
+
112
+        <div class="di-section-title">{{ dmT("sectionPovertyPopulation") }}</div>
107 113
         <el-form-item prop="povertyNetIncome" :rules="formRules.povertyNetIncome">
108 114
           <template slot="label">{{ dmT("formPovertyNetIncome") }}</template>
109 115
           <div class="dm-input-with-unit">
@@ -130,7 +136,8 @@
130 136
     </el-dialog>
131 137
 
132 138
     <el-dialog :title="dmCommon('viewTitle')" :visible.sync="viewOpen" width="640px" append-to-body>
133
-      <el-form label-width="180px" size="small">
139
+      <el-form class="dm-view-form" label-width="140px" size="small">
140
+        <div class="di-section-title">{{ dmT("sectionRuralResident") }}</div>
134 141
         <el-form-item :label="dmT('formStatYear')">
135 142
           <span>{{ viewRow.statYear || dash }}</span>
136 143
         </el-form-item>
@@ -143,6 +150,8 @@
143 150
         <el-form-item :label="dmT('formIncomeGrowthRate')">
144 151
           <span>{{ formatGrowthRate(viewRow.incomeGrowthRate) }}</span>
145 152
         </el-form-item>
153
+
154
+        <div class="di-section-title">{{ dmT("sectionPovertyPopulation") }}</div>
146 155
         <el-form-item :label="dmT('formPovertyNetIncome')">
147 156
           <span>{{ formatWithUnit(formatMoney(viewRow.povertyNetIncome), "unitYuan") }}</span>
148 157
         </el-form-item>
@@ -297,7 +306,7 @@ export default {
297 306
       }
298 307
       return n.toFixed(2)
299 308
     },
300
-    /** 列表/详情:库中 null 显示为 0.00%;小数转百分比 */
309
+    /** 列表/详情:库中 null 显示为 0.00%;按库值直接展示百分比(不再 ×100) */
301 310
     formatGrowthRate(val) {
302 311
       if (val == null || val === "") {
303 312
         return "0.00%"
@@ -306,7 +315,7 @@ export default {
306 315
       if (!Number.isFinite(n)) {
307 316
         return "0.00%"
308 317
       }
309
-      return (n * 100).toFixed(2) + "%"
318
+      return n.toFixed(2) + "%"
310 319
     },
311 320
     validateNonNegativeMoney(rule, value, callback) {
312 321
       if (value == null || value === "") {
@@ -482,6 +491,11 @@ export default {
482 491
 </script>
483 492
 
484 493
 <style scoped>
494
+.di-section-title {
495
+  margin: 4px 0 12px;
496
+  font-weight: 600;
497
+  color: #303133;
498
+}
485 499
 .di-view-text {
486 500
   white-space: pre-wrap;
487 501
   word-break: break-all;

+ 222 - 54
ruoyi-ui/src/views/dataModel/familyRanch/index.vue

@@ -108,7 +108,7 @@
108 108
     </el-card>
109 109
 
110 110
     <el-dialog :title="dialogTitle" :visible.sync="open" width="980px" append-to-body @close="cancel">
111
-      <el-form :key="formKey" ref="form" :model="form" label-width="168px" size="small">
111
+      <el-form :key="formKey" ref="form" :model="form" class="fr-form" label-width="220px" size="small">
112 112
         <div class="fr-section-title">{{ dmT("sectionBasic") }}</div>
113 113
         <el-row :gutter="16">
114 114
           <el-col :span="12">
@@ -146,6 +146,10 @@
146 146
               </el-select>
147 147
             </el-form-item>
148 148
           </el-col>
149
+        </el-row>
150
+
151
+        <div class="fr-section-title">{{ dmT("sectionRanchInfo") }}</div>
152
+        <el-row :gutter="16">
149 153
           <el-col :span="12">
150 154
             <el-form-item prop="enterpriseName" :rules="formRules.enterpriseName">
151 155
               <template slot="label">{{ dmT("formEnterpriseName") }}</template>
@@ -213,7 +217,7 @@
213 217
 
214 218
         <div class="fr-section-title">{{ dmT("sectionStock") }}</div>
215 219
         <el-row :gutter="16">
216
-          <el-col v-for="field in stockCountFields" :key="field.prop" :span="12">
220
+          <el-col v-for="field in stockInventoryFields" :key="field.prop" :span="12">
217 221
             <el-form-item :prop="field.prop" :rules="formRules.count">
218 222
               <template slot="label">{{ dmT(field.labelKey) }}</template>
219 223
               <div class="dm-input-with-unit">
@@ -232,8 +236,36 @@
232 236
             <el-form-item>
233 237
               <template slot="label">{{ dmT("formStockSubtotal") }}</template>
234 238
               <div class="dm-input-with-unit">
235
-                <el-input :value="stockSubtotalDisplay" disabled class="dm-input-with-unit__input" />
236
-                <span class="dm-input-with-unit__suffix">{{ dmT("unitHead") }}</span>
239
+                <el-input-number :value="stockSubtotalDisplay" :controls="false" disabled class="dm-input-with-unit__input" />
240
+                <span class="dm-input-with-unit__suffix">{{ dmT("unitHeadSheepHorse") }}</span>
241
+              </div>
242
+            </el-form-item>
243
+          </el-col>
244
+        </el-row>
245
+
246
+        <div class="fr-section-title">{{ dmT("sectionOutbound") }}</div>
247
+        <el-row :gutter="16">
248
+          <el-col v-for="field in stockOutboundFields" :key="field.prop" :span="12">
249
+            <el-form-item :prop="field.prop" :rules="formRules.count">
250
+              <template slot="label">{{ dmT(field.labelKey) }}</template>
251
+              <div class="dm-input-with-unit">
252
+                <el-input-number
253
+                  v-model="form[field.prop]"
254
+                  :min="0"
255
+                  :precision="0"
256
+                  controls-position="right"
257
+                  class="dm-input-with-unit__input"
258
+                />
259
+                <span class="dm-input-with-unit__suffix">{{ dmT(field.unitKey) }}</span>
260
+              </div>
261
+            </el-form-item>
262
+          </el-col>
263
+          <el-col :span="12">
264
+            <el-form-item>
265
+              <template slot="label">{{ dmT("formOutboundSubtotal") }}</template>
266
+              <div class="dm-input-with-unit">
267
+                <el-input-number :value="outboundSubtotalDisplay" :controls="false" disabled class="dm-input-with-unit__input" />
268
+                <span class="dm-input-with-unit__suffix">{{ dmT("unitHeadSheepHorse") }}</span>
237 269
               </div>
238 270
             </el-form-item>
239 271
           </el-col>
@@ -302,6 +334,18 @@
302 334
               </div>
303 335
             </el-form-item>
304 336
           </el-col>
337
+        </el-row>
338
+
339
+        <div class="fr-section-title">{{ dmT("sectionSubsidy") }}</div>
340
+        <el-row :gutter="16">
341
+          <el-col :span="12">
342
+            <el-form-item prop="hasSubsidy">
343
+              <template slot="label">{{ dmT("formHasSubsidy") }}</template>
344
+              <el-radio-group v-model="form.hasSubsidy">
345
+                <el-radio v-for="item in yesNoOptions" :key="'hs-' + item" :label="item">{{ item }}</el-radio>
346
+              </el-radio-group>
347
+            </el-form-item>
348
+          </el-col>
305 349
           <el-col :span="12">
306 350
             <el-form-item prop="subsidyYear">
307 351
               <template slot="label">{{ dmT("formSubsidyYear") }}</template>
@@ -315,14 +359,6 @@
315 359
               />
316 360
             </el-form-item>
317 361
           </el-col>
318
-          <el-col :span="12">
319
-            <el-form-item prop="hasSubsidy">
320
-              <template slot="label">{{ dmT("formHasSubsidy") }}</template>
321
-              <el-radio-group v-model="form.hasSubsidy">
322
-                <el-radio v-for="item in yesNoOptions" :key="'hs-' + item" :label="item">{{ item }}</el-radio>
323
-              </el-radio-group>
324
-            </el-form-item>
325
-          </el-col>
326 362
           <el-col :span="12">
327 363
             <el-form-item prop="subsidyAmount" :rules="formRules.decimal">
328 364
               <template slot="label">{{ dmT("formSubsidyAmount") }}</template>
@@ -393,8 +429,9 @@
393 429
     </el-dialog>
394 430
 
395 431
     <el-dialog :title="dmCommon('viewTitle')" :visible.sync="viewOpen" width="980px" append-to-body>
396
-      <el-form label-width="168px" size="small">
397
-        <el-row :gutter="16">
432
+      <el-form class="dm-view-form fr-form" label-width="220px" size="small">
433
+        <div class="fr-section-title">{{ dmT("sectionBasic") }}</div>
434
+        <el-row :gutter="8">
398 435
           <el-col :span="12">
399 436
             <el-form-item :label="dmT('formStatYear')"><span>{{ viewRow.statYear || dash }}</span></el-form-item>
400 437
           </el-col>
@@ -407,9 +444,132 @@
407 444
           <el-col :span="12">
408 445
             <el-form-item :label="dmT('formVillage')"><span>{{ viewRow.villageName || dash }}</span></el-form-item>
409 446
           </el-col>
410
-          <el-col v-for="field in viewFields" :key="'v-' + field.prop" :span="12">
447
+        </el-row>
448
+
449
+        <div class="fr-section-title">{{ dmT("sectionRanchInfo") }}</div>
450
+        <el-row :gutter="8">
451
+          <el-col :span="12">
452
+            <el-form-item :label="dmT('formEnterpriseName')"><span>{{ viewRow.enterpriseName || dash }}</span></el-form-item>
453
+          </el-col>
454
+          <el-col :span="12">
455
+            <el-form-item :label="dmT('formLegalRepresentative')"><span>{{ viewRow.legalRepresentative || dash }}</span></el-form-item>
456
+          </el-col>
457
+          <el-col :span="12">
458
+            <el-form-item :label="dmT('formEnterpriseType')"><span>{{ viewRow.enterpriseType || dash }}</span></el-form-item>
459
+          </el-col>
460
+          <el-col :span="12">
461
+            <el-form-item :label="dmT('formRegisteredCapital')">
462
+              <span>{{ formatWithUnit(formatDecimal(viewRow.registeredCapital), "unitWanYuan") }}</span>
463
+            </el-form-item>
464
+          </el-col>
465
+          <el-col :span="12">
466
+            <el-form-item :label="dmT('formEstablishDate')"><span>{{ viewRow.establishDate || dash }}</span></el-form-item>
467
+          </el-col>
468
+          <el-col :span="12">
469
+            <el-form-item :label="dmT('formLivestockLaborCount')">
470
+              <span>{{ formatWithUnit(formatCount(viewRow.livestockLaborCount), "unitPerson") }}</span>
471
+            </el-form-item>
472
+          </el-col>
473
+        </el-row>
474
+
475
+        <div class="fr-section-title">{{ dmT("sectionStock") }}</div>
476
+        <el-row :gutter="8">
477
+          <el-col v-for="field in stockInventoryFields" :key="'vs-' + field.prop" :span="12">
411 478
             <el-form-item :label="dmT(field.labelKey)">
412
-              <span>{{ formatViewField(viewRow, field) }}</span>
479
+              <span>{{ formatWithUnit(formatCount(viewRow[field.prop]), field.unitKey) }}</span>
480
+            </el-form-item>
481
+          </el-col>
482
+          <el-col :span="12">
483
+            <el-form-item :label="dmT('formStockSubtotal')">
484
+              <span>{{ formatWithUnit(formatCount(stockSubtotalOf(viewRow)), "unitHeadSheepHorse") }}</span>
485
+            </el-form-item>
486
+          </el-col>
487
+        </el-row>
488
+
489
+        <div class="fr-section-title">{{ dmT("sectionOutbound") }}</div>
490
+        <el-row :gutter="8">
491
+          <el-col v-for="field in stockOutboundFields" :key="'vo-' + field.prop" :span="12">
492
+            <el-form-item :label="dmT(field.labelKey)">
493
+              <span>{{ formatWithUnit(formatCount(viewRow[field.prop]), field.unitKey) }}</span>
494
+            </el-form-item>
495
+          </el-col>
496
+          <el-col :span="12">
497
+            <el-form-item :label="dmT('formOutboundSubtotal')">
498
+              <span>{{ formatWithUnit(formatCount(outboundSubtotalOf(viewRow)), "unitHeadSheepHorse") }}</span>
499
+            </el-form-item>
500
+          </el-col>
501
+        </el-row>
502
+
503
+        <div class="fr-section-title">{{ dmT("sectionGrassland") }}</div>
504
+        <el-row :gutter="8">
505
+          <el-col v-for="field in grasslandDecimalFields" :key="'vg-' + field.prop" :span="12">
506
+            <el-form-item :label="dmT(field.labelKey)">
507
+              <span>{{ formatWithUnit(formatDecimal(viewRow[field.prop]), field.unitKey) }}</span>
508
+            </el-form-item>
509
+          </el-col>
510
+          <el-col :span="12">
511
+            <el-form-item :label="dmT('formGrasslandAreaSubtotal')">
512
+              <span>{{ formatWithUnit(formatDecimal(grasslandAreaSubtotalOf(viewRow)), "unitMu") }}</span>
513
+            </el-form-item>
514
+          </el-col>
515
+          <el-col :span="12">
516
+            <el-form-item :label="dmT('formIsGrassBalanced')"><span>{{ viewRow.isGrassBalanced || dash }}</span></el-form-item>
517
+          </el-col>
518
+        </el-row>
519
+
520
+        <div class="fr-section-title">{{ dmT("sectionFinance") }}</div>
521
+        <el-row :gutter="8">
522
+          <el-col :span="12">
523
+            <el-form-item :label="dmT('formIncome')">
524
+              <span>{{ formatWithUnit(formatDecimal(viewRow.income), "unitWanYuan") }}</span>
525
+            </el-form-item>
526
+          </el-col>
527
+          <el-col :span="12">
528
+            <el-form-item :label="dmT('formExpense')">
529
+              <span>{{ formatWithUnit(formatDecimal(viewRow.expense), "unitWanYuan") }}</span>
530
+            </el-form-item>
531
+          </el-col>
532
+          <el-col :span="12">
533
+            <el-form-item :label="dmT('formProfit')">
534
+              <span>{{ formatWithUnit(formatDecimal(viewRow.profit), "unitWanYuan") }}</span>
535
+            </el-form-item>
536
+          </el-col>
537
+        </el-row>
538
+
539
+        <div class="fr-section-title">{{ dmT("sectionSubsidy") }}</div>
540
+        <el-row :gutter="8">
541
+          <el-col :span="12">
542
+            <el-form-item :label="dmT('formHasSubsidy')"><span>{{ viewRow.hasSubsidy || dash }}</span></el-form-item>
543
+          </el-col>
544
+          <el-col :span="12">
545
+            <el-form-item :label="dmT('formSubsidyYear')"><span>{{ viewRow.subsidyYear || dash }}</span></el-form-item>
546
+          </el-col>
547
+          <el-col :span="12">
548
+            <el-form-item :label="dmT('formSubsidyAmount')">
549
+              <span>{{ formatWithUnit(formatDecimal(viewRow.subsidyAmount), "unitWanYuan") }}</span>
550
+            </el-form-item>
551
+          </el-col>
552
+        </el-row>
553
+
554
+        <div class="fr-section-title">{{ dmT("sectionOther") }}</div>
555
+        <el-row :gutter="8">
556
+          <el-col :span="12">
557
+            <el-form-item :label="dmT('formHasTrademark')"><span>{{ viewRow.hasTrademark || dash }}</span></el-form-item>
558
+          </el-col>
559
+          <el-col :span="12">
560
+            <el-form-item :label="dmT('formHasQualityCert')"><span>{{ viewRow.hasQualityCert || dash }}</span></el-form-item>
561
+          </el-col>
562
+          <el-col :span="12">
563
+            <el-form-item :label="dmT('formSalesChannel')"><span>{{ viewRow.salesChannel || dash }}</span></el-form-item>
564
+          </el-col>
565
+          <el-col :span="12">
566
+            <el-form-item :label="dmT('formDrivenPopulation')">
567
+              <span>{{ formatWithUnit(formatCount(viewRow.drivenPopulation), "unitPerson") }}</span>
568
+            </el-form-item>
569
+          </el-col>
570
+          <el-col :span="12">
571
+            <el-form-item :label="dmT('formWagePaid')">
572
+              <span>{{ formatWithUnit(formatDecimal(viewRow.wagePaid), "unitWanYuan") }}</span>
413 573
             </el-form-item>
414 574
           </el-col>
415 575
           <el-col :span="24">
@@ -514,11 +674,14 @@ const YES_NO_OPTIONS = ["是", "否"]
514 674
 const DEFAULT_ENTERPRISE_TYPE = "个体工商户"
515 675
 const DEFAULT_SALES_CHANNEL = "其他"
516 676
 
517
-const STOCK_COUNT_FIELDS = [
677
+const STOCK_INVENTORY_FIELDS = [
518 678
   { prop: "cattleYearEndStock", labelKey: "formCattleYearEndStock", unitKey: "unitHead" },
519 679
   { prop: "cattleBreedingFemaleStock", labelKey: "formCattleBreedingFemaleStock", unitKey: "unitHead" },
520 680
   { prop: "sheepYearEndStock", labelKey: "formSheepYearEndStock", unitKey: "unitHead" },
521
-  { prop: "sheepBreedingFemaleStock", labelKey: "formSheepBreedingFemaleStock", unitKey: "unitHead" },
681
+  { prop: "sheepBreedingFemaleStock", labelKey: "formSheepBreedingFemaleStock", unitKey: "unitHead" }
682
+]
683
+
684
+const STOCK_OUTBOUND_FIELDS = [
522 685
   { prop: "cattleOutbound", labelKey: "formCattleOutbound", unitKey: "unitHead" },
523 686
   { prop: "sheepOutbound", labelKey: "formSheepOutbound", unitKey: "unitHead" }
524 687
 ]
@@ -532,7 +695,8 @@ const GRASSLAND_DECIMAL_FIELDS = [
532 695
 
533 696
 const COUNT_PROPS = [
534 697
   "livestockLaborCount",
535
-  ...STOCK_COUNT_FIELDS.map((f) => f.prop),
698
+  ...STOCK_INVENTORY_FIELDS.map((f) => f.prop),
699
+  ...STOCK_OUTBOUND_FIELDS.map((f) => f.prop),
536 700
   "drivenPopulation"
537 701
 ]
538 702
 
@@ -545,39 +709,6 @@ const DECIMAL_PROPS = [
545 709
   "wagePaid"
546 710
 ]
547 711
 
548
-const VIEW_FIELDS = [
549
-  { prop: "enterpriseName", labelKey: "formEnterpriseName", type: "text" },
550
-  { prop: "legalRepresentative", labelKey: "formLegalRepresentative", type: "text" },
551
-  { prop: "enterpriseType", labelKey: "formEnterpriseType", type: "text" },
552
-  { prop: "registeredCapital", labelKey: "formRegisteredCapital", type: "decimal", unitKey: "unitWanYuan" },
553
-  { prop: "establishDate", labelKey: "formEstablishDate", type: "text" },
554
-  { prop: "livestockLaborCount", labelKey: "formLivestockLaborCount", type: "count", unitKey: "unitPerson" },
555
-  { prop: "cattleYearEndStock", labelKey: "formCattleYearEndStock", type: "count", unitKey: "unitHead" },
556
-  { prop: "cattleBreedingFemaleStock", labelKey: "formCattleBreedingFemaleStock", type: "count", unitKey: "unitHead" },
557
-  { prop: "sheepYearEndStock", labelKey: "formSheepYearEndStock", type: "count", unitKey: "unitHead" },
558
-  { prop: "sheepBreedingFemaleStock", labelKey: "formSheepBreedingFemaleStock", type: "count", unitKey: "unitHead" },
559
-  { prop: "cattleOutbound", labelKey: "formCattleOutbound", type: "count", unitKey: "unitHead" },
560
-  { prop: "sheepOutbound", labelKey: "formSheepOutbound", type: "count", unitKey: "unitHead" },
561
-  { prop: "stockSubtotal", labelKey: "formStockSubtotal", type: "count", unitKey: "unitHead" },
562
-  { prop: "grassBalanceArea", labelKey: "formGrassBalanceArea", type: "decimal", unitKey: "unitMu" },
563
-  { prop: "transferGrassArea", labelKey: "formTransferGrassArea", type: "decimal", unitKey: "unitMu" },
564
-  { prop: "grasslandAreaSubtotal", labelKey: "formGrasslandAreaSubtotal", type: "decimal", unitKey: "unitMu" },
565
-  { prop: "approvedCarryingCapacity", labelKey: "formApprovedCarryingCapacity", type: "decimal", unitKey: "unitHead" },
566
-  { prop: "yearEndStockSheepUnit", labelKey: "formYearEndStockSheepUnit", type: "decimal", unitKey: "unitHead" },
567
-  { prop: "isGrassBalanced", labelKey: "formIsGrassBalanced", type: "text" },
568
-  { prop: "income", labelKey: "formIncome", type: "decimal", unitKey: "unitWanYuan" },
569
-  { prop: "expense", labelKey: "formExpense", type: "decimal", unitKey: "unitWanYuan" },
570
-  { prop: "profit", labelKey: "formProfit", type: "decimal", unitKey: "unitWanYuan" },
571
-  { prop: "subsidyYear", labelKey: "formSubsidyYear", type: "count" },
572
-  { prop: "hasSubsidy", labelKey: "formHasSubsidy", type: "text" },
573
-  { prop: "subsidyAmount", labelKey: "formSubsidyAmount", type: "decimal", unitKey: "unitWanYuan" },
574
-  { prop: "hasTrademark", labelKey: "formHasTrademark", type: "text" },
575
-  { prop: "hasQualityCert", labelKey: "formHasQualityCert", type: "text" },
576
-  { prop: "salesChannel", labelKey: "formSalesChannel", type: "text" },
577
-  { prop: "drivenPopulation", labelKey: "formDrivenPopulation", type: "count", unitKey: "unitPerson" },
578
-  { prop: "wagePaid", labelKey: "formWagePaid", type: "decimal", unitKey: "unitWanYuan" }
579
-]
580
-
581 712
 function getCurrentYearMonth() {
582 713
   const now = new Date()
583 714
   return { statYear: now.getFullYear(), statMonth: now.getMonth() + 1 }
@@ -678,9 +809,9 @@ export default {
678 809
       enterpriseTypeOptions: ENTERPRISE_TYPE_OPTIONS,
679 810
       salesChannelOptions: SALES_CHANNEL_OPTIONS,
680 811
       yesNoOptions: YES_NO_OPTIONS,
681
-      stockCountFields: STOCK_COUNT_FIELDS,
812
+      stockInventoryFields: STOCK_INVENTORY_FIELDS,
813
+      stockOutboundFields: STOCK_OUTBOUND_FIELDS,
682 814
       grasslandDecimalFields: GRASSLAND_DECIMAL_FIELDS,
683
-      viewFields: VIEW_FIELDS,
684 815
       viewRow: {},
685 816
       importForm: { statYear: undefined, statMonth: undefined },
686 817
       exportForm: { statYear: undefined, statMonth: undefined, townDeptId: undefined },
@@ -705,6 +836,9 @@ export default {
705 836
     stockSubtotalDisplay() {
706 837
       return safeNum(this.form.cattleYearEndStock) + safeNum(this.form.sheepYearEndStock)
707 838
     },
839
+    outboundSubtotalDisplay() {
840
+      return safeNum(this.form.cattleOutbound) + safeNum(this.form.sheepOutbound)
841
+    },
708 842
     grasslandAreaSubtotalDisplay() {
709 843
       const n = safeNum(this.form.grassBalanceArea) + safeNum(this.form.transferGrassArea)
710 844
       return Number(n.toFixed(4))
@@ -813,6 +947,36 @@ export default {
813 947
       }
814 948
       return this.formatWithUnit(val, field.unitKey)
815 949
     },
950
+    stockSubtotalOf(row) {
951
+      if (!row) {
952
+        return 0
953
+      }
954
+      if (row.stockSubtotal != null && row.stockSubtotal !== "") {
955
+        return row.stockSubtotal
956
+      }
957
+      return safeNum(row.cattleYearEndStock) + safeNum(row.sheepYearEndStock)
958
+    },
959
+    outboundSubtotalOf(row) {
960
+      if (!row) {
961
+        return 0
962
+      }
963
+      if (row.outboundSubtotal != null && row.outboundSubtotal !== "") {
964
+        return row.outboundSubtotal
965
+      }
966
+      return safeNum(row.cattleOutbound) + safeNum(row.sheepOutbound)
967
+    },
968
+    grasslandAreaSubtotalOf(row) {
969
+      if (!row) {
970
+        return undefined
971
+      }
972
+      if (row.grasslandAreaSubtotal != null && row.grasslandAreaSubtotal !== "") {
973
+        return row.grasslandAreaSubtotal
974
+      }
975
+      if (row.grassBalanceArea == null && row.transferGrassArea == null) {
976
+        return undefined
977
+      }
978
+      return Number((safeNum(row.grassBalanceArea) + safeNum(row.transferGrassArea)).toFixed(4))
979
+    },
816 980
     isFutureStatPeriod(statYear, statMonth) {
817 981
       if (statYear == null || statMonth == null) {
818 982
         return false
@@ -1167,6 +1331,10 @@ export default {
1167 1331
   font-weight: 600;
1168 1332
   color: #303133;
1169 1333
 }
1334
+.fr-form >>> .el-form-item__label {
1335
+  white-space: nowrap;
1336
+  line-height: 32px;
1337
+}
1170 1338
 .fr-import-tip {
1171 1339
   margin: 0 0 12px;
1172 1340
   color: #909399;

Разница между файлами не показана из-за своего большого размера
+ 1030 - 0
ruoyi-ui/src/views/dataModel/farmerHousehold/index.vue


Разница между файлами не показана из-за своего большого размера
+ 1365 - 0
ruoyi-ui/src/views/dataModel/largeLivestockFarmer/index.vue


+ 12 - 1
ruoyi-ui/src/views/dataModel/livestockProductOutput/index.vue

@@ -106,6 +106,7 @@
106 106
 
107 107
     <el-dialog :title="dialogTitle" :visible.sync="open" width="640px" append-to-body @close="cancel">
108 108
       <el-form :key="formKey" ref="form" :model="form" label-width="120px" size="small">
109
+        <div class="lpo-section-title">{{ dmT("sectionBasic") }}</div>
109 110
         <el-form-item prop="statYear" :rules="formRules.statYear">
110 111
           <template slot="label">{{ dmT("formStatYear") }}</template>
111 112
           <el-select v-model="form.statYear" :placeholder="dmCommon('pleaseSelect')" style="width: 100%">
@@ -135,6 +136,8 @@
135 136
             />
136 137
           </el-select>
137 138
         </el-form-item>
139
+
140
+        <div class="lpo-section-title">{{ dmT("sectionOutput") }}</div>
138 141
         <el-form-item prop="meatOutput" :rules="formRules.decimal">
139 142
           <template slot="label">{{ dmT("formMeatOutput") }}</template>
140 143
           <div class="dm-input-with-unit">
@@ -175,7 +178,8 @@
175 178
     </el-dialog>
176 179
 
177 180
     <el-dialog :title="dmCommon('viewTitle')" :visible.sync="viewOpen" width="640px" append-to-body>
178
-      <el-form label-width="120px" size="small">
181
+      <el-form class="dm-view-form" label-width="120px" size="small">
182
+        <div class="lpo-section-title">{{ dmT("sectionBasic") }}</div>
179 183
         <el-form-item :label="dmT('formStatYear')">
180 184
           <span>{{ viewRow.statYear || dash }}</span>
181 185
         </el-form-item>
@@ -188,6 +192,8 @@
188 192
         <el-form-item :label="dmT('formVillage')">
189 193
           <span>{{ viewRow.villageName || dash }}</span>
190 194
         </el-form-item>
195
+
196
+        <div class="lpo-section-title">{{ dmT("sectionOutput") }}</div>
191 197
         <el-form-item :label="dmT('formMeatOutput')">
192 198
           <span>{{ formatWithUnit(formatOutput(viewRow.meatOutput), "unitWanTon") }}</span>
193 199
         </el-form-item>
@@ -810,6 +816,11 @@ export default {
810 816
 </script>
811 817
 
812 818
 <style scoped>
819
+.lpo-section-title {
820
+  margin: 4px 0 12px;
821
+  font-weight: 600;
822
+  color: #303133;
823
+}
813 824
 .lpo-import-tip {
814 825
   margin: 0 0 12px;
815 826
   color: #909399;

+ 834 - 0
ruoyi-ui/src/views/dataModel/vaccinationData/index.vue

@@ -0,0 +1,834 @@
1
+<template>
2
+  <div class="app-container">
3
+    <el-card shadow="never">
4
+      <el-form ref="queryForm" :model="queryParams" size="small" :inline="true">
5
+        <el-form-item prop="statYear">
6
+          <template slot="label">{{ dmT("queryStatYear") }}</template>
7
+          <el-select v-model="queryParams.statYear" :placeholder="dmCommon('pleaseSelect')" clearable style="width: 120px">
8
+            <el-option v-for="y in yearOptions" :key="y" :label="String(y)" :value="y" />
9
+          </el-select>
10
+        </el-form-item>
11
+        <el-form-item prop="statMonth">
12
+          <template slot="label">{{ dmT("queryStatMonth") }}</template>
13
+          <el-select v-model="queryParams.statMonth" :placeholder="dmCommon('pleaseSelect')" clearable style="width: 120px">
14
+            <el-option v-for="m in monthOptions" :key="'q-' + m" :label="formatStatMonth(m)" :value="m" />
15
+          </el-select>
16
+        </el-form-item>
17
+        <el-form-item prop="townDeptId">
18
+          <template slot="label">{{ dmT("queryTown") }}</template>
19
+          <el-select v-model="queryParams.townDeptId" :placeholder="dmCommon('pleaseSelect')" clearable filterable style="width: 180px">
20
+            <el-option v-for="item in townOptions" :key="item.deptId" :label="item.deptName" :value="item.deptId" />
21
+          </el-select>
22
+        </el-form-item>
23
+        <el-form-item prop="villageDeptId">
24
+          <template slot="label">{{ dmT("queryVillage") }}</template>
25
+          <el-select
26
+            v-model="queryParams.villageDeptId"
27
+            :placeholder="dmT('phVillageSearch')"
28
+            clearable
29
+            filterable
30
+            style="width: 220px"
31
+          >
32
+            <el-option
33
+              v-for="item in villageOptions"
34
+              :key="'q-v-' + item.deptId"
35
+              :label="item.label"
36
+              :value="item.deptId"
37
+            />
38
+          </el-select>
39
+        </el-form-item>
40
+        <el-form-item>
41
+          <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">{{ dmCommon("search") }}</el-button>
42
+          <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">{{ dmCommon("reset") }}</el-button>
43
+          <el-button
44
+            v-hasPermi="['dataModel:vaccinationData:add']"
45
+            type="primary"
46
+            plain
47
+            icon="el-icon-plus"
48
+            size="mini"
49
+            @click="handleAdd"
50
+          >{{ dmCommon("add") }}</el-button>
51
+          <el-button
52
+            v-hasPermi="['dataModel:vaccinationData:import']"
53
+            type="info"
54
+            plain
55
+            icon="el-icon-upload2"
56
+            size="mini"
57
+            @click="handleImportOpen"
58
+          >{{ dmT("btnImport") }}</el-button>
59
+          <el-button
60
+            v-hasPermi="['dataModel:vaccinationData:export']"
61
+            type="warning"
62
+            plain
63
+            icon="el-icon-download"
64
+            size="mini"
65
+            @click="handleExportOpen"
66
+          >{{ dmCommon("export") }}</el-button>
67
+        </el-form-item>
68
+      </el-form>
69
+    </el-card>
70
+
71
+    <br />
72
+
73
+    <el-card shadow="never">
74
+      <el-table v-loading="loading" :data="tableList" border>
75
+        <template slot="empty">
76
+          <span>{{ dmT("emptyList") }}</span>
77
+        </template>
78
+        <el-table-column :label="dmT('colStatYear')" prop="statYear" align="center" width="90" />
79
+        <el-table-column :label="dmT('colStatMonth')" align="center" width="80">
80
+          <template slot-scope="scope">{{ formatStatMonth(scope.row.statMonth) }}</template>
81
+        </el-table-column>
82
+        <el-table-column :label="dmT('colTownName')" prop="townName" align="center" min-width="110" :show-overflow-tooltip="true" />
83
+        <el-table-column :label="dmT('colVillageName')" prop="villageName" align="center" min-width="110" :show-overflow-tooltip="true" />
84
+        <el-table-column :label="dmT('colShouldVaccinateCount')" align="center" width="100">
85
+          <template slot-scope="scope">{{ formatCount(scope.row.shouldVaccinateCount) }}</template>
86
+        </el-table-column>
87
+        <el-table-column :label="dmT('colActualVaccinateCount')" align="center" width="100">
88
+          <template slot-scope="scope">{{ formatCount(scope.row.actualVaccinateCount) }}</template>
89
+        </el-table-column>
90
+        <el-table-column :label="dmT('colImmunityRate')" align="center" width="100">
91
+          <template slot-scope="scope">{{ formatImmunityRate(scope.row.immunityRate) }}</template>
92
+        </el-table-column>
93
+        <el-table-column :label="dmCommon('colOp')" align="center" class-name="small-padding fixed-width" width="180" fixed="right">
94
+          <template slot-scope="scope">
95
+            <el-button v-hasPermi="['dataModel:vaccinationData:query']" type="text" size="mini" @click="handleView(scope.row)">{{ dmCommon("view") }}</el-button>
96
+            <el-button v-hasPermi="['dataModel:vaccinationData:edit']" type="text" size="mini" @click="handleEdit(scope.row)">{{ dmCommon("edit") }}</el-button>
97
+            <el-button v-hasPermi="['dataModel:vaccinationData:remove']" type="text" size="mini" @click="handleDelete(scope.row)">{{ dmCommon("delete") }}</el-button>
98
+          </template>
99
+        </el-table-column>
100
+      </el-table>
101
+      <pagination
102
+        v-show="total > 0"
103
+        :total="total"
104
+        :page.sync="queryParams.pageNum"
105
+        :limit.sync="queryParams.pageSize"
106
+        @pagination="getList"
107
+      />
108
+    </el-card>
109
+
110
+    <el-dialog :title="dialogTitle" :visible.sync="open" width="640px" append-to-body @close="cancel">
111
+      <el-form :key="formKey" ref="form" :model="form" class="vd-form" label-width="120px" size="small">
112
+        <div class="vd-section-title">{{ dmT("sectionBasic") }}</div>
113
+        <el-form-item prop="statYear" :rules="formRules.statYear">
114
+          <template slot="label">{{ dmT("formStatYear") }}</template>
115
+          <el-select v-model="form.statYear" :placeholder="dmCommon('pleaseSelect')" style="width: 100%">
116
+            <el-option v-for="y in yearOptions" :key="'f-' + y" :label="String(y)" :value="y" />
117
+          </el-select>
118
+        </el-form-item>
119
+        <el-form-item prop="statMonth" :rules="formRules.statMonth">
120
+          <template slot="label">{{ dmT("formStatMonth") }}</template>
121
+          <el-select v-model="form.statMonth" :placeholder="dmCommon('pleaseSelect')" style="width: 100%">
122
+            <el-option v-for="m in monthOptions" :key="'fm-' + m" :label="formatStatMonth(m)" :value="m" />
123
+          </el-select>
124
+        </el-form-item>
125
+        <el-form-item prop="villageDeptId" :rules="formRules.villageDeptId">
126
+          <template slot="label">{{ dmT("formVillage") }}</template>
127
+          <el-select
128
+            v-model="form.villageDeptId"
129
+            :placeholder="dmT('phVillageSearch')"
130
+            filterable
131
+            clearable
132
+            style="width: 100%"
133
+          >
134
+            <el-option
135
+              v-for="item in villageOptions"
136
+              :key="'f-v-' + item.deptId"
137
+              :label="item.label"
138
+              :value="item.deptId"
139
+            />
140
+          </el-select>
141
+        </el-form-item>
142
+
143
+        <div class="vd-section-title">{{ dmT("sectionVaccination") }}</div>
144
+        <el-form-item prop="shouldVaccinateCount" :rules="formRules.count">
145
+          <template slot="label">{{ dmT("formShouldVaccinateCount") }}</template>
146
+          <div class="dm-input-with-unit">
147
+            <el-input-number
148
+              v-model="form.shouldVaccinateCount"
149
+              :min="0"
150
+              :precision="0"
151
+              controls-position="right"
152
+              class="dm-input-with-unit__input"
153
+              @change="onShouldCountChange"
154
+            />
155
+            <span class="dm-input-with-unit__suffix">{{ dmT("unitHead") }}</span>
156
+          </div>
157
+        </el-form-item>
158
+        <el-form-item prop="actualVaccinateCount" :rules="formRules.actualCount">
159
+          <template slot="label">{{ dmT("formActualVaccinateCount") }}</template>
160
+          <div class="dm-input-with-unit">
161
+            <el-input-number
162
+              v-model="form.actualVaccinateCount"
163
+              :min="0"
164
+              :precision="0"
165
+              controls-position="right"
166
+              class="dm-input-with-unit__input"
167
+            />
168
+            <span class="dm-input-with-unit__suffix">{{ dmT("unitHead") }}</span>
169
+          </div>
170
+        </el-form-item>
171
+        <el-form-item>
172
+          <template slot="label">{{ dmT("formImmunityRate") }}</template>
173
+          <el-input :value="immunityRateDisplay" disabled />
174
+        </el-form-item>
175
+        <el-form-item prop="remark" :rules="formRules.remark">
176
+          <template slot="label">{{ dmT("formRemark") }}</template>
177
+          <el-input v-model="form.remark" type="textarea" :rows="2" :placeholder="dmT('phRemark')" maxlength="500" show-word-limit />
178
+        </el-form-item>
179
+      </el-form>
180
+      <div slot="footer" class="dialog-footer">
181
+        <el-button type="primary" @click="submitForm">{{ dmCommon("ok") }}</el-button>
182
+        <el-button @click="cancel">{{ dmCommon("cancel") }}</el-button>
183
+      </div>
184
+    </el-dialog>
185
+
186
+    <el-dialog :title="dmCommon('viewTitle')" :visible.sync="viewOpen" width="640px" append-to-body>
187
+      <el-form class="dm-view-form vd-form" label-width="120px" size="small">
188
+        <div class="vd-section-title">{{ dmT("sectionBasic") }}</div>
189
+        <el-form-item :label="dmT('formStatYear')"><span>{{ viewRow.statYear || dash }}</span></el-form-item>
190
+        <el-form-item :label="dmT('formStatMonth')"><span>{{ formatStatMonth(viewRow.statMonth) }}</span></el-form-item>
191
+        <el-form-item :label="dmT('formTown')"><span>{{ viewRow.townName || dash }}</span></el-form-item>
192
+        <el-form-item :label="dmT('formVillage')"><span>{{ viewRow.villageName || dash }}</span></el-form-item>
193
+
194
+        <div class="vd-section-title">{{ dmT("sectionVaccination") }}</div>
195
+        <el-form-item :label="dmT('formShouldVaccinateCount')">
196
+          <span>{{ formatWithUnit(formatCount(viewRow.shouldVaccinateCount), "unitHead") }}</span>
197
+        </el-form-item>
198
+        <el-form-item :label="dmT('formActualVaccinateCount')">
199
+          <span>{{ formatWithUnit(formatCount(viewRow.actualVaccinateCount), "unitHead") }}</span>
200
+        </el-form-item>
201
+        <el-form-item :label="dmT('formImmunityRate')">
202
+          <span>{{ formatImmunityRate(viewRow.immunityRate) }}</span>
203
+        </el-form-item>
204
+        <el-form-item :label="dmT('formRemark')">
205
+          <span class="vd-view-text">{{ viewRow.remark || dash }}</span>
206
+        </el-form-item>
207
+      </el-form>
208
+      <div slot="footer" class="dialog-footer">
209
+        <el-button v-hasPermi="['dataModel:vaccinationData:edit']" type="primary" @click="handleEditFromView">{{ dmCommon("edit") }}</el-button>
210
+        <el-button @click="viewOpen = false">{{ dmCommon("close") }}</el-button>
211
+      </div>
212
+    </el-dialog>
213
+
214
+    <el-dialog :title="dmT('importTitle')" :visible.sync="importOpen" width="480px" append-to-body @close="resetImport">
215
+      <el-form ref="importFormRef" :model="importForm" label-width="100px" size="small">
216
+        <el-form-item prop="statYear" :rules="importRules.statYear">
217
+          <template slot="label">{{ dmT("importStatYear") }}</template>
218
+          <el-select v-model="importForm.statYear" :placeholder="dmT('importStatYearPh')" style="width: 100%">
219
+            <el-option v-for="y in yearOptions" :key="'iy-' + y" :label="String(y)" :value="y" />
220
+          </el-select>
221
+        </el-form-item>
222
+        <el-form-item prop="statMonth" :rules="importRules.statMonth">
223
+          <template slot="label">{{ dmT("importStatMonth") }}</template>
224
+          <el-select v-model="importForm.statMonth" :placeholder="dmT('importStatMonthPh')" style="width: 100%">
225
+            <el-option v-for="m in monthOptions" :key="'im-' + m" :label="formatStatMonth(m)" :value="m" />
226
+          </el-select>
227
+        </el-form-item>
228
+        <p class="vd-import-tip">{{ dmT("importTip") }}</p>
229
+        <el-upload ref="importUpload" drag :limit="1" accept=".xlsx,.xls" :auto-upload="false" action="#">
230
+          <i class="el-icon-upload" />
231
+          <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
232
+          <div slot="tip" class="el-upload__tip">
233
+            <el-link type="primary" :underline="false" @click="handleDownloadTemplate">{{ dmT("btnDownloadTemplate") }}</el-link>
234
+          </div>
235
+        </el-upload>
236
+      </el-form>
237
+      <div slot="footer" class="dialog-footer">
238
+        <el-button type="primary" :loading="importing" @click="handleImportSubmit">{{ dmCommon("ok") }}</el-button>
239
+        <el-button @click="importOpen = false">{{ dmCommon("cancel") }}</el-button>
240
+      </div>
241
+    </el-dialog>
242
+
243
+    <el-dialog :title="dmT('exportTitle')" :visible.sync="exportOpen" width="480px" append-to-body @close="resetExport">
244
+      <el-form ref="exportFormRef" :model="exportForm" label-width="100px" size="small">
245
+        <el-form-item prop="statYear" :rules="exportRules.statYear">
246
+          <template slot="label">{{ dmT("exportStatYear") }}</template>
247
+          <el-select v-model="exportForm.statYear" :placeholder="dmT('exportStatYearPh')" style="width: 100%">
248
+            <el-option v-for="y in yearOptions" :key="'ey-' + y" :label="String(y)" :value="y" />
249
+          </el-select>
250
+        </el-form-item>
251
+        <el-form-item prop="statMonth" :rules="exportRules.statMonth">
252
+          <template slot="label">{{ dmT("exportStatMonth") }}</template>
253
+          <el-select v-model="exportForm.statMonth" :placeholder="dmT('exportStatMonthPh')" style="width: 100%">
254
+            <el-option v-for="m in monthOptions" :key="'em-' + m" :label="formatStatMonth(m)" :value="m" />
255
+          </el-select>
256
+        </el-form-item>
257
+        <el-form-item>
258
+          <template slot="label">{{ dmT("exportTown") }}</template>
259
+          <el-select
260
+            v-model="exportForm.townDeptId"
261
+            :placeholder="dmT('exportTownPh')"
262
+            clearable
263
+            filterable
264
+            style="width: 100%"
265
+          >
266
+            <el-option v-for="item in townOptions" :key="'et-' + item.deptId" :label="item.deptName" :value="item.deptId" />
267
+          </el-select>
268
+        </el-form-item>
269
+      </el-form>
270
+      <div slot="footer" class="dialog-footer">
271
+        <el-button type="primary" :loading="exporting" @click="handleExportSubmit">{{ dmCommon("ok") }}</el-button>
272
+        <el-button @click="exportOpen = false">{{ dmCommon("cancel") }}</el-button>
273
+      </div>
274
+    </el-dialog>
275
+  </div>
276
+</template>
277
+
278
+<script>
279
+import dataModelLocaleMixin from "@/mixins/dataModelLocaleMixin"
280
+import {
281
+  listVaccinationData,
282
+  getVaccinationData,
283
+  addVaccinationData,
284
+  updateVaccinationData,
285
+  delVaccinationData,
286
+  listVaccinationDataYearOptions,
287
+  listVaccinationDataMonthOptions,
288
+  listVaccinationDataTownOptions,
289
+  listVaccinationDataVillageTree,
290
+  importVaccinationData,
291
+  downloadVaccinationDataTemplate,
292
+  exportVaccinationData
293
+} from "@/api/dataModel/vaccinationData"
294
+import { blobValidate } from "@/utils/ruoyi"
295
+import { saveAs } from "file-saver"
296
+
297
+function getCurrentYearMonth() {
298
+  const now = new Date()
299
+  return { statYear: now.getFullYear(), statMonth: now.getMonth() + 1 }
300
+}
301
+
302
+function createEmptyForm() {
303
+  return {
304
+    id: undefined,
305
+    statYear: undefined,
306
+    statMonth: undefined,
307
+    villageDeptId: undefined,
308
+    shouldVaccinateCount: undefined,
309
+    actualVaccinateCount: undefined,
310
+    remark: undefined
311
+  }
312
+}
313
+
314
+function normalizeForm(data) {
315
+  const row = Object.assign(createEmptyForm(), data || {})
316
+  ;["shouldVaccinateCount", "actualVaccinateCount"].forEach((prop) => {
317
+    const val = row[prop]
318
+    row[prop] = val == null || val === "" ? undefined : Number(val)
319
+  })
320
+  return row
321
+}
322
+
323
+function flattenVillageOptions(tree) {
324
+  const list = []
325
+  ;(tree || []).forEach((county) => {
326
+    ;(county.children || []).forEach((town) => {
327
+      ;(town.children || []).forEach((village) => {
328
+        if (village == null || village.id == null) {
329
+          return
330
+        }
331
+        const townName = town.label || ""
332
+        const villageName = village.label || ""
333
+        list.push({
334
+          deptId: village.id,
335
+          label: townName ? `${townName} / ${villageName}` : villageName
336
+        })
337
+      })
338
+    })
339
+  })
340
+  return list
341
+}
342
+
343
+function calcImmunityRate(should, actual) {
344
+  if (should == null || should <= 0 || actual == null || actual === "") {
345
+    return null
346
+  }
347
+  const s = Number(should)
348
+  const a = Number(actual)
349
+  if (!Number.isFinite(s) || !Number.isFinite(a) || s <= 0) {
350
+    return null
351
+  }
352
+  return Math.round((a * 10000) / s) / 100
353
+}
354
+
355
+export default {
356
+  name: "VaccinationData",
357
+  mixins: [dataModelLocaleMixin],
358
+  data() {
359
+    return {
360
+      dmNs: "vaccinationData",
361
+      loading: false,
362
+      importing: false,
363
+      exporting: false,
364
+      open: false,
365
+      viewOpen: false,
366
+      importOpen: false,
367
+      exportOpen: false,
368
+      dialogEdit: false,
369
+      formKey: 0,
370
+      total: 0,
371
+      tableList: [],
372
+      yearOptions: [],
373
+      monthOptions: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
374
+      townOptions: [],
375
+      villageOptions: [],
376
+      viewRow: {},
377
+      importForm: { statYear: undefined, statMonth: undefined },
378
+      exportForm: { statYear: undefined, statMonth: undefined, townDeptId: undefined },
379
+      queryParams: {
380
+        pageNum: 1,
381
+        pageSize: 20,
382
+        statYear: undefined,
383
+        statMonth: undefined,
384
+        townDeptId: undefined,
385
+        villageDeptId: undefined
386
+      },
387
+      form: createEmptyForm()
388
+    }
389
+  },
390
+  computed: {
391
+    dash() {
392
+      return this.$t("dataModel.status.dash")
393
+    },
394
+    dialogTitle() {
395
+      return this.dialogEdit ? this.dmT("dialogEdit") : this.dmT("dialogAdd")
396
+    },
397
+    immunityRateDisplay() {
398
+      const rate = calcImmunityRate(this.form.shouldVaccinateCount, this.form.actualVaccinateCount)
399
+      return this.formatImmunityRate(rate)
400
+    },
401
+    formRules() {
402
+      return {
403
+        statYear: [{ required: true, message: this.dmT("ruleStatYearRequired"), trigger: "change" }],
404
+        statMonth: [
405
+          { required: true, message: this.dmT("ruleStatMonthRequired"), trigger: "change" },
406
+          { validator: this.validateFormStatMonth, trigger: "change" }
407
+        ],
408
+        villageDeptId: [{ required: true, message: this.dmT("ruleVillageRequired"), trigger: "change" }],
409
+        count: [{ validator: this.validateOptionalCount, trigger: "change" }],
410
+        actualCount: [{ validator: this.validateActualCount, trigger: "change" }],
411
+        remark: [{ max: 500, message: this.dmCommon("ruleLen500"), trigger: "blur" }]
412
+      }
413
+    },
414
+    importRules() {
415
+      return {
416
+        statYear: [{ required: true, message: this.dmT("ruleStatYearRequired"), trigger: "change" }],
417
+        statMonth: [
418
+          { required: true, message: this.dmT("ruleStatMonthRequired"), trigger: "change" },
419
+          { validator: this.validateImportStatMonth, trigger: "change" }
420
+        ]
421
+      }
422
+    },
423
+    exportRules() {
424
+      return {
425
+        statYear: [{ required: true, message: this.dmT("exportStatYearRequired"), trigger: "change" }],
426
+        statMonth: [
427
+          { required: true, message: this.dmT("exportStatMonthRequired"), trigger: "change" },
428
+          { validator: this.validateExportStatMonth, trigger: "change" }
429
+        ]
430
+      }
431
+    }
432
+  },
433
+  created() {
434
+    this.loadOptions()
435
+    this.getList()
436
+  },
437
+  methods: {
438
+    loadOptions() {
439
+      listVaccinationDataYearOptions().then((res) => {
440
+        this.yearOptions = Array.isArray(res.data) ? res.data : []
441
+      })
442
+      listVaccinationDataMonthOptions().then((res) => {
443
+        if (Array.isArray(res.data) && res.data.length) {
444
+          this.monthOptions = res.data
445
+        }
446
+      })
447
+      listVaccinationDataTownOptions().then((res) => {
448
+        this.townOptions = Array.isArray(res.data) ? res.data : []
449
+      })
450
+      this.loadVillageTree()
451
+    },
452
+    loadVillageTree() {
453
+      return listVaccinationDataVillageTree()
454
+        .then((res) => {
455
+          const raw = res && res.data !== undefined ? res.data : res
456
+          this.villageOptions = flattenVillageOptions(Array.isArray(raw) ? raw : [])
457
+          if (!this.villageOptions.length) {
458
+            this.$modal.msgWarning(this.dmT("villageTreeEmpty"))
459
+          }
460
+        })
461
+        .catch(() => {
462
+          this.villageOptions = []
463
+        })
464
+    },
465
+    formatStatMonth(month) {
466
+      if (month == null || month === "") {
467
+        return this.dash
468
+      }
469
+      return this.dmT("statMonthLabel", { month })
470
+    },
471
+    formatCount(val) {
472
+      return val == null || val === "" ? this.dash : val
473
+    },
474
+    formatImmunityRate(rate) {
475
+      if (rate == null || rate === "") {
476
+        return this.dash
477
+      }
478
+      const n = Number(rate)
479
+      if (!Number.isFinite(n)) {
480
+        return this.dash
481
+      }
482
+      return `${n.toFixed(2)}%`
483
+    },
484
+    isFutureStatPeriod(statYear, statMonth) {
485
+      if (statYear == null || statMonth == null) {
486
+        return false
487
+      }
488
+      const now = new Date()
489
+      const y = now.getFullYear()
490
+      const m = now.getMonth() + 1
491
+      return statYear > y || (statYear === y && statMonth > m)
492
+    },
493
+    validateFormStatMonth(rule, value, callback) {
494
+      if (this.isFutureStatPeriod(this.form.statYear, value)) {
495
+        callback(new Error(this.dmT("ruleStatMonthFuture")))
496
+        return
497
+      }
498
+      callback()
499
+    },
500
+    validateImportStatMonth(rule, value, callback) {
501
+      if (this.isFutureStatPeriod(this.importForm.statYear, value)) {
502
+        callback(new Error(this.dmT("ruleStatMonthFuture")))
503
+        return
504
+      }
505
+      callback()
506
+    },
507
+    validateExportStatMonth(rule, value, callback) {
508
+      if (this.isFutureStatPeriod(this.exportForm.statYear, value)) {
509
+        callback(new Error(this.dmT("ruleStatMonthFuture")))
510
+        return
511
+      }
512
+      callback()
513
+    },
514
+    validateOptionalCount(rule, value, callback) {
515
+      if (value == null || value === "") {
516
+        callback()
517
+        return
518
+      }
519
+      if (typeof value !== "number" || Number.isNaN(value) || value < 0 || !Number.isInteger(value)) {
520
+        callback(new Error(this.dmT("ruleCountNonNegative")))
521
+        return
522
+      }
523
+      callback()
524
+    },
525
+    validateActualCount(rule, value, callback) {
526
+      if (value == null || value === "") {
527
+        callback()
528
+        return
529
+      }
530
+      if (typeof value !== "number" || Number.isNaN(value) || value < 0 || !Number.isInteger(value)) {
531
+        callback(new Error(this.dmT("ruleCountNonNegative")))
532
+        return
533
+      }
534
+      const should = this.form.shouldVaccinateCount
535
+      if (should != null && should !== "" && Number.isFinite(Number(should)) && value > Number(should)) {
536
+        callback(new Error(this.dmT("ruleActualLeShould")))
537
+        return
538
+      }
539
+      callback()
540
+    },
541
+    onShouldCountChange() {
542
+      this.$nextTick(() => {
543
+        if (this.$refs.form) {
544
+          this.$refs.form.validateField("actualVaccinateCount")
545
+        }
546
+      })
547
+    },
548
+    buildListQuery() {
549
+      const q = {
550
+        pageNum: this.queryParams.pageNum,
551
+        pageSize: this.queryParams.pageSize
552
+      }
553
+      if (this.queryParams.statYear != null) {
554
+        q.statYear = this.queryParams.statYear
555
+      }
556
+      if (this.queryParams.statMonth != null) {
557
+        q.statMonth = this.queryParams.statMonth
558
+      }
559
+      if (this.queryParams.townDeptId != null) {
560
+        q.townDeptId = this.queryParams.townDeptId
561
+      }
562
+      if (this.queryParams.villageDeptId != null) {
563
+        q.villageDeptId = this.queryParams.villageDeptId
564
+      }
565
+      return q
566
+    },
567
+    getList() {
568
+      this.loading = true
569
+      listVaccinationData(this.buildListQuery())
570
+        .then((res) => {
571
+          this.tableList = res.rows || []
572
+          this.total = res.total || 0
573
+        })
574
+        .finally(() => {
575
+          this.loading = false
576
+        })
577
+    },
578
+    handleQuery() {
579
+      this.queryParams.pageNum = 1
580
+      this.getList()
581
+    },
582
+    resetQuery() {
583
+      this.queryParams = {
584
+        pageNum: 1,
585
+        pageSize: 20,
586
+        statYear: undefined,
587
+        statMonth: undefined,
588
+        townDeptId: undefined,
589
+        villageDeptId: undefined
590
+      }
591
+      this.getList()
592
+    },
593
+    handleAdd() {
594
+      this.dialogEdit = false
595
+      this.formKey += 1
596
+      this.form = createEmptyForm()
597
+      const ym = getCurrentYearMonth()
598
+      this.form.statYear = ym.statYear
599
+      this.form.statMonth = ym.statMonth
600
+      this.open = true
601
+      this.$nextTick(() => {
602
+        if (this.$refs.form) {
603
+          this.$refs.form.clearValidate()
604
+        }
605
+      })
606
+    },
607
+    handleEdit(row) {
608
+      getVaccinationData(row.id).then((res) => {
609
+        this.dialogEdit = true
610
+        this.formKey += 1
611
+        this.form = normalizeForm(res.data)
612
+        this.open = true
613
+        this.viewOpen = false
614
+        this.$nextTick(() => {
615
+          if (this.$refs.form) {
616
+            this.$refs.form.clearValidate()
617
+          }
618
+        })
619
+      })
620
+    },
621
+    handleView(row) {
622
+      getVaccinationData(row.id).then((res) => {
623
+        this.viewRow = res.data || {}
624
+        this.viewOpen = true
625
+      })
626
+    },
627
+    handleEditFromView() {
628
+      if (!this.viewRow || this.viewRow.id == null) {
629
+        return
630
+      }
631
+      this.handleEdit(this.viewRow)
632
+    },
633
+    handleDelete(row) {
634
+      this.$modal
635
+        .confirm(this.dmT("confirmDelete"))
636
+        .then(() => delVaccinationData(row.id))
637
+        .then(() => {
638
+          this.$modal.msgSuccess(this.dmCommon("msgDelOk"))
639
+          this.getList()
640
+        })
641
+        .catch(() => {})
642
+    },
643
+    buildSubmitPayload() {
644
+      return {
645
+        id: this.form.id,
646
+        statYear: this.form.statYear,
647
+        statMonth: this.form.statMonth,
648
+        villageDeptId: this.form.villageDeptId,
649
+        shouldVaccinateCount:
650
+          this.form.shouldVaccinateCount == null || this.form.shouldVaccinateCount === ""
651
+            ? null
652
+            : this.form.shouldVaccinateCount,
653
+        actualVaccinateCount:
654
+          this.form.actualVaccinateCount == null || this.form.actualVaccinateCount === ""
655
+            ? null
656
+            : this.form.actualVaccinateCount,
657
+        remark: this.form.remark
658
+      }
659
+    },
660
+    submitForm() {
661
+      this.$refs.form.validate((valid) => {
662
+        if (!valid) {
663
+          return
664
+        }
665
+        const payload = this.buildSubmitPayload()
666
+        if (this.dialogEdit) {
667
+          updateVaccinationData(payload).then(() => {
668
+            this.$modal.msgSuccess(this.dmCommon("msgEditOk"))
669
+            this.open = false
670
+            this.getList()
671
+          })
672
+        } else {
673
+          addVaccinationData(payload).then(() => {
674
+            this.$modal.msgSuccess(this.dmCommon("msgAddOk"))
675
+            this.open = false
676
+            this.getList()
677
+          })
678
+        }
679
+      })
680
+    },
681
+    cancel() {
682
+      this.open = false
683
+      this.form = createEmptyForm()
684
+    },
685
+    handleImportOpen() {
686
+      const ym = getCurrentYearMonth()
687
+      this.importForm = {
688
+        statYear: this.queryParams.statYear != null ? this.queryParams.statYear : ym.statYear,
689
+        statMonth: this.queryParams.statMonth != null ? this.queryParams.statMonth : ym.statMonth
690
+      }
691
+      this.importOpen = true
692
+      this.$nextTick(() => {
693
+        if (this.$refs.importFormRef) {
694
+          this.$refs.importFormRef.clearValidate()
695
+        }
696
+        if (this.$refs.importUpload) {
697
+          this.$refs.importUpload.clearFiles()
698
+        }
699
+      })
700
+    },
701
+    resetImport() {
702
+      this.importForm = { statYear: undefined, statMonth: undefined }
703
+      if (this.$refs.importUpload) {
704
+        this.$refs.importUpload.clearFiles()
705
+      }
706
+    },
707
+    handleDownloadTemplate() {
708
+      downloadVaccinationDataTemplate().then(async (data) => {
709
+        const isBlob = blobValidate(data)
710
+        if (isBlob) {
711
+          saveAs(data, `vaccination_data_import_template_${new Date().getTime()}.xlsx`)
712
+        } else {
713
+          this.$modal.msgError(this.dmT("exportFail"))
714
+        }
715
+      })
716
+    },
717
+    handleImportSubmit() {
718
+      this.$refs.importFormRef.validate((valid) => {
719
+        if (!valid) {
720
+          return
721
+        }
722
+        const files = this.$refs.importUpload ? this.$refs.importUpload.uploadFiles : []
723
+        if (!files || !files.length) {
724
+          this.$modal.msgError(this.dmCommon("pleaseSelect"))
725
+          return
726
+        }
727
+        const raw = files[0].raw
728
+        this.importing = true
729
+        this.$modal.loading(this.dmT("importLoading"))
730
+        importVaccinationData(raw, this.importForm.statYear, this.importForm.statMonth)
731
+          .then((res) => {
732
+            const data = res.data || {}
733
+            const msg = this.dmT("importSummary", {
734
+              insert: data.insertCount != null ? data.insertCount : 0,
735
+              update: data.updateCount != null ? data.updateCount : 0,
736
+              fail: data.failCount != null ? data.failCount : 0
737
+            })
738
+            this.$modal.msgSuccess(msg)
739
+            if (data.warnMessages && data.warnMessages.length) {
740
+              this.$alert(data.warnMessages.join("<br/>"), this.dmT("importWarnTitle"), { dangerouslyUseHTMLString: true })
741
+            }
742
+            if (data.failMessages && data.failMessages.length) {
743
+              this.$alert(data.failMessages.join("<br/>"), this.dmT("importFailTitle"), { dangerouslyUseHTMLString: true })
744
+            }
745
+            this.importOpen = false
746
+            this.getList()
747
+          })
748
+          .finally(() => {
749
+            this.importing = false
750
+            this.$modal.closeLoading()
751
+          })
752
+      })
753
+    },
754
+    handleExportOpen() {
755
+      const ym = getCurrentYearMonth()
756
+      this.exportForm = {
757
+        statYear: this.queryParams.statYear != null ? this.queryParams.statYear : ym.statYear,
758
+        statMonth: this.queryParams.statMonth != null ? this.queryParams.statMonth : ym.statMonth,
759
+        townDeptId: this.queryParams.townDeptId
760
+      }
761
+      this.exportOpen = true
762
+      this.$nextTick(() => {
763
+        if (this.$refs.exportFormRef) {
764
+          this.$refs.exportFormRef.clearValidate()
765
+        }
766
+      })
767
+    },
768
+    resetExport() {
769
+      this.exportForm = { statYear: undefined, statMonth: undefined, townDeptId: undefined }
770
+    },
771
+    handleExportSubmit() {
772
+      this.$refs.exportFormRef.validate((valid) => {
773
+        if (!valid) {
774
+          return
775
+        }
776
+        this.exporting = true
777
+        this.$modal.loading(this.dmT("exportLoading"))
778
+        exportVaccinationData(this.exportForm.statYear, this.exportForm.statMonth, this.exportForm.townDeptId)
779
+          .then(async (data) => {
780
+            const isBlob = blobValidate(data)
781
+            if (isBlob) {
782
+              saveAs(
783
+                data,
784
+                `vaccination_data_${this.exportForm.statYear}_${this.exportForm.statMonth}_${new Date().getTime()}.xlsx`
785
+              )
786
+              this.exportOpen = false
787
+            } else {
788
+              this.$modal.msgError(this.dmT("exportFail"))
789
+            }
790
+          })
791
+          .finally(() => {
792
+            this.exporting = false
793
+            this.$modal.closeLoading()
794
+          })
795
+      })
796
+    }
797
+  }
798
+}
799
+</script>
800
+
801
+<style scoped>
802
+.vd-section-title {
803
+  margin: 4px 0 12px;
804
+  font-weight: 600;
805
+  color: #303133;
806
+}
807
+.vd-import-tip {
808
+  margin: 0 0 12px;
809
+  color: #909399;
810
+  font-size: 12px;
811
+  line-height: 1.5;
812
+}
813
+.vd-view-text {
814
+  white-space: pre-wrap;
815
+  word-break: break-all;
816
+}
817
+.dm-input-with-unit {
818
+  display: flex;
819
+  align-items: center;
820
+  width: 100%;
821
+}
822
+.dm-input-with-unit__input {
823
+  flex: 1;
824
+  width: 100%;
825
+}
826
+.dm-input-with-unit__suffix {
827
+  margin-left: 8px;
828
+  color: #909399;
829
+  white-space: nowrap;
830
+}
831
+.dm-input-with-unit >>> .el-input-number {
832
+  width: 100%;
833
+}
834
+</style>

+ 316 - 31
ruoyi-ui/src/views/dataModel/yakHerdInventory/index.vue

@@ -87,15 +87,27 @@
87 87
         <el-table-column :label="dmT('colHerdsmanHouseholdCount')" align="center" width="90">
88 88
           <template slot-scope="scope">{{ formatCount(scope.row.herdsmanHouseholdCount) }}</template>
89 89
         </el-table-column>
90
-        <el-table-column :label="dmT('colYakTotal')" align="center" width="100">
91
-          <template slot-scope="scope">{{ formatCount(scope.row.yakTotal) }}</template>
92
-        </el-table-column>
93
-        <el-table-column :label="dmT('colBullTotal')" align="center" width="110">
90
+        <el-table-column :label="dmT('colBullTotal')" align="center" width="120">
94 91
           <template slot-scope="scope">{{ formatCount(scope.row.bullTotal) }}</template>
95 92
         </el-table-column>
96
-        <el-table-column :label="dmT('colCowTotal')" align="center" width="110">
93
+        <el-table-column :label="dmT('colCowTotal')" align="center" width="120">
97 94
           <template slot-scope="scope">{{ formatCount(scope.row.cowTotal) }}</template>
98 95
         </el-table-column>
96
+        <el-table-column :label="dmT('colDairyTotal')" align="center" width="120">
97
+          <template slot-scope="scope">{{ formatCount(scope.row.dairyTotal) }}</template>
98
+        </el-table-column>
99
+        <el-table-column :label="dmT('colSheepTotal')" align="center" width="110">
100
+          <template slot-scope="scope">{{ formatCount(scope.row.sheepTotal) }}</template>
101
+        </el-table-column>
102
+        <el-table-column :label="dmT('colInsuredYakCount')" align="center" width="130">
103
+          <template slot-scope="scope">{{ formatCount(scope.row.insuredYakCount) }}</template>
104
+        </el-table-column>
105
+        <el-table-column :label="dmT('colYakTotal')" align="center" width="120">
106
+          <template slot-scope="scope">{{ formatCount(scope.row.yakTotal) }}</template>
107
+        </el-table-column>
108
+        <el-table-column :label="dmT('colGrandTotal')" align="center" width="100">
109
+          <template slot-scope="scope">{{ formatCount(scope.row.grandTotal) }}</template>
110
+        </el-table-column>
99 111
         <el-table-column :label="dmCommon('colOp')" align="center" class-name="small-padding fixed-width" width="180" fixed="right">
100 112
           <template slot-scope="scope">
101 113
             <el-button v-hasPermi="['dataModel:yakHerdInventory:query']" type="text" size="mini" @click="handleView(scope.row)">{{ dmCommon("view") }}</el-button>
@@ -114,7 +126,7 @@
114 126
     </el-card>
115 127
 
116 128
     <el-dialog :title="dialogTitle" :visible.sync="open" width="920px" append-to-body @close="cancel">
117
-      <el-form :key="formKey" ref="form" :model="form" label-width="168px" size="small">
129
+      <el-form :key="formKey" ref="form" :model="form" label-width="200px" size="small">
118 130
         <div class="yhi-section-title">{{ dmT("sectionBasic") }}</div>
119 131
         <el-row :gutter="16">
120 132
           <el-col :span="12">
@@ -155,9 +167,59 @@
155 167
             </el-form-item>
156 168
           </el-col>
157 169
         </el-row>
158
-        <div class="yhi-section-title">{{ dmT("sectionInventory") }}</div>
170
+
171
+        <div class="yhi-section-title">{{ dmT("sectionFarmer") }}</div>
172
+        <el-row :gutter="16">
173
+          <el-col v-for="field in farmerFields" :key="field.prop" :span="12">
174
+            <el-form-item :prop="field.prop" :rules="formRules.count">
175
+              <template slot="label">{{ dmT(field.labelKey) }}</template>
176
+              <div class="dm-input-with-unit">
177
+                <el-input-number
178
+                  v-model="form[field.prop]"
179
+                  :min="0"
180
+                  :precision="0"
181
+                  :controls="true"
182
+                  controls-position="right"
183
+                  class="dm-input-with-unit__input"
184
+                />
185
+                <span class="dm-input-with-unit__suffix">{{ dmT(field.unitKey) }}</span>
186
+              </div>
187
+            </el-form-item>
188
+          </el-col>
189
+        </el-row>
190
+
191
+        <div class="yhi-section-title">{{ dmT("sectionBull") }}</div>
192
+        <el-row :gutter="16">
193
+          <el-col v-for="field in bullInputFields" :key="field.prop" :span="12">
194
+            <el-form-item :prop="field.prop" :rules="formRules.count">
195
+              <template slot="label">{{ dmT(field.labelKey) }}</template>
196
+              <div class="dm-input-with-unit">
197
+                <el-input-number
198
+                  v-model="form[field.prop]"
199
+                  :min="0"
200
+                  :precision="0"
201
+                  :controls="true"
202
+                  controls-position="right"
203
+                  class="dm-input-with-unit__input"
204
+                />
205
+                <span class="dm-input-with-unit__suffix">{{ dmT(field.unitKey) }}</span>
206
+              </div>
207
+            </el-form-item>
208
+          </el-col>
209
+          <el-col :span="12">
210
+            <el-form-item>
211
+              <template slot="label">{{ dmT("formBullTotal") }}</template>
212
+              <div class="dm-input-with-unit">
213
+                <el-input-number :value="bullTotalDisplay" :controls="false" disabled class="dm-input-with-unit__input" />
214
+                <span class="dm-input-with-unit__suffix">{{ dmT("unitHead") }}</span>
215
+              </div>
216
+            </el-form-item>
217
+          </el-col>
218
+        </el-row>
219
+
220
+        <div class="yhi-section-title">{{ dmT("sectionCow") }}</div>
159 221
         <el-row :gutter="16">
160
-          <el-col v-for="field in inputCountFields" :key="field.prop" :span="12">
222
+          <el-col v-for="field in cowInputFields" :key="field.prop" :span="12">
161 223
             <el-form-item :prop="field.prop" :rules="formRules.count">
162 224
               <template slot="label">{{ dmT(field.labelKey) }}</template>
163 225
               <div class="dm-input-with-unit">
@@ -173,7 +235,113 @@
173 235
               </div>
174 236
             </el-form-item>
175 237
           </el-col>
238
+          <el-col :span="12">
239
+            <el-form-item>
240
+              <template slot="label">{{ dmT("formCowTotal") }}</template>
241
+              <div class="dm-input-with-unit">
242
+                <el-input-number :value="cowTotalDisplay" :controls="false" disabled class="dm-input-with-unit__input" />
243
+                <span class="dm-input-with-unit__suffix">{{ dmT("unitHead") }}</span>
244
+              </div>
245
+            </el-form-item>
246
+          </el-col>
176 247
         </el-row>
248
+
249
+        <div class="yhi-section-title">{{ dmT("sectionDairy") }}</div>
250
+        <el-row :gutter="16">
251
+          <el-col v-for="field in dairyInputFields" :key="field.prop" :span="12">
252
+            <el-form-item :prop="field.prop" :rules="formRules.count">
253
+              <template slot="label">{{ dmT(field.labelKey) }}</template>
254
+              <div class="dm-input-with-unit">
255
+                <el-input-number
256
+                  v-model="form[field.prop]"
257
+                  :min="0"
258
+                  :precision="0"
259
+                  :controls="true"
260
+                  controls-position="right"
261
+                  class="dm-input-with-unit__input"
262
+                />
263
+                <span class="dm-input-with-unit__suffix">{{ dmT(field.unitKey) }}</span>
264
+              </div>
265
+            </el-form-item>
266
+          </el-col>
267
+          <el-col :span="12">
268
+            <el-form-item>
269
+              <template slot="label">{{ dmT("formDairyTotal") }}</template>
270
+              <div class="dm-input-with-unit">
271
+                <el-input-number :value="dairyTotalDisplay" :controls="false" disabled class="dm-input-with-unit__input" />
272
+                <span class="dm-input-with-unit__suffix">{{ dmT("unitHead") }}</span>
273
+              </div>
274
+            </el-form-item>
275
+          </el-col>
276
+        </el-row>
277
+
278
+        <div class="yhi-section-title">{{ dmT("sectionSheep") }}</div>
279
+        <el-row :gutter="16">
280
+          <el-col v-for="field in sheepInputFields" :key="field.prop" :span="12">
281
+            <el-form-item :prop="field.prop" :rules="formRules.count">
282
+              <template slot="label">{{ dmT(field.labelKey) }}</template>
283
+              <div class="dm-input-with-unit">
284
+                <el-input-number
285
+                  v-model="form[field.prop]"
286
+                  :min="0"
287
+                  :precision="0"
288
+                  :controls="true"
289
+                  controls-position="right"
290
+                  class="dm-input-with-unit__input"
291
+                />
292
+                <span class="dm-input-with-unit__suffix">{{ dmT(field.unitKey) }}</span>
293
+              </div>
294
+            </el-form-item>
295
+          </el-col>
296
+        </el-row>
297
+
298
+        <div class="yhi-section-title">{{ dmT("sectionSummary") }}</div>
299
+        <el-row :gutter="16">
300
+          <el-col :span="12">
301
+            <el-form-item prop="insuredYakCount" :rules="formRules.count">
302
+              <template slot="label">{{ dmT("formInsuredYakCount") }}</template>
303
+              <div class="dm-input-with-unit">
304
+                <el-input-number
305
+                  v-model="form.insuredYakCount"
306
+                  :min="0"
307
+                  :precision="0"
308
+                  :controls="true"
309
+                  controls-position="right"
310
+                  class="dm-input-with-unit__input"
311
+                />
312
+                <span class="dm-input-with-unit__suffix">{{ dmT("unitHead") }}</span>
313
+              </div>
314
+            </el-form-item>
315
+          </el-col>
316
+          <el-col :span="12">
317
+            <el-form-item>
318
+              <template slot="label">{{ dmT("formYakTotal") }}</template>
319
+              <div class="dm-input-with-unit">
320
+                <el-input-number :value="yakTotalDisplay" :controls="false" disabled class="dm-input-with-unit__input" />
321
+                <span class="dm-input-with-unit__suffix">{{ dmT("unitHead") }}</span>
322
+              </div>
323
+            </el-form-item>
324
+          </el-col>
325
+          <el-col :span="12">
326
+            <el-form-item>
327
+              <template slot="label">{{ dmT("formGrandTotal") }}</template>
328
+              <div class="dm-input-with-unit">
329
+                <el-input-number :value="grandTotalDisplay" :controls="false" disabled class="dm-input-with-unit__input" />
330
+                <span class="dm-input-with-unit__suffix">{{ dmT("unitHead") }}</span>
331
+              </div>
332
+            </el-form-item>
333
+          </el-col>
334
+          <el-col :span="12">
335
+            <el-form-item>
336
+              <template slot="label">{{ dmT("formYakSheepTotal") }}</template>
337
+              <div class="dm-input-with-unit">
338
+                <el-input-number :value="yakSheepTotalDisplay" :controls="false" disabled class="dm-input-with-unit__input" />
339
+                <span class="dm-input-with-unit__suffix">{{ dmT("unitHead") }}</span>
340
+              </div>
341
+            </el-form-item>
342
+          </el-col>
343
+        </el-row>
344
+
177 345
         <el-form-item prop="remark" :rules="formRules.remark">
178 346
           <template slot="label">{{ dmT("formRemark") }}</template>
179 347
           <el-input v-model="form.remark" type="textarea" :rows="2" :placeholder="dmT('phRemark')" maxlength="500" show-word-limit />
@@ -186,7 +354,8 @@
186 354
     </el-dialog>
187 355
 
188 356
     <el-dialog :title="dmCommon('viewTitle')" :visible.sync="viewOpen" width="920px" append-to-body>
189
-      <el-form label-width="168px" size="small">
357
+      <el-form class="dm-view-form" label-width="200px" size="small">
358
+        <div class="yhi-section-title">{{ dmT("sectionBasic") }}</div>
190 359
         <el-row :gutter="16">
191 360
           <el-col :span="12">
192 361
             <el-form-item :label="dmT('formStatYear')">
@@ -208,16 +377,90 @@
208 377
               <span>{{ viewRow.villageName || dash }}</span>
209 378
             </el-form-item>
210 379
           </el-col>
211
-          <el-col v-for="field in inputCountFields" :key="'vi-' + field.prop" :span="12">
380
+        </el-row>
381
+
382
+        <div class="yhi-section-title">{{ dmT("sectionFarmer") }}</div>
383
+        <el-row :gutter="16">
384
+          <el-col v-for="field in farmerFields" :key="'vf-' + field.prop" :span="12">
385
+            <el-form-item :label="dmT(field.labelKey)">
386
+              <span>{{ formatWithUnit(formatCount(viewRow[field.prop]), field.unitKey) }}</span>
387
+            </el-form-item>
388
+          </el-col>
389
+        </el-row>
390
+
391
+        <div class="yhi-section-title">{{ dmT("sectionBull") }}</div>
392
+        <el-row :gutter="16">
393
+          <el-col v-for="field in bullInputFields" :key="'vb-' + field.prop" :span="12">
212 394
             <el-form-item :label="dmT(field.labelKey)">
213 395
               <span>{{ formatWithUnit(formatCount(viewRow[field.prop]), field.unitKey) }}</span>
214 396
             </el-form-item>
215 397
           </el-col>
216
-          <el-col v-for="field in derivedCountFields" :key="'vd-' + field.prop" :span="12">
398
+          <el-col :span="12">
399
+            <el-form-item :label="dmT('formBullTotal')">
400
+              <span>{{ formatWithUnit(formatCount(viewRow.bullTotal), "unitHead") }}</span>
401
+            </el-form-item>
402
+          </el-col>
403
+        </el-row>
404
+
405
+        <div class="yhi-section-title">{{ dmT("sectionCow") }}</div>
406
+        <el-row :gutter="16">
407
+          <el-col v-for="field in cowInputFields" :key="'vc-' + field.prop" :span="12">
217 408
             <el-form-item :label="dmT(field.labelKey)">
218 409
               <span>{{ formatWithUnit(formatCount(viewRow[field.prop]), field.unitKey) }}</span>
219 410
             </el-form-item>
220 411
           </el-col>
412
+          <el-col :span="12">
413
+            <el-form-item :label="dmT('formCowTotal')">
414
+              <span>{{ formatWithUnit(formatCount(viewRow.cowTotal), "unitHead") }}</span>
415
+            </el-form-item>
416
+          </el-col>
417
+        </el-row>
418
+
419
+        <div class="yhi-section-title">{{ dmT("sectionDairy") }}</div>
420
+        <el-row :gutter="16">
421
+          <el-col v-for="field in dairyInputFields" :key="'vd-' + field.prop" :span="12">
422
+            <el-form-item :label="dmT(field.labelKey)">
423
+              <span>{{ formatWithUnit(formatCount(viewRow[field.prop]), field.unitKey) }}</span>
424
+            </el-form-item>
425
+          </el-col>
426
+          <el-col :span="12">
427
+            <el-form-item :label="dmT('formDairyTotal')">
428
+              <span>{{ formatWithUnit(formatCount(viewRow.dairyTotal), "unitHead") }}</span>
429
+            </el-form-item>
430
+          </el-col>
431
+        </el-row>
432
+
433
+        <div class="yhi-section-title">{{ dmT("sectionSheep") }}</div>
434
+        <el-row :gutter="16">
435
+          <el-col v-for="field in sheepInputFields" :key="'vs-' + field.prop" :span="12">
436
+            <el-form-item :label="dmT(field.labelKey)">
437
+              <span>{{ formatWithUnit(formatCount(viewRow[field.prop]), field.unitKey) }}</span>
438
+            </el-form-item>
439
+          </el-col>
440
+        </el-row>
441
+
442
+        <div class="yhi-section-title">{{ dmT("sectionSummary") }}</div>
443
+        <el-row :gutter="16">
444
+          <el-col :span="12">
445
+            <el-form-item :label="dmT('formInsuredYakCount')">
446
+              <span>{{ formatWithUnit(formatCount(viewRow.insuredYakCount), "unitHead") }}</span>
447
+            </el-form-item>
448
+          </el-col>
449
+          <el-col :span="12">
450
+            <el-form-item :label="dmT('formYakTotal')">
451
+              <span>{{ formatWithUnit(formatCount(viewRow.yakTotal), "unitHead") }}</span>
452
+            </el-form-item>
453
+          </el-col>
454
+          <el-col :span="12">
455
+            <el-form-item :label="dmT('formGrandTotal')">
456
+              <span>{{ formatWithUnit(formatCount(viewRow.grandTotal), "unitHead") }}</span>
457
+            </el-form-item>
458
+          </el-col>
459
+          <el-col :span="12">
460
+            <el-form-item :label="dmT('formYakSheepTotal')">
461
+              <span>{{ formatWithUnit(formatCount(viewRow.yakSheepTotal), "unitHead") }}</span>
462
+            </el-form-item>
463
+          </el-col>
221 464
           <el-col :span="24">
222 465
             <el-form-item :label="dmT('formRemark')">
223 466
               <span class="yhi-view-text">{{ viewRow.remark || dash }}</span>
@@ -346,29 +589,38 @@ import { blobValidate } from "@/utils/ruoyi"
346 589
 import { saveAs } from "file-saver"
347 590
 
348 591
 /** 手工录入明细(表单可编辑;选填) */
349
-const INPUT_COUNT_FIELDS = [
592
+const FARMER_FIELDS = [
350 593
   { prop: "villageCount", labelKey: "formVillageCount", unitKey: "unitGe" },
351
-  { prop: "herdsmanHouseholdCount", labelKey: "formHerdsmanHouseholdCount", unitKey: "unitHousehold" },
594
+  { prop: "herdsmanHouseholdCount", labelKey: "formHerdsmanHouseholdCount", unitKey: "unitHousehold" }
595
+]
596
+const BULL_INPUT_FIELDS = [
352 597
   { prop: "breedingBullCount", labelKey: "formBreedingBullCount", unitKey: "unitHead" },
353
-  { prop: "bullCastratedCount", labelKey: "formBullCastratedCount", unitKey: "unitHead" },
598
+  { prop: "bullCastratedCount", labelKey: "formBullCastratedCount", unitKey: "unitHead" }
599
+]
600
+const COW_INPUT_FIELDS = [
354 601
   { prop: "cowYoungCount", labelKey: "formCowYoungCount", unitKey: "unitHead" },
355
-  { prop: "cowAdultCount", labelKey: "formCowAdultCount", unitKey: "unitHead" },
602
+  { prop: "cowAdultCount", labelKey: "formCowAdultCount", unitKey: "unitHead" }
603
+]
604
+const DAIRY_INPUT_FIELDS = [
356 605
   { prop: "milkingCowCount", labelKey: "formMilkingCowCount", unitKey: "unitHead" },
357
-  { prop: "fertileCowCount", labelKey: "formFertileCowCount", unitKey: "unitHead" },
358
-  { prop: "sheepTotal", labelKey: "formSheepTotal", unitKey: "unitHead" },
606
+  { prop: "fertileCowCount", labelKey: "formFertileCowCount", unitKey: "unitHead" }
607
+]
608
+const SHEEP_INPUT_FIELDS = [
359 609
   { prop: "milkingSheepCount", labelKey: "formMilkingSheepCount", unitKey: "unitHead" },
360
-  { prop: "insuredYakCount", labelKey: "formInsuredYakCount", unitKey: "unitHead" }
610
+  { prop: "sheepTotal", labelKey: "formSheepTotal", unitKey: "unitHead" }
361 611
 ]
612
+const INPUT_COUNT_FIELDS = FARMER_FIELDS.concat(
613
+  BULL_INPUT_FIELDS,
614
+  COW_INPUT_FIELDS,
615
+  DAIRY_INPUT_FIELDS,
616
+  SHEEP_INPUT_FIELDS,
617
+  [{ prop: "insuredYakCount", labelKey: "formInsuredYakCount", unitKey: "unitHead" }]
618
+)
362 619
 
363
-/** 系统计算字段(仅详情展示) */
364
-const DERIVED_COUNT_FIELDS = [
365
-  { prop: "bullTotal", labelKey: "formBullTotal", unitKey: "unitHead" },
366
-  { prop: "cowTotal", labelKey: "formCowTotal", unitKey: "unitHead" },
367
-  { prop: "dairyTotal", labelKey: "formDairyTotal", unitKey: "unitHead" },
368
-  { prop: "yakTotal", labelKey: "formYakTotal", unitKey: "unitHead" },
369
-  { prop: "grandTotal", labelKey: "formGrandTotal", unitKey: "unitHead" },
370
-  { prop: "yakSheepTotal", labelKey: "formYakSheepTotal", unitKey: "unitHead" }
371
-]
620
+function safeNum(val) {
621
+  const n = Number(val)
622
+  return Number.isFinite(n) ? n : 0
623
+}
372 624
 
373 625
 function getCurrentYearMonth() {
374 626
   const now = new Date()
@@ -473,11 +725,44 @@ export default {
473 725
     dash() {
474 726
       return this.$t("dataModel.status.dash")
475 727
     },
476
-    inputCountFields() {
477
-      return INPUT_COUNT_FIELDS
728
+    farmerFields() {
729
+      return FARMER_FIELDS
730
+    },
731
+    bullInputFields() {
732
+      return BULL_INPUT_FIELDS
733
+    },
734
+    cowInputFields() {
735
+      return COW_INPUT_FIELDS
736
+    },
737
+    dairyInputFields() {
738
+      return DAIRY_INPUT_FIELDS
739
+    },
740
+    sheepInputFields() {
741
+      return SHEEP_INPUT_FIELDS
742
+    },
743
+    bullTotalDisplay() {
744
+      return safeNum(this.form.breedingBullCount) + safeNum(this.form.bullCastratedCount)
745
+    },
746
+    cowTotalDisplay() {
747
+      return safeNum(this.form.cowYoungCount) + safeNum(this.form.cowAdultCount)
748
+    },
749
+    dairyTotalDisplay() {
750
+      return safeNum(this.form.milkingCowCount) + safeNum(this.form.fertileCowCount)
751
+    },
752
+    yakTotalDisplay() {
753
+      return this.bullTotalDisplay + this.cowTotalDisplay + safeNum(this.form.insuredYakCount)
754
+    },
755
+    grandTotalDisplay() {
756
+      return (
757
+        this.bullTotalDisplay +
758
+        this.cowTotalDisplay +
759
+        safeNum(this.form.insuredYakCount) +
760
+        this.dairyTotalDisplay +
761
+        safeNum(this.form.sheepTotal)
762
+      )
478 763
     },
479
-    derivedCountFields() {
480
-      return DERIVED_COUNT_FIELDS
764
+    yakSheepTotalDisplay() {
765
+      return this.bullTotalDisplay + this.cowTotalDisplay + safeNum(this.form.insuredYakCount) + safeNum(this.form.sheepTotal)
481 766
     },
482 767
     dialogTitle() {
483 768
       return this.dialogEdit ? this.dmT("dialogEdit") : this.dmT("dialogAdd")

+ 54 - 9
ruoyi-ui/src/views/dataModel/yakOutboundReport/index.vue

@@ -195,6 +195,15 @@
195 195
               </div>
196 196
             </el-form-item>
197 197
           </el-col>
198
+          <el-col :span="12">
199
+            <el-form-item>
200
+              <template slot="label">{{ dmT("formOutboundTotal") }}</template>
201
+              <div class="dm-input-with-unit">
202
+                <el-input-number :value="outboundTotalDisplay" :controls="false" disabled class="dm-input-with-unit__input" />
203
+                <span class="dm-input-with-unit__suffix">{{ dmT("unitHeadSheepHorse") }}</span>
204
+              </div>
205
+            </el-form-item>
206
+          </el-col>
198 207
         </el-row>
199 208
         <div class="yor-section-title">{{ dmT("sectionSelfConsumption") }}</div>
200 209
         <el-row :gutter="16">
@@ -214,6 +223,15 @@
214 223
               </div>
215 224
             </el-form-item>
216 225
           </el-col>
226
+          <el-col :span="12">
227
+            <el-form-item>
228
+              <template slot="label">{{ dmT("formSelfConsumptionTotal") }}</template>
229
+              <div class="dm-input-with-unit">
230
+                <el-input-number :value="selfConsumptionTotalDisplay" :controls="false" disabled class="dm-input-with-unit__input" />
231
+                <span class="dm-input-with-unit__suffix">{{ dmT("unitHeadSheepHorse") }}</span>
232
+              </div>
233
+            </el-form-item>
234
+          </el-col>
217 235
         </el-row>
218 236
         <el-form-item prop="remark" :rules="formRules.remark">
219 237
           <template slot="label">{{ dmT("formRemark") }}</template>
@@ -227,7 +245,8 @@
227 245
     </el-dialog>
228 246
 
229 247
     <el-dialog :title="dmCommon('viewTitle')" :visible.sync="viewOpen" width="920px" append-to-body>
230
-      <el-form label-width="168px" size="small">
248
+      <el-form class="dm-view-form" label-width="168px" size="small">
249
+        <div class="yor-section-title">{{ dmT("sectionBasic") }}</div>
231 250
         <el-row :gutter="16">
232 251
           <el-col :span="12">
233 252
             <el-form-item :label="dmT('formStatYear')">
@@ -249,27 +268,47 @@
249 268
               <span>{{ viewRow.villageName || dash }}</span>
250 269
             </el-form-item>
251 270
           </el-col>
252
-          <el-col v-for="field in inputCountFields" :key="'v-' + field.prop" :span="12">
271
+        </el-row>
272
+
273
+        <div class="yor-section-title">{{ dmT("sectionFarmer") }}</div>
274
+        <el-row :gutter="16">
275
+          <el-col v-for="field in farmerCountFields" :key="'vf-' + field.prop" :span="12">
276
+            <el-form-item :label="dmT(field.labelKey)">
277
+              <span>{{ formatWithUnit(formatCount(viewRow[field.prop]), field.unitKey) }}</span>
278
+            </el-form-item>
279
+          </el-col>
280
+        </el-row>
281
+
282
+        <div class="yor-section-title">{{ dmT("sectionOutbound") }}</div>
283
+        <el-row :gutter="16">
284
+          <el-col v-for="field in outboundCountFields" :key="'vo-' + field.prop" :span="12">
253 285
             <el-form-item :label="dmT(field.labelKey)">
254 286
               <span>{{ formatWithUnit(formatCount(viewRow[field.prop]), field.unitKey) }}</span>
255 287
             </el-form-item>
256 288
           </el-col>
257 289
           <el-col :span="12">
258 290
             <el-form-item :label="dmT('formOutboundTotal')">
259
-              <span>{{ formatWithUnit(formatCount(sumOutboundTotal(viewRow)), "unitHead") }}</span>
291
+              <span>{{ formatWithUnit(formatCount(sumOutboundTotal(viewRow)), "unitHeadSheepHorse") }}</span>
260 292
             </el-form-item>
261 293
           </el-col>
262
-          <el-col :span="12">
263
-            <el-form-item :label="dmT('formSelfConsumptionTotal')">
264
-              <span>{{ formatWithUnit(formatCount(sumSelfConsumptionTotal(viewRow)), "unitHead") }}</span>
294
+        </el-row>
295
+
296
+        <div class="yor-section-title">{{ dmT("sectionSelfConsumption") }}</div>
297
+        <el-row :gutter="16">
298
+          <el-col v-for="field in selfConsumptionCountFields" :key="'vs-' + field.prop" :span="12">
299
+            <el-form-item :label="dmT(field.labelKey)">
300
+              <span>{{ formatWithUnit(formatCount(viewRow[field.prop]), field.unitKey) }}</span>
265 301
             </el-form-item>
266 302
           </el-col>
267
-          <el-col :span="24">
268
-            <el-form-item :label="dmT('formRemark')">
269
-              <span class="yor-view-text">{{ viewRow.remark || dash }}</span>
303
+          <el-col :span="12">
304
+            <el-form-item :label="dmT('formSelfConsumptionTotal')">
305
+              <span>{{ formatWithUnit(formatCount(sumSelfConsumptionTotal(viewRow)), "unitHeadSheepHorse") }}</span>
270 306
             </el-form-item>
271 307
           </el-col>
272 308
         </el-row>
309
+        <el-form-item :label="dmT('formRemark')">
310
+          <span class="yor-view-text">{{ viewRow.remark || dash }}</span>
311
+        </el-form-item>
273 312
       </el-form>
274 313
       <div slot="footer" class="dialog-footer">
275 314
         <el-button
@@ -521,6 +560,12 @@ export default {
521 560
     selfConsumptionCountFields() {
522 561
       return COUNT_FIELDS.filter((field) => field.section === "selfConsumption")
523 562
     },
563
+    outboundTotalDisplay() {
564
+      return sumProps(this.form, OUTBOUND_TOTAL_PROPS)
565
+    },
566
+    selfConsumptionTotalDisplay() {
567
+      return sumProps(this.form, SELF_CONSUMPTION_TOTAL_PROPS)
568
+    },
524 569
     dialogTitle() {
525 570
       return this.dialogEdit ? this.dmT("dialogEdit") : this.dmT("dialogAdd")
526 571
     },