Files
pangolin/docs/contact-telegram-channels-design.html
wangjia 14bcdc2e79 docs(contact): 落定渠道二级页设计 —— 统一单表 + LINE 灰置
拍板:不展示成员数;群组=「加入」其余=「打开」;独立 GET /v1/contact;
全渠道(Telegram/LINE/邮箱/发卡)统一一张 contact_link 表,靠 url 协议区分
(mailto:/https:/tg://),邮箱=kind=link+mailto。L1 平台图标/名/强调色由前端
platform 注册表内置(唯一不入库的皮)。LINE 也做二级、同构,但先灰置「即将开放」
(registry comingSoon=[line],配好去灰即用)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 12:30:24 +08:00

338 lines
23 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>联系我们:渠道二级页(Telegram 频道/群组,DB 配置)· 交互设计</title>
<style>
:root{
--bg:#0f1117; --panel:#171a22; --panel2:#1d2129; --fg:#e6e8ee; --fg2:#a8afbd;
--accent:#e0884f; --accent2:#5fb0c9; --ok:#5ec27a; --bad:#e06a6a; --warn:#e0b84f;
--border:#272c36; --mono:"SF Mono",ui-monospace,Menlo,Consolas,monospace;
--sans:-apple-system,"PingFang SC","Helvetica Neue",Arial,sans-serif;
}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--fg);font-family:var(--sans);line-height:1.7;font-size:15px}
.wrap{max-width:960px;margin:0 auto;padding:48px 24px 96px}
h1{font-size:30px;line-height:1.3;margin:0 0 8px;letter-spacing:-.01em}
.sub{color:var(--fg2);font-size:15px;margin:0 0 32px}
h2{font-size:21px;margin:44px 0 14px;padding-bottom:8px;border-bottom:1px solid var(--border)}
h3{font-size:16px;margin:26px 0 8px;color:var(--accent2)}
p{margin:10px 0}
code{font-family:var(--mono);font-size:.88em;background:var(--panel2);padding:1px 6px;border-radius:5px;color:#f0d9c4}
pre{background:#0a0c11;border:1px solid var(--border);border-radius:10px;padding:14px 16px;overflow-x:auto;font-family:var(--mono);font-size:13px;line-height:1.55;color:#cdd3df}
.tag{display:inline-block;font-size:12px;font-weight:600;padding:2px 9px;border-radius:999px;vertical-align:middle}
.tag.ok{background:rgba(94,194,122,.16);color:var(--ok)}
.tag.warn{background:rgba(224,184,79,.16);color:var(--warn)}
.tag.info{background:rgba(95,176,201,.16);color:var(--accent2)}
.card{background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:18px 20px;margin:16px 0}
.card.root{border-left:3px solid var(--accent)}
.card h3{margin-top:0}
table{width:100%;border-collapse:collapse;margin:16px 0;font-size:14px}
th,td{text-align:left;padding:9px 12px;border-bottom:1px solid var(--border);vertical-align:top}
th{color:var(--fg2);font-weight:600;font-size:13px}
td code{font-size:.85em}
ul,ol{padding-left:22px;margin:10px 0}
li{margin:5px 0}
.lead{background:linear-gradient(180deg,rgba(224,136,79,.10),transparent);border:1px solid var(--border);border-radius:12px;padding:18px 20px;margin:0 0 8px}
.small{color:var(--fg2);font-size:13px}
a{color:var(--accent2)}
.back{display:inline-block;margin-bottom:24px;font-size:13px}
b{color:#fff}
/* ── 交互原型:用真实 App 暗色 token(design/colors_and_type.css [data-theme=dark])──*/
.proto{
--p-bg:#14110E; --p-bg-subtle:#1F1C18; --p-surface:#221E19; --p-surface2:#2A251F;
--p-fg1:#F4EFE8; --p-fg2:#B6AC9C; --p-fg3:#897F6F; --p-fg-on-accent:#1F1C18;
--p-accent:#CC8B5C; --p-accent-hover:#D9A982; --p-accent-subtle:rgba(204,139,92,.14);
--p-accent-border:rgba(204,139,92,.30);
--p-border:rgba(242,238,231,.10); --p-border-strong:rgba(242,238,231,.18);
--p-green:#7FB07A;
background:var(--p-bg);border:1px solid var(--border);border-radius:14px;overflow:hidden;
display:flex;height:520px;margin:18px 0;font-size:14px;
}
.proto *{box-sizing:border-box}
/* sidebar */
.p-side{width:190px;flex:none;background:var(--p-bg);border-right:1px solid var(--p-border);padding:18px 14px;display:flex;flex-direction:column;gap:4px}
.p-brand{display:flex;align-items:center;gap:10px;padding:4px 8px 18px}
.p-logo{width:30px;height:30px;border-radius:8px;background:var(--p-accent-subtle);display:flex;align-items:center;justify-content:center;color:var(--p-accent);font-size:16px}
.p-brand b{color:var(--p-fg1);font-size:16px;line-height:1.1}
.p-brand span{display:block;color:var(--p-fg3);font-size:9px;letter-spacing:2px}
.p-nav{display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:9px;color:var(--p-fg2);cursor:default}
.p-nav .ic{width:17px;text-align:center;opacity:.85}
.p-nav.active{background:var(--p-accent-subtle);color:var(--p-accent);font-weight:600}
/* main */
.p-main{flex:1;display:flex;flex-direction:column;min-width:0}
.p-top{display:flex;align-items:center;gap:12px;padding:16px 22px;border-bottom:1px solid var(--p-border)}
.p-top .ttl{font-size:19px;font-weight:700;color:var(--p-fg1)}
.p-top .rt{margin-left:auto;display:flex;align-items:center;gap:14px;color:var(--p-fg2);font-size:12px}
.p-dot{width:7px;height:7px;border-radius:50%;background:var(--p-green);display:inline-block;margin-right:5px}
.p-body{padding:20px 22px;overflow-y:auto}
.p-intro{color:var(--p-fg2);font-size:13.5px;margin:0 0 14px}
/* channel / item cards */
.p-card{display:flex;align-items:center;gap:13px;padding:13px 15px;background:var(--p-surface);border:1px solid var(--p-border);border-radius:13px;margin-bottom:10px;cursor:pointer;transition:border-color .12s,background .12s}
.p-card:hover{border-color:var(--p-accent-border);background:var(--p-surface2)}
.p-ic{width:38px;height:38px;flex:none;border-radius:10px;background:var(--p-bg-subtle);display:flex;align-items:center;justify-content:center;font-size:18px;color:var(--p-fg2)}
.p-ic.accent{background:var(--p-accent-subtle);color:var(--p-accent)}
.p-tx{flex:1;min-width:0}
.p-tx .nm{color:var(--p-fg1);font-weight:600;font-size:14.5px;display:flex;align-items:center;gap:6px}
.p-tx .sb{color:var(--p-fg3);font-size:12.5px;margin-top:1px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.p-chev{color:var(--p-fg3);font-size:17px;flex:none}
.p-verify{color:var(--p-accent);font-size:12px}
.p-count{color:var(--p-fg3);font-size:11.5px;flex:none;display:flex;align-items:center;gap:4px}
.p-btn{flex:none;font-size:12.5px;font-weight:600;padding:6px 15px;border-radius:8px;border:1px solid var(--p-accent-border);color:var(--p-accent);background:transparent}
.p-btn.solid{background:var(--p-accent);color:var(--p-fg-on-accent);border-color:transparent}
.p-sechd{color:var(--p-fg3);font-size:11px;font-weight:700;letter-spacing:1.4px;margin:18px 2px 9px}
.p-back{display:inline-flex;align-items:center;gap:8px;color:var(--p-fg2);font-size:13px;cursor:pointer;padding:2px 0;margin-bottom:2px}
.p-back:hover{color:var(--p-fg1)}
.p-detail-hd{display:flex;align-items:center;gap:12px;margin:6px 0 4px}
.p-detail-hd .p-ic{width:44px;height:44px;font-size:21px}
.p-detail-hd .nm{font-size:18px;font-weight:700;color:var(--p-fg1)}
.p-detail-hd .sb{color:var(--p-fg3);font-size:12.5px}
.hide{display:none!important}
.p-card.disabled{opacity:.5;cursor:not-allowed}
.p-card.disabled:hover{border-color:var(--p-border);background:var(--p-surface)}
.p-soon{font-size:10px;font-weight:600;padding:1px 7px;border-radius:999px;background:var(--p-bg-subtle);color:var(--p-fg3);border:1px solid var(--p-border)}
.flag{margin-left:auto;color:var(--p-fg3);font-size:12px}
.toggles{display:flex;gap:8px;margin:10px 0 2px}
.toggles button{background:var(--panel2);color:var(--fg2);border:1px solid var(--border);border-radius:8px;padding:6px 12px;font-size:13px;cursor:pointer}
.toggles button:hover{color:var(--fg)}
.capt{color:var(--fg2);font-size:12.5px;text-align:center;margin-top:-4px}
</style>
</head>
<body>
<div class="wrap">
<a class="back" href="index.html">← 返回文档索引</a>
<h1>联系我们 · 渠道二级页</h1>
<p class="sub">交互设计 · Telegram/LINE 多频道 · 群组 · 内容 DB 配置 · <span class="tag info">前端 + 后端 + 数据库</span></p>
<div class="lead">
现「联系我们」把每个渠道当<b>单一入口</b>Telegram 只挂一个 <code>@PangolinVPN_bot</code>)。
需求:点 Telegram 进入<b>二级页</b>,列出该平台下的<b>多个频道 / 群组 / Bot</b>
每项含名称、@handle、一句说明、可选成员数、认证标记与「打开 / 加入」动作,
<b>全部由数据库配置</b>(运营可随时增删改,客户端不写死)。本页给出交互原型 + 数据模型 + 接口,待你统一后再开发。
</div>
<h2>可点原型(点 Telegram 卡片进二级,← 返回)</h2>
<p class="small">下方为内嵌可交互原型,配色用 App 真实暗色 tokenclay/espresso)。点 <b>Telegram</b><b>LINE</b> 卡进详情;「邮箱客服 / 自助发卡商店」为单链接,点即直接打开(原型里仅提示)。</p>
<div class="proto" id="proto">
<!-- sidebar -->
<div class="p-side">
<div class="p-brand"><div class="p-logo">🐾</div><div><b>穿山甲</b><span>PANGOLIN</span></div></div>
<div class="p-nav"><span class="ic"></span>连接</div>
<div class="p-nav"><span class="ic">🌐</span>节点</div>
<div class="p-nav"><span class="ic">📊</span>统计</div>
<div class="p-nav"><span class="ic"></span>设置</div>
<div class="p-nav active"><span class="ic">💬</span>联系我们</div>
</div>
<!-- main -->
<div class="p-main">
<div class="p-top">
<span class="ttl" id="p-title">联系我们</span>
<span class="rt"><span><span class="p-dot"></span>US</span><span>🌙</span></span>
</div>
<!-- L1: channel list -->
<div class="p-body" id="view-l1">
<p class="p-intro">遇到问题?通过以下任一渠道联系我们,通常数分钟内回复。</p>
<div class="p-card" onclick="showTg()">
<div class="p-ic accent"></div>
<div class="p-tx"><div class="nm">Telegram</div><div class="sb">官方频道 · 交流群 · 客服 Bot</div></div>
<span class="p-chev"></span>
</div>
<div class="p-card disabled" title="即将开放,先灰置">
<div class="p-ic">💬</div>
<div class="p-tx"><div class="nm">LINE <span class="p-soon">即将开放</span></div><div class="sb">官方账号 · 中文/日文群</div></div>
<span class="p-chev"></span>
</div>
<div class="p-card" title="单链接:直接打开邮件">
<div class="p-ic"></div>
<div class="p-tx"><div class="nm">邮箱客服</div><div class="sb">support@pangolin.vpn</div></div>
<span class="p-chev"></span>
</div>
<div class="p-card" title="单链接:直接打开商店">
<div class="p-ic">🛍</div>
<div class="p-tx"><div class="nm">自助发卡商店</div><div class="sb">shop.pangolin.vpn</div></div>
<span class="p-chev"></span>
</div>
</div>
<!-- L2: Telegram detail -->
<div class="p-body hide" id="view-tg">
<div class="p-back" onclick="showList()"> 返回</div>
<div class="p-detail-hd">
<div class="p-ic accent"></div>
<div><div class="nm">Telegram</div><div class="sb">加入官方频道获取更新,进群与用户互助</div></div>
</div>
<div class="p-sechd">频道 · CHANNELS</div>
<div class="p-card">
<div class="p-ic accent">📣</div>
<div class="p-tx"><div class="nm">穿山甲 · 官方频道 <span class="p-verify"></span></div><div class="sb">产品更新与公告 · @PangolinVPN</div></div>
<button class="p-btn">打开</button>
</div>
<div class="p-card">
<div class="p-ic accent">📶</div>
<div class="p-tx"><div class="nm">穿山甲 · 节点状态</div><div class="sb">节点/故障实时播报 · @PangolinStatus</div></div>
<button class="p-btn">打开</button>
</div>
<div class="p-sechd">群组 · GROUPS</div>
<div class="p-card">
<div class="p-ic">👥</div>
<div class="p-tx"><div class="nm">穿山甲 · 用户交流群</div><div class="sb">使用问题互助交流 · @PangolinChat</div></div>
<button class="p-btn solid">加入</button>
</div>
<div class="p-card">
<div class="p-ic">🌏</div>
<div class="p-tx"><div class="nm">Pangolin · English Group</div><div class="sb">English support &amp; chat · @PangolinEN</div></div>
<button class="p-btn solid">加入</button>
</div>
<div class="p-sechd">客服机器人 · BOT</div>
<div class="p-card">
<div class="p-ic accent">🤖</div>
<div class="p-tx"><div class="nm">客服机器人</div><div class="sb">自动答疑 / 提交工单 · @PangolinVPN_bot</div></div>
<button class="p-btn">打开</button>
</div>
</div>
<!-- L2: LINE detail (示意同构) -->
<div class="p-body hide" id="view-line">
<div class="p-back" onclick="showList()"> 返回</div>
<div class="p-detail-hd">
<div class="p-ic">💬</div>
<div><div class="nm">LINE</div><div class="sb">官方账号与交流群</div></div>
</div>
<div class="p-sechd">官方账号 · OFFICIAL</div>
<div class="p-card">
<div class="p-ic">💬</div>
<div class="p-tx"><div class="nm">Pangolin 官方账号 <span class="p-verify"></span></div><div class="sb">公告与客服 · @pangolinvpn</div></div>
<button class="p-btn">打开</button>
</div>
<div class="p-sechd">群组 · GROUPS</div>
<div class="p-card">
<div class="p-ic">👥</div>
<div class="p-tx"><div class="nm">中文交流群</div><div class="sb">使用互助 · openchat</div></div>
<button class="p-btn solid">加入</button>
</div>
</div>
</div>
</div>
<div class="toggles">
<button onclick="showList()">L1 渠道列表</button>
<button onclick="showTg()">L2 · Telegram</button>
<button onclick="showLine()">L2 · LINE(预留结构预览)</button>
</div>
<p class="capt">同一原型内切换三态 · 真机为路由 push(移动端整页)/ 内容区替换(桌面)。
L1 上 LINE 为<b>灰置「即将开放」不可点</b>;「L2 · LINE」按钮仅用于预览其<b>预留的二级结构</b>(去灰后即此样式)。</p>
<h2>交互规则</h2>
<ul>
<li><b>进入二级的条件</b>:某平台配置了 <b>&gt;1 条</b>链接 → 卡片带 <code></code>,点击进二级页(Telegram / LINE)。
<b>1 条</b>链接的平台(邮箱、发卡商店)→ 点击<b>直接执行该链接动作</b>(打开邮件 / 浏览器),不进二级。
规则统一由「该平台 link 条数」驱动,无需前端写死哪个进二级。</li>
<li><b>二级页结构</b>:顶部 <code> 返回</code> + 平台头(图标 + 名 + 一句副标题);下方按 <b>kind 分组</b>展示
——<code>频道 CHANNELS</code> / <code>群组 GROUPS</code> / <code>客服机器人 BOT</code>(分组标题仅在该组有内容时出现,顺序固定)。</li>
<li><b>每一项</b>:图标/头像 · 标题(可带 <span class="p-verify" style="color:var(--accent)"></span> 认证)· 一句说明 + <code>@handle</code> ·
可选成员数(<b>展示用缓存文本</b>,不实时拉 Telegram)· 动作按钮。</li>
<li><b>动作</b>:频道/Bot → 「打开」(描边按钮);群组 → 「加入」(实心强调按钮)。点按钮或点整行都触发。
优先 <code>tg://resolve?domain=…</code> 唤起已装 Telegram,失败回退 <code>https://t.me/…</code>(浏览器)。</li>
<li><b>桌面 vs 移动</b>:桌面在右侧内容区做<b>视图替换</b>(标题栏文案随之切到「Telegram」,← 返回回列表);
移动端为<b>整页 push 路由</b>,系统返回手势/返回键回列表。两端同一份数据与卡片组件。</li>
<li><b>空/禁用</b>:某平台所有 link <code>enabled=0</code>(或库里无该平台行)→ 默认 L1 <b>不展示</b>该平台;二级页某分组为空 → 不渲染该分组标题。</li>
<li><b>「即将开放」灰置</b>:前端 platform 注册表有一个 <code>comingSoon</code> 列表(当前 = <code>[line]</code>)。列在其中且<b>暂无 enabled 链接</b>的平台,L1 <b>置灰 + 「即将开放」角标、不可点进</b>(占位预告,不隐藏)。
运营在库里配好该平台链接后,从 <code>comingSoon</code> 列表移除该项(一行代码)→ 自动变可点二级页。LINE 即走此路:结构与 Telegram 同构,先灰、内容就绪即上。</li>
</ul>
<h2>数据模型(DB 配置)· 全渠道统一一张表</h2>
<p><b>一张表覆盖所有联系方式</b> —— Telegram 频道/群组/Bot、LINE、邮箱、发卡商店都是 <code>contact_link</code> 里的一行,
差别只在 <code>platform</code>(分到哪个 L1 卡)+ <code>kind</code>(二级分到哪组 &amp; 动作样式)+ <code>url</code> 协议。
一行 = 一条可点链接;L1 按 <code>platform</code> 聚合,L2 按 <code>kind</code> 分组。</p>
<pre>contact_link
─────────────────────────────────────────────────────────────
id INTEGER PK
platform TEXT -- telegram | line | email | store | whatsapp | ...(L1 分组键)
kind TEXT -- channel | group | bot | link(L2 分组键 & 动作样式)
title TEXT -- "穿山甲 · 官方频道" / "邮箱客服" / "自助发卡商店"
handle TEXT -- "@PangolinVPN"(展示;可空,邮箱/商店留空)
url TEXT -- 点击目标(见下表);App 侧对 telegram 优先转 tg://
description TEXT -- 一句说明(可空)
verified INTEGER -- 0/1 认证勾
sort_order INTEGER -- 组内排序
enabled INTEGER -- 0/1 下线开关
locale TEXT -- "zh"|"en"|NULL(全部) 可选按语言过滤
</pre>
<p><b>邮箱之类怎么进这张表 —— 就是把 <code>url</code> 换个协议、<code>kind=link</code></b></p>
<table>
<tr><th>渠道</th><th>platform</th><th>kind</th><th>url 示例</th><th>动作</th></tr>
<tr><td>Telegram 频道</td><td><code>telegram</code></td><td><code>channel</code></td><td><code>https://t.me/PangolinVPN</code>App 转 <code>tg://</code></td><td>打开</td></tr>
<tr><td>Telegram 群组</td><td><code>telegram</code></td><td><code>group</code></td><td><code>https://t.me/PangolinChat</code></td><td>加入</td></tr>
<tr><td>Telegram Bot</td><td><code>telegram</code></td><td><code>bot</code></td><td><code>https://t.me/PangolinVPN_bot</code></td><td>打开</td></tr>
<tr><td>LINE 账号</td><td><code>line</code></td><td><code>link</code></td><td><code>https://line.me/R/ti/p/@pangolinvpn</code></td><td>打开</td></tr>
<tr><td>邮箱客服</td><td><code>email</code></td><td><code>link</code></td><td><code>mailto:support@pangolin.vpn</code></td><td>打开(拉起邮件)</td></tr>
<tr><td>自助发卡商店</td><td><code>store</code></td><td><code>link</code></td><td><code>https://shop.pangolin.vpn</code></td><td>打开(浏览器)</td></tr>
<tr><td>WhatsApp(将来)</td><td><code>whatsapp</code></td><td><code>link</code></td><td><code>https://wa.me/…</code></td><td>打开</td></tr>
</table>
<p class="small">动作按钮文案由 <code>kind</code> 决定:<code>group</code><b>「加入」</b>(实心强调);其余(<code>channel/bot/link</code>)→ <b>「打开」</b>(描边)。
点击一律「用系统方式打开 <code>url</code>」,App 侧仅对 <code>telegram</code> 平台做 <code>https://t.me/x → tg://resolve?domain=x</code> 的唤起优化,失败回退原 url。</p>
<p class="small"><b>唯一不入库的是「皮」</b>L1 平台卡的<b>图标 / 强调色 / 默认显示名</b>由前端一个小 <b>platform 注册表</b><code>platform</code> 键内置
<code>telegram</code>=✈+强调色、<code>line</code>=💬、<code>email</code>=✉、<code>store</code>=🛍…),避免把图标资源塞进数据库;未知 platform 用通用图标兜底。
库里只配<b>内容</b>。加已有平台的新频道/群 = 纯 DB,无需发版;加一个全新平台类型(新图标)= 注册表加一行 + 发版。</p>
<h2>接口</h2>
<pre>GET /v1/contact # 无需登录亦可(客户端普通请求)
→ 200
{
"platforms": [
{ "platform":"telegram",
"links":[
{"kind":"channel","title":"穿山甲 · 官方频道","handle":"@PangolinVPN",
"url":"https://t.me/PangolinVPN","description":"产品更新与公告","verified":true},
{"kind":"group","title":"穿山甲 · 用户交流群","handle":"@PangolinChat",
"url":"https://t.me/PangolinChat","description":"使用问题互助"},
{"kind":"bot","title":"客服机器人","handle":"@PangolinVPN_bot",
"url":"https://t.me/PangolinVPN_bot","description":"自动答疑/提交工单"}
]},
{ "platform":"line", "links":[ ... ] },
{ "platform":"email", "links":[{"kind":"link","title":"邮箱客服","url":"mailto:support@pangolin.vpn"}] },
{ "platform":"store", "links":[{"kind":"link","title":"自助发卡商店","url":"https://shop.pangolin.vpn"}] }
]
}</pre>
<ul>
<li>后端按 <code>enabled=1</code> 过滤、按 <code>sort_order</code> 排序、按 <code>platform</code><code>kind</code> 分组返回;客户端只渲染。</li>
<li>客户端<b>缓存</b>上次结果(离线/弱网仍可展示),启动或进联系页时后台刷新。</li>
<li>迁移:<code>server/migrations/{mysql,sqlite}/</code> 各加建表 + 种子数据(把现有 4 渠道灌入,Telegram 先补真实频道/群)。</li>
</ul>
<h2>已定(本轮拍板)</h2>
<ul>
<li><span class="tag ok"></span> <b>不展示成员数</b> —— 已从模型与 UI 移除 <code>member_hint</code></li>
<li><span class="tag ok"></span> 群组动作叫 <b>「加入」</b><code>kind=group</code>,实心强调);频道/Bot/普通链接 <b>「打开」</b>(描边)。</li>
<li><span class="tag ok"></span> 接口走 <b>独立 <code>GET /v1/contact</code></b>(不并进 <code>/me</code> 引导)。</li>
<li><span class="tag ok"></span> <b>全渠道统一一张 <code>contact_link</code></b>:邮箱/发卡/LINE 与 Telegram 同表,靠 <code>url</code> 协议区分(<code>mailto:</code> / <code>https:</code> / <code>tg://</code>)。</li>
<li><span class="tag ok"></span> <b>LINE 也做二级</b>(与 Telegram 同构),但<b>先灰置</b>——L1 上 LINE 卡置灰 + 「即将开放」,不可点进;二级页结构预留,等运营在库里配好 LINE 链接、去灰即用。</li>
</ul>
<h2>仍可再定(不阻塞,先给默认)</h2>
<ul>
<li><b>认证勾 <span class="p-verify" style="color:var(--accent)"></span> 与分组标题</b>:默认<b>保留</b>(频道/群组/Bot 分组 + 官方项带勾)。若想更简可拍平成单列表 —— 说一声即可。</li>
<li><b>成员数字段是否保留在库里(仅不展示)</b>:默认<b>删列</b>,需要时再加回不迟。</li>
</ul>
</div>
</body>
<script>
function _hideAll(){ ['view-l1','view-tg','view-line'].forEach(id=>document.getElementById(id).classList.add('hide')); }
function showList(){ _hideAll(); document.getElementById('view-l1').classList.remove('hide'); document.getElementById('p-title').textContent='联系我们'; }
function showTg(){ _hideAll(); document.getElementById('view-tg').classList.remove('hide'); document.getElementById('p-title').textContent='Telegram'; }
function showLine(){ _hideAll(); document.getElementById('view-line').classList.remove('hide'); document.getElementById('p-title').textContent='LINE'; }
</script>
</html>