From aae31e75062cbc0be779c2f0d99d7b5c1965d7cc Mon Sep 17 00:00:00 2001
From: gongzhiyong
Date: Thu, 30 Apr 2026 15:37:33 +0800
Subject: [PATCH] feat(new-api): rebrand manager UI and expose login
integration assets
Rebrand the default console experience to Heicode Manager, reshape key navigation toward deployment/ops workflows, and surface login integration docs/screenshots directly in the app for implementation handoff.
Constraint: Keep runtime/module identifiers compatible while shipping user-visible brand and IA changes first
Confidence: medium
Scope-risk: moderate
Not-tested: Full browser regression run across all default/classic pages
Made-with: Cursor
---
docs/integration/Heicode-登录接口对接文档.md | 349 ++++++++++++++++++
docs/integration/README.md | 7 +-
docs/integration/agnet-platform-api-design.md | 60 +--
docs/integration/heicode-oauth-flow.md | 11 +
new-api/common/constants.go | 2 +-
new-api/web/default/index.html | 6 +-
new-api/web/default/src/assets/logo.tsx | 4 +-
.../components/layout/components/footer.tsx | 63 +---
.../layout/components/workspace-switcher.tsx | 2 +-
.../web/default/src/features/about/index.tsx | 121 +++---
.../system-settings/general/index.tsx | 2 +-
.../general/system-info-section.tsx | 4 +-
.../default/src/hooks/use-sidebar-config.ts | 49 ++-
.../web/default/src/hooks/use-sidebar-data.ts | 56 +--
new-api/web/default/src/lib/constants.ts | 2 +-
.../src/routes/_authenticated/audit/index.tsx | 10 +
.../_authenticated/deployments/index.tsx | 10 +
.../routes/_authenticated/events/index.tsx | 10 +
18 files changed, 564 insertions(+), 204 deletions(-)
create mode 100644 docs/integration/Heicode-登录接口对接文档.md
create mode 100644 new-api/web/default/src/routes/_authenticated/audit/index.tsx
create mode 100644 new-api/web/default/src/routes/_authenticated/deployments/index.tsx
create mode 100644 new-api/web/default/src/routes/_authenticated/events/index.tsx
diff --git a/docs/integration/Heicode-登录接口对接文档.md b/docs/integration/Heicode-登录接口对接文档.md
new file mode 100644
index 0000000..15dc4d4
--- /dev/null
+++ b/docs/integration/Heicode-登录接口对接文档.md
@@ -0,0 +1,349 @@
+# Heicode 客户端 — 登录接口对接文档
+
+**版本**: v1.0
+**生效日期**: 2026-04-30
+**状态**: 已上线生产,已通过端到端测试
+
+---
+
+## 1. 概述
+
+本文档描述 Heicode 客户端(桌面/CLI)与 Heicode Manager(即 mcp-server)之间的**登录认证接口**。共 4 个接口,覆盖完整登录生命周期:
+
+| 接口 | 用途 |
+|------|------|
+| `POST /api/auth/login` | 账号密码登录,换取 token |
+| `GET /api/auth/me` | 校验 token 有效性 + 获取当前用户资料 |
+| `POST /api/auth/refresh` | access token 过期时换新的 |
+| `POST /api/auth/logout` | 登出(token 加入黑名单) |
+
+> 不在本期范围:注册、找回密码、改密码 — 这些走官网 web 端完成。
+
+---
+
+## 2. 接入信息
+
+### 2.1 Base URL
+
+生产环境通过 Azure APIM 网关接入:
+
+```
+https://apimtaiji.azure-api.net/api/mcp
+```
+
+完整路径示例:
+```
+POST https://apimtaiji.azure-api.net/api/mcp/api/auth/login
+```
+
+### 2.2 通用请求头
+
+| Header | 必填 | 说明 |
+|--------|------|------|
+| `Content-Type: application/json` | 是(POST/PUT) | 请求体 JSON |
+| `Authorization: Bearer ` | 受保护接口必填 | 见 §3 |
+| `X-Request-Id: ` | 建议 | 全链路追踪 ID,客户端生成 |
+
+### 2.3 Token 模型
+
+登录成功返回两个 token:
+
+| Token | 用途 | 有效期 |
+|-------|------|--------|
+| **Access Token** | 调业务接口(含 `/me`、`/logout`) | 24 小时 |
+| **Refresh Token** | 仅用于 `/refresh` 换新 access | 7 天 |
+
+JWT claims 包含:`sub`(user_id)、`email`、`role`、`channelId`、`type`(access/refresh)、`iat`、`exp`。
+
+---
+
+## 3. 接口详情
+
+### 3.1 POST /api/auth/login — 登录
+
+**请求**
+
+```http
+POST /api/auth/login HTTP/1.1
+Content-Type: application/json
+
+{
+ "email": "user@example.com",
+ "password": "YourPassword123",
+ "role": "user"
+}
+```
+
+字段:
+- `email` (string, 必填)
+- `password` (string, 必填)
+- `role` (string, 必填):Heicode 客户端**固定传 `"user"`**
+
+**成功响应 200**
+
+```json
+{
+ "success": true,
+ "data": {
+ "token": "eyJhbGciOiJIUzI1NiIs...",
+ "refreshToken": "eyJhbGciOiJIUzI1NiIs...",
+ "user": {
+ "id": "b00a7b8e-9e8b-463d-9593-a3b4d0006778",
+ "name": "张三",
+ "email": "user@example.com",
+ "role": "user",
+ "channelId": "6e6fc470-76f8-4bb1-8ea4-625dc5b12bc6"
+ }
+ }
+}
+```
+
+**错误响应**
+
+| HTTP | 含义 | 客户端处理建议 |
+|------|------|----------------|
+| 401 | 邮箱或密码错误 | 显示"账号或密码错误",让用户重新输入 |
+| 403 | 账户已被禁用 | 提示用户联系管理员 |
+| 429 | 登录尝试过于频繁(**每 IP 5 次/分钟**) | 显示倒计时;响应头 `Retry-After: 60` 表示秒数 |
+| 422 | 请求体校验失败(邮箱格式不合法等) | 检查 `detail` 字段 |
+| 500 | 服务异常 | 重试或提示稍后再试 |
+
+**重要:限流规则**
+
+- **每 IP 每分钟最多 5 次**登录尝试(不区分成功失败)
+- 超出返回 **429 Too Many Requests**,含 `Retry-After` 头(秒)
+- 计数滑动窗口,60 秒后自动恢复
+
+---
+
+### 3.2 GET /api/auth/me — 获取当前用户
+
+客户端**启动时**应调用此接口校验本地缓存的 access token 是否仍有效,并刷新用户信息。
+
+**请求**
+
+```http
+GET /api/auth/me HTTP/1.1
+Authorization: Bearer
+```
+
+**成功响应 200**
+
+```json
+{
+ "success": true,
+ "data": {
+ "id": "b00a7b8e-9e8b-463d-9593-a3b4d0006778",
+ "email": "user@example.com",
+ "name": "张三",
+ "role": "user",
+ "channelId": "6e6fc470-76f8-4bb1-8ea4-625dc5b12bc6",
+ "status": "active",
+ "subscriptionTier": "free",
+ "lastLoginAt": "2026-04-30T06:38:14.765457"
+ }
+}
+```
+
+**错误响应**
+
+| HTTP | 含义 | 客户端处理建议 |
+|------|------|----------------|
+| 401 | Token 无效/过期/已登出/用户不存在 | 调 `/refresh` 换新 token;若 refresh 也 401,跳登录页 |
+| 403 | 账户已被禁用 | 强制登出,提示联系管理员 |
+
+---
+
+### 3.3 POST /api/auth/refresh — 刷新 token
+
+access token 接近或已过期时调用,使用 **refresh token** 换取新的 access + refresh token 对。
+
+**请求**
+
+```http
+POST /api/auth/refresh HTTP/1.1
+Authorization: Bearer
+```
+
+> ⚠️ **必须传 refresh token**,传 access token 会被拒绝。
+
+**成功响应 200**
+
+```json
+{
+ "success": true,
+ "data": {
+ "token": "eyJhbGciOiJIUzI1NiIs...",
+ "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
+ }
+}
+```
+
+客户端收到新的 token 对后**应替换本地缓存**(包括 refresh token,旧的也作废)。
+
+**错误响应**
+
+| HTTP | 含义 | 客户端处理建议 |
+|------|------|----------------|
+| 401 | refresh token 无效 / 过期 / 错传了 access token | 跳登录页 |
+
+实施细节:
+- 服务端会校验 token claims `type == "refresh"`,否则拒绝
+- 旧 refresh token 不会被立即吊销(容许并发换发期),但客户端应丢弃旧的
+
+---
+
+### 3.4 POST /api/auth/logout — 登出
+
+将当前 access token 加入黑名单,使其立即失效。
+
+**请求**
+
+```http
+POST /api/auth/logout HTTP/1.1
+Authorization: Bearer
+```
+
+**成功响应 200**
+
+```json
+{
+ "success": true,
+ "data": null,
+ "message": "登出成功"
+}
+```
+
+**错误响应**
+
+logout 容错性较强,token 黑名单写入失败也会返回 200(前端清理本地 token 即可)。
+
+**客户端登出流程**:
+1. 调 `/api/auth/logout`
+2. 清除本地存储的 access + refresh token
+3. 清除当前用户资料缓存
+4. 跳转到登录页
+
+---
+
+## 4. 完整登录流程(示例)
+
+### 启动时
+
+```
+┌─ 本地有 access token ?
+│
+├─ 是 ─→ GET /me
+│ ├─ 200 ─→ 进入主界面
+│ └─ 401 ─→ 本地有 refresh token ?
+│ ├─ 是 ─→ POST /refresh
+│ │ ├─ 200 ─→ 替换 token,进入主界面
+│ │ └─ 401 ─→ 跳登录页
+│ └─ 否 ─→ 跳登录页
+│
+└─ 否 ─→ 跳登录页
+```
+
+### 登录页提交
+
+```
+POST /login
+ ├─ 200 ─→ 存 token 对,进主界面
+ ├─ 401 ─→ 显示"账号或密码错误"
+ ├─ 429 ─→ 显示"尝试过于频繁,请 N 秒后重试"(N 取响应头 Retry-After)
+ └─ 其他 ─→ 显示通用错误
+```
+
+### 业务请求过程中 access token 过期
+
+```
+任意业务接口返回 401
+ └─→ POST /refresh (用 refresh token)
+ ├─ 200 ─→ 替换 token,重试原请求
+ └─ 401 ─→ 清理 token,跳登录页
+```
+
+### 登出按钮
+
+```
+POST /logout
+ └─→ 不论结果都清理本地 token,跳登录页
+```
+
+---
+
+## 5. 错误响应格式
+
+当前为 FastAPI 默认格式(下个版本 `/api/v1/*` 路径会改为标准 envelope,本期保留兼容):
+
+```json
+{
+ "detail": "邮箱或密码错误"
+}
+```
+
+422 校验错误格式(Pydantic):
+
+```json
+{
+ "detail": [
+ {
+ "type": "value_error",
+ "loc": ["body", "email"],
+ "msg": "value is not a valid email address: ...",
+ "input": "abc"
+ }
+ ]
+}
+```
+
+---
+
+## 6. 安全注意事项
+
+| 项 | 说明 |
+|---|---|
+| **token 存储** | 桌面应用建议存到 OS 安全凭据存储(Windows Credential Manager / macOS Keychain / Linux Secret Service) |
+| **HTTPS 强制** | 生产 base URL 已是 HTTPS;客户端**禁止**回退 HTTP |
+| **token 泄露应对** | 用户怀疑泄露时提示去官网 web 端改密码(改密会导致所有 session 黑名单) |
+| **审计日志** | 所有 login 尝试(成功/失败)服务端均写审计 |
+| **状态码不泄漏** | 错误信息已统一用"邮箱或密码错误",不区分账号是否存在,防爆破 |
+
+---
+
+## 7. 测试账号(仅供联调)
+
+| 角色 | 邮箱 | 密码 |
+|------|------|------|
+| 普通用户 | `55@55.com` | `By@123456.` |
+
+> ⚠️ 测试账号仅用于联调阶段,正式上线前请务必关闭。
+
+---
+
+## 8. 已上线生产验证清单
+
+| 测试项 | 结果 |
+|--------|------|
+| login 200 + 返回 access/refresh token | ✅ |
+| /me 用 access token → 200 + 完整 profile | ✅ |
+| /refresh 用 refresh token → 200 + 新 token 对 | ✅ |
+| /refresh 用 access token → 401 拒绝 | ✅ |
+| logout → 200 | ✅ |
+| logout 后旧 token 调 /me → 401(黑名单生效) | ✅ |
+| 连续 7 次错密 → 第 6 次起 429(每 IP 5/min 限流) | ✅ |
+| 服务器审计日志记录所有 login(含成功/失败) | ✅ |
+
+镜像 digest: `sha256:339b64ae090dc81fa13cb29705958167e77fe0698e27ac227c05054ed5c42309`
+镜像 tag: `taiji.azurecr.io/mcp-server:heicode-auth-fix2-20260430`
+部署日期: 2026-04-30
+
+---
+
+## 9. 联系
+
+如对接过程发现接口行为与本文档不一致,请联系 Heicode Manager 后端团队,附上:
+
+- 请求完整 URL / Headers / Body
+- 响应 HTTP 状态 + Body
+- `X-Request-Id` 头值(便于服务端按 ID 反查日志)
diff --git a/docs/integration/README.md b/docs/integration/README.md
index 8a6e726..609d9c4 100644
--- a/docs/integration/README.md
+++ b/docs/integration/README.md
@@ -22,9 +22,10 @@
| 7 | `[./agnet-platform-api-design.md](./agnet-platform-api-design.md)` §5 | 一键部署、SK 绑定、控制面 API |
| 8 | `[./orchestration-plan-contract.md](./orchestration-plan-contract.md)` | 模型提案对象与平台裁决规则 |
| 9 | `[./agnet-platform-api-design.md](./agnet-platform-api-design.md)` §6–§7 | 运行态、聚合视图、事件流(双轨) |
-| 10 | `[./heicode-oauth-flow.md](./heicode-oauth-flow.md)` | 客户端浏览器登录到 Manager 的完整流程 |
-| 11 | `[./acceptance-matrix.md](./acceptance-matrix.md)` | 集成验收最小测试矩阵 |
-| 12 | `[../milestones/README.md](../milestones/README.md)` + `[../milestones/STATUS.md](../milestones/STATUS.md)` | 落地节奏与现状 |
+| 10 | `[./Heicode-登录接口对接文档.md](./Heicode-登录接口对接文档.md)` | 已上线认证接口契约(login / me / refresh / logout) |
+| 11 | `[./heicode-oauth-flow.md](./heicode-oauth-flow.md)` | 客户端浏览器登录到 Manager 的完整流程 |
+| 12 | `[./acceptance-matrix.md](./acceptance-matrix.md)` | 集成验收最小测试矩阵 |
+| 13 | `[../milestones/README.md](../milestones/README.md)` + `[../milestones/STATUS.md](../milestones/STATUS.md)` | 落地节奏与现状 |
## 边界速览
diff --git a/docs/integration/agnet-platform-api-design.md b/docs/integration/agnet-platform-api-design.md
index 3086bde..e4f92ab 100644
--- a/docs/integration/agnet-platform-api-design.md
+++ b/docs/integration/agnet-platform-api-design.md
@@ -3,7 +3,7 @@
本文描述 **Agnet 平台**应向 **Heicode(Manager / 客户端 / 自动化服务)** 暴露的 **控制面、数据面隔离、权限模型与可视化/事件接口**。
路径、字段名为 **设计意图**;落地时可等价映射为 gRPC 或 GraphQL,但**语义与隔离边界**应保持一致。
-**关联里程碑**:[`../milestones/`](../milestones/README.md) 中 M3~M5。
+**关联里程碑**:`[../milestones/](../milestones/README.md)` 中 M3~M5。
---
@@ -79,7 +79,7 @@
- **控制面**(部署/改策略)与 **观测面**(读指标)可分角色授予。
- **凭据类写操作**(绑定 Git Token、云 SA)单独 scope:`agnet:credential:write`。
-- **SK 正文写入**:仅允许经 **Heicode 客户端**身份或专用 **`heicode:sk:write`**(示例名)路径;**Agnet / Manager 控制台接口不得授予 SK 正文写权限**(与 §5.0「SK 仅在 Heicode 编辑」一致)。
+- **SK 正文写入**:仅允许经 **Heicode 客户端**身份或专用 `**heicode:sk:write`**(示例名)路径;**Agnet / Manager 控制台接口不得授予 SK 正文写权限**(与 §5.0「SK 仅在 Heicode 编辑」一致)。
- **拒绝隐式升级**:只读 Token **不得**通过查询参数绕过 body 校验升格为写操作。
---
@@ -122,7 +122,7 @@ Tenant(租户)
### 5.0 Heicode Manager:一键部署 Agnet 团队与 SK 边界(产品契约)
-下列条款为 **Heicode 与 Agnet 联合落地时必须写清** 的契约;API 形状可与 **`POST /deployments`** 合一或拆为 **`POST /teams/deployments`** 等聚合端点,但 **语义不得缩水**。
+下列条款为 **Heicode 与 Agnet 联合落地时必须写清** 的契约;API 形状可与 `**POST /deployments`** 合一或拆为 `**POST /teams/deployments`** 等聚合端点,但 **语义不得缩水**。
| 契约项 | 要求 |
@@ -165,7 +165,7 @@ Tenant(租户)
}
```
-- **`sk_sources`(推荐显式建模)**:替代或细化纯路径数组 `sk_file_refs`; 每个元素标明来源类型,便于 Agnet 实现拉取与快照。
+- `**sk_sources`(推荐显式建模)**:替代或细化纯路径数组 `sk_file_refs`; 每个元素标明来源类型,便于 Agnet 实现拉取与快照。
**部署请求体中 SK 绑定扩展示意**
@@ -195,15 +195,15 @@ Tenant(租户)
| 类别 | 要求 |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
-| **部署与编队** | 实现 **`POST /deployments`**(或 **`POST /teams/deployments`**)可接收 **成员、成员模型、子 agent 模板及 `sk_sources`**;返回 **`deployment_id`**、实例/子 agent 标识,供 Callback 与观测关联。 |
+| **部署与编队** | 实现 `**POST /deployments`**(或 `**POST /teams/deployments`**)可接收 **成员、成员模型、子 agent 模板及 `sk_sources`**;返回 `**deployment_id**`、实例/子 agent 标识,供 Callback 与观测关联。 |
| **SK 快照只读** | 对每个 `deployment_id` / `sub_agent_id`,Agnet 须能记录 **已解析的 SK 快照**(Git:`commit_sha` + 路径哈希;Upload:`artifact_id` + 版本)。运行注入 **仅此快照**,不得在执行中「瞒报版本」拉未授权路径。 |
| **Git 拉取** | Agnet 须支持 **按租户注册 Git 凭据/连接**(`connection_id` 或等价),由用户在 **Heicode/Manager 流程**中授权;**Agnet 不提供 Git 写接口用于改 SK**——写操作发生在 Git 远端或经 Heicode 提交后,Agnet 仅 **fetch + checkout 指定 ref**。 |
-| **上传制品** | 若支持 `type: "upload"`:Agnet(或与 Manager 分工)须提供 **`artifact_id`** 的只读获取(如 `GET /sk-artifacts/{artifact_id}/content` 或预签名 URL),**无 `PUT` 修改正文**于 Agnet 控制台;上传入口 **仅** Heicode 侧发起、Agnet 存只读副本。 |
-| **刷新策略** | 约定 **何时重新解析 SK**(如新 commit、用户触发刷新、部署新版本);须可通过 API 或事件暴露 **`sk_snapshot_refreshed`**,便于 Heicode 提示「已用新版本 SK」。 |
+| **上传制品** | 若支持 `type: "upload"`:Agnet(或与 Manager 分工)须提供 `**artifact_id`** 的只读获取(如 `GET /sk-artifacts/{artifact_id}/content` 或预签名 URL),**无 `PUT` 修改正文**于 Agnet 控制台;上传入口 **仅** Heicode 侧发起、Agnet 存只读副本。 |
+| **刷新策略** | 约定 **何时重新解析 SK**(如新 commit、用户触发刷新、部署新版本);须可通过 API 或事件暴露 `**sk_snapshot_refreshed`**,便于 Heicode 提示「已用新版本 SK」。 |
| **禁止项** | **不得**提供面向 SK 正文的 **通用写 API**(与 §3.2 一致);子 agent **只读**绑定列表内的快照。 |
-- **`sk_file_refs`**(若保留简化字段):视为 **相对某默认 Git 根**或 **由 Manager 展开为 `sk_sources`** 前的简写;联合 RFC 须声明展开规则。
+- `**sk_file_refs`**(若保留简化字段):视为 **相对某默认 Git 根**或 **由 Manager 展开为 `sk_sources`** 前的简写;联合 RFC 须声明展开规则。
- **验收**:部署完成后,Manager 可展示「团队成员—模型—**Agnet 子 agent**—SK 源(Git ref / 上传件)—快照版本」;Git 更新或 Heicode 重新上传后,按刷新策略在后续运行使用新快照。
### 5.1 部署编队
@@ -345,7 +345,7 @@ Tenant(租户)
`WS /projects/{project_id}/stream`
-- 首帧 **鉴权**(query token 或子协议);订阅主题:`deployment.*`、`instance.*`。
+- 首帧 **鉴权**(query token 或子协议);订阅主题:`deployment.`*、`instance.`*。
### 7.3 重连与顺序
@@ -404,7 +404,7 @@ Tenant(租户)
- **平台裁决**:Agnet 对提案执行权限、租户、预算、模型授权校验后决定执行
- **Manager 入口**:Heicode Manager 仅作为调用入口与状态展示,不绕过裁决链路
-详见:[`./orchestration-plan-contract.md`](./orchestration-plan-contract.md)。
+详见:`[./orchestration-plan-contract.md](./orchestration-plan-contract.md)`。
最低校验项(平台必须执行):
@@ -420,14 +420,16 @@ Tenant(租户)
建议固定以下事件名,避免前后端各自命名造成协议漂移:
-| event | 用途 |
-|------|------|
-| `deployment.accepted` | 部署请求被接受,进入编排队列 |
-| `deployment.rejected` | 部署被策略拒绝 |
-| `instance.phase_changed` | 执行单元阶段变化 |
-| `instance.health_changed` | 执行单元健康状态变化 |
-| `sub_agent.output_delta` | 子 agent 流式输出增量 |
-| `sk_snapshot_refreshed` | SK 快照刷新完成 |
+
+| event | 用途 |
+| ------------------------- | -------------- |
+| `deployment.accepted` | 部署请求被接受,进入编排队列 |
+| `deployment.rejected` | 部署被策略拒绝 |
+| `instance.phase_changed` | 执行单元阶段变化 |
+| `instance.health_changed` | 执行单元健康状态变化 |
+| `sub_agent.output_delta` | 子 agent 流式输出增量 |
+| `sk_snapshot_refreshed` | SK 快照刷新完成 |
+
每个事件最小字段建议:
@@ -445,17 +447,19 @@ Tenant(租户)
除 HTTP 状态码外,建议统一错误码最小集合:
-| code | 说明 |
-|------|------|
-| `POLICY_REJECTED` | 平台策略拒绝执行提案 |
-| `MODEL_NOT_ALLOWED` | 模型未授权 |
-| `SK_SOURCE_UNRESOLVABLE` | SK 源不可解析或不可读 |
-| `BUDGET_EXCEEDED` | 超预算 |
-| `FORBIDDEN_CROSS_TENANT` | 跨租户访问拒绝 |
-| `DEPLOYMENT_CONFLICT` | 幂等或状态冲突 |
-| `CALLBACK_SIGNATURE_INVALID` | 回调签名校验失败 |
-验收用例集合见:[`./acceptance-matrix.md`](./acceptance-matrix.md)。
+| code | 说明 |
+| ---------------------------- | ------------ |
+| `POLICY_REJECTED` | 平台策略拒绝执行提案 |
+| `MODEL_NOT_ALLOWED` | 模型未授权 |
+| `SK_SOURCE_UNRESOLVABLE` | SK 源不可解析或不可读 |
+| `BUDGET_EXCEEDED` | 超预算 |
+| `FORBIDDEN_CROSS_TENANT` | 跨租户访问拒绝 |
+| `DEPLOYMENT_CONFLICT` | 幂等或状态冲突 |
+| `CALLBACK_SIGNATURE_INVALID` | 回调签名校验失败 |
+
+
+验收用例集合见:`[./acceptance-matrix.md](./acceptance-matrix.md)`。
---
diff --git a/docs/integration/heicode-oauth-flow.md b/docs/integration/heicode-oauth-flow.md
index 2ca188f..7c79b26 100644
--- a/docs/integration/heicode-oauth-flow.md
+++ b/docs/integration/heicode-oauth-flow.md
@@ -137,3 +137,14 @@ sequenceDiagram
- Token 长生命周期使用前提:Manager 端可吊销且具备审计;不要在跨设备粘贴中传播
- 出现安全事件时,Manager 应能批量吊销名为 `HeiCode` 的 Token
+## 八、界面截图(docs/images)
+
+> 下列截图来自 `docs/images/`,用于辅助理解登录链路与界面落位。
+
+
+
+
+
+
+
+
diff --git a/new-api/common/constants.go b/new-api/common/constants.go
index c4d2511..7f53036 100644
--- a/new-api/common/constants.go
+++ b/new-api/common/constants.go
@@ -13,7 +13,7 @@ import (
var StartTime = time.Now().Unix() // unit: second
var Version = "v0.0.0" // this hard coding will be replaced automatically when building, no need to manually change
-var SystemName = "New API"
+var SystemName = "Heicode Manager"
var Footer = ""
var Logo = ""
var TopUpLink = ""
diff --git a/new-api/web/default/index.html b/new-api/web/default/index.html
index ed041d2..02da866 100644
--- a/new-api/web/default/index.html
+++ b/new-api/web/default/index.html
@@ -6,11 +6,11 @@
- New API
-
+ Heicode Manager
+
diff --git a/new-api/web/default/src/assets/logo.tsx b/new-api/web/default/src/assets/logo.tsx
index a4e6384..90c2eb7 100644
--- a/new-api/web/default/src/assets/logo.tsx
+++ b/new-api/web/default/src/assets/logo.tsx
@@ -4,7 +4,7 @@ import { cn } from '@/lib/utils'
export function Logo({ className, ...props }: SVGProps) {
return (
) {
className={cn('size-6', className)}
{...props}
>
- New API
+ Heicode Manager
)
diff --git a/new-api/web/default/src/components/layout/components/footer.tsx b/new-api/web/default/src/components/layout/components/footer.tsx
index eed0b6c..04e133f 100644
--- a/new-api/web/default/src/components/layout/components/footer.tsx
+++ b/new-api/web/default/src/components/layout/components/footer.tsx
@@ -60,7 +60,7 @@ export function Footer(props: FooterProps) {
} = useSystemConfig()
const displayLogo = systemLogo || props.logo || '/logo.png'
- const displayName = systemName || props.name || 'New API'
+ const displayName = systemName || props.name || 'Heicode Manager'
const isDemoSiteMode = Boolean(demoSiteEnabled)
const currentYear = new Date().getFullYear()
@@ -69,52 +69,25 @@ export function Footer(props: FooterProps) {
{
title: t('footer.columns.about.title'),
links: [
- {
- text: t('footer.columns.about.links.aboutProject'),
- href: 'https://docs.newapi.pro/wiki/project-introduction/',
- },
- {
- text: t('footer.columns.about.links.contact'),
- href: 'https://docs.newapi.pro/support/community-interaction/',
- },
- {
- text: t('footer.columns.about.links.features'),
- href: 'https://docs.newapi.pro/wiki/features-introduction/',
- },
+ { text: t('About'), href: '/about' },
+ { text: t('Profile'), href: '/profile' },
+ { text: t('System Settings'), href: '/system-settings/general' },
],
},
{
title: t('footer.columns.docs.title'),
links: [
- {
- text: t('footer.columns.docs.links.quickStart'),
- href: 'https://docs.newapi.pro/getting-started/',
- },
- {
- text: t('footer.columns.docs.links.installation'),
- href: 'https://docs.newapi.pro/installation/',
- },
- {
- text: t('footer.columns.docs.links.apiDocs'),
- href: 'https://docs.newapi.pro/api/',
- },
+ { text: t('Deployments'), href: '/deployments' },
+ { text: t('Events'), href: '/events' },
+ { text: t('API Keys'), href: '/keys' },
],
},
{
title: t('footer.columns.related.title'),
links: [
- {
- text: t('footer.columns.related.links.oneApi'),
- href: 'https://github.com/songquanpeng/one-api',
- },
- {
- text: t('footer.columns.related.links.midjourney'),
- href: 'https://github.com/novicezk/midjourney-proxy',
- },
- {
- text: t('footer.columns.related.links.neko'),
- href: 'https://github.com/Calcium-Ion/neko-api-key-tool',
- },
+ { text: t('Channels'), href: '/channels' },
+ { text: t('Models'), href: '/models/metadata' },
+ { text: t('Users'), href: '/users' },
],
},
],
@@ -182,19 +155,9 @@ export function Footer(props: FooterProps) {
© {currentYear} {displayName}.{' '}
{props.copyright ?? t('footer.defaultCopyright')}
-
+
+ {t('Platform Console')}
+
diff --git a/new-api/web/default/src/components/layout/components/workspace-switcher.tsx b/new-api/web/default/src/components/layout/components/workspace-switcher.tsx
index fc1801d..3f50420 100644
--- a/new-api/web/default/src/components/layout/components/workspace-switcher.tsx
+++ b/new-api/web/default/src/components/layout/components/workspace-switcher.tsx
@@ -37,7 +37,7 @@ type WorkspaceSwitcherProps = {
*/
export function WorkspaceSwitcher({
workspaces,
- defaultName = 'New API',
+ defaultName = 'Heicode Manager',
defaultVersion,
}: WorkspaceSwitcherProps) {
const { t } = useTranslation()
diff --git a/new-api/web/default/src/features/about/index.tsx b/new-api/web/default/src/features/about/index.tsx
index 53dcf8c..8a90c68 100644
--- a/new-api/web/default/src/features/about/index.tsx
+++ b/new-api/web/default/src/features/about/index.tsx
@@ -1,6 +1,7 @@
import { useQuery } from '@tanstack/react-query'
import { Construction } from 'lucide-react'
import { useTranslation } from 'react-i18next'
+import { Link } from '@tanstack/react-router'
import { Markdown } from '@/components/ui/markdown'
import { Skeleton } from '@/components/ui/skeleton'
import { PublicLayout } from '@/components/layout'
@@ -19,9 +20,61 @@ function isLikelyHtml(value: string) {
return /<\/?[a-z][\s\S]*>/i.test(value)
}
+const HEICODE_INTEGRATION_IMAGES = [
+ '/docs/images/wecom-screenshot-01.jpg',
+ '/docs/images/wecom-screenshot-02.jpg',
+ '/docs/images/wecom-screenshot-03.jpg',
+ '/docs/images/wecom-screenshot-04.jpg',
+ '/docs/images/wecom-screenshot-05.jpg',
+ '/docs/images/wecom-screenshot-06.jpg',
+]
+
+function HeicodeIntegrationPanel() {
+ const { t } = useTranslation()
+
+ return (
+
+
+
+
+ {HEICODE_INTEGRATION_IMAGES.map((src, index) => (
+
+
+
+ ))}
+
+
+ )
+}
+
function EmptyAboutState() {
const { t } = useTranslation()
- const currentYear = new Date().getFullYear()
return (
@@ -37,66 +90,13 @@ function EmptyAboutState() {
)}
-
@@ -162,6 +162,7 @@ export function About() {
{rawContent}
)}
+
)
diff --git a/new-api/web/default/src/features/system-settings/general/index.tsx b/new-api/web/default/src/features/system-settings/general/index.tsx
index 054a3f8..31ce67d 100644
--- a/new-api/web/default/src/features/system-settings/general/index.tsx
+++ b/new-api/web/default/src/features/system-settings/general/index.tsx
@@ -11,7 +11,7 @@ import {
const defaultGeneralSettings: GeneralSettings = {
'theme.frontend': 'default',
Notice: '',
- SystemName: 'New API',
+ SystemName: 'Heicode Manager',
Logo: '',
Footer: '',
About: '',
diff --git a/new-api/web/default/src/features/system-settings/general/system-info-section.tsx b/new-api/web/default/src/features/system-settings/general/system-info-section.tsx
index 6993662..19a1747 100644
--- a/new-api/web/default/src/features/system-settings/general/system-info-section.tsx
+++ b/new-api/web/default/src/features/system-settings/general/system-info-section.tsx
@@ -201,7 +201,7 @@ export function SystemInfoSection({ defaultValues }: SystemInfoSectionProps) {
{t('System Name')}
-
+
{t('The name displayed across the application')}
@@ -305,7 +305,7 @@ export function SystemInfoSection({ defaultValues }: SystemInfoSectionProps) {
{t('Home Page Content')}
diff --git a/new-api/web/default/src/hooks/use-sidebar-config.ts b/new-api/web/default/src/hooks/use-sidebar-config.ts
index 05b8a11..51e07d5 100644
--- a/new-api/web/default/src/hooks/use-sidebar-config.ts
+++ b/new-api/web/default/src/hooks/use-sidebar-config.ts
@@ -25,11 +25,10 @@ const DEFAULT_SIDEBAR_MODULES: SidebarModulesAdminConfig = {
},
console: {
enabled: true,
- detail: true,
+ deployments: true,
+ events: true,
+ audit: true,
token: true,
- log: true,
- midjourney: true,
- task: true,
},
personal: {
enabled: true,
@@ -40,9 +39,7 @@ const DEFAULT_SIDEBAR_MODULES: SidebarModulesAdminConfig = {
enabled: true,
channel: true,
models: true,
- redemption: true,
user: true,
- setting: true,
subscription: true,
},
}
@@ -52,15 +49,19 @@ const DEFAULT_SIDEBAR_MODULES: SidebarModulesAdminConfig = {
*/
const URL_TO_CONFIG_MAP: Record = {
'/playground': { section: 'chat', module: 'playground' },
- '/dashboard': { section: 'console', module: 'detail' },
- '/dashboard/overview': { section: 'console', module: 'detail' },
- '/dashboard/models': { section: 'console', module: 'detail' },
- '/dashboard/users': { section: 'console', module: 'detail' },
+ '/dashboard': { section: 'console', module: 'deployments' },
+ '/dashboard/overview': { section: 'console', module: 'deployments' },
+ '/dashboard/models': { section: 'console', module: 'deployments' },
+ '/dashboard/users': { section: 'console', module: 'deployments' },
+ '/deployments': { section: 'console', module: 'deployments' },
+ '/models/deployments': { section: 'console', module: 'deployments' },
+ '/events': { section: 'console', module: 'events' },
'/keys': { section: 'console', module: 'token' },
- '/usage-logs': { section: 'console', module: 'log' },
- '/usage-logs/common': { section: 'console', module: 'log' },
- '/usage-logs/drawing': { section: 'console', module: 'midjourney' },
- '/usage-logs/task': { section: 'console', module: 'task' },
+ '/audit': { section: 'console', module: 'audit' },
+ '/usage-logs': { section: 'console', module: 'events' },
+ '/usage-logs/common': { section: 'console', module: 'events' },
+ '/usage-logs/drawing': { section: 'console', module: 'audit' },
+ '/usage-logs/task': { section: 'console', module: 'audit' },
'/wallet': { section: 'personal', module: 'topup' },
'/profile': { section: 'personal', module: 'personal' },
'/channels': { section: 'admin', module: 'channel' },
@@ -68,7 +69,6 @@ const URL_TO_CONFIG_MAP: Record = {
'/models/metadata': { section: 'admin', module: 'models' },
'/models/deployments': { section: 'admin', module: 'models' },
'/users': { section: 'admin', module: 'user' },
- '/redemption-codes': { section: 'admin', module: 'redemption' },
'/subscriptions': { section: 'admin', module: 'subscription' },
}
@@ -93,6 +93,25 @@ function parseSidebarConfig(
if (parsed.chat.playground === undefined) parsed.chat.playground = true
if (parsed.chat.chat === undefined) parsed.chat.chat = true
}
+ if (!parsed.console) {
+ parsed.console = {
+ enabled: true,
+ deployments: true,
+ events: true,
+ audit: true,
+ token: true,
+ }
+ } else {
+ if (parsed.console.enabled === undefined) parsed.console.enabled = true
+ if (parsed.console.deployments === undefined)
+ parsed.console.deployments = parsed.console.detail ?? true
+ if (parsed.console.events === undefined)
+ parsed.console.events = parsed.console.log ?? true
+ if (parsed.console.audit === undefined)
+ parsed.console.audit =
+ parsed.console.task ?? parsed.console.midjourney ?? true
+ if (parsed.console.token === undefined) parsed.console.token = true
+ }
return parsed
} catch {
// eslint-disable-next-line no-console
diff --git a/new-api/web/default/src/hooks/use-sidebar-data.ts b/new-api/web/default/src/hooks/use-sidebar-data.ts
index 0424953..f146ba9 100644
--- a/new-api/web/default/src/hooks/use-sidebar-data.ts
+++ b/new-api/web/default/src/hooks/use-sidebar-data.ts
@@ -1,19 +1,16 @@
import {
- LayoutDashboard,
Activity,
Key,
- FileText,
- Wallet,
+ ShieldCheck,
Box,
Users,
- Ticket,
User,
Command,
Radio,
FlaskConical,
MessageSquare,
CreditCard,
- ListTodo,
+ Rocket,
} from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { WORKSPACE_IDS } from '@/components/layout/lib/workspace-registry'
@@ -50,40 +47,30 @@ export function useSidebarData(): SidebarData {
},
{
id: 'general',
- title: t('General'),
+ title: t('Operations'),
items: [
{
- title: t('Overview'),
- url: '/dashboard/overview',
+ title: t('Deployments'),
+ url: '/deployments',
+ icon: Rocket,
+ },
+ {
+ title: t('Events'),
+ url: '/events',
icon: Activity,
},
{
- title: t('Dashboard'),
- url: '/dashboard/models',
- icon: LayoutDashboard,
+ title: t('Audit'),
+ url: '/audit',
+ activeUrls: ['/usage-logs/drawing', '/usage-logs/task'],
+ configUrls: ['/audit', '/usage-logs/drawing', '/usage-logs/task'],
+ icon: ShieldCheck,
},
{
title: t('API Keys'),
url: '/keys',
icon: Key,
},
- {
- title: t('Usage Logs'),
- url: '/usage-logs/common',
- icon: FileText,
- },
- {
- title: t('Task Logs'),
- url: '/usage-logs/task',
- activeUrls: ['/usage-logs/drawing'],
- configUrls: ['/usage-logs/drawing', '/usage-logs/task'],
- icon: ListTodo,
- },
- {
- title: t('Wallet'),
- url: '/wallet',
- icon: Wallet,
- },
{
title: t('Profile'),
url: '/profile',
@@ -93,15 +80,15 @@ export function useSidebarData(): SidebarData {
},
{
id: 'admin',
- title: t('Admin'),
+ title: t('Control Plane'),
items: [
{
- title: t('Channels'),
+ title: t('Provider Channels'),
url: '/channels',
icon: Radio,
},
{
- title: t('Models'),
+ title: t('Model Catalog'),
url: '/models/metadata',
icon: Box,
},
@@ -111,12 +98,7 @@ export function useSidebarData(): SidebarData {
icon: Users,
},
{
- title: t('Redemption Codes'),
- url: '/redemption-codes',
- icon: Ticket,
- },
- {
- title: t('Subscription Management'),
+ title: t('Subscriptions'),
url: '/subscriptions',
icon: CreditCard,
},
diff --git a/new-api/web/default/src/lib/constants.ts b/new-api/web/default/src/lib/constants.ts
index bd001e0..94cd642 100644
--- a/new-api/web/default/src/lib/constants.ts
+++ b/new-api/web/default/src/lib/constants.ts
@@ -3,7 +3,7 @@
*/
// System Configuration Defaults
-export const DEFAULT_SYSTEM_NAME = 'New API'
+export const DEFAULT_SYSTEM_NAME = 'Heicode Manager'
export const DEFAULT_LOGO = '/logo.png'
// LocalStorage Keys
diff --git a/new-api/web/default/src/routes/_authenticated/audit/index.tsx b/new-api/web/default/src/routes/_authenticated/audit/index.tsx
new file mode 100644
index 0000000..e48ee8e
--- /dev/null
+++ b/new-api/web/default/src/routes/_authenticated/audit/index.tsx
@@ -0,0 +1,10 @@
+import { createFileRoute, redirect } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_authenticated/audit/')({
+ beforeLoad: () => {
+ throw redirect({
+ to: '/usage-logs/$section',
+ params: { section: 'task' },
+ })
+ },
+})
diff --git a/new-api/web/default/src/routes/_authenticated/deployments/index.tsx b/new-api/web/default/src/routes/_authenticated/deployments/index.tsx
new file mode 100644
index 0000000..5c86d77
--- /dev/null
+++ b/new-api/web/default/src/routes/_authenticated/deployments/index.tsx
@@ -0,0 +1,10 @@
+import { createFileRoute, redirect } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_authenticated/deployments/')({
+ beforeLoad: () => {
+ throw redirect({
+ to: '/models/$section',
+ params: { section: 'deployments' },
+ })
+ },
+})
diff --git a/new-api/web/default/src/routes/_authenticated/events/index.tsx b/new-api/web/default/src/routes/_authenticated/events/index.tsx
new file mode 100644
index 0000000..0dd6485
--- /dev/null
+++ b/new-api/web/default/src/routes/_authenticated/events/index.tsx
@@ -0,0 +1,10 @@
+import { createFileRoute, redirect } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_authenticated/events/')({
+ beforeLoad: () => {
+ throw redirect({
+ to: '/usage-logs/$section',
+ params: { section: 'common' },
+ })
+ },
+})