Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 
 

345 linhas
9.4 KiB

  1. <template>
  2. <view>
  3. <l-label title="流程名称:">{{ taskParam.taskName }}</l-label>
  4. <l-label title="当前操作:">{{ typeText }}{{ type === 'sign' ? '' : ` [${taskParam.name}]` }}</l-label>
  5. <l-organize-picker
  6. v-if="type === 'sign'"
  7. v-model="staff"
  8. title="加签人员"
  9. placeholder="请选择加签人员"
  10. type="user"
  11. required
  12. arrow
  13. />
  14. <!-- 手写签名 canvas 区 -->
  15. <template v-if="Number(taskParam.isSign) === 1">
  16. <view class="cu-form-group"><view class="title">手写签名:</view></view>
  17. <view class="sign-area bg-white">
  18. <canvas
  19. v-if="canvas"
  20. @touchmove="signMove"
  21. @touchstart="signStart($event)"
  22. @touchend="signEnd"
  23. @touchcancel="signEnd"
  24. disable-scroll="true"
  25. canvas-id="sign-canvas"
  26. id="sign-canvas"
  27. class="sign-canvas"
  28. ></canvas>
  29. </view>
  30. <view class="sign-action padding-bottom text-right">
  31. <l-button @click="clearSign" color="red" style="margin-right: 15px;">清空签名板</l-button>
  32. </view>
  33. </template>
  34. <l-textarea v-model="remark" :placeholder="`输入${typeText}意见`" title="审核意见:" />
  35. <!-- 弹层 -->
  36. <l-modal v-model="modal" @close="reviewer = ''" title="指派审核人">
  37. <l-checkbox-picker @input="(e)=>{reviewer = e}" :value="reviewer" :readonly="false" :range="reviewerList"
  38. required title="审核人" />
  39. <l-button @click="userAssign" color="blue" class="block" block>确定指派</l-button>
  40. <l-button @click="()=>{modal = false;reviewer = ''}" line="blue" class="block margin-top-sm" block>取消</l-button>
  41. </l-modal>
  42. <view class="padding margin-top bg-white">
  43. <l-button @click="submit" class="block" size="lg" color="green" block>提交流程{{ typeText }}</l-button>
  44. </view>
  45. </view>
  46. </template>
  47. <script>
  48. import get from 'lodash/get'
  49. let context = null
  50. let touchs = []
  51. export default {
  52. data() {
  53. return {
  54. type: 'sign',
  55. typeText: '',
  56. staff: '',
  57. remark: '',
  58. taskParam: {},
  59. canvas: true,
  60. modal: false,
  61. reviewer: [],
  62. reviewerList: [],
  63. reviewerListId:'',
  64. submitPostData:null,
  65. }
  66. },
  67. async onLoad() {
  68. await this.init()
  69. },
  70. methods: {
  71. // 页面初始化
  72. async init() {
  73. this.taskParam = this.GET_PARAM()
  74. this.type = this.taskParam.type
  75. this.typeText = this.taskParam.type === 'sign' ? '加签' : '审核'
  76. if (Number(this.taskParam.isSign) === 1) {
  77. this.canvasInit()
  78. }
  79. },
  80. // 初始化签名区 canvas
  81. canvasInit() {
  82. this.canvas = true
  83. context = uni.createCanvasContext('sign-canvas')
  84. context.setStrokeStyle('#000')
  85. context.setLineWidth(5)
  86. context.setLineCap('round')
  87. context.setLineJoin('round')
  88. touchs = []
  89. },
  90. // 指派审核人
  91. async userAssign() {
  92. if(!this.reviewer.length){
  93. this.modal = false
  94. this.TOAST('请选择审核人')
  95. return
  96. }
  97. // let formdata = new FormData()
  98. // formdata.append("data",this.taskParam.formreq)
  99. const res = await this.HTTP_POST('learun/adms/newwf/instance', this.taskParam.formreq, `指派审核人时发生错误`)
  100. if(!res){
  101. return
  102. }
  103. this.submitPostData.auditors = JSON.stringify({[this.reviewerListId]:this.reviewer.toString()})
  104. delete this.submitPostData.formreq
  105. // this.submitPostData.auditors[this.reviewerListId] = this.reviewer
  106. // console.log(this.submitPostData)
  107. uni.showLoading({
  108. title: '提交中...'
  109. });
  110. const success = await this.HTTP_POST(
  111. this.type === 'sign' ? 'learun/adms/newwf/sign' : 'learun/adms/newwf/auditors',
  112. this.submitPostData,
  113. `提交[${this.typeText}]时发生错误`
  114. )
  115. if (!success) {
  116. uni.hideLoading();
  117. return
  118. }
  119. this.EMIT('task-list-change')
  120. this.NAV_BACK(2)
  121. uni.hideLoading();
  122. this.TOAST(`已成功提交${this.typeText}`, 'success')
  123. },
  124. newguid() {
  125. return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
  126. var r = Math.random() * 16 | 0,
  127. v = c == 'x' ? r : (r & 0x3 | 0x8);
  128. return v.toString(16);
  129. });
  130. },
  131. // 点击「提交」按钮
  132. async submit() {
  133. if (this.type === 'sign' && !this.staff) {
  134. this.CONFIRM('请补全必填项', '必须指定一个加签用户')
  135. return
  136. }
  137. const postData = {
  138. operationCode: this.taskParam.code,
  139. operationName: this.taskParam.name,
  140. processId: this.taskParam.processId,
  141. taskId: this.taskParam.taskId,
  142. des: this.remark,
  143. formreq: this.taskParam.formreq
  144. }
  145. if (this.type === 'sign') {
  146. postData.userId = this.staff
  147. } else {
  148. postData.auditors = this.taskParam.auditors
  149. }
  150. // 需要手写签名时,将 canvas 导出为 base64 格式
  151. // 各个平台写法均不相同,需要注意
  152. if (Number(this.taskParam.isSign) === 1) {
  153. // H5 平台,canvasToTempFilePath 的结果直接为画布的 base64
  154. // #ifdef H5
  155. const [err, { tempFilePath }] = await uni.canvasToTempFilePath({ canvasId: 'sign-canvas' })
  156. postData.signUrl = tempFilePath
  157. // #endif
  158. // App 平台,canvasToTempFilePath 输出文件,上传后台转为 base64 格式
  159. // #ifdef APP-VUE
  160. const [err, { tempFilePath }] = await uni.canvasToTempFilePath({ canvasId: 'sign-canvas' })
  161. const signBase64 = await this.HTTP_UPLOAD2('/learun/adms/annexes/wxbase64',tempFilePath,{folderId:this.newguid()})
  162. postData.signUrl = 'data:image/png;base64,' + signBase64
  163. // #endif
  164. // 微信小程序,canvasToTempFilePath 输出文件,使用文件管理器以 base64 格式读取文件即可
  165. // #ifdef MP-WEIXIN
  166. const [err, { tempFilePath }] = await uni.canvasToTempFilePath({ canvasId: 'sign-canvas' })
  167. postData.signUrl = 'data:image/png;base64,' + uni.getFileSystemManager().readFileSync(tempFilePath, 'base64')
  168. // #endif
  169. // #ifdef MP-ALIPAY
  170. // 钉钉小程序,context.toTempFilePath 输出文件,上传后台转为 base64 格式
  171. // #ifdef MP-DINGTALK
  172. const filePath = await new Promise((res, rej) => {
  173. context.toTempFilePath({
  174. success: ({ filePath }) => {
  175. res(filePath)
  176. },
  177. fail: () => {
  178. rej()
  179. }
  180. })
  181. })
  182. const signBase64 = await this.HTTP_UPLOAD('/annexes/wxtobase64', filePath)
  183. postData.signUrl = 'data:image/png;base64,' + signBase64
  184. // #endif
  185. // 支付宝小程序,context.toDataURL 直接输出 base64 字符串
  186. // #ifndef MP-DINGTALK
  187. postData.signUrl = await context.toDataURL('image/png', 1)
  188. // #endif
  189. // #endif
  190. }
  191. // 是否需要指派审核人
  192. let isNext = this.taskParam.currentNode.isNext
  193. if (this.taskParam.next == '2') {
  194. isNext = '1';
  195. }
  196. if (isNext == '1') {
  197. let params = {
  198. code: this.taskParam.schemeCode,
  199. processId: this.taskParam.processId,
  200. taskId: this.taskParam.taskId,
  201. nodeId: this.taskParam.currentNode.id,
  202. operationCode: this.taskParam.code,
  203. }
  204. const userList = await this.HTTP_GET('learun/adms/newwf/auditer', params, `获取审核人时发生错误`)
  205. if (!userList) {
  206. return
  207. }
  208. let arr = Object.entries(userList)
  209. this.reviewerListId = arr[0][0]
  210. this.reviewerList = arr[0][1].map(item => {
  211. return {
  212. text: item.Name,
  213. value: item.Id
  214. }
  215. })
  216. this.submitPostData = postData
  217. if(this.reviewerList.length>1){
  218. this.modal = true
  219. return
  220. }
  221. }
  222. const success = await this.HTTP_POST(
  223. this.type === 'sign' ? 'learun/adms/newwf/sign' : 'learun/adms/newwf/audit',
  224. postData,
  225. `提交[${this.typeText}]时发生错误`
  226. )
  227. if (!success) {
  228. return
  229. }
  230. this.EMIT('task-list-change')
  231. this.NAV_BACK(2)
  232. this.TOAST(`已成功提交${this.typeText}`, 'success')
  233. },
  234. // 手写板事件(开始拖动)
  235. signStart(e) {
  236. touchs.push({
  237. x: e.changedTouches[0].x,
  238. y: e.changedTouches[0].y
  239. })
  240. },
  241. // 手写板事件(拖动签名)
  242. signMove(e) {
  243. touchs.push({
  244. x: e.touches[0].x,
  245. y: e.touches[0].y
  246. })
  247. this.drawLine()
  248. },
  249. // 手写板事件(签名结束)
  250. signEnd(e) {
  251. touchs = []
  252. },
  253. // 手写板事件(绘出线型)
  254. drawLine() {
  255. if (touchs.length < 2) {
  256. return
  257. }
  258. const [p1, p2] = touchs
  259. touchs.shift()
  260. context.moveTo(p1.x, p1.y)
  261. context.lineTo(p2.x, p2.y)
  262. context.stroke()
  263. context.draw(true)
  264. },
  265. // 清除手写板
  266. // 阿里小程序无法使用 clearRect 来清空,因此直接重新渲染 canvas
  267. clearSign() {
  268. // #ifndef MP-ALIPAY
  269. context.clearRect(0, 0, 9999, 9999)
  270. context.draw()
  271. context.setStrokeStyle('#000')
  272. context.setLineWidth(5)
  273. context.setLineCap('round')
  274. context.setLineJoin('round')
  275. // #endif
  276. // #ifdef MP-ALIPAY
  277. // 阿里系小程序无法 clearRect 清空画布,必须重新渲染 canvas
  278. this.canvas = false
  279. this.$nextTick(() => {
  280. this.canvasInit()
  281. })
  282. // #endif
  283. }
  284. }
  285. }
  286. </script>
  287. <style lang="less" scoped>
  288. .sign-area {
  289. min-height: 500rpx;
  290. margin: 23rpx;
  291. border: 2rpx dashed #444444;
  292. .sign-canvas {
  293. width: 700rpx;
  294. height: 500rpx;
  295. }
  296. .sign-action {
  297. text-align: right;
  298. }
  299. }
  300. </style>