From 6cf66c722cd87d5a83c085ce3ea68131bb1277d5 Mon Sep 17 00:00:00 2001 From: jacy <18049821889@163.com> Date: Thu, 20 Aug 2026 11:58:15 +0800 Subject: [PATCH] =?UTF-8?q?v3.5.2=20=E5=A4=A7=E5=B1=8F=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/admin-web/src/admin.css | 21 ++- apps/admin-web/src/pages/BigScreenPage.tsx | 148 ++++-------------- .../src/modules/ops/admin-orders.service.ts | 5 +- 3 files changed, 51 insertions(+), 123 deletions(-) diff --git a/apps/admin-web/src/admin.css b/apps/admin-web/src/admin.css index e2089d8..3ed57c4 100644 --- a/apps/admin-web/src/admin.css +++ b/apps/admin-web/src/admin.css @@ -291,18 +291,21 @@ body:has(.big-screen-page), z-index: 1; flex: 1; min-height: 0; + width: 100%; display: flex; flex-direction: column; - padding: 0 8px; + padding: 0; overflow: hidden; } .big-screen-list-head, .big-screen-row { display: grid; - grid-template-columns: 208px 1fr 160px 200px; + grid-template-columns: minmax(180px, 18%) minmax(0, 1fr) minmax(140px, 16%) minmax(160px, 18%); align-items: center; column-gap: 16px; + width: 100%; + box-sizing: border-box; } .big-screen-list-head { @@ -457,10 +460,16 @@ body:has(.big-screen-page), } .big-screen-empty { + display: flex; + align-items: center; + justify-content: center; + height: 100%; text-align: center; - color: rgba(255, 255, 255, 0.45); - padding: 48px 20px; - font-size: 18px; + color: rgba(145, 190, 230, 0.42); + padding: 48px 40px; + font-size: 60px; + letter-spacing: 6px; + font-weight: 400; } .big-screen-fx { @@ -715,7 +724,7 @@ body:has(.big-screen-page), } .big-screen-list-head, .big-screen-row { - grid-template-columns: 172px 1fr 120px 160px; + grid-template-columns: minmax(140px, 20%) minmax(0, 1fr) minmax(110px, 16%) minmax(130px, 18%); font-size: 16px; } .big-screen-amount--6d { diff --git a/apps/admin-web/src/pages/BigScreenPage.tsx b/apps/admin-web/src/pages/BigScreenPage.tsx index 84a3b43..2eb70ec 100644 --- a/apps/admin-web/src/pages/BigScreenPage.tsx +++ b/apps/admin-web/src/pages/BigScreenPage.tsx @@ -16,103 +16,10 @@ type AmountTier = 1 | 2 | 3; const POLL_MS = 3000; const ROW_MS = 2500; +/** 不足此条数时重复填充,保证滚动连贯 */ +const MIN_SCROLL_ROWS = 10; +const FX_DURATION_MS = 10_000; const WEEKDAYS = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']; -const TIER_DURATION: Record = { 1: 3000, 2: 4500, 3: 6000 }; - -const SEED_IDS = new Set( - ['seed-1', 'seed-2', 'seed-3', 'seed-4', 'seed-5', 'seed-6', 'seed-7', 'seed-8'], -); - -function seedPaidAt(h: number, m: number, s: number): string { - const d = new Date(); - d.setHours(h, m, s, 0); - return d.toISOString(); -} - -/** 发布会滚动列表垫底演示数据(不参与成交动效) */ -const BIG_SCREEN_SEED_ORDERS: BigScreenOrder[] = [ - { - id: 'seed-1', - orderNo: 'DK-DEMO-001', - payAmount: 1288, - items: '杜康君酿 · 浓香型 × 6瓶', - createdAt: seedPaidAt(14, 28, 36), - paidAt: seedPaidAt(14, 28, 36), - userPhoneMasked: '138****8888', - }, - { - id: 'seed-2', - orderNo: 'DK-DEMO-002', - payAmount: 688, - items: '杜康君酿 · 浓香型 × 2瓶', - createdAt: seedPaidAt(14, 22, 18), - paidAt: seedPaidAt(14, 22, 18), - userPhoneMasked: '139****6666', - }, - { - id: 'seed-3', - orderNo: 'DK-DEMO-003', - payAmount: 1588, - items: '杜康典藏 · 礼盒装 × 2套', - createdAt: seedPaidAt(14, 15, 42), - paidAt: seedPaidAt(14, 15, 42), - userPhoneMasked: '136****9527', - }, - { - id: 'seed-4', - orderNo: 'DK-DEMO-004', - payAmount: 520, - items: '杜康特曲 · 500ml × 4瓶', - createdAt: seedPaidAt(14, 8, 55), - paidAt: seedPaidAt(14, 8, 55), - userPhoneMasked: '135****3210', - }, - { - id: 'seed-5', - orderNo: 'DK-DEMO-005', - payAmount: 268, - items: '杜康君酿 · 浓香型 × 1瓶', - createdAt: seedPaidAt(13, 56, 7), - paidAt: seedPaidAt(13, 56, 7), - userPhoneMasked: '137****1888', - }, - { - id: 'seed-6', - orderNo: 'DK-DEMO-006', - payAmount: 999, - items: '杜康窖藏 · 珍藏版 × 3瓶', - createdAt: seedPaidAt(13, 48, 33), - paidAt: seedPaidAt(13, 48, 33), - userPhoneMasked: '133****7788', - }, - { - id: 'seed-7', - orderNo: 'DK-DEMO-007', - payAmount: 188, - items: '杜康小酒 · 品鉴装 × 2瓶', - createdAt: seedPaidAt(13, 35, 21), - paidAt: seedPaidAt(13, 35, 21), - userPhoneMasked: '158****0099', - }, - { - id: 'seed-8', - orderNo: 'DK-DEMO-008', - payAmount: 1200, - items: '杜康君酿 · 浓香型 × 5瓶', - createdAt: seedPaidAt(13, 22, 49), - paidAt: seedPaidAt(13, 22, 49), - userPhoneMasked: '186****5566', - }, -]; - -function mergeDisplayItems(live: BigScreenOrder[]): BigScreenOrder[] { - if (!live.length) return [...BIG_SCREEN_SEED_ORDERS]; - return [...live, ...BIG_SCREEN_SEED_ORDERS]; -} - -function isSeedOrder(order: BigScreenOrder): boolean { - return SEED_IDS.has(order.id); -} function pad(n: number) { return String(n).padStart(2, '0'); @@ -264,10 +171,9 @@ function CelebrateFx({ order, onDone }: { order: BigScreenOrder; onDone: () => v const [displayAmount, setDisplayAmount] = useState(tier === 3 ? 0 : order.payAmount); useEffect(() => { - const duration = TIER_DURATION[tier]; - const timer = window.setTimeout(() => onDoneRef.current(), duration); + const timer = window.setTimeout(() => onDoneRef.current(), FX_DURATION_MS); return () => window.clearTimeout(timer); - }, [order.id, tier]); + }, [order.id]); useEffect(() => { if (tier !== 3) return; @@ -299,7 +205,6 @@ function CelebrateFx({ order, onDone }: { order: BigScreenOrder; onDone: () => v let raf = 0; let last = performance.now(); const started = performance.now(); - const duration = TIER_DURATION[tier]; const gravity = tier === 3 ? 0.18 : 0.14; const loop = (now: number) => { const dt = Math.min(32, now - last) / 16.6; @@ -310,8 +215,12 @@ function CelebrateFx({ order, onDone }: { order: BigScreenOrder; onDone: () => v p.x += p.vx * dt; p.y += p.vy * dt; p.rot += p.vr * dt; - p.life -= (tier === 3 ? 0.0032 : 0.005) * dt; - if (p.rain && (p.y > canvas.clientHeight + 30 || p.life <= 0) && now - started < duration - 400) { + p.life -= (tier === 3 ? 0.002 : 0.003) * dt; + if ( + p.rain && + (p.y > canvas.clientHeight + 30 || p.life <= 0) && + now - started < FX_DURATION_MS - 400 + ) { p.x = Math.random() * canvas.clientWidth; p.y = -16 - Math.random() * 60; p.vx = (Math.random() - 0.5) * 1.4; @@ -374,12 +283,9 @@ export default function BigScreenPage() { const queueRef = useRef([]); const celebratingRef = useRef(false); const viewportRef = useRef(null); + const dayKeyRef = useRef(''); const [viewportH, setViewportH] = useState(0); - useEffect(() => { - for (const o of BIG_SCREEN_SEED_ORDERS) celebratedIdsRef.current.add(o.id); - }, []); - const playNext = useCallback(() => { const next = queueRef.current.shift() ?? null; celebratingRef.current = !!next; @@ -404,10 +310,22 @@ export default function BigScreenPage() { ); const fetchData = useCallback(() => { + const now = new Date(); + const todayKey = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`; + if (dayKeyRef.current && dayKeyRef.current !== todayKey) { + seenIdsRef.current = null; + celebratedIdsRef.current = new Set(); + queueRef.current = []; + celebratingRef.current = false; + setCelebrate(null); + setPaused(false); + } + dayKeyRef.current = todayKey; + return request<{ items: BigScreenOrder[] }>('/admin/orders/big-screen?limit=2000') .then((d) => { const list = d.items ?? []; - setItems(mergeDisplayItems(list)); + setItems(list); setLoadError(''); const seen = seenIdsRef.current; if (!seen) { @@ -421,7 +339,6 @@ export default function BigScreenPage() { }) .catch((e) => { setLoadError(e instanceof Error ? e.message : '加载失败'); - setItems(mergeDisplayItems([])); }); }, [enqueueNew]); @@ -457,7 +374,7 @@ export default function BigScreenPage() { if (!items.length) return []; const rowH = 80; const visible = Math.max(1, Math.ceil((viewportH || 480) / rowH)); - const minCount = visible + 1; + const minCount = Math.max(MIN_SCROLL_ROWS, visible + 1); const unit: BigScreenOrder[] = []; while (unit.length < minCount) unit.push(...items); return unit; @@ -466,8 +383,7 @@ export default function BigScreenPage() { const trackItems = useMemo(() => unitItems.concat(unitItems), [unitItems]); const marqueeMs = Math.max(unitItems.length, 1) * ROW_MS; const rolling = items.length > 0 && unitItems.length > 0; - const latestLive = items.find((o) => !isSeedOrder(o)); - const latestId = latestLive?.id; + const latestId = items[0]?.id; return (
@@ -497,14 +413,14 @@ export default function BigScreenPage() {
- 下单金额 - 下单商品 - 付款时间 - 下单人 + 订单金额 + 订单商品 + 下单时间 + 下单账号
{items.length === 0 ? ( -
{loadError || '暂无订单'}
+
{loadError || '当日暂无订单'}
) : (