diff --git a/src/utils/systemInfo.js b/src/utils/systemInfo.js new file mode 100644 index 00000000..fe1fe00a --- /dev/null +++ b/src/utils/systemInfo.js @@ -0,0 +1,475 @@ +// 浏览器信息检测 +class SystemInfo { + constructor() { + this.info = { + browser: this.getBrowserInfo(), + os: this.getOSInfo(), + hardware: this.getHardwareInfo(), + webgl: this.getWebGLInfo() + }; + } + + // 获取浏览器信息 + getBrowserInfo() { + const ua = navigator.userAgent; + let browser = { + name: 'Unknown', + version: 'Unknown', + fullVersion: navigator.appVersion + }; + + // 检测浏览器类型 + if (ua.includes('Firefox')) { + browser.name = 'Firefox'; + browser.version = this.extractVersion(ua, 'Firefox'); + } else if (ua.includes('Chrome') && !ua.includes('Edg') && !ua.includes('OPR')) { + browser.name = 'Chrome'; + browser.version = this.extractVersion(ua, 'Chrome'); + } else if (ua.includes('Safari') && !ua.includes('Chrome')) { + browser.name = 'Safari'; + browser.version = this.extractVersion(ua, 'Version'); + } else if (ua.includes('Edg')) { + browser.name = 'Edge'; + browser.version = this.extractVersion(ua, 'Edg'); + } else if (ua.includes('OPR') || ua.includes('Opera')) { + browser.name = 'Opera'; + browser.version = this.extractVersion(ua, 'OPR') || this.extractVersion(ua, 'Opera'); + } else if (ua.includes('Trident') || ua.includes('MSIE')) { + browser.name = 'Internet Explorer'; + browser.version = this.extractVersion(ua, 'MSIE') || this.extractVersion(ua, 'rv:'); + } + + return browser; + } + + // 提取版本号 + extractVersion(userAgent, browserName) { + const match = userAgent.match(new RegExp(`${browserName}/([0-9]+(\\.[0-9]+)?)`)); + return match ? match[1] : 'Unknown'; + } + + // 获取操作系统信息 + getOSInfo() { + const ua = navigator.userAgent; + let os = { + name: 'Unknown', + version: 'Unknown', + architecture: this.getArchitecture() + }; + + if (ua.includes('Windows')) { + os.name = 'Windows'; + if (ua.includes('Windows NT 10.0')) os.version = '10'; + else if (ua.includes('Windows NT 6.3')) os.version = '8.1'; + else if (ua.includes('Windows NT 6.2')) os.version = '8'; + else if (ua.includes('Windows NT 6.1')) os.version = '7'; + else if (ua.includes('Windows NT 6.0')) os.version = 'Vista'; + else if (ua.includes('Windows NT 5.1')) os.version = 'XP'; + } else if (ua.includes('Mac OS X')) { + os.name = 'macOS'; + const match = ua.match(/Mac OS X (\d+[._]\d+)/); + if (match) os.version = match[1].replace('_', '.'); + } else if (ua.includes('Linux')) { + os.name = 'Linux'; + } else if (ua.includes('Android')) { + os.name = 'Android'; + const match = ua.match(/Android ([0-9.]+)/); + if (match) os.version = match[1]; + } else if (ua.includes('like Mac')) { + os.name = 'iOS'; + const match = ua.match(/OS (\d+[_]\d+)/); + if (match) os.version = match[1].replace('_', '.'); + } + + return os; + } + + // 获取系统架构 + getArchitecture() { + if (navigator.userAgent.includes('x64') || navigator.userAgent.includes('x86_64')) { + return '64-bit'; + } else if (navigator.userAgent.includes('x86') || navigator.userAgent.includes('i686')) { + return '32-bit'; + } else if (navigator.userAgent.includes('ARM')) { + return 'ARM'; + } else if (navigator.userAgent.includes('Win64')) { + return '64-bit'; + } + return 'Unknown'; + } + + // 获取硬件信息 + getHardwareInfo() { + return { + logicalCores: navigator.hardwareConcurrency || 'Unknown', + deviceMemory: navigator.deviceMemory ? `${navigator.deviceMemory} GB` : 'Unknown', + maxTouchPoints: navigator.maxTouchPoints || 0 + }; + } + + // 获取WebGL和显卡信息 + getWebGLInfo() { + const webglInfo = { + webgl1: this.getWebGLContextInfo('webgl'), + webgl2: this.getWebGLContextInfo('webgl2'), + supported: false, + renderer: 'Unknown', + vendor: 'Unknown', + version: 'Unknown', + shadingLanguage: 'Unknown', + extensions: [] + }; + + const canvas = document.createElement('canvas'); + let gl = null; + + // 尝试获取WebGL2上下文 + try { + gl = canvas.getContext('webgl2') || canvas.getContext('experimental-webgl2'); + } catch (e) { + console.log('WebGL2 not supported:', e.message); + } + + // 如果WebGL2不可用,尝试WebGL1 + if (!gl) { + try { + gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); + } catch (e) { + console.log('WebGL not supported:', e.message); + } + } + + if (gl) { + webglInfo.supported = true; + + // 获取显卡信息 + const debugInfo = gl.getExtension('WEBGL_debug_renderer_info'); + if (debugInfo) { + webglInfo.renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL) || 'Unknown'; + webglInfo.vendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL) || 'Unknown'; + } + + // 获取WebGL版本信息 + webglInfo.version = gl.getParameter(gl.VERSION) || 'Unknown'; + webglInfo.shadingLanguage = gl.getParameter(gl.SHADING_LANGUAGE_VERSION) || 'Unknown'; + + // 获取支持的扩展 + try { + webglInfo.extensions = gl.getSupportedExtensions() || []; + } catch (e) { + console.log('无法获取WebGL扩展:', e.message); + } + + // 检查GPU性能级别 + webglInfo.performance = this.getGPUPerformanceInfo(gl); + + // 检查内存信息(如果支持) + webglInfo.memoryInfo = this.getGPUMemoryInfo(gl); + + // 检查是否使用集成显卡 + if (webglInfo.renderer) { + webglInfo.gpuType = this.detectGPUType(webglInfo.renderer); + } + } + + return webglInfo; + } + + // 获取WebGL上下文的具体信息 + getWebGLContextInfo(contextType) { + const canvas = document.createElement('canvas'); + let gl = null; + + try { + gl = canvas.getContext(contextType) || + canvas.getContext(`experimental-${contextType}`); + } catch (e) { + return { supported: false, error: e.message }; + } + + if (!gl) { + return { supported: false }; + } + + return { + supported: true, + context: gl + }; + } + + // 获取GPU性能信息 + getGPUPerformanceInfo(gl) { + const info = { tier: 'unknown', features: [] }; + + // 检查是否支持高性能特性 + try { + // 检查帧缓冲 + if (gl.checkFramebufferStatus) { + info.features.push('framebuffer'); + } + + // 检查浮点纹理 + const floatExt = gl.getExtension('OES_texture_float') || + gl.getExtension('EXT_color_buffer_float'); + if (floatExt) info.features.push('float_textures'); + + // 检查多重采样 + const msaaExt = gl.getExtension('WEBGL_multisampled_render_to_texture'); + if (msaaExt) info.features.push('msaa'); + + // 检查实例化渲染 + const instancingExt = gl.getExtension('ANGLE_instanced_arrays') || + gl.getExtension('WEBGL_draw_buffers'); + if (instancingExt) info.features.push('instancing'); + + // 尝试检测性能级别(基于支持的扩展) + if (info.features.includes('float_textures') && + info.features.includes('msaa') && + info.features.includes('instancing')) { + info.tier = 'high'; + } else if (info.features.length >= 2) { + info.tier = 'medium'; + } else { + info.tier = 'low'; + } + } catch (e) { + console.log('获取GPU性能信息失败:', e); + } + + return info; + } + + // 获取GPU内存信息 + getGPUMemoryInfo(gl) { + const memoryInfo = { estimatedMemory: 'Unknown' }; + + // 尝试通过扩展获取内存信息 + try { + // 检查是否支持内存信息扩展 + const memoryExt = gl.getExtension('WEBGL_debug_renderer_info'); + if (memoryExt) { + // 一些浏览器会通过UNMASKED_RENDERER_WEBGL暴露内存信息 + const renderer = gl.getParameter(memoryExt.UNMASKED_RENDERER_WEBGL); + if (renderer) { + // 尝试从渲染器字符串中提取内存信息 + const match = renderer.match(/(\d+)\s*MB|(\d+)\s*GB|VRAM\s*:\s*(\d+)/i); + if (match) { + memoryInfo.estimatedMemory = match[0]; + } + } + } + + // 通过创建大纹理测试内存 + memoryInfo.maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE); + memoryInfo.maxRenderbufferSize = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE); + } catch (e) { + // 静默失败 + } + + return memoryInfo; + } + + // 检测GPU类型 + detectGPUType(renderer) { + const r = renderer.toLowerCase(); + + if (r.includes('nvidia') || r.includes('geforce') || r.includes('gtx') || r.includes('rtx')) { + return { type: 'NVIDIA', discrete: true }; + } else if (r.includes('amd') || r.includes('radeon') || r.includes('rx')) { + return { type: 'AMD', discrete: true }; + } else if (r.includes('intel') || r.includes('hd graphics') || r.includes('iris') || r.includes('uhd')) { + return { type: 'Intel', discrete: false }; + } else if (r.includes('apple') || r.includes('apple gpu') || r.includes('apple m')) { + return { type: 'Apple Silicon', discrete: false }; + } else if (r.includes('mali') || r.includes('adreno') || r.includes('powervr')) { + return { type: 'Mobile GPU', discrete: false }; + } else if (r.includes('microsoft') || r.includes('basic')) { + return { type: 'Software Renderer', discrete: false }; + } + + return { type: 'Unknown', discrete: false }; + } + + // 获取屏幕信息 + getScreenInfo() { + return { + width: window.screen.width, + height: window.screen.height, + colorDepth: window.screen.colorDepth, + pixelDepth: window.screen.pixelDepth, + devicePixelRatio: window.devicePixelRatio || 1, + orientation: window.screen.orientation ? window.screen.orientation.type : 'unknown' + }; + } + + // 获取所有系统信息 + getAllInfo() { + return { + ...this.info, + screen: this.getScreenInfo(), + userAgent: navigator.userAgent, + platform: navigator.platform, + language: navigator.language, + languages: navigator.languages, + cookiesEnabled: navigator.cookieEnabled, + online: navigator.onLine, + javaEnabled: navigator.javaEnabled ? navigator.javaEnabled() : false, + pdfViewerEnabled: navigator.pdfViewerEnabled || false, + doNotTrack: navigator.doNotTrack || 'unknown', + timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, + dateTimeFormat: new Date().toString() + }; + } + + // 格式化输出 + formatAsText() { + const info = this.getAllInfo(); + let output = '========== 系统信息 ==========\n\n'; + + // 浏览器信息 + output += '=== 浏览器信息 ===\n'; + output += `浏览器: ${info.browser.name} ${info.browser.version}\n`; + output += `完整版本: ${info.browser.fullVersion}\n`; + output += `用户代理: ${info.userAgent}\n\n`; + + // 操作系统信息 + output += '=== 操作系统信息 ===\n'; + output += `系统: ${info.os.name} ${info.os.version}\n`; + output += `架构: ${info.os.architecture}\n`; + output += `平台: ${info.platform}\n\n`; + + // 硬件信息 + output += '=== 硬件信息 ===\n'; + output += `逻辑核心数: ${info.hardware.logicalCores}\n`; + output += `设备内存: ${info.hardware.deviceMemory}\n`; + output += `最大触摸点数: ${info.hardware.maxTouchPoints}\n\n`; + + // 屏幕信息 + output += '=== 屏幕信息 ===\n'; + output += `分辨率: ${info.screen.width} × ${info.screen.height}\n`; + output += `设备像素比: ${info.screen.devicePixelRatio}\n`; + output += `颜色深度: ${info.screen.colorDepth} 位\n`; + output += `像素深度: ${info.screen.pixelDepth} 位\n`; + output += `方向: ${info.screen.orientation}\n\n`; + + // WebGL信息 + output += '=== WebGL 信息 ===\n'; + output += `WebGL 支持: ${info.webgl.supported ? '是' : '否'}\n`; + + if (info.webgl.supported) { + output += `WebGL 版本: ${info.webgl.version}\n`; + output += `显卡型号: ${info.webgl.renderer}\n`; + output += `显卡厂商: ${info.webgl.vendor}\n`; + output += `着色语言: ${info.webgl.shadingLanguage}\n`; + + if (info.webgl.gpuType) { + output += `GPU 类型: ${info.webgl.gpuType.type}\n`; + output += `独立显卡: ${info.webgl.gpuType.discrete ? '是' : '否'}\n`; + } + + output += `性能等级: ${info.webgl.performance.tier}\n`; + output += `支持特性: ${info.webgl.performance.features.join(', ')}\n`; + + if (info.webgl.memoryInfo.estimatedMemory !== 'Unknown') { + output += `显存估计: ${info.webgl.memoryInfo.estimatedMemory}\n`; + } + + if (info.webgl.memoryInfo.maxTextureSize) { + output += `最大纹理尺寸: ${info.webgl.memoryInfo.maxTextureSize}\n`; + } + + output += `WebGL 扩展数: ${info.webgl.extensions.length}\n`; + } + + // 其他信息 + output += '\n=== 其他信息 ===\n'; + output += `语言: ${info.language}\n`; + output += `支持语言: ${info.languages.join(', ')}\n`; + output += `时区: ${info.timezone}\n`; + output += `Cookie 支持: ${info.cookiesEnabled ? '是' : '否'}\n`; + output += `在线状态: ${info.online ? '在线' : '离线'}\n`; + output += `Java 支持: ${info.javaEnabled ? '是' : '否'}\n`; + output += `PDF 查看器: ${info.pdfViewerEnabled ? '支持' : '不支持'}\n`; + output += `Do Not Track: ${info.doNotTrack}\n`; + output += `当前时间: ${info.dateTimeFormat}\n`; + + return output; + } + + // 创建HTML显示 + createInfoHTML() { + const info = this.getAllInfo(); + let html = ` +
+

系统信息

+ +
+

🌐 浏览器信息

+ + + + +
浏览器${info.browser.name} ${info.browser.version}
用户代理${info.userAgent}
平台${info.platform}
+
+ +
+

💻 操作系统

+ + + + + +
系统${info.os.name} ${info.os.version}
架构${info.os.architecture}
语言${info.language}
时区${info.timezone}
+
+ +
+

🖥️ 硬件信息

+ + + + + +
CPU 核心数${info.hardware.logicalCores}
设备内存${info.hardware.deviceMemory}
屏幕分辨率${info.screen.width} × ${info.screen.height}
设备像素比${info.screen.devicePixelRatio}
+
+ `; + + if (info.webgl.supported) { + html += ` +
+

🎮 WebGL & 显卡信息

+ + + + + + + + + + `; + + if (info.webgl.memoryInfo.estimatedMemory !== 'Unknown') { + html += ``; + } + + html += `
WebGL 支持✅ 已支持
WebGL 版本${info.webgl.version}
显卡型号${info.webgl.renderer}
显卡厂商${info.webgl.vendor}
GPU 类型${info.webgl.gpuType.type} ${info.webgl.gpuType.discrete ? '(独立显卡)' : '(集成显卡)'}
着色语言${info.webgl.shadingLanguage}
性能等级${info.webgl.performance.tier}
WebGL 扩展数${info.webgl.extensions.length} 个
显存估计${info.webgl.memoryInfo.estimatedMemory}
`; + } else { + html += ` +
+

🎮 WebGL & 显卡信息

+

❌ WebGL 不支持

+
+ `; + } + + html += `
`; + + return html; + } +} + +if (typeof module !== 'undefined' && module.exports) { + module.exports = SystemInfo; +} else if (typeof window !== 'undefined') { + window.SystemInfo = SystemInfo; +} \ No newline at end of file diff --git a/src/views/dictionary/template/browser/tip.vue b/src/views/dictionary/template/browser/tip.vue index 5e380a6e..a88e10d1 100644 --- a/src/views/dictionary/template/browser/tip.vue +++ b/src/views/dictionary/template/browser/tip.vue @@ -6,12 +6,13 @@ diff --git a/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue b/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue index f76e71b5..e82995b7 100644 --- a/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue +++ b/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue @@ -498,6 +498,7 @@ import uploadDicomAndNonedicom from '@/components/uploadDicomAndNonedicom' import downloadDicomAndNonedicom from '@/components/downloadDicomAndNonedicom' import { getNetWorkSpeed, setNetWorkSpeedSizeAll, workSpeedclose } from "@/utils" import readingChart from '@/components/readingChart' +import SystemInfo from "@/utils/systemInfo"; const { visibility } = annotation const { ViewportType, Events } = Enums const renderingEngineId = 'myRenderingEngine' @@ -3289,8 +3290,11 @@ export default { } const series = data ? data : this.$refs[`viewport-${this.activeViewportIndex}`][0].series if (series.ImageIds.length <= 5) return this.$confirm(this.$t('trials:reading:confirm:smallNumberOfimage')) + if (series.ImageIds.length > 500) { + let res = await this.getSystemInfo() + if (!res) return false + } this.isMPR = true - console.log(series, 'series') this.rows = 3 this.cols = 1 this.loading = true @@ -3315,11 +3319,15 @@ export default { if (!confirm) return false this.$refs[`ecrf_${this.taskInfo.VisitTaskId}`][0].removeAllNoSaveAnnotation() } + const { ct, pt } = data + if (ct.ImageIds.length > 400) { + let res = await this.getSystemInfo() + if (!res) return false + } this.fusionVisible = false this.isFusion = true this.rows = 2 this.cols = 2 - const { ct, pt } = data this.loading = true this.loadingText = this.$t('trials:lugano:message:loadVolumes') this.renderedTaskIds = [] @@ -3456,6 +3464,23 @@ export default { this.uploadStatus = status this[`${status}ImageVisible`] = true }, + getSystemInfo() { + return new Promise(async resolve => { + const systemInfo = new SystemInfo(); + const allInfo = systemInfo.getAllInfo(); + let deviceMemory = allInfo.hardware.deviceMemory; // 设备内存 + let { width, height } = allInfo.screen; // 分辨率 + let discrete = allInfo.webgl.gpuType.discrete; // 是否独立显卡 + let estimatedMemory = allInfo.webgl.memoryInfo.estimatedMemory; // 显卡内存 + if (parseFloat(deviceMemory) < 16 || width < 1920 || height < 1080 || !discrete || parseFloat(estimatedMemory) < 2) { + let res = await this.$confirm(this.$t('browser:tip:ReadingConfiguration')) + resolve(res) + } else { + resolve(true) + } + + }) + }, }, beforeDestroy() { DicomEvent.$off('isCanActiveNoneDicomTool')