From da8b02b49289afd6c168deeba95645287667015e Mon Sep 17 00:00:00 2001 From: jiang <821644@qq.com> Date: Fri, 17 Apr 2026 00:12:23 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=8C=BB=E9=99=A2=E5=90=8E=E5=8B=A4?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E7=B3=BB=E7=BB=9F=E5=88=9D=E5=A7=8B=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=20-=20=E5=90=8E=E7=AB=AF=E4=BB=A3=E7=A0=81=20+=20?= =?UTF-8?q?=E5=AE=8C=E6=95=B4=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../docs-merge-refactor_eca19d14(未完成).md | 93 +++ .codebuddy/plans/docs-merge-v2_5f294389.md | 162 ++++ .../医院物业SaaS管理后台-概要设计_c528df96.md | 339 ++++++++ .../测试要求增强与权限方案优化_06fa523e.md | 91 ++ .../移除Docker相关文件和文档描述_8a12f801.md | 62 ++ .../plans/详细功能说明文档编写_92e2a4d9.md | 148 ++++ .codebuddy/plans/项目技术要求文档_29ab44d0.md | 158 ++++ .editorconfig | 30 + .env.example | 18 + .gitignore | 35 + README.md | 195 +++++ backend/pom.xml | 216 +++++ .../mgmt/HospitalMgmtApplication.java | 14 + .../mgmt/common/annotation/AuditLog.java | 13 + .../mgmt/common/annotation/ReadOnly.java | 9 + .../hospital/mgmt/common/base/BaseEntity.java | 33 + .../mgmt/common/context/TenantContext.java | 46 + .../common/exception/BusinessException.java | 23 + .../mgmt/common/exception/ErrorCode.java | 26 + .../exception/GlobalExceptionHandler.java | 70 ++ .../mgmt/common/result/ApiResult.java | 37 + .../mgmt/common/result/PageResult.java | 15 + .../mgmt/common/result/Pagination.java | 19 + .../com/hospital/mgmt/config/AsyncConfig.java | 25 + .../mgmt/config/MyBatisPlusConfig.java | 44 + .../com/hospital/mgmt/config/RedisConfig.java | 23 + .../hospital/mgmt/config/ShedLockConfig.java | 25 + .../hospital/mgmt/config/WebMvcConfig.java | 19 + .../entity/AttendanceCheckPoint.java | 19 + .../attendance/entity/AttendanceRecord.java | 32 + .../attendance/entity/AttendanceRule.java | 22 + .../mapper/AttendanceRecordMapper.java | 8 + .../mgmt/modules/audit/entity/AuditLog.java | 32 + .../modules/audit/mapper/AuditLogMapper.java | 8 + .../auth/controller/AuthController.java | 39 + .../mgmt/modules/auth/dto/LoginRequest.java | 13 + .../mgmt/modules/auth/dto/LoginResponse.java | 28 + .../modules/auth/dto/RefreshTokenRequest.java | 10 + .../modules/auth/service/AuthService.java | 97 +++ .../modules/bidding/entity/BiddingPlan.java | 24 + .../bidding/entity/BiddingSection.java | 21 + .../bidding/entity/BiddingSupplier.java | 20 + .../cleaning/entity/CleaningAttachment.java | 21 + .../cleaning/entity/CleaningSchedule.java | 18 + .../modules/cleaning/entity/CleaningTask.java | 35 + .../cleaning/mapper/CleaningTaskMapper.java | 8 + .../modules/contract/entity/Contract.java | 30 + .../contract/entity/ContractChange.java | 23 + .../contract/entity/ContractPayment.java | 22 + .../contract/mapper/ContractMapper.java | 8 + .../modules/device/entity/DeviceBeacon.java | 32 + .../device/mapper/DeviceBeaconMapper.java | 8 + .../modules/evaluation/entity/Evaluation.java | 26 + .../evaluation/entity/EvaluationConfig.java | 18 + .../inspection/entity/InspectionAbnormal.java | 19 + .../inspection/entity/InspectionArea.java | 20 + .../entity/InspectionAttachment.java | 22 + .../inspection/entity/InspectionPlan.java | 25 + .../inspection/entity/InspectionTask.java | 35 + .../mapper/InspectionTaskMapper.java | 8 + .../mgmt/modules/org/entity/CleaningArea.java | 22 + .../mgmt/modules/org/entity/Hospital.java | 18 + .../modules/org/entity/HospitalCampus.java | 17 + .../modules/org/entity/PropertyCompany.java | 21 + .../modules/org/entity/PropertyHospital.java | 19 + .../mgmt/modules/org/entity/Staff.java | 19 + .../mgmt/modules/org/entity/StaffTeam.java | 17 + .../mgmt/modules/org/entity/Team.java | 20 + .../org/mapper/HospitalCampusMapper.java | 8 + .../modules/org/mapper/HospitalMapper.java | 8 + .../org/mapper/PropertyCompanyMapper.java | 8 + .../mgmt/modules/org/mapper/StaffMapper.java | 8 + .../mgmt/modules/org/mapper/TeamMapper.java | 8 + .../permission/entity/PermissionConfig.java | 24 + .../mgmt/modules/permission/entity/Role.java | 19 + .../permission/entity/RolePermission.java | 13 + .../mgmt/modules/permission/entity/User.java | 28 + .../entity/UserPermissionOverride.java | 14 + .../modules/permission/entity/UserRole.java | 13 + .../mapper/PermissionConfigMapper.java | 8 + .../modules/permission/mapper/RoleMapper.java | 8 + .../modules/permission/mapper/UserMapper.java | 8 + .../mgmt/modules/plugin/ConfigDefinition.java | 30 + .../mgmt/modules/plugin/IModulePlugin.java | 33 + .../mgmt/modules/plugin/MenuDefinition.java | 20 + .../mgmt/modules/plugin/ModuleContext.java | 7 + .../mgmt/modules/plugin/ModuleInfo.java | 26 + .../modules/plugin/PermissionDefinition.java | 46 + .../mgmt/modules/plugin/RouteDefinition.java | 28 + .../mgmt/modules/plugin/TableDefinition.java | 35 + .../plugin/event/PermissionChangedEvent.java | 15 + .../listener/PermissionChangeListener.java | 50 ++ .../repair/entity/RepairDelayApply.java | 21 + .../modules/repair/entity/RepairOrder.java | 40 + .../repair/entity/RepairOrderAttachment.java | 22 + .../modules/repair/entity/RepairOrderLog.java | 21 + .../modules/repair/entity/RepairType.java | 19 + .../repair/mapper/RepairOrderMapper.java | 8 + .../system/entity/BluetoothPolicy.java | 25 + .../mgmt/modules/system/entity/DictData.java | 17 + .../mgmt/modules/system/entity/DictType.java | 15 + .../system/entity/MessageTemplate.java | 19 + .../modules/system/entity/TenantModule.java | 17 + .../mgmt/modules/system/entity/Version.java | 20 + .../system/mapper/BluetoothPolicyMapper.java | 8 + .../modules/system/mapper/DictTypeMapper.java | 8 + .../security/JwtAuthenticationFilter.java | 81 ++ .../mgmt/security/JwtTokenProvider.java | 81 ++ .../security/RestAccessDeniedHandler.java | 31 + .../RestAuthenticationEntryPoint.java | 31 + .../mgmt/security/SecurityConfig.java | 57 ++ .../hospital/mgmt/security/TenantHandler.java | 45 + .../src/main/resources/application-prod.yml | 76 ++ backend/src/main/resources/application.yml | 79 ++ backend/src/main/resources/db/init.sql | 790 ++++++++++++++++++ .../src/test/resources/application-test.yml | 20 + docs/01-模块划分.md | 523 ++++++++++++ docs/02-功能清单-医院.md | 80 ++ docs/02-功能清单-医院/01-合同管理.md | 298 +++++++ docs/02-功能清单-医院/02-分段招标管理.md | 310 +++++++ docs/02-功能清单-医院/03-服务监督.md | 172 ++++ docs/02-功能清单-医院/04-服务评价.md | 192 +++++ docs/02-功能清单-医院/05-统计报表.md | 219 +++++ docs/02-功能清单-小程序端.md | 155 ++++ docs/02-功能清单-小程序端/01-通用功能.md | 239 ++++++ docs/02-功能清单-小程序端/02-报修相关功能.md | 339 ++++++++ docs/02-功能清单-小程序端/03-巡检相关功能.md | 259 ++++++ docs/02-功能清单-小程序端/04-保洁相关功能.md | 297 +++++++ docs/02-功能清单-小程序端/05-考勤相关功能.md | 268 ++++++ .../06-组织架构相关功能.md | 102 +++ .../07-服务评价相关功能.md | 159 ++++ docs/02-功能清单-小程序端/08-统计概览功能.md | 108 +++ .../09-管理员小程序功能.md | 294 +++++++ docs/02-功能清单-物业公司.md | 133 +++ docs/02-功能清单-物业公司/01-在线报修.md | 392 +++++++++ docs/02-功能清单-物业公司/02-巡检管理.md | 382 +++++++++ docs/02-功能清单-物业公司/03-保洁管理.md | 354 ++++++++ docs/02-功能清单-物业公司/04-组织架构.md | 338 ++++++++ docs/02-功能清单-物业公司/05-考勤打卡.md | 279 +++++++ docs/02-功能清单-物业公司/06-服务评价.md | 221 +++++ docs/02-功能清单-物业公司/07-统计报表.md | 243 ++++++ docs/02-功能清单-物业公司/08-操作日志.md | 200 +++++ docs/02-功能清单-物业公司/09-系统配置.md | 304 +++++++ docs/02-功能清单-超级管理员.md | 56 ++ docs/02-功能清单-超级管理员/01-账号管理.md | 588 +++++++++++++ docs/02-功能清单-超级管理员/02-权限管理.md | 382 +++++++++ docs/02-功能清单-超级管理员/03-系统配置.md | 177 ++++ docs/02-功能清单-超级管理员/04-操作日志.md | 201 +++++ docs/03-业务流转逻辑-医院.md | 187 +++++ docs/03-业务流转逻辑-小程序端.md | 417 +++++++++ docs/03-业务流转逻辑-物业公司.md | 363 ++++++++ docs/03-业务流转逻辑-超级管理员.md | 268 ++++++ docs/04-开发与测试规范.md | 361 ++++++++ docs/05-接口规范.md | 611 ++++++++++++++ docs/06-项目技术要求.md | 492 +++++++++++ docs/Windows部署指南.md | 691 +++++++++++++++ 156 files changed, 16562 insertions(+) create mode 100644 .codebuddy/plans/docs-merge-refactor_eca19d14(未完成).md create mode 100644 .codebuddy/plans/docs-merge-v2_5f294389.md create mode 100644 .codebuddy/plans/医院物业SaaS管理后台-概要设计_c528df96.md create mode 100644 .codebuddy/plans/测试要求增强与权限方案优化_06fa523e.md create mode 100644 .codebuddy/plans/移除Docker相关文件和文档描述_8a12f801.md create mode 100644 .codebuddy/plans/详细功能说明文档编写_92e2a4d9.md create mode 100644 .codebuddy/plans/项目技术要求文档_29ab44d0.md create mode 100644 .editorconfig create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 README.md create mode 100644 backend/pom.xml create mode 100644 backend/src/main/java/com/hospital/mgmt/HospitalMgmtApplication.java create mode 100644 backend/src/main/java/com/hospital/mgmt/common/annotation/AuditLog.java create mode 100644 backend/src/main/java/com/hospital/mgmt/common/annotation/ReadOnly.java create mode 100644 backend/src/main/java/com/hospital/mgmt/common/base/BaseEntity.java create mode 100644 backend/src/main/java/com/hospital/mgmt/common/context/TenantContext.java create mode 100644 backend/src/main/java/com/hospital/mgmt/common/exception/BusinessException.java create mode 100644 backend/src/main/java/com/hospital/mgmt/common/exception/ErrorCode.java create mode 100644 backend/src/main/java/com/hospital/mgmt/common/exception/GlobalExceptionHandler.java create mode 100644 backend/src/main/java/com/hospital/mgmt/common/result/ApiResult.java create mode 100644 backend/src/main/java/com/hospital/mgmt/common/result/PageResult.java create mode 100644 backend/src/main/java/com/hospital/mgmt/common/result/Pagination.java create mode 100644 backend/src/main/java/com/hospital/mgmt/config/AsyncConfig.java create mode 100644 backend/src/main/java/com/hospital/mgmt/config/MyBatisPlusConfig.java create mode 100644 backend/src/main/java/com/hospital/mgmt/config/RedisConfig.java create mode 100644 backend/src/main/java/com/hospital/mgmt/config/ShedLockConfig.java create mode 100644 backend/src/main/java/com/hospital/mgmt/config/WebMvcConfig.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/attendance/entity/AttendanceCheckPoint.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/attendance/entity/AttendanceRecord.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/attendance/entity/AttendanceRule.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/attendance/mapper/AttendanceRecordMapper.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/audit/entity/AuditLog.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/audit/mapper/AuditLogMapper.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/auth/controller/AuthController.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/auth/dto/LoginRequest.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/auth/dto/LoginResponse.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/auth/dto/RefreshTokenRequest.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/auth/service/AuthService.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/bidding/entity/BiddingPlan.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/bidding/entity/BiddingSection.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/bidding/entity/BiddingSupplier.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/cleaning/entity/CleaningAttachment.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/cleaning/entity/CleaningSchedule.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/cleaning/entity/CleaningTask.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/cleaning/mapper/CleaningTaskMapper.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/contract/entity/Contract.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/contract/entity/ContractChange.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/contract/entity/ContractPayment.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/contract/mapper/ContractMapper.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/device/entity/DeviceBeacon.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/device/mapper/DeviceBeaconMapper.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/evaluation/entity/Evaluation.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/evaluation/entity/EvaluationConfig.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/inspection/entity/InspectionAbnormal.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/inspection/entity/InspectionArea.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/inspection/entity/InspectionAttachment.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/inspection/entity/InspectionPlan.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/inspection/entity/InspectionTask.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/inspection/mapper/InspectionTaskMapper.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/org/entity/CleaningArea.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/org/entity/Hospital.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/org/entity/HospitalCampus.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/org/entity/PropertyCompany.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/org/entity/PropertyHospital.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/org/entity/Staff.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/org/entity/StaffTeam.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/org/entity/Team.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/org/mapper/HospitalCampusMapper.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/org/mapper/HospitalMapper.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/org/mapper/PropertyCompanyMapper.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/org/mapper/StaffMapper.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/org/mapper/TeamMapper.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/permission/entity/PermissionConfig.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/permission/entity/Role.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/permission/entity/RolePermission.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/permission/entity/User.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/permission/entity/UserPermissionOverride.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/permission/entity/UserRole.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/permission/mapper/PermissionConfigMapper.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/permission/mapper/RoleMapper.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/permission/mapper/UserMapper.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/plugin/ConfigDefinition.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/plugin/IModulePlugin.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/plugin/MenuDefinition.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/plugin/ModuleContext.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/plugin/ModuleInfo.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/plugin/PermissionDefinition.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/plugin/RouteDefinition.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/plugin/TableDefinition.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/plugin/event/PermissionChangedEvent.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/plugin/listener/PermissionChangeListener.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/repair/entity/RepairDelayApply.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/repair/entity/RepairOrder.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/repair/entity/RepairOrderAttachment.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/repair/entity/RepairOrderLog.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/repair/entity/RepairType.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/repair/mapper/RepairOrderMapper.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/system/entity/BluetoothPolicy.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/system/entity/DictData.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/system/entity/DictType.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/system/entity/MessageTemplate.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/system/entity/TenantModule.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/system/entity/Version.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/system/mapper/BluetoothPolicyMapper.java create mode 100644 backend/src/main/java/com/hospital/mgmt/modules/system/mapper/DictTypeMapper.java create mode 100644 backend/src/main/java/com/hospital/mgmt/security/JwtAuthenticationFilter.java create mode 100644 backend/src/main/java/com/hospital/mgmt/security/JwtTokenProvider.java create mode 100644 backend/src/main/java/com/hospital/mgmt/security/RestAccessDeniedHandler.java create mode 100644 backend/src/main/java/com/hospital/mgmt/security/RestAuthenticationEntryPoint.java create mode 100644 backend/src/main/java/com/hospital/mgmt/security/SecurityConfig.java create mode 100644 backend/src/main/java/com/hospital/mgmt/security/TenantHandler.java create mode 100644 backend/src/main/resources/application-prod.yml create mode 100644 backend/src/main/resources/application.yml create mode 100644 backend/src/main/resources/db/init.sql create mode 100644 backend/src/test/resources/application-test.yml create mode 100644 docs/01-模块划分.md create mode 100644 docs/02-功能清单-医院.md create mode 100644 docs/02-功能清单-医院/01-合同管理.md create mode 100644 docs/02-功能清单-医院/02-分段招标管理.md create mode 100644 docs/02-功能清单-医院/03-服务监督.md create mode 100644 docs/02-功能清单-医院/04-服务评价.md create mode 100644 docs/02-功能清单-医院/05-统计报表.md create mode 100644 docs/02-功能清单-小程序端.md create mode 100644 docs/02-功能清单-小程序端/01-通用功能.md create mode 100644 docs/02-功能清单-小程序端/02-报修相关功能.md create mode 100644 docs/02-功能清单-小程序端/03-巡检相关功能.md create mode 100644 docs/02-功能清单-小程序端/04-保洁相关功能.md create mode 100644 docs/02-功能清单-小程序端/05-考勤相关功能.md create mode 100644 docs/02-功能清单-小程序端/06-组织架构相关功能.md create mode 100644 docs/02-功能清单-小程序端/07-服务评价相关功能.md create mode 100644 docs/02-功能清单-小程序端/08-统计概览功能.md create mode 100644 docs/02-功能清单-小程序端/09-管理员小程序功能.md create mode 100644 docs/02-功能清单-物业公司.md create mode 100644 docs/02-功能清单-物业公司/01-在线报修.md create mode 100644 docs/02-功能清单-物业公司/02-巡检管理.md create mode 100644 docs/02-功能清单-物业公司/03-保洁管理.md create mode 100644 docs/02-功能清单-物业公司/04-组织架构.md create mode 100644 docs/02-功能清单-物业公司/05-考勤打卡.md create mode 100644 docs/02-功能清单-物业公司/06-服务评价.md create mode 100644 docs/02-功能清单-物业公司/07-统计报表.md create mode 100644 docs/02-功能清单-物业公司/08-操作日志.md create mode 100644 docs/02-功能清单-物业公司/09-系统配置.md create mode 100644 docs/02-功能清单-超级管理员.md create mode 100644 docs/02-功能清单-超级管理员/01-账号管理.md create mode 100644 docs/02-功能清单-超级管理员/02-权限管理.md create mode 100644 docs/02-功能清单-超级管理员/03-系统配置.md create mode 100644 docs/02-功能清单-超级管理员/04-操作日志.md create mode 100644 docs/03-业务流转逻辑-医院.md create mode 100644 docs/03-业务流转逻辑-小程序端.md create mode 100644 docs/03-业务流转逻辑-物业公司.md create mode 100644 docs/03-业务流转逻辑-超级管理员.md create mode 100644 docs/04-开发与测试规范.md create mode 100644 docs/05-接口规范.md create mode 100644 docs/06-项目技术要求.md create mode 100644 docs/Windows部署指南.md diff --git a/.codebuddy/plans/docs-merge-refactor_eca19d14(未完成).md b/.codebuddy/plans/docs-merge-refactor_eca19d14(未完成).md new file mode 100644 index 0000000..e4884f4 --- /dev/null +++ b/.codebuddy/plans/docs-merge-refactor_eca19d14(未完成).md @@ -0,0 +1,93 @@ +--- +name: docs-merge-refactor +overview: 将docs目录下04-08文档合并精简为3个文件:开发与测试规范、接口规范、项目技术要求,删除核心数据模型和TAPD需求拆解两个延后文档 +todos: + - id: create-04-dev-test-spec + content: 新建 04-开发与测试规范.md,含Git规范、代码风格、测试、前后端协作、CI/CD五大板块 + status: pending + - id: merge-05-06-api-spec + content: 合并 05-API接口规范.md + 06-扩展接口规范.md 为 05-接口规范.md + status: pending + - id: rename-08-to-06 + content: 将 08-项目技术要求.md 改为 06-项目技术要求.md,移除已拆分章节并更新引用路径 + status: pending + dependencies: + - create-04-dev-test-spec + - id: delete-old-files + content: 删除旧文件:04-核心数据模型.md、05-API接口规范.md、06-扩展接口规范.md、07-TAPD需求拆解.md、08-项目技术要求.md + status: pending + dependencies: + - merge-05-06-api-spec + - rename-08-to-06 +--- + +## 产品概述 + +将医院后勤管理项目的文档体系从5个文件(04-08)精简为3个文件,优先整理开发规范和技术要求,延后数据模型设计。 + +## 核心功能 + +- 删除 `04-核心数据模型.md` 和 `07-TAPD需求拆解.md`(延后处理) +- 新建 `04-开发与测试规范.md`,包含:Git分支/提交规范、代码风格规范、测试规范、前后端协作规范、CI/CD流程规范 +- 合并 `05-API接口规范.md` + `06-扩展接口规范.md` 为 `05-接口规范.md` +- 将 `08-项目技术要求.md` 重命名为 `06-项目技术要求.md` + +## 最终文档结构 + +``` +docs/ +├── 01-模块划分.md +├── 02-功能清单-超级管理员.md +├── 02-功能清单-物业公司.md +├── 02-功能清单-医院.md +├── 02-功能清单-小程序端.md +├── 03-业务流转逻辑-超级管理员.md +├── 03-业务流转逻辑-物业公司.md +├── 03-业务流转逻辑-医院.md +├── 03-业务流转逻辑-小程序端.md +├── 04-开发与测试规范.md ← 新建 +├── 05-接口规范.md ← 原05+06合并 +└── 06-项目技术要求.md ← 原08重命名 +``` + +## 技术栈 + +纯文档整理任务,无代码技术栈依赖。文档内容基于现有项目技术栈(Java 17 + Spring Boot 3 + Vue 3 + uni-app)。 + +## 实现方案 + +### 1. 新建 04-开发与测试规范.md + +从08-项目技术要求.md第七章"开发规范"和第九章"测试要求"中提取相关内容,并大幅扩展为独立文档,包含5大板块: + +- **Git分支与提交规范**:分支策略(已有框架)、Commit Message规范(Conventional Commits)、分支保护规则、Merge Request流程 +- **代码风格规范**:后端Java规范(基于08第七章7.3命名规范扩展)、前端Vue/TypeScript规范、小程序uni-app规范、ESLint/Prettier配置 +- **测试规范**:单元测试(JUnit5+Mockito)、集成测试、E2E测试、测试覆盖率要求(从08第九章提取并细化) +- **前后端协作规范**:API联调流程、接口文档管理(Swagger)、Mock数据规范、联调排期约定 +- **CI/CD流程规范**:Jenkins/GitLab CI流水线配置、构建-测试-部署各阶段门禁、环境管理策略(从08第十章提取) + +### 2. 合并 05+06 为 05-接口规范.md + +- 05-API接口规范.md 作为主体,保持原有结构不变 +- 06-扩展接口规范.md 作为新章节追加到主体末尾,章节号顺延 +- 合并后结构:一~十七(原05内容)+ 十八~二十七(原06内容,章节号重编) +- 删除原06中与05重复的全局约定内容 + +### 3. 重命名 08 → 06-项目技术要求.md + +- 内容基本不变,但需移除已拆分到04的开发规范和测试规范章节(改为引用04) +- 更新文档内引用路径(如"详见06-扩展接口规范.md"改为"详见05-接口规范.md") + +### 4. 删除旧文件 + +- 删除 04-核心数据模型.md +- 删除 05-API接口规范.md +- 删除 06-扩展接口规范.md +- 删除 07-TAPD需求拆解.md +- 删除 08-项目技术要求.md + +## 实施注意事项 + +- 04-开发与测试规范.md 的内容应与08-项目技术要求.md 中的开发/测试章节保持一致,04独立后08中对应章节改为引用 +- 合并接口规范时保持原有API路径、请求体、响应体格式不变,仅做章节编号调整 +- 08重命名为06后,内部引用路径需同步更新 \ No newline at end of file diff --git a/.codebuddy/plans/docs-merge-v2_5f294389.md b/.codebuddy/plans/docs-merge-v2_5f294389.md new file mode 100644 index 0000000..9e3190f --- /dev/null +++ b/.codebuddy/plans/docs-merge-v2_5f294389.md @@ -0,0 +1,162 @@ +--- +name: docs-merge-v2 +overview: 将04-08文档精简为3个规范类文档,接口规范只写约定不写具体字段,删除数据模型和TAPD拆解 +todos: + - id: create-04-dev-test-spec + content: 新建 04-开发与测试规范.md:提取08第七/九章内容并扩展前端/小程序/Commit/协作规范 + status: completed + - id: create-05-api-spec + content: 新建 05-接口规范.md:提取05全局约定+认证规范+06模块化架构规范,删除具体接口字段 + status: completed + - id: rename-08-to-06 + content: 将08改写为06-项目技术要求.md:移除已拆分章节改为引用,更新内部引用路径 + status: completed + dependencies: + - create-04-dev-test-spec + - create-05-api-spec + - id: delete-old-files + content: 删除旧文件:04-核心数据模型.md、05-API接口规范.md、06-扩展接口规范.md、07-TAPD需求拆解.md、08-项目技术要求.md + status: completed + dependencies: + - rename-08-to-06 +--- + +## 产品概述 + +将医院后勤管理项目的04-08号文档精简合并,只保留规范和约定层面内容,去掉具体数据模型表结构、具体接口请求/响应字段定义、TAPD需求拆解等延后处理的内容。 + +## 核心功能 + +- 删除 `04-核心数据模型.md`(表结构延后到开发阶段) +- 删除 `07-TAPD需求拆解.md`(需求拆解延后处理) +- 新建 `04-开发与测试规范.md`:从08中提取开发规范(第七章)和测试规范(第九章),并适当扩展 +- 新建 `05-接口规范.md`:从05中提取全局约定(第一章)+认证规范(第二章概要),从06中提取模块化架构规范(IModulePlugin接口定义、模块注册流程、事件通信规范、模块开发规范、前端加载机制、版本升级、安全规范),删除所有具体接口的请求/响应字段定义 +- 将 `08-项目技术要求.md` 重命名为 `06-项目技术要求.md`,移除已拆分到04的开发规范和测试规范章节,改为引用04 + +## 最终文档结构 + +``` +docs/ +├── 01-模块划分.md +├── 02-功能清单-超级管理员.md +├── 02-功能清单-物业公司.md +├── 02-功能清单-医院.md +├── 02-功能清单-小程序端.md +├── 03-业务流转逻辑-超级管理员.md +├── 03-业务流转逻辑-物业公司.md +├── 03-业务流转逻辑-医院.md +├── 03-业务流转逻辑-小程序端.md +├── 04-开发与测试规范.md ← 新建(提取自08第七/九章) +├── 05-接口规范.md ← 新建(提取05全局约定+06架构规范,删除具体接口) +└── 06-项目技术要求.md ← 原08重命名,移除已拆分章节 +``` + +## 技术栈 + +纯文档整理任务,无代码技术栈依赖。文档内容基于现有项目技术栈(Java 17 + Spring Boot 3 + Vue 3 + uni-app + MariaDB + Redis)。 + +## 实现方案 + +### 1. 新建 04-开发与测试规范.md + +从08-项目技术要求.md第七章"开发规范"和第九章"测试要求"中提取并重组: + +**开发规范部分(来自08第七章)**: + +- API规范(引用05-接口规范.md,保留核心约定如RESTful风格、统一响应格式、错误码分段、分页参数) +- 代码分层规范(Controller→Service→Repository三层分离,DTO/VO/Entity严格分离) +- 命名规范(包名、类名、方法名、常量、数据库表名/字段名、枚举值、API路径) +- 数据库规范(tenant_id必含、雪花主键、逻辑删除、枚举VARCHAR、JSON字段限制、索引规范) +- 模块开发规范(引用05-接口规范.md IModulePlugin规范,模块目录结构,模块间通信规则) +- 审计日志规范(@AuditLog注解、AOP切面、记录内容、变更快照) +- Git分支规范(main/develop/feature/hotfix/release) +- 代码审查要求(审查清单) + +**测试规范部分(来自08第九章)**: + +- 单元测试(覆盖率要求、框架JUnit5+Mockito、命名规范、必须测试场景) +- 测试前置流程(修改后必先测试、CI门禁、JaCoCo覆盖率报告) +- 集成测试(多租户隔离、读写分离、权限实时生效、蓝牙策略) +- 蓝牙场景测试(信号/距离/离线/断开等场景) +- 性能测试(JMeter/wrk、并发场景、慢SQL阈值) +- 安全测试(SQL注入、越权访问、敏感数据、接口鉴权) + +**扩展内容**: + +- 前端开发规范(Vue 3组件规范、TypeScript规范、状态管理规范)—— 从08中的前端技术栈推导 +- 小程序开发规范(uni-app规范、蓝牙调用规范)—— 从08中的小程序技术栈和蓝牙要求推导 +- Commit Message规范(Conventional Commits格式) +- 前后端协作规范(API联调流程、接口文档管理、Mock数据规范) + +### 2. 新建 05-接口规范.md + +**从05-API接口规范.md提取(仅规范/约定,不提取具体接口字段)**: + +- 一、全局约定(完整保留):请求头、统一响应格式、错误码规范、通用错误码、查询参数约定 +- 二、认证模块(仅保留规范概要):认证方式说明(Web端用户名密码→JWT、小程序微信openid→JWT、首次绑定手机号)、JWT载荷标准字段,删除每个接口的具体请求/响应字段 +- 十七、接口权限汇总(保留,作为规范参考) + +**删除的内容(具体接口定义,开发时再细化)**: + +- 三~十六章所有具体API端点、请求体、响应体示例 + +**从06-扩展接口规范.md提取(架构规范层面)**: + +- 一、设计目标(模块即插即用、热注册、隔离、租户级控制) +- 二、核心接口定义(IModulePlugin接口及所有数据结构:ModuleInfo/MenuDefinition/PermissionDefinition/RouteDefinition/TableDefinition/ConfigDefinition/ModuleContext) +- 三、模块注册中心(ModuleRegistry接口、注册流程) +- 四、模块启用/禁用管理(仅保留规范说明,删除具体API请求/响应字段) +- 五、模块间事件通信(EventBus、预定义事件表、事件订阅示例) +- 六、模块配置管理(仅保留规范说明,删除具体API请求/响应字段) +- 七、扩展模块实现规范(目录结构、module.yml、IModulePlugin实现示例——这些是开发规范必须保留) +- 八、前端模块加载机制 +- 九、模块版本升级 +- 十、模块安全规范 + +### 3. 修改 08 → 06-项目技术要求.md + +**移除的章节**(已拆分到04和05): + +- 7.1 API规范 → 改为引用05 +- 7.2 代码分层规范 → 移至04 +- 7.3 命名规范 → 移至04 +- 7.4 数据库规范 → 移至04 +- 7.5 模块开发规范 → 改为引用05 +- 7.6 审计日志规范 → 移至04 +- 7.7 Git分支规范 → 移至04 +- 7.8 代码审查要求 → 移至04 +- 9.1~9.6 测试要求 → 全部移至04 +- 附录A 蓝牙策略配置数据模型 → 删除(表结构延后) + +**保留的章节**(技术架构和运维层面): + +- 一、技术栈选型与版本要求 +- 二、架构设计要求 +- 三、去中间件方案 +- 四、安全要求(4.1认证方案、4.2四级权限体系、4.3数据权限、4.4蓝牙策略配置、4.5审计日志、4.6通用安全要求) +- 五、性能要求 +- 六、数据库备份与恢复 +- 八、部署与运维要求 +- 十、环境配置管理 + +**新增引用**: + +- 开发规范 → "详见 04-开发与测试规范.md" +- 测试规范 → "详见 04-开发与测试规范.md" +- 模块化架构 → "详见 05-接口规范.md" +- 更新文档内引用路径("06-扩展接口规范.md"→"05-接口规范.md","04-核心数据模型.md"→删除引用) + +### 4. 删除旧文件 + +- 04-核心数据模型.md +- 05-API接口规范.md +- 06-扩展接口规范.md +- 07-TAPD需求拆解.md +- 08-项目技术要求.md + +## 实施注意事项 + +- 05-接口规范.md中IModulePlugin相关代码示例保留(这些是架构规范,不是业务接口字段) +- 06中第四章模块启用/禁用API和第六章模块配置API,保留路径表格,删除请求/响应体示例 +- 08移入04的内容保持原意不变,仅做格式调整和引用更新 +- 文档编号连续:01→02→03→04→05→06,无跳号 \ No newline at end of file diff --git a/.codebuddy/plans/医院物业SaaS管理后台-概要设计_c528df96.md b/.codebuddy/plans/医院物业SaaS管理后台-概要设计_c528df96.md new file mode 100644 index 0000000..f9266ae --- /dev/null +++ b/.codebuddy/plans/医院物业SaaS管理后台-概要设计_c528df96.md @@ -0,0 +1,339 @@ +--- +name: 医院物业SaaS管理后台-概要设计 +overview: 设计面向医院物业公司的SaaS模式管理员后台系统概要设计,涵盖在线报修、巡检、保洁、服务评价等核心模块,以及医废管理、陪检管理、合同管理、分段招标管理等扩展模块接口预留。 +design: + architecture: + framework: react + component: tdesign + styleKeywords: + - 企业级SaaS + - 专业高效 + - 数据驱动 + - 清爽蓝白 + - 卡片式布局 + fontSystem: + fontFamily: PingFang SC + heading: + size: 24px + weight: 600 + subheading: + size: 16px + weight: 500 + body: + size: 14px + weight: 400 + colorSystem: + primary: + - "#0052D9" + - "#266FE8" + - "#4787F0" + background: + - "#F3F4F6" + - "#FFFFFF" + - "#F9FAFB" + text: + - "#1F2937" + - "#4B5563" + - "#9CA3AF" + functional: + - "#00A870" + - "#E34D59" + - "#ED7B2F" + - "#0052D9" +todos: + - id: design-overview + content: 编写概要设计文档,涵盖系统架构、模块划分、数据模型、接口规范与扩展机制 + status: completed + - id: data-model + content: 设计核心数据模型(租户、班组、工单、巡检计划、保洁任务、评价、蓝牙设备) + status: completed + dependencies: + - design-overview + - id: api-spec + content: 设计各模块RESTful API接口规范,含请求/响应结构与权限要求 + status: completed + dependencies: + - design-overview + - id: extension-interface + content: 设计IModulePlugin扩展接口规范,定义模块注册、菜单注入、权限声明机制 + status: completed + dependencies: + - design-overview + - id: tapd-import + content: 使用[skill:TAPD]将需求拆解录入TAPD,创建Epic与Story树 + status: completed + dependencies: + - design-overview + - data-model + - api-spec +--- + +## 产品概述 + +面向医院物业公司的SaaS模式管理员后台系统,提供报修、巡检、保洁及服务评价四大核心功能模块,支持多租户隔离与自定义班组人员分配,并预留医废管理、陪检管理、合同管理、分段招标管理等扩展模块接口。 + +## 核心功能 + +### 在线报修模块 + +- 微信扫码注册:扫描二维码进入小程序/公众号,自动注册并绑定身份信息 +- 上传照片:报修时支持拍摄/上传故障照片,最多9张,含水印时间定位 +- 工单生成与流转:自动生成工单编号,按预设规则流转(待分配→处理中→待验收→已完成/已关闭),支持催单、退单、转单 +- 延期及协助维修:维修人员可申请延期,需主管审批;可请求其他班组协助,生成协助子工单 + +### 巡检管理模块 + +- 主管制定计划:按区域/设备/频次创建巡检计划,自动生成巡检任务排期 +- 蓝牙卡定位打卡:通过蓝牙Beacon定位确认巡检人员到达指定位置,防止代签 +- 异常记录:巡检发现异常可拍照上传、标记严重等级、自动触发报修工单 + +### 保洁管理模块 + +- 多级管理:项目→区域→楼栋→楼层→区域责任人五级保洁管理架构 +- 蓝牙卡定位确认完成:保洁人员到达指定区域蓝牙打卡确认完成,主管可抽查 +- 保洁任务看板:日/周/月任务视图,超时未完成自动预警 + +### 服务评价模块 + +- 五分制评分:对报修/巡检/保洁服务进行1-5分打分 +- 留言评价:支持文字留言及图片上传 +- 评价看板:汇总统计各班组/人员评分,生成绩效报表 + +### 系统管理 + +- 自定义班组:创建/编辑班组,设置班组长,支持多班组协作 +- 人员分配逻辑:按区域/技能/排班等维度分配人员到班组,支持一人多班组 +- 多租户隔离:SaaS模式下各物业公司数据完全隔离 +- 角色权限:超管→租户管理员→项目经理→主管→员工五级角色体系 + +### 扩展模块预留 + +- 医废管理:医废收集、称重、转运、销毁全流程追踪 +- 陪检管理:陪检任务分配、签到确认、耗时统计 +- 合同管理:合同台账、到期预警、续签审批 +- 分段招标管理:招标计划、供应商管理、评标定标 + +## 技术栈 + +- 前端:React 18 + TypeScript + Ant Design Pro + Tailwind CSS +- 后端:Node.js + NestJS(TypeScript) +- 数据库:PostgreSQL(多租户共享数据库隔离schema方案)+ Redis(缓存/会话) +- 消息队列:RabbitMQ(工单流转、异步通知) +- 对象存储:腾讯云COS(图片/附件) +- 微信集成:微信小程序API + 微信公众号API + +## 实现方案 + +### 架构策略 + +采用领域驱动设计(DDD)分层架构,按业务领域拆分微服务模块(NestJS Module级别),预留标准扩展接口。SaaS多租户采用共享数据库、Schema隔离方案,通过TenantContext中间件自动切换。 + +### 核心技术决策 + +1. **多租户方案**:共享数据库+行级隔离(tenant_id字段),兼顾成本与隔离性,通过NestJS Guard统一注入租户上下文 +2. **工单流转引擎**:基于状态机模式实现,状态转移规则可配置,支持自定义流转路径 +3. **蓝牙定位**:前端小程序对接蓝牙Beacon协议,后端校验打卡位置合法性 +4. **扩展模块接口**:定义IModulePlugin接口,新模块通过实现标准接口注册到系统,自动获得菜单、权限、路由注入能力 + +### 数据流 + +``` +微信扫码/小程序 → API网关(NestJS) → 租户识别中间件 → 业务模块 → PostgreSQL/Redis + → 消息队列(异步通知/工单流转) + → 腾讯云COS(图片存储) +``` + +## 架构设计 + +```mermaid +graph TB + subgraph 前端层 + A[管理员后台 React] + B[微信小程序] + end + + subgraph API网关层 + C[NestJS API Gateway] + C1[租户识别中间件] + C2[JWT认证守卫] + C3[权限守卫] + end + + subgraph 业务模块层 + D1[报修模块 RepairModule] + D2[巡检模块 InspectionModule] + D3[保洁模块 CleaningModule] + D4[评价模块 EvaluationModule] + D5[组织架构模块 OrgModule] + D6[系统管理模块 SystemModule] + D7[扩展模块接口 IModulePlugin] + end + + subgraph 基础设施层 + E1[PostgreSQL] + E2[Redis] + E3[RabbitMQ] + E4[腾讯云COS] + E5[微信API] + end + + A --> C + B --> C + C --> C1 --> C2 --> C3 + C3 --> D1 & D2 & D3 & D4 & D5 & D6 & D7 + D1 & D2 & D3 & D4 & D5 & D6 & D7 --> E1 & E2 & E3 & E4 + D1 & D2 & D3 --> E5 +``` + +### 模块插件化扩展设计 + +```mermaid +graph LR + subgraph 核心框架 + M[ModuleRegistry 注册中心] + R[路由自动注入] + P[权限自动注册] + N[菜单自动生成] + end + + subgraph 扩展模块 + E1[医废管理 MedicalWasteModule] + E2[陪检管理 EscortModule] + E3[合同管理 ContractModule] + E4[分段招标 BiddingModule] + end + + E1 & E2 & E3 & E4 -->|实现IModulePlugin| M + M --> R & P & N +``` + +## 目录结构 + +``` +hospital-facility-management/ +├── packages/ +│ ├── server/ # 后端服务 +│ │ ├── src/ +│ │ │ ├── main.ts # 入口文件,NestJS bootstrap +│ │ │ ├── app.module.ts # 根模块,注册所有业务模块 +│ │ │ ├── common/ # 公共层 +│ │ │ │ ├── guards/ # 租户守卫、JWT守卫、权限守卫 +│ │ │ │ ├── interceptors/ # 响应格式化、日志拦截器 +│ │ │ │ ├── filters/ # 异常过滤器 +│ │ │ │ ├── decorators/ # 自定义装饰器(@Tenant, @Permissions) +│ │ │ │ ├── pipes/ # 验证管道 +│ │ │ │ └── interfaces/ # IModulePlugin, ITenantContext等公共接口 +│ │ │ ├── config/ # 配置管理(数据库、Redis、COS、微信等) +│ │ │ ├── modules/ +│ │ │ │ ├── auth/ # 认证模块(微信登录、JWT、角色管理) +│ │ │ │ ├── tenant/ # 租户管理模块 +│ │ │ │ ├── org/ # 组织架构模块(班组、人员分配) +│ │ │ │ ├── repair/ # 报修模块 +│ │ │ │ │ ├── repair.module.ts +│ │ │ │ │ ├── controllers/ +│ │ │ │ │ ├── services/ +│ │ │ │ │ ├── entities/ +│ │ │ │ │ ├── dto/ +│ │ │ │ │ └── workflow/ # 工单状态机引擎 +│ │ │ │ ├── inspection/ # 巡检模块 +│ │ │ │ ├── cleaning/ # 保洁模块 +│ │ │ │ ├── evaluation/ # 评价模块 +│ │ │ │ └── _plugins/ # 扩展模块目录 +│ │ │ │ ├── medical-waste/ # 医废管理(预留) +│ │ │ │ ├── escort/ # 陪检管理(预留) +│ │ │ │ ├── contract/ # 合同管理(预留) +│ │ │ │ └── bidding/ # 分段招标(预留) +│ │ │ └── shared/ # 共享服务(通知、文件上传、蓝牙校验) +│ │ └── test/ +│ └── admin-web/ # 管理员后台前端 +│ ├── src/ +│ │ ├── layouts/ # 布局组件(SiderMenu + Header + Content) +│ │ ├── pages/ +│ │ │ ├── dashboard/ # 仪表盘首页 +│ │ │ ├── repair/ # 报修管理页面 +│ │ │ ├── inspection/ # 巡检管理页面 +│ │ │ ├── cleaning/ # 保洁管理页面 +│ │ │ ├── evaluation/ # 评价管理页面 +│ │ │ ├── org/ # 组织架构管理页面 +│ │ │ └── system/ # 系统设置页面 +│ │ ├── components/ # 公共组件 +│ │ ├── services/ # API调用层 +│ │ ├── stores/ # 状态管理(Zustand) +│ │ ├── hooks/ # 自定义Hooks +│ │ └── utils/ # 工具函数 +│ └── public/ +└── package.json # Monorepo 根配置 +``` + +## 实现要点 + +- **工单流转引擎**:采用有限状态机(XState理念),状态转移规则存储于数据库,支持租户自定义流转路径 +- **蓝牙定位校验**:小程序端扫描Beacon信号强度(RSSI)换算距离,后端校验打卡坐标与任务区域匹配度 +- **多租户隔离**:所有业务表携带tenant_id,TypeORM通过全局scope自动注入查询条件,防止越权 +- **扩展模块注册**:IModulePlugin接口定义register()、getMenus()、getPermissions()方法,新模块实现后自动注入 +- **消息通知**:工单状态变更、巡检超时、保洁预警等事件通过RabbitMQ发布,消费端推送微信模板消息 + +## 设计风格 + +采用现代企业级SaaS管理后台风格,以TDesign组件库为基础,搭配Tailwind CSS自定义样式。整体视觉追求专业、高效、清晰,符合医院物业管理行业特征。 + +## 页面规划 + +### 1. 仪表盘首页(Dashboard) + +- **顶部统计卡片区**:今日报修数/进行中工单/待巡检数/保洁完成率,大字号数字+环比趋势箭头 +- **工单状态分布图**:环形图展示各状态工单占比 +- **最新工单列表**:展示最近10条工单,含状态标签、紧急程度、处理人 +- **班组工作量排行**:横向柱状图展示各班组本周完成量 +- **评分趋势图**:折线图展示近30天平均评分走势 + +### 2. 报修管理页 + +- **工单列表区**:表格展示,支持状态/日期/区域/班组多维度筛选,含快捷操作按钮 +- **工单详情抽屉**:右侧抽屉展示工单完整信息、流转记录时间轴、照片附件、评价信息 +- **工单创建弹窗**:表单录入报修信息,支持图片上传预览 + +### 3. 巡检管理页 + +- **巡检计划看板**:日历视图+列表视图切换,按颜色区分正常/异常/未执行 +- **巡检记录详情**:展示打卡时间、定位信息、异常记录及关联工单 +- **计划创建表单**:区域选择、频次设置、人员分配、蓝牙点位绑定 + +### 4. 保洁管理页 + +- **保洁任务看板**:看板视图(待执行/执行中/已完成),支持拖拽调整 +- **区域管理树**:左侧树形结构展示五级保洁区域架构 +- **人员排班表**:周视图展示排班情况,支持点击编辑 + +### 5. 评价管理页 + +- **评价汇总统计**:各模块平均评分卡片+星级分布图 +- **评价列表**:支持按模块/评分/日期筛选,展示评分星级、评语、关联工单 +- **绩效报表**:班组/人员评分排名表,支持导出 + +### 6. 组织架构管理页 + +- **班组管理**:卡片式展示各班组,含人员数量、负责区域、班组长信息 +- **人员分配**:左右穿梭框选择人员分配到班组,支持批量操作 +- **排班日历**:月视图排班管理 + +### 7. 系统设置页 + +- **租户信息**:公司基本信息、Logo上传 +- **角色权限**:角色列表+权限树勾选 +- **蓝牙设备管理**:Beacon设备列表、位置绑定、状态监控 +- **微信配置**:小程序/公众号参数配置 + +## 全局布局 + +- 左侧固定侧边栏:可折叠,含模块图标+文字,底部展开/收起按钮 +- 顶部导航栏:面包屑导航 + 全局搜索 + 通知铃铛 + 用户头像下拉菜单 +- 内容区:带内边距的白色背景卡片式内容区 + +## Agent Extensions + +### Skill + +- **TAPD** +- Purpose: 将概要设计中的各模块需求拆解为TAPD需求和任务,录入项目管理平台 +- Expected outcome: 在TAPD中创建完整的需求树(Epic→Story→Task),覆盖报修、巡检、保洁、评价、组织架构、系统管理六大模块,含优先级、描述、关联关系 \ No newline at end of file diff --git a/.codebuddy/plans/测试要求增强与权限方案优化_06fa523e.md b/.codebuddy/plans/测试要求增强与权限方案优化_06fa523e.md new file mode 100644 index 0000000..9f600a0 --- /dev/null +++ b/.codebuddy/plans/测试要求增强与权限方案优化_06fa523e.md @@ -0,0 +1,91 @@ +--- +name: 测试要求增强与权限方案优化 +overview: 1. 增强测试要求:代码级100%覆盖(每个类/方法/if-else/case分支)、测试前置流程(修改后必须先测试通过才能继续);2. 权限实时生效方案从"数据库轮询标记"改为"Redis Pub/Sub",利用已有Redis实例零额外中间件 +todos: + - id: update-08-redis + content: 更新08-项目技术要求.md中权限实时通知方案为Redis Pub/Sub + status: completed + - id: update-08-test + content: 更新08-项目技术要求.md中测试要求(100%覆盖+测试前置流程) + status: completed + dependencies: + - update-08-redis + - id: update-08-misc + content: 更新08-项目技术要求.md中缓存策略表、缓存管理表、配置项等关联内容 + status: completed + dependencies: + - update-08-redis + - id: update-03-redis + content: 更新03-业务流转逻辑.md中权限实时生效描述 + status: completed + - id: update-01-redis + content: 更新01-模块划分.md中权限实时生效描述 + status: completed +--- + +## 用户需求 + +### 需求1:权限实时生效方案优化 + +当前方案"数据库轮询标记 + Spring Event"每5秒轮询一次数据库,资源消耗大。需要改为更轻量的方案,利用已有Redis实例实现毫秒级权限变更通知,零额外中间件、零数据库压力。 + +### 需求2:测试要求增强 + +- **100%代码级覆盖**:每个类、方法、包括方法里if-else、case分支都必须测试到 +- **测试前置流程**:每次代码修改后,必须先进行测试,测试通过后才能进行下一步操作 + +## 方案概述 + +### 一、权限实时生效:Redis Pub/Sub 替代数据库轮询 + +**原理**:权限变更时通过 Redis `PUBLISH` 命令发布消息,各服务节点通过 `MessageListener` 订阅频道,收到消息后刷新本地权限缓存。 + +**优势对比**: + +| 对比项 | 数据库轮询(原方案) | Redis Pub/Sub(新方案) | +| --- | --- | --- | +| 数据库压力 | 每5秒N次SQL | 0(不碰数据库) | +| 延迟 | 最大5秒 | 毫秒级(内存操作) | +| 资源消耗 | 定时线程+DB连接 | 复用已有Redis连接,几乎零额外开销 | +| 多节点支持 | 需每节点轮询 | 天然支持(每节点各自订阅) | +| 降级策略 | 无 | Redis断连时,权限缓存TTL(2小时)到期后自然刷新 | + + +**实现要点**: + +- 频道命名:`permission:changed` +- 消息内容:版本号(Long),用于判断是否需要刷新 +- 发布时机:角色权限变更、用户角色分配变更 +- 订阅方:各服务实例启动时注册 `RedisMessageListenerContainer` +- 降级保障:Redis连接断开时不影响业务,缓存TTL到期后自动刷新 + +### 二、测试要求增强 + +- 单元测试覆盖率从70%提升至100%(行覆盖+分支覆盖) +- 新增JaCoCo分支覆盖指标要求 +- 新增"9.6 测试前置流程"章节,定义代码修改→测试→下一步的强制流程 +- 在7.8代码审查要求中增加测试覆盖率检查项 + +### 修改范围 + +3个文档,共约12处修改点: + +1. **docs/08-项目技术要求.md**(9处) + +- 3.1 权限变更实时通知:方案描述+代码示例 +- 3.3 跨实例通信描述 +- 5.3 缓存策略表 +- 7.8 代码审查要求 +- 8.4 缓存管理策略表 +- 9.1 单元测试:覆盖率和分支要求 +- 9.2 集成测试:权限生效延迟描述 +- 新增9.6 测试前置流程 +- 10.3 配置项:删除轮询间隔,新增Redis频道配置 + +2. **docs/03-业务流转逻辑.md**(1处) + +- 2.3 权限实时生效流程中的描述 + +3. **docs/01-模块划分.md**(1处) + +- 2.4 权限实时生效机制中的描述 \ No newline at end of file diff --git a/.codebuddy/plans/移除Docker相关文件和文档描述_8a12f801.md b/.codebuddy/plans/移除Docker相关文件和文档描述_8a12f801.md new file mode 100644 index 0000000..e23697c --- /dev/null +++ b/.codebuddy/plans/移除Docker相关文件和文档描述_8a12f801.md @@ -0,0 +1,62 @@ +--- +name: 移除Docker相关文件和文档描述 +overview: 移除所有Docker相关文件,并清理3个文档中的Docker/容器化描述,改为Windows直接部署方式 +todos: + - id: delete-docker-files + content: 删除 backend/Dockerfile、docker-compose.yml、.dockerignore + status: completed + - id: update-readme + content: 更新 README.md:删除Docker技术栈、目录项、部署章节,替换为Windows部署指引 + status: completed + dependencies: + - delete-docker-files + - id: update-08-tech + content: 更新 08-项目技术要求.md:基础设施表、部署架构图、8.2部署章节 + status: completed + dependencies: + - delete-docker-files +--- + +## 用户需求 + +不需要Docker,移除所有相关文件,并检查文档中内容,去掉Docker/容器化相关描述,替换为Windows服务部署方式。 + +### 需要删除的文件(3个) + +1. `backend/Dockerfile` +2. `docker-compose.yml` +3. `.dockerignore` + +### 需要修改的文档(2个) + +- `README.md`:删除Docker技术栈、Dockerfile目录项、Docker部署章节,替换为Windows部署指引 +- `docs/08-项目技术要求.md`:基础设施表Docker行改为Windows Service、部署架构图去掉Docker Compose、8.2节从Docker Compose改为Windows服务部署要求 + +### 无需修改的文档 + +- `docs/01-模块划分.md`、`docs/03-业务流转逻辑.md` 等不含Docker相关内容 + +## 修改范围 + +### 删除文件 + +| 文件 | 说明 | +| --- | --- | +| `backend/Dockerfile` | Docker镜像构建脚本 | +| `docker-compose.yml` | Docker Compose编排文件 | +| `.dockerignore` | Docker构建排除文件 | + + +### 修改文件 + +#### README.md(3处修改) + +1. 技术栈表删除 `| 容器化 | Docker + Docker Compose |` 行 +2. 项目结构树删除 `├── Dockerfile` 行,删除 `docker-compose.yml` 相关行 +3. 部署章节:将"2. Docker Compose 部署(推荐)"和"3. 仅构建后端镜像"替换为Windows服务部署指引,引用 `docs/Windows部署指南.md` + +#### docs/08-项目技术要求.md(3处修改) + +1. 1.4 基础设施表:`Docker + Docker Compose | 私有云容器化部署` 改为 `Windows Service + WinSW | Windows服务部署(开机自启)` +2. 8.1 部署架构图:将Docker Compose容器编排图改为Windows同机服务部署架构图 +3. 8.2 节:标题从"Docker Compose部署要求"改为"Windows服务部署要求",yaml示例替换为WinSW配置示例 \ No newline at end of file diff --git a/.codebuddy/plans/详细功能说明文档编写_92e2a4d9.md b/.codebuddy/plans/详细功能说明文档编写_92e2a4d9.md new file mode 100644 index 0000000..c4d01a0 --- /dev/null +++ b/.codebuddy/plans/详细功能说明文档编写_92e2a4d9.md @@ -0,0 +1,148 @@ +--- +name: 详细功能说明文档编写 +overview: 基于全部项目文档要求,按照02-功能清单-*.md的4个端侧(小程序端、物业公司、医院、超级管理员),创建对应文件夹,每个功能菜单拆分为独立.md文件,包含页面名称、页面元素、查询条件、列表字段、界面布局,以及需求追溯和功能关联。 +todos: + - id: create-folders + content: 创建4个功能说明文件夹 + status: completed + - id: write-super-admin + content: 编写超级管理员功能说明(4个文件) + status: completed + dependencies: + - create-folders + - id: write-property + content: 编写物业公司功能说明(9个文件) + status: completed + dependencies: + - create-folders + - id: write-hospital + content: 编写医院功能说明(5个文件) + status: completed + dependencies: + - create-folders + - id: write-miniprogram + content: 编写小程序端功能说明(9个文件) + status: completed + dependencies: + - create-folders +--- + +## 产品概述 + +基于现有项目文档(01~06号文档),编写4套详细功能说明文档,覆盖全部角色端的功能页面设计。 + +## 核心功能 + +- 按照02-功能清单的4个文件名创建4个文件夹:超级管理员、物业公司、医院、小程序端 +- 每个功能菜单独立一个.md文件,共约27个文件 +- 每个文件包含:菜单/子菜单/页面名称、页面元素、查询条件、列表字段、界面布局描述 +- 每个功能标注:对应文档要求来源、后续服务功能、关联功能 +- 所有设计需满足01-模块划分、03-业务流转逻辑、05-接口规范、06-项目技术要求中定义的约束 + +## 文件统计 + +- 02-功能清单-超级管理员/:4个文件(账号管理、权限管理、系统配置、操作日志) +- 02-功能清单-物业公司/:9个文件(在线报修、巡检管理、保洁管理、组织架构、考勤打卡、服务评价、统计报表、操作日志、系统配置) +- 02-功能清单-医院/:5个文件(合同管理、分段招标管理、服务监督、服务评价、统计报表) +- 02-功能清单-小程序端/:9个文件(通用功能、报修、巡检、保洁、考勤、组织架构、服务评价、统计概览、管理员功能) + +## 文档编写规范 + +### 单文件模板结构 + +每个.md文件遵循统一模板: + +``` +# {菜单名称} + +> 模块编码:{module code} +> 端侧:Web/小程序 +> 关联文档:列出关联的01~06号文档章节 + +## 功能概览 +| 项目 | 说明 | +|------|------| +| 菜单名称 | | +| 子菜单 | | +| 功能编号 | 如 PR-R-01~11 | +| 权限编码 | 如 repair:list:* | + +## 页面清单 + +### 页面N:{页面名称} +- **页面路径**:路由路径 +- **页面元素**:表单字段、按钮、标签页等 +- **查询条件**:筛选器列表 +- **列表字段**:表格列定义 +- **界面布局**:文字描述布局结构 +- **操作按钮**:可用动作及权限要求 + +## 需求追溯 +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| + +## 业务规则 +- 从03-业务流转逻辑和06-项目技术要求中提取的约束 + +## 状态流转(如有) +- 状态机定义 +``` + +### 需求追溯规范 + +- **文档来源**:标注来自哪个文档的哪个编号,如"02-物业公司 PR-R-01"、"03-物业公司 1.2节"、"06-技术要求 4.4节" +- **后续服务**:该功能完成后触发的下游服务,如"工单分配→触发通知服务" +- **关联功能**:与本功能有数据依赖或交互的其他功能,如"工单列表↔巡检异常上报" + +### 数据来源 + +所有页面设计的数据字段从以下文档综合提取: + +- 01-模块划分.md:角色权限、数据范围 +- 02-功能清单-*.md:功能点编号和描述 +- 03-业务流转逻辑-*.md:流转规则、状态定义、补录标记字段 +- 05-接口规范.md:权限编码矩阵(第九章)、模块事件定义 +- 06-项目技术要求.md:蓝牙策略、审计日志、四级权限体系 + +### 目录结构 + +``` +docs/ +├── 02-功能清单-超级管理员/ +│ ├── 01-账号管理.md # SA-A-01~08,含医院/物业账号CRUD、有效期、到期管理 +│ ├── 02-权限管理.md # SA-P-01~10,含角色定义、权限分配、预设模板、审计日志 +│ ├── 03-系统配置.md # SA-S-01~02,含版本管理、缓存管理 +│ └── 04-操作日志.md # SA-L-01~02,含权限变更日志、账号操作日志 +├── 02-功能清单-物业公司/ +│ ├── 01-在线报修.md # PR-R-01~11,含工单列表/详情/分配/流转/延期/补录/导出 +│ ├── 02-巡检管理.md # PR-I-01~07,含计划/看板/记录/异常/区域/补录 +│ ├── 03-保洁管理.md # PR-C-01~08,含区域/看板/排班/蓝牙/超时/抽查/补录 +│ ├── 04-组织架构.md # PR-O-01~11,含班组/人员/排班/技能/打卡点/下属账号 +│ ├── 05-考勤打卡.md # PR-A-01~05,含打卡点/规则/记录/异常审核/补录 +│ ├── 06-服务评价.md # PR-E-01~05,含汇总/列表/回复/绩效/配置 +│ ├── 07-统计报表.md # PR-ST-01~07,含报修/巡检/保洁/评价/考勤/综合/自定义 +│ ├── 08-操作日志.md # PR-AL-01~05,含时间轴/列表/详情/导出/补录日志 +│ └── 09-系统配置.md # PR-S-01~05,含蓝牙设备/字典/微信/消息模板/补录审核 +├── 02-功能清单-医院/ +│ ├── 01-合同管理.md # HO-CT-01~11,含台账/录入/审批/付款/变更/预警/续签 +│ ├── 02-分段招标管理.md # HO-BD-01~09,含计划/标段/供应商/发布/投标/评标/定标 +│ ├── 03-服务监督.md # HO-SP-01~04,含报修/巡检/保洁数据只读查看 +│ ├── 04-服务评价.md # HO-EV-01~03,含发起评价/汇总查看/列表查看 +│ └── 05-统计报表.md # HO-ST-01~08,含业务/合同/招标/综合/自定义报表 +└── 02-功能清单-小程序端/ + ├── 01-通用功能.md # MP-C-01~06,含登录/个人信息/消息/补录/版本/通讯录 + ├── 02-报修相关功能.md # MP-R-01~12,含扫码/报修/工单/催单/接单/完工/延期/验收/评价 + ├── 03-巡检相关功能.md # MP-I-01~06,含今日任务/蓝牙打卡/执行/异常上报/补录 + ├── 04-保洁相关功能.md # MP-CL-01~07,含今日任务/蓝牙打卡/执行/异常/抽查/补录 + ├── 05-考勤相关功能.md # MP-AT-01~06,含上下班打卡/记录/申诉/日历/审核 + ├── 06-组织架构相关功能.md # MP-OR-01~02,含我的班组/我的排班 + ├── 07-服务评价相关功能.md # MP-EV-01~03,含待评价/评分留言/历史评价 + ├── 08-统计概览功能.md # MP-ST-01~02,含简版概览/个人绩效 + └── 09-管理员小程序功能.md # MP-PM-01~06,含报修/巡检/保洁/考勤/评价/组织架构管理 +``` + +## Agent Extensions + +### SubAgent + +- **code-explorer**: 在编写功能说明时,快速检索项目文档中特定功能点的定义、流转规则和权限编码,确保文档内容与现有规范一致 \ No newline at end of file diff --git a/.codebuddy/plans/项目技术要求文档_29ab44d0.md b/.codebuddy/plans/项目技术要求文档_29ab44d0.md new file mode 100644 index 0000000..d29495b --- /dev/null +++ b/.codebuddy/plans/项目技术要求文档_29ab44d0.md @@ -0,0 +1,158 @@ +--- +name: 项目技术要求文档 +overview: 基于已有的7份设计文档和用户补充信息,创建项目技术要求文档(08-技术要求.md),覆盖技术栈选型、架构设计、安全、性能、开发规范、部署运维、测试等维度,并纳入无中间件方案、蓝牙策略配置等新增需求。 +todos: + - id: write-tech-doc + content: 编写docs/08-项目技术要求.md文档,涵盖技术栈、架构、安全、性能、蓝牙策略、去中间件方案、开发规范、部署运维、测试要求全量内容 + status: completed + - id: update-model-bluetooth + content: 更新docs/04-核心数据模型.md,新增蓝牙策略配置表(sys_bluetooth_policy)和审核表(sys_bluetooth_policy_audit),打卡记录表增加check_type字段 + status: completed + dependencies: + - write-tech-doc + - id: update-api-bluetooth + content: 更新docs/05-API接口规范.md,新增蓝牙策略配置API和打卡记录check_type返回字段 + status: completed + dependencies: + - write-tech-doc + - id: update-flow-bluetooth + content: 更新docs/03-业务流转逻辑.md,蓝牙校验流程改为按策略配置判断(强制/非强制),补录模式仅在强制蓝牙+蓝牙失败时触发 + status: completed + dependencies: + - write-tech-doc +--- + +## 产品概述 + +医院物业SaaS管理后台的项目技术要求文档,作为内部团队开发标准,所有开发人员必须严格按照此标准执行。 + +## 核心功能 + +- 明确技术栈选型与版本要求(Java+Spring Boot+MariaDB+Vue+uni-app+Redis) +- 定义架构设计规范(多租户、模块化、前后端分离、双端、读写分离、去中间件方案) +- 规定安全要求(认证、四级权限、行级数据隔离、蓝牙校验、审计日志) +- 设定性能基线(API响应<500ms、蓝牙交互可靠性、数据补录降级) +- 制定开发规范(API规范、代码规范、数据库规范、模块开发规范) +- 约定部署运维要求(私有云部署、数据库定时备份与恢复、缓存管理、版本更新策略) +- 新增蓝牙策略配置要求(物业公司配置是否强制蓝牙、医院账号审核、报表区分蓝牙/手动打卡) + +## 技术栈选型 + +### 后端 + +- 语言:Java 17+ +- 框架:Spring Boot 3.x +- 数据库:MariaDB 10.6+(主从复制读写分离) +- 缓存:Redis 7.x(权限/字典/菜单缓存,Pub/Sub用于应用内事件) +- ORM:MyBatis-Plus 3.5+ +- 认证:Spring Security + JWT +- 文件存储:腾讯云COS + +### 前端Web + +- 框架:Vue 3 + TypeScript +- 构建工具:Vite 5.x +- 状态管理:Pinia +- 路由:Vue Router 4 +- UI组件库:Element Plus(企业级后台管理场景适配度最高) +- HTTP客户端:Axios +- 图表:ECharts + +### 小程序 + +- 框架:uni-app + Vue 3 +- 蓝牙SDK:uni-ble(uni-app蓝牙低功耗插件) +- UI组件库:uni-ui + +### 基础设施 + +- 部署:私有云(Docker + Docker Compose) +- CI/CD:Jenkins/GitLab CI +- 版本管理:Git + +## 去中间件方案 + +不引入RocketMQ/Kafka等消息中间件,采用以下替代方案: + +### 1. 权限变更实时通知 + +- 方案:数据库轮询标记 + Spring Event +- 实现:权限变更时写入`sys_config`表标记字段`permission_version`递增;各服务实例定时5秒轮询该字段,检测到版本变化时触发本地权限缓存刷新 +- 优势:无额外中间件依赖,实现简单可靠 +- 降级:轮询间隔内最大5秒延迟,对权限场景可接受 + +### 2. 异步任务处理 + +- 方案:Spring @Async + 自定义线程池 +- 实现:配置`ThreadPoolTaskExecutor`,核心线程数=CPU核心数,最大线程数=2*CPU核心数,队列容量1000,拒绝策略CallerRunsPolicy +- 适用场景:报表导出、消息推送、日志异步写入 +- 持久化:关键任务落库后异步执行,避免线程池丢失 + +### 3. 模块间通信 + +- 方案:Spring ApplicationEvent + ApplicationEventPublisher +- 实现:模块间通过Spring Event解耦,事件定义在共享API模块中 +- 跨实例:结合数据库轮询标记实现(事件落库+轮询消费) +- 适用场景:工单完成触发评价、巡检异常触发报修、低分评价通知主管 + +### 4. 定时任务 + +- 方案:Spring @Scheduled + 数据库分布式锁 +- 实现:`@Scheduled`注解声明定时任务,通过`shedlock`或数据库行锁保证集群内单实例执行 +- 适用场景:巡检任务自动生成、保洁超时预警、合同到期提醒、Beacon心跳检测 + +## 架构设计 + +### 整体架构 + +``` +客户端层:Vue3 Web管理后台 | uni-app微信小程序 + ↓ HTTPS +网关层:Spring Cloud Gateway / Nginx 反向代理 + ↓ +应用层:Spring Boot 单体应用(模块化IModulePlugin) + ↓ +数据层:MariaDB主从(读写分离)| Redis缓存 | 腾讯云COS +``` + +### 读写分离方案 + +- 实现:MariaDB主从复制 + MyBatis-Plus动态数据源切换 +- 规则:写操作走主库,读操作走从库 +- 注解:自定义`@ReadOnly`注解标记读操作,AOP切面切换数据源 +- 容错:从库不可用时自动降级到主库读取 + +### 数据库备份与恢复 + +- 定时备份:每日凌晨2:00全量备份(mysqldump),每4小时增量备份(binlog) +- 备份保留:全量备份保留30天,增量备份保留7天 +- 备份存储:私有云本地磁盘 + 异地备份服务器 +- 恢复流程:全量恢复 + binlog重放,RTO<2小时,RPO<4小时 +- 定期演练:每季度执行一次恢复演练 + +### 蓝牙策略配置(新增) + +- 配置方:物业公司管理员 +- 审核方:医院账号 +- 配置项:各场景是否强制蓝牙连接(巡检打卡/巡检拍照/保洁打卡/保洁拍照/考勤打卡) +- 数据模型:新增`sys_bluetooth_policy`配置表 + `sys_bluetooth_policy_audit`审核表 +- 打卡记录标记:所有打卡记录区分`check_type`(BLUETOOTH/MANUAL),后台列表和报表明确显示 +- 降级逻辑:非强制蓝牙场景下,蓝牙失败可直接手动打卡(记录check_type=MANUAL);强制蓝牙场景下,蓝牙失败进入补录模式 + +## 性能要求 + +- API平均响应时间 < 300ms,P99 < 500ms +- 列表查询响应 < 500ms(含分页) +- 报表生成 < 5s(单月数据) +- 并发支持:单实例100 QPS,水平扩展 +- 蓝牙校验:扫描超时3秒,距离计算<100ms + +## 开发规范 + +- API规范:遵循已有05-API接口规范.md +- 代码分层:Controller → Service → Repository,DTO/VO/Entity严格分离 +- 命名规范:包名小写、类名大驼峰、方法名小驼峰、常量全大写下划线 +- 数据库规范:遵循已有04-核心数据模型.md公共字段约定 +- 模块开发:遵循已有06-扩展接口规范.md IModulePlugin规范 +- 审计日志:所有写操作自动记录,使用AOP切面统一处理 +- 单元测试:核心业务Service覆盖率 >= 70% \ No newline at end of file diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..1f37404 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,30 @@ +# https://editorconfig.org +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.java] +indent_style = space +indent_size = 4 + +[*.{yml,yaml}] +indent_style = space +indent_size = 2 + +[*.xml] +indent_style = space +indent_size = 4 + +[*.sql] +indent_style = space +indent_size = 4 + +[*.md] +trim_trailing_whitespace = false + +[Makefile] +indent_style = tab diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..86dd2d0 --- /dev/null +++ b/.env.example @@ -0,0 +1,18 @@ +# ============================================================ +# 医院物业 SaaS 管理后台 — 环境变量配置 +# 复制本文件为 .env 并修改实际值 +# ============================================================ + +# ---- MariaDB ---- +DB_PASSWORD=root +DB_PORT=3306 + +# ---- Redis ---- +REDIS_PASSWORD= +REDIS_PORT=6379 + +# ---- Application ---- +APP_PORT=8080 + +# ---- JWT ---- +JWT_SECRET=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5d80821 --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +# Compiled class files +*.class + +# Log files +*.log + +# Package files +*.jar +*.war +*.ear +*.zip +*.tar.gz +*.rar + +# Maven +target/ + +# IDE +.idea/ +*.iml +.vscode/ +.settings/ +.project +.classpath +.factorypath +*.swp +*.swo + +# OS +.DS_Store +Thumbs.db + +# Env +.env +.env.local diff --git a/README.md b/README.md new file mode 100644 index 0000000..413c201 --- /dev/null +++ b/README.md @@ -0,0 +1,195 @@ +# 医院物业 SaaS 管理后台 + +> 多租户医院物业管理平台,涵盖报修、巡检、保洁、考勤、合同、招标等核心业务模块,支持蓝牙打卡、微信小程序端操作。 + +## 技术栈 + +| 类别 | 技术 | +|------|------| +| 语言 | Java 17 | +| 框架 | Spring Boot 3.2.5 | +| ORM | MyBatis-Plus 3.5.5 | +| 安全 | Spring Security + JWT | +| 数据库 | MariaDB 10.6+ | +| 缓存 | Redis 7 | +| API 文档 | SpringDoc / Swagger | +| 构建工具 | Maven 3.9+ | +| 容器化 | Docker + Docker Compose | + +## 项目结构 + +``` +backend/ +├── src/main/java/com/hospital/mgmt/ +│ ├── common/ # 通用组件 +│ │ ├── annotation/ # 自定义注解(@AuditLog, @ReadOnly) +│ │ ├── base/ # 基础实体类 +│ │ ├── context/ # 租户上下文(ThreadLocal) +│ │ ├── exception/ # 全局异常处理 +│ │ └── result/ # 统一响应封装 +│ ├── config/ # 配置类 +│ ├── security/ # 安全模块(JWT、认证、租户拦截) +│ └── modules/ # 业务模块 +│ ├── auth/ # 认证(登录/刷新Token) +│ ├── org/ # 组织架构(医院/物业/班组/员工) +│ ├── permission/ # 权限管理(用户/角色/权限配置) +│ ├── repair/ # 在线报修 +│ ├── inspection/ # 巡检管理 +│ ├── cleaning/ # 保洁管理 +│ ├── evaluation/ # 服务评价 +│ ├── attendance/ # 考勤打卡 +│ ├── contract/ # 合同管理 +│ ├── bidding/ # 分段招标 +│ ├── device/ # 蓝牙设备管理 +│ ├── audit/ # 操作日志 +│ ├── system/ # 系统管理(字典/版本/模板) +│ └── plugin/ # IModulePlugin 扩展接口 +├── src/main/resources/ +│ ├── application.yml # 默认配置 +│ ├── application-prod.yml # 生产配置 +│ └── db/init.sql # 数据库初始化脚本 +├── Dockerfile +└── pom.xml +``` + +## 快速开始 + +### 前置条件 + +- JDK 17+ +- Maven 3.9+ +- MariaDB 10.6+ +- Redis 7+ + +### 1. 本地开发 + +```bash +# 克隆项目 +git clone +cd 医院后勤管理 + +# 初始化数据库 +mysql -uroot -proot < backend/src/main/resources/db/init.sql + +# 修改配置(如需要) +# 编辑 backend/src/main/resources/application.yml 中的数据库和Redis连接信息 + +# 编译运行 +cd backend +mvn clean package -DskipTests +java -jar target/hospital-mgmt-1.0.0.jar +``` + +应用启动后访问: +- API 基地址:`http://localhost:8080/api/v1` +- Swagger UI:`http://localhost:8080/api/v1/swagger-ui.html` + +### 2. Docker Compose 部署(推荐) + +```bash +# 复制环境变量模板并修改 +cp .env.example .env + +# 一键启动(MariaDB + Redis + 后端) +docker compose up -d + +# 查看日志 +docker compose logs -f backend + +# 停止 +docker compose down +``` + +### 3. 仅构建后端镜像 + +```bash +cd backend +docker build -t hospital-mgmt:1.0.0 . +``` + +## 环境变量 + +| 变量 | 说明 | 默认值 | +|------|------|--------| +| `DB_HOST` | MariaDB 主机 | localhost | +| `DB_PORT` | MariaDB 端口 | 3306 | +| `DB_NAME` | 数据库名 | hospital_mgmt | +| `DB_USER` | 数据库用户 | root | +| `DB_PASSWORD` | 数据库密码 | root | +| `REDIS_HOST` | Redis 主机 | localhost | +| `REDIS_PORT` | Redis 端口 | 6379 | +| `REDIS_PASSWORD` | Redis 密码 | (空) | +| `JWT_SECRET` | JWT 签名密钥 | (内置默认值) | +| `JAVA_OPTS` | JVM 参数 | -Xms256m -Xmx512m | +| `SPRING_PROFILES_ACTIVE` | Spring Profile | prod | + +## 默认账号 + +| 角色 | 用户名 | 密码 | +|------|--------|------| +| 超级管理员 | superadmin | admin123 | + +## 核心功能模块 + +### 在线报修 +- 工单全生命周期:提交 → 智能派单 → 接单 → 处理 → 验收 → 评价 +- 支持紧急催单、延期申请、协助工单 +- 补录机制(需审批) + +### 巡检管理 +- 自定义巡检区域与计划 +- 支持日/周/月/自定义频率 +- 蓝牙打卡验证巡检人员位置 +- 异常自动转报修工单 + +### 保洁管理 +- 五级区域树结构管理 +- 日保/深度/临时任务类型 +- 排班与任务自动生成 +- 抽检功能 + +### 考勤打卡 +- 基于蓝牙 Beacon 的近距离验证 +- 灵活配置上下班规则 +- 异常申诉与补录审批 + +### 合同管理 +- 合同全生命周期 +- 付款节点管理与到期预警 +- 合同变更审批流 + +### 分段招标 +- 招标计划与标段管理 +- 供应商资质审核 +- 黑名单机制 + +### 服务评价 +- 多模块统一评价体系 +- 低评分自动通知 +- 评价回复机制 + +### 权限管理 +- RBAC + 四级数据权限(全院/医院/班组/个人) +- 用户级权限覆盖 +- Redis 实时权限变更广播 + +### 蓝牙策略 +- 各院区独立配置打卡策略 +- 必选/可选/禁用三级配置 +- 策略审批生效机制 + +### 扩展接口 (IModulePlugin) +- SPI 机制支持模块热插拔 +- 自定义菜单、路由、权限、数据表 +- 运行时模块启用/禁用 + +## API 规范 + +- RESTful 风格 +- 统一响应格式:`{ code, message, data, timestamp }` +- 分页响应:`{ list, pagination: { page, pageSize, total, totalPages } }` +- 错误码:5 位数字(4xxxx 客户端错误,5xxxx 服务端错误) + +## License + +Private — Internal Use Only diff --git a/backend/pom.xml b/backend/pom.xml new file mode 100644 index 0000000..e2dfe9a --- /dev/null +++ b/backend/pom.xml @@ -0,0 +1,216 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.2.5 + + + + com.hospital + hospital-mgmt + 1.0.0 + hospital-mgmt + 医院物业SaaS管理后台 + + + 17 + 3.5.6 + 0.12.5 + 5.12.0 + 5.8.26 + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-data-redis + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-aop + + + + + com.baomidou + mybatis-plus-spring-boot3-starter + ${mybatis-plus.version} + + + + + org.mariadb.jdbc + mariadb-java-client + runtime + + + + + io.jsonwebtoken + jjwt-api + ${jjwt.version} + + + io.jsonwebtoken + jjwt-impl + ${jjwt.version} + runtime + + + io.jsonwebtoken + jjwt-jackson + ${jjwt.version} + runtime + + + + + net.javacrumbs.shedlock + shedlock-spring + ${shedlock.version} + + + net.javacrumbs.shedlock + shedlock-provider-jdbc-template + ${shedlock.version} + + + + + cn.hutool + hutool-all + ${hutool.version} + + + + + org.projectlombok + lombok + true + + + + + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.5.0 + + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + + + com.h2database + h2 + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.version} + ${java.version} + + + org.projectlombok + lombok + ${lombok.version} + + + + + + org.jacoco + jacoco-maven-plugin + 0.8.12 + + + + prepare-agent + + + + report + test + + report + + + + + + + BUNDLE + + + LINE + COVEREDRATIO + 1.00 + + + BRANCH + COVEREDRATIO + 1.00 + + + + + + + + + diff --git a/backend/src/main/java/com/hospital/mgmt/HospitalMgmtApplication.java b/backend/src/main/java/com/hospital/mgmt/HospitalMgmtApplication.java new file mode 100644 index 0000000..9e3a2a8 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/HospitalMgmtApplication.java @@ -0,0 +1,14 @@ +package com.hospital.mgmt; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; + +@SpringBootApplication +@EnableScheduling +public class HospitalMgmtApplication { + + public static void main(String[] args) { + SpringApplication.run(HospitalMgmtApplication.class, args); + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/common/annotation/AuditLog.java b/backend/src/main/java/com/hospital/mgmt/common/annotation/AuditLog.java new file mode 100644 index 0000000..9413560 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/common/annotation/AuditLog.java @@ -0,0 +1,13 @@ +package com.hospital.mgmt.common.annotation; + +import java.lang.annotation.*; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface AuditLog { + String moduleCode(); + String moduleName(); + String operationType(); + String operationContent() default ""; +} diff --git a/backend/src/main/java/com/hospital/mgmt/common/annotation/ReadOnly.java b/backend/src/main/java/com/hospital/mgmt/common/annotation/ReadOnly.java new file mode 100644 index 0000000..6bbfa97 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/common/annotation/ReadOnly.java @@ -0,0 +1,9 @@ +package com.hospital.mgmt.common.annotation; + +import java.lang.annotation.*; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface ReadOnly { +} diff --git a/backend/src/main/java/com/hospital/mgmt/common/base/BaseEntity.java b/backend/src/main/java/com/hospital/mgmt/common/base/BaseEntity.java new file mode 100644 index 0000000..ce75f42 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/common/base/BaseEntity.java @@ -0,0 +1,33 @@ +package com.hospital.mgmt.common.base; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import java.io.Serializable; +import java.time.LocalDateTime; + +@Data +public abstract class BaseEntity implements Serializable { + @TableId(type = IdType.ASSIGN_ID) + private Long id; + + private Long tenantId; + private Long createdBy; + + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createdAt; + + private Long updatedBy; + + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updatedAt; + + @TableLogic + private Integer deleted; + + private Integer isSupplement; + private String supplementReason; + private String supplementRemark; + private String supplementAuditStatus; + private Long supplementAuditorId; + private LocalDateTime supplementAuditTime; +} diff --git a/backend/src/main/java/com/hospital/mgmt/common/context/TenantContext.java b/backend/src/main/java/com/hospital/mgmt/common/context/TenantContext.java new file mode 100644 index 0000000..42fc96d --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/common/context/TenantContext.java @@ -0,0 +1,46 @@ +package com.hospital.mgmt.common.context; + +import lombok.Data; + +@Data +public class TenantContext { + private Long userId; + private Long tenantId; + private String userType; + private Long hospitalId; + private Long propertyCompanyId; + private Long staffId; + + private static final ThreadLocal CONTEXT = new ThreadLocal<>(); + + public static void set(TenantContext context) { + CONTEXT.set(context); + } + + public static TenantContext get() { + return CONTEXT.get(); + } + + public static void clear() { + CONTEXT.remove(); + } + + public static Long getTenantId() { + TenantContext ctx = CONTEXT.get(); + return ctx != null ? ctx.getTenantId() : null; + } + + public static Long getUserId() { + TenantContext ctx = CONTEXT.get(); + return ctx != null ? ctx.getUserId() : null; + } + + public static String getUserType() { + TenantContext ctx = CONTEXT.get(); + return ctx != null ? ctx.getUserType() : null; + } + + public static boolean isSuperAdmin() { + return "SUPER_ADMIN".equals(getUserType()); + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/common/exception/BusinessException.java b/backend/src/main/java/com/hospital/mgmt/common/exception/BusinessException.java new file mode 100644 index 0000000..187e795 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/common/exception/BusinessException.java @@ -0,0 +1,23 @@ +package com.hospital.mgmt.common.exception; + +import lombok.Getter; + +@Getter +public class BusinessException extends RuntimeException { + private final int code; + + public BusinessException(int code, String message) { + super(message); + this.code = code; + } + + public BusinessException(ErrorCode errorCode) { + super(errorCode.getMessage()); + this.code = errorCode.getCode(); + } + + public BusinessException(ErrorCode errorCode, String message) { + super(message); + this.code = errorCode.getCode(); + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/common/exception/ErrorCode.java b/backend/src/main/java/com/hospital/mgmt/common/exception/ErrorCode.java new file mode 100644 index 0000000..ba0a205 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/common/exception/ErrorCode.java @@ -0,0 +1,26 @@ +package com.hospital.mgmt.common.exception; + +import lombok.Getter; + +@Getter +public enum ErrorCode { + SUCCESS(0, "成功"), + MISSING_PARAM(40001, "缺少必填参数"), + INVALID_PARAM(40002, "参数格式错误"), + UNAUTHORIZED(40100, "未认证"), + INVALID_TOKEN(40101, "Token无效"), + NO_PERMISSION(40300, "无功能权限"), + NO_DATA_PERMISSION(40301, "无数据权限"), + NOT_FOUND(40400, "资源不存在"), + STATUS_CONFLICT(40900, "状态冲突"), + DATA_EXISTS(40901, "数据已存在"), + INTERNAL_ERROR(50000, "服务器内部错误"); + + private final int code; + private final String message; + + ErrorCode(int code, String message) { + this.code = code; + this.message = message; + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/common/exception/GlobalExceptionHandler.java b/backend/src/main/java/com/hospital/mgmt/common/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..eb8d3d6 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/common/exception/GlobalExceptionHandler.java @@ -0,0 +1,70 @@ +package com.hospital.mgmt.common.exception; + +import com.hospital.mgmt.common.result.ApiResult; +import jakarta.validation.ConstraintViolationException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.validation.BindException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@Slf4j +@RestControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(BusinessException.class) + @ResponseStatus(HttpStatus.OK) + public ApiResult handleBusinessException(BusinessException e) { + log.warn("Business exception: code={}, message={}", e.getCode(), e.getMessage()); + return ApiResult.error(e.getCode(), e.getMessage()); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + @ResponseStatus(HttpStatus.OK) + public ApiResult handleValidationException(MethodArgumentNotValidException e) { + String message = e.getBindingResult().getFieldErrors().stream() + .map(f -> f.getField() + ": " + f.getDefaultMessage()) + .findFirst() + .orElse("参数校验失败"); + return ApiResult.error(ErrorCode.INVALID_PARAM.getCode(), message); + } + + @ExceptionHandler(BindException.class) + @ResponseStatus(HttpStatus.OK) + public ApiResult handleBindException(BindException e) { + String message = e.getFieldErrors().stream() + .map(f -> f.getField() + ": " + f.getDefaultMessage()) + .findFirst() + .orElse("参数绑定失败"); + return ApiResult.error(ErrorCode.INVALID_PARAM.getCode(), message); + } + + @ExceptionHandler(ConstraintViolationException.class) + @ResponseStatus(HttpStatus.OK) + public ApiResult handleConstraintViolation(ConstraintViolationException e) { + return ApiResult.error(ErrorCode.INVALID_PARAM.getCode(), e.getMessage()); + } + + @ExceptionHandler(AccessDeniedException.class) + @ResponseStatus(HttpStatus.FORBIDDEN) + public ApiResult handleAccessDenied(AccessDeniedException e) { + return ApiResult.error(ErrorCode.NO_PERMISSION.getCode(), ErrorCode.NO_PERMISSION.getMessage()); + } + + @ExceptionHandler(BadCredentialsException.class) + @ResponseStatus(HttpStatus.UNAUTHORIZED) + public ApiResult handleBadCredentials(BadCredentialsException e) { + return ApiResult.error(ErrorCode.UNAUTHORIZED.getCode(), "用户名或密码错误"); + } + + @ExceptionHandler(Exception.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public ApiResult handleException(Exception e) { + log.error("Unexpected error", e); + return ApiResult.error(ErrorCode.INTERNAL_ERROR.getCode(), ErrorCode.INTERNAL_ERROR.getMessage()); + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/common/result/ApiResult.java b/backend/src/main/java/com/hospital/mgmt/common/result/ApiResult.java new file mode 100644 index 0000000..d12888f --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/common/result/ApiResult.java @@ -0,0 +1,37 @@ +package com.hospital.mgmt.common.result; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; +import java.io.Serializable; + +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ApiResult implements Serializable { + private int code; + private String message; + private T data; + private Long timestamp; + + private ApiResult() {} + + public static ApiResult success(T data) { + ApiResult result = new ApiResult<>(); + result.setCode(0); + result.setMessage("success"); + result.setData(data); + result.setTimestamp(System.currentTimeMillis()); + return result; + } + + public static ApiResult success() { + return success(null); + } + + public static ApiResult error(int code, String message) { + ApiResult result = new ApiResult<>(); + result.setCode(code); + result.setMessage(message); + result.setTimestamp(System.currentTimeMillis()); + return result; + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/common/result/PageResult.java b/backend/src/main/java/com/hospital/mgmt/common/result/PageResult.java new file mode 100644 index 0000000..0550f91 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/common/result/PageResult.java @@ -0,0 +1,15 @@ +package com.hospital.mgmt.common.result; + +import lombok.Data; +import java.util.List; + +@Data +public class PageResult { + private List list; + private Pagination pagination; + + public PageResult(List list, int page, int pageSize, long total) { + this.list = list; + this.pagination = new Pagination(page, pageSize, total); + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/common/result/Pagination.java b/backend/src/main/java/com/hospital/mgmt/common/result/Pagination.java new file mode 100644 index 0000000..e50ac80 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/common/result/Pagination.java @@ -0,0 +1,19 @@ +package com.hospital.mgmt.common.result; + +import lombok.Data; +import java.io.Serializable; + +@Data +public class Pagination implements Serializable { + private int page; + private int pageSize; + private long total; + private int totalPages; + + public Pagination(int page, int pageSize, long total) { + this.page = page; + this.pageSize = pageSize; + this.total = total; + this.totalPages = (int) Math.ceil((double) total / pageSize); + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/config/AsyncConfig.java b/backend/src/main/java/com/hospital/mgmt/config/AsyncConfig.java new file mode 100644 index 0000000..fd62621 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/config/AsyncConfig.java @@ -0,0 +1,25 @@ +package com.hospital.mgmt.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.AsyncConfigurer; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import java.util.concurrent.Executor; + +@Configuration +@EnableAsync +public class AsyncConfig implements AsyncConfigurer { + + @Override + public Executor getAsyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(4); + executor.setMaxPoolSize(8); + executor.setQueueCapacity(1000); + executor.setKeepAliveSeconds(60); + executor.setThreadNamePrefix("async-"); + executor.setRejectedExecutionHandler(new java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy()); + executor.initialize(); + return executor; + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/config/MyBatisPlusConfig.java b/backend/src/main/java/com/hospital/mgmt/config/MyBatisPlusConfig.java new file mode 100644 index 0000000..de07306 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/config/MyBatisPlusConfig.java @@ -0,0 +1,44 @@ +package com.hospital.mgmt.config; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; +import com.hospital.mgmt.common.context.TenantContext; +import com.hospital.mgmt.security.TenantHandler; +import lombok.RequiredArgsConstructor; +import org.apache.ibatis.reflection.MetaObject; + +import java.time.LocalDateTime; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@RequiredArgsConstructor +public class MyBatisPlusConfig implements MetaObjectHandler { + + private final TenantHandler tenantHandler; + + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(tenantHandler)); + interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MARIADB)); + return interceptor; + } + + @Override + public void insertFill(MetaObject metaObject) { + this.strictInsertFill(metaObject, "createdAt", LocalDateTime.class, LocalDateTime.now()); + this.strictInsertFill(metaObject, "updatedAt", LocalDateTime.class, LocalDateTime.now()); + this.strictInsertFill(metaObject, "tenantId", Long.class, TenantContext.getTenantId()); + this.strictInsertFill(metaObject, "createdBy", Long.class, TenantContext.getUserId()); + } + + @Override + public void updateFill(MetaObject metaObject) { + this.strictUpdateFill(metaObject, "updatedAt", LocalDateTime.class, LocalDateTime.now()); + this.strictUpdateFill(metaObject, "updatedBy", Long.class, TenantContext.getUserId()); + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/config/RedisConfig.java b/backend/src/main/java/com/hospital/mgmt/config/RedisConfig.java new file mode 100644 index 0000000..02ae8d4 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/config/RedisConfig.java @@ -0,0 +1,23 @@ +package com.hospital.mgmt.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.listener.RedisMessageListenerContainer; + +@Configuration +public class RedisConfig { + + @Bean + public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory) { + RedisMessageListenerContainer container = new RedisMessageListenerContainer(); + container.setConnectionFactory(connectionFactory); + return container; + } + + @Bean + public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory connectionFactory) { + return new StringRedisTemplate(connectionFactory); + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/config/ShedLockConfig.java b/backend/src/main/java/com/hospital/mgmt/config/ShedLockConfig.java new file mode 100644 index 0000000..200faba --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/config/ShedLockConfig.java @@ -0,0 +1,25 @@ +package com.hospital.mgmt.config; + +import net.javacrumbs.shedlock.core.LockProvider; +import net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider; +import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.core.JdbcTemplate; + +import javax.sql.DataSource; + +@Configuration +@EnableSchedulerLock(defaultLockAtLeastFor = "PT1M", defaultLockAtMostFor = "PT30M") +public class ShedLockConfig { + + @Bean + public LockProvider lockProvider(DataSource dataSource) { + return new JdbcTemplateLockProvider( + JdbcTemplateLockProvider.Configuration.builder() + .withJdbcTemplate(new JdbcTemplate(dataSource)) + .withTableName("shedlock") + .build() + ); + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/config/WebMvcConfig.java b/backend/src/main/java/com/hospital/mgmt/config/WebMvcConfig.java new file mode 100644 index 0000000..3ce86cc --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/config/WebMvcConfig.java @@ -0,0 +1,19 @@ +package com.hospital.mgmt.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOriginPatterns("http://localhost:*") + .allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH") + .allowedHeaders("*") + .allowCredentials(true) + .maxAge(3600); + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/attendance/entity/AttendanceCheckPoint.java b/backend/src/main/java/com/hospital/mgmt/modules/attendance/entity/AttendanceCheckPoint.java new file mode 100644 index 0000000..71b4041 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/attendance/entity/AttendanceCheckPoint.java @@ -0,0 +1,19 @@ +package com.hospital.mgmt.modules.attendance.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("attendance_check_point") +public class AttendanceCheckPoint extends BaseEntity { + private String name; + private Long beaconId; + private Long hospitalId; + private Long campusId; + private String location; + private String teamIds; + private String status; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/attendance/entity/AttendanceRecord.java b/backend/src/main/java/com/hospital/mgmt/modules/attendance/entity/AttendanceRecord.java new file mode 100644 index 0000000..7b2dc62 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/attendance/entity/AttendanceRecord.java @@ -0,0 +1,32 @@ +package com.hospital.mgmt.modules.attendance.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("attendance_record") +public class AttendanceRecord extends BaseEntity { + private Long staffId; + private String staffName; + private LocalDate checkDate; + private String checkType; + private String checkMethod; + private LocalDateTime checkTime; + private Long checkPointId; + private Long beaconId; + private String beaconUuid; + private BigDecimal distance; + private String result; + private String abnormalType; + private String appealStatus; + private String appealReason; + private Long appealAuditorId; + private String appealAuditRemark; + private LocalDateTime appealAuditAt; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/attendance/entity/AttendanceRule.java b/backend/src/main/java/com/hospital/mgmt/modules/attendance/entity/AttendanceRule.java new file mode 100644 index 0000000..66ff0c5 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/attendance/entity/AttendanceRule.java @@ -0,0 +1,22 @@ +package com.hospital.mgmt.modules.attendance.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.time.LocalTime; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("attendance_rule") +public class AttendanceRule extends BaseEntity { + private String name; + private Long teamId; + private LocalTime workStartTime; + private LocalTime workEndTime; + private Integer startBufferMinutes; + private Integer endBufferMinutes; + private Integer lateThresholdMinutes; + private Integer earlyLeaveThresholdMinutes; + private String status; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/attendance/mapper/AttendanceRecordMapper.java b/backend/src/main/java/com/hospital/mgmt/modules/attendance/mapper/AttendanceRecordMapper.java new file mode 100644 index 0000000..33482ca --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/attendance/mapper/AttendanceRecordMapper.java @@ -0,0 +1,8 @@ +package com.hospital.mgmt.modules.attendance.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.hospital.mgmt.modules.attendance.entity.AttendanceRecord; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface AttendanceRecordMapper extends BaseMapper {} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/audit/entity/AuditLog.java b/backend/src/main/java/com/hospital/mgmt/modules/audit/entity/AuditLog.java new file mode 100644 index 0000000..b1d93c5 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/audit/entity/AuditLog.java @@ -0,0 +1,32 @@ +package com.hospital.mgmt.modules.audit.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.io.Serializable; +import java.time.LocalDateTime; + +@Data +@TableName("audit_log") +public class AuditLog implements Serializable { + private Long id; + private Long tenantId; + private Long operatorId; + private String operatorName; + private String operatorIp; + private String moduleCode; + private String moduleName; + private String pageCode; + private String pageName; + private String actionCode; + private String actionName; + private String operationType; + private String operationContent; + private Long businessId; + private String businessNo; + private String beforeData; + private String afterData; + private String requestParams; + private String responseStatus; + private String errorMessage; + private LocalDateTime operatedAt; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/audit/mapper/AuditLogMapper.java b/backend/src/main/java/com/hospital/mgmt/modules/audit/mapper/AuditLogMapper.java new file mode 100644 index 0000000..6fe5e9e --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/audit/mapper/AuditLogMapper.java @@ -0,0 +1,8 @@ +package com.hospital.mgmt.modules.audit.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.hospital.mgmt.modules.audit.entity.AuditLog; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface AuditLogMapper extends BaseMapper {} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/auth/controller/AuthController.java b/backend/src/main/java/com/hospital/mgmt/modules/auth/controller/AuthController.java new file mode 100644 index 0000000..94c0627 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/auth/controller/AuthController.java @@ -0,0 +1,39 @@ +package com.hospital.mgmt.modules.auth.controller; + +import com.hospital.mgmt.common.result.ApiResult; +import com.hospital.mgmt.modules.auth.dto.LoginRequest; +import com.hospital.mgmt.modules.auth.dto.LoginResponse; +import com.hospital.mgmt.modules.auth.dto.RefreshTokenRequest; +import com.hospital.mgmt.modules.auth.service.AuthService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +@Tag(name = "认证管理") +@RestController +@RequestMapping("/auth") +@RequiredArgsConstructor +public class AuthController { + + private final AuthService authService; + + @Operation(summary = "Web端账号登录") + @PostMapping("/login") + public ApiResult login(@Valid @RequestBody LoginRequest request) { + return ApiResult.success(authService.login(request)); + } + + @Operation(summary = "刷新Token") + @PostMapping("/refresh") + public ApiResult refresh(@Valid @RequestBody RefreshTokenRequest request) { + return ApiResult.success(authService.refreshToken(request.getRefreshToken())); + } + + @Operation(summary = "获取当前用户权限集") + @GetMapping("/permissions") + public ApiResult getPermissions() { + return ApiResult.success(authService.getCurrentUserPermissions()); + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/auth/dto/LoginRequest.java b/backend/src/main/java/com/hospital/mgmt/modules/auth/dto/LoginRequest.java new file mode 100644 index 0000000..866dec6 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/auth/dto/LoginRequest.java @@ -0,0 +1,13 @@ +package com.hospital.mgmt.modules.auth.dto; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +@Data +public class LoginRequest { + @NotBlank(message = "用户名不能为空") + private String username; + + @NotBlank(message = "密码不能为空") + private String password; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/auth/dto/LoginResponse.java b/backend/src/main/java/com/hospital/mgmt/modules/auth/dto/LoginResponse.java new file mode 100644 index 0000000..b05ca13 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/auth/dto/LoginResponse.java @@ -0,0 +1,28 @@ +package com.hospital.mgmt.modules.auth.dto; + +import lombok.Builder; +import lombok.Data; +import java.util.List; + +@Data +@Builder +public class LoginResponse { + private String accessToken; + private String refreshToken; + private long expiresIn; + private UserInfo user; + + @Data + @Builder + public static class UserInfo { + private Long id; + private String realName; + private String phone; + private String userType; + private String avatarUrl; + private Long tenantId; + private Long hospitalId; + private Long propertyCompanyId; + private List permissions; + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/auth/dto/RefreshTokenRequest.java b/backend/src/main/java/com/hospital/mgmt/modules/auth/dto/RefreshTokenRequest.java new file mode 100644 index 0000000..9c2ac85 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/auth/dto/RefreshTokenRequest.java @@ -0,0 +1,10 @@ +package com.hospital.mgmt.modules.auth.dto; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +@Data +public class RefreshTokenRequest { + @NotBlank(message = "refreshToken不能为空") + private String refreshToken; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/auth/service/AuthService.java b/backend/src/main/java/com/hospital/mgmt/modules/auth/service/AuthService.java new file mode 100644 index 0000000..fb97e50 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/auth/service/AuthService.java @@ -0,0 +1,97 @@ +package com.hospital.mgmt.modules.auth.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.hospital.mgmt.common.exception.BusinessException; +import com.hospital.mgmt.common.exception.ErrorCode; +import com.hospital.mgmt.modules.auth.dto.LoginRequest; +import com.hospital.mgmt.modules.auth.dto.LoginResponse; +import com.hospital.mgmt.modules.permission.entity.User; +import com.hospital.mgmt.modules.permission.mapper.UserMapper; +import com.hospital.mgmt.security.JwtTokenProvider; +import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +@RequiredArgsConstructor +public class AuthService { + + private final UserMapper userMapper; + private final PasswordEncoder passwordEncoder; + private final JwtTokenProvider jwtTokenProvider; + + public LoginResponse login(LoginRequest request) { + User user = userMapper.selectOne( + new LambdaQueryWrapper().eq(User::getUsername, request.getUsername()) + ); + if (user == null) { + throw new BusinessException(ErrorCode.UNAUTHORIZED, "用户名或密码错误"); + } + if (!passwordEncoder.matches(request.getPassword(), user.getPasswordHash())) { + throw new BusinessException(ErrorCode.UNAUTHORIZED, "用户名或密码错误"); + } + if ("DISABLED".equals(user.getStatus())) { + throw new BusinessException(ErrorCode.STATUS_CONFLICT, "账号已被禁用"); + } + + String accessToken = jwtTokenProvider.createAccessToken( + user.getId(), user.getTenantId(), user.getUserType(), + user.getHospitalId(), user.getPropertyCompanyId(), user.getStaffId() + ); + String refreshToken = jwtTokenProvider.createRefreshToken(user.getId()); + + return LoginResponse.builder() + .accessToken(accessToken) + .refreshToken(refreshToken) + .expiresIn(7200) + .user(LoginResponse.UserInfo.builder() + .id(user.getId()) + .realName(user.getRealName()) + .phone(user.getPhone()) + .userType(user.getUserType()) + .avatarUrl(user.getAvatarUrl()) + .tenantId(user.getTenantId()) + .hospitalId(user.getHospitalId()) + .propertyCompanyId(user.getPropertyCompanyId()) + .permissions(new ArrayList<>()) + .build()) + .build(); + } + + public LoginResponse refreshToken(String refreshToken) { + if (!jwtTokenProvider.validateToken(refreshToken)) { + throw new BusinessException(ErrorCode.INVALID_TOKEN, "refreshToken无效或已过期"); + } + Long userId = jwtTokenProvider.getUserIdFromToken(refreshToken); + User user = userMapper.selectById(userId); + if (user == null) { + throw new BusinessException(ErrorCode.NOT_FOUND, "用户不存在"); + } + + String newAccessToken = jwtTokenProvider.createAccessToken( + user.getId(), user.getTenantId(), user.getUserType(), + user.getHospitalId(), user.getPropertyCompanyId(), user.getStaffId() + ); + String newRefreshToken = jwtTokenProvider.createRefreshToken(user.getId()); + + return LoginResponse.builder() + .accessToken(newAccessToken) + .refreshToken(newRefreshToken) + .expiresIn(7200) + .build(); + } + + public Object getCurrentUserPermissions() { + // TODO: 从缓存或数据库加载完整权限集 + Map result = new HashMap<>(); + result.put("permissions", new ArrayList<>()); + result.put("menus", new ArrayList<>()); + result.put("dataScope", "SELF"); + return result; + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/bidding/entity/BiddingPlan.java b/backend/src/main/java/com/hospital/mgmt/modules/bidding/entity/BiddingPlan.java new file mode 100644 index 0000000..eea20c1 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/bidding/entity/BiddingPlan.java @@ -0,0 +1,24 @@ +package com.hospital.mgmt.modules.bidding.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.math.BigDecimal; +import java.time.LocalDate; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("bidding_plan") +public class BiddingPlan extends BaseEntity { + private String planNo; + private String title; + private String biddingType; + private Long hospitalId; + private BigDecimal budgetAmount; + private LocalDate publishDate; + private LocalDate deadlineDate; + private LocalDate openBidDate; + private String status; + private String description; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/bidding/entity/BiddingSection.java b/backend/src/main/java/com/hospital/mgmt/modules/bidding/entity/BiddingSection.java new file mode 100644 index 0000000..f59f8a7 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/bidding/entity/BiddingSection.java @@ -0,0 +1,21 @@ +package com.hospital.mgmt.modules.bidding.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.math.BigDecimal; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("bidding_section") +public class BiddingSection extends BaseEntity { + private Long planId; + private String sectionNo; + private String name; + private String scope; + private String requirements; + private BigDecimal budgetAmount; + private Long winnerSupplierId; + private String status; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/bidding/entity/BiddingSupplier.java b/backend/src/main/java/com/hospital/mgmt/modules/bidding/entity/BiddingSupplier.java new file mode 100644 index 0000000..a9ee2a5 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/bidding/entity/BiddingSupplier.java @@ -0,0 +1,20 @@ +package com.hospital.mgmt.modules.bidding.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("bidding_supplier") +public class BiddingSupplier extends BaseEntity { + private String name; + private String unifiedSocialCode; + private String contactPerson; + private String contactPhone; + private String address; + private String qualificationStatus; + private Integer blacklist; + private String remark; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/cleaning/entity/CleaningAttachment.java b/backend/src/main/java/com/hospital/mgmt/modules/cleaning/entity/CleaningAttachment.java new file mode 100644 index 0000000..b79ec77 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/cleaning/entity/CleaningAttachment.java @@ -0,0 +1,21 @@ +package com.hospital.mgmt.modules.cleaning.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.time.LocalDateTime; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("cleaning_attachment") +public class CleaningAttachment extends BaseEntity { + private Long taskId; + private String fileType; + private String fileUrl; + private String fileName; + private String uploadStage; + private LocalDateTime watermarkTime; + private String watermarkLocation; + private Integer bluetoothConnected; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/cleaning/entity/CleaningSchedule.java b/backend/src/main/java/com/hospital/mgmt/modules/cleaning/entity/CleaningSchedule.java new file mode 100644 index 0000000..a114552 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/cleaning/entity/CleaningSchedule.java @@ -0,0 +1,18 @@ +package com.hospital.mgmt.modules.cleaning.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.time.LocalDate; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("cleaning_schedule") +public class CleaningSchedule extends BaseEntity { + private Long areaId; + private Long staffId; + private LocalDate scheduleDate; + private String shiftType; + private String status; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/cleaning/entity/CleaningTask.java b/backend/src/main/java/com/hospital/mgmt/modules/cleaning/entity/CleaningTask.java new file mode 100644 index 0000000..9b0d30f --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/cleaning/entity/CleaningTask.java @@ -0,0 +1,35 @@ +package com.hospital.mgmt.modules.cleaning.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("cleaning_task") +public class CleaningTask extends BaseEntity { + private String taskNo; + private Long areaId; + private String areaName; + private String areaPath; + private Long assignedStaffId; + private String assignedStaffName; + private LocalDate taskDate; + private String taskType; + private String status; + private LocalDateTime checkInTime; + private Long checkInBeaconId; + private BigDecimal checkInDistance; + private String checkType; + private LocalDateTime completedAt; + private LocalDateTime timeoutAt; + private Integer isSpotChecked; + private String spotCheckResult; + private Long spotCheckerId; + private LocalDateTime spotCheckAt; + private String spotCheckRemark; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/cleaning/mapper/CleaningTaskMapper.java b/backend/src/main/java/com/hospital/mgmt/modules/cleaning/mapper/CleaningTaskMapper.java new file mode 100644 index 0000000..cb470ca --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/cleaning/mapper/CleaningTaskMapper.java @@ -0,0 +1,8 @@ +package com.hospital.mgmt.modules.cleaning.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.hospital.mgmt.modules.cleaning.entity.CleaningTask; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface CleaningTaskMapper extends BaseMapper {} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/contract/entity/Contract.java b/backend/src/main/java/com/hospital/mgmt/modules/contract/entity/Contract.java new file mode 100644 index 0000000..3c95910 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/contract/entity/Contract.java @@ -0,0 +1,30 @@ +package com.hospital.mgmt.modules.contract.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.math.BigDecimal; +import java.time.LocalDate; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("contract") +public class Contract extends BaseEntity { + private String contractNo; + private String title; + private String contractType; + private Long propertyCompanyId; + private Long hospitalId; + private Long campusId; + private BigDecimal totalAmount; + private LocalDate startDate; + private LocalDate endDate; + private String status; + private String paymentStatus; + private BigDecimal paidAmount; + private LocalDate signDate; + private String attachmentUrls; + private String remark; + private Integer warnDaysBefore; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/contract/entity/ContractChange.java b/backend/src/main/java/com/hospital/mgmt/modules/contract/entity/ContractChange.java new file mode 100644 index 0000000..91cfc81 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/contract/entity/ContractChange.java @@ -0,0 +1,23 @@ +package com.hospital.mgmt.modules.contract.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.time.LocalDateTime; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("contract_change") +public class ContractChange extends BaseEntity { + private Long contractId; + private String changeType; + private String changeContent; + private String beforeData; + private String afterData; + private Long applicantId; + private String auditStatus; + private Long auditorId; + private String auditRemark; + private LocalDateTime auditAt; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/contract/entity/ContractPayment.java b/backend/src/main/java/com/hospital/mgmt/modules/contract/entity/ContractPayment.java new file mode 100644 index 0000000..64b8a0f --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/contract/entity/ContractPayment.java @@ -0,0 +1,22 @@ +package com.hospital.mgmt.modules.contract.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.math.BigDecimal; +import java.time.LocalDate; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("contract_payment") +public class ContractPayment extends BaseEntity { + private Long contractId; + private String nodeName; + private BigDecimal amount; + private LocalDate planDate; + private LocalDate actualDate; + private String status; + private Long confirmerId; + private String confirmRemark; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/contract/mapper/ContractMapper.java b/backend/src/main/java/com/hospital/mgmt/modules/contract/mapper/ContractMapper.java new file mode 100644 index 0000000..02924e2 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/contract/mapper/ContractMapper.java @@ -0,0 +1,8 @@ +package com.hospital.mgmt.modules.contract.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.hospital.mgmt.modules.contract.entity.Contract; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface ContractMapper extends BaseMapper {} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/device/entity/DeviceBeacon.java b/backend/src/main/java/com/hospital/mgmt/modules/device/entity/DeviceBeacon.java new file mode 100644 index 0000000..7e4478a --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/device/entity/DeviceBeacon.java @@ -0,0 +1,32 @@ +package com.hospital.mgmt.modules.device.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("device_beacon") +public class DeviceBeacon extends BaseEntity { + private String uuid; + private Integer major; + private Integer minor; + private String name; + private String macAddress; + private Long hospitalId; + private Long campusId; + private String bindType; + private Long bindId; + private String location; + private BigDecimal latitude; + private BigDecimal longitude; + private Integer rssiThreshold; + private BigDecimal distanceThreshold; + private Integer batteryLevel; + private Integer batteryWarnThreshold; + private LocalDateTime lastHeartbeatAt; + private String status; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/device/mapper/DeviceBeaconMapper.java b/backend/src/main/java/com/hospital/mgmt/modules/device/mapper/DeviceBeaconMapper.java new file mode 100644 index 0000000..da38210 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/device/mapper/DeviceBeaconMapper.java @@ -0,0 +1,8 @@ +package com.hospital.mgmt.modules.device.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.hospital.mgmt.modules.device.entity.DeviceBeacon; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface DeviceBeaconMapper extends BaseMapper {} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/evaluation/entity/Evaluation.java b/backend/src/main/java/com/hospital/mgmt/modules/evaluation/entity/Evaluation.java new file mode 100644 index 0000000..71feb7f --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/evaluation/entity/Evaluation.java @@ -0,0 +1,26 @@ +package com.hospital.mgmt.modules.evaluation.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.time.LocalDateTime; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("evaluation") +public class Evaluation extends BaseEntity { + private String moduleType; + private Long businessId; + private String businessNo; + private Integer score; + private String content; + private Long evaluatorId; + private String evaluatorName; + private String evaluatorType; + private Long targetStaffId; + private Long targetTeamId; + private String replyContent; + private Long replierId; + private LocalDateTime repliedAt; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/evaluation/entity/EvaluationConfig.java b/backend/src/main/java/com/hospital/mgmt/modules/evaluation/entity/EvaluationConfig.java new file mode 100644 index 0000000..24fe60e --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/evaluation/entity/EvaluationConfig.java @@ -0,0 +1,18 @@ +package com.hospital.mgmt.modules.evaluation.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("evaluation_config") +public class EvaluationConfig extends BaseEntity { + private String moduleType; + private Integer autoTrigger; + private Integer triggerDelayMinutes; + private Integer lowScoreThreshold; + private String lowScoreNotifyType; + private Integer mustReplyHours; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/inspection/entity/InspectionAbnormal.java b/backend/src/main/java/com/hospital/mgmt/modules/inspection/entity/InspectionAbnormal.java new file mode 100644 index 0000000..ebdcf1a --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/inspection/entity/InspectionAbnormal.java @@ -0,0 +1,19 @@ +package com.hospital.mgmt.modules.inspection.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("inspection_abnormal") +public class InspectionAbnormal extends BaseEntity { + private Long taskId; + private Long areaId; + private String itemName; + private String severity; + private String description; + private Long repairOrderId; + private String status; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/inspection/entity/InspectionArea.java b/backend/src/main/java/com/hospital/mgmt/modules/inspection/entity/InspectionArea.java new file mode 100644 index 0000000..ac59d79 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/inspection/entity/InspectionArea.java @@ -0,0 +1,20 @@ +package com.hospital.mgmt.modules.inspection.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("inspection_area") +public class InspectionArea extends BaseEntity { + private String name; + private String code; + private Long hospitalId; + private Long campusId; + private Long parentId; + private Long beaconId; + private Integer sortOrder; + private String status; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/inspection/entity/InspectionAttachment.java b/backend/src/main/java/com/hospital/mgmt/modules/inspection/entity/InspectionAttachment.java new file mode 100644 index 0000000..d94b4c5 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/inspection/entity/InspectionAttachment.java @@ -0,0 +1,22 @@ +package com.hospital.mgmt.modules.inspection.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.time.LocalDateTime; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("inspection_attachment") +public class InspectionAttachment extends BaseEntity { + private Long taskId; + private Long abnormalId; + private String fileType; + private String fileUrl; + private String fileName; + private String uploadStage; + private LocalDateTime watermarkTime; + private String watermarkLocation; + private Integer bluetoothConnected; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/inspection/entity/InspectionPlan.java b/backend/src/main/java/com/hospital/mgmt/modules/inspection/entity/InspectionPlan.java new file mode 100644 index 0000000..97904c8 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/inspection/entity/InspectionPlan.java @@ -0,0 +1,25 @@ +package com.hospital.mgmt.modules.inspection.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.time.LocalDate; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("inspection_plan") +public class InspectionPlan extends BaseEntity { + private String name; + private Long areaId; + private String frequency; + private String frequencyConfig; + private Long teamId; + private String staffIds; + private String assignRule; + private String checkItems; + private LocalDate startDate; + private LocalDate endDate; + private Integer remindBefore; + private String status; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/inspection/entity/InspectionTask.java b/backend/src/main/java/com/hospital/mgmt/modules/inspection/entity/InspectionTask.java new file mode 100644 index 0000000..46e5fb7 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/inspection/entity/InspectionTask.java @@ -0,0 +1,35 @@ +package com.hospital.mgmt.modules.inspection.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("inspection_task") +public class InspectionTask extends BaseEntity { + private Long planId; + private String taskNo; + private Long areaId; + private String areaName; + private Long assignedStaffId; + private String assignedStaffName; + private LocalDate planDate; + private LocalTime planTimeStart; + private LocalTime planTimeEnd; + private String status; + private LocalDateTime checkInTime; + private Long checkInBeaconId; + private BigDecimal checkInLatitude; + private BigDecimal checkInLongitude; + private BigDecimal checkInDistance; + private String checkType; + private String checkResult; + private Integer abnormalCount; + private LocalDateTime completedAt; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/inspection/mapper/InspectionTaskMapper.java b/backend/src/main/java/com/hospital/mgmt/modules/inspection/mapper/InspectionTaskMapper.java new file mode 100644 index 0000000..65f0ce6 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/inspection/mapper/InspectionTaskMapper.java @@ -0,0 +1,8 @@ +package com.hospital.mgmt.modules.inspection.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.hospital.mgmt.modules.inspection.entity.InspectionTask; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface InspectionTaskMapper extends BaseMapper {} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/org/entity/CleaningArea.java b/backend/src/main/java/com/hospital/mgmt/modules/org/entity/CleaningArea.java new file mode 100644 index 0000000..5776811 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/org/entity/CleaningArea.java @@ -0,0 +1,22 @@ +package com.hospital.mgmt.modules.org.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("org_cleaning_area") +public class CleaningArea extends BaseEntity { + private Long parentId; + private Integer level; + private String name; + private String code; + private Long hospitalId; + private Long campusId; + private Long responsibleStaffId; + private Long beaconId; + private Integer sortOrder; + private String status; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/org/entity/Hospital.java b/backend/src/main/java/com/hospital/mgmt/modules/org/entity/Hospital.java new file mode 100644 index 0000000..f75d5e9 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/org/entity/Hospital.java @@ -0,0 +1,18 @@ +package com.hospital.mgmt.modules.org.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_hospital") +public class Hospital extends BaseEntity { + private String name; + private String address; + private String contactPerson; + private String contactPhone; + private String logoUrl; + private String status; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/org/entity/HospitalCampus.java b/backend/src/main/java/com/hospital/mgmt/modules/org/entity/HospitalCampus.java new file mode 100644 index 0000000..69d29c0 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/org/entity/HospitalCampus.java @@ -0,0 +1,17 @@ +package com.hospital.mgmt.modules.org.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.io.Serializable; + +@Data +@TableName("sys_hospital_campus") +public class HospitalCampus implements Serializable { + private Long id; + private Long hospitalId; + private String name; + private String address; + private String contactPerson; + private String contactPhone; + private Integer sortOrder; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/org/entity/PropertyCompany.java b/backend/src/main/java/com/hospital/mgmt/modules/org/entity/PropertyCompany.java new file mode 100644 index 0000000..a9c7e4e --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/org/entity/PropertyCompany.java @@ -0,0 +1,21 @@ +package com.hospital.mgmt.modules.org.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.io.Serializable; +import java.time.LocalDateTime; + +@Data +@TableName("sys_property_company") +public class PropertyCompany implements Serializable { + private Long id; + private String name; + private String address; + private String contactPerson; + private String contactPhone; + private String licenseNo; + private String logoUrl; + private String status; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/org/entity/PropertyHospital.java b/backend/src/main/java/com/hospital/mgmt/modules/org/entity/PropertyHospital.java new file mode 100644 index 0000000..516ef95 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/org/entity/PropertyHospital.java @@ -0,0 +1,19 @@ +package com.hospital.mgmt.modules.org.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.io.Serializable; +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Data +@TableName("sys_property_hospital") +public class PropertyHospital implements Serializable { + private Long id; + private Long propertyCompanyId; + private Long hospitalId; + private String campusIds; + private LocalDate startDate; + private LocalDate endDate; + private String status; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/org/entity/Staff.java b/backend/src/main/java/com/hospital/mgmt/modules/org/entity/Staff.java new file mode 100644 index 0000000..e7fdef8 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/org/entity/Staff.java @@ -0,0 +1,19 @@ +package com.hospital.mgmt.modules.org.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("org_staff") +public class Staff extends BaseEntity { + private String name; + private String phone; + private String gender; + private String avatarUrl; + private String employeeNo; + private String skills; + private String status; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/org/entity/StaffTeam.java b/backend/src/main/java/com/hospital/mgmt/modules/org/entity/StaffTeam.java new file mode 100644 index 0000000..5949e52 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/org/entity/StaffTeam.java @@ -0,0 +1,17 @@ +package com.hospital.mgmt.modules.org.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.io.Serializable; +import java.time.LocalDate; + +@Data +@TableName("org_staff_team") +public class StaffTeam implements Serializable { + private Long id; + private Long tenantId; + private Long staffId; + private Long teamId; + private Integer isPrimary; + private LocalDate joinDate; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/org/entity/Team.java b/backend/src/main/java/com/hospital/mgmt/modules/org/entity/Team.java new file mode 100644 index 0000000..fa8829b --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/org/entity/Team.java @@ -0,0 +1,20 @@ +package com.hospital.mgmt.modules.org.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("org_team") +public class Team extends BaseEntity { + private String name; + private String teamType; + private Long leaderId; + private Long hospitalId; + private Long campusId; + private String description; + private String skills; + private String status; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/org/mapper/HospitalCampusMapper.java b/backend/src/main/java/com/hospital/mgmt/modules/org/mapper/HospitalCampusMapper.java new file mode 100644 index 0000000..a04b755 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/org/mapper/HospitalCampusMapper.java @@ -0,0 +1,8 @@ +package com.hospital.mgmt.modules.org.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.hospital.mgmt.modules.org.entity.HospitalCampus; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface HospitalCampusMapper extends BaseMapper {} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/org/mapper/HospitalMapper.java b/backend/src/main/java/com/hospital/mgmt/modules/org/mapper/HospitalMapper.java new file mode 100644 index 0000000..451c6c4 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/org/mapper/HospitalMapper.java @@ -0,0 +1,8 @@ +package com.hospital.mgmt.modules.org.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.hospital.mgmt.modules.org.entity.Hospital; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface HospitalMapper extends BaseMapper {} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/org/mapper/PropertyCompanyMapper.java b/backend/src/main/java/com/hospital/mgmt/modules/org/mapper/PropertyCompanyMapper.java new file mode 100644 index 0000000..ae278ff --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/org/mapper/PropertyCompanyMapper.java @@ -0,0 +1,8 @@ +package com.hospital.mgmt.modules.org.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.hospital.mgmt.modules.org.entity.PropertyCompany; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface PropertyCompanyMapper extends BaseMapper {} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/org/mapper/StaffMapper.java b/backend/src/main/java/com/hospital/mgmt/modules/org/mapper/StaffMapper.java new file mode 100644 index 0000000..e19aaab --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/org/mapper/StaffMapper.java @@ -0,0 +1,8 @@ +package com.hospital.mgmt.modules.org.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.hospital.mgmt.modules.org.entity.Staff; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface StaffMapper extends BaseMapper {} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/org/mapper/TeamMapper.java b/backend/src/main/java/com/hospital/mgmt/modules/org/mapper/TeamMapper.java new file mode 100644 index 0000000..fd25eba --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/org/mapper/TeamMapper.java @@ -0,0 +1,8 @@ +package com.hospital.mgmt.modules.org.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.hospital.mgmt.modules.org.entity.Team; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface TeamMapper extends BaseMapper {} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/permission/entity/PermissionConfig.java b/backend/src/main/java/com/hospital/mgmt/modules/permission/entity/PermissionConfig.java new file mode 100644 index 0000000..f0b7ec0 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/permission/entity/PermissionConfig.java @@ -0,0 +1,24 @@ +package com.hospital.mgmt.modules.permission.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.io.Serializable; + +@Data +@TableName("sys_permission_config") +public class PermissionConfig implements Serializable { + private Long id; + private Long parentId; + private Integer level; + private String menuCode; + private String menuName; + private String pageCode; + private String pageName; + private String actionCode; + private String actionName; + private String operationCode; + private String operationName; + private Integer sortOrder; + private String moduleCode; + private String status; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/permission/entity/Role.java b/backend/src/main/java/com/hospital/mgmt/modules/permission/entity/Role.java new file mode 100644 index 0000000..f50d097 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/permission/entity/Role.java @@ -0,0 +1,19 @@ +package com.hospital.mgmt.modules.permission.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.io.Serializable; + +@Data +@TableName("sys_role") +public class Role implements Serializable { + private Long id; + private Long tenantId; + private String name; + private String code; + private String description; + private String scope; + private Integer isPreset; + private String dataScope; + private String status; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/permission/entity/RolePermission.java b/backend/src/main/java/com/hospital/mgmt/modules/permission/entity/RolePermission.java new file mode 100644 index 0000000..eb1a322 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/permission/entity/RolePermission.java @@ -0,0 +1,13 @@ +package com.hospital.mgmt.modules.permission.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.io.Serializable; + +@Data +@TableName("sys_role_permission") +public class RolePermission implements Serializable { + private Long id; + private Long roleId; + private Long permissionId; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/permission/entity/User.java b/backend/src/main/java/com/hospital/mgmt/modules/permission/entity/User.java new file mode 100644 index 0000000..e1c1e0b --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/permission/entity/User.java @@ -0,0 +1,28 @@ +package com.hospital.mgmt.modules.permission.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.io.Serializable; +import java.time.LocalDateTime; + +@Data +@TableName("sys_user") +public class User implements Serializable { + private Long id; + private Long tenantId; + private String username; + private String passwordHash; + private String userType; + private String realName; + private String phone; + private String email; + private String avatarUrl; + private Long hospitalId; + private Long propertyCompanyId; + private Long staffId; + private String wechatOpenid; + private String wechatUnionid; + private String status; + private LocalDateTime lastLoginAt; + private String lastLoginIp; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/permission/entity/UserPermissionOverride.java b/backend/src/main/java/com/hospital/mgmt/modules/permission/entity/UserPermissionOverride.java new file mode 100644 index 0000000..518df50 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/permission/entity/UserPermissionOverride.java @@ -0,0 +1,14 @@ +package com.hospital.mgmt.modules.permission.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.io.Serializable; + +@Data +@TableName("sys_user_permission_override") +public class UserPermissionOverride implements Serializable { + private Long id; + private Long userId; + private Long permissionId; + private String grantType; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/permission/entity/UserRole.java b/backend/src/main/java/com/hospital/mgmt/modules/permission/entity/UserRole.java new file mode 100644 index 0000000..88a8a35 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/permission/entity/UserRole.java @@ -0,0 +1,13 @@ +package com.hospital.mgmt.modules.permission.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.io.Serializable; + +@Data +@TableName("sys_user_role") +public class UserRole implements Serializable { + private Long id; + private Long userId; + private Long roleId; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/permission/mapper/PermissionConfigMapper.java b/backend/src/main/java/com/hospital/mgmt/modules/permission/mapper/PermissionConfigMapper.java new file mode 100644 index 0000000..ee573e4 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/permission/mapper/PermissionConfigMapper.java @@ -0,0 +1,8 @@ +package com.hospital.mgmt.modules.permission.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.hospital.mgmt.modules.permission.entity.PermissionConfig; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface PermissionConfigMapper extends BaseMapper {} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/permission/mapper/RoleMapper.java b/backend/src/main/java/com/hospital/mgmt/modules/permission/mapper/RoleMapper.java new file mode 100644 index 0000000..5be9afd --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/permission/mapper/RoleMapper.java @@ -0,0 +1,8 @@ +package com.hospital.mgmt.modules.permission.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.hospital.mgmt.modules.permission.entity.Role; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface RoleMapper extends BaseMapper {} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/permission/mapper/UserMapper.java b/backend/src/main/java/com/hospital/mgmt/modules/permission/mapper/UserMapper.java new file mode 100644 index 0000000..c3384f3 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/permission/mapper/UserMapper.java @@ -0,0 +1,8 @@ +package com.hospital.mgmt.modules.permission.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.hospital.mgmt.modules.permission.entity.User; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface UserMapper extends BaseMapper {} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/plugin/ConfigDefinition.java b/backend/src/main/java/com/hospital/mgmt/modules/plugin/ConfigDefinition.java new file mode 100644 index 0000000..9676a8b --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/plugin/ConfigDefinition.java @@ -0,0 +1,30 @@ +package com.hospital.mgmt.modules.plugin; + +import lombok.Builder; +import lombok.Data; +import java.util.List; + +@Data +@Builder +public class ConfigDefinition { + private String code; + private String name; + private String description; + private String valueType; + private Object defaultValue; + private List options; + private boolean tenantLevel; + private boolean required; + private String group; + + @Data + @Builder + public static class SelectOption { + private String value; + private String label; + + public static SelectOption of(String value, String label) { + return SelectOption.builder().value(value).label(label).build(); + } + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/plugin/IModulePlugin.java b/backend/src/main/java/com/hospital/mgmt/modules/plugin/IModulePlugin.java new file mode 100644 index 0000000..06d6a50 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/plugin/IModulePlugin.java @@ -0,0 +1,33 @@ +package com.hospital.mgmt.modules.plugin; + +import java.util.Collections; +import java.util.List; + +public interface IModulePlugin { + + ModuleInfo getModuleInfo(); + + List getMenuDefinitions(); + + List getPermissionDefinitions(); + + default List getRouteDefinitions() { + return Collections.emptyList(); + } + + default List getTableDefinitions() { + return Collections.emptyList(); + } + + default void onInitialize(ModuleContext context) {} + + default void onDestroy() {} + + default List getDependencies() { + return Collections.emptyList(); + } + + default List getConfigDefinitions() { + return Collections.emptyList(); + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/plugin/MenuDefinition.java b/backend/src/main/java/com/hospital/mgmt/modules/plugin/MenuDefinition.java new file mode 100644 index 0000000..2e6781f --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/plugin/MenuDefinition.java @@ -0,0 +1,20 @@ +package com.hospital.mgmt.modules.plugin; + +import lombok.Builder; +import lombok.Data; +import java.util.List; + +@Data +@Builder +public class MenuDefinition { + private String code; + private String name; + private String icon; + private String path; + private int sortOrder; + private boolean visible; + private String platform; + private List children; + private List scopeRestrictions; + private String externalLink; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/plugin/ModuleContext.java b/backend/src/main/java/com/hospital/mgmt/modules/plugin/ModuleContext.java new file mode 100644 index 0000000..7864691 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/plugin/ModuleContext.java @@ -0,0 +1,7 @@ +package com.hospital.mgmt.modules.plugin; + +public interface ModuleContext { + Long getTenantId(); + void subscribe(Class eventType, java.util.function.Consumer listener); + void scheduleCron(String cron, Runnable task); +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/plugin/ModuleInfo.java b/backend/src/main/java/com/hospital/mgmt/modules/plugin/ModuleInfo.java new file mode 100644 index 0000000..205b5e0 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/plugin/ModuleInfo.java @@ -0,0 +1,26 @@ +package com.hospital.mgmt.modules.plugin; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class ModuleInfo { + private String code; + private String name; + private String description; + private String version; + private String author; + private String icon; + private int sortOrder; + private boolean builtIn; + private boolean defaultEnabled; + private ModuleType type; + private String platform; + private String minSystemVersion; + private String homePath; + + public enum ModuleType { + CORE, BUSINESS, EXTENSION + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/plugin/PermissionDefinition.java b/backend/src/main/java/com/hospital/mgmt/modules/plugin/PermissionDefinition.java new file mode 100644 index 0000000..d6210b7 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/plugin/PermissionDefinition.java @@ -0,0 +1,46 @@ +package com.hospital.mgmt.modules.plugin; + +import lombok.Builder; +import lombok.Data; +import java.util.List; + +@Data +@Builder +public class PermissionDefinition { + private String menuCode; + private String menuName; + private List pages; + + @Data + @Builder + public static class PagePermission { + private String pageCode; + private String pageName; + private String pagePath; + private List actions; + } + + @Data + @Builder + public static class ActionPermission { + private String actionCode; + private String actionName; + private List operations; + } + + @Data + @Builder + public static class OperationDef { + private String operationCode; + private String operationName; + private boolean defaultGranted; + + public static OperationDef of(String code, String name, boolean defaultGranted) { + return OperationDef.builder() + .operationCode(code) + .operationName(name) + .defaultGranted(defaultGranted) + .build(); + } + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/plugin/RouteDefinition.java b/backend/src/main/java/com/hospital/mgmt/modules/plugin/RouteDefinition.java new file mode 100644 index 0000000..6d08742 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/plugin/RouteDefinition.java @@ -0,0 +1,28 @@ +package com.hospital.mgmt.modules.plugin; + +import lombok.Builder; +import lombok.Data; +import java.util.List; + +@Data +@Builder +public class RouteDefinition { + private String path; + private String name; + private String component; + private RouteMeta meta; + private List children; + private boolean requiresAuth; + private List allowedRoles; + + @Data + @Builder + public static class RouteMeta { + private String title; + private String icon; + private boolean keepAlive; + private boolean hidden; + private List breadcrumb; + private List permissions; + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/plugin/TableDefinition.java b/backend/src/main/java/com/hospital/mgmt/modules/plugin/TableDefinition.java new file mode 100644 index 0000000..5e543c4 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/plugin/TableDefinition.java @@ -0,0 +1,35 @@ +package com.hospital.mgmt.modules.plugin; + +import lombok.Builder; +import lombok.Data; +import java.util.List; + +@Data +@Builder +public class TableDefinition { + private String tableName; + private String description; + private List columns; + private List indexes; + private String initialDataSql; + + @Data + @Builder + public static class ColumnDefinition { + private String name; + private String dataType; + private boolean nullable; + private boolean primaryKey; + private String defaultValue; + private String comment; + private boolean tenantField; + } + + @Data + @Builder + public static class IndexDefinition { + private String name; + private List columns; + private boolean unique; + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/plugin/event/PermissionChangedEvent.java b/backend/src/main/java/com/hospital/mgmt/modules/plugin/event/PermissionChangedEvent.java new file mode 100644 index 0000000..98891b7 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/plugin/event/PermissionChangedEvent.java @@ -0,0 +1,15 @@ +package com.hospital.mgmt.modules.plugin.event; + +import lombok.Getter; +import java.time.LocalDateTime; + +@Getter +public class PermissionChangedEvent { + private final Long tenantId; + private final LocalDateTime timestamp; + + public PermissionChangedEvent(Long tenantId) { + this.tenantId = tenantId; + this.timestamp = LocalDateTime.now(); + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/plugin/listener/PermissionChangeListener.java b/backend/src/main/java/com/hospital/mgmt/modules/plugin/listener/PermissionChangeListener.java new file mode 100644 index 0000000..1aca6e7 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/plugin/listener/PermissionChangeListener.java @@ -0,0 +1,50 @@ +package com.hospital.mgmt.modules.plugin.listener; + +import com.hospital.mgmt.modules.plugin.event.PermissionChangedEvent; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.data.redis.connection.Message; +import org.springframework.data.redis.connection.MessageListener; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.listener.ChannelTopic; +import org.springframework.data.redis.listener.RedisMessageListenerContainer; +import org.springframework.stereotype.Component; + +import jakarta.annotation.PostConstruct; + +@Slf4j +@Component +@RequiredArgsConstructor +public class PermissionChangeListener implements MessageListener { + + private final StringRedisTemplate redisTemplate; + private final RedisMessageListenerContainer listenerContainer; + private final org.springframework.context.ApplicationEventPublisher eventPublisher; + + @PostConstruct + public void subscribe() { + listenerContainer.addMessageListener(this, new ChannelTopic("permission:changed")); + log.info("Subscribed to Redis channel: permission:changed"); + } + + @Override + public void onMessage(Message message, byte[] pattern) { + String channel = new String(message.getChannel()); + String body = new String(message.getBody()); + log.info("Received Redis message on channel: {}, body: {}", channel, body); + eventPublisher.publishEvent(new PermissionChangedEvent(null)); + } + + @EventListener + public void onPermissionChanged(PermissionChangedEvent event) { + log.info("Permission changed event received, refreshing local permission cache"); + // TODO: 刷新本地权限缓存 + } + + public void publishPermissionChange(Long tenantId) { + redisTemplate.convertAndSend("permission:changed", + String.valueOf(System.currentTimeMillis())); + log.info("Published permission change notification"); + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/repair/entity/RepairDelayApply.java b/backend/src/main/java/com/hospital/mgmt/modules/repair/entity/RepairDelayApply.java new file mode 100644 index 0000000..d67ab24 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/repair/entity/RepairDelayApply.java @@ -0,0 +1,21 @@ +package com.hospital.mgmt.modules.repair.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.time.LocalDateTime; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("repair_delay_apply") +public class RepairDelayApply extends BaseEntity { + private Long orderId; + private Long applicantId; + private String reason; + private LocalDateTime expectedFinishAt; + private String auditStatus; + private Long auditorId; + private String auditRemark; + private LocalDateTime auditAt; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/repair/entity/RepairOrder.java b/backend/src/main/java/com/hospital/mgmt/modules/repair/entity/RepairOrder.java new file mode 100644 index 0000000..fe1f242 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/repair/entity/RepairOrder.java @@ -0,0 +1,40 @@ +package com.hospital.mgmt.modules.repair.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("repair_order") +public class RepairOrder extends BaseEntity { + private String orderNo; + private Long repairTypeId; + private String title; + private String description; + private String urgency; + private String status; + private Long hospitalId; + private Long campusId; + private String location; + private String locationDetail; + private Long reporterId; + private String reporterType; + private String reporterName; + private String reporterPhone; + private Long assignedTeamId; + private Long assignedStaffId; + private LocalDateTime assignedAt; + private LocalDateTime expectedFinishAt; + private LocalDateTime actualFinishAt; + private LocalDateTime completedAt; + private LocalDateTime closedAt; + private String closeReason; + private Long parentOrderId; + private Integer isAssist; + private Integer remindCount; + private LocalDateTime lastRemindAt; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/repair/entity/RepairOrderAttachment.java b/backend/src/main/java/com/hospital/mgmt/modules/repair/entity/RepairOrderAttachment.java new file mode 100644 index 0000000..42f22ac --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/repair/entity/RepairOrderAttachment.java @@ -0,0 +1,22 @@ +package com.hospital.mgmt.modules.repair.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.time.LocalDateTime; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("repair_order_attachment") +public class RepairOrderAttachment extends BaseEntity { + private Long orderId; + private String fileType; + private String fileUrl; + private String fileName; + private Long fileSize; + private String uploadStage; + private LocalDateTime watermarkTime; + private String watermarkLocation; + private Integer sortOrder; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/repair/entity/RepairOrderLog.java b/backend/src/main/java/com/hospital/mgmt/modules/repair/entity/RepairOrderLog.java new file mode 100644 index 0000000..884e5eb --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/repair/entity/RepairOrderLog.java @@ -0,0 +1,21 @@ +package com.hospital.mgmt.modules.repair.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.time.LocalDateTime; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("repair_order_log") +public class RepairOrderLog extends BaseEntity { + private Long orderId; + private String fromStatus; + private String toStatus; + private String action; + private Long operatorId; + private String operatorName; + private String remark; + private LocalDateTime operatedAt; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/repair/entity/RepairType.java b/backend/src/main/java/com/hospital/mgmt/modules/repair/entity/RepairType.java new file mode 100644 index 0000000..ef76d42 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/repair/entity/RepairType.java @@ -0,0 +1,19 @@ +package com.hospital.mgmt.modules.repair.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.time.LocalDateTime; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("repair_type") +public class RepairType extends BaseEntity { + private String name; + private String code; + private Long defaultTeamId; + private String iconUrl; + private Integer sortOrder; + private String status; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/repair/mapper/RepairOrderMapper.java b/backend/src/main/java/com/hospital/mgmt/modules/repair/mapper/RepairOrderMapper.java new file mode 100644 index 0000000..db3af8b --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/repair/mapper/RepairOrderMapper.java @@ -0,0 +1,8 @@ +package com.hospital.mgmt.modules.repair.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.hospital.mgmt.modules.repair.entity.RepairOrder; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface RepairOrderMapper extends BaseMapper {} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/system/entity/BluetoothPolicy.java b/backend/src/main/java/com/hospital/mgmt/modules/system/entity/BluetoothPolicy.java new file mode 100644 index 0000000..d3e4ecb --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/system/entity/BluetoothPolicy.java @@ -0,0 +1,25 @@ +package com.hospital.mgmt.modules.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_bluetooth_policy") +public class BluetoothPolicy extends BaseEntity { + private Long hospitalId; + private Long campusId; + private String inspectionCheckIn; + private String inspectionPhoto; + private String cleaningCheckIn; + private String cleaningPhoto; + private String attendanceCheck; + private String auditStatus; + private String auditRemark; + private Long auditorId; + private java.time.LocalDateTime auditAt; + private java.time.LocalDateTime effectiveAt; + private String status; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/system/entity/DictData.java b/backend/src/main/java/com/hospital/mgmt/modules/system/entity/DictData.java new file mode 100644 index 0000000..692b65e --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/system/entity/DictData.java @@ -0,0 +1,17 @@ +package com.hospital.mgmt.modules.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.io.Serializable; + +@Data +@TableName("sys_dict_data") +public class DictData implements Serializable { + private Long id; + private Long tenantId; + private String typeCode; + private String label; + private String value; + private Integer sortOrder; + private String status; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/system/entity/DictType.java b/backend/src/main/java/com/hospital/mgmt/modules/system/entity/DictType.java new file mode 100644 index 0000000..913b497 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/system/entity/DictType.java @@ -0,0 +1,15 @@ +package com.hospital.mgmt.modules.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.io.Serializable; + +@Data +@TableName("sys_dict_type") +public class DictType implements Serializable { + private Long id; + private Long tenantId; + private String code; + private String name; + private String status; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/system/entity/MessageTemplate.java b/backend/src/main/java/com/hospital/mgmt/modules/system/entity/MessageTemplate.java new file mode 100644 index 0000000..e851a56 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/system/entity/MessageTemplate.java @@ -0,0 +1,19 @@ +package com.hospital.mgmt.modules.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hospital.mgmt.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_message_template") +public class MessageTemplate extends BaseEntity { + private String code; + private String name; + private String channel; + private String templateId; + private String title; + private String content; + private String status; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/system/entity/TenantModule.java b/backend/src/main/java/com/hospital/mgmt/modules/system/entity/TenantModule.java new file mode 100644 index 0000000..8ce6109 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/system/entity/TenantModule.java @@ -0,0 +1,17 @@ +package com.hospital.mgmt.modules.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.io.Serializable; + +@Data +@TableName("sys_tenant_module") +public class TenantModule implements Serializable { + private Long id; + private Long tenantId; + private String moduleCode; + private Integer enabled; + private java.time.LocalDateTime enabledAt; + private Long enabledBy; + private String configData; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/system/entity/Version.java b/backend/src/main/java/com/hospital/mgmt/modules/system/entity/Version.java new file mode 100644 index 0000000..f20aaba --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/system/entity/Version.java @@ -0,0 +1,20 @@ +package com.hospital.mgmt.modules.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.io.Serializable; +import java.time.LocalDateTime; + +@Data +@TableName("sys_version") +public class Version implements Serializable { + private Long id; + private String platform; + private String versionNo; + private String minCompatibleVersion; + private String updateType; + private String releaseNotes; + private Integer forceUpdate; + private LocalDateTime publishedAt; + private String status; +} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/system/mapper/BluetoothPolicyMapper.java b/backend/src/main/java/com/hospital/mgmt/modules/system/mapper/BluetoothPolicyMapper.java new file mode 100644 index 0000000..bf899a8 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/system/mapper/BluetoothPolicyMapper.java @@ -0,0 +1,8 @@ +package com.hospital.mgmt.modules.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.hospital.mgmt.modules.system.entity.BluetoothPolicy; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface BluetoothPolicyMapper extends BaseMapper {} diff --git a/backend/src/main/java/com/hospital/mgmt/modules/system/mapper/DictTypeMapper.java b/backend/src/main/java/com/hospital/mgmt/modules/system/mapper/DictTypeMapper.java new file mode 100644 index 0000000..59ba53f --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/modules/system/mapper/DictTypeMapper.java @@ -0,0 +1,8 @@ +package com.hospital.mgmt.modules.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.hospital.mgmt.modules.system.entity.DictType; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface DictTypeMapper extends BaseMapper {} diff --git a/backend/src/main/java/com/hospital/mgmt/security/JwtAuthenticationFilter.java b/backend/src/main/java/com/hospital/mgmt/security/JwtAuthenticationFilter.java new file mode 100644 index 0000000..5db325d --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/security/JwtAuthenticationFilter.java @@ -0,0 +1,81 @@ +package com.hospital.mgmt.security; + +import com.hospital.mgmt.common.context.TenantContext; +import com.hospital.mgmt.common.exception.BusinessException; +import com.hospital.mgmt.common.exception.ErrorCode; +import io.jsonwebtoken.Claims; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +@Slf4j +@Component +@RequiredArgsConstructor +public class JwtAuthenticationFilter extends OncePerRequestFilter { + + private final JwtTokenProvider jwtTokenProvider; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, + FilterChain filterChain) throws ServletException, IOException { + String token = resolveToken(request); + + if (StringUtils.hasText(token) && jwtTokenProvider.validateToken(token)) { + try { + Claims claims = jwtTokenProvider.parseToken(token); + Long userId = Long.parseLong(claims.getSubject()); + Long tenantId = claims.get("tid", Long.class); + String userType = claims.get("utype", String.class); + Long hospitalId = claims.get("hid", Long.class); + Long propertyCompanyId = claims.get("pid", Long.class); + Long staffId = claims.get("sid", Long.class); + + // 设置租户上下文 + TenantContext ctx = new TenantContext(); + ctx.setUserId(userId); + ctx.setTenantId(tenantId); + ctx.setUserType(userType); + ctx.setHospitalId(hospitalId); + ctx.setPropertyCompanyId(propertyCompanyId); + ctx.setStaffId(staffId); + TenantContext.set(ctx); + + // 设置Spring Security上下文 + List authorities = new ArrayList<>(); + UsernamePasswordAuthenticationToken authentication = + new UsernamePasswordAuthenticationToken(userId, null, authorities); + SecurityContextHolder.getContext().setAuthentication(authentication); + + } catch (Exception e) { + log.error("Cannot set user authentication: {}", e.getMessage()); + } + } + + try { + filterChain.doFilter(request, response); + } finally { + TenantContext.clear(); + } + } + + private String resolveToken(HttpServletRequest request) { + String bearerToken = request.getHeader("Authorization"); + if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { + return bearerToken.substring(7); + } + return null; + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/security/JwtTokenProvider.java b/backend/src/main/java/com/hospital/mgmt/security/JwtTokenProvider.java new file mode 100644 index 0000000..8907bb3 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/security/JwtTokenProvider.java @@ -0,0 +1,81 @@ +package com.hospital.mgmt.security; + +import io.jsonwebtoken.*; +import io.jsonwebtoken.security.Keys; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.crypto.SecretKey; +import java.nio.charset.StandardCharsets; +import java.util.Date; + +@Component +public class JwtTokenProvider { + + private final SecretKey key; + private final long expiration; + private final long refreshExpiration; + + public JwtTokenProvider( + @Value("${jwt.secret}") String secret, + @Value("${jwt.expiration}") long expiration, + @Value("${jwt.refresh-expiration}") long refreshExpiration + ) { + this.key = Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8)); + this.expiration = expiration * 1000; + this.refreshExpiration = refreshExpiration * 1000; + } + + public String createAccessToken(Long userId, Long tenantId, String userType, + Long hospitalId, Long propertyCompanyId, Long staffId) { + Date now = new Date(); + Date expiryDate = new Date(now.getTime() + expiration); + + return Jwts.builder() + .subject(String.valueOf(userId)) + .claim("tid", tenantId) + .claim("utype", userType) + .claim("hid", hospitalId) + .claim("pid", propertyCompanyId) + .claim("sid", staffId) + .issuedAt(now) + .expiration(expiryDate) + .signWith(key) + .compact(); + } + + public String createRefreshToken(Long userId) { + Date now = new Date(); + Date expiryDate = new Date(now.getTime() + refreshExpiration); + + return Jwts.builder() + .subject(String.valueOf(userId)) + .claim("type", "refresh") + .issuedAt(now) + .expiration(expiryDate) + .signWith(key) + .compact(); + } + + public Claims parseToken(String token) { + return Jwts.parser() + .verifyWith(key) + .build() + .parseSignedClaims(token) + .getPayload(); + } + + public boolean validateToken(String token) { + try { + parseToken(token); + return true; + } catch (JwtException | IllegalArgumentException e) { + return false; + } + } + + public Long getUserIdFromToken(String token) { + Claims claims = parseToken(token); + return Long.parseLong(claims.getSubject()); + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/security/RestAccessDeniedHandler.java b/backend/src/main/java/com/hospital/mgmt/security/RestAccessDeniedHandler.java new file mode 100644 index 0000000..703a586 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/security/RestAccessDeniedHandler.java @@ -0,0 +1,31 @@ +package com.hospital.mgmt.security; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.hospital.mgmt.common.result.ApiResult; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.stereotype.Component; + +import java.io.IOException; + +@Component +@RequiredArgsConstructor +public class RestAccessDeniedHandler implements AccessDeniedHandler { + + private final ObjectMapper objectMapper; + + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, + AccessDeniedException accessDeniedException) throws IOException { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + response.setContentType(MediaType.APPLICATION_JSON_VALUE); + response.setCharacterEncoding("UTF-8"); + + ApiResult result = ApiResult.error(40300, "无权限访问"); + response.getWriter().write(objectMapper.writeValueAsString(result)); + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/security/RestAuthenticationEntryPoint.java b/backend/src/main/java/com/hospital/mgmt/security/RestAuthenticationEntryPoint.java new file mode 100644 index 0000000..9305170 --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/security/RestAuthenticationEntryPoint.java @@ -0,0 +1,31 @@ +package com.hospital.mgmt.security; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.hospital.mgmt.common.result.ApiResult; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import java.io.IOException; + +@Component +@RequiredArgsConstructor +public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint { + + private final ObjectMapper objectMapper; + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, + AuthenticationException authException) throws IOException { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.setContentType(MediaType.APPLICATION_JSON_VALUE); + response.setCharacterEncoding("UTF-8"); + + ApiResult result = ApiResult.error(40100, "未认证或Token已过期"); + response.getWriter().write(objectMapper.writeValueAsString(result)); + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/security/SecurityConfig.java b/backend/src/main/java/com/hospital/mgmt/security/SecurityConfig.java new file mode 100644 index 0000000..3f1c68a --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/security/SecurityConfig.java @@ -0,0 +1,57 @@ +package com.hospital.mgmt.security; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +@Configuration +@EnableWebSecurity +@EnableMethodSecurity +@RequiredArgsConstructor +public class SecurityConfig { + + private final JwtAuthenticationFilter jwtAuthenticationFilter; + private final RestAuthenticationEntryPoint authenticationEntryPoint; + private final RestAccessDeniedHandler accessDeniedHandler; + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http + .csrf(AbstractHttpConfigurer::disable) + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .exceptionHandling(ex -> ex + .authenticationEntryPoint(authenticationEntryPoint) + .accessDeniedHandler(accessDeniedHandler) + ) + .authorizeHttpRequests(auth -> auth + .requestMatchers("/auth/login", "/auth/wechat/login", "/auth/refresh").permitAll() + .requestMatchers("/swagger-ui/**", "/swagger-docs/**", "/v3/api-docs/**").permitAll() + .requestMatchers("/actuator/**").permitAll() + .anyRequest().authenticated() + ) + .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); + + return http.build(); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Bean + public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception { + return config.getAuthenticationManager(); + } +} diff --git a/backend/src/main/java/com/hospital/mgmt/security/TenantHandler.java b/backend/src/main/java/com/hospital/mgmt/security/TenantHandler.java new file mode 100644 index 0000000..40c78bf --- /dev/null +++ b/backend/src/main/java/com/hospital/mgmt/security/TenantHandler.java @@ -0,0 +1,45 @@ +package com.hospital.mgmt.security; + +import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; +import com.hospital.mgmt.common.context.TenantContext; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.LongValue; +import net.sf.jsqlparser.expression.NullValue; +import org.springframework.stereotype.Component; + +@Component +public class TenantHandler implements TenantLineHandler { + + @Override + public Expression getTenantId() { + Long tenantId = TenantContext.getTenantId(); + if (tenantId != null) { + return new LongValue(tenantId); + } + return new NullValue(); + } + + @Override + public boolean ignoreTable(String tableName) { + // 超管忽略租户隔离 + if (TenantContext.isSuperAdmin()) { + return true; + } + // 不需要租户隔离的表 + return tableName.startsWith("sys_hospital") + || tableName.startsWith("sys_property_company") + || tableName.startsWith("sys_property_hospital") + || tableName.startsWith("sys_permission_config") + || tableName.startsWith("sys_bluetooth_policy") + || tableName.startsWith("sys_dict_type") + || tableName.startsWith("sys_dict_data") + || tableName.startsWith("sys_version") + || tableName.startsWith("shedlock") + || tableName.startsWith("audit_log"); + } + + @Override + public String getTenantIdColumn() { + return "tenant_id"; + } +} diff --git a/backend/src/main/resources/application-prod.yml b/backend/src/main/resources/application-prod.yml new file mode 100644 index 0000000..20b8896 --- /dev/null +++ b/backend/src/main/resources/application-prod.yml @@ -0,0 +1,76 @@ +server: + port: 8080 + servlet: + context-path: /api/v1 + +spring: + application: + name: hospital-mgmt + datasource: + driver-class-name: org.mariadb.jdbc.Driver + hikari: + maximum-pool-size: 20 + minimum-idle: 10 + idle-timeout: 600000 + max-lifetime: 1800000 + data: + redis: + lettuce: + pool: + max-active: 16 + max-idle: 8 + min-idle: 4 + jackson: + date-format: yyyy-MM-dd HH:mm:ss + time-zone: Asia/Shanghai + serialization: + write-dates-as-timestamps: false + default-property-inclusion: non_null + +mybatis-plus: + configuration: + map-underscore-to-camel-case: true + global-config: + db-config: + id-type: assign_id + logic-delete-field: deleted + logic-delete-value: 1 + logic-not-delete-value: 0 + mapper-locations: classpath*:mapper/**/*.xml + +jwt: + expiration: 7200 + refresh-expiration: 604800 + +bluetooth: + rssi-threshold: -70 + distance-threshold: 5 + scan-timeout: 3 + +permission: + redis-channel: permission:changed + +async: + pool: + core-size: 4 + max-size: 8 + queue-capacity: 1000 + +upload: + max-size: 20 + +springdoc: + api-docs: + path: /swagger-docs + swagger-ui: + path: /swagger-ui.html + +logging: + level: + com.hospital.mgmt: INFO + file: + name: /app/logs/hospital-mgmt.log + logback: + rollingpolicy: + max-file-size: 50MB + max-history: 30 diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml new file mode 100644 index 0000000..65a71e9 --- /dev/null +++ b/backend/src/main/resources/application.yml @@ -0,0 +1,79 @@ +server: + port: 8080 + servlet: + context-path: /api/v1 + +spring: + application: + name: hospital-mgmt + datasource: + driver-class-name: org.mariadb.jdbc.Driver + url: jdbc:mariadb://localhost:3306/hospital_mgmt?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=Asia/Shanghai + username: root + password: root + hikari: + maximum-pool-size: 9 + minimum-idle: 5 + idle-timeout: 600000 + max-lifetime: 1800000 + data: + redis: + host: ${REDIS_HOST:localhost} + port: ${REDIS_PORT:6379} + password: ${REDIS_PASSWORD:} + lettuce: + pool: + max-active: 8 + max-idle: 8 + min-idle: 2 + jackson: + date-format: yyyy-MM-dd HH:mm:ss + time-zone: Asia/Shanghai + serialization: + write-dates-as-timestamps: false + default-property-inclusion: non_null + +mybatis-plus: + configuration: + map-underscore-to-camel-case: true + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + global-config: + db-config: + id-type: assign_id + logic-delete-field: deleted + logic-delete-value: 1 + logic-not-delete-value: 0 + mapper-locations: classpath*:mapper/**/*.xml + +jwt: + secret: ${JWT_SECRET:a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6} + expiration: 7200 + refresh-expiration: 604800 + +bluetooth: + rssi-threshold: -70 + distance-threshold: 5 + scan-timeout: 3 + +permission: + redis-channel: permission:changed + +async: + pool: + core-size: 4 + max-size: 8 + queue-capacity: 1000 + +upload: + max-size: 20 + +springdoc: + api-docs: + path: /swagger-docs + swagger-ui: + path: /swagger-ui.html + +logging: + level: + com.hospital.mgmt: DEBUG + org.springframework.security: DEBUG diff --git a/backend/src/main/resources/db/init.sql b/backend/src/main/resources/db/init.sql new file mode 100644 index 0000000..e2ff0fb --- /dev/null +++ b/backend/src/main/resources/db/init.sql @@ -0,0 +1,790 @@ +-- 医院物业SaaS管理后台 - 数据库初始化脚本 +-- MariaDB 10.6+ +-- 日期: 2026-04-16 + +CREATE DATABASE IF NOT EXISTS hospital_mgmt DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +USE hospital_mgmt; + +-- ==================== 租户与组织架构 ==================== + +CREATE TABLE IF NOT EXISTS sys_hospital ( + id BIGINT PRIMARY KEY, + name VARCHAR(100) NOT NULL COMMENT '医院名称', + address VARCHAR(255) COMMENT '医院地址', + contact_person VARCHAR(50) COMMENT '联系人', + contact_phone VARCHAR(20) COMMENT '联系电话', + logo_url VARCHAR(500) COMMENT 'Logo URL', + status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '状态: ACTIVE/DISABLED', + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) COMMENT '医院信息表'; + +CREATE TABLE IF NOT EXISTS sys_hospital_campus ( + id BIGINT PRIMARY KEY, + hospital_id BIGINT NOT NULL COMMENT '关联医院ID', + name VARCHAR(100) NOT NULL COMMENT '院区名称', + address VARCHAR(255) COMMENT '院区地址', + contact_person VARCHAR(50) COMMENT '院区联系人', + contact_phone VARCHAR(20) COMMENT '院区联系电话', + sort_order INT DEFAULT 0 COMMENT '排序号', + INDEX idx_hospital_id (hospital_id) +) COMMENT '医院院区表'; + +CREATE TABLE IF NOT EXISTS sys_property_company ( + id BIGINT PRIMARY KEY COMMENT '主键,同时作为tenant_id', + name VARCHAR(100) NOT NULL COMMENT '公司名称', + address VARCHAR(255) COMMENT '公司地址', + contact_person VARCHAR(50) COMMENT '联系人', + contact_phone VARCHAR(20) COMMENT '联系电话', + license_no VARCHAR(50) COMMENT '营业执照号', + logo_url VARCHAR(500) COMMENT '公司Logo URL', + status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '状态: ACTIVE/DISABLED', + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) COMMENT '物业公司表'; + +CREATE TABLE IF NOT EXISTS sys_property_hospital ( + id BIGINT PRIMARY KEY, + property_company_id BIGINT NOT NULL COMMENT '物业公司ID', + hospital_id BIGINT NOT NULL COMMENT '医院ID', + campus_ids JSON COMMENT '关联院区ID列表', + start_date DATE COMMENT '服务开始日期', + end_date DATE COMMENT '服务结束日期', + status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '状态: ACTIVE/EXPIRED/TERMINATED', + INDEX idx_property_company (property_company_id), + INDEX idx_hospital (hospital_id) +) COMMENT '物业-医院关联表'; + +-- ==================== 组织架构 ==================== + +CREATE TABLE IF NOT EXISTS org_team ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL COMMENT '租户ID', + name VARCHAR(100) NOT NULL COMMENT '班组名称', + team_type VARCHAR(30) NOT NULL COMMENT '班组类型: REPAIR/INSPECTION/CLEANING/ESCORT/OTHER', + leader_id BIGINT COMMENT '班组长ID', + hospital_id BIGINT NOT NULL COMMENT '关联医院ID', + campus_id BIGINT COMMENT '关联院区ID', + description VARCHAR(500) COMMENT '班组描述', + skills JSON COMMENT '班组技能标签列表', + status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '状态: ACTIVE/DISABLED', + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_tenant_id (tenant_id) +) COMMENT '班组表'; + +CREATE TABLE IF NOT EXISTS org_staff ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL COMMENT '租户ID', + name VARCHAR(50) NOT NULL COMMENT '姓名', + phone VARCHAR(20) NOT NULL COMMENT '手机号', + gender VARCHAR(10) COMMENT '性别: MALE/FEMALE', + avatar_url VARCHAR(500) COMMENT '头像URL', + employee_no VARCHAR(50) COMMENT '工号', + skills JSON COMMENT '技能标签列表', + status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '状态: ACTIVE/DISABLED', + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_tenant_id (tenant_id) +) COMMENT '员工表'; + +CREATE TABLE IF NOT EXISTS org_staff_team ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + staff_id BIGINT NOT NULL COMMENT '员工ID', + team_id BIGINT NOT NULL COMMENT '班组ID', + is_primary TINYINT NOT NULL DEFAULT 1 COMMENT '是否主班组: 0-否, 1-是', + join_date DATE COMMENT '加入日期', + INDEX idx_staff_id (staff_id), + INDEX idx_team_id (team_id) +) COMMENT '员工-班组关联表'; + +CREATE TABLE IF NOT EXISTS org_cleaning_area ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + parent_id BIGINT COMMENT '父级区域ID', + level INT NOT NULL COMMENT '层级: 1-5', + name VARCHAR(100) NOT NULL COMMENT '区域名称', + code VARCHAR(50) COMMENT '区域编码', + hospital_id BIGINT NOT NULL COMMENT '关联医院ID', + campus_id BIGINT COMMENT '关联院区ID', + responsible_staff_id BIGINT COMMENT '责任人ID', + beacon_id BIGINT COMMENT '关联蓝牙Beacon ID', + sort_order INT DEFAULT 0, + status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE', + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_tenant_id (tenant_id) +) COMMENT '保洁区域表'; + +-- ==================== 用户与权限 ==================== + +CREATE TABLE IF NOT EXISTS sys_user ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT COMMENT '租户ID', + username VARCHAR(50) NOT NULL UNIQUE COMMENT '登录账号', + password_hash VARCHAR(255) NOT NULL COMMENT '密码哈希', + user_type VARCHAR(20) NOT NULL COMMENT '用户类型: SUPER_ADMIN/HOSPITAL_ADMIN/PROPERTY_ADMIN/STAFF', + real_name VARCHAR(50) NOT NULL COMMENT '真实姓名', + phone VARCHAR(20) COMMENT '手机号', + email VARCHAR(100) COMMENT '邮箱', + avatar_url VARCHAR(500) COMMENT '头像URL', + hospital_id BIGINT COMMENT '绑定医院ID', + property_company_id BIGINT COMMENT '绑定物业公司ID', + staff_id BIGINT COMMENT '关联员工ID', + wechat_openid VARCHAR(100) COMMENT '微信OpenID', + wechat_unionid VARCHAR(100) COMMENT '微信UnionID', + status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '状态: ACTIVE/DISABLED', + last_login_at DATETIME COMMENT '最后登录时间', + last_login_ip VARCHAR(50) COMMENT '最后登录IP', + INDEX idx_wechat_openid (wechat_openid), + INDEX idx_tenant_status (tenant_id, status) +) COMMENT '用户账号表'; + +CREATE TABLE IF NOT EXISTS sys_role ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT COMMENT '租户ID', + name VARCHAR(50) NOT NULL COMMENT '角色名称', + code VARCHAR(50) NOT NULL COMMENT '角色编码', + description VARCHAR(500) COMMENT '角色描述', + scope VARCHAR(20) NOT NULL COMMENT '适用范围: HOSPITAL_ADMIN/PROPERTY_ADMIN/STAFF', + is_preset TINYINT NOT NULL DEFAULT 0 COMMENT '是否预设模板: 0-否, 1-是', + data_scope VARCHAR(20) COMMENT '数据权限范围: ALL/HOSPITAL/TEAM/SELF', + status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE', + UNIQUE KEY uk_tenant_code (tenant_id, code) +) COMMENT '角色表'; + +CREATE TABLE IF NOT EXISTS sys_user_role ( + id BIGINT PRIMARY KEY, + user_id BIGINT NOT NULL, + role_id BIGINT NOT NULL, + INDEX idx_user_id (user_id), + INDEX idx_role_id (role_id) +) COMMENT '用户-角色关联表'; + +CREATE TABLE IF NOT EXISTS sys_permission_config ( + id BIGINT PRIMARY KEY, + parent_id BIGINT COMMENT '父级ID', + level INT NOT NULL COMMENT '层级: 1-4', + menu_code VARCHAR(50) NOT NULL COMMENT '功能菜单编码', + menu_name VARCHAR(100) NOT NULL COMMENT '功能菜单名称', + page_code VARCHAR(50) COMMENT '页面编码', + page_name VARCHAR(100) COMMENT '页面名称', + action_code VARCHAR(50) COMMENT '功能点编码', + action_name VARCHAR(100) COMMENT '功能点名称', + operation_code VARCHAR(30) COMMENT '动作编码', + operation_name VARCHAR(30) COMMENT '动作名称', + sort_order INT DEFAULT 0, + module_code VARCHAR(50) NOT NULL COMMENT '所属模块编码', + status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE', + INDEX idx_module_code (module_code) +) COMMENT '权限配置表'; + +CREATE TABLE IF NOT EXISTS sys_role_permission ( + id BIGINT PRIMARY KEY, + role_id BIGINT NOT NULL, + permission_id BIGINT NOT NULL, + INDEX idx_role_id (role_id) +) COMMENT '角色权限关联表'; + +CREATE TABLE IF NOT EXISTS sys_user_permission_override ( + id BIGINT PRIMARY KEY, + user_id BIGINT NOT NULL, + permission_id BIGINT NOT NULL, + grant_type VARCHAR(10) NOT NULL COMMENT '授权类型: GRANT/DENY', + INDEX idx_user_id (user_id) +) COMMENT '用户自定义权限表'; + +-- ==================== 在线报修 ==================== + +CREATE TABLE IF NOT EXISTS repair_type ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + name VARCHAR(50) NOT NULL, + code VARCHAR(50) NOT NULL, + default_team_id BIGINT, + icon_url VARCHAR(500), + sort_order INT DEFAULT 0, + status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE', + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_tenant_id (tenant_id) +) COMMENT '报修类型表'; + +CREATE TABLE IF NOT EXISTS repair_order ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + order_no VARCHAR(30) NOT NULL COMMENT '工单编号', + repair_type_id BIGINT NOT NULL, + title VARCHAR(200) NOT NULL, + description TEXT, + urgency VARCHAR(20) NOT NULL COMMENT '紧急程度: LOW/MEDIUM/HIGH/URGENT', + status VARCHAR(20) NOT NULL COMMENT '工单状态', + hospital_id BIGINT NOT NULL, + campus_id BIGINT, + location VARCHAR(255) NOT NULL, + location_detail VARCHAR(255), + reporter_id BIGINT NOT NULL, + reporter_type VARCHAR(20) NOT NULL COMMENT 'STAFF/EXTERNAL', + reporter_name VARCHAR(50), + reporter_phone VARCHAR(20), + assigned_team_id BIGINT, + assigned_staff_id BIGINT, + assigned_at DATETIME, + expected_finish_at DATETIME, + actual_finish_at DATETIME, + completed_at DATETIME, + closed_at DATETIME, + close_reason VARCHAR(500), + parent_order_id BIGINT, + is_assist TINYINT NOT NULL DEFAULT 0, + remind_count INT NOT NULL DEFAULT 0, + last_remind_at DATETIME, + is_supplement TINYINT DEFAULT 0, + supplement_reason VARCHAR(50), + supplement_remark TEXT, + supplement_audit_status VARCHAR(20), + supplement_auditor_id BIGINT, + supplement_audit_time DATETIME, + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + UNIQUE KEY uk_order_no (order_no), + INDEX idx_tenant_status (tenant_id, status), + INDEX idx_reporter (reporter_id, created_at), + INDEX idx_assigned_team (assigned_team_id, status) +) COMMENT '报修工单表'; + +-- ==================== 巡检管理 ==================== + +CREATE TABLE IF NOT EXISTS inspection_area ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + name VARCHAR(100) NOT NULL, + code VARCHAR(50), + hospital_id BIGINT NOT NULL, + campus_id BIGINT, + parent_id BIGINT, + beacon_id BIGINT, + sort_order INT DEFAULT 0, + status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE', + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_tenant_id (tenant_id) +) COMMENT '巡检区域表'; + +CREATE TABLE IF NOT EXISTS inspection_plan ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + name VARCHAR(100) NOT NULL, + area_id BIGINT NOT NULL, + frequency VARCHAR(20) NOT NULL COMMENT 'DAILY/WEEKLY/MONTHLY/CUSTOM', + frequency_config JSON, + team_id BIGINT NOT NULL, + staff_ids JSON, + assign_rule VARCHAR(20) NOT NULL COMMENT 'ROUND_ROBIN/RANDOM/FIXED', + check_items JSON NOT NULL, + start_date DATE NOT NULL, + end_date DATE, + remind_before INT, + status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE', + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_tenant_id (tenant_id) +) COMMENT '巡检计划表'; + +CREATE TABLE IF NOT EXISTS inspection_task ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + plan_id BIGINT, + task_no VARCHAR(30) NOT NULL, + area_id BIGINT NOT NULL, + area_name VARCHAR(100), + assigned_staff_id BIGINT NOT NULL, + assigned_staff_name VARCHAR(50), + plan_date DATE NOT NULL, + plan_time_start TIME, + plan_time_end TIME, + status VARCHAR(20) NOT NULL COMMENT 'PENDING/IN_PROGRESS/COMPLETED/EXPIRED', + check_in_time DATETIME, + check_in_beacon_id BIGINT, + check_in_latitude DECIMAL(10,7), + check_in_longitude DECIMAL(10,7), + check_in_distance DECIMAL(6,2), + check_type VARCHAR(20) NOT NULL DEFAULT 'BLUETOOTH' COMMENT 'BLUETOOTH/MANUAL', + check_result JSON, + abnormal_count INT NOT NULL DEFAULT 0, + completed_at DATETIME, + is_supplement TINYINT DEFAULT 0, + supplement_reason VARCHAR(50), + supplement_remark TEXT, + supplement_audit_status VARCHAR(20), + supplement_auditor_id BIGINT, + supplement_audit_time DATETIME, + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_tenant_date (tenant_id, plan_date), + INDEX idx_staff_date (assigned_staff_id, plan_date) +) COMMENT '巡检任务表'; + +CREATE TABLE IF NOT EXISTS inspection_abnormal ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + task_id BIGINT NOT NULL, + area_id BIGINT NOT NULL, + item_name VARCHAR(100) NOT NULL, + severity VARCHAR(20) NOT NULL COMMENT 'LOW/MEDIUM/HIGH/CRITICAL', + description TEXT, + repair_order_id BIGINT, + status VARCHAR(20) NOT NULL DEFAULT 'PENDING' COMMENT 'PENDING/PROCESSING/RESOLVED', + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_tenant_id (tenant_id) +) COMMENT '巡检异常记录表'; + +-- ==================== 保洁管理 ==================== + +CREATE TABLE IF NOT EXISTS cleaning_task ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + task_no VARCHAR(30) NOT NULL, + area_id BIGINT NOT NULL, + area_name VARCHAR(100), + area_path VARCHAR(500), + assigned_staff_id BIGINT NOT NULL, + assigned_staff_name VARCHAR(50), + task_date DATE NOT NULL, + task_type VARCHAR(20) NOT NULL COMMENT 'DAILY/DEEP/TEMPORARY', + status VARCHAR(20) NOT NULL COMMENT 'PENDING/IN_PROGRESS/COMPLETED/OVERDUE', + check_in_time DATETIME, + check_in_beacon_id BIGINT, + check_in_distance DECIMAL(6,2), + check_type VARCHAR(20) NOT NULL DEFAULT 'BLUETOOTH', + completed_at DATETIME, + timeout_at DATETIME, + is_spot_checked TINYINT NOT NULL DEFAULT 0, + spot_check_result VARCHAR(20) COMMENT 'QUALIFIED/UNQUALIFIED', + spot_checker_id BIGINT, + spot_check_at DATETIME, + spot_check_remark TEXT, + is_supplement TINYINT DEFAULT 0, + supplement_reason VARCHAR(50), + supplement_remark TEXT, + supplement_audit_status VARCHAR(20), + supplement_auditor_id BIGINT, + supplement_audit_time DATETIME, + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_tenant_date (tenant_id, task_date), + INDEX idx_staff_date (assigned_staff_id, task_date) +) COMMENT '保洁任务表'; + +CREATE TABLE IF NOT EXISTS cleaning_schedule ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + area_id BIGINT NOT NULL, + staff_id BIGINT NOT NULL, + schedule_date DATE NOT NULL, + shift_type VARCHAR(20) NOT NULL COMMENT 'MORNING/AFTERNOON/NIGHT/WHOLE_DAY', + status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE', + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_tenant_area_date (tenant_id, area_id, schedule_date), + INDEX idx_tenant_staff_date (tenant_id, staff_id, schedule_date) +) COMMENT '保洁排班表'; + +-- ==================== 服务评价 ==================== + +CREATE TABLE IF NOT EXISTS evaluation ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + module_type VARCHAR(20) NOT NULL COMMENT 'REPAIR/INSPECTION/CLEANING', + business_id BIGINT NOT NULL, + business_no VARCHAR(30), + score TINYINT NOT NULL COMMENT '评分1-5', + content TEXT, + evaluator_id BIGINT NOT NULL, + evaluator_name VARCHAR(50), + evaluator_type VARCHAR(20) COMMENT 'STAFF/EXTERNAL', + target_staff_id BIGINT, + target_team_id BIGINT, + reply_content TEXT, + replier_id BIGINT, + replied_at DATETIME, + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_module_business (module_type, business_id), + INDEX idx_target_staff (target_staff_id, created_at) +) COMMENT '评价表'; + +CREATE TABLE IF NOT EXISTS evaluation_config ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + module_type VARCHAR(20) NOT NULL, + auto_trigger TINYINT NOT NULL DEFAULT 1, + trigger_delay_minutes INT, + low_score_threshold INT, + low_score_notify_type VARCHAR(30), + must_reply_hours INT, + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_tenant_id (tenant_id) +) COMMENT '评价配置表'; + +-- ==================== 考勤打卡 ==================== + +CREATE TABLE IF NOT EXISTS attendance_check_point ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + name VARCHAR(100) NOT NULL, + beacon_id BIGINT NOT NULL, + hospital_id BIGINT NOT NULL, + campus_id BIGINT, + location VARCHAR(255), + team_ids JSON, + status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE', + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_tenant_id (tenant_id) +) COMMENT '打卡点表'; + +CREATE TABLE IF NOT EXISTS attendance_rule ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + name VARCHAR(100) NOT NULL, + team_id BIGINT, + work_start_time TIME NOT NULL, + work_end_time TIME NOT NULL, + start_buffer_minutes INT NOT NULL DEFAULT 30, + end_buffer_minutes INT NOT NULL DEFAULT 30, + late_threshold_minutes INT NOT NULL DEFAULT 5, + early_leave_threshold_minutes INT NOT NULL DEFAULT 5, + status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE', + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_tenant_id (tenant_id) +) COMMENT '打卡规则表'; + +CREATE TABLE IF NOT EXISTS attendance_record ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + staff_id BIGINT NOT NULL, + staff_name VARCHAR(50), + check_date DATE NOT NULL, + check_type VARCHAR(20) NOT NULL COMMENT 'CHECK_IN/CHECK_OUT', + check_method VARCHAR(20) NOT NULL COMMENT 'BLUETOOTH/MANUAL', + check_time DATETIME NOT NULL, + check_point_id BIGINT, + beacon_id BIGINT, + beacon_uuid VARCHAR(100), + distance DECIMAL(6,2), + result VARCHAR(20) NOT NULL COMMENT 'NORMAL/LATE/EARLY_LEAVE/ABSENT', + abnormal_type VARCHAR(30), + appeal_status VARCHAR(20) DEFAULT 'NONE' COMMENT 'NONE/PENDING/APPROVED/REJECTED', + appeal_reason TEXT, + appeal_auditor_id BIGINT, + appeal_audit_remark TEXT, + appeal_audit_at DATETIME, + is_supplement TINYINT DEFAULT 0, + supplement_reason VARCHAR(50), + supplement_remark TEXT, + supplement_audit_status VARCHAR(20), + supplement_auditor_id BIGINT, + supplement_audit_time DATETIME, + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_staff_date (staff_id, check_date) +) COMMENT '打卡记录表'; + +-- ==================== 蓝牙策略配置 ==================== + +CREATE TABLE IF NOT EXISTS sys_bluetooth_policy ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + hospital_id BIGINT NOT NULL, + campus_id BIGINT COMMENT '院区ID, NULL表示全院统一', + inspection_check_in VARCHAR(10) NOT NULL DEFAULT 'REQUIRED', + inspection_photo VARCHAR(10) NOT NULL DEFAULT 'REQUIRED', + cleaning_check_in VARCHAR(10) NOT NULL DEFAULT 'OPTIONAL', + cleaning_photo VARCHAR(10) NOT NULL DEFAULT 'OPTIONAL', + attendance_check VARCHAR(10) NOT NULL DEFAULT 'REQUIRED', + audit_status VARCHAR(20) NOT NULL DEFAULT 'PENDING', + audit_remark TEXT, + auditor_id BIGINT, + audit_at DATETIME, + effective_at DATETIME, + status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE', + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_tenant_hospital (tenant_id, hospital_id, campus_id), + INDEX idx_audit_status (audit_status) +) COMMENT '蓝牙策略配置表'; + +-- ==================== 蓝牙设备 ==================== + +CREATE TABLE IF NOT EXISTS device_beacon ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + uuid VARCHAR(100) NOT NULL, + major INT, + minor INT, + name VARCHAR(100) NOT NULL, + mac_address VARCHAR(20), + hospital_id BIGINT NOT NULL, + campus_id BIGINT, + bind_type VARCHAR(20) NOT NULL COMMENT 'INSPECTION/CLEANING/ATTENDANCE', + bind_id BIGINT, + location VARCHAR(255), + latitude DECIMAL(10,7), + longitude DECIMAL(10,7), + rssi_threshold INT DEFAULT -70, + distance_threshold DECIMAL(6,2) DEFAULT 5.00, + battery_level INT, + battery_warn_threshold INT DEFAULT 20, + last_heartbeat_at DATETIME, + status VARCHAR(20) NOT NULL DEFAULT 'ONLINE' COMMENT 'ONLINE/OFFLINE/FAULT/DISABLED', + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_tenant_id (tenant_id) +) COMMENT '蓝牙Beacon设备表'; + +-- ==================== 合同管理 ==================== + +CREATE TABLE IF NOT EXISTS contract ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + contract_no VARCHAR(30) NOT NULL, + title VARCHAR(200) NOT NULL, + contract_type VARCHAR(30) NOT NULL COMMENT 'SERVICE/PURCHASE/LEASE/OTHER', + property_company_id BIGINT, + hospital_id BIGINT NOT NULL, + campus_id BIGINT, + total_amount DECIMAL(12,2), + start_date DATE NOT NULL, + end_date DATE NOT NULL, + status VARCHAR(20) NOT NULL DEFAULT 'DRAFT', + payment_status VARCHAR(20) COMMENT 'UNPAID/PARTIAL_PAID/PAID', + paid_amount DECIMAL(12,2), + sign_date DATE, + attachment_urls JSON, + remark TEXT, + warn_days_before INT DEFAULT 30, + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_tenant_id (tenant_id) +) COMMENT '合同表'; + +CREATE TABLE IF NOT EXISTS contract_payment ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + contract_id BIGINT NOT NULL, + node_name VARCHAR(100) NOT NULL, + amount DECIMAL(12,2) NOT NULL, + plan_date DATE NOT NULL, + actual_date DATE, + status VARCHAR(20) NOT NULL DEFAULT 'PENDING' COMMENT 'PENDING/PAID/OVERDUE', + confirmer_id BIGINT, + confirm_remark TEXT, + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_contract_id (contract_id) +) COMMENT '合同付款节点表'; + +CREATE TABLE IF NOT EXISTS contract_change ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + contract_id BIGINT NOT NULL, + change_type VARCHAR(30) NOT NULL, + change_content TEXT NOT NULL, + before_data JSON, + after_data JSON, + applicant_id BIGINT NOT NULL, + audit_status VARCHAR(20) NOT NULL DEFAULT 'PENDING', + auditor_id BIGINT, + audit_remark TEXT, + audit_at DATETIME, + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_contract_id (contract_id) +) COMMENT '合同变更记录表'; + +-- ==================== 分段招标 ==================== + +CREATE TABLE IF NOT EXISTS bidding_plan ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + plan_no VARCHAR(30) NOT NULL, + title VARCHAR(200) NOT NULL, + bidding_type VARCHAR(30) NOT NULL, + hospital_id BIGINT NOT NULL, + budget_amount DECIMAL(12,2), + publish_date DATE, + deadline_date DATE, + open_bid_date DATE, + status VARCHAR(20) NOT NULL DEFAULT 'DRAFT', + description TEXT, + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_tenant_id (tenant_id) +) COMMENT '招标计划表'; + +CREATE TABLE IF NOT EXISTS bidding_section ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + plan_id BIGINT NOT NULL, + section_no VARCHAR(30) NOT NULL, + name VARCHAR(200) NOT NULL, + scope TEXT NOT NULL, + requirements TEXT, + budget_amount DECIMAL(12,2), + winner_supplier_id BIGINT, + status VARCHAR(20) NOT NULL DEFAULT 'PUBLISHED', + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_plan_id (plan_id) +) COMMENT '标段表'; + +CREATE TABLE IF NOT EXISTS bidding_supplier ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + name VARCHAR(100) NOT NULL, + unified_social_code VARCHAR(50), + contact_person VARCHAR(50), + contact_phone VARCHAR(20), + address VARCHAR(255), + qualification_status VARCHAR(20) NOT NULL DEFAULT 'PENDING', + blacklist TINYINT NOT NULL DEFAULT 0, + remark TEXT, + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_tenant_id (tenant_id) +) COMMENT '供应商表'; + +-- ==================== 操作日志 ==================== + +CREATE TABLE IF NOT EXISTS audit_log ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT, + operator_id BIGINT NOT NULL, + operator_name VARCHAR(50), + operator_ip VARCHAR(50), + module_code VARCHAR(50) NOT NULL, + module_name VARCHAR(100), + page_code VARCHAR(50), + page_name VARCHAR(100), + action_code VARCHAR(50), + action_name VARCHAR(100), + operation_type VARCHAR(30) NOT NULL, + operation_content TEXT, + business_id BIGINT, + business_no VARCHAR(30), + before_data JSON, + after_data JSON, + request_params JSON, + response_status VARCHAR(20) NOT NULL, + error_message TEXT, + operated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + INDEX idx_tenant_time (tenant_id, operated_at), + INDEX idx_module_time (module_code, operated_at), + INDEX idx_operator_time (operator_id, operated_at) +) COMMENT '操作日志表'; + +-- ==================== 系统管理 ==================== + +CREATE TABLE IF NOT EXISTS sys_dict_type ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT, + code VARCHAR(50) NOT NULL, + name VARCHAR(100) NOT NULL, + status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE', + UNIQUE KEY uk_tenant_code (tenant_id, code) +) COMMENT '字典类型表'; + +CREATE TABLE IF NOT EXISTS sys_dict_data ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT, + type_code VARCHAR(50) NOT NULL, + label VARCHAR(100) NOT NULL, + value VARCHAR(100) NOT NULL, + sort_order INT DEFAULT 0, + status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE', + INDEX idx_type_code (type_code) +) COMMENT '字典数据表'; + +CREATE TABLE IF NOT EXISTS sys_message_template ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + code VARCHAR(50) NOT NULL, + name VARCHAR(100) NOT NULL, + channel VARCHAR(20) NOT NULL COMMENT 'WECHAT_MINI/WECHAT_OFFICIAL/SMS/IN_APP', + template_id VARCHAR(100), + title VARCHAR(200), + content TEXT NOT NULL, + status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE', + created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT NOT NULL DEFAULT 0, + INDEX idx_tenant_id (tenant_id) +) COMMENT '消息模板表'; + +CREATE TABLE IF NOT EXISTS sys_version ( + id BIGINT PRIMARY KEY, + platform VARCHAR(20) NOT NULL COMMENT 'WEB/MINI_PROGRAM', + version_no VARCHAR(20) NOT NULL, + min_compatible_version VARCHAR(20), + update_type VARCHAR(20) NOT NULL COMMENT 'COMPATIBLE/BREAKING', + release_notes TEXT, + force_update TINYINT NOT NULL DEFAULT 0, + published_at DATETIME, + status VARCHAR(20) NOT NULL DEFAULT 'DRAFT' +) COMMENT '系统版本表'; + +CREATE TABLE IF NOT EXISTS sys_tenant_module ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + module_code VARCHAR(50) NOT NULL, + enabled TINYINT NOT NULL DEFAULT 1, + enabled_at DATETIME, + enabled_by BIGINT, + config_data JSON, + INDEX idx_tenant_id (tenant_id) +) COMMENT '租户模块关联表'; + +-- ==================== ShedLock ==================== + +CREATE TABLE IF NOT EXISTS shedlock ( + name VARCHAR(64) NOT NULL, + lock_until TIMESTAMP(3) NOT NULL, + locked_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + locked_by VARCHAR(255) NOT NULL, + PRIMARY KEY (name) +) COMMENT '分布式锁表'; + +-- ==================== 初始化超级管理员 ==================== + +-- 密码: admin123 (BCrypt加密) +INSERT INTO sys_user (id, username, password_hash, user_type, real_name, status) +VALUES (1, 'superadmin', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9lBOsl7iKTVKIUi', 'SUPER_ADMIN', '超级管理员', 'ACTIVE'); diff --git a/backend/src/test/resources/application-test.yml b/backend/src/test/resources/application-test.yml new file mode 100644 index 0000000..430f110 --- /dev/null +++ b/backend/src/test/resources/application-test.yml @@ -0,0 +1,20 @@ +spring: + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:mem:testdb;MODE=MariaDB;DB_CLOSE_DELAY=-1 + username: sa + password: + h2: + console: + enabled: true + sql: + init: + mode: always + +mybatis-plus: + configuration: + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + +logging: + level: + com.hospital.mgmt: DEBUG diff --git a/docs/01-模块划分.md b/docs/01-模块划分.md new file mode 100644 index 0000000..513a73c --- /dev/null +++ b/docs/01-模块划分.md @@ -0,0 +1,523 @@ +# 医院物业SaaS管理后台 — 模块划分 + +> 技术栈:Java + Spring Boot + MariaDB +> 端侧:管理员后台(Web)+ 微信小程序(物业人员) +> 日期:2026-04-16 +> 版本:v4.0 + +--- + +## 一、角色与账号体系 + +### 1.1 角色定义 + +| 角色 | 创建者 | 说明 | 端侧 | +|------|--------|------|------| +| **超级管理员** | 系统预置 | 平台方运营,管理账号、权限与系统配置,不涉及业务数据 | Web | +| **医院账号** | 超级管理员 | 查看为其服务的物业公司全部日常数据,独占合同管理+分段招标 | Web | +| **物业公司管理员** | 超级管理员 | 每个管理员账号绑定一家医院,管理该院下业务,创建下属账号 | Web+小程序 | +| **物业下属人员** | 物业公司管理员 | 按分配的自定义角色操作(主管/员工等),主要通过小程序使用 | 小程序为主 | + +### 1.2 多租户关系模型 + +``` +超级管理员(平台方) + │ + ├── 创建医院信息(支持多院区) + │ └── XX医院 + │ ├── 主院区 + │ ├── 东院区 + │ └── 南院区 + │ + ├── 创建医院账号(绑定医院,设有效期) + │ └── 医院A账号 → 可查看为其服务的物业公司全部日常数据 + │ + └── 创建物业公司信息 + 物业公司管理员账号(绑定物业公司+医院,设有效期) + └── XX物业公司 + ├── 管理员账号1(服务A医院)→ 管理A医院业务 + └── 管理员账号2(服务B医院)→ 管理B医院业务 +``` + +**关键规则:** +- 一个物业公司服务多家医院时,每个医院对应一个独立的管理员账号 +- 物业公司管理员登录后只看到绑定医院的数据,无需切换视图 +- 医院账号可查看为其服务的物业公司的全部日常数据 +- 合同管理、分段招标功能仅医院账号可用 +- 超级管理员只管理账号、权限与系统配置,不查看业务数据 + +### 1.3 数据权限(行级隔离) + +| 角色 | 数据范围 | 说明 | +|------|----------|------| +| 超级管理员 | 仅系统配置与账号数据 | 不涉及业务数据 | +| 医院账号 | 本医院+关联物业公司数据 | 仅查看,不可操作日常业务 | +| 物业公司管理员 | 本公司绑定的医院数据 | 可操作管理 | +| 主管 | 本班组数据 | 仅可查看/操作本班组的工单、人员、记录 | +| 员工 | 仅本人数据 | 只能查看自己的工单、任务、考勤 | + +### 1.4 账号有效期与到期提醒机制 + +**适用范围:** 仅医院账号和物业公司管理员账号需要设置有效期,物业下属人员不单独设有效期(随物业公司账号到期而自动失效)。 + +**有效期设置:** +- 超级管理员创建医院/物业公司账号时,必须设置账号有效期 +- 支持在账号管理页面修改有效期、手动续期 + +**到期提醒规则:** +- 超级管理员可在系统配置中设置到期提醒天数(如提前7天、15天、30天) +- 到期前到达提醒天数时,用户登录后弹出到期提醒弹窗 +- 弹窗关闭后可正常登录使用,不影响功能 +- 超级管理员后台可查看即将到期的账号列表 + +**过期后行为:** +- 账号过期后禁止登录 +- 超级管理员可手动续期恢复 + +--- + +## 二、超级管理员 — 功能模块 + +> 超级管理员负责平台运营,管理账号、权限与系统配置,不查看业务数据。 + +### 2.1 账号管理 + +| 功能点 | 说明 | +|--------|------| +| 医院账号管理 | 创建/编辑/启停医院账号,设置有效期 | +| 物业公司账号管理 | 创建/编辑/启停物业公司管理员账号,设置有效期 | +| 医院信息管理 | 创建/编辑医院信息(含多院区) | +| 物业公司信息管理 | 创建/编辑物业公司信息 | +| 到期账号管理 | 查看即将到期/已过期账号列表,手动续期 | +| 账号有效期配置 | 配置到期提醒规则(提前N天提醒) | + +### 2.2 权限管理 + +| 功能点 | 说明 | +|--------|------| +| 角色定义 | 四级权限树形勾选(功能菜单→页面→功能点→动作) | +| 权限自动同步 | 新增功能时自动注册到权限体系,权限管理页面自动渲染新可勾选项 | +| 权限预设模板 | 提供预设角色模板,创建角色时选择模板自动填充权限 | +| 账号角色绑定 | 为账号分配/移除角色 | +| 权限审计日志 | 记录所有权限变更操作(操作人、时间、类型、变更前后对比) | +| 权限实时生效 | 权限变更后通过Redis Pub/Sub毫秒级生效,无需重新登录 | + +### 2.3 系统配置 + +| 功能点 | 说明 | +|--------|------| +| 系统版本管理 | 管理后台和小程序版本信息 | +| 缓存管理 | 手动清理缓存,查看缓存状态 | +| 到期提醒规则配置 | 配置账号到期提醒天数阈值 | + +--- + +## 三、物业公司 — 功能模块 + +> 物业公司管理员负责绑定医院的日常业务管理,可创建下属人员账号并分配角色。 + +### 3.1 在线报修(repair) + +**Web端:** +- 工单列表、工单详情、工单分配、工单流转 +- 延期审批、协助维修管理 +- 报修类型管理、数据补录、报修统计 + +**小程序端:** +- 扫码注册、一键报修、我的工单、催单 +- 维修接单/完工、延期申请/审批 +- 协助申请、工单分配(主管)、工单验收、评价 + +### 3.2 巡检管理(inspection) + +**Web端:** +- 巡检计划管理、任务看板、记录查询 +- 异常跟踪、区域管理、数据补录、补录审核 + +**小程序端:** +- 今日巡检、蓝牙强制打卡(必须连接才可打卡和拍照) +- 巡检执行、异常上报、异常数据补录 + +### 3.3 保洁管理(cleaning) + +**Web端:** +- 区域管理(五级架构)、任务看板、人员排班 +- 蓝牙点位管理、超时预警、保洁抽查 +- 数据补录、补录审核 + +**小程序端:** +- 今日保洁、蓝牙强制打卡确认 +- 保洁执行、异常反馈、抽查标记(主管)、异常数据补录 + +### 3.4 组织架构(org) + +**Web端:** +- 班组管理、人员管理、人员分配 +- 排班管理、技能管理、打卡点分配 + +**小程序端:** +- 我的班组、我的排班、通讯录 + +### 3.5 考勤打卡(attendance) + +**Web端:** +- 打卡点管理(按班组分配不同打卡点+蓝牙绑定) +- 打卡规则、考勤记录、考勤统计 +- 异常审核、数据补录 + +**小程序端:** +- 上下班蓝牙强制打卡(必须在指定打卡点连接蓝牙后打卡) +- 打卡记录、异常申诉、考勤日历 + +### 3.6 服务评价(evaluation) + +**Web端:** +- 评价汇总看板、评价列表、评价回复 +- 绩效报表、评价配置 + +**小程序端:** +- 待评价列表、评分留言、历史评价 + +### 3.7 统计报表(statistics) + +按天/周/月/年/自定义时间段查询,支持Excel/PDF导出。 + +| 报表类型 | 可用角色 | +|----------|----------| +| 报修统计 | 物业 | +| 巡检统计 | 物业 | +| 保洁统计 | 物业 | +| 评价统计 | 物业 | +| 考勤统计 | 物业 | +| 综合看板 | 物业 | +| 自定义报表 | 物业(用户自选维度+指标) | + +### 3.8 操作日志(audit-log) + +| 功能点 | 说明 | +|--------|------| +| 日志时间轴 | 以时间轴形式展示操作记录,按时间倒序排列 | +| 日志列表 | 以表格形式展示,支持按模块/操作人/日期/操作类型筛选 | +| 日志详情 | 查看单条操作的完整信息(操作人、时间、IP、操作内容、变更前后对比) | +| 日志导出 | 导出操作日志Excel | +| 权限变更日志 | 专门查看权限变更记录(含变更前后对比) | +| 数据补录日志 | 专门查看数据补录记录 | + +### 3.9 系统配置 + +| 功能点 | 说明 | +|--------|------| +| 蓝牙设备管理 | Beacon列表、位置绑定、状态监控、电量预警 | +| 字典管理 | 报修/巡检/保洁类型等字典,按租户自定义 | +| 微信配置 | 小程序/公众号参数配置 | +| 消息模板 | 微信模板消息配置 | +| 数据补录审核 | 审核各模块数据补录申请(主管) | + +--- + +## 四、医院 — 功能模块(仅Web端) + +> 医院账号仅使用Web端,以服务监督和数据查看为主,独占合同管理与分段招标。 + +### 4.1 合同管理(contract) + +**仅医院账号可用,物业公司不可操作此模块。** + +| 功能点 | 说明 | +|--------|------| +| 合同台账 | 合同列表与状态总览 | +| 合同录入 | 新建合同,关联物业公司与院区 | +| 合同详情 | 查看合同完整信息与履约记录 | +| 付款管理 | 付款节点管理与确认 | +| 变更管理 | 合同变更申请与审批 | +| 到期预警 | 合同到期自动提醒 | +| 续签管理 | 合同续签流程 | +| 合同统计 | 合同金额、履约率等统计报表 | + +### 4.2 分段招标管理(bidding) + +**仅医院账号可用,物业公司不可操作此模块。** + +| 功能点 | 说明 | +|--------|------| +| 招标计划 | 创建招标计划,关联院区与预算 | +| 标段管理 | 标段划分与配置 | +| 供应商管理 | 供应商资质审核、黑名单管理 | +| 招标发布 | 发布招标公告 | +| 投标管理 | 供应商投标管理 | +| 评标管理 | 评标流程与打分 | +| 定标审批 | 定标审批与公示 | +| 中标公示 | 中标结果公示 | +| 招标统计 | 招标效率、成本对比等统计 | + +### 4.3 服务监督 + +| 功能点 | 说明 | +|--------|------| +| 报修数据查看 | 查看关联物业公司的报修工单数据(只读) | +| 巡检数据查看 | 查看关联物业公司的巡检记录数据(只读) | +| 保洁数据查看 | 查看关联物业公司的保洁任务数据(只读) | + +### 4.4 服务评价 + +| 功能点 | 说明 | +|--------|------| +| 发起评价 | 对物业服务发起评分与留言 | +| 评价汇总查看 | 查看评价汇总看板与统计 | + +### 4.5 统计报表 + +| 报表类型 | 说明 | +|----------|------| +| 报修统计 | 查看关联物业报修数据统计(只读) | +| 巡检统计 | 查看关联物业巡检数据统计(只读) | +| 保洁统计 | 查看关联物业保洁数据统计(只读) | +| 评价统计 | 查看评价统计(只读) | +| 合同统计 | 合同相关统计 | +| 招标统计 | 招标相关统计 | +| 综合看板 | 全局数据综合看板 | +| 自定义报表 | 用户自选维度+指标 | + +--- + +## 五、微信小程序 — 功能总览(仅物业人员使用) + +> 微信小程序仅供物业人员使用,医院账号无小程序端。 + +### 5.1 物业人员工作台 + +不同角色登录后看到不同功能入口: + +**维修人员:** +- 我的工单(接单/完工/延期申请) +- 协助申请 +- 工单验收 +- 消息通知 + +**巡检人员:** +- 今日巡检 +- 蓝牙强制打卡 +- 异常上报 +- 异常数据补录 + +**保洁人员:** +- 今日保洁 +- 蓝牙强制打卡确认 +- 保洁执行 +- 异常反馈 + +**主管/班组长:** +- 工单分配 +- 巡检/保洁任务查看 +- 延期审批 +- 保洁抽查 +- 考勤审核 +- 数据补录审核 + +**物业公司管理员:** +- 报修管理(工单列表/分配/流转) +- 巡检管理(计划/看板/记录) +- 保洁管理(任务/排班/抽查) +- 考勤管理(记录/统计) +- 评价管理(查看/回复) +- 组织架构查看 + +### 5.2 通用功能 + +| 功能 | 说明 | +|------|------| +| 快捷登录 | 微信授权+手机号绑定,自动匹配物业公司与人员信息 | +| 个人信息 | 查看与编辑个人资料 | +| 消息通知 | 接收系统推送消息(新工单、催单、审批等) | +| 数据补录申请 | 提交数据补录申请(需审批) | +| 通讯录 | 查看本班组/物业公司联系人 | + +### 5.3 小程序登录与权限机制 + +``` +首次使用:扫码/打开小程序 → 微信授权获取openid → 绑定手机号 + → 系统匹配物业公司+人员信息 → 创建账号 → 进入工作台 + +再次使用:打开小程序 → 自动读取本地token → 验证有效性 + → 有效:直接进入工作台(无感登录) + → 失效:自动使用openid静默登录 → 刷新token → 进入工作台 +``` + +**权限判断机制:** +``` +用户登录 → 获取角色及权限集(四级粒度) → 根据权限动态渲染: + - 可见菜单项 + - 页面内可见功能点 + - 功能点可用动作(按钮显示/隐藏/禁用) + - 数据范围(行级隔离) +``` + +--- + +## 六、跨角色数据流转矩阵 + +### 6.1 业务数据流转 + +| 数据 | 产生方 | 查看方 | 操作方 | 说明 | +|------|--------|--------|--------|------| +| 报修工单 | 物业(员工提交/系统派单) | 物业、医院 | 物业 | 医院只读查看工单数据 | +| 巡检记录 | 物业(巡检员打卡) | 物业、医院 | 物业 | 医院只读查看巡检数据 | +| 保洁记录 | 物业(保洁员打卡) | 物业、医院 | 物业 | 医院只读查看保洁数据 | +| 考勤记录 | 物业(员工打卡) | 物业 | 物业 | 仅物业公司内部数据 | +| 服务评价 | 医院(发起评价) | 物业、医院 | 医院 | 医院发起,物业查看与回复 | +| 合同数据 | 医院(录入管理) | 医院 | 医院 | 物业公司不可见 | +| 招标数据 | 医院(录入管理) | 医院 | 医院 | 物业公司不可见 | +| 操作日志 | 系统自动记录 | 超管、物业 | — | 仅查看,不可修改 | + +### 6.2 账号与权限流转 + +| 操作 | 执行方 | 影响方 | 说明 | +|------|--------|--------|------| +| 创建医院/物业账号 | 超级管理员 | 医院/物业 | 超管创建账号并设有效期,对方收到开通通知 | +| 创建下属人员 | 物业公司管理员 | 物业下属 | 物业管理员创建下属账号并分配角色 | +| 修改角色权限 | 超管(角色定义)/物业管理员(下属角色) | 被修改角色的人员 | 权限实时生效,无需重新登录 | +| 账号到期提醒 | 系统 | 医院/物业管理员 | 登录时弹窗提醒,关闭后可正常使用 | +| 账号续期 | 超级管理员 | 医院/物业 | 超管手动续期,恢复或延长有效期 | + +--- + +## 七、通知机制 + +### 7.1 通知场景与方式 + +| 触发场景 | 通知对象 | 通知方式 | 说明 | +|----------|----------|----------|------| +| 账号即将到期 | 医院/物业管理员 | Web弹窗提醒 | 到期前N天登录时弹窗,关闭后可正常使用 | +| 新工单分配 | 物业维修人员 | 小程序推送 | 实时推送新工单通知 | +| 催单 | 物业主管 | 小程序推送 | 医院或报修人催单时通知 | +| 合同到期预警 | 医院账号 | Web提醒 | 合同即将到期时在Web端提醒 | +| 低评分评价 | 物业管理员 | 小程序推送 | 收到低评分评价时即时通知 | +| 工单完工 | 报修人 | 小程序推送 | 维修完成后通知报修人评价 | +| 审批待办 | 审批人 | 小程序推送 | 有待审批事项时推送 | +| 巡检/保洁异常 | 物业主管 | 小程序推送 | 异常上报时即时通知 | + +### 7.2 消息模板管理 + +- 物业公司管理员可配置微信模板消息内容 +- 支持按场景自定义模板变量(工单号、人员姓名、时间等) +- 消息发送记录可查询 + +--- + +## 八、权限体系(技术参考) + +### 8.1 四级权限粒度 + +权限按 **功能菜单 → 页面 → 功能点 → 动作** 四级树形结构划分: + +``` +功能菜单:在线报修 + ├── 页面:工单列表 + │ ├── 功能点:工单管理 + │ │ ├── ☑ 查看 + │ │ ├── ☑ 新增 + │ │ ├── ☑ 编辑 + │ │ ├── ☐ 删除 + │ │ ├── ☐ 审批 + │ │ ├── ☑ 导出 + │ │ └── ☑ 分配 + │ └── 功能点:批量操作 + │ ├── ☑ 查看 + │ ├── ☐ 新增 + │ ... + ├── 页面:工单详情 + │ ├── 功能点:延期审批 + │ │ ├── ☑ 查看 + │ │ └── ☑ 审批 + │ └── 功能点:工单验收 + │ ├── ☑ 查看 + │ └── ☑ 审批 + └── 页面:报修类型管理 + ├── 功能点:类型管理 + │ ├── ☑ 查看 + │ ├── ☑ 新增 + │ ├── ☑ 编辑 + │ └── ☐ 删除 +``` + +**7种动作类型:** + +| 动作 | 编码 | 说明 | +|------|------|------| +| 查看 | view | 能否看到该页面/数据 | +| 新增 | create | 能否创建新记录 | +| 编辑 | update | 能否修改已有记录 | +| 删除 | delete | 能否删除记录 | +| 审批 | approve | 能否执行审批操作 | +| 导出 | export | 能否导出数据/报表 | +| 分配 | assign | 能否分配工单/任务/人员 | + +### 8.2 权限自动同步机制 + +``` +开发人员新增功能 + │ + 在权限配置表中注册: + - 菜单编码 + 菜单名称 + - 页面编码 + 页面名称 + - 功能点编码 + 功能点名称 + - 适用动作列表(查看/新增/编辑...) + │ + 系统启动时自动扫描权限配置表 + │ + 权限管理页面自动渲染新的可勾选项 + │ + 超级管理员可为角色分配新权限 +``` + +### 8.3 权限实时生效机制 + +``` +权限变更操作(超管/物业管理员修改角色权限) + │ + 更新数据库权限记录 + │ + 发送权限变更事件(Redis Pub/Sub,毫秒级生效) + │ + 所有服务实例接收事件 → 刷新本地权限缓存 + │ + 已登录用户下次操作时加载新权限(无需重新登录) + │ + 小程序端:下次接口请求时返回新权限集 → 动态更新界面 +``` + +### 8.4 权限预设模板 + +| 模板名称 | 适用对象 | 典型权限 | +|----------|----------|----------| +| 物业管理员模板 | 物业公司管理员 | 全部日常业务管理权限 | +| 主管模板 | 主管 | 本班组管理+审批+查看+导出 | +| 班组长模板 | 班组长 | 本班组查看+分配+导出 | +| 维修员模板 | 维修人员 | 接单+完工+延期申请 | +| 巡检员模板 | 巡检人员 | 巡检执行+打卡+异常上报 | +| 保洁员模板 | 保洁人员 | 保洁执行+打卡确认 | +| 医院查看模板 | 医院账号 | 全部日常数据查看+合同+招标 | + +**使用方式:** 创建角色时选择模板 → 系统自动填充权限 → 管理员微调后保存。 + +### 8.5 权限审计日志 + +| 记录项 | 说明 | +|--------|------| +| 操作人 | 谁执行了权限变更 | +| 操作时间 | 何时执行 | +| 操作类型 | 创建角色/修改权限/分配角色/移除角色 | +| 目标对象 | 被变更的角色或账号 | +| 变更详情 | 新增/移除了哪些权限项(对比前后差异) | + +--- + +## 九、蓝牙场景汇总(技术参考) + +| 模块 | 场景 | 蓝牙要求 | 失败处理 | +|------|------|----------|----------| +| 巡检 | 巡检打卡 | 必须连接对应点位Beacon | 进入补录模式 | +| 巡检 | 巡检拍照 | 必须在蓝牙连接状态下拍照 | 进入补录模式 | +| 保洁 | 保洁打卡确认 | 必须连接对应区域Beacon | 进入补录模式 | +| 保洁 | 保洁拍照 | 必须在蓝牙连接状态下拍照 | 进入补录模式 | +| 考勤 | 上班打卡 | 必须连接指定打卡点Beacon | 提交异常申诉 | +| 考勤 | 下班打卡 | 必须连接指定打卡点Beacon | 提交异常申诉 | diff --git a/docs/02-功能清单-医院.md b/docs/02-功能清单-医院.md new file mode 100644 index 0000000..eb0fa7d --- /dev/null +++ b/docs/02-功能清单-医院.md @@ -0,0 +1,80 @@ +# 医院 — 功能点清单 + +> 版本:v4.0 +> 医院账号仅使用Web端,以服务监督和数据查看为主,独占合同管理与分段招标。 +> 端侧:仅Web端(无小程序端) +> 关联文档:`01-模块划分.md`(v4.0) + +--- + +## 1. 合同管理(contract)— 仅医院账号 + +> 物业公司不可操作此模块。 + +| 编号 | 功能点 | 说明 | 优先级 | +|------|--------|------|--------| +| HO-CT-01 | 合同台账 | 合同列表,按状态/类型/日期筛选 | P0 | +| HO-CT-02 | 合同录入 | 基本信息、金额、服务期限、附件上传 | P0 | +| HO-CT-03 | 合同详情 | 完整信息、付款节点、变更记录、关联项目 | P0 | +| HO-CT-04 | 合同审批 | 审批新录入合同 | P0 | +| HO-CT-05 | 付款管理 | 付款计划管理,节点提醒 | P0 | +| HO-CT-06 | 付款确认 | 确认付款节点完成 | P0 | +| HO-CT-07 | 变更管理 | 变更申请、审批、记录 | P0 | +| HO-CT-08 | 变更审批 | 审批合同变更申请 | P0 | +| HO-CT-09 | 到期预警 | 合同到期前自动提醒(30/15/7天) | P0 | +| HO-CT-10 | 续签管理 | 续签审批流程 | P0 | +| HO-CT-11 | 合同导出 | 导出合同列表/详情 | P1 | + +--- + +## 2. 分段招标管理(bidding)— 仅医院账号 + +> 物业公司不可操作此模块。 + +| 编号 | 功能点 | 说明 | 优先级 | +|------|--------|------|--------| +| HO-BD-01 | 招标计划 | 创建计划,关联项目,设置招标方式和时间节点 | P0 | +| HO-BD-02 | 标段管理 | 拆分为多个标段,设置范围和要求 | P0 | +| HO-BD-03 | 供应商管理 | 供应商信息库、资质审核、黑白名单 | P0 | +| HO-BD-04 | 招标发布 | 发布招标公告,邀请供应商 | P0 | +| HO-BD-05 | 投标管理 | 投标文件管理,截止时间控制 | P0 | +| HO-BD-06 | 评标管理 | 评标委员会组建,评分标准设置,评分录入 | P0 | +| HO-BD-07 | 定标审批 | 定标审批流程 | P0 | +| HO-BD-08 | 中标公示 | 公示中标结果,公示期后生成合同 | P0 | +| HO-BD-09 | 招标导出 | 导出招标相关文档 | P1 | + +--- + +## 3. 服务监督 + +| 编号 | 功能点 | 说明 | 优先级 | +|------|--------|------|--------| +| HO-SP-01 | 报修数据查看 | 查看关联物业公司的报修工单数据(只读) | P0 | +| HO-SP-02 | 工单详情查看 | 查看工单完整信息、流转记录、照片附件(只读) | P0 | +| HO-SP-03 | 巡检数据查看 | 查看关联物业公司的巡检记录数据(只读) | P0 | +| HO-SP-04 | 保洁数据查看 | 查看关联物业公司的保洁任务数据(只读) | P0 | + +--- + +## 4. 服务评价 + +| 编号 | 功能点 | 说明 | 优先级 | +|------|--------|------|--------| +| HO-EV-01 | 发起评价 | 对物业服务发起评分与留言 | P0 | +| HO-EV-02 | 评价汇总查看 | 查看评价汇总看板与统计 | P0 | +| HO-EV-03 | 评价列表查看 | 查看历史评价列表(只读) | P0 | + +--- + +## 5. 统计报表 + +| 编号 | 报表类型 | 时间维度 | 支持操作 | 优先级 | +|------|----------|----------|----------|--------| +| HO-ST-01 | 报修统计 | 天/周/月/年/自定义 | 查看(只读) | P0 | +| HO-ST-02 | 巡检统计 | 天/周/月/年/自定义 | 查看(只读) | P0 | +| HO-ST-03 | 保洁统计 | 天/周/月/年/自定义 | 查看(只读) | P0 | +| HO-ST-04 | 评价统计 | 天/周/月/年/自定义 | 查看(只读) | P0 | +| HO-ST-05 | 合同统计 | 天/周/月/年/自定义 | 查看+导出 | P0 | +| HO-ST-06 | 招标统计 | 天/周/月/年/自定义 | 查看+导出 | P0 | +| HO-ST-07 | 综合看板 | 天/周/月/年/自定义 | 查看 | P0 | +| HO-ST-08 | 自定义报表 | 自定义 | 用户自选维度+指标 | P1 | diff --git a/docs/02-功能清单-医院/01-合同管理.md b/docs/02-功能清单-医院/01-合同管理.md new file mode 100644 index 0000000..cb23965 --- /dev/null +++ b/docs/02-功能清单-医院/01-合同管理.md @@ -0,0 +1,298 @@ +# 合同管理 + +> 模块编码:contract +> 端侧:Web专属(仅医院账号) +> 关联文档:01-模块划分 §4.1 / 02-功能清单-医院 §1 / 03-业务流转逻辑-医院 §1 / 05-接口规范 §9.2 + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 合同管理 | +| 子菜单 | 合同台账、合同录入、合同详情、合同审批、付款管理、变更管理、到期预警、续签管理、合同导出 | +| 功能编号 | HO-CT-01 ~ HO-CT-11 | +| 权限编码前缀 | contract:list:* / contract:approve:* / contract:payment:* / contract:change:* | + +> **重要**:合同管理仅医院账号可用,物业公司不可操作此模块。 + +--- + +## 页面1:合同台账页 + +**页面编号**:HO-CT-01-P01 +**端侧归属**:Web专属 +**页面路径**:/contract/list + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 合同管理 > 合同台账 │ +├──────────────────────────────────────────────────────────────────┤ +│ [查询条件区] │ +│ 合同名称[____] 合同类型[▼] 状态[▼] 物业公司[▼] │ +│ 签约日期[起始]~[结束] [查询] [重置] │ +├──────────────────────────────────────────────────────────────────┤ +│ [操作栏] [新增合同] [导出Excel] │ +├──────────────────────────────────────────────────────────────────┤ +│ [列表区] │ +│ 序号| 合同名称 | 类型 | 物业公司 | 金额 | 状态 | 到期日 │ +│ 1 | 2026年保洁 | 保洁 | XX物业 | 120万 | 履约中 | 2027-04 │ +│ 2 | 2026年维修 | 维修 | XX物业 | 80万 | 审批中 | — │ +│ 3 | 2025年安保 | 安保 | YY物业 | 60万 | 即将到期| 2026-05 │ +├──────────────────────────────────────────────────────────────────┤ +│ [分页] 共25条 每页[20▼] < 1 2 > │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 合同名称 | 文本输入 | 否 | — | 模糊匹配 | +| 合同类型 | 下拉单选 | 否 | 全部 | 保洁/维修/安保/综合/其他 | +| 状态 | 下拉单选 | 否 | 全部 | 审批中/履约中/变更审批中/即将到期/已终止 | +| 物业公司 | 下拉单选 | 否 | 全部 | 关联物业公司 | +| 签约日期 | 日期范围 | 否 | — | — | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 序号 | 60px | — | 自增 | +| 2 | 合同名称 | 180px | 是 | 点击跳转详情 | +| 3 | 合同类型 | 80px | 否 | 标签样式 | +| 4 | 物业公司 | 120px | 是 | — | +| 5 | 合同金额 | 100px | 是 | — | +| 6 | 状态 | 90px | 是 | 彩色标签 | +| 7 | 服务期限 | 120px | 否 | 起始~结束 | +| 8 | 到期日 | 100px | 是 | 即将到期=橙色 | +| 9 | 操作 | 140px | — | 查看/审批 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 新增合同 | contract:list:create | 操作栏 | 始终 | — | +| 导出Excel | contract:list:export | 操作栏 | 始终 | — | +| 查看 | contract:list:view | 行操作 | 始终 | — | +| 审批 | contract:approve:* | 行操作 | 状态=审批中 | — | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/contracts | GET | 分页查询 | +| 导出 | /api/v1/contracts/export | GET | — | + +--- + +## 页面2:合同录入页 + +**页面编号**:HO-CT-02-P01 +**端侧归属**:Web专属 +**页面路径**:/contract/create + +### 表单字段 + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 合同名称 | 文本输入 | 是 | — | 自填 | 最大100字 | +| 合同类型 | 下拉单选 | 是 | — | 字典管理-合同类型 | — | +| 关联物业公司 | 下拉单选 | 是 | — | 本医院关联的物业公司 | — | +| 关联院区 | 下拉多选 | 是 | — | 本医院院区列表 | — | +| 合同金额 | 数字输入 | 是 | — | 自填 | >0 | +| 服务期限(起) | 日期选择 | 是 | — | 自填 | — | +| 服务期限(止) | 日期选择 | 是 | — | 自填 | 晚于起始日期 | +| 付款方式 | 下拉单选 | 是 | — | 固定选项 | 一次性/分期/按节点 | +| 合同描述 | 多行文本 | 否 | — | 自填 | 最大500字 | +| 合同附件 | 文件上传 | 是 | — | 上传 | ≤10个文件,支持PDF/Word/图片 | + +### 付款节点(分期付款时) + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 节点名称 | 文本输入 | 是 | — | 自填 | — | +| 节点金额 | 数字输入 | 是 | — | 自填 | — | +| 预计付款日期 | 日期选择 | 是 | — | 自填 | — | +| 付款条件 | 多行文本 | 否 | — | 自填 | — | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 保存草稿 | contract:list:create | 底部 | 始终 | — | +| 提交审批 | contract:list:create | 底部 | 始终 | 状态→审批中 | + +### 通知触发 + +| 触发操作 | 通知对象 | 通知方式 | 消息模板 | 文档来源 | +|----------|----------|----------|----------|----------| +| 提交审批 | 审批人 | Web提醒 | 合同审批待办 | 03-医院 §1.2 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 新增 | /api/v1/contracts | POST | — | +| 提交审批 | /api/v1/contracts/{id}/submit | POST | — | + +--- + +## 页面3:合同详情页 + +**页面编号**:HO-CT-03-P01 +**端侧归属**:Web专属 +**页面路径**:/contract/:id + +### 标签页内容 + +| 标签页 | 内容 | 说明 | +|--------|------|------| +| 基本信息 | 合同名称、类型、金额、服务期限、物业公司、院区 | — | +| 付款节点 | 付款计划列表、各节点状态 | — | +| 变更记录 | 合同变更历史 | — | +| 关联项目 | 关联的招标项目 | — | +| 附件 | 合同文件、补充文件 | — | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 审批通过 | contract:approve:* | 底部 | 状态=审批中 | — | +| 审批驳回 | contract:approve:* | 底部 | 状态=审批中 | 填写驳回原因 | +| 申请变更 | contract:change:create | 底部 | 状态=履约中 | — | +| 终止合同 | contract:list:update | 底部 | 状态=履约中 | 二次确认 | + +--- + +## 页面4:付款管理页 + +**页面编号**:HO-CT-05-P01 +**端侧归属**:Web专属 +**页面路径**:/contract/payments + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 合同名称 | 150px | 否 | — | +| 2 | 节点名称 | 120px | 否 | — | +| 3 | 节点金额 | 100px | 是 | — | +| 4 | 预计付款日期 | 120px | 是 | — | +| 5 | 实际付款日期 | 120px | 否 | — | +| 6 | 状态 | 80px | 否 | 待付款/已付款/逾期 | +| 7 | 操作 | 100px | — | 确认付款 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 确认付款 | contract:payment:update | 行操作 | 状态=待付款 | 填写实际付款信息 | + +### 通知触发 + +| 触发操作 | 通知对象 | 通知方式 | 消息模板 | 文档来源 | +|----------|----------|----------|----------|----------| +| 付款节点到期提醒 | 医院账号 | Web提醒 | 付款节点即将到期 | 03-医院 §1.2 | + +--- + +## 页面5:变更管理页 + +**页面编号**:HO-CT-07-P01 +**端侧归属**:Web专属 +**页面路径**:/contract/changes + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 合同名称 | 150px | 否 | — | +| 2 | 变更类型 | 80px | 否 | 金额变更/期限变更/条款变更 | +| 3 | 变更原因 | 200px | 否 | — | +| 4 | 申请人 | 80px | 否 | — | +| 5 | 申请时间 | 140px | 是 | 默认倒序 | +| 6 | 审批状态 | 90px | 否 | 待审批/已通过/已驳回 | +| 7 | 操作 | 100px | — | 审批/查看 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 审批 | contract:change:approve | 行操作 | 审批状态=待审批 | 通过/驳回 | + +--- + +## 页面6:到期预警页 + +**页面编号**:HO-CT-09-P01 +**端侧归属**:Web专属 +**页面路径**:/contract/expiring + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 合同名称 | 150px | 否 | — | +| 2 | 物业公司 | 120px | 否 | — | +| 3 | 到期日期 | 120px | 是 | — | +| 4 | 剩余天数 | 80px | 是 | 红色标记 | +| 5 | 操作 | 120px | — | 续签/终止 | + +### 通知触发 + +| 触发操作 | 通知对象 | 通知方式 | 消息模板 | 文档来源 | +|----------|----------|----------|----------|----------| +| 合同到期前30天 | 医院账号 | Web提醒 | 合同即将到期 | 03-医院 §1.2 / 05 §5.2 (CONTRACT_EXPIRING) | +| 合同到期前15天 | 医院账号 | Web提醒 | 合同即将到期 | — | +| 合同到期前7天 | 医院账号 | Web提醒 | 合同即将到期 | — | + +--- + +## 需求追溯 + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| HO-CT-01 | 合同台账 | 02-医院 §1 / 03-医院 §1.2 | — | — | +| HO-CT-02 | 合同录入 | 02-医院 §1 / 03-医院 §1.2 | 录入→提交审批 | — | +| HO-CT-03 | 合同详情 | 02-医院 §1 / 03-医院 §1.2 | — | 招标管理(关联项目) | +| HO-CT-04 | 合同审批 | 02-医院 §1 / 03-医院 §1.2 | 审批→履约中 | 操作日志 | +| HO-CT-05 | 付款管理 | 02-医院 §1 / 03-医院 §1.2 | 节点到期→提醒 | — | +| HO-CT-06 | 付款确认 | 02-医院 §1 / 03-医院 §1.2 | 确认→更新付款状态 | — | +| HO-CT-07 | 变更管理 | 02-医院 §1 / 03-医院 §1.2 | 变更→审批 | — | +| HO-CT-08 | 变更审批 | 02-医院 §1 / 03-医院 §1.2 | 通过→变更生效 | 操作日志 | +| HO-CT-09 | 到期预警 | 02-医院 §1 / 03-医院 §1.2 | 到期→提醒→续签/终止 | 通知机制 | +| HO-CT-10 | 续签管理 | 02-医院 §1 / 03-医院 §1.2 | 续签→审批流程 | 合同审批 | +| HO-CT-11 | 合同导出 | 02-医院 §1 | — | 操作日志 | + +## 业务规则 + +1. **仅医院账号可用**:物业公司不可操作此模块(来源:01 §4.1 / 02-医院 §1) +2. **合同审批流程**:录入→审批中→审批通过(履约中)/审批驳回(需修改重新提交)(来源:03-医院 §1.2) +3. **到期预警**:合同到期前30/15/7天自动提醒(来源:02-医院 HO-CT-09 / 03-医院 §1.2) +4. **付款节点提醒**:付款节点到期前自动提醒医院账号(来源:03-医院 §1.2) +5. **变更需审批**:合同变更申请需审批通过后才生效(来源:03-医院 §1.2) +6. **所有操作记录日志**:合同录入、审批、付款、变更等操作自动记录(来源:06 §4.5) + +## 状态流转 + +``` +合同录入 ──▶ 审批中 ──▶ 履约中 ──▶ 到期预警 ──▶ 续签/终止 + │ │ + 审批驳回 变更管理(可选) ──▶ 变更审批中 + (需修改) │ + 变更审批通过/驳回 +``` + +| 当前状态 | 操作 | 目标状态 | 执行角色 | 端侧 | +|----------|------|----------|----------|------| +| — | 合同录入 | 审批中 | 医院账号 | Web | +| 审批中 | 审批通过 | 履约中 | 医院账号 | Web | +| 审批中 | 审批驳回 | — | 医院账号 | Web | +| 履约中 | 付款确认 | 履约中 | 医院账号 | Web | +| 履约中 | 变更申请 | 变更审批中 | 医院账号 | Web | +| 变更审批中 | 变更审批通过 | 履约中 | 医院账号 | Web | +| 变更审批中 | 变更审批驳回 | 履约中 | 医院账号 | Web | +| 履约中 | 续签 | 履约中 | 医院账号 | Web | +| 履约中 | 终止 | 已终止 | 医院账号 | Web | diff --git a/docs/02-功能清单-医院/02-分段招标管理.md b/docs/02-功能清单-医院/02-分段招标管理.md new file mode 100644 index 0000000..cf6ae23 --- /dev/null +++ b/docs/02-功能清单-医院/02-分段招标管理.md @@ -0,0 +1,310 @@ +# 分段招标管理 + +> 模块编码:bidding +> 端侧:Web专属(仅医院账号) +> 关联文档:01-模块划分 §4.2 / 02-功能清单-医院 §2 / 03-业务流转逻辑-医院 §2 / 05-接口规范 §9.2 + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 分段招标管理 | +| 子菜单 | 招标计划、标段管理、供应商管理、招标发布、投标管理、评标管理、定标审批、中标公示 | +| 功能编号 | HO-BD-01 ~ HO-BD-09 | +| 权限编码前缀 | bidding:plan:* / bidding:section:* / bidding:supplier:* / bidding:award:* | + +> **重要**:分段招标管理仅医院账号可用,物业公司不可操作此模块。 + +--- + +## 页面1:招标计划页 + +**页面编号**:HO-BD-01-P01 +**端侧归属**:Web专属 +**页面路径**:/bidding/plans + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 分段招标管理 > 招标计划 │ +├──────────────────────────────────────────────────────────────────┤ +│ [查询条件区] │ +│ 计划名称[____] 状态[▼] 招标方式[▼] [查询] [重置] │ +├──────────────────────────────────────────────────────────────────┤ +│ [操作栏] [新增招标计划] │ +├──────────────────────────────────────────────────────────────────┤ +│ [列表区] │ +│ 序号| 计划名称 | 招标方式 | 标段数 | 状态 | 创建时间 | 操作 │ +│ 1 | 2026年保洁招标 | 公开招标 | 3 | 投标中 | 04-01 | 查看 │ +│ 2 | 2026年维修招标 | 邀请招标 | 2 | 计划中 | 04-10 | 编辑 │ +├──────────────────────────────────────────────────────────────────┤ +│ [分页] 共8条 │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 表单字段(新增/编辑页) + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 计划名称 | 文本输入 | 是 | — | 自填 | 最大100字 | +| 关联项目 | 下拉单选 | 是 | — | 本医院院区 | — | +| 招标方式 | 下拉单选 | 是 | — | 固定选项 | 公开招标/邀请招标/竞争性谈判 | +| 预算金额 | 数字输入 | 是 | — | 自填 | >0 | +| 投标截止日期 | 日期时间 | 是 | — | 自填 | 晚于当前时间 | +| 计划描述 | 多行文本 | 否 | — | 自填 | 最大500字 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 新增招标计划 | bidding:plan:create | 操作栏 | 始终 | — | +| 编辑 | bidding:plan:update | 行操作 | 状态=计划中 | — | +| 查看 | bidding:plan:view | 行操作 | 始终 | — | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/bidding-plans | GET | — | +| 新增 | /api/v1/bidding-plans | POST | — | +| 编辑 | /api/v1/bidding-plans/{id} | PUT | — | + +--- + +## 页面2:标段管理页 + +**页面编号**:HO-BD-02-P01 +**端侧归属**:Web专属 +**页面路径**:/bidding/sections + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 标段名称 | 150px | 否 | — | +| 2 | 所属计划 | 150px | 否 | — | +| 3 | 标段范围 | 200px | 否 | — | +| 4 | 预算金额 | 100px | 是 | — | +| 5 | 投标供应商数 | 100px | 否 | — | +| 6 | 状态 | 80px | 否 | — | +| 7 | 操作 | 100px | — | 编辑/查看 | + +### 表单字段(新增/编辑弹窗) + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 标段名称 | 文本输入 | 是 | — | 自填 | 最大50字 | +| 标段范围 | 多行文本 | 是 | — | 自填 | 最大500字 | +| 预算金额 | 数字输入 | 是 | — | 自填 | >0 | +| 资质要求 | 多行文本 | 否 | — | 自填 | — | +| 评标标准 | 多行文本 | 否 | — | 自填 | — | + +--- + +## 页面3:供应商管理页 + +**页面编号**:HO-BD-03-P01 +**端侧归属**:Web专属 +**页面路径**:/bidding/suppliers + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 供应商名称 | 150px | 是 | — | +| 2 | 联系人 | 80px | 否 | — | +| 3 | 联系电话 | 120px | 否 | — | +| 4 | 资质状态 | 80px | 否 | 已审核/待审核/黑名单 | +| 5 | 合作次数 | 80px | 是 | — | +| 6 | 操作 | 140px | — | 编辑/审核/拉黑 | + +### 表单字段(新增/编辑弹窗) + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 供应商名称 | 文本输入 | 是 | — | 自填 | 最大100字 | +| 统一社会信用代码 | 文本输入 | 是 | — | 自填 | 18位 | +| 联系人 | 文本输入 | 是 | — | 自填 | — | +| 联系电话 | 文本输入 | 是 | — | 自填 | 手机号格式 | +| 地址 | 文本输入 | 否 | — | 自填 | — | +| 资质文件 | 文件上传 | 否 | — | 上传 | ≤5个文件 | +| 备注 | 多行文本 | 否 | — | 自填 | 最大200字 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 新增供应商 | bidding:supplier:create | 操作栏 | 始终 | — | +| 编辑 | bidding:supplier:update | 行操作 | 始终 | — | +| 资质审核 | bidding:supplier:approve | 行操作 | 资质状态=待审核 | 通过/驳回 | +| 拉黑/移出黑名单 | bidding:supplier:update | 行操作 | 始终 | 黑名单供应商不可投标 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/suppliers | GET | — | +| 新增 | /api/v1/suppliers | POST | — | +| 资质审核 | /api/v1/suppliers/{id}/audit | POST | — | +| 拉黑 | /api/v1/suppliers/{id}/blacklist | PUT | — | + +--- + +## 页面4:招标发布页 + +**页面编号**:HO-BD-04-P01 +**端侧归属**:Web专属 +**页面路径**:/bidding/publish + +### 操作流程 + +``` +选择招标计划 → 确认标段 → 上传招标文件 → 邀请供应商(邀请招标时) → 发布 +``` + +### 表单字段 + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 招标计划 | 下拉单选 | 是 | — | 计划中/待发布的计划 | — | +| 招标公告 | 多行文本 | 是 | — | 自填 | — | +| 招标文件 | 文件上传 | 是 | — | 上传 | ≤10个文件 | +| 邀请供应商 | 下拉多选 | 条件 | — | 供应商列表(已审核) | 邀请招标时必填 | + +--- + +## 页面5:投标管理页 + +**页面编号**:HO-BD-05-P01 +**端侧归属**:Web专属 +**页面路径**:/bidding/bids + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 标段名称 | 120px | 否 | — | +| 2 | 供应商 | 120px | 否 | — | +| 3 | 投标时间 | 140px | 是 | — | +| 4 | 投标金额 | 100px | 是 | — | +| 5 | 投标文件 | 100px | 否 | 下载查看 | +| 6 | 状态 | 80px | 否 | 已投标/已开标 | + +--- + +## 页面6:评标管理页 + +**页面编号**:HO-BD-06-P01 +**端侧归属**:Web专属 +**页面路径**:/bidding/evaluations + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 分段招标管理 > 评标管理 │ +├──────────────────────────────────────────────────────────────────┤ +│ [评标委员会] [组建评标委员会] │ +│ 评标人1:张三 评标人2:李四 评标人3:王五 │ +├──────────────────────────────────────────────────────────────────┤ +│ [评分标准] [设置评分标准] │ +│ 商务评分权重:40% 技术评分权重:40% 价格评分权重:20% │ +├──────────────────────────────────────────────────────────────────┤ +│ [评分录入] │ +│ 供应商 | 商务分 | 技术分 | 价格分 | 总分 | 排名 │ +│ XX公司 | [___] | [___] | [___] | — | — │ +│ YY公司 | [___] | [___] | [___] | — | — │ +│ [提交评标结果] │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 组建评标委员会 | bidding:award:create | 操作栏 | 始终 | — | +| 设置评分标准 | bidding:award:create | 操作栏 | 始终 | — | +| 提交评标结果 | bidding:award:update | 操作栏 | 始终 | — | + +--- + +## 页面7:定标审批页 + +**页面编号**:HO-BD-07-P01 +**端侧归属**:Web专属 +**页面路径**:/bidding/award + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 定标审批 | bidding:award:approve | 行操作 | 状态=待定标 | 通过/驳回 | + +--- + +## 页面8:中标公示页 + +**页面编号**:HO-BD-08-P01 +**端侧归属**:Web专属 +**页面路径**:/bidding/publicity + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 标段名称 | 120px | 否 | — | +| 2 | 中标供应商 | 120px | 否 | — | +| 3 | 中标金额 | 100px | 是 | — | +| 4 | 公示开始日 | 100px | 否 | — | +| 5 | 公示结束日 | 100px | 否 | — | +| 6 | 状态 | 80px | 否 | 公示中/已生效 | +| 7 | 操作 | 100px | — | 生成合同 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 生成合同 | contract:list:create | 行操作 | 状态=已生效 | 跳转合同管理创建合同 | + +--- + +## 需求追溯 + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| HO-BD-01 | 招标计划 | 02-医院 §2 / 03-医院 §2.2 | 计划→标段拆分 | — | +| HO-BD-02 | 标段管理 | 02-医院 §2 / 03-医院 §2.2 | 标段→招标发布 | — | +| HO-BD-03 | 供应商管理 | 02-医院 §2 | 供应商→投标 | — | +| HO-BD-04 | 招标发布 | 02-医院 §2 / 03-医院 §2.2 | 发布→供应商投标 | — | +| HO-BD-05 | 投标管理 | 02-医院 §2 / 03-医院 §2.2 | 投标截止→评标 | — | +| HO-BD-06 | 评标管理 | 02-医院 §2 / 03-医院 §2.2 | 评标完成→定标 | — | +| HO-BD-07 | 定标审批 | 02-医院 §2 / 03-医院 §2.2 | 定标→公示 | 操作日志 | +| HO-BD-08 | 中标公示 | 02-医院 §2 / 03-医院 §2.2 | 公示期满→生成合同 | 合同管理 | +| HO-BD-09 | 招标导出 | 02-医院 §2 | — | 操作日志 | + +## 业务规则 + +1. **仅医院账号可用**:物业公司不可操作此模块(来源:01 §4.2 / 02-医院 §2) +2. **供应商信息自管**:供应商信息由医院账号在本系统中录入和管理(来源:03-医院 §2.2) +3. **黑名单供应商**:黑名单供应商不可参与投标(来源:02-医院 HO-BD-03) +4. **投标截止**:截止时间到达后自动截止,不可再提交投标(来源:03-医院 §2.2) +5. **中标→生成合同**:公示期满后可一键生成合同,跳转合同管理创建(来源:03-医院 §2.2) +6. **所有操作记录日志**:招标各环节操作自动记录(来源:06 §4.5) + +## 状态流转 + +``` +招标计划 ──▶ 标段拆分 ──▶ 招标发布 ──▶ 投标中 ──▶ 评标中 ──▶ 待定标 ──▶ 公示中 ──▶ 已定标 ──▶ 生成合同 +``` + +| 当前状态 | 操作 | 目标状态 | 执行角色 | 端侧 | +|----------|------|----------|----------|------| +| — | 创建招标计划 | 计划中 | 医院账号 | Web | +| 计划中 | 标段拆分 | 待发布 | 医院账号 | Web | +| 待发布 | 发布招标 | 投标中 | 医院账号 | Web | +| 投标中 | 投标截止 | 评标中 | 系统/医院 | Web | +| 评标中 | 评标完成 | 待定标 | 医院账号 | Web | +| 待定标 | 定标审批 | 公示中 | 医院账号 | Web | +| 公示中 | 公示期满 | 已定标 | 系统自动 | Web | +| 已定标 | 生成合同 | — | 医院账号 | Web | diff --git a/docs/02-功能清单-医院/03-服务监督.md b/docs/02-功能清单-医院/03-服务监督.md new file mode 100644 index 0000000..cdbea38 --- /dev/null +++ b/docs/02-功能清单-医院/03-服务监督.md @@ -0,0 +1,172 @@ +# 服务监督 + +> 模块编码:service-supervision +> 端侧:Web专属(仅医院账号) +> 关联文档:01-模块划分 §4.3 / 02-功能清单-医院 §3 / 03-业务流转逻辑-医院 §3 / 05-接口规范 §9.2 + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 服务监督 | +| 子菜单 | 报修数据查看、巡检数据查看、保洁数据查看 | +| 功能编号 | HO-SP-01 ~ HO-SP-04 | +| 权限编码前缀 | 继承物业模块权限的只读版本 | + +> **重要**:医院账号仅查看关联物业公司的日常业务数据,**只读,不可操作**。 + +--- + +## 页面1:报修数据查看页 + +**页面编号**:HO-SP-01-P01 +**端侧归属**:Web专属 +**页面路径**:/supervision/repair + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 服务监督 > 报修数据查看 │ +├──────────────────────────────────────────────────────────────────┤ +│ [查询条件区] │ +│ 工单号[____] 状态[▼] 报修类型[▼] 紧急程度[▼] │ +│ 提交日期[起始]~[结束] 所属班组[▼] 所属区域[▼] │ +│ [查询] [重置] │ +├──────────────────────────────────────────────────────────────────┤ +│ [统计卡片区] │ +│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │ +│ │总工单│ │待分配│ │处理中│ │已完成│ │ +│ │ 156 │ │ 12 │ │ 23 │ │ 108 │ │ +│ └──────┘ └──────┘ └──────┘ └──────┘ │ +├──────────────────────────────────────────────────────────────────┤ +│ [列表区] │ +│ 工单号 | 报修类型 | 紧急程度 | 状态 | 报修人 | 班组 | 提交时间 │ +│ WX001 | 水电 | 紧急 | 待分配| 张三 | 水电班| 04-16 10:30│ +├──────────────────────────────────────────────────────────────────┤ +│ [分页] 共156条 每页[20▼] < 1 2 3 ... 8 > │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 工单号 | 文本输入 | 否 | — | 模糊匹配 | +| 状态 | 下拉多选 | 否 | 全部 | — | +| 报修类型 | 下拉单选 | 否 | 全部 | — | +| 紧急程度 | 下拉单选 | 否 | 全部 | — | +| 提交日期 | 日期范围 | 否 | — | — | +| 所属班组 | 下拉单选 | 否 | 全部 | — | +| 所属区域 | 级联选择 | 否 | 全部 | — | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 工单号 | 140px | 是 | 点击查看详情(只读) | +| 2 | 报修类型 | 80px | 否 | — | +| 3 | 紧急程度 | 80px | 否 | — | +| 4 | 状态 | 90px | 是 | — | +| 5 | 报修人 | 80px | 否 | — | +| 6 | 负责班组 | 90px | 否 | — | +| 7 | 维修人员 | 80px | 否 | — | +| 8 | 提交时间 | 150px | 是 | 默认倒序 | +| 9 | 操作 | 80px | — | 查看详情(只读) | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 查看详情 | repair:list:view(只读) | 行操作 | 始终 | 跳转只读详情页 | + +### 角色差异化视图 + +| 角色 | 可见按钮 | 数据范围 | 备注 | +|------|----------|----------|------| +| 医院账号 | 仅查看 | 关联物业公司的全部报修数据 | 无任何操作按钮 | + +### 工单详情页(只读) + +- 展示与物业公司工单详情相同的信息 +- 标签页:基本信息、流转记录、照片附件 +- 底部无任何操作按钮 + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/repair-orders | GET | 只读,自动过滤关联物业公司 | +| 详情查询 | /api/v1/repair-orders/{id} | GET | 只读 | + +--- + +## 页面2:巡检数据查看页 + +**页面编号**:HO-SP-03-P01 +**端侧归属**:Web专属 +**页面路径**:/supervision/inspection + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 巡检人员 | 80px | 否 | — | +| 2 | 计划名称 | 150px | 否 | — | +| 3 | 巡检区域 | 150px | 否 | — | +| 4 | 打卡时间 | 140px | 是 | — | +| 5 | 打卡方式 | 80px | 否 | 蓝牙/手动/补录 | +| 6 | 状态 | 80px | 否 | 正常/异常 | +| 7 | 异常数 | 70px | 否 | — | +| 8 | 操作 | 80px | — | 查看详情 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 查看详情 | inspection:task:view(只读) | 行操作 | 始终 | 只读 | + +--- + +## 页面3:保洁数据查看页 + +**页面编号**:HO-SP-04-P01 +**端侧归属**:Web专属 +**页面路径**:/supervision/cleaning + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 保洁人员 | 80px | 否 | — | +| 2 | 保洁区域 | 150px | 否 | — | +| 3 | 任务日期 | 100px | 是 | — | +| 4 | 打卡时间 | 140px | 否 | — | +| 5 | 打卡方式 | 80px | 否 | — | +| 6 | 完成状态 | 80px | 否 | 已完成/超时/未执行 | +| 7 | 抽查结果 | 80px | 否 | 合格/不合格/未抽查 | +| 8 | 操作 | 80px | — | 查看详情 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 查看详情 | cleaning:task:view(只读) | 行操作 | 始终 | 只读 | + +--- + +## 需求追溯 + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| HO-SP-01 | 报修数据查看 | 02-医院 §3 / 03-医院 §3.1 | — | 物业在线报修(数据来源) | +| HO-SP-02 | 工单详情查看 | 02-医院 §3 / 03-医院 §3.1 | — | 物业工单详情(数据来源) | +| HO-SP-03 | 巡检数据查看 | 02-医院 §3 / 03-医院 §3.1 | — | 物业巡检管理(数据来源) | +| HO-SP-04 | 保洁数据查看 | 02-医院 §3 / 03-医院 §3.1 | — | 物业保洁管理(数据来源) | + +## 业务规则 + +1. **仅查看不可操作**:医院账号可查看关联物业公司的全部日常业务数据,但不能分配工单、审核补录等操作(来源:01 §4.3 / 03-医院 §3) +2. **数据来源**:物业公司日常业务录入的数据(来源:03-医院 §3.1) +3. **数据范围**:仅查看为本医院服务的物业公司的数据(来源:01 §1.3 / 03-医院 §3) +4. **支持筛选和导出**:支持时间范围、区域、状态等筛选条件,支持导出报表(只读)(来源:03-医院 §3.1) diff --git a/docs/02-功能清单-医院/04-服务评价.md b/docs/02-功能清单-医院/04-服务评价.md new file mode 100644 index 0000000..67bc7af --- /dev/null +++ b/docs/02-功能清单-医院/04-服务评价.md @@ -0,0 +1,192 @@ +# 服务评价 + +> 模块编码:evaluation +> 端侧:Web专属(仅医院账号) +> 关联文档:01-模块划分 §4.4 / 02-功能清单-医院 §4 / 03-业务流转逻辑-医院 §4 / 05-接口规范 §9.2 + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 服务评价 | +| 子菜单 | 发起评价、评价汇总查看、评价列表查看 | +| 功能编号 | HO-EV-01 ~ HO-EV-03 | +| 权限编码前缀 | evaluation:list:* | + +> **重要**:医院账号是评价的**发起方**,物业公司是评价的**接收和回复方**。 + +--- + +## 页面1:发起评价页 + +**页面编号**:HO-EV-01-P01 +**端侧归属**:Web专属 +**页面路径**:/evaluation/create + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 服务评价 > 发起评价 │ +├──────────────────────────────────────────────────────────────────┤ +│ ── 评价类型 ── │ +│ ○ 报修服务 ○ 巡检服务 ○ 保洁服务 ○ 综合评价 │ +├──────────────────────────────────────────────────────────────────┤ +│ ── 评价对象 ── │ +│ 关联物业公司:[▼] │ +│ 关联服务:[▼] (选择具体工单/巡检任务/保洁任务) │ +├──────────────────────────────────────────────────────────────────┤ +│ ── 评分 ── │ +│ ★★★★★ 5分-非常满意 │ +│ ★★★★☆ 4分-满意 │ +│ ★★★☆☆ 3分-一般 │ +│ ★★☆☆☆ 2分-不满意 │ +│ ★☆☆☆☆ 1分-非常不满意 │ +├──────────────────────────────────────────────────────────────────┤ +│ ── 评价内容 ── │ +│ 留言:[____________________________] │ +│ 图片:[+点击上传] (≤5张) │ +├──────────────────────────────────────────────────────────────────┤ +│ [取消] [提交评价] │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 表单字段 + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 评价类型 | 单选按钮 | 是 | — | 固定选项 | 报修/巡检/保洁/综合 | +| 关联物业公司 | 下拉单选 | 是 | — | 本医院关联物业公司 | — | +| 关联服务 | 下拉单选 | 条件 | — | 物业公司业务数据 | 非综合评价时必填 | +| 评分 | 星级选择 | 是 | — | 固定选项 | 1~5分 | +| 留言 | 多行文本 | 否 | — | 自填 | 最大500字 | +| 图片 | 图片上传 | 否 | — | 上传 | ≤5张 | + +### 通知触发 + +| 触发操作 | 通知对象 | 通知方式 | 消息模板 | 文档来源 | +|----------|----------|----------|----------|----------| +| 低评分(≤2分) | 物业主管+管理员 | 小程序推送 | 低评分评价通知 | 03-医院 §4.1 / 03-物业公司 §6 | +| 新评价 | 物业公司 | — | 物业可查看评价 | — | + +### 评分触发规则 + +| 评分 | 含义 | 物业端触发动作 | 文档来源 | +|------|------|----------------|----------| +| 5分 | 非常满意 | — | 03-医院 §4.1 | +| 4分 | 满意 | — | 03-医院 §4.1 | +| 3分 | 一般 | 主管关注 | 03-医院 §4.1 | +| 2分 | 不满意 | 自动通知物业主管,要求回复 | 03-医院 §4.1 | +| 1分 | 非常不满意 | 通知主管+管理员,24h内必须回复 | 03-医院 §4.1 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 发起评价 | /api/v1/evaluations | POST | — | + +--- + +## 页面2:评价汇总查看页 + +**页面编号**:HO-EV-02-P01 +**端侧归属**:Web专属 +**页面路径**:/evaluation/dashboard + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 服务评价 > 评价汇总 │ +├──────────────────────────────────────────────────────────────────┤ +│ [时间选择] 本月 / 本季度 / 本年 / 自定义 │ +├──────────────────────────────────────────────────────────────────┤ +│ [统计卡片区] │ +│ ┌──────┐ ┌──────┐ ┌──────┐ │ +│ │总评价│ │平均分│ │待回复│ │ +│ │ 45 │ │ 4.2 │ │ 3 │ │ +│ └──────┘ └──────┘ └──────┘ │ +├──────────────────────────────────────────────────────────────────┤ +│ [图表区] │ +│ ┌────────────────────────┐ ┌────────────────────────┐ │ +│ │ 评分趋势(折线图) │ │ 各物业公司评分对比(柱状图)│ │ +│ └────────────────────────┘ └────────────────────────┘ │ +│ ┌────────────────────────┐ │ +│ │ 星级分布(饼图) │ │ +│ └────────────────────────┘ │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 汇总数据 | /api/v1/evaluations/summary | GET | 本医院发起的评价汇总 | + +--- + +## 页面3:评价列表查看页 + +**页面编号**:HO-EV-03-P01 +**端侧归属**:Web专属 +**页面路径**:/evaluation/list + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 评价类型 | 下拉单选 | 否 | 全部 | — | +| 评分 | 下拉单选 | 否 | 全部 | — | +| 物业公司 | 下拉单选 | 否 | 全部 | — | +| 日期范围 | 日期范围 | 否 | — | — | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 评价类型 | 90px | 否 | — | +| 2 | 关联服务 | 150px | 否 | — | +| 3 | 物业公司 | 120px | 否 | — | +| 4 | 评分 | 80px | 是 | 星级展示 | +| 5 | 评价内容 | 200px | 否 | — | +| 6 | 评价时间 | 140px | 是 | 默认倒序 | +| 7 | 回复状态 | 80px | 否 | 已回复/未回复 | +| 8 | 物业回复 | 200px | 否 | — | +| 9 | 操作 | 80px | — | 查看详情 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 查看详情 | evaluation:list:view | 行操作 | 始终 | 只读 | + +### 角色差异化视图 + +| 角色 | 可见按钮 | 数据范围 | 备注 | +|------|----------|----------|------| +| 医院账号 | 查看 | 本医院发起的所有评价 | — | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/evaluations | GET | 本医院发起的评价 | +| 详情 | /api/v1/evaluations/{id} | GET | 含物业回复 | + +--- + +## 需求追溯 + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| HO-EV-01 | 发起评价 | 02-医院 §4 / 03-医院 §4.1 | 评价→通知物业公司 | 物业服务评价(查看/回复) | +| HO-EV-02 | 评价汇总查看 | 02-医院 §4 / 03-医院 §4.2 | — | 物业评价汇总看板(数据来源) | +| HO-EV-03 | 评价列表查看 | 02-医院 §4 / 03-医院 §4.2 | — | 物业评价列表(数据来源) | + +## 业务规则 + +1. **医院是评价发起方**:医院账号对物业服务发起评分与留言,物业公司查看和回复(来源:01 §6.1 / 03-医院 §4) +2. **评价类型**:报修服务/巡检服务/保洁服务/综合评价(来源:03-医院 §4.1) +3. **关联服务**:评价时需选择具体的工单/巡检任务/保洁任务(综合评价除外)(来源:03-医院 §4.1) +4. **低评分通知**:2分自动通知物业主管,1分通知主管+管理员且24h内必须回复(来源:03-医院 §4.1) +5. **评价数据来源**:物业公司业务数据为只读引用,不可修改(来源:03-医院 §4.1) diff --git a/docs/02-功能清单-医院/05-统计报表.md b/docs/02-功能清单-医院/05-统计报表.md new file mode 100644 index 0000000..b0db996 --- /dev/null +++ b/docs/02-功能清单-医院/05-统计报表.md @@ -0,0 +1,219 @@ +# 统计报表 + +> 模块编码:statistics +> 端侧:Web专属(仅医院账号) +> 关联文档:01-模块划分 §4.5 / 02-功能清单-医院 §5 / 03-业务流转逻辑-医院 §5 / 05-接口规范 §9.2 + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 统计报表 | +| 子菜单 | 报修统计、巡检统计、保洁统计、评价统计、合同统计、招标统计、综合看板、自定义报表 | +| 功能编号 | HO-ST-01 ~ HO-ST-08 | +| 权限编码前缀 | statistics:repair:* / statistics:inspection:* / statistics:cleaning:* / statistics:evaluation:* / statistics:contract:* / statistics:bidding:* / statistics:dashboard:* / statistics:custom:* | + +--- + +## 页面1:报修统计页(只读) + +**页面编号**:HO-ST-01-P01 +**端侧归属**:Web专属 +**页面路径**:/statistics/repair + +### 统计指标 + +| 指标 | 说明 | 数据来源 | +|------|------|----------| +| 总工单数 | 统计时间段内工单总数 | 物业报修数据(只读) | +| 各状态分布 | 待分配/处理中/已完成/已关闭 | 物业报修数据 | +| 完成率 | 已完成/总数 | 物业报修数据 | +| 平均处理时长 | 从分配到完工的平均时间 | 物业报修数据 | +| 紧急工单占比 | 紧急工单/总数 | 物业报修数据 | +| 各班组工单量 | 按班组统计工单数 | 物业报修数据 | + +### 操作权限 + +| 操作 | 权限 | 说明 | +|------|------|------| +| 查看 | statistics:repair:view | 仅查看,不可导出 | +| 导出 | ❌ 不支持 | 业务数据报表仅查看(来源:03-医院 §5) | + +--- + +## 页面2:巡检统计页(只读) + +**页面编号**:HO-ST-02-P01 +**端侧归属**:Web专属 + +### 统计指标 + +| 指标 | 说明 | +|------|------| +| 总巡检任务数 | — | +| 完成率 | — | +| 异常率 | — | +| 蓝牙打卡率 | — | +| 补录率 | — | + +--- + +## 页面3:保洁统计页(只读) + +**页面编号**:HO-ST-03-P01 +**端侧归属**:Web专属 + +### 统计指标 + +| 指标 | 说明 | +|------|------| +| 总保洁任务数 | — | +| 完成率 | — | +| 超时率 | — | +| 抽查合格率 | — | + +--- + +## 页面4:评价统计页(只读) + +**页面编号**:HO-ST-04-P01 +**端侧归属**:Web专属 + +### 统计指标 + +| 指标 | 说明 | +|------|------| +| 总评价数 | 本医院发起的评价 | +| 平均评分 | — | +| 各物业公司评分对比 | — | +| 低评分占比 | — | +| 物业回复率 | — | + +--- + +## 页面5:合同统计页(可导出) + +**页面编号**:HO-ST-05-P01 +**端侧归属**:Web专属 +**页面路径**:/statistics/contract + +### 统计指标 + +| 指标 | 说明 | 数据来源 | +|------|------|----------| +| 合同总数 | — | 本系统合同数据 | +| 合同总金额 | — | 本系统合同数据 | +| 履约率 | 已完成付款/合同金额 | 本系统合同数据 | +| 各物业合同分布 | 按物业公司统计 | 本系统合同数据 | +| 付款完成率 | 已付款节点/总节点 | 本系统合同数据 | +| 即将到期合同 | 30天内到期的合同 | 本系统合同数据 | + +### 操作权限 + +| 操作 | 权限 | 说明 | +|------|------|------| +| 查看 | statistics:contract:view | — | +| 导出 | statistics:contract:export | 合同统计可导出(来源:03-医院 §5) | + +--- + +## 页面6:招标统计页(可导出) + +**页面编号**:HO-ST-06-P01 +**端侧归属**:Web专属 + +### 统计指标 + +| 指标 | 说明 | +|------|------| +| 招标项目数 | — | +| 中标率 | — | +| 平均招标周期 | 从发布到定标的天数 | +| 成本对比 | 预算 vs 中标金额 | +| 各标段中标情况 | — | + +### 操作权限 + +| 操作 | 权限 | 说明 | +|------|------|------| +| 查看 | statistics:bidding:view | — | +| 导出 | statistics:bidding:export | 招标统计可导出 | + +--- + +## 页面7:综合看板页 + +**页面编号**:HO-ST-07-P01 +**端侧归属**:Web专属 +**页面路径**:/statistics/dashboard + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 统计报表 > 综合看板 │ +├──────────────────────────────────────────────────────────────────┤ +│ [时间选择] 今天 / 本周 / 本月 / 自定义 │ +├──────────────────────────────────────────────────────────────────┤ +│ ┌───────────────── 服务数据(只读) ──────────────────┐ │ +│ │ 报修完成率 巡检完成率 保洁完成率 评价均分 │ │ +│ │ 69% 92% 85% 4.2 │ │ +│ └────────────────────────────────────────────────────┘ │ +│ ┌───────────────── 合同/招标数据 ──────────────────┐ │ +│ │ 活跃合同 付款完成率 招标项目 即将到期合同 │ │ +│ │ 12 78% 3 2 │ │ +│ └────────────────────────────────────────────────────┘ │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 数据来源 + +- 服务数据:物业公司业务数据(只读) +- 合同/招标数据:本系统数据 + +--- + +## 页面8:自定义报表页 + +**页面编号**:HO-ST-08-P01 +**端侧归属**:Web专属 +**页面路径**:/statistics/custom + +### 配置选项 + +| 配置项 | 说明 | +|--------|------| +| 数据源 | 报修/巡检/保洁/评价(只读) + 合同/招标(可导出) | +| 维度 | 时间/物业公司/区域/类型 | +| 指标 | 数量/完成率/金额/评分... | +| 时间范围 | 自定义 | + +### 操作权限 + +| 操作 | 权限 | 说明 | +|------|------|------| +| 生成报表 | statistics:custom:view | — | +| 导出 | statistics:custom:export | 合同/招标相关数据可导出,业务数据仅查看 | + +--- + +## 需求追溯 + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| HO-ST-01 | 报修统计 | 02-医院 §5 / 03-医院 §5 | — | 物业报修统计(数据来源) | +| HO-ST-02 | 巡检统计 | 02-医院 §5 / 03-医院 §5 | — | 物业巡检统计(数据来源) | +| HO-ST-03 | 保洁统计 | 02-医院 §5 / 03-医院 §5 | — | 物业保洁统计(数据来源) | +| HO-ST-04 | 评价统计 | 02-医院 §5 / 03-医院 §5 | — | 物业评价统计(数据来源) | +| HO-ST-05 | 合同统计 | 02-医院 §5 / 03-医院 §5 | — | 合同管理(数据来源) | +| HO-ST-06 | 招标统计 | 02-医院 §5 / 03-医院 §5 | — | 招标管理(数据来源) | +| HO-ST-07 | 综合看板 | 02-医院 §5 | — | 全部模块(数据来源) | +| HO-ST-08 | 自定义报表 | 02-医院 §5 | — | 全部模块(数据来源) | + +## 业务规则 + +1. **业务数据报表只读**:报修/巡检/保洁/评价统计仅查看,不支持导出(来源:03-医院 §5) +2. **合同/招标报表可导出**:合同和招标统计支持导出Excel/PDF(来源:03-医院 §5) +3. **数据来源**:业务数据来源于物业公司日常数据(只读),合同/招标数据来源于本系统(来源:03-医院 §5) +4. **数据范围**:仅查看为本医院服务的物业公司的数据(来源:01 §1.3) +5. **时间维度**:支持天/周/月/年/自定义时间段(来源:02-医院 §5) diff --git a/docs/02-功能清单-小程序端.md b/docs/02-功能清单-小程序端.md new file mode 100644 index 0000000..15d43d2 --- /dev/null +++ b/docs/02-功能清单-小程序端.md @@ -0,0 +1,155 @@ +# 微信小程序端 — 功能点清单 + +> 版本:v4.0 +> 微信小程序仅供物业人员使用,**医院账号无小程序端**。 +> 不同角色登录后看到不同功能入口。 +> 关联文档:`01-模块划分.md`(v4.0) + +--- + +## 1. 通用功能 + +| 编号 | 功能点 | 说明 | 优先级 | +|------|--------|------|--------| +| MP-C-01 | 快捷登录 | 微信授权+手机号绑定,自动匹配物业公司与人员信息 | P0 | +| MP-C-02 | 个人信息 | 查看与编辑个人资料 | P0 | +| MP-C-03 | 消息通知 | 接收系统推送消息(新工单、催单、审批等) | P0 | +| MP-C-04 | 数据补录申请 | 提交数据补录申请(需审批) | P0 | +| MP-C-05 | 版本更新提示 | 检测到新版本时提示更新/强制更新 | P0 | +| MP-C-06 | 通讯录 | 查看本班组/物业公司联系人 | P1 | + +--- + +## 2. 报修相关功能 + +| 编号 | 功能点 | 适用角色 | 说明 | 优先级 | +|------|--------|----------|------|--------| +| MP-R-01 | 扫码注册 | 全部 | 扫项目二维码进入,自动注册绑定身份 | P0 | +| MP-R-02 | 一键报修 | 全部 | 选类型、填描述、上传照片(≤9张,含水印时间定位) | P0 | +| MP-R-03 | 我的工单 | 全部 | 查看本人提交的工单及状态 | P0 | +| MP-R-04 | 催单 | 全部 | 对处理中工单发起催单 | P0 | +| MP-R-05 | 维修接单 | 维修人员 | 查看待处理工单、接单 | P0 | +| MP-R-06 | 维修完工 | 维修人员 | 上传维修后照片,填写说明,提交待验收 | P0 | +| MP-R-07 | 延期申请 | 维修人员 | 填写延期原因和预计完成时间 | P0 | +| MP-R-08 | 延期审批 | 主管 | 审批维修人员延期申请 | P0 | +| MP-R-09 | 协助维修申请 | 维修人员 | 请求其他班组协助 | P0 | +| MP-R-10 | 工单分配 | 主管 | 在小程序端分配工单 | P0 | +| MP-R-11 | 工单验收 | 主管/报修人 | 在小程序端验收工单 | P0 | +| MP-R-12 | 评价 | 报修人 | 完工后评分留言 | P0 | + +--- + +## 3. 巡检相关功能 + +| 编号 | 功能点 | 适用角色 | 说明 | 优先级 | +|------|--------|----------|------|--------| +| MP-I-01 | 今日巡检任务 | 巡检人员 | 当日待执行巡检列表 | P0 | +| MP-I-02 | 蓝牙强制打卡 | 巡检人员 | **必须连接蓝牙Beacon后才可打卡,拍照也须在蓝牙连接状态下进行** | P0 | +| MP-I-03 | 巡检执行 | 巡检人员 | 逐项检查巡检清单,记录正常/异常 | P0 | +| MP-I-04 | 异常上报 | 巡检人员 | 拍照上传,标记严重等级,可一键生成报修工单 | P0 | +| MP-I-05 | 巡检历史 | 巡检人员 | 个人巡检记录 | P1 | +| MP-I-06 | 异常数据补录 | 巡检人员 | 蓝牙失灵/定位失败时,进入离线补录模式,填写原因后手动提交,需主管审核 | P0 | + +--- + +## 4. 保洁相关功能 + +| 编号 | 功能点 | 适用角色 | 说明 | 优先级 | +|------|--------|----------|------|--------| +| MP-CL-01 | 今日保洁任务 | 保洁人员 | 当日保洁任务列表 | P0 | +| MP-CL-02 | 蓝牙强制打卡确认 | 保洁人员 | **必须连接蓝牙Beacon后才可确认完成,拍照也须在蓝牙连接状态下进行** | P0 | +| MP-CL-03 | 保洁执行 | 保洁人员 | 逐项完成保洁清单,上传完成后照片 | P0 | +| MP-CL-04 | 异常反馈 | 保洁人员 | 发现卫生问题拍照上报 | P0 | +| MP-CL-05 | 保洁抽查 | 主管 | 在小程序端标记抽查合格/不合格 | P0 | +| MP-CL-06 | 保洁历史 | 保洁人员 | 个人保洁记录 | P1 | +| MP-CL-07 | 异常数据补录 | 保洁人员 | 蓝牙失灵时,进入离线补录模式,填写原因后手动提交 | P0 | + +--- + +## 5. 考勤相关功能 + +| 编号 | 功能点 | 适用角色 | 说明 | 优先级 | +|------|--------|----------|------|--------| +| MP-AT-01 | 上班打卡 | 全部 | **必须在指定打卡点连接蓝牙后才可打卡**,自动记录时间 | P0 | +| MP-AT-02 | 下班打卡 | 全部 | 同上班打卡要求 | P0 | +| MP-AT-03 | 打卡记录 | 全部 | 查看个人打卡历史 | P0 | +| MP-AT-04 | 异常申诉 | 全部 | 蓝牙失灵/系统宕机时提交打卡异常申诉,附原因说明 | P0 | +| MP-AT-05 | 考勤日历 | 全部 | 月视图展示出勤情况 | P1 | +| MP-AT-06 | 考勤审核 | 主管 | 审核员工打卡异常申诉 | P0 | + +--- + +## 6. 组织架构相关功能 + +| 编号 | 功能点 | 适用角色 | 说明 | 优先级 | +|------|--------|----------|------|--------| +| MP-OR-01 | 我的班组 | 全部 | 所在班组信息、班组成员 | P0 | +| MP-OR-02 | 我的排班 | 全部 | 个人排班日历 | P0 | + +--- + +## 7. 服务评价相关功能 + +| 编号 | 功能点 | 适用角色 | 说明 | 优先级 | +|------|--------|----------|------|--------| +| MP-EV-01 | 待评价列表 | 报修人 | 待评价的服务工单 | P0 | +| MP-EV-02 | 评分留言 | 报修人 | 五分制评分+文字留言+图片上传 | P0 | +| MP-EV-03 | 历史评价 | 报修人 | 已提交评价及回复 | P1 | + +--- + +## 8. 统计概览功能 + +| 编号 | 功能点 | 适用角色 | 说明 | 优先级 | +|------|--------|----------|------|--------| +| MP-ST-01 | 简版统计概览 | 管理员/主管 | 按角色权限显示今日/本周关键指标 | P0 | +| MP-ST-02 | 个人绩效统计 | 员工 | 员工查看个人工单量、评分、考勤 | P1 | + +--- + +## 9. 物业公司管理员小程序功能 + +| 编号 | 功能点 | 说明 | 优先级 | +|------|--------|------|--------| +| MP-PM-01 | 报修管理 | 工单列表/分配/流转 | P0 | +| MP-PM-02 | 巡检管理 | 计划/看板/记录 | P0 | +| MP-PM-03 | 保洁管理 | 任务/排班/抽查 | P0 | +| MP-PM-04 | 考勤管理 | 记录/统计 | P0 | +| MP-PM-05 | 评价管理 | 查看/回复 | P0 | +| MP-PM-06 | 组织架构查看 | 查看班组/人员 | P0 | + +--- + +## 附:操作日志记录范围 + +每个业务操作自动记录以下信息: + +| 字段 | 说明 | +|------|------| +| 操作人 | 执行操作的用户 | +| 操作时间 | 精确到秒 | +| 操作人IP | 请求来源IP | +| 操作模块 | 所属功能菜单 | +| 操作页面 | 所属页面 | +| 操作类型 | 查看/新增/编辑/删除/审批/导出/分配 | +| 操作内容 | 具体操作描述 | +| 变更前数据 | 修改前的数据快照(编辑/删除时) | +| 变更后数据 | 修改后的数据快照(新增/编辑时) | +| 请求参数 | 接口请求参数 | +| 响应状态 | 操作成功/失败 | + +## 附:双端审批功能对照表 + +| 审批场景 | Web端 | 小程序端 | 审批角色 | +|----------|-------|----------|----------| +| 工单延期审批 | ✅ | ✅ | 物业(主管) | +| 工单分配 | ✅ | ✅ | 物业(主管) | +| 工单验收 | ✅ | ✅ | 物业(主管/报修人) | +| 合同审批 | ✅ | — | 医院账号(仅Web端) | +| 合同变更审批 | ✅ | — | 医院账号(仅Web端) | +| 合同续签审批 | ✅ | — | 医院账号(仅Web端) | +| 付款确认 | ✅ | — | 医院账号(仅Web端) | +| 定标审批 | ✅ | — | 医院账号(仅Web端) | +| 打卡异常审核 | ✅ | ✅ | 物业(主管) | +| 数据补录审核 | ✅ | ✅ | 物业(主管) | +| 保洁抽查 | ✅ | ✅ | 物业(主管) | diff --git a/docs/02-功能清单-小程序端/01-通用功能.md b/docs/02-功能清单-小程序端/01-通用功能.md new file mode 100644 index 0000000..daeaf88 --- /dev/null +++ b/docs/02-功能清单-小程序端/01-通用功能.md @@ -0,0 +1,239 @@ +# 通用功能 + +> 模块编码:common +> 端侧:小程序 +> 关联文档:01-模块划分.md §5.2、02-功能清单-小程序端.md §1、03-业务流转逻辑-小程序端.md §1&10、05-接口规范.md §2、06-项目技术要求.md §4.1 + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 通用功能 | +| 子菜单 | 快捷登录、个人信息、消息通知、数据补录申请、版本更新提示、通讯录 | +| 功能编号 | MP-C-01 ~ MP-C-06 | +| 权限编码 | —(通用功能,登录即可用) | + +## 页面清单 + +### 页面1:登录页 + +- **页面路径**:`/pages/login/index` +- **页面元素**: + - 微信授权登录按钮(获取openid) + - 手机号绑定按钮(微信获取手机号组件) + - 用户协议与隐私政策链接 + - 版本号展示 +- **界面布局**: + - 顶部:应用Logo + 系统名称 + - 中部:微信一键登录按钮(大按钮,居中) + - 底部:版本号 + 协议链接 +- **操作按钮**: + | 按钮 | 权限 | 说明 | + |------|------|------| + | 微信一键登录 | — | 触发wx.login()获取code,后端换openid | + | 获取手机号 | — | 微信获取手机号组件,绑定手机号 | + +### 页面2:工作台首页 + +- **页面路径**:`/pages/workbench/index` +- **页面元素**: + - 用户头像 + 姓名 + 角色 + - 功能入口网格(根据角色动态渲染) + - 消息通知红点提示 + - 今日关键指标简卡 +- **查询条件**:无 +- **列表字段**:无 +- **界面布局**: + - 顶部:用户信息栏(头像 + 姓名 + 角色 + 消息入口) + - 中部:功能入口网格(2列×N行,按角色动态显示) + - 维修人员:我的工单、消息通知 + - 巡检人员:今日巡检、异常上报 + - 保洁人员:今日保洁、异常反馈 + - 主管:工单分配、审批中心、统计概览 + - 管理员:报修管理、巡检管理、保洁管理、考勤管理、评价管理、组织架构 + - 底部:底部Tab栏(工作台、消息、我的) +- **操作按钮**: + | 按钮 | 权限 | 说明 | + |------|------|------| + | 各功能入口 | 按角色 | 根据权限集动态显示/隐藏 | + +### 页面3:个人信息页 + +- **页面路径**:`/pages/profile/index` +- **页面元素**: + - 头像(可点击查看大图) + - 姓名(只读) + - 手机号(脱敏显示,可修改) + - 所属物业公司(只读) + - 所属班组(只读) + - 角色信息(只读) + - 退出登录按钮 +- **查询条件**:无 +- **列表字段**:无 +- **界面布局**: + - 顶部:头像(居中,大尺寸) + - 中部:信息列表(Label + Value形式) + - 底部:退出登录按钮(红色文字) +- **操作按钮**: + | 按钮 | 权限 | 说明 | + |------|------|------| + | 修改手机号 | — | 弹出微信获取手机号组件 | + | 退出登录 | — | 清除本地token,跳转登录页 | + +### 页面4:消息通知列表 + +- **页面路径**:`/pages/message/list` +- **页面元素**: + - 消息分类Tab(全部 / 工单 / 审批 / 系统) + - 消息列表 + - 未读标记红点 + - 全部标记已读按钮 +- **查询条件**: + | 条件 | 类型 | 说明 | + |------|------|------| + | 分类 | Tab切换 | 全部/工单/审批/系统 | +- **列表字段**: + | 字段 | 说明 | + |------|------| + | 消息标题 | 通知标题 | + | 消息摘要 | 内容前30字 | + | 消息时间 | 相对时间(如"5分钟前") | + | 已读标记 | 红点显示未读 | + | 消息类型图标 | 不同类型不同图标 | +- **界面布局**: + - 顶部:分类Tab + - 中部:消息列表(左图标 + 中标题摘要 + 右时间 + 未读红点) + - 底部:全部标记已读按钮 +- **操作按钮**: + | 按钮 | 权限 | 说明 | + |------|------|------| + | 全部标记已读 | — | 将所有未读消息标为已读 | + | 点击消息 | — | 跳转到对应业务详情页 | + +### 页面5:数据补录申请页 + +- **页面路径**:`/pages/supplement/apply` +- **页面元素**: + - 补录模块选择(报修/巡检/保洁/考勤) + - 补录原因(下拉选择:蓝牙失灵/定位失败/系统异常/其他) + - 补录说明(多行文本,最多200字) + - 证明材料上传(照片,最多3张) + - 补录数据表单(根据选择的模块动态渲染) +- **查询条件**:无 +- **列表字段**:无 +- **界面布局**: + - 顶部:补录模块选择(下拉选择器) + - 中部:补录原因 + 说明 + 上传证明 + - 下部:补录数据表单(动态) + - 底部:提交按钮 +- **操作按钮**: + | 按钮 | 权限 | 说明 | + |------|------|------| + | 提交申请 | — | 提交补录申请,等待主管审核 | + +### 页面6:通讯录页 + +- **页面路径**:`/pages/contacts/index` +- **页面元素**: + - 搜索框 + - 按班组分组显示联系人 + - 联系人信息卡片 +- **查询条件**: + | 条件 | 类型 | 说明 | + |------|------|------| + | 搜索关键词 | 输入框 | 按姓名/手机号搜索 | +- **列表字段**: + | 字段 | 说明 | + |------|------| + | 头像 | 联系人头像 | + | 姓名 | 联系人姓名 | + | 角色 | 联系人角色 | + | 手机号 | 脱敏显示,点击可拨打 | + | 班组 | 所属班组 | +- **界面布局**: + - 顶部:搜索框 + - 中部:按班组分组的联系人列表 + - 班组标题(灰色背景) + - 联系人卡片(左头像 + 中姓名角色 + 右手机号图标) +- **操作按钮**: + | 按钮 | 权限 | 说明 | + |------|------|------| + | 拨打电话 | — | 点击手机号直接拨打 | + +### 页面7:版本更新提示弹窗 + +- **页面路径**:弹窗组件(非独立页面) +- **页面元素**: + - 新版本号 + - 更新内容说明 + - 更新/取消按钮(小版本) + - 强制更新按钮(大版本) +- **界面布局**: + - 居中弹窗 + - 顶部:版本号 + - 中部:更新说明 + - 底部:操作按钮 + +## 需求追溯 + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-C-01 | 快捷登录 | 02-小程序端 §1 | 登录成功→加载权限集→渲染工作台 | 权限管理(角色分配) | +| MP-C-02 | 个人信息 | 02-小程序端 §1 | 修改手机号→更新sys_user | 通讯录 | +| MP-C-03 | 消息通知 | 02-小程序端 §1 | 点击消息→跳转业务详情 | 各业务模块(推送触发) | +| MP-C-04 | 数据补录申请 | 02-小程序端 §1 | 提交→触发补录审核→主管审批 | 各模块补录审核 | +| MP-C-05 | 版本更新提示 | 02-小程序端 §1 | 小版本→提示更新;大版本→强制更新 | 超管系统配置(版本管理) | +| MP-C-06 | 通讯录 | 02-小程序端 §1 | 点击拨打→调起手机拨号 | 组织架构(班组/人员) | + +## 业务规则 + +1. **登录规则**(03-业务流转逻辑-小程序端 §1): + - 首次登录:微信授权获取openid → 绑定手机号 → 系统匹配物业公司+人员信息 + - 匹配成功:创建账号,进入工作台 + - 匹配失败:提示"未找到关联信息,请联系管理员",无法使用 + - 再次登录:读取本地token → 有效则直接进入 → 无效则openid静默登录 + +2. **权限加载规则**(01-模块划分.md §5.3): + - 登录后获取角色及权限集(四级粒度) + - 根据权限动态渲染:可见菜单项、页面内可见功能点、功能点可用动作、数据范围(行级隔离) + +3. **Token管理**(06-项目技术要求.md §4.1): + - 小程序端存本地Storage,2小时过期 + - Token失效自动使用openid静默登录,刷新token + +4. **版本更新规则**(03-业务流转逻辑-小程序端 §10): + - 启动时调用后台接口获取最新版本号 + 最低兼容版本 + - 版本一致:正常使用 + - 小版本更新(兼容):提示"发现新版本,是否更新?",用户可取消 + - 大版本更新(不兼容):强制更新,引导前往微信更新小程序 + - SDK依赖校验:启动时校验蓝牙SDK、微信SDK等关键依赖版本 + +5. **消息通知规则**(01-模块划分.md §7): + - 通知场景:新工单、催单、审批、完工、异常上报等 + - 通知方式:小程序推送 + - 点击消息跳转对应业务详情 + +6. **数据补录规则**(06-项目技术要求.md §4.5): + - 补录数据必须标记 `is_supplement=true` + - 补录申请需主管审核(Web+小程序均可) + - 补录日志单独记录 + +## 状态流转 + +### 登录状态流转 + +``` +未登录 ──[微信授权]──▶ 获取openid ──[绑定手机号]──▶ 匹配人员信息 + │ + ┌───匹配成功───┐ ┌───匹配失败───┐ + │ │ │ │ + 创建账号 提示联系管理员 + 进入工作台 无法使用 +``` + +### 补录申请状态流转 + +``` +草稿 ──[提交]──▶ 待审核 ──[主管通过]──▶ 已通过(数据补录生效) + └──[主管驳回]──▶ 已驳回(通知申请人) +``` diff --git a/docs/02-功能清单-小程序端/02-报修相关功能.md b/docs/02-功能清单-小程序端/02-报修相关功能.md new file mode 100644 index 0000000..be3d1ff --- /dev/null +++ b/docs/02-功能清单-小程序端/02-报修相关功能.md @@ -0,0 +1,339 @@ +# 报修相关功能 + +> 模块编码:repair +> 端侧:小程序 +> 关联文档:01-模块划分.md §3.1、02-功能清单-小程序端.md §2、03-业务流转逻辑-小程序端.md §2、05-接口规范.md §9.2、06-项目技术要求.md §4.4 + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 报修相关功能 | +| 子菜单 | 扫码注册、一键报修、我的工单、催单、维修接单、维修完工、延期申请、延期审批、协助维修申请、工单分配、工单验收、评价 | +| 功能编号 | MP-R-01 ~ MP-R-12 | +| 权限编码 | repair:list:* / repair:detail:approve 等 | + +## 页面清单 + +### 页面1:扫码注册页 + +- **页面路径**:`/pages/repair/scan-register` +- **页面元素**: + - 扫码区域(调用wx.scanCode) + - 项目信息展示(扫码后显示) + - 确认绑定按钮 +- **界面布局**: + - 顶部:扫码提示文字 + - 中部:扫码框(居中,带边框提示) + - 底部:扫码结果展示 + 确认绑定按钮 +- **操作按钮**: + | 按钮 | 权限 | 说明 | + |------|------|------| + | 扫描二维码 | — | 调用wx.scanCode扫描项目二维码 | + | 确认绑定 | — | 绑定身份到对应项目 | + +### 页面2:一键报修页 + +- **页面路径**:`/pages/repair/create` +- **页面元素**: + - 报修类型选择(下拉,数据来源:物业公司Web端配置的报修类型字典) + - 报修描述(多行文本,最多500字) + - 照片上传区域(最多9张,含水印时间定位) + - 报修位置(可选,手动选择或自动定位) + - 联系方式(默认当前用户手机号) +- **界面布局**: + - 顶部:报修类型选择器 + - 中部:报修描述输入框 + - 下部:照片上传网格(3列,+号占位) + - 底部:提交按钮 +- **操作按钮**: + | 按钮 | 权限 | 说明 | + |------|------|------| + | 拍照上传 | — | 调用相机,自动添加水印(时间+位置) | + | 从相册选择 | — | 选择相册照片,自动添加水印 | + | 提交报修 | — | 生成工单,等待分配 | + +### 页面3:我的工单列表 + +- **页面路径**:`/pages/repair/my-orders` +- **页面元素**: + - 状态Tab筛选(全部/待分配/处理中/待验收/已完成/已关闭) + - 工单列表 + - 下拉刷新 + 上拉加载 +- **查询条件**: + | 条件 | 类型 | 说明 | + |------|------|------| + | 状态筛选 | Tab | 全部/待分配/处理中/待验收/已完成/已关闭 | + | 关键词 | 搜索框 | 按工单号/描述搜索 | +- **列表字段**: + | 字段 | 说明 | + |------|------| + | 工单编号 | 如 WO20260416001 | + | 报修类型 | 图标+文字 | + | 报修描述 | 截断显示 | + | 报修时间 | 相对时间 | + | 工单状态 | 状态标签(不同颜色) | + | 维修人员 | 已分配时显示 | + | 催单标记 | 已催单显示红色标记 | +- **界面布局**: + - 顶部:状态Tab + 搜索框 + - 中部:工单卡片列表 + - 卡片顶部:工单编号 + 状态标签 + - 卡片中部:报修类型 + 描述 + - 卡片底部:时间 + 维修人员 + 催单标记 + - 底部:无更多数据提示 +- **操作按钮**: + | 按钮 | 权限 | 说明 | + |------|------|------| + | 查看详情 | — | 跳转工单详情页 | + | 催单 | repair:list:view | 处理中工单可催单 | + +### 页面4:待处理工单列表(维修人员) + +- **页面路径**:`/pages/repair/pending-orders` +- **页面元素**: + - 待接单工单列表 + - 下拉刷新 + 上拉加载 +- **查询条件**:无(自动加载分配给当前人员的待处理工单) +- **列表字段**: + | 字段 | 说明 | + |------|------| + | 工单编号 | 如 WO20260416001 | + | 报修类型 | 图标+文字 | + | 报修描述 | 截断显示 | + | 报修时间 | 相对时间 | + | 优先级 | 高/中/低,不同颜色标记 | + | 报修照片缩略图 | 第一张照片 | +- **界面布局**: + - 顶部:待处理工单数量统计 + - 中部:工单卡片列表 + - 卡片顶部:工单编号 + 优先级标签 + - 卡片中部:报修类型 + 描述 + - 卡片底部:报修时间 + 接单按钮 + - 底部:无更多数据提示 +- **操作按钮**: + | 按钮 | 权限 | 说明 | + |------|------|------| + | 接单 | repair:list:update | 接单后工单状态变为"处理中" | + +### 页面5:维修完工页 + +- **页面路径**:`/pages/repair/complete` +- **页面元素**: + - 工单基本信息(只读) + - 维修说明(多行文本,必填) + - 维修后照片上传(最多9张,含水印时间定位) + - 材料使用记录(可选) +- **界面布局**: + - 顶部:工单信息摘要 + - 中部:维修说明输入框 + - 下部:照片上传网格 + - 底部:提交完工按钮 +- **操作按钮**: + | 按钮 | 权限 | 说明 | + |------|------|------| + | 拍照上传 | — | 拍摄维修后照片 | + | 提交完工 | repair:list:update | 工单状态变为"待验收" | + +### 页面6:延期申请页 + +- **页面路径**:`/pages/repair/extension-apply` +- **页面元素**: + - 工单基本信息(只读) + - 延期原因(多行文本,必填) + - 预计完成时间(日期时间选择器,必填) +- **界面布局**: + - 顶部:工单信息摘要 + - 中部:延期原因输入 + 预计完成时间 + - 底部:提交申请按钮 +- **操作按钮**: + | 按钮 | 权限 | 说明 | + |------|------|------| + | 提交延期申请 | repair:list:update | 工单状态变为"延期中",等待主管审批 | + +### 页面7:延期审批页(主管) + +- **页面路径**:`/pages/repair/extension-approve` +- **页面元素**: + - 工单基本信息(只读) + - 延期申请详情(申请人、原因、预计完成时间) + - 审批意见输入(多行文本) + - 通过/驳回按钮 +- **界面布局**: + - 顶部:工单信息摘要 + - 中部:延期申请详情 + 审批意见 + - 底部:通过 + 驳回按钮(并排) +- **操作按钮**: + | 按钮 | 权限 | 说明 | + |------|------|------| + | 通过 | repair:detail:approve | 延期生效,工单继续处理 | + | 驳回 | repair:detail:approve | 通知维修人员,工单恢复原状态 | + +### 页面8:协助维修申请页 + +- **页面路径**:`/pages/repair/assist-apply` +- **页面元素**: + - 工单基本信息(只读) + - 协助班组选择(下拉选择其他班组) + - 协助原因(多行文本,必填) +- **界面布局**: + - 顶部:工单信息摘要 + - 中部:协助班组选择 + 协助原因 + - 底部:提交申请按钮 +- **操作按钮**: + | 按钮 | 权限 | 说明 | + |------|------|------| + | 提交协助申请 | repair:list:update | 生成协助子工单,等待协助完成 | + +### 页面9:工单分配页(主管) + +- **页面路径**:`/pages/repair/assign` +- **页面元素**: + - 工单基本信息(只读) + - 分配班组选择(下拉选择) + - 分配人员选择(联动,根据班组筛选) + - 分配备注(可选) +- **界面布局**: + - 顶部:工单信息摘要 + - 中部:班组 + 人员级联选择 + - 底部:确认分配按钮 +- **操作按钮**: + | 按钮 | 权限 | 说明 | + |------|------|------| + | 确认分配 | repair:list:assign | 分配成功后通知维修人员 | + +### 页面10:工单验收页 + +- **页面路径**:`/pages/repair/accept` +- **页面元素**: + - 工单基本信息(只读) + - 维修说明展示 + - 维修前后照片对比 + - 验收结果选择(通过/不通过) + - 验收意见(多行文本,不通过时必填) +- **界面布局**: + - 顶部:工单信息摘要 + - 中部:维修说明 + 照片对比 + - 下部:验收结果选择 + 验收意见 + - 底部:提交验收按钮 +- **操作按钮**: + | 按钮 | 权限 | 说明 | + |------|------|------| + | 提交验收 | repair:detail:approve | 通过→工单完成;不通过→退回维修 | + +### 页面11:工单评价页 + +- **页面路径**:`/pages/repair/evaluate` +- **页面元素**: + - 工单基本信息(只读) + - 评分组件(五分制星级评分) + - 评价内容(多行文本,最多200字) + - 图片上传(最多3张) +- **界面布局**: + - 顶部:工单信息摘要 + - 中部:评分星级 + 评价输入 + 图片上传 + - 底部:提交评价按钮 +- **操作按钮**: + | 按钮 | 权限 | 说明 | + |------|------|------| + | 提交评价 | — | 评价提交后不可修改 | + +### 页面12:工单详情页 + +- **页面路径**:`/pages/repair/detail` +- **页面元素**: + - 工单基本信息 + - 报修照片 + - 维修人员信息(已分配时) + - 维修记录时间轴 + - 维修后照片 + - 操作按钮区(根据状态和角色动态显示) +- **界面布局**: + - 顶部:工单编号 + 状态标签 + - 信息区:报修类型、描述、位置、联系方式、报修时间 + - 照片区:报修照片轮播 + - 维修区:维修人员 + 维修说明 + 维修照片 + - 时间轴:工单流转记录(提交→分配→接单→完工→验收) + - 底部:操作按钮区(动态) +- **操作按钮**(根据角色和状态动态显示): + | 按钮 | 适用角色 | 工单状态 | 说明 | + |------|----------|----------|------| + | 催单 | 报修人 | 处理中 | 发起催单 | + | 接单 | 维修人员 | 待分配/已分配 | 接单 | + | 完工 | 维修人员 | 处理中 | 提交维修完工 | + | 延期申请 | 维修人员 | 处理中 | 申请延期 | + | 协助申请 | 维修人员 | 处理中 | 请求协助 | + | 分配 | 主管 | 待分配 | 分配工单 | + | 延期审批 | 主管 | 延期中 | 审批延期 | + | 验收 | 主管/报修人 | 待验收 | 验收工单 | + | 评价 | 报修人 | 已完成 | 评价工单 | + +## 需求追溯 + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-R-01 | 扫码注册 | 02-小程序端 §2 | 注册成功→绑定项目身份 | 通用功能(登录) | +| MP-R-02 | 一键报修 | 02-小程序端 §2 | 提交→生成工单→触发分配通知 | 物业Web端工单列表 | +| MP-R-03 | 我的工单 | 02-小程序端 §2 | 查看工单状态→催单/验收/评价 | 工单详情 | +| MP-R-04 | 催单 | 02-小程序端 §2 | 催单→触发通知服务→通知维修人员/主管 | 消息通知 | +| MP-R-05 | 维修接单 | 02-小程序端 §2 | 接单→工单状态变更→通知报修人 | 工单详情 | +| MP-R-06 | 维修完工 | 02-小程序端 §2 | 完工→工单状态变为"待验收"→触发验收通知 | 工单验收 | +| MP-R-07 | 延期申请 | 02-小程序端 §2 | 申请→工单状态变为"延期中"→通知主管审批 | 延期审批 | +| MP-R-08 | 延期审批 | 02-小程序端 §2 | 通过→延期生效;驳回→通知申请人 | 延期申请 | +| MP-R-09 | 协助维修申请 | 02-小程序端 §2 | 申请→生成协助子工单→通知协助班组 | 工单分配 | +| MP-R-10 | 工单分配 | 02-小程序端 §2 | 分配→通知维修人员 | 维修接单 | +| MP-R-11 | 工单验收 | 02-小程序端 §2 | 验收通过→工单完成→触发评价 | 服务评价 | +| MP-R-12 | 评价 | 02-小程序端 §2 | 评价→数据写入评价模块→物业可查看回复 | 服务评价 | + +## 业务规则 + +1. **照片上传规则**(06-项目技术要求.md §4.4): + - 报修照片最多9张,必须含水印(时间+位置信息) + - 水印位置:图片右下角 + - 上传时自动附带 `bluetooth_connected` 标记(如蓝牙连接时) + +2. **工单状态流转**(03-业务流转逻辑-小程序端 §2): + - 报修人提交 → 待分配 → 处理中(接单) → 待验收(完工) → 已完成(验收通过) + - 处理中可延期 → 延期中 → 主管审批 → 继续处理/驳回 + - 处理中可申请协助 → 生成子工单 + +3. **催单规则**: + - 只有处理中的工单可以催单 + - 催单后触发通知服务,通知维修人员和主管 + - 同一工单每天最多催单3次 + +4. **双端审批对照**(02-功能清单-小程序端.md 附录): + - 工单延期审批:Web+小程序均可(物业主管) + - 工单分配:Web+小程序均可(物业主管) + - 工单验收:Web+小程序均可(物业主管/报修人) + +5. **数据权限**(01-模块划分.md §1.3): + - 主管:本班组工单数据 + - 员工:仅本人相关工单数据 + +## 状态流转 + +### 工单完整状态流转 + +``` +待分配 ──[主管分配/自动分配]──▶ 已分配 ──[维修人员接单]──▶ 处理中 + │ │ + │ ┌───正常完工───┐───延期申请───┐───协助申请───┐ + │ │ │ │ + │ ▼ ▼ ▼ + │ 待验收 延期中 协助处理中 + │ │ │ │ + │ │ 主管审批 协助完成 + │ │ ┌通过┐┌驳回┐ │ + │ │ ▼ ▼ │ + │ │ 继续处理 通知员工 │ + │ │ │ + │ ┌───验收通过───┐───验收不通过───┐ + │ │ │ │ + │ ▼ ▼ │ + │ 已完成 退回处理中 │ + │ │ │ + │ 可评价 │ + │ │ + └─────────────────────────────────────────────────────────────────────────┘ +``` diff --git a/docs/02-功能清单-小程序端/03-巡检相关功能.md b/docs/02-功能清单-小程序端/03-巡检相关功能.md new file mode 100644 index 0000000..6328ec3 --- /dev/null +++ b/docs/02-功能清单-小程序端/03-巡检相关功能.md @@ -0,0 +1,259 @@ +# 巡检相关功能 + +> 模块编码:inspection +> 端侧:小程序 +> 关联文档:01-模块划分.md §3.2、02-功能清单-小程序端.md §3、03-业务流转逻辑-小程序端.md §3、05-接口规范.md §9.2、06-项目技术要求.md §4.4&5.4 + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 巡检相关功能 | +| 子菜单 | 今日巡检任务、蓝牙强制打卡、巡检执行、异常上报、巡检历史、异常数据补录 | +| 功能编号 | MP-I-01 ~ MP-I-06 | +| 权限编码 | inspection:plan:* / inspection:task:* 等 | + +## 页面清单 + +### 页面1:今日巡检任务列表 + +- **页面路径**:`/pages/inspection/today-tasks` +- **页面元素**: + - 今日任务统计(待执行/已完成/异常) + - 任务列表 + - 下拉刷新 +- **查询条件**:无(自动加载当日任务) +- **列表字段**: + | 字段 | 说明 | + |------|------| + | 任务名称 | 巡检计划名称 | + | 巡检区域 | 区域名称 | + | 计划时间 | 开始~结束时间 | + | 任务状态 | 待执行/进行中/已完成/异常 | + | 蓝牙打卡状态 | 未打卡/已打卡 | + | 异常数量 | 异常项数量(红色标记) | +- **界面布局**: + - 顶部:统计卡片(待执行/已完成/异常 三列数字) + - 中部:任务卡片列表 + - 卡片顶部:任务名称 + 状态标签 + - 卡片中部:巡检区域 + 计划时间 + - 卡片底部:蓝牙打卡状态 + 异常数量 + - 底部:无更多数据提示 +- **操作按钮**: + | 按钮 | 权限 | 说明 | + |------|------|------| + | 开始巡检 | inspection:task:view | 跳转巡检执行页 | + | 查看详情 | inspection:task:view | 已完成的任务查看详情 | + +### 页面2:蓝牙打卡页 + +- **页面路径**:`/pages/inspection/bluetooth-checkin` +- **页面元素**: + - 蓝牙扫描动画 + - 当前扫描状态提示 + - 检测到的Beacon列表(如多个) + - 打卡结果提示 + - 补录入口 +- **界面布局**: + - 顶部:蓝牙扫描状态(扫描动画 + 文字提示) + - 中部:Beacon信息展示 + - Beacon名称 + - UUID + - 信号强度(RSSI) + - 连接状态 + - 底部:打卡结果 + 重试/补录按钮 +- **操作按钮**: + | 按钮 | 权限 | 说明 | + |------|------|------| + | 重新扫描 | — | 蓝牙扫描超时后可重试(最多3次) | + | 进入补录模式 | — | 蓝牙无法连接时,进入补录模式 | + +### 页面3:巡检执行页 + +- **页面路径**:`/pages/inspection/execute` +- **页面元素**: + - 巡检清单列表(逐项检查) + - 每项检查项:正常/异常选择 + - 异常项附加信息(拍照+严重等级+描述) + - 打卡状态指示 + - 进度指示(已检查/总数) +- **查询条件**:无 +- **列表字段**: + | 字段 | 说明 | + |------|------| + | 检查项序号 | 序号标识 | + | 检查项名称 | 巡检清单项 | + | 检查结果 | 正常(绿)/异常(红)/未检查(灰) | + | 严重等级 | 异常时显示:一般/较重/严重 | +- **界面布局**: + - 顶部:进度条(已检查/总数)+ 蓝牙连接状态指示 + - 中部:检查项列表 + - 每项:序号 + 名称 + 正常/异常切换 + - 异常项展开:严重等级选择 + 描述输入 + 拍照上传 + - 底部:提交巡检结果按钮 +- **操作按钮**: + | 按钮 | 权限 | 说明 | + |------|------|------| + | 标记正常 | — | 当前项标记为正常 | + | 标记异常 | — | 当前项标记为异常,展开附加信息 | + | 拍照上传 | — | 异常项拍照(蓝牙策略=REQUIRED时须在蓝牙连接下拍照) | + | 一键生成报修 | — | 异常项可直接生成报修工单(数据写入报修模块) | + | 提交巡检结果 | inspection:task:view | 提交巡检记录 | + +### 页面4:异常上报页 + +- **页面路径**:`/pages/inspection/report-abnormal` +- **页面元素**: + - 异常描述(多行文本,必填) + - 严重等级选择(一般/较重/严重) + - 照片上传(最多9张,含水印时间定位) + - 是否生成报修工单(开关) + - 报修类型选择(生成工单时) +- **界面布局**: + - 顶部:严重等级选择(三档按钮) + - 中部:异常描述输入 + 照片上传网格 + - 下部:生成报修工单开关 + 报修类型选择 + - 底部:提交上报按钮 +- **操作按钮**: + | 按钮 | 权限 | 说明 | + |------|------|------| + | 拍照上传 | — | 拍摄异常照片 | + | 提交上报 | — | 上报异常,如选择生成工单则同时创建报修工单 | + +### 页面5:巡检历史列表 + +- **页面路径**:`/pages/inspection/history` +- **页面元素**: + - 日期选择器(按月切换) + - 巡检记录列表 + - 下拉刷新 + 上拉加载 +- **查询条件**: + | 条件 | 类型 | 说明 | + |------|------|------| + | 月份 | 月份选择器 | 按月筛选巡检记录 | +- **列表字段**: + | 字段 | 说明 | + |------|------| + | 巡检日期 | 日期时间 | + | 巡检区域 | 区域名称 | + | 打卡方式 | 蓝牙/手动/补录 | + | 检查项总数 | 总计 | + | 异常数 | 异常项数量 | + | 状态 | 正常/异常 | +- **界面布局**: + - 顶部:月份选择器 + - 中部:巡检记录卡片列表 + - 卡片顶部:日期 + 状态标签 + - 卡片中部:区域 + 打卡方式 + - 卡片底部:检查项总数 + 异常数 +- **操作按钮**: + | 按钮 | 权限 | 说明 | + |------|------|------| + | 查看详情 | inspection:task:view | 查看巡检记录详情 | + +### 页面6:异常数据补录页 + +- **页面路径**:`/pages/inspection/supplement` +- **页面元素**: + - 补录原因选择(下拉:蓝牙失灵/定位失败/系统异常/其他) + - 补录说明(多行文本,必填) + - 证明材料上传(照片,最多3张) + - 巡检记录补录表单 + - 巡检时间(手动选择) + - 巡检区域 + - 检查项结果(逐项填写) +- **界面布局**: + - 顶部:补录原因选择 + 说明 + - 中部:证明材料上传 + - 下部:巡检记录补录表单 + - 底部:提交补录申请按钮 +- **操作按钮**: + | 按钮 | 权限 | 说明 | + |------|------|------| + | 提交补录申请 | — | 提交后等待主管审核 | + +## 需求追溯 + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-I-01 | 今日巡检任务 | 02-小程序端 §3 | 查看任务→开始巡检→蓝牙打卡 | 巡检计划(Web端) | +| MP-I-02 | 蓝牙强制打卡 | 02-小程序端 §3 | 打卡成功→记录check_type=BLUETOOTH→开始巡检 | 蓝牙策略配置 | +| MP-I-03 | 巡检执行 | 02-小程序端 §3 | 逐项检查→记录正常/异常→提交 | 巡检计划清单 | +| MP-I-04 | 异常上报 | 02-小程序端 §3 | 上报→可一键生成报修工单→通知主管 | 在线报修(报修工单) | +| MP-I-05 | 巡检历史 | 02-小程序端 §3 | 查看个人历史巡检记录 | 统计报表 | +| MP-I-06 | 异常数据补录 | 02-小程序端 §3 | 提交补录→主管审核→审核通过后数据生效 | 补录审核(Web+小程序) | + +## 业务规则 + +1. **蓝牙策略规则**(06-项目技术要求.md §4.4): + - 策略=REQUIRED(强制蓝牙): + - 必须连接蓝牙Beacon后才可打卡 + - 拍照也须在蓝牙连接状态下进行 + - 蓝牙扫描超时3秒,重试3次 + - 未检测到蓝牙 → 提示"未检测到蓝牙信号" → 可重试或进入补录模式 + - 打卡记录 `check_type=BLUETOOTH` + - 策略=OPTIONAL(非强制蓝牙): + - 用户选择打卡方式:蓝牙打卡或手动打卡 + - 手动打卡:`check_type=MANUAL` + +2. **蓝牙连接判定**(06-项目技术要求.md §5.4): + - **不判断距离,只要成功连接蓝牙设备即可打卡** + - 信号阈值:RSSI > -70dBm(可配置,仅用于判定是否能建立连接) + - 扫描超时:3秒 + - 重试次数:3次 + +3. **蓝牙策略查询**(03-业务流转逻辑-小程序端 §3): + - 数据来源:`GET /system/bluetooth-policy → inspection_check_in`(打卡策略) + - 数据来源:`GET /system/bluetooth-policy → inspection_photo`(拍照策略) + +4. **异常上报关联报修**(03-业务流转逻辑-小程序端 §3): + - 异常上报时可一键生成报修工单 + - 数据写入报修模块(INSPECTION_ABNORMAL事件 → repair模块消费) + +5. **补录数据规则**(06-项目技术要求.md §4.5): + - 补录数据必须标记 `is_supplement=true` + - 补录原因必填 + - 需主管审核(Web+小程序均可审核) + +6. **数据权限**(01-模块划分.md §1.3): + - 巡检人员:仅本人巡检数据 + - 主管:本班组巡检数据 + +## 状态流转 + +### 巡检任务状态流转 + +``` +待执行 ──[蓝牙打卡]──▶ 进行中 ──[逐项检查]──▶ 已完成 + │ │ + │ └──[发现异常]──▶ 异常(可一键报修) + │ + └──[蓝牙失败]──▶ 补录模式 ──[手动填写]──▶ 待审核 ──[主管通过]──▶ 已完成 + └──[主管驳回]──▶ 已驳回 +``` + +### 蓝牙打卡流程 + +``` +开始打卡 + │ +查询蓝牙策略(inspection_check_in) + │ +┌───策略=REQUIRED───┐ +│ 自动扫描蓝牙Beacon │ +│ │ │ +│ ┌──检测到Beacon──┐ ┌──未检测到──┐ +│ │ 连接蓝牙 │ │ 提示未检测 │ +│ │ 连接成功→打卡 │ │ 重试/补录 │ +│ │ check_type= │ └────────────┘ +│ │ BLUETOOTH │ +│ └────────────────┘ +└────────────────────┘ + │ +┌───策略=OPTIONAL───┐ +│ 选择打卡方式 │ +│ ┌蓝牙打卡─手动打卡┐│ +│ │BLUETOOTH MANUAL││ +│ └────────────────┘│ +└────────────────────┘ +``` diff --git a/docs/02-功能清单-小程序端/04-保洁相关功能.md b/docs/02-功能清单-小程序端/04-保洁相关功能.md new file mode 100644 index 0000000..8625eec --- /dev/null +++ b/docs/02-功能清单-小程序端/04-保洁相关功能.md @@ -0,0 +1,297 @@ +# 保洁相关功能 + +> 模块编码:cleaning +> 端侧:微信小程序 +> 关联文档:01-模块划分.md(v4.0)、02-功能清单-小程序端.md(§4)、03-业务流转逻辑-小程序端.md(§4)、05-接口规范.md(§9)、06-项目技术要求.md + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 保洁管理 | +| 子菜单 | 今日保洁任务 / 保洁执行 / 保洁历史 | +| 功能编号 | MP-CL-01 ~ MP-CL-07 | +| 权限编码 | cleaning:task:*、cleaning:spot-check:*、cleaning:supplement:* | + +## 页面清单 + +### 页面1:今日保洁任务 + +- **页面路径**:`/pages/cleaning/today` +- **适用角色**:保洁人员 +- **页面元素**: + - 日期显示(当天日期) + - 任务统计卡片(待执行/进行中/已完成) + - 任务列表 +- **查询条件**:无(自动按当天+本人过滤) +- **列表字段**: + +| 字段 | 类型 | 说明 | +|------|------|------| +| 任务名称 | 文本 | 保洁区域+任务类型 | +| 保洁区域 | 标签 | 关联区域名称 | +| 计划时间 | 时间 | 预计开始时间 | +| 状态 | 标签 | 待执行/进行中/已完成/超时 | +| 蓝牙状态 | 图标 | 是否需蓝牙打卡 | + +- **界面布局**: + - 顶部:日期 + 统计数字横向排列 + - 中部:任务卡片列表,每张卡片显示区域、时间、状态 + - 底部:无操作栏 +- **操作按钮**: + - 「开始执行」→ 进入保洁执行页(权限:cleaning:task:update) + - 「查看详情」→ 查看任务详情 + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-CL-01 | 今日保洁任务 | 02-小程序端 §4 | 蓝牙打卡确认 | 保洁执行 | + +--- + +### 页面2:蓝牙强制打卡确认 + +- **页面路径**:`/pages/cleaning/check-in`(从今日任务页面跳转) +- **适用角色**:保洁人员 +- **页面元素**: + - 蓝牙扫描状态指示器(扫描中/已连接/未检测到) + - 当前打卡点名称 + - 蓝牙信号强度显示 + - 重试按钮 + - 补录入口(蓝牙未连接时显示) +- **查询条件**:无 +- **列表字段**:无 +- **界面布局**: + - 顶部:打卡点名称 + 蓝牙状态大图标 + - 中部:蓝牙连接动画(扫描→连接→成功) + - 底部:操作按钮区 +- **操作按钮**: + - 「重新扫描」→ 重新搜索蓝牙Beacon + - 「进入补录模式」→ 跳转补录申请页(蓝牙策略=REQUIRED且扫描失败时显示) + - 「确认打卡」→ 记录蓝牙打卡成功(check_type=BLUETOOTH) + +**蓝牙策略判断逻辑**: +- 调用 `GET /system/bluetooth-policy → cleaning_check_in` +- 策略=REQUIRED:必须蓝牙连接后才能打卡 +- 策略=OPTIONAL:可选蓝牙或手动打卡 + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-CL-02 | 蓝牙强制打卡确认 | 02-小程序端 §4 | 保洁执行 | 保洁补录、系统蓝牙配置 | + +--- + +### 页面3:保洁执行 + +- **页面路径**:`/pages/cleaning/execute` +- **适用角色**:保洁人员 +- **页面元素**: + - 任务信息卡片(区域、类型、时间) + - 保洁清单(逐项检查列表) + - 每项操作按钮(完成/标记异常) + - 完成后照片上传区(≤9张,含水印时间定位) + - 蓝牙拍照提示(策略=REQUIRED时显示) +- **查询条件**:无 +- **列表字段**: + +| 字段 | 类型 | 说明 | +|------|------|------| +| 检查项名称 | 文本 | 保洁清单项目 | +| 状态 | 标签 | 待完成/已完成/异常 | +| 备注 | 文本 | 异常时填写说明 | + +- **界面布局**: + - 顶部:任务信息摘要卡片 + - 中部:保洁清单列表(逐项勾选) + - 底部:照片上传区 + 提交按钮 +- **操作按钮**: + - 「完成该项」→ 标记该项完成 + - 「标记异常」→ 跳转异常反馈页 + - 「拍照」→ 调用相机拍照(蓝牙策略=REQUIRED时须在蓝牙连接状态下进行) + - 「提交完成」→ 提交整个保洁任务 + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-CL-03 | 保洁执行 | 02-小程序端 §4 | 主管抽查 | 保洁异常反馈 | + +--- + +### 页面4:异常反馈 + +- **页面路径**:`/pages/cleaning/abnormal` +- **适用角色**:保洁人员 +- **页面元素**: + - 异常描述输入框(多行文本) + - 拍照上传区(≤9张,含水印时间定位) + - 严重程度选择(一般/严重/紧急) + - 提交按钮 +- **查询条件**:无 +- **列表字段**:无 +- **界面布局**: + - 顶部:异常类型提示 + - 中部:照片上传 + 描述填写 + - 底部:提交按钮 +- **操作按钮**: + - 「拍照」→ 调用相机 + - 「提交反馈」→ 提交异常反馈 + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-CL-04 | 异常反馈 | 02-小程序端 §4 | 通知主管 | 保洁管理(Web端) | + +--- + +### 页面5:保洁抽查 + +- **页面路径**:`/pages/cleaning/spot-check` +- **适用角色**:主管 +- **页面元素**: + - 待抽查任务列表 + - 任务详情查看 + - 抽查结果标记(合格/不合格) + - 不合格原因输入框 + - 不合格照片上传 +- **查询条件**: + - 日期筛选 + - 区域筛选 + - 状态筛选(待抽查/合格/不合格) +- **列表字段**: + +| 字段 | 类型 | 说明 | +|------|------|------| +| 区域 | 文本 | 保洁区域名称 | +| 执行人 | 文本 | 保洁人员姓名 | +| 完成时间 | 时间 | 实际完成时间 | +| 抽查状态 | 标签 | 待抽查/合格/不合格 | + +- **界面布局**: + - 顶部:筛选条件横向滑动 + - 中部:任务卡片列表 + - 弹窗:抽查结果标记弹窗 +- **操作按钮**: + - 「合格」→ 确认完成(权限:cleaning:spot-check:approve) + - 「不合格」→ 填写原因后重新生成任务 + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-CL-05 | 保洁抽查 | 02-小程序端 §4 | 不合格时重新生成任务 | 保洁管理(Web端) | + +--- + +### 页面6:保洁历史 + +- **页面路径**:`/pages/cleaning/history` +- **适用角色**:保洁人员 +- **页面元素**: + - 月份选择器 + - 历史任务列表 + - 任务详情查看 +- **查询条件**: + - 月份筛选 + - 状态筛选(全部/正常/异常/补录) +- **列表字段**: + +| 字段 | 类型 | 说明 | +|------|------|------| +| 日期 | 日期 | 执行日期 | +| 区域 | 文本 | 保洁区域 | +| 状态 | 标签 | 正常/异常/补录 | +| 打卡方式 | 标签 | 蓝牙/手动/补录 | + +- **界面布局**: + - 顶部:月份选择器 + 统计数字 + - 中部:按日期分组的任务列表 + - 底部:无操作栏 +- **操作按钮**: + - 「查看详情」→ 查看历史任务详情 + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-CL-06 | 保洁历史 | 02-小程序端 §4 | 无 | 保洁执行 | + +--- + +### 页面7:异常数据补录 + +- **页面路径**:`/pages/cleaning/supplement` +- **适用角色**:保洁人员(蓝牙失灵/定位失败时) +- **页面元素**: + - 补录原因选择(蓝牙故障/手机异常/系统异常/其他) + - 补录说明输入框 + - 手动填写保洁记录 + - 照片上传区(补录证据) + - 提交按钮 +- **查询条件**:无 +- **列表字段**:无 +- **界面布局**: + - 顶部:补录模式提示(红色警示条) + - 中部:原因选择 + 说明填写 + 保洁记录 + - 底部:提交按钮 +- **操作按钮**: + - 「提交补录」→ 提交补录申请(需主管审核) + +**补录数据标记**: +- 所有补录数据标记 `is_supplement=true` +- `supplement_reason`:补录原因 +- `check_type=MANUAL` + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-CL-07 | 异常数据补录 | 02-小程序端 §4 | 主管审核补录 | 操作日志、考勤补录审核 | + +--- + +## 业务规则 + +1. **蓝牙策略**:保洁打卡和拍照均受蓝牙策略控制(`GET /system/bluetooth-policy → cleaning_check_in` / `cleaning_photo`) +2. **蓝牙强制打卡**:策略=REQUIRED时,必须连接蓝牙Beacon后才可确认完成,拍照也须在蓝牙连接状态下进行 +3. **非强制蓝牙**:策略=OPTIONAL时,可选蓝牙打卡(check_type=BLUETOOTH)或手动打卡(check_type=MANUAL) +4. **补录审核**:所有蓝牙失灵的补录数据需主管在Web端或小程序端审核 +5. **补录标记**:补录数据必须标记 `is_supplement=true`,并在操作日志中记录 +6. **照片水印**:所有照片自动添加时间+位置水印,蓝牙场景标记 `bluetooth_connected` +7. **抽查不合格**:主管标记不合格后,系统自动重新生成保洁任务 +8. **照片数量**:单次上传最多9张照片 + +## 状态流转 + +### 保洁任务状态 + +``` +待执行 → 进行中 → 待抽查 → 已完成 + ↓ + 异常反馈 → 待处理 + ↓ + 主管抽查 → 合格 → 已完成 + → 不合格 → 重新生成任务 +``` + +### 补录流程 + +``` +蓝牙失灵/定位失败 + │ + 进入补录模式 + │ + 选择补录原因 + 手动填写记录 + │ + 提交补录申请(is_supplement=true) + │ + 主管审核(Web/小程序均可) + │ + ┌─审核通过─┐ ┌─审核驳回─┐ + 补录生效 通知员工 + 记录审核日志 记录审核日志 +``` diff --git a/docs/02-功能清单-小程序端/05-考勤相关功能.md b/docs/02-功能清单-小程序端/05-考勤相关功能.md new file mode 100644 index 0000000..548c7cb --- /dev/null +++ b/docs/02-功能清单-小程序端/05-考勤相关功能.md @@ -0,0 +1,268 @@ +# 考勤相关功能 + +> 模块编码:attendance +> 端侧:微信小程序 +> 关联文档:01-模块划分.md(v4.0)、02-功能清单-小程序端.md(§5)、03-业务流转逻辑-小程序端.md(§5)、05-接口规范.md(§9)、06-项目技术要求.md + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 考勤打卡 | +| 子菜单 | 上班打卡 / 下班打卡 / 打卡记录 / 异常申诉 / 考勤日历 / 考勤审核 | +| 功能编号 | MP-AT-01 ~ MP-AT-06 | +| 权限编码 | attendance:record:*、attendance:appeal:*、attendance:supplement:* | + +## 页面清单 + +### 页面1:上班打卡 + +- **页面路径**:`/pages/attendance/clock-in` +- **适用角色**:全部 +- **页面元素**: + - 当前时间显示(大字时钟) + - 打卡状态指示(未打卡/已打卡) + - 蓝牙扫描状态指示器 + - 当前打卡点名称 + - 蓝牙信号强度显示 + - 打卡按钮 + - 补录/申诉入口 +- **查询条件**:无 +- **列表字段**:无 +- **界面布局**: + - 顶部:当前时间大字显示 + - 中部:打卡点信息 + 蓝牙状态 + - 底部:打卡按钮(圆形大按钮) +- **操作按钮**: + - 「上班打卡」→ 记录上班打卡(权限:attendance:record:create) + - 「异常申诉」→ 跳转异常申诉页(蓝牙未检测到时显示) + +**蓝牙策略判断逻辑**: +- 调用 `GET /system/bluetooth-policy → attendance_check` +- 策略=REQUIRED:必须连接指定打卡点蓝牙Beacon后才可打卡 + - 验证Beacon属于本人班组打卡点 + - 打卡成功记录 `check_method=BLUETOOTH` +- 策略=OPTIONAL:可选蓝牙打卡或手动打卡 + - 手动打卡:`check_method=MANUAL` + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-AT-01 | 上班打卡 | 02-小程序端 §5 | 记录操作日志 | 考勤记录、打卡点管理 | + +--- + +### 页面2:下班打卡 + +- **页面路径**:`/pages/attendance/clock-out` +- **适用角色**:全部 +- **页面元素**: + - 当前时间显示(大字时钟) + - 打卡状态指示(未打卡/已打卡) + - 上班打卡时间显示 + - 蓝牙扫描状态指示器 + - 当前打卡点名称 + - 打卡按钮 + - 补录/申诉入口 +- **查询条件**:无 +- **列表字段**:无 +- **界面布局**: + - 顶部:当前时间 + 上班打卡时间 + - 中部:打卡点信息 + 蓝牙状态 + - 底部:打卡按钮(圆形大按钮) +- **操作按钮**: + - 「下班打卡」→ 记录下班打卡(权限:attendance:record:create) + - 「异常申诉」→ 跳转异常申诉页 + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-AT-02 | 下班打卡 | 02-小程序端 §5 | 记录操作日志 | 考勤记录 | + +--- + +### 页面3:打卡记录 + +- **页面路径**:`/pages/attendance/records` +- **适用角色**:全部 +- **页面元素**: + - 月份选择器 + - 统计信息卡片(出勤天数/迟到/早退/缺卡) + - 打卡记录列表 + - 记录详情弹窗 +- **查询条件**: + - 月份筛选 + - 状态筛选(全部/正常/迟到/早退/缺卡/补录) +- **列表字段**: + +| 字段 | 类型 | 说明 | +|------|------|------| +| 日期 | 日期 | 打卡日期 | +| 上班时间 | 时间 | 上班打卡时间 | +| 下班时间 | 时间 | 下班打卡时间 | +| 打卡方式 | 标签 | 蓝牙/手动/补录 | +| 状态 | 标签 | 正常/迟到/早退/缺卡 | + +- **界面布局**: + - 顶部:月份选择器 + 统计数字横向排列 + - 中部:按日期分组的打卡记录列表 + - 底部:无操作栏 +- **操作按钮**: + - 「查看详情」→ 查看打卡详情(含打卡点、蓝牙信息等) + - 「异常申诉」→ 对异常记录发起申诉 + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-AT-03 | 打卡记录 | 02-小程序端 §5 | 无 | 考勤日历 | + +--- + +### 页面4:异常申诉 + +- **页面路径**:`/pages/attendance/appeal` +- **适用角色**:全部(蓝牙失灵/系统宕机时) +- **页面元素**: + - 异常日期选择 + - 异常类型选择(上班/下班/全天) + - 异常原因选择(蓝牙故障/手机异常/系统异常/忘记打卡/其他) + - 补充说明输入框(多行文本) + - 照片上传区(补充证据,≤9张) + - 提交按钮 +- **查询条件**:无 +- **列表字段**:无 +- **界面布局**: + - 顶部:申诉模式提示 + - 中部:原因选择 + 说明填写 + 照片上传 + - 底部:提交按钮 +- **操作按钮**: + - 「提交申诉」→ 提交打卡异常申诉(权限:attendance:appeal:create) + - 申诉提交后等待主管审核(Web/小程序均可审核) + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-AT-04 | 异常申诉 | 02-小程序端 §5 | 主管审核 | 考勤审核 | + +--- + +### 页面5:考勤日历 + +- **页面路径**:`/pages/attendance/calendar` +- **适用角色**:全部 +- **页面元素**: + - 月历视图(日历格子) + - 每日状态标记(颜色点) + - 点击日期显示详情弹窗 + - 图例说明 +- **查询条件**: + - 月份切换(左右滑动) +- **列表字段**:无(日历模式) +- **界面布局**: + - 顶部:月份切换 + 统计信息 + - 中部:月历网格,每日格子中用颜色点标记状态 + - 绿色:正常 + - 黄色:迟到/早退 + - 红色:缺卡 + - 蓝色:补录 + - 灰色:休息日 + - 底部:图例说明 +- **操作按钮**: + - 「点击日期」→ 显示当日打卡详情弹窗 + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-AT-05 | 考勤日历 | 02-小程序端 §5 | 无 | 打卡记录 | + +--- + +### 页面6:考勤审核 + +- **页面路径**:`/pages/attendance/review` +- **适用角色**:主管 +- **页面元素**: + - 待审核申诉列表 + - 申诉详情查看 + - 审核操作区(通过/驳回) + - 驳回原因输入框 +- **查询条件**: + - 状态筛选(待审核/已通过/已驳回) + - 日期筛选 + - 人员筛选 +- **列表字段**: + +| 字段 | 类型 | 说明 | +|------|------|------| +| 申诉人 | 文本 | 员工姓名 | +| 申诉日期 | 日期 | 异常打卡日期 | +| 异常类型 | 标签 | 上班/下班/全天 | +| 申诉原因 | 文本 | 原因摘要 | +| 提交时间 | 时间 | 申诉提交时间 | +| 审核状态 | 标签 | 待审核/已通过/已驳回 | + +- **界面布局**: + - 顶部:筛选条件 + - 中部:申诉卡片列表 + - 底部:审核操作按钮(通过/驳回) +- **操作按钮**: + - 「通过」→ 系统自动补录打卡记录,标注"补录"(权限:attendance:appeal:approve) + - 「驳回」→ 填写驳回原因,通知员工 + +**审核流程**: +``` +员工提交异常申诉(小程序端) + │ + 主管审核(Web+小程序均可) + │ + ┌─审核通过─┐ ┌─审核驳回─┐ + 系统自动补录 通知员工 + 打卡记录 申诉未通过 + 标注"补录" 记录审核日志 + 记录审核日志 +``` + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-AT-06 | 考勤审核 | 02-小程序端 §5 | 补录打卡记录 | 操作日志、考勤管理(Web端) | + +--- + +## 业务规则 + +1. **蓝牙策略**:考勤打卡受蓝牙策略控制(`GET /system/bluetooth-policy → attendance_check`) +2. **蓝牙强制打卡**:策略=REQUIRED时,必须在指定打卡点连接蓝牙Beacon后才可打卡 + - 验证Beacon属于本人班组打卡点 + - 打卡成功记录 `check_method=BLUETOOTH` + Beacon标识 +3. **非强制蓝牙**:策略=OPTIONAL时,可选蓝牙打卡或手动打卡(`check_method=MANUAL`) +4. **打卡点验证**:蓝牙打卡时验证Beacon属于本人班组绑定的打卡点 +5. **打卡时间**:自动记录精确到秒 +6. **异常申诉审核**:主管在Web端或小程序端均可审核 +7. **补录标记**:审核通过后系统自动补录打卡记录,标记 `is_supplement=true` +8. **操作日志**:所有打卡操作记录审计日志 +9. **双端审批**:打卡异常申诉支持Web+小程序双端审核 + +## 状态流转 + +### 打卡状态 + +``` +未打卡 → 已打卡(正常/迟到/早退) + ↓ + 缺卡 → 异常申诉 → 审核通过 → 补录打卡(标记补录) + → 审核驳回 → 保持缺卡 +``` + +### 申诉审核状态 + +``` +待审核 → 审核通过 → 系统补录打卡记录 + → 审核驳回 → 通知员工 +``` diff --git a/docs/02-功能清单-小程序端/06-组织架构相关功能.md b/docs/02-功能清单-小程序端/06-组织架构相关功能.md new file mode 100644 index 0000000..283a06c --- /dev/null +++ b/docs/02-功能清单-小程序端/06-组织架构相关功能.md @@ -0,0 +1,102 @@ +# 组织架构相关功能 + +> 模块编码:org +> 端侧:微信小程序 +> 关联文档:01-模块划分.md(v4.0)、02-功能清单-小程序端.md(§6)、03-业务流转逻辑-小程序端.md(§6)、05-接口规范.md(§9)、06-项目技术要求.md + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 组织架构 | +| 子菜单 | 我的班组 / 我的排班 | +| 功能编号 | MP-OR-01 ~ MP-OR-02 | +| 权限编码 | org:team:view、org:schedule:view | + +## 页面清单 + +### 页面1:我的班组 + +- **页面路径**:`/pages/org/my-team` +- **适用角色**:全部 +- **页面元素**: + - 班组信息卡片(班组名称、所属部门、班组长) + - 班组成员列表 + - 成员详情弹窗 +- **查询条件**:无(自动加载本人所在班组) +- **列表字段**: + +| 字段 | 类型 | 说明 | +|------|------|------| +| 姓名 | 文本 | 成员姓名 | +| 职位 | 标签 | 岗位/职位 | +| 联系电话 | 文本 | 手机号(脱敏显示) | +| 技能标签 | 标签组 | 专业技能标签 | + +- **界面布局**: + - 顶部:班组信息卡片(班组名、部门、班组长) + - 中部:成员列表(头像 + 姓名 + 职位 + 电话) + - 底部:无操作栏 +- **操作按钮**: + - 「拨打电话」→ 调用手机拨号功能 + - 「查看详情」→ 显示成员详情弹窗 + +**数据来源**:物业管理员在Web端配置的班组信息 + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-OR-01 | 我的班组 | 02-小程序端 §6 | 无 | 组织架构(Web端)、通讯录 | + +--- + +### 页面2:我的排班 + +- **页面路径**:`/pages/org/my-schedule` +- **适用角色**:全部 +- **页面元素**: + - 月历视图(排班日历) + - 每日排班标记(颜色条) + - 点击日期显示排班详情 + - 图例说明 +- **查询条件**: + - 月份切换(左右滑动) +- **列表字段**:无(日历模式) +- **界面布局**: + - 顶部:月份切换 + - 中部:月历网格,每日格子中用颜色条标记排班类型 + - 蓝色条:白班 + - 绿色条:夜班 + - 橙色条:全天班 + - 灰色条:休息 + - 底部:图例说明 +- **操作按钮**: + - 「点击日期」→ 显示当日排班详情弹窗 + - 排班类型 + - 上班时间 + - 下班时间 + - 打卡点 + +**数据来源**:物业管理员在Web端配置的排班数据 + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-OR-02 | 我的排班 | 02-小程序端 §6 | 无 | 考勤打卡、组织架构排班(Web端) | + +--- + +## 业务规则 + +1. **数据只读**:小程序端组织架构信息为只读,修改需在Web端操作 +2. **数据来源**:班组信息和排班数据均由物业管理员在Web端配置 +3. **权限限制**:员工只能查看本人所在班组信息和排班 +4. **电话脱敏**:通讯录中电话号码中间4位脱敏显示(如138****5678),点击拨号时显示完整号码 +5. **排班实时同步**:Web端修改排班后,小程序端实时更新 +6. **考勤关联**:排班数据与考勤打卡关联,排班中的打卡点与蓝牙打卡验证一致 + +## 状态流转 + +本模块为只读查看功能,无状态流转。 diff --git a/docs/02-功能清单-小程序端/07-服务评价相关功能.md b/docs/02-功能清单-小程序端/07-服务评价相关功能.md new file mode 100644 index 0000000..705c856 --- /dev/null +++ b/docs/02-功能清单-小程序端/07-服务评价相关功能.md @@ -0,0 +1,159 @@ +# 服务评价相关功能 + +> 模块编码:evaluation +> 端侧:微信小程序 +> 关联文档:01-模块划分.md(v4.0)、02-功能清单-小程序端.md(§7)、03-业务流转逻辑-小程序端.md(§7)、05-接口规范.md(§9)、06-项目技术要求.md + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 服务评价 | +| 子菜单 | 待评价列表 / 评分留言 / 历史评价 | +| 功能编号 | MP-EV-01 ~ MP-EV-03 | +| 权限编码 | evaluation:list:* | + +## 页面清单 + +### 页面1:待评价列表 + +- **页面路径**:`/pages/evaluation/pending` +- **适用角色**:报修人 +- **页面元素**: + - 待评价工单列表 + - 工单摘要信息 + - 评价入口 + - 提醒红点/数字标记 +- **查询条件**:无(自动过滤待评价工单) +- **列表字段**: + +| 字段 | 类型 | 说明 | +|------|------|------| +| 工单编号 | 文本 | 报修工单号 | +| 报修类型 | 标签 | 报修分类 | +| 报修描述 | 文本 | 问题描述摘要 | +| 完工时间 | 时间 | 维修完成时间 | +| 维修人员 | 文本 | 处理人姓名 | +| 评价状态 | 标签 | 待评价/已评价 | + +- **界面布局**: + - 顶部:待评价数量统计 + - 中部:工单卡片列表,每张卡片显示工单信息 + - 底部:无操作栏 +- **操作按钮**: + - 「去评价」→ 跳转评分留言页 + +**触发条件**:工单完工验收后,系统自动推送评价通知给报修人 + +**数据来源**:物业公司在Web/小程序端验收通过后,触发评价事件(ORDER_COMPLETED) + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-EV-01 | 待评价列表 | 02-小程序端 §7 | 评分留言 | 在线报修(验收完成后触发) | + +--- + +### 页面2:评分留言 + +- **页面路径**:`/pages/evaluation/rate` +- **适用角色**:报修人 +- **页面元素**: + - 工单信息摘要卡片 + - 五分制评分组件(⭐⭐⭐⭐⭐) + - 评分维度标签(响应速度/服务态度/维修质量/整体满意度) + - 文字留言输入框(多行文本,最多200字) + - 图片上传区(≤9张) + - 匿名评价开关 + - 提交按钮 +- **查询条件**:无 +- **列表字段**:无 +- **界面布局**: + - 顶部:工单信息摘要 + - 中部:评分星星 + 维度标签 + 留言框 + 图片上传 + - 底部:匿名开关 + 提交按钮 +- **操作按钮**: + - 「选择评分」→ 点击星星选择1~5分 + - 「拍照」→ 调用相机拍照评价凭证 + - 「提交评价」→ 提交评价(权限:evaluation:list:create) + +**评价规则**: +- 五分制评分:1分=非常不满意,2分=不满意,3分=一般,4分=满意,5分=非常满意 +- 评分≤3分时触发低分评价事件(LOW_SCORE_EVALUATION),通知主管 +- 提交后不可修改评价 +- 评价数据写入评价模块,物业公司Web端可查看和回复 + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-EV-02 | 评分留言 | 02-小程序端 §7 | 物业公司查看回复 | 服务评价(Web端) | + +--- + +### 页面3:历史评价 + +- **页面路径**:`/pages/evaluation/history` +- **适用角色**:报修人 +- **页面元素**: + - 历史评价列表 + - 评价详情查看 + - 物业回复内容展示 +- **查询条件**: + - 评分筛选(全部/好评/中评/差评) + - 时间筛选 +- **列表字段**: + +| 字段 | 类型 | 说明 | +|------|------|------| +| 工单编号 | 文本 | 报修工单号 | +| 评分 | 数字 | 1~5分 | +| 评价内容 | 文本 | 留言摘要 | +| 评价时间 | 时间 | 提交评价时间 | +| 回复状态 | 标签 | 已回复/未回复 | + +- **界面布局**: + - 顶部:筛选条件 + 统计信息 + - 中部:评价卡片列表,每张卡片显示评分、留言、回复 + - 底部:无操作栏 +- **操作按钮**: + - 「查看详情」→ 查看评价详情及物业回复 + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-EV-03 | 历史评价 | 02-小程序端 §7 | 无 | 服务评价(Web端) | + +--- + +## 业务规则 + +1. **评价触发**:工单完工验收通过后自动触发评价通知(事件:ORDER_COMPLETED) +2. **评价时效**:验收通过后7天内可评价,超期不可评价 +3. **低分预警**:评分≤3分触发 LOW_SCORE_EVALUATION 事件,通知主管 +4. **评价匿名**:支持匿名评价,物业公司无法看到评价人信息 +5. **评价不可修改**:提交后不可修改评价内容 +6. **物业回复**:物业公司可在Web端查看评价并回复,回复内容在小程序端展示 +7. **图片水印**:评价图片自动添加时间水印 +8. **图片数量**:单次评价最多上传9张图片 +9. **评分维度**:支持多维度评分(响应速度/服务态度/维修质量/整体满意度) + +## 状态流转 + +### 评价状态 + +``` +待评价 → 已评价(显示物业回复) + ↓ + 超期未评价 → 关闭评价入口 +``` + +### 事件触发 + +``` +工单验收通过 → ORDER_COMPLETED 事件 → 触发评价通知 +评价提交(≤3分)→ LOW_SCORE_EVALUATION 事件 → 通知主管 +评价提交 → 评价数据写入评价模块 → 物业公司Web端可查看回复 +``` diff --git a/docs/02-功能清单-小程序端/08-统计概览功能.md b/docs/02-功能清单-小程序端/08-统计概览功能.md new file mode 100644 index 0000000..68d5340 --- /dev/null +++ b/docs/02-功能清单-小程序端/08-统计概览功能.md @@ -0,0 +1,108 @@ +# 统计概览功能 + +> 模块编码:statistics +> 端侧:微信小程序 +> 关联文档:01-模块划分.md(v4.0)、02-功能清单-小程序端.md(§8)、03-业务流转逻辑-小程序端.md(§8)、05-接口规范.md(§9)、06-项目技术要求.md + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 统计概览 | +| 子菜单 | 简版统计概览 / 个人绩效统计 | +| 功能编号 | MP-ST-01 ~ MP-ST-02 | +| 权限编码 | statistics:{module}:* | + +## 页面清单 + +### 页面1:简版统计概览 + +- **页面路径**:`/pages/statistics/overview` +- **适用角色**:管理员/主管 +- **页面元素**: + - 今日/本周切换标签 + - 关键指标卡片组 + - 简版趋势图 +- **查询条件**: + - 时间范围切换(今日/本周) +- **列表字段**:无(概览卡片模式) +- **界面布局**: + - 顶部:今日/本周切换标签 + - 中部:四组指标卡片 + - **报修**:今日工单数 / 待处理 / 已完成 + - **巡检**:今日任务数 / 已完成 / 异常 + - **保洁**:今日任务数 / 已完成 / 超时 + - **考勤**:今日出勤率 + - 底部:简版趋势折线图(近7天工单量) +- **操作按钮**: + - 无(纯展示页面,详细数据在Web端查看) + +**数据来源**:物业公司各业务模块实时数据 + +**按角色权限显示**: +- 全局管理员:显示全部指标 +- 主管:仅显示所管辖模块的指标 + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-ST-01 | 简版统计概览 | 02-小程序端 §8 | 无 | 统计报表(Web端) | + +--- + +### 页面2:个人绩效统计 + +- **页面路径**:`/pages/statistics/personal` +- **适用角色**:员工 +- **页面元素**: + - 个人关键指标卡片 + - 绩效评分展示 + - 近期趋势图 +- **查询条件**: + - 时间范围选择(本周/本月) +- **列表字段**:无(概览卡片模式) +- **界面布局**: + - 顶部:时间范围选择 + - 中部:绩效指标卡片 + - **工单量**:已完成工单数 / 平均处理时长 + - **评分**:平均评分 / 评价数 + - **考勤**:出勤天数 / 迟到次数 + - 底部:近期绩效趋势图 +- **操作按钮**: + - 无(纯展示页面) + +**数据来源**: +- 报修模块工单数据 +- 评价模块评分数据 +- 考勤模块打卡数据 + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-ST-02 | 个人绩效统计 | 02-小程序端 §8 | 无 | 统计报表(Web端) | + +--- + +## 业务规则 + +1. **数据实时性**:统计数据基于各业务模块实时数据计算 +2. **权限隔离**:管理员/主管看到团队指标,员工仅看到个人绩效 +3. **简版展示**:小程序端为简版概览,详细报表在Web端查看 +4. **时间范围**:支持今日/本周切换,个人绩效支持本周/本月 +5. **趋势图**:展示近7天数据趋势,辅助快速判断 +6. **出勤率计算**:出勤率 = 实际出勤人数 / 应出勤人数 × 100% +7. **数据来源汇总**: + +| 指标 | 数据来源 | +|------|----------| +| 工单数/待处理/已完成 | 报修模块工单数据 | +| 巡检任务数/已完成/异常 | 巡检模块任务数据 | +| 保洁任务数/已完成/超时 | 保洁模块任务数据 | +| 出勤率 | 考勤模块打卡数据 | +| 个人评分 | 评价模块评分数据 | + +## 状态流转 + +本模块为纯展示功能,无状态流转。 diff --git a/docs/02-功能清单-小程序端/09-管理员小程序功能.md b/docs/02-功能清单-小程序端/09-管理员小程序功能.md new file mode 100644 index 0000000..c24efbd --- /dev/null +++ b/docs/02-功能清单-小程序端/09-管理员小程序功能.md @@ -0,0 +1,294 @@ +# 管理员小程序功能 + +> 模块编码:property-manager +> 端侧:微信小程序 +> 关联文档:01-模块划分.md(v4.0)、02-功能清单-小程序端.md(§9)、03-业务流转逻辑-小程序端.md(§9)、05-接口规范.md(§9)、06-项目技术要求.md + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 管理工作台 | +| 子菜单 | 报修管理 / 巡检管理 / 保洁管理 / 考勤管理 / 评价管理 / 组织架构查看 | +| 功能编号 | MP-PM-01 ~ MP-PM-06 | +| 权限编码 | repair:list:*、inspection:*:*、cleaning:*:*、attendance:*:*、evaluation:list:*、org:team:view | + +> **说明**:管理员小程序功能是物业公司管理员/主管在小程序端的简化版管理功能,与Web端功能对应但功能简化。所有数据与Web端同一数据源,操作实时同步。 + +## 页面清单 + +### 页面1:报修管理 + +- **页面路径**:`/pages/manager/repair` +- **适用角色**:物业管理员/主管 +- **页面元素**: + - 工单统计卡片(待分配/处理中/待验收/已完成) + - 工单列表 + - 工单分配操作 + - 工单流转操作 +- **查询条件**: + - 状态筛选(全部/待分配/处理中/待验收/已完成) + - 日期筛选 + - 类型筛选 + - 关键词搜索 +- **列表字段**: + +| 字段 | 类型 | 说明 | +|------|------|------| +| 工单编号 | 文本 | 报修工单号 | +| 报修类型 | 标签 | 报修分类 | +| 报修描述 | 文本 | 问题描述摘要 | +| 报修人 | 文本 | 提交人姓名 | +| 状态 | 标签 | 待分配/处理中/待验收/已完成 | +| 创建时间 | 时间 | 工单创建时间 | + +- **界面布局**: + - 顶部:统计数字横向排列 + - 中部:筛选条件 + 工单卡片列表 + - 底部:操作按钮 +- **操作按钮**: + - 「分配」→ 分配工单到班组/人员(权限:repair:list:assign) + - 「查看详情」→ 查看工单详情 + - 「审批延期」→ 审批维修人员延期申请(权限:repair:detail:approve) + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-PM-01 | 报修管理 | 02-小程序端 §9 | 通知维修人员 | 在线报修(Web端) | + +--- + +### 页面2:巡检管理 + +- **页面路径**:`/pages/manager/inspection` +- **适用角色**:物业管理员/主管 +- **页面元素**: + - 巡检统计卡片(今日任务/已完成/异常) + - 巡检看板(人员执行状态) + - 巡检记录列表 + - 异常记录查看 +- **查询条件**: + - 日期筛选 + - 状态筛选 + - 人员筛选 +- **列表字段**: + +| 字段 | 类型 | 说明 | +|------|------|------| +| 计划名称 | 文本 | 巡检计划名称 | +| 执行人 | 文本 | 巡检人员姓名 | +| 区域 | 文本 | 巡检区域 | +| 状态 | 标签 | 待执行/进行中/已完成 | +| 异常数 | 数字 | 发现异常数量 | + +- **界面布局**: + - 顶部:统计数字 + 看板缩略 + - 中部:巡检记录卡片列表 + - 底部:无操作栏 +- **操作按钮**: + - 「查看详情」→ 查看巡检记录详情 + - 「审核补录」→ 审核巡检补录申请(权限:inspection:supplement:approve) + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-PM-02 | 巡检管理 | 02-小程序端 §9 | 无 | 巡检管理(Web端) | + +--- + +### 页面3:保洁管理 + +- **页面路径**:`/pages/manager/cleaning` +- **适用角色**:物业管理员/主管 +- **页面元素**: + - 保洁统计卡片(今日任务/已完成/超时) + - 保洁任务列表 + - 排班查看 + - 抽查操作 +- **查询条件**: + - 日期筛选 + - 区域筛选 + - 状态筛选 +- **列表字段**: + +| 字段 | 类型 | 说明 | +|------|------|------| +| 任务名称 | 文本 | 保洁区域+类型 | +| 执行人 | 文本 | 保洁人员姓名 | +| 区域 | 文本 | 保洁区域 | +| 状态 | 标签 | 待执行/进行中/待抽查/已完成 | +| 抽查结果 | 标签 | 合格/不合格/待抽查 | + +- **界面布局**: + - 顶部:统计数字 + - 中部:任务卡片列表 + - 底部:抽查操作按钮 +- **操作按钮**: + - 「抽查」→ 标记抽查合格/不合格(权限:cleaning:spot-check:approve) + - 「审核补录」→ 审核保洁补录申请(权限:cleaning:supplement:approve) + - 「查看详情」→ 查看任务详情 + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-PM-03 | 保洁管理 | 02-小程序端 §9 | 不合格时重新生成任务 | 保洁管理(Web端) | + +--- + +### 页面4:考勤管理 + +- **页面路径**:`/pages/manager/attendance` +- **适用角色**:物业管理员/主管 +- **页面元素**: + - 今日出勤统计卡片(应到/实到/缺勤/异常) + - 考勤记录列表 + - 异常申诉审核 +- **查询条件**: + - 日期筛选 + - 班组筛选 + - 状态筛选(正常/迟到/早退/缺卡/异常) +- **列表字段**: + +| 字段 | 类型 | 说明 | +|------|------|------| +| 姓名 | 文本 | 员工姓名 | +| 班组 | 文本 | 所属班组 | +| 上班时间 | 时间 | 上班打卡时间 | +| 下班时间 | 时间 | 下班打卡时间 | +| 状态 | 标签 | 正常/迟到/早退/缺卡 | +| 打卡方式 | 标签 | 蓝牙/手动/补录 | + +- **界面布局**: + - 顶部:统计数字 + - 中部:考勤记录列表 + - 底部:审核操作按钮 +- **操作按钮**: + - 「审核申诉」→ 审核打卡异常申诉(权限:attendance:appeal:approve) + - 「审核补录」→ 审核考勤补录(权限:attendance:supplement:approve) + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-PM-04 | 考勤管理 | 02-小程序端 §9 | 补录打卡记录 | 考勤打卡(Web端) | + +--- + +### 页面5:评价管理 + +- **页面路径**:`/pages/manager/evaluation` +- **适用角色**:物业管理员/主管 +- **页面元素**: + - 评价统计卡片(总评价数/平均分/待回复) + - 评价列表 + - 回复操作 +- **查询条件**: + - 评分筛选(全部/好评/中评/差评) + - 回复状态筛选(全部/待回复/已回复) + - 时间筛选 +- **列表字段**: + +| 字段 | 类型 | 说明 | +|------|------|------| +| 工单编号 | 文本 | 关联工单号 | +| 评分 | 数字 | 1~5分 | +| 评价内容 | 文本 | 留言摘要 | +| 评价时间 | 时间 | 提交评价时间 | +| 回复状态 | 标签 | 已回复/未回复 | + +- **界面布局**: + - 顶部:统计数字 + 平均分显示 + - 中部:评价卡片列表 + - 底部:回复操作 +- **操作按钮**: + - 「回复」→ 回复评价(权限:evaluation:list:update) + - 「查看详情」→ 查看评价详情 + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-PM-05 | 评价管理 | 02-小程序端 §9 | 通知报修人 | 服务评价(Web端) | + +--- + +### 页面6:组织架构查看 + +- **页面路径**:`/pages/manager/org` +- **适用角色**:物业管理员/主管 +- **页面元素**: + - 班组列表 + - 班组成员查看 + - 人员基本信息查看 +- **查询条件**: + - 班组筛选 + - 关键词搜索(姓名/职位) +- **列表字段**: + +| 字段 | 类型 | 说明 | +|------|------|------| +| 班组名称 | 文本 | 班组名 | +| 班组长 | 文本 | 负责人姓名 | +| 人数 | 数字 | 班组人数 | +| 技能标签 | 标签组 | 班组主要技能 | + +- **界面布局**: + - 顶部:搜索框 + 筛选 + - 中部:班组卡片列表 → 点击展开成员列表 + - 底部:无操作栏 +- **操作按钮**: + - 「查看班组」→ 展开班组成员列表 + - 「查看人员」→ 查看人员详情 + - 「拨打电话」→ 调用手机拨号功能 + +**数据来源**:与Web端组织架构同一数据源 + +**需求追溯**: + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| MP-PM-06 | 组织架构查看 | 02-小程序端 §9 | 无 | 组织架构(Web端) | + +--- + +## 业务规则 + +1. **数据同步**:管理员小程序端与Web端同一数据源,操作实时同步 +2. **功能简化**:小程序端为简化版管理功能,完整管理操作在Web端进行 +3. **权限继承**:管理员小程序端的权限与Web端角色权限一致,通过四级权限体系控制 +4. **双端审批**:以下审批场景支持Web+小程序双端操作: + - 工单延期审批 ✅ + - 工单分配 ✅ + - 工单验收 ✅ + - 打卡异常审核 ✅ + - 数据补录审核 ✅ + - 保洁抽查 ✅ +5. **仅限物业端审批**:合同审批、合同变更审批、合同续签审批、付款确认、定标审批仅Web端(医院账号) +6. **推送通知**:审批待办通过微信小程序推送通知管理员 +7. **操作日志**:所有管理操作记录审计日志 + +## 状态流转 + +管理员小程序端的状态流转与Web端一致,具体参见各模块文档: +- 报修工单流转 → 参见02-功能清单-物业公司/01-在线报修.md +- 巡检任务流转 → 参见02-功能清单-物业公司/02-巡检管理.md +- 保洁任务流转 → 参见02-功能清单-物业公司/03-保洁管理.md + +## 双端审批对照表 + +| 审批场景 | Web端 | 小程序端 | 审批角色 | +|----------|-------|----------|----------| +| 工单延期审批 | ✅ | ✅ | 物业(主管) | +| 工单分配 | ✅ | ✅ | 物业(主管) | +| 工单验收 | ✅ | ✅ | 物业(主管/报修人) | +| 合同审批 | ✅ | — | 医院账号(仅Web端) | +| 合同变更审批 | ✅ | — | 医院账号(仅Web端) | +| 合同续签审批 | ✅ | — | 医院账号(仅Web端) | +| 付款确认 | ✅ | — | 医院账号(仅Web端) | +| 定标审批 | ✅ | — | 医院账号(仅Web端) | +| 打卡异常审核 | ✅ | ✅ | 物业(主管) | +| 数据补录审核 | ✅ | ✅ | 物业(主管) | +| 保洁抽查 | ✅ | ✅ | 物业(主管) | diff --git a/docs/02-功能清单-物业公司.md b/docs/02-功能清单-物业公司.md new file mode 100644 index 0000000..bdf57ea --- /dev/null +++ b/docs/02-功能清单-物业公司.md @@ -0,0 +1,133 @@ +# 物业公司 — 功能点清单 + +> 版本:v4.0 +> 物业公司管理员负责绑定医院的日常业务管理,可创建下属人员账号并分配角色。 +> 端侧:Web端 + 微信小程序端(小程序端功能详见 `02-功能清单-小程序端.md`) +> 关联文档:`01-模块划分.md`(v4.0) + +--- + +## 1. 在线报修(repair) + +| 编号 | 功能点 | 说明 | 优先级 | +|------|--------|------|--------| +| PR-R-01 | 工单列表 | 按状态/日期/区域/班组/紧急程度多维筛选,批量操作 | P0 | +| PR-R-02 | 工单详情 | 完整信息、流转记录时间轴、照片附件、评价 | P0 | +| PR-R-03 | 工单分配 | 手动分配或按规则自动分配到班组/维修人员 | P0 | +| PR-R-04 | 工单流转 | 待分配→处理中→待验收→已完成/已关闭 | P0 | +| PR-R-05 | 延期审批 | 审批维修人员延期申请 | P0 | +| PR-R-06 | 协助维修管理 | 查看协助子工单,协调跨班组协作 | P0 | +| PR-R-07 | 报修类型管理 | 维护报修分类及对应班组(可自定义) | P0 | +| PR-R-08 | 工单验收 | 主管/报修人验收工单 | P0 | +| PR-R-09 | 退单/返修处理 | 验收不通过退回返修 | P0 | +| PR-R-10 | 数据补录 | 对因系统异常导致的缺失数据进行补录,标注补录标记和原因 | P0 | +| PR-R-11 | 工单导出 | 导出工单列表Excel | P1 | + +--- + +## 2. 巡检管理(inspection) + +| 编号 | 功能点 | 说明 | 优先级 | +|------|--------|------|--------| +| PR-I-01 | 巡检计划管理 | 创建/编辑/停用计划(区域、设备、频次、人员) | P0 | +| PR-I-02 | 巡检任务看板 | 日历视图+列表视图,颜色区分正常/异常/未执行 | P0 | +| PR-I-03 | 巡检记录查询 | 打卡时间、定位、照片、异常记录 | P0 | +| PR-I-04 | 异常处理跟踪 | 异常触发的报修工单及进度 | P0 | +| PR-I-05 | 巡检区域管理 | 巡检点位及蓝牙Beacon绑定 | P0 | +| PR-I-06 | 数据补录 | 对因蓝牙失灵/系统宕机导致缺失的巡检记录补录 | P0 | +| PR-I-07 | 补录审核 | 审核巡检人员提交的异常数据补录申请 | P0 | + +--- + +## 3. 保洁管理(cleaning) + +| 编号 | 功能点 | 说明 | 优先级 | +|------|--------|------|--------| +| PR-C-01 | 保洁区域管理 | 五级架构:项目→区域→楼栋→楼层→区域责任人 | P0 | +| PR-C-02 | 保洁任务看板 | 看板视图(待执行/执行中/已完成) | P0 | +| PR-C-03 | 人员排班 | 周/月视图排班,支持复制排班 | P0 | +| PR-C-04 | 蓝牙点位管理 | 保洁区域与Beacon绑定,设置打卡规则 | P0 | +| PR-C-05 | 超时预警 | 任务超时自动预警推送主管 | P0 | +| PR-C-06 | 保洁抽查 | 主管标记需抽查任务,查看结果 | P0 | +| PR-C-07 | 数据补录 | 对因系统异常导致缺失的保洁完成记录补录 | P0 | +| PR-C-08 | 补录审核 | 审核保洁人员提交的异常数据补录申请 | P0 | + +--- + +## 4. 组织架构(org) + +| 编号 | 功能点 | 说明 | 优先级 | +|------|--------|------|--------| +| PR-O-01 | 班组管理 | 创建/编辑/停用班组,设置班组长,分配负责区域 | P0 | +| PR-O-02 | 人员管理 | 员工信息维护,技能标签,支持一人多班组 | P0 | +| PR-O-03 | 人员分配 | 按区域/技能/排班维度分配人员到班组 | P0 | +| PR-O-04 | 排班管理 | 班组排班日历,批量排班和模板排班 | P0 | +| PR-O-05 | 技能管理 | 维护技能标签,关联班组和人员 | P0 | +| PR-O-06 | 打卡点分配 | 按班组设置上下班蓝牙打卡点位 | P0 | +| PR-O-07 | 下属账号管理 | 创建/编辑/停用下属账号(主管/员工等) | P0 | +| PR-O-08 | 下属角色分配 | 从超管定义的角色中选择,分配给下属 | P0 | +| PR-O-09 | 下属权限覆盖 | 对特定下属自定义权限(在角色基础上调整) | P0 | +| PR-O-10 | 下属账号批量操作 | 批量启停/分配角色 | P1 | +| PR-O-11 | 下属数据权限设置 | 设置下属的数据可见范围(班组/区域级别) | P0 | + +--- + +## 5. 考勤打卡(attendance) + +| 编号 | 功能点 | 说明 | 优先级 | +|------|--------|------|--------| +| PR-A-01 | 打卡点管理 | 按班组/角色设置不同上下班打卡点,绑定蓝牙Beacon | P0 | +| PR-A-02 | 打卡规则 | 设置上班/下班时间窗口、迟到/早退规则(可自定义) | P0 | +| PR-A-03 | 考勤记录 | 查看全员打卡记录,支持按班组/日期筛选 | P0 | +| PR-A-04 | 异常审核 | 审核员工提交的打卡异常申诉 | P0 | +| PR-A-05 | 数据补录 | 对因系统/蓝牙异常导致的考勤缺失进行补录 | P0 | + +--- + +## 6. 服务评价(evaluation) + +| 编号 | 功能点 | 说明 | 优先级 | +|------|--------|------|--------| +| PR-E-01 | 评价汇总看板 | 各模块平均评分、星级分布、评分趋势 | P0 | +| PR-E-02 | 评价列表 | 按模块/评分/日期筛选 | P0 | +| PR-E-03 | 评价回复 | 对用户评价回复 | P0 | +| PR-E-04 | 绩效报表 | 班组/人员评分排名,支持导出 | P1 | +| PR-E-05 | 评价配置 | 设置评价触发规则 | P0 | + +--- + +## 7. 统计报表(statistics) + +| 编号 | 报表类型 | 时间维度 | 支持操作 | 优先级 | +|------|----------|----------|----------|--------| +| PR-ST-01 | 报修统计 | 天/周/月/年/自定义 | 查看+导出Excel/PDF | P0 | +| PR-ST-02 | 巡检统计 | 天/周/月/年/自定义 | 查看+导出 | P0 | +| PR-ST-03 | 保洁统计 | 天/周/月/年/自定义 | 查看+导出 | P0 | +| PR-ST-04 | 评价统计 | 天/周/月/年/自定义 | 查看+导出 | P0 | +| PR-ST-05 | 考勤统计 | 天/周/月/年/自定义 | 查看+导出 | P0 | +| PR-ST-06 | 综合看板 | 天/周/月/年/自定义 | 查看 | P0 | +| PR-ST-07 | 自定义报表 | 自定义 | 用户自选维度+指标 | P1 | + +--- + +## 8. 操作日志(audit-log) + +| 编号 | 功能点 | 说明 | 优先级 | +|------|--------|------|--------| +| PR-AL-01 | 日志时间轴 | 以时间轴形式展示操作记录,按时间倒序排列 | P0 | +| PR-AL-02 | 日志列表 | 以表格形式展示,支持按模块/操作人/日期/操作类型筛选 | P0 | +| PR-AL-03 | 日志详情 | 查看单条操作完整信息(操作人、时间、IP、操作内容、变更前后对比) | P0 | +| PR-AL-04 | 日志导出 | 导出操作日志Excel | P1 | +| PR-AL-05 | 数据补录日志 | 专门查看数据补录记录 | P0 | + +--- + +## 9. 系统配置 + +| 编号 | 功能点 | 说明 | 优先级 | +|------|--------|------|--------| +| PR-S-01 | 蓝牙设备管理 | Beacon列表、位置绑定、状态监控、电量预警 | P0 | +| PR-S-02 | 字典管理 | 报修/巡检/保洁类型等字典,按租户自定义 | P0 | +| PR-S-03 | 微信配置 | 小程序/公众号参数配置 | P0 | +| PR-S-04 | 消息模板 | 微信模板消息配置 | P0 | +| PR-S-05 | 数据补录审核 | 审核各模块数据补录申请(主管) | P0 | diff --git a/docs/02-功能清单-物业公司/01-在线报修.md b/docs/02-功能清单-物业公司/01-在线报修.md new file mode 100644 index 0000000..046d1a2 --- /dev/null +++ b/docs/02-功能清单-物业公司/01-在线报修.md @@ -0,0 +1,392 @@ +# 在线报修 + +> 模块编码:repair +> 端侧:Web + 小程序(双端) +> 关联文档:01-模块划分 §3.1 / 02-功能清单-物业公司 §1 / 03-业务流转逻辑-物业公司 §1 / 05-接口规范 §9.2 / 06-项目技术要求 §4.4 + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 在线报修 | +| 子菜单 | 工单列表、工单详情、报修类型管理、数据补录 | +| 功能编号 | PR-R-01 ~ PR-R-11 | +| 权限编码前缀 | repair:list:* / repair:detail:* / repair:type:* / repair:supplement:* | + +--- + +## 页面1:工单列表页 + +**页面编号**:PR-R-01-P01 +**端侧归属**:Web专属(小程序端对应"我的工单",见 MP-R-03) +**页面路径**:/repair/orders + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 在线报修 > 工单列表 │ +├──────────────────────────────────────────────────────────────────┤ +│ [查询条件区] │ +│ 工单号[____] 状态[▼多选] 报修类型[▼] 紧急程度[▼] │ +│ 提交日期[起始]~[结束] 所属班组[▼] 所属区域[▼] │ +│ [查询] [重置] │ +├──────────────────────────────────────────────────────────────────┤ +│ [操作栏] [新增工单] [批量分配] [批量关闭] [导出Excel] │ +├──────────────────────────────────────────────────────────────────┤ +│ [列表区] │ +│ ☐ | 工单号 | 报修类型 | 紧急程度 | 状态 | 报修人 | 班组 | ... │ +│ ☐ | WX001 | 水电 | 紧急 | 待分配| 张三 | 水电班| ... │ +│ ☐ | WX002 | 木工 | 普通 | 处理中| 李四 | 木工班| ... │ +├──────────────────────────────────────────────────────────────────┤ +│ [分页] 共156条 每页[20▼] < 1 2 3 ... 8 > │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 工单号 | 文本输入 | 否 | — | 模糊匹配 | +| 状态 | 下拉多选 | 否 | 全部 | 待分配/处理中/延期中/待验收/已完成/已关闭 | +| 报修类型 | 下拉单选 | 否 | 全部 | 数据来源:字典管理-报修类型 | +| 紧急程度 | 下拉单选 | 否 | 全部 | 紧急/普通/低优先 | +| 提交日期 | 日期范围 | 否 | — | 起始~结束 | +| 所属班组 | 下拉单选 | 否 | 全部 | 数据来源:组织架构-班组 | +| 所属区域 | 级联选择 | 否 | 全部 | 项目→区域→楼栋→楼层 | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | ☐勾选 | 40px | — | 批量操作用 | +| 2 | 工单号 | 140px | 是 | 点击跳转详情页 | +| 3 | 报修类型 | 80px | 是 | 标签样式 | +| 4 | 紧急程度 | 80px | 是 | 紧急=红色/普通=蓝色/低=灰色 | +| 5 | 状态 | 90px | 是 | 彩色标签区分状态 | +| 6 | 报修人 | 80px | 否 | — | +| 7 | 负责班组 | 90px | 是 | — | +| 8 | 维修人员 | 80px | 否 | 未分配时显示"—" | +| 9 | 提交时间 | 150px | 是 | 默认倒序 | +| 10 | 预约时间 | 150px | 否 | — | +| 11 | 补录标记 | 70px | 否 | 补录数据显示"补录"橙色标签 | +| 12 | 操作 | 160px | — | 查看/分配/关闭 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 新增工单 | repair:list:create | 操作栏 | 始终 | 弹窗/跳转新增页 | +| 批量分配 | repair:list:assign | 操作栏 | 勾选≥1条且状态=待分配 | 批量分配弹窗 | +| 批量关闭 | repair:list:update | 操作栏 | 勾选≥1条且状态=待分配 | 二次确认弹窗 | +| 导出Excel | repair:list:export | 操作栏 | 始终 | 导出当前筛选结果 | +| 行内-分配 | repair:list:assign | 操作列 | 状态=待分配 | — | +| 行内-关闭 | repair:list:update | 操作列 | 状态=待分配 | 二次确认 | +| 行内-查看 | repair:list:view | 操作列 | 始终 | 跳转详情页 | + +### 角色差异化视图 + +| 角色 | 可见按钮 | 数据范围 | 备注 | +|------|----------|----------|------| +| 物业管理员 | 全部按钮 | 本公司绑定医院全部数据 | — | +| 主管 | 查看、分配、导出 | 本班组数据 | 无新增按钮 | +| 维修人员 | 仅查看 | 仅本人负责的工单 | 操作列仅"查看" | + +### 通知触发 + +| 触发操作 | 通知对象 | 通知方式 | 消息模板 | 文档来源 | +|----------|----------|----------|----------|----------| +| 工单分配 | 被分配的维修人员 | 小程序推送 | 新工单通知 | 01 §7.1 | +| 工单关闭 | 报修人 | 小程序推送 | 工单关闭通知 | 01 §7.1 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/repair-orders | GET | 分页查询,支持筛选参数 | +| 批量分配 | /api/v1/repair-orders/batch-assign | POST | 批量分配到班组/人员 | +| 批量关闭 | /api/v1/repair-orders/batch-close | POST | 需填关闭原因 | +| 导出 | /api/v1/repair-orders/export | GET | 导出Excel | + +--- + +## 页面2:工单详情页 + +**页面编号**:PR-R-02-P01 +**端侧归属**:Web专属 +**页面路径**:/repair/orders/:id + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 在线报修 > 工单列表 > 工单详情 │ +├──────────────────────────────────────────────────────────────────┤ +│ [状态栏] 工单号:WX20260416001 当前状态:待分配 │ +├──────────────────────────────────────────────────────────────────┤ +│ [标签页] 基本信息 | 流转记录 | 照片附件 | 评价信息 │ +├──────────────────────────────────────────────────────────────────┤ +│ ── 基本信息(默认展示)── │ +│ 报修类型:水电 紧急程度:紧急 │ +│ 报修人:张三 联系电话:138****1234 │ +│ 报修区域:主院区/门诊楼/3层 │ +│ 报修描述:3楼走廊灯管不亮,影响夜间通行 │ +│ 预约时间:2026-04-16 14:00 │ +│ 补录标记:否 │ +├──────────────────────────────────────────────────────────────────┤ +│ [底部操作栏] │ +│ [分配工单] [关闭工单] 状态=待分配时显示 │ +│ [验收通过] [验收不通过(退回)] 状态=待验收时显示 │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 标签页内容 + +| 标签页 | 内容 | 说明 | +|--------|------|------| +| 基本信息 | 报修类型、紧急程度、报修人、区域、描述、预约时间、补录标记 | 补录数据额外显示补录原因和审核状态 | +| 流转记录 | 时间轴展示工单状态变更历史 | 每条记录含:操作人、时间、操作类型、备注 | +| 照片附件 | 报修照片(缩略图+点击预览) | 照片含水印信息:时间+位置+蓝牙连接标记 | +| 评价信息 | 工单完成后的评价内容 | 评分+留言+图片,未评价时显示"暂无评价" | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 分配工单 | repair:list:assign | 底部操作栏 | 状态=待分配 | 弹窗选择班组/人员 | +| 关闭工单 | repair:list:update | 底部操作栏 | 状态=待分配 | 填写关闭原因 | +| 审批延期 | repair:detail:approve | 底部操作栏 | 状态=延期中 | 通过/驳回 | +| 验收通过 | repair:detail:approve | 底部操作栏 | 状态=待验收 | — | +| 验收不通过 | repair:detail:approve | 底部操作栏 | 状态=待验收 | 填写不通过原因,退回返修 | + +### 角色差异化视图 + +| 角色 | 可见操作 | 数据范围 | 备注 | +|------|----------|----------|------| +| 物业管理员 | 全部操作 | 全部工单 | — | +| 主管 | 分配、审批、验收 | 本班组工单 | — | +| 维修人员 | 仅查看 | 仅本人负责的工单 | 底部操作栏隐藏 | + +### 通知触发 + +| 触发操作 | 通知对象 | 通知方式 | 消息模板 | 文档来源 | +|----------|----------|----------|----------|----------| +| 分配工单 | 维修人员 | 小程序推送 | 新工单通知 | 01 §7.1 | +| 延期审批结果 | 维修人员 | 小程序推送 | 延期审批结果通知 | 01 §7.1 | +| 验收不通过 | 维修人员 | 小程序推送 | 验收退回通知 | 01 §7.1 | +| 验收通过 | 报修人 | 小程序推送 | 工单完成通知,触发评价 | 01 §7.1 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 详情查询 | /api/v1/repair-orders/{id} | GET | 含基本信息+流转记录+照片 | +| 分配工单 | /api/v1/repair-orders/{id}/assign | POST | 分配到班组/人员 | +| 关闭工单 | /api/v1/repair-orders/{id}/close | POST | 填写关闭原因 | +| 延期审批 | /api/v1/repair-orders/{id}/delay-approve | POST | 通过/驳回 | +| 验收 | /api/v1/repair-orders/{id}/accept | POST | 通过/不通过 | + +--- + +## 页面3:新增工单弹窗 + +**页面编号**:PR-R-01-P02 +**端侧归属**:Web专属 +**页面路径**:弹窗形式 + +### 界面布局 + +``` +┌──────────────────────────────────────┐ +│ 新增工单 [×] │ +├──────────────────────────────────────┤ +│ 报修类型:[▼必选] 紧急程度:[▼] │ +│ 报修区域:[级联选择▼] │ +│ 报修人: [____] 联系电话:[____] │ +│ 预约时间:[日期时间选择] │ +│ 报修描述: │ +│ ┌────────────────────────────────┐ │ +│ │ │ │ +│ └────────────────────────────────┘ │ +│ 照片上传:[+点击上传] (≤9张) │ +│ 📷1 📷2 📷3 │ +├──────────────────────────────────────┤ +│ [取消] [提交] │ +└──────────────────────────────────────┘ +``` + +### 表单字段 + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 报修类型 | 下拉单选 | 是 | — | 字典管理-报修类型 | — | +| 紧急程度 | 下拉单选 | 是 | 普通 | 固定选项 | 紧急/普通/低优先 | +| 报修区域 | 级联选择 | 是 | — | 区域五级架构 | 至少选到楼层 | +| 报修人 | 文本输入 | 是 | — | 自填 | 最大20字 | +| 联系电话 | 文本输入 | 是 | — | 自填 | 手机号格式校验 | +| 预约时间 | 日期时间 | 否 | — | 自填 | 不早于当前时间 | +| 报修描述 | 多行文本 | 是 | — | 自填 | 最大500字 | +| 照片 | 图片上传 | 否 | — | 拍照/相册 | ≤9张,单张≤20MB,自动加水印 | + +--- + +## 页面4:报修类型管理页 + +**页面编号**:PR-R-07-P01 +**端侧归属**:Web专属 +**页面路径**:/repair/types + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 在线报修 > 报修类型管理 │ +├──────────────────────────────────────────────────────────────────┤ +│ [操作栏] [新增类型] │ +├──────────────────────────────────────────────────────────────────┤ +│ [列表区] │ +│ 序号 | 类型名称 | 关联班组 | 工单数量 | 状态 | 操作 │ +│ 1 | 水电 | 水电班 | 23 | 启用 | 编辑 停用 │ +│ 2 | 木工 | 木工班 | 8 | 启用 | 编辑 停用 │ +│ 3 | 空调 | 暖通班 | 15 | 停用 | 编辑 启用 │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 表单字段(新增/编辑弹窗) + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 类型名称 | 文本输入 | 是 | — | 自填 | 最大20字,同租户内唯一 | +| 关联班组 | 下拉多选 | 是 | — | 组织架构-班组 | 至少选一个 | +| 描述 | 多行文本 | 否 | — | 自填 | 最大200字 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 新增类型 | repair:type:create | 操作栏 | 始终 | 弹窗 | +| 编辑 | repair:type:update | 行操作 | 始终 | 弹窗 | +| 启用/停用 | repair:type:update | 行操作 | 始终 | 有工单关联时不可停用,提示先迁移 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/repair-types | GET | — | +| 新增 | /api/v1/repair-types | POST | — | +| 编辑 | /api/v1/repair-types/{id} | PUT | — | +| 启用/停用 | /api/v1/repair-types/{id}/toggle-status | PUT | — | + +--- + +## 页面5:数据补录页 + +**页面编号**:PR-R-10-P01 +**端侧归属**:Web专属 +**页面路径**:/repair/supplement + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 在线报修 > 数据补录 │ +├──────────────────────────────────────────────────────────────────┤ +│ [查询条件区] │ +│ 补录状态[▼] 补录人[____] 补录时间[起始]~[结束] [查询] [重置] │ +├──────────────────────────────────────────────────────────────────┤ +│ [列表区] │ +│ 序号 | 工单号 | 补录人 | 补录原因 | 补录时间 | 审核状态 | 操作 │ +│ 1 | WX001 | 张三 | 系统异常 | 10:30 | 待审核 | 审核 详情│ +│ 2 | WX002 | 李四 | 蓝牙故障 | 09:15 | 已通过 | 详情 │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 补录状态 | 下拉单选 | 否 | 全部 | 待审核/已通过/已驳回 | +| 补录人 | 文本输入 | 否 | — | 模糊匹配 | +| 补录时间 | 日期范围 | 否 | — | — | + +### 补录数据标记规范 + +| 标记项 | 说明 | +|--------|------| +| 列表标签 | 补录行在工单列表中显示"补录"橙色标签 | +| 补录原因 | 蓝牙故障/系统异常/定位失败/其他(枚举) | +| 审核状态列 | 待审核(黄色)/已通过(绿色)/已驳回(红色) | +| 详情展示 | 补录原因+详细说明+审核人+审核时间 | +| 统计排除 | 补录数据在统计报表中单独标记,默认包含,可筛选排除 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 审核 | repair:supplement:approve | 行操作 | 审核状态=待审核 | 通过/驳回弹窗 | +| 详情 | repair:supplement:view | 行操作 | 始终 | 查看补录详情 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/repair-orders/supplements | GET | 分页查询 | +| 审核 | /api/v1/repair-orders/supplements/{id}/approve | POST | 通过/驳回 | + +--- + +## 需求追溯 + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| PR-R-01 | 工单列表 | 02-物业公司 §1 / 03-物业公司 §1.2 | — | 巡检异常上报→自动生成工单 | +| PR-R-02 | 工单详情 | 02-物业公司 §1 / 03-物业公司 §1.2 | 流转记录、照片查看 | 评价管理→工单评价展示 | +| PR-R-03 | 工单分配 | 02-物业公司 §1 / 03-物业公司 §1.2 | 触发通知服务→推送维修人员 | 组织架构→班组/人员选择 | +| PR-R-04 | 工单流转 | 02-物业公司 §1 / 03-物业公司 §1.2 | 状态变更→触发通知 | — | +| PR-R-05 | 延期审批 | 02-物业公司 §1 / 03-物业公司 §1.2 | 审批结果→通知维修人员 | 小程序端延期申请(MP-R-07) | +| PR-R-06 | 协助维修管理 | 02-物业公司 §1 / 03-物业公司 §1.2 | 生成协助子工单→通知协助班组 | 小程序端协助申请(MP-R-09) | +| PR-R-07 | 报修类型管理 | 02-物业公司 §1 | 类型变更→刷新字典缓存 | 字典管理→报修类型字典 | +| PR-R-08 | 工单验收 | 02-物业公司 §1 / 03-物业公司 §1.2 | 验收通过→触发评价 | 小程序端验收(MP-R-11) / 评价管理 | +| PR-R-09 | 退单/返修处理 | 02-物业公司 §1 / 03-物业公司 §1.2 | 退回→通知维修人员 | — | +| PR-R-10 | 数据补录 | 02-物业公司 §1 / 03-物业公司 §2.2 | 补录审核→通知补录人 | 操作日志→补录日志 | +| PR-R-11 | 工单导出 | 02-物业公司 §1 | 记录导出操作日志 | — | + +## 业务规则 + +1. **工单号规则**:WX + 年月日 + 3位序号,如 WX20260416001(来源:03-物业公司 §1) +2. **状态流转规则**:待分配→处理中→待验收→已完成/已关闭,详见状态流转图(来源:03-物业公司 §1.2) +3. **分配规则**:支持手动分配和自动分配(按报修类型→关联班组→班组内轮询)(来源:02-物业公司 PR-R-03) +4. **照片水印**:上传照片自动添加水印(时间+位置+蓝牙连接标记),来源:05-接口规范 §3.2 +5. **补录审核**:补录数据需主管审核,审核通过后生效;审核驳回需通知补录人(来源:03-物业公司 §2.2) +6. **验收触发评价**:工单验收通过后自动触发评价流程(来源:03-物业公司 §1.2,事件:ORDER_COMPLETED) +7. **退单返修**:验收不通过时工单退回处理中状态,维修人员需重新处理(来源:03-物业公司 §1.2) +8. **数据权限**:主管仅看本班组数据,员工仅看本人数据(来源:01 §1.3) +9. **操作日志**:所有工单操作自动记录审计日志(来源:06 §4.5) + +## 状态流转 + +``` + ┌─── 关闭工单 ──▶ 已关闭 + │ +报修提交 ──▶ 待分配 ──▶ 分配工单 ──▶ 处理中 ──▶ 提交完工 ──▶ 待验收 ──▶ 验收通过 ──▶ 已完成 + │ │ + 申请延期▶ 延期中 验收不通过 + 申请协助▶ 生成子工单 │ + │ ▼ + 延期审批 退回处理中 + 通过/驳回 (返修) +``` + +| 当前状态 | 操作 | 目标状态 | 执行角色 | 端侧 | +|----------|------|----------|----------|------| +| — | 提交报修 | 待分配 | 报修人 | 小程序 | +| 待分配 | 分配工单 | 处理中 | 主管/系统 | Web+小程序 | +| 待分配 | 关闭工单 | 已关闭 | 主管 | Web+小程序 | +| 处理中 | 提交完工 | 待验收 | 维修人员 | 小程序 | +| 处理中 | 申请延期 | 延期中 | 维修人员 | 小程序 | +| 处理中 | 申请协助 | 处理中 | 维修人员 | 小程序 | +| 延期中 | 审批通过 | 处理中 | 主管 | Web+小程序 | +| 延期中 | 审批驳回 | 处理中 | 主管 | Web+小程序 | +| 待验收 | 验收通过 | 已完成 | 主管/报修人 | Web+小程序 | +| 待验收 | 验收不通过 | 处理中 | 主管/报修人 | Web+小程序 | +| 已完成 | 评价 | 已完成 | 报修人 | 小程序 | diff --git a/docs/02-功能清单-物业公司/02-巡检管理.md b/docs/02-功能清单-物业公司/02-巡检管理.md new file mode 100644 index 0000000..730543c --- /dev/null +++ b/docs/02-功能清单-物业公司/02-巡检管理.md @@ -0,0 +1,382 @@ +# 巡检管理 + +> 模块编码:inspection +> 端侧:Web + 小程序(双端) +> 关联文档:01-模块划分 §3.2 / 02-功能清单-物业公司 §2 / 03-业务流转逻辑-物业公司 §2 / 05-接口规范 §9.2 / 06-项目技术要求 §4.4 + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 巡检管理 | +| 子菜单 | 巡检计划管理、巡检任务看板、巡检记录查询、异常处理跟踪、巡检区域管理、数据补录 | +| 功能编号 | PR-I-01 ~ PR-I-07 | +| 权限编码前缀 | inspection:plan:* / inspection:task:* / inspection:area:* / inspection:supplement:* | + +--- + +## 页面1:巡检计划管理页 + +**页面编号**:PR-I-01-P01 +**端侧归属**:Web专属 +**页面路径**:/inspection/plans + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 巡检管理 > 巡检计划管理 │ +├──────────────────────────────────────────────────────────────────┤ +│ [查询条件区] │ +│ 计划名称[____] 状态[▼] 巡检类型[▼] 负责班组[▼] [查询] [重置] │ +├──────────────────────────────────────────────────────────────────┤ +│ [操作栏] [新增计划] │ +├──────────────────────────────────────────────────────────────────┤ +│ [列表区] │ +│ 序号 | 计划名称 | 巡检类型 | 频次 | 负责班组 | 巡检人员 | 状态 | 操作│ +│ 1 | 门诊楼日常| 日常 | 每日 | 巡检一班 | 张三,李四| 启用 | 编辑│ +│ 2 | 空调专项 | 专项 | 每周 | 巡检二班 | 王五 | 停用 | 编辑│ +├──────────────────────────────────────────────────────────────────┤ +│ [分页] 共25条 每页[20▼] < 1 2 > │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 计划名称 | 文本输入 | 否 | — | 模糊匹配 | +| 状态 | 下拉单选 | 否 | 全部 | 启用/停用 | +| 巡检类型 | 下拉单选 | 否 | 全部 | 数据来源:字典管理-巡检类型 | +| 负责班组 | 下拉单选 | 否 | 全部 | 数据来源:组织架构-班组 | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 序号 | 60px | — | 自增 | +| 2 | 计划名称 | 160px | 是 | — | +| 3 | 巡检类型 | 80px | 否 | 标签样式 | +| 4 | 频次 | 80px | 否 | 每日/每周/每月/自定义 | +| 5 | 负责班组 | 100px | 是 | — | +| 6 | 巡检人员 | 150px | 否 | 显示人员列表 | +| 7 | 巡检区域 | 150px | 否 | 简略显示区域 | +| 8 | 状态 | 80px | 是 | 启用/停用 | +| 9 | 操作 | 100px | — | 编辑/停用 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 新增计划 | inspection:plan:create | 操作栏 | 始终 | 跳转新增页 | +| 编辑 | inspection:plan:update | 行操作 | 始终 | — | +| 启用/停用 | inspection:plan:update | 行操作 | 始终 | 停用后不再生成任务 | + +### 表单字段(新增/编辑页) + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 计划名称 | 文本输入 | 是 | — | 自填 | 最大50字,同租户内唯一 | +| 巡检类型 | 下拉单选 | 是 | — | 字典管理-巡检类型 | — | +| 巡检区域 | 级联多选 | 是 | — | 区域五级架构 | 至少选一个 | +| 巡检设备 | 下拉多选 | 否 | — | 区域关联设备 | 可选,不选则巡检所有 | +| 频次 | 下拉单选 | 是 | — | 固定选项 | 每日/每周/每月/自定义 | +| 自定义cron | 文本输入 | 条件 | — | 自填 | 频次=自定义时必填 | +| 负责班组 | 下拉单选 | 是 | — | 组织架构-班组 | — | +| 巡检人员 | 下拉多选 | 是 | — | 班组内人员 | 至少选一个 | +| 巡检清单 | 下拉多选 | 是 | — | 巡检清单模板 | 至少选一个检查项 | +| 生效日期 | 日期选择 | 是 | — | 自填 | 不早于当前日期 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/inspection-plans | GET | 分页查询 | +| 新增 | /api/v1/inspection-plans | POST | — | +| 编辑 | /api/v1/inspection-plans/{id} | PUT | — | +| 启用/停用 | /api/v1/inspection-plans/{id}/toggle-status | PUT | — | + +--- + +## 页面2:巡检任务看板页 + +**页面编号**:PR-I-02-P01 +**端侧归属**:Web专属 +**页面路径**:/inspection/tasks + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 巡检管理 > 巡检任务看板 │ +├──────────────────────────────────────────────────────────────────┤ +│ [视图切换] 📅日历视图 📋列表视图 日期:[◀ 2026-04-16 ▶] │ +├──────────────────────────────────────────────────────────────────┤ +│ ── 日历视图(默认)── │ +│ 1 2 3 4 5 6 7 │ +│ 上午 🟢 🟢 🔴 🟢 🟡 🟢 🟢 │ +│ 下午 🟢 🟡 🟢 🟢 🟢 — — │ +│ 🟢=正常 🔴=异常 🟡=未执行 —=无任务 │ +├──────────────────────────────────────────────────────────────────┤ +│ ── 列表视图 ── │ +│ 日期 | 计划名称 | 巡检人员 | 打卡时间 | 状态 | 异常数 | 操作 │ +│ 04-16| 门诊楼日常| 张三 | 09:15 | 正常 | 0 | 查看 │ +│ 04-16| 住院楼日常| 李四 | — | 未执行| — | — │ +│ 04-15| 门诊楼日常| 张三 | 09:20 | 异常 | 2 | 查看 │ +├──────────────────────────────────────────────────────────────────┤ +│ [分页] 共30条 每页[20▼] < 1 2 > │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 日期 | 日期选择 | 否 | 今天 | — | +| 计划名称 | 下拉单选 | 否 | 全部 | — | +| 状态 | 下拉单选 | 否 | 全部 | 正常/异常/未执行 | +| 巡检人员 | 文本输入 | 否 | — | 模糊匹配 | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 日期 | 100px | 是 | — | +| 2 | 计划名称 | 150px | 否 | — | +| 3 | 巡检人员 | 80px | 否 | — | +| 4 | 打卡时间 | 100px | 是 | 未执行显示"—" | +| 5 | 打卡方式 | 80px | 否 | 蓝牙/手动/补录 | +| 6 | 状态 | 80px | 是 | 正常(绿)/异常(红)/未执行(黄) | +| 7 | 异常数 | 70px | 否 | 点击查看异常详情 | +| 8 | 操作 | 80px | — | 查看 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 任务列表 | /api/v1/inspection-tasks | GET | 分页查询 | +| 日历数据 | /api/v1/inspection-tasks/calendar | GET | 按月返回日历数据 | + +--- + +## 页面3:巡检记录查询页 + +**页面编号**:PR-I-03-P01 +**端侧归属**:Web专属 +**页面路径**:/inspection/records + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 巡检人员 | 文本输入 | 否 | — | 模糊匹配 | +| 日期范围 | 日期范围 | 否 | — | — | +| 打卡方式 | 下拉单选 | 否 | 全部 | 蓝牙/手动/补录 | +| 结果状态 | 下拉单选 | 否 | 全部 | 全部正常/有异常 | +| 补录标记 | 下拉单选 | 否 | 全部 | 正常数据/补录数据 | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 巡检人员 | 80px | 否 | — | +| 2 | 计划名称 | 150px | 否 | — | +| 3 | 巡检区域 | 150px | 否 | — | +| 4 | 打卡时间 | 140px | 是 | 默认倒序 | +| 5 | 打卡方式 | 80px | 否 | 蓝牙(蓝)/手动(灰)/补录(橙) | +| 6 | 检查项数 | 70px | 否 | — | +| 7 | 异常数 | 70px | 否 | — | +| 8 | 补录标记 | 70px | 否 | 补录显示"补录"标签+原因 | +| 9 | 操作 | 120px | — | 查看详情/查看异常 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 查看详情 | inspection:task:view | 行操作 | 始终 | 跳转记录详情 | +| 查看异常 | inspection:task:view | 行操作 | 异常数>0 | 跳转异常列表 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 记录列表 | /api/v1/inspection-records | GET | 分页查询 | +| 记录详情 | /api/v1/inspection-records/{id} | GET | 含打卡信息+检查项结果+照片 | + +--- + +## 页面4:异常处理跟踪页 + +**页面编号**:PR-I-04-P01 +**端侧归属**:Web专属 +**页面路径**:/inspection/abnormals + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 严重等级 | 下拉单选 | 否 | 全部 | 一般/较重/严重 | +| 处理状态 | 下拉单选 | 否 | 全部 | 待处理/已生成工单/已关闭 | +| 日期范围 | 日期范围 | 否 | — | — | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 异常编号 | 120px | 否 | — | +| 2 | 巡检记录 | 120px | 否 | 关联巡检记录 | +| 3 | 严重等级 | 80px | 是 | 一般(黄)/较重(橙)/严重(红) | +| 4 | 异常描述 | 200px | 否 | — | +| 5 | 上报人 | 80px | 否 | — | +| 6 | 上报时间 | 140px | 是 | 默认倒序 | +| 7 | 处理状态 | 100px | 否 | 待处理/已生成工单/已关闭 | +| 8 | 关联工单 | 120px | 否 | 点击跳转工单详情 | +| 9 | 操作 | 120px | — | 生成工单/查看 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 生成报修工单 | repair:list:create | 行操作 | 处理状态=待处理 | 一键生成,自动关联异常记录 | +| 查看 | inspection:task:view | 行操作 | 始终 | 查看异常详情 | + +### 通知触发 + +| 触发操作 | 通知对象 | 通知方式 | 消息模板 | 文档来源 | +|----------|----------|----------|----------|----------| +| 异常上报 | 物业主管 | 小程序推送 | 巡检异常通知 | 01 §7.1 | +| 生成工单 | 维修人员 | 小程序推送 | 新工单通知 | 05 §5.2 (INSPECTION_ABNORMAL) | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 异常列表 | /api/v1/inspection-abnormals | GET | 分页查询 | +| 生成工单 | /api/v1/inspection-abnormals/{id}/create-order | POST | — | + +--- + +## 页面5:巡检区域管理页 + +**页面编号**:PR-I-05-P01 +**端侧归属**:Web专属 +**页面路径**:/inspection/areas + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 巡检管理 > 巡检区域管理 │ +├──────────────────────────────────────────────────────────────────┤ +│ [操作栏] [新增区域] [批量导入] │ +├──────────────────────────────────────────────────────────────────┤ +│ [树形结构+列表] │ +│ ┌──────────────┐ ┌──────────────────────────────────────────┐ │ +│ │ 主院区 │ │ 区域:主院区 > 门诊楼 > 1层 │ │ +│ │ ├ 门诊楼 │ │ 蓝牙Beacon:B-001 (在线) │ │ +│ │ │ ├ 1层 │ │ Beacon UUID:xxxx-xxxx-xxxx │ │ +│ │ │ ├ 2层 │ │ 关联设备:灯控系统、空调系统 │ │ +│ │ │ └ 3层 │ │ 巡检计划:门诊楼日常巡检 │ │ +│ │ └ 住院楼 │ │ [编辑] [删除]│ │ +│ └──────────────┘ └──────────────────────────────────────────┘ │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 新增区域 | inspection:area:create | 操作栏 | 始终 | 弹窗 | +| 编辑 | inspection:area:update | 详情区 | 始终 | — | +| 删除 | inspection:area:delete | 详情区 | 无关联计划时 | 二次确认 | + +### 表单字段(新增/编辑弹窗) + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 区域名称 | 文本输入 | 是 | — | 自填 | 最大30字 | +| 上级区域 | 级联选择 | 是 | — | 区域树 | — | +| 蓝牙Beacon | 下拉单选 | 是 | — | 蓝牙设备管理(在线设备) | — | +| 关联设备 | 下拉多选 | 否 | — | 设备列表 | — | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 区域树 | /api/v1/inspection-areas/tree | GET | 树形结构 | +| 新增 | /api/v1/inspection-areas | POST | — | +| 编辑 | /api/v1/inspection-areas/{id} | PUT | — | +| 删除 | /api/v1/inspection-areas/{id} | DELETE | — | + +--- + +## 页面6:数据补录与补录审核页 + +**页面编号**:PR-I-06-P01 / PR-I-07-P01 +**端侧归属**:Web专属 +**页面路径**:/inspection/supplement + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 审核状态 | 下拉单选 | 否 | 全部 | 待审核/已通过/已驳回 | +| 补录人 | 文本输入 | 否 | — | 模糊匹配 | +| 补录原因 | 下拉单选 | 否 | 全部 | 蓝牙故障/系统异常/定位失败/其他 | +| 日期范围 | 日期范围 | 否 | — | — | + +### 补录数据标记规范 + +| 标记项 | 说明 | +|--------|------| +| is_supplement | true | +| supplement_reason | 蓝牙故障/系统异常/定位失败/其他 | +| supplement_remark | 补录详细说明 | +| supplement_audit_status | 待审核/通过/驳回 | +| supplement_auditor | 审核人ID | +| supplement_audit_time | 审核时间 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 审核 | inspection:supplement:approve | 行操作 | 审核状态=待审核 | 通过/驳回弹窗 | +| 查看 | inspection:supplement:view | 行操作 | 始终 | 查看补录详情 | + +### 通知触发 + +| 触发操作 | 通知对象 | 通知方式 | 消息模板 | 文档来源 | +|----------|----------|----------|----------|----------| +| 审核通过 | 补录人 | 小程序推送 | 补录审核通过通知 | 03-物业公司 §2.2 | +| 审核驳回 | 补录人 | 小程序推送 | 补录审核驳回通知,需重新执行 | 03-物业公司 §2.2 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 补录列表 | /api/v1/inspection-records/supplements | GET | 分页查询 | +| 审核 | /api/v1/inspection-records/supplements/{id}/approve | POST | — | + +--- + +## 需求追溯 + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| PR-I-01 | 巡检计划管理 | 02-物业公司 §2 / 03-物业公司 §2.1 | 计划创建→自动生成每日任务 | 巡检任务看板 | +| PR-I-02 | 巡检任务看板 | 02-物业公司 §2 / 03-物业公司 §2.1 | — | 小程序端今日巡检(MP-I-01) | +| PR-I-03 | 巡检记录查询 | 02-物业公司 §2 / 03-物业公司 §2.1 | — | 统计报表→巡检统计 | +| PR-I-04 | 异常处理跟踪 | 02-物业公司 §2 / 03-物业公司 §2.1 | 异常→一键生成报修工单 | 在线报修(工单创建) | +| PR-I-05 | 巡检区域管理 | 02-物业公司 §2 | 区域→蓝牙Beacon绑定 | 系统配置→蓝牙设备管理 | +| PR-I-06 | 数据补录 | 02-物业公司 §2 / 03-物业公司 §2.2 | 补录→审核→生效 | 小程序端异常数据补录(MP-I-06) | +| PR-I-07 | 补录审核 | 02-物业公司 §2 / 03-物业公司 §2.2 | 审核结果→通知补录人 | 操作日志→补录日志 | + +## 业务规则 + +1. **任务自动生成**:巡检计划创建后,系统按频次自动生成每日巡检任务(来源:03-物业公司 §2.1) +2. **蓝牙打卡**:小程序端巡检必须连接蓝牙Beacon后才可打卡和拍照(策略=REQUIRED时),失败进入补录模式(来源:01 §9 / 06 §4.4) +3. **蓝牙双模式**:策略=OPTIONAL时允许手动打卡(check_type=MANUAL),无需补录审核(来源:06 §4.4 / 03-物业公司 §10) +4. **异常上报→工单**:巡检发现异常可一键生成报修工单,触发INSPECTION_ABNORMAL事件(来源:05 §5.2 / 03-物业公司 §2.1) +5. **补录审核流程**:补录数据需主管审核,审核通过生效,驳回需重新执行(来源:03-物业公司 §2.2) +6. **补录数据标记**:所有补录记录标记is_supplement=true,补录原因、审核状态等完整记录(来源:03-物业公司 §2.3) +7. **数据权限**:主管仅看本班组数据,员工仅看本人数据(来源:01 §1.3) diff --git a/docs/02-功能清单-物业公司/03-保洁管理.md b/docs/02-功能清单-物业公司/03-保洁管理.md new file mode 100644 index 0000000..72e67c4 --- /dev/null +++ b/docs/02-功能清单-物业公司/03-保洁管理.md @@ -0,0 +1,354 @@ +# 保洁管理 + +> 模块编码:cleaning +> 端侧:Web + 小程序(双端) +> 关联文档:01-模块划分 §3.3 / 02-功能清单-物业公司 §3 / 03-业务流转逻辑-物业公司 §3 / 05-接口规范 §9.2 / 06-项目技术要求 §4.4 + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 保洁管理 | +| 子菜单 | 保洁区域管理、保洁任务看板、人员排班、蓝牙点位管理、超时预警、保洁抽查、数据补录 | +| 功能编号 | PR-C-01 ~ PR-C-08 | +| 权限编码前缀 | cleaning:area:* / cleaning:task:* / cleaning:schedule:* / cleaning:spot-check:* / cleaning:supplement:* | + +--- + +## 页面1:保洁区域管理页 + +**页面编号**:PR-C-01-P01 +**端侧归属**:Web专属 +**页面路径**:/cleaning/areas + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 保洁管理 > 保洁区域管理 │ +├──────────────────────────────────────────────────────────────────┤ +│ [操作栏] [新增区域] │ +├──────────────────────────────────────────────────────────────────┤ +│ [树形+列表] │ +│ ┌──────────────┐ ┌──────────────────────────────────────────┐ │ +│ │ 主院区(项目) │ │ 区域:主院区 > 门诊楼 > 3层 > 公共区域 │ │ +│ │ ├ 门诊楼 │ │ 区域责任人:张三 │ │ +│ │ │ ├ 1层 │ │ 蓝牙Beacon:B-010 (在线) │ │ +│ │ │ │ ├ 大厅 │ │ 当前排班:早班(06:00-14:00) │ │ +│ │ │ │ └ 走廊 │ │ [编辑] [删除]│ │ +│ │ │ ├ 2层 │ └──────────────────────────────────────────┘ │ +│ │ │ └ 3层 │ │ +│ │ └ 住院楼 │ │ +│ └──────────────┘ │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 五级架构 + +| 层级 | 说明 | 示例 | +|------|------|------| +| 项目 | 最顶层 | 主院区 | +| 区域 | 建筑分区 | 门诊楼 | +| 楼栋 | 单独楼 | 1号楼 | +| 楼层 | 楼层 | 3层 | +| 区域责任人 | 最末级+负责人 | 公共区域(张三) | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 新增区域 | cleaning:area:create | 操作栏 | 始终 | 弹窗 | +| 编辑 | cleaning:area:update | 详情区 | 始终 | — | +| 删除 | cleaning:area:delete | 详情区 | 无排班关联时 | 二次确认 | + +### 表单字段(新增/编辑弹窗) + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 区域名称 | 文本输入 | 是 | — | 自填 | 最大30字 | +| 上级区域 | 级联选择 | 是 | — | 区域树 | — | +| 区域责任人 | 下拉单选 | 是 | — | 组织架构-人员 | — | +| 蓝牙Beacon | 下拉单选 | 是 | — | 蓝牙设备管理 | — | +| 保洁清单 | 下拉多选 | 是 | — | 保洁清单模板 | 至少选一个 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 区域树 | /api/v1/cleaning-areas/tree | GET | 五级树形结构 | +| 新增 | /api/v1/cleaning-areas | POST | — | +| 编辑 | /api/v1/cleaning-areas/{id} | PUT | — | +| 删除 | /api/v1/cleaning-areas/{id} | DELETE | — | + +--- + +## 页面2:保洁任务看板页 + +**页面编号**:PR-C-02-P01 +**端侧归属**:Web专属 +**页面路径**:/cleaning/tasks + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 保洁管理 > 保洁任务看板 │ +├──────────────────────────────────────────────────────────────────┤ +│ [看板视图] │ +│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ +│ │ 待执行(5) │ │ 执行中(3) │ │ 已完成(12)│ │ +│ │ ┌──────┐ │ │ ┌──────┐ │ │ ┌──────┐ │ │ +│ │ │门诊1层│ │ │ │门诊3层│ │ │ │门诊2层│ │ │ +│ │ │张三 │ │ │ │李四 │ │ │ │王五 │ │ │ +│ │ │06:00 │ │ │ │06:15 │ │ │ │07:00 │ │ │ +│ │ └──────┘ │ │ └──────┘ │ │ └──────┘ │ │ +│ └──────────┘ └──────────┘ └──────────┘ │ +├──────────────────────────────────────────────────────────────────┤ +│ [查询条件区] │ +│ 日期[____] 班组[▼] 人员[____] 状态[▼] [查询] [重置] │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 日期 | 日期选择 | 否 | 今天 | — | +| 班组 | 下拉单选 | 否 | 全部 | — | +| 人员 | 文本输入 | 否 | — | 模糊匹配 | +| 状态 | 下拉单选 | 否 | 全部 | 待执行/执行中/已完成/超时 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 查看详情 | cleaning:task:view | 卡片/行操作 | 始终 | 跳转任务详情 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 任务列表 | /api/v1/cleaning-tasks | GET | 分页查询+看板数据 | + +--- + +## 页面3:人员排班页 + +**页面编号**:PR-C-03-P01 +**端侧归属**:Web专属 +**页面路径**:/cleaning/schedules + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 保洁管理 > 人员排班 │ +├──────────────────────────────────────────────────────────────────┤ +│ [视图切换] 📅周视图 📆月视图 [◀ 本周 ▶] [复制上周排班] │ +├──────────────────────────────────────────────────────────────────┤ +│ [周视图] │ +│ 区域/人员 | 周一 | 周二 | 周三 | ... | 周日 │ +│ 门诊1层大厅 | 张三早班| 张三早班| 李四早班| ... | 张三早班 │ +│ 门诊2层走廊 | 王五早班| 王五早班| 王五早班| ... | — │ +│ 住院1层 | 李四晚班| 李四晚班| — | ... | 李四晚班 │ +├──────────────────────────────────────────────────────────────────┤ +│ [操作] [保存排班] [清空本周] [导出排班表] │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 复制上周排班 | cleaning:schedule:create | 操作栏 | 始终 | 一键复制上周排班到本周 | +| 保存排班 | cleaning:schedule:update | 操作栏 | 始终 | — | +| 清空本周 | cleaning:schedule:delete | 操作栏 | 始终 | 二次确认 | +| 导出排班表 | cleaning:schedule:export | 操作栏 | 始终 | 导出Excel | + +### 表单字段(排班编辑弹窗) + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 保洁人员 | 下拉单选 | 是 | — | 组织架构-保洁人员 | — | +| 班次 | 下拉单选 | 是 | — | 字典管理-班次 | 早班/晚班/全天 | +| 时间范围 | 时间范围 | 是 | — | 自填 | — | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 排班查询 | /api/v1/cleaning-schedules | GET | 按周/月查询 | +| 保存排班 | /api/v1/cleaning-schedules/batch | POST | 批量保存 | +| 复制排班 | /api/v1/cleaning-schedules/copy | POST | 从指定周复制 | +| 导出 | /api/v1/cleaning-schedules/export | GET | 导出Excel | + +--- + +## 页面4:蓝牙点位管理页 + +**页面编号**:PR-C-04-P01 +**端侧归属**:Web专属 +**页面路径**:/cleaning/beacon-points + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 区域 | 级联选择 | 否 | 全部 | — | +| Beacon状态 | 下拉单选 | 否 | 全部 | 在线/离线 | +| 电量 | 下拉单选 | 否 | 全部 | 正常/低电量 | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | Beacon名称 | 120px | 否 | — | +| 2 | UUID | 180px | 否 | — | +| 3 | 绑定区域 | 150px | 否 | — | +| 4 | 状态 | 80px | 是 | 在线(绿)/离线(红) | +| 5 | 电量 | 80px | 是 | <20%=红色低电量 | +| 6 | 最后心跳 | 140px | 是 | 超过15分钟=离线 | +| 7 | 操作 | 100px | — | 编辑绑定/解绑 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 编辑绑定 | cleaning:area:update | 行操作 | 始终 | 绑定/更换区域 | +| 解绑 | cleaning:area:update | 行操作 | 已绑定 | 二次确认 | + +### 通知触发 + +| 触发操作 | 通知对象 | 通知方式 | 消息模板 | 文档来源 | +|----------|----------|----------|----------|----------| +| Beacon离线 | 物业管理员 | 系统内通知 | Beacon离线预警 | 05 §5.2 (BEACON_OFFLINE) | +| Beacon低电量 | 物业管理员 | 系统内通知 | Beacon低电量预警 | 05 §5.2 (BEACON_LOW_BATTERY) | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/cleaning-beacon-points | GET | — | +| 绑定 | /api/v1/cleaning-beacon-points/{id}/bind | PUT | 绑定区域 | +| 解绑 | /api/v1/cleaning-beacon-points/{id}/unbind | PUT | — | + +--- + +## 页面5:超时预警页 + +**页面编号**:PR-C-05-P01 +**端侧归属**:Web专属 +**页面路径**:/cleaning/timeouts + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 任务区域 | 150px | 否 | — | +| 2 | 保洁人员 | 80px | 否 | — | +| 3 | 计划完成时间 | 140px | 是 | — | +| 4 | 超时时长 | 80px | 是 | 红色标记 | +| 5 | 当前状态 | 100px | 否 | 超时未开始/超时未完成 | +| 6 | 操作 | 100px | — | 催办/查看 | + +### 通知触发 + +| 触发操作 | 通知对象 | 通知方式 | 消息模板 | 文档来源 | +|----------|----------|----------|----------|----------| +| 任务超时 | 物业主管 | 小程序推送 | 保洁超时预警 | 01 §7.1 / 05 §5.2 (CLEANING_TIMEOUT) | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 超时列表 | /api/v1/cleaning-tasks/timeouts | GET | 仅显示超时任务 | + +--- + +## 页面6:保洁抽查页 + +**页面编号**:PR-C-06-P01 +**端侧归属**:Web专属 +**页面路径**:/cleaning/spot-checks + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 抽查结果 | 下拉单选 | 否 | 全部 | 合格/不合格 | +| 抽查人 | 文本输入 | 否 | — | 模糊匹配 | +| 日期范围 | 日期范围 | 否 | — | — | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 任务区域 | 150px | 否 | — | +| 2 | 保洁人员 | 80px | 否 | — | +| 3 | 抽查人 | 80px | 否 | 主管名称 | +| 4 | 抽查时间 | 140px | 是 | 默认倒序 | +| 5 | 抽查结果 | 80px | 否 | 合格(绿)/不合格(红) | +| 6 | 不合格原因 | 150px | 否 | — | +| 7 | 操作 | 100px | — | 标记抽查 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 标记抽查 | cleaning:spot-check:approve | 操作栏 | 始终 | 弹窗选择合格/不合格 | +| 不合格→重新生成 | cleaning:spot-check:approve | 行操作 | 结果=不合格 | 重新生成该区域保洁任务 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 抽查列表 | /api/v1/cleaning-spot-checks | GET | — | +| 标记抽查 | /api/v1/cleaning-spot-checks | POST | — | + +--- + +## 页面7:数据补录与补录审核页 + +**页面编号**:PR-C-07-P01 / PR-C-08-P01 +**端侧归属**:Web专属 +**页面路径**:/cleaning/supplement + +### 补录数据标记规范 + +| 标记项 | 说明 | +|--------|------| +| is_supplement | true | +| supplement_reason | 蓝牙故障/系统异常/定位失败/其他 | +| supplement_audit_status | 待审核/通过/驳回 | +| 统计排除 | 补录数据在统计中单独标记 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 审核 | cleaning:supplement:approve | 行操作 | 审核状态=待审核 | 通过/驳回 | + +--- + +## 需求追溯 + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| PR-C-01 | 保洁区域管理 | 02-物业公司 §3 / 03-物业公司 §3 | 五级架构→排班→任务生成 | 巡检区域管理(复用架构) | +| PR-C-02 | 保洁任务看板 | 02-物业公司 §3 / 03-物业公司 §3 | — | 小程序端今日保洁(MP-CL-01) | +| PR-C-03 | 人员排班 | 02-物业公司 §3 / 03-物业公司 §3 | 排班→自动生成每日任务 | 组织架构→人员管理 | +| PR-C-04 | 蓝牙点位管理 | 02-物业公司 §3 | 区域→Beacon绑定 | 系统配置→蓝牙设备管理 | +| PR-C-05 | 超时预警 | 02-物业公司 §3 / 03-物业公司 §3 | 超时→推送主管 | 通知机制 | +| PR-C-06 | 保洁抽查 | 02-物业公司 §3 / 03-物业公司 §3 | 不合格→重新生成任务 | 小程序端抽查标记(MP-CL-05) | +| PR-C-07 | 数据补录 | 02-物业公司 §3 / 03-物业公司 §2.2 | 补录→审核 | 小程序端异常数据补录(MP-CL-07) | +| PR-C-08 | 补录审核 | 02-物业公司 §3 / 03-物业公司 §2.2 | 审核→通知补录人 | 操作日志→补录日志 | + +## 业务规则 + +1. **五级架构**:项目→区域→楼栋→楼层→区域责任人,最末级必须指定责任人(来源:02-物业公司 PR-C-01) +2. **排班自动生成任务**:根据排班数据自动生成每日保洁任务(来源:03-物业公司 §3) +3. **蓝牙打卡确认**:策略=REQUIRED时必须连接Beacon后才可确认完成,失败进入补录模式(来源:06 §4.4) +4. **蓝牙双模式**:策略=OPTIONAL时允许手动打卡(check_type=MANUAL)(来源:06 §4.4) +5. **超时预警**:任务超过计划完成时间未完成,系统自动预警推送主管(来源:02-物业公司 PR-C-05 / 03-物业公司 §3) +6. **抽查不合格**:主管标记不合格后,系统自动重新生成该区域保洁任务(来源:03-物业公司 §3) +7. **补录流程**:与巡检一致,补录需主管审核(来源:03-物业公司 §2.2) diff --git a/docs/02-功能清单-物业公司/04-组织架构.md b/docs/02-功能清单-物业公司/04-组织架构.md new file mode 100644 index 0000000..1d3bbe5 --- /dev/null +++ b/docs/02-功能清单-物业公司/04-组织架构.md @@ -0,0 +1,338 @@ +# 组织架构 + +> 模块编码:org +> 端侧:Web + 小程序(双端) +> 关联文档:01-模块划分 §3.4 / 02-功能清单-物业公司 §4 / 03-业务流转逻辑-物业公司 §4 / 05-接口规范 §9.2 + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 组织架构 | +| 子菜单 | 班组管理、人员管理、人员分配、排班管理、技能管理、打卡点分配、下属账号管理 | +| 功能编号 | PR-O-01 ~ PR-O-11 | +| 权限编码前缀 | org:team:* / org:staff:* | + +--- + +## 页面1:班组管理页 + +**页面编号**:PR-O-01-P01 +**端侧归属**:Web专属 +**页面路径**:/org/teams + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 组织架构 > 班组管理 │ +├──────────────────────────────────────────────────────────────────┤ +│ [查询条件区] │ +│ 班组名称[____] 班组类型[▼] 状态[▼] [查询] [重置] │ +├──────────────────────────────────────────────────────────────────┤ +│ [操作栏] [新增班组] │ +├──────────────────────────────────────────────────────────────────┤ +│ [列表区] │ +│ 序号| 班组名称 | 类型 | 班组长 | 人数 | 负责区域 | 状态 | 操作 │ +│ 1 | 水电维修班| 维修 | 张三 | 8 | 门诊楼 | 启用 | 编辑 停用│ +│ 2 | 巡检一班 | 巡检 | 李四 | 5 | 全院 | 启用 | 编辑 停用│ +│ 3 | 保洁早班 | 保洁 | 王五 | 12 | 门诊+住院| 启用 | 编辑 停用│ +├──────────────────────────────────────────────────────────────────┤ +│ [分页] 共10条 │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 表单字段(新增/编辑弹窗) + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 班组名称 | 文本输入 | 是 | — | 自填 | 最大30字,同租户唯一 | +| 班组类型 | 下拉单选 | 是 | — | 字典管理-班组类型 | 维修/巡检/保洁/综合 | +| 班组长 | 下拉单选 | 是 | — | 人员列表 | — | +| 负责区域 | 级联多选 | 否 | — | 区域五级架构 | — | +| 描述 | 多行文本 | 否 | — | 自填 | 最大200字 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 新增班组 | org:team:create | 操作栏 | 始终 | — | +| 编辑 | org:team:update | 行操作 | 始终 | — | +| 停用 | org:team:update | 行操作 | 始终 | 有未完成任务时不可停用 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/teams | GET | — | +| 新增 | /api/v1/teams | POST | — | +| 编辑 | /api/v1/teams/{id} | PUT | — | + +--- + +## 页面2:人员管理页 + +**页面编号**:PR-O-02-P01 +**端侧归属**:Web专属 +**页面路径**:/org/staffs + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 姓名 | 文本输入 | 否 | — | 模糊匹配 | +| 所属班组 | 下拉单选 | 否 | 全部 | — | +| 技能标签 | 下拉多选 | 否 | 全部 | — | +| 状态 | 下拉单选 | 否 | 全部 | 在职/离职 | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 姓名 | 80px | 否 | — | +| 2 | 手机号 | 120px | 否 | 脱敏显示 | +| 3 | 所属班组 | 120px | 是 | 支持一人多班组,逗号分隔 | +| 4 | 技能标签 | 150px | 否 | 标签样式 | +| 5 | 角色 | 100px | 否 | 下属账号角色 | +| 6 | 状态 | 80px | 是 | 在职/离职 | +| 7 | 操作 | 160px | — | 编辑/分配/查看排班 | + +### 表单字段(新增/编辑弹窗) + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 姓名 | 文本输入 | 是 | — | 自填 | 最大20字 | +| 手机号 | 文本输入 | 是 | — | 自填 | 手机号格式 | +| 所属班组 | 下拉多选 | 是 | — | 班组列表 | 支持一人多班组 | +| 技能标签 | 下拉多选 | 否 | — | 技能管理 | — | +| 入职日期 | 日期选择 | 否 | — | 自填 | — | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 新增人员 | org:staff:create | 操作栏 | 始终 | — | +| 编辑 | org:staff:update | 行操作 | 始终 | — | +| 分配 | org:staff:update | 行操作 | 始终 | 分配到班组/区域 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/staffs | GET | — | +| 新增 | /api/v1/staffs | POST | — | +| 编辑 | /api/v1/staffs/{id} | PUT | — | + +--- + +## 页面3:排班管理页 + +**页面编号**:PR-O-04-P01 +**端侧归属**:Web专属 +**页面路径**:/org/schedules + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 组织架构 > 排班管理 │ +├──────────────────────────────────────────────────────────────────┤ +│ [视图切换] 📅周视图 📆月视图 班组:[▼] [◀ 本周 ▶] │ +├──────────────────────────────────────────────────────────────────┤ +│ [周视图] │ +│ 人员 | 周一 | 周二 | 周三 | 周四 | 周五 | 周六 | 周日│ +│ 张三 | 早班 | 早班 | 晚班 | 早班 | 早班 | 休息 | 休息│ +│ 李四 | 晚班 | 晚班 | 早班 | 晚班 | 晚班 | 休息 | 休息│ +├──────────────────────────────────────────────────────────────────┤ +│ [操作] [保存] [批量排班] [模板排班] [导出] │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 批量排班 | org:team:create | 操作栏 | 始终 | 选择多人同一班次 | +| 模板排班 | org:team:create | 操作栏 | 始终 | 从已有模板加载 | +| 保存 | org:team:update | 操作栏 | 始终 | — | +| 导出 | org:team:export | 操作栏 | 始终 | 导出排班表 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 排班查询 | /api/v1/team-schedules | GET | — | +| 保存 | /api/v1/team-schedules/batch | POST | — | + +--- + +## 页面4:技能管理页 + +**页面编号**:PR-O-05-P01 +**端侧归属**:Web专属 +**页面路径**:/org/skills + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 技能名称 | 150px | 否 | 如:水电维修、空调维修 | +| 2 | 关联班组 | 150px | 否 | 使用该技能的班组 | +| 3 | 持有人员数 | 100px | 是 | — | +| 4 | 操作 | 100px | — | 编辑/删除 | + +### 表单字段(新增/编辑弹窗) + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 技能名称 | 文本输入 | 是 | — | 自填 | 最大30字,同租户唯一 | +| 关联班组 | 下拉多选 | 否 | — | 班组列表 | — | +| 描述 | 多行文本 | 否 | — | 自填 | 最大200字 | + +--- + +## 页面5:打卡点分配页 + +**页面编号**:PR-O-06-P01 +**端侧归属**:Web专属 +**页面路径**:/org/check-in-points + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 班组 | 120px | 否 | — | +| 2 | 打卡点名称 | 150px | 否 | — | +| 3 | 位置 | 150px | 否 | — | +| 4 | 蓝牙Beacon | 120px | 否 | — | +| 5 | 适用角色 | 100px | 否 | 全部/主管/员工 | +| 6 | 操作 | 100px | — | 编辑/删除 | + +### 表单字段(新增/编辑弹窗) + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 打卡点名称 | 文本输入 | 是 | — | 自填 | 最大30字 | +| 适用班组 | 下拉单选 | 是 | — | 班组列表 | — | +| 位置描述 | 文本输入 | 是 | — | 自填 | — | +| 蓝牙Beacon | 下拉单选 | 是 | — | 蓝牙设备管理 | — | +| 适用角色 | 下拉多选 | 是 | 全部 | 固定选项 | — | + +--- + +## 页面6:下属账号管理页 + +**页面编号**:PR-O-07-P01 +**端侧归属**:Web专属 +**页面路径**:/org/subordinates + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 组织架构 > 下属账号管理 │ +├──────────────────────────────────────────────────────────────────┤ +│ [查询条件区] │ +│ 姓名[____] 班组[▼] 角色[▼] 状态[▼] [查询] [重置] │ +├──────────────────────────────────────────────────────────────────┤ +│ [操作栏] [新增下属] [批量分配角色] [批量启停] │ +├──────────────────────────────────────────────────────────────────┤ +│ [列表区] │ +│ ☐| 姓名 | 手机号 | 班组 | 角色 | 状态 | 操作 │ +│ ☐| 张三 | 138****12| 水电班 | 主管 | 启用 | 编辑 角色 权限 启停│ +│ ☐| 李四 | 139****34| 水电班 | 维修员 | 启用 | 编辑 角色 权限 启停│ +├──────────────────────────────────────────────────────────────────┤ +│ [分页] 共50条 每页[20▼] < 1 2 3 > │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 姓名 | 文本输入 | 否 | — | 模糊匹配 | +| 班组 | 下拉单选 | 否 | 全部 | — | +| 角色 | 下拉单选 | 否 | 全部 | 数据来源:超管定义的角色 | +| 状态 | 下拉单选 | 否 | 全部 | 启用/禁用 | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | ☐勾选 | 40px | — | 批量操作用 | +| 2 | 姓名 | 80px | 否 | — | +| 3 | 手机号 | 120px | 否 | 脱敏 | +| 4 | 所属班组 | 120px | 是 | — | +| 5 | 角色 | 120px | 否 | — | +| 6 | 数据权限 | 100px | 否 | 本班组/指定区域 | +| 7 | 状态 | 80px | 是 | — | +| 8 | 操作 | 220px | — | 编辑/分配角色/权限覆盖/启停 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 新增下属 | org:staff:create | 操作栏 | 始终 | 弹窗 | +| 批量分配角色 | permission:user:update | 操作栏 | 勾选≥1条 | 弹窗选择角色 | +| 批量启停 | org:staff:update | 操作栏 | 勾选≥1条 | 二次确认 | +| 编辑 | org:staff:update | 行操作 | 始终 | — | +| 分配角色 | permission:user:update | 行操作 | 始终 | 选择角色 | +| 权限覆盖 | permission:user:update | 行操作 | 始终 | 在角色基础上自定义权限(四级树形) | +| 启停 | org:staff:update | 行操作 | 始终 | 二次确认 | + +### 新增下属弹窗 + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 姓名 | 文本输入 | 是 | — | 自填 | 最大20字 | +| 手机号 | 文本输入 | 是 | — | 自填 | 手机号格式 | +| 所属班组 | 下拉多选 | 是 | — | 班组列表 | — | +| 分配角色 | 下拉单选 | 是 | — | 超管定义的角色列表 | — | +| 是否自定义权限 | 开关 | 否 | 否 | — | 开启后显示四级权限树 | +| 数据权限范围 | 下拉单选 | 是 | 本班组 | 固定选项 | 本班组/指定区域 | + +### 通知触发 + +| 触发操作 | 通知对象 | 通知方式 | 消息模板 | 文档来源 | +|----------|----------|----------|----------|----------| +| 下属账号创建 | 下属人员 | 小程序推送 | 账号开通通知 | 03-物业公司 §4 | +| 角色变更 | 下属人员 | Redis Pub/Sub | 权限实时生效 | 03-物业公司 §4 | +| 账号禁用 | 下属人员 | — | session失效+小程序下线 | 03-物业公司 §4 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/subordinates | GET | — | +| 新增 | /api/v1/subordinates | POST | — | +| 分配角色 | /api/v1/subordinates/{id}/assign-role | PUT | — | +| 权限覆盖 | /api/v1/subordinates/{id}/override-permissions | PUT | 四级树形权限 | +| 批量操作 | /api/v1/subordinates/batch | POST | 批量启停/分配角色 | + +--- + +## 需求追溯 + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| PR-O-01 | 班组管理 | 02-物业公司 §4 | 班组→人员分配→排班 | 巡检管理(巡检班组) / 保洁管理(保洁班组) | +| PR-O-02 | 人员管理 | 02-物业公司 §4 | 人员→技能标签→工单分配 | 在线报修(维修人员) | +| PR-O-03 | 人员分配 | 02-物业公司 §4 | 分配→班组关联 | 班组管理 / 技能管理 | +| PR-O-04 | 排班管理 | 02-物业公司 §4 | 排班→保洁任务生成 | 保洁管理(排班) / 小程序端我的排班(MP-OR-02) | +| PR-O-05 | 技能管理 | 02-物业公司 §4 | 技能→工单自动分配依据 | 在线报修(自动分配) | +| PR-O-06 | 打卡点分配 | 02-物业公司 §4 | 打卡点→考勤蓝牙绑定 | 考勤打卡(打卡点管理) / 系统配置(蓝牙设备) | +| PR-O-07 | 下属账号管理 | 02-物业公司 §4 / 03-物业公司 §4 | 创建下属→分配角色→权限覆盖 | 超管权限管理(角色定义) | +| PR-O-08 | 下属角色分配 | 02-物业公司 §4 | 选择超管定义的角色→分配 | 超管权限管理(角色管理) | +| PR-O-09 | 下属权限覆盖 | 02-物业公司 §4 / 03-物业公司 §4 | 在角色基础上调整权限(四级树形) | 超管权限管理(权限分配) | +| PR-O-10 | 下属批量操作 | 02-物业公司 §4 | 批量启停/分配角色 | — | +| PR-O-11 | 下属数据权限 | 02-物业公司 §4 / 01 §1.3 | 设置数据可见范围 | 数据权限校验 | + +## 业务规则 + +1. **一人多班组**:支持一个人员属于多个班组(来源:02-物业公司 PR-O-02) +2. **下属角色来源于超管**:物业公司管理员从超管定义的角色中选择,分配给下属(来源:03-物业公司 §4 / 01 §8.4) +3. **权限覆盖**:可在角色权限基础上自定义调整,使用四级树形勾选(来源:03-物业公司 §4) +4. **下属不单独设有效期**:随物业公司管理员账号到期而自动失效(来源:01 §1.4) +5. **数据权限**:主管仅看本班组数据,员工仅看本人数据(来源:01 §1.3) +6. **权限实时生效**:角色/权限变更后毫秒级生效,无需重新登录(来源:01 §8.3) +7. **操作日志**:下属创建、角色分配、权限覆盖均记录审计日志(来源:06 §4.5) diff --git a/docs/02-功能清单-物业公司/05-考勤打卡.md b/docs/02-功能清单-物业公司/05-考勤打卡.md new file mode 100644 index 0000000..41fcaac --- /dev/null +++ b/docs/02-功能清单-物业公司/05-考勤打卡.md @@ -0,0 +1,279 @@ +# 考勤打卡 + +> 模块编码:attendance +> 端侧:Web + 小程序(双端) +> 关联文档:01-模块划分 §3.5 / 02-功能清单-物业公司 §5 / 03-业务流转逻辑-物业公司 §5 / 05-接口规范 §9.2 / 06-项目技术要求 §4.4 + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 考勤打卡 | +| 子菜单 | 打卡点管理、打卡规则、考勤记录、异常审核、数据补录 | +| 功能编号 | PR-A-01 ~ PR-A-05 | +| 权限编码前缀 | attendance:point:* / attendance:rule:* / attendance:record:* / attendance:appeal:* / attendance:supplement:* | + +--- + +## 页面1:打卡点管理页 + +**页面编号**:PR-A-01-P01 +**端侧归属**:Web专属 +**页面路径**:/attendance/points + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 考勤打卡 > 打卡点管理 │ +├──────────────────────────────────────────────────────────────────┤ +│ [查询条件区] │ +│ 打卡点名称[____] 所属班组[▼] 状态[▼] [查询] [重置] │ +├──────────────────────────────────────────────────────────────────┤ +│ [操作栏] [新增打卡点] │ +├──────────────────────────────────────────────────────────────────┤ +│ [列表区] │ +│ 序号| 打卡点名称 | 所属班组 | 蓝牙Beacon | Beacon状态 | 操作 │ +│ 1 | 1号楼大厅 | 水电班 | B-001 | 在线 | 编辑 删除 │ +│ 2 | 2号楼入口 | 巡检班 | B-002 | 离线 | 编辑 删除 │ +├──────────────────────────────────────────────────────────────────┤ +│ [分页] 共8条 │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 表单字段(新增/编辑弹窗) + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 打卡点名称 | 文本输入 | 是 | — | 自填 | 最大30字 | +| 所属班组 | 下拉单选 | 是 | — | 班组列表 | — | +| 位置描述 | 文本输入 | 是 | — | 自填 | 最大100字 | +| 蓝牙Beacon | 下拉单选 | 是 | — | 蓝牙设备管理 | — | +| 适用角色 | 下拉多选 | 是 | 全部 | 固定选项 | 全部/主管/员工 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 新增打卡点 | attendance:point:create | 操作栏 | 始终 | — | +| 编辑 | attendance:point:update | 行操作 | 始终 | — | +| 删除 | attendance:point:delete | 行操作 | 无人员关联 | 二次确认 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/attendance-points | GET | — | +| 新增 | /api/v1/attendance-points | POST | — | +| 编辑 | /api/v1/attendance-points/{id} | PUT | — | + +--- + +## 页面2:打卡规则页 + +**页面编号**:PR-A-02-P01 +**端侧归属**:Web专属 +**页面路径**:/attendance/rules + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 考勤打卡 > 打卡规则 │ +├──────────────────────────────────────────────────────────────────┤ +│ [按班组显示规则卡片] │ +│ ┌──────────────────────────────────────────────────────────────┐ │ +│ │ 水电维修班 │ │ +│ │ 上班时间:08:00 上班打卡窗口:07:30~08:30 │ │ +│ │ 下班时间:17:00 下班打卡窗口:16:30~17:30 │ │ +│ │ 迟到规则:>08:00 迟到 >08:30 严重迟到 │ │ +│ │ 早退规则:<17:00 早退 <16:30 严重早退 │ │ +│ │ [编辑] │ │ +│ └──────────────────────────────────────────────────────────────┘ │ +│ ┌──────────────────────────────────────────────────────────────┐ │ +│ │ 巡检一班 │ │ +│ │ ... [编辑] │ │ +│ └──────────────────────────────────────────────────────────────┘ │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 表单字段(编辑弹窗) + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 上班时间 | 时间选择 | 是 | 08:00 | 自填 | — | +| 上班打卡窗口(起) | 时间选择 | 是 | 上班前30分 | 自填 | — | +| 上班打卡窗口(止) | 时间选择 | 是 | 上班后30分 | 自填 | — | +| 下班时间 | 时间选择 | 是 | 17:00 | 自填 | — | +| 下班打卡窗口(起) | 时间选择 | 是 | 下班前30分 | 自填 | — | +| 下班打卡窗口(止) | 时间选择 | 是 | 下班后30分 | 自填 | — | +| 迟到阈值(分钟) | 数字输入 | 是 | 0 | 自填 | ≥0 | +| 严重迟到阈值(分钟) | 数字输入 | 是 | 30 | 自填 | >迟到阈值 | +| 早退阈值(分钟) | 数字输入 | 是 | 0 | 自填 | ≥0 | +| 严重早退阈值(分钟) | 数字输入 | 是 | 30 | 自填 | >早退阈值 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 编辑 | attendance:rule:update | 卡片操作 | 始终 | — | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 规则查询 | /api/v1/attendance-rules | GET | 按班组查询 | +| 保存 | /api/v1/attendance-rules | POST | — | + +--- + +## 页面3:考勤记录页 + +**页面编号**:PR-A-03-P01 +**端侧归属**:Web专属 +**页面路径**:/attendance/records + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 日期 | 日期选择 | 否 | 今天 | — | +| 班组 | 下拉单选 | 否 | 全部 | — | +| 人员 | 文本输入 | 否 | — | 模糊匹配 | +| 打卡状态 | 下拉单选 | 否 | 全部 | 正常/迟到/早退/缺卡/补录 | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 姓名 | 80px | 否 | — | +| 2 | 班组 | 100px | 否 | — | +| 3 | 上班打卡时间 | 120px | 是 | — | +| 4 | 上班打卡方式 | 90px | 否 | 蓝牙/手动/补录 | +| 5 | 上班状态 | 80px | 否 | 正常/迟到/严重迟到 | +| 6 | 下班打卡时间 | 120px | 是 | — | +| 7 | 下班打卡方式 | 90px | 否 | — | +| 8 | 下班状态 | 80px | 否 | 正常/早退/严重早退 | +| 9 | 补录标记 | 70px | 否 | 补录显示"补录"标签 | +| 10 | 操作 | 80px | — | 查看详情 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 查看详情 | attendance:record:view | 行操作 | 始终 | — | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 记录查询 | /api/v1/attendance-records | GET | 分页查询 | + +--- + +## 页面4:异常审核页 + +**页面编号**:PR-A-04-P01 +**端侧归属**:Web专属 +**页面路径**:/attendance/appeals + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 审核状态 | 下拉单选 | 否 | 全部 | 待审核/已通过/已驳回 | +| 申诉人 | 文本输入 | 否 | — | 模糊匹配 | +| 日期范围 | 日期范围 | 否 | — | — | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 申诉人 | 80px | 否 | — | +| 2 | 班组 | 100px | 否 | — | +| 3 | 申诉日期 | 100px | 是 | — | +| 4 | 异常类型 | 100px | 否 | 蓝牙故障/手机异常/系统异常/忘记打卡/其他 | +| 5 | 申诉说明 | 200px | 否 | — | +| 6 | 审核状态 | 90px | 是 | 待审核(黄)/已通过(绿)/已驳回(红) | +| 7 | 操作 | 100px | — | 审核/查看 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 审核 | attendance:appeal:approve | 行操作 | 审核状态=待审核 | 通过/驳回弹窗 | + +### 通知触发 + +| 触发操作 | 通知对象 | 通知方式 | 消息模板 | 文档来源 | +|----------|----------|----------|----------|----------| +| 审核通过 | 申诉人 | 小程序推送 | 申诉通过,系统自动补录打卡 | 03-物业公司 §5 / 03-小程序端 §5.1 | +| 审核驳回 | 申诉人 | 小程序推送 | 申诉未通过 | 03-物业公司 §5 | + +### 蓝牙双模式差异 + +| 元素 | 策略=REQUIRED | 策略=OPTIONAL | +|------|---------------|---------------| +| 打卡方式 | 仅蓝牙打卡 | 蓝牙/手动双按钮 | +| 蓝牙失败 | 提交异常申诉 | 可直接手动打卡(check_method=MANUAL) | +| 异常申诉 | 必须审核 | 无需申诉(手动打卡) | +| 打卡记录标记 | check_method=BLUETOOTH | check_method=MANUAL | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 申诉列表 | /api/v1/attendance-appeals | GET | — | +| 审核 | /api/v1/attendance-appeals/{id}/approve | POST | 通过后自动补录打卡 | + +--- + +## 页面5:数据补录页 + +**页面编号**:PR-A-05-P01 +**端侧归属**:Web专属 +**页面路径**:/attendance/supplement + +### 补录数据标记规范 + +| 标记项 | 说明 | +|--------|------| +| is_supplement | true | +| supplement_reason | 蓝牙故障/系统异常/其他 | +| supplement_audit_status | 待审核/通过/驳回 | +| 自动补录 | 异常申诉审核通过后系统自动补录打卡记录 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 审核 | attendance:supplement:approve | 行操作 | 审核状态=待审核 | — | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 补录列表 | /api/v1/attendance-records/supplements | GET | — | +| 审核 | /api/v1/attendance-records/supplements/{id}/approve | POST | — | + +--- + +## 需求追溯 + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| PR-A-01 | 打卡点管理 | 02-物业公司 §5 / 03-物业公司 §5 | 打卡点→蓝牙绑定→小程序打卡 | 组织架构(打卡点分配) / 系统配置(蓝牙设备) | +| PR-A-02 | 打卡规则 | 02-物业公司 §5 / 03-物业公司 §5 | 规则→迟到早退判定 | — | +| PR-A-03 | 考勤记录 | 02-物业公司 §5 | — | 统计报表→考勤统计 | +| PR-A-04 | 异常审核 | 02-物业公司 §5 / 03-物业公司 §5 | 审核→自动补录打卡 | 小程序端异常申诉(MP-AT-04) | +| PR-A-05 | 数据补录 | 02-物业公司 §5 | 补录→审核 | 操作日志→补录日志 | + +## 业务规则 + +1. **蓝牙强制打卡**:策略=REQUIRED时必须在指定打卡点连接蓝牙后才可打卡(来源:01 §9 / 06 §4.4) +2. **蓝牙双模式**:策略=OPTIONAL时允许手动打卡(check_method=MANUAL)(来源:06 §4.4) +3. **异常申诉流程**:蓝牙失败→提交异常申诉→主管审核→通过后系统自动补录打卡记录(来源:03-物业公司 §5 / 03-小程序端 §5.1) +4. **打卡窗口**:上班/下班各设打卡时间窗口,窗口外打卡标记异常(来源:02-物业公司 PR-A-02) +5. **迟到/早退规则**:可自定义迟到、严重迟到、早退、严重早退的分钟阈值(来源:02-物业公司 PR-A-02) +6. **数据权限**:主管仅看本班组数据,员工仅看本人数据(来源:01 §1.3) +7. **打卡判定**:不判断距离,只要成功连接蓝牙设备即可打卡(来源:06 §5.4) diff --git a/docs/02-功能清单-物业公司/06-服务评价.md b/docs/02-功能清单-物业公司/06-服务评价.md new file mode 100644 index 0000000..137e85c --- /dev/null +++ b/docs/02-功能清单-物业公司/06-服务评价.md @@ -0,0 +1,221 @@ +# 服务评价 + +> 模块编码:evaluation +> 端侧:Web + 小程序(双端) +> 关联文档:01-模块划分 §3.6 / 02-功能清单-物业公司 §6 / 03-业务流转逻辑-物业公司 §6 / 05-接口规范 §9.2 + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 服务评价 | +| 子菜单 | 评价汇总看板、评价列表、评价回复、绩效报表、评价配置 | +| 功能编号 | PR-E-01 ~ PR-E-05 | +| 权限编码前缀 | evaluation:list:* / evaluation:summary:* / evaluation:config:* | + +--- + +## 页面1:评价汇总看板页 + +**页面编号**:PR-E-01-P01 +**端侧归属**:Web专属 +**页面路径**:/evaluation/dashboard + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 服务评价 > 评价汇总看板 │ +├──────────────────────────────────────────────────────────────────┤ +│ [时间选择] 今日 / 本周 / 本月 / 自定义 [起始]~[结束] │ +├──────────────────────────────────────────────────────────────────┤ +│ [统计卡片区] │ +│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ +│ │ 平均评分 │ │ 评价总数 │ │ 待回复数 │ │ 低评分数 │ │ +│ │ 4.2 │ │ 156 │ │ 3 │ │ 5 │ │ +│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ +├──────────────────────────────────────────────────────────────────┤ +│ [图表区] │ +│ ┌────────────────────────┐ ┌────────────────────────┐ │ +│ │ 各模块平均评分(柱状图)│ │ 评分趋势(折线图) │ │ +│ │ 报修:4.3 巡检:4.1 │ │ ← 按月展示趋势 │ │ +│ │ 保洁:4.0 综合:4.2 │ │ │ │ +│ └────────────────────────┘ └────────────────────────┘ │ +│ ┌────────────────────────┐ │ +│ │ 星级分布(饼图) │ │ +│ │ 5星:45% 4星:30% 3星:15%│ │ +│ │ 2星:7% 1星:3% │ │ +│ └────────────────────────┘ │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 导出 | evaluation:summary:view | 页面右上 | 始终 | 导出汇总数据 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 汇总数据 | /api/v1/evaluations/summary | GET | 含统计卡片+图表数据 | + +--- + +## 页面2:评价列表页 + +**页面编号**:PR-E-02-P01 +**端侧归属**:Web专属 +**页面路径**:/evaluation/list + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 评价类型 | 下拉单选 | 否 | 全部 | 报修服务/巡检服务/保洁服务/综合评价 | +| 评分 | 下拉单选 | 否 | 全部 | 1分/2分/3分/4分/5分 | +| 回复状态 | 下拉单选 | 否 | 全部 | 已回复/未回复 | +| 日期范围 | 日期范围 | 否 | — | — | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 评价类型 | 90px | 否 | 标签样式 | +| 2 | 关联服务 | 150px | 否 | 工单号/巡检任务/保洁任务 | +| 3 | 评分 | 80px | 是 | 星级展示,低分红色标记 | +| 4 | 评价人 | 80px | 否 | — | +| 5 | 评价内容 | 200px | 否 | — | +| 6 | 评价时间 | 140px | 是 | 默认倒序 | +| 7 | 回复状态 | 80px | 否 | 已回复(绿)/未回复(红) | +| 8 | 操作 | 100px | — | 查看详情/回复 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 查看详情 | evaluation:list:view | 行操作 | 始终 | 弹窗 | +| 回复 | evaluation:list:update | 行操作 | 未回复或低分 | 弹窗填写回复 | + +### 角色差异化视图 + +| 角色 | 可见按钮 | 数据范围 | 备注 | +|------|----------|----------|------| +| 物业管理员 | 查看、回复 | 本公司全部评价 | — | +| 主管 | 查看、回复 | 本班组相关评价 | — | + +### 通知触发 + +| 触发操作 | 通知对象 | 通知方式 | 消息模板 | 文档来源 | +|----------|----------|----------|----------|----------| +| 低评分评价(≤2分) | 物业主管 | 小程序推送 | 低评分评价通知 | 01 §7.1 / 05 §5.2 (LOW_SCORE_EVALUATION) | +| 回复完成 | 评价人(医院) | — | 评价已回复 | 03-物业公司 §6 | + +### 低评分评价处理规则 + +| 评分 | 含义 | 物业端触发动作 | 文档来源 | +|------|------|----------------|----------| +| 5分 | 非常满意 | — | 03-物业公司 §6 | +| 4分 | 满意 | — | 03-物业公司 §6 | +| 3分 | 一般 | 主管关注 | 03-物业公司 §6 | +| 2分 | 不满意 | 自动通知主管,要求回复 | 03-物业公司 §6 | +| 1分 | 非常不满意 | 通知主管+管理员,24h内必须回复 | 03-物业公司 §6 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/evaluations | GET | 分页查询 | +| 回复 | /api/v1/evaluations/{id}/reply | POST | — | + +--- + +## 页面3:绩效报表页 + +**页面编号**:PR-E-04-P01 +**端侧归属**:Web专属 +**页面路径**:/evaluation/performance + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 时间维度 | 下拉单选 | 是 | 本月 | 天/周/月/年/自定义 | +| 班组 | 下拉单选 | 否 | 全部 | — | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 班组 | 120px | 否 | — | +| 2 | 人员 | 80px | 否 | — | +| 3 | 评价数 | 80px | 是 | — | +| 4 | 平均评分 | 80px | 是 | — | +| 5 | 5星占比 | 80px | 否 | — | +| 6 | 低分(≤2)数 | 80px | 是 | 红色标记 | +| 7 | 回复率 | 80px | 否 | — | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 导出Excel | evaluation:summary:view | 操作栏 | 始终 | — | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 绩效数据 | /api/v1/evaluations/performance | GET | — | +| 导出 | /api/v1/evaluations/performance/export | GET | — | + +--- + +## 页面4:评价配置页 + +**页面编号**:PR-E-05-P01 +**端侧归属**:Web专属 +**页面路径**:/evaluation/config + +### 表单字段 + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 工单完成后自动触发评价 | 开关 | 是 | 开 | — | — | +| 巡检完成后自动触发评价 | 开关 | 是 | 关 | — | — | +| 保洁完成后自动触发评价 | 开关 | 是 | 关 | — | — | +| 低评分阈值 | 数字输入 | 是 | 2 | — | ≤此分数触发通知 | +| 低评分必须回复时限(小时) | 数字输入 | 是 | 24 | — | 仅1分评价 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 保存 | evaluation:config:update | 底部 | 始终 | — | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 查询配置 | /api/v1/evaluation-configs | GET | — | +| 保存 | /api/v1/evaluation-configs | PUT | — | + +--- + +## 需求追溯 + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| PR-E-01 | 评价汇总看板 | 02-物业公司 §6 / 03-物业公司 §6 | — | 统计报表→评价统计 | +| PR-E-02 | 评价列表 | 02-物业公司 §6 / 03-物业公司 §6 | 低分→通知主管 | 通知机制 | +| PR-E-03 | 评价回复 | 02-物业公司 §6 / 03-物业公司 §6 | 回复→通知评价人 | 医院端评价查看(HO-EV-03) | +| PR-E-04 | 绩效报表 | 02-物业公司 §6 | — | 统计报表→评价统计 | +| PR-E-05 | 评价配置 | 02-物业公司 §6 | 配置→自动触发评价规则 | 在线报修(ORDER_COMPLETED事件) | + +## 业务规则 + +1. **评价发起方**:医院账号发起评价,物业公司查看和回复(来源:01 §6.1 / 03-物业公司 §6) +2. **评价触发**:工单完成后自动触发评价(ORDER_COMPLETED事件),可配置其他模块是否触发(来源:05 §5.2 / 03-物业公司 §6) +3. **低评分处理**:2分自动通知主管要求回复,1分通知主管+管理员且24h内必须回复(来源:03-物业公司 §6) +4. **评分等级**:五分制,1=非常不满意,5=非常满意(来源:03-物业公司 §6) +5. **数据权限**:主管仅看本班组相关评价(来源:01 §1.3) diff --git a/docs/02-功能清单-物业公司/07-统计报表.md b/docs/02-功能清单-物业公司/07-统计报表.md new file mode 100644 index 0000000..f24e654 --- /dev/null +++ b/docs/02-功能清单-物业公司/07-统计报表.md @@ -0,0 +1,243 @@ +# 统计报表 + +> 模块编码:statistics +> 端侧:Web专属 +> 关联文档:01-模块划分 §3.7 / 02-功能清单-物业公司 §7 / 03-业务流转逻辑-物业公司 §7 / 05-接口规范 §9.2 + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 统计报表 | +| 子菜单 | 报修统计、巡检统计、保洁统计、评价统计、考勤统计、综合看板、自定义报表 | +| 功能编号 | PR-ST-01 ~ PR-ST-07 | +| 权限编码前缀 | statistics:repair:* / statistics:inspection:* / statistics:cleaning:* / statistics:evaluation:* / statistics:attendance:* / statistics:dashboard:* / statistics:custom:* | + +--- + +## 页面1:报修统计页 + +**页面编号**:PR-ST-01-P01 +**端侧归属**:Web专属 +**页面路径**:/statistics/repair + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 统计报表 > 报修统计 │ +├──────────────────────────────────────────────────────────────────┤ +│ [时间选择] 今天 / 本周 / 本月 / 本年 / 自定义 [起始]~[结束] │ +│ [筛选] 班组[▼] 区域[▼] 紧急程度[▼] │ +├──────────────────────────────────────────────────────────────────┤ +│ [统计卡片区] │ +│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │ +│ │总工单│ │待分配│ │处理中│ │已完成│ │已关闭│ │完成率│ │ +│ │ 156 │ │ 12 │ │ 23 │ │ 108 │ │ 13 │ │ 69% │ │ +│ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ │ +├──────────────────────────────────────────────────────────────────┤ +│ [图表区] │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ │ +│ │ 工单趋势(折线图) │ │ 类型分布(饼图) │ │ +│ └─────────────────────────┘ └─────────────────────────┘ │ +│ ┌─────────────────────────┐ │ +│ │ 班组工单量排名(柱状图) │ │ +│ └─────────────────────────┘ │ +├──────────────────────────────────────────────────────────────────┤ +│ [数据表格] │ +│ 班组 | 总工单 | 已完成 | 完成率 | 平均处理时长 | 评分 │ +│ 水电班 | 56 | 42 | 75% | 4.2小时 | 4.3 │ +│ 木工班 | 32 | 28 | 87% | 3.8小时 | 4.5 │ +├──────────────────────────────────────────────────────────────────┤ +│ [操作] [导出Excel] [导出PDF] │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 导出Excel | statistics:repair:export | 操作栏 | 始终 | — | +| 导出PDF | statistics:repair:export | 操作栏 | 始终 | — | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 统计数据 | /api/v1/statistics/repair | GET | 含卡片+图表+表格 | +| 导出 | /api/v1/statistics/repair/export | GET | 支持Excel/PDF | + +--- + +## 页面2:巡检统计页 + +**页面编号**:PR-ST-02-P01 +**端侧归属**:Web专属 +**页面路径**:/statistics/inspection + +### 统计指标 + +| 指标 | 说明 | +|------|------| +| 总巡检任务数 | 统计时间段内任务总数 | +| 完成率 | 已完成/总数 | +| 异常率 | 有异常记录数/已完成数 | +| 补录率 | 补录记录数/总记录数 | +| 蓝牙打卡率 | 蓝牙打卡数/总打卡数 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 导出 | statistics:inspection:export | 操作栏 | 始终 | — | + +--- + +## 页面3:保洁统计页 + +**页面编号**:PR-ST-03-P01 +**端侧归属**:Web专属 +**页面路径**:/statistics/cleaning + +### 统计指标 + +| 指标 | 说明 | +|------|------| +| 总保洁任务数 | — | +| 完成率 | — | +| 超时率 | 超时任务数/总数 | +| 抽查合格率 | 抽查合格数/抽查总数 | +| 补录率 | — | + +--- + +## 页面4:评价统计页 + +**页面编号**:PR-ST-04-P01 +**端侧归属**:Web专属 +**页面路径**:/statistics/evaluation + +### 统计指标 + +| 指标 | 说明 | +|------|------| +| 总评价数 | — | +| 平均评分 | — | +| 各模块评分对比 | 报修/巡检/保洁/综合 | +| 低评分占比 | ≤2分评价占比 | +| 回复率 | 已回复/总评价数 | + +--- + +## 页面5:考勤统计页 + +**页面编号**:PR-ST-05-P01 +**端侧归属**:Web专属 +**页面路径**:/statistics/attendance + +### 统计指标 + +| 指标 | 说明 | +|------|------| +| 出勤率 | 实际打卡人数/应打卡人数 | +| 迟到率 | 迟到人数/实际打卡人数 | +| 早退率 | — | +| 异常申诉率 | 申诉数/总打卡次数 | +| 蓝牙打卡率 | 蓝牙打卡数/总打卡数 | + +--- + +## 页面6:综合看板页 + +**页面编号**:PR-ST-06-P01 +**端侧归属**:Web专属 +**页面路径**:/statistics/dashboard + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 统计报表 > 综合看板 │ +├──────────────────────────────────────────────────────────────────┤ +│ [时间选择] 今天 / 本周 / 本月 / 自定义 │ +├──────────────────────────────────────────────────────────────────┤ +│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │ +│ │报修 │ │巡检 │ │保洁 │ │考勤 │ │ +│ │完成率│ │完成率│ │完成率│ │出勤率│ │ +│ │ 69% │ │ 92% │ │ 85% │ │ 96% │ │ +│ └──────┘ └──────┘ └──────┘ └──────┘ │ +│ ┌──────┐ ┌──────┐ │ +│ │评价 │ │待处理│ │ +│ │均分 │ │工单 │ │ +│ │ 4.2 │ │ 12 │ │ +│ └──────┘ └──────┘ │ +├──────────────────────────────────────────────────────────────────┤ +│ [趋势图] 各模块指标趋势对比 │ +└──────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 页面7:自定义报表页 + +**页面编号**:PR-ST-07-P01 +**端侧归属**:Web专属 +**页面路径**:/statistics/custom + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 统计报表 > 自定义报表 │ +├──────────────────────────────────────────────────────────────────┤ +│ [配置区] │ +│ 数据源:[▼多选] (报修/巡检/保洁/评价/考勤) │ +│ 维度:[▼多选] (时间/班组/区域/人员/类型) │ +│ 指标:[▼多选] (数量/完成率/平均时长/评分...) │ +│ 时间范围:[起始]~[结束] │ +│ 筛选条件:[动态添加] │ +├──────────────────────────────────────────────────────────────────┤ +│ [操作] [生成报表] [保存模板] [导出] │ +├──────────────────────────────────────────────────────────────────┤ +│ [结果展示区] │ +│ 图表 + 数据表格 │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 生成报表 | statistics:custom:view | 操作栏 | 始终 | — | +| 保存模板 | statistics:custom:create | 操作栏 | 始终 | 保存当前配置为模板 | +| 导出 | statistics:custom:export | 操作栏 | 已生成报表 | — | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 生成报表 | /api/v1/statistics/custom | POST | 自定义维度+指标 | +| 保存模板 | /api/v1/statistics/custom/templates | POST | — | +| 导出 | /api/v1/statistics/custom/export | GET | — | + +--- + +## 需求追溯 + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| PR-ST-01 | 报修统计 | 02-物业公司 §7 / 03-物业公司 §7 | — | 在线报修(数据源) | +| PR-ST-02 | 巡检统计 | 02-物业公司 §7 / 03-物业公司 §7 | — | 巡检管理(数据源) | +| PR-ST-03 | 保洁统计 | 02-物业公司 §7 / 03-物业公司 §7 | — | 保洁管理(数据源) | +| PR-ST-04 | 评价统计 | 02-物业公司 §7 / 03-物业公司 §7 | — | 服务评价(数据源) | +| PR-ST-05 | 考勤统计 | 02-物业公司 §7 / 03-物业公司 §7 | — | 考勤打卡(数据源) | +| PR-ST-06 | 综合看板 | 02-物业公司 §7 | — | 全部模块(数据源) | +| PR-ST-07 | 自定义报表 | 02-物业公司 §7 | — | 全部模块(数据源) | + +## 业务规则 + +1. **时间维度**:支持天/周/月/年/自定义时间段查询(来源:02-物业公司 §7) +2. **导出格式**:支持Excel和PDF导出(来源:02-物业公司 §7) +3. **数据权限**:物业公司管理员看本公司绑定医院数据,主管看本班组数据(来源:01 §1.3) +4. **补录数据标记**:统计报表中补录数据单独标记,可筛选排除(来源:03-物业公司 §2.3) +5. **导出日志**:每次导出操作记录审计日志(来源:06 §4.5) diff --git a/docs/02-功能清单-物业公司/08-操作日志.md b/docs/02-功能清单-物业公司/08-操作日志.md new file mode 100644 index 0000000..d8aef56 --- /dev/null +++ b/docs/02-功能清单-物业公司/08-操作日志.md @@ -0,0 +1,200 @@ +# 操作日志 + +> 模块编码:audit-log +> 端侧:Web专属 +> 关联文档:01-模块划分 §3.8 / 02-功能清单-物业公司 §8 / 03-业务流转逻辑-物业公司 §8 / 05-接口规范 §9.2 / 06-项目技术要求 §4.5 + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 操作日志 | +| 子菜单 | 日志时间轴、日志列表、日志详情、日志导出、数据补录日志 | +| 功能编号 | PR-AL-01 ~ PR-AL-05 | +| 权限编码前缀 | audit-log:list:* / audit-log:supplement:view | + +--- + +## 页面1:日志时间轴页 + +**页面编号**:PR-AL-01-P01 +**端侧归属**:Web专属 +**页面路径**:/audit-log/timeline + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 操作日志 > 日志时间轴 │ +├──────────────────────────────────────────────────────────────────┤ +│ [查询条件区] │ +│ 模块[▼] 操作人[____] 日期[起始]~[结束] [查询] [重置] │ +├──────────────────────────────────────────────────────────────────┤ +│ [时间轴视图] │ +│ ┃ 2026-04-16 10:30:25 张三 提交了报修工单 #WX20260416001 │ +│ ┃ [查看详情] │ +│ ┃ 2026-04-16 10:15:10 李四 审批通过了延期申请 #DQ20260416003 │ +│ ┃ [查看详情] │ +│ ┃ 2026-04-16 09:45:00 王五 完成了巡检打卡 门诊楼1层 │ +│ ┃ [查看详情] │ +│ ┃ 2026-04-16 09:00:12 赵六 上班打卡 1号楼大厅 │ +│ ▼ [查看详情] │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 模块 | 下拉单选 | 否 | 全部 | 报修/巡检/保洁/考勤/评价/组织架构/系统配置 | +| 操作人 | 文本输入 | 否 | — | 模糊匹配 | +| 日期范围 | 日期范围 | 否 | 今天 | — | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 查看详情 | audit-log:list:view | 时间轴节点 | 始终 | 弹窗展示完整信息 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 时间轴查询 | /api/v1/audit-logs/timeline | GET | — | + +--- + +## 页面2:日志列表页 + +**页面编号**:PR-AL-02-P01 +**端侧归属**:Web专属 +**页面路径**:/audit-log/list + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 模块 | 下拉单选 | 否 | 全部 | — | +| 操作人 | 文本输入 | 否 | — | 模糊匹配 | +| 操作类型 | 下拉多选 | 否 | 全部 | 查看/新增/编辑/删除/审批/导出/分配 | +| 日期范围 | 日期范围 | 否 | 今天 | — | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 操作时间 | 150px | 是 | 默认倒序 | +| 2 | 操作人 | 80px | 否 | — | +| 3 | 模块 | 80px | 否 | — | +| 4 | 操作类型 | 80px | 否 | 彩色标签 | +| 5 | 操作内容 | 250px | 否 | — | +| 6 | 响应状态 | 80px | 否 | 成功(绿)/失败(红) | +| 7 | 操作 | 80px | — | 查看详情 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 查看详情 | audit-log:list:view | 行操作 | 始终 | 弹窗 | + +### 日志详情弹窗 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ 操作日志详情 [×] │ +├──────────────────────────────────────────────────────────────────┤ +│ 操作人:张三(水电维修班) │ +│ 操作时间:2026-04-16 10:30:25 │ +│ 操作IP:192.168.1.100 │ +│ 操作模块:在线报修 → 工单列表 → 工单管理 → 新增 │ +│ 操作内容:提交报修工单 #WX20260416001 │ +│ 变更前数据:(无,新增操作) │ +│ 变更后数据:{ "id": "WX20260416001", "type": "水电", ... } │ +│ 请求参数:{ "type": "水电", "description": "3楼灯管不亮", ... } │ +│ 响应状态:成功 │ +├──────────────────────────────────────────────────────────────────┤ +│ [关闭] │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/audit-logs | GET | 分页查询 | +| 详情 | /api/v1/audit-logs/{id} | GET | 含完整信息 | + +--- + +## 页面3:日志导出 + +**页面编号**:PR-AL-04-P01 +**端侧归属**:Web专属 +**页面路径**:导出弹窗 + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 导出Excel | audit-log:list:export | 列表页操作栏 | 始终 | 导出当前筛选结果 | + +--- + +## 页面4:数据补录日志页 + +**页面编号**:PR-AL-05-P01 +**端侧归属**:Web专属 +**页面路径**:/audit-log/supplement + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 模块 | 下拉单选 | 否 | 全部 | 巡检/保洁/考勤 | +| 补录人 | 文本输入 | 否 | — | 模糊匹配 | +| 审核状态 | 下拉单选 | 否 | 全部 | 待审核/通过/驳回 | +| 日期范围 | 日期范围 | 否 | — | — | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 补录时间 | 140px | 是 | 默认倒序 | +| 2 | 补录人 | 80px | 否 | — | +| 3 | 模块 | 80px | 否 | — | +| 4 | 补录原因 | 100px | 否 | 蓝牙故障/系统异常/其他 | +| 5 | 审核状态 | 90px | 否 | — | +| 6 | 审核人 | 80px | 否 | — | +| 7 | 审核时间 | 140px | 否 | — | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 查看详情 | audit-log:supplement:view | 行操作 | 始终 | — | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 补录日志 | /api/v1/audit-logs/supplement | GET | — | + +--- + +## 需求追溯 + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| PR-AL-01 | 日志时间轴 | 02-物业公司 §8 / 03-物业公司 §8.2 | — | — | +| PR-AL-02 | 日志列表 | 02-物业公司 §8 / 03-物业公司 §8.2 | — | — | +| PR-AL-03 | 日志详情 | 02-物业公司 §8 / 03-物业公司 §8.2 | — | — | +| PR-AL-04 | 日志导出 | 02-物业公司 §8 | — | — | +| PR-AL-05 | 数据补录日志 | 02-物业公司 §8 / 03-物业公司 §8.1 | — | 巡检/保洁/考勤补录审核 | + +## 业务规则 + +1. **日志记录范围**:在线报修/巡检管理/保洁管理/考勤打卡/服务评价/组织架构/系统配置(来源:03-物业公司 §8.1) +2. **自动记录**:所有写操作通过AOP切面统一记录,业务代码无感知(来源:06 §4.5) +3. **记录内容**:操作人、时间、IP、模块、操作类型、变更前后数据快照(来源:06 §4.5 / 03-物业公司 §8.2) +4. **日志保留**:至少保留1年,支持导出(来源:06 §4.5) +5. **物业管理员数据范围**:仅查看本公司绑定医院的操作日志(来源:01 §1.3) diff --git a/docs/02-功能清单-物业公司/09-系统配置.md b/docs/02-功能清单-物业公司/09-系统配置.md new file mode 100644 index 0000000..6dc74bc --- /dev/null +++ b/docs/02-功能清单-物业公司/09-系统配置.md @@ -0,0 +1,304 @@ +# 系统配置 + +> 模块编码:system +> 端侧:Web专属 +> 关联文档:01-模块划分 §3.9 / 02-功能清单-物业公司 §9 / 03-业务流转逻辑-物业公司 §9 / 05-接口规范 §9.2 / 06-项目技术要求 §4.4 + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 系统配置 | +| 子菜单 | 蓝牙设备管理、字典管理、微信配置、消息模板、数据补录审核 | +| 功能编号 | PR-S-01 ~ PR-S-05 | +| 权限编码前缀 | device:beacon:* / system:dict:* / system:wechat:* / system:template:* / system:bluetooth-policy:* | + +--- + +## 页面1:蓝牙设备管理页 + +**页面编号**:PR-S-01-P01 +**端侧归属**:Web专属 +**页面路径**:/system/beacons + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 系统配置 > 蓝牙设备管理 │ +├──────────────────────────────────────────────────────────────────┤ +│ [查询条件区] │ +│ Beacon名称[____] 状态[▼] 绑定位置[____] [查询] [重置] │ +├──────────────────────────────────────────────────────────────────┤ +│ [操作栏] [新增Beacon] │ +├──────────────────────────────────────────────────────────────────┤ +│ [列表区] │ +│ 序号| 名称 | UUID | 绑定位置 | 状态 | 电量 | 最后心跳 │ +│ 1 | B-001 | xxxx-xxxx... | 门诊1层 | 在线 | 85% | 10:30 │ +│ 2 | B-002 | xxxx-xxxx... | 住院1层 | 离线 | 12% | 08:15 │ +├──────────────────────────────────────────────────────────────────┤ +│ [分页] 共30条 每页[20▼] < 1 2 > │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| Beacon名称 | 文本输入 | 否 | — | 模糊匹配 | +| 状态 | 下拉单选 | 否 | 全部 | 在线/离线 | +| 绑定位置 | 文本输入 | 否 | — | 模糊匹配 | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 名称 | 100px | 否 | — | +| 2 | UUID | 180px | 否 | — | +| 3 | 绑定位置 | 150px | 否 | 巡检点位/保洁区域/打卡点 | +| 4 | 绑定模块 | 80px | 否 | 巡检/保洁/考勤 | +| 5 | 状态 | 80px | 是 | 在线(绿)/离线(红) | +| 6 | 电量 | 70px | 是 | <20%=红色低电量 | +| 7 | 最后心跳时间 | 140px | 是 | 超过15分钟=离线 | +| 8 | 操作 | 120px | — | 编辑/解绑/删除 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 新增Beacon | device:beacon:create | 操作栏 | 始终 | — | +| 编辑 | device:beacon:update | 行操作 | 始终 | — | +| 解绑 | device:beacon:update | 行操作 | 已绑定 | — | +| 删除 | device:beacon:delete | 行操作 | 未绑定时 | 二次确认 | + +### 表单字段(新增/编辑弹窗) + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| Beacon名称 | 文本输入 | 是 | — | 自填 | 最大30字 | +| UUID | 文本输入 | 是 | — | 自填 | UUID格式 | +| 绑定位置 | 级联选择 | 否 | — | 区域树 | — | +| 绑定模块 | 下拉单选 | 否 | — | 固定选项 | 巡检/保洁/考勤 | +| 电量预警阈值(%) | 数字输入 | 否 | 20 | — | 0~100 | + +### 通知触发 + +| 触发操作 | 通知对象 | 通知方式 | 消息模板 | 文档来源 | +|----------|----------|----------|----------|----------| +| Beacon离线(>15分钟) | 物业管理员 | 系统内通知 | Beacon离线预警 | 05 §5.2 (BEACON_OFFLINE) / 06 §5.4 | +| Beacon低电量(<20%) | 物业管理员 | 系统内通知 | Beacon低电量预警 | 05 §5.2 (BEACON_LOW_BATTERY) | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/beacons | GET | — | +| 新增 | /api/v1/beacons | POST | — | +| 编辑 | /api/v1/beacons/{id} | PUT | — | +| 解绑 | /api/v1/beacons/{id}/unbind | PUT | — | +| 删除 | /api/v1/beacons/{id} | DELETE | — | + +--- + +## 页面2:字典管理页 + +**页面编号**:PR-S-02-P01 +**端侧归属**:Web专属 +**页面路径**:/system/dicts + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 系统配置 > 字典管理 │ +├──────────────────────────────────────────────────────────────────┤ +│ [左侧-字典类型] │ [右侧-字典值] │ +│ ┌──────────────┐ │ ┌──────────────────────────────────────┐ │ +│ │ 报修类型 │◀── │ 序号 | 字典值 | 排序 | 状态 | 操作 │ │ +│ │ 巡检类型 │ │ 1 | 水电 | 1 | 启用 | 编辑 停用│ │ +│ │ 保洁类型 │ │ 2 | 木工 | 2 | 启用 | 编辑 停用│ │ +│ │ 班组类型 │ │ 3 | 空调 | 3 | 停用 | 编辑 启用│ │ +│ │ 班次类型 │ │ │ │ +│ │ [新增类型] │ │ [新增字典值] │ │ +│ └──────────────┘ │ └──────────────────────────────────────┘ │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 新增字典类型 | system:dict:create | 左侧 | 始终 | — | +| 新增字典值 | system:dict:create | 右侧 | 始终 | — | +| 编辑 | system:dict:update | 行操作 | 始终 | — | +| 启用/停用 | system:dict:update | 行操作 | 始终 | 被引用时不可停用 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 字典类型列表 | /api/v1/dict-types | GET | — | +| 字典值列表 | /api/v1/dict-types/{typeCode}/values | GET | — | +| 新增类型 | /api/v1/dict-types | POST | — | +| 新增值 | /api/v1/dict-types/{typeCode}/values | POST | — | + +--- + +## 页面3:微信配置页 + +**页面编号**:PR-S-03-P01 +**端侧归属**:Web专属 +**页面路径**:/system/wechat + +### 表单字段 + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 小程序AppID | 文本输入 | 是 | — | 微信公众平台 | — | +| 小程序AppSecret | 密码输入 | 是 | — | 微信公众平台 | — | +| 公众号AppID | 文本输入 | 否 | — | 微信公众平台 | — | +| 公众号AppSecret | 密码输入 | 否 | — | 微信公众平台 | — | +| 服务器地址(URL) | 文本输入 | 是 | — | 自填 | URL格式 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 保存 | system:wechat:update | 底部 | 始终 | — | +| 测试连接 | system:wechat:view | 底部 | 始终 | 验证配置是否正确 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 查询配置 | /api/v1/system/wechat-config | GET | — | +| 保存 | /api/v1/system/wechat-config | PUT | — | +| 测试连接 | /api/v1/system/wechat-config/test | POST | — | + +--- + +## 页面4:消息模板管理页 + +**页面编号**:PR-S-04-P01 +**端侧归属**:Web专属 +**页面路径**:/system/message-templates + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 模板名称 | 150px | 否 | 如:新工单通知 | +| 2 | 模板ID | 150px | 否 | 微信模板消息ID | +| 3 | 适用场景 | 120px | 否 | 工单分配/催单/审批/超时... | +| 4 | 模板变量 | 200px | 否 | {{工单号}}, {{人员姓名}}... | +| 5 | 状态 | 80px | 否 | 启用/停用 | +| 6 | 操作 | 100px | — | 编辑 | + +### 表单字段(编辑弹窗) + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 模板名称 | 文本输入 | 是 | — | 自填 | 最大50字 | +| 模板ID | 文本输入 | 是 | — | 微信后台 | — | +| 适用场景 | 下拉单选 | 是 | — | 固定选项 | — | +| 模板内容 | 多行文本 | 是 | — | 微信后台复制 | 最大500字 | +| 模板变量说明 | 多行文本 | 否 | — | 自填 | — | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/message-templates | GET | — | +| 编辑 | /api/v1/message-templates/{id} | PUT | — | + +--- + +## 页面5:蓝牙策略配置页 + +**页面编号**:PR-S-05-P01(含数据补录审核) +**端侧归属**:Web专属 +**页面路径**:/system/bluetooth-policy + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 系统配置 > 蓝牙策略配置 │ +├──────────────────────────────────────────────────────────────────┤ +│ [策略配置] │ +│ ┌────────────────────────────────────────────────────────────┐ │ +│ │ 场景 │ 策略 │ 说明 │ │ +│ │ 巡检打卡 │ [▼REQUIRED]│ 必须连接Beacon打卡 │ │ +│ │ 巡检拍照 │ [▼OPTIONAL]│ 可自由拍照 │ │ +│ │ 保洁打卡 │ [▼REQUIRED]│ 必须连接Beacon打卡 │ │ +│ │ 保洁拍照 │ [▼OPTIONAL]│ 可自由拍照 │ │ +│ │ 考勤打卡 │ [▼REQUIRED]│ 必须连接Beacon打卡 │ │ +│ └────────────────────────────────────────────────────────────┘ │ +├──────────────────────────────────────────────────────────────────┤ +│ [保存] [提交审核] │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 策略配置说明 + +| 场景 | 配置项 | 强制蓝牙(REQUIRED) | 非强制(OPTIONAL) | 文档来源 | +|------|--------|-------------------|------------------|----------| +| 巡检打卡 | inspection_check_in | 必须连接Beacon打卡,失败进补录 | 可手动打卡 | 06 §4.4 | +| 巡检拍照 | inspection_photo | 必须在蓝牙连接下拍照 | 可自由拍照 | 06 §4.4 | +| 保洁打卡 | cleaning_check_in | 必须连接Beacon打卡,失败进补录 | 可手动打卡 | 06 §4.4 | +| 保洁拍照 | cleaning_photo | 必须在蓝牙连接下拍照 | 可自由拍照 | 06 §4.4 | +| 考勤打卡 | attendance_check | 必须连接Beacon打卡,失败提交异常申诉 | 可手动打卡 | 06 §4.4 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 保存 | system:bluetooth-policy:update | 底部 | 始终 | 保存草稿 | +| 提交审核 | system:bluetooth-policy:approve | 底部 | 始终 | 提交医院账号审核 | + +### 通知触发 + +| 触发操作 | 通知对象 | 通知方式 | 消息模板 | 文档来源 | +|----------|----------|----------|----------|----------| +| 策略提交审核 | 医院账号 | Web提醒 | 蓝牙策略变更审核 | 06 §4.4 | +| 审核通过 | 物业管理员 | 系统内通知 | 蓝牙策略已生效 | 06 §4.4 | +| 审核拒绝 | 物业管理员 | 系统内通知 | 蓝牙策略审核被拒绝 | 06 §4.4 | + +### 审核流程 + +``` +物业公司配置策略 → 提交审核 → 医院账号审核 + │ + ┌──审核通过──┐ ┌──审核拒绝──┐ + 策略生效 维持原配置 + 通知物业 通知物业 +``` + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 查询策略 | /api/v1/system/bluetooth-policy | GET | — | +| 保存 | /api/v1/system/bluetooth-policy | PUT | — | +| 提交审核 | /api/v1/system/bluetooth-policy/submit | POST | — | + +--- + +## 需求追溯 + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| PR-S-01 | 蓝牙设备管理 | 02-物业公司 §9 / 03-物业公司 §9.1 | Beacon→绑定位置→打卡 | 巡检区域管理 / 保洁区域管理 / 考勤打卡点 | +| PR-S-02 | 字典管理 | 02-物业公司 §9 / 03-物业公司 §9.2 | 字典→各模块下拉选项 | 报修类型管理 / 巡检类型 / 保洁类型 | +| PR-S-03 | 微信配置 | 02-物业公司 §9 | 配置→小程序登录+推送 | 小程序端(登录/通知) | +| PR-S-04 | 消息模板 | 02-物业公司 §9 / 03-物业公司 §9.3 | 模板→微信推送消息 | 通知机制 | +| PR-S-05 | 数据补录审核 | 02-物业公司 §9 | 审核→补录数据生效 | 巡检/保洁/考勤补录 | + +## 业务规则 + +1. **Beacon心跳检测**:每5分钟上报心跳,超过15分钟标记OFFLINE(来源:06 §5.4) +2. **Beacon电量预警**:电量<20%时系统内通知预警(来源:06 §5.4 / 05 §5.2) +3. **字典租户隔离**:字典数据仅对本物业公司(租户)可见(来源:03-物业公司 §9.2) +4. **蓝牙策略审核**:物业公司提交配置→医院账号审核通过后生效,审核拒绝则维持原配置(来源:06 §4.4) +5. **蓝牙打卡判定**:不判断距离,只要成功连接蓝牙设备即可打卡,RSSI > -70dBm(来源:06 §5.4) +6. **消息模板变量**:支持自定义模板变量(工单号、人员姓名、时间等)(来源:03-物业公司 §9.3) diff --git a/docs/02-功能清单-超级管理员.md b/docs/02-功能清单-超级管理员.md new file mode 100644 index 0000000..d8e5667 --- /dev/null +++ b/docs/02-功能清单-超级管理员.md @@ -0,0 +1,56 @@ +# 超级管理员 — 功能点清单 + +> 版本:v4.0 +> 超级管理员负责平台运营,管理账号、权限与系统配置,**不查看业务数据**。 +> 端侧:仅Web端 +> 关联文档:`01-模块划分.md`(v4.0) + +--- + +## 1. 账号管理 + +| 编号 | 功能点 | 说明 | 优先级 | +|------|--------|------|--------| +| SA-A-01 | 医院信息管理 | 创建/编辑医院信息(含多院区:院区名称、地址、联系人) | P0 | +| SA-A-02 | 物业公司信息管理 | 创建/编辑物业公司信息(名称、联系人、联系电话) | P0 | +| SA-A-03 | 医院账号管理 | 创建/编辑/启停医院账号,绑定医院 | P0 | +| SA-A-04 | 物业管理员账号管理 | 创建/编辑/启停物业管理员账号,绑定物业公司+医院 | P0 | +| SA-A-05 | 账号有效期设置 | 创建医院/物业公司账号时设置有效期(到期日),支持修改和手动续期 | P0 | +| SA-A-06 | 账号可用性控制 | 启用/禁用账号,立即生效 | P0 | +| SA-A-07 | 到期账号管理 | 查看即将到期/已过期账号列表,手动续期恢复 | P0 | +| SA-A-08 | 到期提醒规则配置 | 配置账号到期提醒天数阈值(如提前7天、15天、30天) | P0 | + +--- + +## 2. 权限管理 + +| 编号 | 功能点 | 说明 | 优先级 | +|------|--------|------|--------| +| SA-P-01 | 角色定义 | 自定义角色名称和描述(如主管、班组长、巡检员等) | P0 | +| SA-P-02 | 角色权限分配 | 四级树形勾选:功能菜单→页面→功能点→动作(查看/新增/编辑/删除/审批/导出/分配) | P0 | +| SA-P-03 | 角色管理 | 编辑/停用/删除自定义角色 | P0 | +| SA-P-04 | 权限预设模板 | 选择预设模板快速创建角色(物业管理员/主管/维修员/巡检员/保洁员/医院查看模板) | P0 | +| SA-P-05 | 账号角色绑定 | 创建医院/物业账号时分配角色 | P0 | +| SA-P-06 | 权限预览 | 预览角色对应的完整权限清单(四级展开) | P0 | +| SA-P-07 | 权限自动同步 | 后台新增功能菜单/页面/功能点时,权限管理页面自动更新可勾选项 | P0 | +| SA-P-08 | 权限审计日志 | 查看权限变更记录(操作人/时间/变更前后对比) | P0 | +| SA-P-09 | 权限实时生效 | 权限变更后通过Redis Pub/Sub毫秒级生效,无需重新登录 | P0 | +| SA-P-10 | 权限配置注册 | 查看和管理权限配置表(功能菜单/页面/功能点注册) | P0 | + +--- + +## 3. 系统配置 + +| 编号 | 功能点 | 说明 | 优先级 | +|------|--------|------|--------| +| SA-S-01 | 系统版本管理 | 管理后台和小程序版本信息、最低兼容版本 | P0 | +| SA-S-02 | 缓存管理 | 手动清理缓存(全部/按模块),查看缓存状态 | P0 | + +--- + +## 4. 操作日志 + +| 编号 | 功能点 | 说明 | 优先级 | +|------|--------|------|--------| +| SA-L-01 | 权限变更日志 | 专门查看权限变更记录(含变更前后对比) | P0 | +| SA-L-02 | 账号操作日志 | 查看账号创建/启停/续期等操作记录 | P0 | diff --git a/docs/02-功能清单-超级管理员/01-账号管理.md b/docs/02-功能清单-超级管理员/01-账号管理.md new file mode 100644 index 0000000..5658bba --- /dev/null +++ b/docs/02-功能清单-超级管理员/01-账号管理.md @@ -0,0 +1,588 @@ +# 账号管理 + +> 模块编码:account +> 端侧:Web专属(仅超级管理员) +> 关联文档:01-模块划分 §1.1~1.4 / 02-功能清单-超级管理员 §1 / 03-业务流转逻辑-超级管理员 §1~3 / 05-接口规范 §9.2 / 06-项目技术要求 §4.1~4.3 + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 账号管理 | +| 子菜单 | 医院信息管理、物业公司信息管理、医院账号管理、物业公司管理员账号管理、到期账号管理、到期提醒规则配置 | +| 功能编号 | SA-A-01 ~ SA-A-08 | +| 权限编码前缀 | permission:user:* / permission:config:* | + +--- + +## 页面1:医院信息管理列表页 + +**页面编号**:SA-A-01-P01 +**端侧归属**:Web专属 +**页面路径**:/account/hospitals + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 账号管理 > 医院信息管理 │ +├──────────────────────────────────────────────────────────────────┤ +│ [查询条件区] │ +│ 医院名称[____] 状态[▼] 联系人[____] [查询] [重置] │ +├──────────────────────────────────────────────────────────────────┤ +│ [操作栏] [新增医院] │ +├──────────────────────────────────────────────────────────────────┤ +│ [列表区] │ +│ 序号 | 医院名称 | 院区数 | 联系人 | 联系电话 | 状态 | 操作 │ +│ 1 | XX医院 | 3 | 张三 | 138****1234| 启用 | 编辑 停用 │ +│ 2 | YY医院 | 1 | 李四 | 139****5678| 停用 | 编辑 启用 │ +├──────────────────────────────────────────────────────────────────┤ +│ [分页] 共50条 每页[20▼] < 1 2 3 > │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 医院名称 | 文本输入 | 否 | — | 模糊匹配 | +| 状态 | 下拉单选 | 否 | 全部 | 启用/停用 | +| 联系人 | 文本输入 | 否 | — | 模糊匹配 | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 序号 | 60px | — | 自增序号 | +| 2 | 医院名称 | 180px | 是 | — | +| 3 | 院区数 | 80px | 否 | 显示关联院区数量,点击展开院区列表 | +| 4 | 联系人 | 100px | 否 | — | +| 5 | 联系电话 | 130px | 否 | 脱敏显示 | +| 6 | 创建时间 | 150px | 是 | 默认倒序 | +| 7 | 状态 | 80px | 是 | 启用(绿色)/停用(红色)标签 | +| 8 | 操作 | 140px | — | 编辑/启停 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 新增医院 | permission:user:create | 操作栏 | 始终 | 跳转新增页 | +| 编辑 | permission:user:update | 行操作 | 始终 | 跳转编辑页 | +| 启用/停用 | permission:user:update | 行操作 | 始终 | 二次确认弹窗 | + +### 角色差异化视图 + +| 角色 | 可见按钮 | 数据范围 | 备注 | +|------|----------|----------|------| +| 超级管理员 | 全部按钮 | 全部医院 | — | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/hospitals | GET | 分页查询 | +| 启用/停用 | /api/v1/hospitals/{id}/toggle-status | PUT | 切换状态 | + +--- + +## 页面2:医院信息新增/编辑页 + +**页面编号**:SA-A-01-P02 +**端侧归属**:Web专属 +**页面路径**:/account/hospitals/create 或 /account/hospitals/:id/edit + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 账号管理 > 医院信息管理 > 新增医院 │ +├──────────────────────────────────────────────────────────────────┤ +│ ── 基本信息 ────────────────────────────────────────────────── │ +│ 医院名称:[____________] 状态:[●启用 ○停用] │ +│ 医院地址:[____________________________] │ +│ 联系人: [__________] 联系电话:[____________] │ +├──────────────────────────────────────────────────────────────────┤ +│ ── 院区信息 ────────────────────────────────────────────────── │ +│ [ + 添加院区 ] │ +│ ┌────────────────────────────────────────────────────────────┐ │ +│ │ 院区1 名称:[主院区] 地址:[____] 联系人:[____] [删除] │ │ +│ │ 院区2 名称:[东院区] 地址:[____] 联系人:[____] [删除] │ │ +│ └────────────────────────────────────────────────────────────┘ │ +├──────────────────────────────────────────────────────────────────┤ +│ [取消] [保存] │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 表单字段(基本信息) + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 医院名称 | 文本输入 | 是 | — | 自填 | 最大50字,全局唯一 | +| 状态 | 单选按钮 | 是 | 启用 | 固定选项 | — | +| 医院地址 | 文本输入 | 否 | — | 自填 | 最大200字 | +| 联系人 | 文本输入 | 否 | — | 自填 | 最大20字 | +| 联系电话 | 文本输入 | 否 | — | 自填 | 手机号格式 | + +### 表单字段(院区信息,支持多条) + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 院区名称 | 文本输入 | 是 | — | 自填 | 最大30字,同医院内唯一 | +| 院区地址 | 文本输入 | 是 | — | 自填 | 最大200字 | +| 联系人 | 文本输入 | 否 | — | 自填 | 最大20字 | + +### 通知触发 + +| 触发操作 | 通知对象 | 通知方式 | 消息模板 | 文档来源 | +|----------|----------|----------|----------|----------| +| 创建医院 | — | — | — | 仅记录操作日志 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 新增医院 | /api/v1/hospitals | POST | 含院区列表 | +| 编辑医院 | /api/v1/hospitals/{id} | PUT | 含院区列表 | +| 查询详情 | /api/v1/hospitals/{id} | GET | 编辑时回填 | + +--- + +## 页面3:物业公司信息管理列表页 + +**页面编号**:SA-A-02-P01 +**端侧归属**:Web专属 +**页面路径**:/account/property-companies + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 账号管理 > 物业公司信息管理 │ +├──────────────────────────────────────────────────────────────────┤ +│ [查询条件区] │ +│ 公司名称[____] 状态[▼] 联系人[____] [查询] [重置] │ +├──────────────────────────────────────────────────────────────────┤ +│ [操作栏] [新增物业公司] │ +├──────────────────────────────────────────────────────────────────┤ +│ [列表区] │ +│ 序号 | 公司名称 | 服务医院 | 联系人 | 联系电话 | 状态 | 操作 │ +│ 1 | XX物业 | A医院 | 王五 | 137****9012| 启用 | 编辑 停用 │ +├──────────────────────────────────────────────────────────────────┤ +│ [分页] 共30条 每页[20▼] < 1 2 > │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 公司名称 | 文本输入 | 否 | — | 模糊匹配 | +| 状态 | 下拉单选 | 否 | 全部 | 启用/停用 | +| 联系人 | 文本输入 | 否 | — | 模糊匹配 | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 序号 | 60px | — | 自增序号 | +| 2 | 公司名称 | 180px | 是 | — | +| 3 | 服务医院 | 150px | 否 | 显示关联医院名称列表 | +| 4 | 联系人 | 100px | 否 | — | +| 5 | 联系电话 | 130px | 否 | 脱敏显示 | +| 6 | 创建时间 | 150px | 是 | 默认倒序 | +| 7 | 状态 | 80px | 是 | 启用/停用标签 | +| 8 | 操作 | 140px | — | 编辑/启停 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 新增物业公司 | permission:user:create | 操作栏 | 始终 | 跳转新增页 | +| 编辑 | permission:user:update | 行操作 | 始终 | — | +| 启用/停用 | permission:user:update | 行操作 | 始终 | 二次确认 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/property-companies | GET | 分页查询 | +| 启用/停用 | /api/v1/property-companies/{id}/toggle-status | PUT | — | + +--- + +## 页面4:物业公司信息新增/编辑页 + +**页面编号**:SA-A-02-P02 +**端侧归属**:Web专属 +**页面路径**:/account/property-companies/create 或 /account/property-companies/:id/edit + +### 表单字段 + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 公司名称 | 文本输入 | 是 | — | 自填 | 最大50字,全局唯一 | +| 公司地址 | 文本输入 | 否 | — | 自填 | 最大200字 | +| 联系人 | 文本输入 | 是 | — | 自填 | 最大20字 | +| 联系电话 | 文本输入 | 是 | — | 自填 | 手机号格式 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 新增 | /api/v1/property-companies | POST | — | +| 编辑 | /api/v1/property-companies/{id} | PUT | — | + +--- + +## 页面5:医院账号管理列表页 + +**页面编号**:SA-A-03-P01 +**端侧归属**:Web专属 +**页面路径**:/account/hospital-accounts + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 账号管理 > 医院账号管理 │ +├──────────────────────────────────────────────────────────────────┤ +│ [查询条件区] │ +│ 登录账号[____] 绑定医院[▼] 状态[▼] 有效期[▼] [查询] [重置] │ +├──────────────────────────────────────────────────────────────────┤ +│ [操作栏] [新增医院账号] │ +├──────────────────────────────────────────────────────────────────┤ +│ [列表区] │ +│ 序号 | 登录账号 | 绑定医院 | 角色 | 有效期至 | 状态 | 操作 │ +│ 1 | hospital01| XX医院 | 医院查看 | 2027-04-16| 正常 | 编辑 续期│ +│ 2 | hospital02| YY医院 | 医院查看 | 2026-03-01| 即将到期| 续期 │ +│ 3 | hospital03| ZZ医院 | 医院查看 | 2026-01-01| 已过期| 续期 │ +├──────────────────────────────────────────────────────────────────┤ +│ [分页] 共20条 每页[20▼] < 1 > │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 登录账号 | 文本输入 | 否 | — | 精确匹配 | +| 绑定医院 | 下拉单选 | 否 | 全部 | 数据来源:医院信息管理 | +| 状态 | 下拉单选 | 否 | 全部 | 正常/即将到期/已过期/已停用 | +| 有效期 | 下拉单选 | 否 | 全部 | 已过期/7天内到期/30天内到期/正常 | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 序号 | 60px | — | 自增 | +| 2 | 登录账号 | 130px | 否 | — | +| 3 | 绑定医院 | 150px | 是 | — | +| 4 | 角色 | 120px | 否 | 显示分配的角色名称 | +| 5 | 有效期至 | 120px | 是 | 即将到期=橙色,已过期=红色 | +| 6 | 状态 | 100px | 是 | 正常(绿)/即将到期(橙)/已过期(红)/已停用(灰) | +| 7 | 操作 | 200px | — | 编辑/续期/启停/重置密码 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 新增医院账号 | permission:user:create | 操作栏 | 始终 | — | +| 编辑 | permission:user:update | 行操作 | 始终 | — | +| 续期 | permission:user:update | 行操作 | 始终 | 修改有效期 | +| 启用/禁用 | permission:user:update | 行操作 | 始终 | 二次确认,禁用立即生效 | +| 重置密码 | permission:user:update | 行操作 | 始终 | 重置为默认密码 | + +### 通知触发 + +| 触发操作 | 通知对象 | 通知方式 | 消息模板 | 文档来源 | +|----------|----------|----------|----------|----------| +| 账号禁用 | 被禁用账号 | — | 已登录session立即失效 | 03-超级管理员 §2 | +| 重置密码 | 账号持有人 | — | 下次登录使用新密码 | — | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/accounts/hospital | GET | 分页查询 | +| 启用/禁用 | /api/v1/accounts/{id}/toggle-status | PUT | 禁用立即失效session | +| 续期 | /api/v1/accounts/{id}/renew | PUT | 修改有效期 | +| 重置密码 | /api/v1/accounts/{id}/reset-password | PUT | — | + +--- + +## 页面6:新增医院账号页 + +**页面编号**:SA-A-03-P02 +**端侧归属**:Web专属 +**页面路径**:/account/hospital-accounts/create + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 账号管理 > 医院账号管理 > 新增医院账号 │ +├──────────────────────────────────────────────────────────────────┤ +│ 登录账号:[____________] 初始密码:[________](自动生成) │ +│ 绑定医院:[▼必选] │ +│ 有效期至:[日期选择] (必填) │ +│ 分配角色:[▼多选] □ 医院查看模板 □ 自定义... │ +├──────────────────────────────────────────────────────────────────┤ +│ [取消] [保存] │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 表单字段 + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 登录账号 | 文本输入 | 是 | — | 自填 | 4~20位字母数字,全局唯一 | +| 初始密码 | 文本输入 | 是 | 系统生成 | 自动生成 | 可手动修改,6~20位 | +| 绑定医院 | 下拉单选 | 是 | — | 医院信息列表 | — | +| 有效期至 | 日期选择 | 是 | — | 自填 | 不早于当前日期 | +| 分配角色 | 下拉多选 | 是 | — | 角色管理-医院适用角色 | 至少选一个 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 新增 | /api/v1/accounts/hospital | POST | — | + +--- + +## 页面7:物业公司管理员账号管理列表页 + +**页面编号**:SA-A-04-P01 +**端侧归属**:Web专属 +**页面路径**:/account/property-accounts + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 账号管理 > 物业管理员账号管理 │ +├──────────────────────────────────────────────────────────────────┤ +│ [查询条件区] │ +│ 登录账号[____] 绑定物业公司[▼] 服务医院[▼] 状态[▼] [查询] [重置] │ +├──────────────────────────────────────────────────────────────────┤ +│ [操作栏] [新增物业管理员账号] │ +├──────────────────────────────────────────────────────────────────┤ +│ [列表区] │ +│ 序号 | 登录账号 | 绑定物业 | 服务医院 | 角色 | 有效期至 | 状态 | 操作│ +│ 1 | prop01 | XX物业 | A医院 | 管理员| 2027-04| 正常 | ...│ +├──────────────────────────────────────────────────────────────────┤ +│ [分页] 共40条 每页[20▼] < 1 2 > │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 登录账号 | 文本输入 | 否 | — | 精确匹配 | +| 绑定物业公司 | 下拉单选 | 否 | 全部 | 数据来源:物业公司信息管理 | +| 服务医院 | 下拉单选 | 否 | 全部 | 数据来源:医院信息管理 | +| 状态 | 下拉单选 | 否 | 全部 | 正常/即将到期/已过期/已停用 | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 序号 | 60px | — | 自增 | +| 2 | 登录账号 | 120px | 否 | — | +| 3 | 绑定物业公司 | 120px | 是 | — | +| 4 | 服务医院 | 120px | 是 | — | +| 5 | 角色 | 120px | 否 | — | +| 6 | 有效期至 | 110px | 是 | 颜色标记同医院账号 | +| 7 | 状态 | 90px | 是 | 同医院账号 | +| 8 | 操作 | 200px | — | 编辑/续期/启停/重置密码 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 新增物业管理员账号 | permission:user:create | 操作栏 | 始终 | — | +| 编辑 | permission:user:update | 行操作 | 始终 | — | +| 续期 | permission:user:update | 行操作 | 始终 | — | +| 启用/禁用 | permission:user:update | 行操作 | 始终 | 禁用时下属账号同步失效 | +| 重置密码 | permission:user:update | 行操作 | 始终 | — | + +### 通知触发 + +| 触发操作 | 通知对象 | 通知方式 | 消息模板 | 文档来源 | +|----------|----------|----------|----------|----------| +| 账号禁用 | 物业管理员 | — | session失效+小程序同步下线 | 03-超级管理员 §2 | +| 账号禁用 | 下属人员 | 小程序推送 | 关联下属账号同步失效 | 01 §1.4 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/accounts/property-admin | GET | 分页查询 | +| 启用/禁用 | /api/v1/accounts/{id}/toggle-status | PUT | 禁用同步下线下属 | +| 续期 | /api/v1/accounts/{id}/renew | PUT | — | + +--- + +## 页面8:新增物业管理员账号页 + +**页面编号**:SA-A-04-P02 +**端侧归属**:Web专属 +**页面路径**:/account/property-accounts/create + +### 表单字段 + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 登录账号 | 文本输入 | 是 | — | 自填 | 4~20位字母数字,全局唯一 | +| 初始密码 | 文本输入 | 是 | 系统生成 | 自动生成 | 可修改 | +| 绑定物业公司 | 下拉单选 | 是 | — | 物业公司信息列表 | — | +| 服务医院 | 下拉单选 | 是 | — | 医院信息列表 | — | +| 有效期至 | 日期选择 | 是 | — | 自填 | 不早于当前日期 | +| 分配角色 | 下拉多选 | 是 | — | 角色管理-物业适用角色 | 至少选一个 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 新增 | /api/v1/accounts/property-admin | POST | — | + +--- + +## 页面9:到期账号管理页 + +**页面编号**:SA-A-07-P01 +**端侧归属**:Web专属 +**页面路径**:/account/expiring + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 账号管理 > 到期账号管理 │ +├──────────────────────────────────────────────────────────────────┤ +│ [统计卡片区] │ +│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ +│ │已过期 │ │7天内到期 │ │30天内到期 │ │ +│ │ 3 │ │ 5 │ │ 12 │ │ +│ └──────────┘ └──────────┘ └──────────┘ │ +├──────────────────────────────────────────────────────────────────┤ +│ [查询条件区] │ +│ 账号类型[▼] 到期状态[▼] [查询] [重置] │ +├──────────────────────────────────────────────────────────────────┤ +│ [列表区] │ +│ 序号 | 登录账号 | 账号类型 | 绑定单位 | 有效期至 | 剩余天数 | 操作 │ +│ 1 | hospital01| 医院 | XX医院 | 2026-04-20| 4天 | 续期 │ +│ 2 | prop01 | 物业 | XX物业 | 2026-03-01| -46天 | 续期 │ +├──────────────────────────────────────────────────────────────────┤ +│ [分页] 共20条 每页[20▼] < 1 > │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 账号类型 | 下拉单选 | 否 | 全部 | 医院/物业管理员 | +| 到期状态 | 下拉单选 | 否 | 全部 | 已过期/7天内到期/30天内到期 | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 序号 | 60px | — | 自增 | +| 2 | 登录账号 | 130px | 否 | — | +| 3 | 账号类型 | 100px | 否 | 医院/物业管理员 | +| 4 | 绑定单位 | 150px | 否 | 医院名称或物业公司名称 | +| 5 | 有效期至 | 120px | 是 | — | +| 6 | 剩余天数 | 90px | 是 | 已过期显示负数,红色标记 | +| 7 | 操作 | 100px | — | 续期 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 续期 | permission:user:update | 行操作 | 始终 | 弹窗修改有效期 | + +### 通知触发 + +| 触发操作 | 通知对象 | 通知方式 | 消息模板 | 文档来源 | +|----------|----------|----------|----------|----------| +| 续期成功 | 被续期账号 | — | 账号恢复可用,记录操作日志 | 03-超级管理员 §3 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/accounts/expiring | GET | 筛选到期账号 | +| 续期 | /api/v1/accounts/{id}/renew | PUT | — | + +--- + +## 页面10:到期提醒规则配置页 + +**页面编号**:SA-A-08-P01 +**端侧归属**:Web专属 +**页面路径**:/account/expiry-settings + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 账号管理 > 到期提醒规则配置 │ +├──────────────────────────────────────────────────────────────────┤ +│ ── 提醒天数配置 ──────────────────────────────────────────── │ +│ 提前提醒天数:[7] [15] [30] 天 (可多选,点击添加/移除) │ +│ │ +│ ── 提醒方式 ────────────────────────────────────────────── │ +│ ☑ 用户登录时弹窗提醒 │ +│ ☐ 邮件提醒(暂未开放) │ +│ │ +│ ── 提醒行为 ────────────────────────────────────────────── │ +│ 提醒弹窗关闭后:☑ 可正常使用 ☐ 限制部分功能 │ +│ 账号过期后: ☑ 禁止登录 ☐ 仅提醒 │ +├──────────────────────────────────────────────────────────────────┤ +│ [取消] [保存] │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 表单字段 + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 提前提醒天数 | 标签多选 | 是 | 7, 15, 30 | — | 至少选一个 | +| 用户登录弹窗 | 开关 | 是 | 开 | — | — | +| 弹窗关闭后行为 | 单选 | 是 | 可正常使用 | 固定选项 | — | +| 过期后行为 | 单选 | 是 | 禁止登录 | 固定选项 | — | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 查询配置 | /api/v1/system/configs/expiry-reminder | GET | — | +| 保存配置 | /api/v1/system/configs/expiry-reminder | PUT | — | + +--- + +## 需求追溯 + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| SA-A-01 | 医院信息管理 | 02-超级管理员 §1 / 03-超级管理员 §1 | 创建医院→创建医院账号 | 医院账号管理(绑定医院) | +| SA-A-02 | 物业公司信息管理 | 02-超级管理员 §1 / 03-超级管理员 §1 | 创建物业公司→创建物业账号 | 物业管理员账号管理(绑定物业) | +| SA-A-03 | 医院账号管理 | 02-超级管理员 §1 / 03-超级管理员 §1~2 | 账号创建→权限分配 | 权限管理(角色绑定) | +| SA-A-04 | 物业管理员账号管理 | 02-超级管理员 §1 / 03-超级管理员 §1~2 | 账号创建→权限分配,禁用→下属同步失效 | 权限管理(角色绑定) / 物业组织架构(下属账号) | +| SA-A-05 | 账号有效期设置 | 02-超级管理员 §1 / 03-超级管理员 §3 / 01 §1.4 | 创建时设置有效期 | 到期账号管理 / 到期提醒规则 | +| SA-A-06 | 账号可用性控制 | 02-超级管理员 §1 / 03-超级管理员 §2 | 禁用→session立即失效+小程序下线 | 操作日志(记录启停操作) | +| SA-A-07 | 到期账号管理 | 02-超级管理员 §1 / 03-超级管理员 §3 / 01 §1.4 | 手动续期→账号恢复 | 到期提醒规则配置 | +| SA-A-08 | 到期提醒规则配置 | 02-超级管理员 §1 / 03-超级管理员 §3 / 01 §1.4 | 配置→系统按规则自动提醒 | 到期账号管理 / 系统配置 | + +## 业务规则 + +1. **新建使用单位流程**:医院信息→物业公司信息→医院账号→物业管理员账号,四步顺序创建(来源:03-超级管理员 §1) +2. **账号有效期必填**:创建医院/物业管理员账号时必须设置有效期(来源:01 §1.4) +3. **物业下属不单独设有效期**:下属人员随物业公司管理员账号到期而自动失效(来源:01 §1.4 / 03-超级管理员 §3) +4. **禁用立即生效**:禁用账号后session立即失效,小程序同步下线(来源:03-超级管理员 §2) +5. **到期提醒弹窗**:到期前N天登录时弹窗提醒,关闭后可正常使用(来源:01 §1.4 / 03-超级管理员 §3) +6. **过期禁止登录**:账号过期后禁止登录,需超管手动续期(来源:01 §1.4 / 03-超级管理员 §3) +7. **超管不涉及业务数据**:超级管理员仅管理系统配置与账号数据,不查看任何业务数据(来源:01 §1.3 / 03-超级管理员 §7) +8. **所有操作记录日志**:账号创建/启停/续期等操作自动记录操作日志(来源:06-项目技术要求 §4.5) diff --git a/docs/02-功能清单-超级管理员/02-权限管理.md b/docs/02-功能清单-超级管理员/02-权限管理.md new file mode 100644 index 0000000..504d0a8 --- /dev/null +++ b/docs/02-功能清单-超级管理员/02-权限管理.md @@ -0,0 +1,382 @@ +# 权限管理 + +> 模块编码:permission +> 端侧:Web专属(仅超级管理员) +> 关联文档:01-模块划分 §8 / 02-功能清单-超级管理员 §2 / 03-业务流转逻辑-超级管理员 §4~6 / 05-接口规范 §4.2~4.3 / 06-项目技术要求 §4.2 + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 权限管理 | +| 子菜单 | 角色管理、权限配置注册、权限审计日志 | +| 功能编号 | SA-P-01 ~ SA-P-10 | +| 权限编码前缀 | permission:role:* / permission:config:* | + +--- + +## 页面1:角色管理列表页 + +**页面编号**:SA-P-01-P01 +**端侧归属**:Web专属 +**页面路径**:/permission/roles + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 权限管理 > 角色管理 │ +├──────────────────────────────────────────────────────────────────┤ +│ [查询条件区] │ +│ 角色名称[____] 适用范围[▼] 状态[▼] [查询] [重置] │ +├──────────────────────────────────────────────────────────────────┤ +│ [操作栏] [新增角色] │ +├──────────────────────────────────────────────────────────────────┤ +│ [列表区] │ +│ 序号 | 角色名称 | 适用范围 | 预设模板 | 关联账号数 | 状态 | 操作 │ +│ 1 | 医院查看 | 医院 | 是 | 5 | 启用 | 编辑 停用│ +│ 2 | 巡检主管 | 物业下属| 否 | 8 | 启用 | 编辑 停用│ +│ 3 | 维修员 | 物业下属| 是 | 23 | 启用 | 编辑 停用│ +├──────────────────────────────────────────────────────────────────┤ +│ [分页] 共15条 每页[20▼] < 1 > │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 角色名称 | 文本输入 | 否 | — | 模糊匹配 | +| 适用范围 | 下拉单选 | 否 | 全部 | 医院账号/物业管理员/物业下属 | +| 状态 | 下拉单选 | 否 | 全部 | 启用/停用 | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 序号 | 60px | — | 自增 | +| 2 | 角色名称 | 150px | 是 | — | +| 3 | 适用范围 | 120px | 否 | 医院账号/物业管理员/物业下属 | +| 4 | 预设模板 | 80px | 否 | 是/否标签 | +| 5 | 关联账号数 | 100px | 是 | 点击查看关联账号列表 | +| 6 | 状态 | 80px | 是 | 启用/停用 | +| 7 | 操作 | 220px | — | 编辑/权限预览/停用/删除 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 新增角色 | permission:role:create | 操作栏 | 始终 | 跳转新增页 | +| 编辑 | permission:role:update | 行操作 | 始终 | 跳转编辑页 | +| 权限预览 | permission:role:view | 行操作 | 始终 | 弹窗展示完整权限清单 | +| 停用 | permission:role:update | 行操作 | 状态=启用 | 二次确认 | +| 删除 | permission:role:delete | 行操作 | 关联账号数=0 | 二次确认 | + +### 角色差异化视图 + +| 角色 | 可见按钮 | 数据范围 | 备注 | +|------|----------|----------|------| +| 超级管理员 | 全部按钮 | 全部角色 | — | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/roles | GET | 分页查询 | +| 停用角色 | /api/v1/roles/{id}/disable | PUT | — | +| 删除角色 | /api/v1/roles/{id} | DELETE | 仅无关联账号时可删 | + +--- + +## 页面2:角色新增/编辑页 + +**页面编号**:SA-P-01-P02 +**端侧归属**:Web专属 +**页面路径**:/permission/roles/create 或 /permission/roles/:id/edit + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 权限管理 > 角色管理 > 新增角色 │ +├──────────────────────────────────────────────────────────────────┤ +│ ── 基本信息 ── │ +│ 角色名称:[____________] │ +│ 角色描述:[____________________________] │ +│ 适用范围:[▼] (医院账号/物业管理员/物业下属) │ +│ 选择预设模板:[▼可选] 选择后自动填充权限,可微调 │ +├──────────────────────────────────────────────────────────────────┤ +│ ── 权限分配(四级树形勾选)── │ +│ ☑ 功能菜单:在线报修 │ +│ ├── ☑ 页面:工单列表 │ +│ │ ├── ☑ 功能点:工单管理 │ +│ │ │ ├── ☑ 查看 ☑ 新增 ☑ 编辑 │ +│ │ │ ├── ☐ 删除 ☐ 审批 ☑ 导出 ☑ 分配 │ +│ │ └── ☑ 功能点:批量操作 │ +│ │ ├── ☑ 查看 ☐ 新增 ☐ 编辑 │ +│ │ └── ☐ 删除 ☐ 审批 ☐ 导出 ☐ 分配 │ +│ ├── ☑ 页面:工单详情 │ +│ │ ├── ☑ 功能点:延期审批 │ +│ │ │ ├── ☑ 查看 ☐ 新增 ☐ 编辑 │ +│ │ │ └── ☐ 删除 ☑ 审批 ☐ 导出 ☐ 分配 │ +│ │ └── ☑ 功能点:工单验收 │ +│ │ ├── ☑ 查看 ☐ 新增 ☐ 编辑 │ +│ │ └── ☐ 删除 ☑ 审批 ☐ 导出 ☐ 分配 │ +│ └── ☐ 页面:报修类型管理 │ +│ ... │ +│ ☐ 功能菜单:巡检管理 │ +│ ... │ +├──────────────────────────────────────────────────────────────────┤ +│ [取消] [权限预览] [保存] │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 表单字段(基本信息) + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 角色名称 | 文本输入 | 是 | — | 自填 | 最大30字,全局唯一 | +| 角色描述 | 多行文本 | 否 | — | 自填 | 最大200字 | +| 适用范围 | 下拉单选 | 是 | — | 固定选项 | 医院账号/物业管理员/物业下属 | +| 预设模板 | 下拉单选 | 否 | — | 预设模板列表 | 选择后自动填充权限 | + +### 预设模板选项 + +| 模板名称 | 适用对象 | 典型权限 | 文档来源 | +|----------|----------|----------|----------| +| 物业管理员模板 | 物业公司管理员 | 全部日常业务管理权限 | 01 §8.4 | +| 主管模板 | 主管 | 本班组管理+审批+查看+导出 | 01 §8.4 | +| 班组长模板 | 班组长 | 本班组查看+分配+导出 | 01 §8.4 | +| 维修员模板 | 维修人员 | 接单+完工+延期申请 | 01 §8.4 | +| 巡检员模板 | 巡检人员 | 巡检执行+打卡+异常上报 | 01 §8.4 | +| 保洁员模板 | 保洁人员 | 保洁执行+打卡确认 | 01 §8.4 | +| 医院查看模板 | 医院账号 | 全部日常数据查看+合同+招标 | 01 §8.4 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 权限预览 | permission:role:view | 底部操作栏 | 始终 | 弹窗展示已勾选的完整权限清单 | +| 保存 | permission:role:create/update | 底部操作栏 | 始终 | 保存后权限审计日志+实时生效 | + +### 通知触发 + +| 触发操作 | 通知对象 | 通知方式 | 消息模板 | 文档来源 | +|----------|----------|----------|----------|----------| +| 权限变更 | 关联账号用户 | Redis Pub/Sub | 毫秒级刷新权限缓存,无需重新登录 | 03-超级管理员 §6 | +| 权限变更 | 关联账号用户 | 小程序 | 下次接口请求时返回新权限集 | 03-超级管理员 §6 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 新增角色 | /api/v1/roles | POST | — | +| 编辑角色 | /api/v1/roles/{id} | PUT | — | +| 获取权限树 | /api/v1/permissions/tree | GET | 四级权限树结构 | +| 权限预览 | /api/v1/roles/{id}/permissions | GET | 已分配的完整权限列表 | + +--- + +## 页面3:权限预览弹窗 + +**页面编号**:SA-P-06-P01 +**端侧归属**:Web专属 +**页面路径**:弹窗形式 + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ 权限预览 — 巡检主管 [×] │ +├──────────────────────────────────────────────────────────────────┤ +│ ☑ 在线报修 │ +│ ├─ ☑ 工单列表 │ +│ │ ├─ ☑ 工单管理:查看 ✓ 新增 ✗ 编辑 ✓ 删除 ✗ 审批 ✓ 导出 ✓ 分配 ✗│ +│ │ └─ ☐ 批量操作 │ +│ ├─ ☑ 工单详情 │ +│ │ ├─ ☑ 延期审批:查看 ✓ 审批 ✓ │ +│ │ └─ ☑ 工单验收:查看 ✓ 审批 ✓ │ +│ └─ ☐ 报修类型管理 │ +│ ☑ 巡检管理 │ +│ ├─ ☑ 巡检计划:查看 ✓ 新增 ✓ 编辑 ✓ │ +│ ... │ +├──────────────────────────────────────────────────────────────────┤ +│ [关闭] │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 说明 + +- 展示角色当前已分配的完整权限清单 +- 四级展开:功能菜单→页面→功能点→动作 +- 每个动作用 ✓/✗ 标识是否有权限 +- 支持搜索功能菜单/页面名称 + +--- + +## 页面4:权限配置注册页 + +**页面编号**:SA-P-10-P01 +**端侧归属**:Web专属 +**页面路径**:/permission/registry + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 权限管理 > 权限配置注册 │ +├──────────────────────────────────────────────────────────────────┤ +│ [说明] 此页面展示系统自动注册的权限配置(来源:IModulePlugin), │ +│ 开发新增功能时自动同步,超级管理员可查看但不可手动编辑 │ +├──────────────────────────────────────────────────────────────────┤ +│ [查询条件区] │ +│ 模块名称[____] 页面名称[____] [查询] [重置] │ +├──────────────────────────────────────────────────────────────────┤ +│ [列表区] │ +│ 模块编码 | 模块名称 | 页面编码 | 页面名称 | 功能点 | 可用动作 │ +│ repair | 在线报修 | repair_list| 工单列表 | 工单管理 | 查看,新增..│ +│ repair | 在线报修 | repair_detail|工单详情| 延期审批| 查看,审批 │ +│ ... │ +├──────────────────────────────────────────────────────────────────┤ +│ [分页] 共120条 每页[20▼] < 1 2 3 ... 6 > │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 模块名称 | 文本输入 | 否 | — | 模糊匹配 | +| 页面名称 | 文本输入 | 否 | — | 模糊匹配 | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 模块编码 | 100px | 否 | — | +| 2 | 模块名称 | 100px | 否 | — | +| 3 | 页面编码 | 130px | 否 | — | +| 4 | 页面名称 | 120px | 否 | — | +| 5 | 功能点编码 | 140px | 否 | — | +| 6 | 功能点名称 | 120px | 否 | — | +| 7 | 可用动作 | 200px | 否 | view,create,update,delete,approve,export,assign | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| — | — | — | — | 此页面只读,数据由IModulePlugin自动注册 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/permissions/registry | GET | 查看已注册的权限配置 | +| 刷新 | /api/v1/permissions/registry/refresh | POST | 手动触发权限重新扫描 | + +--- + +## 页面5:权限审计日志页 + +**页面编号**:SA-P-08-P01 +**端侧归属**:Web专属 +**页面路径**:/permission/audit-log + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 权限管理 > 权限审计日志 │ +├──────────────────────────────────────────────────────────────────┤ +│ [查询条件区] │ +│ 操作人[____] 操作类型[▼] 角色[____] 日期[起始]~[结束] [查询] [重置]│ +├──────────────────────────────────────────────────────────────────┤ +│ [列表区] │ +│ 序号 | 操作时间 | 操作人 | 操作类型 | 目标角色 | 变更详情 | 操作 │ +│ 1 | 14:00 | admin | 权限修改 | 巡检主管 | [+2项][-1项]| 查看│ +│ 2 | 11:30 | admin | 角色创建 | 保洁主管 | — | 查看│ +├──────────────────────────────────────────────────────────────────┤ +│ [分页] 共80条 每页[20▼] < 1 2 3 4 > │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 操作人 | 文本输入 | 否 | — | 模糊匹配 | +| 操作类型 | 下拉单选 | 否 | 全部 | 角色创建/权限修改/角色分配/角色移除 | +| 角色 | 文本输入 | 否 | — | 模糊匹配角色名称 | +| 日期范围 | 日期范围 | 否 | — | 操作时间范围 | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 序号 | 60px | — | 自增 | +| 2 | 操作时间 | 150px | 是 | 默认倒序 | +| 3 | 操作人 | 100px | 否 | — | +| 4 | 操作类型 | 100px | 否 | 标签样式 | +| 5 | 目标角色 | 120px | 否 | — | +| 6 | 变更详情 | 120px | 否 | [+N项][-M项],简洁展示 | +| 7 | 操作 | 80px | — | 查看详情 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 查看详情 | audit-log:permission:view | 行操作 | 始终 | 弹窗展示变更前后对比 | + +### 审计日志详情弹窗 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ 权限变更详情 [×] │ +├──────────────────────────────────────────────────────────────────┤ +│ 角色:巡检主管 │ +│ 操作人:超级管理员(admin) │ +│ 操作时间:2026-04-16 14:00:00 │ +│ 操作类型:权限修改 │ +├──────────────────────────────────────────────────────────────────┤ +│ 变更对比: │ +│ [+新增] 在线报修 → 工单详情 → 延期审批 → 审批 │ +│ [+新增] 在线报修 → 工单列表 → 工单管理 → 导出 │ +│ [-移除] 巡检管理 → 巡检计划 → 计划管理 → 删除 │ +├──────────────────────────────────────────────────────────────────┤ +│ [关闭] │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/audit-logs/permission | GET | 分页查询 | +| 详情查询 | /api/v1/audit-logs/permission/{id} | GET | 含变更前后对比 | + +--- + +## 需求追溯 + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| SA-P-01 | 角色定义 | 02-超级管理员 §2 / 03-超级管理员 §4 | 创建角色→权限分配 | 账号管理(角色绑定) | +| SA-P-02 | 角色权限分配 | 02-超级管理员 §2 / 03-超级管理员 §4 / 01 §8.1 | 权限变更→审计日志+实时生效 | 权限审计日志 / 权限实时生效 | +| SA-P-03 | 角色管理 | 02-超级管理员 §2 | 停用→关联账号权限失效 | 账号管理(角色绑定) | +| SA-P-04 | 权限预设模板 | 02-超级管理员 §2 / 01 §8.4 | 选择模板→自动填充权限 | 角色新增页(模板选择) | +| SA-P-05 | 账号角色绑定 | 02-超级管理员 §2 / 03-超级管理员 §4 | 在账号管理中操作 | 账号管理 / 物业组织架构(下属角色分配) | +| SA-P-06 | 权限预览 | 02-超级管理员 §2 | 预览→确认权限分配 | 角色新增/编辑页 | +| SA-P-07 | 权限自动同步 | 02-超级管理员 §2 / 03-超级管理员 §5 / 01 §8.2 | IModulePlugin注册→权限树自动更新 | 权限配置注册页 | +| SA-P-08 | 权限审计日志 | 02-超级管理员 §2 / 03-超级管理员 §8.2 / 01 §8.5 | 权限变更→自动记录 | 操作日志 | +| SA-P-09 | 权限实时生效 | 02-超级管理员 §2 / 03-超级管理员 §6 / 01 §8.3 | Redis Pub/Sub毫秒级生效 | — | +| SA-P-10 | 权限配置注册 | 02-超级管理员 §2 / 03-超级管理员 §5 | 查看IModulePlugin注册的权限 | 05-接口规范 §4.2 | + +## 业务规则 + +1. **四级权限粒度**:功能菜单→页面→功能点→动作,7种动作类型(view/create/update/delete/approve/export/assign)(来源:01 §8.1 / 06 §4.2) +2. **权限自动同步**:新模块通过IModulePlugin.getPermissionDefinitions()自动注册,权限管理页面自动渲染新可勾选项(来源:01 §8.2 / 05 §4.2) +3. **权限实时生效**:权限变更后通过Redis Pub/Sub毫秒级生效,无需重新登录(来源:01 §8.3 / 03-超级管理员 §6 / 06 §3.1) +4. **权限审计日志**:记录操作人、时间、类型、变更前后对比(来源:01 §8.5 / 03-超级管理员 §8.2) +5. **角色删除条件**:仅关联账号数为0时才可删除(来源:02-超级管理员 SA-P-03) +6. **预设模板使用**:创建角色时选择模板→系统自动填充权限→管理员微调后保存(来源:01 §8.4) +7. **权限配置表只读**:权限配置注册页数据来源于IModulePlugin自动注册,超管只可查看不可手动编辑(来源:03-超级管理员 §5) diff --git a/docs/02-功能清单-超级管理员/03-系统配置.md b/docs/02-功能清单-超级管理员/03-系统配置.md new file mode 100644 index 0000000..04a2100 --- /dev/null +++ b/docs/02-功能清单-超级管理员/03-系统配置.md @@ -0,0 +1,177 @@ +# 系统配置 + +> 模块编码:system +> 端侧:Web专属(仅超级管理员) +> 关联文档:01-模块划分 §2.3 / 02-功能清单-超级管理员 §3 / 03-业务流转逻辑-超级管理员 §9 / 05-接口规范 §9.2 / 06-项目技术要求 §8.3~8.4 + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 系统配置 | +| 子菜单 | 系统版本管理、缓存管理 | +| 功能编号 | SA-S-01 ~ SA-S-02 | +| 权限编码前缀 | system:version:* / system:cache:* | + +--- + +## 页面1:系统版本管理页 + +**页面编号**:SA-S-01-P01 +**端侧归属**:Web专属 +**页面路径**:/system/versions + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 系统配置 > 系统版本管理 │ +├──────────────────────────────────────────────────────────────────┤ +│ [当前版本信息卡片] │ +│ ┌──────────────────────┐ ┌──────────────────────┐ │ +│ │ 管理后台版本 │ │ 小程序版本 │ │ +│ │ 当前版本:v1.2.0 │ │ 当前版本:v1.1.0 │ │ +│ │ 最低兼容:v1.0.0 │ │ 最低兼容:v1.0.0 │ │ +│ │ 发布日期:2026-04-01 │ │ 发布日期:2026-03-15 │ │ +│ └──────────────────────┘ └──────────────────────┘ │ +├──────────────────────────────────────────────────────────────────┤ +│ [操作栏] [新增版本] │ +├──────────────────────────────────────────────────────────────────┤ +│ [列表区] │ +│ 序号 | 版本号 | 端侧 | 最低兼容版本 | 是否强制更新 | 发布日期 | 操作 │ +│ 1 | v1.2.0 | Web | v1.0.0 | 否 | 2026-04-01| 编辑│ +│ 2 | v1.1.0 | 小程序 | v1.0.0 | 否 | 2026-03-15| 编辑│ +│ 3 | v1.0.0 | 小程序 | v1.0.0 | 是 | 2026-01-01| — │ +├──────────────────────────────────────────────────────────────────┤ +│ [分页] 共5条 │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| — | — | — | — | 无筛选条件,展示全部版本 | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 序号 | 60px | — | 自增 | +| 2 | 版本号 | 100px | 是 | 语义化版本号 | +| 3 | 端侧 | 80px | 否 | Web/小程序 | +| 4 | 最低兼容版本 | 120px | 否 | 低于此版本需强制更新 | +| 5 | 是否强制更新 | 110px | 否 | 是(红色)/否(绿色) | +| 6 | 发布日期 | 120px | 是 | 默认倒序 | +| 7 | 更新说明 | 200px | 否 | 简述本次更新内容 | +| 8 | 操作 | 80px | — | 编辑 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 新增版本 | system:version:create | 操作栏 | 始终 | 弹窗 | +| 编辑 | system:version:update | 行操作 | 始终 | 弹窗 | + +### 表单字段(新增/编辑弹窗) + +| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 | +|--------|----------|------|--------|----------|----------| +| 版本号 | 文本输入 | 是 | — | 自填 | 语义化版本格式(x.y.z) | +| 端侧 | 下拉单选 | 是 | — | 固定选项 | Web/小程序 | +| 最低兼容版本 | 文本输入 | 是 | — | 自填 | 语义化版本格式 | +| 是否强制更新 | 开关 | 是 | 否 | — | 强制更新时用户无法跳过 | +| 更新说明 | 多行文本 | 是 | — | 自填 | 最大500字 | + +### 通知触发 + +| 触发操作 | 通知对象 | 通知方式 | 消息模板 | 文档来源 | +|----------|----------|----------|----------|----------| +| 版本发布 | 小程序用户 | 小程序检测 | 下次启动时检测版本更新 | 03-小程序端 §10 / 06 §8.3 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/system/versions | GET | — | +| 新增 | /api/v1/system/versions | POST | — | +| 编辑 | /api/v1/system/versions/{id} | PUT | — | +| 获取最新版本 | /api/v1/system/versions/latest | GET | 小程序启动时调用 | + +--- + +## 页面2:缓存管理页 + +**页面编号**:SA-S-02-P01 +**端侧归属**:Web专属 +**页面路径**:/system/cache + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 系统配置 > 缓存管理 │ +├──────────────────────────────────────────────────────────────────┤ +│ [缓存状态概览] │ +│ ┌────────────────────────────────────────────────────────────┐ │ +│ │ Redis状态:● 已连接 内存使用:128MB/512MB 连接数:24 │ │ +│ └────────────────────────────────────────────────────────────┘ │ +├──────────────────────────────────────────────────────────────────┤ +│ [缓存模块列表] │ +│ 模块名称 | 缓存键前缀 | 缓存条数 | 最后更新时间 | 操作 │ +│ 权限缓存 | perm:* | 1,234 | 10:30:25 | [清理] │ +│ 字典缓存 | dict:* | 56 | 09:00:00 | [清理] │ +│ 菜单缓存 | menu:* | 120 | 09:00:00 | [清理] │ +│ 业务缓存 | biz:* | 0 | — | [清理] │ +├──────────────────────────────────────────────────────────────────┤ +│ [操作栏] [全部清理] │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 清理(单模块) | system:cache:update | 行操作 | 始终 | 二次确认后清理指定模块缓存 | +| 全部清理 | system:cache:update | 操作栏 | 始终 | 二次确认后清理全部缓存 | + +### 缓存模块说明 + +| 模块 | 缓存键前缀 | 过期策略 | 刷新机制 | 文档来源 | +|------|------------|----------|----------|----------| +| 权限缓存 | perm:* | 2小时TTL | 权限变更时实时刷新(Redis Pub/Sub) | 06 §5.3 / 03-超级管理员 §9 | +| 字典缓存 | dict:* | 24小时TTL | 字典变更时手动/自动刷新 | 06 §5.3 | +| 菜单缓存 | menu:* | 24小时TTL | 菜单变更时手动/自动刷新 | 06 §5.3 | +| 业务缓存 | biz:* | 按需懒加载 | 不缓存,实时查询 | 06 §5.3 | + +### 通知触发 + +| 触发操作 | 通知对象 | 通知方式 | 消息模板 | 文档来源 | +|----------|----------|----------|----------|----------| +| 缓存清理 | 在线用户 | WebSocket推送 | 提示刷新页面 | 03-超级管理员 §9 | +| 权限缓存清理 | 在线用户 | Redis Pub/Sub | 刷新权限缓存 | 03-超级管理员 §9 | + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 缓存状态 | /api/v1/system/cache/status | GET | Redis连接状态+各模块缓存统计 | +| 清理单模块 | /api/v1/system/cache/clear/{module} | POST | 清理指定模块缓存 | +| 全部清理 | /api/v1/system/cache/clear-all | POST | 清理全部缓存 | + +--- + +## 需求追溯 + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| SA-S-01 | 系统版本管理 | 02-超级管理员 §3 / 03-超级管理员 §9 | 版本发布→小程序检测更新 | 小程序端版本更新提示(MP-C-05) | +| SA-S-02 | 缓存管理 | 02-超级管理员 §3 / 03-超级管理员 §9 | 清理缓存→通知在线用户刷新 | 权限管理(权限缓存清理) / 物业系统配置(字典缓存) | + +## 业务规则 + +1. **版本更新策略**:小版本更新提示用户可选更新,大版本更新(低于最低兼容版本)强制更新(来源:03-小程序端 §10 / 06 §8.3) +2. **SDK依赖校验**:小程序启动时校验蓝牙SDK、微信SDK等关键依赖版本(来源:03-小程序端 §10) +3. **缓存自动清理**:系统启动时自动全量清理缓存,权限变更时定向清理权限缓存(来源:03-超级管理员 §9 / 06 §8.4) +4. **缓存手动清理**:超级管理员可按模块清理缓存,清理后通知在线用户刷新页面(来源:03-超级管理员 §9) +5. **权限缓存TTL降级**:Redis连接断开时,权限缓存2小时TTL到期后自动刷新(来源:06 §3.1) diff --git a/docs/02-功能清单-超级管理员/04-操作日志.md b/docs/02-功能清单-超级管理员/04-操作日志.md new file mode 100644 index 0000000..8c86670 --- /dev/null +++ b/docs/02-功能清单-超级管理员/04-操作日志.md @@ -0,0 +1,201 @@ +# 操作日志 + +> 模块编码:audit-log +> 端侧:Web专属(仅超级管理员) +> 关联文档:01-模块划分 §2.3 / 02-功能清单-超级管理员 §4 / 03-业务流转逻辑-超级管理员 §8 / 05-接口规范 §9.2 / 06-项目技术要求 §4.5 + +## 功能概览 + +| 项目 | 说明 | +|------|------| +| 菜单名称 | 操作日志 | +| 子菜单 | 权限变更日志、账号操作日志 | +| 功能编号 | SA-L-01 ~ SA-L-02 | +| 权限编码前缀 | audit-log:permission:view / audit-log:list:* | + +--- + +## 页面1:权限变更日志页 + +**页面编号**:SA-L-01-P01 +**端侧归属**:Web专属 +**页面路径**:/audit-log/permission + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 操作日志 > 权限变更日志 │ +├──────────────────────────────────────────────────────────────────┤ +│ [查询条件区] │ +│ 操作人[____] 操作类型[▼] 角色[____] 日期[起始]~[结束] [查询] [重置]│ +├──────────────────────────────────────────────────────────────────┤ +│ [列表区] │ +│ 序号 | 操作时间 | 操作人 | 操作类型 | 目标角色 | 变更摘要 | 操作 │ +│ 1 | 14:00 | admin | 权限修改 | 巡检主管 | +2项 -1项 | 查看 │ +│ 2 | 11:30 | admin | 角色创建 | 保洁主管 | 初始权限 | 查看 │ +│ 3 | 09:15 | admin | 角色分配 | 医院查看 | 分配给5个账号| 查看│ +├──────────────────────────────────────────────────────────────────┤ +│ [分页] 共120条 每页[20▼] < 1 2 3 ... 6 > │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 操作人 | 文本输入 | 否 | — | 模糊匹配 | +| 操作类型 | 下拉单选 | 否 | 全部 | 角色创建/权限修改/角色分配/角色移除 | +| 角色 | 文本输入 | 否 | — | 模糊匹配角色名称 | +| 日期范围 | 日期范围 | 否 | — | 操作时间范围 | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 序号 | 60px | — | 自增 | +| 2 | 操作时间 | 150px | 是 | 默认倒序 | +| 3 | 操作人 | 100px | 否 | — | +| 4 | 操作类型 | 100px | 否 | 彩色标签区分 | +| 5 | 目标角色 | 120px | 否 | — | +| 6 | 变更摘要 | 150px | 否 | +N项 -M项 简述 | +| 7 | 操作 | 80px | — | 查看详情 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 查看详情 | audit-log:permission:view | 行操作 | 始终 | 弹窗展示变更前后对比 | + +### 变更详情弹窗 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ 权限变更详情 [×] │ +├──────────────────────────────────────────────────────────────────┤ +│ 角色:巡检主管 │ +│ 操作人:超级管理员(admin) │ +│ 操作时间:2026-04-16 14:00:00 │ +│ 操作类型:权限修改 │ +│ 操作IP:192.168.1.100 │ +├──────────────────────────────────────────────────────────────────┤ +│ 变更对比: │ +│ [+新增] 在线报修 → 工单详情 → 延期审批 → 审批 │ +│ [+新增] 在线报修 → 工单列表 → 工单管理 → 导出 │ +│ [-移除] 巡检管理 → 巡检计划 → 计划管理 → 删除 │ +├──────────────────────────────────────────────────────────────────┤ +│ [关闭] │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/audit-logs/permission | GET | 分页查询 | +| 详情查询 | /api/v1/audit-logs/permission/{id} | GET | 含变更前后对比 | + +--- + +## 页面2:账号操作日志页 + +**页面编号**:SA-L-02-P01 +**端侧归属**:Web专属 +**页面路径**:/audit-log/account + +### 界面布局 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ [面包屑] 操作日志 > 账号操作日志 │ +├──────────────────────────────────────────────────────────────────┤ +│ [查询条件区] │ +│ 操作人[____] 操作类型[▼] 账号类型[▼] 日期[起始]~[结束] [查询] [重置]│ +├──────────────────────────────────────────────────────────────────┤ +│ [列表区] │ +│ 序号 | 操作时间 | 操作人 | 操作类型 | 目标账号 | 账号类型 | 详情 │ +│ 1 | 15:00 | admin | 账号创建 | hosp01 | 医院 | 查看 │ +│ 2 | 14:30 | admin | 账号续期 | prop01 | 物业 | 查看 │ +│ 3 | 10:00 | admin | 账号禁用 | prop02 | 物业 | 查看 │ +├──────────────────────────────────────────────────────────────────┤ +│ [分页] 共85条 每页[20▼] < 1 2 3 4 5 > │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 查询条件 + +| 字段名 | 控件类型 | 必填 | 默认值 | 说明 | +|--------|----------|------|--------|------| +| 操作人 | 文本输入 | 否 | — | 模糊匹配 | +| 操作类型 | 下拉单选 | 否 | 全部 | 创建/编辑/启用/禁用/续期/重置密码 | +| 账号类型 | 下拉单选 | 否 | 全部 | 医院/物业管理员 | +| 日期范围 | 日期范围 | 否 | — | 操作时间范围 | + +### 列表字段 + +| 序号 | 字段名 | 列宽 | 支持排序 | 说明 | +|------|--------|------|----------|------| +| 1 | 序号 | 60px | — | 自增 | +| 2 | 操作时间 | 150px | 是 | 默认倒序 | +| 3 | 操作人 | 100px | 否 | — | +| 4 | 操作类型 | 100px | 否 | 彩色标签 | +| 5 | 目标账号 | 120px | 否 | — | +| 6 | 账号类型 | 90px | 否 | 医院/物业管理员 | +| 7 | 绑定单位 | 150px | 否 | 医院或物业公司名称 | +| 8 | 详情 | 80px | — | 查看 | + +### 操作按钮 + +| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 | +|------|----------|------|----------|------| +| 查看详情 | audit-log:list:view | 行操作 | 始终 | 弹窗展示完整操作信息 | + +### 操作详情弹窗 + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ 账号操作详情 [×] │ +├──────────────────────────────────────────────────────────────────┤ +│ 操作人:超级管理员(admin) │ +│ 操作时间:2026-04-16 15:00:00 │ +│ 操作IP:192.168.1.100 │ +│ 操作类型:账号创建 │ +│ 目标账号:hosp01 │ +│ 账号类型:医院账号 │ +│ 绑定医院:XX医院 │ +├──────────────────────────────────────────────────────────────────┤ +│ 变更前数据:(无,新增操作) │ +│ 变更后数据: │ +│ 登录账号:hosp01 │ +│ 绑定医院:XX医院 │ +│ 有效期至:2027-04-16 │ +│ 分配角色:医院查看模板 │ +├──────────────────────────────────────────────────────────────────┤ +│ [关闭] │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### API端点 + +| 页面操作 | API路径 | 方法 | 说明 | +|----------|---------|------|------| +| 列表查询 | /api/v1/audit-logs/account | GET | 分页查询 | +| 详情查询 | /api/v1/audit-logs/account/{id} | GET | 含变更前后数据 | + +--- + +## 需求追溯 + +| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 | +|------------|----------|----------|----------|----------| +| SA-L-01 | 权限变更日志 | 02-超级管理员 §4 / 03-超级管理员 §8.2 / 01 §8.5 | — | 权限管理(变更时自动记录) | +| SA-L-02 | 账号操作日志 | 02-超级管理员 §4 / 03-超级管理员 §8.1 | — | 账号管理(操作时自动记录) | + +## 业务规则 + +1. **日志记录范围**:权限管理(角色创建/修改/删除、权限分配/变更)、账号管理(创建/启停/续期/有效期修改)、系统管理(配置变更/缓存清理/版本管理)(来源:03-超级管理员 §8.1) +2. **权限审计日志特殊展示**:额外展示变更前后权限对比,用[+新增][-移除]标记(来源:03-超级管理员 §8.2) +3. **日志记录内容**:操作人、时间、IP、模块、操作类型、变更前后数据快照(来源:06 §4.5) +4. **日志保留期限**:至少保留1年,支持导出(来源:06 §4.5) +5. **自动记录**:所有写操作通过AOP切面统一记录,业务代码无感知(来源:06 §4.5) +6. **超管仅查看系统数据**:超管操作日志仅涉及账号/权限/系统配置相关操作,不包含任何业务数据(来源:01 §1.3) diff --git a/docs/03-业务流转逻辑-医院.md b/docs/03-业务流转逻辑-医院.md new file mode 100644 index 0000000..a0449ad --- /dev/null +++ b/docs/03-业务流转逻辑-医院.md @@ -0,0 +1,187 @@ +# 医院 — 业务流转逻辑 + +> 版本:v4.0 +> 医院账号仅使用Web端,以服务监督和数据查看为主,独占合同管理与分段招标。 +> 端侧:仅Web端(无小程序端) +> 关联文档:`01-模块划分.md`(v4.0)、`02-功能清单-医院.md` + +--- + +## 1. 合同管理 — 合同流转(仅医院账号) + +> **物业公司不可操作此模块**,仅医院账号有全部权限。 + +### 1.1 合同状态流转图 + +``` + 合同录入 ──▶ 审批中 ──▶ 履约中 ──▶ 到期预警 ──▶ 续签/终止 + │ │ + 审批(Web端) 付款节点到期提醒(Web端提醒) + 变更管理(可选) ──▶ 变更审批(Web端) +``` + +### 1.2 合同流转规则 + +| 当前状态 | 操作 | 目标状态 | 执行角色 | 端侧 | 说明 | +|----------|------|----------|----------|------|------| +| — | 合同录入 | 审批中 | 医院账号 | Web | 基本信息、金额、服务期限、附件上传 | +| 审批中 | 审批通过 | 履约中 | 医院账号 | Web | 审批新录入合同 | +| 审批中 | 审批驳回 | — | 医院账号 | Web | 驳回需修改后重新提交 | +| 履约中 | 付款确认 | 履约中 | 医院账号 | Web | 确认付款节点完成 | +| 履约中 | 变更申请 | 变更审批中 | 医院账号 | Web | 合同变更申请 | +| 变更审批中 | 变更审批通过 | 履约中 | 医院账号 | Web | 变更生效 | +| 变更审批中 | 变更审批驳回 | 履约中 | 医院账号 | Web | 变更不生效 | +| 履约中 | 到期预警 | — | 系统自动 | Web | 合同到期前30/15/7天提醒 | +| 履约中 | 续签 | 履约中 | 医院账号 | Web | 续签审批流程 | +| 履约中 | 终止 | 已终止 | 医院账号 | Web | 合同终止 | + +> **所有合同相关操作均在Web端完成,无小程序端。每次操作自动记录操作日志。** + +--- + +## 2. 分段招标管理 — 招标流转(仅医院账号) + +> **物业公司不可操作此模块**,仅医院账号有全部权限。 + +### 2.1 招标状态流转图 + +``` + 招标计划 ──▶ 标段拆分 ──▶ 招标发布 ──▶ 投标截止 ──▶ 评标 ──▶ 定标审批 ──▶ 中标公示 ──▶ 生成合同 + (Web端) +``` + +### 2.2 招标流转规则 + +| 当前状态 | 操作 | 目标状态 | 执行角色 | 端侧 | 说明 | +|----------|------|----------|----------|------|------| +| — | 创建招标计划 | 计划中 | 医院账号 | Web | 关联项目,设置招标方式和时间节点 | +| 计划中 | 标段拆分 | 待发布 | 医院账号 | Web | 拆分为多个标段,设置范围和要求 | +| 待发布 | 发布招标 | 投标中 | 医院账号 | Web | 发布招标公告,邀请供应商 | +| 投标中 | 投标截止 | 评标中 | 系统自动/医院 | Web | 截止时间到达自动截止 | +| 评标中 | 评标完成 | 待定标 | 医院账号 | Web | 评分录入完成 | +| 待定标 | 定标审批 | 公示中 | 医院账号 | Web | 定标审批(仅Web端) | +| 公示中 | 公示期满 | 已定标 | 系统自动 | Web | 公示期后自动生效 | +| 已定标 | 生成合同 | — | 医院账号 | Web | 跳转合同管理创建合同 | + +> **所有招标相关操作均在Web端完成,无小程序端。每次操作自动记录操作日志。** +> **数据来源:** 供应商信息由医院账号在本系统中录入和管理,非外部系统导入。 + +--- + +## 3. 服务监督 — 数据查看流程 + +> 医院账号可查看关联物业公司的日常业务数据,**仅查看,不可操作**。 + +### 3.1 数据查看规则 + +| 查看内容 | 数据来源 | 说明 | +|----------|----------|------| +| 报修工单数据 | 物业公司报修模块 | 查看工单列表、详情、流转记录、照片附件(只读) | +| 巡检记录数据 | 物业公司巡检模块 | 查看巡检打卡记录、异常记录(只读) | +| 保洁任务数据 | 物业公司保洁模块 | 查看保洁任务完成情况、抽查结果(只读) | + +``` +医院账号登录Web端 + │ + 进入"服务监督"模块 + │ + 选择查看类型(报修/巡检/保洁) + │ + 查看关联物业公司的数据(只读,不可操作) + **数据来源:物业公司日常业务录入的数据** + │ + 支持筛选条件:时间范围、区域、状态等 + │ + 支持导出报表(只读) +``` + +> **关键规则:** 医院账号看到的是为其服务的物业公司全部日常数据,但只能查看,不能分配工单、审核补录等操作。 + +--- + +## 4. 服务评价 — 发起与查看流程 + +> 医院账号是评价的**发起方**,物业公司是评价的**接收和回复方**。 + +### 4.1 发起评价流程 + +``` +医院账号进入"服务评价"模块 + │ + 点击"发起评价" + │ + 选择评价类型(报修服务/巡检服务/保洁服务/综合评价) + │ + ┌─── 选择评价对象 ────────────────────────┐ + │ 选择关联的物业公司 │ + │ 选择具体服务(如某个工单/巡检/保洁任务) │ + │ **数据来源:物业公司业务数据(只读引用)** │ + └──────────────────────────────────────────┘ + │ + 填写评分(五分制)+ 文字留言 + │ + 提交评价 → 通知物业公司 + │ + ┌─── 评分触发规则 ────────────────────────┐ + │ 5分(非常满意)→ 无额外动作 │ + │ 4分(满意)→ 无额外动作 │ + │ 3分(一般)→ 物业主管关注 │ + │ 2分(不满意)→ 自动通知物业主管,要求回复 │ + │ 1分(非常不满意)→ 通知主管+管理员,24h内回复 │ + └──────────────────────────────────────────┘ +``` + +### 4.2 查看评价汇总 + +``` +医院账号进入"评价汇总" + │ + 查看各模块评价统计: + ├── 平均评分趋势 + ├── 星级分布 + ├── 各物业公司评分对比 + └── 历史评价列表 + │ + **数据来源:本医院发起的所有评价数据 + 物业公司的回复** +``` + +--- + +## 5. 统计报表 — 查看流程 + +``` +医院账号进入统计报表模块 + │ + 选择报表类型 + │ + ┌─── 业务数据报表(只读)────────────────────────────┐ + │ 报修统计:查看关联物业报修数据统计 │ + │ 巡检统计:查看关联物业巡检数据统计 │ + │ 保洁统计:查看关联物业保洁数据统计 │ + │ 评价统计:查看评价统计数据 │ + │ **数据来源:物业公司业务数据(只读)** │ + └────────────────────────────────────────────────────┘ + │ + ┌─── 合同/招标报表(可导出)──────────────────────┐ + │ 合同统计:合同金额、履约率等统计 │ + │ 招标统计:招标效率、成本对比等统计 │ + │ **数据来源:本系统合同/招标数据** │ + └────────────────────────────────────────────────────┘ + │ + ┌─── 综合看板 ────────────────────────────────┐ + │ 全局数据综合看板 │ + │ **数据来源:物业公司业务数据 + 本系统合同/招标数据** │ + └────────────────────────────────────────────────────┘ + │ + ┌─── 自定义报表 ──────────────────────────────┐ + │ 用户自选维度+指标生成报表 │ + │ **数据来源:综合上述所有数据** │ + └────────────────────────────────────────────────────┘ + │ + 选择时间维度(天/周/月/年/自定义) + │ + 生成报表 → 查看 + │ + 合同/招标/自定义报表支持导出(Excel/PDF) + 业务数据报表仅查看,不支持导出 +``` diff --git a/docs/03-业务流转逻辑-小程序端.md b/docs/03-业务流转逻辑-小程序端.md new file mode 100644 index 0000000..95b5a7a --- /dev/null +++ b/docs/03-业务流转逻辑-小程序端.md @@ -0,0 +1,417 @@ +# 微信小程序端 — 业务流转逻辑 + +> 版本:v4.0 +> 微信小程序仅供物业人员使用,**医院账号无小程序端**。 +> 不同角色登录后看到不同功能入口。 +> 关联文档:`01-模块划分.md`(v4.0)、`02-功能清单-小程序端.md` + +--- + +## 1. 登录与权限加载流程 + +### 1.1 首次登录 + +``` +用户打开小程序 + │ + 微信授权获取openid + │ + 绑定手机号(微信获取手机号组件) + │ + 系统匹配物业公司+人员信息 + **数据来源:物业公司Web端创建的下属账号(sys_user表)** + │ + ┌─── 匹配成功 ──┐ ┌─── 匹配失败 ──┐ + │ │ │ │ + 创建账号 提示"未找到关联信息,请联系管理员" + 进入工作台 无法使用 +``` + +### 1.2 再次登录 + +``` +打开小程序 + │ + 读取本地token + │ + ┌─── token有效 ──┐ ┌─── token无效 ──┐ + │ │ │ │ + 直接进入工作台 openid静默登录 + **数据来源:系统用户表自动匹配** + │ + 刷新token + │ + 进入工作台 +``` + +### 1.3 权限加载与界面渲染 + +``` +用户登录成功 + │ + 获取角色及权限集(四级粒度) + **数据来源:超级管理员定义的角色+物业公司管理员分配的角色** + │ + 根据权限动态渲染: + ├── 可见菜单项 + ├── 页面内可见功能点 + ├── 功能点可用动作(按钮显示/隐藏/禁用) + └── 数据范围(行级隔离) +``` + +--- + +## 2. 报修流程 + +### 2.1 报修人视角 + +``` +首页工作台 → 一键报修 + │ + 选择报修类型(数据来源:物业公司Web端配置的报修类型字典) + │ + 填写描述 + │ + 拍照上传(≤9张,含水印时间定位) + │ + 提交 → 生成工单 → 等待分配 + │ + 接收处理通知 + │ + 接收完工通知 → 评价(五分制+留言) +``` + +### 2.2 维修人员视角 + +``` +接收工单通知(小程序推送) + │ + 查看待处理工单列表 + **数据来源:物业公司Web端分配的工单,或自动分配** + │ + 接单 + │ + 处理维修 + │ + ┌─── 正常完工 ────────────────────┐ + │ 上传维修后照片 → 填写说明 → 提交 │ + │ → 工单状态变为"待验收" │ + └────────────────────────────────────┘ + │ + ┌─── 需要延期 ────────────────────┐ + │ 填写延期原因和预计完成时间 │ + │ → 工单状态变为"延期中" │ + │ → 等待主管审批 │ + │ **审批数据来源:主管在Web或小程序端审批** │ + └────────────────────────────────────┘ + │ + ┌─── 需要协助 ────────────────────┐ + │ 请求其他班组协助 │ + │ → 生成协助子工单 │ + │ → 等待协助完成 │ + └────────────────────────────────────┘ + │ + 等待验收 + **验收数据来源:主管或报修人在Web/小程序端验收** +``` + +### 2.3 主管视角(工单管理) + +``` +查看待分配工单列表 +**数据来源:报修人提交的工单(小程序端)+ Web端录入的工单** + │ + 工单分配(手动分配到班组/人员) + │ + 延期审批(审批维修人员延期申请) + **数据来源:维修人员在小程序端提交的延期申请** + │ + 工单验收 +``` + +--- + +## 3. 巡检流程(巡检人员视角) + +``` +查看今日巡检任务 +**数据来源:物业管理员在Web端创建的巡检计划自动生成** + │ + 到达巡检点位 + │ + 查询蓝牙策略配置 + **数据来源:系统配置的蓝牙策略(GET /system/bluetooth-policy → inspection_check_in)** + │ + ┌─── 策略=REQUIRED(强制蓝牙)───────────────────────────┐ + │ │ + │ 小程序自动扫描蓝牙Beacon │ + │ │ │ + │ ┌─── 检测到目标Beacon ───┐ ┌─── 未检测到 ────────────┐ │ + │ │ │ │ │ │ + │ │ 读取UUID │ 提示"未检测到蓝牙信号" │ │ + │ │ 连接蓝牙设备 │ │ │ │ + │ │ 连接成功即打卡 │ ┌─重试──▶ 重新扫描 │ │ + │ │ check_type=BLUETOOTH │ └─补录──▶ 进入补录模式 │ │ + │ │ **无需距离校验** │ │ │ │ + │ └─────────────────────────┘ 选择补录原因 │ │ + │ 手动填写巡检记录 │ │ + │ 提交补录申请 │ │ + │ **需主管审核(Web/小程序)**│ │ + └──────────────────────────────────────────────────────────┘ + │ + ┌─── 策略=OPTIONAL(非强制蓝牙)──────────────────────────┐ + │ │ + │ 用户选择打卡方式 │ + │ ┌───蓝牙打卡──┐───手动打卡──┐ │ + │ 扫描蓝牙 直接打卡 │ + │ check_type= check_type=MANUAL │ + │ BLUETOOTH │ + └──────────────────────────────────────────────────────────┘ + │ + 打卡成功后 → 逐项检查巡检清单 → 记录正常/异常 + │ + ┌─── 发现异常 ────────────────────────────────────┐ + │ 拍照上传 + 标记严重等级 │ + │ 可一键生成报修工单(数据写入报修模块) │ + └──────────────────────────────────────────────────┘ + │ + ┌─── 拍照(蓝牙策略=REQUIRED时)────────────────────┐ + │ 拍照也须在蓝牙连接状态下进行 │ + │ **拍照策略数据来源:GET /system/bluetooth-policy │ + │ → inspection_photo** │ + └──────────────────────────────────────────────────┘ +``` + +--- + +## 4. 保洁流程(保洁人员视角) + +``` +查看今日保洁任务 +**数据来源:物业管理员在Web端配置的排班自动生成** + │ + 到达保洁区域 + │ + 查询蓝牙策略配置 + **数据来源:系统配置的蓝牙策略(GET /system/bluetooth-policy → cleaning_check_in)** + │ + ┌─── 策略=REQUIRED(强制蓝牙)──────────────────────┐ + │ 蓝牙强制打卡确认(流程同巡检3.1) │ + │ check_type=BLUETOOTH │ + │ 未检测到蓝牙 → 进入补录模式(需主管审核) │ + └──────────────────────────────────────────────────────┘ + │ + ┌─── 策略=OPTIONAL(非强制蓝牙)─────────────────────┐ + │ 可选蓝牙打卡或手动打卡 │ + │ 手动打卡:check_type=MANUAL │ + └──────────────────────────────────────────────────────┘ + │ + 逐项完成保洁清单 → 上传完成后照片 + │ + ┌─── 发现异常 ─────────────────────────────┐ + │ 异常反馈 → 拍照上报 │ + └────────────────────────────────────────────┘ + │ + 任务完成 + │ + 主管抽查(数据来源:主管在小程序端标记) + ┌─合格─┐ ┌─不合格─┐ + 确认完成 重新生成任务 +``` + +--- + +## 5. 考勤打卡流程(员工视角) + +``` +到达班组打卡点 + │ + 查询蓝牙策略配置 + **数据来源:系统配置的蓝牙策略(GET /system/bluetooth-policy → attendance_check)** + │ + ┌─── 策略=REQUIRED(强制蓝牙)──────────────────────┐ + │ │ + │ 小程序自动扫描蓝牙Beacon │ + │ │ │ + │ ┌─── 检测到指定打卡点Beacon ───┐ │ + │ │ 验证Beacon属于本人班组打卡点 │ │ + │ │ 连接蓝牙成功 │ │ + │ │ 记录打卡时间+Beacon标识 │ │ + │ │ **打卡点数据来源:Web端配置的打卡点+蓝牙绑定** │ + │ │ 打卡成功 check_method=BLUETOOTH │ + │ └──────────────────────────────┘ │ + │ │ │ + │ ┌─── 未检测到打卡点蓝牙 ──────────┐ │ + │ │ 提示"未检测到打卡点蓝牙信号" │ │ + │ │ ┌─重试──▶ 重新扫描 │ │ + │ │ └─异常申诉──▶ 提交打卡异常申诉 │ │ + │ │ 选择异常原因(蓝牙故障/手机异常/系统异常/ │ + │ │ 忘记打卡/其他) │ + │ │ 补充说明(可上传照片) │ + │ │ 提交申诉 → 等待主管审核 │ + │ │ **审核数据来源:主管在Web/小程序端审核** │ + │ └──────────────────────────────────┘ │ + └──────────────────────────────────────────────────────┘ + │ + ┌─── 策略=OPTIONAL(非强制蓝牙)─────────────────────┐ + │ 可选蓝牙打卡或手动打卡 │ + │ 手动打卡:check_method=MANUAL │ + └──────────────────────────────────────────────────────┘ + │ + 打卡成功 → 记录操作日志 +``` + +### 5.1 打卡异常申诉审核流程 + +``` +员工提交打卡异常申诉(小程序端) + │ + 主管审核(Web+小程序均可) + **申诉数据来源:小程序端提交的异常申诉** + │ + ┌─审核通过─┐ ┌─审核驳回─┐ + 系统自动补录 通知员工 + 打卡记录 申诉未通过 + 标注"补录" 记录审核日志 + 记录审核日志 +``` + +--- + +## 6. 组织架构相关流程 + +``` +查看我的班组 +**数据来源:物业管理员在Web端配置的班组信息** + │ + 班组信息 + 班组成员列表 + │ + 查看我的排班 + **数据来源:物业管理员在Web端配置的排班数据** + │ + 个人排班日历 +``` + +--- + +## 7. 服务评价流程(报修人视角) + +``` +工单完工后收到评价通知 +**触发数据来源:物业公司在Web/小程序端验收通过** + │ + 打开待评价列表 + │ + 五分制评分 + 文字留言 + 图片上传 + │ + 提交评价 + │ + 物业公司可查看和回复(数据写入评价模块) + **评价数据来源:小程序端提交,物业公司Web端可查看回复** +``` + +--- + +## 8. 统计概览流程 + +### 8.1 管理员/主管视角 + +``` +进入工作台 → 简版统计概览 + │ + 按角色权限显示今日/本周关键指标: + ├── 报修:今日工单数/待处理/已完成 + ├── 巡检:今日任务数/已完成/异常 + ├── 保洁:今日任务数/已完成/超时 + └── 考勤:今日出勤率 + │ + **数据来源:物业公司各业务模块实时数据** +``` + +### 8.2 员工视角 + +``` +进入工作台 → 个人绩效统计 + │ + 个人工单量、评分、考勤 + **数据来源:报修模块工单数据 + 评价模块评分 + 考勤模块打卡数据** +``` + +--- + +## 9. 物业公司管理员小程序功能 + +``` +物业管理员登录小程序 + │ + 功能入口(与Web端对应,但功能简化): + ├── 报修管理:工单列表/分配/流转 + ├── 巡检管理:计划/看板/记录 + ├── 保洁管理:任务/排班/抽查 + ├── 考勤管理:记录/统计 + ├── 评价管理:查看/回复 + └── 组织架构查看:查看班组/人员 + │ + **所有数据来源:与Web端同一数据源,操作实时同步** +``` + +--- + +## 10. 小程序更新流程 + +``` +小程序启动 + │ + 调用后台接口获取最新版本号 + 最低兼容版本 + **数据来源:超级管理员在Web端配置的版本信息** + │ + 与本地版本号比较 + │ + ┌── 版本一致 ──▶ 正常使用 + │ + ┌── 小版本更新(兼容) ──▶ 提示"发现新版本,是否更新?" + │ │ + │ 用户确认 → 触发热更新/重启 + │ 用户取消 → 继续使用旧版 + │ + └── 大版本更新(不兼容) ──▶ 强制更新 + │ + 提示"版本过低,必须更新" + │ + 引导前往微信更新小程序 +``` + +**SDK依赖校验:** +- 启动时校验蓝牙SDK、微信SDK等关键依赖版本 +- 低于最低兼容版本时提示更新 +- 记录SDK版本信息到操作日志(便于排查问题) + +--- + +## 11. 审批流程(主管视角) + +``` +收到审批推送(小程序推送通知) +**推送数据来源:系统根据业务规则自动触发** + │ + 打开审批中心 + │ + 查看待审批列表 + │ + 查看详情 → 通过/驳回 + │ + 通知申请人 + │ + 记录审批操作日志 +``` + +**审批场景汇总:** + +| 审批场景 | 发起端 | 审批端 | 数据来源 | +|----------|--------|--------|----------| +| 工单延期审批 | 小程序(维修人员申请) | Web+小程序(主管审批) | 小程序端延期申请 | +| 工单分配 | Web+小程序(主管分配) | — | 报修人提交的工单 | +| 工单验收 | Web+小程序(主管/报修人) | — | 维修人员提交的完工 | +| 打卡异常审核 | 小程序(员工申诉) | Web+小程序(主管审核) | 小程序端异常申诉 | +| 数据补录审核 | 小程序(员工补录) | Web+小程序(主管审核) | 小程序端补录申请 | +| 保洁抽查 | 小程序(主管标记) | — | 保洁人员完成的任务 | diff --git a/docs/03-业务流转逻辑-物业公司.md b/docs/03-业务流转逻辑-物业公司.md new file mode 100644 index 0000000..244ae93 --- /dev/null +++ b/docs/03-业务流转逻辑-物业公司.md @@ -0,0 +1,363 @@ +# 物业公司 — 业务流转逻辑 + +> 版本:v4.0 +> 物业公司管理员负责绑定医院的日常业务管理,可创建下属人员账号并分配角色。 +> 端侧:Web端 + 微信小程序端(小程序端交互详见 `03-业务流转逻辑-小程序端.md`) +> 关联文档:`01-模块划分.md`(v4.0)、`02-功能清单-物业公司.md` + +--- + +## 1. 在线报修 — 工单流转 + +### 1.1 工单状态流转图 + +``` + 报修提交 ──▶ 待分配 ──▶ 处理中 ──▶ 待验收 ──▶ 已完成 + │ │ │ + ▼ ▼ ▼ + 已关闭 延期中 退单/返修 + (待审批) + │ + 延期审批 + 通过/驳回 +``` + +### 1.2 工单流转规则 + +| 当前状态 | 操作 | 目标状态 | 执行角色 | 端侧 | 说明 | +|----------|------|----------|----------|------|------| +| — | 提交报修 | 待分配 | 报修人 | 小程序 | 自动生成工单号,**数据来源:小程序端报修提交** | +| 待分配 | 分配工单 | 处理中 | 物业(主管)/系统 | Web+小程序 | 手动或自动 | +| 待分配 | 关闭工单 | 已关闭 | 物业(主管) | Web+小程序 | 无效报修 | +| 处理中 | 提交完工 | 待验收 | 维修人员 | 小程序 | 上传照片和说明,**数据来源:小程序端完工提交** | +| 处理中 | 申请延期 | 延期中 | 维修人员 | 小程序 | 填写原因和时间,**数据来源:小程序端延期申请** | +| 处理中 | 申请协助 | 处理中 | 维修人员 | 小程序 | 生成协助子工单,**数据来源:小程序端协助申请** | +| 延期中 | 审批通过 | 处理中 | 物业(主管) | Web+小程序 | 延长时限 | +| 延期中 | 审批驳回 | 处理中 | 物业(主管) | Web+小程序 | 须按时完成 | +| 待验收 | 验收通过 | 已完成 | 物业(主管/报修人) | Web+小程序 | 触发评价(**数据来源:医院发起评价,见医院端评价流程**) | +| 待验收 | 验收不通过 | 处理中 | 物业(主管/报修人) | Web+小程序 | 退回返修 | +| 已完成 | 评价 | 已完成 | 报修人 | 小程序 | 五分制+留言 | + +> **医院账号:** 仅查看工单数据(数据来源:物业公司的报修数据),不可操作。 +> **每次操作自动记录操作日志。** + +--- + +## 2. 巡检管理 — 任务流转 + +### 2.1 巡检计划与执行流程 + +``` +物业管理员创建巡检计划(Web端) + │ + 配置:区域、设备、频次、人员 + │ + 系统按计划自动生成每日巡检任务 + │ + 巡检人员执行(小程序端,详见小程序端流程) + │ + ┌─── 正常完成 ──────────────────┐ + │ 打卡+逐项检查 → 记录巡检结果 │ + │ 数据来源:小程序端巡检打卡 │ + └────────────────────────────────┘ + │ + ┌─── 异常上报 ──────────────────┐ + │ 拍照上传+标记严重等级 │ + │ 可一键生成报修工单 │ + │ → 触发报修流程(见1.2) │ + │ 数据来源:小程序端异常上报 │ + └────────────────────────────────┘ + │ + 物业管理员查看巡检记录(Web端) + │ + 异常跟踪 → 查看关联报修工单进度 +``` + +### 2.2 异常数据补录流程 + +``` +蓝牙失灵/定位失败/系统宕机(小程序端触发) + │ + 员工选择"补录模式"(小程序端操作) + │ + 选择补录原因(蓝牙故障/手机异常/系统异常/其他) + │ + 手动填写巡检记录(时间、位置、检查项) + │ + 提交补录申请 → 标记为"补录" → 记录操作日志 + **数据来源:小程序端补录提交** + │ + 主管审核(Web+小程序均可) + │ + ┌─审核通过─┐ ┌─审核驳回─┐ + 补录记录生效 通知员工重新执行 + 记录审核日志 记录审核日志 +``` + +### 2.3 补录数据标记规则 + +| 字段 | 值 | 说明 | +|------|------|------| +| is_supplement | true | 是否补录数据 | +| supplement_reason | 枚举值 | 蓝牙故障/系统异常/定位失败/其他 | +| supplement_remark | 文本 | 补录详细说明 | +| supplement_audit_status | 枚举值 | 待审核/通过/驳回 | +| supplement_auditor | 人员ID | 审核人 | +| supplement_audit_time | 时间 | 审核时间 | + +--- + +## 3. 保洁管理 — 任务流转 + +``` +物业管理员配置保洁区域(Web端) + │ + 五级架构:项目→区域→楼栋→楼层→区域责任人 + │ + 配置人员排班 + 蓝牙点位 + │ + 系统按排班自动生成每日保洁任务 + │ + 保洁人员执行(小程序端,详见小程序端流程) + │ + ┌─── 正常完成 ──────────────────────────┐ + │ 蓝牙打卡确认+完成保洁清单+上传照片 │ + │ 数据来源:小程序端保洁打卡 │ + └────────────────────────────────────────┘ + │ + ┌─── 超时未完成 ────────────────────────┐ + │ 系统自动预警 → 推送主管(小程序推送) │ + └────────────────────────────────────────┘ + │ + 主管抽查(Web+小程序) + │ + ┌─合格─┐ ┌─不合格─┐ + 任务完成 重新生成任务 +``` + +> 保洁异常数据补录流程与巡检一致(见2.2),补录数据来源为小程序端补录提交。 + +--- + +## 4. 组织架构 — 下属账号管理流程 + +``` +物业管理员进入"下属管理" + │ + 点击"新增下属" + │ + 填写基本信息:姓名、手机号、所属班组 + │ + 选择角色(数据来源:超级管理员定义的角色列表) + │ + ┌── 是否需要自定义权限?──┐ + │ │ + NO YES + │ │ + 直接创建 进入权限覆盖界面 + │ │ + 下属账号创建完成 在角色权限基础上调整(四级树形) + │ + 保存自定义权限 + │ + 下属账号创建完成 + │ + 记录操作日志和权限审计日志 +``` + +> **说明:** 物业下属人员不单独设有效期,随物业公司管理员账号到期而自动失效。 + +--- + +## 5. 考勤打卡 — 管理流程 + +``` +物业管理员配置打卡规则(Web端) + │ + ┌─── 打卡点管理 ──────────────────────────┐ + │ 按班组/角色设置不同上下班打卡点 │ + │ 绑定蓝牙Beacon(数据来源:系统配置-蓝牙设备) │ + └──────────────────────────────────────────┘ + │ + ┌─── 打卡规则 ────────────────────────────┐ + │ 设置上班/下班时间窗口 │ + │ 设置迟到/早退规则(可自定义) │ + └──────────────────────────────────────────┘ + │ + 员工打卡(小程序端操作,详见小程序端流程) + │ + 物业管理员查看考勤记录(Web端) + │ + ┌─── 异常审核 ──────────────────────────┐ + │ 员工提交的打卡异常申诉(数据来源:小程序端) │ + │ 主管审核通过 → 系统自动补录打卡记录 │ + │ 主管审核驳回 → 通知员工 │ + └──────────────────────────────────────────┘ + │ + ┌─── 数据补录 ──────────────────────────┐ + │ 对因系统/蓝牙异常导致的考勤缺失进行补录 │ + │ 标注补录标记和原因 │ + └──────────────────────────────────────────┘ +``` + +--- + +## 6. 服务评价 — 查看与回复流程 + +``` +服务完成(工单/巡检/保洁) + │ + 医院账号发起评价(数据来源:医院端评价流程,详见03-业务流转逻辑-医院.md) + │ + ┌─── 评价通知 ──────────────────────────┐ + │ 低评分(≤2分)→ 自动通知主管+物业管理员 │ + │ 2分 → 要求回复 │ + │ 1分 → 24h内必须回复 │ + └──────────────────────────────────────────┘ + │ + 物业管理员/主管查看评价(Web端) + │ + 评价回复 → 通知评价人(数据来源:医院账号的评价) + │ + 评价汇总看板 → 各模块平均评分、星级分布、评分趋势 + **数据来源:医院账号发起的评价数据** +``` + +| 评分 | 含义 | 物业端触发动作 | +|------|------|----------------| +| 5分 | 非常满意 | — | +| 4分 | 满意 | — | +| 3分 | 一般 | 主管关注 | +| 2分 | 不满意 | 自动通知主管,要求回复 | +| 1分 | 非常不满意 | 通知主管+物业管理员,24h内必须回复 | + +--- + +## 7. 统计报表 — 查询与导出流程 + +``` +物业管理员进入统计报表模块 + │ + 选择报表类型(报修/巡检/保洁/评价/考勤/综合看板/自定义) + │ + 选择时间维度(天/周/月/年/自定义) + │ + 选择筛选条件(区域/班组/人员/状态等,可自定义组合) + │ + 生成报表 → 展示图表+数据表格 + **数据来源:本系统各业务模块数据** + │ + 导出(Excel/PDF) → 记录导出操作日志 +``` + +--- + +## 8. 操作日志 — 记录与展示流程 + +### 8.1 日志记录范围 + +| 模块 | 记录的操作 | +|------|-----------| +| 在线报修 | 工单提交/分配/流转/延期/协助/验收 | +| 巡检管理 | 计划创建/打卡/异常上报/补录/补录审核 | +| 保洁管理 | 任务生成/打卡/抽查/补录/补录审核 | +| 考勤打卡 | 打卡/异常申诉/异常审核 | +| 服务评价 | 评价查看/回复 | +| 组织架构 | 下属账号创建/角色分配/权限覆盖 | +| 系统配置 | 蓝牙/字典/微信/消息模板配置变更 | + +### 8.2 日志展示形式 + +**时间轴视图:** +``` +┃ 2026-04-16 10:30:25 张三 提交了报修工单 #WX20260416001 +┃ 2026-04-16 10:15:10 李四 审批通过了延期申请 #DQ20260416003 +┃ 2026-04-16 09:45:00 王五 完成了巡检打卡 门诊楼1层 +┃ 2026-04-16 09:00:12 赵六 上班打卡 1号楼大厅 +▼ +``` + +**列表视图:** + +| 时间 | 操作人 | 模块 | 操作类型 | 操作内容 | 详情 | +|------|--------|------|----------|----------|------| +| 10:30:25 | 张三 | 报修 | 新增 | 提交工单 #WX... | 查看 | +| 10:15:10 | 李四 | 报修 | 审批 | 延期审批通过 #DQ... | 查看 | +| 09:45:00 | 王五 | 巡检 | 查看 | 巡检打卡 门诊楼1层 | 查看 | + +**日志详情(点击"查看"展开):** +``` +操作人:张三(水电维修班) +操作时间:2026-04-16 10:30:25 +操作IP:192.168.1.100 +操作模块:在线报修 → 工单列表 → 工单管理 → 新增 +操作内容:提交报修工单 #WX20260416001 +变更前数据:(无,新增操作) +变更后数据:{ "id": "WX20260416001", "type": "水电", ... } +请求参数:{ "type": "水电", "description": "3楼灯管不亮", ... } +响应状态:成功 +``` + +--- + +## 9. 系统配置管理流程 + +### 9.1 蓝牙设备管理 + +``` +物业管理员进入"蓝牙设备管理" + │ + Beacon列表(数据来源:系统已注册的蓝牙设备) + │ + 位置绑定 → 将Beacon绑定到具体巡检点位/保洁区域/打卡点 + │ + 状态监控 → 在线/离线状态实时展示 + │ + 电量预警 → Beacon电量低于阈值时预警提醒 +``` + +### 9.2 字典管理 + +``` +物业管理员进入"字典管理" + │ + 按模块维护字典数据: + ├── 报修类型(水电/木工/空调/其他...) + ├── 巡检类型(日常/专项/夜间...) + ├── 保洁类型(日常保洁/深度清洁/专项...) + └── 自定义字典 + │ + 字典数据仅对本物业公司(租户)可见 +``` + +### 9.3 消息模板管理 + +``` +物业管理员进入"消息模板" + │ + 配置微信模板消息: + ├── 新工单通知模板 + ├── 催单通知模板 + ├── 审批待办通知模板 + └── 其他自定义模板 + │ + 支持自定义模板变量(工单号、人员姓名、时间等) + │ + 消息发送记录可查询 +``` + +--- + +## 10. 异常场景处理汇总 + +| 场景 | 处理方式 | 补录要求 | 日志记录 | +|------|----------|----------|----------| +| 巡检蓝牙无信号(策略=REQUIRED) | 进入补录模式 | 填写原因,手动提交,主管审核 | 记录补录日志 | +| 巡检蓝牙无信号(策略=OPTIONAL) | 允许手动打卡 | check_type=MANUAL,无需补录 | 记录手动打卡日志 | +| 保洁蓝牙无信号(策略=REQUIRED) | 进入补录模式 | 填写原因,手动提交,主管审核 | 记录补录日志 | +| 保洁蓝牙无信号(策略=OPTIONAL) | 允许手动打卡 | check_type=MANUAL,无需补录 | 记录手动打卡日志 | +| 考勤蓝牙无信号(策略=REQUIRED) | 提交异常申诉 | 填写原因,主管审核 | 记录申诉日志 | +| 考勤蓝牙无信号(策略=OPTIONAL) | 允许手动打卡 | check_method=MANUAL,无需申诉 | 记录手动打卡日志 | +| 巡检定位偏差 | 手动确认打卡 | 系统标注"定位偏差" | 记录偏差日志 | +| 系统宕机 | 恢复后补录申请 | 注明宕机时间段,主管审核 | 记录补录日志 | +| 工单数据丢失 | Web端补录 | 标注补录标记和原因 | 记录补录日志 | diff --git a/docs/03-业务流转逻辑-超级管理员.md b/docs/03-业务流转逻辑-超级管理员.md new file mode 100644 index 0000000..049025e --- /dev/null +++ b/docs/03-业务流转逻辑-超级管理员.md @@ -0,0 +1,268 @@ +# 超级管理员 — 业务流转逻辑 + +> 版本:v4.0 +> 超级管理员负责平台运营,管理账号、权限与系统配置,**不查看业务数据**。 +> 端侧:仅Web端 +> 关联文档:`01-模块划分.md`(v4.0)、`02-功能清单-超级管理员.md` + +--- + +## 1. 新建使用单位流程 + +``` +超级管理员登录后台 + │ + 点击"新增使用单位" + │ + ┌─── 第1步:填写医院信息 ────────────────────────┐ + │ 医院名称 │ + │ 医院地址 │ + │ 院区列表(支持多院区): │ + │ ├── 院区1:主院区 / 地址 / 联系人 │ + │ ├── 院区2:东院区 / 地址 / 联系人 │ + │ └── 院区3:南院区 / 地址 / 联系人 │ + └───────────────────────────────────────────────────┘ + │ + ┌─── 第2步:填写物业公司信息 ──────────────────────┐ + │ 公司名称 / 公司地址 / 联系人 │ + └───────────────────────────────────────────────────┘ + │ + ┌─── 第3步:创建医院账号 ──────────────────────────┐ + │ 登录账号 / 初始密码 / 绑定医院 │ + │ 设置账号有效期(必填,到期日) │ + │ 分配角色(选择"医院查看模板"或其他预设模板) │ + └───────────────────────────────────────────────────┘ + │ + ┌─── 第4步:创建物业公司管理员账号 ─────────────────┐ + │ 登录账号 / 初始密码 / 绑定物业公司+医院 │ + │ 设置账号有效期(必填,到期日) │ + │ 分配角色(选择"物业管理员模板"或其他预设模板) │ + └───────────────────────────────────────────────────┘ + │ + 创建完成 → 自动记录操作日志 +``` + +--- + +## 2. 账号可用性控制流程 + +``` +超级管理员选择账号 → 启用/禁用 + │ + 禁用时: + → 账号立即无法登录 + → 已登录的session失效 + → 微信小程序端同步下线(数据来源:物业公司系统的下属账号) + → 保留所有历史数据 + → 记录操作日志 + │ + 启用时: + → 账号恢复正常登录 + → 可选重置密码 + → 记录操作日志 +``` + +--- + +## 3. 账号有效期与到期提醒流程 + +``` +超级管理员创建/编辑医院或物业公司账号 + │ + 设置账号有效期(到期日) + │ + 系统按到期提醒规则(超管在系统配置中设定的天数阈值)自动检测 + │ + 到期前N天,用户登录时弹出到期提醒弹窗 + │ + ┌─── 弹窗行为 ────────────────────────┐ + │ 提示"您的账号将于X天后到期" │ + │ 用户点击"我知道了"关闭弹窗 │ + │ 关闭后可正常使用,不影响功能 │ + └──────────────────────────────────────┘ + │ + 账号过期后 + │ + ┌─── 过期行为 ────────────────────────┐ + │ 账号禁止登录 │ + │ 超级管理员可手动续期恢复 │ + │ 记录续期操作日志 │ + └──────────────────────────────────────┘ +``` + +**到期账号管理流程:** +``` +超级管理员进入"到期账号管理" + │ + 查看即将到期/已过期账号列表(数据来源:本系统sys_user表) + │ + 选择账号 → 手动续期(修改有效期) + │ + 续期成功 → 账号恢复可用 → 记录操作日志 +``` + +> **说明:** 物业下属人员(主管/员工)不单独设有效期,随物业公司管理员账号到期而自动失效。 + +--- + +## 4. 角色定义与权限分配流程 + +``` +超级管理员进入"权限管理" + │ + ┌─── 第1步:创建角色 ──────────────────────┐ + │ 角色名称(自定义) │ + │ 角色描述 │ + │ 适用范围(医院账号/物业管理员/物业下属) │ + │ 选择预设模板(可选,选择后自动填充权限) │ + └──────────────────────────────────────────┘ + │ + ┌─── 第2步:分配权限(四级树形勾选) ────────────────────────┐ + │ ☑ 功能菜单:在线报修 │ + │ ├── ☑ 页面:工单列表 │ + │ │ ├── ☑ 功能点:工单管理 │ + │ │ │ ├── ☑ 查看 ☑ 新增 ☑ 编辑 │ + │ │ │ ├── ☐ 删除 ☐ 审批 ☑ 导出 ☑ 分配 │ + │ │ └── ☑ 功能点:批量操作 │ + │ │ ├── ☑ 查看 ☑ 新增 ☐ 编辑 │ + │ │ └── ☐ 删除 ☐ 审批 ☐ 导出 ☐ 分配 │ + │ ├── ☑ 页面:工单详情 │ + │ │ ├── ☑ 功能点:延期审批 │ + │ │ │ ├── ☑ 查看 ☐ 新增 ☐ 编辑 │ + │ │ │ └── ☐ 删除 ☑ 审批 ☐ 导出 ☐ 分配 │ + │ │ └── ☑ 功能点:工单验收 │ + │ │ ├── ☑ 查看 ☐ 新增 ☐ 编辑 │ + │ │ └── ☐ 删除 ☑ 审批 ☐ 导出 ☐ 分配 │ + │ └── ☐ 页面:报修类型管理 │ + │ ... │ + │ ☐ 功能菜单:巡检管理 │ + │ ... │ + └───────────────────────────────────────────────────────────┘ + │ + ┌─── 第3步:保存角色 ──────────────────────┐ + │ 记录权限审计日志(变更前后对比) │ + │ 权限实时生效 │ + └──────────────────────────────────────────┘ +``` + +--- + +## 5. 权限自动同步流程 + +``` +开发人员新增功能(菜单/页面/功能点) + │ + 在权限配置表中注册: + menu_code: "repair" + menu_name: "在线报修" + page_code: "repair_list" + page_name: "工单列表" + action_code: "repair_list_manage" + action_name: "工单管理" + available_actions: ["view","create","update","delete","approve","export","assign"] + │ + 系统启动时自动扫描权限配置表 + │ + 权限管理页面自动渲染新的可勾选项 + │ + 超级管理员可为角色分配新权限 + │ + 记录权限变更审计日志 +``` + +--- + +## 6. 权限实时生效流程 + +``` +权限变更操作(超级管理员修改角色权限) + │ + 更新数据库权限记录 + │ + 发送权限变更事件(Redis Pub/Sub + Spring Event,毫秒级生效) + │ + 所有服务实例接收事件 → 刷新本地权限缓存 + │ + 已登录用户下次操作时自动加载新权限(无需重新登录) + │ + Web端:下次页面跳转/刷新时加载新权限 → 动态更新菜单和按钮 + │ + 小程序端(数据来源:物业公司的下属人员):下次接口请求时返回新权限集 → 动态更新界面 + │ + 记录权限审计日志 +``` + +--- + +## 7. 数据权限校验流程 + +``` +用户发起操作请求 + │ + ┌── 第1层:功能权限校验 ──┐ + │ 用户是否有该功能点的对应动作权限? │ + │ → 否:返回403,提示无权限 │ + └────────────────────────┘ + │ (是) + ┌── 第2层:数据权限校验 ──┐ + │ 超级管理员 → 仅系统配置与账号数据 │ + │ 医院账号 → 本医院+关联物业公司数据 │ + │ 物业管理员 → 绑定医院数据 │ + │ 主管 → 本班组数据 │ + │ 员工 → 仅本人数据 │ + │ │ + │ → 自动在SQL中注入数据范围条件 │ + │ → 超出范围的数据不可见 │ + └────────────────────────┘ +``` + +> **关键规则:** 超级管理员仅可查看系统配置与账号数据,**不涉及任何业务数据**(报修、巡检、保洁、考勤、评价、合同、招标等)。 + +--- + +## 8. 操作日志流程 + +### 8.1 日志记录范围 + +| 模块 | 记录的操作 | +|------|-----------| +| 权限管理 | 角色创建/修改/删除、权限分配/变更 | +| 账号管理 | 账号创建/启停/续期/有效期修改 | +| 系统管理 | 配置变更/缓存清理/版本管理 | + +### 8.2 权限审计日志特殊展示 + +权限变更日志额外展示变更前后对比: + +``` +角色:巡检主管 +操作人:超级管理员 +操作时间:2026-04-16 14:00:00 +操作类型:权限修改 + +变更对比: + [+新增] 在线报修 → 工单详情 → 延期审批 → 审批 + [+新增] 在线报修 → 工单列表 → 工单管理 → 导出 + [-移除] 巡检管理 → 巡检计划 → 计划管理 → 删除 +``` + +--- + +## 9. 系统更新与缓存策略 + +``` +后台系统发布更新 + │ + 自动执行缓存清理: + ├── 清除权限缓存 → 重新从数据库加载 + ├── 清除字典缓存 → 重新加载字典数据 + ├── 清除菜单缓存 → 重新加载菜单配置 + └── 清除业务数据缓存 → 按需懒加载 + │ + 缓存清理方式: + ├── 自动:系统启动时全量清理 + ├── 手动:超管在"缓存管理"页面按模块清理 + └── 事件驱动:权限变更时定向清理权限缓存 + │ + 通知在线用户刷新页面(WebSocket推送) +``` diff --git a/docs/04-开发与测试规范.md b/docs/04-开发与测试规范.md new file mode 100644 index 0000000..1306819 --- /dev/null +++ b/docs/04-开发与测试规范.md @@ -0,0 +1,361 @@ +# 医院物业SaaS管理后台 — 开发与测试规范 + +> 版本:v1.0 +> 定位:开发团队统一规范,所有开发人员必须严格遵守 +> 日期:2026-04-16 + +--- + +## 一、后端开发规范 + +### 1.1 代码分层规范 + +``` +Controller层:接收请求、参数校验、调用Service、返回响应 + ↓ +Service层:业务逻辑编排、事务管理、权限校验 + ↓ +Repository层:数据访问(MyBatis-Plus Mapper) +``` + +**严格分离原则**: + +| 类型 | 用途 | 位置 | +|------|------|------| +| DTO | 接收请求参数 | `dto/request/` | +| VO | 返回响应数据 | `dto/response/` | +| Entity | 数据库映射 | `entity/` | +| 禁止 | Controller直接返回Entity | — | +| 禁止 | Service层接收HttpServletRequest | — | + +### 1.2 命名规范 + +| 对象 | 规范 | 示例 | +|------|------|------| +| 包名 | 全小写,模块开头 | `com.hospital.mgmt.modules.repair` | +| 类名 | 大驼峰 | `RepairOrderService` | +| 方法名 | 小驼峰,动词开头 | `createOrder`, `getById`, `listByStatus` | +| 常量 | 全大写下划线 | `MAX_UPLOAD_SIZE` | +| 数据库表名 | 小写下划线,模块前缀 | `repair_order`, `inspection_task` | +| 数据库字段 | 小写下划线 | `created_at`, `tenant_id` | +| 枚举值 | 全大写下划线 | `ACTIVE`, `PENDING` | +| API路径 | 小写连字符,资源复数 | `/repair-orders`, `/check-in` | + +### 1.3 数据库规范 + +- 所有业务表必须包含 `tenant_id` 字段 +- 主键使用雪花算法生成 BIGINT +- 逻辑删除:`deleted` 字段(0-正常,1-已删除) +- 枚举值存储为 VARCHAR,禁止使用数字枚举 +- JSON 字段用于存储动态配置(如 `check_items`, `skills`),禁止存储核心查询字段 +- 索引规范: + - 所有表自动在 `tenant_id` 上建立索引 + - 业务编码字段建立唯一索引 + - 状态+时间组合查询建立复合索引 + - 禁止在 JSON 字段上建索引 + +### 1.4 模块开发规范 + +- 详见 `05-接口规范.md` IModulePlugin 规范 +- 每个模块必须实现 `IModulePlugin` 接口 +- 模块目录结构: + ``` + modules/{module-code}/ + ├── {ModuleCode}Module.java # IModulePlugin实现类 + ├── config/ # 模块配置 + ├── controller/ # REST控制器 + ├── service/ # 业务服务 + ├── entity/ # 数据实体 + ├── dto/ # 数据传输对象 + ├── repository/ # 数据访问层 + ├── event/ # 模块事件 + └── resources/ + ├── module.yml # 模块描述文件 + └── db/migration/ # 数据库迁移脚本 + ``` +- 模块间通信必须通过 Spring Event,禁止跨模块直接调用 Service +- 新模块上线前必须通过审核清单(详见 `05-接口规范.md` 模块安全规范) + +### 1.5 审计日志规范 + +- 所有写操作自动记录审计日志(AOP 切面统一处理) +- 业务代码中只需在 Controller 方法上添加 `@AuditLog` 注解 +- 记录内容自动采集:操作人、时间、IP、模块、操作类型 +- 变更前后数据快照:UPDATE/DELETE 操作自动对比记录 +- 禁止在业务代码中手动记录审计日志 + +--- + +## 二、前端开发规范(Vue 3 + TypeScript) + +### 2.1 组件规范 + +| 规范项 | 要求 | +|--------|------| +| 组件命名 | 大驼峰,多词组合(`RepairOrderList.vue`) | +| 组件结构 | `