You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
666 lines
26 KiB
666 lines
26 KiB
10 months ago
|
<!DOCTYPE html>
|
||
3 months ago
|
<html lang="zh-CN">
|
||
10 months ago
|
<head>
|
||
|
<meta charset="UTF-8">
|
||
3 months ago
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
|
<title>人员关系管理系统</title>
|
||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
|
||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome@6.4.0/css/all.min.css">
|
||
10 months ago
|
<style>
|
||
|
:root {
|
||
3 months ago
|
--primary-color: #3498db;
|
||
|
--secondary-color: #2c3e50;
|
||
|
--success-color: #2ecc71;
|
||
|
--warning-color: #f39c12;
|
||
|
--danger-color: #e74c3c;
|
||
|
--light-color: #ecf0f1;
|
||
|
--dark-color: #34495e;
|
||
|
}
|
||
|
|
||
10 months ago
|
body {
|
||
3 months ago
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||
|
background-color: #f5f7fa;
|
||
|
color: #333;
|
||
|
padding-top: 20px;
|
||
|
}
|
||
|
|
||
|
.header {
|
||
|
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
|
||
|
color: white;
|
||
|
padding: 20px;
|
||
|
border-radius: 10px;
|
||
|
margin-bottom: 30px;
|
||
|
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
|
||
10 months ago
|
}
|
||
3 months ago
|
|
||
|
.card {
|
||
|
border: none;
|
||
|
border-radius: 10px;
|
||
|
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
|
||
|
transition: transform 0.3s, box-shadow 0.3s;
|
||
|
margin-bottom: 20px;
|
||
10 months ago
|
}
|
||
3 months ago
|
|
||
|
.card:hover {
|
||
|
transform: translateY(-5px);
|
||
|
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
|
||
|
}
|
||
|
|
||
|
.card-header {
|
||
|
background-color: var(--secondary-color);
|
||
|
color: white;
|
||
|
border-radius: 10px 10px 0 0 !important;
|
||
|
padding: 15px 20px;
|
||
|
font-weight: 600;
|
||
|
}
|
||
|
|
||
|
.person-item {
|
||
10 months ago
|
display: flex;
|
||
|
align-items: center;
|
||
3 months ago
|
padding: 12px 15px;
|
||
|
border-bottom: 1px solid #eee;
|
||
|
transition: background-color 0.2s;
|
||
10 months ago
|
}
|
||
3 months ago
|
|
||
|
.person-item:last-child {
|
||
|
border-bottom: none;
|
||
10 months ago
|
}
|
||
3 months ago
|
|
||
|
.person-item:hover {
|
||
|
background-color: #f8f9fa;
|
||
10 months ago
|
}
|
||
3 months ago
|
|
||
|
.person-avatar {
|
||
10 months ago
|
width: 40px;
|
||
|
height: 40px;
|
||
3 months ago
|
border-radius: 50%;
|
||
|
background-color: var(--primary-color);
|
||
|
color: white;
|
||
|
display: flex;
|
||
|
align-items: center;
|
||
|
justify-content: center;
|
||
|
font-weight: bold;
|
||
|
margin-right: 15px;
|
||
10 months ago
|
}
|
||
3 months ago
|
|
||
|
.person-info {
|
||
|
flex-grow: 1;
|
||
10 months ago
|
}
|
||
3 months ago
|
|
||
|
.person-name {
|
||
|
font-weight: 600;
|
||
|
margin-bottom: 3px;
|
||
10 months ago
|
}
|
||
3 months ago
|
|
||
|
.person-status {
|
||
|
font-size: 0.85rem;
|
||
|
color: #6c757d;
|
||
|
}
|
||
|
|
||
|
.person-actions {
|
||
|
display: flex;
|
||
|
gap: 10px;
|
||
|
}
|
||
|
|
||
|
.btn-sm {
|
||
|
padding: 0.25rem 0.5rem;
|
||
|
font-size: 0.875rem;
|
||
|
}
|
||
|
|
||
|
.relationship-view {
|
||
|
height: 500px;
|
||
|
overflow-y: auto;
|
||
|
padding: 20px;
|
||
|
background-color: white;
|
||
10 months ago
|
border-radius: 10px;
|
||
3 months ago
|
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
|
||
10 months ago
|
}
|
||
3 months ago
|
|
||
|
.tree-view ul {
|
||
|
list-style-type: none;
|
||
|
padding-left: 20px;
|
||
10 months ago
|
}
|
||
3 months ago
|
|
||
|
.tree-view li {
|
||
|
margin: 10px 0;
|
||
|
position: relative;
|
||
10 months ago
|
}
|
||
3 months ago
|
|
||
|
.tree-view li::before {
|
||
|
content: "";
|
||
|
position: absolute;
|
||
|
top: 0;
|
||
|
left: -20px;
|
||
|
border-left: 1px solid #ccc;
|
||
|
height: 100%;
|
||
|
}
|
||
|
|
||
|
.tree-view li::after {
|
||
|
content: "";
|
||
|
position: absolute;
|
||
|
top: 10px;
|
||
|
left: -20px;
|
||
|
border-top: 1px solid #ccc;
|
||
|
width: 20px;
|
||
|
}
|
||
|
|
||
|
.tree-view li:last-child::before {
|
||
|
height: 10px;
|
||
|
}
|
||
|
|
||
|
.tree-node {
|
||
10 months ago
|
display: inline-block;
|
||
3 months ago
|
padding: 5px 10px;
|
||
|
border-radius: 5px;
|
||
|
background-color: var(--light-color);
|
||
|
margin-bottom: 5px;
|
||
10 months ago
|
}
|
||
3 months ago
|
|
||
|
.modal-content {
|
||
|
border-radius: 10px;
|
||
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
||
|
}
|
||
|
|
||
|
.modal-header {
|
||
|
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
|
||
|
color: white;
|
||
|
border-radius: 10px 10px 0 0;
|
||
|
}
|
||
|
|
||
|
.modal-footer {
|
||
|
border-top: none;
|
||
|
}
|
||
|
|
||
|
.btn-primary {
|
||
|
background-color: var(--primary-color);
|
||
|
border-color: var(--primary-color);
|
||
|
}
|
||
|
|
||
|
.btn-primary:hover {
|
||
|
background-color: #2980b9;
|
||
|
border-color: #2980b9;
|
||
|
}
|
||
|
|
||
|
.btn-success {
|
||
|
background-color: var(--success-color);
|
||
|
border-color: var(--success-color);
|
||
|
}
|
||
|
|
||
|
.btn-success:hover {
|
||
|
background-color: #27ae60;
|
||
|
border-color: #27ae60;
|
||
|
}
|
||
|
|
||
|
.btn-danger {
|
||
|
background-color: var(--danger-color);
|
||
|
border-color: var(--danger-color);
|
||
|
}
|
||
|
|
||
|
.btn-danger:hover {
|
||
|
background-color: #c0392b;
|
||
|
border-color: #c0392b;
|
||
|
}
|
||
|
|
||
|
.toast-container {
|
||
|
position: fixed;
|
||
|
top: 20px;
|
||
|
right: 20px;
|
||
|
z-index: 1060;
|
||
|
}
|
||
|
|
||
|
.badge {
|
||
|
font-weight: 500;
|
||
|
padding: 5px 10px;
|
||
|
border-radius: 20px;
|
||
|
}
|
||
|
|
||
|
.badge-primary {
|
||
|
background-color: var(--primary-color);
|
||
|
}
|
||
|
|
||
|
.badge-success {
|
||
|
background-color: var(--success-color);
|
||
|
}
|
||
|
|
||
|
.badge-warning {
|
||
|
background-color: var(--warning-color);
|
||
|
}
|
||
|
|
||
|
.search-box {
|
||
|
position: relative;
|
||
|
margin-bottom: 20px;
|
||
10 months ago
|
}
|
||
3 months ago
|
|
||
|
.search-box input {
|
||
|
padding-left: 40px;
|
||
|
border-radius: 20px;
|
||
|
border: 1px solid #ddd;
|
||
|
box-shadow: 0 2px 5px rgba(0,0,0,0.05);
|
||
10 months ago
|
}
|
||
3 months ago
|
|
||
|
.search-box i {
|
||
|
position: absolute;
|
||
|
left: 15px;
|
||
|
top: 10px;
|
||
|
color: #aaa;
|
||
10 months ago
|
}
|
||
|
</style>
|
||
|
</head>
|
||
|
<body>
|
||
3 months ago
|
<div class="container">
|
||
|
<div class="header text-center">
|
||
|
<h1><i class="fas fa-sitemap me-2"></i>人员关系管理系统</h1>
|
||
|
<p class="mb-0">设置和管理人员之间的父子关系</p>
|
||
10 months ago
|
</div>
|
||
3 months ago
|
|
||
|
<div class="row">
|
||
|
<div class="col-md-5">
|
||
|
<div class="card">
|
||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||
|
<span><i class="fas fa-users me-2"></i>人员列表</span>
|
||
|
<button class="btn btn-sm btn-light" id="addPersonBtn">
|
||
|
<i class="fas fa-plus me-1"></i>添加人员
|
||
|
</button>
|
||
|
</div>
|
||
|
<div class="card-body p-0">
|
||
|
<div class="search-box p-3">
|
||
|
<i class="fas fa-search"></i>
|
||
|
<input type="text" class="form-control" id="searchPerson" placeholder="搜索人员...">
|
||
10 months ago
|
</div>
|
||
3 months ago
|
<div id="personList" style="max-height: 400px; overflow-y: auto;">
|
||
|
<!-- 人员列表将通过JS动态生成 -->
|
||
10 months ago
|
</div>
|
||
3 months ago
|
</div>
|
||
10 months ago
|
</div>
|
||
3 months ago
|
</div>
|
||
|
|
||
|
<div class="col-md-7">
|
||
|
<div class="card">
|
||
|
<div class="card-header">
|
||
|
<i class="fas fa-sitemap me-2"></i>组织关系图
|
||
|
</div>
|
||
|
<div class="card-body">
|
||
|
<div class="relationship-view">
|
||
|
<div class="tree-view" id="relationshipTree">
|
||
|
<!-- 关系树将通过JS动态生成 -->
|
||
|
</div>
|
||
10 months ago
|
</div>
|
||
3 months ago
|
</div>
|
||
10 months ago
|
</div>
|
||
3 months ago
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<!-- 设置父子关系的模态框 -->
|
||
|
<div class="modal fade" id="setRelationshipModal" tabindex="-1" aria-hidden="true">
|
||
|
<div class="modal-dialog">
|
||
|
<div class="modal-content">
|
||
|
<div class="modal-header">
|
||
|
<h5 class="modal-title">设置父子关系</h5>
|
||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||
10 months ago
|
</div>
|
||
3 months ago
|
<div class="modal-body">
|
||
|
<p>为 <strong id="currentPersonName"></strong> 选择父级:</p>
|
||
|
<select class="form-select" id="parentSelect">
|
||
|
<option value="">无父级(顶级人员)</option>
|
||
|
<!-- 可选父级将通过JS动态生成 -->
|
||
|
</select>
|
||
|
<div class="alert alert-warning mt-3" id="warningMessage" style="display: none;">
|
||
|
<i class="fas fa-exclamation-triangle me-2"></i>
|
||
|
<span id="warningText"></span>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div class="modal-footer">
|
||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
||
|
<button type="button" class="btn btn-primary" id="saveRelationship">保存</button>
|
||
10 months ago
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
3 months ago
|
</div>
|
||
|
|
||
|
<!-- 添加人员的模态框 -->
|
||
|
<div class="modal fade" id="addPersonModal" tabindex="-1" aria-hidden="true">
|
||
|
<div class="modal-dialog">
|
||
|
<div class="modal-content">
|
||
|
<div class="modal-header">
|
||
|
<h5 class="modal-title">添加新人员</h5>
|
||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||
|
</div>
|
||
|
<div class="modal-body">
|
||
|
<div class="mb-3">
|
||
|
<label for="newPersonName" class="form-label">人员姓名</label>
|
||
|
<input type="text" class="form-control" id="newPersonName" placeholder="请输入姓名">
|
||
|
</div>
|
||
|
<div class="mb-3">
|
||
|
<label for="newPersonTitle" class="form-label">职位</label>
|
||
|
<input type="text" class="form-control" id="newPersonTitle" placeholder="请输入职位">
|
||
|
</div>
|
||
|
</div>
|
||
|
<div class="modal-footer">
|
||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
||
|
<button type="button" class="btn btn-success" id="saveNewPerson">添加</button>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<!-- 提示消息 -->
|
||
|
<div class="toast-container"></div>
|
||
|
|
||
|
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
|
||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||
|
<script>
|
||
|
$(document).ready(function() {
|
||
|
// 示例数据
|
||
|
let people = [
|
||
|
{ id: 1, name: "张三", title: "总经理", parentId: null },
|
||
|
{ id: 2, name: "李四", title: "副总经理", parentId: 1 },
|
||
|
{ id: 3, name: "王五", title: "技术总监", parentId: 1 },
|
||
|
{ id: 4, name: "赵六", title: "市场总监", parentId: 1 },
|
||
|
{ id: 5, name: "钱七", title: "前端开发", parentId: 3 },
|
||
|
{ id: 6, name: "孙八", title: "后端开发", parentId: 3 },
|
||
|
{ id: 7, name: "周九", title: "UI设计师", parentId: 3 },
|
||
|
{ id: 8, name: "吴十", title: "销售经理", parentId: 4 },
|
||
|
{ id: 9, name: "郑十一", title: "销售代表", parentId: 8 },
|
||
|
{ id: 10, name: "王十二", title: "销售代表", parentId: 8 },
|
||
|
{ id: 11, name: "李十三", title: "人事经理", parentId: 2 },
|
||
|
{ id: 12, name: "张十四", title: "财务经理", parentId: 2 },
|
||
|
{ id: 13, name: "刘十五", title: "人事专员", parentId: 11 },
|
||
|
{ id: 14, name: "陈十六", title: "财务专员", parentId: 12 },
|
||
|
{ id: 15, name: "杨十七", title: "测试工程师", parentId: 3 },
|
||
|
{ id: 16, name: "黄十八", title: "产品经理", parentId: 1 },
|
||
|
{ id: 17, name: "周十九", title: "产品助理", parentId: 16 },
|
||
|
{ id: 18, name: "吴二十", title: "实习生", parentId: 5 },
|
||
|
{ id: 19, name: "郑二十一", title: "实习生", parentId: 6 },
|
||
|
{ id: 20, name: "王二十二", title: "实习生", parentId: 7 }
|
||
|
];
|
||
|
|
||
|
// 初始化
|
||
|
renderPersonList();
|
||
|
renderRelationshipTree();
|
||
|
|
||
|
// 渲染人员列表
|
||
|
function renderPersonList() {
|
||
|
const $personList = $('#personList');
|
||
|
$personList.empty();
|
||
|
|
||
|
people.forEach(person => {
|
||
|
const parentName = person.parentId ? people.find(p => p.id === person.parentId).name : "无";
|
||
|
const hasChildren = people.some(p => p.parentId === person.id);
|
||
|
|
||
|
const $item = $(`
|
||
|
<div class="person-item" data-id="${person.id}">
|
||
|
<div class="person-avatar">${person.name.charAt(0)}</div>
|
||
|
<div class="person-info">
|
||
|
<div class="person-name">${person.name}</div>
|
||
|
<div class="person-status">
|
||
|
<span class="text-muted">${person.title}</span>
|
||
|
<span class="ms-2 badge ${person.parentId ? 'bg-info' : 'bg-success'}">${person.parentId ? '子级' : '顶级'}</span>
|
||
|
${hasChildren ? '<span class="ms-2 badge bg-warning">有下属</span>' : ''}
|
||
|
</div>
|
||
|
</div>
|
||
|
<div class="person-actions">
|
||
|
<button class="btn btn-sm btn-outline-primary set-parent-btn">
|
||
|
<i class="fas fa-exchange-alt"></i>
|
||
|
</button>
|
||
|
<button class="btn btn-sm btn-outline-danger remove-btn">
|
||
|
<i class="fas fa-trash"></i>
|
||
|
</button>
|
||
|
</div>
|
||
|
</div>
|
||
|
`);
|
||
|
|
||
|
$personList.append($item);
|
||
|
});
|
||
|
|
||
|
// 绑定设置父级按钮事件
|
||
|
$('.set-parent-btn').click(function() {
|
||
|
const personId = $(this).closest('.person-item').data('id');
|
||
|
openSetParentModal(personId);
|
||
|
});
|
||
|
|
||
|
// 绑定删除按钮事件
|
||
|
$('.remove-btn').click(function() {
|
||
|
const personId = $(this).closest('.person-item').data('id');
|
||
|
removePerson(personId);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// 渲染关系树
|
||
|
function renderRelationshipTree() {
|
||
|
const $tree = $('#relationshipTree');
|
||
|
$tree.empty();
|
||
|
|
||
|
// 获取顶级人员
|
||
|
const topLevelPeople = people.filter(p => p.parentId === null);
|
||
|
|
||
|
if (topLevelPeople.length === 0) {
|
||
|
$tree.html('<div class="alert alert-info">暂无人员关系数据</div>');
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const $ul = $('<ul></ul>');
|
||
|
topLevelPeople.forEach(person => {
|
||
|
const $li = createTreeNode(person);
|
||
|
$ul.append($li);
|
||
|
});
|
||
|
|
||
|
$tree.append($ul);
|
||
|
}
|
||
|
|
||
|
// 创建树节点
|
||
|
function createTreeNode(person) {
|
||
|
const $li = $('<li></li>');
|
||
|
const $node = $(`<div class="tree-node">${person.name} (${person.title})</div>`);
|
||
|
$li.append($node);
|
||
|
|
||
|
// 查找子节点
|
||
|
const children = people.filter(p => p.parentId === person.id);
|
||
|
if (children.length > 0) {
|
||
|
const $childUl = $('<ul></ul>');
|
||
|
children.forEach(child => {
|
||
|
const $childLi = createTreeNode(child);
|
||
|
$childUl.append($childLi);
|
||
|
});
|
||
|
$li.append($childUl);
|
||
|
}
|
||
|
|
||
|
return $li;
|
||
|
}
|
||
|
|
||
|
// 打开设置父级模态框
|
||
|
function openSetParentModal(personId) {
|
||
|
const person = people.find(p => p.id === personId);
|
||
|
$('#currentPersonName').text(person.name);
|
||
|
|
||
|
// 填充可选父级下拉框
|
||
|
const $parentSelect = $('#parentSelect');
|
||
|
$parentSelect.empty();
|
||
|
$parentSelect.append('<option value="">无父级(顶级人员)</option>');
|
||
|
|
||
|
// 获取可以作为父级的人员(不能是自己或自己的子孙)
|
||
|
const descendants = getDescendants(personId);
|
||
|
const availableParents = people.filter(p => p.id !== personId && !descendants.includes(p.id));
|
||
|
|
||
|
availableParents.forEach(p => {
|
||
|
const selected = p.id === person.parentId ? 'selected' : '';
|
||
|
$parentSelect.append(`<option value="${p.id}" ${selected}>${p.name} (${p.title})</option>`);
|
||
|
});
|
||
|
|
||
|
// 检查是否有子节点
|
||
|
const hasChildren = people.some(p => p.parentId === personId);
|
||
|
const $warning = $('#warningMessage');
|
||
|
const $warningText = $('#warningText');
|
||
|
|
||
|
if (hasChildren) {
|
||
|
$warning.show();
|
||
|
$warningText.text('注意:此人有下属,如果设置为他人的子级,其下属将自动上移一级');
|
||
|
} else {
|
||
|
$warning.hide();
|
||
|
}
|
||
|
|
||
|
// 显示模态框
|
||
|
const modal = new bootstrap.Modal(document.getElementById('setRelationshipModal'));
|
||
|
modal.show();
|
||
|
|
||
|
// 保存按钮事件
|
||
|
$('#saveRelationship').off('click').on('click', function() {
|
||
|
const newParentId = $('#parentSelect').val() ? parseInt($('#parentSelect').val()) : null;
|
||
|
|
||
|
// 如果选择的新父级已经是某人的子级,且该人有子级,则不允许设置
|
||
|
if (newParentId !== null) {
|
||
|
const newParent = people.find(p => p.id === newParentId);
|
||
|
if (newParent.parentId !== null && people.some(p => p.parentId === newParentId)) {
|
||
|
showToast('错误', '不能将人员设置为已有子级的人的子级', 'danger');
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 如果该人有子级,需要处理子级
|
||
|
if (hasChildren) {
|
||
|
const children = people.filter(p => p.parentId === personId);
|
||
|
const oldParentId = person.parentId;
|
||
|
|
||
|
// 将子级上移一级
|
||
|
children.forEach(child => {
|
||
|
child.parentId = oldParentId;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// 设置新的父级
|
||
|
person.parentId = newParentId;
|
||
|
|
||
|
// 更新视图
|
||
|
renderPersonList();
|
||
|
renderRelationshipTree();
|
||
|
|
||
|
// 关闭模态框
|
||
|
modal.hide();
|
||
|
|
||
|
showToast('成功', '已成功设置父子关系', 'success');
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// 获取某人的所有子孙ID
|
||
|
function getDescendants(personId) {
|
||
|
const descendants = [];
|
||
|
|
||
|
function collectDescendants(id) {
|
||
|
const children = people.filter(p => p.parentId === id);
|
||
|
children.forEach(child => {
|
||
|
descendants.push(child.id);
|
||
|
collectDescendants(child.id);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
collectDescendants(personId);
|
||
|
return descendants;
|
||
|
}
|
||
|
|
||
|
// 删除人员
|
||
|
function removePerson(personId) {
|
||
|
if (confirm('确定要删除此人员吗?其下属将自动上移一级')) {
|
||
|
const person = people.find(p => p.id === personId);
|
||
|
const children = people.filter(p => p.parentId === personId);
|
||
|
|
||
|
// 将子级上移一级
|
||
|
children.forEach(child => {
|
||
|
child.parentId = person.parentId;
|
||
|
});
|
||
|
|
||
|
// 删除人员
|
||
|
people = people.filter(p => p.id !== personId);
|
||
|
|
||
|
// 更新视图
|
||
|
renderPersonList();
|
||
|
renderRelationshipTree();
|
||
|
|
||
|
showToast('成功', '已成功删除人员', 'success');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 显示提示消息
|
||
|
function showToast(title, message, type) {
|
||
|
const $toast = $(`
|
||
|
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||
|
<div class="toast-header bg-${type} text-white">
|
||
|
<strong class="me-auto">${title}</strong>
|
||
|
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
|
||
|
</div>
|
||
|
<div class="toast-body">
|
||
|
${message}
|
||
|
</div>
|
||
|
</div>
|
||
|
`);
|
||
|
|
||
|
$('.toast-container').append($toast);
|
||
|
const toast = new bootstrap.Toast($toast[0], { delay: 3000 });
|
||
|
toast.show();
|
||
|
|
||
|
// 自动移除
|
||
|
$toast.on('hidden.bs.toast', function() {
|
||
|
$(this).remove();
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// 添加人员按钮事件
|
||
|
$('#addPersonBtn').click(function() {
|
||
|
$('#newPersonName').val('');
|
||
|
$('#newPersonTitle').val('');
|
||
|
|
||
|
const modal = new bootstrap.Modal(document.getElementById('addPersonModal'));
|
||
|
modal.show();
|
||
|
|
||
|
// 保存按钮事件
|
||
|
$('#saveNewPerson').off('click').on('click', function() {
|
||
|
const name = $('#newPersonName').val().trim();
|
||
|
const title = $('#newPersonTitle').val().trim();
|
||
|
|
||
|
if (!name) {
|
||
|
alert('请输入姓名');
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// 生成新ID
|
||
|
const newId = Math.max(...people.map(p => p.id)) + 1;
|
||
|
|
||
|
// 添加新人员
|
||
|
people.push({
|
||
|
id: newId,
|
||
|
name: name,
|
||
|
title: title || '未设置',
|
||
|
parentId: null
|
||
|
});
|
||
|
|
||
|
// 更新视图
|
||
|
renderPersonList();
|
||
|
renderRelationshipTree();
|
||
|
|
||
|
// 关闭模态框
|
||
|
modal.hide();
|
||
|
|
||
|
showToast('成功', '已成功添加人员', 'success');
|
||
|
});
|
||
|
});
|
||
|
|
||
|
// 搜索功能
|
||
|
$('#searchPerson').on('input', function() {
|
||
|
const searchText = $(this).val().toLowerCase();
|
||
|
|
||
|
$('.person-item').each(function() {
|
||
|
const personId = $(this).data('id');
|
||
|
const person = people.find(p => p.id === personId);
|
||
|
const nameMatch = person.name.toLowerCase().includes(searchText);
|
||
|
const titleMatch = person.title.toLowerCase().includes(searchText);
|
||
|
|
||
|
if (nameMatch || titleMatch || searchText === '') {
|
||
|
$(this).show();
|
||
|
} else {
|
||
|
$(this).hide();
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
</script>
|
||
10 months ago
|
</body>
|
||
|
</html>
|