diff --git a/.vitepress/theme/components/ScreenshotPreview.vue b/.vitepress/theme/components/ScreenshotPreview.vue
new file mode 100644
index 0000000..62ae337
--- /dev/null
+++ b/.vitepress/theme/components/ScreenshotPreview.vue
@@ -0,0 +1,226 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
![]()
+
+
+
截图待补
+
{{ mainShot.caption }}
+
+
+ {{ mainShot.caption }}
+
+
+
+
+
+
+
+
+ 截图按端分组,点击缩略图切换主图。当前为占位状态,补齐截图后自动替换。
+
+
+
+
+
diff --git a/.vitepress/theme/index.ts b/.vitepress/theme/index.ts
index 0357d09..dd0563c 100644
--- a/.vitepress/theme/index.ts
+++ b/.vitepress/theme/index.ts
@@ -7,6 +7,7 @@ import ProjectList from './components/ProjectList.vue'
import HomePage from './components/HomePage.vue'
import CapabilityTabs from './components/CapabilityTabs.vue'
import FeatureGrid from './components/FeatureGrid.vue'
+import ScreenshotPreview from './components/ScreenshotPreview.vue'
import './styles/portal.css'
@@ -28,5 +29,6 @@ export default {
app.component('HomePage', HomePage)
app.component('CapabilityTabs', CapabilityTabs)
app.component('FeatureGrid', FeatureGrid)
+ app.component('ScreenshotPreview', ScreenshotPreview)
},
} satisfies Theme
diff --git a/.vitepress/theme/styles/portal.css b/.vitepress/theme/styles/portal.css
index bfa92ce..e2b4afc 100644
--- a/.vitepress/theme/styles/portal.css
+++ b/.vitepress/theme/styles/portal.css
@@ -741,3 +741,181 @@ html.dark .p-tab.is-active {
.vp-doc a:hover {
text-decoration-color: var(--p-accent);
}
+
+/* ============================================================
+ 产品功能卡片
+ ============================================================ */
+.pf-card {
+ position: relative;
+}
+
+.pf-name {
+ font-size: 17px;
+}
+
+.pf-tagline {
+ margin: 8px 0 0;
+ font-size: 13.5px;
+ font-weight: 600;
+ color: var(--p-accent);
+}
+
+.pf-list {
+ margin: 20px 0 0;
+ padding: 0;
+ list-style: none;
+ flex: 1;
+}
+
+.pf-list li {
+ position: relative;
+ padding: 9px 0 9px 22px;
+ font-size: 13.5px;
+ line-height: 1.6;
+ color: var(--p-ink-2);
+ border-top: 1px solid var(--p-line);
+}
+
+.pf-list li:first-child {
+ border-top: none;
+}
+
+.pf-list li::before {
+ content: '';
+ position: absolute;
+ left: 2px;
+ top: 17px;
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ background: var(--p-accent);
+ opacity: 0.55;
+}
+
+.pf-more {
+ display: inline-block;
+ margin-top: 20px;
+ font-size: 13px;
+ font-weight: 600;
+ color: var(--p-accent);
+ text-decoration: none !important;
+}
+
+.pf-more:hover {
+ text-decoration: underline !important;
+ text-underline-offset: 3px;
+}
+
+/* ============================================================
+ 核心能力卡片
+ ============================================================ */
+.ca-card {
+ position: relative;
+ padding: 26px 24px;
+}
+
+.ca-tag {
+ display: inline-block;
+ align-self: flex-start;
+ width: auto;
+ margin-bottom: 14px;
+ padding: 2px 9px;
+ font-size: 11.5px;
+ font-weight: 600;
+ letter-spacing: 0.04em;
+ color: var(--p-accent);
+ background: var(--p-accent-soft);
+ border-radius: 5px;
+}
+
+.ca-card .p-card-title {
+ font-size: 15.5px;
+}
+
+.ca-card .p-card-text {
+ font-size: 13.5px;
+ line-height: 1.7;
+}
+
+/* ============================================================
+ 官方文档
+ ============================================================ */
+.doc-grid {
+ margin-bottom: 8px;
+}
+
+.doc-card {
+ text-decoration: none !important;
+ color: var(--p-ink) !important;
+}
+
+.doc-top {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 12px;
+}
+
+.doc-top .p-card-title {
+ font-size: 15.5px;
+}
+
+.doc-arrow {
+ flex: none;
+ margin-top: 3px;
+ color: var(--p-ink-3);
+ transition: color 0.18s, transform 0.18s;
+}
+
+.doc-card:hover .doc-arrow {
+ color: var(--p-accent);
+ transform: translate(1px, -1px);
+}
+
+.doc-card .p-card-text {
+ flex: 1;
+ font-size: 13.5px;
+ line-height: 1.7;
+}
+
+.doc-project {
+ display: inline-block;
+ align-self: flex-start;
+ margin-top: 18px;
+ padding: 2px 9px;
+ font-size: 11.5px;
+ color: var(--p-ink-3);
+ background: var(--p-surface-alt);
+ border: 1px solid var(--p-line);
+ border-radius: 5px;
+}
+
+html.dark .doc-project {
+ background: rgba(255, 255, 255, 0.04);
+}
+
+.doc-note {
+ margin: 28px 0 0;
+ text-align: center;
+ font-size: 13px;
+ color: var(--p-ink-3);
+}
+
+.doc-note a {
+ color: var(--p-accent);
+ text-decoration: none;
+}
+
+.doc-note a:hover {
+ text-decoration: underline;
+ text-underline-offset: 3px;
+}
+
+/* ============================================================
+ 导航:锚点项在窄屏隐藏,避免挤压
+ ============================================================ */
+@media (max-width: 860px) {
+ .VPNavBarMenuGroup:nth-child(n + 5):nth-child(-n + 7) {
+ display: none;
+ }
+}
diff --git a/data/content.ts b/data/content.ts
index 6f1ad95..49d1b75 100644
--- a/data/content.ts
+++ b/data/content.ts
@@ -19,6 +19,120 @@ export const stats: Stat[] = [
{ num: '100', unit: '%', label: 'Apache-2.0 许可' },
]
+/* ============================================================
+ 产品功能 —— 首页「产品功能」区块,按产品线列功能点
+ ============================================================ */
+
+export interface ProductLine {
+ id: string
+ name: string
+ /** 一句话定位 */
+ tagline: string
+ /** 该产品线的功能清单,取 6 条最能说明问题的 */
+ features: string[]
+ /** 对应详情页 */
+ page: string
+}
+
+export const productLines: ProductLine[] = [
+ {
+ id: 'iotlcm',
+ name: 'iotLCM 物联网卡',
+ tagline: 'SIM 卡从入库到销户的全流程',
+ features: [
+ '卡信息检索与批量导入',
+ '入库 / 库存 / 出库三级流转',
+ '批量开停复机与续费',
+ '套餐、流量池与定价',
+ '三大运营商协议直连',
+ '达量断网与智能诊断',
+ ],
+ page: '/projects/iotlcm/',
+ },
+ {
+ id: 'xiu-dtu',
+ name: '秀杰 DTU 设备',
+ tagline: 'DTU 设备从生产到运行监控',
+ features: [
+ '产品、型号与生产批次',
+ '固件版本与 OTA 升级',
+ '配置分组与下发状态',
+ '代理商划拨与回收',
+ 'HTTP / TCP 双通道接入',
+ '设备在线状态监控',
+ ],
+ page: '/projects/xiu-dtu/',
+ },
+ {
+ id: 'xiu-admin',
+ name: 'XiuAdmin 中后台',
+ tagline: '22 项内置功能的应用底座',
+ features: [
+ '多租户与租户套餐',
+ '用户、部门、岗位、角色',
+ '菜单与按钮级权限',
+ '代码生成(CURD / 树表)',
+ '定时任务与消息队列',
+ '服务监控与操作日志',
+ ],
+ page: '/projects/xiu-admin/',
+ },
+]
+
+/* ============================================================
+ 核心能力 —— 首页「核心能力」区块,强调工程层面的硬指标
+ ============================================================ */
+
+export interface CoreAbility {
+ title: string
+ text: string
+ /** 卡片角标,一个词概括 */
+ tag: string
+}
+
+export const coreAbilities: CoreAbility[] = [
+ {
+ tag: '部署',
+ title: '单机一条命令起',
+ text: 'Docker Compose 编排齐备,首次启动自动建库建表、导入种子数据与时序库建表,不需要本地编译,约一分钟可用。',
+ },
+ {
+ tag: '接入',
+ title: '运营商协议内置',
+ text: '中国移动 OneLink、中国电信 5G CMP、中国联通 10646 的接口差异收敛在对接层,上层业务不感知底层协议。',
+ },
+ {
+ tag: '开放',
+ title: '版本化对外接口',
+ text: 'V3 版本化接口、旧版兼容接口与运营商能力代理三套合同并行,升级不破坏既有调用方。',
+ },
+ {
+ tag: '治理',
+ title: '多租户权限模型',
+ text: '租户、部门、岗位、角色四层结构,菜单与按钮级权限、数据范围划分,关键操作全程留痕。',
+ },
+ {
+ tag: '韧性',
+ title: '上游抖动隔离',
+ text: '独立的通道缓存转发层,上游接口异常或超时不直接传导到管理端,配合健康探针与运行期 DNS 解析自动跟随容器 IP 变化。',
+ },
+ {
+ tag: '交付',
+ title: '离线可部署',
+ text: '镜像可导出为归档文件带入内网,无外网环境同样能完成安装与升级,适合企业内网与客户现场。',
+ },
+ {
+ tag: '数据',
+ title: '时序数据留存',
+ text: '流量与状态按账期落入时序库,月度账单自动生成、每小时增量更新,长期趋势分析不失真。',
+ },
+ {
+ tag: '维护',
+ title: '文档与代码同仓',
+ text: '使用手册、部署手册与接口合同与代码同仓维护,随平台一起发布,版本不会脱节。',
+ },
+]
+
export interface Capability {
title: string
text: string
@@ -170,3 +284,98 @@ export const dtuGroups: CapGroup[] = [
],
},
]
+
+/* ============================================================
+ 界面预览 —— 首页「界面预览」区块
+ ============================================================ */
+
+export interface PreviewShot {
+ /** 截图文件名,放在 pages/public/screenshots/ 下;为空时渲染占位框 */
+ file: string
+ /** 图注,说明这张图看的是什么 */
+ caption: string
+ /** 所属端,用于标签切换 */
+ group: 'web' | 'app'
+}
+
+/**
+ * 每个分组的第一张是首屏大图,其余进下方缩略图条。
+ *
+ * 图片放置约定:pages/public/screenshots/
+ * 建议尺寸 1600x1000(web)/ 750x1334(app),单张控制在 400KB 以内。
+ * file 留空时页面显示占位框与图注,不会报错 —— 补图时只改 file 字段即可。
+ */
+export const previewShots: Record<'web' | 'app', PreviewShot[]> = {
+ web: [
+ { file: '', caption: '管理端工作台:卡量与用量概览', group: 'web' },
+ { file: '', caption: '卡信息列表:三码检索与批量操作', group: 'web' },
+ { file: '', caption: '业务受理:开通、续费与变更套餐', group: 'web' },
+ { file: '', caption: '套餐与定价配置', group: 'web' },
+ { file: '', caption: '通道与上游接入管理', group: 'web' },
+ { file: '', caption: '企业、用户与角色权限', group: 'web' },
+ ],
+ app: [
+ { file: '', caption: '用户端首页:公开查卡入口', group: 'app' },
+ { file: '', caption: '卡片详情与用量', group: 'app' },
+ { file: '', caption: '业务办理:续费与套餐变更', group: 'app' },
+ { file: '', caption: '智能诊断:按链路排查问题', group: 'app' },
+ ],
+}
+
+/* ============================================================
+ 官方文档 —— 首页「官方文档」区块
+ ============================================================ */
+
+export interface DocEntry {
+ name: string
+ /** 这份文档解决什么问题 */
+ desc: string
+ url: string
+ /** 归属项目名,用于分组显示 */
+ project: string
+}
+
+/**
+ * 文档站是随 iotLCM 发布的独立站点(VitePress),按手册分册。
+ * 地址可用 DOCS_BASE 环境变量在构建时覆盖,见 .vitepress/config.mts。
+ */
+const DOCS_BASE = 'http://open.5iot.com:5051/docs'
+
+export const docs: DocEntry[] = [
+ {
+ name: '文档中心',
+ desc: '全部手册的入口页,按端与用途分册索引',
+ url: `${DOCS_BASE}/`,
+ project: 'iotLCM',
+ },
+ {
+ name: '使用手册 · Web 管理端',
+ desc: '查卡、业务受理、套餐定价、库存出入库、通道管理、企业用户与角色、工单、API 凭证',
+ url: `${DOCS_BASE}/manual/web/`,
+ project: 'iotLCM',
+ },
+ {
+ name: '使用手册 · 小程序端',
+ desc: '公开查卡、卡片排查、客户管理与划拨、工单、批次执行日志、消息与个人中心',
+ url: `${DOCS_BASE}/manual/mini-program/`,
+ project: 'iotLCM',
+ },
+ {
+ name: '部署手册',
+ desc: '环境要求、一键部署、配置说明、离线部署、拆分部署、自建镜像、运维与排错',
+ url: `${DOCS_BASE}/deploy/`,
+ project: 'iotLCM',
+ },
+ {
+ name: 'OpenAPI 合同',
+ desc: '鉴权方式、V3 接口、旧版兼容接口、运营商能力代理',
+ url: `${DOCS_BASE}/openapi/`,
+ project: 'iotLCM',
+ },
+ {
+ name: '门户部署说明',
+ desc: '本门户自身的构建参数、镜像形态与容器部署方式',
+ url: '/guide/portal-deploy',
+ project: '门户站',
+ },
+]
diff --git a/pages/public/screenshots/README.md b/pages/public/screenshots/README.md
new file mode 100644
index 0000000..285bf4e
--- /dev/null
+++ b/pages/public/screenshots/README.md
@@ -0,0 +1,37 @@
+# 界面预览截图
+
+首页「界面预览」区块从这里取图。补图时**只改 `data/content.ts` 里的 `file` 字段**,不用动组件。
+
+## 命名约定
+
+```
+pages/public/screenshots/
+├── web-dashboard.png # 管理端工作台(首屏大图)
+├── web-cards.png # 卡信息列表
+├── web-business.png # 业务受理
+├── web-packages.png # 套餐与定价
+├── web-channels.png # 通道管理
+├── web-org.png # 企业与权限
+├── app-home.png # 用户端首页
+├── app-card-detail.png # 卡片详情
+├── app-business.png # 业务办理
+└── app-diagnosis.png # 智能诊断
+```
+
+## 规格
+
+| 项 | 建议 |
+| --- | --- |
+| Web 端尺寸 | 1600 × 1000(16:10) |
+| 小程序端尺寸 | 750 × 1334(9:16) |
+| 单张体积 | 400 KB 以内,PNG 或 WebP |
+| 内容 | 用演示数据,不要出现真实客户名、真实 ICCID、真实手机号 |
+| 敏感信息 | 账号、口令、密钥片段一律打码 |
+
+## 补图步骤
+
+1. 把图片放进本目录,按上面约定命名
+2. 打开 `data/content.ts`,找到 `previewShots`,把对应条目的 `file` 从 `''` 改成文件名
+3. 保存,页面自动从占位框切换成真实截图
+
+`file` 留空时页面显示带图注的占位框,不会报错,也不影响构建。