edit.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. <template>
  2. <ele-modal
  3. :title="title"
  4. :visible.sync="visible"
  5. :before-close="handleClose"
  6. :close-on-click-modal="false"
  7. :close-on-press-escape="false"
  8. append-to-body
  9. width="75%"
  10. :maxable="true"
  11. >
  12. <el-card shadow="never">
  13. <el-form
  14. ref="formName"
  15. :model="formData"
  16. label-width="80px"
  17. :rules="rules"
  18. >
  19. <el-row :gutter="15">
  20. <el-col :span="6">
  21. <el-form-item label="编码:" prop="code">
  22. <el-input
  23. v-model="formData.code"
  24. placeholder="请输入内容"
  25. disabled
  26. ></el-input>
  27. </el-form-item>
  28. </el-col>
  29. <el-col :span="6">
  30. <el-form-item label="类型:" prop="sourceType">
  31. <el-select
  32. style="width: 100%"
  33. v-model="formData.sourceType"
  34. placeholder="请选择类型"
  35. :disabled="readonlyMode"
  36. >
  37. <el-option label="余料退库" value="SurplusReturn"></el-option>
  38. <el-option
  39. label="不良退库"
  40. value="UnqualifiedReturn"
  41. ></el-option>
  42. <el-option label="完工入库" value="Finish"></el-option>
  43. <el-option label="暂存入库" value="Temp"></el-option>
  44. </el-select>
  45. </el-form-item>
  46. </el-col>
  47. <el-col :span="6">
  48. <el-form-item label="备注" prop="remark">
  49. <el-input
  50. v-model="formData.remark"
  51. placeholder="请输入内容"
  52. :disabled="readonlyMode"
  53. ></el-input>
  54. </el-form-item>
  55. </el-col>
  56. </el-row>
  57. </el-form>
  58. <div style="margin-top: 12px">
  59. <ele-pro-table
  60. ref="eleTable"
  61. row-key="outInDetailId"
  62. :columns="tableColumns"
  63. :datasource="datasource"
  64. height="calc(100vh - 405px)"
  65. full-height="calc(100vh - 116px)"
  66. tool-class="ele-toolbar-form"
  67. :pageSize="20"
  68. @selection-change="handleSelectionChange"
  69. :initLoad="false"
  70. @done="onDone"
  71. >
  72. <template v-slot:measureQuantity="{ row }">
  73. <el-input
  74. v-model="row.measureQuantity"
  75. placeholder="请输入"
  76. :disabled="readonlyMode"
  77. @input="(value) => inputNum(value, row)"
  78. ></el-input>
  79. </template>
  80. <template v-slot:purpose="{ row }">
  81. <el-input
  82. v-model="row.purpose"
  83. placeholder="请输入"
  84. :disabled="readonlyMode"
  85. ></el-input>
  86. </template>
  87. <template v-slot:certificateNumber="{ row, $index }">
  88. <div>
  89. <el-input
  90. v-model="row.certificateNumber"
  91. placeholder="请输入"
  92. :disabled="readonlyMode"
  93. @blur="validateCertificate(row, $index)"
  94. :class="{ 'is-error': row.certificateError }"
  95. ></el-input>
  96. <div v-if="row.certificateError" class="el-form-item__error">
  97. {{ row.certificateError }}
  98. </div>
  99. </div>
  100. </template>
  101. </ele-pro-table>
  102. </div>
  103. </el-card>
  104. <div class="btns" v-if="title != '详情'">
  105. <el-button type="primary" size="small" @click="handleSave"
  106. >确认</el-button
  107. >
  108. <el-button size="small" @click="handleClose">取消</el-button>
  109. </div>
  110. </ele-modal>
  111. </template>
  112. <script>
  113. import storageApi from '@/api/warehouseManagement';
  114. import { getCode } from '@/api/codeManagement/index.js';
  115. export default {
  116. props: {},
  117. data() {
  118. return {
  119. visible: false,
  120. title: '',
  121. formData: {
  122. code: '',
  123. sourceType: '',
  124. remark: ''
  125. },
  126. rules: {
  127. sourceType: [
  128. { required: true, message: '请选择申请类型', trigger: 'change' }
  129. ]
  130. },
  131. loading: false,
  132. selectionList: [],
  133. ids: [],
  134. detailJnVOList: []
  135. };
  136. },
  137. computed: {
  138. readonlyMode() {
  139. return this.title === '详情';
  140. },
  141. tableColumns() {
  142. return this.title === '详情'
  143. ? this.columns.filter((c) => c.type !== 'selection')
  144. : this.columns;
  145. },
  146. columns() {
  147. return [
  148. {
  149. columnKey: 'selection',
  150. type: 'selection',
  151. width: 45,
  152. align: 'center'
  153. },
  154. {
  155. columnKey: 'index',
  156. type: 'index',
  157. width: 50,
  158. align: 'center',
  159. label: '序号',
  160. showOverflowTooltip: true,
  161. fixed: 'left'
  162. },
  163. {
  164. prop: 'batchNo',
  165. label: '批次号',
  166. align: 'center',
  167. width: 100
  168. },
  169. {
  170. prop: 'categoryCode',
  171. label: '物品编码',
  172. align: 'center',
  173. showOverflowTooltip: true,
  174. width: 100
  175. },
  176. {
  177. slot: 'categoryName',
  178. prop: 'categoryName',
  179. label: '物品名称',
  180. align: 'center',
  181. showOverflowTooltip: true,
  182. minWidth: 160
  183. },
  184. {
  185. prop: 'inventoryCycle',
  186. label: '存货周期(天)',
  187. align: 'center',
  188. width: 120,
  189. showOverflowTooltip: true
  190. },
  191. {
  192. prop: 'brandNum',
  193. label: '牌号',
  194. align: 'center',
  195. showOverflowTooltip: true
  196. },
  197. {
  198. prop: 'categoryModel',
  199. label: '型号',
  200. align: 'center',
  201. width: 120,
  202. showOverflowTooltip: true
  203. },
  204. {
  205. prop: 'specification',
  206. label: '规格',
  207. align: 'center',
  208. width: 120,
  209. showOverflowTooltip: true
  210. },
  211. {
  212. prop: 'supplierName',
  213. label: '供应商',
  214. showOverflowTooltip: true,
  215. width: 130,
  216. align: 'center'
  217. },
  218. {
  219. prop: 'level',
  220. label: '级别',
  221. showOverflowTooltip: true
  222. },
  223. {
  224. prop: 'certificateNumber',
  225. slot: 'certificateNumber',
  226. label: '合格证号',
  227. showOverflowTooltip: true,
  228. width: 160
  229. },
  230. {
  231. prop: 'stockCountBase',
  232. label: '库存数量',
  233. sortable: 'custom',
  234. isNone: this.title == '详情',
  235. showOverflowTooltip: true,
  236. width: 130,
  237. align: 'center'
  238. },
  239. {
  240. prop: 'availableCountBase',
  241. isNone: this.title == '详情',
  242. label: '可用数量',
  243. sortable: 'custom',
  244. showOverflowTooltip: true,
  245. width: 130,
  246. align: 'center'
  247. },
  248. {
  249. prop: 'lockQuantity',
  250. isNone: this.title == '详情',
  251. label: '锁定数量',
  252. sortable: 'custom',
  253. showOverflowTooltip: true,
  254. width: 130,
  255. align: 'center'
  256. },
  257. {
  258. prop: 'measureQuantity',
  259. slot: 'measureQuantity',
  260. label: '计量数量',
  261. sortable: 'custom',
  262. showOverflowTooltip: true,
  263. width: 130,
  264. align: 'center'
  265. },
  266. {
  267. prop: 'measureUnit',
  268. label: '计量单位',
  269. align: 'center'
  270. },
  271. {
  272. prop: 'weight',
  273. label: '重量',
  274. showOverflowTooltip: true
  275. },
  276. {
  277. prop: 'weightUnit',
  278. label: '重量单位',
  279. showOverflowTooltip: true
  280. },
  281. {
  282. prop: 'purpose',
  283. slot: 'purpose',
  284. label: '用途',
  285. showOverflowTooltip: true,
  286. width: 130
  287. }
  288. ].filter((c) => !c.isNone);
  289. }
  290. },
  291. methods: {
  292. async datasource({ page, where, limit }) {
  293. if (this.readonlyMode) {
  294. return (this.detailJnVOList || []).map((item) => ({
  295. ...item,
  296. originalMeasureQuantity:
  297. item.originalMeasureQuantity ?? item.measureQuantity,
  298. certificateError: ''
  299. }));
  300. }
  301. const res = await storageApi.getBatchList({ ...where, page, limit });
  302. const data = res.list.map((item) => {
  303. item.originalMeasureQuantity = item.measureQuantity;
  304. item.certificateError = '';
  305. item.outInDetailId = item.id;
  306. delete item.id;
  307. return {
  308. ...item
  309. };
  310. });
  311. return data;
  312. },
  313. reload(where) {
  314. this.$nextTick(() => {
  315. if (this.$refs.eleTable && this.$refs.eleTable.reload)
  316. this.$refs.eleTable.reload({ page: 1, where: where });
  317. });
  318. },
  319. onDone() {
  320. this.$nextTick(() => {
  321. this.$refs.eleTable.setSelectedRowKeys(this.ids);
  322. });
  323. if (this.detailJnVOList.length > 0) {
  324. let list = this.$refs.eleTable.getData();
  325. for (let i = 0; i < list.length; i++) {
  326. for (let j = 0; j < this.detailJnVOList.length; j++) {
  327. if (
  328. list[i].outInDetailId == this.detailJnVOList[j].outInDetailId
  329. ) {
  330. this.$set(
  331. list[i],
  332. 'certificateNumber',
  333. this.detailJnVOList[j].certificateNumber
  334. );
  335. this.$set(
  336. list[i],
  337. 'measureQuantity',
  338. this.detailJnVOList[j].measureQuantity
  339. );
  340. this.$set(list[i], 'purpose', this.detailJnVOList[j].purpose);
  341. }
  342. }
  343. }
  344. }
  345. },
  346. resetData() {
  347. this.formData = {
  348. code: '',
  349. sourceType: '',
  350. remark: ''
  351. };
  352. this.detailJnVOList = [];
  353. },
  354. validateCertificate(row, index) {
  355. let list = this.$refs.eleTable.getData();
  356. if (!row.certificateNumber || row.certificateNumber.trim() === '') {
  357. this.$set(list[index], 'certificateError', '证书号不能为空');
  358. } else {
  359. this.$set(list[index], 'certificateError', '');
  360. }
  361. },
  362. async open(type, row) {
  363. this.resetData();
  364. this.visible = true;
  365. this.title =
  366. type == 'add' ? '新增' : type == 'detail' ? '详情' : '编辑';
  367. if (type == 'add') {
  368. const code = await getCode('Storage_application');
  369. this.formData.code = code;
  370. } else if (row?.id) {
  371. await this.getDraftDetail(row.id);
  372. }
  373. await this.reload();
  374. },
  375. async getDraftDetail(id) {
  376. const res = await storageApi.getStoragejnDetails(id);
  377. if (res) {
  378. this.$set(this, 'formData', res);
  379. this.ids =
  380. res.detailJnVOList?.map((item) => item.outInDetailId) || [];
  381. this.detailJnVOList = res.detailJnVOList || [];
  382. }
  383. },
  384. inputNum(value, row) {
  385. const num = value.replace(/[^\d.]/g, '');
  386. const oldValue = row.originalMeasureQuantity;
  387. if (num > oldValue) {
  388. this.$set(row, 'measureQuantity', oldValue);
  389. } else {
  390. this.$set(row, 'measureQuantity', num);
  391. }
  392. },
  393. handleSelectionChange(selection) {
  394. console.log(selection, '勾选');
  395. if (this.title === '新增' && selection.length > 1) {
  396. const last = selection[selection.length - 1];
  397. this.selectionList = [last];
  398. this.$nextTick(() => {
  399. if (this.$refs.eleTable && this.$refs.eleTable.setSelectedRowKeys) {
  400. this.$refs.eleTable.setSelectedRowKeys([last.outInDetailId]);
  401. }
  402. });
  403. return;
  404. }
  405. this.selectionList = selection;
  406. },
  407. handleClose() {
  408. this.visible = false;
  409. this.resetData();
  410. },
  411. handleSave() {
  412. this.$refs.formName.validate(async (valid) => {
  413. if (valid) {
  414. if (this.selectionList.length == 0)
  415. return this.$message.warning('请选择入库物品');
  416. let isValid = true;
  417. this.selectionList.forEach((item) => {
  418. if (!item.certificateNumber?.trim()) {
  419. isValid = false;
  420. this.$set(item, 'certificateError', '证书号不能为空');
  421. }
  422. });
  423. if (!isValid) {
  424. this.$message.error('请填写所有必填项');
  425. return;
  426. }
  427. let postData = {
  428. type: 1,
  429. code: this.formData.code,
  430. sourceType: this.formData.sourceType,
  431. detailJnAddPOList: this.selectionList,
  432. id: this.title == '编辑' ? this.formData.id : null
  433. };
  434. this.loading = true;
  435. storageApi
  436. .saveStoragejn(postData)
  437. .then(async (res) => {
  438. if (res == 0) {
  439. try {
  440. this.$message.success('保存成功');
  441. this.loading = false;
  442. this.visible = false;
  443. this.$emit('success');
  444. } catch (error) {
  445. this.visible = false;
  446. console.log('失败', error);
  447. }
  448. }
  449. })
  450. .catch((err) => {
  451. console.log('申请失败', err);
  452. this.loading = false;
  453. this.visible = false;
  454. });
  455. } else {
  456. return false;
  457. }
  458. });
  459. }
  460. }
  461. };
  462. </script>
  463. <style lang="scss" scoped>
  464. .btns {
  465. text-align: center;
  466. padding: 10px 0;
  467. }
  468. .el-form-item__error {
  469. color: red;
  470. font-size: 12px;
  471. line-height: 1;
  472. padding-top: 4px;
  473. position: relative;
  474. }
  475. .is-error .el-input__inner {
  476. border-color: red;
  477. }
  478. </style>