Files
agent-profiles/suites-help/前端设计约定.md
T

11 KiB
Raw Blame History

🏗️ AgentGIS 前端约定

目的: 减少每个子系统在前端上的反复调整,一次定规矩,后续照做。 适用: suite-market、auth-center、discussions 等所有 Next.js 前端。 版本: v1.0 (2026-07-21)


一、页面骨架

所有页面使用统一的三段式骨架布局,不另起炉灶:

┌──────────────────────────────────────────────┐
│ 顶部导航(Navbar)                             │
│ 套件 | 发布 | 管理 | 文档    [登录/用户头像]   │
├────────┬─────────────────────────────────────┤
│ 左侧   │           右侧内容区                  │
│ 导航   │   (各页面自定)                      │
│        │                                     │
│ (各页面  │                                     │
│  自定)  │                                     │
└────────┴─────────────────────────────────────┘
└────────────── 页脚(Footer) ──────────────────┘

规则:

  • 顶部导航统一在 Navbar.tsx 维护,不单独定制
  • 左侧导航通过页面级 layout.tsx 注入(Next.js App Router
  • 页脚全局统一
  • 不出现面包屑(用左侧导航替代)

二、未认证状态

所有需要登录的页面,未认证时必须做到:

┌─────────────────────────────────────┐
│     🔒 请登录后浏览                  │
│                                      │
│  登录后可查看套件、文档、管理后台等    │
│                                      │
│  (不显示登录按钮 — header 右上角有) │
└─────────────────────────────────────┘

规则:

  • 使用统一 LoginPrompt.tsx 组件,不自制
  • 不显示登录按钮/链接(header 右上角已有「登录」按钮)
  • API 调用返回 401 时,前端必须捕获并切换到 LoginPrompt不能卡在加载中
  • 公开页面(首页等)不需登录,正常渲染

三、数据加载与错误处理

所有页面按此顺序处理状态:

加载中 → 出错 → 空数据 → 正常渲染

规则:

  • 加载中:显示统一的「加载中...」骨架屏
  • 出错(含 401):捕获错误,切换 LoginPrompt 或显示错误信息
  • 空数据:显示「暂无内容」+ 引导文案
  • 正常渲染:展示数据
  • 不允许出现「永远卡在加载中」的情况

所有 API 调用都必须有 .catch()

// ✅ 正确
fetchData().then(setData).catch(handleError)

// ❌ 错误
fetchData().then(setData)  // 无 catch = 卡在加载中

四、目录结构

每个 Next.js 前端项目统一按以下结构组织:

frontend/
├── app/                    # App Router 页面
│   ├── layout.tsx          # 全局布局(Navbar + Footer
│   ├── page.tsx            # 首页
│   ├── suites/             # 套件
│   │   ├── layout.tsx      # 套件左侧导航
│   │   ├── page.tsx        # 列表
│   │   └── [id]/page.tsx   # 详情
│   ├── docs/               # 文档
│   │   ├── layout.tsx      # 文档树形导航
│   │   ├── page.tsx
│   │   └── [slug]/page.tsx
│   ├── admin/              # 管理后台
│   │   ├── layout.tsx      # 管理侧边栏
│   │   ├── applications/
│   │   ├── suites/
│   │   └── docs/
│   └── publish/
│
├── components/             # 共享组件
│   ├── Navbar.tsx          # 顶部导航
│   ├── LayoutShell.tsx     # 骨架布局
│   ├── LoginPrompt.tsx     # 未登录提示
│   └── ...                 # 其他通用组件
│
├── lib/                    # 工具库
│   ├── api.ts             # API 封装(含统一 401 处理)
│   ├── auth.ts            # 认证
│   └── auth-context.tsx   # 认证上下文
│
├── public/
├── package.json
└── next.config.ts

规则:

  • app/ 下只放路由文件,不放组件
  • 业务组件放 components/
  • 工具函数放 lib/

五、API 401 拦截器

lib/api.ts 中的 axios 实例统一处理 401:

api.interceptors.response.use(
  (res) => res,
  async (err) => {
    if (err.response?.status === 401 && typeof window !== "undefined") {
      // 公开页面:静默返回错误,让页面组件自己处理
      const path = window.location.pathname;
      if (path === "/" || path.startsWith("/suites") || path.startsWith("/docs")) {
        return Promise.reject(err);
      }
      // 管理类页面:尝试刷新 token
      try {
        const refreshRes = await axios.post(
          "https://auth.mercator.cn/api/v1/public/refresh/",
          {},
          { withCredentials: true }
        );
        if (refreshRes.data?.access_token) {
          setAccessToken(refreshRes.data.access_token);
          err.config.headers["Authorization"] = "Bearer " + refreshRes.data.access_token;
          return axios(err.config);
        }
      } catch {}
      // 刷新失败:跳转登录
      window.location.href = "https://auth.mercator.cn/login?return_url=" + encodeURIComponent(path);
    }
    return Promise.reject(err);
  }
);

规则:

  • 公开页面(suites、docs)的 401 → 静默返回,页面组件切换到 LoginPrompt
  • 管理页面(admin、publish)的 401 → 尝试刷新 token,刷新失败跳转登录
  • 不拦截器里弹 alert 或直接修改 DOM

六、深色/浅色主题

  • 使用 Tailwind dark: 变体控制深色模式
  • 通过 ThemeToggle 组件切换(位于 components/
  • 默认跟随系统 prefers-color-scheme
  • 切换结果存入 localStorage,下次加载优先读取
  • 所有新组件必须同时测试浅色和深色模式

七、页面宽度与容器尺寸

统一使用以下预设宽度:

用途 Tailwind class 说明
最宽布局 max-w-7xl mx-auto 列表页、管理后台
内容页(窄) max-w-3xl mx-auto 详情页、阅读页
内容页(中) max-w-5xl mx-auto 文档列表、套件详情
表单 max-w-lg mx-auto 登录、设置
全宽 max-w-none 极少使用

不允许: 每个页面自定义宽度,导致用户在页面间切换时视觉跳跃。


八、移动端适配

  • 使用 Tailwind 响应式前缀:sm:640px)、md:768px)、lg:1024px)、xl:1280px
  • 导航栏在 lg 断点以下折叠为汉堡菜单(已实现)
  • 左侧导航在 md 以下默认隐藏,通过按钮切换显示
  • 表格在 md 以下切换为卡片视图(每行一张卡片)
  • 不允许仅桌面端可用的设计,所有页面必须跑通 375px 宽度

九、通知(Toast 替代 alert/confirm

  • 不使用浏览器原生的 alert()confirm()prompt()
  • 使用统一的 Toast 通知组件
  • Toast 位置:右上角固定
  • 类型:success(绿色)、error(红色)、warning(黄色)、info(蓝色)
  • 自动消失:success/info 3 秒,warning/error 5 秒
  • 实现:用 react-hot-toast 或自建 ToastProvider

十、布局模板

按是否有侧边导航分两种布局:

带侧边导航

┌──────────┬────────────────────────────────┐
│ 顶部导航  │                                │
├──────────┤        右侧内容区                │
│  侧边栏   │                                │
│  (页面    │                                │
│  自定)    │                                │
└──────────┴────────────────────────────────┘

适用:suites、docs、admin 实现方式:<page>/layout.tsx

无侧边导航(全宽)

┌────────────────────────────────────────────┐
│ 顶部导航                                    │
├────────────────────────────────────────────┤
│                                            │
│              居中内容区                      │
│                                            │
└────────────────────────────────────────────┘

适用:/、/publish 实现方式:<page>/layout.tsx 或直接在 page 中 max-w-* mx-auto


十一、FastAPI 端点避免冲突

suite-market 和 auth-center 后端都是 FastAPI,默认暴露 /docsSwagger UI)、/redoc/openapi.json

如果前端有同名路由(如文档模块的 /docs),会与 FastAPI 默认端点冲突。

必须:

app = FastAPI(
    docs_url="/api/docs",         # 改 /docs → /api/docs
    redoc_url="/api/redoc",       # 改 /redoc → /api/redoc
    openapi_url="/api/openapi.json"  # 改 /openapi.json → /api/openapi.json
)

十二、Header/Footer 统一

  • Header:统一使用 Navbar.tsxcomponents/ 下),不单独在各页面重复
  • Footer:全局底部,包含 ICP 备案号、公安备案号、版权信息
  • Header 和 Footer 在全局 layout.tsx 中加载,页面层不覆盖

十三、组件命名

类型 命名规则 示例
页面组件(app/ PascalCase + Page 后缀 DocsPage, SuiteDetailPage
布局(layout 文件名固定 layout.tsx 不导出命名函数
通用组件 PascalCase LoginPrompt, SuiteCard
工具函数 camelCase fetchDocuments, formatDate
API 函数 camelCase fetchDocuments, createDocument

六、认证

  • header 右上角只有一个「登录」按钮
  • 登录跳转到 auth.mercator.cn
  • 登录后通过 JWT cookie 回传
  • API 调用由 api.ts 中的 axios 实例统一处理(interceptor 自动附带 token

不允许:

  • 页面内部额外加「登录」按钮或链接
  • 手动拼写 Authorization header
  • 直接调用 fetch

七、样式

  • 使用 Tailwind CSS
  • 基础样式在 globals.css 中定义
  • 组件样式使用 Tailwind class,不单独写 CSS 文件
  • 不使用 CSS Modules 或 styled-components

八、落地方式

  1. 此文档纳入 SuiteHub/agent-profiles/suites-help/ 作为平台规范
  2. 新建前端页面时,开发者对照此文档逐一检查
  3. Code Review 时以此文档为标准
  4. 后续如有不合理之处,更新此文档(不改代码,改规矩)