// dudu 移动端 · 语音键盘(键盘扩展) // 微信聊天上下文 + 以语音为主的键盘:工具条 / partial 文本条 / 功能键行 / 大麦克风条 // 按住麦克风条:partial 流式显示 → 松开 final 上屏到宿主输入框 const KB_SENTENCES = [ '好的,我马上把文件发给你,大概十分钟之内。', '今晚的聚餐改到八点,地址我发你定位。', ]; function KeyboardScreen({ account = 'ok' }) { // account: ok(有余额) | trial(试用中) | guest(未登录) | quota(今日试用已用完) const { MicBar } = window.DuduDesignSystem_2e0172; const [recording, setRecording] = React.useState(false); const [finalText, setFinalText] = React.useState(''); const [partialText, setPartialText] = React.useState(''); const [inputText, setInputText] = React.useState(''); const [seconds, setSeconds] = React.useState(0); const [idx, setIdx] = React.useState(0); const timers = React.useRef({}); const ref = React.useRef({}); ref.current = { finalText, partialText, idx }; const stop = () => { clearInterval(timers.current.t); clearInterval(timers.current.s); const { finalText: f, partialText: p, idx: i } = ref.current; const committed = f + p; if (committed) { setInputText((v) => v + committed); setIdx((i + 1) % KB_SENTENCES.length); } setFinalText(''); setPartialText(''); setSeconds(0); setRecording(false); }; const start = () => { if (account === 'guest' || account === 'quota') return; setRecording(true); setFinalText(''); setPartialText(''); setSeconds(0); const sentence = KB_SENTENCES[ref.current.idx]; let i = 0; timers.current.t = setInterval(() => { i += 1; if (i >= sentence.length) { clearInterval(timers.current.t); setFinalText(sentence); setPartialText(''); return; } const lastPunct = Math.max(sentence.lastIndexOf(',', i), sentence.lastIndexOf('。', i)); setFinalText(sentence.slice(0, lastPunct + 1)); setPartialText(sentence.slice(lastPunct + 1, i)); }, 95); timers.current.s = setInterval(() => setSeconds((s) => s + 1), 1000); }; React.useEffect(() => () => { clearInterval(timers.current.t); clearInterval(timers.current.s); }, []); const micState = account === 'guest' ? 'disabled' : account === 'quota' ? 'quota' : recording ? 'recording' : 'idle'; const fmt = (s) => `00:${String(s).padStart(2, '0')}`; const FnKey = ({ children, label, flex = 1, onClick }) => ( ); return ( {/* 宿主 App:微信聊天 */}
张三
上次说的那份材料方便发我一下吗
稍等,我看一下
{/* 宿主输入框 */}
{inputText || '发消息…'}
{/* ===== 键盘扩展 ===== */}
{/* 工具条 */}
dudu 语音输入 {account === 'guest' ? '未登录' : account === 'quota' ? '今日试用已用完' : recording ? fmt(seconds) : account === 'trial' ? '试用 · 今日剩 2 分钟' : 余额 472 分钟 }
{/* partial 文本条(录音中替代功能键行) */} {recording ? (
{finalText}{partialText}
) : (
setInputText((v) => v + ',')}>, setInputText((v) => v + '。')}>。 setInputText((v) => v.slice(0, -1))}> setInputText('')}>
)} {/* 大麦克风条 */}
recording && stop()} />
{recording && (
上滑取消
)}
); } Object.assign(window, { KeyboardScreen });