西藏巴青项目

index.vue 56KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388
  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 prop="enterpriseName">
  41. <template slot="label">{{ dmT("queryEnterpriseName") }}</template>
  42. <el-input
  43. v-model="queryParams.enterpriseName"
  44. :placeholder="dmT('phEnterpriseName')"
  45. clearable
  46. style="width: 180px"
  47. @keyup.enter.native="handleQuery"
  48. />
  49. </el-form-item>
  50. <el-form-item>
  51. <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">{{ dmCommon("search") }}</el-button>
  52. <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">{{ dmCommon("reset") }}</el-button>
  53. <el-button
  54. v-hasPermi="['dataModel:largeLivestockFarmer:add']"
  55. type="primary"
  56. plain
  57. icon="el-icon-plus"
  58. size="mini"
  59. @click="handleAdd"
  60. >{{ dmCommon("add") }}</el-button>
  61. <el-button
  62. v-hasPermi="['dataModel:largeLivestockFarmer:import']"
  63. type="info"
  64. plain
  65. icon="el-icon-upload2"
  66. size="mini"
  67. @click="handleImportOpen"
  68. >{{ dmT("btnImport") }}</el-button>
  69. <el-button
  70. v-hasPermi="['dataModel:largeLivestockFarmer:export']"
  71. type="warning"
  72. plain
  73. icon="el-icon-download"
  74. size="mini"
  75. @click="handleExportOpen"
  76. >{{ dmCommon("export") }}</el-button>
  77. </el-form-item>
  78. </el-form>
  79. </el-card>
  80. <br />
  81. <el-card shadow="never">
  82. <el-table v-loading="loading" :data="tableList" border>
  83. <template slot="empty">
  84. <span>{{ dmT("emptyList") }}</span>
  85. </template>
  86. <el-table-column :label="dmT('colStatYear')" prop="statYear" align="center" width="90" />
  87. <el-table-column :label="dmT('colStatMonth')" align="center" width="80">
  88. <template slot-scope="scope">{{ formatStatMonth(scope.row.statMonth) }}</template>
  89. </el-table-column>
  90. <el-table-column :label="dmT('colTownName')" prop="townName" align="center" min-width="100" :show-overflow-tooltip="true" />
  91. <el-table-column :label="dmT('colVillageName')" prop="villageName" align="center" min-width="100" :show-overflow-tooltip="true" />
  92. <el-table-column :label="dmT('colEnterpriseName')" prop="enterpriseName" align="center" min-width="140" :show-overflow-tooltip="true" />
  93. <el-table-column :label="dmT('colLegalRepresentative')" prop="legalRepresentative" align="center" min-width="90" :show-overflow-tooltip="true" />
  94. <el-table-column :label="dmT('colEnterpriseType')" prop="enterpriseType" align="center" min-width="110" :show-overflow-tooltip="true" />
  95. <el-table-column :label="dmT('colRegisteredCapital')" align="center" width="100">
  96. <template slot-scope="scope">{{ formatDecimal(scope.row.registeredCapital) }}</template>
  97. </el-table-column>
  98. <el-table-column :label="dmT('colEstablishDate')" prop="establishDate" align="center" width="110" :show-overflow-tooltip="true" />
  99. <el-table-column :label="dmT('colCattleYearEndStock')" align="center" width="90">
  100. <template slot-scope="scope">{{ formatCount(scope.row.cattleYearEndStock) }}</template>
  101. </el-table-column>
  102. <el-table-column :label="dmT('colCattleOutbound')" align="center" width="90">
  103. <template slot-scope="scope">{{ formatCount(scope.row.cattleOutbound) }}</template>
  104. </el-table-column>
  105. <el-table-column :label="dmT('colGrasslandArea')" align="center" width="100">
  106. <template slot-scope="scope">{{ formatDecimal(scope.row.grasslandAreaSubtotal) }}</template>
  107. </el-table-column>
  108. <el-table-column :label="dmCommon('colOp')" align="center" class-name="small-padding fixed-width" width="180" fixed="right">
  109. <template slot-scope="scope">
  110. <el-button v-hasPermi="['dataModel:largeLivestockFarmer:query']" type="text" size="mini" @click="handleView(scope.row)">{{ dmCommon("view") }}</el-button>
  111. <el-button v-hasPermi="['dataModel:largeLivestockFarmer:edit']" type="text" size="mini" @click="handleEdit(scope.row)">{{ dmCommon("edit") }}</el-button>
  112. <el-button v-hasPermi="['dataModel:largeLivestockFarmer:remove']" type="text" size="mini" @click="handleDelete(scope.row)">{{ dmCommon("delete") }}</el-button>
  113. </template>
  114. </el-table-column>
  115. </el-table>
  116. <pagination
  117. v-show="total > 0"
  118. :total="total"
  119. :page.sync="queryParams.pageNum"
  120. :limit.sync="queryParams.pageSize"
  121. @pagination="getList"
  122. />
  123. </el-card>
  124. <el-dialog :title="dialogTitle" :visible.sync="open" width="980px" append-to-body @close="cancel">
  125. <el-form :key="formKey" ref="form" :model="form" class="llf-form" label-width="220px" size="small">
  126. <div class="llf-section-title">{{ dmT("sectionBasic") }}</div>
  127. <el-row :gutter="16">
  128. <el-col :span="12">
  129. <el-form-item prop="statYear" :rules="formRules.statYear">
  130. <template slot="label">{{ dmT("formStatYear") }}</template>
  131. <el-select v-model="form.statYear" :placeholder="dmCommon('pleaseSelect')" style="width: 100%">
  132. <el-option v-for="y in yearOptions" :key="'f-' + y" :label="String(y)" :value="y" />
  133. </el-select>
  134. </el-form-item>
  135. </el-col>
  136. <el-col :span="12">
  137. <el-form-item prop="statMonth" :rules="formRules.statMonth">
  138. <template slot="label">{{ dmT("formStatMonth") }}</template>
  139. <el-select v-model="form.statMonth" :placeholder="dmCommon('pleaseSelect')" style="width: 100%">
  140. <el-option v-for="m in monthOptions" :key="'fm-' + m" :label="formatStatMonth(m)" :value="m" />
  141. </el-select>
  142. </el-form-item>
  143. </el-col>
  144. <el-col :span="24">
  145. <el-form-item prop="villageDeptId" :rules="formRules.villageDeptId">
  146. <template slot="label">{{ dmT("formVillage") }}</template>
  147. <el-select
  148. v-model="form.villageDeptId"
  149. :placeholder="dmT('phVillageSearch')"
  150. filterable
  151. clearable
  152. style="width: 100%"
  153. >
  154. <el-option
  155. v-for="item in villageOptions"
  156. :key="'f-v-' + item.deptId"
  157. :label="item.label"
  158. :value="item.deptId"
  159. />
  160. </el-select>
  161. </el-form-item>
  162. </el-col>
  163. </el-row>
  164. <div class="llf-section-title">{{ dmT("sectionFarmerInfo") }}</div>
  165. <el-row :gutter="16">
  166. <el-col :span="12">
  167. <el-form-item prop="enterpriseName" :rules="formRules.enterpriseName">
  168. <template slot="label">{{ dmT("formEnterpriseName") }}</template>
  169. <el-input v-model="form.enterpriseName" :placeholder="dmT('phEnterpriseName')" maxlength="200" show-word-limit />
  170. </el-form-item>
  171. </el-col>
  172. <el-col :span="12">
  173. <el-form-item prop="legalRepresentative" :rules="formRules.legalRepresentative">
  174. <template slot="label">{{ dmT("formLegalRepresentative") }}</template>
  175. <el-input v-model="form.legalRepresentative" maxlength="64" show-word-limit />
  176. </el-form-item>
  177. </el-col>
  178. <el-col :span="12">
  179. <el-form-item prop="enterpriseType">
  180. <template slot="label">{{ dmT("formEnterpriseType") }}</template>
  181. <el-select v-model="form.enterpriseType" :placeholder="dmCommon('pleaseSelect')" style="width: 100%">
  182. <el-option v-for="item in enterpriseTypeOptions" :key="item" :label="item" :value="item" />
  183. </el-select>
  184. </el-form-item>
  185. </el-col>
  186. <el-col :span="12">
  187. <el-form-item prop="registeredCapital" :rules="formRules.decimal">
  188. <template slot="label">{{ dmT("formRegisteredCapital") }}</template>
  189. <div class="dm-input-with-unit">
  190. <el-input-number
  191. v-model="form.registeredCapital"
  192. :min="0"
  193. :precision="4"
  194. controls-position="right"
  195. class="dm-input-with-unit__input"
  196. />
  197. <span class="dm-input-with-unit__suffix">{{ dmT("unitWanYuan") }}</span>
  198. </div>
  199. </el-form-item>
  200. </el-col>
  201. <el-col :span="12">
  202. <el-form-item prop="establishDate">
  203. <template slot="label">{{ dmT("formEstablishDate") }}</template>
  204. <el-date-picker
  205. v-model="form.establishDate"
  206. type="date"
  207. value-format="yyyy-MM-dd"
  208. :placeholder="dmCommon('pleaseSelect')"
  209. clearable
  210. style="width: 100%"
  211. />
  212. </el-form-item>
  213. </el-col>
  214. <el-col :span="12">
  215. <el-form-item prop="livestockLaborCount" :rules="formRules.count">
  216. <template slot="label">{{ dmT("formLivestockLaborCount") }}</template>
  217. <div class="dm-input-with-unit">
  218. <el-input-number
  219. v-model="form.livestockLaborCount"
  220. :min="0"
  221. :precision="0"
  222. controls-position="right"
  223. class="dm-input-with-unit__input"
  224. />
  225. <span class="dm-input-with-unit__suffix">{{ dmT("unitPerson") }}</span>
  226. </div>
  227. </el-form-item>
  228. </el-col>
  229. </el-row>
  230. <div class="llf-section-title">{{ dmT("sectionStock") }}</div>
  231. <el-row :gutter="16">
  232. <el-col v-for="field in stockInventoryFields" :key="field.prop" :span="12">
  233. <el-form-item :prop="field.prop" :rules="formRules.count">
  234. <template slot="label">{{ dmT(field.labelKey) }}</template>
  235. <div class="dm-input-with-unit">
  236. <el-input-number
  237. v-model="form[field.prop]"
  238. :min="0"
  239. :precision="0"
  240. controls-position="right"
  241. class="dm-input-with-unit__input"
  242. />
  243. <span class="dm-input-with-unit__suffix">{{ dmT(field.unitKey) }}</span>
  244. </div>
  245. </el-form-item>
  246. </el-col>
  247. <el-col :span="12">
  248. <el-form-item>
  249. <template slot="label">{{ dmT("formStockSubtotal") }}</template>
  250. <div class="dm-input-with-unit">
  251. <el-input-number :value="stockSubtotalDisplay" :controls="false" disabled class="dm-input-with-unit__input" />
  252. <span class="dm-input-with-unit__suffix">{{ dmT("unitHeadSheepHorse") }}</span>
  253. </div>
  254. </el-form-item>
  255. </el-col>
  256. </el-row>
  257. <div class="llf-section-title">{{ dmT("sectionOutbound") }}</div>
  258. <el-row :gutter="16">
  259. <el-col v-for="field in stockOutboundFields" :key="field.prop" :span="12">
  260. <el-form-item :prop="field.prop" :rules="formRules.count">
  261. <template slot="label">{{ dmT(field.labelKey) }}</template>
  262. <div class="dm-input-with-unit">
  263. <el-input-number
  264. v-model="form[field.prop]"
  265. :min="0"
  266. :precision="0"
  267. controls-position="right"
  268. class="dm-input-with-unit__input"
  269. />
  270. <span class="dm-input-with-unit__suffix">{{ dmT(field.unitKey) }}</span>
  271. </div>
  272. </el-form-item>
  273. </el-col>
  274. <el-col :span="12">
  275. <el-form-item>
  276. <template slot="label">{{ dmT("formOutboundSubtotal") }}</template>
  277. <div class="dm-input-with-unit">
  278. <el-input-number :value="outboundSubtotalDisplay" :controls="false" disabled class="dm-input-with-unit__input" />
  279. <span class="dm-input-with-unit__suffix">{{ dmT("unitHeadSheepHorse") }}</span>
  280. </div>
  281. </el-form-item>
  282. </el-col>
  283. </el-row>
  284. <div class="llf-section-title">{{ dmT("sectionGrassland") }}</div>
  285. <el-row :gutter="16">
  286. <el-col v-for="field in grasslandDecimalFields" :key="field.prop" :span="12">
  287. <el-form-item :prop="field.prop" :rules="formRules.decimal">
  288. <template slot="label">{{ dmT(field.labelKey) }}</template>
  289. <div class="dm-input-with-unit">
  290. <el-input-number
  291. v-model="form[field.prop]"
  292. :min="0"
  293. :precision="4"
  294. controls-position="right"
  295. class="dm-input-with-unit__input"
  296. />
  297. <span class="dm-input-with-unit__suffix">{{ dmT(field.unitKey) }}</span>
  298. </div>
  299. </el-form-item>
  300. </el-col>
  301. <el-col :span="12">
  302. <el-form-item>
  303. <template slot="label">{{ dmT("formGrasslandAreaSubtotal") }}</template>
  304. <div class="dm-input-with-unit">
  305. <el-input :value="grasslandAreaSubtotalDisplay" disabled class="dm-input-with-unit__input" />
  306. <span class="dm-input-with-unit__suffix">{{ dmT("unitMu") }}</span>
  307. </div>
  308. </el-form-item>
  309. </el-col>
  310. <el-col :span="12">
  311. <el-form-item>
  312. <template slot="label">{{ dmT("formIsGrassBalanced") }}</template>
  313. <el-input :value="isGrassBalancedDisplay" disabled />
  314. </el-form-item>
  315. </el-col>
  316. </el-row>
  317. <div class="llf-section-title">{{ dmT("sectionFinance") }}</div>
  318. <el-row :gutter="16">
  319. <el-col :span="12">
  320. <el-form-item prop="income" :rules="formRules.decimal">
  321. <template slot="label">{{ dmT("formIncome") }}</template>
  322. <div class="dm-input-with-unit">
  323. <el-input-number v-model="form.income" :min="0" :precision="4" controls-position="right" class="dm-input-with-unit__input" />
  324. <span class="dm-input-with-unit__suffix">{{ dmT("unitWanYuan") }}</span>
  325. </div>
  326. </el-form-item>
  327. </el-col>
  328. <el-col :span="12">
  329. <el-form-item prop="expense" :rules="formRules.decimal">
  330. <template slot="label">{{ dmT("formExpense") }}</template>
  331. <div class="dm-input-with-unit">
  332. <el-input-number v-model="form.expense" :min="0" :precision="4" controls-position="right" class="dm-input-with-unit__input" />
  333. <span class="dm-input-with-unit__suffix">{{ dmT("unitWanYuan") }}</span>
  334. </div>
  335. </el-form-item>
  336. </el-col>
  337. <el-col :span="12">
  338. <el-form-item>
  339. <template slot="label">{{ dmT("formProfit") }}</template>
  340. <div class="dm-input-with-unit">
  341. <el-input :value="profitDisplay" disabled class="dm-input-with-unit__input" />
  342. <span class="dm-input-with-unit__suffix">{{ dmT("unitWanYuan") }}</span>
  343. </div>
  344. </el-form-item>
  345. </el-col>
  346. </el-row>
  347. <div class="llf-section-title">{{ dmT("sectionSubsidy") }}</div>
  348. <el-row :gutter="16">
  349. <el-col :span="12">
  350. <el-form-item prop="hasSubsidy">
  351. <template slot="label">{{ dmT("formHasSubsidy") }}</template>
  352. <el-radio-group v-model="form.hasSubsidy">
  353. <el-radio v-for="item in yesNoOptions" :key="'hs-' + item" :label="item">{{ item }}</el-radio>
  354. </el-radio-group>
  355. </el-form-item>
  356. </el-col>
  357. <el-col :span="12">
  358. <el-form-item prop="subsidyYear">
  359. <template slot="label">{{ dmT("formSubsidyYear") }}</template>
  360. <el-date-picker
  361. v-model="form.subsidyYear"
  362. type="year"
  363. value-format="yyyy"
  364. :placeholder="dmCommon('pleaseSelect')"
  365. clearable
  366. style="width: 100%"
  367. />
  368. </el-form-item>
  369. </el-col>
  370. <el-col :span="12">
  371. <el-form-item prop="subsidyAmount" :rules="formRules.decimal">
  372. <template slot="label">{{ dmT("formSubsidyAmount") }}</template>
  373. <div class="dm-input-with-unit">
  374. <el-input-number v-model="form.subsidyAmount" :min="0" :precision="4" controls-position="right" class="dm-input-with-unit__input" />
  375. <span class="dm-input-with-unit__suffix">{{ dmT("unitWanYuan") }}</span>
  376. </div>
  377. </el-form-item>
  378. </el-col>
  379. </el-row>
  380. <div class="llf-section-title">{{ dmT("sectionOther") }}</div>
  381. <el-row :gutter="16">
  382. <el-col :span="12">
  383. <el-form-item prop="hasTrademark">
  384. <template slot="label">{{ dmT("formHasTrademark") }}</template>
  385. <el-radio-group v-model="form.hasTrademark">
  386. <el-radio v-for="item in yesNoOptions" :key="'ht-' + item" :label="item">{{ item }}</el-radio>
  387. </el-radio-group>
  388. </el-form-item>
  389. </el-col>
  390. <el-col :span="12">
  391. <el-form-item prop="hasQualityCert">
  392. <template slot="label">{{ dmT("formHasQualityCert") }}</template>
  393. <el-radio-group v-model="form.hasQualityCert">
  394. <el-radio v-for="item in yesNoOptions" :key="'hq-' + item" :label="item">{{ item }}</el-radio>
  395. </el-radio-group>
  396. </el-form-item>
  397. </el-col>
  398. <el-col :span="12">
  399. <el-form-item prop="salesChannel">
  400. <template slot="label">{{ dmT("formSalesChannel") }}</template>
  401. <el-select v-model="form.salesChannel" :placeholder="dmCommon('pleaseSelect')" style="width: 100%">
  402. <el-option v-for="item in salesChannelOptions" :key="item" :label="item" :value="item" />
  403. </el-select>
  404. </el-form-item>
  405. </el-col>
  406. <el-col :span="12">
  407. <el-form-item prop="drivenPopulation" :rules="formRules.count">
  408. <template slot="label">{{ dmT("formDrivenPopulation") }}</template>
  409. <div class="dm-input-with-unit">
  410. <el-input-number v-model="form.drivenPopulation" :min="0" :precision="0" controls-position="right" class="dm-input-with-unit__input" />
  411. <span class="dm-input-with-unit__suffix">{{ dmT("unitPerson") }}</span>
  412. </div>
  413. </el-form-item>
  414. </el-col>
  415. <el-col :span="12">
  416. <el-form-item prop="wagePaid" :rules="formRules.decimal">
  417. <template slot="label">{{ dmT("formWagePaid") }}</template>
  418. <div class="dm-input-with-unit">
  419. <el-input-number v-model="form.wagePaid" :min="0" :precision="4" controls-position="right" class="dm-input-with-unit__input" />
  420. <span class="dm-input-with-unit__suffix">{{ dmT("unitWanYuan") }}</span>
  421. </div>
  422. </el-form-item>
  423. </el-col>
  424. <el-col :span="24">
  425. <el-form-item prop="remark" :rules="formRules.remark">
  426. <template slot="label">{{ dmT("formRemark") }}</template>
  427. <el-input v-model="form.remark" type="textarea" :rows="2" :placeholder="dmT('phRemark')" maxlength="500" show-word-limit />
  428. </el-form-item>
  429. </el-col>
  430. </el-row>
  431. </el-form>
  432. <div slot="footer" class="dialog-footer">
  433. <el-button type="primary" @click="submitForm">{{ dmCommon("ok") }}</el-button>
  434. <el-button @click="cancel">{{ dmCommon("cancel") }}</el-button>
  435. </div>
  436. </el-dialog>
  437. <el-dialog :title="dmCommon('viewTitle')" :visible.sync="viewOpen" width="980px" append-to-body>
  438. <el-form class="dm-view-form llf-form" label-width="220px" size="small">
  439. <div class="llf-section-title">{{ dmT("sectionBasic") }}</div>
  440. <el-row :gutter="8">
  441. <el-col :span="12">
  442. <el-form-item :label="dmT('formStatYear')"><span>{{ viewRow.statYear || dash }}</span></el-form-item>
  443. </el-col>
  444. <el-col :span="12">
  445. <el-form-item :label="dmT('formStatMonth')"><span>{{ formatStatMonth(viewRow.statMonth) }}</span></el-form-item>
  446. </el-col>
  447. <el-col :span="12">
  448. <el-form-item :label="dmT('formTown')"><span>{{ viewRow.townName || dash }}</span></el-form-item>
  449. </el-col>
  450. <el-col :span="12">
  451. <el-form-item :label="dmT('formVillage')"><span>{{ viewRow.villageName || dash }}</span></el-form-item>
  452. </el-col>
  453. </el-row>
  454. <div class="llf-section-title">{{ dmT("sectionFarmerInfo") }}</div>
  455. <el-row :gutter="8">
  456. <el-col :span="12">
  457. <el-form-item :label="dmT('formEnterpriseName')"><span>{{ viewRow.enterpriseName || dash }}</span></el-form-item>
  458. </el-col>
  459. <el-col :span="12">
  460. <el-form-item :label="dmT('formLegalRepresentative')"><span>{{ viewRow.legalRepresentative || dash }}</span></el-form-item>
  461. </el-col>
  462. <el-col :span="12">
  463. <el-form-item :label="dmT('formEnterpriseType')"><span>{{ viewRow.enterpriseType || dash }}</span></el-form-item>
  464. </el-col>
  465. <el-col :span="12">
  466. <el-form-item :label="dmT('formRegisteredCapital')">
  467. <span>{{ formatWithUnit(formatDecimal(viewRow.registeredCapital), "unitWanYuan") }}</span>
  468. </el-form-item>
  469. </el-col>
  470. <el-col :span="12">
  471. <el-form-item :label="dmT('formEstablishDate')"><span>{{ viewRow.establishDate || dash }}</span></el-form-item>
  472. </el-col>
  473. <el-col :span="12">
  474. <el-form-item :label="dmT('formLivestockLaborCount')">
  475. <span>{{ formatWithUnit(formatCount(viewRow.livestockLaborCount), "unitPerson") }}</span>
  476. </el-form-item>
  477. </el-col>
  478. </el-row>
  479. <div class="llf-section-title">{{ dmT("sectionStock") }}</div>
  480. <el-row :gutter="8">
  481. <el-col v-for="field in stockInventoryFields" :key="'vs-' + field.prop" :span="12">
  482. <el-form-item :label="dmT(field.labelKey)">
  483. <span>{{ formatWithUnit(formatCount(viewRow[field.prop]), field.unitKey) }}</span>
  484. </el-form-item>
  485. </el-col>
  486. <el-col :span="12">
  487. <el-form-item :label="dmT('formStockSubtotal')">
  488. <span>{{ formatWithUnit(formatCount(stockSubtotalOf(viewRow)), "unitHeadSheepHorse") }}</span>
  489. </el-form-item>
  490. </el-col>
  491. </el-row>
  492. <div class="llf-section-title">{{ dmT("sectionOutbound") }}</div>
  493. <el-row :gutter="8">
  494. <el-col v-for="field in stockOutboundFields" :key="'vo-' + field.prop" :span="12">
  495. <el-form-item :label="dmT(field.labelKey)">
  496. <span>{{ formatWithUnit(formatCount(viewRow[field.prop]), field.unitKey) }}</span>
  497. </el-form-item>
  498. </el-col>
  499. <el-col :span="12">
  500. <el-form-item :label="dmT('formOutboundSubtotal')">
  501. <span>{{ formatWithUnit(formatCount(outboundSubtotalOf(viewRow)), "unitHeadSheepHorse") }}</span>
  502. </el-form-item>
  503. </el-col>
  504. </el-row>
  505. <div class="llf-section-title">{{ dmT("sectionGrassland") }}</div>
  506. <el-row :gutter="8">
  507. <el-col v-for="field in grasslandDecimalFields" :key="'vg-' + field.prop" :span="12">
  508. <el-form-item :label="dmT(field.labelKey)">
  509. <span>{{ formatWithUnit(formatDecimal(viewRow[field.prop]), field.unitKey) }}</span>
  510. </el-form-item>
  511. </el-col>
  512. <el-col :span="12">
  513. <el-form-item :label="dmT('formGrasslandAreaSubtotal')">
  514. <span>{{ formatWithUnit(formatDecimal(grasslandAreaSubtotalOf(viewRow)), "unitMu") }}</span>
  515. </el-form-item>
  516. </el-col>
  517. <el-col :span="12">
  518. <el-form-item :label="dmT('formIsGrassBalanced')"><span>{{ viewRow.isGrassBalanced || dash }}</span></el-form-item>
  519. </el-col>
  520. </el-row>
  521. <div class="llf-section-title">{{ dmT("sectionFinance") }}</div>
  522. <el-row :gutter="8">
  523. <el-col :span="12">
  524. <el-form-item :label="dmT('formIncome')">
  525. <span>{{ formatWithUnit(formatDecimal(viewRow.income), "unitWanYuan") }}</span>
  526. </el-form-item>
  527. </el-col>
  528. <el-col :span="12">
  529. <el-form-item :label="dmT('formExpense')">
  530. <span>{{ formatWithUnit(formatDecimal(viewRow.expense), "unitWanYuan") }}</span>
  531. </el-form-item>
  532. </el-col>
  533. <el-col :span="12">
  534. <el-form-item :label="dmT('formProfit')">
  535. <span>{{ formatWithUnit(formatDecimal(viewRow.profit), "unitWanYuan") }}</span>
  536. </el-form-item>
  537. </el-col>
  538. </el-row>
  539. <div class="llf-section-title">{{ dmT("sectionSubsidy") }}</div>
  540. <el-row :gutter="8">
  541. <el-col :span="12">
  542. <el-form-item :label="dmT('formHasSubsidy')"><span>{{ viewRow.hasSubsidy || dash }}</span></el-form-item>
  543. </el-col>
  544. <el-col :span="12">
  545. <el-form-item :label="dmT('formSubsidyYear')"><span>{{ viewRow.subsidyYear || dash }}</span></el-form-item>
  546. </el-col>
  547. <el-col :span="12">
  548. <el-form-item :label="dmT('formSubsidyAmount')">
  549. <span>{{ formatWithUnit(formatDecimal(viewRow.subsidyAmount), "unitWanYuan") }}</span>
  550. </el-form-item>
  551. </el-col>
  552. </el-row>
  553. <div class="llf-section-title">{{ dmT("sectionOther") }}</div>
  554. <el-row :gutter="8">
  555. <el-col :span="12">
  556. <el-form-item :label="dmT('formHasTrademark')"><span>{{ viewRow.hasTrademark || dash }}</span></el-form-item>
  557. </el-col>
  558. <el-col :span="12">
  559. <el-form-item :label="dmT('formHasQualityCert')"><span>{{ viewRow.hasQualityCert || dash }}</span></el-form-item>
  560. </el-col>
  561. <el-col :span="12">
  562. <el-form-item :label="dmT('formSalesChannel')"><span>{{ viewRow.salesChannel || dash }}</span></el-form-item>
  563. </el-col>
  564. <el-col :span="12">
  565. <el-form-item :label="dmT('formDrivenPopulation')">
  566. <span>{{ formatWithUnit(formatCount(viewRow.drivenPopulation), "unitPerson") }}</span>
  567. </el-form-item>
  568. </el-col>
  569. <el-col :span="12">
  570. <el-form-item :label="dmT('formWagePaid')">
  571. <span>{{ formatWithUnit(formatDecimal(viewRow.wagePaid), "unitWanYuan") }}</span>
  572. </el-form-item>
  573. </el-col>
  574. <el-col :span="24">
  575. <el-form-item :label="dmT('formRemark')">
  576. <span class="llf-view-text">{{ viewRow.remark || dash }}</span>
  577. </el-form-item>
  578. </el-col>
  579. </el-row>
  580. </el-form>
  581. <div slot="footer" class="dialog-footer">
  582. <el-button v-hasPermi="['dataModel:largeLivestockFarmer:edit']" type="primary" @click="handleEditFromView">{{ dmCommon("edit") }}</el-button>
  583. <el-button @click="viewOpen = false">{{ dmCommon("close") }}</el-button>
  584. </div>
  585. </el-dialog>
  586. <el-dialog :title="dmT('importTitle')" :visible.sync="importOpen" width="480px" append-to-body @close="resetImport">
  587. <el-form ref="importFormRef" :model="importForm" label-width="100px" size="small">
  588. <el-form-item prop="statYear" :rules="importRules.statYear">
  589. <template slot="label">{{ dmT("importStatYear") }}</template>
  590. <el-select v-model="importForm.statYear" :placeholder="dmT('importStatYearPh')" style="width: 100%">
  591. <el-option v-for="y in yearOptions" :key="'iy-' + y" :label="String(y)" :value="y" />
  592. </el-select>
  593. </el-form-item>
  594. <el-form-item prop="statMonth" :rules="importRules.statMonth">
  595. <template slot="label">{{ dmT("importStatMonth") }}</template>
  596. <el-select v-model="importForm.statMonth" :placeholder="dmT('importStatMonthPh')" style="width: 100%">
  597. <el-option v-for="m in monthOptions" :key="'im-' + m" :label="formatStatMonth(m)" :value="m" />
  598. </el-select>
  599. </el-form-item>
  600. <p class="llf-import-tip">{{ dmT("importTip") }}</p>
  601. <el-upload ref="importUpload" drag :limit="1" accept=".xlsx,.xls" :auto-upload="false" action="#">
  602. <i class="el-icon-upload" />
  603. <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
  604. <div slot="tip" class="el-upload__tip">
  605. <el-link type="primary" :underline="false" @click="handleDownloadTemplate">{{ dmT("btnDownloadTemplate") }}</el-link>
  606. </div>
  607. </el-upload>
  608. </el-form>
  609. <div slot="footer" class="dialog-footer">
  610. <el-button type="primary" :loading="importing" @click="handleImportSubmit">{{ dmCommon("ok") }}</el-button>
  611. <el-button @click="importOpen = false">{{ dmCommon("cancel") }}</el-button>
  612. </div>
  613. </el-dialog>
  614. <el-dialog :title="dmT('exportTitle')" :visible.sync="exportOpen" width="480px" append-to-body @close="resetExport">
  615. <el-form ref="exportFormRef" :model="exportForm" label-width="100px" size="small">
  616. <el-form-item prop="statYear" :rules="exportRules.statYear">
  617. <template slot="label">{{ dmT("exportStatYear") }}</template>
  618. <el-select v-model="exportForm.statYear" :placeholder="dmT('exportStatYearPh')" style="width: 100%">
  619. <el-option v-for="y in yearOptions" :key="'ey-' + y" :label="String(y)" :value="y" />
  620. </el-select>
  621. </el-form-item>
  622. <el-form-item prop="statMonth" :rules="exportRules.statMonth">
  623. <template slot="label">{{ dmT("exportStatMonth") }}</template>
  624. <el-select v-model="exportForm.statMonth" :placeholder="dmT('exportStatMonthPh')" style="width: 100%">
  625. <el-option v-for="m in monthOptions" :key="'em-' + m" :label="formatStatMonth(m)" :value="m" />
  626. </el-select>
  627. </el-form-item>
  628. <el-form-item>
  629. <template slot="label">{{ dmT("queryTown") }}</template>
  630. <el-select
  631. v-model="exportForm.townDeptId"
  632. :placeholder="dmCommon('pleaseSelect')"
  633. clearable
  634. filterable
  635. style="width: 100%"
  636. >
  637. <el-option v-for="item in townOptions" :key="'et-' + item.deptId" :label="item.deptName" :value="item.deptId" />
  638. </el-select>
  639. </el-form-item>
  640. </el-form>
  641. <div slot="footer" class="dialog-footer">
  642. <el-button type="primary" :loading="exporting" @click="handleExportSubmit">{{ dmCommon("ok") }}</el-button>
  643. <el-button @click="exportOpen = false">{{ dmCommon("cancel") }}</el-button>
  644. </div>
  645. </el-dialog>
  646. </div>
  647. </template>
  648. <script>
  649. import dataModelLocaleMixin from "@/mixins/dataModelLocaleMixin"
  650. import {
  651. listLargeLivestockFarmer,
  652. getLargeLivestockFarmer,
  653. addLargeLivestockFarmer,
  654. updateLargeLivestockFarmer,
  655. delLargeLivestockFarmer,
  656. listLargeLivestockFarmerYearOptions,
  657. listLargeLivestockFarmerMonthOptions,
  658. listLargeLivestockFarmerTownOptions,
  659. listLargeLivestockFarmerVillageTree,
  660. importLargeLivestockFarmer,
  661. downloadLargeLivestockFarmerTemplate,
  662. exportLargeLivestockFarmer
  663. } from "@/api/dataModel/largeLivestockFarmer"
  664. import { blobValidate } from "@/utils/ruoyi"
  665. import { saveAs } from "file-saver"
  666. const ENTERPRISE_TYPE_OPTIONS = ["个体工商户", "个人独资企业", "有限责任公司", "合伙企业", "其他"]
  667. const SALES_CHANNEL_OPTIONS = ["其他", "线上销售", "线下集市", "企事业单位", "商超门店"]
  668. const YES_NO_OPTIONS = ["是", "否"]
  669. const DEFAULT_ENTERPRISE_TYPE = "个体工商户"
  670. const DEFAULT_SALES_CHANNEL = "其他"
  671. const STOCK_INVENTORY_FIELDS = [
  672. { prop: "cattleYearEndStock", labelKey: "formCattleYearEndStock", unitKey: "unitHead" },
  673. { prop: "cattleBreedingFemaleStock", labelKey: "formCattleBreedingFemaleStock", unitKey: "unitHead" },
  674. { prop: "sheepYearEndStock", labelKey: "formSheepYearEndStock", unitKey: "unitHead" },
  675. { prop: "sheepBreedingFemaleStock", labelKey: "formSheepBreedingFemaleStock", unitKey: "unitHead" }
  676. ]
  677. const STOCK_OUTBOUND_FIELDS = [
  678. { prop: "cattleOutbound", labelKey: "formCattleOutbound", unitKey: "unitHead" },
  679. { prop: "sheepOutbound", labelKey: "formSheepOutbound", unitKey: "unitHead" }
  680. ]
  681. const GRASSLAND_DECIMAL_FIELDS = [
  682. { prop: "grassBalanceArea", labelKey: "formGrassBalanceArea", unitKey: "unitMu" },
  683. { prop: "transferGrassArea", labelKey: "formTransferGrassArea", unitKey: "unitMu" },
  684. { prop: "approvedCarryingCapacity", labelKey: "formApprovedCarryingCapacity", unitKey: "unitHead" },
  685. { prop: "yearEndStockSheepUnit", labelKey: "formYearEndStockSheepUnit", unitKey: "unitHead" }
  686. ]
  687. const COUNT_PROPS = [
  688. "livestockLaborCount",
  689. ...STOCK_INVENTORY_FIELDS.map((f) => f.prop),
  690. ...STOCK_OUTBOUND_FIELDS.map((f) => f.prop),
  691. "drivenPopulation"
  692. ]
  693. const DECIMAL_PROPS = [
  694. "registeredCapital",
  695. ...GRASSLAND_DECIMAL_FIELDS.map((f) => f.prop),
  696. "income",
  697. "expense",
  698. "subsidyAmount",
  699. "wagePaid"
  700. ]
  701. function getCurrentYearMonth() {
  702. const now = new Date()
  703. return { statYear: now.getFullYear(), statMonth: now.getMonth() + 1 }
  704. }
  705. function createEmptyForm() {
  706. const form = {
  707. id: undefined,
  708. statYear: undefined,
  709. statMonth: undefined,
  710. villageDeptId: undefined,
  711. enterpriseName: undefined,
  712. legalRepresentative: undefined,
  713. enterpriseType: undefined,
  714. establishDate: undefined,
  715. subsidyYear: undefined,
  716. hasSubsidy: undefined,
  717. hasTrademark: undefined,
  718. hasQualityCert: undefined,
  719. salesChannel: undefined,
  720. remark: undefined
  721. }
  722. COUNT_PROPS.forEach((p) => {
  723. form[p] = undefined
  724. })
  725. DECIMAL_PROPS.forEach((p) => {
  726. form[p] = undefined
  727. })
  728. return form
  729. }
  730. function normalizeForm(data) {
  731. const row = Object.assign(createEmptyForm(), data || {})
  732. COUNT_PROPS.concat(DECIMAL_PROPS).forEach((prop) => {
  733. const val = row[prop]
  734. row[prop] = val == null || val === "" ? undefined : Number(val)
  735. })
  736. // 年份选择器 value-format=yyyy,表单内用字符串
  737. if (row.subsidyYear == null || row.subsidyYear === "") {
  738. row.subsidyYear = undefined
  739. } else {
  740. row.subsidyYear = String(row.subsidyYear)
  741. }
  742. ;["hasSubsidy", "hasTrademark", "hasQualityCert"].forEach((prop) => {
  743. if (row[prop] === "") {
  744. row[prop] = undefined
  745. }
  746. })
  747. return row
  748. }
  749. function flattenVillageOptions(tree) {
  750. const list = []
  751. ;(tree || []).forEach((county) => {
  752. ;(county.children || []).forEach((town) => {
  753. ;(town.children || []).forEach((village) => {
  754. if (village == null || village.id == null) {
  755. return
  756. }
  757. const townName = town.label || ""
  758. const villageName = village.label || ""
  759. list.push({
  760. deptId: village.id,
  761. label: townName ? `${townName} / ${villageName}` : villageName
  762. })
  763. })
  764. })
  765. })
  766. return list
  767. }
  768. function safeNum(val) {
  769. const n = Number(val)
  770. return Number.isFinite(n) ? n : 0
  771. }
  772. export default {
  773. name: "LargeLivestockFarmer",
  774. mixins: [dataModelLocaleMixin],
  775. data() {
  776. return {
  777. dmNs: "largeLivestockFarmer",
  778. loading: false,
  779. importing: false,
  780. exporting: false,
  781. open: false,
  782. viewOpen: false,
  783. importOpen: false,
  784. exportOpen: false,
  785. dialogEdit: false,
  786. formKey: 0,
  787. total: 0,
  788. tableList: [],
  789. yearOptions: [],
  790. monthOptions: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
  791. townOptions: [],
  792. villageOptions: [],
  793. enterpriseTypeOptions: ENTERPRISE_TYPE_OPTIONS,
  794. salesChannelOptions: SALES_CHANNEL_OPTIONS,
  795. yesNoOptions: YES_NO_OPTIONS,
  796. stockInventoryFields: STOCK_INVENTORY_FIELDS,
  797. stockOutboundFields: STOCK_OUTBOUND_FIELDS,
  798. grasslandDecimalFields: GRASSLAND_DECIMAL_FIELDS,
  799. viewRow: {},
  800. importForm: { statYear: undefined, statMonth: undefined },
  801. exportForm: { statYear: undefined, statMonth: undefined, townDeptId: undefined },
  802. queryParams: {
  803. pageNum: 1,
  804. pageSize: 20,
  805. statYear: undefined,
  806. statMonth: undefined,
  807. townDeptId: undefined,
  808. villageDeptId: undefined,
  809. enterpriseName: undefined
  810. },
  811. form: createEmptyForm()
  812. }
  813. },
  814. computed: {
  815. dash() {
  816. return this.$t("dataModel.status.dash")
  817. },
  818. dialogTitle() {
  819. return this.dialogEdit ? this.dmT("dialogEdit") : this.dmT("dialogAdd")
  820. },
  821. stockSubtotalDisplay() {
  822. return safeNum(this.form.cattleYearEndStock) + safeNum(this.form.sheepYearEndStock)
  823. },
  824. outboundSubtotalDisplay() {
  825. return safeNum(this.form.cattleOutbound) + safeNum(this.form.sheepOutbound)
  826. },
  827. grasslandAreaSubtotalDisplay() {
  828. const n = safeNum(this.form.grassBalanceArea) + safeNum(this.form.transferGrassArea)
  829. return Number(n.toFixed(4))
  830. },
  831. profitDisplay() {
  832. if (this.form.income == null || this.form.expense == null) {
  833. return this.dash
  834. }
  835. return Number((safeNum(this.form.income) - safeNum(this.form.expense)).toFixed(4))
  836. },
  837. isGrassBalancedDisplay() {
  838. if (this.form.approvedCarryingCapacity == null || this.form.yearEndStockSheepUnit == null) {
  839. return this.dash
  840. }
  841. return safeNum(this.form.approvedCarryingCapacity) >= safeNum(this.form.yearEndStockSheepUnit) ? "是" : "否"
  842. },
  843. formRules() {
  844. return {
  845. statYear: [{ required: true, message: this.dmT("ruleStatYearRequired"), trigger: "change" }],
  846. statMonth: [
  847. { required: true, message: this.dmT("ruleStatMonthRequired"), trigger: "change" },
  848. { validator: this.validateFormStatMonth, trigger: "change" }
  849. ],
  850. villageDeptId: [{ required: true, message: this.dmT("ruleVillageRequired"), trigger: "change" }],
  851. enterpriseName: [
  852. { required: true, message: this.dmT("ruleEnterpriseNameRequired"), trigger: "blur" },
  853. { max: 200, message: this.dmT("ruleEnterpriseNameLen"), trigger: "blur" }
  854. ],
  855. legalRepresentative: [{ max: 64, message: this.dmT("ruleLegalRepLen"), trigger: "blur" }],
  856. count: [{ validator: this.validateOptionalCount, trigger: "change" }],
  857. decimal: [{ validator: this.validateOptionalDecimal, trigger: "change" }],
  858. remark: [{ max: 500, message: this.dmCommon("ruleLen500"), trigger: "blur" }]
  859. }
  860. },
  861. importRules() {
  862. return {
  863. statYear: [{ required: true, message: this.dmT("ruleStatYearRequired"), trigger: "change" }],
  864. statMonth: [
  865. { required: true, message: this.dmT("ruleStatMonthRequired"), trigger: "change" },
  866. { validator: this.validateImportStatMonth, trigger: "change" }
  867. ]
  868. }
  869. },
  870. exportRules() {
  871. return {
  872. statYear: [{ required: true, message: this.dmT("exportStatYearRequired"), trigger: "change" }],
  873. statMonth: [
  874. { required: true, message: this.dmT("exportStatMonthRequired"), trigger: "change" },
  875. { validator: this.validateExportStatMonth, trigger: "change" }
  876. ]
  877. }
  878. }
  879. },
  880. created() {
  881. this.loadOptions()
  882. this.getList()
  883. },
  884. methods: {
  885. loadOptions() {
  886. listLargeLivestockFarmerYearOptions().then((res) => {
  887. this.yearOptions = Array.isArray(res.data) ? res.data : []
  888. })
  889. listLargeLivestockFarmerMonthOptions().then((res) => {
  890. if (Array.isArray(res.data) && res.data.length) {
  891. this.monthOptions = res.data
  892. }
  893. })
  894. listLargeLivestockFarmerTownOptions().then((res) => {
  895. this.townOptions = Array.isArray(res.data) ? res.data : []
  896. })
  897. this.loadVillageTree()
  898. },
  899. loadVillageTree() {
  900. return listLargeLivestockFarmerVillageTree()
  901. .then((res) => {
  902. const raw = res && res.data !== undefined ? res.data : res
  903. this.villageOptions = flattenVillageOptions(Array.isArray(raw) ? raw : [])
  904. if (!this.villageOptions.length) {
  905. this.$modal.msgWarning(this.dmT("villageTreeEmpty"))
  906. }
  907. })
  908. .catch(() => {
  909. this.villageOptions = []
  910. })
  911. },
  912. formatStatMonth(month) {
  913. if (month == null || month === "") {
  914. return this.dash
  915. }
  916. return this.dmT("statMonthLabel", { month })
  917. },
  918. formatCount(val) {
  919. return val == null || val === "" ? this.dash : val
  920. },
  921. formatDecimal(val) {
  922. return val == null || val === "" ? this.dash : val
  923. },
  924. formatViewField(row, field) {
  925. let val
  926. if (field.type === "count") {
  927. val = this.formatCount(row[field.prop])
  928. } else if (field.type === "decimal") {
  929. val = this.formatDecimal(row[field.prop])
  930. } else {
  931. val = row[field.prop] || this.dash
  932. }
  933. return this.formatWithUnit(val, field.unitKey)
  934. },
  935. stockSubtotalOf(row) {
  936. if (!row) {
  937. return 0
  938. }
  939. if (row.stockSubtotal != null && row.stockSubtotal !== "") {
  940. return row.stockSubtotal
  941. }
  942. return safeNum(row.cattleYearEndStock) + safeNum(row.sheepYearEndStock)
  943. },
  944. outboundSubtotalOf(row) {
  945. if (!row) {
  946. return 0
  947. }
  948. if (row.outboundSubtotal != null && row.outboundSubtotal !== "") {
  949. return row.outboundSubtotal
  950. }
  951. return safeNum(row.cattleOutbound) + safeNum(row.sheepOutbound)
  952. },
  953. grasslandAreaSubtotalOf(row) {
  954. if (!row) {
  955. return undefined
  956. }
  957. if (row.grasslandAreaSubtotal != null && row.grasslandAreaSubtotal !== "") {
  958. return row.grasslandAreaSubtotal
  959. }
  960. if (row.grassBalanceArea == null && row.transferGrassArea == null) {
  961. return undefined
  962. }
  963. return Number((safeNum(row.grassBalanceArea) + safeNum(row.transferGrassArea)).toFixed(4))
  964. },
  965. isFutureStatPeriod(statYear, statMonth) {
  966. if (statYear == null || statMonth == null) {
  967. return false
  968. }
  969. const now = new Date()
  970. const y = now.getFullYear()
  971. const m = now.getMonth() + 1
  972. return statYear > y || (statYear === y && statMonth > m)
  973. },
  974. validateFormStatMonth(rule, value, callback) {
  975. if (this.isFutureStatPeriod(this.form.statYear, value)) {
  976. callback(new Error(this.dmT("ruleStatMonthFuture")))
  977. return
  978. }
  979. callback()
  980. },
  981. validateImportStatMonth(rule, value, callback) {
  982. if (this.isFutureStatPeriod(this.importForm.statYear, value)) {
  983. callback(new Error(this.dmT("ruleStatMonthFuture")))
  984. return
  985. }
  986. callback()
  987. },
  988. validateExportStatMonth(rule, value, callback) {
  989. if (this.isFutureStatPeriod(this.exportForm.statYear, value)) {
  990. callback(new Error(this.dmT("ruleStatMonthFuture")))
  991. return
  992. }
  993. callback()
  994. },
  995. validateOptionalCount(rule, value, callback) {
  996. if (value == null || value === "") {
  997. callback()
  998. return
  999. }
  1000. if (!Number.isInteger(value) || value < 0) {
  1001. callback(new Error(this.dmT("ruleCountNonNegative")))
  1002. return
  1003. }
  1004. callback()
  1005. },
  1006. validateOptionalDecimal(rule, value, callback) {
  1007. if (value == null || value === "") {
  1008. callback()
  1009. return
  1010. }
  1011. if (typeof value !== "number" || Number.isNaN(value) || value < 0) {
  1012. callback(new Error(this.dmT("ruleDecimalNonNegative")))
  1013. return
  1014. }
  1015. callback()
  1016. },
  1017. buildListQuery() {
  1018. const q = { pageNum: this.queryParams.pageNum, pageSize: this.queryParams.pageSize }
  1019. if (this.queryParams.statYear != null) {
  1020. q.statYear = this.queryParams.statYear
  1021. }
  1022. if (this.queryParams.statMonth != null) {
  1023. q.statMonth = this.queryParams.statMonth
  1024. }
  1025. if (this.queryParams.townDeptId != null) {
  1026. q.townDeptId = this.queryParams.townDeptId
  1027. }
  1028. if (this.queryParams.villageDeptId != null) {
  1029. q.villageDeptId = this.queryParams.villageDeptId
  1030. }
  1031. const name = this.queryParams.enterpriseName != null ? String(this.queryParams.enterpriseName).trim() : ""
  1032. if (name) {
  1033. q.enterpriseName = name
  1034. }
  1035. return q
  1036. },
  1037. buildPayload() {
  1038. const remarkText = this.form.remark != null ? String(this.form.remark).trim() : ""
  1039. const enterpriseName = this.form.enterpriseName != null ? String(this.form.enterpriseName).trim() : ""
  1040. const legalRep = this.form.legalRepresentative != null ? String(this.form.legalRepresentative).trim() : ""
  1041. let subsidyYear
  1042. if (this.form.subsidyYear != null && this.form.subsidyYear !== "") {
  1043. const y = Number(this.form.subsidyYear)
  1044. subsidyYear = Number.isFinite(y) ? y : undefined
  1045. }
  1046. const payload = {
  1047. statYear: this.form.statYear,
  1048. statMonth: this.form.statMonth,
  1049. villageDeptId: this.form.villageDeptId,
  1050. enterpriseName,
  1051. legalRepresentative: legalRep !== "" ? legalRep : undefined,
  1052. enterpriseType: this.form.enterpriseType || undefined,
  1053. establishDate: this.form.establishDate || undefined,
  1054. subsidyYear,
  1055. hasSubsidy: this.form.hasSubsidy || undefined,
  1056. hasTrademark: this.form.hasTrademark || undefined,
  1057. hasQualityCert: this.form.hasQualityCert || undefined,
  1058. salesChannel: this.form.salesChannel || undefined,
  1059. remark: remarkText !== "" ? remarkText : undefined
  1060. }
  1061. COUNT_PROPS.concat(DECIMAL_PROPS).forEach((prop) => {
  1062. const val = this.form[prop]
  1063. payload[prop] = val == null || val === "" ? undefined : val
  1064. })
  1065. return payload
  1066. },
  1067. getList() {
  1068. this.loading = true
  1069. listLargeLivestockFarmer(this.buildListQuery())
  1070. .then((res) => {
  1071. this.tableList = res.rows || []
  1072. this.total = res.total != null ? res.total : 0
  1073. })
  1074. .finally(() => {
  1075. this.loading = false
  1076. })
  1077. },
  1078. handleQuery() {
  1079. this.queryParams.pageNum = 1
  1080. this.getList()
  1081. },
  1082. resetQuery() {
  1083. this.queryParams.statYear = undefined
  1084. this.queryParams.statMonth = undefined
  1085. this.queryParams.townDeptId = undefined
  1086. this.queryParams.villageDeptId = undefined
  1087. this.queryParams.enterpriseName = undefined
  1088. this.resetForm("queryForm")
  1089. this.handleQuery()
  1090. },
  1091. handleAdd() {
  1092. const openDialog = () => {
  1093. this.formKey += 1
  1094. const current = getCurrentYearMonth()
  1095. this.form = createEmptyForm()
  1096. this.form.statYear = current.statYear
  1097. this.form.statMonth = current.statMonth
  1098. this.form.enterpriseType = DEFAULT_ENTERPRISE_TYPE
  1099. this.form.salesChannel = DEFAULT_SALES_CHANNEL
  1100. this.dialogEdit = false
  1101. this.open = true
  1102. this.$nextTick(() => {
  1103. if (this.$refs.form) {
  1104. this.$refs.form.clearValidate()
  1105. }
  1106. })
  1107. }
  1108. if (!this.villageOptions.length) {
  1109. this.loadVillageTree().finally(openDialog)
  1110. } else {
  1111. openDialog()
  1112. }
  1113. },
  1114. handleEdit(row) {
  1115. const openWithData = (data) => {
  1116. this.formKey += 1
  1117. this.dialogEdit = true
  1118. this.form = normalizeForm(data)
  1119. this.open = true
  1120. this.viewOpen = false
  1121. this.$nextTick(() => {
  1122. if (this.$refs.form) {
  1123. this.$refs.form.clearValidate()
  1124. }
  1125. })
  1126. }
  1127. getLargeLivestockFarmer(row.id).then((res) => {
  1128. const data = res.data || {}
  1129. if (!this.villageOptions.length) {
  1130. this.loadVillageTree().finally(() => openWithData(data))
  1131. } else {
  1132. openWithData(data)
  1133. }
  1134. })
  1135. },
  1136. handleEditFromView() {
  1137. this.handleEdit(this.viewRow)
  1138. },
  1139. handleView(row) {
  1140. getLargeLivestockFarmer(row.id).then((res) => {
  1141. this.viewRow = res.data || {}
  1142. this.viewOpen = true
  1143. })
  1144. },
  1145. handleDelete(row) {
  1146. this.$modal
  1147. .confirm(this.dmT("confirmDelete"))
  1148. .then(() => delLargeLivestockFarmer(row.id))
  1149. .then(() => {
  1150. this.$modal.msgSuccess(this.dmCommon("msgDelOk"))
  1151. this.viewOpen = false
  1152. this.getList()
  1153. })
  1154. .catch(() => {})
  1155. },
  1156. submitForm() {
  1157. this.$refs.form.validate((valid) => {
  1158. if (!valid) {
  1159. return
  1160. }
  1161. const payload = this.buildPayload()
  1162. if (this.dialogEdit) {
  1163. payload.id = this.form.id
  1164. updateLargeLivestockFarmer(payload).then(() => {
  1165. this.$modal.msgSuccess(this.dmCommon("msgModOk"))
  1166. this.open = false
  1167. this.getList()
  1168. })
  1169. } else {
  1170. addLargeLivestockFarmer(payload).then(() => {
  1171. this.$modal.msgSuccess(this.dmCommon("msgAddOk"))
  1172. this.open = false
  1173. this.getList()
  1174. })
  1175. }
  1176. })
  1177. },
  1178. cancel() {
  1179. this.open = false
  1180. this.form = createEmptyForm()
  1181. },
  1182. handleImportOpen() {
  1183. const current = getCurrentYearMonth()
  1184. this.importForm.statYear = current.statYear
  1185. this.importForm.statMonth = current.statMonth
  1186. this.importOpen = true
  1187. this.$nextTick(() => this.resetImportFiles())
  1188. },
  1189. resetImportFiles() {
  1190. if (this.$refs.importUpload) {
  1191. this.$refs.importUpload.clearFiles()
  1192. }
  1193. },
  1194. resetImport() {
  1195. this.importing = false
  1196. this.importForm.statYear = undefined
  1197. this.importForm.statMonth = undefined
  1198. this.resetImportFiles()
  1199. },
  1200. handleDownloadTemplate() {
  1201. const filename = `large_livestock_farmer_template_${new Date().getTime()}.xlsx`
  1202. this.$modal.loading("正在下载模板,请稍候")
  1203. downloadLargeLivestockFarmerTemplate()
  1204. .then(async (data) => {
  1205. if (blobValidate(data)) {
  1206. saveAs(new Blob([data], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }), filename)
  1207. } else {
  1208. const resText = await data.text()
  1209. const rspObj = JSON.parse(resText)
  1210. this.$modal.msgError(rspObj.msg || "下载模板失败")
  1211. }
  1212. })
  1213. .catch(() => this.$modal.msgError("下载模板失败"))
  1214. .finally(() => this.$modal.closeLoading())
  1215. },
  1216. handleExportOpen() {
  1217. const current = getCurrentYearMonth()
  1218. this.exportForm.statYear = current.statYear
  1219. this.exportForm.statMonth = current.statMonth
  1220. this.exportForm.townDeptId = this.queryParams.townDeptId
  1221. this.exportOpen = true
  1222. this.$nextTick(() => {
  1223. if (this.$refs.exportFormRef) {
  1224. this.$refs.exportFormRef.clearValidate()
  1225. }
  1226. })
  1227. },
  1228. resetExport() {
  1229. this.exporting = false
  1230. this.exportForm.statYear = undefined
  1231. this.exportForm.statMonth = undefined
  1232. this.exportForm.townDeptId = undefined
  1233. },
  1234. handleExportSubmit() {
  1235. this.$refs.exportFormRef.validate((valid) => {
  1236. if (!valid) {
  1237. return
  1238. }
  1239. const { statYear, statMonth } = this.exportForm
  1240. if (!this.yearOptions.includes(statYear) || !this.monthOptions.includes(statMonth)) {
  1241. this.$modal.msgError(this.dmT("exportStatYearInvalid"))
  1242. return
  1243. }
  1244. const filename = `${statYear}年${statMonth}月养殖大户数据.xlsx`
  1245. this.exporting = true
  1246. this.$modal.loading(this.dmT("exportLoading"))
  1247. exportLargeLivestockFarmer(statYear, statMonth, this.exportForm.townDeptId)
  1248. .then(async (data) => {
  1249. if (blobValidate(data)) {
  1250. saveAs(new Blob([data], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }), filename)
  1251. this.exportOpen = false
  1252. } else {
  1253. const resText = await data.text()
  1254. const rspObj = JSON.parse(resText)
  1255. this.$modal.msgError(rspObj.msg || this.dmT("exportFail"))
  1256. }
  1257. })
  1258. .catch(() => this.$modal.msgError(this.dmT("exportFail")))
  1259. .finally(() => {
  1260. this.exporting = false
  1261. this.$modal.closeLoading()
  1262. })
  1263. })
  1264. },
  1265. handleImportSubmit() {
  1266. this.$refs.importFormRef.validate((valid) => {
  1267. if (!valid) {
  1268. return
  1269. }
  1270. const files = this.$refs.importUpload && this.$refs.importUpload.uploadFiles
  1271. if (!files || !files.length) {
  1272. this.$modal.msgError("请选择要上传的文件")
  1273. return
  1274. }
  1275. const raw = files[0].raw
  1276. const name = (raw.name || "").toLowerCase()
  1277. if (!name.endsWith(".xlsx") && !name.endsWith(".xls")) {
  1278. this.$modal.msgError('请选择后缀为 "xls" 或 "xlsx" 的文件')
  1279. return
  1280. }
  1281. this.importing = true
  1282. this.$modal.loading(this.dmT("importLoading"))
  1283. importLargeLivestockFarmer(raw, this.importForm.statYear, this.importForm.statMonth)
  1284. .then((res) => {
  1285. this.importOpen = false
  1286. this.showImportResult(res.data || {})
  1287. this.getList()
  1288. })
  1289. .finally(() => {
  1290. this.importing = false
  1291. this.$modal.closeLoading()
  1292. this.resetImportFiles()
  1293. })
  1294. })
  1295. },
  1296. showImportResult(data) {
  1297. const insert = data.insertCount != null ? data.insertCount : 0
  1298. const update = data.updateCount != null ? data.updateCount : 0
  1299. const fail = data.failCount != null ? data.failCount : 0
  1300. let html = this.dmT("importSummary", { insert, update, fail })
  1301. if (data.warnMessages && data.warnMessages.length) {
  1302. html += `<p><strong>${this.dmT("importWarnTitle")}</strong></p><p>${data.warnMessages.join("<br/>")}</p>`
  1303. }
  1304. if (data.failMessages && data.failMessages.length) {
  1305. html += `<p><strong>${this.dmT("importFailTitle")}</strong></p><p>${data.failMessages.join("<br/>")}</p>`
  1306. }
  1307. this.$alert(
  1308. `<div style='overflow:auto;overflow-x:hidden;max-height:70vh;padding:10px 20px 0;'>${html}</div>`,
  1309. this.dmT("importTitle"),
  1310. { dangerouslyUseHTMLString: true }
  1311. )
  1312. }
  1313. }
  1314. }
  1315. </script>
  1316. <style scoped>
  1317. .llf-section-title {
  1318. margin: 4px 0 12px;
  1319. font-weight: 600;
  1320. color: #303133;
  1321. }
  1322. .llf-form >>> .el-form-item__label {
  1323. white-space: nowrap;
  1324. line-height: 32px;
  1325. }
  1326. .llf-import-tip {
  1327. margin: 0 0 12px;
  1328. color: #909399;
  1329. font-size: 12px;
  1330. line-height: 1.5;
  1331. }
  1332. .llf-view-text {
  1333. white-space: pre-wrap;
  1334. word-break: break-all;
  1335. }
  1336. .dm-input-with-unit {
  1337. display: flex;
  1338. align-items: center;
  1339. width: 100%;
  1340. }
  1341. .dm-input-with-unit__input {
  1342. flex: 1;
  1343. width: 100%;
  1344. }
  1345. .dm-input-with-unit__suffix {
  1346. margin-left: 8px;
  1347. color: #909399;
  1348. white-space: nowrap;
  1349. }
  1350. .dm-input-with-unit >>> .el-input-number {
  1351. width: 100%;
  1352. }
  1353. </style>