util.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. import { getUserInfo,behaviorReport } from '../api/user'
  2. import md5 from './md5.min.js'
  3. // 获取手机号
  4. export const MAKE_PHONE_CALL = (phoneNumber) => {
  5. if (!phoneNumber) {
  6. wx.showToast({ title: '暂无手机号', icon: 'none' });
  7. }
  8. wx.makePhoneCall({
  9. phoneNumber: phoneNumber,
  10. success() {
  11. console.log('拨打电话成功');
  12. },
  13. fail(err) {
  14. console.error('拨打电话失败', err);
  15. }
  16. });
  17. };
  18. // 获取用户信息
  19. export async function FETCH_AND_FORMAT_USER_INFO() {
  20. const userRes = await getUserInfo()
  21. const data = userRes.data || {};
  22. let dataInfo = {
  23. ...data,
  24. nickname: data.nickname || data.phone || data.username.substring(0,6)
  25. }
  26. wx.setStorageSync('userInfo', dataInfo)
  27. getApp().globalData.userInfo = dataInfo
  28. }
  29. // 埋点上报
  30. export async function REPORT_BEHAVIOR(eventName = '', extra = {}) {
  31. const timestamp = Date.now();
  32. let _k = md5(`${timestamp} + ${eventName} + aaddfzew1343!@##`);
  33. try {
  34. const res = await behaviorReport({
  35. type: eventName,
  36. ...extra,
  37. _k,
  38. timestamp
  39. });
  40. console.log('埋点成功:', res);
  41. return res;
  42. } catch (err) {
  43. console.error('埋点失败:', err);
  44. return null;
  45. }
  46. }
  47. // 生成海报
  48. export async function DRAW_POSTER() {
  49. const userInfo = getApp().globalData.userInfo || wx.getStorageSync('userInfo');
  50. const programConfig = getApp().globalData.programConfig || wx.getStorageSync('programConfig');
  51. const ctx = wx.createCanvasContext('posterCanvas'); // 不要传 this,容易丢失上下文
  52. const canvasWidth = 300;
  53. const canvasHeight = 600;
  54. const bottomHeight = 80;
  55. const radius = 16; // 圆角半径
  56. // 白色背景 + 圆角
  57. ctx.save();
  58. ctx.setFillStyle('#fff');
  59. drawRoundRect(ctx, 0, 0, canvasWidth, canvasHeight, radius);
  60. ctx.fill();
  61. ctx.restore();
  62. // 背景图
  63. if (programConfig.share_img) {
  64. const bgPath = await loadImage(programConfig.share_img);
  65. ctx.drawImage(bgPath, 0, 0, canvasWidth, canvasHeight - bottomHeight);
  66. }
  67. // 底部白色区域
  68. ctx.setFillStyle('#fff');
  69. ctx.fillRect(0, canvasHeight - bottomHeight, canvasWidth, bottomHeight);
  70. // 用户头像(圆形裁剪)
  71. if (userInfo.avatar) {
  72. const avatarPath = await loadImage(userInfo.avatar);
  73. const avatarSize = 40;
  74. const avatarX = 20;
  75. const avatarY = canvasHeight - bottomHeight + (bottomHeight - avatarSize) / 2;
  76. ctx.save();
  77. ctx.beginPath();
  78. ctx.arc(avatarX + avatarSize / 2, avatarY + avatarSize / 2, avatarSize / 2, 0, Math.PI * 2);
  79. ctx.clip();
  80. ctx.drawImage(avatarPath, avatarX, avatarY, avatarSize, avatarSize);
  81. ctx.restore();
  82. }
  83. // 昵称
  84. const nickName = userInfo.nickname || '游客';
  85. ctx.setFontSize(16);
  86. ctx.setFillStyle('#000');
  87. ctx.fillText(nickName, 72, canvasHeight - bottomHeight / 2 + 6);
  88. // 二维码
  89. if (programConfig.share_qrcode) {
  90. const qrPath = await loadImage(programConfig.share_qrcode);
  91. const qrSize = 50;
  92. const qrX = canvasWidth - qrSize - 20;
  93. const qrY = canvasHeight - bottomHeight + (bottomHeight - qrSize) / 2;
  94. ctx.drawImage(qrPath, qrX, qrY, qrSize, qrSize);
  95. }
  96. // 导出图片
  97. return new Promise((resolve, reject) => {
  98. ctx.draw(false, () => {
  99. wx.canvasToTempFilePath({
  100. canvasId: 'posterCanvas',
  101. destWidth: canvasWidth * 2, // 提高清晰度,避免导出失败
  102. destHeight: canvasHeight * 2,
  103. success: res => resolve(res.tempFilePath),
  104. fail: err => {
  105. console.error('生成临时文件失败:', err);
  106. reject(err);
  107. }
  108. });
  109. });
  110. });
  111. }
  112. // 图片预加载
  113. function loadImage(url) {
  114. return new Promise((resolve, reject) => {
  115. wx.getImageInfo({
  116. src: url,
  117. success(res) { resolve(res.path); },
  118. fail(err) { reject(err); }
  119. });
  120. });
  121. }
  122. // 圆角矩形
  123. function drawRoundRect(ctx, x, y, w, h, r) {
  124. ctx.beginPath();
  125. ctx.moveTo(x + r, y);
  126. ctx.arcTo(x + w, y, x + w, y + h, r);
  127. ctx.arcTo(x + w, y + h, x, y + h, r);
  128. ctx.arcTo(x, y + h, x, y, r);
  129. ctx.arcTo(x, y, x + w, y, r);
  130. ctx.closePath();
  131. }
  132. // base64 转临时文件路径
  133. export function base64ToFilePath(base64Data, fileName = 'poster.png') {
  134. return new Promise((resolve, reject) => {
  135. try {
  136. const fs = wx.getFileSystemManager();
  137. const filePath = `${wx.env.USER_DATA_PATH}/${fileName}`;
  138. // 去掉可能存在的 data:image/jpeg;base64, 前缀
  139. const pureBase64 = base64Data.replace(/^data:image\/\w+;base64,/, "");
  140. const buffer = wx.base64ToArrayBuffer(pureBase64);
  141. fs.writeFile({
  142. filePath,
  143. data: buffer,
  144. encoding: 'binary',
  145. success: () => resolve(filePath), // 返回本地路径
  146. fail: reject
  147. });
  148. } catch (err) {
  149. reject(err);
  150. }
  151. });
  152. }