1
0
forked from dyf/APP

优化100j

This commit is contained in:
微微一笑
2026-03-26 19:20:52 +08:00
parent e7b40dbed6
commit b99ac04c88
8 changed files with 745 additions and 120 deletions

View File

@ -105,7 +105,9 @@
videRenameAudioFile,
deviceDeleteAudioFile,
deviceUpdateVoice,
updateBleStatus
updateBleStatus,
sync100JBleProtocolFromHelper,
remove100JVoiceBleCache
} from '@/api/100J/HBY100-J.js'
import { baseURL } from '@/utils/request.js'
import {
@ -431,7 +433,10 @@
let task = () => {
if (item._isLocal) {
// 本地项:从本地存储移除
const key = `100J_local_audio_${this.device.deviceId}`;
const devId = this.device.deviceId;
const vid = (item.id != null && item.id !== '') ? item.id : item.fileId;
remove100JVoiceBleCache(devId, vid);
const key = `100J_local_audio_${devId}`;
let list = uni.getStorageSync(key) || [];
list = list.filter(l => l.id !== item.id && l.Id !== item.Id);
uni.setStorageSync(key, list);
@ -528,12 +533,16 @@
const raw = item.fileUrl || item.url || item.filePath || item.audioUrl || item.ossUrl || '';
fileUrl = (typeof raw === 'string' && raw) ? (raw.startsWith('/') ? (baseURL + raw) : raw) : '';
} else {
// 本地项localPath 优先,无则用 fileUrlmergeLocal 可能只有 fileUrl路径
if (!localPath && item.fileUrl) localPath = item.fileUrl;
// 本地项localPath 优先mergeLocal 可能把路径放在 fileUrl,但勿把 http 当成本地路径
if (!localPath && item.fileUrl) {
const cand = String(item.fileUrl).trim();
if (cand && !/^https?:\/\//i.test(cand)) localPath = cand;
}
}
const data = {
id: item.id,
fileUrl,
id: (item.id != null && item.id !== '') ? item.id : item.fileId,
// 本地合并项 mergeLocal 会把路径写在 fileUrl需带给接口层做 effectiveLocal 兜底
fileUrl: item._isLocal ? (typeof item.fileUrl === 'string' ? item.fileUrl : '') : fileUrl,
localPath,
onProgress: (p) => { this.updateProgress = p; },
// 不传「蓝牙连接中」类提示:关蓝牙走 4G 时易误导;进度条 + 必要时全局请稍候即可
@ -546,8 +555,9 @@
this.isUpdating = false;
this.updateProgress = 0;
}
}, 60000);
deviceUpdateVoice(data).then((RES) => {
}, 120000); // 蓝牙分片+MTU 协商+大包写入较慢60s 易误报「操作超时」
// 进入列表时的蓝牙快照可能过期;与 HBY100 详情页一致,从 BleHelper 按 MAC 再对齐一次,否则常静默走 4G、看不到 [100J-蓝牙] 分片日志
sync100JBleProtocolFromHelper(this.device).then(() => deviceUpdateVoice(data)).then((RES) => {
clearTimeout(overallTimer);
if (RES.code == 200) {
// 蓝牙上传:进度已由 onProgress 更新,直接完成
@ -596,7 +606,8 @@
}).catch((err) => {
clearTimeout(overallTimer);
this.isUpdating = false;
uni.showToast({ title: err.message || '操作失败', icon: 'none', duration: 2000 });
this.updateProgress = 0;
uni.showToast({ title: err.message || '操作失败', icon: 'none', duration: 2500 });
});
},
closePop: function() {

View File

@ -137,8 +137,9 @@
updateLoading
} from '@/utils/loading.js';
import Common from '@/utils/Common.js';
import {
cache100JVoiceFileForBle
} from '@/api/100J/HBY100-J.js';
export default {
data() {
@ -422,10 +423,19 @@
}, 1200);
},
// 无网络时保存到本地,供蓝牙直接发送(不依赖 OSS
// 将临时文件复制到持久化目录 _doc/100J_audio/,避免被系统清理
// 当前部分机型 PUBLIC_DOWNLOADS 在读取阶段会出现 requestFileSystem/resolve 长时间无回调,
// 因此本地语音优先落到 _doc/100J_audio后续蓝牙下发走 PRIVATE_DOC 分支更稳定。
saveLocalForBle(filePath) {
const deviceId = these.Status.ID;
if (!deviceId) return;
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,
@ -442,22 +452,86 @@
uni.setStorageSync(key, list);
these.AudioData.tempFilePath = "";
these.Status.isRecord = false;
// 再用持久路径补写一遍缓存(若前面已成功则覆盖同 key
cache100JVoiceFileForBle(deviceId, item.id, persistentPath);
uni.navigateBack();
};
if (typeof plus !== 'undefined' && plus.io) {
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';
plus.io.resolveLocalFileSystemURL(filePath, (entry) => {
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, (newEntry) => {
doSave(newEntry.fullPath);
}, () => { doSave(filePath); });
}, () => { doSave(filePath); });
}, () => { doSave(filePath); });
}, () => { doSave(filePath); });
} else {
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() {
@ -478,19 +552,40 @@
console.log("自动添加.mp3扩展名新路径:", uploadFilePath);
}
console.log("上传文件路径:", uploadFilePath);
plus.io.resolveLocalFileSystemURL(uploadFilePath, (entry) => {
entry.getMetadata((metadata) => {
console.log("文件大小:", metadata.size, "字节");
console.log("文件类型验证通过");
this.doUpload(uploadFilePath);
const startOssUpload = () => {
console.log("上传文件路径:", uploadFilePath);
plus.io.resolveLocalFileSystemURL(uploadFilePath, (entry) => {
entry.getMetadata((metadata) => {
console.log("文件大小:", metadata.size, "字节");
console.log("文件类型验证通过");
this.doUpload(uploadFilePath);
}, (err) => {
console.error("获取文件元数据失败:", err);
this.doUpload(this.AudioData.tempFilePath);
});
}, (err) => {
console.error("获取文件元数据失败:", err);
console.error("文件不存在或路径错误:", err);
this.doUpload(this.AudioData.tempFilePath);
});
}, (err) => {
console.error("文件不存在或路径错误:", err);
this.doUpload(this.AudioData.tempFilePath);
};
// 无网络时不调 OSS直接落本地列表避免 uploadFile 白失败;列表里点「使用」走蓝牙下发
uni.getNetworkType({
success: (res) => {
if (res.networkType === 'none') {
this.saveLocalForBle(uploadFilePath);
uni.showToast({
title: '无网络,已保存到本地。请在列表连接蓝牙后点「使用」下发;有网后可再保存上传云端',
icon: 'none',
duration: 4000
});
return;
}
startOssUpload();
},
fail: () => {
startOssUpload();
}
});
},
@ -535,6 +630,9 @@
if (fileUrl) cache[fileUrl] = filePath;
if (d && typeof d === 'object' && d.id) cache[d.id] = filePath;
uni.setStorageSync(cacheKey, cache);
if (d && typeof d === 'object' && d.id) {
cache100JVoiceFileForBle(deviceId, d.id, filePath);
}
}
}
// 合并两个存储操作