Ver código fonte

添加功能页面

lex 1 ano atrás
pai
commit
ae2c13de53
36 arquivos alterados com 2680 adições e 395 exclusões
  1. 41 0
      src/router/routes-tenant.ts
  2. 1 1
      src/state.ts
  3. BIN
      src/tenant/activation-code/icon-1.png
  4. 137 0
      src/tenant/activation-code/index.module.less
  5. 189 0
      src/tenant/activation-code/index.tsx
  6. 12 2
      src/tenant/exercise-record/exercis-detail.module.less
  7. 68 73
      src/tenant/exercise-record/exercis-detail.tsx
  8. 420 0
      src/tenant/goods-order/after-sale.tsx
  9. 115 0
      src/tenant/goods-order/components/after-sale-btns/index.tsx
  10. 119 0
      src/tenant/goods-order/index.module.less
  11. 234 0
      src/tenant/goods-order/index.tsx
  12. 44 0
      src/tenant/goods-order/item.tsx
  13. 2 2
      src/tenant/main.ts
  14. 1 1
      src/tenant/music/album-detail/index.tsx
  15. 1 2
      src/tenant/music/component/song-share/index.tsx
  16. 1 1
      src/tenant/music/component/song/index.module.less
  17. 1 1
      src/tenant/music/music-detail/index.tsx
  18. 35 33
      src/tenant/music/personal/tenant-album.tsx
  19. 11 1
      src/tenant/music/train-list/index.tsx
  20. BIN
      src/tenant/music/train-tool/images/icon-close.png
  21. BIN
      src/tenant/music/train-tool/images/icon-menu.png
  22. BIN
      src/tenant/music/train-tool/images/icon-pian.png
  23. BIN
      src/tenant/music/train-tool/images/icon-right-top.png
  24. BIN
      src/tenant/music/train-tool/images/icon-selected.png
  25. BIN
      src/tenant/music/train-tool/images/price-bg.png
  26. 364 0
      src/tenant/music/train-tool/index.module.less
  27. 416 0
      src/tenant/music/train-tool/index.tsx
  28. 18 0
      src/tenant/ranking-list/index.module.less
  29. 26 0
      src/tenant/ranking-list/index.tsx
  30. 5 3
      src/views/adapay/payment/index.tsx
  31. 122 119
      src/views/article-center/help-center.tsx
  32. 21 8
      src/views/order-detail/index.tsx
  33. 82 0
      src/views/order-detail/order-tennat-album/index.module.less
  34. 32 0
      src/views/order-detail/order-tennat-album/index.tsx
  35. 7 0
      src/views/order-detail/orderStatus.ts
  36. 155 148
      src/views/order-detail/userAuth/index.tsx

+ 41 - 0
src/router/routes-tenant.ts

@@ -53,6 +53,16 @@ const noLoginRouter = [
     meta: {
       title: '交易详情'
     }
+  },
+  {
+    path: '/helpCenter',
+    name: 'helpCenter',
+    component: () => import('@/views/article-center/help-center')
+  },
+  {
+    path: '/helpCenterDetail',
+    name: 'helpCenterDetail',
+    component: () => import('@/views/article-center/help-center-detail')
   }
 ]
 
@@ -130,6 +140,13 @@ export default [
         }
       },
       {
+        path: '/train-tool',
+        component: () => import('@/tenant/music/train-tool'),
+        meta: {
+          title: '训练工具'
+        }
+      },
+      {
         path: '/look-album-list',
         component: () => import('@/tenant/music/look-album-list'),
         meta: {
@@ -144,6 +161,30 @@ export default [
           title: '练习统计'
         }
       },
+      {
+        path: '/activation-code',
+        name: 'activation-code',
+        component: () => import('@/tenant/activation-code'),
+        meta: {
+          title: '激活码'
+        }
+      },
+      {
+        path: '/ranking-list',
+        name: 'ranking-list',
+        component: () => import('@/tenant/ranking-list'),
+        meta: {
+          title: '排行榜'
+        }
+      },
+      {
+        path: '/goodsOrder',
+        name: 'goodsOrder',
+        component: () => import('@/tenant/goods-order/index'),
+        meta: {
+          title: '订单信息'
+        }
+      },
       // {
       //   path: '/practiceClass',
       //   name: 'practiceClass',

+ 1 - 1
src/state.ts

@@ -18,7 +18,7 @@ export const state = reactive({
     unionId: 0 // 是否已关联账号
   } as any, // 管乐团信息
   projectType: 'default' as 'default' | 'tenant', // 机构端,还是默认
-  payBackPath: '/tenant/',
+  payBackPath: '/tenant.html',
   platformType: '' as 'STUDENT' | 'TEACHER',
   platformApi: '/api-student' as '/api-student' | '/api-teacher',
   version: '', // 版本号 例如: 1.0.0

BIN
src/tenant/activation-code/icon-1.png


+ 137 - 0
src/tenant/activation-code/index.module.less

@@ -0,0 +1,137 @@
+.bgImg {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 214px;
+  // object-fit: cover;
+  z-index: -1;
+}
+
+.sticky {
+  :global {
+    .van-sticky {
+      background: url('../images/bg-image.png') no-repeat top center;
+      background-size: 100% 214px;
+    }
+  }
+}
+
+.codeContainer {
+  display: flex;
+  align-items: center;
+  flex-direction: column;
+  padding: 20px 40px 20px;
+
+  .codeInput {
+    background: #FFFFFF;
+    border-radius: 10px;
+    border: 2px solid rgba(255, 60, 129, 1);
+    // border-image: linear-gradient(270deg, rgba(255, 60, 129, 1), rgba(255, 118, 166, 1)) 2 2;
+    height: 48px;
+    width: 100%;
+    text-align: center;
+    font-size: 16px;
+    font-weight: 400;
+    color: #333;
+
+    &::placeholder {
+      color: #AAAAAA
+    }
+  }
+
+  .codeBtn {
+    margin-top: 25px;
+    background: linear-gradient(270deg, #FF7B57 0%, #FF3460 100%);
+    border-radius: 22px;
+    border: none;
+    height: 44px;
+    font-size: 16px;
+    font-weight: 500;
+    color: #FFFFFF;
+  }
+}
+
+.colGroup {
+  margin: 20px 13px;
+  background: #FFFFFF;
+  border-radius: 10px;
+  padding: 0 12px;
+
+  .title {
+    display: flex;
+    align-items: center;
+    padding: 16px 0;
+    font-size: 16px;
+    font-weight: 600;
+    color: #131415;
+    line-height: 1;
+
+    img {
+      margin-top: -1px;
+      width: 18px;
+      height: 18px;
+      margin-right: 4px;
+    }
+  }
+
+
+  .colRow {
+    :global {
+      .van-col {
+        font-size: 14px;
+        font-weight: 500;
+        color: #333333;
+      }
+
+      .van-col--9 {
+        text-align: center;
+      }
+    }
+  }
+
+  .codeList {
+    :global {
+      .van-row {
+        padding: 16px 0;
+        font-size: 12px;
+        font-weight: 400;
+        color: #444444;
+        border-bottom: 1px solid #F2F2F2;
+
+        &:last-child {
+          border: none;
+        }
+      }
+
+      .van-col {
+        display: flex;
+        align-items: center;
+      }
+
+      .van-col--9 {
+        text-align: center;
+        justify-content: center;
+      }
+    }
+
+    .c1 {
+      color: #248FFE;
+    }
+
+    .c2 {
+      color: #FE2451;
+    }
+
+    .c3 {
+      color: #AAAAAA;
+    }
+
+    .liveBtn {
+      background: #FE2451;
+      border-radius: 6px;
+      padding: 0 20px;
+      height: 25px;
+    }
+  }
+}

+ 189 - 0
src/tenant/activation-code/index.tsx

@@ -0,0 +1,189 @@
+import TheSticky from '@/components/the-sticky'
+import { defineComponent, onMounted, reactive } from 'vue'
+import styles from './index.module.less'
+import ColHeader from '@/components/col-header'
+import bgImg from '../images/bg-image.png'
+import { Button, List, Row, Col, Toast } from 'vant'
+import icon1 from './icon-1.png'
+import request from '@/helpers/request'
+
+export default defineComponent({
+  name: 'activation-code',
+  setup() {
+    // tenantActivationCode/page
+    const state = reactive({
+      refreshing: false,
+      height: 0, // 页面头部高度,为了处理下拉刷新用的
+      list: [],
+      dataShow: true, // 判断是否有数据
+      loading: false,
+      finished: false,
+      params: {
+        page: 1,
+        rows: 10
+      },
+      isClick: false,
+      code: ''
+    })
+    const getList = async (hideLoading = false) => {
+      try {
+        if (state.isClick) return
+        state.isClick = true
+        const res = await request.post(
+          '/api-student/tenantActivationCode/page',
+          {
+            data: {
+              ...state.params
+            },
+            hideLoading: hideLoading
+          }
+        )
+        state.isClick = false
+        state.loading = false
+        state.refreshing = false
+        const result = res.data || {}
+        // 处理重复请求数据
+        if (state.list.length > 0 && result.current === 1) {
+          return
+        }
+        state.list = state.list.concat(result.rows || [])
+        state.finished = result.current >= result.pages
+        state.params.page = result.current + 1
+        state.dataShow = state.list.length > 0
+      } catch {
+        state.isClick = false
+        state.dataShow = false
+        state.refreshing = false
+        state.finished = true
+      }
+    }
+
+    const onSubmit = async () => {
+      try {
+        if (!state.code) {
+          Toast('请输入激活码')
+          return
+        }
+
+        await request.post(
+          '/api-student/tenantActivationCode/active?activationCode=' +
+            state.code
+        )
+        Toast.success('激活成功')
+        state.params.page = 1
+        getList(true)
+      } catch {
+        //
+      }
+    }
+
+    //
+    const onActiveation = async (item: any) => {
+      try {
+        await request.post(
+          '/api-student/tenantActivationCode/activeById?id=' + item.id
+        )
+        Toast.success('激活成功')
+        state.params.page = 1
+        getList(true)
+      } catch {
+        //
+      }
+    }
+
+    onMounted(() => {
+      getList()
+    })
+    return () => (
+      <div class={styles.activationCode}>
+        <div class={styles.sticky}>
+          <TheSticky position="top">
+            <ColHeader
+              background="transparent"
+              isFixed={false}
+              border={false}
+              color="#131415"
+            />
+            <div class={styles.codeContainer}>
+              <input
+                v-model={state.code}
+                placeholder="请输入激活码"
+                class={styles.codeInput}
+                maxlength={7}
+              />
+
+              <Button
+                type="primary"
+                round
+                class={styles.codeBtn}
+                block
+                onClick={onSubmit}
+              >
+                立即兑换
+              </Button>
+            </div>
+          </TheSticky>
+          <img class={styles.bgImg} src={bgImg} />
+
+          <List
+            loading-text=" "
+            // finished={finished.value}
+            finished-text=" "
+            // onLoad={getList}
+            style={{ overflow: 'hidden' }}
+          >
+            <div class={styles.colGroup}>
+              <div class={styles.title}>
+                <img src={icon1} />
+                激活记录
+              </div>
+              <Row class={styles.colRow}>
+                <Col span={5}>激活码</Col>
+                <Col span={4}>周期</Col>
+                <Col span={6}>激活状态</Col>
+                <Col span={9}>激活时间</Col>
+              </Row>
+
+              <div class={styles.codeList}>
+                {state.list.map((item: any) => (
+                  <Row>
+                    <Col span={5}>{item.activationCode}</Col>
+                    <Col span={4}>6个月</Col>
+                    <Col
+                      span={6}
+                      class={item.activationStatus ? styles.c1 : styles.c3}
+                    >
+                      {item.activationStatus ? '已激活' : '待激活'}
+                    </Col>
+                    <Col span={9}>
+                      {item.activationStatus ? (
+                        item.activationTime
+                      ) : (
+                        <Button
+                          class={styles.liveBtn}
+                          color="#FE2451"
+                          onClick={() => onActiveation(item)}
+                        >
+                          激活
+                        </Button>
+                      )}
+
+                      {/* 2023-07-22 12:00:02 */}
+                    </Col>
+                  </Row>
+                ))}
+              </div>
+            </div>
+          </List>
+          {/* ) : (
+            <div
+              class={styles.emptyContainer}
+            >
+              <ColResult tips="暂无学练统计" btnStatus={false} />
+            </div>
+          )} */}
+        </div>
+      </div>
+    )
+  }
+})

+ 12 - 2
src/tenant/exercise-record/exercis-detail.module.less

@@ -21,7 +21,7 @@
 }
 
 .userMember {
-  background-color: transparent;
+  background-color: transparent !important;
   width: auto;
   padding: 0;
   // border-radius: 10px;
@@ -111,7 +111,7 @@
   align-items: center;
   justify-content: space-around;
   text-align: center;
-  background-color: #fff;
+  background-color: transparent;
   border-radius: 10px;
   padding: 20px 0;
 
@@ -300,4 +300,14 @@
       }
     }
   }
+}
+
+.fullRefresh {
+  min-height: calc(100vh - var(--header-height) - 275px)
+}
+
+.emptyContainer {
+  height: calc(100vh - var(--header-height) - 275px);
+  display: flex;
+  align-items: center;
 }

+ 68 - 73
src/tenant/exercise-record/exercis-detail.tsx

@@ -99,7 +99,8 @@ export default defineComponent({
       userTrainOverView: {
         trainDays: 0,
         trainNum: 0,
-        trainTime: 0
+        trainTime: 0,
+        avgTrainTime: 0
       },
       userTrainChartData: [] as any,
       myChart: null as any
@@ -124,9 +125,7 @@ export default defineComponent({
       }
     })
     const forms = reactive({
-      practiceMonth: dayjs().day(1).format('YYYYMMDD'),
-      // startTime: dayjs().day(1).format('YYYYMMDD'),
-      startTime: dayjs().day(1).format('YYYY-MM'),
+      startTime: dayjs().day(1).format('YYYY-MM-DD'),
       endTime: dayjs().day(7).format('YYYY-MM-DD'),
       page: 1,
       rows: 20
@@ -148,7 +147,7 @@ export default defineComponent({
       }
       try {
         const { data } = await request.get(
-          `/api-student/sysMusicRecord/studentTrainData`,
+          `/api-student/sysMusicRecord/studentTrainDataByWeek`,
           {
             params: { ...forms }
           }
@@ -277,7 +276,7 @@ export default defineComponent({
               </div>
               <div class={styles.itemBottomDot}>
                 <p class={styles.dotMain}>
-                  {state.userTrainOverView.trainTime || 0}
+                  {state.userTrainOverView.avgTrainTime || 0}
                   <span>分钟</span>{' '}
                 </p>
                 <p class={styles.dotSub}>平均训练时长 </p>
@@ -287,71 +286,66 @@ export default defineComponent({
                   {state.userTrainOverView.trainNum || 0}
                   <span>次</span>{' '}
                 </p>
-                <p class={styles.dotSub}>平均训练次数 </p>
+                <p class={styles.dotSub}>累计训练次数 </p>
               </div>
             </div>
           </TheSticky>
         </div>
         <img class={styles.bgImg} src={bgImg} />
 
+        <div class={styles.trainWeek}>
+          <div class={styles.trainTitle}>
+            <img src={iconTrainTitle} />
+
+            <span
+              class={styles.timeRange}
+              onClick={() => (state.showPopoverTime = true)}
+            >
+              {dayjs(forms.startTime).format('YYYY-MM-DD')}至
+              {dayjs(forms.endTime).format('YYYY-MM-DD')}
+              <i class={styles.iconArrow}></i>
+            </span>
+          </div>
+          <div class={styles.TrainDataTopRight}>
+            <div
+              onClick={() => {
+                qualifiedFlag.value = !qualifiedFlag.value
+                lineChartOption.legend.selected['训练时长'] =
+                  qualifiedFlag.value
+                state.myChart.setOption(lineChartOption)
+              }}
+              class={[
+                styles.DataTopRightItem,
+                qualifiedFlag.value ? '' : styles.DataTopRightItemDis
+              ]}
+            >
+              <div class={styles.DataTopRightDot}></div>
+              <p>训练时长</p>
+            </div>
+            <div
+              onClick={() => {
+                unqualifiedFlag.value = !unqualifiedFlag.value
+                lineChartOption.legend.selected['使用次数'] =
+                  unqualifiedFlag.value
+                state.myChart.setOption(lineChartOption)
+              }}
+              class={[
+                styles.DataTopRightItem,
+                unqualifiedFlag.value ? '' : styles.DataTopRightItemDis
+              ]}
+            >
+              <div class={[styles.DataTopRightDot, styles.red]}></div>
+              <p>使用次数</p>
+            </div>
+          </div>
+          <div id="exerciseWeek" class={styles.exerciseWeek}></div>
+        </div>
         {showContact.value ? (
           <OFullRefresh
             v-model:modelValue={refreshing.value}
             onRefresh={onRefresh}
-            style={{ minHeight: `calc(100vh - var(--header-height))` }}
+            class={styles.fullRefresh}
           >
-            <div class={styles.trainWeek}>
-              <div class={styles.trainTitle}>
-                <img src={iconTrainTitle} />
-
-                <span
-                  class={styles.timeRange}
-                  onClick={() => (state.showPopoverTime = true)}
-                >
-                  {dayjs(forms.practiceMonth).format('YYYY-MM-DD')}至
-                  {dayjs(forms.endTime).format('YYYY-MM-DD')}
-                  <i class={styles.iconArrow}></i>
-                </span>
-              </div>
-              <div class={styles.TrainDataTopRight}>
-                <div
-                  onClick={() => {
-                    qualifiedFlag.value = !qualifiedFlag.value
-                    lineChartOption.legend.selected['训练时长'] =
-                      qualifiedFlag.value
-                    state.myChart.setOption(lineChartOption)
-                  }}
-                  class={[
-                    styles.DataTopRightItem,
-                    qualifiedFlag.value ? '' : styles.DataTopRightItemDis
-                  ]}
-                >
-                  <div class={styles.DataTopRightDot}></div>
-                  <p>训练时长</p>
-                </div>
-                <div
-                  onClick={() => {
-                    unqualifiedFlag.value = !unqualifiedFlag.value
-                    lineChartOption.legend.selected['使用次数'] =
-                      unqualifiedFlag.value
-                    state.myChart.setOption(lineChartOption)
-                  }}
-                  class={[
-                    styles.DataTopRightItem,
-                    unqualifiedFlag.value ? '' : styles.DataTopRightItemDis
-                  ]}
-                >
-                  <div class={[styles.DataTopRightDot, styles.red]}></div>
-                  <p>使用次数</p>
-                </div>
-              </div>
-              <div
-                id="exerciseWeek"
-                class={styles.exerciseWeek}
-                // style={{ height: payForm.height, width: payForm.width }}
-              ></div>
-            </div>
-
             <List
               loading-text=" "
               finished={finished.value}
@@ -366,11 +360,12 @@ export default defineComponent({
           </OFullRefresh>
         ) : (
           <div
-            style={{
-              height: `calc(100vh - var(--header-height))`,
-              display: 'flex',
-              alignItems: 'center'
-            }}
+            // style={{
+            //   height: `calc(100vh - var(--header-height))`,
+            //   display: 'flex',
+            //   alignItems: 'center'
+            // }}
+            class={styles.emptyContainer}
           >
             <ColResult tips="暂无学练统计" btnStatus={false} />
           </div>
@@ -385,38 +380,38 @@ export default defineComponent({
           maxRange={7}
           minDate={new Date('2023-02-27')}
           defaultDate={[
-            dayjs(forms.practiceMonth).toDate(),
+            dayjs(forms.startTime).toDate(),
             dayjs(forms.endTime).toDate()
           ]}
           style={{
             height: '70%'
           }}
           onSelect={(item: any) => {
-            forms.practiceMonth = ''
+            forms.startTime = ''
             forms.endTime = ''
             if (
               !dayjs(item[0]).isBetween(
-                dayjs(forms.practiceMonth),
+                dayjs(forms.startTime),
                 dayjs(forms.endTime)
               )
             ) {
               const week = dayjs(item[0]).day()
               if (week === 0) {
                 // 星期天
-                forms.practiceMonth = dayjs(item[0])
+                forms.startTime = dayjs(item[0])
                   .subtract(6, 'day')
-                  .format('YYYYMMDD')
+                  .format('YYYY-MM-DD')
                 forms.endTime = dayjs(item[0]).format('YYYY-MM-DD')
               } else if (week === 1) {
                 // 星期一
-                forms.practiceMonth = dayjs(item[0]).format('YYYYMMDD')
+                forms.startTime = dayjs(item[0]).format('YYYY-MM-DD')
                 forms.endTime = dayjs(item[0])
                   .add(6, 'day')
                   .format('YYYY-MM-DD')
               } else {
-                forms.practiceMonth = dayjs(item[0])
+                forms.startTime = dayjs(item[0])
                   .subtract(week - 1, 'day')
-                  .format('YYYYMMDD')
+                  .format('YYYY-MM-DD')
                 forms.endTime = dayjs(item[0])
                   .add(7 - week, 'day')
                   .format('YYYY-MM-DD')

+ 420 - 0
src/tenant/goods-order/after-sale.tsx

@@ -0,0 +1,420 @@
+import ColHeader from '@/components/col-header'
+import ColResult from '@/components/col-result'
+import request from '@/helpers/request'
+import { state } from '@/state'
+import {
+  ActionSheet,
+  Button,
+  Cell,
+  CellGroup,
+  Dialog,
+  Field,
+  Image,
+  List,
+  Tab,
+  Tabs,
+  Toast
+} from 'vant'
+import { defineComponent } from 'vue'
+import Item from './item'
+import styles from './index.module.less'
+
+const returnState = {
+  0: '待处理',
+  1: '退货中',
+  2: '已完成',
+  3: '已拒绝'
+}
+type good = {
+  description: string
+  memberUsername: string
+  orderId: number
+  orderSn: string
+  productAttr: string
+  productBrand: string
+  productCount: number
+  productId: number
+  productName: string
+  productPic: string
+  productPrice: number
+  productRealPrice: number
+  proofPics: string
+  returnName: string
+  returnPhone: string
+  orderItemId: string
+}
+
+export default defineComponent({
+  name: 'after-sale',
+  data() {
+    return {
+      active: '0',
+      list: [],
+      dataShow: false, // 判断是否有数据
+      loading: false,
+      finished: false,
+      show: false,
+      kmsShow: false,
+      params: {
+        pageNum: 1,
+        pageSize: 20
+      },
+
+      returnGood: {} as good,
+      reason: '', // 退货原因
+      returnOrderSn: '', // 退货快递单号
+      returnGoodId: 0 // 退货申请服务单号
+    }
+  },
+  watch: {
+    active() {
+      this.init()
+      this.getList()
+    }
+  },
+  mounted() {
+    this.getList()
+  },
+  methods: {
+    init() {
+      this.params.pageNum = 1
+      this.finished = false
+      this.list = []
+    },
+
+    async getList() {
+      //避免重复请求
+      console.log(this.loading, this.finished)
+      if (this.loading && this.finished) {
+        return
+      }
+      this.loading = true
+      let res: any
+      if (this.active === '0') {
+        // 可退货列表
+        res = await this.getIsReturnOrderList()
+      } else {
+        // 退货申请列表
+        res = await this.getReturnList()
+      }
+      if (res && res.code === 200 && res.data.list) {
+        let data = res.data
+        if (Array.isArray(data.list)) {
+          let list = [] as any
+          // 过滤一个订单里面所有商品都申请了退货
+          for (let i = 0; i < data.list.length; i++) {
+            if (data.list[i].orderItemList) {
+              let isHave =
+                data.list[i].orderItemList.findIndex(n => n.returnStatus < 0) >
+                -1
+              if (isHave) {
+                list.push(data.list[i])
+              }
+            } else {
+              list.push(data.list[i])
+            }
+          }
+          this.list = this.list.concat(this.list, list)
+        }
+        // this.list = [].concat(this.list, res.data.list)
+
+        this.params.pageNum = res.data.pageNum + 1
+      }
+      this.finished = this.params.pageNum >= res?.data?.totalPage
+      this.loading = false
+    },
+
+    //获取可退货列表
+    async getIsReturnOrderList(): Promise<object> {
+      try {
+        let res = await request.get('/api-mall-portal/order/list', {
+          params: {
+            ...this.params,
+            status: '1,2,3'
+          }
+        })
+        return res
+      } catch (error) {}
+      return {}
+    },
+
+    // 获取退货申请
+    async getReturnList(): Promise<object> {
+      try {
+        let res = await request.post('/api-mall-portal/returnApply/list', {
+          data: {
+            ...this.params,
+            status: this.active === '1' ? '0,1' : '2,3'
+          }
+        })
+        return res
+      } catch (error) {}
+      return {}
+    },
+
+    // 设置退货参数
+    setReturnParams(item: any, n: any): void {
+      this.returnGood.memberUsername = state.user.data.username
+      this.returnGood.orderId = item.id
+      this.returnGood.orderSn = item.orderSn
+      this.returnGood.productAttr = n.productAttr
+      this.returnGood.productBrand = n.productBrand
+      this.returnGood.productCount = n.productQuantity
+      this.returnGood.productId = n.productId
+      this.returnGood.productName = n.productName
+      this.returnGood.productPic = n.productPic
+      this.returnGood.productPrice = n.productPrice
+      this.returnGood.productRealPrice = n.productPrice
+      this.returnGood.proofPics = ''
+      this.returnGood.returnName = item.receiverName
+      this.returnGood.returnPhone = item.receiverPhone
+      this.returnGood.orderItemId = n.id
+      console.log(this.returnGood)
+    },
+    // 退商品
+    async setReturnShop(): Promise<void> {
+      if (!this.reason) {
+        Toast('请填写退货原因!')
+        return
+      }
+      try {
+        let res = await request.post('/api-mall-portal/returnApply/create', {
+          data: {
+            ...this.returnGood,
+            reason: this.reason
+          }
+        })
+        if (res.code === 200) {
+          Toast({
+            message: '退货申请成功',
+            icon: 'success'
+          })
+          setTimeout(() => {
+            this.show = false
+            this.reason = ''
+            this.returnOrderSn = ''
+            this.active = '1'
+          }, 500)
+        }
+      } catch (error) {}
+      this.returnGood = {} as good
+    },
+
+    // 填写快递单号
+    async setReturnApplySn(): Promise<void> {
+      if (!this.returnOrderSn) {
+        Toast('请填写退货快递单号')
+        return
+      }
+
+      try {
+        let { code, data } = await request.post(
+          '/api-mall-portal/returnApply/deliverySn',
+          {
+            data: {
+              deliverySn: this.returnOrderSn,
+              id: this.returnGoodId
+            }
+          }
+        )
+        if (code === 200) {
+          this.returnOrderSn = ''
+          this.kmsShow = false
+          this.init()
+          this.getList()
+        }
+      } catch (error) {}
+    },
+    //撤销申请
+    deleteReturnApply(): void {
+      Dialog.confirm({
+        title: '提示',
+        message: '是否撤销退货申请?',
+        confirmButtonText: '撤销',
+        confirmButtonColor: 'var(--van-primary)'
+      }).then(async () => {
+        try {
+          let { code, data } = await request.post(
+            '/api-mall-portal/returnApply/delete/' + this.returnGoodId
+          )
+          if (code === 200) {
+            this.init()
+            this.getList()
+          }
+        } catch (err) {}
+      })
+    }
+  },
+  render() {
+    const tabs = [
+      { name: '0', title: '全部' },
+      { name: '1', title: '处理中' },
+      { name: '2', title: '已处理' }
+    ]
+    return (
+      <div class={styles.shopOrder}>
+        <ColHeader />
+
+        <Tabs
+          v-model:active={this.active}
+          color="var(--van-primary)"
+          lineWidth={28}
+          animated
+          swipeable
+        >
+          {tabs.map(tab => (
+            <Tab name={tab.name} title={tab.title}>
+              {this.list.length ? (
+                <List
+                  loading={this.loading}
+                  finished={this.finished}
+                  finishedText=" "
+                  class={[styles.goodsList]}
+                  onLoad={this.getList}
+                >
+                  {this.active === tab.name &&
+                    this.list.map((item: any) => (
+                      <>
+                        {item.orderItemList && item.orderItemList.length ? (
+                          item.orderItemList.map((n: any) => (
+                            <CellGroup class={styles.cellGroup}>
+                              <Item item={n} />
+                              <Cell
+                                center
+                                v-slots={{
+                                  default: () => (
+                                    <div class={styles.btnList}>
+                                      {this.active === '0' &&
+                                      n.returnStatus < 0 && (item.status == 3 ? (item.afterSale == 0) : true) ? (
+                                        <Button
+                                          size="small"
+                                          round
+                                          type="primary"
+                                          onClick={() => {
+                                            this.show = true
+                                            this.setReturnParams(item, n)
+                                          }}
+                                        >
+                                          退货申请
+                                        </Button>
+                                      ) : null}
+                                      {n.returnStatus >= 0 ? (
+                                        <div>{returnState[n.returnStatus]}</div>
+                                      ) : null}
+                                    </div>
+                                  )
+                                }}
+                              ></Cell>
+                            </CellGroup>
+                          ))
+                        ) : (
+                          <CellGroup class={styles.cellGroup}>
+                            <Cell
+                              title={item.createTime}
+                              titleClass={styles.payTime}
+                              value={returnState[item.status]}
+                              // valueClass={}
+                            ></Cell>
+                            <Item item={item} />
+                            <Cell
+                              center
+                              v-slots={{
+                                default: () => (
+                                  <div class={styles.btnList}>
+                                    {item.status === 1 && !item.deliverySn ? (
+                                      <Button
+                                        size="small"
+                                        round
+                                        onClick={() => {
+                                          this.returnGoodId = item.id
+                                          this.kmsShow = true
+                                        }}
+                                      >
+                                        填写退货快递单号
+                                      </Button>
+                                    ) : null}
+                                    {item.status <= 1 ? (
+                                      <Button
+                                        size="small"
+                                        round
+                                        type="primary"
+                                        onClick={() => {
+                                          this.returnGoodId = item.id
+                                          this.deleteReturnApply()
+                                        }}
+                                      >
+                                        撤销申请
+                                      </Button>
+                                    ) : null}
+                                    {item.status === 2 ? (
+                                      <div class={styles.returnDes}>
+                                        该商品金额已于 {item.handleTime}{' '}
+                                        原路退还
+                                      </div>
+                                    ) : item.status === 3 ? (
+                                      <div class={styles.returnDes}>
+                                        拒绝原因: {item.handleNote}
+                                      </div>
+                                    ) : null}
+                                  </div>
+                                )
+                              }}
+                            ></Cell>
+                          </CellGroup>
+                        )}
+                      </>
+                    ))}
+                </List>
+              ) : (
+                <ColResult
+                  btnStatus={false}
+                  classImgSize="SMALL"
+                  tips="暂无数据"
+                />
+              )}
+            </Tab>
+          ))}
+        </Tabs>
+
+        <ActionSheet v-model:show={this.show} title="退货原因">
+          <div style={{ paddingTop: '15px' }}>
+            <Field
+              class={[styles.field]}
+              placeholder="请输入退货原因"
+              type="textarea"
+              rows={3}
+              v-model={this.reason}
+            />
+          </div>
+          <div class={styles['btn-group']}>
+            <Button
+              type="primary"
+              block
+              round
+              onClick={() => this.setReturnShop()}
+            >
+              确定
+            </Button>
+          </div>
+        </ActionSheet>
+        <ActionSheet v-model:show={this.kmsShow} title="填写退货快递单号">
+          <Field
+            v-model={this.returnOrderSn}
+            class={[styles.field]}
+            placeholder="请输入退货快递单号"
+          />
+          <div class={styles['btn-group']}>
+            <Button
+              type="primary"
+              block
+              round
+              onClick={() => this.setReturnApplySn()}
+            >
+              确定
+            </Button>
+          </div>
+        </ActionSheet>
+      </div>
+    )
+  }
+})

+ 115 - 0
src/tenant/goods-order/components/after-sale-btns/index.tsx

@@ -0,0 +1,115 @@
+import { moneyFormat } from '@/helpers/utils'
+import { Button, Cell } from 'vant'
+import { defineComponent, PropType } from 'vue'
+import styles from '../../index.module.less'
+
+export default defineComponent({
+  name: 'AfterSaleBtns',
+  props: {
+    item: {
+      type: Object,
+      default: {}
+    },
+    onCancelOrder: {
+      type: Function,
+      default: (n: any) => {}
+    },
+    onPayOrder: {
+      type: Function,
+      default: (n: any) => {}
+    },
+    onConfirmReceipt: {
+      type: Function,
+      default: (n: any) => {}
+    },
+    onAginOrder: {
+      type: Function,
+      default: (n: any) => {}
+    }
+  },
+  setup({ item, onCancelOrder, onPayOrder, onConfirmReceipt, onAginOrder }) {
+    return () => (
+      <Cell
+        center
+        v-slots={{
+          title: () => (
+            <div class={styles.orderPrice}>
+              <div>
+                订单金额
+                <span class={styles.price} style={{ paddingLeft: '5px' }}>
+                  <i>¥ </i>
+                  {moneyFormat(item.payAmount)}
+                </span>
+              </div>
+              {!!item.couponAmount && (
+                <div class={styles.coupon}>
+                  优惠券: -¥ {moneyFormat(item.couponAmount)}
+                </div>
+              )}
+            </div>
+          ),
+          default: () => (
+            <div class={styles.btnList}>
+              {/* <span class={styles.sureGoods}>已确认收货</span> */}
+
+              {item.status === 0 || item.status === 6 ? (
+                <>
+                  <Button
+                    size="small"
+                    round
+                    onClick={(e: Event) => {
+                      e.stopPropagation()
+                      onCancelOrder!(item)
+                    }}
+                  >
+                    取消订单
+                  </Button>
+                  <Button
+                    size="small"
+                    round
+                    type="primary"
+                    onClick={(e: Event) => {
+                      e.stopPropagation()
+                      onPayOrder!(item)
+                    }}
+                  >
+                    继续支付
+                  </Button>
+                </>
+              ) : null}
+              {item.status === 2 ? (
+                <Button
+                  size="small"
+                  round
+                  type="primary"
+                  onClick={(e: Event) => {
+                    e.stopPropagation()
+                    onConfirmReceipt!(item)
+                  }}
+                >
+                  确认收货
+                </Button>
+              ) : null}
+              {item.status === 3 ? (
+                <>
+                  <span class={styles.confirmReceipt}>已确认收货</span>
+                  <Button
+                    size="small"
+                    round
+                    type="primary"
+                    onClick={(e: Event) => {
+                      e.stopPropagation()
+                      onAginOrder!(item)
+                    }}
+                  >
+                    再来一单
+                  </Button>
+                </>
+              ) : null}
+            </div>
+          )
+        }}
+      ></Cell>
+    )
+  }
+})

+ 119 - 0
src/tenant/goods-order/index.module.less

@@ -0,0 +1,119 @@
+.shopOrder {
+  --van-nav-bar-text-color: #666666;
+  :global {
+    .van-tab__panel {
+      min-height: calc(100vh - var(--van-tabs-line-height) - var(--van-nav-bar-height) - 45px);
+    }
+  }
+}
+
+.goodsList {
+  margin-top: 12px;
+}
+
+.payTime {
+  font-size: 13px;
+  color: #666666;
+}
+.payStatus {
+  color: #ff4e19;
+}
+.paySuccess {
+  color: var(--van-primary);
+}
+
+.cellGroup {
+  margin: 12px 14px;
+  border-radius: 10px;
+  overflow: hidden;
+}
+
+.goodsImg {
+  width: 100px;
+  height: 100px;
+  border-radius: 8px;
+  overflow: hidden;
+}
+
+.goodsContainer {
+  margin-left: 10px;
+}
+
+.goodsTitle {
+  font-size: 16px;
+  color: #333333;
+  line-height: 22px;
+}
+
+.model {
+  font-size: 14px;
+  color: #999999;
+  line-height: 20px;
+  padding: 6px 0 10px 0;
+}
+
+.goodsPrice {
+  display: flex;
+  justify-content: space-between;
+
+  .num {
+    font-size: 12px;
+    font-weight: 500;
+    color: #666666;
+    line-height: 17px;
+  }
+}
+
+.btnList {
+  display: flex;
+  align-items: center;
+  justify-content: flex-end;
+  :global {
+    .van-button + .van-button {
+      margin-left: 10px;
+    }
+  }
+}
+
+.price {
+  color: #ff4e19;
+  font-size: 16px;
+  i {
+    font-size: 12px;
+    font-style: normal;
+  }
+}
+.coupon{
+  font-size: 12px;
+  color: #ff4e19;
+}
+
+.sureGoods {
+  padding-right: 12px;
+  font-size: 12px;
+  color: #999999;
+  line-height: 17px;
+}
+
+.field {
+  margin: 0 26px 13px;
+  border: 1px solid #dedede;
+  width: auto;
+  border-radius: 10px;
+  overflow: hidden;
+}
+
+.btn-group {
+  padding: 0 15% 12px;
+}
+.returnDes {
+  color: #666;
+  font-size: 14px;
+  margin-right: auto;
+}
+
+.confirmReceipt{
+  font-size: 12px;
+  color: #999;
+  margin-right: 19px;
+}

+ 234 - 0
src/tenant/goods-order/index.tsx

@@ -0,0 +1,234 @@
+import ColHeader from '@/components/col-header'
+import ColResult from '@/components/col-result'
+import request from '@/helpers/request'
+import { Button, Cell, CellGroup, Dialog, Image, List, Tab, Tabs } from 'vant'
+import { defineComponent } from 'vue'
+import styles from './index.module.less'
+import { orderState } from '@/views/shop-mall/shop-mall'
+import { cartConfirm } from '@/views/cart/cart'
+import Item from './item'
+import AfterSaleBtns from './components/after-sale-btns'
+import { useEventTracking } from '@/helpers/hooks'
+
+export default defineComponent({
+  name: 'shop-order',
+  data() {
+    return {
+      active: 0,
+      list: [],
+      dataShow: true, // 判断是否有数据
+      loading: false,
+      finished: false,
+      params: {
+        search: '',
+        groupStatus: 'APPLY',
+        page: 1,
+        rows: 20
+      },
+      page: {
+        pageNum: 1,
+        pageSize: 20
+      }
+    }
+  },
+  watch: {
+    active(val) {
+      this.init()
+      this.getList()
+    }
+  },
+  mounted() {
+    useEventTracking('订单')
+  },
+  methods: {
+    init() {
+      this.page.pageNum = 1
+      this.finished = false
+      this.list = []
+      this.dataShow = true
+    },
+    async getList() {
+      if (this.loading || this.finished) {
+        return
+      }
+      this.loading = true
+      try {
+        const { code, data } = await request.get(
+          '/api-mall-portal/order/list',
+          {
+            params: {
+              ...this.page,
+              status:
+                this.active === 0 ? '0,6' : this.active === 1 ? '1,2' : '3,4'
+            }
+          }
+        )
+
+        if (code === 200 && data.list) {
+          this.page.pageNum += 1
+          this.list = [].concat(this.list as any, data.list)
+        }
+        if (this.list.length >= data.total) {
+          this.finished = true
+        }
+
+        if (this.list.length === 0) {
+          this.dataShow = false
+        }
+      } catch (error) {
+        this.finished = true
+        this.dataShow = false
+      }
+      this.loading = false
+    },
+    onClickRight() {
+      this.$router.push('/afterSale')
+    },
+
+    async cancelOrder(item: any) {
+      const dialog = await Dialog.confirm({
+        title: '提示',
+        message: '确认取消订单?',
+        confirmButtonText: '取消订单',
+        confirmButtonColor: 'var(--van-primary)'
+      })
+      if (dialog === 'confirm') {
+        const { code, data } = await request.post(
+          '/api-mall-portal/order/cancelUserOrder',
+          { params: { orderId: item.id } }
+        )
+        if (code === 200) {
+          this.init()
+          this.getList()
+        }
+      }
+    },
+    payOrder(item: any) {
+      cartConfirm.orderInfo = item
+      this.$router.push({ path: '/cartConfirmAgin' })
+    },
+
+    // 再来一单
+    async onAginOrder(item: any) {
+      try {
+        const res = await request.post('/api-mall-portal/order/oneOrder', {
+          params: {
+            orderId: item.id
+          }
+        })
+        const { code, data } = res
+        if (code === 200) {
+          cartConfirm.calcAmount = data.calcAmount
+          cartConfirm.cartPromotionItemList = data.cartPromotionItemList
+          cartConfirm.memberReceiveAddressList = data.memberReceiveAddressList
+          this.$router.push({
+            path: '/cartConfirm'
+          })
+        }
+        console.log(res)
+      } catch (error) {}
+    },
+
+    // 确认收货
+    async onConfirmReceipt(item: any) {
+      const dialog = await Dialog.confirm({
+        title: '提示',
+        message: '确认收货?',
+        confirmButtonText: '收货',
+        confirmButtonColor: 'var(--van-primary)'
+      })
+      if (dialog === 'confirm') {
+        const res = await request.post(
+          '/api-mall-portal/order/confirmReceiveOrder',
+          { params: { orderId: item.id } }
+        )
+        if (res.code === 200) {
+          this.init()
+          this.getList()
+        }
+      }
+    }
+  },
+  render() {
+    const tabs = [
+      { name: 0, title: '待支付' },
+      { name: 1, title: '待收货' },
+      { name: 2, title: '已完成' }
+    ]
+
+    return (
+      <div class={styles.shopOrder}>
+        <ColHeader
+          ref="colHeader"
+          class="header"
+          rightText="售后服务"
+          onClickRight={this.onClickRight}
+        />
+        <Tabs
+          v-model:active={this.active}
+          color="var(--van-primary)"
+          lineWidth={28}
+          animated
+          swipeable
+        >
+          {tabs.map(tab => (
+            <Tab name={tab.name} title={tab.title}>
+              {this.active === tab.name && this.dataShow ? (
+                <List
+                  loading={this.loading}
+                  finished={this.finished}
+                  finishedText=" "
+                  class={[styles.goodsList]}
+                  onLoad={this.getList}
+                >
+                  {this.list.map((item: any) => (
+                    <>
+                      <CellGroup
+                        class={styles.cellGroup}
+                        onClick={() => {
+                          this.$router.push({
+                            path: '/shopOrderDetail',
+                            query: { id: item.id }
+                          })
+                        }}
+                      >
+                        <Cell
+                          title={item.createTime}
+                          titleClass={styles.payTime}
+                          value={orderState[item.status]}
+                          valueClass={
+                            [0, 4, 5, 6].includes(item.status)
+                              ? styles.payStatus
+                              : styles.paySuccess
+                          }
+                        ></Cell>
+                        {item.orderItemList && item.orderItemList.length
+                          ? item.orderItemList.map((n: any) => (
+                              <Item item={n} />
+                            ))
+                          : null}
+                        <AfterSaleBtns
+                          item={item}
+                          onCancelOrder={this.cancelOrder}
+                          onPayOrder={this.payOrder}
+                          onConfirmReceipt={this.onConfirmReceipt}
+                          onAginOrder={this.onAginOrder}
+                        />
+                      </CellGroup>
+                    </>
+                  ))}
+                </List>
+              ) : (
+                <ColResult
+                  btnStatus={false}
+                  classImgSize="SMALL"
+                  tips="暂无订单"
+                />
+              )}
+            </Tab>
+          ))}
+        </Tabs>
+      </div>
+    )
+  }
+})

+ 44 - 0
src/tenant/goods-order/item.tsx

@@ -0,0 +1,44 @@
+import { moneyFormat } from '@/helpers/utils'
+import { Cell, Image } from 'vant'
+import { defineComponent } from 'vue'
+import { formateAttr } from '../../views/cart/cart'
+import styles from './index.module.less'
+
+export default defineComponent({
+  name: 'GoodItem',
+  props: {
+    item: {
+      type: Object,
+      default: {}
+    }
+  },
+  setup({ item }) {
+    return () => (
+      <Cell
+        center
+        v-slots={{
+          icon: () => (
+            <Image class={styles.goodsImg} src={item.productPic} fit="cover" />
+          ),
+          default: () => (
+            <div class={styles.goodsContainer}>
+              <div class={[styles.goodsTitle, 'van-ellipsis']}>
+                {item.productName}
+              </div>
+              <div class={styles.model}>{formateAttr(item.productAttr)}</div>
+              <div class={styles.goodsPrice}>
+                <span class={styles.price}>
+                  <i>¥</i>
+                  {moneyFormat(item.productPrice)}
+                </span>
+                <span class={styles.num}>
+                  x{item.productQuantity || item.productCount}
+                </span>
+              </div>
+            </div>
+          )
+        }}
+      ></Cell>
+    )
+  }
+})

+ 2 - 2
src/tenant/main.ts

@@ -15,8 +15,8 @@ import { browser, setAuth } from '@/helpers/utils'
 
 const app = createApp(App)
 
-import Vconsole from 'vconsole'
-const vconsole = new Vconsole()
+// import Vconsole from 'vconsole'
+// const vconsole = new Vconsole()
 postMessage(
   {
     api: 'getVersion'

+ 1 - 1
src/tenant/music/album-detail/index.tsx

@@ -233,7 +233,7 @@ export default defineComponent({
         }
       }
       shareUrl.value = `${location.origin}/teacher#/shareAblum?id=${id}&recomUserId=${userId}&activityId=${activityId}&userType=${state.platformType}`
-      console.log(shareUrl.value, 'shareUrl')
+      // console.log(shareUrl.value, 'shareUrl')
       shareStatus.value = true
     }
 

+ 1 - 2
src/tenant/music/component/song-share/index.tsx

@@ -28,7 +28,6 @@ export default defineComponent({
   },
   emits: ['detail'],
   setup(props, { emit }) {
-
     const list = computed(() => {
       return props.list.map(n => {
         if (typeof n.paymentType === 'string')
@@ -70,7 +69,7 @@ export default defineComponent({
                   </span>
 
                   <div class={styles.tags}>
-                    {n?.subjectNames.split(',').map((name: any) => (
+                    {n?.subjectNames?.split(',').map((name: any) => (
                       <span>{name}</span>
                     ))}
                   </div>

+ 1 - 1
src/tenant/music/component/song/index.module.less

@@ -8,7 +8,7 @@
   .item {
     display: flex;
     align-items: center;
-    border-bottom: 1px solid #f2f2f2;
+    // border-bottom: 1px solid #f2f2f2;
     padding: 16px 0;
 
     &:last-child {

+ 1 - 1
src/tenant/music/music-detail/index.tsx

@@ -961,7 +961,7 @@ export default defineComponent({
                   <h4 class="van-multi-ellipsis--l2">
                     {musicDetail.value?.musicSheetName}
                   </h4>
-                  <p>作曲人:{musicDetail.value?.composer}</p>
+                  <p>作曲人:{musicDetail.value?.composer || ''}</p>
                 </div>
               </div>
             </ColShare>

+ 35 - 33
src/tenant/music/personal/tenant-album.tsx

@@ -35,6 +35,7 @@ export default defineComponent({
         })
         rows.value = [...rows.value, ...res.data.rows]
         data.value = res.data
+        console.log(data.value)
         params.page = res.data.pageNo + 1
         finished.value = res.data.pageNo >= res.data.totalPage
       } catch (error) {
@@ -48,42 +49,43 @@ export default defineComponent({
         <List
           loading={loading.value}
           finished={finished.value}
-          finished-text={rows.value.length ? '没有更多了' : ''}
+          finished-text={rows.value.length ? ' ' : ''}
           onLoad={FetchList}
           error={isError.value}
         >
-          {rows.value.length ? (
-            <CellGroup class={styles.tennatCellGroup} border={false}>
-              <Cell isLink>
-                {{
-                  icon: () => <img class={styles.tenantLogo} />,
-                  title: () => <div class={styles.tenantName}>测试机构</div>
-                }}
-              </Cell>
-              <Cell>
-                {{
-                  icon: () => <Image class={styles.tenantCoverImg} />,
-                  title: () => (
-                    <div class={styles.tenantContent}>
-                      <h2>巴赫旧约 | 四号勃兰登堡长笛协奏曲</h2>
-                      <p class="van-multi-ellipsis--l2">
-                        巴赫经典曲目巴赫经典曲目巴赫经典曲目巴赫经典曲目巴赫经典曲目
-                        巴赫经典曲目 巴赫经典曲目 巴赫经典曲目 巴赫经典曲目
-                      </p>
-                    </div>
-                  )
-                }}
-              </Cell>
-            </CellGroup>
-          ) : (
-            !loading.value && (
-              <ColResult
-                tips="暂无训练教程"
-                classImgSize="SMALL"
-                btnStatus={false}
-              />
-            )
-          )}
+          {rows.value.length
+            ? rows.value.map((item: any) => (
+                <CellGroup class={styles.tennatCellGroup} border={false}>
+                  <Cell isLink>
+                    {{
+                      icon: () => (
+                        <img src={item.coverImg} class={styles.tenantLogo} />
+                      ),
+                      title: () => (
+                        <div class={styles.tenantName}>{item.tenantName}</div>
+                      )
+                    }}
+                  </Cell>
+                  <Cell>
+                    {{
+                      icon: () => <Image class={styles.tenantCoverImg} />,
+                      title: () => (
+                        <div class={styles.tenantContent}>
+                          <h2>{item.name}</h2>
+                          <p class="van-multi-ellipsis--l2">{item.describe}</p>
+                        </div>
+                      )
+                    }}
+                  </Cell>
+                </CellGroup>
+              ))
+            : !loading.value && (
+                <ColResult
+                  tips="暂无训练教程"
+                  classImgSize="SMALL"
+                  btnStatus={false}
+                />
+              )}
         </List>
       )
     }

+ 11 - 1
src/tenant/music/train-list/index.tsx

@@ -251,6 +251,16 @@ export default defineComponent({
     }
 
     onMounted(async () => {
+      // SUBJECT: '声部练习',
+      // MUSIC: '独奏曲目',
+      // ENSEMBLE: '合奏练习'
+      if (params.subjectType === 'SUBJECT') {
+        document.title = '声部练习'
+      } else if (params.subjectType === 'MUSIC') {
+        document.title = '独奏曲目'
+      } else if (params.subjectType === 'ENSEMBLE') {
+        document.title = '合奏练习'
+      }
       getSubjectList()
       getSelectCondition()
     })
@@ -360,7 +370,7 @@ export default defineComponent({
               ) : (
                 !loading.value && (
                   <ColResult
-                    tips="暂无声部训练"
+                    tips="暂无曲目"
                     classImgSize="SMALL"
                     btnStatus={false}
                   />

BIN
src/tenant/music/train-tool/images/icon-close.png


BIN
src/tenant/music/train-tool/images/icon-menu.png


BIN
src/tenant/music/train-tool/images/icon-pian.png


BIN
src/tenant/music/train-tool/images/icon-right-top.png


BIN
src/tenant/music/train-tool/images/icon-selected.png


BIN
src/tenant/music/train-tool/images/price-bg.png


+ 364 - 0
src/tenant/music/train-tool/index.module.less

@@ -0,0 +1,364 @@
+.musicContent {
+  position: absolute;
+  top: 0;
+  height: 265px;
+  width: 100%;
+  padding-top: 55px;
+  z-index: 10;
+  background-color: rgba(0, 0, 0, 0.2);
+  backdrop-filter: blur(20px);
+  -webkit-backdrop-filter: blur(20px);
+}
+
+
+.bgImg {
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 265px;
+  object-fit: cover;
+  filter: blur(20px);
+  backdrop-filter: blur(22px);
+  -webkit-backdrop-filter: blur(20px);
+}
+
+.bg {
+  position: relative;
+  height: 100%;
+  padding: 16px 16px 12px;
+  z-index: 11;
+}
+
+.alumWrap {
+  position: relative;
+  display: flex;
+  align-items: center;
+  flex-direction: column;
+  margin-bottom: 76px;
+
+  .img {
+    width: 118px;
+    height: 118px;
+    flex-shrink: 0;
+    border-radius: 6px;
+    position: relative;
+    z-index: 9;
+  }
+
+  .iconPian {
+    position: absolute;
+    right: -40px;
+    top: 8px;
+    z-index: -1;
+    width: 110px;
+    height: 110px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    background: url('./images/icon-pian.png') no-repeat center;
+    background-size: contain;
+
+    :global {
+      .van-image {
+        width: 60px !important;
+        height: 60px !important;
+        border-radius: 50%;
+        overflow: hidden;
+      }
+    }
+  }
+
+  .numContent {
+    position: absolute;
+    right: 4px;
+    bottom: 4px;
+    display: flex;
+    align-items: center;
+    background: rgba(255, 255, 255, 0.8);
+    border-radius: 4px;
+    font-size: 12px;
+    font-weight: 500;
+    color: #000000;
+    padding: 2px 3px;
+
+    .iconMenu {
+      margin-top: -2px;
+      width: 10px;
+      height: 12px;
+      margin-right: 4px;
+    }
+  }
+
+  .alumTitle {
+    font-size: 16px;
+    font-weight: 600;
+    color: #fff;
+    line-height: 24px;
+    padding-bottom: 8px;
+  }
+
+  .alumDes {
+    position: absolute;
+    bottom: -80px;
+    z-index: 99;
+    width: calc(100% - 96px);
+    padding-top: 16px;
+    text-align: center;
+
+    .des {
+
+      font-size: 12px;
+      color: #fff;
+    }
+  }
+}
+
+.musicList {
+  position: relative;
+  z-index: 12;
+  background-color: #fff;
+  border-radius: 16px;
+  min-height: 40vh; //calc(100vh - 210px - var(--header-height));
+
+  --van-cell-background-color: transparent;
+  --van-cell-font-size: 16px;
+  --van-cell-text-color: #333;
+  --van-cell-value-color: #999;
+  --van-cell-icon-size: 10px;
+
+  :global {
+    .van-tab {
+      font-size: 16px !important;
+      margin-top: 15px;
+      color: #999999;
+    }
+
+    .van-tab--active {
+      font-size: 16px !important;
+      color: #131415;
+    }
+
+    .van-tabs__line {
+      width: 24px;
+      height: 4px;
+      background: linear-gradient(90deg, #FF3C81 0%, rgba(255, 118, 166, 0.5) 100%) !important;
+      border-radius: 36px 36px 0px 0px;
+    }
+
+    .van-button--plain.van-button--primary {
+      background-color: transparent;
+    }
+  }
+
+  .alumnList {
+    padding: 0 15px;
+  }
+}
+
+.btnGroup {
+  // background-color: #fff;
+  padding: 12px;
+
+  :global {
+    .van-button {
+      font-size: 18px;
+      font-weight: 500;
+    }
+  }
+}
+
+
+.system-list::-webkit-scrollbar {
+  display: none;
+  /* Chrome Safari */
+}
+
+.system-list {
+  width: 100%;
+  overflow-x: auto;
+  overflow-y: hidden;
+  display: flex;
+  position: relative;
+  user-select: none;
+  box-sizing: content-box;
+  margin-bottom: 25px;
+  height: auto;
+  transition: all .2s;
+
+  &.systemHide {
+    height: 0;
+    transition: all .2s;
+    margin-bottom: 0px;
+  }
+}
+
+.system-item {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  flex: 1 0 auto;
+  width: 96px;
+  min-height: 120px;
+  box-sizing: border-box;
+  background: #ffffff;
+  border-radius: 12px;
+  border: 1px solid #e5e5e5;
+  margin-left: 10px;
+
+  &:last-child {
+    margin-right: 10px;
+  }
+
+  .title {
+    font-size: 14px;
+    font-weight: 500;
+    color: #333333;
+    line-height: 20px;
+  }
+
+  .price {
+    color: #EF2F56;
+    font-size: 25px;
+    line-height: 1.5;
+    font-family: DINAlternate-Bold, DINAlternate;
+    font-weight: bold;
+
+    span {
+      font-size: 16px;
+    }
+  }
+
+  .originalPrice {
+    color: #999999;
+    font-size: 13px;
+  }
+
+  &.active {
+    background: linear-gradient(223deg, #FEECE3 0%, #FEE4E3 52%, #FFDCE6 100%);
+    border: 1px solid #FF4264;
+    position: relative;
+
+    .title {
+      color: #EF2F56;
+    }
+
+
+    .originalPrice {
+      color: #EF2F56;
+    }
+
+    &::before {
+      content: ' ';
+      font: 14px/1 'vant-icon';
+      width: 27px;
+      height: 18px;
+
+      position: absolute;
+      top: -1px;
+      right: -1px;
+      background: url('./images/icon-selected.png') no-repeat center;
+      background-size: contain;
+    }
+  }
+}
+
+.bottom_function {
+  background: url('./images/price-bg.png') no-repeat top center #fff;
+  background-size: contain;
+  box-shadow: inset 0px 1px 0px 0px #FFFFFF;
+  border-radius: 16px 16px 0px 0px;
+  // border: none;
+
+  .iconRightTop {
+    position: absolute;
+    top: -51px;
+    right: 9px;
+    width: 144px;
+    height: 154px;
+  }
+
+  .iconClose {
+    position: absolute;
+    top: -51px;
+    right: 9px;
+    width: 32px;
+    height: 32px;
+    background: url('./images/icon-close.png') no-repeat center;
+    background-size: contain;
+    display: inline-block;
+    z-index: 99;
+  }
+}
+
+
+.popupStatus {
+  overflow-y: initial;
+}
+
+.memberMeal {
+  .titleMeal {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    font-size: 16px;
+    font-weight: 600;
+    color: #131415;
+    line-height: 22px;
+    padding: 26px 24px;
+
+    .iconArrowLine {
+      display: inline-block;
+      width: 14px;
+      height: 14px;
+      background: url('./images/icon-arrow-line.png') no-repeat center;
+      background-size: contain;
+    }
+  }
+}
+
+.btnGroup {
+  // position: fixed;
+  // bottom: 0;
+  // left: 0;
+  // right: 0;
+  // z-index: 100;
+  // background-color: #fff;
+  display: flex;
+  align-items: center;
+  padding: 0 16px 12px;
+  justify-content: space-between;
+
+  .btn {
+    padding: 0 22px;
+    height: 44px;
+    color: #fff !important;
+    background: linear-gradient(270deg, #FF204B 0%, #FE5B71 100%);
+    border-radius: 39px;
+    font-size: 18px;
+    font-weight: bold;
+    border: none;
+
+    .unit {
+      font-size: 14px;
+    }
+  }
+
+  .priceSection {
+    display: flex;
+    align-items: center;
+    font-size: 16px;
+    color: #1a1a1a;
+
+    .price {
+      font-size: 18px;
+      font-weight: bold;
+      color: #ff3535;
+
+      .priceUnit {
+        font-size: 14px;
+      }
+    }
+  }
+}

+ 416 - 0
src/tenant/music/train-tool/index.tsx

@@ -0,0 +1,416 @@
+import { defineComponent, onMounted, reactive, ref } from 'vue'
+import { Image, Tabs, Tab, List, Button, Popup, Dialog } from 'vant'
+import styles from './index.module.less'
+import TheSticky from '@/components/the-sticky'
+import ColHeader from '@/components/col-header'
+import { useWindowScroll, useEventListener } from '@vueuse/core'
+import request from '@/helpers/request'
+import iconMenu from './images/icon-menu.png'
+import iconRightTop from './images/icon-right-top.png'
+import { state as baseState } from '@/state'
+import Song from '../component/song'
+import { useRouter } from 'vue-router'
+import ColResult from '@/components/col-result'
+import { moneyFormat } from '@/helpers/utils'
+import { orderStatus } from '@/views/order-detail/orderStatus'
+
+export default defineComponent({
+  name: 'train-tool',
+  setup() {
+    const router = useRouter()
+    const background = ref<string>('rgba(55, 205, 177, 0)')
+    const color = ref<string>('#fff')
+    const state = reactive({
+      details: {} as any,
+      activeTab: 'SUBJECT',
+      loading: false,
+      finished: false,
+      isError: false,
+      list: [] as any,
+      popupStatus: false,
+      selectMember: {} as any, // 购买的月份
+      buyList: [
+        {
+          purchaseCycle: 6,
+          salePrice: 0,
+          costPrice: 0,
+          status: true
+        },
+        {
+          purchaseCycle: 12,
+          salePrice: 0,
+          costPrice: 0,
+          status: false
+        },
+        {
+          purchaseCycle: 18,
+          salePrice: 0,
+          costPrice: 0,
+          status: false
+        },
+        {
+          purchaseCycle: 24,
+          salePrice: 0,
+          costPrice: 0,
+          status: false
+        },
+        {
+          purchaseCycle: 30,
+          salePrice: 0,
+          costPrice: 0,
+          status: false
+        },
+        {
+          purchaseCycle: 36,
+          salePrice: 0,
+          costPrice: 0,
+          status: false
+        }
+      ]
+    })
+    const params = reactive({
+      page: 1,
+      rows: 20
+    })
+    const apiSuffix = ref(
+      baseState.platformType === 'STUDENT' ? '/api-student' : '/api-teacher'
+    )
+
+    const getDetails = async () => {
+      try {
+        const { data } = await request.post(
+          apiSuffix.value + '/userTenantAlbumRecord/detail'
+        )
+        state.details = data || {}
+
+        state.buyList.forEach((item: any, index: number) => {
+          item.salePrice = (index + 1) * data.salePrice
+          item.costPrice = (index + 1) * data.costPrice
+        })
+
+        state.selectMember = {
+          ...state.buyList[0]
+        }
+      } catch {
+        //
+      }
+    }
+
+    const FetchList = async () => {
+      if (state.loading) {
+        return
+      }
+      state.loading = true
+      state.isError = false
+      const tempParams = {
+        albumId: state.details.id || null,
+        subjectType: state.activeTab,
+        ...params
+      }
+
+      try {
+        const { data } = await request.post(
+          `${apiSuffix.value}/tenantAlbumMusic/page`,
+          {
+            data: tempParams
+          }
+        )
+        if (state.list.length > 0 && data.pageNo === 1) {
+          return
+        }
+        state.list = state.list.concat(data.rows || [])
+        params.page = data.pageNo + 1
+        // showContact.value = state.list.length > 0
+        state.loading = false
+        state.finished = data.pageNo >= data.totalPage
+        params.page = data.pageNo + 1
+      } catch (error) {
+        state.isError = true
+      }
+      state.loading = false
+    }
+
+    onMounted(async () => {
+      useEventListener(document, 'scroll', evt => {
+        const { y } = useWindowScroll()
+        if (y.value > 20) {
+          background.value = `rgba(255, 255, 255)`
+          color.value = 'black'
+          postMessage({
+            api: 'backIconChange',
+            content: { iconStyle: 'black' }
+          })
+        } else {
+          background.value = 'transparent'
+          color.value = '#fff'
+          postMessage({
+            api: 'backIconChange',
+            content: { iconStyle: 'white' }
+          })
+        }
+      })
+
+      await getDetails()
+      await FetchList()
+    })
+
+    const onSubmit = async () => {
+      const album = state.selectMember
+      const details = state.details
+      orderStatus.orderObject.orderType = 'TENANT_ALBUM'
+      orderStatus.orderObject.orderName = details.name
+      orderStatus.orderObject.orderDesc = details.name
+      orderStatus.orderObject.actualPrice = album.salePrice
+      // orderStatus.orderObject.recomUserId = route.query.recomUserId || 0
+      // orderStatus.orderObject.activityId = route.query.activityId || 0
+      orderStatus.orderObject.orderNo = ''
+      orderStatus.orderObject.orderList = [
+        {
+          orderType: 'TENANT_ALBUM',
+          goodsName: details.name,
+          actualPrice: album.salePrice,
+          // recomUserId: route.query.recomUserId || 0,
+          price: album.salePrice,
+          ...details,
+          ...album
+        }
+      ]
+
+      // const res = await request.post('/api-student/userOrder/getPendingOrder', {
+      //   data: {
+      //     goodType: 'TENANT_ALBUM',
+      //     bizId: details.id
+      //   }
+      // })
+
+      // const result = res.data
+      if (false) {
+        state.popupStatus = false
+        Dialog.confirm({
+          title: '提示',
+          message: '您有一个未支付的订单,是否继续支付?',
+          confirmButtonColor: '#269a93',
+          cancelButtonText: '取消订单',
+          confirmButtonText: '继续支付'
+        })
+          .then(async () => {
+            orderStatus.orderObject.orderNo = result.orderNo
+            orderStatus.orderObject.actualPrice = result.actualPrice
+            orderStatus.orderObject.discountPrice = result.discountPrice
+            routerTo()
+          })
+          .catch(() => {
+            Dialog.close()
+            // 只用取消订单,不用做其它处理
+            cancelPayment(result.orderNo)
+          })
+      } else {
+        routerTo()
+      }
+    }
+    const routerTo = () => {
+      const album = state.details
+      router.push({
+        path: '/orderDetail',
+        query: {
+          orderType: 'ALBUM',
+          album: album.id
+        }
+      })
+    }
+
+    const cancelPayment = async (orderNo: string) => {
+      try {
+        await request.post('/api-student/userOrder/orderCancel/v2', {
+          data: {
+            orderNo
+          }
+        })
+      } catch {
+        //
+      }
+    }
+
+    return () => (
+      <div class={styles.trainTool}>
+        <TheSticky position="top">
+          <ColHeader
+            background={background.value}
+            border={false}
+            isFixed={false}
+            color={color.value}
+            backIconColor="white"
+          />
+        </TheSticky>
+        <img class={styles.bgImg} src={state.details?.coverImg} />
+        <div class={styles.musicContent}></div>
+        <div class={styles.bg}>
+          <div class={styles.alumWrap}>
+            <div class={styles.img}>
+              <Image
+                class={styles.image}
+                width="100%"
+                height="100%"
+                fit="cover"
+                src={state.details?.coverImg}
+              />
+              <span class={styles.numContent}>
+                <img src={iconMenu} class={styles.iconMenu} />共
+                {state.details?.musicNum}首
+              </span>
+
+              <div class={styles.iconPian}>
+                <Image
+                  class={styles.image}
+                  width="100%"
+                  height="100%"
+                  fit="cover"
+                  src={state.details?.coverImg}
+                />
+              </div>
+            </div>
+            <div class={styles.alumDes}>
+              <div class={[styles.alumTitle, 'van-ellipsis']}>
+                {state.details?.name}
+              </div>
+              <div
+                class={[styles.des, 'van-multi-ellipsis--l2']}
+                style={{
+                  height: '32px',
+                  lineHeight: '16px'
+                }}
+              >
+                {state.details?.describe}
+              </div>
+            </div>
+          </div>
+        </div>
+
+        <div class={styles.musicList}>
+          <Tabs
+            color="var(--van-primary)"
+            background="transparent"
+            lineWidth={20}
+            shrink
+            v-model:active={state.activeTab}
+            onChange={val => {
+              state.activeTab = val
+
+              params.page = 1
+              state.list = []
+              FetchList()
+            }}
+          >
+            <Tab title="声部练习" name="SUBJECT"></Tab>
+            <Tab title="合奏练习" name="ENSEMBLE"></Tab>
+            <Tab title="独奏曲目" name="MUSIC"></Tab>
+          </Tabs>
+
+          <div class={styles.alumnList}>
+            <List
+              loading={state.loading}
+              finished={state.finished}
+              finished-text={' '}
+              onLoad={FetchList}
+              error={state.isError}
+            >
+              {state.list && state.list.length ? (
+                <Song
+                  showNumber
+                  list={state.list}
+                  onDetail={(item: any) => {
+                    router.push({
+                      path: '/music-detail',
+                      query: {
+                        id: item.id
+                        // albumId: route.params.id
+                      }
+                    })
+                  }}
+                />
+              ) : (
+                !state.loading && (
+                  <ColResult
+                    tips="暂无曲目"
+                    classImgSize="SMALL"
+                    btnStatus={false}
+                  />
+                )
+              )}
+            </List>
+          </div>
+        </div>
+        {!state.loading && !state.details.ifBuy && (
+          <TheSticky position="bottom">
+            <div class={styles.btnGroup}>
+              <Button
+                round
+                block
+                color="#FE2451"
+                onClick={() => (state.popupStatus = true)}
+              >
+                购买教程
+              </Button>
+            </div>
+          </TheSticky>
+        )}
+        <Popup
+          v-model:show={state.popupStatus}
+          position="bottom"
+          round
+          zIndex={9999}
+          safe-area-inset-bottom
+          closeable={false}
+          class={styles.popupStatus}
+          onClose={() => (state.popupStatus = false)}
+          // onClosed={() => (this.openStatus = false)}
+        >
+          <div class={styles.bottom_function}>
+            <i
+              class={styles.iconClose}
+              onClick={() => (state.popupStatus = false)}
+            ></i>
+            <img src={iconRightTop} class={styles.iconRightTop} />
+            <div class={styles.memberMeal}>
+              <div class={styles.titleMeal}>
+                <span>请选择教程购买周期</span>
+              </div>
+
+              <div class={styles['system-list']}>
+                {state.buyList.map((item: any) => (
+                  <div
+                    class={[
+                      styles['system-item'],
+                      item.status && styles.active
+                    ]}
+                    onClick={() => {
+                      state.buyList.forEach((item: any) => {
+                        item.status = false
+                      })
+                      item.status = true
+                      state.selectMember = item
+                    }}
+                  >
+                    <p class={styles.title}>{item.purchaseCycle}个月</p>
+                    <p class={styles.price}>
+                      <span>¥</span>
+                      {moneyFormat(item.salePrice, '0,0[.]00')}
+                    </p>
+                    <del class={styles.originalPrice}>
+                      ¥{moneyFormat(item.costPrice, '0,0[.]00')}
+                    </del>
+                  </div>
+                ))}
+              </div>
+            </div>
+            <div class={styles.btnGroup}>
+              <Button round block class={styles.btn} onClick={onSubmit}>
+                点击购买
+              </Button>
+            </div>
+          </div>
+        </Popup>
+      </div>
+    )
+  }
+})

+ 18 - 0
src/tenant/ranking-list/index.module.less

@@ -0,0 +1,18 @@
+.bgImg {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 214px;
+  // object-fit: cover;
+  z-index: -1;
+}
+
+.sticky {
+  :global {
+    .van-sticky {
+      background: url('../images/bg-image.png') no-repeat top center;
+      background-size: 100% 214px;
+    }
+  }
+}

+ 26 - 0
src/tenant/ranking-list/index.tsx

@@ -0,0 +1,26 @@
+import TheSticky from '@/components/the-sticky'
+import { defineComponent } from 'vue'
+import styles from './index.module.less'
+import ColHeader from '@/components/col-header'
+import bgImg from '../images/bg-image.png'
+
+export default defineComponent({
+  name: 'ranking-list',
+  setup() {
+    return () => (
+      <div class={styles.activationCode}>
+        <div class={styles.sticky}>
+          <TheSticky position="top">
+            <ColHeader
+              background="transparent"
+              isFixed={false}
+              border={false}
+              color="#131415"
+            />
+          </TheSticky>
+          <img class={styles.bgImg} src={bgImg} />
+        </div>
+      </div>
+    )
+  }
+})

+ 5 - 3
src/views/adapay/payment/index.tsx

@@ -22,7 +22,7 @@ export default defineComponent({
     }
   },
   emits: ['backOut', 'close', 'confirm', 'update:modelValue'],
-  setup(props, { slots, attrs, emit }) {
+  setup(props, { emit }) {
     const router = useRouter()
     const state = reactive({
       payType: 'wx',
@@ -35,10 +35,12 @@ export default defineComponent({
         confirmButtonText: '继续付款',
         cancelButtonText: '放弃'
       })
-        .then(() => {})
+        .then(() => {
+          //
+        })
         .catch(async () => {
           // this.onCancel()
-          // useEventTracking('取消支付')
+          useEventTracking('取消支付')
           await onCancel()
           emit('close')
           useEventTracking('取消支付')

+ 122 - 119
src/views/article-center/help-center.tsx

@@ -1,119 +1,122 @@
-import { state } from '@/state'
-import request from '@/helpers/request'
-import { Cell, List, Sticky } from 'vant'
-import { defineComponent } from 'vue'
-import ColSearch from '@/components/col-search'
-import ColResult from '@/components/col-result'
-import { useEventTracking } from '@/helpers/hooks'
-
-export default defineComponent({
-  name: 'help-center',
-  data() {
-    const query = this.$route.query
-    const title = query.catalogType == '2' ? '公告列表' : '帮助中心'
-    document.title = title
-
-    // 处理兼容性问题
-    if (query.mode === 'accompany') {
-      query.platformType = 'ANALYSIS'
-    }
-    return {
-      list: [],
-      dataShow: true, // 判断是否有数据
-      dataLoading: false,
-      loading: false,
-      finished: false,
-      // 1:帮助中心,2:公告管理
-      params: {
-        catalogIds: query.catalogType || 1,
-        title: '',
-        status: 1,
-        // STUDENT:学生 TEACHER:老师 ANALYSIS:智能陪练
-        catalogType: query.platformType || state.platformType,
-        page: 1,
-        rows: 20
-      }
-    }
-  },
-  mounted(){
-    useEventTracking('帮助中心')
-  },
-  methods: {
-    async getList() {
-      try {
-        if (this.dataLoading) {
-          return
-        }
-        this.dataLoading = true
-        let params = this.params
-        const res = await request.post('/api-cms/helpCenterContent/list', {
-          data: {
-            ...params
-          }
-        })
-        this.dataLoading = false
-        this.loading = false
-        const result = res.data || {}
-        // 处理重复请求数据
-        if (this.list.length > 0 && result.pageNo === 1) {
-          return
-        }
-        this.list = this.list.concat(result.rows || [])
-        this.finished = result.pageNo >= result.totalPage
-        this.params.page = result.pageNo + 1
-        this.dataShow = this.list.length > 0
-      } catch {
-        this.dataShow = false
-        this.finished = true
-      }
-    },
-    onSearch(val: string) {
-      this.params.title = val
-      this.params.page = 1
-      this.list = []
-      this.dataShow = true // 判断是否有数据
-      this.loading = false
-      this.finished = false
-      this.getList()
-    },
-    onDetail(item: any) {
-      this.$router.push({
-        path: 'helpCenterDetail',
-        query: {
-          id: item.id,
-          catalogType: this.params.catalogType
-        }
-      })
-    }
-  },
-  render() {
-    return (
-      <div>
-        <Sticky offsetTop={0} position="top" class={'mb12'}>
-          <ColSearch onSearch={this.onSearch} />
-        </Sticky>
-        {this.dataShow ? (
-          <List
-            v-model:loading={this.loading}
-            finished={this.finished}
-            finishedText="没有更多了"
-            onLoad={this.getList}
-          >
-            {this.list.map((item: any) => (
-              <Cell
-                title={item.title}
-                titleClass={'van-ellipsis'}
-                isLink
-                onClick={() => {
-                  this.onDetail(item)
-                }}
-              />
-            ))}
-          </List>
-        ) : (
-          <ColResult btnStatus={false} classImgSize="SMALL" tips="暂无内容" />
-        )}
-      </div>
-    )
-  }
-})
+import { state } from '@/state'
+import request from '@/helpers/request'
+import { Cell, List, Sticky } from 'vant'
+import { defineComponent } from 'vue'
+import ColSearch from '@/components/col-search'
+import ColResult from '@/components/col-result'
+import { useEventTracking } from '@/helpers/hooks'
+
+export default defineComponent({
+  name: 'help-center',
+  data() {
+    const query = this.$route.query
+    const title = query.catalogType == '2' ? '公告列表' : '帮助中心'
+    document.title = title
+
+    // 处理兼容性问题
+    if (query.mode === 'accompany') {
+      query.platformType = 'ANALYSIS'
+    }
+    return {
+      list: [],
+      dataShow: true, // 判断是否有数据
+      dataLoading: false,
+      loading: false,
+      finished: false,
+      // 1:帮助中心,2:公告管理
+      params: {
+        catalogIds: query.catalogType || 1,
+        title: '',
+        status: 1,
+        // STUDENT:学生 TEACHER:老师 ANALYSIS:智能陪练
+        catalogType: query.platformType || state.platformType,
+        page: 1,
+        rows: 20
+      }
+    }
+  },
+  mounted() {
+    useEventTracking('帮助中心')
+  },
+  methods: {
+    async getList() {
+      try {
+        if (this.dataLoading) {
+          return
+        }
+        this.dataLoading = true
+        const params = this.params
+        const res = await request.post('/api-cms/helpCenterContent/list', {
+          data: {
+            ...params
+          }
+        })
+        this.dataLoading = false
+        this.loading = false
+        const result = res.data || {}
+        // 处理重复请求数据
+        if (this.list.length > 0 && result.pageNo === 1) {
+          return
+        }
+        this.list = this.list.concat(result.rows || [])
+        this.finished = result.pageNo >= result.totalPage
+        this.params.page = result.pageNo + 1
+        this.dataShow = this.list.length > 0
+      } catch {
+        this.dataShow = false
+        this.finished = true
+      }
+    },
+    onSearch(val: string) {
+      this.params.title = val
+      this.params.page = 1
+      this.list = []
+      this.dataShow = true // 判断是否有数据
+      this.loading = false
+      this.finished = false
+      this.getList()
+    },
+    onDetail(item: any) {
+      this.$router.push({
+        path: 'helpCenterDetail',
+        query: {
+          id: item.id,
+          catalogType: this.params.catalogType
+        }
+      })
+    }
+  },
+  render() {
+    return (
+      <div>
+        <Sticky offsetTop={0} position="top" class={'mb12'}>
+          <ColSearch
+            type={state.projectType === 'tenant' ? 'tenant' : 'person'}
+            onSearch={this.onSearch}
+          />
+        </Sticky>
+        {this.dataShow ? (
+          <List
+            v-model:loading={this.loading}
+            finished={this.finished}
+            finishedText="没有更多了"
+            onLoad={this.getList}
+          >
+            {this.list.map((item: any) => (
+              <Cell
+                title={item.title}
+                titleClass={'van-ellipsis'}
+                isLink
+                onClick={() => {
+                  this.onDetail(item)
+                }}
+              />
+            ))}
+          </List>
+        ) : (
+          <ColResult btnStatus={false} classImgSize="SMALL" tips="暂无内容" />
+        )}
+      </div>
+    )
+  }
+})

+ 21 - 8
src/views/order-detail/index.tsx

@@ -33,6 +33,7 @@ import UseCoupon from './use-coupons'
 import OrderAlbum from './order-album'
 import { useRect } from '@vant/use'
 import QrcodePayment from './qrcode-payment'
+import OrderTennatAlbum from './order-tennat-album'
 
 export default defineComponent({
   name: 'order-detail',
@@ -163,7 +164,6 @@ export default defineComponent({
             }
           }
         )
-        console.log(data, 'data')
         this.paymentVersion = data.paymentVersion || 'V1'
         this.paymentVendor = data.paymentVendor
       } catch {
@@ -200,8 +200,7 @@ export default defineComponent({
       try {
         const orderObject = orderStatus.orderObject
 
-        console.log(this.paymentVendor, '12')
-        if (this.paymentVersion === 'V2') {
+        if (this.paymentVersion === 'V1') {
           const url =
             state.platformType === 'TEACHER'
               ? '/api-teacher/userOrder/executeOrder'
@@ -239,7 +238,7 @@ export default defineComponent({
               : '/api-student/userOrder/executeOrder/v2'
           const orders: any = []
           this.orderList.forEach((item: any) => {
-            const params = {
+            const params: any = {
               goodType: item.orderType,
               goodName: item.goodsName,
               goodNum: 1,
@@ -259,6 +258,17 @@ export default defineComponent({
                 actualPrice: item.actualPrice || 0,
                 clientType: state.platformType
               }
+            } else if (item.orderType === 'TENANT_ALBUM') {
+              params.bizContent = {
+                tenantAlbumId: item.id,
+                actualPrice: item.actualPrice || 0,
+                buyNumber: 1,
+                buyMultiple: item.purchaseCycle / 6,
+                clientType: state.platformType
+              }
+              params.bizId = item.id
+              params.buyNumber = 1
+              params.buyMultiple = item.purchaseCycle / 6
             }
             orders.push(params)
           })
@@ -417,6 +427,8 @@ export default defineComponent({
                 return <OrderActive item={item} />
               } else if (item.orderType === 'ALBUM') {
                 return <OrderAlbum item={item} />
+              } else if (item.orderType === 'TENANT_ALBUM') {
+                return <OrderTennatAlbum item={item} />
               }
             })}
 
@@ -486,7 +498,7 @@ export default defineComponent({
           style={{ minHeight: '30%' }}
         >
           {/* 判断类型使用什么去支付 */}
-          {this.paymentVersion === 'V2' ? (
+          {this.paymentVersion === 'V1' ? (
             <Payment
               v-model={this.paymentStatus}
               orderInfo={orderStatus.orderObject}
@@ -494,9 +506,10 @@ export default defineComponent({
             />
           ) : (
             <UrlPayment
-              // v-model={this.paymentStatus}
-              paymentConfig={orderStatus.orderObject}
-              // onBackOut={this.onBackOut}
+              paymentConfig={{
+                ...orderStatus.orderObject,
+                orderNo: this.orderNo
+              }}
               onClose={() => (this.paymentStatus = false)}
               onBackOut={this.onBackOut}
               onConfirm={(val: any) => this.onConfirm(val)}

+ 82 - 0
src/views/order-detail/order-tennat-album/index.module.less

@@ -0,0 +1,82 @@
+.album {
+  margin-bottom: 12px;
+  padding: 10px;
+  background-color: var(--music-list-item-background-color);
+  border-radius: 10px;
+  display: flex;
+  position: relative;
+
+  .albumType {
+    position: absolute;
+    left: 10px;
+    top: 10px;
+    background: #FE2451;
+    border-radius: 10px 0px 10px 0px;
+    font-size: 12px;
+    padding: 0 6px;
+    line-height: 20px;
+    color: #ffffff;
+  }
+
+  .img {
+    width: 94px;
+    height: 94px;
+    margin-right: 18px;
+    position: relative;
+
+    >img,
+    >div {
+      position: absolute;
+      border-radius: 10px;
+      overflow: hidden;
+    }
+  }
+
+  .content {
+    flex: 1;
+
+    >h4 {
+      font-size: 14px;
+      color: #131415;
+      line-height: 24px;
+    }
+
+    >p {
+      margin: 4px 0 6px;
+      font-size: 12px;
+      color: #777777;
+      line-height: 18px;
+    }
+
+    .musicNum {
+      font-size: 12px;
+      color: #FE2451;
+      border-radius: 4px;
+      border: 1px solid #FE2451;
+      padding: 1px 6px;
+    }
+  }
+}
+
+.footer {
+  margin-top: 11px;
+  display: flex;
+
+  >div {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    font-size: 12px;
+    color: var(--music-list-item-mate-color);
+    margin-right: 18px;
+
+    .icon {
+      margin-right: 5px;
+    }
+
+    span {
+      display: block;
+      margin-top: 1px;
+    }
+  }
+}

+ 32 - 0
src/views/order-detail/order-tennat-album/index.tsx

@@ -0,0 +1,32 @@
+import { defineComponent } from 'vue'
+import styles from './index.module.less'
+import { Image } from 'vant'
+import { useRouter } from 'vue-router'
+
+export default defineComponent({
+  name: 'OrderMusic',
+  props: {
+    item: {
+      type: Object,
+      default: {}
+    }
+  },
+  render() {
+    const item = this.item
+    console.log(item)
+    return (
+      <div class={styles.album}>
+        <Image class={styles.img} src={item.coverImg} />
+
+        <span class={styles.albumType}>{item.purchaseCycle}个月</span>
+
+        <div class={styles.content}>
+          <h4 class="van-ellipsis">{item.name}</h4>
+          <p class="van-multi-ellipsis--l2">{item.describe}</p>
+
+          <span class={styles.musicNum}>共{item.musicNum}首</span>
+        </div>
+      </div>
+    )
+  }
+})

+ 7 - 0
src/views/order-detail/orderStatus.ts

@@ -13,6 +13,7 @@ type orderType =
   | 'PIANO_ROOM'
   | 'ACTI_REGIST'
   | 'ALBUM'
+  | 'TENANT_ALBUM'
   | ''
 
 const original = () => {
@@ -126,6 +127,12 @@ export const orderInfos = () => {
       params.bizContent = {
         activityId: item.activityId
       }
+    } else if (item.orderType === 'TENANT_ALBUM') {
+      params.bizContent = {
+        musicSheetId: item.id,
+        actualPrice: item.actualPrice || 0,
+        clientType: state.platformType
+      }
     }
     return params
   })

+ 155 - 148
src/views/order-detail/userAuth/index.tsx

@@ -1,148 +1,155 @@
-import ColField from '@/components/col-field'
-import ColFieldGroup from '@/components/col-field-group'
-import ColHeader from '@/components/col-header'
-import request from '@/helpers/request'
-import { verifyIdCard } from '@/helpers/toolsValidate'
-import { postMessage } from '@/helpers/native-message'
-import { state } from '@/state'
-import { Button, CellGroup, Checkbox, Field, Form, Icon, Toast } from 'vant'
-import { defineComponent } from 'vue'
-import activeButtonIcon from '@common/images/icon_checkbox.png'
-import inactiveButtonIcon from '@common/images/icon_checkbox_default.png'
-import styles from './index.module.less'
-
-export default defineComponent({
-  name: 'UserAuth',
-  props: {
-    onSuccess: {
-      // 实名成功
-      type: Function,
-      default: () => {}
-    },
-    exists: {
-      type: Boolean,
-      default: false
-    },
-    hideHeader: {
-      type: Boolean,
-      default: false
-    }
-  },
-  data() {
-    return {
-      form: {
-        realName: '',
-        idCardNo: ''
-      },
-      checked: false
-    }
-  },
-  mounted() {
-    // exists
-    this.checked = this.checked || this.exists
-    // 初始化数据
-    const users = state.user.data
-    this.form.realName = users?.realName
-    // this.form.idCardNo = users?.idCardNo
-  },
-  methods: {
-    async onSubmit() {
-      try {
-        if (!this.checked) {
-          Toast('请先阅读并同意《用户注册协议》')
-          return
-        }
-        const url =
-          state.platformType === 'STUDENT'
-            ? '/api-student/student/realNameAuth'
-            : '/api-teacher/teacher/realNameAuth'
-        await request.post(url, {
-          data: {
-            ...this.form,
-            contract: true,
-            save: true
-          }
-        })
-        Toast('实名成功')
-        state.user.data.realName = this.form.realName
-        state.user.data.idCardNo = this.form.idCardNo
-        setTimeout(() => {
-          this.onSuccess()
-        }, 500)
-      } catch {}
-    },
-    getContractDetail() {
-      // 查看协议
-      const client = state.platformType === 'STUDENT' ? 'student' : 'teacher'
-      postMessage({
-        api: 'openWebView',
-        content: {
-          url: `${location.origin}/${client}/#/previewProtocol`,
-          orientation: 1,
-          isHideTitle: false
-        }
-      })
-    }
-  },
-  render() {
-    return (
-      <Form class={styles.userAuth} onSubmit={this.onSubmit}>
-        {!this.hideHeader && <ColHeader title="实名认证" />}
-
-        <ColFieldGroup style={{ marginTop: '15px' }}>
-          <ColField title="姓名" required>
-            <Field
-              name="lessonName"
-              maxlength={20}
-              v-model={this.form.realName}
-              placeholder="请输入真实姓名"
-              rules={[{ required: true, message: '请输入真实姓名' }]}
-            />
-          </ColField>
-          <ColField title="证件号码" required>
-            <Field
-              name="lessonSubjectName"
-              v-model={this.form.idCardNo}
-              rules={[
-                { required: true, message: '请输入身份证号' },
-                {
-                  pattern:
-                    /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/,
-                  message: '请输入正确的身份证号'
-                }
-              ]}
-              placeholder="请输入身份证号"
-            />
-          </ColField>
-        </ColFieldGroup>
-        <div class={styles.colProtocol}>
-          {!this.exists && (
-            <Checkbox
-              v-model={this.checked}
-              v-slots={{
-                icon: (props: any) => (
-                  <Icon
-                    class={styles.boxStyle}
-                    name={props.checked ? activeButtonIcon : inactiveButtonIcon}
-                    size="15"
-                  />
-                )
-              }}
-            >
-              我已阅读并同意
-            </Checkbox>
-          )}
-          {this.exists && <>查看</>}
-          <span onClick={this.getContractDetail} class={styles.protocolText}>
-            《用户注册协议》
-          </span>
-        </div>
-        <div class={['btnGroup']}>
-          <Button block round type="primary" native-type="submit">
-            确定
-          </Button>
-        </div>
-      </Form>
-    )
-  }
-})
+import ColField from '@/components/col-field'
+import ColFieldGroup from '@/components/col-field-group'
+import ColHeader from '@/components/col-header'
+import request from '@/helpers/request'
+import { verifyIdCard } from '@/helpers/toolsValidate'
+import { postMessage } from '@/helpers/native-message'
+import { state } from '@/state'
+import { Button, CellGroup, Checkbox, Field, Form, Icon, Toast } from 'vant'
+import { defineComponent } from 'vue'
+import activeButtonIcon from '@common/images/icon_checkbox.png'
+import inactiveButtonIcon from '@common/images/icon_checkbox_default.png'
+import activeButtonIconTenant from '@common/images/icon_checkbox-tenant.png'
+import styles from './index.module.less'
+
+export default defineComponent({
+  name: 'UserAuth',
+  props: {
+    onSuccess: {
+      // 实名成功
+      type: Function,
+      default: () => {}
+    },
+    exists: {
+      type: Boolean,
+      default: false
+    },
+    hideHeader: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      form: {
+        realName: '',
+        idCardNo: ''
+      },
+      checked: false
+    }
+  },
+  mounted() {
+    // exists
+    this.checked = this.checked || this.exists
+    // 初始化数据
+    const users = state.user.data
+    this.form.realName = users?.realName
+    // this.form.idCardNo = users?.idCardNo
+  },
+  methods: {
+    async onSubmit() {
+      try {
+        if (!this.checked) {
+          Toast('请先阅读并同意《用户注册协议》')
+          return
+        }
+        const url =
+          state.platformType === 'STUDENT'
+            ? '/api-student/student/realNameAuth'
+            : '/api-teacher/teacher/realNameAuth'
+        await request.post(url, {
+          data: {
+            ...this.form,
+            contract: true,
+            save: true
+          }
+        })
+        Toast('实名成功')
+        state.user.data.realName = this.form.realName
+        state.user.data.idCardNo = this.form.idCardNo
+        setTimeout(() => {
+          this.onSuccess()
+        }, 500)
+      } catch {}
+    },
+    getContractDetail() {
+      // 查看协议
+      const client = state.platformType === 'STUDENT' ? 'student' : 'teacher'
+      postMessage({
+        api: 'openWebView',
+        content: {
+          url: `${location.origin}/${client}/#/previewProtocol`,
+          orientation: 1,
+          isHideTitle: false
+        }
+      })
+    }
+  },
+  render() {
+    return (
+      <Form class={styles.userAuth} onSubmit={this.onSubmit}>
+        {!this.hideHeader && <ColHeader title="实名认证" />}
+
+        <ColFieldGroup style={{ marginTop: '15px' }}>
+          <ColField title="姓名" required>
+            <Field
+              name="lessonName"
+              maxlength={20}
+              v-model={this.form.realName}
+              placeholder="请输入真实姓名"
+              rules={[{ required: true, message: '请输入真实姓名' }]}
+            />
+          </ColField>
+          <ColField title="证件号码" required>
+            <Field
+              name="lessonSubjectName"
+              v-model={this.form.idCardNo}
+              rules={[
+                { required: true, message: '请输入身份证号' },
+                {
+                  pattern:
+                    /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/,
+                  message: '请输入正确的身份证号'
+                }
+              ]}
+              placeholder="请输入身份证号"
+            />
+          </ColField>
+        </ColFieldGroup>
+        <div class={styles.colProtocol}>
+          {!this.exists && (
+            <Checkbox
+              v-model={this.checked}
+              v-slots={{
+                icon: (props: any) => (
+                  <Icon
+                    class={styles.boxStyle}
+                    name={
+                      props.checked
+                        ? state.projectType === 'tenant'
+                          ? activeButtonIconTenant
+                          : activeButtonIcon
+                        : inactiveButtonIcon
+                    }
+                    size="15"
+                  />
+                )
+              }}
+            >
+              我已阅读并同意
+            </Checkbox>
+          )}
+          {this.exists && <>查看</>}
+          <span onClick={this.getContractDetail} class={styles.protocolText}>
+            《用户注册协议》
+          </span>
+        </div>
+        <div class={['btnGroup']}>
+          <Button block round type="primary" native-type="submit">
+            确定
+          </Button>
+        </div>
+      </Form>
+    )
+  }
+})