Преглед на файлове

Merge branch 'zcx_4_24' of FanYanPeng/EAIFrontend into host-nju

JiangPengYu преди 4 месеца
родител
ревизия
b9d6efc9c8
променени са 4 файла, в които са добавени 104 реда и са изтрити 9 реда
  1. 5 0
      dw
  2. 8 4
      src/apis/class.ts
  3. 1 1
      src/router/index.ts
  4. 90 4
      src/views/ClassPage/ClassStudent.vue

+ 5 - 0
dw

@@ -0,0 +1,5 @@
+* Bug_fis_414
+  feature/Dockerfile_registry_change
+  feature/bugfix
+  feature/class
+  host-nju

+ 8 - 4
src/apis/class.ts

@@ -28,10 +28,14 @@ const classApis = {
     getStudentsOfClass:(classId:number) => {
         return axiosInstance.get(ENGAGE_PREFIX+`/${classId}`)
     },
-    addStudentOfClasss:(classId:number,officialNumber:number) => {
-        return axiosInstance.post(ENGAGE_PREFIX+`/${classId}/students`,{},{
-            params:{
-                officialNumber
+    addStudentOfClasss:(classId:number,officialNumber:number,stuName:string,phone:string) => {
+        return axiosInstance.post(ENGAGE_PREFIX+`/${classId}/students/import`,{
+            officialNumber,
+            stuName,
+            phone,
+        },{
+            headers: {
+                'Content-Type': 'application/json'
             }
         })
     },

+ 1 - 1
src/router/index.ts

@@ -260,7 +260,7 @@ const router = createRouter({
  */
   router.beforeEach(async (to) => {
     const store = useStore();
-    const publicPaths = [  '/register', '/passwordChange', '/admin/login' ];
+    const publicPaths = [  '/register', '/passwordChange', '/admin/login'];
     // 1. 检查URL中的token
     const urlToken = new URLSearchParams(window.location.search).get('token');
     if (urlToken) {

+ 90 - 4
src/views/ClassPage/ClassStudent.vue

@@ -104,6 +104,29 @@
         </div>
     </div>
 
+    <div v-if="visible_import" class="modal-mask" @click.self="isloading_import || (visible_import=false)" >
+        <div class="modal-container">
+            <div class="modal-body">
+                <div class="import-result">
+                    <h2>{{isloading_import?"导入中...":`成功${successImport}条,失败${failedImport}条,跳过${skippedImport}条,共${totalImport}条`}}</h2>
+                    <div v-if="failedName.length>0">
+                        <h4>失败学生名单:</h4>
+                        <div v-for="(name,index) in failedName" :key="index">
+                            {{ name }},学号:{{ failedOfficialNumber[index] }}
+                        </div>
+                    </div>
+                    <div v-if="skippedName.length>0">
+                        <h4>跳过学生名单:</h4>
+                        <div v-for="(name,index) in skippedName" :key="index">
+                            {{ name }},学号:{{ skippedOfficialNumber[index] }}
+                        </div>
+                    </div>
+                    <div style="height: 15px;"></div>
+                </div>
+            </div>
+        </div>
+    </div>
+
     <div v-if="visible_add" class="modal-mask" @click.self="isloading_add || (visible_add=false)" >
         <div class="modal-container">
             <div class="add1" v-show="!isloading_add">
@@ -112,6 +135,9 @@
             <div class="add1" v-show="!isloading_add">
                 <h2>学生学号:</h2> <input type="text" v-model.trim="addOfficalNumber" ></input>
             </div>
+            <div class="add1" v-show="!isloading_add">
+                <h2>电话号码:</h2> <input type="text" v-model.trim="addPhoneNumber" ></input>
+            </div>
             <div class="add1" v-show="isloading_add" 
             :style="{'height': '66%', 'margin-left':'210px'}">
                 <h2>上传中...</h2>
@@ -132,6 +158,8 @@ import { useRoute } from 'vue-router';
 import type {ClassStudentVO} from "@/types/vo";
 import useApis from "@/apis";
 import { get } from 'http';
+import { log } from 'console';
+import { fail } from 'assert';
 
 const route = useRoute()
 const apis = useApis()
@@ -142,15 +170,26 @@ const currentPage = ref(1)
 const searchInput = ref("")
 const visible_add = ref(false)
 const visible_del = ref(false)
+const visible_import = ref(false)
 const isloading = ref(false)
+const isloading_import = ref(false)
 const isloading_add = ref(false)
 const addStudentName = ref("")
 const addOfficalNumber = ref("")
+const addPhoneNumber = ref("")
 const deleteId = ref(-1)
 const deleteIds = ref<number[]>([])
 const deleteName = ref("")
 const hoverStuId = ref(-1)
 const isSingleDelete = ref(true)
+let totalImport = 0
+let successImport = 0
+let failedImport = 0
+let skippedImport = 0
+let failedName = []
+let failedOfficialNumber = []
+let skippedName = []
+let skippedOfficialNumber = []
 
 const StudentsDataLoading = ref(false)
 
@@ -164,7 +203,7 @@ const handleDelete = (sid) => {
     }).stuName
 }
 const importData = async () => {
-    console.log("importData");
+    // console.log("importData");
     const input = document.createElement('input')
     input.type = 'file'
     input.accept = '.xlsx,.xls,.csv'
@@ -177,8 +216,33 @@ const importData = async () => {
         }
         isloading_add.value = true
         try {
+            isloading_import.value = true
+            visible_import.value = true
+            failedName = []
+            failedOfficialNumber = []
+            skippedName = []
+            skippedOfficialNumber = []
             const res = await apis.importStudentsOfClass(classId, selectedFile)
+            totalImport= res.data.data.total
+            successImport = res.data.data.successCount
+            failedImport = res.data.data.failedCount
+            skippedImport = res.data.data.skippedCount    
+            isloading_import.value = false
             console.log('Import response:', res)
+            // res.data.data.failedCount/skippedCount/successCount/total 弹窗提示总数据:成功多少条,失败多少条,跳过多少条
+            // alert(`总数据:${res.data.data.total},成功${res.data.data.successCount}条,失败${res.data.data.failedCount}条,跳过${res.data.data.skippedCount}条`)
+            // res.data.data.details 是每个学生的导入详情,其中status为状态,FAILED为失败,SUCCESS为成功,SKIPPED为跳过
+            // foreach遍历,将失败的学生的姓名stuName和学号officialNumber展示到弹窗中
+            res.data.data.details.forEach((item) => {
+                if (item.status === 'FAILED') {
+                    failedName.push(item.stuName)
+                    failedOfficialNumber.push(item.officialNumber)
+                }
+                if (item.status === 'SKIPPED') {
+                    skippedName.push(item.stuName)
+                    skippedOfficialNumber.push(item.officialNumber)
+                }   
+            })
             getStudents()
         } catch (error) {
             console.error('Import failed:', error)
@@ -210,10 +274,10 @@ const DeleteStudents = async () => {
 }
 const AddStudent = async () => {
     isloading_add.value = true
-    console.log(addStudentName.value)
-    console.log(+addOfficalNumber.value)
+    console.log(+addOfficalNumber.value,addStudentName.value,addPhoneNumber.value)
     console.log(classId);
-    await apis.addStudentOfClasss(classId,+addOfficalNumber.value)
+    const res = await apis.addStudentOfClasss(classId,+addOfficalNumber.value,addStudentName.value,addPhoneNumber.value)
+    console.log('添加学生反馈',res)
     isloading_add.value = false
     visible_add.value=false
     addStudentName.value = ""
@@ -444,6 +508,28 @@ input[type="checkbox"]:checked {
             align-items: center;
             color:#70bbdb
         }
+        .modal-body {
+            padding: 16px 20px;
+            height: 100%;
+            display: flex;
+            flex-direction: row;
+            justify-content: center;
+            align-items: center;
+            color:#70bbdb;
+            .import-result {
+                /* 可滚动 */
+                overflow-y: auto;
+                height: 100%;
+                /* 隐藏滚动条 */
+                -ms-overflow-style: none;
+                scrollbar-width: none;
+                /* 划到最底下但最底下的被遮盖住了一大部分 */
+                ::-webkit-scrollbar {
+                    display: none;
+                }
+            }
+
+        }
         .modal-footer {
             padding: 12px 20px;
             height: 50%;