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 } }