204 lines
8.2 KiB
JavaScript
204 lines
8.2 KiB
JavaScript
/* 老师管理:增删改查
|
||
接口 /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 };
|
||
},
|
||
},
|
||
});
|