feat: 增强规则资产管理与审计页面运行时调试
后端新增规则资产版本管理和规则文件 CRUD 接口,优化风险 规则生成模板执行和员工数据模型字段,知识库 RAG 增强本 地回退和文档提取能力,清理旧风险规则文件统一由生成引擎 管理,前端审计页面增加运行时调试面板和规则资产编辑交互, 补充单元测试覆盖。
This commit is contained in:
@@ -34,6 +34,7 @@ import {
|
||||
export {
|
||||
DETAIL_TITLES,
|
||||
DOMAIN_LABELS,
|
||||
ENABLED_STATE_OPTIONS,
|
||||
EXPENSE_RULE_BLOCK_PATTERN,
|
||||
JSON_RISK_DETAIL_MODE,
|
||||
LEGACY_RISK_SCENARIO_KEYS,
|
||||
@@ -43,6 +44,7 @@ export {
|
||||
REVIEW_META,
|
||||
RISK_SCENARIO_OPTIONS,
|
||||
RISK_SCENARIO_VALUES,
|
||||
RISK_RULE_TABLE_COLUMNS,
|
||||
RULE_SPREADSHEET_BLOCK_PATTERN,
|
||||
RULE_TABLE_COLUMNS,
|
||||
RULE_TAB_TAG_ALIASES,
|
||||
@@ -51,6 +53,7 @@ export {
|
||||
SPREADSHEET_DETAIL_MODE,
|
||||
STATUS_META,
|
||||
STATUS_OPTIONS,
|
||||
ONLINE_STATE_OPTIONS,
|
||||
TAB_META,
|
||||
TYPE_META,
|
||||
VERSION_STATE_META
|
||||
@@ -189,6 +192,17 @@ export function readConfigJson(value) {
|
||||
return {}
|
||||
}
|
||||
|
||||
export function resolveRiskRuleEnabled(source, rulePayload = null) {
|
||||
const configJson = readConfigJson(source)
|
||||
if (isPlainObject(rulePayload) && rulePayload.enabled === false) {
|
||||
return false
|
||||
}
|
||||
if (source?.enabled === false || configJson.enabled === false) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
export function readRuleDocumentMeta(value) {
|
||||
const configJson = readConfigJson(value)
|
||||
return isPlainObject(configJson.rule_document) ? configJson.rule_document : null
|
||||
@@ -417,6 +431,12 @@ export function buildRiskListSubtitle(text, maxLength = 42) {
|
||||
|
||||
export function applyRiskRuleJsonState(target, payload, apiPayload) {
|
||||
const rulePayload = isPlainObject(payload) ? payload : {}
|
||||
const metadata = rulePayload.metadata && typeof rulePayload.metadata === 'object'
|
||||
? rulePayload.metadata
|
||||
: {}
|
||||
const apiConfig = apiPayload?.config_json && typeof apiPayload.config_json === 'object'
|
||||
? apiPayload.config_json
|
||||
: {}
|
||||
const fullDescription =
|
||||
resolveRiskRuleDescription(rulePayload) ||
|
||||
normalizeText(apiPayload?.description) ||
|
||||
@@ -427,6 +447,21 @@ export function applyRiskRuleJsonState(target, payload, apiPayload) {
|
||||
const riskRuleFields = resolveRiskRuleFields(rulePayload)
|
||||
const riskRuleCreatedAt = resolveRiskRuleCreatedAt(rulePayload, target.createdAt || target.updatedAt)
|
||||
|
||||
const statusValue = apiPayload?.status || target.statusValue || 'draft'
|
||||
const isOnlineLabel = statusValue === 'active' ? '是' : '否'
|
||||
const isEnabledValue = resolveRiskRuleEnabled(target, rulePayload)
|
||||
|
||||
const publisher = apiPayload?.created_by || target.publisher || (apiPayload?.recent_versions && apiPayload.recent_versions[0]?.created_by) || '系统管理员'
|
||||
|
||||
let publishedAt = target.publishedAt || '-'
|
||||
if (apiPayload?.recent_versions) {
|
||||
const history = buildHistory(apiPayload.recent_versions, { ...target, config_json: payload })
|
||||
const publishedVersionObj = history.find((item) => item.isPublished || item.lifecycleState === 'published')
|
||||
publishedAt = publishedVersionObj ? publishedVersionObj.time : (apiPayload?.latest_review?.reviewed_at ? formatDateTime(apiPayload.latest_review.reviewed_at) : '-')
|
||||
} else if (apiPayload?.latest_review?.reviewed_at) {
|
||||
publishedAt = formatDateTime(apiPayload.latest_review.reviewed_at)
|
||||
}
|
||||
|
||||
return {
|
||||
...target,
|
||||
riskRuleDescription: fullDescription,
|
||||
@@ -444,6 +479,12 @@ export function applyRiskRuleJsonState(target, payload, apiPayload) {
|
||||
riskRuleFlow: resolveRiskRuleFlow(rulePayload, riskRuleFields),
|
||||
riskRuleFlowDiagramSvg:
|
||||
normalizeText(apiPayload?.flow_diagram_svg) || resolveRiskRuleFlowDiagramSvg(rulePayload),
|
||||
riskRuleRequiresAttachment: Boolean(
|
||||
rulePayload.requires_attachment ||
|
||||
metadata.requires_attachment ||
|
||||
apiConfig.requires_attachment ||
|
||||
target.configJson?.requires_attachment
|
||||
),
|
||||
riskRuleSummary: {
|
||||
name: apiPayload?.name || target.name,
|
||||
evaluator: apiPayload?.evaluator || rulePayload.evaluator || '',
|
||||
@@ -451,7 +492,13 @@ export function applyRiskRuleJsonState(target, payload, apiPayload) {
|
||||
inputs: apiPayload?.inputs || rulePayload.inputs || {},
|
||||
outcomes: apiPayload?.outcomes || rulePayload.outcomes || {}
|
||||
},
|
||||
riskRuleJsonText: JSON.stringify(rulePayload, null, 2)
|
||||
riskRuleJsonText: JSON.stringify(rulePayload, null, 2),
|
||||
isOnlineLabel,
|
||||
isEnabledValue,
|
||||
isEnabledLabel: isEnabledValue ? '是' : '否',
|
||||
isEnabledTone: isEnabledValue ? 'success' : 'disabled',
|
||||
publisher,
|
||||
publishedAt
|
||||
}
|
||||
}
|
||||
|
||||
@@ -810,6 +857,15 @@ export function buildListItem(asset) {
|
||||
const listSubtitle = isRiskRule
|
||||
? buildRiskListSubtitle(asset.description)
|
||||
: normalizeText(asset.description)
|
||||
const isOnlineValue = asset.status === 'active'
|
||||
const isEnabledValue = usesJsonRiskRule ? resolveRiskRuleEnabled(asset) : true
|
||||
const reviewer = normalizeText(asset.reviewer) || '待分配'
|
||||
const publisher = isRiskRule
|
||||
? isOnlineValue
|
||||
? normalizeText(asset.published_by) || reviewer || modifiedBy || '系统管理员'
|
||||
: '-'
|
||||
: ''
|
||||
const publishedAt = isRiskRule && isOnlineValue ? formatDateTime(asset.published_at || asset.updated_at) : '-'
|
||||
|
||||
return {
|
||||
id: asset.id,
|
||||
@@ -826,8 +882,8 @@ export function buildListItem(asset) {
|
||||
summary: listSubtitle,
|
||||
listSubtitle,
|
||||
category: resolveDomainLabel(asset.domain),
|
||||
owner: asset.owner,
|
||||
reviewer: asset.reviewer || '待分配',
|
||||
owner: isRiskRule ? reviewer : asset.owner,
|
||||
reviewer,
|
||||
scope: typeKey === 'rules' ? ruleScenarioCategory || '通用' : formatScenarioList(asset.scenario_json),
|
||||
riskCategory: ruleScenarioCategory,
|
||||
model: buildRowRuntime(asset, typeKey),
|
||||
@@ -838,10 +894,18 @@ export function buildListItem(asset) {
|
||||
status: statusMeta.label,
|
||||
statusValue: asset.status,
|
||||
statusTone: statusMeta.tone,
|
||||
hitRate: buildRowMetric({ ...asset, modified_by: modifiedBy }, typeKey),
|
||||
hitRate: isRiskRule ? publisher : buildRowMetric({ ...asset, modified_by: modifiedBy }, typeKey),
|
||||
publisher,
|
||||
publishedAt,
|
||||
isOnlineValue,
|
||||
isOnlineLabel: isOnlineValue ? '是' : '否',
|
||||
isOnlineTone: isOnlineValue ? 'success' : 'disabled',
|
||||
isEnabledValue,
|
||||
isEnabledLabel: isEnabledValue ? '是' : '否',
|
||||
isEnabledTone: isEnabledValue ? 'success' : 'disabled',
|
||||
modifiedBy,
|
||||
changeCount,
|
||||
updatedAt: formatDateTime(asset.updated_at),
|
||||
updatedAt: isRiskRule ? publishedAt : formatDateTime(asset.updated_at),
|
||||
badgeTone: tabMeta.badgeTone,
|
||||
domainValue: asset.domain
|
||||
}
|
||||
@@ -1218,6 +1282,7 @@ export function buildDetailViewModel(detail, runs) {
|
||||
const ruleTemplateLabel = normalizeText(configJson.rule_template_label) || resolveRuleTemplateLabel(ruleTemplateKey)
|
||||
const runtimeKind = normalizeText(configJson.runtime_kind || previewRuntimeRule.kind) || 'policy_rule_draft'
|
||||
const ruleScenarioCategory = typeKey === 'rules' ? resolveRuleScenarioCategory(detail, tabId) : ''
|
||||
const isEnabledValue = usesJsonRiskRule ? resolveRiskRuleEnabled(detail) : true
|
||||
|
||||
return {
|
||||
id: detail.id,
|
||||
@@ -1258,10 +1323,28 @@ export function buildDetailViewModel(detail, runs) {
|
||||
riskRuleSeverityLabel: '中风险',
|
||||
riskRuleCreatedAt: formatDateTime(detail.created_at),
|
||||
riskRuleAgeLabel: formatRiskRuleAge(detail.created_at),
|
||||
isOnlineLabel: detail.status === 'active' ? '是' : '否',
|
||||
isEnabledValue,
|
||||
isEnabledLabel: isEnabledValue ? '是' : '否',
|
||||
isEnabledTone: isEnabledValue ? 'success' : 'disabled',
|
||||
publisher:
|
||||
detail.status === 'active'
|
||||
? normalizeText(detail.published_by) ||
|
||||
detail.latest_review?.reviewer ||
|
||||
detail.reviewer ||
|
||||
(detail.recent_versions && detail.recent_versions[0]?.created_by) ||
|
||||
'系统管理员'
|
||||
: '-',
|
||||
publishedAt:
|
||||
history.find((item) => item.isPublished || item.lifecycleState === 'published')?.time ||
|
||||
(detail.published_at ? formatDateTime(detail.published_at) : '') ||
|
||||
(detail.latest_review?.reviewed_at ? formatDateTime(detail.latest_review.reviewed_at) : '-'),
|
||||
riskRuleFields: [],
|
||||
riskRuleFieldSummary: '未识别字段',
|
||||
riskRuleFlow: resolveRiskRuleFlow({}, []),
|
||||
riskRuleFlowDiagramSvg: normalizeText(configJson.flow_diagram_svg),
|
||||
riskRuleRequiresAttachment: Boolean(configJson.requires_attachment),
|
||||
latestTestSummary: detail.latest_test_summary || detail.latestTestSummary || null,
|
||||
riskCategory: typeKey === 'rules' ? ruleScenarioCategory : '',
|
||||
ruleDocument,
|
||||
scenarioList: typeKey === 'rules' && ruleScenarioCategory
|
||||
|
||||
Reference in New Issue
Block a user