From 3b3878ea5c4e7795107e400c94655d052915bd46 Mon Sep 17 00:00:00 2001 From: YANG JIANKUAN Date: Mon, 20 Apr 2026 22:10:38 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=A5=96=E5=93=81=E5=91=BD?= =?UTF-8?q?=E5=90=8D=E5=8E=BB=E9=99=A4"=E7=BA=AA=E5=BF=B5=E7=AB=A0"?= =?UTF-8?q?=E5=AD=97=E6=A0=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 奖品不一定是纪念章(可能是实物、折扣券、体验券等), 统一改为"XX · 专属奖品"。新增一次性数据清理脚本, 同步改写存量 Prize 与 Redemption 历史快照。 Co-Authored-By: Claude Opus 4.6 --- .../server/src/scripts/rename-prize-names.ts | 73 +++++++++++++++++++ packages/server/src/seed.ts | 4 +- packages/web/src/admin/StampForm.tsx | 2 +- 3 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 packages/server/src/scripts/rename-prize-names.ts diff --git a/packages/server/src/scripts/rename-prize-names.ts b/packages/server/src/scripts/rename-prize-names.ts new file mode 100644 index 0000000..3484414 --- /dev/null +++ b/packages/server/src/scripts/rename-prize-names.ts @@ -0,0 +1,73 @@ +import { prisma } from "@stamp/shared"; + +const OLD_SUFFIX = "· 纪念章"; +const NEW_SUFFIX = "· 专属奖品"; +const OLD_DESC_RE = /^在「(.+)」集到的专属纪念奖品$/; +const NEW_DESC = (brand: string) => `在「${brand}」可兑换的专属奖品`; + +async function main() { + const apply = process.argv.includes("--apply"); + + const prizes = await prisma.prize.findMany(); + const prizeNameHits = prizes.filter((p) => p.name.endsWith(OLD_SUFFIX)); + const prizeDescHits = prizes.filter((p) => p.description && OLD_DESC_RE.test(p.description)); + + const redemptions = await prisma.redemption.findMany(); + const redemptionHits = redemptions.filter((r) => r.prizeName.endsWith(OLD_SUFFIX)); + + console.log(`=== Prize.name (${prizeNameHits.length}) ===`); + prizeNameHits.slice(0, 20).forEach((p) => { + const next = p.name.slice(0, -OLD_SUFFIX.length) + NEW_SUFFIX; + console.log(` "${p.name}" → "${next}"`); + }); + if (prizeNameHits.length > 20) console.log(` ...共 ${prizeNameHits.length} 条`); + + console.log(`\n=== Prize.description (${prizeDescHits.length}) ===`); + prizeDescHits.slice(0, 20).forEach((p) => { + const m = p.description!.match(OLD_DESC_RE)!; + console.log(` "${p.description}" → "${NEW_DESC(m[1])}"`); + }); + if (prizeDescHits.length > 20) console.log(` ...共 ${prizeDescHits.length} 条`); + + console.log(`\n=== Redemption.prizeName (${redemptionHits.length}) ===`); + redemptionHits.slice(0, 20).forEach((r) => { + const next = r.prizeName.slice(0, -OLD_SUFFIX.length) + NEW_SUFFIX; + console.log(` "${r.prizeName}" → "${next}"`); + }); + if (redemptionHits.length > 20) console.log(` ...共 ${redemptionHits.length} 条`); + + const total = prizeNameHits.length + prizeDescHits.length + redemptionHits.length; + if (total === 0) { + console.log("\n✓ 没有需要替换的记录。"); + return; + } + + if (!apply) { + console.log(`\nDRY RUN — 共 ${total} 条待改。传入 --apply 执行写入。`); + return; + } + + console.log(`\n正在写入...`); + await prisma.$transaction(async (tx) => { + for (const p of prizeNameHits) { + const next = p.name.slice(0, -OLD_SUFFIX.length) + NEW_SUFFIX; + await tx.prize.update({ where: { id: p.id }, data: { name: next } }); + } + for (const p of prizeDescHits) { + const m = p.description!.match(OLD_DESC_RE)!; + await tx.prize.update({ where: { id: p.id }, data: { description: NEW_DESC(m[1]) } }); + } + for (const r of redemptionHits) { + const next = r.prizeName.slice(0, -OLD_SUFFIX.length) + NEW_SUFFIX; + await tx.redemption.update({ where: { id: r.id }, data: { prizeName: next } }); + } + }); + console.log(`\n完成。已更新 ${total} 条。`); +} + +main() + .catch((e) => { + console.error(e); + process.exit(1); + }) + .finally(() => prisma.$disconnect()); diff --git a/packages/server/src/seed.ts b/packages/server/src/seed.ts index 69aae4f..65a4445 100644 --- a/packages/server/src/seed.ts +++ b/packages/server/src/seed.ts @@ -36,8 +36,8 @@ async function seed() { sortOrder: idx + 1, prize: { create: { - name: `${s.name} · 纪念章`, - description: `在「${s.name}」集到的专属纪念奖品`, + name: `${s.name} · 专属奖品`, + description: `在「${s.name}」可兑换的专属奖品`, stock: 100, enabled: true, }, diff --git a/packages/web/src/admin/StampForm.tsx b/packages/web/src/admin/StampForm.tsx index 60de8ae..5bef333 100644 --- a/packages/web/src/admin/StampForm.tsx +++ b/packages/web/src/admin/StampForm.tsx @@ -229,7 +229,7 @@ export default function StampForm({ open, id, onClose, onSaved }: Props) { setPrizeName(e.target.value)} - placeholder="如:朝天宫纪念书签" + placeholder="如:品牌 8 折券 / 定制书签" className={fieldCls} />