# P3: muse-admin 管理端搭建 — 执行计划 > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. **目标:** 在 Vben Admin fork 基础上搭建 muse-admin,实现 MetaSchema 管理、系统治理、AI 配置、市场治理、全局知识管理、Account/New-API、任务监控、日志审计功能域。 **架构:** Vue 3 + Vben Admin + TypeScript,Composition API + SFC script setup,defHttp API 集成,Vben 内置表格/表单组件复用。 **技术栈:** Vue 3.5, TypeScript 5, Vben Admin 5, Pinia, Vitest + Vue Test Utils + Playwright 注: muse-admin 已 fork 完成,存在 `apps/web-antd` 和 `packages/` 结构。 **合同校准(2026-05-24):** - 以 `design-docs/产品-02B-管理员控制台功能规格.md`、`docs/dev-baseline/muse-admin/CLAUDE.md` 和 `docs/api-contracts/**/openapi.yaml` 为实现依据;本文示例代码如与上述合同冲突,以上述合同为准。 - Muse 业务页面目录使用 `apps/web-antd/src/views/muse/**`,不是根级 `src/views/{governance,ai,...}`。 - Account/New-API 页面只实现治理和对账所需的脱敏摘要、配额调整、网关绑定、余额查询、调用日志归属;用户侧账户完整体验仍由 `产品-02G` 承接。 - 日志审计必须包含接口调用日志和业务审计日志两个 surface;对应契约为 `/admin-api/muse/audit/api-logs`、`/admin-api/muse/audit/api-logs/{logId}`、`/admin-api/muse/audit/business-events`、`/admin-api/muse/audit/business-events/{eventId}`。 --- ## Step 1: 工程调整 ### Task 1.1: 业务目录结构建立 **仓库路径:** `muse-admin/` - [ ] **Step 1: 创建业务模块目录** ```bash mkdir -p muse-admin/apps/web-antd/src/views/muse/{governance,ai,knowledge,market,account,newapi,jobs,audit} mkdir -p muse-admin/apps/web-antd/src/api/muse/{governance,ai,knowledge,market,account,newapi,jobs,audit} ``` - [ ] **Step 2: 检查现有结构** ```bash ls muse-admin/apps/web-antd/src/views/ ls muse-admin/packages/@core/ ``` - [ ] **Step 3: 提交** ```bash git add muse-admin/apps/web-antd/src/views/muse/ muse-admin/apps/web-antd/src/api/muse/ git commit -m "feat(struct): 建立管理端业务模块目录" ``` ### Task 1.2: API 类型集成 - [ ] **Step 1: 复制 OpenAPI 生成的类型** ```bash cp docs/api-contracts/generated/typescript/*.ts muse-admin/apps/web-antd/src/api/types/ ``` - [ ] **Step 2: 编写 API 客户端** ```typescript // muse-admin/apps/web-antd/src/api/muse/client.ts import { requestClient } from '#/api/request'; const BASE = '/admin-api/muse'; export const museAdminApi = { get: (url: string, params?: Record) => requestClient.get(`${BASE}${url}`, { params }), post: (url: string, data?: unknown) => requestClient.post(`${BASE}${url}`, data), put: (url: string, data?: unknown) => requestClient.put(`${BASE}${url}`, data), delete: (url: string) => requestClient.delete(`${BASE}${url}`), }; ``` - [ ] **Step 3: 提交** ```bash git add -A && git commit -m "feat(api): 集成管理端 API 客户端 + OpenAPI 类型包" ``` --- ## Step 2: 管理页面开发(按优先级) ### Task 2.1: MetaSchema 管理 — 列表页 **文件:** - 创建: `apps/web-antd/src/views/governance/MetaSchemaList.vue` - 创建: `apps/web-antd/src/api/muse/governance/meta-schema.ts` - [ ] **Step 1: 编写 API service** ```typescript // apps/web-antd/src/api/muse/governance/meta-schema.ts import { museAdminApi } from '../client'; export interface MetaSchemaSummary { schemaKey: string; displayName: string; fieldType: string; scope: string; activeVersion: number; status: string; } export function listMetaSchemas(params: { pageNo: number; pageSize: number; scope?: string; }) { return museAdminApi.get<{ total: number; list: MetaSchemaSummary[]; }>('/governance/meta-schemas', params); } export function getMetaSchema(schemaKey: string) { return museAdminApi.get(`/governance/meta-schemas/${schemaKey}`); } export function createMetaSchemaDraft(schemaKey: string, data: any) { return museAdminApi.post(`/governance/meta-schemas/${schemaKey}/drafts`, data); } export function publishMetaSchemaDraft(schemaKey: string, draftVersion: number, data: any) { return museAdminApi.post( `/governance/meta-schemas/${schemaKey}/drafts/${draftVersion}/publish`, data ); } ``` - [ ] **Step 2: 编写列表页** ```vue ``` - [ ] **Step 3: 编写测试** ```typescript // apps/web-antd/src/views/governance/__tests__/MetaSchemaList.spec.ts import { describe, it, expect, vi } from 'vitest'; import { mount } from '@vue/test-utils'; import MetaSchemaList from '../MetaSchemaList.vue'; vi.mock('#/api/muse/governance/meta-schema', () => ({ listMetaSchemas: vi.fn().mockResolvedValue({ total: 2, list: [ { schemaKey: 'character_name', displayName: '角色名', fieldType: 'string', scope: 'work', activeVersion: 3, status: 'active' }, { schemaKey: 'world_setting', displayName: '世界设定', fieldType: 'text', scope: 'global', activeVersion: 1, status: 'active' }, ], }), })); describe('MetaSchemaList', () => { it('should render table', () => { const wrapper = mount(MetaSchemaList); expect(wrapper.find('.p-4').exists()).toBe(true); }); }); ``` - [ ] **Step 4: 提交** ```bash git add -A && git commit -m "feat(governance): 实现 MetaSchema 列表页(Vben Table + API 集成)" ``` ### Task 2.2: MetaSchema 管理 — 详情/草稿编辑页 实现 MetaSchema 详情页,包含: - 版本历史时间线 - 当前 active 版本字段展示 - 草稿编辑 + 校验 + 影响预览 + 发布流程 - 灰度规则配置 使用 Vben 内置表单组件 + 动态表单渲染。 ### Task 2.3-2.5: 其余管理页面 按优先级依次实现: **Task 2.3: 系统治理** — 用户管理(复用 Yudao system 模块)、角色权限配置、审计日志查看 **Task 2.4: AI 配置** — Prompt 模板管理、质量门控维度配置、保护节点注册管理、Tool Grant 配置 **Task 2.5: 市场治理 + 全局知识管理** — 资产审核(上架/驳回)、下架/召回、申诉处理、全局知识库维护、知识来源管理 每个页面遵循相同模式:API service → 组件实现 → 测试 → 提交。 --- ### Task 2.6: Account 管理页面 **文件:** - 创建: `apps/web-antd/src/api/muse/account/index.ts` **页面清单:** | 页面 | 路由 | 说明 | |------|------|------| | 用户权益列表 | `/account/entitlements` | 表格:用户 + 权益类型 + 上限 + 已用 + 过期时间 | | 配额调整表单 | `/account/quota-adjustments` | 弹窗:用户 + 资源类型 + 调整量 + 原因 + commandId | | New-API 绑定状态 | `/account/new-api-bindings` | 表格:用户 + 绑定状态 + 同步状态 | | 购买/使用记录 | `/account/records` | 只读脱敏治理摘要;不实现 `产品-02G` 的用户侧完整账户体验 | **API endpoints:** ``` GET /admin-api/muse/account/users # 用户列表 GET /admin-api/muse/account/users/{userId}/entitlements # 用户权益 POST /admin-api/muse/account/users/{userId}/quota-adjustments # 配额调整 GET /admin-api/muse/account/new-api-bindings # New-API 绑定状态 GET /admin-api/muse/account/usage-records # 脱敏用量摘要 GET /admin-api/muse/account/purchase-records # 脱敏购买摘要 ``` **代码示例 — API service:** ```typescript // apps/web-antd/src/api/muse/account/index.ts import { museAdminApi } from '../client'; export interface UserEntitlement { userId: string; entitlementType: string; limit: number; used: number; expiry: string; } export interface QuotaAdjustment { userId: string; resourceType: string; adjustmentAmount: number; reason: string; commandId: string; } export function getAccountUsers(params: { pageNo: number; pageSize: number }) { return museAdminApi.get<{ total: number; list: any[] }>('/account/users', params); } export function getUserEntitlements(userId: string) { return museAdminApi.get(`/account/users/${userId}/entitlements`); } export function adjustQuota(userId: string, data: QuotaAdjustment) { return museAdminApi.post(`/account/users/${userId}/quota-adjustments`, data); } export function getNewApiBindings(params: { pageNo: number; pageSize: number }) { return museAdminApi.get<{ total: number; list: any[] }>('/account/new-api-bindings', params); } ``` ### Task 2.7: 任务监控页面 **文件:** - 创建: `apps/web-antd/src/api/muse/jobs/index.ts` **页面清单:** | 页面 | 路由 | 说明 | |------|------|------| | 任务列表 | `/jobs` | 表格:job ID + 类型 + 状态 + 创建时间 + 重试次数 | | 任务详情 | `/jobs/:jobId` | 状态 + 失败原因 + 重试/取消按钮 | | 源事件列表 | `/jobs/source-events` | 表格:事件类型 + 来源 + 状态 + 影响摘要 | **API endpoints:** ``` GET /admin-api/muse/jobs # 任务列表 GET /admin-api/muse/jobs/{jobId} # 任务详情 POST /admin-api/muse/jobs/{jobId}/retry # 重试任务 GET /admin-api/muse/source-events # 源事件列表 ``` **代码示例 — API service:** ```typescript // apps/web-antd/src/api/muse/jobs/index.ts import { museAdminApi } from '../client'; export interface JobSummary { jobId: string; jobType: string; status: string; createdAt: string; retryCount: number; } export interface JobDetail extends JobSummary { failureReason?: string; payload?: Record; result?: Record; } export interface SourceEvent { eventType: string; source: string; status: string; impactSummary: string; createdAt: string; } export function listJobs(params: { pageNo: number; pageSize: number; status?: string }) { return museAdminApi.get<{ total: number; list: JobSummary[] }>('/jobs', params); } export function getJob(jobId: string) { return museAdminApi.get(`/jobs/${jobId}`); } export function retryJob(jobId: string) { return museAdminApi.post(`/jobs/${jobId}/retry`); } export function listSourceEvents(params: { pageNo: number; pageSize: number }) { return museAdminApi.get<{ total: number; list: SourceEvent[] }>('/source-events', params); } ``` ### Task 2.8: 审计日志页面 **文件:** - 创建: `apps/web-antd/src/api/muse/audit/index.ts` **页面清单:** | 页面 | 路由 | 说明 | |------|------|------| | 业务审计事件列表 | `/audit/business-events` | 表格:时间戳 + 操作者 + 操作 + 目标 + 结果 | | 审计详情 | `/audit/business-events/:eventId` | 完整 before/after 快照对比 | | 接口调用日志 | `/audit/api-logs` | 表格:请求 ID + 调用人 + 路径摘要 + 状态码 + 耗时 | | 接口调用详情 | `/audit/api-logs/:logId` | 只展示脱敏请求/响应摘要,不展示 token、secret、完整 header 或私有正文 | **API endpoints:** ``` GET /admin-api/muse/audit/api-logs # 接口调用日志列表 GET /admin-api/muse/audit/api-logs/{logId} # 接口调用日志详情 GET /admin-api/muse/audit/business-events # 业务审计事件列表 GET /admin-api/muse/audit/business-events/{eventId} # 业务审计详情 ``` **代码示例 — API service:** ```typescript // apps/web-antd/src/api/muse/audit/index.ts import { museAdminApi } from '../client'; export interface BusinessAuditEvent { eventId: string; timestamp: string; actor: string; action: string; target: string; result: string; } export interface BusinessAuditDetail extends BusinessAuditEvent { beforeSnapshot?: Record; afterSnapshot?: Record; } export function listBusinessAuditEvents(params: { pageNo: number; pageSize: number; actor?: string; action?: string }) { return museAdminApi.get<{ total: number; list: BusinessAuditEvent[] }>('/audit/business-events', params); } export function getBusinessAuditDetail(eventId: string) { return museAdminApi.get(`/audit/business-events/${eventId}`); } ``` --- ## Step 3: Mock API 配置 - [ ] **Step 1: 配置 MSW 或 Vben 内置 Mock** 为每个 `/admin-api/muse/**` 接口提供 mock 数据,使管理端可独立开发。 --- ## 完成标准 - [ ] 5 个功能域管理页面可交互 - [ ] 组件单元测试覆盖率 ≥70%(Vitest + Vue Test Utils) - [ ] E2E 测试覆盖核心管理流程(Playwright) - [ ] ESLint + Prettier + TypeScript 类型检查通过 - [ ] Vite build 成功