feat: redesign admin layout and stats dashboards

This commit is contained in:
2026-02-07 01:59:29 +08:00
parent 9991834ccd
commit 6eb0651e23
70 changed files with 713 additions and 690 deletions

View File

@@ -0,0 +1,164 @@
<script setup>
const props = defineProps({
items: {
type: Array,
default: () => [],
},
loading: {
type: Boolean,
default: false,
},
minWidth: {
type: Number,
default: 180,
},
})
</script>
<template>
<div class="metric-grid" :style="{ '--metric-min': `${minWidth}px` }">
<div
v-for="item in items"
:key="item?.key || item?.label"
class="metric-card"
:class="`metric-tone--${item?.tone || 'blue'}`"
>
<div class="metric-top">
<div v-if="item?.icon" class="metric-icon">
<el-icon><component :is="item.icon" /></el-icon>
</div>
<div class="metric-label">{{ item?.label || '-' }}</div>
</div>
<div class="metric-value">
<el-skeleton v-if="loading" :rows="1" animated />
<template v-else>{{ item?.value ?? 0 }}</template>
</div>
<div v-if="item?.hint || item?.sub" class="metric-hint app-muted">{{ item?.hint || item?.sub }}</div>
</div>
</div>
</template>
<style scoped>
.metric-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(var(--metric-min), 1fr));
gap: 12px;
}
.metric-card {
position: relative;
overflow: hidden;
border-radius: 14px;
border: 1px solid var(--app-border);
background: linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(250, 252, 255, 0.9));
box-shadow: var(--app-shadow-soft);
padding: 13px 14px;
min-height: 104px;
}
.metric-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
background: var(--metric-top, #3b82f6);
}
.metric-top {
display: flex;
align-items: center;
gap: 8px;
}
.metric-icon {
width: 26px;
height: 26px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
background: var(--metric-icon-bg, rgba(59, 130, 246, 0.12));
color: var(--metric-icon-color, #1d4ed8);
}
.metric-label {
font-size: 12px;
color: #475569;
font-weight: 700;
line-height: 1.4;
}
.metric-value {
margin-top: 10px;
font-size: 26px;
line-height: 1.05;
font-weight: 900;
color: #0f172a;
}
.metric-hint {
margin-top: 8px;
font-size: 12px;
line-height: 1.4;
}
.metric-tone--blue {
--metric-top: linear-gradient(90deg, #3b82f6, #06b6d4);
--metric-icon-bg: rgba(59, 130, 246, 0.14);
--metric-icon-color: #1d4ed8;
}
.metric-tone--green {
--metric-top: linear-gradient(90deg, #10b981, #22c55e);
--metric-icon-bg: rgba(16, 185, 129, 0.14);
--metric-icon-color: #047857;
}
.metric-tone--purple {
--metric-top: linear-gradient(90deg, #8b5cf6, #ec4899);
--metric-icon-bg: rgba(139, 92, 246, 0.14);
--metric-icon-color: #6d28d9;
}
.metric-tone--orange {
--metric-top: linear-gradient(90deg, #f59e0b, #f97316);
--metric-icon-bg: rgba(245, 158, 11, 0.14);
--metric-icon-color: #b45309;
}
.metric-tone--red {
--metric-top: linear-gradient(90deg, #ef4444, #f43f5e);
--metric-icon-bg: rgba(239, 68, 68, 0.14);
--metric-icon-color: #b91c1c;
}
.metric-tone--cyan {
--metric-top: linear-gradient(90deg, #06b6d4, #3b82f6);
--metric-icon-bg: rgba(6, 182, 212, 0.14);
--metric-icon-color: #0e7490;
}
@media (max-width: 768px) {
.metric-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.metric-card {
min-height: 96px;
}
.metric-value {
font-size: 22px;
}
}
@media (max-width: 480px) {
.metric-grid {
grid-template-columns: 1fr;
}
}
</style>

View File

@@ -162,11 +162,12 @@ async function go(path) {
<span class="app-muted">管理员</span> <span class="app-muted">管理员</span>
<strong>{{ adminUsername || '-' }}</strong> <strong>{{ adminUsername || '-' }}</strong>
</div> </div>
<el-button type="primary" plain @click="logout">退出</el-button> <el-button type="primary" plain class="logout-btn" @click="logout">退出</el-button>
</div> </div>
</el-header> </el-header>
<el-main class="layout-main"> <el-main class="layout-main">
<div class="main-shell">
<Suspense> <Suspense>
<template #default> <template #default>
<RouterView /> <RouterView />
@@ -177,6 +178,7 @@ async function go(path) {
</el-card> </el-card>
</template> </template>
</Suspense> </Suspense>
</div>
</el-main> </el-main>
</el-container> </el-container>
@@ -204,31 +206,58 @@ async function go(path) {
} }
.layout-aside { .layout-aside {
background: #ffffff; background: linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(248, 250, 252, 0.94));
border-right: 1px solid var(--app-border); border-right: 1px solid var(--app-border);
box-shadow: 4px 0 16px rgba(15, 23, 42, 0.04);
}
.brand,
.drawer-brand {
padding: 18px 16px 14px;
} }
.brand { .brand {
padding: 18px 16px 10px; border-bottom: 1px solid rgba(15, 23, 42, 0.06);
}
.drawer-brand {
padding: 18px 16px 10px;
} }
.brand-title { .brand-title {
font-size: 15px; font-size: 16px;
font-weight: 800; font-weight: 800;
letter-spacing: 0.2px; letter-spacing: 0.2px;
} }
.brand-sub { .brand-sub {
margin-top: 2px; margin-top: 4px;
font-size: 12px; font-size: 12px;
} }
.aside-menu { .aside-menu {
border-right: none; border-right: none;
padding: 8px;
background: transparent;
}
.aside-menu :deep(.el-menu-item) {
height: 42px;
line-height: 42px;
margin: 3px 0;
border-radius: 10px;
color: #334155;
font-weight: 600;
}
.aside-menu :deep(.el-menu-item .el-icon) {
margin-right: 10px;
}
.aside-menu :deep(.el-menu-item:hover) {
background: rgba(59, 130, 246, 0.08);
color: #1d4ed8;
}
.aside-menu :deep(.el-menu-item.is-active) {
background: linear-gradient(135deg, rgba(37, 99, 235, 0.12), rgba(124, 58, 237, 0.1));
color: #1e40af;
} }
.menu-label { .menu-label {
@@ -243,16 +272,22 @@ async function go(path) {
} }
.fallback-card { .fallback-card {
border-radius: var(--app-radius); min-height: 160px;
border-radius: var(--app-radius-lg);
border: 1px solid var(--app-border); border: 1px solid var(--app-border);
} }
.layout-header { .layout-header {
position: sticky;
top: 0;
z-index: 20;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
gap: 12px; gap: 12px;
background: rgba(246, 247, 251, 0.6); height: 58px;
padding: 0 18px;
background: rgba(255, 255, 255, 0.78);
backdrop-filter: saturate(180%) blur(10px); backdrop-filter: saturate(180%) blur(10px);
border-bottom: 1px solid var(--app-border); border-bottom: 1px solid var(--app-border);
} }
@@ -265,7 +300,7 @@ async function go(path) {
} }
.header-title { .header-title {
font-size: 14px; font-size: 15px;
font-weight: 800; font-weight: 800;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
@@ -288,18 +323,33 @@ async function go(path) {
align-items: baseline; align-items: baseline;
gap: 8px; gap: 8px;
font-size: 13px; font-size: 13px;
color: #334155;
}
.admin-name strong {
color: #0f172a;
font-weight: 800;
}
.logout-btn {
min-width: 74px;
} }
.layout-main { .layout-main {
padding: 16px; padding: 18px;
}
.main-shell {
width: 100%;
max-width: 1600px;
margin: 0 auto;
} }
@media (max-width: 768px) { @media (max-width: 768px) {
.layout-header { .layout-header {
flex-wrap: wrap; flex-wrap: wrap;
height: auto; height: auto;
padding-top: 10px; padding: 10px 12px;
padding-bottom: 10px;
} }
.header-right { .header-right {

View File

@@ -291,18 +291,22 @@ onMounted(load)
.page-stack { .page-stack {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 12px; gap: 14px;
min-width: 0;
} }
.card { .card {
border-radius: var(--app-radius); border-radius: var(--app-radius);
border: 1px solid var(--app-border); border: 1px solid var(--app-border);
background: var(--app-card-bg);
box-shadow: var(--app-shadow-soft);
} }
.section-title { .section-title {
margin: 0 0 12px; margin: 0 0 12px;
font-size: 14px; font-size: 15px;
font-weight: 800; font-weight: 800;
letter-spacing: 0.2px;
} }
.help { .help {
@@ -364,6 +368,9 @@ onMounted(load)
.table-wrap { .table-wrap {
overflow-x: auto; overflow-x: auto;
border-radius: 10px;
border: 1px solid var(--app-border);
background: #fff;
} }
.ellipsis { .ellipsis {

View File

@@ -12,6 +12,7 @@ import {
testSmtpConfig, testSmtpConfig,
updateSmtpConfig, updateSmtpConfig,
} from '../api/smtp' } from '../api/smtp'
import MetricGrid from '../components/MetricGrid.vue'
// ========== 全局设置 ========== // ========== 全局设置 ==========
const emailSettingsLoading = ref(false) const emailSettingsLoading = ref(false)
@@ -487,6 +488,21 @@ function emailLogUserLabel(row) {
return '系统' return '系统'
} }
const emailSummaryCards = computed(() => [
{ key: 'total_sent', label: '总发送', value: emailStats.value?.total_sent || 0, tone: 'blue' },
{ key: 'total_success', label: '成功', value: emailStats.value?.total_success || 0, tone: 'green' },
{ key: 'total_failed', label: '失败', value: emailStats.value?.total_failed || 0, tone: 'red' },
{ key: 'success_rate', label: '成功率', value: `${emailStats.value?.success_rate || 0}%`, tone: 'purple' },
])
const emailTypeCards = computed(() => [
{ key: 'register_sent', label: '注册验证', value: emailStats.value?.register_sent || 0, tone: 'cyan' },
{ key: 'reset_sent', label: '密码重置', value: emailStats.value?.reset_sent || 0, tone: 'orange' },
{ key: 'bind_sent', label: '邮箱绑定', value: emailStats.value?.bind_sent || 0, tone: 'purple' },
{ key: 'task_complete_sent', label: '任务完成', value: emailStats.value?.task_complete_sent || 0, tone: 'green' },
])
async function loadEmailStats() { async function loadEmailStats() {
emailStatsLoading.value = true emailStatsLoading.value = true
try { try {
@@ -668,38 +684,10 @@ onMounted(refreshAll)
<el-card shadow="never" :body-style="{ padding: '16px' }" class="card" v-loading="emailStatsLoading"> <el-card shadow="never" :body-style="{ padding: '16px' }" class="card" v-loading="emailStatsLoading">
<h3 class="section-title">邮件发送统计</h3> <h3 class="section-title">邮件发送统计</h3>
<el-row :gutter="12"> <MetricGrid :items="emailSummaryCards" :loading="emailStatsLoading" :min-width="160" />
<el-col :xs="12" :sm="6">
<el-card shadow="never" class="stat-card" :body-style="{ padding: '14px' }">
<div class="stat-value">{{ emailStats.total_sent || 0 }}</div>
<div class="stat-label">总发送</div>
</el-card>
</el-col>
<el-col :xs="12" :sm="6">
<el-card shadow="never" class="stat-card" :body-style="{ padding: '14px' }">
<div class="stat-value ok">{{ emailStats.total_success || 0 }}</div>
<div class="stat-label">成功</div>
</el-card>
</el-col>
<el-col :xs="12" :sm="6">
<el-card shadow="never" class="stat-card" :body-style="{ padding: '14px' }">
<div class="stat-value err">{{ emailStats.total_failed || 0 }}</div>
<div class="stat-label">失败</div>
</el-card>
</el-col>
<el-col :xs="12" :sm="6">
<el-card shadow="never" class="stat-card" :body-style="{ padding: '14px' }">
<div class="stat-value">{{ emailStats.success_rate || 0 }}%</div>
<div class="stat-label">成功率</div>
</el-card>
</el-col>
</el-row>
<div class="sub-stats"> <div class="sub-stats">
<el-tag effect="light">注册验证 {{ emailStats.register_sent || 0 }}</el-tag> <MetricGrid :items="emailTypeCards" :loading="emailStatsLoading" :min-width="150" />
<el-tag effect="light">密码重置 {{ emailStats.reset_sent || 0 }}</el-tag>
<el-tag effect="light">邮箱绑定 {{ emailStats.bind_sent || 0 }}</el-tag>
<el-tag effect="light">任务完成 {{ emailStats.task_complete_sent || 0 }}</el-tag>
</div> </div>
<div class="help app-muted">最后更新{{ emailStats.last_updated || '-' }}</div> <div class="help app-muted">最后更新{{ emailStats.last_updated || '-' }}</div>
@@ -853,7 +841,8 @@ onMounted(refreshAll)
.page-stack { .page-stack {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 12px; gap: 14px;
min-width: 0;
} }
.toolbar { .toolbar {
@@ -866,6 +855,8 @@ onMounted(refreshAll)
.card { .card {
border-radius: var(--app-radius); border-radius: var(--app-radius);
border: 1px solid var(--app-border); border: 1px solid var(--app-border);
background: var(--app-card-bg);
box-shadow: var(--app-shadow-soft);
} }
.section-head { .section-head {
@@ -879,8 +870,9 @@ onMounted(refreshAll)
.section-title { .section-title {
margin: 0; margin: 0;
font-size: 14px; font-size: 15px;
font-weight: 800; font-weight: 800;
letter-spacing: 0.2px;
} }
.help { .help {
@@ -891,37 +883,13 @@ onMounted(refreshAll)
.table-wrap { .table-wrap {
overflow-x: auto; overflow-x: auto;
} border-radius: 10px;
.stat-card {
border-radius: var(--app-radius);
border: 1px solid var(--app-border); border: 1px solid var(--app-border);
background: #fff;
} }
.stat-value {
font-size: 20px;
font-weight: 900;
line-height: 1.1;
}
.stat-label {
margin-top: 6px;
font-size: 12px;
color: var(--app-muted);
}
.ok {
color: #047857;
}
.err {
color: #b91c1c;
}
.sub-stats { .sub-stats {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 12px; margin-top: 12px;
} }

View File

@@ -1,8 +1,9 @@
<script setup> <script setup>
import { inject, onMounted, ref } from 'vue' import { computed, inject, onMounted, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { closeFeedback, deleteFeedback, fetchFeedbacks, replyFeedback } from '../api/feedbacks' import { closeFeedback, deleteFeedback, fetchFeedbacks, replyFeedback } from '../api/feedbacks'
import MetricGrid from '../components/MetricGrid.vue'
const refreshNavBadges = inject('refreshNavBadges', null) const refreshNavBadges = inject('refreshNavBadges', null)
@@ -18,6 +19,13 @@ const statusOptions = [
{ label: '已关闭', value: 'closed' }, { label: '已关闭', value: 'closed' },
] ]
const metricItems = computed(() => [
{ key: 'total', label: '总反馈', value: stats.value.total || 0, tone: 'blue' },
{ key: 'pending', label: '待处理', value: stats.value.pending || 0, tone: 'orange' },
{ key: 'replied', label: '已回复', value: stats.value.replied || 0, tone: 'green' },
{ key: 'closed', label: '已关闭', value: stats.value.closed || 0, tone: 'purple' },
])
function statusMeta(status) { function statusMeta(status) {
if (status === 'pending') return { label: '待处理', type: 'warning' } if (status === 'pending') return { label: '待处理', type: 'warning' }
if (status === 'replied') return { label: '已回复', type: 'success' } if (status === 'replied') return { label: '已回复', type: 'success' }
@@ -121,34 +129,14 @@ onMounted(load)
</div> </div>
</div> </div>
<el-row :gutter="12"> <MetricGrid :items="metricItems" :loading="loading" :min-width="165" />
<el-col :xs="12" :sm="6">
<el-card shadow="never" class="stat-card" :body-style="{ padding: '14px' }">
<div class="stat-value">{{ stats.total || 0 }}</div>
<div class="stat-label">总计</div>
</el-card>
</el-col>
<el-col :xs="12" :sm="6">
<el-card shadow="never" class="stat-card" :body-style="{ padding: '14px' }">
<div class="stat-value warn">{{ stats.pending || 0 }}</div>
<div class="stat-label">待处理</div>
</el-card>
</el-col>
<el-col :xs="12" :sm="6">
<el-card shadow="never" class="stat-card" :body-style="{ padding: '14px' }">
<div class="stat-value ok">{{ stats.replied || 0 }}</div>
<div class="stat-label">已回复</div>
</el-card>
</el-col>
<el-col :xs="12" :sm="6">
<el-card shadow="never" class="stat-card" :body-style="{ padding: '14px' }">
<div class="stat-value">{{ stats.closed || 0 }}</div>
<div class="stat-label">已关闭</div>
</el-card>
</el-col>
</el-row>
<el-card shadow="never" :body-style="{ padding: '16px' }" class="card"> <el-card shadow="never" :body-style="{ padding: '16px' }" class="card">
<div class="section-head">
<h3 class="section-title">反馈列表</h3>
<div class="app-muted"> {{ list.length }} 当前筛选</div>
</div>
<div class="table-wrap"> <div class="table-wrap">
<el-table :data="list" v-loading="loading" style="width: 100%"> <el-table :data="list" v-loading="loading" style="width: 100%">
<el-table-column prop="id" label="ID" width="80" /> <el-table-column prop="id" label="ID" width="80" />
@@ -204,43 +192,44 @@ onMounted(load)
.page-stack { .page-stack {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 12px; gap: 14px;
min-width: 0;
} }
.toolbar { .toolbar {
display: flex; display: flex;
gap: 10px; gap: 10px;
align-items: center; align-items: center;
flex-wrap: wrap;
} }
.card, .card {
.stat-card {
border-radius: var(--app-radius); border-radius: var(--app-radius);
border: 1px solid var(--app-border); border: 1px solid var(--app-border);
background: var(--app-card-bg);
box-shadow: var(--app-shadow-soft);
} }
.stat-value { .section-head {
font-size: 20px; display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-bottom: 12px;
flex-wrap: wrap;
}
.section-title {
margin: 0;
font-size: 15px;
font-weight: 800; font-weight: 800;
line-height: 1.1;
}
.stat-label {
margin-top: 6px;
font-size: 12px;
color: var(--app-muted);
}
.warn {
color: #b45309;
}
.ok {
color: #047857;
} }
.table-wrap { .table-wrap {
overflow-x: auto; overflow-x: auto;
border-radius: 10px;
border: 1px solid var(--app-border);
background: #fff;
} }
.ellipsis { .ellipsis {

View File

@@ -249,12 +249,15 @@ onMounted(async () => {
.page-stack { .page-stack {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 12px; gap: 14px;
min-width: 0;
} }
.card { .card {
border-radius: var(--app-radius); border-radius: var(--app-radius);
border: 1px solid var(--app-border); border: 1px solid var(--app-border);
background: var(--app-card-bg);
box-shadow: var(--app-shadow-soft);
} }
.filters { .filters {
@@ -266,6 +269,9 @@ onMounted(async () => {
.table-wrap { .table-wrap {
overflow-x: auto; overflow-x: auto;
border-radius: 10px;
border: 1px solid var(--app-border);
background: #fff;
} }
.ellipsis { .ellipsis {

View File

@@ -20,6 +20,7 @@ import { fetchEmailStats } from '../api/email'
import { fetchDockerStats, fetchRunningTasks, fetchServerInfo, fetchTaskStats } from '../api/tasks' import { fetchDockerStats, fetchRunningTasks, fetchServerInfo, fetchTaskStats } from '../api/tasks'
import { fetchBrowserPoolStats } from '../api/browser_pool' import { fetchBrowserPoolStats } from '../api/browser_pool'
import { fetchSystemConfig } from '../api/system' import { fetchSystemConfig } from '../api/system'
import MetricGrid from '../components/MetricGrid.vue'
const refreshStats = inject('refreshStats', null) const refreshStats = inject('refreshStats', null)
const adminStats = inject('adminStats', null) const adminStats = inject('adminStats', null)
@@ -143,6 +144,50 @@ const taskTodaySuccessRate = computed(() => {
const emailSuccessRate = computed(() => normalizeCount(emailStats.value?.success_rate)) const emailSuccessRate = computed(() => normalizeCount(emailStats.value?.success_rate))
const taskTodayCards = computed(() => [
{ label: '总任务', value: normalizeCount(taskToday.value.total_tasks), tone: 'blue' },
{ label: '成功', value: normalizeCount(taskToday.value.success_tasks), tone: 'green' },
{ label: '失败', value: normalizeCount(taskToday.value.failed_tasks), tone: 'red' },
{ label: '浏览内容', value: normalizeCount(taskToday.value.total_items), tone: 'purple' },
{ label: '查看附件', value: normalizeCount(taskToday.value.total_attachments), tone: 'cyan' },
])
const taskTotalCards = computed(() => [
{ label: '总任务', value: normalizeCount(taskTotal.value.total_tasks), tone: 'blue' },
{ label: '成功', value: normalizeCount(taskTotal.value.success_tasks), tone: 'green' },
{ label: '失败', value: normalizeCount(taskTotal.value.failed_tasks), tone: 'red' },
{ label: '浏览内容', value: normalizeCount(taskTotal.value.total_items), tone: 'purple' },
{ label: '查看附件', value: normalizeCount(taskTotal.value.total_attachments), tone: 'cyan' },
])
const emailCards = computed(() => [
{ label: '总发送', value: normalizeCount(emailStats.value?.total_sent), tone: 'blue' },
{ label: '成功', value: normalizeCount(emailStats.value?.total_success), tone: 'green' },
{ label: '失败', value: normalizeCount(emailStats.value?.total_failed), tone: 'red' },
{ label: '成功率', value: `${emailSuccessRate.value}%`, tone: 'purple' },
])
const emailTypeCards = computed(() => [
{ label: '注册验证', value: normalizeCount(emailStats.value?.register_sent), tone: 'cyan' },
{ label: '密码重置', value: normalizeCount(emailStats.value?.reset_sent), tone: 'orange' },
{ label: '邮箱绑定', value: normalizeCount(emailStats.value?.bind_sent), tone: 'purple' },
{ label: '任务完成', value: normalizeCount(emailStats.value?.task_complete_sent), tone: 'green' },
])
const feedbackCards = computed(() => [
{ label: '总反馈', value: normalizeCount(feedbackStats.value?.total), tone: 'blue' },
{ label: '待处理', value: normalizeCount(feedbackStats.value?.pending), tone: 'orange' },
{ label: '已回复', value: normalizeCount(feedbackStats.value?.replied), tone: 'green' },
])
const browserPoolCards = computed(() => [
{ label: '总 Worker', value: browserPoolTotalWorkers.value, tone: 'blue' },
{ label: '活跃 Worker', value: browserPoolActiveWorkers.value, tone: 'green' },
{ label: '空闲 Worker', value: browserPoolIdleWorkers.value, tone: 'cyan' },
{ label: '忙碌 Worker', value: browserPoolBusyWorkers.value, tone: 'orange' },
{ label: '队列', value: browserPoolQueueSize.value, tone: 'purple' },
])
const scheduleEnabled = computed(() => (systemConfig.value?.schedule_enabled ?? 0) === 1) const scheduleEnabled = computed(() => (systemConfig.value?.schedule_enabled ?? 0) === 1)
const scheduleTime = computed(() => systemConfig.value?.schedule_time || '-') const scheduleTime = computed(() => systemConfig.value?.schedule_time || '-')
const scheduleBrowseType = computed(() => systemConfig.value?.schedule_browse_type || '-') const scheduleBrowseType = computed(() => systemConfig.value?.schedule_browse_type || '-')
@@ -250,12 +295,10 @@ onUnmounted(() => {
<template> <template>
<div class="page-stack"> <div class="page-stack">
<div class="hero"> <section class="report-hero">
<div class="hero-top"> <div class="hero-head">
<div class="hero-title"> <div class="hero-main">
<div class="hero-title-row">
<h2>报表中心</h2> <h2>报表中心</h2>
</div>
<div class="hero-meta app-muted"> <div class="hero-meta app-muted">
<span v-if="lastUpdatedAt">更新时间{{ lastUpdatedAt }}</span> <span v-if="lastUpdatedAt">更新时间{{ lastUpdatedAt }}</span>
<span v-if="serverInfo?.uptime" class="hero-dot">·</span> <span v-if="serverInfo?.uptime" class="hero-dot">·</span>
@@ -264,23 +307,12 @@ onUnmounted(() => {
</div> </div>
<div class="hero-actions"> <div class="hero-actions">
<el-button type="primary" plain :loading="loading" @click="manualRefresh">刷新</el-button> <el-button type="primary" :loading="loading" @click="manualRefresh">刷新数据</el-button>
</div> </div>
</div> </div>
<div class="kpi-grid"> <MetricGrid :items="overviewCards" :loading="loading" :min-width="165" />
<div v-for="c in overviewCards" :key="c.label" class="kpi-card" :class="`kpi-tone--${c.tone}`"> </section>
<div class="kpi-icon">
<el-icon><component :is="c.icon" /></el-icon>
</div>
<div class="kpi-body">
<div class="kpi-value">{{ c.value }}</div>
<div class="kpi-label">{{ c.label }}</div>
<div v-if="c.sub" class="kpi-sub app-muted">{{ c.sub }}</div>
</div>
</div>
</div>
</div>
<el-row :gutter="12"> <el-row :gutter="12">
<el-col :xs="24" :lg="12"> <el-col :xs="24" :lg="12">
@@ -309,58 +341,16 @@ onUnmounted(() => {
/> />
</div> </div>
<div class="tile-section"> <div class="metrics-block">
<div class="tile-title app-muted">今日</div> <div class="block-title">今日</div>
<div class="tile-grid"> <MetricGrid :items="taskTodayCards" :loading="refreshing" :min-width="120" />
<div class="tile">
<div class="tile-v">{{ normalizeCount(taskToday.total_tasks) }}</div>
<div class="tile-k app-muted">总任务</div>
</div>
<div class="tile">
<div class="tile-v ok">{{ normalizeCount(taskToday.success_tasks) }}</div>
<div class="tile-k app-muted">成功</div>
</div>
<div class="tile">
<div class="tile-v err">{{ normalizeCount(taskToday.failed_tasks) }}</div>
<div class="tile-k app-muted">失败</div>
</div>
<div class="tile">
<div class="tile-v">{{ normalizeCount(taskToday.total_items) }}</div>
<div class="tile-k app-muted">浏览内容</div>
</div>
<div class="tile">
<div class="tile-v">{{ normalizeCount(taskToday.total_attachments) }}</div>
<div class="tile-k app-muted">查看附件</div>
</div>
</div>
</div> </div>
<div class="divider"></div> <div class="divider"></div>
<div class="tile-section"> <div class="metrics-block">
<div class="tile-title app-muted">累计</div> <div class="block-title">累计</div>
<div class="tile-grid"> <MetricGrid :items="taskTotalCards" :loading="refreshing" :min-width="120" />
<div class="tile">
<div class="tile-v">{{ normalizeCount(taskTotal.total_tasks) }}</div>
<div class="tile-k app-muted">总任务</div>
</div>
<div class="tile">
<div class="tile-v ok">{{ normalizeCount(taskTotal.success_tasks) }}</div>
<div class="tile-k app-muted">成功</div>
</div>
<div class="tile">
<div class="tile-v err">{{ normalizeCount(taskTotal.failed_tasks) }}</div>
<div class="tile-k app-muted">失败</div>
</div>
<div class="tile">
<div class="tile-v">{{ normalizeCount(taskTotal.total_items) }}</div>
<div class="tile-k app-muted">浏览内容</div>
</div>
<div class="tile">
<div class="tile-v">{{ normalizeCount(taskTotal.total_attachments) }}</div>
<div class="tile-k app-muted">查看附件</div>
</div>
</div>
</div> </div>
</el-card> </el-card>
</el-col> </el-col>
@@ -466,41 +456,13 @@ onUnmounted(() => {
</div> </div>
</div> </div>
<div class="tile-grid tile-grid--3"> <MetricGrid :items="emailCards" :loading="refreshing" :min-width="132" />
<div class="tile">
<div class="tile-v">{{ normalizeCount(emailStats?.total_sent) }}</div>
<div class="tile-k app-muted">总发送</div>
</div>
<div class="tile">
<div class="tile-v ok">{{ normalizeCount(emailStats?.total_success) }}</div>
<div class="tile-k app-muted">成功</div>
</div>
<div class="tile">
<div class="tile-v err">{{ normalizeCount(emailStats?.total_failed) }}</div>
<div class="tile-k app-muted">失败</div>
</div>
</div>
<div class="divider"></div> <div class="divider"></div>
<div class="sub-title">类型统计</div> <div class="metrics-block">
<div class="type-grid"> <div class="block-title">类型统计</div>
<div class="type-item"> <MetricGrid :items="emailTypeCards" :loading="refreshing" :min-width="132" />
<div class="type-v">{{ normalizeCount(emailStats?.register_sent) }}</div>
<div class="type-k app-muted">注册验证</div>
</div>
<div class="type-item">
<div class="type-v">{{ normalizeCount(emailStats?.reset_sent) }}</div>
<div class="type-k app-muted">密码重置</div>
</div>
<div class="type-item">
<div class="type-v">{{ normalizeCount(emailStats?.bind_sent) }}</div>
<div class="type-k app-muted">邮箱绑定</div>
</div>
<div class="type-item">
<div class="type-v">{{ normalizeCount(emailStats?.task_complete_sent) }}</div>
<div class="type-k app-muted">任务完成</div>
</div>
</div> </div>
</el-card> </el-card>
</el-col> </el-col>
@@ -519,24 +481,9 @@ onUnmounted(() => {
</div> </div>
</div> </div>
<div class="tile-grid tile-grid--3"> <MetricGrid :items="feedbackCards" :loading="refreshing" :min-width="145" />
<div class="tile">
<div class="tile-v">{{ normalizeCount(feedbackStats?.total) }}</div>
<div class="tile-k app-muted">总反馈</div>
</div>
<div class="tile">
<div class="tile-v warn">{{ normalizeCount(feedbackStats?.pending) }}</div>
<div class="tile-k app-muted">待处理</div>
</div>
<div class="tile">
<div class="tile-v ok">{{ normalizeCount(feedbackStats?.replied) }}</div>
<div class="tile-k app-muted">已回复</div>
</div>
</div>
<div class="divider"></div> <div class="help app-muted">提示反馈处理越及时用户留存与满意度越高</div>
<div class="help app-muted">提示用户的反馈需要及时处理避免影响活跃度与留存</div>
</el-card> </el-card>
</el-col> </el-col>
</el-row> </el-row>
@@ -590,7 +537,7 @@ onUnmounted(() => {
<div class="divider"></div> <div class="divider"></div>
<div class="sub-title">容器</div> <div class="block-title">容器</div>
<el-descriptions border :column="2" size="small"> <el-descriptions border :column="2" size="small">
<el-descriptions-item label="状态">{{ dockerStats?.status || '-' }}</el-descriptions-item> <el-descriptions-item label="状态">{{ dockerStats?.status || '-' }}</el-descriptions-item>
<el-descriptions-item label="容器名">{{ dockerStats?.container_name || '-' }}</el-descriptions-item> <el-descriptions-item label="容器名">{{ dockerStats?.container_name || '-' }}</el-descriptions-item>
@@ -614,24 +561,7 @@ onUnmounted(() => {
<el-tag v-if="browserPoolStats?.server_time_cst" effect="light" type="info">{{ browserPoolStats.server_time_cst }}</el-tag> <el-tag v-if="browserPoolStats?.server_time_cst" effect="light" type="info">{{ browserPoolStats.server_time_cst }}</el-tag>
</div> </div>
<div class="tile-grid tile-grid--4"> <MetricGrid :items="browserPoolCards" :loading="refreshing" :min-width="120" />
<div class="tile">
<div class="tile-v">{{ browserPoolTotalWorkers }}</div>
<div class="tile-k app-muted"> Worker</div>
</div>
<div class="tile">
<div class="tile-v ok">{{ browserPoolActiveWorkers }}</div>
<div class="tile-k app-muted">活跃有执行环境</div>
</div>
<div class="tile">
<div class="tile-v">{{ browserPoolIdleWorkers }}</div>
<div class="tile-k app-muted">空闲无任务</div>
</div>
<div class="tile">
<div class="tile-v warn">{{ browserPoolQueueSize }}</div>
<div class="tile-k app-muted">队列等待</div>
</div>
</div>
<div class="divider"></div> <div class="divider"></div>
@@ -722,7 +652,7 @@ onUnmounted(() => {
gap: 14px; gap: 14px;
} }
.hero { .report-hero {
position: relative; position: relative;
overflow: hidden; overflow: hidden;
border-radius: 18px; border-radius: 18px;
@@ -730,31 +660,24 @@ onUnmounted(() => {
background: radial-gradient(circle at 10% 10%, rgba(59, 130, 246, 0.18), transparent 48%), background: radial-gradient(circle at 10% 10%, rgba(59, 130, 246, 0.18), transparent 48%),
radial-gradient(circle at 80% 0%, rgba(236, 72, 153, 0.16), transparent 45%), radial-gradient(circle at 80% 0%, rgba(236, 72, 153, 0.16), transparent 45%),
radial-gradient(circle at 90% 90%, rgba(16, 185, 129, 0.14), transparent 42%), radial-gradient(circle at 90% 90%, rgba(16, 185, 129, 0.14), transparent 42%),
rgba(255, 255, 255, 0.65); rgba(255, 255, 255, 0.72);
box-shadow: 0 14px 40px rgba(15, 23, 42, 0.08); box-shadow: 0 14px 40px rgba(15, 23, 42, 0.08);
backdrop-filter: saturate(180%) blur(12px); backdrop-filter: saturate(180%) blur(12px);
padding: 16px; padding: 16px;
} }
.hero-top { .hero-head {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
justify-content: space-between; justify-content: space-between;
gap: 10px; gap: 12px;
flex-wrap: wrap; flex-wrap: wrap;
margin-bottom: 14px; margin-bottom: 14px;
} }
.hero-title-row { .hero-main h2 {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
}
.hero-title h2 {
margin: 0; margin: 0;
font-size: 18px; font-size: 19px;
font-weight: 900; font-weight: 900;
letter-spacing: 0.2px; letter-spacing: 0.2px;
} }
@@ -763,9 +686,9 @@ onUnmounted(() => {
margin-top: 6px; margin-top: 6px;
font-size: 12px; font-size: 12px;
display: flex; display: flex;
align-items: center;
flex-wrap: wrap; flex-wrap: wrap;
gap: 8px; gap: 8px;
align-items: center;
} }
.hero-dot { .hero-dot {
@@ -779,140 +702,10 @@ onUnmounted(() => {
flex-wrap: wrap; flex-wrap: wrap;
} }
.kpi-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 12px;
}
.kpi-card {
position: relative;
overflow: hidden;
border-radius: 16px;
border: 1px solid rgba(17, 24, 39, 0.1);
background: rgba(255, 255, 255, 0.7);
box-shadow: 0 12px 32px rgba(15, 23, 42, 0.08);
padding: 14px;
display: flex;
gap: 12px;
align-items: flex-start;
transition:
transform 160ms ease,
box-shadow 160ms ease,
border-color 160ms ease;
}
.kpi-card::before {
content: '';
position: absolute;
inset: 0;
background: var(--kpi-grad, transparent);
opacity: 0.9;
pointer-events: none;
}
.kpi-card::after {
content: '';
position: absolute;
left: 0;
top: 0;
right: 0;
height: 3px;
background: var(--kpi-top, transparent);
opacity: 0.9;
pointer-events: none;
}
.kpi-card:hover {
transform: translateY(-2px);
box-shadow: 0 18px 40px rgba(15, 23, 42, 0.12);
border-color: rgba(17, 24, 39, 0.14);
}
.kpi-icon {
position: relative;
z-index: 1;
width: 38px;
height: 38px;
border-radius: 14px;
display: flex;
align-items: center;
justify-content: center;
background: var(--kpi-icon-bg, rgba(59, 130, 246, 0.14));
color: var(--kpi-icon-color, #1d4ed8);
border: 1px solid rgba(17, 24, 39, 0.08);
flex: 0 0 auto;
}
.kpi-body {
position: relative;
z-index: 1;
min-width: 0;
}
.kpi-value {
font-size: 22px;
font-weight: 900;
line-height: 1.1;
}
.kpi-label {
margin-top: 6px;
font-size: 12px;
color: rgba(17, 24, 39, 0.7);
}
.kpi-sub {
margin-top: 6px;
font-size: 12px;
}
.kpi-tone--blue {
--kpi-grad: linear-gradient(135deg, rgba(59, 130, 246, 0.14), rgba(6, 182, 212, 0.1));
--kpi-top: linear-gradient(90deg, #3b82f6, #06b6d4);
--kpi-icon-bg: rgba(59, 130, 246, 0.14);
--kpi-icon-color: #1d4ed8;
}
.kpi-tone--green {
--kpi-grad: linear-gradient(135deg, rgba(16, 185, 129, 0.14), rgba(34, 197, 94, 0.1));
--kpi-top: linear-gradient(90deg, #10b981, #22c55e);
--kpi-icon-bg: rgba(16, 185, 129, 0.14);
--kpi-icon-color: #047857;
}
.kpi-tone--purple {
--kpi-grad: linear-gradient(135deg, rgba(139, 92, 246, 0.14), rgba(236, 72, 153, 0.1));
--kpi-top: linear-gradient(90deg, #8b5cf6, #ec4899);
--kpi-icon-bg: rgba(139, 92, 246, 0.14);
--kpi-icon-color: #6d28d9;
}
.kpi-tone--orange {
--kpi-grad: linear-gradient(135deg, rgba(245, 158, 11, 0.14), rgba(249, 115, 22, 0.1));
--kpi-top: linear-gradient(90deg, #f59e0b, #f97316);
--kpi-icon-bg: rgba(245, 158, 11, 0.14);
--kpi-icon-color: #b45309;
}
.kpi-tone--red {
--kpi-grad: linear-gradient(135deg, rgba(239, 68, 68, 0.14), rgba(244, 63, 94, 0.1));
--kpi-top: linear-gradient(90deg, #ef4444, #f43f5e);
--kpi-icon-bg: rgba(239, 68, 68, 0.14);
--kpi-icon-color: #b91c1c;
}
.kpi-tone--cyan {
--kpi-grad: linear-gradient(135deg, rgba(34, 211, 238, 0.14), rgba(59, 130, 246, 0.1));
--kpi-top: linear-gradient(90deg, #22d3ee, #3b82f6);
--kpi-icon-bg: rgba(34, 211, 238, 0.14);
--kpi-icon-color: #0369a1;
}
.panel { .panel {
border-radius: 18px; border-radius: 18px;
border: 1px solid rgba(17, 24, 39, 0.1); border: 1px solid rgba(17, 24, 39, 0.1);
background: rgba(255, 255, 255, 0.7); background: rgba(255, 255, 255, 0.72);
box-shadow: var(--app-shadow); box-shadow: var(--app-shadow);
backdrop-filter: saturate(180%) blur(10px); backdrop-filter: saturate(180%) blur(10px);
} }
@@ -991,60 +784,16 @@ onUnmounted(() => {
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.tile-section { .metrics-block {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 10px; gap: 10px;
} }
.tile-title { .block-title {
font-size: 12px; font-size: 13px;
font-weight: 800;
letter-spacing: 0.2px;
}
.tile-grid {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 10px;
}
.tile-grid--3 {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.tile-grid--4 {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.tile {
border: 1px solid rgba(17, 24, 39, 0.08);
border-radius: 16px;
padding: 12px;
background: rgba(255, 255, 255, 0.65);
}
.tile-v {
font-size: 18px;
font-weight: 900; font-weight: 900;
line-height: 1.1; letter-spacing: 0.2px;
}
.tile-k {
margin-top: 6px;
font-size: 12px;
}
.ok {
color: #047857;
}
.warn {
color: #b45309;
}
.err {
color: #b91c1c;
} }
.divider { .divider {
@@ -1063,38 +812,11 @@ onUnmounted(() => {
gap: 6px; gap: 6px;
} }
.sub-title {
font-size: 13px;
font-weight: 900;
margin-bottom: 10px;
letter-spacing: 0.2px;
}
.type-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
}
.type-item {
border: 1px solid rgba(17, 24, 39, 0.08);
border-radius: 16px;
padding: 12px;
background: rgba(255, 255, 255, 0.65);
}
.type-v {
font-size: 16px;
font-weight: 900;
}
.type-k {
margin-top: 6px;
font-size: 12px;
}
.table-wrap { .table-wrap {
overflow-x: auto; overflow-x: auto;
border-radius: 10px;
border: 1px solid var(--app-border);
background: #fff;
} }
.help { .help {
@@ -1112,7 +834,7 @@ onUnmounted(() => {
border: 1px solid rgba(17, 24, 39, 0.08); border: 1px solid rgba(17, 24, 39, 0.08);
border-radius: 16px; border-radius: 16px;
padding: 12px; padding: 12px;
background: rgba(255, 255, 255, 0.65); background: rgba(255, 255, 255, 0.7);
} }
.resource-k { .resource-k {
@@ -1135,7 +857,7 @@ onUnmounted(() => {
border: 1px solid rgba(17, 24, 39, 0.08); border: 1px solid rgba(17, 24, 39, 0.08);
border-radius: 16px; border-radius: 16px;
padding: 12px; padding: 12px;
background: rgba(255, 255, 255, 0.65); background: rgba(255, 255, 255, 0.7);
} }
.config-k { .config-k {
@@ -1166,6 +888,10 @@ onUnmounted(() => {
font-size: 12px; font-size: 12px;
} }
.err {
color: #b91c1c;
}
:deep(.el-table) { :deep(.el-table) {
--el-table-border-color: rgba(17, 24, 39, 0.08); --el-table-border-color: rgba(17, 24, 39, 0.08);
--el-table-header-bg-color: rgba(246, 247, 251, 0.8); --el-table-header-bg-color: rgba(246, 247, 251, 0.8);
@@ -1176,30 +902,8 @@ onUnmounted(() => {
} }
@media (max-width: 768px) { @media (max-width: 768px) {
.kpi-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.tile-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.tile-grid--3 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.tile-grid--4 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.resource-grid { .resource-grid {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
} }
@media (max-width: 520px) {
.kpi-grid {
grid-template-columns: 1fr;
}
}
</style> </style>

View File

@@ -16,6 +16,7 @@ import {
unbanIp, unbanIp,
unbanUser, unbanUser,
} from '../api/security' } from '../api/security'
import MetricGrid from '../components/MetricGrid.vue'
const pageSize = 20 const pageSize = 20
@@ -119,9 +120,27 @@ const threatTypeOptions = computed(() => {
const dashboardCards = computed(() => { const dashboardCards = computed(() => {
const d = dashboard.value || {} const d = dashboard.value || {}
return [ return [
{ key: 'threat_events_24h', label: '最近24小时威胁事件', value: normalizeCount(d.threat_events_24h) }, {
{ key: 'banned_ip_count', label: '当前封禁IP数', value: normalizeCount(d.banned_ip_count) }, key: 'threat_events_24h',
{ key: 'banned_user_count', label: '当前封禁用户数', value: normalizeCount(d.banned_user_count) }, label: '最近24小时威胁事件',
value: normalizeCount(d.threat_events_24h),
tone: 'red',
hint: '用于衡量当前攻击面活跃度',
},
{
key: 'banned_ip_count',
label: '当前封禁 IP 数',
value: normalizeCount(d.banned_ip_count),
tone: 'orange',
hint: '自动与人工封禁总量',
},
{
key: 'banned_user_count',
label: '当前封禁用户数',
value: normalizeCount(d.banned_user_count),
tone: 'purple',
hint: '高风险账户拦截情况',
},
] ]
}) })
@@ -452,17 +471,7 @@ onMounted(async () => {
</div> </div>
</div> </div>
<el-row :gutter="12" class="stats-row"> <MetricGrid :items="dashboardCards" :loading="dashboardLoading" :min-width="220" />
<el-col v-for="it in dashboardCards" :key="it.key" :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<el-card shadow="never" class="stat-card" :body-style="{ padding: '14px' }">
<div class="stat-value">
<el-skeleton v-if="dashboardLoading" :rows="1" animated />
<template v-else>{{ it.value }}</template>
</div>
<div class="stat-label">{{ it.label }}</div>
</el-card>
</el-col>
</el-row>
<el-card shadow="never" :body-style="{ padding: '16px' }" class="card"> <el-card shadow="never" :body-style="{ padding: '16px' }" class="card">
<el-tabs v-model="activeTab"> <el-tabs v-model="activeTab">
@@ -731,7 +740,8 @@ onMounted(async () => {
.page-stack { .page-stack {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 12px; gap: 14px;
min-width: 0;
} }
.toolbar { .toolbar {
@@ -741,13 +751,12 @@ onMounted(async () => {
flex-wrap: wrap; flex-wrap: wrap;
} }
.stats-row {
margin-bottom: 2px;
}
.card { .card {
border-radius: var(--app-radius); border-radius: var(--app-radius);
border: 1px solid var(--app-border); border: 1px solid var(--app-border);
background: var(--app-card-bg);
box-shadow: var(--app-shadow-soft);
} }
.sub-card { .sub-card {
@@ -756,23 +765,6 @@ onMounted(async () => {
border: 1px solid var(--app-border); border: 1px solid var(--app-border);
} }
.stat-card {
border-radius: var(--app-radius);
border: 1px solid var(--app-border);
box-shadow: var(--app-shadow);
}
.stat-value {
font-size: 22px;
font-weight: 800;
line-height: 1.1;
}
.stat-label {
margin-top: 6px;
font-size: 12px;
color: var(--app-muted);
}
.filters { .filters {
display: flex; display: flex;
@@ -784,6 +776,9 @@ onMounted(async () => {
.table-wrap { .table-wrap {
overflow-x: auto; overflow-x: auto;
border-radius: 10px;
border: 1px solid var(--app-border);
background: #fff;
} }
.ellipsis { .ellipsis {

View File

@@ -132,18 +132,22 @@ async function savePassword() {
.page-stack { .page-stack {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 12px; gap: 14px;
min-width: 0;
} }
.card { .card {
border-radius: var(--app-radius); border-radius: var(--app-radius);
border: 1px solid var(--app-border); border: 1px solid var(--app-border);
background: var(--app-card-bg);
box-shadow: var(--app-shadow-soft);
} }
.section-title { .section-title {
margin: 0 0 12px; margin: 0 0 12px;
font-size: 14px; font-size: 15px;
font-weight: 800; font-weight: 800;
letter-spacing: 0.2px;
} }
.help { .help {

View File

@@ -642,18 +642,22 @@ onMounted(loadAll)
.page-stack { .page-stack {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 12px; gap: 14px;
min-width: 0;
} }
.card { .card {
border-radius: var(--app-radius); border-radius: var(--app-radius);
border: 1px solid var(--app-border); border: 1px solid var(--app-border);
background: var(--app-card-bg);
box-shadow: var(--app-shadow-soft);
} }
.section-title { .section-title {
margin: 0 0 12px; margin: 0 0 12px;
font-size: 14px; font-size: 15px;
font-weight: 800; font-weight: 800;
letter-spacing: 0.2px;
} }
.kdocs-qr { .kdocs-qr {

View File

@@ -285,18 +285,22 @@ onMounted(refreshAll)
.page-stack { .page-stack {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 12px; gap: 14px;
min-width: 0;
} }
.card { .card {
border-radius: var(--app-radius); border-radius: var(--app-radius);
border: 1px solid var(--app-border); border: 1px solid var(--app-border);
background: var(--app-card-bg);
box-shadow: var(--app-shadow-soft);
} }
.section-title { .section-title {
margin: 0 0 12px; margin: 0 0 12px;
font-size: 14px; font-size: 15px;
font-weight: 800; font-weight: 800;
letter-spacing: 0.2px;
} }
.help { .help {
@@ -306,6 +310,9 @@ onMounted(refreshAll)
.table-wrap { .table-wrap {
overflow-x: auto; overflow-x: auto;
border-radius: 10px;
border: 1px solid var(--app-border);
background: #fff;
} }
.user-block { .user-block {

View File

@@ -1,10 +1,14 @@
:root { :root {
--app-bg: #f6f7fb; --app-bg: #f4f6fb;
--app-text: #111827; --app-text: #111827;
--app-muted: #6b7280; --app-muted: #6b7280;
--app-border: rgba(17, 24, 39, 0.08); --app-border: rgba(15, 23, 42, 0.1);
--app-border-strong: rgba(15, 23, 42, 0.14);
--app-radius: 12px; --app-radius: 12px;
--app-shadow: 0 8px 24px rgba(17, 24, 39, 0.06); --app-radius-lg: 14px;
--app-shadow-soft: 0 8px 24px rgba(15, 23, 42, 0.05);
--app-shadow: 0 12px 30px rgba(15, 23, 42, 0.08);
--app-card-bg: rgba(255, 255, 255, 0.94);
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif; 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;
@@ -20,10 +24,17 @@ body,
height: 100%; height: 100%;
} }
* {
box-sizing: border-box;
}
body { body {
margin: 0; margin: 0;
background: var(--app-bg);
color: var(--app-text); color: var(--app-text);
background:
radial-gradient(1200px 500px at -10% -10%, rgba(59, 130, 246, 0.12), transparent 55%),
radial-gradient(1000px 420px at 110% 0%, rgba(139, 92, 246, 0.1), transparent 50%),
var(--app-bg);
} }
a { a {
@@ -36,13 +47,13 @@ a {
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
gap: 12px; gap: 12px;
margin: 0 0 12px; margin: 0 0 14px;
} }
.app-page-title h2 { .app-page-title h2 {
margin: 0; margin: 0;
font-size: 18px; font-size: 19px;
font-weight: 700; font-weight: 800;
letter-spacing: 0.2px; letter-spacing: 0.2px;
} }
@@ -50,12 +61,72 @@ a {
color: var(--app-muted); color: var(--app-muted);
} }
.page-stack {
display: flex;
flex-direction: column;
gap: 14px;
min-width: 0;
}
.el-card {
border-radius: var(--app-radius-lg);
border: 1px solid var(--app-border);
background: var(--app-card-bg);
box-shadow: var(--app-shadow-soft);
}
.el-button {
border-radius: 10px;
font-weight: 600;
}
.el-input__wrapper,
.el-textarea__inner,
.el-select__wrapper,
.el-input-number,
.el-picker__wrapper {
border-radius: 10px;
}
.el-table {
border-radius: 10px;
overflow: hidden;
}
.el-table th.el-table__cell {
background: #f8fafc;
color: #334155;
font-weight: 700;
}
.el-table td.el-table__cell,
.el-table th.el-table__cell {
padding-top: 11px;
padding-bottom: 11px;
}
.el-table .el-table__row:hover > td.el-table__cell {
background: #f8fbff;
}
.el-tag {
border-radius: 999px;
}
.el-dialog {
border-radius: var(--app-radius-lg);
}
@media (max-width: 768px) { @media (max-width: 768px) {
.app-page-title { .app-page-title {
flex-wrap: wrap; flex-wrap: wrap;
align-items: flex-start; align-items: flex-start;
} }
.app-page-title h2 {
font-size: 17px;
}
.el-dialog { .el-dialog {
max-width: 92vw; max-width: 92vw;
} }
@@ -78,3 +149,59 @@ a {
width: 100%; width: 100%;
} }
} }
.section-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
flex-wrap: wrap;
}
.section-title {
margin: 0;
font-size: 15px;
font-weight: 800;
letter-spacing: 0.2px;
}
.toolbar {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
}
.table-wrap {
overflow-x: auto;
border-radius: 10px;
border: 1px solid var(--app-border);
background: #fff;
}
.pagination {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
margin-top: 14px;
flex-wrap: wrap;
}
.page-hint {
font-size: 12px;
}
.el-tabs__item {
font-weight: 700;
}
.el-form-item {
margin-bottom: 18px;
}
@media (max-width: 768px) {
.pagination {
justify-content: flex-start;
}
}

View File

@@ -308,11 +308,6 @@ onMounted(async () => {
<span>还没有账号</span> <span>还没有账号</span>
<button type="button" class="link-btn" @click="goRegister">立即注册</button> <button type="button" class="link-btn" @click="goRegister">立即注册</button>
</div> </div>
<div class="back-link">
<span>管理员请前往</span>
<a href="/yuyx">后台登录</a>
</div>
</div> </div>
<el-dialog v-model="forgotOpen" title="找回密码" width="min(560px, 92vw)"> <el-dialog v-model="forgotOpen" title="找回密码" width="min(560px, 92vw)">
@@ -549,23 +544,6 @@ onMounted(async () => {
font-size: 13px; font-size: 13px;
} }
.back-link {
text-align: center;
margin-top: 18px;
color: #6b7280;
font-size: 13px;
}
.back-link a {
margin-left: 6px;
color: #2563eb;
text-decoration: none;
font-weight: 700;
}
.back-link a:hover {
text-decoration: underline;
}
.dialog-form { .dialog-form {
margin-top: 10px; margin-top: 10px;

View File

@@ -1,34 +1,48 @@
{ {
"_email-C4xyG93p.js": { "_MetricGrid-W4bphIvI.js": {
"file": "assets/email-C4xyG93p.js", "file": "assets/MetricGrid-W4bphIvI.js",
"name": "MetricGrid",
"imports": [
"index.html"
],
"css": [
"assets/MetricGrid-yP_dkP6X.css"
]
},
"_MetricGrid-yP_dkP6X.css": {
"file": "assets/MetricGrid-yP_dkP6X.css",
"src": "_MetricGrid-yP_dkP6X.css"
},
"_email-CgV08DvO.js": {
"file": "assets/email-CgV08DvO.js",
"name": "email", "name": "email",
"imports": [ "imports": [
"index.html" "index.html"
] ]
}, },
"_system-C6kBIFhi.js": { "_system-XwnAZq10.js": {
"file": "assets/system-C6kBIFhi.js", "file": "assets/system-XwnAZq10.js",
"name": "system", "name": "system",
"imports": [ "imports": [
"index.html" "index.html"
] ]
}, },
"_tasks-dxahzB_w.js": { "_tasks-xgGctksM.js": {
"file": "assets/tasks-dxahzB_w.js", "file": "assets/tasks-xgGctksM.js",
"name": "tasks", "name": "tasks",
"imports": [ "imports": [
"index.html" "index.html"
] ]
}, },
"_users-ecMaaAFD.js": { "_users-D07hXCyn.js": {
"file": "assets/users-ecMaaAFD.js", "file": "assets/users-D07hXCyn.js",
"name": "users", "name": "users",
"imports": [ "imports": [
"index.html" "index.html"
] ]
}, },
"index.html": { "index.html": {
"file": "assets/index-DKH_HvPt.js", "file": "assets/index-Bd3qzysl.js",
"name": "index", "name": "index",
"src": "index.html", "src": "index.html",
"isEntry": true, "isEntry": true,
@@ -44,11 +58,11 @@
"src/pages/SettingsPage.vue" "src/pages/SettingsPage.vue"
], ],
"css": [ "css": [
"assets/index-_5Ec1Hmd.css" "assets/index-Gi1T-zxa.css"
] ]
}, },
"src/pages/AnnouncementsPage.vue": { "src/pages/AnnouncementsPage.vue": {
"file": "assets/AnnouncementsPage-kpoSCxEP.js", "file": "assets/AnnouncementsPage-C4Nx-yDs.js",
"name": "AnnouncementsPage", "name": "AnnouncementsPage",
"src": "src/pages/AnnouncementsPage.vue", "src": "src/pages/AnnouncementsPage.vue",
"isDynamicEntry": true, "isDynamicEntry": true,
@@ -56,77 +70,81 @@
"index.html" "index.html"
], ],
"css": [ "css": [
"assets/AnnouncementsPage-BhIwmMSX.css" "assets/AnnouncementsPage-1S2fTjRW.css"
] ]
}, },
"src/pages/EmailPage.vue": { "src/pages/EmailPage.vue": {
"file": "assets/EmailPage-CEtsoP5P.js", "file": "assets/EmailPage-DV2FB_3E.js",
"name": "EmailPage", "name": "EmailPage",
"src": "src/pages/EmailPage.vue", "src": "src/pages/EmailPage.vue",
"isDynamicEntry": true, "isDynamicEntry": true,
"imports": [ "imports": [
"_email-C4xyG93p.js", "_email-CgV08DvO.js",
"index.html" "index.html",
"_MetricGrid-W4bphIvI.js"
], ],
"css": [ "css": [
"assets/EmailPage-BH6ksrcc.css" "assets/EmailPage-BUCRqRf3.css"
] ]
}, },
"src/pages/FeedbacksPage.vue": { "src/pages/FeedbacksPage.vue": {
"file": "assets/FeedbacksPage-ByHln3Ce.js", "file": "assets/FeedbacksPage-CJdd3zlQ.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-W4bphIvI.js"
], ],
"css": [ "css": [
"assets/FeedbacksPage-BKNQYWPz.css" "assets/FeedbacksPage-OAEQDysw.css"
] ]
}, },
"src/pages/LogsPage.vue": { "src/pages/LogsPage.vue": {
"file": "assets/LogsPage-vZFAwgb-.js", "file": "assets/LogsPage-CE03Ev2z.js",
"name": "LogsPage", "name": "LogsPage",
"src": "src/pages/LogsPage.vue", "src": "src/pages/LogsPage.vue",
"isDynamicEntry": true, "isDynamicEntry": true,
"imports": [ "imports": [
"_users-ecMaaAFD.js", "_users-D07hXCyn.js",
"_tasks-dxahzB_w.js", "_tasks-xgGctksM.js",
"index.html" "index.html"
], ],
"css": [ "css": [
"assets/LogsPage-Cmm-qHAH.css" "assets/LogsPage-BX8Vwozm.css"
] ]
}, },
"src/pages/ReportPage.vue": { "src/pages/ReportPage.vue": {
"file": "assets/ReportPage--ClMBhif.js", "file": "assets/ReportPage-BVWvJbtL.js",
"name": "ReportPage", "name": "ReportPage",
"src": "src/pages/ReportPage.vue", "src": "src/pages/ReportPage.vue",
"isDynamicEntry": true, "isDynamicEntry": true,
"imports": [ "imports": [
"index.html", "index.html",
"_email-C4xyG93p.js", "_email-CgV08DvO.js",
"_tasks-dxahzB_w.js", "_tasks-xgGctksM.js",
"_system-C6kBIFhi.js" "_system-XwnAZq10.js",
"_MetricGrid-W4bphIvI.js"
], ],
"css": [ "css": [
"assets/ReportPage-Q8rCsG8A.css" "assets/ReportPage-BFOQHLC4.css"
] ]
}, },
"src/pages/SecurityPage.vue": { "src/pages/SecurityPage.vue": {
"file": "assets/SecurityPage-DBhX0IuO.js", "file": "assets/SecurityPage-CwG-un_5.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-W4bphIvI.js"
], ],
"css": [ "css": [
"assets/SecurityPage-Dv9jYTtC.css" "assets/SecurityPage-CQ0qfBKE.css"
] ]
}, },
"src/pages/SettingsPage.vue": { "src/pages/SettingsPage.vue": {
"file": "assets/SettingsPage-D91FOriC.js", "file": "assets/SettingsPage-D8X8xkDr.js",
"name": "SettingsPage", "name": "SettingsPage",
"src": "src/pages/SettingsPage.vue", "src": "src/pages/SettingsPage.vue",
"isDynamicEntry": true, "isDynamicEntry": true,
@@ -134,33 +152,33 @@
"index.html" "index.html"
], ],
"css": [ "css": [
"assets/SettingsPage-DKTq8S2K.css" "assets/SettingsPage-DaB8PeRL.css"
] ]
}, },
"src/pages/SystemPage.vue": { "src/pages/SystemPage.vue": {
"file": "assets/SystemPage-DVj-4Lnp.js", "file": "assets/SystemPage-D-4toRBK.js",
"name": "SystemPage", "name": "SystemPage",
"src": "src/pages/SystemPage.vue", "src": "src/pages/SystemPage.vue",
"isDynamicEntry": true, "isDynamicEntry": true,
"imports": [ "imports": [
"_system-C6kBIFhi.js", "_system-XwnAZq10.js",
"index.html" "index.html"
], ],
"css": [ "css": [
"assets/SystemPage-C8GQyKcD.css" "assets/SystemPage-DY4Ehu3c.css"
] ]
}, },
"src/pages/UsersPage.vue": { "src/pages/UsersPage.vue": {
"file": "assets/UsersPage-C_vL5-r3.js", "file": "assets/UsersPage-Cny_5hNj.js",
"name": "UsersPage", "name": "UsersPage",
"src": "src/pages/UsersPage.vue", "src": "src/pages/UsersPage.vue",
"isDynamicEntry": true, "isDynamicEntry": true,
"imports": [ "imports": [
"_users-ecMaaAFD.js", "_users-D07hXCyn.js",
"index.html" "index.html"
], ],
"css": [ "css": [
"assets/UsersPage-CC4Unpwt.css" "assets/UsersPage-UH4VKUOR.css"
] ]
} }
} }

View File

@@ -0,0 +1 @@
.page-stack[data-v-fe3cd445]{display:flex;flex-direction:column;gap:14px;min-width:0}.card[data-v-fe3cd445]{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-fe3cd445]{margin:0 0 12px;font-size:15px;font-weight:800;letter-spacing:.2px}.help[data-v-fe3cd445]{margin-top:10px;font-size:12px;color:var(--app-muted)}.image-preview[data-v-fe3cd445]{margin:6px 0 2px;display:flex;justify-content:flex-start}.image-preview img[data-v-fe3cd445]{max-width:280px;max-height:160px;border-radius:8px;border:1px solid var(--app-border);object-fit:contain}.image-upload-row[data-v-fe3cd445]{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.image-input[data-v-fe3cd445]{display:none}.image-url[data-v-fe3cd445]{font-size:12px;color:var(--app-muted);word-break:break-all}.announcement-view[data-v-fe3cd445]{display:flex;flex-direction:column;gap:12px}.announcement-view-text[data-v-fe3cd445]{white-space:pre-wrap;line-height:1.6;font-size:14px}.announcement-view-image[data-v-fe3cd445]{max-width:100%;max-height:320px;border-radius:10px;border:1px solid var(--app-border);object-fit:contain}.table-wrap[data-v-fe3cd445]{overflow-x:auto;border-radius:10px;border:1px solid var(--app-border);background:#fff}.ellipsis[data-v-fe3cd445]{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.actions[data-v-fe3cd445]{display:flex;flex-wrap:wrap;gap:8px}

View File

@@ -1 +0,0 @@
.page-stack[data-v-cad97d6b]{display:flex;flex-direction:column;gap:12px}.card[data-v-cad97d6b]{border-radius:var(--app-radius);border:1px solid var(--app-border)}.section-title[data-v-cad97d6b]{margin:0 0 12px;font-size:14px;font-weight:800}.help[data-v-cad97d6b]{margin-top:10px;font-size:12px;color:var(--app-muted)}.image-preview[data-v-cad97d6b]{margin:6px 0 2px;display:flex;justify-content:flex-start}.image-preview img[data-v-cad97d6b]{max-width:280px;max-height:160px;border-radius:8px;border:1px solid var(--app-border);object-fit:contain}.image-upload-row[data-v-cad97d6b]{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.image-input[data-v-cad97d6b]{display:none}.image-url[data-v-cad97d6b]{font-size:12px;color:var(--app-muted);word-break:break-all}.announcement-view[data-v-cad97d6b]{display:flex;flex-direction:column;gap:12px}.announcement-view-text[data-v-cad97d6b]{white-space:pre-wrap;line-height:1.6;font-size:14px}.announcement-view-image[data-v-cad97d6b]{max-width:100%;max-height:320px;border-radius:10px;border:1px solid var(--app-border);object-fit:contain}.table-wrap[data-v-cad97d6b]{overflow-x:auto}.ellipsis[data-v-cad97d6b]{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.actions[data-v-cad97d6b]{display:flex;flex-wrap:wrap;gap:8px}

View File

@@ -1 +0,0 @@
.page-stack[data-v-7a7e1e9d]{display:flex;flex-direction:column;gap:12px}.toolbar[data-v-7a7e1e9d]{display:flex;gap:10px;align-items:center;flex-wrap:wrap}.card[data-v-7a7e1e9d]{border-radius:var(--app-radius);border:1px solid var(--app-border)}.section-head[data-v-7a7e1e9d]{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:12px;flex-wrap:wrap}.section-title[data-v-7a7e1e9d]{margin:0;font-size:14px;font-weight:800}.help[data-v-7a7e1e9d]{margin-top:8px;font-size:12px;color:var(--app-muted)}.table-wrap[data-v-7a7e1e9d]{overflow-x:auto}.stat-card[data-v-7a7e1e9d]{border-radius:var(--app-radius);border:1px solid var(--app-border)}.stat-value[data-v-7a7e1e9d]{font-size:20px;font-weight:900;line-height:1.1}.stat-label[data-v-7a7e1e9d]{margin-top:6px;font-size:12px;color:var(--app-muted)}.ok[data-v-7a7e1e9d]{color:#047857}.err[data-v-7a7e1e9d]{color:#b91c1c}.sub-stats[data-v-7a7e1e9d]{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}.ellipsis[data-v-7a7e1e9d]{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pagination[data-v-7a7e1e9d]{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:14px;flex-wrap:wrap}.page-hint[data-v-7a7e1e9d]{font-size:12px}.dialog-actions[data-v-7a7e1e9d]{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.spacer[data-v-7a7e1e9d]{flex:1}

View File

@@ -0,0 +1 @@
.page-stack[data-v-f379c43d]{display:flex;flex-direction:column;gap:14px;min-width:0}.toolbar[data-v-f379c43d]{display:flex;gap:10px;align-items:center;flex-wrap:wrap}.card[data-v-f379c43d]{border-radius:var(--app-radius);border:1px solid var(--app-border);background:var(--app-card-bg);box-shadow:var(--app-shadow-soft)}.section-head[data-v-f379c43d]{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:12px;flex-wrap:wrap}.section-title[data-v-f379c43d]{margin:0;font-size:15px;font-weight:800;letter-spacing:.2px}.help[data-v-f379c43d]{margin-top:8px;font-size:12px;color:var(--app-muted)}.table-wrap[data-v-f379c43d]{overflow-x:auto;border-radius:10px;border:1px solid var(--app-border);background:#fff}.sub-stats[data-v-f379c43d]{margin-top:12px}.ellipsis[data-v-f379c43d]{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pagination[data-v-f379c43d]{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:14px;flex-wrap:wrap}.page-hint[data-v-f379c43d]{font-size:12px}.dialog-actions[data-v-f379c43d]{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.spacer[data-v-f379c43d]{flex:1}

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-97c1e509]{display:flex;flex-direction:column;gap:12px}.toolbar[data-v-97c1e509]{display:flex;gap:10px;align-items:center}.card[data-v-97c1e509],.stat-card[data-v-97c1e509]{border-radius:var(--app-radius);border:1px solid var(--app-border)}.stat-value[data-v-97c1e509]{font-size:20px;font-weight:800;line-height:1.1}.stat-label[data-v-97c1e509]{margin-top:6px;font-size:12px;color:var(--app-muted)}.warn[data-v-97c1e509]{color:#b45309}.ok[data-v-97c1e509]{color:#047857}.table-wrap[data-v-97c1e509]{overflow-x:auto}.ellipsis[data-v-97c1e509]{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.actions[data-v-97c1e509]{display:flex;flex-wrap:wrap;gap:8px}

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 @@
.page-stack[data-v-a383a5a0]{display:flex;flex-direction:column;gap:14px;min-width:0}.toolbar[data-v-a383a5a0]{display:flex;gap:10px;align-items:center;flex-wrap:wrap}.card[data-v-a383a5a0]{border-radius:var(--app-radius);border:1px solid var(--app-border);background:var(--app-card-bg);box-shadow:var(--app-shadow-soft)}.section-head[data-v-a383a5a0]{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:12px;flex-wrap:wrap}.section-title[data-v-a383a5a0]{margin:0;font-size:15px;font-weight:800}.table-wrap[data-v-a383a5a0]{overflow-x:auto;border-radius:10px;border:1px solid var(--app-border);background:#fff}.ellipsis[data-v-a383a5a0]{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.actions[data-v-a383a5a0]{display:flex;flex-wrap:wrap;gap:8px}

View File

@@ -0,0 +1 @@
.page-stack[data-v-d1dc979d]{display:flex;flex-direction:column;gap:14px;min-width:0}.card[data-v-d1dc979d]{border-radius:var(--app-radius);border:1px solid var(--app-border);background:var(--app-card-bg);box-shadow:var(--app-shadow-soft)}.filters[data-v-d1dc979d]{display:flex;flex-wrap:wrap;gap:10px;align-items:center}.table-wrap[data-v-d1dc979d]{overflow-x:auto;border-radius:10px;border:1px solid var(--app-border);background:#fff}.ellipsis[data-v-d1dc979d]{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pagination[data-v-d1dc979d]{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:14px;flex-wrap:wrap}.page-hint[data-v-d1dc979d]{font-size:12px}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
.page-stack[data-v-080a6c1f]{display:flex;flex-direction:column;gap:12px}.card[data-v-080a6c1f]{border-radius:var(--app-radius);border:1px solid var(--app-border)}.filters[data-v-080a6c1f]{display:flex;flex-wrap:wrap;gap:10px;align-items:center}.table-wrap[data-v-080a6c1f]{overflow-x:auto}.ellipsis[data-v-080a6c1f]{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pagination[data-v-080a6c1f]{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:14px;flex-wrap:wrap}.page-hint[data-v-080a6c1f]{font-size:12px}

View File

@@ -0,0 +1 @@
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,q as k,U as f}from"./index-Bd3qzysl.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};

View File

@@ -0,0 +1 @@
.metric-grid[data-v-00e217d4]{display:grid;grid-template-columns:repeat(auto-fill,minmax(var(--metric-min),1fr));gap:12px}.metric-card[data-v-00e217d4]{position:relative;overflow:hidden;border-radius:14px;border:1px solid var(--app-border);background:linear-gradient(180deg,#fffffffa,#fafcffe6);box-shadow:var(--app-shadow-soft);padding:13px 14px;min-height:104px}.metric-card[data-v-00e217d4]:before{content:"";position:absolute;top:0;left:0;right:0;height:3px;background:var(--metric-top, #3b82f6)}.metric-top[data-v-00e217d4]{display:flex;align-items:center;gap:8px}.metric-icon[data-v-00e217d4]{width:26px;height:26px;border-radius:8px;display:flex;align-items:center;justify-content:center;background:var(--metric-icon-bg, rgba(59, 130, 246, .12));color:var(--metric-icon-color, #1d4ed8)}.metric-label[data-v-00e217d4]{font-size:12px;color:#475569;font-weight:700;line-height:1.4}.metric-value[data-v-00e217d4]{margin-top:10px;font-size:26px;line-height:1.05;font-weight:900;color:#0f172a}.metric-hint[data-v-00e217d4]{margin-top:8px;font-size:12px;line-height:1.4}.metric-tone--blue[data-v-00e217d4]{--metric-top: linear-gradient(90deg, #3b82f6, #06b6d4);--metric-icon-bg: rgba(59, 130, 246, .14);--metric-icon-color: #1d4ed8}.metric-tone--green[data-v-00e217d4]{--metric-top: linear-gradient(90deg, #10b981, #22c55e);--metric-icon-bg: rgba(16, 185, 129, .14);--metric-icon-color: #047857}.metric-tone--purple[data-v-00e217d4]{--metric-top: linear-gradient(90deg, #8b5cf6, #ec4899);--metric-icon-bg: rgba(139, 92, 246, .14);--metric-icon-color: #6d28d9}.metric-tone--orange[data-v-00e217d4]{--metric-top: linear-gradient(90deg, #f59e0b, #f97316);--metric-icon-bg: rgba(245, 158, 11, .14);--metric-icon-color: #b45309}.metric-tone--red[data-v-00e217d4]{--metric-top: linear-gradient(90deg, #ef4444, #f43f5e);--metric-icon-bg: rgba(239, 68, 68, .14);--metric-icon-color: #b91c1c}.metric-tone--cyan[data-v-00e217d4]{--metric-top: linear-gradient(90deg, #06b6d4, #3b82f6);--metric-icon-bg: rgba(6, 182, 212, .14);--metric-icon-color: #0e7490}@media(max-width:768px){.metric-grid[data-v-00e217d4]{grid-template-columns:repeat(2,minmax(0,1fr))}.metric-card[data-v-00e217d4]{min-height:96px}.metric-value[data-v-00e217d4]{font-size:22px}}@media(max-width:480px){.metric-grid[data-v-00e217d4]{grid-template-columns:1fr}}

File diff suppressed because one or more lines are too long

View File

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

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 @@
.page-stack[data-v-09b34cd6]{display:flex;flex-direction:column;gap:14px;min-width:0}.toolbar[data-v-09b34cd6]{display:flex;gap:10px;align-items:center;flex-wrap:wrap}.card[data-v-09b34cd6]{border-radius:var(--app-radius);border:1px solid var(--app-border);background:var(--app-card-bg);box-shadow:var(--app-shadow-soft)}.sub-card[data-v-09b34cd6]{margin-top:12px;border-radius:var(--app-radius);border:1px solid var(--app-border)}.filters[data-v-09b34cd6]{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin-bottom:12px}.table-wrap[data-v-09b34cd6]{overflow-x:auto;border-radius:10px;border:1px solid var(--app-border);background:#fff}.ellipsis[data-v-09b34cd6]{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mono[data-v-09b34cd6]{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.pagination[data-v-09b34cd6]{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:14px;flex-wrap:wrap}.page-hint[data-v-09b34cd6]{font-size:12px}.inner-tabs[data-v-09b34cd6]{margin-top:6px}.risk-head[data-v-09b34cd6]{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:12px;flex-wrap:wrap}.risk-title[data-v-09b34cd6]{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.dialog-actions[data-v-09b34cd6]{display:flex;align-items:center;gap:10px}.spacer[data-v-09b34cd6]{flex:1}

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-22d57053]{display:flex;flex-direction:column;gap:12px}.toolbar[data-v-22d57053]{display:flex;gap:10px;align-items:center;flex-wrap:wrap}.stats-row[data-v-22d57053]{margin-bottom:2px}.card[data-v-22d57053]{border-radius:var(--app-radius);border:1px solid var(--app-border)}.sub-card[data-v-22d57053]{margin-top:12px;border-radius:var(--app-radius);border:1px solid var(--app-border)}.stat-card[data-v-22d57053]{border-radius:var(--app-radius);border:1px solid var(--app-border);box-shadow:var(--app-shadow)}.stat-value[data-v-22d57053]{font-size:22px;font-weight:800;line-height:1.1}.stat-label[data-v-22d57053]{margin-top:6px;font-size:12px;color:var(--app-muted)}.filters[data-v-22d57053]{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin-bottom:12px}.table-wrap[data-v-22d57053]{overflow-x:auto}.ellipsis[data-v-22d57053]{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mono[data-v-22d57053]{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.pagination[data-v-22d57053]{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:14px;flex-wrap:wrap}.page-hint[data-v-22d57053]{font-size:12px}.inner-tabs[data-v-22d57053]{margin-top:6px}.risk-head[data-v-22d57053]{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:12px;flex-wrap:wrap}.risk-title[data-v-22d57053]{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.dialog-actions[data-v-22d57053]{display:flex;align-items:center;gap:10px}.spacer[data-v-22d57053]{flex:1}

View File

@@ -1 +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,q as x,L as i,K as b}from"./index-DKH_HvPt.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-12a26d11"]]);export{M as default}; 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,q as x,J as i,I as b}from"./index-Bd3qzysl.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})])}}},I=B(E,[["__scopeId","data-v-83d3840a"]]);export{I as default};

View File

@@ -1 +0,0 @@
.page-stack[data-v-12a26d11]{display:flex;flex-direction:column;gap:12px}.card[data-v-12a26d11]{border-radius:var(--app-radius);border:1px solid var(--app-border)}.section-title[data-v-12a26d11]{margin:0 0 12px;font-size:14px;font-weight:800}.help[data-v-12a26d11]{margin-top:10px;font-size:12px;color:var(--app-muted)}

View File

@@ -0,0 +1 @@
.page-stack[data-v-83d3840a]{display:flex;flex-direction:column;gap:14px;min-width:0}.card[data-v-83d3840a]{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-83d3840a]{margin:0 0 12px;font-size:15px;font-weight:800;letter-spacing:.2px}.help[data-v-83d3840a]{margin-top:10px;font-size:12px;color:var(--app-muted)}

View File

@@ -1 +0,0 @@
.page-stack[data-v-b359577d]{display:flex;flex-direction:column;gap:12px}.card[data-v-b359577d]{border-radius:var(--app-radius);border:1px solid var(--app-border)}.section-title[data-v-b359577d]{margin:0 0 12px;font-size:14px;font-weight:800}.kdocs-qr[data-v-b359577d]{display:flex;flex-direction:column;align-items:center;gap:12px}.kdocs-qr img[data-v-b359577d]{width:260px;max-width:100%;border:1px solid var(--app-border);border-radius:8px;padding:8px;background:#fff}.help[data-v-b359577d]{margin-top:6px;font-size:12px;color:var(--app-muted)}.row-actions[data-v-b359577d]{display:flex;flex-wrap:wrap;gap:10px}

View File

@@ -0,0 +1 @@
.page-stack[data-v-f6db7ea6]{display:flex;flex-direction:column;gap:14px;min-width:0}.card[data-v-f6db7ea6]{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-f6db7ea6]{margin:0 0 12px;font-size:15px;font-weight:800;letter-spacing:.2px}.kdocs-qr[data-v-f6db7ea6]{display:flex;flex-direction:column;align-items:center;gap:12px}.kdocs-qr img[data-v-f6db7ea6]{width:260px;max-width:100%;border:1px solid var(--app-border);border-radius:8px;padding:8px;background:#fff}.help[data-v-f6db7ea6]{margin-top:6px;font-size:12px;color:var(--app-muted)}.row-actions[data-v-f6db7ea6]{display:flex;flex-wrap:wrap;gap:10px}

View File

@@ -1 +0,0 @@
.page-stack[data-v-d73d2b82]{display:flex;flex-direction:column;gap:12px}.card[data-v-d73d2b82]{border-radius:var(--app-radius);border:1px solid var(--app-border)}.section-title[data-v-d73d2b82]{margin:0 0 12px;font-size:14px;font-weight:800}.help[data-v-d73d2b82]{margin-top:10px;font-size:12px}.table-wrap[data-v-d73d2b82]{overflow-x:auto}.user-block[data-v-d73d2b82]{display:flex;flex-direction:column;gap:2px}.user-main[data-v-d73d2b82]{display:inline-flex;align-items:center;gap:8px;flex-wrap:wrap}.user-sub[data-v-d73d2b82]{font-size:12px}.vip-sub[data-v-d73d2b82]{font-size:12px;color:#7c3aed}.actions[data-v-d73d2b82]{display:flex;flex-wrap:wrap;gap:8px}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
.page-stack[data-v-db2dc218]{display:flex;flex-direction:column;gap:14px;min-width:0}.card[data-v-db2dc218]{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-db2dc218]{margin:0 0 12px;font-size:15px;font-weight:800;letter-spacing:.2px}.help[data-v-db2dc218]{margin-top:10px;font-size:12px}.table-wrap[data-v-db2dc218]{overflow-x:auto;border-radius:10px;border:1px solid var(--app-border);background:#fff}.user-block[data-v-db2dc218]{display:flex;flex-direction:column;gap:2px}.user-main[data-v-db2dc218]{display:inline-flex;align-items:center;gap:8px;flex-wrap:wrap}.user-sub[data-v-db2dc218]{font-size:12px}.vip-sub[data-v-db2dc218]{font-size:12px;color:#7c3aed}.actions[data-v-db2dc218]{display:flex;flex-wrap:wrap;gap:8px}

View File

@@ -1 +1 @@
import{a as n}from"./index-DKH_HvPt.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-Bd3qzysl.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

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
import{a}from"./index-DKH_HvPt.js";async function s(){const{data:t}=await a.get("/system/config");return t}async function c(t){const{data:e}=await a.post("/system/config",t);return e}async function o(){const{data:t}=await a.post("/schedule/execute",{});return t}export{o as e,s as f,c as u}; import{a}from"./index-Bd3qzysl.js";async function s(){const{data:t}=await a.get("/system/config");return t}async function c(t){const{data:e}=await a.post("/system/config",t);return e}async function o(){const{data:t}=await a.post("/schedule/execute",{});return t}export{o as e,s as f,c as u};

View File

@@ -1 +1 @@
import{a}from"./index-DKH_HvPt.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-Bd3qzysl.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-DKH_HvPt.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-Bd3qzysl.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,8 +5,8 @@
<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-DKH_HvPt.js"></script> <script type="module" crossorigin src="./assets/index-Bd3qzysl.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-_5Ec1Hmd.css"> <link rel="stylesheet" crossorigin href="./assets/index-Gi1T-zxa.css">
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

View File

@@ -1,20 +1,20 @@
{ {
"_accounts-Cq6KNxFR.js": { "_accounts-DMWldvrc.js": {
"file": "assets/accounts-Cq6KNxFR.js", "file": "assets/accounts-DMWldvrc.js",
"name": "accounts", "name": "accounts",
"imports": [ "imports": [
"index.html" "index.html"
] ]
}, },
"_auth-CjQgMKAl.js": { "_auth-RsjJ-Dgh.js": {
"file": "assets/auth-CjQgMKAl.js", "file": "assets/auth-RsjJ-Dgh.js",
"name": "auth", "name": "auth",
"imports": [ "imports": [
"index.html" "index.html"
] ]
}, },
"index.html": { "index.html": {
"file": "assets/index-DMtbRy1f.js", "file": "assets/index-D1OuoXoU.js",
"name": "index", "name": "index",
"src": "index.html", "src": "index.html",
"isEntry": true, "isEntry": true,
@@ -32,12 +32,12 @@
] ]
}, },
"src/pages/AccountsPage.vue": { "src/pages/AccountsPage.vue": {
"file": "assets/AccountsPage-xwYY9lse.js", "file": "assets/AccountsPage-BaKp9Hif.js",
"name": "AccountsPage", "name": "AccountsPage",
"src": "src/pages/AccountsPage.vue", "src": "src/pages/AccountsPage.vue",
"isDynamicEntry": true, "isDynamicEntry": true,
"imports": [ "imports": [
"_accounts-Cq6KNxFR.js", "_accounts-DMWldvrc.js",
"index.html" "index.html"
], ],
"css": [ "css": [
@@ -45,51 +45,51 @@
] ]
}, },
"src/pages/LoginPage.vue": { "src/pages/LoginPage.vue": {
"file": "assets/LoginPage-BchU6qog.js", "file": "assets/LoginPage-BVBKu4Tf.js",
"name": "LoginPage", "name": "LoginPage",
"src": "src/pages/LoginPage.vue", "src": "src/pages/LoginPage.vue",
"isDynamicEntry": true, "isDynamicEntry": true,
"imports": [ "imports": [
"index.html", "index.html",
"_auth-CjQgMKAl.js" "_auth-RsjJ-Dgh.js"
], ],
"css": [ "css": [
"assets/LoginPage-Dra3USJu.css" "assets/LoginPage-m2uYyAaW.css"
] ]
}, },
"src/pages/RegisterPage.vue": { "src/pages/RegisterPage.vue": {
"file": "assets/RegisterPage-CwVejO-I.js", "file": "assets/RegisterPage-D74ftG7F.js",
"name": "RegisterPage", "name": "RegisterPage",
"src": "src/pages/RegisterPage.vue", "src": "src/pages/RegisterPage.vue",
"isDynamicEntry": true, "isDynamicEntry": true,
"imports": [ "imports": [
"index.html", "index.html",
"_auth-CjQgMKAl.js" "_auth-RsjJ-Dgh.js"
], ],
"css": [ "css": [
"assets/RegisterPage-BOcNcW5D.css" "assets/RegisterPage-BOcNcW5D.css"
] ]
}, },
"src/pages/ResetPasswordPage.vue": { "src/pages/ResetPasswordPage.vue": {
"file": "assets/ResetPasswordPage-Cp3rzSEn.js", "file": "assets/ResetPasswordPage-DlzgcuUb.js",
"name": "ResetPasswordPage", "name": "ResetPasswordPage",
"src": "src/pages/ResetPasswordPage.vue", "src": "src/pages/ResetPasswordPage.vue",
"isDynamicEntry": true, "isDynamicEntry": true,
"imports": [ "imports": [
"index.html", "index.html",
"_auth-CjQgMKAl.js" "_auth-RsjJ-Dgh.js"
], ],
"css": [ "css": [
"assets/ResetPasswordPage-DybfLMAw.css" "assets/ResetPasswordPage-DybfLMAw.css"
] ]
}, },
"src/pages/SchedulesPage.vue": { "src/pages/SchedulesPage.vue": {
"file": "assets/SchedulesPage-BebL6WA6.js", "file": "assets/SchedulesPage-CgezmtHQ.js",
"name": "SchedulesPage", "name": "SchedulesPage",
"src": "src/pages/SchedulesPage.vue", "src": "src/pages/SchedulesPage.vue",
"isDynamicEntry": true, "isDynamicEntry": true,
"imports": [ "imports": [
"_accounts-Cq6KNxFR.js", "_accounts-DMWldvrc.js",
"index.html" "index.html"
], ],
"css": [ "css": [
@@ -97,7 +97,7 @@
] ]
}, },
"src/pages/ScreenshotsPage.vue": { "src/pages/ScreenshotsPage.vue": {
"file": "assets/ScreenshotsPage-M4eRrqBg.js", "file": "assets/ScreenshotsPage-CQ27mEKf.js",
"name": "ScreenshotsPage", "name": "ScreenshotsPage",
"src": "src/pages/ScreenshotsPage.vue", "src": "src/pages/ScreenshotsPage.vue",
"isDynamicEntry": true, "isDynamicEntry": true,
@@ -109,7 +109,7 @@
] ]
}, },
"src/pages/VerifyResultPage.vue": { "src/pages/VerifyResultPage.vue": {
"file": "assets/VerifyResultPage-D9tJlwTO.js", "file": "assets/VerifyResultPage-CfKXGuTu.js",
"name": "VerifyResultPage", "name": "VerifyResultPage",
"src": "src/pages/VerifyResultPage.vue", "src": "src/pages/VerifyResultPage.vue",
"isDynamicEntry": true, "isDynamicEntry": true,

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 @@
.login-page[data-v-60947b3b]{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:20px;position:relative;background:linear-gradient(135deg,#eef2ff,#f6f7fb 45%,#ecfeff)}.login-page[data-v-60947b3b]:before{content:"";position:fixed;inset:0;background:radial-gradient(800px 500px at 15% 20%,rgba(59,130,246,.18),transparent 60%),radial-gradient(700px 420px at 85% 70%,rgba(124,58,237,.16),transparent 55%);pointer-events:none}.login-container[data-v-60947b3b]{width:100%;max-width:420px;background:#fff;border-radius:16px;box-shadow:0 18px 60px #11182726;border:1px solid rgba(17,24,39,.08);padding:38px 34px;position:relative;z-index:1}.login-header[data-v-60947b3b]{text-align:center;margin-bottom:28px}.login-badge[data-v-60947b3b]{display:inline-block;background:#3b82f61a;color:#1d4ed8;padding:6px 14px;border-radius:999px;font-size:12px;font-weight:700;margin-bottom:14px}.login-header h1[data-v-60947b3b]{font-size:24px;color:#111827;margin:0 0 10px;letter-spacing:.2px}.login-header p[data-v-60947b3b]{margin:0;color:#6b7280;font-size:14px}.form-group[data-v-60947b3b]{margin-bottom:20px}.form-group label[data-v-60947b3b]{display:block;margin-bottom:8px;color:#111827;font-weight:700;font-size:13px}.login-input[data-v-60947b3b] .el-input__wrapper{border-radius:10px;min-height:44px;background:#ffffffe6;box-shadow:0 0 0 1px #11182724 inset;transition:box-shadow .2s}.login-input[data-v-60947b3b] .el-input__wrapper.is-focus{box-shadow:0 0 0 1px #3b82f6b3 inset,0 0 0 4px #3b82f629}.login-input[data-v-60947b3b] .el-input__inner{font-size:14px}.btn-login[data-v-60947b3b]{width:100%;padding:12px;border:none;border-radius:10px;background:linear-gradient(135deg,#2563eb,#7c3aed);color:#fff;font-size:16px;font-weight:800;cursor:pointer;transition:transform .15s,filter .15s}.btn-login[data-v-60947b3b]:hover:not(:disabled){transform:translateY(-2px);filter:brightness(1.02)}.btn-login[data-v-60947b3b]:active:not(:disabled){transform:translateY(0)}.btn-login[data-v-60947b3b]:disabled{cursor:not-allowed;opacity:.8}.action-links[data-v-60947b3b]{margin-top:14px;display:flex;align-items:center;justify-content:space-between;gap:8px;flex-wrap:wrap}.link-btn[data-v-60947b3b]{border:none;background:none;color:#2563eb;font-size:13px;font-weight:700;cursor:pointer;padding:0}.link-btn[data-v-60947b3b]:hover{text-decoration:underline}.register-row[data-v-60947b3b]{margin-top:16px;display:flex;justify-content:center;align-items:center;gap:8px;color:#6b7280;font-size:13px}.back-link[data-v-60947b3b]{text-align:center;margin-top:18px;color:#6b7280;font-size:13px}.back-link a[data-v-60947b3b]{margin-left:6px;color:#2563eb;text-decoration:none;font-weight:700}.back-link a[data-v-60947b3b]:hover{text-decoration:underline}.dialog-form[data-v-60947b3b]{margin-top:10px}.alert[data-v-60947b3b]{margin-top:12px}.captcha-row[data-v-60947b3b]{display:flex;align-items:center;gap:10px;width:100%}.captcha-input[data-v-60947b3b]{flex:1;min-width:0}.captcha-img[data-v-60947b3b]{height:46px;border:1px solid rgba(17,24,39,.14);border-radius:8px;cursor:pointer;-webkit-user-select:none;user-select:none}.captcha-refresh[data-v-60947b3b]{height:44px;padding:0 14px;border:1px solid rgba(17,24,39,.14);border-radius:10px;background:#f8fafc;color:#111827;font-size:13px;cursor:pointer}.captcha-refresh[data-v-60947b3b]:hover{background:#f1f5f9}@media(max-width:480px){.login-page[data-v-60947b3b]{align-items:flex-start;padding:20px 12px 12px}.login-container[data-v-60947b3b]{max-width:100%;padding:28px 20px;border-radius:14px}.login-header h1[data-v-60947b3b]{font-size:22px}.btn-login[data-v-60947b3b]{padding:13px;font-size:15px}.captcha-img[data-v-60947b3b]{height:42px}.captcha-refresh[data-v-60947b3b]{height:42px;padding:0 12px}}

View File

@@ -0,0 +1 @@
.login-page[data-v-b82518fc]{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:20px;position:relative;background:linear-gradient(135deg,#eef2ff,#f6f7fb 45%,#ecfeff)}.login-page[data-v-b82518fc]:before{content:"";position:fixed;inset:0;background:radial-gradient(800px 500px at 15% 20%,rgba(59,130,246,.18),transparent 60%),radial-gradient(700px 420px at 85% 70%,rgba(124,58,237,.16),transparent 55%);pointer-events:none}.login-container[data-v-b82518fc]{width:100%;max-width:420px;background:#fff;border-radius:16px;box-shadow:0 18px 60px #11182726;border:1px solid rgba(17,24,39,.08);padding:38px 34px;position:relative;z-index:1}.login-header[data-v-b82518fc]{text-align:center;margin-bottom:28px}.login-badge[data-v-b82518fc]{display:inline-block;background:#3b82f61a;color:#1d4ed8;padding:6px 14px;border-radius:999px;font-size:12px;font-weight:700;margin-bottom:14px}.login-header h1[data-v-b82518fc]{font-size:24px;color:#111827;margin:0 0 10px;letter-spacing:.2px}.login-header p[data-v-b82518fc]{margin:0;color:#6b7280;font-size:14px}.form-group[data-v-b82518fc]{margin-bottom:20px}.form-group label[data-v-b82518fc]{display:block;margin-bottom:8px;color:#111827;font-weight:700;font-size:13px}.login-input[data-v-b82518fc] .el-input__wrapper{border-radius:10px;min-height:44px;background:#ffffffe6;box-shadow:0 0 0 1px #11182724 inset;transition:box-shadow .2s}.login-input[data-v-b82518fc] .el-input__wrapper.is-focus{box-shadow:0 0 0 1px #3b82f6b3 inset,0 0 0 4px #3b82f629}.login-input[data-v-b82518fc] .el-input__inner{font-size:14px}.btn-login[data-v-b82518fc]{width:100%;padding:12px;border:none;border-radius:10px;background:linear-gradient(135deg,#2563eb,#7c3aed);color:#fff;font-size:16px;font-weight:800;cursor:pointer;transition:transform .15s,filter .15s}.btn-login[data-v-b82518fc]:hover:not(:disabled){transform:translateY(-2px);filter:brightness(1.02)}.btn-login[data-v-b82518fc]:active:not(:disabled){transform:translateY(0)}.btn-login[data-v-b82518fc]:disabled{cursor:not-allowed;opacity:.8}.action-links[data-v-b82518fc]{margin-top:14px;display:flex;align-items:center;justify-content:space-between;gap:8px;flex-wrap:wrap}.link-btn[data-v-b82518fc]{border:none;background:none;color:#2563eb;font-size:13px;font-weight:700;cursor:pointer;padding:0}.link-btn[data-v-b82518fc]:hover{text-decoration:underline}.register-row[data-v-b82518fc]{margin-top:16px;display:flex;justify-content:center;align-items:center;gap:8px;color:#6b7280;font-size:13px}.dialog-form[data-v-b82518fc]{margin-top:10px}.alert[data-v-b82518fc]{margin-top:12px}.captcha-row[data-v-b82518fc]{display:flex;align-items:center;gap:10px;width:100%}.captcha-input[data-v-b82518fc]{flex:1;min-width:0}.captcha-img[data-v-b82518fc]{height:46px;border:1px solid rgba(17,24,39,.14);border-radius:8px;cursor:pointer;-webkit-user-select:none;user-select:none}.captcha-refresh[data-v-b82518fc]{height:44px;padding:0 14px;border:1px solid rgba(17,24,39,.14);border-radius:10px;background:#f8fafc;color:#111827;font-size:13px;cursor:pointer}.captcha-refresh[data-v-b82518fc]:hover{background:#f1f5f9}@media(max-width:480px){.login-page[data-v-b82518fc]{align-items:flex-start;padding:20px 12px 12px}.login-container[data-v-b82518fc]{max-width:100%;padding:28px 20px;border-radius:14px}.login-header h1[data-v-b82518fc]{font-size:22px}.btn-login[data-v-b82518fc]{padding:13px;font-size:15px}.captcha-img[data-v-b82518fc]{height:42px}.captcha-refresh[data-v-b82518fc]{height:42px;padding:0 12px}}

View File

@@ -1 +1 @@
import{_ as M,r as j,a as d,c as B,o as A,b as U,e as l,h as o,g as v,u as H,i as b,d as n,j as N,f as E,w as P,t as q,k as S,E as c,v as z}from"./index-DMtbRy1f.js";import{g as F,f as G,b as J}from"./auth-CjQgMKAl.js";const O={class:"auth-wrap"},Q={class:"hint app-muted"},W={class:"captcha-row"},X=["src"],Y={class:"actions"},Z={__name:"RegisterPage",setup($){const T=H(),a=j({username:"",password:"",confirm_password:"",email:"",captcha:""}),f=d(!1),w=d(""),h=d(""),V=d(!1),t=d(""),_=d(""),k=d(""),K=B(()=>f.value?"邮箱 *":"邮箱(可选)"),R=B(()=>f.value?"必填,用于账号验证":"选填,用于找回密码和接收通知");async function y(){try{const u=await F();h.value=u?.session_id||"",w.value=u?.captcha_image||"",a.captcha=""}catch{h.value="",w.value=""}}async function D(){try{const u=await G();f.value=!!u?.register_verify_enabled}catch{f.value=!1}}function I(){t.value="",_.value="",k.value=""}async function C(){I();const u=a.username.trim(),e=a.password,g=a.confirm_password,s=a.email.trim(),i=a.captcha.trim();if(u.length<3){t.value="用户名至少3个字符",c.error(t.value);return}const p=z(e);if(!p.ok){t.value=p.message||"密码格式不正确",c.error(t.value);return}if(e!==g){t.value="两次输入的密码不一致",c.error(t.value);return}if(f.value&&!s){t.value="请填写邮箱地址用于账号验证",c.error(t.value);return}if(s&&!s.includes("@")){t.value="邮箱格式不正确",c.error(t.value);return}if(!i){t.value="请输入验证码",c.error(t.value);return}V.value=!0;try{const m=await J({username:u,password:e,email:s,captcha_session:h.value,captcha:i});_.value=m?.message||"注册成功",k.value=m?.need_verify?"请检查您的邮箱(包括垃圾邮件文件夹)":"",c.success("注册成功"),a.username="",a.password="",a.confirm_password="",a.email="",a.captcha="",setTimeout(()=>{window.location.href="/login"},3e3)}catch(m){const x=m?.response?.data;t.value=x?.error||"注册失败",c.error(t.value),await y()}finally{V.value=!1}}function L(){T.push("/login")}return A(async()=>{await y(),await D()}),(u,e)=>{const g=v("el-alert"),s=v("el-input"),i=v("el-form-item"),p=v("el-button"),m=v("el-form"),x=v("el-card");return b(),U("div",O,[l(x,{shadow:"never",class:"auth-card","body-style":{padding:"22px"}},{default:o(()=>[e[11]||(e[11]=n("div",{class:"brand"},[n("div",{class:"brand-title"},"知识管理平台"),n("div",{class:"brand-sub app-muted"},"用户注册")],-1)),t.value?(b(),N(g,{key:0,type:"error",closable:!1,title:t.value,"show-icon":"",class:"alert"},null,8,["title"])):E("",!0),_.value?(b(),N(g,{key:1,type:"success",closable:!1,title:_.value,description:k.value,"show-icon":"",class:"alert"},null,8,["title","description"])):E("",!0),l(m,{"label-position":"top"},{default:o(()=>[l(i,{label:"用户名 *"},{default:o(()=>[l(s,{modelValue:a.username,"onUpdate:modelValue":e[0]||(e[0]=r=>a.username=r),placeholder:"至少3个字符",autocomplete:"username"},null,8,["modelValue"]),e[5]||(e[5]=n("div",{class:"hint app-muted"},"至少3个字符",-1))]),_:1}),l(i,{label:"密码 *"},{default:o(()=>[l(s,{modelValue:a.password,"onUpdate:modelValue":e[1]||(e[1]=r=>a.password=r),type:"password","show-password":"",placeholder:"至少8位且包含字母和数字",autocomplete:"new-password"},null,8,["modelValue"]),e[6]||(e[6]=n("div",{class:"hint app-muted"},"至少8位且包含字母和数字",-1))]),_:1}),l(i,{label:"确认密码 *"},{default:o(()=>[l(s,{modelValue:a.confirm_password,"onUpdate:modelValue":e[2]||(e[2]=r=>a.confirm_password=r),type:"password","show-password":"",placeholder:"请再次输入密码",autocomplete:"new-password",onKeyup:P(C,["enter"])},null,8,["modelValue"])]),_:1}),l(i,{label:K.value},{default:o(()=>[l(s,{modelValue:a.email,"onUpdate:modelValue":e[3]||(e[3]=r=>a.email=r),placeholder:"name@example.com",autocomplete:"email"},null,8,["modelValue"]),n("div",Q,q(R.value),1)]),_:1},8,["label"]),l(i,{label:"验证码 *"},{default:o(()=>[n("div",W,[l(s,{modelValue:a.captcha,"onUpdate:modelValue":e[4]||(e[4]=r=>a.captcha=r),placeholder:"请输入验证码",onKeyup:P(C,["enter"])},null,8,["modelValue"]),w.value?(b(),U("img",{key:0,class:"captcha-img",src:w.value,alt:"验证码",title:"点击刷新",onClick:y},null,8,X)):E("",!0),l(p,{onClick:y},{default:o(()=>[...e[7]||(e[7]=[S("刷新",-1)])]),_:1})])]),_:1})]),_:1}),l(p,{type:"primary",class:"submit-btn",loading:V.value,onClick:C},{default:o(()=>[...e[8]||(e[8]=[S("注册",-1)])]),_:1},8,["loading"]),n("div",Y,[e[10]||(e[10]=n("span",{class:"app-muted"},"已有账号?",-1)),l(p,{link:"",type:"primary",onClick:L},{default:o(()=>[...e[9]||(e[9]=[S("立即登录",-1)])]),_:1})])]),_:1})])}}},te=M(Z,[["__scopeId","data-v-a9d7804f"]]);export{te as default}; import{_ as M,r as j,a as d,c as B,o as A,b as U,e as l,h as o,g as v,u as H,i as b,d as n,j as N,f as E,w as P,t as q,k as S,E as c,v as z}from"./index-D1OuoXoU.js";import{g as F,f as G,b as J}from"./auth-RsjJ-Dgh.js";const O={class:"auth-wrap"},Q={class:"hint app-muted"},W={class:"captcha-row"},X=["src"],Y={class:"actions"},Z={__name:"RegisterPage",setup($){const T=H(),a=j({username:"",password:"",confirm_password:"",email:"",captcha:""}),f=d(!1),w=d(""),h=d(""),V=d(!1),t=d(""),_=d(""),k=d(""),K=B(()=>f.value?"邮箱 *":"邮箱(可选)"),R=B(()=>f.value?"必填,用于账号验证":"选填,用于找回密码和接收通知");async function y(){try{const u=await F();h.value=u?.session_id||"",w.value=u?.captcha_image||"",a.captcha=""}catch{h.value="",w.value=""}}async function D(){try{const u=await G();f.value=!!u?.register_verify_enabled}catch{f.value=!1}}function I(){t.value="",_.value="",k.value=""}async function C(){I();const u=a.username.trim(),e=a.password,g=a.confirm_password,s=a.email.trim(),i=a.captcha.trim();if(u.length<3){t.value="用户名至少3个字符",c.error(t.value);return}const p=z(e);if(!p.ok){t.value=p.message||"密码格式不正确",c.error(t.value);return}if(e!==g){t.value="两次输入的密码不一致",c.error(t.value);return}if(f.value&&!s){t.value="请填写邮箱地址用于账号验证",c.error(t.value);return}if(s&&!s.includes("@")){t.value="邮箱格式不正确",c.error(t.value);return}if(!i){t.value="请输入验证码",c.error(t.value);return}V.value=!0;try{const m=await J({username:u,password:e,email:s,captcha_session:h.value,captcha:i});_.value=m?.message||"注册成功",k.value=m?.need_verify?"请检查您的邮箱(包括垃圾邮件文件夹)":"",c.success("注册成功"),a.username="",a.password="",a.confirm_password="",a.email="",a.captcha="",setTimeout(()=>{window.location.href="/login"},3e3)}catch(m){const x=m?.response?.data;t.value=x?.error||"注册失败",c.error(t.value),await y()}finally{V.value=!1}}function L(){T.push("/login")}return A(async()=>{await y(),await D()}),(u,e)=>{const g=v("el-alert"),s=v("el-input"),i=v("el-form-item"),p=v("el-button"),m=v("el-form"),x=v("el-card");return b(),U("div",O,[l(x,{shadow:"never",class:"auth-card","body-style":{padding:"22px"}},{default:o(()=>[e[11]||(e[11]=n("div",{class:"brand"},[n("div",{class:"brand-title"},"知识管理平台"),n("div",{class:"brand-sub app-muted"},"用户注册")],-1)),t.value?(b(),N(g,{key:0,type:"error",closable:!1,title:t.value,"show-icon":"",class:"alert"},null,8,["title"])):E("",!0),_.value?(b(),N(g,{key:1,type:"success",closable:!1,title:_.value,description:k.value,"show-icon":"",class:"alert"},null,8,["title","description"])):E("",!0),l(m,{"label-position":"top"},{default:o(()=>[l(i,{label:"用户名 *"},{default:o(()=>[l(s,{modelValue:a.username,"onUpdate:modelValue":e[0]||(e[0]=r=>a.username=r),placeholder:"至少3个字符",autocomplete:"username"},null,8,["modelValue"]),e[5]||(e[5]=n("div",{class:"hint app-muted"},"至少3个字符",-1))]),_:1}),l(i,{label:"密码 *"},{default:o(()=>[l(s,{modelValue:a.password,"onUpdate:modelValue":e[1]||(e[1]=r=>a.password=r),type:"password","show-password":"",placeholder:"至少8位且包含字母和数字",autocomplete:"new-password"},null,8,["modelValue"]),e[6]||(e[6]=n("div",{class:"hint app-muted"},"至少8位且包含字母和数字",-1))]),_:1}),l(i,{label:"确认密码 *"},{default:o(()=>[l(s,{modelValue:a.confirm_password,"onUpdate:modelValue":e[2]||(e[2]=r=>a.confirm_password=r),type:"password","show-password":"",placeholder:"请再次输入密码",autocomplete:"new-password",onKeyup:P(C,["enter"])},null,8,["modelValue"])]),_:1}),l(i,{label:K.value},{default:o(()=>[l(s,{modelValue:a.email,"onUpdate:modelValue":e[3]||(e[3]=r=>a.email=r),placeholder:"name@example.com",autocomplete:"email"},null,8,["modelValue"]),n("div",Q,q(R.value),1)]),_:1},8,["label"]),l(i,{label:"验证码 *"},{default:o(()=>[n("div",W,[l(s,{modelValue:a.captcha,"onUpdate:modelValue":e[4]||(e[4]=r=>a.captcha=r),placeholder:"请输入验证码",onKeyup:P(C,["enter"])},null,8,["modelValue"]),w.value?(b(),U("img",{key:0,class:"captcha-img",src:w.value,alt:"验证码",title:"点击刷新",onClick:y},null,8,X)):E("",!0),l(p,{onClick:y},{default:o(()=>[...e[7]||(e[7]=[S("刷新",-1)])]),_:1})])]),_:1})]),_:1}),l(p,{type:"primary",class:"submit-btn",loading:V.value,onClick:C},{default:o(()=>[...e[8]||(e[8]=[S("注册",-1)])]),_:1},8,["loading"]),n("div",Y,[e[10]||(e[10]=n("span",{class:"app-muted"},"已有账号?",-1)),l(p,{link:"",type:"primary",onClick:L},{default:o(()=>[...e[9]||(e[9]=[S("立即登录",-1)])]),_:1})])]),_:1})])}}},te=M(Z,[["__scopeId","data-v-a9d7804f"]]);export{te as default};

View File

@@ -1 +1 @@
import{_ as L,a as n,l as M,r as U,c as j,o as F,m as K,b as v,e as s,h as a,g as l,u as D,i as w,d as m,F as T,k,j as q,f as x,w as z,t as G,v as H,E as y}from"./index-DMtbRy1f.js";import{c as J}from"./auth-CjQgMKAl.js";const O={class:"auth-wrap"},Q={class:"actions"},W={class:"actions"},X={key:0,class:"app-muted"},Y={__name:"ResetPasswordPage",setup(Z){const B=M(),A=D(),r=n(String(B.params.token||"")),i=n(!0),b=n(""),t=U({newPassword:"",confirmPassword:""}),g=n(!1),_=n(""),d=n(0);let u=null;function C(){if(typeof window>"u")return null;const o=window.__APP_INITIAL_STATE__;return!o||typeof o!="object"?null:(window.__APP_INITIAL_STATE__=null,o)}const I=j(()=>!!(i.value&&r.value&&!_.value));function S(){A.push("/login")}function N(){d.value=3,u=window.setInterval(()=>{d.value-=1,d.value<=0&&(window.clearInterval(u),u=null,window.location.href="/login")},1e3)}async function V(){if(!I.value)return;const o=t.newPassword,e=t.confirmPassword,c=H(o);if(!c.ok){y.error(c.message);return}if(o!==e){y.error("两次输入的密码不一致");return}g.value=!0;try{await J({token:r.value,new_password:o}),_.value="密码重置成功3秒后跳转到登录页面...",y.success("密码重置成功"),N()}catch(p){const f=p?.response?.data;y.error(f?.error||"重置失败")}finally{g.value=!1}}return F(()=>{const o=C();o?.page==="reset_password"?(r.value=String(o?.token||r.value||""),i.value=!!o?.valid,b.value=o?.error_message||(i.value?"":"重置链接无效或已过期,请重新申请密码重置")):r.value||(i.value=!1,b.value="重置链接无效或已过期,请重新申请密码重置")}),K(()=>{u&&window.clearInterval(u)}),(o,e)=>{const c=l("el-alert"),p=l("el-button"),f=l("el-input"),h=l("el-form-item"),R=l("el-form"),E=l("el-card");return w(),v("div",O,[s(E,{shadow:"never",class:"auth-card","body-style":{padding:"22px"}},{default:a(()=>[e[5]||(e[5]=m("div",{class:"brand"},[m("div",{class:"brand-title"},"知识管理平台"),m("div",{class:"brand-sub app-muted"},"重置密码")],-1)),i.value?(w(),v(T,{key:1},[_.value?(w(),q(c,{key:0,type:"success",closable:!1,title:"重置成功",description:_.value,"show-icon":"",class:"alert"},null,8,["description"])):x("",!0),s(R,{"label-position":"top"},{default:a(()=>[s(h,{label:"新密码至少8位且包含字母和数字"},{default:a(()=>[s(f,{modelValue:t.newPassword,"onUpdate:modelValue":e[0]||(e[0]=P=>t.newPassword=P),type:"password","show-password":"",placeholder:"请输入新密码",autocomplete:"new-password"},null,8,["modelValue"])]),_:1}),s(h,{label:"确认密码"},{default:a(()=>[s(f,{modelValue:t.confirmPassword,"onUpdate:modelValue":e[1]||(e[1]=P=>t.confirmPassword=P),type:"password","show-password":"",placeholder:"请再次输入新密码",autocomplete:"new-password",onKeyup:z(V,["enter"])},null,8,["modelValue"])]),_:1})]),_:1}),s(p,{type:"primary",class:"submit-btn",loading:g.value,disabled:!I.value,onClick:V},{default:a(()=>[...e[3]||(e[3]=[k(" 确认重置 ",-1)])]),_:1},8,["loading","disabled"]),m("div",W,[s(p,{link:"",type:"primary",onClick:S},{default:a(()=>[...e[4]||(e[4]=[k("返回登录",-1)])]),_:1}),d.value>0?(w(),v("span",X,G(d.value)+" 秒后自动跳转…",1)):x("",!0)])],64)):(w(),v(T,{key:0},[s(c,{type:"error",closable:!1,title:"链接已失效",description:b.value,"show-icon":""},null,8,["description"]),m("div",Q,[s(p,{type:"primary",onClick:S},{default:a(()=>[...e[2]||(e[2]=[k("返回登录",-1)])]),_:1})])],64))]),_:1})])}}},oe=L(Y,[["__scopeId","data-v-0bbb511c"]]);export{oe as default}; import{_ as L,a as n,l as M,r as U,c as j,o as F,m as K,b as v,e as s,h as a,g as l,u as D,i as w,d as m,F as T,k,j as q,f as x,w as z,t as G,v as H,E as y}from"./index-D1OuoXoU.js";import{c as J}from"./auth-RsjJ-Dgh.js";const O={class:"auth-wrap"},Q={class:"actions"},W={class:"actions"},X={key:0,class:"app-muted"},Y={__name:"ResetPasswordPage",setup(Z){const B=M(),A=D(),r=n(String(B.params.token||"")),i=n(!0),b=n(""),t=U({newPassword:"",confirmPassword:""}),g=n(!1),_=n(""),d=n(0);let u=null;function C(){if(typeof window>"u")return null;const o=window.__APP_INITIAL_STATE__;return!o||typeof o!="object"?null:(window.__APP_INITIAL_STATE__=null,o)}const I=j(()=>!!(i.value&&r.value&&!_.value));function S(){A.push("/login")}function N(){d.value=3,u=window.setInterval(()=>{d.value-=1,d.value<=0&&(window.clearInterval(u),u=null,window.location.href="/login")},1e3)}async function V(){if(!I.value)return;const o=t.newPassword,e=t.confirmPassword,c=H(o);if(!c.ok){y.error(c.message);return}if(o!==e){y.error("两次输入的密码不一致");return}g.value=!0;try{await J({token:r.value,new_password:o}),_.value="密码重置成功3秒后跳转到登录页面...",y.success("密码重置成功"),N()}catch(p){const f=p?.response?.data;y.error(f?.error||"重置失败")}finally{g.value=!1}}return F(()=>{const o=C();o?.page==="reset_password"?(r.value=String(o?.token||r.value||""),i.value=!!o?.valid,b.value=o?.error_message||(i.value?"":"重置链接无效或已过期,请重新申请密码重置")):r.value||(i.value=!1,b.value="重置链接无效或已过期,请重新申请密码重置")}),K(()=>{u&&window.clearInterval(u)}),(o,e)=>{const c=l("el-alert"),p=l("el-button"),f=l("el-input"),h=l("el-form-item"),R=l("el-form"),E=l("el-card");return w(),v("div",O,[s(E,{shadow:"never",class:"auth-card","body-style":{padding:"22px"}},{default:a(()=>[e[5]||(e[5]=m("div",{class:"brand"},[m("div",{class:"brand-title"},"知识管理平台"),m("div",{class:"brand-sub app-muted"},"重置密码")],-1)),i.value?(w(),v(T,{key:1},[_.value?(w(),q(c,{key:0,type:"success",closable:!1,title:"重置成功",description:_.value,"show-icon":"",class:"alert"},null,8,["description"])):x("",!0),s(R,{"label-position":"top"},{default:a(()=>[s(h,{label:"新密码至少8位且包含字母和数字"},{default:a(()=>[s(f,{modelValue:t.newPassword,"onUpdate:modelValue":e[0]||(e[0]=P=>t.newPassword=P),type:"password","show-password":"",placeholder:"请输入新密码",autocomplete:"new-password"},null,8,["modelValue"])]),_:1}),s(h,{label:"确认密码"},{default:a(()=>[s(f,{modelValue:t.confirmPassword,"onUpdate:modelValue":e[1]||(e[1]=P=>t.confirmPassword=P),type:"password","show-password":"",placeholder:"请再次输入新密码",autocomplete:"new-password",onKeyup:z(V,["enter"])},null,8,["modelValue"])]),_:1})]),_:1}),s(p,{type:"primary",class:"submit-btn",loading:g.value,disabled:!I.value,onClick:V},{default:a(()=>[...e[3]||(e[3]=[k(" 确认重置 ",-1)])]),_:1},8,["loading","disabled"]),m("div",W,[s(p,{link:"",type:"primary",onClick:S},{default:a(()=>[...e[4]||(e[4]=[k("返回登录",-1)])]),_:1}),d.value>0?(w(),v("span",X,G(d.value)+" 秒后自动跳转…",1)):x("",!0)])],64)):(w(),v(T,{key:0},[s(c,{type:"error",closable:!1,title:"链接已失效",description:b.value,"show-icon":""},null,8,["description"]),m("div",Q,[s(p,{type:"primary",onClick:S},{default:a(()=>[...e[2]||(e[2]=[k("返回登录",-1)])]),_:1})])],64))]),_:1})])}}},oe=L(Y,[["__scopeId","data-v-0bbb511c"]]);export{oe as default};

View File

@@ -1 +1 @@
import{_ as U,a as o,c as I,o as E,m as R,b as k,e as i,h as s,g as d,u as j,i as _,d as l,f as B,j as W,k as T,t as v}from"./index-DMtbRy1f.js";const $={class:"auth-wrap"},z={class:"actions"},D={key:0,class:"countdown app-muted"},M={__name:"VerifyResultPage",setup(q){const x=j(),p=o(!1),f=o(""),m=o(""),w=o(""),y=o(""),r=o(""),u=o(""),c=o(""),n=o(0);let a=null;function C(){if(typeof window>"u")return null;const e=window.__APP_INITIAL_STATE__;return!e||typeof e!="object"?null:(window.__APP_INITIAL_STATE__=null,e)}function N(e){const t=!!e?.success;p.value=t,f.value=e?.title||(t?"验证成功":"验证失败"),m.value=e?.message||e?.error_message||(t?"操作已完成,现在可以继续使用系统。":"操作失败,请稍后重试。"),w.value=e?.primary_label||(t?"立即登录":"重新注册"),y.value=e?.primary_url||(t?"/login":"/register"),r.value=e?.secondary_label||(t?"":"返回登录"),u.value=e?.secondary_url||(t?"":"/login"),c.value=e?.redirect_url||(t?"/login":""),n.value=Number(e?.redirect_seconds||(t?5:0))||0}const A=I(()=>!!(r.value&&u.value)),b=I(()=>!!(c.value&&n.value>0));async function g(e){if(e){if(e.startsWith("http://")||e.startsWith("https://")){window.location.href=e;return}await x.push(e)}}function P(){b.value&&(a=window.setInterval(()=>{n.value-=1,n.value<=0&&(window.clearInterval(a),a=null,window.location.href=c.value)},1e3))}return E(()=>{const e=C();N(e),P()}),R(()=>{a&&window.clearInterval(a)}),(e,t)=>{const h=d("el-button"),V=d("el-result"),L=d("el-card");return _(),k("div",$,[i(L,{shadow:"never",class:"auth-card","body-style":{padding:"22px"}},{default:s(()=>[t[2]||(t[2]=l("div",{class:"brand"},[l("div",{class:"brand-title"},"知识管理平台"),l("div",{class:"brand-sub app-muted"},"验证结果")],-1)),i(V,{icon:p.value?"success":"error",title:f.value,"sub-title":m.value,class:"result"},{extra:s(()=>[l("div",z,[i(h,{type:"primary",onClick:t[0]||(t[0]=S=>g(y.value))},{default:s(()=>[T(v(w.value),1)]),_:1}),A.value?(_(),W(h,{key:0,onClick:t[1]||(t[1]=S=>g(u.value))},{default:s(()=>[T(v(r.value),1)]),_:1})):B("",!0)]),b.value?(_(),k("div",D,v(n.value)+" 秒后自动跳转... ",1)):B("",!0)]),_:1},8,["icon","title","sub-title"])]),_:1})])}}},G=U(M,[["__scopeId","data-v-1fc6b081"]]);export{G as default}; import{_ as U,a as o,c as I,o as E,m as R,b as k,e as i,h as s,g as d,u as j,i as _,d as l,f as B,j as W,k as T,t as v}from"./index-D1OuoXoU.js";const $={class:"auth-wrap"},z={class:"actions"},D={key:0,class:"countdown app-muted"},M={__name:"VerifyResultPage",setup(q){const x=j(),p=o(!1),f=o(""),m=o(""),w=o(""),y=o(""),r=o(""),u=o(""),c=o(""),n=o(0);let a=null;function C(){if(typeof window>"u")return null;const e=window.__APP_INITIAL_STATE__;return!e||typeof e!="object"?null:(window.__APP_INITIAL_STATE__=null,e)}function N(e){const t=!!e?.success;p.value=t,f.value=e?.title||(t?"验证成功":"验证失败"),m.value=e?.message||e?.error_message||(t?"操作已完成,现在可以继续使用系统。":"操作失败,请稍后重试。"),w.value=e?.primary_label||(t?"立即登录":"重新注册"),y.value=e?.primary_url||(t?"/login":"/register"),r.value=e?.secondary_label||(t?"":"返回登录"),u.value=e?.secondary_url||(t?"":"/login"),c.value=e?.redirect_url||(t?"/login":""),n.value=Number(e?.redirect_seconds||(t?5:0))||0}const A=I(()=>!!(r.value&&u.value)),b=I(()=>!!(c.value&&n.value>0));async function g(e){if(e){if(e.startsWith("http://")||e.startsWith("https://")){window.location.href=e;return}await x.push(e)}}function P(){b.value&&(a=window.setInterval(()=>{n.value-=1,n.value<=0&&(window.clearInterval(a),a=null,window.location.href=c.value)},1e3))}return E(()=>{const e=C();N(e),P()}),R(()=>{a&&window.clearInterval(a)}),(e,t)=>{const h=d("el-button"),V=d("el-result"),L=d("el-card");return _(),k("div",$,[i(L,{shadow:"never",class:"auth-card","body-style":{padding:"22px"}},{default:s(()=>[t[2]||(t[2]=l("div",{class:"brand"},[l("div",{class:"brand-title"},"知识管理平台"),l("div",{class:"brand-sub app-muted"},"验证结果")],-1)),i(V,{icon:p.value?"success":"error",title:f.value,"sub-title":m.value,class:"result"},{extra:s(()=>[l("div",z,[i(h,{type:"primary",onClick:t[0]||(t[0]=S=>g(y.value))},{default:s(()=>[T(v(w.value),1)]),_:1}),A.value?(_(),W(h,{key:0,onClick:t[1]||(t[1]=S=>g(u.value))},{default:s(()=>[T(v(r.value),1)]),_:1})):B("",!0)]),b.value?(_(),k("div",D,v(n.value)+" 秒后自动跳转... ",1)):B("",!0)]),_:1},8,["icon","title","sub-title"])]),_:1})])}}},G=U(M,[["__scopeId","data-v-1fc6b081"]]);export{G as default};

View File

@@ -1 +1 @@
import{p as c}from"./index-DMtbRy1f.js";async function o(t={}){const{data:a}=await c.get("/accounts",{params:t});return a}async function u(t){const{data:a}=await c.post("/accounts",t);return a}async function r(t,a){const{data:n}=await c.put(`/accounts/${t}`,a);return n}async function e(t){const{data:a}=await c.delete(`/accounts/${t}`);return a}async function i(t,a){const{data:n}=await c.put(`/accounts/${t}/remark`,a);return n}async function p(t,a){const{data:n}=await c.post(`/accounts/${t}/start`,a);return n}async function d(t){const{data:a}=await c.post(`/accounts/${t}/stop`,{});return a}async function f(t){const{data:a}=await c.post("/accounts/batch/start",t);return a}async function w(t){const{data:a}=await c.post("/accounts/batch/stop",t);return a}async function y(){const{data:t}=await c.post("/accounts/clear",{});return t}async function A(t,a={}){const{data:n}=await c.post(`/accounts/${t}/screenshot`,a);return n}export{w as a,f as b,y as c,d,e,o as f,u as g,i as h,p as s,A as t,r as u}; import{p as c}from"./index-D1OuoXoU.js";async function o(t={}){const{data:a}=await c.get("/accounts",{params:t});return a}async function u(t){const{data:a}=await c.post("/accounts",t);return a}async function r(t,a){const{data:n}=await c.put(`/accounts/${t}`,a);return n}async function e(t){const{data:a}=await c.delete(`/accounts/${t}`);return a}async function i(t,a){const{data:n}=await c.put(`/accounts/${t}/remark`,a);return n}async function p(t,a){const{data:n}=await c.post(`/accounts/${t}/start`,a);return n}async function d(t){const{data:a}=await c.post(`/accounts/${t}/stop`,{});return a}async function f(t){const{data:a}=await c.post("/accounts/batch/start",t);return a}async function w(t){const{data:a}=await c.post("/accounts/batch/stop",t);return a}async function y(){const{data:t}=await c.post("/accounts/clear",{});return t}async function A(t,a={}){const{data:n}=await c.post(`/accounts/${t}/screenshot`,a);return n}export{w as a,f as b,y as c,d,e,o as f,u as g,i as h,p as s,A as t,r as u};

View File

@@ -1 +1 @@
import{p as s}from"./index-DMtbRy1f.js";async function r(){const{data:a}=await s.get("/email/verify-status");return a}async function o(){const{data:a}=await s.post("/generate_captcha",{});return a}async function e(a){const{data:t}=await s.post("/login",a);return t}async function i(a){const{data:t}=await s.post("/register",a);return t}async function c(a){const{data:t}=await s.post("/resend-verify-email",a);return t}async function f(a){const{data:t}=await s.post("/forgot-password",a);return t}async function u(a){const{data:t}=await s.post("/reset-password-confirm",a);return t}export{f as a,i as b,u as c,r as f,o as g,e as l,c as r}; import{p as s}from"./index-D1OuoXoU.js";async function r(){const{data:a}=await s.get("/email/verify-status");return a}async function o(){const{data:a}=await s.post("/generate_captcha",{});return a}async function e(a){const{data:t}=await s.post("/login",a);return t}async function i(a){const{data:t}=await s.post("/register",a);return t}async function c(a){const{data:t}=await s.post("/resend-verify-email",a);return t}async function f(a){const{data:t}=await s.post("/forgot-password",a);return t}async function u(a){const{data:t}=await s.post("/reset-password-confirm",a);return t}export{f as a,i as b,u as c,r as f,o as g,e as l,c as r};

File diff suppressed because one or more lines are too long

View File

@@ -4,7 +4,7 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
<title>知识管理平台</title> <title>知识管理平台</title>
<script type="module" crossorigin src="./assets/index-DMtbRy1f.js"></script> <script type="module" crossorigin src="./assets/index-D1OuoXoU.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-BVjJVlht.css"> <link rel="stylesheet" crossorigin href="./assets/index-BVjJVlht.css">
</head> </head>
<body> <body>