# INST-机构管ç†ç«?- 模å—当å‰çжæ€ä¸Žå¼€å‘指å? > **æœ€åŽæ›´æ–°ï¼š** 2026-01-11 > **状æ€ï¼š** 🔴 未开始(等待è¿è¥ç®¡ç†ç«¯å®Œæˆï¼‰ > **版本ï¼?* v0.0 (Planning) --- ## 🎯 一å¥è¯æ€»ç»“ **机构管ç†ç«¯ä¸ºåŒ»é™¢å’Œè¯ä¼å®¢æˆ·æä¾›è‡ªæœåŠ¡ç®¡ç†ç•Œé¢ï¼Œè®©æœºæž„管ç†å‘˜èƒ½å¤Ÿç‹¬ç«‹ç®¡ç†ç”¨æˆ·ã€é…é¢ã€ç§‘å®?项目等资æºã€?* --- ## 📊 当å‰å¼€å‘状æ€? ### âœ?已完æˆ? - [ ] **æ—?*(尚未开始) ### 🚧 进行ä¸? - [ ] **æ—?* ### â?å¾…å¼€å‘(ä¾èµ–è¿è¥ç®¡ç†ç«¯ï¼‰ **å‰ç½®æ¡ä»¶ï¼ˆå¿…须先完æˆï¼‰ï¼š** - [ ] è¿è¥ç®¡ç†ç«¯åŸºç¡€æž¶æž„(Phase 0-2ï¼? - [ ] 租户管ç†åŠŸèƒ½ - [ ] 租户专属登录é¡? - [ ] å“牌定制é…ç½® **机构管ç†ç«¯å¼€å‘计划(预计Week 5+):** **P1 - 医院管ç†ç«¯ï¼ˆWeek 5-6ï¼?* - [ ] 用户管ç†ï¼ˆCRUD + 科室分é…ï¼? - [ ] 科室管ç†ï¼ˆæ”¯æŒå¤šçº§ç»“构) - [ ] é…é¢åˆ†é…(科å®?个人ï¼? - [ ] 审计日志查询 **P1 - è¯ä¼ç®¡ç†ç«¯ï¼ˆWeek 7-8ï¼?* - [ ] 用户管ç†ï¼ˆCRUD + 角色分é…ï¼? - [ ] 项目管ç†ï¼ˆIIT项目关è”ï¼? - [ ] é…é¢åˆ†é…(项ç›?个人ï¼? - [ ] 审计日志查询(FDAåˆè§„ï¼? --- ## ðŸ—ï¸?架构概览 ``` ┌─────────────────────────────────────────────────â”? â”? 机构管ç†ç«¯ï¼ˆINST Portalï¼? â”? ├──────────────────────┬──────────────────────────â”? â”? 🥠医院管ç†ç«? â”? 💊 è¯ä¼ç®¡ç†ç«? â”? ├──────────────────────┼──────────────────────────â”? â”?· ç”¨æˆ·ç®¡ç† â”? · ç”¨æˆ·ç®¡ç† â”? â”?· ç§‘å®¤ç®¡ç† â”? · é¡¹ç›®ç®¡ç† â”? â”?· é…é¢åˆ†é…(科å®?人) â”? · é…é¢åˆ†é…(项ç›?人) â”? â”?· 审计日志 â”? · 审计日志(åˆè§„) â”? └──────────────────────┴──────────────────────────â”? â†? 继承è¿è¥ç®¡ç†ç«¯çš„基础设施 â†? ┌─────────────────────────────────────────────────â”? â”? Platform Layer â”? â”? 认è¯ä¸­å¿ƒ â”?æƒé™ä¸­å¿ƒ â”?多租户隔ç¦?â”?审计日志 â”? └─────────────────────────────────────────────────â”? ``` --- ## 🔠æƒé™çŸ©é˜µ | 功能 | HOSPITAL_ADMIN | DEPARTMENT_ADMIN | PHARMA_ADMIN | PROJECT_MANAGER | USER | |------|----------------|------------------|--------------|-----------------|------| | 用户管ç†ï¼ˆç§Ÿæˆ·å†…ï¼?| âœ?全部 | âœ?本科å®?| âœ?全部 | âœ?项目æˆå‘˜ | â?| | ç§‘å®¤ç®¡ç† | âœ?| â?| N/A | N/A | â?| | é¡¹ç›®ç®¡ç† | N/A | N/A | âœ?查看 | âœ?ç®¡ç† | â?| | é…é¢åˆ†é… | âœ?| âœ?本科å®?| âœ?| âœ?项目å†?| â?| | 审计日志 | âœ?租户å†?| âœ?本科å®?| âœ?租户å†?| âœ?项目å†?| â?| | 业务模å—使用 | âœ?| âœ?| âœ?| âœ?| âœ?| --- ## 📠代ç ç»“构(规划) ### åŽç«¯ ``` backend/src/ ├── modules/ â”? └── institution/ # 机构管ç†ç«¯æ¨¡å? â”? ├── controllers/ â”? â”? ├── hospital/ â”? â”? â”? ├── user.controller.ts â”? â”? â”? ├── department.controller.ts â”? â”? â”? └── quota.controller.ts â”? â”? â”? â”? â”? └── pharma/ â”? â”? ├── user.controller.ts â”? â”? ├── project.controller.ts â”? â”? └── quota.controller.ts â”? â”? â”? ├── services/ â”? â”? ├── hospital.service.ts â”? â”? └── pharma.service.ts â”? â”? â”? └── routes/ â”? ├── hospital.routes.ts â”? └── pharma.routes.ts â”? └── common/ └── middleware/ ├── tenant.middleware.ts # 租户隔离(å¤ç”¨ï¼‰ └── department.middleware.ts # 科室æƒé™æ£€æŸ? ``` ### å‰ç«¯ ``` frontend-v2/src/ ├── modules/ â”? └── institution/ # 机构管ç†ç«¯æ¨¡å? â”? ├── pages/ â”? â”? ├── hospital/ â”? â”? â”? ├── UserManagement/ â”? â”? â”? ├── DepartmentManagement/ â”? â”? â”? ├── QuotaAllocation/ â”? â”? â”? └── AuditLog/ â”? â”? â”? â”? â”? └── pharma/ â”? â”? ├── UserManagement/ â”? â”? ├── ProjectManagement/ â”? â”? ├── QuotaAllocation/ â”? â”? └── AuditLog/ â”? â”? â”? └── components/ â”? ├── UserForm/ â”? ├── DepartmentTree/ â”? ├── QuotaAllocator/ â”? └── AuditLogViewer/ â”? └── layouts/ └── TenantLayout/ # 租户专属布局(å“牌定制) ``` --- ## 🎨 UI/UX 特æ€? ### 1. 租户å“牌定制 ```typescript // 从API获å–租户é…ç½® const tenantConfig = await api.get('/api/public/tenant-config/:tenantCode'); // 应用å“ç‰Œæ ·å¼ document.documentElement.style.setProperty('--primary-color', config.primaryColor); document.title = config.systemName; ``` **效果ï¼?* - å和医院看到的是åå’ŒLogoå’?å和临床研究平å°" - 辉瑞è¯ä¸šçœ‹åˆ°çš„æ˜¯è¾‰ç‘žLogoå’?辉瑞IIT管ç†å¹³å°" ### 2. 科室树组件(医院端) ```tsx loadDeptUsers(dept)} showQuota={true} // 显示科室é…é¢ allowEdit={hasPermission('dept:edit')} /> ``` **支æŒï¼?* - 多级展开/æŠ˜å  - æ‹–æ‹½æŽ’åº - é…é¢å¯è§†åŒ? ### 3. é…é¢åˆ†é…å™? ```tsx handleAllocate(target, amount)} /> ``` **特性:** - å¯è§†åŒ–è¿›åº¦æ¡ - 实时计算剩余é…é¢ - è¶…é¢é¢„è­¦ --- ## 🗄ï¸?æ•°æ®æ¨¡åž‹ ### 医院ç«? ```typescript // 科室 interface Department { id: string; tenantId: string; name: string; parentId?: string; // 支æŒå¤šçº§ description?: string; members: User[]; quota?: QuotaAllocation; } // é…é¢åˆ†é… interface QuotaAllocation { id: string; tenantId: string; targetType: 'DEPARTMENT' | 'USER'; targetKey: string; // DepartmentID æˆ?UserID limitAmount: bigint; usedAmount: bigint; } ``` ### è¯ä¼ç«? ```typescript // 项目(关è”IITï¼? interface Project { id: string; tenantId: string; iitProjectId?: string; // å…³è”IIT项目 name: string; description?: string; members: User[]; quota?: QuotaAllocation; } // 项目æˆå‘˜ interface ProjectMember { id: string; projectId: string; userId: string; role: 'PROJECT_MANAGER' | 'DATA_ANALYST' | 'MEMBER'; } ``` --- ## 🚀 开呿µç¨? ### Step 1: 设计阶段(当å‰ï¼‰ - [ ] 详细需求文档(PRDï¼? - [ ] API接å£è®¾è®¡ - [ ] æ•°æ®åº“表设计 - [ ] UI原型设计 ### Step 2: åŽç«¯å¼€å‘(ä¾èµ–è¿è¥ç«¯å®Œæˆï¼‰ 1. **医院端API** - 用户管ç†API - 科室管ç†API - é…é¢åˆ†é…API - 审计日志API 2. **è¯ä¼ç«¯API** - 用户管ç†API - 项目管ç†API - é…é¢åˆ†é…API - 审计日志API(åˆè§„) ### Step 3: å‰ç«¯å¼€å? 1. **公共组件** - TenantLayout(å“牌定制布局ï¼? - QuotaAllocator(é…é¢åˆ†é…器ï¼? - AuditLogViewer(审计日志查看器ï¼? 2. **医院端页é?* - ç”¨æˆ·ç®¡ç† - 科室管ç†ï¼ˆDepartmentTreeï¼? - é…é¢åˆ†é… 3. **è¯ä¼ç«¯é¡µé?* - ç”¨æˆ·ç®¡ç† - é¡¹ç›®ç®¡ç† - é…é¢åˆ†é… --- ## 📚 核心文档导航 ### 当å‰å¯é˜…è¯? 1. **整体架构** `../ADMIN-è¿è¥ç®¡ç†ç«?00-系统设计/00-æƒé™ä¸Žè§’è‰²ä½“ç³»æ¢³ç†æŠ¥å‘Š_v1.0.md` 2. **éœ€æ±‚æ–‡æ¡£ï¼ˆåŒ…å«æœºæž„端)** `../ADMIN-è¿è¥ç®¡ç†ç«?01-需求分æž?02-通用能力层_07-è¿è¥ä¸Žæœºæž„管ç†ç«¯PRD_v2.1.md` 3. **è¿è¥ç«¯çжæ€?* `../ADMIN-è¿è¥ç®¡ç†ç«?00-模å—当å‰çжæ€ä¸Žå¼€å‘指å?md` ### 待创建文æ¡? **00-系统设计/** - [ ] `01-机构管ç†ç«¯æž¶æž„设è®?md` - [ ] `02-多租户隔离设è®?md` - [ ] `03-é…é¢ç®¡ç†è®¾è®¡.md` **01-需求分æž?** - [ ] `01-医院管ç†ç«¯PRD.md` - [ ] `02-è¯ä¼ç®¡ç†ç«¯PRD.md` - [ ] `03-用户故事与验收标å‡?md` **02-技术设è®?** - [ ] `01-API设计文档.md` - [ ] `02-æ•°æ®åº“设计文æ¡?md` - [ ] `03-科室树实现方æ¡?md` - [ ] `04-é…é¢è®¡ç®—算法.md` **03-UI设计/** - [ ] `01-医院端原型设è®?html` - [ ] `02-è¯ä¼ç«¯åŽŸåž‹è®¾è®?html` - [ ] `03-å“牌定制指å—.md` --- ## âš ï¸ æŠ€æœ¯è¦ç‚? ### 1. 多租户隔ç¦? ```typescript // 中间件:确ä¿åªèƒ½è®¿é—®è‡ªå·±ç§Ÿæˆ·çš„æ•°æ? export const requireTenantAccess = async (request: FastifyRequest) => { const { tenantId } = request.user; const { id } = request.params; const resource = await prisma.resource.findUnique({ where: { id } }); if (resource.tenantId !== tenantId) { throw new ForbiddenError('æ— æƒè®¿é—®å…¶ä»–租户资æº'); } }; ``` ### 2. 科室æƒé™æ£€æŸ? ```typescript // 科室管ç†å‘˜åªèƒ½ç®¡ç†è‡ªå·±ç§‘å®? export const requireDepartmentAccess = async (request: FastifyRequest) => { const { role, departmentId } = request.user; const { deptId } = request.params; if (role === 'DEPARTMENT_ADMIN' && departmentId !== deptId) { throw new ForbiddenError('æ— æƒè®¿é—®å…¶ä»–科室'); } }; ``` ### 3. é…é¢è®¡ç®— ```typescript // 计算å¯åˆ†é…é…é¢? export const calculateAvailableQuota = async (tenantId: string) => { // 1. 获å–租户总é…é¢? const tenantQuota = await getTenantQuota(tenantId); // 2. 计算已分é…é…é¢? const allocated = await prisma.tenantQuotaAllocation.aggregate({ where: { tenantId }, _sum: { limitAmount: true } }); // 3. 返回å¯ç”¨é…é¢ return tenantQuota.totalAmount - (allocated._sum.limitAmount || 0); }; ``` --- ## 🔠与è¿è¥ç®¡ç†ç«¯çš„对æ¯? | 特æ€?| è¿è¥ç®¡ç†ç«¯ï¼ˆADMINï¼?| 机构管ç†ç«¯ï¼ˆINSTï¼?| |------|-------------------|------------------| | **用户** | å…¬å¸å†…部è¿è¥äººå‘˜ | 医院/è¯ä¼ç®¡ç†å‘?| | **æƒé™** | å…¨å±€ç®¡ç†æƒé™ | ç§Ÿæˆ·çº§ç®¡ç†æƒé™?| | **租户管ç†** | âœ?创建/ç®¡ç†æ‰€æœ‰ç§Ÿæˆ?| â?åªèƒ½çœ‹åˆ°è‡ªå·±ç§Ÿæˆ· | | **用户管ç†** | âœ?å…¨å±€ç”¨æˆ·ç®¡ç† | âœ?租户内用户管ç?| | **é…é¢ç®¡ç†** | âœ?分é…租户总é…é¢?| âœ?分é…科室/项目é…é¢ | | **Prompt管ç†** | âœ?生产环境调试 | â?æ— æƒé™?| | **审计日志** | âœ?全局日志 | âœ?租户内日å¿?| | **å“牌定制** | âœ?é…置所有租户å“ç‰?| â?åªèƒ½æŸ¥çœ‹ | --- ## 📅 é¢„è®¡å¼€å‘æ—¶é—? **剿ï¼?* è¿è¥ç®¡ç†ç«¯åŸºç¡€æž¶æž„完æˆï¼ˆWeek 4ï¼? - **Week 5-6ï¼?* 医院管ç†ç«¯ï¼ˆ8人天ï¼? - **Week 7-8ï¼?* è¯ä¼ç®¡ç†ç«¯ï¼ˆ8人天ï¼? - **Week 9ï¼?* 测试与优化(3人天ï¼? **总计ï¼?* çº?9人天(~4周) --- ## 📞 需è¦å¸®åŠ©ï¼Ÿ 1. **架构问题**:å‚考è¿è¥ç®¡ç†ç«¯å®žçް 2. **æƒé™é—®é¢˜**:查看`00-æƒé™ä¸Žè§’è‰²ä½“ç³»æ¢³ç†æŠ¥å‘Š_v1.0.md` 3. **UI问题**:å‚考DC/ASL等已有模å? --- ## 🎯 下一步行åŠ? - [ ] 等待è¿è¥ç®¡ç†ç«¯å®ŒæˆåŸºç¡€æž¶æž„ - [ ] 开始编写详细PRD - [ ] 设计UI原型 - [ ] 设计APIæŽ¥å£ --- *机构管ç†ç«¯è™½ç„¶å°šæœªå¼€å§‹å¼€å‘,但设计æ€è·¯å·²æ˜Žç¡®ã€‚å¾…è¿è¥ç®¡ç†ç«¯å®ŒæˆåŽï¼Œå¯å¿«é€Ÿå¯åЍ开å‘ã€? --- **🚀 敬请期待ï¼?*