diff --git a/pages-subpackage/furniture_reception/serviceListFurniture.vue b/pages-subpackage/furniture_reception/serviceListFurniture.vue index cfd3cd1..391ec15 100644 --- a/pages-subpackage/furniture_reception/serviceListFurniture.vue +++ b/pages-subpackage/furniture_reception/serviceListFurniture.vue @@ -233,6 +233,20 @@ function firstNonEmptyString(...parts) { return ""; } +// 跨页面录音会话缓存(模块级):页面销毁后仍保留录音状态与分段上传结果 +const recordingSessionCache = { + recordingServiceId: null, + recordingContext: null, + recordingElapsedSeconds: 0, + recordingEstimatedSizeBytes: 0, + recordingManualStopRequested: false, + recordingCurrentSegmentNo: 0, + recordingCurrentSegmentStartAt: 0, + recordingCurrentSegmentElapsedSeconds: 0, + uploadingCountMap: {}, + uploadResultMap: {}, +}; + export default { props: { /** 卡片右侧状态文案,默认与接待页「服务中」Tab 一致 */ @@ -283,22 +297,22 @@ export default { }, recorderSupported: false, recorderManager: null, - recordingServiceId: null, - recordingContext: null, - recordingElapsedSeconds: 0, - recordingEstimatedSizeBytes: 0, + recordingServiceId: recordingSessionCache.recordingServiceId, + recordingContext: recordingSessionCache.recordingContext, + recordingElapsedSeconds: recordingSessionCache.recordingElapsedSeconds, + recordingEstimatedSizeBytes: recordingSessionCache.recordingEstimatedSizeBytes, recordingTicker: null, keepScreenOnEnabled: false, // 上传前压缩策略:从录音源头降低采样率/码率,减少上传文件体积 recordingSampleRate: 16000, recordingEncodeBitRate: 32000, recordingSegmentDurationMs: 5 * 60 * 1000, - recordingManualStopRequested: false, - recordingCurrentSegmentNo: 0, - recordingCurrentSegmentStartAt: 0, - recordingCurrentSegmentElapsedSeconds: 0, - uploadingCountMap: {}, - uploadResultMap: {} + recordingManualStopRequested: recordingSessionCache.recordingManualStopRequested, + recordingCurrentSegmentNo: recordingSessionCache.recordingCurrentSegmentNo, + recordingCurrentSegmentStartAt: recordingSessionCache.recordingCurrentSegmentStartAt, + recordingCurrentSegmentElapsedSeconds: recordingSessionCache.recordingCurrentSegmentElapsedSeconds, + uploadingCountMap: { ...recordingSessionCache.uploadingCountMap }, + uploadResultMap: { ...recordingSessionCache.uploadResultMap } } }, mounted() { @@ -307,26 +321,71 @@ export default { // 获取当前用户手机号 this.loadCurrentUserPhone(); this.initServiceRecorder(); + this.restoreRecordingSessionFromCache(); + if (this.recordingServiceId && this.recordingContext?.id) { + this.startRecordingTicker({ reset: false }); + } this.fetchServiceStatusList(); }, beforeUnmount() { - this.stopRecordingTicker(); - this.setKeepScreenOn(false); - if (this.recorderManager && this.recordingServiceId) { - try { - this.recorderManager.stop(); - } catch (e) { - /* ignore */ - } - } + // 跨页面持续录音:离开页面仅暂停UI定时器,不清空录音显示状态 + this.pauseRecordingTicker(); + // 跨页面持续录音:离开页面时不主动 stop + this.persistRecordingSessionToCache(); }, methods: { + persistRecordingSessionToCache() { + recordingSessionCache.recordingServiceId = this.recordingServiceId || null; + recordingSessionCache.recordingContext = this.recordingContext ? { ...this.recordingContext } : null; + recordingSessionCache.recordingElapsedSeconds = Number(this.recordingElapsedSeconds) || 0; + recordingSessionCache.recordingEstimatedSizeBytes = Number(this.recordingEstimatedSizeBytes) || 0; + recordingSessionCache.recordingManualStopRequested = !!this.recordingManualStopRequested; + recordingSessionCache.recordingCurrentSegmentNo = Number(this.recordingCurrentSegmentNo) || 0; + recordingSessionCache.recordingCurrentSegmentStartAt = Number(this.recordingCurrentSegmentStartAt) || 0; + recordingSessionCache.recordingCurrentSegmentElapsedSeconds = Number(this.recordingCurrentSegmentElapsedSeconds) || 0; + recordingSessionCache.uploadingCountMap = { ...this.uploadingCountMap }; + recordingSessionCache.uploadResultMap = { ...this.uploadResultMap }; + }, + restoreRecordingSessionFromCache() { + this.recordingServiceId = recordingSessionCache.recordingServiceId || null; + this.recordingContext = recordingSessionCache.recordingContext ? { ...recordingSessionCache.recordingContext } : null; + this.recordingElapsedSeconds = Number(recordingSessionCache.recordingElapsedSeconds) || 0; + this.recordingEstimatedSizeBytes = Number(recordingSessionCache.recordingEstimatedSizeBytes) || 0; + this.recordingManualStopRequested = !!recordingSessionCache.recordingManualStopRequested; + this.recordingCurrentSegmentNo = Number(recordingSessionCache.recordingCurrentSegmentNo) || 0; + this.recordingCurrentSegmentStartAt = Number(recordingSessionCache.recordingCurrentSegmentStartAt) || 0; + this.recordingCurrentSegmentElapsedSeconds = Number(recordingSessionCache.recordingCurrentSegmentElapsedSeconds) || 0; + this.uploadingCountMap = { ...recordingSessionCache.uploadingCountMap }; + this.uploadResultMap = { ...recordingSessionCache.uploadResultMap }; + }, initServiceRecorder() { this.recorderSupported = typeof uni.getRecorderManager === 'function'; if (!this.recorderSupported) { return; } - this.recorderManager = uni.getRecorderManager(); + this.ensureRecorderManager(); + this.bindRecorderEvents(); + }, + ensureRecorderManager() { + if (!this.recorderSupported) { + return false; + } + if (!this.recorderManager) { + this.recorderManager = uni.getRecorderManager(); + } + return !!this.recorderManager; + }, + bindRecorderEvents() { + if (!this.ensureRecorderManager()) { + return; + } + // 先解绑,避免重复绑定或被其它页面覆盖后残留旧回调 + if (typeof this.recorderManager.offStop === 'function') { + this.recorderManager.offStop(); + } + if (typeof this.recorderManager.offError === 'function') { + this.recorderManager.offError(); + } // 录音每段停止后回调:静默上传,若非手动停止则继续下一段 this.recorderManager.onStop((res) => { const ctx = this.recordingContext; @@ -384,6 +443,7 @@ export default { this.recordingCurrentSegmentStartAt = 0; this.recordingCurrentSegmentElapsedSeconds = 0; this.setKeepScreenOn(false); + this.persistRecordingSessionToCache(); }); this.recorderManager.onError(() => { this.recordingServiceId = null; @@ -394,6 +454,7 @@ export default { this.recordingCurrentSegmentElapsedSeconds = 0; this.stopRecordingTicker(); this.setKeepScreenOn(false); + this.persistRecordingSessionToCache(); uni.showToast({ title: '录音出错', icon: 'none' }); }); }, @@ -411,25 +472,48 @@ export default { }, }); }, - startRecordingTicker() { - this.stopRecordingTicker(); - this.recordingElapsedSeconds = 0; - this.recordingEstimatedSizeBytes = 0; + startRecordingTicker(options = {}) { + const { reset = true } = options; + this.pauseRecordingTicker(); + if (reset) { + this.recordingElapsedSeconds = 0; + this.recordingEstimatedSizeBytes = 0; + } else if (this.recordingCurrentSegmentStartAt) { + const resumedElapsed = Math.max( + 0, + Math.floor((Date.now() - Number(this.recordingCurrentSegmentStartAt)) / 1000) + ); + this.recordingElapsedSeconds = resumedElapsed; + const bytesPerSecond = (Number(this.recordingEncodeBitRate) || 32000) / 8; + this.recordingEstimatedSizeBytes = Math.floor(resumedElapsed * bytesPerSecond); + } const bytesPerSecond = (Number(this.recordingEncodeBitRate) || 32000) / 8; this.recordingTicker = setInterval(() => { - this.recordingElapsedSeconds += 1; + if (this.recordingCurrentSegmentStartAt) { + this.recordingElapsedSeconds = Math.max( + 0, + Math.floor((Date.now() - Number(this.recordingCurrentSegmentStartAt)) / 1000) + ); + } else { + this.recordingElapsedSeconds += 1; + } this.recordingCurrentSegmentElapsedSeconds = this.recordingElapsedSeconds; this.recordingEstimatedSizeBytes = Math.floor(this.recordingElapsedSeconds * bytesPerSecond); + this.persistRecordingSessionToCache(); }, 1000); }, - stopRecordingTicker() { + pauseRecordingTicker() { if (this.recordingTicker) { clearInterval(this.recordingTicker); } this.recordingTicker = null; + }, + stopRecordingTicker() { + this.pauseRecordingTicker(); this.recordingCurrentSegmentElapsedSeconds = this.recordingElapsedSeconds; this.recordingElapsedSeconds = 0; this.recordingEstimatedSizeBytes = 0; + this.persistRecordingSessionToCache(); }, startNewSegmentRecording() { if (!this.recorderManager || !this.recordingServiceId || !this.recordingContext?.id) { @@ -447,6 +531,7 @@ export default { format: 'mp3' }); this.startRecordingTicker(); + this.persistRecordingSessionToCache(); } catch (e) { this.recordingServiceId = null; this.recordingContext = null; @@ -456,6 +541,7 @@ export default { this.recordingCurrentSegmentElapsedSeconds = 0; this.stopRecordingTicker(); this.setKeepScreenOn(false); + this.persistRecordingSessionToCache(); uni.showToast({ title: '无法开始录音', icon: 'none' }); } }, @@ -482,6 +568,9 @@ export default { return String(recordId) === this.recordingServiceId; }, startPhoneRecord(item) { + // 返回页面后可能被其它页面覆盖录音回调,这里每次录音前重新绑定一次 + this.ensureRecorderManager(); + this.bindRecorderEvents(); if (!this.recorderSupported || !this.recorderManager) { uni.showToast({ title: '当前环境不支持录音,请使用微信小程序或 App', @@ -512,6 +601,7 @@ export default { this.recordingContext = { ...item }; this.recordingServiceId = String(item.id); this.setKeepScreenOn(true); + this.persistRecordingSessionToCache(); this.startNewSegmentRecording(); }, /** 结束录音;onStop 回调中会调用 uploadFileForRecord 上传至后端 */ @@ -523,6 +613,7 @@ export default { return; } this.recordingManualStopRequested = true; + this.persistRecordingSessionToCache(); this.recorderManager.stop(); }, /** @@ -788,12 +879,14 @@ export default { const key = String(recordId); const next = Number(this.uploadingCountMap[key] || 0) + 1; this.uploadingCountMap = { ...this.uploadingCountMap, [key]: next }; + this.persistRecordingSessionToCache(); }, decreaseUploadingCount(recordId) { const key = String(recordId); const current = Number(this.uploadingCountMap[key] || 0); const next = Math.max(0, current - 1); this.uploadingCountMap = { ...this.uploadingCountMap, [key]: next }; + this.persistRecordingSessionToCache(); }, getUploadResultList(recordId) { const key = String(recordId || ''); @@ -803,6 +896,7 @@ export default { setUploadResultList(recordId, list) { const key = String(recordId || ''); this.uploadResultMap = { ...this.uploadResultMap, [key]: Array.isArray(list) ? list : [] }; + this.persistRecordingSessionToCache(); }, pushUploadResult(recordId, segment) { const list = this.getUploadResultList(recordId); diff --git a/unpackage/dist/build/mp-weixin/pages-subpackage/furniture_reception/serviceListFurniture.js b/unpackage/dist/build/mp-weixin/pages-subpackage/furniture_reception/serviceListFurniture.js index 9aaf029..09f1960 100644 --- a/unpackage/dist/build/mp-weixin/pages-subpackage/furniture_reception/serviceListFurniture.js +++ b/unpackage/dist/build/mp-weixin/pages-subpackage/furniture_reception/serviceListFurniture.js @@ -1 +1 @@ -"use strict";const e=require("../../common/vendor.js"),t=require("../../common/config.js"),r=require("../../common/store.js");function i(...e){for(const t of e){if(null==t)continue;const e=String(t).trim();if(e)return e}return""}const s={props:{recordStateLabel:{type:String,default:"服务中"},emptyListHint:{type:String,default:"暂无服务中记录"},showReceptionEntryShortcut:{type:Boolean,default:!1},showRecordStateIndicator:{type:Boolean,default:!0}},data:()=>({serviceStatusLoading:!1,serviceStatusTotal:0,serviceStatusPage:{current:1,size:10},serviceStatusQuery:{salesName:"",customerName:"",salesPhone:""},isAdmin:!1,currentUserPhone:"",serviceStatusList:[],showSupplementModal:!1,currentSupplementItem:null,uploadingIds:[],supplementForm:{customerName:"",contact:"",recordingName:"",remarks:""},recorderSupported:!1,recorderManager:null,recordingServiceId:null,recordingContext:null,recordingElapsedSeconds:0,recordingEstimatedSizeBytes:0,recordingTicker:null,keepScreenOnEnabled:!1,recordingSampleRate:16e3,recordingEncodeBitRate:32e3,recordingSegmentDurationMs:3e5,recordingManualStopRequested:!1,recordingCurrentSegmentNo:0,recordingCurrentSegmentStartAt:0,recordingCurrentSegmentElapsedSeconds:0,uploadingCountMap:{},uploadResultMap:{}}),mounted(){this.checkUserRole(),this.loadCurrentUserPhone(),this.initServiceRecorder(),this.fetchServiceStatusList()},beforeUnmount(){if(this.stopRecordingTicker(),this.setKeepScreenOn(!1),this.recorderManager&&this.recordingServiceId)try{this.recorderManager.stop()}catch(e){}},methods:{initServiceRecorder(){this.recorderSupported="function"==typeof e.index.getRecorderManager,this.recorderSupported&&(this.recorderManager=e.index.getRecorderManager(),this.recorderManager.onStop((e=>{const t=this.recordingContext,r=this.recordingServiceId,i=this.recordingCurrentSegmentNo,s=this.recordingCurrentSegmentElapsedSeconds||this.recordingElapsedSeconds||0,n=!(!r||!t||!t.id||this.recordingManualStopRequested),o=i>0?i:1;this.stopRecordingTicker();const a=e.tempFilePath||"";if(t&&t.id){const r=`service_record_${t.id}_${Date.now()}_part${o}.mp3`;a?this.uploadFileForRecord(t,{path:a,name:r,size:Number(e.fileSize)||0},{silent:!0,segmentNo:o,durationSeconds:s,retryOnceOnFail:!0}):this.pushUploadResult(String(t.id),{id:`seg_${String(t.id)}_${o}_${Date.now()}`,segmentNo:o,durationText:this.formatRecordingElapsed(s),sizeText:"--",status:"failed",statusText:"上传失败",message:"未获取到录音文件(已重试1次)"})}if(n)return this.setKeepScreenOn(!0),void setTimeout((()=>{this.startNewSegmentRecording()}),80);this.recordingServiceId=null,this.recordingContext=null,this.recordingManualStopRequested=!1,this.recordingCurrentSegmentNo=0,this.recordingCurrentSegmentStartAt=0,this.recordingCurrentSegmentElapsedSeconds=0,this.setKeepScreenOn(!1)})),this.recorderManager.onError((()=>{this.recordingServiceId=null,this.recordingContext=null,this.recordingManualStopRequested=!1,this.recordingCurrentSegmentNo=0,this.recordingCurrentSegmentStartAt=0,this.recordingCurrentSegmentElapsedSeconds=0,this.stopRecordingTicker(),this.setKeepScreenOn(!1),e.index.showToast({title:"录音出错",icon:"none"})})))},setKeepScreenOn(t){"function"==typeof e.index.setKeepScreenOn&&e.index.setKeepScreenOn({keepScreenOn:!!t,success:()=>{this.keepScreenOnEnabled=!!t},fail:()=>{this.keepScreenOnEnabled=!1}})},startRecordingTicker(){this.stopRecordingTicker(),this.recordingElapsedSeconds=0,this.recordingEstimatedSizeBytes=0;const e=(Number(this.recordingEncodeBitRate)||32e3)/8;this.recordingTicker=setInterval((()=>{this.recordingElapsedSeconds+=1,this.recordingCurrentSegmentElapsedSeconds=this.recordingElapsedSeconds,this.recordingEstimatedSizeBytes=Math.floor(this.recordingElapsedSeconds*e)}),1e3)},stopRecordingTicker(){this.recordingTicker&&clearInterval(this.recordingTicker),this.recordingTicker=null,this.recordingCurrentSegmentElapsedSeconds=this.recordingElapsedSeconds,this.recordingElapsedSeconds=0,this.recordingEstimatedSizeBytes=0},startNewSegmentRecording(){var t;if(this.recorderManager&&this.recordingServiceId&&(null==(t=this.recordingContext)?void 0:t.id)){this.recordingCurrentSegmentNo+=1,this.recordingCurrentSegmentStartAt=Date.now(),this.recordingCurrentSegmentElapsedSeconds=0;try{this.recorderManager.start({duration:this.recordingSegmentDurationMs,sampleRate:this.recordingSampleRate,numberOfChannels:1,encodeBitRate:this.recordingEncodeBitRate,format:"mp3"}),this.startRecordingTicker()}catch(r){this.recordingServiceId=null,this.recordingContext=null,this.recordingManualStopRequested=!1,this.recordingCurrentSegmentNo=0,this.recordingCurrentSegmentStartAt=0,this.recordingCurrentSegmentElapsedSeconds=0,this.stopRecordingTicker(),this.setKeepScreenOn(!1),e.index.showToast({title:"无法开始录音",icon:"none"})}}},formatRecordingElapsed(e){const t=Math.max(0,Number(e)||0);return`${String(Math.floor(t/60)).padStart(2,"0")}:${String(t%60).padStart(2,"0")}`},formatRecordingSize(e){const t=Math.max(0,Number(e)||0);return t<1024?`${t} B`:t<1048576?`${(t/1024).toFixed(1)} KB`:`${(t/1048576).toFixed(2)} MB`},isRecordingItem(e){return!(!e||!this.recordingServiceId)&&String(e)===this.recordingServiceId},startPhoneRecord(t){this.recorderSupported&&this.recorderManager?t&&t.id?this.recordingServiceId?e.index.showToast({title:"请先停止当前录音",icon:"none"}):this.isUploading(t.id)?e.index.showToast({title:"正在上传,请稍候",icon:"none"}):(this.recordingManualStopRequested=!1,this.recordingCurrentSegmentNo=0,this.recordingCurrentSegmentStartAt=0,this.recordingCurrentSegmentElapsedSeconds=0,this.setUploadResultList(String(t.id),[]),this.recordingContext={...t},this.recordingServiceId=String(t.id),this.setKeepScreenOn(!0),this.startNewSegmentRecording()):e.index.showToast({title:"无法获取服务记录ID",icon:"none"}):e.index.showToast({title:"当前环境不支持录音,请使用微信小程序或 App",icon:"none"})},stopPhoneRecordAndUpload(e){this.recorderManager&&(null==e?void 0:e.id)&&String(e.id)===this.recordingServiceId&&(this.recordingManualStopRequested=!0,this.recorderManager.stop())},checkUserRole(){try{const t=e=>"string"==typeof e?e.split(",").map((e=>e.trim().toLowerCase())).filter(Boolean):[],r=e.index.getStorageSync("backend-role-name")||"",i=(e.index.getStorageSync("backend-login-response")||{}).roleName||"",s=[...t(r),...t(i)];this.isAdmin=s.some((e=>e.includes("admin"))),console.log("用户角色检查:",{storedRole:r,respRole:i,roles:s,isAdmin:this.isAdmin})}catch(t){console.error("检查用户角色失败:",t),this.isAdmin=!1}},loadCurrentUserPhone(){try{const t=e.index.getStorageSync("backend-login-response")||{};t.phone?this.currentUserPhone=t.phone:t.userName?this.currentUserPhone=t.userName:this.currentUserPhone=""}catch(t){console.error("加载当前用户手机号或登录账户失败:",t),this.currentUserPhone=""}},onServiceStatusSearch(){this.serviceStatusPage.current=1,this.fetchServiceStatusList({force:!0})},onServiceStatusRefresh(){this.serviceStatusPage.current=1,this.fetchServiceStatusList({force:!0})},goReceptionEntry(){e.index.navigateTo({url:"/pages-subpackage/furniture_reception/furniture_reception_entry?tab=reception",fail:()=>{e.index.showToast({title:"跳转接待失败",icon:"none"})}})},onServiceStatusReachBottom(){this.serviceStatusLoading||this.serviceStatusList.length>=this.serviceStatusTotal||(this.serviceStatusPage.current+=1,this.fetchServiceStatusList())},async fetchServiceStatusList({force:r=!1}={}){var i,s,n,o,a,c,d;if(!this.serviceStatusLoading||r){this.serviceStatusLoading=!0;try{const u={current:this.serviceStatusPage.current,size:this.serviceStatusPage.size,serviceStatus:"服务中"},h=null==(s=null==(i=this.serviceStatusQuery)?void 0:i.salesName)?void 0:s.trim(),g=null==(o=null==(n=this.serviceStatusQuery)?void 0:n.customerName)?void 0:o.trim();if(h&&(u.salesName=h),g&&(u.customerName=g),this.isAdmin){const e=null==(c=null==(a=this.serviceStatusQuery)?void 0:a.salesPhone)?void 0:c.trim();e&&(u.salesPhone=e)}else this.currentUserPhone&&(u.salesPhone=this.currentUserPhone);u.serviceStatus="服务中";const m=Object.keys(u).filter((e=>null!==u[e]&&void 0!==u[e]&&""!==u[e])).map((e=>`${encodeURIComponent(e)}=${encodeURIComponent(u[e])}`)).join("&");console.log("服务状态查询参数:",JSON.stringify(u)),console.log("查询字符串:",m);const p=t.getApiUrl("/api/audioManagement/list"),S=m?`${p}?${m}`:p;let v="",f="";try{v=e.index.getStorageSync("backend-tenant-id")||"",f=e.index.getStorageSync("backend-token")||""}catch(l){console.error("获取认证信息失败:",l)}const y={"Content-Type":"application/json"};f&&(y.Authorization=`Bearer ${f}`),v&&(y["X-Tenant-Id"]=v);const x=await e.index.request({url:S,method:"POST",data:{},header:y,timeout:3e4});if(200===x.statusCode&&x.data&&x.data.success){const e=Array.isArray(x.data.data)?x.data.data:[];if(0===e.length)return this.serviceStatusList=[],void(this.serviceStatusTotal=0);const t=e.map((e=>this.buildServiceStatusItem(e))).filter((e=>null!==e));1===this.serviceStatusPage.current||r?this.serviceStatusList=[...t]:this.serviceStatusList=[...this.serviceStatusList,...t],this.serviceStatusTotal=Number(x.data.total)||0}else this.serviceStatusList=[],this.serviceStatusTotal=0,e.index.showToast({title:(null==(d=x.data)?void 0:d.message)||"获取服务中列表失败",icon:"none"})}catch(u){console.error("获取服务中列表失败:",u);let t="获取服务状态失败,请稍后重试";u.errMsg&&(u.errMsg.includes("timeout")?t="请求超时,请检查网络连接后重试":u.errMsg.includes("fail")&&(t="网络请求失败,请检查网络连接")),e.index.showToast({title:t,icon:"none",duration:3e3})}finally{this.serviceStatusLoading=!1}}},buildServiceStatusItem(e={}){if(!e||"object"!=typeof e)return null;const t=this.formatDateTime(e.createTime),r=[];e.recordingName&&r.push({text:`录音:${e.recordingName}`,color:"blue"}),e.intentionLevel&&r.push({text:`意向:${e.intentionLevel}`,color:"orange"}),e.projectName&&r.push({text:`项目:${e.projectName}`,color:"blue"});const s=i(e.recordingName)||(i(e.customerName)?`${String(e.customerName).trim()}的接待记录`:"")||"";return{id:e.id||"",staffName:e.salesName||"未分配销售",status:e.syncStatus||"服务中",customerName:e.customerName||"",customerPhone:e.customerPhone||"",customerId:e.customerId||"",recordingName:e.recordingName||"",title:s,remarks:e.remarks||"",tags:r,durationText:t?`开始时间:${t}`:"暂无开始时间"}},formatDateTime(e){if(!e)return"";const t=new Date(e);if(Number.isNaN(t.getTime()))return"";return`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")} ${String(t.getHours()).padStart(2,"0")}:${String(t.getMinutes()).padStart(2,"0")}:${String(t.getSeconds()).padStart(2,"0")}`},viewServiceDetail(e){console.log("查看服务详情",e)},isUploading(e){return!!e&&Number(this.uploadingCountMap[String(e)]||0)>0},increaseUploadingCount(e){const t=String(e),r=Number(this.uploadingCountMap[t]||0)+1;this.uploadingCountMap={...this.uploadingCountMap,[t]:r}},decreaseUploadingCount(e){const t=String(e),r=Number(this.uploadingCountMap[t]||0),i=Math.max(0,r-1);this.uploadingCountMap={...this.uploadingCountMap,[t]:i}},getUploadResultList(e){const t=String(e||""),r=this.uploadResultMap[t];return Array.isArray(r)?r:[]},setUploadResultList(e,t){const r=String(e||"");this.uploadResultMap={...this.uploadResultMap,[r]:Array.isArray(t)?t:[]}},pushUploadResult(e,t){const r=this.getUploadResultList(e);this.setUploadResultList(e,[...r,t])},updateUploadResult(e,t,r={}){const i=this.getUploadResultList(e).map((e=>e.id!==t?e:{...e,...r}));this.setUploadResultList(e,i)},isMp3UploadFile(e){if(!e||!e.path)return!1;const t=e=>{if(!e||"string"!=typeof e)return"";return(e.split("/").pop()||e.split("\\").pop()||e).trim()},r=[t(e.name),t(e.path)].filter(Boolean);for(const i of r)if(i.toLowerCase().endsWith(".mp3"))return!0;return!1},async chooseAndUploadFile(t){if(!t||!t.id)return void e.index.showToast({title:"无法获取服务记录ID",icon:"none"});if(this.isUploading(t.id))return;const r=await this.selectUploadFile();r&&r.path&&await this.uploadFileForRecord(t,r)},selectUploadFile(){return new Promise((t=>{const r=r=>{const i=(e=>{const t=Array.isArray(null==e?void 0:e.tempFiles)?e.tempFiles:[];if(!t.length)return null;const r=t[0]||{},i=r.path||r.tempFilePath||r.url||"",s=r.name||i.split("/").pop()||`service_file_${Date.now()}`;return i?{path:i,name:s}:null})(r);return i?this.isMp3UploadFile(i)?void t(i):(e.index.showToast({title:"仅支持上传 MP3 文件",icon:"none"}),void t(null)):(e.index.showToast({title:"未选择有效文件",icon:"none"}),void t(null))},i=r=>{((null==r?void 0:r.errMsg)||"").includes("cancel")||(console.error("选择文件失败:",r),e.index.showToast({title:"选择文件失败",icon:"none"})),t(null)};"function"!=typeof e.index.chooseMessageFile?"function"!=typeof e.index.chooseFile?e.index.chooseImage({count:1,success:r,fail:i}):e.index.chooseFile({count:1,extension:[".mp3"],success:r,fail:i}):e.index.chooseMessageFile({count:1,type:"file",success:r,fail:i})}))},getAuthHeaders(){let t="",r="";try{t=e.index.getStorageSync("backend-tenant-id")||"",r=e.index.getStorageSync("backend-token")||""}catch(s){console.error("获取认证信息失败:",s)}const i={};return r&&(i.Authorization=`Bearer ${r}`),t&&(i["X-Tenant-Id"]=t),i},async uploadFileForRecord(r,i,s={}){const n=String(r.id),o=Number(s.segmentNo)||1,a=Math.max(0,Number(s.durationSeconds)||0),c=Math.max(0,Number(null==i?void 0:i.size)||0),d=`seg_${n}_${o}_${Date.now()}`;this.pushUploadResult(n,{id:d,segmentNo:o,durationText:this.formatRecordingElapsed(a),sizeText:this.formatRecordingSize(c),status:"uploading",statusText:"上传中",message:""}),this.increaseUploadingCount(n);try{const o=s.retryOnceOnFail?2:1;let a="";for(let s=1;s<=o;s+=1){const c=await e.index.uploadFile({url:t.getApiUrl("/api/audio/upload"),filePath:i.path,name:"file",formData:{id:r.id,audioId:r.id,customerId:r.customerId||"",customerName:r.customerName||"",fileName:i.name||`service_file_${Date.now()}`,compress:!0},header:this.getAuthHeaders(),timeout:6e4});let u={};try{u="string"==typeof(null==c?void 0:c.data)?JSON.parse(c.data):(null==c?void 0:c.data)||{}}catch(l){u=(null==c?void 0:c.data)||{}}if(200===(null==c?void 0:c.statusCode)&&!1!==(null==u?void 0:u.success))return this.updateUploadResult(n,d,{status:"success",statusText:"上传成功",message:s>1?`第${s}次尝试成功`:""}),this.serviceStatusPage.current=1,this.fetchServiceStatusList({force:!0}),!0;a=(null==u?void 0:u.message)||`上传失败(HTTP ${(null==c?void 0:c.statusCode)||"--"})`,s{var s,n;if(i.confirm)try{e.index.showLoading({title:"结束中..."});const i=t.getApiUrl("/api/audioManagement/finishServiceById");let a="",c="";try{a=e.index.getStorageSync("backend-tenant-id")||"",c=e.index.getStorageSync("backend-token")||""}catch(o){console.error("获取认证信息失败:",o)}const d={"Content-Type":"application/json"};c&&(d.Authorization=`Bearer ${c}`),a&&(d["X-Tenant-Id"]=a);const l={id:r.id},u=await e.index.request({url:i,method:"POST",data:l,header:d,timeout:3e4});if(e.index.hideLoading(),200===u.statusCode&&u.data&&u.data.success){const t=((null==(s=u.data)?void 0:s.message)||"结束服务成功").replace(/[A-Za-z]+/g,"").split(/\n/).map((e=>e.trim())).filter(Boolean).join("\n")||"结束服务成功";e.index.showToast({title:t,icon:"success"}),this.serviceStatusPage.current=1,this.fetchServiceStatusList({force:!0})}else e.index.showToast({title:(null==(n=u.data)?void 0:n.message)||"结束服务失败",icon:"none"})}catch(a){e.index.hideLoading(),console.error("结束服务失败:",a);let t="结束服务失败,请重试";a.errMsg&&(a.errMsg.includes("timeout")?t="请求超时,请检查网络连接后重试":a.errMsg.includes("fail")&&(t="网络请求失败,请检查网络连接")),e.index.showToast({title:t,icon:"none",duration:3e3})}}}):e.index.showToast({title:"无法获取服务记录ID",icon:"none"})},showSupplementDialog(e){this.currentSupplementItem=e,this.supplementForm={customerName:e.customerName||"",contact:e.customerPhone||"",recordingName:e.recordingName||"",remarks:e.remarks||""},this.showSupplementModal=!0},closeSupplementDialog(){this.showSupplementModal=!1,this.currentSupplementItem=null,this.supplementForm={customerName:"",contact:"",recordingName:"",remarks:""}},async saveSupplement(){var s,n,o,a,c;const d=null==(s=this.supplementForm.contact)?void 0:s.trim();if(!d||this.isValidPhoneNumber(d))if(this.currentSupplementItem&&this.currentSupplementItem.id)try{e.index.showLoading({title:"保存中..."});let s="",u="";try{s=e.index.getStorageSync("backend-tenant-id")||"",u=e.index.getStorageSync("backend-token")||""}catch(l){console.error("获取认证信息失败:",l)}const h={"Content-Type":"application/json"};u&&(h.Authorization=`Bearer ${u}`),s&&(h["X-Tenant-Id"]=s);let g={};try{g=e.index.getStorageSync("backend-login-response")||{}}catch(l){console.error("读取登录信息失败:",l)}const m=r.store.userInfo||{},p=i(g.phone,g.userName,m.username),S=i(g.realName,g.name,g.nickName,m.nickname,g.userName,m.username),v={id:this.currentSupplementItem.id,customerId:this.currentSupplementItem.customerId||"",customerName:(null==(n=this.supplementForm.customerName)?void 0:n.trim())||"",customerPhone:d||"",recordingName:(null==(o=this.supplementForm.recordingName)?void 0:o.trim())||"",remarks:(null==(a=this.supplementForm.remarks)?void 0:a.trim())||"",salesPhone:p,salesName:S},f=await e.index.request({url:t.getApiUrl("/api/audioManagement/updateForCustomerInfo"),method:"PUT",data:v,header:h,timeout:3e4});e.index.hideLoading(),200===f.statusCode&&f.data&&f.data.success?(e.index.showToast({title:"补录成功",icon:"success"}),this.closeSupplementDialog(),this.serviceStatusPage.current=1,this.fetchServiceStatusList({force:!0})):e.index.showToast({title:(null==(c=f.data)?void 0:c.message)||"补录失败",icon:"none"})}catch(u){e.index.hideLoading(),console.error("补录失败:",u);let t="补录失败,请重试";u.errMsg&&(u.errMsg.includes("timeout")?t="请求超时,请检查网络连接后重试":u.errMsg.includes("fail")&&(t="网络请求失败,请检查网络连接")),e.index.showToast({title:t,icon:"none",duration:3e3})}else e.index.showToast({title:"无法获取服务记录ID",icon:"none"});else e.index.showToast({title:"请输入有效的客户电话",icon:"none"})},isValidPhoneNumber(e){const t=null==e?void 0:e.trim();return!!t&&/^1[3-9]\d{9}$/.test(t)}}};if(!Array){e.resolveComponent("uni-icons")()}Math;const n=e._export_sfc(s,[["render",function(t,r,i,s,n,o){return e.e({a:e.t(n.serviceStatusTotal),b:e.o(((...e)=>o.onServiceStatusSearch&&o.onServiceStatusSearch(...e)),"1e"),c:n.serviceStatusQuery.salesName,d:e.o((e=>n.serviceStatusQuery.salesName=e.detail.value),"5b"),e:e.o(((...e)=>o.onServiceStatusSearch&&o.onServiceStatusSearch(...e)),"4f"),f:n.serviceStatusQuery.customerName,g:e.o((e=>n.serviceStatusQuery.customerName=e.detail.value),"ff"),h:n.isAdmin},n.isAdmin?{i:e.o(((...e)=>o.onServiceStatusSearch&&o.onServiceStatusSearch(...e)),"91"),j:n.serviceStatusQuery.salesPhone,k:e.o((e=>n.serviceStatusQuery.salesPhone=e.detail.value),"86")}:{},{l:i.showReceptionEntryShortcut},i.showReceptionEntryShortcut?{m:e.p({type:"home",size:"18",color:"#2A68FF"}),n:e.o(((...e)=>o.goReceptionEntry&&o.goReceptionEntry(...e)),"5d")}:{},{o:e.p({type:"refresh",size:"18",color:"#2A68FF"}),p:e.o(((...e)=>o.onServiceStatusRefresh&&o.onServiceStatusRefresh(...e)),"84"),q:e.f(n.serviceStatusList,((t,r,i)=>e.e({a:e.t(t.staffName?t.staffName.charAt(0):"未"),b:e.t(t.staffName||"未分配销售"),c:"8e98b19a-2-"+i,d:t.title},t.title?{e:e.t(t.title)}:{},{f:e.t(t.customerName||"未知客户"),g:t.customerPhone},t.customerPhone?{h:e.t(t.customerPhone)}:{},{i:e.f(t.tags,((t,r,i)=>({a:e.t(t.text),b:e.n("tag-"+t.color),c:r}))),j:t.alert},t.alert?e.e({k:e.t(t.alert.title),l:"risk"===t.alert.type},"risk"===t.alert.type?{m:e.t(t.alert.message)}:{n:e.f(t.alert.messages,((t,r,i)=>({a:e.t(t),b:r})))},{o:e.n("risk"===t.alert.type?"alert-risk-text":"alert-reminder-text"),p:e.n("risk"===t.alert.type?"alert-risk-box":"alert-reminder-box")}):{},{q:e.t(t.durationText),r:!o.isRecordingItem(t.id)},o.isRecordingItem(t.id)?{t:e.o((e=>o.stopPhoneRecordAndUpload(t)),t.id||r)}:{s:e.o((e=>o.startPhoneRecord(t)),t.id||r)},{v:e.o((e=>o.showSupplementDialog(t)),t.id||r),w:e.o((e=>o.chooseAndUploadFile(t)),t.id||r),x:e.o((e=>o.finishService(t)),t.id||r),y:o.isRecordingItem(t.id)},o.isRecordingItem(t.id)?{z:e.t(o.formatRecordingElapsed(n.recordingElapsedSeconds)),A:e.t(o.formatRecordingSize(n.recordingEstimatedSizeBytes))}:{},{B:o.getUploadResultList(t.id).length},o.getUploadResultList(t.id).length?{C:e.f(o.getUploadResultList(t.id),((t,r,i)=>e.e({a:e.t(t.segmentNo),b:e.t(t.durationText||"--:--"),c:e.t(t.sizeText||"--"),d:e.t(t.statusText),e:t.message},t.message?{f:e.t(t.message)}:{},{g:t.id})))}:{},{D:t.id||r,E:e.o((e=>o.viewServiceDetail(t)),t.id||r)}))),r:e.p({type:"bars",size:"16",color:"#007AFF"}),s:e.t(i.recordStateLabel),t:!n.serviceStatusLoading&&!n.serviceStatusList.length},n.serviceStatusLoading||n.serviceStatusList.length?{}:{v:e.t(i.emptyListHint)},{w:n.serviceStatusLoading&&n.serviceStatusList.length},(n.serviceStatusLoading&&n.serviceStatusList.length,{}),{x:e.o(((...e)=>o.onServiceStatusReachBottom&&o.onServiceStatusReachBottom(...e)),"d2"),y:n.showSupplementModal},n.showSupplementModal?{z:e.p({type:"close",size:"20",color:"#999"}),A:e.o(((...e)=>o.closeSupplementDialog&&o.closeSupplementDialog(...e)),"8e"),B:n.supplementForm.customerName,C:e.o((e=>n.supplementForm.customerName=e.detail.value),"72"),D:n.supplementForm.contact,E:e.o((e=>n.supplementForm.contact=e.detail.value),"04"),F:n.supplementForm.recordingName,G:e.o((e=>n.supplementForm.recordingName=e.detail.value),"7b"),H:n.supplementForm.remarks,I:e.o((e=>n.supplementForm.remarks=e.detail.value),"36"),J:e.o(((...e)=>o.closeSupplementDialog&&o.closeSupplementDialog(...e)),"c5"),K:e.o(((...e)=>o.saveSupplement&&o.saveSupplement(...e)),"13"),L:e.o((()=>{}),"b8"),M:e.o(((...e)=>o.closeSupplementDialog&&o.closeSupplementDialog(...e)),"7c")}:{})}],["__scopeId","data-v-8e98b19a"]]);wx.createComponent(n); +"use strict";const e=require("../../common/vendor.js"),t=require("../../common/config.js"),r=require("../../common/store.js");function i(...e){for(const t of e){if(null==t)continue;const e=String(t).trim();if(e)return e}return""}const s={recordingServiceId:null,recordingContext:null,recordingElapsedSeconds:0,recordingEstimatedSizeBytes:0,recordingManualStopRequested:!1,recordingCurrentSegmentNo:0,recordingCurrentSegmentStartAt:0,recordingCurrentSegmentElapsedSeconds:0,uploadingCountMap:{},uploadResultMap:{}},n={props:{recordStateLabel:{type:String,default:"服务中"},emptyListHint:{type:String,default:"暂无服务中记录"},showReceptionEntryShortcut:{type:Boolean,default:!1},showRecordStateIndicator:{type:Boolean,default:!0}},data:()=>({serviceStatusLoading:!1,serviceStatusTotal:0,serviceStatusPage:{current:1,size:10},serviceStatusQuery:{salesName:"",customerName:"",salesPhone:""},isAdmin:!1,currentUserPhone:"",serviceStatusList:[],showSupplementModal:!1,currentSupplementItem:null,uploadingIds:[],supplementForm:{customerName:"",contact:"",recordingName:"",remarks:""},recorderSupported:!1,recorderManager:null,recordingServiceId:s.recordingServiceId,recordingContext:s.recordingContext,recordingElapsedSeconds:s.recordingElapsedSeconds,recordingEstimatedSizeBytes:s.recordingEstimatedSizeBytes,recordingTicker:null,keepScreenOnEnabled:!1,recordingSampleRate:16e3,recordingEncodeBitRate:32e3,recordingSegmentDurationMs:3e5,recordingManualStopRequested:s.recordingManualStopRequested,recordingCurrentSegmentNo:s.recordingCurrentSegmentNo,recordingCurrentSegmentStartAt:s.recordingCurrentSegmentStartAt,recordingCurrentSegmentElapsedSeconds:s.recordingCurrentSegmentElapsedSeconds,uploadingCountMap:{...s.uploadingCountMap},uploadResultMap:{...s.uploadResultMap}}),mounted(){var e;this.checkUserRole(),this.loadCurrentUserPhone(),this.initServiceRecorder(),this.restoreRecordingSessionFromCache(),this.recordingServiceId&&(null==(e=this.recordingContext)?void 0:e.id)&&this.startRecordingTicker({reset:!1}),this.fetchServiceStatusList()},beforeUnmount(){this.pauseRecordingTicker(),this.persistRecordingSessionToCache()},methods:{persistRecordingSessionToCache(){s.recordingServiceId=this.recordingServiceId||null,s.recordingContext=this.recordingContext?{...this.recordingContext}:null,s.recordingElapsedSeconds=Number(this.recordingElapsedSeconds)||0,s.recordingEstimatedSizeBytes=Number(this.recordingEstimatedSizeBytes)||0,s.recordingManualStopRequested=!!this.recordingManualStopRequested,s.recordingCurrentSegmentNo=Number(this.recordingCurrentSegmentNo)||0,s.recordingCurrentSegmentStartAt=Number(this.recordingCurrentSegmentStartAt)||0,s.recordingCurrentSegmentElapsedSeconds=Number(this.recordingCurrentSegmentElapsedSeconds)||0,s.uploadingCountMap={...this.uploadingCountMap},s.uploadResultMap={...this.uploadResultMap}},restoreRecordingSessionFromCache(){this.recordingServiceId=s.recordingServiceId||null,this.recordingContext=s.recordingContext?{...s.recordingContext}:null,this.recordingElapsedSeconds=Number(s.recordingElapsedSeconds)||0,this.recordingEstimatedSizeBytes=Number(s.recordingEstimatedSizeBytes)||0,this.recordingManualStopRequested=!!s.recordingManualStopRequested,this.recordingCurrentSegmentNo=Number(s.recordingCurrentSegmentNo)||0,this.recordingCurrentSegmentStartAt=Number(s.recordingCurrentSegmentStartAt)||0,this.recordingCurrentSegmentElapsedSeconds=Number(s.recordingCurrentSegmentElapsedSeconds)||0,this.uploadingCountMap={...s.uploadingCountMap},this.uploadResultMap={...s.uploadResultMap}},initServiceRecorder(){this.recorderSupported="function"==typeof e.index.getRecorderManager,this.recorderSupported&&(this.ensureRecorderManager(),this.bindRecorderEvents())},ensureRecorderManager(){return!!this.recorderSupported&&(this.recorderManager||(this.recorderManager=e.index.getRecorderManager()),!!this.recorderManager)},bindRecorderEvents(){this.ensureRecorderManager()&&("function"==typeof this.recorderManager.offStop&&this.recorderManager.offStop(),"function"==typeof this.recorderManager.offError&&this.recorderManager.offError(),this.recorderManager.onStop((e=>{const t=this.recordingContext,r=this.recordingServiceId,i=this.recordingCurrentSegmentNo,s=this.recordingCurrentSegmentElapsedSeconds||this.recordingElapsedSeconds||0,n=!(!r||!t||!t.id||this.recordingManualStopRequested),o=i>0?i:1;this.stopRecordingTicker();const a=e.tempFilePath||"";if(t&&t.id){const r=`service_record_${t.id}_${Date.now()}_part${o}.mp3`;a?this.uploadFileForRecord(t,{path:a,name:r,size:Number(e.fileSize)||0},{silent:!0,segmentNo:o,durationSeconds:s,retryOnceOnFail:!0}):this.pushUploadResult(String(t.id),{id:`seg_${String(t.id)}_${o}_${Date.now()}`,segmentNo:o,durationText:this.formatRecordingElapsed(s),sizeText:"--",status:"failed",statusText:"上传失败",message:"未获取到录音文件(已重试1次)"})}if(n)return this.setKeepScreenOn(!0),void setTimeout((()=>{this.startNewSegmentRecording()}),80);this.recordingServiceId=null,this.recordingContext=null,this.recordingManualStopRequested=!1,this.recordingCurrentSegmentNo=0,this.recordingCurrentSegmentStartAt=0,this.recordingCurrentSegmentElapsedSeconds=0,this.setKeepScreenOn(!1),this.persistRecordingSessionToCache()})),this.recorderManager.onError((()=>{this.recordingServiceId=null,this.recordingContext=null,this.recordingManualStopRequested=!1,this.recordingCurrentSegmentNo=0,this.recordingCurrentSegmentStartAt=0,this.recordingCurrentSegmentElapsedSeconds=0,this.stopRecordingTicker(),this.setKeepScreenOn(!1),this.persistRecordingSessionToCache(),e.index.showToast({title:"录音出错",icon:"none"})})))},setKeepScreenOn(t){"function"==typeof e.index.setKeepScreenOn&&e.index.setKeepScreenOn({keepScreenOn:!!t,success:()=>{this.keepScreenOnEnabled=!!t},fail:()=>{this.keepScreenOnEnabled=!1}})},startRecordingTicker(e={}){const{reset:t=!0}=e;if(this.pauseRecordingTicker(),t)this.recordingElapsedSeconds=0,this.recordingEstimatedSizeBytes=0;else if(this.recordingCurrentSegmentStartAt){const e=Math.max(0,Math.floor((Date.now()-Number(this.recordingCurrentSegmentStartAt))/1e3));this.recordingElapsedSeconds=e;const t=(Number(this.recordingEncodeBitRate)||32e3)/8;this.recordingEstimatedSizeBytes=Math.floor(e*t)}const r=(Number(this.recordingEncodeBitRate)||32e3)/8;this.recordingTicker=setInterval((()=>{this.recordingCurrentSegmentStartAt?this.recordingElapsedSeconds=Math.max(0,Math.floor((Date.now()-Number(this.recordingCurrentSegmentStartAt))/1e3)):this.recordingElapsedSeconds+=1,this.recordingCurrentSegmentElapsedSeconds=this.recordingElapsedSeconds,this.recordingEstimatedSizeBytes=Math.floor(this.recordingElapsedSeconds*r),this.persistRecordingSessionToCache()}),1e3)},pauseRecordingTicker(){this.recordingTicker&&clearInterval(this.recordingTicker),this.recordingTicker=null},stopRecordingTicker(){this.pauseRecordingTicker(),this.recordingCurrentSegmentElapsedSeconds=this.recordingElapsedSeconds,this.recordingElapsedSeconds=0,this.recordingEstimatedSizeBytes=0,this.persistRecordingSessionToCache()},startNewSegmentRecording(){var t;if(this.recorderManager&&this.recordingServiceId&&(null==(t=this.recordingContext)?void 0:t.id)){this.recordingCurrentSegmentNo+=1,this.recordingCurrentSegmentStartAt=Date.now(),this.recordingCurrentSegmentElapsedSeconds=0;try{this.recorderManager.start({duration:this.recordingSegmentDurationMs,sampleRate:this.recordingSampleRate,numberOfChannels:1,encodeBitRate:this.recordingEncodeBitRate,format:"mp3"}),this.startRecordingTicker(),this.persistRecordingSessionToCache()}catch(r){this.recordingServiceId=null,this.recordingContext=null,this.recordingManualStopRequested=!1,this.recordingCurrentSegmentNo=0,this.recordingCurrentSegmentStartAt=0,this.recordingCurrentSegmentElapsedSeconds=0,this.stopRecordingTicker(),this.setKeepScreenOn(!1),this.persistRecordingSessionToCache(),e.index.showToast({title:"无法开始录音",icon:"none"})}}},formatRecordingElapsed(e){const t=Math.max(0,Number(e)||0);return`${String(Math.floor(t/60)).padStart(2,"0")}:${String(t%60).padStart(2,"0")}`},formatRecordingSize(e){const t=Math.max(0,Number(e)||0);return t<1024?`${t} B`:t<1048576?`${(t/1024).toFixed(1)} KB`:`${(t/1048576).toFixed(2)} MB`},isRecordingItem(e){return!(!e||!this.recordingServiceId)&&String(e)===this.recordingServiceId},startPhoneRecord(t){this.ensureRecorderManager(),this.bindRecorderEvents(),this.recorderSupported&&this.recorderManager?t&&t.id?this.recordingServiceId?e.index.showToast({title:"请先停止当前录音",icon:"none"}):this.isUploading(t.id)?e.index.showToast({title:"正在上传,请稍候",icon:"none"}):(this.recordingManualStopRequested=!1,this.recordingCurrentSegmentNo=0,this.recordingCurrentSegmentStartAt=0,this.recordingCurrentSegmentElapsedSeconds=0,this.setUploadResultList(String(t.id),[]),this.recordingContext={...t},this.recordingServiceId=String(t.id),this.setKeepScreenOn(!0),this.persistRecordingSessionToCache(),this.startNewSegmentRecording()):e.index.showToast({title:"无法获取服务记录ID",icon:"none"}):e.index.showToast({title:"当前环境不支持录音,请使用微信小程序或 App",icon:"none"})},stopPhoneRecordAndUpload(e){this.recorderManager&&(null==e?void 0:e.id)&&String(e.id)===this.recordingServiceId&&(this.recordingManualStopRequested=!0,this.persistRecordingSessionToCache(),this.recorderManager.stop())},checkUserRole(){try{const t=e=>"string"==typeof e?e.split(",").map((e=>e.trim().toLowerCase())).filter(Boolean):[],r=e.index.getStorageSync("backend-role-name")||"",i=(e.index.getStorageSync("backend-login-response")||{}).roleName||"",s=[...t(r),...t(i)];this.isAdmin=s.some((e=>e.includes("admin"))),console.log("用户角色检查:",{storedRole:r,respRole:i,roles:s,isAdmin:this.isAdmin})}catch(t){console.error("检查用户角色失败:",t),this.isAdmin=!1}},loadCurrentUserPhone(){try{const t=e.index.getStorageSync("backend-login-response")||{};t.phone?this.currentUserPhone=t.phone:t.userName?this.currentUserPhone=t.userName:this.currentUserPhone=""}catch(t){console.error("加载当前用户手机号或登录账户失败:",t),this.currentUserPhone=""}},onServiceStatusSearch(){this.serviceStatusPage.current=1,this.fetchServiceStatusList({force:!0})},onServiceStatusRefresh(){this.serviceStatusPage.current=1,this.fetchServiceStatusList({force:!0})},goReceptionEntry(){e.index.navigateTo({url:"/pages-subpackage/furniture_reception/furniture_reception_entry?tab=reception",fail:()=>{e.index.showToast({title:"跳转接待失败",icon:"none"})}})},onServiceStatusReachBottom(){this.serviceStatusLoading||this.serviceStatusList.length>=this.serviceStatusTotal||(this.serviceStatusPage.current+=1,this.fetchServiceStatusList())},async fetchServiceStatusList({force:r=!1}={}){var i,s,n,o,a,c,d;if(!this.serviceStatusLoading||r){this.serviceStatusLoading=!0;try{const l={current:this.serviceStatusPage.current,size:this.serviceStatusPage.size,serviceStatus:"服务中"},g=null==(s=null==(i=this.serviceStatusQuery)?void 0:i.salesName)?void 0:s.trim(),h=null==(o=null==(n=this.serviceStatusQuery)?void 0:n.customerName)?void 0:o.trim();if(g&&(l.salesName=g),h&&(l.customerName=h),this.isAdmin){const e=null==(c=null==(a=this.serviceStatusQuery)?void 0:a.salesPhone)?void 0:c.trim();e&&(l.salesPhone=e)}else this.currentUserPhone&&(l.salesPhone=this.currentUserPhone);l.serviceStatus="服务中";const p=Object.keys(l).filter((e=>null!==l[e]&&void 0!==l[e]&&""!==l[e])).map((e=>`${encodeURIComponent(e)}=${encodeURIComponent(l[e])}`)).join("&");console.log("服务状态查询参数:",JSON.stringify(l)),console.log("查询字符串:",p);const m=t.getApiUrl("/api/audioManagement/list"),S=p?`${m}?${p}`:m;let v="",f="";try{v=e.index.getStorageSync("backend-tenant-id")||"",f=e.index.getStorageSync("backend-token")||""}catch(u){console.error("获取认证信息失败:",u)}const R={"Content-Type":"application/json"};f&&(R.Authorization=`Bearer ${f}`),v&&(R["X-Tenant-Id"]=v);const C=await e.index.request({url:S,method:"POST",data:{},header:R,timeout:3e4});if(200===C.statusCode&&C.data&&C.data.success){const e=Array.isArray(C.data.data)?C.data.data:[];if(0===e.length)return this.serviceStatusList=[],void(this.serviceStatusTotal=0);const t=e.map((e=>this.buildServiceStatusItem(e))).filter((e=>null!==e));1===this.serviceStatusPage.current||r?this.serviceStatusList=[...t]:this.serviceStatusList=[...this.serviceStatusList,...t],this.serviceStatusTotal=Number(C.data.total)||0}else this.serviceStatusList=[],this.serviceStatusTotal=0,e.index.showToast({title:(null==(d=C.data)?void 0:d.message)||"获取服务中列表失败",icon:"none"})}catch(l){console.error("获取服务中列表失败:",l);let t="获取服务状态失败,请稍后重试";l.errMsg&&(l.errMsg.includes("timeout")?t="请求超时,请检查网络连接后重试":l.errMsg.includes("fail")&&(t="网络请求失败,请检查网络连接")),e.index.showToast({title:t,icon:"none",duration:3e3})}finally{this.serviceStatusLoading=!1}}},buildServiceStatusItem(e={}){if(!e||"object"!=typeof e)return null;const t=this.formatDateTime(e.createTime),r=[];e.recordingName&&r.push({text:`录音:${e.recordingName}`,color:"blue"}),e.intentionLevel&&r.push({text:`意向:${e.intentionLevel}`,color:"orange"}),e.projectName&&r.push({text:`项目:${e.projectName}`,color:"blue"});const s=i(e.recordingName)||(i(e.customerName)?`${String(e.customerName).trim()}的接待记录`:"")||"";return{id:e.id||"",staffName:e.salesName||"未分配销售",status:e.syncStatus||"服务中",customerName:e.customerName||"",customerPhone:e.customerPhone||"",customerId:e.customerId||"",recordingName:e.recordingName||"",title:s,remarks:e.remarks||"",tags:r,durationText:t?`开始时间:${t}`:"暂无开始时间"}},formatDateTime(e){if(!e)return"";const t=new Date(e);if(Number.isNaN(t.getTime()))return"";return`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")} ${String(t.getHours()).padStart(2,"0")}:${String(t.getMinutes()).padStart(2,"0")}:${String(t.getSeconds()).padStart(2,"0")}`},viewServiceDetail(e){console.log("查看服务详情",e)},isUploading(e){return!!e&&Number(this.uploadingCountMap[String(e)]||0)>0},increaseUploadingCount(e){const t=String(e),r=Number(this.uploadingCountMap[t]||0)+1;this.uploadingCountMap={...this.uploadingCountMap,[t]:r},this.persistRecordingSessionToCache()},decreaseUploadingCount(e){const t=String(e),r=Number(this.uploadingCountMap[t]||0),i=Math.max(0,r-1);this.uploadingCountMap={...this.uploadingCountMap,[t]:i},this.persistRecordingSessionToCache()},getUploadResultList(e){const t=String(e||""),r=this.uploadResultMap[t];return Array.isArray(r)?r:[]},setUploadResultList(e,t){const r=String(e||"");this.uploadResultMap={...this.uploadResultMap,[r]:Array.isArray(t)?t:[]},this.persistRecordingSessionToCache()},pushUploadResult(e,t){const r=this.getUploadResultList(e);this.setUploadResultList(e,[...r,t])},updateUploadResult(e,t,r={}){const i=this.getUploadResultList(e).map((e=>e.id!==t?e:{...e,...r}));this.setUploadResultList(e,i)},isMp3UploadFile(e){if(!e||!e.path)return!1;const t=e=>{if(!e||"string"!=typeof e)return"";return(e.split("/").pop()||e.split("\\").pop()||e).trim()},r=[t(e.name),t(e.path)].filter(Boolean);for(const i of r)if(i.toLowerCase().endsWith(".mp3"))return!0;return!1},async chooseAndUploadFile(t){if(!t||!t.id)return void e.index.showToast({title:"无法获取服务记录ID",icon:"none"});if(this.isUploading(t.id))return;const r=await this.selectUploadFile();r&&r.path&&await this.uploadFileForRecord(t,r)},selectUploadFile(){return new Promise((t=>{const r=r=>{const i=(e=>{const t=Array.isArray(null==e?void 0:e.tempFiles)?e.tempFiles:[];if(!t.length)return null;const r=t[0]||{},i=r.path||r.tempFilePath||r.url||"",s=r.name||i.split("/").pop()||`service_file_${Date.now()}`;return i?{path:i,name:s}:null})(r);return i?this.isMp3UploadFile(i)?void t(i):(e.index.showToast({title:"仅支持上传 MP3 文件",icon:"none"}),void t(null)):(e.index.showToast({title:"未选择有效文件",icon:"none"}),void t(null))},i=r=>{((null==r?void 0:r.errMsg)||"").includes("cancel")||(console.error("选择文件失败:",r),e.index.showToast({title:"选择文件失败",icon:"none"})),t(null)};"function"!=typeof e.index.chooseMessageFile?"function"!=typeof e.index.chooseFile?e.index.chooseImage({count:1,success:r,fail:i}):e.index.chooseFile({count:1,extension:[".mp3"],success:r,fail:i}):e.index.chooseMessageFile({count:1,type:"file",success:r,fail:i})}))},getAuthHeaders(){let t="",r="";try{t=e.index.getStorageSync("backend-tenant-id")||"",r=e.index.getStorageSync("backend-token")||""}catch(s){console.error("获取认证信息失败:",s)}const i={};return r&&(i.Authorization=`Bearer ${r}`),t&&(i["X-Tenant-Id"]=t),i},async uploadFileForRecord(r,i,s={}){const n=String(r.id),o=Number(s.segmentNo)||1,a=Math.max(0,Number(s.durationSeconds)||0),c=Math.max(0,Number(null==i?void 0:i.size)||0),d=`seg_${n}_${o}_${Date.now()}`;this.pushUploadResult(n,{id:d,segmentNo:o,durationText:this.formatRecordingElapsed(a),sizeText:this.formatRecordingSize(c),status:"uploading",statusText:"上传中",message:""}),this.increaseUploadingCount(n);try{const o=s.retryOnceOnFail?2:1;let a="";for(let s=1;s<=o;s+=1){const c=await e.index.uploadFile({url:t.getApiUrl("/api/audio/upload"),filePath:i.path,name:"file",formData:{id:r.id,audioId:r.id,customerId:r.customerId||"",customerName:r.customerName||"",fileName:i.name||`service_file_${Date.now()}`,compress:!0},header:this.getAuthHeaders(),timeout:6e4});let l={};try{l="string"==typeof(null==c?void 0:c.data)?JSON.parse(c.data):(null==c?void 0:c.data)||{}}catch(u){l=(null==c?void 0:c.data)||{}}if(200===(null==c?void 0:c.statusCode)&&!1!==(null==l?void 0:l.success))return this.updateUploadResult(n,d,{status:"success",statusText:"上传成功",message:s>1?`第${s}次尝试成功`:""}),this.serviceStatusPage.current=1,this.fetchServiceStatusList({force:!0}),!0;a=(null==l?void 0:l.message)||`上传失败(HTTP ${(null==c?void 0:c.statusCode)||"--"})`,s{var s,n;if(i.confirm)try{e.index.showLoading({title:"结束中..."});const i=t.getApiUrl("/api/audioManagement/finishServiceById");let a="",c="";try{a=e.index.getStorageSync("backend-tenant-id")||"",c=e.index.getStorageSync("backend-token")||""}catch(o){console.error("获取认证信息失败:",o)}const d={"Content-Type":"application/json"};c&&(d.Authorization=`Bearer ${c}`),a&&(d["X-Tenant-Id"]=a);const u={id:r.id},l=await e.index.request({url:i,method:"POST",data:u,header:d,timeout:3e4});if(e.index.hideLoading(),200===l.statusCode&&l.data&&l.data.success){const t=((null==(s=l.data)?void 0:s.message)||"结束服务成功").replace(/[A-Za-z]+/g,"").split(/\n/).map((e=>e.trim())).filter(Boolean).join("\n")||"结束服务成功";e.index.showToast({title:t,icon:"success"}),this.serviceStatusPage.current=1,this.fetchServiceStatusList({force:!0})}else e.index.showToast({title:(null==(n=l.data)?void 0:n.message)||"结束服务失败",icon:"none"})}catch(a){e.index.hideLoading(),console.error("结束服务失败:",a);let t="结束服务失败,请重试";a.errMsg&&(a.errMsg.includes("timeout")?t="请求超时,请检查网络连接后重试":a.errMsg.includes("fail")&&(t="网络请求失败,请检查网络连接")),e.index.showToast({title:t,icon:"none",duration:3e3})}}}):e.index.showToast({title:"无法获取服务记录ID",icon:"none"})},showSupplementDialog(e){this.currentSupplementItem=e,this.supplementForm={customerName:e.customerName||"",contact:e.customerPhone||"",recordingName:e.recordingName||"",remarks:e.remarks||""},this.showSupplementModal=!0},closeSupplementDialog(){this.showSupplementModal=!1,this.currentSupplementItem=null,this.supplementForm={customerName:"",contact:"",recordingName:"",remarks:""}},async saveSupplement(){var s,n,o,a,c;const d=null==(s=this.supplementForm.contact)?void 0:s.trim();if(!d||this.isValidPhoneNumber(d))if(this.currentSupplementItem&&this.currentSupplementItem.id)try{e.index.showLoading({title:"保存中..."});let s="",l="";try{s=e.index.getStorageSync("backend-tenant-id")||"",l=e.index.getStorageSync("backend-token")||""}catch(u){console.error("获取认证信息失败:",u)}const g={"Content-Type":"application/json"};l&&(g.Authorization=`Bearer ${l}`),s&&(g["X-Tenant-Id"]=s);let h={};try{h=e.index.getStorageSync("backend-login-response")||{}}catch(u){console.error("读取登录信息失败:",u)}const p=r.store.userInfo||{},m=i(h.phone,h.userName,p.username),S=i(h.realName,h.name,h.nickName,p.nickname,h.userName,p.username),v={id:this.currentSupplementItem.id,customerId:this.currentSupplementItem.customerId||"",customerName:(null==(n=this.supplementForm.customerName)?void 0:n.trim())||"",customerPhone:d||"",recordingName:(null==(o=this.supplementForm.recordingName)?void 0:o.trim())||"",remarks:(null==(a=this.supplementForm.remarks)?void 0:a.trim())||"",salesPhone:m,salesName:S},f=await e.index.request({url:t.getApiUrl("/api/audioManagement/updateForCustomerInfo"),method:"PUT",data:v,header:g,timeout:3e4});e.index.hideLoading(),200===f.statusCode&&f.data&&f.data.success?(e.index.showToast({title:"补录成功",icon:"success"}),this.closeSupplementDialog(),this.serviceStatusPage.current=1,this.fetchServiceStatusList({force:!0})):e.index.showToast({title:(null==(c=f.data)?void 0:c.message)||"补录失败",icon:"none"})}catch(l){e.index.hideLoading(),console.error("补录失败:",l);let t="补录失败,请重试";l.errMsg&&(l.errMsg.includes("timeout")?t="请求超时,请检查网络连接后重试":l.errMsg.includes("fail")&&(t="网络请求失败,请检查网络连接")),e.index.showToast({title:t,icon:"none",duration:3e3})}else e.index.showToast({title:"无法获取服务记录ID",icon:"none"});else e.index.showToast({title:"请输入有效的客户电话",icon:"none"})},isValidPhoneNumber(e){const t=null==e?void 0:e.trim();return!!t&&/^1[3-9]\d{9}$/.test(t)}}};if(!Array){e.resolveComponent("uni-icons")()}Math;const o=e._export_sfc(n,[["render",function(t,r,i,s,n,o){return e.e({a:e.t(n.serviceStatusTotal),b:e.o(((...e)=>o.onServiceStatusSearch&&o.onServiceStatusSearch(...e)),"1e"),c:n.serviceStatusQuery.salesName,d:e.o((e=>n.serviceStatusQuery.salesName=e.detail.value),"5b"),e:e.o(((...e)=>o.onServiceStatusSearch&&o.onServiceStatusSearch(...e)),"4f"),f:n.serviceStatusQuery.customerName,g:e.o((e=>n.serviceStatusQuery.customerName=e.detail.value),"ff"),h:n.isAdmin},n.isAdmin?{i:e.o(((...e)=>o.onServiceStatusSearch&&o.onServiceStatusSearch(...e)),"91"),j:n.serviceStatusQuery.salesPhone,k:e.o((e=>n.serviceStatusQuery.salesPhone=e.detail.value),"86")}:{},{l:i.showReceptionEntryShortcut},i.showReceptionEntryShortcut?{m:e.p({type:"home",size:"18",color:"#2A68FF"}),n:e.o(((...e)=>o.goReceptionEntry&&o.goReceptionEntry(...e)),"5d")}:{},{o:e.p({type:"refresh",size:"18",color:"#2A68FF"}),p:e.o(((...e)=>o.onServiceStatusRefresh&&o.onServiceStatusRefresh(...e)),"84"),q:e.f(n.serviceStatusList,((t,r,i)=>e.e({a:e.t(t.staffName?t.staffName.charAt(0):"未"),b:e.t(t.staffName||"未分配销售"),c:"ba2ce898-2-"+i,d:t.title},t.title?{e:e.t(t.title)}:{},{f:e.t(t.customerName||"未知客户"),g:t.customerPhone},t.customerPhone?{h:e.t(t.customerPhone)}:{},{i:e.f(t.tags,((t,r,i)=>({a:e.t(t.text),b:e.n("tag-"+t.color),c:r}))),j:t.alert},t.alert?e.e({k:e.t(t.alert.title),l:"risk"===t.alert.type},"risk"===t.alert.type?{m:e.t(t.alert.message)}:{n:e.f(t.alert.messages,((t,r,i)=>({a:e.t(t),b:r})))},{o:e.n("risk"===t.alert.type?"alert-risk-text":"alert-reminder-text"),p:e.n("risk"===t.alert.type?"alert-risk-box":"alert-reminder-box")}):{},{q:e.t(t.durationText),r:!o.isRecordingItem(t.id)},o.isRecordingItem(t.id)?{t:e.o((e=>o.stopPhoneRecordAndUpload(t)),t.id||r)}:{s:e.o((e=>o.startPhoneRecord(t)),t.id||r)},{v:e.o((e=>o.showSupplementDialog(t)),t.id||r),w:e.o((e=>o.chooseAndUploadFile(t)),t.id||r),x:e.o((e=>o.finishService(t)),t.id||r),y:o.isRecordingItem(t.id)},o.isRecordingItem(t.id)?{z:e.t(o.formatRecordingElapsed(n.recordingElapsedSeconds)),A:e.t(o.formatRecordingSize(n.recordingEstimatedSizeBytes))}:{},{B:o.getUploadResultList(t.id).length},o.getUploadResultList(t.id).length?{C:e.f(o.getUploadResultList(t.id),((t,r,i)=>e.e({a:e.t(t.segmentNo),b:e.t(t.durationText||"--:--"),c:e.t(t.sizeText||"--"),d:e.t(t.statusText),e:t.message},t.message?{f:e.t(t.message)}:{},{g:t.id})))}:{},{D:t.id||r,E:e.o((e=>o.viewServiceDetail(t)),t.id||r)}))),r:e.p({type:"bars",size:"16",color:"#007AFF"}),s:e.t(i.recordStateLabel),t:!n.serviceStatusLoading&&!n.serviceStatusList.length},n.serviceStatusLoading||n.serviceStatusList.length?{}:{v:e.t(i.emptyListHint)},{w:n.serviceStatusLoading&&n.serviceStatusList.length},(n.serviceStatusLoading&&n.serviceStatusList.length,{}),{x:e.o(((...e)=>o.onServiceStatusReachBottom&&o.onServiceStatusReachBottom(...e)),"d2"),y:n.showSupplementModal},n.showSupplementModal?{z:e.p({type:"close",size:"20",color:"#999"}),A:e.o(((...e)=>o.closeSupplementDialog&&o.closeSupplementDialog(...e)),"8e"),B:n.supplementForm.customerName,C:e.o((e=>n.supplementForm.customerName=e.detail.value),"72"),D:n.supplementForm.contact,E:e.o((e=>n.supplementForm.contact=e.detail.value),"04"),F:n.supplementForm.recordingName,G:e.o((e=>n.supplementForm.recordingName=e.detail.value),"7b"),H:n.supplementForm.remarks,I:e.o((e=>n.supplementForm.remarks=e.detail.value),"36"),J:e.o(((...e)=>o.closeSupplementDialog&&o.closeSupplementDialog(...e)),"c5"),K:e.o(((...e)=>o.saveSupplement&&o.saveSupplement(...e)),"13"),L:e.o((()=>{}),"b8"),M:e.o(((...e)=>o.closeSupplementDialog&&o.closeSupplementDialog(...e)),"7c")}:{})}],["__scopeId","data-v-ba2ce898"]]);wx.createComponent(o); diff --git a/unpackage/dist/build/mp-weixin/pages-subpackage/furniture_reception/serviceListFurniture.wxml b/unpackage/dist/build/mp-weixin/pages-subpackage/furniture_reception/serviceListFurniture.wxml index a44db48..44fd124 100644 --- a/unpackage/dist/build/mp-weixin/pages-subpackage/furniture_reception/serviceListFurniture.wxml +++ b/unpackage/dist/build/mp-weixin/pages-subpackage/furniture_reception/serviceListFurniture.wxml @@ -1 +1 @@ -共{{a}}条接待刷新{{item.a}}{{item.b}}{{s}}{{item.e}}客户:{{item.f}}电话:{{item.h}}{{tag.a}}{{item.k}}{{item.m}}{{msg.a}}{{item.q}}录音停止录音补录客户上传录音结束服务已录音:{{item.z}}当前大小:{{item.A}} 第{{segment.a}}段({{segment.b}} / {{segment.c}}):{{segment.d}}{{segment.f}}{{v}}正在加载更多...补录信息客户姓名客户电话录音名客户详细地址