Refactor/themes (#311)

* refactor: theme
This commit is contained in:
RealityBoy 2022-07-26 13:16:44 +08:00 committed by GitHub
parent 708ce43e00
commit d824c99489
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 1100 additions and 1066 deletions

View File

@ -32,10 +32,10 @@
"@ctrl/tinycolor": "^3.4.1",
"@logicflow/core": "^1.1.22",
"@logicflow/extension": "^1.1.22",
"@pureadmin/components": "^1.0.6",
"@pureadmin/components": "^1.1.0",
"@pureadmin/descriptions": "^1.1.0",
"@pureadmin/table": "^1.2.0",
"@pureadmin/utils": "^0.0.32",
"@pureadmin/utils": "^0.0.33",
"@vueuse/core": "^8.9.4",
"@vueuse/motion": "^2.0.0-beta.12",
"@vueuse/shared": "^8.9.4",
@ -143,7 +143,7 @@
"typescript": "^4.6.3",
"unocss": "^0.44.3",
"unplugin-vue-define-options": "^0.6.1",
"vite": "^3.0.1",
"vite": "^3.0.2",
"vite-plugin-mock": "^2.9.6",
"vite-plugin-remove-console": "^1.1.0",
"vite-svg-loader": "^3.4.0",

735
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -42,7 +42,6 @@ export default defineComponent({
<>
<div
class="scroll-num"
// @ts-ignore
style={{ "--i": props.i, "--delay": props.delay }}
>
<ul ref="ul" style={{ fontSize: "32px" }}>

View File

@ -102,6 +102,7 @@ onMounted(() => {
v-for="(item, key) in titleLists"
:key="key"
:title="item.text"
class="dark:color-bg_color"
@mouseenter.prevent="onEnter(key)"
@mouseleave.prevent="focusIndex = -1"
>

View File

@ -35,7 +35,7 @@ const nodeDragNode = item => {
<!-- 左侧bpmn元素选择器 -->
<div class="node-panel">
<div
class="node-item"
class="node-item dark:color-bg_color"
v-for="item in props.nodeList"
:key="item.text"
@mousedown="nodeDragNode(item)"

View File

@ -87,6 +87,8 @@ import Ppt from "@iconify-icons/ri/file-ppt-2-line";
import TerminalWindowLine from "@iconify-icons/ri/terminal-window-line";
import User from "@iconify-icons/ri/user-3-fill";
import Lock from "@iconify-icons/ri/lock-fill";
import MenuUnfold from "@iconify-icons/ri/menu-unfold-fill";
import MenuFold from "@iconify-icons/ri/menu-fold-fill";
addIcon("arrow-right-s-line", ArrowRightSLine);
addIcon("arrow-left-s-line", ArrowLeftSLine);
addIcon("logout-circle-r-line", LogoutCircleRLine);
@ -112,6 +114,8 @@ addIcon("ppt", Ppt);
addIcon("terminal-window-line", TerminalWindowLine);
addIcon("user", User);
addIcon("lock", Lock);
addIcon("menu-unfold", MenuUnfold);
addIcon("menu-fold", MenuFold);
// Font Awesome 4
import FaUser from "@iconify-icons/fa/user";
@ -161,6 +165,9 @@ export default defineComponent({
IconifyIcon,
{
icon: `${this.icon}`,
style: attrs?.style
? Object.assign(attrs.style, { outline: "none" })
: { outline: "none" },
...attrs
},
{

View File

@ -17,6 +17,9 @@ export default defineComponent({
IconifyIcon,
{
icon: `${this.icon}`,
style: attrs?.style
? Object.assign(attrs.style, { outline: "none" })
: { outline: "none" },
...attrs
},
{

View File

@ -246,7 +246,7 @@ export default defineComponent({
>
<div class="absolute top-[50%] left-[50%] font-bold">
<IconifyIconOffline
class="cursor-pointer outline-none"
class="cursor-pointer"
icon="refresh-right"
width="30"
color="var(--el-color-primary)"

View File

@ -57,7 +57,7 @@ export default defineComponent({
return {
background:
s === size.value ? useEpThemeStoreHook().epThemeColor : "",
color: s === size.value ? "#f4f4f5" : "#000"
color: s === size.value ? "#fff" : "var(--el-text-color-primary)"
};
};
});
@ -104,10 +104,10 @@ export default defineComponent({
const reference = {
reference: () => (
<IconifyIconOffline
class="cursor-pointer outline-none"
class="cursor-pointer"
icon="setting"
width="16"
color="#606266"
color="text_color_regular"
onMouseover={e => (buttonRef.value = e.currentTarget)}
/>
)
@ -117,7 +117,7 @@ export default defineComponent({
<>
<div
{...attrs}
class="w-99/100 mt-6 pt-2 pl-2 pr-2 pb-1 bg-white"
class="w-99/100 mt-6 p-2 bg-white dark:bg-dark"
v-loading={props.loading}
element-loading-svg={loadingSvg}
element-loading-svg-view-box="-10, -10, 50, 50"
@ -134,10 +134,10 @@ export default defineComponent({
placement="top"
>
<IconifyIconOffline
class="cursor-pointer outline-none"
class="cursor-pointer"
icon={isExpandAll.value ? "unExpand" : "expand"}
width="16"
color="#606266"
color="text_color_regular"
onClick={() => onExpand()}
/>
</el-tooltip>
@ -146,10 +146,10 @@ export default defineComponent({
) : undefined}
<el-tooltip effect="dark" content="刷新" placement="top">
<IconifyIconOffline
class="cursor-pointer outline-none"
class="cursor-pointer"
icon="refresh-right"
width="16"
color="#606266"
color="text_color_regular"
onClick={() => emit("refresh")}
/>
</el-tooltip>
@ -158,10 +158,10 @@ export default defineComponent({
<el-tooltip effect="dark" content="密度" placement="top">
<el-dropdown v-slots={dropdown} trigger="click">
<IconifyIconOffline
class="cursor-pointer outline-none"
class="cursor-pointer"
icon="density"
width="16"
color="#606266"
color="text_color_regular"
/>
</el-dropdown>
</el-tooltip>

View File

@ -6,7 +6,6 @@ import Search from "./search/index.vue";
import Notice from "./notice/index.vue";
import mixNav from "./sidebar/mixNav.vue";
import avatars from "/@/assets/avatars.jpg";
import Hamburger from "./sidebar/hamBurger.vue";
import { watch, getCurrentInstance } from "vue";
import Breadcrumb from "./sidebar/breadCrumb.vue";
import { deviceDetection } from "@pureadmin/utils";
@ -21,11 +20,11 @@ const {
logout,
onPanel,
changeTitle,
toggleSideBar,
pureApp,
username,
avatarsStyle,
getDropdownItemStyle,
getDropdownItemClass,
changeWangeditorLanguage
} = useNav();
@ -51,14 +50,9 @@ function translationEn() {
</script>
<template>
<div class="navbar">
<Hamburger
v-if="pureApp.layout !== 'mix'"
:is-active="pureApp.sidebar.opened"
class="hamburger-container"
@toggleClick="toggleSideBar"
/>
<div
class="navbar bg-[#fff] shadow-sm shadow-[rgba(0, 21, 41, 0.08)] dark:shadow-[#0d0d0d]"
>
<Breadcrumb v-if="pureApp.layout !== 'mix'" class="breadcrumb-container" />
<mixNav v-if="pureApp.layout === 'mix'" />
@ -72,11 +66,14 @@ function translationEn() {
<screenfull id="header-screenfull" v-show="!deviceDetection()" />
<!-- 国际化 -->
<el-dropdown id="header-translation" trigger="click">
<globalization />
<globalization
class="navbar-bg-hover w-40px h-48px p-11px cursor-pointer outline-none"
/>
<template #dropdown>
<el-dropdown-menu class="translation">
<el-dropdown-item
:style="getDropdownItemStyle(locale, 'zh')"
:class="['!dark:color-white', getDropdownItemClass(locale, 'zh')]"
@click="translationCh"
>
<IconifyIconOffline
@ -88,6 +85,7 @@ function translationEn() {
</el-dropdown-item>
<el-dropdown-item
:style="getDropdownItemStyle(locale, 'en')"
:class="['!dark:color-white', getDropdownItemClass(locale, 'en')]"
@click="translationEn"
>
<span class="check-en" v-show="locale === 'en'">
@ -100,9 +98,9 @@ function translationEn() {
</el-dropdown>
<!-- 退出登录 -->
<el-dropdown trigger="click">
<span class="el-dropdown-link">
<span class="el-dropdown-link navbar-bg-hover">
<img v-if="avatars" :src="avatars" :style="avatarsStyle" />
<p v-if="username">{{ username }}</p>
<p v-if="username" class="dark:color-white">{{ username }}</p>
</span>
<template #dropdown>
<el-dropdown-menu class="logout">
@ -117,7 +115,7 @@ function translationEn() {
</template>
</el-dropdown>
<span
class="el-icon-setting"
class="el-icon-setting navbar-bg-hover"
:title="t('buttons.hssystemSet')"
@click="onPanel"
>
@ -132,17 +130,6 @@ function translationEn() {
width: 100%;
height: 48px;
overflow: hidden;
background: #fff;
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
.hamburger-container {
line-height: 48px;
height: 100%;
float: left;
cursor: pointer;
transition: background 0.3s;
-webkit-tap-highlight-color: transparent;
}
.vertical-header-right {
display: flex;
@ -152,31 +139,6 @@ function translationEn() {
color: #000000d9;
justify-content: flex-end;
:deep(.dropdown-badge) {
&:hover {
background: #f6f6f6;
}
}
.screen-full {
cursor: pointer;
&:hover {
background: #f6f6f6;
}
}
.globalization {
height: 48px;
width: 40px;
padding: 11px;
cursor: pointer;
&:hover {
background: #f6f6f6;
}
}
.el-dropdown-link {
height: 48px;
padding: 10px;
@ -186,10 +148,6 @@ function translationEn() {
cursor: pointer;
color: #000000d9;
&:hover {
background: #f6f6f6;
}
p {
font-size: 14px;
}
@ -208,15 +166,12 @@ function translationEn() {
display: flex;
cursor: pointer;
align-items: center;
&:hover {
background: #f6f6f6;
}
}
}
.breadcrumb-container {
float: left;
margin-left: 16px;
}
}

View File

@ -22,7 +22,7 @@ function tabClick() {
<template>
<el-dropdown ref="dropdownDom" trigger="click" placement="bottom-end">
<span class="dropdown-badge">
<span class="dropdown-badge navbar-bg-hover select-none">
<el-badge :value="noticesNum" :max="99">
<span class="header-notice-icon">
<IconifyIconOffline icon="bell" />

View File

@ -44,7 +44,9 @@ function hoverDescription(event, description) {
</script>
<template>
<div class="notice-container">
<div
class="notice-container border-b-1 border-[#f0f0f0] dark:border-[#303030]"
>
<el-avatar
v-if="props.noticeItem.avatar"
:size="30"
@ -52,7 +54,7 @@ function hoverDescription(event, description) {
class="notice-container-avatar"
/>
<div class="notice-container-text">
<div class="notice-text-title">
<div class="notice-text-title color-[#000000d9] dark:color-white">
<el-tooltip
popper-class="notice-title-popper"
:disabled="!titleTooltip"
@ -91,7 +93,7 @@ function hoverDescription(event, description) {
{{ props.noticeItem.description }}
</div>
</el-tooltip>
<div class="notice-text-datetime">
<div class="notice-text-datetime color-[#00000073] dark:color-white">
{{ props.noticeItem.datetime }}
</div>
</div>
@ -109,7 +111,7 @@ function hoverDescription(event, description) {
align-items: flex-start;
justify-content: space-between;
padding: 12px 0;
border-bottom: 1px solid #f0f0f0;
// border-bottom: 1px solid #f0f0f0;
.notice-container-avatar {
margin-right: 16px;
@ -128,7 +130,6 @@ function hoverDescription(event, description) {
font-weight: 400;
font-size: 14px;
line-height: 1.5715;
color: rgba(0, 0, 0, 0.85);
cursor: pointer;
.notice-title-content {
@ -150,7 +151,6 @@ function hoverDescription(event, description) {
.notice-text-datetime {
font-size: 12px;
line-height: 1.5715;
color: rgba(0, 0, 0, 0.45);
}
.notice-text-description {

View File

@ -18,7 +18,7 @@ emitter.on("openPanel", () => {
<template>
<div :class="{ show: show }" class="right-panel-container">
<div class="right-panel-background" />
<div ref="target" class="right-panel">
<div ref="target" class="right-panel bg-white dark:bg-dark">
<div class="right-panel-items">
<div class="project-configuration">
<h3>项目配置</h3>
@ -26,7 +26,7 @@ emitter.on("openPanel", () => {
<IconifyIconOffline icon="close" />
</el-icon>
</div>
<div style="border-bottom: 1px solid #dcdfe6" />
<div class="border-b-1 border-[#dcdfe6] dark:border-[#303030]" />
<slot />
</div>
</div>
@ -62,7 +62,7 @@ emitter.on("openPanel", () => {
box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.05);
transition: all 0.25s cubic-bezier(0.7, 0.3, 0.1, 1);
transform: translate(100%);
background: #fff;
// background: #fff;
z-index: 40000;
}

View File

@ -1,13 +1,16 @@
<script setup lang="ts">
import { useFullscreen } from "@vueuse/core";
import { useI18n } from "vue-i18n";
import { useFullscreen } from "@vueuse/core";
const { t } = useI18n();
const { isFullscreen, toggle } = useFullscreen();
</script>
<template>
<div class="screen-full" @click="toggle">
<div
class="screen-full w-36px h-48px flex-ac cursor-pointer navbar-bg-hover"
@click="toggle"
>
<FontIcon
:title="
isFullscreen ? t('buttons.hsexitfullscreen') : t('buttons.hsfullscreen')
@ -16,13 +19,3 @@ const { isFullscreen, toggle } = useFullscreen();
/>
</div>
</template>
<style lang="scss" scoped>
.screen-full {
width: 36px;
height: 48px;
display: flex;
align-items: center;
justify-content: space-around;
}
</style>

View File

@ -1,5 +1,5 @@
<template>
<div class="search-footer">
<div class="search-footer color-[#333] dark:color-white">
<span class="search-footer-item">
<enterOutlined class="icon" />
确认
@ -23,7 +23,6 @@ import mdiKeyboardEsc from "/@/assets/svg/mdi_keyboard_esc.svg?component";
<style lang="scss" scoped>
.search-footer {
display: flex;
color: #333;
.search-footer-item {
display: flex;

View File

@ -1,24 +1,3 @@
<template>
<div class="result">
<template v-for="item in options" :key="item.path">
<div
class="result-item"
:style="{
background:
item?.path === active ? useEpThemeStoreHook().epThemeColor : '',
color: item.path === active ? '#fff' : ''
}"
@click="handleTo"
@mouseenter="handleMouse(item)"
>
<component :is="useRenderIcon(item.meta?.icon ?? 'bookmark-2-line')" />
<span class="result-item-title">{{ t(item.meta?.title) }}</span>
<enterOutlined />
</div>
</template>
</div>
</template>
<script lang="ts" setup>
import { computed } from "vue";
import { useI18n } from "vue-i18n";
@ -49,6 +28,17 @@ interface Emits {
const props = withDefaults(defineProps<Props>(), {});
const emit = defineEmits<Emits>();
const itemStyle = computed(() => {
return item => {
return {
background:
item?.path === active.value ? useEpThemeStoreHook().epThemeColor : "",
color: item.path === active.value ? "#fff" : "",
fontSize: item.path === active.value ? "16px" : "14px"
};
};
});
const active = computed({
get() {
return props.value;
@ -67,6 +57,24 @@ function handleTo() {
emit("enter");
}
</script>
<template>
<div class="result">
<template v-for="item in options" :key="item.path">
<div
class="result-item dark:bg-[#1d1d1d]"
:style="itemStyle(item)"
@click="handleTo"
@mouseenter="handleMouse(item)"
>
<component :is="useRenderIcon(item.meta?.icon ?? 'bookmark-2-line')" />
<span class="result-item-title">{{ t(item.meta?.title) }}</span>
<enterOutlined />
</div>
</template>
</div>
</template>
<style lang="scss" scoped>
.result {
padding-bottom: 12px;
@ -78,8 +86,9 @@ function handleTo() {
margin-top: 8px;
padding: 14px;
border-radius: 4px;
background: #e5e7eb;
cursor: pointer;
border: 0.1px solid #ccc;
transition: all 0.3s;
&-title {
display: flex;

View File

@ -8,23 +8,11 @@ function handleSearch() {
</script>
<template>
<div class="search-container" @click="handleSearch">
<div
class="search-container w-40px h-48px flex-c cursor-pointer navbar-bg-hover"
@click="handleSearch"
>
<IconifyIconOffline icon="search" />
</div>
<SearchModal v-model:value="show" />
</template>
<style lang="scss" scoped>
.search-container {
display: flex;
align-items: center;
justify-content: center;
height: 48px;
width: 40px;
cursor: pointer;
&:hover {
background: #f6f6f6;
}
}
</style>

View File

@ -1,9 +1,9 @@
<script setup lang="ts">
import {
reactive,
ref,
unref,
watch,
reactive,
computed,
nextTick,
useCssModule,
@ -15,21 +15,30 @@ import { useRouter } from "vue-router";
import panel from "../panel/index.vue";
import { emitter } from "/@/utils/mitt";
import { templateRef } from "@vueuse/core";
import { TinyColor } from "@ctrl/tinycolor";
import { themeColorsType } from "../../types";
import { routerArrays } from "/@/layout/types";
import type { StorageConfigs } from "/#/index";
import { useAppStoreHook } from "/@/store/modules/app";
import { shadeBgColor } from "../../theme/element-plus";
import { useEpThemeStoreHook } from "/@/store/modules/epTheme";
import { toggleTheme } from "@pureadmin/theme/dist/browser-utils";
import { useMultiTagsStoreHook } from "/@/store/modules/multiTags";
import { createNewStyle, writeNewStyle } from "../../theme/element-plus";
import { debounce, storageLocal, storageSession } from "@pureadmin/utils";
import {
useDark,
debounce,
storageLocal,
storageSession
} from "@pureadmin/utils";
import {
darken,
lighten,
toggleTheme
} from "@pureadmin/theme/dist/browser-utils";
import dayIcon from "/@/assets/svg/day.svg?component";
import darkIcon from "/@/assets/svg/dark.svg?component";
const router = useRouter();
const { isDark } = useDark();
const { isSelect } = useCssModule();
const body = document.documentElement as HTMLElement;
const instance =
@ -39,29 +48,29 @@ const instanceConfig =
getCurrentInstance().appContext.app.config.globalProperties.$config;
let themeColors = ref<Array<themeColorsType>>([
//
/* 道奇蓝(默认) */
{ color: "#1b2a47", themeColor: "default" },
//
/* 亮白色 */
{ color: "#ffffff", themeColor: "light" },
//
/* 猩红色 */
{ color: "#f5222d", themeColor: "dusk" },
//
/* 橙红色 */
{ color: "#fa541c", themeColor: "volcano" },
//
/* 金色 */
{ color: "#fadb14", themeColor: "yellow" },
// 绿
/* 绿宝石 */
{ color: "#13c2c2", themeColor: "mingQing" },
// 绿
/* 酸橙绿 */
{ color: "#52c41a", themeColor: "auroraGreen" },
//
/* 深粉色 */
{ color: "#eb2f96", themeColor: "pink" },
//
/* 深紫罗兰色 */
{ color: "#722ed1", themeColor: "saucePurple" }
]);
const mixRef = templateRef<HTMLElement | null>("mixRef", null);
const verticalRef = templateRef<HTMLElement | null>("verticalRef", null);
const horizontalRef = templateRef<HTMLElement | null>("horizontalRef", null);
const mixRef = templateRef<HTMLElement | null>("mixRef", null);
let layoutTheme =
ref(storageLocal.getItem<StorageConfigs>("responsive-layout")) ||
@ -70,7 +79,7 @@ let layoutTheme =
theme: instanceConfig?.Theme ?? "default"
});
// bodylayoutsrc/style/sidebar.scss
/* body添加layout属性作用于src/style/sidebar.scss */
if (unref(layoutTheme)) {
let layout = unref(layoutTheme).layout;
let theme = unref(layoutTheme).theme;
@ -80,13 +89,11 @@ if (unref(layoutTheme)) {
setLayoutModel(layout);
}
//
/** 默认灵动模式 */
const markValue = ref(instance.configure?.showModel ?? "smart");
const logoVal = ref(instance.configure?.showLogo ?? true);
const epThemeColor = ref(useEpThemeStoreHook().getEpThemeColor);
const settings = reactive({
greyVal: instance.configure.grey,
weakVal: instance.configure.weak,
@ -102,6 +109,13 @@ const getThemeColorStyle = computed(() => {
};
});
/** 当网页为暗黑模式时不显示亮白色切换选项 */
const showThemeColors = computed(() => {
return themeColor => {
return themeColor === "light" && isDark.value ? false : true;
};
});
function storageConfigureChange<T>(key: string, val: T): void {
const storageConfigure = instance.configure;
storageConfigure[key] = val;
@ -115,13 +129,13 @@ function toggleClass(flag: boolean, clsName: string, target?: HTMLElement) {
targetEl.className = flag ? `${className} ${clsName} ` : className;
}
//
/** 灰色模式设置 */
const greyChange = (value): void => {
toggleClass(settings.greyVal, "html-grey", document.querySelector("html"));
storageConfigureChange("grey", value);
};
//
/** 色弱模式设置 */
const weekChange = (value): void => {
toggleClass(
settings.weakVal,
@ -143,7 +157,7 @@ const multiTagsCacheChange = () => {
useMultiTagsStoreHook().multiTagsCacheChange(multiTagsCache);
};
//
/** 清空缓存并返回登录页 */
function onReset() {
router.push("/login");
const { Grey, Weak, MultiTagsCache, EpThemeColor, Layout } = getConfig();
@ -162,7 +176,7 @@ function onChange(label) {
emitter.emit("tagViewsShowModel", label);
}
// Logo
/** 侧边栏Logo */
function logoChange() {
unref(logoVal)
? storageConfigureChange("showLogo", true)
@ -177,7 +191,7 @@ function setFalse(Doms): any {
}
watch(instance, ({ layout }) => {
// wangeditorV5
/* 设置wangeditorV5主题色 */
body.style.setProperty("--w-e-toolbar-active-color", layout["epThemeColor"]);
switch (layout["layout"]) {
case "vertical":
@ -198,7 +212,7 @@ watch(instance, ({ layout }) => {
}
});
//
/** 主题色 激活选择项 */
const getThemeColor = computed(() => {
return current => {
if (
@ -217,7 +231,7 @@ const getThemeColor = computed(() => {
};
});
//
/** 设置导航模式 */
function setLayoutModel(layout: string) {
layoutTheme.value.layout = layout;
window.document.body.setAttribute("layout", layout);
@ -231,12 +245,8 @@ function setLayoutModel(layout: string) {
useAppStoreHook().setLayout(layout);
}
//
let tempLayoutThemeColor;
//
/** 设置导航主题色 */
function setLayoutThemeColor(theme: string) {
tempLayoutThemeColor = instance.layout.theme;
layoutTheme.value.theme = theme;
toggleTheme({
scopeName: `layout-theme-${theme}`
@ -257,43 +267,60 @@ function setLayoutThemeColor(theme: string) {
}
}
// ep
/**
* @description 自动计算hover和active颜色
* @see {@link https://element-plus.org/zh-CN/component/button.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E9%A2%9C%E8%89%B2}
*/
const shadeBgColor = (color: string): string => {
return new TinyColor(color).shade(10).toString();
};
/** 设置ep主题色 */
const setEpThemeColor = (color: string) => {
// @ts-expect-error
writeNewStyle(createNewStyle(color));
useEpThemeStoreHook().setEpThemeColor(color);
body.style.setProperty("--el-color-primary-active", shadeBgColor(color));
document.documentElement.style.setProperty("--el-color-primary", color);
for (let i = 1; i <= 9; i++) {
document.documentElement.style.setProperty(
`--el-color-primary-light-${i}`,
lighten(color, i / 10)
);
}
for (let i = 1; i <= 2; i++) {
document.documentElement.style.setProperty(
`--el-color-primary-dark-${i}`,
darken(color, i / 10)
);
}
};
let dataTheme = ref<boolean>(instance.layout.darkMode);
//
/** 日间、夜间主题切换 */
function dataThemeChange() {
if (dataTheme.value) {
body.setAttribute("data-theme", "dark");
setLayoutThemeColor("light");
/* 如果当前是light夜间主题默认切换到default主题 */
if (useEpThemeStoreHook().epTheme === "light" && dataTheme.value) {
setLayoutThemeColor("default");
} else {
body.setAttribute("data-theme", "");
tempLayoutThemeColor && setLayoutThemeColor(tempLayoutThemeColor);
instance.layout = {
layout: useAppStoreHook().layout,
theme: instance.layout.theme,
darkMode: dataTheme.value,
sidebarStatus: instance.layout.sidebarStatus,
epThemeColor: instance.layout.epThemeColor
};
setLayoutThemeColor(useEpThemeStoreHook().epTheme);
}
if (dataTheme.value) {
instance.layout.darkMode = true;
document.documentElement.classList.add("dark");
} else {
instance.layout.darkMode = false;
document.documentElement.classList.remove("dark");
}
}
//
/* 初始化项目配置 */
nextTick(() => {
settings.greyVal &&
document.querySelector("html")?.setAttribute("class", "html-grey");
settings.weakVal &&
document.querySelector("html")?.setAttribute("class", "html-weakness");
settings.tabsVal && tagsChange();
// @ts-expect-error
writeNewStyle(createNewStyle(epThemeColor.value));
dataThemeChange();
});
</script>
@ -346,11 +373,12 @@ nextTick(() => {
</el-tooltip>
</ul>
<el-divider v-show="!dataTheme">主题色</el-divider>
<ul class="theme-color" v-show="!dataTheme">
<el-divider>主题色</el-divider>
<ul class="theme-color">
<li
v-for="(item, index) in themeColors"
:key="index"
v-show="showThemeColors(item.themeColor)"
:style="getThemeColorStyle(item.color)"
@click="setLayoutThemeColor(item.themeColor)"
>
@ -366,7 +394,7 @@ nextTick(() => {
<el-divider>界面显示</el-divider>
<ul class="setting">
<li v-show="!dataTheme">
<li>
<span>灰色模式</span>
<el-switch
v-model="settings.greyVal"
@ -377,7 +405,7 @@ nextTick(() => {
@change="greyChange"
/>
</li>
<li v-show="!dataTheme">
<li>
<span>色弱模式</span>
<el-switch
v-model="settings.weakVal"

View File

@ -98,7 +98,7 @@ const handleLink = (item: RouteLocationMatched): any => {
</script>
<template>
<el-breadcrumb class="app-breadcrumb" separator="/">
<el-breadcrumb class="app-breadcrumb select-none" separator="/">
<transition-group appear name="breadcrumb">
<el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
<span

View File

@ -1,15 +1,14 @@
<script setup lang="ts">
import { ref } from "vue";
import { useEpThemeStoreHook } from "/@/store/modules/epTheme";
export interface Props {
import { useDark } from "@pureadmin/utils";
interface Props {
isActive: boolean;
}
const props = withDefaults(defineProps<Props>(), {
isActive: false
});
const fillColor = ref<string>("");
const { isDark } = useDark();
const emit = defineEmits<{
(e: "toggleClick"): void;
@ -21,43 +20,28 @@ const toggleClick = () => {
</script>
<template>
<div
:class="classes.container"
:title="props.isActive ? '点击折叠' : '点击展开'"
@click="toggleClick"
@mouseenter="fillColor = useEpThemeStoreHook().epThemeColor"
@mouseleave="fillColor = ''"
>
<svg
:fill="fillColor"
:class="['hamburger', props.isActive ? 'is-active' : '']"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
width="64"
height="64"
<div class="hamburger-container">
<el-tooltip
placement="right"
:effect="isDark ? 'dark' : 'light'"
:content="props.isActive ? '点击折叠' : '点击展开'"
>
<path
d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z"
<IconifyIconOffline
:icon="props.isActive ? 'menu-fold' : 'menu-unfold'"
class="cursor-pointer inline-block align-middle color-primary hover:color-primary !dark:hover:color-white w-16px h-16px ml-4 mb-1"
@click="toggleClick"
/>
</svg>
</el-tooltip>
</div>
</template>
<style module="classes" scoped>
.container {
padding: 0 15px;
}
</style>
<style scoped>
.hamburger {
display: inline-block;
vertical-align: middle;
width: 20px;
height: 20px;
}
.is-active {
transform: rotate(180deg);
<style lang="scss" scoped>
.hamburger-container {
position: absolute;
bottom: 0;
width: 210px;
height: 40px;
line-height: 40px;
box-shadow: 0 0 6px -2px var(--el-color-primary);
}
</style>

View File

@ -32,6 +32,7 @@ const {
username,
avatarsStyle,
getDropdownItemStyle,
getDropdownItemClass,
changeWangeditorLanguage
} = useNav();
@ -78,11 +79,11 @@ function translationEn() {
<h4>{{ title }}</h4>
</div>
<el-menu
ref="menu"
class="horizontal-header-menu"
mode="horizontal"
:default-active="route.path"
router
ref="menu"
mode="horizontal"
class="horizontal-header-menu"
:default-active="route.path"
@select="indexPath => menuSelect(indexPath, routers)"
>
<sidebar-item
@ -101,11 +102,14 @@ function translationEn() {
<screenfull id="header-screenfull" v-show="!deviceDetection()" />
<!-- 国际化 -->
<el-dropdown id="header-translation" trigger="click">
<globalization />
<globalization
class="navbar-bg-hover w-40px h-48px p-11px cursor-pointer outline-none"
/>
<template #dropdown>
<el-dropdown-menu class="translation">
<el-dropdown-item
:style="getDropdownItemStyle(locale, 'zh')"
:class="['!dark:color-white', getDropdownItemClass(locale, 'zh')]"
@click="translationCh"
>
<span class="check-zh" v-show="locale === 'zh'">
@ -115,6 +119,7 @@ function translationEn() {
</el-dropdown-item>
<el-dropdown-item
:style="getDropdownItemStyle(locale, 'en')"
:class="['!dark:color-white', getDropdownItemClass(locale, 'en')]"
@click="translationEn"
>
<span class="check-en" v-show="locale === 'en'">
@ -127,9 +132,9 @@ function translationEn() {
</el-dropdown>
<!-- 退出登录 -->
<el-dropdown trigger="click">
<span class="el-dropdown-link">
<span class="el-dropdown-link navbar-bg-hover">
<img v-if="avatars" :src="avatars" :style="avatarsStyle" />
<p v-if="username">{{ username }}</p>
<p v-if="username" class="dark:color-white">{{ username }}</p>
</span>
<template #dropdown>
<el-dropdown-menu class="logout">
@ -144,7 +149,7 @@ function translationEn() {
</template>
</el-dropdown>
<span
class="el-icon-setting"
class="el-icon-setting navbar-bg-hover"
:title="t('buttons.hssystemSet')"
@click="onPanel"
>

View File

@ -10,11 +10,17 @@ import screenfull from "../screenfull/index.vue";
import { useRoute, useRouter } from "vue-router";
import { deviceDetection } from "@pureadmin/utils";
import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
import { useEpThemeStoreHook } from "/@/store/modules/epTheme";
import { getParentPaths, findRouteByPath } from "/@/router/utils";
import { usePermissionStoreHook } from "/@/store/modules/permission";
import globalization from "/@/assets/svg/globalization.svg?component";
import { ref, watch, nextTick, onMounted, getCurrentInstance } from "vue";
import {
ref,
toRaw,
watch,
nextTick,
onMounted,
getCurrentInstance
} from "vue";
const route = useRoute();
const { locale, t } = useI18n();
@ -27,14 +33,13 @@ const {
logout,
onPanel,
changeTitle,
toggleSideBar,
handleResize,
menuSelect,
resolvePath,
pureApp,
username,
avatarsStyle,
getDropdownItemStyle,
getDropdownItemClass,
changeWangeditorLanguage
} = useNav();
@ -89,33 +94,12 @@ function translationEn() {
<template>
<div class="horizontal-header">
<div
:class="classes.container"
:title="pureApp.sidebar.opened ? '点击折叠' : '点击展开'"
@click="toggleSideBar"
>
<svg
:fill="useEpThemeStoreHook().fill"
:class="[
'hamburger',
pureApp.sidebar.opened ? 'is-active-hamburger' : ''
]"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
width="64"
height="64"
>
<path
d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z"
/>
</svg>
</div>
<el-menu
ref="menu"
class="horizontal-header-menu"
mode="horizontal"
:default-active="defaultActive"
router
ref="menu"
mode="horizontal"
class="horizontal-header-menu"
:default-active="defaultActive"
@select="indexPath => menuSelect(indexPath, routers)"
>
<el-menu-item
@ -124,10 +108,15 @@ function translationEn() {
:index="resolvePath(route) || route.redirect"
>
<template #title>
<div v-show="route.meta.icon" :class="['el-icon', route.meta.icon]">
<component :is="useRenderIcon(route.meta && route.meta.icon)" />
<div
v-if="toRaw(route.meta.icon)"
:class="['sub-menu-icon', route.meta.icon]"
>
<component
:is="useRenderIcon(route.meta && toRaw(route.meta.icon))"
/>
</div>
<span>{{ transformI18n(route.meta.title) }}</span>
<span class="select-none">{{ transformI18n(route.meta.title) }}</span>
<FontIcon
v-if="route.meta.extraIcon"
width="30px"
@ -148,11 +137,14 @@ function translationEn() {
<screenfull id="header-screenfull" v-show="!deviceDetection()" />
<!-- 国际化 -->
<el-dropdown id="header-translation" trigger="click">
<globalization />
<globalization
class="navbar-bg-hover w-40px h-48px p-11px cursor-pointer outline-none"
/>
<template #dropdown>
<el-dropdown-menu class="translation">
<el-dropdown-item
:style="getDropdownItemStyle(locale, 'zh')"
:class="['!dark:color-white', getDropdownItemClass(locale, 'zh')]"
@click="translationCh"
>
<span class="check-zh" v-show="locale === 'zh'">
@ -162,6 +154,7 @@ function translationEn() {
</el-dropdown-item>
<el-dropdown-item
:style="getDropdownItemStyle(locale, 'en')"
:class="['!dark:color-white', getDropdownItemClass(locale, 'en')]"
@click="translationEn"
>
<span class="check-en" v-show="locale === 'en'">
@ -174,9 +167,9 @@ function translationEn() {
</el-dropdown>
<!-- 退出登录 -->
<el-dropdown trigger="click">
<span class="el-dropdown-link">
<span class="el-dropdown-link navbar-bg-hover">
<img v-if="avatars" :src="avatars" :style="avatarsStyle" />
<p v-if="username">{{ username }}</p>
<p v-if="username" class="dark:color-white">{{ username }}</p>
</span>
<template #dropdown>
<el-dropdown-menu class="logout">
@ -191,7 +184,7 @@ function translationEn() {
</template>
</el-dropdown>
<span
class="el-icon-setting"
class="el-icon-setting navbar-bg-hover"
:title="t('buttons.hssystemSet')"
@click="onPanel"
>
@ -201,26 +194,7 @@ function translationEn() {
</div>
</template>
<style module="classes" scoped>
.container {
padding: 0 15px;
}
</style>
<style lang="scss" scoped>
.hamburger {
width: 20px;
height: 20px;
&:hover {
cursor: pointer;
}
}
.is-active-hamburger {
transform: rotate(180deg);
}
.translation {
::v-deep(.el-dropdown-menu__item) {
padding: 5px 40px;

View File

@ -5,7 +5,7 @@ import { childrenType } from "../../types";
import { transformI18n } from "/@/plugins/i18n";
import { useAppStoreHook } from "/@/store/modules/app";
import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
import { ref, PropType, nextTick, computed, CSSProperties } from "vue";
import { ref, toRaw, PropType, nextTick, computed, CSSProperties } from "vue";
const { pureApp } = useNav();
const menuMode = ["vertical", "mix"].includes(pureApp.layout);
@ -54,9 +54,9 @@ const getDivStyle = computed((): CSSProperties => {
};
});
const getMenuTextStyle = computed((): CSSProperties => {
const getMenuTextStyle = computed(() => {
return {
width: pureApp.sidebar.opened ? "125px" : "",
width: pureApp.sidebar.opened ? "210px" : "",
overflow: "hidden",
textOverflow: "ellipsis",
outline: "none"
@ -65,14 +65,14 @@ const getMenuTextStyle = computed((): CSSProperties => {
const getSubTextStyle = computed((): CSSProperties => {
return {
width: pureApp.sidebar.opened ? "125px" : "",
width: pureApp.sidebar.opened ? "210px" : "",
display: "inline-block",
overflow: "hidden",
textOverflow: "ellipsis"
};
});
const getSpanStyle = computed((): CSSProperties => {
const getSpanStyle = computed(() => {
return {
overflow: "hidden",
textOverflow: "ellipsis"
@ -148,12 +148,12 @@ function resolvePath(routePath) {
:class="{ 'submenu-title-noDropdown': !isNest }"
:style="getNoDropdownStyle"
>
<div class="sub-menu-icon" v-show="props.item.meta.icon">
<div class="sub-menu-icon" v-if="toRaw(props.item.meta.icon)">
<component
:is="
useRenderIcon(
onlyOneChild.meta.icon ||
(props.item.meta && props.item.meta.icon)
toRaw(onlyOneChild.meta.icon) ||
(props.item.meta && toRaw(props.item.meta.icon))
)
"
/>
@ -205,19 +205,14 @@ function resolvePath(routePath) {
</el-menu-item>
</template>
<el-sub-menu
v-else
ref="subMenu"
:index="resolvePath(props.item.path)"
popper-append-to-body
>
<el-sub-menu v-else ref="subMenu" :index="resolvePath(props.item.path)">
<template #title>
<div v-show="props.item.meta.icon" class="sub-menu-icon">
<div v-if="toRaw(props.item.meta.icon)" class="sub-menu-icon">
<component
:is="useRenderIcon(props.item.meta && props.item.meta.icon)"
:is="useRenderIcon(props.item.meta && toRaw(props.item.meta.icon))"
/>
</div>
<span v-if="!menuMode">{{ transformI18n(props.item.meta.title) }}</span>
<span v-if="!menuMode"> {{ transformI18n(props.item.meta.title) }}</span>
<el-tooltip
v-else
placement="top"

View File

@ -1,5 +1,6 @@
<script setup lang="ts">
import Logo from "./logo.vue";
import Hamburger from "./hamBurger.vue";
import { emitter } from "/@/utils/mitt";
import { useNav } from "../../hooks/nav";
import SidebarItem from "./sidebarItem.vue";
@ -16,7 +17,7 @@ const showLogo = ref(
storageLocal.getItem<StorageConfigs>("responsive-configure")?.showLogo ?? true
);
const { pureApp, isCollapse, menuSelect } = useNav();
const { pureApp, isCollapse, menuSelect, toggleSideBar } = useNav();
let subMenuData = ref([]);
@ -62,13 +63,13 @@ watch(
<Logo v-if="showLogo" :collapse="isCollapse" />
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu
:default-active="route.path"
:collapse="isCollapse"
unique-opened
router
:collapse-transition="false"
unique-opened
mode="vertical"
class="outer-most"
:collapse="isCollapse"
:default-active="route.path"
:collapse-transition="false"
@select="indexPath => menuSelect(indexPath, routers)"
>
<sidebar-item
@ -80,5 +81,9 @@ watch(
/>
</el-menu>
</el-scrollbar>
<Hamburger
:is-active="pureApp.sidebar.opened"
@toggleClick="toggleSideBar"
/>
</div>
</template>

View File

@ -43,7 +43,7 @@
font-size: 14px;
display: flex;
align-items: center;
color: var(--el-text-color-regular);
color: var(--el-text-color-primary);
background: #fff;
position: relative;
box-shadow: 0 0 1px #888;
@ -92,7 +92,7 @@
a {
text-decoration: none;
color: #666;
color: var(--el-text-color-primary);
padding: 0 4px;
}
@ -144,7 +144,7 @@
list-style-type: none;
padding: 5px 0;
border-radius: 4px;
color: #000000d9;
color: var(--el-text-color-primary);
font-weight: normal;
font-size: 13px;
white-space: nowrap;
@ -160,7 +160,7 @@
align-items: center;
&:hover {
background: var(--el-color-primary-light-9);
// background: var(--el-color-primary-light-9);
color: var(--el-color-primary);
}
@ -207,7 +207,7 @@
}
.scroll-item.is-active {
background-color: var(--el-color-primary-light-9);
// background-color: var(--el-color-primary-light-9);
position: relative;
color: #fff;
@ -220,7 +220,7 @@
}
a {
color: var(--el-color-primary);
color: var(--el-color-primary) !important;
}
}
@ -228,7 +228,7 @@
.arrow-right {
width: 40px;
height: 38px;
color: #00000073;
color: var(--el-text-color-primary);
position: relative;
svg {

View File

@ -665,7 +665,10 @@ const getContextMenuStyle = computed((): CSSProperties => {
@mouseleave.prevent="onMouseleave(index)"
@click="tagOnClick(item)"
>
<router-link :to="item.path">
<router-link
:to="item.path"
class="!dark:color-text_color_primary !dark:hover:color-primary"
>
{{ transformI18n(item.meta.title) }}
</router-link>
<span
@ -729,7 +732,7 @@ const getContextMenuStyle = computed((): CSSProperties => {
placement="bottom-end"
@command="handleCommand"
>
<IconifyIconOffline icon="arrow-down" />
<IconifyIconOffline icon="arrow-down" class="dark:color-white" />
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item

View File

@ -1,13 +1,3 @@
<template>
<div
class="frame"
v-loading="loading"
:element-loading-text="t('status.hsLoad')"
>
<iframe :src="frameSrc" class="frame-iframe" ref="frameRef" />
</div>
</template>
<script lang="ts" setup>
import { useI18n } from "vue-i18n";
import { useRoute } from "vue-router";
@ -54,6 +44,16 @@ onMounted(() => {
});
</script>
<template>
<div
class="frame"
v-loading="loading"
:element-loading-text="t('status.hsLoad')"
>
<iframe :src="frameSrc" class="frame-iframe" ref="frameRef" />
</div>
</template>
<style lang="scss" scoped>
.frame {
height: calc(100vh - 88px);

View File

@ -30,6 +30,11 @@ export function useNav() {
};
};
});
const getDropdownItemClass = computed(() => {
return (locale, t) => {
return locale === t ? "" : "!dark:hover:color-primary";
};
});
const avatarsStyle = computed(() => {
return username ? { marginRight: "10px" } : "";
@ -137,6 +142,7 @@ export function useNav() {
username,
avatarsStyle,
getDropdownItemStyle,
getDropdownItemClass,
changeWangeditorLanguage
};
}

View File

@ -11,8 +11,8 @@ import { setType } from "./types";
import { useI18n } from "vue-i18n";
import { routerArrays } from "./types";
import { emitter } from "/@/utils/mitt";
import { deviceDetection } from "@pureadmin/utils";
import { useAppStoreHook } from "/@/store/modules/app";
import { deviceDetection, useDark } from "@pureadmin/utils";
import { useMultiTagsStore } from "/@/store/modules/multiTags";
import { useSettingStoreHook } from "/@/store/modules/settings";
@ -27,6 +27,7 @@ import setting from "./components/setting/index.vue";
import Vertical from "./components/sidebar/vertical.vue";
import Horizontal from "./components/sidebar/horizontal.vue";
const { isDark } = useDark();
const isMobile = deviceDetection();
const pureSetting = useSettingStoreHook();
const instance = getCurrentInstance().appContext.app.config.globalProperties;
@ -165,7 +166,9 @@ const layoutHeader = defineComponent({
class: { "fixed-header": set.fixedHeader },
style: [
set.hideTabs && layout.value.includes("horizontal")
? "box-shadow: 0 1px 4px rgb(0 21 41 / 8%);"
? isDark.value
? "box-shadow: 0 1px 4px #0d0d0d"
: "box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08)"
: ""
]
},
@ -185,10 +188,14 @@ const layoutHeader = defineComponent({
default: () => [
h(
"span",
{ onClick: onFullScreen },
{
onClick: onFullScreen
},
{
default: () => [
!pureSetting.hiddenSideBar ? h(fullScreen) : h(exitScreen)
!pureSetting.hiddenSideBar
? h(fullScreen, { class: "dark:color-white" })
: h(exitScreen, { class: "dark:color-white" })
]
}
)

View File

@ -1,84 +0,0 @@
/* 动态改变element-plus主题色 */
import rgbHex from "rgb-hex";
import epCss from "./element.scss";
import { TinyColor } from "@ctrl/tinycolor";
import { convert } from "css-color-function";
// 色值表
const formula = {
"shade-1": "color(primary shade(10%))",
"light-1": "color(primary tint(10%))",
"light-2": "color(primary tint(20%))",
"light-3": "color(primary tint(30%))",
"light-4": "color(primary tint(40%))",
"light-5": "color(primary tint(50%))",
"light-6": "color(primary tint(60%))",
"light-7": "color(primary tint(70%))",
"light-8": "color(primary tint(80%))",
"light-9": "color(primary tint(90%))"
};
// 把生成的样式表写入到style中
export const writeNewStyle = (newStyle: string): void => {
const style = window.document.createElement("style");
style.innerText = newStyle;
window.document.head.appendChild(style);
};
// 根据主题色,生成最新的样式表
export const createNewStyle = (
primaryStyle: Record<string, any>
): Record<string, any> => {
// 根据主色生成色值表
const colors = createColors(primaryStyle);
// 在当前ep的默认样式表中标记需要替换的色值
let cssText = getStyleTemplate(epCss);
// 遍历生成的色值表,在 默认样式表 进行全局替换
Object.keys(colors).forEach(key => {
cssText = cssText.replace(
new RegExp("(:|\\s+)" + key, "g"),
"$1" + colors[key]
);
});
return cssText;
};
export const createColors = (
primary: Record<string, any>
): Record<string, any> => {
if (!primary) return;
const colors = {
primary
};
Object.keys(formula).forEach(key => {
const value = formula[key].replace(/primary/, primary);
colors[key] = "#" + rgbHex(convert(value));
});
return colors;
};
const getStyleTemplate = (data: Record<string, any>): Record<string, any> => {
const colorMap = {
"#3a8ee6": "shade-1",
"#409eff": "primary",
"#53a8ff": "light-1",
"#66b1ff": "light-2",
"#79bbff": "light-3",
"#8cc5ff": "light-4",
"#a0cfff": "light-5",
"#b3d8ff": "light-6",
"#c6e2ff": "light-7",
"#d9ecff": "light-8",
"#ecf5ff": "light-9"
};
Object.keys(colorMap).forEach(key => {
const value = colorMap[key];
data = data.replace(new RegExp(key, "ig"), value);
});
return data;
};
// 自动计算hover和active颜色https://element-plus.org/zh-CN/component/button.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E9%A2%9C%E8%89%B2
export const shadeBgColor = (color: string): string => {
return new TinyColor(color).shade(10).toString();
};

View File

@ -1,2 +0,0 @@
/* 通过scss模块本地导入element-plus的全局样式文件解决vite2.7.13版本后使用 import epCss from "element-plus/dist/index.css",打包后加载不到样式的问题 */
@import "element-plus/dist/index.css";

View File

@ -1,7 +1,17 @@
/**
* @description 使
*/
import { EpThemeColor } from "../../../public/serverConfig.json";
// 将vxe默认主题色和ep默认主题色保持一致
type MultipleScopeVarsItem = {
scopeName: string;
varsContent: string;
};
/** 将vxe默认主题色和ep默认主题色保持一致 */
const vxeColor = EpThemeColor;
/** 预设主题色 */
const themeColors = {
default: {
vxeColor,
@ -122,12 +132,10 @@ const themeColors = {
}
};
type MultipleScopeVarsItem = {
scopeName: string;
varsContent: string;
};
export function genScssMultipleScopeVars(): MultipleScopeVarsItem[] {
/**
* @description
*/
export const genScssMultipleScopeVars = (): MultipleScopeVarsItem[] => {
const result = [] as MultipleScopeVarsItem[];
Object.keys(themeColors).forEach(key => {
result.push({
@ -148,4 +156,4 @@ export function genScssMultipleScopeVars(): MultipleScopeVarsItem[] {
} as MultipleScopeVarsItem);
});
return result;
}
};

View File

@ -23,6 +23,7 @@ import "./style/index.scss";
import "element-plus/dist/index.css";
import "@pureadmin/components/dist/index.css";
import "@pureadmin/components/dist/theme.css";
import "@pureadmin/components/dist/dark.scss";
// 导入字体图标
import "./assets/iconfont/iconfont.js";
import "./assets/iconfont/iconfont.css";

View File

@ -48,14 +48,11 @@ export const useAppStore = defineStore({
}
storageLocal.setItem("responsive-layout", layout);
},
TOGGLE_DEVICE(device: string) {
this.device = device;
},
async toggleSideBar(opened?: boolean, resize?: string) {
await this.TOGGLE_SIDEBAR(opened, resize);
},
toggleDevice(device) {
this.TOGGLE_DEVICE(device);
toggleDevice(device: string) {
this.device = device;
},
setLayout(layout) {
this.layout = layout;

View File

@ -1,29 +1,188 @@
/* 暗黑模式 */
[data-theme="dark"] {
filter: invert(0.9) hue-rotate(180deg);
@import "element-plus/theme-chalk/src/dark/css-vars.scss";
#mse,
img,
.icon-svg,
.login-container {
filter: invert(1) hue-rotate(180deg);
/* 暗黑模式适配 */
html.dark {
/* 自定义深色背景颜色 */
// --el-bg-color: #020409;
$border-style: #303030;
$color-white: #fff;
.navbar,
.tags-view,
.contextmenu,
.sidebar-container,
.horizontal-header,
.sidebar-logo-container,
.horizontal-header .el-sub-menu__title,
.horizontal-header .submenu-title-noDropdown {
background: var(--el-bg-color) !important;
}
// element plus
.el-radio-button__original-radio:checked + .el-radio-button__inner,
.el-image-viewer__close,
.el-image-viewer__actions__inner,
.el-image-viewer__next,
.el-image-viewer__prev {
color: #000 !important;
.app-main {
background: #020409 !important;
}
.el-overlay {
background-color: rgb(0 0 0 / 5%) !important;
.frame,
.logic-flow-view,
.wangeditor {
filter: invert(0.9) hue-rotate(180deg);
}
.el-drawer {
box-shadow: 0 8px 10px -5px rgb(0 0 0 / 1%), 0 16px 24px 2px rgb(0 0 0 / 2%),
0 6px 30px 5px rgb(0 0 0 / 1%);
.ant-tabs {
background: var(--el-bg-color);
color: $color-white;
}
/* 标签页 */
.tags-view {
.arrow-left,
.arrow-right {
box-shadow: none;
}
.arrow-right {
border-left: 1px solid $border-style;
}
.arrow-left,
.arrow-right,
.right-button li {
border-right: 1px solid $border-style;
}
}
/* vxe-table */
.vxe-table--header-wrapper,
.vxe-table--body-wrapper {
color: var(--el-text-color-primary);
background: var(--el-bg-color) !important;
}
.vxe-table--render-default.border--full .vxe-header--column,
.vxe-table--render-default.border--full .vxe-body--column,
.vxe-table--render-default.border--full .vxe-footer--column {
background-image: linear-gradient(
var(--el-border-color-lighter),
var(--el-border-color-lighter)
),
linear-gradient(
var(--el-border-color-lighter),
var(--el-border-color-lighter)
);
}
/* 表头 */
.vxe-table--header-wrapper {
background: #262727 !important;
}
.vxe-table--render-wrapper,
.vxe-table--main-wrapper {
border: none;
}
.vxe-pager.is--perfect,
.vxe-table--render-default .vxe-table--border-line {
border: 1px solid var(--el-border-color-lighter);
}
.vxe-table--header-border-line {
border-bottom: 1px solid var(--el-border-color-lighter) !important;
}
.vxe-body--row.row--hover,
.vxe-pager {
background-color: #262727;
}
.vxe-input--inner,
.vxe-pager .vxe-pager--jump-prev,
.vxe-pager .vxe-pager--prev-btn,
.vxe-pager .vxe-pager--next-btn,
.vxe-pager .vxe-pager--jump-next,
.vxe-pager .vxe-pager--num-btn,
.vxe-pager .vxe-pager--jump .vxe-pager--goto {
background-color: transparent;
color: var(--el-text-color-primary);
// outline: none !important;
}
.vxe-select-option--wrapper {
background: var(--el-bg-color) !important;
}
.vxe-select-option:not(.is--disabled).is--hover {
background: var(--el-color-primary-light-6) !important;
}
.vxe-modal--wrapper.type--modal .vxe-modal--box,
.vxe-modal--wrapper.type--alert .vxe-modal--box,
.vxe-modal--wrapper.type--confirm .vxe-modal--box,
.vxe-form {
background: var(--el-bg-color) !important;
}
.vxe-modal--box,
.vxe-modal--header {
border: none;
background: var(--el-bg-color) !important;
}
.vxe-modal--title,
.vxe-button--content {
color: var(--el-text-color-primary);
}
.vxe-button.type--button.size--medium:hover {
background: var(--el-color-primary) !important;
}
/* 项目配置面板 */
.right-panel-items {
.el-divider__text {
--el-bg-color: var(--el-bg-color);
}
.el-divider--horizontal {
border-top: none;
}
}
/* 表单设计器 */
.design-form {
.el-main.config-content,
.el-header,
.el-main.widget-empty,
.widget-form-list,
.el-aside,
.widget-view {
background: var(--el-bg-color) !important;
}
.form-edit-widget-label a {
background: var(--el-color-primary);
border: none;
border-radius: 5px;
color: $color-white;
}
.el-aside {
color: $color-white;
}
}
/* element-plus */
.el-table__cell {
background: var(--el-bg-color);
}
.el-card {
--el-card-bg-color: var(--el-bg-color);
// border: none !important;
}
.el-backtop {
--el-backtop-bg-color: var(--el-color-primary-light-9);
--el-backtop-hover-bg-color: var(--el-color-primary);
}
.el-dropdown-menu__item:not(.is-disabled):hover {
background: transparent;
}
}

View File

@ -46,13 +46,6 @@
padding: 0 !important;
}
/* 动态改变cssvar 用于主题切换 https://github.com/element-plus/element-plus/issues/4856#issuecomment-1000174357 */
.el-button--primary,
.el-button--primary.is-plain {
--el-button-active-bg-color: var(--el-color-primary) !important;
--el-button-active-border-color: var(--el-color-primary) !important;
}
/* nprogress适配ep的primary */
#nprogress {
& .bar {

View File

@ -4,6 +4,10 @@
@import "./sidebar.scss";
@import "./dark.scss";
:root {
--pure-transition-duration: 0.016s;
}
body {
width: 100%;
height: 100%;

View File

@ -6,6 +6,12 @@
}
}
@mixin relative {
position: relative;
width: 100%;
height: 100%;
}
@mixin scrollBar {
&::-webkit-scrollbar-track-piece {
background: #d3dce6;
@ -20,9 +26,3 @@
border-radius: 20px;
}
}
@mixin relative {
position: relative;
width: 100%;
height: 100%;
}

View File

@ -16,17 +16,18 @@
.sub-menu-icon {
vertical-align: middle;
margin-right: 5px;
font-size: 18px;
display: inline-flex;
justify-content: center;
align-items: center;
margin-right: 5px;
}
.main-container {
height: 100vh;
min-height: 100%;
transition: margin-left 0.1s;
/* main-content属性动画 */
transition: margin-left var(--pure-transition-duration);
margin-left: $sideBarWidth;
position: relative;
background: #f0f2f5;
@ -43,7 +44,8 @@
right: 0;
z-index: 998;
width: calc(100% - 210px);
transition: width 0.1s;
/* fixed-header属性左上角动画 */
transition: width var(--pure-transition-duration);
}
.main-hidden {
@ -63,7 +65,8 @@
}
.sidebar-container {
transition: width 0.1s;
/* 展开动画 */
transition: width var(--pure-transition-duration);
width: $sideBarWidth !important;
background: $menuBg;
height: 100%;
@ -80,22 +83,18 @@
overflow-x: hidden !important;
}
.horizontal-collapse-transition {
transition: 0s width ease-in-out, 0s padding-left ease-in-out,
0s padding-right ease-in-out;
}
.el-scrollbar__bar.is-vertical {
right: 0;
}
.el-scrollbar {
height: 100%;
height: calc(100% - 44px);
}
&.has-logo {
.el-scrollbar {
height: calc(100% - 50px);
/* logo: 48px、Hamburger: 40px、Hamburger-shadow: 4px */
height: calc(100% - 92px);
}
}
@ -189,7 +188,7 @@
align-items: center;
padding-left: 10px;
cursor: pointer;
transition: all 0.2s ease;
transition: all 0.125s ease;
i {
font-size: 30px;
@ -219,54 +218,46 @@
color: $subMenuActiveText;
justify-content: flex-end;
/* 搜索 */
.search-container,
/* 告警 */
.dropdown-badge,
/* 全屏 */
.screen-full,
/* 国际化 */
.globalization,
/* 登陆名 */
.el-dropdown-link,
/* 设置 */
.el-icon-setting {
&:hover {
background: $menuHover;
}
}
.dropdown-badge {
height: 48px;
color: $subMenuActiveText;
&:hover {
background: $menuHover;
}
}
.search-container {
&:hover {
background: $menuHover;
}
}
.screen-full {
cursor: pointer;
&:hover {
background: $menuHover;
}
}
.globalization {
height: 48px;
width: 40px;
height: 48px;
padding: 11px;
outline: none;
cursor: pointer;
color: $subMenuActiveText;
&:hover {
background: $menuHover;
}
}
.el-dropdown-link {
height: 48px;
padding: 10px;
display: flex;
cursor: pointer;
align-items: center;
justify-content: space-around;
cursor: pointer;
color: $subMenuActiveText;
&:hover {
background: $menuHover;
}
p {
font-size: 14px;
}
@ -285,18 +276,14 @@
display: flex;
cursor: pointer;
align-items: center;
&:hover {
background: $menuHover;
}
}
}
.el-menu {
border: none;
height: 100%;
background-color: transparent;
width: 100% !important;
background-color: transparent;
}
.el-menu-item,
@ -322,7 +309,6 @@
.is-active > .el-sub-menu__title,
.is-active.submenu-title-noDropdown {
color: $subMenuActiveText !important;
border-bottom-color: #409eff;
i {
color: $subMenuActiveText !important;
@ -332,7 +318,6 @@
.is-active {
transition: color 0.3s;
color: $subMenuActiveText !important;
border-bottom-color: #409eff;
}
}
@ -344,15 +329,6 @@
.el-menu-item {
span {
font-size: 12px;
margin-left: 10px;
}
}
.el-sub-menu__title {
color: $menuText;
span {
margin-left: 10px;
}
}
}
@ -402,15 +378,19 @@
.el-menu-item,
.el-sub-menu {
i {
width: 20px;
text-align: center;
font-size: 16px;
}
// i {
// width: 20px;
// text-align: center;
// font-size: 16px;
// }
i.fa {
margin-right: 5px;
font-size: 16px;
// i.fa {
// margin-right: 5px;
// font-size: 16px;
// }
.el-menu-tooltip__trigger {
width: 54px;
padding: 18px !important;
}
}
}
@ -431,16 +411,11 @@
span {
font-size: 12px;
margin-left: 10px;
}
}
.el-sub-menu__title {
color: $menuText;
span {
margin-left: 10px;
}
}
}
@ -495,7 +470,9 @@
/* 有子菜单 */
.el-menu--collapse
.is-active.outer-most.el-sub-menu
> .el-sub-menu__title::before {
> .el-sub-menu__title::before,
/* 无子菜单 */
.el-menu--collapse .is-active.submenu-title-noDropdown.outer-most::before {
position: absolute;
top: 0;
left: 2px;
@ -504,20 +481,7 @@
background-color: $menuActiveBefore;
content: "";
clear: both;
transition: all 0.2s ease-in-out;
transform: translateY(0);
}
/* 无子菜单 */
.el-menu--collapse .is-active.submenu-title-noDropdown.outer-most::before {
position: absolute;
top: 0;
width: 2px;
height: 100%;
background-color: $menuActiveBefore;
content: "";
clear: both;
transition: all 0.2s ease-in-out;
transition: all 0.125s ease-in-out;
transform: translateY(0);
}
@ -536,7 +500,7 @@
.mobile {
.fixed-header {
width: 100% !important;
transition: width 0.1s;
transition: width var(--pure-transition-duration);
}
.main-container {
@ -544,7 +508,7 @@
}
.sidebar-container {
transition: transform 0.1s;
transition: transform var(--pure-transition-duration);
width: $sideBarWidth;
}
@ -556,14 +520,6 @@
}
}
}
/* vertical菜单下hideSidebar去除动画 */
.withoutAnimation {
.main-container,
.sidebar-container {
transition: none;
}
}
}
body[layout="vertical"] {
@ -581,10 +537,11 @@ body[layout="vertical"] {
.hideSidebar {
.fixed-header {
width: calc(100% - 54px);
transition: width 0.1s;
transition: width var(--pure-transition-duration);
}
.sidebar-container {
transition: width 0.125s;
width: 54px !important;
.is-active.submenu-title-noDropdown.outer-most {
@ -596,15 +553,6 @@ body[layout="vertical"] {
margin-left: 54px;
}
.submenu-title-noDropdown {
padding: 0 !important;
position: relative;
.el-tooltip {
padding: 0 !important;
}
}
/* 菜单折叠 */
.el-menu--collapse {
.el-sub-menu {
@ -623,20 +571,31 @@ body[layout="vertical"] {
background: transparent !important;
}
/* 有无子菜单 */
.el-sub-menu__title,
.el-menu-item [class^="el-icon"] {
right: 2px;
.el-sub-menu__title {
padding: 0 18px !important;
}
}
.el-menu-tooltip__trigger {
padding: 0 18px;
}
.sub-menu-icon {
margin-right: 0;
}
}
.sub-menu-icon {
width: 24px;
/* 搜索 */
.search-container,
/* 告警 */
.dropdown-badge,
/* 全屏 */
.screen-full,
/* 国际化 */
.globalization,
/* 登陆名 */
.el-dropdown-link,
/* 设置 */
.el-icon-setting {
&:hover {
background: #f6f6f6;
}
}
}
@ -654,6 +613,10 @@ body[layout="mix"] {
$sideBarWidth: 210px;
@include merge-style($sideBarWidth);
.el-menu--collapse {
width: 54px;
}
.el-menu {
--el-menu-hover-bg-color: transparent !important;
}
@ -661,10 +624,11 @@ body[layout="mix"] {
.hideSidebar {
.fixed-header {
width: calc(100% - 54px);
transition: width 0.1s;
transition: width var(--pure-transition-duration);
}
.sidebar-container {
transition: width 0.125s;
width: 54px !important;
.is-active.submenu-title-noDropdown.outer-most {
@ -676,15 +640,6 @@ body[layout="mix"] {
margin-left: 54px;
}
.submenu-title-noDropdown {
padding: 0 !important;
position: relative;
.el-tooltip {
padding: 0 !important;
}
}
/* 菜单折叠 */
.el-menu--collapse {
.el-sub-menu {
@ -698,15 +653,6 @@ body[layout="mix"] {
}
}
}
/* 无子菜单 */
.el-menu-item [class^="el-icon"] {
right: 5px;
}
.el-sub-menu__title [class^="el-icon"] {
right: 2px;
}
}
}
}

View File

@ -40,3 +40,16 @@
.breadcrumb-leave-active {
position: absolute;
}
/**
* @description 重置el-menu的展开收起动画时长
* @see {@link https://github.com/element-plus/element-plus/issues/4509#issuecomment-980165001}
*/
.outer-most .el-collapse-transition-leave-active,
.outer-most .el-collapse-transition-enter-active {
transition: 0.12s all ease-in-out !important;
}
.horizontal-collapse-transition {
transition: var(--pure-transition-duration) all !important;
}

View File

@ -1,4 +1,4 @@
###
### 注
- [文档](https://pure-admin-utils.vercel.app)
- [npm](https://www.npmjs.com/package/@pureadmin/utils)

View File

@ -18,13 +18,12 @@ const url = ref(`${VITE_PUBLIC_PATH}html/button.html`);
<span class="font-medium">通过iframe引入按钮页面</span>
</div>
</template>
<iframe :src="url" frameborder="0" class="iframe" />
<iframe :src="url" frameborder="0" class="iframe w-full h-60vh" />
</el-card>
</template>
<style scoped>
<style lang="scss" scoped>
.iframe {
width: 100%;
height: 60vh;
filter: invert(0.9) hue-rotate(180deg);
}
</style>

View File

@ -34,14 +34,3 @@ defineOptions({
</div>
</el-card>
</template>
<style lang="scss" scoped>
.flex {
display: flex;
}
:deep(.el-card) {
text-align: center;
margin-bottom: 10px;
}
</style>

View File

@ -54,18 +54,20 @@ const handleCreated = editor => {
</span>
</div>
</template>
<Toolbar
style="border-bottom: 1px solid #ccc"
:editor="editorRef"
:defaultConfig="toolbarConfig"
:mode="mode"
/>
<Editor
style="height: 500px; overflow-y: hidden"
v-model="valueHtml"
:defaultConfig="editorConfig"
:mode="mode"
@onCreated="handleCreated"
/>
<div class="wangeditor">
<Toolbar
style="border-bottom: 1px solid #ccc"
:editor="editorRef"
:defaultConfig="toolbarConfig"
:mode="mode"
/>
<Editor
style="height: 500px; overflow-y: hidden"
v-model="valueHtml"
:defaultConfig="editorConfig"
:mode="mode"
@onCreated="handleCreated"
/>
</div>
</el-card>
</template>

View File

@ -20,7 +20,7 @@ onBeforeMount(() => {
</script>
<template>
<ElDesignForm v-loading="loading" style="height: 100vh" />
<ElDesignForm v-loading="loading" style="height: 100vh" class="design-form" />
</template>
<style lang="scss" scoped>

View File

@ -6,17 +6,17 @@ import serviceIcon from "/@/assets/svg/service.svg?component";
import calendarIcon from "/@/assets/svg/calendar.svg?component";
import userAvatarIcon from "/@/assets/svg/user_avatar.svg?component";
export interface CardProductType {
defineOptions({
name: "ReCard"
});
interface CardProductType {
type: number;
isSetup: boolean;
description: string;
name: string;
}
defineOptions({
name: "ReCard"
});
const props = defineProps({
product: {
type: Object as PropType<CardProductType>
@ -46,7 +46,7 @@ const cardLogoClass = computed(() => [
<template>
<div :class="cardClass">
<div class="list-card-item_detail">
<div class="list-card-item_detail !bg-white !dark:bg-dark">
<el-row justify="space-between">
<div :class="cardLogoClass">
<shopIcon v-if="product.type === 1" />
@ -68,7 +68,7 @@ const cardLogoClass = computed(() => [
:disabled="!product.isSetup"
max-height="2"
>
<IconifyIconOffline icon="more-vertical" class="icon-more" />
<IconifyIconOffline icon="more-vertical" class="text-size-24px" />
<template #dropdown>
<el-dropdown-menu :disabled="!product.isSetup">
<el-dropdown-item @click="handleClickManage(product)">
@ -82,15 +82,17 @@ const cardLogoClass = computed(() => [
</el-dropdown>
</div>
</el-row>
<p class="list-card-item_detail--name">{{ product.name }}</p>
<p class="list-card-item_detail--desc">{{ product.description }}</p>
<p class="list-card-item_detail--name color-text_color_primary">
{{ product.name }}
</p>
<p class="list-card-item_detail--desc color-text_color_regular">
{{ product.description }}
</p>
</div>
</div>
</template>
<style scoped lang="scss">
$text-color-disabled: rgba(0, 0, 0, 0.26);
.list-card-item {
display: flex;
flex-direction: column;
@ -98,11 +100,9 @@ $text-color-disabled: rgba(0, 0, 0, 0.26);
border-radius: 3px;
overflow: hidden;
cursor: pointer;
color: rgba(0, 0, 0, 0.6);
&_detail {
flex: 1;
background: #fff;
padding: 24px 32px;
min-height: 140px;
@ -131,16 +131,10 @@ $text-color-disabled: rgba(0, 0, 0, 0.26);
}
}
.icon-more {
font-size: 24px;
color: rgba(36, 36, 36, 1);
}
&--name {
margin: 24px 0 8px 0;
font-size: 16px;
font-weight: 400;
color: rgba(0, 0, 0, 0.9);
}
&--desc {
@ -157,14 +151,9 @@ $text-color-disabled: rgba(0, 0, 0, 0.26);
}
&__disabled {
color: $text-color-disabled;
.icon-more {
color: $text-color-disabled;
}
.list-card-item_detail--name {
color: $text-color-disabled;
.list-card-item_detail--name,
.list-card-item_detail--desc {
color: var(--el-text-color-disabled);
}
.list-card-item_detail--operation--tag {

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import { getCardList } from "/@/api/list";
import Card from "./components/Card.vue";
import { getCardList } from "/@/api/list";
import { ref, onMounted, nextTick } from "vue";
import dialogForm from "./components/DialogForm.vue";
import { ElMessage, ElMessageBox } from "element-plus";

View File

@ -26,8 +26,7 @@ const { columns } = useColumns();
<PureDescriptions
:columns="columns"
title="您提交的内容有如下错误:"
style="background: rgb(250, 250, 250)"
class="p-6 ml-10 mr-10"
class="p-6 ml-10 mr-10 bg-[#fafafa] dark:bg-[#1d1d1d]"
/>
</el-card>
</template>

View File

@ -41,7 +41,7 @@ const columns = [
</div>
</template>
</el-result>
<div style="background: rgb(250, 250, 250)" class="p-6 ml-10 mr-10">
<div class="p-6 ml-10 mr-10 bg-[#fafafa] dark:bg-[#1d1d1d]">
<PureDescriptions title="项目名称" :columns="columns" class="mb-5" />
<el-steps :active="2">
<el-step title="创建项目">

View File

@ -60,7 +60,7 @@ onMounted(() => {
ref="formRef"
:inline="true"
:model="form"
class="bg-white w-99/100 pl-8 pt-4"
class="bg-white dark:bg-dark w-99/100 pl-8 pt-4"
>
<el-form-item label="部门名称:" prop="user">
<el-input v-model="form.user" placeholder="请输入部门名称" clearable />
@ -110,7 +110,10 @@ onMounted(() => {
:data="dataList"
:columns="columns"
:checkList="checkList"
:header-cell-style="{ background: '#fafafa', color: '#606266' }"
:header-cell-style="{
background: 'var(--el-table-row-hover-bg-color)',
color: 'var(--el-text-color-primary)'
}"
@selection-change="handleSelectionChange"
>
<template #operation="{ row }">

View File

@ -82,12 +82,14 @@ const checkboxChangeEvent: VxeTableEvents.CheckboxChange = ({ records }) => {
<div class="config">
<el-drawer
:model-value="drawer"
:title="drawTitle"
:direction="direction"
:before-close="handleClose"
destroy-on-close
size="680px"
>
<template #header>
<span class="color-black dark:color-white">{{ drawTitle }}</span>
</template>
<el-divider />
<!-- 列表 -->
<div class="p-2">
@ -162,10 +164,8 @@ const checkboxChangeEvent: VxeTableEvents.CheckboxChange = ({ records }) => {
margin-bottom: 0;
}
:deep(.el-drawer__header span) {
color: rgba(0, 0, 0, 0.85);
font-weight: 500;
font-size: 16px;
:deep(.el-drawer__body) {
padding: 0;
}
:deep(.el-divider--horizontal) {

View File

@ -222,13 +222,19 @@ function onHide() {
<template>
<div>
<!-- 工具栏 -->
<vxe-toolbar>
<vxe-toolbar class="dark:bg-dark">
<template #buttons>
<vxe-input
v-model="dictData.filterName"
:placeholder="t('buttons.hssearch')"
@keyup="searchEvent"
/>
<div class="ml-20px">
<label>字典名称</label>
<el-input
class="!w-200px"
v-model="dictData.filterName"
:placeholder="t('buttons.hssearch')"
@keyup.prevent="searchEvent"
@input="searchEvent"
clearable
/>
</div>
</template>
<template #tools>
<el-button-group>

View File

@ -77,7 +77,7 @@ onMounted(() => {
ref="formRef"
:inline="true"
:model="form"
class="bg-white w-99/100 pl-8 pt-4"
class="bg-white dark:bg-dark w-99/100 pl-8 pt-4"
>
<el-form-item label="角色名称:" prop="name">
<el-input v-model="form.name" placeholder="请输入角色名称" clearable />
@ -129,7 +129,10 @@ onMounted(() => {
:checkList="checkList"
:pagination="pagination"
:paginationSmall="size === 'small' ? true : false"
:header-cell-style="{ background: '#fafafa', color: '#606266' }"
:header-cell-style="{
background: 'var(--el-table-row-hover-bg-color)',
color: 'var(--el-text-color-primary)'
}"
@selection-change="handleSelectionChange"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"

View File

@ -79,7 +79,7 @@ onMounted(() => {
ref="formRef"
:inline="true"
:model="form"
class="bg-white w-99/100 pl-8 pt-4"
class="bg-white dark:bg-dark w-99/100 pl-8 pt-4"
>
<el-form-item label="用户名称:" prop="username">
<el-input
@ -141,7 +141,10 @@ onMounted(() => {
:checkList="checkList"
:pagination="pagination"
:paginationSmall="size === 'small' ? true : false"
:header-cell-style="{ background: '#fafafa', color: '#606266' }"
:header-cell-style="{
background: 'var(--el-table-row-hover-bg-color)',
color: 'var(--el-text-color-primary)'
}"
@selection-change="handleSelectionChange"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"

View File

@ -70,7 +70,7 @@ onMounted(async () => {
</script>
<template>
<div class="max-w-260px h-full min-h-780px bg-white">
<div class="max-w-260px h-full min-h-780px bg-white dark:bg-dark">
<div class="flex items-center h-34px">
<p class="flex-1 ml-2 font-bold text-base truncate" title="部门列表">
部门列表
@ -101,7 +101,7 @@ onMounted(async () => {
<el-dropdown-menu>
<el-dropdown-item>
<el-button
class="reset-margin !h-20px !text-gray-500"
class="reset-margin !h-20px !text-gray-500 !dark:hover:color-primary"
link
type="primary"
:icon="useRenderIcon('expand')"
@ -112,7 +112,7 @@ onMounted(async () => {
</el-dropdown-item>
<el-dropdown-item>
<el-button
class="reset-margin !h-20px !text-gray-500"
class="reset-margin !h-20px !text-gray-500 !dark:hover:color-primary"
link
type="primary"
:icon="useRenderIcon('unExpand')"
@ -123,7 +123,7 @@ onMounted(async () => {
</el-dropdown-item>
<el-dropdown-item>
<el-button
class="reset-margin !h-20px !text-gray-500"
class="reset-margin !h-20px !text-gray-500 !dark:hover:color-primary"
link
type="primary"
:icon="useRenderIcon('reset')"
@ -159,7 +159,8 @@ onMounted(async () => {
'select-none',
searchValue.trim().length > 0 &&
node.label.includes(searchValue) &&
'text-red-500'
'text-red-500',
highlightMap[node.id]?.highlight ? 'dark:color-primary' : ''
]"
:style="{
background: highlightMap[node.id]?.highlight

View File

@ -1,9 +1,17 @@
<script setup lang="ts">
import { ref, type Ref } from "vue";
import { useECharts } from "@pureadmin/utils";
import { ref, computed, type Ref } from "vue";
import { useDark, useECharts, type EchartOptions } from "@pureadmin/utils";
const { isDark } = useDark();
let theme: EchartOptions["theme"] = computed(() => {
return isDark.value ? "dark" : "light";
});
const barChartRef = ref<HTMLDivElement | null>(null);
const { setOptions } = useECharts(barChartRef as Ref<HTMLDivElement>);
const { setOptions } = useECharts(barChartRef as Ref<HTMLDivElement>, {
theme
});
setOptions(
{

View File

@ -64,7 +64,7 @@ let classOption = reactive({
</script>
<template>
<div class="infinite">
<div class="infinite bg-[#fafafa] dark:bg-dark">
<ul class="top">
<li>更新日期</li>
<li>项目名称</li>
@ -98,7 +98,7 @@ let classOption = reactive({
font-size: 14px;
color: #909399;
font-weight: 400;
background: #fafafa;
// background: #fafafa;
li {
width: 34%;

View File

@ -1,9 +1,17 @@
<script setup lang="ts">
import { ref, type Ref } from "vue";
import { useECharts } from "@pureadmin/utils";
import { ref, computed, type Ref } from "vue";
import { useDark, useECharts, type EchartOptions } from "@pureadmin/utils";
const { isDark } = useDark();
let theme: EchartOptions["theme"] = computed(() => {
return isDark.value ? "dark" : "light";
});
const lineChartRef = ref<HTMLDivElement | null>(null);
const { setOptions } = useECharts(lineChartRef as Ref<HTMLDivElement>);
const { setOptions } = useECharts(lineChartRef as Ref<HTMLDivElement>, {
theme
});
setOptions(
{

View File

@ -1,9 +1,17 @@
<script setup lang="ts">
import { ref, type Ref } from "vue";
import { useECharts } from "@pureadmin/utils";
import { ref, computed, type Ref } from "vue";
import { useDark, useECharts, type EchartOptions } from "@pureadmin/utils";
const { isDark } = useDark();
let theme: EchartOptions["theme"] = computed(() => {
return isDark.value ? "dark" : "light";
});
const pieChartRef = ref<HTMLDivElement | null>(null);
const { setOptions } = useECharts(pieChartRef as Ref<HTMLDivElement>);
const { setOptions } = useECharts(pieChartRef as Ref<HTMLDivElement>, {
theme
});
setOptions(
{

View File

@ -35,7 +35,7 @@ const openDepot = (): void => {
<template>
<div class="welcome">
<el-card class="top-content">
<el-card class="top-content dark:border-none">
<div class="left-mark">
<img :src="avatars" title="直达仓库地址" @click="openDepot" />
<span>{{ greetings }}</span>
@ -233,7 +233,7 @@ const openDepot = (): void => {
justify-content: space-between;
align-items: center;
height: 60px;
background: #fff;
background: var(--el-bg-color);
.left-mark {
display: flex;

6
types/global.d.ts vendored
View File

@ -5,6 +5,7 @@ import type {
FunctionalComponent,
PropType as VuePropType
} from "vue";
import type { ECharts } from "echarts";
// GlobalComponents for Volar
declare module "vue" {
@ -108,6 +109,11 @@ declare global {
};
}
declare interface GlobalPropertiesApi {
$echarts: ECharts;
$storage: ServerConfigs;
}
function parseInt(s: string | number, radix?: number): number;
function parseFloat(string: string | number): number;

View File

@ -13,9 +13,22 @@ export default defineConfig({
transformers: [transformerDirectives(), transformerVariantGroup()],
exclude: [`${__dirname}/node_modules/**/*`],
shortcuts: {
"bg-dark": "bg-bg_color",
"wh-full": "w-full h-full",
"cp-on": "cursor-pointer outline-none",
"flex-c": "flex justify-center items-center",
"flex-ac": "flex justify-around items-center",
"flex-bc": "flex justify-between items-center"
"flex-bc": "flex justify-between items-center",
"navbar-bg-hover": "dark:color-white !dark:hover:bg-[#242424]"
},
theme: {}
theme: {
colors: {
bg_color: "var(--el-bg-color)",
primary: "var(--el-color-primary)",
primary_light_9: "var(--el-color-primary-light-9)",
text_color_primary: "var(--el-text-color-primary)",
text_color_regular: "var(--el-text-color-regular)",
text_color_disabled: "var(--el-text-color-disabled)"
}
}
});