<template>
<el-container style="height: 100vh; overflow: hidden;">
<!-- 侧边栏 -->
<el-aside width="200px" style="background-color: #304156;">
<el-menu default-active="1" class="el-menu-vertical-demo" background-color="#304156" text-color="#bfcbd9"
active-text-color="#409EFF">
<el-menu-item index="1">
<i class="el-icon-user"></i>
<span>员工管理</span>
</el-menu-item>
</el-menu>
</el-aside>
<!-- 主内容区 -->
<el-container>
<!-- 头部 -->
<el-header class="app-header">
<h2 class="app-title">员工管理系统</h2>
</el-header>
<!-- 主要内容 -->
<el-main class="app-content">
<!-- 查询条件 -->
<div class="query-section">
<el-row :gutter="20">
<el-col :span="4">
<el-input v-model="queryParams.name" placeholder="请输入姓名" clearable />
</el-col>
<el-col :span="4">
<el-select v-model="queryParams.gender" placeholder="请选择性别" clearable>
<el-option label="男" :value="0" />
<el-option label="女" :value="1" />
</el-select>
</el-col>
<el-col :span="4">
<el-select v-model="queryParams.job" placeholder="请选择职位" clearable>
<el-option v-for="item in jobOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-col>
<el-col :span="6">
<el-date-picker v-model="queryParams.dateRange" type="daterange" start-placeholder="开始日期"
end-placeholder="结束日期" format="YYYY-MM-DD" value-format="YYYY-MM-DD" />
</el-col>
<el-col :span="6" class="action-buttons">
<el-button type="primary" @click="fetchData" icon="el-icon-search">搜索</el-button>
<el-button type="success" @click="showAddDialog" icon="el-icon-plus">新增</el-button>
<el-button type="danger" @click="batchDelete" icon="el-icon-delete">批量删除</el-button>
</el-col>
</el-row>
</div>
<!-- 数据表格 -->
<div class="table-section">
<el-table :data="tableData" border stripe style="width: 100%" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column prop="id" label="ID" width="80" align="center" />
<el-table-column prop="name" label="姓名" width="120" />
<el-table-column label="头像" width="100" align="center">
<template #default="scope">
<el-avatar v-if="scope.row.image" :src="scope.row.image" :size="50" shape="square"
:preview-src-list="[scope.row.image]" />
<el-avatar v-else :size="50" shape="square">
<i class="el-icon-user-solid" style="font-size: 24px;" />
</el-avatar>
</template>
</el-table-column>
<el-table-column prop="gender" label="性别" width="80" align="center">
<template #default="scope">
<el-tag :type="scope.row.gender === 0 ? 'primary' : 'danger'">
{{ scope.row.gender === 0 ? '男' : '女' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="job" label="职位" width="150">
<template #default="scope">
<el-tag :type="getJobTagType(scope.row.job)">
{{ jobMap[scope.row.job] || '未知' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="entrydate" label="入职时间" width="120" align="center" />
<el-table-column prop="createTime" label="创建时间" width="180" align="center" />
<!-- 添加最后修改时间列 -->
<el-table-column prop="updateTime" label="最后修改时间" width="180" align="center" />
<el-table-column label="操作" width="200" align="center" fixed="right">
<template #default="scope">
<el-button size="small" type="primary" icon="el-icon-edit" @click="handleEdit(scope.row)">编辑</el-button>
<el-button size="small" type="danger" icon="el-icon-delete"
@click="handleDelete(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页组件 -->
<div class="pagination-section">
<el-pagination background layout="total, prev, pager, next, sizes" :total="total"
:page-sizes="[5, 10, 20, 50]" :page-size="queryParams.pageSize" v-model:current-page="queryParams.pageNum"
@current-change="fetchData" @size-change="handleSizeChange" />
</div>
</el-main>
</el-container>
</el-container>
<!-- 新增/编辑对话框 - 优化样式 -->
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="700px" :close-on-click-modal="false">
<el-form :model="form" ref="formRef" :rules="formRules" label-width="100px" label-position="left">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="用户名" prop="username">
<el-input v-model="form.username" />
</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="form.gender" placeholder="请选择性别" style="width: 100%">
<el-option label="男" :value="0" />
<el-option label="女" :value="1" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="职位" prop="job">
<el-select v-model="form.job" placeholder="请选择职位" style="width: 100%">
<el-option v-for="item in jobOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="密码" prop="password" v-if="!isEdit">
<el-input v-model="form.password" show-password />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="入职时间" prop="entrydate">
<el-date-picker v-model="form.entrydate" type="date" placeholder="选择日期" format="YYYY-MM-DD"
value-format="YYYY-MM-DD" style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="头像链接" prop="image">
<el-input v-model="form.image" placeholder="请输入图片URL" />
<div class="avatar-preview" v-if="form.image">
<el-image :src="form.image" fit="cover" style="width: 100px; height: 100px; margin-top: 10px;"
:preview-src-list="[form.image]" />
</div>
</el-form-item>
<el-form-item class="form-actions">
<el-button type="primary" @click="submitForm">提交</el-button>
<el-button @click="dialogVisible = false">取消</el-button>
</el-form-item>
</el-form>
</el-dialog>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import axios from 'axios';
import { ElMessage, ElMessageBox } from 'element-plus';
// 设置 axios 实例
const apiClient = axios.create({
baseURL: 'http://localhost:8080/emps',
timeout: 5000,
});
// 表格数据
const tableData = ref([]);
const total = ref(0);
const selectedRows = ref([]);
const formRef = ref(null);
// 查询参数
const queryParams = reactive({
pageNum: 1,
pageSize: 5,
name: '',
gender: null,
job: null,
dateRange: []
});
// 表单数据
const form = reactive({
id: null,
username: '',
password: '',
name: '',
gender: null,
job: null,
image: '',
entrydate: ''
});
// 表单验证规则
const formRules = {
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
gender: [{ required: true, message: '请选择性别', trigger: 'change' }],
job: [{ required: true, message: '请选择职位', trigger: 'change' }],
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
entrydate: [{ required: true, message: '请选择入职日期', trigger: 'change' }]
};
// 对话框控制
const dialogVisible = ref(false);
const dialogTitle = ref('新增员工');
const isEdit = ref(false);
// 职位映射表
const jobMap = {
1: '班主任',
2: '讲师',
3: '学工主管',
4: '教研主管',
5: '咨询师'
};
// 职位选项
const jobOptions = [
{ label: '班主任', value: 1 },
{ label: '讲师', value: 2 },
{ label: '学工主管', value: 3 },
{ label: '教研主管', value: 4 },
{ label: '咨询师', value: 5 }
];
// 获取职位标签类型
const getJobTagType = (job) => {
const types = ['', 'success', 'warning', 'danger', 'info', 'primary'];
return types[job] || 'info';
};
// 获取数据
const fetchData = async () => {
const params = {
page: queryParams.pageNum,
pageSize: queryParams.pageSize,
name: queryParams.name,
gender: queryParams.gender,
job: queryParams.job,
begin: queryParams.dateRange[0] || '',
end: queryParams.dateRange[1] || ''
};
try {
const res = await apiClient.get('', { params });
if (res.data.code === 1) {
tableData.value = res.data.data.rows.map(item => ({
...item,
// 格式化最后修改时间
updateTime: formatDateTime(item.updateTime)
}));
total.value = res.data.data.total;
} else {
ElMessage.error('获取数据失败:' + res.data.msg);
}
} catch (error) {
console.error('请求出错:', error);
ElMessage.error('网络请求失败,请检查后端是否运行正常');
}
};
// 时间格式化函数
const formatDateTime = (dateTime) => {
if (!dateTime) return '';
// 如果是字符串直接返回
if (typeof dateTime === 'string') {
// 尝试解析ISO格式时间
try {
const date = new Date(dateTime);
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
}).replace(/\//g, '-');
} catch (e) {
return dateTime;
}
}
// 如果是Date对象或时间戳
const date = new Date(dateTime);
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
}).replace(/\//g, '-');
};
// 显示新增对话框
const showAddDialog = () => {
dialogTitle.value = '新增员工';
isEdit.value = false;
Object.assign(form, {
id: null,
username: '',
password: '',
name: '',
gender: null,
job: null,
image: '',
entrydate: ''
});
dialogVisible.value = true;
};
// 显示编辑对话框
const handleEdit = (row) => {
dialogTitle.value = '编辑员工';
isEdit.value = true;
Object.assign(form, { ...row });
dialogVisible.value = true;
};
// 提交表单
const submitForm = async () => {
try {
await formRef.value.validate();
if (isEdit.value) {
await apiClient.put('', form);
ElMessage.success('员工信息更新成功');
} else {
await apiClient.post('', form);
ElMessage.success('员工添加成功');
}
dialogVisible.value = false;
fetchData();
} catch (error) {
if (error.name !== 'Error') {
console.error('保存失败:', error);
ElMessage.error('操作失败:' + (error.response?.data?.message || error.message));
}
}
};
// 删除员工
const handleDelete = async (id) => {
try {
await ElMessageBox.confirm(`确认删除ID为 ${id} 的员工吗?`, '删除确认', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
});
await apiClient.delete(`/${[id]}`);
ElMessage.success('删除成功');
fetchData();
} catch (error) {
if (error !== 'cancel') {
console.error('删除失败:', error);
ElMessage.error('删除失败:' + (error.response?.data?.message || error.message));
}
}
};
// 批量删除
const batchDelete = async () => {
if (selectedRows.value.length === 0) {
ElMessage.warning('请至少选择一条记录');
return;
}
try {
const ids = selectedRows.value.map(item => item.id);
await ElMessageBox.confirm(`确认删除选中的 ${ids.length} 条员工吗?`, '批量删除确认', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
});
await apiClient.delete(`/${ids}`);
ElMessage.success(`成功删除 ${ids.length} 条记录`);
fetchData();
} catch (error) {
if (error !== 'cancel') {
console.error('批量删除失败:', error);
ElMessage.error('删除失败:' + (error.response?.data?.message || error.message));
}
}
};
// 表格选择监听
const handleSelectionChange = (rows) => {
selectedRows.value = rows;
};
// 处理分页大小变化
const handleSizeChange = (size) => {
queryParams.pageSize = size;
fetchData();
};
// 初始化加载数据
onMounted(() => {
fetchData();
});
</script>
<style scoped>
/* 全局样式 */
.app-header {
background-color: #fff;
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
display: flex;
align-items: center;
padding: 0 20px;
z-index: 1;
}
.app-title {
margin: 0;
font-size: 18px;
font-weight: 600;
color: #333;
}
.app-content {
padding: 20px;
background-color: #f0f2f5;
height: calc(100vh - 60px);
overflow-y: auto;
}
.query-section {
background: #fff;
padding: 20px;
border-radius: 4px;
margin-bottom: 20px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.table-section {
background: #fff;
padding: 20px;
border-radius: 4px;
margin-bottom: 20px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.pagination-section {
display: flex;
justify-content: center;
background: #fff;
padding: 15px 0;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.action-buttons {
display: flex;
justify-content: flex-end;
}
.form-actions {
display: flex;
justify-content: center;
margin-top: 20px;
}
.avatar-preview {
display: flex;
justify-content: center;
margin-top: 10px;
}
.el-avatar {
background-color: #f5f7fa;
display: flex;
align-items: center;
justify-content: center;
}
.el-avatar i {
color: #909399;
}
/* 优化对话框样式 */
.el-dialog__body {
padding: 20px 25px;
}
/* 调整操作列按钮间距 */
.el-table .el-button {
margin: 0 5px;
}
/* 确保选择器宽度100% */
.el-select {
width: 100%;
}
</style>
优化一下代码使代码量减少,更简洁,解决表格右侧空白的问题
最新发布