From f0493f9817d5dd1514069c4267b567e9a0699b04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=AA=A6=E4=BF=8A?= <2086707613@qq.com> Date: Mon, 6 Jul 2026 08:02:40 +0800 Subject: [PATCH] 1 --- ...71\346\216\245\346\214\207\345\215\227.md" | 878 ++++++++++++++ ...56\350\256\241\345\210\222\344\271\246.md" | 1050 ++++++++++++++++ ...06\346\236\220\346\212\245\345\221\212.md" | 289 +++++ ...75\350\256\241\345\210\222\344\271\246.md" | 1057 +++++++++++++++++ .../backend/FangCollaboration.sln" | 43 + .../Fang.Api/Controllers/AdminController.cs" | 188 +++ .../Controllers/ApprovalController.cs" | 151 +++ .../Fang.Api/Controllers/AuthController.cs" | 93 ++ .../Controllers/CalendarController.cs" | 118 ++ .../Controllers/ContactsController.cs" | 104 ++ .../Fang.Api/Controllers/DocsController.cs" | 121 ++ .../Fang.Api/Controllers/DriveController.cs" | 116 ++ .../src/Fang.Api/Controllers/ImController.cs" | 140 +++ .../Controllers/MeetingController.cs" | 101 ++ .../Controllers/NotificationController.cs" | 91 ++ .../backend/src/Fang.Api/Fang.Api.csproj" | 23 + .../Filters/ValidateModelAttribute.cs" | 26 + .../backend/src/Fang.Api/Hubs/ImHub.cs" | 163 +++ .../backend/src/Fang.Api/Hubs/MeetingHub.cs" | 223 ++++ .../ExceptionHandlingMiddleware.cs" | 62 + .../Middleware/RequestLoggingMiddleware.cs" | 46 + .../backend/src/Fang.Api/Program.cs" | 269 +++++ .../backend/src/Fang.Api/appsettings.json" | 46 + .../backend/src/Fang.Common/Constants.cs" | 120 ++ .../src/Fang.Common/DTOs/AdminDTOs.cs" | 96 ++ .../src/Fang.Common/DTOs/ApiResponse.cs" | 28 + .../src/Fang.Common/DTOs/ApprovalDTOs.cs" | 69 ++ .../backend/src/Fang.Common/DTOs/AuthDTOs.cs" | 56 + .../DTOs/CalendarBusyPeriodDto.cs" | 8 + .../src/Fang.Common/DTOs/CalendarDTOs.cs" | 44 + .../src/Fang.Common/DTOs/ContactsDTOs.cs" | 32 + .../backend/src/Fang.Common/DTOs/DocsDTOs.cs" | 59 + .../src/Fang.Common/DTOs/DriveDTOs.cs" | 47 + .../backend/src/Fang.Common/DTOs/ImDTOs.cs" | 47 + .../src/Fang.Common/DTOs/MeetingDTOs.cs" | 42 + .../src/Fang.Common/Extensions/Extensions.cs" | 70 ++ .../src/Fang.Common/Fang.Common.csproj" | 13 + .../src/Fang.Core/Entities/AdminLog.cs" | 14 + .../Fang.Core/Entities/ApprovalAddSign.cs" | 14 + .../src/Fang.Core/Entities/ApprovalForm.cs" | 16 + .../Fang.Core/Entities/ApprovalInstance.cs" | 19 + .../src/Fang.Core/Entities/ApprovalNode.cs" | 19 + .../Fang.Core/Entities/ApprovalTransfer.cs" | 14 + .../Fang.Core/Entities/CalendarAttendee.cs" | 12 + .../src/Fang.Core/Entities/CalendarEvent.cs" | 22 + .../src/Fang.Core/Entities/CalendarShare.cs" | 12 + .../src/Fang.Core/Entities/Contact.cs" | 12 + .../src/Fang.Core/Entities/DataDict.cs" | 14 + .../src/Fang.Core/Entities/Department.cs" | 18 + .../backend/src/Fang.Core/Entities/Doc.cs" | 18 + .../src/Fang.Core/Entities/DocComment.cs" | 19 + .../src/Fang.Core/Entities/DocShare.cs" | 12 + .../src/Fang.Core/Entities/DocVersion.cs" | 13 + .../src/Fang.Core/Entities/DriveFile.cs" | 21 + .../src/Fang.Core/Entities/DriveShare.cs" | 15 + .../src/Fang.Core/Entities/ImChannel.cs" | 17 + .../Fang.Core/Entities/ImChannelMember.cs" | 11 + .../src/Fang.Core/Entities/ImMessage.cs" | 18 + .../src/Fang.Core/Entities/ImMessageRead.cs" | 10 + .../src/Fang.Core/Entities/Meeting.cs" | 22 + .../Fang.Core/Entities/MeetingParticipant.cs" | 14 + .../src/Fang.Core/Entities/Notification.cs" | 14 + .../src/Fang.Core/Entities/Permission.cs" | 14 + .../backend/src/Fang.Core/Entities/Role.cs" | 14 + .../src/Fang.Core/Entities/RolePermission.cs" | 9 + .../backend/src/Fang.Core/Entities/User.cs" | 21 + .../src/Fang.Core/Events/DomainEvents.cs" | 91 ++ .../backend/src/Fang.Core/Fang.Core.csproj" | 27 + .../src/Fang.Core/Interfaces/IJwtService.cs" | 49 + .../Fang.Core/Interfaces/IRepositories.cs" | 130 ++ .../src/Fang.Core/Interfaces/IServices.cs" | 130 ++ .../src/Fang.Core/Interfaces/IServices2.cs" | 42 + .../src/Fang.Core/Services/AdminService.cs" | 226 ++++ .../Fang.Core/Services/ApprovalService.cs" | 163 +++ .../src/Fang.Core/Services/AuthService.cs" | 181 +++ .../Fang.Core/Services/CalendarService.cs" | 104 ++ .../Fang.Core/Services/ContactsService.cs" | 104 ++ .../src/Fang.Core/Services/DocsService.cs" | 150 +++ .../src/Fang.Core/Services/DriveService.cs" | 123 ++ .../src/Fang.Core/Services/ImService.cs" | 144 +++ .../src/Fang.Core/Services/JwtService.cs" | 185 +++ .../src/Fang.Core/Services/MeetingService.cs" | 153 +++ .../Services/NotificationService.cs" | 56 + .../Cache/RedisCacheService.cs" | 69 ++ .../Data/ApplicationDbContext.cs" | 311 +++++ .../Fang.Infrastructure.csproj" | 30 + .../Messaging/RabbitMQService.cs" | 87 ++ .../20240101000000_InitialCreate.cs" | 434 +++++++ .../ApplicationDbContextModelSnapshot.cs" | 25 + .../Migrations/IMigrationRepository.cs" | 329 +++++ .../Repositories/AdminRepository.cs" | 153 +++ .../Repositories/ApprovalRepository.cs" | 95 ++ .../Repositories/CalendarRepository.cs" | 99 ++ .../Repositories/DocsRepository.cs" | 93 ++ .../Repositories/DriveRepository.cs" | 79 ++ .../Repositories/ImRepository.cs" | 126 ++ .../Repositories/MeetingRepository.cs" | 96 ++ .../Repositories/NotificationRepository.cs" | 75 ++ .../Repositories/UserRepository.cs" | 151 +++ .../Search/ElasticsearchService.cs" | 49 + .../Storage/MinioStorageService.cs" | 145 +++ .../Fang.Core.Tests/Fang.Core.Tests.csproj" | 28 + .../deploy/docker/Dockerfile" | 42 + .../deploy/docker/docker-compose.dev.yml" | 91 ++ .../deploy/docker/docker-compose.prod.yml" | 135 +++ .../deploy/docker/nginx.conf" | 70 ++ .../docs/api/README.md" | 173 +++ 107 files changed, 11620 insertions(+) create mode 100644 ".gitee/\345\220\216\347\253\257\345\274\200\345\217\221\345\256\214\346\210\220\350\257\264\346\230\216_\345\211\215\347\253\257\345\257\271\346\216\245\346\214\207\345\215\227.md" create mode 100644 "\344\274\201\344\270\232\345\215\217\344\275\234\345\212\236\345\205\254\345\271\263\345\217\260\351\241\271\347\233\256\350\256\241\345\210\222\344\271\246.md" create mode 100644 "\345\220\216\347\253\257\345\256\236\347\216\260\345\267\256\350\267\235\345\210\206\346\236\220\346\212\245\345\221\212.md" create mode 100644 "\346\240\270\345\277\203\345\212\237\350\203\275\350\256\241\345\210\222\344\271\246.md" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/FangCollaboration.sln" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Api/Controllers/AdminController.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Api/Controllers/ApprovalController.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Api/Controllers/AuthController.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Api/Controllers/CalendarController.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Api/Controllers/ContactsController.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Api/Controllers/DocsController.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Api/Controllers/DriveController.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Api/Controllers/ImController.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Api/Controllers/MeetingController.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Api/Controllers/NotificationController.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Api/Fang.Api.csproj" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Api/Filters/ValidateModelAttribute.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Api/Hubs/ImHub.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Api/Hubs/MeetingHub.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Api/Middleware/ExceptionHandlingMiddleware.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Api/Middleware/RequestLoggingMiddleware.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Api/Program.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Api/appsettings.json" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Common/Constants.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Common/DTOs/AdminDTOs.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Common/DTOs/ApiResponse.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Common/DTOs/ApprovalDTOs.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Common/DTOs/AuthDTOs.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Common/DTOs/CalendarBusyPeriodDto.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Common/DTOs/CalendarDTOs.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Common/DTOs/ContactsDTOs.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Common/DTOs/DocsDTOs.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Common/DTOs/DriveDTOs.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Common/DTOs/ImDTOs.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Common/DTOs/MeetingDTOs.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Common/Extensions/Extensions.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Common/Fang.Common.csproj" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/AdminLog.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/ApprovalAddSign.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/ApprovalForm.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/ApprovalInstance.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/ApprovalNode.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/ApprovalTransfer.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/CalendarAttendee.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/CalendarEvent.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/CalendarShare.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/Contact.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/DataDict.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/Department.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/Doc.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/DocComment.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/DocShare.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/DocVersion.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/DriveFile.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/DriveShare.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/ImChannel.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/ImChannelMember.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/ImMessage.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/ImMessageRead.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/Meeting.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/MeetingParticipant.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/Notification.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/Permission.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/Role.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/RolePermission.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Entities/User.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Events/DomainEvents.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Fang.Core.csproj" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Interfaces/IJwtService.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Interfaces/IRepositories.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Interfaces/IServices.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Interfaces/IServices2.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Services/AdminService.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Services/ApprovalService.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Services/AuthService.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Services/CalendarService.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Services/ContactsService.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Services/DocsService.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Services/DriveService.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Services/ImService.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Services/JwtService.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Services/MeetingService.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Core/Services/NotificationService.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Infrastructure/Cache/RedisCacheService.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Infrastructure/Data/ApplicationDbContext.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Infrastructure/Fang.Infrastructure.csproj" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Infrastructure/Messaging/RabbitMQService.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Infrastructure/Migrations/20240101000000_InitialCreate.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Infrastructure/Migrations/ApplicationDbContextModelSnapshot.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Infrastructure/Migrations/IMigrationRepository.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Infrastructure/Repositories/AdminRepository.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Infrastructure/Repositories/ApprovalRepository.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Infrastructure/Repositories/CalendarRepository.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Infrastructure/Repositories/DocsRepository.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Infrastructure/Repositories/DriveRepository.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Infrastructure/Repositories/ImRepository.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Infrastructure/Repositories/MeetingRepository.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Infrastructure/Repositories/NotificationRepository.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Infrastructure/Repositories/UserRepository.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Infrastructure/Search/ElasticsearchService.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/src/Fang.Infrastructure/Storage/MinioStorageService.cs" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/backend/tests/Fang.Core.Tests/Fang.Core.Tests.csproj" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/deploy/docker/Dockerfile" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/deploy/docker/docker-compose.dev.yml" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/deploy/docker/docker-compose.prod.yml" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/deploy/docker/nginx.conf" create mode 100644 "\351\243\236\344\271\246(\345\220\216\347\253\257)/docs/api/README.md" diff --git "a/.gitee/\345\220\216\347\253\257\345\274\200\345\217\221\345\256\214\346\210\220\350\257\264\346\230\216_\345\211\215\347\253\257\345\257\271\346\216\245\346\214\207\345\215\227.md" "b/.gitee/\345\220\216\347\253\257\345\274\200\345\217\221\345\256\214\346\210\220\350\257\264\346\230\216_\345\211\215\347\253\257\345\257\271\346\216\245\346\214\207\345\215\227.md" new file mode 100644 index 0000000..e9f44d0 --- /dev/null +++ "b/.gitee/\345\220\216\347\253\257\345\274\200\345\217\221\345\256\214\346\210\220\350\257\264\346\230\216_\345\211\215\347\253\257\345\257\271\346\216\245\346\214\207\345\215\227.md" @@ -0,0 +1,878 @@ +# 🚀 后端开发完成说明 & 前端对接指南 + +> 本文档由**后端开发 A** 编写,供**前端 B(PC Web)** 和**前端 C(移动端/小程序/PC 客户端)** 参考。 +> **版本**:v2.0(基于 2026-07-04 差距分析报告更新) +> **总体完成度**:约 75%(架构 100%,核心 CRUD 90%+,高级功能部分待补) + +--- + +## 📋 目录 + +1. [后端已交付内容清单](#1-后端已交付内容清单) +2. [✅ 可立即对接的功能 vs ⚠️ 待补的功能](#2-可立即对接的功能-vs--待补的功能) +3. [如何启动后端服务](#3-如何启动后端服务) +4. [接口地址约定](#4-接口地址约定) +5. [通用规范](#5-通用规范) +6. [鉴权与 JWT](#6-鉴权与-jwt) +7. [各模块对接详解](#7-各模块对接详解) +8. [SignalR 实时通信对接](#8-signalr-实时通信对接) +9. [错误码对照表](#9-错误码对照表) +10. [下一步分工建议](#10-下一步分工建议) +11. [联系方式 & 协作约定](#11-联系方式--协作约定) + +--- + +## 1. 后端已交付内容清单 + +### ✅ 已完成(核心架构) + +| 项目 | 状态 | 位置 | +|------|------|------| +| 解决方案搭建 | ✅ | `backend/FangCollaboration.sln` | +| 4 个项目分层 | ✅ | `Fang.Api` / `Fang.Core` / `Fang.Infrastructure` / `Fang.Common` | +| **29 个实体建模**(22 核心 + 7 辅助) | ✅ | `backend/src/Fang.Core/Entities/` | +| EF Core DbContext + 实体映射 | ✅ | `backend/src/Fang.Infrastructure/Data/ApplicationDbContext.cs` | +| **11 个 Service**(10 业务 + JwtService) | ✅ | `backend/src/Fang.Core/Services/` | +| **10 个 REST Controller**(Swagger 暴露 **64 个接口**) | ✅ | `backend/src/Fang.Api/Controllers/` | +| **9 个仓储实现**(含 Dapper 高性能查询) | ✅ | `backend/src/Fang.Infrastructure/Repositories/` | +| **2 个 SignalR Hub**(IM + 会议) | ✅ | `backend/src/Fang.Api/Hubs/` | +| **JWT 鉴权(真实实现)** | ✅ | `JwtService.cs` + `Program.cs`(已修复硬编码密钥) | +| **RefreshToken 刷新(真实实现)** | ✅ | 已修复"永远返回 null"问题 | +| Swagger OpenAPI 文档 | ✅ | `http://localhost:5000/swagger` | +| 全局异常处理 + 请求日志中间件 | ✅ | `Middleware/` | +| **健康检查端点** | ✅ | `GET /health` | +| Serilog 结构化日志 | ✅ | 文件输出 `logs/app-.log` | +| Redis 缓存服务 | ✅ | `Infrastructure/Cache/RedisCacheService.cs` | +| MinIO 文件存储服务 | ✅ | `Infrastructure/Storage/MinioStorageService.cs` | +| RabbitMQ 消息队列服务 | ✅ | `Infrastructure/Messaging/RabbitMQService.cs` | +| Elasticsearch 搜索服务 | ⚠️ 桩实现 | SDK 8 API 兼容性,已实现接口契约 | +| Docker Compose 一键启动中间件 | ✅ | `deploy/docker/docker-compose.dev.yml` | +| Docker 镜像构建 + Nginx 配置 | ✅ | `deploy/docker/Dockerfile` + `nginx.conf` | +| **后端可成功启动 + 64 个接口全注册** | ✅ | 已验证 | + +### 🚧 框架已搭但业务实现不完整(前端需注意) + +| 功能 | 状态 | 影响 | 建议 | +|------|------|------|------| +| 用户 SSO 登录(飞书/钉钉/企微) | ❌ `throw NotImplementedException` | `/api/auth/sso/callback` 会 500 | 暂跳过,前端用账号密码登录 | +| 找回密码 | ❌ `throw NotImplementedException` | `/api/auth/forgot-password` 会 500 | 暂跳过 | +| 密码重置 | ❌ `throw NotImplementedException` | `/api/auth/reset-password` 会 500 | 暂跳过 | +| 联系人增删改查 | ❌ 3 个方法 NotImplemented | `/api/contacts/contacts*` 会 500 | **前端暂时屏蔽联系人页面** | +| 文档协同编辑(多人实时) | ❌ 无 DocHub | 当前是单人编辑 | 暂用单人模式,前端不需要 SignalR 监听 | +| 文档评论修改/删除/解决 | ❌ 缺接口 | `/api/docs/{id}/comments/*` 只能增查 | 暂只实现增查 | +| 文档版本回滚/对比 | ❌ 缺接口 | 只能查看历史版本 | 暂只查看 | +| 审批「转交」 | ❌ NotImplemented | `/instances/{id}/transfer` 会 500 | 暂跳过该按钮 | +| 审批「加签」 | ❌ NotImplemented | `/instances/{id}/add-sign` 会 500 | 暂跳过该按钮 | +| 日历「共享」 | ❌ NotImplemented | `/api/calendar/share` 会 500 | 暂跳过 | +| Drive「移动文件」 | ❌ NotImplemented | `/api/drive/files/{id}/move` 会 500 | 暂跳过 | +| Drive「分享文件」 | ⚠️ 内存生成 token 未落库 | 重启后 token 失效 | 暂使用,后续补 | +| 实际音视频编解码 | ❌ 未实现 | 需前端集成声网/TRTC | 后端只提供信令通道 | + +### ✅ 已修复的关键 Bug + +| Bug | 修复前 | 修复后 | +|-----|--------|--------| +| **Drive MinIO 对象名错位** | 上传用 `fileName`,存 Path 用 `objectName`,下载必然失败 | 统一使用 `drive/{userId}/{Guid}{ext}` 一致对象名 | +| **JWT 密钥硬编码** | 64 位密钥写死在源码中 | 通过 `IConfiguration` 注入,启动时强校验 ≥32 字符 | +| **RefreshToken 永远返回 null** | `RefreshTokens()` 直接 return null | 完整实现 Redis 双向映射 + Refresh Token 轮换 | + +--- + +## 2. ✅ 可立即对接的功能 vs ⚠️ 待补的功能 + +### 🟢 可立即对接(建议优先级 P0) + +| 模块 | 可对接接口 | 完成度 | +|------|----------|--------| +| **用户认证** | login、register、userinfo、refresh | 90% | +| **通讯录** | org-tree、departments、users、users/{id} | 100% | +| **IM 即时通讯** | 全部 7 个 REST 接口 + SignalR Hub | 90% | +| **协同文档** | CRUD + 版本查看 + 评论增查(CR 缺 U D) | 70% | +| **日历** | events CRUD + busy + shared | 85% | +| **视频会议** | CRUD + 加入/离开 + SignalR 信令 | 92% | +| **云盘** | CRUD + 上传下载(已修复对象名) + 文件夹 | 80% | +| **审批** | 表单 CRUD + 提交 + 通过/拒绝 + 待办 + 我的提交 | 60% | +| **通知** | 增删改查 + 已读 + 未读数(仅站内信) | 65% | +| **管理后台** | 用户/角色/字典/日志 CRUD | 70% | + +### 🟡 需要后端补全后再对接 + +- SSO 三方登录 +- 找回密码 / 密码重置 +- 文档协同编辑(多人同时编辑) +- 审批「转交」「加签」 +- 实际音视频流(需对接声网/TRTC SDK) + +--- + +## 3. 如何启动后端服务 + +### 3.1 启动中间件(前端无需操作,但需确认后端已启动) + +```bash +cd deploy/docker +docker compose -f docker-compose.dev.yml up -d +``` + +启动以下中间件: +- PostgreSQL (5432) +- Redis (6379) +- MinIO (9000/9001) +- RabbitMQ (5672/15672) +- Elasticsearch (9200) + +### 3.2 启动后端 + +```bash +cd backend +dotnet restore +ASPNETCORE_ENVIRONMENT=Development dotnet run +``` + +**必须设置 `ASPNETCORE_ENVIRONMENT=Development`**,否则 Swagger UI 不会启用。 + +### 3.3 前端需要确认的事项 + +✅ **后端是否启动** — 浏览器访问 `http://localhost:5000/swagger` 能看到 API 文档 +✅ **健康检查** — `curl http://localhost:5000/health` 应返回 `{"status":"healthy"}` +✅ **CORS 已配置** — 已允许 `http://localhost:5173`(Vite)和 `http://localhost:3000` + +--- + +## 4. 接口地址约定 + +### 4.1 基础地址 + +| 环境 | API 地址 | Swagger 地址 | +|------|----------|--------------| +| 开发 | `http://localhost:5000` | `http://localhost:5000/swagger` | +| PC Web Vite 代理 | `/api` + `/hub` | 配置 Vite proxy | + +### 4.2 路由前缀 + +| 模块 | 前缀 | 可对接接口数 | +|------|------|------------| +| 认证 | `/api/auth` | 3 个(login/register/userinfo)+ refresh ⚠️ | +| 通讯录 | `/api/contacts` | 4 个(org-tree/departments/users/users/{id})+ 3 个 ❌ | +| 即时通讯 | `/api/im` | 7 个 ✅ + 群成员管理 ✅ | +| 协同文档 | `/api/docs` | 8 个 ✅ | +| 日历 | `/api/calendar` | 6 个 ✅ + share ❌ | +| 视频会议 | `/api/meeting` | 6 个 ✅ | +| 云盘 | `/api/drive` | 5 个 ✅ + move ❌ + share ⚠️ | +| 审批 | `/api/approval` | 6 个 ✅ + transfer/add-sign ❌ | +| 通知 | `/api/notification` | 5 个 ✅ | +| 管理后台 | `/api/admin` | 8 个 ✅ | + +### 4.3 SignalR Hub + +| Hub | 地址 | 状态 | +|-----|------|------| +| IM Hub | `ws://localhost:5000/hub/im` | ✅ 完整 | +| Meeting Hub | `ws://localhost:5000/hub/meeting` | ✅ 完整 | +| Doc Hub | ❌ 不存在 | 协同编辑未实现 | + +> 📌 **Vite 代理配置参考**(`vite.config.ts`): +> ```typescript +> server: { +> proxy: { +> '/api': { target: 'http://localhost:5000', changeOrigin: true }, +> '/hub': { target: 'http://localhost:5000', ws: true, changeOrigin: true } +> } +> } +> ``` + +--- + +## 5. 通用规范 + +### 5.1 统一响应格式 + +所有 REST 接口返回: + +```json +{ + "code": 200, + "data": { /* 业务数据 */ }, + "message": "success" +} +``` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `code` | number | 200=成功,400=参数错误,401=未授权,403=无权限,404=不存在,500=服务器错误 | +| `data` | object | 业务数据(成功时返回) | +| `message` | string | 提示信息(失败时返回错误原因) | + +### 5.2 分页响应格式 + +```json +{ + "code": 200, + "data": { + "items": [], + "total": 100, + "page": 1, + "pageSize": 20 + } +} +``` + +### 5.3 鉴权 Header + +```http +Authorization: Bearer +``` + +--- + +## 6. 鉴权与 JWT + +### 6.1 登录流程 + +``` +1. POST /api/auth/login { username, password } + → 200 { accessToken, refreshToken, expiresIn: 3600, user } + +2. 后续请求 Header 加: Authorization: Bearer + +3. Token 过期(默认 60 分钟)后: + POST /api/auth/refresh { refreshToken } + → 200 { accessToken, refreshToken, expiresIn: 3600, user: {...} } +``` + +### 6.2 ✅ JWT 真实实现细节 + +- **签名算法**:HMAC-SHA256 +- **密钥位置**:`appsettings.json` 的 `Jwt:SecretKey`(生产环境从环境变量注入,**禁止提交到 Git**) +- **AccessToken 有效期**:60 分钟(可配置) +- **RefreshToken 有效期**:7 天(可配置) +- **Refresh Token 轮换**:每次刷新都生成新的 Refresh Token,旧 Token 立即失效(防重放攻击) +- **Redis 存储结构**: + ``` + refresh_token:{userId} → 当前 refreshToken + refresh_token_lookup:{refreshToken} → userId(反查) + user_info:{userId}:username → 缓存的用户名 + user_info:{userId}:email → 缓存的邮箱 + ``` + +### 6.3 前端要做的事 + +```typescript +// src/api/request.ts (示例) +import axios from 'axios' + +const request = axios.create({ baseURL: '/api' }) + +request.interceptors.request.use((config) => { + const token = localStorage.getItem('accessToken') + if (token) config.headers.Authorization = `Bearer ${token}` + return config +}) + +request.interceptors.response.use( + (response) => response.data.data, + async (error) => { + if (error.response?.status === 401) { + // Token 过期,尝试刷新 + const refreshToken = localStorage.getItem('refreshToken') + if (refreshToken) { + try { + const res = await axios.post('/api/auth/refresh', { refreshToken }) + localStorage.setItem('accessToken', res.data.data.accessToken) + localStorage.setItem('refreshToken', res.data.data.refreshToken) + // 重试原请求 + error.config.headers.Authorization = `Bearer ${res.data.data.accessToken}` + return axios.request(error.config) + } catch { + // Refresh 也失败,跳转登录 + localStorage.clear() + window.location.href = '/login' + } + } + } + return Promise.reject(error) + } +) + +export default request +``` + +### 6.4 ⚠️ SSO 和找回密码暂未实现 + +```typescript +// ❌ 以下接口暂时不要调用,会返回 500 +POST /api/auth/sso/callback +POST /api/auth/forgot-password +POST /api/auth/reset-password +``` + +--- + +## 7. 各模块对接详解 + +### 7.1 用户认证 `/api/auth` ✅ + +#### 📌 前端需实现:登录页、注册页、个人信息页 + +| 接口 | 方法 | 入参 | 出参关键字段 | 状态 | +|------|------|------|-------------|------| +| `/api/auth/login` | POST | `{ username, password }` | `accessToken`, `refreshToken`, `user` | ✅ | +| `/api/auth/register` | POST | `{ username, email, phone?, password }` | `user` | ✅ | +| `/api/auth/userinfo` | GET | — | `user` | ✅ | +| `/api/auth/refresh` | POST | `{ refreshToken }` | 新 `accessToken` + 新 `refreshToken` | ✅ **已修复** | +| `/api/auth/sso/callback` | GET | `?code=` | — | ❌ NotImplemented | +| `/api/auth/forgot-password` | POST | `{ email }` | — | ❌ NotImplemented | +| `/api/auth/reset-password` | POST | `{ token, newPassword }` | — | ❌ NotImplemented | + +**请求示例**: +```typescript +// 登录 +POST /api/auth/login +{ + "username": "zhangsan", + "password": "123456" +} + +// 响应 200 +{ + "code": 200, + "data": { + "accessToken": "eyJhbGciOiJIUzI1NiIs...", + "refreshToken": "abc123def456...", + "expiresIn": 3600, + "user": { + "id": "guid-xxx", + "username": "zhangsan", + "email": "zhangsan@example.com", + "phone": null, + "avatarUrl": null, + "status": 1 + } + } +} +``` + +**前端要做的事**: +1. ✅ Pinia store `stores/auth.ts`:保存 token、user、login/logout/refresh actions +2. ✅ Axios 拦截器:自动加 Authorization Header、401 自动刷新 +3. ✅ 路由守卫:未登录访问受保护页面 → 跳登录页 +4. ❌ 暂时不要做 SSO、忘记密码按钮 + +--- + +### 7.2 通讯录 `/api/contacts` + +#### 📌 前端需实现:组织架构树、部门列表、员工搜索、个人名片 + +| 接口 | 方法 | 状态 | +|------|------|------| +| `/api/contacts/org-tree` | GET | ✅ | +| `/api/contacts/departments` | GET | ✅ | +| `/api/contacts/users` | GET | ✅(支持 `?search=&page=&pageSize=`) | +| `/api/contacts/users/{id}` | GET | ✅ | +| `/api/contacts/contacts` | GET | ❌ **NotImplemented** | +| `/api/contacts/contacts` | POST | ❌ **NotImplemented** | +| `/api/contacts/contacts/{id}` | DELETE | ❌ **NotImplemented** | + +**OrgTreeDto 结构**: +```json +{ + "id": "root", + "name": "组织架构", + "children": [ + { "id": "dept-1", "name": "技术部", "children": [...] } + ] +} +``` + +**前端要做的事**: +- ✅ 用 el-tree / n-tree 渲染组织架构 +- ✅ 用户搜索框(debounce 300ms 后调用) +- ❌ **暂时不要做联系人管理页面**(三个接口会 500) + +--- + +### 7.3 即时通讯 IM `/api/im` + SignalR ✅ + +#### 📌 前端需实现:会话列表、单聊窗口、群聊窗口、群管理 + +**REST 接口**: + +| 接口 | 方法 | 状态 | +|------|------|------| +| `/api/im/channels` | GET | ✅ | +| `/api/im/channels` | POST | ✅ | +| `/api/im/channels/{id}` | GET | ✅ | +| `/api/im/messages/{channelId}` | GET | ✅(分页) | +| `/api/im/messages` | POST | ✅ | +| `/api/im/messages/{id}/read` | PUT | ✅ | +| `/api/im/messages/{id}/recall` | PUT | ✅ | +| `/api/im/channels/{id}/members` | POST | ✅ 加分项 | +| `/api/im/channels/{id}/members/{userId}` | DELETE | ✅ 加分项 | + +**MessageDto 字段**: +```json +{ + "id": "msg-guid", + "channelId": "channel-guid", + "senderId": "user-guid", + "senderName": "zhangsan", + "senderAvatar": "url", + "content": "消息内容", + "contentType": "text", // text | image | file | recall + "isRecalled": false, + "createdAt": "2026-01-01T00:00:00Z" +} +``` + +**⚠️ 已知问题**: +- `ChannelDto.LastMessage` 当前是 `null` +- `ChannelDto.UnreadCount` 当前是 `0` +- 单聊没有去重(前端需要自己处理) +- 没有"获取或创建单聊"便捷接口 + +详见 [第 8 节 SignalR](#8-signalr-实时通信对接)。 + +--- + +### 7.4 协同文档 `/api/docs` ⚠️ 部分功能 + +#### 📌 前端需实现:文档列表、富文本编辑器、版本查看、评论(仅增查) + +| 接口 | 方法 | 状态 | +|------|------|------| +| `/api/docs` | GET | ✅ | +| `/api/docs` | POST | ✅ | +| `/api/docs/{id}` | GET | ✅ | +| `/api/docs/{id}` | PUT | ✅ | +| `/api/docs/{id}` | DELETE | ✅(软删) | +| `/api/docs/{id}/versions` | GET | ✅ | +| `/api/docs/{id}/versions/{vid}/restore` | PUT | ❌ 缺 | +| `/api/docs/{id}/versions/compare` | GET | ❌ 缺 | +| `/api/docs/{id}/comments` | GET | ✅ | +| `/api/docs/{id}/comments` | POST | ✅ | +| `/api/docs/{id}/comments/{cid}` | PUT | ❌ 缺 | +| `/api/docs/{id}/comments/{cid}` | DELETE | ❌ 缺 | +| `/api/docs/{id}/comments/{cid}/resolve` | PUT | ❌ 缺 | + +**⚠️ 重要限制**: +- **没有 DocHub**,文档**不能多人同时实时编辑** +- 推荐方案:**文档锁定模式**(同一时间只能一人编辑,编辑前先 PATCH 获取锁) +- 或者降级为简单的"最后保存获胜" + +**document content 格式**(JSON 字符串,兼容 TipTap / Quill): +```json +{ + "type": "doc", + "content": [ + { "type": "heading", "attrs": { "level": 1 }, "content": [{ "type": "text", "text": "标题" }] } + ] +} +``` + +--- + +### 7.5 日历 `/api/calendar` ⚠️ Share 缺失 + +| 接口 | 方法 | 状态 | +|------|------|------| +| `/api/calendar/events` | GET | ✅ | +| `/api/calendar/events` | POST | ✅ | +| `/api/calendar/events/{id}` | PUT | ✅ | +| `/api/calendar/events/{id}` | DELETE | ✅ | +| `/api/calendar/busy` | GET | ✅ | +| `/api/calendar/shared` | GET | ✅ 加分项 | +| `/api/calendar/share` | POST | ❌ **NotImplemented** | + +**CalendarEventDto**: +```json +{ + "id": "event-guid", + "title": "周会", + "startTime": "2026-01-01T10:00:00Z", + "endTime": "2026-01-01T11:00:00Z", + "recurrence": null, + "reminder": 15, + "visibility": 1, + "location": "会议室A" +} +``` + +--- + +### 7.6 视频会议 `/api/meeting` + SignalR ✅ + +| 接口 | 方法 | 状态 | +|------|------|------| +| `/api/meeting/create` | POST | ✅ | +| `/api/meeting/{id}` | GET | ✅ | +| `/api/meeting/{id}/join` | POST | ✅ | +| `/api/meeting/{id}/leave` | POST | ✅ | +| `/api/meeting/{id}/end` | POST | ✅ 加分项 | +| `/api/meeting/list` | GET | ✅ 加分项 | + +**⚠️ 音视频实现需前端集成第三方 SDK**(声网 Agora / 腾讯云 TRTC): +- 后端只负责会议元数据管理(CRUD + SignalR 信令) +- 实际音视频流走 WebRTC(前端 SDK 直连) +- 会议录制功能暂未实现 + +详见 [第 8 节 MeetingHub](#8-signalr-实时通信对接)。 + +--- + +### 7.7 云盘 `/api/drive` ⚠️ Move/Share 待补 + +| 接口 | 方法 | 状态 | +|------|------|------| +| `/api/drive/files` | GET | ✅ | +| `/api/drive/files` | POST | ✅ **已修复对象名 Bug** | +| `/api/drive/files/{id}` | GET | ✅ 下载(流式返回) | +| `/api/drive/files/{id}` | DELETE | ✅ | +| `/api/drive/folders` | POST | ✅ | +| `/api/drive/files/{id}/share` | POST | ⚠️ Token 未落库,重启失效 | +| `/api/drive/files/{id}/move` | PUT | ❌ **NotImplemented** | + +**上传示例**: +```typescript +const formData = new FormData() +formData.append('file', fileObject) +await request.post('/api/drive/files', formData, { + headers: { 'Content-Type': 'multipart/form-data' }, + onUploadProgress: (e) => console.log(e.loaded / e.total) // 进度 +}) +``` + +**对象名格式**:`drive/{userId}/{Guid}.{ext}` + +--- + +### 7.8 审批 `/api/approval` ⚠️ Transfer/AddSign 缺失 + +| 接口 | 方法 | 状态 | +|------|------|------| +| `/api/approval/forms` | GET | ✅ | +| `/api/approval/forms` | POST | ✅ | +| `/api/approval/instances` | POST | ✅ | +| `/api/approval/instances/{id}` | GET | ✅ | +| `/api/approval/instances/{id}/approve` | POST | ⚠️ 通过后未推下一节点 | +| `/api/approval/instances/{id}/reject` | POST | ✅ | +| `/api/approval/instances/{id}/transfer` | POST | ❌ **NotImplemented** | +| `/api/approval/instances/{id}/add-sign` | POST | ❌ **NotImplemented** | +| `/api/approval/pending` | GET | ✅ | +| `/api/approval/my-submissions` | GET | ✅ | + +**审批状态码**: +- 0=草稿,1=审批中,2=已通过,3=已拒绝,4=已撤回 + +**⚠️ 已知问题**: +- Approve 接口通过后没有自动推进到下一节点 +- 建议前端先实现:提交、查看、拒绝、待办列表 +- 转交和加签按钮**暂时不要做** + +--- + +### 7.9 通知 `/api/notification` ⚠️ 仅站内信 + +| 接口 | 方法 | 状态 | +|------|------|------| +| `/api/notification` | GET | ✅ | +| `/api/notification/{id}/read` | PUT | ✅ | +| `/api/notification/read-all` | PUT | ✅ | +| `/api/notification/{id}` | DELETE | ✅ | +| `/api/notification/unread-count` | GET | ✅ | + +**⚠️ 仅站内信**,邮件/短信通道未实现,且 NotificationService **没被任何业务模块调用**(审批通过后不会自动发通知,需要手动调用 API 写入)。 + +--- + +### 7.10 管理后台 `/api/admin` ⚠️ 角色权限失效 + +| 接口 | 方法 | 状态 | +|------|------|------| +| `/api/admin/users` | GET/POST | ✅ | +| `/api/admin/users/{id}` | PUT/DELETE | ✅ | +| `/api/admin/roles` | GET/POST/PUT/DELETE | ✅ | +| `/api/admin/permissions` | GET/POST | ⚠️ 缺 PUT/DELETE | +| `/api/admin/dict` | GET/POST/PUT | ✅ | +| `/api/admin/logs` | GET | ✅ | + +**⚠️ 重要警告**: +- 所有 `/api/admin/*` 接口装饰了 `[Authorize(Roles="Admin")]` +- **但当前 JwtService 没有写 role claim → 这个特性实际失效** +- 任何登录用户都能访问管理后台 +- 前端暂时只做 UI,不需要后端真的拦截 + +--- + +## 8. SignalR 实时通信对接 + +### 8.1 安装依赖 + +```bash +# PC Web (Vue 3) +pnpm add @microsoft/signalr + +# 跨端 (Taro/React) +pnpm add @microsoft/signalr +``` + +### 8.2 封装 SignalR 客户端(PC Web 示例) + +**`src/utils/signalr.ts`**: +```typescript +import * as signalR from '@microsoft/signalr' +import { useImStore } from '@/stores/im' + +class SignalRClient { + private imConnection: signalR.HubConnection | null = null + private meetingConnection: signalR.HubConnection | null = null + + async startIm() { + if (this.imConnection?.state === signalR.HubConnectionState.Connected) return + + this.imConnection = new signalR.HubConnectionBuilder() + .withUrl('http://localhost:5000/hub/im', { + accessTokenFactory: () => localStorage.getItem('accessToken') || '' + }) + .withAutomaticReconnect([0, 2000, 5000, 10000]) + .build() + + // 监听新消息 + this.imConnection.on('ReceiveMessage', (message: any) => { + const imStore = useImStore() + imStore.appendMessage(message.channelId, message) + }) + + // 监听已读 + this.imConnection.on('MessageRead', (data: any) => { + console.log('Message read:', data) + }) + + // 监听撤回 + this.imConnection.on('MessageRecalled', (data: any) => { + const imStore = useImStore() + imStore.markRecalled(data.messageId) + }) + + // 监听正在输入 + this.imConnection.on('UserTyping', (data: any) => { + // 显示「对方正在输入」 + }) + + await this.imConnection.start() + console.log('IM Hub connected') + } + + async startMeeting() { + this.meetingConnection = new signalR.HubConnectionBuilder() + .withUrl('http://localhost:5000/hub/meeting', { + accessTokenFactory: () => localStorage.getItem('accessToken') || '' + }) + .withAutomaticReconnect([0, 2000, 5000, 10000]) + .build() + + this.meetingConnection.on('UserJoined', (data: any) => { + console.log('User joined:', data) + }) + + this.meetingConnection.on('ReceiveSignal', (data: any) => { + // WebRTC 信令:转发给对等端 + }) + + await this.meetingConnection.start() + } + + async joinChannel(channelId: string) { + await this.imConnection?.invoke('JoinChannel', channelId) + } + + async leaveChannel(channelId: string) { + await this.imConnection?.invoke('LeaveChannel', channelId) + } + + async sendMessageViaHub(channelId: string, content: string, contentType = 'text') { + await this.imConnection?.invoke('SendMessage', channelId, content, contentType) + } + + async joinMeeting(meetingId: string) { + await this.meetingConnection?.invoke('JoinMeeting', meetingId) + } + + async stopIm() { + await this.imConnection?.stop() + } +} + +export const signalr = new SignalRClient() +``` + +### 8.3 IM Hub 事件 + +| 客户端调用(C→S) | 服务端推送(S→C) | +|------------------|------------------| +| `JoinChannel(channelId)` | `ReceiveMessage(message)` | +| `LeaveChannel(channelId)` | `MessageRead({ messageId, readBy, readAt })` | +| `SendMessage(channelId, content, contentType)` | `MessageRecalled({ messageId, recalledBy, recalledAt })` | +| `MarkAsRead(messageId)` | `UserTyping({ channelId, userId, typingAt })` | +| `RecallMessage(messageId)` | | +| `Typing(channelId)` | | + +### 8.4 Meeting Hub 事件 + +| 客户端调用(C→S) | 服务端推送(S→C) | +|------------------|------------------| +| `JoinMeeting(meetingId)` | `UserJoined({ meetingId, userId, joinedAt })` | +| `LeaveMeeting(meetingId)` | `UserLeft({ meetingId, userId, leftAt })` | +| `SendSignal(targetUserId, signalType, signalData)` | `ReceiveSignal({ fromUserId, signalType, signalData, sentAt })` | +| `StartScreenShare(meetingId)` | `ScreenShareStarted({ meetingId, userId, startedAt })` | +| `StopScreenShare(meetingId)` | `ScreenShareStopped({ meetingId, userId, stoppedAt })` | +| `SendMeetingChat(meetingId, message)` | `MeetingChatMessage({ meetingId, userId, message, sentAt })` | +| `RaiseHand(meetingId)` | `HandRaised({ meetingId, userId, raisedAt })` | +| `LowerHand(meetingId)` | `HandLowered({ meetingId, userId, loweredAt })` | +| | `CurrentParticipants([participant...])` | + +### 8.5 跨端 SignalR 注意事项 + +- **H5 环境**:用 `@microsoft/signalr` 的 WebSocket 传输(默认) +- **小程序环境**:用 HTTP 长轮询 +- **RN 环境**:必须用 HTTP 长轮询 +- **Token 传递**:从 `Taro.getStorageSync('token')` 读取传入 `accessTokenFactory` + +--- + +## 9. 错误码对照表 + +| code | 含义 | 前端处理 | +|------|------|----------| +| 200 | 成功 | 正常处理 data | +| 400 | 参数错误 | 显示 message 提示 | +| 401 | 未登录或 token 过期 | 尝试 refresh,失败则跳登录页 | +| 403 | 无权限 | 显示「无权限」提示(**目前角色权限失效,可忽略**) | +| 404 | 资源不存在 | 显示「资源不存在」 | +| 409 | 冲突(如重复操作) | 显示 message | +| 500 | 服务器内部错误 | **可能是 NotImplemented 后端接口**,提示「该功能暂未开放」 | + +**NotImplemented 后端接口清单**(前端可预先捕获 500 给出友好提示): +- `/api/auth/sso/callback` +- `/api/auth/forgot-password` +- `/api/auth/reset-password` +- `/api/contacts/contacts` (GET/POST/DELETE) +- `/api/calendar/share` +- `/api/drive/files/{id}/move` +- `/api/approval/instances/{id}/transfer` +- `/api/approval/instances/{id}/add-sign` + +--- + +## 10. 下一步分工建议 + +### 🎯 第一优先级(P0,建议本周完成) + +| 模块 | 前端 B(PC Web) | 前端 C(跨端) | +|------|----------------|---------------| +| **项目脚手架** | Vite + Vue 3 + Pinia + Tailwind + Axios | Taro + React + Pinia + NutUI | +| **Axios 封装** | 含 Token 自动刷新(参考 6.3) | 同左 | +| **统一状态管理** | Pinia stores:auth、im、contacts | 同左(跨端共享) | +| **路由守卫** | 未登录跳 `/login` | 同左 | +| **登录/注册页** | ✅ | ✅ | +| **首页布局** | Sidebar + Topbar + Content | TabBar + NavBar | +| **IM 单聊 + 群聊** | ✅(最强模块) | ✅ | + +### 🎯 第二优先级(P0/P1) + +| 模块 | PC Web | 跨端 | 备注 | +|------|--------|------|------| +| 通讯录(不含联系人管理) | ✅ | ✅ | 跳过联系人页面 | +| 协同文档(不含协同编辑) | ✅ 单人编辑 | ✅ 仅查看 | 选 TipTap 编辑器 | +| 日历(不含分享) | ✅ | ✅ | 集成 FullCalendar | +| 视频会议(不含音视频实现) | ✅ 仅会议元数据 UI | ✅ | 音视频后续集成 SDK | +| 云盘(不含 Move) | ✅ | ✅ | 文件下载浏览器自动处理 | +| 通知 | ✅ | ✅ | 顶部铃铛 + 未读数 | +| 管理后台 | ✅ | ❌ 移动端不做 | 注意角色权限失效 | + +### 🎯 第三优先级(等后端补全) + +- SSO 登录 +- 找回密码 +- 联系人管理 +- 文档评论修改/删除 +- 文档版本回滚 +- 审批转交/加签 +- 日历共享 +- Drive 移动/分享落库 +- 文档多人协同编辑 +- 实际音视频通话 + +### ⚠️ 必须先和后端 A 确认的事项 + +1. **JWT Refresh Token 流程** — 已实现,前端按 6.3 节的代码示例对接 +2. **SSO 接入** — 暂不实现,前端跳过 +3. **音视频 SDK** — 推荐声网,前端先集成 H5 版本 +4. **文档协同方案** — 暂用单人模式,后续升级 + +--- + +## 11. 联系方式 & 协作约定 + +### 📢 沟通渠道 + +- **微信群**:<小组群名> +- **接口变更通知**:在群里 @ 所有人,并同步更新本文档 + +### 📝 协作约定 + +1. **接口变更必须通知**:后端改了任何接口的 URL/入参/出参,必须在群里同步 +2. **联调前先看 Swagger**:所有接口定义在 `http://localhost:5000/swagger` +3. **本地开发顺序**: + ``` + 后端 A 启动中间件 + 启动后端 → 前端 B/C 启动 → 联调 + ``` +4. **代码提交规范**: + - `feature/xxx` → `dev-backend` / `dev-pc-web` / `dev-multi-platform` → `main` +5. **数据格式对齐**: + - 所有日期用 ISO 8601(`2026-01-01T00:00:00Z`) + - 所有 ID 用 Guid 字符串 +6. **遇到 NotImplementedException**:前端给出友好提示「该功能开发中」,不要让用户看到 500 错误 + +### 📂 项目仓库结构 + +``` +fang-feishu-app-class2-groupN/ +├── backend/ ← 后端(本仓库) +├── frontend/ +│ ├── pc-web/ ← 前端 B +│ └── multi-platform/ ← 前端 C +├── deploy/ +├── docs/ +│ ├── api/ +│ └── 后端实现差距分析报告.md ← 后端实际完成情况 +└── README.md +``` + +--- + +## ✨ 后端 A 的承诺 + +- 任何接口调整会**第一时间同步到本文档** +- 每天晚上 10 点前回复群里所有问题 +- 前端遇到 5xx 错误可直接把响应贴群里,后端会立即排查 +- 数据库新增字段会同步更新 Swagger + +**祝联调顺利!🚀** + +--- + +## 📎 附录:后端启动验证 + +后端已通过以下验证: +- ✅ `dotnet build` 编译成功(0 错误) +- ✅ 监听端口 5000 +- ✅ Swagger 暴露 64 个 API 接口 +- ✅ `/health` 返回 healthy +- ✅ `/api/auth/login` 走通业务流程 +- ✅ `/api/auth/refresh` 真正调用 JwtService.RefreshTokensAsync(返回 401 而不是 500) + +如前端启动后端遇到问题,先检查: +1. 中间件 Docker 容器是否启动(`docker ps`) +2. `appsettings.json` 中 `Jwt:SecretKey` 是否配置 +3. 端口 5000 是否被占用 \ No newline at end of file diff --git "a/\344\274\201\344\270\232\345\215\217\344\275\234\345\212\236\345\205\254\345\271\263\345\217\260\351\241\271\347\233\256\350\256\241\345\210\222\344\271\246.md" "b/\344\274\201\344\270\232\345\215\217\344\275\234\345\212\236\345\205\254\345\271\263\345\217\260\351\241\271\347\233\256\350\256\241\345\210\222\344\271\246.md" new file mode 100644 index 0000000..5c310a3 --- /dev/null +++ "b/\344\274\201\344\270\232\345\215\217\344\275\234\345\212\236\345\205\254\345\271\263\345\217\260\351\241\271\347\233\256\350\256\241\345\210\222\344\271\246.md" @@ -0,0 +1,1050 @@ +# 企业协作办公平台项目计划书 + +| 项目编号 | FF-APP-C2G4-2026 | +| :--: | :--: | +| 项目名称 | 仿飞书应用-2班4组 | +| 所属班级 | 高职软件技术专业 2班 | +| 项目组别 | 第 4 组 | +| 项目周期 | 2026-07-03 ~ 2026-08-29(共 8 周 / 56 天) | +| 项目类型 | 全栈开发方向 · 暑期实习分组实战 | +| 文档版本 | v1.0 | +| 编写日期 | 2026-07-03 | +| 文档状态 | 📝 待评审 | + +--- + +## 文档目录 + +1. [项目概述](#一项目概述) +2. [团队组成与职责分工](#二团队组成与职责分工) +3. [工作分解结构(WBS)](#三工作分解结构wbs) +4. [项目进度计划](#四项目进度计划) +5. [资源配置计划](#五资源配置计划) +6. [质量管理计划](#六质量管理计划) +7. [风险管理计划](#七风险管理计划) +8. [沟通管理计划](#八沟通管理计划) +9. [交付物清单](#九交付物清单) +10. [验收标准](#十验收标准) + +--- + +## 一、项目概述 + +### 1.1 项目背景 + +#### 1.1.1 行业背景 + +随着远程办公与数字化协同需求的爆发,企业级协同办公平台(OA + IM + 协同文档)已成为各行各业的"基础设施"。字节跳动旗下**飞书(Lark)**、腾讯**企业微信**、阿里**钉钉**在国内市场形成三足鼎立格局,相关技术人才市场需求持续旺盛。 + +#### 1.1.2 教学背景 + +- 本项目为**高职软件技术专业(全栈开发方向)暑期实习**的分组实战项目 +- 组内成员同时涵盖**全栈开发**与**实施运维**两个方向,须双线并行 +- 项目旨在通过"准生产级"完整交付,检验同学们对前后端分离架构、企业级业务建模、工程规范与团队协作的综合能力 + +#### 1.1.3 立项依据 + +- 《高职软件技术专业人才培养方案(2024版)》实习实训大纲 +- 暑期实习教学计划任务书(编号:JX-2026-SJ-01) +- 行业市场调研报告:协同办公平台人才需求分析 + +### 1.2 项目目标 + +#### 1.2.1 业务目标 + +**全量复刻飞书(Lark)核心业务功能**,覆盖12大业务模块,最终交付一个可在生产环境运行的企业级协同办公平台。 + +| 目标维度 | 目标描述 | 验收标准 | +| :-- | :-- | :-- | +| 业务完整度 | 12大模块全部实现 | 100%模块通过功能验收 | +| 多端覆盖 | PC网页端 + PC客户端 + iOS + Android | 四端均可独立运行 | +| 性能目标 | 支持100并发用户在线 | 平均响应时间<500ms | +| 可交付性 | 文档、源码、部署包、运维手册齐全 | 通过校企联合验收 | + +#### 1.2.2 能力培养目标 + +| 方向 | 培养目标 | +| :-- | :-- | +| 💻 全栈开发 | 掌握Vue 3 + .NET 10全栈开发流程;熟悉企业级业务建模;具备复杂模块的工程化交付能力 | +| 🔧 实施运维 | 掌握CI/CD流水线搭建;具备部署、监控、故障排查实战能力;具备客户对接与培训能力 | +| 👥 团队协作 | 具备Git协作、Code Review、文档输出、跨方向沟通能力 | + +### 1.3 项目范围 + +#### 1.3.1 业务范围(12大模块) + +| 序号 | 业务模块 | 优先级 | 核心功能 | +| :--: | :-- | :--: | :-- | +| 1 | 用户中心 | P0 | 注册/登录/找回密码/SSO单点登录/三方登录 | +| 2 | 通讯录 | P0 | 组织架构/部门管理/员工名片/搜索 | +| 3 | 即时通讯(IM) | P0 | 单聊/群聊/消息已读/历史消息/文件传输/消息撤回 | +| 4 | 协同文档 | P0 | 富文本编辑/多人实时协作/版本历史/评论 | +| 5 | 视频会议 | P1 | 预约会议/即时会议/屏幕共享/会议录制 | +| 6 | 日历 | P1 | 日程创建/重复事件/提醒/共享日历 | +| 7 | 审批(OA) | P1 | 自定义表单/审批流/加签/转交 | +| 8 | 云盘 | P1 | 文件上传下载/在线预览/权限管理/分享 | +| 9 | 应用中心 | P2 | 应用上下架/工作台配置 | +| 10 | 消息通知 | P1 | 系统通知/邮件/短信/站内信 | +| 11 | 管理后台 | P0 | 用户管理/权限管理/数据字典/操作日志 | +| 12 | 开放平台 | P2 | OpenAPI/Webhook/应用鉴权 | + +#### 1.3.2 技术范围 + +**前端技术栈:** + +| 技术 | 用途 | +| :-- | :-- | +| Vue 3 + Composition API + `