handle.vue 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225
  1. <template>
  2. <div class="app-container">
  3. <div v-if="isLoadingStatus"></div>
  4. <div v-else>
  5. <el-alert
  6. v-if="
  7. activeIndex !== nodeStepList.length &&
  8. processStructureValue.workOrder.is_end === 1
  9. "
  10. style="margin-top: 15px"
  11. :title="alertMessage"
  12. type="error"
  13. :closable="false"
  14. />
  15. <el-card class="box-card" style="margin-top: 15px">
  16. <div slot="header" class="clearfix">
  17. <span>公共信息</span>
  18. </div>
  19. <div class="text item">
  20. <el-form label-width="100px">
  21. <el-row>
  22. <el-col :span="6">
  23. <el-form-item label="编号(ID):" style="margin-bottom: 5px">
  24. <span>{{ this.workOrderId }}</span>
  25. </el-form-item>
  26. </el-col>
  27. <el-col :span="18">
  28. <el-form-item label="标题:" style="margin-bottom: 5px">
  29. <span>{{ processStructureValue.workOrder.title }}</span>
  30. </el-form-item>
  31. </el-col>
  32. <el-col :span="6">
  33. <el-form-item label="优先级:" style="margin-bottom: 0">
  34. <span v-if="processStructureValue.workOrder.priority === 2">
  35. <el-tag type="warning">紧急</el-tag>
  36. </span>
  37. <span
  38. v-else-if="processStructureValue.workOrder.priority === 3"
  39. >
  40. <el-tag type="danger">非常紧急</el-tag>
  41. </span>
  42. <span v-else>
  43. <el-tag type="success">一般</el-tag>
  44. </span>
  45. </el-form-item>
  46. </el-col>
  47. <el-col :span="18">
  48. <el-form-item label="工单类型:" style="margin-bottom: 5px">
  49. <span>{{ processStructureValue.process.name }}</span>
  50. </el-form-item>
  51. </el-col>
  52. </el-row>
  53. </el-form>
  54. </div>
  55. </el-card>
  56. <el-card class="box-card" style="margin-top: 15px">
  57. <div slot="header" class="clearfix">
  58. <span>表单信息</span>
  59. </div>
  60. <div class="text item">
  61. <template v-for="(tplItem, tplIndex) in processStructureValue.tpls">
  62. <fm-generate-form
  63. v-show="
  64. currentNode.hideTpls === undefined ||
  65. currentNode.hideTpls === null ||
  66. currentNode.hideTpls.indexOf(tplItem.form_structure.id) === -1
  67. "
  68. :key="tplIndex"
  69. :ref="'generateForm-' + tplItem.id"
  70. :preview="true"
  71. :remote="remoteFunc"
  72. :value="tplItem.form_data"
  73. :data="tplItem.form_structure"
  74. :organ-list="organList"
  75. />
  76. </template>
  77. </div>
  78. <hr
  79. v-if="is_end == 0"
  80. style="
  81. background-color: #d9d9d9;
  82. border: 0;
  83. height: 1px;
  84. margin-bottom: 15px;
  85. "
  86. />
  87. <div class="text item" style="margin-top: 18px; text-align: center">
  88. <!-- 只要没有结束就可以评论 -->
  89. <el-button round type="info" @click="handleCommit"
  90. >评论</el-button
  91. >
  92. <template v-if="is_end == 0 && processStructureValue.userAuthority">
  93. <!-- 没有结束,自己审批 -->
  94. <el-button
  95. type="warning"
  96. round
  97. @click="handleInversion(endNodeDetail)"
  98. >转交</el-button
  99. >
  100. <el-button
  101. v-for="(item, index) in btn_group"
  102. :key="index"
  103. :type="item.className"
  104. @click="submitAction(item)"
  105. round
  106. >{{ item.labelShow }}</el-button
  107. >
  108. <!-- 拒绝按钮内置 -->
  109. <el-button
  110. v-if="endNodeDetail.id"
  111. type="danger"
  112. round
  113. @click="submitAction(endNodeDetail)"
  114. >{{ endNodeDetail.label }}</el-button
  115. >
  116. </template>
  117. </div>
  118. </el-card>
  119. <el-card class="box-card" style="margin-top: 15px">
  120. <div slot="header" class="clearfix">
  121. <span>流程</span>
  122. </div>
  123. <div class="text item">
  124. <el-timeline
  125. v-if="
  126. currentNode.clazz !== undefined &&
  127. currentNode.clazz !== null &&
  128. currentNode.clazz !== ''
  129. "
  130. >
  131. <el-timeline-item
  132. v-for="(item, index) in circulationList"
  133. :key="index"
  134. :icon="formatIcon(item, index, 'icon')"
  135. :class="activeIndex >= index ? 'large-icon' : ''"
  136. size="large"
  137. >
  138. <div class="step-title">
  139. {{ item.state || item.label }}
  140. <span class="apply-time">
  141. {{
  142. item.create_time
  143. ? dayjs(item.create_time).format("MM-DD HH:mm")
  144. : null
  145. }}
  146. </span>
  147. </div>
  148. <template v-if="!item.create_time">
  149. <p
  150. class="apply-status"
  151. v-if="item.assignUsers && item.assignUsers.length > 0"
  152. >
  153. <!-- 判断是否是自己审批 -->
  154. <template
  155. v-if="
  156. item.assignUsers[0].userId == userInfo.userId &&
  157. activeIndex == index
  158. "
  159. >
  160. 我(审批中)
  161. </template>
  162. <template v-else>
  163. <template v-if="item.isCounterSign">
  164. <span
  165. v-for="(au, aIndex) in item.assignUsers"
  166. :key="aIndex"
  167. >
  168. {{ au.username
  169. }}{{
  170. aIndex < item.assignUsers.length - 1 ? "," : null
  171. }}
  172. </span>
  173. </template>
  174. <template v-else>
  175. {{ item.assignUsers[0].username }}
  176. </template>
  177. {{ activeIndex == index ? `(审批中)` : null }}
  178. </template>
  179. </p>
  180. </template>
  181. <template v-else>
  182. <p class="apply-status" v-if="item.processor">
  183. {{ item.processor
  184. }}{{ item.circulation ? `(${item.circulation})` : null }}
  185. </p>
  186. <template v-if="item.remarks && item.remarks.trim()">
  187. <p
  188. class="remarks"
  189. v-html="dataModelFormatBr(item.remarks)"
  190. ></p>
  191. </template>
  192. <!-- 判断是否有添加图片 -->
  193. <div
  194. class="imgUploader"
  195. v-if="
  196. item.fileUrl &&
  197. item.fileUrl.file &&
  198. item.fileUrl.image.length > 0
  199. "
  200. >
  201. <el-image
  202. v-for="(file, index) in item.fileUrl.image"
  203. :key="index"
  204. style="width: 40px; height: 40px; margin-right: 12px"
  205. :src="file"
  206. :preview-src-list="item.fileUrl.image"
  207. >
  208. </el-image>
  209. </div>
  210. <!-- 判断是否有添加的文件 -->
  211. <div
  212. v-if="
  213. item.fileUrl &&
  214. item.fileUrl.file &&
  215. item.fileUrl.file.length > 0
  216. "
  217. >
  218. <div
  219. v-for="(uploadUrlItem, uploadUrlIndex) in item.fileUrl.file"
  220. :key="uploadUrlIndex"
  221. style="margin-bottom: 3px"
  222. class="fileUploader"
  223. >
  224. <i style="color: #909399" class="el-icon-document" />
  225. <span style="margin-right: 10px">{{
  226. uploadUrlItem.name || uploadUrlItem.url
  227. }}</span>
  228. <el-button
  229. round
  230. size="mini"
  231. @click="onDownload(uploadUrlItem, 'download')"
  232. >下载</el-button
  233. >
  234. <!-- <el-button
  235. round
  236. type="primary"
  237. @click="onDownload(uploadUrlItem)"
  238. v-if="checkFileSuffix(uploadUrlItem.url)"
  239. size="mini"
  240. >预览</el-button
  241. > -->
  242. <el-button
  243. round
  244. type="primary"
  245. @click="onDownload(uploadUrlItem)"
  246. v-if="
  247. checkFileSuffix(uploadUrlItem.url) &&
  248. !isCheckImage(uploadUrlItem.url)
  249. "
  250. size="mini"
  251. >预览</el-button
  252. >
  253. <div
  254. v-if="isCheckImage(uploadUrlItem.url)"
  255. style="
  256. display: inline-flex;
  257. position: relative;
  258. margin-left: 10px;
  259. "
  260. >
  261. <el-button
  262. style="position: absolute; left: 0; top: 0"
  263. round
  264. type="primary"
  265. @click="onDownload(uploadUrlItem)"
  266. v-if="checkFileSuffix(uploadUrlItem.url)"
  267. size="mini"
  268. >预览</el-button
  269. >
  270. <el-image
  271. style="width: 56px; height: 28px; opacity: 0"
  272. :src="uploadUrlItem.url"
  273. :preview-src-list="[uploadUrlItem.url]"
  274. >
  275. </el-image>
  276. </div>
  277. </div>
  278. </div>
  279. </template>
  280. <!-- 有抄送人并且,本节点已经审批完成了 -->
  281. <template
  282. v-if="
  283. item.cc_user && item.cc_user.length > 0 && activeIndex > index
  284. "
  285. >
  286. <!-- 已抄送1人 -->
  287. <div class="ccUsers" @click="onCCChange(item)">
  288. <span>已抄送{{ item.cc_user.length }}人</span>
  289. <el-icon
  290. v-show="!item.ccStatus"
  291. style="color: #cccccc"
  292. name="arrow-down"
  293. />
  294. <el-icon
  295. v-show="item.ccStatus"
  296. style="color: #cccccc"
  297. name="arrow-up"
  298. />
  299. </div>
  300. <div class="ccUserDetail" v-if="item.ccStatus">
  301. <span>{{ item.cc_user.join(",") }}</span>
  302. </div>
  303. </template>
  304. </el-timeline-item>
  305. </el-timeline>
  306. </div>
  307. </el-card>
  308. </div>
  309. <el-dialog title="转交工单" :visible.sync="dialogVisible" width="40%">
  310. <TransferInversion
  311. v-if="dialogVisible"
  312. :selectItem="selectItem"
  313. @getList="getProcessNodeList"
  314. @close="dialogVisible = false"
  315. />
  316. </el-dialog>
  317. <el-dialog :title="submitTitle" :visible.sync="dialogSubmit" width="40%">
  318. <TransferSubmit
  319. v-if="dialogSubmit"
  320. :type="submitType"
  321. :submitItem="submitItem"
  322. @getList="getProcessNodeList"
  323. @close="dialogSubmit = false"
  324. />
  325. </el-dialog>
  326. </div>
  327. </template>
  328. <script>
  329. import Upload from "./model/upload";
  330. import Vue from "vue";
  331. import { GenerateForm } from "@/components/VueFormMaking";
  332. import "form-making/dist/FormMaking.css";
  333. Vue.component(GenerateForm.name, GenerateForm);
  334. import dayjs from "dayjs";
  335. import {
  336. processStructure,
  337. handleWorkOrder,
  338. activeOrder,
  339. asyncPlayLog,
  340. queryUserInfo,
  341. queryAllToOrgan,
  342. queryTeacherOrgan,
  343. orderComment,
  344. } from "@/api/process/work-order";
  345. import store from "@/store";
  346. import { getInfo } from "@/api/user";
  347. import { listUser } from "@/api/system/sysuser";
  348. import TransferInversion from "./model/transferInversion";
  349. import TransferSubmit from "./model/transferSubmit.vue";
  350. import load from "@/utils/loading";
  351. import { mapGetters } from "vuex";
  352. export default {
  353. components: {
  354. TransferInversion,
  355. TransferSubmit,
  356. Upload,
  357. },
  358. data() {
  359. const query = this.$route.query;
  360. return {
  361. submitTitle: "提交信息",
  362. dialogSubmit: false,
  363. submitType: "commit",
  364. submitItem: {},
  365. workOrderId: query.workOrderId,
  366. processId: query.processId,
  367. isLoadingStatus: true,
  368. currentNode: {
  369. hideTpls: null,
  370. writeTpls: null,
  371. },
  372. isActiveProcessing: false,
  373. tpls: [],
  374. organList: [],
  375. dataList: {
  376. remarks: "", // 备注信息
  377. },
  378. fileUrl: [],
  379. userInfo: {},
  380. alertMessage: "",
  381. nodeStepList: [],
  382. circulationHistoryList: [],
  383. circulationList: [],
  384. activeIndex: 0,
  385. processStructureValue: {
  386. workOrder: { title: "" },
  387. },
  388. ownerApply: false, // 是否是自己提交的申请
  389. endNodeDetail: {}, // 结束结节信息
  390. ruleForm: {
  391. title: "",
  392. process: "",
  393. classify: "",
  394. state_id: "",
  395. state: "",
  396. source_state: "",
  397. processor: "",
  398. process_method: "",
  399. tpls: [],
  400. tasks: [],
  401. },
  402. userIds: null,
  403. tenantId: 1,
  404. userType: "SYSTEM",
  405. btn_group: [],
  406. is_end: 0, // 是否结束
  407. remoteFunc: {
  408. // 获取用户列表
  409. userList(resolve) {
  410. listUser({
  411. pageSize: 999999,
  412. }).then((response) => {
  413. const options = response.data.list;
  414. resolve(options);
  415. });
  416. },
  417. },
  418. dialogVisible: false,
  419. selectItem: {
  420. work_order_id: "",
  421. node_id: null,
  422. nodeList: [],
  423. users: [],
  424. },
  425. };
  426. },
  427. computed: {
  428. ...mapGetters(["userId"]),
  429. },
  430. async mounted() {
  431. await this.getUserInfo();
  432. await this.getAllOrgan();
  433. await this.getProcessNodeList();
  434. // 获取用户信息
  435. try {
  436. let user = await getInfo();
  437. this.userInfo = user.data;
  438. this.ownerApply =
  439. this.processStructureValue.workOrder.creator == user.data.userId
  440. ? true
  441. : false;
  442. } catch {
  443. //
  444. }
  445. console.log({
  446. is_end: this.is_end,
  447. ownerApply: this.ownerApply,
  448. userAuthority: this.processStructureValue.userAuthority,
  449. });
  450. },
  451. methods: {
  452. dayjs,
  453. // 获取学校列表
  454. onDownload(item, type) {
  455. if (type == "download") {
  456. window.location.href = item.url;
  457. return;
  458. }
  459. let urlArr = item.url.split(".");
  460. let suffix = urlArr[urlArr.length - 1];
  461. const imgSuffix = ["png", "jpg", "jpeg", "gif", "ico"];
  462. if (imgSuffix.includes(suffix)) {
  463. } else if (suffix != "pdf") {
  464. this.previewUrl =
  465. "https://view.officeapps.live.com/op/view.aspx?src=" + item.url;
  466. window.open(this.previewUrl);
  467. return;
  468. } else {
  469. this.previewUrl =
  470. this.validManageUrl() + "/pdf/web/viewer.html?file=" + item.url;
  471. window.open(this.previewUrl);
  472. return;
  473. }
  474. },
  475. // 教务地址
  476. validManageUrl() {
  477. let url = window.location.hostname;
  478. let returnUrl = "";
  479. if (/dev/.test(url)) {
  480. // dev 环境
  481. returnUrl = "https://dev.gym.lexiaoya.cn/manager";
  482. } else if (/test/.test(url)) {
  483. // dev 环境
  484. returnUrl = "https://test.gym.lexiaoya.cn/manager";
  485. } else {
  486. //线上
  487. returnUrl = "https://gym.lexiaoya.cn/manager";
  488. }
  489. return returnUrl;
  490. },
  491. isCheckImage(file) {
  492. const urlArr = file.split(".");
  493. const suffix = urlArr[urlArr.length - 1];
  494. const imgSuffix = ["png", "jpg", "jpeg", "gif", "ico"];
  495. console.log(imgSuffix.includes(suffix), "11");
  496. return imgSuffix.includes(suffix);
  497. },
  498. checkFileSuffix(url) {
  499. let urlArr = url.split(".");
  500. let suffix = urlArr[urlArr.length - 1];
  501. const passSuffix = [
  502. "xlsx",
  503. "xls",
  504. "pdf",
  505. "png",
  506. "jpg",
  507. "jpeg",
  508. "gif",
  509. "ico",
  510. ];
  511. if (passSuffix.includes(suffix)) {
  512. return true;
  513. } else {
  514. return false;
  515. }
  516. },
  517. async handleCommit() {
  518. console.log("handleCommit", true);
  519. this.submitTitle = "添加评论";
  520. this.submitType = "commit";
  521. this.submitItem = {
  522. workOrderId: parseInt(this.workOrderId),
  523. };
  524. this.dialogSubmit = true;
  525. },
  526. async handleInversion() {
  527. let workOrder = this.processStructureValue.workOrder;
  528. this.selectItem.work_order_id = workOrder.id;
  529. this.selectItem.nodeList = workOrder.state || [];
  530. this.selectItem.nodeList.forEach((item) => {
  531. item.text = item.label;
  532. });
  533. if (this.selectItem.nodeList.length === 1) {
  534. this.selectItem.node_id = this.selectItem.nodeList[0].id;
  535. }
  536. if (this.selectItem.users.length <= 0) {
  537. load.startLoading();
  538. await listUser({
  539. pageSize: 999999,
  540. }).then((response) => {
  541. this.selectItem.users = response.data.list;
  542. });
  543. load.endLoading();
  544. }
  545. this.dialogVisible = true;
  546. },
  547. async getUserInfo() {
  548. await queryUserInfo().then((res) => {
  549. // console.log(res);
  550. if (res.code == 200) {
  551. this.userIds = res.data.id;
  552. this.tenantId = res.data.tenantId;
  553. this.userType = res.data.userType;
  554. } else {
  555. this.$message.error(res.data);
  556. }
  557. });
  558. },
  559. async getProcessNodeList() {
  560. await processStructure({
  561. processId: this.processId,
  562. workOrderId: this.workOrderId,
  563. userId: this.userIds,
  564. }).then((response) => {
  565. let tempData = response.data.tpls;
  566. // 获取对应模板中,下拉框的key, value
  567. let selectList = this.getSelectValueObject(tempData);
  568. // 获取对应模板中,需要隐藏的字段
  569. let hiddenFormList = this.getSelectValueObject(
  570. tempData,
  571. "hiddenForm",
  572. selectList
  573. );
  574. tempData.forEach((temp, index) => {
  575. let tempList = temp.form_structure.list || [];
  576. tempList.forEach((item) => {
  577. if (hiddenFormList[index].length > 0) {
  578. if (item.type != "text" && !item.options.relationStatus) {
  579. item.hidden = true;
  580. } else {
  581. item.hidden = false;
  582. }
  583. // item.hidden = false
  584. if (hiddenFormList[index].includes(item.model)) {
  585. item.hidden = false;
  586. }
  587. } else {
  588. item.hidden = false;
  589. }
  590. // 子表单
  591. if (item.type == "subform") {
  592. let childList = item.columns || [];
  593. let subFormStatus = true;
  594. childList.forEach((child) => {
  595. let childList = child.list || [];
  596. childList.forEach((c) => {
  597. if (hiddenFormList[index].length > 0) {
  598. if (c.type != "text" && !c.options.relationStatus) {
  599. c.hidden = true;
  600. } else {
  601. c.hidden = false;
  602. subFormStatus = false;
  603. }
  604. if (hiddenFormList[index].includes(c.model)) {
  605. c.hidden = false;
  606. subFormStatus = false;
  607. }
  608. } else {
  609. c.hidden = false;
  610. subFormStatus = false;
  611. }
  612. });
  613. });
  614. item.hidden = subFormStatus;
  615. }
  616. });
  617. });
  618. this.isActiveProcessing = false;
  619. this.processStructureValue = response.data;
  620. this.is_end = this.processStructureValue.workOrder.is_end;
  621. this.circulationHistoryList =
  622. this.processStructureValue.circulationHistory;
  623. this.circulationList = JSON.parse(
  624. JSON.stringify(this.circulationHistoryList)
  625. );
  626. this.circulationHistoryList.forEach((item) => {
  627. const file = item.file_url ? JSON.parse(item.file_url) : [];
  628. const tempFile = {
  629. image: [],
  630. file: [],
  631. };
  632. // console.log(file)
  633. file.forEach((item) => {
  634. if (item.type == "image") {
  635. tempFile.image.push(item.url);
  636. } else if (item.type == "file") {
  637. tempFile.file.push(item);
  638. }
  639. });
  640. item.fileUrl = tempFile;
  641. });
  642. this.circulationList.forEach((item) => {
  643. const file = item.file_url ? JSON.parse(item.file_url) : [];
  644. const tempFile = {
  645. image: [],
  646. file: [],
  647. };
  648. // console.log(file)
  649. file.forEach((item) => {
  650. if (item.type == "image") {
  651. tempFile.image.push(item.url);
  652. } else if (item.type == "file") {
  653. tempFile.file.push(item);
  654. }
  655. });
  656. item.fileUrl = tempFile;
  657. });
  658. // console.log(this.circulationHistoryList, "circulationHistoryList");
  659. // 获取当前展示节点列表
  660. // this.nodeStepList = this.processStructureValue.circulationHistory
  661. // 获取当前展示节点列表
  662. this.nodeStepList = [];
  663. let nodes = this.processStructureValue.nodes;
  664. this.principals = "处理中";
  665. for (var i = 0; i < nodes.length; i++) {
  666. // console.log(
  667. // nodes[i].id,
  668. // this.processStructureValue.workOrder.current_state,
  669. // "xji"
  670. // );
  671. if (
  672. nodes[i].id === this.processStructureValue.workOrder.current_state
  673. ) {
  674. // 当前节点
  675. this.nodeStepList.push(nodes[i]);
  676. this.activeIndex = this.nodeStepList.length - 1;
  677. if (i + 1 === nodes.length) {
  678. this.activeIndex = this.nodeStepList.length;
  679. }
  680. this.currentNode = nodes[i];
  681. // 处理是认谁在处理,已处理完成则显示处理中
  682. const assignUsers = nodes[i].assignUsers;
  683. if (assignUsers && assignUsers.length > 0) {
  684. this.principals = assignUsers[0].username + "处理中";
  685. }
  686. } else if (!nodes[i].isHideNode) {
  687. // 非隐藏节点
  688. this.nodeStepList.push(nodes[i]);
  689. }
  690. // 判断节点里面是否有结束节点,而且一个流程里面只能有一个结束结点,
  691. if (nodes[i].clazz == "end") {
  692. this.endNodeDetail = JSON.parse(JSON.stringify(nodes[i]));
  693. this.endNodeDetail.target = nodes[i].id;
  694. this.endNodeDetail.flowProperties = 0; // 拒绝属性
  695. this.endNodeDetail.label = "拒绝";
  696. }
  697. }
  698. this.circulationList.reverse();
  699. // 如果审批流程没有结束则,流程和历史记录合并显示;结束了,就只显示历史记录
  700. if (!this.processStructureValue.workOrder.is_end) {
  701. this.circulationList.forEach((cir) => {
  702. this.nodeStepList.forEach((node) => {
  703. if (cir.source == node.id) {
  704. cir.label = node.label;
  705. cir.assignType = node.assignType;
  706. cir.assignValue = node.assignValue;
  707. cir.assignUsers = node.assignUsers;
  708. cir.id = node.id;
  709. }
  710. });
  711. });
  712. let tempNodes = [];
  713. this.nodeStepList.forEach((node) => {
  714. let count = 0;
  715. this.circulationList.forEach((cir) => {
  716. if (node.id === cir.source) {
  717. count += 1;
  718. }
  719. });
  720. if (count <= 0) {
  721. tempNodes.push(node);
  722. }
  723. });
  724. this.circulationList.push(...tempNodes);
  725. this.circulationList.forEach((cir, index) => {
  726. if (cir.id == this.processStructureValue.workOrder.current_state) {
  727. this.activeIndex = index;
  728. if (index + 1 == this.circulationList.length) {
  729. this.activeIndex = this.circulationList.length;
  730. }
  731. }
  732. });
  733. } else {
  734. this.activeIndex = this.circulationList.length;
  735. }
  736. // 添加抄送状态
  737. this.circulationList.forEach((res) => {
  738. res.ccStatus = true;
  739. });
  740. // console.log(this.nodeStepList);
  741. // console.log(this.circulationList, "this.circulationList");
  742. // if(this.processStructureValue.nodes) {
  743. // for (var i = 0; i < this.processStructureValue.nodes.length; i++) {
  744. // if (this.processStructureValue.nodes[i].id === this.processStructureValue.workOrder.current_state) {
  745. // // 当前节点
  746. // this.nodeStepList.push(this.processStructureValue.nodes[i])
  747. // this.activeIndex = this.nodeStepList.length - 1
  748. // if (i + 1 === this.processStructureValue.nodes.length) {
  749. // this.activeIndex = this.nodeStepList.length
  750. // }
  751. // this.currentNode = this.processStructureValue.nodes[i]
  752. // } else if (!this.processStructureValue.nodes[i].isHideNode) {
  753. // // 非隐藏节点
  754. // this.nodeStepList.push(this.processStructureValue.nodes[i])
  755. // }
  756. // }
  757. // }
  758. // 如果回退到初始节点则可编辑。
  759. if (this.activeIndex === 0 && this.currentNode.clazz === "start") {
  760. this.currentNode.writeTpls = [];
  761. for (var tplTmp of this.processStructureValue.tpls) {
  762. this.currentNode.writeTpls.push(tplTmp.form_structure.id);
  763. }
  764. }
  765. // 判断是否需要主动处理
  766. for (var stateValue of this.processStructureValue.workOrder.state) {
  767. if (
  768. this.processStructureValue.workOrder.current_state ===
  769. stateValue.id &&
  770. stateValue.processor.length > 1
  771. ) {
  772. this.isActiveProcessing = true;
  773. break;
  774. }
  775. }
  776. // const nodes = this.processStructureValue.nodes;
  777. // for (var i = 0; i < nodes.length; i++) {
  778. // // 判断节点里面是否有结束节点,而且一个流程里面只能有一个结束结点,
  779. // if (nodes[i].clazz == "end") {
  780. // this.endNodeDetail = JSON.parse(JSON.stringify(nodes[i]));
  781. // this.endNodeDetail.target = nodes[i].id;
  782. // this.endNodeDetail.flowProperties = 0; // 拒绝属性
  783. // this.endNodeDetail.label = "拒绝";
  784. // }
  785. // }
  786. let psv = response.data.edges || [];
  787. let btn_group = [];
  788. psv.forEach((item) => {
  789. // 过滤其它类型的操作
  790. if (
  791. this.processStructureValue.workOrder.is_end === 0 &&
  792. item.source === this.currentNode.id &&
  793. item.flowProperties == 1
  794. ) {
  795. if (item.flowProperties == 1) {
  796. item.className = "primary";
  797. item.labelShow = "同意";
  798. } else if (item.flowProperties == 0) {
  799. item.className = "danger";
  800. } else if (item.flowProperties == 2) {
  801. item.className = "primary";
  802. }
  803. btn_group.push(item);
  804. } else {
  805. item.className = "primary";
  806. }
  807. });
  808. this.btn_group = btn_group;
  809. this.isLoadingStatus = false;
  810. // console.log(this.circulationList, "circulationList");
  811. // console.log(this.currentNode, "currentNode ");
  812. this.getAlertMessage();
  813. });
  814. },
  815. getSelectValueObject(tpls, type = "value", tplValues = []) {
  816. const tempData = tpls || [];
  817. let selectList = [];
  818. tempData.forEach((temp, index) => {
  819. let tempList = temp.form_structure.list || [];
  820. let tempSelectList = tplValues[index] || [];
  821. let listArray = [];
  822. tempList.forEach((list) => {
  823. if (list.type == "select") {
  824. if (type == "value") {
  825. const result = this.getFormDataDetail(temp.form_data, list.model);
  826. if (result.status) {
  827. listArray.push(result);
  828. }
  829. } else {
  830. let selectOptions = [];
  831. let selectValue = [];
  832. tempSelectList.forEach((tsl) => {
  833. if (tsl.model == list.model) {
  834. selectOptions = list.options.options || [];
  835. selectValue = tsl.value || [];
  836. }
  837. });
  838. selectOptions.forEach((so) => {
  839. if (selectValue.includes(so.value)) {
  840. let tempRo = so.relationOptions || [];
  841. listArray.push(...tempRo);
  842. }
  843. });
  844. }
  845. }
  846. if (list.type == "subform") {
  847. let childList = list.columns || [];
  848. childList.forEach((child) => {
  849. let childList = child.list || [];
  850. childList.forEach((c) => {
  851. if (c.type == "select") {
  852. if (type == "value") {
  853. const originObj = JSON.parse(JSON.stringify(c));
  854. const result = this.getFormDataDetail(
  855. temp.form_data,
  856. originObj.model
  857. );
  858. if (result.status) {
  859. listArray.push(result);
  860. }
  861. } else {
  862. let selectOptions = [];
  863. let selectValue = [];
  864. tempSelectList.forEach((tsl) => {
  865. if (tsl.model == c.model) {
  866. selectOptions = c.options.options || [];
  867. selectValue = tsl.value || [];
  868. }
  869. });
  870. selectOptions.forEach((so) => {
  871. if (selectValue.includes(so.value)) {
  872. let tempRo = so.relationOptions || [];
  873. listArray.push(...tempRo);
  874. }
  875. });
  876. }
  877. }
  878. });
  879. });
  880. }
  881. });
  882. selectList.push(listArray);
  883. });
  884. return selectList;
  885. },
  886. // 获取对应元素的值
  887. getFormDataDetail(formData, model) {
  888. let modelStatus = {
  889. status: false,
  890. value: null,
  891. };
  892. for (let data in formData) {
  893. if (typeof formData[data] == "object") {
  894. // 没有子表单里面有子表单
  895. for (let child in formData[data]) {
  896. if (child == model) {
  897. modelStatus = {
  898. status: true,
  899. model: child,
  900. value: formData[data][child]
  901. ? formData[data][child].split(",")
  902. : [],
  903. };
  904. }
  905. }
  906. } else {
  907. if (data == model) {
  908. modelStatus = {
  909. status: true,
  910. model: data,
  911. value: formData[data] ? formData[data].split(",") : [],
  912. };
  913. }
  914. }
  915. }
  916. return modelStatus;
  917. },
  918. submitAction(item) {
  919. var promiseList = [];
  920. this.tpls = [];
  921. for (var tpl of this.processStructureValue.tpls) {
  922. this.tpls.push({
  923. tplDataId: tpl.id,
  924. tplId: tpl.form_structure.id,
  925. });
  926. promiseList.push(this.$refs["generateForm-" + tpl.id][0].getData());
  927. }
  928. console.log({
  929. tasks: this.processStructureValue.process.task,
  930. source_state: this.processStructureValue.workOrder.current_state,
  931. target_state: item.target,
  932. circulation: item.label,
  933. flow_properties:
  934. item.flowProperties === undefined ? 2 : parseInt(item.flowProperties),
  935. work_order_id: parseInt(this.$route.query.workOrderId),
  936. remarks: this.dataList.remarks,
  937. fileUrl: JSON.stringify(this.fileUrl || []),
  938. tpls: this.tpls,
  939. });
  940. const flow =
  941. item.flowProperties === undefined ? 2 : parseInt(item.flowProperties);
  942. let str = "同意";
  943. if (flow == 1) {
  944. str = "同意";
  945. this.submitTitle = "确认同意";
  946. this.submitType = "argee";
  947. } else if (flow == 0) {
  948. str = "拒绝";
  949. this.submitTitle = "确认拒绝";
  950. this.submitType = "reject";
  951. } else {
  952. str = "操作";
  953. this.submitTitle = "操作";
  954. this.submitType = "operation";
  955. }
  956. const tips = `您是否${str}此审批?`;
  957. // this.$confirm(tips, "提示", {
  958. // confirmButtonText: "确定",
  959. // cancelButtonText: "取消",
  960. // type: "warning"
  961. // }).then(() => {
  962. Promise.all(promiseList).then((values) => {
  963. for (var tplDataIndex in this.tpls) {
  964. this.tpls[tplDataIndex].tplValue = values[tplDataIndex];
  965. }
  966. let fileList = [];
  967. this.tpls &&
  968. this.tpls.forEach((tpl) => {
  969. for (let val in tpl.tplValue) {
  970. if (val.indexOf("file") != -1) {
  971. const file = tpl.tplValue[val] || [];
  972. file.forEach((item) => {
  973. fileList.push(item.url);
  974. });
  975. }
  976. }
  977. });
  978. this.submitItem = {
  979. tasks: this.processStructureValue.process.task,
  980. source_state: this.processStructureValue.workOrder.current_state,
  981. target_state: item.target,
  982. circulation: item.label,
  983. flow_properties:
  984. item.flowProperties === undefined
  985. ? 2
  986. : parseInt(item.flowProperties),
  987. work_order_id: parseInt(this.$route.query.workOrderId),
  988. tpls: this.tpls,
  989. fileList,
  990. tips,
  991. };
  992. this.dialogSubmit = true;
  993. });
  994. // });
  995. },
  996. onCCChange(item) {
  997. item.ccStatus = !item.ccStatus;
  998. this.$forceUpdate();
  999. },
  1000. // 获取提示消息
  1001. getAlertMessage() {
  1002. if (this.processStructureValue.workOrder.is_end === 1) {
  1003. this.alertMessage = "当前工单已结束。";
  1004. }
  1005. },
  1006. // activeOrderActive() {
  1007. // var jsonData = [{
  1008. // id: this.nodeStepList[this.activeIndex].id,
  1009. // label: this.nodeStepList[this.activeIndex].label,
  1010. // process_method: 'person',
  1011. // processor: [this.userId]
  1012. // }]
  1013. // activeOrder(jsonData, this.$route.query.workOrderId).then(() => {
  1014. // this.getProcessNodeList()
  1015. // })
  1016. // },
  1017. async getAllOrgan() {
  1018. // 获取分部
  1019. console.log(this.tenantId, "tenantId");
  1020. // if (this.userType.indexOf("SYSTEM") != -1) {
  1021. queryAllToOrgan({ tenantId: this.tenantId }).then((res) => {
  1022. if (res.code == 200) {
  1023. const result = res.data;
  1024. const processId = this.$route.query.processId;
  1025. let filterOrganId = [];
  1026. if ([40, 41, 45, 46, 47].includes(processId)) {
  1027. filterOrganId = [4];
  1028. } else {
  1029. filterOrganId = [
  1030. 1, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
  1031. 22, 23, 25, 26, 27, 28, 34, 37, 40, 71, 72, 123, 124, 125, 128, 134,
  1032. 148, 147, 127, 139, 151, 36, 149, 152, 153, 158
  1033. ];
  1034. }
  1035. let tempOrgan = [];
  1036. // 过滤不会显示的分部
  1037. result.forEach((item) => {
  1038. if (filterOrganId.includes(item.id)) {
  1039. tempOrgan.push(item);
  1040. }
  1041. });
  1042. this.organList = tempOrgan;
  1043. }
  1044. });
  1045. // } else {
  1046. // queryTeacherOrgan({ tenantId: this.tenantId }).then((res) => {
  1047. // if (res.code == 200) {
  1048. // const result = res.data;
  1049. // const filterOrganId = [
  1050. // 36, 39, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 52, 54, 55, 56,
  1051. // ];
  1052. // let tempOrgan = [];
  1053. // // 过滤不会显示的分部
  1054. // result.forEach((item) => {
  1055. // if (!filterOrganId.includes(item.key)) {
  1056. // tempOrgan.push({
  1057. // id: item.key,
  1058. // name: item.value,
  1059. // });
  1060. // }
  1061. // });
  1062. // this.organList = tempOrgan;
  1063. // }
  1064. // });
  1065. // }
  1066. },
  1067. dataModelFormatBr(str) {
  1068. return str ? str.replace(/\n/g, "<br />") : str;
  1069. },
  1070. formatIcon(item, index, type) {
  1071. // 格式化ICON
  1072. // console.log(item, index)
  1073. // console.log(this.activeIndex)
  1074. if (this.activeIndex >= index) {
  1075. if (item.circulation == "转交") {
  1076. return "icon-transfer";
  1077. } else if (this.activeIndex == index) {
  1078. return "icon-wait";
  1079. } else if (item.status == 0) {
  1080. return "el-icon-error";
  1081. } else {
  1082. return "el-icon-success";
  1083. }
  1084. }
  1085. // #fd803a
  1086. return "";
  1087. },
  1088. },
  1089. };
  1090. </script>
  1091. <style lang="scss" scoped>
  1092. :deep(.el-step__title) {
  1093. font-size: 13px;
  1094. line-height: 1.3;
  1095. width: 100%;
  1096. padding-top: 10px;
  1097. padding-right: 10px;
  1098. }
  1099. .step-title {
  1100. color: #000;
  1101. font-size: 16px;
  1102. }
  1103. .apply-time {
  1104. font-size: #999;
  1105. color: #999;
  1106. padding-left: 10px;
  1107. }
  1108. .apply-status {
  1109. line-height: 1.5;
  1110. color: #999;
  1111. margin: 5px 0;
  1112. }
  1113. .remarks {
  1114. background: #f5f5f5;
  1115. padding: 8px;
  1116. color: #323233;
  1117. border-radius: 6px;
  1118. line-height: 1.5;
  1119. }
  1120. .imgUploader {
  1121. background: #f5f5f5;
  1122. margin-top: 8px;
  1123. padding: 8px;
  1124. border-radius: 6px;
  1125. .el-image {
  1126. vertical-align: middle;
  1127. }
  1128. }
  1129. .fileUploader {
  1130. display: flex;
  1131. align-items: center;
  1132. margin-top: 8px;
  1133. background: #f5f5f5;
  1134. padding: 6px;
  1135. border-radius: 4px;
  1136. }
  1137. :deep(.icon-transfer),
  1138. :deep(.icon-wait) {
  1139. display: flex;
  1140. align-items: center;
  1141. box-sizing: content-box;
  1142. background-color: #fff;
  1143. padding: 2px 0;
  1144. height: 23px;
  1145. &::before {
  1146. content: " ";
  1147. display: inline-block;
  1148. width: 23px;
  1149. height: 23px;
  1150. background: url("../../../assets/system-transfer.png") no-repeat center;
  1151. background-size: contain;
  1152. }
  1153. }
  1154. :deep(.icon-wait) {
  1155. &::before {
  1156. content: " ";
  1157. display: inline-block;
  1158. width: 23px;
  1159. height: 23px;
  1160. background: url("../../../assets/system-wait.png") no-repeat center;
  1161. background-size: contain;
  1162. }
  1163. }
  1164. .large-icon {
  1165. :deep(.el-timeline-item__node--large) {
  1166. top: -8px;
  1167. left: -7px;
  1168. width: 24px;
  1169. height: 24px;
  1170. background-color: transparent;
  1171. }
  1172. :deep(.el-icon-success),
  1173. :deep(.el-icon-error) {
  1174. font-size: 24px;
  1175. color: #22b4a9;
  1176. background-color: #fff;
  1177. padding: 2px 0;
  1178. }
  1179. :deep(.el-icon-error) {
  1180. color: #ff2e2e;
  1181. }
  1182. }
  1183. </style>