<script setup>
import { reactive, ref, onMounted, computed, nextTick } from "vue";
import { ElMessage } from "element-plus";
import { queryPageApi, addApi, updateApi, queryDeptApi } from "@/api/emp";
import { Plus } from "@element-plus/icons-vue";
const formRef = ref();
const formInline = reactive({
user: "",
region: "",
date: null, // 新增初始化
begin: "",
end: "",
});
const GENDER_MAP = { 1: "男", 2: "女" };
const JOB_MAP = {
1: "班主任",
2: "讲师",
3: "学工主管",
4: "教研主管",
5: "咨询师",
};
// 日期范围验证器(确保开始/结束时间成对出现)
const validateDates = (rule, value, callback) => {
const { begin, end } = formInline;
// 检查成对存在性
if (!!begin !== !!end) {
callback(new Error("开始时间和结束时间必须同时填写或同时为空"));
return;
}
// 当两者都存在时检查时间顺序
if (begin && end) {
if (new Date(end) < new Date(begin)) {
callback(new Error("结束日期不能早于开始日期"));
return;
}
}
callback();
};
// 表单验证规则配置(Element Plus 校验规则)
const rules = reactive({
begin: [
{
validator: (rule, value, callback) => {
validateDates(rule, value, callback);
formRef.value?.validateField("end"); // 触发结束日期重新校验
},
trigger: ["change", "blur"], // 增加 blur 触发时机
},
],
end: [
{
validator: (rule, value, callback) => {
validateDates(rule, value, callback);
formRef.value?.validateField("begin"); // 触发开始日期重新校验
},
trigger: ["change", "blur"], // 增加 blur 触发时机
},
],
username: [
{ required: true, message: "请输入用户名", trigger: "blur" },
{ min: 2, max: 20, message: "用户名长度应在2到20个字符之间", trigger: "blur" },
],
name: [
{ required: true, message: "请输入姓名", trigger: "blur" },
{ min: 2, max: 10, message: "姓名长度应在2到10个字符之间", trigger: "blur" },
],
gender: [{ required: true, message: "请选择性别", trigger: "change" }],
phone: [
{ required: true, message: "请输入手机号", trigger: "blur" },
{ pattern: /^1\d{10}$/, message: "请输入有效的手机号", trigger: "blur" },
],
job: [{ required: true, message: "请选择职位", trigger: "change" }],
deptId: [{ required: true, message: "请选择部门", trigger: "change" }],
entryDate: [{ required: true, message: "请选择入职日期", trigger: "change" }],
});
// 表单提交处理(查询操作)
const onSubmit = () => {
search();
console.log("提交查询参数:", {
name: formInline.user,
gender: formInline.region,
startDate: formInline.begin,
end: formInline.end,
});
};
// 日期字段清除处理(联动清空两个日期)
const handleDateClear = () => {
formInline.date = null; // 新增
formInline.begin = "";
formInline.end = "";
};
// 表单重置方法(清空所有字段)
const clearForm = () => {
formInline.user = "";
formInline.region = "";
handleDateClear(); // 复用日期清除方法
search();
};
// 示例数据
const empList = ref([]);
// 分页配置
const currentPage = ref(1);
const pageSize = ref(10);
const total = ref(0);
// 分页处理
const handleSizeChange = (val) => {
pageSize.value = val; // 更新每页条数
currentPage.value = 1; // 重置到第一页
search();
};
const handleCurrentChange = (val) => {
currentPage.value = val; // 更新当前页码
search();
};
//查询员工
const search = async () => {
console.log("Search:", formInline);
try {
const result = await queryPageApi(
formInline.user,
formInline.region ? parseInt(formInline.region) : "",
formInline.begin,
formInline.end,
currentPage.value,
pageSize.value
);
console.log("API Response:", result); // 添加响应日志
if (result.code === 1) {
empList.value = result.data?.rows || [];
total.value = result.data?.total || 0;
} else {
ElMessage.error(result.msg || "查询失败");
}
} catch (e) {
console.error("搜索失败:", e); // 添加错误日志
ElMessage.error("请求异常");
empList.value = [];
}
};
// --------------------新增员工--------------------
const mode = ref("add"); // 新增模式标识
const dialogVisible = ref(false);
const dialogTitle = computed(() => (mode.value === "add" ? "新增员工" : "编辑员工"));
const formData = reactive({
id: "",
username: "",
name: "",
gender: "",
phone: "",
job: "",
salary: "",
deptId: "",
entryDate: "",
image: "",
exprList: [
// 修改字段名与数据模型对齐
{
dateRange: [],
company: "",
job: "", // 原position改为job
},
],
});
//钩子函数
onMounted(async () => {
try {
const res = await queryDeptApi();
if (res.code === 1) {
deptOptions.value = res.data.map((item) => ({
label: item.name,
value: String(item.id),
}));
}
} catch (e) {
ElMessage.error("部门加载失败");
}
// 确保无论如何都执行查询
search();
});
// 部门数据获取
const deptOptions = ref([]);
// 打开对话框方法
const openDialog = (rowData) => {
dialogVisible.value = true; // 必须先设置对话框可见
mode.value = rowData ? "edit" : "add";
if (rowData) {
nextTick(() => {
Object.assign(formData, {
...rowData,
gender: String(rowData.gender),
job: String(rowData.job),
deptId: String(rowData.deptId),
image: rowData.image || "",
});
dialogForm.value?.clearValidate?.();
});
} else {
resetFormData();
}
};
// 新增清空表单方法
const resetFormData = () => {
Object.assign(formData, {
id: "",
username: "",
name: "",
gender: "",
phone: "",
job: "",
salary: "",
deptId: "",
entryDate: "",
image: "",
exprList: [
{
dateRange: [],
company: "",
job: "",
},
],
});
};
// 新增提交方法
const submitForm = async () => {
try {
const payload = {
...formData,
gender: Number(formData.gender),
job: Number(formData.job),
deptId: Number(formData.deptId),
salary: Number(formData.salary),
exprList: formData.exprList.map((exp) => ({
company: exp.company,
job: exp.job,
begin: exp.dateRange?.[0] || "",
end: exp.dateRange?.[1] || "",
})),
};
const result =
mode.value === "add" ? await addApi(payload) : await updateApi(payload);
if (result.code === 1) {
ElMessage.success(mode.value === "add" ? "新增成功" : "修改成功");
dialogVisible.value = false;
search();
}
} catch (error) {
ElMessage.error("提交失败");
}
};
</script>
<template>
<!-- 页面主标题 -->
<h2 class="page-title">员工管理</h2>
<!-- 搜索筛选表单 -->
<el-form
ref="formRef"
:inline="true"
:model="formInline"
:rules="rules"
class="demo-form-inline"
>
<el-row :gutter="16" class="full-width-row">
<!-- 姓名查询模块 -->
<el-col :span="5">
<el-form-item label="姓名" prop="user">
<el-input v-model="formInline.user" placeholder="员工姓名" clearable />
</el-form-item>
</el-col>
<!-- 性别筛选模块 -->
<el-col :span="5">
<el-form-item label="性别" prop="region">
<el-select v-model="formInline.region" placeholder="性别" clearable>
<el-option label="男" value="1" />
<el-option label="女" value="2" />
</el-select>
</el-form-item>
</el-col>
<!-- 入职时间范围选择 -->
<el-col :span="8">
<el-form-item label="入职时间" prop="dateRange">
<el-date-picker
v-model="formInline.date"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
style="width: 100%"
/>
</el-form-item>
</el-col>
<!-- 操作按钮组 -->
<el-col :span="null" class="flex-auto">
<el-form-item>
<el-button type="primary" @click="onSubmit">查询</el-button>
<el-button @click="clearForm">清除</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- 操作按钮组 -->
<el-col :span="20" class="button-group">
<el-form-item>
<el-button type="primary" class="ml-2" @click="openDialog">+ 新增</el-button>
<el-button type="danger">- 删除</el-button>
</el-form-item>
</el-col>
<!-- --------------------表格-------------------- -->
<el-table :data="empList" border style="width: 100%">
<el-table-column type="selection" width="55" align="center"></el-table-column>
<el-table-column
prop="name"
label="姓名"
width="120"
align="center"
></el-table-column>
<el-table-column label="性别" width="100" align="center">
<template #default="scope">
{{ scope.row.gender == 1 ? "男" : "女" }}
</template>
</el-table-column>
<el-table-column label="头像" width="170" align="center">
<template #default="scope">
<img :src="scope.row.image" alt="Avatar" class="avatar" />
</template>
</el-table-column>
<el-table-column
prop="deptName"
label="部门名称"
width="170"
align="center"
></el-table-column>
<el-table-column label="职位" width="120" align="center">
<template #default="scope">
<span v-if="scope.row.job == 1">班主任</span>
<span v-else-if="scope.row.job == 2">讲师</span>
<span v-else-if="scope.row.job == 3">学工主管</span>
<span v-else-if="scope.row.job == 4">教研主管</span>
<span v-else-if="scope.row.job == 5">咨询师</span>
<span v-else>其他</span>
</template>
</el-table-column>
<el-table-column
prop="entryDate"
label="入职日期"
width="180"
align="center"
></el-table-column>
<el-table-column
prop="updateTime"
label="最后操作时间"
width="210"
align="center"
></el-table-column>
<el-table-column label="操作" fixed="right" align="center">
<template #default="scope">
<el-button size="small" type="primary" @click="openDialog(scope.row)"
>编辑</el-button
>
<el-button size="small" type="danger" @click="">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[10, 20, 30, 40]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
>
</el-pagination>
<!-- ---------------新增----------------- -->
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="50%">
<el-form :model="formData" :rules="rules" label-width="120px" ref="dialogForm">
<!-- 基本信息 -->
<el-divider content-position="left">基本信息</el-divider>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="用户名" prop="username">
<el-input
v-model="formData.username"
placeholder="请输入员工用户名,2-20个字"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="姓名" prop="name">
<el-input v-model="formData.name" placeholder="请输入员工姓名,2-10个字" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="性别" prop="gender">
<el-select v-model="formData.gender" placeholder="请选择">
<el-option label="男" value="1" />
<el-option label="女" value="2" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="手机号" prop="phone">
<el-input v-model="formData.phone" placeholder="请输入员工手机号" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="职位" prop="job">
<el-select v-model="formData.job" placeholder="请选择">
<el-option label="班主任" value="1" />
<el-option label="讲师" value="2" />
<el-option label="学工主管" value="3" />
<el-option label="教研主管" value="4" />
<el-option label="咨询师" value="5" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="薪资">
<el-input v-model="formData.salary" placeholder="请输入员工薪资" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="所属部门" prop="deptId">
<el-select v-model="formData.deptId" placeholder="请选择">
<el-option
v-for="item in deptOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="入职日期" prop="entryDate">
<el-date-picker
v-model="formData.entryDate"
type="date"
value-format="YYYY-MM-DD"
placeholder="选择日期"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="头像">
<el-upload
action="#"
:auto-upload="false"
:show-file-list="false"
:on-change="
(file) => {
const reader = new FileReader();
reader.onload = (e) => (formData.image = e.target.result);
reader.readAsDataURL(file.raw);
}
"
>
<img v-if="formData.image" :src="formData.image" class="avatar" />
<el-icon v-else class="avatar-uploader-icon">
<Plus />
</el-icon>
</el-upload>
</el-form-item>
</el-col>
</el-row>
<!-- 工作经历 -->
<el-divider content-position="left">
工作经历
<el-button
type="primary"
size="small"
@click="formData.exprList.push({ dateRange: [], company: '', job: '' })"
>
添加工作经历
</el-button>
</el-divider>
<div v-for="(exp, index) in formData.exprList" :key="index">
<el-row :gutter="3">
<el-col :span="10">
<el-form-item size="small" label="时间" label-width="80px">
<el-date-picker
v-model="exp.dateRange"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item size="small" label="公司" label-width="60px">
<el-input placeholder="请输入公司名称" v-model="exp.company" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item size="small" label="职位" label-width="60px">
<el-input placeholder="请输入职位" v-model="exp.job" />
</el-form-item>
</el-col>
<el-col :span="1">
<el-button
type="danger"
@click="formData.exprList.splice(index, 1)"
size="small"
>删除</el-button
>
</el-col>
</el-row>
</div>
</el-form>
<el-form-item class="dialog-footer">
<el-button type="primary" @click="submitForm">保存</el-button>
<el-button @click="dialogVisible = false">取消</el-button>
</el-form-item>
</el-dialog>
</template>
<style scoped>
.avatar {
width: 40px;
height: 40px;
object-fit: cover;
border-radius: 50%;
}
/* 页面标题样式 */
.page-title {
margin-bottom: 24px;
color: #303133;
}
/* 表单元素统一宽度 */
.demo-form-inline :deep(.el-input),
.demo-form-inline :deep(.el-select) {
--el-input-width: 220px;
--el-select-width: 220px;
}
/* 日期范围选择布局 */
.date-range {
width: 100%;
display: flex;
align-items: center;
}
.separator {
text-align: center;
}
/* 操作按钮间距 */
.action-buttons {
margin-left: 16px;
}
</style>
前端304显示空白