Jelajahi Sumber

添加统计样式

lex-xin 3 bulan lalu
induk
melakukan
f48f6e9e91

+ 21 - 2
src/business-components/calendar/index.tsx

@@ -104,6 +104,18 @@ export default defineComponent({
     this.maxDate = dayjs().add(1, 'day').endOf('month').toDate()
     this.minDate = dayjs().add(1, 'day').toDate()
 
+    // console.log(this.list, "this.list")
+    // for(const key in this.list) {
+    //   console.log(key, this.list[key])
+    //   let dataList = [] as any
+    //   if (this.list[key] && Array.isArray(this.list[key].courseTime)) {
+    //     dataList = [...this.list[key].courseTime].filter(n =>
+    //       dayjs().isBefore(dayjs(n.startTime))
+    //     )
+    //   }
+    //   this.list[key].courseTime = dataList
+    // }
+
     // 初始化日历
     // console.log(this.list, 323, this.maxDays)
   },
@@ -111,14 +123,21 @@ export default defineComponent({
     formatter(date: any) {
       const dateStr = dayjs(date.date).format('YYYY-MM-DD')
       const dateObj = this.list[dateStr]
+      // 格式化选择的时间
+      let courseTime = [] as any
+      if (dateObj && Array.isArray(dateObj.courseTime)) {
+        courseTime = [...dateObj.courseTime].filter(n =>
+          dayjs().isBefore(dayjs(n.startTime))
+        )
+      }
       date.type = ''
       // 判断是否有课程 并且 时间在当前时间之后
       if (dateObj && dayjs().subtract(1, 'day').isBefore(dayjs(date.date))) {
         // fullCourse当天是否排满 0: 未,1:满 , courseTime 当天没有课程
         if (
           dateObj.fullCourse ||
-          !dateObj?.courseTime ||
-          dateObj?.courseTime?.length <= 0
+          !courseTime ||
+          courseTime?.length <= 0
         ) {
           date.bottomInfo = '满'
           date.className = 'full'

+ 8 - 0
src/router/routes-teacher.ts

@@ -411,6 +411,14 @@ export default [
         meta: {
           title: '数据详情'
         }
+      },
+      {
+        path: '/practice-detail',
+        name: 'practice-detail',
+        component: () => import('@/teacher/statistics/practice-detail/index'),
+        meta: {
+          title: '练习统计'
+        }
       }
     ]
   },

+ 7 - 5
src/student/teacher-dependent/components/practice.tsx

@@ -159,12 +159,12 @@ export default defineComponent({
     async getList(date?: Date) {
       try {
         const tempDate = date || dayjs().add(1, 'day').toDate()
-        let params = {
+        const params = {
           day: dayjs(tempDate).format('DD'),
           month: dayjs(tempDate).format('MM'),
           year: dayjs(tempDate).format('YYYY')
         }
-        let res = await request.post(
+        const res = await request.post(
           '/api-student/courseSchedule/createPracticeCourseCalendar',
           {
             data: {
@@ -176,17 +176,19 @@ export default defineComponent({
           }
         )
         const result = res.data || []
-        let tempObj = {}
+        const tempObj = {}
         result.forEach((item: any) => {
           tempObj[item.date] = item
         })
         this.calendarList = tempObj
         this.calendarStatus = result.length > 0
-      } catch {}
+      } catch {
+        // 
+      }
     },
     onSelectDay(obj: any) {
       const result = obj || []
-      let list = [...this.selectCourseList] as any
+      const list = [...this.selectCourseList] as any
 
       result.forEach((item: any) => {
         const isExist = list.some(

+ 96 - 0
src/teacher/statistics/home-statistics-detail/buy-item/index.module.less

@@ -0,0 +1,96 @@
+.cell {
+  padding: 13px 12px;
+
+  .top {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+  }
+  .timer {
+    display: flex;
+    align-items: center;
+    font-size: 13px;
+    color: #666666;
+    line-height: 18px;
+    img {
+      width: 16px;
+      height: 16px;
+      margin-right: 6px;
+    }
+  }
+
+  .userInfo {
+    display: flex;
+    align-items: center;
+    img {
+      width: 20px;
+      height: 20px;
+      border-radius: 20px;
+      margin-left: 4px;
+    }
+    .name {
+      font-size: 13px;
+      color: #333333;
+      line-height: 17px;
+      max-width: 70px;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+    }
+  }
+
+  .content {
+    display: flex;
+    // align-items: center;
+    padding-top: 12px;
+  }
+  .cover {
+    width: 90px;
+    height: 51px;
+    border-radius: 4px;
+    overflow: hidden;
+    flex-shrink: 0;
+    margin-right: 10px;
+  }
+  .cover1 {
+    width: 51px;
+  }
+
+  .info {
+    // flex: 1;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    padding: 3px 0;
+    .iTitle {
+      font-weight: 600;
+      font-size: 14px;
+      color: #333333;
+      line-height: 17px;
+      // width: 100%;
+      max-width: 220px;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+    }
+    .iPrice {
+      font-size: 13px;
+      color: #777777;
+      line-height: 17px;
+      display: flex;
+      align-items: center;
+
+      .price {
+        font-family: DINAlternate, DINAlternate;
+        font-weight: bold;
+        font-size: 18px;
+        color: #ff5a56;
+        line-height: 16px;
+        i {
+          font-style: normal;
+          font-size: 14px;
+        }
+      }
+    }
+  }
+}

+ 58 - 0
src/teacher/statistics/home-statistics-detail/buy-item/index.tsx

@@ -0,0 +1,58 @@
+import { defineComponent } from 'vue'
+import styles from './index.module.less'
+import { Cell, CellGroup } from 'vant'
+import iconTimer from '@/common/images/icon_timer2.png'
+import iconMoney from '../../images/icon-money.png'
+
+export default defineComponent({
+  name: 'teacher-item',
+  props: {
+    list: {
+      type: Array,
+      default: () => []
+    },
+    isSquare: {
+      type: Boolean,
+      default: false
+    }
+  },
+  setup(props) {
+    return () => (
+      <CellGroup border={false}>
+        {props.list.map((item, index) => (
+          <Cell class={styles.cell} center>
+            {{
+              title: () => (
+                <div class={styles.top}>
+                  <div class={styles.timer}>
+                    <img src={iconTimer} />
+                    <span>购买时间:2024-10-30 15:23</span>
+                  </div>
+                  <div class={styles.userInfo}>
+                    <span class={styles.name}>张涵宇张涵宇张涵宇</span>
+                    <img src={iconMoney} />
+                  </div>
+                </div>
+              ),
+              label: () => (
+                <div class={styles.content}>
+                  <img class={[styles.cover, props.isSquare && styles.cover1]} />
+                  <div class={styles.info}>
+                    <div class={styles.iTitle}>著名大号大师严琦带你去走近带你去走近带你去走近音</div>
+                    <div class={styles.iPrice}>
+                      <span>预计收入</span>
+                      <span class={styles.price}>
+                        <i>¥</i>
+                        560.00
+                      </span>
+                    </div>
+                  </div>
+                </div>
+              )
+            }}
+          </Cell>
+        ))}
+      </CellGroup>
+    )
+  }
+})

+ 103 - 0
src/teacher/statistics/home-statistics-detail/echats/index.module.less

@@ -0,0 +1,103 @@
+
+.homeHead {
+  display: flex;
+  justify-content: space-between;
+  padding-bottom: 12px;
+
+  .title {
+    display: flex;
+    align-items: center;
+    font-weight: 600;
+    font-size: 15px;
+    color: #333333;
+    line-height: 20px;
+
+    img {
+      width: 18px;
+      height: 18px;
+      margin-right: 6px;
+    }
+  }
+  
+  .right {
+    display: flex;
+    align-items: center;
+  }
+
+  .showItem {
+    display: flex;
+    align-items: center;
+    font-size: 13px;
+    color: #131415;
+    line-height: 18px;
+
+    img {
+      margin-left: 4px;
+      width: 9px;
+      height: 5px;
+    }
+
+    &.showItemActive {
+      color: #2DC7AA;
+    }
+  }
+}
+
+.eChartSection {
+  background-color: #fff;
+  box-shadow: 0px 2px 10px 0px rgba(229, 229, 229, 0.1);
+  border-radius: 10px;
+  padding: 12px;
+  margin: 0 14px;
+  .eChartTitle {
+    display: flex;
+    justify-content: space-between;
+    background: #F8F8F8;
+    border-radius: 4px;
+    padding: 6px 12px;
+
+    .left {
+      display: flex;
+      align-items: center;
+    }
+
+    .item {
+      display: flex;
+      align-items: center;
+      margin-right: 12px;
+      --color: #2DC7AA;
+
+      &:last-child {
+        margin-right: 0;
+      }
+
+      .line {
+        display: inline-block;
+        width: 10px;
+        height: 3px;
+        background: var(--color);
+        border-radius: 3px;
+
+      }
+
+      .text {
+        font-size: 12px;
+        color: #333333;
+        line-height: 16px;
+        padding: 0 4px 0 6px;
+      }
+
+      .num {
+        font-weight: 600;
+        font-size: 12px;
+        color: var(--color);
+        line-height: 16px;
+      }
+    }
+  }
+
+  .eChart {
+    height: 240px;
+    padding: 0;
+  }
+}

+ 262 - 0
src/teacher/statistics/home-statistics-detail/echats/index.tsx

@@ -0,0 +1,262 @@
+import { defineComponent, nextTick, onMounted, ref } from 'vue'
+import styles from './index.module.less'
+import icon1 from '../../images/icon1.png';
+import iconArrow from '../../images/icon-arrow.png';
+import iconArrow1 from '../../images/icon-arrow1.png'
+import iconArrow11 from '../../images/icon-arrow1-1.png'
+import * as echarts from 'echarts/core'
+import {
+  LineChart
+  // LineSeriesOption
+} from 'echarts/charts'
+// import { PieChart } from 'echarts/charts'
+import {
+  TitleComponent,
+  // 组件类型的定义后缀都为 ComponentOption
+  // TitleComponentOption,
+  TooltipComponent,
+  // TooltipComponentOption,
+  GridComponent,
+  // 数据集组件
+  DatasetComponent,
+  // DatasetComponentOption,
+  // 内置数据转换器组件 (filter, sort)
+  // TransformComponent,
+  LegendComponent,
+  ToolboxComponent,
+  DataZoomComponent
+} from 'echarts/components'
+import { LabelLayout } from 'echarts/features'
+import { CanvasRenderer } from 'echarts/renderers'
+
+// 注册必须的组件
+echarts.use([
+  TitleComponent,
+  TooltipComponent,
+  GridComponent,
+  DatasetComponent,
+  // TransformComponent,
+  LabelLayout,
+  // UniversalTransition,
+  CanvasRenderer,
+  // PieChart,
+  ToolboxComponent,
+  LegendComponent,
+  DataZoomComponent,
+  LineChart
+])
+
+const lineChartOption = (xAxisData: any, seriesData: any) => {
+  return {
+    title: {
+      text: '单位:次',
+      textStyle: {
+        color: '#777777',
+        fontSize: 13,
+        fontWeight: 400
+      }
+    },
+    legend: { show: false },
+    emphasis: { lineStyle: { width: 2 } },
+    xAxis: {
+      boundaryGap: false,
+      data: xAxisData,
+      type: 'category',
+      axisLine: { lineStyle: { color: '#8C8C8C' } },
+      lineStyle: { color: '#F2F2F2' }
+    },
+    color: [
+      '#2DC7AA',
+      '#FF6079'
+      // '#2DC7AA',
+      // '#FF602C',
+      // '#91DD1C',
+      // '#FFA92C',
+      // '#BE7E2E',
+      // '#1C96DD',
+      // '#D22CFF',
+      // '#FF3C3C',
+      // '#1AEE3E',
+      // '#00c9ff'
+    ],
+    series: [
+      {
+        lineStyle: { width: 1 },
+        data: seriesData[0],
+        symbol: 'circle',
+        name: '浏览次数',
+        type: 'line',
+        emphasis: { lineStyle: { width: 1 } }
+      },
+      {
+        lineStyle: { width: 1 },
+        data: seriesData[1],
+        symbol: 'circle',
+        name: '购买次数',
+        type: 'line',
+        areaStyle: {
+          color: {
+            type: 'linear',
+            x: 0,
+            y: 0,
+            x2: 0,
+            y2: 1,
+            colorStops: [
+              {
+                offset: 0,
+                color: 'rgba(255, 96, 121, 0.23)'
+                // 0% 处的颜色
+              },
+              {
+                offset: 1,
+                // 100% 处的颜色
+                color: 'rgba(255, 96, 121, 0)'
+              }
+            ]
+          }
+        },
+        emphasis: { lineStyle: { width: 1 } }
+      }
+    ],
+    grid: {
+      bottom: '3%',
+      containLabel: true,
+      left: '3%',
+      right: '5%',
+      top: '40'
+    },
+    tooltip: {
+      trigger: 'axis',
+      confine: true,
+      formatter: function (params: any) {
+        return params[0].name
+      },
+      backgroundColor: '#FF6079',
+      borderWidth: 0,
+      borderRadius: 24,
+      padding: [1, 4],
+      textStyle: {
+        color: '#FFFFFF',
+        fontSize: 12
+      }
+    },
+    yAxis: {
+      type: 'value',
+      splitLine: {
+        axisLine: { lineStyle: { color: '#8C8C8C' } },
+        lineStyle: { color: ['#f2f2f2'], type: 'dashed' }
+      }
+    },
+    dataZoom: [{ type: 'inside', throttle: 100 }],
+    toolbox: { feature: { saveAsImage: { show: false } } }
+  }
+}
+export default defineComponent({
+  name: 'eChats-model',
+  props: {
+    list: {
+      type: Array,
+      default: () => []
+    }
+  },
+  setup(props, { emit }) {
+    const chartId = 'eChart' + Date.now()
+    const popoverStatus = ref(false)
+    const statisticCounts = ref({
+      browseCount: 0,
+      buyCount: 0
+    })
+    let myChart: echarts.ECharts
+
+    nextTick(() => {
+      myChart = echarts.init(
+        document.getElementById(chartId) as HTMLDivElement
+      )
+    })
+
+    onMounted(() => {
+      nextTick(() => {
+        myChart.clear()
+        lineChartOption &&
+          myChart.setOption(
+            lineChartOption(
+              [
+                '01月',
+                '02月',
+                '03月',
+                '04月',
+                '05月',
+                '06月',
+                '07月',
+                '08月',
+                '09月',
+                '10月',
+                '11月',
+                '12月'
+              ],
+              [
+                ['0', '0', '0', '0', '0', '0', '0', '2', '0', '8', '10', '0'],
+                ['0', '0', '0', '0', '1', '3', '0', '2', '0', '8', '10', '0']
+              ]
+            )
+          )
+        myChart.on('highlight', function (params: any) {
+          const batch = params.batch || []
+          const options: any = myChart.getOption()
+          batch.forEach((item: any) => {
+            const batchIndex = item.dataIndex
+
+            const browseCount = options.series[0].data[batchIndex]
+            const buyCount = options.series[1].data[batchIndex]
+            statisticCounts.value = {
+              browseCount,
+              buyCount
+            }
+          })
+        })
+      })
+    })
+    return () => (
+      <div class={styles.eChartSection}>
+        <div class={styles.homeHead}>
+          <div class={styles.title}>
+            <img src={icon1} />
+            <span>浏览/购买</span>
+          </div>
+
+          <div class={styles.right}>
+            <div
+              class={[
+                styles.showItem,
+                popoverStatus.value && styles.showItemActive
+              ]}
+            >
+              <span>本月</span>
+              <img src={popoverStatus.value ? iconArrow11 : iconArrow1} />
+            </div>
+          </div>
+        </div>
+        <div class={styles.eChartTitle}>
+          <div class={styles.left}>
+            <div class={styles.item} style="--color: #2DC7AA">
+              <span class={styles.line}></span>
+              <span class={styles.text}>浏览次数</span>
+              <span class={styles.num}>
+                {statisticCounts.value.browseCount}次
+              </span>
+            </div>
+            <div class={styles.item} style="--color: #FF6079">
+              <span class={styles.line}></span>
+              <span class={styles.text}>购买次数</span>
+              <span class={styles.num}>{statisticCounts.value.buyCount}次</span>
+            </div>
+          </div>
+        </div>
+
+        <div class={styles.eChart}>
+          <div id={chartId} style="width: 100%; height: 100%;"></div>
+        </div>
+      </div>
+    )
+  }
+})

+ 25 - 144
src/teacher/statistics/home-statistics-detail/index.module.less

@@ -1,155 +1,36 @@
 .homeStatistics {
-  background: #FFFFFF;
-  box-shadow: 0px 2px 10px 0px rgba(229, 229, 229, 0.1);
-  border-radius: 10px;
-  padding: 12px;
-  margin: 0 14px;
+  min-height: 100vh;
+  // background: #F6F7F8;
+  background: linear-gradient(to bottom, #beffe6 0px, #f6f7f8 595px);
+  // background: linear-gradient(90deg, #FE4083 0%, #FEC3D4 100%);
 }
 
-.homeHead {
-  display: flex;
-  justify-content: space-between;
-  padding-bottom: 12px;
-
-  .title {
-    display: flex;
-    align-items: center;
-    font-weight: 600;
-    font-size: 15px;
-    color: #333333;
-    line-height: 20px;
-
-    img {
-      width: 18px;
-      height: 18px;
-      margin-right: 6px;
+.tabs {
+  :global {
+    .van-tabs__nav {
+      background-color: transparent;
+      padding-bottom: 12px;
     }
-  }
-
-  .more {
-    display: flex;
-    align-items: center;
-    font-weight: 400;
-    font-size: 12px;
-    color: rgba(45, 199, 170, 1);
-    line-height: 17px;
-    cursor: pointer;
-    background: rgba(45, 199, 170, 0.1);
-    border-radius: 9px;
-    padding: 0 6px;
-
-    img {
-      width: 5px;
-      height: 8px;
-      margin-left: 5px;
-    }
-  }
-}
-
-.eChartSection {
-  .eChartTitle {
-    display: flex;
-    justify-content: space-between;
-    background: #F8F8F8;
-    border-radius: 4px;
-    padding: 6px 12px;
-
-    .left {
-      display: flex;
-      align-items: center;
+    .van-tab {
+      font-size: 16px;
+      color: #666;
     }
-
-    .item {
-      display: flex;
-      align-items: center;
-      margin-right: 12px;
-      --color: #2DC7AA;
-
-      &:last-child {
-        margin-right: 0;
-      }
-
-      .line {
-        display: inline-block;
-        width: 10px;
-        height: 3px;
-        background: var(--color);
-        border-radius: 3px;
-
-      }
-
-      .text {
-        font-size: 12px;
-        color: #333333;
-        line-height: 16px;
-        padding: 0 4px 0 6px;
-      }
-
-      .num {
-        font-weight: 600;
-        font-size: 12px;
-        color: var(--color);
-        line-height: 16px;
-      }
+    .van-tab--active {
+      font-weight: 600;
+      color: #333333;
     }
-
-    .right {
-      display: flex;
-      align-items: center;
+    .van-tabs__line {
+      width: 16px;
+      height: 4px;
+      background: #2dc7aa;
+      border-radius: 2px;
     }
-
-    .showItem {
-      display: flex;
-      align-items: center;
-      font-size: 13px;
-      color: #131415;
-      line-height: 18px;
-
-      img {
-        margin-left: 4px;
-        width: 9px;
-        height: 5px;
-      }
-
-      &.showItemActive {
-        color: #2DC7AA;
-      }
+    .van-tabs__content {
+      padding-top: 12px;
+      height: calc(100vh - var(--van-tabs-line-height) - var(--header-height, 0));
+      overflow-x: hidden;
+      overflow-y: auto;
     }
   }
-
-  .eChart {
-    height: 240px;
-    padding: 0;
-  }
 }
 
-:global {
-  .select-time {
-    width: 81px;
-    background: #FFFFFF;
-    box-shadow: 0px 0px 18px 0px rgba(0, 0, 0, 0.15);
-    border-radius: 8px;
-    padding: 6px;
-
-    span {
-      display: block;
-      font-size: 13px;
-      color: #323233;
-      line-height: 20px;
-      text-align: center;
-      line-height: 28px;
-      margin-bottom: 6px;
-
-      &:last-child {
-        margin-bottom: 0;
-      }
-    }
-
-    .active {
-      background: rgba(45, 199, 170, 0.1);
-      border-radius: 4px;
-      color: #2DC7AA;
-      font-weight: 500;
-    }
-  }
-}

+ 33 - 278
src/teacher/statistics/home-statistics-detail/index.tsx

@@ -1,287 +1,42 @@
-import { defineComponent, nextTick, onMounted, ref } from "vue";
-import styles from './index.module.less';
-import icon1 from '../images/icon1.png';
-import iconArrow from '../images/icon-arrow.png';
-import iconArrow1 from '../images/icon-arrow1.png';
-import iconArrow11 from '../images/icon-arrow1-1.png';
-import { Popover } from "vant";
-
-import * as echarts from 'echarts/core'
-import {
-  LineChart,
-  // LineSeriesOption
-} from 'echarts/charts'
-// import { PieChart } from 'echarts/charts'
-import {
-  TitleComponent,
-  // 组件类型的定义后缀都为 ComponentOption
-  // TitleComponentOption,
-  TooltipComponent,
-  // TooltipComponentOption,
-  GridComponent,
-  // 数据集组件
-  DatasetComponent,
-  // DatasetComponentOption,
-  // 内置数据转换器组件 (filter, sort)
-  // TransformComponent,
-  LegendComponent,
-  ToolboxComponent,
-  DataZoomComponent
-} from 'echarts/components'
-import { LabelLayout } from 'echarts/features'
-import { CanvasRenderer } from 'echarts/renderers'
-import { format } from "path";
-
-// 注册必须的组件
-echarts.use([
-  TitleComponent,
-  TooltipComponent,
-  GridComponent,
-  DatasetComponent,
-  // TransformComponent,
-  LabelLayout,
-  // UniversalTransition,
-  CanvasRenderer,
-  // PieChart,
-  ToolboxComponent,
-  LegendComponent,
-  DataZoomComponent,
-  LineChart
-])
-
-const lineChartOption = (xAxisData: any, seriesData: any) => {
-  return {
-    title: {
-      text: "单位:次",
-      textStyle: {
-        color: "#777777",
-        fontSize: 13,
-        fontWeight: 400
-      }
-    },
-    legend: { show: false },
-    emphasis: { lineStyle: { width: 2 } },
-    xAxis: {
-      boundaryGap: false,
-      data: xAxisData,
-      type: 'category',
-      axisLine: { lineStyle: { color: '#8C8C8C' } },
-      lineStyle: { color: '#F2F2F2' }
-    },
-    color: [
-      '#2DC7AA',
-      '#FF6079',
-      // '#2DC7AA',
-      // '#FF602C',
-      // '#91DD1C',
-      // '#FFA92C',
-      // '#BE7E2E',
-      // '#1C96DD',
-      // '#D22CFF',
-      // '#FF3C3C',
-      // '#1AEE3E',
-      // '#00c9ff'
-    ],
-    series: [
-      {
-        lineStyle: { width: 1 },
-        data: seriesData[0],
-        symbol: 'circle',
-        name: '浏览次数',
-        type: 'line',
-        emphasis: { lineStyle: { width: 1 } }
-      },
-      {
-        lineStyle: { width: 1 },
-        data: seriesData[1],
-        symbol: 'circle',
-        name: '购买次数',
-        type: 'line',
-        areaStyle: {
-          color: {
-            type: 'linear',
-            x: 0,
-            y: 0,
-            x2: 0,
-            y2: 1,
-            colorStops: [
-              {
-                offset: 0,
-                color: 'rgba(255, 96, 121, 0.23)'
-                // 0% 处的颜色
-              },
-              {
-                offset: 1,
-                // 100% 处的颜色
-                color: 'rgba(255, 96, 121, 0)'
-              }
-            ]
-          }
-        },
-        emphasis: { lineStyle: { width: 1 } }
-      }
-    ],
-    grid: {
-      bottom: '3%',
-      containLabel: true,
-      left: '3%',
-      right: '5%',
-      top: '40'
-    },
-    tooltip: {
-      trigger: 'axis',
-      confine: true,
-      formatter: function (params: any) {
-        return params[0].name;
-      },
-      backgroundColor: '#FF6079',
-      borderWidth: 0,
-      borderRadius: 24,
-      padding: [1, 4],
-      textStyle: {
-        color: '#FFFFFF',
-        fontSize: 12
-      }
-    },
-    yAxis: {
-      type: 'value',
-      splitLine: {
-        axisLine: { lineStyle: { color: '#8C8C8C' } },
-        lineStyle: { color: ['#f2f2f2'], type: 'dashed' }
-      }
-    },
-    dataZoom: [{ type: 'inside', throttle: 100 }],
-    toolbox: { feature: { saveAsImage: { show: false } } }
-  }
-}
+import { defineComponent } from 'vue'
+import styles from './index.module.less'
+import { Tab, Tabs } from 'vant'
+import Echats from './echats'
+import ColHeader from '@/components/col-header'
+import TheSticky from '@/components/the-sticky'
+import TeacherItem from './teacher-item'
+import List from './list'
 
 export default defineComponent({
   name: 'HomeStatistics',
   setup() {
-    const popoverStatus = ref(false);
-    const statisticCounts = ref({
-      browseCount: 0,
-      buyCount: 0
-    })
-    let myChart: echarts.ECharts
-
-    nextTick(() => {
-      myChart = echarts.init(document.getElementById('eChart') as HTMLDivElement)
-    })
-
-    onMounted(() => {
-      nextTick(() => {
-        myChart.clear()
-        lineChartOption && myChart.setOption(lineChartOption([
-        '01月',
-        '02月',
-        '03月',
-        '04月',
-        '05月',
-        '06月',
-        '07月',
-        '08月',
-        '09月',
-        '10月',
-        '11月',
-        '12月'
-      ], [[
-        '0',
-        '0',
-        '0',
-        '0',
-        '0',
-        '0',
-        '0',
-        '2',
-        '0',
-        '8',
-        '10',
-        '0'
-      ], [
-        '0',
-        '0',
-        '0',
-        '0',
-        '1',
-        '3',
-        '0',
-        '2',
-        '0',
-        '8',
-        '10',
-        '0'
-      ]]))
-        myChart.on('highlight', function (params: any) {
-          const batch = params.batch || []
-          const options: any = myChart.getOption()
-          batch.forEach((item: any) => {
-            const batchIndex = item.dataIndex;
-
-            const browseCount = options.series[0].data[batchIndex]
-            const buyCount = options.series[1].data[batchIndex]
-            statisticCounts.value = {
-              browseCount,
-              buyCount
-            }
-          })
-        })
-      })
-    })
-
-
     return () => (
       <div class={styles.homeStatistics}>
-        <div class={styles.homeHead}>
-          <div class={styles.title}>
-            <img src={icon1} />
-            <span>浏览/购买</span>
-          </div>
-
-          <div class={styles.more}>
-            <span>详情</span>
-            <img src={iconArrow} />
-          </div>
-        </div>
-
-        <div class={styles.eChartSection}>
-          <div class={styles.eChartTitle}>
-            <div class={styles.left}>
-              <div class={styles.item} style="--color: #2DC7AA">
-                <span class={styles.line}></span>
-                <span class={styles.text}>浏览次数</span>
-                <span class={styles.num}>{statisticCounts.value.browseCount}次</span>
-              </div>
-              <div class={styles.item} style="--color: #FF6079">
-                <span class={styles.line}></span>
-                <span class={styles.text}>购买次数</span>
-                <span class={styles.num}>{statisticCounts.value.buyCount}次</span>
-              </div>
-            </div>
-            <div class={styles.right}>
-              <Popover v-model:show={popoverStatus.value} showArrow={false}>
-                {{
-                  default: () => (
-                    <div class={'select-time'}>
-                      <span>本月</span>
-                      <span class={'active'}>近三个月</span>
-                      <span>近半年</span>
-                      <span>近一年</span>
-                    </div>),
-                  reference: () => (<div class={[styles.showItem, popoverStatus.value && styles.showItemActive]}>
-                    <span>本月</span>
-                    <img src={popoverStatus.value?iconArrow11 : iconArrow1} />
-                  </div>)
-                }}
-              </Popover>
-            </div>
-          </div>
-
-          <div class={styles.eChart}>
-            <div id="eChart" style="width: 100%; height: 100%;"></div>
-          </div>
-        </div>
+        <TheSticky position="top">
+        <ColHeader border={false} background="transparent" />
+        </TheSticky>
+
+        <Tabs class={styles.tabs}>
+          <Tab title="VIP定制课" name="vip">
+            <List type="vip" />
+          </Tab>
+          <Tab title="趣纠课" name="practice">
+            <List type="practice" />
+          </Tab>
+          <Tab title="小组课" name="group">
+            <List type="group" />
+          </Tab>
+          <Tab title="直播课" name="live">
+            <List type="live" />
+          </Tab>
+          <Tab title="视频课" name="video">
+            <List type="video" />
+          </Tab>
+          <Tab title="乐谱" name="music">
+            <List type="music" />
+          </Tab>
+        </Tabs>
       </div>
     )
   }
-})
+})

+ 73 - 0
src/teacher/statistics/home-statistics-detail/list/index.module.less

@@ -0,0 +1,73 @@
+.expectedIncome {
+  background: #ffffff;
+  border-radius: 10px;
+  margin: 12px 14px 30px;
+  overflow: hidden;
+  .incomeTitle {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 15px 12px 12px;
+    .title {
+      display: flex;
+      align-items: center;
+      font-weight: 600;
+      font-size: 15px;
+      color: #333333;
+      line-height: 20px;
+    }
+    img {
+      width: 18px;
+      height: 18px;
+      margin-right: 6px;
+    }
+    .price {
+      font-weight: bold;
+      font-size: 16px;
+      color: #333333;
+      line-height: 16px;
+      font-family: DINAlternate, DINAlternate;
+      span {
+        font-size: 14px;
+      }
+    }
+  }
+  .incomeTip {
+    font-size: 13px;
+    color: #ef8548;
+    line-height: 18px;
+    background: #fff9f0;
+    box-shadow: 0px 2px 10px 0px rgba(229, 229, 229, 0.1);
+    border-radius: 6px;
+    border: 1px solid #ffefdf;
+    padding: 5px 10px;
+    margin: 10px 12px 0;
+  }
+
+  .element {
+    position: relative;
+    height: 0;
+    border-top: 1px dashed #dedede;
+    margin: 16px 19px 0;
+
+    &::before,
+    &::after {
+      content: '';
+      position: absolute;
+      z-index: 1;
+      bottom: -6.5px;
+      display: inline-block;
+      width: 14px;
+      height: 14px;
+      background: #f6f7f8;
+      border-radius: 50%;
+    }
+
+    &::before {
+      left: -26px;
+    }
+    &::after {
+      right: -26px;
+    }
+  }
+}

+ 53 - 0
src/teacher/statistics/home-statistics-detail/list/index.tsx

@@ -0,0 +1,53 @@
+import { defineComponent, PropType } from 'vue'
+import styles from './index.module.less'
+import { CellGroup, Sticky } from 'vant'
+import iconMoney from '../../images/icon-money.png'
+import ColResult from '@/components/col-result'
+import Echats from '../echats'
+import TeacherItem from '../teacher-item'
+import BuyItem from '../buy-item'
+
+export default defineComponent({
+  name: 'list',
+  props: {
+    type: {
+      type: String as PropType<
+        'vip' | 'practice' | 'group' | 'live' | 'video' | 'music'
+      >,
+      default: 'vip'
+    }
+  },
+  setup(props) {
+    return () => (
+      <div class={styles.list}>
+        <Echats />
+
+        <div class={styles.expectedIncome}>
+          {/* <Sticky> */}
+            <div class={styles.incomeTitle}>
+              <div class={styles.title}>
+                <img src={iconMoney} />
+                <span>预计总收入</span>
+              </div>
+
+              <div class={styles.price}>
+                <span>¥ </span>
+                4260.00
+              </div>
+            </div>
+          {/* </Sticky> */}
+          <div class={styles.incomeTip}>实际收入将在课程结束2天后结算</div>
+
+          <div class={styles.element}></div>
+          <CellGroup border={false}>
+            {['vip', 'practice'].includes(props.type) && <TeacherItem list={[1,2,3,4,5,6,7,7,8,]} />}
+            {['group', 'live', 'video', 'music'].includes(props.type) && (
+              <BuyItem list={[1,2,3,4,5,6,7,7,8,]} isSquare={props.type === "music"} />
+            )}
+          </CellGroup>
+          {/* <ColResult type="empty" btnStatus={false} classImgSize="SMALL" tips='暂无数据~' /> */}
+        </div>
+      </div>
+    )
+  }
+})

+ 90 - 0
src/teacher/statistics/home-statistics-detail/teacher-item/index.module.less

@@ -0,0 +1,90 @@
+.cell {
+  padding: 13px 12px;
+
+  .timer {
+    display: flex;
+    align-items: center;
+    font-size: 13px;
+    color: #666666;
+    line-height: 18px;
+    img {
+      width: 16px;
+      height: 16px;
+      margin-right: 6px;
+    }
+  }
+
+  .content {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding-top: 12px;
+    flex: 1;
+  }
+
+  .userInfo {
+    display: flex;
+    align-items: center;
+    // flex: 1;
+    flex-basis: 40%;
+    img {
+      width: 40px;
+      height: 40px;
+      border-radius: 20px;
+      margin-right: 9px;
+    }
+    .item {
+      flex-basis: auto;
+    }
+  }
+  .item {
+    display: flex;
+    flex-direction: column;
+    align-items: flex-start;
+    // flex: 1;
+    flex-basis: 30%;
+    .name {
+      font-size: 13px;
+      color: #333333;
+      line-height: 17px;
+      padding-bottom: 4px;
+      max-width: 70px;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+    }
+    .subjects {
+      font-size: 10px;
+      color: #ff8c00;
+      line-height: 14px;
+      background: #fff1de;
+      border-radius: 4px;
+      padding: 2px 4px;
+    }
+    .classNum {
+      font-family: DIN;
+      font-weight: bold;
+      font-size: 18px;
+      color: #333333;
+      display: flex;
+      align-items: center;
+      i {
+        font-style: normal;
+        font-size: 12px;
+        color: #777777;
+        padding-left: 1px;
+      }
+    }
+    .classPrice {
+      font-family: DIN;
+      font-weight: bold;
+      font-size: 16px;
+      color: #ff5a56;
+      line-height: 16px;
+      i {
+        font-size: 14px;
+        font-style: normal;
+      }
+    }
+  }
+}

+ 59 - 0
src/teacher/statistics/home-statistics-detail/teacher-item/index.tsx

@@ -0,0 +1,59 @@
+import { defineComponent } from 'vue'
+import styles from './index.module.less'
+import { Cell, CellGroup } from 'vant'
+import iconTimer from '@/common/images/icon_timer2.png'
+import iconMoney from '../../images/icon-money.png'
+import ColResult from '@/components/col-result'
+
+export default defineComponent({
+  name: 'teacher-item',
+  props: {
+    list: {
+      type: Array,
+      default: () => []
+    }
+  },
+  setup(props) {
+    return () => (
+      <CellGroup border={false}>
+        {props.list.map((item, index) => (
+          <Cell class={styles.cell} center>
+            {{
+              title: () => (
+                <div class={styles.timer}>
+                  <img src={iconTimer} />
+                  <span>购买时间:2024-10-30 15:23</span>
+                </div>
+              ),
+              label: () => (
+                <div class={styles.content}>
+                  <div class={styles.userInfo}>
+                    <img src={iconMoney} />
+                    <div class={styles.item}>
+                      <span class={styles.name}>
+                        {index === 0 ? '张涵宇张涵宇张涵宇' : '张涵宇'}
+                      </span>
+                      <span class={styles.subjects}>长笛</span>
+                    </div>
+                  </div>
+                  <div class={styles.item} style={{ alignItems: 'center' }}>
+                    <span class={styles.name}>课时数</span>
+                    <span class={styles.classNum}>
+                      12 <i>节</i>
+                    </span>
+                  </div>
+                  <div class={styles.item} style={{ alignItems: 'flex-end' }}>
+                    <span class={styles.name}>预计收入</span>
+                    <span class={styles.classPrice}>
+                      <i>¥</i> 560.00
+                    </span>
+                  </div>
+                </div>
+              )
+            }}
+          </Cell>
+        ))}
+      </CellGroup>
+    )
+  }
+})

+ 12 - 0
src/teacher/statistics/home-statistics/index.tsx

@@ -232,6 +232,18 @@ export default defineComponent({
 
     return () => (
       <div class={styles.homeStatistics}>
+        <div class={styles.homeHead}>
+          <div class={styles.title}>
+            <img src={icon1} />
+            <span>浏览/购买</span>
+          </div>
+
+          <div class={styles.more}>
+            <span>详情</span>
+            <img src={iconArrow} />
+          </div>
+        </div>
+
         <div class={styles.eChartSection}>
           <div class={styles.eChartTitle}>
             <div class={styles.left}>

TEMPAT SAMPAH
src/teacher/statistics/images/filter-bg.png


TEMPAT SAMPAH
src/teacher/statistics/images/icon-1.png


TEMPAT SAMPAH
src/teacher/statistics/images/icon-2.png


TEMPAT SAMPAH
src/teacher/statistics/images/icon-download.png


TEMPAT SAMPAH
src/teacher/statistics/images/icon-money.png


+ 237 - 0
src/teacher/statistics/practice-detail/index.module.less

@@ -0,0 +1,237 @@
+.practiceDetail {
+  min-height: 100vh;
+  background-color: #f6f7f8;
+  overflow: hidden;
+  background: linear-gradient(to bottom, #beffe6 0px, #f6f7f8 392px);
+}
+
+.section {
+  background: #ffffff;
+  box-shadow: 0px 2px 10px 0px rgba(229, 229, 229, 0.1);
+  border-radius: 10px;
+  overflow: hidden;
+  padding: 12px;
+  margin: 12px 14px 0;
+  position: relative;
+
+  .filter {
+    position: absolute;
+    top: 0;
+    right: 0;
+    background: url('../images/filter-bg.png') no-repeat center;
+    background-size: contain;
+    width: 114.5px;
+    height: 37px;
+    display: flex;
+    align-items: center;
+    font-size: 14px;
+    color: #131415;
+    line-height: 20px;
+    &.active {
+      color: #2DC7AA;
+    }
+    span {
+      padding-left: 49px;
+    }
+    img {
+      width: 9px;
+      height: 5px;
+      margin-left: 4px;
+    }
+  }
+
+  .title {
+    display: flex;
+    justify-content: space-between;
+    span {
+      display: flex;
+      align-items: center;
+      font-weight: 600;
+      font-size: 15px;
+      color: #333333;
+      line-height: 18px;
+      &::before {
+        content: '';
+        display: inline-block;
+        width: 3px;
+        height: 12px;
+        background: linear-gradient(180deg, #59e5d4 0%, #2dc7aa 100%);
+        border-radius: 2px;
+        margin-right: 4px;
+      }
+    }
+
+    .download {
+      display: flex;
+      align-items: center;
+      background: rgba(45, 199, 170, 0.1);
+      border-radius: 9px;
+      padding: 0 6px;
+      font-size: 12px;
+      color: #2dc7aa;
+      line-height: 17px;
+      img {
+        width: 10px;
+        height: 10px;
+        margin-left: 4px;
+      }
+    }
+  }
+  .leaveTime {
+    padding-top: 20px;
+    padding-bottom: 20px;
+    .num {
+      font-family: DIN;
+      font-weight: bold;
+      font-size: 30px;
+      color: #333333;
+      line-height: 35px;
+    }
+    .text {
+      font-weight: 400;
+      font-size: 14px;
+      color: #777777;
+      line-height: 26px;
+      padding: 0 2px;
+    }
+  }
+
+  .sList {
+    display: flex;
+  }
+  .sItem {
+    background: #f8f8f8;
+    box-shadow: 0px 2px 10px 0px rgba(229, 229, 229, 0.1);
+    border-radius: 4px;
+    padding: 10px;
+    flex: 1;
+    &:last-child {
+      margin-left: 10px;
+    }
+    .sTop {
+      display: flex;
+      align-items: center;
+      font-weight: 600;
+      font-size: 14px;
+      color: #2dc7aa;
+      line-height: 18px;
+      padding-bottom: 5px;
+      img {
+        margin-right: 6px;
+        width: 16px;
+        height: 16px;
+      }
+    }
+    .sBottom {
+      .num {
+        font-family: DIN;
+        font-weight: bold;
+        font-size: 22px;
+        color: #333333;
+        line-height: 26px;
+      }
+      .text {
+        font-size: 12px;
+        color: #777777;
+        line-height: 26px;
+      }
+    }
+  }
+}
+
+.scroll {
+  overflow-y: hidden;
+  overflow-x: auto;
+  position: relative;
+  z-index: auto;
+  height: 100%;
+  width: 100%;
+  padding-top: 12px;
+  &::-webkit-scrollbar {
+    display: none;
+  }
+}
+
+.dataTable {
+  word-break: break-word;
+  // transition: background-color .3s var(--n-bezier);
+  border-collapse: separate;
+  border-spacing: 0;
+
+  .tdFixedLeft {
+    position: sticky;
+    z-index: 1;
+    left: 0;
+  }
+
+  th {
+    font-weight: 600;
+    line-height: 26px;
+    margin-right: 2px;
+    font-weight: 600;
+    font-size: 12px;
+    &:last-child {
+      margin-right: 0;
+    }
+    &:first-child {
+      padding-left: 6px;
+      padding-right: 6px;
+      text-align: left;
+      background: #f8f8f8;
+    }
+    &:nth-child(5n),
+    &:nth-child(3n) {
+      background: #F8F1E9;
+      color: #DF8010;
+    }
+    &:nth-child(2n),
+    &:nth-child(4n) {
+      background: #e8f4f4;
+      color: #17bda6;
+    }
+  }
+
+  td {
+    line-height: 34px;
+    height: 34px;
+    text-align: center;
+    background: #fff;
+    margin-right: 2px;
+    font-weight: bold;
+    font-family: DIN;
+    &:last-child {
+      margin-right: 0;
+    }
+    &:first-child {
+      padding-left: 6px;
+      padding-right: 6px;
+      text-align: left;
+      display: flex;
+      align-items: center;
+      font-weight: 400;
+      span {
+        font-size: 13px;
+        color: #333333;
+        line-height: 20px;
+        max-width: 60px;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+      }
+    }
+    &:nth-child(4n) {
+      color: #17bda6;
+    }
+    &:nth-child(3n),
+    &:nth-child(5n) {
+      color: #df8010;
+    }
+    .userImg {
+      width: 16px;
+      height: 16px;
+      border-radius: 50%;
+      margin-right: 4px;
+      flex-shrink: 0;
+    }
+  }
+}

+ 112 - 0
src/teacher/statistics/practice-detail/index.tsx

@@ -0,0 +1,112 @@
+import { defineComponent, ref } from 'vue'
+import styles from './index.module.less'
+import iconArrow1 from '../images/icon-arrow1.png'
+import iconArrow11 from '../images/icon-arrow1-1.png'
+import icon1 from '../images/icon-1.png'
+import icon2 from '../images/icon-2.png'
+import iconDownload from '../images/icon-download.png'
+import { Popup } from 'vant'
+
+export default defineComponent({
+  name: 'PracticeDetail',
+  setup() {
+    const searchStatus = ref(false)
+    return () => (
+      <div class={styles.practiceDetail}>
+        <div class={styles.section}>
+          <div class={[styles.filter, searchStatus.value && styles.active]} onClick={() => searchStatus.value = true}>
+            <span>筛选</span>
+            <img src={searchStatus.value ? iconArrow11 : iconArrow1} />
+          </div>
+          <div class={styles.title}>
+            <span>练习详情</span>
+          </div>
+
+          <div class={styles.leaveTime}>
+            <span class={styles.num}>23</span>
+            <span class={styles.text}>时</span>
+            <span class={styles.num}>36</span>
+            <span class={styles.text}>分</span>
+            <span class={styles.num}>23</span>
+            <span class={styles.text}>秒</span>
+          </div>
+
+          <div class={styles.sList}>
+            <div class={styles.sItem}>
+              <div class={styles.sTop}>
+                <img src={icon2} />
+                <span>练习人数</span>
+              </div>
+              <div class={styles.sBottom}>
+                <span class={styles.num}>23</span>
+                <span class={styles.text}>人</span>
+              </div>
+            </div>
+            <div class={styles.sItem}>
+              <div class={styles.sTop}>
+                <img src={icon1} />
+                <span>平均练习时长</span>
+              </div>
+              <div class={styles.sBottom}>
+                <span class={styles.num}>23</span>
+                <span class={styles.text}>分钟</span>
+              </div>
+            </div>
+          </div>
+        </div>
+
+        <div class={styles.section}>
+          <div class={styles.title}>
+            <span>学员练习时长</span>
+            <div class={styles.download}>
+              <div>导出</div>
+              <img src={iconDownload} />
+            </div>
+          </div>
+
+          <div class={styles.scroll}>
+            <table class={styles.dataTable} style={{ width: '486px' }}>
+              <colgroup>
+                <col style="width: 88px;" />
+                <col style="width: 105px;" />
+                <col style="width: 106px;" />
+                <col style="width: 72px;" />
+                <col style="width: 106px;" />
+              </colgroup>
+              <thead>
+                <tr>
+                  <th class={styles.tdFixedLeft}>学员</th>
+                  <th>乐器</th>
+                  <th>
+                    <div>练习时长</div>
+                    {/* <div class={styles.filters}>
+                      
+                    </div> */}
+                  </th>
+                  <th>练习天数</th>
+                  <th>平均练习时长</th>
+                </tr>
+              </thead>
+              <tbody>
+                <tr>
+                  <td class={styles.tdFixedLeft}>
+                    <img class={styles.userImg} />
+                    <span>王曼王曼王曼</span>
+                  </td>
+                  <td>长笛</td>
+                  <td>22小时56分24秒</td>
+                  <td>8</td>
+                  <td>22小时56分24秒</td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </div>
+
+        <Popup v-model:show={searchStatus.value}>
+
+        </Popup>
+      </div>
+    )
+  }
+})