+
+ 历史提交:
+
{{ formatTime(h.createdAt) }}
-
- {{ h.isValid===true?'✓':h.isValid===false?'✗':'?' }}
-
+ {{ h.statusCode }}
@@ -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 }