feat(voice): 入驻页录音 + 后台审核真实试听
- 入驻申请页新增「语音自我介绍(可选,≤60s)」录音/试听,申请成功拿到大神档案 id 后自动上传,失败不影响入驻结果 - 管理端审核「真人语音包核听」由 3 秒假播放改为按 voiceIntroUrl 真实播放,未上传显示灰色标记 - 清理小程序审核敏感词(语音房/连麦/开麦),入驻页身份改用 normalizeUserId 与 token 保持一致 - 新增 voice-intro-consistency.spec.ts(107 套件/709 用例全绿)
这个提交包含在:
@@ -64,16 +64,18 @@
|
||||
<template #cell="{ record }">
|
||||
<a-space>
|
||||
<a-button
|
||||
v-if="record.voiceIntroUrl"
|
||||
size="mini"
|
||||
type="outline"
|
||||
shape="round"
|
||||
@click="playVoice(record.id)"
|
||||
@click="playVoice(record)"
|
||||
>
|
||||
<template #icon>
|
||||
<icon-sound />
|
||||
</template>
|
||||
{{ playingId === record.id ? '播放中 16s...' : '试听语音包' }}
|
||||
{{ playingId === record.id ? '播放中…' : '试听语音包' }}
|
||||
</a-button>
|
||||
<a-tag v-else color="gray">未上传</a-tag>
|
||||
</a-space>
|
||||
</template>
|
||||
</a-table-column>
|
||||
@@ -161,7 +163,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue';
|
||||
import axios from 'axios';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
@@ -214,15 +216,39 @@
|
||||
}
|
||||
};
|
||||
|
||||
const playVoice = (id: number) => {
|
||||
playingId.value = id;
|
||||
setTimeout(() => {
|
||||
if (playingId.value === id) {
|
||||
playingId.value = null;
|
||||
}
|
||||
}, 3000);
|
||||
let voiceAudio: HTMLAudioElement | null = null;
|
||||
const playVoice = (record: any) => {
|
||||
const url = String(record?.voiceIntroUrl || '');
|
||||
if (!url) {
|
||||
Message.info('该申请人未上传语音介绍');
|
||||
return;
|
||||
}
|
||||
// 再次点击同一条 = 停止
|
||||
if (playingId.value === record.id) {
|
||||
try { voiceAudio?.pause(); } catch (_) {}
|
||||
playingId.value = null;
|
||||
return;
|
||||
}
|
||||
try { voiceAudio?.pause(); } catch (_) {}
|
||||
voiceAudio = new Audio(url);
|
||||
voiceAudio.onended = () => { playingId.value = null; };
|
||||
voiceAudio.onerror = () => {
|
||||
playingId.value = null;
|
||||
Message.error('语音播放失败,请检查文件是否存在');
|
||||
};
|
||||
voiceAudio.play().catch(() => {
|
||||
playingId.value = null;
|
||||
Message.error('浏览器阻止了自动播放,请重试');
|
||||
});
|
||||
playingId.value = record.id;
|
||||
};
|
||||
|
||||
onUnmounted(() => {
|
||||
try { voiceAudio?.pause(); } catch (_) {}
|
||||
voiceAudio = null;
|
||||
playingId.value = null;
|
||||
});
|
||||
|
||||
const handleAudit = async (id: number, action: 'approve' | 'reject' | 'revoke', reason?: string) => {
|
||||
try {
|
||||
await axios.post(`/api/companions/${id}/audit`, {
|
||||
|
||||
在新工单中引用
屏蔽一个用户