Files
liuzhuohua a8659dfb98 docs(readme): 用 78 张真实界面截图替换 SVG 占位图
原文里 docs/screenshots/ 放的是 6 张同尺寸 SVG 占位图,只为让 README
在仓库刚建好时能完整渲染。现在换成 78 张真实运行截图(1272x900,
取自一台 2 核 4G 的 Debian 13 虚拟机)。

改动:
- 新增 docs/screenshots/ 78 张 jpg,按 9 个功能分组编号命名
  (01-login / 02-overview… / 09-settings-4),覆盖全部 43 个功能页
- 删除 6 张 SVG 占位图与 devtools/make-placeholder-shots.py
- README「截图」章节重写:首屏放 8 张精选大图,其余 70 张按功能分
  组放进 9 个 <details> 折叠块,每组内用两列表格 + 图注
- README 项目结构补充 docs/screenshots 与 devtools/shots-map.py
- dist/RELEASE_NOTES.md 同步「截图已全部为真图」

为什么文件名必须 ASCII:
  GitHub Releases 资产名已被实测证明会静默剥离非 ASCII 字符
  (DOCKER-使用说明.md → DOCKER-.md);且原始文件名含 &(如
  AC&AP管理中心.jpg、UPnp&NAT-PMP.jpg)在 shell / CI 里都要额外转义。
  devtools/shots-map.py 负责「中文名 → ASCII 名」的映射与复制,
  并做完整性校验(漏拷/多余/重名都会中止)。

新增两项预检,挂进 devtools/sync.sh:
- devtools/check-md-links.py:所有 md 的本地引用逐条查存在性
- 截图清单双向校验:README 引用的 78 张与目录里的 78 个文件必须一一对应

验证:check-md-links 扫 10 个 md / 98 个本地引用,0 死链;
      78 张图与源目录 md5 集合完全一致;
      t-packaging / t-audit / t-deps / t-cachebust 全部通过。
2026-09-30 22:46:43 +08:00

160 lines
11 KiB
Python
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.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
把桌面原始截图(中文名)映射成仓库内的 ASCII 序号名,并复制到 docs/screenshots/。
为什么必须改成 ASCII 文件名:
1. GitHub Releases 资产名已被实测证明会静默剥离非 ASCII 字符
(DOCKER-使用说明.md → DOCKER-.md),同类坑不要重复踩。
2. 文件名里含 & (AC&AP管理中心.jpg、UPnp&NAT-PMP.jpg…)在 shell、
Makefile、CI 里都要额外转义,属于纯粹的负债。
3. ASCII 名方便 diff、grep、脚本批量处理,也方便日后用户自己补图。
命名规则:<分组号>-<页面短名>[-<序号>].jpg
例如 05-dhcp.jpg / 05-dhcp-2.jpg / 05-dhcp-3.jpg
"""
import os
import shutil
import sys
SRC = r"C:\Users\lyrz-pve-win10\Desktop\drouter"
DST = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
"docs", "screenshots")
# (中文源文件名, 目标 ASCII 名, 图注标题)
# 顺序 = README 里的展示顺序;分组号与 README 的 8 个功能分组对应。
# 注意:这里必须写全 78 张,任何一张漏掉都会在最后被 assert 抓到。
MAP = [
# ── 01 登入 ────────────────────────────────────────────────
("登入.jpg", "01-login.jpg", "登录页"),
# ── 02 概览 ────────────────────────────────────────────────
("概述.jpg", "02-overview.jpg", "系统概览"),
("概述2.jpg", "02-overview-2.jpg", "系统概览 · 硬件仪表盘"),
("概述3.jpg", "02-overview-3.jpg", "系统概览 · 网络与服务状态"),
("网络状态&加速.jpg", "02-netstat.jpg", "网络状态 / 加速"),
("网络状态&加速2.jpg", "02-netstat-2.jpg", "网络状态 · 路由表与接口地址"),
("网络状态&加速3.jpg", "02-netstat-3.jpg", "网络状态 · flowtable 软加速"),
# ── 03 接口 ────────────────────────────────────────────────
("网卡与桥接.jpg", "03-iface.jpg", "网卡与桥接"),
("WAN口.jpg", "03-wan.jpg", "WAN 口 · 接入方式"),
("WAN口2.jpg", "03-wan-2.jpg", "WAN 口 · 实时状态"),
("WAN口3.jpg", "03-wan-3.jpg", "WAN 口 · 拨号日志"),
("PPPOE多拨.jpg", "03-pppoe.jpg", "PPPoE 多拨"),
("PPPOE多拨2.jpg", "03-pppoe-2.jpg", "PPPoE 多拨 · 会话状态"),
("LAN口.jpg", "03-lan.jpg", "LAN 口"),
("VLAN&IPTV.jpg", "03-vlan.jpg", "VLAN / IPTV 单线复用"),
("网络唤醒(WOL).jpg", "03-wol.jpg", "网络唤醒 WOL"),
# ── 04 寻址与路由 ──────────────────────────────────────────
("DHCP服务.jpg", "04-dhcp.jpg", "DHCP 服务"),
("DHCP服务2.jpg", "04-dhcp-2.jpg", "DHCP 服务 · 租约表"),
("DNS服务.jpg", "04-dns.jpg", "DNS 服务"),
("IPV6&RA.jpg", "04-ipv6ra.jpg", "IPv6 / RA"),
("IPV6&RA2.jpg", "04-ipv6ra-2.jpg", "IPv6 / RA · 前缀与 RDNSS"),
("IPV6&RA3.jpg", "04-ipv6ra-3.jpg", "IPv6 / RA · 运行状态"),
("DHCPV6&前缀委派.jpg", "04-dhcpv6.jpg", "DHCPv6 / 前缀委派"),
("动态域名解析.jpg", "04-ddns.jpg", "动态域名 DDNS"),
("动态域名解析2.jpg", "04-ddns-2.jpg", "动态域名 DDNS · IPv6 记录"),
("动态域名解析3.jpg", "04-ddns-3.jpg", "动态域名 DDNS · 解析结果"),
("真·公网IP判定.jpg", "04-publicip.jpg", "真·公网 IP 判定"),
("真·公网IP判定2.jpg", "04-publicip-2.jpg", "真·公网 IP 判定 · NAT 类型"),
# ── 05 安全 ────────────────────────────────────────────────
("防火墙IPV4.jpg", "05-fw4.jpg", "防火墙 IPv4"),
("防火墙IPV4-2.jpg", "05-fw4-2.jpg", "防火墙 IPv4 · 规则与日志"),
("防火墙IPV6.jpg", "05-fw6.jpg", "防火墙 IPv6"),
("防火墙IPV6-2.jpg", "05-fw6-2.jpg", "防火墙 IPv6 · 规则与日志"),
("端口转发&DMZ.jpg", "05-dnat.jpg", "端口转发 / DMZ"),
("UPnp&NAT-PMP.jpg", "05-upnp.jpg", "UPnP / NAT-PMP"),
("访问控制&时间组.jpg", "05-acl.jpg", "访问控制 / 时间组"),
# ── 06 服务 ────────────────────────────────────────────────
("智能限速QOS.jpg", "06-qos.jpg", "智能限速 QoS"),
("智能限速QOS2.jpg", "06-qos-2.jpg", "智能限速 QoS · 队列与规则"),
("应用识别DPI.jpg", "06-dpi.jpg", "应用识别 DPI"),
("应用识别DPI-2.jpg", "06-dpi-2.jpg", "应用识别 DPI · 识别结果"),
("NTP时间同步.jpg", "06-ntp.jpg", "NTP 时间同步"),
("文件共享SMB&NFS.jpg", "06-smb.jpg", "文件共享 SMB / NFS"),
("文件共享SMB&NFS-2.jpg", "06-smb-2.jpg", "文件共享 · 共享目录"),
("打印服务.jpg", "06-cups.jpg", "打印服务 CUPS"),
("打印服务2.jpg", "06-cups-2.jpg", "打印服务 · 打印队列"),
("打印服务3.jpg", "06-cups-3.jpg", "打印服务 · USB 直通"),
("打印服务4.jpg", "06-cups-4.jpg", "打印服务 · 共享设置"),
("AC&AP管理中心.jpg", "06-acap.jpg", "AC / AP 管理中心"),
("AC&AP管理中心2.jpg", "06-acap-2.jpg", "AC / AP · 无线与 VLAN"),
# ── 07 工具 ────────────────────────────────────────────────
("WEB终端&文件.jpg", "07-webshell.jpg", "Web 终端 / 文件"),
("通用API接口.jpg", "07-api.jpg", "通用 API 接口"),
("通用API接口2.jpg", "07-api-2.jpg", "通用 API · OpenAPI 文档"),
("网络诊断工具.jpg", "07-diag.jpg", "网络诊断工具"),
("IPV6连通性测试.jpg", "07-ipv6test.jpg", "IPv6 连通性测试"),
("docker&compose.jpg", "07-docker.jpg", "Docker / Compose"),
("docker&compose2.jpg", "07-docker-2.jpg", "Docker · 容器与镜像"),
("docker&compose3.jpg", "07-docker-3.jpg", "Docker · Compose 项目"),
("docker引擎配置.jpg", "07-dockerconf.jpg", "Docker 引擎配置"),
("docker引擎配置2.jpg", "07-dockerconf-2.jpg", "Docker 引擎 · 镜像源测速"),
("docker引擎配置3.jpg", "07-dockerconf-3.jpg", "Docker 引擎 · daemon.json"),
# ── 08 日志与审计 ──────────────────────────────────────────
("系统日志.jpg", "08-syslog.jpg", "系统日志"),
("连接与流日志.jpg", "08-flowlog.jpg", "连接与流日志"),
("连接与流日志2.jpg", "08-flowlog-2.jpg", "连接与流日志 · conntrack"),
# ── 09 系统 ────────────────────────────────────────────────
("依赖自检与安装.jpg", "09-deps.jpg", "依赖自检与安装"),
("依赖自检与安装2.jpg", "09-deps-2.jpg", "依赖自检 · 探测结果"),
("磁盘与日志清理.jpg", "09-cleanup.jpg", "磁盘与日志清理"),
("磁盘与日志清理2.jpg", "09-cleanup-2.jpg", "磁盘与日志清理 · 占用明细"),
("内核转发与加速.jpg", "09-kernel.jpg", "内核转发与加速"),
("内核转发与加速2.jpg", "09-kernel-2.jpg", "内核转发 · 开关与联动"),
("证书&SSL.jpg", "09-tls.jpg", "证书 / SSL"),
("证书&SSL2.jpg", "09-tls-2.jpg", "证书 / SSL · 签发与部署"),
("证书&SSL3.jpg", "09-tls-3.jpg", "证书 / SSL · 握手体检"),
("电源控制.jpg", "09-power.jpg", "电源控制"),
("用户与密钥.jpg", "09-user.jpg", "用户与密钥"),
("用户与密钥2.jpg", "09-user-2.jpg", "用户与密钥 · SSH 公钥"),
("系统设置.jpg", "09-settings.jpg", "系统设置"),
("系统设置2.jpg", "09-settings-2.jpg", "系统设置 · 时区与主机名"),
("系统设置3.jpg", "09-settings-3.jpg", "系统设置 · Web 端口"),
("系统设置4.jpg", "09-settings-4.jpg", "系统设置 · 审计日志"),
]
def main():
if not os.path.isdir(SRC):
sys.exit("源目录不存在: " + SRC)
# 完整性校验:源目录里的 jpg 必须一张不漏、一张不多地出现在 MAP 里
on_disk = {f for f in os.listdir(SRC) if f.lower().endswith(".jpg")}
in_map = {src for src, _, _ in MAP}
missing = sorted(on_disk - in_map)
ghost = sorted(in_map - on_disk)
dup = len(MAP) - len(in_map)
if missing or ghost or dup:
print("!! 映射表与磁盘不一致,已中止")
if missing:
print(" 磁盘有、MAP 里没有:", missing)
if ghost:
print(" MAP 里有、磁盘上没有:", ghost)
if dup:
print(" MAP 里有重复条目的数量:", dup)
sys.exit(1)
os.makedirs(DST, exist_ok=True)
# 先清掉旧的 svg 占位图(调用方决定,这里只处理 jpg)
for src, dst, _ in MAP:
shutil.copy2(os.path.join(SRC, src), os.path.join(DST, dst))
print("copied %d jpg -> %s" % (len(MAP), DST))
# 输出一份 markdown 引用清单,供 README 章节直接取用
print("\n" + "=" * 60)
for _, dst, cap in MAP:
print("%-24s %s" % (dst, cap))
if __name__ == "__main__":
main()