# 医院物业SaaS管理后台 — 项目技术要求 > 版本:v1.1 > 定位:内部团队开发标准,所有开发人员必须严格按照此标准执行 > 日期:2026-04-16 --- ## 一、技术栈选型与版本要求 ### 1.1 后端技术栈 | 技术 | 版本要求 | 用途 | |------|----------|------| | Java | 17+ | 开发语言 | | Spring Boot | 3.x | 应用框架 | | MariaDB | 10.6+ | 主数据库(主从复制读写分离) | | Redis | 7.x | 缓存(权限/字典/菜单)、分布式锁 | | MyBatis-Plus | 3.5+ | ORM框架 | | Spring Security | 6.x | 认证与授权 | | JWT (jjwt) | 0.12+ | Token生成与校验 | | 腾讯云COS SDK | 最新稳定版 | 文件存储 | | ShedLock | 5.x+ | 分布式定时任务锁 | ### 1.2 前端Web技术栈 | 技术 | 版本要求 | 用途 | |------|----------|------| | Vue | 3.x | 前端框架 | | TypeScript | 5.x | 类型安全 | | Vite | 5.x | 构建工具 | | Pinia | 2.x | 状态管理 | | Vue Router | 4.x | 路由管理 | | Element Plus | 最新稳定版 | UI组件库 | | Axios | 1.x | HTTP客户端 | | ECharts | 5.x | 图表可视化 | ### 1.3 微信小程序技术栈 | 技术 | 版本要求 | 用途 | |------|----------|------| | uni-app | 3.x | 跨端框架(Vue 3模式) | | uni-ui | 最新稳定版 | UI组件库 | | uni-ble | 兼容最新版 | 蓝牙低功耗(BLE)插件 | ### 1.4 基础设施 | 技术 | 用途 | |------|------| | Docker + Docker Compose | 私有云容器化部署 | | Nginx | 反向代理 + 静态资源 | | Jenkins / GitLab CI | CI/CD流水线 | | Git | 版本管理 | --- ## 二、架构设计要求 ### 2.1 整体架构 ``` ┌─────────────────────────────────────────────────┐ │ 客户端层 │ │ Vue3 Web管理后台 │ uni-app微信小程序 │ └───────────┬───────────┴───────────┬──────────────┘ │ HTTPS │ ┌───────────▼───────────────────────▼──────────────┐ │ 网关层 │ │ Nginx 反向代理 │ └───────────┬──────────────────────────────────────┘ │ ┌───────────▼──────────────────────────────────────┐ │ 应用层 │ │ Spring Boot 单体应用(模块化 IModulePlugin) │ │ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │ │ │报修 │ │巡检 │ │保洁 │ │考勤 │ │合同 │... │ │ └──┬───┘ └──┬───┘ └──┬───┘ └──┬───┘ └──┬───┘ │ │ └────────┴────────┴────────┴────────┘ │ │ Spring Event 模块间通信 │ └───────────┬──────────────────────────────────────┘ │ ┌───────────▼──────────────────────────────────────┐ │ 数据层 │ │ MariaDB主库 ──复制──▶ MariaDB从库(读写分离) │ │ Redis 缓存(权限/字典/菜单) │ │ 腾讯云COS(照片/附件/合同文件) │ └──────────────────────────────────────────────────┘ ``` ### 2.2 多租户方案 - **隔离方式**:共享数据库 + 行级隔离(`tenant_id`字段) - **实现方式**:MyBatis-Plus `TenantLineInnerInterceptor` 自动注入 `tenant_id` 条件 - **租户识别**:从JWT Token中提取 `tenant_id`,无需前端传递 - **超管例外**:超级管理员操作不受租户隔离限制 ### 2.3 模块化架构 - **核心接口**:`IModulePlugin`(详见 `05-接口规范.md`) - **模块注册**:系统启动时自动扫描并注册所有 `IModulePlugin` 实现类 - **模块通信**:Spring `ApplicationEvent` + `ApplicationEventPublisher` - **模块隔离**:各模块独立目录结构,禁止跨模块直接调用Service,必须通过Event解耦 - **租户级控制**:支持按租户启用/禁用特定模块(`sys_tenant_module` 表) ### 2.4 前后端分离 - Web端与后端通过RESTful API通信 - 小程序端与后端通过同一套API通信 - 前端路由由后端权限接口动态驱动 - 统一JWT认证,Web端存localStorage,小程序端存本地Storage ### 2.5 读写分离方案 - **实现方式**:MariaDB主从复制 + MyBatis-Plus动态数据源切换 - **路由规则**: - 写操作(INSERT/UPDATE/DELETE)→ 主库 - 读操作(SELECT)→ 从库 - **注解标记**:自定义 `@ReadOnly` 注解标记读操作,AOP切面切换数据源 - **容错机制**:从库不可用时自动降级到主库读取,超时阈值3秒 - **配置要求**:在 `application.yml` 中分别配置 `spring.datasource.master` 和 `spring.datasource.slave` 两套数据源连接地址 --- ## 三、去中间件方案 **不引入RocketMQ/Kafka等消息中间件**,采用以下Spring Boot内置机制替代: ### 3.1 权限变更实时通知 - **替代方案**:Redis Pub/Sub + Spring Event - **实现细节**: 1. 权限变更时,通过 Redis Pub/Sub 发布变更消息 `PUBLISH permission:changed ` 2. 各服务实例订阅 `permission:changed` 频道,收到消息后触发 Spring Event 3. 监听器刷新本地权限缓存 - **优势**:毫秒级延迟,零数据库压力,复用已有 Redis 实例 - **降级策略**:Redis 连接断开时,权限缓存 TTL(2小时)到期后自动刷新 - **实现要点**: 1. 权限变更时通过 `StringRedisTemplate.convertAndSend()` 发布消息到 `permission:changed` 频道 2. 各实例 `MessageListener` 订阅该频道,收到消息后发布 Spring Event 3. `@EventListener` 监听事件并刷新本地权限缓存 ### 3.2 异步任务处理 - **替代方案**:Spring `@Async` + 自定义线程池 - **线程池配置要求**: - 核心线程数:CPU核心数(默认4) - 最大线程数:CPU核心数×2(默认8) - 队列容量:1000 - 线程空闲时间:60秒 - 拒绝策略:CallerRunsPolicy(调用者线程执行) - **适用场景**:报表导出、消息推送、日志异步写入、图片处理 - **持久化保障**:关键任务必须先落库再异步执行,避免线程池丢失任务 ### 3.3 模块间事件通信 - **替代方案**:Spring `ApplicationEvent` + `ApplicationEventPublisher` - **进程内通信**:直接使用Spring Event,事件定义在共享API模块中 - **跨实例通信**:Redis Pub/Sub 广播事件(与权限通知同一机制) - **预定义事件**: | 事件类型 | 来源模块 | 消费方 | |----------|----------|--------| | ORDER_COMPLETED | repair | evaluation(触发评价) | | INSPECTION_ABNORMAL | inspection | repair(生成报修) | | CLEANING_TIMEOUT | cleaning | notification(推送预警) | | BEACON_OFFLINE | device | notification(推送预警) | | PERMISSION_CHANGED | permission | 各模块(刷新缓存) | ### 3.4 定时任务 - **替代方案**:Spring `@Scheduled` + 数据库分布式锁 - **分布式锁实现**:ShedLock 或数据库行锁(`SELECT ... FOR UPDATE`) - **适用场景**:巡检任务自动生成、保洁超时预警、合同到期提醒、Beacon心跳检测 - **实现要点**:定时方法加 `@Scheduled` 注解声明cron表达式,配合 `@ShedLock` 注解声明锁名称、最少/最多持有时间,确保多实例部署时同一时刻仅一个实例执行 --- ## 四、安全要求 ### 4.1 认证方案 | 场景 | 认证方式 | Token管理 | |------|----------|-----------| | Web端登录 | 用户名+密码 → JWT | localStorage存储,2小时过期 | | 小程序登录 | 微信openid静默登录 → JWT | 本地Storage存储,2小时过期 | | 小程序首次使用 | 微信授权openid + 手机号绑定 | 自动创建账号 | **JWT载荷标准字段**: | 字段 | 说明 | |------|------| | sub | 用户ID | | tid | 租户ID | | utype | 用户类型 | | hid | 医院ID | | pid | 物业公司ID | | sid | 员工ID | | iat | 签发时间 | | exp | 过期时间 | ### 4.2 四级权限体系 权限按 **功能菜单 → 页面 → 功能点 → 动作** 四级树形结构划分: - **7种动作类型**:查看(view)、新增(create)、编辑(update)、删除(delete)、审批(approve)、导出(export)、分配(assign) - **权限编码规范**:`{module}:{page}:{action}`,如 `repair:list:create` - **自动同步**:新模块通过 `IModulePlugin.getPermissionDefinitions()` 自动注册到权限配置表 - **实时生效**:权限变更后毫秒级生效(Redis Pub/Sub),无需重新登录 ### 4.3 数据权限(行级隔离) | 角色 | 数据范围 | 实现方式 | |------|----------|----------| | 超级管理员 | 全局所有数据 | 不注入tenant_id条件 | | 医院账号 | 本医院+关联物业公司数据 | 注入hospital_id条件,只读 | | 物业公司管理员 | 绑定医院数据 | 注入tenant_id + hospital_id条件 | | 主管 | 本班组数据 | 注入team_id条件 | | 员工 | 仅本人数据 | 注入staff_id条件 | **实现方式**:MyBatis-Plus拦截器自动注入SQL条件,禁止手动拼接数据权限条件。 ### 4.4 蓝牙策略配置 蓝牙打卡/巡检/拍照是否强制要求连接,由物业公司配置、医院账号审核: - **配置方**:物业公司管理员 - **审核方**:医院账号 - **配置项**:各场景是否强制蓝牙连接 | 场景 | 配置项 | 强制蓝牙时的行为 | 非强制蓝牙时的行为 | |------|--------|-----------------|-------------------| | 巡检打卡 | `inspection_check_in` | 必须连接Beacon打卡,失败进补录 | 可手动打卡(check_type=MANUAL) | | 巡检拍照 | `inspection_photo` | 必须在蓝牙连接下拍照 | 可自由拍照 | | 保洁打卡 | `cleaning_check_in` | 必须连接Beacon打卡,失败进补录 | 可手动打卡(check_type=MANUAL) | | 保洁拍照 | `cleaning_photo` | 必须在蓝牙连接下拍照 | 可自由拍照 | | 考勤打卡 | `attendance_check` | 必须连接Beacon打卡,失败提交异常申诉 | 可手动打卡(check_type=MANUAL) | - **数据标记**:所有打卡记录区分 `check_type`(BLUETOOTH/MANUAL),后台列表和统计报表明确显示 - **降级逻辑**: - 非强制蓝牙场景:蓝牙失败可直接手动打卡 - 强制蓝牙场景:蓝牙失败进入补录模式,需主管审核 - **审核流程**:物业公司提交配置 → 医院账号审核通过后生效 → 审核拒绝则维持原配置 ### 4.5 审计日志 - **记录范围**:所有写操作(CREATE/UPDATE/DELETE/APPROVE/ASSIGN/EXPORT)自动记录 - **实现方式**:AOP切面统一处理,业务代码无感知 - **记录内容**:操作人、时间、IP、模块、操作类型、变更前后数据快照 - **权限变更日志**:单独记录,展示变更前后权限对比 - **数据补录日志**:单独记录,标记补录原因和审核状态 - **日志保留**:至少保留1年,支持导出 ### 4.6 通用安全要求 | 安全项 | 要求 | |--------|------| | SQL注入防护 | 必须使用MyBatis-Plus参数化查询,禁止拼接SQL | | XSS防护 | 所有用户输入必须HTML转义后存储,前端渲染使用v-text而非v-html | | 密码存储 | BCrypt加密,禁止明文存储 | | 敏感数据 | 手机号脱敏显示(138****1234),身份证号如需存储需AES加密 | | 接口鉴权 | 所有API必须声明权限要求(除公开接口外) | | 跨域控制 | Nginx配置白名单域名,禁止 `Access-Control-Allow-Origin: *` | | 请求限流 | Redis令牌桶限流,API默认100次/分钟/用户 | --- ## 五、性能要求 ### 5.1 响应时间基线 | 指标 | 要求 | 测量方式 | |------|------|----------| | API平均响应时间 | < 300ms | 服务端P50 | | API P99响应时间 | < 500ms | 服务端P99 | | 列表查询(含分页) | < 500ms | 端到端 | | 报表生成(单月数据) | < 5s | 端到端 | | 蓝牙扫描超时 | 3秒 | 客户端 | | 蓝牙连接建立 | < 3秒 | 客户端 | ### 5.2 并发与容量 - 单实例支持100 QPS - 支持水平扩展(无状态设计,Session存Redis) - 数据库连接池:HikariCP,最大连接数 = CPU核心数 * 2 + 1 - Redis连接池:Lettuce,最大连接数 = CPU核心数 * 2 ### 5.3 缓存策略 | 缓存对象 | 过期策略 | 刷新机制 | |----------|----------|----------| | 用户权限集 | 2小时TTL | 权限变更时实时刷新(毫秒级,Redis Pub/Sub) | | 字典数据 | 24小时TTL | 字典变更时手动/自动刷新 | | 菜单配置 | 24小时TTL | 菜单变更时手动/自动刷新 | | 业务数据 | 按需懒加载 | 不缓存,实时查询 | ### 5.4 蓝牙交互可靠性 | 指标 | 要求 | |------|------| | 连接判定 | **不判断距离,只要成功连接蓝牙设备即可打卡** | | 信号阈值 | RSSI > -70dBm(可配置,仅用于判定是否能建立连接) | | 扫描超时 | 3秒 | | 重试次数 | 3次 | | 补录降级 | 蓝牙失败后必须提供补录/手动打卡入口 | | 心跳检测 | Beacon每5分钟上报心跳,超15分钟标记OFFLINE | --- ## 六、数据库备份与恢复 ### 6.1 备份策略 | 备份类型 | 频率 | 工具 | 保留时间 | |----------|------|------|----------| | 全量备份 | 每日凌晨2:00 | mysqldump --single-transaction | 30天 | | 增量备份 | 每4小时 | MariaDB binlog | 7天 | | 异地备份 | 每日 | rsync/scp到备份服务器 | 30天 | ### 6.2 备份存储 - **主存储**:私有云本地磁盘(独立磁盘,与数据盘分离) - **异地存储**:异地备份服务器(不同机房或不同物理机) - **备份文件命名**:`hospital_mgmt_full_YYYYMMDD_HHmmss.sql.gz`、`hospital_mgmt_incr_YYYYMMDD_HHmmss.binlog.gz` ### 6.3 恢复方案 | 指标 | 要求 | |------|------| | RTO(恢复时间目标) | < 2小时 | | RPO(恢复点目标) | < 4小时(增量备份间隔) | | 恢复方式 | 全量恢复 + binlog重放 | | 恢复流程 | 1. 停止应用 → 2. 恢复最近全量备份 → 3. 重放binlog到故障时间点 → 4. 验证数据完整性 → 5. 启动应用 | ### 6.4 恢复演练 - **频率**:每季度一次 - **内容**:在测试环境执行完整恢复流程,验证RTO和RPO - **记录**:演练结果记录文档,问题纳入改进计划 - **责任人**:DBA + 运维 ### 6.5 备份脚本要求 - 全量备份使用 `mysqldump --single-transaction` 导出并gzip压缩 - 备份文件命名格式:`hospital_mgmt_full_YYYYMMDD_HHmmss.sql.gz`(增量:`hospital_mgmt_incr_YYYYMMDD_HHmmss.binlog.gz`) - 自动清理30天前的全量备份文件 - 备份完成后通过 rsync 同步到异地备份服务器 --- ## 七、开发与测试规范 > 开发规范、测试规范已独立为 `04-开发与测试规范.md`,本章仅保留引用。 - **后端开发规范**(代码分层、命名、数据库、模块开发、审计日志)→ 详见 `04-开发与测试规范.md` 第一章 - **前端开发规范**(Vue3组件、TypeScript、状态管理、API调用)→ 详见 `04-开发与测试规范.md` 第二章 - **小程序开发规范**(目录、蓝牙、图片上传)→ 详见 `04-开发与测试规范.md` 第三章 - **Git分支与提交规范** → 详见 `04-开发与测试规范.md` 第四章 - **前后端协作规范** → 详见 `04-开发与测试规范.md` 第五章 - **代码审查要求** → 详见 `04-开发与测试规范.md` 第六章 - **测试规范**(单元测试、集成测试、蓝牙测试、性能测试、安全测试)→ 详见 `04-开发与测试规范.md` 第七章 --- ## 八、部署与运维要求 ### 8.1 部署架构(私有云) ``` ┌──────────────────────────────────────────┐ │ 私有云服务器 │ │ │ │ ┌─────────────┐ ┌─────────────────┐ │ │ │ Nginx │ │ Docker Compose │ │ │ │ 反向代理 │──│ ┌────────────┐ │ │ │ │ 静态资源 │ │ │ Spring Boot│ │ │ │ └─────────────┘ │ │ 应用容器 │ │ │ │ │ └────────────┘ │ │ │ │ ┌────────────┐ │ │ │ │ │ Redis │ │ │ │ │ │ 缓存容器 │ │ │ │ │ └────────────┘ │ │ │ └─────────────────┘ │ │ │ │ ┌─────────────┐ ┌─────────────────┐ │ │ │ MariaDB主库 │ │ MariaDB从库 │ │ │ │ 写操作 │──│ 读操作 │ │ │ └─────────────┘ └─────────────────┘ │ └──────────────────────────────────────────┘ ``` ### 8.2 Docker Compose部署要求 部署包含以下服务容器: | 服务 | 镜像 | 说明 | |------|------|------| | app | hospital-mgmt:latest | Spring Boot应用,端口8080,依赖Redis和MariaDB主库 | | redis | redis:7-alpine | 缓存服务,持久化存储 | | mariadb-master | mariadb:10.6 | 主库(写),持久化存储 | | mariadb-slave | mariadb:10.6 | 从库(读),依赖主库,持久化存储 | | nginx | nginx:alpine | 反向代理+静态资源,端口80/443,挂载自定义nginx.conf和前端dist目录 | - **环境变量注入**:通过 `SPRING_PROFILES_ACTIVE`、`SPRING_DATASOURCE_URL`、`SPRING_DATASOURCE_SLAVE_URL`、`SPRING_REDIS_HOST` 等环境变量配置连接信息,禁止硬编码 ### 8.3 小程序版本更新策略 ``` 小程序启动 │ 调用 GET /system/versions/latest 获取最新版本号 │ 与本地版本号比较 │ ├── 版本一致 ──▶ 正常使用 │ ├── 小版本更新(兼容) ──▶ 提示"发现新版本,是否更新?" │ └── 大版本更新(不兼容) ──▶ 强制更新,引导前往微信更新 ``` ### 8.4 缓存管理策略 | 触发方式 | 清理范围 | 说明 | |----------|----------|------| | 系统启动 | 全部缓存 | 启动时自动清理 | | 权限变更 | 权限缓存 | 变更后毫秒级自动刷新(Redis Pub/Sub) | | 手动清理 | 指定模块缓存 | 超管在"缓存管理"页面操作 | | 系统更新 | 全部缓存 | 部署新版本后自动清理 | ### 8.5 监控与告警 | 监控项 | 告警条件 | 通知方式 | |--------|----------|----------| | 应用健康 | 健康检查失败 | 邮件+企业微信 | | 数据库连接 | 连接池使用率>80% | 企业微信 | | Redis连接 | 连接池使用率>80% | 企业微信 | | Beacon离线 | 离线超过15分钟 | 系统内通知 | | Beacon低电量 | 电量<20% | 系统内通知 | | 磁盘空间 | 使用率>85% | 邮件+企业微信 | | 备份失败 | 备份任务失败 | 邮件 | --- ## 九、接口规范 > 接口规范已独立为 `05-接口规范.md`,本章仅保留引用。 - **全局约定**(请求头、统一响应格式、错误码、查询参数)→ 详见 `05-接口规范.md` 第一章 - **认证规范**(认证方式、JWT载荷、权限编码)→ 详见 `05-接口规范.md` 第二章 - **文件上传规范** → 详见 `05-接口规范.md` 第三章 - **模块化架构规范**(IModulePlugin、模块注册、事件通信、版本升级、安全规范)→ 详见 `05-接口规范.md` 第四~八章 - **接口权限汇总** → 详见 `05-接口规范.md` 第九章 --- ## 十、环境配置管理 ### 10.1 环境划分 | 环境 | 用途 | 数据库 | 配置文件 | |------|------|--------|----------| | dev | 本地开发 | 本地MariaDB | application-dev.yml | | test | 集成测试 | 测试MariaDB | application-test.yml | | staging | 预发布 | 预发布MariaDB | application-staging.yml | | prod | 生产 | 生产MariaDB主从 | application-prod.yml | ### 10.2 敏感配置管理 - 数据库密码、Redis密码、JWT密钥、腾讯云SecretKey等 **禁止硬编码** - 使用环境变量注入:`SPRING_DATASOURCE_PASSWORD`, `JWT_SECRET`, `COS_SECRET_KEY` - 生产环境密码定期轮换(每季度) ### 10.3 配置项清单 | 配置项 | 说明 | 默认值 | |--------|------|--------| | `jwt.expiration` | Token过期时间(秒) | 7200 | | `jwt.refresh-expiration` | Refresh Token过期时间(秒) | 604800 | | `bluetooth.rssi-threshold` | 蓝牙信号阈值(dBm) | -70 | | `bluetooth.distance-threshold` | ~~已废弃~~ 蓝牙不判断距离,连接即打卡 | — | | `bluetooth.scan-timeout` | 蓝牙扫描超时(秒) | 3 | | `permission.redis-channel` | 权限变更Redis频道名 | permission:changed | | `async.pool.core-size` | 异步线程池核心线程数 | CPU核心数 | | `async.pool.max-size` | 异步线程池最大线程数 | CPU核心数*2 | | `upload.max-size` | 文件上传大小限制(MB) | 20 | | `cos.bucket-name` | 腾讯云COS存储桶名称 | — | | `backup.full-cron` | 全量备份cron | 0 2 * * ? | | `backup.incr-interval-hours` | 增量备份间隔(小时) | 4 | --- > **本文档为内部开发标准,所有开发人员必须严格按照此标准执行。如有疑问或需要调整,需经技术负责人审批。**