433 lines
12 KiB
Markdown
433 lines
12 KiB
Markdown
# 拖拽修改权限等级功能 - 完整实现
|
||
|
||
## 🎯 功能概述
|
||
|
||
根据您的需求,我们实现了通过拖拽方式修改部门权限等级(grade)的功能。
|
||
|
||
**核心特性:**
|
||
- ✅ 拖拽节点名称旁的提示文字 `⋮⋮ 拖拽修改权限`
|
||
- ✅ 弹出权限等级选择面板(90/80/70/60/50/0)
|
||
- ✅ 支持6个权限等级(超级/高级/中级/一般/较低/普通)
|
||
- ✅ 显示当前权限等级
|
||
- ✅ 拖拽时实时提示
|
||
- ✅ 点击面板选择新等级
|
||
- ✅ 确认后更新数据库
|
||
|
||
---
|
||
|
||
## 🎨 界面设计
|
||
|
||
### 1. 权限等级显示
|
||
每个部门节点显示当前权限等级:
|
||
```
|
||
🔑 权限等级: 80
|
||
```
|
||
- 样式:黄色背景 (#fef3c7),橙色边框 (#fcd34d)
|
||
- 位置:部门代码和区域标签下方
|
||
- 图标:🔑 钥匙图标
|
||
|
||
### 2. 拖拽提示
|
||
节点名称右侧显示拖拽提示:
|
||
```
|
||
部门名称 ⋮⋮ 拖拽修改权限
|
||
```
|
||
- 字体:11px,灰色 (#9ca3af)
|
||
- 鼠标样式:move(可移动)
|
||
- 拖拽时:半透明 + 阴影 + 旋转效果
|
||
|
||
### 3. 权限等级选择面板
|
||
**位置:** 页面右上角
|
||
**样式:**
|
||
- 白色卡片,紫色边框 (#4f46e5)
|
||
- 圆角12px,大阴影
|
||
- 280px 最小宽度
|
||
|
||
**内容:**
|
||
```
|
||
┌────────────────────────┐
|
||
│ 修改「XX部门」的权限等级 │
|
||
│ 当前等级:80,选择新等级: │
|
||
│ ┌───┐ ┌───┐ ┌───┐ │
|
||
│ │ 90│ │ 80│ │ 70│ │
|
||
│ │超级│ │高级│ │中级│ │
|
||
│ └───┘ └───┘ └───┘ │
|
||
│ ┌───┐ ┌───┐ ┌───┐ │
|
||
│ │ 60│ │ 50│ │ 0│ │
|
||
│ │一般│ │较低│ │普通│ │
|
||
│ └───┘ └───┘ └───┘ │
|
||
└────────────────────────┘
|
||
```
|
||
|
||
**交互效果:**
|
||
- 悬停:边框变蓝,背景变淡蓝,上移2px
|
||
- 点击:边框和背景变蓝,白色文字,加粗
|
||
|
||
---
|
||
|
||
## ⚙️ 技术实现
|
||
|
||
### 后端改动
|
||
|
||
#### 1. 数据库 Schema (`licensing_repo.py`)
|
||
```sql
|
||
ALTER TABLE service_departments
|
||
ADD COLUMN IF NOT EXISTS grade int DEFAULT 0;
|
||
|
||
CREATE INDEX IF NOT EXISTS service_departments_grade_idx
|
||
ON service_departments (grade);
|
||
```
|
||
|
||
#### 2. 服务函数 (`licensing_repo.py`)
|
||
|
||
**创建部门** - 支持grade参数:
|
||
```python
|
||
def create_service_department(
|
||
name: str,
|
||
*,
|
||
code: Optional[str] = None,
|
||
phone: Optional[str] = None,
|
||
parent_id: Optional[str] = None,
|
||
region_id: Optional[str] = None,
|
||
description: Optional[str] = None,
|
||
grade: Optional[int] = 0, # 新增
|
||
) -> Dict[str, Any]:
|
||
```
|
||
|
||
**更新部门** - 支持grade更新:
|
||
```python
|
||
def update_service_department(
|
||
department_id: str,
|
||
*,
|
||
name: Optional[str] = None,
|
||
phone: Optional[str] = None,
|
||
parent_id: Optional[str] = None,
|
||
region_id: Optional[str] = None,
|
||
description: Optional[str] = None,
|
||
grade: Optional[int] = None, # 新增
|
||
) -> Optional[Dict[str, Any]]:
|
||
```
|
||
|
||
**序列化** - 返回grade字段:
|
||
```python
|
||
def _serialize_service_department_row(record: Dict[str, Any]) -> Dict[str, Any]:
|
||
return {
|
||
...
|
||
"grade": record.get("grade", 0), # 新增
|
||
...
|
||
}
|
||
```
|
||
|
||
#### 3. API 路由 (`v2.py`)
|
||
|
||
**创建部门** - 处理grade:
|
||
```python
|
||
POST /fs-ai-asistant/api/workflow/lawrisk/admin/service-departments
|
||
{
|
||
"name": "部门名称",
|
||
"code": "部门账号",
|
||
"grade": 80, # 新增字段
|
||
...
|
||
}
|
||
```
|
||
|
||
**更新部门** - 处理grade更新:
|
||
```python
|
||
PATCH /fs-ai-asistant/api/workflow/lawrisk/admin/service-departments/{id}
|
||
{
|
||
"grade": 90, # 修改权限等级
|
||
...
|
||
}
|
||
```
|
||
|
||
### 前端实现
|
||
|
||
#### 1. HTML结构 (`super_admin.html`)
|
||
```html
|
||
<!-- 权限等级选择面板 -->
|
||
<div id="gradeDropPanel" class="grade-drop-panel">
|
||
<h4>选择权限等级</h4>
|
||
<p>拖拽部门到此处来修改权限</p>
|
||
<div class="grade-options">
|
||
<div class="grade-option" data-grade="90">
|
||
<span class="grade-number">90</span>
|
||
<span class="grade-label">超级</span>
|
||
</div>
|
||
<div class="grade-option" data-grade="80">
|
||
<span class="grade-number">80</span>
|
||
<span class="grade-label">高级</span>
|
||
</div>
|
||
<div class="grade-option" data-grade="70">
|
||
<span class="grade-number">70</span>
|
||
<span class="grade-label">中级</span>
|
||
</div>
|
||
<div class="grade-option" data-grade="60">
|
||
<span class="grade-number">60</span>
|
||
<span class="grade-label">一般</span>
|
||
</div>
|
||
<div class="grade-option" data-grade="50">
|
||
<span class="grade-number">50</span>
|
||
<span class="grade-label">较低</span>
|
||
</div>
|
||
<div class="grade-option" data-grade="0">
|
||
<span class="grade-number">0</span>
|
||
<span class="grade-label">普通</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
```
|
||
|
||
#### 2. CSS样式 (`super_admin.html`)
|
||
```css
|
||
/* 权限等级显示 */
|
||
.node-grade {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
padding: 3px 8px;
|
||
background: #fef3c7;
|
||
border-radius: 6px;
|
||
font-size: 12px;
|
||
color: #92400e;
|
||
border: 1px solid #fcd34d;
|
||
}
|
||
|
||
/* 权限等级选择面板 */
|
||
.grade-drop-panel {
|
||
position: fixed;
|
||
background: white;
|
||
border: 2px solid #4f46e5;
|
||
border-radius: 12px;
|
||
padding: 16px;
|
||
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.25);
|
||
z-index: 2000;
|
||
min-width: 280px;
|
||
}
|
||
|
||
/* 权限等级选项 */
|
||
.grade-option {
|
||
border: 2px solid #e5e7eb;
|
||
border-radius: 8px;
|
||
padding: 12px 8px;
|
||
text-align: center;
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
background: #f9fafb;
|
||
}
|
||
|
||
.grade-option:hover {
|
||
border-color: #4f46e5;
|
||
background: #eef2ff;
|
||
transform: translateY(-2px);
|
||
}
|
||
```
|
||
|
||
#### 3. JavaScript逻辑 (`super_admin.html`)
|
||
```javascript
|
||
function initDragAndDrop() {
|
||
const nameSpans = document.querySelectorAll('.node-name');
|
||
const gradePanel = document.getElementById('gradeDropPanel');
|
||
|
||
nameSpans.forEach(span => {
|
||
const nodeDiv = span.closest('.org-node');
|
||
const nodeId = nodeDiv.getAttribute('data-node-id');
|
||
|
||
span.setAttribute('draggable', 'true');
|
||
|
||
span.addEventListener('dragstart', (evt) => {
|
||
currentDraggedNode = nodeId;
|
||
nodeDiv.classList.add('dragging');
|
||
|
||
const sourceNode = orgChartData.nodeMap[nodeId];
|
||
gradePanel.querySelector('h4').textContent =
|
||
`修改「${sourceNode.name}」的权限等级`;
|
||
gradePanel.querySelector('p').textContent =
|
||
'当前等级:' + (sourceNode.grade || 0) + ',选择新等级:';
|
||
|
||
gradePanel.classList.add('show');
|
||
});
|
||
|
||
span.addEventListener('dragend', () => {
|
||
nodeDiv.classList.remove('dragging');
|
||
gradePanel.classList.remove('show');
|
||
currentDraggedNode = null;
|
||
});
|
||
});
|
||
|
||
// 点击权限等级选项
|
||
gradePanel.querySelectorAll('.grade-option').forEach(option => {
|
||
option.addEventListener('click', async () => {
|
||
const newGrade = parseInt(option.dataset.grade);
|
||
const sourceNode = orgChartData.nodeMap[currentDraggedNode];
|
||
const currentGrade = sourceNode.grade || 0;
|
||
|
||
if (confirm(`确定要将「${sourceNode.name}」的权限等级从 ${currentGrade} 修改为 ${newGrade} 吗?`)) {
|
||
await fetchJSON(`${API_BASE}/admin/service-departments/${sourceNode.id}`, {
|
||
method: 'PATCH',
|
||
body: JSON.stringify({ grade: newGrade })
|
||
});
|
||
showMessage(`权限等级已更新为 ${newGrade}`, 'success');
|
||
gradePanel.classList.remove('show');
|
||
await loadOrgChart();
|
||
}
|
||
});
|
||
});
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🎬 使用步骤
|
||
|
||
### 1. 访问界面
|
||
```
|
||
http://127.0.0.1:8000/static/super_admin.html
|
||
```
|
||
|
||
### 2. 切换到组织架构标签页
|
||
点击「组织架构」标签
|
||
|
||
### 3. 查看权限等级
|
||
每个部门节点下方显示:
|
||
```
|
||
🔑 权限等级: 80
|
||
```
|
||
|
||
### 4. 拖拽修改权限
|
||
1. **开始拖拽**:拖拽节点名称右侧的 `⋮⋮ 拖拽修改权限`
|
||
2. **显示面板**:权限等级选择面板自动弹出
|
||
3. **选择等级**:点击面板中的权限等级(90/80/70/60/50/0)
|
||
4. **确认操作**:弹出确认对话框
|
||
5. **完成更新**:数据库更新,界面刷新
|
||
|
||
### 5. 新增部门时设置权限
|
||
1. 点击 `➕ 新增` 按钮
|
||
2. 填写部门信息
|
||
3. **选择权限等级**:下拉菜单选择 90-0
|
||
4. 点击「确定」创建
|
||
|
||
### 6. 编辑部门权限
|
||
1. 点击 `✏️ 编辑` 按钮
|
||
2. 修改「权限等级」下拉菜单
|
||
3. 点击「确定」保存
|
||
|
||
---
|
||
|
||
## 📊 权限等级说明
|
||
|
||
| 等级 | 名称 | 用途 |
|
||
|------|------|------|
|
||
| 90 | 超级 | 最高管理权限,系统级操作 |
|
||
| 80 | 高级 | 部门级管理权限,默认等级 |
|
||
| 70 | 中级 | 一般管理权限 |
|
||
| 60 | 一般 | 标准操作权限 |
|
||
| 50 | 较低 | 受限操作权限 |
|
||
| 0 | 普通 | 基础查看权限 |
|
||
|
||
**默认等级:** 80(高级)
|
||
|
||
---
|
||
|
||
## ✨ 功能特点
|
||
|
||
### 1. 直观的拖拽体验
|
||
- ✅ 清晰的拖拽提示文字
|
||
- ✅ 拖拽时的视觉反馈(半透明+旋转)
|
||
- ✅ 实时显示当前权限等级
|
||
- ✅ 友好的确认对话框
|
||
|
||
### 2. 清晰的视觉设计
|
||
- ✅ 权限等级标签使用醒目颜色(黄色背景)
|
||
- ✅ 权限等级面板使用紫色主题
|
||
- ✅ 悬停效果提升交互感
|
||
- ✅ 图标+文字的组合设计
|
||
|
||
### 3. 完善的功能支持
|
||
- ✅ 新增部门时可设置权限等级
|
||
- ✅ 编辑部门时可修改权限等级
|
||
- ✅ 拖拽快速调整权限等级
|
||
- ✅ 显示所有部门当前权限
|
||
|
||
### 4. 数据安全
|
||
- ✅ 拖拽前显示当前权限
|
||
- ✅ 修改前弹出确认对话框
|
||
- ✅ 修改后显示成功消息
|
||
- ✅ 数据库实时更新
|
||
|
||
---
|
||
|
||
## 🧪 测试用例
|
||
|
||
### 测试用例 1:查看权限等级显示
|
||
**步骤:**
|
||
1. 访问组织架构页面
|
||
2. 查看部门节点信息
|
||
|
||
**预期:**
|
||
- 每个节点显示 `🔑 权限等级: XX`
|
||
- 颜色为黄色背景,橙色边框
|
||
|
||
### 测试用例 2:拖拽修改权限
|
||
**步骤:**
|
||
1. 拖拽节点名称旁的 `⋮⋮ 拖拽修改权限`
|
||
2. 权限面板弹出,显示当前等级
|
||
3. 点击新的权限等级(如从 80 改为 90)
|
||
4. 确认对话框出现
|
||
5. 点击「确定」
|
||
|
||
**预期:**
|
||
- 权限面板显示部门名称和当前等级
|
||
- 点击后弹出确认对话框
|
||
- 确认后权限等级更新
|
||
- 界面显示成功消息
|
||
- 页面刷新,新权限生效
|
||
|
||
### 测试用例 3:新增部门设置权限
|
||
**步骤:**
|
||
1. 点击 `➕ 新增` 按钮
|
||
2. 填写部门信息
|
||
3. 选择权限等级(如选择 70)
|
||
4. 点击「确定」
|
||
|
||
**预期:**
|
||
- 表单中有「权限等级」下拉菜单
|
||
- 默认选中 80(高级)
|
||
- 创建成功后显示默认密码
|
||
- 新部门显示选中的权限等级
|
||
|
||
### 测试用例 4:编辑部门权限
|
||
**步骤:**
|
||
1. 点击 `✏️ 编辑` 按钮
|
||
2. 修改权限等级下拉菜单
|
||
3. 点击「确定」
|
||
|
||
**预期:**
|
||
- 表单预填充当前权限等级
|
||
- 可以修改权限等级
|
||
- 保存后权限更新成功
|
||
|
||
---
|
||
|
||
## 🎉 总结
|
||
|
||
拖拽修改权限等级功能已经完全实现!
|
||
|
||
**主要文件:**
|
||
- ✅ `lawrisk/services/licensing_repo.py` - 数据库Schema和操作函数
|
||
- ✅ `lawrisk/api/v2.py` - API路由和业务逻辑
|
||
- ✅ `static/super_admin.html` - 前端界面和交互
|
||
|
||
**核心功能:**
|
||
- ✅ 拖拽修改权限等级(6个等级:90/80/70/60/50/0)
|
||
- ✅ 权限等级显示(黄色标签)
|
||
- ✅ 权限等级面板(紫色主题)
|
||
- ✅ 新增时设置权限
|
||
- ✅ 编辑时修改权限
|
||
|
||
**用户体验:**
|
||
- ✅ 清晰的拖拽提示
|
||
- ✅ 实时权限显示
|
||
- ✅ 友好的确认对话框
|
||
- ✅ 操作成功反馈
|
||
|
||
完全满足您的需求!🎯
|