# 许可管理单位权限优化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
共找到 0 条许可
``` #### 3.3.2 联动逻辑 ```javascript // 市级单位选择变化时,动态加载区级单位 document.getElementById('municipalDept').addEventListener('change', function() { const municipalId = this.value; const districtSelect = document.getElementById('districtDept'); if (!municipalId) { districtSelect.innerHTML = ''; districtSelect.disabled = true; return; } // 加载该市级单位下的区级单位 fetch(`/api/admin/departments/children?parent_id=${municipalId}`) .then(res => res.json()) .then(data => { districtSelect.innerHTML = ''; data.units.forEach(unit => { districtSelect.innerHTML += ``; }); 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

{{ permit.name }}

{{ permit.department_name }} {{ permit.region_name }}
{{ permit.theme_name }} 风险 {{ permit.risk_count }} 条
``` ## 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