v2.4: 网页版适配 Odoo 网站嵌入

- URL 深度链接:?series= 打开系列 / ?model= 定位型号 / ?embed=1 隐藏自身顶栏 / ?nav=0 隐藏侧边栏 / ?lang= 切语言
- 路径自适应:VIEWER_BASE 与模型路径从 location.pathname 推导,支持子路径部署(原来硬编码 /viewer/ 和 /step/ 会在子路径下 404)
- embed 模式样式:隐藏 header/footer,让 iframe 内更干净
- 手册页图片点击放大:全屏弹窗,← → 翻页,Esc/点遮罩关闭
- 数据表 PDF 弹窗预览:原为直接下载,改为内联预览(弹窗内保留下载入口)
- 数据表按钮加内联 SVG 图标(PDF + 放大镜),区别于纯下载按钮
- 隐藏「返回系列总览」按钮(嵌入模式下属多余)

注:本次改动服务于 OneBot 官网产品页的选型 tab 嵌入。

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
wangruiguo
2026-09-17 02:57:34 +08:00
parent e030b65104
commit f343b26444
3 changed files with 379 additions and 27 deletions

View File

@@ -265,7 +265,16 @@ main { flex: 1; display: flex; min-height: 0; }
.param-row select:focus, .param-input:focus {
border-color: var(--primary-500); box-shadow: 0 0 0 3px rgba(20,184,166,.15);
}
#actions { margin-top: 16px; display: flex; gap: 8px; flex-wrap: wrap; }
/* #actions 原在左侧参数面板底部,现移到 tab 行右侧(与 3D/尺寸图 等同一行)。
元素 id 未变,JS 按 id 取用,位置移动不影响逻辑。 */
#actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
/* tab 行的弹性占位:把 #actions 推到最右 */
.tabs-spacer { flex: 1; min-width: 8px; }
/* 窄屏时按钮换行到下一行,避免挤压 tab */
@media (max-width: 1100px) {
.tabs { flex-wrap: wrap; }
.tabs-spacer { flex-basis: 100%; height: 0; }
}
/* ============================================================ 零件号实时条 (DESTACO 风)
* 边选边拼: 已确定部分实心高亮, 未定部分虚化占位。 */
@@ -387,10 +396,114 @@ main { flex: 1; display: flex; min-height: 0; }
.hidden { display: none !important; }
/* ------------------------------------------------------------ 嵌入模式
供 Odoo 产品页 iframe 使用 (?embed=1):隐藏工具自身的顶栏与底栏,
避免在网站页面里出现"页中页",同时把高度让给内容区。
由 app.js 的 applyDeepLink() 给 body 加 .embed-mode 触发。 */
body.embed-mode header,
body.embed-mode footer { display: none !important; }
body.embed-mode { height: 100vh; }
/* 隐藏模式 (?nav=0):嵌入 Odoo 产品页时用。
产品页已经决定了是哪个系列,左侧系列树、分隔条、「返回系列总览」纯属多余,
隐藏后让参数面板 + 内容区铺满整宽,观感更干净。 */
body.nav-off #tree,
body.nav-off #split1,
body.nav-off .content-back { display: none !important; }
/* 隐藏侧栏后,参数面板适当加宽(原来 330px 是因为旁边还有树+主区抢空间) */
body.nav-off .params { width: 300px; }
/* ------------------------------------------------------------ 内容区 / 标签页 */
.content { flex: 1; display: flex; flex-direction: column; min-width: 0; padding: 14px; }
.tabs { display: flex; gap: 6px; flex: none; }
.tabs { display: flex; gap: 6px; flex: none; align-items: center; }
.content-back { flex: none; margin: 10px 0 0; }
/* ------------------------------------------------------------ 手册页图片放大
点击手册页图片 → 全屏遮罩显示大图。点遮罩任意处 / 按 Esc 关闭。
用 position:fixed 覆盖整个视口(含 iframe 内嵌场景)。 */
.manual-img { cursor: zoom-in; }
/* 数据表按钮图标(内联 SVG,工具无图标字体) */
.ds-ico { width: 15px; height: 15px; flex: none; vertical-align: -3px; }
.ds-ico-eye { opacity: .65; }
#btnDatasheet { display: inline-flex; align-items: center; gap: 6px; }
#btnDatasheet:hover .ds-ico-eye { opacity: 1; }
#btnDatasheet .ds-txt { white-space: nowrap; }
.img-zoom-overlay {
position: fixed; inset: 0; z-index: 900;
background: rgba(17, 24, 39, .88);
display: flex; align-items: center; justify-content: center;
padding: 24px; cursor: zoom-out;
animation: imgZoomIn .16s ease-out;
}
@keyframes imgZoomIn { from { opacity: 0; } to { opacity: 1; } }
.img-zoom-overlay img {
max-width: 100%; max-height: 100%;
object-fit: contain; border-radius: 6px;
box-shadow: 0 12px 48px rgba(0, 0, 0, .5);
}
.img-zoom-close {
position: absolute; top: 14px; right: 18px;
width: 40px; height: 40px; border: 0; border-radius: 50%;
background: rgba(255, 255, 255, .16); color: #fff;
font-size: 22px; line-height: 1; cursor: pointer;
display: flex; align-items: center; justify-content: center;
transition: background .18s;
}
.img-zoom-close:hover { background: rgba(255, 255, 255, .3); }
.img-zoom-cap {
position: absolute; bottom: 14px; left: 0; right: 0;
text-align: center; color: rgba(255, 255, 255, .75); font-size: 12.5px;
pointer-events: none;
}
/* ------------------------------------------------------------ 数据表 PDF 弹窗预览
点击「数据表」→ 弹窗内用浏览器内置 PDF 阅读器打开,标题栏含下载入口。 */
.pdf-zoom-overlay {
position: fixed; inset: 0; z-index: 910;
background: rgba(17, 24, 39, .72);
display: flex; align-items: center; justify-content: center;
padding: 24px;
animation: imgZoomIn .16s ease-out;
}
.pdf-zoom-box {
width: min(1100px, 100%); height: min(92vh, 100%);
display: flex; flex-direction: column;
background: var(--surface, #fff);
border-radius: 10px; overflow: hidden;
box-shadow: 0 16px 56px rgba(0, 0, 0, .45);
}
.pdf-zoom-head {
flex: none; display: flex; align-items: center; gap: 12px;
padding: 10px 12px 10px 16px;
border-bottom: 1px solid var(--border, #e5e7eb);
background: var(--surface, #fff);
}
.pdf-zoom-title {
flex: 1; font-size: 13px; font-weight: 600; color: var(--gray-900, #111827);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pdf-zoom-dl {
flex: none; font-size: 12.5px; text-decoration: none;
padding: 6px 14px; border-radius: 6px;
background: var(--primary, #14b8a6); color: #fff;
transition: filter .18s;
}
.pdf-zoom-dl:hover { filter: brightness(.94); }
.pdf-zoom-close {
position: static; flex: none;
width: 32px; height: 32px; font-size: 18px;
background: var(--gray-100, #f3f4f6); color: var(--gray-700, #374151);
}
.pdf-zoom-close:hover { background: var(--gray-200, #e5e7eb); }
.pdf-zoom-frame {
flex: 1; width: 100%; border: 0; background: #525659;
}
@media (max-width: 767.98px) {
.pdf-zoom-overlay { padding: 0; }
.pdf-zoom-box { width: 100%; height: 100%; border-radius: 0; }
}
.tab {
height: 36px; padding: 0 16px; border: 1px solid var(--border);
border-radius: var(--radius-sm); background: var(--surface);