plan-edit-dialog.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. <template>
  2. <ele-modal :visible.sync="visible" :closed="cancel" :title="`${type == 'add' ? '创建' : '编辑'}采购配料计划`"
  3. custom-class="ele-dialog-form" :close-on-click-modal="true" :close-on-press-escape="false" width="80%">
  4. <el-form :model="formData" ref="formRef" label-width="120px" class="ele-body" :rules="rules">
  5. <el-row :gutter="32">
  6. <el-col :span="12">
  7. <el-form-item label="配料计划名称" prop="name">
  8. <el-input placeholder="请选择" v-model="formData.name"></el-input>
  9. </el-form-item>
  10. </el-col>
  11. <el-col :span="12">
  12. <el-form-item label="备注" prop="remark">
  13. <el-input placeholder="备注" v-model="formData.remark"></el-input>
  14. </el-form-item>
  15. </el-col>
  16. </el-row>
  17. </el-form>
  18. <el-form :model="formData" ref="tableForm">
  19. <ele-pro-table ref="table" :needPage="false" :columns="columns" row-key="id">
  20. <template v-slot:toolbar>
  21. <el-button size="small" type="primary" icon="el-icon-plus" class="ele-btn-icon" @click="showAdd">
  22. 添加销售订单
  23. </el-button>
  24. </template>
  25. <template v-slot:code="{ row }">
  26. <el-input placeholder="请输入" readonly :value="row.code || row.salesOrderCode"></el-input>
  27. </template>
  28. <template v-slot:productionPlanId="{ row }">
  29. <el-link type="primary" v-if="!row.productionPlanId" :underline="false"
  30. @click.native="openVersion(row)">选择</el-link>
  31. </template>
  32. <template v-slot:action="{ row, $index }">
  33. <template>
  34. <el-link type="primary" :underline="false" @click="categorySelect(row)">
  35. 添加物料
  36. </el-link>
  37. <el-popconfirm class="ele-action" title="确定要删除此销售订单吗?" @confirm="remove(row, $index)">
  38. <template v-slot:reference>
  39. <el-link type="danger" :underline="false" icon="el-icon-delete">
  40. 删除
  41. </el-link>
  42. </template>
  43. </el-popconfirm>
  44. </template>
  45. </template>
  46. <!-- 展开内容 -->
  47. <template v-slot:expand="{ row, $index }">
  48. <div style="width:calc(100% - 95px); min-height: 60px; margin-left: 95px;" v-if="row.materialList.length > 0">
  49. <ele-pro-table :toolbar="false" toolsTheme="none" ref="table2" :need-page="false"
  50. :datasource="row.materialList" :columns="columns2" :key="row.categoryId + '-'+ $index">
  51. <template v-slot:sort="{ $index }">
  52. {{ $index }}
  53. </template>
  54. <template v-slot:unit="{ row }">
  55. {{ row.unit }}
  56. </template>
  57. <template v-slot:demandQuantity="{ row }">
  58. <el-input v-model="row.demandQuantity" placeholder="请输入" @input="(value) =>
  59. (row.demandQuantity = value.replace(
  60. /^(-)*(\d+)\.(\d\d\d\d\d\d).*$/,
  61. '$1$2.$3'
  62. ))
  63. "></el-input>
  64. </template>
  65. <template v-slot:purchaseQuantity="{ row }">
  66. <el-input v-model="row.purchaseQuantity" placeholder="请输入" @input="(value) =>
  67. (row.purchaseQuantity = value.replace(
  68. /^(-)*(\d+)\.(\d\d\d\d\d\d).*$/,
  69. '$1$2.$3'
  70. ))
  71. "></el-input>
  72. </template>
  73. <template v-slot:deliveryMethod="{ row }">
  74. <el-select clearable class="ele-block" v-model="row.deliveryMethod" placeholder="请选择">
  75. <el-option label="一次性到货" :value="1" @click.native="row.timeList = null" />
  76. <el-option label="分批到货" :value="2" @click.native="handleMethod(row); row.requireDeliveryTime= null" />
  77. </el-select>
  78. </template>
  79. <template v-slot:requireDeliveryTime="{ row }" >
  80. <el-date-picker style="width: 100%" clearable v-model="row.requireDeliveryTime" type="date"
  81. v-if="row.deliveryMethod == 1" value-format="yyyy-MM-dd" placeholder="请选择日期">
  82. </el-date-picker>
  83. <el-link type="primary" :underline="false" v-if="row.deliveryMethod == 2"
  84. @click.native="handleMethod(row)">
  85. 设置分批时间
  86. </el-link>
  87. </template>
  88. <template v-slot:imgUrl="{ row }">
  89. <fileUpload v-model="row.imgUrl" module="main" :showLib="false" :limit="1" />
  90. </template>
  91. <template v-slot:files="{ row }">
  92. <fileUpload v-model="row.files" module="main" :showLib="false" :limit="1" />
  93. </template>
  94. <template v-slot:action="{ row }">
  95. <el-popconfirm class="ele-action" title="确定要删除当前物料吗?" @confirm="remove2(row)">
  96. <template v-slot:reference>
  97. <el-link type="danger" :underline="false" icon="el-icon-delete">
  98. 删除
  99. </el-link>
  100. </template>
  101. </el-popconfirm>
  102. </template>
  103. </ele-pro-table>
  104. </div>
  105. </template>
  106. </ele-pro-table>
  107. </el-form>
  108. <div slot="footer">
  109. <el-button @click="cancel">取消</el-button>
  110. <el-button type="primary" @click="confirm">保存</el-button>
  111. </div>
  112. <saleOrderPop ref="saleOrderRef" @chooseOrder="chooseOrder"></saleOrderPop>
  113. <ProductModal ref="productRefs" @chooseModal="chooseModal" />
  114. <ProductionVersion ref="versionRefs" @changeProduct="changeProduct"></ProductionVersion>
  115. <timeDialog ref="timeDialogRef" @chooseTime="chooseTime"></timeDialog>
  116. </ele-modal>
  117. </template>
  118. <script>
  119. import saleOrderPop from './saleOrderPop.vue'
  120. import ProductModal from './ProductModal.vue'
  121. import { listBomBySalesOrderIds, listBomBySalesOrderId, save, getById } from '@/api/materialPlan/index';
  122. import ProductionVersion from '@/components/CreatePlan/ProductionVersion2.vue';
  123. import fileUpload from '@/components/upload/fileUpload';
  124. import timeDialog from './timeDialog'
  125. export default {
  126. components: {
  127. saleOrderPop,
  128. ProductModal,
  129. ProductionVersion,
  130. fileUpload,
  131. timeDialog
  132. },
  133. data() {
  134. return {
  135. visible: false,
  136. type: 'add',
  137. tableData: [],
  138. xsId: null,
  139. // 表格列配置
  140. columns: [
  141. {
  142. width: 45,
  143. type: 'expand',
  144. columnKey: 'materialList',
  145. align: 'center',
  146. slot: 'expand'
  147. },
  148. {
  149. width: 50,
  150. label: '序号',
  151. type: 'index',
  152. align: 'center',
  153. slot: 'index'
  154. },
  155. {
  156. prop: 'code',
  157. label: '销售订单号',
  158. slot: 'code',
  159. showOverflowTooltip: true,
  160. align: 'center',
  161. minWidth: 170
  162. },
  163. {
  164. prop: 'customerName',
  165. label: '客户名称',
  166. align: 'center',
  167. showOverflowTooltip: true
  168. },
  169. {
  170. prop: 'deliveryNum',
  171. label: '客户代号',
  172. align: 'center',
  173. showOverflowTooltip: true
  174. },
  175. {
  176. prop: 'productCode',
  177. label: '产品编码',
  178. align: 'center',
  179. showOverflowTooltip: true,
  180. minWidth: 140
  181. },
  182. {
  183. prop: 'productName',
  184. label: '产品名称',
  185. align: 'center',
  186. minWidth: 120
  187. },
  188. {
  189. prop: 'model',
  190. label: '型号',
  191. align: 'center',
  192. minWidth: 120
  193. },
  194. {
  195. prop: 'brandNo',
  196. label: '牌号',
  197. align: 'center'
  198. },
  199. {
  200. prop: 'deliveryTime',
  201. label: '交付日期',
  202. align: 'center',
  203. showOverflowTooltip: true
  204. },
  205. {
  206. prop: 'contractNum',
  207. label: '合同数量',
  208. align: 'center'
  209. },
  210. {
  211. prop: 'lackNum',
  212. label: '欠交数量',
  213. align: 'center'
  214. },
  215. {
  216. prop: 'productionPlanId',
  217. label: '工艺路线',
  218. slot: 'productionPlanId',
  219. align: 'center',
  220. minWidth: 110
  221. },
  222. {
  223. columnKey: 'action',
  224. label: '操作',
  225. width: 150,
  226. align: 'center',
  227. resizable: false,
  228. slot: 'action',
  229. showOverflowTooltip: true
  230. }
  231. ],
  232. columns2: [
  233. {
  234. width: 50,
  235. label: '序号',
  236. prop: 'sort',
  237. slot: 'sort',
  238. align: 'center',
  239. },
  240. {
  241. label: '物料名称',
  242. prop: 'name',
  243. align: 'center',
  244. },
  245. {
  246. label: '物料编码',
  247. prop: 'code',
  248. align: 'center',
  249. },
  250. {
  251. label: '牌号',
  252. prop: 'brandNum',
  253. align: 'center',
  254. },
  255. {
  256. label: '型号',
  257. prop: 'modelType',
  258. align: 'center',
  259. },
  260. {
  261. prop: 'inventoryQuantity',
  262. label: '库存',
  263. showOverflowTooltip: true,
  264. },
  265. {
  266. prop: 'unit',
  267. label: '计量单位',
  268. showOverflowTooltip: true,
  269. action: 'unit',
  270. slot: 'unit',
  271. },
  272. {
  273. label: '需求数量',
  274. slot: 'demandQuantity',
  275. action: 'demandQuantity',
  276. align: 'center',
  277. },
  278. {
  279. label: '采购数量',
  280. slot: 'purchaseQuantity',
  281. action: 'purchaseQuantity',
  282. align: 'center',
  283. },
  284. {
  285. label: '到货方式',
  286. slot: 'deliveryMethod',
  287. action: 'deliveryMethod',
  288. align: 'center',
  289. minWidth: 140
  290. },
  291. {
  292. label: '要求到货时间',
  293. slot: 'requireDeliveryTime',
  294. action: 'requireDeliveryTime',
  295. align: 'center',
  296. minWidth: 140
  297. },
  298. {
  299. label: '图纸',
  300. slot: 'imgUrl',
  301. action: ' imgUrl',
  302. align: 'center',
  303. minWidth: 140
  304. },
  305. {
  306. label: '附件',
  307. slot: 'files',
  308. action: ' files',
  309. align: 'center',
  310. minWidth: 140
  311. },
  312. {
  313. columnKey: 'action',
  314. label: '操作',
  315. width: 70,
  316. align: 'center',
  317. resizable: false,
  318. slot: 'action',
  319. showOverflowTooltip: true
  320. }
  321. ],
  322. rules: {
  323. name: [
  324. {
  325. required: true,
  326. message: '请输入配料计划名称',
  327. trigger: ['blur', 'change']
  328. }
  329. ],
  330. },
  331. formData: {
  332. name: '',
  333. remark: '',
  334. detailRemoveIds: [],
  335. materialRemoveIds: []
  336. },
  337. };
  338. },
  339. methods: {
  340. async open(type, row) {
  341. this.type = type;
  342. this.visible = true;
  343. if (row) {
  344. this.getDetail(row.id)
  345. } else {
  346. this.$nextTick(() => {
  347. this.$refs.table.setData([]);
  348. })
  349. }
  350. },
  351. getDetail(id) {
  352. getById(id).then(res => {
  353. this.$set(this.formData, 'name', res.name)
  354. this.$set(this.formData, 'remark', res.remark)
  355. this.formData['id'] = res.id
  356. this.$refs.table.setData([...res.salesOrderList]);
  357. this.$nextTick(() => {
  358. this.$refs.table.toggleRowExpansionAll()
  359. this.$forceUpdate()
  360. })
  361. })
  362. },
  363. confirm() {
  364. this.$refs.formRef.validate(async (value) => {
  365. if (value) {
  366. let _arr = this.$refs.table.getData() ?? []
  367. if (_arr.length == 0) {
  368. this.$message.info('请添加销售订单');
  369. return false
  370. }
  371. let _arr2 = []
  372. _arr2 = _arr.map(m => {
  373. if (Object.prototype.hasOwnProperty.call(m, "salesOrderId") && m.salesOrderId) {
  374. } else {
  375. m.salesOrderId = m.id
  376. m.salesOrderCode = m.code
  377. delete m.id
  378. delete m.code
  379. }
  380. return {
  381. ...m,
  382. }
  383. })
  384. this.formData['type'] = 1
  385. this.formData['salesOrderList'] = _arr2
  386. await save(this.formData);
  387. this.$message.success('保存成功!');
  388. this.$emit('success');
  389. this.cancel();
  390. }
  391. });
  392. },
  393. cancel() {
  394. this.visible = false;
  395. this.formData = {};
  396. this.formData.detailRemoveIds = []
  397. this.formData.materialRemoveIds = []
  398. this.$refs.table.setData([]);
  399. this.$refs.formRef.resetFields();
  400. },
  401. datasource({ }) {
  402. return []
  403. },
  404. reload() {
  405. this.$refs.table.reload();
  406. },
  407. showAdd() {
  408. this.tableData = this.$refs.table.getData();
  409. this.$refs.saleOrderRef.open(this.tableData)
  410. },
  411. chooseOrder(list) {
  412. let salesOrderIds = []
  413. list.map((m => {
  414. salesOrderIds.push(m.id)
  415. return {
  416. ...m,
  417. }
  418. }))
  419. if (salesOrderIds.length > 0) {
  420. listBomBySalesOrderIds({ salesOrderIds: salesOrderIds }).then((res) => {
  421. res.forEach(m => {
  422. if(m.materialList.length > 0) {
  423. m.materialList.forEach(p => {
  424. p.detailId = m.id
  425. })
  426. }
  427. })
  428. this.$refs.table.setData([...this.tableData, ...res]);
  429. this.$nextTick(() => {
  430. this.$refs.table.toggleRowExpansionAll()
  431. this.$forceUpdate()
  432. })
  433. })
  434. }
  435. },
  436. remove(row, index) {
  437. this.formData.detailRemoveIds.push(row.id)
  438. let _arr = this.$refs.table.getData() || [];
  439. _arr.splice(index, 1);
  440. this.$refs.table.setData([..._arr]);
  441. },
  442. categorySelect(row) {
  443. this.$refs.productRefs.open(row.materialList, row, this.type)
  444. },
  445. chooseModal(data, current) {
  446. data.map((m => {
  447. m.detailId = current.id
  448. return {
  449. ...m,
  450. }
  451. }))
  452. let tableList = []
  453. tableList = this.$refs.table.getData()
  454. tableList.forEach(e => {
  455. if (e.id == current.id) {
  456. if (e.materialList.length == 0) {
  457. e.materialList = data
  458. } else {
  459. e.materialList = [...e.materialList, ...data]
  460. }
  461. }
  462. })
  463. console.log(tableList);
  464. this.$refs.table.setData([...tableList]);
  465. this.$forceUpdate()
  466. },
  467. remove2(row) {
  468. const data = this.$refs.table.getData() ?? [];
  469. this.formData.materialRemoveIds.push(row.categoryId)
  470. data.forEach((e) => {
  471. if (row.detailId == e.id) {
  472. e.materialList = e.materialList.filter((d) => d.categoryId !== row.categoryId);
  473. }
  474. })
  475. this.$refs.table.setData([...data])
  476. this.$forceUpdate()
  477. },
  478. openVersion(row) {
  479. this.xsId = row.id
  480. this.$refs.versionRefs.open();
  481. },
  482. changeProduct(data) {
  483. let param = {
  484. salesOrderIds: [this.xsId],
  485. produceRoutingId: data.id
  486. }
  487. listBomBySalesOrderId(param).then((res) => {
  488. let tableList = []
  489. tableList = this.$refs.table.getData()
  490. tableList.forEach(e => {
  491. if (e.id == this.xsId) {
  492. res.map(m => {
  493. m.detailId = this.xsId
  494. return {
  495. ...m,
  496. }
  497. })
  498. e.materialList = res
  499. this.$nextTick(() => {
  500. this.$refs.table.setData([...tableList]);
  501. this.$refs.table.toggleRowExpansionAll()
  502. })
  503. }
  504. })
  505. })
  506. },
  507. handleMethod(row) {
  508. this.$refs.timeDialogRef.open(row)
  509. },
  510. chooseTime(current, timeList) {
  511. let tableList = []
  512. tableList = this.$refs.table.getData()
  513. tableList.forEach(e => {
  514. if (e.id == current.detailId) {
  515. e.materialList.forEach(m => {
  516. if (m.categoryId == current.categoryId) {
  517. m.timeList = timeList || []
  518. }
  519. })
  520. }
  521. })
  522. this.$refs.table.setData([...tableList]);
  523. this.$forceUpdate()
  524. }
  525. }
  526. };
  527. </script>
  528. <style lang="scss" scoped>
  529. :deep(.el-table__expanded-cell) {
  530. padding-bottom: 30px !important;
  531. border-bottom: 12px solid #CCFFCC !important;
  532. }
  533. </style>