|
|
|
@ -91,20 +91,6 @@
|
|
|
|
<el-form-item label="班级名称" prop="className">
|
|
|
|
<el-form-item label="班级名称" prop="className">
|
|
|
|
<el-input v-model="formInline.className" placeholder="请输入班级名称" class="form-control" />
|
|
|
|
<el-input v-model="formInline.className" placeholder="请输入班级名称" class="form-control" />
|
|
|
|
</el-form-item>
|
|
|
|
</el-form-item>
|
|
|
|
<el-form-item v-if="activeClassType === 'TEACHING' && isCreate" label="名单创建">
|
|
|
|
|
|
|
|
<div class="import-create-actions">
|
|
|
|
|
|
|
|
<el-upload
|
|
|
|
|
|
|
|
action="/api/user/uploadTeachingClassByStudentMembers"
|
|
|
|
|
|
|
|
:data="importCreateUploadData"
|
|
|
|
|
|
|
|
:show-file-list="false"
|
|
|
|
|
|
|
|
:before-upload="beforeImportCreate"
|
|
|
|
|
|
|
|
:http-request="uploadImportCreate"
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
<el-button type="primary">导入名单创建</el-button>
|
|
|
|
|
|
|
|
</el-upload>
|
|
|
|
|
|
|
|
<el-button @click="downloadTeachingClassImportTemplate">模板下载</el-button>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
</el-form>
|
|
|
|
</el-form>
|
|
|
|
<template #footer>
|
|
|
|
<template #footer>
|
|
|
|
<span class="dialog-footers">
|
|
|
|
<span class="dialog-footers">
|
|
|
|
@ -190,6 +176,7 @@ const selectedTeachingClass = ref(null);
|
|
|
|
|
|
|
|
|
|
|
|
const currentUserId = computed(() => userStore.userInfo.userId);
|
|
|
|
const currentUserId = computed(() => userStore.userInfo.userId);
|
|
|
|
const currentSchoolId = computed(() => userStore.userInfo.schoolId);
|
|
|
|
const currentSchoolId = computed(() => userStore.userInfo.schoolId);
|
|
|
|
|
|
|
|
const isManagerTeacher = computed(() => userStore.userInfo.teacherAdmin === true);
|
|
|
|
const legacyAdminEnabled = computed(() => userStore.schoolProductConfig?.organizationMode !== "TEACHING_CLASS_ONLY");
|
|
|
|
const legacyAdminEnabled = computed(() => userStore.schoolProductConfig?.organizationMode !== "TEACHING_CLASS_ONLY");
|
|
|
|
const facultyManagementEnabled = computed(() => userStore.schoolProductConfig?.facultyManagementEnabled ?? legacyAdminEnabled.value);
|
|
|
|
const facultyManagementEnabled = computed(() => userStore.schoolProductConfig?.facultyManagementEnabled ?? legacyAdminEnabled.value);
|
|
|
|
const majorManagementEnabled = computed(() => userStore.schoolProductConfig?.majorManagementEnabled ?? legacyAdminEnabled.value);
|
|
|
|
const majorManagementEnabled = computed(() => userStore.schoolProductConfig?.majorManagementEnabled ?? legacyAdminEnabled.value);
|
|
|
|
@ -236,15 +223,6 @@ const adminClassOptions = computed(() => {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const importCreateUploadData = computed(() => ({
|
|
|
|
|
|
|
|
schoolId: currentSchoolId.value,
|
|
|
|
|
|
|
|
schoolFacultyId: formInline.value.schoolFacultyId,
|
|
|
|
|
|
|
|
schoolMajorId: formInline.value.schoolMajorId,
|
|
|
|
|
|
|
|
className: formInline.value.className,
|
|
|
|
|
|
|
|
operatorId: currentUserId.value,
|
|
|
|
|
|
|
|
sourceClassIds: sourceAdminClassIds.value.join(","),
|
|
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const memberUploadData = computed(() => ({
|
|
|
|
const memberUploadData = computed(() => ({
|
|
|
|
teachingClassId: selectedTeachingClass.value?.schoolClassId || "",
|
|
|
|
teachingClassId: selectedTeachingClass.value?.schoolClassId || "",
|
|
|
|
operatorId: currentUserId.value,
|
|
|
|
operatorId: currentUserId.value,
|
|
|
|
@ -290,6 +268,7 @@ function defaultMemberParams() {
|
|
|
|
schoolClassId: "",
|
|
|
|
schoolClassId: "",
|
|
|
|
name: "",
|
|
|
|
name: "",
|
|
|
|
userName: "",
|
|
|
|
userName: "",
|
|
|
|
|
|
|
|
operatorId: currentUserId.value,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -304,6 +283,9 @@ function canOperateClass(schoolClass) {
|
|
|
|
if (schoolClass?.dataSource === "ZHIYUN") {
|
|
|
|
if (schoolClass?.dataSource === "ZHIYUN") {
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isManagerTeacher.value) {
|
|
|
|
|
|
|
|
return !schoolClass?.schoolId || schoolClass.schoolId === currentSchoolId.value;
|
|
|
|
|
|
|
|
}
|
|
|
|
if (normalizeClassType(schoolClass) === "ADMIN") {
|
|
|
|
if (normalizeClassType(schoolClass) === "ADMIN") {
|
|
|
|
return !schoolClass?.schoolId || schoolClass.schoolId === currentSchoolId.value;
|
|
|
|
return !schoolClass?.schoolId || schoolClass.schoolId === currentSchoolId.value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -419,71 +401,6 @@ function submitForm() {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function beforeImportCreate(file) {
|
|
|
|
|
|
|
|
if (activeClassType.value !== "TEACHING") {
|
|
|
|
|
|
|
|
proxy.$message.warning("请切换到教学班");
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!formInline.value.schoolFacultyId || !formInline.value.schoolMajorId || !formInline.value.className) {
|
|
|
|
|
|
|
|
proxy.$message.warning("请先填写院系、专业和班级名称");
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sourceAdminClassIds.value.length === 0) {
|
|
|
|
|
|
|
|
proxy.$message.warning("请选择来源行政班");
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
const total = await getSelectedSourceAdminStudentTotal();
|
|
|
|
|
|
|
|
if (total <= 0) {
|
|
|
|
|
|
|
|
proxy.$message.warning("所选来源行政班暂无学生,请先在学生管理中导入行政班学生后再创建教学班");
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!/\.(xls|xlsx)$/i.test(file.name)) {
|
|
|
|
|
|
|
|
proxy.$message.warning("请选择xls或xlsx格式文件");
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function getSelectedSourceAdminStudentTotal() {
|
|
|
|
|
|
|
|
const results = await Promise.all(sourceAdminClassIds.value.map((schoolClassId) => {
|
|
|
|
|
|
|
|
return indexApi.getStudentList({
|
|
|
|
|
|
|
|
index: 1,
|
|
|
|
|
|
|
|
size: 1,
|
|
|
|
|
|
|
|
schoolId: currentSchoolId.value,
|
|
|
|
|
|
|
|
schoolClassId,
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
return results.reduce((sum, res) => sum + Number(res.data?.total || 0), 0);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function uploadImportCreate(options, confirmMultiTeachingClass = false) {
|
|
|
|
|
|
|
|
const formData = buildUploadFormData(options.file, importCreateUploadData.value, confirmMultiTeachingClass);
|
|
|
|
|
|
|
|
return indexApi
|
|
|
|
|
|
|
|
.uploadTeachingClassByStudentMembers(formData)
|
|
|
|
|
|
|
|
.then((res) => {
|
|
|
|
|
|
|
|
handleImportCreateSuccess(res);
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.catch((error) => {
|
|
|
|
|
|
|
|
if (!isMultiTeachingClassConflict(error)) return;
|
|
|
|
|
|
|
|
return ElMessageBox.confirm(multiTeachingClassMessage(error), "学生已在其他教学班", {
|
|
|
|
|
|
|
|
confirmButtonText: "继续导入创建",
|
|
|
|
|
|
|
|
cancelButtonText: "取消",
|
|
|
|
|
|
|
|
type: "warning",
|
|
|
|
|
|
|
|
}).then(() => uploadImportCreate(options, true));
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function handleImportCreateSuccess(res) {
|
|
|
|
|
|
|
|
if (res?.statusCode && res.statusCode !== "OK" && res.statusCode !== 200) {
|
|
|
|
|
|
|
|
proxy.$message.error(res?.message || "导入创建失败");
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
proxy.$message.success("导入创建成功");
|
|
|
|
|
|
|
|
dialogVisible.value = false;
|
|
|
|
|
|
|
|
getList();
|
|
|
|
|
|
|
|
refreshAllClassList();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function openMemberDialog(schoolClass) {
|
|
|
|
function openMemberDialog(schoolClass) {
|
|
|
|
selectedTeachingClass.value = schoolClass;
|
|
|
|
selectedTeachingClass.value = schoolClass;
|
|
|
|
memberParams.value = {
|
|
|
|
memberParams.value = {
|
|
|
|
@ -653,28 +570,6 @@ async function downloadMemberImportTemplate() {
|
|
|
|
XLSX.writeFile(workbook, "教学班成员导入模板.xlsx");
|
|
|
|
XLSX.writeFile(workbook, "教学班成员导入模板.xlsx");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function downloadTeachingClassImportTemplate() {
|
|
|
|
|
|
|
|
const XLSX = await import("xlsx");
|
|
|
|
|
|
|
|
const templateSheet = XLSX.utils.aoa_to_sheet([
|
|
|
|
|
|
|
|
["所属院系", "所属专业", "行政班", "学号", "学生姓名", "性别", "手机号", "邮箱"],
|
|
|
|
|
|
|
|
["商学院", "电子商务", "2026电子商务1班-行政班", "20260001", "张三", "男", "13800000000", "zhangsan@example.com"],
|
|
|
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
templateSheet["!cols"] = [{ wch: 18 }, { wch: 18 }, { wch: 28 }, { wch: 18 }, { wch: 16 }, { wch: 10 }, { wch: 18 }, { wch: 26 }];
|
|
|
|
|
|
|
|
const guideSheet = XLSX.utils.aoa_to_sheet([
|
|
|
|
|
|
|
|
["填写说明"],
|
|
|
|
|
|
|
|
["1. 先在新增教学班弹窗中选择院系、专业并填写班级名称;来源行政班可以不选。"],
|
|
|
|
|
|
|
|
["2. 不要填写任何数据ID,院系、专业、行政班请填写页面中的名称。"],
|
|
|
|
|
|
|
|
["3. 学生必须已存在于对应行政班;如果行政班暂无学生,请先在学生管理中导入行政班学生。"],
|
|
|
|
|
|
|
|
["4. 系统会按模板学生名单加入新教学班;学生若已在其他教学班,将自动转入新教学班。"],
|
|
|
|
|
|
|
|
["5. 任意一行校验失败时,整批导入创建失败,教学班和成员关系都不会写入。"],
|
|
|
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
guideSheet["!cols"] = [{ wch: 96 }];
|
|
|
|
|
|
|
|
const workbook = XLSX.utils.book_new();
|
|
|
|
|
|
|
|
XLSX.utils.book_append_sheet(workbook, templateSheet, "教学班名单创建模板");
|
|
|
|
|
|
|
|
XLSX.utils.book_append_sheet(workbook, guideSheet, "填写说明");
|
|
|
|
|
|
|
|
XLSX.writeFile(workbook, "教学班名单创建模板.xlsx");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function deleteClass(id) {
|
|
|
|
function deleteClass(id) {
|
|
|
|
ElMessageBox.confirm("确定删除该班级吗?", "提示", {
|
|
|
|
ElMessageBox.confirm("确定删除该班级吗?", "提示", {
|
|
|
|
confirmButtonText: "确定",
|
|
|
|
confirmButtonText: "确定",
|
|
|
|
@ -866,13 +761,6 @@ onMounted(() => {
|
|
|
|
width: 100%;
|
|
|
|
width: 100%;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.import-create-actions {
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.member-toolbar {
|
|
|
|
.member-toolbar {
|
|
|
|
display: flex;
|
|
|
|
display: flex;
|
|
|
|
flex-wrap: wrap;
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|