splitDialog.vue 21 KB

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