西藏巴青项目

index.vue 30KB

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