Selaa lähdekoodia

更新前端页面

xsh_1997 2 viikkoa sitten
vanhempi
commit
f57b862125

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

@@ -0,0 +1,108 @@
1
+# 可支配收入数据填报 — 前端技术方案
2
+
3
+> 依据:同目录 `可支配收入数据填报功能需求.md`、`可支配收入数据填报技术方案.md`;布局对齐存栏等填报页(双 `el-card` + 分页表格);字段 **小驼峰**。
4
+
5
+---
6
+
7
+## 1. 页面与路由
8
+
9
+| 项 | 说明 |
10
+| --- | --- |
11
+| **Vue 路径** | `ruoyi-ui/src/views/dataModel/disposableIncome/index.vue` |
12
+| **组件名** | `DisposableIncome` |
13
+| **菜单配置** | 组件路径:`dataModel/disposableIncome/index` |
14
+| **权限前缀** | `dataModel:disposableIncome:list\|query\|add\|edit\|remove` |
15
+
16
+无导入 / 导出按钮与接口。
17
+
18
+---
19
+
20
+## 2. API 模块
21
+
22
+| 项 | 说明 |
23
+| --- | --- |
24
+| **文件** | `ruoyi-ui/src/api/dataModel/disposableIncome.js` |
25
+| **Base** | `/dataModel/disposableIncome` |
26
+
27
+| 方法 | HTTP | 说明 |
28
+| --- | --- | --- |
29
+| `listDisposableIncome` | GET | `/list` 分页列表 |
30
+| `getDisposableIncome` | GET | `/{id}` 详情 |
31
+| `addDisposableIncome` | POST | `/` 新增 |
32
+| `updateDisposableIncome` | PUT | `/` 修改 |
33
+| `delDisposableIncome` | DELETE | `/{ids}` 删除 |
34
+| `listDisposableIncomeYearOptions` | GET | `/yearOptions`(当前年起向前 5 年共 6 个) |
35
+
36
+---
37
+
38
+## 3. 页面结构
39
+
40
+1. **筛选区**:所属年份;搜索、重置、新增。  
41
+2. **列表区**:所属年份、农村居民人均可支配收入、增幅、增速、脱贫人口人均纯收入、操作。  
42
+3. **操作列**:查看、修改、删除。  
43
+4. **新增/编辑弹窗**:年份、人均可支配收入、增幅(选填)、增速(选填)、人均纯收入、备注;新增年份默认本年。  
44
+5. **查看弹窗**:上述字段只读。
45
+
46
+---
47
+
48
+## 4. 业务规则(前端)
49
+
50
+| 规则 | 实现 |
51
+| --- | --- |
52
+| 年份选项 | `/yearOptions`;列表筛选可清空;进入页不默认年份 |
53
+| 必填 | `statYear`、`ruralDisposableIncome`、`povertyNetIncome`(≥0) |
54
+| 增幅 / 增速表单 | **普通 `el-input`**(非 `el-input-number`),支持空值;提交空 → 不传/后端按 `null` 补齐 |
55
+| 改年份或人均可支配收入 | 编辑态清空增幅、增速输入,与后端 `recalculateGrowth` 一致 |
56
+| 列表 / 详情展示 | `formatIncrease`:`null` → `0.00`;`formatGrowthRate`:`null` → `0.00%`,有值则按小数×100 显示百分比 |
57
+| 收入金额展示 | `formatMoney` → 两位小数;空值 `—` |
58
+| 唯一性 | 同年重复由后端拦截「该年份数据已存在」 |
59
+| 删除 | `$modal.confirm` 后物理删除 |
60
+
61
+### 4.1 字段映射
62
+
63
+| 界面 | 字段 |
64
+| --- | --- |
65
+| 所属年份 | `statYear` |
66
+| 农村居民人均可支配收入(元) | `ruralDisposableIncome` |
67
+| 增幅(元) | `incomeIncrease` |
68
+| 增速(小数,如 0.1228) | `incomeGrowthRate` |
69
+| 脱贫人口人均纯收入(元) | `povertyNetIncome` |
70
+| 备注 | `remark` |
71
+
72
+---
73
+
74
+## 5. 国际化
75
+
76
+| 项 | 说明 |
77
+| --- | --- |
78
+| **语言包** | `dataModel.disposableIncome`、`dataModel.common` |
79
+| **文件** | `lang/zh/dataModel.js`、`lang/bo/dataModel.js` |
80
+| **Mixin** | `dataModelLocaleMixin`,`dmNs = 'disposableIncome'` |
81
+
82
+---
83
+
84
+## 6. 联调说明
85
+
86
+1. 部署后端并执行 `sql/biz_disposable_income.sql`。  
87
+2. 菜单组件 `dataModel/disposableIncome/index`,权限见 §1。  
88
+3. 验证:新增默认本年;不填增幅增速时有上年则列表自动出现;改年份/可支配收入后重算;列表/详情 null 显示 `0.00` / `0.00%`;编辑回填时 null 保持空;无导入导出入口。
89
+
90
+---
91
+
92
+## 7. 文件清单
93
+
94
+| 类型 | 路径 |
95
+| --- | --- |
96
+| 页面 | `ruoyi-ui/src/views/dataModel/disposableIncome/index.vue` |
97
+| API | `ruoyi-ui/src/api/dataModel/disposableIncome.js` |
98
+| Mixin | `ruoyi-ui/src/mixins/dataModelLocaleMixin.js` |
99
+| i18n | `ruoyi-ui/src/lang/zh/dataModel.js`、`lang/bo/dataModel.js` |
100
+
101
+---
102
+
103
+## 8. 修订记录
104
+
105
+| 版本 | 说明 |
106
+| --- | --- |
107
+| 1.0 | 初版:县级年度 CRUD;增幅/增速选填;列表详情 null 显示为 0;无导入导出 |
108
+| 1.2 | 与需求对齐:改年份/可支配收入清空增幅增速;增速百分比展示 |

+ 129 - 0
doc/产业数据模型及服务/合作社发展数据填报/合作社发展数据填报前端技术方案.md

@@ -0,0 +1,129 @@
1
+# 合作社发展数据填报 — 前端技术方案
2
+
3
+> 依据:同目录 `合作社发展数据填报功能需求.md`、`合作社发展数据填报技术方案.md`;交互对齐存栏/出栏填报(双 `el-card` + 分页表格);字段 **小驼峰**。
4
+
5
+---
6
+
7
+## 1. 页面与路由
8
+
9
+| 项 | 说明 |
10
+| --- | --- |
11
+| **Vue 路径** | `ruoyi-ui/src/views/dataModel/cooperativeDevelopment/index.vue` |
12
+| **组件名** | `CooperativeDevelopment` |
13
+| **菜单配置** | 组件路径:`dataModel/cooperativeDevelopment/index` |
14
+| **权限前缀** | `dataModel:cooperativeDevelopment:list\|query\|add\|edit\|remove\|import\|export` |
15
+
16
+---
17
+
18
+## 2. API 模块
19
+
20
+| 项 | 说明 |
21
+| --- | --- |
22
+| **文件** | `ruoyi-ui/src/api/dataModel/cooperativeDevelopment.js` |
23
+| **Base** | `/dataModel/cooperativeDevelopment` |
24
+
25
+| 方法 | HTTP | 说明 |
26
+| --- | --- | --- |
27
+| `listCooperativeDevelopment` | GET | `/list` 分页列表 |
28
+| `getCooperativeDevelopment` | GET | `/{id}` 详情 |
29
+| `addCooperativeDevelopment` | POST | `/` 新增 |
30
+| `updateCooperativeDevelopment` | PUT | `/` 修改 |
31
+| `delCooperativeDevelopment` | DELETE | `/{ids}` 删除 |
32
+| `listCooperativeDevelopmentYearOptions` | GET | `/yearOptions` |
33
+| `listCooperativeDevelopmentMonthOptions` | GET | `/monthOptions` |
34
+| `listCooperativeDevelopmentTownOptions` | GET | `/townOptions` |
35
+| `listCooperativeDevelopmentVillageTree` | GET | `/villageTree` 县→乡镇→村 |
36
+| `importCooperativeDevelopment` | POST | `/importData`(`file` + `statYear` + `statMonth`) |
37
+| `exportCooperativeDevelopment` | GET | `/export`(`statYear` + `statMonth`,可选 `townDeptId`,`blob`) |
38
+| `downloadCooperativeDevelopmentTemplate` | GET | `/importTemplate`(`blob`) |
39
+
40
+模板下载与导出均用 **GET + `blob`**,勿用若依全局 `this.download()`(固定 POST)。
41
+
42
+---
43
+
44
+## 3. 页面结构
45
+
46
+1. **筛选区**:所属年份、所属月份、所属乡镇、所属村(可搜索)、合作社名称;搜索、重置、新增、导入、导出。  
47
+2. **列表区**(列顺序):所属年份、所属月份、所属村、所属乡镇、合作社名称、法定代表人、成立时间、注册资本、截止年底总资产、总收入、亏损、牛存栏、牛出栏、操作;空值展示 `—`。  
48
+3. **操作列**:查看、修改、删除。  
49
+4. **新增/编辑弹窗**:年份、月份、所属村、合作社名称(必填);分区录入见 §4;**牲畜入股小计**只读(牛入股+羊入股);新增默认当前年月。  
50
+5. **查看弹窗**:全部明细只读(含乡镇反推结果、牲畜入股小计、经营范围/模式/运营情况)。  
51
+6. **导入弹窗**:选填报年月(默认当前)→ 上传 `.xlsx` → `$alert` 展示 insert/update/fail/warn。  
52
+7. **导出弹窗**:选所属年月(默认当前)、可选所属乡镇(可清空;不选则全部)→ 下载 `{年}年{月}月合作社发展数据.xlsx`。
53
+
54
+---
55
+
56
+## 4. 业务规则(前端)
57
+
58
+| 规则 | 实现 |
59
+| --- | --- |
60
+| 年份 / 月份 | `/yearOptions`、`/monthOptions`;展示 `{month}月`;不可选未来月 |
61
+| 村选项 | `/villageTree` 拍平为「乡镇 / 村」下拉;`el-select` + `filterable` 支持搜索 |
62
+| 列表筛选 | `statYear`、`statMonth`、`townDeptId`、`villageDeptId`、`cooperativeName`;进入页不默认年月 |
63
+| 提交体 | 传 `villageDeptId`、合作社名称及明细;**不传**乡镇(后端反推) |
64
+| 唯一性 | 同年同月同村同合作社名称重复由后端拦截 |
65
+| 牲畜入股小计 | 前端只读展示 `cattleShareCount + sheepShareCount`;保存时以后端重算为准 |
66
+| 经营范围 | `el-checkbox-group` → 提交逗号分隔字符串(与后端枚举一致) |
67
+| 经营模式 / 运营情况 | `el-radio-group` 单选,取值与后端标签一致 |
68
+| 导入 | `FormData` 含年月;按唯一键 upsert,摘要含新增/更新条数 |
69
+| 导出 | 可选 `townDeptId`;导出文件不含合计行(后端保证) |
70
+| 删除 | `$modal.confirm` 后物理删除 |
71
+
72
+### 4.1 表单分区与字段
73
+
74
+| 分区 | 字段(小驼峰) |
75
+| --- | --- |
76
+| 基本信息 | `statYear`、`statMonth`、`villageDeptId`、`cooperativeName`、`legalRepresentative`、`establishDate`(`el-date-picker`,`yyyy-MM-dd`)、`registeredCapital`、`yearEndTotalAssets` |
77
+| 入社与入股 | `memberHouseholdCount`、`memberPopulationCount`、`povertyMonitorCount`、`cattleShareCount`、`sheepShareCount`、**`livestockShareTotal`(只读)**、`grasslandShareArea`、`laborShareCount`、`cashShareAmount`、`otherShareAmount` |
78
+| 效益情况 | `totalIncome`、`netIncome`、`cashDividend`、`inKindDividend`、`revolvingFund`、`lossAmount` |
79
+| 就业与存出栏 | `collegeGraduateCount`、`collegeGraduateWage`、`farmerTransferEmploymentCount`、`farmerTransferWage`、`cattleInventoryCount`、`cattleOutboundCount`、`sheepInventoryCount`、`sheepOutboundCount` |
80
+| 产品认证与培训 | `trademarkProductCount`、`qualityCertProductCount`、`trainingManageCount`、`trainingSkillCount`、`trainingOtherCount` |
81
+| 经营情况 | `businessScope`(多选)、`businessModel`(单选)、`operationStatus`(单选)、`remark` |
82
+
83
+### 4.2 枚举取值(与 Excel / 后端一致)
84
+
85
+| 类型 | 取值 |
86
+| --- | --- |
87
+| 主要经营范围 | 养殖业、种养结合、农产品加工、农机服务、劳务输出、建筑工程、旅游服务、运输、特色产品制作及销售、其他 |
88
+| 经营模式分类 | 整村合作社、股份合作社、联合合作社、多种经营合作社、公司型合作社、其它 |
89
+| 运营情况 | 规范、一般、差 |
90
+
91
+---
92
+
93
+## 5. 国际化
94
+
95
+| 项 | 说明 |
96
+| --- | --- |
97
+| **语言包** | `dataModel.cooperativeDevelopment`、`dataModel.common` |
98
+| **文件** | `lang/zh/dataModel.js`、`lang/bo/dataModel.js` |
99
+| **Mixin** | `dataModelLocaleMixin`,`dmNs = 'cooperativeDevelopment'` |
100
+
101
+文案键覆盖筛选/列表/表单分区/导入导出/校验提示;单位含户、人、头、个、万元、万亩。
102
+
103
+---
104
+
105
+## 6. 联调说明
106
+
107
+1. 部署后端并执行 `sql/biz_cooperative_development.sql`。  
108
+2. 菜单组件配置为 `dataModel/cooperativeDevelopment/index`,权限见 §1。  
109
+3. 验证:村下拉可搜索;新增只选村且乡镇回填;同年同月同村同名拦截;导入 upsert 摘要;导出可选乡镇且无合计行;详情含全部明细;汉藏切换。
110
+
111
+---
112
+
113
+## 7. 文件清单
114
+
115
+| 类型 | 路径 |
116
+| --- | --- |
117
+| 页面 | `ruoyi-ui/src/views/dataModel/cooperativeDevelopment/index.vue` |
118
+| API | `ruoyi-ui/src/api/dataModel/cooperativeDevelopment.js` |
119
+| Mixin | `ruoyi-ui/src/mixins/dataModelLocaleMixin.js` |
120
+| i18n | `ruoyi-ui/src/lang/zh/dataModel.js`、`lang/bo/dataModel.js` |
121
+
122
+---
123
+
124
+## 8. 修订记录
125
+
126
+| 版本 | 说明 |
127
+| --- | --- |
128
+| 1.0 | 初版:村×合作社×年月;列表/CRUD/详情/导入 upsert/导出可选乡镇;经营范围多选与模式/运营单选;汉藏 i18n |
129
+| 1.1 | 与实现对齐:村选项为拍平可搜索 `el-select`(非 Treeselect);牲畜入股小计表单只读展示 |

+ 81 - 0
doc/产业数据模型及服务/家庭牧场数据填报/家庭牧场数据填报前端技术方案.md

@@ -0,0 +1,81 @@
1
+# 家庭牧场数据填报 — 前端技术方案
2
+
3
+> 依据:同目录功能需求、技术方案;交互对齐出栏/合作社村级填报;字段 **小驼峰**。
4
+
5
+---
6
+
7
+## 1. 页面与路由
8
+
9
+| 项 | 说明 |
10
+| --- | --- |
11
+| **Vue 路径** | `ruoyi-ui/src/views/dataModel/familyRanch/index.vue` |
12
+| **组件名** | `FamilyRanch` |
13
+| **菜单配置** | 组件路径:`dataModel/familyRanch/index` |
14
+| **权限前缀** | `dataModel:familyRanch:list\|query\|add\|edit\|remove\|import\|export` |
15
+
16
+---
17
+
18
+## 2. API 模块
19
+
20
+| 项 | 说明 |
21
+| --- | --- |
22
+| **文件** | `ruoyi-ui/src/api/dataModel/familyRanch.js` |
23
+| **Base** | `/dataModel/familyRanch` |
24
+
25
+CRUD、`yearOptions` / `monthOptions` / `townOptions` / `villageTree`、导入 `importData`、模板 `importTemplate`、导出 `export`(可选 `townDeptId`)与畜牧产品产量模块同构;模板/导出均为 **GET + blob**。
26
+
27
+---
28
+
29
+## 3. 页面结构
30
+
31
+1. **筛选**:年、月、乡镇、企业名称(无村筛选,与需求一致)。  
32
+2. **列表**:年、月、乡镇、村、企业、法人、类型、注册资本、成立时间、牛存栏、牛出栏、草场面积(`grasslandAreaSubtotal`)、操作。  
33
+3. **新增/编辑**:选村(可搜索);企业类型默认「个体工商户」、销售渠道默认「其他」;成立时间 `el-date-picker`(`yyyy-MM-dd`);派生字段只读展示。  
34
+4. **详情**:全部字段含派生 + 乡镇只读。  
35
+5. **导入**:选年月 → upsert 摘要。  
36
+6. **导出**:选年月;所属乡镇与列表共用选项与文案,打开时带入列表当前乡镇,清空=全部。
37
+
38
+---
39
+
40
+## 4. 业务规则
41
+
42
+| 规则 | 实现 |
43
+| --- | --- |
44
+| 必填 | 年、月、村、企业名称 |
45
+| 提交 | 只传 `villageDeptId` 与录入项;乡镇与派生由后端计算 |
46
+| 前端只读派生 | 存栏小计、草场面积小计、利润、是否草畜平衡户(与后端公式一致,便于预览) |
47
+| 是/否 | `hasSubsidy` / `hasTrademark` / `hasQualityCert` 单选「是」「否」 |
48
+| 枚举 | 企业类型、销售渠道与后端 `FamilyRanchValidation` 一致 |
49
+
50
+---
51
+
52
+## 5. 国际化
53
+
54
+`dataModel.familyRanch`(`lang/zh|bo/dataModel.js`);`dmNs = 'familyRanch'`。
55
+
56
+---
57
+
58
+## 6. 联调说明
59
+
60
+1. 执行 `sql/biz_family_ranch.sql`。  
61
+2. 菜单组件 `dataModel/familyRanch/index`。  
62
+3. 验证:默认类型/渠道、派生只读、导出乡镇带入列表筛选、草畜失衡写入疾病预警(后端)。
63
+
64
+---
65
+
66
+## 7. 文件清单
67
+
68
+| 类型 | 路径 |
69
+| --- | --- |
70
+| 页面 | `ruoyi-ui/src/views/dataModel/familyRanch/index.vue` |
71
+| API | `ruoyi-ui/src/api/dataModel/familyRanch.js` |
72
+| i18n | `lang/zh/dataModel.js`、`lang/bo/dataModel.js` |
73
+
74
+---
75
+
76
+## 8. 修订记录
77
+
78
+| 版本 | 说明 |
79
+| --- | --- |
80
+| 1.0 | 初版:村×年月×企业;CRUD + 导入 upsert + 导出乡镇与列表联动 |
81
+| 1.1 | 成立时间日期组件;补助资金年份 `type=year`(`yyyy`);派生字段表单只读预览 |

+ 92 - 0
doc/产业数据模型及服务/畜牧产品产量登记/畜牧产品产量登记前端技术方案.md

@@ -0,0 +1,92 @@
1
+# 畜牧产品产量登记 — 前端技术方案
2
+
3
+> 依据:同目录功能需求、技术方案;交互对齐出栏/合作社村级填报;字段 **小驼峰**。
4
+
5
+---
6
+
7
+## 1. 页面与路由
8
+
9
+| 项 | 说明 |
10
+| --- | --- |
11
+| **Vue 路径** | `ruoyi-ui/src/views/dataModel/livestockProductOutput/index.vue` |
12
+| **组件名** | `LivestockProductOutput` |
13
+| **菜单配置** | 组件路径:`dataModel/livestockProductOutput/index` |
14
+| **权限前缀** | `dataModel:livestockProductOutput:list\|query\|add\|edit\|remove\|import\|export` |
15
+
16
+---
17
+
18
+## 2. API 模块
19
+
20
+| 项 | 说明 |
21
+| --- | --- |
22
+| **文件** | `ruoyi-ui/src/api/dataModel/livestockProductOutput.js` |
23
+| **Base** | `/dataModel/livestockProductOutput` |
24
+
25
+| 方法 | HTTP | 说明 |
26
+| --- | --- | --- |
27
+| `listLivestockProductOutput` | GET | `/list` |
28
+| `getLivestockProductOutput` | GET | `/{id}` |
29
+| `addLivestockProductOutput` | POST | `/` |
30
+| `updateLivestockProductOutput` | PUT | `/` |
31
+| `delLivestockProductOutput` | DELETE | `/{ids}` |
32
+| `listLivestockProductOutputYearOptions` | GET | `/yearOptions` |
33
+| `listLivestockProductOutputMonthOptions` | GET | `/monthOptions` |
34
+| `listLivestockProductOutputTownOptions` | GET | `/townOptions` |
35
+| `listLivestockProductOutputVillageTree` | GET | `/villageTree` |
36
+| `importLivestockProductOutput` | POST | `/importData`(`file` + 年月) |
37
+| `downloadLivestockProductOutputTemplate` | GET | `/importTemplate`(`blob`) |
38
+| `exportLivestockProductOutput` | GET | `/export`(年月,可选 `townDeptId`,`blob`) |
39
+
40
+---
41
+
42
+## 3. 页面结构
43
+
44
+1. **筛选**:年、月、乡镇、村(可搜索);搜索 / 重置 / 新增 / 导入 / 导出。  
45
+2. **列表**:年、月、乡镇、村、肉产量、奶产量、操作。  
46
+3. **新增/编辑**:年、月、村(必填);肉/奶产量(万吨,≥0);备注;新增默认本年本月;不选乡镇。  
47
+4. **详情**:全部字段 + 乡镇只读。  
48
+5. **导入**:选年月 → 上传 → upsert 摘要。  
49
+6. **导出**:选年月,可选乡镇;文件含合计行(后端)。
50
+
51
+---
52
+
53
+## 4. 业务规则
54
+
55
+| 规则 | 实现 |
56
+| --- | --- |
57
+| 村选项 | `/villageTree` 拍平为「乡镇 / 村」;`el-select` + `filterable` |
58
+| 提交 | 只传 `villageDeptId` 与产量;乡镇由后端反推 |
59
+| 唯一键 | 年+月+村,重复由后端拦截 |
60
+| 产量 | `meatOutput`、`milkOutput`,单位万吨,精度 4 位,可选非负 |
61
+
62
+---
63
+
64
+## 5. 国际化
65
+
66
+`dataModel.livestockProductOutput`(`lang/zh|bo/dataModel.js`);`dmNs = 'livestockProductOutput'`。
67
+
68
+---
69
+
70
+## 6. 联调说明
71
+
72
+1. 执行 `sql/biz_livestock_product_output.sql`。  
73
+2. 菜单组件 `dataModel/livestockProductOutput/index`。  
74
+3. 验证:村可搜索、CRUD、导入 upsert、导出含合计行。
75
+
76
+---
77
+
78
+## 7. 文件清单
79
+
80
+| 类型 | 路径 |
81
+| --- | --- |
82
+| 页面 | `ruoyi-ui/src/views/dataModel/livestockProductOutput/index.vue` |
83
+| API | `ruoyi-ui/src/api/dataModel/livestockProductOutput.js` |
84
+| i18n | `lang/zh/dataModel.js`、`lang/bo/dataModel.js` |
85
+
86
+---
87
+
88
+## 8. 修订记录
89
+
90
+| 版本 | 说明 |
91
+| --- | --- |
92
+| 1.0 | 初版:村×年月;CRUD + 导入 upsert + 导出可选乡镇 |

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

@@ -0,0 +1,120 @@
1
+import request from "@/utils/request"
2
+
3
+/** 分页列表 */
4
+export function listCooperativeDevelopment(query) {
5
+  return request({
6
+    url: "/dataModel/cooperativeDevelopment/list",
7
+    method: "get",
8
+    params: query
9
+  })
10
+}
11
+
12
+/** 详情 */
13
+export function getCooperativeDevelopment(id) {
14
+  return request({
15
+    url: "/dataModel/cooperativeDevelopment/" + id,
16
+    method: "get"
17
+  })
18
+}
19
+
20
+/** 新增 */
21
+export function addCooperativeDevelopment(data) {
22
+  return request({
23
+    url: "/dataModel/cooperativeDevelopment",
24
+    method: "post",
25
+    data
26
+  })
27
+}
28
+
29
+/** 修改 */
30
+export function updateCooperativeDevelopment(data) {
31
+  return request({
32
+    url: "/dataModel/cooperativeDevelopment",
33
+    method: "put",
34
+    data
35
+  })
36
+}
37
+
38
+/** 删除 */
39
+export function delCooperativeDevelopment(ids) {
40
+  return request({
41
+    url: "/dataModel/cooperativeDevelopment/" + ids,
42
+    method: "delete"
43
+  })
44
+}
45
+
46
+/** 可选年份 */
47
+export function listCooperativeDevelopmentYearOptions() {
48
+  return request({
49
+    url: "/dataModel/cooperativeDevelopment/yearOptions",
50
+    method: "get"
51
+  })
52
+}
53
+
54
+/** 可选月份(1~12) */
55
+export function listCooperativeDevelopmentMonthOptions() {
56
+  return request({
57
+    url: "/dataModel/cooperativeDevelopment/monthOptions",
58
+    method: "get"
59
+  })
60
+}
61
+
62
+/** 乡镇下拉 */
63
+export function listCooperativeDevelopmentTownOptions() {
64
+  return request({
65
+    url: "/dataModel/cooperativeDevelopment/townOptions",
66
+    method: "get"
67
+  })
68
+}
69
+
70
+/** 县→乡镇→村树 */
71
+export function listCooperativeDevelopmentVillageTree() {
72
+  return request({
73
+    url: "/dataModel/cooperativeDevelopment/villageTree",
74
+    method: "get"
75
+  })
76
+}
77
+
78
+/** Excel 导入 */
79
+export function importCooperativeDevelopment(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/cooperativeDevelopment/importData",
86
+    method: "post",
87
+    headers: {
88
+      repeatSubmit: false
89
+    },
90
+    data: formData
91
+  })
92
+}
93
+
94
+/** 下载导入模板(GET) */
95
+export function downloadCooperativeDevelopmentTemplate() {
96
+  return request({
97
+    url: "/dataModel/cooperativeDevelopment/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 exportCooperativeDevelopment(statYear, statMonth, townDeptId) {
110
+  const params = { statYear, statMonth }
111
+  if (townDeptId != null && townDeptId !== "") {
112
+    params.townDeptId = townDeptId
113
+  }
114
+  return request({
115
+    url: "/dataModel/cooperativeDevelopment/export",
116
+    method: "get",
117
+    params,
118
+    responseType: "blob"
119
+  })
120
+}

+ 52 - 0
ruoyi-ui/src/api/dataModel/disposableIncome.js

@@ -0,0 +1,52 @@
1
+import request from "@/utils/request"
2
+
3
+/** 分页列表 */
4
+export function listDisposableIncome(query) {
5
+  return request({
6
+    url: "/dataModel/disposableIncome/list",
7
+    method: "get",
8
+    params: query
9
+  })
10
+}
11
+
12
+/** 详情 */
13
+export function getDisposableIncome(id) {
14
+  return request({
15
+    url: "/dataModel/disposableIncome/" + id,
16
+    method: "get"
17
+  })
18
+}
19
+
20
+/** 新增 */
21
+export function addDisposableIncome(data) {
22
+  return request({
23
+    url: "/dataModel/disposableIncome",
24
+    method: "post",
25
+    data
26
+  })
27
+}
28
+
29
+/** 修改 */
30
+export function updateDisposableIncome(data) {
31
+  return request({
32
+    url: "/dataModel/disposableIncome",
33
+    method: "put",
34
+    data
35
+  })
36
+}
37
+
38
+/** 删除 */
39
+export function delDisposableIncome(ids) {
40
+  return request({
41
+    url: "/dataModel/disposableIncome/" + ids,
42
+    method: "delete"
43
+  })
44
+}
45
+
46
+/** 可选年份(当前年起向前 5 年) */
47
+export function listDisposableIncomeYearOptions() {
48
+  return request({
49
+    url: "/dataModel/disposableIncome/yearOptions",
50
+    method: "get"
51
+  })
52
+}

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

@@ -0,0 +1,120 @@
1
+import request from "@/utils/request"
2
+
3
+/** 分页列表 */
4
+export function listFamilyRanch(query) {
5
+  return request({
6
+    url: "/dataModel/familyRanch/list",
7
+    method: "get",
8
+    params: query
9
+  })
10
+}
11
+
12
+/** 详情 */
13
+export function getFamilyRanch(id) {
14
+  return request({
15
+    url: "/dataModel/familyRanch/" + id,
16
+    method: "get"
17
+  })
18
+}
19
+
20
+/** 新增 */
21
+export function addFamilyRanch(data) {
22
+  return request({
23
+    url: "/dataModel/familyRanch",
24
+    method: "post",
25
+    data
26
+  })
27
+}
28
+
29
+/** 修改 */
30
+export function updateFamilyRanch(data) {
31
+  return request({
32
+    url: "/dataModel/familyRanch",
33
+    method: "put",
34
+    data
35
+  })
36
+}
37
+
38
+/** 删除 */
39
+export function delFamilyRanch(ids) {
40
+  return request({
41
+    url: "/dataModel/familyRanch/" + ids,
42
+    method: "delete"
43
+  })
44
+}
45
+
46
+/** 可选年份 */
47
+export function listFamilyRanchYearOptions() {
48
+  return request({
49
+    url: "/dataModel/familyRanch/yearOptions",
50
+    method: "get"
51
+  })
52
+}
53
+
54
+/** 可选月份(1~12) */
55
+export function listFamilyRanchMonthOptions() {
56
+  return request({
57
+    url: "/dataModel/familyRanch/monthOptions",
58
+    method: "get"
59
+  })
60
+}
61
+
62
+/** 乡镇下拉 */
63
+export function listFamilyRanchTownOptions() {
64
+  return request({
65
+    url: "/dataModel/familyRanch/townOptions",
66
+    method: "get"
67
+  })
68
+}
69
+
70
+/** 县→乡镇→村树 */
71
+export function listFamilyRanchVillageTree() {
72
+  return request({
73
+    url: "/dataModel/familyRanch/villageTree",
74
+    method: "get"
75
+  })
76
+}
77
+
78
+/** Excel 导入 */
79
+export function importFamilyRanch(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/familyRanch/importData",
86
+    method: "post",
87
+    headers: {
88
+      repeatSubmit: false
89
+    },
90
+    data: formData
91
+  })
92
+}
93
+
94
+/** 下载导入模板(GET) */
95
+export function downloadFamilyRanchTemplate() {
96
+  return request({
97
+    url: "/dataModel/familyRanch/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 exportFamilyRanch(statYear, statMonth, townDeptId) {
110
+  const params = { statYear, statMonth }
111
+  if (townDeptId != null && townDeptId !== "") {
112
+    params.townDeptId = townDeptId
113
+  }
114
+  return request({
115
+    url: "/dataModel/familyRanch/export",
116
+    method: "get",
117
+    params,
118
+    responseType: "blob"
119
+  })
120
+}

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

@@ -0,0 +1,120 @@
1
+import request from "@/utils/request"
2
+
3
+/** 分页列表 */
4
+export function listLivestockProductOutput(query) {
5
+  return request({
6
+    url: "/dataModel/livestockProductOutput/list",
7
+    method: "get",
8
+    params: query
9
+  })
10
+}
11
+
12
+/** 详情 */
13
+export function getLivestockProductOutput(id) {
14
+  return request({
15
+    url: "/dataModel/livestockProductOutput/" + id,
16
+    method: "get"
17
+  })
18
+}
19
+
20
+/** 新增 */
21
+export function addLivestockProductOutput(data) {
22
+  return request({
23
+    url: "/dataModel/livestockProductOutput",
24
+    method: "post",
25
+    data
26
+  })
27
+}
28
+
29
+/** 修改 */
30
+export function updateLivestockProductOutput(data) {
31
+  return request({
32
+    url: "/dataModel/livestockProductOutput",
33
+    method: "put",
34
+    data
35
+  })
36
+}
37
+
38
+/** 删除 */
39
+export function delLivestockProductOutput(ids) {
40
+  return request({
41
+    url: "/dataModel/livestockProductOutput/" + ids,
42
+    method: "delete"
43
+  })
44
+}
45
+
46
+/** 可选年份 */
47
+export function listLivestockProductOutputYearOptions() {
48
+  return request({
49
+    url: "/dataModel/livestockProductOutput/yearOptions",
50
+    method: "get"
51
+  })
52
+}
53
+
54
+/** 可选月份(1~12) */
55
+export function listLivestockProductOutputMonthOptions() {
56
+  return request({
57
+    url: "/dataModel/livestockProductOutput/monthOptions",
58
+    method: "get"
59
+  })
60
+}
61
+
62
+/** 乡镇下拉 */
63
+export function listLivestockProductOutputTownOptions() {
64
+  return request({
65
+    url: "/dataModel/livestockProductOutput/townOptions",
66
+    method: "get"
67
+  })
68
+}
69
+
70
+/** 县→乡镇→村树 */
71
+export function listLivestockProductOutputVillageTree() {
72
+  return request({
73
+    url: "/dataModel/livestockProductOutput/villageTree",
74
+    method: "get"
75
+  })
76
+}
77
+
78
+/** Excel 导入 */
79
+export function importLivestockProductOutput(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/livestockProductOutput/importData",
86
+    method: "post",
87
+    headers: {
88
+      repeatSubmit: false
89
+    },
90
+    data: formData
91
+  })
92
+}
93
+
94
+/** 下载导入模板(GET) */
95
+export function downloadLivestockProductOutputTemplate() {
96
+  return request({
97
+    url: "/dataModel/livestockProductOutput/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 exportLivestockProductOutput(statYear, statMonth, townDeptId) {
110
+  const params = { statYear, statMonth }
111
+  if (townDeptId != null && townDeptId !== "") {
112
+    params.townDeptId = townDeptId
113
+  }
114
+  return request({
115
+    url: "/dataModel/livestockProductOutput/export",
116
+    method: "get",
117
+    params,
118
+    responseType: "blob"
119
+  })
120
+}

+ 20 - 3
ruoyi-ui/src/api/dataModel/yakHerdInventory.js

@@ -67,6 +67,14 @@ export function listYakHerdInventoryTownOptions() {
67 67
   })
68 68
 }
69 69
 
70
+/** 县→乡镇→村树(表单/筛选选村) */
71
+export function listYakHerdInventoryVillageTree() {
72
+  return request({
73
+    url: "/dataModel/yakHerdInventory/villageTree",
74
+    method: "get"
75
+  })
76
+}
77
+
70 78
 /** Excel 导入(multipart/form-data,file 为 el-upload 的 raw File) */
71 79
 export function importYakHerdInventory(file, statYear, statMonth) {
72 80
   const formData = new FormData()
@@ -92,12 +100,21 @@ export function downloadYakHerdInventoryTemplate() {
92 100
   })
93 101
 }
94 102
 
95
-/** 按年月导出(GET,后端 @GetMapping("/export")) */
96
-export function exportYakHerdInventory(statYear, statMonth) {
103
+/**
104
+ * 按年月导出(GET,后端 @GetMapping("/export"))
105
+ * @param {number} statYear
106
+ * @param {number} statMonth
107
+ * @param {number} [townDeptId] 可选乡镇
108
+ */
109
+export function exportYakHerdInventory(statYear, statMonth, townDeptId) {
110
+  const params = { statYear, statMonth }
111
+  if (townDeptId != null && townDeptId !== "") {
112
+    params.townDeptId = townDeptId
113
+  }
97 114
   return request({
98 115
     url: "/dataModel/yakHerdInventory/export",
99 116
     method: "get",
100
-    params: { statYear, statMonth },
117
+    params,
101 118
     responseType: "blob"
102 119
   })
103 120
 }

+ 21 - 4
ruoyi-ui/src/api/dataModel/yakOutboundReport.js

@@ -67,7 +67,15 @@ export function listYakOutboundReportTownOptions() {
67 67
   })
68 68
 }
69 69
 
70
-/** Excel 导入(multipart/form-data,file 为 el-upload 的 raw File) */
70
+/** 县→乡镇→村树 */
71
+export function listYakOutboundReportVillageTree() {
72
+  return request({
73
+    url: "/dataModel/yakOutboundReport/villageTree",
74
+    method: "get"
75
+  })
76
+}
77
+
78
+/** Excel 导入 */
71 79
 export function importYakOutboundReport(file, statYear, statMonth) {
72 80
   const formData = new FormData()
73 81
   formData.append("file", file, file.name)
@@ -92,12 +100,21 @@ export function downloadYakOutboundReportTemplate() {
92 100
   })
93 101
 }
94 102
 
95
-/** 按年月导出(GET) */
96
-export function exportYakOutboundReport(statYear, statMonth) {
103
+/**
104
+ * 按年月导出(GET)
105
+ * @param {number} statYear
106
+ * @param {number} statMonth
107
+ * @param {number} [townDeptId] 可选乡镇
108
+ */
109
+export function exportYakOutboundReport(statYear, statMonth, townDeptId) {
110
+  const params = { statYear, statMonth }
111
+  if (townDeptId != null && townDeptId !== "") {
112
+    params.townDeptId = townDeptId
113
+  }
97 114
   return request({
98 115
     url: "/dataModel/yakOutboundReport/export",
99 116
     method: "get",
100
-    params: { statYear, statMonth },
117
+    params,
101 118
     responseType: "blob"
102 119
   })
103 120
 }

+ 458 - 134
ruoyi-ui/src/lang/bo/dataModel.js

@@ -1,4 +1,4 @@
1
-/** 产业数据模型及体系 — 藏文 */
1
+/** ཐོན་ལས་གཞི་གྲངས་དཔེ་གཞི་དང་མ་ལག — བོད་ཡིག */
2 2
 export default {
3 3
   common: {
4 4
     search: "འཚོལ་བཤེར།",
@@ -275,145 +275,469 @@ export default {
275 275
     emptyList: "ཉེན་བརྡ་མེད།"
276 276
   },
277 277
   yakHerdInventory: {
278
-    queryStatYear: "ལོ་ཚད།",
279
-    queryStatMonth: "ཟླ་ཚད།",
280
-    queryTown: "ཤང་གྲོང་།",
281
-    colStatYear: "ལོ་ཚད།",
282
-    colStatMonth: "ཟླ་ཚད།",
283
-    colTownName: "ཤང་གྲོང་།",
278
+    queryStatYear: "གཏོགས་ལོ།",
279
+    queryStatMonth: "གཏོགས་ཟླ།",
280
+    queryTown: "ཤང་གྲོང།",
281
+    queryVillage: "གྲོང་ཚོ།",
282
+    colStatYear: "གཏོགས་ལོ།",
283
+    colStatMonth: "གཏོགས་ཟླ།",
284
+    colTownName: "ཤང་གྲོང།",
285
+    colVillageName: "གྲོང་ཚོ།",
284 286
     statMonthLabel: "{month}ཟླ།",
285 287
     colVillageCount: "གྲོང་ཚོ་གྲངས།",
286
-    colHerdsmanHouseholdCount: "འབྲོག་པ་ཁྱིམ་གྲངས།",
287
-    colYakTotal: "གནས་ཚད།",
288
-    colBullTotal: "ཕོ་བ་གནས་ཚད།",
289
-    colCowTotal: "མོ་བ་གནས་ཚད།",
290
-    formStatYear: "ལོ་ཚད།",
291
-    formStatMonth: "ཟླ་ཚད།",
292
-    formTown: "ཤང་གྲོང་།",
288
+    colHerdsmanHouseholdCount: "འབྲོག་ཁྱིམ་གྲངས།",
289
+    colYakTotal: "གནས་ཚད་གྲངས།",
290
+    colBullTotal: "གླང་གནས་ཚད།",
291
+    colCowTotal: "བ་མོ་གནས་ཚད།",
292
+    formStatYear: "གཏོགས་ལོ།",
293
+    formStatMonth: "གཏོགས་ཟླ།",
294
+    formTown: "ཤང་གྲོང།",
295
+    formVillage: "གྲོང་ཚོ།",
293 296
     formVillageCount: "གྲོང་ཚོ་གྲངས།",
294
-    formHerdsmanHouseholdCount: "འབྲོག་པ་ཁྱིམ་གྲངས།",
295
-    formYakTotal: "གཡག་གནས་ཚད།",
296
-    formBullTotal: "ཕོ་བ་གནས་ཚད།",
297
-    formCowTotal: "མོ་བ་གནས་ཚད།",
298
-    formBreedingBullCount: "རྒྱུད་ཕོ་བ།",
299
-    formBullCastratedCount: "ཕོ/སྤྱི་བ།",
300
-    formCowUnder1Count: "མོ 1 ལོ་མན།",
301
-    formCow13Count: "མོ 1-3 ལོ།",
302
-    formCow312Count: "མོ 3-12 ལོ།",
303
-    formCowOver12Count: "མོ 12 ལོ་ཡན།",
297
+    formHerdsmanHouseholdCount: "འབྲོག་ཁྱིམ་གྲངས།",
298
+    formBreedingBullCount: "ས་བོན་གླང་གནས་ཚད།",
299
+    formBullCastratedCount: "གླང་/རླིག་ཕྱུགས་གནས་ཚད།",
300
+    formCowYoungCount: "ལོ་0~1.5 ཕྲུ་གུ་གནས་ཚད།",
301
+    formCowAdultCount: "ལོ་1.5་ཡན་དར་ཕྱུགས་གནས་ཚད།",
302
+    formMilkingCowCount: "འོ་མ་བཞོ་བ་མོ་གནས་ཚད།",
303
+    formFertileCowCount: "འཕེལ་ནུས་བ་མོ་གནས་ཚད།",
304
+    formSheepTotal: "ལུག་སྤྱི་གནས་ཚད།",
305
+    formMilkingSheepCount: "འོ་མ་བཞོ་ལུག་གནས་ཚད།",
306
+    formInsuredYakCount: "འགན་བཅོལ་གཡག་གནས་ཚད།",
307
+    formBullTotal: "གླང་བསྡོམས།",
308
+    formCowTotal: "བ་མོ་བསྡོམས།",
309
+    formDairyTotal: "འོ་མ་བཞོ་བ་བསྡོམས།",
310
+    formYakTotal: "གཡག་སྤྱི་གནས་ཚད།",
311
+    formGrandTotal: "སྤྱི་བསྡོམས།",
312
+    formYakSheepTotal: "སྤྱི་ཚད(གཡག+ལུག)",
304 313
     formRemark: "ཟིན་བྲིས།",
305
-    phRemark: "འདེམས་ཆོག ཡིག་ཆ་500ལས་མི་ཆོག",
306
-    formVillageDeptId: "གྲོང་ཚོ ID(预留)",
307
-    formVillageName: "གྲོང་ཚོ(预留)",
308
-    sectionBasic: "གཞི་རྩའི་ཆ་འཕྲིན།",
309
-    sectionInventory: "གནས་ཚད་གྲངས་ཀ།",
310
-    sectionReserved: "预留",
314
+    phRemark: "འདེམས་འབྲི,ཡིག་ཆ་500ལས་མི་ཆོག",
315
+    sectionBasic: "གཞི་རྩའི་གནས་ཚུལ།",
316
+    sectionInventory: "གནས་ཚད་དཔྱད་གཞི།",
311 317
     btnImport: "ནང་འདྲེན།",
312
-    btnDownloadTemplate: "模板下载",
313
-    exportTitle: "Excel 导出",
314
-    exportStatYear: "所属年份",
315
-    exportStatYearPh: "请选择所属年份",
316
-    exportStatMonth: "所属月份",
317
-    exportStatMonthPh: "请选择所属月份",
318
-    exportStatYearRequired: "请选择所属年份",
319
-    exportStatMonthRequired: "请选择所属月份",
320
-    exportStatYearInvalid: "年月不在可选范围",
321
-    exportLoading: "正在导出...",
322
-    exportFail: "导出失败",
323
-    importTitle: "Excel 导入",
324
-    importStatYear: "填报年份",
325
-    importStatYearPh: "请选择年份",
326
-    importStatMonth: "填报月份",
327
-    importStatMonthPh: "请选择月份",
328
-    importTip: "先选年月再上传 .xlsx",
329
-    importLoading: "正在导入,请稍候...",
330
-    importSummary: "导入:新增 {insert} 更新 {update} 失败 {fail}",
331
-    importWarnTitle: "警告",
332
-    importFailTitle: "失败明细",
333
-    dialogAdd: "[新增]牦牛存栏",
334
-    dialogEdit: "[编辑]牦牛存栏",
335
-    confirmDelete: "是否删除?",
336
-    emptyList: "暂无数据",
337
-    unitGe: "个",
338
-    unitHousehold: "户",
339
-    unitHead: "头",
340
-    ruleStatYearRequired: "请选择年份",
341
-    ruleStatMonthRequired: "请选择月份",
342
-    ruleStatMonthFuture: "未来月份不可填",
343
-    ruleTownRequired: "请选择乡镇",
344
-    ruleCountRequired: "请填写",
345
-    ruleCountNonNegative: "≥0 整数",
346
-    viewCreateBy: "创建人",
347
-    viewUpdateBy: "修改人",
348
-    viewUpdateTime: "修改时间"
318
+    btnDownloadTemplate: "དཔེ་ཡིག་ཕབ་ལེན།",
319
+    exportTitle: "Excel ཕྱིར་འདྲེན།",
320
+    exportStatYear: "གཏོགས་ལོ།",
321
+    exportStatYearPh: "གཏོགས་ལོ་འདེམས་རོགས།",
322
+    exportStatMonth: "གཏོགས་ཟླ།",
323
+    exportStatMonthPh: "གཏོགས་ཟླ་འདེམས་རོགས།",
324
+    exportTown: "ཤང་གྲོང།",
325
+    exportTownPh: "མ་འདེམས་ན་ལོ་ཟླ་དེའི་ཤང་གྲོང་ཚང་མ་ཕྱིར་འདྲེན།",
326
+    exportStatYearRequired: "གཏོགས་ལོ་འདེམས་རོགས།",
327
+    exportStatMonthRequired: "གཏོགས་ཟླ་འདེམས་རོགས།",
328
+    exportStatYearInvalid: "ཕྱིར་འདྲེན་ལོ་ཟླ་འདེམས་ཁོངས་ནང་མེད།",
329
+    exportLoading: "ཕྱིར་འདྲེན་བཞིན... སྒུག་རོགས།",
330
+    exportFail: "ཕྱིར་འདྲེན་ཕམ།",
331
+    importTitle: "Excel ནང་འདྲེན།",
332
+    importStatYear: "འབྲི་ལོ།",
333
+    importStatYearPh: "འབྲི་ལོ་འདེམས་རོགས།",
334
+    importStatMonth: "འབྲི་ཟླ།",
335
+    importStatMonthPh: "འབྲི་ཟླ་འདེམས་རོགས།",
336
+    importTip: "སྔོན་ལ་འབྲི་ལོ་ཟླ་འདེམས,དེ་ནས་དཔེ་ཡིག་དང་མཐུན་པའི .xlsx ཡར་འཇུག;ལོ་ཟླ་གྲོང་ཚོ་གཅིག་པ་ཡོད་ན་རྩོམ་སྒྲིག",
337
+    importLoading: "ནང་འདྲེན་བཞིན... སྒུག་རོགས།",
338
+    importSummary: "ནང་འདྲེན་ཟིན:གསར་{insert} རྩོམ་{update} ཕམ་{fail}",
339
+    importWarnTitle: "ནང་འདྲེན་ཉེན་བརྡ།",
340
+    importFailTitle: "ནང་འདྲེན་ཕམ་ཞིབ།",
341
+    dialogAdd: "[གསར་སྣོན]གཡག་གནས་ཚད་གཞི་གྲངས།",
342
+    dialogEdit: "[རྩོམ་སྒྲིག]གཡག་གནས་ཚད་གཞི་གྲངས།",
343
+    confirmDelete: "ཐོ་གཞུང་འདི་སུབ་རྒྱུ་གཏན་ཁེལ་ལམ?",
344
+    emptyList: "འབྲི་གཞི་གྲངས་མེད།",
345
+    unitGe: "གྲངས།",
346
+    unitHousehold: "ཁྱིམ།",
347
+    unitHead: "ཨ།",
348
+    ruleStatYearRequired: "གཏོགས་ལོ་འདེམས་རོགས།",
349
+    ruleStatMonthRequired: "གཏོགས་ཟླ་འདེམས་རོགས།",
350
+    ruleStatMonthFuture: "མ་འོངས་ཟླ་འབྲི་མི་ཆོག",
351
+    ruleVillageRequired: "གྲོང་ཚོ་འདེམས་རོགས།",
352
+    ruleCountNonNegative: "0་ཡན་གྱི་ཧྲིལ་གྲངས་དགོས།",
353
+    villageTreeEmpty: "གྲོང་ཚོའི་སྒྲིག་འཛུགས་མ་ལོན,ལས་ཁུངས་ནང་「ཤང་གྲོང→གྲོང་ཚོ」ཡོད་མེད་ཞིབ་རོགས།",
354
+    viewCreateBy: "གསར་སྣོན་མཁན།",
355
+    viewUpdateBy: "རྩོམ་སྒྲིག་མཁན།",
356
+    viewUpdateTime: "རྩོམ་སྒྲིག་དུས་ཚོད།"
349 357
   },
350 358
   yakOutboundReport: {
351
-    queryStatYear: "所属年份",
352
-    queryStatMonth: "所属月份",
353
-    queryTown: "所属乡镇",
354
-    colStatYear: "所属年份",
355
-    colStatMonth: "所属月份",
356
-    statMonthLabel: "{month}月",
357
-    colTownName: "所属乡镇",
358
-    colFarmerHouseholdCount: "农牧户户数",
359
-    colFarmerPopulationCount: "农牧户人数",
360
-    colYakOutboundCount: "牦牛出栏数",
361
-    colSelfConsumptionCattle: "自食情况(牛)",
362
-    formStatYear: "所属年份",
363
-    formStatMonth: "所属月份",
364
-    formTown: "所属乡镇",
365
-    formFarmerHouseholdCount: "农牧户户数",
366
-    formFarmerPopulationCount: "农牧户人数",
367
-    formYakOutboundCount: "牦牛出栏数",
368
-    formCattleOutboundCount: "黄牛/奶牛/犏牛出栏数",
369
-    formSheepOutboundCount: "绵羊出栏数",
370
-    formGoatOutboundCount: "山羊出栏数",
371
-    formHorseMuleOutboundCount: "马骡出栏数",
372
-    formDonkeyOutboundCount: "驴出栏数",
373
-    formSelfConsumptionCattleCount: "自食牛头数",
374
-    formSelfConsumptionSheepCount: "自食绵羊只数",
375
-    formSelfConsumptionGoatCount: "自食山羊只数",
376
-    formRemark: "备注",
377
-    phRemark: "选填,不超过 500 字",
378
-    sectionBasic: "基本信息",
379
-    sectionFarmer: "农牧户情况",
380
-    sectionOutbound: "出栏情况",
381
-    sectionSelfConsumption: "自食情况",
382
-    btnImport: "导入",
383
-    btnDownloadTemplate: "模板下载",
384
-    exportTitle: "Excel 导出",
385
-    exportStatYear: "所属年份",
386
-    exportStatYearPh: "请选择所属年份",
387
-    exportStatMonth: "所属月份",
388
-    exportStatMonthPh: "请选择所属月份",
389
-    exportStatYearRequired: "请选择所属年份",
390
-    exportStatMonthRequired: "请选择所属月份",
391
-    exportStatYearInvalid: "导出年月不在可选范围",
392
-    exportLoading: "正在导出...",
393
-    exportFail: "导出失败",
394
-    importTitle: "Excel 导入",
395
-    importStatYear: "填报年份",
396
-    importStatYearPh: "请选择年份",
397
-    importStatMonth: "填报月份",
398
-    importStatMonthPh: "请选择月份",
399
-    importTip: "请先选择填报年月,再上传 .xlsx 文件",
400
-    importLoading: "正在导入...",
401
-    importSummary: "导入完成:新增 {insert} 条,更新 {update} 条,失败 {fail} 条",
402
-    importWarnTitle: "导入警告",
403
-    importFailTitle: "失败明细",
404
-    dialogAdd: "[新增]牦牛出栏",
405
-    dialogEdit: "[编辑]牦牛出栏",
406
-    confirmDelete: "是否删除?",
407
-    emptyList: "暂无数据",
408
-    unitHousehold: "户",
409
-    unitPerson: "人",
410
-    unitHead: "头",
411
-    unitSheep: "只",
412
-    unitHorse: "匹",
413
-    ruleStatYearRequired: "请选择年份",
414
-    ruleStatMonthRequired: "请选择月份",
415
-    ruleStatMonthFuture: "不可填报未来月份",
416
-    ruleTownRequired: "请选择乡镇",
417
-    ruleCountNonNegative: "≥0 整数"
359
+    queryStatYear: "གཏོགས་ལོ།",
360
+    queryStatMonth: "གཏོགས་ཟླ།",
361
+    queryTown: "ཤང་གྲོང།",
362
+    queryVillage: "གྲོང་ཚོ།",
363
+    colStatYear: "གཏོགས་ལོ།",
364
+    colStatMonth: "གཏོགས་ཟླ།",
365
+    statMonthLabel: "{month}ཟླ།",
366
+    colTownName: "ཤང་གྲོང།",
367
+    colVillageName: "གྲོང་ཚོ།",
368
+    colFarmerHouseholdCount: "ཞིང་འབྲོག་ཁྱིམ་གྲངས།",
369
+    colFarmerPopulationCount: "ཞིང་འབྲོག་མི་གྲངས།",
370
+    colYakOutboundCount: "གཡག་ཕྱིར་ཐོན་གྲངས།",
371
+    colOutboundTotal: "ཕྱུགས་སྤྱི་ཕྱིར་ཐོན།",
372
+    colSelfConsumptionCattle: "རང་ཟ་གླང་གྲངས།",
373
+    colSelfConsumptionTotal: "རང་ཟ་ཕྱུགས་སྤྱི།",
374
+    formStatYear: "གཏོགས་ལོ།",
375
+    formStatMonth: "གཏོགས་ཟླ།",
376
+    formTown: "ཤང་གྲོང།",
377
+    formVillage: "གྲོང་ཚོ།",
378
+    formFarmerHouseholdCount: "ཞིང་འབྲོག་ཁྱིམ་གྲངས།",
379
+    formFarmerPopulationCount: "ཞིང་འབྲོག་མི་གྲངས།",
380
+    formYakOutboundCount: "གཡག་ཕྱིར་ཐོན་གྲངས།",
381
+    formCattleOutboundCount: "གླང་དཀར་/འོ་མ་བཞོ/མཛོ་ཕྱིར་ཐོན།",
382
+    formSheepOutboundCount: "ལུག་ཕྱིར་ཐོན།",
383
+    formGoatOutboundCount: "ར་ཕྱིར་ཐོན།",
384
+    formHorseMuleOutboundCount: "རྟ་དྲེལ་ཕྱིར་ཐོན།",
385
+    formDonkeyOutboundCount: "བོང་བུ་ཕྱིར་ཐོན།",
386
+    formSelfConsumptionCattleCount: "རང་ཟ་གླང་གྲངས།",
387
+    formSelfConsumptionSheepCount: "རང་ཟ་ལུག་གྲངས།",
388
+    formSelfConsumptionGoatCount: "རང་ཟ་ར་གྲངས།",
389
+    formOutboundTotal: "ཕྱུགས་སྤྱི་ཕྱིར་ཐོན།",
390
+    formSelfConsumptionTotal: "རང་ཟ་ཕྱུགས་སྤྱི།",
391
+    formRemark: "ཟིན་བྲིས།",
392
+    phRemark: "འདེམས་འབྲི,ཡིག་ཆ་500ལས་མི་ཆོག",
393
+    sectionBasic: "གཞི་རྩའི་གནས་ཚུལ།",
394
+    sectionFarmer: "ཞིང་འབྲོག་ཁྱིམ་གནས་ཚུལ།",
395
+    sectionOutbound: "ཕྱིར་ཐོན་གནས་ཚུལ།",
396
+    sectionSelfConsumption: "རང་ཟ་གནས་ཚུལ།",
397
+    btnImport: "ནང་འདྲེན།",
398
+    btnDownloadTemplate: "དཔེ་ཡིག་ཕབ་ལེན།",
399
+    exportTitle: "Excel ཕྱིར་འདྲེན།",
400
+    exportStatYear: "གཏོགས་ལོ།",
401
+    exportStatYearPh: "གཏོགས་ལོ་འདེམས་རོགས།",
402
+    exportStatMonth: "གཏོགས་ཟླ།",
403
+    exportStatMonthPh: "གཏོགས་ཟླ་འདེམས་རོགས།",
404
+    exportTown: "ཤང་གྲོང།",
405
+    exportTownPh: "མ་འདེམས་ན་ལོ་ཟླ་དེའི་ཤང་གྲོང་ཚང་མ་ཕྱིར་འདྲེན།",
406
+    exportStatYearRequired: "གཏོགས་ལོ་འདེམས་རོགས།",
407
+    exportStatMonthRequired: "གཏོགས་ཟླ་འདེམས་རོགས།",
408
+    exportStatYearInvalid: "ཕྱིར་འདྲེན་ལོ་ཟླ་འདེམས་ཁོངས་ནང་མེད།",
409
+    exportLoading: "ཕྱིར་འདྲེན་བཞིན... སྒུག་རོགས།",
410
+    exportFail: "ཕྱིར་འདྲེན་ཕམ།",
411
+    importTitle: "Excel ནང་འདྲེན།",
412
+    importStatYear: "འབྲི་ལོ།",
413
+    importStatYearPh: "འབྲི་ལོ་འདེམས་རོགས།",
414
+    importStatMonth: "འབྲི་ཟླ།",
415
+    importStatMonthPh: "འབྲི་ཟླ་འདེམས་རོགས།",
416
+    importTip: "སྔོན་ལ་འབྲི་ལོ་ཟླ་འདེམས,དེ་ནས་དཔེ་ཡིག་དང་མཐུན་པའི .xlsx ཡར་འཇུག;ལོ་ཟླ་གྲོང་ཚོ་གཅིག་པ་ཡོད་ན་རྩོམ་སྒྲིག",
417
+    importLoading: "ནང་འདྲེན་བཞིན... སྒུག་རོགས།",
418
+    importSummary: "ནང་འདྲེན་ཟིན:གསར་{insert} རྩོམ་{update} ཕམ་{fail}",
419
+    importWarnTitle: "ནང་འདྲེན་ཉེན་བརྡ།",
420
+    importFailTitle: "ནང་འདྲེན་ཕམ་ཞིབ།",
421
+    dialogAdd: "[གསར་སྣོན]གཡག་ཕྱིར་ཐོན་གཞི་གྲངས།",
422
+    dialogEdit: "[རྩོམ་སྒྲིག]གཡག་ཕྱིར་ཐོན་གཞི་གྲངས།",
423
+    confirmDelete: "ཐོ་གཞུང་འདི་སུབ་རྒྱུ་གཏན་ཁེལ་ལམ?",
424
+    emptyList: "འབྲི་གཞི་གྲངས་མེད།",
425
+    unitHousehold: "ཁྱིམ།",
426
+    unitPerson: "མི།",
427
+    unitHead: "ཨ།",
428
+    unitSheep: "ཐོག",
429
+    unitHorse: "རྟ།",
430
+    ruleStatYearRequired: "གཏོགས་ལོ་འདེམས་རོགས།",
431
+    ruleStatMonthRequired: "གཏོགས་ཟླ་འདེམས་རོགས།",
432
+    ruleStatMonthFuture: "མ་འོངས་ཟླ་འབྲི་མི་ཆོག",
433
+    ruleVillageRequired: "གྲོང་ཚོ་འདེམས་རོགས།",
434
+    ruleCountNonNegative: "0་ཡན་གྱི་ཧྲིལ་གྲངས་དགོས།",
435
+    villageTreeEmpty: "གྲོང་ཚོའི་སྒྲིག་འཛུགས་མ་ལོན,ལས་ཁུངས་ནང་「ཤང་གྲོང→གྲོང་ཚོ」ཡོད་མེད་ཞིབ་རོགས།"
436
+  },
437
+  cooperativeDevelopment: {
438
+    queryStatYear: "གཏོགས་ལོ།",
439
+    queryStatMonth: "གཏོགས་ཟླ།",
440
+    queryTown: "ཤང་གྲོང།",
441
+    queryVillage: "གྲོང་ཚོ།",
442
+    queryCooperativeName: "མཉམ་ལས་ཁང་མིང་།",
443
+    phVillageSearch: "འདེམས་པའམ་འཚོལ་འཇུག་རོགས།",
444
+    phCooperativeName: "མཉམ་ལས་ཁང་མིང་འབྲི་རོགས།",
445
+    phEstablishDate: "དཔེར་ན་ 2020-01-01",
446
+    phRemark: "འདེམས་འབྲི,ཡིག་ཆ་500ལས་མི་ཆོག",
447
+    colStatYear: "གཏོགས་ལོ།",
448
+    colStatMonth: "གཏོགས་ཟླ།",
449
+    statMonthLabel: "{month}ཟླ།",
450
+    colVillageName: "གྲོང་ཚོ།",
451
+    colTownName: "ཤང་གྲོང།",
452
+    colCooperativeName: "མཉམ་ལས་ཁང་མིང་།",
453
+    colLegalRepresentative: "ཁྲིམས་མིའི་ངོ་ཚབ།",
454
+    colEstablishDate: "འཛུགས་དུས།",
455
+    colRegisteredCapital: "ཐོ་འགོད་མ་རྩ།",
456
+    colYearEndTotalAssets: "ལོ་མཇུག་རྒྱུ་ནོར་སྤྱི།",
457
+    colTotalIncome: "ཡོང་འབབ་སྤྱི།",
458
+    colLossAmount: "གྱོང་གུད།",
459
+    colCattleInventoryCount: "གླང་གནས་ཚད།",
460
+    colCattleOutboundCount: "གླང་ཕྱིར་ཐོན།",
461
+    formStatYear: "གཏོགས་ལོ།",
462
+    formStatMonth: "གཏོགས་ཟླ།",
463
+    formTown: "ཤང་གྲོང།",
464
+    formVillage: "གྲོང་ཚོ།",
465
+    formCooperativeName: "མཉམ་ལས་ཁང་མིང་།",
466
+    formLegalRepresentative: "ཁྲིམས་མིའི་ངོ་ཚབ།",
467
+    formEstablishDate: "འཛུགས་དུས།",
468
+    formRegisteredCapital: "ཐོ་འགོད་མ་རྩ།",
469
+    formYearEndTotalAssets: "ལོ་མཇུག་རྒྱུ་ནོར་སྤྱི།",
470
+    formMemberHouseholdCount: "ཞུགས་ཁྱིམ་གྲངས།",
471
+    formMemberPopulationCount: "ཞུགས་མི་གྲངས།",
472
+    formPovertyMonitorCount: "དབུལ་ལོག་སྔོན་འགོག་ལྟ་ཞིབ་མི་གྲངས།",
473
+    formCattleShareCount: "གླང་ཤ་སྒོར་གྲངས།",
474
+    formSheepShareCount: "ལུག་ཤ་སྒོར་གྲངས།",
475
+    formLivestockShareTotal: "ཕྱུགས་ཤ་སྒོར་ཆུང་བསྡོམས།",
476
+    formGrasslandShareArea: "རྩྭ་ཐང་ཤ་སྒོར།",
477
+    formLaborShareCount: "ངལ་རྩོལ་ཤ་སྒོར།",
478
+    formCashShareAmount: "དངུལ་ཤ་སྒོར།",
479
+    formOtherShareAmount: "གཞན་ཤ་སྒོར།",
480
+    formTotalIncome: "ཡོང་འབབ་སྤྱི།",
481
+    formNetIncome: "དག་ཡོང་།",
482
+    formCashDividend: "དངུལ་བགོ་བཤའ།",
483
+    formInKindDividend: "དངོས་པོ་བགོ་བཤའ་བརྩིས།",
484
+    formRevolvingFund: "འཁོར་དངུལ།",
485
+    formLossAmount: "གྱོང་གུད།",
486
+    formCollegeGraduateCount: "སློབ་ཆེན་མཐར་ཕྱིན་བསྡུ།",
487
+    formCollegeGraduateWage: "སློབ་ཆེན་གླ་ཕོགས་ཡོང་འབབ།",
488
+    formFarmerTransferEmploymentCount: "ཞིང་འབྲོག་པ་ལས་གནས་སྤོ།",
489
+    formFarmerTransferWage: "ཞིང་འབྲོག་པ་གླ་ཕོགས་ཡོང་འབབ།",
490
+    formCattleInventoryCount: "གླང་གནས་ཚད།",
491
+    formCattleOutboundCount: "གླང་ཕྱིར་ཐོན།",
492
+    formSheepInventoryCount: "ལུག་གནས་ཚད།",
493
+    formSheepOutboundCount: "ལུག་ཕྱིར་ཐོན།",
494
+    formTrademarkProductCount: "ཐོ་འགོད་ཐོབ་རྟགས་ཐོན་རྫས་གྲངས།",
495
+    formQualityCertProductCount: "སྤུས་ཚད་ངོས་འཛིན་ཐོན་རྫས་གྲངས།",
496
+    formTrainingManageCount: "སློབ་སྦྱོང-དོ་དམ་ནུས་པ།",
497
+    formTrainingSkillCount: "སློབ་སྦྱོང-ཆེད་ལས་ལག་རྩལ།",
498
+    formTrainingOtherCount: "སློབ་སྦྱོང-གཞན།",
499
+    formBusinessScope: "གཙོ་བོ་ཚོང་གཉེར་ཁྱབ་ཁོངས།",
500
+    formBusinessModel: "ཚོང་གཉེར་རྣམ་པ།",
501
+    formOperationStatus: "འཁོར་སྐྱོད་གནས་ཚུལ།",
502
+    formRemark: "ཟིན་བྲིས།",
503
+    sectionBasic: "གཞི་རྩའི་གནས་ཚུལ།",
504
+    sectionMemberShare: "ཞུགས་པ་དང་ཤ་སྒོར།",
505
+    sectionBenefit: "ཕན་འབྲས་གནས་ཚུལ།",
506
+    sectionEmploymentLivestock: "ལས་ཞུགས་དང་གནས་ཕྱིར་ཐོན།",
507
+    sectionProductTraining: "ཐོན་རྫས་ངོས་འཛིན་དང་སློབ་སྦྱོང།",
508
+    sectionOperation: "ཚོང་གཉེར་གནས་ཚུལ།",
509
+    btnImport: "ནང་འདྲེན།",
510
+    btnChooseFile: "ཡིག་ཆ་འདེམས།",
511
+    btnDownloadTemplate: "དཔེ་ཡིག་ཕབ་ལེན།",
512
+    exportTitle: "Excel ཕྱིར་འདྲེན།",
513
+    exportStatYear: "གཏོགས་ལོ།",
514
+    exportStatYearPh: "གཏོགས་ལོ་འདེམས་རོགས།",
515
+    exportStatMonth: "གཏོགས་ཟླ།",
516
+    exportStatMonthPh: "གཏོགས་ཟླ་འདེམས་རོགས།",
517
+    exportTown: "ཤང་གྲོང།",
518
+    exportTownPh: "མ་འདེམས་ན་ལོ་ཟླ་དེའི་ཤང་གྲོང་ཚང་མ་ཕྱིར་འདྲེན།",
519
+    exportStatYearRequired: "གཏོགས་ལོ་འདེམས་རོགས།",
520
+    exportStatMonthRequired: "གཏོགས་ཟླ་འདེམས་རོགས།",
521
+    exportStatYearInvalid: "ཕྱིར་འདྲེན་ལོ་ཟླ་འདེམས་ཁོངས་ནང་མེད།",
522
+    exportLoading: "ཕྱིར་འདྲེན་བཞིན... སྒུག་རོགས།",
523
+    exportFail: "ཕྱིར་འདྲེན་ཕམ།",
524
+    importTitle: "Excel ནང་འདྲེན།",
525
+    importStatYear: "འབྲི་ལོ།",
526
+    importStatYearPh: "འབྲི་ལོ་འདེམས་རོགས།",
527
+    importStatMonth: "འབྲི་ཟླ།",
528
+    importStatMonthPh: "འབྲི་ཟླ་འདེམས་རོགས།",
529
+    importTip: "སྔོན་ལ་འབྲི་ལོ་ཟླ་འདེམས,དེ་ནས་དཔེ་ཡིག་དང་མཐུན་པའི .xlsx ཡར་འཇུག;ལོ་ཟླ་གྲོང་ཚོ་མཉམ་ལས་ཁང་མིང་གཅིག་པ་ཡོད་ན་རྩོམ་སྒྲིག",
530
+    importLoading: "ནང་འདྲེན་བཞིན... སྒུག་རོགས།",
531
+    importSummary: "ནང་འདྲེན་ཟིན:གསར་{insert} རྩོམ་{update} ཕམ་{fail}",
532
+    importWarnTitle: "ནང་འདྲེན་ཉེན་བརྡ།",
533
+    importFailTitle: "ནང་འདྲེན་ཕམ་ཞིབ།",
534
+    dialogAdd: "[གསར་སྣོན]མཉམ་ལས་ཁང་འཕེལ་རྒྱས་གཞི་གྲངས།",
535
+    dialogEdit: "[རྩོམ་སྒྲིག]མཉམ་ལས་ཁང་འཕེལ་རྒྱས་གཞི་གྲངས།",
536
+    confirmDelete: "ཐོ་གཞུང་འདི་སུབ་རྒྱུ་གཏན་ཁེལ་ལམ?",
537
+    emptyList: "འབྲི་གཞི་གྲངས་མེད།",
538
+    unitHousehold: "ཁྱིམ།",
539
+    unitPerson: "མི།",
540
+    unitHead: "ཨ།",
541
+    unitGe: "གྲངས།",
542
+    unitWanYuan: "ཁྲི་སྒོར།",
543
+    unitWanMu: "ཁྲི་མུ།",
544
+    ruleStatYearRequired: "གཏོགས་ལོ་འདེམས་རོགས།",
545
+    ruleStatMonthRequired: "གཏོགས་ཟླ་འདེམས་རོགས།",
546
+    ruleStatMonthFuture: "མ་འོངས་ཟླ་འབྲི་མི་ཆོག",
547
+    ruleVillageRequired: "གྲོང་ཚོ་འདེམས་རོགས།",
548
+    ruleCooperativeNameRequired: "མཉམ་ལས་ཁང་མིང་འབྲི་རོགས།",
549
+    ruleCooperativeNameLen: "མཉམ་ལས་ཁང་མིང་ཡིག་ཆ་200ལས་མི་ཆོག",
550
+    ruleLegalRepLen: "ཁྲིམས་མིའི་ངོ་ཚབ་ཡིག་ཆ་64ལས་མི་ཆོག",
551
+    ruleEstablishDateLen: "འཛུགས་དུས་ཡིག་ཆ་32ལས་མི་ཆོག",
552
+    ruleCountNonNegative: "0་ཡན་གྱི་ཧྲིལ་གྲངས་དགོས།",
553
+    ruleDecimalNonNegative: "0་ཡན་གྱི་གྲངས་དགོས།",
554
+    villageTreeEmpty: "གྲོང་ཚོའི་སྒྲིག་འཛུགས་མ་ལོན,ལས་ཁུངས་ནང་「ཤང་གྲོང→གྲོང་ཚོ」ཡོད་མེད་ཞིབ་རོགས།"
555
+  },
556
+  disposableIncome: {
557
+    queryStatYear: "གཏོགས་ལོ།",
558
+    colStatYear: "གཏོགས་ལོ།",
559
+    colRuralDisposableIncome: "གྲོང་གསེབ་མི་དམངས་མི་རེའི་སྤྱོད་ཆོག་ཡོང་འབབ།",
560
+    colIncomeIncrease: "འཕར་ཚད།",
561
+    colIncomeGrowthRate: "འཕེལ་མྱུར།",
562
+    colPovertyNetIncome: "དབུལ་སྐྱོབ་མི་མང་མི་རེའི་དག་ཡོང་།",
563
+    formStatYear: "གཏོགས་ལོ།",
564
+    formRuralDisposableIncome: "གྲོང་གསེབ་མི་དམངས་མི་རེའི་སྤྱོད་ཆོག་ཡོང་འབབ།",
565
+    formIncomeIncrease: "འཕར་ཚད།",
566
+    formIncomeGrowthRate: "འཕེལ་མྱུར།",
567
+    formPovertyNetIncome: "དབུལ་སྐྱོབ་མི་མང་མི་རེའི་དག་ཡོང་།",
568
+    formRemark: "ཟིན་བྲིས།",
569
+    phIncomeIncrease: "འདེམས་འབྲི,སྒོར;མ་འབྲི་ན་སྔོན་ལོ་ལྟར་རང་རྩིས།",
570
+    phIncomeGrowthRate: "འདེམས་འབྲི,ཆ་ཤས་དཔེར་ན་ 0.1228;མ་འབྲི་ན་རང་རྩིས།",
571
+    phRemark: "འདེམས་འབྲི,ཡིག་ཆ་500ལས་མི་ཆོག",
572
+    dialogAdd: "[གསར་སྣོན]སྤྱོད་ཆོག་ཡོང་འབབ་གཞི་གྲངས།",
573
+    dialogEdit: "[རྩོམ་སྒྲིག]སྤྱོད་ཆོག་ཡོང་འབབ་གཞི་གྲངས།",
574
+    confirmDelete: "ཐོ་གཞུང་འདི་སུབ་རྒྱུ་གཏན་ཁེལ་ལམ?",
575
+    emptyList: "འབྲི་གཞི་གྲངས་མེད།",
576
+    unitYuan: "སྒོར།",
577
+    ruleStatYearRequired: "གཏོགས་ལོ་འདེམས་རོགས།",
578
+    ruleRuralIncomeRequired: "གྲོང་གསེབ་མི་དམངས་མི་རེའི་སྤྱོད་ཆོག་ཡོང་འབབ་འབྲི་རོགས།",
579
+    rulePovertyIncomeRequired: "དབུལ་སྐྱོབ་མི་མང་མི་རེའི་དག་ཡོང་འབྲི་རོགས།",
580
+    ruleMoneyNonNegative: "0་ཡན་གྱི་གྲངས་དགོས།",
581
+    ruleNumberInvalid: "ནུས་ལྡན་གྲངས་འབྲི་རོགས།"
582
+  },
583
+  livestockProductOutput: {
584
+    queryStatYear: "གཏོགས་ལོ།",
585
+    queryStatMonth: "གཏོགས་ཟླ།",
586
+    queryTown: "ཤང་གྲོང།",
587
+    queryVillage: "གྲོང་ཚོ།",
588
+    phVillageSearch: "འདེམས་པའམ་འཚོལ་འཇུག་རོགས།",
589
+    phRemark: "འདེམས་འབྲི,ཡིག་ཆ་500ལས་མི་ཆོག",
590
+    colStatYear: "གཏོགས་ལོ།",
591
+    colStatMonth: "གཏོགས་ཟླ།",
592
+    statMonthLabel: "{month}ཟླ།",
593
+    colTownName: "ཤང་གྲོང།",
594
+    colVillageName: "གྲོང་ཚོ།",
595
+    colMeatOutput: "ཤ་ཐོན་ཚད།",
596
+    colMilkOutput: "འོ་མ་ཐོན་ཚད།",
597
+    formStatYear: "གཏོགས་ལོ།",
598
+    formStatMonth: "གཏོགས་ཟླ།",
599
+    formTown: "ཤང་གྲོང།",
600
+    formVillage: "གྲོང་ཚོ།",
601
+    formMeatOutput: "ཤ་ཐོན་ཚད།",
602
+    formMilkOutput: "འོ་མ་ཐོན་ཚད།",
603
+    formRemark: "ཟིན་བྲིས།",
604
+    btnImport: "ནང་འདྲེན།",
605
+    btnDownloadTemplate: "དཔེ་ཡིག་ཕབ་ལེན།",
606
+    exportTitle: "Excel ཕྱིར་འདྲེན།",
607
+    exportStatYear: "གཏོགས་ལོ།",
608
+    exportStatYearPh: "གཏོགས་ལོ་འདེམས་རོགས།",
609
+    exportStatMonth: "གཏོགས་ཟླ།",
610
+    exportStatMonthPh: "གཏོགས་ཟླ་འདེམས་རོགས།",
611
+    exportTown: "ཤང་གྲོང།",
612
+    exportTownPh: "མ་འདེམས་ན་ལོ་ཟླ་དེའི་ཤང་གྲོང་ཚང་མ་ཕྱིར་འདྲེན།",
613
+    exportStatYearRequired: "གཏོགས་ལོ་འདེམས་རོགས།",
614
+    exportStatMonthRequired: "གཏོགས་ཟླ་འདེམས་རོགས།",
615
+    exportStatYearInvalid: "ཕྱིར་འདྲེན་ལོ་ཟླ་འདེམས་ཁོངས་ནང་མེད།",
616
+    exportLoading: "ཕྱིར་འདྲེན་བཞིན... སྒུག་རོགས།",
617
+    exportFail: "ཕྱིར་འདྲེན་ཕམ།",
618
+    importTitle: "Excel ནང་འདྲེན།",
619
+    importStatYear: "འབྲི་ལོ།",
620
+    importStatYearPh: "འབྲི་ལོ་འདེམས་རོགས།",
621
+    importStatMonth: "འབྲི་ཟླ།",
622
+    importStatMonthPh: "འབྲི་ཟླ་འདེམས་རོགས།",
623
+    importTip: "སྔོན་ལ་འབྲི་ལོ་ཟླ་འདེམས,དེ་ནས་དཔེ་ཡིག་དང་མཐུན་པའི .xlsx ཡར་འཇུག;ལོ་ཟླ་གྲོང་ཚོ་གཅིག་པ་ཡོད་ན་རྩོམ་སྒྲིག",
624
+    importLoading: "ནང་འདྲེན་བཞིན... སྒུག་རོགས།",
625
+    importSummary: "ནང་འདྲེན་ཟིན:གསར་{insert} རྩོམ་{update} ཕམ་{fail}",
626
+    importWarnTitle: "ནང་འདྲེན་ཉེན་བརྡ།",
627
+    importFailTitle: "ནང་འདྲེན་ཕམ་ཞིབ།",
628
+    dialogAdd: "[གསར་སྣོན]ཕྱུགས་ལས་ཐོན་རྫས་ཐོན་ཚད།",
629
+    dialogEdit: "[རྩོམ་སྒྲིག]ཕྱུགས་ལས་ཐོན་རྫས་ཐོན་ཚད།",
630
+    confirmDelete: "ཐོ་གཞུང་འདི་སུབ་རྒྱུ་གཏན་ཁེལ་ལམ?",
631
+    emptyList: "ཐོ་འགོད་གཞི་གྲངས་མེད།",
632
+    unitWanTon: "ཁྲི་ཏུན།",
633
+    ruleStatYearRequired: "གཏོགས་ལོ་འདེམས་རོགས།",
634
+    ruleStatMonthRequired: "གཏོགས་ཟླ་འདེམས་རོགས།",
635
+    ruleStatMonthFuture: "མ་འོངས་ཟླ་འབྲི་མི་ཆོག",
636
+    ruleVillageRequired: "གྲོང་ཚོ་འདེམས་རོགས།",
637
+    ruleDecimalNonNegative: "0་ཡན་གྱི་གྲངས་དགོས།",
638
+    villageTreeEmpty: "གྲོང་ཚོའི་སྒྲིག་འཛུགས་མ་ལོན,ལས་ཁུངས་ནང་「ཤང་གྲོང→གྲོང་ཚོ」ཡོད་མེད་ཞིབ་རོགས།"
639
+  },
640
+  familyRanch: {
641
+    queryStatYear: "གཏོགས་ལོ།",
642
+    queryStatMonth: "གཏོགས་ཟླ།",
643
+    queryTown: "ཤང་གྲོང།",
644
+    queryEnterpriseName: "ཁེ་ལས་མིང་།",
645
+    phVillageSearch: "འདེམས་པའམ་འཚོལ་འཇུག་རོགས།",
646
+    phEnterpriseName: "ཁེ་ལས་མིང་འབྲི་རོགས།",
647
+    phRemark: "འདེམས་འབྲི,ཡིག་ཆ་500ལས་མི་ཆོག",
648
+    colStatYear: "གཏོགས་ལོ།",
649
+    colStatMonth: "གཏོགས་ཟླ།",
650
+    statMonthLabel: "{month}ཟླ།",
651
+    colTownName: "ཤང་གྲོང།",
652
+    colVillageName: "གྲོང་ཚོ།",
653
+    colEnterpriseName: "ཁེ་ལས་མིང་།",
654
+    colLegalRepresentative: "ཁྲིམས་མིའི་ངོ་ཚབ།",
655
+    colEnterpriseType: "ཁེ་ལས་རིགས།",
656
+    colRegisteredCapital: "ཐོ་འགོད་མ་རྩ།",
657
+    colEstablishDate: "འཛུགས་དུས།",
658
+    colCattleYearEndStock: "གླང་གནས་ཚད།",
659
+    colCattleOutbound: "གླང་ཕྱིར་ཐོན།",
660
+    colGrasslandArea: "རྩྭ་ཐང་རྒྱ་ཁྱོན།",
661
+    formStatYear: "གཏོགས་ལོ།",
662
+    formStatMonth: "གཏོགས་ཟླ།",
663
+    formTown: "ཤང་གྲོང།",
664
+    formVillage: "གྲོང་ཚོ།",
665
+    formEnterpriseName: "ཁེ་ལས་མིང་།",
666
+    formLegalRepresentative: "ཁྲིམས་མིའི་ངོ་ཚབ།",
667
+    formEnterpriseType: "ཁེ་ལས་རིགས།",
668
+    formRegisteredCapital: "ཐོ་འགོད་མ་རྩ།",
669
+    formEstablishDate: "འཛུགས་དུས།",
670
+    formLivestockLaborCount: "ཕྱུགས་ལས་ངལ་རྩོལ་མི་སྣ།",
671
+    formCattleYearEndStock: "གླང་ལོ་མཇུག་གནས་ཚད།",
672
+    formCattleBreedingFemaleStock: "གླང་འཕེལ་ནུས་མོ་ཕྱུགས།",
673
+    formSheepYearEndStock: "ལུག་ལོ་མཇུག་གནས་ཚད།",
674
+    formSheepBreedingFemaleStock: "ལུག་འཕེལ་ནུས་མོ་ཕྱུགས།",
675
+    formCattleOutbound: "གླང་ཕྱིར་ཐོན།",
676
+    formSheepOutbound: "ལུག་ཕྱིར་ཐོན།",
677
+    formStockSubtotal: "ལོ་མཇུག་ཕྱུགས་གནས་ཚད་ཆུང་བསྡོམས།",
678
+    formGrassBalanceArea: "རྩྭ་ཕྱུགས་སྙོམས་རྒྱ་ཁྱོན།",
679
+    formTransferGrassArea: "བརྗེ་སྤོ་ཚོང་གཉེར་རྩྭ་ས་རྒྱ་ཁྱོན།",
680
+    formGrasslandAreaSubtotal: "རྩྭ་ཐང་རྒྱ་ཁྱོན་ཆུང་བསྡོམས།",
681
+    formApprovedCarryingCapacity: "གཏན་འཁེལ་ལོ་མཇུག་རྩྭ་ཕྱུགས་སྙོམས་ཁུར་ཚད།",
682
+    formYearEndStockSheepUnit: "ལོ་མཇུག་ཕྱུགས་གནས་ཚད།",
683
+    formIsGrassBalanced: "རྩྭ་ཕྱུགས་སྙོམས་ཁྱིམ་ཡིན་ནམ།",
684
+    formIncome: "ལོ་རེའི་ཚོང་གཉེར་ཡོང་འབབ་སྤྱི།",
685
+    formExpense: "ལོ་རེའི་ཚོང་གཉེར་འགྲོ་སོང་སྤྱི།",
686
+    formProfit: "ཁེ་བཟང་།",
687
+    formSubsidyYear: "རོགས་དངུལ་ལོ།",
688
+    formHasSubsidy: "རོགས་དངུལ་ཐོབ་ཡོད་དམ།",
689
+    formSubsidyAmount: "རོགས་དངུལ།",
690
+    formHasTrademark: "ཐོ་འགོད་ཐོབ་རྟགས་ཡོད་དམ།",
691
+    formHasQualityCert: "ཞིང་ཐོན་སྤུས་ཚད་ངོས་འཛིན་བརྒྱུད་ཡོད་དམ།",
692
+    formSalesChannel: "ཐོན་རྫས་བཙོང་ལམ།",
693
+    formDrivenPopulation: "སྐུལ་འདེད་མི་གྲངས།",
694
+    formWagePaid: "གླ་ཕོགས་སྤྲོད།",
695
+    formRemark: "ཟིན་བྲིས།",
696
+    sectionBasic: "གཞི་རྩའི་གནས་ཚུལ།",
697
+    sectionStock: "གནས་ཚད་དང་ཕྱིར་ཐོན།",
698
+    sectionGrassland: "རྩྭ་ཐང་དང་རྩྭ་ཕྱུགས་སྙོམས།",
699
+    sectionFinance: "ཚོང་གཉེར་དང་རོགས་དངུལ།",
700
+    sectionOther: "གཞན།",
701
+    btnImport: "ནང་འདྲེན།",
702
+    btnDownloadTemplate: "དཔེ་ཡིག་ཕབ་ལེན།",
703
+    exportTitle: "Excel ཕྱིར་འདྲེན།",
704
+    exportStatYear: "གཏོགས་ལོ།",
705
+    exportStatYearPh: "གཏོགས་ལོ་འདེམས་རོགས།",
706
+    exportStatMonth: "གཏོགས་ཟླ།",
707
+    exportStatMonthPh: "གཏོགས་ཟླ་འདེམས་རོགས།",
708
+    exportStatYearRequired: "གཏོགས་ལོ་འདེམས་རོགས།",
709
+    exportStatMonthRequired: "གཏོགས་ཟླ་འདེམས་རོགས།",
710
+    exportStatYearInvalid: "ཕྱིར་འདྲེན་ལོ་ཟླ་འདེམས་ཁོངས་ནང་མེད།",
711
+    exportLoading: "ཕྱིར་འདྲེན་བཞིན... སྒུག་རོགས།",
712
+    exportFail: "ཕྱིར་འདྲེན་ཕམ།",
713
+    importTitle: "Excel ནང་འདྲེན།",
714
+    importStatYear: "འབྲི་ལོ།",
715
+    importStatYearPh: "འབྲི་ལོ་འདེམས་རོགས།",
716
+    importStatMonth: "འབྲི་ཟླ།",
717
+    importStatMonthPh: "འབྲི་ཟླ་འདེམས་རོགས།",
718
+    importTip: "སྔོན་ལ་འབྲི་ལོ་ཟླ་འདེམས,དེ་ནས་དཔེ་ཡིག་དང་མཐུན་པའི .xlsx ཡར་འཇུག;ལོ་ཟླ་གྲོང་ཚོ་ཁེ་ལས་མིང་གཅིག་པ་ཡོད་ན་རྩོམ་སྒྲིག",
719
+    importLoading: "ནང་འདྲེན་བཞིན... སྒུག་རོགས།",
720
+    importSummary: "ནང་འདྲེན་ཟིན:གསར་{insert} རྩོམ་{update} ཕམ་{fail}",
721
+    importWarnTitle: "ནང་འདྲེན་ཉེན་བརྡ།",
722
+    importFailTitle: "ནང་འདྲེན་ཕམ་ཞིབ།",
723
+    dialogAdd: "[གསར་སྣོན]ཁྱིམ་ཚང་འབྲོག་ར་གཞི་གྲངས།",
724
+    dialogEdit: "[རྩོམ་སྒྲིག]ཁྱིམ་ཚང་འབྲོག་ར་གཞི་གྲངས།",
725
+    confirmDelete: "ཐོ་གཞུང་འདི་སུབ་རྒྱུ་གཏན་ཁེལ་ལམ?",
726
+    emptyList: "འབྲི་གཞི་གྲངས་མེད།",
727
+    unitPerson: "མི།",
728
+    unitHead: "ཨ།",
729
+    unitMu: "མུ།",
730
+    unitWanYuan: "ཁྲི་སྒོར།",
731
+    unitSheepUnit: "ལུག་རིམ།",
732
+    ruleStatYearRequired: "གཏོགས་ལོ་འདེམས་རོགས།",
733
+    ruleStatMonthRequired: "གཏོགས་ཟླ་འདེམས་རོགས།",
734
+    ruleStatMonthFuture: "མ་འོངས་ཟླ་འབྲི་མི་ཆོག",
735
+    ruleVillageRequired: "གྲོང་ཚོ་འདེམས་རོགས།",
736
+    ruleEnterpriseNameRequired: "ཁེ་ལས་མིང་འབྲི་རོགས།",
737
+    ruleEnterpriseNameLen: "ཁེ་ལས་མིང་ཡིག་ཆ་200ལས་མི་ཆོག",
738
+    ruleLegalRepLen: "ཁྲིམས་མིའི་ངོ་ཚབ་ཡིག་ཆ་64ལས་མི་ཆོག",
739
+    ruleCountNonNegative: "0་ཡན་གྱི་ཧྲིལ་གྲངས་དགོས།",
740
+    ruleDecimalNonNegative: "0་ཡན་གྱི་གྲངས་དགོས།",
741
+    villageTreeEmpty: "གྲོང་ཚོའི་སྒྲིག་འཛུགས་མ་ལོན,ལས་ཁུངས་ནང་「ཤང་གྲོང→གྲོང་ཚོ」ཡོད་མེད་ཞིབ་རོགས།"
418 742
   }
419 743
 }

+ 349 - 25
ruoyi-ui/src/lang/zh/dataModel.js

@@ -278,9 +278,11 @@ export default {
278 278
     queryStatYear: "所属年份",
279 279
     queryStatMonth: "所属月份",
280 280
     queryTown: "所属乡镇",
281
+    queryVillage: "所属村",
281 282
     colStatYear: "所属年份",
282 283
     colStatMonth: "所属月份",
283
-    colTownName: "乡镇",
284
+    colTownName: "所属乡镇",
285
+    colVillageName: "所属村",
284 286
     statMonthLabel: "{month}月",
285 287
     colVillageCount: "村居数",
286 288
     colHerdsmanHouseholdCount: "牧户数",
@@ -290,24 +292,28 @@ export default {
290 292
     formStatYear: "所属年份",
291 293
     formStatMonth: "所属月份",
292 294
     formTown: "所属乡镇",
295
+    formVillage: "所属村",
293 296
     formVillageCount: "村居数",
294 297
     formHerdsmanHouseholdCount: "牧户数",
295
-    formYakTotal: "牦牛存栏数",
296
-    formBullTotal: "公牛存栏数",
297
-    formCowTotal: "母牛存栏数",
298 298
     formBreedingBullCount: "种公牛存栏数",
299 299
     formBullCastratedCount: "公牛/阉畜存栏数",
300
-    formCowUnder1Count: "1岁以下母牛存栏数",
301
-    formCow13Count: "1~3岁母牛存栏数",
302
-    formCow312Count: "3~12岁母牛存栏数",
303
-    formCowOver12Count: "12岁以上母牛存栏数",
300
+    formCowYoungCount: "0~1.5岁幼畜存栏数",
301
+    formCowAdultCount: "1.5岁以上成畜存栏数",
302
+    formMilkingCowCount: "产奶母牛存栏数",
303
+    formFertileCowCount: "能繁母牛存栏数",
304
+    formSheepTotal: "羊总存栏数",
305
+    formMilkingSheepCount: "产奶羊存栏数",
306
+    formInsuredYakCount: "保险牦牛存栏数",
307
+    formBullTotal: "公牛合计",
308
+    formCowTotal: "母牛合计",
309
+    formDairyTotal: "奶牛合计",
310
+    formYakTotal: "牦牛总存栏",
311
+    formGrandTotal: "总合计",
312
+    formYakSheepTotal: "总量(牦牛+羊)",
304 313
     formRemark: "备注",
305 314
     phRemark: "选填,不超过 500 字",
306
-    formVillageDeptId: "所属村居ID(预留)",
307
-    formVillageName: "所属村居(预留)",
308 315
     sectionBasic: "基本信息",
309 316
     sectionInventory: "存栏指标",
310
-    sectionReserved: "预留字段",
311 317
     btnImport: "导入",
312 318
     btnDownloadTemplate: "下载模板",
313 319
     exportTitle: "Excel 导出",
@@ -315,6 +321,8 @@ export default {
315 321
     exportStatYearPh: "请选择所属年份",
316 322
     exportStatMonth: "所属月份",
317 323
     exportStatMonthPh: "请选择所属月份",
324
+    exportTown: "所属乡镇",
325
+    exportTownPh: "不选则导出该年月全部乡镇",
318 326
     exportStatYearRequired: "请选择所属年份",
319 327
     exportStatMonthRequired: "请选择所属月份",
320 328
     exportStatYearInvalid: "导出年月不在可选范围内",
@@ -325,7 +333,7 @@ export default {
325 333
     importStatYearPh: "请选择填报年份",
326 334
     importStatMonth: "填报月份",
327 335
     importStatMonthPh: "请选择填报月份",
328
-    importTip: "请先选择填报年月,再上传与模板格式一致的 .xlsx 文件",
336
+    importTip: "请先选择填报年月,再上传与模板格式一致的 .xlsx 文件;同年同月同村已存在则更新",
329 337
     importLoading: "正在导入,请稍候...",
330 338
     importSummary: "导入完成:新增 {insert} 条,更新 {update} 条,失败 {fail} 条",
331 339
     importWarnTitle: "导入警告",
@@ -340,9 +348,9 @@ export default {
340 348
     ruleStatYearRequired: "请选择所属年份",
341 349
     ruleStatMonthRequired: "请选择所属月份",
342 350
     ruleStatMonthFuture: "不可填报未来月份",
343
-    ruleTownRequired: "请选择所属乡镇",
344
-    ruleCountRequired: "请填写该项",
351
+    ruleVillageRequired: "请选择所属村",
345 352
     ruleCountNonNegative: "须为大于等于 0 的整数",
353
+    villageTreeEmpty: "未加载到村级组织数据,请确认系统部门已维护「乡镇→村」",
346 354
     viewCreateBy: "创建人",
347 355
     viewUpdateBy: "修改人",
348 356
     viewUpdateTime: "修改时间"
@@ -351,28 +359,35 @@ export default {
351 359
     queryStatYear: "所属年份",
352 360
     queryStatMonth: "所属月份",
353 361
     queryTown: "所属乡镇",
362
+    queryVillage: "所属村",
354 363
     colStatYear: "所属年份",
355 364
     colStatMonth: "所属月份",
356 365
     statMonthLabel: "{month}月",
357 366
     colTownName: "所属乡镇",
358
-    colFarmerHouseholdCount: "农牧户户数",
359
-    colFarmerPopulationCount: "农牧户人数",
367
+    colVillageName: "所属村",
368
+    colFarmerHouseholdCount: "农牧户数",
369
+    colFarmerPopulationCount: "农牧人数",
360 370
     colYakOutboundCount: "牦牛出栏数",
361
-    colSelfConsumptionCattle: "自食情况(牛)",
371
+    colOutboundTotal: "牲畜总出栏数",
372
+    colSelfConsumptionCattle: "自食牛数",
373
+    colSelfConsumptionTotal: "自食牲畜总数",
362 374
     formStatYear: "所属年份",
363 375
     formStatMonth: "所属月份",
364 376
     formTown: "所属乡镇",
365
-    formFarmerHouseholdCount: "农牧户户数",
366
-    formFarmerPopulationCount: "农牧户人数",
377
+    formVillage: "所属村",
378
+    formFarmerHouseholdCount: "农牧户数",
379
+    formFarmerPopulationCount: "农牧人数",
367 380
     formYakOutboundCount: "牦牛出栏数",
368 381
     formCattleOutboundCount: "黄牛/奶牛/犏牛出栏数",
369 382
     formSheepOutboundCount: "绵羊出栏数",
370 383
     formGoatOutboundCount: "山羊出栏数",
371 384
     formHorseMuleOutboundCount: "马骡出栏数",
372 385
     formDonkeyOutboundCount: "驴出栏数",
373
-    formSelfConsumptionCattleCount: "自食牛头数",
374
-    formSelfConsumptionSheepCount: "自食绵羊只数",
375
-    formSelfConsumptionGoatCount: "自食山羊只数",
386
+    formSelfConsumptionCattleCount: "自食牛数",
387
+    formSelfConsumptionSheepCount: "自食绵羊数",
388
+    formSelfConsumptionGoatCount: "自食山羊数",
389
+    formOutboundTotal: "牲畜总出栏数",
390
+    formSelfConsumptionTotal: "自食牲畜总数",
376 391
     formRemark: "备注",
377 392
     phRemark: "选填,不超过 500 字",
378 393
     sectionBasic: "基本信息",
@@ -386,6 +401,8 @@ export default {
386 401
     exportStatYearPh: "请选择所属年份",
387 402
     exportStatMonth: "所属月份",
388 403
     exportStatMonthPh: "请选择所属月份",
404
+    exportTown: "所属乡镇",
405
+    exportTownPh: "不选则导出该年月全部乡镇",
389 406
     exportStatYearRequired: "请选择所属年份",
390 407
     exportStatMonthRequired: "请选择所属月份",
391 408
     exportStatYearInvalid: "导出年月不在可选范围内",
@@ -396,7 +413,7 @@ export default {
396 413
     importStatYearPh: "请选择填报年份",
397 414
     importStatMonth: "填报月份",
398 415
     importStatMonthPh: "请选择填报月份",
399
-    importTip: "请先选择填报年月,再上传与模板格式一致的 .xlsx 文件",
416
+    importTip: "请先选择填报年月,再上传与模板格式一致的 .xlsx 文件;同年同月同村已存在则更新",
400 417
     importLoading: "正在导入,请稍候...",
401 418
     importSummary: "导入完成:新增 {insert} 条,更新 {update} 条,失败 {fail} 条",
402 419
     importWarnTitle: "导入警告",
@@ -413,7 +430,314 @@ export default {
413 430
     ruleStatYearRequired: "请选择所属年份",
414 431
     ruleStatMonthRequired: "请选择所属月份",
415 432
     ruleStatMonthFuture: "不可填报未来月份",
416
-    ruleTownRequired: "请选择所属乡镇",
417
-    ruleCountNonNegative: "须为大于等于 0 的整数"
433
+    ruleVillageRequired: "请选择所属村",
434
+    ruleCountNonNegative: "须为大于等于 0 的整数",
435
+    villageTreeEmpty: "未加载到村级组织数据,请确认系统部门已维护「乡镇→村」"
436
+  },
437
+  cooperativeDevelopment: {
438
+    queryStatYear: "所属年份",
439
+    queryStatMonth: "所属月份",
440
+    queryTown: "所属乡镇",
441
+    queryVillage: "所属村",
442
+    queryCooperativeName: "合作社名称",
443
+    phVillageSearch: "请选择或输入搜索",
444
+    phCooperativeName: "请输入合作社名称",
445
+    phEstablishDate: "如 2020-01-01",
446
+    phRemark: "选填,不超过 500 字",
447
+    colStatYear: "所属年份",
448
+    colStatMonth: "所属月份",
449
+    statMonthLabel: "{month}月",
450
+    colVillageName: "所属村",
451
+    colTownName: "所属乡镇",
452
+    colCooperativeName: "合作社名称",
453
+    colLegalRepresentative: "法定代表人",
454
+    colEstablishDate: "成立时间",
455
+    colRegisteredCapital: "注册资本",
456
+    colYearEndTotalAssets: "截止年底总资产",
457
+    colTotalIncome: "总收入",
458
+    colLossAmount: "亏损",
459
+    colCattleInventoryCount: "牛存栏",
460
+    colCattleOutboundCount: "牛出栏",
461
+    formStatYear: "所属年份",
462
+    formStatMonth: "所属月份",
463
+    formTown: "所属乡镇",
464
+    formVillage: "所属村",
465
+    formCooperativeName: "合作社名称",
466
+    formLegalRepresentative: "法定代表人",
467
+    formEstablishDate: "成立时间",
468
+    formRegisteredCapital: "注册资本",
469
+    formYearEndTotalAssets: "截止年底总资产",
470
+    formMemberHouseholdCount: "入社户数",
471
+    formMemberPopulationCount: "入社人数",
472
+    formPovertyMonitorCount: "防返贫监测人数",
473
+    formCattleShareCount: "牛入股数量",
474
+    formSheepShareCount: "羊入股数量",
475
+    formLivestockShareTotal: "牲畜入股小计",
476
+    formGrasslandShareArea: "草场入股",
477
+    formLaborShareCount: "劳动力入股",
478
+    formCashShareAmount: "现金入股",
479
+    formOtherShareAmount: "其他入股",
480
+    formTotalIncome: "总收入",
481
+    formNetIncome: "纯收入",
482
+    formCashDividend: "现金分红",
483
+    formInKindDividend: "实物分红折算",
484
+    formRevolvingFund: "周转金",
485
+    formLossAmount: "亏损",
486
+    formCollegeGraduateCount: "吸纳大学生",
487
+    formCollegeGraduateWage: "大学生工资性收入",
488
+    formFarmerTransferEmploymentCount: "农牧民转移就业",
489
+    formFarmerTransferWage: "农牧民工资性收入",
490
+    formCattleInventoryCount: "牛存栏",
491
+    formCattleOutboundCount: "牛出栏",
492
+    formSheepInventoryCount: "羊存栏",
493
+    formSheepOutboundCount: "羊出栏",
494
+    formTrademarkProductCount: "注册商标产品数量",
495
+    formQualityCertProductCount: "质量认证产品数量",
496
+    formTrainingManageCount: "培训-管理能力",
497
+    formTrainingSkillCount: "培训-专业技能",
498
+    formTrainingOtherCount: "培训-其他",
499
+    formBusinessScope: "主要经营范围",
500
+    formBusinessModel: "经营模式分类",
501
+    formOperationStatus: "运营情况",
502
+    formRemark: "备注",
503
+    sectionBasic: "基本信息",
504
+    sectionMemberShare: "入社与入股",
505
+    sectionBenefit: "效益情况",
506
+    sectionEmploymentLivestock: "就业与存出栏",
507
+    sectionProductTraining: "产品认证与培训",
508
+    sectionOperation: "经营情况",
509
+    btnImport: "导入",
510
+    btnChooseFile: "选取文件",
511
+    btnDownloadTemplate: "下载模板",
512
+    exportTitle: "Excel 导出",
513
+    exportStatYear: "所属年份",
514
+    exportStatYearPh: "请选择所属年份",
515
+    exportStatMonth: "所属月份",
516
+    exportStatMonthPh: "请选择所属月份",
517
+    exportTown: "所属乡镇",
518
+    exportTownPh: "不选则导出该年月全部乡镇",
519
+    exportStatYearRequired: "请选择所属年份",
520
+    exportStatMonthRequired: "请选择所属月份",
521
+    exportStatYearInvalid: "导出年月不在可选范围内",
522
+    exportLoading: "正在导出,请稍候...",
523
+    exportFail: "导出失败",
524
+    importTitle: "Excel 导入",
525
+    importStatYear: "填报年份",
526
+    importStatYearPh: "请选择填报年份",
527
+    importStatMonth: "填报月份",
528
+    importStatMonthPh: "请选择填报月份",
529
+    importTip: "请先选择填报年月,再上传与模板格式一致的 .xlsx 文件;同年同月同村同合作社名称已存在则更新",
530
+    importLoading: "正在导入,请稍候...",
531
+    importSummary: "导入完成:新增 {insert} 条,更新 {update} 条,失败 {fail} 条",
532
+    importWarnTitle: "导入警告",
533
+    importFailTitle: "导入失败明细",
534
+    dialogAdd: "[新增]合作社发展数据",
535
+    dialogEdit: "[编辑]合作社发展数据",
536
+    confirmDelete: "是否确认删除这条数据?",
537
+    emptyList: "暂无填报数据",
538
+    unitHousehold: "户",
539
+    unitPerson: "人",
540
+    unitHead: "头",
541
+    unitGe: "个",
542
+    unitWanYuan: "万元",
543
+    unitWanMu: "万亩",
544
+    ruleStatYearRequired: "请选择所属年份",
545
+    ruleStatMonthRequired: "请选择所属月份",
546
+    ruleStatMonthFuture: "不可填报未来月份",
547
+    ruleVillageRequired: "请选择所属村",
548
+    ruleCooperativeNameRequired: "请输入合作社名称",
549
+    ruleCooperativeNameLen: "合作社名称不能超过 200 字",
550
+    ruleLegalRepLen: "法定代表人不能超过 64 字",
551
+    ruleEstablishDateLen: "成立时间不能超过 32 字",
552
+    ruleCountNonNegative: "须为大于等于 0 的整数",
553
+    ruleDecimalNonNegative: "须为大于等于 0 的数字",
554
+    villageTreeEmpty: "未加载到村级组织数据,请确认系统部门已维护「乡镇→村」"
555
+  },
556
+  disposableIncome: {
557
+    queryStatYear: "所属年份",
558
+    colStatYear: "所属年份",
559
+    colRuralDisposableIncome: "农村居民人均可支配收入",
560
+    colIncomeIncrease: "增幅",
561
+    colIncomeGrowthRate: "增速",
562
+    colPovertyNetIncome: "脱贫人口人均纯收入",
563
+    formStatYear: "所属年份",
564
+    formRuralDisposableIncome: "农村居民人均可支配收入",
565
+    formIncomeIncrease: "增幅",
566
+    formIncomeGrowthRate: "增速",
567
+    formPovertyNetIncome: "脱贫人口人均纯收入",
568
+    formRemark: "备注",
569
+    phIncomeIncrease: "选填,元;不填则按上年自动计算",
570
+    phIncomeGrowthRate: "选填,小数如 0.1228;不填则自动计算",
571
+    phRemark: "选填,不超过 500 字",
572
+    dialogAdd: "[新增]可支配收入数据",
573
+    dialogEdit: "[编辑]可支配收入数据",
574
+    confirmDelete: "是否确认删除这条数据?",
575
+    emptyList: "暂无填报数据",
576
+    unitYuan: "元",
577
+    ruleStatYearRequired: "请选择所属年份",
578
+    ruleRuralIncomeRequired: "请输入农村居民人均可支配收入",
579
+    rulePovertyIncomeRequired: "请输入脱贫人口人均纯收入",
580
+    ruleMoneyNonNegative: "须为大于等于 0 的数字",
581
+    ruleNumberInvalid: "请输入有效数字"
582
+  },
583
+  livestockProductOutput: {
584
+    queryStatYear: "所属年份",
585
+    queryStatMonth: "所属月份",
586
+    queryTown: "所属乡镇",
587
+    queryVillage: "所属村",
588
+    phVillageSearch: "请选择或输入搜索",
589
+    phRemark: "选填,不超过 500 字",
590
+    colStatYear: "所属年份",
591
+    colStatMonth: "所属月份",
592
+    statMonthLabel: "{month}月",
593
+    colTownName: "所属乡镇",
594
+    colVillageName: "所属村",
595
+    colMeatOutput: "肉产量",
596
+    colMilkOutput: "奶产量",
597
+    formStatYear: "所属年份",
598
+    formStatMonth: "所属月份",
599
+    formTown: "所属乡镇",
600
+    formVillage: "所属村",
601
+    formMeatOutput: "肉产量",
602
+    formMilkOutput: "奶产量",
603
+    formRemark: "备注",
604
+    btnImport: "导入",
605
+    btnDownloadTemplate: "下载模板",
606
+    exportTitle: "Excel 导出",
607
+    exportStatYear: "所属年份",
608
+    exportStatYearPh: "请选择所属年份",
609
+    exportStatMonth: "所属月份",
610
+    exportStatMonthPh: "请选择所属月份",
611
+    exportTown: "所属乡镇",
612
+    exportTownPh: "不选则导出该年月全部乡镇",
613
+    exportStatYearRequired: "请选择所属年份",
614
+    exportStatMonthRequired: "请选择所属月份",
615
+    exportStatYearInvalid: "导出年月不在可选范围内",
616
+    exportLoading: "正在导出,请稍候...",
617
+    exportFail: "导出失败",
618
+    importTitle: "Excel 导入",
619
+    importStatYear: "填报年份",
620
+    importStatYearPh: "请选择填报年份",
621
+    importStatMonth: "填报月份",
622
+    importStatMonthPh: "请选择填报月份",
623
+    importTip: "请先选择填报年月,再上传与模板格式一致的 .xlsx 文件;同年同月同村已存在则更新",
624
+    importLoading: "正在导入,请稍候...",
625
+    importSummary: "导入完成:新增 {insert} 条,更新 {update} 条,失败 {fail} 条",
626
+    importWarnTitle: "导入警告",
627
+    importFailTitle: "导入失败明细",
628
+    dialogAdd: "[新增]畜牧产品产量",
629
+    dialogEdit: "[编辑]畜牧产品产量",
630
+    confirmDelete: "是否确认删除这条数据?",
631
+    emptyList: "暂无登记数据",
632
+    unitWanTon: "万吨",
633
+    ruleStatYearRequired: "请选择所属年份",
634
+    ruleStatMonthRequired: "请选择所属月份",
635
+    ruleStatMonthFuture: "不可填报未来月份",
636
+    ruleVillageRequired: "请选择所属村",
637
+    ruleDecimalNonNegative: "须为大于等于 0 的数字",
638
+    villageTreeEmpty: "未加载到村级组织数据,请确认系统部门已维护「乡镇→村」"
639
+  },
640
+  familyRanch: {
641
+    queryStatYear: "所属年份",
642
+    queryStatMonth: "所属月份",
643
+    queryTown: "所属乡镇",
644
+    queryEnterpriseName: "企业名称",
645
+    phVillageSearch: "请选择或输入搜索",
646
+    phEnterpriseName: "请输入企业名称",
647
+    phRemark: "选填,不超过 500 字",
648
+    colStatYear: "所属年份",
649
+    colStatMonth: "所属月份",
650
+    statMonthLabel: "{month}月",
651
+    colTownName: "所属乡镇",
652
+    colVillageName: "所属村",
653
+    colEnterpriseName: "企业名称",
654
+    colLegalRepresentative: "法定代表人",
655
+    colEnterpriseType: "企业类型",
656
+    colRegisteredCapital: "注册资本",
657
+    colEstablishDate: "成立时间",
658
+    colCattleYearEndStock: "牛存栏",
659
+    colCattleOutbound: "牛出栏",
660
+    colGrasslandArea: "草场面积",
661
+    formStatYear: "所属年份",
662
+    formStatMonth: "所属月份",
663
+    formTown: "所属乡镇",
664
+    formVillage: "所属村",
665
+    formEnterpriseName: "企业名称",
666
+    formLegalRepresentative: "法定代表人",
667
+    formEnterpriseType: "企业类型",
668
+    formRegisteredCapital: "注册资本",
669
+    formEstablishDate: "成立时间",
670
+    formLivestockLaborCount: "从事畜牧业劳力人员",
671
+    formCattleYearEndStock: "牛年底存栏",
672
+    formCattleBreedingFemaleStock: "牛能繁母畜",
673
+    formSheepYearEndStock: "羊年底存栏",
674
+    formSheepBreedingFemaleStock: "羊能繁母畜",
675
+    formCattleOutbound: "牛出栏",
676
+    formSheepOutbound: "羊出栏",
677
+    formStockSubtotal: "年底牲畜存栏小计",
678
+    formGrassBalanceArea: "草畜平衡面积",
679
+    formTransferGrassArea: "流转经营草地面积",
680
+    formGrasslandAreaSubtotal: "草场面积小计",
681
+    formApprovedCarryingCapacity: "核定年末草畜平衡载畜量",
682
+    formYearEndStockSheepUnit: "年底牲畜存栏",
683
+    formIsGrassBalanced: "是否草畜平衡户",
684
+    formIncome: "年度经营总收入",
685
+    formExpense: "年度经营总支出",
686
+    formProfit: "利润",
687
+    formSubsidyYear: "补助资金年份",
688
+    formHasSubsidy: "是否享受补助",
689
+    formSubsidyAmount: "补贴资金",
690
+    formHasTrademark: "是否有注册商标",
691
+    formHasQualityCert: "是否通过农产品质量认证",
692
+    formSalesChannel: "产品销售渠道",
693
+    formDrivenPopulation: "带动人数",
694
+    formWagePaid: "发放工资",
695
+    formRemark: "备注",
696
+    sectionBasic: "基本信息",
697
+    sectionStock: "存栏与出栏",
698
+    sectionGrassland: "草场与草畜平衡",
699
+    sectionFinance: "经营与补助",
700
+    sectionOther: "其他",
701
+    btnImport: "导入",
702
+    btnDownloadTemplate: "下载模板",
703
+    exportTitle: "Excel 导出",
704
+    exportStatYear: "所属年份",
705
+    exportStatYearPh: "请选择所属年份",
706
+    exportStatMonth: "所属月份",
707
+    exportStatMonthPh: "请选择所属月份",
708
+    exportStatYearRequired: "请选择所属年份",
709
+    exportStatMonthRequired: "请选择所属月份",
710
+    exportStatYearInvalid: "导出年月不在可选范围内",
711
+    exportLoading: "正在导出,请稍候...",
712
+    exportFail: "导出失败",
713
+    importTitle: "Excel 导入",
714
+    importStatYear: "填报年份",
715
+    importStatYearPh: "请选择填报年份",
716
+    importStatMonth: "填报月份",
717
+    importStatMonthPh: "请选择填报月份",
718
+    importTip: "请先选择填报年月,再上传与模板格式一致的 .xlsx 文件;同年同月同村同企业名称已存在则更新",
719
+    importLoading: "正在导入,请稍候...",
720
+    importSummary: "导入完成:新增 {insert} 条,更新 {update} 条,失败 {fail} 条",
721
+    importWarnTitle: "导入警告",
722
+    importFailTitle: "导入失败明细",
723
+    dialogAdd: "[新增]家庭牧场数据",
724
+    dialogEdit: "[编辑]家庭牧场数据",
725
+    confirmDelete: "是否确认删除这条数据?",
726
+    emptyList: "暂无填报数据",
727
+    unitPerson: "人",
728
+    unitHead: "头",
729
+    unitMu: "亩",
730
+    unitWanYuan: "万元",
731
+    unitSheepUnit: "绵羊单位",
732
+    ruleStatYearRequired: "请选择所属年份",
733
+    ruleStatMonthRequired: "请选择所属月份",
734
+    ruleStatMonthFuture: "不可填报未来月份",
735
+    ruleVillageRequired: "请选择所属村",
736
+    ruleEnterpriseNameRequired: "请输入企业名称",
737
+    ruleEnterpriseNameLen: "企业名称不能超过 200 字",
738
+    ruleLegalRepLen: "法定代表人不能超过 64 字",
739
+    ruleCountNonNegative: "须为大于等于 0 的整数",
740
+    ruleDecimalNonNegative: "须为大于等于 0 的数字",
741
+    villageTreeEmpty: "未加载到村级组织数据,请确认系统部门已维护「乡镇→村」"
418 742
   }
419 743
 }

+ 17 - 0
ruoyi-ui/src/mixins/dataModelLocaleMixin.js

@@ -1,5 +1,7 @@
1 1
 /**
2 2
  * 产业数据模型及体系:dmT(data.dmNs)、dmCommon(通用按钮/校验)
3
+ *
4
+ * 查看弹窗约定:数值类字段须用 formatWithUnit 展示单位(与表单后缀一致)。
3 5
  */
4 6
 export default {
5 7
   methods: {
@@ -13,6 +15,21 @@ export default {
13 15
     dmCommon(key) {
14 16
       return this.$t(`dataModel.common.${key}`)
15 17
     },
18
+    /**
19
+     * 查看弹窗:数值 + 单位。空值仅显示 —,不拼单位。
20
+     * @param {*} value 已格式化或原始展示值
21
+     * @param {string} [unitKey] 模块内单位 i18n 键,如 unitHead
22
+     */
23
+    formatWithUnit(value, unitKey) {
24
+      const dash = this.$t("dataModel.status.dash")
25
+      if (value == null || value === "" || value === dash) {
26
+        return dash
27
+      }
28
+      if (!unitKey) {
29
+        return value
30
+      }
31
+      return `${value} ${this.dmT(unitKey)}`
32
+    },
16 33
     warningTypeText(type) {
17 34
       if (type === 1) {
18 35
         return this.$t("dataModel.yakDiseaseWarning.warningType1")

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1255 - 0
ruoyi-ui/src/views/dataModel/cooperativeDevelopment/index.vue


+ 506 - 0
ruoyi-ui/src/views/dataModel/disposableIncome/index.vue

@@ -0,0 +1,506 @@
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: 140px">
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>
12
+          <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">{{ dmCommon("search") }}</el-button>
13
+          <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">{{ dmCommon("reset") }}</el-button>
14
+          <el-button
15
+            v-hasPermi="['dataModel:disposableIncome:add']"
16
+            type="primary"
17
+            plain
18
+            icon="el-icon-plus"
19
+            size="mini"
20
+            @click="handleAdd"
21
+          >{{ dmCommon("add") }}</el-button>
22
+        </el-form-item>
23
+      </el-form>
24
+    </el-card>
25
+
26
+    <br />
27
+
28
+    <el-card shadow="never">
29
+      <el-table v-loading="loading" :data="tableList" border>
30
+        <template slot="empty">
31
+          <span>{{ dmT("emptyList") }}</span>
32
+        </template>
33
+        <el-table-column :label="dmT('colStatYear')" prop="statYear" align="center" width="120" />
34
+        <el-table-column :label="dmT('colRuralDisposableIncome')" align="center" min-width="180">
35
+          <template slot-scope="scope">{{ formatMoney(scope.row.ruralDisposableIncome) }}</template>
36
+        </el-table-column>
37
+        <el-table-column :label="dmT('colIncomeIncrease')" align="center" min-width="120">
38
+          <template slot-scope="scope">{{ formatIncrease(scope.row.incomeIncrease) }}</template>
39
+        </el-table-column>
40
+        <el-table-column :label="dmT('colIncomeGrowthRate')" align="center" min-width="120">
41
+          <template slot-scope="scope">{{ formatGrowthRate(scope.row.incomeGrowthRate) }}</template>
42
+        </el-table-column>
43
+        <el-table-column :label="dmT('colPovertyNetIncome')" align="center" min-width="180">
44
+          <template slot-scope="scope">{{ formatMoney(scope.row.povertyNetIncome) }}</template>
45
+        </el-table-column>
46
+        <el-table-column :label="dmCommon('colOp')" align="center" class-name="small-padding fixed-width" width="180" fixed="right">
47
+          <template slot-scope="scope">
48
+            <el-button v-hasPermi="['dataModel:disposableIncome:query']" type="text" size="mini" @click="handleView(scope.row)">{{ dmCommon("view") }}</el-button>
49
+            <el-button v-hasPermi="['dataModel:disposableIncome:edit']" type="text" size="mini" @click="handleEdit(scope.row)">{{ dmCommon("edit") }}</el-button>
50
+            <el-button v-hasPermi="['dataModel:disposableIncome:remove']" type="text" size="mini" @click="handleDelete(scope.row)">{{ dmCommon("delete") }}</el-button>
51
+          </template>
52
+        </el-table-column>
53
+      </el-table>
54
+      <pagination
55
+        v-show="total > 0"
56
+        :total="total"
57
+        :page.sync="queryParams.pageNum"
58
+        :limit.sync="queryParams.pageSize"
59
+        @pagination="getList"
60
+      />
61
+    </el-card>
62
+
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">
65
+        <el-form-item prop="statYear" :rules="formRules.statYear">
66
+          <template slot="label">{{ dmT("formStatYear") }}</template>
67
+          <el-select v-model="form.statYear" :placeholder="dmCommon('pleaseSelect')" style="width: 100%" @change="onStatYearOrIncomeChange">
68
+            <el-option v-for="y in yearOptions" :key="'f-' + y" :label="String(y)" :value="y" />
69
+          </el-select>
70
+        </el-form-item>
71
+        <el-form-item prop="ruralDisposableIncome" :rules="formRules.ruralDisposableIncome">
72
+          <template slot="label">{{ dmT("formRuralDisposableIncome") }}</template>
73
+          <div class="dm-input-with-unit">
74
+            <el-input-number
75
+              v-model="form.ruralDisposableIncome"
76
+              :min="0"
77
+              :precision="2"
78
+              :controls="true"
79
+              controls-position="right"
80
+              class="dm-input-with-unit__input"
81
+              @change="onStatYearOrIncomeChange"
82
+            />
83
+            <span class="dm-input-with-unit__suffix">{{ dmT("unitYuan") }}</span>
84
+          </div>
85
+        </el-form-item>
86
+        <el-form-item prop="incomeIncrease" :rules="formRules.optionalNumber">
87
+          <template slot="label">{{ dmT("formIncomeIncrease") }}</template>
88
+          <div class="dm-input-with-unit">
89
+            <el-input
90
+              v-model="form.incomeIncrease"
91
+              :placeholder="dmT('phIncomeIncrease')"
92
+              clearable
93
+              class="dm-input-with-unit__input"
94
+            />
95
+            <span class="dm-input-with-unit__suffix">{{ dmT("unitYuan") }}</span>
96
+          </div>
97
+        </el-form-item>
98
+        <el-form-item prop="incomeGrowthRate" :rules="formRules.optionalNumber">
99
+          <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
+          />
106
+        </el-form-item>
107
+        <el-form-item prop="povertyNetIncome" :rules="formRules.povertyNetIncome">
108
+          <template slot="label">{{ dmT("formPovertyNetIncome") }}</template>
109
+          <div class="dm-input-with-unit">
110
+            <el-input-number
111
+              v-model="form.povertyNetIncome"
112
+              :min="0"
113
+              :precision="2"
114
+              :controls="true"
115
+              controls-position="right"
116
+              class="dm-input-with-unit__input"
117
+            />
118
+            <span class="dm-input-with-unit__suffix">{{ dmT("unitYuan") }}</span>
119
+          </div>
120
+        </el-form-item>
121
+        <el-form-item prop="remark" :rules="formRules.remark">
122
+          <template slot="label">{{ dmT("formRemark") }}</template>
123
+          <el-input v-model="form.remark" type="textarea" :rows="2" :placeholder="dmT('phRemark')" maxlength="500" show-word-limit />
124
+        </el-form-item>
125
+      </el-form>
126
+      <div slot="footer" class="dialog-footer">
127
+        <el-button type="primary" @click="submitForm">{{ dmCommon("ok") }}</el-button>
128
+        <el-button @click="cancel">{{ dmCommon("cancel") }}</el-button>
129
+      </div>
130
+    </el-dialog>
131
+
132
+    <el-dialog :title="dmCommon('viewTitle')" :visible.sync="viewOpen" width="640px" append-to-body>
133
+      <el-form label-width="180px" size="small">
134
+        <el-form-item :label="dmT('formStatYear')">
135
+          <span>{{ viewRow.statYear || dash }}</span>
136
+        </el-form-item>
137
+        <el-form-item :label="dmT('formRuralDisposableIncome')">
138
+          <span>{{ formatWithUnit(formatMoney(viewRow.ruralDisposableIncome), "unitYuan") }}</span>
139
+        </el-form-item>
140
+        <el-form-item :label="dmT('formIncomeIncrease')">
141
+          <span>{{ formatWithUnit(formatIncrease(viewRow.incomeIncrease), "unitYuan") }}</span>
142
+        </el-form-item>
143
+        <el-form-item :label="dmT('formIncomeGrowthRate')">
144
+          <span>{{ formatGrowthRate(viewRow.incomeGrowthRate) }}</span>
145
+        </el-form-item>
146
+        <el-form-item :label="dmT('formPovertyNetIncome')">
147
+          <span>{{ formatWithUnit(formatMoney(viewRow.povertyNetIncome), "unitYuan") }}</span>
148
+        </el-form-item>
149
+        <el-form-item :label="dmT('formRemark')">
150
+          <span class="di-view-text">{{ viewRow.remark || dash }}</span>
151
+        </el-form-item>
152
+      </el-form>
153
+      <div slot="footer" class="dialog-footer">
154
+        <el-button
155
+          v-hasPermi="['dataModel:disposableIncome:edit']"
156
+          type="primary"
157
+          @click="handleEditFromView"
158
+        >{{ dmCommon("edit") }}</el-button>
159
+        <el-button @click="viewOpen = false">{{ dmCommon("close") }}</el-button>
160
+      </div>
161
+    </el-dialog>
162
+  </div>
163
+</template>
164
+
165
+<script>
166
+import dataModelLocaleMixin from "@/mixins/dataModelLocaleMixin"
167
+import {
168
+  listDisposableIncome,
169
+  getDisposableIncome,
170
+  addDisposableIncome,
171
+  updateDisposableIncome,
172
+  delDisposableIncome,
173
+  listDisposableIncomeYearOptions
174
+} from "@/api/dataModel/disposableIncome"
175
+
176
+function createEmptyForm() {
177
+  return {
178
+    id: undefined,
179
+    statYear: undefined,
180
+    ruralDisposableIncome: undefined,
181
+    incomeIncrease: undefined,
182
+    incomeGrowthRate: undefined,
183
+    povertyNetIncome: undefined,
184
+    remark: undefined
185
+  }
186
+}
187
+
188
+function optionalFieldToInput(val) {
189
+  if (val == null || val === "") {
190
+    return undefined
191
+  }
192
+  return String(val)
193
+}
194
+
195
+function parseOptionalNumber(val) {
196
+  if (val == null || val === "") {
197
+    return undefined
198
+  }
199
+  const n = Number(val)
200
+  return Number.isFinite(n) ? n : NaN
201
+}
202
+
203
+function normalizeForm(data) {
204
+  const row = Object.assign(createEmptyForm(), data || {})
205
+  if (row.ruralDisposableIncome != null && row.ruralDisposableIncome !== "") {
206
+    row.ruralDisposableIncome = Number(row.ruralDisposableIncome)
207
+  } else {
208
+    row.ruralDisposableIncome = undefined
209
+  }
210
+  if (row.povertyNetIncome != null && row.povertyNetIncome !== "") {
211
+    row.povertyNetIncome = Number(row.povertyNetIncome)
212
+  } else {
213
+    row.povertyNetIncome = undefined
214
+  }
215
+  row.incomeIncrease = optionalFieldToInput(row.incomeIncrease)
216
+  row.incomeGrowthRate = optionalFieldToInput(row.incomeGrowthRate)
217
+  return row
218
+}
219
+
220
+export default {
221
+  name: "DisposableIncome",
222
+  mixins: [dataModelLocaleMixin],
223
+  data() {
224
+    return {
225
+      dmNs: "disposableIncome",
226
+      loading: false,
227
+      open: false,
228
+      viewOpen: false,
229
+      dialogEdit: false,
230
+      formKey: 0,
231
+      total: 0,
232
+      tableList: [],
233
+      yearOptions: [],
234
+      viewRow: {},
235
+      /** 编辑时用于判断年份/可支配收入是否变更,以便清空增幅增速 */
236
+      baselineStatYear: undefined,
237
+      baselineRuralDisposableIncome: undefined,
238
+      queryParams: {
239
+        pageNum: 1,
240
+        pageSize: 20,
241
+        statYear: undefined
242
+      },
243
+      form: createEmptyForm()
244
+    }
245
+  },
246
+  computed: {
247
+    dash() {
248
+      return this.$t("dataModel.status.dash")
249
+    },
250
+    dialogTitle() {
251
+      return this.dialogEdit ? this.dmT("dialogEdit") : this.dmT("dialogAdd")
252
+    },
253
+    formRules() {
254
+      return {
255
+        statYear: [{ required: true, message: this.dmT("ruleStatYearRequired"), trigger: "change" }],
256
+        ruralDisposableIncome: [
257
+          { required: true, message: this.dmT("ruleRuralIncomeRequired"), trigger: "change" },
258
+          { validator: this.validateNonNegativeMoney, trigger: "change" }
259
+        ],
260
+        povertyNetIncome: [
261
+          { required: true, message: this.dmT("rulePovertyIncomeRequired"), trigger: "change" },
262
+          { validator: this.validateNonNegativeMoney, trigger: "change" }
263
+        ],
264
+        optionalNumber: [{ validator: this.validateOptionalNumber, trigger: "blur" }],
265
+        remark: [{ max: 500, message: this.dmCommon("ruleLen500"), trigger: "blur" }]
266
+      }
267
+    }
268
+  },
269
+  created() {
270
+    this.loadOptions()
271
+    this.getList()
272
+  },
273
+  methods: {
274
+    loadOptions() {
275
+      listDisposableIncomeYearOptions().then((res) => {
276
+        this.yearOptions = Array.isArray(res.data) ? res.data : []
277
+      })
278
+    },
279
+    formatMoney(val) {
280
+      if (val == null || val === "") {
281
+        return this.dash
282
+      }
283
+      const n = Number(val)
284
+      if (!Number.isFinite(n)) {
285
+        return this.dash
286
+      }
287
+      return n.toFixed(2)
288
+    },
289
+    /** 列表/详情:库中 null 显示为 0.00 */
290
+    formatIncrease(val) {
291
+      if (val == null || val === "") {
292
+        return "0.00"
293
+      }
294
+      const n = Number(val)
295
+      if (!Number.isFinite(n)) {
296
+        return "0.00"
297
+      }
298
+      return n.toFixed(2)
299
+    },
300
+    /** 列表/详情:库中 null 显示为 0.00%;小数转百分比 */
301
+    formatGrowthRate(val) {
302
+      if (val == null || val === "") {
303
+        return "0.00%"
304
+      }
305
+      const n = Number(val)
306
+      if (!Number.isFinite(n)) {
307
+        return "0.00%"
308
+      }
309
+      return (n * 100).toFixed(2) + "%"
310
+    },
311
+    validateNonNegativeMoney(rule, value, callback) {
312
+      if (value == null || value === "") {
313
+        callback()
314
+        return
315
+      }
316
+      if (typeof value !== "number" || Number.isNaN(value) || value < 0) {
317
+        callback(new Error(this.dmT("ruleMoneyNonNegative")))
318
+        return
319
+      }
320
+      callback()
321
+    },
322
+    validateOptionalNumber(rule, value, callback) {
323
+      if (value == null || value === "") {
324
+        callback()
325
+        return
326
+      }
327
+      const n = Number(value)
328
+      if (!Number.isFinite(n)) {
329
+        callback(new Error(this.dmT("ruleNumberInvalid")))
330
+        return
331
+      }
332
+      callback()
333
+    },
334
+    clearGrowthFields() {
335
+      this.form.incomeIncrease = undefined
336
+      this.form.incomeGrowthRate = undefined
337
+    },
338
+    onStatYearOrIncomeChange() {
339
+      if (!this.dialogEdit || !this.open) {
340
+        return
341
+      }
342
+      const yearChanged = this.form.statYear !== this.baselineStatYear
343
+      const incomeChanged = !this.sameDecimal(this.form.ruralDisposableIncome, this.baselineRuralDisposableIncome)
344
+      if (yearChanged || incomeChanged) {
345
+        this.clearGrowthFields()
346
+      }
347
+    },
348
+    sameDecimal(a, b) {
349
+      if (a == null && b == null) {
350
+        return true
351
+      }
352
+      if (a == null || b == null) {
353
+        return false
354
+      }
355
+      return Number(a) === Number(b)
356
+    },
357
+    buildListQuery() {
358
+      const q = {
359
+        pageNum: this.queryParams.pageNum,
360
+        pageSize: this.queryParams.pageSize
361
+      }
362
+      if (this.queryParams.statYear != null) {
363
+        q.statYear = this.queryParams.statYear
364
+      }
365
+      return q
366
+    },
367
+    buildPayload() {
368
+      const remarkText = this.form.remark != null ? String(this.form.remark).trim() : ""
369
+      const incomeIncrease = parseOptionalNumber(this.form.incomeIncrease)
370
+      const incomeGrowthRate = parseOptionalNumber(this.form.incomeGrowthRate)
371
+      return {
372
+        statYear: this.form.statYear,
373
+        ruralDisposableIncome: this.form.ruralDisposableIncome,
374
+        povertyNetIncome: this.form.povertyNetIncome,
375
+        incomeIncrease: incomeIncrease === undefined ? undefined : incomeIncrease,
376
+        incomeGrowthRate: incomeGrowthRate === undefined ? undefined : incomeGrowthRate,
377
+        remark: remarkText !== "" ? remarkText : undefined
378
+      }
379
+    },
380
+    getList() {
381
+      this.loading = true
382
+      listDisposableIncome(this.buildListQuery())
383
+        .then((res) => {
384
+          this.tableList = res.rows || []
385
+          this.total = res.total != null ? res.total : 0
386
+        })
387
+        .finally(() => {
388
+          this.loading = false
389
+        })
390
+    },
391
+    handleQuery() {
392
+      this.queryParams.pageNum = 1
393
+      this.getList()
394
+    },
395
+    resetQuery() {
396
+      this.queryParams.statYear = undefined
397
+      this.resetForm("queryForm")
398
+      this.handleQuery()
399
+    },
400
+    handleAdd() {
401
+      this.formKey += 1
402
+      this.form = createEmptyForm()
403
+      this.form.statYear = new Date().getFullYear()
404
+      this.baselineStatYear = undefined
405
+      this.baselineRuralDisposableIncome = undefined
406
+      this.dialogEdit = false
407
+      this.open = true
408
+      this.$nextTick(() => {
409
+        if (this.$refs.form) {
410
+          this.$refs.form.clearValidate()
411
+        }
412
+      })
413
+    },
414
+    handleEdit(row) {
415
+      getDisposableIncome(row.id).then((res) => {
416
+        this.formKey += 1
417
+        this.dialogEdit = true
418
+        this.form = normalizeForm(res.data || {})
419
+        this.baselineStatYear = this.form.statYear
420
+        this.baselineRuralDisposableIncome = this.form.ruralDisposableIncome
421
+        this.open = true
422
+        this.viewOpen = false
423
+        this.$nextTick(() => {
424
+          if (this.$refs.form) {
425
+            this.$refs.form.clearValidate()
426
+          }
427
+        })
428
+      })
429
+    },
430
+    handleEditFromView() {
431
+      this.handleEdit(this.viewRow)
432
+    },
433
+    handleView(row) {
434
+      getDisposableIncome(row.id).then((res) => {
435
+        this.viewRow = res.data || {}
436
+        this.viewOpen = true
437
+      })
438
+    },
439
+    handleDelete(row) {
440
+      this.$modal
441
+        .confirm(this.dmT("confirmDelete"))
442
+        .then(() => delDisposableIncome(row.id))
443
+        .then(() => {
444
+          this.$modal.msgSuccess(this.dmCommon("msgDelOk"))
445
+          this.viewOpen = false
446
+          this.getList()
447
+        })
448
+        .catch(() => {})
449
+    },
450
+    submitForm() {
451
+      this.$refs.form.validate((valid) => {
452
+        if (!valid) {
453
+          return
454
+        }
455
+        const payload = this.buildPayload()
456
+        if (Number.isNaN(payload.incomeIncrease) || Number.isNaN(payload.incomeGrowthRate)) {
457
+          this.$modal.msgError(this.dmT("ruleNumberInvalid"))
458
+          return
459
+        }
460
+        if (this.dialogEdit) {
461
+          payload.id = this.form.id
462
+          updateDisposableIncome(payload).then(() => {
463
+            this.$modal.msgSuccess(this.dmCommon("msgModOk"))
464
+            this.open = false
465
+            this.getList()
466
+          })
467
+        } else {
468
+          addDisposableIncome(payload).then(() => {
469
+            this.$modal.msgSuccess(this.dmCommon("msgAddOk"))
470
+            this.open = false
471
+            this.getList()
472
+          })
473
+        }
474
+      })
475
+    },
476
+    cancel() {
477
+      this.open = false
478
+      this.form = createEmptyForm()
479
+    }
480
+  }
481
+}
482
+</script>
483
+
484
+<style scoped>
485
+.di-view-text {
486
+  white-space: pre-wrap;
487
+  word-break: break-all;
488
+}
489
+.dm-input-with-unit {
490
+  display: flex;
491
+  align-items: center;
492
+  width: 100%;
493
+}
494
+.dm-input-with-unit__input {
495
+  flex: 1;
496
+  width: 100%;
497
+}
498
+.dm-input-with-unit__suffix {
499
+  margin-left: 8px;
500
+  color: #909399;
501
+  white-space: nowrap;
502
+}
503
+.dm-input-with-unit >>> .el-input-number {
504
+  width: 100%;
505
+}
506
+</style>

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1197 - 0
ruoyi-ui/src/views/dataModel/familyRanch/index.vue


+ 840 - 0
ruoyi-ui/src/views/dataModel/livestockProductOutput/index.vue

@@ -0,0 +1,840 @@
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:livestockProductOutput: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:livestockProductOutput: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:livestockProductOutput: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="100" />
79
+        <el-table-column :label="dmT('colStatMonth')" align="center" width="90">
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('colMeatOutput')" align="center" min-width="120">
85
+          <template slot-scope="scope">{{ formatOutput(scope.row.meatOutput) }}</template>
86
+        </el-table-column>
87
+        <el-table-column :label="dmT('colMilkOutput')" align="center" min-width="120">
88
+          <template slot-scope="scope">{{ formatOutput(scope.row.milkOutput) }}</template>
89
+        </el-table-column>
90
+        <el-table-column :label="dmCommon('colOp')" align="center" class-name="small-padding fixed-width" width="180" fixed="right">
91
+          <template slot-scope="scope">
92
+            <el-button v-hasPermi="['dataModel:livestockProductOutput:query']" type="text" size="mini" @click="handleView(scope.row)">{{ dmCommon("view") }}</el-button>
93
+            <el-button v-hasPermi="['dataModel:livestockProductOutput:edit']" type="text" size="mini" @click="handleEdit(scope.row)">{{ dmCommon("edit") }}</el-button>
94
+            <el-button v-hasPermi="['dataModel:livestockProductOutput:remove']" type="text" size="mini" @click="handleDelete(scope.row)">{{ dmCommon("delete") }}</el-button>
95
+          </template>
96
+        </el-table-column>
97
+      </el-table>
98
+      <pagination
99
+        v-show="total > 0"
100
+        :total="total"
101
+        :page.sync="queryParams.pageNum"
102
+        :limit.sync="queryParams.pageSize"
103
+        @pagination="getList"
104
+      />
105
+    </el-card>
106
+
107
+    <el-dialog :title="dialogTitle" :visible.sync="open" width="640px" append-to-body @close="cancel">
108
+      <el-form :key="formKey" ref="form" :model="form" label-width="120px" size="small">
109
+        <el-form-item prop="statYear" :rules="formRules.statYear">
110
+          <template slot="label">{{ dmT("formStatYear") }}</template>
111
+          <el-select v-model="form.statYear" :placeholder="dmCommon('pleaseSelect')" style="width: 100%">
112
+            <el-option v-for="y in yearOptions" :key="'f-' + y" :label="String(y)" :value="y" />
113
+          </el-select>
114
+        </el-form-item>
115
+        <el-form-item prop="statMonth" :rules="formRules.statMonth">
116
+          <template slot="label">{{ dmT("formStatMonth") }}</template>
117
+          <el-select v-model="form.statMonth" :placeholder="dmCommon('pleaseSelect')" style="width: 100%">
118
+            <el-option v-for="m in monthOptions" :key="'fm-' + m" :label="formatStatMonth(m)" :value="m" />
119
+          </el-select>
120
+        </el-form-item>
121
+        <el-form-item prop="villageDeptId" :rules="formRules.villageDeptId">
122
+          <template slot="label">{{ dmT("formVillage") }}</template>
123
+          <el-select
124
+            v-model="form.villageDeptId"
125
+            :placeholder="dmT('phVillageSearch')"
126
+            filterable
127
+            clearable
128
+            style="width: 100%"
129
+          >
130
+            <el-option
131
+              v-for="item in villageOptions"
132
+              :key="'f-v-' + item.deptId"
133
+              :label="item.label"
134
+              :value="item.deptId"
135
+            />
136
+          </el-select>
137
+        </el-form-item>
138
+        <el-form-item prop="meatOutput" :rules="formRules.decimal">
139
+          <template slot="label">{{ dmT("formMeatOutput") }}</template>
140
+          <div class="dm-input-with-unit">
141
+            <el-input-number
142
+              v-model="form.meatOutput"
143
+              :min="0"
144
+              :precision="4"
145
+              :controls="true"
146
+              controls-position="right"
147
+              class="dm-input-with-unit__input"
148
+            />
149
+            <span class="dm-input-with-unit__suffix">{{ dmT("unitWanTon") }}</span>
150
+          </div>
151
+        </el-form-item>
152
+        <el-form-item prop="milkOutput" :rules="formRules.decimal">
153
+          <template slot="label">{{ dmT("formMilkOutput") }}</template>
154
+          <div class="dm-input-with-unit">
155
+            <el-input-number
156
+              v-model="form.milkOutput"
157
+              :min="0"
158
+              :precision="4"
159
+              :controls="true"
160
+              controls-position="right"
161
+              class="dm-input-with-unit__input"
162
+            />
163
+            <span class="dm-input-with-unit__suffix">{{ dmT("unitWanTon") }}</span>
164
+          </div>
165
+        </el-form-item>
166
+        <el-form-item prop="remark" :rules="formRules.remark">
167
+          <template slot="label">{{ dmT("formRemark") }}</template>
168
+          <el-input v-model="form.remark" type="textarea" :rows="2" :placeholder="dmT('phRemark')" maxlength="500" show-word-limit />
169
+        </el-form-item>
170
+      </el-form>
171
+      <div slot="footer" class="dialog-footer">
172
+        <el-button type="primary" @click="submitForm">{{ dmCommon("ok") }}</el-button>
173
+        <el-button @click="cancel">{{ dmCommon("cancel") }}</el-button>
174
+      </div>
175
+    </el-dialog>
176
+
177
+    <el-dialog :title="dmCommon('viewTitle')" :visible.sync="viewOpen" width="640px" append-to-body>
178
+      <el-form label-width="120px" size="small">
179
+        <el-form-item :label="dmT('formStatYear')">
180
+          <span>{{ viewRow.statYear || dash }}</span>
181
+        </el-form-item>
182
+        <el-form-item :label="dmT('formStatMonth')">
183
+          <span>{{ formatStatMonth(viewRow.statMonth) }}</span>
184
+        </el-form-item>
185
+        <el-form-item :label="dmT('formTown')">
186
+          <span>{{ viewRow.townName || dash }}</span>
187
+        </el-form-item>
188
+        <el-form-item :label="dmT('formVillage')">
189
+          <span>{{ viewRow.villageName || dash }}</span>
190
+        </el-form-item>
191
+        <el-form-item :label="dmT('formMeatOutput')">
192
+          <span>{{ formatWithUnit(formatOutput(viewRow.meatOutput), "unitWanTon") }}</span>
193
+        </el-form-item>
194
+        <el-form-item :label="dmT('formMilkOutput')">
195
+          <span>{{ formatWithUnit(formatOutput(viewRow.milkOutput), "unitWanTon") }}</span>
196
+        </el-form-item>
197
+        <el-form-item :label="dmT('formRemark')">
198
+          <span class="lpo-view-text">{{ viewRow.remark || dash }}</span>
199
+        </el-form-item>
200
+      </el-form>
201
+      <div slot="footer" class="dialog-footer">
202
+        <el-button
203
+          v-hasPermi="['dataModel:livestockProductOutput:edit']"
204
+          type="primary"
205
+          @click="handleEditFromView"
206
+        >{{ dmCommon("edit") }}</el-button>
207
+        <el-button @click="viewOpen = false">{{ dmCommon("close") }}</el-button>
208
+      </div>
209
+    </el-dialog>
210
+
211
+    <el-dialog :title="dmT('importTitle')" :visible.sync="importOpen" width="480px" append-to-body @close="resetImport">
212
+      <el-form ref="importFormRef" :model="importForm" label-width="100px" size="small">
213
+        <el-form-item prop="statYear" :rules="importRules.statYear">
214
+          <template slot="label">{{ dmT("importStatYear") }}</template>
215
+          <el-select v-model="importForm.statYear" :placeholder="dmT('importStatYearPh')" style="width: 100%">
216
+            <el-option v-for="y in yearOptions" :key="'iy-' + y" :label="String(y)" :value="y" />
217
+          </el-select>
218
+        </el-form-item>
219
+        <el-form-item prop="statMonth" :rules="importRules.statMonth">
220
+          <template slot="label">{{ dmT("importStatMonth") }}</template>
221
+          <el-select v-model="importForm.statMonth" :placeholder="dmT('importStatMonthPh')" style="width: 100%">
222
+            <el-option v-for="m in monthOptions" :key="'im-' + m" :label="formatStatMonth(m)" :value="m" />
223
+          </el-select>
224
+        </el-form-item>
225
+        <p class="lpo-import-tip">{{ dmT("importTip") }}</p>
226
+        <el-upload
227
+          ref="importUpload"
228
+          drag
229
+          :limit="1"
230
+          accept=".xlsx,.xls"
231
+          :auto-upload="false"
232
+          action="#"
233
+        >
234
+          <i class="el-icon-upload" />
235
+          <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
236
+          <div slot="tip" class="el-upload__tip">
237
+            <el-link type="primary" :underline="false" @click="handleDownloadTemplate">{{ dmT("btnDownloadTemplate") }}</el-link>
238
+          </div>
239
+        </el-upload>
240
+      </el-form>
241
+      <div slot="footer" class="dialog-footer">
242
+        <el-button type="primary" :loading="importing" @click="handleImportSubmit">{{ dmCommon("ok") }}</el-button>
243
+        <el-button @click="importOpen = false">{{ dmCommon("cancel") }}</el-button>
244
+      </div>
245
+    </el-dialog>
246
+
247
+    <el-dialog :title="dmT('exportTitle')" :visible.sync="exportOpen" width="480px" append-to-body @close="resetExport">
248
+      <el-form ref="exportFormRef" :model="exportForm" label-width="100px" size="small">
249
+        <el-form-item prop="statYear" :rules="exportRules.statYear">
250
+          <template slot="label">{{ dmT("exportStatYear") }}</template>
251
+          <el-select v-model="exportForm.statYear" :placeholder="dmT('exportStatYearPh')" style="width: 100%">
252
+            <el-option v-for="y in yearOptions" :key="'ey-' + y" :label="String(y)" :value="y" />
253
+          </el-select>
254
+        </el-form-item>
255
+        <el-form-item prop="statMonth" :rules="exportRules.statMonth">
256
+          <template slot="label">{{ dmT("exportStatMonth") }}</template>
257
+          <el-select v-model="exportForm.statMonth" :placeholder="dmT('exportStatMonthPh')" style="width: 100%">
258
+            <el-option v-for="m in monthOptions" :key="'em-' + m" :label="formatStatMonth(m)" :value="m" />
259
+          </el-select>
260
+        </el-form-item>
261
+        <el-form-item>
262
+          <template slot="label">{{ dmT("exportTown") }}</template>
263
+          <el-select
264
+            v-model="exportForm.townDeptId"
265
+            :placeholder="dmT('exportTownPh')"
266
+            clearable
267
+            filterable
268
+            style="width: 100%"
269
+          >
270
+            <el-option v-for="item in townOptions" :key="'et-' + item.deptId" :label="item.deptName" :value="item.deptId" />
271
+          </el-select>
272
+        </el-form-item>
273
+      </el-form>
274
+      <div slot="footer" class="dialog-footer">
275
+        <el-button type="primary" :loading="exporting" @click="handleExportSubmit">{{ dmCommon("ok") }}</el-button>
276
+        <el-button @click="exportOpen = false">{{ dmCommon("cancel") }}</el-button>
277
+      </div>
278
+    </el-dialog>
279
+  </div>
280
+</template>
281
+
282
+<script>
283
+import dataModelLocaleMixin from "@/mixins/dataModelLocaleMixin"
284
+import {
285
+  listLivestockProductOutput,
286
+  getLivestockProductOutput,
287
+  addLivestockProductOutput,
288
+  updateLivestockProductOutput,
289
+  delLivestockProductOutput,
290
+  listLivestockProductOutputYearOptions,
291
+  listLivestockProductOutputMonthOptions,
292
+  listLivestockProductOutputTownOptions,
293
+  listLivestockProductOutputVillageTree,
294
+  importLivestockProductOutput,
295
+  downloadLivestockProductOutputTemplate,
296
+  exportLivestockProductOutput
297
+} from "@/api/dataModel/livestockProductOutput"
298
+import { blobValidate } from "@/utils/ruoyi"
299
+import { saveAs } from "file-saver"
300
+
301
+function getCurrentYearMonth() {
302
+  const now = new Date()
303
+  return {
304
+    statYear: now.getFullYear(),
305
+    statMonth: now.getMonth() + 1
306
+  }
307
+}
308
+
309
+function createEmptyForm() {
310
+  return {
311
+    id: undefined,
312
+    statYear: undefined,
313
+    statMonth: undefined,
314
+    villageDeptId: undefined,
315
+    meatOutput: undefined,
316
+    milkOutput: undefined,
317
+    remark: undefined
318
+  }
319
+}
320
+
321
+function normalizeForm(data) {
322
+  const row = Object.assign(createEmptyForm(), data || {})
323
+  ;["meatOutput", "milkOutput"].forEach((prop) => {
324
+    const val = row[prop]
325
+    row[prop] = val == null || val === "" ? undefined : Number(val)
326
+  })
327
+  return row
328
+}
329
+
330
+function flattenVillageOptions(tree) {
331
+  const list = []
332
+  ;(tree || []).forEach((county) => {
333
+    ;(county.children || []).forEach((town) => {
334
+      ;(town.children || []).forEach((village) => {
335
+        if (village == null || village.id == null) {
336
+          return
337
+        }
338
+        const townName = town.label || ""
339
+        const villageName = village.label || ""
340
+        list.push({
341
+          deptId: village.id,
342
+          deptName: villageName,
343
+          townName,
344
+          label: townName ? `${townName} / ${villageName}` : villageName
345
+        })
346
+      })
347
+    })
348
+  })
349
+  return list
350
+}
351
+
352
+export default {
353
+  name: "LivestockProductOutput",
354
+  mixins: [dataModelLocaleMixin],
355
+  data() {
356
+    return {
357
+      dmNs: "livestockProductOutput",
358
+      loading: false,
359
+      importing: false,
360
+      exporting: false,
361
+      open: false,
362
+      viewOpen: false,
363
+      importOpen: false,
364
+      exportOpen: false,
365
+      dialogEdit: false,
366
+      formKey: 0,
367
+      total: 0,
368
+      tableList: [],
369
+      yearOptions: [],
370
+      monthOptions: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
371
+      townOptions: [],
372
+      villageOptions: [],
373
+      viewRow: {},
374
+      importForm: {
375
+        statYear: undefined,
376
+        statMonth: undefined
377
+      },
378
+      exportForm: {
379
+        statYear: undefined,
380
+        statMonth: undefined,
381
+        townDeptId: undefined
382
+      },
383
+      queryParams: {
384
+        pageNum: 1,
385
+        pageSize: 20,
386
+        statYear: undefined,
387
+        statMonth: undefined,
388
+        townDeptId: undefined,
389
+        villageDeptId: undefined
390
+      },
391
+      form: createEmptyForm()
392
+    }
393
+  },
394
+  computed: {
395
+    dash() {
396
+      return this.$t("dataModel.status.dash")
397
+    },
398
+    dialogTitle() {
399
+      return this.dialogEdit ? this.dmT("dialogEdit") : this.dmT("dialogAdd")
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
+        decimal: [{ validator: this.validateOptionalDecimal, trigger: "change" }],
410
+        remark: [{ max: 500, message: this.dmCommon("ruleLen500"), trigger: "blur" }]
411
+      }
412
+    },
413
+    importRules() {
414
+      return {
415
+        statYear: [{ required: true, message: this.dmT("ruleStatYearRequired"), trigger: "change" }],
416
+        statMonth: [
417
+          { required: true, message: this.dmT("ruleStatMonthRequired"), trigger: "change" },
418
+          { validator: this.validateImportStatMonth, trigger: "change" }
419
+        ]
420
+      }
421
+    },
422
+    exportRules() {
423
+      return {
424
+        statYear: [{ required: true, message: this.dmT("exportStatYearRequired"), trigger: "change" }],
425
+        statMonth: [
426
+          { required: true, message: this.dmT("exportStatMonthRequired"), trigger: "change" },
427
+          { validator: this.validateExportStatMonth, trigger: "change" }
428
+        ]
429
+      }
430
+    }
431
+  },
432
+  created() {
433
+    this.loadOptions()
434
+    this.getList()
435
+  },
436
+  methods: {
437
+    loadOptions() {
438
+      listLivestockProductOutputYearOptions().then((res) => {
439
+        this.yearOptions = Array.isArray(res.data) ? res.data : []
440
+      })
441
+      listLivestockProductOutputMonthOptions().then((res) => {
442
+        if (Array.isArray(res.data) && res.data.length) {
443
+          this.monthOptions = res.data
444
+        }
445
+      })
446
+      listLivestockProductOutputTownOptions().then((res) => {
447
+        this.townOptions = Array.isArray(res.data) ? res.data : []
448
+      })
449
+      this.loadVillageTree()
450
+    },
451
+    loadVillageTree() {
452
+      return listLivestockProductOutputVillageTree()
453
+        .then((res) => {
454
+          const raw = res && res.data !== undefined ? res.data : res
455
+          const tree = Array.isArray(raw) ? raw : []
456
+          this.villageOptions = flattenVillageOptions(tree)
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
+    formatOutput(val) {
472
+      if (val == null || val === "") {
473
+        return this.dash
474
+      }
475
+      const n = Number(val)
476
+      if (!Number.isFinite(n)) {
477
+        return this.dash
478
+      }
479
+      return n
480
+    },
481
+    isFutureStatPeriod(statYear, statMonth) {
482
+      if (statYear == null || statMonth == null) {
483
+        return false
484
+      }
485
+      const now = new Date()
486
+      const currentYear = now.getFullYear()
487
+      const currentMonth = now.getMonth() + 1
488
+      if (statYear > currentYear) {
489
+        return true
490
+      }
491
+      return statYear === currentYear && statMonth > currentMonth
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
+    validateOptionalDecimal(rule, value, callback) {
515
+      if (value == null || value === "") {
516
+        callback()
517
+        return
518
+      }
519
+      if (typeof value !== "number" || Number.isNaN(value) || value < 0) {
520
+        callback(new Error(this.dmT("ruleDecimalNonNegative")))
521
+        return
522
+      }
523
+      callback()
524
+    },
525
+    buildListQuery() {
526
+      const q = {
527
+        pageNum: this.queryParams.pageNum,
528
+        pageSize: this.queryParams.pageSize
529
+      }
530
+      if (this.queryParams.statYear != null) {
531
+        q.statYear = this.queryParams.statYear
532
+      }
533
+      if (this.queryParams.statMonth != null) {
534
+        q.statMonth = this.queryParams.statMonth
535
+      }
536
+      if (this.queryParams.townDeptId != null) {
537
+        q.townDeptId = this.queryParams.townDeptId
538
+      }
539
+      if (this.queryParams.villageDeptId != null) {
540
+        q.villageDeptId = this.queryParams.villageDeptId
541
+      }
542
+      return q
543
+    },
544
+    buildPayload() {
545
+      const remarkText = this.form.remark != null ? String(this.form.remark).trim() : ""
546
+      return {
547
+        statYear: this.form.statYear,
548
+        statMonth: this.form.statMonth,
549
+        villageDeptId: this.form.villageDeptId,
550
+        meatOutput: this.form.meatOutput == null || this.form.meatOutput === "" ? undefined : this.form.meatOutput,
551
+        milkOutput: this.form.milkOutput == null || this.form.milkOutput === "" ? undefined : this.form.milkOutput,
552
+        remark: remarkText !== "" ? remarkText : undefined
553
+      }
554
+    },
555
+    getList() {
556
+      this.loading = true
557
+      listLivestockProductOutput(this.buildListQuery())
558
+        .then((res) => {
559
+          this.tableList = res.rows || []
560
+          this.total = res.total != null ? res.total : 0
561
+        })
562
+        .finally(() => {
563
+          this.loading = false
564
+        })
565
+    },
566
+    handleQuery() {
567
+      this.queryParams.pageNum = 1
568
+      this.getList()
569
+    },
570
+    resetQuery() {
571
+      this.queryParams.statYear = undefined
572
+      this.queryParams.statMonth = undefined
573
+      this.queryParams.townDeptId = undefined
574
+      this.queryParams.villageDeptId = undefined
575
+      this.resetForm("queryForm")
576
+      this.handleQuery()
577
+    },
578
+    handleAdd() {
579
+      const openDialog = () => {
580
+        this.formKey += 1
581
+        const current = getCurrentYearMonth()
582
+        this.form = createEmptyForm()
583
+        this.form.statYear = current.statYear
584
+        this.form.statMonth = current.statMonth
585
+        this.dialogEdit = false
586
+        this.open = true
587
+        this.$nextTick(() => {
588
+          if (this.$refs.form) {
589
+            this.$refs.form.clearValidate()
590
+          }
591
+        })
592
+      }
593
+      if (!this.villageOptions.length) {
594
+        this.loadVillageTree().finally(openDialog)
595
+      } else {
596
+        openDialog()
597
+      }
598
+    },
599
+    handleEdit(row) {
600
+      const openWithData = (data) => {
601
+        this.formKey += 1
602
+        this.dialogEdit = true
603
+        this.form = normalizeForm(data)
604
+        this.open = true
605
+        this.viewOpen = false
606
+        this.$nextTick(() => {
607
+          if (this.$refs.form) {
608
+            this.$refs.form.clearValidate()
609
+          }
610
+        })
611
+      }
612
+      getLivestockProductOutput(row.id).then((res) => {
613
+        const data = res.data || {}
614
+        if (!this.villageOptions.length) {
615
+          this.loadVillageTree().finally(() => openWithData(data))
616
+        } else {
617
+          openWithData(data)
618
+        }
619
+      })
620
+    },
621
+    handleEditFromView() {
622
+      this.handleEdit(this.viewRow)
623
+    },
624
+    handleView(row) {
625
+      getLivestockProductOutput(row.id).then((res) => {
626
+        this.viewRow = res.data || {}
627
+        this.viewOpen = true
628
+      })
629
+    },
630
+    handleDelete(row) {
631
+      this.$modal
632
+        .confirm(this.dmT("confirmDelete"))
633
+        .then(() => delLivestockProductOutput(row.id))
634
+        .then(() => {
635
+          this.$modal.msgSuccess(this.dmCommon("msgDelOk"))
636
+          this.viewOpen = false
637
+          this.getList()
638
+        })
639
+        .catch(() => {})
640
+    },
641
+    submitForm() {
642
+      this.$refs.form.validate((valid) => {
643
+        if (!valid) {
644
+          return
645
+        }
646
+        const payload = this.buildPayload()
647
+        if (this.dialogEdit) {
648
+          payload.id = this.form.id
649
+          updateLivestockProductOutput(payload).then(() => {
650
+            this.$modal.msgSuccess(this.dmCommon("msgModOk"))
651
+            this.open = false
652
+            this.getList()
653
+          })
654
+        } else {
655
+          addLivestockProductOutput(payload).then(() => {
656
+            this.$modal.msgSuccess(this.dmCommon("msgAddOk"))
657
+            this.open = false
658
+            this.getList()
659
+          })
660
+        }
661
+      })
662
+    },
663
+    cancel() {
664
+      this.open = false
665
+      this.form = createEmptyForm()
666
+    },
667
+    handleImportOpen() {
668
+      const current = getCurrentYearMonth()
669
+      this.importForm.statYear = current.statYear
670
+      this.importForm.statMonth = current.statMonth
671
+      this.importOpen = true
672
+      this.$nextTick(() => {
673
+        this.resetImportFiles()
674
+      })
675
+    },
676
+    resetImportFiles() {
677
+      if (this.$refs.importUpload) {
678
+        this.$refs.importUpload.clearFiles()
679
+      }
680
+    },
681
+    resetImport() {
682
+      this.importing = false
683
+      this.importForm.statYear = undefined
684
+      this.importForm.statMonth = undefined
685
+      this.resetImportFiles()
686
+    },
687
+    handleDownloadTemplate() {
688
+      const filename = `livestock_product_output_template_${new Date().getTime()}.xlsx`
689
+      this.$modal.loading("正在下载模板,请稍候")
690
+      downloadLivestockProductOutputTemplate()
691
+        .then(async (data) => {
692
+          if (blobValidate(data)) {
693
+            saveAs(new Blob([data], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }), filename)
694
+          } else {
695
+            const resText = await data.text()
696
+            const rspObj = JSON.parse(resText)
697
+            this.$modal.msgError(rspObj.msg || "下载模板失败")
698
+          }
699
+        })
700
+        .catch(() => {
701
+          this.$modal.msgError("下载模板失败")
702
+        })
703
+        .finally(() => {
704
+          this.$modal.closeLoading()
705
+        })
706
+    },
707
+    handleExportOpen() {
708
+      const current = getCurrentYearMonth()
709
+      this.exportForm.statYear = current.statYear
710
+      this.exportForm.statMonth = current.statMonth
711
+      this.exportForm.townDeptId = undefined
712
+      this.exportOpen = true
713
+      this.$nextTick(() => {
714
+        if (this.$refs.exportFormRef) {
715
+          this.$refs.exportFormRef.clearValidate()
716
+        }
717
+      })
718
+    },
719
+    resetExport() {
720
+      this.exporting = false
721
+      this.exportForm.statYear = undefined
722
+      this.exportForm.statMonth = undefined
723
+      this.exportForm.townDeptId = undefined
724
+    },
725
+    handleExportSubmit() {
726
+      this.$refs.exportFormRef.validate((valid) => {
727
+        if (!valid) {
728
+          return
729
+        }
730
+        const statYear = this.exportForm.statYear
731
+        const statMonth = this.exportForm.statMonth
732
+        if (!this.yearOptions.includes(statYear) || !this.monthOptions.includes(statMonth)) {
733
+          this.$modal.msgError(this.dmT("exportStatYearInvalid"))
734
+          return
735
+        }
736
+        const filename = `${statYear}年${statMonth}月畜牧产品产量数据.xlsx`
737
+        this.exporting = true
738
+        this.$modal.loading(this.dmT("exportLoading"))
739
+        exportLivestockProductOutput(statYear, statMonth, this.exportForm.townDeptId)
740
+          .then(async (data) => {
741
+            if (blobValidate(data)) {
742
+              saveAs(new Blob([data], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }), filename)
743
+              this.exportOpen = false
744
+            } else {
745
+              const resText = await data.text()
746
+              const rspObj = JSON.parse(resText)
747
+              this.$modal.msgError(rspObj.msg || this.dmT("exportFail"))
748
+            }
749
+          })
750
+          .catch(() => {
751
+            this.$modal.msgError(this.dmT("exportFail"))
752
+          })
753
+          .finally(() => {
754
+            this.exporting = false
755
+            this.$modal.closeLoading()
756
+          })
757
+      })
758
+    },
759
+    handleImportSubmit() {
760
+      this.$refs.importFormRef.validate((valid) => {
761
+        if (!valid) {
762
+          return
763
+        }
764
+        const upload = this.$refs.importUpload
765
+        const files = upload && upload.uploadFiles
766
+        if (!files || !files.length) {
767
+          this.$modal.msgError("请选择要上传的文件")
768
+          return
769
+        }
770
+        const raw = files[0].raw
771
+        const name = (raw.name || "").toLowerCase()
772
+        if (!name.endsWith(".xlsx") && !name.endsWith(".xls")) {
773
+          this.$modal.msgError('请选择后缀为 "xls" 或 "xlsx" 的文件')
774
+          return
775
+        }
776
+        this.importing = true
777
+        this.$modal.loading(this.dmT("importLoading"))
778
+        importLivestockProductOutput(raw, this.importForm.statYear, this.importForm.statMonth)
779
+          .then((res) => {
780
+            this.importOpen = false
781
+            this.showImportResult(res.data || {})
782
+            this.getList()
783
+          })
784
+          .finally(() => {
785
+            this.importing = false
786
+            this.$modal.closeLoading()
787
+            this.resetImportFiles()
788
+          })
789
+      })
790
+    },
791
+    showImportResult(data) {
792
+      const insert = data.insertCount != null ? data.insertCount : 0
793
+      const update = data.updateCount != null ? data.updateCount : 0
794
+      const fail = data.failCount != null ? data.failCount : 0
795
+      let html = this.dmT("importSummary", { insert, update, fail })
796
+      if (data.warnMessages && data.warnMessages.length) {
797
+        html += `<p><strong>${this.dmT("importWarnTitle")}</strong></p><p>${data.warnMessages.join("<br/>")}</p>`
798
+      }
799
+      if (data.failMessages && data.failMessages.length) {
800
+        html += `<p><strong>${this.dmT("importFailTitle")}</strong></p><p>${data.failMessages.join("<br/>")}</p>`
801
+      }
802
+      this.$alert(
803
+        `<div style='overflow:auto;overflow-x:hidden;max-height:70vh;padding:10px 20px 0;'>${html}</div>`,
804
+        this.dmT("importTitle"),
805
+        { dangerouslyUseHTMLString: true }
806
+      )
807
+    }
808
+  }
809
+}
810
+</script>
811
+
812
+<style scoped>
813
+.lpo-import-tip {
814
+  margin: 0 0 12px;
815
+  color: #909399;
816
+  font-size: 12px;
817
+  line-height: 1.5;
818
+}
819
+.lpo-view-text {
820
+  white-space: pre-wrap;
821
+  word-break: break-all;
822
+}
823
+.dm-input-with-unit {
824
+  display: flex;
825
+  align-items: center;
826
+  width: 100%;
827
+}
828
+.dm-input-with-unit__input {
829
+  flex: 1;
830
+  width: 100%;
831
+}
832
+.dm-input-with-unit__suffix {
833
+  margin-left: 8px;
834
+  color: #909399;
835
+  white-space: nowrap;
836
+}
837
+.dm-input-with-unit >>> .el-input-number {
838
+  width: 100%;
839
+}
840
+</style>

+ 182 - 62
ruoyi-ui/src/views/dataModel/yakHerdInventory/index.vue

@@ -20,6 +20,23 @@
20 20
             <el-option v-for="item in townOptions" :key="item.deptId" :label="item.deptName" :value="item.deptId" />
21 21
           </el-select>
22 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="dmCommon('pleaseSelect')"
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>
23 40
         <el-form-item>
24 41
           <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">{{ dmCommon("search") }}</el-button>
25 42
           <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">{{ dmCommon("reset") }}</el-button>
@@ -62,7 +79,8 @@
62 79
         <el-table-column :label="dmT('colStatMonth')" align="center" width="90">
63 80
           <template slot-scope="scope">{{ formatStatMonth(scope.row.statMonth) }}</template>
64 81
         </el-table-column>
65
-        <el-table-column :label="dmT('colTownName')" prop="townName" align="center" min-width="120" :show-overflow-tooltip="true" />
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" />
66 84
         <el-table-column :label="dmT('colVillageCount')" align="center" width="90">
67 85
           <template slot-scope="scope">{{ formatCount(scope.row.villageCount) }}</template>
68 86
         </el-table-column>
@@ -96,10 +114,10 @@
96 114
     </el-card>
97 115
 
98 116
     <el-dialog :title="dialogTitle" :visible.sync="open" width="920px" append-to-body @close="cancel">
99
-      <el-form :key="formKey" ref="form" :model="form" label-width="150px" size="small">
117
+      <el-form :key="formKey" ref="form" :model="form" label-width="168px" size="small">
100 118
         <div class="yhi-section-title">{{ dmT("sectionBasic") }}</div>
101 119
         <el-row :gutter="16">
102
-          <el-col :span="8">
120
+          <el-col :span="12">
103 121
             <el-form-item prop="statYear" :rules="formRules.statYear">
104 122
               <template slot="label">{{ dmT("formStatYear") }}</template>
105 123
               <el-select v-model="form.statYear" :placeholder="dmCommon('pleaseSelect')" style="width: 100%">
@@ -107,7 +125,7 @@
107 125
               </el-select>
108 126
             </el-form-item>
109 127
           </el-col>
110
-          <el-col :span="8">
128
+          <el-col :span="12">
111 129
             <el-form-item prop="statMonth" :rules="formRules.statMonth">
112 130
               <template slot="label">{{ dmT("formStatMonth") }}</template>
113 131
               <el-select v-model="form.statMonth" :placeholder="dmCommon('pleaseSelect')" style="width: 100%">
@@ -115,18 +133,31 @@
115 133
               </el-select>
116 134
             </el-form-item>
117 135
           </el-col>
118
-          <el-col :span="8">
119
-            <el-form-item prop="townDeptId" :rules="formRules.townDeptId">
120
-              <template slot="label">{{ dmT("formTown") }}</template>
121
-              <el-select v-model="form.townDeptId" :placeholder="dmCommon('pleaseSelect')" filterable style="width: 100%">
122
-                <el-option v-for="item in townOptions" :key="'ft-' + item.deptId" :label="item.deptName" :value="item.deptId" />
136
+        </el-row>
137
+        <el-row :gutter="16">
138
+          <el-col :span="24">
139
+            <el-form-item prop="villageDeptId" :rules="formRules.villageDeptId">
140
+              <template slot="label">{{ dmT("formVillage") }}</template>
141
+              <el-select
142
+                v-model="form.villageDeptId"
143
+                :placeholder="dmCommon('pleaseSelect')"
144
+                filterable
145
+                clearable
146
+                style="width: 100%"
147
+              >
148
+                <el-option
149
+                  v-for="item in villageOptions"
150
+                  :key="'f-v-' + item.deptId"
151
+                  :label="item.label"
152
+                  :value="item.deptId"
153
+                />
123 154
               </el-select>
124 155
             </el-form-item>
125 156
           </el-col>
126 157
         </el-row>
127 158
         <div class="yhi-section-title">{{ dmT("sectionInventory") }}</div>
128 159
         <el-row :gutter="16">
129
-          <el-col v-for="field in countFields" :key="field.prop" :span="12">
160
+          <el-col v-for="field in inputCountFields" :key="field.prop" :span="12">
130 161
             <el-form-item :prop="field.prop" :rules="formRules.count">
131 162
               <template slot="label">{{ dmT(field.labelKey) }}</template>
132 163
               <div class="dm-input-with-unit">
@@ -155,7 +186,7 @@
155 186
     </el-dialog>
156 187
 
157 188
     <el-dialog :title="dmCommon('viewTitle')" :visible.sync="viewOpen" width="920px" append-to-body>
158
-      <el-form label-width="150px" size="small">
189
+      <el-form label-width="168px" size="small">
159 190
         <el-row :gutter="16">
160 191
           <el-col :span="12">
161 192
             <el-form-item :label="dmT('formStatYear')">
@@ -173,18 +204,18 @@
173 204
             </el-form-item>
174 205
           </el-col>
175 206
           <el-col :span="12">
176
-            <el-form-item :label="dmT('formVillageDeptId')">
177
-              <span>{{ viewRow.villageDeptId || dash }}</span>
207
+            <el-form-item :label="dmT('formVillage')">
208
+              <span>{{ viewRow.villageName || dash }}</span>
178 209
             </el-form-item>
179 210
           </el-col>
180
-          <el-col :span="12">
181
-            <el-form-item :label="dmT('formVillageName')">
182
-              <span>{{ viewRow.villageName || dash }}</span>
211
+          <el-col v-for="field in inputCountFields" :key="'vi-' + field.prop" :span="12">
212
+            <el-form-item :label="dmT(field.labelKey)">
213
+              <span>{{ formatWithUnit(formatCount(viewRow[field.prop]), field.unitKey) }}</span>
183 214
             </el-form-item>
184 215
           </el-col>
185
-          <el-col v-for="field in countFields" :key="'v-' + field.prop" :span="12">
216
+          <el-col v-for="field in derivedCountFields" :key="'vd-' + field.prop" :span="12">
186 217
             <el-form-item :label="dmT(field.labelKey)">
187
-              <span>{{ formatCount(viewRow[field.prop]) }}</span>
218
+              <span>{{ formatWithUnit(formatCount(viewRow[field.prop]), field.unitKey) }}</span>
188 219
             </el-form-item>
189 220
           </el-col>
190 221
           <el-col :span="24">
@@ -274,6 +305,18 @@
274 305
             <el-option v-for="m in monthOptions" :key="'em-' + m" :label="formatStatMonth(m)" :value="m" />
275 306
           </el-select>
276 307
         </el-form-item>
308
+        <el-form-item prop="townDeptId">
309
+          <template slot="label">{{ dmT("exportTown") }}</template>
310
+          <el-select
311
+            v-model="exportForm.townDeptId"
312
+            :placeholder="dmT('exportTownPh')"
313
+            clearable
314
+            filterable
315
+            style="width: 100%"
316
+          >
317
+            <el-option v-for="item in townOptions" :key="'et-' + item.deptId" :label="item.deptName" :value="item.deptId" />
318
+          </el-select>
319
+        </el-form-item>
277 320
       </el-form>
278 321
       <div slot="footer" class="dialog-footer">
279 322
         <el-button type="primary" :loading="exporting" @click="handleExportSubmit">{{ dmCommon("ok") }}</el-button>
@@ -294,6 +337,7 @@ import {
294 337
   listYakHerdInventoryYearOptions,
295 338
   listYakHerdInventoryMonthOptions,
296 339
   listYakHerdInventoryTownOptions,
340
+  listYakHerdInventoryVillageTree,
297 341
   importYakHerdInventory,
298 342
   downloadYakHerdInventoryTemplate,
299 343
   exportYakHerdInventory
@@ -301,18 +345,29 @@ import {
301 345
 import { blobValidate } from "@/utils/ruoyi"
302 346
 import { saveAs } from "file-saver"
303 347
 
304
-const COUNT_FIELDS = [
348
+/** 手工录入明细(表单可编辑;选填) */
349
+const INPUT_COUNT_FIELDS = [
305 350
   { prop: "villageCount", labelKey: "formVillageCount", unitKey: "unitGe" },
306 351
   { prop: "herdsmanHouseholdCount", labelKey: "formHerdsmanHouseholdCount", unitKey: "unitHousehold" },
307
-  { prop: "yakTotal", labelKey: "formYakTotal", unitKey: "unitHead" },
308
-  { prop: "bullTotal", labelKey: "formBullTotal", unitKey: "unitHead" },
309
-  { prop: "cowTotal", labelKey: "formCowTotal", unitKey: "unitHead" },
310 352
   { prop: "breedingBullCount", labelKey: "formBreedingBullCount", unitKey: "unitHead" },
311 353
   { prop: "bullCastratedCount", labelKey: "formBullCastratedCount", unitKey: "unitHead" },
312
-  { prop: "cowUnder1Count", labelKey: "formCowUnder1Count", unitKey: "unitHead" },
313
-  { prop: "cow13Count", labelKey: "formCow13Count", unitKey: "unitHead" },
314
-  { prop: "cow312Count", labelKey: "formCow312Count", unitKey: "unitHead" },
315
-  { prop: "cowOver12Count", labelKey: "formCowOver12Count", unitKey: "unitHead" }
354
+  { prop: "cowYoungCount", labelKey: "formCowYoungCount", unitKey: "unitHead" },
355
+  { prop: "cowAdultCount", labelKey: "formCowAdultCount", unitKey: "unitHead" },
356
+  { prop: "milkingCowCount", labelKey: "formMilkingCowCount", unitKey: "unitHead" },
357
+  { prop: "fertileCowCount", labelKey: "formFertileCowCount", unitKey: "unitHead" },
358
+  { prop: "sheepTotal", labelKey: "formSheepTotal", unitKey: "unitHead" },
359
+  { prop: "milkingSheepCount", labelKey: "formMilkingSheepCount", unitKey: "unitHead" },
360
+  { prop: "insuredYakCount", labelKey: "formInsuredYakCount", unitKey: "unitHead" }
361
+]
362
+
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" }
316 371
 ]
317 372
 
318 373
 function getCurrentYearMonth() {
@@ -328,24 +383,50 @@ function createEmptyForm() {
328 383
     id: undefined,
329 384
     statYear: undefined,
330 385
     statMonth: undefined,
331
-    townDeptId: undefined,
386
+    villageDeptId: undefined,
332 387
     remark: undefined
333 388
   }
334
-  COUNT_FIELDS.forEach((field) => {
335
-    form[field.prop] = 0
389
+  INPUT_COUNT_FIELDS.forEach((field) => {
390
+    form[field.prop] = undefined
336 391
   })
337 392
   return form
338 393
 }
339 394
 
340
-function normalizeCountFields(data) {
395
+function normalizeInputFields(data) {
341 396
   const row = Object.assign(createEmptyForm(), data || {})
342
-  COUNT_FIELDS.forEach((field) => {
397
+  INPUT_COUNT_FIELDS.forEach((field) => {
343 398
     const val = row[field.prop]
344
-    row[field.prop] = val == null || val === "" ? 0 : val
399
+    row[field.prop] = val == null || val === "" ? undefined : val
345 400
   })
346 401
   return row
347 402
 }
348 403
 
404
+/** 县→乡镇→村 树拍平为村下拉(搜索与新增共用) */
405
+function flattenVillageOptions(tree) {
406
+  const list = []
407
+  ;(tree || []).forEach((county) => {
408
+    ;(county.children || []).forEach((town) => {
409
+      const villages = town.children || []
410
+      if (villages.length) {
411
+        villages.forEach((village) => {
412
+          if (village == null || village.id == null) {
413
+            return
414
+          }
415
+          const townName = town.label || ""
416
+          const villageName = village.label || ""
417
+          list.push({
418
+            deptId: village.id,
419
+            deptName: villageName,
420
+            townName,
421
+            label: townName ? `${townName} / ${villageName}` : villageName
422
+          })
423
+        })
424
+      }
425
+    })
426
+  })
427
+  return list
428
+}
429
+
349 430
 export default {
350 431
   name: "YakHerdInventory",
351 432
   mixins: [dataModelLocaleMixin],
@@ -366,6 +447,7 @@ export default {
366 447
       yearOptions: [],
367 448
       monthOptions: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
368 449
       townOptions: [],
450
+      villageOptions: [],
369 451
       viewRow: {},
370 452
       importForm: {
371 453
         statYear: undefined,
@@ -373,14 +455,16 @@ export default {
373 455
       },
374 456
       exportForm: {
375 457
         statYear: undefined,
376
-        statMonth: undefined
458
+        statMonth: undefined,
459
+        townDeptId: undefined
377 460
       },
378 461
       queryParams: {
379 462
         pageNum: 1,
380 463
         pageSize: 20,
381 464
         statYear: undefined,
382 465
         statMonth: undefined,
383
-        townDeptId: undefined
466
+        townDeptId: undefined,
467
+        villageDeptId: undefined
384 468
       },
385 469
       form: createEmptyForm()
386 470
     }
@@ -389,8 +473,11 @@ export default {
389 473
     dash() {
390 474
       return this.$t("dataModel.status.dash")
391 475
     },
392
-    countFields() {
393
-      return COUNT_FIELDS
476
+    inputCountFields() {
477
+      return INPUT_COUNT_FIELDS
478
+    },
479
+    derivedCountFields() {
480
+      return DERIVED_COUNT_FIELDS
394 481
     },
395 482
     dialogTitle() {
396 483
       return this.dialogEdit ? this.dmT("dialogEdit") : this.dmT("dialogAdd")
@@ -402,11 +489,8 @@ export default {
402 489
           { required: true, message: this.dmT("ruleStatMonthRequired"), trigger: "change" },
403 490
           { validator: this.validateFormStatMonth, trigger: "change" }
404 491
         ],
405
-        townDeptId: [{ required: true, message: this.dmT("ruleTownRequired"), trigger: "change" }],
406
-        count: [
407
-          { required: true, message: this.dmT("ruleCountRequired"), trigger: "change" },
408
-          { validator: this.validateRequiredCount, trigger: "change" }
409
-        ],
492
+        villageDeptId: [{ required: true, message: this.dmT("ruleVillageRequired"), trigger: "change" }],
493
+        count: [{ validator: this.validateOptionalCount, trigger: "change" }],
410 494
         remark: [{ max: 500, message: this.dmCommon("ruleLen500"), trigger: "blur" }]
411 495
       }
412 496
     },
@@ -446,6 +530,21 @@ export default {
446 530
       listYakHerdInventoryTownOptions().then((res) => {
447 531
         this.townOptions = Array.isArray(res.data) ? res.data : []
448 532
       })
533
+      this.loadVillageTree()
534
+    },
535
+    loadVillageTree() {
536
+      return listYakHerdInventoryVillageTree()
537
+        .then((res) => {
538
+          const raw = res && res.data !== undefined ? res.data : res
539
+          const tree = Array.isArray(raw) ? raw : []
540
+          this.villageOptions = flattenVillageOptions(tree)
541
+          if (!this.villageOptions.length) {
542
+            this.$modal.msgWarning(this.dmT("villageTreeEmpty"))
543
+          }
544
+        })
545
+        .catch(() => {
546
+          this.villageOptions = []
547
+        })
449 548
     },
450 549
     formatStatMonth(month) {
451 550
       if (month == null || month === "") {
@@ -492,9 +591,9 @@ export default {
492 591
       }
493 592
       return val
494 593
     },
495
-    validateRequiredCount(rule, value, callback) {
594
+    validateOptionalCount(rule, value, callback) {
496 595
       if (value == null || value === "") {
497
-        callback(new Error(this.dmT("ruleCountRequired")))
596
+        callback()
498 597
         return
499 598
       }
500 599
       if (!Number.isInteger(value) || value < 0) {
@@ -517,6 +616,9 @@ export default {
517 616
       if (this.queryParams.townDeptId != null) {
518 617
         q.townDeptId = this.queryParams.townDeptId
519 618
       }
619
+      if (this.queryParams.villageDeptId != null) {
620
+        q.villageDeptId = this.queryParams.villageDeptId
621
+      }
520 622
       return q
521 623
     },
522 624
     buildPayload() {
@@ -524,11 +626,12 @@ export default {
524 626
       const payload = {
525 627
         statYear: this.form.statYear,
526 628
         statMonth: this.form.statMonth,
527
-        townDeptId: this.form.townDeptId,
629
+        villageDeptId: this.form.villageDeptId,
528 630
         remark: remarkText !== "" ? remarkText : undefined
529 631
       }
530
-      COUNT_FIELDS.forEach((field) => {
531
-        payload[field.prop] = this.form[field.prop]
632
+      INPUT_COUNT_FIELDS.forEach((field) => {
633
+        const val = this.form[field.prop]
634
+        payload[field.prop] = val == null || val === "" ? undefined : val
532 635
       })
533 636
       return payload
534 637
     },
@@ -551,29 +654,36 @@ export default {
551 654
       this.queryParams.statYear = undefined
552 655
       this.queryParams.statMonth = undefined
553 656
       this.queryParams.townDeptId = undefined
657
+      this.queryParams.villageDeptId = undefined
554 658
       this.resetForm("queryForm")
555 659
       this.handleQuery()
556 660
     },
557 661
     handleAdd() {
558
-      this.formKey += 1
559
-      const current = getCurrentYearMonth()
560
-      this.form = createEmptyForm()
561
-      this.form.statYear = current.statYear
562
-      this.form.statMonth = current.statMonth
563
-      this.dialogEdit = false
564
-      this.open = true
565
-      this.$nextTick(() => {
566
-        if (this.$refs.form) {
567
-          this.$refs.form.clearValidate()
568
-        }
569
-      })
662
+      const openDialog = () => {
663
+        this.formKey += 1
664
+        const current = getCurrentYearMonth()
665
+        this.form = createEmptyForm()
666
+        this.form.statYear = current.statYear
667
+        this.form.statMonth = current.statMonth
668
+        this.dialogEdit = false
669
+        this.open = true
670
+        this.$nextTick(() => {
671
+          if (this.$refs.form) {
672
+            this.$refs.form.clearValidate()
673
+          }
674
+        })
675
+      }
676
+      if (!this.villageOptions.length) {
677
+        this.loadVillageTree().finally(openDialog)
678
+      } else {
679
+        openDialog()
680
+      }
570 681
     },
571 682
     handleEdit(row) {
572
-      getYakHerdInventory(row.id).then((res) => {
573
-        const data = res.data || {}
683
+      const openWithData = (data) => {
574 684
         this.formKey += 1
575 685
         this.dialogEdit = true
576
-        this.form = normalizeCountFields(data)
686
+        this.form = normalizeInputFields(data)
577 687
         this.open = true
578 688
         this.viewOpen = false
579 689
         this.$nextTick(() => {
@@ -581,6 +691,14 @@ export default {
581 691
             this.$refs.form.clearValidate()
582 692
           }
583 693
         })
694
+      }
695
+      getYakHerdInventory(row.id).then((res) => {
696
+        const data = res.data || {}
697
+        if (!this.villageOptions.length) {
698
+          this.loadVillageTree().finally(() => openWithData(data))
699
+        } else {
700
+          openWithData(data)
701
+        }
584 702
       })
585 703
     },
586 704
     handleEditFromView() {
@@ -673,6 +791,7 @@ export default {
673 791
       const current = getCurrentYearMonth()
674 792
       this.exportForm.statYear = current.statYear
675 793
       this.exportForm.statMonth = current.statMonth
794
+      this.exportForm.townDeptId = undefined
676 795
       this.exportOpen = true
677 796
       this.$nextTick(() => {
678 797
         if (this.$refs.exportFormRef) {
@@ -684,6 +803,7 @@ export default {
684 803
       this.exporting = false
685 804
       this.exportForm.statYear = undefined
686 805
       this.exportForm.statMonth = undefined
806
+      this.exportForm.townDeptId = undefined
687 807
     },
688 808
     handleExportSubmit() {
689 809
       this.$refs.exportFormRef.validate((valid) => {
@@ -699,7 +819,7 @@ export default {
699 819
         const filename = `${statYear}年${statMonth}月牦牛存栏数据.xlsx`
700 820
         this.exporting = true
701 821
         this.$modal.loading(this.dmT("exportLoading"))
702
-        exportYakHerdInventory(statYear, statMonth)
822
+        exportYakHerdInventory(statYear, statMonth, this.exportForm.townDeptId)
703 823
           .then(async (data) => {
704 824
             if (blobValidate(data)) {
705 825
               saveAs(new Blob([data], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }), filename)

+ 203 - 43
ruoyi-ui/src/views/dataModel/yakOutboundReport/index.vue

@@ -20,6 +20,23 @@
20 20
             <el-option v-for="item in townOptions" :key="item.deptId" :label="item.deptName" :value="item.deptId" />
21 21
           </el-select>
22 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="dmCommon('pleaseSelect')"
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>
23 40
         <el-form-item>
24 41
           <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">{{ dmCommon("search") }}</el-button>
25 42
           <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">{{ dmCommon("reset") }}</el-button>
@@ -62,7 +79,8 @@
62 79
         <el-table-column :label="dmT('colStatMonth')" align="center" width="90">
63 80
           <template slot-scope="scope">{{ formatStatMonth(scope.row.statMonth) }}</template>
64 81
         </el-table-column>
65
-        <el-table-column :label="dmT('colTownName')" prop="townName" align="center" min-width="120" :show-overflow-tooltip="true" />
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" />
66 84
         <el-table-column :label="dmT('colFarmerHouseholdCount')" align="center" width="100">
67 85
           <template slot-scope="scope">{{ formatCount(scope.row.farmerHouseholdCount) }}</template>
68 86
         </el-table-column>
@@ -72,9 +90,15 @@
72 90
         <el-table-column :label="dmT('colYakOutboundCount')" align="center" width="110">
73 91
           <template slot-scope="scope">{{ formatCount(scope.row.yakOutboundCount) }}</template>
74 92
         </el-table-column>
75
-        <el-table-column :label="dmT('colSelfConsumptionCattle')" align="center" width="120">
93
+        <el-table-column :label="dmT('colOutboundTotal')" align="center" width="120">
94
+          <template slot-scope="scope">{{ formatCount(sumOutboundTotal(scope.row)) }}</template>
95
+        </el-table-column>
96
+        <el-table-column :label="dmT('colSelfConsumptionCattle')" align="center" width="100">
76 97
           <template slot-scope="scope">{{ formatCount(scope.row.selfConsumptionCattleCount) }}</template>
77 98
         </el-table-column>
99
+        <el-table-column :label="dmT('colSelfConsumptionTotal')" align="center" width="120">
100
+          <template slot-scope="scope">{{ formatCount(sumSelfConsumptionTotal(scope.row)) }}</template>
101
+        </el-table-column>
78 102
         <el-table-column :label="dmCommon('colOp')" align="center" class-name="small-padding fixed-width" width="180" fixed="right">
79 103
           <template slot-scope="scope">
80 104
             <el-button v-hasPermi="['dataModel:yakOutboundReport:query']" type="text" size="mini" @click="handleView(scope.row)">{{ dmCommon("view") }}</el-button>
@@ -96,7 +120,7 @@
96 120
       <el-form :key="formKey" ref="form" :model="form" label-width="168px" size="small">
97 121
         <div class="yor-section-title">{{ dmT("sectionBasic") }}</div>
98 122
         <el-row :gutter="16">
99
-          <el-col :span="8">
123
+          <el-col :span="12">
100 124
             <el-form-item prop="statYear" :rules="formRules.statYear">
101 125
               <template slot="label">{{ dmT("formStatYear") }}</template>
102 126
               <el-select v-model="form.statYear" :placeholder="dmCommon('pleaseSelect')" style="width: 100%">
@@ -104,7 +128,7 @@
104 128
               </el-select>
105 129
             </el-form-item>
106 130
           </el-col>
107
-          <el-col :span="8">
131
+          <el-col :span="12">
108 132
             <el-form-item prop="statMonth" :rules="formRules.statMonth">
109 133
               <template slot="label">{{ dmT("formStatMonth") }}</template>
110 134
               <el-select v-model="form.statMonth" :placeholder="dmCommon('pleaseSelect')" style="width: 100%">
@@ -112,11 +136,24 @@
112 136
               </el-select>
113 137
             </el-form-item>
114 138
           </el-col>
115
-          <el-col :span="8">
116
-            <el-form-item prop="townDeptId" :rules="formRules.townDeptId">
117
-              <template slot="label">{{ dmT("formTown") }}</template>
118
-              <el-select v-model="form.townDeptId" :placeholder="dmCommon('pleaseSelect')" filterable style="width: 100%">
119
-                <el-option v-for="item in townOptions" :key="'ft-' + item.deptId" :label="item.deptName" :value="item.deptId" />
139
+        </el-row>
140
+        <el-row :gutter="16">
141
+          <el-col :span="24">
142
+            <el-form-item prop="villageDeptId" :rules="formRules.villageDeptId">
143
+              <template slot="label">{{ dmT("formVillage") }}</template>
144
+              <el-select
145
+                v-model="form.villageDeptId"
146
+                :placeholder="dmCommon('pleaseSelect')"
147
+                filterable
148
+                clearable
149
+                style="width: 100%"
150
+              >
151
+                <el-option
152
+                  v-for="item in villageOptions"
153
+                  :key="'f-v-' + item.deptId"
154
+                  :label="item.label"
155
+                  :value="item.deptId"
156
+                />
120 157
               </el-select>
121 158
             </el-form-item>
122 159
           </el-col>
@@ -189,7 +226,7 @@
189 226
       </div>
190 227
     </el-dialog>
191 228
 
192
-    <el-dialog :title="dmCommon('viewTitle')" :visible.sync="viewOpen" width="720px" append-to-body>
229
+    <el-dialog :title="dmCommon('viewTitle')" :visible.sync="viewOpen" width="920px" append-to-body>
193 230
       <el-form label-width="168px" size="small">
194 231
         <el-row :gutter="16">
195 232
           <el-col :span="12">
@@ -207,9 +244,29 @@
207 244
               <span>{{ viewRow.townName || dash }}</span>
208 245
             </el-form-item>
209 246
           </el-col>
210
-          <el-col v-for="field in viewFields" :key="'v-' + field.prop" :span="12">
247
+          <el-col :span="12">
248
+            <el-form-item :label="dmT('formVillage')">
249
+              <span>{{ viewRow.villageName || dash }}</span>
250
+            </el-form-item>
251
+          </el-col>
252
+          <el-col v-for="field in inputCountFields" :key="'v-' + field.prop" :span="12">
211 253
             <el-form-item :label="dmT(field.labelKey)">
212
-              <span>{{ formatCount(viewRow[field.prop]) }}</span>
254
+              <span>{{ formatWithUnit(formatCount(viewRow[field.prop]), field.unitKey) }}</span>
255
+            </el-form-item>
256
+          </el-col>
257
+          <el-col :span="12">
258
+            <el-form-item :label="dmT('formOutboundTotal')">
259
+              <span>{{ formatWithUnit(formatCount(sumOutboundTotal(viewRow)), "unitHead") }}</span>
260
+            </el-form-item>
261
+          </el-col>
262
+          <el-col :span="12">
263
+            <el-form-item :label="dmT('formSelfConsumptionTotal')">
264
+              <span>{{ formatWithUnit(formatCount(sumSelfConsumptionTotal(viewRow)), "unitHead") }}</span>
265
+            </el-form-item>
266
+          </el-col>
267
+          <el-col :span="24">
268
+            <el-form-item :label="dmT('formRemark')">
269
+              <span class="yor-view-text">{{ viewRow.remark || dash }}</span>
213 270
             </el-form-item>
214 271
           </el-col>
215 272
         </el-row>
@@ -274,6 +331,18 @@
274 331
             <el-option v-for="m in monthOptions" :key="'em-' + m" :label="formatStatMonth(m)" :value="m" />
275 332
           </el-select>
276 333
         </el-form-item>
334
+        <el-form-item prop="townDeptId">
335
+          <template slot="label">{{ dmT("exportTown") }}</template>
336
+          <el-select
337
+            v-model="exportForm.townDeptId"
338
+            :placeholder="dmT('exportTownPh')"
339
+            clearable
340
+            filterable
341
+            style="width: 100%"
342
+          >
343
+            <el-option v-for="item in townOptions" :key="'et-' + item.deptId" :label="item.deptName" :value="item.deptId" />
344
+          </el-select>
345
+        </el-form-item>
277 346
       </el-form>
278 347
       <div slot="footer" class="dialog-footer">
279 348
         <el-button type="primary" :loading="exporting" @click="handleExportSubmit">{{ dmCommon("ok") }}</el-button>
@@ -294,6 +363,7 @@ import {
294 363
   listYakOutboundReportYearOptions,
295 364
   listYakOutboundReportMonthOptions,
296 365
   listYakOutboundReportTownOptions,
366
+  listYakOutboundReportVillageTree,
297 367
   importYakOutboundReport,
298 368
   downloadYakOutboundReportTemplate,
299 369
   exportYakOutboundReport
@@ -315,11 +385,19 @@ const COUNT_FIELDS = [
315 385
   { prop: "selfConsumptionGoatCount", labelKey: "formSelfConsumptionGoatCount", unitKey: "unitSheep", section: "selfConsumption" }
316 386
 ]
317 387
 
318
-const VIEW_FIELDS = [
319
-  { prop: "farmerHouseholdCount", labelKey: "formFarmerHouseholdCount" },
320
-  { prop: "farmerPopulationCount", labelKey: "formFarmerPopulationCount" },
321
-  { prop: "yakOutboundCount", labelKey: "formYakOutboundCount" },
322
-  { prop: "selfConsumptionCattleCount", labelKey: "formSelfConsumptionCattleCount" }
388
+const OUTBOUND_TOTAL_PROPS = [
389
+  "yakOutboundCount",
390
+  "cattleOutboundCount",
391
+  "sheepOutboundCount",
392
+  "goatOutboundCount",
393
+  "horseMuleOutboundCount",
394
+  "donkeyOutboundCount"
395
+]
396
+
397
+const SELF_CONSUMPTION_TOTAL_PROPS = [
398
+  "selfConsumptionCattleCount",
399
+  "selfConsumptionSheepCount",
400
+  "selfConsumptionGoatCount"
323 401
 ]
324 402
 
325 403
 function getCurrentYearMonth() {
@@ -335,11 +413,11 @@ function createEmptyForm() {
335 413
     id: undefined,
336 414
     statYear: undefined,
337 415
     statMonth: undefined,
338
-    townDeptId: undefined,
416
+    villageDeptId: undefined,
339 417
     remark: undefined
340 418
   }
341 419
   COUNT_FIELDS.forEach((field) => {
342
-    form[field.prop] = 0
420
+    form[field.prop] = undefined
343 421
   })
344 422
   return form
345 423
 }
@@ -348,11 +426,43 @@ function normalizeCountFields(data) {
348 426
   const row = Object.assign(createEmptyForm(), data || {})
349 427
   COUNT_FIELDS.forEach((field) => {
350 428
     const val = row[field.prop]
351
-    row[field.prop] = val == null || val === "" ? 0 : val
429
+    row[field.prop] = val == null || val === "" ? undefined : val
352 430
   })
353 431
   return row
354 432
 }
355 433
 
434
+function flattenVillageOptions(tree) {
435
+  const list = []
436
+  ;(tree || []).forEach((county) => {
437
+    ;(county.children || []).forEach((town) => {
438
+      ;(town.children || []).forEach((village) => {
439
+        if (village == null || village.id == null) {
440
+          return
441
+        }
442
+        const townName = town.label || ""
443
+        const villageName = village.label || ""
444
+        list.push({
445
+          deptId: village.id,
446
+          deptName: villageName,
447
+          townName,
448
+          label: townName ? `${townName} / ${villageName}` : villageName
449
+        })
450
+      })
451
+    })
452
+  })
453
+  return list
454
+}
455
+
456
+function sumProps(row, props) {
457
+  if (!row) {
458
+    return 0
459
+  }
460
+  return props.reduce((sum, prop) => {
461
+    const n = Number(row[prop])
462
+    return sum + (Number.isFinite(n) ? n : 0)
463
+  }, 0)
464
+}
465
+
356 466
 export default {
357 467
   name: "YakOutboundReport",
358 468
   mixins: [dataModelLocaleMixin],
@@ -373,6 +483,7 @@ export default {
373 483
       yearOptions: [],
374 484
       monthOptions: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
375 485
       townOptions: [],
486
+      villageOptions: [],
376 487
       viewRow: {},
377 488
       importForm: {
378 489
         statYear: undefined,
@@ -380,14 +491,16 @@ export default {
380 491
       },
381 492
       exportForm: {
382 493
         statYear: undefined,
383
-        statMonth: undefined
494
+        statMonth: undefined,
495
+        townDeptId: undefined
384 496
       },
385 497
       queryParams: {
386 498
         pageNum: 1,
387 499
         pageSize: 20,
388 500
         statYear: undefined,
389 501
         statMonth: undefined,
390
-        townDeptId: undefined
502
+        townDeptId: undefined,
503
+        villageDeptId: undefined
391 504
       },
392 505
       form: createEmptyForm()
393 506
     }
@@ -396,6 +509,9 @@ export default {
396 509
     dash() {
397 510
       return this.$t("dataModel.status.dash")
398 511
     },
512
+    inputCountFields() {
513
+      return COUNT_FIELDS
514
+    },
399 515
     farmerCountFields() {
400 516
       return COUNT_FIELDS.filter((field) => field.section === "farmer")
401 517
     },
@@ -405,9 +521,6 @@ export default {
405 521
     selfConsumptionCountFields() {
406 522
       return COUNT_FIELDS.filter((field) => field.section === "selfConsumption")
407 523
     },
408
-    viewFields() {
409
-      return VIEW_FIELDS
410
-    },
411 524
     dialogTitle() {
412 525
       return this.dialogEdit ? this.dmT("dialogEdit") : this.dmT("dialogAdd")
413 526
     },
@@ -418,7 +531,7 @@ export default {
418 531
           { required: true, message: this.dmT("ruleStatMonthRequired"), trigger: "change" },
419 532
           { validator: this.validateFormStatMonth, trigger: "change" }
420 533
         ],
421
-        townDeptId: [{ required: true, message: this.dmT("ruleTownRequired"), trigger: "change" }],
534
+        villageDeptId: [{ required: true, message: this.dmT("ruleVillageRequired"), trigger: "change" }],
422 535
         count: [{ validator: this.validateOptionalCount, trigger: "change" }],
423 536
         remark: [{ max: 500, message: this.dmCommon("ruleLen500"), trigger: "blur" }]
424 537
       }
@@ -459,6 +572,27 @@ export default {
459 572
       listYakOutboundReportTownOptions().then((res) => {
460 573
         this.townOptions = Array.isArray(res.data) ? res.data : []
461 574
       })
575
+      this.loadVillageTree()
576
+    },
577
+    loadVillageTree() {
578
+      return listYakOutboundReportVillageTree()
579
+        .then((res) => {
580
+          const raw = res && res.data !== undefined ? res.data : res
581
+          const tree = Array.isArray(raw) ? raw : []
582
+          this.villageOptions = flattenVillageOptions(tree)
583
+          if (!this.villageOptions.length) {
584
+            this.$modal.msgWarning(this.dmT("villageTreeEmpty"))
585
+          }
586
+        })
587
+        .catch(() => {
588
+          this.villageOptions = []
589
+        })
590
+    },
591
+    sumOutboundTotal(row) {
592
+      return sumProps(row, OUTBOUND_TOTAL_PROPS)
593
+    },
594
+    sumSelfConsumptionTotal(row) {
595
+      return sumProps(row, SELF_CONSUMPTION_TOTAL_PROPS)
462 596
     },
463 597
     formatStatMonth(month) {
464 598
       if (month == null || month === "") {
@@ -530,6 +664,9 @@ export default {
530 664
       if (this.queryParams.townDeptId != null) {
531 665
         q.townDeptId = this.queryParams.townDeptId
532 666
       }
667
+      if (this.queryParams.villageDeptId != null) {
668
+        q.villageDeptId = this.queryParams.villageDeptId
669
+      }
533 670
       return q
534 671
     },
535 672
     buildPayload() {
@@ -537,11 +674,12 @@ export default {
537 674
       const payload = {
538 675
         statYear: this.form.statYear,
539 676
         statMonth: this.form.statMonth,
540
-        townDeptId: this.form.townDeptId,
677
+        villageDeptId: this.form.villageDeptId,
541 678
         remark: remarkText !== "" ? remarkText : undefined
542 679
       }
543 680
       COUNT_FIELDS.forEach((field) => {
544
-        payload[field.prop] = this.form[field.prop]
681
+        const val = this.form[field.prop]
682
+        payload[field.prop] = val == null || val === "" ? undefined : val
545 683
       })
546 684
       return payload
547 685
     },
@@ -564,26 +702,33 @@ export default {
564 702
       this.queryParams.statYear = undefined
565 703
       this.queryParams.statMonth = undefined
566 704
       this.queryParams.townDeptId = undefined
705
+      this.queryParams.villageDeptId = undefined
567 706
       this.resetForm("queryForm")
568 707
       this.handleQuery()
569 708
     },
570 709
     handleAdd() {
571
-      this.formKey += 1
572
-      const current = getCurrentYearMonth()
573
-      this.form = createEmptyForm()
574
-      this.form.statYear = current.statYear
575
-      this.form.statMonth = current.statMonth
576
-      this.dialogEdit = false
577
-      this.open = true
578
-      this.$nextTick(() => {
579
-        if (this.$refs.form) {
580
-          this.$refs.form.clearValidate()
581
-        }
582
-      })
710
+      const openDialog = () => {
711
+        this.formKey += 1
712
+        const current = getCurrentYearMonth()
713
+        this.form = createEmptyForm()
714
+        this.form.statYear = current.statYear
715
+        this.form.statMonth = current.statMonth
716
+        this.dialogEdit = false
717
+        this.open = true
718
+        this.$nextTick(() => {
719
+          if (this.$refs.form) {
720
+            this.$refs.form.clearValidate()
721
+          }
722
+        })
723
+      }
724
+      if (!this.villageOptions.length) {
725
+        this.loadVillageTree().finally(openDialog)
726
+      } else {
727
+        openDialog()
728
+      }
583 729
     },
584 730
     handleEdit(row) {
585
-      getYakOutboundReport(row.id).then((res) => {
586
-        const data = res.data || {}
731
+      const openWithData = (data) => {
587 732
         this.formKey += 1
588 733
         this.dialogEdit = true
589 734
         this.form = normalizeCountFields(data)
@@ -594,6 +739,14 @@ export default {
594 739
             this.$refs.form.clearValidate()
595 740
           }
596 741
         })
742
+      }
743
+      getYakOutboundReport(row.id).then((res) => {
744
+        const data = res.data || {}
745
+        if (!this.villageOptions.length) {
746
+          this.loadVillageTree().finally(() => openWithData(data))
747
+        } else {
748
+          openWithData(data)
749
+        }
597 750
       })
598 751
     },
599 752
     handleEditFromView() {
@@ -686,6 +839,7 @@ export default {
686 839
       const current = getCurrentYearMonth()
687 840
       this.exportForm.statYear = current.statYear
688 841
       this.exportForm.statMonth = current.statMonth
842
+      this.exportForm.townDeptId = undefined
689 843
       this.exportOpen = true
690 844
       this.$nextTick(() => {
691 845
         if (this.$refs.exportFormRef) {
@@ -697,6 +851,7 @@ export default {
697 851
       this.exporting = false
698 852
       this.exportForm.statYear = undefined
699 853
       this.exportForm.statMonth = undefined
854
+      this.exportForm.townDeptId = undefined
700 855
     },
701 856
     handleExportSubmit() {
702 857
       this.$refs.exportFormRef.validate((valid) => {
@@ -712,7 +867,7 @@ export default {
712 867
         const filename = `${statYear}年${statMonth}月牦牛出栏数据.xlsx`
713 868
         this.exporting = true
714 869
         this.$modal.loading(this.dmT("exportLoading"))
715
-        exportYakOutboundReport(statYear, statMonth)
870
+        exportYakOutboundReport(statYear, statMonth, this.exportForm.townDeptId)
716 871
           .then(async (data) => {
717 872
             if (blobValidate(data)) {
718 873
               saveAs(new Blob([data], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }), filename)
@@ -795,6 +950,11 @@ export default {
795 950
   border-left: 3px solid #409eff;
796 951
 }
797 952
 
953
+.yor-view-text {
954
+  white-space: pre-wrap;
955
+  word-break: break-word;
956
+}
957
+
798 958
 .yor-import-tip {
799 959
   margin: 0 0 12px;
800 960
   font-size: 12px;