customFlowUpdate.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. <template>
  2. <view class="uni-app">
  3. <view class="status-bar" />
  4. <view class="main-container">
  5. <wk-nav-bar :title="navTitle" />
  6. <view
  7. v-if="showNoData"
  8. :style="{backgroundImage: bgUrl('images/no_data.png')}"
  9. class="no-data">
  10. 暂无数据
  11. </view>
  12. <view
  13. v-else class="container">
  14. <view
  15. v-if="detailData.taskData && detailData.taskData.length"
  16. class="task-contaienr">
  17. <view class="group-title-box">
  18. <view class="prev-badge" />
  19. <text>阶段工作</text>
  20. </view>
  21. <view class="task-content">
  22. <view
  23. v-for="(task, index) in detailData.taskData"
  24. :key="index"
  25. class="task-item"
  26. @click="changeTaskStatus(task)">
  27. <view :class="{over: task.isOk}" class="checkbox">
  28. <text v-if="task.isOk" class="icon wk wk-check" />
  29. </view>
  30. <view class="item-content">
  31. <view class="item-title" :class="{'over': task.isOk}">
  32. <text v-if="task.isNull" class="required">
  33. *
  34. </text>
  35. <text>{{ task.taskName }}</text>
  36. </view>
  37. <view
  38. v-if="task.isOk && task.createUserName"
  39. class="item-desc">
  40. {{ task.createUserName }}于{{ task.createTime | formatTime }}完成
  41. </view>
  42. </view>
  43. </view>
  44. </view>
  45. </view>
  46. <view
  47. v-if="fieldList.length"
  48. class="form-container">
  49. <view class="group-title-box">
  50. <view class="prev-badge" />
  51. <text>表单信息</text>
  52. </view>
  53. <view class="form-content">
  54. <wk-form
  55. ref="fieldForm"
  56. :fields="fieldList"
  57. @change="formChange" />
  58. </view>
  59. </view>
  60. <view v-if="showAudit" class="examine-container">
  61. <wk-audit-add ref="wkAuditAdd" />
  62. </view>
  63. </view>
  64. <view
  65. v-if="!showNoData"
  66. class="footer-btn-group">
  67. <button
  68. class="button plain-btn"
  69. @click="handleToComment">
  70. 反馈
  71. <template v-if="detailData.commentNum">
  72. ({{ detailData.commentNum }})
  73. </template>
  74. </button>
  75. <button
  76. class="button"
  77. @click="handleSave(true)">
  78. 保存草稿箱
  79. </button>
  80. <button
  81. class="button"
  82. @click="handleSave(false)">
  83. 提交
  84. </button>
  85. </view>
  86. </view>
  87. <uni-popup
  88. ref="commentPopup"
  89. radius="20rpx 20rpx 0 0"
  90. type="bottom"
  91. @click.stop>
  92. <flow-comment-popup
  93. v-if="showCommentContent"
  94. :data-id="routerQuery.id"
  95. :comment-num="detailData.commentNum"
  96. @update="getData"
  97. @close="handleCloseComment" />
  98. </uni-popup>
  99. </view>
  100. </template>
  101. <script>
  102. import {
  103. QueryFlowDataInfoAPI,
  104. SaveFlowDataAPI
  105. } from '@/api/crm/flow.js'
  106. import { PreviewFiledName } from '@/api/examine.js'
  107. import FlowCommentPopup from './components/customFlow/flowCommentPopup.vue'
  108. import formMixins from '@/mixins/formMixins.js'
  109. import { deepCopy } from '@/utils/lib.js'
  110. import { isArray } from '@/utils/types.js'
  111. import moment from 'moment'
  112. export default {
  113. name: 'CustomFlowUpdate',
  114. filters: {
  115. formatTime(data) {
  116. return moment(data).format('YYYY-MM-DD HH:mm:ss')
  117. }
  118. },
  119. components: {
  120. FlowCommentPopup
  121. },
  122. mixins: [formMixins],
  123. data() {
  124. return {
  125. loading: false,
  126. routerQuery: {},
  127. detailData: {},
  128. fieldList: [],
  129. showAudit: false,
  130. auditConditionFields: [],
  131. timer: null,
  132. showCommentContent: false,
  133. commandData: []
  134. }
  135. },
  136. computed: {
  137. navTitle() {
  138. const name = this.detailData.flowName || ''
  139. return `${name}阶段信息`
  140. },
  141. showNoData() {
  142. if (!this.detailData) return true
  143. if (
  144. this.detailData.taskData &&
  145. this.detailData.taskData.length
  146. ) return false
  147. if (this.fieldList.length) return false
  148. if (this.showAudit) return false
  149. return true
  150. }
  151. },
  152. onLoad(options) {
  153. this.routerQuery = options || {}
  154. this.getData()
  155. },
  156. methods: {
  157. bgUrl(val) {
  158. return `url(${this.$static(val)})`
  159. },
  160. getData() {
  161. QueryFlowDataInfoAPI({
  162. dataId: this.routerQuery.id
  163. }).then(res => {
  164. this.detailData = res
  165. const list = deepCopy(this.detailData.fieldData || [])
  166. console.log('list: ', list)
  167. list.forEach(field => {
  168. field.value = this.mixinsFormatFieldValue(field)
  169. })
  170. this.fieldList = list
  171. if (res.examineId) {
  172. this.getAuditList()
  173. }
  174. }).catch(() => {})
  175. },
  176. /**
  177. * 获取审批流程条件
  178. */
  179. getAuditList() {
  180. PreviewFiledName({
  181. examineId: this.detailData.examineId
  182. }).then(res => {
  183. this.showAudit = res !== null
  184. if (!this.showAudit) return
  185. const mapIns = new Map()
  186. this.auditConditionFields = res.filter(o => !mapIns.has(o.fieldId) && mapIns.set(o.fieldId, 1))
  187. // console.log('PreviewFiledName: ', this.auditConditionFields)
  188. this.$nextTick(() => {
  189. const dataMap = {}
  190. this.auditConditionFields.forEach(o => {
  191. const findRes = this.fieldList.find(f => f.fieldName === o.fieldName)
  192. if (findRes) {
  193. let value = findRes.value
  194. switch (findRes.formType) {
  195. case 'select':
  196. if (this.$isEmpty(value)) value = ''
  197. if (isArray(value)) {
  198. value = value[0].value
  199. }
  200. break
  201. case 'checkbox':
  202. if (this.$isEmpty(value)) value = ''
  203. if (isArray(value)) {
  204. value = value.map(o => o.value).join(',')
  205. }
  206. break
  207. default:
  208. value = this.$isEmpty(value) ? '' : value
  209. }
  210. o._val = value
  211. dataMap[o.fieldName] = value
  212. }
  213. })
  214. this.$refs.wkAuditAdd.getAuditInfo({
  215. examineId: this.detailData.examineId,
  216. dataMap
  217. })
  218. })
  219. }).catch(() => {})
  220. },
  221. /**
  222. * 根据条件更新审批流程
  223. * @param {Object} field
  224. * @param {Object} value
  225. */
  226. changeAuditFlow(field, value) {
  227. if (!this.showAudit) return
  228. const findRes = this.auditConditionFields.find(o => o.fieldName === field.fieldName)
  229. if (!findRes) return
  230. switch (field.formType) {
  231. case 'select':
  232. if (this.$isEmpty(value)) value = ''
  233. if (isArray(value)) {
  234. value = value[0].value
  235. }
  236. break
  237. case 'checkbox':
  238. if (this.$isEmpty(value)) value = ''
  239. if (isArray(value)) {
  240. value = value.map(o => o.value).join(',')
  241. }
  242. break
  243. default:
  244. value = this.$isEmpty(value) ? '' : value
  245. }
  246. findRes._val = value
  247. const dataMap = {}
  248. this.auditConditionFields.forEach(o => {
  249. if (o.hasOwnProperty('_val')) {
  250. dataMap[o.fieldName] = this.$isEmpty(o._val) ? '' : o._val
  251. } else {
  252. dataMap[o.fieldName] = ''
  253. }
  254. })
  255. this.$nextTick(() => {
  256. this.$refs.wkAuditAdd.getAuditInfo({
  257. examineId: this.detailData.examineId,
  258. dataMap
  259. })
  260. })
  261. },
  262. /**
  263. * 修改任务状态
  264. */
  265. changeTaskStatus(task) {
  266. const status = task.isOk === 1 ? 0 : 1
  267. this.$set(task, 'isOk', status)
  268. },
  269. /**
  270. * 修改表单字段值
  271. * @param {Object} data
  272. */
  273. formChange(data) {
  274. console.log('value change: ', data)
  275. this.changeAuditFlow(data.field, data.value)
  276. },
  277. /**
  278. * 反馈信息弹窗
  279. */
  280. handleToComment() {
  281. this.showCommentContent = true
  282. this.$refs.commentPopup.open()
  283. },
  284. /**
  285. * 关闭反馈弹窗
  286. */
  287. handleCloseComment() {
  288. this.showCommentContent = false
  289. this.$refs.commentPopup.close()
  290. },
  291. handleSave(isDraft = false) {
  292. if (this.loading) return
  293. this.loading = true
  294. const saveForm = {
  295. id: this.detailData.id, // 阶段id
  296. flowId: this.detailData.flowId, // 阶段流程id
  297. status: isDraft ? 0 : 1 // 0 保存草稿 1 提交
  298. }
  299. // 任务
  300. saveForm.taskData = deepCopy(this.detailData.taskData || [])
  301. if (saveForm.taskData.length) {
  302. const filterArr = saveForm.taskData.filter(task => {
  303. return task.isNull && !task.isOk
  304. })
  305. if (filterArr.length) {
  306. const msg = filterArr.map(o => o.taskName).join(',')
  307. this.$toast(`阶段工作${msg}为必做`)
  308. return
  309. }
  310. saveForm.taskData.forEach(task => {
  311. delete task.companyId
  312. })
  313. }
  314. // 审批信息
  315. if (!isDraft && this.showAudit) {
  316. const data = this.$refs.wkAuditAdd.getSaveData()
  317. if (data === null) {
  318. this.loading = false
  319. return
  320. }
  321. const dataMap = {}
  322. this.auditConditionFields.forEach(o => {
  323. if (o.hasOwnProperty('_val')) {
  324. dataMap[o.fieldName] = this.$isEmpty(o._val) ? '' : o._val
  325. }
  326. })
  327. saveForm.examineFlowData = {
  328. ...data,
  329. categoryId: this.detailData.examineId,
  330. dataMap
  331. }
  332. }
  333. // 表单
  334. const fieldFormInstance = this.$refs.fieldForm
  335. if (fieldFormInstance) {
  336. fieldFormInstance.getForm().then(form => {
  337. saveForm.fieldData = form.field
  338. this.submitForm(saveForm)
  339. }).catch(() => {
  340. this.loading = false
  341. })
  342. } else {
  343. this.submitForm(saveForm)
  344. }
  345. },
  346. /**
  347. * 提交流程表单
  348. * @param {Object} form
  349. */
  350. submitForm(form) {
  351. // console.log('submit form: ', form)
  352. this.loading = true
  353. SaveFlowDataAPI(form).then(res => {
  354. this.loading = false
  355. this.$refreshAndToPrev(this, true)
  356. }).catch(() => {
  357. this.loading = false
  358. })
  359. }
  360. }
  361. }
  362. </script>
  363. <style scoped lang="scss">
  364. .checkbox {
  365. width: 32rpx;
  366. height: 32rpx;
  367. border: 1rpx solid #CCCCCC;
  368. border-radius: 6rpx;
  369. overflow: hidden;
  370. @include center;
  371. .icon {
  372. font-size: 24rpx;
  373. line-height: 1;
  374. color: white;
  375. }
  376. &.over {
  377. background-color: $theme-color;
  378. border-color: $theme-color;
  379. }
  380. }
  381. .no-data {
  382. width: 100%;
  383. flex: 1;
  384. text-align: center;
  385. font-size: 26rpx;
  386. color: #BBBBBB;
  387. background-position: center 200rpx;
  388. background-repeat: no-repeat;
  389. background-size: 200rpx;
  390. padding-top: 430rpx;
  391. }
  392. .container {
  393. flex: 1;
  394. background-color: white;
  395. overflow: auto;
  396. padding: 0 30rpx 20rpx;
  397. .group-title-box {
  398. font-size: $wk-font-medium;
  399. padding: 18rpx 0;
  400. @include left;
  401. .prev-badge {
  402. width: 10rpx;
  403. height: 30rpx;
  404. border-radius: 10rpx;
  405. background-color: $theme-color;
  406. margin-right: 15rpx;
  407. }
  408. }
  409. .task-contaienr {
  410. .task-content {
  411. padding-left: 15rpx;
  412. margin-top: -15rpx;
  413. .task-item {
  414. padding: 20rpx 0;
  415. display: flex;
  416. align-items: flex-start;
  417. justify-content: flex-start;
  418. .item-content {
  419. flex: 1;
  420. margin-left: 25rpx;
  421. .required {
  422. color: $error;
  423. }
  424. }
  425. .item-desc {
  426. font-size: $wk-font-sm;
  427. color: $light;
  428. margin-top: 5rpx;
  429. }
  430. }
  431. }
  432. }
  433. .form-container {
  434. .form-content {
  435. margin: -15rpx -30rpx 0 -30rpx;
  436. }
  437. }
  438. .examine-container {
  439. margin: 0 -30rpx;
  440. }
  441. }
  442. .footer-btn-group {
  443. .button {
  444. margin: 0 10rpx;
  445. }
  446. .plain-btn {
  447. color: $theme-color;
  448. border: 1px solid $theme-color;
  449. background-color: white;
  450. }
  451. }
  452. </style>