You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

250 lines
6.7 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. <view class="padding margin-top bg-white">
  36. <l-button @click="submit" class="block" size="lg" color="green" block>提交流程{{ typeText }}</l-button>
  37. </view>
  38. </view>
  39. </template>
  40. <script>
  41. import get from 'lodash/get'
  42. let context = null
  43. let touchs = []
  44. export default {
  45. data() {
  46. return {
  47. type: 'sign',
  48. typeText: '',
  49. staff: '',
  50. remark: '',
  51. taskParam: {},
  52. canvas: true
  53. }
  54. },
  55. async onLoad() {
  56. await this.init()
  57. },
  58. methods: {
  59. // 页面初始化
  60. async init() {
  61. this.taskParam = this.GET_PARAM()
  62. this.type = this.taskParam.type
  63. this.typeText = this.taskParam.type === 'sign' ? '加签' : '审核'
  64. if (Number(this.taskParam.isSign) === 1) {
  65. this.canvasInit()
  66. }
  67. },
  68. // 初始化签名区 canvas
  69. canvasInit() {
  70. this.canvas = true
  71. context = uni.createCanvasContext('sign-canvas')
  72. context.setStrokeStyle('#000')
  73. context.setLineWidth(5)
  74. context.setLineCap('round')
  75. context.setLineJoin('round')
  76. touchs = []
  77. },
  78. // 点击「提交」按钮
  79. async submit() {
  80. if (this.type === 'sign' && !this.staff) {
  81. this.CONFIRM('请补全必填项', '必须指定一个加签用户')
  82. return
  83. }
  84. const postData = {
  85. operationCode: this.taskParam.code,
  86. operationName: this.taskParam.name,
  87. processId: this.taskParam.processId,
  88. taskId: this.taskParam.taskId,
  89. des: this.remark,
  90. formreq: this.taskParam.formreq
  91. }
  92. if (this.type === 'sign') {
  93. postData.userId = this.staff
  94. } else {
  95. postData.auditors = this.taskParam.auditors
  96. }
  97. // 需要手写签名时,将 canvas 导出为 base64 格式
  98. // 各个平台写法均不相同,需要注意
  99. if (Number(this.taskParam.isSign) === 1) {
  100. // H5 平台,canvasToTempFilePath 的结果直接为画布的 base64
  101. // #ifdef H5
  102. const [err, { tempFilePath }] = await uni.canvasToTempFilePath({ canvasId: 'sign-canvas' })
  103. postData.signUrl = tempFilePath
  104. // #endif
  105. // App 平台,canvasToTempFilePath 输出文件,上传后台转为 base64 格式
  106. // #ifdef APP-VUE
  107. const [err, { tempFilePath }] = await uni.canvasToTempFilePath({ canvasId: 'sign-canvas' })
  108. const signBase64 = await this.HTTP_UPLOAD('/annexes/wxtobase64', tempFilePath)
  109. postData.signUrl = 'data:image/png;base64,' + signBase64
  110. // #endif
  111. // 微信小程序,canvasToTempFilePath 输出文件,使用文件管理器以 base64 格式读取文件即可
  112. // #ifdef MP-WEIXIN
  113. const [err, { tempFilePath }] = await uni.canvasToTempFilePath({ canvasId: 'sign-canvas' })
  114. postData.signUrl = 'data:image/png;base64,' + uni.getFileSystemManager().readFileSync(tempFilePath, 'base64')
  115. // #endif
  116. // #ifdef MP-ALIPAY
  117. // 钉钉小程序,context.toTempFilePath 输出文件,上传后台转为 base64 格式
  118. // #ifdef MP-DINGTALK
  119. const filePath = await new Promise((res, rej) => {
  120. context.toTempFilePath({
  121. success: ({ filePath }) => {
  122. res(filePath)
  123. },
  124. fail: () => {
  125. rej()
  126. }
  127. })
  128. })
  129. const signBase64 = await this.HTTP_UPLOAD('/annexes/wxtobase64', filePath)
  130. postData.signUrl = 'data:image/png;base64,' + signBase64
  131. // #endif
  132. // 支付宝小程序,context.toDataURL 直接输出 base64 字符串
  133. // #ifndef MP-DINGTALK
  134. postData.signUrl = await context.toDataURL('image/png', 1)
  135. // #endif
  136. // #endif
  137. }
  138. const success = await this.HTTP_POST(
  139. this.type === 'sign' ? 'learun/adms/newwf/sign' : 'learun/adms/newwf/audit',
  140. postData,
  141. `提交[${this.typeText}]时发生错误`
  142. )
  143. if (!success) {
  144. return
  145. }
  146. this.EMIT('task-list-change')
  147. this.NAV_BACK(2)
  148. this.TOAST(`已成功提交${this.typeText}`, 'success')
  149. },
  150. // 手写板事件(开始拖动)
  151. signStart(e) {
  152. touchs.push({
  153. x: e.changedTouches[0].x,
  154. y: e.changedTouches[0].y
  155. })
  156. },
  157. // 手写板事件(拖动签名)
  158. signMove(e) {
  159. touchs.push({
  160. x: e.touches[0].x,
  161. y: e.touches[0].y
  162. })
  163. this.drawLine()
  164. },
  165. // 手写板事件(签名结束)
  166. signEnd(e) {
  167. touchs = []
  168. },
  169. // 手写板事件(绘出线型)
  170. drawLine() {
  171. if (touchs.length < 2) {
  172. return
  173. }
  174. const [p1, p2] = touchs
  175. touchs.shift()
  176. context.moveTo(p1.x, p1.y)
  177. context.lineTo(p2.x, p2.y)
  178. context.stroke()
  179. context.draw(true)
  180. },
  181. // 清除手写板
  182. // 阿里小程序无法使用 clearRect 来清空,因此直接重新渲染 canvas
  183. clearSign() {
  184. // #ifndef MP-ALIPAY
  185. context.clearRect(0, 0, 9999, 9999)
  186. context.draw()
  187. context.setStrokeStyle('#000')
  188. context.setLineWidth(5)
  189. context.setLineCap('round')
  190. context.setLineJoin('round')
  191. // #endif
  192. // #ifdef MP-ALIPAY
  193. // 阿里系小程序无法 clearRect 清空画布,必须重新渲染 canvas
  194. this.canvas = false
  195. this.$nextTick(() => {
  196. this.canvasInit()
  197. })
  198. // #endif
  199. }
  200. }
  201. }
  202. </script>
  203. <style lang="less" scoped>
  204. .sign-area {
  205. min-height: 500rpx;
  206. margin: 23rpx;
  207. border: 2rpx dashed #444444;
  208. .sign-canvas {
  209. width: 700rpx;
  210. height: 500rpx;
  211. }
  212. .sign-action {
  213. text-align: right;
  214. }
  215. }
  216. </style>