index.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. import {miniProgramConfig,sharePoster} from '../../api/other';
  2. import {BASE_URL} from '../../utils/request';
  3. import {isLoggedIn,doLogin} from '../../utils/auth';
  4. import { REPORT_BEHAVIOR } from '../../utils/util.js';
  5. const app = getApp();
  6. Page({
  7. data: {
  8. baseUrl:BASE_URL,
  9. banners: [],
  10. introduction:'',
  11. start_time:'',
  12. end_time:'',
  13. ad_img:'',
  14. share_img:'',
  15. pendingAction:null,//按钮类型
  16. loggedIn:false,
  17. showShare: false,
  18. showPoster:false,
  19. posterImg:'',//生成的海报
  20. },
  21. onLoad(){
  22. // this.getminiProgramConfig();
  23. },
  24. // 获取配置信息
  25. async getminiProgramConfig(){
  26. const res = await miniProgramConfig();
  27. wx.setStorageSync('programConfig', res.data);
  28. app.globalData.programConfig = res.data;
  29. this.setData({
  30. banners:res.data.carousels,
  31. introduction:res.data.marathon_event.introduction,
  32. start_time:res.data.marathon_event.start_time,
  33. end_time:res.data.marathon_event.end_time,
  34. ad_img:res.data.ad_img,
  35. share_img:res.data.share_img
  36. })
  37. },
  38. onShow() {
  39. if(!app.globalData.programConfig){
  40. this.getminiProgramConfig();
  41. }else{
  42. this.setData({
  43. banners:app.globalData.programConfig.carousels,
  44. introduction:app.globalData.programConfig.marathon_event.introduction,
  45. start_time:app.globalData.programConfig.marathon_event.start_time,
  46. end_time:app.globalData.programConfig.marathon_event.end_time,
  47. ad_img:app.globalData.programConfig.ad_img,
  48. share_img:app.globalData.programConfig.share_img
  49. })
  50. }
  51. if (typeof this.getTabBar === 'function' && this.getTabBar()) {
  52. this.getTabBar().setData({
  53. selected: 0
  54. })
  55. this.setData({
  56. loggedIn: isLoggedIn()
  57. })
  58. }
  59. },
  60. goPage(e){
  61. const index = e.currentTarget.dataset.index;
  62. if(index == 0){
  63. wx.navigateTo({
  64. url: `/pages/rules/rules?type=${index}`
  65. })
  66. }else if(index == 1){
  67. wx.navigateTo({
  68. url: `/pages/rules/rules?type=${index}`
  69. })
  70. }
  71. },
  72. onShareAppMessage() {
  73. REPORT_BEHAVIOR('分享');
  74. return {
  75. path: '/pages/index/index',
  76. imageUrl: app.globalData.programConfig.share_img
  77. }
  78. },
  79. goRegister(e) {
  80. const action = e.currentTarget.dataset.action;
  81. if (isLoggedIn()) {
  82. this.doAction(action)
  83. }
  84. },
  85. async onGetPhoneNumber(e) {
  86. const action = e.currentTarget.dataset.action;
  87. if (e.detail.errMsg !== 'getPhoneNumber:ok') {
  88. wx.showToast({ title: '授权失败', icon: 'none' })
  89. return
  90. }
  91. const { encryptedData, iv } = e.detail;
  92. try {
  93. wx.login({
  94. success: async loginRes => {
  95. await doLogin({
  96. code: loginRes.code,
  97. phone: { encryptedData, iv }
  98. });
  99. this.setData({ loggedIn: isLoggedIn() })
  100. this.doAction(action);
  101. }
  102. })
  103. } catch (err) {
  104. wx.showToast({ title: '登录失败,请重试', icon: 'none' });
  105. console.error(err);
  106. }
  107. },
  108. doAction(action) {
  109. if (action === 'register') wx.navigateTo({ url: '/pages/register/register' });
  110. if (action === 'invite'){
  111. this.setData({ showShare: true });
  112. };
  113. },
  114. // 弹框取消
  115. onClose(){
  116. this.setData({ showShare: false });
  117. },
  118. // 点击海报生成图片
  119. async openPoster() {
  120. const userInfo = app.globalData.userInfo || wx.getStorageSync('userInfo');
  121. const programConfig = app.globalData.programConfig || wx.getStorageSync('programConfig');
  122. const posterKey = `posterImg_${userInfo.avatar}_${userInfo.nickname}_${programConfig.share_img}_${programConfig.share_qrcode}`;
  123. const cachedData = wx.getStorageSync('posterCache') || {};
  124. if (cachedData.key === posterKey && cachedData.path) {
  125. this.setData({ posterImg: cachedData.path, showPoster: true });
  126. } else {
  127. this.setData({ showPoster: true }, async () => {
  128. const path = await this.drawPoster();
  129. wx.setStorageSync('posterCache', { key: posterKey, path });
  130. });
  131. }
  132. },
  133. async drawPoster() {
  134. const userInfo = app.globalData.userInfo || wx.getStorageSync('userInfo');
  135. const programConfig = app.globalData.programConfig || wx.getStorageSync('programConfig');
  136. const ctx = wx.createCanvasContext('posterCanvas', this);
  137. const canvasWidth = 300;
  138. const canvasHeight = 600;
  139. const bottomHeight = 80;
  140. const radius = 16; // 圆角半径
  141. ctx.save();
  142. ctx.setFillStyle('#fff');
  143. this.drawRoundRect(ctx, 0, 0, canvasWidth, canvasHeight, radius);
  144. // 背景图
  145. const bgUrl = programConfig.share_img;
  146. if (bgUrl) {
  147. const bgPath = bgUrl.startsWith('http') ? await this.downloadImage(bgUrl) : bgUrl;
  148. ctx.drawImage(bgPath, 0, 0, canvasWidth, canvasHeight - bottomHeight);
  149. }
  150. // 底部白色区域
  151. ctx.setFillStyle('#fff');
  152. ctx.fillRect(0, canvasHeight - bottomHeight, canvasWidth, bottomHeight);
  153. // 用户头像(圆形)
  154. const avatarUrl = userInfo.avatar;
  155. if (avatarUrl) {
  156. const avatarPath = avatarUrl.startsWith('http') ? await this.downloadImage(avatarUrl) : avatarUrl;
  157. const avatarSize = 40;
  158. const avatarX = 20;
  159. const avatarY = canvasHeight - bottomHeight + (bottomHeight - avatarSize) / 2;
  160. ctx.save();
  161. ctx.beginPath();
  162. ctx.arc(avatarX + avatarSize / 2, avatarY + avatarSize / 2, avatarSize / 2, 0, Math.PI * 2);
  163. ctx.clip();
  164. ctx.drawImage(avatarPath, avatarX, avatarY, avatarSize, avatarSize);
  165. ctx.restore();
  166. }
  167. // 昵称
  168. const nickName = userInfo.nickname || '游客';
  169. ctx.setFontSize(16);
  170. ctx.setFillStyle('#000');
  171. const textX = 20 + 40 + 12;
  172. const textY = canvasHeight - bottomHeight + bottomHeight / 2 + 6;
  173. ctx.fillText(nickName, textX, textY);
  174. // 二维码
  175. const qrUrl = programConfig.share_qrcode;
  176. if (qrUrl) {
  177. const qrPath = qrUrl.startsWith('http') ? await this.downloadImage(qrUrl) : qrUrl;
  178. const qrSize = 50;
  179. const qrX = canvasWidth - qrSize - 20;
  180. const qrY = canvasHeight - bottomHeight + (bottomHeight - qrSize) / 2;
  181. ctx.drawImage(qrPath, qrX, qrY, qrSize, qrSize);
  182. }
  183. ctx.restore(); // 恢复裁剪
  184. return new Promise((resolve, reject) => {
  185. ctx.draw(true, () => {
  186. wx.canvasToTempFilePath({
  187. canvasId: 'posterCanvas',
  188. success: res => resolve(res.tempFilePath),
  189. fail: err => {
  190. console.error('生成临时文件失败:', err);
  191. reject(err);
  192. }
  193. }, this);
  194. });
  195. });
  196. },
  197. // 下载网络图片到临时路径
  198. downloadImage(url) {
  199. return new Promise((resolve, reject) => {
  200. wx.downloadFile({
  201. url,
  202. success(res) {
  203. if (res.statusCode === 200) resolve(res.tempFilePath);
  204. else reject(new Error('下载失败'));
  205. },
  206. fail(err) { reject(err); }
  207. });
  208. });
  209. },
  210. // 绘制圆角矩形函数
  211. drawRoundRect(ctx, x, y, w, h, r) {
  212. ctx.beginPath();
  213. ctx.moveTo(x + r, y);
  214. ctx.arcTo(x + w, y, x + w, y + h, r);
  215. ctx.arcTo(x + w, y + h, x, y + h, r);
  216. ctx.arcTo(x, y + h, x, y, r);
  217. ctx.arcTo(x, y, x + w, y, r);
  218. ctx.closePath();
  219. ctx.fill();
  220. ctx.clip(); // 关键:裁剪出圆角
  221. },
  222. closePoster(){
  223. this.setData({ showPoster: false});
  224. },
  225. // 保存相册
  226. savePoster() {
  227. wx.saveImageToPhotosAlbum({
  228. filePath: this.data.posterImg,
  229. success() { wx.showToast({ title: '保存成功' }); },
  230. fail(err) {
  231. if (err.errMsg.includes('auth')) wx.openSetting();
  232. }
  233. });
  234. },
  235. // 发送朋友
  236. sendImg(){
  237. if (!this.data.posterImg) return;
  238. wx.showShareImageMenu({
  239. path: this.data.posterImg,
  240. success() {},
  241. fail: console.error,
  242. });
  243. }
  244. })