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