feat: show managed teaching class students

dev-QQq
chenyuan 4 weeks ago
parent 328241211a
commit ff527582bc

@ -64,15 +64,14 @@
<span>{{ formatDate(row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="320">
<el-table-column label="操作" align="center" width="360">
<template #default="{ row }">
<template v-if="canOperateStudent(row)">
<div class="student-action-group">
<el-button type="info" text @click="editSchool(row)"></el-button>
<el-button type="danger" text @click="delSchool(row)"></el-button>
<el-button type="success" text @click="initPassword(row, 0)">密码初始化</el-button>
<el-button type="warning" text @click="initPassword(row, 1)">数据初始化</el-button>
</template>
<el-tag v-else type="info">仅查看</el-tag>
</div>
</template>
</el-table-column>
</el-table>
@ -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;
}
}
}
</style>

@ -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("仅查看</el-tag>"), "学生列表不应再展示仅查看操作");
assert(page.includes("请选择自己的教学班后再导入学生"), "导入必须要求选中教学班");
assert(page.includes('["学生姓名", "学号"]'), "教学班导入模板必须只有学生姓名和学号");
assert(page.includes("initPassword(row, 1)"), "学生列表必须提供数据初始化操作");

@ -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'), "教师名单接口必须提交已选择的教学班");

Loading…
Cancel
Save