/* 学生管理:增删改查 + 按学号/姓名/班级/顾问筛选
注意:学号是后端按班级开课时间生成的,表单里不给填,新增成功后提示出来 */
window.PAGES.push({
key: 'students',
title: '学生管理',
sub: '学生基本信息,学号由班级开课时间自动生成',
group: '数据管理',
icon: 'student',
component: {
name: 'StudentsPage',
template: `
查询
重置
学生列表
共 {{ rows.length }} 人
+ 新增学生
{{ className(row.class_id) }}
{{ advisorName(row.advisor_id) }}
{{ row.stu_gender }}
—
{{ dash(row.stu_age) }}
{{ dash(row.native_place) }}
{{ dash(row.graduate_school) }}
{{ dash(row.major) }}
{{ dash(row.edu) }}
{{ dash(fmtDate(row.in_time)) }}
{{ dash(fmtDate(row.out_time)) }}
编辑
删除
取消
保存
`,
setup() {
const loading = ref(false);
const saving = ref(false);
const rows = ref([]);
const classes = ref([]);
const advisors = ref([]);
const dialog = ref(false);
const editing = ref(null);
const formRef = ref(null);
const filter = ref({ stu_no: '', stu_name: '', class_id: null, advisor_id: null });
const page = ref(1);
const pageSize = ref(10);
const emptyForm = () => ({
class_id: null, advisor_id: null, stu_name: '', native_place: '',
graduate_school: '', major: '', in_time: null, out_time: null,
edu: null, stu_age: null, stu_gender: null,
});
const form = ref(emptyForm());
// 学号是后端生成的,所以班级必选;其余字段都可空
const rules = {
class_id: [{ required: true, message: '请选择班级', trigger: 'change' }],
stu_name: [{ required: true, message: '请填写姓名', trigger: 'blur' }],
};
// 表格是客户端分页:接口本身没有分页参数,一次把命中的都取回来
const pagedRows = computed(() => {
const start = (page.value - 1) * pageSize.value;
return rows.value.slice(start, start + pageSize.value);
});
const load = async () => {
loading.value = true;
try {
rows.value = await StudentApi.list({
stu_no: filter.value.stu_no,
stu_name: filter.value.stu_name,
class_id: filter.value.class_id,
advisor_id: filter.value.advisor_id,
});
page.value = 1;
} catch (e) { toastErr(e); }
finally { loading.value = false; }
};
const reset = () => {
filter.value = { stu_no: '', stu_name: '', class_id: null, advisor_id: null };
load();
};
const openCreate = () => {
editing.value = null;
form.value = emptyForm();
dialog.value = true;
};
const openEdit = (row) => {
editing.value = row.stu_no;
form.value = {
class_id: row.class_id, advisor_id: row.advisor_id, stu_name: row.stu_name,
native_place: row.native_place, graduate_school: row.graduate_school,
major: row.major, in_time: fmtDate(row.in_time) || null,
out_time: fmtDate(row.out_time) || null, edu: row.edu,
stu_age: row.stu_age, stu_gender: row.stu_gender,
};
dialog.value = true;
};
const submit = async () => {
if (!formRef.value) return;
try { await formRef.value.validate(); } catch (e) { return; }
saving.value = true;
try {
// pruneEmpty:没填的字段不下发,避免把可空字段写成空字符串
const payload = pruneEmpty(form.value);
if (editing.value) {
await StudentApi.update(editing.value, payload);
toastOk('修改成功');
} else {
const created = await StudentApi.create(payload);
toastOk('新增成功,学号:' + created.stu_no);
}
Cache.invalidate('students');
dialog.value = false;
await load();
} catch (e) { toastErr(e); }
finally { saving.value = false; }
};
const remove = async (row) => {
try {
await ElementPlus.ElMessageBox.confirm(
`确定删除学生「${row.stu_name || row.stu_no}」吗?`,
'删除确认', { type: 'warning', confirmButtonText: '确定删除', cancelButtonText: '取消' });
} catch (e) { return; }
try {
await StudentApi.remove(row.stu_no);
toastOk('删除成功');
Cache.invalidate('students');
await load();
} catch (e) { toastErr(e); }
};
// 班级/顾问下拉的数据先准备好,再拉学生列表
onMounted(async () => {
try {
[classes.value, advisors.value] = await Promise.all([
Cache.loadClasses(), Cache.loadAdvisors(),
]);
} catch (e) { toastErr(e); }
load();
});
return {
loading, saving, rows, classes, advisors, dialog, editing, formRef,
filter, form, rules, page, pageSize, pagedRows,
load, reset, openCreate, openEdit, submit, remove,
GENDER_OPTIONS, EDU_OPTIONS, dash, fmtDate, className, advisorName, classLabel,
};
},
},
});