Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled
前端: - 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>
51 lines
1.5 KiB
JavaScript
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);
|
|
});
|