feat(practice): streamline pilot content operations
This commit is contained in:
@@ -74,7 +74,7 @@
|
||||
<text class="scene-picker-note">复杂场景的正式前置解锁规则仍待业务确认;系统不会以估算分数硬性拦截已发布训练。</text>
|
||||
</view>
|
||||
|
||||
<view v-if="loggedIn && practiceView === 'prep' && availableScenarios.length" class="panel scenario-card employee-card">
|
||||
<view v-if="loggedIn && practiceView === 'prep' && availableScenarios.length" class="panel scenario-card practice-scenario-card employee-card">
|
||||
<view class="scenario-headline">
|
||||
<text class="scenario-title">{{ activeScenarioName }}</text>
|
||||
<text class="scenario-desc">{{ selectedScenarioDescription }}</text>
|
||||
@@ -110,7 +110,14 @@
|
||||
>
|
||||
{{ status === 'finished' ? '再练一次' : '我已准备好,开始练习' }}
|
||||
</button>
|
||||
<view v-if="(status === 'idle' || status === 'finished') && realtimePersonaOptions.length" class="realtime-persona-picker">
|
||||
</view>
|
||||
|
||||
<view v-if="loggedIn && practiceView === 'prep'" class="panel scenario-card realtime-entry-card employee-card">
|
||||
<view class="scenario-headline">
|
||||
<text class="scenario-title">实时陪练 Beta</text>
|
||||
<text class="scenario-desc">直接与数字师傅或模拟业主对话,不依赖场景审核发布。</text>
|
||||
</view>
|
||||
<view v-if="realtimePersonaOptions.length" class="realtime-persona-picker">
|
||||
<view class="realtime-persona-heading">
|
||||
<text class="realtime-persona-title">实时陪练人设</text>
|
||||
</view>
|
||||
@@ -134,10 +141,10 @@
|
||||
<button
|
||||
v-if="status === 'idle' || status === 'finished'"
|
||||
class="secondary-button realtime-start-button"
|
||||
:disabled="!canStartPractice || busy"
|
||||
:disabled="!canStartRealtime || busy"
|
||||
@click="startRealtime"
|
||||
>
|
||||
实时陪练 Beta
|
||||
开始实时陪练
|
||||
</button>
|
||||
<text class="realtime-beta-note">自然打断、边听边说;本次体验不计入训练成绩。</text>
|
||||
</view>
|
||||
@@ -593,6 +600,9 @@ const canStartPractice = computed(() =>
|
||||
&& (status.value === 'idle' || status.value === 'finished')
|
||||
&& Boolean(selectedScenario.value?.id)
|
||||
);
|
||||
const canStartRealtime = computed(() =>
|
||||
status.value === 'idle' || status.value === 'finished'
|
||||
);
|
||||
const hasTraineeReply = computed(() => turns.value.some((item) => item.role === 'trainee'));
|
||||
const canFinishPractice = computed(() => hasTraineeReply.value && !redFlagActive.value);
|
||||
const hasCoachState = computed(() => emotionScore.value > 0 || trustScore.value > 0 || redFlagActive.value);
|
||||
@@ -1005,7 +1015,7 @@ const stopRealtime = () => {
|
||||
};
|
||||
|
||||
const startRealtime = async () => {
|
||||
if (!canStartPractice.value || !requireLogin()) return;
|
||||
if (!canStartRealtime.value || !requireLogin()) return;
|
||||
speechPlayback.stop();
|
||||
cancelRecording();
|
||||
turnVoiceGeneration += 1;
|
||||
|
||||
@@ -376,10 +376,14 @@ test('场景目录加载失败时清空旧场景并禁止开始训练', async ()
|
||||
assert.match(source, /!curriculumLoading\.value/);
|
||||
});
|
||||
|
||||
test('无已发布场景时不展示默认预习卡或训练入口', async () => {
|
||||
test('无已发布场景时隐藏常规训练,但仍展示独立实时陪练入口', async () => {
|
||||
const source = await pageSource('../src/pages/user/practice/index.vue');
|
||||
|
||||
assert.match(source, /v-if="loggedIn && practiceView === 'prep' && availableScenarios\.length" class="panel scenario-card employee-card"/);
|
||||
assert.match(source, /v-if="loggedIn && practiceView === 'prep' && availableScenarios\.length" class="panel scenario-card practice-scenario-card employee-card"/);
|
||||
assert.match(source, /v-if="loggedIn && practiceView === 'prep'" class="panel scenario-card realtime-entry-card employee-card"/);
|
||||
assert.match(source, /:disabled="!canStartRealtime \|\| busy"/);
|
||||
assert.match(source, /if \(!canStartRealtime\.value \|\| !requireLogin\(\)\) return;/);
|
||||
assert.doesNotMatch(source, /if \(!canStartPractice\.value \|\| !requireLogin\(\)\) return;\s*speechPlayback\.stop\(\);\s*cancelRecording\(\);\s*turnVoiceGeneration \+= 1;/);
|
||||
assert.match(source, /const activeScenario = nextScenarios\.find\([\s\S]*?\|\| nextScenarios\[0\];[\s\S]*?else \{\s*selectedScenarioId\.value = '';\s*activeScenarioName\.value = '暂无可用训练场景';\s*prepCard\.value = null;/);
|
||||
});
|
||||
|
||||
|
||||
@@ -56,6 +56,9 @@ test('实时陪练通过受认证代理接入,前端不携带供应商密钥
|
||||
assert.match(page, /fetchRealtimePersonas/);
|
||||
assert.match(page, /createRealtimeSession/);
|
||||
assert.match(page, /正在查知识库/);
|
||||
assert.match(page, /class="panel scenario-card realtime-entry-card employee-card"/);
|
||||
assert.match(page, /const canStartRealtime = computed/);
|
||||
assert.match(page, /if \(!canStartRealtime\.value \|\| !requireLogin\(\)\) return;/);
|
||||
assert.doesNotMatch(page, /realtimeVoice|selectRealtimeVoice|aihr_realtime_practice_voice/);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user