提交100J代码
This commit is contained in:
@ -525,7 +525,11 @@
|
||||
},
|
||||
Apply(item, index) {
|
||||
this.updateProgress = 0;
|
||||
this.isUpdating = true;
|
||||
if (this.upgradeTimer) {
|
||||
clearTimeout(this.upgradeTimer);
|
||||
this.upgradeTimer = null;
|
||||
}
|
||||
// 本地项在无网时禁止下发,仅弹窗(isUpdating 在确认可执行后再置 true)
|
||||
// 本地项优先用 localPath;云端项用 fileUrl(兼容多种字段名),相对路径补全 baseURL
|
||||
let fileUrl = '';
|
||||
let localPath = (item.localPath && typeof item.localPath === 'string') ? item.localPath : '';
|
||||
@ -548,67 +552,99 @@
|
||||
// 不传「蓝牙连接中」类提示:关蓝牙走 4G 时易误导;进度条 + 必要时全局请稍候即可
|
||||
onWaiting: () => {}
|
||||
};
|
||||
// 整体超时 60 秒(仅影响蓝牙上传,4G HTTP 很快返回)
|
||||
const overallTimer = setTimeout(() => {
|
||||
if (this.isUpdating) {
|
||||
uni.showToast({ title: '操作超时', icon: 'none', duration: 2000 });
|
||||
const runDeviceUpdate = () => {
|
||||
const overallTimer = setTimeout(() => {
|
||||
if (this.isUpdating) {
|
||||
uni.showToast({ title: '操作超时', icon: 'none', duration: 2000 });
|
||||
this.isUpdating = false;
|
||||
this.updateProgress = 0;
|
||||
}
|
||||
}, 120000);
|
||||
// 进入列表时的蓝牙快照可能过期;与 HBY100 详情页一致,从 BleHelper 按 MAC 再对齐一次
|
||||
sync100JBleProtocolFromHelper(this.device).then(() => deviceUpdateVoice(data)).then((RES) => {
|
||||
clearTimeout(overallTimer);
|
||||
if (RES.code == 200) {
|
||||
// 蓝牙上传:进度已由 onProgress 更新,直接完成
|
||||
if (RES._channel === 'ble') {
|
||||
if (this.upgradeTimer) {
|
||||
clearTimeout(this.upgradeTimer);
|
||||
this.upgradeTimer = null;
|
||||
}
|
||||
const title = RES._updateVoiceAfterBleFailed
|
||||
? '蓝牙已下发,云端同步失败可稍后重试'
|
||||
: '音频上传成功';
|
||||
this.syncVoiceListUseStatus(item);
|
||||
uni.showToast({ title, icon: RES._updateVoiceAfterBleFailed ? 'none' : 'success', duration: 2000 });
|
||||
this.isUpdating = false;
|
||||
setTimeout(() => { uni.navigateBack(); }, 1500);
|
||||
return;
|
||||
}
|
||||
// 4G:订阅 MQTT 获取设备端进度,6 秒超时
|
||||
this.upgradeTimer = setTimeout(() => {
|
||||
if (this.isUpdating) {
|
||||
uni.showToast({ title: '音频进度同步超时', icon: 'none', duration: 2000 });
|
||||
this.isUpdating = false;
|
||||
this.updateProgress = 0;
|
||||
}
|
||||
}, 6000);
|
||||
this.mqttClient = this.mqttClient || new MqttClient();
|
||||
this.mqttClient.connect(() => {
|
||||
const statusTopic = `status/894078/HBY100/${this.device.deviceImei}`;
|
||||
this.mqttClient.subscribe(statusTopic, (payload) => {
|
||||
try {
|
||||
const payloadObj = typeof payload === 'string' ? JSON.parse(payload) : payload;
|
||||
const progress = payloadObj.data?.progress;
|
||||
if (progress !== undefined && !isNaN(progress) && progress >= 0 && progress <= 100) {
|
||||
this.updateProgress = progress;
|
||||
if (progress === 100) {
|
||||
clearTimeout(this.upgradeTimer);
|
||||
this.syncVoiceListUseStatus(item);
|
||||
uni.showToast({ title: '音频上传成功', icon: 'success', duration: 2000 });
|
||||
this.isUpdating = false;
|
||||
setTimeout(() => { uni.navigateBack(); }, 1500);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
clearTimeout(this.upgradeTimer);
|
||||
console.error('解析MQTT payload失败:', e);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.isUpdating = false;
|
||||
uni.showToast({ title: RES.msg || '操作失败', icon: 'none', duration: 1000 });
|
||||
}
|
||||
}).catch((err) => {
|
||||
clearTimeout(overallTimer);
|
||||
this.isUpdating = false;
|
||||
this.updateProgress = 0;
|
||||
}
|
||||
}, 120000); // 蓝牙分片+MTU 协商+大包写入较慢,60s 易误报「操作超时」
|
||||
// 进入列表时的蓝牙快照可能过期;与 HBY100 详情页一致,从 BleHelper 按 MAC 再对齐一次,否则常静默走 4G、看不到 [100J-蓝牙] 分片日志
|
||||
sync100JBleProtocolFromHelper(this.device).then(() => deviceUpdateVoice(data)).then((RES) => {
|
||||
clearTimeout(overallTimer);
|
||||
if (RES.code == 200) {
|
||||
// 蓝牙上传:进度已由 onProgress 更新,直接完成
|
||||
if (RES._channel === 'ble') {
|
||||
this.syncVoiceListUseStatus(item);
|
||||
uni.showToast({ title: '音频上传成功', icon: 'success', duration: 2000 });
|
||||
this.isUpdating = false;
|
||||
setTimeout(() => { uni.navigateBack(); }, 1500);
|
||||
return;
|
||||
}
|
||||
// 4G:订阅 MQTT 获取设备端进度,6 秒超时
|
||||
this.upgradeTimer = setTimeout(() => {
|
||||
if (this.isUpdating) {
|
||||
uni.showToast({ title: '音频进度同步超时', icon: 'none', duration: 2000 });
|
||||
this.isUpdating = false;
|
||||
this.updateProgress = 0;
|
||||
uni.showToast({ title: err.message || '操作失败', icon: 'none', duration: 2500 });
|
||||
});
|
||||
};
|
||||
if (item._isLocal) {
|
||||
uni.getNetworkType({
|
||||
success: (net) => {
|
||||
if (net.networkType === 'none') {
|
||||
uni.showModal({
|
||||
title: '无法使用',
|
||||
content: '无网保存的本地语音无法通过蓝牙下发。请先连接 WiFi 或移动网络后,重新录制并保存(上传云端),再点「使用」。',
|
||||
showCancel: false,
|
||||
confirmText: '知道了'
|
||||
});
|
||||
return;
|
||||
}
|
||||
}, 6000);
|
||||
this.mqttClient = this.mqttClient || new MqttClient();
|
||||
this.mqttClient.connect(() => {
|
||||
const statusTopic = `status/894078/HBY100/${this.device.deviceImei}`;
|
||||
this.mqttClient.subscribe(statusTopic, (payload) => {
|
||||
try {
|
||||
const payloadObj = typeof payload === 'string' ? JSON.parse(payload) : payload;
|
||||
const progress = payloadObj.data?.progress;
|
||||
if (progress !== undefined && !isNaN(progress) && progress >= 0 && progress <= 100) {
|
||||
this.updateProgress = progress;
|
||||
if (progress === 100) {
|
||||
clearTimeout(this.upgradeTimer);
|
||||
this.syncVoiceListUseStatus(item);
|
||||
uni.showToast({ title: '音频上传成功', icon: 'success', duration: 2000 });
|
||||
this.isUpdating = false;
|
||||
setTimeout(() => { uni.navigateBack(); }, 1500);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
clearTimeout(this.upgradeTimer);
|
||||
console.error('解析MQTT payload失败:', e);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.isUpdating = false;
|
||||
uni.showToast({ title: RES.msg || '操作失败', icon: 'none', duration: 1000 });
|
||||
}
|
||||
}).catch((err) => {
|
||||
clearTimeout(overallTimer);
|
||||
this.isUpdating = false;
|
||||
this.updateProgress = 0;
|
||||
uni.showToast({ title: err.message || '操作失败', icon: 'none', duration: 2500 });
|
||||
});
|
||||
this.isUpdating = true;
|
||||
runDeviceUpdate();
|
||||
},
|
||||
fail: () => {
|
||||
this.isUpdating = true;
|
||||
runDeviceUpdate();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.isUpdating = true;
|
||||
runDeviceUpdate();
|
||||
},
|
||||
closePop: function() {
|
||||
this.Status.Pop.showPop = false;
|
||||
|
||||
@ -422,117 +422,6 @@
|
||||
hideLoading(these);
|
||||
}, 1200);
|
||||
},
|
||||
// 无网络时保存到本地,供蓝牙直接发送(不依赖 OSS)
|
||||
// 当前部分机型 PUBLIC_DOWNLOADS 在读取阶段会出现 requestFileSystem/resolve 长时间无回调,
|
||||
// 因此本地语音优先落到 _doc/100J_audio,后续蓝牙下发走 PRIVATE_DOC 分支更稳定。
|
||||
saveLocalForBle(filePath) {
|
||||
const deviceId = these.Status.ID;
|
||||
if (!deviceId) {
|
||||
uni.showToast({ title: '缺少设备信息,请从语音列表进入录音页', icon: 'none', duration: 2500 });
|
||||
return;
|
||||
}
|
||||
const warmCacheNow = (srcPath) => {
|
||||
if (!srcPath) return;
|
||||
// 像 HBY100 一样优先写 uni 存储:后续「使用」先读缓存,尽量不再依赖当场读文件
|
||||
cache100JVoiceFileForBle(deviceId, 'local_' + these.cEdit.Id, srcPath);
|
||||
};
|
||||
const doSave = (persistentPath) => {
|
||||
const item = {
|
||||
...these.cEdit,
|
||||
localPath: persistentPath,
|
||||
fileUrl: '',
|
||||
deviceId,
|
||||
id: 'local_' + these.cEdit.Id,
|
||||
_createTime: these.cEdit.createTime || Common.DateFormat(new Date(), "yyyy年MM月dd日"),
|
||||
_isLocal: true
|
||||
};
|
||||
const key = `100J_local_audio_${deviceId}`;
|
||||
let list = uni.getStorageSync(key) || [];
|
||||
list.unshift(item);
|
||||
uni.setStorageSync(key, list);
|
||||
these.AudioData.tempFilePath = "";
|
||||
these.Status.isRecord = false;
|
||||
// 再用持久路径补写一遍缓存(若前面已成功则覆盖同 key)
|
||||
cache100JVoiceFileForBle(deviceId, item.id, persistentPath);
|
||||
uni.navigateBack();
|
||||
};
|
||||
const toPlusUrl = (p) => {
|
||||
if (!p) return p;
|
||||
try {
|
||||
if (plus.io.convertLocalFileSystemURL) {
|
||||
const c = plus.io.convertLocalFileSystemURL(p);
|
||||
if (c) return c;
|
||||
}
|
||||
} catch (e) {}
|
||||
return p;
|
||||
};
|
||||
const copyToDocByReadWrite = (srcPath, fileName, onOk, onFail) => {
|
||||
plus.io.resolveLocalFileSystemURL(toPlusUrl(srcPath), (srcEntry) => {
|
||||
srcEntry.file((file) => {
|
||||
const reader = new plus.io.FileReader();
|
||||
reader.onloadend = (e) => {
|
||||
const buf = e.target.result;
|
||||
if (!buf || !(buf.byteLength > 0)) {
|
||||
onFail(new Error('读取录音文件为空'));
|
||||
return;
|
||||
}
|
||||
plus.io.requestFileSystem(plus.io.PRIVATE_DOC, (fs) => {
|
||||
fs.root.getDirectory('100J_audio', { create: true }, (dirEntry) => {
|
||||
dirEntry.getFile(fileName, { create: true }, (newEntry) => {
|
||||
newEntry.createWriter((writer) => {
|
||||
writer.onwrite = () => onOk();
|
||||
writer.onerror = (ex) => onFail(ex || new Error('写入失败'));
|
||||
try {
|
||||
const blob = new Blob([buf], { type: 'application/octet-stream' });
|
||||
writer.write(blob);
|
||||
} catch (wex) {
|
||||
writer.write(buf);
|
||||
}
|
||||
}, onFail);
|
||||
}, onFail);
|
||||
}, onFail);
|
||||
}, onFail);
|
||||
};
|
||||
reader.onerror = () => onFail(new Error('读取录音失败'));
|
||||
reader.readAsArrayBuffer(file);
|
||||
}, onFail);
|
||||
}, onFail);
|
||||
};
|
||||
const fallbackDocSubdir = () => {
|
||||
if (typeof plus === 'undefined' || !plus.io) {
|
||||
doSave(filePath);
|
||||
return;
|
||||
}
|
||||
const fileName = 'audio_' + (these.cEdit.Id || Date.now()) + '.mp3';
|
||||
const docRel = '_doc/100J_audio/' + fileName;
|
||||
const tryRwFallback = (reason) => {
|
||||
console.warn('[100J] saveLocalForBle 复制失败,尝试读写落盘:', reason || '');
|
||||
copyToDocByReadWrite(filePath, fileName, () => doSave(docRel), () => doSave(filePath));
|
||||
};
|
||||
plus.io.resolveLocalFileSystemURL(toPlusUrl(filePath), (entry) => {
|
||||
plus.io.resolveLocalFileSystemURL('_doc/', (docEntry) => {
|
||||
docEntry.getDirectory('100J_audio', { create: true }, (dirEntry) => {
|
||||
entry.copyTo(dirEntry, fileName, () => {
|
||||
doSave(docRel);
|
||||
}, () => { tryRwFallback('copyTo'); });
|
||||
}, () => { tryRwFallback('getDirectory'); });
|
||||
}, () => { tryRwFallback('resolve _doc'); });
|
||||
}, () => { tryRwFallback('resolve src'); });
|
||||
};
|
||||
if (typeof plus === 'undefined' || !plus.io) {
|
||||
doSave(filePath);
|
||||
return;
|
||||
}
|
||||
const rawPath = (filePath && String(filePath).trim()) || '';
|
||||
// 保存流程开始时即尝试缓存一次(通常是 _doc/uniapp_temp 源路径)
|
||||
warmCacheNow(rawPath);
|
||||
// 已是 _doc 路径时直接保存;其余路径统一转存到 _doc/100J_audio
|
||||
if (rawPath.indexOf('_doc/') === 0) {
|
||||
doSave(rawPath);
|
||||
return;
|
||||
}
|
||||
fallbackDocSubdir();
|
||||
},
|
||||
// 保存录音并上传(已修复文件格式问题)
|
||||
uploadLuYin() {
|
||||
// 文件类型验证
|
||||
@ -554,6 +443,12 @@
|
||||
|
||||
const startOssUpload = () => {
|
||||
console.log("上传文件路径:", uploadFilePath);
|
||||
// _downloads/_doc 相对路径上 resolve 部分机型会长期无回调,直接走 doUpload(内会 convert 供 uni.uploadFile)
|
||||
const fp = String(uploadFilePath || '');
|
||||
if (fp.indexOf('_downloads/') === 0 || fp.indexOf('_doc/') === 0) {
|
||||
this.doUpload(uploadFilePath);
|
||||
return;
|
||||
}
|
||||
plus.io.resolveLocalFileSystemURL(uploadFilePath, (entry) => {
|
||||
entry.getMetadata((metadata) => {
|
||||
console.log("文件大小:", metadata.size, "字节");
|
||||
@ -569,15 +464,15 @@
|
||||
});
|
||||
};
|
||||
|
||||
// 无网络时不调 OSS,直接落本地列表,避免 uploadFile 白失败;列表里点「使用」走蓝牙下发
|
||||
// 无网络不允许保存:无网本地项无法上传云端,列表里「使用」也无法可靠读本地蓝牙下发
|
||||
uni.getNetworkType({
|
||||
success: (res) => {
|
||||
if (res.networkType === 'none') {
|
||||
this.saveLocalForBle(uploadFilePath);
|
||||
uni.showToast({
|
||||
title: '无网络,已保存到本地。请在列表连接蓝牙后点「使用」下发;有网后可再保存上传云端',
|
||||
icon: 'none',
|
||||
duration: 4000
|
||||
uni.showModal({
|
||||
title: '无法保存',
|
||||
content: '当前无网络,语音需上传云端后才能正常使用与蓝牙下发。请连接 WiFi 或移动网络后再点保存。',
|
||||
showCancel: false,
|
||||
confirmText: '知道了'
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -592,18 +487,27 @@
|
||||
// 执行上传操作
|
||||
doUpload(filePath) {
|
||||
const key = `${Common.pcmStorageKey}_${this.cEdit.Id}`;
|
||||
const store = uni.getStorageInfoSync();
|
||||
if (store.keys.includes(key)) return;
|
||||
// 勿因历史 pcmStorageKey_* 存在就静默 return,否则用户点保存无反应、OSS 永不上传
|
||||
const token = uni.getStorageSync('token');
|
||||
const clientid = uni.getStorageSync('clientID');
|
||||
const these = this;
|
||||
let pathForUpload = filePath;
|
||||
try {
|
||||
if (typeof plus !== 'undefined' && plus.io && plus.io.convertLocalFileSystemURL) {
|
||||
const fp = String(filePath || '');
|
||||
if (fp.indexOf('_downloads/') === 0 || fp.indexOf('_doc/') === 0) {
|
||||
const c = plus.io.convertLocalFileSystemURL(fp);
|
||||
if (c) pathForUpload = c;
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
showLoading(this, {
|
||||
text: "文件上传中"
|
||||
});
|
||||
console.log("最终上传文件路径:", filePath);
|
||||
console.log("最终上传文件路径:", pathForUpload);
|
||||
uni.uploadFile({
|
||||
url: baseURL + "/app/video/uploadAudioToOss",
|
||||
filePath: filePath,
|
||||
filePath: pathForUpload,
|
||||
name: 'file',
|
||||
header: {
|
||||
"Authorization": `Bearer ${token}`,
|
||||
@ -690,14 +594,13 @@
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('上传文件失败:', err);
|
||||
// 无网络时保存到本地,供蓝牙直接发送
|
||||
these.saveLocalForBle(filePath);
|
||||
uni.showToast({
|
||||
title: '网络不可用,已保存到本地,可通过蓝牙发送',
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
these.timeOutCloseLoad();
|
||||
uni.showModal({
|
||||
title: '保存失败',
|
||||
content: '文件未能上传到服务器。请检查网络后重试;无网时无法保存语音。',
|
||||
showCancel: false,
|
||||
confirmText: '知道了'
|
||||
});
|
||||
},
|
||||
complete: () => {
|
||||
console.log('上传操作完成');
|
||||
|
||||
Reference in New Issue
Block a user