certificateQualificationsDialog.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  1. <template>
  2. <ele-modal
  3. custom-class="ele-dialog-form long-dialog-form"
  4. :centered="true"
  5. :visible.sync="certificateQualificationsDialogFlag"
  6. :title="title"
  7. append-to-body
  8. :close-on-click-modal="false"
  9. width="70%"
  10. :before-close="cancel"
  11. :maxable="true"
  12. :resizable="true"
  13. >
  14. <el-tabs v-model="activeName" type="card">
  15. <el-tab-pane label="证书资质" name="QC">
  16. <el-form ref="form" :model="form" class="el-form-box">
  17. <headerTitle title="基本信息" />
  18. <el-row :gutter="20">
  19. <el-col :span="12">
  20. <el-form-item
  21. label-width="50px"
  22. label="名称"
  23. prop="name"
  24. >
  25. <el-input
  26. v-model="form.name"
  27. :disabled="type == 'view'"
  28. clearable
  29. ></el-input>
  30. </el-form-item>
  31. </el-col>
  32. <el-col :span="12">
  33. <el-form-item label="有效时间:" prop="date" label-width="90px">
  34. <el-date-picker
  35. :disabled="type == 'view'"
  36. v-model="form.date"
  37. style="width: 100%"
  38. type="daterange"
  39. value-format="yyyy-MM-dd"
  40. range-separator="至"
  41. start-placeholder="开始日期"
  42. end-placeholder="结束日期"
  43. >
  44. </el-date-picker>
  45. </el-form-item>
  46. </el-col>
  47. </el-row>
  48. <el-row :gutter="20">
  49. <el-col :span="12">
  50. <el-form-item label-width="50px" label="备注">
  51. <el-input
  52. type="textarea"
  53. v-model="form.remark"
  54. :disabled="type == 'view'"
  55. clearable
  56. ></el-input>
  57. </el-form-item>
  58. </el-col>
  59. <el-col :span="12">
  60. <el-form-item label="附件:" prop="accessory" label-width="90px">
  61. <fileMain v-model="form.accessory" :type="type"></fileMain>
  62. </el-form-item>
  63. </el-col>
  64. </el-row>
  65. <headerTitle title="资质信息" />
  66. <ele-pro-table
  67. ref="linkTable"
  68. :columns="columns"
  69. :datasource="form.detailsList"
  70. :toolkit="[]"
  71. height="300px"
  72. :need-page="false"
  73. >
  74. <!-- 表头工具栏 -->
  75. <template v-slot:toolbar>
  76. <el-button
  77. v-if="type !== 'view'"
  78. type="primary"
  79. @click="handleAdd"
  80. >添加</el-button
  81. >
  82. </template>
  83. <template v-slot:name="scope">
  84. <el-form-item
  85. :prop="'detailsList.' + scope.$index + '.name'"
  86. :rules="{
  87. required: true,
  88. message: '',
  89. trigger: 'change'
  90. }"
  91. >
  92. <el-select
  93. v-if="type !== 'view'"
  94. v-model="scope.row.name"
  95. clearable
  96. @change="(val) => handleChangeType(val, scope.row)"
  97. >
  98. <el-option
  99. :disabled="
  100. disabledToType(scope.row).includes(item.dictCode)
  101. "
  102. v-for="item in dictList"
  103. :value="item.dictValue"
  104. :label="item.dictValue"
  105. ></el-option>
  106. </el-select>
  107. <!-- <DictSelection v-if="type!=='view'" clearable dictName="客户/供应商资质类型" v-model="scope.row.type"-->
  108. <!-- @itemChange="(val)=>handleChangeType(val,scope.row)"></DictSelection>-->
  109. <span v-else>{{ scope.row.name }}</span>
  110. </el-form-item>
  111. </template>
  112. <template v-slot:code="scope">
  113. <el-form-item
  114. :prop="'detailsList.' + scope.$index + '.code'"
  115. >
  116. <el-input
  117. v-model="scope.row.code"
  118. :disabled="type == 'view'"
  119. clearable
  120. ></el-input>
  121. </el-form-item>
  122. </template>
  123. <template v-slot:businessRange="scope">
  124. <el-form-item
  125. :prop="'detailsList.' + scope.$index + '.businessRange'"
  126. >
  127. <el-input
  128. type="textarea"
  129. v-model="scope.row.businessRange"
  130. :disabled="type == 'view'"
  131. clearable
  132. ></el-input>
  133. </el-form-item>
  134. </template>
  135. <template v-slot:startTime="scope">
  136. <el-form-item
  137. inline-message
  138. :prop="'detailsList.' + scope.$index + '.startTime'"
  139. :rules="{
  140. required: false,
  141. message: '',
  142. trigger: 'change'
  143. }"
  144. >
  145. <el-date-picker
  146. :disabled="type == 'view'"
  147. v-model="scope.row.startTime"
  148. type="date"
  149. style="width: 100%"
  150. value-format="yyyy-MM-dd"
  151. placeholder="选择日期"
  152. >
  153. </el-date-picker>
  154. </el-form-item>
  155. </template>
  156. <template v-slot:endTime="scope">
  157. <el-form-item
  158. :prop="'detailsList.' + scope.$index + '.endTime'"
  159. :rules="{
  160. required: false,
  161. validator: validateEndDate(scope.row, scope.$index),
  162. trigger: ['blur', 'change']
  163. }"
  164. >
  165. <el-date-picker
  166. :disabled="type == 'view'"
  167. v-model="scope.row.endTime"
  168. type="date"
  169. style="width: 100%"
  170. value-format="yyyy-MM-dd"
  171. placeholder="选择日期"
  172. >
  173. </el-date-picker>
  174. </el-form-item>
  175. </template>
  176. <template v-slot:noticePersonName="scope">
  177. <el-form-item
  178. :prop="'detailsList.' + scope.$index + '.noticePersonName'"
  179. >
  180. <el-input
  181. :disabled="type == 'view'"
  182. @click.native="openStaffSelection(scope.$index)"
  183. v-model="scope.row.noticePersonName"
  184. placeholder="请选择"
  185. ></el-input>
  186. </el-form-item>
  187. </template>
  188. <template v-slot:accessory="scope">
  189. <el-form-item
  190. :prop="'detailsList.' + scope.$index + '.accessory'"
  191. :rules="{
  192. required: true,
  193. message: '',
  194. trigger: ['change', 'blur']
  195. }"
  196. >
  197. <fileMain v-model="scope.row.accessory" :type="type"></fileMain>
  198. </el-form-item>
  199. </template>
  200. <template v-slot:type="scope">
  201. <el-form-item :prop="'detailsList.' + scope.$index + '.type'">
  202. <el-select
  203. v-if="type !== 'view'"
  204. v-model="scope.row.type"
  205. clearable
  206. >
  207. <el-option
  208. v-for="item in typeList"
  209. :value="item.dictCode"
  210. :label="item.dictValue"
  211. ></el-option>
  212. </el-select>
  213. <span v-else>{{ getLabelName(typeList, scope.row.type) }}</span>
  214. </el-form-item>
  215. </template>
  216. <template v-slot:level="scope">
  217. <el-form-item :prop="'detailsList.' + scope.$index + '.level'">
  218. <el-select
  219. v-if="type !== 'view'"
  220. v-model="scope.row.level"
  221. clearable
  222. >
  223. <el-option
  224. v-for="item in levelOptions"
  225. :value="item.dictCode"
  226. :label="item.dictValue"
  227. ></el-option>
  228. </el-select>
  229. <!-- <DictSelection v-if="type!=='view'" clearable dictName="客户/供应商资质类型" v-model="scope.row.type"-->
  230. <!-- @itemChange="(val)=>handleChangeType(val,scope.row)"></DictSelection>-->
  231. <span v-else>{{
  232. getLabelName(levelOptions, scope.row.type)
  233. }}</span>
  234. </el-form-item>
  235. </template>
  236. <template v-slot:remark="scope">
  237. <el-form-item :prop="'detailsList.' + scope.$index + '.remark'">
  238. <el-input
  239. type="textarea"
  240. :disabled="type == 'view'"
  241. v-model="scope.row.remark"
  242. ></el-input>
  243. </el-form-item>
  244. </template>
  245. <template v-slot:status="scope">
  246. <el-form-item :prop="'detailsList.' + scope.$index + '.status'">
  247. <el-tag
  248. v-if="scope.row.status"
  249. :type="statusTagTypeList[scope.row.status]"
  250. >
  251. {{ statusList[scope.row.status] }}
  252. </el-tag>
  253. </el-form-item>
  254. </template>
  255. <template v-slot:isRequired="{ column }">
  256. <span class="is-required">{{ column.label }}</span>
  257. </template>
  258. <template v-slot:action="{ row, $index }">
  259. <el-popconfirm
  260. class="ele-action"
  261. title="确定要删除该信息吗?"
  262. @confirm="handleRemove($index)"
  263. >
  264. <template v-slot:reference>
  265. <el-link
  266. v-if="type !== 'view'"
  267. type="danger"
  268. :underline="false"
  269. icon="el-icon-delete"
  270. >
  271. 删除
  272. </el-link>
  273. </template>
  274. </el-popconfirm>
  275. </template>
  276. </ele-pro-table>
  277. </el-form>
  278. </el-tab-pane>
  279. <el-tab-pane
  280. v-if="form.processInstanceId"
  281. label="流程详情"
  282. name="processInstance"
  283. >
  284. <bpmDetail
  285. :id="form.processInstanceId"
  286. v-if="activeName == 'processInstance'"
  287. ></bpmDetail>
  288. </el-tab-pane>
  289. </el-tabs>
  290. <div slot="footer" v-if="activeName == 'QC'">
  291. <el-button
  292. v-if="type !== 'view'"
  293. type="primary"
  294. @click="handleSave(false)"
  295. >保存</el-button
  296. >
  297. <el-button
  298. v-if="isNeed_process_is_close && type !== 'view' && contactInfo.id"
  299. type="primary"
  300. plan
  301. @click="handleSave(true)"
  302. >提交</el-button
  303. >
  304. <el-button @click="cancel">返回</el-button>
  305. </div>
  306. <staffSelection
  307. ref="staffSelection"
  308. @confirm="confirmStaffSelection"
  309. ></staffSelection>
  310. <process-submit-dialog
  311. :processSubmitDialogFlag.sync="processSubmitDialogFlag"
  312. v-if="processSubmitDialogFlag"
  313. ref="processSubmitDialogRef"
  314. @reload="reload"
  315. ></process-submit-dialog>
  316. </ele-modal>
  317. </template>
  318. <script>
  319. import FileUpload from '@/components/upload/fileUpload.vue';
  320. import staffSelection from '@/components/staffSelection/staffSelection.vue';
  321. import {
  322. contactQcPackDetailAPI,
  323. contactQcPackSaveAPI,
  324. contactQcPackUpdateAPI,
  325. contactQcSubmit
  326. } from '@/api/saleManage/contact';
  327. import { getFile } from '@/api/system/file';
  328. import bpmDetail from '@/views/bpm/processInstance/detail.vue';
  329. import { mapActions, mapGetters } from 'vuex';
  330. import dictEnum from '@/enum/dict';
  331. import fileMain from '@/components/addDoc/index.vue';
  332. import processSubmitDialog from '@/BIZComponents/processSubmitDialog/processSubmitDialog.vue';
  333. export default {
  334. name: 'certificateQualificationsDialog',
  335. components: {
  336. processSubmitDialog,
  337. fileMain,
  338. bpmDetail,
  339. FileUpload,
  340. staffSelection
  341. },
  342. props: {
  343. certificateQualificationsDialogFlag: Boolean,
  344. contactInfo: Object,
  345. typeInfo: String
  346. },
  347. data() {
  348. return {
  349. title: '',
  350. type: '',
  351. activeName: 'QC',
  352. defaultData: {
  353. accessory: [],
  354. name: '',
  355. noticePersonId: '',
  356. noticePersonName: '',
  357. num: '',
  358. remark: '',
  359. businessRange: '',
  360. type: '',
  361. endTime: '',
  362. startTime: ''
  363. },
  364. form: {
  365. accessory: [],
  366. detailsList: [],
  367. relationName: '',
  368. name: '',
  369. date: [],
  370. remark: ''
  371. },
  372. curIndex: null,
  373. index: '',
  374. processSubmitDialogFlag: false,
  375. levelOptions: [
  376. {
  377. dictValue: '初级',
  378. dictCode: '1'
  379. },
  380. {
  381. dictValue: '中级',
  382. dictCode: '2'
  383. },
  384. {
  385. dictValue: '高级',
  386. dictCode: '3'
  387. }
  388. ],
  389. statusList: {
  390. 10: '有效',
  391. 20: '无效',
  392. 30: '已过期'
  393. },
  394. statusTagTypeList: {
  395. 10: 'success',
  396. 20: 'info',
  397. 30: 'danger'
  398. }
  399. };
  400. },
  401. computed: {
  402. ...mapGetters(['dict']),
  403. dictList() {
  404. return this.dict[dictEnum['客户/供应商资质类型']] || [];
  405. },
  406. typeList() {
  407. return this.dict[dictEnum['工种类型']] || [];
  408. },
  409. columns() {
  410. return [
  411. {
  412. type: 'index',
  413. width: 55,
  414. align: 'center'
  415. },
  416. {
  417. label: '名称',
  418. prop: 'name',
  419. slot: 'name',
  420. headerSlot: 'isRequired',
  421. minWidth: 180,
  422. align: 'center'
  423. },
  424. {
  425. label: '编号',
  426. prop: 'code',
  427. slot: 'code',
  428. // headerSlot: 'isRequired',
  429. minWidth: 120,
  430. align: 'center'
  431. },
  432. {
  433. label: '许可/经营范围',
  434. prop: 'businessRange',
  435. slot: 'businessRange',
  436. minWidth: 140,
  437. align: 'center'
  438. },
  439. {
  440. label: '有效期起始日期',
  441. prop: 'startTime',
  442. slot: 'startTime',
  443. // headerSlot: 'isRequired',
  444. minWidth: 160,
  445. align: 'center'
  446. },
  447. {
  448. label: '有效期截止日期',
  449. prop: 'endTime',
  450. slot: 'endTime',
  451. // headerSlot: 'isRequired',
  452. minWidth: 160,
  453. align: 'center'
  454. },
  455. {
  456. label: '通知人',
  457. prop: 'noticePersonName',
  458. slot: 'noticePersonName',
  459. // headerSlot: 'isRequired',
  460. minWidth: 140,
  461. align: 'center'
  462. },
  463. {
  464. label: '附件',
  465. prop: 'accessory',
  466. slot: 'accessory',
  467. headerSlot: 'isRequired',
  468. minWidth: 140
  469. },
  470. {
  471. label: '等级',
  472. prop: 'level',
  473. slot: 'level',
  474. minWidth: 140,
  475. align: 'center'
  476. },
  477. {
  478. label: '分类',
  479. prop: 'type',
  480. slot: 'type',
  481. minWidth: 140,
  482. align: 'center'
  483. },
  484. {
  485. label: '备注',
  486. prop: 'remark',
  487. slot: 'remark',
  488. minWidth: 140,
  489. align: 'center'
  490. },
  491. {
  492. label: '状态',
  493. prop: 'status',
  494. slot: 'status',
  495. align: 'center'
  496. },
  497. {
  498. action: 'action',
  499. slot: 'action',
  500. label: '操作',
  501. align: 'center',
  502. fixed: 'right'
  503. }
  504. ];
  505. },
  506. disabledToType() {
  507. return (row) => {
  508. let list = this.form.detailsList.map((item) => item.name);
  509. let dictCodeList = this.dictList.map((item) => item.dictCode);
  510. let intersectionList = list.filter(
  511. (v) => dictCodeList.indexOf(v) > -1
  512. );
  513. intersectionList = intersectionList.filter((v) => row.name !== v);
  514. return intersectionList;
  515. };
  516. }
  517. },
  518. created() {
  519. this.requestDict('客户/供应商资质类型');
  520. this.requestDict('工种类型');
  521. },
  522. methods: {
  523. ...mapActions('dict', ['requestDict']),
  524. getLabelName(arr, id) {
  525. if (!id) return '';
  526. return arr.find((item) => item.dictCode == id)?.dictValue;
  527. },
  528. //删除资质
  529. handleRemove(index) {
  530. this.form.detailsList.splice(index, 1);
  531. },
  532. //结束日期验证
  533. validateEndDate(row, index) {
  534. return (rule, value, callback) => {
  535. //new Error('')
  536. if (!value) return callback();
  537. if (row.endTime && row.startTime && value < row.startTime) {
  538. callback(new Error('截止日期不能小于起始日期'));
  539. } else {
  540. callback();
  541. }
  542. };
  543. },
  544. //页面初始化
  545. init(type, row = {}, index) {
  546. this.title =
  547. type == 'add' ? '新增' : type == 'update' ? '修改' : '详情';
  548. this.type = type;
  549. if (type !== 'add') {
  550. if (this.contactInfo.id) {
  551. this.getCertificateInfo(row);
  552. } else {
  553. this.form = row;
  554. this.index = index;
  555. // this.form.date=[this.form.startTime, this.form.endTime];
  556. this.$set(this.form, 'date', [
  557. this.form.startTime,
  558. this.form.endTime
  559. ]);
  560. }
  561. }
  562. },
  563. async getCertificateInfo(row) {
  564. this.form = await contactQcPackDetailAPI(row.id);
  565. this.$set(this.form, 'date', [this.form.startTime, this.form.endTime]);
  566. },
  567. //打开选择负责人弹窗
  568. openStaffSelection(index) {
  569. this.curIndex = index;
  570. this.$refs.staffSelection.open([]);
  571. },
  572. //选择负责人回调
  573. confirmStaffSelection(data) {
  574. this.form.detailsList[this.curIndex].noticePersonName = data
  575. .map((item) => item.name)
  576. .toString();
  577. this.form.detailsList[this.curIndex].noticePersonId = data
  578. .map((item) => item.id)
  579. .toString();
  580. },
  581. //新增
  582. handleAdd() {
  583. this.form.detailsList.push({ ...this.defaultData });
  584. },
  585. //修改资质证书
  586. handleChangeType(val, row) {
  587. if (!val) return (row.name = '');
  588. // row.name = this.dictList.find(i => i.dictCode == val)?.dictValue || ''
  589. },
  590. downloadFile(file) {
  591. getFile({ objectName: file.storePath }, file.name);
  592. },
  593. //保存/提交
  594. handleSave(isSub) {
  595. this.$refs.form.validate(async (valid) => {
  596. if (!valid) return this.$message.warning('有必填项未填写,请检查');
  597. if (!this.form.detailsList.length)
  598. return this.$message.warning('至少保存一条资质信息');
  599. this.form.certificationType = this.typeInfo;
  600. this.form.relationId = this.contactInfo.id;
  601. this.form.relationName = this.contactInfo.name;
  602. this.form.startTime = this.form.date[0];
  603. this.form.endTime = this.form.date[1];
  604. if (!this.contactInfo.id) {
  605. this.$emit('success', { form: this.form, index: this.index });
  606. this.cancel();
  607. return;
  608. }
  609. let api =
  610. this.type == 'add' ? contactQcPackSaveAPI : contactQcPackUpdateAPI;
  611. let id = await api(this.form);
  612. if (isSub) {
  613. // await contactQcSubmit({businessId: id, certificationType: this.typeInfo})
  614. await this.submit({
  615. businessId: id,
  616. certificationType: this.typeInfo
  617. });
  618. return;
  619. }
  620. this.$message.success('保存成功');
  621. this.$emit('success', {});
  622. this.cancel();
  623. });
  624. },
  625. async submit(row) {
  626. let data = await contactQcPackDetailAPI(this.form.id || row.businessId);
  627. this.processSubmitDialogFlag = true;
  628. this.$nextTick(() => {
  629. let key =
  630. this.typeInfo == 1 ? 'contact_qc_approve' : 'supplier_qc_approve';
  631. let params = {
  632. businessId: data.id,
  633. businessKey: key,
  634. formCreateUserId: data.createUserId,
  635. variables: {
  636. certificationType: this.typeInfo
  637. }
  638. // callBackMethodType : '1',
  639. // callBackMethod : 'proTargetPlanApproveApiImpl.updatePlanApprovalStatus',
  640. // pcHandle : '/bpm/handleTask/components/project-manage/plan-manage/submit.vue',
  641. // pcView : '/bpm/handleTask/components/project-manage/plan-manage/detailDialog.vue',
  642. // miniHandle : '',
  643. // miniView : '',
  644. };
  645. this.$refs.processSubmitDialogRef.init(params);
  646. });
  647. },
  648. reload() {
  649. this.$emit('success', {});
  650. this.cancel();
  651. },
  652. //关闭弹窗
  653. cancel() {
  654. this.$emit('update:certificateQualificationsDialogFlag', false);
  655. }
  656. }
  657. };
  658. </script>
  659. <style scoped lang="scss">
  660. :deep.el-form-item {
  661. margin-bottom: 0;
  662. }
  663. </style>