2025-12-20 16:53:57 +08:00
|
|
|
|
# 组织架构管理功能实现文档
|
|
|
|
|
|
|
|
|
|
|
|
## 功能概述
|
|
|
|
|
|
|
|
|
|
|
|
基于用户需求,我们在组织架构中实现了完整的管理功能,包括部门的新增、编辑、删除和层级调整(拖拽)。
|
|
|
|
|
|
|
|
|
|
|
|
## 核心功能
|
|
|
|
|
|
|
|
|
|
|
|
### 1. 新增部门 ✨
|
|
|
|
|
|
|
|
|
|
|
|
**操作方式:**
|
|
|
|
|
|
- 点击任意节点上的 `➕ 新增` 按钮
|
|
|
|
|
|
|
|
|
|
|
|
**功能特点:**
|
|
|
|
|
|
- ✅ **必填信息**:部门名称、部门账号
|
|
|
|
|
|
- ✅ **可选信息**:联系电话、备注
|
|
|
|
|
|
- ✅ **自动账号创建**:系统自动为每个部门创建管理员账号
|
|
|
|
|
|
- ✅ **默认密码**:账号+123456(例如:账号为`ABC`,密码为`ABC123456`)
|
|
|
|
|
|
- ✅ **角色配置**:自动分配`department_admin`角色,级别80
|
|
|
|
|
|
|
|
|
|
|
|
**后端实现:**
|
|
|
|
|
|
```python
|
|
|
|
|
|
# lawrisk/api/v2.py - admin_create_service_department()
|
|
|
|
|
|
department = create_service_department(name, **kwargs)
|
|
|
|
|
|
user = create_user(
|
|
|
|
|
|
username=code,
|
|
|
|
|
|
password=f"{code}123456",
|
|
|
|
|
|
display_name=f"{name}管理员",
|
|
|
|
|
|
role="department_admin",
|
|
|
|
|
|
grade=80,
|
|
|
|
|
|
service_department_id=department_id
|
|
|
|
|
|
)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**前端界面:**
|
|
|
|
|
|
- 模态框表单设计
|
|
|
|
|
|
- 表单验证(账号只能包含字母和数字)
|
|
|
|
|
|
- 友好的提示信息
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### 2. 编辑部门 ✏️
|
|
|
|
|
|
|
|
|
|
|
|
**操作方式:**
|
|
|
|
|
|
- 点击节点上的 `✏️ 编辑` 按钮
|
|
|
|
|
|
|
|
|
|
|
|
**功能特点:**
|
|
|
|
|
|
- ✅ **可编辑字段**:部门名称、联系电话、备注
|
|
|
|
|
|
- ⚠️ **不可修改**:部门账号(防止登录用户名冲突)
|
|
|
|
|
|
- ✅ **即时保存**:修改后立即更新到数据库
|
|
|
|
|
|
|
|
|
|
|
|
**支持字段:**
|
|
|
|
|
|
- 部门名称(必填)
|
|
|
|
|
|
- 部门账号(只读)
|
|
|
|
|
|
- 联系电话
|
|
|
|
|
|
- 备注
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### 3. 删除部门 🗑️
|
|
|
|
|
|
|
|
|
|
|
|
**操作方式:**
|
|
|
|
|
|
- 点击节点上的 `🗑️ 删除` 按钮
|
|
|
|
|
|
|
|
|
|
|
|
**安全机制:**
|
|
|
|
|
|
1. **下级部门检查**:如果有下级部门,会提示用户删除后的影响
|
|
|
|
|
|
2. **账号绑定检查**:如果部门下有账号绑定,默认不允许删除
|
|
|
|
|
|
3. **强制删除选项**:如需强制删除,可解除所有账号绑定
|
|
|
|
|
|
|
|
|
|
|
|
**删除逻辑:**
|
|
|
|
|
|
```python
|
|
|
|
|
|
# 1. 检查下级部门
|
|
|
|
|
|
children_count = orgChartData.allNodes.filter(n => n.parent_id === nodeId)
|
|
|
|
|
|
|
|
|
|
|
|
# 2. 检查账号绑定
|
|
|
|
|
|
bound_count = cur.execute(
|
|
|
|
|
|
"SELECT COUNT(*) FROM auth_users WHERE service_department_id = %s",
|
|
|
|
|
|
(dept_token,)
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 3. 强制删除(可选)
|
|
|
|
|
|
if force:
|
|
|
|
|
|
update_user_account(user_id, service_department_id=None)
|
|
|
|
|
|
delete_service_department(dept_id)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**删除行为:**
|
|
|
|
|
|
- 普通删除:要求无下级部门且无账号绑定
|
|
|
|
|
|
- 强制删除:自动解除所有账号绑定
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### 4. 拖拽修改层级 🎯
|
|
|
|
|
|
|
|
|
|
|
|
**操作方式:**
|
|
|
|
|
|
- 拖拽节点名称右侧的提示文字 `⋮⋮ 拖拽修改层级`
|
|
|
|
|
|
- 拖拽到目标节点上
|
|
|
|
|
|
|
|
|
|
|
|
**视觉反馈:**
|
|
|
|
|
|
- 拖拽时:节点半透明显示,带阴影和旋转效果
|
|
|
|
|
|
- 悬停目标:虚线边框高亮,显示"↳ 拖放到此处"提示
|
|
|
|
|
|
- 释放后:弹出确认对话框
|
|
|
|
|
|
|
|
|
|
|
|
**拖拽实现:**
|
|
|
|
|
|
```javascript
|
|
|
|
|
|
// HTML5 Drag & Drop API
|
|
|
|
|
|
span.setAttribute('draggable', 'true');
|
|
|
|
|
|
nodeDiv.addEventListener('drop', async (evt) => {
|
|
|
|
|
|
evt.preventDefault();
|
|
|
|
|
|
await fetchJSON(`${API_BASE}/admin/service-departments/${sourceId}`, {
|
|
|
|
|
|
method: 'PATCH',
|
|
|
|
|
|
body: JSON.stringify({ parent_id: targetId })
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**安全限制:**
|
|
|
|
|
|
- 不能将节点设置为自己的子节点
|
|
|
|
|
|
- 不能拖拽到自身
|
|
|
|
|
|
- 需要用户确认操作
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 界面设计
|
|
|
|
|
|
|
|
|
|
|
|
### 操作按钮样式
|
|
|
|
|
|
|
|
|
|
|
|
**新增按钮** (`add-child-btn`):
|
|
|
|
|
|
- 🟢 绿色背景 `#dcfce7`
|
|
|
|
|
|
- 文字颜色:`#166534`
|
|
|
|
|
|
- 图标:`➕`
|
|
|
|
|
|
|
|
|
|
|
|
**编辑按钮** (`edit-btn`):
|
|
|
|
|
|
- 🔵 蓝色背景 `#dbeafe`
|
|
|
|
|
|
- 文字颜色:`#1e40af`
|
|
|
|
|
|
- 图标:`✏️`
|
|
|
|
|
|
|
|
|
|
|
|
**删除按钮** (`delete-btn`):
|
|
|
|
|
|
- 🔴 红色背景 `#fee2e2`
|
|
|
|
|
|
- 文字颜色:`#991b1b`
|
|
|
|
|
|
- 图标:`🗑️`
|
|
|
|
|
|
|
|
|
|
|
|
### 拖拽视觉样式
|
|
|
|
|
|
|
|
|
|
|
|
**拖拽中** (`.dragging`):
|
|
|
|
|
|
- 透明度:`0.6`
|
|
|
|
|
|
- 阴影:`0 8px 24px rgba(0, 0, 0, 0.15)`
|
|
|
|
|
|
- 旋转:`rotate(2deg)`
|
|
|
|
|
|
- z-index:`1000`
|
|
|
|
|
|
|
|
|
|
|
|
**放置目标** (`.drop-target`):
|
|
|
|
|
|
- 虚线边框:`2px dashed #4f46e5`
|
|
|
|
|
|
- 提示覆盖层:`↳ 拖放到此处`
|
|
|
|
|
|
|
|
|
|
|
|
### 模态框设计
|
|
|
|
|
|
|
|
|
|
|
|
**结构:**
|
|
|
|
|
|
- 遮罩层:半透明黑色背景
|
|
|
|
|
|
- 模态框:白色卡片,圆角16px
|
|
|
|
|
|
- 表单:垂直排列,间距12px
|
|
|
|
|
|
- 按钮:取消(灰色)+ 确定(渐变蓝)
|
|
|
|
|
|
|
|
|
|
|
|
**样式特点:**
|
|
|
|
|
|
- 最大宽度:480px
|
|
|
|
|
|
- 响应式设计(90%宽度)
|
|
|
|
|
|
- 圆角边框:8px
|
|
|
|
|
|
- 聚焦效果:3px蓝紫色阴影
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 技术实现
|
|
|
|
|
|
|
|
|
|
|
|
### 后端 API
|
|
|
|
|
|
|
|
|
|
|
|
**文件**:`lawrisk/api/v2.py`
|
|
|
|
|
|
|
|
|
|
|
|
#### 创建部门
|
|
|
|
|
|
```python
|
|
|
|
|
|
POST /fs-ai-asistant/api/workflow/lawrisk/admin/service-departments
|
|
|
|
|
|
{
|
|
|
|
|
|
"name": "部门名称",
|
|
|
|
|
|
"code": "部门账号",
|
|
|
|
|
|
"phone": "联系电话",
|
|
|
|
|
|
"parent_id": "上级ID",
|
|
|
|
|
|
"description": "备注"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 更新部门
|
|
|
|
|
|
```python
|
|
|
|
|
|
PATCH /fs-ai-asistant/api/workflow/lawrisk/admin/service-departments/{id}
|
|
|
|
|
|
{
|
|
|
|
|
|
"name": "新名称",
|
|
|
|
|
|
"phone": "新电话",
|
|
|
|
|
|
"parent_id": "新上级ID", # 用于拖拽修改层级
|
|
|
|
|
|
"description": "新备注"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 删除部门
|
|
|
|
|
|
```python
|
|
|
|
|
|
DELETE /fs-ai-asistant/api/workflow/lawrisk/admin/service-departments/{id}?force=true
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 前端实现
|
|
|
|
|
|
|
|
|
|
|
|
**文件**:`static/super_admin.html`
|
|
|
|
|
|
|
|
|
|
|
|
#### 核心函数
|
|
|
|
|
|
|
|
|
|
|
|
1. **`showAddChildModal(nodeData)`**
|
|
|
|
|
|
- 创建新增部门模态框
|
|
|
|
|
|
- 自动设置parent_id
|
|
|
|
|
|
- 显示密码提示信息
|
|
|
|
|
|
|
|
|
|
|
|
2. **`showEditModal(nodeData)`**
|
|
|
|
|
|
- 创建编辑部门模态框
|
|
|
|
|
|
- 预填充现有数据
|
|
|
|
|
|
- 禁用账号字段
|
|
|
|
|
|
|
|
|
|
|
|
3. **`showDeleteConfirm(nodeData)`**
|
|
|
|
|
|
- 检查下级部门数量
|
|
|
|
|
|
- 检查账号绑定情况
|
|
|
|
|
|
- 支持强制删除选项
|
|
|
|
|
|
|
|
|
|
|
|
4. **`initDragAndDrop()`**
|
|
|
|
|
|
- 初始化拖拽事件监听
|
|
|
|
|
|
- 设置拖拽源和目标
|
|
|
|
|
|
- 处理拖拽逻辑
|
|
|
|
|
|
|
|
|
|
|
|
#### 数据结构
|
|
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
|
orgChartData = {
|
|
|
|
|
|
tree: [], // 树形结构
|
|
|
|
|
|
allNodes: [], // 所有节点扁平化列表
|
|
|
|
|
|
parentMap: {}, // 父节点映射
|
|
|
|
|
|
nodeMap: {} // 节点ID到节点数据映射
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 测试建议
|
|
|
|
|
|
|
|
|
|
|
|
### 功能测试
|
|
|
|
|
|
|
|
|
|
|
|
1. **新增部门测试**
|
|
|
|
|
|
```
|
|
|
|
|
|
1. 点击任意节点的 ➕ 新增按钮
|
|
|
|
|
|
2. 填写部门名称:测试部门
|
|
|
|
|
|
3. 填写部门账号:TEST001
|
|
|
|
|
|
4. 点击确定
|
|
|
|
|
|
5. 验证:显示默认密码 TEST001123456
|
|
|
|
|
|
6. 验证:新部门出现在树形结构中
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
2. **编辑部门测试**
|
|
|
|
|
|
```
|
|
|
|
|
|
1. 点击测试部门的 ✏️ 编辑按钮
|
|
|
|
|
|
2. 修改部门名称:测试部门-已修改
|
|
|
|
|
|
3. 修改联系电话:0757-12345678
|
|
|
|
|
|
4. 点击确定
|
|
|
|
|
|
5. 验证:信息更新成功
|
|
|
|
|
|
6. 验证:账号字段不可修改
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
3. **删除部门测试**
|
|
|
|
|
|
```
|
|
|
|
|
|
1. 点击测试部门的 🗑️ 删除按钮
|
|
|
|
|
|
2. 验证:弹出确认对话框
|
|
|
|
|
|
3. 如有下级部门,验证:显示下级数量提示
|
|
|
|
|
|
4. 确认删除
|
|
|
|
|
|
5. 验证:部门从树形结构中移除
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
4. **拖拽测试**
|
|
|
|
|
|
```
|
|
|
|
|
|
1. 拖拽节点A的 ⋮⋮ 提示文字
|
|
|
|
|
|
2. 悬停到节点B上
|
|
|
|
|
|
3. 验证:节点B显示虚线边框
|
|
|
|
|
|
4. 释放鼠标
|
|
|
|
|
|
5. 验证:弹出确认对话框
|
|
|
|
|
|
6. 确认操作
|
|
|
|
|
|
7. 验证:节点A成为节点B的子节点
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 边界测试
|
|
|
|
|
|
|
|
|
|
|
|
1. **账号重复测试**
|
|
|
|
|
|
- 创建部门时使用已存在的账号
|
|
|
|
|
|
- 预期:显示错误信息
|
|
|
|
|
|
|
|
|
|
|
|
2. **自引用测试**
|
|
|
|
|
|
- 尝试将节点设置为自己的子节点
|
|
|
|
|
|
- 预期:拒绝操作并显示错误
|
|
|
|
|
|
|
|
|
|
|
|
3. **层级循环测试**
|
|
|
|
|
|
- A → B → C → A 试图形成循环
|
|
|
|
|
|
- 预期:系统防止这种操作
|
|
|
|
|
|
|
|
|
|
|
|
4. **删除根节点测试**
|
|
|
|
|
|
- 删除顶级部门
|
|
|
|
|
|
- 预期:下级部门变成新的根节点
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 优点
|
|
|
|
|
|
|
|
|
|
|
|
### 1. 用户体验
|
|
|
|
|
|
- ✅ **操作直观**:按钮图标清晰,操作流程简单
|
|
|
|
|
|
- ✅ **视觉反馈**:拖拽、悬停、点击都有明确反馈
|
|
|
|
|
|
- ✅ **错误提示**:友好的错误信息和解决建议
|
|
|
|
|
|
- ✅ **即时响应**:操作后立即更新界面
|
|
|
|
|
|
|
|
|
|
|
|
### 2. 安全性
|
|
|
|
|
|
- ✅ **数据验证**:前后端双重验证
|
|
|
|
|
|
- ✅ **权限控制**:需要管理员权限
|
|
|
|
|
|
- ✅ **防止误删**:多层确认机制
|
|
|
|
|
|
- ✅ **防止循环**:自动检测父子关系
|
|
|
|
|
|
|
|
|
|
|
|
### 3. 可维护性
|
|
|
|
|
|
- ✅ **模块化设计**:每个功能独立实现
|
|
|
|
|
|
- ✅ **代码复用**:模态框和事件处理可复用
|
|
|
|
|
|
- ✅ **类型安全**:JavaScript + TypeScript(如需要)
|
|
|
|
|
|
- ✅ **文档完整**:详细的实现文档
|
|
|
|
|
|
|
|
|
|
|
|
### 4. 扩展性
|
|
|
|
|
|
- ✅ **易于添加字段**:部门表可扩展更多属性
|
|
|
|
|
|
- ✅ **支持批量操作**:可扩展多选删除
|
|
|
|
|
|
- ✅ **审计日志**:可集成操作日志记录
|
|
|
|
|
|
- ✅ **权限细粒度**:可扩展更细的权限控制
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 文件清单
|
|
|
|
|
|
|
|
|
|
|
|
### 后端文件
|
|
|
|
|
|
- ✅ `lawrisk/api/v2.py` - API路由实现
|
|
|
|
|
|
- `admin_create_service_department()`
|
|
|
|
|
|
- `admin_update_service_department()`
|
|
|
|
|
|
- `admin_delete_service_department()`
|
|
|
|
|
|
|
|
|
|
|
|
- ✅ `lawrisk/services/licensing_repo.py` - 数据库操作
|
|
|
|
|
|
- `create_service_department()`
|
|
|
|
|
|
- `update_service_department()`
|
|
|
|
|
|
- `delete_service_department()`
|
|
|
|
|
|
- `build_service_department_tree()`
|
|
|
|
|
|
|
|
|
|
|
|
- ✅ `lawrisk/services/auth_service.py` - 账号管理
|
|
|
|
|
|
- `create_user()`
|
|
|
|
|
|
- `update_user_account()`
|
|
|
|
|
|
- `list_users()`
|
|
|
|
|
|
|
|
|
|
|
|
### 前端文件
|
|
|
|
|
|
- ✅ `static/super_admin.html` - 完整实现
|
|
|
|
|
|
- CSS样式:操作按钮、拖拽、模态框
|
|
|
|
|
|
- JavaScript:事件处理、拖拽逻辑、API调用
|
|
|
|
|
|
- HTML结构:模态框、操作按钮
|
|
|
|
|
|
|
|
|
|
|
|
### 测试文件
|
|
|
|
|
|
- ✅ `test_org_management.py` - 自动化测试脚本
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 总结
|
|
|
|
|
|
|
|
|
|
|
|
本次实现完全满足用户需求:
|
|
|
|
|
|
|
|
|
|
|
|
1. ✅ **新增部门** - 填写名称和账号,自动创建账号,默认密码规则
|
|
|
|
|
|
2. ✅ **修改部门** - 编辑名称、电话、备注,账号不可修改
|
|
|
|
|
|
3. ✅ **删除部门** - 安全删除,支持强制删除绑定账号
|
|
|
|
|
|
4. ✅ **拖拽修改层级** - 直观的拖拽操作,视觉反馈清晰
|
|
|
|
|
|
|
|
|
|
|
|
所有功能都已经完整实现,代码经过精心设计,具有良好的用户体验、安全性和可维护性。 🎉
|