mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-10-13 12:49:30 +00:00
refactor: 前端项目代码优化与样式调整
本次提交包含多项改进: 1. 新增移动端断点常量并全局复用,重构响应式设备检测逻辑 2. 优化表格卡片样式与布局,统一移除多余的shadow属性 3. 调整表单、按钮、分页组件的移动端适配样式 4. 补充邮箱国际化文案与图表组件标题属性 5. 优化菜单hover效果、全局搜索样式与深色主题变量 6. 修复权限配置、组件默认值与布局排版问题 7. 简化部分代码冗余逻辑,统一代码风格
This commit is contained in:
+11
-7
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="fa-full-height">
|
||||
<div class="flex flex-col relative last:mb-0">
|
||||
<ElTabs>
|
||||
<!-- 监控信息 Tab -->
|
||||
<ElTabPane label="监控信息">
|
||||
@@ -13,7 +13,7 @@
|
||||
<span class="font-medium">Redis监控信息</span>
|
||||
</div>
|
||||
</template>
|
||||
<FaDescriptions :column="6" :scrollbar="false">
|
||||
<FaDescriptions :column="descColumns" :scrollbar="false">
|
||||
<ElDescriptionsItem label="Redis版本">
|
||||
{{ cache.info?.redis_version || "-" }}
|
||||
</ElDescriptionsItem>
|
||||
@@ -61,7 +61,7 @@
|
||||
</ElRow>
|
||||
|
||||
<ElRow :gutter="16" class="flex-1 min-h-0">
|
||||
<ElCol :span="12" class="flex flex-col min-h-0">
|
||||
<ElCol :xs="24" :sm="12" class="mb-5">
|
||||
<ElCard shadow="hover" class="flex-1 flex flex-col chart-card">
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2">
|
||||
@@ -72,7 +72,7 @@
|
||||
<div ref="commandstats" class="chart-container" />
|
||||
</ElCard>
|
||||
</ElCol>
|
||||
<ElCol :span="12" class="flex flex-col min-h-0">
|
||||
<ElCol :xs="24" :sm="12" class="mb-5">
|
||||
<ElCard shadow="hover" class="flex-1 flex flex-col chart-card">
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2">
|
||||
@@ -92,7 +92,7 @@
|
||||
<div class="cache-mgmt-tab">
|
||||
<ElRow :gutter="16" class="flex-1 min-h-0">
|
||||
<!-- 缓存列表 -->
|
||||
<ElCol :span="8" class="cache-mgmt-col">
|
||||
<ElCol :xs="24" :md="8" class="cache-mgmt-col mb-5 h-full">
|
||||
<ElCard :loading="loading" shadow="hover" class="cache-mgmt-card">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
@@ -152,7 +152,7 @@
|
||||
</ElCol>
|
||||
|
||||
<!-- 键名列表 -->
|
||||
<ElCol :span="8" class="cache-mgmt-col">
|
||||
<ElCol :xs="24" :md="8" class="cache-mgmt-col mb-5 h-full">
|
||||
<ElCard :loading="loading" shadow="hover" class="cache-mgmt-card">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
@@ -215,7 +215,7 @@
|
||||
</ElCol>
|
||||
|
||||
<!-- 缓存内容 -->
|
||||
<ElCol :span="8" class="cache-mgmt-col">
|
||||
<ElCol :xs="24" :md="8" class="cache-mgmt-col mb-5 h-full">
|
||||
<ElCard :loading="loading" shadow="hover" class="cache-mgmt-card">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
@@ -270,9 +270,13 @@ import CacheAPI, {
|
||||
type RedisInfo,
|
||||
} from "@/api/module_monitor/cache";
|
||||
import * as echarts from "echarts";
|
||||
import { useWindowSize } from "@vueuse/core";
|
||||
|
||||
defineOptions({ name: "CacheMonitor" });
|
||||
|
||||
const { width: winWidth } = useWindowSize();
|
||||
const descColumns = computed(() => (winWidth.value < 768 ? 2 : 6));
|
||||
|
||||
const cacheNames = ref<CacheInfo[]>([]);
|
||||
const cacheKeys = ref<string[]>([]);
|
||||
const loading = ref(true);
|
||||
|
||||
@@ -17,11 +17,7 @@
|
||||
@reset="onResetSearch"
|
||||
/>
|
||||
|
||||
<ElCard
|
||||
shadow="hover"
|
||||
class="fa-table-card"
|
||||
:style="{ 'margin-top': showSearchBar ? '12px' : '0' }"
|
||||
>
|
||||
<ElCard class="fa-table-card" :style="{ 'margin-top': showSearchBar ? '12px' : '0' }">
|
||||
<FaTableHeader
|
||||
v-model:columns="columnChecks"
|
||||
v-model:showSearchBar="showSearchBar"
|
||||
@@ -64,12 +60,12 @@ import { h, ref, computed } from "vue";
|
||||
import { useTable } from "@/hooks/core/useTable";
|
||||
import OnlineAPI, { type OnlineUserTable } from "@/api/module_monitor/online";
|
||||
import type { ColumnOption } from "@/types/component";
|
||||
import { ElMessageBox, ElTooltip } from "element-plus";
|
||||
import { ElMessageBox } from "element-plus";
|
||||
import { useAuth } from "@/hooks/core/useAuth";
|
||||
import { renderTableOperationCell, type TableOperationAction } from "@/utils/table";
|
||||
import type { SearchFormItem } from "@/components/forms/fa-search-bar/index.vue";
|
||||
import type FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
|
||||
import FaCopyButton from "@/components/others/fa-copy-button/index.vue";
|
||||
import FaButtonTable from "@/components/forms/fa-button-table/index.vue";
|
||||
|
||||
const { hasAuth } = useAuth();
|
||||
|
||||
@@ -143,6 +139,23 @@ function kickSession(sessionId: string) {
|
||||
})();
|
||||
}
|
||||
|
||||
function buildOnlineRowActions(row: OnlineUserTable): TableOperationAction[] {
|
||||
const all: TableOperationAction[] = [
|
||||
{
|
||||
key: "kick",
|
||||
label: "强退",
|
||||
artType: "delete",
|
||||
perm: "module_monitor:online:delete",
|
||||
run: () => kickSession(row.session_id),
|
||||
},
|
||||
];
|
||||
return all.filter((a) => a.perm != null && hasAuth(a.perm));
|
||||
}
|
||||
|
||||
function formatOnlineOperationCell(row: OnlineUserTable) {
|
||||
return renderTableOperationCell(buildOnlineRowActions(row));
|
||||
}
|
||||
|
||||
const {
|
||||
columns,
|
||||
columnChecks,
|
||||
@@ -226,20 +239,8 @@ const {
|
||||
label: "操作",
|
||||
width: 88,
|
||||
fixed: "right",
|
||||
align: "right",
|
||||
formatter: (row: OnlineUserTable) => {
|
||||
if (!hasAuth("module_monitor:online:delete")) {
|
||||
return h("span", { class: "text-g-400" }, "—");
|
||||
}
|
||||
return h(ElTooltip, { content: "强退", placement: "top" }, () =>
|
||||
h("span", { class: "inline-flex" }, [
|
||||
h(FaButtonTable, {
|
||||
type: "delete",
|
||||
onClick: () => kickSession(row.session_id),
|
||||
}),
|
||||
])
|
||||
);
|
||||
},
|
||||
align: "center",
|
||||
formatter: (row: OnlineUserTable) => formatOnlineOperationCell(row),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -223,7 +223,7 @@ import type { ColumnOption } from "@/types/component";
|
||||
import { useAuth } from "@/hooks/core/useAuth";
|
||||
import type { SearchFormItem } from "@/components/forms/fa-search-bar/index.vue";
|
||||
import type FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
|
||||
import FaButtonTable from "@/components/forms/fa-button-table/index.vue";
|
||||
import { renderTableOperationCell, type TableOperationAction } from "@/utils/table";
|
||||
|
||||
const { hasAuth } = useAuth();
|
||||
|
||||
@@ -391,53 +391,51 @@ const {
|
||||
{
|
||||
prop: "operation",
|
||||
label: "操作",
|
||||
width: 220,
|
||||
width: 136,
|
||||
fixed: "right",
|
||||
align: "center",
|
||||
formatter: (row: ResourceItem) =>
|
||||
h(
|
||||
ElSpace,
|
||||
{ wrap: true, size: 4 },
|
||||
() =>
|
||||
[
|
||||
!row.is_dir && hasAuth("module_monitor:resource:download")
|
||||
? h(ElTooltip, { content: "下载", placement: "top" }, () =>
|
||||
h("span", { class: "inline-flex" }, [
|
||||
h(FaButtonTable, {
|
||||
type: "view",
|
||||
icon: "ri:download-line",
|
||||
onClick: () => void handleDownload(row),
|
||||
}),
|
||||
])
|
||||
)
|
||||
: null,
|
||||
hasAuth("module_monitor:resource:rename")
|
||||
? h(ElTooltip, { content: "重命名", placement: "top" }, () =>
|
||||
h("span", { class: "inline-flex" }, [
|
||||
h(FaButtonTable, {
|
||||
type: "edit",
|
||||
onClick: () => void handleRenameOpen(row),
|
||||
}),
|
||||
])
|
||||
)
|
||||
: null,
|
||||
hasAuth("module_monitor:resource:delete")
|
||||
? h(ElTooltip, { content: "删除", placement: "top" }, () =>
|
||||
h("span", { class: "inline-flex" }, [
|
||||
h(FaButtonTable, {
|
||||
type: "delete",
|
||||
onClick: () => void handleDelete(row),
|
||||
}),
|
||||
])
|
||||
)
|
||||
: null,
|
||||
].filter(Boolean) as ReturnType<typeof h>[]
|
||||
),
|
||||
formatter: (row: ResourceItem) => formatResourceOperationCell(row),
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
function buildResourceRowActions(row: ResourceItem): TableOperationAction[] {
|
||||
const actions: TableOperationAction[] = [];
|
||||
if (!row.is_dir && hasAuth("module_monitor:resource:download")) {
|
||||
actions.push({
|
||||
key: "download",
|
||||
label: "下载",
|
||||
artType: "view",
|
||||
icon: "ri:download-line",
|
||||
run: () => void handleDownload(row),
|
||||
});
|
||||
}
|
||||
if (hasAuth("module_monitor:resource:rename")) {
|
||||
actions.push({
|
||||
key: "rename",
|
||||
label: "重命名",
|
||||
artType: "edit",
|
||||
run: () => void handleRenameOpen(row),
|
||||
});
|
||||
}
|
||||
if (hasAuth("module_monitor:resource:delete")) {
|
||||
actions.push({
|
||||
key: "delete",
|
||||
label: "删除",
|
||||
artType: "delete",
|
||||
run: () => void handleDelete(row),
|
||||
});
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
||||
function formatResourceOperationCell(row: ResourceItem) {
|
||||
return renderTableOperationCell(buildResourceRowActions(row), {
|
||||
wrapperClass: "inline-flex items-center justify-center gap-1",
|
||||
});
|
||||
}
|
||||
|
||||
function handleBreadcrumbClick(item: { path: string }) {
|
||||
currentPath.value = item.path;
|
||||
updateBreadcrumb();
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div class="server-container">
|
||||
<ElRow :gutter="16" class="server-row">
|
||||
<div class="flex flex-col relative last:mb-0">
|
||||
<ElRow :gutter="16">
|
||||
<!-- CPU 使用情况 -->
|
||||
<ElCol :span="12" class="server-col">
|
||||
<ElCard :loading="loading" shadow="hover" class="server-card">
|
||||
<ElCol :xs="24" :sm="12" class="mb-5">
|
||||
<ElCard :loading="loading" shadow="hover">
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2">
|
||||
<FaSvgIcon icon="ri:cpu-line" class="text-lg" />
|
||||
@@ -11,7 +11,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<div class="flex items-center flex-col gap-4">
|
||||
<div class="flex items-center gap-6">
|
||||
<div class="flex items-center gap-6 max-md:flex-col max-md:gap-3">
|
||||
<ElProgress
|
||||
type="circle"
|
||||
:percentage="server.cpu?.used || 0"
|
||||
@@ -45,8 +45,8 @@
|
||||
</ElCol>
|
||||
|
||||
<!-- 内存使用情况 -->
|
||||
<ElCol :span="12" class="server-col">
|
||||
<ElCard :loading="loading" shadow="hover" class="server-card">
|
||||
<ElCol :xs="24" :sm="12" class="mb-5">
|
||||
<ElCard :loading="loading" shadow="hover">
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2">
|
||||
<FaSvgIcon icon="ri:ram-line" class="text-lg" />
|
||||
@@ -54,7 +54,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<div class="flex items-center flex-col gap-4">
|
||||
<div class="flex items-center gap-6">
|
||||
<div class="flex items-center gap-6 max-md:flex-col max-md:gap-3">
|
||||
<ElProgress
|
||||
type="circle"
|
||||
:percentage="server.mem?.usage || 0"
|
||||
@@ -88,10 +88,10 @@
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElRow :gutter="16" class="server-row">
|
||||
<ElRow :gutter="16">
|
||||
<!-- 服务器基本信息 -->
|
||||
<ElCol :span="12" class="server-col">
|
||||
<ElCard :loading="loading" shadow="hover" class="server-card">
|
||||
<ElCol :xs="24" :sm="12" class="mb-5">
|
||||
<ElCard :loading="loading" shadow="hover">
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2">
|
||||
<FaSvgIcon icon="ri:server-line" class="text-lg" />
|
||||
@@ -116,8 +116,8 @@
|
||||
</ElCol>
|
||||
|
||||
<!-- Python运行环境 -->
|
||||
<ElCol :span="12" class="server-col">
|
||||
<ElCard :loading="loading" shadow="hover" class="server-card">
|
||||
<ElCol :xs="24" :sm="12" class="mb-5">
|
||||
<ElCard :loading="loading" shadow="hover">
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2">
|
||||
<FaSvgIcon icon="ri:code-s-slash-line" class="text-lg" />
|
||||
@@ -149,9 +149,9 @@
|
||||
</ElRow>
|
||||
|
||||
<!-- 磁盘使用情况 -->
|
||||
<ElRow :gutter="16" class="server-row">
|
||||
<ElCol :span="24" class="server-col">
|
||||
<ElCard :loading="loading" shadow="hover" class="server-card">
|
||||
<ElRow :gutter="16">
|
||||
<ElCol :span="24" class="mb-5">
|
||||
<ElCard :loading="loading" shadow="hover">
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2">
|
||||
<FaSvgIcon icon="ri:hard-drive-2-line" class="text-lg" />
|
||||
@@ -227,34 +227,9 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
// 与 dashboard 首页一致:自定义圆角 + 边框色
|
||||
:deep(.el-card) {
|
||||
--el-card-border-radius: calc(var(--custom-radius) + 2px);
|
||||
|
||||
border: 1px solid var(--fa-card-border);
|
||||
}
|
||||
|
||||
.server-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.server-row {
|
||||
.server-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
|
||||
.server-card {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
|
||||
:deep(.el-card__body) {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user