|
|
@@ -442,12 +442,165 @@ export type CreateChannelDto = z.infer<typeof CreateChannelSchema>;
|
|
|
- 验证:数值计算、等级规则
|
|
|
- 包含整体集成测试:验证所有模块协同工作
|
|
|
|
|
|
+## 文件实体集成方案
|
|
|
+
|
|
|
+### 现状分析
|
|
|
+
|
|
|
+#### 1. 现有file-module结构
|
|
|
+- **实体**:`File`(对应`files`表)
|
|
|
+- **核心功能**:
|
|
|
+ - MinIO对象存储集成
|
|
|
+ - 预签名URL生成(`fullUrl`属性)
|
|
|
+ - 完整的文件元数据管理(名称、类型、大小、描述等)
|
|
|
+ - 用户关联(上传用户、时间)
|
|
|
+- **表结构**:`id`, `name`, `type`, `size`, `path`, `description`, `upload_user_id`, `upload_time`等
|
|
|
+
|
|
|
+#### 2. allin_system-master中的文件相关实体
|
|
|
+1. **DisabledPhoto**(`disabled_photo`表):残疾人照片管理
|
|
|
+ - 字段:`photo_id`, `person_id`, `photo_type`, `photo_url`, `upload_time`, `can_download`
|
|
|
+ - 直接存储文件URL在`photo_url`字段
|
|
|
+
|
|
|
+2. **OrderPersonAsset**(`order_person_asset`表):订单人员资产管理
|
|
|
+ - 字段:`op_id`, `order_id`, `person_id`, `asset_type`, `asset_file_type`, `asset_url`, `related_time`
|
|
|
+ - 存储图片/视频URL在`asset_url`字段
|
|
|
+
|
|
|
+### 集成方案(推荐:统一使用file-module)
|
|
|
+
|
|
|
+#### 方案A:实体重构(推荐)
|
|
|
+**核心思想**:将文件URL存储转换为引用`File`实体,统一文件管理
|
|
|
+
|
|
|
+**实施步骤**:
|
|
|
+1. **数据库迁移**:
|
|
|
+ ```sql
|
|
|
+ -- 1. 添加file_id字段
|
|
|
+ ALTER TABLE disabled_photo ADD COLUMN file_id INT;
|
|
|
+ ALTER TABLE order_person_asset ADD COLUMN file_id INT;
|
|
|
+
|
|
|
+ -- 2. 创建files表记录(可选,根据现有URL数据)
|
|
|
+ -- 3. 建立外键关系
|
|
|
+ ALTER TABLE disabled_photo ADD FOREIGN KEY (file_id) REFERENCES files(id);
|
|
|
+ ALTER TABLE order_person_asset ADD FOREIGN KEY (file_id) REFERENCES files(id);
|
|
|
+ ```
|
|
|
+
|
|
|
+2. **实体重构**:
|
|
|
+ ```typescript
|
|
|
+ // 原DisabledPhoto实体
|
|
|
+ @Entity('disabled_photo')
|
|
|
+ export class DisabledPhoto {
|
|
|
+ @Column({ name: 'photo_url' })
|
|
|
+ photoUrl: string; // 直接存储URL
|
|
|
+ }
|
|
|
+
|
|
|
+ // 重构后
|
|
|
+ @Entity('disabled_photo')
|
|
|
+ export class DisabledPhoto {
|
|
|
+ @Column({ name: 'file_id' })
|
|
|
+ fileId: number;
|
|
|
+
|
|
|
+ @ManyToOne(() => File)
|
|
|
+ @JoinColumn({ name: 'file_id' })
|
|
|
+ file: File; // 引用File实体
|
|
|
+
|
|
|
+ // 保持原有字段
|
|
|
+ @Column({ name: 'photo_type' })
|
|
|
+ photoType: string;
|
|
|
+
|
|
|
+ @Column({ name: 'can_download' })
|
|
|
+ canDownload: number;
|
|
|
+
|
|
|
+ // 兼容性属性
|
|
|
+ get photoUrl(): Promise<string> {
|
|
|
+ return this.file?.fullUrl || Promise.resolve('');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ```
|
|
|
+
|
|
|
+3. **服务层调整**:
|
|
|
+ ```typescript
|
|
|
+ // 使用FileService处理文件上传
|
|
|
+ import { FileService } from '@d8d/file-module';
|
|
|
+
|
|
|
+ export class DisabilityService {
|
|
|
+ async uploadPhoto(personId: number, fileData: Buffer, filename: string): Promise<DisabledPhoto> {
|
|
|
+ // 1. 使用FileService上传文件
|
|
|
+ const file = await this.fileService.uploadFile({
|
|
|
+ name: filename,
|
|
|
+ data: fileData,
|
|
|
+ uploadUserId: currentUser.id
|
|
|
+ });
|
|
|
+
|
|
|
+ // 2. 创建DisabledPhoto记录
|
|
|
+ const photo = this.photoRepository.create({
|
|
|
+ personId,
|
|
|
+ fileId: file.id,
|
|
|
+ photoType: this.getPhotoType(filename),
|
|
|
+ canDownload: 1
|
|
|
+ });
|
|
|
+
|
|
|
+ return this.photoRepository.save(photo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ```
|
|
|
+
|
|
|
+#### 方案B:服务层集成(备选)
|
|
|
+**核心思想**:保持表结构不变,在服务层集成FileService
|
|
|
+
|
|
|
+**实施步骤**:
|
|
|
+1. **保持表结构**:不修改`disabled_photo`和`order_person_asset`表
|
|
|
+2. **服务层集成**:
|
|
|
+ ```typescript
|
|
|
+ export class DisabilityService {
|
|
|
+ async getPhotoUrl(photoId: number): Promise<string> {
|
|
|
+ const photo = await this.getPhoto(photoId);
|
|
|
+
|
|
|
+ // 如果photo_url是MinIO路径,使用FileService生成预签名URL
|
|
|
+ if (this.isMinioPath(photo.photoUrl)) {
|
|
|
+ const path = this.extractMinioPath(photo.photoUrl);
|
|
|
+ return this.fileService.getPresignedUrl(path);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 否则返回原始URL
|
|
|
+ return photo.photoUrl;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ```
|
|
|
+
|
|
|
+### 推荐方案A的理由
|
|
|
+
|
|
|
+1. **标准化管理**:统一使用项目现有的文件管理架构
|
|
|
+2. **功能复用**:利用file-module的完整功能(权限、元数据、存储)
|
|
|
+3. **扩展性**:便于未来添加文件版本、缩略图、水印等功能
|
|
|
+4. **一致性**:与项目其他模块保持相同的技术栈和模式
|
|
|
+5. **维护性**:集中文件逻辑,减少重复代码
|
|
|
+
|
|
|
+### 影响的故事
|
|
|
+
|
|
|
+需要调整以下故事的文件实体处理:
|
|
|
+
|
|
|
+1. **故事4(disability-module)**:
|
|
|
+ - 修改`DisabledPhoto`实体,引用`File`实体
|
|
|
+ - 更新照片上传/下载服务,使用`FileService`
|
|
|
+ - 调整API集成测试,验证文件功能
|
|
|
+
|
|
|
+2. **故事5(order-module)**:
|
|
|
+ - 修改`OrderPersonAsset`实体,引用`File`实体
|
|
|
+ - 更新资产上传服务,使用`FileService`
|
|
|
+ - 调整测试用例
|
|
|
+
|
|
|
+### 实施注意事项
|
|
|
+
|
|
|
+1. **数据迁移**:需要制定现有URL数据的迁移方案
|
|
|
+2. **兼容性**:保持API兼容,逐步迁移
|
|
|
+3. **性能**:注意N+1查询问题,合理使用数据加载策略
|
|
|
+4. **错误处理**:处理文件服务不可用的情况
|
|
|
+
|
|
|
## 兼容性要求
|
|
|
|
|
|
- [ ] 现有API接口保持不变
|
|
|
-- [ ] 数据库schema保持向后兼容
|
|
|
+- [ ] 数据库schema保持向后兼容(通过迁移方案)
|
|
|
- [ ] 遵循现有TypeScript配置和构建模式
|
|
|
- [ ] 性能影响最小化
|
|
|
+- [ ] 文件功能与现有file-module集成
|
|
|
|
|
|
## 风险缓解
|
|
|
|
|
|
@@ -533,4 +686,19 @@ export type CreateChannelDto = z.infer<typeof CreateChannelSchema>;
|
|
|
- 包含认证测试、数据验证测试、错误处理测试
|
|
|
- 每个端点都要有成功和失败场景测试
|
|
|
|
|
|
-史诗应在保持系统完整性的同时实现将有实体模块从NestJS架构移植到Hono架构的标准化独立包,每个模块都要有完整的API集成测试验证。"
|
|
|
+**文件实体集成方案**:
|
|
|
+发现allin_system-master中有文件相关实体(DisabledPhoto、OrderPersonAsset),需要与现有file-module集成。
|
|
|
+
|
|
|
+**推荐方案**:统一使用file-module,重构文件实体引用
|
|
|
+1. **故事4(disability-module)**:修改`DisabledPhoto`实体,添加`fileId`字段引用`File`实体
|
|
|
+2. **故事5(order-module)**:修改`OrderPersonAsset`实体,添加`fileId`字段引用`File`实体
|
|
|
+3. **服务层**:使用`FileService`处理文件上传/下载
|
|
|
+4. **数据库**:需要迁移现有URL数据到files表
|
|
|
+
|
|
|
+**实施要点**:
|
|
|
+- 保持API兼容性
|
|
|
+- 制定数据迁移方案
|
|
|
+- 注意N+1查询性能问题
|
|
|
+- 处理文件服务错误情况
|
|
|
+
|
|
|
+史诗应在保持系统完整性的同时实现将有实体模块从NestJS架构移植到Hono架构的标准化独立包,每个模块都要有完整的API集成测试验证,并完成与现有file-module的文件集成。"
|