ApprovalAction.vue 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013
  1. <template>
  2. <div :class="(userAuthority || ownerApply) && is_end == 0 && share != 1 ? 'approvalAction' : null">
  3. <m-header v-if="share != 1" :isNative="false">
  4. <template #right>
  5. <van-icon @click="onShare" :name="iconShare" style="transform: translateY(5px);" size="22"></van-icon>
  6. </template>
  7. </m-header>
  8. <!-- <van-notice-bar
  9. v-if="activeIndex !== nodeStepList.length && is_end===1"
  10. style="margin-bottom: .1rem"
  11. :text="alertMessage"
  12. :scrollable="false"
  13. /> -->
  14. <van-cell class="headerInfo" v-if="processStructureValue.workOrder.priority">
  15. <template #title>
  16. <div class="titleSection" v-if="title">
  17. <span class="titleContent">{{ title }}</span>
  18. <template v-if="processStructureValue.workOrder.priority===2">
  19. <van-tag size="small" style="background: #fff9f6;vertical-align: text-bottom;" plain type="warning">紧急</van-tag>
  20. </template>
  21. <template v-else-if="processStructureValue.workOrder.priority===3">
  22. <van-tag size="small" style="background: #fff6f7;vertical-align: text-bottom;" plain type="danger">非常紧急</van-tag>
  23. </template>
  24. <template v-else-if="processStructureValue.workOrder.priority===1">
  25. <van-tag size="small" style="background: #edfff6;vertical-align: text-bottom;" plain type="success">一般</van-tag>
  26. </template>
  27. </div>
  28. <template v-if="is_end == 0">
  29. <span v-if="userAuthority" class="waitStatus">等待我审批</span>
  30. <span v-else class="waitStatus">{{ principals }}</span>
  31. </template>
  32. <template v-else>
  33. <template v-if="is_cancel == 0">
  34. <span v-if="processStructureValue.workOrder.is_denied" class="waitStatus">审批拒绝</span>
  35. <span v-else class="waitStatus">审批通过</span>
  36. <img v-if="processStructureValue.workOrder.is_denied" class="imgStatus" src="./images/icon_reject.png" />
  37. <img v-else class="imgStatus" src="./images/icon_resolve.png" />
  38. </template>
  39. <template v-else>
  40. <span class="waitStatus">已关闭</span>
  41. <img class="imgStatus" src="./images/icon_close_round.png" />
  42. </template>
  43. </template>
  44. </template>
  45. </van-cell>
  46. <div style="margin: 0 .12rem .12rem;border-radius: .05rem;overflow: hidden;">
  47. <template v-for="(tplItem, tplIndex) in processStructureValue.tpls">
  48. <form-modal
  49. style="padding-bottom: .12rem; background: #fff;"
  50. :key="tplIndex"
  51. v-if="(currentNode.hideTpls!==undefined &&
  52. currentNode.hideTpls!==null &&
  53. currentNode.hideTpls.indexOf(tplItem.form_structure.id)!==-1) ||
  54. (currentNode.writeTpls===undefined ||
  55. currentNode.writeTpls===null ||
  56. currentNode.writeTpls.indexOf(tplItem.form_structure.id)===-1)"
  57. :formData="tplItem.form_structure"
  58. :value="tplItem.form_data"
  59. :preview="true" />
  60. </template>
  61. </div>
  62. <template v-if="userAuthority">
  63. <van-form ref="headForm" validate-first @submit="onSubmitHead" :scroll-to-error="true" :show-error="false">
  64. <template v-for="(tplItem, tplIndex) in processStructureValue.tpls">
  65. <form-modal
  66. :key="tplIndex"
  67. v-if="(currentNode.writeTpls!==undefined &&
  68. currentNode.writeTpls!==null &&
  69. currentNode.writeTpls.indexOf(tplItem.form_structure.id)>-1)?true:false"
  70. :ref="'generateForm-'+tplItem.id"
  71. :value="tplItem.form_data"
  72. :formData="tplItem.form_structure" />
  73. </template>
  74. </van-form>
  75. </template>
  76. <div class="step_section" v-if="circulationHistoryList.length > 0">
  77. <div class="step_title">流程</div>
  78. <van-steps v-if="currentNode.clazz !== undefined && currentNode.clazz !== null && currentNode.clazz !== ''" :active="activeIndex" direction="vertical" inactive-color="#D8D8D8" active-color="#D8D8D8">
  79. <template v-for="(item, index) in circulationHistoryList">
  80. <van-step v-if="item.isHideNode === false ||
  81. item.isHideNode === undefined ||
  82. item.isHideNode == null ||
  83. item.id === processStructureValue.workOrder.current_state"
  84. :key="index" class="step">
  85. <template #inactive-icon>
  86. <i class="inactive-icon"></i>
  87. </template>
  88. <template #active-icon>
  89. <van-icon :name="iconWait" />
  90. </template>
  91. <template #finish-icon>
  92. <template v-if="item.circulation == '转交'">
  93. <van-icon :name="iconSystemTransfer" />
  94. </template>
  95. <template v-else>
  96. <van-icon :name="iconReject" v-if="item.status == 0" />
  97. <van-icon :name="iconComplete" v-else />
  98. </template>
  99. </template>
  100. <div class="step-t">
  101. <p class="apply-state">{{ item.state || item.label }}</p>
  102. <p class="apply-time">{{ item.create_time ? dayjs(item.create_time).format('MM-DD HH:mm') : null }}</p>
  103. </div>
  104. <!-- 判断是否有审核数据 -->
  105. <template v-if="!item.create_time">
  106. <p class="apply-status" v-if="item.assignUsers && item.assignUsers.length > 0">
  107. <!-- 判断是否是自己审批 -->
  108. <template v-if="item.assignUsers[0].userId == userInfo.userId && activeIndex == index">
  109. 我(审批中)
  110. </template>
  111. <template v-else>
  112. <template v-if="item.isCounterSign">
  113. <span v-for="(au, aIndex) in item.assignUsers" :key="aIndex">
  114. {{ au.username }}{{ aIndex<(item.assignUsers.length-1) ? ',' : null }}
  115. </span>
  116. </template>
  117. <template v-else>
  118. {{ item.assignUsers[0].username }}
  119. </template>
  120. {{ activeIndex == index ? `(审批中)` : null }}
  121. <!-- {{ item.assignUsers[0].username }}{{ activeIndex == index ? `(审批中)` : null }} -->
  122. </template>
  123. </p>
  124. </template>
  125. <template v-else>
  126. <p class="apply-status" v-if="item.processor">{{ item.processor }}{{ item.circulation ? `(${item.circulation})` : null }}</p>
  127. <p class="remarks" v-if="item.remarks">{{ item.remarks }}</p>
  128. </template>
  129. <!-- 有抄送人并且,本节点已经审批完成了 -->
  130. <template v-if="item.cc_user && item.cc_user.length > 0 && activeIndex > index">
  131. <!-- 已抄送1人 -->
  132. <div class="ccUsers" @click="onCCChange(item)">
  133. <span>已抄送{{ item.cc_user.length }}人</span>
  134. <van-icon v-show="!item.ccStatus" style="color: #CCCCCC" name="arrow-down" />
  135. <van-icon v-show="item.ccStatus" style="color: #CCCCCC" name="arrow-up" />
  136. </div>
  137. <div class="ccUserDetail" v-if="item.ccStatus">
  138. <span>{{ item.cc_user.join(',') }}</span>
  139. </div>
  140. </template>
  141. </van-step>
  142. </template>
  143. </van-steps>
  144. </div>
  145. <!-- 是自己审批 或者 是自己提交的记录 并且不是分享连接 -->
  146. <van-goods-action v-if="(userAuthority || ownerApply) && is_end == 0 && share != 1">
  147. <van-goods-action-icon v-if="is_end == 0 && ownerApply" :icon="iconDing" text="催办" @click="handleUrge" />
  148. <van-goods-action-icon v-if="is_end == 0 && ownerApply" :icon="iconClose" text="关闭" @click="handleUnity" />
  149. <van-goods-action-icon v-if="is_end == 0 && userAuthority" :icon="iconTransfer" text="转交" @click="exchange" />
  150. <template v-if="userAuthority">
  151. <van-goods-action-button
  152. v-for="(item, index) in btn_group"
  153. :key="index"
  154. :type="item.className"
  155. :disabled="submitDisabled"
  156. :text="item.labelShow"
  157. plain
  158. @click="onCheckSubmit(item)"
  159. />
  160. <!-- 拒绝按钮内置 -->
  161. <van-goods-action-button
  162. v-if="endNodeDetail.id"
  163. :disabled="submitDisabled"
  164. plain
  165. :text="endNodeDetail.label" type="danger"
  166. @click="onCheckSubmit(endNodeDetail)" />
  167. </template>
  168. </van-goods-action>
  169. <!-- 审批时填写意见 -->
  170. <van-popup v-model="showMarks" closeable class="markModel">
  171. <div class="popup-marks">
  172. <h2>确认{{ popupMarkTxt }}</h2>
  173. <van-field
  174. name='remarks'
  175. v-model="remarks"
  176. type="textarea"
  177. row="5"
  178. :autosize=" { maxHeight: 300, minHeight: 180 }"
  179. :placeholder="'请输入审批意见'"
  180. />
  181. <van-button type="info" round @click="popupSubmit">确认{{ popupMarkTxt }}</van-button>
  182. </div>
  183. </van-popup>
  184. <!-- 转交 -->
  185. <van-popup v-model="transferStatus" position="bottom" :style="{ height: '100%', width: '100%' }">
  186. <m-header name="转交" :backUrl="backUrl2" />
  187. <transfer-modal v-if="transferStatus" :popupForm="popupForm" :columns="columns" :nodeList="nodeList" />
  188. </van-popup>
  189. </div>
  190. </template>
  191. <script>
  192. import MHeader from '@/components/MHeader'
  193. import { processStructure, handleWorkOrder, sysUserList, urgeWorkOrder, getInfo, unityWorkOrder, asyncPlayLog } from './api'
  194. import FormModal from './modal/formModal'
  195. import TransferModal from './modal/transferModal'
  196. import copy from "copy-to-clipboard";
  197. import dayjs from 'dayjs'
  198. export default {
  199. name: 'approvalAction',
  200. components: { MHeader, FormModal, TransferModal },
  201. data() {
  202. let query = this.$route.query
  203. return {
  204. iconComplete: require('./images/system-complete-default.png'),
  205. iconWait: require('./images/system-wait.png'),
  206. iconReject: require('./images/system-reject.png'),
  207. iconSystemTransfer: require('./images/system-transfer.png'),
  208. iconTransfer: require('./images/icon_transfer.png'),
  209. iconDing: require('./images/icon_ding.png'),
  210. iconClose: require('./images/icon_close.png'),
  211. iconShare: require('./images/icon_share.png'),
  212. showMarks: false,
  213. popupMarkTxt: null,
  214. backUrl2: {
  215. callBack: () => {
  216. this.transferStatus = false
  217. }
  218. },
  219. dayjs,
  220. active: 0,
  221. // classify: query.classify,
  222. processId: query.processId,
  223. workOrderId: query.workOrderId,
  224. principals: null,
  225. share: query.share,
  226. title: null,
  227. submitDisabled: false,
  228. ruleForm: {
  229. title: '',
  230. priority: 1,
  231. process: '',
  232. classify: '',
  233. state: [],
  234. source: '',
  235. source_state: '',
  236. process_method: '',
  237. tpls: {
  238. 'form_structure': [],
  239. 'form_data': []
  240. },
  241. tasks: []
  242. },
  243. currentNode: {
  244. hideTpls: null,
  245. writeTpls: null
  246. },
  247. isActiveProcessing: false,
  248. tpls: [],
  249. remarks: '', // 备注信息
  250. alertMessage: '',
  251. nodeStepList: [],
  252. circulationHistoryList: [],
  253. endNodeDetail: {}, // 结束结节信息
  254. activeIndex: 0,
  255. processStructureValue: {
  256. workOrder: { title: '' }
  257. },
  258. selectItem: null,
  259. btn_group: [],
  260. transferStatus: false,
  261. columns: [],
  262. popupForm: {
  263. work_order_id: '',
  264. node_id: '',
  265. user_id: '',
  266. remarks: ''
  267. },
  268. userInfo: {},
  269. userAuthority: false, // 是否是自己审批
  270. ownerApply: false, // 是否是自己提交的申请
  271. is_end: 0, // 是否结束
  272. is_cancel: 0, // 是否取消
  273. }
  274. },
  275. async mounted() {
  276. await this.getProcessNodeList()
  277. if(this.share != 1) {
  278. await this.getUserInfo()
  279. }
  280. },
  281. methods: {
  282. onShare() {
  283. const url = window.location.href + '&share=1'
  284. copy(url);
  285. copy(url);
  286. this.$toast('分享连接复制成功')
  287. },
  288. // 获取对应元素的值
  289. getFormDataDetail(formData, model) {
  290. let modelStatus = {
  291. status: false,
  292. value: null
  293. }
  294. for(let data in formData) {
  295. if(typeof formData[data] == 'object') {
  296. // 没有子表单里面有子表单
  297. for(let child in formData[data]) {
  298. if(child == model) {
  299. modelStatus = {
  300. status: true,
  301. model: child,
  302. value: formData[data][child] ? formData[data][child].split(',') : []
  303. }
  304. }
  305. }
  306. } else {
  307. if(data == model) {
  308. modelStatus = {
  309. status: true,
  310. model: data,
  311. value: formData[data] ? formData[data].split(',') : []
  312. }
  313. }
  314. }
  315. }
  316. return modelStatus
  317. },
  318. getSelectValueObject(tpls, type = 'value', tplValues = []) {
  319. const tempData = tpls || []
  320. let selectList = []
  321. tempData.forEach((temp, index) => {
  322. let tempList = temp.form_structure.list || []
  323. let tempSelectList = tplValues[index] || []
  324. let listArray = []
  325. tempList.forEach(list => {
  326. if(list.type == 'select') {
  327. if(type == 'value') {
  328. const result = this.getFormDataDetail(temp.form_data, list.model)
  329. if(result.status) {
  330. listArray.push(result)
  331. }
  332. } else {
  333. let selectOptions = []
  334. let selectValue = []
  335. tempSelectList.forEach(tsl => {
  336. if(tsl.model == list.model) {
  337. selectOptions = list.options?.options || []
  338. selectValue = tsl.value || []
  339. }
  340. })
  341. selectOptions.forEach(so => {
  342. if(selectValue.includes(so.value)) {
  343. let tempRo = so.relationOptions || []
  344. listArray.push(...tempRo)
  345. }
  346. })
  347. }
  348. }
  349. if(list.type == 'subform') {
  350. let childList = list.columns || []
  351. childList.forEach(child => {
  352. let childList = child.list || []
  353. childList.forEach(c => {
  354. if(c.type == 'select') {
  355. if(type == 'value') {
  356. const originObj = JSON.parse(JSON.stringify(c))
  357. const result = this.getFormDataDetail(temp.form_data, originObj.model)
  358. if(result.status) {
  359. listArray.push(result)
  360. }
  361. } else {
  362. let selectOptions = []
  363. let selectValue = []
  364. tempSelectList.forEach(tsl => {
  365. if(tsl.model == c.model) {
  366. selectOptions = c.options?.options || []
  367. selectValue = tsl.value || []
  368. }
  369. })
  370. selectOptions.forEach(so => {
  371. if(selectValue.includes(so.value)) {
  372. let tempRo = so.relationOptions || []
  373. listArray.push(...tempRo)
  374. }
  375. })
  376. }
  377. }
  378. })
  379. });
  380. }
  381. })
  382. selectList.push(listArray)
  383. })
  384. return selectList
  385. },
  386. async getProcessNodeList() {
  387. try {
  388. let params = {
  389. processId: this.processId,
  390. workOrderId: this.workOrderId
  391. }
  392. const userId = sessionStorage.getItem('userId')
  393. if(this.share != 1 && userId) {
  394. params.userId = userId
  395. }
  396. let res = await processStructure(params)
  397. this.isActiveProcessing = false
  398. let tempData = res.data.tpls
  399. // 获取对应模板中,下拉框的key, value
  400. let selectList = this.getSelectValueObject(tempData)
  401. // 获取对应模板中,需要隐藏的字段
  402. let hiddenFormList = this.getSelectValueObject(tempData, 'hiddenForm', selectList)
  403. tempData.forEach((temp, index) => {
  404. let tempList = temp.form_structure.list || []
  405. tempList.forEach(item => {
  406. if(hiddenFormList[index].length > 0) {
  407. if(item.type != 'text' && !item.options.relationStatus) {
  408. item.hidden = true
  409. } else {
  410. item.hidden = false
  411. }
  412. // item.hidden = false
  413. if(hiddenFormList[index].includes(item.model)) {
  414. item.hidden = false
  415. }
  416. } else {
  417. item.hidden = false
  418. }
  419. // 子表单
  420. if(item.type == 'subform') {
  421. let childList = item.columns || []
  422. let subFormStatus = true
  423. childList.forEach(child => {
  424. let childList = child.list || []
  425. childList.forEach(c => {
  426. if(hiddenFormList[index].length > 0) {
  427. if(c.type != 'text' && !c.options.relationStatus) {
  428. c.hidden = true
  429. } else {
  430. c.hidden = false
  431. subFormStatus = false
  432. }
  433. if(hiddenFormList[index].includes(c.model)) {
  434. c.hidden = false
  435. subFormStatus = false
  436. }
  437. } else {
  438. c.hidden = false
  439. subFormStatus = false
  440. }
  441. })
  442. });
  443. item.hidden = subFormStatus
  444. }
  445. })
  446. })
  447. this.processStructureValue = res.data
  448. this.circulationHistoryList = this.processStructureValue.circulationHistory
  449. this.userAuthority = this.processStructureValue.userAuthority
  450. this.is_end = res.data.workOrder.is_end
  451. this.is_cancel = res.data.workOrder.is_cancel
  452. if(res.data.workOrder.title) {
  453. this.title = res.data.workOrder.title
  454. }
  455. // 获取当前展示节点列表
  456. this.nodeStepList = []
  457. this.tempNodeStepList = []
  458. const nodes = this.processStructureValue.nodes
  459. this.principals = '处理中'
  460. for (var i = 0; i < nodes.length; i++) {
  461. if (nodes[i].id === this.processStructureValue.workOrder.current_state) {
  462. // 当前节点
  463. this.nodeStepList.push(nodes[i])
  464. this.activeIndex = this.nodeStepList.length - 1
  465. if (i + 1 === nodes.length) {
  466. this.activeIndex = this.nodeStepList.length
  467. }
  468. this.currentNode = nodes[i]
  469. // 处理是认谁在处理,已处理完成则显示处理中
  470. const assignUsers = nodes[i].assignUsers
  471. if(assignUsers && assignUsers.length > 0) {
  472. this.principals = assignUsers[0].username + '处理中'
  473. }
  474. } else if (!nodes[i].isHideNode) {
  475. // 非隐藏节点
  476. this.nodeStepList.push(nodes[i])
  477. }
  478. // 判断节点里面是否有结束节点,而且一个流程里面只能有一个结束结点,
  479. if(nodes[i].clazz == 'end') {
  480. this.endNodeDetail = JSON.parse(JSON.stringify(nodes[i]))
  481. this.endNodeDetail.target = nodes[i].id
  482. this.endNodeDetail.flowProperties = 0 // 拒绝属性
  483. this.endNodeDetail.label = '拒绝'
  484. }
  485. }
  486. this.circulationHistoryList.reverse()
  487. // 如果审批流程没有结束则,流程和历史记录合并显示;结束了,就只显示历史记录
  488. if (!this.is_end) {
  489. this.circulationHistoryList.forEach(cir => {
  490. this.nodeStepList.forEach(node => {
  491. if(cir.source == node.id) {
  492. cir.label = node.label
  493. cir.assignType = node.assignType
  494. cir.assignValue = node.assignValue
  495. cir.assignUsers = node.assignUsers
  496. cir.id = node.id
  497. }
  498. })
  499. })
  500. let tempNodes = []
  501. this.nodeStepList.forEach(node => {
  502. let count = 0
  503. this.circulationHistoryList.forEach(cir => {
  504. if(node.id === cir.source) {
  505. count += 1
  506. }
  507. })
  508. if(count <= 0) {
  509. tempNodes.push(node)
  510. }
  511. })
  512. this.circulationHistoryList.push(...tempNodes)
  513. this.circulationHistoryList.forEach((cir, index) => {
  514. if(cir.id == this.processStructureValue.workOrder.current_state) {
  515. this.activeIndex = index
  516. if(index + 1 == this.circulationHistoryList.length) {
  517. this.activeIndex = this.circulationHistoryList.length
  518. }
  519. }
  520. })
  521. } else {
  522. this.activeIndex = this.circulationHistoryList.length
  523. }
  524. // 添加抄送状态
  525. this.circulationHistoryList.forEach((res) => {
  526. res.ccStatus = true
  527. })
  528. // 如果回退到初始节点则可编辑。
  529. if (this.activeIndex === 0 && this.currentNode.clazz === 'start') {
  530. this.currentNode.writeTpls = []
  531. for (var tplTmp of this.processStructureValue.tpls) {
  532. this.currentNode.writeTpls.push(tplTmp.form_structure.id)
  533. }
  534. }
  535. // 判断是否需要主动处理
  536. for (var stateValue of this.processStructureValue.workOrder.state) {
  537. if (this.processStructureValue.workOrder.current_state === stateValue.id && stateValue.processor.length > 1) {
  538. this.isActiveProcessing = true
  539. break
  540. }
  541. }
  542. let psv = res.data?.edges || []
  543. let btn_group = []
  544. psv.forEach(item => {
  545. // console.log(this.currentNode)
  546. // 过滤其它类型的操作
  547. if(this.is_end===0 && item.source===this.currentNode.id && item.flowProperties == 1) {
  548. if(item.flowProperties == 1) {
  549. item.className = 'info'
  550. item.labelShow = '同意'
  551. } else if(item.flowProperties == 0) {
  552. item.className = 'danger'
  553. } else if(item.flowProperties == 2) {
  554. item.className = 'info'
  555. }
  556. btn_group.push(item)
  557. } else {
  558. item.className = 'info'
  559. }
  560. })
  561. this.btn_group = btn_group
  562. // console.log(this.endNodeDetail, btn_group , 'btn_group')
  563. this.getAlertMessage()
  564. } catch {
  565. //
  566. }
  567. },
  568. relationFormChange(value) {
  569. let temp = value || []
  570. this.formData.list?.forEach(item => {
  571. item.hidden = false
  572. if(temp.includes(item.model)) {
  573. item.hidden = true
  574. }
  575. // 子表单
  576. if(item.type == 'subform') {
  577. let childList = item.columns || []
  578. childList.forEach(child => {
  579. if(child.list?.length > 0) {
  580. child.list.forEach(c => {
  581. c.hidden = false
  582. if(temp.includes(c.originModel)) {
  583. c.hidden = true
  584. }
  585. })
  586. }
  587. });
  588. // 重置数据
  589. let subForm = this.$refs.subform
  590. subForm.forEach(item => {
  591. item.reSetFormData()
  592. })
  593. }
  594. })
  595. },
  596. async getUserInfo() {
  597. // 获取用户信息
  598. try {
  599. let user = await getInfo()
  600. this.userInfo = user.data
  601. this.ownerApply = this.processStructureValue.workOrder.creator == this.userInfo.userId ? true : false
  602. } catch {
  603. //
  604. }
  605. },
  606. // 获取提示消息
  607. getAlertMessage() {
  608. if (this.is_end === 1) {
  609. this.alertMessage = '当前工单已结束'
  610. }
  611. },
  612. // 转交
  613. async exchange() {
  614. let workOrder = this.processStructureValue.workOrder
  615. this.popupForm.work_order_id = workOrder.id
  616. this.nodeList = workOrder.state || []
  617. this.nodeList.forEach(item => {
  618. item.text = item.label
  619. })
  620. if (this.nodeList.length === 1) {
  621. this.popupForm.node_id = this.nodeList[0].id
  622. }
  623. try {
  624. // 获取所有用户
  625. const res = await sysUserList({ pageSize: 9999 })
  626. const users = res.data.list || []
  627. users.forEach(item => {
  628. this.columns.push({
  629. avatar: item.avatar,
  630. text: item.nickName,
  631. phone: item.phone,
  632. id: item.userId
  633. })
  634. })
  635. } catch {
  636. //
  637. }
  638. this.transferStatus = true
  639. },
  640. // 催办
  641. handleUrge() {
  642. this.$dialog.confirm({
  643. title: '催办',
  644. allowHtml : true,
  645. message: '<span style="font-size:15px ">对此工单处理人进行催办通知提醒, 是否继续?</span><br><span style="color: #c33; font-size: 10px">注意:十分钟内只能催办一次。</span>',
  646. confirmButtonColor: '#01C1B5'
  647. }).then(async () => {
  648. try {
  649. let workOrder = this.processStructureValue.workOrder
  650. let workOrderId = workOrder.id
  651. await urgeWorkOrder({ workOrderId })
  652. this.$toast('已进行催办通知')
  653. } catch {
  654. //
  655. }
  656. })
  657. },
  658. handleUnity() {
  659. // 关闭
  660. this.$dialog.confirm({
  661. title: '提示',
  662. allowHtml : true,
  663. message: '<span style="font-size:15px ">此操作将会关闭该工单, 是否继续?</span>',
  664. confirmButtonColor: '#01C1B5'
  665. }).then(async () => {
  666. try {
  667. let workOrder = this.processStructureValue.workOrder
  668. let work_oroder_id = workOrder.id
  669. await unityWorkOrder({ work_oroder_id })
  670. this.$toast('已关闭工单')
  671. setTimeout(() => {
  672. this.$router.push({
  673. path: '/myApproval',
  674. query: {
  675. classify: 2
  676. }
  677. })
  678. }, 500)
  679. } catch {
  680. //
  681. }
  682. })
  683. },
  684. onCheckSubmit(item) {
  685. this.selectItem = item
  686. this.$refs.headForm.validate().then(() => {
  687. this.showMarks = true
  688. this.popupMarkTxt = item.label
  689. })
  690. },
  691. popupSubmit() {
  692. this.$refs.headForm.submit()
  693. this.showMarks = false
  694. this.popupMarkTxt = null
  695. },
  696. onCCChange(item) {
  697. item.ccStatus = !item.ccStatus
  698. this.$forceUpdate()
  699. },
  700. async onSubmitHead(values) {
  701. // remarks
  702. let { ...res } = values
  703. let promiseList = []
  704. this.tpls = []
  705. for (let tpl of this.processStructureValue.tpls) {
  706. this.tpls.push({
  707. tplDataId: tpl.id,
  708. tplId: tpl.form_structure.id
  709. })
  710. // 说明是当前用户需要填写的列表数据
  711. if((this.currentNode.writeTpls!==undefined &&
  712. this.currentNode.writeTpls!==null &&
  713. this.currentNode.writeTpls.indexOf(tpl.form_structure.id)>-1)) {
  714. let fd = this.formatData(res)
  715. promiseList.push(fd)
  716. } else {
  717. // 已存在的表单数据
  718. promiseList.push(tpl.form_data)
  719. }
  720. }
  721. for (let tplDataIndex in this.tpls) {
  722. this.tpls[tplDataIndex].tplValue = promiseList[tplDataIndex]
  723. }
  724. let params = {
  725. tasks: this.processStructureValue.process.task,
  726. source_state: this.processStructureValue.workOrder.current_state,
  727. target_state: this.selectItem.target,
  728. circulation: this.selectItem.label,
  729. flow_properties: this.selectItem.flowProperties === undefined ? 2 : parseInt(this.selectItem.flowProperties),
  730. work_order_id: parseInt(this.workOrderId),
  731. remarks: this.remarks,
  732. tpls: this.tpls
  733. }
  734. let fileList = []
  735. this.tpls && this.tpls.forEach(tpl => {
  736. for(let val in tpl.tplValue) {
  737. if(val.indexOf('file') != -1) {
  738. const file = tpl.tplValue[val] || []
  739. file.forEach(item => {
  740. fileList.push(item.url)
  741. })
  742. }
  743. }
  744. })
  745. try {
  746. // const fileUrl = ''
  747. // console.log(params)
  748. // return
  749. // 确认提交
  750. await handleWorkOrder(params)
  751. await asyncPlayLog({ workOrderId: parseInt(this.workOrderId), fileUrl: fileList.join(',')})
  752. this.submitDisabled = false
  753. // workOrderId
  754. this.getProcessNodeList()
  755. } catch {
  756. //
  757. this.submitDisabled = false
  758. }
  759. },
  760. formatData(json) {
  761. let tempJson = {}
  762. let subFormList = {}
  763. for(let v in json) {
  764. let nameList = v.split('.')
  765. // 只要大于1说明是子表单
  766. if(nameList.length > 1) {
  767. nameList.push(v)
  768. let delName = nameList.shift()
  769. if(subFormList[delName]) {
  770. subFormList[delName].push(nameList)
  771. } else {
  772. subFormList[delName] = []
  773. subFormList[delName].push(nameList)
  774. }
  775. } else {
  776. tempJson[v] = json[v]
  777. }
  778. }
  779. for(let sub in subFormList) {
  780. let subList = subFormList[sub] || []
  781. let subDown = []
  782. subList.forEach(item => {
  783. if(subDown[item[1]]) {
  784. subDown[item[1]][item[0]] = json[item[2]]
  785. } else {
  786. subDown[item[1]] = {}
  787. subDown[item[1]][item[0]] = json[item[2]]
  788. }
  789. })
  790. tempJson[sub] = subDown
  791. }
  792. return tempJson
  793. },
  794. getHideTplData(tpl) {
  795. // 獲取隱藏模板數據
  796. let list = tpl.list
  797. let data = {}
  798. list.forEach(item => {
  799. if(item.type == 'subform') {
  800. if(item.columns.length > 0) {
  801. data[item.model] = []
  802. let arr = []
  803. item.columns?.forEach(col => {
  804. if(col.list?.length > 0) {
  805. arr.push(...col.list)
  806. }
  807. })
  808. let tempSub = {}
  809. arr.forEach(a => {
  810. tempSub[a.model] = a.options.defaultValue
  811. })
  812. data[item.model].push(tempSub)
  813. } else {
  814. data[item.model] = ''
  815. }
  816. } else {
  817. data[item.model] = item.options.defaultValue
  818. }
  819. })
  820. return data
  821. }
  822. }
  823. }
  824. </script>
  825. <style lang='less' scoped>
  826. @import url("../../assets/commonLess/variable.less");
  827. .approvalAction {
  828. margin-bottom: 85px;
  829. padding-bottom: env(safe-area-inset-bottom)
  830. }
  831. /deep/.van-goods-action {
  832. box-shadow: 0 4px 10px 0 #cecece;
  833. z-index: 99;
  834. justify-content: space-around;
  835. height: 70px;
  836. .van-goods-action-icon__icon {
  837. font-size: 20px;
  838. min-width: 55px;
  839. }
  840. .van-goods-action-button--last {
  841. margin-right: .12rem;
  842. }
  843. .van-button--danger {
  844. background: #fff;
  845. border: 1px solid #01C1B5;
  846. color: #01C1B5;
  847. }
  848. }
  849. .style {
  850. margin-bottom: .12rem;
  851. padding: 12px 16px;
  852. line-height: 1.3;
  853. font-size: 16px;
  854. &.info {
  855. display: flex;
  856. flex-direction: column;
  857. }
  858. /deep/.van-field__label {
  859. margin-bottom: 7px;
  860. width: auto;
  861. color: #111F2C;
  862. }
  863. /deep/.van-field__value {
  864. padding: .03rem 0;
  865. }
  866. }
  867. .headerInfo {
  868. margin-bottom: 0.1rem;
  869. padding: 0.18rem 0.12rem;
  870. overflow: inherit;
  871. /deep/.van-cell__title {
  872. flex-direction: column;
  873. align-items: flex-start;
  874. }
  875. }
  876. .titleSection {
  877. .titleContent {
  878. font-size: 0.18rem;
  879. color: #333333;
  880. padding-right: 0.08rem;
  881. }
  882. }
  883. .waitStatus {
  884. color: #F39001;
  885. font-size: .14rem;
  886. display: inline-block;
  887. padding-top: .06rem;
  888. }
  889. .imgStatus {
  890. bottom: -35%;
  891. width: 0.75rem;
  892. height: 0.75rem;
  893. position: absolute;
  894. z-index: 98;
  895. right: .2rem;
  896. }
  897. .markModel {
  898. width: 90%;
  899. border-radius: .08rem;
  900. padding: .2rem 0;
  901. }
  902. .popup-marks {
  903. // width: 95%;
  904. h2 {
  905. font-size: .16rem;
  906. text-align: center;
  907. }
  908. /deep/.van-cell {
  909. font-size: .14rem;
  910. }
  911. /deep/.van-button {
  912. width: 90%;
  913. margin-left: 5%;
  914. font-size: .16rem;
  915. }
  916. }
  917. .step_section {
  918. margin: 0px 0.12rem 0.12rem;
  919. border-radius: .1rem;
  920. overflow: hidden;
  921. .step_title {
  922. background: #fff;
  923. padding: .1rem 0.16rem;
  924. color: #333333;
  925. font-size: .18rem;
  926. font-weight: 500;
  927. }
  928. /deep/.van-steps--vertical {
  929. padding-left: .45rem;
  930. .van-step__circle-container, .van-step__line {
  931. left: -22px;
  932. }
  933. }
  934. .step {
  935. font-size: .13rem;
  936. .step-t {
  937. display: flex;
  938. align-content: center;
  939. justify-content: space-between;
  940. font-size: .16rem;
  941. color: #444;
  942. }
  943. .inactive-icon {
  944. width: .1rem;
  945. height: .1rem;
  946. background: #D8D8D8;
  947. display: inline-block;
  948. border-radius: 1rem;
  949. }
  950. .apply-state {
  951. line-height: 1.5;
  952. flex-basis: 73%;
  953. }
  954. .apply-time {
  955. font-size: .14rem;
  956. color: #999999;
  957. flex-basis: 27%;
  958. }
  959. .apply-status {
  960. padding: .05rem 0;
  961. color: #999;
  962. }
  963. .remarks {
  964. background: #f5f5f5;
  965. padding: .08rem;
  966. color: #323233;
  967. }
  968. .van-icon {
  969. font-size: .17rem;
  970. }
  971. }
  972. .ccUsers {
  973. display: flex;
  974. align-items: center;
  975. justify-content: space-between;
  976. color: #444;
  977. padding-top: .08rem;
  978. }
  979. .ccUserDetail {
  980. color: #444;
  981. }
  982. }
  983. </style>