certificateQualificationsDialog.vue 21 KB

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