style(web): 统一后台图标与全局视觉

This commit is contained in:
Zhou Weidong committed 2026-10-19 11:12:38 +08:00
1 parent 5c087f4db9
commit 97fbeda508
67 files changed
+737 -744

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
// Author: fruit.com.cn
import AppIcon from './src/AppIcon.vue'
export { AppIcon }
+40
View File
@@ -0,0 +1,40 @@
<!-- Author: fruit.com.cn -->
<script setup lang="ts">
import { computed } from 'vue'
import { Icon } from '@/components/Icon'
import { normalizeAppIcon } from '@/constants/icons'
import { propTypes } from '@/utils/propTypes'
/**
* 后台统一图标入口:默认使用 Material Symbols Rounded。
*/
const props = defineProps({
icon: propTypes.string,
color: propTypes.string,
size: propTypes.number.def(18),
hoverColor: propTypes.string
})
const resolvedIcon = computed(() => normalizeAppIcon(props.icon))
</script>
<template>
<Icon
:icon="resolvedIcon"
:color="color"
:size="size"
:hover-color="hoverColor"
class="app-icon"
/>
</template>
<style scoped>
.app-icon {
display: inline-flex;
align-items: center;
justify-content: center;
line-height: 1;
vertical-align: middle;
}
</style>
+4 -4
View File
@@ -9,7 +9,7 @@ import { filterBreadcrumb } from './helper'
import { filter, treeToList } from '@/utils/tree'
import type { RouteLocationNormalizedLoaded, RouteMeta } from 'vue-router'
import { useI18n } from '@/hooks/web/useI18n'
import { Icon } from '@/components/Icon'
import { AppIcon } from '@/components/AppIcon'
import { useAppStore } from '@/store/modules/app'
import { useDesign } from '@/hooks/web/useDesign'
@@ -54,7 +54,7 @@ export default defineComponent({
<ElBreadcrumbItem to={{ path: disabled ? '' : v.path }} key={v.name}>
{meta?.icon && breadcrumbIcon.value ? (
<>
<Icon icon={meta.icon} class="mr-[5px]"></Icon> {t(v?.meta?.title)}
<AppIcon icon={meta.icon} class="mr-[5px]"></AppIcon> {t(v?.meta?.title)}
</>
) : (
t(v?.meta?.title)
@@ -117,10 +117,10 @@ export default defineComponent({
:deep(&__item):last-child {
.@{prefix-cls}__inner {
color: var(--el-text-color-placeholder);
color: var(--el-text-color-regular);
&:hover {
color: var(--el-text-color-placeholder);
color: var(--el-color-primary);
}
}
}
+3 -2
View File
@@ -5,6 +5,7 @@ import { computed, unref } from 'vue'
import { useAppStore } from '@/store/modules/app'
import { propTypes } from '@/utils/propTypes'
import { useDesign } from '@/hooks/web/useDesign'
import { AppIcons } from '@/constants/icons'
const { getPrefixCls } = useDesign()
@@ -26,9 +27,9 @@ const toggleCollapse = () => {
<template>
<div :class="prefixCls" @click="toggleCollapse">
<Icon
<AppIcon
:size="18"
:icon="collapse ? 'ant-design:menu-unfold-outlined' : 'ant-design:menu-fold-outlined'"
:icon="collapse ? AppIcons.menuOpen : AppIcons.menu"
:color="color"
class="cursor-pointer"
/>
@@ -4,6 +4,7 @@
import { ElCard, ElTooltip } from 'element-plus'
import { propTypes } from '@/utils/propTypes'
import { useDesign } from '@/hooks/web/useDesign'
import { AppIcons } from '@/constants/icons'
const { getPrefixCls } = useDesign()
@@ -24,7 +25,7 @@ defineProps({
<template #content>
<div class="max-w-200px">{{ message }}</div>
</template>
<Icon class="ml-5px" icon="bi:question-circle-fill" :size="14" />
<AppIcon class="ml-5px" :icon="AppIcons.help" :size="14" />
</ElTooltip>
</div>
</template>
@@ -66,7 +66,7 @@ defineExpose({
:disabled="item.disabled"
:command="item"
>
<Icon :icon="item.icon" /> {{ t(item.label) }}
<AppIcon :icon="item.icon" /> {{ t(item.label) }}
</ElDropdownItem>
</ElDropdownMenu>
</template>
@@ -7,8 +7,9 @@ import { propTypes } from '@/utils/propTypes'
import { ref, unref, PropType, computed, defineComponent } from 'vue'
import { useAppStore } from '@/store/modules/app'
import { DescriptionsSchema } from './types'
import { Icon } from '@/components/Icon'
import { AppIcon } from '@/components/AppIcon'
import { get } from 'lodash-es'
import { AppIcons } from '@/constants/icons'
const appStore = useAppStore()
@@ -94,12 +95,14 @@ export default defineComponent({
{props.title}
{props.message ? (
<ElTooltip content={props.message} placement="right">
<Icon icon="bi:question-circle-fill" class="ml-5px" size={14} />
<AppIcon icon={AppIcons.help} class="ml-5px" size={14} />
</ElTooltip>
) : null}
</div>
</div>
{props.collapse ? <Icon icon={show.value ? 'ep:arrow-down' : 'ep:arrow-up'} /> : null}
{props.collapse ? (
<AppIcon icon={show.value ? AppIcons.chevronDown : AppIcons.chevronUp} />
) : null}
</div>
) : null}
+5 -4
View File
@@ -5,6 +5,7 @@ import { ElDialog, ElScrollbar } from 'element-plus'
import { propTypes } from '@/utils/propTypes'
import { computed, useAttrs, ref, unref, useSlots, watch, nextTick } from 'vue'
import { isNumber } from '@/utils/is'
import { AppIcons } from '@/constants/icons'
const slots = useSlots()
@@ -77,17 +78,17 @@ const dialogStyle = computed(() => {
<div
class="h-54px flex justify-between items-center absolute top-[50%] right-15px translate-y-[-50%]"
>
<Icon
<AppIcon
v-if="fullscreen"
class="cursor-pointer is-hover !h-54px mr-10px"
:icon="isFullscreen ? 'radix-icons:exit-full-screen' : 'radix-icons:enter-full-screen'"
:icon="isFullscreen ? AppIcons.fullscreenExit : AppIcons.fullscreen"
color="var(--el-color-info)"
hover-color="var(--el-color-primary)"
@click="toggleFull"
/>
<Icon
<AppIcon
class="cursor-pointer is-hover !h-54px"
icon="ep:close"
:icon="AppIcons.close"
hover-color="var(--el-color-primary)"
color="var(--el-color-info)"
@click="close"
+5 -3
View File
@@ -6,6 +6,7 @@ import { ElIcon } from 'element-plus'
import { propTypes } from '@/utils/propTypes'
import { useDesign } from '@/hooks/web/useDesign'
import { Icon } from '@iconify/vue'
import { normalizeAppIcon } from '@/constants/icons'
const { getPrefixCls } = useDesign()
@@ -22,9 +23,10 @@ const props = defineProps({
})
const isLocal = computed(() => props.icon.startsWith('svg-icon:'))
const normalizedIcon = computed(() => normalizeAppIcon(props.icon))
const symbolId = computed(() => {
return unref(isLocal) ? `#icon-${props.icon.split('svg-icon:')[1]}` : props.icon
return unref(isLocal) ? `#icon-${props.icon.split('svg-icon:')[1]}` : unref(normalizedIcon)
})
// 是否使用在线图标
@@ -48,8 +50,8 @@ const getIconifyStyle = computed(() => {
</svg>
<template v-else>
<Icon v-if="isUseOnline" :icon="icon" :style="getIconifyStyle" />
<div v-else :class="`${icon} iconify`" :style="getIconifyStyle"></div>
<Icon v-if="isUseOnline" :icon="normalizedIcon" :style="getIconifyStyle" />
<div v-else :class="`${normalizedIcon} iconify`" :style="getIconifyStyle"></div>
</template>
</ElIcon>
</template>
@@ -7,6 +7,7 @@ import { useLocaleStore } from '@/store/modules/locale'
import { useLocale } from '@/hooks/web/useLocale'
import { propTypes } from '@/utils/propTypes'
import { useDesign } from '@/hooks/web/useDesign'
import { AppIcons } from '@/constants/icons'
const { getPrefixCls } = useDesign()
@@ -36,9 +37,9 @@ const setLang = (lang: LocaleType) => {
<template>
<ElDropdown :class="prefixCls" trigger="click" @command="setLang">
<Icon
<AppIcon
:size="18"
icon="ion:language-sharp"
:icon="AppIcons.language"
class="cursor-pointer !p-0"
:class="$attrs.class"
:color="color"
+2 -2
View File
@@ -67,8 +67,8 @@ watch(
to="/"
>
<img
src="@/assets/imgs/logo.png"
class="w-[calc(var(--logo-height)-10px)] h-[calc(var(--logo-height)-10px)]"
src="@/assets/imgs/brand-mark.png"
class="w-[var(--brand-mark-size)] h-[var(--brand-mark-size)] rounded-[var(--brand-mark-radius)] object-cover"
/>
<div
v-if="show"
@@ -1,5 +1,7 @@
// Author: fruit.com.cn
import type { RouteMeta } from 'vue-router'
import { Icon } from '@/components/Icon'
import { AppIcon } from '@/components/AppIcon'
import { useI18n } from '@/hooks/web/useI18n'
export const useRenderMenuTitle = () => {
@@ -9,7 +11,7 @@ export const useRenderMenuTitle = () => {
return icon ? (
<>
<Icon icon={meta.icon}></Icon>
<AppIcon icon={meta.icon}></AppIcon>
<span class="v-menu__title overflow-hidden overflow-ellipsis whitespace-nowrap">
{t(title as string)}
</span>
+4 -3
View File
@@ -1,10 +1,11 @@
<!-- Author: fruit.com.cn -->
<script setup lang="ts">
import { Icon } from '@/components/Icon'
import { AppIcon } from '@/components/AppIcon'
import { useFullscreen } from '@vueuse/core'
import { propTypes } from '@/utils/propTypes'
import { useDesign } from '@/hooks/web/useDesign'
import { AppIcons } from '@/constants/icons'
const { getPrefixCls } = useDesign()
@@ -23,9 +24,9 @@ const toggleFullscreen = () => {
<template>
<div :class="prefixCls" @click="toggleFullscreen">
<Icon
<AppIcon
:size="18"
:icon="isFullscreen ? 'zmdi:fullscreen-exit' : 'zmdi:fullscreen'"
:icon="isFullscreen ? AppIcons.fullscreenExit : AppIcons.fullscreen"
:color="color"
/>
</div>
@@ -5,6 +5,7 @@ import { ElButton } from 'element-plus'
import { useIcon } from '@/hooks/web/useIcon'
import { propTypes } from '@/utils/propTypes'
import { useI18n } from '@/hooks/web/useI18n'
import { AppIcons } from '@/constants/icons'
const emit = defineEmits(['search', 'reset', 'expand'])
@@ -37,7 +38,7 @@ const onExpand = () => {
v-if="showSearch"
type="primary"
:loading="searchLoading"
:icon="useIcon({ icon: 'ep:search' })"
:icon="useIcon({ icon: AppIcons.search })"
@click="onSearch"
>
{{ t('common.query') }}
@@ -45,14 +46,14 @@ const onExpand = () => {
<ElButton
v-if="showReset"
:loading="resetLoading"
:icon="useIcon({ icon: 'ep:refresh-right' })"
:icon="useIcon({ icon: AppIcons.refresh })"
@click="onReset"
>
{{ t('common.reset') }}
</ElButton>
<ElButton
v-if="showExpand"
:icon="useIcon({ icon: visible ? 'ep:arrow-down' : 'ep:arrow-up' })"
:icon="useIcon({ icon: visible ? AppIcons.chevronDown : AppIcons.chevronUp })"
text
@click="onExpand"
>
+16 -6
View File
@@ -1,7 +1,7 @@
<!-- Author: fruit.com.cn -->
<script setup lang="ts">
import { ElDrawer, ElDivider, ElMessage } from 'element-plus'
import { ElDrawer, ElDivider, ElMessage, ElMessageBox } from 'element-plus'
import { ref, unref } from 'vue'
import { useI18n } from '@/hooks/web/useI18n'
import { ThemeSwitch } from '@/components/ThemeSwitch'
@@ -14,6 +14,7 @@ import LayoutRadioPicker from './components/LayoutRadioPicker.vue'
import { useStorage } from '@/hooks/web/useStorage'
import { useClipboard } from '@vueuse/core'
import { useDesign } from '@/hooks/web/useDesign'
import { AppIcons } from '@/constants/icons'
const { clear: storageClear } = useStorage('localStorage')
@@ -145,9 +146,18 @@ const copyConfig = async () => {
}
// 清空缓存
const clear = () => {
storageClear()
window.location.reload()
const clear = async () => {
try {
await ElMessageBox.confirm(t('setting.clearCacheMessage'), t('setting.clearAndReset'), {
confirmButtonText: t('common.ok'),
cancelButtonText: t('common.cancel'),
type: 'warning'
})
storageClear()
window.location.reload()
} catch {
// 取消清除时保持当前状态
}
}
const themeChange = () => {
@@ -163,7 +173,7 @@ const themeChange = () => {
class="fixed top-[45%] right-0 w-40px h-40px flex items-center justify-center bg-[var(--el-color-primary)] cursor-pointer z-10"
@click="drawer = true"
>
<Icon icon="ant-design:setting-outlined" color="#fff" />
<AppIcon :icon="AppIcons.settings" color="#fff" />
</div>
<ElDrawer v-model="drawer" direction="rtl" size="350px" :z-index="4000">
@@ -254,6 +264,6 @@ const themeChange = () => {
@prefix-cls: ~'@{namespace}-setting';
.@{prefix-cls} {
border-radius: 6px 0 0 6px;
border-radius: var(--app-radius-md) 0 0 6px;
}
</style>
@@ -4,6 +4,7 @@
import { PropType, watch, unref, ref } from 'vue'
import { propTypes } from '@/utils/propTypes'
import { useDesign } from '@/hooks/web/useDesign'
import { AppIcons } from '@/constants/icons'
const { getPrefixCls } = useDesign()
@@ -51,7 +52,7 @@ watch(
}"
@click="colorVal = item"
>
<Icon v-if="colorVal === item" color="#fff" icon="ep:check" :size="16" />
<AppIcon v-if="colorVal === item" color="#fff" :icon="AppIcons.check" :size="16" />
</span>
</div>
</template>
@@ -67,7 +67,7 @@ const layout = computed(() => appStore.getLayout)
.@{prefix-cls} {
&__classic {
border: 2px solid #e5e7eb;
border-radius: 4px;
border-radius: var(--app-radius-sm);
&::before {
position: absolute;
@@ -77,7 +77,7 @@ const layout = computed(() => appStore.getLayout)
width: 33%;
height: 100%;
background-color: #273352;
border-radius: 4px 0 0 4px;
border-radius: var(--app-radius-sm) 0 0 4px;
content: '';
}
@@ -88,14 +88,14 @@ const layout = computed(() => appStore.getLayout)
width: 100%;
height: 25%;
background-color: #fff;
border-radius: 4px 4px 0;
border-radius: var(--app-radius-sm) 4px 0;
content: '';
}
}
&__top-left {
border: 2px solid #e5e7eb;
border-radius: 4px;
border-radius: var(--app-radius-sm);
&::before {
position: absolute;
@@ -105,7 +105,7 @@ const layout = computed(() => appStore.getLayout)
width: 100%;
height: 33%;
background-color: #273352;
border-radius: 4px 4px 0 0;
border-radius: var(--app-radius-sm) 4px 0 0;
content: '';
}
@@ -116,14 +116,14 @@ const layout = computed(() => appStore.getLayout)
width: 33%;
height: 100%;
background-color: #fff;
border-radius: 4px 0 0 4px;
border-radius: var(--app-radius-sm) 0 0 4px;
content: '';
}
}
&__top {
border: 2px solid #e5e7eb;
border-radius: 4px;
border-radius: var(--app-radius-sm);
&::before {
position: absolute;
@@ -133,14 +133,14 @@ const layout = computed(() => appStore.getLayout)
width: 100%;
height: 33%;
background-color: #273352;
border-radius: 4px 4px 0 0;
border-radius: var(--app-radius-sm) 4px 0 0;
content: '';
}
}
&__cut-menu {
border: 2px solid #e5e7eb;
border-radius: 4px;
border-radius: var(--app-radius-sm);
&::before {
position: absolute;
@@ -150,7 +150,7 @@ const layout = computed(() => appStore.getLayout)
width: 100%;
height: 33%;
background-color: #273352;
border-radius: 4px 4px 0 0;
border-radius: var(--app-radius-sm) 4px 0 0;
content: '';
}
@@ -161,7 +161,7 @@ const layout = computed(() => appStore.getLayout)
width: 10%;
height: 100%;
background-color: #fff;
border-radius: 4px 0 0 4px;
border-radius: var(--app-radius-sm) 0 0 4px;
content: '';
}
}
@@ -7,6 +7,7 @@ import { useAppStore } from '@/store/modules/app'
import { useI18n } from '@/hooks/web/useI18n'
import { propTypes } from '@/utils/propTypes'
import { useDesign } from '@/hooks/web/useDesign'
import { AppIcons } from '@/constants/icons'
const { getPrefixCls } = useDesign()
@@ -29,7 +30,7 @@ const setCurrentSize = (size: ComponentSize) => {
<template>
<ElDropdown :class="prefixCls" trigger="click" @command="setCurrentSize">
<Icon :size="18" icon="mdi:format-size" :color="color" class="cursor-pointer" />
<AppIcon :size="18" :icon="AppIcons.formatSize" :color="color" class="cursor-pointer" />
<template #dropdown>
<ElDropdownMenu>
<ElDropdownItem v-for="item in sizeMap" :key="item" :command="item">
+4 -3
View File
@@ -6,7 +6,7 @@ import { useAppStore } from '@/store/modules/app'
import { computed, unref, defineComponent, watch, ref, onMounted } from 'vue'
import { useI18n } from '@/hooks/web/useI18n'
import { ElScrollbar } from 'element-plus'
import { Icon } from '@/components/Icon'
import { AppIcon } from '@/components/AppIcon'
import { Menu } from '@/components/Menu'
import { useRouter } from 'vue-router'
import { pathResolve } from '@/utils/routerHelper'
@@ -14,6 +14,7 @@ import { cloneDeep } from 'lodash-es'
import { filterMenusPath, initTabMap, tabPathMap } from './helper'
import { useDesign } from '@/hooks/web/useDesign'
import { isUrl } from '@/utils/is'
import { AppIcons } from '@/constants/icons'
const { getPrefixCls, variables } = useDesign()
@@ -180,7 +181,7 @@ export default defineComponent({
}}
>
<div>
<Icon icon={item?.meta?.icon}></Icon>
<AppIcon icon={item?.meta?.icon}></AppIcon>
</div>
{!unref(showTitle) ? undefined : (
<p class="break-words mt-5px px-2px">{t(item.meta?.title)}</p>
@@ -198,7 +199,7 @@ export default defineComponent({
]}
onClick={setCollapse}
>
<Icon icon={unref(collapse) ? 'ep:d-arrow-right' : 'ep:d-arrow-left'}></Icon>
<AppIcon icon={unref(collapse) ? AppIcons.chevronRight : AppIcons.chevronLeft}></AppIcon>
</div>
<Menu
class={[
+3 -2
View File
@@ -20,8 +20,9 @@ import { CSSProperties } from 'vue'
import { getSlot } from '@/utils/tsxHelper'
import TableActions from './components/TableActions.vue'
import { createVideoViewer } from '@/components/VideoPlayer'
import { Icon } from '@/components/Icon'
import { AppIcon } from '@/components/AppIcon'
import { BaseButton } from '@/components/Button'
import { AppIcons } from '@/constants/icons'
export default defineComponent({
name: 'Table',
@@ -408,7 +409,7 @@ export default defineComponent({
) : videoPreview.includes(field) ? (
<BaseButton
type="primary"
icon={<Icon icon="ep:video-play" />}
icon={<AppIcon icon={AppIcons.videoPlay} />}
onClick={() => {
createVideoViewer({
url
@@ -13,6 +13,7 @@ import { TableColumn } from '../types'
import { PropType, ref, watch, unref } from 'vue'
import { cloneDeep } from 'lodash-es'
import { DEFAULT_FILTER_COLUMN } from '@/constants'
import { AppIcons } from '@/constants/icons'
import { VueDraggable } from 'vue-draggable-plus'
const modelValue = defineModel<boolean>()
@@ -141,17 +142,19 @@ watch(
<div class="flex items-center">
<ElRadioGroup size="small" v-model="item.fixed">
<ElRadioButton label="left">
<Icon icon="ep:arrow-left" />
<AppIcon :icon="AppIcons.chevronLeft" />
</ElRadioButton>
<ElRadioButton :label="undefined">
<Icon icon="ep:close" />
<AppIcon :icon="AppIcons.close" />
</ElRadioButton>
<ElRadioButton label="right">
<Icon icon="ep:arrow-right" />
<AppIcon :icon="AppIcons.chevronRight" />
</ElRadioButton>
</ElRadioGroup>
<div class="ml-12px cursor-move handle"><Icon icon="ep:rank" /></div>
<div class="ml-12px cursor-move handle">
<AppIcon :icon="AppIcons.drag" />
</div>
</div>
</div>
</ElCheckboxGroup>
@@ -3,11 +3,12 @@
<script lang="tsx">
import { defineComponent, unref, computed, PropType, ref } from 'vue'
import { ElDropdown, ElDropdownMenu, ElDropdownItem, ComponentSize } from 'element-plus'
import { Icon } from '@/components/Icon'
import { AppIcon } from '@/components/AppIcon'
import { useI18n } from '@/hooks/web/useI18n'
import { useAppStore } from '@/store/modules/app'
import { TableColumn } from '../types'
import ColumnSetting from './ColumnSetting.vue'
import { AppIcons } from '@/constants/icons'
export default defineComponent({
name: 'TableActions',
@@ -47,8 +48,8 @@ export default defineComponent({
<>
<div class="text-right h-28px flex items-center justify-end">
<div title="刷新" class="w-30px h-20px flex items-center justify-end" onClick={refresh}>
<Icon
icon="ant-design:sync-outlined"
<AppIcon
icon={AppIcons.refresh}
class="cursor-pointer"
hover-color="var(--el-color-primary)"
/>
@@ -59,8 +60,8 @@ export default defineComponent({
default: () => {
return (
<div title="尺寸" class="w-30px h-20px flex items-center justify-end">
<Icon
icon="ant-design:column-height-outlined"
<AppIcon
icon={AppIcons.viewColumn}
class="cursor-pointer"
hover-color="var(--el-color-primary)"
/>
@@ -92,8 +93,8 @@ export default defineComponent({
class="w-30px h-20px flex items-center justify-end"
onClick={showColumnSetting}
>
<Icon
icon="ant-design:setting-outlined"
<AppIcon
icon={AppIcons.settings}
class="cursor-pointer"
hover-color="var(--el-color-primary)"
/>
+28 -31
View File
@@ -16,6 +16,7 @@ import { ElScrollbar } from 'element-plus'
import { useScrollTo } from '@/hooks/event/useScrollTo'
import { useTagsView } from '@/hooks/web/useTagsView'
import { cloneDeep } from 'lodash-es'
import { AppIcons } from '@/constants/icons'
const { getPrefixCls } = useDesign()
@@ -262,18 +263,14 @@ watch(
</script>
<template>
<div
:id="prefixCls"
:class="prefixCls"
class="flex w-full relative bg-[#fff] dark:bg-[var(--el-bg-color)]"
>
<div :id="prefixCls" :class="prefixCls" class="flex w-full relative bg-[var(--el-bg-color)]">
<span
:class="`${prefixCls}__tool ${prefixCls}__tool--first`"
class="w-[var(--tags-view-height)] h-[var(--tags-view-height)] flex items-center justify-center cursor-pointer"
@click="move(-200)"
>
<Icon
icon="ep:d-arrow-left"
<AppIcon
:icon="AppIcons.chevronLeft"
color="var(--el-text-color-placeholder)"
:hover-color="isDark ? '#fff' : 'var(--el-color-black)'"
/>
@@ -285,7 +282,7 @@ watch(
:ref="itemRefs.set"
:schema="[
{
icon: 'ant-design:sync-outlined',
icon: AppIcons.refresh,
label: t('common.reload'),
disabled: selectedTag?.fullPath !== item.fullPath,
command: () => {
@@ -293,7 +290,7 @@ watch(
}
},
{
icon: 'ant-design:close-outlined',
icon: AppIcons.close,
label: t('common.closeTab'),
disabled: !!visitedViews?.length && selectedTag?.meta.affix,
command: () => {
@@ -302,7 +299,7 @@ watch(
},
{
divided: true,
icon: 'ant-design:vertical-right-outlined',
icon: AppIcons.splitRight,
label: t('common.closeTheLeftTab'),
disabled:
!!visitedViews?.length &&
@@ -313,7 +310,7 @@ watch(
}
},
{
icon: 'ant-design:vertical-left-outlined',
icon: AppIcons.splitLeft,
label: t('common.closeTheRightTab'),
disabled:
!!visitedViews?.length &&
@@ -325,7 +322,7 @@ watch(
},
{
divided: true,
icon: 'ant-design:tag-outlined',
icon: AppIcons.tag,
label: t('common.closeOther'),
disabled: selectedTag?.fullPath !== item.fullPath,
command: () => {
@@ -333,7 +330,7 @@ watch(
}
},
{
icon: 'ant-design:line-outlined',
icon: AppIcons.line,
label: t('common.closeAll'),
command: () => {
closeAllTags()
@@ -358,7 +355,7 @@ watch(
@click="navigate"
class="h-full flex justify-center items-center whitespace-nowrap pl-15px"
>
<Icon
<AppIcon
v-if="
item?.matched &&
item?.matched[1] &&
@@ -370,10 +367,10 @@ watch(
class="mr-5px"
/>
{{ t(item?.meta?.title as string) }}
<Icon
<AppIcon
:class="`${prefixCls}__item--close`"
color="#333"
icon="ant-design:close-outlined"
color="var(--el-text-color-secondary)"
:icon="AppIcons.close"
:size="12"
@click.prevent.stop="closeSelectedTag(item)"
/>
@@ -389,8 +386,8 @@ watch(
class="w-[var(--tags-view-height)] h-[var(--tags-view-height)] flex items-center justify-center cursor-pointer"
@click="move(200)"
>
<Icon
icon="ep:d-arrow-right"
<AppIcon
:icon="AppIcons.chevronRight"
color="var(--el-text-color-placeholder)"
:hover-color="isDark ? '#fff' : 'var(--el-color-black)'"
/>
@@ -400,8 +397,8 @@ watch(
class="w-[var(--tags-view-height)] h-[var(--tags-view-height)] flex items-center justify-center cursor-pointer"
@click="refreshSelectedTag(selectedTag)"
>
<Icon
icon="ant-design:reload-outlined"
<AppIcon
:icon="AppIcons.refresh"
color="var(--el-text-color-placeholder)"
:hover-color="isDark ? '#fff' : 'var(--el-color-black)'"
/>
@@ -410,14 +407,14 @@ watch(
trigger="click"
:schema="[
{
icon: 'ant-design:sync-outlined',
icon: AppIcons.refresh,
label: t('common.reload'),
command: () => {
refreshSelectedTag(selectedTag)
}
},
{
icon: 'ant-design:close-outlined',
icon: AppIcons.close,
label: t('common.closeTab'),
disabled: !!visitedViews?.length && selectedTag?.meta.affix,
command: () => {
@@ -426,7 +423,7 @@ watch(
},
{
divided: true,
icon: 'ant-design:vertical-right-outlined',
icon: AppIcons.splitRight,
label: t('common.closeTheLeftTab'),
disabled: !!visitedViews?.length && selectedTag?.fullPath === visitedViews[0].fullPath,
command: () => {
@@ -434,7 +431,7 @@ watch(
}
},
{
icon: 'ant-design:vertical-left-outlined',
icon: AppIcons.splitLeft,
label: t('common.closeTheRightTab'),
disabled:
!!visitedViews?.length &&
@@ -445,14 +442,14 @@ watch(
},
{
divided: true,
icon: 'ant-design:tag-outlined',
icon: AppIcons.tag,
label: t('common.closeOther'),
command: () => {
closeOthersTags()
}
},
{
icon: 'ant-design:line-outlined',
icon: AppIcons.line,
label: t('common.closeAll'),
command: () => {
closeAllTags()
@@ -464,8 +461,8 @@ watch(
:class="`${prefixCls}__tool`"
class="w-[var(--tags-view-height)] h-[var(--tags-view-height)] flex items-center justify-center cursor-pointer block"
>
<Icon
icon="ant-design:setting-outlined"
<AppIcon
:icon="AppIcons.settings"
color="var(--el-text-color-placeholder)"
:hover-color="isDark ? '#fff' : 'var(--el-color-black)'"
/>
@@ -542,8 +539,8 @@ watch(
&__item.is-active {
color: var(--el-color-white);
background-color: var(--el-color-primary);
border: 1px solid var(--el-color-primary);
background-color: var(--app-primary-strong);
border: 1px solid var(--app-primary-strong);
.@{prefix-cls}__item--close {
:deep(svg) {
color: var(--el-color-white) !important;
+18 -10
View File
@@ -6,6 +6,7 @@ import { useAppStore } from '@/store/modules/app'
import { ElSwitch } from 'element-plus'
import { useIcon } from '@/hooks/web/useIcon'
import { useDesign } from '@/hooks/web/useDesign'
import { AppIcons } from '@/constants/icons'
const { getPrefixCls } = useDesign()
@@ -13,18 +14,15 @@ const emit = defineEmits(['change'])
const prefixCls = getPrefixCls('theme-switch')
const Sun = useIcon({ icon: 'emojione-monotone:sun', color: '#fde047' })
const Sun = useIcon({ icon: AppIcons.lightMode, color: '#fde047' })
const CrescentMoon = useIcon({ icon: 'emojione-monotone:crescent-moon', color: '#fde047' })
const CrescentMoon = useIcon({ icon: AppIcons.darkMode, color: '#fde047' })
const appStore = useAppStore()
// 初始化获取是否是暗黑主题
const isDark = ref(appStore.getIsDark)
// 设置switch的背景颜色
const blackColor = 'var(--el-color-black)'
const themeChange = (val: boolean) => {
appStore.setIsDark(val)
emit('change', val)
@@ -36,9 +34,6 @@ const themeChange = (val: boolean) => {
:class="prefixCls"
v-model="isDark"
inline-prompt
:border-color="blackColor"
:inactive-color="blackColor"
:active-color="blackColor"
:active-icon="Sun"
:inactive-icon="CrescentMoon"
@change="themeChange"
@@ -46,7 +41,20 @@ const themeChange = (val: boolean) => {
</template>
<style lang="less" scoped>
:deep(.el-switch__core .el-switch__inner .is-icon) {
overflow: visible;
.v-theme-switch {
:deep(.el-switch__core .el-switch__inner .is-icon) {
overflow: visible;
}
:deep(.el-switch__core) {
min-width: 44px;
background: var(--el-fill-color-darker);
border-color: var(--el-text-color-secondary);
}
}
.v-theme-switch.is-checked :deep(.el-switch__core) {
background: var(--app-primary-strong) !important;
border-color: var(--app-primary-strong) !important;
}
</style>
+18 -3
View File
@@ -9,6 +9,8 @@ import { ref, computed } from 'vue'
import LockPage from './components/LockPage.vue'
import { useLockStore } from '@/store/modules/lock'
import { useUserStore } from '@/store/modules/user'
import { AppIcon } from '@/components/AppIcon'
import { AppIcons } from '@/constants/icons'
const userStore = useUserStore()
@@ -22,6 +24,12 @@ const prefixCls = getPrefixCls('user-info')
const { t } = useI18n()
const displayName = computed(
() => userStore.getUserInfo?.name || userStore.getUserInfo?.username || '-'
)
const avatarUrl = computed(() => userStore.getUserInfo?.avatar || '')
const loginOut = () => {
userStore.logoutConfirm()
}
@@ -38,12 +46,19 @@ const lockScreen = () => {
<ElDropdown class="custom-hover" :class="prefixCls" trigger="click">
<div class="flex items-center">
<img
src="@/assets/imgs/avatar.jpg"
v-if="avatarUrl"
:src="avatarUrl"
alt=""
class="w-[calc(var(--logo-height)-25px)] rounded-[50%]"
class="w-[calc(var(--logo-height)-25px)] h-[calc(var(--logo-height)-25px)] rounded-[50%] object-cover"
/>
<span
v-else
class="w-[calc(var(--logo-height)-25px)] h-[calc(var(--logo-height)-25px)] rounded-[50%] flex items-center justify-center bg-[var(--el-fill-color)]"
>
<AppIcon :icon="AppIcons.person" />
</span>
<span class="<lg:hidden text-14px pl-[5px] text-[var(--top-header-text-color)]">{{
userStore.getUserInfo?.username
displayName
}}</span>
</div>
<template #dropdown>
@@ -12,6 +12,9 @@ import { FormSchema } from '@/components/Form'
import { ElButton } from 'element-plus'
import { useDesign } from '@/hooks/web/useDesign'
import { useLockStore } from '@/store/modules/lock'
import { useUserStore } from '@/store/modules/user'
import { AppIcon } from '@/components/AppIcon'
import { AppIcons } from '@/constants/icons'
const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('lock-dialog')
@@ -21,6 +24,12 @@ const { required } = useValidator()
const { t } = useI18n()
const lockStore = useLockStore()
const userStore = useUserStore()
const displayName = computed(
() => userStore.getUserInfo?.name || userStore.getUserInfo?.username || '-'
)
const avatarUrl = computed(() => userStore.getUserInfo?.avatar || '')
const props = defineProps({
modelValue: {
@@ -84,8 +93,18 @@ const handleLock = async () => {
:title="dialogTitle"
>
<div class="flex flex-col items-center">
<img src="@/assets/imgs/avatar.jpg" alt="" class="w-70px h-70px rounded-[50%]" />
<span class="text-14px my-10px text-[var(--top-header-text-color)]">Archer</span>
<img
v-if="avatarUrl"
:src="avatarUrl"
alt=""
class="w-70px h-70px rounded-[50%] object-cover"
/>
<span
v-else
class="w-70px h-70px rounded-[50%] flex items-center justify-center bg-[var(--el-fill-color)]"
><AppIcon :icon="AppIcons.person" :size="30"
/></span>
<span class="text-14px my-10px text-[var(--top-header-text-color)]">{{ displayName }}</span>
</div>
<Form :is-col="false" :schema="schema" :rules="rules" @register="formRegister" />
<template #footer>
@@ -1,7 +1,7 @@
<!-- Author: fruit.com.cn -->
<script lang="ts" setup>
import { ref } from 'vue'
import { computed, ref } from 'vue'
import { ElInput, ElButton } from 'element-plus'
import { resetRouter } from '@/router'
import { useRouter } from 'vue-router'
@@ -10,11 +10,14 @@ import { useLockStore } from '@/store/modules/lock'
import { useI18n } from '@/hooks/web/useI18n'
import { useNow } from '@/hooks/web/useNow'
import { useDesign } from '@/hooks/web/useDesign'
import { Icon } from '@/components/Icon'
import { AppIcon } from '@/components/AppIcon'
import { loginOutApi } from '@/api/login'
import { useTagsViewStore } from '@/store/modules/tagsView'
import { AppIcons } from '@/constants/icons'
import { useUserStore } from '@/store/modules/user'
const tagsViewStore = useTagsViewStore()
const userStore = useUserStore()
const { clear } = useStorage()
@@ -34,6 +37,11 @@ const { hour, month, minute, meridiem, year, day, week } = useNow(true)
const { t } = useI18n()
const displayName = computed(
() => userStore.getUserInfo?.name || userStore.getUserInfo?.username || '-'
)
const avatarUrl = computed(() => userStore.getUserInfo?.avatar || '')
// 解锁
async function unLock() {
if (!password.value) {
@@ -77,7 +85,7 @@ function handleShowForm(show = false) {
@click="handleShowForm(false)"
v-show="showDate"
>
<Icon icon="ep:lock" />
<AppIcon :icon="AppIcons.lock" />
<span>{{ t('lock.unlock') }}</span>
</div>
@@ -96,8 +104,20 @@ function handleShowForm(show = false) {
<div :class="`${prefixCls}-entry`" v-show="!showDate">
<div :class="`${prefixCls}-entry-content`">
<div class="flex flex-col items-center">
<img src="@/assets/imgs/avatar.jpg" alt="" class="w-70px h-70px rounded-[50%]" />
<span class="text-14px my-10px text-[var(--logo-title-text-color)]">Archer</span>
<img
v-if="avatarUrl"
:src="avatarUrl"
alt=""
class="w-70px h-70px rounded-[50%] object-cover"
/>
<span
v-else
class="w-70px h-70px rounded-[50%] flex items-center justify-center bg-[var(--el-fill-color)]"
><AppIcon :icon="AppIcons.person" :size="30"
/></span>
<span class="text-14px my-10px text-[var(--logo-title-text-color)]">{{
displayName
}}</span>
</div>
<ElInput
type="password"
@@ -4,7 +4,8 @@
import { VideoPlayer } from '@/components/VideoPlayer'
import { ElOverlay } from 'element-plus'
import { ref, nextTick } from 'vue'
import { Icon } from '@/components/Icon'
import { AppIcon } from '@/components/AppIcon'
import { AppIcons } from '@/constants/icons'
const props = defineProps({
show: {
@@ -43,7 +44,7 @@ const close = async () => {
class="w-44px h-44px color-[#fff] bg-[var(--el-text-color-regular)] rounded-full border-[#fff] flex justify-center items-center cursor-pointer absolute top-40px right-40px"
@click="close"
>
<Icon icon="ep:close" :size="24" />
<AppIcon :icon="AppIcons.close" :size="24" />
</div>
<VideoPlayer :url="url" :poster="poster" />
</div>
+2
View File
@@ -2,9 +2,11 @@
import type { App } from 'vue'
import { Icon } from './Icon'
import { AppIcon } from './AppIcon'
import { BaseButton } from './Button'
export const setupGlobCom = (app: App<Element>): void => {
app.component('Icon', Icon)
app.component('AppIcon', AppIcon)
app.component('BaseButton', BaseButton)
}