oh-my-muse/docs/superpowers/plans/2026-05-24-P3-muse-admin.md

14 KiB
Raw Blame History

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 + TypeScriptComposition API + SFC script setupdefHttp API 集成Vben 内置表格/表单组件复用。

技术栈: Vue 3.5, TypeScript 5, Vben Admin 5, Pinia, Vitest + Vue Test Utils + Playwright

注: muse-admin 已 fork 完成,存在 apps/web-antdpackages/ 结构。

合同校准2026-05-24:

  • design-docs/产品-02B-管理员控制台功能规格.mddocs/dev-baseline/muse-admin/CLAUDE.mddocs/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: 创建业务模块目录
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: 检查现有结构
ls muse-admin/apps/web-antd/src/views/
ls muse-admin/packages/@core/
  • Step 3: 提交
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 生成的类型
cp docs/api-contracts/generated/typescript/*.ts muse-admin/apps/web-antd/src/api/types/
  • Step 2: 编写 API 客户端
// muse-admin/apps/web-antd/src/api/muse/client.ts
import { requestClient } from '#/api/request';

const BASE = '/admin-api/muse';

export const museAdminApi = {
  get: <T>(url: string, params?: Record<string, unknown>) =>
    requestClient.get<T>(`${BASE}${url}`, { params }),

  post: <T>(url: string, data?: unknown) =>
    requestClient.post<T>(`${BASE}${url}`, data),

  put: <T>(url: string, data?: unknown) =>
    requestClient.put<T>(`${BASE}${url}`, data),

  delete: <T>(url: string) =>
    requestClient.delete<T>(`${BASE}${url}`),
};
  • Step 3: 提交
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

// 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<any>(`/governance/meta-schemas/${schemaKey}`);
}

export function createMetaSchemaDraft(schemaKey: string, data: any) {
  return museAdminApi.post<any>(`/governance/meta-schemas/${schemaKey}/drafts`, data);
}

export function publishMetaSchemaDraft(schemaKey: string, draftVersion: number, data: any) {
  return museAdminApi.post<any>(
    `/governance/meta-schemas/${schemaKey}/drafts/${draftVersion}/publish`,
    data
  );
}
  • Step 2: 编写列表页
<!-- apps/web-antd/src/views/governance/MetaSchemaList.vue -->
<script setup lang="ts">
import { ref } from 'vue';
import { BasicTable, useTable, BasicColumn } from '@vben/common-ui';
import { listMetaSchemas, type MetaSchemaSummary } from '#/api/muse/governance/meta-schema';
import { useRouter } from 'vue-router';

const router = useRouter();

const [registerTable, { reload }] = useTable({
  api: async ({ page, size, scope }) => {
    const res = await listMetaSchemas({ pageNo: page, pageSize: size, scope });
    return { items: res.list, total: res.total };
  },
  columns: [
    { title: 'Schema Key', dataIndex: 'schemaKey', width: 200 },
    { title: '显示名称', dataIndex: 'displayName', width: 200 },
    { title: '字段类型', dataIndex: 'fieldType', width: 100 },
    { title: '作用域', dataIndex: 'scope', width: 100 },
    { title: '活跃版本', dataIndex: 'activeVersion', width: 100 },
    { title: '状态', dataIndex: 'status', width: 100 },
  ] as BasicColumn[],
});

function handleDetail(record: MetaSchemaSummary) {
  router.push(`/governance/meta-schemas/${record.schemaKey}`);
}
</script>

<template>
  <div class="p-4">
    <BasicTable @register="registerTable" @row-click="handleDetail">
      <template #toolbar>
        <a-button type="primary">新建 MetaSchema</a-button>
      </template>
    </BasicTable>
  </div>
</template>
  • Step 3: 编写测试
// 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: 提交
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:

// 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<UserEntitlement[]>(`/account/users/${userId}/entitlements`);
}

export function adjustQuota(userId: string, data: QuotaAdjustment) {
  return museAdminApi.post<void>(`/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:

// 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<string, unknown>;
  result?: Record<string, unknown>;
}

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<JobDetail>(`/jobs/${jobId}`);
}

export function retryJob(jobId: string) {
  return museAdminApi.post<void>(`/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:

// 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<string, unknown>;
  afterSnapshot?: Record<string, unknown>;
}

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<BusinessAuditDetail>(`/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 成功