- 原生 Next.js App Router + 严格 TypeScript 实现花魁短剧 PC/H5 页面,按 src/features/{catalog,content,playback} 组织,保留完整 SEO(metadata、JSON-LD、canonical、robots、llms、sitemap、IndexNow)。
- 主域名通过 SITE_URL=https://huakuidj.com 强制覆盖后端 foreverUrlAddr(config/*.env、src/server/config.ts、src/server/seo/shared.ts、src/server/services/shared.ts),支持邮箱改为 support@huakuidj.com。
- 移除登录与账户体系:删除 /account 全部页面、登录/注册/充值弹窗、收藏点赞、评论、金币解锁及对应 BFF 接口;旧账户地址 GET/HEAD 统一 301 到首页(src/lib/routes.ts REMOVED_ACCOUNT_PATHS),保留游客会话、反馈、图片上传、观看上报与搜索联想。
- 播放页:评论位改为同类推荐 + 热播榜单,锁定集改为 App 观看遮罩与底部弹层,新增简介标签、分集图例与独立视觉皮肤(src/features/playback、src/styles/pages/playback.css)。
- 卡片:短剧/视频卡状态与时长移至信息行胶囊标签,封面角标移至左上角(src/components/catalog/Cards.tsx、src/styles/foundations/base.css)。
- 同步更新单元测试、浏览器冒烟脚本、路由清单与 README。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
40 lines
2.5 KiB
TypeScript
40 lines
2.5 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { appDownloadURL } from "../src/lib/app-download";
|
|
import { createContext } from "../src/server/context";
|
|
import { loadSharedData } from "../src/server/services/shared";
|
|
|
|
test("download destination keeps the primary address ahead of the official fallback", () => {
|
|
assert.equal(appDownloadURL({ appAddr: " https://downloads.example/app?channel=web ", officialAppAddr: "https://official.example/app" }), "https://downloads.example/app?channel=web");
|
|
assert.equal(appDownloadURL({ config: { appAddr: "https://downloads.example/config" }, newAddressInfo: { appAddr: "https://downloads.example/new" } }), "https://downloads.example/config");
|
|
});
|
|
|
|
test("empty config fields cannot erase valid address data or its official fallback", () => {
|
|
assert.equal(appDownloadURL({ appAddr: "", config: { appAddr: " " }, newAddressInfo: { appAddr: "https://downloads.example/new" }, officialAppAddr: "https://official.example/app" }), "https://downloads.example/new");
|
|
assert.equal(appDownloadURL({ appAddr: " ", config: { officialAppAddr: " https://official.example/app " } }), "https://official.example/app");
|
|
assert.equal(appDownloadURL({ newAddressInfo: { officialAppAddr: "https://official.example/new" } }), "https://official.example/new");
|
|
assert.equal(appDownloadURL({ AppAddr: "https://downloads.example/legacy" }), "https://downloads.example/legacy");
|
|
});
|
|
|
|
test("missing download configuration stays empty rather than inventing a QR destination", () => {
|
|
for (const value of [undefined, null, "https://downloads.example/", {}, { appAddr: " ", officialAppAddr: "" }, { appAddr: 123, config: null, newAddressInfo: { officialAppAddr: false } }]) {
|
|
assert.equal(appDownloadURL(value), "");
|
|
}
|
|
});
|
|
|
|
test("the installation dialog receives the same primary or official destination as the QR", async () => {
|
|
for (const appConfig of [
|
|
{ appAddr: "https://downloads.example/app", officialAppAddr: "https://official.example/app" },
|
|
{ appAddr: "", officialAppAddr: "https://official.example/app" },
|
|
{ config: { appAddr: "" }, newAddressInfo: { appAddr: "https://downloads.example/new" } },
|
|
{ appAddr: "", officialAppAddr: "" },
|
|
]) {
|
|
const ctx = createContext(new Request("http://site.test/"));
|
|
const data = await loadSharedData(ctx, {
|
|
appConfig, categoryList: [{ name: "首页", urlValue: "/", categoryType: 1 }],
|
|
themeList: [], homeConfigData: [], searchTrends: [],
|
|
});
|
|
assert.equal(data.installGuide.fallbackURL, appDownloadURL(appConfig) || "/app/download/");
|
|
}
|
|
});
|