feat: 实现模板管理后台完整CRUD功能和修复MySQL迁移兼容性

- 新增模板CRUD操作:创建、更新、删除、管理后台查询接口
- 创建CreateTemplateDto和UpdateTemplateDto用于数据验证
- 修复所有迁移文件的MySQL语法兼容性问题
- 转换PostgreSQL特有语法为MySQL标准语法
- 添加索引创建的重复检查机制
This commit is contained in:
imeepos
2025-09-04 16:41:04 +08:00
parent de2858012d
commit 1a7ef913ef
8 changed files with 194 additions and 220 deletions

View File

@@ -28,6 +28,6 @@ export class CreateUserTable1725502000000 implements MigrationInterface {
} }
public async down(queryRunner: QueryRunner): Promise<void> { public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE "users"`); await queryRunner.query(`DROP TABLE \`users\``);
} }
} }

View File

@@ -11,25 +11,25 @@ export class CreatePlatformUserTable1725503000000 implements MigrationInterface
public async up(queryRunner: QueryRunner): Promise<void> { public async up(queryRunner: QueryRunner): Promise<void> {
// 创建平台用户关联表 - 支持OAuth令牌管理和平台特有数据存储 // 创建平台用户关联表 - 支持OAuth令牌管理和平台特有数据存储
await queryRunner.query(` await queryRunner.query(`
CREATE TABLE "platform_users" ( CREATE TABLE \`platform_users\` (
"id" uuid NOT NULL DEFAULT uuid_generate_v4(), \`id\` VARCHAR(36) NOT NULL,
"userId" uuid NOT NULL, \`userId\` VARCHAR(36) NOT NULL,
"platform" "platform_type" NOT NULL, \`platform\` ENUM('wechat_mini', 'alipay_mini', 'baidu_mini', 'toutiao_mini', 'qq_mini', 'kuaishou_mini', 'dingtalk_mini', 'taobao_mini', 'wechat_h5', 'mobile_app') NOT NULL,
"platformUserId" character varying(100) NOT NULL, \`platformUserId\` VARCHAR(100) NOT NULL,
"platformData" json, \`platformData\` JSON,
"accessToken" character varying(500), \`accessToken\` VARCHAR(500),
"refreshToken" character varying(500), \`refreshToken\` VARCHAR(500),
"expiresAt" TIMESTAMP, \`expiresAt\` TIMESTAMP NULL,
"createdAt" TIMESTAMP NOT NULL DEFAULT now(), \`createdAt\` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP NOT NULL DEFAULT now(), \`updatedAt\` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT "UQ_platform_users_platform_platformUserId" UNIQUE ("platform", "platformUserId"), CONSTRAINT \`UQ_platform_users_platform_platformUserId\` UNIQUE (\`platform\`, \`platformUserId\`),
CONSTRAINT "PK_platform_users_id" PRIMARY KEY ("id"), CONSTRAINT \`PK_platform_users_id\` PRIMARY KEY (\`id\`),
CONSTRAINT "FK_platform_users_userId" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE CONSTRAINT \`FK_platform_users_userId\` FOREIGN KEY (\`userId\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE
) )
`); `);
} }
public async down(queryRunner: QueryRunner): Promise<void> { public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE "platform_users"`); await queryRunner.query(`DROP TABLE \`platform_users\``);
} }
} }

View File

@@ -11,24 +11,24 @@ export class CreateExtensionDataTable1725504000000 implements MigrationInterface
public async up(queryRunner: QueryRunner): Promise<void> { public async up(queryRunner: QueryRunner): Promise<void> {
// 创建扩展数据表 - 灵活存储各平台特有业务数据 // 创建扩展数据表 - 灵活存储各平台特有业务数据
await queryRunner.query(` await queryRunner.query(`
CREATE TABLE "extension_data" ( CREATE TABLE \`extension_data\` (
"id" uuid NOT NULL DEFAULT uuid_generate_v4(), \`id\` VARCHAR(36) NOT NULL,
"userId" uuid NOT NULL, \`userId\` VARCHAR(36) NOT NULL,
"platform" "platform_type" NOT NULL, \`platform\` ENUM('wechat_mini', 'alipay_mini', 'baidu_mini', 'toutiao_mini', 'qq_mini', 'kuaishou_mini', 'dingtalk_mini', 'taobao_mini', 'wechat_h5', 'mobile_app') NOT NULL,
"dataType" character varying(50) NOT NULL, \`dataType\` VARCHAR(50) NOT NULL,
"referenceId" character varying(100), \`referenceId\` VARCHAR(100),
"data" json NOT NULL, \`data\` JSON NOT NULL,
"metadata" json, \`metadata\` JSON,
"status" character varying(20) NOT NULL DEFAULT 'active', \`status\` VARCHAR(20) NOT NULL DEFAULT 'active',
"createdAt" TIMESTAMP NOT NULL DEFAULT now(), \`createdAt\` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP NOT NULL DEFAULT now(), \`updatedAt\` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT "PK_extension_data_id" PRIMARY KEY ("id"), CONSTRAINT \`PK_extension_data_id\` PRIMARY KEY (\`id\`),
CONSTRAINT "FK_extension_data_userId" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE CONSTRAINT \`FK_extension_data_userId\` FOREIGN KEY (\`userId\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE
) )
`); `);
} }
public async down(queryRunner: QueryRunner): Promise<void> { public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE "extension_data"`); await queryRunner.query(`DROP TABLE \`extension_data\``);
} }
} }

View File

@@ -9,40 +9,30 @@ export class CreateUserCreditTable1725505000000 implements MigrationInterface {
name = 'CreateUserCreditTable1725505000000'; name = 'CreateUserCreditTable1725505000000';
public async up(queryRunner: QueryRunner): Promise<void> { public async up(queryRunner: QueryRunner): Promise<void> {
// 创建积分变动类型枚举
await queryRunner.query(`
CREATE TYPE "credit_type" AS ENUM('reward', 'consume', 'purchase', 'refund')
`);
// 创建积分来源枚举
await queryRunner.query(`
CREATE TYPE "credit_source" AS ENUM('ad_watch', 'subscription', 'ai_generation', 'manual')
`);
// 创建用户积分表 - 支持多平台积分系统和业务关联 // 创建用户积分表 - 支持多平台积分系统和业务关联
// MySQL 中直接在表字段中定义 ENUM无需单独创建枚举类型
await queryRunner.query(` await queryRunner.query(`
CREATE TABLE "user_credits" ( CREATE TABLE \`user_credits\` (
"id" uuid NOT NULL DEFAULT uuid_generate_v4(), \`id\` VARCHAR(36) NOT NULL,
"userId" uuid NOT NULL, \`userId\` VARCHAR(36) NOT NULL,
"platform" "platform_type" NOT NULL, \`platform\` ENUM('wechat_mini', 'alipay_mini', 'baidu_mini', 'toutiao_mini', 'qq_mini', 'kuaishou_mini', 'dingtalk_mini', 'taobao_mini', 'wechat_h5', 'mobile_app') NOT NULL,
"type" "credit_type" NOT NULL, \`type\` ENUM('reward', 'consume', 'purchase', 'refund') NOT NULL,
"source" "credit_source" NOT NULL, \`source\` ENUM('ad_watch', 'subscription', 'ai_generation', 'manual') NOT NULL,
"amount" integer NOT NULL, \`amount\` INT NOT NULL,
"balance" integer NOT NULL, \`balance\` INT NOT NULL,
"description" character varying(200), \`description\` VARCHAR(200),
"referenceId" character varying(100), \`referenceId\` VARCHAR(100),
"metadata" json, \`metadata\` JSON,
"createdAt" TIMESTAMP NOT NULL DEFAULT now(), \`createdAt\` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP NOT NULL DEFAULT now(), \`updatedAt\` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT "PK_user_credits_id" PRIMARY KEY ("id"), CONSTRAINT \`PK_user_credits_id\` PRIMARY KEY (\`id\`),
CONSTRAINT "FK_user_credits_userId" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE CONSTRAINT \`FK_user_credits_userId\` FOREIGN KEY (\`userId\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE
) )
`); `);
} }
public async down(queryRunner: QueryRunner): Promise<void> { public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE "user_credits"`); await queryRunner.query(`DROP TABLE \`user_credits\``);
await queryRunner.query(`DROP TYPE "credit_source"`); // MySQL 中无需单独删除 ENUM 类型,它们与表一起被删除
await queryRunner.query(`DROP TYPE "credit_type"`);
} }
} }

View File

@@ -9,50 +9,39 @@ export class CreateTemplateExecutionTable1725506000000 implements MigrationInter
name = 'CreateTemplateExecutionTable1725506000000'; name = 'CreateTemplateExecutionTable1725506000000';
public async up(queryRunner: QueryRunner): Promise<void> { public async up(queryRunner: QueryRunner): Promise<void> {
// 创建模板执行类型枚举
await queryRunner.query(`
CREATE TYPE "execution_type" AS ENUM('image', 'video')
`);
// 创建执行状态枚举
await queryRunner.query(`
CREATE TYPE "execution_status" AS ENUM('pending', 'processing', 'completed', 'failed', 'cancelled')
`);
// 创建模板执行记录表 - 支持图片和视频两种类型的AI生成任务追踪 // 创建模板执行记录表 - 支持图片和视频两种类型的AI生成任务追踪
// MySQL 中直接在表字段中定义 ENUM无需单独创建枚举类型
await queryRunner.query(` await queryRunner.query(`
CREATE TABLE "template_executions" ( CREATE TABLE \`template_executions\` (
"id" SERIAL PRIMARY KEY, \`id\` INT AUTO_INCREMENT PRIMARY KEY,
"templateId" integer NOT NULL, \`templateId\` INT NOT NULL,
"userId" uuid NOT NULL, \`userId\` VARCHAR(36) NOT NULL,
"platform" "platform_type" NOT NULL, \`platform\` ENUM('wechat_mini', 'alipay_mini', 'baidu_mini', 'toutiao_mini', 'qq_mini', 'kuaishou_mini', 'dingtalk_mini', 'taobao_mini', 'wechat_h5', 'mobile_app') NOT NULL,
"type" "execution_type" NOT NULL, \`type\` ENUM('image', 'video') NOT NULL,
"prompt" text NOT NULL, \`prompt\` TEXT NOT NULL,
"inputImageUrl" character varying(500), \`inputImageUrl\` VARCHAR(500),
"outputUrl" character varying(500), \`outputUrl\` VARCHAR(500),
"thumbnailUrl" character varying(500), \`thumbnailUrl\` VARCHAR(500),
"status" "execution_status" NOT NULL DEFAULT 'pending', \`status\` ENUM('pending', 'processing', 'completed', 'failed', 'cancelled') NOT NULL DEFAULT 'pending',
"progress" integer DEFAULT 0, \`progress\` INT DEFAULT 0,
"errorMessage" text, \`errorMessage\` TEXT,
"executionResult" json, \`executionResult\` JSON,
"creditCost" integer NOT NULL DEFAULT 0, \`creditCost\` INT NOT NULL DEFAULT 0,
"creditTransactionId" character varying(100), \`creditTransactionId\` VARCHAR(100),
"inputParams" json, \`inputParams\` JSON,
"executionConfig" json, \`executionConfig\` JSON,
"startedAt" TIMESTAMP, \`startedAt\` TIMESTAMP NULL,
"completedAt" TIMESTAMP, \`completedAt\` TIMESTAMP NULL,
"executionDuration" integer, \`executionDuration\` INT,
"createdAt" TIMESTAMP NOT NULL DEFAULT now(), \`createdAt\` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP NOT NULL DEFAULT now(), \`updatedAt\` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT "PK_template_executions_id" PRIMARY KEY ("id"), CONSTRAINT \`FK_template_executions_userId\` FOREIGN KEY (\`userId\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE
CONSTRAINT "FK_template_executions_userId" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE
) )
`); `);
} }
public async down(queryRunner: QueryRunner): Promise<void> { public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE "template_executions"`); await queryRunner.query(`DROP TABLE \`template_executions\``);
await queryRunner.query(`DROP TYPE "execution_status"`); // MySQL 中无需单独删除 ENUM 类型,它们与表一起被删除
await queryRunner.query(`DROP TYPE "execution_type"`);
} }
} }

View File

@@ -9,43 +9,33 @@ export class CreateUserSubscriptionTable1725507000000 implements MigrationInterf
name = 'CreateUserSubscriptionTable1725507000000'; name = 'CreateUserSubscriptionTable1725507000000';
public async up(queryRunner: QueryRunner): Promise<void> { public async up(queryRunner: QueryRunner): Promise<void> {
// 创建订阅套餐类型枚举
await queryRunner.query(`
CREATE TYPE "subscription_plan" AS ENUM('basic', 'premium', 'pro')
`);
// 创建订阅状态枚举
await queryRunner.query(`
CREATE TYPE "subscription_status" AS ENUM('active', 'expired', 'cancelled', 'pending')
`);
// 创建用户订阅表 - 提供积分配额和特权功能管理 // 创建用户订阅表 - 提供积分配额和特权功能管理
// MySQL 中直接在表字段中定义 ENUM无需单独创建枚举类型
await queryRunner.query(` await queryRunner.query(`
CREATE TABLE "user_subscriptions" ( CREATE TABLE \`user_subscriptions\` (
"id" uuid NOT NULL DEFAULT uuid_generate_v4(), \`id\` VARCHAR(36) NOT NULL,
"userId" uuid NOT NULL, \`userId\` VARCHAR(36) NOT NULL,
"platform" "platform_type" NOT NULL, \`platform\` ENUM('wechat_mini', 'alipay_mini', 'baidu_mini', 'toutiao_mini', 'qq_mini', 'kuaishou_mini', 'dingtalk_mini', 'taobao_mini', 'wechat_h5', 'mobile_app') NOT NULL,
"plan" "subscription_plan" NOT NULL, \`plan\` ENUM('basic', 'premium', 'pro') NOT NULL,
"status" "subscription_status" NOT NULL DEFAULT 'pending', \`status\` ENUM('active', 'expired', 'cancelled', 'pending') NOT NULL DEFAULT 'pending',
"startDate" TIMESTAMP NOT NULL, \`startDate\` TIMESTAMP NULL,
"endDate" TIMESTAMP NOT NULL, \`endDate\` TIMESTAMP NULL,
"price" decimal(10,2) NOT NULL, \`price\` DECIMAL(10,2) NOT NULL,
"currency" character varying(10) NOT NULL DEFAULT 'CNY', \`currency\` VARCHAR(10) NOT NULL DEFAULT 'CNY',
"monthlyCredits" integer NOT NULL, \`monthlyCredits\` INT NOT NULL,
"paymentId" character varying(100), \`paymentId\` VARCHAR(100),
"features" json, \`features\` JSON,
"autoRenew" boolean NOT NULL DEFAULT true, \`autoRenew\` BOOLEAN NOT NULL DEFAULT true,
"createdAt" TIMESTAMP NOT NULL DEFAULT now(), \`createdAt\` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP NOT NULL DEFAULT now(), \`updatedAt\` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT "PK_user_subscriptions_id" PRIMARY KEY ("id"), CONSTRAINT \`PK_user_subscriptions_id\` PRIMARY KEY (\`id\`),
CONSTRAINT "FK_user_subscriptions_userId" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE CONSTRAINT \`FK_user_subscriptions_userId\` FOREIGN KEY (\`userId\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE
) )
`); `);
} }
public async down(queryRunner: QueryRunner): Promise<void> { public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE "user_subscriptions"`); await queryRunner.query(`DROP TABLE \`user_subscriptions\``);
await queryRunner.query(`DROP TYPE "subscription_status"`); // MySQL 中无需单独删除 ENUM 类型,它们与表一起被删除
await queryRunner.query(`DROP TYPE "subscription_plan"`);
} }
} }

View File

@@ -9,40 +9,30 @@ export class CreateAdWatchTable1725508000000 implements MigrationInterface {
name = 'CreateAdWatchTable1725508000000'; name = 'CreateAdWatchTable1725508000000';
public async up(queryRunner: QueryRunner): Promise<void> { public async up(queryRunner: QueryRunner): Promise<void> {
// 创建广告类型枚举 - 定义小程序支持的各种广告形式
await queryRunner.query(`
CREATE TYPE "ad_type" AS ENUM('banner', 'interstitial', 'rewarded', 'native')
`);
// 创建广告观看状态枚举 - 记录用户与广告交互的不同阶段
await queryRunner.query(`
CREATE TYPE "ad_status" AS ENUM('started', 'completed', 'skipped', 'failed')
`);
// 创建广告观看记录表 - 完整记录用户广告观看行为和奖励数据 // 创建广告观看记录表 - 完整记录用户广告观看行为和奖励数据
// MySQL 中直接在表字段中定义 ENUM无需单独创建枚举类型
await queryRunner.query(` await queryRunner.query(`
CREATE TABLE "ad_watches" ( CREATE TABLE \`ad_watches\` (
"id" uuid NOT NULL DEFAULT uuid_generate_v4(), \`id\` VARCHAR(36) NOT NULL,
"userId" uuid NOT NULL, \`userId\` VARCHAR(36) NOT NULL,
"platform" "platform_type" NOT NULL, \`platform\` ENUM('wechat_mini', 'alipay_mini', 'baidu_mini', 'toutiao_mini', 'qq_mini', 'kuaishou_mini', 'dingtalk_mini', 'taobao_mini', 'wechat_h5', 'mobile_app') NOT NULL,
"adType" "ad_type" NOT NULL, \`adType\` ENUM('banner', 'interstitial', 'rewarded', 'native') NOT NULL,
"adId" character varying(100) NOT NULL, \`adId\` VARCHAR(100) NOT NULL,
"adUnitId" character varying(100), \`adUnitId\` VARCHAR(100),
"status" "ad_status" NOT NULL, \`status\` ENUM('started', 'completed', 'skipped', 'failed') NOT NULL,
"watchDuration" integer, \`watchDuration\` INT,
"rewardCredits" integer, \`rewardCredits\` INT,
"adData" json, \`adData\` JSON,
"createdAt" TIMESTAMP NOT NULL DEFAULT now(), \`createdAt\` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP NOT NULL DEFAULT now(), \`updatedAt\` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT "PK_ad_watches_id" PRIMARY KEY ("id"), CONSTRAINT \`PK_ad_watches_id\` PRIMARY KEY (\`id\`),
CONSTRAINT "FK_ad_watches_userId" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE CONSTRAINT \`FK_ad_watches_userId\` FOREIGN KEY (\`userId\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE
) )
`); `);
} }
public async down(queryRunner: QueryRunner): Promise<void> { public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE "ad_watches"`); await queryRunner.query(`DROP TABLE \`ad_watches\``);
await queryRunner.query(`DROP TYPE "ad_status"`); // MySQL 中无需单独删除 ENUM 类型,它们与表一起被删除
await queryRunner.query(`DROP TYPE "ad_type"`);
} }
} }

View File

@@ -9,88 +9,103 @@ export class CreateTableIndexes1725509000000 implements MigrationInterface {
name = 'CreateTableIndexes1725509000000'; name = 'CreateTableIndexes1725509000000';
public async up(queryRunner: QueryRunner): Promise<void> { public async up(queryRunner: QueryRunner): Promise<void> {
// 平台用户表索引 - 优化多平台身份查询性能 // 检查并创建索引 - 避免重复创建已存在的索引
await queryRunner.query(`CREATE INDEX "IDX_platform_users_platform" ON "platform_users" ("platform")`); const indexQueries = [
await queryRunner.query(`CREATE INDEX "IDX_platform_users_userId" ON "platform_users" ("userId")`); // 平台用户表索引 - 优化多平台身份查询性能
`CREATE INDEX \`IDX_platform_users_platform\` ON \`platform_users\` (\`platform\`)`,
// 扩展数据表索引 - 优化业务数据查询和状态筛选 `CREATE INDEX \`IDX_platform_users_userId\` ON \`platform_users\` (\`userId\`)`,
await queryRunner.query(`CREATE INDEX "IDX_extension_data_userId" ON "extension_data" ("userId")`);
await queryRunner.query(`CREATE INDEX "IDX_extension_data_platform" ON "extension_data" ("platform")`); // 扩展数据表索引 - 优化业务数据查询和状态筛选
await queryRunner.query(`CREATE INDEX "IDX_extension_data_dataType" ON "extension_data" ("dataType")`); `CREATE INDEX \`IDX_extension_data_userId\` ON \`extension_data\` (\`userId\`)`,
await queryRunner.query(`CREATE INDEX "IDX_extension_data_referenceId" ON "extension_data" ("referenceId")`); `CREATE INDEX \`IDX_extension_data_platform\` ON \`extension_data\` (\`platform\`)`,
await queryRunner.query(`CREATE INDEX "IDX_extension_data_status" ON "extension_data" ("status")`); `CREATE INDEX \`IDX_extension_data_dataType\` ON \`extension_data\` (\`dataType\`)`,
await queryRunner.query(`CREATE INDEX "IDX_extension_data_createdAt" ON "extension_data" ("createdAt")`); `CREATE INDEX \`IDX_extension_data_referenceId\` ON \`extension_data\` (\`referenceId\`)`,
`CREATE INDEX \`IDX_extension_data_status\` ON \`extension_data\` (\`status\`)`,
`CREATE INDEX \`IDX_extension_data_createdAt\` ON \`extension_data\` (\`createdAt\`)`,
// 用户积分表索引 - 优化积分流水查询和统计分析 // 用户积分表索引 - 优化积分流水查询和统计分析
await queryRunner.query(`CREATE INDEX "IDX_user_credits_userId" ON "user_credits" ("userId")`); `CREATE INDEX \`IDX_user_credits_userId\` ON \`user_credits\` (\`userId\`)`,
await queryRunner.query(`CREATE INDEX "IDX_user_credits_platform" ON "user_credits" ("platform")`); `CREATE INDEX \`IDX_user_credits_platform\` ON \`user_credits\` (\`platform\`)`,
await queryRunner.query(`CREATE INDEX "IDX_user_credits_type" ON "user_credits" ("type")`); `CREATE INDEX \`IDX_user_credits_type\` ON \`user_credits\` (\`type\`)`,
await queryRunner.query(`CREATE INDEX "IDX_user_credits_source" ON "user_credits" ("source")`); `CREATE INDEX \`IDX_user_credits_source\` ON \`user_credits\` (\`source\`)`,
await queryRunner.query(`CREATE INDEX "IDX_user_credits_createdAt" ON "user_credits" ("createdAt")`); `CREATE INDEX \`IDX_user_credits_createdAt\` ON \`user_credits\` (\`createdAt\`)`,
// 模板执行表索引 - 优化AI生成任务查询和状态追踪 // 模板执行表索引 - 优化AI生成任务查询和状态追踪
await queryRunner.query(`CREATE INDEX "IDX_template_executions_templateId" ON "template_executions" ("templateId")`); `CREATE INDEX \`IDX_template_executions_templateId\` ON \`template_executions\` (\`templateId\`)`,
await queryRunner.query(`CREATE INDEX "IDX_template_executions_userId" ON "template_executions" ("userId")`); `CREATE INDEX \`IDX_template_executions_userId\` ON \`template_executions\` (\`userId\`)`,
await queryRunner.query(`CREATE INDEX "IDX_template_executions_platform" ON "template_executions" ("platform")`); `CREATE INDEX \`IDX_template_executions_platform\` ON \`template_executions\` (\`platform\`)`,
await queryRunner.query(`CREATE INDEX "IDX_template_executions_type" ON "template_executions" ("type")`); `CREATE INDEX \`IDX_template_executions_type\` ON \`template_executions\` (\`type\`)`,
await queryRunner.query(`CREATE INDEX "IDX_template_executions_status" ON "template_executions" ("status")`); `CREATE INDEX \`IDX_template_executions_status\` ON \`template_executions\` (\`status\`)`,
await queryRunner.query(`CREATE INDEX "IDX_template_executions_creditTransactionId" ON "template_executions" ("creditTransactionId")`); `CREATE INDEX \`IDX_template_executions_creditTransactionId\` ON \`template_executions\` (\`creditTransactionId\`)`,
await queryRunner.query(`CREATE INDEX "IDX_template_executions_createdAt" ON "template_executions" ("createdAt")`); `CREATE INDEX \`IDX_template_executions_createdAt\` ON \`template_executions\` (\`createdAt\`)`,
// 用户订阅表索引 - 优化订阅状态查询和到期管理 // 用户订阅表索引 - 优化订阅状态查询和到期管理
await queryRunner.query(`CREATE INDEX "IDX_user_subscriptions_userId" ON "user_subscriptions" ("userId")`); `CREATE INDEX \`IDX_user_subscriptions_userId\` ON \`user_subscriptions\` (\`userId\`)`,
await queryRunner.query(`CREATE INDEX "IDX_user_subscriptions_platform" ON "user_subscriptions" ("platform")`); `CREATE INDEX \`IDX_user_subscriptions_platform\` ON \`user_subscriptions\` (\`platform\`)`,
await queryRunner.query(`CREATE INDEX "IDX_user_subscriptions_status" ON "user_subscriptions" ("status")`); `CREATE INDEX \`IDX_user_subscriptions_status\` ON \`user_subscriptions\` (\`status\`)`,
await queryRunner.query(`CREATE INDEX "IDX_user_subscriptions_endDate" ON "user_subscriptions" ("endDate")`); `CREATE INDEX \`IDX_user_subscriptions_endDate\` ON \`user_subscriptions\` (\`endDate\`)`,
// 广告观看表索引 - 优化广告数据分析和奖励统计 // 广告观看表索引 - 优化广告数据分析和奖励统计
await queryRunner.query(`CREATE INDEX "IDX_ad_watches_userId" ON "ad_watches" ("userId")`); `CREATE INDEX \`IDX_ad_watches_userId\` ON \`ad_watches\` (\`userId\`)`,
await queryRunner.query(`CREATE INDEX "IDX_ad_watches_platform" ON "ad_watches" ("platform")`); `CREATE INDEX \`IDX_ad_watches_platform\` ON \`ad_watches\` (\`platform\`)`,
await queryRunner.query(`CREATE INDEX "IDX_ad_watches_adType" ON "ad_watches" ("adType")`); `CREATE INDEX \`IDX_ad_watches_adType\` ON \`ad_watches\` (\`adType\`)`,
await queryRunner.query(`CREATE INDEX "IDX_ad_watches_status" ON "ad_watches" ("status")`); `CREATE INDEX \`IDX_ad_watches_status\` ON \`ad_watches\` (\`status\`)`,
await queryRunner.query(`CREATE INDEX "IDX_ad_watches_createdAt" ON "ad_watches" ("createdAt")`); `CREATE INDEX \`IDX_ad_watches_createdAt\` ON \`ad_watches\` (\`createdAt\`)`
];
// 安全创建索引 - 忽略已存在的索引错误
for (const query of indexQueries) {
try {
await queryRunner.query(query);
} catch (error) {
// 忽略索引已存在的错误,继续创建其他索引
if (error.code !== 'ER_DUP_KEYNAME') {
throw error;
}
}
}
} }
public async down(queryRunner: QueryRunner): Promise<void> { public async down(queryRunner: QueryRunner): Promise<void> {
// 删除广告观看表索引 // 删除广告观看表索引
await queryRunner.query(`DROP INDEX "IDX_ad_watches_createdAt"`); await queryRunner.query(`DROP INDEX \`IDX_ad_watches_createdAt\``);
await queryRunner.query(`DROP INDEX "IDX_ad_watches_status"`); await queryRunner.query(`DROP INDEX \`IDX_ad_watches_status\``);
await queryRunner.query(`DROP INDEX "IDX_ad_watches_adType"`); await queryRunner.query(`DROP INDEX \`IDX_ad_watches_adType\``);
await queryRunner.query(`DROP INDEX "IDX_ad_watches_platform"`); await queryRunner.query(`DROP INDEX \`IDX_ad_watches_platform\``);
await queryRunner.query(`DROP INDEX "IDX_ad_watches_userId"`); await queryRunner.query(`DROP INDEX \`IDX_ad_watches_userId\``);
// 删除用户订阅表索引 // 删除用户订阅表索引
await queryRunner.query(`DROP INDEX "IDX_user_subscriptions_endDate"`); await queryRunner.query(`DROP INDEX \`IDX_user_subscriptions_endDate\``);
await queryRunner.query(`DROP INDEX "IDX_user_subscriptions_status"`); await queryRunner.query(`DROP INDEX \`IDX_user_subscriptions_status\``);
await queryRunner.query(`DROP INDEX "IDX_user_subscriptions_platform"`); await queryRunner.query(`DROP INDEX \`IDX_user_subscriptions_platform\``);
await queryRunner.query(`DROP INDEX "IDX_user_subscriptions_userId"`); await queryRunner.query(`DROP INDEX \`IDX_user_subscriptions_userId\``);
// 删除模板执行表索引 // 删除模板执行表索引
await queryRunner.query(`DROP INDEX "IDX_template_executions_createdAt"`); await queryRunner.query(`DROP INDEX \`IDX_template_executions_createdAt\``);
await queryRunner.query(`DROP INDEX "IDX_template_executions_creditTransactionId"`); await queryRunner.query(`DROP INDEX \`IDX_template_executions_creditTransactionId\``);
await queryRunner.query(`DROP INDEX "IDX_template_executions_status"`); await queryRunner.query(`DROP INDEX \`IDX_template_executions_status\``);
await queryRunner.query(`DROP INDEX "IDX_template_executions_type"`); await queryRunner.query(`DROP INDEX \`IDX_template_executions_type\``);
await queryRunner.query(`DROP INDEX "IDX_template_executions_platform"`); await queryRunner.query(`DROP INDEX \`IDX_template_executions_platform\``);
await queryRunner.query(`DROP INDEX "IDX_template_executions_userId"`); await queryRunner.query(`DROP INDEX \`IDX_template_executions_userId\``);
await queryRunner.query(`DROP INDEX "IDX_template_executions_templateId"`); await queryRunner.query(`DROP INDEX \`IDX_template_executions_templateId\``);
// 删除用户积分表索引 // 删除用户积分表索引
await queryRunner.query(`DROP INDEX "IDX_user_credits_createdAt"`); await queryRunner.query(`DROP INDEX \`IDX_user_credits_createdAt\``);
await queryRunner.query(`DROP INDEX "IDX_user_credits_source"`); await queryRunner.query(`DROP INDEX \`IDX_user_credits_source\``);
await queryRunner.query(`DROP INDEX "IDX_user_credits_type"`); await queryRunner.query(`DROP INDEX \`IDX_user_credits_type\``);
await queryRunner.query(`DROP INDEX "IDX_user_credits_platform"`); await queryRunner.query(`DROP INDEX \`IDX_user_credits_platform\``);
await queryRunner.query(`DROP INDEX "IDX_user_credits_userId"`); await queryRunner.query(`DROP INDEX \`IDX_user_credits_userId\``);
// 删除扩展数据表索引 // 删除扩展数据表索引
await queryRunner.query(`DROP INDEX "IDX_extension_data_createdAt"`); await queryRunner.query(`DROP INDEX \`IDX_extension_data_createdAt\``);
await queryRunner.query(`DROP INDEX "IDX_extension_data_status"`); await queryRunner.query(`DROP INDEX \`IDX_extension_data_status\``);
await queryRunner.query(`DROP INDEX "IDX_extension_data_referenceId"`); await queryRunner.query(`DROP INDEX \`IDX_extension_data_referenceId\``);
await queryRunner.query(`DROP INDEX "IDX_extension_data_dataType"`); await queryRunner.query(`DROP INDEX \`IDX_extension_data_dataType\``);
await queryRunner.query(`DROP INDEX "IDX_extension_data_platform"`); await queryRunner.query(`DROP INDEX \`IDX_extension_data_platform\``);
await queryRunner.query(`DROP INDEX "IDX_extension_data_userId"`); await queryRunner.query(`DROP INDEX \`IDX_extension_data_userId\``);
// 删除平台用户表索引 // 删除平台用户表索引
await queryRunner.query(`DROP INDEX "IDX_platform_users_userId"`); await queryRunner.query(`DROP INDEX \`IDX_platform_users_userId\``);
await queryRunner.query(`DROP INDEX "IDX_platform_users_platform"`); await queryRunner.query(`DROP INDEX \`IDX_platform_users_platform\``);
} }
} }