splitDialog.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. <template>
  2. <ele-modal
  3. custom-class="ele-dialog-form long-dialog-form"
  4. :centered="true"
  5. :visible.sync="splitDialogFlag"
  6. title="拆分"
  7. :close-on-click-modal="false"
  8. width="80%"
  9. :before-close="cancel"
  10. :maxable="true"
  11. :resizable="true"
  12. >
  13. <el-form ref="form" :model="form" class="el-form-box" label-width="120px">
  14. <headerTitle title="基本信息"> </headerTitle>
  15. <expandPanel :contentStyle="{ height: '0px' }" :isExpand.sync="isExpand">
  16. <el-row>
  17. <el-col :span="12" style="height: 46px">
  18. <el-form-item label="需求单名称:" prop="requirementCode">
  19. <el-input v-model="form.requirementName" disabled></el-input>
  20. </el-form-item>
  21. </el-col>
  22. <el-col :span="12" style="height: 46px">
  23. <el-form-item label="计划单名称:" prop="planName">
  24. <el-input v-model="form.planName" disabled></el-input>
  25. <!-- {{ form.requirementCode }} -->
  26. </el-form-item>
  27. </el-col>
  28. <el-col :span="12">
  29. <el-form-item label="负责人:" prop="responsibleName">
  30. <el-input v-model="form.responsibleName" disabled></el-input>
  31. </el-form-item>
  32. </el-col>
  33. <el-col :span="12">
  34. <el-form-item label="需求类型:" prop="sourceTypeName">
  35. <el-input v-model="form.sourceTypeName" disabled></el-input>
  36. </el-form-item>
  37. </el-col>
  38. <el-col :span="12">
  39. <el-form-item label="需求部门:" prop="requireDeptName">
  40. <el-input v-model="form.requireDeptName" disabled></el-input>
  41. </el-form-item>
  42. </el-col>
  43. <el-col :span="12">
  44. <el-form-item label="需求人:" prop="requireUserName">
  45. <el-input v-model="form.requireUserName" disabled></el-input>
  46. </el-form-item>
  47. </el-col>
  48. <el-col :span="12">
  49. <el-form-item prop="remark" label="是否接受拆单:">
  50. <el-select
  51. v-model="form.acceptUnpack"
  52. placeholder="请选择"
  53. disabled
  54. style="width: 100%"
  55. >
  56. <el-option label="接受" :value="1"></el-option>
  57. <el-option label="不接受" :value="0"></el-option>
  58. </el-select>
  59. </el-form-item>
  60. </el-col>
  61. <el-col :span="12">
  62. <el-form-item label="完结日期:" prop="receiveDate">
  63. <el-input v-model="form.receiveDate" disabled></el-input>
  64. </el-form-item>
  65. </el-col>
  66. <el-col :span="12">
  67. <el-form-item prop="remark" label="备注:">
  68. <el-input v-model="form.remark" disabled></el-input>
  69. </el-form-item>
  70. </el-col>
  71. <el-col :span="12">
  72. <el-form-item prop="askFile" label="附件:">
  73. <el-link
  74. v-if="form.files && form.files !== ''"
  75. type="primary"
  76. :underline="false"
  77. @click="downloadFile(form.files)"
  78. >
  79. {{ form.files.name }}
  80. </el-link>
  81. </el-form-item>
  82. </el-col>
  83. </el-row>
  84. </expandPanel>
  85. <headerTitle title="计划清单" style="margin-top: 15px"></headerTitle>
  86. <ele-pro-table
  87. ref="table"
  88. :needPage="false"
  89. :columns="columns"
  90. :toolkit="[]"
  91. :selection.sync="selection"
  92. max-height="500px"
  93. :datasource="form.detailList"
  94. row-key="id"
  95. >
  96. <!-- 表头工具栏 -->
  97. <template v-slot:toolbar="{ row }">
  98. <el-button
  99. size="small"
  100. type="primary"
  101. icon="el-icon-plus"
  102. class="ele-btn-icon"
  103. @click="handleSplit"
  104. >
  105. 拆分
  106. </el-button>
  107. </template>
  108. <template v-slot:expectReceiveDate="scope">
  109. <el-form-item
  110. v-if="scope.row.arrivalWay == 1"
  111. label-width="0px"
  112. :rules="{
  113. required: true,
  114. message: '请选择日期',
  115. trigger: 'blur'
  116. }"
  117. >
  118. <el-date-picker
  119. style="width: 100%"
  120. clearable
  121. v-model="scope.row.expectReceiveDate"
  122. type="date"
  123. value-format="yyyy-MM-dd"
  124. placeholder="请选择日期"
  125. >
  126. </el-date-picker>
  127. </el-form-item>
  128. <el-form-item label-width="0px" v-if="scope.row.arrivalWay == 2">
  129. <el-link
  130. type="primary"
  131. :underline="false"
  132. @click.native="handleMethod(scope.row, scope.$index, '', 'form')"
  133. >
  134. 设置分批时间
  135. </el-link>
  136. </el-form-item>
  137. </template>
  138. <template v-slot:arrivalWay="scope">
  139. <el-form-item
  140. :rules="{
  141. required: true,
  142. message: '请选择',
  143. trigger: 'blur'
  144. }"
  145. label-width="0px"
  146. >
  147. <el-select
  148. v-model="scope.row.arrivalWay"
  149. clearable
  150. style="width: 100%"
  151. >
  152. <el-option
  153. v-for="item in arrivalWayList"
  154. :key="item.value"
  155. :label="item.label"
  156. :value="item.value"
  157. >
  158. </el-option>
  159. </el-select>
  160. </el-form-item>
  161. </template>
  162. <template v-slot:totalCount="scope">
  163. <span v-if="scope.row.totalCount">{{ scope.row.totalCount }}</span>
  164. <span v-else style="color: red">已全部拆完</span>
  165. </template>
  166. <template v-slot:technicalDrawings="{ row }">
  167. <div v-if="row.technicalDrawings && row.technicalDrawings?.length">
  168. <el-link
  169. v-for="link in row.technicalDrawings"
  170. :key="link.id"
  171. type="primary"
  172. :underline="false"
  173. @click="downloadFile(link)"
  174. >
  175. {{ link.name }}
  176. </el-link>
  177. </div>
  178. </template>
  179. <template v-slot:files="{ row }">
  180. <div v-if="row.files && row.files?.length">
  181. <el-link
  182. v-for="link in row.files"
  183. :key="link.id"
  184. type="primary"
  185. :underline="false"
  186. @click="downloadFile(link)"
  187. >
  188. {{ link.name }}
  189. </el-link>
  190. </div>
  191. </template>
  192. </ele-pro-table>
  193. </el-form>
  194. <headerTitle v-if="splitFormList.length" title="拆分明细" />
  195. <el-form
  196. v-if="splitFormList.length"
  197. :key="index"
  198. class="el-form-box"
  199. v-for="(item, index) in splitFormList"
  200. :model="item"
  201. >
  202. <el-row>
  203. <el-col :span="12">
  204. <el-form-item
  205. label="责任人"
  206. prop="responsibleName"
  207. label-width="80px"
  208. >
  209. <el-input
  210. @click.native="openStaffSelection(index)"
  211. v-model="item.responsibleName"
  212. placeholder="请选择"
  213. ></el-input>
  214. </el-form-item>
  215. </el-col>
  216. <el-col :span="12" style="display: flex; justify-content: flex-end">
  217. <el-button type="text" @click="handleMerge(index)" style="color: red">
  218. 删除</el-button
  219. >
  220. </el-col>
  221. </el-row>
  222. <!-- :selection.sync="selection[index]" -->
  223. <ele-pro-table
  224. ref="table"
  225. :needPage="false"
  226. :columns="splitColumns"
  227. :toolkit="[]"
  228. style="margin-bottom: 10px"
  229. :datasource="item.detailList"
  230. row-key="id"
  231. >
  232. <template v-slot:totalCount="{ row }">
  233. <el-input-number
  234. style="width: 100%"
  235. :min="0"
  236. :max="getCountMax(row)"
  237. @change="handleTotalCount(row, index)"
  238. v-model="row.totalCount"
  239. ></el-input-number>
  240. </template>
  241. <template v-slot:expectReceiveDate="scope">
  242. <el-form-item
  243. v-if="scope.row.arrivalWay == 1"
  244. label-width="0px"
  245. :rules="{
  246. required: true,
  247. message: '请选择日期',
  248. trigger: 'blur'
  249. }"
  250. >
  251. <el-date-picker
  252. style="width: 100%"
  253. clearable
  254. v-model="scope.row.expectReceiveDate"
  255. type="date"
  256. value-format="yyyy-MM-dd"
  257. placeholder="请选择日期"
  258. >
  259. </el-date-picker>
  260. </el-form-item>
  261. <el-form-item label-width="0px" v-if="scope.row.arrivalWay == 2">
  262. <el-link
  263. type="primary"
  264. :underline="false"
  265. @click.native="
  266. handleMethod(scope.row, scope.$index, index, 'splitForm')
  267. "
  268. >
  269. 设置分批时间
  270. </el-link>
  271. </el-form-item>
  272. </template>
  273. <template v-slot:arrivalWay="scope">
  274. <el-form-item
  275. :rules="{
  276. required: true,
  277. message: '请选择',
  278. trigger: 'blur'
  279. }"
  280. label-width="0px"
  281. >
  282. <el-select
  283. v-model="scope.row.arrivalWay"
  284. clearable
  285. style="width: 100%"
  286. >
  287. <el-option
  288. v-for="item in arrivalWayList"
  289. :key="item.value"
  290. :label="item.label"
  291. :value="item.value"
  292. >
  293. </el-option>
  294. </el-select>
  295. </el-form-item>
  296. </template>
  297. <template v-slot:action="scope">
  298. <el-popconfirm
  299. class="ele-action"
  300. title="确定要删除吗?"
  301. @confirm="handleRemove(index, scope.$index, scope.row)"
  302. >
  303. <template v-slot:reference>
  304. <el-link type="danger" :underline="false" icon="el-icon-delete">
  305. 删除
  306. </el-link>
  307. </template>
  308. </el-popconfirm>
  309. </template>
  310. </ele-pro-table>
  311. </el-form>
  312. <staffSelection
  313. ref="staffSelection"
  314. @confirm="confirmStaffSelection"
  315. ></staffSelection>
  316. <timeDialog @chooseTime="chooseTime" ref="timeDialogRef"></timeDialog>
  317. <div slot="footer" class="footer">
  318. <el-button type="primary" @click="save">保存</el-button>
  319. <el-button @click="cancel">返回</el-button>
  320. </div>
  321. </ele-modal>
  322. </template>
  323. <script>
  324. import personSelect from '@/components/CommomSelect/person-select.vue';
  325. import fileUpload from '@/components/upload/fileUpload.vue';
  326. import {
  327. getplanDetail,
  328. savePurchasePlanCutAPI
  329. } from '@/api/purchasingManage/purchasePlanManage';
  330. import { deepClone } from '@/utils';
  331. import expandPanel from '@/components/Expand-Panel/index.vue';
  332. import staffSelection from '@/views/purchasingManage/purchasePlanManage/components/staffSelection.vue';
  333. import timeDialog from '@/components/timeDialog/index.vue';
  334. import { copyObj } from '@/utils/util';
  335. export default {
  336. name: 'splitDialog',
  337. components: {
  338. timeDialog,
  339. staffSelection,
  340. fileUpload,
  341. personSelect,
  342. expandPanel
  343. },
  344. props: {
  345. splitDialogFlag: Boolean
  346. },
  347. data() {
  348. return {
  349. title: '',
  350. currentIndex: null,
  351. currentForm: null,
  352. isExpand: true,
  353. form: {},
  354. historyForm: {},
  355. splitFormList: [],
  356. rules: {},
  357. selection: [],
  358. columns: [
  359. {
  360. width: 45,
  361. type: 'index',
  362. columnKey: 'index',
  363. align: 'center',
  364. fixed: 'left'
  365. },
  366. {
  367. width: 45,
  368. type: 'selection',
  369. columnKey: 'selection',
  370. align: 'center',
  371. fixed: 'left',
  372. selectable: (row, index) => {
  373. return row.totalCount > 0;
  374. }
  375. },
  376. {
  377. minWidth: 120,
  378. prop: 'productCategoryName',
  379. label: '分类',
  380. slot: 'productCategoryName',
  381. align: 'center',
  382. showOverflowTooltip: true
  383. },
  384. {
  385. minWidth: 120,
  386. prop: 'productCode',
  387. label: '编码',
  388. slot: 'productCode',
  389. align: 'center',
  390. showOverflowTooltip: true
  391. },
  392. {
  393. minWidth: 150,
  394. prop: 'productName',
  395. label: '名称',
  396. slot: 'productName',
  397. align: 'center',
  398. showOverflowTooltip: true
  399. },
  400. {
  401. minWidth: 100,
  402. label: '状态',
  403. fixed: 'left',
  404. formatter: (row, column) => {
  405. return row.isInquiry == 1
  406. ? '部分核价'
  407. : row.isInquiry == 2
  408. ? '全部核价完成'
  409. : row.isInquiry == 3
  410. ? '核价中'
  411. : '未核价';
  412. },
  413. align: 'center'
  414. },
  415. {
  416. minWidth: 150,
  417. prop: 'totalCount',
  418. label: '数量',
  419. slot: 'totalCount',
  420. align: 'center'
  421. },
  422. {
  423. width: 150,
  424. prop: 'inquiryNum',
  425. label: '已核价数量',
  426. align: 'center'
  427. },
  428. {
  429. width: 100,
  430. prop: 'measuringUnit',
  431. label: '单位',
  432. slot: 'measuringUnit',
  433. align: 'center'
  434. },
  435. {
  436. width: 170,
  437. prop: 'planStartDate',
  438. label: '计划开始日期',
  439. slot: 'planStartDate',
  440. align: 'center'
  441. },
  442. {
  443. width: 170,
  444. prop: 'planEndDate',
  445. label: '计划结束日期',
  446. slot: 'planEndDate',
  447. align: 'center'
  448. },
  449. {
  450. width: 160,
  451. prop: 'arrivalWay',
  452. label: '到货方式',
  453. slot: 'arrivalWay',
  454. align: 'center'
  455. },
  456. {
  457. width: 170,
  458. prop: 'expectReceiveDate',
  459. label: '到货日期',
  460. slot: 'expectReceiveDate',
  461. align: 'center'
  462. }
  463. ],
  464. arrivalWayList: [
  465. { label: '一次性到货', value: 1 },
  466. { label: '分批到货', value: 2 }
  467. ],
  468. splitColumns: [
  469. {
  470. width: 45,
  471. type: 'index',
  472. columnKey: 'index',
  473. align: 'center',
  474. fixed: 'left'
  475. },
  476. {
  477. minWidth: 120,
  478. prop: 'productCategoryName',
  479. label: '分类',
  480. slot: 'productCategoryName',
  481. align: 'center',
  482. showOverflowTooltip: true
  483. },
  484. {
  485. minWidth: 120,
  486. prop: 'productCode',
  487. label: '编码',
  488. slot: 'productCode',
  489. align: 'center',
  490. showOverflowTooltip: true
  491. },
  492. {
  493. minWidth: 150,
  494. prop: 'productName',
  495. label: '名称',
  496. slot: 'productName',
  497. align: 'center',
  498. showOverflowTooltip: true
  499. },
  500. {
  501. minWidth: 160,
  502. prop: 'totalCount',
  503. label: '数量',
  504. slot: 'totalCount',
  505. align: 'center'
  506. },
  507. {
  508. width: 100,
  509. prop: 'measuringUnit',
  510. label: '单位',
  511. slot: 'measuringUnit',
  512. align: 'center'
  513. },
  514. {
  515. width: 170,
  516. prop: 'planStartDate',
  517. label: '计划开始日期',
  518. slot: 'planStartDate',
  519. align: 'center'
  520. },
  521. {
  522. width: 170,
  523. prop: 'planEndDate',
  524. label: '计划结束日期',
  525. slot: 'planEndDate',
  526. align: 'center'
  527. },
  528. {
  529. width: 150,
  530. prop: 'arrivalWay',
  531. label: '到货方式',
  532. slot: 'arrivalWay',
  533. align: 'center'
  534. },
  535. {
  536. width: 170,
  537. prop: 'expectReceiveDate',
  538. label: '到货日期',
  539. slot: 'expectReceiveDate',
  540. align: 'center'
  541. },
  542. {
  543. columnKey: 'action',
  544. label: '操作',
  545. width: 120,
  546. align: 'center',
  547. resizable: false,
  548. slot: 'action',
  549. fixed: 'right',
  550. showOverflowTooltip: true
  551. }
  552. ]
  553. };
  554. },
  555. computed: {
  556. getCountMax() {
  557. return (row) => {
  558. let maxCount = this.historyForm.detailList.find(
  559. (item) => row.id == item.id
  560. )?.totalCount;
  561. let usedCount = this.splitFormList.reduce((num, item) => {
  562. num += item.detailList.find((o) => o.id == row.id)?.totalCount || 0;
  563. return num;
  564. }, 0);
  565. let remainCount = maxCount - usedCount;
  566. let availableCount = remainCount + row.totalCount;
  567. this.setFormCount(row.id, remainCount);
  568. return availableCount;
  569. };
  570. }
  571. },
  572. methods: {
  573. init(row) {
  574. this.getPlanData(row.planId || row.id);
  575. },
  576. async getPlanData(id) {
  577. this.loading = true;
  578. const data = await getplanDetail(id);
  579. this.loading = false;
  580. if (data) {
  581. this.form = data;
  582. this.historyForm = deepClone(this.form);
  583. if (data.files && data.files.length > 0) {
  584. this.form.files = data.files[0];
  585. } else {
  586. this.form.files = null;
  587. }
  588. }
  589. },
  590. setFormCount(id, num) {
  591. let index = this.form.detailList.findIndex((item) => item.id == id);
  592. this.$set(this.form.detailList[index], 'totalCount', num);
  593. },
  594. handleTotalCount(row, formIndex) {
  595. row.arrivalBatch = [];
  596. let index = this.form.detailList.findIndex((item) => item.id == row.id);
  597. if (index >= 0) {
  598. this.form.detailList[index].arrivalBatch = [];
  599. }
  600. // this.splitFormList[formIndex].detailList.
  601. },
  602. handleSplit() {
  603. if (!this.selection.length) {
  604. this.$message.warning('请选择计划清单');
  605. return;
  606. }
  607. let form = deepClone(this.form);
  608. form.detailList = form.detailList.filter((item) =>
  609. this.selection.map((item) => item.id).includes(item.id)
  610. );
  611. this.openStaffSelection(this.splitFormList.length)
  612. this.splitFormList.push(form);
  613. },
  614. handleRemove(formIndex, index, row) {
  615. this.splitFormList[formIndex].detailList.splice(index, 1);
  616. let count = this.form.detailList.find(
  617. (item) => item.id == row.id
  618. )?.totalCount;
  619. count += row.totalCount;
  620. this.setFormCount(row.id, count);
  621. if (this.splitFormList[formIndex].detailList.length == 0) {
  622. this.handleMerge(formIndex, 'delAll');
  623. }
  624. },
  625. handleMerge(index, type) {
  626. // if (this.selection[index]?.length && type != 'delAll') {
  627. // this.selectionDel(index);
  628. // return;
  629. // }
  630. this.splitFormList.splice(index, 1);
  631. if (this.splitFormList.length == 0) {
  632. this.form = deepClone(this.historyForm);
  633. }
  634. },
  635. selectionDel(index) {
  636. this.selection[index].forEach((item) => {
  637. let i = this.splitFormList[index].detailList.findIndex(
  638. (val) => val.id == item.id
  639. );
  640. if (i != '-1') {
  641. this.handleRemove(index, i, item);
  642. }
  643. });
  644. // console.log(this.selection[index], 'this.selection[index]');
  645. },
  646. openStaffSelection(index) {
  647. console.log(index,'index')
  648. this.$refs.staffSelection.open(
  649. this.splitFormList[index]?.responsibleName
  650. ? [
  651. {
  652. name: this.splitFormList[index]?.responsibleName,
  653. id: this.splitFormList[index]?.responsibleId
  654. }
  655. ]
  656. : []
  657. );
  658. this.currentIndex = index;
  659. },
  660. confirmStaffSelection(data) {
  661. console.log(data,'data')
  662. this.$set(
  663. this.splitFormList[this.currentIndex],
  664. 'responsibleId',
  665. (data && data[0].id) || ''
  666. );
  667. this.$set(
  668. this.splitFormList[this.currentIndex],
  669. 'responsibleName',
  670. (data && data[0].name) || ''
  671. );
  672. },
  673. handleMethod(row, index, splitFormIndex, currentForm) {
  674. console.log(splitFormIndex);
  675. this.currentIndex = splitFormIndex;
  676. this.currentForm = currentForm;
  677. this.$refs.timeDialogRef.open(row, index);
  678. },
  679. chooseTime({ arrivalBatch, index }) {
  680. if (this.currentForm == 'splitForm') {
  681. console.log(
  682. index,
  683. 'this.splitFormList[this.currentIndex].detailList[index]'
  684. );
  685. this.$set(
  686. this.splitFormList[this.currentIndex].detailList[index],
  687. 'arrivalBatch',
  688. deepClone(arrivalBatch)
  689. );
  690. } else {
  691. this.$set(
  692. this.form.detailList[index],
  693. 'arrivalBatch',
  694. deepClone(arrivalBatch)
  695. );
  696. }
  697. },
  698. async save() {
  699. let copyList = deepClone(this.splitFormList);
  700. let isArrivalBatch = false;
  701. copyList.push(deepClone(this.form));
  702. copyList.forEach((item, index) => {
  703. item.detailList = item.detailList.filter((i) => i.totalCount > 0);
  704. item.detailList.forEach((i, _index) => {
  705. if (!i.arrivalBatch.length && i.arrivalWay == 2) {
  706. isArrivalBatch = true;
  707. }
  708. i.id = '';
  709. });
  710. item.parentId = item.id;
  711. item.id = '';
  712. });
  713. copyList = copyList.filter((item) => item.detailList.length);
  714. if (isArrivalBatch)
  715. return this.$message.warning('因数量变化请重新设置分批到货时间');
  716. await savePurchasePlanCutAPI(copyList);
  717. this.$message.success('操作成功');
  718. this.$emit('done');
  719. this.cancel();
  720. },
  721. cancel() {
  722. this.$emit('update:splitDialogFlag', false);
  723. }
  724. }
  725. };
  726. </script>
  727. <style scoped lang="scss">
  728. ::v-deep .el-input-number__increase.is-disabled {
  729. color: #ffffff;
  730. cursor: not-allowed;
  731. }
  732. ::v-deep .el-input-number__decrease.is-disabled {
  733. color: #ffffff;
  734. cursor: not-allowed;
  735. }
  736. </style>