本文目录导读:

我将为您提供一个完整的PHP部门管理树形结构实现,包含数据库设计、后端API和前端展示。
数据库设计
CREATE TABLE `department` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(100) NOT NULL COMMENT '部门名称', `parent_id` int(11) NOT NULL DEFAULT 0 COMMENT '父部门ID,0为顶级', `level` int(11) NOT NULL DEFAULT 1 COMMENT '层级', `path` varchar(255) DEFAULT '' COMMENT '路径', `sort_order` int(11) NOT NULL DEFAULT 0 COMMENT '排序', `status` tinyint(1) NOT NULL DEFAULT 1 COMMENT '状态:1启用,0禁用', `leader` varchar(50) DEFAULT NULL COMMENT '负责人', `phone` varchar(20) DEFAULT NULL COMMENT '联系电话', `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_parent_id` (`parent_id`), KEY `idx_path` (`path`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='部门表'; -- 示例数据 INSERT INTO `department` VALUES (1, '总公司', 0, 1, '1', 1, 1, '张三', '13800138000', NOW(), NOW()), (2, '技术部', 1, 2, '1,2', 1, 1, '李四', '13800138001', NOW(), NOW()), (3, '产品部', 1, 2, '1,3', 2, 1, '王五', '13800138002', NOW(), NOW()), (4, '后端组', 2, 3, '1,2,4', 1, 1, '赵六', '13800138003', NOW(), NOW()), (5, '前端组', 2, 3, '1,2,5', 2, 1, '钱七', '13800138004', NOW(), NOW());
PHP后端实现
Department.php (模型类)
<?php
class Department {
private $db;
public function __construct($db) {
$this->db = $db;
}
/**
* 获取所有部门(支持树形结构)
*/
public function getTree() {
$sql = "SELECT * FROM department WHERE status = 1 ORDER BY sort_order ASC";
$result = $this->db->query($sql);
$departments = [];
while ($row = $result->fetch_assoc()) {
$departments[] = $row;
}
return $this->buildTree($departments);
}
/**
* 构建树形结构
*/
private function buildTree($items, $parentId = 0) {
$tree = [];
foreach ($items as $item) {
if ($item['parent_id'] == $parentId) {
$children = $this->buildTree($items, $item['id']);
if ($children) {
$item['children'] = $children;
}
$tree[] = $item;
}
}
return $tree;
}
/**
* 获取部门详情
*/
public function getById($id) {
$sql = "SELECT * FROM department WHERE id = ? LIMIT 1";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('i', $id);
$stmt->execute();
return $stmt->get_result()->fetch_assoc();
}
/**
* 添加部门
*/
public function add($data) {
$name = $data['name'];
$parentId = $data['parent_id'] ?? 0;
// 计算层级和路径
$level = 1;
$path = $parentId;
if ($parentId > 0) {
$parent = $this->getById($parentId);
if ($parent) {
$level = $parent['level'] + 1;
$path = $parent['path'] . ',' . $parentId;
}
}
$sql = "INSERT INTO department (name, parent_id, level, path, sort_order, leader, phone)
VALUES (?, ?, ?, ?, ?, ?, ?)";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('siissss',
$name,
$parentId,
$level,
$path,
$data['sort_order'] ?? 0,
$data['leader'] ?? null,
$data['phone'] ?? null
);
if ($stmt->execute()) {
return $this->db->insert_id;
}
return false;
}
/**
* 更新部门
*/
public function update($id, $data) {
$fields = [];
$types = '';
$values = [];
// 允许更新的字段
$allowedFields = ['name', 'leader', 'phone', 'sort_order', 'status'];
foreach ($allowedFields as $field) {
if (isset($data[$field])) {
$fields[] = "$field = ?";
$types .= 's';
$values[] = $data[$field];
}
}
if (empty($fields)) {
return false;
}
$types .= 'i';
$values[] = $id;
$sql = "UPDATE department SET " . implode(', ', $fields) . " WHERE id = ?";
$stmt = $this->db->prepare($sql);
$stmt->bind_param($types, ...$values);
return $stmt->execute();
}
/**
* 删除部门(包含所有子部门)
*/
public function delete($id) {
$department = $this->getById($id);
if (!$department) {
return false;
}
// 获取所有子部门ID
$allIds = $this->getAllChildIds($id);
$allIds[] = $id;
$idStr = implode(',', $allIds);
$sql = "DELETE FROM department WHERE id IN ($idStr)";
return $this->db->query($sql);
}
/**
* 获取所有子部门ID
*/
public function getAllChildIds($parentId) {
$ids = [];
$sql = "SELECT id FROM department WHERE parent_id = ?";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('i', $parentId);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
$ids[] = $row['id'];
// 递归获取子部门的子部门
$childIds = $this->getAllChildIds($row['id']);
$ids = array_merge($ids, $childIds);
}
return $ids;
}
/**
* 获取部门路径
*/
public function getPath($departmentId) {
$department = $this->getById($departmentId);
if (!$department) {
return [];
}
$pathIds = explode(',', $department['path']);
$result = [];
foreach ($pathIds as $id) {
if ($id > 0) {
$dept = $this->getById($id);
if ($dept) {
$result[] = $dept['name'];
}
}
}
$result[] = $department['name'];
return $result;
}
/**
* 移动部门
*/
public function move($id, $newParentId) {
$department = $this->getById($id);
if (!$department) {
return false;
}
// 防止将部门移动到其子部门下
$childIds = $this->getAllChildIds($id);
$childIds[] = $id;
if (in_array($newParentId, $childIds)) {
return false;
}
// 更新父部门
$parent = $newParentId > 0 ? $this->getById($newParentId) : null;
$level = $parent ? $parent['level'] + 1 : 1;
$path = $parent ? $parent['path'] . ',' . $newParentId : $newParentId;
$sql = "UPDATE department SET parent_id = ?, level = ?, path = ? WHERE id = ?";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('iisi', $newParentId, $level, $path, $id);
if ($stmt->execute()) {
// 更新所有子部门的level和path
$this->updateChildrenPath($id, $level, $path);
return true;
}
return false;
}
/**
* 递归更新子部门的层级和路径
*/
private function updateChildrenPath($parentId, $parentLevel, $parentPath) {
$children = [];
$sql = "SELECT id FROM department WHERE parent_id = ?";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('i', $parentId);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
$children[] = $row['id'];
}
foreach ($children as $childId) {
$newParentPath = "$parentPath,$parentId";
$newLevel = $parentLevel + 1;
$sql = "UPDATE department SET level = ?, path = ? WHERE id = ?";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('isi', $newLevel, $newParentPath, $childId);
$stmt->execute();
$this->updateChildrenPath($childId, $newLevel, $newParentPath);
}
}
}
?>
department_api.php (API接口)
<?php
header('Content-Type: application/json; charset=utf-8');
session_start();
require_once 'config.php'; // 数据库配置
require_once 'Department.php';
$db = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
$department = new Department($db);
$action = $_GET['action'] ?? '';
$method = $_SERVER['REQUEST_METHOD'];
// 简单的权限验证(可以扩展)
// if (!isset($_SESSION['user_id'])) {
// echo json_encode(['code' => 401, 'msg' => '未登录']);
// exit;
// }
try {
switch ($action) {
case 'getTree':
if ($method != 'GET') {
throw new Exception('请求方法错误');
}
$tree = $department->getTree();
echo json_encode(['code' => 200, 'data' => $tree]);
break;
case 'getById':
$id = $_GET['id'] ?? 0;
$dept = $department->getById($id);
if ($dept) {
$dept['path_names'] = $department->getPath($id);
echo json_encode(['code' => 200, 'data' => $dept]);
} else {
echo json_encode(['code' => 404, 'msg' => '部门不存在']);
}
break;
case 'add':
if ($method != 'POST') {
throw new Exception('请求方法错误');
}
$data = json_decode(file_get_contents('php://input'), true);
$result = $department->add($data);
if ($result) {
echo json_encode(['code' => 200, 'msg' => '添加成功', 'id' => $result]);
} else {
echo json_encode(['code' => 500, 'msg' => '添加失败']);
}
break;
case 'update':
if ($method != 'PUT') {
throw new Exception('请求方法错误');
}
$id = $_GET['id'] ?? 0;
$data = json_decode(file_get_contents('php://input'), true);
$result = $department->update($id, $data);
if ($result) {
echo json_encode(['code' => 200, 'msg' => '更新成功']);
} else {
echo json_encode(['code' => 500, 'msg' => '更新失败']);
}
break;
case 'delete':
if ($method != 'DELETE') {
throw new Exception('请求方法错误');
}
$id = $_GET['id'] ?? 0;
$result = $department->delete($id);
if ($result) {
echo json_encode(['code' => 200, 'msg' => '删除成功']);
} else {
echo json_encode(['code' => 500, 'msg' => '删除失败']);
}
break;
case 'move':
if ($method != 'POST') {
throw new Exception('请求方法错误');
}
$data = json_decode(file_get_contents('php://input'), true);
$result = $department->move($data['id'], $data['new_parent_id']);
if ($result) {
echo json_encode(['code' => 200, 'msg' => '移动成功']);
} else {
echo json_encode(['code' => 500, 'msg' => '移动失败']);
}
break;
default:
echo json_encode(['code' => 404, 'msg' => 'Unknown action']);
}
} catch (Exception $e) {
echo json_encode(['code' => 500, 'msg' => $e->getMessage()]);
} finally {
$db->close();
}
?>
前端实现
1 HTML + CSS
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">部门管理</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: Arial, sans-serif; background: #f5f5f5; }
.container {
max-width: 1200px;
margin: 20px auto;
padding: 20px;
background: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 20px;
border-bottom: 1px solid #eee;
}
.btn {
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
.btn-primary {
background: #4A90E2;
color: white;
}
.btn-danger {
background: #E74C3C;
color: white;
}
.tree-container {
padding: 20px;
}
.tree-item {
margin: 5px 0;
padding: 8px;
border: 1px solid #e8e8e8;
border-radius: 4px;
transition: all 0.3s;
}
.tree-item:hover {
background: #f8f9fa;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.tree-item .department-header {
display: flex;
align-items: center;
gap: 10px;
}
.tree-item .actions {
margin-left: auto;
display: flex;
gap: 5px;
}
.tree-item .actions button {
padding: 5px 10px;
font-size: 12px;
}
.tree-children {
margin-left: 30px;
padding-left: 20px;
border-left: 2px solid #4A90E2;
}
.modal-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
z-index: 1000;
}
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
background: white;
padding: 30px;
border-radius: 8px;
z-index: 1001;
min-width: 400px;
max-height: 80vh;
overflow-y: auto;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
.form-group input,
.form-group select {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
.form-actions {
display: flex;
justify-content: flex-end;
gap: 10px;
margin-top: 20px;
}
.form-actions button {
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
}
.form-actions button[type="submit"] {
background: #4A90E2;
color: white;
}
.form-actions button.close {
background: #e0e0e0;
}
.expandable {
cursor: pointer;
user-select: none;
color: #4A90E2;
margin-right: 5px;
}
.collapsed .tree-children {
display: none;
}
.badge {
background: #4A90E2;
color: white;
padding: 2px 6px;
border-radius: 3px;
font-size: 12px;
}
.status-badge {
font-size: 12px;
padding: 2px 8px;
border-radius: 3px;
}
.status-active {
background: #27ae60;
color: white;
}
.status-inactive {
background: #e74c3c;
color: white;
}
.breadcrumb {
padding: 10px;
background: #f8f9fa;
border-radius: 4px;
margin-bottom: 20px;
}
#toast {
position: fixed;
top: 20px;
right: 20px;
padding: 15px 20px;
border-radius: 4px;
color: white;
display: none;
z-index: 9999;
animation: slideIn 0.3s;
}
#toast.success {
background: #27ae60;
}
#toast.error {
background: #e74c3c;
}
@keyframes slideIn {
from { transform: translateX(100%); }
to { transform: translateX(0); }
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h2>组织架构管理</h2>
<div class="actions">
<button class="btn btn-primary" onclick="openAddModal(0)">添加顶级部门</button>
<button class="btn btn-primary" onclick="loadTree()">刷新</button>
</div>
</div>
<div id="breadcrumbs" class="breadcrumb" style="display:none;"></div>
<div class="tree-container">
<div id="departmentTree"></div>
</div>
</div>
<!-- 添加/编辑弹窗 -->
<div id="modalOverlay" class="modal-overlay">
<div class="modal">
<h3 id="modalTitle">添加部门</h3>
<form id="departmentForm">
<input type="hidden" id="deptId">
<input type="hidden" id="parentId">
<div class="form-group">
<label>部门名称</label>
<input type="text" id="name" required>
</div>
<div class="form-group">
<label>上级部门</label>
<select id="parentSelect">
<option value="0">无(顶级)</option>
</select>
</div>
<div class="form-group">
<label>负责人</label>
<input type="text" id="leader">
</div>
<div class="form-group">
<label>联系电话</label>
<input type="text" id="phone">
</div>
<div class="form-group">
<label>排序</label>
<input type="number" id="sortOrder" value="0">
</div>
<div class="form-group" id="statusGroup">
<label>状态</label>
<select id="status">
<option value="1">启用</option>
<option value="0">禁用</option>
</select>
</div>
<div class="form-actions">
<button type="button" class="close" onclick="closeModal()">取消</button>
<button type="submit">保存</button>
</div>
</form>
</div>
</div>
<div id="toast"></div>
<div id="currentPath" style="display:none;"></div>
</body>
</html>
2 JavaScript功能
<script>
let currentDepartment = null;
let treeData = [];
// 加载部门树
async function loadTree() {
try {
const response = await fetch('department_api.php?action=getTree');
const result = await response.json();
if (result.code === 200) {
treeData = result.data;
renderTree(treeData);
} else {
showToast(result.msg, 'error');
}
} catch (e) {
showToast('加载部门失败', 'error');
}
}
// 渲染树形结构
function renderTree(data, containerId = 'departmentTree') {
if (!data || data.length === 0) {
document.getElementById(containerId).innerHTML = '<div style="text-align:center;color:#999;">暂无数据</div>';
return;
}
const container = document.getElementById(containerId);
let html = buildTreeHTML(data);
container.innerHTML = html;
// 绑定事件
container.addEventListener('click', handleTreeClick);
// 初始化折叠状态
document.querySelectorAll('.tree-item').forEach(item => {
const expandBtn = item.querySelector('.expandable');
if (expandBtn && item.querySelector('.tree-children')) {
expandBtn.textContent = '▼';
} else if (expandBtn) {
expandBtn.textContent = '◆';
expandBtn.style.cursor = 'default';
}
});
}
// 构建树HTML
function buildTreeHTML(items) {
let html = '<ul style="list-style:none; padding-left:0;">';
items.forEach(item => {
const hasChildren = item.children && item.children.length > 0;
const statusBadge = item.status == 1 ?
'<span class="status-badge status-active">启用</span>' :
'<span class="status-badge status-inactive">禁用</span>';
html += `
<li class="tree-item" data-id="${item.id}">
<div class="department-header">
<span class="expandable">${hasChildren ? '▶' : '◆'}</span>
<strong>${escapeHtml(item.name)}</strong>
${statusBadge}
${item.leader ? `<small>负责人:${escapeHtml(item.leader)}</small>` : ''}
${item.phone ? `<small>电话:${escapeHtml(item.phone)}</small>` : ''}
<div class="actions">
<button class="btn btn-primary" onclick="openAddModal(${item.id})">添加子部门</button>
<button class="btn btn-primary" onclick="openEditModal(${item.id})">编辑</button>
<button class="btn btn-danger" onclick="deleteDepartment(${item.id})">删除</button>
</div>
</div>
${hasChildren ? `<div class="tree-children" style="display:none;">${buildTreeHTML(item.children)}</div>` : ''}
</li>
`;
});
html += '</ul>';
return html;
}
// 处理树节点点击
function handleTreeClick(e) {
const target = e.target;
// 折叠/展开
if (target.classList.contains('expandable')) {
const treeItem = target.closest('.tree-item');
const children = treeItem.querySelector('.tree-children');
if (children) {
if (children.style.display === 'none') {
children.style.display = 'block';
target.textContent = '▼';
} else {
children.style.display = 'none';
target.textContent = '▶';
}
}
}
// 点击部门节点查看详情
if (target.closest('.department-header')) {
const treeItem = target.closest('.tree-item');
const deptId = treeItem.dataset.id;
viewDepartmentDetail(deptId);
}
}
// 查看部门详情
async function viewDepartmentDetail(id) {
try {
const response = await fetch(`department_api.php?action=getById&id=${id}`);
const result = await response.json();
if (result.code === 200) {
currentDepartment = result.data;
// 显示路径
const pathHtml = result.data.path_names.map((name, index) => {
return index < result.data.path_names.length - 1 ? `${name} → ` : name;
}).join('');
document.getElementById('currentPath').innerHTML = pathHtml;
// 可以在这里显示更多详情
showToast(`当前部门:${result.data.name}`, 'success');
} else {
showToast(result.msg, 'error');
}
} catch (e) {
showToast('获取部门详情失败', 'error');
}
}
// 打开添加部门弹窗
async function openAddModal(parentId = 0) {
document.getElementById('modalTitle').textContent = '添加部门';
document.getElementById('deptId').value = '';
document.getElementById('parentId').value = parentId;
// 填充上级部门下拉框
await populateParentSelect(parentId);
// 清空表单
document.getElementById('name').value = '';
document.getElementById('leader').value = '';
document.getElementById('phone').value = '';
document.getElementById('sortOrder').value = '0';
document.getElementById('status').value = '1';
document.getElementById('statusGroup').style.display = 'none';
showModal();
}
// 打开编辑部门弹窗
async function openEditModal(id) {
try {
const response = await fetch(`department_api.php?action=getById&id=${id}`);
const result = await response.json();
if (result.code === 200) {
const dept = result.data;
document.getElementById('modalTitle').textContent = '编辑部门';
document.getElementById('deptId').value = dept.id;
document.getElementById('parentId').value = dept.parent_id;
// 填充上级部门下拉框
await populateParentSelect(dept.parent_id, id);
// 填充表单数据
document.getElementById('name').value = dept.name;
document.getElementById('leader').value = dept.leader || '';
document.getElementById('phone').value = dept.phone || '';
document.getElementById('sortOrder').value = dept.sort_order || 0;
document.getElementById('status').value = dept.status;
document.getElementById('statusGroup').style.display = 'block';
showModal();
} else {
showToast(result.msg, 'error');
}
} catch (e) {
showToast('获取部门信息失败', 'error');
}
}
// 填充上级部门下拉框
async function populateParentSelect(selectedId = 0, excludeId = 0) {
try {
const response = await fetch('department_api.php?action=getTree');
const result = await response.json();
if (result.code === 200) {
const select = document.getElementById('parentSelect');
select.innerHTML = '<option value="0">无(顶级)</option>';
function addOptions(items, level = 0) {
items.forEach(item => {
if (item.id !== excludeId) {
const option = document.createElement('option');
option.value = item.id;
option.textContent = `${' '.repeat(level)}${item.name}`;
if (item.id === selectedId) {
option.selected = true;
}
select.appendChild(option);
if (item.children) {
addOptions(item.children, level + 1);
}
}
});
}
addOptions(result.data);
}
} catch (e) {
console.error('填充上级部门下拉框失败', e);
}
}
// 提交表单
document.getElementById('departmentForm').addEventListener('submit', async function(e) {
e.preventDefault();
const id = document.getElementById('deptId').value;
const data = {
name: document.getElementById('name').value,
parent_id: document.getElementById('parentId').value || 0,
leader: document.getElementById('leader').value,
phone: document.getElementById('phone').value,
sort_order: document.getElementById('sortOrder').value,
status: document.getElementById('status').value,
};
let url = 'department_api.php?action=add';
let method = 'POST';
if (id) {
url = `department_api.php?action=update&id=${id}`;
method = 'PUT';
}
try {
const response = await fetch(url, {
method: method,
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
const result = await response.json();
if (result.code === 200) {
showToast(result.msg, 'success');
closeModal();
loadTree();
} else {
showToast(result.msg, 'error');
}
} catch (e) {
showToast('保存失败', 'error');
}
});
// 删除部门
async function deleteDepartment(id) {
if (!confirm('确定要删除该部门及其所有子部门吗?')) {
return;
}
try {
const response = await fetch(`department_api.php?action=delete&id=${id}`, {
method: 'DELETE'
});
const result = await response.json();
if (result.code === 200) {
showToast(result.msg, 'success');
loadTree();
} else {
showToast(result.msg, 'error');
}
} catch (e) {
showToast('删除失败', 'error');
}
}
// 移动部门
async function moveDepartment(id, newParentId) {
try {
const response = await fetch('department_api.php?action=move', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
id: id,
new_parent_id: newParentId
})
});
const result = await response.json();
if (result.code === 200) {
showToast('移动成功', 'success');
loadTree();
} else {
showToast(result.msg, 'error');
}
} catch (e) {
showToast('移动失败', 'error');
}
}
// 显示/关闭弹窗
function showModal() {
document.getElementById('modalOverlay').style.display = 'block';
}
function closeModal() {
document.getElementById('modalOverlay').style.display = 'none';
}
// Toast消息
function showToast(message, type = 'info') {
const toast = document.getElementById('toast');
toast.textContent = message;
toast.className = type;
toast.style.display = 'block';
setTimeout(() => {
toast.style.display = 'none';
}, 3000);
}
// HTML转义
function escapeHtml(text) {
if (!text) return '';
const div = document.createElement('div');
div.appendChild(document.createTextNode(text));
return div.innerHTML;
}
// 初始化加载
document.addEventListener('DOMContentLoaded', function() {
loadTree();
// 点击遮罩层关闭弹窗
document.getElementById('modalOverlay').addEventListener('click', function(e) {
if (e.target === this) {
closeModal();
}
});
// 键盘ESC关闭弹窗
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
closeModal();
}
});
});
</script>
数据库配置文件 (config.php)
<?php
define('DB_HOST', 'localhost');
define('DB_USER', 'root');
define('DB_PASS', '');
define('DB_NAME', 'department_db');
?>
功能特点
核心功能:
- 树形展示:递归展示部门层级关系
- 添加部门:可以添加顶级部门或子部门
- 编辑部门:修改部门信息
- 删除部门:级联删除所有子部门
- 移动部门:调整部门层级关系
- 折叠/展开:支持树的展开和折叠
技术亮点:
- 使用递归算法构建树形结构
- 路径字段(path)用于快速查询部门层级
- 支持批量操作和动态表单验证
- RESTful API设计
- 异步请求处理
使用说明
- 创建数据库和表结构
- 配置数据库连接(config.php)
- 部署文件到Web服务器
- 通过浏览器访问HTML页面
这个部门管理系统提供了完整的树形结构管理功能,具有良好的扩展性,可以根据实际需求添加更多功能(如权限管理、人员关联等)。