4 Commits

Author SHA1 Message Date
jacy a8a37fbc4a Merge pull request 'v3.5.2 大屏调整' (#22) from dev_jacy into dev
CI / verify (pull_request) Has been cancelled
Reviewed-on: https://git.yqidian.com/jacy/dukang/pulls/22
2026-08-20 12:00:57 +08:00
jacy e34416a9b3 Merge pull request 'Dev jacy mock 支付调整' (#20) from dev_jacy into dev
CI / verify (pull_request) Has been cancelled
Reviewed-on: https://git.yqidian.com/jacy/dukang/pulls/20
2026-08-20 00:54:17 +08:00
jacy 6c44e9c56f Merge pull request 'v3.5.1 版本更新' (#18) from dev_jacy into dev
CI / verify (pull_request) Has been cancelled
Reviewed-on: https://git.yqidian.com/jacy/dukang/pulls/18
2026-08-19 16:00:56 +08:00
jacy 905e145af3 Merge pull request 'v3.4.18' (#16) from dev_jacy into dev
CI / verify (pull_request) Has been cancelled
Reviewed-on: https://git.yqidian.com/jacy/dukang/pulls/16
2026-08-17 23:45:00 +08:00
7 changed files with 28 additions and 103 deletions
+14 -9
View File
@@ -308,6 +308,14 @@ body:has(.big-screen-page),
box-sizing: border-box;
}
.big-screen-list-head {
flex: 0 0 auto;
padding: 0 28px 10px 40px;
font-size: 15px;
color: rgba(170, 200, 230, 0.55);
letter-spacing: 2px;
}
.big-screen-list-body {
flex: 1 1 0%;
min-height: 0;
@@ -452,20 +460,16 @@ body:has(.big-screen-page),
}
.big-screen-empty {
position: absolute;
left: 0;
right: 0;
/* 全屏高度黄金分割点(≈0.382),略偏上 */
top: 38.2%;
transform: translateY(-50%);
z-index: 2;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
text-align: center;
color: rgba(145, 190, 230, 0.42);
padding: 0 40px;
padding: 48px 40px;
font-size: 60px;
letter-spacing: 6px;
font-weight: 400;
pointer-events: none;
}
.big-screen-fx {
@@ -718,6 +722,7 @@ body:has(.big-screen-page),
.big-screen-clock {
font-size: 56px;
}
.big-screen-list-head,
.big-screen-row {
grid-template-columns: minmax(140px, 20%) minmax(0, 1fr) minmax(110px, 16%) minmax(130px, 18%);
font-size: 16px;
+13 -88
View File
@@ -1,8 +1,5 @@
import { useCallback, useEffect, useMemo, useRef, useState, type CSSProperties } from 'react';
import { request } from '../lib/api';
import sfxTier1 from '../assets/big-screen/celebrate-t1.mp3';
import sfxTier2 from '../assets/big-screen/celebrate-t2.mp3';
import sfxTier3 from '../assets/big-screen/celebrate-t3.mp3';
export type BigScreenOrder = {
id: string;
@@ -24,57 +21,6 @@ const MIN_SCROLL_ROWS = 10;
const FX_DURATION_MS = 10_000;
const WEEKDAYS = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
const CELEBRATE_SFX: Record<AmountTier, string> = {
1: sfxTier1,
2: sfxTier2,
3: sfxTier3,
};
/** 浏览器自动播放策略:需用户手势后才能出声 */
let audioUnlocked = false;
const sharedAudio = typeof Audio !== 'undefined' ? new Audio() : null;
function unlockCelebrateAudio() {
if (audioUnlocked || !sharedAudio) return;
sharedAudio.muted = true;
sharedAudio.src = CELEBRATE_SFX[1];
void sharedAudio
.play()
.then(() => {
sharedAudio.pause();
sharedAudio.currentTime = 0;
sharedAudio.muted = false;
audioUnlocked = true;
})
.catch(() => {
/* 等待下次手势 */
});
}
function playCelebrateSfx(tier: AmountTier): () => void {
if (!sharedAudio) return () => undefined;
try {
sharedAudio.pause();
sharedAudio.currentTime = 0;
sharedAudio.src = CELEBRATE_SFX[tier];
sharedAudio.volume = tier === 3 ? 0.85 : tier === 2 ? 0.75 : 0.65;
sharedAudio.muted = false;
void sharedAudio.play().catch(() => {
/* 未解锁时静默失败 */
});
} catch {
/* ignore */
}
return () => {
try {
sharedAudio.pause();
sharedAudio.currentTime = 0;
} catch {
/* ignore */
}
};
}
function pad(n: number) {
return String(n).padStart(2, '0');
}
@@ -95,20 +41,11 @@ function formatOrderTime(iso: string): string {
}
}
// function formatAmount(n: number): string {
// return Number(n || 0).toLocaleString('zh-CN', {
// minimumFractionDigits: 0,
// maximumFractionDigits: 0,
// });
// }
function formatAmount(n: number): string {
const num = Number(n || 0);
// 先保留两位小数,再分割处理
const fixed = num.toFixed(2);
const [intStr, decStr] = fixed.split('.');
const intFormatted = Number(intStr).toLocaleString('zh-CN');
return decStr === '00' ? intFormatted : `${intFormatted}.${decStr}`;
return Number(n || 0).toLocaleString('zh-CN', {
minimumFractionDigits: 0,
maximumFractionDigits: 0,
});
}
function amountCssClass(payAmount: number, base: string): string {
@@ -238,11 +175,6 @@ function CelebrateFx({ order, onDone }: { order: BigScreenOrder; onDone: () => v
return () => window.clearTimeout(timer);
}, [order.id]);
useEffect(() => {
const stop = playCelebrateSfx(tier);
return stop;
}, [order.id, tier]);
useEffect(() => {
if (tier !== 3) return;
const start = performance.now();
@@ -416,17 +348,6 @@ export default function BigScreenPage() {
return () => clearInterval(id);
}, [fetchData]);
useEffect(() => {
unlockCelebrateAudio();
const unlock = () => unlockCelebrateAudio();
window.addEventListener('pointerdown', unlock, { once: true });
window.addEventListener('keydown', unlock, { once: true });
return () => {
window.removeEventListener('pointerdown', unlock);
window.removeEventListener('keydown', unlock);
};
}, []);
useEffect(() => {
const html = document.documentElement;
const prevHtml = html.style.overflow;
@@ -491,8 +412,16 @@ export default function BigScreenPage() {
<LiveClock />
<div className="big-screen-list">
<div className="big-screen-list-head">
<span></span>
<span></span>
<span></span>
<span></span>
</div>
<div className="big-screen-list-body" ref={viewportRef}>
{items.length === 0 ? null : (
{items.length === 0 ? (
<div className="big-screen-empty">{loadError || '当日暂无订单'}</div>
) : (
<div
className={`big-screen-track${rolling ? ' is-rolling' : ''}${paused ? ' is-paused' : ''}`}
style={rolling ? ({ ['--marquee-ms']: `${marqueeMs}ms` } as CSSProperties) : undefined}
@@ -509,10 +438,6 @@ export default function BigScreenPage() {
</div>
</div>
{items.length === 0 ? (
<div className="big-screen-empty">{loadError || '当日暂无订单'}</div>
) : null}
{celebrate ? (
<CelebrateFx
key={celebrate.id}
-6
View File
@@ -1,6 +0,0 @@
/// <reference types="vite/client" />
declare module '*.mp3' {
const src: string;
export default src;
}
@@ -32,6 +32,7 @@ export class AdminOrdersService {
startOfToday.setHours(0, 0, 0, 0);
const orders = await this.prisma.order.findMany({
where: {
payAmount: { gte: 100 },
payStatus: 'PAID',
paidAt: { gte: startOfToday },
},