feat: use teacher roster import flow

dev-QQq
chenyuan 4 weeks ago
parent 8025486f50
commit 87abf8981a

@ -346,6 +346,14 @@ export function uploadTeachingClassStudentMembers(data) {
headers: { "Content-Type": "multipart/form-data" },
});
}
export function importTeacherRosterMembers(teachingClassId, data) {
return request({
url: `/api/user/teaching-classes/${teachingClassId}/students/import`,
method: "POST",
data,
headers: { "Content-Type": "multipart/form-data" },
});
}
export function importTeacherStudents(data) {
return request({
url: "/api/user/importTeacherStudents",

@ -316,7 +316,10 @@ function getList(options = {}) {
loading.value = true;
}
indexApi
.getClassesList(paramsquery.value)
.getClassesList({
...paramsquery.value,
operatorId: currentUserId.value,
})
.then((res) => {
tableData.value = res.data?.list || [];
schoolTotal.value = res.data?.total || 0;
@ -538,6 +541,15 @@ function beforeImportMembers(file) {
}
function uploadMemberImport(options, confirmMultiTeachingClass = false) {
if (isTeacherRosterMode.value) {
const formData = new FormData();
formData.append("file", options.file);
return indexApi
.importTeacherRosterMembers(selectedTeachingClass.value.schoolClassId, formData)
.then((res) => {
handleMemberImportSuccess(res);
});
}
const formData = buildUploadFormData(options.file, memberUploadData.value, confirmMultiTeachingClass);
return indexApi
.uploadTeachingClassStudentMembers(formData)
@ -602,6 +614,26 @@ function initializeMember(row) {
async function downloadMemberImportTemplate() {
const XLSX = await import("xlsx");
if (isTeacherRosterMode.value) {
const templateSheet = XLSX.utils.aoa_to_sheet([
["学生姓名", "学号"],
["张三", "20260001"],
]);
templateSheet["!cols"] = [{ wch: 16 }, { wch: 18 }];
const guideSheet = XLSX.utils.aoa_to_sheet([
["填写说明"],
["1. 本模板用于向当前教学班添加成员。"],
["2. 仅填写学生姓名和学号,不需要填写班级或其他个人信息。"],
["3. 学号已存在时,系统会复用该学生并加入当前教学班。"],
["4. 任意一行校验失败时,整批导入失败并返回失败原因。"],
]);
guideSheet["!cols"] = [{ wch: 72 }];
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, templateSheet, "教学班成员导入模板");
XLSX.utils.book_append_sheet(workbook, guideSheet, "填写说明");
XLSX.writeFile(workbook, "教学班成员导入模板.xlsx");
return;
}
const templateSheet = XLSX.utils.aoa_to_sheet([
["所属院系", "所属专业", "行政班", "学号", "学生姓名", "性别", "手机号", "邮箱"],
["商学院", "电子商务", "2026电子商务1班-行政班", "20260001", "张三", "男", "13800000000", "zhangsan@example.com"],

@ -11,7 +11,7 @@ const apiSource = read("src/api/teacher.js");
const pageSource = read("src/views/teacherEnd/defaultTask/index.vue");
assert.match(routerSource, /requiresManagerTeacher:\s*true/);
assert.match(sidebarSource, /route\.meta\?\.requiresManagerTeacher/);
assert.match(sidebarSource, /capability\.requiresManagerTeacher && userStore\.userInfo\.teacherAdmin !== true/);
assert.match(apiSource, /\/api\/school-default-tasks/);
assert.match(pageSource, /正在初始化,稍后刷新/);
assert.match(pageSource, /立即重试/);

@ -0,0 +1,21 @@
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const pagePath = path.join(__dirname, "..", "src", "views", "teacherEnd", "class", "index.vue");
const apiPath = path.join(__dirname, "..", "src", "api", "teacher.js");
const page = fs.readFileSync(pagePath, "utf8");
const api = fs.readFileSync(apiPath, "utf8");
assert.match(page, /getClassesList\(\{\s*\.\.\.paramsquery\.value,\s*operatorId: currentUserId\.value,?\s*\}\)/,
"班级查询必须提交当前操作教师,以便后端限制为本人教学班");
assert.match(api, /export function importTeacherRosterMembers\(teachingClassId, data\)/,
"前端 API 层必须提供教师教学班成员导入接口");
assert.match(api, /url: `\/api\/user\/teaching-classes\/\$\{teachingClassId\}\/students\/import`/,
"教师教学班成员导入必须使用专用端点");
assert.match(page, /if \(isTeacherRosterMode\.value\) \{[\s\S]*importTeacherRosterMembers/,
"教学班专属模式必须走教师名单导入端点");
assert.match(page, /\["学生姓名", "学号"\]/,
"教学班专属模式模板必须只包含姓名和学号");
console.log("teacher owned class roster static checks passed");
Loading…
Cancel
Save