mo 1 年之前
父節點
當前提交
9d47920d92

+ 11 - 0
package-lock.json

@@ -11,6 +11,7 @@
       "dependencies": {
         "@vant/use": "^1.5.2",
         "@vueuse/core": "^10.2.0",
+        "animate.css": "^4.1.1",
         "clean-deep": "^3.4.0",
         "dayjs": "^1.11.7",
         "echarts": "^5.4.2",
@@ -3275,6 +3276,11 @@
         "uri-js": "^4.2.2"
       }
     },
+    "node_modules/animate.css": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmmirror.com/animate.css/-/animate.css-4.1.1.tgz",
+      "integrity": "sha512-+mRmCTv6SbCmtYJCN4faJMNFVNN5EuCTTprDTAo7YzIGji2KADmakjVA3+8mVDkZ2Bf09vayB35lSQIex2+QaQ=="
+    },
     "node_modules/ansi-escapes": {
       "version": "4.3.2",
       "resolved": "https://registry.npmmirror.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
@@ -11198,6 +11204,11 @@
         "uri-js": "^4.2.2"
       }
     },
+    "animate.css": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmmirror.com/animate.css/-/animate.css-4.1.1.tgz",
+      "integrity": "sha512-+mRmCTv6SbCmtYJCN4faJMNFVNN5EuCTTprDTAo7YzIGji2KADmakjVA3+8mVDkZ2Bf09vayB35lSQIex2+QaQ=="
+    },
     "ansi-escapes": {
       "version": "4.3.2",
       "resolved": "https://registry.npmmirror.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz",

+ 1 - 0
package.json

@@ -24,6 +24,7 @@
   "dependencies": {
     "@vant/use": "^1.5.2",
     "@vueuse/core": "^10.2.0",
+    "animate.css": "^4.1.1",
     "clean-deep": "^3.4.0",
     "dayjs": "^1.11.7",
     "echarts": "^5.4.2",

+ 43 - 20
src/components/layout/index.module.less

@@ -127,31 +127,54 @@
       display: flex;
       flex-direction: row;
       align-items: center;
-
       .messageBadge {
         margin-right: 24px;
         :global {
-          // .n-badge-sup {
-          //   height: 22px;
-          //   padding: 0 5px;
-          //   border: 1px solid #fff;
-          //   min-width: 22px;
-          //   border-radius: 11px;
-          //   text-align: center;
-          //   display: flex;
-          //   flex-direction: column;
-          //   align-items: center;
-          //   line-height: 20px;
-          // }
-          // .n-base-slot-machine-current-number__inner {
-          //   top: 1px;
-          // }
+          .n-badge-sup {
+            left: 20px;
+            -webkit-animation: TadaNum 1s 2s both infinite !important;
+            -moz-animation: TadaNum 1s 2s both infinite !important;
+            -ms-animation: TadaNum 1s 2s both infinite !important;
+            animation: TadaNum 1s 2s both infinite !important;
+          }
         }
         .messageIcon {
+          -webkit-animation: Tada 1s 2s both infinite;
+          -moz-animation: Tada 1s 2s both infinite;
+          -ms-animation: Tada 1s 2s both infinite;
+          animation: Tada 1s 2s both infinite;
           width: 32px;
           height: 32px;
         }
       }
+      @keyframes Tada {
+        0% {
+          transform: scale(1);
+          transform: scale(1);
+        }
+        10%,
+        20% {
+          transform: scale(0.9) rotate(-3deg);
+          transform: scale(0.9) rotate(-3deg);
+        }
+        30%,
+        50%,
+        70%,
+        90% {
+          transform: scale(1.1) rotate(3deg);
+          transform: scale(1.1) rotate(3deg);
+        }
+        40%,
+        60%,
+        80% {
+          transform: scale(1.1) rotate(-3deg);
+          transform: scale(1.1) rotate(-3deg);
+        }
+        100% {
+          transform: scale(1) rotate(0);
+          transform: scale(1) rotate(0);
+        }
+      }
 
       .line {
         width: 1px;
@@ -283,8 +306,8 @@
 }
 
 .toolboxImg {
-  width: 115px;
-  height: 115px;
+  width: 138px;
+  height: 138px;
   position: absolute;
   right: 32px;
   bottom: 84px;
@@ -292,8 +315,8 @@
   z-index: 1000;
 }
 .isDragIng {
-  width: 115px;
-  height: 115px;
+  width: 138px;
+  height: 138px;
 }
 
 :global {

+ 3 - 3
src/components/layout/layoutTop.tsx

@@ -10,7 +10,7 @@ import schoolDot from './images/schoolDot.png';
 import personIcon from './images/personIcon.png';
 import { useUserStore } from '@/store/modules/users';
 import { useRouter } from 'vue-router';
-
+import 'animate.css';
 export default defineComponent({
   name: 'layoutTop',
   setup() {
@@ -26,13 +26,13 @@ export default defineComponent({
           </div>
           <div class={styles.layoutRight}>
             <NBadge
-              value={999}
+              value={12}
               max={99}
               class={styles.messageBadge}
               color={'#FF1036'}>
               <NImage
+                class={[styles.messageIcon]}
                 preview-disabled
-                class={styles.messageIcon}
                 src={messageIcon}></NImage>
             </NBadge>
             <div class={styles.line}></div>

+ 33 - 2
src/styles/index.less

@@ -131,6 +131,9 @@ body {
 
     color: #333333;
     font-size: 15px;
+    .n-button__content {
+      color: #1677ff;
+    }
   }
 }
 
@@ -209,7 +212,6 @@ body {
 
 :root {
   --product-color: #3044ca;
-  --n-text-color: #1677ff !important;
 }
 
 // .n-button--primary-type {
@@ -237,4 +239,33 @@ body {
   /* Internet Explorer 10+ */
 
   color: rgba(0, 0, 0, 0.4);
-}
+}
+
+@keyframes TadaNum {
+  0% {
+    transform: rotate(0);
+    transform: rotate(0);
+  }
+  10%,
+  20% {
+    transform: rotate(-6deg);
+    transform: rotate(-6deg);
+  }
+  30%,
+  50%,
+  70%,
+  90% {
+    transform: rotate(6deg);
+    transform: rotate(6deg);
+  }
+  40%,
+  60%,
+  80% {
+    transform: rotate(-6deg);
+    transform: rotate(-6deg);
+  }
+  100% {
+    transform: rotate(0);
+    transform: rotate(0);
+  }
+}

+ 286 - 0
src/views/home/components/practiceData.tsx

@@ -0,0 +1,286 @@
+import { Ref, defineComponent, reactive, ref } from 'vue';
+import styles from '../index.module.less';
+import { NButton, NDataTable, NNumberAnimation } from 'naive-ui';
+import numeral from 'numeral';
+import { useECharts } from '@/hooks/web/useECharts';
+import Pagination from '/src/components/pagination';
+export default defineComponent({
+  name: 'home-practiceData',
+  setup() {
+    const chartRef = ref<HTMLDivElement | null>(null);
+    const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
+    const practiceFlag = ref(true);
+    const payForm = reactive({
+      height: '360px',
+      width: '100%',
+      studentNum: 0,
+      paymentAmount: 0,
+      dateList: [
+        '2022-10-10',
+        '2022-10-11',
+        '2022-10-12',
+        '2022-10-13',
+        '2022-10-14',
+        '2022-10-15',
+        '2022-10-16'
+      ],
+      timeList: [90, 128, 242, 120, 186, 77, 148]
+    });
+
+    const state = reactive({
+      loading: false,
+      pagination: {
+        page: 1,
+        rows: 10,
+        pageTotal: 4
+      },
+      tableList: [
+        {
+          teacherName: '孙忆枫',
+          createTime: '2023-06-27',
+          endTime: '2023-06-30',
+          status: 'ing',
+          studentNum: 100,
+          submitNum: 100,
+          quantityNum: 60,
+          submitRate: 100,
+          quantityRate: 60
+        },
+        {
+          teacherName: '孙忆枫',
+          createTime: '2023-06-27',
+          endTime: '2023-06-30',
+          status: 'ing',
+          studentNum: 100,
+          submitNum: 100,
+          quantityNum: 60,
+          submitRate: 100,
+          quantityRate: 60
+        },
+        {
+          teacherName: '孙忆枫',
+          createTime: '2023-06-27',
+          endTime: '2023-06-30',
+          status: 'ing',
+          studentNum: 100,
+          submitNum: 100,
+          quantityNum: 60,
+          submitRate: 100,
+          quantityRate: 60
+        },
+        {
+          teacherName: '孙忆枫',
+          createTime: '2023-06-25',
+          endTime: '2023-06-26',
+          status: 'end',
+          studentNum: 100,
+          submitNum: 100,
+          quantityNum: 60,
+          submitRate: 100,
+          quantityRate: 60
+        }
+      ] as any,
+      goCourseVisiable: false
+    });
+    const columns = () => {
+      return [
+        {
+          title: '日期',
+          key: 'createTime'
+        },
+        {
+          title: '练习人数',
+          key: 'quantityNum',
+          render(row: any) {
+            return <span>{row.quantityNum}人</span>;
+          }
+        },
+
+        {
+          title: '平均练习时长(分钟)',
+          key: 'submitNum',
+          render(row: any) {
+            return <span>{row.submitNum}分钟</span>;
+          }
+        }
+      ];
+    };
+    const getList = () => {
+      console.log('1');
+    };
+    const setChart = () => {
+      setOptions({
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: {
+            type: 'none'
+          }
+        },
+        legend: {
+          show: false,
+          selected: {
+            //在这里设置默认展示就ok了
+            '练习时长(分钟)': practiceFlag.value
+          }
+        },
+        xAxis: {
+          type: 'category',
+          boundaryGap: true,
+          axisLabel: {
+            show: true,
+            interval: 0
+          },
+          data: payForm.dateList
+        },
+        yAxis: [
+          {
+            type: 'value',
+            axisLabel: {
+              formatter: '{value} min'
+            },
+            axisTick: {
+              show: false
+            },
+            splitArea: {
+              show: false,
+              areaStyle: {
+                color: ['rgba(255,255,255,0.2)']
+              }
+            }
+          }
+        ],
+        grid: {
+          left: '1%',
+          right: '1%',
+          top: '2%',
+          bottom: 0,
+          containLabel: true
+        },
+        series: [
+          {
+            // smooth: true,
+            data: payForm.timeList,
+            type: 'bar',
+            barWidth: '48px',
+            label: {
+              // 柱图头部显示值
+              show: true,
+              position: 'top',
+              color: '#333',
+              fontSize: '12px',
+              fontWeight: 600
+            },
+
+            itemStyle: {
+              normal: {
+                //这里设置柱形图圆角 [左上角,右上角,右下角,左下角]
+                barBorderRadius: [8, 8, 0, 0],
+                color: '#D5E9FF'
+              },
+              emphasis: {
+                color: '#3583FA' //hover时改变柱子颜色
+                // borderWidth: 4,
+                // borderColor: 'rgba(213, 233, 255,.4)',
+                // borderType: 'solid'
+              }
+            } as any
+          }
+        ],
+
+        formatter: (item: any) => {
+          if (Array.isArray(item)) {
+            return [
+              item[0].axisValueLabel,
+              ...item.map(
+                (d: any) =>
+                  `<br/>${
+                    d.marker
+                  }<span style="margin-top:10px;margin-left:5px;font-size: 13px;font-weight: 500;
+                  color: #131415;font-weight: 600;
+                  margin-top:12px
+                  line-height: 18px;">练习时长: ${d.value}${'分钟'} </span>`
+              )
+            ].join('');
+          } else {
+            return item;
+          }
+        }
+        // dataZoom: [
+        //   {
+        //     type: 'slider',
+        //     start: 5,
+        //     end: 100,
+        //     filterMode: 'empty'
+        //   }
+        // ]
+      });
+    };
+    setChart();
+    return () => (
+      <>
+        <div class={styles.homeTrainData}>
+          <div class={styles.TrainDataTop}>
+            <div class={styles.TrainDataTopLeft}>
+              <div class={styles.TrainDataItem}>
+                <p class={styles.TrainDataItemTitle}>
+                  <span>
+                    <NNumberAnimation from={0} to={32}></NNumberAnimation>
+                  </span>
+                  人
+                </p>
+                <p class={styles.TrainDataItemsubTitle}>练习人数</p>
+              </div>
+              <div class={styles.TrainDataItem}>
+                <p class={styles.TrainDataItemTitle}>
+                  <span>
+                    <NNumberAnimation from={0} to={32}></NNumberAnimation>
+                  </span>
+                  分钟
+                </p>
+                <p class={styles.TrainDataItemsubTitle}>平均练习时长</p>
+              </div>
+            </div>
+            <div class={styles.TrainDataTopRight}>
+              <div
+                // onClick={() => {
+                //   practiceFlag.value = !practiceFlag.value;
+                //   setChart();
+                // }}
+                class={[
+                  styles.DataTopRightItem,
+                  practiceFlag.value ? '' : styles.DataTopRightItemDis
+                ]}>
+                <div
+                  class={[
+                    styles.DataTopRightDot,
+                    styles.DataTopRightDotBlue
+                  ]}></div>
+                <p>练习时长(分钟)</p>
+              </div>
+            </div>
+          </div>
+          <div class={styles.chatrs}>
+            <div
+              ref={chartRef}
+              style={{ height: payForm.height, width: payForm.width }}></div>
+          </div>
+          <div class={styles.tableWrap}>
+            <NDataTable
+              class={styles.classTable}
+              loading={state.loading}
+              columns={columns()}
+              data={state.tableList}></NDataTable>
+            <Pagination
+              v-model:page={state.pagination.page}
+              v-model:pageSize={state.pagination.rows}
+              v-model:pageTotal={state.pagination.pageTotal}
+              onList={getList}
+              sync
+              saveKey="orchestraRegistration-key"
+            />
+          </div>
+        </div>
+      </>
+    );
+  }
+});

+ 38 - 5
src/views/home/components/study.tsx

@@ -1,12 +1,14 @@
-import { defineComponent } from 'vue';
+import { defineComponent, ref } from 'vue';
 import styles from '../index.module.less';
 import bannerPerson from './images/bannerPerson.png';
 import { NIcon, NImage, NDatePicker, NSpace, NButton } from 'naive-ui';
 import CDatePicker from '@/components/CDatePicker';
 import TrainData from './trainData';
+import PracticeData from './practiceData';
 export default defineComponent({
   name: 'home-study',
   setup() {
+    const chioseTab = ref('practiceData');
     return () => (
       <>
         <div class={styles.homeStudy}>
@@ -16,11 +18,36 @@ export default defineComponent({
           </div>
           <div class={styles.homeStudyInfoList}>
             <div class={styles.homeStudyInfoTabs}>
-              <div class={[styles.homeStudyInfoTabItem, styles.active]}>
+              <div
+                onClick={() => {
+                  chioseTab.value = 'trainData';
+                }}
+                class={[
+                  styles.homeStudyInfoTabItem,
+                  chioseTab.value == 'trainData' ? styles.active : null
+                ]}>
                 训练数据
               </div>
-              <div class={styles.homeStudyInfoTabItem}>练习数据</div>
-              <div class={styles.homeStudyInfoTabItem}>练习排行</div>
+              <div
+                onClick={() => {
+                  chioseTab.value = 'practiceData';
+                }}
+                class={[
+                  styles.homeStudyInfoTabItem,
+                  chioseTab.value == 'practiceData' ? styles.active : null
+                ]}>
+                练习数据
+              </div>
+              <div
+                onClick={() => {
+                  chioseTab.value = 'practiceRanking';
+                }}
+                class={[
+                  styles.homeStudyInfoTabItem,
+                  chioseTab.value == 'practiceRanking' ? styles.active : null
+                ]}>
+                练习排行
+              </div>
             </div>
             <div class={styles.homeStudyInfoDate}>
               <NSpace>
@@ -34,7 +61,13 @@ export default defineComponent({
               </NSpace>
             </div>
           </div>
-          <TrainData></TrainData>
+          {chioseTab.value == 'trainData' ? <TrainData></TrainData> : null}
+          {chioseTab.value == 'practiceData' ? (
+            <PracticeData></PracticeData>
+          ) : null}
+          {chioseTab.value == 'practiceRanking' ? (
+            <TrainData></TrainData>
+          ) : null}
         </div>
       </>
     );

+ 145 - 3
src/views/home/components/trainData.tsx

@@ -1,8 +1,9 @@
 import { Ref, defineComponent, reactive, ref } from 'vue';
 import styles from '../index.module.less';
-import { NNumberAnimation } from 'naive-ui';
+import { NButton, NDataTable, NNumberAnimation } from 'naive-ui';
 import numeral from 'numeral';
 import { useECharts } from '@/hooks/web/useECharts';
+import Pagination from '/src/components/pagination';
 export default defineComponent({
   name: 'home-trainData',
   setup() {
@@ -27,7 +28,133 @@ export default defineComponent({
       studentList: [50, 100, 80, 180, 70, 99, 300],
       payInfoList: [100, 200, 300, 450, 330, 200, 10]
     });
-
+    const state = reactive({
+      loading: false,
+      pagination: {
+        page: 1,
+        rows: 10,
+        pageTotal: 4
+      },
+      tableList: [
+        {
+          teacherName: '孙忆枫',
+          createTime: '2023-06-27',
+          endTime: '2023-06-30',
+          status: 'ing',
+          studentNum: 100,
+          submitNum: 100,
+          quantityNum: 60,
+          submitRate: 100,
+          quantityRate: 60
+        },
+        {
+          teacherName: '孙忆枫',
+          createTime: '2023-06-27',
+          endTime: '2023-06-30',
+          status: 'ing',
+          studentNum: 100,
+          submitNum: 100,
+          quantityNum: 60,
+          submitRate: 100,
+          quantityRate: 60
+        },
+        {
+          teacherName: '孙忆枫',
+          createTime: '2023-06-27',
+          endTime: '2023-06-30',
+          status: 'ing',
+          studentNum: 100,
+          submitNum: 100,
+          quantityNum: 60,
+          submitRate: 100,
+          quantityRate: 60
+        },
+        {
+          teacherName: '孙忆枫',
+          createTime: '2023-06-25',
+          endTime: '2023-06-26',
+          status: 'end',
+          studentNum: 100,
+          submitNum: 100,
+          quantityNum: 60,
+          submitRate: 100,
+          quantityRate: 60
+        }
+      ] as any,
+      goCourseVisiable: false
+    });
+    const columns = () => {
+      return [
+        {
+          title: '布置老师',
+          key: 'teacherName'
+        },
+        {
+          title: '布置时间',
+          key: 'createTime'
+        },
+        {
+          title: '截止时间',
+          key: 'endTime'
+        },
+        {
+          title: '训练状态',
+          key: 'status',
+          render(row: any) {
+            return row.status == 'ing' ? (
+              <div class={styles.indDot}>
+                {' '}
+                <span></span> 进行中
+              </div>
+            ) : (
+              <div class={styles.endDot}>
+                <span></span>已结束
+              </div>
+            );
+          }
+        },
+        {
+          title: '布置人数',
+          key: 'studentNum'
+        },
+        {
+          title: '提交人数',
+          key: 'submitNum'
+        },
+        {
+          title: '合格人数',
+          key: 'quantityNum'
+        },
+        {
+          title: '提交率',
+          key: 'submitRate',
+          render(row: any) {
+            return <span>{row.submitRate}%</span>;
+          }
+        },
+        {
+          title: '合格率',
+          key: 'quantityRate',
+          render(row: any) {
+            return <span>{row.quantityRate}%</span>;
+          }
+        },
+        {
+          title: '操作',
+          key: 'id',
+          render(row: any) {
+            return (
+              <NButton text type="primary">
+                详情
+              </NButton>
+            );
+          }
+        }
+      ];
+    };
+    const getList = () => {
+      console.log('1');
+    };
     const setChart = () => {
       setOptions({
         tooltip: {
@@ -49,7 +176,7 @@ export default defineComponent({
         },
         xAxis: {
           type: 'category',
-          boundaryGap: false,
+          boundaryGap: true,
           axisLabel: {
             show: true,
             interval: 0
@@ -295,6 +422,21 @@ export default defineComponent({
               ref={chartRef}
               style={{ height: payForm.height, width: payForm.width }}></div>
           </div>
+          <div class={styles.tableWrap}>
+            <NDataTable
+              class={styles.classTable}
+              loading={state.loading}
+              columns={columns()}
+              data={state.tableList}></NDataTable>
+            <Pagination
+              v-model:page={state.pagination.page}
+              v-model:pageSize={state.pagination.rows}
+              v-model:pageTotal={state.pagination.pageTotal}
+              onList={getList}
+              sync
+              saveKey="orchestraRegistration-key"
+            />
+          </div>
         </div>
       </>
     );

+ 3 - 1
src/views/home/index.module.less

@@ -280,7 +280,9 @@
           border-radius: 4px;
           margin-right: 6px;
         }
-
+        .DataTopRightDot.DataTopRightDotBlue {
+          background: #d5e9ff;
+        }
         .DataTopRightDot.red {
           background: #ff7aa7;
         }

+ 0 - 15
src/views/home/index.tsx

@@ -180,21 +180,6 @@ export default defineComponent({
           </div>
           <div class={styles.leftBottomWrap}>
             <Study></Study>
-            <div class={styles.tableWrap}>
-              <NDataTable
-                class={styles.classTable}
-                loading={state.loading}
-                columns={columns()}
-                data={state.tableList}></NDataTable>
-              <Pagination
-                v-model:page={state.pagination.page}
-                v-model:pageSize={state.pagination.rows}
-                v-model:pageTotal={state.pagination.pageTotal}
-                onList={getList}
-                sync
-                saveKey="orchestraRegistration-key"
-              />
-            </div>
           </div>
         </div>
         <div class={styles.homeInfoRight}>