feat: 实现模板执行记录系统和完整的CRUD API接口

- 新增TemplateExecutionEntity实体替代原有的GenerationTask方式
- 实现模板执行记录的完整生命周期管理,包含状态跟踪和性能指标
- 添加模板管理的完整CRUD操作API(创建、更新、删除、查询)
- 更新数据库迁移文件,包含n8n_templates和template_executions表
- 完善模板工厂服务,支持执行记录管理和统计分析
- 重构DynamicN8nImageTemplate和DynamicN8nVideoTemplate类名
- 添加用户相关实体:User、PlatformUser、ExtensionData、UserCredit等
- 实现完整的数据库表结构和索引优化
This commit is contained in:
imeepos
2025-09-04 16:29:24 +08:00
parent cf6844ad6e
commit de2858012d
23 changed files with 2026 additions and 108 deletions

View File

@@ -198,10 +198,9 @@ import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateCol
import { PlatformUser } from './platform-user.entity';
import { ExtensionData } from './extension-data.entity';
import { UserCredit } from './user-credit.entity';
import { GenerationTask } from './generation-task.entity';
import { TemplateExecutionEntity } from './template-execution.entity';
import { UserSubscription } from './user-subscription.entity';
import { AdWatch } from './ad-watch.entity';
// import { TemplateExecution } from './template-execution.entity'; // 已移除,使用面向对象模板系统
@Entity('users')
export class User {
@@ -241,8 +240,8 @@ export class User {
@OneToMany(() => UserCredit, userCredit => userCredit.user)
credits: UserCredit[];
@OneToMany(() => GenerationTask, generationTask => generationTask.user)
generationTasks: GenerationTask[];
@OneToMany(() => TemplateExecutionEntity, execution => execution.userId)
templateExecutions: TemplateExecutionEntity[];
@OneToMany(() => UserSubscription, userSubscription => userSubscription.user)
subscriptions: UserSubscription[];
@@ -250,7 +249,7 @@ export class User {
@OneToMany(() => AdWatch, adWatch => adWatch.user)
adWatches: AdWatch[];
// 注意: 模板执行记录通过面向对象方式管理,不存储在数据库中
// 注意: 现在使用 TemplateExecutionEntity 实体管理模板执行记录
}
```
@@ -675,37 +674,51 @@ export class AdWatch {
}
```
### 8. AI生成任务与模板系统集成说明
### 8. 模板执行记录系统说明
**重要说明**: 本项目采用面向对象的模板管理系统,使用数据库存储模板定义和执行记录。
**重要说明**: 本项目采用混合式模板管理系统,使用数据库存储模板配置和执行记录。
#### 8.1 模板系统架构
- **模板定义**: 通过TypeScript类定义编译时类型检查
- **模板管理**: 通过TemplateManager内存管理支持动态注册/卸载
- **执行记录**: 通过GenerationTask表记录AI生成任务模板信息作为metadata存储
- **模板定义**: 通过 N8nTemplateEntity 存储模板配置
- **模板管理**: 通过 N8nTemplateFactoryService 管理模板实例化
- **执行记录**: 通过 TemplateExecutionEntity 表记录AI生成任务的完整过程
#### 8.2 与GenerationTask的关系
#### 8.2 TemplateExecutionEntity 实体结构
```typescript
// GenerationTask实体中存储模板相关信息
@Entity('generation_tasks')
export class GenerationTask {
// ... 其他字段
// 现在使用专门的模板执行记录实体
@Entity('template_executions')
export class TemplateExecutionEntity {
@PrimaryGeneratedColumn()
id: number;
@Column({ type: 'json', nullable: true })
parameters: any; // 存储模板执行参数
@Column({ name: 'template_id' })
templateId: number;
@Column({ type: 'json', nullable: true })
metadata: any; // 存储模板代码、版本等信息
@Column({ name: 'user_id' })
userId: string;
@Column({ type: 'enum', enum: PlatformType })
platform: PlatformType;
@Column({ type: 'enum', enum: ExecutionType })
type: ExecutionType;
@Column({ type: 'text' })
prompt: string;
@Column({ name: 'output_url', length: 500, nullable: true })
outputUrl: string;
@Column({ type: 'enum', enum: ExecutionStatus, default: ExecutionStatus.PENDING })
status: ExecutionStatus;
@Column({ name: 'credit_cost', default: 0 })
creditCost: number;
@ManyToOne(() => N8nTemplateEntity)
@JoinColumn({ name: 'template_id' })
template: N8nTemplateEntity;
}
// 使用示例
const task = new GenerationTask();
task.metadata = {
templateCode: 'outfit_change_v1',
templateName: '智能换装',
templateVersion: '1.0.0',
executionId: 'exec_123456789'
};
```
### 4. TypeORM配置
@@ -923,8 +936,72 @@ export class CreateInitialTables1703001000000 implements MigrationInterface {
)
`);
// 注意: AI模板系统采用面向对象设计不需要数据库
// 模板定义通过TypeScript类管理执行记录通过GenerationTask表的metadata字段存储
// 创建N8N模板配置
await queryRunner.query(`
CREATE TABLE "n8n_templates" (
"id" bigint NOT NULL AUTO_INCREMENT,
"code" varchar(100) NOT NULL UNIQUE,
"name" varchar(200) NOT NULL,
"description" text,
"creditCost" int NOT NULL DEFAULT 0,
"version" varchar(50) NOT NULL,
"inputExampleUrl" text,
"outputExampleUrl" text,
"tags" json,
"templateType" enum('image', 'video') NOT NULL,
"templateClass" varchar(100) NOT NULL,
"imageModel" varchar(100),
"imagePrompt" text,
"videoModel" varchar(100),
"videoPrompt" text,
"duration" int,
"aspectRatio" varchar(20),
"isActive" boolean DEFAULT TRUE,
"sortOrder" int DEFAULT 0,
"createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT "PK_n8n_templates_id" PRIMARY KEY ("id")
)
`);
// 创建模板执行记录表
await queryRunner.query(`
CREATE TYPE "execution_status" AS ENUM('pending', 'processing', 'completed', 'failed', 'cancelled')
`);
await queryRunner.query(`
CREATE TYPE "execution_type" AS ENUM('image', 'video')
`);
await queryRunner.query(`
CREATE TABLE "template_executions" (
"id" bigint NOT NULL AUTO_INCREMENT,
"templateId" bigint NOT NULL,
"userId" uuid NOT NULL,
"platform" "platform_type" NOT NULL,
"type" "execution_type" NOT NULL,
"prompt" text NOT NULL,
"inputImageUrl" varchar(500),
"outputUrl" varchar(500),
"thumbnailUrl" varchar(500),
"status" "execution_status" DEFAULT 'pending',
"progress" int DEFAULT 0,
"errorMessage" text,
"executionResult" json,
"creditCost" int DEFAULT 0,
"creditTransactionId" varchar(100),
"inputParams" json,
"executionConfig" json,
"startedAt" TIMESTAMP NULL,
"completedAt" TIMESTAMP NULL,
"executionDuration" int,
"createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT "PK_template_executions_id" PRIMARY KEY ("id"),
CONSTRAINT "FK_template_executions_templateId" FOREIGN KEY ("templateId") REFERENCES "n8n_templates"("id") ON DELETE CASCADE,
CONSTRAINT "FK_template_executions_userId" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE
)
`);
// 创建索引
await queryRunner.query(`CREATE INDEX "IDX_platform_users_platform" ON "platform_users" ("platform")`);
@@ -963,23 +1040,36 @@ export class CreateInitialTables1703001000000 implements MigrationInterface {
await queryRunner.query(`CREATE INDEX "IDX_ad_watches_status" ON "ad_watches" ("status")`);
await queryRunner.query(`CREATE INDEX "IDX_ad_watches_createdAt" ON "ad_watches" ("createdAt")`);
// 注意: 模板系统索引已移除,使用面向对象管理
// N8n模板表索引
await queryRunner.query(`CREATE INDEX "IDX_n8n_templates_code" ON "n8n_templates" ("code")`);
await queryRunner.query(`CREATE INDEX "IDX_n8n_templates_templateType" ON "n8n_templates" ("templateType")`);
await queryRunner.query(`CREATE INDEX "IDX_n8n_templates_templateClass" ON "n8n_templates" ("templateClass")`);
await queryRunner.query(`CREATE INDEX "IDX_n8n_templates_isActive" ON "n8n_templates" ("isActive")`);
// 模板执行记录表索引
await queryRunner.query(`CREATE INDEX "IDX_template_executions_templateId" ON "template_executions" ("templateId")`);
await queryRunner.query(`CREATE INDEX "IDX_template_executions_userId" ON "template_executions" ("userId")`);
await queryRunner.query(`CREATE INDEX "IDX_template_executions_platform" ON "template_executions" ("platform")`);
await queryRunner.query(`CREATE INDEX "IDX_template_executions_status" ON "template_executions" ("status")`);
await queryRunner.query(`CREATE INDEX "IDX_template_executions_type" ON "template_executions" ("type")`);
await queryRunner.query(`CREATE INDEX "IDX_template_executions_creditTransactionId" ON "template_executions" ("creditTransactionId")`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE "template_executions"`);
await queryRunner.query(`DROP TABLE "n8n_templates"`);
await queryRunner.query(`DROP TABLE "ad_watches"`);
await queryRunner.query(`DROP TABLE "user_subscriptions"`);
await queryRunner.query(`DROP TABLE "generation_tasks"`);
await queryRunner.query(`DROP TABLE "user_credits"`);
await queryRunner.query(`DROP TABLE "extension_data"`);
await queryRunner.query(`DROP TABLE "platform_users"`);
await queryRunner.query(`DROP TABLE "users"`);
await queryRunner.query(`DROP TYPE "execution_type"`);
await queryRunner.query(`DROP TYPE "execution_status"`);
await queryRunner.query(`DROP TYPE "ad_status"`);
await queryRunner.query(`DROP TYPE "ad_type"`);
await queryRunner.query(`DROP TYPE "subscription_status"`);
await queryRunner.query(`DROP TYPE "subscription_plan"`);
await queryRunner.query(`DROP TYPE "task_status"`);
await queryRunner.query(`DROP TYPE "generation_type"`);
await queryRunner.query(`DROP TYPE "credit_source"`);
await queryRunner.query(`DROP TYPE "credit_type"`);
await queryRunner.query(`DROP TYPE "platform_type"`);