Browse Source

添加畅学卡

lex-xin 3 months ago
parent
commit
15908bd9d0
39 changed files with 981 additions and 247 deletions
  1. BIN
      src/common/images/icon_discount.png
  2. 2 2
      src/constant/index.ts
  3. 9 1
      src/router/routes-student.ts
  4. 1 1
      src/router/routes-teacher.ts
  5. BIN
      src/student/discount-card/images/bg.png
  6. BIN
      src/student/discount-card/images/btn-bg.png
  7. BIN
      src/student/discount-card/images/card-bg.png
  8. BIN
      src/student/discount-card/images/icon-star.png
  9. BIN
      src/student/discount-card/images/icon-svip-disabled.png
  10. BIN
      src/student/discount-card/images/icon-svip.png
  11. BIN
      src/student/discount-card/images/icon-vip-disabled.png
  12. BIN
      src/student/discount-card/images/icon-vip.png
  13. BIN
      src/student/discount-card/images/memo.png
  14. BIN
      src/student/discount-card/images/ring.png
  15. BIN
      src/student/discount-card/images/tip.png
  16. BIN
      src/student/discount-card/images/title1.png
  17. 293 0
      src/student/discount-card/index.module.less
  18. 297 0
      src/student/discount-card/index.tsx
  19. 1 1
      src/student/practice-class/index.tsx
  20. 1 1
      src/student/practice-class/model/all-search.tsx
  21. 8 8
      src/student/teacher-dependent/components/practice.tsx
  22. 1 1
      src/student/teacher-dependent/teacher-home.tsx
  23. 1 1
      src/student/trade/tradeOrder.ts
  24. 1 1
      src/teacher/extend-plan/index.tsx
  25. 2 2
      src/teacher/income-consus/echarts.ts
  26. 2 2
      src/teacher/income-consus/index.tsx
  27. 1 1
      src/teacher/piano-room/tradeOrder.ts
  28. 1 1
      src/teacher/practice-class/model/timer.tsx
  29. 8 0
      src/teacher/practice-class/practice-setting.module.less
  30. 50 168
      src/teacher/practice-class/practice-setting.tsx
  31. 6 0
      src/teacher/practice-class/timer/timer.module.less
  32. 17 46
      src/teacher/practice-class/timer/timer.tsx
  33. 2 2
      src/tenant/exercise-record/echats.ts
  34. 1 1
      src/tenant/trade/tradeOrder.ts
  35. 19 6
      src/views/order-detail/index.tsx
  36. 127 0
      src/views/order-detail/order-discount/index.module.less
  37. 128 0
      src/views/order-detail/order-discount/index.tsx
  38. 1 1
      src/views/order-detail/order-practice/index.tsx
  39. 1 0
      src/views/order-detail/use-coupons/index.tsx

BIN
src/common/images/icon_discount.png


+ 2 - 2
src/constant/index.ts

@@ -1,6 +1,6 @@
 export const goodsType = {
   LIVE: '直播课',
-  PRACTICE: '陪练课',
+  PRACTICE: '趣纠课',
   VIDEO: '视频课',
   VIP: '开通VIP会员',
   SVIP: '开通SVIP会员',
@@ -55,7 +55,7 @@ export const courseType = {
 }
 
 export const bizStatus = {
-  PRACTICE: '陪练课',
+  PRACTICE: '趣纠课',
   LIVE: '直播课',
   VIDEO: '视频课',
   MUSIC: '乐谱',

+ 9 - 1
src/router/routes-student.ts

@@ -45,7 +45,7 @@ export default [
         name: 'practiceClass',
         component: () => import('@/student/practice-class/index'),
         meta: {
-          title: '陪练课'
+          title: '趣纠课'
         }
       },
       {
@@ -151,6 +151,14 @@ export default [
         meta: {
           title: '评测曲目'
         }
+      },
+      {
+        path: '/discount-card',
+        component: () =>
+          import('@/student/discount-card/index'),
+        meta: {
+          title: '畅学卡'
+        }
       }
     ]
   },

+ 1 - 1
src/router/routes-teacher.ts

@@ -189,7 +189,7 @@ export default [
         name: 'practiceSetting',
         component: () => import('@/teacher/practice-class/practice-setting'),
         meta: {
-          title: '陪练课设置'
+          title: '趣纠课设置'
         }
       },
       {

BIN
src/student/discount-card/images/bg.png


BIN
src/student/discount-card/images/btn-bg.png


BIN
src/student/discount-card/images/card-bg.png


BIN
src/student/discount-card/images/icon-star.png


BIN
src/student/discount-card/images/icon-svip-disabled.png


BIN
src/student/discount-card/images/icon-svip.png


BIN
src/student/discount-card/images/icon-vip-disabled.png


BIN
src/student/discount-card/images/icon-vip.png


BIN
src/student/discount-card/images/memo.png


BIN
src/student/discount-card/images/ring.png


BIN
src/student/discount-card/images/tip.png


BIN
src/student/discount-card/images/title1.png


+ 293 - 0
src/student/discount-card/index.module.less

@@ -0,0 +1,293 @@
+.discountCardContainer {
+  min-height: 100vh;
+  background: url('./images/bg.png') no-repeat top center #cbf3ff;
+  background-size: contain;
+}
+
+.cardContainer {
+  position: relative;
+  padding: 20px 14px 0;
+
+  .imgSection {
+    font-size: 0;
+    padding-bottom: 20px;
+    img {
+      width: 100%;
+      margin-top: 16px;
+    }
+  }
+}
+
+.userSection {
+  display: flex;
+  align-items: flex-start;
+
+  .userImgSection {
+    position: relative;
+    width: 48px;
+    height: 48px;
+    margin-right: 13px;
+    flex-shrink: 0;
+
+    .userImg {
+      width: 48px;
+      height: 48px;
+      border-radius: 50%;
+      overflow: hidden;
+      border: 2px solid #f2f6f7;
+    }
+
+    .showMemeber {
+      position: absolute;
+      bottom: 1px;
+      right: -4px;
+      width: 18px;
+      height: 18px;
+    }
+
+    &.userVip {
+      .showMemeber {
+        background: url('./images/icon-vip-disabled.png') no-repeat center;
+        background-size: contain;
+      }
+
+      &.isVip {
+        .userImg {
+          border: 2px solid #f0af88;
+        }
+
+        .showMemeber {
+          background: url('./images/icon-vip.png') no-repeat center;
+          background-size: contain;
+        }
+      }
+    }
+
+    &.userSVip {
+      .showMemeber {
+        background: url('./images/icon-svip-disabled.png') no-repeat center;
+        background-size: contain;
+      }
+
+      &.isVip {
+        .userImg {
+          border: 2px solid #f0af88;
+        }
+
+        .showMemeber {
+          background: url('./images/icon-svip.png') no-repeat center;
+          background-size: contain;
+        }
+      }
+    }
+  }
+
+  .userInfo {
+    padding-top: 5px;
+    max-width: 185px;
+
+    .userName {
+      display: flex;
+      align-items: center;
+      padding-bottom: 4px;
+    }
+
+    .name {
+      font-weight: 500;
+      font-size: 18px;
+      color: #000000;
+      line-height: 25px;
+      letter-spacing: 1px;
+      max-width: 90px;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+    }
+
+    .phone {
+      font-size: 13px;
+      color: rgba(0, 0, 0, 0.6);
+    }
+
+    .member_time {
+      font-size: 12px;
+      color: #777777;
+      line-height: 17px;
+
+      span {
+        color: #1d88ff;
+        font-weight: 500;
+      }
+    }
+  }
+}
+
+.cardSection {
+  position: relative;
+  background: url('./images/card-bg.png') no-repeat center;
+  background-size: contain;
+  height: 203px;
+  max-width: 347px;
+  margin-top: 27px;
+
+  .top {
+    display: flex;
+    align-items: center;
+    padding-top: 19px;
+    padding-left: 26px;
+    .iconTitle1 {
+      // width: 63px;
+      height: 25px;
+      margin-right: 6px;
+    }
+
+    .priceSection {
+      flex-shrink: 0;
+      display: flex;
+      align-items: center;
+      .currentPrice {
+        display: flex;
+        align-items: flex-end;
+        background: linear-gradient(270deg, #ff7b57 0%, #ff3460 100%);
+        border-radius: 100px 100px 100px 2px;
+        padding: 0 8px;
+        font-weight: 600;
+        color: #ffffff;
+        height: 23px;
+        .l {
+          font-size: 12px;
+          line-height: 17px;
+          padding-right: 2px;
+        }
+        .c {
+          font-size: 20px;
+          line-height: 1;
+        }
+        .r {
+          font-size: 12px;
+          line-height: 17px;
+        }
+      }
+      .originPrice {
+        padding-left: 6px;
+        font-size: 12px;
+        color: rgba(19, 20, 21, 0.4)
+      }
+    }
+  }
+
+  .chapter {
+    position: absolute;
+    right: 19px;
+    top: -14px;
+    background: url('./images/ring.png') no-repeat center;
+    background-size: contain;
+    width: 60px;
+    height: 60px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    flex-direction: column;
+    transform: rotate(-15deg);
+
+    .chapterTop {
+      padding-top: 6px;
+      font-weight: 500;
+      font-size: 11px;
+      color: #ffffff;
+      line-height: 15px;
+    }
+    .chapterBottom {
+      font-family: DINAlternate, DINAlternate;
+      font-weight: bold;
+      font-size: 22px;
+      color: #ffffff;
+      line-height: 1;
+      // display: flex;
+      // align-items: center;
+      i {
+        vertical-align: middle;
+        padding-left: 1px;
+        font-style: normal;
+        font-weight: 500;
+        font-size: 12px;
+        color: #ffffff;
+        line-height: 1;
+      }
+    }
+  }
+}
+
+.btnGroup {
+  background-color: #fff;
+  padding: 10px 30px 30px;
+
+  .submitBtn {
+    background: url('./images/btn-bg.png') no-repeat center;
+    background-size: contain;
+    width: 315px;
+    height: 46px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    font-weight: 600;
+    font-size: 18px;
+    color: #ffffff;
+    line-height: 26px;
+    i {
+      padding-top: 2px;
+      padding-right: 2px;
+      font-size: 14px;
+      font-style: normal;
+      line-height: 20px;
+    }
+  }
+}
+
+
+// 弹窗样式
+.dialogContainer {
+  width: 287px;
+  box-sizing: border-box;
+  background: #FFFFFF;
+  border-radius: 12px;
+  padding: 16px 24px 22px;
+  text-align: center;
+
+  .dialogTitle {
+    font-weight: 500;
+    font-size: 18px;
+    color: #333333;
+    line-height: 25px;
+  }
+
+  .dialogContent {
+    padding: 16px 0 21px;
+    font-size: 15px;
+    color: #777777;
+    line-height: 26px;
+  }
+
+  .dialogBtnGroup {
+    padding: 0 16px;
+
+    &.orderGroup {
+      display: flex;
+      align-items: center;
+      padding: 0;
+    }
+
+    :global {
+      .van-button {
+        font-weight: 500;
+        font-size: 16px;
+      }
+    }
+  }
+
+  .dialogBtn {
+    margin-left: 12px;
+    color: #FFFFFF;
+    line-height: 22px;
+  }
+}

+ 297 - 0
src/student/discount-card/index.tsx

@@ -0,0 +1,297 @@
+import { computed, defineComponent, onMounted, reactive } from 'vue'
+import styles from './index.module.less'
+import ColHeader from '@/components/col-header'
+import { useEventListener } from '@vant/use'
+import iconStudent from '@common/images/icon_student.png'
+import { Button, Image, Popup } from 'vant'
+import { state as baseState } from '@/state'
+
+import iconMemo from './images/memo.png'
+import iconTip from './images/tip.png'
+import iconTitle1 from './images/title1.png'
+import TheSticky from '@/components/the-sticky'
+import request from '@/helpers/request'
+import { tradeOrder } from '../trade/tradeOrder'
+import { useRouter } from 'vue-router'
+import dayjs from 'dayjs'
+import { orderStatus } from '@/views/order-detail/orderStatus'
+
+export default defineComponent({
+  name: 'discount-card',
+  setup() {
+    const router = useRouter()
+    const state = reactive({
+      discountDetail: {} as any,
+      titleOpacity: 0,
+      orderVisiable: false,
+      orderDetail: {} as any
+    })
+    const userInfo = computed(() => {
+      const users = baseState.user.data
+      console.log(users, 'users')
+      return {
+        username: users?.username,
+        phone: users?.phone,
+        avatar: users?.heardUrl,
+        id: users?.userId,
+        discountCardFlag: users?.discountCardFlag,
+        discountEndTime: users?.discountEndTime,
+        userVip: users?.userVip
+      }
+    })
+
+    useEventListener('scroll', () => {
+      const height =
+        window.scrollY ||
+        window.pageYOffset ||
+        document.documentElement.scrollTop
+      state.titleOpacity = height > 30 ? 1 : 0
+    })
+
+     // 取消支付
+     const onCancelOrder = async () => {
+      try {
+        await request.post(`${baseState.platformApi}/userOrder/orderCancel`, {
+          data: { orderNo: state.orderDetail.orderNo }
+        })
+        state.orderVisiable = false
+      } catch {
+        //
+      }
+    }
+
+    // 继续支付
+    const onContinueOrder = async () => {
+      const orderDetail = state.orderDetail || {}
+      tradeOrder(orderDetail, () => {
+        router.push({
+          path: '/orderDetail',
+          query: {
+            orderType: orderDetail.orderType
+          }
+        })
+      })
+    }
+
+    const onSubmit = async () => {
+      try {
+        // 永久会员
+        // const { data } = await request.post(
+        //   `${baseState.platformApi}/memberPriceSettings/list`,
+        //   {
+        //     data: {
+        //       status: 1
+        //     }
+        //   }
+        // )
+        // const result = data.list || []
+        // const selectItem = result.find(
+        //   (item: any) => item.id === state.selectMember?.id
+        // )
+        // // 状态、售价变更时
+        // if (
+        //   !selectItem ||
+        //   (selectItem && selectItem.salePrice !== state.selectMember.salePrice)
+        // ) {
+        //   state.dialogVisiable = true
+        //   return
+        // }
+
+        // 判断是否有待支付订单
+        // const resPadding = await request.post(
+        //   `${baseState.platformApi}/userOrder/getPendingOrder`,
+        //   {
+        //     data: { goodType: 'DISCOUNT' }
+        //   }
+        // )
+        // console.log(resPadding, 'resPadding')
+        // if (resPadding?.data?.id) {
+        //   state.orderVisiable = true
+        //   state.orderDetail = resPadding.data || {}
+        //   return
+        // }
+
+        // const member: any = state.selectMember
+        // // 判断是否有会员
+        // let startTime = new Date()
+        // // vip类型 VIP:会员 SVIP:SVIP,PERMANENT_SVIP:永久SVIP,NOT_VIP:不是vip
+        // // vip过期类型 VIP:会员 SVIP:SVIP,ALL_VIP:全vip
+        // if (state.tabActive === 'SVIP') {
+        //   startTime = dayjs(
+        //     userInfo.value.userVip.svipEndDate || new Date()
+        //   ).toDate()
+        // } else if (state.tabActive === 'VIP') {
+        //   // 购买Vip时,先有vip的有效时间,如果没有则取SVIP有效时间,都没有默认当前
+        //   startTime = dayjs(
+        //     userInfo.value.userVip.vipEndDate ||
+        //       userInfo.value.userVip.svipEndDate ||
+        //       new Date()
+        //   ).toDate()
+        // } else if (isPermanent.value) {
+        //   Toast('您已是永久SVIP会员')
+        //   return
+        // }
+
+        let startTime = new Date()
+        if(userInfo.value.discountCardFlag) {
+          startTime = dayjs(userInfo.value.discountEndTime || new Date()).toDate()
+        }
+        let endTime = new Date()
+        if (state.discountDetail.period === 'MONTH') {
+          endTime = dayjs(startTime).add(1, 'month').toDate()
+        } else if (state.discountDetail.period === 'QUARTERLY') {
+          endTime = dayjs(startTime).add(3, 'month').toDate()
+        } else if (state.discountDetail.period === 'YEAR_HALF') {
+          endTime = dayjs(startTime).add(6, 'month').toDate()
+        } else if (state.discountDetail.period === 'YEAR') {
+          endTime = dayjs(startTime).add(1, 'year').toDate()
+        }
+        orderStatus.orderObject.orderType = 'DISCOUNT'
+        orderStatus.orderObject.orderName = `畅学卡`
+        orderStatus.orderObject.orderDesc = `畅学卡`
+        orderStatus.orderObject.actualPrice = state.discountDetail.salePrice || 0
+        orderStatus.orderObject.recomUserId = null
+        orderStatus.orderObject.activityId = null
+        orderStatus.orderObject.orderNo = ''
+
+        orderStatus.orderObject.orderList = [
+          {
+            orderType: 'DISCOUNT',
+            goodsName: `畅学卡`,
+            id: state.discountDetail.id,
+            title: '畅学卡',
+            num: 1, // 购买个数
+            salePrice: state.discountDetail.salePrice,
+            period: state.discountDetail.period,
+            price: state.discountDetail.salePrice,
+            startTime: dayjs(startTime).format('YYYY-MM-DD'),
+            endTime: dayjs(endTime).format('YYYY-MM-DD')
+          }
+        ]
+        router.push({
+          path: '/orderDetail',
+          query: {
+            orderType: 'DISCOUNT'
+          }
+        })
+      } catch {
+        //
+      }
+    }
+
+    onMounted(async () => {
+      const { data } = await request.get(
+        `${baseState.platformApi}/memberPriceSettings/getDiscount`
+      )
+      state.discountDetail = data
+    })
+    return () => (
+      <div class={styles.discountCardContainer}>
+        <ColHeader
+          background={`rgba(255,255,255, ${state.titleOpacity})`}
+          backIconColor="black"
+          hideHeader={false}
+          border={false}
+        />
+        <div class={styles.cardContainer}>
+          <div class={styles.userSection}>
+            <div
+              class={[
+                styles.userImgSection,
+                (userInfo.value.userVip.vipType === 'SVIP' ||
+                  userInfo.value.userVip.vipType === 'PERMANENT_SVIP') &&
+                  styles.userSVip,
+                userInfo.value.userVip.vipType === 'VIP' && styles.userVip,
+                userInfo.value.userVip.svipEndDays > 0 ||
+                userInfo.value.userVip.vipEndDays > 0
+                  ? styles.isVip
+                  : ''
+              ]}
+            >
+              <Image
+                class={styles.userImg}
+                src={userInfo.value.avatar || iconStudent}
+                fit="cover"
+              />
+              <i class={styles.showMemeber}></i>
+            </div>
+            <div class={styles.userInfo}>
+              <div class={styles.userName}>
+                <span class={styles.name}>{userInfo.value.username}</span>
+                {userInfo.value.phone && (
+                  <span class={styles.phone}>({userInfo.value.phone})</span>
+                )}
+              </div>
+              <div class={styles.member_time}>
+                {userInfo.value.discountCardFlag ? <>有效期至<span>{userInfo.value.discountEndTime}</span></> : '您当前尚未开通畅学卡'}
+              </div>
+            </div>
+          </div>
+
+          <div class={styles.cardSection}>
+            <div class={styles.top}>
+              <img src={iconTitle1} class={styles.iconTitle1} />
+              <div class={styles.priceSection}>
+                <div class={styles.currentPrice}>
+                  <div class={styles.l}>¥</div>
+                  <div class={styles.c}>{state.discountDetail.salePrice || 0}</div>
+                  <div class={styles.r}>/年</div>
+                </div>
+                <del class={styles.originPrice}>原价¥{state.discountDetail.originalPrice}/年</del>
+              </div>
+            </div>
+
+            <div class={styles.chapter}>
+              <div class={styles.chapterTop}>课程全部</div>
+              <div class={styles.chapterBottom}>
+                {(state.discountDetail.discountRate || 0) * 100}<i>折</i>
+              </div>
+            </div>
+          </div>
+
+          <div class={styles.imgSection}>
+            <img src={iconMemo} class={styles.iconMemo} />
+            <img src={iconTip} class={styles.iconTip} />
+          </div>
+        </div>
+
+        <TheSticky position="bottom">
+          <div class={styles.btnGroup}>
+            <div class={styles.submitBtn} onClick={onSubmit}>
+              {userInfo.value.discountCardFlag ? '立即续费' : <><i>¥</i>{state.discountDetail.salePrice||0}元立即开通</>}
+            </div>
+          </div>
+        </TheSticky>
+
+
+        <Popup
+          v-model:show={state.orderVisiable}
+          style={{ background: 'transparent' }}
+          closeOnClickOverlay={false}
+        >
+          <div class={styles.dialogContainer}>
+            <div class={styles.dialogTitle}>提示</div>
+            <div class={styles.dialogContent}>
+              您有待支付的订单,是否继续支付
+            </div>
+
+            <div class={[styles.dialogBtnGroup, styles.orderGroup]}>
+              <Button round type="default" plain block onClick={onCancelOrder}>
+                取消订单
+              </Button>
+              <Button
+                round
+                type="primary"
+                block
+                class={styles.dialogBtn}
+                onClick={onContinueOrder}
+              >
+                继续支付
+              </Button>
+            </div>
+          </div>
+        </Popup>
+      </div>
+    )
+  }
+})

+ 1 - 1
src/student/practice-class/index.tsx

@@ -164,7 +164,7 @@ export default defineComponent({
         >
           <div ref="headers">
             <ColHeader
-              title="陪练课"
+              title="趣纠课"
               isFixed={false}
               border={false}
               backIconColor="white"

+ 1 - 1
src/student/practice-class/model/all-search.tsx

@@ -25,7 +25,7 @@ export default defineComponent({
       <>
         <div class={styles.filterTitle}>全部筛选</div>
         <div class={styles.searchResult}>
-          <div class={styles.searchTitle}>陪练课数</div>
+          <div class={styles.searchTitle}>趣纠课数</div>
           <RadioGroup
             class={styles['radio-group']}
             modelValue={this.popupParams.expTime}

+ 8 - 8
src/student/teacher-dependent/components/practice.tsx

@@ -50,7 +50,7 @@ export default defineComponent({
       selectStatus: false,
       coursePlanList: [] as any,
       calendarDate: dayjs().add(1, 'day').toDate() as Date, // 日历当前时间
-      settingStatus: true, // 是否设置陪练
+      settingStatus: true, // 是否设置趣纠
       loadDataStatus: true // 是否加载数据
     }
   },
@@ -306,8 +306,8 @@ export default defineComponent({
           ).format('HH:mm')}~${dayjs(item.endTime).format('HH:mm')}`
         })
         orderStatus.orderObject.orderType = 'PRACTICE'
-        orderStatus.orderObject.orderName = subjectInfo.subjectName + '陪练课'
-        orderStatus.orderObject.orderDesc = subjectInfo.subjectName + '陪练课'
+        orderStatus.orderObject.orderName = subjectInfo.subjectName + '趣纠课'
+        orderStatus.orderObject.orderDesc = subjectInfo.subjectName + '趣纠课'
         orderStatus.orderObject.actualPrice = Number(
           (this.courseNum * subjectInfo.subjectPrice).toFixed(2)
         )
@@ -315,9 +315,9 @@ export default defineComponent({
         orderStatus.orderObject.orderList = [
           {
             orderType: 'PRACTICE',
-            goodsName: subjectInfo.subjectName + '陪练课',
-            courseGroupName: subjectInfo.subjectName + '陪练课',
-            courseIntroduce: subjectInfo.subjectName + '陪练课',
+            goodsName: subjectInfo.subjectName + '趣纠课',
+            courseGroupName: subjectInfo.subjectName + '趣纠课',
+            courseIntroduce: subjectInfo.subjectName + '趣纠课',
             subjectId: subjectInfo.subjectId,
             singleCourseMinutes: subjectInfo.courseMinutes,
             courseNum: this.courseNum,
@@ -382,7 +382,7 @@ export default defineComponent({
                 <CellGroup class={styles.group} border={false}>
                   {this.subjectInfo.subjectPrice > 0 && (
                     <Cell
-                      title="陪练课收费"
+                      title="趣纠课收费"
                       v-slots={{
                         default: () => (
                           <div class={styles.price}>
@@ -565,7 +565,7 @@ export default defineComponent({
             <ColResult
               btnStatus={false}
               classImgSize="SMALL"
-              tips="老师暂未开放陪练课"
+              tips="老师暂未开放趣纠课"
             />
           ))}
       </>

+ 1 - 1
src/student/teacher-dependent/teacher-home.tsx

@@ -119,7 +119,7 @@ export default defineComponent({
               {this.tabs === 'single' && <Single userInfo={this.userInfo} />}
             </div>
           </Tab>
-          <Tab title="陪练课" name="practice">
+          <Tab title="趣纠课" name="practice">
             <div style={{ minHeight: this.homeContaiterHeight }}>
               {this.tabs === 'practice' && (
                 <Practice userInfo={this.userInfo} />

+ 1 - 1
src/student/trade/tradeOrder.ts

@@ -7,7 +7,7 @@ import dayjs from 'dayjs'
 const apiSuffix =
   state.platformType === 'STUDENT' ? '/api-student' : '/api-teacher'
 // LIVE: '直播课',
-// PRACTICE: '陪练课',
+// PRACTICE: '趣纠课',
 // VIDEO: '视频课',
 // VIP: '开通会员',
 // MUSIC: '单曲点播'

+ 1 - 1
src/teacher/extend-plan/index.tsx

@@ -56,7 +56,7 @@ export default defineComponent({
         page: 1,
         rows: 20
       },
-      // 业务类型:PRACTICE, 陪练课 LIVE, 直播课 VIDEO, 视频课 MUSIC, 乐谱 WITHDRAWAL, 提现 LIVE_SHARE, 直播课分润 VIDEO_SHARE, 视频课分润 MUSIC_SHARE, 乐谱分润 VIP_SHARE, 会员分润 MALL_SHARE, 商品分润 ,可用值:PRACTICE,LIVE,VIDEO,MUSIC,VIP,MALL,WITHDRAWAL,LIVE_SHARE,VIDEO_SHARE,MUSIC_SHARE,VIP_SHARE,MALL_SHARE
+      // 业务类型:PRACTICE, 趣纠课 LIVE, 直播课 VIDEO, 视频课 MUSIC, 乐谱 WITHDRAWAL, 提现 LIVE_SHARE, 直播课分润 VIDEO_SHARE, 视频课分润 MUSIC_SHARE, 乐谱分润 VIP_SHARE, 会员分润 MALL_SHARE, 商品分润 ,可用值:PRACTICE,LIVE,VIDEO,MUSIC,VIP,MALL,WITHDRAWAL,LIVE_SHARE,VIDEO_SHARE,MUSIC_SHARE,VIP_SHARE,MALL_SHARE
       actions: [
         { name: '全部推广', value: '' },
         { name: '直播课', value: 'LIVE_SHARE' },

+ 2 - 2
src/teacher/income-consus/echarts.ts

@@ -53,7 +53,7 @@ export const lineChartOption = {
         '0.00'
       ],
       symbol: 'circle',
-      name: '陪练课',
+      name: '趣纠课',
       type: 'line',
       emphasis: { lineStyle: { width: 1 } }
     },
@@ -345,7 +345,7 @@ export const pieChartOption = {
       avoidLabelOverlap: false,
       label: { show: false },
       data: [
-        { name: '陪练课', value: '0.00' },
+        { name: '趣纠课', value: '0.00' },
         { name: '直播课', value: '0.00' },
         { name: '视频课', value: '0.00' },
         { name: '乐谱', value: '0.00' },

+ 2 - 2
src/teacher/income-consus/index.tsx

@@ -297,7 +297,7 @@ export default defineComponent({
               <Col span={6}>
                 <i></i>
                 <div class={styles.type}>
-                  <span>陪练课</span>
+                  <span>趣纠课</span>
                   <span class={styles.price}>
                     {moneyFormat(this.moneyInfo.practiceAmount)}
                   </span>
@@ -426,7 +426,7 @@ export default defineComponent({
           <div class={styles.pieData}>
             <div>
               <i class={styles.piePractice}></i>
-              <span class={styles.pieTitle}>陪练课</span>
+              <span class={styles.pieTitle}>趣纠课</span>
               <span>{this.moneyInfo.practiceRate}%</span>
             </div>
             <div>

+ 1 - 1
src/teacher/piano-room/tradeOrder.ts

@@ -3,7 +3,7 @@ import request from '@/helpers/request'
 import { orderStatus } from '@/views/order-detail/orderStatus'
 import dayjs from 'dayjs'
 // LIVE: '直播课',
-// PRACTICE: '陪练课',
+// PRACTICE: '趣纠课',
 // VIDEO: '视频课',
 // VIP: '开通会员',
 // MUSIC: '单曲点播'

+ 1 - 1
src/teacher/practice-class/model/timer.tsx

@@ -172,7 +172,7 @@ export default defineComponent({
         <div class={styles.tips}>
           <div class={styles.tipsTitle}>请选择陪练开始时间</div>
           <div class={styles.tipsTime}>
-            陪练课单课时时长为 <span>{this.courseMinutes}</span> 分钟
+            趣纠课单课时时长为 <span>{this.courseMinutes}</span> 分钟
           </div>
         </div>
 

+ 8 - 0
src/teacher/practice-class/practice-setting.module.less

@@ -77,3 +77,11 @@
     }
   }
 }
+
+.PracticeSettingBtns {
+  :global {
+    .van-button {
+      font-size: 18px;
+    }
+  }
+}

+ 50 - 168
src/teacher/practice-class/practice-setting.tsx

@@ -6,8 +6,6 @@ import request from '@/helpers/request'
 import { postMessage } from '@/helpers/native-message'
 import {
   Form,
-  Radio,
-  RadioGroup,
   Tag,
   Sticky,
   Button,
@@ -21,14 +19,17 @@ import {
 import { defineComponent } from 'vue'
 import styles from './practice-setting.module.less'
 import { verifyNumberIntegerAndFloat } from '@/helpers/toolsValidate'
-import Timer from './model/timer'
 import ColHeader from '@/components/col-header'
 import { state } from '@/state'
+import TheSticky from '@/components/the-sticky'
 
 export default defineComponent({
   name: 'PracticeSetting',
   data() {
+    const query = this.$route.query
     return {
+      courseType: query.tabs == 'vip' ? 'VIP' : 'PRACTICE',
+      text: query.tabs == 'vip' ? 'VIP定制课' : '趣纠课',
       subjectList: [],
       chargeTypeArr: {
         0: '否',
@@ -37,23 +38,12 @@ export default defineComponent({
       checkStatus:false, // 是否审核版本
       classTimeStatus: false,
       subjectStatus: false,
-      timerStatus: false,
-      timeSetting: {
-        courseMinutes: 25,
-        freeMinutes: 5,
-        startSetting: '08:00',
-        endSetting: '18:00'
-      },
-      timerObject: {} as any,
       form: {
-        enableFlag: 1,
         courseMinutes: null as any,
         freeMinutes: 0,
         subjectIdTemp: '',
         subjectId: [] as any[],
         subjectPrice: [] as any[],
-        skipHolidayFlag: 1,
-        setting: ''
       },
       minutes: [] as any,
       rate: 0
@@ -67,6 +57,7 @@ export default defineComponent({
     }
   },
   async mounted() {
+    document.title = `${this.text}设置`
     try {
       // 获取手续费和分钟数
       const config = await request.get(
@@ -74,13 +65,13 @@ export default defineComponent({
         {
           params: {
             paramNames:
-              'practice_times_setting,practice_service_fee,course_start_setting,course_end_setting'
+              'practice_times_setting,practice_service_fee,vip_course_times_setting'
           }
         }
       )
       const configData = config.data || []
       configData.forEach((item: any) => {
-        if (item.paramName === 'practice_times_setting') {
+        if (item.paramName === (this.courseType === 'VIP' ? 'vip_course_times_setting' : 'practice_times_setting')) {
           const mins = item.paramValue ? JSON.parse(item.paramValue) : []
           const tempArr = [] as any
           mins.forEach((item: any) => {
@@ -90,16 +81,14 @@ export default defineComponent({
             })
           })
           this.minutes = [...tempArr]
+          if(this.minutes.length > 0) {
+            this.form.courseMinutes = this.minutes[0].courseMinutes
+            this.form.freeMinutes = this.minutes[0].freeMinutes
+          }
         }
         if (item.paramName === 'practice_service_fee') {
           this.rate = item.paramValue
         }
-        if (item.paramName === 'course_start_setting') {
-          this.timeSetting.startSetting = item.paramValue
-        }
-        if (item.paramName === 'course_end_setting') {
-          this.timeSetting.endSetting = item.paramValue
-        }
       })
       //
       const teacher = await request.post('/api-teacher/teacher/querySubject')
@@ -107,60 +96,30 @@ export default defineComponent({
 
       // 获取课程设置
       const setting = await request.post(
-        '/api-teacher/teacherFreeTime/getDetail',
+        '/api-teacher/teacherSubjectPrice/list',
         {
           data: {
-            defaultFlag: 1
+            courseType: this.courseType
           }
         }
       )
       const sr = setting.data
-      if (sr) {
-        this.timeSetting.courseMinutes = sr.courseMinutes
-        this.timeSetting.freeMinutes = sr.freeMinutes
-
-        this.timerObject = {
-          monday: sr.monday ? JSON.parse(sr.monday) : [],
-          tuesday: sr.tuesday ? JSON.parse(sr.tuesday) : [],
-          wednesday: sr.wednesday ? JSON.parse(sr.wednesday) : [],
-          thursday: sr.thursday ? JSON.parse(sr.thursday) : [],
-          friday: sr.friday ? JSON.parse(sr.friday) : [],
-          saturday: sr.saturday ? JSON.parse(sr.saturday) : [],
-          sunday: sr.sunday ? JSON.parse(sr.sunday) : []
-        }
-
-        const tempIds: any = []
-        const tempPrices: any = []
-        const subjectPrice = sr.subjectPrice || []
-        subjectPrice.forEach((item: any) => {
-          tempIds.push(item.subjectId)
-          tempPrices.push({
+      if(Array.isArray(sr)) {
+        const tempSubjects: any = []
+        sr.forEach((item: any) => {
+          this.form.courseMinutes = item.courseMinutes
+          this.form.freeMinutes = item.freeMinutes
+          this.form.subjectId.push(item.subjectId)
+          tempSubjects.push({
             subjectId: item.subjectId,
-            subjectPrice: item.subjectPrice,
-            subjectName: item.subjectName
+            subjectName: item.subjectName,
+            subjectPrice: item.subjectPrice
           })
         })
-        const to = this.timerObject
-        this.form = {
-          enableFlag: sr.enableFlag,
-          courseMinutes: sr.courseMinutes,
-          freeMinutes: sr.freeMinutes,
-          subjectIdTemp: tempIds.join(','),
-          subjectId: tempIds,
-          subjectPrice: tempPrices,
-          skipHolidayFlag: sr.skipHolidayFlag,
-          setting:
-            to.monday.length > 0 ||
-            to.tuesday.length > 0 ||
-            to.wednesday.length > 0 ||
-            to.thursday.length > 0 ||
-            to.friday.length > 0 ||
-            to.saturday.length > 0 ||
-            to.sunday.length > 0
-              ? '已设置'
-              : ''
-        }
+        this.form.subjectIdTemp = this.form.subjectId.join(',')
+        this.form.subjectPrice = tempSubjects
       }
+      
 
       // 判断如果是审核的则不显示
       const resVersion = await request.post('/api-teacher/open/appVersion', {
@@ -176,31 +135,9 @@ export default defineComponent({
   },
   methods: {
     onSelect(item: any) {
-      // 如果分钟数不同,则清空
-      if (this.form.courseMinutes !== item.courseMinutes) {
-        this.timerObject = {}
-        this.form.setting = ''
-      }
       this.form.courseMinutes = item.courseMinutes
       this.form.freeMinutes = item.freeMinutes
     },
-    async onTimer() {
-      try {
-        const form = this.form
-        if (!form.courseMinutes) {
-          Toast('请选择单课时时长')
-          return
-        }
-        this.timeSetting.courseMinutes = Number(form.courseMinutes)
-        this.timeSetting.freeMinutes = Number(form.freeMinutes)
-        this.timerStatus = true
-      } catch {}
-    },
-    onChoiceTimer(item: any, status: boolean) {
-      this.form.setting = status ? '已设置' : ''
-      this.timerObject = item
-      this.timerStatus = false
-    },
     onChoice(item: any) {
       console.log(item)
       const tempItem = item || []
@@ -240,16 +177,26 @@ export default defineComponent({
     async onSubmit() {
       try {
         const form = this.form
+        const params: any = []
         form.subjectPrice.forEach((item: any) => {
-          item.subjectName = this.getSubjectName(item.subjectId)
+          const subjectName = this.getSubjectName(item.subjectId)
+          console.log(subjectName, 'subjectName')
+          params.push({
+            ...item,
+            courseMinutes: this.form.courseMinutes,
+            courseType: this.courseType,
+            freeMinutes: this.form.freeMinutes,
+            subjectName
+            
+          })
         })
-        await request.post('/api-teacher/teacherFreeTime/upSet', {
-          data: {
-            ...form,
-            ...this.timerObject
-          }
+        console.log(params,'foparamsrm')
+        await request.post('/api-teacher/teacherSubjectPrice/saveOrUpdate', {
+          data: params
         })
-        Toast('设置成功')
+        setTimeout(() => {
+          Toast('设置成功')
+        }, 100);
         setTimeout(() => {
           postMessage({ api: 'back', content: {} })
         }, 500)
@@ -259,27 +206,8 @@ export default defineComponent({
   render() {
     return (
       <Form style={{ paddingTop: '15px' }} onSubmit={this.onSubmit}>
-        <ColHeader />
+        <ColHeader title={`${this.text}设置`} />
         <ColFieldGroup>
-          <ColField title="是否开启陪练课" required border={false}>
-            <RadioGroup
-              class={styles['radio-group']}
-              modelValue={this.form.enableFlag}
-              onUpdate:modelValue={val => (this.form.enableFlag = val)}
-            >
-              {['1', '0'].map((item: string) => {
-                const isActive = Number(item) === Number(this.form.enableFlag)
-                const type = isActive ? 'primary' : 'default'
-                return (
-                  <Radio class={styles.radio} name={item}>
-                    <Tag size="large" plain={isActive} type={type}>
-                      {this.chargeTypeArr[item]}
-                    </Tag>
-                  </Radio>
-                )
-              })}
-            </RadioGroup>
-          </ColField>
           <ColField title="可教授乐器" required>
             {this.form.subjectPrice && this.form.subjectPrice.length > 0 && (
               <CheckboxGroup
@@ -371,7 +299,7 @@ export default defineComponent({
           <ColFieldGroup>
             {this.form.subjectPrice.map((item: any) => (
               <ColField
-                title={`${this.getSubjectName(item.subjectId)}声部陪练价格`}
+                title={`${this.getSubjectName(item.subjectId)}声部${this.text}价格`}
                 required
               >
                 <Field
@@ -383,12 +311,12 @@ export default defineComponent({
                   rules={[
                     {
                       required: true,
-                      message: `请选择声部陪练价格`
+                      message: `请选择声部${this.text}价格`
                     }
                   ]}
                   formatter={this.onFormatter}
                   maxlength={8}
-                  placeholder={`请选择声部陪练价格`}
+                  placeholder={`请选择声部${this.text}价格`}
                   v-slots={{
                     button: () => <span>元</span>
                   }}
@@ -398,49 +326,13 @@ export default defineComponent({
           </ColFieldGroup>
         )}
 
-        <ColFieldGroup>
-          <ColField title="可陪练时间段">
-            <Field
-              modelValue={this.form.setting}
-              name="singleMins"
-              readonly
-              isLink
-              onClick={this.onTimer}
-              placeholder="未设置"
-            />
-          </ColField>
-        </ColFieldGroup>
-
-        <ColFieldGroup>
-          <ColField required title="是否跳过节假日" border={false}>
-            <RadioGroup
-              class={styles['radio-group']}
-              modelValue={this.form.skipHolidayFlag}
-              onUpdate:modelValue={val => (this.form.skipHolidayFlag = val)}
-            >
-              {['1', '0'].map((item: string) => {
-                const isActive =
-                  Number(item) === Number(this.form.skipHolidayFlag)
-                const type = isActive ? 'primary' : 'default'
-                return (
-                  <Radio class={styles.radio} name={item}>
-                    <Tag size="large" plain={isActive} type={type}>
-                      {this.chargeTypeArr[item]}
-                    </Tag>
-                  </Radio>
-                )
-              })}
-            </RadioGroup>
-          </ColField>
-        </ColFieldGroup>
-
-        <Sticky offsetBottom={0} position="bottom">
-          <div class={'btnGroup'}>
+        <TheSticky position="bottom">
+          <div class={['btnGroup', styles.PracticeSettingBtns]}>
             <Button block round type="primary" native-type="submit">
               提交
             </Button>
           </div>
-        </Sticky>
+        </TheSticky>
 
         <ColPopup v-model={this.subjectStatus} destroy>
           <ColHeader />
@@ -453,17 +345,7 @@ export default defineComponent({
           />
         </ColPopup>
 
-        <ColPopup v-model={this.timerStatus} destroy>
-          <ColHeader title="设置陪练时间段" />
-          <Timer
-            onChoice={this.onChoiceTimer}
-            timerObject={this.timerObject}
-            courseMinutes={Number(this.timeSetting.courseMinutes)}
-            freeMinutes={Number(this.timeSetting.freeMinutes)}
-            startSetting={this.timeSetting.startSetting}
-            endSetting={this.timeSetting.endSetting}
-          />
-        </ColPopup>
+
 
         <ActionSheet
           v-model:show={this.classTimeStatus}

+ 6 - 0
src/teacher/practice-class/timer/timer.module.less

@@ -132,3 +132,9 @@
   color: #ffffff !important;
   background: #ffb752;
 }
+
+
+.btnGroupTimer {
+  padding-top: 20px;
+  background: #F6F8F9;
+}

+ 17 - 46
src/teacher/practice-class/timer/timer.tsx

@@ -1,4 +1,4 @@
-import { Button, Col, Radio, RadioGroup, Row, Sticky, Tag } from 'vant'
+import { Button, Col, Radio, RadioGroup, Row, Tag, Toast } from 'vant'
 import { defineComponent } from 'vue'
 import styles from './timer.module.less'
 import dayjs from 'dayjs'
@@ -7,20 +7,13 @@ import customParseFormat from 'dayjs/plugin/customParseFormat'
 import iconQuestion from '../icon-question.png'
 import ColField from '@/components/col-field'
 import request from '@/helpers/request'
-import { browser } from '@/helpers/utils'
 import { postMessage } from '@/helpers/native-message'
+import TheSticky from '@/components/the-sticky'
 dayjs.extend(customParseFormat)
 dayjs.extend(isSameOrBefore)
 
 export default defineComponent({
   name: 'timer',
-  props: {
-    onChoice: {
-      // 点击选择时间
-      type: Function,
-      default: (item: any) => {}
-    },
-  },
   data() {
     return {
       startSetting: '08:00',  // 开始设置时间
@@ -48,13 +41,12 @@ export default defineComponent({
     }
   },
   async mounted() {
-    this._initFetch()
+   await this._initFetch()
     this.list = this.timerInit(
       this.startSetting,
       this.endSetting,
       this.courseMinutes + this.freeMinutes || 30
     )
-    console.log(this.endSetting)
   },
   methods: {
     async _initFetch() {
@@ -80,19 +72,9 @@ export default defineComponent({
         })
   
         // 获取课程设置
-        const setting = await request.post(
-          '/api-teacher/teacherFreeTime/getDetail',
-          {
-            data: {
-              defaultFlag: 1
-            }
-          }
-        )
+        const setting = await request.get('/api-teacher/teacherFreeTime/get')
         const sr = setting.data
         if (sr) {
-          this.courseMinutes = sr.courseMinutes
-          this.freeMinutes = sr.freeMinutes
-  
           this.timerObject = {
             monday: sr.monday ? JSON.parse(sr.monday) : [],
             tuesday: sr.tuesday ? JSON.parse(sr.tuesday) : [],
@@ -102,19 +84,7 @@ export default defineComponent({
             saturday: sr.saturday ? JSON.parse(sr.saturday) : [],
             sunday: sr.sunday ? JSON.parse(sr.sunday) : []
           }
-  
-          const tempIds: any = []
-          const tempPrices: any = []
-          const subjectPrice = sr.subjectPrice || []
-          subjectPrice.forEach((item: any) => {
-            tempIds.push(item.subjectId)
-            tempPrices.push({
-              subjectId: item.subjectId,
-              subjectPrice: item.subjectPrice,
-              subjectName: item.subjectName
-            })
-          })
-          const to = this.timerObject
+          this.skipHolidayFlag = sr.skipHolidayFlag ? 1 : 0
         }
   
         
@@ -218,14 +188,15 @@ export default defineComponent({
         })
       })
       await request.post('/api-teacher/teacherFreeTime/upSet', {
-        ...weekList,
-        skipHolidayFlag: this.skipHolidayFlag
+        data: {...weekList,
+          skipHolidayFlag: this.skipHolidayFlag}
       })
-      if(browser().isApp) {
-        postMessage({
-          api: 'back'
-        })
-      }
+      setTimeout(() => {
+        Toast('设置成功')
+      }, 100);
+      setTimeout(() => {
+        postMessage({ api: 'back', content: {} })
+      }, 500)
     }
   },
   render() {
@@ -260,7 +231,7 @@ export default defineComponent({
         {/* <div class={styles.tips}>
           <div class={styles.tipsTitle}>请选择陪练开始时间</div>
           <div class={styles.tipsTime}>
-            陪练课单课时时长为 <span>{this.courseMinutes}</span> 分钟
+            趣纠课单课时时长为 <span>{this.courseMinutes}</span> 分钟
           </div>
         </div> */}
 
@@ -325,13 +296,13 @@ export default defineComponent({
           ))}
         </div>
 
-        <Sticky offsetBottom={0} position="bottom">
-          <div class={'btnGroup'}>
+        <TheSticky position='bottom' >
+          <div class={['btnGroup', styles.btnGroupTimer]}>
             <Button block round type="primary" onClick={this.onSubmit}>
               确定
             </Button>
           </div>
-        </Sticky>
+        </TheSticky>
       </div>
     )
   }

+ 2 - 2
src/tenant/exercise-record/echats.ts

@@ -227,7 +227,7 @@ export const lineChartOption = {
 //         '0.00'
 //       ],
 //       symbol: 'circle',
-//       name: '陪练课',
+//       name: '趣纠课',
 //       type: 'line',
 //       emphasis: { lineStyle: { width: 1 } }
 //     },
@@ -519,7 +519,7 @@ export const pieChartOption = {
       avoidLabelOverlap: false,
       label: { show: false },
       data: [
-        { name: '陪练课', value: '0.00' },
+        { name: '趣纠课', value: '0.00' },
         { name: '直播课', value: '0.00' },
         { name: '视频课', value: '0.00' },
         { name: '乐谱', value: '0.00' },

+ 1 - 1
src/tenant/trade/tradeOrder.ts

@@ -7,7 +7,7 @@ import dayjs from 'dayjs'
 const apiSuffix =
   state.platformType === 'STUDENT' ? '/api-student' : '/api-teacher'
 // LIVE: '直播课',
-// PRACTICE: '陪练课',
+// PRACTICE: '趣纠课',
 // VIDEO: '视频课',
 // VIP: '开通会员',
 // MUSIC: '单曲点播'

+ 19 - 6
src/views/order-detail/index.tsx

@@ -40,6 +40,8 @@ import OrderAlbum from './order-album'
 import { useRect } from '@vant/use'
 import QrcodePayment from './qrcode-payment'
 import OrderTennatAlbum from './order-tennat-album'
+import { orderType } from '@/constant'
+import OrderDiscount from './order-discount'
 
 export default defineComponent({
   name: 'order-detail',
@@ -521,12 +523,6 @@ export default defineComponent({
                     item={item}
                     disabled={this.disabledCoupon}
                     onPriceChange={(price: number) => {
-                      console.log(
-                        price,
-                        this.orderAmount,
-                        orderStatus.orderObject.couponDiscountPrice,
-                        'orderStatus.orderObject.couponDiscountPrice'
-                      )
                       // 重置金额
                       this.orderAmount = Number(price)
                       const lastAmount = Number(
@@ -549,6 +545,23 @@ export default defineComponent({
                 return <OrderAlbum item={item} />
               } else if (item.orderType === 'TENANT_ALBUM') {
                 return <OrderTennatAlbum item={item} />
+              } else if (item.orderType === 'DISCOUNT') {
+                return (
+                  <OrderDiscount
+                    item={item}
+                    onPriceChange={(price: number) => {
+                      // 重置金额
+                      this.orderAmount = Number(price)
+                      const lastAmount = Number(
+                        (
+                          Number(this.orderAmount) -
+                          Number(orderStatus.orderObject.couponDiscountPrice)
+                        ).toFixed(2)
+                      )
+                      this.orderPrice = lastAmount >= 0 ? lastAmount : 0
+                    }}
+                  />
+                )
               }
             })}
 

+ 127 - 0
src/views/order-detail/order-discount/index.module.less

@@ -0,0 +1,127 @@
+.memberLogo {
+  width: 98px;
+  height: 98px;
+}
+
+.container {
+  padding-top: 2px;
+}
+
+.titleClass {
+  padding-left: 15px;
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+}
+
+.title {
+  padding-top: 2px;
+  font-size: 16px;
+  font-weight: 500;
+  line-height: 22px;
+
+  color: #131415;
+}
+
+.price {
+  padding-top: 8px;
+  font-size: 25px;
+  font-family: DINAlternate-Bold, DINAlternate;
+  font-weight: bold;
+  color: #EF2F56;
+
+  i {
+    line-height: 19px;
+    font-style: normal;
+    font-size: 16px;
+  }
+}
+
+.timerTitle {
+  display: flex;
+  align-items: center;
+  // font-size: 14px;
+  // font-weight: 500;
+  // color: #333333;
+
+  color: var(--van-cell-text-color) !important;
+  font-size: var(--van-cell-font-size) !important;
+  line-height: var(--van-cell-line-height) !important;
+  line-height: 20px;
+  padding-right: 12px;
+}
+
+.timer {
+  font-size: 14px;
+  font-weight: 500;
+  color: #FE2451;
+  line-height: 20px;
+}
+
+.timerCell {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+
+  // span {
+  //   font-size: 16px;
+  //   font-weight: 600;
+  //   color: #131415;
+  // }
+}
+
+.cellGroup {
+  border-radius: 10px;
+  overflow: hidden;
+}
+
+.cellGroupTimer {
+  :global {
+    .van-cell {
+      padding: 15px;
+    }
+  }
+}
+
+.discountTips {
+  background: linear-gradient(203deg, rgba(254, 237, 197, 0.5) 0%, rgba(255, 198, 179, 0.5) 100%);
+  border-radius: 6px;
+  padding: 6px 3px 6px 8px;
+  font-weight: 500;
+  font-size: 12px;
+  line-height: 17px;
+  color: #6B4429;
+  margin-bottom: 12px;
+
+  span {
+    color: #FF491A;
+  }
+}
+
+.addNum {
+  display: flex;
+  justify-content: flex-end;
+  --van-stepper-input-height: 22px;
+  --van-stepper-button-round-theme-color: #2DC7AA;
+
+  :global {
+    .van-stepper--round .van-stepper__minus {
+      // width: 22px;
+      // height: 22px;
+      border-color: #F7F8F9;
+      background-color: #F7F8F9;
+      color: #333333;
+    }
+
+    .van-stepper--round .van-stepper__input {
+      background: #F7F8F9;
+      border-radius: 6px;
+      margin: 0 8px;
+    }
+
+    .van-stepper--round .van-stepper__plus--disabled,
+    .van-stepper--round .van-stepper__minus--disabled {
+      opacity: 0.6;
+    }
+  }
+}

+ 128 - 0
src/views/order-detail/order-discount/index.tsx

@@ -0,0 +1,128 @@
+import { Cell, CellGroup, Icon, Image, Stepper } from 'vant'
+import { defineComponent } from 'vue'
+import styles from './index.module.less'
+// import { orderStatus } from '../orderStatus'
+
+import iconDiscount from '@common/images/icon_discount.png'
+import dayjs from 'dayjs'
+import { memberSimpleType } from '@/constant'
+
+export default defineComponent({
+  name: 'OrderVideo',
+  props: {
+    item: {
+      type: Object,
+      default: () => ({})
+    },
+    disabled: {
+      type: Boolean,
+      default: false
+    }
+  },
+  emits: ['priceChange'],
+  computed: {
+    startTime() {
+      const item = this.item
+      if (this.disabled) {
+        return item.startTime
+      }
+      if (item.svipEndDays > 0 && item.orderType === 'SVIP') {
+        return dayjs(item.startTime).add(1, 'day').format('YYYY-MM-DD')
+      }
+      if (item.vipEndDays > 0 && item.orderType === 'VIP') {
+        return dayjs(item.startTime).add(1, 'day').format('YYYY-MM-DD')
+      }
+      return item.startTime
+    }
+  },
+  render() {
+    const item = this.item
+    return (
+      <div class={styles.videoOrder}>
+        <CellGroup class={['mb12', styles.cellGroup]} border={false}>
+          <Cell
+            // center
+            titleClass={styles.titleClass}
+            v-slots={{
+              icon: () => (
+                <Image class={styles.memberLogo} src={iconDiscount} />
+              ),
+              title: () => (
+                <>
+                  <div class={styles.container}>
+                    <div class={styles.title}>
+                      {item.goodsName || item.goodName}
+                    </div>
+                    <div class={styles.price}>
+                      <i>¥ </i>
+                      {(this as any).$filters.moneyFormat(item.price)}
+                    </div>
+                  </div>
+                  <div class={styles.addNum}>
+                    <Stepper
+                      disableInput
+                      disabled={item.period === 'PERPETUAL' || this.disabled}
+                      v-model={item.num}
+                      theme="round"
+                      min={1}
+                      max={99}
+                      onChange={() => {
+                        let endTime = new Date()
+                        if (item.period === 'MONTH') {
+                          endTime = dayjs(item.startTime)
+                            .add(1 * item.num, 'month')
+                            .toDate()
+                        } else if (item.period === 'QUARTERLY') {
+                          endTime = dayjs(item.startTime)
+                            .add(3 * item.num, 'month')
+                            .toDate()
+                        } else if (item.period === 'YEAR_HALF') {
+                          endTime = dayjs(item.startTime)
+                            .add(6 * item.num, 'month')
+                            .toDate()
+                        } else if (item.period === 'YEAR') {
+                          endTime = dayjs(item.startTime)
+                            .add(1 * item.num, 'year')
+                            .toDate()
+                        }
+                        item.endTime = dayjs(endTime).format('YYYY-MM-DD')
+                        // 价格变化
+                        this.$emit(
+                          'priceChange',
+                          (item.price * item.num).toFixed(2)
+                        )
+                      }}
+                    ></Stepper>
+                  </div>
+                </>
+              )
+            }}
+          />
+        </CellGroup>
+
+        <CellGroup
+          class={['mb12', styles.cellGroup, styles.cellGroupTimer]}
+          border={false}
+        >
+          <Cell
+            center
+            v-slots={{
+              title: () => (
+                <div class={styles.timerCell}>
+                  <div class={styles.timerTitle}>
+                    {/* <Icon name={iconTimer} size={18} /> */}
+                    <span>生效时间</span>
+                  </div>
+                  <div class={styles.timer}>
+                    {this.startTime} 至 {item.endTime}
+                  </div>
+                </div>
+              )
+            }}
+          />
+        </CellGroup>
+      </div>
+      // 视频课
+    )
+  }
+})

+ 1 - 1
src/views/order-detail/order-practice/index.tsx

@@ -30,7 +30,7 @@ export default defineComponent({
             v-slots={{
               title: () => (
                 <div class={[styles.title, 'van-ellipsis']}>
-                  <span class={styles.tag}>陪练课</span>
+                  <span class={styles.tag}>趣纠课</span>
                   {item.courseGroupName}
                 </div>
               )

+ 1 - 0
src/views/order-detail/use-coupons/index.tsx

@@ -15,6 +15,7 @@ export const couponEnum = {
   PIANO_ROOM: 'PIANO',
   GOODS: 'MALL',
   MUSIC: 'MUSIC',
+  DISCOUNT: 'DISCOUNT',
   PRACTICE: 'SPARRING',
   LIVE: 'LIVE',
   VIDEO: 'VIDEO',