Files
1/static/js/pages/emps.js
T

206 lines
8.6 KiB
JavaScript
Raw Normal View History

2026-09-14 10:23:36 +08:00
/* 就业管理:增删改查
学号必须从学生下拉框里选:表的 stu_no 是指向 wl_student 的外键,
手填一个不存在的学号会直接撞外键约束报 500 */
window.PAGES.push({
key: 'emps',
title: '就业管理',
sub: '学生就业去向与薪资,一个学生一条记录',
group: '数据管理',
icon: 'emp',
component: {
name: 'EmpsPage',
template: `
<div>
<div class="card">
<div class="filters">
<el-input v-model="filter.company_name" placeholder="公司名称(模糊)" clearable style="width:200px" @keyup.enter="load" />
<el-input v-model="keyword" placeholder="按学号筛选" clearable style="width:160px" />
<el-button type="primary" @click="load">查询</el-button>
<el-button @click="reset">重置</el-button>
<span class="muted">共 {{ filtered.length }} 条</span>
</div>
<div class="card-head">
<div class="card-title">就业列表</div>
<div class="card-tools">
<el-button type="primary" @click="openCreate">+ 新增就业</el-button>
</div>
</div>
<el-table :data="filtered" v-loading="loading" border stripe row-key="stu_no">
<el-table-column prop="stu_no" label="学号" width="130" />
<el-table-column label="学生姓名" width="120">
<template #default="{ row }">
<span v-if="row.stu_name">{{ row.stu_name }}</span>
<el-tag v-else size="small" type="info" effect="plain">学生已删除</el-tag>
</template>
</el-table-column>
<el-table-column prop="company_name" label="公司名称" min-width="170" show-overflow-tooltip />
<el-table-column label="薪资" width="110">
<template #default="{ row }">
<span v-if="row.salary">{{ row.salary.toLocaleString() }}</span>
<span v-else class="muted">—</span>
</template>
</el-table-column>
<el-table-column label="就业开放时间" width="150">
<template #default="{ row }">{{ dash(fmtDateTime(row.emp_open_time)) }}</template>
</el-table-column>
<el-table-column label="offer 下发时间" width="150">
<template #default="{ row }">{{ dash(fmtDateTime(row.offer_time)) }}</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="薪资、两个时间留空时会走数据库默认值(薪资默认 15000,offer 时间取当前时间)" />
</div>
<el-dialog v-model="dialog" :title="editing ? '编辑就业信息' : '新增就业信息'" width="620px" destroy-on-close>
<el-form ref="formRef" :model="form" :rules="rules" label-width="104px">
<div class="form-grid">
<el-form-item label="学生" prop="stu_no" class="span2">
<el-select v-model="form.stu_no" placeholder="按学号或姓名搜索" filterable
:disabled="!!editing" style="width:100%">
<el-option v-for="s in students" :key="s.stu_no" :label="studentLabel(s)" :value="s.stu_no" />
</el-select>
</el-form-item>
<el-form-item label="公司名称" prop="company_name" class="span2">
<el-input v-model="form.company_name" placeholder="就业公司" maxlength="100" />
</el-form-item>
<el-form-item label="薪资">
<el-input-number v-model="form.salary" :min="0" :step="1000"
controls-position="right" style="width:100%" placeholder="默认 15000" />
</el-form-item>
<el-form-item label="就业开放时间">
<el-date-picker v-model="form.emp_open_time" type="datetime"
value-format="YYYY-MM-DDTHH:mm:ss" placeholder="可不填"
style="width:100%" />
</el-form-item>
<el-form-item label="offer 下发时间" class="span2">
<el-date-picker v-model="form.offer_time" type="datetime"
value-format="YYYY-MM-DDTHH:mm:ss" placeholder="可不填,默认当前时间"
style="width:100%" />
</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 rows = ref([]);
const students = ref([]);
const keyword = ref('');
const dialog = ref(false);
const editing = ref(null);
const formRef = ref(null);
const filter = ref({ company_name: '' });
const emptyForm = () => ({
stu_no: null, company_name: '', salary: null,
emp_open_time: null, offer_time: null,
});
const form = ref(emptyForm());
const rules = {
stu_no: [{ required: true, message: '请选择学生', trigger: 'change' }],
company_name: [{ required: true, message: '请填写公司名称', trigger: 'blur' }],
};
const filtered = computed(() => {
const k = keyword.value.trim().toLowerCase();
if (!k) return rows.value;
return rows.value.filter(r => String(r.stu_no || '').toLowerCase().includes(k));
});
const load = async () => {
loading.value = true;
try {
rows.value = await EmpApi.list({ company_name: filter.value.company_name, limit: 1000 });
} catch (e) { toastErr(e); }
finally { loading.value = false; }
};
const reset = () => {
filter.value = { company_name: '' };
keyword.value = '';
load();
};
const openCreate = () => {
editing.value = null;
form.value = emptyForm();
dialog.value = true;
};
const openEdit = (row) => {
// 学号是主键,EmpUpdate 里也没有这个字段,编辑时只允许改其余信息
editing.value = row.stu_no;
form.value = {
stu_no: row.stu_no, company_name: row.company_name, salary: row.salary,
emp_open_time: row.emp_open_time ? String(row.emp_open_time).slice(0, 19) : null,
offer_time: row.offer_time ? String(row.offer_time).slice(0, 19) : null,
};
dialog.value = true;
};
const submit = async () => {
if (!formRef.value) return;
try { await formRef.value.validate(); } catch (e) { return; }
saving.value = true;
try {
const payload = pruneEmpty(form.value);
if (editing.value) {
delete payload.stu_no; // 主键不参与修改
await EmpApi.update(editing.value, payload);
toastOk('保存成功');
} else {
await EmpApi.create(payload);
// 该学生的记录若曾被删除,后端会直接把旧记录复活,所以提示统一写"保存成功"
toastOk('保存成功');
}
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 EmpApi.remove(row.stu_no);
toastOk('删除成功');
await load();
} catch (e) { toastErr(e); }
};
onMounted(async () => {
try { students.value = await Cache.loadStudents(); }
catch (e) { toastErr(e); }
load();
});
return { loading, saving, rows, students, keyword, filtered, filter, dialog, editing,
formRef, form, rules, load, reset, openCreate, openEdit, submit, remove,
dash, fmtDateTime, studentLabel };
},
},
});