Files
1/static/js/pages/teachers.js
T
2026-09-14 10:23:36 +08:00

204 lines
8.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 老师管理:增删改查
接口 /teacher/ 没有查询参数,筛选在客户端做;
新增必须选一个已存在的班级,否则会撞外键约束 */
window.PAGES.push({
key: 'teachers',
title: '老师管理',
sub: '班主任与任课老师,工号可自动生成',
group: '数据管理',
icon: 'teacher',
component: {
name: 'TeachersPage',
template: `
<div>
<div class="card">
<div class="filters">
<el-input v-model="keyword" placeholder="按工号 / 姓名筛选" clearable style="width:220px" />
<span class="muted">共 {{ filtered.length }} 位老师</span>
</div>
<div class="card-head">
<div class="card-title">老师列表</div>
<div class="card-tools">
<el-button @click="load">刷新</el-button>
<el-button type="primary" @click="openCreate">+ 新增老师</el-button>
</div>
</div>
<el-table :data="filtered" v-loading="loading" border stripe row-key="t_id">
<el-table-column prop="t_id" label="ID" width="70" />
<el-table-column prop="t_no" label="工号" width="150" />
<el-table-column prop="t_name" label="姓名" width="110" />
<el-table-column label="班级" width="200" show-overflow-tooltip>
<template #default="{ row }">{{ className(row.class_id) }}</template>
</el-table-column>
<el-table-column label="角色" width="100">
<template #default="{ row }">
<el-tag size="small" :type="row.role === '班主任' ? 'primary' : 'info'" effect="light">
{{ row.role }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="t_phone" label="电话" width="140">
<template #default="{ row }">{{ dash(row.t_phone) }}</template>
</el-table-column>
<el-table-column prop="t_email" label="邮箱" min-width="160">
<template #default="{ row }">{{ dash(row.t_email) }}</template>
</el-table-column>
<el-table-column label="操作" width="140" fixed="right">
<template #default="{ row }">
<el-button link type="primary" @click="openEdit(row)">编辑</el-button>
<el-button link type="danger" @click="remove(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-alert class="mt12" type="info" :closable="false" show-icon
title="电话和邮箱列在数据库里都是 20 个字符,填长了会被后端拒绝" />
</div>
<el-dialog v-model="dialog" :title="editing ? '编辑老师' : '新增老师'" width="620px" destroy-on-close>
<el-form ref="formRef" :model="form" :rules="rules" label-width="88px">
<div class="form-grid">
<el-form-item label="工号" class="span2">
<div style="display:flex; gap:8px; width:100%">
<el-input v-model="form.t_no" placeholder="留空则自动生成" maxlength="20" />
<el-button :loading="generating" @click="generateNo">自动生成</el-button>
</div>
</el-form-item>
<el-form-item label="姓名" prop="t_name">
<el-input v-model="form.t_name" placeholder="老师姓名" maxlength="50" />
</el-form-item>
<el-form-item label="角色" prop="role">
<el-select v-model="form.role" placeholder="请选择角色" filterable allow-create style="width:100%">
<el-option v-for="r in ROLE_OPTIONS" :key="r" :label="r" :value="r" />
</el-select>
</el-form-item>
<el-form-item label="班级" prop="class_id" class="span2">
<el-select v-model="form.class_id" placeholder="请选择班级" style="width:100%">
<el-option v-for="c in classes" :key="c.class_id" :label="classLabel(c.class_id)" :value="c.class_id" />
</el-select>
</el-form-item>
<el-form-item label="电话">
<el-input v-model="form.t_phone" placeholder="电话" maxlength="20" show-word-limit />
</el-form-item>
<el-form-item label="邮箱">
<el-input v-model="form.t_email" placeholder="邮箱" maxlength="20" show-word-limit />
</el-form-item>
</div>
</el-form>
<template #footer>
<el-button @click="dialog = false">取消</el-button>
<el-button type="primary" :loading="saving" @click="submit">保存</el-button>
</template>
</el-dialog>
</div>
`,
setup() {
const loading = ref(false);
const saving = ref(false);
const generating = ref(false);
const rows = ref([]);
const classes = ref([]);
const keyword = ref('');
const dialog = ref(false);
const editing = ref(null);
const formRef = ref(null);
const emptyForm = () => ({ t_no: '', t_name: '', t_phone: '', t_email: '', class_id: null, role: '任课' });
const form = ref(emptyForm());
const rules = {
t_name: [{ required: true, message: '请填写姓名', trigger: 'blur' }],
class_id: [{ required: true, message: '请选择班级', trigger: 'change' }],
role: [{ required: true, message: '请选择角色', trigger: 'change' }],
};
// 接口没有查询条件,拿回全部后在本地过滤
const filtered = computed(() => {
const k = keyword.value.trim().toLowerCase();
if (!k) return rows.value;
return rows.value.filter(r =>
String(r.t_no || '').toLowerCase().includes(k) ||
String(r.t_name || '').toLowerCase().includes(k));
});
const load = async () => {
loading.value = true;
try { rows.value = await TeacherApi.list(); }
catch (e) { toastErr(e); }
finally { loading.value = false; }
};
const generateNo = async () => {
generating.value = true;
try {
const r = await TeacherApi.generateNo();
form.value.t_no = r.t_no;
toastOk('已生成工号:' + r.t_no);
} catch (e) { toastErr(e); }
finally { generating.value = false; }
};
const openCreate = () => {
editing.value = null;
form.value = emptyForm();
dialog.value = true;
};
const openEdit = (row) => {
editing.value = row.t_id;
form.value = {
t_no: row.t_no, t_name: row.t_name, t_phone: row.t_phone,
t_email: row.t_email, class_id: row.class_id, role: row.role,
};
dialog.value = true;
};
const submit = async () => {
if (!formRef.value) return;
try { await formRef.value.validate(); } catch (e) { return; }
saving.value = true;
try {
if (editing.value) {
await TeacherApi.update(editing.value, pruneEmpty(form.value));
toastOk('修改成功');
} else {
await TeacherApi.create(pruneEmpty(form.value));
toastOk('新增成功');
}
dialog.value = false;
await load();
} catch (e) { toastErr(e); }
finally { saving.value = false; }
};
const remove = async (row) => {
try {
await ElementPlus.ElMessageBox.confirm(
`确定删除老师「${row.t_name}」吗?`,
'删除确认', { type: 'warning', confirmButtonText: '确定删除', cancelButtonText: '取消' });
} catch (e) { return; }
try {
await TeacherApi.remove(row.t_id);
toastOk('删除成功');
await load();
} catch (e) { toastErr(e); }
};
onMounted(async () => {
try { classes.value = await Cache.loadClasses(); }
catch (e) { toastErr(e); }
load();
});
return { loading, saving, generating, rows, classes, keyword, filtered, dialog,
editing, formRef, form, rules, load, generateNo, openCreate, openEdit,
submit, remove, ROLE_OPTIONS, dash, className, classLabel };
},
},
});