lex-xin 17 godzin temu
rodzic
commit
7d64e48bfa

+ 20 - 0
miniprogram/api/login.ts

@@ -56,6 +56,26 @@ export const api_executeOrderV2 = (params: any) => {
 };
 
 /** 用户下单 */
+export const api_sendImgCode = (params: any) => {
+  return request({
+    url: `/edu-app/open/sendImgCode`,
+    method: "get",
+    requestType: "form",
+    hideLoading: true,
+    data: params,
+  } as any);
+};
+
+export const api_sendSmsVerify = (params: any) => {
+  return request({
+    url: `/edu-app/open/sendSmsVerify`,
+    method: "post",
+    requestType: "form",
+    hideLoading: true,
+    data: params,
+  } as any);
+};
+
 export const api_executePayment = (params: any) => {
   return request({
     url: `/edu-app/open/userOrder/executePayment`,

+ 11 - 0
miniprogram/pages/index/index.less

@@ -534,6 +534,17 @@ page {
         color: #15171c;
         font-weight: 600;
       }
+
+      &.disabled {
+        color: #b9bdc7;
+        background: #f1f2f4;
+      }
+
+      &.disabled.active {
+        color: #b9bdc7;
+        background: #f1f2f4;
+        font-weight: 400;
+      }
     }
   }
 }

+ 78 - 9
miniprogram/pages/index/index.ts

@@ -11,6 +11,7 @@ const PURCHASE_TYPE = {
 };
 const TEACHER_VIP_PARAM_NAME = "teacher_vip_purchase_list";
 const purchaseDataCache: any = {};
+let purchaseDataRequestId = 0;
 
 function getProductImage(item: any, userType: string) {
   if (!item) {
@@ -71,6 +72,23 @@ function getPeriodScrollIntoView(periodList: any[], selectedPeriod: string) {
   return periodList.find((item: any) => String(item.value) === String(selectedPeriod))?.viewId || "";
 }
 
+function markPeriodListActive(periodList: any[], selectedPeriod: string) {
+  return periodList.map((item: any) => ({
+    ...item,
+    active: String(item.value) === String(selectedPeriod),
+  }));
+}
+
+function syncPurchaseDataCache(userType: string, patch: any) {
+  if (!purchaseDataCache[userType]) {
+    return;
+  }
+  purchaseDataCache[userType] = {
+    ...purchaseDataCache[userType],
+    ...patch,
+  };
+}
+
 function selectDefaultTeacherVip(list: any[]) {
   const saleableList = list.filter((item: any) => Number(item.stockNum ?? 1) > 0);
   const candidates = saleableList.length ? saleableList : list;
@@ -310,12 +328,13 @@ Page({
    */
   async onInit() {
     const userType = this.data.userTypes;
+    const requestId = ++purchaseDataRequestId;
     if (purchaseDataCache[userType]) {
       this.applyPurchaseData(purchaseDataCache[userType]);
       return
     }
     if (userType === PURCHASE_TYPE.TEACHER) {
-      await this.onInitTeacherVip()
+      await this.onInitTeacherVip(requestId)
       return
     }
     try {
@@ -373,6 +392,9 @@ Page({
         showBonusGift: Boolean(formatGiftText(selected))
       };
       purchaseDataCache[userType] = purchaseData;
+      if (requestId !== purchaseDataRequestId || this.data.userTypes !== userType) {
+        return;
+      }
       this.applyPurchaseData(purchaseData);
     } catch (e) {
       console.log(e, "e");
@@ -380,13 +402,17 @@ Page({
   },
   // 格式化类型
   applyPurchaseData(purchaseData: any) {
-    const periodScrollIntoView = getPeriodScrollIntoView(
+    const periodList = markPeriodListActive(
       purchaseData.periodList,
       purchaseData.selectedPeriod
     );
+    const periodScrollIntoView = getPeriodScrollIntoView(
+      periodList,
+      purchaseData.selectedPeriod
+    );
     this.setData({
       list: purchaseData.list,
-      periodList: purchaseData.periodList,
+      periodList,
       selectedPeriod: purchaseData.selectedPeriod,
       periodScrollIntoView,
       instrumentList: purchaseData.instrumentList,
@@ -399,7 +425,8 @@ Page({
       this.onFormatGoods()
     });
   },
-  async onInitTeacherVip() {
+  async onInitTeacherVip(requestId: number) {
+    const userType = PURCHASE_TYPE.TEACHER;
     try {
       const { data } = await api_queryByParamNameList({
         paramNames: TEACHER_VIP_PARAM_NAME
@@ -452,10 +479,16 @@ Page({
         selectedInstrument: {},
         showBonusGift: Boolean(formatGiftText(selected))
       };
-      purchaseDataCache[PURCHASE_TYPE.TEACHER] = purchaseData;
+      purchaseDataCache[userType] = purchaseData;
+      if (requestId !== purchaseDataRequestId || this.data.userTypes !== userType) {
+        return;
+      }
       this.applyPurchaseData(purchaseData);
     } catch (e) {
       console.log(e, "e");
+      if (requestId !== purchaseDataRequestId || this.data.userTypes !== userType) {
+        return;
+      }
       this.setData({
         list: [],
         instrumentList: [],
@@ -629,7 +662,28 @@ Page({
       return
     }
     this.setData({
-      userTypes: dataset.type
+      userTypes: dataset.type,
+      list: [],
+      periodList: [],
+      selectedPeriod: '',
+      periodScrollIntoView: '',
+      instrumentList: [],
+      selected: {},
+      selectInstrumentId: '',
+      selectedInstrument: {},
+      showBonusGift: false,
+      formatSelectGood: {
+        typeName: '',
+        name: '',
+        productImage: '',
+        giftText: '',
+        showSalePrice: '',
+        originalPrice: 0,
+        salePrice: 0,
+        discountPrice: '',
+        integerPart: '',
+        decimalPart: '',
+      }
     }, () => {
       // 这里可以根据用户类型重新加载商品数据
       // 目前先保持逻辑不变,后续可根据后端 API 扩展
@@ -639,8 +693,12 @@ Page({
   /** 选择期限 */
   onSelectPeriod(e: any) {
     const { value } = e.currentTarget.dataset
-    const periodItem = this.data.periodList.find((item: any) => item.value === value)
+    const periodItem = this.data.periodList.find((item: any) => String(item.value) === String(value))
     if (periodItem?.disabled) {
+      wx.showToast({
+        title: '暂无库存',
+        icon: 'none',
+      });
       return
     }
 
@@ -649,15 +707,26 @@ Page({
       return
     }
 
+    const selectedPeriod = String(value);
+    const periodList = markPeriodListActive(this.data.periodList, selectedPeriod);
     this.setData({
-      selectedPeriod: String(value),
+      periodList,
+      selectedPeriod,
       selected: selectedItem,
-      periodScrollIntoView: getPeriodScrollIntoView(this.data.periodList, String(value)),
+      periodScrollIntoView: getPeriodScrollIntoView(periodList, selectedPeriod),
       showBonusGift: Boolean(formatGiftText(selectedItem))
     }, () => {
       // 根据选中的期限更新商品
       this.onFormatGoods()
     })
+    syncPurchaseDataCache(this.data.userTypes, {
+      periodList,
+      selectedPeriod,
+      selected: selectedItem,
+      selectInstrumentId: this.data.selectInstrumentId,
+      selectedInstrument: this.data.selectedInstrument,
+      showBonusGift: Boolean(formatGiftText(selectedItem))
+    });
   },
   /** 根据期限更新商品列表 */
   onUpdatePeriodList() {

+ 1 - 1
miniprogram/pages/index/index.wxml

@@ -122,7 +122,7 @@
           <view class="section-label">选择期限</view>
           <scroll-view class="period-options-scroll" scroll-x="{{true}}" enhanced="{{true}}" show-scrollbar="{{false}}" scroll-into-view="{{ periodScrollIntoView }}" scroll-with-animation="{{true}}">
             <view class="period-options">
-              <view wx:for="{{ periodList }}" wx:key="value" id="{{ item.viewId }}" class="period-btn {{ selectedPeriod === item.value ? 'active' : '' }}" bind:tap="onSelectPeriod" data-value="{{ item.value }}">
+              <view wx:for="{{ periodList }}" wx:key="value" id="{{ item.viewId }}" class="period-btn {{ item.active ? 'active' : '' }} {{ item.disabled ? 'disabled' : '' }}" catch:tap="onSelectPeriod" data-value="{{ item.value }}">
                 {{ item.label }}
               </view>
             </view>

BIN
miniprogram/pages/orders/images/border.png


BIN
miniprogram/pages/orders/images/icon-copy-link.png


BIN
miniprogram/pages/orders/images/student-use-qrcode.png


+ 65 - 0
miniprogram/pages/orders/order-detail.less

@@ -282,8 +282,10 @@ page {
 
 .addPhone {
   padding: 12rpx 24rpx;
+  display: block;
   .van-cell {
     padding-left: 0;
+    padding-right: 0;
   }
   .van-field__label {
     font-weight: 600;
@@ -294,6 +296,27 @@ page {
     max-width: 5em !important;
     min-width: 5em !important;
   }
+  .sms-code-btn {
+    min-width: 180rpx;
+    font-weight: 500;
+    font-size: 28rpx;
+    color: #0088FF;
+    line-height: 40rpx;
+    display: flex;
+    align-items: center;
+    justify-content: flex-end;
+
+    &.disabled {
+      // color: #999999;
+      color: rgba(0,136,255,0.4);
+    }
+  }
+  .sms-code-divider {
+    width: 2rpx;
+    height: 28rpx;
+    margin-right: 24rpx;
+    background-color: #E5E5E5;
+  }
 }
 
 .select-address {
@@ -792,6 +815,48 @@ page {
   }
 }
 
+.img-code-section {
+  width: 620rpx;
+  padding: 56rpx 32rpx 36rpx;
+  box-sizing: border-box;
+
+  .img-code-title {
+    font-weight: 600;
+    font-size: 32rpx;
+    color: #131415;
+    line-height: 44rpx;
+    text-align: center;
+    padding-bottom: 32rpx;
+  }
+
+  .img-code-row {
+    display: flex;
+    align-items: center;
+    border: 2rpx solid #f0f0f0;
+    border-radius: 12rpx;
+    overflow: hidden;
+  }
+
+  .img-code-input {
+    flex: 1;
+  }
+
+  .img-code-image {
+    width: 220rpx;
+    height: 88rpx;
+    flex-shrink: 0;
+    background: #f7f7f7;
+  }
+
+  .img-code-change {
+    padding-top: 24rpx;
+    text-align: right;
+    font-size: 26rpx;
+    color: #6d4718;
+    line-height: 36rpx;
+  }
+}
+
 .empty-box {
   text-align: center;
   font-size: 32rpx;

+ 127 - 6
miniprogram/pages/orders/order-detail.ts

@@ -1,11 +1,13 @@
-// pages/orders/order-detail.ts
-import { api_executeOrderV2, api_executePayment, api_queryByParamName, api_userPaymentOrderDetail, api_userPaymentOrderUnpaid } from "../../api/login";
+// pages/orders/order-detail.ts
+import { api_executeOrderV2, api_executePayment, api_queryByParamName, api_sendImgCode, api_sendSmsVerify, api_userPaymentOrderDetail, api_userPaymentOrderUnpaid } from "../../api/login";
 import { api_sysAreaQueryAllProvince, api_trackPointLog, api_userReceiveAddressPage, api_userReceiveAddressRemove, api_userReceiveAddressSave, api_userReceiveAddressUpdate } from "../../api/new";
 import { formatPrice, formatTime, GRADE_ENUM } from "../../utils/util";
 
 // 获取应用实例
 const app = getApp<IAppOption>()
 const DEFAULT_ORDER_TYPE = "WECHAT_MINI"
+const SMS_COUNT_DOWN = 120
+let smsTimer: ReturnType<typeof setInterval> | null = null
 Page({
   /**
    * 页面的初始数据
@@ -31,6 +33,13 @@ Page({
     },
     userNote: '', // 购买人手机号
     userBeneficiaryId: '', // 添加购买人信息
+    smsCode: '',
+    smsCountDown: SMS_COUNT_DOWN,
+    smsCounting: false,
+    imgCodeShow: false,
+    imgCodeUrl: '',
+    imgCode: '',
+    imgCodeSending: false,
     userBeneficiaryInfo: {
       name: '',
       phoneNumber: '',
@@ -333,6 +342,106 @@ Page({
     })
   },
   // 购买
+  isValidPhone(phone: string) {
+    return /^1[3456789]\d{9}$/.test(phone)
+  },
+  async onSendSmsCode() {
+    if (this.data.smsCounting) return
+    if (!this.data.userNote || !this.isValidPhone(this.data.userNote)) {
+      wx.showToast({
+        title: '\u8bf7\u8f93\u5165\u6b63\u786e\u7684\u624b\u673a\u53f7',
+        icon: "none"
+      })
+      return
+    }
+    this.setData({
+      imgCodeShow: true,
+      imgCode: ''
+    })
+    await this.sendImgCode()
+  },
+  async sendImgCode() {
+    try {
+      const { data }: any = await api_sendImgCode({
+        phone: this.data.userNote
+      })
+      this.setData({
+        imgCodeUrl: data.data || data
+      })
+    } catch {
+      //
+    }
+  },
+  onCloseImgCode() {
+    this.setData({
+      imgCodeShow: false,
+      imgCode: ''
+    })
+  },
+  onRefreshImgCode() {
+    this.setData({
+      imgCode: ''
+    })
+    this.sendImgCode()
+  },
+  async onImgCodeChange(e: any) {
+    const code = e.detail
+    if (code.length < 4 || this.data.imgCodeSending) return
+    this.setData({
+      imgCodeSending: true
+    })
+    try {
+      await api_sendSmsVerify({
+        code,
+        clientId: 'cooleshow-student',
+        type: 'REGISTER',
+        mobile: this.data.userNote
+      })
+      wx.showToast({
+        title: '\u9a8c\u8bc1\u7801\u5df2\u53d1\u9001',
+        icon: 'none'
+      })
+      this.onCloseImgCode()
+      this.startSmsCountDown()
+    } catch {
+      this.setData({
+        imgCode: ''
+      })
+      setTimeout(() => {
+        this.sendImgCode()
+      }, 2000)
+    } finally {
+      this.setData({
+        imgCodeSending: false
+      })
+    }
+  },
+  startSmsCountDown() {
+    if (smsTimer) {
+      clearInterval(smsTimer)
+    }
+    this.setData({
+      smsCounting: true,
+      smsCountDown: SMS_COUNT_DOWN
+    })
+    smsTimer = setInterval(() => {
+      const next = this.data.smsCountDown - 1
+      if (next <= 0) {
+        if (smsTimer) {
+          clearInterval(smsTimer)
+          smsTimer = null
+        }
+        this.setData({
+          smsCounting: false,
+          smsCountDown: SMS_COUNT_DOWN
+        })
+        return
+      }
+      this.setData({
+        smsCountDown: next
+      })
+    }, 1000)
+  },
   async onSubmit() {
     if (!this.data.receiveAddress && this.data.hasInstrument) {
       wx.showToast({
@@ -344,7 +453,7 @@ Page({
 
     console.log(this.data, 'data - info')
 
-    if (!this.data.userNote || !/^1[3456789]\d{9}$/.test(this.data.userNote)) {
+    if (!this.data.userNote || !this.isValidPhone(this.data.userNote)) {
       wx.showToast({
         title: '请输入正确的手机号',
         icon: "none"
@@ -352,6 +461,14 @@ Page({
       return
     }
     // if (!this.data.userBeneficiaryId) {
+    if (!this.data.smsCode || !/^\d{6}$/.test(this.data.smsCode)) {
+      wx.showToast({
+        title: '\u8bf7\u8f93\u51656\u4f4d\u77ed\u4fe1\u9a8c\u8bc1\u7801',
+        icon: "none"
+      })
+      return
+    }
+    // if (!this.data.userBeneficiaryId) {
     //   wx.showToast({
     //     title: '请添加购买人',
     //     icon: 'none'
@@ -408,6 +525,7 @@ Page({
           receiveAddress: this.data.receiveAddress,
           userBeneficiaryId: this.data.userBeneficiaryId,
           userNote: this.data.userNote,
+          smsCode: this.data.smsCode,
           "orderName": name,
           "orderDesc": name
         })
@@ -465,7 +583,7 @@ Page({
         } else if(res.data.code === 5428) {
           wx.showToast({ title: res.data.message, icon: 'success' });
           wx.redirectTo({
-            url: '/pages/orders/order-result?orderNo=' + orderNo
+            url: '/pages/orders/order-result?orderNo=' + orderNo + '&orderType=' + this.data.orderType
           })
         } else {
           this.onPayError(res.data.message)
@@ -492,7 +610,7 @@ Page({
       success() {
         wx.showToast({ title: '支付成功', icon: 'success' });
         wx.redirectTo({
-          url: '/pages/orders/order-result?orderNo=' + orderNo
+          url: '/pages/orders/order-result?orderNo=' + orderNo + '&orderType=' + that.data.orderType
         })
       },
       fail(ressonInfo) {
@@ -808,7 +926,10 @@ Page({
    * 生命周期函数--监听页面卸载
    */
   onUnload() {
-
+    if (smsTimer) {
+      clearInterval(smsTimer)
+      smsTimer = null
+    }
   },
 
   /**

+ 19 - 2
miniprogram/pages/orders/order-detail.wxml

@@ -53,7 +53,7 @@
         </view>
 
       </view>
-      <view class="select-section" bind:tap="onTagAddress" wx:if="{{ !receiveAddress && hasInstrument }}" wx:key="receiveAddress">
+      <!-- <view class="select-section" bind:tap="onTagAddress" wx:if="{{ !receiveAddress && hasInstrument }}" wx:key="receiveAddress">
         <view class="name">请选择收货地址</view>
         <image src="./images/icon-arrow.png" class="icon-arrow" />
       </view>
@@ -68,12 +68,19 @@
           </view>
         </view>
         <image src="./images/icon-arrow.png" wx:if="{{ !goodsInfo.orderNo }}" class="icon-arrow" />
-      </view>
+      </view> -->
 
       <view class="select-section addPhone" wx:if="{{!goodsInfo.orderNo}}">
         <van-field style="width: 100%" border="{{false}}" model:value="{{ userNote }}" maxlength="11" type="number" placeholder="请输入购买人手机号码" >
           <view class="required" slot="label">手机号码</view>
         </van-field>
+        <van-field style="width: 100%" border="{{false}}" model:value="{{ smsCode }}" maxlength="6" type="number" placeholder="请输入短信验证码" >
+          <view class="required" slot="label">验证码</view>
+          <view class="sms-code-btn {{ smsCounting ? 'disabled' : '' }}" slot="button" bind:tap="onSendSmsCode">
+            <view class="sms-code-divider"></view>
+            <text>{{ smsCounting ? smsCountDown + 's后重试' : '发送验证码' }}</text>
+          </view>
+        </van-field>
       </view>
       <!-- <view class="select-section" wx:if="{{ !userBeneficiaryId }}" wx:key="userBeneficiaryId">
         <view class="name">添加购买人</view>
@@ -231,5 +238,15 @@
         </view>
       </view>
     </van-popup>
+    <van-popup round lock-scroll="{{true}}" closeable z-index="{{103}}" show="{{imgCodeShow}}" bind:close="onCloseImgCode">
+      <view class="img-code-section">
+        <view class="img-code-title">输入图形验证码</view>
+        <view class="img-code-row">
+          <van-field class="img-code-input" border="{{false}}" model:value="{{ imgCode }}" maxlength="4" placeholder="请输入验证码" bind:change="onImgCodeChange" />
+          <image class="img-code-image" src="{{ imgCodeUrl }}" mode="aspectFill" bind:tap="onRefreshImgCode" />
+        </view>
+        <view class="img-code-change" bind:tap="onRefreshImgCode">看不清?换一换</view>
+      </view>
+    </van-popup>
   </view>
 </page-meta>

+ 155 - 1
miniprogram/pages/orders/order-result.less

@@ -590,6 +590,160 @@ page {
   }
 }
 
+.usage-guide {
+  margin: 24rpx 26rpx 0;
+}
+
+.usage-guide__header {
+  height: 198rpx;
+  padding: 24rpx;
+  box-sizing: border-box;
+  border: 2rpx solid #ffffff;
+  border-radius: 24rpx;
+  background: linear-gradient(90deg, #0077FF 0%, #00BBFF 100%);
+  display: flex;
+  justify-content: space-between;
+}
+
+.usage-guide__title {
+  font-weight: 700;
+  font-size: 36rpx;
+  color: #FFFFFF;
+  line-height: 44rpx;
+}
+
+.usage-guide__subtitle {
+  max-width: 442rpx;
+  font-family: Arial, sans-serif;
+  font-size: 36rpx;
+  color: rgba(255, 255, 255, 0.18);
+  line-height: 44rpx;
+  white-space: nowrap;
+  margin-top: 6rpx;
+}
+
+.usage-guide__content {
+  margin-top: -100rpx;
+  min-height: 396rpx;
+  padding: 24rpx;
+  box-sizing: border-box;
+  border: 2rpx solid #ffffff;
+  border-radius: 24rpx;
+  background: linear-gradient(180deg, #FFFFFF 70%, #E1F5FF 100%);
+  position: relative;
+  z-index: 1;
+
+  &.student {
+    min-height: 440rpx;
+    background: linear-gradient(180deg, #FFFFFF 80%, #E0F0FF 100%);
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+  }
+
+  &.teacher {
+    display: flex;
+    flex-direction: column;
+  }
+}
+
+.usage-guide__steps {
+  position: absolute;
+  top: 24rpx;
+  left: 12rpx;
+  display: flex;
+  flex-direction: column;
+  gap: 26rpx;
+}
+
+.usage-guide__step {
+  width: 40rpx;
+  height: 44rpx;
+  border-radius: 12rpx;
+  background: #C2EBFF;
+  font-weight: 700;
+  font-size: 26rpx;
+  color: #131415;
+  line-height: 44rpx;
+  text-align: center;
+}
+
+.usage-guide__text {
+  padding-left: 52rpx;
+  font-size: 28rpx;
+  color: #131415;
+  line-height: 44rpx;
+}
+
+.usage-guide__paragraph {
+  margin-top: 24rpx;
+}
+
+.usage-guide__link {
+  color: #0088FF;
+}
+
+.usage-guide__copy-btn {
+  width: 446rpx;
+  height: 80rpx;
+  margin: 24rpx auto 0;
+  padding: 0;
+  border-radius: 84rpx;
+  background: #0088FF;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 32rpx;
+  color: #FFFFFF;
+  line-height: 44rpx;
+
+  &::after {
+    border: none;
+  }
+
+  image {
+    width: 36rpx;
+    height: 36rpx;
+    margin-right: 12rpx;
+  }
+}
+
+.usage-guide__student-text {
+  width: 100%;
+  font-size: 28rpx;
+  color: #131415;
+  line-height: 44rpx;
+
+  text {
+    color: #0088FF;
+  }
+}
+
+.usage-guide__qrcode {
+  position: relative;
+  width: 280rpx;
+  height: 264rpx;
+  margin-top: 32rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.usage-guide__qrcode__bg {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+}
+
+.usage-guide__qrcode__img {
+  position: relative;
+  z-index: 10;
+  width: 224rpx;
+  height: 224rpx;
+}
+
 .scroll-brank {
   height: 44rpx;
   width: 100%;
@@ -812,4 +966,4 @@ page {
       color: #777777;
     }
   }
-}
+}

+ 43 - 1
miniprogram/pages/orders/order-result.ts

@@ -3,6 +3,28 @@
 import { api_userPaymentCancelRefund, api_userPaymentOrderDetail } from "../../api/login";
 import { formatPrice, GRADE_ENUM } from "../../utils/util";
 
+const DEFAULT_ORDER_TYPE = "WECHAT_MINI"
+const TEACHER_ORDER_TYPE = "TEACHER_VIP"
+const TEACHER_USAGE_URL = "https://kt.colexiu.com"
+
+function resolveOrderType(result: any, currentOrderType: string) {
+  if (result.orderType || result.paymentType) {
+    return result.orderType || result.paymentType
+  }
+
+  const text = [
+    result.orderName,
+    result.orderDesc,
+    ...(result.goodsInfos || []).map((item: any) => item.goodsName || item.name)
+  ].filter(Boolean).join(' ')
+
+  if (/老师|教师|teacher/i.test(text)) {
+    return TEACHER_ORDER_TYPE
+  }
+
+  return currentOrderType || DEFAULT_ORDER_TYPE
+}
+
 // 获取应用实例
 Page({
   /**
@@ -46,6 +68,9 @@ Page({
     timerCount: 0,
     timer: null as any,
     goodsInfo: {} as any,
+    orderType: DEFAULT_ORDER_TYPE,
+    isTeacherOrder: false,
+    teacherUsageUrl: TEACHER_USAGE_URL,
     // tabIdx: 0, // 当前是从哪个tab来的
     orderNo: "" as string,
     showCanvas: false, // 是否显示二维码
@@ -59,8 +84,11 @@ Page({
    */
   onLoad(options: any) {
     if (options.orderNo) {
+      const orderType = options.orderType || DEFAULT_ORDER_TYPE
       this.setData({
         orderNo: options.orderNo,
+        orderType,
+        isTeacherOrder: orderType === TEACHER_ORDER_TYPE,
         // tabIdx: options.tabIdx
       });
     }
@@ -85,6 +113,7 @@ Page({
       });
       if (data.code == 200) {
         const result = data.data || {}
+        const orderType = resolveOrderType(result, this.data.orderType)
         const goodsInfos = result.goodsInfos || []
         const tempGoods: any = []
         goodsInfos.forEach((item: any) => {
@@ -129,7 +158,9 @@ Page({
         }
         this.setData({
           goodsInfo,
-          status: result.wechatStatus
+          status: result.wechatStatus,
+          orderType,
+          isTeacherOrder: orderType === TEACHER_ORDER_TYPE
         })
       }
     } catch (error) {
@@ -209,6 +240,17 @@ Page({
       }
     })
   },
+  onCopyTeacherLink() {
+    wx.setClipboardData({
+      data: TEACHER_USAGE_URL,
+      success: () => {
+        wx.showToast({ title: '复制成功', icon: 'none' })
+      },
+      fail: () => {
+        wx.showToast({ title: '复制失败,请稍后再试', icon: 'none' })
+      }
+    })
+  },
   onActivation(e: { currentTarget: any }) {
     const code = e.currentTarget.dataset.code || ''
     if (!code) {

+ 42 - 2
miniprogram/pages/orders/order-result.wxml

@@ -50,7 +50,7 @@
       </view>
     </view>
 
-    <view class="select-section select-address" wx:if="{{ goodsInfo.addresses.id }}" wx:key="receiveAddress">
+    <!-- <view class="select-section select-address" wx:if="{{ goodsInfo.addresses.id }}" wx:key="receiveAddress">
       <view class="address-info">
         <view class="address-text">
           {{ goodsInfo.addresses.addressDetail }}
@@ -60,7 +60,7 @@
           <text>{{ goodsInfo.addresses.phoneNumber }}</text>
         </view>
       </view>
-    </view>
+    </view> -->
 
     <view class="select-section select-buy-user" wx:if="{{ goodsInfo.beneficiary.id }}" wx:key="userBeneficiaryId">
       <view class="title">
@@ -100,6 +100,46 @@
         <view class="value">{{ goodsInfo.createTime }}</view>
       </view>
     </view>
+
+    <view class="usage-guide">
+      <view class="usage-guide__header">
+        <view class="usage-guide__title">使用说明</view>
+        <view class="usage-guide__subtitle">INSTRUCTIONS FOR USE</view>
+      </view>
+
+      <view class="usage-guide__content {{ isTeacherOrder ? 'teacher' : 'student' }}">
+        <block wx:if="{{ isTeacherOrder }}">
+          <view class="usage-guide__steps">
+            <view class="usage-guide__step">1</view>
+            <view class="usage-guide__step">2</view>
+          </view>
+          <view class="usage-guide__text">
+            <view>老师端兼容电脑、一体机及希沃白板等设备。</view>
+            <view class="usage-guide__paragraph">
+              购买完成后,建议您使用谷歌浏览器访问
+              <text class="usage-guide__link">{{ teacherUsageUrl }}</text>
+              ,通过预留的手机号与默认密码(yyszkt+手机号)进行登录。祝您使用愉快,畅享全新授课体验!
+            </view>
+          </view>
+          <button class="usage-guide__copy-btn" bind:tap="onCopyTeacherLink">
+            <image src="./images/icon-copy-link.png" mode="aspectFit"></image>
+            <text>复制链接</text>
+          </button>
+        </block>
+
+        <block wx:else>
+          <view class="usage-guide__student-text">
+            扫描下方二维码或者在应用市场下载
+            <text>【音乐数字课堂】</text>
+            ,开启您全新的音乐之旅!
+          </view>
+          <view class="usage-guide__qrcode">
+            <image class="usage-guide__qrcode__bg" src="./images/border.png" mode="aspectFit"></image>
+            <image class="usage-guide__qrcode__img" src="./images/student-use-qrcode.png" mode="aspectFit"></image>
+          </view>
+        </block>
+      </view>
+    </view>
     <!-- <view class="order-content" wx:if="{{ (goodsInfo.wechatStatus == 'PAID' || goodsInfo.wechatStatus == 'WAIT_USE') && showCanvas }}">
       <view class="qrcode-text" wx:if="{{goodsInfo.wechatStatus == 'WAIT_USE'}}"><text>扫描二维码</text>或<text>点击激活按钮</text>使用<block wx:if="{{ goodsInfo.giftStatus === 'WAIT_GIFT' }}">
           ,<text class="free">当天激活</text><text class="free blod">赠{{ goodsInfo.giftLongTime }}</text>

+ 3 - 1
miniprogram/pages/orders/orders.ts

@@ -252,8 +252,10 @@ Page({
         url: `../orders/order-detail?orderInfo=${info}&orderNo=${orderDetail.orderNo}&status=${orderDetail.wechatStatus}&orderType=${orderDetail.orderType || orderDetail.paymentType || DEFAULT_ORDER_TYPE}`,
       });
     } else {
+      const orderDetail: any = this.data.recordList.find((item: any) => item.orderNo === dataset.orderno)
+      const orderType = orderDetail?.orderType || orderDetail?.paymentType || DEFAULT_ORDER_TYPE
       wx.navigateTo({
-        url: `../orders/order-result?orderNo=${dataset.orderno}&tabIdx=${this.data.tabIdx}`
+        url: `../orders/order-result?orderNo=${dataset.orderno}&tabIdx=${this.data.tabIdx}&orderType=${orderType}`
       })
     }
   },