- DB: companions.voice_intro_url;仓储 updateCompanionVoice;详情与 /api/expert/me 返回 voiceIntroUrl/voiceDuration - 后端: POST /api/companions/:id/voice(音频白名单 mp3/m4a/aac/wav/ogg、5MB、≤60s、限流、仅本人或管理员) - 小程序: api.uploadVoiceIntro(uni.uploadFile + 用户令牌);工作台新增「语音介绍」卡片(录制/重录/试听,60s mp3);详情页改为 uni.createInnerAudioContext 真实播放,卸载销毁 - 修复 uploadImage 未携带用户令牌(生产 fail-closed 后会导致上传失败) - 新增 voice-intro.spec.ts(104 套件/701 用例全绿);冒烟 7/7
55 行
2.3 KiB
TypeScript
55 行
2.3 KiB
TypeScript
// 已读取AGENTS.md
|
|
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
|
|
/**
|
|
* 第八十八批:大神语音介绍(录音试听)真实落地。
|
|
* 说明:「语音试听」= 大神自我介绍录音;平台不提供实时语音房/连麦。
|
|
*/
|
|
describe('第八十八批语音介绍闸门', () => {
|
|
const root = path.resolve(__dirname, '../../');
|
|
const read = (p: string) => fs.readFileSync(path.join(root, p), 'utf-8');
|
|
const indexCode = read('server/src/index.ts');
|
|
const repoCode = read('server/src/db/repository.ts');
|
|
const mysqlCode = read('server/src/db/mysql.ts');
|
|
const api = read('pwuniapp/common/api.js');
|
|
const detail = read('pwuniapp/pages/expert/detail.vue');
|
|
const workspace = read('pwuniapp/pages/expert/workspace.vue');
|
|
|
|
it('数据库与仓储支持语音介绍地址/时长', () => {
|
|
expect(mysqlCode).toContain('voice_intro_url');
|
|
expect(repoCode).toContain('voiceIntroUrl');
|
|
expect(repoCode).toContain('async updateCompanionVoice(');
|
|
});
|
|
|
|
it('提供语音上传接口(音频白名单 + 限流 + 归属校验)', () => {
|
|
expect(indexCode).toContain("app.post(\n '/api/companions/:id/voice'");
|
|
expect(indexCode).toContain("name: 'voice_upload'");
|
|
expect(indexCode).toContain("'audio/mpeg'");
|
|
expect(indexCode).toContain("assertCompanionActor(req, own, '上传语音介绍')");
|
|
expect(indexCode).toContain('fileSize: 5 * 1024 * 1024');
|
|
});
|
|
|
|
it('详情页真实播放(不再用 setTimeout 假动画)', () => {
|
|
expect(detail).toContain('voiceIntroUrl');
|
|
expect(detail).toContain('uni.createInnerAudioContext()');
|
|
expect(detail).not.toContain('4s 真实原声');
|
|
// 播放器需在卸载时销毁,避免泄漏
|
|
expect(detail).toContain('voiceAudio.destroy()');
|
|
});
|
|
|
|
it('工作台支持录音上传与试听', () => {
|
|
expect(workspace).toContain('uni.getRecorderManager()');
|
|
expect(workspace).toContain('uploadVoiceIntro(');
|
|
expect(workspace).toContain('format: \'mp3\'');
|
|
expect(workspace).toContain('duration: 60000');
|
|
expect(workspace).toContain('uni.createInnerAudioContext()');
|
|
});
|
|
|
|
it('上传类接口携带用户令牌(含图片上传修复)', () => {
|
|
expect(api).toContain('function authHeader()');
|
|
expect(api).toContain('export function uploadVoiceIntro(');
|
|
expect(api).toContain('header: authHeader()');
|
|
});
|
|
});
|