增加录音功能调整页面布局。
This commit is contained in:
@@ -443,8 +443,7 @@ export default {
|
||||
detailedAddress: this.formData.detailedAddress?.trim() || "",
|
||||
salesPhone: trimmedSalesPhone || "",
|
||||
contactCount: Number(this.formData.contactCount) || 0,
|
||||
operationType: action,
|
||||
scenario: "furniture"
|
||||
operationType: action
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -455,9 +454,13 @@ export default {
|
||||
// 获取认证信息
|
||||
let tenantId = '';
|
||||
let token = '';
|
||||
let scenario = '';
|
||||
try {
|
||||
const loginResponse = uni.getStorageSync('backend-login-response') || {};
|
||||
tenantId = uni.getStorageSync('backend-tenant-id') || '';
|
||||
token = uni.getStorageSync('backend-token') || '';
|
||||
// 场景值来自登录返回,兜底读取历史缓存字段
|
||||
scenario = (loginResponse.scenario || uni.getStorageSync('backend-scenario') || '').toString().trim();
|
||||
} catch (e) {
|
||||
console.error('获取认证信息失败:', e);
|
||||
}
|
||||
@@ -472,6 +475,10 @@ export default {
|
||||
if (tenantId) {
|
||||
headers['X-Tenant-Id'] = tenantId;
|
||||
}
|
||||
if (scenario) {
|
||||
headers['X-Scenario'] = scenario;
|
||||
params.scenario = scenario;
|
||||
}
|
||||
|
||||
const res = await uni.request({
|
||||
url: getApiUrl('/api/customerManagement/add'),
|
||||
|
||||
@@ -19,18 +19,18 @@
|
||||
<view class="content">
|
||||
<!-- 标签页 -->
|
||||
<view class="tabs" :style="{ top: computedNavbarTop || navbarTop }">
|
||||
<view
|
||||
class="tab-item"
|
||||
:class="{ active: activeTab === 'status' }"
|
||||
@click="switchTab('status')">
|
||||
<text>服务中</text>
|
||||
</view>
|
||||
<view
|
||||
class="tab-item"
|
||||
:class="{ active: activeTab === 'reception' }"
|
||||
@click="switchTab('reception')">
|
||||
<text>开始接待</text>
|
||||
</view>
|
||||
<view
|
||||
class="tab-item"
|
||||
:class="{ active: activeTab === 'status' }"
|
||||
@click="switchTab('status')">
|
||||
<text>服务中</text>
|
||||
</view>
|
||||
<view
|
||||
class="tab-item"
|
||||
:class="{ active: activeTab === 'tag' }"
|
||||
|
||||
@@ -52,6 +52,20 @@
|
||||
<text class="staff-name">{{ item.staffName || '未分配销售' }}</text>
|
||||
</view>
|
||||
<view class="service-status">
|
||||
<view
|
||||
v-if="!isRecordingItem(item.id)"
|
||||
class="service-action-btn service-action-btn--record"
|
||||
@click.stop="startPhoneRecord(item)"
|
||||
>
|
||||
<text>录音</text>
|
||||
</view>
|
||||
<view
|
||||
v-else
|
||||
class="service-action-btn service-action-btn--record service-action-btn--recording"
|
||||
@click.stop="stopPhoneRecordAndUpload(item)"
|
||||
>
|
||||
<text>停止</text>
|
||||
</view>
|
||||
<view class="service-action-btn service-action-btn--supplement" @click.stop="showSupplementDialog(item)">
|
||||
<text>补录</text>
|
||||
</view>
|
||||
@@ -212,7 +226,11 @@ export default {
|
||||
contact: "",
|
||||
recordingName: "",
|
||||
remarks: ""
|
||||
}
|
||||
},
|
||||
recorderSupported: false,
|
||||
recorderManager: null,
|
||||
recordingServiceId: null,
|
||||
recordingContext: null
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -220,9 +238,102 @@ export default {
|
||||
this.checkUserRole();
|
||||
// 获取当前用户手机号
|
||||
this.loadCurrentUserPhone();
|
||||
this.initServiceRecorder();
|
||||
this.fetchServiceStatusList();
|
||||
},
|
||||
beforeUnmount() {
|
||||
if (this.recorderManager && this.recordingServiceId) {
|
||||
try {
|
||||
this.recorderManager.stop();
|
||||
} catch (e) {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initServiceRecorder() {
|
||||
this.recorderSupported = typeof uni.getRecorderManager === 'function';
|
||||
if (!this.recorderSupported) {
|
||||
return;
|
||||
}
|
||||
this.recorderManager = uni.getRecorderManager();
|
||||
// 用户点击「停止」后由系统回调此处,再将临时录音文件上传到 /api/audio/upload
|
||||
this.recorderManager.onStop((res) => {
|
||||
const ctx = this.recordingContext;
|
||||
this.recordingServiceId = null;
|
||||
this.recordingContext = null;
|
||||
const tempFilePath = res.tempFilePath || '';
|
||||
if (!ctx || !ctx.id) {
|
||||
return;
|
||||
}
|
||||
if (!tempFilePath) {
|
||||
uni.showToast({ title: '未获取到录音文件', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
const name = `service_record_${ctx.id}_${Date.now()}.mp3`;
|
||||
this.uploadFileForRecord(ctx, { path: tempFilePath, name });
|
||||
});
|
||||
this.recorderManager.onError(() => {
|
||||
this.recordingServiceId = null;
|
||||
this.recordingContext = null;
|
||||
uni.showToast({ title: '录音出错', icon: 'none' });
|
||||
});
|
||||
},
|
||||
isRecordingItem(recordId) {
|
||||
if (!recordId || !this.recordingServiceId) {
|
||||
return false;
|
||||
}
|
||||
return String(recordId) === this.recordingServiceId;
|
||||
},
|
||||
startPhoneRecord(item) {
|
||||
if (!this.recorderSupported || !this.recorderManager) {
|
||||
uni.showToast({
|
||||
title: '当前环境不支持录音,请使用微信小程序或 App',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!item || !item.id) {
|
||||
uni.showToast({
|
||||
title: '无法获取服务记录ID',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (this.recordingServiceId) {
|
||||
uni.showToast({ title: '请先停止当前录音', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (this.isUploading(item.id)) {
|
||||
uni.showToast({ title: '正在上传,请稍候', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
this.recordingContext = { ...item };
|
||||
this.recordingServiceId = String(item.id);
|
||||
try {
|
||||
this.recorderManager.start({
|
||||
duration: 600000,
|
||||
sampleRate: 44100,
|
||||
numberOfChannels: 1,
|
||||
encodeBitRate: 96000,
|
||||
format: 'mp3'
|
||||
});
|
||||
} catch (e) {
|
||||
this.recordingServiceId = null;
|
||||
this.recordingContext = null;
|
||||
uni.showToast({ title: '无法开始录音', icon: 'none' });
|
||||
}
|
||||
},
|
||||
/** 结束录音;onStop 回调中会调用 uploadFileForRecord 上传至后端 */
|
||||
stopPhoneRecordAndUpload(item) {
|
||||
if (!this.recorderManager || !item?.id) {
|
||||
return;
|
||||
}
|
||||
if (String(item.id) !== this.recordingServiceId) {
|
||||
return;
|
||||
}
|
||||
this.recorderManager.stop();
|
||||
},
|
||||
/**
|
||||
* 检查用户角色,判断是否包含admin
|
||||
* 只要角色中包含admin字符串(如admin_furniture),就视为admin角色
|
||||
@@ -467,6 +578,22 @@ export default {
|
||||
if (!recordId) return false;
|
||||
return this.uploadingIds.includes(String(recordId));
|
||||
},
|
||||
/** 仅允许扩展名为 .mp3 的文件(不区分大小写) */
|
||||
isMp3UploadFile(selected) {
|
||||
if (!selected || !selected.path) return false;
|
||||
const pickBase = (s) => {
|
||||
if (!s || typeof s !== 'string') return '';
|
||||
const seg = s.split('/').pop() || s.split('\\').pop() || s;
|
||||
return seg.trim();
|
||||
};
|
||||
const bases = [pickBase(selected.name), pickBase(selected.path)].filter(Boolean);
|
||||
for (const base of bases) {
|
||||
if (base.toLowerCase().endsWith('.mp3')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
async chooseAndUploadFile(item) {
|
||||
if (!item || !item.id) {
|
||||
uni.showToast({
|
||||
@@ -508,6 +635,14 @@ export default {
|
||||
resolve(null);
|
||||
return;
|
||||
}
|
||||
if (!this.isMp3UploadFile(selected)) {
|
||||
uni.showToast({
|
||||
title: '仅支持上传 MP3 文件',
|
||||
icon: 'none'
|
||||
});
|
||||
resolve(null);
|
||||
return;
|
||||
}
|
||||
resolve(selected);
|
||||
};
|
||||
const onFail = (err) => {
|
||||
@@ -535,6 +670,7 @@ export default {
|
||||
if (typeof uni.chooseFile === 'function') {
|
||||
uni.chooseFile({
|
||||
count: 1,
|
||||
extension: ['.mp3'],
|
||||
success: onSuccess,
|
||||
fail: onFail
|
||||
});
|
||||
@@ -573,11 +709,12 @@ export default {
|
||||
title: '上传中...'
|
||||
});
|
||||
const uploadRes = await uni.uploadFile({
|
||||
url: getApiUrl('/api/audioManagement/uploadBluetoothAudio'),
|
||||
url: getApiUrl('/api/audio/upload'),
|
||||
filePath: selectedFile.path,
|
||||
name: 'file',
|
||||
formData: {
|
||||
id: item.id,
|
||||
audioId: item.id,
|
||||
customerId: item.customerId || '',
|
||||
customerName: item.customerName || '',
|
||||
fileName: selectedFile.name || `service_file_${Date.now()}`
|
||||
@@ -1210,6 +1347,19 @@ export default {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.service-action-btn--record {
|
||||
color: #007AFF;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.service-action-btn--record:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.service-action-btn--recording {
|
||||
color: #FF3B30;
|
||||
}
|
||||
|
||||
.service-status-empty {
|
||||
padding: 48rpx 0;
|
||||
text-align: center;
|
||||
|
||||
Reference in New Issue
Block a user