feat(admin): compact mobile cards for report center

This commit is contained in:
2026-02-07 09:54:11 +08:00
parent 12e07962c7
commit 69e3e4c45c
26 changed files with 324 additions and 53 deletions

View File

@@ -63,6 +63,10 @@ function parsePercent(value) {
return n
}
function percentText(value) {
return `${Math.round(parsePercent(value))}%`
}
function sourceLabel(source) {
const raw = String(source ?? '').trim()
if (!raw) return '手动'
@@ -227,6 +231,119 @@ const runningCountsLabel = computed(() => {
return `运行中 ${runningCount} / 排队 ${queuingCount} / 并发上限 ${maxGlobal || maxConcurrentGlobal.value || '-'}`
})
const taskModuleItems = computed(() => [
{ label: '今日总任务', value: normalizeCount(taskToday.value.total_tasks) },
{ label: '今日成功', value: normalizeCount(taskToday.value.success_tasks) },
{ label: '今日失败', value: normalizeCount(taskToday.value.failed_tasks) },
{ label: '今日成功率', value: `${taskTodaySuccessRate.value}%` },
{ label: '累计任务', value: normalizeCount(taskTotal.value.total_tasks) },
{ label: '累计成功', value: normalizeCount(taskTotal.value.success_tasks) },
])
const queueModuleItems = computed(() => [
{ label: '运行中', value: runningCount.value },
{ label: '排队中', value: queuingCount.value },
{ label: '并发上限', value: normalizeCount(runningTasks.value?.max_concurrent) || maxConcurrentGlobal.value || '-' },
{ label: '排队首条来源', value: sourceLabel(queuingTaskList.value[0]?.source) },
{ label: '排队首条状态', value: queuingTaskList.value[0]?.detail_status || queuingTaskList.value[0]?.status || '-' },
{ label: '最长等待', value: queuingTaskList.value[0]?.elapsed_display || '-' },
])
const emailModuleItems = computed(() => [
{ label: '总发送', value: normalizeCount(emailStats.value?.total_sent) },
{ label: '成功', value: normalizeCount(emailStats.value?.total_success) },
{ label: '失败', value: normalizeCount(emailStats.value?.total_failed) },
{ label: '成功率', value: `${emailSuccessRate.value}%` },
{ label: '注册验证', value: normalizeCount(emailStats.value?.register_sent) },
{ label: '重置密码', value: normalizeCount(emailStats.value?.reset_sent) },
])
const feedbackModuleItems = computed(() => [
{ label: '总反馈', value: normalizeCount(feedbackStats.value?.total) },
{ label: '待处理', value: normalizeCount(feedbackStats.value?.pending) },
{ label: '已回复', value: normalizeCount(feedbackStats.value?.replied) },
])
const resourceModuleItems = computed(() => [
{ label: 'CPU', value: percentText(serverInfo.value?.cpu_percent) },
{ label: '内存', value: percentText(serverInfo.value?.memory_percent) },
{ label: '磁盘', value: percentText(serverInfo.value?.disk_percent) },
{ label: '容器状态', value: dockerStats.value?.status || '-' },
{ label: '容器名', value: dockerStats.value?.container_name || '-' },
{ label: '容器运行', value: dockerStats.value?.uptime || '-' },
])
const workerModuleItems = computed(() => [
{ label: '总 Worker', value: browserPoolTotalWorkers.value },
{ label: '活跃 Worker', value: browserPoolActiveWorkers.value },
{ label: '忙碌 Worker', value: browserPoolBusyWorkers.value },
{ label: '空闲 Worker', value: browserPoolIdleWorkers.value },
{ label: '任务队列', value: browserPoolQueueSize.value },
])
const configModuleItems = computed(() => [
{ label: '定时任务', value: scheduleEnabled.value ? '启用' : '关闭' },
{ label: '执行时间', value: scheduleTime.value || '-' },
{ label: '浏览类型', value: scheduleBrowseType.value || '-' },
{ label: '代理', value: proxyEnabled.value ? '启用' : '关闭' },
{ label: '代理有效期', value: proxyExpireMinutes.value ? `${proxyExpireMinutes.value} 分钟` : '-' },
{ label: '全局并发', value: maxConcurrentGlobal.value || '-' },
{ label: '单账号并发', value: maxConcurrentPerAccount.value || '-' },
{ label: '截图并发', value: maxScreenshotConcurrent.value || '-' },
])
const mobileModules = computed(() => [
{
key: 'task',
title: '任务概览',
desc: normalizeCount(taskToday.value.total_tasks) > 0 ? `今日成功率 ${taskTodaySuccessRate.value}%` : '今日暂无任务',
tone: 'purple',
items: taskModuleItems.value,
},
{
key: 'queue',
title: '队列监控',
desc: runningCountsLabel.value,
tone: 'blue',
items: queueModuleItems.value,
},
{
key: 'email',
title: '邮件报表',
desc: `成功率 ${emailSuccessRate.value}%`,
tone: 'cyan',
items: emailModuleItems.value,
},
{
key: 'feedback',
title: '反馈概览',
desc: `待处理 ${normalizeCount(feedbackStats.value?.pending)}`,
tone: 'orange',
items: feedbackModuleItems.value,
},
{
key: 'resource',
title: '系统资源',
desc: serverInfo.value?.uptime ? `运行 ${serverInfo.value.uptime}` : '运行状态获取中',
tone: 'green',
items: resourceModuleItems.value,
},
{
key: 'worker',
title: '截图线程池',
desc: `活跃 ${browserPoolActiveWorkers.value} · 忙碌 ${browserPoolBusyWorkers.value}`,
tone: 'cyan',
items: workerModuleItems.value,
},
{
key: 'config',
title: '配置概览',
desc: '并发 / 代理 / 定时任务',
tone: 'red',
items: configModuleItems.value,
},
])
async function refreshAll(options = {}) {
const showLoading = options.showLoading ?? true
if (refreshing.value) return
@@ -307,6 +424,29 @@ onUnmounted(() => {
<MetricGrid :items="overviewCards" :loading="loading" :min-width="165" />
</section>
<section class="mobile-report">
<el-card
v-for="module in mobileModules"
:key="module.key"
shadow="never"
class="mobile-module-card"
:class="`mobile-tone-${module.tone}`"
:body-style="{ padding: '12px' }"
>
<div class="mobile-module-head">
<div class="mobile-module-title">{{ module.title }}</div>
<div class="mobile-module-desc app-muted">{{ module.desc }}</div>
</div>
<div class="mobile-metrics">
<div v-for="item in module.items" :key="`${module.key}-${item.label}`" class="mobile-metric-item">
<div class="mobile-metric-label app-muted">{{ item.label }}</div>
<div class="mobile-metric-value">{{ item.value }}</div>
</div>
</div>
</el-card>
</section>
<div class="desktop-report">
<el-row :gutter="12">
<el-col :xs="24" :lg="12">
<el-card shadow="never" class="panel" :body-style="{ padding: '16px' }">
@@ -635,6 +775,7 @@ onUnmounted(() => {
</el-card>
</el-col>
</el-row>
</div>
</div>
</template>
@@ -695,6 +836,102 @@ onUnmounted(() => {
flex-wrap: wrap;
}
.mobile-report {
display: none;
}
.mobile-module-card {
position: relative;
overflow: hidden;
border-radius: 14px;
border: 1px solid rgba(17, 24, 39, 0.12);
background: rgba(255, 255, 255, 0.9);
box-shadow: var(--app-shadow-soft);
}
.mobile-module-card::before {
content: '';
position: absolute;
left: 0;
top: 0;
right: 0;
height: 3px;
background: var(--mobile-accent, #3b82f6);
}
.mobile-tone-blue {
--mobile-accent: linear-gradient(90deg, #3b82f6, #06b6d4);
}
.mobile-tone-cyan {
--mobile-accent: linear-gradient(90deg, #06b6d4, #3b82f6);
}
.mobile-tone-purple {
--mobile-accent: linear-gradient(90deg, #8b5cf6, #ec4899);
}
.mobile-tone-orange {
--mobile-accent: linear-gradient(90deg, #f59e0b, #f97316);
}
.mobile-tone-green {
--mobile-accent: linear-gradient(90deg, #10b981, #22c55e);
}
.mobile-tone-red {
--mobile-accent: linear-gradient(90deg, #ef4444, #f43f5e);
}
.mobile-module-head {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 10px;
}
.mobile-module-title {
font-size: 13px;
font-weight: 900;
color: #0f172a;
}
.mobile-module-desc {
min-width: 0;
max-width: 68%;
font-size: 11px;
line-height: 1.4;
text-align: right;
}
.mobile-metrics {
margin-top: 10px;
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 8px;
}
.mobile-metric-item {
padding: 8px 10px;
border-radius: 10px;
border: 1px solid rgba(17, 24, 39, 0.08);
background: rgba(248, 250, 252, 0.9);
}
.mobile-metric-label {
font-size: 11px;
line-height: 1.35;
}
.mobile-metric-value {
margin-top: 4px;
font-size: 14px;
font-weight: 800;
color: #0f172a;
line-height: 1.3;
word-break: break-word;
}
.panel {
border-radius: 18px;
border: 1px solid rgba(17, 24, 39, 0.1);
@@ -895,8 +1132,42 @@ onUnmounted(() => {
}
@media (max-width: 768px) {
.desktop-report {
display: none;
}
.mobile-report {
display: grid;
gap: 10px;
}
.report-hero {
border-radius: 14px;
padding: 12px;
}
.hero-main h2 {
font-size: 17px;
}
.hero-meta {
margin-top: 4px;
gap: 6px;
font-size: 11px;
}
.resource-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 420px) {
.mobile-metrics {
grid-template-columns: 1fr;
}
.mobile-module-desc {
max-width: 62%;
}
}
</style>

View File

@@ -1,6 +1,6 @@
{
"_MetricGrid-DZUrF_Un.js": {
"file": "assets/MetricGrid-DZUrF_Un.js",
"_MetricGrid-CO_q83yh.js": {
"file": "assets/MetricGrid-CO_q83yh.js",
"name": "MetricGrid",
"imports": [
"index.html"
@@ -13,36 +13,36 @@
"file": "assets/MetricGrid-yP_dkP6X.css",
"src": "_MetricGrid-yP_dkP6X.css"
},
"_email-CvVAilYN.js": {
"file": "assets/email-CvVAilYN.js",
"_email-DXFDTcFR.js": {
"file": "assets/email-DXFDTcFR.js",
"name": "email",
"imports": [
"index.html"
]
},
"_system-VhyLCmjS.js": {
"file": "assets/system-VhyLCmjS.js",
"_system-DoHHS63d.js": {
"file": "assets/system-DoHHS63d.js",
"name": "system",
"imports": [
"index.html"
]
},
"_tasks-D7g7NShX.js": {
"file": "assets/tasks-D7g7NShX.js",
"_tasks-DZN3Iufx.js": {
"file": "assets/tasks-DZN3Iufx.js",
"name": "tasks",
"imports": [
"index.html"
]
},
"_users-BEod_y0N.js": {
"file": "assets/users-BEod_y0N.js",
"_users-COdHnepZ.js": {
"file": "assets/users-COdHnepZ.js",
"name": "users",
"imports": [
"index.html"
]
},
"index.html": {
"file": "assets/index-BTIe-LzI.js",
"file": "assets/index-CpTjoI5H.js",
"name": "index",
"src": "index.html",
"isEntry": true,
@@ -62,7 +62,7 @@
]
},
"src/pages/AnnouncementsPage.vue": {
"file": "assets/AnnouncementsPage-BI2YHYxD.js",
"file": "assets/AnnouncementsPage-S4Vp-C2C.js",
"name": "AnnouncementsPage",
"src": "src/pages/AnnouncementsPage.vue",
"isDynamicEntry": true,
@@ -74,40 +74,40 @@
]
},
"src/pages/EmailPage.vue": {
"file": "assets/EmailPage-BbHeWCVl.js",
"file": "assets/EmailPage-QNoD0vM8.js",
"name": "EmailPage",
"src": "src/pages/EmailPage.vue",
"isDynamicEntry": true,
"imports": [
"_email-CvVAilYN.js",
"_email-DXFDTcFR.js",
"index.html",
"_MetricGrid-DZUrF_Un.js"
"_MetricGrid-CO_q83yh.js"
],
"css": [
"assets/EmailPage-BmPCDPYC.css"
]
},
"src/pages/FeedbacksPage.vue": {
"file": "assets/FeedbacksPage-DHEEAjuM.js",
"file": "assets/FeedbacksPage-c1mEklN7.js",
"name": "FeedbacksPage",
"src": "src/pages/FeedbacksPage.vue",
"isDynamicEntry": true,
"imports": [
"index.html",
"_MetricGrid-DZUrF_Un.js"
"_MetricGrid-CO_q83yh.js"
],
"css": [
"assets/FeedbacksPage-mrXjCiV2.css"
]
},
"src/pages/LogsPage.vue": {
"file": "assets/LogsPage-B8VOeIJO.js",
"file": "assets/LogsPage-D81ZpiBx.js",
"name": "LogsPage",
"src": "src/pages/LogsPage.vue",
"isDynamicEntry": true,
"imports": [
"_users-BEod_y0N.js",
"_tasks-D7g7NShX.js",
"_users-COdHnepZ.js",
"_tasks-DZN3Iufx.js",
"index.html"
],
"css": [
@@ -115,36 +115,36 @@
]
},
"src/pages/ReportPage.vue": {
"file": "assets/ReportPage-C-_600qN.js",
"file": "assets/ReportPage-Cgvv4cbM.js",
"name": "ReportPage",
"src": "src/pages/ReportPage.vue",
"isDynamicEntry": true,
"imports": [
"index.html",
"_email-CvVAilYN.js",
"_tasks-D7g7NShX.js",
"_system-VhyLCmjS.js",
"_MetricGrid-DZUrF_Un.js"
"_email-DXFDTcFR.js",
"_tasks-DZN3Iufx.js",
"_system-DoHHS63d.js",
"_MetricGrid-CO_q83yh.js"
],
"css": [
"assets/ReportPage-HC4elboH.css"
"assets/ReportPage-MS8zJmyZ.css"
]
},
"src/pages/SecurityPage.vue": {
"file": "assets/SecurityPage-Ce7j6UO4.js",
"file": "assets/SecurityPage-BLF3zGyy.js",
"name": "SecurityPage",
"src": "src/pages/SecurityPage.vue",
"isDynamicEntry": true,
"imports": [
"index.html",
"_MetricGrid-DZUrF_Un.js"
"_MetricGrid-CO_q83yh.js"
],
"css": [
"assets/SecurityPage-DN76ndc_.css"
]
},
"src/pages/SettingsPage.vue": {
"file": "assets/SettingsPage-nj1AULlf.js",
"file": "assets/SettingsPage-kou4GC5e.js",
"name": "SettingsPage",
"src": "src/pages/SettingsPage.vue",
"isDynamicEntry": true,
@@ -156,12 +156,12 @@
]
},
"src/pages/SystemPage.vue": {
"file": "assets/SystemPage-i6_qDLAX.js",
"file": "assets/SystemPage-DZnURk26.js",
"name": "SystemPage",
"src": "src/pages/SystemPage.vue",
"isDynamicEntry": true,
"imports": [
"_system-VhyLCmjS.js",
"_system-DoHHS63d.js",
"index.html"
],
"css": [
@@ -169,12 +169,12 @@
]
},
"src/pages/UsersPage.vue": {
"file": "assets/UsersPage-BbP8F1bH.js",
"file": "assets/UsersPage-7SCtUJvO.js",
"name": "UsersPage",
"src": "src/pages/UsersPage.vue",
"isDynamicEntry": true,
"imports": [
"_users-BEod_y0N.js",
"_users-COdHnepZ.js",
"index.html"
],
"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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
import{_ as m,f as c,g as s,h as t,F as l,q as u,D as p,j as o,n as r,m as y,w as h,B as i,T as v,p as n,x as k,U as f}from"./index-CpTjoI5H.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,w)=>{const d=c("el-icon"),_=c("el-skeleton");return t(),s("div",{class:"metric-grid",style:f({"--metric-min":`${a.minWidth}px`})},[(t(!0),s(l,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)])):r("",!0),o("div",g,n(e?.label||"-"),1)]),o("div",B,[a.loading?(t(),i(_,{key:0,rows:1,animated:""})):(t(),s(l,{key:1},[k(n(e?.value??0),1)],64))]),e?.hint||e?.sub?(t(),s("div",C,n(e?.hint||e?.sub),1)):r("",!0)],2))),128))],4)}}},M=m(N,[["__scopeId","data-v-00e217d4"]]);export{M};

View File

@@ -1 +0,0 @@
import{_ as m,f as c,g as s,h as t,F as l,K as u,C as p,j as o,n as r,m as y,w as h,A as i,T as v,p as n,v as k,U as f}from"./index-BTIe-LzI.js";const b={class:"metric-top"},g={key:0,class:"metric-icon"},x={class:"metric-label"},C={class:"metric-value"},B={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,w)=>{const d=c("el-icon"),_=c("el-skeleton");return t(),s("div",{class:"metric-grid",style:f({"--metric-min":`${a.minWidth}px`})},[(t(!0),s(l,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",g,[y(d,null,{default:h(()=>[(t(),i(v(e.icon)))]),_:2},1024)])):r("",!0),o("div",x,n(e?.label||"-"),1)]),o("div",C,[a.loading?(t(),i(_,{key:0,rows:1,animated:""})):(t(),s(l,{key:1},[k(n(e?.value??0),1)],64))]),e?.hint||e?.sub?(t(),s("div",B,n(e?.hint||e?.sub),1)):r("",!0)],2))),128))],4)}}},z=m(N,[["__scopeId","data-v-00e217d4"]]);export{z as M};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
.page-stack[data-v-e84bdbad]{display:flex;flex-direction:column;gap:14px}.report-hero[data-v-e84bdbad]{position:relative;overflow:hidden;border-radius:18px;border:1px solid rgba(17,24,39,.1);background:radial-gradient(circle at 10% 10%,rgba(59,130,246,.18),transparent 48%),radial-gradient(circle at 80% 0%,rgba(236,72,153,.16),transparent 45%),radial-gradient(circle at 90% 90%,rgba(16,185,129,.14),transparent 42%),#ffffffb8;box-shadow:0 14px 40px #0f172a14;-webkit-backdrop-filter:saturate(180%) blur(12px);backdrop-filter:saturate(180%) blur(12px);padding:16px}.hero-head[data-v-e84bdbad]{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-bottom:14px}.hero-main h2[data-v-e84bdbad]{margin:0;font-size:19px;font-weight:900;letter-spacing:.2px}.hero-meta[data-v-e84bdbad]{margin-top:6px;font-size:12px;display:flex;align-items:center;flex-wrap:wrap;gap:8px}.hero-dot[data-v-e84bdbad]{opacity:.65}.hero-actions[data-v-e84bdbad]{display:flex;gap:10px;align-items:center;flex-wrap:wrap}.panel[data-v-e84bdbad]{border-radius:18px;border:1px solid rgba(17,24,39,.1);background:#ffffffb8;box-shadow:var(--app-shadow);-webkit-backdrop-filter:saturate(180%) blur(10px);backdrop-filter:saturate(180%) blur(10px)}.panel-head[data-v-e84bdbad]{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:14px}.head-left[data-v-e84bdbad]{display:flex;align-items:center;gap:12px;min-width:0}.head-text[data-v-e84bdbad]{min-width:0}.head-icon[data-v-e84bdbad]{width:40px;height:40px;border-radius:16px;display:flex;align-items:center;justify-content:center;border:1px solid rgba(17,24,39,.08);flex:0 0 auto}.tone-blue[data-v-e84bdbad]{background:#3b82f61f;color:#1d4ed8}.tone-cyan[data-v-e84bdbad]{background:#22d3ee1f;color:#0369a1}.tone-purple[data-v-e84bdbad]{background:#8b5cf61f;color:#6d28d9}.tone-orange[data-v-e84bdbad]{background:#f59e0b1f;color:#b45309}.tone-green[data-v-e84bdbad]{background:#10b9811f;color:#047857}.tone-red[data-v-e84bdbad]{background:#ef44441f;color:#b91c1c}.panel-title[data-v-e84bdbad]{font-size:14px;font-weight:900}.panel-sub[data-v-e84bdbad]{margin-top:4px;font-size:12px;color:var(--app-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.metrics-block[data-v-e84bdbad]{display:flex;flex-direction:column;gap:10px}.block-title[data-v-e84bdbad]{font-size:13px;font-weight:900;letter-spacing:.2px}.divider[data-v-e84bdbad]{height:1px;background:linear-gradient(90deg,transparent,rgba(17,24,39,.12),transparent);margin:14px 0}.queue-tabs[data-v-e84bdbad] .el-tabs__header{margin:0 0 10px}.tab-label[data-v-e84bdbad]{display:inline-flex;align-items:center;gap:6px}.table-wrap[data-v-e84bdbad]{overflow-x:auto;border-radius:10px;border:1px solid var(--app-border);background:#fff}.help[data-v-e84bdbad]{margin-top:10px;font-size:12px}.resource-grid[data-v-e84bdbad]{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px}.resource-item[data-v-e84bdbad]{border:1px solid rgba(17,24,39,.08);border-radius:16px;padding:12px;background:#ffffffb3}.resource-k[data-v-e84bdbad]{font-size:12px;margin-bottom:8px}.resource-sub[data-v-e84bdbad]{margin-top:8px;font-size:12px}.config-grid[data-v-e84bdbad]{display:grid;grid-template-columns:1fr;gap:10px}.config-item[data-v-e84bdbad]{border:1px solid rgba(17,24,39,.08);border-radius:16px;padding:12px;background:#ffffffb3}.config-k[data-v-e84bdbad]{font-size:12px}.config-v[data-v-e84bdbad]{margin-top:8px;display:flex;align-items:center;gap:8px;flex-wrap:wrap}.config-inline[data-v-e84bdbad]{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.config-split[data-v-e84bdbad]{opacity:.65}.config-sub[data-v-e84bdbad]{margin-top:8px;font-size:12px}.err[data-v-e84bdbad]{color:#b91c1c}[data-v-e84bdbad] .el-table{--el-table-border-color: rgba(17, 24, 39, .08);--el-table-header-bg-color: rgba(246, 247, 251, .8)}[data-v-e84bdbad] .el-table th.el-table__cell{background:#f6f7fbcc}@media(max-width:768px){.resource-grid[data-v-e84bdbad]{grid-template-columns:1fr}}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
import{a as m,_ as B,r as p,f as u,g as T,h as P,j as r,m as a,w as l,x,K as i,J as b}from"./index-CpTjoI5H.js";async function C(o){const{data:s}=await m.put("/admin/username",{new_username:o});return s}async function S(o){const{data:s}=await m.put("/admin/password",{new_password:o});return s}async function U(){const{data:o}=await m.post("/logout");return o}const A={class:"page-stack"},E={__name:"SettingsPage",setup(o){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 U()}catch{}finally{window.location.href="/yuyx"}}async function V(){const t=s.value.trim();if(!t){i.error("请输入新用户名");return}try{await b.confirm(`确定将管理员用户名修改为「${t}」吗?修改后需要重新登录。`,"修改用户名",{confirmButtonText:"确认修改",cancelButtonText:"取消",type:"warning"})}catch{return}n.value=!0;try{await C(t),i.success("用户名修改成功,请重新登录"),s.value="",setTimeout(f,1200)}catch{}finally{n.value=!1}}async function h(){const t=d.value;if(!t){i.error("请输入新密码");return}const e=k(t);if(!e.ok){i.error(e.message);return}try{await b.confirm("确定修改管理员密码吗?修改后需要重新登录。","修改密码",{confirmButtonText:"确认修改",cancelButtonText:"取消",type:"warning"})}catch{return}n.value=!0;try{await S(t),i.success("密码修改成功,请重新登录"),d.value="",setTimeout(f,1200)}catch{}finally{n.value=!1}}return(t,e)=>{const g=u("el-input"),w=u("el-form-item"),v=u("el-form"),y=u("el-button"),_=u("el-card");return P(),T("div",A,[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:l(()=>[e[3]||(e[3]=r("h3",{class:"section-title"},"修改管理员用户名",-1)),a(v,{"label-width":"120px"},{default:l(()=>[a(w,{label:"新用户名"},{default:l(()=>[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:l(()=>[...e[2]||(e[2]=[x("保存用户名",-1)])]),_:1},8,["loading"])]),_:1}),a(_,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:l(()=>[e[5]||(e[5]=r("h3",{class:"section-title"},"修改管理员密码",-1)),a(v,{"label-width":"120px"},{default:l(()=>[a(w,{label:"新密码"},{default:l(()=>[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:h},{default:l(()=>[...e[4]||(e[4]=[x("保存密码",-1)])]),_:1},8,["loading"]),e[6]||(e[6]=r("div",{class:"help"},"建议使用更强密码至少8位且包含字母与数字。",-1))]),_:1})])}}},M=B(E,[["__scopeId","data-v-83d3840a"]]);export{M as default};

View File

@@ -1 +0,0 @@
import{a as m,_ as B,r as p,f as u,g as T,h as P,j as r,m as a,w as l,v as x,J as i,I as b}from"./index-BTIe-LzI.js";async function C(o){const{data:s}=await m.put("/admin/username",{new_username:o});return s}async function S(o){const{data:s}=await m.put("/admin/password",{new_password:o});return s}async function U(){const{data:o}=await m.post("/logout");return o}const A={class:"page-stack"},E={__name:"SettingsPage",setup(o){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 U()}catch{}finally{window.location.href="/yuyx"}}async function V(){const t=s.value.trim();if(!t){i.error("请输入新用户名");return}try{await b.confirm(`确定将管理员用户名修改为「${t}」吗?修改后需要重新登录。`,"修改用户名",{confirmButtonText:"确认修改",cancelButtonText:"取消",type:"warning"})}catch{return}n.value=!0;try{await C(t),i.success("用户名修改成功,请重新登录"),s.value="",setTimeout(f,1200)}catch{}finally{n.value=!1}}async function h(){const t=d.value;if(!t){i.error("请输入新密码");return}const e=k(t);if(!e.ok){i.error(e.message);return}try{await b.confirm("确定修改管理员密码吗?修改后需要重新登录。","修改密码",{confirmButtonText:"确认修改",cancelButtonText:"取消",type:"warning"})}catch{return}n.value=!0;try{await S(t),i.success("密码修改成功,请重新登录"),d.value="",setTimeout(f,1200)}catch{}finally{n.value=!1}}return(t,e)=>{const g=u("el-input"),v=u("el-form-item"),w=u("el-form"),y=u("el-button"),_=u("el-card");return P(),T("div",A,[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:l(()=>[e[3]||(e[3]=r("h3",{class:"section-title"},"修改管理员用户名",-1)),a(w,{"label-width":"120px"},{default:l(()=>[a(v,{label:"新用户名"},{default:l(()=>[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:l(()=>[...e[2]||(e[2]=[x("保存用户名",-1)])]),_:1},8,["loading"])]),_:1}),a(_,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:l(()=>[e[5]||(e[5]=r("h3",{class:"section-title"},"修改管理员密码",-1)),a(w,{"label-width":"120px"},{default:l(()=>[a(v,{label:"新密码"},{default:l(()=>[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:h},{default:l(()=>[...e[4]||(e[4]=[x("保存密码",-1)])]),_:1},8,["loading"]),e[6]||(e[6]=r("div",{class:"help"},"建议使用更强密码至少8位且包含字母与数字。",-1))]),_:1})])}}},I=B(E,[["__scopeId","data-v-83d3840a"]]);export{I as default};

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
import{a as n}from"./index-BTIe-LzI.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};
import{a as n}from"./index-CpTjoI5H.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

View File

@@ -1 +1 @@
import{a}from"./index-BTIe-LzI.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};
import{a}from"./index-CpTjoI5H.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};

View File

@@ -1 +1 @@
import{a}from"./index-BTIe-LzI.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 o(){const{data:t}=await a.get("/task/stats");return t}async function r(){const{data:t}=await a.get("/task/running");return t}async function i(t){const{data:s}=await a.get("/task/logs",{params:t});return s}async function f(t){const{data:s}=await a.post("/task/logs/clear",{days:t});return s}export{r as a,c as b,e as c,i as d,f as e,o as f};
import{a}from"./index-CpTjoI5H.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 o(){const{data:t}=await a.get("/task/stats");return t}async function r(){const{data:t}=await a.get("/task/running");return t}async function i(t){const{data:s}=await a.get("/task/logs",{params:t});return s}async function f(t){const{data:s}=await a.post("/task/logs/clear",{days:t});return s}export{r as a,c as b,e as c,i as d,f as e,o as f};

View File

@@ -1 +1 @@
import{a as t}from"./index-BTIe-LzI.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-CpTjoI5H.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};

View File

@@ -5,7 +5,7 @@
<link rel="icon" type="image/svg+xml" href="./vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>后台管理 - 知识管理平台</title>
<script type="module" crossorigin src="./assets/index-BTIe-LzI.js"></script>
<script type="module" crossorigin src="./assets/index-CpTjoI5H.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-DRsk2q1y.css">
</head>
<body>