feat: 新增数字员工管理页面与工作台首页重构

后端优化 agent 资产种子初始化和常量配置,前端新增数字员工
视图和调度对话框组件,重构个人工作台首页布局和洞察面板,
完善审计页面数字员工详情和运行时模型,优化侧边栏导航和图
标配置,新增工作台摘要和工作台数据模块,补充单元测试。
This commit is contained in:
caoxiaozhu
2026-05-28 09:30:34 +08:00
parent d4d5d40569
commit 04cd6d0f81
38 changed files with 3413 additions and 1301 deletions

View File

@@ -1,4 +1,5 @@
const DIGITAL_EMPLOYEE_AGENT = 'hermes'
export const DIGITAL_EMPLOYEE_SKILL_CATEGORY_OPTIONS = ['积累', '升级', '整理', '评估']
const TASK_TYPE_LABELS = {
daily_risk_scan: '每日风险巡检',
@@ -7,11 +8,25 @@ const TASK_TYPE_LABELS = {
weekly_expense_report: '周度费用洞察',
rule_review_digest: '规则待审摘要',
knowledge_index_sync: '知识库归集',
llm_wiki_rule_formation: '知识库归集',
x_financial_callback: '任务回调上报'
}
const TASK_TYPE_SKILL_CATEGORIES = {
daily_risk_scan: '评估',
global_risk_scan: '评估',
weekly_ar_summary: '整理',
weekly_expense_report: '整理',
rule_review_digest: '升级',
knowledge_index_sync: '积累',
llm_wiki_rule_formation: '积累',
x_financial_callback: '升级'
}
const CONTENT_LABELS = {
task_type: '技能类型',
task_type: '任务类型',
skill_category: '技能类型',
skill_category_options: '技能类型范围',
schedule: '执行计划',
cron: '调度表达式',
folder: '归集范围',
@@ -45,6 +60,14 @@ export function sanitizeDigitalEmployeeText(value, fallback = '') {
return text || fallback
}
export function sanitizeDigitalEmployeeSource(value, fallback = '') {
const text = normalizeDigitalEmployeeText(value)
.replace(/hermes/gi, '数字员工')
.replace(/赫尔墨斯/g, '数字员工')
.trim()
return text || fallback
}
export function sanitizeDigitalEmployeeName(value, fallback = '数字员工技能') {
const text = sanitizeDigitalEmployeeText(value, fallback)
.replace(/^数字员工[\s·:-]*/i, '')
@@ -80,6 +103,22 @@ export function resolveDigitalEmployeeTaskType(source = {}, content = {}) {
return raw.replace(/[-.]/g, '_')
}
export function resolveDigitalEmployeeSkillCategory(source = {}, content = {}) {
const config = source.config_json || source.configJson || {}
const taskType = resolveDigitalEmployeeTaskType(source, content)
const explicitCategory =
normalizeDigitalEmployeeText(config.skill_category) ||
normalizeDigitalEmployeeText(config.skillCategory) ||
normalizeDigitalEmployeeText(content.skill_category) ||
normalizeDigitalEmployeeText(content.skillCategory)
if (DIGITAL_EMPLOYEE_SKILL_CATEGORY_OPTIONS.includes(explicitCategory)) {
return explicitCategory
}
return TASK_TYPE_SKILL_CATEGORIES[taskType] || '整理'
}
export function isDigitalEmployeeAsset(source = {}) {
const config = source.config_json || source.configJson || {}
const haystack = [
@@ -145,10 +184,10 @@ export function formatDigitalEmployeeCron(value) {
export function resolveDigitalEmployeeSchedule(source = {}, content = {}) {
const config = source.config_json || source.configJson || {}
const raw =
normalizeDigitalEmployeeText(content.schedule) ||
normalizeDigitalEmployeeText(config.cron) ||
normalizeDigitalEmployeeText(config.schedule) ||
normalizeDigitalEmployeeText(config.cron_expression)
normalizeDigitalEmployeeText(config.cron_expression) ||
normalizeDigitalEmployeeText(content.schedule)
return {
value: raw,
label: formatDigitalEmployeeCron(raw)
@@ -205,9 +244,85 @@ export function buildDigitalEmployeeContentPreview(content = {}) {
return sanitizeDigitalEmployeeText(JSON.stringify(visiblePayload, null, 2))
}
function resolveDigitalEmployeeMarkdownFromContent(content = {}, config = {}) {
const candidates = [
content.skill_markdown,
content.skills_markdown,
content.source_markdown,
content.markdown,
content.skill_source,
config.skill_markdown,
config.skills_markdown,
config.source_markdown,
config.skill_source
]
return candidates.find((item) => normalizeDigitalEmployeeText(item)) || ''
}
function buildDefaultDigitalEmployeeSource(source = {}, listMeta = {}, schedule = {}) {
const name = listMeta.name || '数字员工技能'
const description =
listMeta.summary ||
sanitizeDigitalEmployeeText(source.description, '该技能用于后台自动执行指定任务。')
return [
'---',
`name: ${listMeta.code || 'digital.skill'}`,
`description: ${description}`,
'---',
'',
`# ${name}`,
'',
'## 功能说明',
'',
description,
'',
'## 执行方式',
'',
`- 技能类型:${listMeta.skillCategory || '整理'}`,
`- 可选类型:${DIGITAL_EMPLOYEE_SKILL_CATEGORY_OPTIONS.join('、')}`,
`- 执行计划:${schedule.label || '手动触发'}`,
`- 触发方式:${listMeta.executionMode || '手动触发'}`,
'',
'## 操作要求',
'',
'- 按任务参数读取业务数据。',
'- 运行完成后写回业务结果或运行日志。'
].join('\n')
}
export function buildDigitalEmployeeSourceMarkdown(source = {}, content = {}, listMeta = {}) {
const config = source.config_json || source.configJson || {}
if (
normalizeDigitalEmployeeText(source.current_version_content_type) === 'markdown' &&
typeof source.current_version_content === 'string'
) {
return sanitizeDigitalEmployeeSource(source.current_version_content)
}
const schedule = resolveDigitalEmployeeSchedule(source, content)
const sourceMarkdown = resolveDigitalEmployeeMarkdownFromContent(content, config)
return sanitizeDigitalEmployeeSource(
sourceMarkdown,
buildDefaultDigitalEmployeeSource(source, listMeta, schedule)
)
}
function buildDigitalEmployeeBasicRows(source = {}, listMeta = {}, schedule = {}) {
return [
{ label: '技能编号', value: listMeta.code },
{ label: '技能类型', value: listMeta.skillCategory },
{ label: '维护人', value: listMeta.owner },
{ label: '执行计划', value: schedule.label },
{ label: '当前版本', value: source.working_version || source.current_version || '-' },
{ label: '最近更新', value: source.updated_at || '-' }
]
}
export function buildDigitalEmployeeListMeta(source = {}) {
const content = parseDigitalEmployeeContent(source.current_version_content)
const taskType = resolveDigitalEmployeeTaskType(source, content)
const skillCategory = resolveDigitalEmployeeSkillCategory(source, content)
const schedule = resolveDigitalEmployeeSchedule(source, content)
const enabled = resolveDigitalEmployeeEnabled(source)
const fallbackName = TASK_TYPE_LABELS[taskType] || '数字员工技能'
@@ -217,6 +332,8 @@ export function buildDigitalEmployeeListMeta(source = {}) {
code: resolveDigitalEmployeeDisplayCode(source, content),
summary: sanitizeDigitalEmployeeText(source.description, '面向后台自动执行的数字员工技能。'),
category: '数字员工',
skillCategory,
skillCategoryOptions: DIGITAL_EMPLOYEE_SKILL_CATEGORY_OPTIONS,
owner: sanitizeDigitalEmployeeText(source.owner, '平台运营'),
reviewer: sanitizeDigitalEmployeeText(source.reviewer, '系统'),
scope: schedule.label,
@@ -237,6 +354,7 @@ export function buildDigitalEmployeeDetailMeta(source = {}) {
})
const schedule = resolveDigitalEmployeeSchedule(source, content)
const contentRows = buildDigitalEmployeeContentRows(content)
const sourceMarkdown = buildDigitalEmployeeSourceMarkdown(source, content, listMeta)
return {
...listMeta,
@@ -245,13 +363,16 @@ export function buildDigitalEmployeeDetailMeta(source = {}) {
source.description,
'该技能由后台数字员工按计划执行,并把结果沉淀到对应业务资产或运行日志中。'
),
sourceMarkdown,
basicRows: buildDigitalEmployeeBasicRows(source, listMeta, schedule),
contentRows,
contentPreview: buildDigitalEmployeeContentPreview(content),
scheduleRows: [
{ label: '执行计划', value: schedule.label },
{ label: '调度表达式', value: schedule.value || '手动触发' },
{ label: '启动状态', value: listMeta.enabledLabel, tone: listMeta.enabledTone },
{ label: '执行方式', value: listMeta.executionMode }
{ label: '执行方式', value: listMeta.executionMode },
{ label: '技能类型', value: listMeta.skillCategory }
],
overviewRows: [
{ label: '能力编号', value: listMeta.code },