Explorar o código

feat: 修改支付逻辑

lex-xin hai 4 días
pai
achega
d19be5bf6b

+ 13 - 5
miniprogram/api/login.ts

@@ -49,7 +49,7 @@ export const api_executeOrder = (params: any) => {
 };
 export const api_executeOrderV2 = (params: any) => {
   return request({
-    url: `/edu-app/userPaymentOrder/miniProgramExecuteOrderV2`,
+    url: `/edu-app/open/userPaymentOrder/miniProgramExecuteOrderV2`,
     method: "post",
     data: params,
   } as any);
@@ -67,7 +67,7 @@ export const api_executePayment = (params: any) => {
 /** 查询待支付信息 */
 export const api_userPaymentOrderUnpaid = (params: any) => {
   return request({
-    url: `/edu-app/userPaymentOrder/unpaid`,
+    url: `/edu-app/open/userPaymentOrder/unpaid`,
     method: "get",
     data: params,
   } as any);
@@ -83,9 +83,17 @@ export const api_queryByParamName = (params: any) => {
 };
 
 /** 订单列表 */
+export const api_queryByParamNameList = (params: any) => {
+  return request({
+    url: `/edu-app/open/paramConfig/queryByParamNameList`,
+    method: "get",
+    data: params,
+  } as any);
+};
+
 export const api_studentOrderPage = (params: any) => {
   return request({
-    url: `/edu-app/userPaymentOrder/studentOrderPage`,
+    url: `/edu-app/open/userPaymentOrder/orderPage`,
     method: "post",
     data: params,
   } as any);
@@ -95,7 +103,7 @@ export const api_studentOrderPage = (params: any) => {
 /** 订单详情 */
 export const api_userPaymentOrderDetail = (orderNo: string, params?: any) => {
   return request({
-    url: `/edu-app/userPaymentOrder/detail/${orderNo}`,
+    url: `/edu-app/open/userPaymentOrder/detail/${orderNo}`,
     method: "get",
     data: params
   } as any);
@@ -126,4 +134,4 @@ export const api_cozeAgent = (data: { message: string; userId?: string, openId?:
     noToken: true,
     data
   } as any);
-};
+};

+ 137 - 98
miniprogram/pages/index/index.less

@@ -345,17 +345,18 @@ page {
     width: 100%;
     background: #ffffff;
     border-radius: 32rpx 32rpx 0 0;
-    padding: 32rpx 32rpx 40rpx;
+    padding: 24rpx 32rpx 0;
     box-sizing: border-box;
+    overflow: hidden;
   }
 
   .iconClose {
     position: absolute;
-    top: 24rpx;
-    right: 24rpx;
-    width: 44rpx;
-    height: 44rpx;
-    padding: 20rpx;
+    top: 48rpx;
+    right: 32rpx;
+    width: 30rpx;
+    height: 30rpx;
+    padding: 24rpx;
     box-sizing: content-box;
     z-index: 11;
   }
@@ -365,22 +366,22 @@ page {
 .user-type-tabs {
   display: flex;
   align-items: center;
-  justify-content: center;
-  margin-bottom: 32rpx;
-  background: #f0f0f0;
-  border-radius: 32rpx;
-  padding: 4rpx;
-  width: fit-content;
-  margin-left: auto;
-  margin-right: auto;
+  width: 442rpx;
+  height: 76rpx;
+  margin: 0 auto 40rpx;
+  padding: 6rpx;
+  box-sizing: border-box;
+  background: rgba(21, 23, 28, 0.05);
+  border-radius: 146rpx;
 
   .tab-item {
-    padding: 16rpx 56rpx;
+    width: 212rpx;
+    height: 64rpx;
+    line-height: 64rpx;
     font-size: 28rpx;
-    color: #666666;
-    border-radius: 28rpx;
+    color: #15171c;
+    border-radius: 104rpx;
     transition: all 0.3s;
-    min-width: 120rpx;
     text-align: center;
 
     &.active {
@@ -394,72 +395,62 @@ page {
 // 商品信息卡片
 .product-info-card {
   display: flex;
-  background: #faf8f5;
-  border-radius: 16rpx;
-  padding: 24rpx;
-  margin-bottom: 32rpx;
+  align-items: center;
+  min-height: 180rpx;
+  margin-bottom: 48rpx;
+  background: #ffffff;
 
-  .product-badge {
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    justify-content: center;
+  .product-image {
+    width: 180rpx;
+    height: 180rpx;
     margin-right: 24rpx;
     flex-shrink: 0;
-
-    .duration-text {
-      width: 88rpx;
-      height: 88rpx;
-      background: linear-gradient(135deg, #ff9a76 0%, #ff6b6b 100%);
-      border-radius: 16rpx;
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      font-size: 26rpx;
-      color: #ffffff;
-      font-weight: 600;
-    }
-
-    .user-label {
-      font-size: 22rpx;
-      color: #ff6b6b;
-      background: rgba(255, 107, 107, 0.1);
-      padding: 4rpx 16rpx;
-      border-radius: 8rpx;
-      margin-top: 8rpx;
-    }
+    border-radius: 24rpx;
+    overflow: hidden;
+    background: #f6f6f6;
   }
 
   .product-detail {
     flex: 1;
+    min-width: 0;
     display: flex;
     flex-direction: column;
+    justify-content: center;
 
     .product-name {
-      font-size: 28rpx;
-      color: #333333;
-      font-weight: 600;
+      font-size: 32rpx;
+      color: #15171c;
+      font-weight: 500;
       margin-bottom: 12rpx;
-      line-height: 40rpx;
+      line-height: 44rpx;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
     }
 
     .price-line {
       display: flex;
       align-items: baseline;
-      margin-bottom: 8rpx;
+      height: 58rpx;
+      margin-bottom: 12rpx;
 
       .price-tag {
+        width: 100rpx;
+        height: 46rpx;
+        line-height: 46rpx;
         font-size: 24rpx;
-        color: #ff6b6b;
-        margin-right: 8rpx;
-        background: rgba(255, 107, 107, 0.1);
-        padding: 2rpx 8rpx;
-        border-radius: 4rpx;
+        color: #7d3f00;
+        margin-right: 12rpx;
+        background: linear-gradient(90deg, #feeac3 0%, #ffdeb0 100%);
+        border-radius: 8rpx;
+        text-align: center;
+        font-weight: 500;
       }
 
       .price-num {
-        font-size: 36rpx;
-        color: #333333;
+        font-size: 48rpx;
+        line-height: 58rpx;
+        color: #15171c;
         font-weight: 700;
       }
     }
@@ -467,25 +458,27 @@ page {
     .origin-line {
       display: flex;
       align-items: center;
-      font-size: 22rpx;
-      color: #999999;
+      min-width: 0;
+      font-size: 24rpx;
+      color: #8a8d93;
+      line-height: 34rpx;
 
       .origin-tag {
-        margin-right: 4rpx;
+        margin-right: 8rpx;
       }
 
       .origin-num {
         text-decoration: line-through;
-        margin-right: 12rpx;
+        margin-right: 8rpx;
       }
 
       .divider {
-        margin: 0 12rpx;
-        color: #cccccc;
+        display: none;
       }
 
       .sold-count {
-        color: #999999;
+        color: #8a8d93;
+        white-space: nowrap;
       }
     }
   }
@@ -493,36 +486,52 @@ page {
 
 // 选择期限
 .period-select-section {
-  margin-bottom: 24rpx;
+  margin-bottom: 48rpx;
 
   .section-label {
     font-size: 28rpx;
-    color: #333333;
+    color: #15171c;
     font-weight: 500;
-    margin-bottom: 20rpx;
+    line-height: 40rpx;
+    margin-bottom: 16rpx;
+  }
+
+  .period-options-scroll {
+    width: 100%;
+    white-space: nowrap;
   }
 
   .period-options {
-    display: flex;
-    gap: 16rpx;
+    display: inline-flex;
+    align-items: center;
+    padding-left: 4rpx;
+    padding-right: 32rpx;
+    box-sizing: border-box;
 
     .period-btn {
-      flex: 1;
-      height: 72rpx;
+      flex: none;
+      min-width: 96rpx;
+      height: 68rpx;
+      padding: 0 24rpx;
+      margin-right: 16rpx;
+      box-sizing: border-box;
       display: flex;
       align-items: center;
       justify-content: center;
-      background: #f5f5f5;
-      border-radius: 12rpx;
-      font-size: 26rpx;
-      color: #666666;
-      border: 2rpx solid transparent;
+      background: #f6f6f6;
+      border-radius: 16rpx;
+      font-size: 28rpx;
+      color: #15171c;
+      border: none;
       transition: all 0.2s;
 
+      &:last-child {
+        margin-right: 0;
+      }
+
       &.active {
-        background: #ffffff;
-        border: 2rpx solid #333333;
-        color: #333333;
+        background: #fff1d6;
+        color: #15171c;
         font-weight: 600;
       }
     }
@@ -530,40 +539,70 @@ page {
 }
 
 // 额外赠送
+.gift-label {
+  margin-bottom: 16rpx;
+  font-weight: 500;
+  font-size: 28rpx;
+  color: #15171c;
+  line-height: 40rpx;
+}
+
 .gift-section {
-  background: #f5f5f5;
-  border-radius: 12rpx;
-  padding: 20rpx 24rpx;
-  margin-bottom: 32rpx;
+  display: inline-flex;
+  align-items: center;
+  min-width: 310rpx;
+  height: 68rpx;
+  padding: 0 28rpx;
+  margin-bottom: 48rpx;
+  box-sizing: border-box;
+  background: #fff1d6;
+  border-radius: 16rpx;
 
   .gift-desc {
-    font-size: 26rpx;
-    color: #666666;
+    font-size: 28rpx;
+    color: #15171c;
+    font-weight: 500;
+    line-height: 40rpx;
   }
 }
 
 // 底部结算栏
 .settlement-bar {
+  width: 750rpx;
+  margin-left: -32rpx;
+  padding: 24rpx 32rpx 58rpx;
+  box-sizing: border-box;
+  background: #ffffff;
+
   .select-summary {
     display: flex;
     align-items: center;
-    font-size: 24rpx;
-    color: #666666;
-    margin-bottom: 20rpx;
-    padding: 0 8rpx;
+    min-width: 0;
+    font-size: 26rpx;
+    color: #15171c;
+    line-height: 36rpx;
+    font-weight: 500;
+    margin-bottom: 24rpx;
+    padding: 0;
 
     .summary-label {
-      color: #999999;
-      margin-right: 8rpx;
+      color: #15171c;
+      flex-shrink: 0;
+      margin-right: 0;
     }
 
     .summary-content {
-      color: #333333;
+      color: #15171c;
+      min-width: 0;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
     }
 
     .summary-save {
-      color: #ff6b6b;
-      margin-left: 4rpx;
+      color: #fd7247;
+      flex-shrink: 0;
+      margin-left: 6rpx;
     }
   }
 

+ 187 - 47
miniprogram/pages/index/index.ts

@@ -1,10 +1,69 @@
 // index.ts
 
-import { api_shopInstruments, api_shopProduct } from "../../api/login";
+import { api_queryByParamNameList, api_shopInstruments, api_shopProduct } from "../../api/login";
 import { api_getOpenId, api_trackPointLog } from "../../api/new";
 import { debounce, formatPrice, formatTime } from "../../utils/util";
 // 获取应用实例
 const app = getApp<IAppOption>();
+const PURCHASE_TYPE = {
+  STUDENT: "WECHAT_MINI",
+  TEACHER: "TEACHER_VIP",
+};
+const TEACHER_VIP_PARAM_NAME = "teacher_vip_purchase_list";
+
+function getProductImage(item: any, userType: string) {
+  if (!item) {
+    return "";
+  }
+  if (userType === PURCHASE_TYPE.TEACHER) {
+    return item.coverImg || item.pic || "";
+  }
+  return item.pic || item.coverImg || "";
+}
+
+function parseTeacherVipList(paramValue: any) {
+  if (!paramValue) {
+    return [];
+  }
+  const value = typeof paramValue === "string" ? JSON.parse(paramValue) : paramValue;
+  if (Array.isArray(value)) {
+    return value;
+  }
+  return value.list || value.goodsList || value.packages || [];
+}
+
+function formatPeriodText(num: any, type: string) {
+  const unitText: any = {
+    DAY: "天",
+    MONTH: "个月",
+    YEAR: "年",
+  };
+  if (!num || !type) {
+    return "";
+  }
+  return `${num}${unitText[type] || ""}`;
+}
+
+function formatGiftText(item: any) {
+  if (!item) {
+    return "";
+  }
+  if (item.free?.number && item.free?.unit) {
+    return formatPeriodText(item.free.number, item.free.unit);
+  }
+  if (item.giftFlag && item.giftVipDay && item.giftPeriod) {
+    return formatPeriodText(item.giftVipDay, item.giftPeriod);
+  }
+  return "";
+}
+
+function buildPeriodList(list: any[]) {
+  return list.map((item: any) => ({
+    label: item.typeName || item.title || item.name || formatPeriodText(item.num, item.period),
+    value: String(item.id),
+    disabled: Number(item.stockNum ?? 1) <= 0,
+  }));
+}
 // pages/orders/orders.ts
 Page({
   /**
@@ -59,6 +118,9 @@ Page({
     selectedInstrument: {} as any,
     formatSelectGood: {
       typeName: '',
+      name: '',
+      productImage: '',
+      giftText: '',
       showSalePrice: '', // 显示的现价
       originalPrice: 0, // 原价
       salePrice: 0, // 现价
@@ -78,15 +140,9 @@ Page({
     titleControls: false, // 详情是否显示控制条
     liuControls: false, // 详情是否显示控制条
     bannerImageloaded: false, // Banner 图片是否加载完成
-    userTypes: 'teacher', // 用户类型:student | teacher
-    periodList: [
-      { label: '7 天', value: '7DAY', disabled: false },
-      { label: '14 天', value: '14DAY', disabled: false },
-      { label: '1 个月', value: '1MONTH', disabled: false },
-      { label: '6 个月', value: '6MONTH', disabled: false },
-      { label: '1 年', value: '1YEAR', disabled: false }
-    ],
-    selectedPeriod: '14DAY', // 选中的期限
+    userTypes: PURCHASE_TYPE.STUDENT, // 用户类型:WECHAT_MINI | TEACHER_VIP
+    periodList: [] as any,
+    selectedPeriod: '', // 选中的期限
     showBonusGift: false, // 是否显示额外赠送
   },
 
@@ -224,6 +280,10 @@ Page({
    * 获取基础信息
    */
   async onInit() {
+    if (this.data.userTypes === PURCHASE_TYPE.TEACHER) {
+      await this.onInitTeacherVip()
+      return
+    }
     try {
       const result = await api_shopInstruments({ appId: app.globalData.appId })
       const instrumentList = result.data.data || []
@@ -237,14 +297,18 @@ Page({
       let selected: any = {};
       let isOverSaled = true; // 是否销售完
       list.forEach((item: any) => {
-        item.originalPrice = formatPrice(item.originalPrice, "ALL");
-        item.showSalePrice = formatPrice(item.salePrice, "ALL");
-        item.typeName = this.formatPeriod(item.num, item.period);
+        const salePrice = Number(item.salePrice || 0);
+        const originalPrice = Number(item.originalPrice || salePrice);
+        item.originalPrice = originalPrice;
+        item.salePrice = salePrice;
+        item.showSalePrice = formatPrice(salePrice, "ALL");
+        item.showOriginalPrice = formatPrice(originalPrice, "ALL");
+        item.typeName = this.formatPeriod(Number(item.num), item.period);
         item.discountPrice = formatPrice(
-          item.originalPrice - item.salePrice,
+          originalPrice - salePrice,
           "ALL"
         );
-        const prices: any = formatPrice(item.salePrice);
+        const prices: any = formatPrice(salePrice);
         item.integerPart = prices.integerPart;
         item.decimalPart = prices.decimalPart;
         // 格式化赠送内容
@@ -265,20 +329,94 @@ Page({
 
       this.setData({
         list,
+        periodList: buildPeriodList(list),
+        selectedPeriod: selected?.id ? String(selected.id) : '',
         instrumentList, // 乐器列表
         isOverSaled,
         selected,
         selectInstrumentId: '',
-        selectedInstrument: {}
+        selectedInstrument: {},
+        showBonusGift: Boolean(formatGiftText(selected))
       }, () => {
         this.onFormatGoods()
-        this.onUpdatePeriodList()
       });
     } catch (e) {
       console.log(e, "e");
     }
   },
   // 格式化类型
+  async onInitTeacherVip() {
+    try {
+      const { data } = await api_queryByParamNameList({
+        paramNames: TEACHER_VIP_PARAM_NAME
+      });
+      const configList = data.data || [];
+      const config = Array.isArray(configList)
+        ? configList.find((item: any) => item.paramName === TEACHER_VIP_PARAM_NAME) || configList[0]
+        : configList;
+      const list = parseTeacherVipList(config?.paramValue).map((item: any, index: number) => {
+        const salePrice = Number(item.salePrice ?? item.currentPrice ?? item.price ?? item.paymentCashAmount ?? 0);
+        const originalPrice = Number(item.originalPrice ?? item.marketPrice ?? item.originalAmount ?? salePrice);
+        const period = item.period || item.unit;
+        const num = item.num ?? item.number;
+        const typeName = item.typeName || item.label || item.title || item.name || formatPeriodText(num, period);
+        const prices: any = formatPrice(salePrice);
+        return {
+          ...item,
+          id: item.id || item.goodsId || item.value || `${TEACHER_VIP_PARAM_NAME}_${index}`,
+          name: item.name || item.title || typeName,
+          pic: item.pic || item.coverImg || "",
+          coverImg: item.coverImg || item.pic || "",
+          shopId: item.shopId || "",
+          stockNum: item.stockNum ?? 999999,
+          originalPrice,
+          salePrice,
+          num,
+          period,
+          showSalePrice: formatPrice(salePrice, "ALL"),
+          showOriginalPrice: formatPrice(originalPrice, "ALL"),
+          discountPrice: formatPrice(originalPrice - salePrice, "ALL"),
+          typeName,
+          giftFlag: Boolean(item.free || item.giftFlag),
+          giftVipDay: item.free?.number ?? item.giftVipDay,
+          giftPeriod: item.free?.unit ?? item.giftPeriod,
+          integerPart: prices.integerPart,
+          decimalPart: prices.decimalPart,
+          goodsType: item.goodsType || PURCHASE_TYPE.TEACHER,
+        };
+      });
+      const selected = list.find((item: any) => item.isHot && item.stockNum > 0)
+        || list.find((item: any) => item.stockNum > 0)
+        || list[0]
+        || {};
+      this.setData({
+        list,
+        periodList: buildPeriodList(list),
+        selectedPeriod: selected?.id ? String(selected.id) : '',
+        instrumentList: [],
+        isOverSaled: !list.some((item: any) => item.stockNum > 0),
+        selected,
+        selectInstrumentId: '',
+        selectedInstrument: {},
+        showBonusGift: Boolean(formatGiftText(selected))
+      }, () => {
+        this.onFormatGoods()
+      });
+    } catch (e) {
+      console.log(e, "e");
+      this.setData({
+        list: [],
+        instrumentList: [],
+        isOverSaled: true,
+        selected: {},
+        selectInstrumentId: '',
+        selectedInstrument: {},
+        showBonusGift: false
+      }, () => {
+        this.onFormatGoods()
+      });
+    }
+  },
   formatPeriod(num: number, type: string) {
     const template: any = {
       DAY: "天卡",
@@ -317,6 +455,9 @@ Page({
   },
   /** 选中乐器 */
   onSelectInstrument(e: any) {
+    if (this.data.userTypes === PURCHASE_TYPE.TEACHER) {
+      return
+    }
     const { dataset } = e.currentTarget;
     if (dataset.id === this.data.selectInstrumentId) {
       this.setData({
@@ -341,8 +482,11 @@ Page({
     const selected = this.data.selected;
     const selectedInstrument = this.data.selectedInstrument
 
-    const params = {
+    const params: any = {
       typeName: '',
+      name: '',
+      productImage: '',
+      giftText: '',
       showSalePrice: '' as any, // 显示的现价
       originalPrice: 0, // 原价
       salePrice: 0, // 现价
@@ -353,6 +497,9 @@ Page({
     // 选中期限
     if (selected.id) {
       params.typeName = selected.typeName
+      params.name = selected.name
+      params.productImage = getProductImage(selected, this.data.userTypes)
+      params.giftText = formatGiftText(selected)
       params.showSalePrice = selected.showSalePrice
       params.originalPrice = selected.originalPrice
       params.salePrice = selected.salePrice
@@ -365,6 +512,7 @@ Page({
     // 选中乐器
     if (selectedInstrument.id) {
       params.typeName = selected.typeName ? selected.typeName + '+' + selectedInstrument.name : selectedInstrument.name
+      params.name = selected.name ? selected.name + '+' + selectedInstrument.name : selectedInstrument.name
       params.originalPrice = Number(selected.originalPrice) + Number(selectedInstrument.originalPrice)
       params.salePrice = Number(selected.salePrice) + Number(selectedInstrument.salePrice)
       params.showSalePrice = formatPrice(params.salePrice, "ALL");
@@ -449,44 +597,36 @@ Page({
       return
     }
 
+    const selectedItem = this.data.list.find((item: any) => String(item.id) === String(value))
+    if (!selectedItem) {
+      return
+    }
+
     this.setData({
-      selectedPeriod: value
+      selectedPeriod: String(value),
+      selected: selectedItem,
+      showBonusGift: Boolean(formatGiftText(selectedItem))
     }, () => {
       // 根据选中的期限更新商品
-      this.onUpdatePeriodList()
+      this.onFormatGoods()
     })
   },
   /** 根据期限更新商品列表 */
   onUpdatePeriodList() {
-    const { selectedPeriod, list } = this.data
-    // 将期限值映射回商品列表的筛选逻辑
-    // 这里需要根据实际的 period 和 num 来匹配
-    const periodMap: any = {
-      '7DAY': { period: 'DAY', num: 7 },
-      '14DAY': { period: 'DAY', num: 14 },
-      '1MONTH': { period: 'MONTH', num: 1 },
-      '6MONTH': { period: 'MONTH', num: 6 },
-      '1YEAR': { period: 'YEAR', num: 1 }
+    if (this.data.userTypes === PURCHASE_TYPE.TEACHER) {
+      return
     }
-
-    const target = periodMap[selectedPeriod]
-    if (target) {
-      const selectedItem = list.find((item: any) =>
-        item.period === target.period && item.num === target.num
-      )
-      if (selectedItem && selectedItem.stockNum > 0) {
-        this.setData({
-          selected: selectedItem
-        }, () => {
-          this.onFormatGoods()
-        })
-      }
+    const { selectedPeriod, list } = this.data
+    const selectedItem = list.find((item: any) => String(item.id) === String(selectedPeriod))
+    if (!selectedItem || Number(selectedItem.stockNum ?? 1) <= 0) {
+      return
     }
 
-    // 判断是否满 1 年,显示赠送提示
-    const showBonusGift = selectedPeriod === '1YEAR'
     this.setData({
-      showBonusGift
+      selected: selectedItem,
+      showBonusGift: Boolean(formatGiftText(selectedItem))
+    }, () => {
+      this.onFormatGoods()
     })
   },
   // 进行埋点
@@ -525,7 +665,7 @@ Page({
           salePrice: selected.salePrice,
           shopId: selected.shopId,
           id: selected.id,
-          goodsType: 'ACTIVATION_CODE', // INSTRUMENTS
+          goodsType: selected.goodsType || 'ACTIVATION_CODE', // INSTRUMENTS
         })
       }
       const selectedInstrument = that.data.selectedInstrument
@@ -553,7 +693,7 @@ Page({
       });
       info = encodeURIComponent(info);
       wx.navigateTo({
-        url: `../orders/order-detail?orderInfo=${info}`,
+        url: `../orders/order-detail?orderInfo=${info}&orderType=${that.data.userTypes}`,
         success: () => {
           that.setData({
             popupShow: false,

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

@@ -95,25 +95,22 @@
 
         <!-- 用户类型切换 -->
         <view class="user-type-tabs">
-          <view class="tab-item {{ userTypes === 'student' ? 'active' : '' }}" bind:tap="onSwitchUserType" data-type="student">学生端</view>
-          <view class="tab-item {{ userTypes === 'teacher' ? 'active' : '' }}" bind:tap="onSwitchUserType" data-type="teacher">老师端</view>
+          <view class="tab-item {{ userTypes === 'WECHAT_MINI' ? 'active' : '' }}" bind:tap="onSwitchUserType" data-type="WECHAT_MINI">学生端</view>
+          <view class="tab-item {{ userTypes === 'TEACHER_VIP' ? 'active' : '' }}" bind:tap="onSwitchUserType" data-type="TEACHER_VIP">老师端</view>
         </view>
 
         <!-- 商品信息卡片 -->
         <view class="product-info-card">
-          <view class="product-badge">
-            <text class="duration-text">{{ selected.typeName || '14天' }}</text>
-            <text class="user-label">学生端</text>
-          </view>
+          <image class="product-image" src="{{ formatSelectGood.productImage }}" mode="aspectFill"></image>
           <view class="product-detail">
-            <view class="product-name">{{ selected.name || '老师端-器乐数字AI畅享卡' }}</view>
+            <view class="product-name">{{ formatSelectGood.name || selected.name || '老师端-器乐数字AI畅享卡' }}</view>
             <view class="price-line">
               <text class="price-tag">到手价</text>
-              <text class="price-num">¥{{ selected.showSalePrice || '388.00' }}</text>
+              <text class="price-num">¥{{ formatSelectGood.showSalePrice || '388.00' }}</text>
             </view>
             <view class="origin-line">
               <text class="origin-tag">日常价</text>
-              <text class="origin-num">¥{{ selected.originalPrice || '2900.00' }}</text>
+              <text class="origin-num">¥{{ formatSelectGood.originalPrice || '2900.00' }}</text>
               <text class="divider">|</text>
               <text class="sold-count">已售10W+</text>
             </view>
@@ -123,23 +120,26 @@
         <!-- 选择期限 -->
         <view class="period-select-section">
           <view class="section-label">选择期限</view>
-          <view class="period-options">
-            <view wx:for="{{ periodList }}" wx:key="value" class="period-btn {{ selectedPeriod === item.value ? 'active' : '' }}" bind:tap="onSelectPeriod" data-value="{{ item.value }}">
-              {{ item.label }}
+          <scroll-view class="period-options-scroll" scroll-x="{{true}}" enhanced="{{true}}" show-scrollbar="{{false}}">
+            <view class="period-options">
+              <view wx:for="{{ periodList }}" wx:key="value" class="period-btn {{ selectedPeriod === item.value ? 'active' : '' }}" bind:tap="onSelectPeriod" data-value="{{ item.value }}">
+                {{ item.label }}
+              </view>
             </view>
-          </view>
+          </scroll-view>
         </view>
 
         <!-- 额外赠送 -->
+        <view class="gift-label" wx:if="{{ showBonusGift }}">额外赠送</view>
         <view class="gift-section" wx:if="{{ showBonusGift }}">
-          <text class="gift-desc">满1年额外赠送2个月</text>
+          <text class="gift-desc">赠送{{ formatSelectGood.giftText }}</text>
         </view>
 
         <!-- 底部结算栏 -->
         <view class="settlement-bar">
           <view class="select-summary">
             <text class="summary-label">选中:</text>
-            <text class="summary-content">{{ userTypes === 'teacher' ? '老师端' : '学生端' }}/{{ selected.typeName || '14天' }},</text>
+            <text class="summary-content">{{ userTypes === 'TEACHER_VIP' ? '老师端' : '学生端' }}/{{ formatSelectGood.typeName || selected.typeName || '14天' }},</text>
             <text class="summary-save">已省¥{{ formatSelectGood.discountPrice || '2512.00' }}</text>
           </view>
           <button class="submit-btn" catch:tap="onSubmit">立即购买</button>

+ 16 - 9
miniprogram/pages/orders/order-detail.ts

@@ -1,10 +1,11 @@
 // pages/orders/order-detail.ts
-import { api_executeOrder, api_executeOrderV2, api_executePayment, api_queryByParamName, api_userPaymentOrderDetail, api_userPaymentOrderUnpaid } from "../../api/login";
+import { api_executeOrderV2, api_executePayment, api_queryByParamName, 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"
 Page({
   /**
    * 页面的初始数据
@@ -36,6 +37,7 @@ Page({
       schoolInfo: ''
     },
     paymentType: null as any, // 支付类型
+    orderType: DEFAULT_ORDER_TYPE,
     paymentChannel: null as any,
     showService: false,
     areaList: [] as any,
@@ -65,9 +67,12 @@ Page({
    * 生命周期函数--监听页面加载
    */
   onLoad(options: any) {
+    this.setData({
+      orderType: options.orderType || DEFAULT_ORDER_TYPE
+    })
     this.queryPayType()
-    this.getAddresss()
-    this.getAreas()
+    // this.getAddresss()
+    // this.getAreas()
     if (options.orderInfo) {
       const goods = JSON.parse(decodeURIComponent(options.orderInfo));
       // console.log(goods, 'goods')
@@ -365,15 +370,17 @@ Page({
       })
 
       // 埋点
-      const openId = wx.getStorageSync("openId")
+      const openId = wx.getStorageSync("openId") || app.globalData.userInfo?.liteOpenid
+      const orderType = this.data.orderType || DEFAULT_ORDER_TYPE
       this.onTrackPoint({
         openId,
         elementName: '去支付'
       })
       if (orderNo) {
         const { data } = await api_userPaymentOrderUnpaid({
+          openId,
           orderNo: orderNo,
-          paymentType: 'WECHAT_MINI'
+          paymentType: orderType
         })
         if (data.code === 200) {
           const { paymentConfig, paymentType, orderNo } = data.data.paymentConfig
@@ -383,12 +390,12 @@ Page({
         }
       } else {
         const { data } = await api_executeOrderV2({
-          "orderType": "WECHAT_MINI",
-          "paymentType": this.data.paymentType,
+          "orderType": orderType,
+          "paymentType": orderType,
           "paymentCashAmount": allSalePrice,
           "paymentCouponAmount": 0,
           "shopId": shopId,
-          "openId": app.globalData.userInfo?.liteOpenid,
+          "openId": openId,
           "goodsInfos": goodsInfos,
           receiveAddress: this.data.receiveAddress,
           userBeneficiaryId: this.data.userBeneficiaryId,
@@ -814,4 +821,4 @@ Page({
       imageUrl: 'https://oss.dayaedu.com/ktyq/1739870592907.png'
     }
   }
-})
+})

+ 9 - 5
miniprogram/pages/orders/orders.ts

@@ -2,6 +2,7 @@ import { api_executePayment, api_queryByParamName, api_studentOrderPage, api_use
 import { formatPrice } from "../../utils/util";
 // 获取应用实例
 const app = getApp<IAppOption>()
+const DEFAULT_ORDER_TYPE = "WECHAT_MINI"
 Page({
 
   /**
@@ -96,7 +97,7 @@ Page({
     try {
       // @ApiModelProperty("订单状态 WAIT_PAY:待支付,WAIT_USE:待使用,SUCCESS:已完成,CLOSE:已取消")
       const { data } = await api_studentOrderPage({
-        openId: app.globalData.userInfo?.liteOpenid,
+        openId: wx.getStorageSync("openId") || app.globalData.userInfo?.liteOpenid,
         page: currentPage,
         rows: this.data.rows,
         version: 'V2',
@@ -212,7 +213,8 @@ Page({
     const item: any = this.data.recordList.find((item: any) => item.id === dataset.id)
     if (item) {
       this.onSubmit({
-        orderNo: item.orderNo
+        orderNo: item.orderNo,
+        orderType: item.orderType || item.paymentType || DEFAULT_ORDER_TYPE
       })
     }
   },
@@ -247,7 +249,7 @@ Page({
       });
       info = encodeURIComponent(info);
       wx.navigateTo({
-        url: `../orders/order-detail?orderInfo=${info}&orderNo=${orderDetail.orderNo}&status=${orderDetail.wechatStatus}`,
+        url: `../orders/order-detail?orderInfo=${info}&orderNo=${orderDetail.orderNo}&status=${orderDetail.wechatStatus}&orderType=${orderDetail.orderType || orderDetail.paymentType || DEFAULT_ORDER_TYPE}`,
       });
     } else {
       wx.navigateTo({
@@ -263,9 +265,11 @@ Page({
     });
     try {
       const { orderNo } = goodsInfo
+      const openId = wx.getStorageSync("openId") || app.globalData.userInfo?.liteOpenid
       const { data } = await api_userPaymentOrderUnpaid({
+        openId,
         orderNo: orderNo,
-        paymentType: 'WECHAT_MINI'
+        paymentType: goodsInfo.orderType || DEFAULT_ORDER_TYPE
       })
       if (data.code === 200) {
         const { paymentConfig, paymentType, orderNo } = data.data.paymentConfig
@@ -455,4 +459,4 @@ Page({
       imageUrl: 'https://oss.dayaedu.com/ktyq/1739870592907.png'
     }
   },
-})
+})