设计思路
使用Element Plus的el-table组件展示人员数据
在姓名表头添加搜索图标按钮
点击按钮弹出搜索对话框
在对话框中输入姓名进行搜索
实现搜索功能并高亮匹配项
下面是完整的实现代码:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>人员管理系统 - Vue3 + Element Plus</title>
<!-- 引入Element Plus样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css">
<!-- 引入Element Plus图标 -->
<link rel="stylesheet" href="https://unpkg.com/@element-plus/icons-vue/dist/index.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
min-height: 100vh;
padding: 20px;
color: #333;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
header {
text-align: center;
margin-bottom: 30px;
padding: 20px;
background: linear-gradient(90deg, #1e3c72 0%, #2a5298 100%);
border-radius: 12px;
color: white;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
}
h1 {
font-size: 2.5rem;
margin-bottom: 10px;
}
.subtitle {
font-size: 1.1rem;
opacity: 0.9;
}
.card {
background: white;
border-radius: 12px;
box-shadow: 0 6px 30px rgba(0, 0, 0, 0.1);
padding: 25px;
margin-bottom: 30px;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
}
.search-container {
display: flex;
justify-content: flex-end;
margin-bottom: 20px;
}
.search-btn {
display: flex;
align-items: center;
background: linear-gradient(90deg, #1e3c72 0%, #2a5298 100%);
color: white;
border: none;
padding: 10px 20px;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(30, 60, 114, 0.3);
}
.search-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(30, 60, 114, 0.4);
}
.search-btn i {
margin-right: 8px;
font-size: 18px;
}
.highlight {
background-color: #ffeb3b;
font-weight: bold;
padding: 0 2px;
border-radius: 3px;
}
.stats {
display: flex;
justify-content: space-between;
margin-top: 20px;
background: #f8f9fc;
padding: 15px;
border-radius: 8px;
font-size: 0.95rem;
}
.stat-item {
text-align: center;
padding: 0 15px;
}
.stat-value {
font-size: 1.4rem;
font-weight: bold;
color: #1e3c72;
}
.stat-label {
color: #6c757d;
font-size: 0.9rem;
}
.footer {
text-align: center;
margin-top: 30px;
color: #6c757d;
font-size: 0.9rem;
}
@media (max-width: 768px) {
.stats {
flex-direction: column;
}
.stat-item {
margin-bottom: 15px;
}
}
</style>
</head>
<body>
<div id="app">
<div class="container">
<header>
<h1>人员管理系统</h1>
<p class="subtitle">使用 Vue3 和 Element Plus 构建</p>
</header>
<main>
<div class="card">
<div class="search-container">
<button class="search-btn" @click="openSearchDialog">
<i class="el-icon-search"></i> 搜索人员
</button>
</div>
<el-table :data="filteredPersonnel" style="width: 100%" border stripe>
<el-table-column prop="id" label="ID" width="80" sortable></el-table-column>
<el-table-column label="姓名" sortable>
<template #header>
<span>姓名</span>
<el-button type="text" @click="openSearchDialog">
<i class="el-icon-search" style="margin-left: 8px; font-size: 16px;"></i>
</el-button>
</template>
<template #default="scope">
<span v-html="highlightSearchTerm(scope.row.name)"></span>
</template>
</el-table-column>
<el-table-column prop="position" label="职位" width="180"></el-table-column>
<el-table-column prop="department" label="部门" width="150"></el-table-column>
<el-table-column prop="email" label="邮箱" width="220"></el-table-column>
<el-table-column prop="phone" label="电话" width="150"></el-table-column>
<el-table-column label="状态" width="120">
<template #default="scope">
<el-tag :type="scope.row.status === '在职' ? 'success' : 'danger'">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
</el-table>
<div class="stats">
<div class="stat-item">
<div class="stat-value">{{ totalPersonnel }}</div>
<div class="stat-label">总人数</div>
</div>
<div class="stat-item">
<div class="stat-value">{{ activePersonnel }}</div>
<div class="stat-label">在职人员</div>
</div>
<div class="stat-item">
<div class="stat-value">{{ filteredCount }}</div>
<div class="stat-label">搜索结果</div>
</div>
</div>
</div>
</main>
<!-- 搜索对话框 -->
<el-dialog v-model="searchDialogVisible" title="搜索人员" width="500px">
<el-input
v-model="searchTerm"
placeholder="请输入人员姓名"
clearable
@keyup.enter="applySearch"
>
<template #prefix>
<i class="el-icon-search"></i>
</template>
</el-input>
<div style="margin-top: 20px;">
<el-button type="primary" @click="applySearch" style="width: 100%;">
<i class="el-icon-search"></i> 搜索
</el-button>
<el-button @click="clearSearch" style="width: 100%; margin-top: 10px;">
<i class="el-icon-refresh"></i> 重置搜索
</el-button>
</div>
<template #footer>
<div style="text-align: center; margin-top: 10px;">
<el-button type="text" @click="searchDialogVisible = false">关闭</el-button>
</div>
</template>
</el-dialog>
<footer class="footer">
<p>© 2023 人员管理系统 | 使用 Vue3 和 Element Plus 构建</p>
</footer>
</div>
</div>
<!-- 引入Vue 3 -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<!-- 引入Element Plus -->
<script src="https://unpkg.com/element-plus/dist/index.full.js"></script>
<!-- 引入Element Plus图标 -->
<script src="https://unpkg.com/@element-plus/icons-vue"></script>
<script>
const { createApp, ref, computed } = Vue;
const app = createApp({
setup() {
// 搜索对话框可见性
const searchDialogVisible = ref(false);
// 搜索关键词
const searchTerm = ref('');
// 打开搜索对话框
const openSearchDialog = () => {
searchDialogVisible.value = true;
};
// 应用搜索
const applySearch = () => {
searchDialogVisible.value = false;
};
// 清除搜索
const clearSearch = () => {
searchTerm.value = '';
applySearch();
};
// 模拟人员数据
const personnelData = ref([
{ id: 1, name: '张明', position: '前端工程师', department: '技术部', email: 'zhangming@example.com', phone: '13800138001', status: '在职' },
{ id: 2, name: '李华', position: '后端工程师', department: '技术部', email: 'lihua@example.com', phone: '13800138002', status: '在职' },
{ id: 3, name: '王芳', position: 'UI设计师', department: '设计部', email: 'wangfang@example.com', phone: '13800138003', status: '在职' },
{ id: 4, name: '刘伟', position: '产品经理', department: '产品部', email: 'liuwei@example.com', phone: '13800138004', status: '在职' },
{ id: 5, name: '陈静', position: '测试工程师', department: '质量保障部', email: 'chenjing@example.com', phone: '13800138005', status: '在职' },
{ id: 6, name: '赵阳', position: '运维工程师', department: '技术部', email: 'zhaoyang@example.com', phone: '13800138006', status: '离职' },
{ id: 7, name: '钱浩', position: '项目经理', department: '项目管理部', email: 'qianhao@example.com', phone: '13800138007', status: '在职' },
{ id: 8, name: '孙琳', position: '数据分析师', department: '数据分析部', email: 'sunlin@example.com', phone: '13800138008', status: '在职' },
{ id: 9, name: '周涛', position: '移动开发工程师', department: '技术部', email: 'zhoutao@example.com', phone: '13800138009', status: '在职' },
{ id: 10, name: '吴敏', position: 'HR专员', department: '人力资源部', email: 'wumin@example.com', phone: '13800138010', status: '在职' }
]);
// 过滤后的人员数据
const filteredPersonnel = computed(() => {
if (!searchTerm.value) {
return personnelData.value;
}
const term = searchTerm.value.toLowerCase();
return personnelData.value.filter(person =>
person.name.toLowerCase().includes(term)
);
});
// 高亮搜索关键词
const highlightSearchTerm = (name) => {
if (!searchTerm.value) return name;
const term = searchTerm.value;
const regex = new RegExp(term, 'gi');
return name.replace(regex, match =>
`<span class="highlight">${match}</span>`
);
};
// 统计信息
const totalPersonnel = computed(() => personnelData.value.length);
const activePersonnel = computed(() =>
personnelData.value.filter(p => p.status === '在职').length
);
const filteredCount = computed(() => filteredPersonnel.value.length);
return {
searchDialogVisible,
searchTerm,
openSearchDialog,
applySearch,
clearSearch,
filteredPersonnel,
highlightSearchTerm,
totalPersonnel,
activePersonnel,
filteredCount
};
}
});
// 注册Element Plus
app.use(ElementPlus);
// 注册图标组件
const ElIcon = ElementPlus.ElIcon;
app.component('el-icon', ElIcon);
app.mount('#app');
</script>
</body>
</html>