refactor: 左脚本编辑器+右URL卡片+历史结果选择,三合一布局
This commit is contained in:
@@ -1,141 +1,110 @@
|
||||
<template>
|
||||
<div>
|
||||
<div style="display:flex;flex-direction:column;height:calc(100vh - 80px)">
|
||||
<!-- 顶栏 -->
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:12px">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;flex-shrink:0">
|
||||
<h2 style="margin:0">适配校验:{{ siteId }}</h2>
|
||||
<el-button @click="$router.push('/access-results')">← 返回列表</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 控制栏 -->
|
||||
<el-card shadow="never" style="margin-bottom:12px">
|
||||
<div style="display:flex;gap:12px;align-items:center;flex-wrap:wrap">
|
||||
<div style="display:flex;gap:12px;align-items:center;flex-wrap:wrap;margin-bottom:8px;flex-shrink:0">
|
||||
<el-select v-model="selectedConfigId" placeholder="选择版本" @change="onConfigChange" style="width:200px">
|
||||
<el-option v-for="v in allConfigVersions" :key="v.id"
|
||||
:label="'v'+v.version + (v.status==='pending'?' [待审]':'') + (v.isLatest?' [当前]':'')" :value="v.id" />
|
||||
</el-select>
|
||||
|
||||
<el-select v-model="selectedConfigId" placeholder="选择配置版本" @change="onConfigChange" style="width:240px">
|
||||
<el-option v-for="v in allConfigVersions" :key="v.id"
|
||||
:label="'v'+v.version + (v.status==='pending'?' [待审核]':'') + (v.isLatest?' [当前]':'')" :value="v.id" />
|
||||
</el-select>
|
||||
<span class="text-xs">{{ pages.length }}页 {{ totalResults }}次</span>
|
||||
|
||||
<el-divider direction="vertical" />
|
||||
<template v-if="selectedConfig">
|
||||
<el-tag v-if="parseSummary.matched>0" size="small" type="success">✓{{ parseSummary.matched }}</el-tag>
|
||||
<el-tag v-if="parseSummary.unmatched>0" size="small" type="warning">⚠{{ parseSummary.unmatched }}</el-tag>
|
||||
</template>
|
||||
|
||||
<span class="text-xs"><strong>{{ pages.length }}</strong> 页面</span>
|
||||
<span class="text-xs"><strong>{{ totalResults }}</strong> 次提交</span>
|
||||
<el-button size="small" @click="refresh" :loading="loading">刷新</el-button>
|
||||
<el-button size="small" @click="doBatchParse" :loading="parseLoading" v-if="selectedConfigId">全部重解析</el-button>
|
||||
|
||||
<el-divider direction="vertical" />
|
||||
<!-- 审批/拒绝 -->
|
||||
<template v-if="selectedConfig?.status==='pending'">
|
||||
<el-button size="small" type="success" @click="approveConfig" :loading="approving">审批通过</el-button>
|
||||
<el-button size="small" type="danger" @click="rejectConfig" :loading="rejecting">拒绝</el-button>
|
||||
</template>
|
||||
<el-button size="small" type="success" @click="approveConfig" :loading="approving" v-if="selectedConfigId && selectedConfig?.status!=='pending'">发布脚本</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 解析摘要 -->
|
||||
<template v-if="selectedConfig">
|
||||
<el-tag v-if="parseSummary.matched>0" size="small" type="success">
|
||||
✓ {{ parseSummary.matched }} 页匹配
|
||||
</el-tag>
|
||||
<el-tag v-if="parseSummary.unmatched>0" size="small" type="warning">
|
||||
⚠ {{ parseSummary.unmatched }} 页未匹配
|
||||
</el-tag>
|
||||
<el-tag v-if="!parseSummary.hasParsed" size="small" type="info">未解析</el-tag>
|
||||
</template>
|
||||
|
||||
<el-button size="small" @click="refresh" :loading="loading">刷新</el-button>
|
||||
<el-button size="small" @click="doBatchParse" :loading="parseLoading" v-if="selectedConfigId">全部重新解析</el-button>
|
||||
|
||||
<!-- 审批/拒绝(待审核配置) -->
|
||||
<template v-if="selectedConfig?.status==='pending'">
|
||||
<el-divider direction="vertical" />
|
||||
<el-button size="small" type="success" @click="approveConfig" :loading="approving">审批通过</el-button>
|
||||
<el-button size="small" type="danger" @click="rejectConfig" :loading="rejecting">拒绝</el-button>
|
||||
</template>
|
||||
|
||||
<el-button size="small" @click="configVisible=true" v-if="selectedConfigId">编辑脚本</el-button>
|
||||
<el-button size="small" type="success" @click="approveConfig" :loading="approving" v-if="selectedConfigId && selectedConfig?.status!=='pending'">发布脚本</el-button>
|
||||
<!-- 主体:脚本 + 结果 -->
|
||||
<div style="display:flex;gap:12px;flex:1;min-height:0">
|
||||
<!-- 左侧:脚本编辑器 -->
|
||||
<div style="flex:0 0 420px;display:flex;flex-direction:column;min-height:0">
|
||||
<div style="font-size:13px;font-weight:500;margin-bottom:4px;display:flex;justify-content:space-between;align-items:center">
|
||||
<span>Groovy 脚本</span>
|
||||
<el-button size="small" type="primary" @click="saveScript" :loading="saving" v-if="selectedConfigId">保存</el-button>
|
||||
</div>
|
||||
<el-input v-model="scriptContent" type="textarea" :rows="1" style="flex:1;font-family:monospace;font-size:11px;line-height:1.4"
|
||||
placeholder="// 先选配置版本,再编辑脚本 // 内置变量: content, url, jsoup, json, utils" />
|
||||
<div style="font-size:10px;color:#909399;margin-top:2px">
|
||||
内置: <code>content</code> <code>url</code> <code>jsoup</code> <code>json</code> <code>utils</code>
|
||||
· 返回 Map{pageName,extracted} 或 List
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 右侧:URL卡片 -->
|
||||
<div style="flex:1;overflow:auto;display:flex;flex-direction:column;gap:8px;min-height:0">
|
||||
<el-card v-for="page in pages" :key="page.url" shadow="hover" size="small">
|
||||
<template #header>
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:8px">
|
||||
<div style="display:flex;align-items:center;gap:8px">
|
||||
<span v-if="page.parsed?.matched" style="color:#67c23a">✓</span>
|
||||
<span v-else-if="page.parsed" style="color:#e6a23c">⚠</span>
|
||||
<span v-else style="color:#c0c4cc">○</span>
|
||||
<strong style="font-size:13px;word-break:break-all">{{ page.url }}</strong>
|
||||
<el-tag v-if="page.statusCode" size="small" :type="statusTag(page.statusCode)">{{ page.statusCode }}</el-tag>
|
||||
<el-tag v-if="page.parsed?.matched" size="small" type="success">{{ page.parsed.pageName }}</el-tag>
|
||||
|
||||
<!-- 选择历史结果 -->
|
||||
<el-select v-if="page.historyIds?.length>1" v-model="page.activeId" size="small" style="width:140px" @change="v=>parseHistory(page,v)">
|
||||
<el-option v-for="h in page.historyIds" :key="h.id" :label="'#'+h.id+' '+h.time" :value="h.id" />
|
||||
</el-select>
|
||||
|
||||
<el-tag size="small" type="info">×{{ page.totalCount }}</el-tag>
|
||||
</div>
|
||||
<div style="display:flex;gap:4px">
|
||||
<el-button size="small" @click="viewRaw(page)">原始</el-button>
|
||||
<el-button size="small" @click="reparseUrl(page)" :loading="reparsingUrls.has(page.url)">重解析</el-button>
|
||||
<el-popconfirm title="确认删除?" @confirm="deleteResult(page)">
|
||||
<template #reference><el-button size="small" type="danger" text>删除</el-button></template>
|
||||
</el-popconfirm>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 解析结果 -->
|
||||
<div v-if="page.parsed?.matched && page.parsed.extracted?.length">
|
||||
<el-table :data="page.parsed.extracted" border stripe size="small" max-height="280">
|
||||
<el-table-column type="index" label="#" width="40" />
|
||||
<el-table-column v-for="col in Object.keys(page.parsed.extracted[0])" :key="col"
|
||||
:prop="col" :label="col" min-width="90" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<span :style="scope.row[col]==null?'color:#c0c4cc':''">{{ scope.row[col] ?? '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div v-else-if="page.parsed" style="color:#e6a23c;font-size:12px">
|
||||
{{ page.parsed.message || '解析失败' }}
|
||||
</div>
|
||||
<div v-else style="color:#909399;font-size:12px">未解析</div>
|
||||
</el-card>
|
||||
|
||||
<div v-if="pages.length===0 && !loading" style="text-align:center;padding:60px;color:#909399">暂无访问结果</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 原始内容弹窗 -->
|
||||
<el-dialog v-model="rawVisible" :title="'原始内容 · ' + rawUrl" width="900px" :close-on-click-modal="false">
|
||||
<div v-if="rawLoading" style="text-align:center;padding:40px;color:#909399">加载中...</div>
|
||||
<el-dialog v-model="rawVisible" title="原始内容" width="900px" :close-on-click-modal="false">
|
||||
<div v-if="rawLoading" style="text-align:center;padding:40px">加载中...</div>
|
||||
<pre v-else class="raw-content">{{ rawContent }}</pre>
|
||||
<template #footer>
|
||||
<el-button @click="rawVisible=false">关闭</el-button>
|
||||
</template>
|
||||
<template #footer><el-button @click="rawVisible=false">关闭</el-button></template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 脚本编辑弹窗 -->
|
||||
<el-dialog v-model="configVisible" title="Groovy 脚本 · v{{ selectedConfig?.version }}" width="880px" :close-on-click-modal="false">
|
||||
<div v-if="scriptLoading" style="text-align:center;padding:20px;color:#909399">加载中...</div>
|
||||
<template v-else>
|
||||
<div style="margin-bottom:6px;font-size:11px;color:#909399">
|
||||
内置变量: <code>content</code>(页面内容) <code>url</code>(访问URL) <code>jsoup</code> <code>json</code> <code>utils</code>
|
||||
· 返回 Map{pageName,extracted,message} 或 List
|
||||
</div>
|
||||
<el-input v-model="scriptContent" type="textarea" :rows="22" style="font-family:monospace;font-size:12px"
|
||||
placeholder="def doc = jsoup.parse(content) def rows = [] doc.select('table tr').each { row -> rows << [ title: utils.text(utils.selectFirst(row,'td.name a')), size: utils.text(utils.selectFirst(row,'td.size')) ] } return [pageName:'search', extracted:rows]" />
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="configVisible=false">关闭</el-button>
|
||||
<el-button type="primary" @click="saveScript" :loading="saving">保存脚本</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 解析中 -->
|
||||
<div v-if="parseLoading" style="text-align:center;padding:12px;color:#909399">
|
||||
<el-icon class="is-loading"><Loading /></el-icon> 正在解析各页面适配结果...
|
||||
</div>
|
||||
|
||||
<!-- URL 卡片列表 -->
|
||||
<div style="display:flex;flex-direction:column;gap:8px">
|
||||
<el-card v-for="page in pages" :key="page.url" shadow="hover" size="small">
|
||||
<template #header>
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:8px">
|
||||
<div style="display:flex;align-items:center;gap:8px">
|
||||
<!-- 解析状态图标 -->
|
||||
<span v-if="page.parsed?.matched" style="color:#67c23a;font-size:16px">✓</span>
|
||||
<span v-else-if="page.parsed" style="color:#e6a23c;font-size:16px">⚠</span>
|
||||
<span v-else style="color:#c0c4cc;font-size:16px">○</span>
|
||||
|
||||
<strong style="font-size:14px;word-break:break-all">{{ page.url }}</strong>
|
||||
<el-tag v-if="page.statusCode" size="small" :type="statusTag(page.statusCode)">{{ page.statusCode }}</el-tag>
|
||||
<span v-if="page.responseTimeMs!=null" class="text-xs" style="color:#909399">{{ page.responseTimeMs }}ms</span>
|
||||
|
||||
<!-- 解析信息 -->
|
||||
<template v-if="page.parsed?.matched">
|
||||
<el-tag size="small" type="success">{{ page.parsed.pageName }}</el-tag>
|
||||
<span class="text-xs" style="color:#909399">{{ page.parsed.rowCount }}行 {{ Object.keys(page.parsed.extracted?.[0]||{}).length }}字段</span>
|
||||
</template>
|
||||
<el-tag v-else-if="page.parsed" size="small" type="warning">未匹配规则</el-tag>
|
||||
|
||||
<el-tag size="small" type="info">×{{ page.totalCount }}</el-tag>
|
||||
</div>
|
||||
<div style="display:flex;gap:6px">
|
||||
<el-button size="small" @click="viewRaw(page)">原始内容</el-button>
|
||||
<el-button size="small" @click="reparseUrl(page)" :loading="reparsingUrls.has(page.url)">重新解析</el-button>
|
||||
<el-popconfirm title="确认删除此访问结果?" @confirm="deleteResult(page)">
|
||||
<template #reference>
|
||||
<el-button size="small" type="danger" text>删除</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 解析结果始终显示 -->
|
||||
<div v-if="page.parsed?.matched && page.parsed.extracted?.length" style="margin-top:4px">
|
||||
<el-table :data="page.parsed.extracted" border stripe size="small" max-height="300">
|
||||
<el-table-column type="index" label="#" width="45" />
|
||||
<el-table-column v-for="col in Object.keys(page.parsed.extracted[0])" :key="col"
|
||||
:prop="col" :label="col" min-width="100" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<span :style="scope.row[col]==null?'color:#c0c4cc':''">{{ scope.row[col] ?? '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div v-else-if="page.parsed" style="color:#e6a23c;font-size:12px;margin-top:4px">
|
||||
{{ page.parsed.message || '解析失败' }}
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<div v-if="pages.length===0 && !loading" style="text-align:center;padding:60px;color:#909399">
|
||||
暂无访问结果
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -147,37 +116,27 @@ import { Loading } from '@element-plus/icons-vue'
|
||||
const route = useRoute()
|
||||
const siteId = route.params.siteId
|
||||
|
||||
const loading = ref(false)
|
||||
const parseLoading = ref(false)
|
||||
const selectedConfigId = ref(null)
|
||||
const selectedConfig = ref(null)
|
||||
const configVisible = ref(false)
|
||||
watch(configVisible, (v) => { if (v) loadScript() })
|
||||
const scriptContent = ref('')
|
||||
const scriptLoading = ref(false)
|
||||
const saving = ref(false)
|
||||
const approving = ref(false)
|
||||
const rejecting = ref(false)
|
||||
|
||||
const allConfigVersions = ref([])
|
||||
const allResults = ref([])
|
||||
const pageParsed = ref({})
|
||||
const expandedSet = reactive(new Set())
|
||||
const reparsingUrls = reactive(new Set())
|
||||
const rawVisible = ref(false), rawLoading = ref(false), rawUrl = ref(''), rawContent = ref('')
|
||||
const loading = ref(false), parseLoading = ref(false)
|
||||
const selectedConfigId = ref(null), selectedConfig = ref(null)
|
||||
const scriptContent = ref(''), saving = ref(false), approving = ref(false), rejecting = ref(false)
|
||||
const allConfigVersions = ref([]), allResults = ref([])
|
||||
const pageParsed = ref({}), reparsingUrls = reactive(new Set())
|
||||
const rawVisible = ref(false), rawLoading = ref(false), rawContent = ref('')
|
||||
|
||||
const totalResults = computed(() => allResults.value.length)
|
||||
|
||||
// 始终从 allResults 按 URL 分组
|
||||
const pages = computed(() => {
|
||||
const map = new Map()
|
||||
const map = new LinkedHashMap()
|
||||
for (const r of allResults.value) {
|
||||
const key = r.url || '(无URL)'
|
||||
if (!map.has(key)) {
|
||||
map.set(key, { url: key, accessResultId: r.id, statusCode: r.statusCode, responseTimeMs: r.responseTimeMs,
|
||||
createdAt: r.createdAt, totalCount: 0, parsed: null })
|
||||
map.set(key, { url: key, activeId: r.id, accessResultId: r.id,
|
||||
statusCode: r.statusCode, responseTimeMs: r.responseTimeMs,
|
||||
createdAt: r.createdAt, totalCount: 0, historyIds: [], parsed: null })
|
||||
}
|
||||
map.get(key).totalCount++
|
||||
const p = map.get(key)
|
||||
p.totalCount++
|
||||
p.historyIds.push({ id: r.id, time: (r.createdAt||'').substring(5,16) })
|
||||
}
|
||||
for (const [url, parsed] of Object.entries(pageParsed.value)) {
|
||||
if (map.has(url)) map.get(url).parsed = parsed
|
||||
@@ -185,35 +144,41 @@ const pages = computed(() => {
|
||||
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++
|
||||
}
|
||||
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)
|
||||
])
|
||||
const approved = ar.status==='fulfilled' ? (ar.value.data||[]) : []
|
||||
const pending = pr.status==='fulfilled' ? (pr.value.data||[]) : []
|
||||
allConfigVersions.value = [...pending, ...approved]
|
||||
const [ar, pr] = await Promise.allSettled([api.configs.bySite(siteId), api.adminConfigs.pendingBySite(siteId)])
|
||||
allConfigVersions.value = [...(pr.status==='fulfilled'?pr.value.data||[]:[]), ...(ar.status==='fulfilled'?ar.value.data||[]:[])]
|
||||
if (allConfigVersions.value.length) selectedConfigId.value = allConfigVersions.value[0].id
|
||||
} catch {}
|
||||
}
|
||||
|
||||
const onConfigChange = async () => {
|
||||
const onConfigChange = () => {
|
||||
const cfg = allConfigVersions.value.find(v => v.id===selectedConfigId.value)
|
||||
if (!cfg) return
|
||||
selectedConfig.value = cfg
|
||||
if (cfg) selectedConfig.value = cfg
|
||||
}
|
||||
|
||||
const loadScript = async () => {
|
||||
if (!selectedConfig.value) return
|
||||
try { const r = await api.adminConfigs.getScript(selectedConfig.value.id); scriptContent.value = r.data?.script||'' }
|
||||
catch { scriptContent.value = '' }
|
||||
}
|
||||
|
||||
watch(selectedConfig, (v) => { if (v) loadScript() })
|
||||
|
||||
const saveScript = async () => {
|
||||
if (!selectedConfig.value) return
|
||||
saving.value = true
|
||||
try { await api.adminConfigs.updateScript(selectedConfig.value.id, scriptContent.value); ElMessage.success('已保存') }
|
||||
catch(e) { ElMessage.error(e.response?.data?.message||'保存失败') }
|
||||
finally { saving.value = false }
|
||||
}
|
||||
|
||||
const doBatchParse = async () => {
|
||||
@@ -222,46 +187,56 @@ const doBatchParse = async () => {
|
||||
try {
|
||||
const r = await api.adapter.parseBatch(selectedConfigId.value, siteId)
|
||||
const map = {}
|
||||
for (const p of (r.data?.pages || [])) {
|
||||
if (p.parsed) map[p.url] = p.parsed
|
||||
}
|
||||
for (const p of (r.data?.pages||[])) { if (p.parsed) map[p.url] = p.parsed }
|
||||
pageParsed.value = map
|
||||
} catch { /* 非关键 */ }
|
||||
} catch {}
|
||||
finally { parseLoading.value = false }
|
||||
}
|
||||
|
||||
const reparseUrl = async (page) => {
|
||||
if (!selectedConfigId.value) return
|
||||
reparsingUrls.add(page.url)
|
||||
try {
|
||||
const r = await api.adapter.parse(selectedConfigId.value, page.activeId)
|
||||
if (r.data) {
|
||||
const np = { ...pageParsed.value }; np[page.url] = r.data; pageParsed.value = np
|
||||
}
|
||||
} catch {}
|
||||
finally { reparsingUrls.delete(page.url) }
|
||||
}
|
||||
|
||||
const parseHistory = async (page, newId) => {
|
||||
page.accessResultId = newId
|
||||
await reparseUrl(page)
|
||||
}
|
||||
|
||||
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('获取访问结果失败') }
|
||||
try { allResults.value = (await api.accessResults.bySite(siteId)).data||[] }
|
||||
catch { ElMessage.error('获取访问结果失败') }
|
||||
finally { loading.value = false }
|
||||
}
|
||||
|
||||
// 编辑
|
||||
const loadScript = async () => {
|
||||
if (!selectedConfig.value) return
|
||||
scriptLoading.value = true
|
||||
try { const r = await api.adminConfigs.getScript(selectedConfig.value.id); scriptContent.value = r.data?.script || '' }
|
||||
catch { scriptContent.value = '' }
|
||||
finally { scriptLoading.value = false }
|
||||
const viewRaw = async (page) => {
|
||||
rawVisible.value = true; rawLoading.value = true; rawContent.value = ''
|
||||
try { rawContent.value = (await api.accessResults.get(page.activeId)).data?.content || '(空)' }
|
||||
catch { rawContent.value = '加载失败' }
|
||||
finally { rawLoading.value = false }
|
||||
}
|
||||
const saveScript = async () => {
|
||||
saving.value = true
|
||||
try {
|
||||
await api.adminConfigs.updateScript(selectedConfig.value.id, scriptContent.value)
|
||||
configVisible.value = false
|
||||
ElMessage.success('脚本已保存')
|
||||
} catch(e) { ElMessage.error(e.response?.data?.message||'保存失败') }
|
||||
finally { saving.value = false }
|
||||
|
||||
const deleteResult = async (page) => {
|
||||
if (!page.accessResultId) return
|
||||
try { await api.accessResults.delete(page.accessResultId); ElMessage.success('已删除'); refresh() }
|
||||
catch { ElMessage.error('删除失败') }
|
||||
}
|
||||
|
||||
const approveConfig = async () => {
|
||||
try { await ElMessageBox.confirm('确认审批?版本号将自动+1','审批配置',{confirmButtonText:'确认'}) } catch{return}
|
||||
if (!selectedConfig.value) return
|
||||
const label = selectedConfig.value.status==='pending' ? '确认审批?版本号将自动+1' : '确认发布脚本?版本号将+1'
|
||||
try { await ElMessageBox.confirm(label,'确认',{confirmButtonText:'确认'}) } catch{return}
|
||||
approving.value = true
|
||||
try { await api.adminConfigs.approve(selectedConfig.value.id); ElMessage.success('已审批'); loadConfigs() }
|
||||
catch(e) { ElMessage.error(e.response?.data?.message||'审批失败') }
|
||||
try { await api.adminConfigs.approve(selectedConfig.value.id); ElMessage.success('已发布'); loadConfigs() }
|
||||
catch(e) { ElMessage.error(e.response?.data?.message||'失败') }
|
||||
finally { approving.value = false }
|
||||
}
|
||||
|
||||
@@ -269,81 +244,22 @@ const rejectConfig = async () => {
|
||||
try { await ElMessageBox.confirm('确认拒绝?','拒绝配置',{confirmButtonText:'确认',type:'warning'}) } catch{return}
|
||||
rejecting.value = true
|
||||
try { await api.adminConfigs.reject(selectedConfig.value.id,''); ElMessage.success('已拒绝'); loadConfigs() }
|
||||
catch(e) { ElMessage.error(e.response?.data?.message||'拒绝失败') }
|
||||
catch(e) { ElMessage.error(e.response?.data?.message||'失败') }
|
||||
finally { rejecting.value = false }
|
||||
}
|
||||
|
||||
const toggleView = (page) => {
|
||||
if (expandedSet.has(page.url)) expandedSet.delete(page.url)
|
||||
else expandedSet.add(page.url)
|
||||
}
|
||||
|
||||
const reparseUrl = async (page) => {
|
||||
if (!selectedConfigId.value || !page.accessResultId) return
|
||||
reparsingUrls.add(page.url)
|
||||
try {
|
||||
const r = await api.adapter.parse(selectedConfigId.value, page.accessResultId)
|
||||
const parsed = r.data
|
||||
if (parsed) {
|
||||
const newParsed = { ...pageParsed.value }
|
||||
newParsed[page.url] = parsed
|
||||
pageParsed.value = newParsed
|
||||
}
|
||||
ElMessage.success('已重新解析')
|
||||
} catch { ElMessage.error('解析失败') }
|
||||
finally { reparsingUrls.delete(page.url) }
|
||||
}
|
||||
|
||||
const viewRaw = async (page) => {
|
||||
rawUrl.value = page.url
|
||||
rawVisible.value = true
|
||||
rawLoading.value = true
|
||||
rawContent.value = ''
|
||||
try {
|
||||
const r = await api.accessResults.get(page.accessResultId)
|
||||
rawContent.value = r.data?.content || '(空)'
|
||||
} catch { rawContent.value = '加载失败' }
|
||||
finally { rawLoading.value = false }
|
||||
}
|
||||
|
||||
const deleteResult = async (page) => {
|
||||
try {
|
||||
await api.accessResults.delete(page.accessResultId)
|
||||
ElMessage.success('已删除')
|
||||
refresh()
|
||||
} catch { ElMessage.error('删除失败') }
|
||||
}
|
||||
|
||||
const statusTag = (code) => {
|
||||
if (code>=200&&code<300) return 'success'
|
||||
if (code>=300&&code<400) return 'warning'
|
||||
return 'danger'
|
||||
}
|
||||
const statusTag = (c) => c>=200&&c<300?'success':c>=300&&c<400?'warning':'danger'
|
||||
|
||||
onMounted(async () => {
|
||||
await refresh()
|
||||
await loadConfigs()
|
||||
if (selectedConfigId.value) {
|
||||
const cfg = allConfigVersions.value.find(v => v.id===selectedConfigId.value)
|
||||
if (cfg) selectedConfig.value = cfg
|
||||
selectedConfig.value = allConfigVersions.value.find(v=>v.id===selectedConfigId.value)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.raw-content {
|
||||
background:#1e1e1e; color:#d4d4d4; padding:12px; border-radius:4px;
|
||||
font-size:11px; line-height:1.4; margin:0; white-space:pre-wrap; word-break:break-all;
|
||||
max-height:550px; overflow:auto;
|
||||
}
|
||||
.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:500px; overflow:auto;
|
||||
}
|
||||
.config-json :deep(.key) { color:#9cdcfe }
|
||||
.config-json :deep(.string) { color:#ce9178 }
|
||||
.config-json :deep(.number) { color:#b5cea8 }
|
||||
.config-json :deep(.boolean) { color:#569cd6 }
|
||||
.config-json :deep(.null) { color:#569cd6 }
|
||||
.raw-content { background:#1e1e1e; color:#d4d4d4; padding:12px; border-radius:4px;
|
||||
font-size:11px; line-height:1.4; margin:0; white-space:pre-wrap; word-break:break-all; max-height:550px; overflow:auto }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user