Przeglądaj źródła

添加训练统计

lex 1 rok temu
rodzic
commit
74db7aba91

+ 16 - 0
src/router/routes-common.ts

@@ -177,6 +177,22 @@ export default [
         meta: {
           title: '请假统计'
         }
+      },
+      {
+        path: '/train-statistics',
+        name: 'train-statistics',
+        component: () => import('@/views/train-statistics'),
+        meta: {
+          title: '训练统计'
+        }
+      },
+      {
+        path: '/train-detail',
+        name: 'train-detail',
+        component: () => import('@/views/train-statistics/train-detail'),
+        meta: {
+          title: '训练详情'
+        }
       }
     ]
   },

+ 23 - 0
src/views/train-statistics/api.ts

@@ -0,0 +1,23 @@
+import request from '@/helpers/request';
+
+/**
+ * 合作单位的乐团
+ * @param data
+ * @returns
+ */
+export const musicGroupPage = (data: any) => {
+  return request.get('/api-web/schoolCooperationOrgan/musicGroupPage', {
+    params: data
+  });
+};
+
+/**
+ * 获取乐团班级列表
+ * @param data
+ * @returns
+ */
+export const musicGroupClassPage = (data: any) => {
+  return request.get('/api-web/schoolCooperationOrgan/musicGroupClassPage', {
+    params: data
+  });
+};

BIN
src/views/train-statistics/images/1.png


BIN
src/views/train-statistics/images/2.png


BIN
src/views/train-statistics/images/3.png


BIN
src/views/train-statistics/images/arrow_down.png


BIN
src/views/train-statistics/images/user_bg.png


BIN
src/views/train-statistics/images/v3.png


+ 121 - 0
src/views/train-statistics/index.module.less

@@ -0,0 +1,121 @@
+.visitList {
+  min-height: 100vh;
+
+  :global {
+    .van-dropdown-menu__bar {
+      box-shadow: none;
+    }
+  }
+
+  .van-tab {
+    font-size: 0.16rem;
+  }
+
+  .search .van-search {
+    margin: 10px 0;
+  }
+}
+
+
+
+.data-content {
+  margin: 10px 15px 0;
+  border-radius: 10px;
+  overflow: hidden;
+
+  .logo {
+    width: 40px;
+    height: 40px;
+    // margin-right: 12px;
+    border-radius: 100%;
+  }
+
+  &:first-child {
+    margin-top: 0;
+  }
+
+  .van-row-item {
+    display: flex;
+    align-items: center;
+  }
+
+  :global {
+    .van-grid-item__content {
+      padding: 3px;
+    }
+
+    .van-grid-item__content {
+      background-color: transparent;
+    }
+
+    .van-grid-item__icon-wrapper {
+      font-size: 15px;
+      font-weight: 500;
+      color: #000;
+    }
+
+    .van-grid-item__text {
+      padding-top: 3px;
+      font-size: 12px;
+      color: #808080;
+    }
+  }
+
+
+  .teacher_info {
+    position: relative;
+    display: flex;
+    align-items: center;
+
+    img {
+      margin-right: 10px;
+      width: 40px;
+      height: 40px;
+      border-radius: 50%;
+    }
+
+    .memberLogo {
+      position: absolute;
+      left: 30px;
+      top: -4px;
+      width: 20px;
+      height: 20px;
+    }
+
+    .userName {
+      color: #1a1a1a;
+      font-size: 14px;
+    }
+  }
+
+  .orchestraName {
+    font-size: 14px;
+    color: #333;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+  }
+}
+
+.btnWrap {
+  display: flex;
+  flex-direction: row;
+
+  .cancelBtn {
+    height: 48px;
+    line-height: 48px;
+    background: #eeeff3;
+    // color: @mColor;
+    text-align: center;
+    width: 100%;
+  }
+
+  .okBtn {
+    width: 100%;
+    height: 48px;
+    line-height: 48px;
+    // background: @mColor;
+    color: #fff;
+    text-align: center;
+  }
+}

+ 211 - 0
src/views/train-statistics/index.tsx

@@ -0,0 +1,211 @@
+import { defineComponent, onMounted, reactive } from 'vue';
+import styles from './index.module.less';
+import MSticky from '@/components/m-sticky';
+import MHeader from '@/components/m-header';
+import { Cell, CellGroup, Grid, GridItem, List } from 'vant';
+import MFullRefresh from '@/components/m-full-refresh';
+import v3 from './images/v3.png';
+import icon_student from '@common/images/icon-student-default.png';
+import request from '@/helpers/request';
+import TrainModel from './train-model';
+import MEmpty from '@/components/m-empty';
+import { useRouter } from 'vue-router';
+import SkeletionIndexModal from './skeletion-index.modal';
+
+export default defineComponent({
+  name: 'train-statistics',
+  setup() {
+    const router = useRouter();
+    const forms = reactive({
+      isClick: false,
+      listState: {
+        dataShow: true, // 判断是否有数据
+        loading: true,
+        finished: false,
+        refreshing: false
+      },
+      params: {
+        page: 1,
+        rows: 20
+      },
+      list: []
+    });
+
+    const getList = async () => {
+      try {
+        if (forms.isClick) return;
+        forms.isClick = true;
+        const { data } = await request.get(
+          '/api-web/schoolCloudStudy/countStudentTrain',
+          {
+            params: {
+              ...forms.params
+            }
+          }
+        );
+        const result = data || {};
+        // 判断是否有数据
+        if (forms.listState.refreshing) {
+          forms.list = result.rows || [];
+        } else {
+          forms.list = forms.list.concat(result.rows || []);
+        }
+
+        forms.listState.finished = result.pageNo >= result.totalPage;
+        forms.params.page = result.pageNo + 1;
+      } catch {
+        forms.listState.finished = true;
+      } finally {
+        setTimeout(() => {
+          forms.listState.dataShow = forms.list.length > 0;
+          forms.listState.refreshing = false;
+          forms.listState.loading = false;
+          forms.isClick = false;
+        }, 500);
+      }
+    };
+
+    const onRefresh = () => {
+      forms.params.page = 1;
+      getList();
+    };
+
+    const onLoad = (value: any) => {
+      forms.params = Object.assign(forms.params, value);
+      onResetList();
+    };
+
+    const onHref = (item: any) => {
+      router.push({
+        path: '/train-detail',
+        query: {
+          userId: item.userId,
+          username: item.username,
+          phone: item.phone,
+          musicGroupName: item.musicGroupName,
+          avatar: item.avatar,
+          visitFlag: item.visitFlag
+        }
+      });
+    };
+
+    const onResetList = () => {
+      forms.list = [];
+      forms.params.page = 1;
+
+      forms.listState.dataShow = true;
+      forms.listState.loading = true;
+      forms.listState.finished = false;
+      forms.listState.refreshing = true;
+      onRefresh();
+    };
+    onMounted(() => {
+      // getList()
+    });
+    return () => (
+      <div class={styles.visitList}>
+        <MSticky position="top">
+          <MHeader />
+          <TrainModel onLoad={onLoad} />
+        </MSticky>
+
+        <SkeletionIndexModal v-model:show={forms.listState.loading}>
+          <MFullRefresh
+            v-model:modelValue={forms.listState.refreshing}
+            onRefresh={() => onRefresh()}
+            style={{
+              minHeight: `calc(100vh - var(--header-height))`
+            }}>
+            <List
+              finished={forms.listState.finished}
+              finishedText=" "
+              style={{ overflow: 'hidden', marginBottom: '18px' }}
+              onLoad={getList}
+              immediateCheck={false}>
+              {forms.listState.dataShow ? (
+                forms.list.map((item: any) => (
+                  <CellGroup
+                    class={styles['data-content']}
+                    border={false}
+                    onClick={() => onHref(item)}>
+                    <Cell center>
+                      {{
+                        title: () => (
+                          <div class={styles.teacher_info}>
+                            {item.memberFlag && (
+                              <img src={v3} class={styles.memberLogo} />
+                            )}
+                            <img
+                              class={styles.logo}
+                              src={item.avatar || icon_student}
+                              alt=""
+                            />
+                            <p class={styles.userName}>{item.username}</p>
+                          </div>
+                        ),
+                        default: () => (
+                          <p class={styles.orchestraName}>
+                            {item.musicGroupName}
+                          </p>
+                        )
+                      }}
+                    </Cell>
+                    <Cell isLink clickable={false} center>
+                      {{
+                        title: () => (
+                          <Grid border={false} columnNum={4} clickable>
+                            <GridItem text="训练次数">
+                              {{
+                                icon: () => (
+                                  <span>{item.totalPlayTime}分钟</span>
+                                )
+                              }}
+                            </GridItem>
+                            <GridItem text="训练时长">
+                              {{
+                                icon: () => (
+                                  <span style="color: #01c1b5">
+                                    {item.trainNum}次
+                                  </span>
+                                )
+                              }}
+                            </GridItem>
+                            <GridItem text="训练天数">
+                              {{
+                                icon: () => (
+                                  <span style="color: #ff802c">
+                                    {item.trainDay}天
+                                  </span>
+                                )
+                              }}
+                            </GridItem>
+                            <GridItem text="评测次数">
+                              {{
+                                icon: () => (
+                                  <span style="color: #f79c00">
+                                    {item.recordNum}次
+                                  </span>
+                                )
+                              }}
+                            </GridItem>
+                          </Grid>
+                        )
+                      }}
+                    </Cell>
+                  </CellGroup>
+                ))
+              ) : (
+                <MEmpty
+                  style={{
+                    minHeight: `calc(100vh - var(--header-height))`
+                  }}
+                  description="暂无数据"
+                />
+              )}
+            </List>
+          </MFullRefresh>
+        </SkeletionIndexModal>
+      </div>
+    );
+  }
+});

+ 173 - 0
src/views/train-statistics/skeletion-detail-modal.tsx

@@ -0,0 +1,173 @@
+import {
+  Cell,
+  CellGroup,
+  Grid,
+  GridItem,
+  Skeleton,
+  SkeletonAvatar,
+  SkeletonParagraph
+} from 'vant';
+import { defineComponent, onMounted, reactive, watch } from 'vue';
+import styles from './train-detail.module.less';
+
+export default defineComponent({
+  name: 'skeleton-modal',
+  props: {
+    show: {
+      type: Boolean,
+      default: false
+    },
+    showCount: {
+      type: Array,
+      default: () => [1, 2, 3, 4, 5]
+    }
+  },
+  setup(props, { slots }) {
+    const forms = reactive({
+      loading: false
+    });
+
+    onMounted(() => {
+      forms.loading = props.show;
+    });
+
+    watch(
+      () => props.show,
+      () => {
+        forms.loading = props.show;
+      }
+    );
+    return () => (
+      <Skeleton loading={forms.loading} style="flex-wrap: wrap">
+        {{
+          template: () => (
+            <div
+              style={{
+                height: `calc(100vh - var(--header-height))`,
+                overflow: 'hidden',
+                width: '100%'
+              }}>
+              {props.showCount.map(() => (
+                <CellGroup
+                  class={styles['data-content']}
+                  border={false}>
+                  <Cell
+                    style={{ padding: '10px 12px 12px' }}
+                    border
+                    center
+                    title-style="flex-basis: 45%;">
+                    {{
+                      title: () => (
+                        <>
+                          <span class={styles.scoreName}>
+                            <SkeletonParagraph rowWidth={'60%'} />
+                          </span>
+                          <p style="font-size: 14px; color: #808080;">
+                            <SkeletonParagraph rowWidth={'50%'} />
+                          </p>
+                        </>
+                      ),
+                      value: () => (
+                        <p>
+                          <SkeletonParagraph />
+                        </p>
+                      )
+                    }}
+                  </Cell>
+                  <Cell
+                    isLink
+                    clickable={false}
+                    center
+                    style="padding: 12px 12px 16px">
+                    {{
+                      title: () => (
+                        <Grid border={false} columnNum={4} clickable>
+                          <GridItem >
+                            {{
+                              text: () => <SkeletonParagraph rowWidth={'50%'} />,
+                            }}
+                          </GridItem>
+                          <GridItem >
+                            {{
+                              text: () => <SkeletonParagraph rowWidth={'50%'} />,
+                            }}
+                          </GridItem>
+                          <GridItem >
+                            {{
+                              text: () => <SkeletonParagraph rowWidth={'50%'} />,
+                            }}
+                          </GridItem>
+                          <GridItem >
+                            {{
+                              text: () => <SkeletonParagraph rowWidth={'50%'} />,
+                            }}
+                          </GridItem>
+                        </Grid>
+                      )
+                    }}
+                  </Cell>
+                </CellGroup>
+                // <CellGroup inset class={styles.detailCellGroup}>
+                //   <Cell
+                //     center
+                //     border={false}
+                //     class={[styles.className, styles.skeletionTitle]}>
+                //     {{
+                //       title: () => <SkeletonParagraph rowWidth={'50%'} />,
+                //       value: () => <SkeletonParagraph />
+                //     }}
+                //   </Cell>
+                //   <Cell center>
+                //     <div class={styles.detailGroup}>
+                //       <div class={styles.detailItem}>
+                //         <div class={styles.detailStatus}>
+                //           <SkeletonParagraph rowWidth={'40%'} />
+                //           <SkeletonAvatar class={styles.img} />
+                //         </div>
+                //         <div class={styles.sign}>
+                //           <SkeletonParagraph rowWidth={'40%'} />
+                //           <SkeletonParagraph rowWidth={'40%'} />
+                //         </div>
+                //       </div>
+                //       <div class={styles.detailItem}>
+                //         <div class={styles.detailStatus}>
+                //           <SkeletonParagraph rowWidth={'40%'} />
+                //           <SkeletonAvatar class={styles.img} />
+                //         </div>
+                //         <div class={styles.sign}>
+                //           <SkeletonParagraph rowWidth={'40%'} />
+                //           <SkeletonParagraph rowWidth={'40%'} />
+                //         </div>
+                //       </div>
+                //       <div class={styles.detailItem}>
+                //         <div class={styles.detailStatus}>
+                //           <SkeletonParagraph rowWidth={'40%'} />
+                //           <SkeletonAvatar class={styles.img} />
+                //         </div>
+                //         <div class={styles.sign}>
+                //           <SkeletonParagraph rowWidth={'40%'} />
+                //           <SkeletonParagraph rowWidth={'40%'} />
+                //         </div>
+                //       </div>
+                //       <div class={styles.detailItem}>
+                //         <div class={styles.detailStatus}>
+                //           <SkeletonParagraph rowWidth={'40%'} />
+                //           <SkeletonAvatar class={styles.img} />
+                //         </div>
+                //         <div class={styles.sign}>
+                //           <SkeletonParagraph rowWidth={'40%'} />
+                //           <SkeletonParagraph rowWidth={'40%'} />
+                //         </div>
+                //       </div>
+                //     </div>
+                //   </Cell>
+                // </CellGroup>
+              ))}
+            </div>
+          ),
+          default: () => slots.default && slots.default()
+        }}
+      </Skeleton>
+    );
+  }
+});

+ 106 - 0
src/views/train-statistics/skeletion-index.modal.tsx

@@ -0,0 +1,106 @@
+import {
+  Cell,
+  CellGroup,
+  Grid,
+  GridItem,
+  Skeleton,
+  SkeletonAvatar,
+  SkeletonParagraph
+} from 'vant';
+import { defineComponent, onMounted, reactive, watch } from 'vue';
+import styles from './index.module.less';
+
+export default defineComponent({
+  name: 'skeleton-modal',
+  props: {
+    show: {
+      type: Boolean,
+      default: false
+    },
+    showCount: {
+      type: Array,
+      default: () => [1, 2, 3, 4, 5]
+    }
+  },
+  setup(props, { slots }) {
+    const forms = reactive({
+      loading: false
+    });
+
+    onMounted(() => {
+      forms.loading = props.show;
+    });
+
+    watch(
+      () => props.show,
+      () => {
+        forms.loading = props.show;
+      }
+    );
+    return () => (
+      <Skeleton loading={forms.loading} style="flex-wrap: wrap">
+        {{
+          template: () => (
+            <div
+              style={{
+                height: `calc(100vh - var(--header-height))`,
+                overflow: 'hidden',
+                width: '100%'
+              }}>
+              {props.showCount.map(() => (
+                <CellGroup
+                  class={styles['data-content']}
+                  border={false}>
+                  <Cell center>
+                    {{
+                      title: () => (
+                        <div class={styles.teacher_info}>
+                          <SkeletonAvatar class={styles.logo} />
+                          <p class={styles.userName} style={{ width: '100px' }}><SkeletonParagraph rowWidth={'50%'} /></p>
+                        </div>
+                      ),
+                      default: () => (
+                        <p class={styles.orchestraName}>
+                          <SkeletonParagraph />
+                        </p>
+                      )
+                    }}
+                  </Cell>
+                  <Cell isLink clickable={false} center>
+                    {{
+                      title: () => (
+                        <Grid border={false} columnNum={4} clickable>
+                          <GridItem>
+                            {{
+                              text: () => <SkeletonParagraph rowWidth={'50%'} />
+                            }}
+                          </GridItem>
+                          <GridItem>
+                            {{
+                              text: () => <SkeletonParagraph rowWidth={'50%'} />
+                            }}
+                          </GridItem>
+                          <GridItem>
+                            {{
+                              text: () => <SkeletonParagraph rowWidth={'50%'} />
+                            }}
+                          </GridItem>
+                          <GridItem>
+                            {{
+                              text: () => <SkeletonParagraph rowWidth={'50%'} />
+                            }}
+                          </GridItem>
+                        </Grid>
+                      )
+                    }}
+                  </Cell>
+                </CellGroup>
+              ))}
+            </div>
+          ),
+          default: () => slots.default && slots.default()
+        }}
+      </Skeleton>
+    );
+  }
+});

+ 171 - 0
src/views/train-statistics/train-detail.module.less

@@ -0,0 +1,171 @@
+.trainDetail {
+  background: #f5f5f5;
+  min-height: 100vh;
+  overflow: hidden;
+}
+
+.evaluation {
+  display: flex;
+  align-items: center;
+  margin: 12px 12px 0;
+  height: 105px;
+  border-radius: 10px;
+  background: url('./images/user_bg.png') no-repeat center #fff;
+  background-size: contain;
+
+  .teacher_info {
+    display: flex;
+    align-items: center;
+
+    img {
+      margin-right: 15px;
+      width: 60px;
+      height: 60px;
+      border-radius: 50%;
+    }
+
+    .username {
+      color: #1a1a1a;
+      font-size: 18px;
+    }
+
+    .musicGroupName {
+      font-size: 14px;
+      color: #333;
+      white-space: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      width: 240px;
+    }
+  }
+}
+
+.search-icon {
+  display: flex;
+  align-items: center;
+}
+
+.scoreImg {
+  width: 66px;
+  height: 25px;
+}
+
+.data-content {
+  margin: 15px 15px 0;
+  border-radius: 10px;
+  overflow: hidden;
+
+  &:first-child {
+    margin-top: 0;
+  }
+
+  .van-row-item {
+    display: flex;
+    align-items: center;
+  }
+
+  :global {
+    .van-grid-item__content {
+      padding: 3px
+    }
+
+    .van-grid-item__content {
+      background-color: transparent;
+    }
+
+    .van-grid-item__icon-wrapper {
+      font-size: 15px;
+      font-weight: 500;
+      color: #000;
+    }
+
+    .van-grid-item__text {
+      padding-top: 3px;
+      font-size: 12px;
+      color: #808080;
+    }
+  }
+
+  .teacher_info {
+    display: flex;
+    align-items: center;
+
+    img {
+      margin-right: 10px;
+      width: 40px;
+      height: 40px;
+      border-radius: 50%;
+    }
+  }
+
+  .scoreName {
+    font-size: 17px;
+    color: #333333;
+    font-weight: 500;
+    padding-right: 5px;
+    padding-bottom: 5px;
+  }
+}
+
+// .specialList {
+//   padding-top: 10px;
+
+//   // padding-bottom: calc(env(safe-area-inset-bottom) / 2);
+//   &.bottomHeight {
+//     padding-bottom: 65px;
+//   }
+// }
+
+.dataSearch {
+  padding: 12px 12px 5px;
+  background-color: #F5F5F5;
+
+  :global {
+    .van-cell {
+      background: #fff;
+      padding: 0 16px;
+      border-radius: 10px;
+      overflow: hidden;
+      height: 27px;
+      line-height: 27px;
+    }
+
+    .van-cell__value--alone {
+      text-align: center;
+    }
+  }
+
+  .flexCenter {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+
+  .btn-search {
+    background: #01C1B5;
+    font-size: 14px;
+    color: #fff;
+    padding: 3px 9px;
+    border-radius: 15px;
+    margin-left: 5px;
+  }
+}
+
+.button-group {
+  overflow: hidden;
+  position: fixed;
+  bottom: 0;
+  width: calc(100% - 24px);
+  z-index: 9;
+  margin: 0 12px 12px;
+
+  .van-button--primary {
+    background: #01C1B5;
+    border: 1px solid #01C1B5;
+    font-size: 16px;
+    float: right;
+    // padding-bottom: calc(env(safe-area-inset-bottom) / 2);
+    height: auto;
+    line-height: 48px;
+  }
+}

+ 403 - 0
src/views/train-statistics/train-detail.tsx

@@ -0,0 +1,403 @@
+import { defineComponent, onMounted, reactive } from 'vue';
+import styles from './train-detail.module.less';
+import MSticky from '@/components/m-sticky';
+import MHeader from '@/components/m-header';
+import {
+  Cell,
+  CellGroup,
+  Col,
+  DatePicker,
+  Grid,
+  GridItem,
+  Icon,
+  List,
+  Popup,
+  Row,
+  showToast
+} from 'vant';
+import icon_student from '@common/images/icon-student-default.png';
+import arrowIcon from './images/arrow_down.png';
+import score1 from './images/1.png';
+import score2 from './images/2.png';
+import score3 from './images/3.png';
+import { useRoute } from 'vue-router';
+import { formatterDatePicker } from '@/helpers/utils';
+import dayjs from 'dayjs';
+import MFullRefresh from '@/components/m-full-refresh';
+import request from '@/helpers/request';
+import MEmpty from '@/components/m-empty';
+import SkeletionDetailModal from './skeletion-detail-modal';
+
+export default defineComponent({
+  name: 'train-detail',
+  setup() {
+    const route = useRoute();
+    const state = reactive({
+      headerStatus: true,
+      show: true,
+      avatar: route.query.avatar as any,
+      username: route.query.username as any,
+      musicGroupName: route.query.musicGroupName as any,
+      visitFlag: Number(route.query.visitFlag) || 0,
+      dataForm: {
+        // 时间下拉框
+        type: null as any,
+        status: false,
+        minDate: new Date(2000, 0, 1),
+        maxDate: new Date(2030, 11, 31),
+        currentDate: [
+          dayjs().format('YYYY'),
+          dayjs().format('MM'),
+          dayjs().format('DD')
+        ] as any
+      },
+      dataList: [],
+      loading: false,
+      finished: false
+    });
+    const forms = reactive({
+      isClick: false,
+      listState: {
+        dataShow: true, // 判断是否有数据
+        loading: true,
+        finished: false,
+        refreshing: false
+      },
+      params: {
+        startTime: null as any,
+        endTime: null as any,
+        userId: route.query.userId as any,
+        page: 1,
+        rows: 20
+      },
+      list: []
+    });
+
+    const onChangeDate = (type: string) => {
+      if (type == 'showEnd' && forms.params.startTime) {
+        state.dataForm.minDate = new Date(
+          dayjs(forms.params.startTime).valueOf()
+        );
+        state.dataForm.maxDate = new Date(2030, 11, 31);
+        setTimeout(() => {
+          state.dataForm.currentDate = forms.params.endTime
+            ? new Date(dayjs(forms.params.endTime).valueOf())
+            : new Date();
+        }, 500);
+      } else if (type == 'showStart' && forms.params.endTime) {
+        state.dataForm.minDate = new Date(2000, 0, 1);
+        state.dataForm.maxDate = new Date(
+          dayjs(forms.params.endTime).valueOf()
+        );
+        setTimeout(() => {
+          state.dataForm.currentDate = forms.params.startTime
+            ? new Date(dayjs(forms.params.startTime).valueOf())
+            : new Date();
+        }, 500);
+      }
+      state.dataForm.status = true;
+      state.dataForm.type = type;
+    };
+
+    const getList = async () => {
+      try {
+        if (forms.isClick) return;
+        forms.isClick = true;
+        const { data } = await request.get(
+          '/api-web/schoolCloudStudy/queryMusicCompareRecord',
+          {
+            params: {
+              ...forms.params
+            }
+          }
+        );
+        const result = data || {};
+        // 判断是否有数据
+        if (forms.listState.refreshing) {
+          forms.list = result.rows || [];
+        } else {
+          forms.list = forms.list.concat(result.rows || []);
+        }
+
+        forms.listState.finished = result.pageNo >= result.totalPage;
+        forms.params.page = result.pageNo + 1;
+      } catch {
+        forms.listState.finished = true;
+      } finally {
+        setTimeout(() => {
+          forms.listState.dataShow = forms.list.length > 0;
+          forms.listState.refreshing = false;
+          forms.listState.loading = false;
+          forms.isClick = false;
+        }, 500);
+      }
+    };
+
+    const getLevelByScore = (score: number) => {
+      let level = 3;
+      if (score > 60 && score <= 80) {
+        level = 2;
+      } else if (score > 80) {
+        level = 1;
+      }
+      return level;
+    };
+    const onRefresh = () => {
+      forms.params.page = 1;
+      getList();
+    };
+
+    const onResetList = () => {
+      forms.list = [];
+      forms.params.page = 1;
+      forms.listState.dataShow = true;
+      forms.listState.loading = true;
+      forms.listState.finished = false;
+      forms.listState.refreshing = true;
+      onRefresh();
+    };
+
+    const showDetail = (item: any) => {
+      if (item.notesDataIndex > 0) {
+        postMessage({
+          api: 'openWebView',
+          content: {
+            url: location.origin + `/accompany/#/report/${item.id}`,
+            orientation: 0,
+            isHideTitle: true,
+            statusBarTextColor: false,
+            isOpenLight: true
+          }
+        });
+      } else {
+        showToast('本次评测未生成报告');
+      }
+    };
+
+    onMounted(() => {
+      getList();
+    });
+
+    return () => (
+      <div class={styles.trainDetail}>
+        <MSticky position="top">
+          <MHeader />
+
+          <div style={{ backgroundColor: '#f5f5f5', overflow: 'hidden' }}>
+            <div class={styles.evaluation}>
+              <Cell
+                style="padding: 16px 12px; background-color: transparent"
+                center>
+                {{
+                  title: () => (
+                    <div class={styles.teacher_info}>
+                      <img
+                        class={styles.logo}
+                        src={state.avatar || icon_student}
+                        alt=""
+                      />
+                      <div class={styles.teacher_content}>
+                        <p class={styles.username}>{state.username}</p>
+                        <p class={styles.musicGroupName}>
+                          {state.musicGroupName}
+                        </p>
+                      </div>
+                    </div>
+                  )
+                }}
+              </Cell>
+            </div>
+
+            {!state.visitFlag && (
+              <Row class={styles.dataSearch} align="center" justify="center">
+                <Col span={9} offset={1}>
+                  <Cell isLink onClick={() => onChangeDate('showStart')}>
+                    {{
+                      'right-icon': () => (
+                        <Icon
+                          name={arrowIcon}
+                          class={styles['search-icon']}
+                          size={10}
+                        />
+                      ),
+                      title: () =>
+                        forms.params.startTime ? (
+                          forms.params.startTime
+                        ) : (
+                          <span style={{ color: '#adadad' }}>开始日期</span>
+                        )
+                    }}
+                  </Cell>
+                </Col>
+                <Col span={1} style={{ 'text-align': 'center' }}>
+                  -
+                </Col>
+                <Col span={9}>
+                  <Cell onClick={() => onChangeDate('showEnd')}>
+                    {{
+                      'right-icon': () => (
+                        <Icon
+                          name={arrowIcon}
+                          class={styles['search-icon']}
+                          size={10}
+                        />
+                      ),
+                      title: () =>
+                        forms.params.endTime ? (
+                          forms.params.endTime
+                        ) : (
+                          <span style={{ color: '#adadad' }}>结束日期</span>
+                        )
+                    }}
+                  </Cell>
+                </Col>
+                <Col span={4}>
+                  {/* onSearch */}
+                  <span
+                    class={styles['btn-search']}
+                    onClick={() => onResetList()}>
+                    搜索
+                  </span>
+                </Col>
+              </Row>
+            )}
+          </div>
+        </MSticky>
+
+        <Popup v-model:show={state.dataForm.status} position="bottom" round>
+          <DatePicker
+            v-model={state.dataForm.currentDate}
+            formatter={formatterDatePicker}
+            minDate={state.dataForm.minDate}
+            maxDate={state.dataForm.maxDate}
+            onCancel={() => (state.dataForm.status = false)}
+            onConfirm={({ selectedValues }) => {
+              let dataForm = state.dataForm;
+              if (dataForm.type == 'showStart') {
+                forms.params.startTime = selectedValues.join('-');
+              } else if (dataForm.type == 'showEnd') {
+                forms.params.endTime = selectedValues.join('-');
+              }
+              state.dataForm.status = false;
+            }}
+          />
+        </Popup>
+
+        <SkeletionDetailModal v-model:show={forms.listState.loading}>
+          <MFullRefresh
+            v-model:modelValue={forms.listState.refreshing}
+            onRefresh={() => onRefresh()}
+            style={{
+              minHeight: `calc(100vh - var(--header-height))`
+            }}>
+            <List
+              finished={forms.listState.finished}
+              finishedText=" "
+              style={{ overflow: 'hidden', marginBottom: '18px' }}
+              onLoad={getList}
+              immediateCheck={false}>
+              {forms.listState.dataShow ? (
+                forms.list.map((item: any) => (
+                  <CellGroup
+                    class={styles['data-content']}
+                    border={false}
+                    onClick={() => showDetail(item)}>
+                    <Cell
+                      style={{ padding: '10px 12px 12px' }}
+                      border
+                      center
+                      title-style="flex-basis: 45%;">
+                      {{
+                        title: () => (
+                          <>
+                            <span class={styles.scoreName}>
+                              {item.sysMusicScoreName}
+                            </span>
+                            <p style="font-size: 14px; color: #808080;">
+                              {item.createTime}
+                            </p>
+                          </>
+                        ),
+                        value: () => (
+                          <p>
+                            {getLevelByScore(item.score) === 1 && (
+                              <img
+                                class={styles.scoreImg}
+                                src={score1}
+                                alt=""></img>
+                            )}
+                            {getLevelByScore(item.score) === 2 && (
+                              <img
+                                class={styles.scoreImg}
+                                src={score2}
+                                alt=""></img>
+                            )}
+                            {getLevelByScore(item.score) === 3 && (
+                              <img
+                                class={styles.scoreImg}
+                                src={score3}
+                                alt=""></img>
+                            )}
+                          </p>
+                        )
+                      }}
+                    </Cell>
+                    <Cell
+                      isLink
+                      clickable={false}
+                      center
+                      style="padding: 12px 12px 16px">
+                      {{
+                        title: () => (
+                          <Grid border={false} columnNum={4} clickable>
+                            <GridItem text="综合得分">
+                              {{ icon: () => <span>{item.score}分</span> }}
+                            </GridItem>
+                            <GridItem text="音准">
+                              {{
+                                icon: () => (
+                                  <span style="color: #01C1B5">
+                                    {item.intonation}分
+                                  </span>
+                                )
+                              }}
+                            </GridItem>
+                            <GridItem text="节奏">
+                              {{
+                                icon: () => (
+                                  <span style="color: #FF802C">
+                                    {item.cadence}分
+                                  </span>
+                                )
+                              }}
+                            </GridItem>
+                            <GridItem text="完成度">
+                              {{
+                                icon: () => (
+                                  <span style="color: #F79C00">
+                                    {item.integrity}分
+                                  </span>
+                                )
+                              }}
+                            </GridItem>
+                          </Grid>
+                        )
+                      }}
+                    </Cell>
+                  </CellGroup>
+                ))
+              ) : (
+                <MEmpty
+                  style={{
+                    minHeight: `calc(100vh - var(--header-height))`
+                  }}
+                  description="暂无训练详情"
+                />
+              )}
+            </List>
+          </MFullRefresh>
+        </SkeletionDetailModal>
+      </div>
+    );
+  }
+});

+ 146 - 0
src/views/train-statistics/train-model.module.less

@@ -0,0 +1,146 @@
+.trainModel {
+  :global {
+    .van-dropdown-menu__title::after {
+      border-color: transparent transparent #aaaaaa #aaaaaa;
+    }
+
+    .van-dropdown-menu__title--active::after {
+      border-color: transparent transparent #01c1b5 #01c1b5;
+    }
+
+    .van-dropdown-item__content {
+      border-radius: 0 0 12px 12px;
+      max-height: 100%;
+    }
+  }
+
+  .cellTitle {
+    font-size: 15px;
+    font-weight: 600;
+  }
+}
+
+.search-group {
+  max-height: 400px;
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+
+.calendarColor {
+  font-size: 15px;
+  color: #333333;
+}
+
+.studentCell {
+  padding: 18px 13px;
+}
+
+.visit-tips {
+  background-color: #fff;
+  // padding: 10px 10px 0;
+  padding: 10px 12px 0;
+  text-align: center;
+
+  span {
+    display: block;
+    padding: 6px 12px;
+    background-color: #fff6de;
+    font-size: 12px;
+    color: #ff802c;
+    text-align: left;
+  }
+}
+
+.searchArray {
+  font-size: 14px;
+  padding-top: 15px;
+  padding-bottom: 12px;
+  color: #1a1a1a;
+  background-color: #f5f5f5;
+}
+
+.title-style {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.box {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  margin-left: 2px;
+}
+
+.box-up {
+  width: 0;
+  height: 0;
+  border-left: 4px solid transparent;
+  border-right: 4px solid transparent;
+  border-bottom: 5px solid #ccc;
+
+  &.active {
+    border-bottom-color: #01c1b5;
+  }
+}
+
+.box-down {
+  width: 0;
+  height: 0;
+  border-left: 4px solid transparent;
+  border-right: 4px solid transparent;
+  border-top: 5px solid #ccc;
+
+  &.active {
+    border-top-color: #01c1b5;
+  }
+}
+
+.studentCell {
+  :global {
+    .van-cell__title {
+      flex-shrink: 0;
+      flex: auto;
+    }
+
+    .van-cell__value {
+      flex: 1 auto;
+    }
+  }
+}
+
+.btn-group {
+  display: flex;
+  align-items: center;
+  flex-wrap: wrap;
+  // gap: 0 10px;
+  margin: 0 -5px;
+
+  :global {
+    .van-button {
+      margin: 10px 5px 0;
+      padding: 0;
+      font-weight: 400;
+      font-size: 13px;
+      width: calc(33.3% - 10px);
+      height: 34px;
+    }
+
+    .van-button--default {
+      background: #f6f6f6;
+      border-color: #f6f6f6;
+    }
+  }
+}
+
+.submit-group {
+  padding: 14px 16px;
+  display: flex;
+
+  :global {
+    .van-button {
+      font-size: 16px;
+      height: 44px;
+    }
+  }
+}

+ 522 - 0
src/views/train-statistics/train-model.tsx

@@ -0,0 +1,522 @@
+import { computed, defineComponent, onMounted, reactive, ref } from "vue";
+import styles from './train-model.module.less'
+import MSearch from "@/components/m-search";
+import { Button, Calendar, Cell, Col, DropdownItem, DropdownMenu, Picker, Popup, Row, showToast } from "vant";
+import dayjs from "dayjs";
+import { musicGroupClassPage, musicGroupPage } from "./api";
+
+export function getNowDateAndMonday(time: any) {
+  let timestamp = new Date(time.replace(/-/g, "/")).getTime();
+  let serverDate = new Date(time);
+  if (serverDate.getDay() == 0) {
+    timestamp -= 7 * 24 * 60 * 60 * 1000;
+  }
+  let mondayTime = timestamp - (serverDate.getDay() - 1) * 24 * 60 * 60 * 1000;
+
+  let mondayData = new Date(mondayTime);
+  //年
+  let mondayY = mondayData.getFullYear();
+  //月
+  let mondayM =
+    mondayData.getMonth() + 1 < 10
+      ? "0" + (mondayData.getMonth() + 1)
+      : mondayData.getMonth() + 1;
+  //日
+  let mondayD =
+    mondayData.getDate() < 10
+      ? "0" + mondayData.getDate()
+      : mondayData.getDate();
+
+  let str = mondayY + "-" + mondayM + "-" + mondayD;
+  return str;
+}
+export function getNowDateAndSunday(time: any) {
+  let timestamp = new Date(time.replace(/-/g, "/")).getTime();
+  let serverDate = new Date(time);
+
+  let num = 7 - serverDate.getDay();
+  if (num == 7) {
+    num = 0;
+  }
+  let sundayTiem = timestamp + num * 24 * 60 * 60 * 1000;
+  let SundayData = new Date(sundayTiem);
+  //年
+  let tomorrowY = SundayData.getFullYear(); //月
+  let tomorrowM =
+    SundayData.getMonth() + 1 < 10
+      ? "0" + (SundayData.getMonth() + 1)
+      : SundayData.getMonth() + 1;
+  //日
+  let tomorrowD =
+    SundayData.getDate() < 10
+      ? "0" + SundayData.getDate()
+      : SundayData.getDate();
+  let str = tomorrowY + "-" + tomorrowM + "-" + tomorrowD;
+  return str;
+}
+
+
+export default defineComponent({
+  props: {
+    active: {
+      type: String,
+      default: 'all'
+    },
+    defaultTime: {
+      type: Number,
+      default: 0
+    },
+  },
+  name: 'train-model',
+  emits: ['load'],
+  setup(props, { emit }) {
+    const state = reactive({
+      showCalendar: false,
+      showMusicGroup: false,
+      musicGroupList: [] as any,
+      showClass: false,
+      classList: [] as any,
+      minDate: new Date(2000, 0, 1),
+      defaultDate: [] as any,
+      memberFlag: '',
+      studentType: '', // 1 -> musicFlag,2 -> hasEndVipFlag,3 -> hasNotStartVipFlag
+      // 类型为全部时
+      startDay: null as any,
+      endDay: null as any,
+      calendarStatus: false,
+      search: null,
+      searchArray: [null, null, null, null],
+      searchType: {
+        // ASC DESC
+        totalPlayTime: null,
+        trainNum: null,
+        trainDay: null,
+        recordNum: null
+      },
+      organId: '',
+      organName: '全部分部',
+      musicGroupId: '',
+      musicGroupName: '全部乐团',
+      classId: '',
+      className: '全部班级'
+    })
+    const dropDownRef = ref()
+    const calendarValue = computed(() => {
+      return `${dayjs(state.startDay).format('YYYY/MM/DD')} - ${dayjs(
+        state.endDay
+      ).format('YYYY/MM/DD')}`;
+    })
+
+    const onSetMusicGrouop = (val: any) => {
+      const option = val.selectedOptions[0]
+      state.musicGroupId = option.value;
+      state.musicGroupName = option.text;
+      state.showMusicGroup = false;
+      getClassList();
+    }
+   const onSetClass = (val: any) => {
+     const option = val.selectedOptions[0]
+     state.classId = option.value;
+     state.className = option.text;
+      state.showClass = false;
+    }
+
+     const  getOrchestraList = async () => {
+      try {
+        const { data } = await musicGroupPage({
+          organId: state.organId
+        });
+        const result = data || [];
+        const tempList = [
+          {
+            text: '全部乐团',
+            value: ''
+          }
+        ];
+        result.forEach((item: any) => {
+          tempList.push({
+            text: item.name,
+            value: item.id
+          });
+        });
+        state.musicGroupList = tempList;
+      } catch {
+        //
+      }
+    }
+    const getClassList = async () => {
+      try {
+        const { data } = await musicGroupClassPage({
+          organId: state.organId,
+          musicGroupId: state.musicGroupId
+        });
+        const result = data || [];
+        const tempList = [
+          {
+            text: '全部乐团',
+            value: ''
+          }
+        ];
+        result.forEach((item: any) => {
+          tempList.push({
+            text: item.name,
+            value: item.id
+          });
+        });
+        state.classList = tempList;
+      } catch {
+        //
+      }
+    }
+
+    const onCheckType = (type: string, value: string) => {
+      if (type === 'member') {
+        state.memberFlag = value;
+      } else if (type === 'type') {
+        state.studentType = value;
+      }
+    }
+
+    const onSort = (type?: any) => {
+      let searchArray: any = state.searchArray;
+      searchArray.forEach((item: any, index: any) => {
+        if (index != type) {
+          searchArray[index] = null;
+        }
+      });
+      if (searchArray[type] == 'ASC') {
+        searchArray[type] = 'DESC';
+      } else if (searchArray[type] == 'DESC') {
+        searchArray[type] = null;
+      } else {
+        searchArray[type] = 'ASC';
+      }
+      onAllFilter();
+    }
+
+    const onAllFilter = () => {
+      const searchArray = state.searchArray;
+      let currentIndex: any = null;
+      let currentType = null;
+      searchArray.forEach((item, index) => {
+        if (item) {
+          currentIndex = index;
+          currentType = item;
+        }
+      });
+      const searchType = ['totalPlayTime', 'trainNum', 'trainDay', 'recordNum'];
+      // 1 -> musicFlag,2 -> hasEndVipFlag,3 -> hasNotStartVipFlag
+      let params = {
+        search: state.search,
+        memberFlag: state.memberFlag,
+        musicFlag: state.studentType === '1' ? true : false,
+        hasEndVipFlag: state.studentType === '2' ? true : false,
+        hasNotStartVipFlag: state.studentType === '3' ? true : false,
+        startTime: state.startDay,
+        endTime: state.endDay,
+        classGroupId: state.classId,
+        musicGroupId: state.musicGroupId,
+        organId: state.organId,
+        page: 1,
+        sort: searchType[currentIndex],
+        order: currentType
+      };
+      emit('load', params);
+    }
+
+    const changeDropDownItemStatus = () => {
+      dropDownRef.value?.toggle(false);
+    }
+    const onSubmit = () => {
+      changeDropDownItemStatus();
+      onAllFilter();
+    }
+    const onReset = () => {
+      let defaultTime = props.defaultTime;
+      let day = defaultTime * 7;
+      let startTime: any = new Date(),
+        endTime: any = new Date();
+      if (day > 0) {
+        startTime = getNowDateAndMonday(
+          dayjs().add(day, 'day').format('YYYY-MM-DD')
+        );
+        endTime = getNowDateAndSunday(
+          dayjs().add(day, 'day').format('YYYY-MM-DD')
+        );
+      } else {
+        startTime = getNowDateAndMonday(
+          dayjs().subtract(Math.abs(day), 'day').format('YYYY-MM-DD')
+        );
+        endTime = getNowDateAndSunday(
+          dayjs().subtract(Math.abs(day), 'day').format('YYYY-MM-DD')
+        );
+      }
+      state.defaultDate = [new Date(startTime), new Date(endTime)];
+      state.startDay = startTime;
+      state.endDay = endTime;
+      state.memberFlag = "";
+      state.studentType = "";
+      state.musicGroupId = "";
+      state.musicGroupName = "全部乐团";
+      state.classId = "";
+      state.className = "全部班级";
+      onSubmit();
+    }
+
+    const selectDate = (date: any) => {
+      let [start, end] = date;
+      if (start) {
+        const num = dayjs(start).get('day');
+        if (num === 0) {
+          start = dayjs(start).subtract(6, 'day');
+        } else {
+          start = dayjs(start).subtract(num - 1, 'day');
+        }
+      }
+      if (start) {
+        const num = 7 - dayjs(start).get('day');
+        if (num < 7) {
+          end = dayjs(start).add(num, 'day');
+        }
+      }
+      state.defaultDate = [new Date(start.valueOf()), new Date(end.valueOf())];
+    }
+    const onConfirm = (date: any) => {
+      let [start, end] = date;
+      state.showCalendar = false;
+      if (start) {
+        const num = dayjs(start).get('day');
+        if (num === 0) {
+          start = dayjs(start).subtract(6, 'day');
+        } else {
+          start = dayjs(start).subtract(num - 1, 'day');
+        }
+      }
+      if (end) {
+        const num = 7 - dayjs(end).get('day');
+        if (num < 7) {
+          end = dayjs(end).add(num, 'day');
+        }
+      }
+      state.calendarStatus = true
+      state.startDay = dayjs(start).format('YYYY-MM-DD');
+      state.endDay = dayjs(end).format('YYYY-MM-DD');
+      //
+      //   this.changeDropDownItemStatus();
+      //   this.onAllFilter();
+    }
+
+    onMounted(() => {
+      let defaultTime = props.defaultTime;
+      let day = defaultTime * 7;
+      let startTime: any = new Date(),
+        endTime: any = new Date();
+      if (day > 0) {
+        startTime = getNowDateAndMonday(
+          dayjs().add(day, 'day').format('YYYY-MM-DD')
+        );
+        endTime = getNowDateAndSunday(
+          dayjs().add(day, 'day').format('YYYY-MM-DD')
+        );
+      } else {
+        startTime = getNowDateAndMonday(
+          dayjs().subtract(Math.abs(day), 'day').format('YYYY-MM-DD')
+        );
+        endTime = getNowDateAndSunday(
+          dayjs().subtract(Math.abs(day), 'day').format('YYYY-MM-DD')
+        );
+      }
+      state.defaultDate = [new Date(startTime), new Date(endTime)];
+      state.startDay = startTime;
+      state.endDay = endTime;
+
+      onSort();
+      getOrchestraList()
+    })
+    return () => <div class={styles.trainModel}>
+      <MSearch placeholder="学生姓名或手机号"
+        // disabled={forms.listState.refreshing}
+        onSearch={(val: string) => {
+          // forms.params.keyword = val;
+          // forms.listState.refreshing = true;
+          // onRefresh();
+        }}>
+        {{
+          left: () => (
+            <DropdownMenu
+              class={styles.patrolDetailDropDown}
+              style={{ 'padding-right': '10px' }}
+              closeOnClickOutside={false}>
+              <DropdownItem title={'筛选'} ref={dropDownRef} >
+                <div class="search-group">
+                  <Cell title={'日期'}
+                    isLink
+                    onClick={() => {state.showCalendar = true
+                      state.calendarStatus = false
+                    }}
+                    titleClass={styles.cellTitle}
+                    value={calendarValue.value}
+                    valueClass={styles.calendarColor}
+                    class={styles.studentCell}></Cell>
+                  <Cell title={'是否学员'} titleClass={styles.cellTitle} class={styles.studentCell}>
+                    {{
+                      label: () => <div class={styles['btn-group']}>
+                        <Button plain={state.memberFlag === ''}
+                          round
+                          type={state.memberFlag === '' ? 'primary' : 'default'}
+                          onClick={() => onCheckType('member', '')}>
+                          全部学员
+                        </Button>
+                        <Button plain={state.memberFlag === '1'}
+                          round
+                          type={state.memberFlag === '1' ? 'primary' : 'default'}
+                          onClick={() => onCheckType('member', '1')}>
+                          会员学员
+                        </Button>
+                        <Button plain={state.memberFlag === '0'}
+                          round
+                          type={state.memberFlag === '0' ? 'primary' : 'default'}
+                          onClick={() => onCheckType('member', '0')}>
+                          普通学员
+                        </Button>
+                      </div>
+                    }}
+                  </Cell>
+                  <Cell title={'是否学员'} titleClass={styles.cellTitle} class={styles.studentCell}>
+                    {{
+                      label: () => <div class={styles['btn-group']}>
+                        <Button plain={state.studentType === ''}
+                          round
+                          type={state.studentType === '' ? 'primary' : 'default'}
+                          onClick={() => onCheckType('type', '')}>
+                          全部学员
+                        </Button>
+                        <Button plain={state.studentType === '1'}
+                          round
+                          type={state.studentType === '1' ? 'primary' : 'default'}
+                          onClick={() => onCheckType('type', '1')}>
+                          乐团学员
+                        </Button>
+                        <Button plain={state.studentType === '2'}
+                          round
+                          type={state.studentType === '2' ? 'primary' : 'default'}
+                          onClick={() => onCheckType('type', '2')}>
+                          已结束小课学员
+                        </Button>
+                        <Button plain={state.studentType === '3'}
+                          round
+                          type={state.studentType === '3' ? 'primary' : 'default'}
+                          onClick={() => onCheckType('type', '3')}>
+                          进行中小课学员
+                        </Button>
+                      </div>
+                    }}
+                  </Cell>
+                  <Cell title={'乐团'}
+                    isLink
+                    onClick={() => state.showMusicGroup = true}
+                    titleClass={styles.cellTitle}
+                    value={state.musicGroupName}
+                    valueClass={styles.calendarColor}
+                    class={styles.studentCell}></Cell>
+                  <Cell title={'班级'}
+                    isLink
+                    onClick={() => {
+                      if (!state.musicGroupId) {
+                        showToast('请选择乐团');
+                        return;
+                      }
+                      state.showClass = true
+                    }}
+                    titleClass={styles.cellTitle}
+                    value={state.className}
+                    valueClass={styles.calendarColor}
+                    class={styles.studentCell}></Cell>
+                </div>
+                <div class={[styles['submit-group'], 'van-hairline--top']}>
+                  <Button round block onClick={onReset} style={{ marginRight: '10px' }}>
+                    重置
+                  </Button>
+                  <Button type="primary" round block onClick={onSubmit}>
+                    确认
+                  </Button>
+                </div>
+              </DropdownItem>
+            </DropdownMenu>
+          )
+        }}
+      </MSearch>
+      <Row class={styles.searchArray}>
+        <Col span="6" class={styles['title-style']} onClick={() => onSort(0)}>
+          训练时长
+          <div>
+            <i
+              class={[styles['box'], styles["box-up"], state.searchArray[0] == 'ASC' && styles.active]}
+              style="margin-bottom: 0.03rem"
+            ></i>
+            <i
+              class={[styles['box'], styles['box-down'], state.searchArray[0] === 'DESC' && styles.active]}
+            ></i>
+          </div>
+        </Col  >
+        <Col span="6" class={styles['title-style']} onClick={() => onSort(1)} >
+          训练次数
+          <div>
+            <i
+              class={[styles['box'], styles["box-up"], state.searchArray[1] == 'ASC' && styles.active]}
+              style="margin-bottom: 0.03rem"
+            ></i>
+            <i
+              class={[styles['box'], styles['box-down'], state.searchArray[1] === 'DESC' && styles.active]}
+            ></i>
+          </div>
+        </Col>
+        <Col span="6" class={styles['title-style']} onClick={() => onSort(2)} >
+          训练天数
+          <div>
+            <i
+              class={[styles['box'], styles["box-up"], state.searchArray[2] == 'ASC' && styles.active]}
+              style="margin-bottom: 0.03rem"
+            ></i>
+            <i
+              class={[styles['box'], styles['box-down'], state.searchArray[2] === 'DESC' && styles.active]}
+            ></i>
+          </div>
+        </Col>
+        <Col span="6" class={styles['title-style']} onClick={() => onSort(3)} >
+          评测次数
+          <div>
+            <i
+              class={[styles['box'], styles["box-up"], state.searchArray[3] == 'ASC' && styles.active]}
+              style="margin-bottom: 0.03rem"
+            ></i>
+            <i
+              class={[styles['box'], styles['box-down'], state.searchArray[3] === 'DESC' && styles.active]}
+            ></i>
+          </div>
+        </Col>
+      </Row>
+
+      <Calendar v-model:show={state.showCalendar}
+        minDate={state.minDate}
+        defaultDate={state.defaultDate}
+        firstDayOfWeek={1} color="#01c1b5" type="range"
+        onSelect={selectDate}
+        onConfirm={onConfirm}
+        onUpdate:show={(val: any) => {
+          console.log('1111')
+          if (!state.calendarStatus) {
+            state.defaultDate = [new Date(state.startDay), new Date(state.endDay)];
+          }
+        }} />
+
+        <Popup v-model:show={state.showMusicGroup} position="bottom" round>
+        <Picker columns={state.musicGroupList} showToolbar onCancel={() => state.showMusicGroup = false} onConfirm={onSetMusicGrouop} />
+        </Popup>
+
+        <Popup v-model:show={state.showClass} position="bottom" round>
+        <Picker columns={state.classList} showToolbar onCancel={() => state.showClass = false} onConfirm={onSetClass} />
+        </Popup>
+    </div>
+  }
+})

+ 1 - 1
vite.config.ts

@@ -13,7 +13,7 @@ function resolve(dir: string) {
 }
 // https://vitejs.dev/config/
 // https://github.com/vitejs/vite/issues/1930 .env
-const proxyUrl = 'https://test.dayaedu.com/';
+const proxyUrl = 'https://dev.dayaedu.com/';
 export default defineConfig({
   base: './',
   plugins: [