Browse Source

Merge branch 'develop3.0' of http://106.12.23.251:10080/TEAMMODEL/TEAMModelOS into develop3.0

jeff 4 years ago
parent
commit
6e0004aaf4

+ 31 - 21
TEAMModelOS/ClientApp/src/api/login.js

@@ -126,30 +126,40 @@ export default {
 				pw: item.pw
 			}
 
+			let error = '';
+
 			// 進行API呼叫
 			await this.studLoginbyIES(data).then(res => {
-				console.log('studLogin studLoginbyIES res:')
-				console.log(res)
-				// 儲存大雲Token
-				localStorage.setItem("auth_token", res.auth_token)
-				store.dispatch('user/setSchoolCode', data.school_code)
-				// store.dispatch('user/setStudentProfile', res) // 暫時註解 要是有再補寫
-				result = res
-			})
-
-			let auth = jwtDecode(result.auth_token)
-			// 一樣要存auth_token
-			localStorage.setItem("auth_token", result.auth_token)
-
-			// 預計返回內容
-			let info = {
-				id: result.id,
-				roles: ['student'],
-				permissions: auth.permissions == null ? [] : auth.permissions,
-				picture: ''
-			}
+				if(res.error == 0){
+					// 儲存大雲Token
+					localStorage.setItem("auth_token", res.auth_token)
+					store.dispatch('user/setSchoolCode', data.school_code)
+					// store.dispatch('user/setStudentProfile', res) // 暫時註解 要是有再補寫
+					result = res
+				} else {
+					error = res
+				}
+			}).catch(err=>{
+                error = err
+            })
 
-			resolve(info)
+			if(error == ''){
+				let auth = jwtDecode(result.auth_token)
+				// 一樣要存auth_token
+				localStorage.setItem("auth_token", result.auth_token)
+	
+				// 預計返回內容
+				let info = {
+					id: result.id,
+					roles: ['student'],
+					permissions: auth.permissions == null ? [] : auth.permissions,
+					picture: ''
+				}
+	
+				resolve(info)
+			} else {
+				reject(error)
+			}		
 		})
 	},
 	// 取得學校名稱

+ 14 - 15
TEAMModelOS/ClientApp/src/api/stuAccount.js

@@ -24,7 +24,20 @@ export default {
             "schoolId": schoolId.toLowerCase(),
             "students": []
         }
-        format.students.push(data)
+        format.students.push(...data)
+        return post('/api/Student/student-manage', format)
+    },
+    /**
+     * 刪除學生
+     * @param {any} data
+     */
+    deleteStudent: function(schoolId, data) {
+        let format = {
+            "grant_type": "delete",
+            "schoolId": schoolId.toLowerCase(),
+            "students": []
+        }
+        format.students.push(...data)
         return post('/api/Student/student-manage', format)
     },
     updateStudent: function(data) {
@@ -33,18 +46,4 @@ export default {
     updateAllStudent: function(data) {
         return post('/api/Student/upsertAll', data)
     },
-    /**
-     * ����ɾ��ѧ��
-     * @param {any} data
-     */
-    deleteStudent: function(data) {
-        return post('/api/Student/delete', data)
-    },
-    /**
-     * ����ɾ��ѧ��
-     * @param {any} data
-     */
-    deleteAllStudent: function (data) {
-        return post('/api/Student/BulkDelete', data)
-    }
 }

+ 19 - 5
TEAMModelOS/ClientApp/src/store/module/schoolBaseInfo.js

@@ -26,13 +26,21 @@ export default {
             state.classroomList = data
         },
         setStudents(state, data) {
+            state.students = data
+        },
+        addStudents(state, data) {
             state.students.push(...data)
         },
         uptStudents(state, data) {
-            data.forEach(function(uptItem){
-                state.students.forEach(function(orgItem){
-
-                })
+            data.forEach(function(item){
+                let objIndex = state.students.findIndex((obj => obj.id == item.id));
+                state.students[objIndex] = item
+            })
+        },
+        delStudents(state, data) {
+            data.forEach(function(item){
+                let objIndex = state.students.findIndex((obj => obj.id == item));
+                state.students.splice(objIndex, 1);
             })
         }
     },
@@ -153,8 +161,14 @@ export default {
         setStudentsToState(context, data) {
             context.commit('setStudents', data)
         },
+        addStudentsToState(context, data) {
+            context.commit('addStudents', data)
+        },
         uptStudentsToState(context, data) {            
             context.commit('uptStudents', data)
-        }
+        },
+        delStudentsToState(context, data) {            
+            context.commit('delStudents', data)
+        },
     }
 }

+ 4 - 0
TEAMModelOS/ClientApp/src/view/login/Index.less

@@ -3,6 +3,10 @@
     display: flex;
     align-items: center;
     flex-direction: column;
+    .iconFrame:before{
+        border-radius: 50%;
+        border: 1px solid #808695;
+    }
     .schoolName{
         letter-spacing: 7px;
         height: 120px;

+ 12 - 80
TEAMModelOS/ClientApp/src/view/login/Index.vue

@@ -96,13 +96,13 @@
         </h4>
 
         <div v-show="!qrloginFlag">
-          <Form class="loginForm" ref="loginForm" :model="loginForm" :rules="loginRule" :show-message="false">
+          <Form class="loginForm" ref="loginForm" :model="loginForm" :rules="loginRule" :show-message="false" @keydown.enter.native="loginSubmit('loginForm')">
             <FormItem class="formItem" prop="id" >
-              <Input v-model="loginForm.id" :placeholder="$t('login.placeholder.id')"/>
+              <Input element-id = "tmdID" v-model="loginForm.id" :placeholder="$t('login.placeholder.id')"/>
             </FormItem>
             <FormItem class="formItem"  prop="pass">
-              <Input  type="password" v-model="loginForm.pass" :placeholder="$t('login.placeholder.psw')" >
-                <Icon size="24" v-show="!loading && loginFormEnter" @click="loginSubmit('loginForm')" type="md-arrow-forward" slot="suffix" />
+              <Input element-id = "tmdpw" type="password" v-model="loginForm.pass" :placeholder="$t('login.placeholder.psw')" >
+                <Icon size="24" v-show="!loading && loginFormEnter" @click="loginSubmit('loginForm')" type="md-arrow-forward" slot="suffix" class="iconFrame" />
                 <div v-show="loading" class="demo-spin-col" slot="suffix">
                   <Spin>
                     <Icon type="ios-loading" size="18" class="demo-spin-icon-load"></Icon>
@@ -176,7 +176,7 @@
         </Tooltip>
       </div>
       <h4 class="subTitle">{{ $t('login.subTitle.schoolLogin') }}</h4>
-      <Form class="loginForm" ref="studForm" :model="studForm" :rules="studRule" :show-message="false">
+      <Form class="loginForm" ref="studForm" :model="studForm" :rules="studRule" :show-message="false" @keydown.enter.native="loginSubmit('studForm')">
         <FormItem class="formItem" style="margin-bottom: 15px;" prop="schoolCode">
           <Select v-show="!defaultSchool.code" v-model="studForm.schoolCode" :placeholder="$t('login.placeholder.schoolMenu')" filterable clearable >
             <template v-for="(item, index) in schoolList" >
@@ -187,12 +187,12 @@
           </Select>
         </FormItem>
         <FormItem class="formItem" prop="id" >
-          <Input v-model="studForm.id" :placeholder="$t('login.placeholder.schoolID')"/>
+          <Input element-id = "studId" v-model="studForm.id" :placeholder="$t('login.placeholder.schoolID')"/>
         </FormItem>
         <FormItem class="formItem"  prop="pass">
-          <Input  type="password" v-model="studForm.pass" :placeholder="$t('login.placeholder.schoolPsw')" >
+          <Input element-id = "studpw"  type="password" v-model="studForm.pass" :placeholder="$t('login.placeholder.schoolPsw')" >
             <!-- <Icon v-show="studFormEnter" @click="loginSubmit('studForm')" type="md-arrow-forward" slot="suffix" /> -->
-            <Icon size="24" v-show="!loading && studFormEnter" @click="loginSubmit('studForm')" type="md-arrow-forward" slot="suffix" />
+            <Icon size="24" v-show="!loading && studFormEnter" @click="loginSubmit('studForm')" type="md-arrow-forward" slot="suffix" class="iconFrame" />
             <div v-show="loading" class="demo-spin-col" slot="suffix">
               <Spin>
                 <Icon type="ios-loading" size="18" class="demo-spin-icon-load"></Icon>
@@ -423,8 +423,9 @@ export default {
                 isFail = true
               })
 
+
               if(isFail){
-                this.studErrorText = this.$t('login.apiError.text1')
+                this.schoolErrText = this.$t('login.apiError.text1')
                 this.loading = false
               } else {
                 //設定權限並登入
@@ -436,77 +437,8 @@ export default {
                 })
               }              
               break;
-          }
-          
-return false;
-
-
-// 取得目前學校的權限
-
-// 沒有加入過任何一間大雲學校,直接到選擇學校頁面
-
-          // if(result.error){
-          //   this.loginErrText = this.$t('login.apiError.text1')
-          // } else {
-          //   let t_Data = this.$jwtDecode(result.id_token)
-          //   let id_token = result.id_token
-
-
-
-
-
-
-
-          //   // 整理符合登入的內容
-          //   let userDetails = result.filter(function(item){
-          //     return parseInt(item.joinStatus) == 1
-          //   })
-          //   // 沒有符合的學校
-          //   if(userDetails.length === 0){
-          //     let userAccess = {
-          //       id: t_Data.sub,
-          //       role: [],
-          //       authority: [],
-          //       picture: t_Data.picture ? t_Data.picture : ''
-          //     }
-
-          //     User.login(userAccess).then(res => {
-          //       if(res) {
-          //         // 沒有加入過任何一間大雲學校,直接到選擇學校頁面
-          //         this.$router.push({ name: 'schoolList' })
-          //       }
-          //     })
-          //   } else {
-          //     // 設定user詳細資訊
-          //     this.$store.dispatch('user/setUserProfile', userDetails)
-
-          //     let _this = this
-          //     let loginSchoolData = userDetails.filter(function(item){
-          //       return item.schoolCode == _this.loginSchooCode
-          //     })
-
-          //     // 檢查登入過的痕跡
-          //     if(loginSchoolData.length === 0){
-          //       // 以第一筆登入
-          //       let firstSchoolInfo =  userDetails[0]
-          //       // 設定此瀏覽器的學校簡碼
-          //       this.$store.dispatch('user/setSchoolCode', firstSchoolInfo.schoolCode)
-
-          //       // 設定權限並登入
-          //       User.login(firstSchoolInfo).then(res => {
-          //         if(res) {
-          //           this.$router.push({ path: '/home' })
-          //         }
-          //       })
-          //     } else {
-          //       User.login(loginSchoolData[0]).then(res => {
-          //         if(res) {
-          //           this.$router.push({ path: '/home' })
-          //         }
-          //       })
-          //     }
-          //   }
-          // }
+          }          
+          return false;
         }
       })
     },

+ 69 - 71
TEAMModelOS/ClientApp/src/view/student-account/AddStudent.vue

@@ -142,10 +142,10 @@
                     <span style="color:white;">{{ gradeName }}</span>
                 </FormItem>
             </div>
-            <div style="display:flex;justify-content: space-between;">
+            <div style="display:flex;justify-content: space-between;" v-if="editStudentInfo.length == 1">
                 <!-- 學年度 -->
                 <FormItem :label="$t('stuAccount.academicYear')" prop="year" style="width:45%">
-                    <InputNumber v-model="editStudentInfo[0].year" :editable="false"></InputNumber>
+                    <Input v-model="editStudentInfo[0].year" disabled></Input>
                 </FormItem>
             </div>
         </Form>
@@ -296,44 +296,7 @@
                     } else {
                         this.gradeName = res.name
                     }
-                })
-                if (this.bizType == 1) {
-                    
-                    
-                } else {
-
-                }
-            },
-            getCurrentClassroom(index) {
-                //bizType:1 新增
-                if (this.bizType == 1) {
-                    // this.studentInfo.classroomName = this.classroomList[index].classroomName
-                    // this.studentInfo.periodCode = this.classroomList[index].periodCode;
-                    // this.studentInfo.gradeCode = this.classroomList[index].gradeCode;
-                    // this.studentInfo.classId = this.classroomList[index].classId;
-                    // let currentInfo = this.$JSONPath.query(this.$store.state.schoolBaseInfo.schoolBaseInfo, "$..period[?(@.periodCode=='" + this.classroomList[index].periodCode + "')]")
-
-                    // if (currentInfo.length > 0) {
-                    //     this.studentInfo.periodName = currentInfo[0].periodName
-                    //     this.studentInfo.gradeName = this.$JSONPath.query(currentInfo, "$..grades[?(@.gradeCode=='" + this.classroomList[index].gradeCode + "')]")[0].gradeName
-                    // }
-
-                } else {
-                    // let currentInfo = this.$JSONPath.query(this.$store.state.schoolBaseInfo.schoolBaseInfo, "$..period[?(@.periodCode=='" + this.classroomList[index].periodCode + "')]")
-                    // let periodName = '数据错误'
-                    // let gradeName = '数据错误'
-                    // if (currentInfo.length > 0) {
-                    //     periodName = currentInfo[0].periodName
-                    //     gradeName = this.$JSONPath.query(currentInfo, "$..grades[?(@.gradeCode=='" + this.classroomList[index].gradeCode + "')]")[0].gradeName
-                    // }
-                    // for (let i = 0; i < this.editStudentInfo.length; i++) {
-                    //     this.editStudentInfo[i].periodCode = this.classroomList[index].periodCode
-                    //     this.editStudentInfo[i].gradeCode = this.classroomList[index].gradeCode
-                    //     this.editStudentInfo[i].classId = this.classroomList[index].classId
-                    //     this.$set(this.editStudentInfo[i],'periodName',periodName)
-                    //     this.$set(this.editStudentInfo[i],'gradeName',gradeName)
-                    // }
-                }
+                })   
             },
             getClassroom() {
                 this.classroomList = this.$store.state.schoolBaseInfo.classroomList
@@ -355,35 +318,58 @@
                     this.same = false
                     if (this.bizType == 2) {
                         this.isLoading = true
-                        let editInfo = this.editStudentInfo.map(function(item){
-                            let itemTemp = item
-                            if(itemTemp.pw == '******') {
-                                delete itemTemp.pw
-                            }
-                            return itemTemp
-                        })
+                        var editInfo = this.editStudentInfo
 
-                        this.$api.stuAccount.saveAllStudent(this.schoolCode, this.editStudentInfo).then(
-                            (res) => {
-                                if (res.error == null) {
-                                    this.show = false
-                                    this.$emit('saveStudentInfo', {
-                                        action: 2, // 批量修改数据
-                                        studentInfo: this.editStudentInfo
-                                    })
-                                    this.$refs.updateForm.resetFields()
-                                    // this.initData();
-                                    this.uploadLoading = false
-                                } else {
-                                    this.$Message.error('API error!')
-                                }
-                                this.isLoading = false
-                            },
-                            (err) => {
-                                this.$Message.error('API error!')
+                        let stringify = JSON.stringify(this.editStudentInfo)
+                        let parse = JSON.parse(stringify)
+                        let apiData = []
+                        if(parse.length == 1){
+                            parse.forEach(function(item){
+                                item.year = item.year ? item.year.toString() : ''
+                                item.no = item.no ? item.no.toString() : ''
+                            })                            
+
+                            if(this.isRepeat(parse[0])){
+                                this.$Message.error('請檢查 帳號資訊 或 座號重複 了。')
                                 this.isLoading = false
+                            } else {
+                                apiData = parse
                             }
-                        )
+                        } else {
+                            let classId = parse[0].classId
+                            let temp = parse.map(function(item){
+                                return {
+                                    no : "",
+                                    id: item.id,
+                                    classId: classId,
+                                    name: item.name,
+                                    year: item.year ? item.year.toString() : ''
+                                }
+                            }) 
+                            apiData = temp
+                        }
+                        if(apiData.length > 0){
+                            this.$api.stuAccount.saveAllStudent(this.schoolCode, apiData).then(
+                                (res) => {
+                                    if (res.error == null) {
+                                        this.show = false
+                                        this.$emit('saveStudentInfo', {
+                                            action: 2, // 批量修改数据
+                                            studentInfos: res.students
+                                        })
+                                        this.$refs.updateForm.resetFields()
+                                        this.uploadLoading = false
+                                    } else {
+                                        this.$Message.error('API error!')
+                                    }
+                                    this.isLoading = false
+                                },
+                                (err) => {
+                                    this.$Message.error('API error!')
+                                    this.isLoading = false
+                                }
+                            )
+                        }
                     } else {
                         this.isLoading = true
 
@@ -398,14 +384,10 @@
                             // "className":this.studentInfo.classroomName ? this.studentInfo.classroomName : ''
                         }
 
-                        let isRepeat= this.students.some(function(item){                            
-                            return (item.id === apiData.id || (apiData.classId !='' && apiData.classId === item.classId && apiData.no === item.no))
-                        })
-                        if(isRepeat){
+                        if(this.isRepeat(apiData)){
                             this.$Message.error('請檢查 帳號資訊 或 座號重複 了。')
                             this.isLoading = false
                         } else {
-
                             this.$api.stuAccount.saveStudent(this.schoolCode, apiData).then(
                                 (res) => {
                                     if (res.error == null) {
@@ -433,6 +415,22 @@
                 this.$router.push({
                     path: '/school/classroom'
                 })
+            },
+            isRepeat(data){
+                if(this.bizType == 1){
+                    return this.students.some(function(item){
+                        return (item.id === data.id || (data.classId !='' && data.classId === item.classId && data.no === item.no))
+                    })
+                } else if(this.bizType == 2){
+                    let temp = this.students.filter(function(item){
+                        return (data.classId !='' && data.classId === item.classId && data.no === item.no)
+                    })
+                    if(temp.length > 0){
+                        return !(temp[0].id == data.id)
+                    } else {
+                        return false
+                    }
+                }                
             }
         },
         created() {

+ 24 - 0
TEAMModelOS/ClientApp/src/view/student-account/IImportStudent.less

@@ -135,3 +135,27 @@
     border: none;
     padding: 0px;
 }
+.importAcademicYear{
+    z-index: 1;
+    position: absolute;
+    left: 24px;
+    top: 8px;
+    overflow: hidden;
+    cursor: pointer;
+    display: flex;
+    align-items: center;
+}
+.importAcademicYear .label{
+    color: #7d7d7d;
+    margin-right: 5px;
+    font-size: 16px;
+}
+.importAcademicYear .ivu-input-number{
+    border-color: #7d7d7d;
+}
+.importAcademicYear .ivu-input-number-input{
+    border: 1px solid #7d7d7d;
+    color: #7d7d7d;
+    font-size: 16px;
+    background-color: #383838;
+}

+ 6 - 2
TEAMModelOS/ClientApp/src/view/student-account/ImportStudent.less

@@ -46,14 +46,18 @@
     }
 
     & > &-item:nth-child(4) {
-        color: #1CCC9E;
+        color: #ed6565;
     }
 
     & > &-item:nth-child(5) {
-        color: #E1B551;
+        color: #1CCC9E;
     }
 
     & > &-item:nth-child(6) {
+        color: #E1B551;
+    }
+
+    & > &-item:nth-child(7) {
         color: #11fd03;
     }
     /*& > &-item:last-child {

+ 50 - 9
TEAMModelOS/ClientApp/src/view/student-account/ImportStudent.vue

@@ -37,7 +37,11 @@
                     <span class="table-info-label">{{$t('stuAccount.importInfo4')}}</span>
                     <span class="table-info-num">{{noClassroomNum}}</span>
                 </div>
-
+                <div class="table-info-item" v-if="noSeatNoNum != 0">
+                    <span class="table-info-label">{{$t('沒有座號:')}}</span>
+                    <span class="table-info-num">{{noSeatNoNum}}</span>
+                </div>
+            
                 <div class="table-info-item" v-if="existNum != 0">
                     <span class="table-info-label">{{$t('stuAccount.importInfo5')}}</span>
                     <span class="table-info-num">{{existNum}}</span>
@@ -55,9 +59,11 @@
                     <p>{{(row.password == '' || row.password == null)? '— —' : row.password.value+''}}</p>
                 </template>
                 <template slot-scope="{ row,index }" slot="status">
-                    <p :class="(repeatAccounts.length == 0 || repeatAccounts.indexOf(row.account) == -1) ? 'account-success-tips':'account-error-tips'">{{(repeatAccounts.length == 0 || repeatAccounts.indexOf(row.account) == -1)?"":"错误:账号重复!" }}</p>
+                    <p :class="(repeatAccounts.length == 0 || repeatAccounts.indexOf(row.studentId) == -1) ? 'account-success-tips':'account-error-tips'">{{(repeatAccounts.length == 0 || repeatAccounts.indexOf(row.studentId) == -1)?"":"错误:账号重复或已存在学校里!" }}</p>
                     <p :class="(row.classroomCode == '' || row.classroomCode == null) ? 'account-warning-tips':''">{{(row.classroomCode == '' || row.classroomCode == null)?"警告 :未找到指定班级":"" }}</p>
-                    <p :class="row.seatRepeat? 'account-error-tips':''">{{row.seatRepeat ? "错误:座位号重复":"" }}</p>
+                    <p :class="row.seatRepeat? 'account-error-tips':''">{{row.seatRepeat ? "错误:座位号重复或已存在於校內":"" }}</p>
+                    <p :class="(row.seatNo == '' || row.seatNo == null) ? 'account-warning-tips':''">{{(row.seatNo == '' || row.seatNo == null)?"警告 :沒有座號":"" }}</p>
+
                 </template>
             </Table>
             <p style="margin-top:15px;">{{$t('stuAccount.passwordTips')}}</p>
@@ -69,6 +75,7 @@
 </template>
 <script>
     import excel from '../../utils/excel'
+    import {  mapGetters } from 'vuex'
     export default {
         props: {
             isShow: {
@@ -78,6 +85,9 @@
             schoolCode: {
                 type: String,
                 default: ''
+            },
+            academicYear: {
+                type: Number,
             }
         },
         data() {
@@ -88,6 +98,7 @@
                 existNum: 0,
                 repeatAccounts: [],
                 noClassroomNum: 0,
+                noSeatNoNum: 0,
                 uploadLoading: false,
                 progressPercent: 0,
                 showProgress: false,
@@ -111,8 +122,11 @@
         components: {
         },
         computed: {
+            ...mapGetters({
+                students: 'schoolBaseInfo/getStudent', // 學生List
+            }),
             isError() {
-                return this.seatRepeatNum + this.repeatNum + this.existNum + this.noClassroomNum
+                return this.seatRepeatNum + this.repeatNum + this.existNum + this.noClassroomNum + this.noSeatNoNum
             },
             show: {
                 get() {
@@ -121,7 +135,6 @@
                 set(value) {
                 }
             }
-
         },
         watch: {
         },
@@ -137,7 +150,7 @@
                 if (!(this.repeatAccounts.length == 0 || this.repeatAccounts.indexOf(row.studentId) == -1) || row.seatRepeat) {
                     className = className + 'account-error-row-bg '
                 }
-                if (row.classroomCode == '' || row.classroomCode == null) {
+                if (row.classroomCode == '' || row.classroomCode == null || row.seatNo == '' || row.seatNo == null) {
                     className = className + 'account-warning-row-bg'
                 }
                 return className
@@ -228,11 +241,19 @@
                             }
                             return item
                         })
+
+                        // 現在的學生List
+                        let studIDs = this.students.map(item => { return item.id })
+
                         // 计算重复账号数量和重复账号,过滤重复账号
                         this.totalNum = this.tableData.length
+                        // 取得Excel 全部的ID
                         let accounts = this.tableData.map(item => { return item.studentId })
-                        this.repeatAccounts = accounts.filter((item, index, self) => self.indexOf(item) != index)
+                        // 合併
+                        let cocatIds = studIDs.concat(accounts);
+                        this.repeatAccounts = cocatIds.filter((item, index, self) => self.indexOf(item) != index)
                         this.repeatAccounts = this.repeatAccounts.filter((item, index, self) => self.indexOf(item) === index)
+
                         // 直接过滤重复账号
                         // this.tableData = this.tableData.filter((item, index, self) => {
                         //  if (accounts.indexOf(item.account) === index) {
@@ -243,8 +264,10 @@
                         // });
                         accounts = accounts.filter((item, index, self) => self.indexOf(item) === index)
                         this.repeatNum = this.totalNum - accounts.length + this.repeatAccounts.length
+
                         // 根据班级Code GroupBy,判断班级座位号是否重复
                         let classStu = this.groupBy(this.tableData, 'classroomCode')
+
                         for (let item of classStu) {
                             let seatNoArr = item.map(item => { return item.seatNo })
                             for (let index in item) {
@@ -264,6 +287,12 @@
                         // 筛选没有班级账号
                         let noRoom = this.tableData.filter(item => { return (item.classroomCode == '' || item.classroomCode == null) })
                         this.noClassroomNum = noRoom.length
+
+                        // 筛选沒有座號
+                        let noSeatNo = this.tableData.filter(item => { return (item.seatNo == '' || item.seatNo == null) })
+                        this.noSeatNoNum = noSeatNo.length
+
+                        //整理TtableData
                         this.tableData.map((item, index) => {
                             let val = item.password
                             item.password = {}
@@ -273,6 +302,18 @@
                             item.password['value'] = val
                             return item
                         })
+
+                        // 檢查與現在的學生名單同教室裡是否有重複座號
+                        this.tableData.forEach( (item) => {
+                            let studdd = this.students.filter( (studInfo) => {
+                                return (item.classroomCode == studInfo.classId && item.seatNo == studInfo.no)
+                            })
+                            if(studdd.length > 0) {
+                                item.seatRepeat = true
+                                this.seatRepeatNum++
+                            }
+                        })
+                        
                         this.$Message.info(this.$t('stuAccount.importTips11'))
                         this.tableLoading = false
                     } else {
@@ -362,6 +403,7 @@
                 this.seatRepeatNum = 0
                 this.repeatAccounts = []
                 this.noClassroomNum = 0
+                this.noSeatNoNum = 0
                 this.uploadLoading = false
                 this.progressPercent = 0
                 this.showProgress = false
@@ -410,10 +452,9 @@
             this.initData()
         },
         mounted() {
-
         },
         watch: {
-
+            
         }
     }
 </script>

+ 98 - 128
TEAMModelOS/ClientApp/src/view/student-account/Index.vue

@@ -47,7 +47,7 @@
                         <Icon type="md-create" :color="selections.length > 0 ? 'white':'#606060'" size="18" />
                         <span>{{ $t('stuAccount.editInfo') }}</span>
                     </li>
-                    <li @click="resetPW()" :class=" selections.length > 0 ? '':'sc-disable-cursor' ">
+                    <li @click="resetPW(-1)" :class=" selections.length > 0 ? '':'sc-disable-cursor' ">
                         <Icon custom="iconfont icon-reset" :color="selections.length > 0 ? 'white':'#606060'" size="18" />
                         <span>重置密码</span>
                     </li>
@@ -77,19 +77,16 @@
                     <template slot-scope="{ row }" slot="gradeName">
                         <span>{{row.gradeName}}</span>
                     </template>
-                    <template slot-scope="{ row,index }" slot="action">
+                    <template slot-scope="{ row }" slot="action">
                         <div class="item-tools" v-if="$access.can('admin.*|student-upd')">
                             <Icon type="md-create" size="18" color="white" @click="editStudent(row)" />
-                            <Icon custom="iconfont icon-reset" size="18" color="white" @click="resetPW(index)" />
-                            <Icon type="md-trash" size="18" color="white" @click="delStudent(index)" />
+                            <Icon custom="iconfont icon-reset" size="18" color="white" @click="resetPW(row)" />
+                            <Icon type="md-trash" size="18" color="white" @click="delStudent(row)" />
                         </div>
                     </template>
                 </Table>
             </Scroll>
-            <!-- <div class="page-box dark-iview-page">
-                <Page :total="totalNum" show-sizer :page-size="pageSize" show-total :current.sync="currentPage" @on-change="getPageData" @on-page-size-change="setPageSize"/>
-            </div>
-            <authorization :isShow="authorizationStatus" @closeAuth="closeAuth" :selected="selections"></authorization> -->
+            <authorization :isShow="authorizationStatus" @closeAuth="closeAuth" :selected="selections"></authorization> 
         </div>
 
         <Modal v-model="addStudentStatus" width="520" class-name="add-student dark-iview-modal" :mask-closable="false">
@@ -100,8 +97,12 @@
         <Modal v-model="importStudentStatus" width="70%" class="import-student" :mask-closable="false">
             <div slot="header">
                 <span class="import-model-title">{{$t('stuAccount.importTitle')}}</span>
+                <div class="importAcademicYear">
+                    <span class="label">學年度:</span>
+                    <InputNumber v-model="academicYear" :editable="false"></InputNumber>
+                </div>
             </div>
-            <import-student v-if="importStudentStatus" :schoolCode="$store.state.user.schoolCode" :isShow="importStudentStatus" @importStudentInfo="closeImportStudent"></import-student>
+            <import-student v-if="importStudentStatus" :schoolCode="$store.state.user.schoolCode" :isShow="importStudentStatus" @importStudentInfo="closeImportStudent" :academicYear="academicYear"></import-student>
             <div slot="footer"></div>
         </Modal>
     </div>
@@ -147,12 +148,68 @@
                 tableColumns: [],
                 queryToken:'',
                 basicCount: 99,
-                pointNum: 0
+                pointNum: 0,
+                academicYear: new Date().getFullYear()
             }
         },
         methods: {
-            resetPW() {
-
+            /**
+             * 重置密碼
+             * @param row
+             */
+            resetPW(row) {
+                //重置单个学生
+                if (row != -1) {
+                    this.$Modal.confirm({
+                        title: this.$t('重置密碼'),
+                        content: '<p>' + this.$t('確定要重置') + " <strong style='color:red;'>" + row.name + '</strong>的密碼</p>',
+                        onOk: () => {
+                            let ids = []
+                            ids.push(
+                                {
+                                    id: row.id,
+                                    pw: row.id
+                                }
+                            )
+                            this.tableLoading = true
+                            this.$api.stuAccount.saveAllStudent(this.$store.state.user.schoolCode , ids).then(
+                                (res) => {
+                                    this.$Message.success('重置成功!')                                    
+                                    this.tableLoading = false
+                                },
+                                (err) => {
+                                    this.$Message.error('API error!')
+                                    this.tableLoading = false
+                                }
+                            )
+                        }
+                    })
+                } else {
+                    //批量重置
+                    if (this.selections.length > 0) {
+                        this.$Modal.confirm({
+                            title: this.$t('重置密碼'),
+                            content: '<p>确认批量重置' + " <strong style='color:red;'>" + this.selections.length + '</strong>个学生密碼</p>',
+                            onOk: () => {
+                                this.tableLoading = true
+                                let ids = this.selections.map((item) => {
+                                    return {id: item.id, pw: item.id}
+                                })
+                                this.$api.stuAccount.saveAllStudent(this.$store.state.user.schoolCode, ids).then(
+                                    (res) => {
+                                        this.selections.length = 0
+                                        this.$Message.success('重置成功!')
+                                        this.tableLoading = false
+                                    },
+                                    (err) => {
+                                        this.$Message.error('API ERROR!')
+                                        this.tableLoading = false
+                                    }
+                                )
+                            }
+                        })
+                    }
+                }
             },
             getFirstChart(name) {
                 if (name) {
@@ -161,14 +218,6 @@
                     return '--'
                 }
             },
-            getGradeList(index) {
-console.log(index, 'getGradeList')
-                // this.gradeList = this.schoolData.period[index].grade
-                // this.classroomShowList = this.classroomList.filter((item) => { return item.period == this.schoolData.period[index].code })
-                // if (this.classroomShowList.length == 0) {
-                //     this.$refs.classroom.clearSingleSelect()
-                // }
-            },
             getClassroomList(index) {
                 this.classroomShowList = this.classroomList.filter((item) => { return item.grade == this.gradeList[index].code })
                 if (this.classroomShowList.length == 0) {
@@ -210,11 +259,13 @@ console.log(index, 'getGradeList')
                 let newStudents = data.studentInfos.map(function(item){
                     let temp = item
                     temp.pw = '******'
+                    temp.year = parseInt(temp.year)
                     return temp
                 })
-                let storePath = (data.action == 1 ? 'schoolBaseInfo/setStudentsToState' : 'schoolBaseInfo/uptStudentsToState')
+                let storePath = (data.action == 1 ? 'schoolBaseInfo/addStudentsToState' : 'schoolBaseInfo/uptStudentsToState')
                 this.$store.dispatch(storePath, newStudents)
                 this.addStudentStatus = false
+                this.filterData()
             },
             closeImportStudent(data) {
                 this.findStudentInfo()
@@ -240,16 +291,19 @@ console.log(index, 'getGradeList')
                 if (index != undefined) {
                     this.editStudentInfo = []
                     index.year = parseInt(index.year)
-                    this.editStudentInfo.push(index)
-                    
-                    // this.tableShowData[index]._checked = true
-                    // this.$forceUpdate()
+                    // 避免被深拷貝
+                    let obj = JSON.parse(JSON.stringify(index))
+                    this.editStudentInfo.push(obj)
+
                     this.addStudentStatus = true
                 } else {
-                    console.log(this.selections, 'selections')
                     if (this.selections.length > 0) {
                         this.editStudentInfo.length = 0
                         this.editStudentInfo = [...this.selections]
+
+                        // 多筆設定拿掉classId
+                        this.editStudentInfo[0].classId = ''
+
                         this.addStudentStatus = true
                     }
                     else {
@@ -259,30 +313,24 @@ console.log(index, 'getGradeList')
             },
             /**
              * 删除学生
-             * @param index
              * @param row
              */
-            delStudent(index, row) {
+            delStudent(row) {
                 //删除单个学生
-                if (index >= 0) {
+                if (row != -1) {
                     this.$Modal.confirm({
                         title: this.$t('stuAccount.tips2Title'),
-                        content: '<p>' + this.$t('stuAccount.tips2Content1') + " <strong style='color:red;'>" + this.tableShowData[index].name + '</strong></p>',
+                        content: '<p>' + this.$t('stuAccount.tips2Content1') + " <strong style='color:red;'>" + row.name + '</strong></p>',
                         onOk: () => {
+                            let delIds = []
+                            delIds.push({id: row.id})
                             this.tableLoading = true
-                            this.$api.stuAccount.deleteStudent(this.tableShowData[index]).then(
+
+                            this.$api.stuAccount.deleteStudent(this.$store.state.user.schoolCode , delIds).then(
                                 (res) => {
-                                    if (res.error == null) {
-                                        //分页查询后,直接重新访问API
-                                        let findCountParams = {
-                                            "collectionName": "Student",
-                                            "queryDict": {
-                                                'code': this.$store.state.user.schoolCode
-                                            }
-                                        }
-                                        this.getResultCount(findCountParams)
-                                        this.findStudentInfo()
-                                    }
+                                    this.$store.dispatch('schoolBaseInfo/delStudentsToState', res.ids)
+                                    this.filterData()
+                                    this.$Message.success('删除成功!')                                    
                                     this.tableLoading = false
                                 },
                                 (err) => {
@@ -300,29 +348,16 @@ console.log(index, 'getGradeList')
                             content: '<p>确认批量删除' + " <strong style='color:red;'>" + this.selections.length + '</strong>个学生</p>',
                             onOk: () => {
                                 this.tableLoading = true
-                                let ids = this.selections.map((item, index) => {
-                                    return item.id
+                                let delIds = this.selections.map((item) => {
+                                    return {id: item.id}
                                 })
-                                this.$api.stuAccount.deleteAllStudent({
-                                    id: ids,
-                                    code:this.$store.state.user.schoolCode
-                                }).then(
+                                this.$api.stuAccount.deleteStudent(this.$store.state.user.schoolCode, delIds).then(
                                     (res) => {
-                                        if (res.error == null) {
-                                            //分页查询后,直接重新访问API
-                                            this.selections.length = 0
-                                            let findCountParams = {
-                                                "collectionName": "Student",
-                                                "queryDict": {
-                                                    'code': this.$store.state.user.schoolCode
-                                                }
-                                            }
-                                            this.getResultCount(findCountParams)
-                                            this.findStudentInfo()
-                                            this.$Message.success('删除成功!')
-                                        } else {
-                                            this.$Message.error('API ERROR!')
-                                        }
+                                        //分页查询后,直接重新访问API
+                                        this.selections.length = 0
+                                        this.$store.dispatch('schoolBaseInfo/delStudentsToState', res.ids)
+                                        this.filterData()
+                                        this.$Message.success('删除成功!')
                                         this.tableLoading = false
                                     },
                                     (err) => {
@@ -335,22 +370,6 @@ console.log(index, 'getGradeList')
                     }
                 }
             },
-            getSchoolData() {
-                this.$store.dispatch('schoolBaseInfo/getClassroom').then(
-                    (res) => {
-                        if (res.code == 2) {
-                            this.$Message.warning('数据为空!')
-                        } else {
-                            this.schoolData = this.$store.state.schoolBaseInfo.schoolBaseInfo
-                            this.classroomList = this.$store.state.schoolBaseInfo.classroomList
-                            this.findStudentInfo()
-                        }
-                    },
-                    (err) => {
-                        this.$Message.error('API error!')
-                    }
-                )
-            },
             initData() {
                 this.tableColumns = [
                     {
@@ -417,16 +436,6 @@ console.log(index, 'getGradeList')
                     }
                 ]
             },
-            /**查询当前Page学生信息 */
-            findStudentInfo() {
-                // this.tableLoading = true
-                // let params = {
-                //     '@CURRPAGE': this.currentPage,
-                //     '@PAGESIZE': this.pageSize,
-                //     'code': this.$store.state.user.schoolCode,
-                // }
-                // this.baseFindStudent(params)
-            },
             /**基础查询数据 */
             baseFindStudent(params) {
                 this.$api.stuAccount.findStudent(this.$store.state.user.schoolCode).then(
@@ -440,41 +449,12 @@ console.log(index, 'getGradeList')
                         })
                         this.$store.dispatch('schoolBaseInfo/setStudentsToState', newStudents)
                         this.filterData()
-
-                        // if (res.error == null) {
-                        //     this.tableData = res.result.data
-                        //     for (let index in this.tableData) {
-                        //         let currentClassroomlInfo = this.$JSONPath.query(this.$store.state.schoolBaseInfo.classroomList, "$..[?(@.classId=='" + this.tableData[index].classId + "')]")
-                        //         if (currentClassroomlInfo.length > 0) {
-                        //             let currentSchoolInfo = this.$JSONPath.query(this.$store.state.schoolBaseInfo.schoolBaseInfo, "$..period[?(@.periodCode=='" + currentClassroomlInfo[0].periodCode + "')]")
-                        //             if (currentSchoolInfo.length > 0) {
-                        //                 this.tableData[index].periodName = currentSchoolInfo[0].periodName
-                        //                 this.tableData[index].periodCode = currentSchoolInfo[0].periodCode
-                        //                 this.tableData[index].gradeName = this.$JSONPath.query(currentSchoolInfo, "$..grades[?(@.gradeCode=='" + currentClassroomlInfo[0].gradeCode + "')]")[0].gradeName
-                        //                 this.tableData[index].gradeCode = this.$JSONPath.query(currentSchoolInfo, "$..grades[?(@.gradeCode=='" + currentClassroomlInfo[0].gradeCode + "')]")[0].gradeCode
-                        //                 this.tableData[index].classroomName = currentClassroomlInfo[0].classroomName
-                        //             }
-                        //         }
-                        //     }
-                        //     [...this.tableShowData] = this.tableData
-                        //     this.tableLoading = false
-                        // } else {
-                        //     this.$Message.error('API error!')
-                        //     this.tableLoading = false
-                        // }
                     },
                     (err) => {
                         this.tableLoading = false
                     }
                 )
             },
-            /**查询学生总共人数 */
-            getResultCount(params) {
-                
-                // this.$api.newEvaluation.FindCount(params).then(res => {
-                //     this.totalNum = res.result.data[0]
-                // })
-            },
             /** 取得年級Name */
             getGradeName: function(periodId, gradeId){
                 if(periodId != null && gradeId != null){
@@ -552,15 +532,6 @@ console.log(index, 'getGradeList')
         created() {
             this.initData()
             this.baseFindStudent()
-
-            // this.getSchoolData()
-            // let findCountParams = {
-            //     "collectionName": "Student",
-            //     "queryDict": {
-            //         'code': this.$store.state.user.schoolCode
-            //     }
-            // }
-            // this.getResultCount(findCountParams)
         },
         computed: {
             ...mapGetters({
@@ -591,7 +562,6 @@ console.log(index, 'getGradeList')
             }
         },
         mounted() {
-
         }
     }
 </script>

+ 169 - 108
TEAMModelOS/Controllers/School/StudentController.cs

@@ -91,7 +91,7 @@ namespace TEAMModelOS.Controllers
                             }
                         }
 
-                        var retStudents = classStudent.SelectMany(o => o.Value.Select(p => new { p.id, p.name, p.no, p.year, classId = o.Key, gradeId = classStuds[o.Key].gradeId, periodId = classStuds[o.Key].periodId }));
+                        var retStudents = classStudent.SelectMany(o => o.Value.Select(p => new { p.id, p.name, p.no, p.year, classId = o.Key, classStuds[o.Key].gradeId, classStuds[o.Key].periodId }));
                         var retUnclassStudents = unclassStudent.Select(o => new { o.id, o.name, o.no, o.year, classId = (string)null, gradeId = (string)null, periodId = (string)null });
 
                         IEnumerable ret = new string[] { };
@@ -114,7 +114,7 @@ namespace TEAMModelOS.Controllers
                     case "update":
                         //更新學生資料,批量密碼重置,基本資訊更新(姓名、教室ID及座號)
                         var (dicStudent, nonexistentIds, errorIds) = await updateStudents(schoolId.GetString(), request.GetProperty("students").EnumerateArray());
-                        var studentClass = await updateClassStudents(schoolId.GetString(), request.GetProperty("students").EnumerateArray());
+                        var studentClass = await updateClassStudents(schoolId.GetString(), dicStudent);
                         if (errorIds.Count == 0)
                         {
                             return this.Ok(new
@@ -796,10 +796,10 @@ namespace TEAMModelOS.Controllers
                     {
                         exceptions.Add(ex);
                     }
-                    if (exceptions.Count == 0) return sucIds;
-                    else if (exceptions.Count > 1) throw new AggregateException(exceptions);
-                    else if (exceptions.Count == 1) throw exceptions.Single();
                 }
+                if (exceptions.Count == 0) return sucIds;
+                else if (exceptions.Count > 1) throw new AggregateException(exceptions);
+                else if (exceptions.Count == 1) throw exceptions.Single();
             }
             catch (CosmosException ex)
             {
@@ -822,6 +822,7 @@ namespace TEAMModelOS.Controllers
             try
             {
                 Dictionary<string, List<string>> classStudent = new Dictionary<string, List<string>>();
+                List<string> studs = new List<string>();
                 //整理教室學生資訊
                 while (students.MoveNext())
                 {
@@ -830,6 +831,7 @@ namespace TEAMModelOS.Controllers
                     if (student.TryGetProperty("id", out var tmpId) && !string.IsNullOrWhiteSpace(tmpId.GetString()))
                     {
                         id = tmpId.GetString();
+                        studs.Add(id);
                     }
                     else continue;
 
@@ -839,63 +841,78 @@ namespace TEAMModelOS.Controllers
                         if (!string.IsNullOrWhiteSpace(classId) && classStudent.ContainsKey(classId)) classStudent[classId].Add(id);
                         else classStudent.Add(classId, new List<string>() { id });
                     }
-                    
-                    //如果沒給教室?但卻有加入過教室
-                    
                 }
 
-                foreach (var c in classStudent)
+                if (studs.Count != 0)
                 {
-                    var response = await _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOSTemp", "School").ReadItemStreamAsync(c.Key, new PartitionKey($"Class-{schoolId}"));
-                    if (response.Status == 200)
+                    //使用子查詢來查詢students欄位裡面是否有相符的學生
+                    var queryText = $"SELECT VALUE c FROM c JOIN (SELECT VALUE t FROM t IN c.students WHERE t.id IN ({string.Join(",", studs.Select(o => $"'{o}'"))}))";
+                    await foreach (Response item in _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOSTemp", "School")
+                                    .GetItemQueryStreamIterator(
+                                        queryText: queryText,
+                                        requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Class-{schoolId}") }))
                     {
-                        using var json = await JsonDocument.ParseAsync(response.ContentStream);
-                        using var memoryStream = new MemoryStream();
-                        using var writer = new Utf8JsonWriter(memoryStream);
-                        writer.WriteStartObject();
-                        foreach (var element in json.RootElement.EnumerateObject())
+                        using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                        if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
                         {
-                            if (element.Name.Equals("students", StringComparison.Ordinal))
+                            JsonElement.ArrayEnumerator docs = json.RootElement.GetProperty("Documents").EnumerateArray();
+                            while (docs.MoveNext())
                             {
-                                writer.WritePropertyName("students");
-                                writer.WriteStartArray();
-                                var s = element.Value.EnumerateArray();
-                                while (s.MoveNext())
+                                JsonElement doc = docs.Current;
+
+                                doc.TryGetProperty("id", out var tmpId);
+                                var id = tmpId.GetString();
+
+                                using var memoryStream = new MemoryStream();
+                                using var writer = new Utf8JsonWriter(memoryStream);
+                                writer.WriteStartObject();
+                                foreach (var element in doc.EnumerateObject())
                                 {
-                                    JsonElement stud = s.Current;
-                                    string id = stud.GetProperty("id").GetString();
-                                    if (!c.Value.Contains(id))
+                                    if (element.Name.Equals("students", StringComparison.Ordinal))
                                     {
-                                        string name = stud.GetProperty("name").GetString();
-                                        string no = stud.GetProperty("no").GetString();
-
-                                        writer.WriteStartObject();
-                                        writer.WriteString("id", id);
-                                        if (string.IsNullOrWhiteSpace(name)) writer.WriteNull("name");
-                                        else writer.WriteString("name", name);
-                                        if (string.IsNullOrWhiteSpace(no)) writer.WriteNull("no");
-                                        else writer.WriteString("no", no);
-                                        writer.WriteEndObject();
+                                        writer.WritePropertyName("students");
+                                        writer.WriteStartArray();
+                                        var s = element.Value.EnumerateArray();
+                                        while (s.MoveNext())
+                                        {
+                                            JsonElement stud = s.Current;
+                                            string sutdId = stud.GetProperty("id").GetString();
+                                            if (!studs.Contains(sutdId))
+                                            {
+                                                string name = stud.GetProperty("name").GetString();
+                                                string no = stud.GetProperty("no").GetString();
+
+                                                writer.WriteStartObject();
+                                                writer.WriteString("id", sutdId);
+                                                if (string.IsNullOrWhiteSpace(name)) writer.WriteNull("name");
+                                                else writer.WriteString("name", name);
+                                                if (string.IsNullOrWhiteSpace(no)) writer.WriteNull("no");
+                                                else writer.WriteString("no", no);
+                                                writer.WriteEndObject();
+                                            }
+                                        }
+                                        writer.WriteEndArray();
+                                    }
+                                    else
+                                    {
+                                        element.WriteTo(writer);
                                     }
                                 }
-                                writer.WriteEndArray();
-                            }
-                            else
-                            {
-                                element.WriteTo(writer);
+                                writer.WriteEndObject();
+                                writer.Flush();
+
+                                var ret = await _azureCosmos
+                                    .GetCosmosClient()
+                                    .GetContainer("TEAMModelOSTemp", "School")
+                                    .ReplaceItemStreamAsync(memoryStream, id, new PartitionKey($"Class-{schoolId}"));
+                                if (ret.Status != (int)HttpStatusCode.OK)
+                                {
+                                    await _dingDing.SendBotMsg(
+                                        $"OS,{_option.Location},Student/removeStudentFromClass()\nClass-{schoolId},{string.Join(",", studs.Select(o => $"'{o}'"))}", 
+                                        GroupNames.醍摩豆服務運維群組);
+                                }
                             }
                         }
-                        writer.WriteEndObject();
-                        writer.Flush();
-
-                        var ret = await _azureCosmos
-                            .GetCosmosClient()
-                            .GetContainer("TEAMModelOSTemp", "School")
-                            .ReadItemStreamAsync(c.Key, new PartitionKey($"Class-{schoolId}"));
-                    }
-                    else
-                    {
-                        //查無該教室
                     }
                 }
             }
@@ -1121,15 +1138,15 @@ namespace TEAMModelOS.Controllers
         /// <param name="schoolId"></param>
         /// <param name="students"></param>
         /// <returns></returns>
-        private async Task<(Dictionary<string, (string name, string year, string pic,string gender, string mail, string mobile)> students, List<string> nonexistentIds, List<string> errorIds)> updateStudents(string schoolId, JsonElement.ArrayEnumerator students)
+        private async Task<(Dictionary<string, (string name, string year, string pic, string gender, string mail, string mobile, string classId, string no)> students, List<string> nonexistentIds, List<string> errorIds)> updateStudents(string schoolId, JsonElement.ArrayEnumerator students)
         {
             try
             {
                 //Key:id Value:學生基本資訊
-                Dictionary<string, (string salt, string pw, string name, string year, string pic,string gender,string mail,string mobile)> studentsInfo
-                    = new Dictionary<string, (string salt, string pw, string name, string year, string pic, string gender, string mail, string mobile)>();
-                List<string> nonexistentIds = new List<string>();
-                List<string> errorIds = new List<string>();
+                var studentsInfos
+                    = new Dictionary<string, (string salt, string pw, string name, string year, string pic, string gender, string mail, string mobile, string classId, string no)>();
+                var nonexistentIds = new List<string>();
+                var errorIds = new List<string>();
 
                 //整理輸入資料
                 while (students.MoveNext())
@@ -1140,9 +1157,9 @@ namespace TEAMModelOS.Controllers
                         //確認是否有id欄位,並且確認是否有給pw欄位,若無給或是null empty等,則使用id當密碼。
                         if (!string.IsNullOrWhiteSpace(id.GetString()))
                         {
-                            string salt = string.Empty, pw = string.Empty, name = string.Empty, year = string.Empty, gender = string.Empty, mail = string.Empty, mobile = string.Empty;
+                            string salt = string.Empty, pw = string.Empty, name = string.Empty, year = string.Empty, gender = string.Empty, mail = string.Empty, mobile = string.Empty, classId = string.Empty, no = string.Empty;
                             //有給pw欄位才進行處理
-                             if (student.TryGetProperty("pw", out var tmpPw))
+                            if (student.TryGetProperty("pw", out var tmpPw))
                             {
                                 salt = Utils.CreatSaltString(8);
                                 pw = !string.IsNullOrWhiteSpace(tmpPw.GetString())
@@ -1169,10 +1186,18 @@ namespace TEAMModelOS.Controllers
                             {
                                 year = tmpYear.GetString();
                             }
-                            if (!studentsInfo.ContainsKey(id.GetString()))
+                            if (student.TryGetProperty("classId", out var tmpclassId))
+                            {
+                                classId = tmpclassId.GetString();
+                            }
+                            if (student.TryGetProperty("no", out var tmpNo))
+                            {
+                                no = tmpNo.GetString();
+                            }
+                            if (!studentsInfos.ContainsKey(id.GetString()))
                             {
                                 //pic,mail,mobile暫不支持更新
-                                studentsInfo.Add(id.GetString(), (salt, pw, name, year, null, gender, null, null));
+                                studentsInfos.Add(id.GetString(), (salt, pw, name, year, null, gender, null, null, classId, no));
                                 nonexistentIds.Add(id.GetString());
                             }
                         }
@@ -1180,11 +1205,11 @@ namespace TEAMModelOS.Controllers
                 }
 
                 //將資料更新到資料庫
-                if (studentsInfo.Count != 0)
+                if (studentsInfos.Count != 0)
                 {
                     CosmosContainer cosmosContainer = _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOSTemp", "Student");
                     //查學生的基本資料
-                    string queryText = $"SELECT * FROM c WHERE c.pk = 'Base' AND c.id IN ({string.Join(",", studentsInfo.Select(o => $"'{o.Key}'"))})";
+                    string queryText = $"SELECT * FROM c WHERE c.pk = 'Base' AND c.id IN ({string.Join(",", studentsInfos.Select(o => $"'{o.Key}'"))})";
 
                     List<JsonElement> listStudent = new List<JsonElement>();
 
@@ -1202,6 +1227,8 @@ namespace TEAMModelOS.Controllers
                                 JsonElement account = accounts.Current;
                                 string id = account.GetProperty("id").GetString();
 
+                                (string salt, string pw, string name, string year, string pic, string gender, string mail, string mobile, string classId, string no) oldData;
+                                oldData = (studentsInfos[id].salt, studentsInfos[id].pw, studentsInfos[id].name, studentsInfos[id].year, studentsInfos[id].pic, studentsInfos[id].gender, studentsInfos[id].mail, studentsInfos[id].mobile, studentsInfos[id].classId, studentsInfos[id].no);
                                 bool upPwDone = false;
                                 using var memoryStream = new MemoryStream();
                                 using var writer = new Utf8JsonWriter(memoryStream);
@@ -1210,23 +1237,56 @@ namespace TEAMModelOS.Controllers
                                 {
                                     switch (true)
                                     {
-                                        case bool _ when element.Name.Equals("name", StringComparison.Ordinal) && !string.IsNullOrWhiteSpace(studentsInfo[id].name):
-                                            writer.WriteString("name", studentsInfo[id].name);
+                                        //case bool _ when element.Name.Equals("name", StringComparison.Ordinal) && !string.IsNullOrWhiteSpace(studentsInfos[id].name):
+                                        //    writer.WriteString("name", studentsInfos[id].name);
+                                        //    break;
+                                        case bool _ when element.Name.Equals("name", StringComparison.Ordinal):
+                                            if (string.IsNullOrWhiteSpace(studentsInfos[id].name))
+                                            {
+                                                element.WriteTo(writer);
+                                                oldData.name = element.Value.GetString();
+                                            }
+                                            else
+                                            {
+                                                writer.WriteString("name", studentsInfos[id].name);
+                                            }
                                             break;
                                         case bool _ when element.Name.Equals("pw", StringComparison.Ordinal):
                                         case bool _ when element.Name.Equals("salt", StringComparison.Ordinal):
-                                            if (!upPwDone && !string.IsNullOrWhiteSpace(studentsInfo[id].salt) && !string.IsNullOrWhiteSpace(studentsInfo[id].pw))
+                                            if (!upPwDone && !string.IsNullOrWhiteSpace(studentsInfos[id].salt) && !string.IsNullOrWhiteSpace(studentsInfos[id].pw))
                                             {
-                                                writer.WriteString("salt", studentsInfo[id].salt);
-                                                writer.WriteString("pw", studentsInfo[id].pw);
+                                                writer.WriteString("salt", studentsInfos[id].salt);
+                                                writer.WriteString("pw", studentsInfos[id].pw);
                                                 upPwDone = true;
                                             }
                                             break;
-                                        case bool _ when element.Name.Equals("gender", StringComparison.Ordinal) && !string.IsNullOrWhiteSpace(studentsInfo[id].gender):
-                                            writer.WriteString("gender", studentsInfo[id].gender);
+                                        //case bool _ when element.Name.Equals("gender", StringComparison.Ordinal) && !string.IsNullOrWhiteSpace(studentsInfos[id].gender):
+                                        //    writer.WriteString("gender", studentsInfos[id].gender);
+                                        //    break;
+                                        case bool _ when element.Name.Equals("gender", StringComparison.Ordinal):
+                                            if (string.IsNullOrWhiteSpace(studentsInfos[id].gender))
+                                            {
+                                                element.WriteTo(writer);
+                                                oldData.gender = element.Value.GetString();
+                                            }
+                                            else
+                                            {
+                                                writer.WriteString("gender", studentsInfos[id].gender);
+                                            }
                                             break;
-                                        case bool _ when element.Name.Equals("year", StringComparison.Ordinal) && !string.IsNullOrWhiteSpace(studentsInfo[id].year):
-                                            writer.WriteString("year", studentsInfo[id].year);
+                                        //case bool _ when element.Name.Equals("year", StringComparison.Ordinal) && !string.IsNullOrWhiteSpace(studentsInfos[id].year):
+                                        //    writer.WriteString("year", studentsInfos[id].year);
+                                        //    break;
+                                        case bool _ when element.Name.Equals("year", StringComparison.Ordinal):
+                                            if (string.IsNullOrWhiteSpace(studentsInfos[id].year))
+                                            {
+                                                element.WriteTo(writer);
+                                                oldData.year = element.Value.GetString();
+                                            }
+                                            else
+                                            {
+                                                writer.WriteString("year", studentsInfos[id].year);
+                                            }
                                             break;
                                         case bool _ when element.Name.StartsWith("_", StringComparison.Ordinal):
                                             break;
@@ -1243,6 +1303,7 @@ namespace TEAMModelOS.Controllers
                                 }
                                 writer.WriteEndObject();
                                 writer.Flush();
+                                studentsInfos[id] = oldData;
 
                                 try
                                 {
@@ -1264,13 +1325,13 @@ namespace TEAMModelOS.Controllers
                             }
                         }
                         //將輸入不存在的資料移除。
-                        nonexistentIds.ForEach(o => studentsInfo.Remove(o));
+                        nonexistentIds.ForEach(o => studentsInfos.Remove(o));
                     }
                     //整理輸出數據
-                    var retStudentsInfo = new Dictionary<string, (string name, string year, string pic, string gender, string mail, string mobile)>();
-                    foreach (var item in studentsInfo)
+                    var retStudentsInfo = new Dictionary<string, (string name, string year, string pic, string gender, string mail, string mobile, string classId, string no)>();
+                    foreach (var item in studentsInfos)
                     {
-                        retStudentsInfo.Add(item.Key, (item.Value.name, item.Value.year, item.Value.pic, item.Value.gender, item.Value.mail, item.Value.mobile));
+                        retStudentsInfo.Add(item.Key, (item.Value.name, item.Value.year, item.Value.pic, item.Value.gender, item.Value.mail, item.Value.mobile, item.Value.classId, item.Value.no));
                     }
                     return (retStudentsInfo, nonexistentIds, errorIds);
                 }
@@ -1292,7 +1353,7 @@ namespace TEAMModelOS.Controllers
         /// <param name="schoolId"></param>
         /// <param name="students"></param>
         /// <returns></returns>
-        private async Task<Dictionary<string, (string classId, string periodId, string gradeId, string name, string no)>> updateClassStudents(string schoolId, JsonElement.ArrayEnumerator students)
+        private async Task<Dictionary<string, (string classId, string periodId, string gradeId, string name, string no)>> updateClassStudents(string schoolId, Dictionary<string, (string name, string year, string pic, string gender, string mail, string mobile, string classId, string no)> students)
         {
             try
             {
@@ -1300,28 +1361,28 @@ namespace TEAMModelOS.Controllers
                 var retStudentsClassInfo = new Dictionary<string, (string classId, string periodId, string gradeId, string name, string no)>();
 
                 //整理輸入的資料
-                var studentsClassInfo = new Dictionary<string, (string classId, string name, string no)>();
-                while (students.MoveNext())
-                {
-                    JsonElement student = students.Current;
-                    if (student.TryGetProperty("id", out var tmpId))
-                    {
-                        if (!string.IsNullOrWhiteSpace(tmpId.GetString()))
-                        {
-                            string classId = string.Empty, className = string.Empty, no = string.Empty, name = string.Empty;
-
-                            if (student.TryGetProperty("name", out var tmpName)) name = tmpName.GetString();
-                            if (student.TryGetProperty("classId", out var tmpClassId)) classId = tmpClassId.GetString();
-                            if (student.TryGetProperty("no", out var tmpNo)) no = tmpNo.GetString();
-
-                            studentsClassInfo.Add(tmpId.GetString(), (classId, name, no));
-                        }
-                    }
-                }
-                if (studentsClassInfo.Count == 0) return retStudentsClassInfo;
+                //var studentsClassInfo = new Dictionary<string, (string classId, string name, string no)>();
+                //while (students.MoveNext())
+                //{
+                //    JsonElement student = students.Current;
+                //    if (student.TryGetProperty("id", out var tmpId))
+                //    {
+                //        if (!string.IsNullOrWhiteSpace(tmpId.GetString()))
+                //        {
+                //            string classId = string.Empty, className = string.Empty, no = string.Empty, name = string.Empty;
+
+                //            if (student.TryGetProperty("name", out var tmpName)) name = tmpName.GetString();
+                //            if (student.TryGetProperty("classId", out var tmpClassId)) classId = tmpClassId.GetString();
+                //            if (student.TryGetProperty("no", out var tmpNo)) no = tmpNo.GetString();
+
+                //            studentsClassInfo.Add(tmpId.GetString(), (classId, name, no));
+                //        }
+                //    }
+                //}
+                if (students.Count == 0) return retStudentsClassInfo;
 
                 //透過id查找已加入的教室
-                var classInfo = await getClassInfoUseStudent(schoolId, studentsClassInfo.Select(o => o.Key).ToList());
+                var classInfo = await getClassInfoUseStudent(schoolId, students.Select(o => o.Key).ToList());
 
                 //如果有查到,代表該學生已經加入過某間教室(Class)
                 if (classInfo.Count != 0)
@@ -1362,17 +1423,17 @@ namespace TEAMModelOS.Controllers
                                 if (Document.TryGetProperty("no", out var tmpNo)) no = tmpNo.GetString();
 
                                 //檢查輸入資料內學生要加入的教室是否一致
-                                if (studentsClassInfo.ContainsKey(studId))
+                                if (students.ContainsKey(studId))
                                 {
                                     //如果是相同的教室id
-                                    if (studentsClassInfo[studId].classId.Equals(classId, StringComparison.Ordinal))
+                                    if (students[studId].classId.Equals(classId, StringComparison.Ordinal))
                                     {
                                         retStudentsClassInfo.Add(studId, (classId, periodId, gradeId, name, no));
 
                                         //座號及姓名檢查,如果不相同則進行更新
                                         if (
-                                            studentsClassInfo[studId].no.Equals(no, StringComparison.Ordinal)
-                                            && studentsClassInfo[studId].name.Equals(name, StringComparison.Ordinal)
+                                            students[studId].no.Equals(no, StringComparison.Ordinal)
+                                            && students[studId].name.Equals(name, StringComparison.Ordinal)
                                             )
                                         {
                                             writer.WriteStartObject();
@@ -1387,16 +1448,16 @@ namespace TEAMModelOS.Controllers
                                         {
                                             writer.WriteStartObject();
                                             writer.WriteString("id", studId);
-                                            if (string.IsNullOrWhiteSpace(studentsClassInfo[studId].name)) writer.WriteNull("name");
-                                            else writer.WriteString("name", studentsClassInfo[studId].name);
-                                            if (string.IsNullOrWhiteSpace(studentsClassInfo[studId].no)) writer.WriteNull("no");
-                                            else writer.WriteString("no", studentsClassInfo[studId].no);
+                                            if (string.IsNullOrWhiteSpace(students[studId].name)) writer.WriteNull("name");
+                                            else writer.WriteString("name", students[studId].name);
+                                            if (string.IsNullOrWhiteSpace(students[studId].no)) writer.WriteNull("no");
+                                            else writer.WriteString("no", students[studId].no);
                                             writer.WriteEndObject();
                                             //更新輸出結果的資料
-                                            retStudentsClassInfo[studId] = (classId, periodId, gradeId, studentsClassInfo[studId].name, studentsClassInfo[studId].no);
+                                            retStudentsClassInfo[studId] = (classId, periodId, gradeId, students[studId].name, students[studId].no);
                                         }
                                         //將已處理好的學生從字典裡移除
-                                        studentsClassInfo.Remove(studId);
+                                        students.Remove(studId);
                                     }
                                     //不是相同教室id,則要移除該學生的資訊,不寫入
                                     else continue;
@@ -1436,10 +1497,10 @@ namespace TEAMModelOS.Controllers
                     }
                 }
                 //始終會加入新教室,除非只是單純的換座號或是姓名
-                if (classInfo.Count == 0 || studentsClassInfo.Count != 0) //透過學生id查找教室,但沒找到任何已加入的教室
+                if (classInfo.Count == 0 || students.Count != 0) //透過學生id查找教室,但沒找到任何已加入的教室
                 {
                     //使用classId來查詢教室資訊
-                    var classInfos = await getClassInfoUseId(schoolId, studentsClassInfo.Select(o => o.Value.classId).ToList());
+                    var classInfos = await getClassInfoUseId(schoolId, students.Select(o => o.Value.classId).ToList());
                     if (classInfos.Count != 0)
                     {
                         foreach (var item in classInfos)
@@ -1486,7 +1547,7 @@ namespace TEAMModelOS.Controllers
                             }
 
                             //將欲加入的學生寫入該教室名單內
-                            var studList = studentsClassInfo
+                            var studList = students
                                 .Where(o => o.Value.classId.Equals(classId, StringComparison.Ordinal))
                                 .Select(o => new { id = o.Key, o.Value.name, o.Value.no }).ToList();
                             foreach (var stud in studList)