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
+2 -2
View File
@@ -16,7 +16,7 @@
<RouterView></RouterView>
<!-- AI 助手 -->
<AiAssistant v-if="enableAiAssistant" />
<FaAiAssistant v-if="enableAiAssistant" />
</ElWatermark>
</ElConfigProvider>
</template>
@@ -27,7 +27,7 @@ import { useAppStore, useUserStore } from "./store";
import { useSettingsStore } from "./store/modules/setting.store";
import { defaultSettings } from "./config/setting";
import { ComponentSize } from "./enums/settings/layout.enum";
import AiAssistant from "./components/AiAssistant/index.vue";
import FaAiAssistant from "./components/others/fa-ai-assistant/index.vue";
import { hexToRgba, toggleTransition } from "./utils/ui";
import { checkStorageCompatibility } from "./utils/storage";
import { initializeTheme } from "./hooks/core/useTheme";
@@ -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 方法 -->
<!--
FaTableElTable 透传 + 分页 + 列渲染约定
- 属性 / 事件 / 插槽与 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 {
/** 图标名称 */
+2 -2
View File
@@ -88,7 +88,7 @@ const appConfig: SystemConfig = {
{
theme: MenuThemeEnum.DESIGN,
background: "#FFFFFF",
systemNameColor: "var(--art-gray-800)",
systemNameColor: "var(--fa-gray-800)",
iconColor: "#6B6B6B",
textColor: "#29343D",
img: configImages.menuStyles.design,
@@ -104,7 +104,7 @@ const appConfig: SystemConfig = {
{
theme: MenuThemeEnum.LIGHT,
background: "#ffffff",
systemNameColor: "var(--art-gray-800)",
systemNameColor: "var(--fa-gray-800)",
iconColor: "#6B6B6B",
textColor: "#29343D",
img: configImages.menuStyles.light,
+6 -8
View File
@@ -24,39 +24,37 @@ export const globalComponentsConfig: GlobalComponentConfig[] = [
{
name: "设置面板",
key: "settings-panel",
component: defineAsyncComponent(() => import("@/layouts/art-settings-panel/index.vue")),
component: defineAsyncComponent(() => import("@/layouts/fa-settings-panel/index.vue")),
enabled: true,
},
{
name: "全局搜索",
key: "global-search",
component: defineAsyncComponent(() => import("@/layouts/art-global-search/index.vue")),
component: defineAsyncComponent(() => import("@/layouts/fa-global-search/index.vue")),
enabled: true,
},
{
name: "锁屏",
key: "screen-lock",
component: defineAsyncComponent(() => import("@/layouts/art-screen-lock/index.vue")),
component: defineAsyncComponent(() => import("@/layouts/fa-screen-lock/index.vue")),
enabled: true,
},
{
name: "聊天窗口",
key: "chat-window",
component: defineAsyncComponent(() => import("@/layouts/art-chat-window/index.vue")),
component: defineAsyncComponent(() => import("@/layouts/fa-chat-window/index.vue")),
enabled: true,
},
{
name: "礼花效果",
key: "fireworks-effect",
component: defineAsyncComponent(() => import("@/layouts/art-fireworks-effect/index.vue")),
component: defineAsyncComponent(() => import("@/layouts/fa-fireworks-effect/index.vue")),
enabled: true,
},
{
name: "水印效果",
key: "watermark",
component: defineAsyncComponent(
() => import("@/components/Core/others/art-watermark/index.vue")
),
component: defineAsyncComponent(() => import("@/components/others/fa-watermark/index.vue")),
enabled: true,
},
];
+1 -1
View File
@@ -13,7 +13,7 @@ const fastEnterConfig: FastEnterConfig = {
{
name: "工作台",
description: "系统概览与数据统计",
icon: "ri:pie-chart-line",
icon: "ri:pie-chfa-line",
iconColor: "#377dff",
enabled: true,
order: 1,
+1 -1
View File
@@ -22,7 +22,7 @@
* - `image` 为红包碎屑 hb、雪花 sd、礼花筒 yd 等时,须在下方 import,勿手写路径字符串。
* - 全局快捷键:**Ctrl + Shift + P**Windows / Linux)或 **⌘ + Shift + P**macOS)立即触发一发礼花;
* 若当天命中某条「带礼花」的节日配置则使用该配置的 `image`,否则为几何礼花。
* - 实现:`src/layouts/art-fireworks-effect/index.vue`(键盘)、`src/hooks/core/useCeremony.ts`(自动连发)。
* - 实现:`src/layouts/fa-fireworks-effect/index.vue`(键盘)、`src/hooks/core/useCeremony.ts`(自动连发)。
*
* ## 自动公历节日
*
+1 -1
View File
@@ -14,7 +14,7 @@
* ## 注意事项
*
* 1. 修改此文件的配置项时,需要同步更新以下文件:
* - src/layouts/art-settings-panel/widget/SettingActions.vue(复制配置和重置配置逻辑)
* - src/layouts/fa-settings-panel/widget/SettingActions.vue(复制配置和重置配置逻辑)
* - src/store/modules/setting.tsStore 状态定义)
* 2. 可以通过设置面板的"复制配置"按钮快速生成配置代码
* 3. 枚举类型的值需要与 src/enums/appEnum.ts 中的定义保持一致
+1 -1
View File
@@ -54,7 +54,7 @@ export const useAuth = () => {
: [];
/**
* 检查是否拥有某权限标识(与 v-hasPerm / 表格内 ArtButtonMore 全码一致)
* 检查是否拥有某权限标识(与 v-hasPerm / 表格内 FaButtonMore 全码一致)
* @param auth 权限标识(多为后端菜单 permission 全码,如 module_system:role:update
*/
const hasAuth = (auth: string): boolean => {
+1 -1
View File
@@ -14,7 +14,7 @@
*
* ## 手动礼花快捷键
*
* 全局 **Ctrl+Shift+P** / **⌘+Shift+P** 由 `art-fireworks-effect` 监听;礼花图与当天节日配置一致,
* 全局 **Ctrl+Shift+P** / **⌘+Shift+P** 由 `fa-fireworks-effect` 监听;礼花图与当天节日配置一致,
* 详见 `src/config/modules/festival.ts` 文件头说明。
*
* ## 使用示例
+1 -4
View File
@@ -29,10 +29,7 @@ export function useCommon() {
*/
const homePath = computed(() => menuStore.getHomePath());
/**
* 刷新当前页面
* 通过切换 setting store 中的 refresh 状态触发页面重新渲染
*/
/** 触发 `FaPageContent` 级重建(与布局 settings 联动) */
const refresh = () => {
settingStore.reload();
};
+1 -1
View File
@@ -82,7 +82,7 @@ export function useHeaderBar() {
return isFeatureEnabled("breadcrumb") && showCrumbs.value;
});
// 全局搜索:新版 ArtGlobalSearch 体验更好,显示条件 = 配置开启 ∧ 旧版「菜单搜索」开关
// 全局搜索:新版 FaGlobalSearch 体验更好,显示条件 = 配置开启 ∧ 旧版「菜单搜索」开关
const shouldShowGlobalSearch = computed(() => {
return isFeatureEnabled("globalSearch") && showMenuSearch.value;
});
@@ -27,12 +27,12 @@ interface LayoutHeightOptions {
extraSpacing?: number;
/** 是否自动更新 CSS 变量(默认 true) */
updateCssVar?: boolean;
/** CSS 变量名称(默认 '--art-full-height' */
/** CSS 变量名称(默认 '--fa-full-height' */
cssVarName?: string;
}
export function useLayoutHeight(options: LayoutHeightOptions = {}) {
const { extraSpacing = 15, updateCssVar = true, cssVarName = "--art-full-height" } = options;
const { extraSpacing = 15, updateCssVar = true, cssVarName = "--fa-full-height" } = options;
// 元素引用
const headerRef = ref<HTMLElement>();
@@ -87,7 +87,7 @@ export function useAutoLayoutHeight(
headerIds: string[] = ["app-header", "app-content-header"],
options: LayoutHeightOptions = {}
) {
const { extraSpacing = 15, updateCssVar = true, cssVarName = "--art-full-height" } = options;
const { extraSpacing = 15, updateCssVar = true, cssVarName = "--fa-full-height" } = options;
// 创建元素引用
const headerRef = ref<HTMLElement>();
@@ -39,7 +39,7 @@ import { useRouter, useRoute } from "vue-router";
import type { RouteLocationMatched, RouteRecordRaw } from "vue-router";
import { formatMenuTitle } from "@utils/navigation";
defineOptions({ name: "ArtBreadcrumb" });
defineOptions({ name: "FaBreadcrumb" });
export interface BreadcrumbItem {
path: string;
@@ -78,8 +78,8 @@
</ElInput>
<div class="mt-3 flex-cb">
<div class="flex-c">
<ArtSvgIcon icon="ri:image-line" class="mr-5 c-p text-g-600 text-lg" />
<ArtSvgIcon icon="ri:emotion-happy-line" class="mr-5 c-p text-g-600 text-lg" />
<FaSvgIcon icon="ri:image-line" class="mr-5 c-p text-g-600 text-lg" />
<FaSvgIcon icon="ri:emotion-happy-line" class="mr-5 c-p text-g-600 text-lg" />
</div>
<ElButton type="primary" @click="sendMessage" v-ripple class="min-w-20">发送</ElButton>
</div>
@@ -95,7 +95,7 @@ import { mittBus } from "@utils/sys";
import meAvatar from "@imgs/avatar/avatar5.webp";
import aiAvatar from "@imgs/avatar/avatar10.webp";
defineOptions({ name: "ArtChatWindow" });
defineOptions({ name: "FaChatWindow" });
//
interface ChatMessage {
@@ -30,7 +30,7 @@
@click="handleApplicationClick(application)"
>
<div class="app-icon size-12 flex-cc rounded-lg bg-g-200/80 dark:bg-g-300/30">
<ArtSvgIcon
<FaSvgIcon
class="text-xl"
:icon="application.icon"
:style="{ color: application.iconColor }"
@@ -65,7 +65,7 @@
import { useFastEnter } from "@/hooks/core/useFastEnter";
import type { FastEnterApplication, FastEnterQuickLink } from "@/types/config";
defineOptions({ name: "ArtFastEnter" });
defineOptions({ name: "FaFastEnter" });
const router = useRouter();
const popoverRef = ref();
@@ -17,7 +17,7 @@ import bp from "@imgs/ceremony/hb.png";
import sd from "@imgs/ceremony/sd.png";
import yd from "@imgs/ceremony/yd.png";
defineOptions({ name: "ArtFireworksEffect" });
defineOptions({ name: "FaFireworksEffect" });
const { currentFestivalData } = useCeremony();
@@ -9,6 +9,6 @@
<script setup lang="ts">
import { getEnabledGlobalComponents } from "@/config/modules/component";
defineOptions({ name: "ArtGlobalComponent" });
defineOptions({ name: "FaGlobalComponent" });
const enabledComponents = computed(() => getEnabledGlobalComponents());
</script>
@@ -22,7 +22,7 @@
<div
class="h-4.5 flex-cc rounded border border-g-300 dark:!bg-g-200/50 !bg-box px-1.5 text-g-500"
>
<ArtSvgIcon icon="fluent:arrow-enter-left-20-filled" />
<FaSvgIcon icon="fluent:arrow-enter-left-20-filled" />
</div>
</template>
</ElInput>
@@ -40,7 +40,7 @@
@mouseenter="highlightOnHover(index)"
>
{{ formatMenuTitle(item.meta.title) }}
<ArtSvgIcon v-show="isHighlighted(index)" icon="fluent:arrow-enter-left-20-filled" />
<FaSvgIcon v-show="isHighlighted(index)" icon="fluent:arrow-enter-left-20-filled" />
</div>
</div>
</div>
@@ -65,7 +65,7 @@
class="size-5 selected-icon select-none rounded-full text-g-500 flex-cc c-p"
@click.stop="deleteHistory(index)"
>
<ArtSvgIcon icon="ri:close-large-fill" class="text-xs" />
<FaSvgIcon icon="ri:close-large-fill" class="text-xs" />
</div>
</div>
</div>
@@ -75,12 +75,12 @@
<template #footer>
<div class="dialog-footer box-border flex-c border-t-d pt-4.5 pb-1">
<div class="flex-cc">
<ArtSvgIcon icon="fluent:arrow-enter-left-20-filled" class="keyboard" />
<FaSvgIcon icon="fluent:arrow-enter-left-20-filled" class="keyboard" />
<span class="mr-3.5 text-xs text-g-700">{{ $t("search.selectKeydown") }}</span>
</div>
<div class="flex-c">
<ArtSvgIcon icon="ri:arrow-up-wide-fill" class="keyboard" />
<ArtSvgIcon icon="ri:arrow-down-wide-fill" class="keyboard" />
<FaSvgIcon icon="ri:arrow-up-wide-fill" class="keyboard" />
<FaSvgIcon icon="ri:arrow-down-wide-fill" class="keyboard" />
<span class="mr-3.5 text-xs text-g-700">{{ $t("search.switchKeydown") }}</span>
</div>
<div class="flex-c">
@@ -103,7 +103,7 @@ import { formatMenuTitle } from "@utils/navigation";
import { handleMenuJump } from "@utils/navigation";
import { type ScrollbarInstance } from "element-plus";
defineOptions({ name: "ArtGlobalSearch" });
defineOptions({ name: "FaGlobalSearch" });
const userStore = useUserStore();
const { menuList } = storeToRefs(useMenuStore());
@@ -381,14 +381,14 @@ const highlightOnHoverHistory = (index: number) => {
.el-input {
:deep(.el-input__wrapper) {
background-color: var(--art-gray-200);
background-color: var(--fa-gray-200);
border: 1px solid var(--default-border-dashed);
border-radius: calc(var(--custom-radius) / 2 + 2px) !important;
box-shadow: none;
}
:deep(.el-input__inner) {
color: var(--art-gray-800) !important;
color: var(--fa-gray-800) !important;
}
}
}
@@ -12,18 +12,18 @@
class="relative box-border flex-b h-15 leading-15 select-none"
:class="[
tabStyle === 'tab-card' || tabStyle === 'tab-google' || tabStyle === 'tab-default'
? 'border-b border-[var(--art-card-border)]'
? 'border-b border-[var(--fa-card-border)]'
: '',
]"
>
<div class="flex-c flex-1 min-w-0 leading-15" style="display: flex">
<!-- 系统信息Logo + 标题一并受显示应用 Logo控制 -->
<div class="flex-c c-p" @click="toHome" v-if="isTopMenu && showAppLogo">
<ArtLogo class="pl-4.5" :src="headerLogoSrc" />
<FaLogo class="pl-4.5" :src="headerLogoSrc" />
<p v-if="width >= 1400" class="my-0 mx-2 ml-2 text-lg">{{ headerSystemName }}</p>
</div>
<ArtLogo
<FaLogo
v-if="showAppLogo"
class="!hidden pl-3.5 overflow-hidden align-[-0.15em] fill-current"
:src="headerLogoSrc"
@@ -31,7 +31,7 @@
/>
<!-- 菜单按钮 -->
<ArtIconButton
<FaIconButton
v-if="isLeftMenu && shouldShowMenuButton"
icon="ri:menu-2-fill"
class="ml-3 max-sm:ml-[7px]"
@@ -39,7 +39,7 @@
/>
<!-- 刷新按钮 -->
<ArtIconButton
<FaIconButton
v-if="shouldShowRefreshButton"
icon="ri:refresh-line"
class="!ml-3 refresh-btn max-sm:!hidden"
@@ -48,20 +48,20 @@
/>
<!-- 快速入口 -->
<ArtFastEnter v-if="shouldShowFastEnter && width >= headerBarFastEnterMinWidth">
<ArtIconButton icon="ri:function-line" class="ml-3" />
</ArtFastEnter>
<FaFastEnter v-if="shouldShowFastEnter && width >= headerBarFastEnterMinWidth">
<FaIconButton icon="ri:function-line" class="ml-3" />
</FaFastEnter>
<!-- 面包屑 -->
<ArtBreadcrumb
<FaBreadcrumb
v-if="(shouldShowBreadcrumb && isLeftMenu) || (shouldShowBreadcrumb && isDualMenu)"
/>
<!-- 顶部菜单 -->
<ArtHorizontalMenu v-if="isTopMenu" :list="menuList" />
<FaHorizontalMenu v-if="isTopMenu" :list="menuList" />
<!-- 混合菜单-顶部 -->
<ArtMixedMenu v-if="isTopLeftMenu" :list="menuList" />
<FaMixedMenu v-if="isTopLeftMenu" :list="menuList" />
</div>
<div id="app-header-toolbar" class="flex-c gap-2.5">
@@ -72,18 +72,18 @@
@click="openSearchDialog"
>
<div class="flex-c">
<ArtSvgIcon icon="ri:search-line" class="text-sm text-g-500" />
<FaSvgIcon icon="ri:search-line" class="text-sm text-g-500" />
<span class="ml-1 text-xs font-normal text-g-500">{{ $t("topBar.search.title") }}</span>
</div>
<div class="flex-c h-5 px-1.5 text-g-500/80 border border-g-400 rounded">
<ArtSvgIcon v-if="isWindows" icon="vaadin:ctrl-a" class="text-sm" />
<ArtSvgIcon v-else icon="ri:command-fill" class="text-xs" />
<FaSvgIcon v-if="isWindows" icon="vaadin:ctrl-a" class="text-sm" />
<FaSvgIcon v-else icon="ri:command-fill" class="text-xs" />
<span class="ml-0.5 text-xs">k</span>
</div>
</div>
<!-- 全屏按钮 -->
<ArtIconButton
<FaIconButton
v-if="shouldShowFullscreen"
:icon="isFullscreen ? 'ri:fullscreen-exit-line' : 'ri:fullscreen-fill'"
:class="[!isFullscreen ? 'full-screen-btn' : 'exit-full-screen-btn', 'ml-3']"
@@ -93,7 +93,7 @@
<!-- 组件尺寸 default/large/small沿 showSizeSelect -->
<div v-if="shouldShowSizeSelect" class="flex-cc ml-1 max-md:!hidden">
<SizeSelect />
<FaSizeSelect />
</div>
<!-- 国际化按钮 -->
@@ -102,7 +102,7 @@
popper-class="langDropDownStyle"
v-if="shouldShowLanguage"
>
<ArtIconButton icon="ri:translate-2" class="language-btn text-[19px]" />
<FaIconButton icon="ri:translate-2" class="language-btn text-[19px]" />
<template #dropdown>
<ElDropdownMenu>
<div v-for="item in languageOptions" :key="item.value" class="lang-btn-item">
@@ -111,7 +111,7 @@
:class="{ 'is-selected': locale === item.value }"
>
<span class="menu-txt">{{ item.label }}</span>
<ArtSvgIcon icon="ri:check-fill" v-if="locale === item.value" />
<FaSvgIcon icon="ri:check-fill" v-if="locale === item.value" />
</ElDropdownItem>
</div>
</ElDropdownMenu>
@@ -119,31 +119,31 @@
</ElDropdown>
<!-- 通知按钮 -->
<ArtIconButton
<FaIconButton
v-if="shouldShowNotification"
icon="ri:notification-2-line"
class="notice-button relative"
@click="visibleNotice"
>
<div class="absolute top-2 right-2 size-1.5 !bg-danger rounded-full"></div>
</ArtIconButton>
</FaIconButton>
<!-- 聊天按钮 -->
<ArtIconButton
<FaIconButton
v-if="shouldShowChat"
icon="ri:message-3-line"
class="chat-button relative"
@click="openChat"
>
<div class="breathing-dot absolute top-2 right-2 size-1.5 !bg-success rounded-full"></div>
</ArtIconButton>
</FaIconButton>
<!-- 设置按钮 -->
<div v-if="shouldShowSettings">
<ElPopover :visible="showSettingGuide" placement="bottom-start" :width="190" :offset="0">
<template #reference>
<div class="flex-cc">
<ArtIconButton icon="ri:settings-line" class="setting-btn" @click="openSetting" />
<FaIconButton icon="ri:settings-line" class="setting-btn" @click="openSetting" />
</div>
</template>
<template #default>
@@ -159,22 +159,22 @@
</div>
<!-- 主题切换按钮 -->
<ArtIconButton
<FaIconButton
v-if="shouldShowThemeToggle"
@click="themeAnimation"
:icon="isDark ? 'ri:sun-fill' : 'ri:moon-line'"
/>
<!-- 用户头像菜单 -->
<ArtUserMenu />
<FaUserMenu />
</div>
</div>
<!-- 标签页 -->
<ArtWorkTab />
<FaWorkTab />
<!-- 通知 -->
<ArtNotification v-model:value="showNotice" ref="notice" />
<FaNotification v-model:value="showNotice" ref="notice" />
</div>
</template>
@@ -193,10 +193,10 @@ import { mittBus } from "@utils/sys";
import { themeAnimation } from "@utils/ui";
import { useCommon } from "@/hooks/core/useCommon";
import { useHeaderBar } from "@/hooks/core/useHeaderBar";
import ArtUserMenu from "./widget/ArtUserMenu.vue";
import SizeSelect from "@/components/SizeSelect/index.vue";
import FaUserMenu from "./widget/FaUserMenu.vue";
import FaSizeSelect from "@/components/others/fa-size-select/index.vue";
defineOptions({ name: "ArtHeaderBar" });
defineOptions({ name: "FaHeaderBar" });
//
const isWindows = navigator.userAgent.includes("Windows");
@@ -347,7 +347,7 @@ const bodyCloseNotice = (e: any): void => {
//
const isNoticeButton = target.closest(".notice-button");
const isNoticePanel = target.closest(".art-notification-panel");
const isNoticePanel = target.closest(".fa-notification-panel");
if (!isNoticeButton && !isNoticePanel) {
showNotice.value = false;
@@ -463,35 +463,35 @@ const openChat = (): void => {
}
/* Hover animation classes */
.refresh-btn:hover :deep(.art-svg-icon) {
.refresh-btn:hover :deep(.fa-svg-icon) {
animation: rotate180 0.5s;
}
.language-btn:hover :deep(.art-svg-icon) {
.language-btn:hover :deep(.fa-svg-icon) {
animation: moveUp 0.4s;
}
.setting-btn:hover :deep(.art-svg-icon) {
.setting-btn:hover :deep(.fa-svg-icon) {
animation: rotate180 0.5s;
}
.full-screen-btn:hover :deep(.art-svg-icon) {
.full-screen-btn:hover :deep(.fa-svg-icon) {
animation: expand 0.6s forwards;
}
:deep(.size-select-btn:hover .art-svg-icon) {
:deep(.size-select-btn:hover .fa-svg-icon) {
animation: expand 0.6s forwards;
}
.exit-full-screen-btn:hover :deep(.art-svg-icon) {
.exit-full-screen-btn:hover :deep(.fa-svg-icon) {
animation: shrink 0.6s forwards;
}
.notice-button:hover :deep(.art-svg-icon) {
.notice-button:hover :deep(.fa-svg-icon) {
animation: shake 0.5s ease-in-out;
}
.chat-button:hover :deep(.art-svg-icon) {
.chat-button:hover :deep(.fa-svg-icon) {
animation: shake 0.5s ease-in-out;
}
@@ -1,7 +1,7 @@
<!-- 用户菜单合并旧版顶栏配置中心Gitee引导+ 新版 Popover 与链接结构 -->
<template>
<!-- inline-flex + items-center与顶栏 ArtIconButton 同一中线对齐避免 Popover 触发层基线偏移 -->
<div class="art-user-menu inline-flex shrink-0 items-center leading-none">
<!-- inline-flex + items-center与顶栏 FaIconButton 同一中线对齐避免 Popover 触发层基线偏移 -->
<div class="fa-user-menu inline-flex shrink-0 items-center leading-none">
<ElPopover
ref="userMenuPopover"
placement="bottom-end"
@@ -15,7 +15,7 @@
>
<template #reference>
<div
class="art-user-menu__avatar-ref mr-5 max-sm:mr-[16px] c-p flex size-8.5 max-sm:w-6.5 max-sm:h-6.5 shrink-0 items-center justify-center"
class="fa-user-menu__avatar-ref mr-5 max-sm:mr-[16px] c-p flex size-8.5 max-sm:w-6.5 max-sm:h-6.5 shrink-0 items-center justify-center"
>
<img
v-if="userAvatar"
@@ -30,7 +30,7 @@
alt="avatar"
/>
<!-- 与旧版 NavbarActions.user-profile__online-indicator 一致 -->
<span class="art-user-menu__online-dot" aria-hidden="true" />
<span class="fa-user-menu__online-dot" aria-hidden="true" />
</div>
</template>
<template #default>
@@ -57,35 +57,35 @@
</div>
<ul class="py-4 mt-3 border-t border-g-300/80">
<li class="btn-item" @click="goPage('/profile')">
<ArtSvgIcon icon="ri:user-3-line" />
<FaSvgIcon icon="ri:user-3-line" />
<span>{{ $t("topBar.user.userCenter") }}</span>
</li>
<li class="btn-item" @click="goChangeLog">
<ArtSvgIcon icon="ri:draft-line" />
<FaSvgIcon icon="ri:draft-line" />
<span>{{ $t("topBar.user.changeLog") }}</span>
</li>
<li class="btn-item" @click="openParamConfig">
<ArtSvgIcon icon="ri:settings-3-line" />
<FaSvgIcon icon="ri:settings-3-line" />
<span>{{ $t("topBar.user.paramConfig") }}</span>
</li>
<li class="btn-item" @click="toDocs()">
<ArtSvgIcon icon="ri:book-2-line" />
<FaSvgIcon icon="ri:book-2-line" />
<span>{{ $t("topBar.user.docs") }}</span>
</li>
<li class="btn-item" @click="toGithub()">
<ArtSvgIcon icon="ri:github-line" />
<FaSvgIcon icon="ri:github-line" />
<span>{{ $t("topBar.user.github") }}</span>
</li>
<li class="btn-item" @click="toGitee">
<ArtSvgIcon icon="ri:git-branch-line" />
<FaSvgIcon icon="ri:git-branch-line" />
<span>{{ $t("topBar.user.gitee") }}</span>
</li>
<li class="btn-item" @click="startTour">
<ArtSvgIcon icon="ri:compass-3-line" />
<FaSvgIcon icon="ri:compass-3-line" />
<span>{{ $t("topBar.user.tour") }}</span>
</li>
<li class="btn-item" @click="lockScreen()">
<ArtSvgIcon icon="ri:lock-line" />
<FaSvgIcon icon="ri:lock-line" />
<span>{{ $t("topBar.user.lockScreen") }}</span>
</li>
<div class="w-full h-px my-2 bg-g-300/80"></div>
@@ -114,7 +114,7 @@ import { WEB_LINKS } from "@utils/constants";
import { DeviceEnum } from "@/enums/settings/device.enum";
import { mittBus } from "@utils/sys";
defineOptions({ name: "ArtUserMenu" });
defineOptions({ name: "FaUserMenu" });
const router = useRouter();
const { t } = useI18n();
@@ -225,12 +225,12 @@ function closeUserMenu(): void {
@apply text-sm;
}
.art-svg-icon {
.fa-svg-icon {
@apply mr-2 text-base;
}
&:hover {
background-color: var(--art-gray-200);
background-color: var(--fa-gray-200);
}
}
@@ -240,26 +240,26 @@ function closeUserMenu(): void {
&:hover {
color: var(--el-color-danger);
background-color: var(--art-gray-200);
background-color: var(--fa-gray-200);
border-color: var(--el-color-danger-light-3);
}
}
}
/* ElPopover 基于 Tooltip:触发层默认 inline-block,与顶栏 flex 图标中线对齐 */
.art-user-menu :deep(.el-tooltip__trigger) {
.fa-user-menu :deep(.el-tooltip__trigger) {
display: inline-flex !important;
align-items: center;
line-height: 1;
}
/* 顶栏头像右下角在线状态(对齐旧版顶栏);占位与 ArtIconButton size-8.5 一致 */
.art-user-menu__avatar-ref {
/* 顶栏头像右下角在线状态(对齐旧版顶栏);占位与 FaIconButton size-8.5 一致 */
.fa-user-menu__avatar-ref {
position: relative;
box-sizing: border-box;
}
.art-user-menu__online-dot {
.fa-user-menu__online-dot {
position: absolute;
right: 0;
bottom: 0;
@@ -5,7 +5,7 @@
:ellipsis="true"
mode="horizontal"
:default-active="routerPath"
:text-color="isDark ? 'var(--art-gray-800)' : 'var(--art-gray-700)'"
:text-color="isDark ? 'var(--fa-gray-800)' : 'var(--fa-gray-700)'"
:popper-offset="-6"
background-color="transparent"
:show-timeout="50"
@@ -29,7 +29,7 @@ import type { AppRouteRecord } from "@/types/router";
import HorizontalSubmenu from "./widget/HorizontalSubmenu.vue";
import { useSettingsStore } from "@stores/modules/setting.store";
defineOptions({ name: "ArtHorizontalMenu" });
defineOptions({ name: "FaHorizontalMenu" });
const settingStore = useSettingsStore();
const { isDark } = storeToRefs(settingStore);
@@ -1,10 +1,10 @@
<template>
<ElSubMenu v-if="hasChildren" :index="item.path || item.meta.title" class="!p-0">
<template #title>
<MenuRouteIcon :icon="item.meta.icon" :color="theme?.iconColor" class="mr-1 text-lg" />
<FaMenuRouteIcon :icon="item.meta.icon" :color="theme?.iconColor" class="mr-1 text-lg" />
<span class="text-md">{{ formatMenuTitle(item.meta.title) }}</span>
<div v-if="item.meta.showBadge" class="art-badge art-badge-horizontal" />
<div v-if="item.meta.showTextBadge" class="art-text-badge">
<div v-if="item.meta.showBadge" class="fa-badge fa-badge-horizontal" />
<div v-if="item.meta.showTextBadge" class="fa-text-badge">
{{ item.meta.showTextBadge }}
</div>
</template>
@@ -35,10 +35,10 @@
<span class="text-md">{{ formatMenuTitle(item.meta.title) }}</span>
<div
v-if="item.meta.showBadge"
class="art-badge"
class="fa-badge"
:style="{ right: level === 0 ? '10px' : '20px' }"
/>
<div v-if="item.meta.showTextBadge && level !== 0" class="art-text-badge">
<div v-if="item.meta.showTextBadge && level !== 0" class="fa-text-badge">
{{ item.meta.showTextBadge }}
</div>
</ElMenuItem>
@@ -26,7 +26,7 @@
}"
@click="handleMenuJump(item, true)"
>
<MenuRouteIcon
<FaMenuRouteIcon
:icon="item.meta.icon"
class="text-lg text-g-700 dark:text-g-800 mr-1"
:class="item.isActive && '!text-theme'"
@@ -37,7 +37,7 @@
>
{{ item.formattedTitle }}
</span>
<div v-if="item.meta.showBadge" class="art-badge art-badge-mixed" />
<div v-if="item.meta.showBadge" class="fa-badge fa-badge-mixed" />
</div>
</template>
</div>
@@ -60,7 +60,7 @@ import { formatMenuTitle } from "@utils/navigation";
import { handleMenuJump } from "@utils/navigation";
import type { AppRouteRecord } from "@/types/router";
defineOptions({ name: "ArtMixedMenu" });
defineOptions({ name: "FaMixedMenu" });
interface Props {
/** 菜单列表数据 */
@@ -11,7 +11,7 @@
class="dual-menu-left"
:style="{ width: dualMenuShowText ? '80px' : '64px', background: getMenuTheme.background }"
>
<ArtLogo v-if="showAppLogo" class="logo" :src="sidebarLogoSrc" @click="navigateToHome" />
<FaLogo v-if="showAppLogo" class="logo" :src="sidebarLogoSrc" @click="navigateToHome" />
<ElScrollbar style="height: calc(100% - 135px)">
<ul>
@@ -35,7 +35,7 @@
height: dualMenuShowText ? '60px' : '46px',
}"
>
<MenuRouteIcon
<FaMenuRouteIcon
class="menu-icon text-g-700 dark:text-g-800"
:icon="menu.meta.icon"
:style="{
@@ -45,14 +45,14 @@
<span v-if="dualMenuShowText" class="text-md text-g-700">
{{ $t(menu.meta.title) }}
</span>
<div v-if="menu.meta.showBadge" class="art-badge art-badge-dual" />
<div v-if="menu.meta.showBadge" class="fa-badge fa-badge-dual" />
</div>
</ElTooltip>
</li>
</ul>
</ElScrollbar>
<ArtIconButton
<FaIconButton
class="switch-btn size-10"
icon="ri:arrow-left-right-fill"
@click="toggleDualMenuMode"
@@ -75,7 +75,7 @@
background: getMenuTheme.background,
}"
>
<ArtLogo v-if="!isDualMenu" class="logo" :src="sidebarLogoSrc" />
<FaLogo v-if="!isDualMenu" class="logo" :src="sidebarLogoSrc" />
<p
:class="{ 'is-dual-menu-name': isDualMenu }"
@@ -111,7 +111,7 @@
<!-- 双列菜单右侧折叠按钮 -->
<div class="dual-menu-collapse-btn" v-if="isDualMenu" @click="toggleMenuVisibility">
<ArtSvgIcon
<FaSvgIcon
class="text-g-500/70"
:icon="menuOpen ? 'ri:arrow-left-wide-fill' : 'ri:arrow-right-wide-fill'"
/>
@@ -138,10 +138,11 @@ import { useMenuStore } from "@stores/modules/menu.store";
import { isIframe } from "@utils/navigation";
import { handleMenuJump } from "@utils/navigation";
import SidebarSubmenu from "./widget/SidebarSubmenu.vue";
import FaMenuRouteIcon from "@/components/others/fa-menu-routeIcon/index.vue";
import { useCommon } from "@/hooks/core/useCommon";
import { useWindowSize, useTimeoutFn } from "@vueuse/core";
defineOptions({ name: "ArtSidebarMenu" });
defineOptions({ name: "FaSidebarMenu" });
const MOBILE_BREAKPOINT = 800;
const ANIMATION_DELAY = 350;

Some files were not shown because too many files have changed in this diff Show More