diff --git a/pwuniapp/common/api.js b/pwuniapp/common/api.js
index c492004..eb1c181 100644
--- a/pwuniapp/common/api.js
+++ b/pwuniapp/common/api.js
@@ -872,6 +872,18 @@ export async function applyPostParty(postId, applyData = {}) {
}
}
+/**
+ * 用户会话 token 请求头(上传类接口需要)
+ */
+function authHeader() {
+ try {
+ const t = uni.getStorageSync('userToken');
+ return t ? { Authorization: `Bearer ${t}` } : {};
+ } catch (_) {
+ return {};
+ }
+}
+
/**
* 真实上传本地图片至服务端持久化静态存储
* @param {string} tempFilePath 本地图片临时路径 (如 wxfile://tmp_xxx 或 blob:xxx)
@@ -917,6 +929,7 @@ export function uploadImage(tempFilePath) {
url: uploadUrl,
filePath: tempFilePath,
name: 'file',
+ header: authHeader(),
success: (uploadRes) => {
try {
const data = JSON.parse(uploadRes.data);
@@ -1097,6 +1110,51 @@ export async function deleteExpertService(expertId, serviceId) {
return res;
}
+/**
+ * 上传大神语音介绍(录音文件),返回可直接播放的公网地址
+ * @param {number} expertId 大神ID
+ * @param {string} tempFilePath 录音临时文件路径
+ * @param {number} duration 时长(秒,≤60)
+ */
+export function uploadVoiceIntro(expertId, tempFilePath, duration) {
+ return new Promise((resolve, reject) => {
+ if (!tempFilePath) return reject(new Error('语音文件路径为空'));
+ // #ifdef H5
+ const uploadUrl = `/api/companions/${Number(expertId)}/voice`;
+ // #endif
+ // #ifndef H5
+ const uploadUrl = `https://peiww.gynhc.com/api/companions/${Number(expertId)}/voice`;
+ // #endif
+ uni.uploadFile({
+ url: uploadUrl,
+ filePath: tempFilePath,
+ name: 'file',
+ header: authHeader(),
+ formData: {
+ duration: String(Math.min(60, Math.max(1, Math.round(Number(duration) || 15)))),
+ userId: String(normalizeUserId()),
+ },
+ success: (uploadRes) => {
+ try {
+ const data = JSON.parse(uploadRes.data);
+ if (data && data.code === 20000 && data.data && data.data.voiceIntroUrl) {
+ let finalUrl = data.data.voiceIntroUrl;
+ // #ifndef H5
+ if (String(finalUrl).startsWith('/uploads/')) finalUrl = `https://peiww.gynhc.com${finalUrl}`;
+ // #endif
+ resolve({ url: finalUrl, duration: data.data.voiceDuration });
+ } else {
+ reject(new Error((data && data.message) || '语音上传失败'));
+ }
+ } catch (e) {
+ reject(new Error('语音上传返回格式错误'));
+ }
+ },
+ fail: (err) => reject(new Error(err.errMsg || '语音上传网络异常')),
+ });
+ });
+}
+
/**
* 获取用户收藏的陪玩列表
*/
diff --git a/pwuniapp/pages/expert/detail.vue b/pwuniapp/pages/expert/detail.vue
index 9ce0eb8..2cbf310 100644
--- a/pwuniapp/pages/expert/detail.vue
+++ b/pwuniapp/pages/expert/detail.vue
@@ -52,14 +52,14 @@
- {{ isPlayingVoice ? '正在播放打招呼原声...' : '点击试听打招呼原声' }}
+ {{ isPlayingVoice ? '正在播放语音介绍...' : (expert.voiceIntroUrl ? '点击试听语音介绍' : '暂未上传语音介绍') }}
- {{ expert.voiceDuration }}s 真实原声
+ {{ expert.voiceIntroUrl ? expert.voiceDuration + 's 真实录音' : '暂无可试听内容' }}
试听
@@ -280,6 +280,7 @@ onMounted(() => {
onUnmounted(() => {
uni.$off('theme-change', onThemeChanged);
+ try { if (voiceAudio) { voiceAudio.destroy(); voiceAudio = null; } } catch (_) {}
});
const stopPropagation = (e) => {
@@ -335,6 +336,7 @@ const expert = ref({
const isCompanion = computed(() => expert.value.isCompanion !== false);
const selectedServiceId = ref('srv_1');
const isPlayingVoice = ref(false);
+let voiceAudio = null;
let currentExpertTargetId = null;
const refreshFavoriteState = async () => {
@@ -526,13 +528,27 @@ const selectService = (srv) => {
};
const toggleVoice = () => {
- isPlayingVoice.value = !isPlayingVoice.value;
- if (isPlayingVoice.value) {
- uni.showToast({ title: '正在播放大神打招呼原声', icon: 'none' });
- setTimeout(() => {
- isPlayingVoice.value = false;
- }, 4000);
+ const url = String((expert.value && expert.value.voiceIntroUrl) || '');
+ if (!url) {
+ uni.showToast({ title: '该大神暂未上传语音介绍', icon: 'none' });
+ return;
}
+ if (isPlayingVoice.value) {
+ try { voiceAudio && voiceAudio.pause(); } catch (_) {}
+ isPlayingVoice.value = false;
+ return;
+ }
+ if (!voiceAudio) {
+ voiceAudio = uni.createInnerAudioContext();
+ voiceAudio.onEnded(() => { isPlayingVoice.value = false; });
+ voiceAudio.onError(() => {
+ isPlayingVoice.value = false;
+ uni.showToast({ title: '语音播放失败,请稍后重试', icon: 'none' });
+ });
+ }
+ voiceAudio.src = url;
+ voiceAudio.play();
+ isPlayingVoice.value = true;
};
const chatOnline = () => {
diff --git a/pwuniapp/pages/expert/workspace.vue b/pwuniapp/pages/expert/workspace.vue
index 4c24ac0..54cdd4c 100644
--- a/pwuniapp/pages/expert/workspace.vue
+++ b/pwuniapp/pages/expert/workspace.vue
@@ -194,6 +194,29 @@
+
+
+
+
+
+ 语音介绍(试听)
+
+ ≤60 秒 · 仅本人录音
+
+
+
+
+
+ {{ voiceUploading ? '上传中…' : (expert.voiceIntroUrl ? `已上传 · ${expert.voiceDuration || 0} 秒` : '暂未上传') }}
+
+
+ 语音仅用于买家试听介绍,平台不提供实时语音房;实际语音沟通在游戏内或微信进行。
+
+
@@ -443,7 +466,7 @@