Ver Fonte

修复bug

wkw há 3 semanas atrás
pai
commit
ecd4b3664e

+ 8 - 0
api/other.js

@@ -71,6 +71,14 @@ export function sharePoster() {
     method: 'GET'
   });
 }
+export function registrationRecord() {
+  return request({
+    loading: false,
+    url: `/api/registration/record`,
+    method: 'GET'
+  });
+}
+
 
 
 

+ 2 - 1
app.json

@@ -9,7 +9,8 @@
     "pages/setting/setting",
     "pages/registrationRecords/registrationRecords",
     "pages/coupon/coupon",
-    "pages/couponDetail/couponDetail"
+    "pages/couponDetail/couponDetail",
+    "pages/registrationRecordList/registrationRecordList"
   ],
   "window": {
     "navigationBarTextStyle": "black",

+ 217 - 0
pages/index/index - 副本.js

@@ -0,0 +1,217 @@
+import {miniProgramConfig,sharePoster} from '../../api/other';
+import {BASE_URL} from '../../utils/request';
+import {isLoggedIn,doLogin} from '../../utils/auth';
+const app = getApp();
+Page({
+  data: {
+    baseUrl:BASE_URL,
+    banners: [],
+    introduction:'',
+    start_time:'',
+    end_time:'',
+    ad_img:'',
+    share_img:'',
+    pendingAction:null,//按钮类型
+    loggedIn:false,
+    showShare: false,
+    showPoster:false,
+    posterImg:'',//生成的海报
+  },
+  async onLoad(){
+    const res = await miniProgramConfig();
+    app.globalData.programConfig = res.data;
+    this.setData({
+      banners:res.data.carousels,
+      introduction:res.data.marathon_event.introduction,
+      start_time:res.data.marathon_event.start_time,
+      end_time:res.data.marathon_event.end_time,
+      ad_img:res.data.ad_img,
+      share_img:res.data.share_img
+    })
+  },
+  onShow() {
+    if (typeof this.getTabBar === 'function' && this.getTabBar()) {
+      this.getTabBar().setData({
+        selected: 0
+      })
+      this.setData({
+        loggedIn: isLoggedIn()
+      })
+    }
+  },
+  goPage(e){
+    const index = e.currentTarget.dataset.index;
+    if(index == 0){
+      wx.navigateTo({
+        url: `/pages/rules/rules?type=${index}`
+      })
+    }else if(index == 1){
+      wx.navigateTo({
+        url: `/pages/rules/rules?type=${index}`
+      })
+    }
+  },
+  onShareAppMessage() {
+    return {
+      path: '/pages/index/index',
+      imageUrl: app.globalData.programConfig.share_img
+    }
+  },
+  goRegister(e) {
+    const action = e.currentTarget.dataset.action;
+    if (isLoggedIn()) {
+      this.doAction(action)
+    }
+  },
+  async onGetPhoneNumber(e) {
+    const action = e.currentTarget.dataset.action;
+    if (e.detail.errMsg !== 'getPhoneNumber:ok') {
+      wx.showToast({ title: '授权失败', icon: 'none' })
+      return
+    }
+    const { encryptedData, iv } = e.detail;
+    try {
+      wx.login({
+        success: async loginRes => {
+          await doLogin({
+            code: loginRes.code,
+            phone: { encryptedData, iv }
+          });
+          this.setData({ loggedIn: isLoggedIn() })
+          this.doAction(action);
+        }
+      })
+    } catch (err) {
+      wx.showToast({ title: '登录失败,请重试', icon: 'none' });
+      console.error(err);
+    }
+  },
+  doAction(action) {
+    if (action === 'register') wx.navigateTo({ url: '/pages/register/register' });
+    if (action === 'invite'){
+      this.setData({ showShare: true });
+    };
+  },
+  // 弹框取消
+  onClose(){
+    this.setData({ showShare: false });
+  },
+  // 点击海报生成图片
+  async openPoster(){
+    this.setData({ showPoster: true }, () => {
+      this.drawPoster();
+    });
+    // wx.showLoading({
+    //   title: '海报生成中...',
+    //   mask: true
+    // });
+    // try {
+    //   const res = await sharePoster();
+    //   if(res.code == 200){
+    //     console.log(res.data);
+    //     this.setData({ showPoster:true,posterImg: res.data});
+    //   }
+    // } catch (error) {
+    //   console.log(error)
+    // } finally{
+    //   wx.hideLoading();
+    // }
+  },
+  async drawPoster() {
+    const ctx = wx.createCanvasContext('posterCanvas', this);
+    const canvasWidth = 300;
+    const canvasHeight = 600;
+    const bottomHeight = 80; // 底部白色区域高度
+    // 先画整体背景图
+    const bgUrl = app.globalData.programConfig.share_img;
+    if (bgUrl) {
+      const bgPath = bgUrl.startsWith('http') ? await this.downloadImage(bgUrl) : bgUrl;
+      ctx.drawImage(bgPath, 0, 0, canvasWidth, canvasHeight - bottomHeight);
+    } else {
+      ctx.setFillStyle('#fff');
+      ctx.fillRect(0, 0, canvasWidth, canvasHeight - bottomHeight);
+    }
+  
+    // 底部白色区域
+    ctx.setFillStyle('#fff');
+    ctx.fillRect(0, canvasHeight - bottomHeight, canvasWidth, bottomHeight);
+  
+    // 用户头像(圆形)放在底部白色区域
+    const avatarUrl = app.globalData.userInfo.avatar;
+    if (avatarUrl) {
+      const avatarPath = avatarUrl.startsWith('http') ? await this.downloadImage(avatarUrl) : avatarUrl;
+      const avatarX = 20; 
+      const avatarY = canvasHeight - bottomHeight + 10;
+      ctx.save();
+      ctx.beginPath();
+      ctx.arc(avatarX + 30, avatarY + 30, 30, 0, Math.PI * 2);
+      ctx.clip();
+      ctx.drawImage(avatarPath, avatarX, avatarY, 60, 60);
+      ctx.restore();
+    }
+  
+    // 昵称放在头像右侧
+    const nickName = app.globalData.userInfo.nickname || '123456';
+    console.log(app.globalData.userInfo.nickName)
+    ctx.setFontSize(16);
+    ctx.setFillStyle('#000');
+    ctx.fillText(nickName, 100, canvasHeight - bottomHeight + 40);
+  
+    // 小程序二维码放在底部白色区域右下角
+    const qrUrl = app.globalData.programConfig.share_qrcode;
+    if (qrUrl) {
+      const qrPath = qrUrl.startsWith('http') ? await this.downloadImage(qrUrl) : qrUrl;
+      const qrSize = 60;
+      ctx.drawImage(qrPath, canvasWidth - qrSize - 20, canvasHeight - bottomHeight + 10, qrSize, qrSize);
+    }
+  
+    // 绘制完成
+    ctx.draw(false, () => {
+      wx.canvasToTempFilePath({
+        canvasId: 'posterCanvas',
+        success: res => this.setData({ posterImg: res.tempFilePath }),
+        fail: err => console.error(err)
+      }, this);
+    });
+  },
+  
+  // 下载网络图片到临时路径
+  downloadImage(url) {
+    return new Promise((resolve, reject) => {
+      wx.downloadFile({
+        url,
+        success(res) {
+          if (res.statusCode === 200) resolve(res.tempFilePath);
+          else reject(new Error('下载失败'));
+        },
+        fail(err) { reject(err); }
+      });
+    });
+  },   
+  closePoster(){
+    this.setData({ showPoster: false});
+  },
+  // 保存相册
+  savePoster() {
+    if (!this.data.posterImg) {
+      wx.showToast({ title: '没有海报图片', icon: 'none' });
+      return;
+    }
+    wx.saveImageToPhotosAlbum({
+      filePath: this.data.posterImg,
+      success() { wx.showToast({ title: '保存成功' }); },
+      fail(err) {
+        if (err.errMsg.includes('auth')) wx.openSetting();
+      }
+    });
+  },  
+  // 发送朋友
+  sendImg(){
+    if (!this.data.posterImg) return;
+    wx.showShareImageMenu({
+      path: this.data.posterImg,
+      success() {},
+      fail: console.error,
+    });
+  }
+})

+ 89 - 0
pages/index/index - 副本.wxml

@@ -0,0 +1,89 @@
+<view class="container">
+  <view class="index">
+    <swiper 
+      class="swiper-container" 
+      indicator-dots="{{true}}" 
+      interval="{{3000}}"
+      duration="{{500}}"
+      circular="{{true}}"
+      autoplay="{{true}}"
+    >
+      <block wx:for="{{banners}}" wx:key="index">
+        <swiper-item>
+          <image 
+            class="swiper-image" 
+            src="{{item.img}}" 
+            mode="aspectFit"
+            lazy-load="true" 
+          />
+        </swiper-item>
+      </block>
+    </swiper>
+    <view class="bg-color">
+      <view class="content">
+        <view class="card-box">
+          <!-- 活动规则 -->
+          <view class="rules-bg">
+            <view class="rules-item" bindtap="goPage" data-index="0">
+              <image class="rules-img" src="/static/image/rules.png" mode="aspectFit"></image>
+              <text>活动规则</text>
+            </view>
+            <view class="line"></view>
+            <view class="rules-item" bindtap="goPage" data-index="1">
+              <image class="rules-img" src="/static/image/rules.png" mode="aspectFit"></image>
+              <text>免责申明</text>
+            </view>
+          </view>
+          <!-- 日历 -->
+          <block wx:if="{{start_time && end_time}}">
+            <view class="countdown">倒计时开跑时间</view>
+            <countdown end-time="{{start_time}}" />
+          </block>
+        </view>
+        <!-- 报名 -->
+        <view class="registration">
+          <view class="registration-lf" bindtap="goRegister" data-action="register">
+            <image class="lf-bg-img" src="{{baseUrl + '/static/image/registration.png'}}" mode="aspectFit" />
+            <image class="registration-img" src="/static/image/lkbm.png" mode="aspectFit" />
+            <button wx:if="{{!loggedIn}}" class="cover-btn" open-type="getPhoneNumber"      bindgetphonenumber="onGetPhoneNumber" data-action="register"></button>
+          </view>
+          <view class="registration-ri" bindtap="goRegister" data-action="invite">
+            <image class="ri-bg-img" src="{{baseUrl + '/static/image/invitation.png'}}" mode="aspectFit" />
+            <image class="registration-img" src="/static/image/yqhy.png" mode="aspectFit"/>
+            <button wx:if="{{!loggedIn}}" class="cover-btn" open-type="getPhoneNumber" bindgetphonenumber="onGetPhoneNumber" data-action="invite"></button>
+          </view>
+        </view>
+        <image class="ad-img" wx:if="{{ad_img}}" src="{{ad_img}}" mode="widthFix"/>
+        <rich-text style="width: 100%;" nodes="{{introduction}}" />
+      </view>
+    </view>
+  </view>
+  <van-popup show="{{showShare}}" position="bottom" round>
+    <view class="share-container">
+      <view class="share-options">
+        <button class="share-item" open-type="share" data-type="friend">
+          <image class="share-icon" src="/static/tabbar/weixin.png" mode="aspectFit" />
+          <text class="share-text">微信好友</text>
+        </button>
+
+        <button class="share-item" bindtap="openPoster">
+          <image class="share-icon" src="/static/tabbar/tp.png" mode="aspectFit" />
+          <text class="share-text">海报转发</text>
+        </button>
+      </view>
+      <view class="share-cancel" bindtap="onClose" hover-class="btn-hover" hover-start-time="50">
+        <image class="share-cancel-img" src="/static/tabbar/cancel.png" mode="aspectFit"/>
+      </view>
+    </view>
+  </van-popup>
+  <view class="poster-container" wx:if="{{showPoster}}" bindtap="closePoster">
+    <view class="poster-content">
+      <canvas canvas-id="posterCanvas" style="width: 300px; height: 600px;"></canvas>
+      <!-- <image src="data:image/png;base64,{{posterImg}}" mode="aspectFit" class="poster-img" /> -->
+      <view class="poster-actions">
+        <button class="poster-lf" bindtap="savePoster">保存到相册</button>
+        <button class="poster-ri" bindtap="sendImg" data-type="poster">发送朋友</button>
+      </view>
+    </view>
+  </view>
+</view>

+ 3 - 0
pages/index/index.js

@@ -1,6 +1,7 @@
 import {miniProgramConfig,sharePoster} from '../../api/other';
 import {BASE_URL} from '../../utils/request';
 import {isLoggedIn,doLogin} from '../../utils/auth';
+import { REPORT_BEHAVIOR } from '../../utils/util.js';
 const app = getApp();
 Page({
   data: {
@@ -52,6 +53,7 @@ Page({
     }
   },
   onShareAppMessage() {
+    REPORT_BEHAVIOR('分享');
     return {
       path: '/pages/index/index',
       imageUrl: app.globalData.programConfig.share_img
@@ -144,6 +146,7 @@ Page({
   },  
   // 发送朋友
   sendImg(){
+    REPORT_BEHAVIOR('分享');
     // 将 base64 转临时文件路径
     const base64Data = this.data.posterImg;
     const filePath = `${wx.env.USER_DATA_PATH}/poster.png`;

+ 0 - 1
pages/index/index.wxml

@@ -3,7 +3,6 @@
     <swiper 
       class="swiper-container" 
       indicator-dots="{{true}}" 
-      autoplay="{{false}}"
       interval="{{3000}}"
       duration="{{500}}"
       circular="{{true}}"

+ 2 - 1
pages/mine/mine.js

@@ -43,7 +43,8 @@ Page({
       1: `/pages/rules/rules?type=${index}`,
       2: `/pages/registrationRecords/registrationRecords`,
       3: `/pages/coupon/coupon`,
-      4: `/pages/setting/setting`
+      4: `/pages/setting/setting`,
+      // 5:`/pages/registrationRecordList/registrationRecordList`,
     };
     if (pageMap[index]) {
       wx.navigateTo({ url: pageMap[index] });

+ 1 - 1
pages/mine/mine.wxml

@@ -3,7 +3,7 @@
   <view class="mine">
     <view class="user-box">
       <button class="avatar-wrapper" open-type="chooseAvatar"   bind:chooseavatar="onChooseAvatar">
-        <van-image lazy-load round width="144rpx" height="144rpx" fit="cover" src="{{userInfo.avatar || '/static/image/cat.jpeg'}}" />
+        <van-image lazy-load round width="144rpx" height="144rpx" fit="cover" src="{{userInfo.avatar || baseUrl + '/static/image/cat.jpeg'}}" />
       </button>
       <view class="user-text mt28">{{userInfo.nickname || '游客'}}</view>
       <view class="user-text user-number" wx:if="{{userInfo.competitionNo}}">报名号:{{userInfo.competitionNo}}</view>

+ 2 - 1
pages/register/register.js

@@ -154,7 +154,7 @@ Page({
   // 校验表单是否可提交
   checkFormValid() {
     const { phone, captcha, nickname, gender, race_number } = this.data.formData;
-    const valid = phone && captcha && nickname && gender && race_number && this.data.checked;
+    const valid = phone && captcha && nickname && gender && race_number && this.data.checked && !this.data.raceNumberError && !this.data.phoneError;
     this.setData({ canSubmit: valid });
   },
   // 获取验证码
@@ -189,6 +189,7 @@ Page({
 
   // 提交报名
   async onSubmit() {
+    this.checkFormValid();
     if (!this.data.canSubmit) return;
     const payload = {
       ...this.data.formData,

+ 67 - 0
pages/registrationRecordList/registrationRecordList.js

@@ -0,0 +1,67 @@
+import { enrollRecord } from '../../api/other';
+
+Page({
+  data: {
+    cardList: [],
+    page: 1,
+    pageSize: 2,
+    loadingMore: false,
+    noMore: false,
+    refreshing: false
+  },
+
+  onLoad() {
+    this.loadData(true);
+  },
+
+  // 请求数据
+  async loadData(isRefresh = false) {
+    if (this.data.loadingMore) return;
+    let page = isRefresh ? 1 : this.data.page;
+    this.setData({ loadingMore: true });
+    try {
+      const res = await enrollRecord({ page, pageSize: this.data.pageSize });
+      const statusImgMap = {
+        0: '/static/image/register/wks.png',
+        1: '/static/image/register/yjs.png',
+        2: '/static/image/register/jxz.png'
+      };
+
+      const newList = res.data.list || [];
+      let allList = isRefresh ? newList : [...this.data.cardList, ...newList];
+      allList = allList.map(item => ({
+        ...item,
+        img: statusImgMap[item.status],
+        genderText: item.gender == 0 ? '女' : '男'
+      }));
+
+      this.setData({
+        cardList: allList,
+        loadingMore: false,
+        page: page + 1,
+        noMore: allList.length >= res.data.total, // 有数据时判断是否加载完
+        refreshing: false
+      });
+    } catch (err) {
+      console.error(err);
+      wx.showToast({ title: '加载失败', icon: 'none' });
+      this.setData({
+        loadingMore: false,
+        refreshing: false
+      });
+    }
+  },
+
+  // 上拉触底
+  onReachBottom() {
+    if (this.data.noMore) return;
+    this.loadData();
+  },
+
+  // 下拉刷新
+  onPullDownRefresh() {
+    if (this.data.refreshing) return;
+    this.setData({ refreshing: true, noMore: false, page: 1 });
+    this.loadData(true);
+  }
+});

+ 8 - 0
pages/registrationRecordList/registrationRecordList.json

@@ -0,0 +1,8 @@
+{
+  "usingComponents": {
+    "header": "/components/Header/Header",
+    "van-cell": "@vant/weapp/cell/index",
+    "van-empty": "@vant/weapp/empty/index"
+  },
+  "navigationStyle": "custom"
+}

+ 40 - 0
pages/registrationRecordList/registrationRecordList.wxml

@@ -0,0 +1,40 @@
+<view class="container">
+  <header text="赛事记录"></header>
+  <scroll-view 
+    class="content"
+    scroll-y="true"
+    bindscrolltolower="onReachBottom"
+    lower-threshold="50"
+    refresher-enabled="true"
+    refresher-triggered="{{refreshing}}"
+    bindrefresherrefresh="onPullDownRefresh"
+  >
+    <!-- 数据列表 -->
+    <block wx:if="{{cardList.length > 0}}">
+      <view class="card-box {{ index === 0 ? 'first-card' : '' }}" wx:for="{{cardList}}" wx:key="index">
+        <view class="card-top">
+          <view class="card-title-box">
+            <view class="card-title">{{item.marathon_event.doings_name}}</view>
+            <view class="card-time">{{item.register_time}}</view>
+          </view>
+          <image class="card-img" src="{{item.img}}" mode="aspectFit"/>
+        </view>
+        <view class="cell-box">
+          <van-cell title="参赛姓名" value="{{item.nickname}}" border="{{ false }}" />
+          <van-cell title="手机号" value="{{item.phone}}" border="{{ false }}" />
+          <van-cell title="性别" value="{{item.genderText}}" border="{{ false }}" />
+          <van-cell title="身份证号" value="{{item.race_number}}" border="{{ false }}" />
+          <van-cell custom-class="cell-list" title="报名号码" value="{{item.competition_no}}" border="{{ false }}" />
+        </view>
+      </view>
+    </block>
+
+    <!-- 空状态 -->
+    <van-empty wx:if="{{!loadingMore && cardList.length === 0}}" description="暂无数据" />
+  </scroll-view>
+
+  <!-- 分页到底提示 -->
+  <view wx:if="{{!loadingMore && noMore && cardList.length > 0}}" class="loading">
+    没有更多数据了
+  </view>
+</view>

+ 74 - 0
pages/registrationRecordList/registrationRecordList.wxss

@@ -0,0 +1,74 @@
+.container{
+  height: 100vh;
+}
+.content{
+  flex: 1;
+  overflow: auto;
+  padding-bottom: 32rpx;
+}
+.card-box{
+  background-color: #fff;
+  border-radius: 28rpx;
+  margin: 40rpx 32rpx;
+}
+.first-card{
+  margin: 32rpx 32rpx 40rpx;
+}
+.card-top{
+  display: flex;
+  position: relative;
+  height: 176.78rpx;
+}
+.card-title-box{
+  padding: 30rpx 0 0 32rpx;
+}
+.card-title{
+  font-weight: 600;
+  font-size: 32rpx;
+  color: #000000;
+  line-height: 44rpx;
+  margin-bottom: 10rpx;
+}
+.card-time{
+  font-weight: 400;
+  font-size: 24rpx;
+  color: #B0B0B0;
+  line-height: 34rpx;
+}
+.card-img{
+  width: 176.78rpx;
+  height: 176.78rpx;
+  position: absolute;
+  top: 0;
+  right: 0;
+}
+.cell-box{
+  padding: 0 32rpx 22rpx;
+}
+.van-cell{
+  padding: 32rpx 0 !important;
+  border-bottom: 1px solid #EDEDED;
+}
+.van-cell__title{
+  font-family: PingFangSC, PingFang SC;
+  font-weight: 400 !important;
+  font-size: 28rpx !important;
+  color: #6F6F6F !important;
+  line-height: 40rpx;
+}
+.van-cell__value{
+  font-family: PingFangSC, PingFang SC;
+  font-weight: 500 !important;
+  font-size: 28rpx !important;
+  color: #000000 !important;
+  line-height: 40rpx;
+}
+.cell-list{
+  border-bottom: 0 !important;
+}
+.loading{
+  color: #969799;
+  font-size:24rpx;
+  text-align: center;
+  padding-bottom: 32rpx;
+}

BIN
static/image/cat.jpeg


+ 0 - 2
utils/util.js

@@ -20,12 +20,10 @@ export async function FETCH_AND_FORMAT_USER_INFO() {
   const data = userRes.data || {};
   getApp().globalData.userInfo = {
     ...data,
-    avatar: data.avatar || '/static/image/cat.jpeg',
     nickname: data.nickname || data.phone || data.username.substring(0,6)
   }
   return {
     ...data,
-    avatar: data.avatar || '/static/image/cat.jpeg',
     nickname: data.nickname || data.phone || data.username.substring(0,6)
   }
 }