|
|
|
|
@ -458,7 +458,7 @@ export default { |
|
|
|
|
window.hirtcwebsdk.init({ |
|
|
|
|
serviceID: '56da5fd8921f4f7093a42e2a', |
|
|
|
|
serviceKey: '2c17c6393771ee3048ae34d6b965sdew', |
|
|
|
|
Services: { BasicRoomServiceToken: "https://192.168.69.174:3001/v1/auth/token" }, |
|
|
|
|
Services: { BasicRoomServiceToken: "https://wjw-ultrasoundappl/v1/auth/token" }, |
|
|
|
|
cameraLayers: [ |
|
|
|
|
{ |
|
|
|
|
width: 320, |
|
|
|
|
@ -902,18 +902,12 @@ export default { |
|
|
|
|
mimeType: 'video/webm;codecs=vp8,opus', |
|
|
|
|
}); |
|
|
|
|
this.recordedChunks = []; |
|
|
|
|
const fileName = `${this.meetingTitle}录制_${new Date().toLocaleString().replace(/[/:\\s]/g, '_')}.webm`; |
|
|
|
|
this.mediaRecorder.ondataavailable = e => e.data.size && this.recordedChunks.push(e.data); |
|
|
|
|
this.mediaRecorder.onstop = () => { |
|
|
|
|
this.mediaRecorder.onstop = async () => { |
|
|
|
|
const blob = new Blob(this.recordedChunks, { type: 'video/webm' }); |
|
|
|
|
const url = URL.createObjectURL(blob); |
|
|
|
|
const a = document.createElement('a'); |
|
|
|
|
a.href = url; |
|
|
|
|
a.download = `${this.meetingTitle}录制_${new Date().toLocaleString()}.webm`; |
|
|
|
|
document.body.appendChild(a); |
|
|
|
|
a.click(); |
|
|
|
|
document.body.removeChild(a); |
|
|
|
|
URL.revokeObjectURL(url); |
|
|
|
|
this.$message.success('录制完成'); |
|
|
|
|
// 优先保存到系统设置的视讯存储路径,降级下载 |
|
|
|
|
await this._saveBlobToVideoPath(blob, fileName, '录制'); |
|
|
|
|
}; |
|
|
|
|
this.mediaRecorder.start(); |
|
|
|
|
this.isRecording = true; |
|
|
|
|
@ -921,6 +915,7 @@ export default { |
|
|
|
|
this.startRecordingTimer(); |
|
|
|
|
this.$message.warning('录制中'); |
|
|
|
|
} catch (e) { |
|
|
|
|
console.error('录制失败', e); |
|
|
|
|
this.$message.error('录制失败'); |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
@ -957,8 +952,44 @@ export default { |
|
|
|
|
this.saveMeetingSnapshot(); |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 保存会议界面截图 |
|
|
|
|
// ==================== 截图保存辅助:IndexedDB 存储目录句柄 ==================== |
|
|
|
|
_openIDB() { |
|
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
|
const req = indexedDB.open('HiUTalkStoreDB', 1); |
|
|
|
|
req.onupgradeneeded = () => { req.result.createObjectStore('handles'); }; |
|
|
|
|
req.onsuccess = () => resolve(req.result); |
|
|
|
|
req.onerror = () => reject(req.error); |
|
|
|
|
}); |
|
|
|
|
}, |
|
|
|
|
async _getStoredDirHandle() { |
|
|
|
|
const db = await this._openIDB(); |
|
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
|
const tx = db.transaction('handles', 'readonly'); |
|
|
|
|
const req = tx.objectStore('handles').get('screenshot_dir'); |
|
|
|
|
req.onsuccess = () => { db.close(); resolve(req.result); }; |
|
|
|
|
req.onerror = () => { db.close(); reject(req.error); }; |
|
|
|
|
}); |
|
|
|
|
}, |
|
|
|
|
// 获取已授权的目录句柄(页面刷新后自动重授权,不弹目录选择器) |
|
|
|
|
async _getAuthorizedHandle() { |
|
|
|
|
const dirHandle = await this._getStoredDirHandle(); |
|
|
|
|
if (!dirHandle) return null; |
|
|
|
|
let perm = await dirHandle.queryPermission({ mode: 'readwrite' }); |
|
|
|
|
// 页面刷新后权限变为 'prompt',需重新请求(saveMeetingSnapshot 由用户点击触发,具备手势上下文) |
|
|
|
|
if (perm !== 'granted') { |
|
|
|
|
try { |
|
|
|
|
perm = await dirHandle.requestPermission({ mode: 'readwrite' }); |
|
|
|
|
} catch (e) { |
|
|
|
|
console.error('重新请求目录权限失败', e); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return perm === 'granted' ? dirHandle : null; |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 保存会议界面截图(保存到系统设置中的视讯存储路径,无弹窗) |
|
|
|
|
async saveMeetingSnapshot() { |
|
|
|
|
// 1. 截图生成 canvas 和 blob |
|
|
|
|
let blob, fileName; |
|
|
|
|
try { |
|
|
|
|
const html2canvas = (await import('html2canvas')).default; |
|
|
|
|
const container = document.querySelector('.meeting-container'); |
|
|
|
|
@ -972,14 +1003,61 @@ export default { |
|
|
|
|
logging: false, |
|
|
|
|
allowTaint: false, |
|
|
|
|
}); |
|
|
|
|
const link = document.createElement('a'); |
|
|
|
|
link.download = `会诊截图_${new Date().toLocaleString()}.png`; |
|
|
|
|
link.href = canvas.toDataURL('image/png'); |
|
|
|
|
link.click(); |
|
|
|
|
this.$message.success('截图已保存'); |
|
|
|
|
} catch (err) { |
|
|
|
|
console.error('截图失败', err); |
|
|
|
|
this.$message.error('截图失败'); |
|
|
|
|
fileName = `会诊截图_${new Date().toLocaleString().replace(/[/:\\s]/g, '_')}.png`; |
|
|
|
|
blob = await new Promise((resolve, reject) => { |
|
|
|
|
canvas.toBlob(b => { if (b) resolve(b); else reject(new Error('toBlob 失败')); }, 'image/png'); |
|
|
|
|
}); |
|
|
|
|
} catch (e) { |
|
|
|
|
console.error('截图生成失败', e); |
|
|
|
|
this.$message.error('截图生成失败'); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 2. 优先保存到系统设置的视讯存储路径,降级下载 |
|
|
|
|
await this._saveBlobToVideoPath(blob, fileName, '截图'); |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 将 blob 保存到系统设置的视讯存储路径(优先写入授权目录,降级下载) |
|
|
|
|
async _saveBlobToVideoPath(blob, fileName, label) { |
|
|
|
|
const videoPath = this._getSystemVideoPath(); |
|
|
|
|
|
|
|
|
|
// 1. 尝试写入已授权的目录 |
|
|
|
|
const dirHandle = await this._getAuthorizedHandle(); |
|
|
|
|
if (dirHandle) { |
|
|
|
|
try { |
|
|
|
|
const fileHandle = await dirHandle.getFileHandle(fileName, { create: true }); |
|
|
|
|
const writable = await fileHandle.createWritable(); |
|
|
|
|
await writable.write(blob); |
|
|
|
|
await writable.close(); |
|
|
|
|
this.$message.success(`${label}已保存到 ${videoPath || dirHandle.name}`); |
|
|
|
|
return; |
|
|
|
|
} catch (err) { |
|
|
|
|
console.error(`${label}写入失败,降级为下载`, err); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 2. 降级方案:浏览器下载 |
|
|
|
|
try { |
|
|
|
|
const { saveAs } = await import('file-saver'); |
|
|
|
|
saveAs(blob, fileName); |
|
|
|
|
this.$message.success(videoPath |
|
|
|
|
? `${label}已下载(请在系统设置中授权"${videoPath}"以自动保存)` |
|
|
|
|
: `${label}已保存`); |
|
|
|
|
} catch (e) { |
|
|
|
|
console.error(`${label}保存失败`, e); |
|
|
|
|
this.$message.error(`${label}保存失败`); |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 从系统设置中读取视讯存储路径 |
|
|
|
|
_getSystemVideoPath() { |
|
|
|
|
try { |
|
|
|
|
const raw = localStorage.getItem('systemSettings'); |
|
|
|
|
if (!raw) return ''; |
|
|
|
|
const settings = JSON.parse(raw); |
|
|
|
|
return settings.basicForm?.videoPath || ''; |
|
|
|
|
} catch (e) { |
|
|
|
|
return ''; |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|