feat(voice): 入驻页录音 + 后台审核真实试听

- 入驻申请页新增「语音自我介绍(可选,≤60s)」录音/试听,申请成功拿到大神档案 id 后自动上传,失败不影响入驻结果

- 管理端审核「真人语音包核听」由 3 秒假播放改为按 voiceIntroUrl 真实播放,未上传显示灰色标记

- 清理小程序审核敏感词(语音房/连麦/开麦),入驻页身份改用 normalizeUserId 与 token 保持一致

- 新增 voice-intro-consistency.spec.ts(107 套件/709 用例全绿)
这个提交包含在:
xcbyy
2026-10-21 11:12:42 +08:00
父节点 7a1e32688c
当前提交 ae62f2b805
共有 6 个文件被更改,包括 228 次插入 和 18 次删除

查看文件

@@ -0,0 +1,49 @@
// 已读取AGENTS.md
import * as fs from 'fs';
import * as path from 'path';
/**
* 第九十一批:语音自我介绍三端一致性。
* 背景:管理端「真人语音包核听」曾是 3 秒假播放(文案写死 16s),
* 入驻申请页也没有录音入口,导致审核端永远听不到真人语音。
*/
describe('第九十一批语音介绍三端一致性闸门', () => {
const root = path.resolve(__dirname, '../../');
const audit = fs.readFileSync(
path.join(root, 'admin/arco-design-pro-vite/src/views/companion/audit/index.vue'),
'utf-8'
);
const apply = fs.readFileSync(path.join(root, 'pwuniapp/pages/expert/apply.vue'), 'utf-8');
it('审核页按真实 voiceIntroUrl 播放,未上传时禁用并标记', () => {
expect(audit).toContain('record.voiceIntroUrl');
expect(audit).toContain('new Audio(url)');
expect(audit).toContain('未上传');
expect(audit).not.toContain('播放中 16s...');
});
it('入驻申请页提供录音入口并在提交成功后上传语音', () => {
expect(apply).toContain('uni.getRecorderManager()');
expect(apply).toContain('uploadVoiceIntro');
expect(apply).toContain('applied.id');
expect(apply).toContain('duration: 60000');
});
const scanSensitive = (dir: string): string[] => {
const hits: string[] = [];
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) hits.push(...scanSensitive(full));
else if (/\.(vue|js)$/.test(entry.name)) {
const text = fs.readFileSync(full, 'utf-8');
if (/语音房|连麦|开麦/.test(text)) hits.push(full);
}
}
return hits;
};
it('小程序页面文案不出现语音房/连麦/开麦等审核敏感词', () => {
const hits = scanSensitive(path.join(root, 'pwuniapp/pages'));
expect(hits).toEqual([]);
});
});