TaskForm.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. <template>
  2. <view>
  3. <u-subsection
  4. :list="procInsId?['表单信息', '流转记录']:['表单信息']"
  5. mode="button"
  6. :fontSize="16"
  7. :current="tabIndex"
  8. @change="tabSelect"
  9. ></u-subsection>
  10. <view v-show="0 === tabIndex">
  11. <scroll-view scroll-y>
  12. <view class=" bg-white ">
  13. <TestActivitiLeaveForm v-if="formUrl.endsWith('TestActivitiLeaveForm')" :formReadOnly="formReadOnly" :class="formReadOnly?'readonly':''" ref="form" :businessId="businessId"></TestActivitiLeaveForm>
  14. <DisposeRubbishForm v-if="formUrl.endsWith('DisposeRubbishForm')" :formReadOnly="formReadOnly" :class="formReadOnly?'readonly':''" ref="form" :businessId="businessId"></DisposeRubbishForm>
  15. <!-- <component :formReadOnly="formReadOnly" :class="formReadOnly?'readonly':''" ref="form" :businessId="businessId" :is="form"></component> -->
  16. <PreviewForm :formData="formData" v-if="formType !== '2'" :processDefinitionId="procDefId" :edit="true" ref="form"></PreviewForm>
  17. </view>
  18. <view class=" bg-white margin-top" v-if="!procInsId || taskId">
  19. <u--form :model="auditForm" labelWidth="130px" class="u-form" labelPosition="left" :rules="rules" ref="auditForm">
  20. <u-form-item v-if="!procInsId" label="流程标题" borderBottom prop="title">
  21. <u--input v-model="title" placeholder="请输入流程标题" border="none"></u--input>
  22. </u-form-item>
  23. <u-form-item v-if="taskId" label="审批意见" borderBottom prop="message">
  24. <u--textarea v-model="auditForm.message" placeholder="请输入审批意见" border="none"></u--textarea>
  25. </u-form-item>
  26. <!--<u-form-item label="是否抄送" borderBottom prop="isCC">
  27. <u-switch v-model="isCC" ></u-switch>
  28. </u-form-item>
  29. <u-form-item label="抄送给" v-if="isCC">
  30. <user-select v-model="auditForm.userIds" ></user-select>
  31. </u-form-item>
  32. <u-form-item label="指定下一步处理者" borderBottom prop="isAssign">
  33. <u-switch v-model="isAssign" ></u-switch>
  34. </u-form-item>
  35. <u-form-item label="指定" v-if="isAssign">
  36. <user-select v-model="auditForm.assignee" ></user-select>
  37. </u-form-item>-->
  38. <user-select-dialog title="选择转办用户" ref="transferUserSelectDialog" :showRadio="true" :showCheckBox="false" @doSubmit="selectUsersToTransferTask"></user-select-dialog>
  39. <user-select-dialog title="选择委派用户" ref="delegateUserSelectDialog" :showRadio="true" :showCheckBox="false" @doSubmit="selectUsersToDelateTask"></user-select-dialog>
  40. <user-select-dialog title="选择加签用户" ref="addSignTaskUserSelectDialog" @doSubmit="selectUsersToAddSignTask"></user-select-dialog>
  41. <task-back-nodes ref="taskBackNodes" @getBackTaskDefKey="back"></task-back-nodes>
  42. <view class="bottom-wrap flex">
  43. <view class="flex-sub" v-show="button.isHide === '0'"
  44. v-for="(button, index) in buttons" :key="index" >
  45. <u-button type="primary" class=" buttonBox" :color="colors[index]" @click="submit(button, buttons)" :text="button.name"></u-button>
  46. </view>
  47. </view>
  48. </u--form>
  49. </view>
  50. <u-gap height="70"></u-gap>
  51. </scroll-view>
  52. </view>
  53. <view v-show="1 === tabIndex">
  54. <view class="padding bg-white">
  55. <view class="cu-timeline" :key="index" v-for="(act, index) in historicTaskList">
  56. <view class="cu-time">{{act.histIns.startTime |formatDate('MM-DD')}}</view>
  57. <view class="cu-item text-blue">
  58. <view class="content">
  59. <view class="cu-capsule radius">
  60. <view class="cu-tag bg-cyan">{{act.histIns.activityName}}</view>
  61. <!-- <view class="cu-tag line-cyan">{{act.histIns.activityName}}</view> -->
  62. </view>
  63. <view class="margin-top">
  64. 审批人 : {{act.assigneeName}}
  65. </view>
  66. <view class="margin-top">
  67. 办理状态 :<view class="cu-tag bg-blue">{{act.comment.status}}</view>
  68. </view>
  69. <view class="margin-top">
  70. 审批意见 : {{act.comment.message}}
  71. </view>
  72. <view class="margin-top">
  73. 开始时间 : {{act.histIns.startTime |formatDate}}
  74. </view>
  75. <view class="margin-top">
  76. 结束时间 : {{act.histIns.endTime |formatDate}}
  77. </view>
  78. <view class="margin-top">
  79. 用时 : {{act.durationTime || '0秒'}}
  80. </view>
  81. </view>
  82. </view>
  83. </view>
  84. </view>
  85. </view>
  86. </view>
  87. </template>
  88. <script>
  89. import userSelect from '@/components/user-select/user-select.vue'
  90. import userSelectDialog from '@/components/user-select/user-select-dialog.vue'
  91. import PreviewForm from '../form/GenerateFlowableForm'
  92. import TaskBackNodes from './components/TaskBackNodes.vue'
  93. import TestActivitiLeaveForm from '@/pages/test/activiti/TestActivitiLeaveForm.vue'
  94. import DisposeRubbishForm from '@/pages/edt/DisposeRubbishForm.vue'
  95. import moment from 'moment'
  96. import taskService from "@/api/flowable/taskService"
  97. import formService from "@/api/flowable/formService"
  98. import processService from "@/api/flowable/processService"
  99. import flowCopyService from "@/api/flowable/flowCopyService"
  100. import taskDefExtensionService from "@/api/flowable/taskDefExtensionService"
  101. var graceChecker = require("@/common/graceChecker.js");
  102. export default {
  103. onLoad: function (option) {
  104. this.flow = JSON.parse(decodeURIComponent(option.flow));
  105. this.procDefId = this.flow.procDefId
  106. this.procDefKey = this.flow.procDefKey
  107. this.formType = this.flow.formType
  108. this.formUrl = this.flow.formUrl
  109. this.taskId = this.flow.taskId
  110. this.taskDefKey = this.flow.taskDefKey
  111. this.status = this.flow.status
  112. this.title = this.flow.formTitle
  113. this.businessId = this.flow.businessId
  114. this.procInsId = this.flow.procInsId
  115. this.formReadOnly = this.flow.formReadOnly !== undefined && this.flow.formReadOnly !== 'false' && this.flow.formReadOnly !== false
  116. this.isCC = false
  117. this.isAssign = false
  118. this.auditForm.assignee = null
  119. this.auditForm.userIds = null
  120. this.auditForm.message = ''
  121. uni.setNavigationBarTitle({
  122. title: this.title
  123. });
  124. },
  125. async mounted () {
  126. if (this.formType === '2') { //外置表单
  127. if (this.formUrl === '/404') {
  128. this.form = null
  129. uni.showToast({ title: '没有关联流程表单!', icon: "none" });
  130. } else {
  131. // uniapp 不支持动态组件,所以通过名称匹配决定调用的表单组件
  132. if(this.formUrl.endsWith('TestActivitiLeaveForm')){
  133. this.form = TestActivitiLeaveForm
  134. }
  135. // uniapp 不支持动态组件,所以通过名称匹配决定调用的表单组件
  136. if(this.formUrl.endsWith('DisposeRubbishForm')){
  137. this.form = DisposeRubbishForm
  138. }else{
  139. uni.showToast({ title: '没有关联流程表单!', icon: "none" });
  140. }
  141. }
  142. } else { // 动态表单
  143. // 读取流程表单
  144. if (this.formUrl === '/404') {
  145. uni.showToast({ title: '没有关联流程表单!', icon: "none" });
  146. } else {
  147. let data = await formService.getMobileForm(this.formUrl);
  148. // 初始化动态表单
  149. data.forEach((item)=>{ //挂载 writable,readable,value 属性,是为了触发对这三个属性的监听
  150. item.writable = true
  151. item.readable = true
  152. if(this.isObjectValue(item)){
  153. item.value = null
  154. }else{
  155. item.value = ''
  156. }
  157. let input = JSON.parse(JSON.stringify(item))
  158. this.formData.push(input)
  159. })
  160. if (this.status === 'start') {
  161. // 读取启动表单配置
  162. let data = await formService.getStartFormData({processDefinitionId: this.procDefId})
  163. this.setData(data, 'start')
  164. } else {
  165. // 读取任务表单配置
  166. let data = await formService.getTaskFormData({taskId: this.taskId})
  167. this.setData(data, 'audit')
  168. }
  169. }
  170. }
  171. // 读取按钮配置
  172. if (this.status === 'start') {
  173. this.buttons = [{code: '_flow_start', name: '启动', isHide: '0'}]
  174. } else if (this.procDefKey && this.taskDefKey) {
  175. // 读取按钮
  176. taskDefExtensionService.queryByDefIdAndTaskId({
  177. processDefId: this.procDefKey,
  178. taskDefId: this.taskDefKey
  179. }).then((data) => {
  180. this.buttons = data.flowButtonList
  181. })
  182. }
  183. // 读取历史任务列表
  184. taskService.historicTaskList(this.procInsId).then((data) => {
  185. this.historicTaskList = data.reverse()
  186. })
  187. },
  188. components:{
  189. userSelect,
  190. userSelectDialog,
  191. TestActivitiLeaveForm,
  192. DisposeRubbishForm,
  193. TaskBackNodes,
  194. PreviewForm
  195. },
  196. data() {
  197. return {
  198. flow: null,
  199. tabIndex: 0,
  200. form: null,
  201. formType: '',
  202. formUrl: '',
  203. taskSelectedTab: 'frist',
  204. historicTaskList: [],
  205. procDefId: '',
  206. procInsId: '',
  207. formReadOnly: false,
  208. procDefKey: '',
  209. taskId: '',
  210. formData: [],
  211. taskDefKey: '',
  212. status: '',
  213. title: '',
  214. businessId: '',
  215. buttons: [],
  216. isCC: false,
  217. isAssign: false,
  218. colors: [ '#3c9cff', '#f56c6c', '#5ac725', '#f9ae3d', '#89c152',
  219. '#c38cc1', '#448aca', '#73d1f1', '#ffb34b', '#f18080',
  220. '#88a867', '#bfbf39', '#94d554', '#f19ec2', '#afaae4',
  221. '#86cefa', '#98d1ee', '#72dcdc', '#9acdcb', '#77b1cc', '#80a7dc'
  222. ],
  223. auditForm: {
  224. message: '',
  225. type: '',
  226. status: '',
  227. userIds: null,
  228. assignee: null
  229. },
  230. rules: {
  231. 'title': [
  232. {
  233. required: true,
  234. message: '流程标题',
  235. trigger: ['blur', 'change']
  236. }
  237. ],
  238. 'messsage': [
  239. {
  240. required: true,
  241. message: '审批内容',
  242. trigger: ['blur', 'change']
  243. }
  244. ]
  245. }
  246. }
  247. },
  248. methods:{
  249. tabSelect (index) {
  250. this.tabIndex = index
  251. },
  252. // 为任务表单赋值
  253. setData (taskFormData, status) {
  254. this.formData.forEach((input)=>{
  255. let item = taskFormData.filter((item)=>{
  256. if(input.model === item.id){
  257. return true
  258. }else{
  259. return false
  260. }
  261. })[0]
  262. if(item){
  263. if(status === 'start'){
  264. this.isFixParam(input)
  265. if(this.isObjectValue(input)){
  266. if(input.options.defaultValue && typeof input.options.defaultValue=== 'string'){
  267. input.value = JSON.parse(input.options.defaultValue)
  268. }else{
  269. input.value = input.options.defaultValue
  270. }
  271. }else{
  272. input.value = input.options.defaultValue || ''
  273. }
  274. }else{
  275. if(this.isObjectValue(input)){
  276. if(item.value && typeof item.value=== 'string'){
  277. input.value = JSON.parse(item.value)
  278. }else {
  279. input.value = item.value
  280. }
  281. }else{
  282. input.value = item.value
  283. }
  284. }
  285. input.readable = item.readable
  286. input.writable = item.writable
  287. }else{
  288. input.readable = false
  289. }
  290. })
  291. },
  292. // 默认参数赋值替换 ${user.name}...
  293. isFixParam (input) {
  294. if(/^[$][{].*[}]$/.test(input.options.defaultValue)){
  295. let params = input.options.defaultValue.substring(2, input.options.defaultValue.length-1)
  296. if(params === "new Date()"){
  297. input.options.defaultValue = moment(new Date()).format('YYYY-MM-DD HH:mm:ss')
  298. }else{
  299. let value = {user: this.$store.state.user.userInfo}
  300. params.split('.').forEach((param)=>{
  301. value = value?.[param]
  302. })
  303. input.options.defaultValue = value
  304. }
  305. }
  306. },
  307. // 判断数据类型是否是非String类型
  308. isObjectValue (input) {
  309. if(input.type === 'checkbox' ||
  310. input.type === 'slider' ||
  311. input.type === 'switch' ||
  312. input.type === 'rate' ||
  313. input.type === 'fileupload' ||
  314. input.type === 'imgupload' ||
  315. input.type === 'select' && input.options.multiple ){
  316. return true
  317. }
  318. return false
  319. },
  320. // 抄送
  321. cc (procInsId) {
  322. if (this.isCC && this.auditForm.userIds) {
  323. flowCopyService.save({
  324. userIds: this.auditForm.userIds,
  325. procDefId: this.procDefId,
  326. procInsId: procInsId,
  327. procDefName: '',
  328. procInsName: this.title,
  329. taskName: ''
  330. })
  331. }
  332. },
  333. // 暂存草稿
  334. save () {
  335. },
  336. // 启动流程
  337. start (vars) {
  338. if (this.formType === '2') { // 外置表单启动
  339. this.$refs.form.saveForm((businessTable, businessId) => {
  340. taskService.start({
  341. procDefKey: this.procDefKey,
  342. businessTable: businessTable,
  343. businessId: businessId,
  344. ...vars,
  345. title: this.title,
  346. assignee: this.auditForm.assignee
  347. }).then((data) => {
  348. uni.showToast({ title: "启动成功", icon: "success" });
  349. uni.navigateTo({
  350. url: '/pages/workbench/task/TodoList'
  351. })
  352. this.cc(data)
  353. })
  354. })
  355. } else { //动态表单启动
  356. this.$refs.form.submitStartFormData({
  357. processDefinitionId: this.procDefId,
  358. ...vars,
  359. title: this.title,
  360. assignee: this.auditForm.assignee
  361. }, (data) => {
  362. uni.showToast({ title: "启动成功", icon: "success" });
  363. uni.navigateTo({
  364. url: '/pages/workbench/task/TodoList'
  365. })
  366. this.cc(data)
  367. })
  368. }
  369. },
  370. // 同意
  371. agree () {
  372. this.commit() // 同意
  373. },
  374. // 驳回
  375. reject () {
  376. uni.showModal({
  377. title: '提示',
  378. content: '确定驳回流程吗?',
  379. success: (res) => {
  380. if (res.confirm) {
  381. uni.showLoading()
  382. taskService.backNodes(this.taskId).then((data) => {
  383. let backNodes = data
  384. if (backNodes.length > 0) {
  385. let backTaskDefKey = backNodes[backNodes.length - 1].taskDefKey
  386. this.back(backTaskDefKey)
  387. }
  388. })
  389. } else if (res.cancel) {
  390. uni.hideLoading()
  391. }
  392. }
  393. });
  394. },
  395. // 驳回到任意节点
  396. turnBack () {
  397. this.$refs.taskBackNodes.init(this.taskId)
  398. },
  399. // 回退到任意节点
  400. back (backTaskDefKey) {
  401. taskService.back({
  402. taskId: this.taskId,
  403. backTaskDefKey: backTaskDefKey,
  404. ...this.auditForm
  405. }).then((data) => {
  406. uni.showToast({ title: "驳回成功", icon: "success" });
  407. uni.navigateTo({
  408. url: '/pages/workbench/task/TodoList'
  409. })
  410. this.cc(data)
  411. })
  412. },
  413. // 加签
  414. addMultiInstance () {
  415. // this.$refs.addSignTaskUserSelectDialog.showModal()
  416. },
  417. selectUsersToAddSignTask (users) {
  418. let userIds = users.map((user) => {
  419. return user.id
  420. }).join(',')
  421. taskService.addSignTask({taskId: this.taskId, userIds: JSON.stringify(userIds), message: '', flag: false}).then((data) => {
  422. uni.showToast({ title: data, icon: "success" });
  423. })
  424. },
  425. // 减签
  426. delMultiInstance () {
  427. },
  428. // 转办
  429. transfer () {
  430. this.$refs.transferUserSelectDialog.showModal()
  431. },
  432. selectUsersToTransferTask (userId) {
  433. alert(userId)
  434. if(!userId){
  435. uni.showToast({ title: '没有选择任何用户!', icon: "none" });
  436. return
  437. }
  438. taskService.transfer(this.taskId, userId).then((data) => {
  439. uni.showToast({ title: data, icon: "success" });
  440. uni.navigateTo({
  441. url: '/pages/workbench/task/TodoList'
  442. })
  443. })
  444. },
  445. // 委托
  446. delegate () {
  447. this.$refs.delegateUserSelectDialog.showModal()
  448. },
  449. selectUsersToDelateTask (userId) {
  450. if(!userId){
  451. uni.showToast({ title: '没有选择任何用户!', icon: "none" });
  452. return
  453. }
  454. taskService.delegate(this.taskId, userId).then((data) => {
  455. uni.showToast({ title: data, icon: "success" });
  456. uni.navigateTo({
  457. url: '/pages/workbench/task/TodoList'
  458. })
  459. })
  460. },
  461. // 终止
  462. stop () {
  463. uni.showLoading()
  464. uni.showModal({
  465. title: '提示',
  466. content: '确定终止流程吗?',
  467. success: (res) => {
  468. if (res.confirm) {
  469. processService.stop(this.procInsId, this.auditForm.message).then((data) => {
  470. uni.showToast({ title: data, icon: "success" });
  471. uni.navigateTo({
  472. url: '/pages/workbench/task/TodoList'
  473. })
  474. })
  475. } else if (res.cancel) {
  476. uni.hideLoading()
  477. }
  478. }
  479. });
  480. },
  481. // 打印
  482. print () {
  483. },
  484. // 自定义按钮提交
  485. commit (vars) {
  486. //定义表单规则
  487. var rule = [
  488. {name:"message", checkType : "notnull", checkRule:"", errorMsg:"审批意见不能为空!"}
  489. ];
  490. //进行表单检查
  491. var formData = this.auditForm;
  492. var checkRes = graceChecker.check(formData, rule);
  493. if(!checkRes){
  494. uni.showToast({ title: graceChecker.error, icon: "none" });
  495. return;
  496. }
  497. if (this.formType === '2') { //外置表单审批
  498. this.$refs.form.saveForm((businessTable, businessId) => {
  499. taskService.audit({
  500. taskId: this.taskId,
  501. taskDefKey: this.taskDefKey,
  502. procInsId: this.procInsId,
  503. procDefId: this.procDefId,
  504. vars: vars,
  505. comment: this.auditForm,
  506. assignee: this.auditForm.assignee
  507. }).then((data) => {
  508. uni.showToast({ title: "审批成功", icon: "success" });
  509. uni.navigateTo({
  510. url: '/pages/workbench/task/TodoList'
  511. })
  512. this.cc(data)
  513. })
  514. })
  515. } else { // 动态表单启动
  516. this.$refs.form.submitTaskFormData(vars, this.procInsId, this.taskId, this.auditForm.assignee, this.auditForm, (data) => {
  517. uni.showToast({ title: "启动成功", icon: "success" });
  518. uni.navigateTo({
  519. url: '/pages/workbench/task/TodoList'
  520. })
  521. //抄送
  522. this.cc(data)
  523. })
  524. }
  525. },
  526. submit (currentBtn, buttons) {
  527. let vars = {} // 存储流程变量
  528. // 把当前操作对应的自定义按钮(以_flow_开头的是系统按钮,排除在外)的编码,存储为对应的流程变量,值设置为true,其余自定义按钮编码对应的流程变量值为false。
  529. buttons.forEach((btn) => {
  530. if (btn.code && !btn.code.startsWith('_flow_')) {
  531. vars[btn.code] = false
  532. }
  533. })
  534. if (currentBtn.code && !currentBtn.code.startsWith('_flow_')) {
  535. vars[currentBtn.code] = true
  536. }
  537. vars.title = this.title // 标题
  538. vars.assignee = this.auditForm.assignee // 指定的下一步骤处理人
  539. this.auditForm.type = currentBtn.code // 提交类型
  540. this.auditForm.status = currentBtn.name // 按钮文字
  541. switch (currentBtn.code) {
  542. case '_flow_start': // 自动流程
  543. this.start(vars)
  544. break
  545. case '_flow_save': // 保存草稿
  546. this.save()
  547. break
  548. case '_flow_agree': // 同意
  549. this.agree()
  550. break
  551. case '_flow_reject': // 驳回
  552. this.reject()
  553. break
  554. case '_flow_back': // 驳回到任意步骤
  555. this.turnBack()
  556. break
  557. case '_flow_add_multi_instance': // 加签
  558. this.addMultiInstance()
  559. break
  560. case '_flow_del_multi_instance': // 减签
  561. this.delMultiInstance()
  562. break
  563. case '_flow_transfer': // 转办
  564. this.transfer()
  565. break
  566. case '_flow_delegate':// 外派
  567. this.delegate()
  568. break
  569. case '_flow_stop':// 终止
  570. this.stop()
  571. break
  572. case '_flow_print':// 打印
  573. this.print()
  574. break
  575. default:
  576. this.commit(vars) // 自定义按钮提交
  577. }
  578. }
  579. }
  580. }
  581. </script>