修复:兼容Chrome公屏语音播放限制
问题:Chrome在页面没有用户操作时拒绝speechSynthesis并返回not-allowed,导致同机Safari有声但Chrome无声。 实现:两个公屏增加一次性声音启用操作,在用户手势中解锁语音;保留每次三遍播报,并补充暂停恢复、失败提示和回归测试。 复现:直接打开公屏页面后由员工端叫号,Chrome不播放声音。
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import { useEffect, useRef } from "react";
|
||||
import { api } from "../api";
|
||||
import { FeedbackBanner, FreshnessBanner, LoadingState } from "../components/Feedback";
|
||||
import { SpeechControl } from "../components/SpeechControl";
|
||||
import { usePollingResource } from "../hooks/usePollingResource";
|
||||
import { useSpeechAnnouncements } from "../hooks/useSpeechAnnouncements";
|
||||
import { formatCallAnnouncement, isTimestampStale } from "../lib/format";
|
||||
import type { CallBatchDto } from "../types";
|
||||
import { DisplayCenter } from "./AdminPage";
|
||||
@@ -11,6 +13,7 @@ function projectCurrentBatch(value: unknown): CallBatchDto | null {
|
||||
}
|
||||
|
||||
export function PublicDisplayCenterPage() {
|
||||
const { announce, enable: enableSpeech, status: speechStatus } = useSpeechAnnouncements();
|
||||
const resource = usePollingResource((signal) => api.displayOverview(signal), { intervalMs: 5_000 });
|
||||
const data = resource.data;
|
||||
const stale = Boolean(data) && isTimestampStale(resource.lastClientSuccessAt, 30_000);
|
||||
@@ -29,26 +32,13 @@ export function PublicDisplayCenterPage() {
|
||||
if (announcement) announcements.push(`${project.name},${announcement}`);
|
||||
}
|
||||
lastCallsRef.current = nextCalls;
|
||||
if (
|
||||
!announcements.length
|
||||
|| !("speechSynthesis" in window)
|
||||
|| typeof SpeechSynthesisUtterance === "undefined"
|
||||
) return;
|
||||
|
||||
window.speechSynthesis.cancel();
|
||||
for (const announcement of announcements) {
|
||||
for (let repeat = 0; repeat < 3; repeat += 1) {
|
||||
const utterance = new SpeechSynthesisUtterance(announcement);
|
||||
utterance.lang = "zh-CN";
|
||||
utterance.rate = 0.9;
|
||||
window.speechSynthesis.speak(utterance);
|
||||
}
|
||||
}
|
||||
}, [data]);
|
||||
announce(announcements);
|
||||
}, [announce, data]);
|
||||
|
||||
return (
|
||||
<div className="app-shell app-shell--admin app-shell--no-primary-action">
|
||||
<a className="skip-link" href="#main-content">跳到主要内容</a>
|
||||
<SpeechControl status={speechStatus} onEnable={enableSpeech} />
|
||||
<header className="app-header">
|
||||
<div className="brand-lockup" aria-label="景区排队叫号系统">
|
||||
<span className="brand-logo-frame" aria-hidden="true"><img className="brand-logo" src="/xiaoqikong-logo.jpg" alt="" /></span>
|
||||
|
||||
Reference in New Issue
Block a user