Files
X-Financial/web/src/views/scripts/auditViewListItemModel.js

206 lines
6.6 KiB
JavaScript
Raw Normal View History

import {
resolveRiskRuleScoreLabel,
resolveRiskRuleScoreLevel,
resolveRiskRuleSeverity,
resolveRiskRuleSeverityLabel
} from './auditViewRiskRuleModel.js'
import { normalizeText } from './auditViewDataUtils.js'
import {
formatDateTime,
formatScenarioList,
formatSeverity,
makeShort,
resolveDomainLabel,
resolveStatusMeta,
resolveTypeKey
} from './auditViewFormatters.js'
import {
buildRiskListSubtitle,
isJsonRiskRuleSource,
isSpreadsheetRuleSource,
readRuleDocumentMeta,
resolveRuleScenarioCategory,
resolveRuleScenarioList,
resolveTabId,
resolveTabMeta
} from './auditViewRuleClassifier.js'
import {
resolveRiskRuleBusinessStage,
resolveRiskRuleEnabled,
resolveRiskRuleOnlineMeta
} from './auditViewRiskRuleState.js'
export function findLatestMcpCall(runs, assetCode) {
const expectedToolName = normalizeText(assetCode).replace(/^mcp\./, '')
for (const run of runs) {
for (const toolCall of run.tool_calls || []) {
const toolName = normalizeText(toolCall.tool_name)
if (
toolName === expectedToolName ||
toolName.endsWith(expectedToolName) ||
expectedToolName.endsWith(toolName)
) {
return {
run,
toolCall
}
}
}
}
return null
}
export function buildRowRuntime(asset, typeKey) {
if (typeKey === 'rules') {
return formatSeverity(asset.config_json?.severity)
}
if (typeKey === 'mcp') {
return normalizeText(asset.config_json?.endpoint) || '未配置地址'
}
return ''
}
export function buildRowMetric(asset, typeKey) {
if (typeKey === 'rules') {
return normalizeText(asset.modified_by) || '未记录'
}
if (typeKey === 'mcp') {
return asset.config_json?.timeout_ms ? `${asset.config_json.timeout_ms} ms` : '未配置超时'
}
return ''
}
export function buildListItem(asset) {
const typeKey = resolveTypeKey(asset.asset_type)
const tabId = resolveTabId(asset, typeKey)
if (!tabId) {
return null
}
const tabMeta = resolveTabMeta(tabId, typeKey)
const statusMeta = resolveStatusMeta(asset.status)
const workingVersion = asset.working_version || asset.current_version || '-'
const changeCount =
typeof asset.change_count === 'number'
? asset.change_count
: Array.isArray(asset.recent_versions)
? Math.max(asset.recent_versions.length - 1, 0)
: 0
const modifiedBy =
normalizeText(asset.modified_by) ||
normalizeText(
Array.isArray(asset.recent_versions)
? asset.recent_versions.find((item) => item.version === workingVersion)?.created_by
: ''
)
const isRiskRule = tabId === 'riskRules'
const usesSpreadsheetRule = typeKey === 'rules' && isSpreadsheetRuleSource(asset)
const usesJsonRiskRule = typeKey === 'rules' && isJsonRiskRuleSource(asset)
const ruleDocument = readRuleDocumentMeta(asset)
const ruleScenarioCategory = typeKey === 'rules' ? resolveRuleScenarioCategory(asset, tabId) : ''
const listSubtitle = isRiskRule
? buildRiskListSubtitle(asset.description)
: normalizeText(asset.description)
const onlineMeta = resolveRiskRuleOnlineMeta(asset.status)
const isOnlineValue = onlineMeta.online
const isEnabledValue = usesJsonRiskRule ? resolveRiskRuleEnabled(asset) : true
const reviewer = normalizeText(asset.reviewer) || '待分配'
const creator =
normalizeText(asset.owner) ||
normalizeText(asset.config_json?.generation_request?.actor) ||
modifiedBy ||
'未知'
const publisher = isRiskRule ? creator : ''
const riskRuleCreatedAt = formatDateTime(asset.created_at || asset.updated_at)
const businessStage = usesJsonRiskRule
? resolveRiskRuleBusinessStage(asset)
: { value: '', label: '' }
const ruleScenarioList = typeKey === 'rules' ? resolveRuleScenarioList(asset, tabId) : []
const riskScoreLevel = usesJsonRiskRule
? resolveRiskRuleScoreLevel(asset.config_json, asset.config_json)
: ''
const riskLevelValue = usesJsonRiskRule
? riskScoreLevel || resolveRiskRuleSeverity(asset.config_json)
: ''
const riskLevelLabel = usesJsonRiskRule
? riskScoreLevel
? resolveRiskRuleScoreLabel(asset.config_json, asset.config_json) || resolveRiskRuleSeverityLabel(asset.config_json)
: resolveRiskRuleSeverityLabel(asset.config_json)
: ''
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'
const searchText = [
displayName,
displayCode,
displaySummary,
displayOwner,
displayScope,
riskLevelLabel
]
.map((value) => normalizeText(value).toLowerCase())
.filter(Boolean)
.join(' ')
return {
id: asset.id,
tabId,
type: typeKey,
isPreviewMock: Boolean(asset.isPreviewMock),
usesSpreadsheetRule,
usesJsonRiskRule,
ruleDocument,
typeLabel: tabMeta.typeLabel,
short: makeShort(displayName),
name: displayName,
code: displayCode,
rawCode: asset.code,
summary: displaySummary,
listSubtitle: displaySummary,
category: displayCategory,
owner: displayOwner,
reviewer: displayReviewer,
scope: displayScope,
riskCategory: ruleScenarioCategory,
scenarioList: ruleScenarioList,
businessStageValue: businessStage.value,
businessStageLabel: businessStage.label,
riskLevelValue,
riskLevelLabel,
riskLevelTone: riskLevelValue,
model: buildRowRuntime(asset, typeKey),
version: workingVersion,
versionDisplay: typeKey === 'rules' ? `${changeCount}` : workingVersion,
publishedVersion: asset.published_version || '-',
workingVersion,
status: statusMeta.label,
statusValue: asset.status,
statusTone: statusMeta.tone,
hitRate: isRiskRule ? publisher : buildRowMetric({ ...asset, modified_by: modifiedBy }, typeKey),
creator,
publisher,
publishedAt: isOnlineValue ? formatDateTime(asset.published_at || asset.updated_at) : '-',
isOnlineValue,
isOnlineLabel: onlineMeta.label,
isOnlineTone: onlineMeta.tone,
isEnabledValue: displayEnabledValue,
isEnabledLabel: displayEnabledLabel,
isEnabledTone: displayEnabledTone,
modifiedBy,
changeCount,
updatedAt: isRiskRule ? riskRuleCreatedAt : formatDateTime(asset.updated_at),
badgeTone: tabMeta.badgeTone,
domainValue: asset.domain,
searchText
}
}