oh-my-muse/design-docs/前端-04-市场与个人中心交互.md
zizi 33aad93bef 提交全维度文档review后的22项架构决策落地
基于产品/架构/流程/前端/后端五维度并行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解决复杂度、知识确认默认自动+冲突时人工
2026-05-24 04:28:52 +08:00

841 lines
30 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 前端-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` | 资产状态机、授权状态机 |