handle.vue 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227
  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" v-if="is_end == 0"
  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.href;
  478. let returnUrl = "";
  479. if (/dev/.test(url)) {
  480. // dev 环境
  481. returnUrl = "http://mandev.dayaedu.com";
  482. } else if (/test/.test(url)) {
  483. // dev 环境
  484. returnUrl = "http://mantest.dayaedu.com";
  485. } else if (/online/.test(url)) {
  486. //线上
  487. returnUrl = "https://manonline.dayaedu.com";
  488. } else {
  489. // 默认dev环境
  490. returnUrl = "http://mandev.dayaedu.com";
  491. }
  492. return returnUrl;
  493. },
  494. isCheckImage(file) {
  495. const urlArr = file.split(".");
  496. const suffix = urlArr[urlArr.length - 1];
  497. const imgSuffix = ["png", "jpg", "jpeg", "gif", "ico"];
  498. console.log(imgSuffix.includes(suffix), "11");
  499. return imgSuffix.includes(suffix);
  500. },
  501. checkFileSuffix(url) {
  502. let urlArr = url.split(".");
  503. let suffix = urlArr[urlArr.length - 1];
  504. const passSuffix = [
  505. "xlsx",
  506. "xls",
  507. "pdf",
  508. "png",
  509. "jpg",
  510. "jpeg",
  511. "gif",
  512. "ico",
  513. ];
  514. if (passSuffix.includes(suffix)) {
  515. return true;
  516. } else {
  517. return false;
  518. }
  519. },
  520. async handleCommit() {
  521. console.log("handleCommit", true);
  522. this.submitTitle = "添加评论";
  523. this.submitType = "commit";
  524. this.submitItem = {
  525. workOrderId: parseInt(this.workOrderId),
  526. };
  527. this.dialogSubmit = true;
  528. },
  529. async handleInversion() {
  530. let workOrder = this.processStructureValue.workOrder;
  531. this.selectItem.work_order_id = workOrder.id;
  532. this.selectItem.nodeList = workOrder.state || [];
  533. this.selectItem.nodeList.forEach((item) => {
  534. item.text = item.label;
  535. });
  536. if (this.selectItem.nodeList.length === 1) {
  537. this.selectItem.node_id = this.selectItem.nodeList[0].id;
  538. }
  539. if (this.selectItem.users.length <= 0) {
  540. load.startLoading();
  541. await listUser({
  542. pageSize: 999999,
  543. }).then((response) => {
  544. this.selectItem.users = response.data.list;
  545. });
  546. load.endLoading();
  547. }
  548. this.dialogVisible = true;
  549. },
  550. async getUserInfo() {
  551. await queryUserInfo().then((res) => {
  552. // console.log(res);
  553. if (res.code == 200) {
  554. this.userIds = res.data.id;
  555. this.tenantId = res.data.tenantId;
  556. this.userType = res.data.userType;
  557. } else {
  558. this.$message.error(res.data);
  559. }
  560. });
  561. },
  562. async getProcessNodeList() {
  563. await processStructure({
  564. processId: this.processId,
  565. workOrderId: this.workOrderId,
  566. userId: this.userIds,
  567. }).then((response) => {
  568. let tempData = response.data.tpls;
  569. // 获取对应模板中,下拉框的key, value
  570. let selectList = this.getSelectValueObject(tempData);
  571. // 获取对应模板中,需要隐藏的字段
  572. let hiddenFormList = this.getSelectValueObject(
  573. tempData,
  574. "hiddenForm",
  575. selectList
  576. );
  577. tempData.forEach((temp, index) => {
  578. let tempList = temp.form_structure.list || [];
  579. tempList.forEach((item) => {
  580. if (hiddenFormList[index].length > 0) {
  581. if (item.type != "text" && !item.options.relationStatus) {
  582. item.hidden = true;
  583. } else {
  584. item.hidden = false;
  585. }
  586. // item.hidden = false
  587. if (hiddenFormList[index].includes(item.model)) {
  588. item.hidden = false;
  589. }
  590. } else {
  591. item.hidden = false;
  592. }
  593. // 子表单
  594. if (item.type == "subform") {
  595. let childList = item.columns || [];
  596. let subFormStatus = true;
  597. childList.forEach((child) => {
  598. let childList = child.list || [];
  599. childList.forEach((c) => {
  600. if (hiddenFormList[index].length > 0) {
  601. if (c.type != "text" && !c.options.relationStatus) {
  602. c.hidden = true;
  603. } else {
  604. c.hidden = false;
  605. subFormStatus = false;
  606. }
  607. if (hiddenFormList[index].includes(c.model)) {
  608. c.hidden = false;
  609. subFormStatus = false;
  610. }
  611. } else {
  612. c.hidden = false;
  613. subFormStatus = false;
  614. }
  615. });
  616. });
  617. item.hidden = subFormStatus;
  618. }
  619. });
  620. });
  621. this.isActiveProcessing = false;
  622. this.processStructureValue = response.data;
  623. this.is_end = this.processStructureValue.workOrder.is_end;
  624. this.circulationHistoryList =
  625. this.processStructureValue.circulationHistory;
  626. this.circulationList = JSON.parse(
  627. JSON.stringify(this.circulationHistoryList)
  628. );
  629. this.circulationHistoryList.forEach((item) => {
  630. const file = item.file_url ? JSON.parse(item.file_url) : [];
  631. const tempFile = {
  632. image: [],
  633. file: [],
  634. };
  635. // console.log(file)
  636. file.forEach((item) => {
  637. if (item.type == "image") {
  638. tempFile.image.push(item.url);
  639. } else if (item.type == "file") {
  640. tempFile.file.push(item);
  641. }
  642. });
  643. item.fileUrl = tempFile;
  644. });
  645. this.circulationList.forEach((item) => {
  646. const file = item.file_url ? JSON.parse(item.file_url) : [];
  647. const tempFile = {
  648. image: [],
  649. file: [],
  650. };
  651. // console.log(file)
  652. file.forEach((item) => {
  653. if (item.type == "image") {
  654. tempFile.image.push(item.url);
  655. } else if (item.type == "file") {
  656. tempFile.file.push(item);
  657. }
  658. });
  659. item.fileUrl = tempFile;
  660. });
  661. // console.log(this.circulationHistoryList, "circulationHistoryList");
  662. // 获取当前展示节点列表
  663. // this.nodeStepList = this.processStructureValue.circulationHistory
  664. // 获取当前展示节点列表
  665. this.nodeStepList = [];
  666. let nodes = this.processStructureValue.nodes;
  667. this.principals = "处理中";
  668. for (var i = 0; i < nodes.length; i++) {
  669. // console.log(
  670. // nodes[i].id,
  671. // this.processStructureValue.workOrder.current_state,
  672. // "xji"
  673. // );
  674. if (
  675. nodes[i].id === this.processStructureValue.workOrder.current_state
  676. ) {
  677. // 当前节点
  678. this.nodeStepList.push(nodes[i]);
  679. this.activeIndex = this.nodeStepList.length - 1;
  680. if (i + 1 === nodes.length) {
  681. this.activeIndex = this.nodeStepList.length;
  682. }
  683. this.currentNode = nodes[i];
  684. // 处理是认谁在处理,已处理完成则显示处理中
  685. const assignUsers = nodes[i].assignUsers;
  686. if (assignUsers && assignUsers.length > 0) {
  687. this.principals = assignUsers[0].username + "处理中";
  688. }
  689. } else if (!nodes[i].isHideNode) {
  690. // 非隐藏节点
  691. this.nodeStepList.push(nodes[i]);
  692. }
  693. // 判断节点里面是否有结束节点,而且一个流程里面只能有一个结束结点,
  694. if (nodes[i].clazz == "end") {
  695. this.endNodeDetail = JSON.parse(JSON.stringify(nodes[i]));
  696. this.endNodeDetail.target = nodes[i].id;
  697. this.endNodeDetail.flowProperties = 0; // 拒绝属性
  698. this.endNodeDetail.label = "拒绝";
  699. }
  700. }
  701. this.circulationList.reverse();
  702. // 如果审批流程没有结束则,流程和历史记录合并显示;结束了,就只显示历史记录
  703. if (!this.processStructureValue.workOrder.is_end) {
  704. this.circulationList.forEach((cir) => {
  705. this.nodeStepList.forEach((node) => {
  706. if (cir.source == node.id) {
  707. cir.label = node.label;
  708. cir.assignType = node.assignType;
  709. cir.assignValue = node.assignValue;
  710. cir.assignUsers = node.assignUsers;
  711. cir.id = node.id;
  712. }
  713. });
  714. });
  715. let tempNodes = [];
  716. this.nodeStepList.forEach((node) => {
  717. let count = 0;
  718. this.circulationList.forEach((cir) => {
  719. if (node.id === cir.source) {
  720. count += 1;
  721. }
  722. });
  723. if (count <= 0) {
  724. tempNodes.push(node);
  725. }
  726. });
  727. this.circulationList.push(...tempNodes);
  728. this.circulationList.forEach((cir, index) => {
  729. if (cir.id == this.processStructureValue.workOrder.current_state) {
  730. this.activeIndex = index;
  731. if (index + 1 == this.circulationList.length) {
  732. this.activeIndex = this.circulationList.length;
  733. }
  734. }
  735. });
  736. } else {
  737. this.activeIndex = this.circulationList.length;
  738. }
  739. // 添加抄送状态
  740. this.circulationList.forEach((res) => {
  741. res.ccStatus = true;
  742. });
  743. // console.log(this.nodeStepList);
  744. // console.log(this.circulationList, "this.circulationList");
  745. // if(this.processStructureValue.nodes) {
  746. // for (var i = 0; i < this.processStructureValue.nodes.length; i++) {
  747. // if (this.processStructureValue.nodes[i].id === this.processStructureValue.workOrder.current_state) {
  748. // // 当前节点
  749. // this.nodeStepList.push(this.processStructureValue.nodes[i])
  750. // this.activeIndex = this.nodeStepList.length - 1
  751. // if (i + 1 === this.processStructureValue.nodes.length) {
  752. // this.activeIndex = this.nodeStepList.length
  753. // }
  754. // this.currentNode = this.processStructureValue.nodes[i]
  755. // } else if (!this.processStructureValue.nodes[i].isHideNode) {
  756. // // 非隐藏节点
  757. // this.nodeStepList.push(this.processStructureValue.nodes[i])
  758. // }
  759. // }
  760. // }
  761. // 如果回退到初始节点则可编辑。
  762. if (this.activeIndex === 0 && this.currentNode.clazz === "start") {
  763. this.currentNode.writeTpls = [];
  764. for (var tplTmp of this.processStructureValue.tpls) {
  765. this.currentNode.writeTpls.push(tplTmp.form_structure.id);
  766. }
  767. }
  768. // 判断是否需要主动处理
  769. for (var stateValue of this.processStructureValue.workOrder.state) {
  770. if (
  771. this.processStructureValue.workOrder.current_state ===
  772. stateValue.id &&
  773. stateValue.processor.length > 1
  774. ) {
  775. this.isActiveProcessing = true;
  776. break;
  777. }
  778. }
  779. // const nodes = this.processStructureValue.nodes;
  780. // for (var i = 0; i < nodes.length; i++) {
  781. // // 判断节点里面是否有结束节点,而且一个流程里面只能有一个结束结点,
  782. // if (nodes[i].clazz == "end") {
  783. // this.endNodeDetail = JSON.parse(JSON.stringify(nodes[i]));
  784. // this.endNodeDetail.target = nodes[i].id;
  785. // this.endNodeDetail.flowProperties = 0; // 拒绝属性
  786. // this.endNodeDetail.label = "拒绝";
  787. // }
  788. // }
  789. let psv = response.data.edges || [];
  790. let btn_group = [];
  791. psv.forEach((item) => {
  792. // 过滤其它类型的操作
  793. if (
  794. this.processStructureValue.workOrder.is_end === 0 &&
  795. item.source === this.currentNode.id &&
  796. item.flowProperties == 1
  797. ) {
  798. if (item.flowProperties == 1) {
  799. item.className = "primary";
  800. item.labelShow = "同意";
  801. } else if (item.flowProperties == 0) {
  802. item.className = "danger";
  803. } else if (item.flowProperties == 2) {
  804. item.className = "primary";
  805. }
  806. btn_group.push(item);
  807. } else {
  808. item.className = "primary";
  809. }
  810. });
  811. this.btn_group = btn_group;
  812. this.isLoadingStatus = false;
  813. // console.log(this.circulationList, "circulationList");
  814. // console.log(this.currentNode, "currentNode ");
  815. this.getAlertMessage();
  816. });
  817. },
  818. getSelectValueObject(tpls, type = "value", tplValues = []) {
  819. const tempData = tpls || [];
  820. let selectList = [];
  821. tempData.forEach((temp, index) => {
  822. let tempList = temp.form_structure.list || [];
  823. let tempSelectList = tplValues[index] || [];
  824. let listArray = [];
  825. tempList.forEach((list) => {
  826. if (list.type == "select") {
  827. if (type == "value") {
  828. const result = this.getFormDataDetail(temp.form_data, list.model);
  829. if (result.status) {
  830. listArray.push(result);
  831. }
  832. } else {
  833. let selectOptions = [];
  834. let selectValue = [];
  835. tempSelectList.forEach((tsl) => {
  836. if (tsl.model == list.model) {
  837. selectOptions = list.options.options || [];
  838. selectValue = tsl.value || [];
  839. }
  840. });
  841. selectOptions.forEach((so) => {
  842. if (selectValue.includes(so.value)) {
  843. let tempRo = so.relationOptions || [];
  844. listArray.push(...tempRo);
  845. }
  846. });
  847. }
  848. }
  849. if (list.type == "subform") {
  850. let childList = list.columns || [];
  851. childList.forEach((child) => {
  852. let childList = child.list || [];
  853. childList.forEach((c) => {
  854. if (c.type == "select") {
  855. if (type == "value") {
  856. const originObj = JSON.parse(JSON.stringify(c));
  857. const result = this.getFormDataDetail(
  858. temp.form_data,
  859. originObj.model
  860. );
  861. if (result.status) {
  862. listArray.push(result);
  863. }
  864. } else {
  865. let selectOptions = [];
  866. let selectValue = [];
  867. tempSelectList.forEach((tsl) => {
  868. if (tsl.model == c.model) {
  869. selectOptions = c.options.options || [];
  870. selectValue = tsl.value || [];
  871. }
  872. });
  873. selectOptions.forEach((so) => {
  874. if (selectValue.includes(so.value)) {
  875. let tempRo = so.relationOptions || [];
  876. listArray.push(...tempRo);
  877. }
  878. });
  879. }
  880. }
  881. });
  882. });
  883. }
  884. });
  885. selectList.push(listArray);
  886. });
  887. return selectList;
  888. },
  889. // 获取对应元素的值
  890. getFormDataDetail(formData, model) {
  891. let modelStatus = {
  892. status: false,
  893. value: null,
  894. };
  895. for (let data in formData) {
  896. if (typeof formData[data] == "object") {
  897. // 没有子表单里面有子表单
  898. for (let child in formData[data]) {
  899. if (child == model) {
  900. modelStatus = {
  901. status: true,
  902. model: child,
  903. value: formData[data][child]
  904. ? formData[data][child].split(",")
  905. : [],
  906. };
  907. }
  908. }
  909. } else {
  910. if (data == model) {
  911. modelStatus = {
  912. status: true,
  913. model: data,
  914. value: formData[data] ? formData[data].split(",") : [],
  915. };
  916. }
  917. }
  918. }
  919. return modelStatus;
  920. },
  921. submitAction(item) {
  922. var promiseList = [];
  923. this.tpls = [];
  924. for (var tpl of this.processStructureValue.tpls) {
  925. this.tpls.push({
  926. tplDataId: tpl.id,
  927. tplId: tpl.form_structure.id,
  928. });
  929. promiseList.push(this.$refs["generateForm-" + tpl.id][0].getData());
  930. }
  931. console.log({
  932. tasks: this.processStructureValue.process.task,
  933. source_state: this.processStructureValue.workOrder.current_state,
  934. target_state: item.target,
  935. circulation: item.label,
  936. flow_properties:
  937. item.flowProperties === undefined ? 2 : parseInt(item.flowProperties),
  938. work_order_id: parseInt(this.$route.query.workOrderId),
  939. remarks: this.dataList.remarks,
  940. fileUrl: JSON.stringify(this.fileUrl || []),
  941. tpls: this.tpls,
  942. });
  943. const flow =
  944. item.flowProperties === undefined ? 2 : parseInt(item.flowProperties);
  945. let str = "同意";
  946. if (flow == 1) {
  947. str = "同意";
  948. this.submitTitle = "确认同意";
  949. this.submitType = "argee";
  950. } else if (flow == 0) {
  951. str = "拒绝";
  952. this.submitTitle = "确认拒绝";
  953. this.submitType = "reject";
  954. } else {
  955. str = "操作";
  956. this.submitTitle = "操作";
  957. this.submitType = "operation";
  958. }
  959. const tips = `您是否${str}此审批?`;
  960. // this.$confirm(tips, "提示", {
  961. // confirmButtonText: "确定",
  962. // cancelButtonText: "取消",
  963. // type: "warning"
  964. // }).then(() => {
  965. Promise.all(promiseList).then((values) => {
  966. for (var tplDataIndex in this.tpls) {
  967. this.tpls[tplDataIndex].tplValue = values[tplDataIndex];
  968. }
  969. let fileList = [];
  970. this.tpls &&
  971. this.tpls.forEach((tpl) => {
  972. for (let val in tpl.tplValue) {
  973. if (val.indexOf("file") != -1) {
  974. const file = tpl.tplValue[val] || [];
  975. file.forEach((item) => {
  976. fileList.push(item.url);
  977. });
  978. }
  979. }
  980. });
  981. this.submitItem = {
  982. tasks: this.processStructureValue.process.task,
  983. source_state: this.processStructureValue.workOrder.current_state,
  984. target_state: item.target,
  985. circulation: item.label,
  986. flow_properties:
  987. item.flowProperties === undefined
  988. ? 2
  989. : parseInt(item.flowProperties),
  990. work_order_id: parseInt(this.$route.query.workOrderId),
  991. tpls: this.tpls,
  992. fileList,
  993. tips,
  994. };
  995. this.dialogSubmit = true;
  996. });
  997. // });
  998. },
  999. onCCChange(item) {
  1000. item.ccStatus = !item.ccStatus;
  1001. this.$forceUpdate();
  1002. },
  1003. // 获取提示消息
  1004. getAlertMessage() {
  1005. if (this.processStructureValue.workOrder.is_end === 1) {
  1006. this.alertMessage = "当前工单已结束。";
  1007. }
  1008. },
  1009. // activeOrderActive() {
  1010. // var jsonData = [{
  1011. // id: this.nodeStepList[this.activeIndex].id,
  1012. // label: this.nodeStepList[this.activeIndex].label,
  1013. // process_method: 'person',
  1014. // processor: [this.userId]
  1015. // }]
  1016. // activeOrder(jsonData, this.$route.query.workOrderId).then(() => {
  1017. // this.getProcessNodeList()
  1018. // })
  1019. // },
  1020. async getAllOrgan() {
  1021. // 获取分部
  1022. console.log(this.tenantId, "tenantId");
  1023. // if (this.userType.indexOf("SYSTEM") != -1) {
  1024. queryAllToOrgan({ tenantId: this.tenantId }).then((res) => {
  1025. if (res.code == 200) {
  1026. const result = res.data;
  1027. const processId = this.$route.query.processId;
  1028. let filterOrganId = [];
  1029. if ([40, 41, 45, 46, 47].includes(processId)) {
  1030. filterOrganId = [4];
  1031. } else {
  1032. filterOrganId = [
  1033. 1, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
  1034. 22, 23, 25, 26, 27, 28, 34, 37, 40, 71, 72, 124, 125,
  1035. ];
  1036. }
  1037. let tempOrgan = [];
  1038. // 过滤不会显示的分部
  1039. result.forEach((item) => {
  1040. if (filterOrganId.includes(item.id)) {
  1041. tempOrgan.push(item);
  1042. }
  1043. });
  1044. this.organList = tempOrgan;
  1045. }
  1046. });
  1047. // } else {
  1048. // queryTeacherOrgan({ tenantId: this.tenantId }).then((res) => {
  1049. // if (res.code == 200) {
  1050. // const result = res.data;
  1051. // const filterOrganId = [
  1052. // 36, 39, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 52, 54, 55, 56,
  1053. // ];
  1054. // let tempOrgan = [];
  1055. // // 过滤不会显示的分部
  1056. // result.forEach((item) => {
  1057. // if (!filterOrganId.includes(item.key)) {
  1058. // tempOrgan.push({
  1059. // id: item.key,
  1060. // name: item.value,
  1061. // });
  1062. // }
  1063. // });
  1064. // this.organList = tempOrgan;
  1065. // }
  1066. // });
  1067. // }
  1068. },
  1069. dataModelFormatBr(str) {
  1070. return str ? str.replace(/\n/g, "<br />") : str;
  1071. },
  1072. formatIcon(item, index, type) {
  1073. // 格式化ICON
  1074. // console.log(item, index)
  1075. // console.log(this.activeIndex)
  1076. if (this.activeIndex >= index) {
  1077. if (item.circulation == "转交") {
  1078. return "icon-transfer";
  1079. } else if (this.activeIndex == index) {
  1080. return "icon-wait";
  1081. } else if (item.status == 0) {
  1082. return "el-icon-error";
  1083. } else {
  1084. return "el-icon-success";
  1085. }
  1086. }
  1087. // #fd803a
  1088. return "";
  1089. },
  1090. },
  1091. };
  1092. </script>
  1093. <style lang="scss" scoped>
  1094. :deep(.el-step__title) {
  1095. font-size: 13px;
  1096. line-height: 1.3;
  1097. width: 100%;
  1098. padding-top: 10px;
  1099. padding-right: 10px;
  1100. }
  1101. .step-title {
  1102. color: #000;
  1103. font-size: 16px;
  1104. }
  1105. .apply-time {
  1106. font-size: #999;
  1107. color: #999;
  1108. padding-left: 10px;
  1109. }
  1110. .apply-status {
  1111. line-height: 1.5;
  1112. color: #999;
  1113. margin: 5px 0;
  1114. }
  1115. .remarks {
  1116. background: #f5f5f5;
  1117. padding: 8px;
  1118. color: #323233;
  1119. border-radius: 6px;
  1120. line-height: 1.5;
  1121. }
  1122. .imgUploader {
  1123. background: #f5f5f5;
  1124. margin-top: 8px;
  1125. padding: 8px;
  1126. border-radius: 6px;
  1127. .el-image {
  1128. vertical-align: middle;
  1129. }
  1130. }
  1131. .fileUploader {
  1132. display: flex;
  1133. align-items: center;
  1134. margin-top: 8px;
  1135. background: #f5f5f5;
  1136. padding: 6px;
  1137. border-radius: 4px;
  1138. }
  1139. :deep(.icon-transfer),
  1140. :deep(.icon-wait) {
  1141. display: flex;
  1142. align-items: center;
  1143. box-sizing: content-box;
  1144. background-color: #fff;
  1145. padding: 2px 0;
  1146. height: 23px;
  1147. &::before {
  1148. content: " ";
  1149. display: inline-block;
  1150. width: 23px;
  1151. height: 23px;
  1152. background: url("../../../assets/system-transfer.png") no-repeat center;
  1153. background-size: contain;
  1154. }
  1155. }
  1156. :deep(.icon-wait) {
  1157. &::before {
  1158. content: " ";
  1159. display: inline-block;
  1160. width: 23px;
  1161. height: 23px;
  1162. background: url("../../../assets/system-wait.png") no-repeat center;
  1163. background-size: contain;
  1164. }
  1165. }
  1166. .large-icon {
  1167. :deep(.el-timeline-item__node--large) {
  1168. top: -8px;
  1169. left: -7px;
  1170. width: 24px;
  1171. height: 24px;
  1172. background-color: transparent;
  1173. }
  1174. :deep(.el-icon-success),
  1175. :deep(.el-icon-error) {
  1176. font-size: 24px;
  1177. color: #22b4a9;
  1178. background-color: #fff;
  1179. padding: 2px 0;
  1180. }
  1181. :deep(.el-icon-error) {
  1182. color: #ff2e2e;
  1183. }
  1184. }
  1185. </style>