Browse Source

学生管理完成

1
mo 1 năm trước cách đây
mục cha
commit
633cbfe722

+ 1 - 1
src/views/classList/api.ts

@@ -154,7 +154,7 @@ export const getTrainingStat = (params: any) => {
  * 获取班级训练详情
  */
 export const getTrainingClassDetail = (params: any) => {
-  return request.get(`/edu-app/lessonTraining/trainingDetail`, {
+  return request.get(`/edu-app/lessonTraining/trainingStudentDetail`, {
     params,
     requestType: 'form'
   });

+ 23 - 0
src/views/studentList/api.ts

@@ -27,3 +27,26 @@ export const getStudentList = (params: any) => {
     data: params
   });
 };
+
+
+/**
+ * 修改学生信息
+ */
+export const resetStudentInfo = (params: any) => {
+  return request.post('/edu-app/student/update', {
+    data: params
+  });
+};
+
+
+/**
+ * 获取学生课后训练
+ */
+
+export const getStudentAfterWork = (params: any) => {
+  return request.post('/edu-app/lessonTraining/trainingTeacherList', {
+    data: params,
+    params
+  });
+};
+

+ 46 - 29
src/views/studentList/components/baseInfo.tsx

@@ -1,4 +1,4 @@
-import { defineComponent, onMounted, reactive, ref } from 'vue';
+import { defineComponent, onMounted, reactive, ref, watch } from 'vue';
 import styles from '../index.module.less';
 import {
   NImage,
@@ -22,10 +22,22 @@ import maleIcon from '../images/maleIcon.png';
 import femaleIcon from '../images/femaleIcon.png';
 import { useUserStore } from '/src/store/modules/users';
 import { api_teacherUpdate } from '/src/api/user';
+import { resetStudentInfo } from '../api'
 import UploadFile from '/src/components/upload-file';
 export default defineComponent({
   name: 'setting-personInfo',
-  setup() {
+  props:{
+    studentInfo:{
+      type:Object,
+      default: () => (
+        { nickname:'',
+      currentGradeNum:'',
+      gender:null,
+      phone:'',
+      id:''
+   })
+  }},
+  setup(props) {
     const message = useMessage();
     const userStore = useUserStore();
     const formOptions = reactive({
@@ -36,24 +48,25 @@ export default defineComponent({
       areaList: [] as any[]
     });
     const formRef = ref();
-    const teacherForm = reactive({
-      provinceCode: '', // 省份编码
-      cityCode: '', // 城市编码
-      regionCode: '', // 区域编码
-      nickname: userStore.info.nickname,
-      phone: userStore.info.phone,
-      gender: userStore.info.gender,
-      schoolId: userStore.info.schoolInfos?.[0]?.id,
-      tenantId: userStore.info.schoolInfos?.[0]?.tenantId,
-      id: userStore.info.id,
-      avatar: userStore.info.avatar
+    const studentForm = reactive({
+      nickname: props.studentInfo.nickname as any,
+      phone: props.studentInfo.phone,
+      gender: props.studentInfo.gender,
+      id: props.studentInfo.id,
+      classGroupName:props.studentInfo.classGroupName
     });
     const data = reactive({
       disabled: true,
       openChangePwd: false,
       uploadShow: true
     });
-
+    watch(()=>props.studentInfo,(val)=>{
+      studentForm.nickname= val.nickname as any
+      studentForm.phone=val.phone
+      studentForm.gender= val.gender
+      studentForm.id= val.id
+      studentForm.classGroupName=val.classGroupName
+    })
     // onMounted(() => {});
 
     const handleSave = () => {
@@ -61,17 +74,23 @@ export default defineComponent({
         if (err) {
           return;
         }
-        await api_teacherUpdate(teacherForm);
-        console.log(teacherForm);
-        userStore.getInfo();
+        await resetStudentInfo({...props.studentInfo,...studentForm});
         data.disabled = true;
         message.success('修改成功');
       });
     };
+    const cancel = ()=>{
+      studentForm.nickname = props.studentInfo.nickname
+      studentForm.phone = props.studentInfo.phone
+      studentForm.gender = props.studentInfo.gender
+      studentForm.classGroupName = props.studentInfo.classGroupName
+
+      data.disabled = true
+    }
     return () => (
       <div class={styles.infoWrap}>
         <div class={styles.setInfo}>
-          <NForm ref={formRef} model={teacherForm} disabled={data.disabled}>
+          <NForm ref={formRef} model={studentForm} disabled={data.disabled}>
             <NGrid cols={4} x-gap="100">
               <NGi>
                 <NFormItem
@@ -85,7 +104,7 @@ export default defineComponent({
                   <NInput
                     bordered={!data.disabled}
                     placeholder="请填写老师姓名"
-                    v-model:value={teacherForm.nickname}></NInput>
+                    v-model:value={studentForm.nickname}></NInput>
                 </NFormItem>
               </NGi>
               <NGi>
@@ -107,7 +126,7 @@ export default defineComponent({
                   <NInput
                     bordered={!data.disabled}
                     placeholder="请填写老师手机号"
-                    v-model:value={teacherForm.phone}></NInput>
+                    v-model:value={studentForm.phone}></NInput>
                 </NFormItem>
               </NGi>
               <NGi>
@@ -118,20 +137,18 @@ export default defineComponent({
                     showArrow={!data.disabled}
                     placeholder="请选择性别"
                     options={formOptions.sexs}
-                    v-model:value={teacherForm.gender}
+                    v-model:value={studentForm.gender}
                   />
                 </NFormItem>
               </NGi>
               <NGi>
                 <NFormItem label="年级班级" path="sex">
-                  <NSelect
+                <NInput
                     bordered={!data.disabled}
-                    class={styles.select}
-                    showArrow={!data.disabled}
-                    placeholder="请选择性别"
-                    options={formOptions.sexs}
-                    v-model:value={teacherForm.gender}
-                  />
+                    disabled={true}
+                    placeholder="年级班级"
+                    v-model:value={studentForm.classGroupName}></NInput>
+
                 </NFormItem>
               </NGi>
             </NGrid>
@@ -148,7 +165,7 @@ export default defineComponent({
           </NSpace>
         ) : (
           <NSpace class={styles.btnList} align="center" justify="end">
-            <NButton class={styles.btn} onClick={() => (data.disabled = true)}>
+            <NButton class={styles.btn} onClick={() => ( cancel())}>
               取消
             </NButton>
             <NButton

+ 284 - 0
src/views/studentList/components/studentAfterWork.tsx

@@ -0,0 +1,284 @@
+import { defineComponent, onMounted, reactive, ref } from 'vue';
+import styles from '../index.module.less';
+import {
+  NButton,
+  NDataTable,
+  NForm,
+  NFormItem,
+  NImage,
+  NModal,
+  NSelect,
+  NSpace
+} from 'naive-ui';
+import SearchInput from '@/components/searchInput';
+import CSelect from '@/components/CSelect';
+import Pagination from '@/components/pagination';
+import { getStudentAfterWork } from '../api';
+import add from './images/add.png';
+import { useRoute } from 'vue-router';
+import CBreadcrumb from '/src/components/CBreadcrumb';
+import CDatePicker from '/src/components/CDatePicker';
+import defultHeade from '@/components/layout/images/teacherIcon.png';
+import {
+  getNowDateAndMonday,
+  getNowDateAndSunday,
+  getTimes
+} from '/src/utils/dateFormat';
+import { trainingStatusArray } from '@/utils/searchArray';
+import StudentTraomomhDetails from '../modals/studentTraomomhDetails'
+import dayjs from 'dayjs';
+import { lookup } from 'dns';
+export default defineComponent({
+  name: 'student-studentList',
+  setup(props, { emit }) {
+    const state = reactive({
+      searchForm: { keyword: '', trainingStatus: null as any },
+      loading: false,
+      pagination: {
+        page: 1,
+        rows: 10,
+        pageTotal: 4
+      },
+      tableList: [] as any,
+      workInfo: {
+        createTime: '',
+        expireDate: '',
+        teacherAvatar: '',
+        teacherName: ''
+      },
+      detailVisiable: false,
+      activeRow: null as any,
+      index: 0
+    });
+    const timer = ref<[number, number]>([
+      getNowDateAndMonday(new Date().getTime()),
+      getNowDateAndSunday(new Date().getTime())
+    ]);
+    const TrainingDetailsRef = ref();
+    const route = useRoute();
+    const routerList = ref([
+      { name: '班级管理', path: '/classList' },
+      { name: route.query.name, path: '/classDetail' },
+      { name: route.query.teacherName, path: '/afterWorkDetail' }
+    ] as any);
+
+    const search = () => {
+      state.pagination.page = 1;
+      getList();
+      console.log('search', state);
+    };
+
+    const onReset = () => {
+      state.searchForm = { keyword: '', trainingStatus: null as any };
+      timer.value = [
+        getNowDateAndMonday(new Date().getTime()),
+        getNowDateAndSunday(new Date().getTime())
+      ];
+      search();
+    };
+    const getList = async () => {
+      state.loading = true;
+      try {
+        const res = await getStudentAfterWork({
+          studentId: route.query.studentId,
+          ...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 getWorkInfo = async () => {
+    //   console.log(route.query);
+    //   try {
+    //     const res = await getWorkDetail({ trainingId: route.query.trainingId });
+    //     state.workInfo = { ...res.data };
+    //   } catch (e) {
+    //     console.log(e);
+    //   }
+    // };
+
+    const lookDetail = (row: any, index: number) => {
+      console.log(index, 'index');
+      state.index = index + 1;
+      state.activeRow = row;
+      state.detailVisiable = true;
+    };
+    onMounted(() => {
+      // getWorkInfo();
+      getList();
+    });
+    const columns = () => {
+      return [
+        {
+          title: '布置老师',
+          key: 'teacherName'
+        },
+        {
+          title: '布置时间',
+          key: 'createTime',
+          render(row: any) {
+            return row.createTime
+              ? dayjs(row.createTime).format('YYYY-MM-DD')
+              : '--';
+          }
+        },
+        {
+          title: '截止时间',
+          key: 'expireDate',
+          render(row: any) {
+            return row.expireDate
+              ? dayjs(row.expireDate).format('YYYY-MM-DD')
+              : '--';
+          }
+        },
+        {
+          title: '最后提交时间',
+          key: 'submitTime',
+          render(row: any) {
+            return row.submitTime
+              ? dayjs(row.submitTime).format('YYYY-MM-DD')
+              : '--';
+          }
+        },
+        {
+          title: '提交状态',
+          key: 'sex',
+          render(row: any) {
+            return (
+              <div>
+                {row.trainingStatus == 'UNSUBMITTED' ? (
+                  <p class={styles.nosub}>未提交</p>
+                ) : null}
+                {row.trainingStatus == 'SUBMITTED' ? (
+                  <p class={styles.ison}>不合格</p>
+                ) : null}
+                {row.trainingStatus == 'TARGET' ? (
+                  <p class={styles.isok}>合格</p>
+                ) : null}
+              </div>
+            );
+          }
+        },
+        {
+          title: '操作',
+          key: 'id',
+          render(row: any, index: number) {
+            return (
+              <NButton
+                text
+                type="primary"
+                onClick={() => {
+                  lookDetail(row, index);
+                }}>
+                详情
+              </NButton>
+            );
+          }
+        }
+      ];
+    };
+
+    const goToNext = () => {
+      ++state.index;
+
+      state.activeRow = state.tableList[state.index - 1];
+
+      TrainingDetailsRef.value.getTrainingDetail(
+        state.activeRow.studentLessonTrainingId
+      );
+    };
+    const gotoPre = () => {
+      --state.index;
+      state.activeRow = state.tableList[state.index - 1];
+      TrainingDetailsRef.value.getTrainingDetail(
+        state.activeRow.studentLessonTrainingId
+      );
+    };
+    return () => (
+      <div>
+        <div >
+          <div class={styles.searchList}>
+            <NForm label-placement="left" inline>
+                       <NFormItem>
+                <CDatePicker
+                  v-model:value={timer.value}
+                  separator={'至'}
+                  type="daterange"
+                  timerValue={timer.value}></CDatePicker>
+              </NFormItem>
+              <NFormItem>
+                <CSelect
+                  {...({
+                    options: [
+                      {
+                        label: '提交状态',
+                        value: null
+                      },
+                      ...trainingStatusArray
+                    ],
+                    placeholder: '提交状态',
+                    clearable: true,
+                    inline: true
+                  } as any)}
+                  v-model:value={state.searchForm.trainingStatus}></CSelect>
+              </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 >
+            <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
+
+            />
+          </div>
+        </div>
+        <NModal
+          v-model:show={state.detailVisiable}
+          preset="card"
+          class={['modalTitle background', styles.wordDetailModel]}
+          title={'训练详情'}>
+          <StudentTraomomhDetails
+            // onNext={() => goToNext()}
+            // onPre={() => gotoPre()}
+            ref={TrainingDetailsRef}
+            onClose={() => (state.detailVisiable = false)}
+            total={state.tableList.length}
+            current={state.index}
+            activeRow={state.activeRow}></StudentTraomomhDetails>
+        </NModal>
+      </div>
+    );
+  }
+});

+ 10 - 1
src/views/studentList/index.module.less

@@ -423,7 +423,7 @@
 
 .setInfo {
   margin-top: 64px;
-  width: 1172px;
+
 
   :global {
     .n-form-item-label {
@@ -459,3 +459,12 @@
     }
   }
 }
+
+.btnList {
+  margin-top: 300px;
+}
+
+
+.wordDetailModel {
+  width: 1012px;
+}

+ 181 - 0
src/views/studentList/modals/studentTraomomhDetails.tsx

@@ -0,0 +1,181 @@
+import {
+  NButton,
+  NSpace,
+  useMessage,
+  NForm,
+  NFormItem,
+  NSelect,
+  NImage,
+  NScrollbar
+} from 'naive-ui';
+import { defineComponent, onMounted, reactive, ref } from 'vue';
+import styles from '@/views/classList/index.module.less';
+import TrainType from '@/views/attend-class/model/train-type';
+import defultHeade from '@/components/layout/images/teacherIcon.png';
+import noSub from '@/views/classList/images/nosub.png';
+import qualified from '@/views/classList/images/qualified.png';
+import unqualified from '@/views/classList/images/unqualified.png';
+import { evaluateDifficult } from '/src/utils/contants';
+import dayjs from 'dayjs';
+import { getTrainingStudentDetail } from '../../classList/api';
+export default defineComponent({
+  props: {
+    activeRow: {
+      type: Object,
+      default: () => ({ id: '' })
+    },
+    total: {
+      type: Number,
+      default: 0
+    },
+    current: {
+      type: Number,
+      default: 0
+    }
+  },
+  name: 'studentTraomomhDetails',
+  emits: ['close'],
+
+  setup(props, { emit, expose }) {
+    const data = reactive({
+      uploading: false
+    });
+    const teacherInfo = ref({
+      teacherName: '',
+      createTime: '',
+      expireDate: '',
+      teacherAvatar: '',
+      studentLessonTrainingDetails: [] as any
+    } as any);
+    const message = useMessage();
+    const foemsRef = ref();
+    const typeFormat = (trainingType: string, configJson: any) => {
+      let tList: string[] = [];
+
+      if (trainingType === 'EVALUATION') {
+        tList = [
+          `${evaluateDifficult[configJson.evaluateDifficult]}`,
+          '全部小节',
+          `速度${configJson.evaluateSpeed}`,
+          `${configJson.trainingTimes}分合格`
+        ];
+        console.log('configJson.evaluateDifficult--', tList);
+      } else {
+        tList = [
+          `${configJson.practiceChapterBegin}-${configJson.practiceChapterEnd}小节`,
+          `速度${configJson.practiceSpeed}`,
+          `${configJson.trainingTimes}分钟`
+        ];
+        console.log('configJson.evaluateDifficult', tList);
+      }
+      return tList;
+    };
+    const getTrainingDetail = async (id: any) => {
+      console.log(id,'getTrainingDetail')
+      try {
+        const res = await getTrainingStudentDetail({
+          studentLessonTrainingId: id
+        });
+        const arr = res.data.studentLessonTrainingDetails.map((item: any) => {
+          const tList = typeFormat(
+            item.trainingType,
+            JSON.parse(item.trainingContent)
+          );
+          return {
+            ...item,
+            coverImg: item.titleImg,
+            allTimes: JSON.parse(item.trainingContent).trainingTimes,
+            typeList: tList || []
+          };
+        });
+        teacherInfo.value = {
+          ...res.data,
+
+          studentLessonTrainingDetails: arr
+        };
+      } catch (e) {
+        console.log(e);
+      }
+    };
+    expose({ getTrainingDetail });
+    onMounted(() => {
+      getTrainingDetail(props.activeRow.id);
+    });
+
+    return () => (
+      <div class={[styles.trainingDetails]}>
+        <div class={styles.studentList}>
+          <div class={styles.studentHeaderWrap}>
+            <div class={styles.studentHeader}>
+              <div class={styles.studentHeaderBorder}>
+                <NImage
+                  class={styles.studentHeaderImg}
+                  src={
+                    teacherInfo.value.teacherAvatar
+                      ? teacherInfo.value.teacherAvatar
+                      : defultHeade
+                  }
+                  previewDisabled></NImage>
+              </div>
+            </div>
+
+            <div class={styles.workafterInfo}>
+              <h4>
+                {teacherInfo.value.teacherName}{' '}
+                <div
+                  class={[
+                    styles.workafterInfoDot,
+                    styles.workafterTeacherInfoDot
+                  ]}>
+                  老师
+                </div>
+              </h4>
+              <p>
+                开始时间:
+                {teacherInfo.value.createTime
+                  ? dayjs(new Date(teacherInfo.value.createTime)).format(
+                      'YYYY-MM-DD'
+                    )
+                  : '--'}{' '}
+                | 结束时间:
+                {dayjs(new Date(teacherInfo.value.expireDate)).format(
+                  'YYYY-MM-DD'
+                )}
+              </p>
+            </div>
+          </div>
+          {teacherInfo.value.trainingStatus == 'UNSUBMITTED' ? (
+            <NImage
+              previewDisabled
+              class={styles.workStatus}
+              src={noSub}></NImage>
+          ) : null}
+          {teacherInfo.value.trainingStatus == 'SUBMITTED' ? (
+            <NImage
+              previewDisabled
+              class={styles.workStatus}
+              src={unqualified}></NImage>
+          ) : null}
+          {teacherInfo.value.trainingStatus == 'TARGET' ? (
+            <NImage
+              previewDisabled
+              class={styles.workStatus}
+              src={qualified}></NImage>
+          ) : null}
+        </div>
+        <NScrollbar style="max-height:400px" trigger="none">
+          <div class={styles.workList}>
+            {teacherInfo.value.studentLessonTrainingDetails.map((item: any) => (
+              <TrainType
+                style={{ marginBottom: '20px' }}
+                isDisabled={true}
+                isDelete={false}
+                isCLassWork={false}
+                item={item}></TrainType>
+            ))}
+          </div>
+        </NScrollbar>
+      </div>
+    );
+  }
+});

+ 13 - 9
src/views/studentList/studentDetail.tsx

@@ -23,14 +23,16 @@ import maleIcon from '@/views/setting/images/maleIcon.png';
 import PracticeData from '@/views/studentList/components/practiceData';
 import EvaluationRecords from '@/views/studentList/components/evaluationRecords';
 import BaseInfo from '@/views/studentList/components/baseInfo';
+import StudentAfterWork from './components/studentAfterWork'
+import { getTabsCache, setTabsCaches } from '@/hooks/use-async';
 import dayjs from 'dayjs';
 export default defineComponent({
   name: 'studentDetail',
   setup(props, { emit }) {
     const state = reactive({
-      studentInfo: { avatar: '', nickname: '', gender: null, subjectNames: '' }
+      studentInfo: { avatar: '', nickname: '', gender: null, subjectNames: '',classGroupName:'' }
     });
-    const activeStudentTab = ref('textRcode');
+    const activeStudentTab = ref('baseInfo');
     const route = useRoute();
     console.log(route.meta.isClass);
     const routerList = ref(
@@ -42,7 +44,6 @@ export default defineComponent({
           ]
         : ([
             { name: '学生管理', path: '/studentList' },
-
             { name: route.query.studentName, path: '/classStudentRecode' }
           ] as any)
     );
@@ -61,7 +62,9 @@ export default defineComponent({
     onMounted(() => {
       getWorkInfo();
     });
-
+    const setTabs = (val: any) => {
+      setTabsCaches(val, 'tabName', route);
+    };
     return () => (
       <div>
         <CBreadcrumb list={routerList.value}></CBreadcrumb>
@@ -88,14 +91,15 @@ export default defineComponent({
                   }></NImage>
               </h4>
               <p>
-                {route.query.name}{' '}
+                {state.studentInfo.classGroupName}{' '}
                 {state.studentInfo.subjectNames
-                  ? '|' + state.studentInfo.subjectNames
-                  : ''}
+                  ? '| ' + state.studentInfo.subjectNames
+                  : ' '}
               </p>
             </div>
           </div>
           <NTabs
+              onUpdate:value={(val: any) => setTabs(val)}
             class={styles.customTabs}
             v-model:value={activeStudentTab.value}
             size="large"
@@ -103,10 +107,10 @@ export default defineComponent({
             pane-wrapper-style="margin: 0 -4px"
             pane-style="padding-left: 4px; padding-right: 4px; box-sizing: border-box;">
             <NTabPane name="baseInfo" tab="基本信息">
-              <BaseInfo></BaseInfo>
+              <BaseInfo studentInfo={state.studentInfo}></BaseInfo>
             </NTabPane>
             <NTabPane name="afterWork" tab="课后训练">
-              课后训练
+              <StudentAfterWork></StudentAfterWork>
             </NTabPane>
             <NTabPane name="textRcode" tab="练习记录">
               <PracticeData