12 KiB
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 配置、市场治理、全局知识管理 5 个功能域。
架构: 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/ 结构。
Step 1: 工程调整
Task 1.1: 业务目录结构建立
仓库路径: muse-admin/
- Step 1: 创建业务模块目录
mkdir -p muse-admin/apps/web-antd/src/views/{governance,ai,knowledge,market,account,jobs,audit}
mkdir -p muse-admin/apps/web-antd/src/api/muse/{governance,ai,knowledge,market,account,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/governance/ muse-admin/apps/web-antd/src/api/muse/
git commit -m "feat(struct): 建立管理端业务模块目录(governance/ai/knowledge/market/account)"
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 |
只读汇总表格 |
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 绑定状态
代码示例 — 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 快照对比 |
API endpoints:
GET /admin-api/muse/audit/business-events # 业务审计事件列表
代码示例 — 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 成功