refactor: 将组件前缀从Art统一替换为Fa

- 更新所有FA前缀的组件文件
- 新增Fa前缀的对应组件
- 更新所有引用路径和组件名
- 修改相关样式和变量名
- 调整部分组件目录结构
This commit is contained in:
zhangtao
2026-05-11 09:23:31 +08:00
parent 68b50359c5
commit 03a8151513
185 changed files with 2912 additions and 1283 deletions
@@ -1,5 +0,0 @@
/** 通用弹窗、抽屉(与业务 CRUD 解耦) */
export { default as ArtDialog } from "./art-dialog/index.vue";
export { default as ArtDrawer } from "./art-drawer/index.vue";
export { default as ArtImportDialog } from "./art-import-dialog/index.vue";
export { default as ArtExportDialog } from "./art-export-dialog/index.vue";
@@ -1 +0,0 @@
export { default as ArtWidgetDemoTitle } from "./ArtWidgetDemoTitle.vue";
@@ -1,7 +1,7 @@
<!-- 基础横幅组件 -->
<template>
<div
class="art-card basic-banner"
class="fa-card basic-banner"
:class="[{ 'has-decoration': decoration }, boxStyle]"
:style="{ height }"
@click="emit('click')"
@@ -72,7 +72,7 @@ import { useSettingsStore } from "@stores/modules/setting.store";
const settingStore = useSettingsStore();
const { isDark } = storeToRefs(settingStore);
defineOptions({ name: "ArtBasicBanner" });
defineOptions({ name: "FaBasicBanner" });
// 流星对象接口定义
interface Meteor {
@@ -1,6 +1,6 @@
<!-- 卡片横幅组件 -->
<template>
<div class="art-card-sm flex-c flex-col pb-6" :style="{ height: height }">
<div class="fa-card-sm flex-c flex-col pb-6" :style="{ height: height }">
<div class="flex-c flex-col gap-4 text-center">
<div class="w-45">
<img :src="image" :alt="title" class="w-full h-full object-contain" />
@@ -38,7 +38,7 @@
// 导入默认图标
import defaultIcon from "@imgs/3d/icon1.webp";
defineOptions({ name: "ArtCardBanner" });
defineOptions({ name: "FaCardBanner" });
// 定义卡片横幅组件的属性接口
interface CardBannerProps {
@@ -13,7 +13,7 @@
class="fixed right-10 bottom-15 size-9.5 flex-cc c-p border border-g-300 rounded-md tad-300 hover:bg-g-200"
@click="scrollToTop"
>
<ArtSvgIcon icon="ri:arrow-up-wide-line" class="text-g-500 text-lg" />
<FaSvgIcon icon="ri:arrow-up-wide-line" class="text-g-500 text-lg" />
</div>
</Transition>
</template>
@@ -21,7 +21,7 @@
<script setup lang="ts">
import { useCommon } from "@/hooks/core/useCommon";
defineOptions({ name: "ArtBackToTop" });
defineOptions({ name: "FaBackToTop" });
const { scrollToTop } = useCommon();
@@ -14,7 +14,7 @@
<script setup lang="ts">
import defaultLogoUrl from "@icons/vite.svg";
defineOptions({ name: "ArtLogo" });
defineOptions({ name: "FaLogo" });
interface Props {
/** logo 大小 */
@@ -1,12 +1,12 @@
<!-- 图标组件 -->
<template>
<Icon v-if="icon" :icon="icon" v-bind="bindAttrs" class="art-svg-icon inline" />
<Icon v-if="icon" :icon="icon" v-bind="bindAttrs" class="fa-svg-icon inline" />
</template>
<script setup lang="ts">
import { Icon } from "@iconify/vue";
defineOptions({ name: "ArtSvgIcon", inheritAttrs: false });
defineOptions({ name: "FaSvgIcon", inheritAttrs: false });
interface Props {
/** Iconify icon name */
@@ -50,48 +50,48 @@ const bindAttrs = computed<{ class: string; style: string }>(() => ({
</div> -->
<!-- Iconify 图标 -->
<!-- <div class="art-card-sm p-5">
<!-- <div class="fa-card-sm p-5">
<div class="text-lg font-semibold mb-4">Iconify</div>
<div class="flex items-center gap-6">
<ArtSvgIcon icon="ri:github-fill" class="text-2xl" />
<ArtSvgIcon icon="ri:copilot-line" class="text-2xl text-theme" />
<ArtSvgIcon icon="ri:edge-line" class="text-2xl text-secondary" />
<ArtSvgIcon icon="ri:planet-line" class="text-2xl text-warning" />
<ArtSvgIcon icon="ri:windows-line" class="text-2xl text-info" />
<ArtSvgIcon icon="ri:thumb-up-line" class="text-2xl text-danger" />
<ArtSvgIcon icon="ri:gift-2-line" class="text-2xl text-success" />
<ArtSvgIcon icon="ri:apple-line" class="text-2xl text-secondary" />
<FaSvgIcon icon="ri:github-fill" class="text-2xl" />
<FaSvgIcon icon="ri:copilot-line" class="text-2xl text-theme" />
<FaSvgIcon icon="ri:edge-line" class="text-2xl text-secondary" />
<FaSvgIcon icon="ri:planet-line" class="text-2xl text-warning" />
<FaSvgIcon icon="ri:windows-line" class="text-2xl text-info" />
<FaSvgIcon icon="ri:thumb-up-line" class="text-2xl text-danger" />
<FaSvgIcon icon="ri:gift-2-line" class="text-2xl text-success" />
<FaSvgIcon icon="ri:apple-line" class="text-2xl text-secondary" />
</div>
</div> -->
<!-- Svg Icons -->
<!-- <div class="art-card-sm p-5">
<!-- <div class="fa-card-sm p-5">
<div class="text-lg font-semibold mb-4">Svg Icons</div>
<div class="flex items-center gap-6">
<ArtSvgIcon icon="svg-spinners:3-dots-fade" class="text-2xl text-red-400" />
<ArtSvgIcon icon="svg-spinners:3-dots-bounce" class="text-2xl text-blue-400" />
<ArtSvgIcon icon="svg-spinners:3-dots-move" class="text-2xl text-orange-400" />
<ArtSvgIcon icon="svg-spinners:3-dots-rotate" class="text-2xl text-purple-400" />
<ArtSvgIcon icon="svg-spinners:blocks-shuffle-2" class="text-2xl text-pink-300" />
<ArtSvgIcon icon="svg-spinners:clock" class="text-2xl text-yellow-500" />
<ArtSvgIcon icon="svg-spinners:tadpole" class="text-2xl text-orange-500" />
<ArtSvgIcon icon="svg-spinners:blocks-wave" class="text-2xl text-blue-500" />
<FaSvgIcon icon="svg-spinners:3-dots-fade" class="text-2xl text-red-400" />
<FaSvgIcon icon="svg-spinners:3-dots-bounce" class="text-2xl text-blue-400" />
<FaSvgIcon icon="svg-spinners:3-dots-move" class="text-2xl text-orange-400" />
<FaSvgIcon icon="svg-spinners:3-dots-rotate" class="text-2xl text-purple-400" />
<FaSvgIcon icon="svg-spinners:blocks-shuffle-2" class="text-2xl text-pink-300" />
<FaSvgIcon icon="svg-spinners:clock" class="text-2xl text-yellow-500" />
<FaSvgIcon icon="svg-spinners:tadpole" class="text-2xl text-orange-500" />
<FaSvgIcon icon="svg-spinners:blocks-wave" class="text-2xl text-blue-500" />
</div>
</div> -->
<!-- Svg Icons -->
<!-- <div class="art-card-sm p-5">
<!-- <div class="fa-card-sm p-5">
<div class="text-lg font-semibold mb-4">Material Line Icons</div>
<div class="flex items-center gap-6">
<ArtSvgIcon icon="line-md:phone-call-twotone-loop" class="text-2xl text-blue-500" />
<FaSvgIcon icon="line-md:phone-call-twotone-loop" class="text-2xl text-blue-500" />
<ArtSvgIcon icon="line-md:switch-off" class="text-2xl text-green-500" />
<ArtSvgIcon icon="line-md:sun-rising-filled-loop" class="text-2xl text-yellow-400" />
<ArtSvgIcon icon="line-md:volume-high-filled" class="text-2xl text-purple-500" />
<ArtSvgIcon icon="line-md:github-twotone" class="text-2xl text-gray-700" />
<ArtSvgIcon icon="line-md:telegram" class="text-2xl text-sky-500" />
<ArtSvgIcon icon="line-md:reddit-loop" class="text-2xl text-orange-400" />
<ArtSvgIcon
<FaSvgIcon icon="line-md:switch-off" class="text-2xl text-green-500" />
<FaSvgIcon icon="line-md:sun-rising-filled-loop" class="text-2xl text-yellow-400" />
<FaSvgIcon icon="line-md:volume-high-filled" class="text-2xl text-purple-500" />
<FaSvgIcon icon="line-md:github-twotone" class="text-2xl text-gray-700" />
<FaSvgIcon icon="line-md:telegram" class="text-2xl text-sky-500" />
<FaSvgIcon icon="line-md:reddit-loop" class="text-2xl text-orange-400" />
<FaSvgIcon
icon="line-md:coffee-half-empty-filled-loop"
class="text-2xl text-emerald-500"
/>
@@ -99,31 +99,31 @@ const bindAttrs = computed<{ class: string; style: string }>(() => ({
</div> -->
<!-- 使用示例 -->
<!-- <div class="art-card-sm p-5">
<!-- <div class="fa-card-sm p-5">
<div class="text-lg font-semibold mb-4">使用示例</div>
<div class="space-y-4">
<div>
<div class="text-sm text-g-600 mb-2">基础使用</div>
<div class="bg-g-200 dark:bg-g-300/30 p-4 rounded font-mono text-sm text-g-800">
&lt;ArtSvgIcon icon="ri:home-line" /&gt;
&lt;FaSvgIcon icon="ri:home-line" /&gt;
</div>
</div>
<div>
<div class="text-sm text-g-600 mb-2">自定义大小</div>
<div class="bg-g-200 dark:bg-g-300/30 p-4 rounded font-mono text-sm text-g-800">
&lt;ArtSvgIcon icon="ri:user-line" class="text-2xl" /&gt;
&lt;FaSvgIcon icon="ri:user-line" class="text-2xl" /&gt;
</div>
</div>
<div>
<div class="text-sm text-g-600 mb-2">自定义颜色</div>
<div class="bg-g-200 dark:bg-g-300/30 p-4 rounded font-mono text-sm text-g-800">
&lt;ArtSvgIcon icon="ri:heart-fill" class="text-red-500" /&gt;
&lt;FaSvgIcon icon="ri:hefa-fill" class="text-red-500" /&gt;
</div>
</div>
<div>
<div class="text-sm text-g-600 mb-2">组合使用</div>
<div class="bg-g-200 dark:bg-g-300/30 p-4 rounded font-mono text-sm text-g-800">
&lt;ArtSvgIcon icon="ri:star-fill" class="text-4xl text-yellow-500" /&gt;
&lt;FaSvgIcon icon="ri:star-fill" class="text-4xl text-yellow-500" /&gt;
</div>
</div>
</div>
@@ -132,7 +132,7 @@ const bindAttrs = computed<{ class: string; style: string }>(() => ({
</template> -->
<!-- <script setup lang="ts">
import ArtSvgIcon from "@/components/Core/base/art-svg-icon/index.vue";
import FaSvgIcon from "@/components/base/fa-svg-icon/index.vue";
defineOptions({ name: "IconPage" });
</script> -->
@@ -1,6 +1,6 @@
<!-- 柱状图卡片 -->
<template>
<div class="art-card relative overflow-hidden" :style="{ height: `${height}rem` }">
<div class="fa-card relative overflow-hidden" :style="{ height: `${height}rem` }">
<div class="mb-5 flex-b items-start px-5 pt-5">
<div>
<p class="m-0 text-2xl font-medium leading-tight text-g-900">
@@ -31,7 +31,7 @@
import { useChartOps, useChartComponent } from "@/hooks/core/useChart";
import { type EChartsOption } from "@/plugins/echarts";
defineOptions({ name: "ArtBarChartCard" });
defineOptions({ name: "FaBarChartCard" });
interface Props {
/** 数值 */
@@ -0,0 +1,35 @@
<template>
<div v-loading="loading" class="min-h-0">
<ElEmpty
v-if="!loading && isEmpty"
:image-size="emptyImageSize"
:description="emptyDescription"
class="py-8"
/>
<div v-else class="min-h-0" :class="gridClass">
<slot />
</div>
</div>
</template>
<script setup lang="ts">
defineOptions({ name: "FaCardList" });
interface FaCardListProps {
loading?: boolean;
isEmpty?: boolean;
emptyDescription?: string;
emptyImageSize?: number;
/** Tailwind/Grid class string for layout */
gridClass?: string;
}
withDefaults(defineProps<FaCardListProps>(), {
loading: false,
isEmpty: false,
emptyDescription: "暂无数据",
emptyImageSize: 80,
gridClass:
"grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 auto-rows-max content-start",
});
</script>
@@ -1,6 +1,6 @@
<!-- 数据列表卡片 -->
<template>
<div class="art-card p-5">
<div class="fa-card p-5">
<div class="pb-3.5">
<p class="text-lg font-medium">{{ title }}</p>
<p class="text-sm text-g-600">{{ subtitle }}</p>
@@ -8,7 +8,7 @@
<ElScrollbar :style="{ height: maxHeight }">
<div v-for="(item, index) in list" :key="index" class="flex-c py-3">
<div v-if="item.icon" class="flex-cc mr-3 size-10 rounded-lg" :class="item.class">
<ArtSvgIcon :icon="item.icon" class="text-xl" />
<FaSvgIcon :icon="item.icon" class="text-xl" />
</div>
<div class="flex-1">
<div class="mb-1 text-sm">{{ item.title }}</div>
@@ -29,7 +29,7 @@
</template>
<script setup lang="ts">
defineOptions({ name: "ArtDataListCard" });
defineOptions({ name: "FaDataListCard" });
interface Props {
/** 数据列表 */
@@ -1,6 +1,6 @@
<!-- 环型图卡片 -->
<template>
<div class="art-card overflow-hidden" :style="{ height: `${height}rem` }">
<div class="fa-card overflow-hidden" :style="{ height: `${height}rem` }">
<div class="flex box-border h-full p-5 pr-2">
<div class="flex w-full items-start gap-5">
<div class="flex-b h-full flex-1 flex-col">
@@ -42,7 +42,7 @@
import { type EChartsOption } from "@/plugins/echarts";
import { useChartOps, useChartComponent } from "@/hooks/core/useChart";
defineOptions({ name: "ArtDonutChartCard" });
defineOptions({ name: "FaDonutChartCard" });
interface Props {
/** 数值 */
@@ -1,7 +1,7 @@
<!-- 图片卡片 -->
<template>
<div class="w-full c-p" @click="handleClick">
<div class="art-card overflow-hidden">
<div class="fa-card overflow-hidden">
<div class="relative w-full aspect-[16/10] overflow-hidden">
<ElImage
:src="props.imageUrl"
@@ -50,7 +50,7 @@
<script setup lang="ts">
import { Picture, View, ChatLineRound } from "@element-plus/icons-vue";
defineOptions({ name: "ArtImageCard" });
defineOptions({ name: "FaImageCard" });
interface Props {
/** 图片地址 */
@@ -1,6 +1,6 @@
<!-- 折线图卡片 -->
<template>
<div class="art-card relative overflow-hidden" :style="{ height: `${height}rem` }">
<div class="fa-card relative overflow-hidden" :style="{ height: `${height}rem` }">
<div class="mb-2.5 flex-b items-start p-5">
<div>
<p class="text-2xl font-medium leading-none">
@@ -35,7 +35,7 @@ import { graphic, type EChartsOption } from "@/plugins/echarts";
import { getCssVar, hexToRgba } from "@utils/ui";
import { useChartOps, useChartComponent } from "@/hooks/core/useChart";
defineOptions({ name: "ArtLineChartCard" });
defineOptions({ name: "FaLineChartCard" });
interface Props {
/** 数值 */
@@ -1,12 +1,12 @@
<!-- 进度条卡片 -->
<template>
<div class="art-card h-32 flex flex-col justify-center px-5">
<div class="fa-card h-32 flex flex-col justify-center px-5">
<div class="mb-3.5 flex-c" :style="{ justifyContent: icon ? 'space-between' : 'flex-start' }">
<div v-if="icon" class="size-11 flex-cc bg-g-300 text-xl rounded-lg" :class="iconStyle">
<ArtSvgIcon :icon="icon" class="text-2xl"></ArtSvgIcon>
<FaSvgIcon :icon="icon" class="text-2xl"></FaSvgIcon>
</div>
<div>
<ArtCountTo
<FaCountTo
class="mb-1 block text-2xl font-semibold"
:target="percentage"
:duration="2000"
@@ -27,7 +27,7 @@
</template>
<script setup lang="ts">
defineOptions({ name: "ArtProgressCard" });
defineOptions({ name: "FaProgressCard" });
interface Props {
/** 进度百分比 */
@@ -1,17 +1,17 @@
<!-- 统计卡片 -->
<template>
<div
class="art-card h-32 flex-c px-5 transition-transform duration-200 hover:-translate-y-0.5"
class="fa-card h-32 flex-c px-5 transition-transform duration-200 hover:-translate-y-0.5"
:class="boxStyle"
>
<div v-if="icon" class="mr-4 size-11 flex-cc rounded-lg text-xl text-white" :class="iconStyle">
<ArtSvgIcon :icon="icon"></ArtSvgIcon>
<FaSvgIcon :icon="icon"></FaSvgIcon>
</div>
<div class="flex-1">
<p class="m-0 text-lg font-medium" :style="{ color: textColor }" v-if="title">
{{ title }}
</p>
<ArtCountTo
<FaCountTo
class="m-0 text-2xl font-medium"
v-if="count !== undefined"
:target="count"
@@ -28,13 +28,13 @@
</p>
</div>
<div v-if="showArrow">
<ArtSvgIcon icon="ri:arrow-right-s-line" class="text-xl text-g-500" />
<FaSvgIcon icon="ri:arrow-right-s-line" class="text-xl text-g-500" />
</div>
</div>
</template>
<script setup lang="ts">
defineOptions({ name: "ArtStatsCard" });
defineOptions({ name: "FaStatsCard" });
interface StatsCardProps {
/** 盒子样式 */
@@ -1,6 +1,6 @@
<!-- 时间轴列表卡片 -->
<template>
<div class="art-card p-5">
<div class="fa-card p-5">
<div class="pb-3.5">
<p class="text-lg font-medium">{{ title }}</p>
<p class="text-sm text-g-600">{{ subtitle }}</p>
@@ -28,7 +28,7 @@
</template>
<script setup lang="ts">
defineOptions({ name: "ArtTimelineListCard" });
defineOptions({ name: "FaTimelineListCard" });
// 常量配置
const ITEM_HEIGHT = 65;
@@ -9,7 +9,7 @@ import { getCssVar } from "@utils/ui";
import { graphic, type EChartsOption } from "@/plugins/echarts";
import type { BarChartProps, BarDataItem } from "@/types/component/chart";
defineOptions({ name: "ArtBarChart" });
defineOptions({ name: "FaBarChart" });
const props = withDefaults(defineProps<BarChartProps>(), {
// 基础配置
@@ -8,7 +8,7 @@ import { useChartOps, useChartComponent } from "@/hooks/core/useChart";
import type { EChartsOption, BarSeriesOption } from "@/plugins/echarts";
import type { BidirectionalBarChartProps } from "@/types/component/chart";
defineOptions({ name: "ArtDualBarCompareChart" });
defineOptions({ name: "FaDualBarCompareChart" });
const props = withDefaults(defineProps<BidirectionalBarChartProps>(), {
// 基础配置
@@ -14,7 +14,7 @@ import { getCssVar } from "@utils/ui";
import { graphic, type EChartsOption } from "@/plugins/echarts";
import type { BarChartProps, BarDataItem } from "@/types/component/chart";
defineOptions({ name: "ArtHBarChart" });
defineOptions({ name: "FaHBarChart" });
const props = withDefaults(defineProps<BarChartProps>(), {
// 基础配置
@@ -13,7 +13,7 @@ import type { EChartsOption } from "@/plugins/echarts";
import { useChartOps, useChartComponent } from "@/hooks/core/useChart";
import type { KLineChartProps } from "@/types/component/chart";
defineOptions({ name: "ArtKLineChart" });
defineOptions({ name: "FaKLineChart" });
const props = withDefaults(defineProps<KLineChartProps>(), {
// 基础配置
@@ -14,7 +14,7 @@ import { getCssVar, hexToRgba } from "@utils/ui";
import { useChartOps, useChartComponent } from "@/hooks/core/useChart";
import type { LineChartProps, LineDataItem } from "@/types/component/chart";
defineOptions({ name: "ArtLineChart" });
defineOptions({ name: "FaLineChart" });
const props = withDefaults(defineProps<LineChartProps>(), {
// 基础配置
@@ -15,7 +15,7 @@ import { useSettingsStore } from "@stores/modules/setting.store";
import chinaMapJson from "@/mock/json/chinaMap.json";
import type { MapChartProps } from "@/types/component/chart";
defineOptions({ name: "ArtMapChart" });
defineOptions({ name: "FaMapChart" });
const chinaMapRef = ref<HTMLElement | null>(null);
const chartInstance = shallowRef<echarts.ECharts | null>(null);
@@ -13,7 +13,7 @@ import type { EChartsOption } from "@/plugins/echarts";
import { useChartOps, useChartComponent } from "@/hooks/core/useChart";
import type { RadarChartProps } from "@/types/component/chart";
defineOptions({ name: "ArtRadarChart" });
defineOptions({ name: "FaRadarChart" });
const props = withDefaults(defineProps<RadarChartProps>(), {
// 基础配置
@@ -13,7 +13,7 @@ import type { EChartsOption } from "@/plugins/echarts";
import { useChartOps, useChartComponent } from "@/hooks/core/useChart";
import type { RingChartProps } from "@/types/component/chart";
defineOptions({ name: "ArtRingChart" });
defineOptions({ name: "FaRingChart" });
const props = withDefaults(defineProps<RingChartProps>(), {
// 基础配置
@@ -14,7 +14,7 @@ import { getCssVar } from "@utils/ui";
import { useChartOps, useChartComponent } from "@/hooks/core/useChart";
import type { ScatterChartProps } from "@/types/component/chart";
defineOptions({ name: "ArtScatterChart" });
defineOptions({ name: "FaScatterChart" });
const props = withDefaults(defineProps<ScatterChartProps>(), {
// 基础配置
@@ -2,7 +2,7 @@
<template>
<div>
<ElDropdown v-if="hasAnyAuthItem">
<ArtIconButton icon="ri:more-2-fill" class="!size-8 bg-g-200 dark:bg-g-300/45 text-sm" />
<FaIconButton icon="ri:more-2-fill" class="!size-8 bg-g-200 dark:bg-g-300/45 text-sm" />
<template #dropdown>
<ElDropdownMenu>
<template v-for="item in list" :key="item.key">
@@ -12,7 +12,7 @@
@click="handleClick(item)"
>
<div class="flex-c gap-2" :style="{ color: item.color }">
<ArtSvgIcon v-if="item.icon" :icon="item.icon" />
<FaSvgIcon v-if="item.icon" :icon="item.icon" />
<span>{{ item.label }}</span>
</div>
</ElDropdownItem>
@@ -26,7 +26,7 @@
<script setup lang="ts">
import { useAuth } from "@/hooks/core/useAuth";
defineOptions({ name: "ArtButtonMore" });
defineOptions({ name: "FaButtonMore" });
const { hasAuth } = useAuth();
@@ -8,12 +8,12 @@
:style="{ backgroundColor: buttonBgColor, color: iconColor }"
@click="handleClick"
>
<ArtSvgIcon :icon="iconContent" />
<FaSvgIcon :icon="iconContent" />
</div>
</template>
<script setup lang="ts">
defineOptions({ name: "ArtButtonTable" });
defineOptions({ name: "FaButtonTable" });
interface Props {
/** 按钮类型 */
@@ -34,13 +34,13 @@
ref="handler"
:style="handlerStyle"
>
<ArtSvgIcon :icon="value ? successIcon : handlerIcon" class="text-g-600"></ArtSvgIcon>
<FaSvgIcon :icon="value ? successIcon : handlerIcon" class="text-g-600"></FaSvgIcon>
</div>
</div>
</template>
<script setup lang="ts">
defineOptions({ name: "ArtDragVerify" });
defineOptions({ name: "FaDragVerify" });
// 事件定义
const emit = defineEmits(["handlerMove", "update:value", "passCallback"]);
@@ -26,7 +26,7 @@ import { Loading } from "@element-plus/icons-vue";
import type { ButtonType } from "element-plus";
import { useThrottleFn } from "@vueuse/core";
defineOptions({ name: "ArtExcelExport" });
defineOptions({ name: "FaExcelExport" });
/** 导出数据类型 */
type ExportValue = string | number | boolean | null | undefined | Date;
@@ -390,11 +390,11 @@ defineExpose({
<!-- <template>
<div class="page-content">
<ArtExcelImport @import-success="handleImportSuccess" @import-error="handleImportError">
<FaExcelImport @import-success="handleImportSuccess" @import-error="handleImportError">
<template #import-text>上传 Excel</template>
</ArtExcelImport>
</FaExcelImport>
<ArtExcelExport
<FaExcelExport
style="margin-left: 10px"
:data="tableData"
filename="用户数据-1"
@@ -408,23 +408,23 @@ defineExpose({
@export-progress="handleProgress"
>
导出 Excel
</ArtExcelExport>
</FaExcelExport>
<ElButton type="danger" @click="handleClear" v-ripple>清除数据</ElButton>
<ArtTable :data="tableData" style="margin-top: 10px">
<FaTable :data="tableData" style="margin-top: 10px">
<ElTableColumn
v-for="key in Object.keys(headers)"
:key="key"
:prop="key"
:label="headers[key as keyof typeof headers]"
/>
</ArtTable>
</FaTable>
</div>
</template>
<script setup lang="ts">
defineOptions({ name: "WidgetsExcel" });
defineOptions({ name: "FaExcelExportDemo" });
/**
* 表格数据类型定义
@@ -18,7 +18,7 @@
import * as XLSX from "xlsx";
import type { UploadFile } from "element-plus";
defineOptions({ name: "ArtExcelImport" });
defineOptions({ name: "FaExcelImport" });
// Excel 导入工具函数
async function importExcel(file: File): Promise<Array<Record<string, unknown>>> {
@@ -63,11 +63,11 @@ const handleFileChange = async (uploadFile: UploadFile) => {
<!-- <template>
<div class="page-content">
<ArtExcelImport @import-success="handleImportSuccess" @import-error="handleImportError">
<FaExcelImport @import-success="handleImportSuccess" @import-error="handleImportError">
<template #import-text>上传 Excel</template>
</ArtExcelImport>
</FaExcelImport>
<ArtExcelExport
<FaExcelExport
style="margin-left: 10px"
:data="tableData"
filename="用户数据-1"
@@ -81,23 +81,23 @@ const handleFileChange = async (uploadFile: UploadFile) => {
@export-progress="handleProgress"
>
导出 Excel
</ArtExcelExport>
</FaExcelExport>
<ElButton type="danger" @click="handleClear" v-ripple>清除数据</ElButton>
<ArtTable :data="tableData" style="margin-top: 10px">
<FaTable :data="tableData" style="margin-top: 10px">
<ElTableColumn
v-for="key in Object.keys(headers)"
:key="key"
:prop="key"
:label="headers[key as keyof typeof headers]"
/>
</ArtTable>
</FaTable>
</div>
</template>
<script setup lang="ts">
defineOptions({ name: "WidgetsExcel" });
defineOptions({ name: "FaExcelImportDemo" });
/**
* 表格数据类型定义
@@ -120,7 +120,7 @@ import {
} from "element-plus";
import { calculateResponsiveSpan, type ResponsiveBreakpoint } from "@utils/form";
defineOptions({ name: "ArtForm" });
defineOptions({ name: "FaForm" });
const componentMap = {
input: ElInput, // 输入框
@@ -1,6 +1,6 @@
<!-- 在 ArtSearchBar 上追加「创建人 / 更新人 / 创建时间 / 更新时间」,并内置 UserTableSelect 插槽;业务页只传自己的 items 即可 -->
<!-- 在 FaSearchBar 上追加「创建人 / 更新人 / 创建时间 / 更新时间」,并内置 UserTableSelect 插槽;业务页只传自己的 items 即可 -->
<template>
<ArtSearchBar
<FaSearchBar
ref="innerRef"
v-model="modelValue"
v-bind="forwardedAttrs"
@@ -31,12 +31,12 @@
/>
</div>
</template>
</ArtSearchBar>
</FaSearchBar>
</template>
<script setup lang="ts">
import { computed, ref, useAttrs } from "vue";
import ArtSearchBar from "./index.vue";
import FaSearchBar from "./index.vue";
import type { SearchFormItem } from "./index.vue";
import {
getAuditSearchFormItems,
@@ -44,13 +44,13 @@ import {
} from "./auditSearchFormItems";
import UserTableSelect from "@views/module_system/user/components/UserTableSelect.vue";
defineOptions({ name: "ArtSearchBarWithAudit", inheritAttrs: false });
defineOptions({ name: "FaSearchBarWithAudit", inheritAttrs: false });
const props = withDefaults(
defineProps<{
/** 仅业务条件表单项,不含审计四字段 */
items: SearchFormItem[];
/** 为 false 时与原生 ArtSearchBar 一致,仅使用 `items` */
/** 为 false 时与原生 FaSearchBar 一致,仅使用 `items` */
includeAudit?: boolean;
/** 传给 getAuditSearchFormItems 的选项 */
auditItemOptions?: GetAuditSearchFormItemsOptions;
@@ -66,7 +66,7 @@ const emit = defineEmits<{
const modelValue = defineModel<Record<string, any>>({ default: () => ({}) });
const attrs = useAttrs();
const innerRef = ref<InstanceType<typeof ArtSearchBar> | null>(null);
const innerRef = ref<InstanceType<typeof FaSearchBar> | null>(null);
const forwardedAttrs = computed(() => attrs as Record<string, unknown>);
@@ -9,7 +9,7 @@ export type AuditSearchFormParams = {
};
export interface GetAuditSearchFormItemsOptions {
/** 栅格列宽,与 ArtSearchBar `span` 一致时建议传相同值,默认 6 */
/** 栅格列宽,与 FaSearchBar `span` 一致时建议传相同值,默认 6 */
span?: number;
createdByLabel?: string;
updatedByLabel?: string;
@@ -25,8 +25,8 @@ export interface GetAuditSearchFormItemsOptions {
}
/**
* 常见「创建人 / 更新人 / 创建时间 / 更新时间」搜索项,供 ArtSearchBar `items` 使用。
* 创建人、更新人需配合 `#created_id`、`#updated_id` 插槽(如 ArtSearchBarWithAudit)。
* 常见「创建人 / 更新人 / 创建时间 / 更新时间」搜索项,供 FaSearchBar `items` 使用。
* 创建人、更新人需配合 `#created_id`、`#updated_id` 插槽(如 FaSearchBarWithAudit)。
*/
export function getAuditSearchFormItems(
options?: GetAuditSearchFormItemsOptions
@@ -2,7 +2,7 @@
<!-- 支持常用表单组件、自定义组件、插槽、校验、隐藏表单项 -->
<!-- 写法同 ElementPlus 官方文档组件,把属性写在 props 里面就可以了 -->
<template>
<section class="art-search-bar art-card-xs" :class="{ 'is-expanded': isExpanded }">
<section class="fa-search-bar fa-card-xs" :class="{ 'is-expanded': isExpanded }">
<ElForm
ref="formRef"
:model="modelValue"
@@ -133,7 +133,7 @@ import {
} from "element-plus";
import { calculateResponsiveSpan, type ResponsiveBreakpoint } from "@utils/form";
defineOptions({ name: "ArtSearchBar" });
defineOptions({ name: "FaSearchBar" });
const componentMap = {
input: ElInput, // 输入框
@@ -512,7 +512,7 @@ const { span, gutter, labelPosition, labelWidth } = toRefs(props);
</script>
<style lang="scss" scoped>
.art-search-bar {
.fa-search-bar {
padding: 15px 20px 0;
.action-column {
@@ -563,7 +563,7 @@ const { span, gutter, labelPosition, labelWidth } = toRefs(props);
// 响应式优化
@media (width <= 768px) {
.art-search-bar {
.fa-search-bar {
padding: 16px 16px 0;
.action-column {
@@ -27,7 +27,7 @@ import { IDomEditor, IToolbarConfig, IEditorConfig } from "@wangeditor/editor";
import request from "@utils/http";
import type { AxiosResponse } from "axios";
defineOptions({ name: "ArtWangEditor" });
defineOptions({ name: "FaWangEditor" });
type InsertFnType = (url: string, alt: string, href: string) => void;
@@ -47,7 +47,7 @@
<script setup lang="ts">
import ImgCutter from "vue-img-cutter";
defineOptions({ name: "ArtCutterImg" });
defineOptions({ name: "FaCutterImg" });
interface CutterProps {
// 基础配置
@@ -268,7 +268,7 @@ function downloadImg() {
.preview-container {
.preview-box {
background-color: var(--art-active-color) !important;
background-color: var(--fa-active-color) !important;
.preview-img {
width: 100%;
@@ -7,7 +7,7 @@
import Player from "xgplayer";
import "xgplayer/dist/index.min.css";
defineOptions({ name: "ArtVideoPlayer" });
defineOptions({ name: "FaVideoPlayer" });
interface Props {
/** 播放器容器 ID */
@@ -113,7 +113,7 @@ onBeforeUnmount(() => {
<!-- <template>
<div class="page-content">
<div class="max-w-150">
<ArtVideoPlayer
<FaVideoPlayer
playerId="my-video-1"
:videoUrl="videoUrl"
:posterUrl="posterUrl"
@@ -128,7 +128,7 @@ onBeforeUnmount(() => {
<script setup lang="ts">
import lockImg from "@imgs/lock/bg_dark.webp";
defineOptions({ name: "WidgetsVideo" });
defineOptions({ name: "FaVideoPlayerDemo" });
/**
* 视频源 URL
@@ -50,7 +50,7 @@ import { Close, Fold, FullScreen } from "@element-plus/icons-vue";
import type { DialogProps } from "element-plus";
import { computed, ref, useAttrs, watch } from "vue";
defineOptions({ name: "ArtDialog", inheritAttrs: false });
defineOptions({ name: "FaDialog", inheritAttrs: false });
const props = withDefaults(
defineProps<{
@@ -34,7 +34,7 @@ import { Close } from "@element-plus/icons-vue";
import type { DrawerProps } from "element-plus";
import { computed, useAttrs } from "vue";
defineOptions({ name: "ArtDrawer", inheritAttrs: false });
defineOptions({ name: "FaDrawer", inheritAttrs: false });
const props = withDefaults(
defineProps<{
@@ -1,7 +1,7 @@
<template>
<div class="crud-export-modal-host">
<!-- 导出弹窗 -->
<ArtDialog
<FaDialog
v-model="exportsModalVisible"
title="导出数据"
width="600px"
@@ -59,19 +59,19 @@
<ElButton @click="handleCloseExportsModal">取 消</ElButton>
</div>
</template>
</ArtDialog>
</FaDialog>
</div>
</template>
<script lang="ts" setup>
import ArtDialog from "@/components/Core/modal/art-dialog/index.vue";
import FaDialog from "@/components/modal/fa-dialog/index.vue";
import ExcelJS from "exceljs";
import type { IContentConfig, IObject } from "@/components/Core/modal/types";
import type { IContentConfig, IObject } from "@/components/modal/types";
import { useThrottleFn } from "@vueuse/core";
import { type FormInstance, type FormRules, ElMessage } from "element-plus";
import { nextTick, ref, reactive, computed } from "vue";
defineOptions({ name: "ArtExportDialog", inheritAttrs: false });
defineOptions({ name: "FaExportDialog", inheritAttrs: false });
function saveBlobDownload(blob: Blob, rawName: string) {
const name = /\.xlsx?$/i.test(rawName) ? rawName : `${rawName}.xlsx`;
@@ -86,7 +86,7 @@ function saveBlobDownload(blob: Blob, rawName: string) {
/**
* 导出模态框组件属性定义
*/
interface ArtExportDialogProps {
interface FaExportDialogProps {
/** 内容配置 */
contentConfig: Pick<
IContentConfig,
@@ -101,7 +101,7 @@ interface ArtExportDialogProps {
}
// 定义接收的属性
const props = defineProps<ArtExportDialogProps>();
const props = defineProps<FaExportDialogProps>();
const remoteExportEnabled = computed(
() => !!(props.contentConfig.exportsAction || props.contentConfig.exportsBlobAction)
@@ -1,7 +1,7 @@
<template>
<div class="crud-import-modal-host">
<!-- 导入弹窗 -->
<ArtDialog
<FaDialog
v-model="importModalVisible"
:title="props.title"
:width="props.width"
@@ -70,23 +70,23 @@
</ElButton>
</div>
</template>
</ArtDialog>
</FaDialog>
</div>
</template>
<script lang="ts" setup>
import { Download, UploadFilled } from "@element-plus/icons-vue";
import ArtDialog from "@/components/Core/modal/art-dialog/index.vue";
import FaDialog from "@/components/modal/fa-dialog/index.vue";
import { ElMessage, type UploadUserFile } from "element-plus";
import { ref, reactive } from "vue";
import type { IContentConfig, IObject } from "@/components/Core/modal/types";
import type { IContentConfig, IObject } from "@/components/modal/types";
defineOptions({ name: "ArtImportDialog", inheritAttrs: false });
defineOptions({ name: "FaImportDialog", inheritAttrs: false });
/**
* 导入模态框组件属性定义
*/
interface ArtImportDialogProps {
interface FaImportDialogProps {
/**
* 弹窗标题
*/
@@ -179,7 +179,7 @@ interface ArtImportDialogProps {
}
// 定义props
const props = withDefaults(defineProps<ArtImportDialogProps>(), {
const props = withDefaults(defineProps<FaImportDialogProps>(), {
title: "导入数据",
width: "600px",
maxHeight: "60vh",
@@ -0,0 +1,5 @@
/** 通用弹窗、抽屉(与业务 CRUD 解耦) */
export { default as FaDialog } from "./fa-dialog/index.vue";
export { default as FaDrawer } from "./fa-drawer/index.vue";
export { default as FaImportDialog } from "./fa-import-dialog/index.vue";
export { default as FaExportDialog } from "./fa-export-dialog/index.vue";
@@ -121,36 +121,36 @@ export interface ISearchConfig {
/** 重置按钮权限 */
resetButtonPerm?: string | string[];
/**
* 搜索区形态:与「高级表格」示例一致用 `art`(ArtSearchBar + art-card-xs);
* 搜索区形态:与「高级表格」示例一致用 `art`(FaSearchBar + fa-card-xs);
* `grid` 等复杂布局仍走 `legacy`(或显式传 legacy)
*/
searchVariant?: "legacy" | "art";
/**
* ArtSearchBar `span`(不传则组件默认 6)。
* 若需与 legacy `showNumber` 折叠条数对齐,可自行传入 `computeArtSearchSpan(showNumber)` 的结果。
* FaSearchBar `span`(不传则组件默认 6)。
* 若需与 legacy `showNumber` 折叠条数对齐,可自行传入 `computeFaSearchSpan(showNumber)` 的结果。
*/
artSearchSpan?: number;
/** ArtSearchBar `showExpand`(不传则 `isExpandable !== false`,否则与组件默认 true 一致) */
/** FaSearchBar `showExpand`(不传则 `isExpandable !== false`,否则与组件默认 true 一致) */
artSearchShowExpand?: boolean;
/** ArtSearchBar 栅格 gutter(不传则用组件默认 12) */
/** FaSearchBar 栅格 gutter(不传则用组件默认 12) */
artSearchGutter?: number;
/** art 搜索区默认展开全部筛选项(对应 ArtSearchBar defaultExpanded) */
/** art 搜索区默认展开全部筛选项(对应 FaSearchBar defaultExpanded) */
searchDefaultExpanded?: boolean;
/**
* art 搜索区内控件最大宽度(不传则不限制,与 ArtSearchBar 示例一致)。
* art 搜索区内控件最大宽度(不传则不限制,与 FaSearchBar 示例一致)。
* 需要限制时再传,如 `"200px"`、`"min(100%, 280px)"`;`false` 显式铺满栅格列。
*/
artSearchFieldMaxWidth?: string | false;
/** 透传 ArtSearchBar → ElForm.rules */
/** 透传 FaSearchBar → ElForm.rules */
artSearchRules?: FormRules;
/** 透传 ArtSearchBar `sanitizeOutput`,控制搜索提交前清洗空值等行为 */
/** 透传 FaSearchBar `sanitizeOutput`,控制搜索提交前清洗空值等行为 */
artSearchSanitizeOutput?: IObject;
/** 透传 ArtSearchBar `buttonLeftLimit`(表单项数 ≤ 该值时操作按钮靠左,默认 2) */
/** 透传 FaSearchBar `buttonLeftLimit`(表单项数 ≤ 该值时操作按钮靠左,默认 2) */
artSearchButtonLeftLimit?: number;
/** 透传 ArtSearchBar `disabledSearch`,为 true 时禁用查询按钮 */
/** 透传 FaSearchBar `disabledSearch`,为 true 时禁用查询按钮 */
artSearchDisabledSearch?: boolean;
/**
* 透传 ArtSearchBar `isExpand`:为 true 时始终展示全部筛选项(不出现「展开更多」)。
* 透传 FaSearchBar `isExpand`:为 true 时始终展示全部筛选项(不出现「展开更多」)。
* 不传时:`isExpandable === false` 自动为 true(与 legacy 全展示一致);可折叠搜索时为 false。
*/
artSearchIsExpand?: boolean;
@@ -244,25 +244,25 @@ export interface IContentConfig<T = any> {
toolbar?: Array<ToolbarLeft | IToolsButton>;
/**
* 表格工具栏右侧图标(仅 **legacy** `el-table` 栈由 `CrudToolbarActions` 渲染)。
* **tableVariant: 'art'** 时刷新/列设置等由 `ArtTableHeader` 自带;导入导出请用 `#toolbar` 插槽自建。
* **tableVariant: 'art'** 时刷新/列设置等由 `FaTableHeader` 自带;导入导出请用 `#toolbar` 插槽自建。
*/
defaultToolbar?: Array<ToolbarRight | IToolsButton>;
/** 为 true 时隐藏 ArtTableHeader「列筛选」按钮(默认 false,显示列筛选) */
/** 为 true 时隐藏 FaTableHeader「列筛选」按钮(默认 false,显示列筛选) */
hideColumnFilter?: boolean;
/**
* 表格栈:`art` 时使用 ArtTableHeader + ArtTable;
* 表格栈:`art` 时使用 FaTableHeader + FaTable;
* `legacy` 为内置 el-table(默认)。
*/
tableVariant?: "legacy" | "art";
/** 内容区外层 el-card 额外 class(默认已含 `art-table-card`) */
/** 内容区外层 el-card 额外 class(默认已含 `fa-table-card`) */
cardClass?: string;
/** el-card 阴影(默认 never,与 Element Plus el-card shadow 一致) */
cardShadow?: "always" | "hover" | "never";
/** 是否显示表格上方工具条(默认 true;纯卡片/无按钮时可设为 false) */
showToolbar?: boolean;
/** ArtTableHeader 布局(不传则用内置默认) */
/** FaTableHeader 布局(不传则用内置默认) */
artToolbarLayout?: string;
/** 表格全屏区域 class,传给 ArtTableHeader fullClass */
/** 表格全屏区域 class,传给 FaTableHeader fullClass */
artFullScreenClass?: string;
/** 更多操作按钮配置 */
moreButtons?: Array<IToolsButton>;
@@ -338,7 +338,7 @@ export interface IContentConfig<T = any> {
/**
* CrudContent 左侧 `createToolbar` 产物,供 CrudToolbarLeft 的 `configButtons` 使用。
*/
export type ArtTableHeaderLeftConfigButton = {
export type FaTableHeaderLeftConfigButton = {
name: string;
text?: string;
attrs?: Record<string, unknown>;
@@ -357,7 +357,7 @@ export interface IModalConfig<T = any> {
pk?: string;
/** 组件类型(默认:dialog) */
component?: "dialog" | "drawer";
/** dialog组件属性(默认可拖拽;全屏由 core/overlays/ArtDialog 标题栏按钮切换) */
/** dialog组件属性(默认可拖拽;全屏由 core/overlays/FaDialog 标题栏按钮切换) */
dialog?: Partial<Omit<DialogProps, "modelValue">> & { draggable?: boolean };
/** drawer组件属性 */
drawer?: Partial<Omit<DrawerProps, "modelValue">>;
@@ -12,7 +12,7 @@
@contextmenu.prevent="fabCollapsed = true"
@click="handleOpen"
>
<ArtSvgIcon :icon="resolveIconForArtSvgIcon('ai')" class="ai-icon" />
<FaSvgIcon :icon="resolveIconForFaSvgIcon('ai')" class="ai-icon" />
</ElButton>
<!-- 收缩态:贴边小标签,避免遮挡表单控件 -->
@@ -36,7 +36,7 @@
>
<template #header>
<div class="dialog-header">
<ArtSvgIcon :icon="resolveIconForArtSvgIcon('ai')" class="header-icon" />
<FaSvgIcon :icon="resolveIconForFaSvgIcon('ai')" class="header-icon" />
<span class="title">AI 智能助手</span>
</div>
</template>
@@ -119,8 +119,10 @@
</template>
<script setup lang="ts">
import ArtSvgIcon from "@/components/Core/base/art-svg-icon/index.vue";
import { resolveIconForArtSvgIcon } from "@utils/menuIcon/remix";
defineOptions({ name: "FaAiAssistant" });
import FaSvgIcon from "@/components/base/fa-svg-icon/index.vue";
import { resolveIconForFaSvgIcon } from "@utils/menuIcon/remix";
import { nextTick, onBeforeUnmount, onMounted, watch, ref, computed } from "vue";
import { useRouter } from "vue-router";
import { ElMessage } from "element-plus";
@@ -77,7 +77,7 @@
<script setup lang="ts">
import { dayjs } from "element-plus";
defineOptions({ name: "HomeCalendar" });
defineOptions({ name: "FaCalendar" });
interface CalendarEvent {
date: string;
@@ -8,8 +8,10 @@
</template>
<script setup lang="ts">
import { useI18n } from "vue-i18n";
defineOptions({
name: "CopyButton",
name: "FaCopyButton",
inheritAttrs: false,
});
@@ -28,6 +28,9 @@
</svg>
</a>
</template>
<script setup lang="ts">
defineOptions({ name: "FaGithubCorner" });
</script>
<style scoped>
.github-corner:hover .octo-arm {
@@ -59,6 +59,7 @@
</template>
<script setup lang="ts">
defineOptions({ name: "FaGuide" });
import { computed, type PropType } from "vue";
import { useSettingsStore } from "@stores";
import { MenuTypeEnum } from "@/enums/appEnum";
@@ -11,10 +11,7 @@
<ElIcon v-if="elementIconComp">
<component :is="elementIconComp" />
</ElIcon>
<ArtSvgIcon
v-else-if="selectedIcon"
:icon="resolveIconForArtSvgIcon(selectedIcon)"
/>
<FaSvgIcon v-else-if="selectedIcon" :icon="resolveIconForFaSvgIcon(selectedIcon)" />
</template>
<template #suffix>
<!-- 清空按钮 -->
@@ -54,7 +51,7 @@
@click="selectIcon(icon)"
>
<ElTooltip :content="icon" placement="bottom" effect="light">
<ArtSvgIcon :icon="resolveIconForArtSvgIcon(icon)" />
<FaSvgIcon :icon="resolveIconForFaSvgIcon(icon)" />
</ElTooltip>
</li>
</ul>
@@ -83,11 +80,12 @@
</template>
<script setup lang="ts">
defineOptions({ name: "FaIconSelect" });
import * as ElementPlusIconsVue from "@element-plus/icons-vue";
import ArtSvgIcon from "@/components/Core/base/art-svg-icon/index.vue";
import FaSvgIcon from "@/components/base/fa-svg-icon/index.vue";
import { listLocalIconBasenames } from "@utils/icons";
import { isIconifyStoredIcon, resolveElementPlusIconComponent } from "@utils/menuIcon";
import { resolveIconForArtSvgIcon } from "@utils/menuIcon/remix";
import { resolveIconForFaSvgIcon } from "@utils/menuIcon/remix";
const props = defineProps({
modelValue: {
@@ -64,6 +64,8 @@
</template>
<script lang="ts" setup>
defineOptions({ name: "FaIntervalTab" });
// 定义接口,增强类型安全
interface CrontabValue {
second: string;
@@ -14,6 +14,8 @@
</template>
<script setup lang="ts">
defineOptions({ name: "FaJsonPretty" });
import { computed } from "vue";
import VueJsonPretty from "vue-json-pretty";
import "vue-json-pretty/lib/styles.css";
@@ -5,7 +5,7 @@
<div
v-show="visible"
:style="menuStyle"
class="context-menu art-card-xs !shadow-xl min-w-[var(--menu-width)] w-[var(--menu-width)]"
class="context-menu fa-card-xs !shadow-xl min-w-[var(--menu-width)] w-[var(--menu-width)]"
>
<ul class="menu-list m-0 list-none" :style="menuListStyle">
<template v-for="item in menuItems" :key="item.key">
@@ -17,7 +17,7 @@
:style="menuItemStyle"
@click="handleMenuClick(item)"
>
<ArtSvgIcon
<FaSvgIcon
v-if="item.icon"
class="mr-2 shrink-0 text-base text-g-800"
:icon="item.icon"
@@ -36,7 +36,7 @@
:style="menuItemStyle"
>
<div class="submenu-title flex-c w-full">
<ArtSvgIcon
<FaSvgIcon
v-if="item.icon"
class="mr-2 shrink-0 text-base text-g-800"
:icon="item.icon"
@@ -46,13 +46,13 @@
>
{{ item.label }}
</span>
<ArtSvgIcon
<FaSvgIcon
icon="ri:arrow-right-s-line"
class="ubmenu-arrow ml-auto mr-0 text-base text-g-500 transition-transform duration-150"
/>
</div>
<ul
class="submenu-list art-card-xs absolute left-full top-0 z-[2001] hidden w-max min-w-max list-none !shadow-xl"
class="submenu-list fa-card-xs absolute left-full top-0 z-[2001] hidden w-max min-w-max list-none !shadow-xl"
:style="submenuListStyle"
>
<li
@@ -63,7 +63,7 @@
:style="menuItemStyle"
@click="handleMenuClick(child)"
>
<ArtSvgIcon
<FaSvgIcon
v-if="child.icon"
class="r-2 shrink-0 text-base text-g-800 mr-1"
:icon="child.icon"
@@ -86,7 +86,7 @@
<script setup lang="ts">
import type { CSSProperties } from "vue";
defineOptions({ name: "ArtMenuRight" });
defineOptions({ name: "FaMenuRight" });
export interface MenuItemType {
/** 菜单项唯一标识 */
@@ -369,7 +369,7 @@ defineExpose({
left: 0;
height: 1px;
content: "";
background-color: var(--art-gray-300);
background-color: var(--fa-gray-300);
}
.menu-item.is-disabled {
@@ -382,7 +382,7 @@ defineExpose({
}
.menu-item.is-disabled i:not(.submenu-arrow),
.menu-item.is-disabled :deep(.art-svg-icon) {
.menu-item.is-disabled :deep(.fa-svg-icon) {
color: var(--el-text-color-disabled) !important;
}
@@ -11,7 +11,7 @@
<component :is="elementComponent" />
</ElIcon>
<ArtSvgIcon
<FaSvgIcon
v-else-if="isInvalidElementPrefix"
:icon="epFallback"
:color="color"
@@ -19,26 +19,20 @@
:style="mergedStyle"
/>
<ArtSvgIcon
v-else
:icon="resolvedArtIcon"
:color="color"
:class="iconClass"
:style="mergedStyle"
/>
<FaSvgIcon v-else :icon="resolvedFaIcon" :color="color" :class="iconClass" :style="mergedStyle" />
</template>
<script setup lang="ts">
import { computed } from "vue";
import ArtSvgIcon from "@/components/Core/base/art-svg-icon/index.vue";
import FaSvgIcon from "@/components/base/fa-svg-icon/index.vue";
import {
elementMenuIconToEpIconify,
isElementPlusStoredIcon,
resolveElementPlusIconComponent,
} from "@utils/menuIcon";
import { resolveIconForArtSvgIcon } from "@utils/menuIcon/remix";
import { resolveIconForFaSvgIcon } from "@utils/menuIcon/remix";
defineOptions({ name: "MenuRouteIcon", inheritAttrs: false });
defineOptions({ name: "FaMenuRouteIcon", inheritAttrs: false });
const props = defineProps<{
icon?: string;
@@ -60,7 +54,7 @@ const isInvalidElementPrefix = computed(
const epFallback = computed(() => elementMenuIconToEpIconify(trimmedIcon.value));
/** Iconify(含历史本地 SVG 文件名 → Remix `ri:`) */
const resolvedArtIcon = computed(() => resolveIconForArtSvgIcon(trimmedIcon.value));
const resolvedFaIcon = computed(() => resolveIconForFaSvgIcon(trimmedIcon.value));
const iconClass = computed(() =>
props.class === false || props.class == null ? undefined : props.class
@@ -101,11 +101,4 @@ function handleCurrentChange(val: number) {
</script>
<style lang="scss" scoped>
.pagination {
padding: 12px;
&.hidden {
display: none;
}
}
</style>
@@ -1,5 +1,5 @@
<template>
<component :is="tag" class="art-widget-demo-title">
<component :is="tag" class="fa-widget-demo-title">
<slot />
</component>
</template>
@@ -7,7 +7,7 @@
<script setup lang="ts">
/**
* Widget 演示页章节标题(与历史 `page-title` Tailwind 一致)。
* 业务页如需同款排版可直接复用;CRUD 列表页优先用 ArtSearchBar + 表格区标题即可。
* 业务页如需同款排版可直接复用;CRUD 列表页优先用 FaSearchBar + 表格区标题即可。
*/
withDefaults(
defineProps<{
@@ -21,7 +21,7 @@ withDefaults(
<style scoped>
@reference "@styles/core/tailwind.css";
.art-widget-demo-title {
.fa-widget-demo-title {
@apply my-5 text-xl font-medium first:mt-0;
}
</style>
@@ -1,12 +1,9 @@
<!-- 布局大小(触发器与顶栏 ArtIconButton 一致,避免与其它图标尺寸/悬停不一致) -->
<!-- 布局大小(触发器与顶栏 FaIconButton 一致,避免与其它图标尺寸/悬停不一致) -->
<template>
<ElTooltip :content="t('sizeSelect.tooltip')" effect="dark" placement="bottom">
<ElDropdown trigger="click" @command="handleSizeChange">
<span class="inline-flex outline-none leading-none">
<ArtIconButton
:icon="resolveIconForArtSvgIcon('size')"
class="size-select-btn text-[19px]"
/>
<FaIconButton :icon="resolveIconForFaSvgIcon('size')" class="size-select-btn text-[19px]" />
</span>
<template #dropdown>
<ElDropdownMenu>
@@ -25,10 +22,12 @@
</template>
<script setup lang="ts">
import ArtIconButton from "@/components/Core/widget/art-icon-button/index.vue";
defineOptions({ name: "FaSizeSelect" });
import FaIconButton from "@/components/widget/fa-icon-button/index.vue";
import { ComponentSize } from "@/enums/settings/layout.enum";
import { useAppStore } from "@stores/modules/app.store";
import { resolveIconForArtSvgIcon } from "@utils/menuIcon/remix";
import { resolveIconForFaSvgIcon } from "@utils/menuIcon/remix";
import { computed } from "vue";
const { t } = useI18n();
@@ -143,6 +143,13 @@
</template>
<script lang="ts" setup>
defineOptions({ name: "FaTableSelect" });
// 显式声明插槽类型(支持动态列插槽)
defineSlots<{
[slotName: string]: (props: Record<string, any>) => void;
}>();
import { ref, reactive, computed } from "vue";
import { useResizeObserver } from "@vueuse/core";
import type { FormInstance, PopoverProps, TableInstance } from "element-plus";
@@ -10,7 +10,7 @@
class="single-image-upload__crop-dialog"
@closed="onCropDialogClosed"
>
<ArtCutterImg
<FaCutterImg
v-if="cropVisible && cropSourceUrl"
:key="cropSourceUrl"
:img-url="cropSourceUrl"
@@ -76,10 +76,12 @@
</template>
<script setup lang="ts">
defineOptions({ name: "FaUpload" });
import { ref, watch } from "vue";
import { UploadRawFile, UploadRequestOptions, ElMessage, type UploadUserFile } from "element-plus";
import ParamsAPI from "@/api/module_system/params";
import ArtCutterImg from "@/components/Core/media/art-cutter-img/index.vue";
import FaCutterImg from "@/components/media/fa-cutter-img/index.vue";
import { dataURLToFile } from "@utils/file/dataUrl";
const props = defineProps({
@@ -26,7 +26,7 @@ import { ThemeMode } from "@/enums";
import { hexToRgba } from "@utils/ui";
import { useSettingsStore } from "@stores/modules/setting.store";
defineOptions({ name: "ArtWatermark" });
defineOptions({ name: "FaWatermark" });
interface WatermarkProps {
/** 水印内容 */
@@ -87,12 +87,12 @@
<script setup lang="ts">
import { ArrowDown, Delete, Download, Plus, Upload } from "@element-plus/icons-vue";
import { computed } from "vue";
import type { ArtTableHeaderLeftConfigButton } from "@/components/Core/modal/types";
import type { FaTableHeaderLeftConfigButton } from "@/components/modal/types";
const props = withDefaults(
defineProps<{
/** 与 CrudContent `toolbarLeftBtn` 一致时走配置驱动(与 handleToolbar 对齐) */
configButtons?: ArtTableHeaderLeftConfigButton[];
configButtons?: FaTableHeaderLeftConfigButton[];
/** 勾选行主键,用于禁用批删 / 更多(插槽完全自定义时可不传) */
removeIds?: Array<string | number>;
/** 新增按钮权限,不传则不显示(configButtons 未传时) */
@@ -1,6 +1,6 @@
<!-- 表格头部,包含表格大小、刷新、全屏、列设置、其他设置 -->
<template>
<div class="flex-cb max-md:!block" id="art-table-header">
<div class="flex-cb max-md:!block" id="fa-table-header">
<div class="flex-wrap">
<slot name="left"></slot>
</div>
@@ -17,7 +17,7 @@
@click="search"
:class="!showSearchBar ? 'active !bg-theme hover:!bg-theme/80' : ''"
>
<ArtSvgIcon icon="ri:search-line" :class="!showSearchBar ? 'text-white' : 'text-g-700'" />
<FaSvgIcon icon="ri:search-line" :class="!showSearchBar ? 'text-white' : 'text-g-700'" />
</div>
</ElTooltip>
@@ -28,7 +28,7 @@
@click="refresh"
:class="{ loading: loading && isManualRefresh }"
>
<ArtSvgIcon
<FaSvgIcon
icon="ri:refresh-line"
:class="loading && isManualRefresh ? 'animate-spin text-g-600' : ''"
/>
@@ -37,7 +37,7 @@
<!-- 表格大小 -->
<ElDropdown v-if="shouldShow('size')" @command="handleTableSizeChange">
<div class="button">
<ArtSvgIcon icon="ri:arrow-up-down-fill" />
<FaSvgIcon icon="ri:arrow-up-down-fill" />
</div>
<template #dropdown>
<ElDropdownMenu>
@@ -60,7 +60,7 @@
<!-- 全屏 -->
<div v-if="shouldShow('fullscreen')" class="button" @click="toggleFullScreen">
<ArtSvgIcon :icon="isFullScreen ? 'ri:fullscreen-exit-line' : 'ri:fullscreen-line'" />
<FaSvgIcon :icon="isFullScreen ? 'ri:fullscreen-exit-line' : 'ri:fullscreen-line'" />
</div>
<!-- 行拖拽排序 -->
@@ -74,7 +74,7 @@
@click="toggleRowDrag"
:class="isRowDrag ? 'active !bg-theme hover:!bg-theme/80' : ''"
>
<ArtSvgIcon icon="ri:drag-move-line" :class="isRowDrag ? 'text-white' : 'text-g-700'" />
<FaSvgIcon icon="ri:drag-move-line" :class="isRowDrag ? 'text-white' : 'text-g-700'" />
</div>
</ElTooltip>
@@ -82,7 +82,7 @@
<ElPopover v-if="shouldShow('columns')" placement="bottom" trigger="click">
<template #reference>
<div class="button">
<ArtSvgIcon icon="ri:align-right" />
<FaSvgIcon icon="ri:align-right" />
</div>
</template>
<div>
@@ -104,7 +104,7 @@
class="drag-icon mr-2 h-4.5 flex-cc text-g-500"
:class="item.fixed ? 'cursor-default text-g-300' : 'cursor-move'"
>
<ArtSvgIcon
<FaSvgIcon
:icon="item.fixed ? 'ri:unpin-line' : 'ri:drag-move-2-fill'"
class="text-base"
/>
@@ -126,7 +126,7 @@
<ElPopover v-if="shouldShow('settings')" placement="bottom" trigger="click">
<template #reference>
<div class="button">
<ArtSvgIcon icon="ri:settings-line" />
<FaSvgIcon icon="ri:settings-line" />
</div>
</template>
<div class="flex min-w-[200px] flex-col gap-2">
@@ -156,7 +156,14 @@ import { useI18n } from "vue-i18n";
import type { ColumnOption } from "@/types/component";
import { ElScrollbar } from "element-plus";
defineOptions({ name: "ArtTableHeader" });
defineOptions({ name: "FaTableHeader" });
// 显式声明插槽类型
defineSlots<{
default?: () => void;
left?: () => void;
right?: () => void;
}>();
const { t } = useI18n();
@@ -172,7 +179,7 @@ interface Props {
}
const props = withDefaults(defineProps<Props>(), {
fullClass: "art-page-view",
fullClass: "fa-page-view",
layout: "search,refresh,size,fullscreen,columns,rowDrag,settings",
showSearchBar: undefined,
});
@@ -1,24 +1,27 @@
<!-- 表格组件 -->
<!-- 支持:el-table 全部属性、事件、插槽,同官方文档写法 -->
<!-- 扩展功能:分页组件、渲染自定义列、loading、表格全局边框、斑马纹、表格尺寸、表头背景配置 -->
<!-- 获取 ref:默认暴露了 elTableRef 外部通过 ref.value.elTableRef 可以调用 el-table 方法 -->
<!--
FaTable:ElTable 透传 + 分页 + 列渲染约定。
- 属性 / 事件 / 插槽与 EP 文档一致;样式可由 tableStore 与 props 覆盖。
- 暴露 `elTableRef`、`scrollToTop`;formatter 列见 TableFormatterOutlet 注释。
-->
<template>
<div class="art-table" :class="{ 'is-empty': isEmpty }" :style="containerHeight">
<VueDraggable
target="tbody"
v-model="dragModel"
:animation="150"
:disabled="rowDragDisabled"
@end="onRowDragEnd"
>
<ElTable ref="elTableRef" v-loading="!!loading" v-bind="mergedTableProps">
<template v-for="col in columns" :key="col.prop || col.type">
<!-- 渲染全局序号列 -->
<ElTableColumn v-if="col.type === 'globalIndex'" v-bind="{ ...col }">
<template #default="{ $index }">
<span>{{ getGlobalIndex($index) }}</span>
</template>
</ElTableColumn>
<div class="fa-table">
<div class="fa-table__main">
<VueDraggable
class="fa-table__drag-wrap"
target="tbody"
v-model="dragModel"
:animation="150"
:disabled="rowDragDisabled"
@end="onRowDragEnd"
>
<ElTable ref="elTableRef" v-loading="!!loading" v-bind="mergedTableProps">
<template v-for="col in columns" :key="col.prop || col.type">
<!-- 渲染全局序号列 -->
<ElTableColumn v-if="col.type === 'globalIndex'" v-bind="{ ...col }">
<template #default="{ $index }">
<span>{{ getGlobalIndex($index) }}</span>
</template>
</ElTableColumn>
<!-- 渲染展开行 -->
<ElTableColumn v-else-if="col.type === 'expand'" v-bind="cleanColumnProps(col)">
@@ -73,7 +76,7 @@
:class="mergedPaginationOptions?.align"
ref="paginationRef"
>
<Pagination
<FaPagination
v-if="pagination"
:page="pagination.current"
:limit="pagination.size"
@@ -109,12 +112,14 @@ import { storeToRefs } from "pinia";
import { ColumnOption } from "@/types";
import { useTableStore } from "@stores/modules/table.store";
import { useCommon } from "@/hooks/core/useCommon";
import { useTableHeight } from "@/hooks/core/useTableHeight";
import { useResizeObserver, useWindowSize } from "@vueuse/core";
import Pagination from "@/components/Pagination/index.vue";
import { useWindowSize } from "@vueuse/core";
import FaPagination from "@/components/others/fa-pagination/index.vue";
import { VueDraggable } from "vue-draggable-plus";
defineOptions({ name: "ArtTable" });
/** 空状态插画高度(列表页统一常量) */
const ART_TABLE_EMPTY_IMAGE_SIZE = 120;
defineOptions({ name: "FaTable" });
const { width } = useWindowSize();
const elTableRef = ref<InstanceType<typeof ElTable> | null>(null);
@@ -152,8 +157,8 @@ interface PaginationOptions {
pagerCount?: number;
}
/** ArtTable 组件的 Props 接口 */
interface ArtTableProps extends TableProps<Record<string, any>> {
/** FaTable 组件的 Props 接口 */
interface FaTableProps extends TableProps<Record<string, any>> {
/** 加载状态 */
loading?: boolean;
/** 列渲染配置 */
@@ -166,13 +171,13 @@ interface ArtTableProps extends TableProps<Record<string, any>> {
emptyHeight?: string;
/** 空数据时显示的文本 */
emptyText?: string;
/** 是否开启 ArtTableHeader,解决表格高度自适应问题 */
/** 是否开启 FaTableHeader,解决表格高度自适应问题 */
showTableHeader?: boolean;
/** 为 true 时关闭行拖拽(忽略工具栏「行拖拽」开关) */
disableRowDrag?: boolean;
}
const props = withDefaults(defineProps<ArtTableProps>(), {
const props = withDefaults(defineProps<FaTableProps>(), {
columns: () => [],
fit: true,
showHeader: true,
@@ -311,7 +316,7 @@ const mergedTableProps = computed(() => ({
border: border.value,
size: size.value,
headerCellStyle: headerCellStyle.value,
// Element Plus 默认值为 true,未显式传入时不应被 ArtTable 覆盖成 false。
// Element Plus 默认值为 true,未显式传入时不应被 FaTable 覆盖成 false。
selectOnIndeterminate: hasExplicitTableProp("selectOnIndeterminate")
? props.selectOnIndeterminate
: undefined,
@@ -361,7 +366,7 @@ const shouldRenderSlotScope = (slotScope: { $index?: number }) => {
/**
* ElTableColumn 若存在 default 插槽且插槽产物含任意非 Comment 的 vnode(含空白文本节点),
* 将不会执行 formatter(见 element-plus render-helper setColumnRenders)。
* ArtTable 中 ElTableColumn 与子节点之间的换行/缩进可能被编译进默认插槽,导致 formatter(如操作列里的按钮)永远不渲染。
* FaTable 中 ElTableColumn 与子节点之间的换行/缩进可能被编译进默认插槽,导致 formatter(如操作列里的按钮)永远不渲染。
* 对声明了 formatter 且未使用 useSlot 的列,在此显式渲染 formatter 返回值。
*/
const renderColumnFormatter = (col: ColumnOption, row: Record<string, unknown>) => {
@@ -4,7 +4,7 @@
class="overflow-hidden transition-[height] duration-300 ease-in-out"
:style="{ height: showFestivalStrip ? '48px' : '0' }"
>
<ArtTextScroll
<FaTextScroll
v-if="showFestivalStrip"
class="!mb-3"
type="primary"
@@ -23,7 +23,7 @@ import { useSettingsStore } from "@stores/modules/setting.store";
import { useCeremony } from "@/hooks/core/useCeremony";
import { WEB_LINKS } from "@utils/constants";
defineOptions({ name: "ArtFestivalTextScroll" });
defineOptions({ name: "FaFestivalTextScroll" });
const settingStore = useSettingsStore();
const { showFestivalText } = storeToRefs(settingStore);
@@ -7,7 +7,7 @@
:style="containerStyle"
>
<div class="flex-cc absolute left-0 h-full w-9 z-10" :style="{ backgroundColor: bgColor }">
<ArtSvgIcon icon="ri:volume-down-line" class="text-lg" />
<FaSvgIcon icon="ri:volume-down-line" class="text-lg" />
</div>
<div
@@ -37,7 +37,7 @@
:style="{ backgroundColor: bgColor }"
@click="handleClose"
>
<ArtSvgIcon icon="ri:close-fill" class="text-lg" />
<FaSvgIcon icon="ri:close-fill" class="text-lg" />
</div>
</div>
</template>
@@ -155,7 +155,7 @@ const themeClasses = computed(() => {
// 背景色
const bgColor = computed(
() =>
`color-mix(in oklch, var(--color-${props.type}) ${isDark.value ? "25" : "10"}%, var(--art-color))`
`color-mix(in oklch, var(--color-${props.type}) ${isDark.value ? "25" : "10"}%, var(--fa-color))`
);
const containerStyle = computed(() => ({
@@ -286,42 +286,42 @@ onBeforeUnmount(() => {
<!-- <template>
<div class="page-content space-y-5">
<ArtTextScroll
<FaTextScroll
text="Art Design Pro 是一款兼具设计美学与高效开发的后台系统 <a target='_blank' href='https://www.artd.pro/docs/'>点击我 </a>访问官方文档"
showClose
/>
<ArtTextScroll type="success" text="这是一条成功类型的滚动公告" />
<FaTextScroll type="success" text="这是一条成功类型的滚动公告" />
<ArtTextScroll type="warning" text="这是一条警告类型的滚动公告" />
<FaTextScroll type="warning" text="这是一条警告类型的滚动公告" />
<ArtTextScroll type="danger" text="这是一条危险类型的滚动公告" />
<FaTextScroll type="danger" text="这是一条危险类型的滚动公告" />
<ArtTextScroll type="info" text="这是一条信息类型的滚动公告" />
<FaTextScroll type="info" text="这是一条信息类型的滚动公告" />
<ArtTextScroll text="这是一条可关闭的滚动公告" @close="handleClose" />
<FaTextScroll text="这是一条可关闭的滚动公告" @close="handleClose" />
<ArtTextScroll
<FaTextScroll
type="warning"
text="这是一条速度较慢、向右滚动的公告"
:speed="30"
direction="right"
/>
<ArtTextScroll
<FaTextScroll
text="这是一条文字溢出才会滚动的公告,当文本内容超出容器宽度时才会开始滚动显示,否则保持静止状态"
@close="handleClose"
:alwaysScroll="false"
/>
<ArtTextScroll type="danger" direction="up" :speed="30" text="这是一条向上滚动的公告" />
<FaTextScroll type="danger" direction="up" :speed="30" text="这是一条向上滚动的公告" />
<ArtTextScroll type="info" direction="down" :speed="30" text="这是一条向下滚动的公告" />
<FaTextScroll type="info" direction="down" :speed="30" text="这是一条向下滚动的公告" />
</div>
</template>
<script setup lang="ts">
defineOptions({ name: "WidgetsTextScroll" });
defineOptions({ name: "FaTextScroll" });
const handleClose = () => {
@@ -1,7 +1,7 @@
<template>
<div class="page-content !border-0 !bg-transparent min-h-screen flex-cc">
<div class="flex-cc max-md:!block max-md:text-center">
<ThemeSvg :src="data.imgUrl" size="100%" class="!w-100" />
<FaThemeSvg :src="data.imgUrl" size="100%" class="!w-100" />
<div class="ml-15 w-75 max-md:mx-auto max-md:mt-10 max-md:w-full max-md:text-center">
<p class="text-xl leading-7 text-g-600 max-md:text-lg">{{ data.desc }}</p>
<ElButton type="primary" size="large" @click="backHome" v-ripple class="mt-5">
@@ -15,6 +15,7 @@
<script setup lang="ts">
import { useCommon } from "@/hooks/core/useCommon";
import { useUserStore } from "@stores/modules/user.store";
import FaThemeSvg from "@/components/theme/fa-theme-svg/index.vue";
const router = useRouter();
const userStore = useUserStore();
@@ -4,7 +4,7 @@
class="auth-top-bar pointer-events-none fixed left-0 right-0 top-0 z-[100] flex items-center justify-between gap-3 bg-transparent px-5 py-[1.125rem] md:gap-4 md:px-10"
>
<div class="pointer-events-auto flex min-w-0 flex-1 items-center gap-3">
<ArtLogo class="icon shrink-0" size="46" :src="webLogoSrc" />
<FaLogo class="icon shrink-0" size="46" :src="webLogoSrc" />
<div class="min-w-0 flex-1">
<div class="flex flex-wrap items-center gap-2">
<h1 class="auth-top-bar__site-title">{{ siteTitle }}</h1>
@@ -30,17 +30,13 @@
:style="{ background: _color, '--index': index }"
@click="changeThemeColor(_color)"
>
<ArtSvgIcon
v-if="_color === systemThemeColor"
icon="ri:check-fill"
class="text-white"
/>
<FaSvgIcon v-if="_color === systemThemeColor" icon="ri:check-fill" class="text-white" />
</div>
</div>
<div
class="btn palette-btn auth-top-bar__action relative z-[2] h-8 w-8 c-p flex-cc tad-300"
>
<ArtSvgIcon icon="ri:palette-line" class="text-xl transition-colors duration-300" />
<FaSvgIcon icon="ri:palette-line" class="text-xl transition-colors duration-300" />
</div>
</div>
<ElDropdown
@@ -52,7 +48,7 @@
class="btn layout-align-btn auth-top-bar__action h-8 w-8 c-p flex-cc tad-300"
:title="$t('login.panelAlign.label')"
>
<ArtSvgIcon
<FaSvgIcon
:icon="panelAlignTriggerIcon"
class="text-xl text-g-800 transition-colors duration-300"
/>
@@ -64,13 +60,9 @@
:command="opt.value"
:class="{ 'is-selected': panelAlign === opt.value }"
>
<ArtSvgIcon :icon="opt.icon" class="mr-2 text-base" />
<FaSvgIcon :icon="opt.icon" class="mr-2 text-base" />
<span class="menu-txt">{{ $t(opt.labelKey) }}</span>
<ArtSvgIcon
icon="ri:check-fill"
class="text-base"
v-if="panelAlign === opt.value"
/>
<FaSvgIcon icon="ri:check-fill" class="text-base" v-if="panelAlign === opt.value" />
</ElDropdownItem>
</div>
</ElDropdownMenu>
@@ -82,7 +74,7 @@
popper-class="langDropDownStyle"
>
<div class="btn language-btn auth-top-bar__action h-8 w-8 c-p flex-cc tad-300">
<ArtSvgIcon
<FaSvgIcon
icon="ri:translate-2"
class="text-[19px] text-g-800 transition-colors duration-300"
/>
@@ -95,7 +87,7 @@
:class="{ 'is-selected': locale === lang.value }"
>
<span class="menu-txt">{{ lang.label }}</span>
<ArtSvgIcon icon="ri:check-fill" class="text-base" v-if="locale === lang.value" />
<FaSvgIcon icon="ri:check-fill" class="text-base" v-if="locale === lang.value" />
</ElDropdownItem>
</div>
</ElDropdownMenu>
@@ -106,7 +98,7 @@
class="btn theme-btn auth-top-bar__action h-8 w-8 c-p flex-cc tad-300"
@click="themeAnimation"
>
<ArtSvgIcon
<FaSvgIcon
:icon="isDark ? 'ri:sun-fill' : 'ri:moon-line'"
class="text-xl text-g-800 transition-colors duration-300"
/>
@@ -260,7 +252,7 @@ const changeThemeColor = (color: string) => {
transform: translateY(-2px);
}
.auth-top-bar__action:hover :deep(.art-svg-icon) {
.auth-top-bar__action:hover :deep(.fa-svg-icon) {
color: var(--el-color-primary);
}
@@ -277,7 +269,7 @@ const changeThemeColor = (color: string) => {
.color-dots {
pointer-events: none;
box-shadow: 0 2px 12px var(--art-gray-300);
box-shadow: 0 2px 12px var(--fa-gray-300);
backdrop-filter: blur(10px);
transform: translateX(10px);
transition:
@@ -313,20 +305,20 @@ const changeThemeColor = (color: string) => {
}
.dark .color-dots {
background-color: var(--art-gray-200);
background-color: var(--fa-gray-200);
box-shadow: none;
}
/* 调色盘:图标颜色与当前主题主色一致(含单独悬浮、整块调色区悬浮) */
.palette-btn :deep(.art-svg-icon) {
.palette-btn :deep(.fa-svg-icon) {
color: v-bind("themeColorForCss");
}
.auth-top-bar__action.palette-btn:hover :deep(.art-svg-icon) {
.auth-top-bar__action.palette-btn:hover :deep(.fa-svg-icon) {
color: v-bind("themeColorForCss");
}
.color-picker-expandable:hover .palette-btn :deep(.art-svg-icon) {
.color-picker-expandable:hover .palette-btn :deep(.fa-svg-icon) {
color: v-bind("themeColorForCss");
}
</style>
@@ -7,13 +7,14 @@
>
<div class="login-center-backdrop__bg" />
<div class="login-center-backdrop__hero-wrap">
<ThemeSvg :src="loginIcon" size="100%" class="login-center-backdrop__hero" />
<FaThemeSvg :src="loginIcon" size="100%" class="login-center-backdrop__hero" />
</div>
</div>
</template>
<script setup lang="ts">
import loginIcon from "@imgs/svg/login_icon.svg";
import FaThemeSvg from "@/components/theme/fa-theme-svg/index.vue";
defineOptions({ name: "LoginCenterBackdrop" });
@@ -2,7 +2,7 @@
<template>
<div class="login-left-view">
<div v-if="!hideTopBranding" class="logo">
<ArtLogo class="icon" size="46" :src="webLogoSrc" />
<FaLogo class="icon" size="46" :src="webLogoSrc" />
<div class="logo-title-wrap">
<div class="logo-title-inline">
<h1 class="title">{{ siteTitle }}</h1>
@@ -14,7 +14,7 @@
</div>
<div class="left-img">
<ThemeSvg :src="loginIcon" size="100%" />
<FaThemeSvg :src="loginIcon" size="100%" />
</div>
<div class="text-wrap">
@@ -82,6 +82,7 @@ import AppConfig from "@/config";
import loginIcon from "@imgs/svg/login_icon.svg";
import { useConfigStore } from "@stores/modules/config.store";
import { themeAnimation } from "@utils/ui";
import FaThemeSvg from "@/components/theme/fa-theme-svg/index.vue";
defineProps<{
hideContent?: boolean;
@@ -91,7 +92,7 @@ defineProps<{
const configStore = useConfigStore();
/** 接口 sys_web_logo,空则 ArtLogo 内置默认图 */
/** 接口 sys_web_logo,空则 FaLogo 内置默认图 */
const webLogoSrc = computed(
() => configStore.configData.sys_web_logo?.config_value?.trim() || undefined
);
@@ -206,13 +207,13 @@ $bg-mix-light-7: color-mix(in srgb, $primary-light-7 80%, $main-bg);
h1 {
font-size: 24px;
font-weight: 400;
color: var(--art-gray-900) !important;
color: var(--fa-gray-900) !important;
}
p {
margin-top: 10px;
font-size: 14px;
color: var(--art-gray-600) !important;
color: var(--fa-gray-600) !important;
}
}
@@ -1,6 +1,6 @@
<template>
<div class="page-content box-border !px-20 py-3.5 text-center max-md:!px-5" :class="type">
<ArtSvgIcon
<FaSvgIcon
class="icon size-22 p-2 mt-16 block rounded-full !text-white"
:icon="iconCode"
:class="type === 'success' ? 'bg-[#19BE6B]' : 'bg-[#ED4014]'"
@@ -21,7 +21,14 @@
</template>
<script setup lang="ts">
defineOptions({ name: "ArtResultPage" });
defineOptions({ name: "FaResultPage" });
// 显式声明插槽类型
defineSlots<{
default?: () => void;
content?: () => void;
buttons?: () => void;
}>();
interface ResultPageProps {
/** 成功/失败 */
@@ -4,13 +4,13 @@
class="size-8.5 inline-flex flex-cc c-p text-g-600 dark:text-g-800 text-xl rounded tad-300 hover:bg-hover-color"
:class="{ 'rounded-full': circle }"
>
<ArtSvgIcon :icon="icon"></ArtSvgIcon>
<FaSvgIcon :icon="icon"></FaSvgIcon>
<slot></slot>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: "ArtIconButton" });
defineOptions({ name: "FaIconButton" });
interface Props {
/** 图标名称 */