L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Design et création · SKILL.md

hugagent-frontend-dev

hugagent-frontend-dev

HugAgentOS 前端开发规范。当需要新增或修改前端代码(组件、Store、Hook、API调用、样式等)时使用此 skill, 确保组件结构、状态管理、样式命名、类型安全等与项目现有规范保持一致。

Independent GitHub snapshot · Automated classification · Original documentation governs

Zzju-real / hugagentosApache-2.0

Documentation de la Skill

GitHub

name: hugagent-frontend-dev description: HugAgentOS 前端开发规范。当需要新增或修改前端代码(组件、Store、Hook、API调用、样式等)时使用此 skill, 确保组件结构、状态管理、样式命名、类型安全等与项目现有规范保持一致。

HugAgentOS 前端开发规范

本 skill 定义了 HugAgentOS 项目前端(React + TypeScript + Ant Design + Zustand)的开发规范与流程。 所有前端代码变更必须遵守以下规范。

文件索引

模板 (templates/)

文件用途
component.tsxReact 组件模板(Props + Hooks + 错误处理)
store.tsZustand Store 模板(CRUD + localStorage 持久化)
hook.ts自定义 Hook 模板(初始化 + 清理 + abort)
css-module.cssCSS 样式模板(.jx- 前缀 + 响应式)

参考文档 (references/)

文件内容
ui-design-spec.mdUI 设计规范(颜色系统、字体排版、图标、圆角、间距、组件规范、Ant Design 主题映射)
icon-assets.md图标资产清单(全部 SVG 图标索引、使用方式、分类说明)
component-tree.md完整组件树
css-variables.mdCSS 变量、命名规则、常用尺寸、样式模式(与 UI 设计规范对齐)
api-patterns.mdAPI 调用模式(authFetch、SSE)
sse-events.mdSSE 事件类型详解(run_started/content/thinking/tool_call/tool_result/tool_pending/batch_confirm/file_confirm/meta/error + [DONE])

图标资产 (assets/)

目录内容
assets/icons/通用 UI 图标(30 个 SVG:logo、导航、操作按钮、场景图标等)
assets/mcp-icons/MCP 工具库图标(12 个 SVG:互联网、数据、报告、知识等)

脚本 (scripts/)

文件用途
scaffold_component.sh一键生成新组件(.tsx + .css + index.ts)

模板中 ${ComponentName} / ${componentName} / ${group} 为占位符,使用时替换。


1. 目录结构

src/frontend/src/
├── main.tsx                   # 入口:按路径分发应用壳
├── App.tsx                    # 主聊天应用(用户端)
├── ApiDocApp.tsx              # /api-docs 开放 API 文档
├── SharePreviewApp.tsx        # ?share= 分享预览页
├── types.ts                   # 共享 TypeScript 类型
├── api.ts                     # API 客户端(信封解包)
├── storage.ts                 # localStorage 工具 + defaultCatalog
│
├── components/                # 组件组(每组 index.ts barrel export)
│   ├── chat/                  # ChatArea, InputArea, MessageBubble, PromptHubPanel
│   ├── agent/                 # 子智能体
│   ├── apidoc/                # 开放 API 文档
│   ├── automation/            # 定时任务/自动化
│   ├── batch/                 # 批量执行
│   ├── canvas/                # 画布产物
│   ├── catalog/               # CatalogPanel(能力中心)
│   ├── citation/              # CitationBadge, CitationHtmlBlock, CitationMarkdownBlock
│   ├── common/                # AuthExpiredModal, ImagePreview 等
│   ├── docs/                  # DocsPanel(版本说明/能力介绍)
│   ├── file/                  # FileAttachmentCard
│   ├── kb/                    # 知识库(CreateKBModal, ReindexModal 等)
│   ├── lab/                   # 实验室(技能蒸馏等)
│   ├── memory/                # 记忆中心
│   ├── myspace/               # 我的空间
│   ├── projects/              # 项目空间
│   ├── settings/              # SettingsModal(含记忆 L1/L2/L3 Tab)
│   ├── share/                 # 分享
│   ├── sidebar/               # Sidebar
│   └── tool/                  # ToolOutputRenderer, ToolResultPanel
│
├── hooks/                     # 7 个自定义 Hook
│   ├── useChatInit.ts         # 认证、Catalog、会话、消息初始化
│   ├── useChatActions.ts      # 聊天 CRUD、重命名、导出
│   ├── useStreaming.ts        # SSE 流式处理、文件上传、发送逻辑、断线续播
│   ├── usePlanMode.ts         # Plan 模式
│   ├── usePageConfig.ts       # 页面配置
│   ├── useDelayedFlag.ts      # 延迟标志位
│   └── useStallDetector.ts    # 流式停滞检测
│
├── stores/                    # 18 个 Zustand Store
│   ├── authStore.ts           # 认证状态
│   ├── chatStore.ts           # 聊天会话、消息、activeRun
│   ├── catalogStore.ts        # Catalog(技能、智能体、MCP、知识库)
│   ├── uiStore.ts             # UI 面板、搜索、筛选、pending confirm 队列
│   ├── settingsStore.ts       # 记忆、排序、偏好
│   ├── fileStore.ts           # 文件上传
│   ├── kbStore.ts             # 知识库管理
│   ├── agentStore.ts          # 子智能体
│   ├── automationStore.ts / automationChatStore.ts  # 自动化
│   ├── batchStore.ts          # 批量执行(pendingConfirm)
│   ├── canvasStore.ts         # 画布
│   ├── editionStore.ts        # CE/EE 门控(消费 /v1/meta/edition)
│   ├── modelCapabilitiesStore.ts  # 模型能力探测
│   ├── mySpaceStore.ts        # 我的空间
│   ├── pageConfigStore.ts     # 页面配置
│   ├── projectStore.ts        # 项目空间
│   └── skillDistillStore.ts   # 技能蒸馏
│
├── utils/                     # 20+ 工具模块
│   ├── citations.ts           # 引用解析与去重
│   ├── constants.ts           # 工具名称、快捷场景、能力卡片
│   ├── export.ts              # PDF 导出
│   ├── fileParser.ts          # 文件解析、OSS 上传
│   ├── history.ts             # 话题推断、日期分组
│   ├── highlight.ts           # 代码高亮
│   ├── markdown.ts            # Markdown 渲染
│   ├── segments.ts            # 消息分段(thinking/tool/text)
│   ├── apiError.ts / avatar.ts / confirmDelete.ts / date.ts / fileIcon.ts /
│   │   folderTree.ts / iconLibrary.ts / pageConfigDefaults.ts / roles.ts /
│   │   scroll.ts / xlsxRange.ts / codeExecParser.ts / codeExecUtils.ts
│   └── index.ts               # Barrel export
│
├── styles/                    # 18 个 CSS 模块
│   ├── variables.css          # CSS 自定义属性(颜色、阴影)
│   ├── common.css             # 全局工具类
│   ├── chat.css / sidebar.css / catalog.css / tool.css
│   ├── automation.css / automation-timeline.css / batch(并入相关文件)
│   ├── canvas.css / config.css / mcp.css / myspace.css / plan.css
│   └── projects.css / search-modal.css / settings.css / skill-distill.css / team-folder.css

核心原则: 按功能分组,每组有 index.ts barrel export。


2. 组件规范

2.1 组件文件结构

import React, { useState, useMemo, useCallback, useRef } from 'react';
import { Button, Input, message } from 'antd';
import { useChatStore } from '../../stores';
import type { ChatMessage } from '../../types';
import './styles.css';  // 如有独立样式

// 1. Props 接口(以 Props 结尾)
interface MyComponentProps {
  chatId: string;
  onClose: () => void;
  items?: SomeItem[];
}

// 2. 函数式组件(named export)
export function MyComponent({ chatId, onClose, items = [] }: MyComponentProps) {
  // 3. Hooks 在顶层调用
  const { store, currentChatId } = useChatStore();
  const [loading, setLoading] = useState(false);
  const inputRef = useRef<HTMLInputElement>(null);

  // 4. useMemo 用于派生状态
  const filteredItems = useMemo(() => {
    return items.filter(item => item.active);
  }, [items]);

  // 5. useCallback 用于稳定引用
  const handleSubmit = useCallback(async () => {
    setLoading(true);
    try {
      await someApiCall();
      message.success('操作成功');
    } catch (e) {
      message.error(`操作失败:${(e as Error).message}`);
    } finally {
      setLoading(false);
    }
  }, [chatId]);

  // 6. Early return 处理空状态
  if (!items.length) {
    return <div className="jx-empty">暂无数据</div>;
  }

  // 7. JSX 渲染
  return (
    <div className="jx-myComponent">
      {filteredItems.map(item => (
        <div key={item.id} className="jx-myComponent-item">
          {item.name}
        </div>
      ))}
      <Button onClick={handleSubmit} loading={loading}>提交</Button>
    </div>
  );
}

2.2 组件规则

  • 命名: PascalCase,一个文件一个组件
  • 导出: 使用 named export(export function),非 default export
  • Props: 必须定义 TypeScript 接口,以 Props 结尾
  • Hooks: 必须在组件顶层调用,不能在条件/循环中
  • 状态: 全局状态用 Zustand Store,局部状态用 useState
  • 性能: 用 useMemo 缓存计算,useCallback 稳定函数引用
  • 错误处理: try-catch + message.error() 提示用户
  • 注册: 新组件必须在对应目录的 index.ts 中 export

3. Zustand Store 规范

3.1 Store 定义模板

import { create } from 'zustand';

// 1. 定义 State 接口(状态 + Actions)
interface MyState {
  // 状态字段
  items: Item[];
  loading: boolean;
  selectedId: string | null;

  // Actions
  setItems: (items: Item[]) => void;
  setLoading: (loading: boolean) => void;
  selectItem: (id: string | null) => void;
  fetchItems: () => Promise<void>;
}

// 2. 创建 Store
export const useMyStore = create<MyState>((set, get) => ({
  // 初始状态
  items: [],
  loading: false,
  selectedId: null,

  // 简单 setter
  setItems: (items) => set({ items }),
  setLoading: (loading) => set({ loading }),
  selectItem: (id) => set({ selectedId: id }),

  // 异步操作
  fetchItems: async () => {
    set({ loading: true });
    try {
      const data = await getItemsApi();
      set({ items: data });
    } catch (e) {
      console.error('Failed to fetch items:', e);
    } finally {
      set({ loading: false });
    }
  },
}));

3.2 Store 使用方式

// 在组件中(自动订阅 re-render)
const { items, loading, fetchItems } = useMyStore();

// 在回调/事件中(不触发 re-render,用于读取最新值)
const currentItems = useMyStore.getState().items;

// 复杂更新(使用 updater 函数)
useChatStore.getState().updateStore((prev) => ({
  chats: { ...prev.chats, [id]: updatedChat },
  order: [id, ...prev.order.filter(x => x !== id)],
}));

3.3 Store 规则

  • 接口驱动:先定义 interface,再实现
  • 状态与 Actions 在同一接口中
  • 简单更新用 set(),复杂逻辑用 get() 读取当前值
  • 需要持久化的状态在 setter 中调用 localStorage 保存
  • Set/Map 类型用于内部状态(如 expandedToolCalls: Set<string>)

4. 自定义 Hook 规范

// Hook 命名以 use 开头
export function useMyFeature(apiUrl: string) {
  const { someState } = useSomeStore();
  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);

  // useEffect 按关注点分离
  useEffect(() => {
    // 初始化逻辑
    return () => {
      // 清理
      if (timerRef.current) clearTimeout(timerRef.current);
    };
  }, []);

  useEffect(() => {
    // 响应依赖变化
  }, [someState, apiUrl]);

  // 返回对象(函数 + refs)
  return {
    doSomething,
    timerRef,
  };
}

规则:

  • Hook 文件放在 hooks/ 目录
  • 复杂初始化逻辑提取到 Hook 中,保持组件简洁
  • 在 hooks/index.ts 中 barrel export

5. API 调用规范

5.1 API 客户端(api.ts)

// 信封类型
interface ApiEnvelope<T> {
  code: number;
  message: string;
  data: T;
  trace_id?: string;
  timestamp?: number;
}

// 带认证的 fetch
export async function authFetch(url: string, init?: RequestInit): Promise<Response> {
  const headers = new Headers(init?.headers || {});
  const token = getAuthToken();
  if (token) headers.set('Authorization', `Bearer ${token}`);
  const response = await fetch(url, { ...init, headers });
  if (response.status === 401) onUnauthorized?.(loginUrl);
  return response;
}

// 使用示例
const r = await authFetch(`${apiUrl}/v1/catalog`);
const { code, data } = await r.json();

5.2 规则

  • 所有 API 调用通过 authFetch()
  • 请求路径使用 /v1/ 前缀
  • 响应解包:检查 code 字段,取 data
  • 401 响应自动触发登录弹窗

6. TypeScript 类型规范

6.1 核心类型(types.ts)

// 面板导航
export type PanelKey =
  | 'chat' | 'skills' | 'agents' | 'mcp' | 'kb' | 'docs'
  | 'app_center' | 'settings' | 'share_records' | 'my_space'
  | 'ability_center' | 'lab' | 'projects' | 'project_detail';

// 聊天消息
export interface ChatMessage {
  role: ChatRole;
  content: string;
  isMarkdown?: boolean;
  ts: number;
  messageId?: string;
  toolCalls?: ToolCall[];
  thinking?: ThinkingBlock[];
  segments?: MessageSegment[];
  citations?: CitationItem[];
  followUpQuestions?: string[];
  attachments?: Array<{ name: string; mime_type?: string; file_id?: string; download_url?: string }>;
}

// Catalog 项
export interface CatalogItemBase {
  id: string;
  name: string;
  desc: string;
  enabled: boolean;
  tags?: string[];
  detail?: string;
}

6.2 类型规则

  • 所有共享类型定义在 types.ts
  • 组件 Props 接口定义在组件文件中
  • 使用 interface 而非 type(除非需要联合类型)
  • 避免 any,必要时用 unknown + 类型守卫
  • 枚举类型用 type = 'a' | 'b' | 'c' 字面量联合

7. CSS 样式规范

完整设计规范: 参见 references/ui-design-spec.md,包含颜色系统、字体排版、图标、圆角、间距等全部视觉标准。

7.1 命名规则

/* 所有类名以 .jx- 为前缀 */
.jx-chatArea { }
.jx-chatArea-header { }       /* Element: 连字符 */
.jx-chatArea-content { }
.jx-chatArea--empty { }       /* Modifier: 双连字符 */

7.2 核心颜色(摘要)

:root {
  /* 主色 — 蓝色系 */
  --color-primary: #126DFF;
  --color-primary-hover: #3C87FF;
  --color-primary-active: #0862F3;
  --color-primary-bg: #DBE9FF;
  --color-primary-light: #EBF2FF;

  /* 文字 */
  --color-text: #262626;           /* 标题/强调 */
  --color-text-secondary: #4D4D4D; /* 正文内容 */
  --color-text-tertiary: #808080;  /* 次要信息 */
  --color-text-placeholder: #B3B3B3; /* 置灰/说明 */

  /* 边框与填充 */
  --color-border: #E3E6EA;
  --color-fill: #D8DBE2;
  --color-bg-gray: #F5F6F7;

  /* 语义色 */
  --color-success: #02B589;
  --color-warning: #F8AB42;
  --color-error: #FC5D5D;

  /* 圆角 */
  --radius-xs: 4px;   /* 标签 */
  --radius-sm: 8px;   /* 按钮、输入框 */
  --radius-md: 12px;  /* 卡片 */
  --radius-lg: 20px;  /* 弹窗 */

  /* 间距 (4px 基准) */
  --space-xs: 4px;  --space-sm: 8px;
  --space-md: 16px; --space-lg: 20px; --space-xl: 40px;

  /* 字体 */
  --font-family: "PingFang SC", "Microsoft YaHei", "微软雅黑", sans-serif;
  --font-family-number: "DingTalk Sans", "PingFang SC", "Microsoft YaHei", sans-serif;
}

7.3 样式规则

  • 前缀: 所有自定义类使用 .jx- 前缀
  • BEM: 子元素用 -,修饰符用 --
  • 颜色: 必须使用 CSS 变量,禁止硬编码色值
  • 间距: 以 4px 为基准,常用 4/8/16/20/40px
  • 圆角: 按组件类型使用对应层级(4/8/12/20px)
  • 字号: 12/14/16/18/22/44px,默认正文 14px
  • 字体: 中文 PingFang SC / 微软雅黑,特殊数字用 DingTalk Sans
  • Icon: 推荐 IconPark 图标库,蓝色系为主
  • 布局: Flexbox 为主
  • 文件: 按功能放在 styles/ 对应文件中
  • Ant Design: 通过 ConfigProvider token 定制主题色,不覆写组件内部样式(详见 ui-design-spec.md 第 13 节)

8. SSE 流式处理规范

// useStreaming.ts 中的 SSE 事件处理模式(详见 references/sse-events.md)
const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
let sseBuffer = '';

// 事件类型处理(注意:没有 text/done 事件!)
// 'run_started'   → 首帧,记录 run_id/message_id 到 chatStore.activeRun(断线续播用)
// 'content'       → 文本 delta 增量,追加到消息内容(兼容别名 ai_message/text/delta)
// 'thinking'      → 思考过程,追加到 thinking segments
// 'tool_call'     → 工具调用,追加到 toolCalls 数组 + segments(兼容 tool_use/tool_start)
// 'tool_result'   → 工具结果,更新对应 toolCall 的 output/status + citations(兼容 tool_end)
// 'tool_pending'  → 工具等待批复,UI 进入 pending 态
// 'batch_confirm' → 批量计划确认 → batchStore.setPendingConfirm 弹确认框
// 'file_confirm'  → /myspace 写确认 → uiStore.enqueuePendingConfirm(流不结束,带外 POST 批复)
// 'follow_up'     → 追问建议 follow_up_questions
// 'meta'          → message_id、citations、workspace_files、artifacts
// 'error'         → 抛错终止
// 'end' / 'data: [DONE]' → 流结束;心跳是 SSE 注释行(15s)

断线续播:run_started 给出的 run_id 可用 GET /v1/chats/stream/{run_id} 重新跟随后台 run。


9. 文件上传规范

// 并行处理:解析内容 + 上传到 OSS
const promise = Promise.all([
  parseFileContent(file, apiUrl),      // 二进制 → 后端解析,文本 → FileReader
  uploadFileToOSS(file, apiUrl, chatId), // FormData → /v1/file/upload
]).then(([content, { file_id, download_url }]) => ({
  name: file.name,
  content,
  file_id,
  download_url,
  mime_type: file.type,
}));

10. localStorage 持久化

// 存储键命名规范
export const STORAGE_KEY = 'hugagent_ui_chat_history_v2';   // 聊天数据
export const ENABLE_KEY = 'hugagent_ui_enabled_catalog_v1'; // Catalog 状态

// ID 生成
export function nowId(prefix = 'chat') {
  const d = new Date();
  const pad = (n: number) => String(n).padStart(2, '0');
  return `${prefix}_${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}_${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;
}

// Store 中自动保存
setStore: (store) => {
  set({ store });
  saveChatStore(store);  // → localStorage.setItem(STORAGE_KEY, JSON.stringify(store))
},

11. 状态管理模式

乐观更新

// catalogStore.ts
toggleItem: async (kind, itemId, enabled) => {
  const { catalog } = get();
  // 1. 先更新本地状态(乐观)
  const updated = {
    ...catalog,
    [kind]: catalog[kind].map(item =>
      item.id === itemId ? { ...item, enabled } : item,
    ),
  };
  set({ catalog: updated });
  saveCatalog(updated);

  // 2. 后端同步(最大努力)
  try {
    await updateCatalogItem(kind, itemId, enabled);
  } catch (e) {
    console.error('Sync failed:', e);
  }
},

派生状态(useMemo)

const filteredList = useMemo(() => {
  return list
    .filter(item => matchesFilter(item, filter))
    .sort((a, b) => b.updatedAt - a.updatedAt);
}, [list, filter]);

12. Nginx 代理配置

# SPA 路由回退
location / {
  try_files $uri $uri/ /index.html;
}

# API 代理(支持 SSE)
location /api/ {
  proxy_pass http://backend:${BACKEND_PORT}/;
  client_max_body_size 50m;
  proxy_buffering off;      # SSE 必须关闭缓冲
  proxy_cache off;
  proxy_read_timeout 300s;
}

# 静态资源(长期缓存)
location /assets/ {
  add_header Cache-Control "public, max-age=31536000, immutable" always;
}

# index.html(不缓存)
location = /index.html {
  add_header Cache-Control "no-store, no-cache, must-revalidate" always;
}

13. Docker 开发流程

# 完整重建(慢但保证正确)
docker-compose up -d --build frontend

# 本地构建 + 热替换(快,需要 Node 20+)
cd src/frontend
npm run build
docker cp dist/. hugagent-frontend:/usr/share/nginx/html/
docker exec hugagent-frontend nginx -s reload

# 前端 lint
cd src/frontend && npm run lint

14. 新功能开发检查清单

  • 组件文件使用 PascalCase 命名
  • Props 定义了 TypeScript 接口
  • 使用 named export
  • 全局状态通过 Zustand Store 管理
  • API 调用通过 authFetch()
  • CSS 类名使用 .jx- 前缀
  • 颜色使用 CSS 变量(--color-primary 等),禁止硬编码色值
  • 圆角使用分层变量(--radius-xs/sm/md/lg)
  • 间距以 4px 为基准(--space-xs/sm/md/lg/xl)
  • 字号使用规范层级(12/14/16/18/22/44px)
  • 中文字体 PingFang SC / 微软雅黑,特殊数字用 DingTalk Sans
  • 错误处理:try-catch + message.error()
  • 组件在 index.ts 中 barrel export
  • 类型定义完整(无 any)
  • useMemo/useCallback 用于性能优化
  • 使用 Ant Design 组件库 + ConfigProvider 主题配置
  • Icon 优先使用 IconPark 图标库,蓝色系为主色调
  • npm run lint 通过
Skills enregistrées