fs-lawrisk/docs/PRD_UNIT_PERMISSION_OPTIMIZ...

581 lines
16 KiB
Markdown
Raw Normal View History

# 许可管理单位权限优化PRD
## 1. 需求背景
### 1.1 当前问题
- 现有权限体系:市局账号 vs 区局子管理员通过grade区分
- 现状:市局账号查看全部许可,区局子管理员仅能查看本区许可
- 局限:
- 缺乏市级单位(局、委、办)和区级单位的层级管理
- 上传许可文件时无法指定绑定的具体单位
- 浏览方式低效(仅按行政区筛选)
### 1.2 优化目标
1. **单位层级管理**:引入市级单位和区级单位的概念
2. **权限细分**
- 市局账号:保留全部可见权限
- 市级单位:可见自身 + 下属区级单位
- 区局子管理员:可见下属所有单位
- 区级单位:仅可见自身
3. **文件绑定优化**:上传许可可绑定到具体单位
4. **浏览效率提升**:从单一"选择区域"改为多维度"过滤器筛选"
### 1.3 保留内容
- ✅ 一市五区的行政区划不变
- ✅ 现有账户保留(作为市局和区局子管理员)
- ✅ 现有API保持兼容
## 2. 功能需求
### 2.1 单位管理功能
#### 2.1.1 单位级别定义
| 单位类型 | 说明 | 示例 | 可视范围 |
|---------|------|------|----------|
| admin | 市局管理员 | FSSJSJ市级管理员 | 全部许可 |
| municipal | 市级单位 | 市监局、卫健局、交通局等 | 自身 + 下属区级单位 |
| district | 区局子管理员 | 禅城区、南海区等管理员 | 下属所有单位 |
| unit | 区级单位 | 禅城区市场监督管理局等 | 仅自身 |
#### 2.1.2 单位创建流程
1. **创建市级单位**
- 指定单位名称、编码
- 设置单位级别为 `municipal`
- 可绑定多个区级行政区
- 自动生成管理员账号
2. **创建区级单位**
- 指定单位名称、编码
- 设置单位级别为 `unit`
- 绑定到具体行政区(禅城区、南海区等)
- 关联到市级单位作为上级
### 2.2 权限控制功能
#### 2.2.1 可见性规则
```python
# 权限判断逻辑
def get_visible_permits(user, filters):
dept = user.service_department
unit_level = dept.unit_level
if user.role == 'admin' or user.grade >= 90:
# 市局:全部许可
return query_all_permits(filters)
elif unit_level == 'municipal':
# 市级单位:自身 + 下属区级单位
subordinate_ids = get_subordinate_departments(dept.id, level='unit')
return query_permits_by_departments([dept.id] + subordinate_ids, filters)
elif unit_level == 'district':
# 区局子管理员:下属所有单位
return query_permits_by_region(dept.region_id, filters)
elif unit_level == 'unit':
# 区级单位:仅自身
return query_permits_by_departments([dept.id], filters)
else:
# 未知级别:无权限
return []
```
#### 2.2.2 权限矩阵
| 用户类型 | 自身许可 | 下属单位许可 | 其他区许可 | 其他市级单位许可 |
|---------|---------|-------------|----------|----------------|
| 市局管理员 | ✅ | ✅ | ✅ | ✅ |
| 市级单位用户 | ✅ | ✅ | ❌ | ❌ |
| 区局子管理员 | ✅ | ✅ | ❌ | ❌ |
| 区级单位用户 | ✅ | ❌ | ❌ | ❌ |
### 2.3 文件上传绑定功能
#### 2.3.1 绑定规则
| 上传者类型 | 默认绑定 | 可修改性 | 可见用户 |
|----------|---------|---------|----------|
| 市局管理员 | 市局自身 | 可选择任意单位 | 所有用户 |
| 市级单位用户 | 市级单位自身 | 可选择下属区级单位 | 市局 + 相关单位 |
| 区局子管理员 | 所属区 | 可修改 | 市局 + 相关区局 |
| 区级单位用户 | 自身单位 | 不可修改 | 市局 + 上级区局 |
#### 2.3.2 绑定流程
```python
def handle_permit_upload(file_data, uploader_user, bound_department_id=None):
# 1. 确定绑定单位
if not bound_department_id:
bound_department_id = get_default_binding(uploader_user)
# 2. 保存文件
file_id = save_permit_file(file_data)
# 3. 记录绑定关系
bind_permit_to_department(
file_id=file_id,
bound_department_id=bound_department_id,
uploader_department_id=uploader_user.service_department_id,
uploader_user_id=uploader_user.id
)
# 4. 返回可见用户列表
return get_visible_users(bound_department_id, uploader_user)
```
### 2.4 筛选浏览功能
#### 2.4.1 筛选维度
1. **市级单位**:下拉选择(全部/具体单位)
2. **区级单位**:下拉选择(全部/具体单位)
3. **行政区**:下拉选择(全部/禅城区/南海区/.../市级)
4. **许可名称**:文本搜索
#### 2.4.2 交互方式
- 市级单位和区级单位联动选择
- 支持搜索过滤
- 重置按钮清空所有筛选
- 显示已筛选结果数量
## 3. 技术方案
### 3.1 数据库设计
#### 3.1.1 现有表调整
**service_departments 表新增字段**
```sql
ALTER TABLE service_departments
ADD COLUMN unit_level VARCHAR(20) DEFAULT 'unit' CHECK (unit_level IN ('admin', 'municipal', 'district', 'unit')),
ADD COLUMN allowed_regions TEXT; -- 市级单位可访问的行政区,多个用逗号分隔
```
**permit_sources 表新增字段**
```sql
ALTER TABLE permit_sources
ADD COLUMN uploader_department_id UUID REFERENCES service_departments(id),
ADD COLUMN bound_department_id UUID REFERENCES service_departments(id);
```
#### 3.1.2 新建索引
```sql
CREATE INDEX idx_service_dept_unit_level ON service_departments(unit_level);
CREATE INDEX idx_service_dept_parent_level ON service_departments(parent_id, unit_level);
CREATE INDEX idx_permit_sources_bound_dept ON permit_sources(bound_department_id);
CREATE INDEX idx_permit_sources_uploader ON permit_sources(uploader_department_id);
```
#### 3.1.3 数据迁移脚本
```sql
-- 迁移现有数据
UPDATE service_departments SET unit_level = 'admin' WHERE grade >= 90;
UPDATE service_departments SET unit_level = 'district' WHERE parent_id IS NULL AND grade < 90;
-- 为现有表添加约束
ALTER TABLE service_departments ALTER COLUMN unit_level SET NOT NULL;
```
### 3.2 后端API设计
#### 3.2.1 新增API
**获取单位列表(支持层级)**
```
GET /admin/departments/tree
Response: {
"success": true,
"data": {
"municipal_units": [
{
"id": "uuid-1",
"name": "市监局",
"code": "AMR_FS",
"units": [
{"id": "uuid-2", "name": "禅城区市监局", "region": "禅城区"},
{"id": "uuid-3", "name": "南海区市监局", "region": "南海区"}
]
}
]
}
}
```
**筛选查询许可**
```
POST /admin/permits/filter
Request: {
"municipal_dept_id": "uuid-1",
"district_dept_id": "uuid-2",
"region": "禅城区",
"search_text": "电影院",
"page": 1,
"page_size": 20
}
Response: {
"success": true,
"data": {
"permits": [...],
"pagination": {
"total": 100,
"page": 1,
"page_size": 20
}
}
}
```
**上传许可文件(新增绑定参数)**
```
POST /admin/permit-import/upload
Request: form-data
- file: [Excel文件]
- bound_department_id: "uuid-2" # 可选,不传则自动绑定
Response: {
"success": true,
"data": {
"session_id": "uuid",
"bound_to": {
"department_id": "uuid-2",
"department_name": "禅城区市监局",
"visible_to": ["admin_users", "related_users"]
}
}
}
```
#### 3.2.2 修改现有API
**获取许可列表(向后兼容)**
```
GET /getPermits?region=禅城区
```
- 保持现有参数不变
- 新增根据单位级别过滤的逻辑
### 3.3 前端设计
#### 3.3.1 筛选器UI
```html
<div class="filter-panel">
<div class="filter-row">
<div class="filter-item">
<label>市级单位:</label>
<select id="municipalDept">
<option value="">全部</option>
<option value="dept_1">市监局</option>
<option value="dept_2">卫健局</option>
<option value="dept_3">交通局</option>
</select>
</div>
<div class="filter-item">
<label>区级单位:</label>
<select id="districtDept" disabled>
<option value="">请先选择市级单位</option>
</select>
</div>
<div class="filter-item">
<label>行政区:</label>
<select id="region">
<option value="">全部</option>
<option value="禅城区">禅城区</option>
<option value="南海区">南海区</option>
<option value="顺德区">顺德区</option>
<option value="三水区">三水区</option>
<option value="高明区">高明区</option>
<option value="市级">市级</option>
</select>
</div>
</div>
<div class="filter-row">
<div class="filter-item search-item">
<label>搜索许可:</label>
<input type="text" id="searchText" placeholder="输入许可名称...">
<button class="btn btn-primary" onclick="applyFilters()">筛选</button>
<button class="btn btn-secondary" onclick="resetFilters()">重置</button>
</div>
</div>
<div class="filter-result-info">
<span id="resultCount">共找到 0 条许可</span>
</div>
</div>
```
#### 3.3.2 联动逻辑
```javascript
// 市级单位选择变化时,动态加载区级单位
document.getElementById('municipalDept').addEventListener('change', function() {
const municipalId = this.value;
const districtSelect = document.getElementById('districtDept');
if (!municipalId) {
districtSelect.innerHTML = '<option value="">请先选择市级单位</option>';
districtSelect.disabled = true;
return;
}
// 加载该市级单位下的区级单位
fetch(`/api/admin/departments/children?parent_id=${municipalId}`)
.then(res => res.json())
.then(data => {
districtSelect.innerHTML = '<option value="">全部</option>';
data.units.forEach(unit => {
districtSelect.innerHTML += `<option value="${unit.id}">${unit.name}</option>`;
});
districtSelect.disabled = false;
});
});
// 应用筛选
function applyFilters() {
const filters = {
municipal_dept_id: document.getElementById('municipalDept').value,
district_dept_id: document.getElementById('districtDept').value,
region: document.getElementById('region').value,
search_text: document.getElementById('searchText').value
};
// 调用API获取数据
fetch('/api/admin/permits/filter', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(filters)
}).then(res => res.json())
.then(data => {
renderPermits(data.permits);
updateResultCount(data.pagination.total);
});
}
```
#### 3.3.3 许可列表展示
```html
<div class="permit-list">
<div class="permit-item" v-for="permit in permits">
<div class="permit-header">
<h3>{{ permit.name }}</h3>
<span class="permit-dept">{{ permit.department_name }}</span>
<span class="permit-region">{{ permit.region_name }}</span>
</div>
<div class="permit-meta">
<span class="permit-theme">{{ permit.theme_name }}</span>
<span class="permit-risk-count">风险 {{ permit.risk_count }} 条</span>
</div>
<div class="permit-actions">
<button @click="viewPermit(permit.id)">查看详情</button>
<button @click="downloadFile(permit.file_id)" v-if="permit.file_id">下载文件</button>
</div>
</div>
</div>
```
## 4. 实施计划
### 4.1 阶段一后端开发预计3-5天
#### 4.1.1 数据库迁移
- [ ] 编写并执行ALTER TABLE语句
- [ ] 创建索引
- [ ] 执行数据迁移脚本
- [ ] 验证迁移结果
**负责人**:后端开发
**交付物**
- 迁移脚本文件
- 数据迁移报告
#### 4.1.2 权限逻辑调整
- [ ] 修改 `licensing_repo.py` 中的 `list_permits_for_region` 函数
- [ ] 新增 `get_subordinate_departments` 函数
- [ ] 新增 `get_visible_permits` 统一接口
- [ ] 编写单元测试
**负责人**:后端开发
**交付物**
- 权限控制代码
- 单元测试用例
- API文档
#### 4.1.3 新增API开发
- [ ] `/admin/departments/tree` - 获取单位树
- [ ] `/admin/departments/children` - 获取子单位
- [ ] `/admin/permits/filter` - 筛选查询
- [ ] 修改 `/admin/permit-import/upload` 支持绑定单位
**负责人**:后端开发
**交付物**
- API接口代码
- API文档
- Postman测试集合
#### 4.1.4 现有API兼容性测试
- [ ] 测试 `/getPermits` 接口
- [ ] 测试所有 `/admin/*` 接口
- [ ] 确保向后兼容
**负责人**:后端开发 + 测试
**交付物**
- 测试报告
- 性能测试结果
### 4.2 阶段二前端开发预计3-4天
#### 4.2.1 筛选器组件开发
- [ ] 设计筛选器UI样式
- [ ] 实现下拉联动逻辑
- [ ] 实现搜索和重置功能
- [ ] 响应式适配
**负责人**:前端开发
**交付物**
- HTML/CSS/JS代码
- 组件文档
#### 4.2.2 API集成
- [ ] 集成新的筛选API
- [ ] 实现数据加载和分页
- [ ] 优化加载性能
- [ ] 错误处理
**负责人**:前端开发
**交付物**
- 集成了新API的前端页面
- 前端测试报告
#### 4.2.3 文件上传绑定UI
- [ ] 添加绑定单位选择器
- [ ] 默认绑定逻辑提示
- [ ] 可见用户列表展示
**负责人**:前端开发
**交付物**
- 文件上传界面
- 用户体验测试报告
#### 4.2.4 整体测试
- [ ] 功能测试
- [ ] 兼容性测试
- [ ] 性能测试
- [ ] 修复BUG
**负责人**:前端开发 + 测试
**交付物**
- 测试报告
- 修复清单
### 4.3 阶段三联调测试预计2-3天
#### 4.3.1 单元测试
- [ ] 后端API测试
- [ ] 前端功能测试
- [ ] 数据库操作测试
#### 4.3.2 集成测试
- [ ] 端到端流程测试
- [ ] 权限验证测试
- [ ] 文件上传下载测试
#### 4.3.3 性能测试
- [ ] 并发查询测试
- [ ] 大量数据查询测试
- [ ] 优化性能瓶颈
#### 4.3.4 用户验收测试
- [ ] 业务场景测试
- [ ] 界面易用性测试
- [ ] 需求确认
**负责人**:全体开发 + 产品 + 测试
**交付物**
- 集成测试报告
- 性能测试报告
- UAT测试报告
### 4.4 阶段四上线部署预计1天
#### 4.4.1 生产环境部署
- [ ] 数据库迁移
- [ ] 后端服务部署
- [ ] 前端页面部署
- [ ] 配置检查
#### 4.4.2 上线验证
- [ ] 功能验证
- [ ] 性能验证
- [ ] 监控检查
**负责人**:运维 + 开发
**交付物**
- 上线检查清单
- 回滚预案
## 5. 风险评估
### 5.1 技术风险
| 风险项 | 影响程度 | 应对措施 |
|--------|---------|---------|
| 数据库迁移失败 | 高 | 提前备份,准备回滚脚本 |
| 权限逻辑复杂导致BUG | 中 | 详细单元测试,逐步发布 |
| 查询性能下降 | 中 | 添加索引必要时优化SQL |
| API变更影响现有功能 | 中 | 保持向后兼容新老API并行 |
### 5.2 业务风险
| 风险项 | 影响程度 | 应对措施 |
|--------|---------|---------|
| 权限设置错误导致数据泄露 | 高 | 严格测试,灰度发布 |
| 用户操作复杂,学习成本高 | 低 | 提供培训,更新文档 |
| 现有工作流程被破坏 | 中 | 保持核心功能不变,新增功能可选 |
### 5.3 应对预案
1. **数据安全**每次部署前创建checkpoint备份
2. **功能回滚**保留旧版本API至少3个月
3. **灰度发布**:新功能先开放给测试用户
4. **应急响应**建立问题反馈群24小时内响应
## 6. 成功标准
### 6.1 功能标准
- [ ] 单位层级管理功能完整可用
- [ ] 权限控制准确无误
- [ ] 文件上传绑定符合预期
- [ ] 筛选浏览高效便捷
### 6.2 性能标准
- [ ] API响应时间 < 1秒
- [ ] 页面加载时间 < 3秒
- [ ] 支持同时在线用户数 > 100
- [ ] 单位数量支持 > 100
### 6.3 用户体验标准
- [ ] 操作步骤减少 30%
- [ ] 筛选精度提升 50%
- [ ] 学习成本 < 30分钟
- [ ] 用户满意度 > 85%
## 7. 项目里程碑
| 里程碑 | 预计完成时间 | 交付物 |
|--------|-------------|--------|
| 需求评审通过 | T+0 | 本PRD文档 |
| 后端开发完成 | T+5 | 后端代码 + 测试 |
| 前端开发完成 | T+9 | 前端代码 + 测试 |
| 集成测试通过 | T+12 | 测试报告 |
| 生产环境上线 | T+13 | 上线系统 |
---
**编写人员**[产品经理] + [技术负责人]
**评审人员**[项目经理] + [开发团队] + [测试团队]
**最后更新**2025-11-19