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

@@ -34,13 +34,6 @@ import {
resolveRiskRuleSeverity,
resolveRiskRuleSeverityLabel
} from './auditViewRiskRuleModel.js'
import {
buildDigitalEmployeeContentRows,
buildDigitalEmployeeDetailMeta,
buildDigitalEmployeeListMeta,
isDigitalEmployeeAsset,
sanitizeDigitalEmployeeText
} from './auditViewDigitalEmployeeModel.js'
const EXPENSE_TYPE_SCENARIO_LABELS = {
travel: '差旅费',
@@ -342,9 +335,6 @@ export function resolveTabId(source, typeKey) {
if (typeKey === 'rules') {
return resolveRuleTabId(source)
}
if (typeKey === 'digitalWorkers') {
return isDigitalEmployeeAsset(source) ? 'digitalWorkers' : ''
}
return typeKey
}
@@ -899,15 +889,9 @@ export function resolveTypeKey(assetType) {
if (assetType === 'rule') {
return 'rules'
}
if (assetType === 'skill') {
return 'skills'
}
if (assetType === 'mcp') {
return 'mcp'
}
if (assetType === 'task') {
return 'digitalWorkers'
}
return ''
}
@@ -965,15 +949,9 @@ export function buildRowRuntime(asset, typeKey) {
if (typeKey === 'rules') {
return formatSeverity(asset.config_json?.severity)
}
if (typeKey === 'skills') {
return formatInputSummary(asset.config_json?.input_schema)
}
if (typeKey === 'mcp') {
return normalizeText(asset.config_json?.endpoint) || '未配置地址'
}
if (typeKey === 'digitalWorkers') {
return buildDigitalEmployeeListMeta(asset).executionMode
}
return ''
}
@@ -981,15 +959,9 @@ export function buildRowMetric(asset, typeKey) {
if (typeKey === 'rules') {
return normalizeText(asset.modified_by) || '未记录'
}
if (typeKey === 'skills') {
return '进入详情查看输出'
}
if (typeKey === 'mcp') {
return asset.config_json?.timeout_ms ? `${asset.config_json.timeout_ms} ms` : '未配置超时'
}
if (typeKey === 'digitalWorkers') {
return buildDigitalEmployeeListMeta(asset).executionMode
}
return ''
}
@@ -1061,19 +1033,16 @@ export function buildListItem(asset) {
? resolveRiskRuleScoreLabel(asset.config_json, asset.config_json) || resolveRiskRuleSeverityLabel(asset.config_json)
: resolveRiskRuleSeverityLabel(asset.config_json)
: ''
const digitalMeta = typeKey === 'digitalWorkers' ? buildDigitalEmployeeListMeta(asset) : null
const displayName = digitalMeta?.name || asset.name
const displayCode = digitalMeta?.code || asset.code
const displaySummary = digitalMeta?.summary || listSubtitle
const displayOwner = digitalMeta?.owner || (isRiskRule ? creator : asset.owner)
const displayReviewer = digitalMeta?.reviewer || reviewer
const displayCategory = digitalMeta?.category || resolveDomainLabel(asset.domain)
const displayScope =
digitalMeta?.scope ||
(typeKey === 'rules' ? ruleScenarioCategory || '閫氱敤' : formatScenarioList(asset.scenario_json))
const displayEnabledValue = digitalMeta ? digitalMeta.enabled : isEnabledValue
const displayEnabledLabel = digitalMeta?.enabledLabel || (isEnabledValue ? '鏄? : '?)
const displayEnabledTone = digitalMeta?.enabledTone || (isEnabledValue ? 'success' : 'disabled')
const displayName = asset.name
const displayCode = asset.code
const displaySummary = listSubtitle
const displayOwner = isRiskRule ? creator : asset.owner
const displayReviewer = reviewer
const displayCategory = resolveDomainLabel(asset.domain)
const displayScope = typeKey === 'rules' ? ruleScenarioCategory || '通用' : formatScenarioList(asset.scenario_json)
const displayEnabledValue = isEnabledValue
const displayEnabledLabel = isEnabledValue ? '是' : '否'
const displayEnabledTone = isEnabledValue ? 'success' : 'disabled'
return {
id: asset.id,
@@ -1093,7 +1062,6 @@ export function buildListItem(asset) {
category: displayCategory,
owner: displayOwner,
reviewer: displayReviewer,
scope: typeKey === 'rules' ? ruleScenarioCategory || '通用' : formatScenarioList(asset.scenario_json),
scope: displayScope,
riskCategory: ruleScenarioCategory,
scenarioList: ruleScenarioList,
@@ -1117,9 +1085,6 @@ export function buildListItem(asset) {
isOnlineValue,
isOnlineLabel: onlineMeta.label,
isOnlineTone: onlineMeta.tone,
isEnabledValue,
isEnabledLabel: isEnabledValue ? '是' : '否',
isEnabledTone: isEnabledValue ? 'success' : 'disabled',
isEnabledValue: displayEnabledValue,
isEnabledLabel: displayEnabledLabel,
isEnabledTone: displayEnabledTone,
@@ -1163,22 +1128,6 @@ export function buildRuleFields(detail) {
]
}
export function buildSkillFields(detail) {
const content = detail.current_version_content || {}
return [
{ label: '技能编码', value: detail.code },
{ label: '业务域', value: resolveDomainLabel(detail.domain) },
{
label: '输入参数',
value: Array.isArray(content.inputs) && content.inputs.length ? content.inputs.join('、') : '未配置'
},
{
label: '输出参数',
value: Array.isArray(content.outputs) && content.outputs.length ? content.outputs.join('、') : '未配置'
}
]
}
export function buildMcpFields(detail, latestCall) {
const content = detail.current_version_content || {}
return [
@@ -1196,9 +1145,6 @@ export function buildFields(detail, typeKey, latestCall) {
if (typeKey === 'rules') {
return buildRuleFields(detail)
}
if (typeKey === 'skills') {
return buildSkillFields(detail)
}
if (typeKey === 'mcp') {
return buildMcpFields(detail, latestCall)
}
@@ -1208,29 +1154,6 @@ export function buildFields(detail, typeKey, latestCall) {
export function buildPromptSections(detail, typeKey) {
const content = detail.current_version_content || {}
if (typeKey === 'skills') {
return [
{
title: '输入参数',
intent: '技能入口',
content: Array.isArray(content.inputs) && content.inputs.length ? content.inputs.join('\n') : '未配置输入参数。'
},
{
title: '输出参数',
intent: '技能产出',
content: Array.isArray(content.outputs) && content.outputs.length ? content.outputs.join('\n') : '未配置输出参数。'
},
{
title: '依赖能力',
intent: '外部依赖',
content:
Array.isArray(content.dependencies) && content.dependencies.length
? content.dependencies.join('\n')
: '当前技能未声明外部依赖。'
}
]
}
if (typeKey === 'mcp') {
return [
{
@@ -1274,14 +1197,6 @@ export function buildOutputRules(detail, typeKey) {
]
}
if (typeKey === 'skills') {
return [
`输入参数:${Array.isArray(content.inputs) && content.inputs.length ? content.inputs.join('、') : '未配置'}`,
`输出参数:${Array.isArray(content.outputs) && content.outputs.length ? content.outputs.join('、') : '未配置'}`,
`依赖能力:${Array.isArray(content.dependencies) && content.dependencies.length ? content.dependencies.join('、') : '未声明'}`
]
}
if (typeKey === 'mcp') {
return [
`服务地址:${normalizeText(detail.config_json?.endpoint) || '未配置'}`,
@@ -1312,24 +1227,6 @@ export function buildTests(detail, typeKey, latestCall) {
]
}
if (typeKey === 'skills') {
const content = detail.current_version_content || {}
return [
{
name: '输入数量',
input: detail.current_version || '暂无版本',
result: `${content.inputs?.length || 0}`,
tone: 'success'
},
{
name: '输出数量',
input: detail.current_version || '暂无版本',
result: `${content.outputs?.length || 0}`,
tone: 'success'
}
]
}
if (typeKey === 'mcp') {
return [
{
@@ -1356,15 +1253,6 @@ export function buildTests(detail, typeKey, latestCall) {
export function buildTools(detail, typeKey, latestCall) {
const content = detail.current_version_content || {}
if (typeKey === 'skills') {
return (content.dependencies || []).map((item) => ({
name: item,
scope: '技能依赖',
mode: '读取',
tone: 'safe'
}))
}
if (typeKey === 'mcp') {
return [
{
@@ -1454,40 +1342,32 @@ export function buildDetailViewModel(detail, runs) {
const initialRiskRuleScore = resolveRiskRuleScore(configJson, configJson)
const initialRiskRuleScoreLevel = resolveRiskRuleScoreLevel(configJson, configJson)
const initialRiskRuleSeverity = initialRiskRuleScoreLevel || resolveRiskRuleSeverity(configJson)
const digitalMeta = typeKey === 'digitalWorkers'
? buildDigitalEmployeeDetailMeta({
...detail,
updated_at: formatDateTime(detail.updated_at)
})
: null
const detailName = digitalMeta?.name || detail.name
const detailCode = digitalMeta?.code || detail.code
const detailSummary = digitalMeta?.description ||
(usesJsonRiskRule ? buildRiskListSubtitle(detail.description) : detail.description)
const detailOwner = digitalMeta?.owner || detail.owner
const detailReviewer = digitalMeta?.reviewer || detail.reviewer || detail.latest_review?.reviewer || '寰呭垎閰?
const detailCategory = digitalMeta?.category || resolveDomainLabel(detail.domain)
const detailScope =
digitalMeta?.scope ||
(typeKey === 'rules' ? ruleScenarioCategory || '閫氱敤' : formatScenarioList(detail.scenario_json))
const detailEnabledValue = digitalMeta ? digitalMeta.enabled : isEnabledValue
const detailEnabledLabel = digitalMeta?.enabledLabel || (isEnabledValue ? '? : '鍚?)
const detailEnabledTone = digitalMeta?.enabledTone || (isEnabledValue ? 'success' : 'disabled')
const detailName = detail.name
const detailCode = detail.code
const detailSummary = usesJsonRiskRule ? buildRiskListSubtitle(detail.description) : detail.description
const detailOwner = detail.owner
const detailReviewer = detail.reviewer || detail.latest_review?.reviewer || '待分配'
const detailCategory = resolveDomainLabel(detail.domain)
const detailScope = typeKey === 'rules' ? ruleScenarioCategory || '通用' : formatScenarioList(detail.scenario_json)
const detailEnabledValue = isEnabledValue
const detailEnabledLabel = isEnabledValue ? '是' : '否'
const detailEnabledTone = isEnabledValue ? 'success' : 'disabled'
return {
id: detail.id,
tabId,
type: typeKey,
typeLabel: tabMeta.typeLabel,
short: makeShort(detail.name),
name: detail.name,
code: detail.code,
summary: usesJsonRiskRule ? buildRiskListSubtitle(detail.description) : detail.description,
listSubtitle: usesJsonRiskRule ? buildRiskListSubtitle(detail.description) : normalizeText(detail.description),
owner: detail.owner,
reviewer: detail.reviewer || detail.latest_review?.reviewer || '待分配',
category: resolveDomainLabel(detail.domain),
scope: typeKey === 'rules' ? ruleScenarioCategory || '通用' : formatScenarioList(detail.scenario_json),
short: makeShort(detailName),
name: detailName,
code: detailCode,
rawCode: detail.code,
summary: detailSummary,
listSubtitle: normalizeText(detailSummary),
owner: detailOwner,
reviewer: detailReviewer,
category: detailCategory,
scope: detailScope,
businessStageValue: businessStage.value,
businessStageLabel: businessStage.label,
version: detail.working_version || detail.current_version || '-',
@@ -1524,9 +1404,9 @@ export function buildDetailViewModel(detail, runs) {
isOnlineValue: onlineMeta.online,
isOnlineLabel: onlineMeta.label,
isOnlineTone: onlineMeta.tone,
isEnabledValue,
isEnabledLabel: isEnabledValue ? '' : '',
isEnabledTone: isEnabledValue ? 'success' : 'disabled',
isEnabledValue: detailEnabledValue,
isEnabledLabel: detailEnabledLabel,
isEnabledTone: detailEnabledTone,
publisher:
detail.status === 'active'
? normalizeText(detail.published_by) ||