- 删除 template-migration.service.ts 文件 - 移除控制器中的迁移相关API接口 (/migrate, /sync, /admin/migration-report) - 清理文档中的迁移服务相关内容 - 添加 data-source.ts 配置文件用于运行数据库迁移 - 模板迁移功能完全通过数据库migration脚本处理
282 lines
7.1 KiB
TypeScript
282 lines
7.1 KiB
TypeScript
import {
|
||
Controller,
|
||
Get,
|
||
Post,
|
||
Param,
|
||
Body,
|
||
ParseIntPipe,
|
||
Query,
|
||
HttpException,
|
||
HttpStatus
|
||
} from '@nestjs/common';
|
||
import { N8nTemplateFactoryService } from '../services/n8n-template-factory.service';
|
||
|
||
/**
|
||
* 模板控制器
|
||
* 提供模板相关的API接口,支持混合式架构的动态模板管理
|
||
*/
|
||
@Controller('templates')
|
||
export class TemplateController {
|
||
constructor(
|
||
private readonly templateFactory: N8nTemplateFactoryService
|
||
) {}
|
||
|
||
/**
|
||
* 执行模板 - 通过模板ID
|
||
* @param templateId 模板ID
|
||
* @param body 请求体,包含imageUrl
|
||
* @returns 执行结果
|
||
*/
|
||
@Post(':templateId/execute')
|
||
async executeTemplateById(
|
||
@Param('templateId', ParseIntPipe) templateId: number,
|
||
@Body() body: { imageUrl: string }
|
||
) {
|
||
try {
|
||
const { imageUrl } = body;
|
||
|
||
if (!imageUrl) {
|
||
throw new HttpException('imageUrl is required', HttpStatus.BAD_REQUEST);
|
||
}
|
||
|
||
// 通过工厂服务创建模板实例并执行
|
||
const template = await this.templateFactory.createTemplate(templateId);
|
||
const result = await template.execute(imageUrl);
|
||
|
||
return {
|
||
success: true,
|
||
data: {
|
||
templateId,
|
||
templateCode: template.code,
|
||
templateName: template.name,
|
||
inputUrl: imageUrl,
|
||
outputUrl: result,
|
||
creditCost: template.creditCost
|
||
}
|
||
};
|
||
} catch (error) {
|
||
throw new HttpException(
|
||
error.message || 'Template execution failed',
|
||
HttpStatus.INTERNAL_SERVER_ERROR
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 执行模板 - 通过模板代码
|
||
* @param code 模板代码
|
||
* @param body 请求体,包含imageUrl
|
||
* @returns 执行结果
|
||
*/
|
||
@Post('code/:code/execute')
|
||
async executeTemplateByCode(
|
||
@Param('code') code: string,
|
||
@Body() body: { imageUrl: string }
|
||
) {
|
||
try {
|
||
const { imageUrl } = body;
|
||
|
||
if (!imageUrl) {
|
||
throw new HttpException('imageUrl is required', HttpStatus.BAD_REQUEST);
|
||
}
|
||
|
||
// 通过模板代码创建实例并执行
|
||
const template = await this.templateFactory.createTemplateByCode(code);
|
||
const result = await template.execute(imageUrl);
|
||
|
||
return {
|
||
success: true,
|
||
data: {
|
||
templateCode: template.code,
|
||
templateName: template.name,
|
||
inputUrl: imageUrl,
|
||
outputUrl: result,
|
||
creditCost: template.creditCost
|
||
}
|
||
};
|
||
} catch (error) {
|
||
throw new HttpException(
|
||
error.message || 'Template execution failed',
|
||
HttpStatus.INTERNAL_SERVER_ERROR
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 批量执行模板
|
||
* @param templateId 模板ID
|
||
* @param body 包含多个imageUrl的数组
|
||
* @returns 批量执行结果
|
||
*/
|
||
@Post(':templateId/batch-execute')
|
||
async batchExecuteTemplate(
|
||
@Param('templateId', ParseIntPipe) templateId: number,
|
||
@Body() body: { imageUrls: string[] }
|
||
) {
|
||
try {
|
||
const { imageUrls } = body;
|
||
|
||
if (!imageUrls || !Array.isArray(imageUrls) || imageUrls.length === 0) {
|
||
throw new HttpException('imageUrls array is required', HttpStatus.BAD_REQUEST);
|
||
}
|
||
|
||
const results = await this.templateFactory.batchExecute(templateId, imageUrls);
|
||
|
||
return {
|
||
success: true,
|
||
data: {
|
||
templateId,
|
||
totalCount: imageUrls.length,
|
||
results: imageUrls.map((inputUrl, index) => ({
|
||
inputUrl,
|
||
outputUrl: results[index]
|
||
}))
|
||
}
|
||
};
|
||
} catch (error) {
|
||
throw new HttpException(
|
||
error.message || 'Batch execution failed',
|
||
HttpStatus.INTERNAL_SERVER_ERROR
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取所有模板列表
|
||
* @returns 模板配置列表
|
||
*/
|
||
@Get()
|
||
async getAllTemplates() {
|
||
try {
|
||
const templates = await this.templateFactory.getAllTemplates();
|
||
return {
|
||
success: true,
|
||
data: templates.map(template => ({
|
||
id: template.id,
|
||
code: template.code,
|
||
name: template.name,
|
||
description: template.description,
|
||
creditCost: template.creditCost,
|
||
version: template.version,
|
||
templateType: template.templateType,
|
||
templateClass: template.templateClass,
|
||
tags: template.tags,
|
||
inputExample: template.inputExampleUrl,
|
||
outputExample: template.outputExampleUrl,
|
||
sortOrder: template.sortOrder,
|
||
isActive: template.isActive,
|
||
createdAt: template.createdAt,
|
||
updatedAt: template.updatedAt
|
||
}))
|
||
};
|
||
} catch (error) {
|
||
throw new HttpException(
|
||
error.message || 'Failed to fetch templates',
|
||
HttpStatus.INTERNAL_SERVER_ERROR
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取图片类型模板
|
||
* @returns 图片模板列表
|
||
*/
|
||
@Get('image')
|
||
async getImageTemplates() {
|
||
try {
|
||
const templates = await this.templateFactory.getImageTemplates();
|
||
return {
|
||
success: true,
|
||
data: templates
|
||
};
|
||
} catch (error) {
|
||
throw new HttpException(
|
||
error.message || 'Failed to fetch image templates',
|
||
HttpStatus.INTERNAL_SERVER_ERROR
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取视频类型模板
|
||
* @returns 视频模板列表
|
||
*/
|
||
@Get('video')
|
||
async getVideoTemplates() {
|
||
try {
|
||
const templates = await this.templateFactory.getVideoTemplates();
|
||
return {
|
||
success: true,
|
||
data: templates
|
||
};
|
||
} catch (error) {
|
||
throw new HttpException(
|
||
error.message || 'Failed to fetch video templates',
|
||
HttpStatus.INTERNAL_SERVER_ERROR
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 根据用户偏好推荐模板
|
||
* @param tags 用户偏好标签,逗号分隔
|
||
* @param limit 推荐数量
|
||
* @returns 推荐模板列表
|
||
*/
|
||
@Get('recommend')
|
||
async recommendTemplates(
|
||
@Query('tags') tags?: string,
|
||
@Query('limit') limit: number = 5
|
||
) {
|
||
try {
|
||
const userTags = tags ? tags.split(',').map(tag => tag.trim()) : [];
|
||
const templates = await this.templateFactory.recommendTemplates(userTags, limit);
|
||
|
||
return {
|
||
success: true,
|
||
data: {
|
||
userTags,
|
||
recommendedTemplates: templates
|
||
}
|
||
};
|
||
} catch (error) {
|
||
throw new HttpException(
|
||
error.message || 'Failed to recommend templates',
|
||
HttpStatus.INTERNAL_SERVER_ERROR
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取特定模板详情
|
||
* @param templateId 模板ID
|
||
* @returns 模板详细信息
|
||
*/
|
||
@Get(':templateId')
|
||
async getTemplateById(@Param('templateId', ParseIntPipe) templateId: number) {
|
||
try {
|
||
const template = await this.templateFactory.createTemplate(templateId);
|
||
|
||
return {
|
||
success: true,
|
||
data: {
|
||
id: templateId,
|
||
code: template.code,
|
||
name: template.name,
|
||
description: template.description,
|
||
creditCost: template.creditCost,
|
||
version: template.version,
|
||
tags: template.tags,
|
||
inputExample: template.input,
|
||
outputExample: template.output
|
||
}
|
||
};
|
||
} catch (error) {
|
||
throw new HttpException(
|
||
error.message || 'Template not found',
|
||
HttpStatus.NOT_FOUND
|
||
);
|
||
}
|
||
}
|
||
|
||
} |