2026-05-29 09:44:03 +08:00
|
|
|
import { computed, ref } from 'vue'
|
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
fetchAgentAssetDetail,
|
|
|
|
|
fetchAgentAssets,
|
|
|
|
|
fetchAgentRuns
|
|
|
|
|
} from '../../services/agentAssets.js'
|
|
|
|
|
import {
|
|
|
|
|
buildDetailViewModel,
|
|
|
|
|
buildListItem
|
|
|
|
|
} from './auditViewModel.js'
|
|
|
|
|
|
|
|
|
|
export function useAuditAssetData({
|
|
|
|
|
activeType,
|
|
|
|
|
activeMeta,
|
|
|
|
|
selectedSkill,
|
|
|
|
|
loadVersionTimeline,
|
|
|
|
|
loadSpreadsheetChangeRecords,
|
|
|
|
|
loadRiskRuleJson,
|
|
|
|
|
toast
|
|
|
|
|
}) {
|
|
|
|
|
const loading = ref(false)
|
|
|
|
|
const errorMessage = ref('')
|
|
|
|
|
const detailLoading = ref(false)
|
|
|
|
|
const detailError = ref('')
|
|
|
|
|
const runLoading = ref(false)
|
|
|
|
|
const runs = ref([])
|
|
|
|
|
const assetBuckets = ref({
|
|
|
|
|
financialRules: [],
|
|
|
|
|
riskRules: [],
|
|
|
|
|
mcp: []
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const currentAssets = computed(() => assetBuckets.value[activeType.value] || [])
|
|
|
|
|
|
|
|
|
|
async function loadRuns(options = {}) {
|
|
|
|
|
if (runLoading.value && !options.force) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
runLoading.value = true
|
|
|
|
|
try {
|
|
|
|
|
const payload = await fetchAgentRuns({ limit: 50 })
|
|
|
|
|
runs.value = Array.isArray(payload) ? payload : []
|
|
|
|
|
} finally {
|
|
|
|
|
runLoading.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function loadAssets(options = {}) {
|
|
|
|
|
const shouldShowLoading = !options.silent && !options.background
|
|
|
|
|
if (shouldShowLoading) {
|
|
|
|
|
loading.value = true
|
|
|
|
|
}
|
|
|
|
|
if (!options.silent) {
|
|
|
|
|
errorMessage.value = ''
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const payload = await fetchAgentAssets({ assetType: activeMeta.value.assetType })
|
|
|
|
|
const items = Array.isArray(payload) ? payload.map(buildListItem).filter(Boolean) : []
|
|
|
|
|
|
|
|
|
|
if (activeMeta.value.assetType === 'rule') {
|
|
|
|
|
const nextBuckets = {
|
|
|
|
|
financialRules: [],
|
|
|
|
|
riskRules: []
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
items.forEach((item) => {
|
|
|
|
|
if (item?.tabId === 'financialRules' || item?.tabId === 'riskRules') {
|
|
|
|
|
nextBuckets[item.tabId].push(item)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
assetBuckets.value = {
|
|
|
|
|
...assetBuckets.value,
|
|
|
|
|
...nextBuckets
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
assetBuckets.value = {
|
|
|
|
|
...assetBuckets.value,
|
|
|
|
|
[activeType.value]: items
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
if (options.silent || options.background) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if (activeMeta.value.assetType === 'rule') {
|
|
|
|
|
assetBuckets.value = {
|
|
|
|
|
...assetBuckets.value,
|
|
|
|
|
financialRules:
|
|
|
|
|
activeType.value === 'financialRules' ? [] : assetBuckets.value.financialRules,
|
|
|
|
|
riskRules: []
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
assetBuckets.value = {
|
|
|
|
|
...assetBuckets.value,
|
|
|
|
|
[activeType.value]: []
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
errorMessage.value = error?.message || '资产数据加载失败,请稍后重试。'
|
|
|
|
|
toast(errorMessage.value)
|
|
|
|
|
} finally {
|
|
|
|
|
if (shouldShowLoading) {
|
|
|
|
|
loading.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function refreshCurrentAssets() {
|
|
|
|
|
await loadAssets({ force: true, silent: true, background: true })
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-01 17:07:14 +08:00
|
|
|
async function loadSelectedAssetDetail(assetId, options = {}) {
|
|
|
|
|
const silent = Boolean(options.silent)
|
|
|
|
|
if (!silent) {
|
|
|
|
|
detailLoading.value = true
|
|
|
|
|
detailError.value = ''
|
|
|
|
|
}
|
2026-05-29 09:44:03 +08:00
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
if (!runs.value.length) {
|
|
|
|
|
await loadRuns()
|
|
|
|
|
}
|
|
|
|
|
const detail = await fetchAgentAssetDetail(assetId)
|
|
|
|
|
selectedSkill.value = buildDetailViewModel(detail, runs.value)
|
|
|
|
|
if (selectedSkill.value?.type !== 'rules') {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!selectedSkill.value.usesSpreadsheetRule && !selectedSkill.value.usesJsonRiskRule) {
|
|
|
|
|
loadVersionTimeline(assetId, { silent: true }).catch(() => {})
|
|
|
|
|
}
|
|
|
|
|
if (selectedSkill.value.usesSpreadsheetRule) {
|
|
|
|
|
loadSpreadsheetChangeRecords(assetId).catch(() => {})
|
|
|
|
|
}
|
|
|
|
|
if (!selectedSkill.value.usesJsonRiskRule) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if (selectedSkill.value.riskRuleGenerationFailed || selectedSkill.value.riskRuleGenerationBusy) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
await loadRiskRuleJson(assetId)
|
|
|
|
|
} catch (jsonError) {
|
|
|
|
|
console.warn('Failed to load risk rule JSON:', jsonError)
|
|
|
|
|
const jsonMessage =
|
|
|
|
|
jsonError?.message || '风险规则 JSON 文件缺失或无法读取,请同步规则库后重试。'
|
|
|
|
|
toast(jsonMessage)
|
|
|
|
|
selectedSkill.value = {
|
|
|
|
|
...selectedSkill.value,
|
|
|
|
|
riskRuleJsonText: '{}',
|
|
|
|
|
riskRuleDescription:
|
|
|
|
|
selectedSkill.value.riskRuleDescription ||
|
|
|
|
|
'规则 JSON 尚未就绪,请联系管理员执行平台风险规则同步。'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
2026-06-01 17:07:14 +08:00
|
|
|
const message = error?.message || '资产详情加载失败,请稍后重试。'
|
|
|
|
|
if (silent) {
|
|
|
|
|
console.warn('Silent asset detail refresh failed:', error)
|
|
|
|
|
} else {
|
|
|
|
|
detailError.value = message
|
|
|
|
|
toast(message)
|
|
|
|
|
}
|
2026-05-29 09:44:03 +08:00
|
|
|
} finally {
|
2026-06-01 17:07:14 +08:00
|
|
|
if (!silent) {
|
|
|
|
|
detailLoading.value = false
|
|
|
|
|
}
|
2026-05-29 09:44:03 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function mergeSelectedRuleLifecycle(detail) {
|
|
|
|
|
if (!selectedSkill.value || !detail) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const next = buildDetailViewModel(detail, runs.value)
|
|
|
|
|
selectedSkill.value = {
|
|
|
|
|
...selectedSkill.value,
|
|
|
|
|
status: next.status,
|
|
|
|
|
statusValue: next.statusValue,
|
|
|
|
|
statusTone: next.statusTone,
|
|
|
|
|
publishedVersion: next.publishedVersion,
|
|
|
|
|
workingVersion: next.workingVersion,
|
|
|
|
|
currentVersion: next.currentVersion,
|
|
|
|
|
displayVersion: next.displayVersion,
|
|
|
|
|
reviewer: next.reviewer,
|
|
|
|
|
publisher: next.publisher,
|
|
|
|
|
publishedAt: next.publishedAt,
|
|
|
|
|
isOnlineValue: next.isOnlineValue,
|
|
|
|
|
isOnlineLabel: next.isOnlineLabel,
|
|
|
|
|
isOnlineTone: next.isOnlineTone,
|
|
|
|
|
isEnabledValue: next.isEnabledValue,
|
|
|
|
|
isEnabledLabel: next.isEnabledLabel,
|
|
|
|
|
isEnabledTone: next.isEnabledTone,
|
|
|
|
|
latestTestSummary: next.latestTestSummary,
|
|
|
|
|
lastOperationLabel: next.lastOperationLabel,
|
|
|
|
|
lastOperationTone: next.lastOperationTone,
|
|
|
|
|
publishMeta: next.publishMeta,
|
|
|
|
|
publishState: next.publishState,
|
|
|
|
|
updatedAt: next.updatedAt,
|
|
|
|
|
configJson: next.configJson
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
loading,
|
|
|
|
|
errorMessage,
|
|
|
|
|
detailLoading,
|
|
|
|
|
detailError,
|
|
|
|
|
runLoading,
|
|
|
|
|
runs,
|
|
|
|
|
assetBuckets,
|
|
|
|
|
currentAssets,
|
|
|
|
|
loadRuns,
|
|
|
|
|
loadAssets,
|
|
|
|
|
refreshCurrentAssets,
|
|
|
|
|
loadSelectedAssetDetail,
|
|
|
|
|
mergeSelectedRuleLifecycle
|
|
|
|
|
}
|
|
|
|
|
}
|