diff --git a/Caddyfile b/Caddyfile
new file mode 100644
index 0000000..913de19
--- /dev/null
+++ b/Caddyfile
@@ -0,0 +1,46 @@
+# Caddy reverse proxy for Eversolo Web
+# Domain: test.luxsin.com.cn
+# Caddy automatically obtains and renews SSL certificates via Let's Encrypt / ZeroSSL.
+# HTTP (port 80) is automatically redirected to HTTPS.
+
+test.luxsin.com.cn {
+ # Security headers (applied to all responses)
+ header {
+ X-Content-Type-Options nosniff
+ X-Frame-Options SAMEORIGIN
+ Referrer-Policy strict-origin-when-cross-origin
+ }
+
+ # Payload uploads served directly from the persistent data volume.
+ # docker-compose mounts ./data/{media,files,videos} -> /srv/uploads/{media,files,videos}
+ # handle creates an exclusive route: once matched, the request never falls through to the app.
+ handle /media/* {
+ root * /srv/uploads
+ header Cache-Control "public, max-age=2592000, immutable"
+ file_server
+ }
+
+ handle /files/* {
+ root * /srv/uploads
+ header Cache-Control "public, max-age=604800"
+ file_server
+ }
+
+ handle /videos/* {
+ root * /srv/uploads
+ header Cache-Control "public, max-age=2592000"
+ file_server
+ }
+
+ # Everything else -> Next.js app (port 3000)
+ # WebSocket upgrade headers are handled automatically by Caddy.
+ handle {
+ reverse_proxy app:3000 {
+ header_up X-Real-IP {remote_host}
+ transport http {
+ read_timeout 300s
+ write_timeout 300s
+ }
+ }
+ }
+}
diff --git a/docker-compose.yml b/docker-compose.yml
index c233ef9..fe2e21c 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -21,19 +21,20 @@ services:
networks:
- web
- nginx:
- image: uhub.service.ucloud.cn/mysql-images/nginx:latest
- container_name: eversolo-nginx
+ caddy:
+ image: uhub.service.ucloud.cn/mysql-images/caddy:2-alpine
+ container_name: eversolo-caddy
restart: unless-stopped
depends_on:
- app
ports:
- "80:80"
- "443:443"
+ - "443:443/udp"
volumes:
- - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- - ./nginx/conf.d:/etc/nginx/conf.d:ro
- - ./nginx/certs:/etc/nginx/certs:ro
+ - ./Caddyfile:/etc/caddy/Caddyfile:ro
+ - caddy_data:/data
+ - caddy_config:/config
- ./data/media:/srv/uploads/media:ro
- ./data/files:/srv/uploads/files:ro
- ./data/videos:/srv/uploads/videos:ro
@@ -67,4 +68,6 @@ networks:
driver: bridge
volumes:
- bootstrap_node_modules:
\ No newline at end of file
+ bootstrap_node_modules:
+ caddy_data:
+ caddy_config:
\ No newline at end of file
diff --git a/docs/admin-operation-guide.md b/docs/admin-operation-guide.md
new file mode 100644
index 0000000..258cfed
--- /dev/null
+++ b/docs/admin-operation-guide.md
@@ -0,0 +1,538 @@
+# Admin 后台操作指南
+
+> 本文档说明 Payload CMS 后台中每个集合(Collection)和全局配置(Global)的作用、可管理的内容,以及最终在前端哪个页面生效。
+
+---
+
+## 目录
+
+- [模块权限体系](#模块权限体系)
+- [Collections(集合)](#collections集合)
+ - [产品目录 Product Catalog](#产品目录-product-catalog)
+ - [支持中心 Support Center](#支持中心-support-center)
+ - [运营管理 Operations](#运营管理-operations)
+ - [销售渠道 Sales Channels](#销售渠道-sales-channels)
+ - [素材库 Asset Library](#素材库-asset-library)
+ - [媒体资料包管理 Media Asset Management](#媒体资料包管理-media-asset-management)
+ - [内容发布 Content Publishing](#内容发布-content-publishing)
+ - [系统设置 System Settings](#系统设置-system-settings)
+- [Globals(全局配置)](#globals全局配置)
+ - [站点管理 Site Management](#站点管理-site-management)
+ - [媒体资料包管理 Media Asset Management](#媒体资料包管理-media-asset-management-1)
+
+---
+
+## 模块权限体系
+
+后台采用 **模块分组 + 角色** 的权限控制。每个集合和全局配置都归属一个管理模块。
+
+| 模块键 | 中文名 | 适用角色 |
+|--------|--------|---------|
+| `systemSettings` | 系统设置 | Admin |
+| `productCatalog` | 产品目录 | Admin / Editor / Reviewer |
+| `supportCenter` | 支持中心 | Admin / Editor / Reviewer |
+| `operations` | 运营管理 | Admin / Editor / Reviewer |
+| `salesChannels` | 销售渠道 | Admin / Editor / Reviewer |
+| `assetLibrary` | 素材库 | Admin / Editor / Reviewer |
+| `mediaAssetManagement` | 媒体资料包管理 | Admin / Editor / Reviewer |
+| `contentPublishing` | 内容发布 | Admin / Editor / Reviewer |
+| `siteManagement` | 站点管理 | Admin / Editor / Reviewer |
+
+**角色说明:**
+- **Admin**:拥有所有模块的完整权限(读、写、删)
+- **Editor**:仅对被勾选授权的模块拥有读取和编辑权限;删除需要额外勾选"删除权限"
+- **Reviewer**:仅对被勾选授权的模块拥有只读权限
+
+---
+
+## Collections(集合)
+
+### 产品目录 Product Catalog
+
+#### Products(产品)
+
+| 项目 | 说明 |
+|------|------|
+| 用途 | 产品主记录,驱动产品模板页、编辑器页面、奖项、下载、SEO |
+| 前端位置 | `/products/[slug]` 产品详情页;`/products` 产品列表页 |
+| 关键字段 | 型号(Model)、链接标识(Slug)、状态(Status)、分类(Category)、模板(Template) |
+| 多语言 | 英文和中文产品作为独立文档维护 |
+
+**主要 Tab 页:**
+
+- **概览**:名称、副标题、摘要、描述正文
+- **媒体素材**:头图、移动端头图、卡片图、场景图、头图视频、相册
+- **内容**:核心卖点(数组)、技术亮点、规格参数(分组数组)
+- **分发设置**:产品页下载按钮开关、相关产品、配件、推荐经销商
+- **奖项**:奖项列表(Logo、名称、年份、链接)
+- **SEO**:页面级 SEO 元数据
+
+---
+
+#### Product Categories(产品分类)
+
+| 项目 | 说明 |
+|------|------|
+| 用途 | 产品目录的导航与分组分类 |
+| 前端位置 | `/products` 产品列表页的分类筛选与导航 |
+| 关键字段 | Slug、名称(Name)、副标题(Subtitle)、头图(Hero Image)、排序(Order) |
+| 多语言 | 英文和中文分类作为独立文档维护 |
+
+---
+
+#### Downloads(下载条目)
+
+| 项目 | 说明 |
+|------|------|
+| 用途 | 固件包、说明书、软件安装包、发布说明,关联到产品 |
+| 前端位置 | `/downloads` 下载中心列表页;`/downloads/[slug]` 下载详情页;`/products/[slug]` 产品详情页的下载区块 |
+| 关键字段 | 标题、分类(固件/说明书/软件/其他)、关联产品、版本号、发布日期、安装包文件、第三方下载地址、更新日志 |
+| 多语言 | 英文和中文下载条目作为独立文档维护 |
+
+**注意**:修改下载条目会自动刷新 `/downloads`、`/products` 和 `/sitemap.xml` 的缓存。
+
+---
+
+#### Product Videos(产品视频)
+
+| 项目 | 说明 |
+|------|------|
+| 用途 | 产品关联的视频条目,用于产品详情页和营销区块 |
+| 前端位置 | `/products/[slug]` 产品详情页的视频区块 |
+| 关键字段 | 标题、关联产品、平台(YouTube/Vimeo/Bilibili)、视频链接、嵌入链接、缩略图 |
+| 多语言 | 英文和中文视频条目作为独立文档维护 |
+
+---
+
+#### Product Reviews(外部评测)
+
+| 项目 | 说明 |
+|------|------|
+| 用途 | 外部评测文章的引用、缩略图和外链;首页评测引用也从此集合获取 |
+| 前端位置 | `/products/[slug]` 产品详情页的评测区块;`/reviews` 视频与评测页面;首页评测引用模块 |
+| 关键字段 | 标题、关联产品、来源名称、评测链接、缩略图、摘要、引用语 |
+| 多语言 | 英文和中文评测条目作为独立文档维护 |
+
+---
+
+### 支持中心 Support Center
+
+#### FAQ Categories(常见问题分类)
+
+| 项目 | 说明 |
+|------|------|
+| 用途 | FAQ 列表的主题分类,用于前台 FAQ 页面的分类筛选 |
+| 前端位置 | `/support/faq` FAQ 页面的分类标签 |
+| 关键字段 | Slug、名称、描述、排序 |
+| 多语言 | 英文和中文分类作为独立文档维护 |
+
+---
+
+#### FAQs(常见问题)
+
+| 项目 | 说明 |
+|------|------|
+| 用途 | 支持知识库条目,驱动 FAQ 中心和产品帮助流 |
+| 前端位置 | `/support/faq` FAQ 页面;`/products/[slug]` 产品详情页的帮助区块 |
+| 关键字段 | 分类、问题、答案(富文本)、关联产品、关联下载(联动选择)、关联素材库文件 |
+| 多语言 | 英文和中文 FAQ 作为独立文档维护 |
+
+**操作提示**:选择"下载型号"后,"关联下载"的下拉选项会自动筛选为该产品下的下载条目。
+
+---
+
+#### Video Tutorials(视频教程)
+
+| 项目 | 说明 |
+|------|------|
+| 用途 | 支持教程视频,展示在公开教程页面 |
+| 前端位置 | `/support/tutorial` 教程页面 |
+| 关键字段 | 标题、封面图、视频链接、嵌入链接、平台、发布时间、排序 |
+| 多语言 | 英文和中文视频作为独立文档维护 |
+
+---
+
+### 运营管理 Operations
+
+#### After-Service Requests(售后请求)
+
+| 项目 | 说明 |
+|------|------|
+| 用途 | 售后表单提交记录(用户通过前台售后表单提交) |
+| 前端位置 | 前台 `/support/contact` 联系支持页面的售后表单(仅提交,不在前台展示) |
+| 关键字段 | 姓名、邮箱、国家、电话、购买渠道、购买日期、产品型号、序列号、问题摘要、详细描述、附件照片 |
+| 工作流 | 状态(新/跟进中/已关闭)、跟进负责人、IP 地址、用户代理 |
+
+---
+
+#### Distributor Requests(经销合作请求)
+
+| 项目 | 说明 |
+|------|------|
+| 用途 | 经销商合作申请提交记录 |
+| 前端位置 | 前台联系表单(仅提交,不在前台展示) |
+| 关键字段 | 公司名称、联系人、邮箱、电话、国家、官网、渠道经验、业务说明 |
+| 工作流 | 状态、跟进负责人 |
+
+---
+
+#### OEM Requests(OEM 请求)
+
+| 项目 | 说明 |
+|------|------|
+| 用途 | OEM / 企业定制询价提交记录 |
+| 前端位置 | 前台联系表单(仅提交,不在前台展示) |
+| 关键字段 | 公司名称、联系人、邮箱、电话、国家、项目类型、项目说明 |
+| 工作流 | 状态、跟进负责人 |
+
+---
+
+#### Support Photos(售后图片)
+
+| 项目 | 说明 |
+|------|------|
+| 用途 | 售后表单中用户上传的图片附件 |
+| 前端位置 | 后台查看售后请求时显示,不在前台展示 |
+| 关键字段 | 文件名、MIME 类型、文件大小、描述 |
+
+---
+
+### 销售渠道 Sales Channels
+
+#### Dealers(经销商)
+
+| 项目 | 说明 |
+|------|------|
+| 用途 | 经销商和分销商记录,用于经销商查找器和产品页推荐经销商 |
+| 前端位置 | `/where-to-buy` 购买渠道页面的经销商列表和地图;`/products/[slug]` 产品详情页的推荐经销商 |
+| 关键字段 | 名称、类型(经销商/体验店)、区域、国家、城市、地址、邮箱、电话、网站、Logo、门店图片、是否授权、排序 |
+| 多语言 | 英文和中文经销商作为独立文档维护 |
+
+---
+
+### 素材库 Asset Library
+
+#### Media(媒体图片)
+
+| 项目 | 说明 |
+|------|------|
+| 用途 | 全站图片上传集合,其他集合的图片字段均关联到此 |
+| 前端位置 | 不直接对应前端页面;通过关联关系间接出现在各页面 |
+| 说明 | Payload CMS 内置的上传集合,文件存储在服务器 `/media` 目录 |
+
+#### Files(文件)
+
+| 项目 | 说明 |
+|------|------|
+| 用途 | 通用文件上传集合(PDF、压缩包等),FAQ 关联资源和下载条目引用此集合 |
+| 前端位置 | 不直接对应前端页面;通过关联关系间接出现在各页面 |
+| 说明 | 文件存储在服务器 `/files` 目录 |
+
+#### Videos(视频文件)
+
+| 项目 | 说明 |
+|------|------|
+| 用途 | 视频文件上传集合,产品头图视频和首页 Hero 视频引用此集合 |
+| 前端位置 | 不直接对应前端页面;通过关联关系间接出现在各页面 |
+| 说明 | 文件存储在服务器 `/videos` 目录 |
+
+---
+
+### 媒体资料包管理 Media Asset Management
+
+#### Media Asset Categories(资料分类)
+
+| 项目 | 说明 |
+|------|------|
+| 用途 | 媒体资料包的分类体系,支持两级层级(一级分类 → 二级分类) |
+| 前端位置 | `/media-assets` 资料包首页 → `/media-assets/[category]` 二级分类页 → `/media-assets/[category]/[subcategory]` 三级详情页 |
+| 关键字段 | 上级分类(为空则为一级)、名称、Slug、分类图片、描述、排序、压缩包下载地址 |
+| 约束 | 只能选择一级分类作为上级;已有子分类的分类不能移到其他分类下 |
+
+---
+
+#### Assets(资料列表)
+
+| 项目 | 说明 |
+|------|------|
+| 用途 | 单个图片、PDF、设计文件、视频等素材条目,属于二级分类 |
+| 前端位置 | `/media-assets/[category]/[subcategory]` 资料详情列表页 |
+| 关键字段 | 所属二级分类、标题、类型(图片/PDF/AI/PSD/视频/通用文件)、缩略图、预览/下载外链、文件格式、文件大小、描述、排序 |
+| 约束 | 必须分配到二级分类,不能分配到一级分类 |
+
+---
+
+### 内容发布 Content Publishing
+
+#### News Categories(新闻分类)
+
+| 项目 | 说明 |
+|------|------|
+| 用途 | 本地 CMS 新闻的分类管理 |
+| 前端位置 | `/news` 新闻列表页的分类筛选 |
+| 关键字段 | Slug、名称、描述、排序 |
+| 多语言 | 英文和中文分类作为独立文档维护 |
+
+---
+
+#### News(新闻)
+
+| 项目 | 说明 |
+|------|------|
+| 用途 | 编辑新闻故事,用于新闻列表页和首页新闻精选 |
+| 前端位置 | `/news` 新闻列表页;`/news/[slug]` 新闻详情页;首页新闻区块(当新闻来源设为"本站新闻"时) |
+| 关键字段 | Slug、分类、标题、摘要、封面图、正文(富文本)、作者、发布时间、关联产品 |
+| 多语言 | 英文和中文新闻作为独立文档维护 |
+
+---
+
+#### Redirects(重定向)
+
+| 项目 | 说明 |
+|------|------|
+| 用途 | URL 重定向规则,用于网站迁移、SEO 优化、旧链接跳转 |
+| 前端位置 | 无独立前端页面;在 Next.js 路由层拦截匹配的请求并重定向 |
+| 关键字段 | 源路径(From)、目标路径(To)、状态码(301/302/307/308)、匹配类型(精确/前缀/正则)、语言(any/en/zh)、启用开关 |
+
+---
+
+### 系统设置 System Settings
+
+#### Users(用户)
+
+| 项目 | 说明 |
+|------|------|
+| 用途 | 后台管理员账户管理 |
+| 前端位置 | 仅后台可见,不影响前台 |
+| 关键字段 | 邮箱、密码、角色(Admin/Editor/Reviewer)、允许访问的模块、删除权限 |
+
+---
+
+### 外部媒体资源(辅助集合)
+
+#### AWS Media Resources / Qiniu Media Resources
+
+| 项目 | 说明 |
+|------|------|
+| 用途 | AWS S3 和七牛云的外部媒体资源记录,提供"上传到 S3 / 七牛"按钮获取外链 |
+| 前端位置 | 无独立前端页面;上传后生成的外链填入到 Media Assets 的"预览/下载外链"字段 |
+
+---
+
+## Globals(全局配置)
+
+### 站点管理 Site Management
+
+#### Homepage(首页)
+
+| 项目 | 说明 |
+|------|------|
+| 前端位置 | `/`(首页) |
+| 可配置内容 | |
+
+- **Hero Slides(首屏多图)**:最多 8 张,每张支持图片/视频模式、眉题、主标题、辅助文案、CTA 按钮、文字位置、遮罩开关、移动端独立图片
+- **Module Order(模块顺序)**:拖拽决定"Banner 区"和"精选产品"哪个先显示
+- **Hero Banners(轮播 Banner)**:首屏下方的轮播 Banner 条,支持标题、图片地址、链接
+- **Featured Products(精选产品卡片)**:3–8 张独立产品卡片,与 Products 集合无关联,在此独立配置图片、文案、链接、文字样式
+- **Featured Layout(精选布局)**:选择布局样式(一排 2/3/4 个、左大右小、横向展陈、杂志堆叠)
+- **Statement(品牌主张)**:眉题、标题、正文、图片、CTA
+- **Recognition(品牌认可)**:奖项列表 + 评测引用列表(首页展示)
+- **Show News Section**:开关控制首页是否显示新闻区块
+- **News Source(新闻来源)**:选择首页新闻取自外部 Blog API 还是本站 CMS 新闻
+- **News Highlights(新闻精选)**:当来源为本地新闻时,手动选择最多 6 篇展示
+- **SEO**:首页级 SEO 元数据(含 canonical、focus keywords、noindex)
+
+---
+
+#### Global Settings(全局设置)
+
+| 项目 | 说明 |
+|------|------|
+| 前端位置 | 全站所有页面 |
+| 可配置内容 | |
+
+- **Site(站点信息)**:站点名称、标语、浅底/深底 Logo、Favicon
+- **Navigation(导航)**:
+ - 主导航菜单(名称、链接、外部链接、新窗口、图标键名)
+ - APP 按钮(文字、链接、桌面端/移动端显示开关)
+- **Footer(页脚)**:
+ - 页脚栏目(标题 + 链接项数组)
+ - 法律链接(隐私政策等)
+ - 版权文案
+- **Social Links(社交链接)**:平台名、展示形式(链接/二维码)、URL、二维码图片、图标键名
+- **SEO Defaults(SEO 默认值)**:标题后缀、默认描述、默认分享图
+- **Sitemap(站点地图)**:控制 `/sitemap.xml` 中包含哪些页面模块的开关(首页、产品、支持、下载、新闻、评测、购买渠道、关于、联系等共 16 项)
+
+---
+
+#### About Page(关于页面)
+
+| 项目 | 说明 |
+|------|------|
+| 前端位置 | `/about` |
+| 可配置内容 | 首屏(眉题、标题、正文、大图、移动端图、文字位置);内容 HTML(支持 HTML 的全文内容区块) |
+| 隐藏字段 | 品牌故事、品牌理念、编辑导语、内容段落、能力支柱、奖项高光、媒体引述(当前不在前端显示) |
+
+---
+
+#### Products Page(产品列表页)
+
+| 项目 | 说明 |
+|------|------|
+| 前端位置 | `/products` |
+| 可配置内容 | Hero 首屏(眉题、标题、描述、图片、移动端图、文字位置) |
+
+---
+
+#### Support Page(支持页面)
+
+| 项目 | 说明 |
+|------|------|
+| 前端位置 | `/support` |
+| 可配置内容 | |
+
+- **Intro(首屏)**:眉题、标题、正文、大图、移动端图、文字位置
+- **Primary Entries(主入口卡片)**:键名、图标键名/自定义图标图、眉题、名称、说明、链接
+- **Support Path Card(支持路径卡片)**:眉题、标题、说明、按钮文案与链接
+- 首页支持区块快捷入口也使用此集合的数据
+
+---
+
+#### FAQ Page(FAQ 页面)
+
+| 项目 | 说明 |
+|------|------|
+| 前端位置 | `/support/faq` |
+| 可配置内容 | Hero 首屏;统计卡片(答案标签、主题标签);联系支持 CTA(文案与链接);支持路径卡片 |
+
+---
+
+#### Contact Page(联系支持页面)
+
+| 项目 | 说明 |
+|------|------|
+| 前端位置 | `/support/contact` |
+| 可配置内容 | |
+
+- **Intro(首屏)**:眉题、标题、正文、大图、移动端图、文字位置
+- **Submission Guidance(提交说明)**:标题、说明文案、提示项数组、快捷链接、富文本(如二维码)
+- **Form Enabled(启用表单)**:开关控制前台售后表单是否可用
+- **Form Disabled Message(表单关闭提示)**:表单关闭时的替代提示文案
+
+---
+
+#### Contact Us Page(联系我们页面)
+
+| 项目 | 说明 |
+|------|------|
+| 前端位置 | `/contact` |
+| 可配置内容 | |
+
+- **Hero(首屏)**:眉题、标题、描述、图片、移动端图、文字位置
+- **Contact Groups(联系方式分组)**:标题、说明、条目数组(标签、内容、链接)
+- **Form Intro(表单说明)**:眉题、标题、描述
+
+---
+
+#### Warranty Page(保修页面)
+
+| 项目 | 说明 |
+|------|------|
+| 前端位置 | `/support/warranty` |
+| 可配置内容 | |
+
+- **Intro(首屏)**:眉题、标题、正文、大图、移动端图、文字位置
+- **Policy Header(保修说明头部)**:眉题、标题、说明文案
+- **Policy Body(保修正文)**:富文本
+- **Service Panel(服务面板)**:清单标题、说明、清单项数组、快捷链接
+
+---
+
+#### Downloads Page(下载列表页)
+
+| 项目 | 说明 |
+|------|------|
+| 前端位置 | `/downloads` |
+| 可配置内容 | Hero 首屏(眉题、标题、描述、图片、移动端图、外部图片地址、文字位置);系列导航标签 |
+
+---
+
+#### Reviews Page(评测页面)
+
+| 项目 | 说明 |
+|------|------|
+| 前端位置 | `/reviews` |
+| 可配置内容 | Hero 首屏(眉题、标题、描述、图片、移动端图、外部图片地址、文字位置) |
+
+---
+
+#### News Page Settings(新闻页面设置)
+
+| 项目 | 说明 |
+|------|------|
+| 前端位置 | `/news` |
+| 可配置内容 | Hero 首屏(眉题、标题、描述、图片、移动端图、外部图片地址、文字位置);新闻来源切换(外部 Blog API / 本站新闻内容) |
+
+---
+
+#### Support Tutorial Page(支持教程页面)
+
+| 项目 | 说明 |
+|------|------|
+| 前端位置 | `/support/tutorial` |
+| 可配置内容 | Hero 首屏;来源链接;介绍 HTML(可选 HTML 显示在视频列表上方) |
+
+---
+
+#### Where to Buy Page(购买渠道页面)
+
+| 项目 | 说明 |
+|------|------|
+| 前端位置 | `/where-to-buy` |
+| 可配置内容 | |
+
+- **Hero(首屏)**:眉题、标题、描述、按钮文案与链接、图片、移动端图、文字位置
+- **Store Links(商城链接)**:最多 4 个购买入口卡片(标题、描述、链接文案、链接、图片)
+- **Business Contact Card(商务合作卡片)**:眉题、标题、按钮文案与链接
+- **Show Dealers(显示经销商)**:开关控制是否显示经销商 Tab、地图、列表
+- **Map(地图)**:是否显示经销商地图
+- **Empty State(空状态)**:无经销商/无体验店时的提示文案
+
+---
+
+### 媒体资料包管理 Media Asset Management
+
+#### Media Assets Page(媒体资料页)
+
+| 项目 | 说明 |
+|------|------|
+| 前端位置 | `/media-assets` |
+| 可配置内容 | 顶部文案(眉题、标题、描述) |
+| 注意 | 保存后自动刷新 `/media-assets` 和 `/sitemap.xml` 缓存 |
+
+---
+
+## 前端路由与 CMS 对应总览表
+
+| 前端路由 | 消费的 Global | 消费的 Collection |
+|---------|--------------|-------------------|
+| `/`(首页) | Homepage | Product Reviews(评测引用)、News(新闻精选)、Support Page(支持快捷卡片) |
+| `/products` | Products Page | Products、Product Categories |
+| `/products/[slug]` | — | Products、Product Videos、Product Reviews、Downloads、Dealers |
+| `/downloads` | Downloads Page | Downloads |
+| `/downloads/[slug]` | — | Downloads、Products |
+| `/support` | Support Page | — |
+| `/support/faq` | FAQ Page | FAQs、FAQ Categories |
+| `/support/contact` | Contact Page | After Service Requests(表单提交) |
+| `/support/warranty` | Warranty Page | — |
+| `/support/tutorial` | Support Tutorial Page | Support Tutorial Videos |
+| `/news` | News Page | News、News Categories |
+| `/news/[slug]` | — | News |
+| `/reviews` | Reviews Page | Product Videos、Product Reviews |
+| `/where-to-buy` | Dealers Page | Dealers |
+| `/contact` | Contact Us Page | Distributor Requests、OEM Requests(表单提交) |
+| `/about` | About Page | — |
+| `/media-assets` | Media Assets Page | Media Asset Categories |
+| `/media-assets/[category]` | — | Media Asset Categories |
+| `/media-assets/[category]/[subcategory]` | — | Media Assets、Media Asset Categories |
+| 全局(所有页面) | Global Settings | Media(图片)、Redirects(重定向) |
diff --git a/src/app/(frontend)/[locale]/about/page.tsx b/src/app/(frontend)/[locale]/about/page.tsx
index e4c1bcf..ed6adfa 100644
--- a/src/app/(frontend)/[locale]/about/page.tsx
+++ b/src/app/(frontend)/[locale]/about/page.tsx
@@ -92,7 +92,7 @@ export default async function AboutPage({
name: pageTitle || undefined,
publisher: {
'@type': 'Organization',
- name: 'Eversolo',
+ name: 'Luxsin',
},
url: buildAbsoluteUrl(`/${locale}/about`),
}),
diff --git a/src/app/(frontend)/[locale]/downloads/[slug]/page.tsx b/src/app/(frontend)/[locale]/downloads/[slug]/page.tsx
index 1b7eb23..6b5c4b5 100644
--- a/src/app/(frontend)/[locale]/downloads/[slug]/page.tsx
+++ b/src/app/(frontend)/[locale]/downloads/[slug]/page.tsx
@@ -128,14 +128,14 @@ function getDownloadSeoTypePhrase(downloads: DownloadItem[], locale: Locale) {
function getDownloadAutoSeoTitle(title: string, downloads: DownloadItem[], locale: Locale) {
const typePhrase = getDownloadSeoTypePhrase(downloads, locale)
- return `${title} ${typePhrase} | Eversolo`
+ return `${title} ${typePhrase} | Luxsin`
}
function getDownloadAutoSeoDescription(title: string, downloads: DownloadItem[], locale: Locale) {
const typePhrase = getDownloadSeoTypePhrase(downloads, locale)
return locale === 'zh'
? `下载 ${title} ${typePhrase}、更新日志和历史版本。`
- : `Download ${title} ${typePhrase}, release notes, and version history from Eversolo.`
+ : `Download ${title} ${typePhrase}, release notes, and version history from Luxsin.`
}
function DownloadTypeIcon({ type }: { type: string }) {
diff --git a/src/app/(frontend)/[locale]/downloads/page.tsx b/src/app/(frontend)/[locale]/downloads/page.tsx
index 98ba147..4377e11 100644
--- a/src/app/(frontend)/[locale]/downloads/page.tsx
+++ b/src/app/(frontend)/[locale]/downloads/page.tsx
@@ -712,7 +712,7 @@ export default async function DownloadsPage({
item,
position: index + 1,
})),
- name: locale === 'zh' ? 'Eversolo 下载中心' : 'Eversolo Downloads Center',
+ name: locale === 'zh' ? 'Luxsin 下载中心' : 'Luxsin Downloads Center',
url: buildAbsoluteUrl(`/${locale}/downloads`),
}),
}}
diff --git a/src/app/(frontend)/[locale]/media-assets/[category]/[subcategory]/page.tsx b/src/app/(frontend)/[locale]/media-assets/[category]/[subcategory]/page.tsx
index c06cdb0..36a16c5 100644
--- a/src/app/(frontend)/[locale]/media-assets/[category]/[subcategory]/page.tsx
+++ b/src/app/(frontend)/[locale]/media-assets/[category]/[subcategory]/page.tsx
@@ -47,7 +47,7 @@ export async function generateMetadata({
return buildSeoMetadata({
description:
pageData.subcategory.description ||
- (locale === 'zh' ? '下载 Eversolo 媒体资料。' : 'Download Eversolo media assets.'),
+ (locale === 'zh' ? '下载 Luxsin 媒体资料。' : 'Download Luxsin media assets.'),
locale,
ogImage: pageData.subcategory.imageUrl,
pathname: `/media-assets/${category}/${subcategory}`,
diff --git a/src/app/(frontend)/[locale]/media-assets/[category]/page.tsx b/src/app/(frontend)/[locale]/media-assets/[category]/page.tsx
index f6b6b47..cd25de5 100644
--- a/src/app/(frontend)/[locale]/media-assets/[category]/page.tsx
+++ b/src/app/(frontend)/[locale]/media-assets/[category]/page.tsx
@@ -30,7 +30,7 @@ export async function generateMetadata({
return buildSeoMetadata({
description:
pageData.category.description ||
- (locale === 'zh' ? '浏览 Eversolo 媒体资料分类。' : 'Browse Eversolo media asset categories.'),
+ (locale === 'zh' ? '浏览 Luxsin 媒体资料分类。' : 'Browse Luxsin media asset categories.'),
locale,
ogImage: pageData.category.imageUrl,
pathname: `/media-assets/${category}`,
diff --git a/src/app/(frontend)/[locale]/news/[slug]/page.tsx b/src/app/(frontend)/[locale]/news/[slug]/page.tsx
index b0ae8e1..2a223a0 100644
--- a/src/app/(frontend)/[locale]/news/[slug]/page.tsx
+++ b/src/app/(frontend)/[locale]/news/[slug]/page.tsx
@@ -133,7 +133,7 @@ export default async function NewsArticlePage({
image: coverImageUrl ? [coverImageUrl] : undefined,
publisher: {
'@type': 'Organization',
- name: 'Eversolo',
+ name: 'Luxsin',
},
url: articleUrl,
}),
diff --git a/src/app/(frontend)/[locale]/news/page.tsx b/src/app/(frontend)/[locale]/news/page.tsx
index 3acecfa..c28fe90 100644
--- a/src/app/(frontend)/[locale]/news/page.tsx
+++ b/src/app/(frontend)/[locale]/news/page.tsx
@@ -225,7 +225,7 @@ export default async function NewsPage({
'@context': 'https://schema.org',
'@type': 'ItemList',
itemListElement: itemListElements,
- name: locale === 'zh' ? 'Eversolo 新闻列表' : 'Eversolo News List',
+ name: locale === 'zh' ? 'Luxsin 新闻列表' : 'Luxsin News List',
}),
}}
/>
diff --git a/src/app/(frontend)/[locale]/not-found.tsx b/src/app/(frontend)/[locale]/not-found.tsx
index 9a8e346..aeb6b99 100644
--- a/src/app/(frontend)/[locale]/not-found.tsx
+++ b/src/app/(frontend)/[locale]/not-found.tsx
@@ -8,7 +8,7 @@ const COPY = {
eyebrow: '404',
title: 'This page is out of range.',
description:
- 'The address may have changed, or the content may no longer be available. Return home or continue through the main Eversolo paths.',
+ 'The address may have changed, or the content may no longer be available. Return home or continue through the main Luxsin paths.',
home: 'Back to Home',
support: 'Open Support',
pathsLabel: 'Useful paths',
diff --git a/src/app/(frontend)/[locale]/page.tsx b/src/app/(frontend)/[locale]/page.tsx
index c821d97..44cf980 100644
--- a/src/app/(frontend)/[locale]/page.tsx
+++ b/src/app/(frontend)/[locale]/page.tsx
@@ -300,7 +300,7 @@ export async function generateMetadata({
extractRichTextPlainText(homepage.statement?.body) ||
undefined
const title =
- homepage.seo?.title?.trim() || (locale === 'zh' ? 'Eversolo 官方网站' : 'Eversolo Official Site')
+ homepage.seo?.title?.trim() || (locale === 'zh' ? 'Luxsin 官方网站' : 'Luxsin Official Site')
return buildSeoMetadata({
description,
@@ -397,7 +397,7 @@ export default async function HomePage({
__html: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'Organization',
- name: 'Eversolo',
+ name: 'Luxsin',
slogan: chrome.siteTagline,
url: buildAbsoluteUrl(`/${locale}`),
}),
diff --git a/src/app/(frontend)/[locale]/products/[slug]/page.tsx b/src/app/(frontend)/[locale]/products/[slug]/page.tsx
index d3b49b7..7eddfc5 100644
--- a/src/app/(frontend)/[locale]/products/[slug]/page.tsx
+++ b/src/app/(frontend)/[locale]/products/[slug]/page.tsx
@@ -145,7 +145,7 @@ function getProductAutoSeoTitle(product: Product, slug: string, locale: Locale)
? `${productName} ${seriesName}`
: productName
- return `${baseTitle} | Eversolo`
+ return `${baseTitle} | Luxsin`
}
type RichTextNodeLike = {
diff --git a/src/app/(frontend)/[locale]/products/page.tsx b/src/app/(frontend)/[locale]/products/page.tsx
index b5bfdef..175bb38 100644
--- a/src/app/(frontend)/[locale]/products/page.tsx
+++ b/src/app/(frontend)/[locale]/products/page.tsx
@@ -199,8 +199,8 @@ export async function generateMetadata({
description:
page.hero?.description ||
(locale === 'zh'
- ? '浏览 Eversolo 的流媒体播放器、解码器、功放与配件产品阵列。'
- : 'Browse the Eversolo lineup across streamers, DACs, amplifiers, and accessories.'),
+ ? '浏览 Luxsin 的流媒体播放器、解码器、功放与配件产品阵列。'
+ : 'Browse the Luxsin lineup across streamers, DACs, amplifiers, and accessories.'),
locale,
ogImage: page.hero?.image || null,
pathname: '/products',
@@ -229,8 +229,8 @@ export default async function ProductsPage({
pageSeo,
hero?.description?.trim() ||
(locale === 'zh'
- ? '浏览 Eversolo 的流媒体播放器、解码器、功放与配件产品阵列。'
- : 'Browse the Eversolo lineup across streamers, DACs, amplifiers, and accessories.'),
+ ? '浏览 Luxsin 的流媒体播放器、解码器、功放与配件产品阵列。'
+ : 'Browse the Luxsin lineup across streamers, DACs, amplifiers, and accessories.'),
)
const categoryMap = new Map(
categories.map((category) => [category.slug, normalizeCategory(category, category.slug, locale)]),
@@ -268,7 +268,7 @@ export default async function ProductsPage({
'@context': 'https://schema.org',
'@type': 'ItemList',
itemListElement: itemList,
- name: locale === 'zh' ? 'Eversolo 产品中心' : 'Eversolo Products',
+ name: locale === 'zh' ? 'Luxsin 产品中心' : 'Luxsin Products',
}),
}}
/>
diff --git a/src/app/(frontend)/[locale]/reviews/page.tsx b/src/app/(frontend)/[locale]/reviews/page.tsx
index 933ae49..adea1da 100644
--- a/src/app/(frontend)/[locale]/reviews/page.tsx
+++ b/src/app/(frontend)/[locale]/reviews/page.tsx
@@ -291,8 +291,8 @@ export default async function ReviewsPage({
'@type': 'CollectionPage',
description:
locale === 'zh'
- ? 'Eversolo 产品视频与媒体评测。'
- : 'Eversolo product videos and editorial reviews.',
+ ? 'Luxsin 产品视频与媒体评测。'
+ : 'Luxsin product videos and editorial reviews.',
name: 'Videos & Reviews',
url: buildAbsoluteUrl(`/${locale}/reviews`),
}),
diff --git a/src/app/(frontend)/[locale]/support/page.tsx b/src/app/(frontend)/[locale]/support/page.tsx
index 2f695e7..0392ad7 100644
--- a/src/app/(frontend)/[locale]/support/page.tsx
+++ b/src/app/(frontend)/[locale]/support/page.tsx
@@ -231,7 +231,7 @@ export default async function SupportPage({
'@context': 'https://schema.org',
'@type': 'ItemList',
itemListElement: itemListElements,
- name: locale === 'zh' ? 'Eversolo 支持中心' : 'Eversolo Support Center',
+ name: locale === 'zh' ? 'Luxsin 支持中心' : 'Luxsin Support Center',
}),
}}
/>
diff --git a/src/app/(frontend)/[locale]/where-to-buy/page.tsx b/src/app/(frontend)/[locale]/where-to-buy/page.tsx
index 903b7fd..26441be 100644
--- a/src/app/(frontend)/[locale]/where-to-buy/page.tsx
+++ b/src/app/(frontend)/[locale]/where-to-buy/page.tsx
@@ -617,7 +617,7 @@ export default async function WhereToBuyPage({
item,
position: index + 1,
})),
- name: locale === 'zh' ? 'Eversolo 授权经销商网络' : 'Eversolo Authorized Dealer Network',
+ name: locale === 'zh' ? 'Luxsin 授权经销商网络' : 'Luxsin Authorized Dealer Network',
url: buildAbsoluteUrl(`/${locale}/where-to-buy`),
}),
}}
diff --git a/src/components/home/home-featured-products.tsx b/src/components/home/home-featured-products.tsx
index 6bf46af..630017f 100644
--- a/src/components/home/home-featured-products.tsx
+++ b/src/components/home/home-featured-products.tsx
@@ -275,7 +275,7 @@ export function HomeFeaturedProducts({ forceDocumentNavigationHrefs = [], items,