mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-26 22:31:21 +00:00
refactor: 项目整体优化与功能迭代
主要变更: 1. 移除冗余代码:删除重复的CommonUtil、旧主题管理、缓存请求等模块 2. 依赖升级:更新vite-plugin-uni-components到0.3.2版本 3. 样式优化:调整卡片高度、主题色配置、隐私弹窗样式 4. 代码重构:简化用户store、请求类型、列表分页逻辑 5. 新增功能:添加工单统计、tabbar高亮、通用工具类等新模块 6. 修复细节:调整排版顺序、修复水印主题store引用、优化表单样式
This commit is contained in:
@@ -69,6 +69,9 @@
|
||||
:is="() => renderColumnHeader(headerScope, col)"
|
||||
/>
|
||||
</template>
|
||||
<template #filter-icon="{ filterOpened }">
|
||||
<Filter class="fa-filter-icon" :class="{ 'is-opened': filterOpened }" />
|
||||
</template>
|
||||
<template #default="slotScope">
|
||||
<component
|
||||
v-if="col.useSlot && col.prop && shouldRenderSlotScope(slotScope)"
|
||||
@@ -138,6 +141,7 @@ import { useCommon } from "@/hooks/core/useCommon";
|
||||
import { useTableHeight } from "@/hooks/core/useTableHeight";
|
||||
import { useWindowSize } from "@vueuse/core";
|
||||
import { VueDraggable } from "vue-draggable-plus";
|
||||
import { Filter } from "@element-plus/icons-vue";
|
||||
import { MOBILE_BREAKPOINT } from "@utils/constants/definitions";
|
||||
import type { ColumnOption } from "@/types/component";
|
||||
|
||||
@@ -542,6 +546,57 @@ const cleanColumnProps = (col: ColumnOption) => {
|
||||
return columnProps;
|
||||
};
|
||||
|
||||
/** 创建人 / 更新人列识别:通过 prop 或 label 匹配 */
|
||||
const PERSON_FILTER_RE = /(?:create|update)(?:d)?_(?:by|user|name|id)|creator|updater/i;
|
||||
const isPersonFilterColumn = (col: ColumnOption): boolean => {
|
||||
// 已显式配置筛选则跳过自动逻辑
|
||||
if (col.filters || col.filterMethod) return false;
|
||||
const prop = col.prop || "";
|
||||
const label = col.label || "";
|
||||
return PERSON_FILTER_RE.test(prop) || /创建人|更新人|创建者|更新者/.test(label);
|
||||
};
|
||||
|
||||
/** 将创建人/更新人列 prop 归一化为名称取值路径:
|
||||
* created_id → created_by.name;created_by / created_by.name 等保持不变 */
|
||||
const getPersonNamePath = (prop: string): string => prop.replace(/_id(?:\..*)?$/i, "_by.name");
|
||||
|
||||
/** 解析嵌套路径取值(如 created_by.name),与 ElTable 单元格取值规则一致 */
|
||||
const getPathValue = (row: Record<string, any>, path: string): unknown => {
|
||||
let value: unknown = row;
|
||||
for (const key of path.split(".")) {
|
||||
if (value == null) return undefined;
|
||||
value = (value as Record<string, unknown>)[key];
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
/** 单元格值规范化为筛选文本:对象时优先取 name(created_by/updated_by 为对象) */
|
||||
const toFilterText = (v: unknown): string => {
|
||||
if (v && typeof v === "object" && "name" in v) {
|
||||
return String((v as { name: unknown }).name ?? "");
|
||||
}
|
||||
return String(v);
|
||||
};
|
||||
|
||||
/** 从当前表格数据中提取某列的去重值作为筛选选项 */
|
||||
const getColumnFilterOptions = (col: ColumnOption): { text: string; value: string }[] => {
|
||||
if (!col.prop) return [];
|
||||
const seen = new Set<string>();
|
||||
const options: { text: string; value: string }[] = [];
|
||||
const path = getPersonNamePath(col.prop);
|
||||
for (const row of props.data || []) {
|
||||
const v = getPathValue(row as Record<string, any>, path);
|
||||
if (v === null || v === undefined || v === "") continue;
|
||||
const text = toFilterText(v);
|
||||
if (!text) continue;
|
||||
if (!seen.has(text)) {
|
||||
seen.add(text);
|
||||
options.push({ text, value: text });
|
||||
}
|
||||
}
|
||||
return options;
|
||||
};
|
||||
|
||||
/** 普通列:单元格已由插槽内 TableFormatterOutlet 渲染,勿再把 formatter 传给 ElTableColumn,避免与 EP 内置 renderCell 混用 */
|
||||
const cleanBodyColumnProps = (col: ColumnOption) => {
|
||||
const columnProps = cleanColumnProps(col);
|
||||
@@ -551,6 +606,13 @@ const cleanBodyColumnProps = (col: ColumnOption) => {
|
||||
if (isOpCol && isMobile.value) {
|
||||
columnProps.width = 80;
|
||||
}
|
||||
// 创建人 / 更新人列:自动生成表头筛选选项,无需调用方手写 filters
|
||||
if (isPersonFilterColumn(col)) {
|
||||
columnProps.filters = getColumnFilterOptions(col);
|
||||
columnProps.filterMethod = (value: any, row: any) =>
|
||||
toFilterText(getPathValue(row as Record<string, any>, getPersonNamePath(col.prop as string))) ===
|
||||
String(value);
|
||||
}
|
||||
return columnProps;
|
||||
};
|
||||
|
||||
@@ -780,5 +842,17 @@ defineExpose({
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
/* 表头筛选图标:替换 EP 默认箭头为漏斗,悬停/展开/已筛选时高亮为主题色 */
|
||||
:deep(.el-table__column-filter-trigger .fa-filter-icon) {
|
||||
color: var(--el-text-color-placeholder);
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
:deep(.el-table__column-filter-trigger:hover .fa-filter-icon),
|
||||
:deep(.el-table__column-filter-trigger .fa-filter-icon.is-opened),
|
||||
:deep(.cell.highlight .fa-filter-icon) {
|
||||
color: var(--theme-color);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
<ElCol :xs="24" :sm="12" :md="12" class="mb-5">
|
||||
<ElCard
|
||||
shadow="hover"
|
||||
class="overflow-hidden border border-(--el-border-color-lighter) rounded-xl flex flex-col h-full"
|
||||
class="fa-card overflow-hidden border border-(--el-border-color-lighter) rounded-xl flex flex-col h-138"
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex flex-wrap gap-3 items-start justify-between w-full">
|
||||
@@ -142,35 +142,13 @@
|
||||
</ElRow>
|
||||
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :xs="24" :sm="6" :md="5" class="mb-5">
|
||||
<FaImageCard
|
||||
:imageUrl="imageCards.imageUrl"
|
||||
:title="imageCards.title"
|
||||
:category="imageCards.category"
|
||||
:readTime="imageCards.readTime"
|
||||
:views="imageCards.views"
|
||||
:comments="imageCards.comments"
|
||||
:date="imageCards.date"
|
||||
@click="handleImageCardClick"
|
||||
/>
|
||||
<ElCol :xs="24" :sm="6" :md="6" class="mb-5">
|
||||
<ImageCards />
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="6" :md="5" class="mb-5">
|
||||
<FaCardBanner
|
||||
:image="bannerIcon4"
|
||||
title="版本更新提醒"
|
||||
description="FastapiAdmin v3.0.0 已发布,包含优化和新功能。"
|
||||
:button="{
|
||||
show: true,
|
||||
text: '立即更新',
|
||||
color: 'var(--theme-color)',
|
||||
textColor: '#fff',
|
||||
}"
|
||||
:cancelButton="{ show: true, text: '稍后提醒', color: '#eee', textColor: '#333' }"
|
||||
@click="handleBannerDemoConfirm"
|
||||
@cancel="handleBannerDemoCancel"
|
||||
/>
|
||||
<ElCol :xs="24" :sm="6" :md="6" class="mb-5">
|
||||
<ItBanners />
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :md="14" class="mb-5">
|
||||
<ElCol :xs="24" :sm="12" :md="12" class="mb-5">
|
||||
<AboutProject />
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
@@ -184,9 +162,8 @@ defineOptions({ name: "Home", inheritAttrs: false });
|
||||
import { ref, onMounted, defineAsyncComponent } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { getDashboardMock } from "@/mock/dashboard";
|
||||
|
||||
import bannerIcon4 from "@imgs/3d/icon4.webp";
|
||||
import cover2 from "@imgs/cover/img2.webp";
|
||||
import ImageCards from "./modules/image_cards.vue";
|
||||
import ItBanners from "./modules/it_banners.vue";
|
||||
import Banner from "./modules/banner.vue";
|
||||
import NewUser from "./modules/new-user.vue";
|
||||
import TodoList from "./modules/todo-list.vue";
|
||||
@@ -216,38 +193,11 @@ const FaDonutChartCard = defineAsyncComponent(
|
||||
() => import("@/components/cards/fa-donut-chart-card/index.vue")
|
||||
);
|
||||
|
||||
// 非关键组件异步导入(延迟加载,提升首屏速度)
|
||||
const FaCardBanner = defineAsyncComponent(
|
||||
() => import("@/components/banners/fa-card-banner/index.vue")
|
||||
);
|
||||
const FaImageCard = defineAsyncComponent(
|
||||
() => import("@/components/cards/fa-image-card/index.vue")
|
||||
);
|
||||
const FaTimelineListCard = defineAsyncComponent(
|
||||
() => import("@/components/cards/fa-timeline-list-card/index.vue")
|
||||
);
|
||||
function handleBannerDemoConfirm() {
|
||||
// TODO: 接入真实操作
|
||||
}
|
||||
function handleBannerDemoCancel() {
|
||||
// TODO: 接入真实操作
|
||||
}
|
||||
// === 卡片演示数据 ← workplace ===
|
||||
const imageCards = {
|
||||
id: 1,
|
||||
imageUrl: cover2,
|
||||
title: "大数据分析助力企业决策的实践案例",
|
||||
category: "技术",
|
||||
readTime: "3分钟",
|
||||
views: 7234,
|
||||
comments: 5,
|
||||
date: "12月20日 周二",
|
||||
};
|
||||
|
||||
function handleMore() {
|
||||
ElMessage.info("查看更多");
|
||||
}
|
||||
function handleImageCardClick() {
|
||||
// TODO: 接入真实跳转
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div class="fa-card p-5 flex justify-between h-full">
|
||||
<div class="fa-card p-5 flex justify-between h-100">
|
||||
<div>
|
||||
<h2 class="text-2xl font-medium">关于项目</h2>
|
||||
<p class="text-g-700 mt-1">{{ systemName }} 是一款兼具设计美学与高效开发的后台系统</p>
|
||||
<p class="text-g-700 mt-1">使用了 Vue3、TypeScript、Vite、Element Plus 等前沿技术</p>
|
||||
|
||||
<div class="flex flex-wrap gap-3.5 max-w-150 mt-9">
|
||||
<div class="grid grid-cols-2 gap-3.5 max-w-150 mt-9">
|
||||
<div
|
||||
class="w-60 flex items-center justify-between h-12.5 px-3.5 border border-g-300 cursor-pointer rounded-lg text-sm bg-g-100 duration-300 hover:-translate-y-1 max-sm:w-full"
|
||||
class="flex items-center justify-between h-12.5 px-3.5 border border-g-300 cursor-pointer rounded-lg text-sm bg-g-100 duration-300 hover:-translate-y-1"
|
||||
v-for="link in linkList"
|
||||
:key="link.label"
|
||||
@click="goPage(link.url)"
|
||||
|
||||
@@ -1,46 +1,132 @@
|
||||
<template>
|
||||
<FaBasicBanner
|
||||
class="justify-center h-54! max-sm:pt-5! max-sm:h-auto!"
|
||||
:title="bannerTitle"
|
||||
:subtitle="bannerSubtitle"
|
||||
boxStyle="bg-theme/10!"
|
||||
titleColor="var(--fa-gray-900)"
|
||||
subtitleColor="var(--fa-gray-500)"
|
||||
:decoration="false"
|
||||
:meteorConfig="{
|
||||
enabled: true,
|
||||
count: 10,
|
||||
}"
|
||||
:buttonConfig="{
|
||||
show: false,
|
||||
text: '开始探索',
|
||||
color: 'var(--fa-success)',
|
||||
textColor: '#fff',
|
||||
radius: '6px',
|
||||
}"
|
||||
:imageConfig="{
|
||||
src: bannerCover,
|
||||
width: '18rem',
|
||||
bottom: '-7.5rem',
|
||||
}"
|
||||
@click="handleBannerClick"
|
||||
>
|
||||
<div class="flex items-center gap-4 mt-2">
|
||||
<ElAvatar
|
||||
v-if="currentUser.avatar"
|
||||
:size="80"
|
||||
:src="currentUser.avatar"
|
||||
style="background-color: transparent"
|
||||
/>
|
||||
<ElIcon v-else :size="56" class="text-g-500"><UserFilled /></ElIcon>
|
||||
<div>
|
||||
<div class="text-lg font-semibold text-g-800">{{ currentUser.name }}</div>
|
||||
<div class="text-sm text-g-600">
|
||||
{{ currentUser.dept_name }} · {{ currentUser.description }} · {{ currentUser.last_login }}
|
||||
<ElCarousel height="220px" :interval="6000">
|
||||
<ElCarouselItem>
|
||||
<FaBasicBanner
|
||||
height="100%"
|
||||
:title="bannerTitle"
|
||||
:subtitle="bannerSubtitle"
|
||||
boxStyle="bg-theme/10!"
|
||||
titleColor="var(--fa-gray-900)"
|
||||
subtitleColor="var(--fa-gray-500)"
|
||||
:decoration="false"
|
||||
:meteorConfig="{
|
||||
enabled: true,
|
||||
count: 10,
|
||||
}"
|
||||
:buttonConfig="{
|
||||
show: false,
|
||||
text: '开始探索',
|
||||
color: 'var(--fa-success)',
|
||||
textColor: '#fff',
|
||||
radius: '6px',
|
||||
}"
|
||||
:imageConfig="{
|
||||
src: bannerCover,
|
||||
width: '18rem',
|
||||
bottom: '-7.5rem',
|
||||
}"
|
||||
@click="handleBannerClick"
|
||||
>
|
||||
<div class="flex items-center gap-3 mt-2">
|
||||
<ElAvatar
|
||||
v-if="currentUser.avatar"
|
||||
:size="44"
|
||||
:src="currentUser.avatar"
|
||||
style="background-color: transparent"
|
||||
/>
|
||||
<ElIcon v-else :size="40" class="text-g-500"><UserFilled /></ElIcon>
|
||||
<div>
|
||||
<div class="text-base font-semibold text-g-800">{{ currentUser.name }}</div>
|
||||
<div class="text-xs text-g-600">
|
||||
{{ currentUser.dept_name }} · {{ currentUser.description }} · {{ currentUser.last_login }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</FaBasicBanner>
|
||||
</FaBasicBanner>
|
||||
</ElCarouselItem>
|
||||
|
||||
<ElCarouselItem>
|
||||
<FaBasicBanner
|
||||
height="100%"
|
||||
title="数据中心运行状态"
|
||||
subtitle="系统访问量同比增长 23%,所有服务运行稳定,数据监控正常。"
|
||||
/>
|
||||
</ElCarouselItem>
|
||||
|
||||
<ElCarouselItem>
|
||||
<FaBasicBanner
|
||||
height="100%"
|
||||
title="欢迎使用 FastapiAdmin"
|
||||
subtitle="基于 Vue 3 + TypeScript + Element Plus 构建的现代化管理系统。"
|
||||
titleColor="#333"
|
||||
subtitleColor="#666"
|
||||
boxStyle="!bg-[#D4F1F7]"
|
||||
:buttonConfig="{
|
||||
show: true,
|
||||
text: '开始探索',
|
||||
color: 'var(--fa-success)',
|
||||
textColor: '#fff',
|
||||
radius: '6px'
|
||||
}"
|
||||
@buttonClick="handleBannerClick"
|
||||
/>
|
||||
</ElCarouselItem>
|
||||
|
||||
<ElCarouselItem>
|
||||
<FaBasicBanner
|
||||
height="100%"
|
||||
title="探索星空计划"
|
||||
subtitle="加入我们的天文观测活动,发现宇宙的奥秘"
|
||||
boxStyle="!bg-[#FF8AAB]"
|
||||
:buttonConfig="{
|
||||
show: true,
|
||||
text: '立即参与',
|
||||
color: '#FF5A89',
|
||||
textColor: '#fff'
|
||||
}"
|
||||
:imageConfig="{
|
||||
src: icon3
|
||||
}"
|
||||
/>
|
||||
</ElCarouselItem>
|
||||
|
||||
<ElCarouselItem>
|
||||
<FaBasicBanner
|
||||
height="100%"
|
||||
boxStyle="!bg-[#70B1FF]"
|
||||
:imageConfig="{
|
||||
src: icon5
|
||||
}"
|
||||
>
|
||||
<template #title>
|
||||
<h2 style="margin: 0; font-size: 1.6rem; color: #fff !important">智能组件系统</h2>
|
||||
</template>
|
||||
|
||||
<template #subtitle>
|
||||
<div style="margin-top: 12px">
|
||||
<p style="position: relative; z-index: 10; font-style: italic"
|
||||
>灵活配置,强大扩展,支持自定义插槽内容</p
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #button>
|
||||
<div style="margin-top: 12px">
|
||||
<ElButton type="primary" color="#04A1FF"> 查看文档 </ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</FaBasicBanner>
|
||||
</ElCarouselItem>
|
||||
|
||||
<ElCarouselItem>
|
||||
<FaBasicBanner v-bind="PresetBanners.marketing" height="100%" />
|
||||
</ElCarouselItem>
|
||||
|
||||
<ElCarouselItem>
|
||||
<FaBasicBanner v-bind="PresetBanners.info" height="100%" />
|
||||
</ElCarouselItem>
|
||||
</ElCarousel>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -49,6 +135,8 @@ import bannerCover from "@imgs/login/lf_icon2.webp";
|
||||
import { useUserStore } from "@stores";
|
||||
import { greetings } from "@utils";
|
||||
import { UserFilled } from "@element-plus/icons-vue";
|
||||
import icon3 from '@imgs/3d/icon3.webp'
|
||||
import icon5 from '@imgs/3d/icon7.webp'
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
@@ -56,6 +144,7 @@ const userInfo = computed(() => userStore.basicInfo);
|
||||
|
||||
const handleBannerClick = (): void => {
|
||||
// TODO: 接入真实跳转或路由
|
||||
console.log('banner clicked')
|
||||
};
|
||||
|
||||
const timefix = greetings();
|
||||
@@ -72,4 +161,39 @@ const currentUser = {
|
||||
const bannerTitle = `欢迎回来 ~ ${currentUser.name}(${currentUser.username}) ${timefix} ${welcome}`;
|
||||
|
||||
const bannerSubtitle = `基于 FastAPI + Vue3 + TypeScript 构建的企业级中后台解决方案,支持多端开发。`;
|
||||
|
||||
/**
|
||||
* 预设横幅配置
|
||||
* 提供常用的横幅样式配置,可直接通过 v-bind 使用
|
||||
*/
|
||||
const PresetBanners = {
|
||||
marketing: {
|
||||
title: '限时优惠活动',
|
||||
subtitle: '精选商品 48 小时闪购,最高享受 7 折优惠,数量有限!',
|
||||
titleColor: 'var(--fa-gray-900)',
|
||||
subtitleColor: 'var(--fa-gray-900)',
|
||||
boxStyle: '!bg-success/15',
|
||||
meteorConfig: { enabled: true, count: 15 },
|
||||
buttonConfig: {
|
||||
show: true,
|
||||
text: '立即抢购',
|
||||
color: 'var(--fa-success)',
|
||||
textColor: '#fff'
|
||||
}
|
||||
},
|
||||
info: {
|
||||
title: '服务到期提醒',
|
||||
subtitle: '您的高级服务将在 7 天后到期,请及时续费以继续享受完整功能。',
|
||||
titleColor: 'var(--fa-gray-900)',
|
||||
subtitleColor: 'var(--fa-gray-900)',
|
||||
boxStyle: '!bg-theme/15',
|
||||
meteorConfig: { enabled: true, count: 15 },
|
||||
buttonConfig: {
|
||||
show: true,
|
||||
text: '立即续费',
|
||||
color: 'var(--fa-secondary)',
|
||||
textColor: '#fff'
|
||||
}
|
||||
}
|
||||
} as const
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<ElCarousel height="400px">
|
||||
<ElCarouselItem v-for="card in imageCards" :key="card.id" class="mb-5">
|
||||
<FaImageCard
|
||||
:imageUrl="card.imageUrl"
|
||||
:title="card.title"
|
||||
:category="card.category"
|
||||
:readTime="card.readTime"
|
||||
:views="card.views"
|
||||
:comments="card.comments"
|
||||
:date="card.date"
|
||||
@click="handleImageCardClick(card)"
|
||||
/>
|
||||
</ElCarouselItem>
|
||||
</ElCarousel>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import FaImageCard from "@/components/cards/fa-image-card/index.vue"
|
||||
import cover1 from '@imgs/cover/img1.webp'
|
||||
import cover2 from '@imgs/cover/img2.webp'
|
||||
import cover3 from '@imgs/cover/img3.webp'
|
||||
import cover4 from '@imgs/cover/img4.webp'
|
||||
|
||||
defineOptions({ name: 'ImageCards' })
|
||||
|
||||
// === 卡片演示数据 ← workplace ===
|
||||
const imageCards = [
|
||||
{
|
||||
id: 1,
|
||||
imageUrl: cover1,
|
||||
title: 'AI技术在医疗领域的创新应用与发展前景',
|
||||
category: '社交',
|
||||
readTime: '2分钟',
|
||||
views: 9125,
|
||||
comments: 3,
|
||||
date: '12月19日 周一'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
imageUrl: cover2,
|
||||
title: '大数据分析助力企业决策的实践案例',
|
||||
category: '技术',
|
||||
readTime: '3分钟',
|
||||
views: 7234,
|
||||
comments: 5,
|
||||
date: '12月20日 周二'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
imageUrl: cover3,
|
||||
title: '区块链技术在供应链管理中的应用',
|
||||
category: '科技',
|
||||
readTime: '4分钟',
|
||||
views: 5678,
|
||||
comments: 8,
|
||||
date: '12月21日 周三'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
imageUrl: cover4,
|
||||
title: '云计算技术发展趋势与未来展望',
|
||||
category: '云技术',
|
||||
readTime: '5分钟',
|
||||
views: 4321,
|
||||
comments: 6,
|
||||
date: '12月22日 周四'
|
||||
}
|
||||
]
|
||||
|
||||
/**
|
||||
* 图片卡片类型定义
|
||||
*/
|
||||
interface ImageCard {
|
||||
id: number
|
||||
imageUrl: string
|
||||
title: string
|
||||
category: string
|
||||
readTime: string
|
||||
views: number
|
||||
comments: number
|
||||
date: string
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理图片卡片点击事件
|
||||
* @param card 卡片数据
|
||||
*/
|
||||
const handleImageCardClick = (card: ImageCard) => {
|
||||
// TODO: 接入真实跳转
|
||||
console.log('点击卡片:', card)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<ElCarousel height="400px">
|
||||
<ElCarouselItem>
|
||||
<FaCardBanner
|
||||
title="系统运行正常"
|
||||
description="所有核心服务运行稳定,响应时间在正常范围内。"
|
||||
/>
|
||||
</ElCarouselItem>
|
||||
|
||||
<ElCarouselItem>
|
||||
<FaCardBanner
|
||||
:image="icon2"
|
||||
title="重要消息通知"
|
||||
description="您有 3 条待处理的重要消息,请及时查看。"
|
||||
:button="{
|
||||
show: true,
|
||||
text: '查看详情',
|
||||
color: 'var(--fa-warning)',
|
||||
textColor: '#fff'
|
||||
}"
|
||||
/>
|
||||
</ElCarouselItem>
|
||||
|
||||
<ElCarouselItem>
|
||||
<FaCardBanner
|
||||
:image="icon3"
|
||||
title="数据分析报告"
|
||||
description="本周业务数据分析报告已完成,请查看关键指标。"
|
||||
:button="{
|
||||
show: true,
|
||||
text: '下载报告',
|
||||
color: 'var(--fa-error)',
|
||||
textColor: '#fff'
|
||||
}"
|
||||
/>
|
||||
</ElCarouselItem>
|
||||
|
||||
<ElCarouselItem>
|
||||
<FaCardBanner
|
||||
:image="icon4"
|
||||
title="版本更新提醒"
|
||||
description="FastapiAdmin v3.1.0 已发布,包含优化和新功能。"
|
||||
:button="{
|
||||
show: true,
|
||||
text: '立即更新',
|
||||
color: 'var(--theme-color)',
|
||||
textColor: '#fff'
|
||||
}"
|
||||
:cancelButton="{
|
||||
show: true,
|
||||
text: '稍后提醒',
|
||||
color: '#eee',
|
||||
textColor: '#333'
|
||||
}"
|
||||
@click="handleConfirm"
|
||||
@cancel="handleCancel"
|
||||
/>
|
||||
</ElCarouselItem>
|
||||
</ElCarousel>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 非关键组件异步导入(延迟加载,提升首屏速度)
|
||||
import FaCardBanner from "@/components/banners/fa-card-banner/index.vue";
|
||||
import icon2 from '@imgs/3d/icon2.webp'
|
||||
import icon3 from '@imgs/3d/icon3.webp'
|
||||
import icon4 from '@imgs/3d/icon4.webp'
|
||||
|
||||
defineOptions({ name: 'ItBanners' })
|
||||
|
||||
/**
|
||||
* 处理确认按钮点击事件
|
||||
*/
|
||||
const handleConfirm = () => {
|
||||
// TODO: 接入真实操作
|
||||
console.log('confirm clicked')
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理取消按钮点击事件
|
||||
*/
|
||||
const handleCancel = () => {
|
||||
// TODO: 接入真实操作
|
||||
console.log('cancel clicked')
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="fa-card flex flex-col p-5 h-134 overflow-hidden">
|
||||
<div class="fa-card flex flex-col p-5 h-138 overflow-hidden">
|
||||
<div class="fa-card-header">
|
||||
<div class="title">
|
||||
<h4>新用户</h4>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="fa-card p-5 pb-3 h-54 max-sm:h-54 flex flex-col relative overflow-hidden">
|
||||
<div class="fa-card p-5 pb-3 h-55 max-sm:h-55 flex flex-col relative overflow-hidden">
|
||||
<div class="fa-card-header">
|
||||
<div class="title">
|
||||
<h4>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="fa-card p-5 h-134 overflow-hidden">
|
||||
<div class="fa-card p-5 h-138 overflow-hidden">
|
||||
<div class="fa-card-header">
|
||||
<div class="title">
|
||||
<h4>待办事项</h4>
|
||||
|
||||
@@ -190,7 +190,7 @@ const {
|
||||
label: "IP地址",
|
||||
minWidth: 150,
|
||||
formatter: (row: OnlineUserTable) =>
|
||||
h("span", { class: "inline-flex items-center flex-wrap gap-0.5" }, [
|
||||
h("span", { class: "inline-flex items-center gap-0.5 whitespace-nowrap" }, [
|
||||
row.ipaddr ?? "",
|
||||
row.ipaddr
|
||||
? h(FaCopyButton, {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
@reset="onResetSearch"
|
||||
/>
|
||||
|
||||
<ElSegmented v-model="menuClientTab" :options="menuSegmentedOptions" @change="handleMenuClientTabChange" />
|
||||
<ElSegmented class="mt-3" v-model="menuClientTab" :options="menuSegmentedOptions" @change="handleMenuClientTabChange" />
|
||||
|
||||
<ElCard
|
||||
class="fa-table-card"
|
||||
|
||||
Reference in New Issue
Block a user