feat(web): merge search filters into one row and tidy episode versions (POLISH-1)
- H&R becomes a quick-filter facet (yes/no/unknown, with counts) on search results and the site resources tab; drop the old free/H&R selects, keep size range and sort on the same row (mobile: drawer), single clear button - legacy free/hr URL params migrate into quick filters; stored selections keep the same localStorage key - search timing and query terms move into TechInfo - library episode versions: click the whole row to expand, versions listed as sibling rows, details only under the selected version, raw values in TechInfo - slot comparison gaps get reason codes (matchGapText in contracts reasons.ts): "可换成 2160p", "缺 HDR 版本" Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
12bc4664b6
commit
71b129d85a
19 files changed
+668
-290
No files matched your search
@@ -145,6 +145,7 @@ describe("与版本目标比对", () => {
|
||||
state: "missing",
|
||||
assetId: null,
|
||||
reasons: [],
|
||||
codes: [],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -158,12 +159,29 @@ describe("与版本目标比对", () => {
|
||||
expect(m.state).toBe("upgradeable");
|
||||
expect(m.assetId).toBe("bd");
|
||||
expect(m.reasons.join(" ")).toMatch(/1080p/);
|
||||
expect(m.codes).toEqual(["version_resolution:2160p"]);
|
||||
});
|
||||
|
||||
it("差距原因码:HDR / 字幕 / 来源带目标参数", () => {
|
||||
const hdr: SlotSpec = { id: "h", name: "h", hard: { hdr: { anyOf: ["DV", "HDR10"] } } };
|
||||
expect(matchVersions(hdr, [v("bd", BD_FILE)], { isEpisode: true }).codes).toEqual(["version_hdr"]);
|
||||
const dvOnly: SlotSpec = { id: "d", name: "d", hard: { hdr: { anyOf: ["DV"] } } };
|
||||
expect(matchVersions(dvOnly, [v("bd", BD_FILE)], { isEpisode: true }).codes).toEqual(["version_hdr:DV"]);
|
||||
const remux: SlotSpec = { id: "r", name: "r", hard: { sources: ["REMUX", "BluRay-Disc"] } };
|
||||
expect(matchVersions(remux, [v("dv", DV_FILE, PROBE_DV)], { isEpisode: true }).codes).toEqual([
|
||||
"version_source:REMUX",
|
||||
]);
|
||||
});
|
||||
|
||||
it("达标但升级策略还有余量 = upgradeable;到顶 = satisfied", () => {
|
||||
const up: SlotSpec = { id: "s", name: "x", hard: {}, upgrade: { enabled: true } };
|
||||
const web = matchVersions(up, [v("dv", DV_FILE, PROBE_DV)], { isEpisode: true });
|
||||
expect(web).toMatchObject({ state: "upgradeable", assetId: "dv", reasons: ["来源还能升级"] });
|
||||
expect(web).toMatchObject({
|
||||
state: "upgradeable",
|
||||
assetId: "dv",
|
||||
reasons: ["来源还能升级"],
|
||||
codes: ["version_source_upgrade"],
|
||||
});
|
||||
const capped: SlotSpec = { ...up, upgrade: { enabled: true, ceilingTier: 2 } };
|
||||
expect(matchVersions(capped, [v("dv", DV_FILE, PROBE_DV)], { isEpisode: true }).state).toBe("satisfied");
|
||||
const onlyWeb: SlotSpec = { ...up, hard: { sources: ["WEB-DL"] } };
|
||||
|
||||
@@ -100,6 +100,19 @@ describe("release-facets", () => {
|
||||
expect(ids(run({ promotion: ["2x"] }))).toEqual(["4"]);
|
||||
});
|
||||
|
||||
it("H&R 三态分面:缺省按未知;未知档只在有资源时列出", () => {
|
||||
const hrItems = [mk("y", { hr: true }), mk("n", { hr: false }), mk("n2", { hr: false }), mk("u")];
|
||||
const r = applyFacets(hrItems, (x) => x, {}, { now: NOW });
|
||||
expect(r.facets.hr).toEqual([
|
||||
{ value: "yes", label: "有", count: 1 },
|
||||
{ value: "no", label: "无", count: 2 },
|
||||
{ value: "unknown", label: "未知", count: 1 },
|
||||
]);
|
||||
expect(ids(applyFacets(hrItems, (x) => x, { hr: ["no", "unknown"] }, { now: NOW }))).toEqual(["n", "n2", "u"]);
|
||||
const known = applyFacets([mk("y", { hr: true })], (x) => x, {}, { now: NOW });
|
||||
expect(known.facets.hr.map((o) => o.value)).toEqual(["yes", "no"]);
|
||||
});
|
||||
|
||||
it("已选但没有结果的值仍列出(计数 0)", () => {
|
||||
const r = run({ releaseGroup: ["NoSuch"], site: ["zzz"] });
|
||||
expect(r.items).toEqual([]);
|
||||
|
||||
Reference in new issue
Block a user