diff --git a/web/src/views/AccessResultCheck.vue b/web/src/views/AccessResultCheck.vue index 2f0a212..fa48c04 100644 --- a/web/src/views/AccessResultCheck.vue +++ b/web/src/views/AccessResultCheck.vue @@ -6,89 +6,106 @@ ← 返回列表 + -
- - - +
+ + + {{ pages.length }} 页面 {{ totalResults }} 次提交 - {{ validCount }} 有效 - {{ invalidCount }} 无效 - {{ uncheckedCount }} 待验 - 刷新 - - - {{ showConfig ? '收起配置' : '查看配置' }} - -
- - -
-
- v{{ selectedConfig.version }} - - {{ selectedConfig.status==='approved'?'已批准':'待审核' }} + + + + 刷新 + 重新解析 + + + + + 查看配置JSON
- + + + +

+      
+    
+ +
正在解析各页面适配结果...
- +
@@ -138,7 +152,7 @@ const parseLoading = ref(false) const selectedConfigId = ref(null) const selectedConfig = ref(null) const selectedConfigJson = ref('') -const showConfig = ref(false) +const configVisible = ref(false) const editing = ref(false) const editContent = ref('') const saving = ref(false) @@ -147,44 +161,47 @@ const rejecting = ref(false) const allConfigVersions = ref([]) const allResults = ref([]) -const pageParsed = ref({}) // url → parsed data +const pageParsed = ref({}) const expandedSet = reactive(new Set()) const totalResults = computed(() => allResults.value.length) -const validCount = computed(() => allResults.value.filter(r => r.isValid===true).length) -const invalidCount = computed(() => allResults.value.filter(r => r.isValid===false).length) -const uncheckedCount = computed(() => allResults.value.filter(r => r.isValid==null).length) -// 始终从 allResults 按 URL 分组生成 pages,解析数据注入 +// 始终从 allResults 按 URL 分组 const pages = computed(() => { const map = new Map() for (const r of allResults.value) { const key = r.url || '(无URL)' if (!map.has(key)) { map.set(key, { url: key, statusCode: r.statusCode, responseTimeMs: r.responseTimeMs, - createdAt: r.createdAt, totalCount: 0, validCount: 0, invalidCount: 0, - uncheckedCount: 0, history: [], parsed: null }) + createdAt: r.createdAt, totalCount: 0, history: [], parsed: null }) } const p = map.get(key) p.totalCount++ - if (r.isValid===true) p.validCount++ - else if (r.isValid===false) p.invalidCount++ - else p.uncheckedCount++ if (p.history.length < 5) p.history.push(r) } - // 合并解析数据 for (const [url, parsed] of Object.entries(pageParsed.value)) { if (map.has(url)) map.get(url).parsed = parsed } return Array.from(map.values()) }) -// 加载配置版本列表 +// 全局解析摘要 +const parseSummary = computed(() => { + let matched = 0, unmatched = 0 + for (const p of pages.value) { + if (p.parsed) { + if (p.parsed.matched) matched++ + else unmatched++ + } + } + return { matched, unmatched, hasParsed: matched + unmatched > 0 } +}) + +// 加载配置版本 const loadConfigs = async () => { try { const [ar, pr] = await Promise.allSettled([ - api.configs.bySite(siteId), - api.adminConfigs.pendingBySite(siteId) + api.configs.bySite(siteId), api.adminConfigs.pendingBySite(siteId) ]) const approved = ar.status==='fulfilled' ? (ar.value.data||[]) : [] const pending = pr.status==='fulfilled' ? (pr.value.data||[]) : [] @@ -193,14 +210,11 @@ const loadConfigs = async () => { } catch {} } -// 选中配置 → 更新 selectedConfig + 自动批量解析 const onConfigChange = async () => { const cfg = allConfigVersions.value.find(v => v.id===selectedConfigId.value) if (!cfg) return selectedConfig.value = cfg editing.value = false - - // 加载配置内容 try { if (cfg.status==='pending') { const r = await api.adminConfigs.getContent(cfg.id) @@ -210,7 +224,6 @@ const onConfigChange = async () => { selectedConfigJson.value = typeof r.data==='string' ? r.data : JSON.stringify(r.data||{},null,2) } } catch { selectedConfigJson.value = '' } - await doBatchParse() } @@ -228,20 +241,17 @@ const doBatchParse = async () => { finally { parseLoading.value = false } } -const reloadBatchParse = () => doBatchParse() - const refresh = async () => { loading.value = true try { const r = await api.accessResults.bySite(siteId) allResults.value = r.data||[] - // 刷新解析数据 if (selectedConfigId.value) await doBatchParse() } catch { ElMessage.error('获取访问结果失败') } finally { loading.value = false } } -// 编辑配置 +// 编辑 const startEdit = () => { editContent.value=selectedConfigJson.value; editing.value=true } const cancelEdit = () => { editing.value=false } const saveEdit = async () => { @@ -270,20 +280,11 @@ const rejectConfig = async () => { finally { rejecting.value = false } } -const toggleConfigPanel = () => showConfig.value = !showConfig.value const toggleView = (page) => { if (expandedSet.has(page.url)) expandedSet.delete(page.url) else expandedSet.add(page.url) } -const batchValidate = async (url, isValid) => { - try { - const r = await api.accessResults.batchValidate(siteId, url, isValid) - ElMessage.success(`已标记 ${r.data?.affected||0} 条为${isValid?'有效':'无效'}`) - refresh() - } catch { ElMessage.error('批量校验失败') } -} - const formatTime = (t) => t ? t.substring(5,16) : '-' const statusTag = (code) => { if (code>=200&&code<300) return 'success' @@ -291,7 +292,6 @@ const statusTag = (code) => { return 'danger' } -// 配置语法高亮 const highlightedConfig = computed(() => { try { return syntaxHighlight(JSON.stringify(JSON.parse(selectedConfigJson.value),null,2)) } catch { return escapeHtml(selectedConfigJson.value||'') } @@ -311,7 +311,6 @@ const syntaxHighlight = (json) => escapeHtml(json).replace( onMounted(async () => { await refresh() await loadConfigs() - // 默认自动解析 if (selectedConfigId.value) await onConfigChange() }) @@ -320,7 +319,7 @@ onMounted(async () => { .config-json { background:#1e1e1e; color:#d4d4d4; padding:10px; border-radius:4px; font-size:11px; line-height:1.5; margin:0; white-space:pre-wrap; word-break:break-all; - max-height:300px; overflow:auto; + max-height:500px; overflow:auto; } .config-json :deep(.key) { color:#9cdcfe } .config-json :deep(.string) { color:#ce9178 }