浏览代码

Merge branch 'startLogin' into dev

mo 1 年之前
父节点
当前提交
ee8ce52cae

+ 3 - 2
src/styles/index.less

@@ -171,6 +171,8 @@ body {
   &.background {
     .n-card-header {
       background: #f5f6fa;
+
+      overflow: hidden;
     }
   }
 
@@ -277,7 +279,6 @@ body {
   }
 }
 
-
 /* 列表动画 start */
 .list-move,
 /* 对移动中的元素应用的过渡 */
@@ -303,4 +304,4 @@ body {
 
 .no-move {
   transition: transform 0s;
-}
+}

+ 30 - 0
src/views/classList/api.ts

@@ -18,3 +18,33 @@ export const getCLassStudent = (params: any) => {
     // requestType: 'form'
   });
 };
+
+/**
+ * 学员调整
+ */
+export const adjustStudent = (params: any) => {
+  return request.post('/edu-app/classGroup/adjustStudent', {
+    data: params
+    // requestType: 'form'
+  });
+};
+
+/**
+ * 删除
+ *
+ */
+export const deleteClass = (params: any) => {
+  return request.post('/edu-app/classGroup/delete', {
+    data: params,
+    requestType: 'form'
+  });
+};
+
+/**
+ * 新建班级
+ */
+export const addClass = (params: any) => {
+  return request.post('/edu-app/classGroup/save', {
+    data: params
+  });
+};

+ 4 - 4
src/views/classList/contants.ts

@@ -5,14 +5,14 @@ export const threeYearSystem = [
   { label: '三年级', value: 3 }
 ];
 export const foreYearSystem = [
-  { label: '全部年级', value: null },
+  { label: '选择年级', value: null },
   { label: '一年级', value: 1 },
   { label: '二年级', value: 2 },
   { label: '三年级', value: 3 },
   { label: '四年级', value: 4 }
 ];
 export const fiveYearSystem = [
-  { label: '全部年级', value: null },
+  { label: '选择年级', value: null },
   { label: '一年级', value: 1 },
   { label: '二年级', value: 2 },
   { label: '三年级', value: 3 },
@@ -29,7 +29,7 @@ export const sixYearSystem = [
   { label: '六年级', value: 6 }
 ];
 export const nineYearSystem = [
-  { label: '全部年级', value: null },
+  { label: '选择年级', value: null },
   { label: '一年级', value: 1 },
   { label: '二年级', value: 2 },
   { label: '三年级', value: 3 },
@@ -41,7 +41,7 @@ export const nineYearSystem = [
   { label: '九年级', value: 9 }
 ];
 export const classArray = [
-  { value: null, label: '全部班级' },
+  { value: null, label: '选择班级' },
   { value: 1, label: '1班' },
   { value: 2, label: '2班' },
   { value: 3, label: '3班' },

+ 74 - 0
src/views/classList/index.module.less

@@ -212,3 +212,77 @@
     }
   }
 }
+.studentTransferList {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  .studentLeft,
+  .studentRight {
+    padding: 14px 16px;
+    width: 277px;
+
+    background: #e8f2ff;
+    border-radius: 16px;
+    .listTop {
+      display: flex;
+      flex-direction: row;
+      align-items: center;
+      padding-bottom: 14px;
+      border-bottom: 1px solid rgba(0, 0, 0, 0.06);
+      font-size: 16px;
+      font-weight: 600;
+      color: #131415;
+      line-height: 22px;
+      span {
+        color: #777;
+        font-weight: 400;
+        font-size: 12px;
+      }
+    }
+    .chioseCheckBox {
+      padding: 2px 2px;
+      font-size: 16px;
+      font-weight: 400;
+      color: #131415;
+    }
+  }
+
+  .chioseBox {
+    width: 80px;
+    height: 389px;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    .chioseBtn {
+      cursor: pointer;
+      width: 34px;
+      height: 34px;
+      border-radius: 8px;
+      background: url('@{img}/transArrrow.png') no-repeat;
+      background-size: 34px 34px;
+      &:hover {
+        background: url('@{img}/transArrowActive.png') no-repeat;
+        background-size: 34px 34px;
+      }
+    }
+    .chioseBtnRight {
+      transform: rotate(180deg);
+      margin-bottom: 23px;
+    }
+  }
+  .chioseCheckAllBox {
+    margin-top: 8px !important;
+    margin-bottom: 14px !important;
+  }
+  .bottom {
+    padding-top: 14px;
+    border-top: 1px solid rgba(0, 0, 0, 0.06);
+  }
+}
+.addClass {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding-top: 50px;
+}

+ 81 - 28
src/views/classList/index.tsx

@@ -1,4 +1,4 @@
-import { defineComponent, reactive, onMounted } from 'vue';
+import { defineComponent, reactive, onMounted, ref } from 'vue';
 import styles from './index.module.less';
 import {
   NButton,
@@ -8,14 +8,17 @@ import {
   NImage,
   NModal,
   NSelect,
-  NSpace
+  NSpace,
+  useDialog,
+  useMessage
 } from 'naive-ui';
 import SearchInput from '@/components/searchInput';
 import CSelect from '@/components/CSelect';
 import Pagination from '@/components/pagination';
-import { classGroupList } from './api';
+import { classGroupList, deleteClass } from './api';
 import { useUserStore } from '/src/store/modules/users';
-import ResetStudent from './modals/resetStudent';
+import CreateClass from './modals/createClass';
+import RestStudentBox from './modals/restStudentBox';
 import {
   sixYearSystem,
   fiveYearSystem,
@@ -24,8 +27,7 @@ import {
   nineYearSystem,
   classArray
 } from './contants';
-import add from './images/add.png';
-import { get } from 'http';
+import add from '@/views/studentList/images/add.png';
 export default defineComponent({
   name: 'class-classList',
   setup(props, { emit }) {
@@ -47,10 +49,15 @@ export default defineComponent({
       gradeNumList: [] as any,
       tableList: [] as any,
       studentVisible: false,
-      activeRow: null as any
+      activeRow: null as any,
+      showaddClass: false
     });
-
+    const formRef = ref();
+    const dialog = useDialog();
+    const message = useMessage();
     const search = () => {
+      state.pagination.page = 1;
+      getList();
       console.log('search', state);
     };
     const userInfo = useUserStore();
@@ -72,7 +79,30 @@ export default defineComponent({
       state.gradeNumList = nineYearSystem;
     }
     const onReset = () => {
-      console.log('search');
+      state.searchForm = {
+        keyword: null as any,
+        currentClass: null,
+        currentGradeNum: null
+      };
+      getList();
+    };
+
+    const removeClass = async (row: any) => {
+      dialog.warning({
+        title: '警告',
+        content: `是否删除班级“${row.name}”?`,
+        positiveText: '确定',
+        negativeText: '取消',
+        onPositiveClick: async () => {
+          try {
+            await deleteClass({ ids: row.id });
+            getList();
+            message.success(`删除成功`);
+          } catch (e) {
+            console.log(e);
+          }
+        }
+      });
     };
     const getList = async () => {
       // classGroupList
@@ -130,9 +160,15 @@ export default defineComponent({
                   <NButton type="primary" text>
                     开始上课
                   </NButton>
-                  <NButton type="primary" text textColor="#EA4132">
-                    删除
-                  </NButton>
+                  {!(row.preStudentNum > 0) ? (
+                    <NButton
+                      type="primary"
+                      text
+                      textColor="#EA4132"
+                      onClick={() => removeClass(row)}>
+                      删除
+                    </NButton>
+                  ) : null}
                 </NSpace>
               </div>
             );
@@ -151,7 +187,7 @@ export default defineComponent({
     return () => (
       <div class={styles.listWrap}>
         <div class={styles.searchList}>
-          <NForm label-placement="left" inline>
+          <NForm label-placement="left" inline ref={formRef}>
             <NFormItem>
               <SearchInput
                 {...{ placeholder: '请输入班级名称' }}
@@ -166,7 +202,7 @@ export default defineComponent({
               <CSelect
                 {...({
                   options: state.gradeNumList,
-                  placeholder: '全部年级',
+                  placeholder: '选择年级',
                   clearable: true,
                   inline: true
                 } as any)}
@@ -176,7 +212,7 @@ export default defineComponent({
               <CSelect
                 {...({
                   options: classArray,
-                  placeholder: '全部班级',
+                  placeholder: '选择班级',
                   clearable: true,
                   inline: true
                 } as any)}
@@ -199,18 +235,19 @@ export default defineComponent({
             </NFormItem>
           </NForm>
         </div>
-        {/* <NButton
-            class={styles.addBtn}
-            type="primary"
-            v-slots={{
-              icon: () => (
-                <>
-                  <NImage class={styles.addBtnIcon} src={add}></NImage>
-                </>
-              )
-            }}>
-            新增学生
-          </NButton> */}
+        <NButton
+          class={styles.addBtn}
+          type="primary"
+          onClick={() => (state.showaddClass = true)}
+          v-slots={{
+            icon: () => (
+              <>
+                <NImage class={styles.addBtnIcon} src={add}></NImage>
+              </>
+            )
+          }}>
+          创建班级
+        </NButton>
         <div class={styles.tableWrap}>
           <NDataTable
             class={styles.classTable}
@@ -232,7 +269,23 @@ export default defineComponent({
           preset="card"
           class={['modalTitle background']}
           title={'学员调整'}>
-          <ResetStudent activeRow={state.activeRow}></ResetStudent>
+          <RestStudentBox
+            activeRow={state.activeRow}
+            onClose={() => (state.studentVisible = false)}
+            onGetList={() => getList()}></RestStudentBox>
+        </NModal>
+        <NModal
+          v-model:show={state.showaddClass}
+          style={{ width: '500px' }}
+          preset="card"
+          class={['modalTitle background']}
+          title={'创建班级'}>
+          <CreateClass
+            gradeNumList={state.gradeNumList}
+            classArray={classArray}
+            onGetList={() => getList()}
+            onClose={() => (state.showaddClass = false)}
+          />
         </NModal>
       </div>
     );

+ 110 - 0
src/views/classList/modals/createClass.tsx

@@ -0,0 +1,110 @@
+import {
+  NButton,
+  NSpace,
+  useMessage,
+  NForm,
+  NFormItem,
+  NSelect
+} from 'naive-ui';
+import { defineComponent, onMounted, reactive, ref } from 'vue';
+import styles from '../index.module.less';
+import CSelect from '/src/components/CSelect';
+import { addClass } from '../api';
+export default defineComponent({
+  props: {
+    activeRow: {
+      type: Object,
+      default: () => ({ id: '' })
+    },
+    gradeNumList: {
+      type: Array,
+      default: () => []
+    },
+    classArray: {
+      type: Array,
+      default: () => []
+    }
+  },
+  name: 'resetStudent',
+  emits: ['close', 'getList'],
+  setup(props, { emit }) {
+    const data = reactive({
+      uploading: false
+    });
+    const message = useMessage();
+    const foemsRef = ref();
+    const createClassForm = reactive({
+      currentGradeNum: null,
+      currentClass: null
+    });
+    const submitForms = () => {
+      foemsRef.value.validate(async (error: any) => {
+        console.log(createClassForm);
+        console.log(error);
+        if (error) {
+          return;
+        }
+        try {
+          const res = await addClass({ ...createClassForm });
+          message.success('新增成功');
+          emit('close');
+          emit('getList');
+        } catch (e) {
+          console.log(e);
+        }
+      });
+    };
+    return () => (
+      <div class={[styles.addClass]}>
+        <NForm label-placement="left" model={createClassForm} ref={foemsRef}>
+          <NFormItem
+            path="currentGradeNum"
+            rule={[
+              {
+                required: true,
+                message: '请选择年级'
+              }
+            ]}>
+            <CSelect
+              {...({
+                style: { width: '400px' },
+                options: props.gradeNumList,
+                placeholder: '选择年级',
+                clearable: true
+              } as any)}
+              v-model:value={createClassForm.currentGradeNum}></CSelect>
+          </NFormItem>
+          <NFormItem
+            path="currentClass"
+            rule={[
+              {
+                required: true,
+                message: '请选择班级'
+              }
+            ]}>
+            <CSelect
+              {...({
+                style: { width: '400px' },
+                options: props.classArray,
+                placeholder: '选择班级',
+                clearable: true
+              } as any)}
+              v-model:value={createClassForm.currentClass}></CSelect>
+          </NFormItem>
+        </NForm>
+        <NSpace class={styles.btnGroup} justify="center">
+          <NButton round onClick={() => emit('close')}>
+            取消
+          </NButton>
+          <NButton
+            round
+            loading={data.uploading}
+            onClick={() => submitForms()}
+            type="primary">
+            保存
+          </NButton>
+        </NSpace>
+      </div>
+    );
+  }
+});

+ 397 - 0
src/views/classList/modals/restStudentBox.tsx

@@ -0,0 +1,397 @@
+import {
+  NButton,
+  NSpace,
+  useMessage,
+  NCheckboxGroup,
+  NCheckbox,
+  NRow,
+  NImage,
+  NInput,
+  NScrollbar,
+  NDropdown
+} from 'naive-ui';
+import { computed, defineComponent, onMounted, reactive, ref } from 'vue';
+import styles from '../index.module.less';
+import SearchInput from '@/components/searchInput';
+import smallArrow from '../images/smallArrow.png';
+import transArrrow from '../images/transArrrow.png';
+import transArrowActive from '../images/transArrowActive.png';
+import { getCLassStudent, classGroupList, adjustStudent } from '../api';
+export default defineComponent({
+  props: {
+    activeRow: {
+      type: Object,
+      default: () => ({ id: '' })
+    }
+  },
+  name: 'RestStudentBox',
+  emits: ['close', 'getList'],
+  setup(props, { emit }) {
+    const message = useMessage();
+    const data = reactive({
+      uploading: false
+    });
+    const options = ref([] as any);
+
+    const chioseOptions = ref([] as any);
+    const formRef = ref();
+    const handleSubmit = async () => {
+      data.uploading = true;
+    };
+    const classList = ref([] as any);
+    console.log(props.activeRow, 'activeRow');
+    const targetClass = reactive({
+      name: '',
+      id: ''
+    });
+    const currentchioseStudent = ref([] as any);
+    const currentStudentList = ref([] as any);
+    const currentSearch = ref(null as any);
+
+    const targetchioseStudent = ref([] as any);
+    const targetStudentList = ref([] as any);
+    const targetSearch = ref(null as any);
+    //
+    const submitList = ref([] as any);
+    /**
+     * 这里干3件事  1.获取当前班的学生
+     * 2.查询所有的班级列表  并且排查当前班级
+     * 3.默认选择第一个班级 并且查出此班的学生
+     */
+    const chioseStudnet = (val: any) => {
+      console.log(val);
+    };
+    const getAllClassList = async () => {
+      try {
+        const res = await classGroupList({ page: 1, rows: 9999 });
+        classList.value = res.data.rows.map((item: any) => {
+          return {
+            label: item.name,
+            key: item.id,
+            disabled: item.id == props.activeRow.id
+          };
+        });
+
+        if (classList.value[0].disabled) {
+          targetClass.name = classList.value[1].label;
+          targetClass.id = classList.value[1].key;
+        } else {
+          targetClass.name = classList.value[0].label;
+          targetClass.id = classList.value[0].key;
+        }
+
+        const tarRes = await getCLassStudentList(targetClass.id);
+        targetStudentList.value = tarRes.data.rows.map((item: any) => {
+          return {
+            label: item.nickname + '(' + item.id + ')',
+            value: item.id
+          };
+        });
+      } catch (e) {
+        console.log(e);
+      }
+    };
+    const getCLassStudentList = async (id: string | number) => {
+      return await getCLassStudent({
+        page: 1,
+        rows: 999,
+        classGroupId: id
+      });
+    };
+    const chioseClass = async (val: any) => {
+      classList.value.forEach((item: any) => {
+        if (item.key == val) {
+          targetClass.name = item.label;
+          targetClass.id = item.key;
+        }
+      });
+      const res = await getCLassStudentList(val);
+      targetStudentList.value = res.data.rows.map((item: any) => {
+        return {
+          label: item.nickname + '(' + item.id + ')',
+          value: item.id
+        };
+      });
+      console.log(submitList.value, 'submitList.value');
+      // 判断一下 targetStudentList.value 和 submitList 对比
+      targetStudentList.value = targetStudentList.value.filter(
+        (item: any) =>
+          !submitList.value.some((ele: any) => ele.value === item.value)
+      );
+      // 如果 如果submitList 学生的toClassId 和targetClassId相同 则添加
+      submitList.value.forEach((ele: any) => {
+        if (ele.toClassId == targetClass.id) {
+          console.log(ele.toClassId, ele);
+          targetStudentList.value.push({
+            label: ele.label,
+            value: ele.value
+          });
+        }
+      });
+      // 有2下 如果submitList 学生 和 targetStudentList 学生id相同 则删除
+    };
+    const currentFitterList = computed(() => {
+      const oraginArr = currentStudentList.value || [];
+      const list = oraginArr.filter((item: any) => {
+        return item.label.indexOf(currentSearch.value || '') != -1;
+      });
+      return list;
+    });
+
+    const targetFitterList = computed(() => {
+      const oraginArr = targetStudentList.value || [];
+      const list = oraginArr.filter((item: any) => {
+        return item.label.indexOf(targetSearch.value || '') != -1;
+      });
+      return list;
+    });
+
+    const chioseAllCurrentStudent = () => {
+      if (
+        currentFitterList.value.length === currentchioseStudent.value.length
+      ) {
+        // 说明要取消全选
+        currentchioseStudent.value = [];
+      } else {
+        currentchioseStudent.value = currentFitterList.value.map(
+          (item: any) => {
+            return item.value;
+          }
+        );
+        // 全选
+      }
+    };
+
+    const chioseAllTargetStudent = () => {
+      if (targetFitterList.value.length === targetchioseStudent.value.length) {
+        // 说明要取消全选
+        targetchioseStudent.value = [];
+      } else {
+        targetchioseStudent.value = targetFitterList.value.map((item: any) => {
+          return item.value;
+        });
+        // 全选
+      }
+    };
+    const toTargetList = () => {
+      const subStudetn = currentStudentList.value.filter((item: any) => {
+        return currentchioseStudent.value.indexOf(item.value) != -1;
+      });
+      if (subStudetn.length > 0) {
+        const arr = subStudetn.map((item: any) => {
+          return {
+            ...item,
+            studentId: item.value,
+            toClassId: targetClass.id
+          };
+        });
+        submitList.value = submitList.value.filter(
+          (item: any) => !arr.some((ele: any) => ele.value === item.value)
+        );
+        submitList.value = submitList.value.concat(arr);
+      }
+      // 接下来 删除 currentStudentList里的这三个学生
+      currentStudentList.value = currentStudentList.value.filter(
+        (item: any) => !subStudetn.some((ele: any) => ele.value === item.value)
+      );
+      subStudetn.forEach((item: any) => {
+        targetStudentList.value.push(item);
+      });
+      currentchioseStudent.value = [];
+    };
+    const toCurrentList = () => {
+      const subStudetn = targetStudentList.value.filter((item: any) => {
+        return targetchioseStudent.value.indexOf(item.value) != -1;
+      });
+      if (subStudetn.length > 0) {
+        const arr = subStudetn.map((item: any) => {
+          return {
+            ...item,
+            studentId: item.value,
+            toClassId: props.activeRow.id
+          };
+        });
+        submitList.value = submitList.value.filter(
+          (item: any) => !arr.some((ele: any) => ele.value === item.value)
+        );
+        submitList.value = submitList.value.concat(arr);
+      }
+      targetStudentList.value = targetStudentList.value.filter(
+        (item: any) => !subStudetn.some((ele: any) => ele.value === item.value)
+      );
+      subStudetn.forEach((item: any) => {
+        currentStudentList.value.push(item);
+      });
+      targetchioseStudent.value = [];
+      // 过去 所以
+      console.log(submitList.value, ' submitList.value===>');
+    };
+
+    const submitStudent = async () => {
+      if (submitList.value < 1) {
+        emit('close');
+        return;
+      }
+      try {
+        const res = await adjustStudent(submitList.value);
+        emit('close');
+        emit('getList');
+      } catch (e) {
+        console.log(e);
+      }
+    };
+    onMounted(async () => {
+      getAllClassList();
+      const res = await getCLassStudentList(props.activeRow.id as string);
+      currentStudentList.value = res.data.rows.map((item: any) => {
+        return {
+          label: item.nickname + '(' + item.id + ')',
+          value: item.id
+        };
+      });
+    });
+    return () => (
+      <div class={[styles.container, styles.resetStudentWrap]}>
+        <div class={styles.studentTransfer}>
+          <div class={styles.studentTransferList}>
+            <div class={styles.studentLeft}>
+              <div class={styles.listTop}>
+                <p>{props.activeRow.name}</p>
+                <span>(当前班级)</span>
+              </div>
+              <div class={styles.listCore}>
+                <NRow class={styles.chioseCheckAllBox}>
+                  <NCheckbox
+                    onUpdateChecked={val => {
+                      chioseAllCurrentStudent();
+                    }}
+                    checked={
+                      currentFitterList.value.length ===
+                      currentchioseStudent.value.length
+                    }
+                    indeterminate={
+                      currentchioseStudent.value.length > 0 &&
+                      currentFitterList.value.length !==
+                        currentchioseStudent.value.length
+                    }
+                    label="全选"></NCheckbox>
+                </NRow>
+                <NRow>
+                  <SearchInput
+                    {...{ placeholder: '请输入学生姓名' }}
+                    class={styles.searchInput}
+                    searchWord={currentSearch.value}
+                    onChangeValue={(val: string) =>
+                      (currentSearch.value = val)
+                    }></SearchInput>
+                </NRow>
+                <NScrollbar style="max-height: 204px;min-height: 204px;margin-top:14px;">
+                  <NCheckboxGroup v-model:value={currentchioseStudent.value}>
+                    {currentFitterList.value.map((item: any) => (
+                      <NRow class={styles.chioseCheckBox}>
+                        <NCheckbox
+                          value={item.value}
+                          label={item.label}></NCheckbox>
+                      </NRow>
+                    ))}
+                  </NCheckboxGroup>
+                </NScrollbar>
+              </div>
+              <div class={[styles.bottomLeft, styles.bottom]}>
+                <div class={styles.bottomWrap}>
+                  共{currentStudentList.value.length}名学生
+                </div>
+              </div>
+            </div>
+            <div class={styles.chioseBox}>
+              <div
+                class={[styles.chioseBtn, styles.chioseBtnRight]}
+                onClick={() => toTargetList()}></div>
+              <div
+                class={styles.chioseBtn}
+                onClick={() => toCurrentList()}></div>
+            </div>
+            <div class={styles.studentRight}>
+              <div class={styles.listTop}>
+                <NDropdown
+                  key="111"
+                  v-model:value={targetClass.id}
+                  options={classList.value}
+                  onSelect={(value: any) => {
+                    chioseClass(value);
+                  }}
+                  scrollable>
+                  <div>
+                    {targetClass.name}
+                    <NImage
+                      class={styles.smallArrow}
+                      src={smallArrow}
+                      previewDisabled></NImage>
+                  </div>
+                </NDropdown>
+              </div>
+              <div class={styles.listCore}>
+                <NRow class={styles.chioseCheckAllBox}>
+                  <NCheckbox
+                    onUpdateChecked={val => {
+                      chioseAllTargetStudent();
+                    }}
+                    checked={
+                      targetFitterList.value.length ===
+                      targetchioseStudent.value.length
+                    }
+                    indeterminate={
+                      targetchioseStudent.value.length > 0 &&
+                      targetFitterList.value.length !==
+                        targetchioseStudent.value.length
+                    }
+                    label="全选"></NCheckbox>
+                </NRow>
+                <NRow>
+                  <SearchInput
+                    {...{ placeholder: '请输入学生姓名' }}
+                    class={styles.searchInput}
+                    searchWord={targetSearch.value}
+                    onChangeValue={(val: string) =>
+                      (targetSearch.value = val)
+                    }></SearchInput>
+                </NRow>
+                <NScrollbar style="max-height: 204px;min-height: 204px;margin-top:14px;">
+                  <NCheckboxGroup v-model:value={targetchioseStudent.value}>
+                    {targetFitterList.value.map((item: any) => (
+                      <NRow class={styles.chioseCheckBox}>
+                        <NCheckbox
+                          value={item.value}
+                          label={item.label}></NCheckbox>
+                      </NRow>
+                    ))}
+                  </NCheckboxGroup>
+                </NScrollbar>
+              </div>
+              <div class={[styles.bottomRight, styles.bottom]}>
+                <div class={styles.bottomWrap}>
+                  共{targetStudentList.value.length}名学生
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+
+        <NSpace class={styles.btnGroup} justify="center">
+          <NButton round onClick={() => emit('close')}>
+            取消
+          </NButton>
+          <NButton
+            round
+            loading={data.uploading}
+            type="primary"
+            onClick={() => {
+              submitStudent();
+            }}>
+            保存
+          </NButton>
+        </NSpace>
+      </div>
+    );
+  }
+});