addDialog.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  1. <template>
  2. <ele-modal
  3. custom-class="ele-dialog-form long-dialog-form"
  4. :centered="true"
  5. :visible="addFlag"
  6. :title="title"
  7. append-to-body
  8. :close-on-click-modal="false"
  9. width="1100px"
  10. :before-close="cancel"
  11. :maxable="true"
  12. :resizable="true"
  13. >
  14. <div style="height: 100%;">
  15. <div>
  16. <el-form
  17. class="ele-form-search"
  18. >
  19. <el-row
  20. :gutter="15"
  21. style="display: flex; align-items: center"
  22. >
  23. <el-col v-bind="{ span: 10 }">
  24. <el-form-item label="单据:" label-width="60px">
  25. <el-select v-model="formId"
  26. @change="init"
  27. >
  28. <el-option
  29. v-for="(item, index) in list"
  30. :key="index"
  31. :value="item.id"
  32. :label="item.name"
  33. ></el-option>
  34. </el-select>
  35. </el-form-item>
  36. </el-col>
  37. </el-row>
  38. </el-form>
  39. </div>
  40. <div style="display: flex; height: 100%; justify-content: space-between">
  41. <div class="form-box">
  42. <el-form
  43. ref="form1"
  44. :rules="rules"
  45. class="el-form-box"
  46. :model="form"
  47. label-width="90px"
  48. :label-position="'left'"
  49. style="padding: 10px"
  50. >
  51. <el-row>
  52. <el-col :span="24">
  53. <el-form-item label="流程分类">
  54. <ele-tree-select
  55. @change="changeLCFL"
  56. clearable
  57. ref="processTypeRef"
  58. filterable
  59. :data="LCFLList"
  60. v-model="form.LCFL"
  61. childrenKey="children"
  62. valueKey="id"
  63. labelKey="name"
  64. placeholder="请选择"
  65. default-expand-all
  66. />
  67. </el-form-item>
  68. </el-col>
  69. <el-col :span="24">
  70. <el-form-item label="发起流程">
  71. <el-select
  72. filterable
  73. v-model="form.FQLC"
  74. @change="changeFQLC"
  75. style="width: 100%"
  76. >
  77. <el-option
  78. v-for="item in processList"
  79. :key="item.id"
  80. :value="item.id"
  81. :label="item.name"
  82. ></el-option>
  83. </el-select>
  84. </el-form-item>
  85. </el-col> </el-row
  86. ></el-form>
  87. <fm-generate-form
  88. :preview="true"
  89. class="el-form-box"
  90. v-if="Object.keys(form?.formJson || {}).length !== 0"
  91. :data="jsonData"
  92. :value="form.valueJson"
  93. ref="generateForm"
  94. >
  95. <!-- 客户名称 -->
  96. <template v-slot:eom_contact="scope">
  97. <div class="eom_contact">
  98. <el-input
  99. v-model="scope.model.eom_contact.name"
  100. style="width: 100%"
  101. @click.native="addContact('eom_contact')"
  102. ></el-input>
  103. </div>
  104. </template>
  105. </fm-generate-form>
  106. </div>
  107. <div
  108. style="
  109. align-self: center;
  110. display: flex;
  111. color: #1890ff;
  112. cursor: pointer;
  113. width: 15px;
  114. "
  115. @click="() => (isRight = !isRight)"
  116. >
  117. <span
  118. style="
  119. align-self: center;
  120. transform: scale(1.5);
  121. "
  122. :class="isRight ? 'el-icon-caret-left' : 'el-icon-caret-right'"
  123. >
  124. </span>
  125. <span style="writing-mode: vertical-rl">选择流程</span>
  126. </div>
  127. <div style="flex: 1" v-if="isRight">
  128. <el-form
  129. ref="form"
  130. :rules="rules"
  131. class="el-form-box"
  132. :model="form"
  133. label-width="80px"
  134. >
  135. <el-row>
  136. <el-col :span="12">
  137. <el-form-item label="流程分类">
  138. <ele-tree-select
  139. @change="changeLCFL"
  140. clearable
  141. ref="processTypeRef"
  142. filterable
  143. :data="LCFLList"
  144. v-model="form.LCFL"
  145. childrenKey="children"
  146. valueKey="id"
  147. labelKey="name"
  148. placeholder="请选择"
  149. default-expand-all
  150. />
  151. </el-form-item>
  152. </el-col>
  153. <el-col :span="12">
  154. <el-form-item label="发起流程">
  155. <el-select
  156. filterable
  157. v-model="form.FQLC"
  158. @change="changeFQLC"
  159. style="width: 100%"
  160. >
  161. <el-option
  162. v-for="item in processList"
  163. :key="item.id"
  164. :value="item.id"
  165. :label="item.name"
  166. ></el-option>
  167. </el-select>
  168. </el-form-item>
  169. </el-col>
  170. </el-row>
  171. <el-row>
  172. <el-col :span="12">
  173. <el-form-item label="流程名称">
  174. <el-input v-model="form.name" clearable></el-input>
  175. </el-form-item>
  176. </el-col>
  177. <el-col :span="12">
  178. <el-form-item label="流程标识">
  179. <el-input v-model="form.key" disabled></el-input>
  180. </el-form-item>
  181. </el-col>
  182. </el-row>
  183. <headerTitle
  184. title="流程执行人/流程图"
  185. style="margin-top: 30px"
  186. ></headerTitle>
  187. <el-table
  188. :data="datasource"
  189. height="150px"
  190. border
  191. style="margin-bottom: 10px"
  192. >
  193. <el-table-column
  194. label="任务节点"
  195. align="center"
  196. prop="taskDefinitionName"
  197. width="140"
  198. fixed
  199. />
  200. <el-table-column
  201. label="执行人"
  202. align="center"
  203. prop="options"
  204. min-width="140px"
  205. >
  206. <template v-slot="scope">
  207. <div
  208. v-if="
  209. scope.row.type !== 60 &&
  210. scope.row.type !== 70 &&
  211. scope.row.options.length > 0
  212. "
  213. >
  214. <el-tag
  215. size="medium"
  216. :key="option"
  217. v-for="option in scope.row.options"
  218. >
  219. {{ getAssignRuleOptionName(scope.row, option) }}
  220. </el-tag>
  221. </div>
  222. <el-tag
  223. size="medium"
  224. v-if="
  225. scope.row.type === 60 ||
  226. scope.row.type === 70 ||
  227. scope.row.type === 80
  228. "
  229. >
  230. {{ getAssignRuleOptionName(scope.row) }}
  231. </el-tag>
  232. </template>
  233. </el-table-column>
  234. </el-table>
  235. <my-process-viewer
  236. style="min-width: 100%; height: 200px"
  237. key="designer"
  238. v-model="bpmnXML"
  239. />
  240. </el-form>
  241. </div>
  242. </div>
  243. </div>
  244. <div slot="footer">
  245. <el-form :model="form">
  246. <el-form-item label="通知人:">
  247. <el-button
  248. style="float: left; margin-top: 5px"
  249. icon="el-icon-circle-plus-outline"
  250. round
  251. @click="handleEditDataScope"
  252. ></el-button>
  253. <div style="display: flex; flex-direction: row; flex-wrap: wrap">
  254. <el-tag
  255. style="float: left; margin: 5px 5px 0 5px"
  256. v-for="(item, index) in form.noticeScope"
  257. :key="item.name"
  258. effect="plain"
  259. closable
  260. :title="item.name"
  261. @close="handleCloseTag(index)"
  262. >
  263. {{
  264. item.name.length > 3
  265. ? item.name[0] + item.name[1] + item.name[2] + '...'
  266. : item.name
  267. }}
  268. </el-tag>
  269. </div>
  270. </el-form-item>
  271. </el-form>
  272. <el-button type="primary" size="small" v-click-once @click="submit">提交</el-button>
  273. <el-button size="small" @click="cancel">关闭</el-button>
  274. <staffSelection
  275. ref="staffSelection"
  276. @confirm="getTreeList"
  277. ></staffSelection>
  278. </div>
  279. <parentList
  280. ref="parentRef"
  281. @changeParent="handleConcatConfirm"
  282. ></parentList>
  283. </ele-modal>
  284. </template>
  285. <script>
  286. import {
  287. getModelPage,
  288. getProcessDefinitionBpmnXML,
  289. processInstanceCreateAPI,
  290. getTaskAssignRuleList,
  291. listAllUserBind,
  292. listSimpleUserGroups,
  293. } from './api';
  294. import { listRoles } from '@/api/system/role';
  295. import dictMixins from '@/mixins/dictMixins';
  296. import { getModel } from '@/api/bpm/model';
  297. import { getToken } from '@/utils/token-util';
  298. import { mapGetters } from 'vuex';
  299. import staffSelection from '@/components/staffSelection/staffSelection.vue';
  300. import dayjs from 'dayjs';
  301. import parentList from '@/views/saleManage/contact/components/parentList.vue';
  302. import { treeClassifyCodeEnum } from '@/enum/dict';
  303. import { listOrganizations } from '@/api/system/organization';
  304. import { getByCode } from '@/api/system/dictionary-data';
  305. import { getGroupUserTree, getProduceTreeByCode } from '@/api/main';
  306. import { topLevel1, topLevel2, topLevel3 } from '@/enum/dict';
  307. import { parameterGetByCode } from '@/api/main/index.js';
  308. export default {
  309. name: 'processSubmitDialog',
  310. components: { staffSelection, parentList },
  311. mixins: [dictMixins],
  312. props: {
  313. addFlag: {
  314. type: Boolean,
  315. default: false
  316. },
  317. list: {
  318. type: Array,
  319. default: () => []
  320. },
  321. },
  322. watch: {
  323. filterText(val) {
  324. this.$refs.tree.filter(val);
  325. }
  326. },
  327. data() {
  328. return {
  329. visibilityRangeDialogFlag: false,
  330. isRight: false,
  331. jsonData: {},
  332. form: {
  333. LCFL: '',
  334. FQLC: '',
  335. processDefinitionId: '',
  336. name: '',
  337. businessId: '',
  338. noticeScope: [],
  339. formJson: {},
  340. valueJson: {},
  341. businessKey: ''
  342. },
  343. formId: '',
  344. title: '',
  345. active: 0,
  346. bpmnXML: null,
  347. filterText: null,
  348. treeList: [],
  349. treeData: [],
  350. defaultProps: {
  351. children: 'children',
  352. label: 'name'
  353. },
  354. LCFLList: [],
  355. processList: [],
  356. datasource: [],
  357. roleOptions: [],
  358. deptOptions: [],
  359. deptTreeOptions: [],
  360. postOptions: [],
  361. userOptions: [],
  362. userGroupOptions: [],
  363. dictList: {},
  364. rules: {},
  365. editForm: {
  366. start: '',
  367. end: '',
  368. days: ''
  369. },
  370. };
  371. },
  372. computed: {
  373. ...mapGetters(['user']),
  374. modelWidth() {
  375. let width =
  376. this.jsonData.config?.platform &&
  377. this.jsonData.config.platform === 'pc'
  378. ? 1100
  379. : 450;
  380. if (this.isRight) {
  381. return width + 350 + 'px';
  382. } else {
  383. return width + 'px';
  384. }
  385. }
  386. },
  387. async created() {
  388. let typeObj = await getProduceTreeByCode(
  389. treeClassifyCodeEnum['PROCESSTYPE']
  390. );
  391. // await this.getTreeData();
  392. this.LCFLList = typeObj[0].children;
  393. // 获得角色列表
  394. this.roleOptions = [];
  395. listRoles({
  396. current: 1,
  397. size: 9999
  398. }).then((data) => {
  399. this.roleOptions.push(...data.list);
  400. });
  401. // 获得部门列表
  402. this.deptOptions = [];
  403. this.deptTreeOptions = [];
  404. listOrganizations().then((data) => {
  405. this.deptOptions.push(...data);
  406. this.deptTreeOptions.push(...this.handleTree(data, 'id'));
  407. });
  408. // 获得岗位列表 暂无岗位概念
  409. this.postOptions = [];
  410. /*listSimplePosts().then(response => {
  411. this.postOptions.push(...response.data);
  412. });*/
  413. // 获得用户列表
  414. this.userOptions = [];
  415. listAllUserBind().then((data) => {
  416. this.userOptions.push(...data);
  417. });
  418. // 获得用户组列表
  419. this.userGroupOptions = [];
  420. listSimpleUserGroups().then((response) => {
  421. this.userGroupOptions.push(...response);
  422. });
  423. //this.dictEnum['工作流任务分配自定义脚本']
  424. await this.getDictList(this.dictEnum['工作流任务分配自定义脚本']);
  425. await this.getDictList(this.dictEnum['工种类型']);
  426. },
  427. mounted() {
  428. },
  429. methods: {
  430. async addContact(type) {
  431. console.log(type);
  432. let data = await this.$refs.generateForm.getData(false);
  433. console.log('data', data);
  434. data[type] = {
  435. id: '',
  436. name: ''
  437. };
  438. this.$refs.generateForm.setData({
  439. type: data[type]
  440. });
  441. let item = {
  442. id: data[type].id
  443. };
  444. this.$refs.parentRef.open(item);
  445. },
  446. async handleConcatConfirm(item) {
  447. console.log('选择的客户', item);
  448. let data = await this.$refs.generateForm.getData(false);
  449. data['eom_contact'] = {
  450. id: item.id,
  451. name: item.name
  452. }
  453. this.$refs.generateForm.setData({
  454. 'eom_contact': data['eom_contact']
  455. });
  456. console.log('data~~~~', data);
  457. },
  458. async init(id) {
  459. const row = this.list.find(item => item.id === id) || {};
  460. this.title = row.name; //'新建' + row.name + '单';
  461. this.form = _.cloneDeep(row);
  462. this.form.formId = row.id;
  463. this.$set(this.form, 'noticeScope', []);
  464. this.$set(this.form, 'LCFL', '');
  465. this.$set(this.form, 'FQLC', '');
  466. this.$set(this.form, 'name', '');
  467. this.$set(this.form, 'key', '');
  468. this.$set(this.form, 'valueJson', {});
  469. this.jsonData = JSON.parse(this.form.formJson.makingJson);
  470. console.log('jsonData', this.jsonData);
  471. this.jsonData.config.dataSource &&
  472. this.jsonData.config.dataSource.forEach((item) => {
  473. item.headers = {
  474. Authorization: getToken()
  475. };
  476. // item.url = item.url && item.url.replace('/api', this.APIUrl);
  477. });
  478. this.jsonData.list.forEach((item) => {
  479. if (item.type == 'deptAndUserCascader') {
  480. }
  481. if (item.type == 'deptCascader') {
  482. if (item.options.isDefaultLoginUser) {
  483. this.form.valueJson[item.model] = this.user.info.groupIdList;
  484. }
  485. }
  486. if (item.type == 'userSelect') {
  487. if (item.options.isDefaultLoginUser) {
  488. this.form.valueJson[item.model] = this.user.info.userId;
  489. }
  490. }
  491. if (item.type == 'imgupload') {
  492. // this.form.valueJson[item.model].length &&
  493. // this.form.valueJson[item.model].forEach((item) => {
  494. // //item.objectUrl = this.APIUrl +'/kd-aiot' + item.storePath
  495. // // item.objectUrl = item.url;
  496. // // console.log(item);
  497. // });
  498. }
  499. });
  500. await this.getProcessDefinitionBpmnXMLInfo(this.form.processModelId);
  501. await this.getTaskAssignRuleListInfo({
  502. modelId: this.form.processModelId,
  503. processDefinitionId: this.form.processDefinitionId
  504. });
  505. await this.getDefaultInfo(row.processModelId);
  506. },
  507. async getDefaultInfo(businessKey) {
  508. let info = await getModel(businessKey);
  509. //let info = await getProcessDefinitionInfo({ id: businessKey });
  510. parameterGetByCode({
  511. code: 'wt_collaborative_bpm'
  512. }).then((res) => {
  513. if (!res.value||res.value=='1') {
  514. this.form.FQLC = info?.id;
  515. this.form.name = this.title;
  516. this.form.key = info?.key;
  517. }
  518. });
  519. this.form.LCFL = info?.category;
  520. if (this.form.LCFL) await this.getProcessList(this.form.LCFL);
  521. },
  522. async getProcessList(val) {
  523. let params = {
  524. pageNo: 1,
  525. pageSize: 999,
  526. processTypeId: val
  527. };
  528. const { list } = await getModelPage(params);
  529. this.processList = list.filter((item) => item.processDefinition);
  530. },
  531. async getProcessDefinitionBpmnXML(val) {
  532. this.bpmnXML = await getProcessDefinitionBpmnXML(val);
  533. },
  534. async getProcessDefinitionBpmnXMLInfo(val) {
  535. // 加载流程图
  536. let res = await getModel(val);
  537. this.bpmnXML = res.bpmnXml;
  538. },
  539. async getTaskAssignRuleListInfo(find) {
  540. this.datasource = await getTaskAssignRuleList({
  541. modelId: find.modelId,
  542. processDefinitionId: find.processDefinitionId
  543. });
  544. },
  545. handleEditDataScope() {
  546. this.$refs.staffSelection.open(this.form.noticeScope);
  547. // this.visibilityRangeDialogFlag = true;
  548. // this.$nextTick(() => {
  549. // this.$refs.visibilityRangeDialogRef.init(this.form);
  550. // });
  551. },
  552. getTreeList(list) {
  553. list.forEach((item) => {
  554. item.type = 1;
  555. });
  556. this.form.noticeScope = list;
  557. },
  558. handleCloseTag(index) {
  559. this.form.noticeScope.splice(index, 1);
  560. },
  561. getAssignRuleOptionName(row, option) {
  562. if (row.type == 10) {
  563. for (const roleOption of this.roleOptions) {
  564. if (roleOption.id === option) {
  565. return roleOption.name;
  566. }
  567. }
  568. } else if (row.type === 20 || row.type === 21) {
  569. for (const deptOption of this.deptOptions) {
  570. if (deptOption.id === option) {
  571. return deptOption.name;
  572. }
  573. }
  574. } else if (row.type === 22) {
  575. option = option + ''; // 转换成 string
  576. return this.getDictV(this.dictEnum['工种类型'], option);
  577. } else if (row.type === 30 || row.type === 31 || row.type === 32) {
  578. for (const userOption of this.userOptions) {
  579. if (userOption.id === option) {
  580. return userOption.nickname || userOption.name;
  581. }
  582. }
  583. } else if (row.type === 40) {
  584. for (const userGroupOption of this.userGroupOptions) {
  585. if (userGroupOption.id === option) {
  586. return userGroupOption.name;
  587. }
  588. }
  589. } else if (row.type === 50) {
  590. option = option + ''; // 转换成 string
  591. return this.getDictV(
  592. this.dictEnum['工作流任务分配自定义脚本'],
  593. option
  594. );
  595. } else if (row.type === 60) {
  596. return row.variableName;
  597. } else if (row.type === 70) {
  598. let data = JSON.parse(row.variableName);
  599. if (data.direction == 1) {
  600. return topLevel2.find((item) => item.value == data.topLevel)?.label;
  601. } else {
  602. return topLevel1.find((item) => item.value == data.topLevel)?.label;
  603. }
  604. } else if (row.type === 80) {
  605. let data = JSON.parse(row.variableName);
  606. return topLevel3.find((item) => item.value == data.topLevel)?.label;
  607. }
  608. return '未知(' + option + ')';
  609. },
  610. async getTreeData() {
  611. this.treeData = await getGroupUserTree();
  612. },
  613. filterNode(value, data) {
  614. if (!value) return true;
  615. return data.name.indexOf(value) !== -1;
  616. },
  617. /**
  618. * 构造树型结构数据
  619. * @param {*} data 数据源
  620. * @param {*} id id字段 默认 'id'
  621. * @param {*} parentId 父节点字段 默认 'parentId'
  622. * @param {*} children 孩子节点字段 默认 'children'
  623. * @param {*} rootId 根Id 默认 0
  624. */
  625. handleTree(data, id, parentId, children, rootId) {
  626. id = id || 'id';
  627. parentId = parentId || 'parentId';
  628. children = children || 'children';
  629. rootId =
  630. rootId ||
  631. Math.min.apply(
  632. Math,
  633. data.map((item) => {
  634. return item[parentId];
  635. })
  636. ) ||
  637. 0;
  638. //对源数据深度克隆
  639. const cloneData = JSON.parse(JSON.stringify(data));
  640. //循环所有项
  641. const treeData = cloneData.filter((father) => {
  642. let branchArr = cloneData.filter((child) => {
  643. //返回每一项的子级数组
  644. return father[id] == child[parentId];
  645. });
  646. branchArr.length > 0 ? (father.children = branchArr) : '';
  647. //返回第一层
  648. return father[parentId] == rootId;
  649. });
  650. return treeData !== '' ? treeData : data;
  651. },
  652. getDictV(code, val) {
  653. if (!this.dictList[code]) return '';
  654. return this.dictList[code].find((item) => item.value == val)?.label;
  655. },
  656. async getDictList(code) {
  657. let { data: res } = await getByCode(code);
  658. this.dictList[code] = res.map((item) => {
  659. let values = Object.keys(item);
  660. return {
  661. value: values[0],
  662. label: item[values[0]]
  663. };
  664. });
  665. },
  666. generateFormValid(validate = true) {
  667. return this.$refs.generateForm.getData(validate).then((data) => {
  668. console.log('data~~~', data);
  669. return data;
  670. }).catch((err) => {
  671. this.$message.error(err);
  672. console.log('err~~~', err);
  673. });
  674. },
  675. handleTreeChange() {
  676. this.$nextTick(() => {
  677. this.form.noticeScope =
  678. this.$refs.treeSelect.$refs.tree.getCheckedNodes();
  679. console.log(this.form.noticeScope);
  680. });
  681. },
  682. async changeLCFL(val) {
  683. this.bpmnXML = null;
  684. this.form.processDefinitionId = null;
  685. this.form.FQLC = null;
  686. await this.getProcessList(val);
  687. },
  688. async changeFQLC(val) {
  689. if (!val) return;
  690. let find = this.processList.find((item) => item.id === val) || {};
  691. this.form.name = find.name;
  692. this.form.key = find.key;
  693. this.form.processDefinitionId = find.processDefinition.id;
  694. this.form.processModelId = val;
  695. await this.getProcessDefinitionBpmnXML(find.processDefinition.id);
  696. await this.getTaskAssignRuleListInfo({
  697. modelId: find.id,
  698. processDefinitionId: find.processDefinition.id
  699. });
  700. },
  701. async submit() {
  702. this.form.valueJson = await this.generateFormValid()
  703. this.form.processType = '1';
  704. console.log('formformformform', this.form);
  705. await processInstanceCreateAPI({
  706. ...this.form,
  707. variables: {
  708. ...this.form.valueJson,
  709. businessCode: this.form.code,
  710. businessName: this.form.name,
  711. businessType: this.form.categoryName
  712. }
  713. });
  714. this.$message('提交审核成功');
  715. this.$emit('reload');
  716. this.cancel();
  717. },
  718. cancel() {
  719. this.$emit('update:addFlag', false);
  720. },
  721. getDays(start, end) {
  722. const startDay = dayjs(start);
  723. const endDay = dayjs(end);
  724. const diffInMilliseconds = endDay.diff(startDay);
  725. // 计算天数
  726. const days = Math.floor(diffInMilliseconds / (1000 * 60 * 60 * 24));
  727. // 计算剩余小时数
  728. const hours = Math.floor(
  729. (diffInMilliseconds % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)
  730. );
  731. // 计算剩余分钟数
  732. const minutes = Math.floor(
  733. (diffInMilliseconds % (1000 * 60 * 60)) / (1000 * 60)
  734. );
  735. // 计算剩余秒数
  736. const seconds = Math.floor((diffInMilliseconds % (1000 * 60)) / 1000);
  737. let result = '';
  738. if (days > 0) result += `${days} 天 `;
  739. if (hours > 0) result += `${hours} 小时 `;
  740. if (minutes > 0) result += `${minutes} 分钟 `;
  741. if (seconds > 0) result += `${seconds} 秒`;
  742. return result.trim();
  743. }
  744. }
  745. };
  746. </script>
  747. <style scoped lang="scss">
  748. .form-box {
  749. // max-height: 500px;
  750. min-width: 400px;
  751. overflow: auto;
  752. background: #4298fd0d;
  753. }
  754. ::v-deep .el-dialog {
  755. min-width: 400px;
  756. .el-dialog__header {
  757. background: #1890ffd6;
  758. }
  759. .el-dialog__title,
  760. .el-dialog__close {
  761. color: #ffffff;
  762. }
  763. }
  764. </style>