feat(speech): add qwen tts voice preferences
This commit is contained in:
@@ -271,6 +271,25 @@
|
||||
</view>
|
||||
<text class="display-note">切换后同步到今日、练、问、我全部页面,并自动保存。</text>
|
||||
</template>
|
||||
|
||||
<view v-if="loggedIn" class="voice-preference-row">
|
||||
<view class="display-heading-copy">
|
||||
<text class="menu-item-title">AI 播报音色</text>
|
||||
<text class="menu-item-desc">{{ currentTtsVoiceLabel }} · 对练情绪和语速仍会保留</text>
|
||||
</view>
|
||||
<picker :range="qwenTtsVoiceOptions" range-key="label" :value="ttsVoiceOptionIndex" @change="changeTtsVoice">
|
||||
<view class="voice-picker-value">{{ currentTtsVoiceLabel }} <uni-icons type="right" size="12" color="#94a3b8" /></view>
|
||||
</picker>
|
||||
</view>
|
||||
<view v-if="loggedIn" class="voice-preference-row">
|
||||
<view class="display-heading-copy">
|
||||
<text class="menu-item-title">AI 播报方言</text>
|
||||
<text class="menu-item-desc">{{ currentTtsDialectLabel }} · 仅影响服务端语音,失败时不退回普通话</text>
|
||||
</view>
|
||||
<picker :range="qwenTtsDialectOptions" range-key="label" :value="ttsDialectOptionIndex" @change="changeTtsDialect">
|
||||
<view class="voice-picker-value">{{ currentTtsDialectLabel }} <uni-icons type="right" size="12" color="#94a3b8" /></view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -297,6 +316,16 @@ import {
|
||||
import { getCompetencyProfile, getPracticeHistory, getPromotionEvidence } from '@/services/practice';
|
||||
import { resetPageScroll } from '@/services/navigation';
|
||||
import { ensureEmployeePosition } from '@/services/position';
|
||||
import {
|
||||
getTtsVoicePreference,
|
||||
getTtsDialectPreference,
|
||||
qwenTtsDialectOptions,
|
||||
qwenTtsVoiceOptions,
|
||||
setTtsDialectPreference,
|
||||
setTtsVoicePreference,
|
||||
type TtsDialectPreference,
|
||||
type TtsVoicePreference
|
||||
} from '@/services/tts-voice-preference';
|
||||
|
||||
const loggedIn = ref(false);
|
||||
const phone = ref('');
|
||||
@@ -313,9 +342,19 @@ const evidence = ref<PromotionEvidence | null>(null);
|
||||
const positionProfile = ref(getSelectedPositionProfile());
|
||||
const supervisorLearning = ref(false);
|
||||
const fontSize = ref<AppFontSize>(getAppFontSize());
|
||||
const ttsVoice = ref<TtsVoicePreference>('');
|
||||
const ttsDialect = ref<TtsDialectPreference>('');
|
||||
const currentFontSizeLabel = computed(() =>
|
||||
appFontSizeOptions.find((item) => item.value === fontSize.value)?.label || '标准'
|
||||
);
|
||||
const ttsVoiceOptionIndex = computed(() => Math.max(0, qwenTtsVoiceOptions.findIndex((item) => item.value === ttsVoice.value)));
|
||||
const currentTtsVoiceLabel = computed(() =>
|
||||
qwenTtsVoiceOptions[ttsVoiceOptionIndex.value]?.label || '跟随场景'
|
||||
);
|
||||
const ttsDialectOptionIndex = computed(() => Math.max(0, qwenTtsDialectOptions.findIndex((item) => item.value === ttsDialect.value)));
|
||||
const currentTtsDialectLabel = computed(() =>
|
||||
qwenTtsDialectOptions[ttsDialectOptionIndex.value]?.label || '跟随场景'
|
||||
);
|
||||
const maskedPhone = computed(() => {
|
||||
const value = phone.value.trim();
|
||||
if (!value) return '未登录';
|
||||
@@ -333,6 +372,8 @@ const refreshAuth = () => {
|
||||
positionProfile.value = getSelectedPositionProfile();
|
||||
supervisorLearning.value = isSupervisorLearnerMode();
|
||||
fontSize.value = getAppFontSize();
|
||||
ttsVoice.value = getTtsVoicePreference(auth.tenantId, auth.phone);
|
||||
ttsDialect.value = getTtsDialectPreference(auth.tenantId, auth.phone);
|
||||
};
|
||||
|
||||
const changeFontSize = (value: AppFontSize) => {
|
||||
@@ -340,6 +381,20 @@ const changeFontSize = (value: AppFontSize) => {
|
||||
uni.showToast({ title: `已切换为${currentFontSizeLabel.value}`, icon: 'none' });
|
||||
};
|
||||
|
||||
const changeTtsVoice = (event: { detail?: { value?: string | number } }) => {
|
||||
const option = qwenTtsVoiceOptions[Number(event.detail?.value)];
|
||||
const auth = getAuth();
|
||||
ttsVoice.value = setTtsVoicePreference(auth.tenantId, auth.phone, option?.value);
|
||||
uni.showToast({ title: `已切换为${currentTtsVoiceLabel.value}`, icon: 'none' });
|
||||
};
|
||||
|
||||
const changeTtsDialect = (event: { detail?: { value?: string | number } }) => {
|
||||
const option = qwenTtsDialectOptions[Number(event.detail?.value)];
|
||||
const auth = getAuth();
|
||||
ttsDialect.value = setTtsDialectPreference(auth.tenantId, auth.phone, option?.value);
|
||||
uni.showToast({ title: `已切换为${currentTtsDialectLabel.value}`, icon: 'none' });
|
||||
};
|
||||
|
||||
const returnToSupervisor = () => {
|
||||
leaveSupervisorLearnerMode();
|
||||
supervisorLearning.value = false;
|
||||
@@ -650,6 +705,28 @@ onShow(() => {
|
||||
box-shadow: 0 4px 12px rgba(24, 34, 48, 0.08);
|
||||
}
|
||||
|
||||
.voice-preference-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding-top: 12px;
|
||||
border-top: 1px solid var(--employee-line);
|
||||
}
|
||||
|
||||
.voice-picker-value {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
max-width: 150px;
|
||||
padding: 8px 10px;
|
||||
border: 1px solid #e3e6ea;
|
||||
border-radius: 10px;
|
||||
color: var(--employee-text);
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.profile-summary {
|
||||
border-color: var(--employee-line);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user