index.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. // pages/sign/index.js
  2. var canvas = null;
  3. const app = getApp()
  4. Page({
  5. /**
  6. * 页面的初始数据
  7. */
  8. data: {
  9. id:'',
  10. ctx: null,
  11. points: [], // 存储所有笔画
  12. currentStroke: [], // 当前笔画
  13. isDrawing: false,
  14. },
  15. /**
  16. * 生命周期函数--监听页面加载
  17. */
  18. onLoad(options) {
  19. this.setData({
  20. id:options.id
  21. })
  22. this.initCanvas();
  23. },
  24. /**
  25. * 初始化画布
  26. * 设置画布大小、像素比例和画笔样式
  27. */
  28. async initCanvas() {
  29. let that = this
  30. // 使用ID获取canvas组件实例
  31. const query = wx.createSelectorQuery();
  32. query.select('#canvas')
  33. .fields({ node: true, size: true })
  34. .exec((res) => {
  35. canvas = res[0].node;
  36. const ctx = canvas.getContext('2d');
  37. // Canvas 画布的实际绘制宽高
  38. const width = res[0].width
  39. const height = res[0].height
  40. // 设置画布大小,使用新的API获取设备像素比
  41. const dpr = wx.getWindowInfo().pixelRatio;
  42. //这里设置宽高,为了测试图片清晰度S
  43. that.setData({
  44. canvasWidth:width,
  45. canvasHeight:height,
  46. dpr:dpr
  47. })
  48. //这里设置宽高,为了测试图片清晰度E
  49. canvas.width = width * dpr;
  50. canvas.height = height * dpr;
  51. ctx.scale(dpr, dpr);
  52. // 设置画笔样式
  53. ctx.strokeStyle = '#000000';
  54. ctx.lineWidth = 3;
  55. ctx.lineCap = 'round';
  56. ctx.lineJoin = 'round';
  57. //绘制背景
  58. ctx.fillStyle = '#fff'
  59. ctx.clearRect(0, 0, canvas.width, canvas.height)
  60. ctx.fillRect(0, 0, canvas.width, canvas.height)
  61. this.setData({ ctx });
  62. });
  63. },
  64. /**
  65. * 处理触摸开始事件
  66. * 开始一个新的笔画,记录起始点
  67. * @param {Object} e - 触摸事件对象
  68. */
  69. handleTouchStart(e) {
  70. const { x, y } = e.touches[0];
  71. this.setData({
  72. isDrawing: true,
  73. currentStroke: [[x, y]]
  74. });
  75. this.data.ctx.beginPath();
  76. this.data.ctx.moveTo(x, y);
  77. },
  78. /**
  79. * 处理触摸移动事件
  80. * 继续绘制当前笔画的路径
  81. * @param {Object} e - 触摸事件对象
  82. */
  83. handleTouchMove(e) {
  84. if (!this.data.isDrawing) return;
  85. const { x, y } = e.touches[0];
  86. this.data.currentStroke.push([x, y]);
  87. this.data.ctx.lineTo(x, y);
  88. this.data.ctx.stroke();
  89. },
  90. /**
  91. * 处理触摸结束事件
  92. * 完成当前笔画,将其添加到笔画历史中
  93. */
  94. handleTouchEnd() {
  95. if (!this.data.isDrawing) return;
  96. this.setData({
  97. isDrawing: false,
  98. points: [...this.data.points, this.data.currentStroke],
  99. currentStroke: []
  100. });
  101. },
  102. /**
  103. * 清除画布内容
  104. * 清空所有笔画记录和画布显示
  105. */
  106. handleClear() {
  107. const { ctx } = this.data;
  108. ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  109. this.setData({ points: [] });
  110. },
  111. /**
  112. * 撤销上一步操作
  113. * 移除最后一笔,并重绘剩余的笔画
  114. */
  115. handleUndo() {
  116. if (this.data.points.length === 0) return;
  117. const { ctx } = this.data;
  118. ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  119. // 移除最后一笔
  120. const newPoints = this.data.points.slice(0, -1);
  121. this.setData({ points: newPoints });
  122. // 重绘所有笔画
  123. newPoints.forEach(stroke => {
  124. ctx.beginPath();
  125. ctx.moveTo(stroke[0][0], stroke[0][1]);
  126. stroke.forEach(([x, y]) => {
  127. ctx.lineTo(x, y);
  128. });
  129. ctx.stroke();
  130. });
  131. },
  132. /**
  133. * 提交签名
  134. * 将画布内容转换为图片并处理提交逻辑
  135. * @returns {Promise<void>}
  136. */
  137. async handleSubmit() {
  138. let that = this
  139. if (this.data.points.length === 0) {
  140. wx.showToast({
  141. title: '请先签名',
  142. icon: 'none'
  143. });
  144. return;
  145. }
  146. try {
  147. // 将画布内容转换为图片
  148. const tempFilePath = await new Promise((resolve, reject) => {
  149. let { canvasWidth, canvasHeight, dpr } = that.data
  150. wx.canvasToTempFilePath({
  151. canvas: canvas,
  152. destWidth:canvasWidth * dpr,
  153. destHeight:canvasHeight * dpr,
  154. success: res => resolve(res.tempFilePath),
  155. fail: reject
  156. });
  157. });
  158. // 这里可以处理签名图片,比如上传到服务器
  159. console.log('签名图片路径:', tempFilePath);
  160. // 将图片转为 Base64
  161. that.imageToBase64(tempFilePath, function (error, base64String) {
  162. if (error) {
  163. return;
  164. }
  165. console.log(base64String)
  166. that.setData({
  167. signature: base64String
  168. })
  169. let formData = {
  170. id:that.data.id,
  171. orderSign:base64String
  172. }
  173. // 上传 Base64 编码的图片,订单签名
  174. app.request.POST({
  175. url: app.API.orderSign,
  176. params: formData,
  177. page: that,
  178. isLoadingTxt: '提交中...',
  179. isSubmitting: true,
  180. successFun: true
  181. }).then(res => {
  182. wx.showToast({
  183. title: '确认成功',
  184. icon: 'success',
  185. duration: 2000,
  186. mask:true,
  187. complete: function () {
  188. setTimeout(() => {
  189. wx.navigateBack()
  190. }, 1500) //延迟时间
  191. }
  192. })
  193. })
  194. //that.selfConfirm(base64String);
  195. });
  196. // wx.showToast({
  197. // title: '提交成功',
  198. // icon: 'success'
  199. // });
  200. // // 返回上一页
  201. // setTimeout(() => {
  202. // wx.navigateBack();
  203. // }, 1500);
  204. } catch (error) {
  205. console.error('提交签名失败:', error);
  206. wx.showToast({
  207. title: '提交失败',
  208. icon: 'error'
  209. });
  210. }
  211. },
  212. //图片转baose64
  213. imageToBase64(tempFilePath, callback) {
  214. wx.getFileSystemManager().readFile({
  215. filePath: tempFilePath,
  216. encoding: 'base64',
  217. success: function (res) {
  218. // 拼接与 PC 端一致的格式
  219. var base64Str = "data:image/png;base64," + res.data;
  220. callback(null, base64Str);
  221. },
  222. fail: function (error) {
  223. callback(error);
  224. }
  225. });
  226. },
  227. /**
  228. * 生命周期函数--监听页面初次渲染完成
  229. */
  230. onReady() {
  231. },
  232. /**
  233. * 生命周期函数--监听页面显示
  234. */
  235. onShow() {
  236. },
  237. /**
  238. * 生命周期函数--监听页面隐藏
  239. */
  240. onHide() {
  241. },
  242. /**
  243. * 生命周期函数--监听页面卸载
  244. */
  245. onUnload() {
  246. },
  247. /**
  248. * 页面相关事件处理函数--监听用户下拉动作
  249. */
  250. onPullDownRefresh() {
  251. },
  252. /**
  253. * 页面上拉触底事件的处理函数
  254. */
  255. onReachBottom() {
  256. },
  257. /**
  258. * 用户点击右上角分享
  259. */
  260. onShareAppMessage() {
  261. }
  262. })