diff --git a/src/views/teacherEnd/student/index.vue b/src/views/teacherEnd/student/index.vue index d2d7b21..7d83bcd 100644 --- a/src/views/teacherEnd/student/index.vue +++ b/src/views/teacherEnd/student/index.vue @@ -64,15 +64,14 @@ {{ formatDate(row.createTime) }} - + @@ -130,6 +129,7 @@ const userStore = useUserStore(); const currentUserId = computed(() => userStore.userInfo.userId); const currentSchoolId = computed(() => userStore.userInfo.schoolId); const isTeacherRosterMode = computed(() => userStore.schoolProductConfig?.studentRosterOwner === "TEACHER"); +const isManagerTeacher = computed(() => userStore.userInfo.teacherAdmin === true); import * as indexApi from "@/api/teacher"; const dialogVisible = ref(false); const loading = ref(false); @@ -194,7 +194,7 @@ const getList = () => { }; // 删除院校 const delSchool = (id) => { - indexApi.deleteStudent({ userId: id.userId, operatorId: currentUserId.value, teachingClassId: currentTeachingClassId() }).then((res) => { + indexApi.deleteStudent({ userId: id.userId, operatorId: currentUserId.value, teachingClassId: resolveRowTeachingClassId(id) }).then((res) => { proxy.$message.success("删除成功"); getList(); }); @@ -412,36 +412,20 @@ const canUseAdminClassForStudent = (schoolClass) => { return !schoolClass?.schoolId || sameValue(schoolClass.schoolId, currentSchoolId.value); }; const classMap = computed(() => new Map(classList.value.map((item) => [item.schoolClassId, item]))); -const adminClassList = computed(() => classList.value.filter((item) => canUseAdminClassForStudent(item))); -const studentClassOptions = computed(() => - isTeacherRosterMode.value ? teachingClassOptions.value : adminClassList.value -); const teachingClassOptions = computed(() => classList.value.filter( (schoolClass) => normalizeClassType(schoolClass) === "TEACHING" && sameValue(schoolClass.schoolId, currentSchoolId.value) && - sameValue(schoolClass.createdBy, currentUserId.value) + (isManagerTeacher.value || sameValue(schoolClass.createdBy, currentUserId.value)) ) ); -const canOperateStudent = (row) => { - const selectedClass = classMap.value.get(paramsquery.value.schoolClassId); - if (isTeacherRosterMode.value) { - return Boolean(selectedClass) - && normalizeClassType(selectedClass) === "TEACHING" - && sameValue(selectedClass.createdBy, currentUserId.value); - } - if (selectedClass && normalizeClassType(selectedClass) === "TEACHING") { - return sameValue(selectedClass.createdBy, currentUserId.value); - } - const adminClass = classMap.value.get(row.schoolClassId); - return normalizeClassType(adminClass) === "ADMIN" - && (!adminClass?.schoolId || sameValue(adminClass.schoolId, currentSchoolId.value)); -}; +const studentClassOptions = computed(() => teachingClassOptions.value); const currentTeachingClassId = () => { const selectedClass = classMap.value.get(paramsquery.value.schoolClassId); return selectedClass && normalizeClassType(selectedClass) === "TEACHING" ? selectedClass.schoolClassId : ""; }; +const resolveRowTeachingClassId = (row) => currentTeachingClassId() || row?.teachingClassId || ""; const beforeImportStudents = (file) => { if (!/\.(xls|xlsx)$/i.test(file.name)) { proxy.$message.warning("请选择xls或xlsx格式文件"); @@ -472,7 +456,7 @@ const initPassword = (row, status) => { type: "warning", }) .then(() => { - indexApi.initStudentPassword({ userId: row.userId, operatorId: currentUserId.value, teachingClassId: currentTeachingClassId() }).then((res) => { + indexApi.initStudentPassword({ userId: row.userId, operatorId: currentUserId.value, teachingClassId: resolveRowTeachingClassId(row) }).then((res) => { proxy.$message.success("密码初始化成功"); getList(); }); @@ -485,12 +469,13 @@ const initPassword = (row, status) => { type: "warning", }) .then(() => { - if (!paramsquery.value.schoolClassId) { + const teachingClassId = resolveRowTeachingClassId(row); + if (!teachingClassId) { proxy.$message.warning("请先选择教学班"); return; } indexApi.initializeTeachingClassStudentTrainingData({ - teachingClassId: paramsquery.value.schoolClassId, + teachingClassId, studentUserId: row.userId, operatorId: currentUserId.value, }).then((res) => { @@ -525,5 +510,16 @@ onMounted(async () => { position: sticky !important; } } + .student-action-group { + display: flex; + align-items: center; + justify-content: center; + gap: 6px; + flex-wrap: nowrap; + white-space: nowrap; + :deep(.el-button + .el-button) { + margin-left: 0; + } + } } diff --git a/tests/teacher-owned-student-management.static.test.cjs b/tests/teacher-owned-student-management.static.test.cjs index a74ffbf..b3324a2 100644 --- a/tests/teacher-owned-student-management.static.test.cjs +++ b/tests/teacher-owned-student-management.static.test.cjs @@ -5,7 +5,13 @@ const root = path.join(__dirname, ".."); const page = fs.readFileSync(path.join(root, "src", "views", "teacherEnd", "student", "index.vue"), "utf8"); assert(page.includes("operatorId: currentUserId.value"), "学生列表必须携带当前教师"); -assert(page.includes("isTeacherRosterMode.value ? teachingClassOptions.value : adminClassList.value"), "教学班模式必须只显示教师自有教学班"); +assert(page.includes("const isManagerTeacher = computed(() => userStore.userInfo.teacherAdmin === true);"), "教师管理员身份必须由当前登录账号识别"); +assert(page.includes("const studentClassOptions = computed(() => teachingClassOptions.value);"), "学生筛选下拉框必须只展示教学班"); +assert(page.includes("isManagerTeacher.value || sameValue(schoolClass.createdBy, currentUserId.value)"), "教师管理员必须可查看本校全部教学班"); +assert(page.includes("const resolveRowTeachingClassId = (row) =>"), "未选择班级时操作必须从学生行解析教学班"); +assert(page.includes('class="student-action-group"'), "学生操作按钮必须使用固定操作组布局"); +assert(page.includes("flex-wrap: nowrap"), "学生操作按钮不得换行"); +assert(!page.includes("仅查看"), "学生列表不应再展示仅查看操作"); assert(page.includes("请选择自己的教学班后再导入学生"), "导入必须要求选中教学班"); assert(page.includes('["学生姓名", "学号"]'), "教学班导入模板必须只有学生姓名和学号"); assert(page.includes("initPassword(row, 1)"), "学生列表必须提供数据初始化操作"); diff --git a/tests/teacher-student-roster-mode.static.test.cjs b/tests/teacher-student-roster-mode.static.test.cjs index 82e75c8..fed95f5 100644 --- a/tests/teacher-student-roster-mode.static.test.cjs +++ b/tests/teacher-student-roster-mode.static.test.cjs @@ -25,6 +25,7 @@ assert( page.includes("row.teachingClassId || currentTeachingClassId()"), "教师维护名单模式再次编辑学生时必须回显该学生当前所属教学班" ); +assert(page.includes("teachingClassId: resolveRowTeachingClassId(row)"), "学生行操作必须携带该学生所属教学班"); assert(api.includes('url: "/api/user/teacher-roster/students"'), "教师名单新增接口必须在前端 API 层声明"); assert(api.includes('teachingClassId: data.teachingClassId'), "教师名单接口必须提交已选择的教学班");