diff --git a/web/src/views/RiskRules.vue b/web/src/views/RiskRules.vue
index 9146e06..5065bbc 100644
--- a/web/src/views/RiskRules.vue
+++ b/web/src/views/RiskRules.vue
@@ -6,70 +6,73 @@
刷新
-
+
-
-
- {{ s.row.ruleCount || 0 }}
-
+ {{ s.row.ruleCount || 0 }}
+
+
+ {{ s.row.version || '-' }}
{{ fmt(s.row.updatedAt) }}
-
+
- 编辑
+
+ {{ editType===s.row.siteType ? '收起' : '编辑' }}
+
+
+
+
+
+
+
+
+ 表格
+ JSON
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ×
+
+ + 添加
+
+
+
+
+
+
+
+ 保存
+
+
-
-
-
-
- 表格编辑
- JSON 编辑
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 删除
-
-
- + 添加规则
-
-
-
-
-
-
-
- 保存
-
-
@@ -77,28 +80,25 @@
import api from '../api'
const loading = ref(false), saving = ref(false)
-const rulesData = ref([])
-const siteTypes = ['nexusphp','mtorrent','gazelle','unit3d']
-const editorVisible = ref(false), editorType = ref(''), editorMode = ref('table'), editorJson = ref('')
+const siteTypes = ref([]), rulesData = ref([])
+const editType = ref(''), editorMode = ref('table'), editorJson = ref('')
const editingRules = ref([])
-watch(editorMode, (m) => {
- if (m === 'json') editorJson.value = JSON.stringify(editingRules.value, null, 2)
- else {
- try { editingRules.value = JSON.parse(editorJson.value) } catch { /* keep table */ }
- }
-})
-
const fmt = (t) => t ? (t.substring(0,19)||'').replace('T',' ') : '-'
+watch(editorMode, (m) => {
+ if (m === 'json') editorJson.value = JSON.stringify(editingRules.value, null, 2)
+ else { try { editingRules.value = JSON.parse(editorJson.value) } catch {} }
+})
+
const merged = computed(() => {
const map = {}
- const list = Array.isArray(rulesData.value) ? rulesData.value : []
- for (const r of list) {
- const cnt = (() => { try { return JSON.parse(r.rulesJson || '[]').length } catch { return 0 } })()
+ const rules = Array.isArray(rulesData.value) ? rulesData.value : []
+ for (const r of rules) {
+ const cnt = (() => { try { return JSON.parse(r.rulesJson||'[]').length } catch { return 0 } })()
map[r.siteType] = { siteType: r.siteType, version: r.version, ruleCount: cnt, updatedAt: r.updatedAt, rulesJson: r.rulesJson }
}
- for (const t of siteTypes) {
+ for (const t of siteTypes.value) {
if (!map[t]) map[t] = { siteType: t, version: null, ruleCount: 0, updatedAt: null, rulesJson: null }
}
return Object.values(map)
@@ -107,31 +107,40 @@ const merged = computed(() => {
const fetchAll = async () => {
loading.value = true
try {
- const r = await api.raw.get('/admin/risk-rules')
- rulesData.value = Array.isArray(r?.data) ? r.data : Array.isArray(r) ? r : []
+ // 获取站点类型(从实际站点数据中提取)
+ const sr = await api.raw.get('/admin/sites').catch(() => ({}))
+ const siteList = (sr?.data || sr || [])
+ siteTypes.value = [...new Set(siteList.map(s => s.siteType).filter(Boolean))]
+ if (siteTypes.value.length === 0) siteTypes.value = ['nexusphp','mtorrent','gazelle','unit3d']
+
+ const rr = await api.raw.get('/admin/risk-rules').catch(() => ({}))
+ rulesData.value = Array.isArray(rr?.data) ? rr.data : Array.isArray(rr) ? rr : []
} catch { ElMessage.error('加载失败') }
finally { loading.value = false }
}
-const showEditor = (row) => {
- editorType.value = row.siteType
- try { editingRules.value = JSON.parse(JSON.stringify(JSON.parse(row.rulesJson || '[]'))) }
+const toggleEdit = (row) => {
+ if (editType.value === row.siteType) { editType.value = ''; return }
+ editType.value = row.siteType
+ editorMode.value = 'table'
+ try { editingRules.value = JSON.parse(JSON.stringify(JSON.parse(row.rulesJson||'[]'))) }
catch { editingRules.value = [{type:'KILL',name:'',metric:'',threshold:0,unit:'DAY',condition:'GT',level:'CRITICAL'}] }
- if (editingRules.value.length === 0) editingRules.value.push({type:'KILL',name:'',metric:'',threshold:0,unit:'DAY',condition:'GT',level:'CRITICAL'})
- editorVisible.value = true
+ if (editingRules.value.length===0) editingRules.value.push({type:'KILL',name:'',metric:'',threshold:0,unit:'DAY',condition:'GT',level:'CRITICAL'})
}
const saveRules = async () => {
saving.value = true
try {
- const rules = editorMode.value === 'json' ? JSON.parse(editorJson.value) : editingRules.value
- await api.raw.post('/risk-rules/' + editorType.value, { rules })
- ElMessage.success('已保存')
- editorVisible.value = false
- fetchAll()
+ const rules = editorMode.value==='json' ? JSON.parse(editorJson.value) : editingRules.value
+ await api.raw.post('/risk-rules/'+editType.value, { rules })
+ ElMessage.success('已保存'); editType.value = ''; fetchAll()
} catch { ElMessage.error('保存失败') }
finally { saving.value = false }
}
onMounted(fetchAll)
+
+
diff --git a/web/src/views/SitePages.vue b/web/src/views/SitePages.vue
index 7f66eb8..37081fd 100644
--- a/web/src/views/SitePages.vue
+++ b/web/src/views/SitePages.vue
@@ -11,59 +11,62 @@
{{ (s.row.names||[]).join(' / ') || '-' }}
-
- {{ s.row.version || '-' }}
-
-
+
{{ s.row.entryCount || 0 }}
+
+ {{ s.row.version || '-' }}
+
{{ fmt(s.row.updatedAt) }}
-
+
- 编辑
+
+ {{ editSiteId===s.row.siteId ? '收起' : '编辑' }}
+
+
+
+
+
+
+
+
+ 表格
+ JSON
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ×
+
+ + 添加
+
+
+
+
+
+
+
+ 保存
+
+
-
-
-
-
- 表格编辑
- JSON 编辑
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 删除
-
-
- + 添加入口
-
-
-
-
-
-
-
- 保存
-
-
@@ -72,21 +75,18 @@ import api from '../api'
const loading = ref(false), saving = ref(false)
const sites = ref([]), pagesMap = ref({})
-const editorVisible = ref(false), editorSiteId = ref(''), editorMode = ref('table'), editorJson = ref('')
+const editSiteId = ref(''), editorMode = ref('table'), editorJson = ref('')
const editingEntries = ref([])
-watch(editorMode, (m) => {
- if (m === 'json') editorJson.value = JSON.stringify(editingEntries.value, null, 2)
- else {
- try { editingEntries.value = JSON.parse(editorJson.value) } catch { /* keep table data */ }
- }
-})
-
const fmt = (t) => t ? (t.substring(0,19)||'').replace('T',' ') : '-'
+watch(editorMode, (m) => {
+ if (m === 'json') editorJson.value = JSON.stringify(editingEntries.value, null, 2)
+ else { try { editingEntries.value = JSON.parse(editorJson.value) } catch {} }
+})
+
const merged = computed(() => {
- const list = Array.isArray(sites.value) ? sites.value : []
- return list.map(s => ({
+ return (Array.isArray(sites.value)?sites.value:[]).map(s => ({
siteId: s.siteId,
names: s.names,
version: pagesMap.value[s.siteId]?.version || null,
@@ -99,41 +99,43 @@ const merged = computed(() => {
const fetchAll = async () => {
loading.value = true
try {
- const [sr, pr] = await Promise.all([
- api.sites.adminList().catch(() => ({})),
- api.raw.get('/admin/site-pages').catch(() => ({})),
+ const [sr, pr] = await Promise.allSettled([
+ api.raw.get('/admin/sites'),
+ api.raw.get('/admin/site-pages'),
])
- sites.value = sr.data || sr || []
- const pages = pr.data || pr || []
+ sites.value = (sr.status==='fulfilled' ? (sr.value?.data || sr.value || []) : [])
+ const pages = pr.status==='fulfilled' ? (pr.value?.data || pr.value || []) : []
const map = {}
for (const p of pages) {
- const entries = JSON.parse(p.entriesJson || '[]')
+ const entries = (() => { try { return JSON.parse(p.entriesJson||'[]') } catch {return []} })()
map[p.siteId] = { version: p.version, entryCount: entries.length, updatedAt: p.updatedAt, entriesJson: p.entriesJson }
}
pagesMap.value = map
- } catch { ElMessage.error('加载失败') }
- finally { loading.value = false }
+ } finally { loading.value = false }
}
-const showEditor = (row) => {
- editorSiteId.value = row.siteId
- try { editingEntries.value = JSON.parse(JSON.stringify(JSON.parse(row.entriesJson || '[]'))) }
- catch { editingEntries.value = [{key:'home',label:'首页',url:'{base}','method':'GET'}] }
- if (editingEntries.value.length === 0) editingEntries.value.push({key:'home',label:'首页',url:'{base}','method':'GET'})
- editorVisible.value = true
+const toggleEdit = (row) => {
+ if (editSiteId.value === row.siteId) { editSiteId.value = ''; return }
+ editSiteId.value = row.siteId
+ editorMode.value = 'table'
+ try { editingEntries.value = JSON.parse(JSON.stringify(JSON.parse(row.entriesJson||'[]'))) }
+ catch { editingEntries.value = [{key:'home',label:'首页',url:'{base}',method:'GET'}] }
+ if (editingEntries.value.length===0) editingEntries.value.push({key:'home',label:'首页',url:'{base}',method:'GET'})
}
const savePages = async () => {
saving.value = true
try {
- const entries = editorMode.value === 'json' ? JSON.parse(editorJson.value) : editingEntries.value
- await api.raw.put('/sites/' + editorSiteId.value + '/pages', { entries })
- ElMessage.success('已保存')
- editorVisible.value = false
- fetchAll()
+ const entries = editorMode.value==='json' ? JSON.parse(editorJson.value) : editingEntries.value
+ await api.raw.put('/sites/'+editSiteId.value+'/pages', { entries })
+ ElMessage.success('已保存'); editSiteId.value = ''; fetchAll()
} catch { ElMessage.error('保存失败') }
finally { saving.value = false }
}
onMounted(fetchAll)
+
+