From 8b069194aacd48a21dd41a71fd79292b089085d7 Mon Sep 17 00:00:00 2001 From: ZF sun <34314687@qq.com> Date: Wed, 6 May 2026 14:24:18 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E5=AD=97=E5=B9=95):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=AD=97=E5=B9=95=E6=A0=B7=E5=BC=8F=E8=AE=BE=E7=BD=AE=E9=9D=A2?= =?UTF-8?q?=E6=9D=BF=E5=8F=8A=E6=8B=96=E6=8B=BD=E7=BC=A9=E6=94=BE=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加字幕样式设置浮动面板,包含宽度、高度、字体大小等配置项 实现字幕容器的拖拽移动和缩放功能 添加字幕容器自动检测和初始化逻辑 --- frontend/index.html | 34 +++++++++ frontend/scripts/main.js | 149 +++++++++++++++++++++++++++++++++++++++ frontend/styles/main.css | 7 ++ 3 files changed, 190 insertions(+) diff --git a/frontend/index.html b/frontend/index.html index 1a3552d..8ad0f76 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -22,6 +22,9 @@ + @@ -68,6 +71,37 @@ + +
+
+

📝 字幕样式设置

+ +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+
+
diff --git a/frontend/scripts/main.js b/frontend/scripts/main.js index 03bdae0..088ac28 100644 --- a/frontend/scripts/main.js +++ b/frontend/scripts/main.js @@ -56,7 +56,15 @@ const elements = { clearLogBtn: document.getElementById('clearLogBtn'), fullscreenBtn: document.getElementById('fullscreenBtn'), toggleConfigBtn: document.getElementById('toggleConfigBtn'), + toggleCaptionBtn: document.getElementById('toggleCaptionBtn'), toggleLogBtn: document.getElementById('toggleLogBtn'), + applyCaptionStyleBtn: document.getElementById('applyCaptionStyleBtn'), + + captionWidth: document.getElementById('captionWidth'), + captionHeight: document.getElementById('captionHeight'), + captionFontSize: document.getElementById('captionFontSize'), + captionRight: document.getElementById('captionRight'), + captionBottom: document.getElementById('captionBottom'), logLevel: document.getElementById('logLevel'), @@ -73,6 +81,7 @@ const fullscreenState = { const panelState = { configPanel: false, + captionPanel: false, logPanel: false }; @@ -200,6 +209,7 @@ function togglePanel(panelId) { const btnMap = { configPanel: 'toggleConfigBtn', + captionPanel: 'toggleCaptionBtn', logPanel: 'toggleLogBtn' }; @@ -338,6 +348,142 @@ function clearLogs() { logger.info('日志已清空'); } +function applyCaptionStyle() { + const width = elements.captionWidth.value; + const height = elements.captionHeight.value; + const fontSize = elements.captionFontSize.value; + const right = elements.captionRight.value; + const bottom = elements.captionBottom.value; + + const captionContainer = document.querySelector('.caption-container-hub'); + if (!captionContainer) { + logger.warn('字幕容器未找到'); + return; + } + + captionContainer.style.position = 'fixed'; + captionContainer.style.width = `${width}px`; + captionContainer.style.height = `${height}px`; + captionContainer.style.maxHeight = `${height}px`; + captionContainer.style.right = `${right}px`; + captionContainer.style.bottom = `${bottom}px`; + captionContainer.style.fontSize = `${fontSize}px`; + captionContainer.style.borderRadius = '8px'; + captionContainer.style.padding = '10px'; + captionContainer.style.overflowY = 'auto'; + captionContainer.style.cursor = 'move'; + captionContainer.style.userSelect = 'none'; + captionContainer.style.zIndex = '9999'; + + const textElements = captionContainer.querySelectorAll('*'); + textElements.forEach(el => { + el.style.fontSize = `${fontSize}px`; + }); + + initCaptionDragAndResize(captionContainer); + + logger.info('字幕容器样式已应用', { width, height, fontSize, right, bottom }); +} + +function initCaptionDragAndResize(container) { + container.dataset.dragInitialized = 'true'; + + let isDragging = false; + let isResizing = false; + let startX, startY, startRight, startBottom, startWidth, startHeight; + + let resizeHandle = container.querySelector('.caption-resize-handle'); + if (!resizeHandle) { + resizeHandle = document.createElement('div'); + resizeHandle.className = 'caption-resize-handle'; + resizeHandle.style.position = 'absolute'; + resizeHandle.style.right = '0'; + resizeHandle.style.bottom = '0'; + resizeHandle.style.width = '20px'; + resizeHandle.style.height = '20px'; + resizeHandle.style.cursor = 'nwse-resize'; + resizeHandle.style.background = 'linear-gradient(135deg, transparent 50%, rgba(255,255,255,0.5) 50%)'; + resizeHandle.style.borderRadius = '0 0 8px 0'; + resizeHandle.style.zIndex = '10000'; + container.appendChild(resizeHandle); + } + + container.onmousedown = (e) => { + if (e.target === resizeHandle || resizeHandle.contains(e.target)) return; + isDragging = true; + startX = e.clientX; + startY = e.clientY; + const rect = container.getBoundingClientRect(); + startRight = window.innerWidth - rect.right; + startBottom = window.innerHeight - rect.bottom; + e.preventDefault(); + e.stopPropagation(); + }; + + resizeHandle.onmousedown = (e) => { + isResizing = true; + startX = e.clientX; + startY = e.clientY; + startWidth = container.offsetWidth; + startHeight = container.offsetHeight; + e.preventDefault(); + e.stopPropagation(); + }; + + document.onmousemove = (e) => { + if (!isDragging && !isResizing) return; + e.preventDefault(); + + if (isDragging) { + const dx = e.clientX - startX; + const dy = e.clientY - startY; + container.style.right = `${startRight - dx}px`; + container.style.bottom = `${startBottom + dy}px`; + } + if (isResizing) { + const dx = e.clientX - startX; + const dy = e.clientY - startY; + const newWidth = Math.max(200, startWidth + dx); + const newHeight = Math.max(100, startHeight + dy); + container.style.width = `${newWidth}px`; + container.style.height = `${newHeight}px`; + container.style.maxHeight = `${newHeight}px`; + } + }; + + document.onmouseup = () => { + isDragging = false; + isResizing = false; + }; + + logger.info('字幕容器拖拽和缩放已启用'); +} + +function watchCaptionContainer() { + const observer = new MutationObserver((mutations) => { + for (const mutation of mutations) { + if (mutation.type === 'childList') { + const captionContainer = document.querySelector('.caption-container-hub'); + if (captionContainer && !captionContainer.dataset.dragInitialized) { + logger.info('检测到字幕容器,自动启用拖拽功能'); + captionContainer.style.position = 'fixed'; + captionContainer.style.cursor = 'move'; + captionContainer.style.userSelect = 'none'; + captionContainer.style.zIndex = '9999'; + initCaptionDragAndResize(captionContainer); + } + } + } + }); + + observer.observe(document.body, { + childList: true, + subtree: true + }); + + logger.info('已启动字幕容器监听'); +} + function calculateScale() { const container = elements.digitalHumanBox; const sdkContainer = container.querySelector('.digital-intelligent-interaction'); @@ -392,6 +538,7 @@ function bindEvents() { elements.initBtn.addEventListener('click', initializeSDK); elements.destroyBtn.addEventListener('click', destroySDK); elements.getOnceCodeBtn.addEventListener('click', handleGetOnceCode); + elements.applyCaptionStyleBtn.addEventListener('click', applyCaptionStyle); elements.clearLogBtn.addEventListener('click', clearLogs); elements.logLevel.addEventListener('change', () => { @@ -402,6 +549,7 @@ function bindEvents() { }); elements.toggleConfigBtn.addEventListener('click', () => togglePanel('configPanel')); + elements.toggleCaptionBtn.addEventListener('click', () => togglePanel('captionPanel')); elements.toggleLogBtn.addEventListener('click', () => togglePanel('logPanel')); elements.fullscreenBtn.addEventListener('click', toggleFullscreen); @@ -434,6 +582,7 @@ function init() { bindEvents(); updateUIState(); initScaling(); + watchCaptionContainer(); } init(); diff --git a/frontend/styles/main.css b/frontend/styles/main.css index 14c17f1..a7e30b1 100644 --- a/frontend/styles/main.css +++ b/frontend/styles/main.css @@ -333,6 +333,13 @@ body { } /* ===== 对话控制面板 ===== */ +/* ===== 字幕样式面板 ===== */ +.caption-panel { + bottom: calc(var(--spacing-xl) + 60px); + right: var(--spacing-xl); + width: 320px; +} + /* ===== 日志面板 ===== */ .log-panel { bottom: calc(var(--spacing-xl) + 60px);