fix: 清理 typecheck 报错并修正迁移列名

- 加入缺失的 @testing-library/dom 依赖(RTL v16 必需 peer),修复 screen 导入
- 修正测试文件错误的相对导入路径(header 改具名导入;prompts/courses 指向 ../page)
- 修正联盟/打赏迁移 SQL:Prisma 列名为 camelCase(仅 @@map 映射表名),原 snake_case 列名导致查询 500,已重建表
- npm run typecheck 现已通过(EXIT=0)
This commit is contained in:
TradeMate Dev
2026-07-11 20:00:14 +08:00
parent 6850ceff56
commit 4ee0e546e3
7 changed files with 776 additions and 581 deletions
@@ -1,5 +1,6 @@
-- 联盟返佣系统:规范化数据模型 -- 联盟返佣系统:规范化数据模型
-- 替换原先手写的 affiliate_stats / affiliate_clicks 裸表,改用 ORM 管理 -- 替换原先手写的 affiliate_stats / affiliate_clicks 裸表,改用 ORM 管理
-- 注意:Prisma 字段名即为列名(camelCase),仅通过 @@map 映射表名为 snake_case
CREATE TABLE IF NOT EXISTS `affiliate_programs` ( CREATE TABLE IF NOT EXISTS `affiliate_programs` (
`id` INT NOT NULL AUTO_INCREMENT, `id` INT NOT NULL AUTO_INCREMENT,
@@ -7,54 +8,54 @@ CREATE TABLE IF NOT EXISTS `affiliate_programs` (
`slug` VARCHAR(191) NOT NULL, `slug` VARCHAR(191) NOT NULL,
`provider` VARCHAR(191), `provider` VARCHAR(191),
`description` TEXT, `description` TEXT,
`commission_rate` VARCHAR(191), `commissionRate` VARCHAR(191),
`cookie_days` INT, `cookieDays` INT,
`homepage_url` VARCHAR(191), `homepageUrl` VARCHAR(191),
`logo` VARCHAR(191), `logo` VARCHAR(191),
`active` TINYINT(1) NOT NULL DEFAULT 1, `active` TINYINT(1) NOT NULL DEFAULT 1,
`sort_order` INT NOT NULL DEFAULT 0, `sortOrder` INT NOT NULL DEFAULT 0,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), `updatedAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE INDEX `affiliate_programs_slug_key` (`slug`) UNIQUE INDEX `affiliate_programs_slug_key` (`slug`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `affiliate_links` ( CREATE TABLE IF NOT EXISTS `affiliate_links` (
`id` INT NOT NULL AUTO_INCREMENT, `id` INT NOT NULL AUTO_INCREMENT,
`program_id` INT NOT NULL, `programId` INT NOT NULL,
`title` VARCHAR(191) NOT NULL, `title` VARCHAR(191) NOT NULL,
`description` TEXT, `description` TEXT,
`url` TEXT NOT NULL, `url` TEXT NOT NULL,
`thumbnail` VARCHAR(191), `thumbnail` VARCHAR(191),
`tool_id` INT, `toolId` INT,
`skill_id` VARCHAR(191), `skillId` VARCHAR(191),
`tags` TEXT, `tags` TEXT,
`estimated_commission` DOUBLE NOT NULL DEFAULT 0, `estimatedCommission` DOUBLE NOT NULL DEFAULT 0,
`sort_order` INT NOT NULL DEFAULT 0, `sortOrder` INT NOT NULL DEFAULT 0,
`is_featured` TINYINT(1) NOT NULL DEFAULT 0, `isFeatured` TINYINT(1) NOT NULL DEFAULT 0,
`active` TINYINT(1) NOT NULL DEFAULT 1, `active` TINYINT(1) NOT NULL DEFAULT 1,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), `updatedAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
INDEX `affiliate_links_program_id_idx` (`program_id`), INDEX `affiliate_links_programId_idx` (`programId`),
INDEX `affiliate_links_tool_id_idx` (`tool_id`), INDEX `affiliate_links_toolId_idx` (`toolId`),
INDEX `affiliate_links_skill_id_idx` (`skill_id`), INDEX `affiliate_links_skillId_idx` (`skillId`),
CONSTRAINT `affiliate_links_program_id_fkey` FOREIGN KEY (`program_id`) REFERENCES `affiliate_programs` (`id`) ON DELETE CASCADE, CONSTRAINT `affiliate_links_programId_fkey` FOREIGN KEY (`programId`) REFERENCES `affiliate_programs` (`id`) ON DELETE CASCADE,
CONSTRAINT `affiliate_links_tool_id_fkey` FOREIGN KEY (`tool_id`) REFERENCES `tools` (`id`) ON DELETE SET NULL, CONSTRAINT `affiliate_links_toolId_fkey` FOREIGN KEY (`toolId`) REFERENCES `tools` (`id`) ON DELETE SET NULL,
CONSTRAINT `affiliate_links_skill_id_fkey` FOREIGN KEY (`skill_id`) REFERENCES `skills` (`id`) ON DELETE SET NULL CONSTRAINT `affiliate_links_skillId_fkey` FOREIGN KEY (`skillId`) REFERENCES `skills` (`id`) ON DELETE SET NULL
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `affiliate_clicks` ( CREATE TABLE IF NOT EXISTS `affiliate_clicks` (
`id` INT NOT NULL AUTO_INCREMENT, `id` INT NOT NULL AUTO_INCREMENT,
`link_id` INT NOT NULL, `linkId` INT NOT NULL,
`user_id` INT, `userId` INT,
`ip` VARCHAR(191), `ip` VARCHAR(191),
`user_agent` TEXT, `userAgent` TEXT,
`ref` VARCHAR(191), `ref` VARCHAR(191),
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
INDEX `affiliate_clicks_link_id_idx` (`link_id`), INDEX `affiliate_clicks_linkId_idx` (`linkId`),
CONSTRAINT `affiliate_clicks_link_id_fkey` FOREIGN KEY (`link_id`) REFERENCES `affiliate_links` (`id`) ON DELETE CASCADE CONSTRAINT `affiliate_clicks_linkId_fkey` FOREIGN KEY (`linkId`) REFERENCES `affiliate_links` (`id`) ON DELETE CASCADE
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 清理旧的手写裸表(被本迁移的规范化模型取代) -- 清理旧的手写裸表(被本迁移的规范化模型取代)
@@ -1,5 +1,6 @@
-- 支持模式:用户自愿打赏(个人收款码捐赠)留言记录 -- 支持模式:用户自愿打赏(个人收款码捐赠)留言记录
-- 平台不代收任何费用,此处仅用于展示「感谢墙」,不记录支付流水 -- 平台不代收任何费用,此处仅用于展示「感谢墙」,不记录支付流水
-- 注意:Prisma 字段名即为列名(camelCase),仅通过 @@map 映射表名为 snake_case
CREATE TABLE IF NOT EXISTS `donations` ( CREATE TABLE IF NOT EXISTS `donations` (
`id` INT NOT NULL AUTO_INCREMENT, `id` INT NOT NULL AUTO_INCREMENT,
@@ -7,7 +8,7 @@ CREATE TABLE IF NOT EXISTS `donations` (
`message` VARCHAR(280), `message` VARCHAR(280),
`channel` VARCHAR(191) NOT NULL DEFAULT 'ALIPAY', `channel` VARCHAR(191) NOT NULL DEFAULT 'ALIPAY',
`amount` DOUBLE, `amount` DOUBLE,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
INDEX `donations_created_at_idx` (`created_at`) INDEX `donations_createdAt_idx` (`createdAt`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
Generated Executable → Regular
+741 -549
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -64,6 +64,7 @@
}, },
"devDependencies": { "devDependencies": {
"@playwright/test": "^1.60.0", "@playwright/test": "^1.60.0",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1", "@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2", "@testing-library/react": "^16.3.2",
"@types/dompurify": "^3.0.5", "@types/dompurify": "^3.0.5",
@@ -75,6 +76,6 @@
"eslint": "^8.57.1", "eslint": "^8.57.1",
"eslint-config-next": "^16.2.6", "eslint-config-next": "^16.2.6",
"jsdom": "^29.1.1", "jsdom": "^29.1.1",
"vitest": "^4.1.5" "vitest": "^4.1.10"
} }
} }
@@ -1,6 +1,6 @@
import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { render, screen } from '@testing-library/react'; import { render, screen } from '@testing-library/react';
import CoursesPage from '../app/courses/page'; import CoursesPage from '../page';
describe('Courses Page', () => { describe('Courses Page', () => {
it('should render courses page', () => { it('should render courses page', () => {
@@ -1,6 +1,6 @@
import { describe, it, expect } from 'vitest'; import { describe, it, expect } from 'vitest';
import { render, screen } from '@testing-library/react'; import { render, screen } from '@testing-library/react';
import PromptsPage from '../app/prompts/page'; import PromptsPage from '../page';
describe('Prompts Page', () => { describe('Prompts Page', () => {
it('should render prompts page', () => { it('should render prompts page', () => {
@@ -1,6 +1,6 @@
import { describe, it, expect } from 'vitest'; import { describe, it, expect } from 'vitest';
import { render, screen } from '@testing-library/react'; import { render, screen } from '@testing-library/react';
import Header from '../header'; import { Header } from '../header';
describe('Header Component', () => { describe('Header Component', () => {
it('should render navigation links', () => { it('should render navigation links', () => {