UI-UX/scripts/apply-migration.mjs
iye 10878ddb3f
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled
feat(vote): 重构投票模型为终身 12 票 + 每艺人 1 票
前端:
- store 改为 votedArtists[] + zustand persist
- VoteModal 删除 1/3/5/ALL 选择器,改三态(待投/已投/满额)
- 卡片/排行/详情页加 hasVoted 状态 + ✓ 角标
- Hero 右上角 Countdown 替换为 HeroVoteProgress(12 格点亮进度)
- /me 改为终身额度叙事(QuotaCard / StatsGrid / MyFanSupport)

后端:
- votes 表加 @@unique([userId, artistId])(已 apply 到生产 RDS)
- /api/vote 重写:12 票上限 + P2002 ALREADY_VOTED + P2003 NOT_FOUND 兜底
- /api/me 新增 votedArtists[] + voteQuota,移除 dailyQuota
- 新增 ERR.ALREADY_VOTED 错误码

测试:
- DB 层 5/5 + E2E 18/18 通过(scripts/e2e-vote-flow.sh)
- 修复 P2003 FK 违反未识别的 bug

详情见 docs/todo/voting-refactor-完成报告.md 与 voting-refactor-backend-完成报告.md

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-15 20:14:57 +08:00

51 lines
1.5 KiB
JavaScript

// 把 prisma/migrations/manual/*.sql 直接 apply 到当前 DATABASE_URL
// 不依赖 prisma migrate dev(项目无 migrations 历史 + 无 shadow DB)
//
// 用法: node scripts/apply-migration.mjs <sql-file>
import { PrismaClient } from "@prisma/client";
import { readFile } from "node:fs/promises";
const prisma = new PrismaClient({ log: ["warn", "error"] });
async function main() {
const file = process.argv[2];
if (!file) {
console.error("用法: node scripts/apply-migration.mjs <sql-file>");
process.exit(2);
}
const sql = await readFile(file, "utf-8");
// 先按行去掉所有 -- 注释行,再按 ; 切分,过滤空段
const cleaned = sql
.split("\n")
.filter((l) => !/^\s*--/.test(l))
.join("\n");
const statements = cleaned
.split(/;\s*(?:\n|$)/)
.map((s) => s.trim())
.filter(Boolean);
console.log(`将执行 ${statements.length} 条 SQL:\n`);
statements.forEach((s, i) => console.log(` [${i + 1}] ${s.split("\n")[0]}...`));
console.log("");
for (const [i, stmt] of statements.entries()) {
console.log(`[${i + 1}/${statements.length}] 执行中...`);
try {
await prisma.$executeRawUnsafe(stmt);
console.log(`[${i + 1}] ✓ 成功`);
} catch (e) {
console.error(`[${i + 1}] ✗ 失败: ${e.message}`);
throw e;
}
}
console.log("\n=== 全部成功 ===");
await prisma.$disconnect();
}
main().catch(async (e) => {
console.error("\n[ABORT]", e.message);
await prisma.$disconnect();
process.exit(1);
});