|
@@ -1,372 +1,503 @@
|
|
|
-import { defineComponent, onMounted, reactive, ref } from 'vue';
|
|
|
-import styles from '../index.module.less';
|
|
|
-import {
|
|
|
- NButton,
|
|
|
- NDataTable,
|
|
|
- NForm,
|
|
|
- NFormItem,
|
|
|
- NGi,
|
|
|
- NGrid,
|
|
|
- NImage,
|
|
|
- NModal,
|
|
|
- NNumberAnimation,
|
|
|
- NSelect,
|
|
|
- NSpace
|
|
|
-} from 'naive-ui';
|
|
|
-import SearchInput from '@/components/searchInput';
|
|
|
-import CSelect from '@/components/CSelect';
|
|
|
-import Pagination from '@/components/pagination';
|
|
|
-import add from './images/add.png';
|
|
|
-import {
|
|
|
- getNowDateAndMonday,
|
|
|
- getNowDateAndSunday,
|
|
|
- getTimes,
|
|
|
- getMinutes,
|
|
|
- getSecend
|
|
|
-} from '/src/utils/dateFormat';
|
|
|
-import { getTestList, getTrainingStat } from '../api';
|
|
|
-import CDatePicker from '/src/components/CDatePicker';
|
|
|
-import { useRoute, useRouter } from 'vue-router';
|
|
|
-import TheEmpty from '/src/components/TheEmpty';
|
|
|
-import { initCache, setCache } from '/src/hooks/use-async';
|
|
|
-
|
|
|
-export default defineComponent({
|
|
|
- name: 'student-studentList',
|
|
|
- setup(props, { emit }) {
|
|
|
- const state = reactive({
|
|
|
- searchForm: {
|
|
|
- keyword: '',
|
|
|
- trainingStatus: null as any,
|
|
|
- vipFlag: '' as any
|
|
|
- },
|
|
|
- searchWord: '',
|
|
|
- orchestraType: null,
|
|
|
- courseTypeCode: null,
|
|
|
- subjectId: null,
|
|
|
- classId: null,
|
|
|
- studentType: null,
|
|
|
- loading: false,
|
|
|
- pagination: {
|
|
|
- page: 1,
|
|
|
- rows: 10,
|
|
|
- pageTotal: 4
|
|
|
- },
|
|
|
- tableList: [] as any,
|
|
|
- memberNumber: 0,
|
|
|
- testInfo: {
|
|
|
- practiceDurationAvg: 0,
|
|
|
- vipUserCount: 0,
|
|
|
- practiceUserCount: 0
|
|
|
- },
|
|
|
- activeRow: null
|
|
|
- });
|
|
|
- const route = useRoute();
|
|
|
- const router = useRouter();
|
|
|
- const search = () => {
|
|
|
- state.pagination.page = 1;
|
|
|
- getInfo();
|
|
|
- getList();
|
|
|
- setCache({
|
|
|
- current: { ...state.searchForm, timer: timer.value },
|
|
|
- saveKey: 'classDetailTestRecord'
|
|
|
- });
|
|
|
- };
|
|
|
- const timer = ref<[number, number]>([
|
|
|
- getNowDateAndMonday(new Date().getTime()),
|
|
|
- getNowDateAndSunday(new Date().getTime())
|
|
|
- ]);
|
|
|
- const onReset = () => {
|
|
|
- timer.value = [
|
|
|
- getNowDateAndMonday(new Date().getTime()),
|
|
|
- getNowDateAndSunday(new Date().getTime())
|
|
|
- ];
|
|
|
- state.searchForm = {
|
|
|
- keyword: '',
|
|
|
- trainingStatus: null as any,
|
|
|
- vipFlag: ''
|
|
|
- };
|
|
|
- search();
|
|
|
- setCache({
|
|
|
- current: { ...state.searchForm, timer: timer.value },
|
|
|
- saveKey: 'classDetailTestRecord'
|
|
|
- });
|
|
|
- };
|
|
|
-
|
|
|
- initCache({
|
|
|
- current: { ...state.searchForm, timer: timer.value },
|
|
|
- saveKey: 'classDetailTestRecord',
|
|
|
- callBack: (active: any) => {
|
|
|
- state.searchForm = active;
|
|
|
- timer.value = active.timer;
|
|
|
- }
|
|
|
- });
|
|
|
- const getList = async () => {
|
|
|
- state.loading = true;
|
|
|
- try {
|
|
|
- const res = await getTestList({
|
|
|
- classGroupId: route.query.id,
|
|
|
- ...state.searchForm,
|
|
|
- ...state.pagination,
|
|
|
- ...getTimes(timer.value, ['startTime', 'endTime'], 'YYYY-MM-DD')
|
|
|
- });
|
|
|
-
|
|
|
- state.tableList = res.data.rows;
|
|
|
-
|
|
|
- state.pagination.pageTotal = res.data.total;
|
|
|
- state.loading = false;
|
|
|
- } catch (e) {
|
|
|
- state.loading = false;
|
|
|
- console.log(e);
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- const getInfo = async () => {
|
|
|
- try {
|
|
|
- const res = await getTrainingStat({
|
|
|
- classGroupId: route.query.id,
|
|
|
- ...getTimes(timer.value, ['startTime', 'endTime'], 'YYYY-MM-DD')
|
|
|
- });
|
|
|
- state.testInfo.practiceDurationAvg = res.data.practiceDurationAvg;
|
|
|
- state.testInfo.practiceUserCount = res.data.practiceUserCount;
|
|
|
- state.testInfo.vipUserCount = res.data.vipUserCount;
|
|
|
- } catch (e) {
|
|
|
- console.log(e);
|
|
|
- }
|
|
|
- };
|
|
|
- onMounted(() => {
|
|
|
- getInfo();
|
|
|
- getList();
|
|
|
- });
|
|
|
- const gotoStudentDetail = (row: any) => {
|
|
|
- router.push({
|
|
|
- path: '/classStudentRecode',
|
|
|
- query: {
|
|
|
- ...route.query,
|
|
|
- studentId: row.studentId,
|
|
|
- studentName: row.studentName
|
|
|
- }
|
|
|
- });
|
|
|
- };
|
|
|
- const columns = () => {
|
|
|
- return [
|
|
|
- {
|
|
|
- title: '学生姓名',
|
|
|
- key: 'studentName'
|
|
|
- },
|
|
|
- {
|
|
|
- title: '手机号',
|
|
|
- key: 'studentPhone'
|
|
|
- },
|
|
|
- {
|
|
|
- title: '性别',
|
|
|
- key: 'sex',
|
|
|
- render(row: any) {
|
|
|
- return (
|
|
|
- <>
|
|
|
- {row.gender + '' != 'null'
|
|
|
- ? row.gender == '0'
|
|
|
- ? '女'
|
|
|
- : '男'
|
|
|
- : '--'}
|
|
|
- </>
|
|
|
- );
|
|
|
- }
|
|
|
- },
|
|
|
- {
|
|
|
- title: '学生类型',
|
|
|
- key: 'studentType',
|
|
|
- render(row: any) {
|
|
|
- return <>{row.vipFlag ? '会员' : '普通'}</>;
|
|
|
- }
|
|
|
- },
|
|
|
- {
|
|
|
- title: '练习天数',
|
|
|
- key: 'practiceDays',
|
|
|
- render(row: any) {
|
|
|
- return <>{row.practiceDays ? row.practiceDays : 0}天</>;
|
|
|
- }
|
|
|
- },
|
|
|
- {
|
|
|
- title: '学练时长',
|
|
|
- key: 'studentType',
|
|
|
- render(row: any) {
|
|
|
- return (
|
|
|
- <>
|
|
|
- {row.practiceDuration
|
|
|
- ? getMinutes(row.practiceDuration) > 0
|
|
|
- ? getMinutes(row.practiceDuration) +
|
|
|
- '分' +
|
|
|
- getSecend(row.practiceDuration) +
|
|
|
- '秒'
|
|
|
- : getSecend(row.practiceDuration) + '秒'
|
|
|
- : 0 + '秒'}
|
|
|
- </>
|
|
|
- );
|
|
|
- }
|
|
|
- },
|
|
|
- {
|
|
|
- title: '操作',
|
|
|
- key: 'id',
|
|
|
- render(row: any) {
|
|
|
- return (
|
|
|
- <NButton
|
|
|
- text
|
|
|
- type="primary"
|
|
|
- onClick={() => {
|
|
|
- gotoStudentDetail(row);
|
|
|
- }}>
|
|
|
- 详情
|
|
|
- </NButton>
|
|
|
- );
|
|
|
- }
|
|
|
- }
|
|
|
- ];
|
|
|
- };
|
|
|
- return () => (
|
|
|
- <div>
|
|
|
- <div class={styles.searchList}>
|
|
|
- <NForm label-placement="left" inline>
|
|
|
- <NFormItem>
|
|
|
- <SearchInput
|
|
|
- {...{ placeholder: '请输入学生姓名' }}
|
|
|
- class={styles.searchInput}
|
|
|
- searchWord={state.searchForm.keyword}
|
|
|
- onChangeValue={(val: string) =>
|
|
|
- (state.searchForm.keyword = val)
|
|
|
- }></SearchInput>
|
|
|
- </NFormItem>
|
|
|
-
|
|
|
- <NFormItem>
|
|
|
- <CSelect
|
|
|
- {...({
|
|
|
- options: [
|
|
|
- {
|
|
|
- label: '全部类型',
|
|
|
- value: ''
|
|
|
- },
|
|
|
- {
|
|
|
- label: '会员',
|
|
|
- value: true
|
|
|
- },
|
|
|
- {
|
|
|
- label: '普通',
|
|
|
- value: false
|
|
|
- }
|
|
|
- ],
|
|
|
- placeholder: '学生类型',
|
|
|
- clearable: true,
|
|
|
- inline: true
|
|
|
- } as any)}
|
|
|
- v-model:value={state.searchForm.vipFlag}></CSelect>
|
|
|
- </NFormItem>
|
|
|
- <NFormItem>
|
|
|
- <CDatePicker
|
|
|
- v-model:value={timer.value}
|
|
|
- separator={'至'}
|
|
|
- type="daterange"
|
|
|
- timerValue={timer.value}></CDatePicker>
|
|
|
- </NFormItem>
|
|
|
- <NFormItem>
|
|
|
- <NSpace justify="end">
|
|
|
- <NButton type="primary" class="searchBtn" onClick={search}>
|
|
|
- 搜索
|
|
|
- </NButton>
|
|
|
- <NButton
|
|
|
- type="primary"
|
|
|
- ghost
|
|
|
- class="resetBtn"
|
|
|
- onClick={onReset}>
|
|
|
- 重置
|
|
|
- </NButton>
|
|
|
- </NSpace>
|
|
|
- </NFormItem>
|
|
|
- </NForm>
|
|
|
- </div>
|
|
|
- <div class={['section-container']}>
|
|
|
- <NGrid x-gap="12" cols={8}>
|
|
|
- <NGi>
|
|
|
- <div class={styles.TrainDataItem}>
|
|
|
- <div>
|
|
|
- <p class={styles.TrainDataItemTitle}>
|
|
|
- <div>
|
|
|
- <span>
|
|
|
- <NNumberAnimation
|
|
|
- from={0}
|
|
|
- to={
|
|
|
- state.testInfo.practiceUserCount
|
|
|
- }></NNumberAnimation>
|
|
|
- </span>{' '}
|
|
|
- 人
|
|
|
- </div>
|
|
|
- </p>
|
|
|
- </div>
|
|
|
- <p class={styles.TrainDataItemsubTitle}>练习人数</p>
|
|
|
- </div>
|
|
|
- </NGi>
|
|
|
- <NGi>
|
|
|
- <div class={styles.TrainDataItem}>
|
|
|
- <p class={styles.TrainDataItemTitle}>
|
|
|
- <div>
|
|
|
- <span>
|
|
|
- <NNumberAnimation
|
|
|
- from={0}
|
|
|
- to={state.testInfo.vipUserCount}></NNumberAnimation>
|
|
|
- </span>{' '}
|
|
|
- 人
|
|
|
- </div>
|
|
|
- </p>
|
|
|
- <p class={styles.TrainDataItemsubTitle}>会员人数</p>
|
|
|
- </div>
|
|
|
- </NGi>
|
|
|
- <NGi>
|
|
|
- <div class={styles.TrainDataItem}>
|
|
|
- <p class={styles.TrainDataItemTitle}>
|
|
|
- {getMinutes(state.testInfo.practiceDurationAvg) > 0 ? (
|
|
|
- <div>
|
|
|
- <span>
|
|
|
- <NNumberAnimation
|
|
|
- from={0}
|
|
|
- to={getMinutes(
|
|
|
- state.testInfo.practiceDurationAvg
|
|
|
- )}></NNumberAnimation>
|
|
|
- </span>{' '}
|
|
|
- 分
|
|
|
- </div>
|
|
|
- ) : null}
|
|
|
- <div>
|
|
|
- <span>
|
|
|
- <NNumberAnimation
|
|
|
- from={0}
|
|
|
- to={getSecend(
|
|
|
- state.testInfo.practiceDurationAvg
|
|
|
- )}></NNumberAnimation>
|
|
|
- </span>{' '}
|
|
|
- 秒
|
|
|
- </div>
|
|
|
- </p>
|
|
|
- <p class={styles.TrainDataItemsubTitle}>平均每天练习时长</p>
|
|
|
- </div>
|
|
|
- </NGi>
|
|
|
- </NGrid>
|
|
|
- </div>
|
|
|
- <div class={styles.tableWrap}>
|
|
|
- <NDataTable
|
|
|
- v-slots={{
|
|
|
- empty: () => <TheEmpty></TheEmpty>
|
|
|
- }}
|
|
|
- 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
|
|
|
- />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- );
|
|
|
- }
|
|
|
-});
|
|
|
+import { defineComponent, nextTick, onMounted, reactive, ref } from 'vue';
|
|
|
+import styles from '../index.module.less';
|
|
|
+import {
|
|
|
+ NButton,
|
|
|
+ NDataTable,
|
|
|
+ NForm,
|
|
|
+ NFormItem,
|
|
|
+ NGi,
|
|
|
+ NGrid,
|
|
|
+ NImage,
|
|
|
+ NModal,
|
|
|
+ NNumberAnimation,
|
|
|
+ NSelect,
|
|
|
+ NSpace,
|
|
|
+ NTooltip
|
|
|
+} from 'naive-ui';
|
|
|
+import SearchInput from '@/components/searchInput';
|
|
|
+import CSelect from '@/components/CSelect';
|
|
|
+import Pagination from '@/components/pagination';
|
|
|
+import add from './images/add.png';
|
|
|
+import {
|
|
|
+ getNowDateAndMonday,
|
|
|
+ getNowDateAndSunday,
|
|
|
+ getTimes,
|
|
|
+ getMinutes,
|
|
|
+ getSecend
|
|
|
+} from '/src/utils/dateFormat';
|
|
|
+import { getTestList, getTrainingStat } from '../api';
|
|
|
+import CDatePicker from '/src/components/CDatePicker';
|
|
|
+import { useRoute, useRouter } from 'vue-router';
|
|
|
+import TheEmpty from '/src/components/TheEmpty';
|
|
|
+import { initCache, setCache } from '/src/hooks/use-async';
|
|
|
+import iconSortDefault from '@/common/images/icon-sort-default.png';
|
|
|
+import iconSortDesc from '@/common/images/icon-sort-desc.png';
|
|
|
+import iconSortAsc from '@/common/images/icon-sort-asc.png';
|
|
|
+
|
|
|
+export default defineComponent({
|
|
|
+ name: 'student-studentList',
|
|
|
+ setup(props, { emit }) {
|
|
|
+ const state = reactive({
|
|
|
+ searchForm: {
|
|
|
+ ase: 0,
|
|
|
+ sortType: 1,
|
|
|
+ keyword: '',
|
|
|
+ trainingStatus: null as any,
|
|
|
+ vipFlag: '' as any
|
|
|
+ },
|
|
|
+ searchWord: '',
|
|
|
+ orchestraType: null,
|
|
|
+ courseTypeCode: null,
|
|
|
+ subjectId: null,
|
|
|
+ classId: null,
|
|
|
+ studentType: null,
|
|
|
+ loading: false,
|
|
|
+ pagination: {
|
|
|
+ page: 1,
|
|
|
+ rows: 10,
|
|
|
+ pageTotal: 4
|
|
|
+ },
|
|
|
+ tableList: [] as any,
|
|
|
+ memberNumber: 0,
|
|
|
+ testInfo: {
|
|
|
+ practiceDurationAvg: 0,
|
|
|
+ vipUserCount: 0,
|
|
|
+ practiceUserCount: 0
|
|
|
+ },
|
|
|
+ activeRow: null
|
|
|
+ });
|
|
|
+ const route = useRoute();
|
|
|
+ const router = useRouter();
|
|
|
+ const search = () => {
|
|
|
+ state.pagination.page = 1;
|
|
|
+ getInfo();
|
|
|
+ getList();
|
|
|
+ setCache({
|
|
|
+ current: { ...state.searchForm, timer: timer.value },
|
|
|
+ saveKey: 'classDetailTestRecord'
|
|
|
+ });
|
|
|
+ };
|
|
|
+ const timer = ref<[number, number]>([
|
|
|
+ getNowDateAndMonday(new Date().getTime()),
|
|
|
+ getNowDateAndSunday(new Date().getTime())
|
|
|
+ ]);
|
|
|
+ const onReset = () => {
|
|
|
+ timer.value = [
|
|
|
+ getNowDateAndMonday(new Date().getTime()),
|
|
|
+ getNowDateAndSunday(new Date().getTime())
|
|
|
+ ];
|
|
|
+ state.searchForm = {
|
|
|
+ ase: 0,
|
|
|
+ sortType: 1,
|
|
|
+ keyword: '',
|
|
|
+ trainingStatus: null as any,
|
|
|
+ vipFlag: ''
|
|
|
+ };
|
|
|
+ search();
|
|
|
+ setCache({
|
|
|
+ current: { ...state.searchForm, timer: timer.value },
|
|
|
+ saveKey: 'classDetailTestRecord'
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ initCache({
|
|
|
+ current: { ...state.searchForm, timer: timer.value },
|
|
|
+ saveKey: 'classDetailTestRecord',
|
|
|
+ callBack: (active: any) => {
|
|
|
+ state.searchForm = active;
|
|
|
+ timer.value = active.timer;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ const getList = async () => {
|
|
|
+ state.loading = true;
|
|
|
+ try {
|
|
|
+ const res = await getTestList({
|
|
|
+ classGroupId: route.query.id,
|
|
|
+ ...state.searchForm,
|
|
|
+ ...state.pagination,
|
|
|
+ ...getTimes(timer.value, ['startTime', 'endTime'], 'YYYY-MM-DD')
|
|
|
+ });
|
|
|
+
|
|
|
+ state.tableList = res.data.rows;
|
|
|
+
|
|
|
+ state.pagination.pageTotal = res.data.total;
|
|
|
+ state.loading = false;
|
|
|
+ } catch (e) {
|
|
|
+ state.loading = false;
|
|
|
+ console.log(e);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const getInfo = async () => {
|
|
|
+ try {
|
|
|
+ const res = await getTrainingStat({
|
|
|
+ classGroupId: route.query.id,
|
|
|
+ ...getTimes(timer.value, ['startTime', 'endTime'], 'YYYY-MM-DD')
|
|
|
+ });
|
|
|
+ state.testInfo.practiceDurationAvg = res.data.practiceDurationAvg;
|
|
|
+ state.testInfo.practiceUserCount = res.data.practiceUserCount;
|
|
|
+ state.testInfo.vipUserCount = res.data.vipUserCount;
|
|
|
+ } catch (e) {
|
|
|
+ console.log(e);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ onMounted(() => {
|
|
|
+ getInfo();
|
|
|
+ getList();
|
|
|
+
|
|
|
+ // nextTick(() => {
|
|
|
+ // // 把默认的排序删除
|
|
|
+ // const dom = document.querySelectorAll('.n-data-table-sorter');
|
|
|
+ // dom.forEach((item: any) => {
|
|
|
+ // item.style.display = 'none';
|
|
|
+ // });
|
|
|
+ // });
|
|
|
+ });
|
|
|
+ const gotoStudentDetail = (row: any) => {
|
|
|
+ router.push({
|
|
|
+ path: '/classStudentRecode',
|
|
|
+ query: {
|
|
|
+ ...route.query,
|
|
|
+ studentId: row.studentId,
|
|
|
+ studentName: row.studentName
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+ const practiceDaysRef = reactive({
|
|
|
+ title() {
|
|
|
+ return (
|
|
|
+ <NTooltip showArrow={false} placement="top-start">
|
|
|
+ {{
|
|
|
+ trigger: () => (
|
|
|
+ <div class={styles.cell}>
|
|
|
+ 练习天数
|
|
|
+ <img
|
|
|
+ class={styles.sortIcon}
|
|
|
+ src={
|
|
|
+ practiceDaysRef.sortOrder === 'descend'
|
|
|
+ ? iconSortDesc
|
|
|
+ : practiceDaysRef.sortOrder === 'ascend'
|
|
|
+ ? iconSortAsc
|
|
|
+ : iconSortDefault
|
|
|
+ }
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ ),
|
|
|
+ default:
|
|
|
+ practiceDaysRef.sortOrder === 'descend'
|
|
|
+ ? '点击升序'
|
|
|
+ : practiceDaysRef.sortOrder === 'ascend'
|
|
|
+ ? '取消排序'
|
|
|
+ : '点击降序'
|
|
|
+ }}
|
|
|
+ </NTooltip>
|
|
|
+ );
|
|
|
+ },
|
|
|
+ key: 'practiceDays',
|
|
|
+ sorter: true,
|
|
|
+ sortOrder: false as any,
|
|
|
+ render(row: any) {
|
|
|
+ return <>{row.practiceDays ? row.practiceDays : 0}天</>;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ const practiceDurationRef = reactive({
|
|
|
+ title() {
|
|
|
+ return (
|
|
|
+ <NTooltip showArrow={false} placement="top-start">
|
|
|
+ {{
|
|
|
+ trigger: () => (
|
|
|
+ <div class={styles.cell}>
|
|
|
+ 学练时长
|
|
|
+ <img
|
|
|
+ class={styles.sortIcon}
|
|
|
+ src={
|
|
|
+ practiceDurationRef.sortOrder === 'descend'
|
|
|
+ ? iconSortDesc
|
|
|
+ : practiceDurationRef.sortOrder === 'ascend'
|
|
|
+ ? iconSortAsc
|
|
|
+ : iconSortDefault
|
|
|
+ }
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ ),
|
|
|
+ default:
|
|
|
+ practiceDurationRef.sortOrder === 'descend'
|
|
|
+ ? '点击升序'
|
|
|
+ : practiceDurationRef.sortOrder === 'ascend'
|
|
|
+ ? '取消排序'
|
|
|
+ : '点击降序'
|
|
|
+ }}
|
|
|
+ </NTooltip>
|
|
|
+ );
|
|
|
+ },
|
|
|
+ key: 'practiceDuration',
|
|
|
+ sorter: true,
|
|
|
+ sortOrder: false as any,
|
|
|
+ render(row: any) {
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ {row.practiceDuration
|
|
|
+ ? getMinutes(row.practiceDuration) > 0
|
|
|
+ ? getMinutes(row.practiceDuration) +
|
|
|
+ '分' +
|
|
|
+ getSecend(row.practiceDuration) +
|
|
|
+ '秒'
|
|
|
+ : getSecend(row.practiceDuration) + '秒'
|
|
|
+ : 0 + '秒'}
|
|
|
+ </>
|
|
|
+ );
|
|
|
+ }
|
|
|
+ });
|
|
|
+ const columns = () => {
|
|
|
+ return [
|
|
|
+ {
|
|
|
+ title: '学生姓名',
|
|
|
+ key: 'studentName'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '手机号',
|
|
|
+ key: 'studentPhone'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '性别',
|
|
|
+ key: 'sex',
|
|
|
+ render(row: any) {
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ {row.gender + '' != 'null'
|
|
|
+ ? row.gender == '0'
|
|
|
+ ? '女'
|
|
|
+ : '男'
|
|
|
+ : '--'}
|
|
|
+ </>
|
|
|
+ );
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '学生类型',
|
|
|
+ key: 'studentType',
|
|
|
+ render(row: any) {
|
|
|
+ return <>{row.vipFlag ? '会员' : '普通'}</>;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ practiceDaysRef,
|
|
|
+ practiceDurationRef,
|
|
|
+ // {
|
|
|
+ // title: '练习天数',
|
|
|
+ // key: 'practiceDays',
|
|
|
+ // render(row: any) {
|
|
|
+ // return <>{row.practiceDays ? row.practiceDays : 0}天</>;
|
|
|
+ // }
|
|
|
+ // },
|
|
|
+ // {
|
|
|
+ // title: '学练时长',
|
|
|
+ // key: 'studentType',
|
|
|
+ // render(row: any) {
|
|
|
+ // return (
|
|
|
+ // <>
|
|
|
+ // {row.practiceDuration
|
|
|
+ // ? getMinutes(row.practiceDuration) > 0
|
|
|
+ // ? getMinutes(row.practiceDuration) +
|
|
|
+ // '分' +
|
|
|
+ // getSecend(row.practiceDuration) +
|
|
|
+ // '秒'
|
|
|
+ // : getSecend(row.practiceDuration) + '秒'
|
|
|
+ // : 0 + '秒'}
|
|
|
+ // </>
|
|
|
+ // );
|
|
|
+ // }
|
|
|
+ // },
|
|
|
+ {
|
|
|
+ title: '操作',
|
|
|
+ key: 'id',
|
|
|
+ render(row: any) {
|
|
|
+ return (
|
|
|
+ <NButton
|
|
|
+ text
|
|
|
+ type="primary"
|
|
|
+ onClick={() => {
|
|
|
+ gotoStudentDetail(row);
|
|
|
+ }}>
|
|
|
+ 详情
|
|
|
+ </NButton>
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ];
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleSorterChange = (sroter: any) => {
|
|
|
+ if (!sroter) {
|
|
|
+ state.searchForm.ase = 0;
|
|
|
+ state.searchForm.sortType = 1;
|
|
|
+ practiceDaysRef.sortOrder = false;
|
|
|
+ practiceDurationRef.sortOrder = false;
|
|
|
+ } else {
|
|
|
+ const list = {
|
|
|
+ practiceDuration: 1,
|
|
|
+ practiceDays: 2
|
|
|
+ };
|
|
|
+ state.searchForm.sortType =
|
|
|
+ list[sroter.columnKey as 'practiceDuration' | 'practiceDays'];
|
|
|
+ if (sroter.columnKey == 'practiceDuration') {
|
|
|
+ practiceDurationRef.sortOrder = sroter.order;
|
|
|
+ practiceDaysRef.sortOrder = false;
|
|
|
+ }
|
|
|
+ if (sroter.columnKey == 'practiceDays') {
|
|
|
+ practiceDaysRef.sortOrder = sroter.order;
|
|
|
+ practiceDurationRef.sortOrder = false;
|
|
|
+ }
|
|
|
+ state.searchForm.ase = sroter.order == 'ascend' ? 1 : 0;
|
|
|
+ }
|
|
|
+ getList();
|
|
|
+ };
|
|
|
+ return () => (
|
|
|
+ <div>
|
|
|
+ <div class={styles.searchList}>
|
|
|
+ <NForm label-placement="left" inline>
|
|
|
+ <NFormItem>
|
|
|
+ <SearchInput
|
|
|
+ {...{ placeholder: '请输入学生姓名' }}
|
|
|
+ class={styles.searchInput}
|
|
|
+ searchWord={state.searchForm.keyword}
|
|
|
+ onChangeValue={(val: string) =>
|
|
|
+ (state.searchForm.keyword = val)
|
|
|
+ }></SearchInput>
|
|
|
+ </NFormItem>
|
|
|
+
|
|
|
+ <NFormItem>
|
|
|
+ <CSelect
|
|
|
+ {...({
|
|
|
+ options: [
|
|
|
+ {
|
|
|
+ label: '全部类型',
|
|
|
+ value: ''
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '会员',
|
|
|
+ value: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '普通',
|
|
|
+ value: false
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ placeholder: '学生类型',
|
|
|
+ clearable: true,
|
|
|
+ inline: true
|
|
|
+ } as any)}
|
|
|
+ v-model:value={state.searchForm.vipFlag}></CSelect>
|
|
|
+ </NFormItem>
|
|
|
+ <NFormItem>
|
|
|
+ <CDatePicker
|
|
|
+ v-model:value={timer.value}
|
|
|
+ separator={'至'}
|
|
|
+ type="daterange"
|
|
|
+ timerValue={timer.value}></CDatePicker>
|
|
|
+ </NFormItem>
|
|
|
+ <NFormItem>
|
|
|
+ <NSpace justify="end">
|
|
|
+ <NButton type="primary" class="searchBtn" onClick={search}>
|
|
|
+ 搜索
|
|
|
+ </NButton>
|
|
|
+ <NButton
|
|
|
+ type="primary"
|
|
|
+ ghost
|
|
|
+ class="resetBtn"
|
|
|
+ onClick={onReset}>
|
|
|
+ 重置
|
|
|
+ </NButton>
|
|
|
+ </NSpace>
|
|
|
+ </NFormItem>
|
|
|
+ </NForm>
|
|
|
+ </div>
|
|
|
+ <div class={['section-container']}>
|
|
|
+ <NGrid x-gap="12" cols={8}>
|
|
|
+ <NGi>
|
|
|
+ <div class={styles.TrainDataItem}>
|
|
|
+ <div>
|
|
|
+ <p class={styles.TrainDataItemTitle}>
|
|
|
+ <div>
|
|
|
+ <span>
|
|
|
+ <NNumberAnimation
|
|
|
+ from={0}
|
|
|
+ to={
|
|
|
+ state.testInfo.practiceUserCount
|
|
|
+ }></NNumberAnimation>
|
|
|
+ </span>{' '}
|
|
|
+ 人
|
|
|
+ </div>
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <p class={styles.TrainDataItemsubTitle}>练习人数</p>
|
|
|
+ </div>
|
|
|
+ </NGi>
|
|
|
+ <NGi>
|
|
|
+ <div class={styles.TrainDataItem}>
|
|
|
+ <p class={styles.TrainDataItemTitle}>
|
|
|
+ <div>
|
|
|
+ <span>
|
|
|
+ <NNumberAnimation
|
|
|
+ from={0}
|
|
|
+ to={state.testInfo.vipUserCount}></NNumberAnimation>
|
|
|
+ </span>{' '}
|
|
|
+ 人
|
|
|
+ </div>
|
|
|
+ </p>
|
|
|
+ <p class={styles.TrainDataItemsubTitle}>会员人数</p>
|
|
|
+ </div>
|
|
|
+ </NGi>
|
|
|
+ <NGi>
|
|
|
+ <div class={styles.TrainDataItem}>
|
|
|
+ <p class={styles.TrainDataItemTitle}>
|
|
|
+ {getMinutes(state.testInfo.practiceDurationAvg) > 0 ? (
|
|
|
+ <div>
|
|
|
+ <span>
|
|
|
+ <NNumberAnimation
|
|
|
+ from={0}
|
|
|
+ to={getMinutes(
|
|
|
+ state.testInfo.practiceDurationAvg
|
|
|
+ )}></NNumberAnimation>
|
|
|
+ </span>{' '}
|
|
|
+ 分
|
|
|
+ </div>
|
|
|
+ ) : null}
|
|
|
+ <div>
|
|
|
+ <span>
|
|
|
+ <NNumberAnimation
|
|
|
+ from={0}
|
|
|
+ to={getSecend(
|
|
|
+ state.testInfo.practiceDurationAvg
|
|
|
+ )}></NNumberAnimation>
|
|
|
+ </span>{' '}
|
|
|
+ 秒
|
|
|
+ </div>
|
|
|
+ </p>
|
|
|
+ <p class={styles.TrainDataItemsubTitle}>平均每天练习时长</p>
|
|
|
+ </div>
|
|
|
+ </NGi>
|
|
|
+ </NGrid>
|
|
|
+ </div>
|
|
|
+ <div class={[styles.tableWrap, styles.noSort]}>
|
|
|
+ <NDataTable
|
|
|
+ v-slots={{
|
|
|
+ empty: () => <TheEmpty></TheEmpty>
|
|
|
+ }}
|
|
|
+ class={styles.classTable}
|
|
|
+ loading={state.loading}
|
|
|
+ columns={columns()}
|
|
|
+ data={state.tableList}
|
|
|
+ onUpdate:sorter={handleSorterChange}></NDataTable>
|
|
|
+ <Pagination
|
|
|
+ v-model:page={state.pagination.page}
|
|
|
+ v-model:pageSize={state.pagination.rows}
|
|
|
+ v-model:pageTotal={state.pagination.pageTotal}
|
|
|
+ onList={getList}
|
|
|
+ sync
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ }
|
|
|
+});
|