From 0e8fc4ebe00a851b1d1de8d608811ce31430fb9c Mon Sep 17 00:00:00 2001 From: R524809 Date: Wed, 26 Aug 2026 17:38:18 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=87=87=E9=9B=86=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extension/entrypoints/panel.content.ts | 41 +++++++++++++++++++++++-- extension/entrypoints/sidepanel/App.tsx | 8 ++--- server/services/watermark.py | 4 +-- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/extension/entrypoints/panel.content.ts b/extension/entrypoints/panel.content.ts index 03b7074..5fde150 100644 --- a/extension/entrypoints/panel.content.ts +++ b/extension/entrypoints/panel.content.ts @@ -33,6 +33,32 @@ const STYLES = ` .fab:hover { transform: scale(1.08); } .fab.hidden { display: none; } + /* 收起按钮:骑在面板左上边缘(一半在面板外)。必须在 iframe 外渲染—— + iframe 裁剪内容,iframe 内的元素永远溢不出面板边界 */ + .panel-close { + position: fixed; + top: 20px; + right: min(880px, 100vw); /* 面板左边缘 = 视口右沿 - 面板宽度 */ + transform: translateX(50%); + width: 28px; + height: 28px; + border-radius: 50%; + border: 1px solid rgba(0, 0, 0, 0.12); + background: #fff; + color: #555; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.18); + z-index: 4; + opacity: 0; + pointer-events: none; + transition: opacity 0.25s ease, transform 0.15s ease; + } + .panel-close.visible { opacity: 1; pointer-events: auto; } + .panel-close:hover { color: #6d28d9; border-color: #6d28d9; transform: translateX(50%) scale(1.08); } + .panel { position: fixed; top: 0; @@ -92,23 +118,34 @@ export default defineContentScript({ const iframe = document.createElement('iframe'); iframe.title = '电商套图工作台'; panel.append(iframe); - container.append(fab, panel); + + // 外置收起按钮(骑在面板左上边缘,一半在面板外) + const closeBtn = document.createElement('button'); + closeBtn.className = 'panel-close'; + closeBtn.title = '收起面板(Esc)'; + closeBtn.innerHTML = + '' + + ''; + container.append(fab, panel, closeBtn); const open = () => { if (!iframe.src) iframe.src = chrome.runtime.getURL('/sidepanel.html'); panel.classList.add('open'); + closeBtn.classList.add('visible'); fab.classList.add('hidden'); // 聚焦进面板,键盘操作(Esc 关闭 / 预览翻页)直接可用 iframe.focus(); }; const close = () => { panel.classList.remove('open'); + closeBtn.classList.remove('visible'); if (isProductPage()) fab.classList.remove('hidden'); }; fab.addEventListener('click', open); + closeBtn.addEventListener('click', close); - // 面板内 App(✕ / Esc)→ 收起 + // 面板内 App(Esc)→ 收起;✕ 按钮已外置到宿主层(closeBtn) window.addEventListener('message', (e) => { if (e.source === iframe.contentWindow && (e.data as any)?.type === PANEL_CLOSE_MSG) close(); }); diff --git a/extension/entrypoints/sidepanel/App.tsx b/extension/entrypoints/sidepanel/App.tsx index e0bc1b4..da6ee6e 100644 --- a/extension/entrypoints/sidepanel/App.tsx +++ b/extension/entrypoints/sidepanel/App.tsx @@ -11,7 +11,7 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import { createRoot } from 'react-dom/client'; import { App as AntApp, ConfigProvider, Popover, Progress, Select } from 'antd'; -import { SettingOutlined, DownloadOutlined, ThunderboltOutlined, UploadOutlined, CloseOutlined } from '@ant-design/icons'; +import { SettingOutlined, DownloadOutlined, ThunderboltOutlined, UploadOutlined } from '@ant-design/icons'; import type { ScanResult, ImageMaterial } from '../../src/collector/scan'; import { cleanFilename } from '../../src/collector/url'; import { @@ -671,11 +671,9 @@ const App: React.FC = () => { return (
- {/* ── 顶栏 ── */} + {/* ── 顶栏 ──(页内模式的收起 ✕ 按钮在宿主层渲染:要骑在面板边缘、一半在面板外, + iframe 会裁剪内容,按钮必须在 iframe 外;Esc 关闭仍走 closePanel) */}
- {IN_PAGE && ( - - )}

电商套图工作台

diff --git a/server/services/watermark.py b/server/services/watermark.py index 1eb1bde..447214c 100644 --- a/server/services/watermark.py +++ b/server/services/watermark.py @@ -18,8 +18,8 @@ from config import get_settings log = logging.getLogger("suite.watermark") -# 尺寸比例(与 ozonSeller app.js 常量一致) -BADGE_SCALE = 0.15 # 图片水印直径 / 图宽 +# 尺寸比例(BADGE_SCALE 在 ozonSeller 的 0.15 基础上缩小 30%:用户反馈偏大) +BADGE_SCALE = 0.105 # 图片水印直径 / 图宽 BADGE_MARGIN = 0.01 # 图片水印边距 / 图宽(ozonSeller 固定 10px,按比例更稳) TEXT_SCALE = 0.06 # 文字字号 / 图宽 TEXT_MIN_SIZE = 12