# -*- coding: utf-8 -*- r'''官网的"产品展示"部分:手表界面 mockup + 连接方式示意。 为什么用 HTML/CSS 画手表界面,而不是放截图: * 手表是安卓设备,没有真机/模拟器就拍不到界面 * CSS 画的图在任何屏幕上都是清晰的(截图放大会糊) * 用的颜色和布局**直接从 MainActivity.java 抄**, 所以不是"想象的样子",是真实界面 手表真实参数(android/.../MainActivity.java): C_BG = 0xFFF5F7FA 页面底色(浅灰) C_FG = 0xFF1F2328 主文字(近黑) C_ACCENT = 0xFF185CE8 强调蓝 C_DIM = 0xFF656D76 次要文字 十个分页:媒体 屏幕 文件 语音 电脑 网络 系统 教室 效率 娱乐 ''' from __future__ import annotations # 和手表代码一致的颜色 W_BG = "#F5F7FA" W_FG = "#1F2328" W_ACCENT = "#185CE8" W_DIM = "#656D76" W_CARD = "#FFFFFF" W_BORDER = "#E3E7ED" TABS = ["媒体", "屏幕", "文件", "语音", "电脑", "网络", "系统", "教室", "效率", "娱乐"] # "媒体"分页的真实操作(从 TabDef 抄的) MEDIA_ACTIONS = [ ("放音频", "🔊"), ("放视频", "▶"), ("暂停", "⏸"), ("继续", "⏵"), ("音量 +", "+"), ("音量 −", "−"), ("静音", "🔇"), ("下一首", "⏭"), ("投图到屏幕", "🖼"), ] # "教室"分页(老师的核心场景) CLASSROOM_ACTIONS = [ ("上课:开投影", "📽"), ("打开课件", "📂"), ("课堂专注", "🎯"), ("恢复桌面", "↩"), ("看屏幕", "👁"), ("下课关机", "⏻"), ] TAB_ACTIONS = {"媒体": MEDIA_ACTIONS, "教室": CLASSROOM_ACTIONS} def _watch_card(active_tab: str) -> str: """画一个手表界面。active_tab 决定显示哪个分页的内容。""" actions = TAB_ACTIONS.get(active_tab, MEDIA_ACTIONS) # 顶部标签条 tabs = [] for name in TABS: on = name == active_tab tabs.append( '%s' % (" on" if on else "", name)) tabs_html = "".join(tabs) # 操作网格 buttons = [] for label, icon in actions: buttons.append( '
%s' '%s
' % (icon, label)) grid_html = "".join(buttons) return ( '
' '
' '
ykxmz' '● 局域网 3 ms
' '
%s
' '
' '
%s
' '
%s
' '
' '
被控端:教室电脑 · 192.168.2.64
' '
' % (tabs_html, active_tab, grid_html) ) def _pc_card() -> str: """电脑端 —— 用真实截图(_build/site_shots/pc-main.png)。""" return ( '
' 'ykxmz 电脑端首次设置界面' '
电脑端:装完填个 6 位配对码就行
' '
' ) def _flow_diagram() -> str: """连接方式示意:局域网直连 vs 跨网络走中转。""" return '''
同一个 WiFi
⌚手表
🖥教室电脑

直连,不经过任何服务器。几十毫秒,画面基本跟手。

不在同一个网络
⌚手表
☁中转
🖥电脑

两边都主动连到中转,绕过 NAT。办公室也能管教室。

''' def render_showcase() -> str: """整个"产品展示"区块。""" return '''

长什么样

手表上十个分页,常用操作都在第一屏

%(watch)s %(pc)s

怎么连上的

同一个 WiFi 就走局域网直连,不同网络自动切中转

%(flow)s
''' % {"watch": _watch_card("媒体"), "pc": _pc_card(), "flow": _flow_diagram()} SHOWCASE_CSS = """ /* ---------- 产品展示 ---------- */ .showcase{display:grid;gap:34px;align-items:start; justify-items:center} @media(min-width:820px){.showcase{grid-template-columns:1fr 1fr}} /* 手表 mockup。尺寸按真实手表屏幕比例 */ .watch{width:300px;padding:10px;border-radius:34px; background:linear-gradient(160deg,#2b3038,#14171c); box-shadow:0 18px 40px rgba(16,24,40,.18); position:relative} .watch::after{content:'';position:absolute;right:-3px;top:110px; width:5px;height:44px;border-radius:3px;background:#3a4048} .w-screen{background:%(W_BG)s;border-radius:26px;overflow:hidden; font-size:11px;color:%(W_FG)s} .w-status{display:flex;justify-content:space-between;align-items:center; padding:11px 12px 7px;font-size:9px;font-weight:600; gap:6px;white-space:nowrap} .w-conn{color:#16a34a;font-weight:600} .w-tabs{display:flex;gap:4px;overflow:hidden;padding:0 11px 8px; border-bottom:1px solid %(W_BORDER)s} .w-tab{flex:none;padding:3px 8px;border-radius:999px;color:%(W_DIM)s; font-size:10px;white-space:nowrap} .w-tab.on{background:%(W_ACCENT)s;color:#fff;font-weight:600} .w-body{padding:12px 13px 14px} .w-head{font-size:12px;font-weight:700;margin-bottom:10px} .w-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:7px} .w-btn{background:%(W_CARD)s;border:1px solid %(W_BORDER)s; border-radius:11px;padding:11px 4px 9px;text-align:center; display:flex;flex-direction:column;align-items:center;gap:5px} .w-ic{font-size:15px;line-height:1} .w-lb{font-size:9px;color:%(W_FG)s;white-space:nowrap} .w-foot{padding:9px 13px 12px;color:%(W_DIM)s;font-size:9px; border-top:1px solid %(W_BORDER)s} /* 电脑端截图 */ .pcshot{margin:0;text-align:center} .pcshot img{width:100%%;max-width:352px;height:auto; border-radius:10px;display:block;margin:0 auto; box-shadow:0 18px 40px rgba(16,24,40,.16)} .pcshot{padding:14px;background:#f2f4f7;border-radius:16px; border:1px solid %(W_BORDER)s} .pcshot figcaption{margin-top:14px;color:%(W_DIM)s;font-size:13px} /* 连接方式示意 */ .flow{display:grid;gap:18px} @media(min-width:760px){.flow{grid-template-columns:1fr 1fr}} .flow-col{border:1px solid #e6e8eb;border-radius:14px;padding:24px 20px; background:#fafbfc} .flow-tag{display:inline-block;padding:3px 11px;border-radius:999px; font-size:12px;font-weight:600;margin-bottom:20px} .flow-tag.ok{background:#dcfce7;color:#15803d} .flow-tag.warn{background:#fef3c7;color:#a16207} .flow-row{display:flex;align-items:center;justify-content:center; gap:2px;margin-bottom:16px;flex-wrap:nowrap} .node{display:flex;flex-direction:column;align-items:center;gap:6px; font-size:26px;flex:none;width:64px} .node span{font-size:12px;color:#4b5563;font-weight:500} .node.relay{font-size:24px} .link{flex:1;min-width:16px;position:relative;display:flex; align-items:center;justify-content:center} .link .line{width:100%%;height:2px;background:#c7cdd6; border-radius:2px} .link .ms{position:absolute;top:-15px;font-size:10px;color:#15803d; font-weight:600;white-space:nowrap} .flow-col p{color:#6b7280;font-size:13px;line-height:1.7;margin:0} """ % {"W_BG": W_BG, "W_FG": W_FG, "W_ACCENT": W_ACCENT, "W_DIM": W_DIM, "W_CARD": W_CARD, "W_BORDER": W_BORDER}