perf(frontend): add api cache layer and reduce report polling pressure
This commit is contained in:
@@ -1,7 +1,11 @@
|
|||||||
import { api } from './client'
|
import { api } from './client'
|
||||||
|
import { createCachedGetter } from './cache'
|
||||||
|
|
||||||
export async function fetchBrowserPoolStats() {
|
const browserPoolStatsGetter = createCachedGetter(async () => {
|
||||||
const { data } = await api.get('/browser_pool/stats')
|
const { data } = await api.get('/browser_pool/stats')
|
||||||
return data
|
return data
|
||||||
}
|
}, 4_000)
|
||||||
|
|
||||||
|
export async function fetchBrowserPoolStats(options = {}) {
|
||||||
|
return browserPoolStatsGetter.run(options)
|
||||||
|
}
|
||||||
|
|||||||
46
admin-frontend/src/api/cache.js
Normal file
46
admin-frontend/src/api/cache.js
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
export function createCachedGetter(fetcher, ttlMs = 0) {
|
||||||
|
let hasValue = false
|
||||||
|
let cachedValue = null
|
||||||
|
let expiresAt = 0
|
||||||
|
let inflight = null
|
||||||
|
|
||||||
|
async function run(options = {}) {
|
||||||
|
const force = Boolean(options?.force)
|
||||||
|
const now = Date.now()
|
||||||
|
|
||||||
|
if (!force && hasValue && now < expiresAt) {
|
||||||
|
return cachedValue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!force && inflight) {
|
||||||
|
return inflight
|
||||||
|
}
|
||||||
|
|
||||||
|
inflight = Promise.resolve()
|
||||||
|
.then(() => fetcher())
|
||||||
|
.then((data) => {
|
||||||
|
cachedValue = data
|
||||||
|
hasValue = true
|
||||||
|
const ttl = Math.max(0, Number(ttlMs) || 0)
|
||||||
|
expiresAt = Date.now() + ttl
|
||||||
|
return data
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
inflight = null
|
||||||
|
})
|
||||||
|
|
||||||
|
return inflight
|
||||||
|
}
|
||||||
|
|
||||||
|
function clear() {
|
||||||
|
hasValue = false
|
||||||
|
cachedValue = null
|
||||||
|
expiresAt = 0
|
||||||
|
inflight = null
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
run,
|
||||||
|
clear,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,10 @@
|
|||||||
import { api } from './client'
|
import { api } from './client'
|
||||||
|
import { createCachedGetter } from './cache'
|
||||||
|
|
||||||
|
const emailStatsGetter = createCachedGetter(async () => {
|
||||||
|
const { data } = await api.get('/email/stats')
|
||||||
|
return data
|
||||||
|
}, 10_000)
|
||||||
|
|
||||||
export async function fetchEmailSettings() {
|
export async function fetchEmailSettings() {
|
||||||
const { data } = await api.get('/email/settings')
|
const { data } = await api.get('/email/settings')
|
||||||
@@ -7,12 +13,12 @@ export async function fetchEmailSettings() {
|
|||||||
|
|
||||||
export async function updateEmailSettings(payload) {
|
export async function updateEmailSettings(payload) {
|
||||||
const { data } = await api.post('/email/settings', payload)
|
const { data } = await api.post('/email/settings', payload)
|
||||||
|
emailStatsGetter.clear()
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchEmailStats() {
|
export async function fetchEmailStats(options = {}) {
|
||||||
const { data } = await api.get('/email/stats')
|
return emailStatsGetter.run(options)
|
||||||
return data
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchEmailLogs(params) {
|
export async function fetchEmailLogs(params) {
|
||||||
@@ -22,6 +28,6 @@ export async function fetchEmailLogs(params) {
|
|||||||
|
|
||||||
export async function cleanupEmailLogs(days) {
|
export async function cleanupEmailLogs(days) {
|
||||||
const { data } = await api.post('/email/logs/cleanup', { days })
|
const { data } = await api.post('/email/logs/cleanup', { days })
|
||||||
|
emailStatsGetter.clear()
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,36 +1,40 @@
|
|||||||
import { api } from './client'
|
import { api } from './client'
|
||||||
|
import { createCachedGetter } from './cache'
|
||||||
|
|
||||||
let _feedbackStatsInflight = null
|
const FEEDBACK_STATS_TTL_MS = 10_000
|
||||||
|
|
||||||
|
const feedbackStatsGetter = createCachedGetter(async () => {
|
||||||
|
const { data } = await api.get('/feedbacks', { params: { limit: 1, offset: 0 } })
|
||||||
|
return data?.stats
|
||||||
|
}, FEEDBACK_STATS_TTL_MS)
|
||||||
|
|
||||||
export async function fetchFeedbacks(status = '') {
|
export async function fetchFeedbacks(status = '') {
|
||||||
const { data } = await api.get('/feedbacks', { params: status ? { status } : {} })
|
const { data } = await api.get('/feedbacks', { params: status ? { status } : {} })
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchFeedbackStats() {
|
export async function fetchFeedbackStats(options = {}) {
|
||||||
if (_feedbackStatsInflight) return _feedbackStatsInflight
|
return feedbackStatsGetter.run(options)
|
||||||
|
}
|
||||||
|
|
||||||
_feedbackStatsInflight = api
|
export function clearFeedbackStatsCache() {
|
||||||
.get('/feedbacks', { params: { limit: 1, offset: 0 } })
|
feedbackStatsGetter.clear()
|
||||||
.then(({ data }) => data?.stats)
|
|
||||||
.finally(() => {
|
|
||||||
_feedbackStatsInflight = null
|
|
||||||
})
|
|
||||||
|
|
||||||
return _feedbackStatsInflight
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function replyFeedback(feedbackId, reply) {
|
export async function replyFeedback(feedbackId, reply) {
|
||||||
const { data } = await api.post(`/feedbacks/${feedbackId}/reply`, { reply })
|
const { data } = await api.post(`/feedbacks/${feedbackId}/reply`, { reply })
|
||||||
|
clearFeedbackStatsCache()
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function closeFeedback(feedbackId) {
|
export async function closeFeedback(feedbackId) {
|
||||||
const { data } = await api.post(`/feedbacks/${feedbackId}/close`)
|
const { data } = await api.post(`/feedbacks/${feedbackId}/close`)
|
||||||
|
clearFeedbackStatsCache()
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteFeedback(feedbackId) {
|
export async function deleteFeedback(feedbackId) {
|
||||||
const { data } = await api.delete(`/feedbacks/${feedbackId}`)
|
const { data } = await api.delete(`/feedbacks/${feedbackId}`)
|
||||||
|
clearFeedbackStatsCache()
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,42 +1,17 @@
|
|||||||
import { api } from './client'
|
import { api } from './client'
|
||||||
|
import { createCachedGetter } from './cache'
|
||||||
|
|
||||||
const _statsCache = {
|
const SYSTEM_STATS_TTL_MS = 15_000
|
||||||
value: null,
|
|
||||||
expiresAt: 0,
|
|
||||||
inflight: null,
|
|
||||||
}
|
|
||||||
|
|
||||||
const SYSTEM_STATS_TTL_MS = 2000
|
const systemStatsGetter = createCachedGetter(async () => {
|
||||||
|
const { data } = await api.get('/stats')
|
||||||
|
return data
|
||||||
|
}, SYSTEM_STATS_TTL_MS)
|
||||||
|
|
||||||
export async function fetchSystemStats(options = {}) {
|
export async function fetchSystemStats(options = {}) {
|
||||||
const force = Boolean(options?.force)
|
return systemStatsGetter.run(options)
|
||||||
const now = Date.now()
|
|
||||||
|
|
||||||
if (!force && _statsCache.value && now < _statsCache.expiresAt) {
|
|
||||||
return _statsCache.value
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!force && _statsCache.inflight) {
|
|
||||||
return _statsCache.inflight
|
|
||||||
}
|
|
||||||
|
|
||||||
const request = api
|
|
||||||
.get('/stats')
|
|
||||||
.then(({ data }) => {
|
|
||||||
_statsCache.value = data
|
|
||||||
_statsCache.expiresAt = Date.now() + SYSTEM_STATS_TTL_MS
|
|
||||||
return data
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
_statsCache.inflight = null
|
|
||||||
})
|
|
||||||
|
|
||||||
_statsCache.inflight = request
|
|
||||||
return request
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clearSystemStatsCache() {
|
export function clearSystemStatsCache() {
|
||||||
_statsCache.value = null
|
systemStatsGetter.clear()
|
||||||
_statsCache.expiresAt = 0
|
|
||||||
_statsCache.inflight = null
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
import { api } from './client'
|
import { api } from './client'
|
||||||
|
import { createCachedGetter } from './cache'
|
||||||
|
|
||||||
export async function fetchSystemConfig() {
|
const systemConfigGetter = createCachedGetter(async () => {
|
||||||
const { data } = await api.get('/system/config')
|
const { data } = await api.get('/system/config')
|
||||||
return data
|
return data
|
||||||
|
}, 15_000)
|
||||||
|
|
||||||
|
export async function fetchSystemConfig(options = {}) {
|
||||||
|
return systemConfigGetter.run(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateSystemConfig(payload) {
|
export async function updateSystemConfig(payload) {
|
||||||
const { data } = await api.post('/system/config', payload)
|
const { data } = await api.post('/system/config', payload)
|
||||||
|
systemConfigGetter.clear()
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -14,4 +20,3 @@ export async function executeScheduleNow() {
|
|||||||
const { data } = await api.post('/schedule/execute', {})
|
const { data } = await api.post('/schedule/execute', {})
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,33 +1,58 @@
|
|||||||
import { api } from './client'
|
import { api } from './client'
|
||||||
|
import { createCachedGetter } from './cache'
|
||||||
|
|
||||||
export async function fetchServerInfo() {
|
const serverInfoGetter = createCachedGetter(async () => {
|
||||||
const { data } = await api.get('/server/info')
|
const { data } = await api.get('/server/info')
|
||||||
return data
|
return data
|
||||||
}
|
}, 30_000)
|
||||||
|
|
||||||
export async function fetchDockerStats() {
|
const dockerStatsGetter = createCachedGetter(async () => {
|
||||||
const { data } = await api.get('/docker_stats')
|
const { data } = await api.get('/docker_stats')
|
||||||
return data
|
return data
|
||||||
}
|
}, 8_000)
|
||||||
|
|
||||||
export async function fetchRequestMetrics() {
|
const requestMetricsGetter = createCachedGetter(async () => {
|
||||||
const { data } = await api.get('/request_metrics')
|
const { data } = await api.get('/request_metrics')
|
||||||
return data
|
return data
|
||||||
}
|
}, 10_000)
|
||||||
|
|
||||||
export async function fetchSlowSqlMetrics() {
|
const slowSqlMetricsGetter = createCachedGetter(async () => {
|
||||||
const { data } = await api.get('/slow_sql_metrics')
|
const { data } = await api.get('/slow_sql_metrics')
|
||||||
return data
|
return data
|
||||||
}
|
}, 10_000)
|
||||||
|
|
||||||
export async function fetchTaskStats() {
|
const taskStatsGetter = createCachedGetter(async () => {
|
||||||
const { data } = await api.get('/task/stats')
|
const { data } = await api.get('/task/stats')
|
||||||
return data
|
return data
|
||||||
}
|
}, 4_000)
|
||||||
|
|
||||||
export async function fetchRunningTasks() {
|
const runningTasksGetter = createCachedGetter(async () => {
|
||||||
const { data } = await api.get('/task/running')
|
const { data } = await api.get('/task/running')
|
||||||
return data
|
return data
|
||||||
|
}, 2_000)
|
||||||
|
|
||||||
|
export async function fetchServerInfo(options = {}) {
|
||||||
|
return serverInfoGetter.run(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchDockerStats(options = {}) {
|
||||||
|
return dockerStatsGetter.run(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchRequestMetrics(options = {}) {
|
||||||
|
return requestMetricsGetter.run(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchSlowSqlMetrics(options = {}) {
|
||||||
|
return slowSqlMetricsGetter.run(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchTaskStats(options = {}) {
|
||||||
|
return taskStatsGetter.run(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchRunningTasks(options = {}) {
|
||||||
|
return runningTasksGetter.run(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchTaskLogs(params) {
|
export async function fetchTaskLogs(params) {
|
||||||
@@ -37,5 +62,7 @@ export async function fetchTaskLogs(params) {
|
|||||||
|
|
||||||
export async function clearOldTaskLogs(days) {
|
export async function clearOldTaskLogs(days) {
|
||||||
const { data } = await api.post('/task/logs/clear', { days })
|
const { data } = await api.post('/task/logs/clear', { days })
|
||||||
|
taskStatsGetter.clear()
|
||||||
|
runningTasksGetter.clear()
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,11 +25,8 @@ const stats = ref({})
|
|||||||
|
|
||||||
const adminUsername = computed(() => stats.value?.admin_username || '')
|
const adminUsername = computed(() => stats.value?.admin_username || '')
|
||||||
|
|
||||||
async function refreshStats() {
|
async function refreshStats(options = {}) {
|
||||||
try {
|
stats.value = await fetchSystemStats(options)
|
||||||
stats.value = await fetchSystemStats()
|
|
||||||
} finally {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadingBadges = ref(false)
|
const loadingBadges = ref(false)
|
||||||
|
|||||||
@@ -550,9 +550,17 @@ const mobileModules = computed(() => [
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const REPORT_SYNC_STATS_EVERY = 3
|
||||||
|
let reportRefreshTick = 0
|
||||||
|
|
||||||
async function refreshAll(options = {}) {
|
async function refreshAll(options = {}) {
|
||||||
const showLoading = options.showLoading ?? true
|
const showLoading = options.showLoading ?? true
|
||||||
if (refreshing.value) return
|
if (refreshing.value) return
|
||||||
|
|
||||||
|
const forceStatsSync = Boolean(options.forceStatsSync)
|
||||||
|
const shouldSyncStats = forceStatsSync || reportRefreshTick % REPORT_SYNC_STATS_EVERY === 0
|
||||||
|
reportRefreshTick += 1
|
||||||
|
|
||||||
refreshing.value = true
|
refreshing.value = true
|
||||||
if (showLoading) {
|
if (showLoading) {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
@@ -593,7 +601,9 @@ async function refreshAll(options = {}) {
|
|||||||
if (slowSqlResult.status === 'fulfilled') slowSqlMetrics.value = slowSqlResult.value
|
if (slowSqlResult.status === 'fulfilled') slowSqlMetrics.value = slowSqlResult.value
|
||||||
if (configResult.status === 'fulfilled') systemConfig.value = configResult.value
|
if (configResult.status === 'fulfilled') systemConfig.value = configResult.value
|
||||||
|
|
||||||
await refreshStats?.()
|
if (shouldSyncStats) {
|
||||||
|
await refreshStats?.({ force: forceStatsSync })
|
||||||
|
}
|
||||||
recordUpdatedAt()
|
recordUpdatedAt()
|
||||||
} finally {
|
} finally {
|
||||||
refreshing.value = false
|
refreshing.value = false
|
||||||
@@ -637,7 +647,7 @@ function onVisibilityChange() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
refreshAll({ showLoading: false })
|
refreshAll({ showLoading: false, forceStatsSync: true })
|
||||||
.catch(() => {})
|
.catch(() => {})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
scheduleRefreshLoop()
|
scheduleRefreshLoop()
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ async function onEnableUser(row) {
|
|||||||
await approveUser(row.id)
|
await approveUser(row.id)
|
||||||
ElMessage.success('用户已启用')
|
ElMessage.success('用户已启用')
|
||||||
await loadUsers()
|
await loadUsers()
|
||||||
await refreshStats?.()
|
await refreshStats?.({ force: true })
|
||||||
} catch {
|
} catch {
|
||||||
// handled by interceptor
|
// handled by interceptor
|
||||||
}
|
}
|
||||||
@@ -93,7 +93,7 @@ async function onDisableUser(row) {
|
|||||||
await rejectUser(row.id)
|
await rejectUser(row.id)
|
||||||
ElMessage.success('用户已禁用')
|
ElMessage.success('用户已禁用')
|
||||||
await loadUsers()
|
await loadUsers()
|
||||||
await refreshStats?.()
|
await refreshStats?.({ force: true })
|
||||||
} catch {
|
} catch {
|
||||||
// handled by interceptor
|
// handled by interceptor
|
||||||
}
|
}
|
||||||
@@ -114,7 +114,7 @@ async function onDelete(row) {
|
|||||||
await deleteUser(row.id)
|
await deleteUser(row.id)
|
||||||
ElMessage.success('用户已删除')
|
ElMessage.success('用户已删除')
|
||||||
await loadUsers()
|
await loadUsers()
|
||||||
await refreshStats?.()
|
await refreshStats?.({ force: true })
|
||||||
} catch {
|
} catch {
|
||||||
// handled by interceptor
|
// handled by interceptor
|
||||||
}
|
}
|
||||||
@@ -136,7 +136,7 @@ async function onSetVip(row, days) {
|
|||||||
const res = await setUserVip(row.id, days)
|
const res = await setUserVip(row.id, days)
|
||||||
ElMessage.success(res?.message || 'VIP设置成功')
|
ElMessage.success(res?.message || 'VIP设置成功')
|
||||||
await loadUsers()
|
await loadUsers()
|
||||||
await refreshStats?.()
|
await refreshStats?.({ force: true })
|
||||||
} catch {
|
} catch {
|
||||||
// handled by interceptor
|
// handled by interceptor
|
||||||
}
|
}
|
||||||
@@ -157,7 +157,7 @@ async function onRemoveVip(row) {
|
|||||||
const res = await removeUserVip(row.id)
|
const res = await removeUserVip(row.id)
|
||||||
ElMessage.success(res?.message || 'VIP已移除')
|
ElMessage.success(res?.message || 'VIP已移除')
|
||||||
await loadUsers()
|
await loadUsers()
|
||||||
await refreshStats?.()
|
await refreshStats?.({ force: true })
|
||||||
} catch {
|
} catch {
|
||||||
// handled by interceptor
|
// handled by interceptor
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_MetricGrid-Df-Dlkt_.js": {
|
"_MetricGrid-CQMxT_6S.js": {
|
||||||
"file": "assets/MetricGrid-Df-Dlkt_.js",
|
"file": "assets/MetricGrid-CQMxT_6S.js",
|
||||||
"name": "MetricGrid",
|
"name": "MetricGrid",
|
||||||
"imports": [
|
"imports": [
|
||||||
"index.html",
|
"index.html",
|
||||||
@@ -14,29 +14,29 @@
|
|||||||
"file": "assets/MetricGrid-yP_dkP6X.css",
|
"file": "assets/MetricGrid-yP_dkP6X.css",
|
||||||
"src": "_MetricGrid-yP_dkP6X.css"
|
"src": "_MetricGrid-yP_dkP6X.css"
|
||||||
},
|
},
|
||||||
"_email-DaWcU8Ml.js": {
|
"_email-DM9tsUhu.js": {
|
||||||
"file": "assets/email-DaWcU8Ml.js",
|
"file": "assets/email-DM9tsUhu.js",
|
||||||
"name": "email",
|
"name": "email",
|
||||||
"imports": [
|
"imports": [
|
||||||
"index.html"
|
"index.html"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"_system-EPeBJB57.js": {
|
"_system--AYWXDUu.js": {
|
||||||
"file": "assets/system-EPeBJB57.js",
|
"file": "assets/system--AYWXDUu.js",
|
||||||
"name": "system",
|
"name": "system",
|
||||||
"imports": [
|
"imports": [
|
||||||
"index.html"
|
"index.html"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"_tasks-suSBBmw0.js": {
|
"_tasks-CF7lDSM6.js": {
|
||||||
"file": "assets/tasks-suSBBmw0.js",
|
"file": "assets/tasks-CF7lDSM6.js",
|
||||||
"name": "tasks",
|
"name": "tasks",
|
||||||
"imports": [
|
"imports": [
|
||||||
"index.html"
|
"index.html"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"_users-D8nCLsxD.js": {
|
"_users-BPRr-UQM.js": {
|
||||||
"file": "assets/users-D8nCLsxD.js",
|
"file": "assets/users-BPRr-UQM.js",
|
||||||
"name": "users",
|
"name": "users",
|
||||||
"imports": [
|
"imports": [
|
||||||
"index.html"
|
"index.html"
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
"name": "vendor-vue"
|
"name": "vendor-vue"
|
||||||
},
|
},
|
||||||
"index.html": {
|
"index.html": {
|
||||||
"file": "assets/index-BhQdNLJb.js",
|
"file": "assets/index-hdJlGZAd.js",
|
||||||
"name": "index",
|
"name": "index",
|
||||||
"src": "index.html",
|
"src": "index.html",
|
||||||
"isEntry": true,
|
"isEntry": true,
|
||||||
@@ -95,11 +95,11 @@
|
|||||||
"src/pages/SettingsPage.vue"
|
"src/pages/SettingsPage.vue"
|
||||||
],
|
],
|
||||||
"css": [
|
"css": [
|
||||||
"assets/index-a3a11Ghn.css"
|
"assets/index-BL6_OP4l.css"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/pages/AnnouncementsPage.vue": {
|
"src/pages/AnnouncementsPage.vue": {
|
||||||
"file": "assets/AnnouncementsPage-Bt9ScJoU.js",
|
"file": "assets/AnnouncementsPage-B9Z0w4LW.js",
|
||||||
"name": "AnnouncementsPage",
|
"name": "AnnouncementsPage",
|
||||||
"src": "src/pages/AnnouncementsPage.vue",
|
"src": "src/pages/AnnouncementsPage.vue",
|
||||||
"isDynamicEntry": true,
|
"isDynamicEntry": true,
|
||||||
@@ -115,14 +115,14 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/pages/EmailPage.vue": {
|
"src/pages/EmailPage.vue": {
|
||||||
"file": "assets/EmailPage-lCqi22rV.js",
|
"file": "assets/EmailPage-CQW4R2Zg.js",
|
||||||
"name": "EmailPage",
|
"name": "EmailPage",
|
||||||
"src": "src/pages/EmailPage.vue",
|
"src": "src/pages/EmailPage.vue",
|
||||||
"isDynamicEntry": true,
|
"isDynamicEntry": true,
|
||||||
"imports": [
|
"imports": [
|
||||||
"_email-DaWcU8Ml.js",
|
"_email-DM9tsUhu.js",
|
||||||
"index.html",
|
"index.html",
|
||||||
"_MetricGrid-Df-Dlkt_.js",
|
"_MetricGrid-CQMxT_6S.js",
|
||||||
"_vendor-element-B5S5pUKo.js",
|
"_vendor-element-B5S5pUKo.js",
|
||||||
"_vendor-vue-CVxSw_oJ.js",
|
"_vendor-vue-CVxSw_oJ.js",
|
||||||
"_vendor-axios-B9ygI19o.js",
|
"_vendor-axios-B9ygI19o.js",
|
||||||
@@ -133,13 +133,13 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/pages/FeedbacksPage.vue": {
|
"src/pages/FeedbacksPage.vue": {
|
||||||
"file": "assets/FeedbacksPage-Bm8Gi6uF.js",
|
"file": "assets/FeedbacksPage-CZ0Batl6.js",
|
||||||
"name": "FeedbacksPage",
|
"name": "FeedbacksPage",
|
||||||
"src": "src/pages/FeedbacksPage.vue",
|
"src": "src/pages/FeedbacksPage.vue",
|
||||||
"isDynamicEntry": true,
|
"isDynamicEntry": true,
|
||||||
"imports": [
|
"imports": [
|
||||||
"index.html",
|
"index.html",
|
||||||
"_MetricGrid-Df-Dlkt_.js",
|
"_MetricGrid-CQMxT_6S.js",
|
||||||
"_vendor-element-B5S5pUKo.js",
|
"_vendor-element-B5S5pUKo.js",
|
||||||
"_vendor-vue-CVxSw_oJ.js",
|
"_vendor-vue-CVxSw_oJ.js",
|
||||||
"_vendor-axios-B9ygI19o.js",
|
"_vendor-axios-B9ygI19o.js",
|
||||||
@@ -150,13 +150,13 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/pages/LogsPage.vue": {
|
"src/pages/LogsPage.vue": {
|
||||||
"file": "assets/LogsPage-BXJhmaAD.js",
|
"file": "assets/LogsPage-C_83A2F1.js",
|
||||||
"name": "LogsPage",
|
"name": "LogsPage",
|
||||||
"src": "src/pages/LogsPage.vue",
|
"src": "src/pages/LogsPage.vue",
|
||||||
"isDynamicEntry": true,
|
"isDynamicEntry": true,
|
||||||
"imports": [
|
"imports": [
|
||||||
"_users-D8nCLsxD.js",
|
"_users-BPRr-UQM.js",
|
||||||
"_tasks-suSBBmw0.js",
|
"_tasks-CF7lDSM6.js",
|
||||||
"index.html",
|
"index.html",
|
||||||
"_vendor-element-B5S5pUKo.js",
|
"_vendor-element-B5S5pUKo.js",
|
||||||
"_vendor-vue-CVxSw_oJ.js",
|
"_vendor-vue-CVxSw_oJ.js",
|
||||||
@@ -168,33 +168,33 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/pages/ReportPage.vue": {
|
"src/pages/ReportPage.vue": {
|
||||||
"file": "assets/ReportPage-BH0iEKUw.js",
|
"file": "assets/ReportPage-C1fr4baB.js",
|
||||||
"name": "ReportPage",
|
"name": "ReportPage",
|
||||||
"src": "src/pages/ReportPage.vue",
|
"src": "src/pages/ReportPage.vue",
|
||||||
"isDynamicEntry": true,
|
"isDynamicEntry": true,
|
||||||
"imports": [
|
"imports": [
|
||||||
"_vendor-element-B5S5pUKo.js",
|
"_vendor-element-B5S5pUKo.js",
|
||||||
"index.html",
|
"index.html",
|
||||||
"_email-DaWcU8Ml.js",
|
"_email-DM9tsUhu.js",
|
||||||
"_tasks-suSBBmw0.js",
|
"_tasks-CF7lDSM6.js",
|
||||||
"_system-EPeBJB57.js",
|
"_system--AYWXDUu.js",
|
||||||
"_MetricGrid-Df-Dlkt_.js",
|
"_MetricGrid-CQMxT_6S.js",
|
||||||
"_vendor-vue-CVxSw_oJ.js",
|
"_vendor-vue-CVxSw_oJ.js",
|
||||||
"_vendor-misc-BeoNyvBp.js",
|
"_vendor-misc-BeoNyvBp.js",
|
||||||
"_vendor-axios-B9ygI19o.js"
|
"_vendor-axios-B9ygI19o.js"
|
||||||
],
|
],
|
||||||
"css": [
|
"css": [
|
||||||
"assets/ReportPage-DN5YlEZa.css"
|
"assets/ReportPage-CP2k7xMv.css"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/pages/SecurityPage.vue": {
|
"src/pages/SecurityPage.vue": {
|
||||||
"file": "assets/SecurityPage-BINdqm-Z.js",
|
"file": "assets/SecurityPage-wDdBM6Ga.js",
|
||||||
"name": "SecurityPage",
|
"name": "SecurityPage",
|
||||||
"src": "src/pages/SecurityPage.vue",
|
"src": "src/pages/SecurityPage.vue",
|
||||||
"isDynamicEntry": true,
|
"isDynamicEntry": true,
|
||||||
"imports": [
|
"imports": [
|
||||||
"index.html",
|
"index.html",
|
||||||
"_MetricGrid-Df-Dlkt_.js",
|
"_MetricGrid-CQMxT_6S.js",
|
||||||
"_vendor-element-B5S5pUKo.js",
|
"_vendor-element-B5S5pUKo.js",
|
||||||
"_vendor-vue-CVxSw_oJ.js",
|
"_vendor-vue-CVxSw_oJ.js",
|
||||||
"_vendor-axios-B9ygI19o.js",
|
"_vendor-axios-B9ygI19o.js",
|
||||||
@@ -205,7 +205,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/pages/SettingsPage.vue": {
|
"src/pages/SettingsPage.vue": {
|
||||||
"file": "assets/SettingsPage-Bb497CTW.js",
|
"file": "assets/SettingsPage-eG6RsmTz.js",
|
||||||
"name": "SettingsPage",
|
"name": "SettingsPage",
|
||||||
"src": "src/pages/SettingsPage.vue",
|
"src": "src/pages/SettingsPage.vue",
|
||||||
"isDynamicEntry": true,
|
"isDynamicEntry": true,
|
||||||
@@ -221,12 +221,12 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/pages/SystemPage.vue": {
|
"src/pages/SystemPage.vue": {
|
||||||
"file": "assets/SystemPage-BOHCIy1Q.js",
|
"file": "assets/SystemPage-C_DDxErs.js",
|
||||||
"name": "SystemPage",
|
"name": "SystemPage",
|
||||||
"src": "src/pages/SystemPage.vue",
|
"src": "src/pages/SystemPage.vue",
|
||||||
"isDynamicEntry": true,
|
"isDynamicEntry": true,
|
||||||
"imports": [
|
"imports": [
|
||||||
"_system-EPeBJB57.js",
|
"_system--AYWXDUu.js",
|
||||||
"index.html",
|
"index.html",
|
||||||
"_vendor-element-B5S5pUKo.js",
|
"_vendor-element-B5S5pUKo.js",
|
||||||
"_vendor-vue-CVxSw_oJ.js",
|
"_vendor-vue-CVxSw_oJ.js",
|
||||||
@@ -238,12 +238,12 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/pages/UsersPage.vue": {
|
"src/pages/UsersPage.vue": {
|
||||||
"file": "assets/UsersPage-70roiEdR.js",
|
"file": "assets/UsersPage-DVi3Wmss.js",
|
||||||
"name": "UsersPage",
|
"name": "UsersPage",
|
||||||
"src": "src/pages/UsersPage.vue",
|
"src": "src/pages/UsersPage.vue",
|
||||||
"isDynamicEntry": true,
|
"isDynamicEntry": true,
|
||||||
"imports": [
|
"imports": [
|
||||||
"_users-D8nCLsxD.js",
|
"_users-BPRr-UQM.js",
|
||||||
"index.html",
|
"index.html",
|
||||||
"_vendor-element-B5S5pUKo.js",
|
"_vendor-element-B5S5pUKo.js",
|
||||||
"_vendor-vue-CVxSw_oJ.js",
|
"_vendor-vue-CVxSw_oJ.js",
|
||||||
@@ -251,7 +251,7 @@
|
|||||||
"_vendor-misc-BeoNyvBp.js"
|
"_vendor-misc-BeoNyvBp.js"
|
||||||
],
|
],
|
||||||
"css": [
|
"css": [
|
||||||
"assets/UsersPage-Cow_LicY.css"
|
"assets/UsersPage-BNDnhJe0.css"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
|||||||
import{_}from"./index-BhQdNLJb.js";import{aj as c,n as s,q as t,K as r,a3 as u,y as p,t as o,G as l,L as y,E as h,D as i,H as v,J as n,I as k,x as f}from"./vendor-vue-CVxSw_oJ.js";const b={class:"metric-top"},x={key:0,class:"metric-icon"},g={class:"metric-label"},B={class:"metric-value"},C={key:0,class:"metric-hint app-muted"},N={__name:"MetricGrid",props:{items:{type:Array,default:()=>[]},loading:{type:Boolean,default:!1},minWidth:{type:Number,default:180}},setup(a){return(V,D)=>{const d=c("el-icon"),m=c("el-skeleton");return t(),s("div",{class:"metric-grid",style:f({"--metric-min":`${a.minWidth}px`})},[(t(!0),s(r,null,u(a.items,e=>(t(),s("div",{key:e?.key||e?.label,class:p(["metric-card",`metric-tone--${e?.tone||"blue"}`])},[o("div",b,[e?.icon?(t(),s("div",x,[y(d,null,{default:h(()=>[(t(),i(v(e.icon)))]),_:2},1024)])):l("",!0),o("div",g,n(e?.label||"-"),1)]),o("div",B,[a.loading?(t(),i(m,{key:0,rows:1,animated:""})):(t(),s(r,{key:1},[k(n(e?.value??0),1)],64))]),e?.hint||e?.sub?(t(),s("div",C,n(e?.hint||e?.sub),1)):l("",!0)],2))),128))],4)}}},w=_(N,[["__scopeId","data-v-00e217d4"]]);export{w as M};
|
import{_}from"./index-hdJlGZAd.js";import{aj as c,n as s,q as t,K as r,a3 as u,y as p,t as o,G as l,L as y,E as h,D as i,H as v,J as n,I as k,x as f}from"./vendor-vue-CVxSw_oJ.js";const b={class:"metric-top"},x={key:0,class:"metric-icon"},g={class:"metric-label"},B={class:"metric-value"},C={key:0,class:"metric-hint app-muted"},N={__name:"MetricGrid",props:{items:{type:Array,default:()=>[]},loading:{type:Boolean,default:!1},minWidth:{type:Number,default:180}},setup(a){return(V,D)=>{const d=c("el-icon"),m=c("el-skeleton");return t(),s("div",{class:"metric-grid",style:f({"--metric-min":`${a.minWidth}px`})},[(t(!0),s(r,null,u(a.items,e=>(t(),s("div",{key:e?.key||e?.label,class:p(["metric-card",`metric-tone--${e?.tone||"blue"}`])},[o("div",b,[e?.icon?(t(),s("div",x,[y(d,null,{default:h(()=>[(t(),i(v(e.icon)))]),_:2},1024)])):l("",!0),o("div",g,n(e?.label||"-"),1)]),o("div",B,[a.loading?(t(),i(m,{key:0,rows:1,animated:""})):(t(),s(r,{key:1},[k(n(e?.value??0),1)],64))]),e?.hint||e?.sub?(t(),s("div",C,n(e?.hint||e?.sub),1)):l("",!0)],2))),128))],4)}}},w=_(N,[["__scopeId","data-v-00e217d4"]]);export{w as M};
|
||||||
File diff suppressed because one or more lines are too long
1
static/admin/assets/ReportPage-C1fr4baB.js
Normal file
1
static/admin/assets/ReportPage-C1fr4baB.js
Normal file
File diff suppressed because one or more lines are too long
1
static/admin/assets/ReportPage-CP2k7xMv.css
Normal file
1
static/admin/assets/ReportPage-CP2k7xMv.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
|||||||
import{a as m,_ as h}from"./index-BhQdNLJb.js";import{a as u,E as x}from"./vendor-element-B5S5pUKo.js";import{r as p,aj as i,n as T,q as E,t as r,L as a,E as o,I as b}from"./vendor-vue-CVxSw_oJ.js";import"./vendor-axios-B9ygI19o.js";import"./vendor-misc-BeoNyvBp.js";async function P(l){const{data:s}=await m.put("/admin/username",{new_username:l});return s}async function C(l){const{data:s}=await m.put("/admin/password",{new_password:l});return s}async function S(){const{data:l}=await m.post("/logout");return l}const U={class:"page-stack"},A={__name:"SettingsPage",setup(l){const s=p(""),d=p(""),n=p(!1);function k(t){const e=String(t||"");return e.length<8?{ok:!1,message:"密码长度至少8位"}:e.length>128?{ok:!1,message:"密码长度不能超过128个字符"}:!/[a-zA-Z]/.test(e)||!/\d/.test(e)?{ok:!1,message:"密码必须包含字母和数字"}:{ok:!0,message:""}}async function f(){try{await S()}catch{}finally{window.location.href="/yuyx"}}async function V(){const t=s.value.trim();if(!t){u.error("请输入新用户名");return}try{await x.confirm(`确定将管理员用户名修改为「${t}」吗?修改后需要重新登录。`,"修改用户名",{confirmButtonText:"确认修改",cancelButtonText:"取消",type:"warning"})}catch{return}n.value=!0;try{await P(t),u.success("用户名修改成功,请重新登录"),s.value="",setTimeout(f,1200)}catch{}finally{n.value=!1}}async function B(){const t=d.value;if(!t){u.error("请输入新密码");return}const e=k(t);if(!e.ok){u.error(e.message);return}try{await x.confirm("确定修改管理员密码吗?修改后需要重新登录。","修改密码",{confirmButtonText:"确认修改",cancelButtonText:"取消",type:"warning"})}catch{return}n.value=!0;try{await C(t),u.success("密码修改成功,请重新登录"),d.value="",setTimeout(f,1200)}catch{}finally{n.value=!1}}return(t,e)=>{const g=i("el-input"),v=i("el-form-item"),w=i("el-form"),y=i("el-button"),_=i("el-card");return E(),T("div",U,[e[7]||(e[7]=r("div",{class:"app-page-title"},[r("h2",null,"设置"),r("span",{class:"app-muted"},"管理员账号设置")],-1)),a(_,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:o(()=>[e[3]||(e[3]=r("h3",{class:"section-title"},"修改管理员用户名",-1)),a(w,{"label-width":"120px"},{default:o(()=>[a(v,{label:"新用户名"},{default:o(()=>[a(g,{modelValue:s.value,"onUpdate:modelValue":e[0]||(e[0]=c=>s.value=c),placeholder:"输入新用户名",disabled:n.value},null,8,["modelValue","disabled"])]),_:1})]),_:1}),a(y,{type:"primary",loading:n.value,onClick:V},{default:o(()=>[...e[2]||(e[2]=[b("保存用户名",-1)])]),_:1},8,["loading"])]),_:1}),a(_,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:o(()=>[e[5]||(e[5]=r("h3",{class:"section-title"},"修改管理员密码",-1)),a(w,{"label-width":"120px"},{default:o(()=>[a(v,{label:"新密码"},{default:o(()=>[a(g,{modelValue:d.value,"onUpdate:modelValue":e[1]||(e[1]=c=>d.value=c),type:"password","show-password":"",placeholder:"输入新密码",disabled:n.value},null,8,["modelValue","disabled"])]),_:1})]),_:1}),a(y,{type:"primary",loading:n.value,onClick:B},{default:o(()=>[...e[4]||(e[4]=[b("保存密码",-1)])]),_:1},8,["loading"]),e[6]||(e[6]=r("div",{class:"help"},"建议使用更强密码(至少8位且包含字母与数字)。",-1))]),_:1})])}}},z=h(A,[["__scopeId","data-v-83d3840a"]]);export{z as default};
|
import{a as m,_ as h}from"./index-hdJlGZAd.js";import{a as u,E as x}from"./vendor-element-B5S5pUKo.js";import{r as p,aj as i,n as T,q as E,t as r,L as a,E as o,I as b}from"./vendor-vue-CVxSw_oJ.js";import"./vendor-axios-B9ygI19o.js";import"./vendor-misc-BeoNyvBp.js";async function P(l){const{data:s}=await m.put("/admin/username",{new_username:l});return s}async function C(l){const{data:s}=await m.put("/admin/password",{new_password:l});return s}async function S(){const{data:l}=await m.post("/logout");return l}const U={class:"page-stack"},A={__name:"SettingsPage",setup(l){const s=p(""),d=p(""),n=p(!1);function k(t){const e=String(t||"");return e.length<8?{ok:!1,message:"密码长度至少8位"}:e.length>128?{ok:!1,message:"密码长度不能超过128个字符"}:!/[a-zA-Z]/.test(e)||!/\d/.test(e)?{ok:!1,message:"密码必须包含字母和数字"}:{ok:!0,message:""}}async function f(){try{await S()}catch{}finally{window.location.href="/yuyx"}}async function V(){const t=s.value.trim();if(!t){u.error("请输入新用户名");return}try{await x.confirm(`确定将管理员用户名修改为「${t}」吗?修改后需要重新登录。`,"修改用户名",{confirmButtonText:"确认修改",cancelButtonText:"取消",type:"warning"})}catch{return}n.value=!0;try{await P(t),u.success("用户名修改成功,请重新登录"),s.value="",setTimeout(f,1200)}catch{}finally{n.value=!1}}async function B(){const t=d.value;if(!t){u.error("请输入新密码");return}const e=k(t);if(!e.ok){u.error(e.message);return}try{await x.confirm("确定修改管理员密码吗?修改后需要重新登录。","修改密码",{confirmButtonText:"确认修改",cancelButtonText:"取消",type:"warning"})}catch{return}n.value=!0;try{await C(t),u.success("密码修改成功,请重新登录"),d.value="",setTimeout(f,1200)}catch{}finally{n.value=!1}}return(t,e)=>{const g=i("el-input"),v=i("el-form-item"),w=i("el-form"),y=i("el-button"),_=i("el-card");return E(),T("div",U,[e[7]||(e[7]=r("div",{class:"app-page-title"},[r("h2",null,"设置"),r("span",{class:"app-muted"},"管理员账号设置")],-1)),a(_,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:o(()=>[e[3]||(e[3]=r("h3",{class:"section-title"},"修改管理员用户名",-1)),a(w,{"label-width":"120px"},{default:o(()=>[a(v,{label:"新用户名"},{default:o(()=>[a(g,{modelValue:s.value,"onUpdate:modelValue":e[0]||(e[0]=c=>s.value=c),placeholder:"输入新用户名",disabled:n.value},null,8,["modelValue","disabled"])]),_:1})]),_:1}),a(y,{type:"primary",loading:n.value,onClick:V},{default:o(()=>[...e[2]||(e[2]=[b("保存用户名",-1)])]),_:1},8,["loading"])]),_:1}),a(_,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:o(()=>[e[5]||(e[5]=r("h3",{class:"section-title"},"修改管理员密码",-1)),a(w,{"label-width":"120px"},{default:o(()=>[a(v,{label:"新密码"},{default:o(()=>[a(g,{modelValue:d.value,"onUpdate:modelValue":e[1]||(e[1]=c=>d.value=c),type:"password","show-password":"",placeholder:"输入新密码",disabled:n.value},null,8,["modelValue","disabled"])]),_:1})]),_:1}),a(y,{type:"primary",loading:n.value,onClick:B},{default:o(()=>[...e[4]||(e[4]=[b("保存密码",-1)])]),_:1},8,["loading"]),e[6]||(e[6]=r("div",{class:"help"},"建议使用更强密码(至少8位且包含字母与数字)。",-1))]),_:1})])}}},z=h(A,[["__scopeId","data-v-83d3840a"]]);export{z as default};
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import{f as be,u as Z}from"./system-EPeBJB57.js";import{a as P,_ as ge}from"./index-BhQdNLJb.js";import{E as ue,a as m}from"./vendor-element-B5S5pUKo.js";import{r as n,c as ke,l as xe,R as we,o as Ue,aj as v,ap as Ce,F as Pe,q as V,n as b,t as s,L as l,E as t,I as g,G as ee,J as le}from"./vendor-vue-CVxSw_oJ.js";import"./vendor-axios-B9ygI19o.js";import"./vendor-misc-BeoNyvBp.js";async function ae(r={}){const{data:c}=await P.get("/kdocs/status",{params:r});return c}async function Se(r={}){const c={force:!0,...r},{data:k}=await P.post("/kdocs/qr",c);return k}async function Ie(){const{data:r}=await P.post("/kdocs/clear-login",{});return r}async function Ae(){const{data:r}=await P.get("/proxy/config");return r}async function Ne(r){const{data:c}=await P.post("/proxy/config",r);return c}async function De(r){const{data:c}=await P.post("/proxy/test",r);return c}const Ee={class:"page-stack"},Ke={class:"config-grid"},Le={class:"row-actions"},Qe={class:"row-actions"},qe={class:"row-actions"},Be={class:"section-head"},Te={class:"status-inline app-muted"},$e={key:0},Me={key:1},Re={key:2},Fe={class:"kdocs-inline"},He={class:"kdocs-range"},he={class:"row-actions"},ze={key:0,class:"help"},Ge={key:1,class:"help"},Oe={class:"kdocs-qr"},je=["src"],Je={__name:"SystemPage",setup(r){const c=n(!1),k=n(2),I=n(1),A=n(3),N=n(120),S=n(!1),f=n(""),D=n(3),E=n(!1),K=n(10),L=n(7),Q=n(!1),q=n(""),B=n(""),T=n(""),$=n(0),M=n("A"),R=n("D"),F=n(0),H=n(0),h=n(!1),z=n(""),p=n({}),x=n(!1),w=n(""),oe=n(!1),G=n(!1),U=n(!1),C=n(!1),O=n("");let j=null;const te=ke(()=>G.value||U.value||C.value);function i(a){if(!a){O.value="";return}const e=new Date().toLocaleTimeString("zh-CN",{hour12:!1});O.value=`${a} (${e})`}async function de(){c.value=!0;try{const[a,e,d]=await Promise.all([be(),Ae(),ae().catch(()=>({}))]);k.value=a.max_concurrent_global??2,I.value=a.max_concurrent_per_account??1,A.value=a.max_screenshot_concurrent??3,N.value=a.db_slow_query_ms??120,E.value=(a.auto_approve_enabled??0)===1,K.value=a.auto_approve_hourly_limit??10,L.value=a.auto_approve_vip_days??7,S.value=(e.proxy_enabled??0)===1,f.value=e.proxy_api_url||"",D.value=e.proxy_expire_minutes??3,Q.value=(a.kdocs_enabled??0)===1,q.value=a.kdocs_doc_url||"",B.value=a.kdocs_default_unit||"",T.value=a.kdocs_sheet_name||"",$.value=a.kdocs_sheet_index??0,M.value=(a.kdocs_unit_column||"A").toUpperCase(),R.value=(a.kdocs_image_column||"D").toUpperCase(),F.value=a.kdocs_row_start??0,H.value=a.kdocs_row_end??0,h.value=(a.kdocs_admin_notify_enabled??0)===1,z.value=a.kdocs_admin_notify_email||"",p.value=d||{}}catch{}finally{c.value=!1}}async function ie(){const a={max_concurrent_global:Number(k.value),max_concurrent_per_account:Number(I.value),max_screenshot_concurrent:Number(A.value),db_slow_query_ms:Number(N.value)};try{await ue.confirm(`确定更新并发配置吗?
|
import{f as be,u as Z}from"./system--AYWXDUu.js";import{a as P,_ as ge}from"./index-hdJlGZAd.js";import{E as ue,a as m}from"./vendor-element-B5S5pUKo.js";import{r as n,c as ke,l as xe,R as we,o as Ue,aj as v,ap as Ce,F as Pe,q as V,n as b,t as s,L as l,E as t,I as g,G as ee,J as le}from"./vendor-vue-CVxSw_oJ.js";import"./vendor-axios-B9ygI19o.js";import"./vendor-misc-BeoNyvBp.js";async function ae(r={}){const{data:c}=await P.get("/kdocs/status",{params:r});return c}async function Se(r={}){const c={force:!0,...r},{data:k}=await P.post("/kdocs/qr",c);return k}async function Ie(){const{data:r}=await P.post("/kdocs/clear-login",{});return r}async function Ae(){const{data:r}=await P.get("/proxy/config");return r}async function Ne(r){const{data:c}=await P.post("/proxy/config",r);return c}async function De(r){const{data:c}=await P.post("/proxy/test",r);return c}const Ee={class:"page-stack"},Ke={class:"config-grid"},Le={class:"row-actions"},Qe={class:"row-actions"},qe={class:"row-actions"},Be={class:"section-head"},Te={class:"status-inline app-muted"},$e={key:0},Me={key:1},Re={key:2},Fe={class:"kdocs-inline"},He={class:"kdocs-range"},he={class:"row-actions"},ze={key:0,class:"help"},Ge={key:1,class:"help"},Oe={class:"kdocs-qr"},je=["src"],Je={__name:"SystemPage",setup(r){const c=n(!1),k=n(2),I=n(1),A=n(3),N=n(120),S=n(!1),f=n(""),D=n(3),E=n(!1),K=n(10),L=n(7),Q=n(!1),q=n(""),B=n(""),T=n(""),$=n(0),M=n("A"),R=n("D"),F=n(0),H=n(0),h=n(!1),z=n(""),p=n({}),x=n(!1),w=n(""),oe=n(!1),G=n(!1),U=n(!1),C=n(!1),O=n("");let j=null;const te=ke(()=>G.value||U.value||C.value);function i(a){if(!a){O.value="";return}const e=new Date().toLocaleTimeString("zh-CN",{hour12:!1});O.value=`${a} (${e})`}async function de(){c.value=!0;try{const[a,e,d]=await Promise.all([be(),Ae(),ae().catch(()=>({}))]);k.value=a.max_concurrent_global??2,I.value=a.max_concurrent_per_account??1,A.value=a.max_screenshot_concurrent??3,N.value=a.db_slow_query_ms??120,E.value=(a.auto_approve_enabled??0)===1,K.value=a.auto_approve_hourly_limit??10,L.value=a.auto_approve_vip_days??7,S.value=(e.proxy_enabled??0)===1,f.value=e.proxy_api_url||"",D.value=e.proxy_expire_minutes??3,Q.value=(a.kdocs_enabled??0)===1,q.value=a.kdocs_doc_url||"",B.value=a.kdocs_default_unit||"",T.value=a.kdocs_sheet_name||"",$.value=a.kdocs_sheet_index??0,M.value=(a.kdocs_unit_column||"A").toUpperCase(),R.value=(a.kdocs_image_column||"D").toUpperCase(),F.value=a.kdocs_row_start??0,H.value=a.kdocs_row_end??0,h.value=(a.kdocs_admin_notify_enabled??0)===1,z.value=a.kdocs_admin_notify_email||"",p.value=d||{}}catch{}finally{c.value=!1}}async function ie(){const a={max_concurrent_global:Number(k.value),max_concurrent_per_account:Number(I.value),max_screenshot_concurrent:Number(A.value),db_slow_query_ms:Number(N.value)};try{await ue.confirm(`确定更新并发配置吗?
|
||||||
|
|
||||||
全局并发数: ${a.max_concurrent_global}
|
全局并发数: ${a.max_concurrent_global}
|
||||||
单账号并发数: ${a.max_concurrent_per_account}
|
单账号并发数: ${a.max_concurrent_per_account}
|
||||||
File diff suppressed because one or more lines are too long
1
static/admin/assets/UsersPage-BNDnhJe0.css
Normal file
1
static/admin/assets/UsersPage-BNDnhJe0.css
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.page-stack[data-v-11f4f270]{display:flex;flex-direction:column;gap:14px;min-width:0}.card[data-v-11f4f270]{border-radius:var(--app-radius);border:1px solid var(--app-border);background:var(--app-card-bg);box-shadow:var(--app-shadow-soft)}.section-title[data-v-11f4f270]{margin:0 0 12px;font-size:15px;font-weight:800;letter-spacing:.2px}.help[data-v-11f4f270]{margin-top:10px;font-size:12px}.table-wrap[data-v-11f4f270]{overflow-x:auto;border-radius:10px;border:1px solid var(--app-border);background:#fff}.user-block[data-v-11f4f270]{display:flex;flex-direction:column;gap:2px}.user-main[data-v-11f4f270]{display:inline-flex;align-items:center;gap:8px;flex-wrap:wrap}.user-sub[data-v-11f4f270]{font-size:12px}.vip-sub[data-v-11f4f270]{font-size:12px;color:#7c3aed}.actions[data-v-11f4f270]{display:flex;flex-wrap:wrap;gap:8px}
|
||||||
@@ -1 +0,0 @@
|
|||||||
.page-stack[data-v-9e917879]{display:flex;flex-direction:column;gap:14px;min-width:0}.card[data-v-9e917879]{border-radius:var(--app-radius);border:1px solid var(--app-border);background:var(--app-card-bg);box-shadow:var(--app-shadow-soft)}.section-title[data-v-9e917879]{margin:0 0 12px;font-size:15px;font-weight:800;letter-spacing:.2px}.help[data-v-9e917879]{margin-top:10px;font-size:12px}.table-wrap[data-v-9e917879]{overflow-x:auto;border-radius:10px;border:1px solid var(--app-border);background:#fff}.user-block[data-v-9e917879]{display:flex;flex-direction:column;gap:2px}.user-main[data-v-9e917879]{display:inline-flex;align-items:center;gap:8px;flex-wrap:wrap}.user-sub[data-v-9e917879]{font-size:12px}.vip-sub[data-v-9e917879]{font-size:12px;color:#7c3aed}.actions[data-v-9e917879]{display:flex;flex-wrap:wrap;gap:8px}
|
|
||||||
1
static/admin/assets/UsersPage-DVi3Wmss.js
Normal file
1
static/admin/assets/UsersPage-DVi3Wmss.js
Normal file
File diff suppressed because one or more lines are too long
1
static/admin/assets/email-DM9tsUhu.js
Normal file
1
static/admin/assets/email-DM9tsUhu.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import{c as s,a as e}from"./index-hdJlGZAd.js";const n=s(async()=>{const{data:a}=await e.get("/email/stats");return a},1e4);async function i(){const{data:a}=await e.get("/email/settings");return a}async function r(a){const{data:t}=await e.post("/email/settings",a);return n.clear(),t}async function o(a={}){return n.run(a)}async function l(a){const{data:t}=await e.get("/email/logs",{params:a});return t}async function u(a){const{data:t}=await e.post("/email/logs/cleanup",{days:a});return n.clear(),t}export{l as a,i as b,u as c,o as f,r as u};
|
||||||
@@ -1 +0,0 @@
|
|||||||
import{a as n}from"./index-BhQdNLJb.js";async function i(){const{data:a}=await n.get("/email/settings");return a}async function e(a){const{data:t}=await n.post("/email/settings",a);return t}async function c(){const{data:a}=await n.get("/email/stats");return a}async function o(a){const{data:t}=await n.get("/email/logs",{params:a});return t}async function l(a){const{data:t}=await n.post("/email/logs/cleanup",{days:a});return t}export{o as a,i as b,l as c,c as f,e as u};
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
static/admin/assets/index-hdJlGZAd.js
Normal file
2
static/admin/assets/index-hdJlGZAd.js
Normal file
File diff suppressed because one or more lines are too long
1
static/admin/assets/system--AYWXDUu.js
Normal file
1
static/admin/assets/system--AYWXDUu.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import{c as s,a}from"./index-hdJlGZAd.js";const e=s(async()=>{const{data:t}=await a.get("/system/config");return t},15e3);async function o(t={}){return e.run(t)}async function r(t){const{data:n}=await a.post("/system/config",t);return e.clear(),n}export{o as f,r as u};
|
||||||
@@ -1 +0,0 @@
|
|||||||
import{a}from"./index-BhQdNLJb.js";async function o(){const{data:t}=await a.get("/system/config");return t}async function e(t){const{data:n}=await a.post("/system/config",t);return n}export{o as f,e as u};
|
|
||||||
1
static/admin/assets/tasks-CF7lDSM6.js
Normal file
1
static/admin/assets/tasks-CF7lDSM6.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import{c as s,a}from"./index-hdJlGZAd.js";const c=s(async()=>{const{data:t}=await a.get("/server/info");return t},3e4),o=s(async()=>{const{data:t}=await a.get("/docker_stats");return t},8e3),u=s(async()=>{const{data:t}=await a.get("/request_metrics");return t},1e4),i=s(async()=>{const{data:t}=await a.get("/slow_sql_metrics");return t},1e4),e=s(async()=>{const{data:t}=await a.get("/task/stats");return t},4e3),r=s(async()=>{const{data:t}=await a.get("/task/running");return t},2e3);async function g(t={}){return c.run(t)}async function y(t={}){return o.run(t)}async function d(t={}){return u.run(t)}async function k(t={}){return i.run(t)}async function l(t={}){return e.run(t)}async function w(t={}){return r.run(t)}async function _(t){const{data:n}=await a.get("/task/logs",{params:t});return n}async function h(t){const{data:n}=await a.post("/task/logs/clear",{days:t});return e.clear(),r.clear(),n}export{w as a,g as b,y as c,d,k as e,l as f,_ as g,h};
|
||||||
@@ -1 +0,0 @@
|
|||||||
import{a}from"./index-BhQdNLJb.js";async function c(){const{data:t}=await a.get("/server/info");return t}async function e(){const{data:t}=await a.get("/docker_stats");return t}async function r(){const{data:t}=await a.get("/request_metrics");return t}async function o(){const{data:t}=await a.get("/slow_sql_metrics");return t}async function i(){const{data:t}=await a.get("/task/stats");return t}async function u(){const{data:t}=await a.get("/task/running");return t}async function f(t){const{data:s}=await a.get("/task/logs",{params:t});return s}async function g(t){const{data:s}=await a.post("/task/logs/clear",{days:t});return s}export{u as a,c as b,e as c,r as d,o as e,i as f,f as g,g as h};
|
|
||||||
@@ -1 +1 @@
|
|||||||
import{a as t}from"./index-BhQdNLJb.js";async function n(){const{data:s}=await t.get("/users");return s}async function o(s){const{data:a}=await t.post(`/users/${s}/approve`);return a}async function c(s){const{data:a}=await t.post(`/users/${s}/reject`);return a}async function i(s){const{data:a}=await t.delete(`/users/${s}`);return a}async function u(s,a){const{data:e}=await t.post(`/users/${s}/vip`,{days:a});return e}async function p(s){const{data:a}=await t.delete(`/users/${s}/vip`);return a}async function d(s,a){const{data:e}=await t.post(`/users/${s}/reset_password`,{new_password:a});return e}export{o as a,p as b,d as c,i as d,n as f,c as r,u as s};
|
import{a as t}from"./index-hdJlGZAd.js";async function n(){const{data:s}=await t.get("/users");return s}async function o(s){const{data:a}=await t.post(`/users/${s}/approve`);return a}async function c(s){const{data:a}=await t.post(`/users/${s}/reject`);return a}async function i(s){const{data:a}=await t.delete(`/users/${s}`);return a}async function u(s,a){const{data:e}=await t.post(`/users/${s}/vip`,{days:a});return e}async function p(s){const{data:a}=await t.delete(`/users/${s}/vip`);return a}async function d(s,a){const{data:e}=await t.post(`/users/${s}/reset_password`,{new_password:a});return e}export{o as a,p as b,d as c,i as d,n as f,c as r,u as s};
|
||||||
@@ -5,13 +5,13 @@
|
|||||||
<link rel="icon" type="image/svg+xml" href="./vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="./vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>后台管理 - 知识管理平台</title>
|
<title>后台管理 - 知识管理平台</title>
|
||||||
<script type="module" crossorigin src="./assets/index-BhQdNLJb.js"></script>
|
<script type="module" crossorigin src="./assets/index-hdJlGZAd.js"></script>
|
||||||
<link rel="modulepreload" crossorigin href="./assets/vendor-vue-CVxSw_oJ.js">
|
<link rel="modulepreload" crossorigin href="./assets/vendor-vue-CVxSw_oJ.js">
|
||||||
<link rel="modulepreload" crossorigin href="./assets/vendor-misc-BeoNyvBp.js">
|
<link rel="modulepreload" crossorigin href="./assets/vendor-misc-BeoNyvBp.js">
|
||||||
<link rel="modulepreload" crossorigin href="./assets/vendor-element-B5S5pUKo.js">
|
<link rel="modulepreload" crossorigin href="./assets/vendor-element-B5S5pUKo.js">
|
||||||
<link rel="modulepreload" crossorigin href="./assets/vendor-axios-B9ygI19o.js">
|
<link rel="modulepreload" crossorigin href="./assets/vendor-axios-B9ygI19o.js">
|
||||||
<link rel="stylesheet" crossorigin href="./assets/vendor-element-C68yOrAy.css">
|
<link rel="stylesheet" crossorigin href="./assets/vendor-element-C68yOrAy.css">
|
||||||
<link rel="stylesheet" crossorigin href="./assets/index-a3a11Ghn.css">
|
<link rel="stylesheet" crossorigin href="./assets/index-BL6_OP4l.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|||||||
Reference in New Issue
Block a user