基于产品/架构/流程/前端/后端五维度并行review,澄清并落地22项关键决策: 架构层:Governance按消费者归属拆散、MetaSchema独立模块、 Source传播改为事件驱动自治、去掉Candidate Decision Envelope 和needs_recheck中间状态、Neo4j决策为依赖RAGFlow GraphRAG 后端层:Entitlement统一为可变表+审计日志、API版本策略采用 X-API-Version Header、知识实体唯一键加scope字段 前端层:SSE实时通信(AI stream独立+事件统一)、正文持久化 IndexedDB安全网、Block粒度为场景/小节级 产品层:范围不变UX解决复杂度、知识确认默认自动+冲突时人工
841 lines
30 KiB
Markdown
841 lines
30 KiB
Markdown
# 前端-04:市场与个人中心交互
|
||
|
||
- 版本:v1
|
||
- 更新日期:2026-05-24
|
||
- 目标读者:前端开发者
|
||
- 阅读时间:40-60 分钟
|
||
- 归属仓库:`muse-studio/`(用户端)+ `muse-admin/`(管理端市场治理)
|
||
- 边界说明:本文件定义市场空间和个人中心空间在 `muse-studio` 用户端的前端交互设计,包括页面结构、组件职责、API 调用、状态管理、Handoff 消费和错误处理。精确 API 看 `后端-05`,产品功能规格看 `产品-02F` 和 `产品-02G`,Handoff 机制看 `架构-01`。
|
||
|
||
---
|
||
|
||
## 1. 路由结构
|
||
|
||
基于 `前端-01` 的路由约定,市场和个人中心在 `muse-studio/` 中的路由组织如下:
|
||
|
||
```text
|
||
muse-studio/
|
||
app/
|
||
(user)/
|
||
marketplace/
|
||
page.tsx # 市场首页与发现
|
||
categories/
|
||
page.tsx # 分类推荐与曝光
|
||
assets/
|
||
[assetId]/
|
||
page.tsx # 资产详情
|
||
acquire/page.tsx # 获取授权确认
|
||
install/page.tsx # 安装与跳转授权入口
|
||
records/page.tsx # 资产级记录
|
||
governance/page.tsx # 治理结果与申诉
|
||
publish/
|
||
page.tsx # 发布者资产与提交状态
|
||
[draftId]/page.tsx # 发布提交
|
||
profile/
|
||
page.tsx # 账户总览
|
||
info/page.tsx # 个人资料与账号信息
|
||
security/page.tsx # 安全与登录
|
||
preferences/page.tsx # 偏好与通知
|
||
usage/page.tsx # Token 与用量总览
|
||
entitlements/page.tsx # 权益与配额
|
||
authorizations/page.tsx # 授权获取记录
|
||
purchases/page.tsx # 购买记录
|
||
installations/page.tsx # 安装与绑定摘要
|
||
publications/page.tsx # 发布记录总览
|
||
components/
|
||
marketplace/
|
||
personal-center/
|
||
```
|
||
|
||
## 2. 市场空间
|
||
|
||
### 2.1 页面结构总览
|
||
|
||
| 页面 | 路由 | 核心组件 | 主要 API |
|
||
|---|---|---|---|
|
||
| 市场首页与发现 | `/marketplace` | `MarketSearch`, `AssetTypeTab`, `RecommendSection`, `AssetList` | `GET /app-api/muse/marketplace/assets`, `GET /app-api/muse/marketplace/categories` |
|
||
| 分类推荐与曝光 | `/marketplace/categories` | `CategoryTree`, `TopicCard`, `ExposureSummary` | `GET /app-api/muse/marketplace/categories` |
|
||
| 资产详情 | `/marketplace/assets/[assetId]` | `AssetHeader`, `LicensePanel`, `VersionInfo`, `GovernanceAlert`, `ActionBar` | `GET /app-api/muse/marketplace/assets/{assetId}` |
|
||
| 获取授权确认 | `/marketplace/assets/[assetId]/acquire` | `LicenseConfirm`, `RestrictionList`, `ExternalAuthRef` | `POST /app-api/muse/marketplace/assets/{assetId}/purchase` |
|
||
| 安装与跳转授权 | `/marketplace/assets/[assetId]/install` | `InstallPanel`, `TargetSelector`, `HandoffGenerator` | `POST /app-api/muse/marketplace/assets/{assetId}/install`, `POST /app-api/muse/marketplace/handoffs` |
|
||
| 发布者资产 | `/marketplace/publish` | `PublisherAssetList`, `StatusFilter`, `ExposureBadge` | `GET /app-api/muse/marketplace/my-publish-records` |
|
||
| 发布提交 | `/marketplace/publish/[draftId]` | `PublishForm`, `CheckRunner`, `SubmitConfirm` | `POST /app-api/muse/marketplace/publish-drafts`, `POST /app-api/muse/marketplace/publish-drafts/{draftId}/checks`, `POST /app-api/muse/marketplace/publish-requests` |
|
||
| 治理结果与申诉 | `/marketplace/assets/[assetId]/governance` | `GovernanceResult`, `ImpactList`, `AppealForm` | `GET /app-api/muse/marketplace/assets/{assetId}/governance-impact`, `POST /app-api/muse/marketplace/appeals` |
|
||
| 资产级记录 | `/marketplace/assets/[assetId]/records` | `RecordTimeline`, `RecordFilter` | 资产级记录通过详情页内嵌展示 |
|
||
|
||
### 2.2 资产发现交互
|
||
|
||
#### 2.2.1 搜索与筛选
|
||
|
||
```typescript
|
||
// lib/queries/marketplace.ts
|
||
// 市场资产列表查询 hook
|
||
export function useMarketplaceAssets(params: MarketplaceAssetsParams) {
|
||
return useQuery({
|
||
queryKey: ['marketplace', 'assets', params],
|
||
queryFn: () => fetchMarketplaceAssets(params),
|
||
// 保持搜索词、分类、筛选和滚动位置
|
||
// 注意:keepPreviousData 是 TanStack Query v4 写法,v5 改用 placeholderData: keepPreviousData(从 @tanstack/react-query 导入)
|
||
keepPreviousData: true,
|
||
});
|
||
}
|
||
|
||
interface MarketplaceAssetsParams {
|
||
keyword?: string; // 搜索关键词
|
||
assetType?: 'work' | 'agent' | 'knowledge_base'; // 资产类型
|
||
categoryId?: string; // 分类 ID
|
||
licenseType?: string; // 许可类型筛选
|
||
status?: string; // 状态筛选
|
||
sortBy?: 'relevance' | 'newest' | 'popular'; // 排序
|
||
pageNo: number;
|
||
pageSize: number;
|
||
}
|
||
```
|
||
|
||
交互规则:
|
||
|
||
- 搜索框支持即时搜索(debounce 300ms),按资产类型 Tab 切换不清空搜索词。
|
||
- 筛选条件变化时重置分页到第一页,保留搜索词。
|
||
- 从详情页返回时恢复搜索词、分类、筛选和滚动位置(通过 URL searchParams 持久化)。
|
||
- 未登录用户只能浏览公开摘要,获取、安装、绑定和收藏操作需要登录。
|
||
|
||
#### 2.2.2 推荐位
|
||
|
||
推荐区独立加载,失败不阻断列表渲染:
|
||
|
||
```typescript
|
||
// 推荐位独立查询,失败时静默降级
|
||
export function useMarketplaceRecommendations() {
|
||
return useQuery({
|
||
queryKey: ['marketplace', 'recommendations'],
|
||
queryFn: () => fetchCategories(), // GET /app-api/muse/marketplace/categories
|
||
retry: 1,
|
||
// 注意:useErrorBoundary 是 TanStack Query v4 写法,v5 改用 throwOnError
|
||
// 推荐位加载失败不影响主列表
|
||
useErrorBoundary: false,
|
||
});
|
||
}
|
||
```
|
||
|
||
#### 2.2.3 收藏
|
||
|
||
```typescript
|
||
// 收藏/取消收藏 mutation
|
||
export function useFavoriteAsset() {
|
||
return useMutation({
|
||
mutationFn: ({ assetId, action }: { assetId: string; action: 'add' | 'remove' }) =>
|
||
action === 'add'
|
||
? postFavorite(assetId) // POST /app-api/muse/marketplace/assets/{assetId}/favorite
|
||
: deleteFavorite(assetId), // DELETE /app-api/muse/marketplace/assets/{assetId}/favorite
|
||
onSuccess: () => {
|
||
queryClient.invalidateQueries(['marketplace', 'assets']);
|
||
},
|
||
});
|
||
}
|
||
```
|
||
|
||
### 2.3 购买/安装流程 UI
|
||
|
||
#### 2.3.1 获取授权确认页
|
||
|
||
获取授权确认页展示许可、版本、限制和外部授权引用状态。核心交互流程:
|
||
|
||
1. 进入页面时加载资产详情和获取确认信息。
|
||
2. 展示许可范围、允许用途、禁止用途、有效期。
|
||
3. 用户确认后调用购买接口,必须携带 `commandId` 幂等键。
|
||
4. 获取成功后可选择进入安装页或返回详情。
|
||
|
||
```typescript
|
||
// 获取授权 mutation
|
||
export function usePurchaseAsset() {
|
||
return useMutation({
|
||
mutationFn: (params: {
|
||
assetId: string;
|
||
commandId: string; // 幂等键,前端生成 UUID
|
||
}) => postPurchase(params.assetId, { commandId: params.commandId }),
|
||
// POST /app-api/muse/marketplace/assets/{assetId}/purchase
|
||
});
|
||
}
|
||
```
|
||
|
||
状态管理:
|
||
|
||
| 状态 | UI 表现 | 用户动作 |
|
||
|---|---|---|
|
||
| 可获取 | 主按钮"确认获取"可用 | 点击确认 |
|
||
| 需登录 | 主按钮禁用,提示登录 | 跳转登录 |
|
||
| 外部授权待确认 | 主按钮禁用,展示外部状态 | 刷新外部授权 |
|
||
| 授权失败 | 展示失败原因 | 重试或返回 |
|
||
| 已拥有 | 展示"已获取",引导安装 | 跳转安装页 |
|
||
| 资产不可获取 | 展示原因(下架/召回) | 返回列表 |
|
||
|
||
#### 2.3.2 安装流程
|
||
|
||
安装只适用于智能体和知识库资产。安装成功只表示资产进入账户可用列表,不等于绑定到作品。
|
||
|
||
```typescript
|
||
// 安装 mutation
|
||
export function useInstallAsset() {
|
||
return useMutation({
|
||
mutationFn: (params: {
|
||
assetId: string;
|
||
commandId: string;
|
||
}) => postInstall(params.assetId, { commandId: params.commandId }),
|
||
// POST /app-api/muse/marketplace/assets/{assetId}/install
|
||
});
|
||
}
|
||
```
|
||
|
||
#### 2.3.3 安装进度与结果
|
||
|
||
安装为同步操作,响应直接返回安装状态。UI 展示:
|
||
|
||
- 安装中:按钮 loading 态。
|
||
- 安装成功:展示"已安装"标记,显示可绑定目标摘要和跳转入口。
|
||
- 安装失败:展示失败原因(授权失效、版本不可用、来源下架)。
|
||
|
||
### 2.4 Handoff 机制的前端消费
|
||
|
||
#### 2.4.1 Handoff 概述
|
||
|
||
市场跨空间跳转使用服务端签发的一次性 handoff token。前端职责:
|
||
|
||
1. 在市场空间发起 handoff 创建请求。
|
||
2. 获取 handoff token 和目标页 URL。
|
||
3. 携带 token 跳转到目标 owner 空间。
|
||
4. 目标空间落地后消费 token,获取 handoff session。
|
||
5. 基于 session 执行目标 owner 的预检和确认。
|
||
|
||
#### 2.4.2 创建 Handoff
|
||
|
||
```typescript
|
||
// 创建市场 handoff
|
||
export function useCreateHandoff() {
|
||
return useMutation({
|
||
mutationFn: (params: CreateHandoffParams) =>
|
||
postHandoff(params),
|
||
// POST /app-api/muse/marketplace/handoffs
|
||
});
|
||
}
|
||
|
||
interface CreateHandoffParams {
|
||
assetId: string;
|
||
targetOwner: 'knowledge' | 'agent' | 'content';
|
||
targetAction: 'bind' | 'slot_bind' | 'asset_use';
|
||
targetWorkId?: string;
|
||
returnUrl: string; // 返回点
|
||
commandId: string; // 幂等键
|
||
}
|
||
```
|
||
|
||
#### 2.4.3 目标空间消费 Handoff
|
||
|
||
目标空间(如作品知识来源页)落地时:
|
||
|
||
```typescript
|
||
// 目标空间消费 handoff token
|
||
export function useConsumeHandoff(handoffToken: string | null) {
|
||
return useQuery({
|
||
queryKey: ['handoff', handoffToken],
|
||
queryFn: () => getHandoffStatus(handoffToken!),
|
||
// GET /app-api/muse/marketplace/handoffs/{handoffToken}
|
||
enabled: !!handoffToken,
|
||
});
|
||
}
|
||
```
|
||
|
||
#### 2.4.4 Token 过期处理
|
||
|
||
| 场景 | 错误码 | 前端处理 |
|
||
|---|---|---|
|
||
| Token 不存在 | `MARKET_HANDOFF_INVALID` | 返回市场刷新状态 |
|
||
| Token 已过期 | `PRECHECK_EXPIRED` | 提示过期,引导重新发起 |
|
||
| Token 已消费 | `MARKET_HANDOFF_INVALID` | 展示已消费状态 |
|
||
| Token 已取消 | `MARKET_HANDOFF_INVALID` | 返回市场 |
|
||
| 目标 owner 不匹配 | `MARKET_HANDOFF_INVALID` | 返回市场刷新 |
|
||
|
||
#### 2.4.5 Handoff 状态轮询
|
||
|
||
对于需要等待目标空间确认的场景,市场侧可轮询 handoff 状态:
|
||
|
||
```typescript
|
||
// 轮询 handoff 状态(用户从目标空间返回后刷新)
|
||
export function useHandoffStatus(handoffToken: string) {
|
||
return useQuery({
|
||
queryKey: ['handoff', 'status', handoffToken],
|
||
queryFn: () => getHandoffStatus(handoffToken),
|
||
// GET /app-api/muse/marketplace/handoffs/{handoffToken}
|
||
refetchOnWindowFocus: true, // 用户从目标空间返回时自动刷新
|
||
});
|
||
}
|
||
```
|
||
|
||
### 2.5 发布准备 UI
|
||
|
||
#### 2.5.1 发布提交流程
|
||
|
||
发布提交页面按资产类型(作品、智能体、知识库)分型展示不同表单字段和检查项。
|
||
|
||
流程步骤:
|
||
|
||
1. 保存发布草稿 → `POST /app-api/muse/marketplace/publish-drafts`
|
||
2. 运行发布检查 → `POST /app-api/muse/marketplace/publish-drafts/{draftId}/checks`
|
||
3. 检查通过后提交审核 → `POST /app-api/muse/marketplace/publish-requests`
|
||
|
||
```typescript
|
||
// 发布检查 mutation
|
||
export function useRunPublishCheck() {
|
||
return useMutation({
|
||
mutationFn: (draftId: string) =>
|
||
postPublishCheck(draftId),
|
||
// POST /app-api/muse/marketplace/publish-drafts/{draftId}/checks
|
||
});
|
||
}
|
||
|
||
// 提交发布申请 mutation
|
||
export function useSubmitPublishRequest() {
|
||
return useMutation({
|
||
mutationFn: (params: {
|
||
draftId: string;
|
||
marketPublishCheckId: string; // 消费发布检查结果
|
||
commandId: string;
|
||
}) => postPublishRequest(params),
|
||
// POST /app-api/muse/marketplace/publish-requests
|
||
});
|
||
}
|
||
```
|
||
|
||
#### 2.5.2 发布检查状态
|
||
|
||
| 检查状态 | UI 表现 | 用户动作 |
|
||
|---|---|---|
|
||
| 未检查 | "运行检查"按钮可用 | 点击运行 |
|
||
| 检查中 | 按钮 loading,展示进度 | 等待 |
|
||
| 检查通过 | 展示通过项,"提交审核"可用 | 提交 |
|
||
| 检查失败 | 展示阻断项和警告项 | 修正后重新检查 |
|
||
| 检查过期 | 提示过期,需重新检查 | 重新运行 |
|
||
|
||
#### 2.5.3 来源状态确认
|
||
|
||
发布前必须确认来源资产状态。前端调用来源状态查询:
|
||
|
||
```typescript
|
||
// 查询来源状态
|
||
export function useSourceStatus(params: SourceStatusParams) {
|
||
return useQuery({
|
||
queryKey: ['source-status', params],
|
||
queryFn: () => postSourceStatusQuery(params),
|
||
// POST /app-api/muse/source-status/query
|
||
});
|
||
}
|
||
```
|
||
|
||
来源状态异常时禁用发布提交按钮,展示原因和处理建议。
|
||
|
||
### 2.6 治理结果展示
|
||
|
||
#### 2.6.1 下架/召回通知
|
||
|
||
资产详情页顶部展示治理状态 Alert:
|
||
|
||
```typescript
|
||
// 治理影响查询
|
||
export function useGovernanceImpact(assetId: string) {
|
||
return useQuery({
|
||
queryKey: ['marketplace', 'governance-impact', assetId],
|
||
queryFn: () => getGovernanceImpact(assetId),
|
||
// GET /app-api/muse/marketplace/assets/{assetId}/governance-impact
|
||
enabled: !!assetId,
|
||
});
|
||
}
|
||
```
|
||
|
||
UI 展示规则:
|
||
|
||
| 治理状态 | Alert 类型 | 展示内容 | 可用动作 |
|
||
|---|---|---|---|
|
||
| 已下架 | warning | 下架原因、影响范围 | 查看替代、申诉 |
|
||
| 召回中 | error | 召回原因、影响范围、处理期限 | 停用安装、申诉 |
|
||
| 授权撤销 | error | 撤销原因、影响绑定 | 重新获取、替代 |
|
||
| 申诉中 | info | 申诉进度、预计处理时间 | 补充材料、撤回 |
|
||
|
||
#### 2.6.2 违规说明
|
||
|
||
违规说明展示在治理结果页,包含:
|
||
|
||
- 结果类型和原因摘要
|
||
- 生效时间
|
||
- 影响范围(新获取、新安装、新绑定、生成使用是否停止)
|
||
- 替代方案建议
|
||
- 申诉入口和期限
|
||
|
||
### 2.7 来源状态反馈
|
||
|
||
#### 2.7.1 来源失效 UI
|
||
|
||
当资产来源失效时,前端根据 `sourceStatus` 和 `actionPolicy` 展示不同 UI:
|
||
|
||
| sourceStatus | actionPolicy | UI 表现 |
|
||
|---|---|---|
|
||
| `active` | `allowed` | 正常展示,所有操作可用 |
|
||
| `stale` | `needs_recheck` | 黄色提示条,建议重验,提供重验按钮 |
|
||
| `revoked` | `blocked` | 红色提示,禁用绑定/生成 |
|
||
| `recalled` | `blocked` | 红色提示,展示召回说明 |
|
||
| `delisted` | `blocked` | 灰色提示,展示下架原因 |
|
||
|
||
#### 2.7.2 授权变化展示
|
||
|
||
授权状态变化时,资产详情页和安装页实时反映:
|
||
|
||
```typescript
|
||
// 资产详情页监听授权状态
|
||
// 通过 refetchOnWindowFocus 和 refetchInterval 保持最新
|
||
export function useAssetDetail(assetId: string) {
|
||
return useQuery({
|
||
queryKey: ['marketplace', 'asset', assetId],
|
||
queryFn: () => getAssetDetail(assetId),
|
||
// GET /app-api/muse/marketplace/assets/{assetId}
|
||
refetchOnWindowFocus: true,
|
||
staleTime: 30_000, // 30 秒内不重复请求
|
||
});
|
||
}
|
||
```
|
||
|
||
### 2.8 错误处理和边界情况
|
||
|
||
#### 2.8.1 通用错误处理策略
|
||
|
||
```typescript
|
||
// lib/api/error-handler.ts
|
||
// 市场空间错误处理映射
|
||
const marketplaceErrorHandlers: Record<string, ErrorHandler> = {
|
||
UNAUTHENTICATED: () => redirectToLogin(),
|
||
FORBIDDEN: (ctx) => showNoPermissionToast(ctx.msg),
|
||
RESOURCE_NOT_FOUND: () => redirectToMarketplaceHome(),
|
||
SOURCE_NEEDS_RECHECK: (ctx) => showRecheckPrompt(ctx.data),
|
||
SOURCE_BLOCKED: (ctx) => showBlockedAlert(ctx.data),
|
||
PRECHECK_EXPIRED: (ctx) => showExpiredPrompt(ctx.data),
|
||
MARKET_HANDOFF_INVALID: () => redirectToMarketplaceWithRefresh(),
|
||
IDEMPOTENCY_CONFLICT: (ctx) => showConflictToast(ctx.msg),
|
||
FEATURE_DISABLED: (ctx) => hideOrDisableEntry(ctx.data),
|
||
};
|
||
```
|
||
|
||
#### 2.8.2 边界情况处理
|
||
|
||
| 边界情况 | 处理方式 |
|
||
|---|---|
|
||
| 资产在浏览过程中被下架 | 详情页展示下架提示,禁用获取/安装按钮 |
|
||
| 获取过程中授权失效 | 中断获取流程,展示失效原因 |
|
||
| Handoff 跳转后目标空间不可用 | 展示错误页,提供返回市场按钮 |
|
||
| 发布检查过程中资产版本变化 | 检查结果标记为过期,需重新检查 |
|
||
| 网络中断 | TanStack Query 自动重试,展示离线提示 |
|
||
| 分页加载失败 | 保留已加载数据,展示重试按钮 |
|
||
|
||
---
|
||
|
||
## 3. 个人中心空间
|
||
|
||
### 3.1 页面结构总览
|
||
|
||
| 页面 | 路由 | 核心组件 | 主要 API |
|
||
|---|---|---|---|
|
||
| 账户总览 | `/profile` | `OverviewCard`, `SecurityCard`, `UsageCard`, `AssetSummaryCard`, `AlertBar` | `GET /app-api/muse/me`, `GET /app-api/muse/account/entitlements`, `GET /app-api/muse/account/usage` |
|
||
| 个人资料 | `/profile/info` | `ProfileForm`, `ContactVerification`, `AvatarUpload` | `GET /app-api/muse/profile`, `PATCH /app-api/muse/profile` |
|
||
| 安全与登录 | `/profile/security` | `PasswordSection`, `MFASection`, `SessionList`, `SecurityEventList` | `GET /app-api/muse/account/security-events` |
|
||
| 偏好与通知 | `/profile/preferences` | `PreferenceForm`, `NotificationSettings` | 偏好相关接口(复用 Yudao 基础能力) |
|
||
| Token 与用量 | `/profile/usage` | `UsageTrend`, `UsageTable`, `AttributionDetail` | `GET /app-api/muse/account/usage`, `GET /app-api/muse/account/entitlements` |
|
||
| 权益与配额 | `/profile/entitlements` | `EntitlementCard`, `QuotaProgress`, `ChangeLog` | `GET /app-api/muse/account/entitlements` |
|
||
| 授权获取记录 | `/profile/authorizations` | `AuthRecordTable`, `SnapshotDrawer` | `GET /app-api/muse/account/licenses` |
|
||
| 购买记录 | `/profile/purchases` | `PurchaseTable`, `ReceiptDrawer` | `GET /app-api/muse/account/purchases` |
|
||
| 安装与绑定摘要 | `/profile/installations` | `InstalledList`, `BindingAnomalyList` | 通过 `/app-api/muse/me` 和相关接口聚合 |
|
||
| 发布记录总览 | `/profile/publications` | `PublishRecordTable`, `StatusBadge` | `GET /app-api/muse/account/publish-records` |
|
||
|
||
### 3.2 权益摘要展示
|
||
|
||
#### 3.2.1 `/app-api/muse/me` 数据消费
|
||
|
||
应用入口初始化时调用 `/app-api/muse/me`,获取当前用户权益摘要和可见产品空间:
|
||
|
||
```typescript
|
||
// lib/queries/me.ts
|
||
// 当前用户信息和权益摘要
|
||
export function useCurrentUser() {
|
||
return useQuery({
|
||
queryKey: ['me'],
|
||
queryFn: () => fetchMe(),
|
||
// GET /app-api/muse/me
|
||
staleTime: 5 * 60 * 1000, // 5 分钟缓存
|
||
refetchOnWindowFocus: true,
|
||
});
|
||
}
|
||
|
||
// 返回数据结构(前端类型定义)
|
||
interface MeResponse {
|
||
userId: string;
|
||
nickname: string;
|
||
avatar: string;
|
||
entitlementSummary: {
|
||
planName: string;
|
||
tokenQuota: number;
|
||
tokenUsed: number;
|
||
expiresAt: string | null;
|
||
isLimited: boolean;
|
||
};
|
||
visibleSpaces: string[]; // 可见产品空间列表
|
||
defaultEntry: string; // 默认入口
|
||
securityRisk: boolean; // 是否有安全风险
|
||
pendingAlerts: number; // 待处理提醒数
|
||
}
|
||
```
|
||
|
||
#### 3.2.2 账户总览页数据聚合
|
||
|
||
账户总览页并行加载多个摘要接口:
|
||
|
||
```typescript
|
||
// 账户总览页数据加载
|
||
export function useProfileOverview() {
|
||
const me = useCurrentUser();
|
||
const entitlements = useEntitlements();
|
||
const usage = useUsageSummary();
|
||
const securityEvents = useSecurityEvents({ limit: 5 });
|
||
|
||
return {
|
||
me,
|
||
entitlements,
|
||
usage,
|
||
securityEvents,
|
||
isLoading: me.isLoading || entitlements.isLoading,
|
||
};
|
||
}
|
||
|
||
// 权益与配额查询
|
||
function useEntitlements() {
|
||
return useQuery({
|
||
queryKey: ['account', 'entitlements'],
|
||
queryFn: () => fetchEntitlements(),
|
||
// GET /app-api/muse/account/entitlements
|
||
});
|
||
}
|
||
|
||
// 用量摘要查询
|
||
function useUsageSummary() {
|
||
return useQuery({
|
||
queryKey: ['account', 'usage'],
|
||
queryFn: () => fetchUsage(),
|
||
// GET /app-api/muse/account/usage
|
||
});
|
||
}
|
||
```
|
||
|
||
### 3.3 配额和用量可视化
|
||
|
||
#### 3.3.1 配额进度条
|
||
|
||
权益与配额页使用进度条可视化展示额度消耗:
|
||
|
||
```typescript
|
||
// components/personal-center/QuotaProgress.tsx
|
||
interface QuotaProgressProps {
|
||
label: string; // 配额名称
|
||
total: number; // 总额度
|
||
used: number; // 已用
|
||
unit: string; // 单位(如 "Token")
|
||
expiresAt?: string; // 到期时间
|
||
isLimited?: boolean; // 是否被限流
|
||
}
|
||
```
|
||
|
||
展示规则:
|
||
|
||
- 使用率 < 70%:绿色进度条
|
||
- 使用率 70%-90%:黄色进度条 + 提醒文案
|
||
- 使用率 > 90%:红色进度条 + 额度不足警告
|
||
- 已过期:灰色进度条 + 过期提示
|
||
- 被限流:红色进度条 + 限流原因和恢复路径
|
||
|
||
#### 3.3.2 用量趋势图
|
||
|
||
Token 与用量页展示近 30 天用量趋势:
|
||
|
||
```typescript
|
||
// 用量趋势数据
|
||
export function useUsageTrend(params: { days: number; groupBy: 'day' | 'week' }) {
|
||
return useQuery({
|
||
queryKey: ['account', 'usage', 'trend', params],
|
||
queryFn: () => fetchUsage(),
|
||
// GET /app-api/muse/account/usage(带时间范围参数)
|
||
});
|
||
}
|
||
```
|
||
|
||
用量明细表支持按来源筛选:
|
||
|
||
| 筛选维度 | 说明 |
|
||
|---|---|
|
||
| 时间范围 | 近 7 天 / 30 天 / 自定义 |
|
||
| 归属对象 | 作品 / 智能体 / 知识库 |
|
||
| 状态 | 已归属 / 待归属 / 异常 |
|
||
|
||
#### 3.3.3 跳转来源记录
|
||
|
||
用量明细中的归属对象支持跳转到对应 owner 空间:
|
||
|
||
```typescript
|
||
// 跨空间跳转(从个人中心到作品/智能体/知识库记录)
|
||
function handleJumpToSource(record: UsageRecord) {
|
||
const targetUrl = buildSourceUrl(record.sourceType, record.sourceId);
|
||
// 使用 router 跳转,携带返回点
|
||
router.push(`${targetUrl}?returnTo=/profile/usage`);
|
||
}
|
||
```
|
||
|
||
### 3.4 安全事件列表和处理交互
|
||
|
||
#### 3.4.1 安全事件列表
|
||
|
||
```typescript
|
||
// 安全事件查询
|
||
export function useSecurityEvents(params: { pageNo: number; pageSize: number }) {
|
||
return useQuery({
|
||
queryKey: ['account', 'security-events', params],
|
||
queryFn: () => fetchSecurityEvents(params),
|
||
// GET /app-api/muse/account/security-events
|
||
});
|
||
}
|
||
```
|
||
|
||
安全事件列表展示:
|
||
|
||
| 字段 | 说明 |
|
||
|---|---|
|
||
| 事件类型 | 异地登录、密码修改、二次验证变更、会话异常 |
|
||
| 时间 | 事件发生时间 |
|
||
| 设备/地点 | 脱敏展示 |
|
||
| 风险等级 | 高/中/低 |
|
||
| 处理状态 | 未处理、已确认本人、已处理 |
|
||
|
||
#### 3.4.2 确认非本人操作
|
||
|
||
高风险安全事件支持"确认本人操作"交互:
|
||
|
||
```typescript
|
||
// 确认安全事件为本人操作
|
||
export function useAcknowledgeSecurityEvent() {
|
||
return useMutation({
|
||
mutationFn: (params: {
|
||
eventId: string;
|
||
confirmation: string; // 确认说明
|
||
commandId: string;
|
||
}) => postAcknowledgeSecurityEvent(params),
|
||
// POST /app-api/muse/account/security-events/{eventId}/acknowledge
|
||
onSuccess: () => {
|
||
queryClient.invalidateQueries(['account', 'security-events']);
|
||
},
|
||
});
|
||
}
|
||
```
|
||
|
||
交互流程:
|
||
|
||
1. 用户点击"这是我本人"按钮。
|
||
2. 高风险事件触发 step-up 验证(二次验证或密码确认)。
|
||
3. step-up 通过后展示事件摘要和确认影响。
|
||
4. 用户确认后追加处置标记。
|
||
5. 刷新安全事件列表和风险提示。
|
||
|
||
如果用户认为非本人操作,引导:修改密码 → 撤销可疑会话 → 联系客服。
|
||
|
||
### 3.5 购买/发布记录的分页和筛选
|
||
|
||
#### 3.5.1 购买记录
|
||
|
||
```typescript
|
||
// 购买记录查询
|
||
export function usePurchaseRecords(params: PurchaseRecordParams) {
|
||
return useQuery({
|
||
queryKey: ['account', 'purchases', params],
|
||
queryFn: () => fetchPurchases(params),
|
||
// GET /app-api/muse/account/purchases
|
||
// 注意:keepPreviousData 是 TanStack Query v4 写法,v5 改用 placeholderData: keepPreviousData(从 @tanstack/react-query 导入)
|
||
keepPreviousData: true,
|
||
});
|
||
}
|
||
|
||
interface PurchaseRecordParams {
|
||
pageNo: number;
|
||
pageSize: number;
|
||
status?: 'completed' | 'processing' | 'failed';
|
||
assetType?: 'work' | 'agent' | 'knowledge_base';
|
||
startTime?: string;
|
||
endTime?: string;
|
||
}
|
||
```
|
||
|
||
购买记录表格列:
|
||
|
||
| 列 | 数据 | 操作 |
|
||
|---|---|---|
|
||
| 时间 | 购买时间 | - |
|
||
| 资产 | 资产名称和类型 | 跳转市场详情 |
|
||
| 来源 | 购买/免费/管理员授权 | - |
|
||
| 金额 | 金额或"免费" | - |
|
||
| 状态 | 已完成/处理中/失败 | 查看凭证 |
|
||
| 授权结果 | 是否已生成授权 | 跳转授权记录 |
|
||
|
||
#### 3.5.2 发布记录
|
||
|
||
```typescript
|
||
// 发布记录查询
|
||
export function usePublishRecords(params: PublishRecordParams) {
|
||
return useQuery({
|
||
queryKey: ['account', 'publish-records', params],
|
||
queryFn: () => fetchPublishRecords(params),
|
||
// GET /app-api/muse/account/publish-records
|
||
// 注意:keepPreviousData 是 TanStack Query v4 写法,v5 改用 placeholderData: keepPreviousData(从 @tanstack/react-query 导入)
|
||
keepPreviousData: true,
|
||
});
|
||
}
|
||
|
||
interface PublishRecordParams {
|
||
pageNo: number;
|
||
pageSize: number;
|
||
assetType?: 'work' | 'agent' | 'knowledge_base';
|
||
reviewStatus?: 'draft' | 'submitted' | 'reviewing' | 'needs_supplement' | 'approved' | 'rejected';
|
||
marketStatus?: 'listed' | 'delisted' | 'recalled';
|
||
}
|
||
```
|
||
|
||
#### 3.5.3 通用分页组件
|
||
|
||
所有记录页使用统一分页组件,支持:
|
||
|
||
- 页码切换和每页条数选择
|
||
- URL searchParams 持久化(刷新不丢失筛选)
|
||
- 加载中保留上一页数据(`keepPreviousData`)
|
||
- 空态展示和跳转入口
|
||
|
||
### 3.6 跳转规则
|
||
|
||
#### 3.6.1 从个人中心跳转到其他空间
|
||
|
||
个人中心是 read model 和跳转入口,所有业务处理必须跳转到对应 owner 空间。
|
||
|
||
| 来源页面 | 跳转目标 | 触发条件 | 携带参数 |
|
||
|---|---|---|---|
|
||
| 授权获取记录 | 市场资产详情 | 点击资产名称 | `assetId`, `returnTo` |
|
||
| 授权获取记录 | 智能体已安装页 | 点击"去安装" | `assetId`, `returnTo` |
|
||
| 授权获取记录 | 知识库已安装页 | 点击"去安装" | `assetId`, `returnTo` |
|
||
| 安装与绑定摘要 | 作品智能体关联 | 点击异常处理 | `workId`, `slotKey`, `returnTo` |
|
||
| 安装与绑定摘要 | 作品知识来源 | 点击异常处理 | `workId`, `bindingId`, `returnTo` |
|
||
| 发布记录总览 | 市场发布提交 | 点击"去补充" | `draftId`, `returnTo` |
|
||
| 发布记录总览 | 智能体发布准备 | 点击"去处理" | `agentId`, `returnTo` |
|
||
| 发布记录总览 | 知识库发布准备 | 点击"去处理" | `kbId`, `returnTo` |
|
||
| Token 与用量 | 作品记录与用量 | 点击归属作品 | `workId`, `returnTo` |
|
||
| 权益与配额 | 市场(补充权益) | 点击"补充权益" | `returnTo` |
|
||
|
||
#### 3.6.2 返回规则
|
||
|
||
所有跳转携带 `returnTo` 参数,目标空间处理完成后通过该参数返回个人中心并刷新对应数据:
|
||
|
||
```typescript
|
||
// 跳转工具函数
|
||
function navigateToOwnerSpace(target: string, returnTo: string) {
|
||
const url = new URL(target, window.location.origin);
|
||
url.searchParams.set('returnTo', returnTo);
|
||
router.push(url.pathname + url.search);
|
||
}
|
||
|
||
// 返回个人中心时刷新数据
|
||
function handleReturnFromOwnerSpace() {
|
||
const returnTo = searchParams.get('returnTo');
|
||
if (returnTo?.startsWith('/profile')) {
|
||
// 失效相关查询缓存,触发重新加载
|
||
queryClient.invalidateQueries(['account']);
|
||
router.push(returnTo);
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 状态管理策略
|
||
|
||
### 4.1 市场空间状态分层
|
||
|
||
| 状态类型 | 管理方式 | 示例 |
|
||
|---|---|---|
|
||
| 服务器数据 | TanStack Query | 资产列表、详情、授权状态、治理结果 |
|
||
| 搜索/筛选状态 | URL searchParams | 搜索词、分类、排序、分页 |
|
||
| UI 临时态 | React useState | 弹窗开关、表单编辑中、loading |
|
||
| 跨页面共享 | Zustand store | 当前 handoff session、返回点 |
|
||
|
||
### 4.2 个人中心状态分层
|
||
|
||
| 状态类型 | 管理方式 | 示例 |
|
||
|---|---|---|
|
||
| 服务器数据 | TanStack Query | 权益、用量、记录列表、安全事件 |
|
||
| 筛选/分页 | URL searchParams | 时间范围、状态筛选、页码 |
|
||
| 表单状态 | React Hook Form | 个人资料编辑、偏好设置 |
|
||
| step-up 状态 | Zustand store | 二次验证流程状态 |
|
||
|
||
### 4.3 缓存失效策略
|
||
|
||
```typescript
|
||
// 市场操作后的缓存失效
|
||
const marketplaceMutationConfig = {
|
||
// 购买成功后失效资产详情和授权记录
|
||
onPurchaseSuccess: () => {
|
||
queryClient.invalidateQueries(['marketplace', 'asset']);
|
||
queryClient.invalidateQueries(['account', 'licenses']);
|
||
queryClient.invalidateQueries(['me']); // 权益可能变化
|
||
},
|
||
// 安装成功后失效安装状态
|
||
onInstallSuccess: () => {
|
||
queryClient.invalidateQueries(['marketplace', 'asset']);
|
||
queryClient.invalidateQueries(['account', 'installations']);
|
||
},
|
||
// 发布提交后失效发布记录
|
||
onPublishSuccess: () => {
|
||
queryClient.invalidateQueries(['account', 'publish-records']);
|
||
queryClient.invalidateQueries(['marketplace', 'my-publish-records']);
|
||
},
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 管理端市场治理(muse-admin)
|
||
|
||
管理端市场治理页面在 `muse-admin/` 中实现,使用 Vben Admin 框架,调用 `/admin-api/**`。
|
||
|
||
### 5.1 管理端市场页面
|
||
|
||
| 页面 | API | 说明 |
|
||
|---|---|---|
|
||
| 市场资产列表 | `GET /admin-api/muse/market/assets` | 查看所有市场资产和治理摘要 |
|
||
| 发布申请审核 | `GET /admin-api/muse/market/publish-requests` | 审核发布申请 |
|
||
| 审核通过/拒绝 | `POST /admin-api/muse/market/publish-requests/{id}/approve` | 审核决策 |
|
||
| 资产下架 | `POST /admin-api/muse/market/assets/{id}/delist` | 下架资产 |
|
||
| 资产召回 | `POST /admin-api/muse/market/assets/{id}/recall` | 召回资产 |
|
||
| 申诉处理 | `GET /admin-api/muse/market/appeals` | 查看和处理申诉 |
|
||
|
||
管理端不承载普通用户的市场发现、购买、安装或绑定流程。
|
||
|
||
---
|
||
|
||
## 6. 关联阅读
|
||
|
||
| 文档 | 关联内容 |
|
||
|---|---|
|
||
| `产品-02F-市场功能规格.md` | 市场产品定义、页面规格、操作规格、跨空间跳转 |
|
||
| `产品-02G-个人中心功能规格.md` | 个人中心产品定义、页面规格、权限和安全规则 |
|
||
| `后端-05-统一API契约-v1.md` | 所有 API 路径、请求响应格式、错误码定义 |
|
||
| `架构-01-系统全貌与边界上下文.md` | Handoff 机制、BC 边界、Source/Authorization 横切契约 |
|
||
| `前端-01-工程结构与核心依赖.md` | 工程结构、路由约定、状态分层、接口边界 |
|
||
| `前端-02-写作台与候选交互.md` | 写作台交互模式参考 |
|
||
| `前端-03-元引擎与动态表单.md` | MetaSchema 消费和动态表单渲染 |
|
||
| `架构-04-状态机与约束清单.md` | 资产状态机、授权状态机 |
|
||
|