Files
xinfra/frontend/src/components/AuditLogTable.vue
T
wonder f1a63ee473 feat(frontend): 支持深色/浅色模式切换,统一主题变量体系
- 新增 useTheme composable,支持 light/dark 双主题,默认浅色模式
- 主题偏好持久化到 localStorage,支持跟随系统主题
- AppHeader 顶栏添加 Moon/Sunny 切换图标,带旋转过渡动效
- variables.css 重构为 :root(浅色)/:root.dark(深色)双套变量
- 新增标签色系(蓝/紫/琥珀/绿)、节点色系、阴影、发光效果等语义化变量
- 全组件硬编码颜色替换为 CSS 变量,消除跨主题不一致
- global.css 添加主题切换过渡动画(background/border/box-shadow)
- 涉及组件:AppHeader、AppSidebar、SubsystemCard、AuditLogTable
- 涉及页面:Dashboard、Resource、Cluster、Config、Task、Service、Login
2026-07-15 14:38:58 +08:00

208 lines
4.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="panel">
<div class="panel-head">
<h3>{{ title }}</h3>
<span class="meta">共 {{ total }} 条</span>
</div>
<div class="panel-body">
<table>
<thead>
<tr>
<th v-for="col in columns" :key="col.key">{{ col.label }}</th>
</tr>
</thead>
<tbody>
<tr v-for="row in data" :key="row.id" class="tr-hover">
<td v-for="col in columns" :key="col.key" :class="col.class">
<template v-if="col.key === 'status'">
<span :class="['status-text', row.status]">
● {{ statusMap[row.status] || row.status }}
</span>
</template>
<template v-else-if="col.key === 'source_ip' || col.key === 'username'">
<span class="mono">{{ row[col.key] }}</span>
</template>
<template v-else>
{{ row[col.key] }}
</template>
</td>
</tr>
</tbody>
</table>
<div class="pagination">
<span>共 {{ total }} 条 · 每页 {{ pageSize }} 条</span>
<div class="pg-btns">
<span class="pg-btn disabled">‹</span>
<span class="pg-btn active">1</span>
<span class="pg-btn">2</span>
<span class="pg-btn">3</span>
<span class="pg-sep">…</span>
<span class="pg-btn">{{ Math.ceil(total / pageSize) }}</span>
<span class="pg-btn">›</span>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
interface Column {
key: string
label: string
class?: string
}
defineProps<{
title: string
columns: Column[]
data: any[]
total: number
pageSize?: number
}>()
const statusMap: Record<string, string> = {
success: '成功',
failed: '失败',
running: '执行中',
}
</script>
<style scoped>
.panel {
background: var(--bg-panel);
border: 1px solid var(--line);
border-radius: 8px;
margin-bottom: 18px;
}
.panel-head {
display: flex;
align-items: center;
justify-content: space-between;
padding: 13px 16px;
border-bottom: 1px solid var(--line-soft);
}
.panel-head h3 {
margin: 0;
font-size: 13.5px;
font-weight: 600;
}
.panel-head .meta {
font-size: 11.5px;
color: var(--text-dim);
font-family: var(--mono);
}
.panel-body {
padding: 4px 0;
}
table {
width: 100%;
border-collapse: collapse;
font-size: 12.5px;
}
th {
text-align: left;
color: var(--text-dim);
font-weight: 500;
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.4px;
padding: 9px 16px;
border-bottom: 1px solid var(--line-soft);
}
td {
padding: 11px 16px;
border-bottom: 1px solid var(--line-soft);
color: var(--text-mid);
}
tr:last-child td {
border-bottom: none;
}
tr.tr-hover:hover td {
background: var(--bg-panel-2);
}
.mono {
font-family: var(--mono);
}
.status-text {
font-size: 12px;
display: flex;
align-items: center;
}
.status-text.success {
color: var(--accent);
}
.status-text.failed {
color: var(--err);
}
.status-text.running {
color: var(--warn);
}
.pagination {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 16px;
border-top: 1px solid var(--line-soft);
font-size: 11.5px;
color: var(--text-dim);
}
.pg-btns {
display: flex;
gap: 4px;
align-items: center;
}
.pg-btn {
min-width: 26px;
height: 26px;
padding: 0 6px;
display: inline-flex;
align-items: center;
justify-content: center;
border: 1px solid var(--line);
border-radius: 5px;
color: var(--text-mid);
font-family: var(--mono);
font-size: 11px;
background: var(--bg-panel-2);
cursor: pointer;
}
.pg-btn.active {
background: var(--accent-dim);
border-color: var(--accent-dim);
color: var(--active-text);
}
.pg-btn:hover {
border-color: var(--hover-border);
color: var(--text-hi);
}
.pg-btn.disabled {
opacity: 0.35;
cursor: not-allowed;
}
.pg-sep {
color: var(--text-dim);
padding: 0 2px;
}
</style>