feat(mobile): restore two old-H5 interaction loops in chat form
旧 H5 vs uniapp 逐功能盘点(客户要求'html 版本逻辑保持')后确认的 两个交互缺口,以会话形态补齐: 1. 学练闭环:总结卡底部新增「去练一遍」(旧版'开始跟读'), 关卡后直达练页预习视图,学完话术立刻练。 2. 建议采用:老师傅提示气泡新增「用这句话回复」(旧版'建议回复' 的真实数据版),ChatComposer 暴露 setDraft(text)——填入输入框并 切键盘模式,员工可修改后发送;对打字困难的老年员工是关键路径。 盘点其余结论:旧版功能全部已迁移或被更优实现替代; 团队短板热力图为写死演示数据,真实版记 P2(需后端维度聚合); 演示角色切换/假数据脚手架确认不迁。 验证:本地+生产 E2E——总结卡→去练一遍→预习视图; 对练→老师傅提示→用这句话回复→输入框回填→发送进入下一轮。 发布备份 h5-before-$TS。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -238,7 +238,15 @@ const teardown = () => {
|
|||||||
recording.value = false;
|
recording.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
defineExpose({ teardown });
|
/** Fill the text input from outside (e.g. adopt a coach suggestion) and
|
||||||
|
* switch to keyboard mode so the user can edit before sending. */
|
||||||
|
const setDraft = (text: string) => {
|
||||||
|
voiceMode.value = false;
|
||||||
|
panelOpen.value = false;
|
||||||
|
draft.value = text;
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ teardown, setDraft });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -213,6 +213,7 @@
|
|||||||
>
|
>
|
||||||
{{ speechButtonLabel(`turn-${index}`) }}
|
{{ speechButtonLabel(`turn-${index}`) }}
|
||||||
</button>
|
</button>
|
||||||
|
<button class="bubble-action" @click="adoptCoachHint(turn.text)">用这句话回复</button>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -587,6 +588,14 @@ const handleComposerSend = (text: string) => {
|
|||||||
void submit();
|
void submit();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 旧 H5「建议回复」逻辑的会话版:把老师傅建议填入输入框,员工可改后发送。 */
|
||||||
|
const adoptCoachHint = (text: string) => {
|
||||||
|
const value = (text || '').trim();
|
||||||
|
if (!value) return;
|
||||||
|
composerRef.value?.setDraft(value);
|
||||||
|
uni.showToast({ title: '已填入输入框,可修改后发送', icon: 'none' });
|
||||||
|
};
|
||||||
|
|
||||||
const submitTranscribed = async (text: string, audioUrl: string, ossId?: string) => {
|
const submitTranscribed = async (text: string, audioUrl: string, ossId?: string) => {
|
||||||
draft.value = text;
|
draft.value = text;
|
||||||
draftAudioUrl.value = audioUrl;
|
draftAudioUrl.value = audioUrl;
|
||||||
|
|||||||
@@ -224,6 +224,7 @@
|
|||||||
<button class="secondary-button footer-btn" @click="toggleSummarySpeech">
|
<button class="secondary-button footer-btn" @click="toggleSummarySpeech">
|
||||||
{{ speechButtonLabel('summary') }}
|
{{ speechButtonLabel('summary') }}
|
||||||
</button>
|
</button>
|
||||||
|
<button class="secondary-button footer-btn" @click="practiceFromSummary">去练一遍</button>
|
||||||
<button class="primary-button footer-btn footer-close" @click="closeSummary">我知道了</button>
|
<button class="primary-button footer-btn footer-close" @click="closeSummary">我知道了</button>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -685,6 +686,12 @@ const closeSummary = () => {
|
|||||||
summaryCard.value = null;
|
summaryCard.value = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 学练闭环(旧 H5 逻辑保留):看完总结卡直接去练一遍。 */
|
||||||
|
const practiceFromSummary = () => {
|
||||||
|
closeSummary();
|
||||||
|
uni.switchTab({ url: '/pages/user/practice/index' });
|
||||||
|
};
|
||||||
|
|
||||||
const speechButtonLabel = (key: string) => {
|
const speechButtonLabel = (key: string) => {
|
||||||
if (speechState.value.key !== key) return '播报';
|
if (speechState.value.key !== key) return '播报';
|
||||||
if (speechState.value.status === 'loading') return '生成语音中';
|
if (speechState.value.status === 'loading') return '生成语音中';
|
||||||
|
|||||||
Reference in New Issue
Block a user