/* 详细机型库(壳内层)— 品牌 logo 网格 →(品牌卡 morph 展开)品牌机型缩略图网格 → 机型详情 sheet;按价格分组视图。
数据:BRANDS/DB_STATS(dbdata.jsx,_mkdb.py 从本地 db dump 生成);DBTV(data.jsx)补 6 台演示机的面板/亮点。
dump 只有价格/尺寸 —— 详情里其余规格为演示值:面板按品牌×系列推断,指标按价位档生成(id 作种子,刷新稳定)。
深链:?tool=db · &dbv=price · &b=品牌中文名 */
const dbCx = (...a) => a.filter(Boolean).join(' ');
const dbQ = (k) => new URLSearchParams(location.search).get(k);
const DB_REDUCE = !!(window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches);
const DBTV_DETAIL = {};
DBTV.forEach((t) => { DBTV_DETAIL[t.id] = t; });
const DB_PRICE_BUCKETS = [
{ label: '5 千内', test: (p) => p < 5000 },
{ label: '5 千 – 1 万', test: (p) => p >= 5000 && p < 10000 },
{ label: '1 – 2 万', test: (p) => p >= 10000 && p < 20000 },
{ label: '2 万以上', test: (p) => p >= 20000 },
];
/* 演示规格生成 —— 同一机型永远得到同一组值 */
const dbSeed = (id) => { let x = id % 233280; return () => (x = (x * 9301 + 49297) % 233280) / 233280; };
function dbSpec(b, m) {
const det = DBTV_DETAIL[m.id];
const rnd = dbSeed(m.id);
const est = m.price || Math.round(m.size * m.size * 1.15); /* 未录价按尺寸估档 */
const tier = est >= 20000 ? 3 : est >= 10000 ? 2 : est >= 5000 ? 1 : 0;
let panel = det && det.panel;
if (!panel) {
if (b.zh === 'LG') panel = 'OLED';
else if (b.zh === '索尼') panel = /A9|BRAVIA 8/i.test(m.m) ? 'QD-OLED' : 'MiniLED';
else if (b.zh === '三星') panel = /S9/i.test(m.m) ? 'QD-OLED' : 'MiniLED';
else panel = tier === 0 ? 'QLED' : 'MiniLED';
}
const oled = /OLED/i.test(panel);
const mini = /Mini/i.test(panel);
const zones = oled ? '逐像素' : mini ? `${[288, 640, 1440, 2560][tier] + Math.round(rnd() * 10) * 32} 区` : '—';
const nits = oled ? 950 + tier * 350 + Math.round(rnd() * 6) * 50
: [550, 1300, 2800, 4600][tier] + Math.round(rnd() * 8) * 50;
const de = ((oled ? 0.9 : 1.4) + (3 - tier) * .35 + rnd() * .6).toFixed(1);
const hz = tier >= 2 ? 144 : 120;
/* SPEC_REAL(data.jsx)锁定值压过价位档演示值 —— 与 Agent 卡片同一口径,避免同屏两套数 */
return { panel, zones, nits, de, hz, hl: det && det.hl, ...(SPEC_REAL[m.id] || {}) };
}
const dbPrice = (p) => p > 0 ? `¥${p.toLocaleString()}` : '未录价';
/* 缩略图卡(品牌详情网格):CSS 绘制的电视正面 —— 品牌色氛围光 + 尺寸 + 面板徽标 */
function DbModelCard({ b, m, onOpen }) {
const sp = dbSpec(b, m);
return (
);
}
function DbModelRow({ b, m, onOpen }) {
const det = DBTV_DETAIL[m.id];
const sub = [det && det.panel, m.size && `${m.size}″`, det && det.hl].filter(Boolean).join(' · ');
return (
);
}
/* 机型详情 sheet:价格 + 六格规格 */
function DbDetailSheet({ sel, closing, onClose }) {
const { b, m } = sel;
const sp = dbSpec(b, m);
const cells = [
['面板类型', sp.panel],
['峰值亮度', `${sp.nits} nit`],
['控光分区', sp.zones],
['色准 ΔE', sp.de],
['尺寸', `${m.size}″`],
['刷新率', `${sp.hz} Hz`],
];
return (
e.stopPropagation()}>
{b.zh} {m.m}
{sp.hl || '实测详情逐步入库中'}
0) && 'na')}>{dbPrice(m.price)}
{cells.map(([k, v]) => (
{k}{v}
))}
);
}
const DB_HUB_MODEL_IDS = [
10000788, /* 海信 85 E8S */
10000227, /* TCL 85 Q9L PRO */
10000443, /* 小米 S Pro 85 Mini LED */
10000445, /* 雷鸟 鹤6 Ultra */
10000222, /* VIDDA 发现 X Pro */
10000455, /* LG 83 C5 */
];
function dbFindModel(id) {
for (const b of BRANDS) {
const m = b.models.find((item) => item.id === id);
if (m) return { b, m };
}
return null;
}
function DbModelPicker({ side, current, onPick, onClose }) {
const candidates = DB_HUB_MODEL_IDS.map(dbFindModel).filter(Boolean);
return (
e.stopPropagation()} aria-label={`选择${side === 'left' ? '左侧' : '右侧'}电视`}>
选择{side === 'left' ? '左侧' : '右侧'}电视从实测在库机型中选择
{candidates.map(({ b, m }) => {
const sp = dbSpec(b, m);
const active = current && current.m.id === m.id;
return (
);
})}
);
}
function DbRankingSheet({ onClose, onLibrary }) {
const rows = [
{ id: 10000788, score: '9.2', why: '亮厅画质领先' },
{ id: 10000227, score: '8.7', why: '综合表现均衡' },
{ id: 10000443, score: '8.5', why: '游戏体验突出' },
].map((item) => ({ ...item, found: dbFindModel(item.id) })).filter((item) => item.found);
return (
e.stopPropagation()} aria-label="实测排行榜">
{rows.map(({ id, score, why, found }, index) => (
{index + 1}
{found.b.zh} {found.m.m}{why}
{score}
))}
);
}
function DbHub({ onBack, onTools, onLibrary }) {
const { useState } = React;
const [left, setLeft] = useState(dbFindModel(10000788));
const [right, setRight] = useState(dbFindModel(10000227));
const [picker, setPicker] = useState(null);
const [ranking, setRanking] = useState(false);
const modelLabel = (item) => item ? `${item.b.zh} ${item.m.m}` : '选择电视';
const pick = (item) => {
if (picker === 'left') setLeft(item);
else setRight(item);
setPicker(null);
};
return (
VS
开始对比
{picker &&
setPicker(null)} />}
{ranking && setRanking(false)} onLibrary={onLibrary} />}
);
}
function DbScreen({ onBack, onTools }) {
const { useState } = React;
const [view, setView] = useState(dbQ('dbv') || dbQ('b') ? 'library' : 'hub');
const [mode, setMode] = useState(dbQ('dbv') === 'price' ? 'price' : 'brand');
const [brand, setBrand] = useState(BRANDS.find((b) => b.zh === dbQ('b')) || null);
const [bRect, setBRect] = useState(null);
const [bFace, setBFace] = useState(null);
const [bOut, setBOut] = useState(false);
const [bKey, setBKey] = useState(0); /* 每次打开换 key:全新实例,避免"关闭中重开"复用半状态 */
const bTimer = React.useRef(null);
const bOrigin = React.useRef(null); /* morph 期间隐藏来源品牌卡,落点由克隆无缝换真 */
const [sel, setSel] = useState(null);
const [selOut, setSelOut] = useState(false);
const sync = (fn) => { const u = new URL(location); fn(u.searchParams); history.replaceState(null, '', u); };
/* 品牌视图从被点的品牌卡 morph 展开(复用 home.jsx 的 MorphLayer;深链 &b= 时 rect=null 中央张开) */
const pickBrand = (b, e) => {
clearTimeout(bTimer.current);
if (bOrigin.current) bOrigin.current.style.visibility = '';
const o = morphOrigin(e, '.db-app');
bOrigin.current = (e && e.currentTarget) || null;
if (bOrigin.current) bOrigin.current.style.visibility = 'hidden';
setBRect(o.rect); setBFace(o.face);
sync((p) => p.set('b', b.zh)); setBOut(false); setBrand(b); setBKey((v) => v + 1);
};
const closeBrand = () => {
sync((p) => p.delete('b')); setBOut(true);
clearTimeout(bTimer.current);
bTimer.current = setTimeout(() => {
setBrand(null); setBOut(false);
if (bOrigin.current) { bOrigin.current.style.visibility = ''; bOrigin.current = null; }
}, DB_REDUCE ? 60 : MORPH_CLOSE_WAIT);
};
const closeSel = () => {
setSelOut(true);
setTimeout(() => { setSel(null); setSelOut(false); }, DB_REDUCE ? 0 : 240);
};
const openLibrary = () => {
sync((p) => p.set('dbv', mode));
setView('library');
};
const closeLibrary = () => {
sync((p) => { p.delete('dbv'); p.delete('b'); });
setBrand(null); setBOut(false); setView('hub');
};
if (view === 'hub') {
return ;
}
return (
机型库
{`在库 ${DB_STATS.inStock} 台 · ${DB_STATS.brands} 个品牌`}
{mode === 'brand' ? (
{BRANDS.map((b) => (
))}
) : (
DB_PRICE_BUCKETS.map((bk) => {
const items = BRANDS.flatMap((b) => b.models.filter((m) => m.price > 0 && bk.test(m.price))
.map((m) => ({ m, b }))).sort((a, c) => a.m.price - c.m.price);
if (!items.length) return null;
return (
{bk.label}{items.length} 台
{items.map(({ m, b }) => )}
);
})
)}
{/* 品牌机型缩略图网格 —— 从品牌卡 morph 展开的覆盖层 */}
{brand && (
{brand.zh}
共收录 {brand.models.length} 款机型
{brand.models.map((m) => )}
)}
{sel &&
}
);
}
Object.assign(window, { DbScreen });