mirror of
https://github.com/pure-admin/vue-pure-admin.git
synced 2025-06-06 08:27:54 +08:00
perf: 更干净整洁的项目配置右侧弹出面板 (#841)
This commit is contained in:
parent
e7d55ff67e
commit
7acdf03f87
@ -1,7 +1,5 @@
|
||||
@import "cropperjs/dist/cropper.css";
|
||||
@import "tippy.js/dist/tippy.css";
|
||||
@import "tippy.js/themes/light.css";
|
||||
@import "tippy.js/animations/perspective.css";
|
||||
@import "cropperjs/dist/cropper.css";
|
||||
|
||||
.re-circled {
|
||||
.cropper-view-box,
|
||||
|
@ -1,10 +1,10 @@
|
||||
import "./circled.css";
|
||||
import Cropper from "cropperjs";
|
||||
import { useTippy } from "vue-tippy";
|
||||
import { ElUpload } from "element-plus";
|
||||
import type { CSSProperties } from "vue";
|
||||
import { useResizeObserver } from "@vueuse/core";
|
||||
import { longpress } from "@/directives/longpress";
|
||||
import { useTippy, directive as tippy } from "vue-tippy";
|
||||
import { delay, debounce, isArray, downloadByBase64 } from "@pureadmin/utils";
|
||||
import {
|
||||
ref,
|
||||
@ -233,7 +233,6 @@ export default defineComponent({
|
||||
|
||||
const menuContent = defineComponent({
|
||||
directives: {
|
||||
tippy,
|
||||
longpress
|
||||
},
|
||||
setup() {
|
||||
|
@ -33,7 +33,7 @@ export function useRenderIcon(icon: any, attrs?: iconType): Component {
|
||||
});
|
||||
} else if (typeof icon === "function" || typeof icon?.render === "function") {
|
||||
// svg
|
||||
return icon;
|
||||
return h(icon, { ...attrs });
|
||||
} else if (typeof icon === "object") {
|
||||
return defineComponent({
|
||||
name: "OfflineIcon",
|
||||
|
@ -13,7 +13,8 @@ export interface iconType {
|
||||
align?: string;
|
||||
onLoad?: Function;
|
||||
includes?: Function;
|
||||
|
||||
// all icon
|
||||
// svg 需要什么SVG属性自行添加
|
||||
fill?: string;
|
||||
// all icon
|
||||
style?: object;
|
||||
}
|
||||
|
@ -6,7 +6,6 @@
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
background-color: rgb(0 0 0 / 4%);
|
||||
border-radius: 2px;
|
||||
transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
}
|
||||
|
||||
.pure-segmented-group {
|
||||
@ -43,7 +42,7 @@
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
transition: all 0.1s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
}
|
||||
|
||||
.pure-segmented-item > div {
|
||||
|
@ -121,7 +121,11 @@ export default defineComponent({
|
||||
class="pure-segmented-item-icon"
|
||||
style={{ marginRight: option.label ? "6px" : 0 }}
|
||||
>
|
||||
{h(useRenderIcon(option.icon))}
|
||||
{h(
|
||||
useRenderIcon(option.icon, {
|
||||
...option?.iconAttrs
|
||||
})
|
||||
)}
|
||||
</span>
|
||||
) : null}
|
||||
{option.label ? (
|
||||
|
@ -1,4 +1,5 @@
|
||||
import type { VNode, Component } from "vue";
|
||||
import type { iconType } from "@/components/ReIcon/src/types.ts";
|
||||
|
||||
export interface OptionsType {
|
||||
/** 文字 */
|
||||
@ -8,6 +9,8 @@ export interface OptionsType {
|
||||
* @see {@link 用法参考 https://yiming_chang.gitee.io/pure-admin-doc/pages/icon/#%E9%80%9A%E7%94%A8%E5%9B%BE%E6%A0%87-userendericon-hooks }
|
||||
*/
|
||||
icon?: string | Component;
|
||||
/** 图标属性、样式配置 */
|
||||
iconAttrs?: iconType;
|
||||
/** 值 */
|
||||
value?: string | number;
|
||||
/** 是否禁用 */
|
||||
|
@ -2,6 +2,7 @@
|
||||
import { emitter } from "@/utils/mitt";
|
||||
import { onClickOutside } from "@vueuse/core";
|
||||
import { ref, computed, onMounted, onBeforeUnmount } from "vue";
|
||||
import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange";
|
||||
import Close from "@iconify-icons/ep/close";
|
||||
|
||||
const target = ref(null);
|
||||
@ -9,7 +10,6 @@ const show = ref<Boolean>(false);
|
||||
|
||||
const iconClass = computed(() => {
|
||||
return [
|
||||
"mr-[20px]",
|
||||
"outline-none",
|
||||
"width-[20px]",
|
||||
"height-[20px]",
|
||||
@ -22,6 +22,8 @@ const iconClass = computed(() => {
|
||||
];
|
||||
});
|
||||
|
||||
const { onReset } = useDataThemeChange();
|
||||
|
||||
onClickOutside(target, (event: any) => {
|
||||
if (event.clientX > target.value.offsetLeft) return;
|
||||
show.value = false;
|
||||
@ -43,23 +45,47 @@ onBeforeUnmount(() => {
|
||||
<div :class="{ show: show }" class="right-panel-container">
|
||||
<div class="right-panel-background" />
|
||||
<div ref="target" class="right-panel bg-bg_color">
|
||||
<div class="right-panel-items">
|
||||
<div class="project-configuration">
|
||||
<h4 class="dark:text-white">项目配置</h4>
|
||||
<span title="关闭配置" :class="iconClass">
|
||||
<IconifyIconOffline
|
||||
class="dark:text-white"
|
||||
width="20px"
|
||||
height="20px"
|
||||
:icon="Close"
|
||||
@click="show = !show"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="border-b-[1px] border-solid border-[#dcdfe6] dark:border-[#303030]"
|
||||
/>
|
||||
<div
|
||||
class="project-configuration border-b-[1px] border-solid border-[var(--pure-border-color)]"
|
||||
>
|
||||
<h4 class="dark:text-white">项目配置</h4>
|
||||
<span
|
||||
v-tippy="{
|
||||
content: '关闭配置',
|
||||
placement: 'bottom-start',
|
||||
zIndex: 41000
|
||||
}"
|
||||
:class="iconClass"
|
||||
>
|
||||
<IconifyIconOffline
|
||||
class="dark:text-white"
|
||||
width="20px"
|
||||
height="20px"
|
||||
:icon="Close"
|
||||
@click="show = !show"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<el-scrollbar>
|
||||
<slot />
|
||||
</el-scrollbar>
|
||||
|
||||
<div
|
||||
class="flex justify-end p-3 border-t-[1px] border-solid border-[var(--pure-border-color)]"
|
||||
>
|
||||
<el-button
|
||||
v-tippy="{
|
||||
content: '清空缓存并返回登录页',
|
||||
placement: 'left-start',
|
||||
zIndex: 41000
|
||||
}"
|
||||
type="danger"
|
||||
text
|
||||
bg
|
||||
@click="onReset"
|
||||
>
|
||||
清空缓存
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -74,6 +100,10 @@ onBeforeUnmount(() => {
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-scrollbar) {
|
||||
height: calc(100vh - 110px);
|
||||
}
|
||||
|
||||
.right-panel-background {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
@ -90,7 +120,7 @@ onBeforeUnmount(() => {
|
||||
right: 0;
|
||||
z-index: 40000;
|
||||
width: 100%;
|
||||
max-width: 315px;
|
||||
max-width: 300px;
|
||||
height: 100vh;
|
||||
box-shadow: 0 0 15px 0 rgb(0 0 0 / 5%);
|
||||
transition: all 0.25s cubic-bezier(0.7, 0.3, 0.1, 1);
|
||||
@ -112,47 +142,10 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.handle-button {
|
||||
position: absolute;
|
||||
top: 45%;
|
||||
left: -48px;
|
||||
z-index: 0;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
font-size: 24px;
|
||||
line-height: 48px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
pointer-events: auto;
|
||||
cursor: pointer;
|
||||
background: rgb(24 144 255);
|
||||
border-radius: 6px 0 0 6px !important;
|
||||
|
||||
i {
|
||||
font-size: 24px;
|
||||
line-height: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
.right-panel-items {
|
||||
height: calc(100vh - 60px);
|
||||
margin-top: 60px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.project-configuration {
|
||||
position: fixed;
|
||||
top: 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
:deep(.el-divider--horizontal) {
|
||||
width: 90%;
|
||||
margin: 20px auto 0;
|
||||
padding: 14px 20px;
|
||||
}
|
||||
</style>
|
||||
|
@ -8,28 +8,22 @@ import {
|
||||
nextTick,
|
||||
onBeforeMount
|
||||
} from "vue";
|
||||
import { getConfig } from "@/config";
|
||||
import { useRouter } from "vue-router";
|
||||
import panel from "../panel/index.vue";
|
||||
import { emitter } from "@/utils/mitt";
|
||||
import { resetRouter } from "@/router";
|
||||
import { removeToken } from "@/utils/auth";
|
||||
import { routerArrays } from "@/layout/types";
|
||||
import { useNav } from "@/layout/hooks/useNav";
|
||||
import { useAppStoreHook } from "@/store/modules/app";
|
||||
import { useDark, debounce, useGlobal } from "@pureadmin/utils";
|
||||
import { toggleTheme } from "@pureadmin/theme/dist/browser-utils";
|
||||
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
|
||||
import Segmented, { type OptionsType } from "@/components/ReSegmented";
|
||||
import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange";
|
||||
import { useDark, debounce, useGlobal, storageLocal } from "@pureadmin/utils";
|
||||
|
||||
import Check from "@iconify-icons/ep/check";
|
||||
import dayIcon from "@/assets/svg/day.svg?component";
|
||||
import darkIcon from "@/assets/svg/dark.svg?component";
|
||||
import Check from "@iconify-icons/ep/check";
|
||||
import Logout from "@iconify-icons/ri/logout-circle-r-line";
|
||||
|
||||
const router = useRouter();
|
||||
const { device } = useNav();
|
||||
const { isDark } = useDark();
|
||||
const { device, tooltipEffect } = useNav();
|
||||
const { $storage } = useGlobal<GlobalPropertiesApi>();
|
||||
|
||||
const mixRef = ref();
|
||||
@ -40,8 +34,8 @@ const {
|
||||
dataTheme,
|
||||
layoutTheme,
|
||||
themeColors,
|
||||
toggleClass,
|
||||
dataThemeChange,
|
||||
setEpThemeColor,
|
||||
setLayoutThemeColor
|
||||
} = useDataThemeChange();
|
||||
|
||||
@ -89,13 +83,6 @@ function storageConfigureChange<T>(key: string, val: T): void {
|
||||
$storage.configure = storageConfigure;
|
||||
}
|
||||
|
||||
function toggleClass(flag: boolean, clsName: string, target?: HTMLElement) {
|
||||
const targetEl = target || document.body;
|
||||
let { className } = targetEl;
|
||||
className = className.replace(clsName, "").trim();
|
||||
targetEl.className = flag ? `${className} ${clsName} ` : className;
|
||||
}
|
||||
|
||||
/** 灰色模式设置 */
|
||||
const greyChange = (value): void => {
|
||||
toggleClass(settings.greyVal, "html-grey", document.querySelector("html"));
|
||||
@ -132,24 +119,11 @@ const multiTagsCacheChange = () => {
|
||||
useMultiTagsStoreHook().multiTagsCacheChange(multiTagsCache);
|
||||
};
|
||||
|
||||
/** 清空缓存并返回登录页 */
|
||||
function onReset() {
|
||||
removeToken();
|
||||
storageLocal().clear();
|
||||
const { Grey, Weak, MultiTagsCache, EpThemeColor, Layout } = getConfig();
|
||||
useAppStoreHook().setLayout(Layout);
|
||||
setEpThemeColor(EpThemeColor);
|
||||
useMultiTagsStoreHook().multiTagsCacheChange(MultiTagsCache);
|
||||
toggleClass(Grey, "html-grey", document.querySelector("html"));
|
||||
toggleClass(Weak, "html-weakness", document.querySelector("html"));
|
||||
router.push("/login");
|
||||
useMultiTagsStoreHook().handleTags("equal", [...routerArrays]);
|
||||
resetRouter();
|
||||
}
|
||||
|
||||
function onChange(label) {
|
||||
storageConfigureChange("showModel", label);
|
||||
emitter.emit("tagViewsShowModel", label);
|
||||
function onChange({ option }) {
|
||||
const { value } = option;
|
||||
markValue.value = value;
|
||||
storageConfigureChange("showModel", value);
|
||||
emitter.emit("tagViewsShowModel", value);
|
||||
}
|
||||
|
||||
/** 侧边栏Logo */
|
||||
@ -185,6 +159,32 @@ const getThemeColor = computed(() => {
|
||||
};
|
||||
});
|
||||
|
||||
const themeOptions = computed<Array<OptionsType>>(() => {
|
||||
return [
|
||||
{
|
||||
label: "亮色",
|
||||
icon: dayIcon,
|
||||
iconAttrs: { fill: isDark.value ? "#fff" : "#000" }
|
||||
},
|
||||
{
|
||||
label: "暗色",
|
||||
icon: darkIcon,
|
||||
iconAttrs: { fill: isDark.value ? "#fff" : "#000" }
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
const markOptions: Array<OptionsType> = [
|
||||
{
|
||||
label: "灵动",
|
||||
value: "smart"
|
||||
},
|
||||
{
|
||||
label: "卡片",
|
||||
value: "card"
|
||||
}
|
||||
];
|
||||
|
||||
/** 设置导航模式 */
|
||||
function setLayoutModel(layout: string) {
|
||||
layoutTheme.value.layout = layout;
|
||||
@ -234,185 +234,153 @@ onBeforeMount(() => {
|
||||
|
||||
<template>
|
||||
<panel>
|
||||
<el-divider>主题</el-divider>
|
||||
<el-switch
|
||||
v-model="dataTheme"
|
||||
inline-prompt
|
||||
class="pure-datatheme"
|
||||
:active-icon="dayIcon"
|
||||
:inactive-icon="darkIcon"
|
||||
@change="dataThemeChange"
|
||||
/>
|
||||
<div class="p-6">
|
||||
<p class="mb-3 font-medium text-sm dark:text-white">整体风格</p>
|
||||
<Segmented
|
||||
:modelValue="dataTheme ? 1 : 0"
|
||||
:options="themeOptions"
|
||||
@change="
|
||||
{
|
||||
dataTheme = !dataTheme;
|
||||
dataThemeChange();
|
||||
}
|
||||
"
|
||||
/>
|
||||
|
||||
<el-divider>导航栏模式</el-divider>
|
||||
<ul class="pure-theme">
|
||||
<el-tooltip
|
||||
:effect="tooltipEffect"
|
||||
class="item"
|
||||
content="左侧模式"
|
||||
placement="bottom"
|
||||
popper-class="pure-tooltip"
|
||||
>
|
||||
<p class="mt-5 mb-3 font-medium text-sm dark:text-white">主题色</p>
|
||||
<ul class="theme-color">
|
||||
<li
|
||||
v-for="(item, index) in themeColors"
|
||||
v-show="showThemeColors(item.themeColor)"
|
||||
:key="index"
|
||||
:style="getThemeColorStyle(item.color)"
|
||||
@click="setLayoutThemeColor(item.themeColor)"
|
||||
>
|
||||
<el-icon
|
||||
style="margin: 0.1em 0.1em 0 0"
|
||||
:size="17"
|
||||
:color="getThemeColor(item.themeColor)"
|
||||
>
|
||||
<IconifyIconOffline :icon="Check" />
|
||||
</el-icon>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p class="mt-5 mb-3 font-medium text-sm dark:text-white">导航模式</p>
|
||||
<ul class="pure-theme">
|
||||
<li
|
||||
ref="verticalRef"
|
||||
v-tippy="{
|
||||
content: '左侧菜单',
|
||||
zIndex: 41000
|
||||
}"
|
||||
:class="layoutTheme.layout === 'vertical' ? 'is-select' : ''"
|
||||
@click="setLayoutModel('vertical')"
|
||||
>
|
||||
<div />
|
||||
<div />
|
||||
</li>
|
||||
</el-tooltip>
|
||||
|
||||
<el-tooltip
|
||||
v-if="device !== 'mobile'"
|
||||
:effect="tooltipEffect"
|
||||
class="item"
|
||||
content="顶部模式"
|
||||
placement="bottom"
|
||||
popper-class="pure-tooltip"
|
||||
>
|
||||
<li
|
||||
v-if="device !== 'mobile'"
|
||||
ref="horizontalRef"
|
||||
v-tippy="{
|
||||
content: '顶部菜单',
|
||||
zIndex: 41000
|
||||
}"
|
||||
:class="layoutTheme.layout === 'horizontal' ? 'is-select' : ''"
|
||||
@click="setLayoutModel('horizontal')"
|
||||
>
|
||||
<div />
|
||||
<div />
|
||||
</li>
|
||||
</el-tooltip>
|
||||
|
||||
<el-tooltip
|
||||
v-if="device !== 'mobile'"
|
||||
:effect="tooltipEffect"
|
||||
class="item"
|
||||
content="混合模式"
|
||||
placement="bottom"
|
||||
popper-class="pure-tooltip"
|
||||
>
|
||||
<li
|
||||
v-if="device !== 'mobile'"
|
||||
ref="mixRef"
|
||||
v-tippy="{
|
||||
content: '混合菜单',
|
||||
zIndex: 41000
|
||||
}"
|
||||
:class="layoutTheme.layout === 'mix' ? 'is-select' : ''"
|
||||
@click="setLayoutModel('mix')"
|
||||
>
|
||||
<div />
|
||||
<div />
|
||||
</li>
|
||||
</el-tooltip>
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
<el-divider>主题色</el-divider>
|
||||
<ul class="theme-color">
|
||||
<li
|
||||
v-for="(item, index) in themeColors"
|
||||
v-show="showThemeColors(item.themeColor)"
|
||||
:key="index"
|
||||
:style="getThemeColorStyle(item.color)"
|
||||
@click="setLayoutThemeColor(item.themeColor)"
|
||||
>
|
||||
<el-icon
|
||||
style="margin: 0.1em 0.1em 0 0"
|
||||
:size="17"
|
||||
:color="getThemeColor(item.themeColor)"
|
||||
>
|
||||
<IconifyIconOffline :icon="Check" />
|
||||
</el-icon>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<el-divider>界面显示</el-divider>
|
||||
<ul class="setting">
|
||||
<li>
|
||||
<span class="dark:text-white">灰色模式</span>
|
||||
<el-switch
|
||||
v-model="settings.greyVal"
|
||||
inline-prompt
|
||||
inactive-color="#a6a6a6"
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
@change="greyChange"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<span class="dark:text-white">色弱模式</span>
|
||||
<el-switch
|
||||
v-model="settings.weakVal"
|
||||
inline-prompt
|
||||
inactive-color="#a6a6a6"
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
@change="weekChange"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<span class="dark:text-white">隐藏标签页</span>
|
||||
<el-switch
|
||||
v-model="settings.tabsVal"
|
||||
inline-prompt
|
||||
inactive-color="#a6a6a6"
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
@change="tagsChange"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<span class="dark:text-white">隐藏页脚</span>
|
||||
<el-switch
|
||||
v-model="settings.hideFooter"
|
||||
inline-prompt
|
||||
inactive-color="#a6a6a6"
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
@change="hideFooterChange"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<span class="dark:text-white">侧边栏Logo</span>
|
||||
<el-switch
|
||||
v-model="logoVal"
|
||||
inline-prompt
|
||||
:active-value="true"
|
||||
:inactive-value="false"
|
||||
inactive-color="#a6a6a6"
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
@change="logoChange"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<span class="dark:text-white">标签页持久化</span>
|
||||
<el-switch
|
||||
v-model="settings.multiTagsCache"
|
||||
inline-prompt
|
||||
inactive-color="#a6a6a6"
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
@change="multiTagsCacheChange"
|
||||
/>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<span class="dark:text-white">标签风格</span>
|
||||
<el-radio-group v-model="markValue" size="small" @change="onChange">
|
||||
<el-radio label="card">卡片</el-radio>
|
||||
<el-radio label="smart">灵动</el-radio>
|
||||
</el-radio-group>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<el-divider />
|
||||
<el-button
|
||||
type="danger"
|
||||
style="width: 90%; margin: 24px 15px"
|
||||
@click="onReset"
|
||||
>
|
||||
<IconifyIconOffline
|
||||
:icon="Logout"
|
||||
width="15"
|
||||
height="15"
|
||||
style="margin-right: 4px"
|
||||
<p class="mt-5 mb-3 font-medium text-base dark:text-white">页签风格</p>
|
||||
<Segmented
|
||||
:modelValue="markValue === 'smart' ? 0 : 1"
|
||||
:options="markOptions"
|
||||
@change="onChange"
|
||||
/>
|
||||
清空缓存并返回登录页
|
||||
</el-button>
|
||||
|
||||
<p class="mt-5 mb-1 font-medium text-sm dark:text-white">界面显示</p>
|
||||
<ul class="setting">
|
||||
<li>
|
||||
<span class="dark:text-white">灰色模式</span>
|
||||
<el-switch
|
||||
v-model="settings.greyVal"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
@change="greyChange"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<span class="dark:text-white">色弱模式</span>
|
||||
<el-switch
|
||||
v-model="settings.weakVal"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
@change="weekChange"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<span class="dark:text-white">隐藏标签页</span>
|
||||
<el-switch
|
||||
v-model="settings.tabsVal"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
@change="tagsChange"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<span class="dark:text-white">隐藏页脚</span>
|
||||
<el-switch
|
||||
v-model="settings.hideFooter"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
@change="hideFooterChange"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<span class="dark:text-white">Logo</span>
|
||||
<el-switch
|
||||
v-model="logoVal"
|
||||
inline-prompt
|
||||
:active-value="true"
|
||||
:inactive-value="false"
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
@change="logoChange"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<span class="dark:text-white">页签持久化</span>
|
||||
<el-switch
|
||||
v-model="settings.multiTagsCache"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
@change="multiTagsCacheChange"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</panel>
|
||||
</template>
|
||||
|
||||
@ -422,41 +390,41 @@ onBeforeMount(() => {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.is-select {
|
||||
border: 2px solid var(--el-color-primary);
|
||||
:deep(.el-switch__core) {
|
||||
--el-switch-off-color: var(--pure-switch-off-color);
|
||||
|
||||
min-width: 36px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.setting {
|
||||
width: 100%;
|
||||
:deep(.el-switch__core .el-switch__action) {
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.theme-color {
|
||||
height: 20px;
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 25px;
|
||||
}
|
||||
}
|
||||
float: left;
|
||||
height: 20px;
|
||||
margin-right: 8px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
|
||||
.pure-datatheme {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
padding-top: 25px;
|
||||
text-align: center;
|
||||
&:nth-child(2) {
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pure-theme {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-around;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
margin-top: 25px;
|
||||
gap: 12px;
|
||||
|
||||
li {
|
||||
position: relative;
|
||||
width: 18%;
|
||||
height: 45px;
|
||||
width: 46px;
|
||||
height: 36px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
background: #f0f2f5;
|
||||
@ -517,27 +485,17 @@ onBeforeMount(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.theme-color {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
margin-top: 20px;
|
||||
.is-select {
|
||||
border: 2px solid var(--el-color-primary);
|
||||
}
|
||||
|
||||
.setting {
|
||||
li {
|
||||
float: left;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-top: 8px;
|
||||
margin-right: 8px;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border-radius: 2px;
|
||||
|
||||
&:nth-child(2) {
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 4px 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,9 +1,14 @@
|
||||
import { ref } from "vue";
|
||||
import { getConfig } from "@/config";
|
||||
import { useLayout } from "./useLayout";
|
||||
import { useGlobal } from "@pureadmin/utils";
|
||||
import { removeToken } from "@/utils/auth";
|
||||
import { routerArrays } from "@/layout/types";
|
||||
import { router, resetRouter } from "@/router";
|
||||
import type { themeColorsType } from "../types";
|
||||
import { useAppStoreHook } from "@/store/modules/app";
|
||||
import { useGlobal, storageLocal } from "@pureadmin/utils";
|
||||
import { useEpThemeStoreHook } from "@/store/modules/epTheme";
|
||||
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
|
||||
import {
|
||||
darken,
|
||||
lighten,
|
||||
@ -37,6 +42,13 @@ export function useDataThemeChange() {
|
||||
const dataTheme = ref<boolean>($storage?.layout?.darkMode);
|
||||
const body = document.documentElement as HTMLElement;
|
||||
|
||||
function toggleClass(flag: boolean, clsName: string, target?: HTMLElement) {
|
||||
const targetEl = target || document.body;
|
||||
let { className } = targetEl;
|
||||
className = className.replace(clsName, "").trim();
|
||||
targetEl.className = flag ? `${className} ${clsName} ` : className;
|
||||
}
|
||||
|
||||
/** 设置导航主题色 */
|
||||
function setLayoutThemeColor(theme = getConfig().Theme ?? "default") {
|
||||
layoutTheme.value.theme = theme;
|
||||
@ -78,9 +90,8 @@ export function useDataThemeChange() {
|
||||
}
|
||||
};
|
||||
|
||||
/** 日间、夜间主题切换 */
|
||||
/** 亮色、暗色整体风格切换 */
|
||||
function dataThemeChange() {
|
||||
/* 如果当前是light夜间主题,默认切换到default主题 */
|
||||
if (useEpThemeStoreHook().epTheme === "light" && dataTheme.value) {
|
||||
setLayoutThemeColor("default");
|
||||
} else {
|
||||
@ -94,11 +105,28 @@ export function useDataThemeChange() {
|
||||
}
|
||||
}
|
||||
|
||||
/** 清空缓存并返回登录页 */
|
||||
function onReset() {
|
||||
removeToken();
|
||||
storageLocal().clear();
|
||||
const { Grey, Weak, MultiTagsCache, EpThemeColor, Layout } = getConfig();
|
||||
useAppStoreHook().setLayout(Layout);
|
||||
setEpThemeColor(EpThemeColor);
|
||||
useMultiTagsStoreHook().multiTagsCacheChange(MultiTagsCache);
|
||||
toggleClass(Grey, "html-grey", document.querySelector("html"));
|
||||
toggleClass(Weak, "html-weakness", document.querySelector("html"));
|
||||
router.push("/login");
|
||||
useMultiTagsStoreHook().handleTags("equal", [...routerArrays]);
|
||||
resetRouter();
|
||||
}
|
||||
|
||||
return {
|
||||
body,
|
||||
dataTheme,
|
||||
layoutTheme,
|
||||
themeColors,
|
||||
onReset,
|
||||
toggleClass,
|
||||
dataThemeChange,
|
||||
setEpThemeColor,
|
||||
setLayoutThemeColor
|
||||
|
@ -45,6 +45,14 @@ app.component("FontIcon", FontIcon);
|
||||
import { Auth } from "@/components/ReAuth";
|
||||
app.component("Auth", Auth);
|
||||
|
||||
// 全局注册`vue-tippy`
|
||||
import "tippy.js/dist/tippy.css";
|
||||
import "tippy.js/animations/perspective.css";
|
||||
import VueTippy from "vue-tippy";
|
||||
app.use(VueTippy, {
|
||||
defaultProps: { animation: "perspective" }
|
||||
});
|
||||
|
||||
getPlatformConfig(app).then(async config => {
|
||||
setupStore(app);
|
||||
app.use(router);
|
||||
|
@ -2,11 +2,18 @@
|
||||
|
||||
/* 暗黑模式适配 */
|
||||
html.dark {
|
||||
/* 自定义深色背景颜色 */
|
||||
// --el-bg-color: #020409;
|
||||
$border-style: #303030;
|
||||
$color-white: #fff;
|
||||
|
||||
/* 自定义深色背景颜色 */
|
||||
// --el-bg-color: #020409;
|
||||
|
||||
/* 常用border-color 需要时可取用 */
|
||||
--pure-border-color: rgb(253 253 253 / 12%);
|
||||
|
||||
/* switch关闭状态下的color 需要时可取用 */
|
||||
--pure-switch-off-color: #ffffff3f;
|
||||
|
||||
.navbar,
|
||||
.tags-view,
|
||||
.contextmenu,
|
||||
|
@ -50,12 +50,6 @@
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
/* 自定义 tooltip 的类名 */
|
||||
.pure-tooltip {
|
||||
// 右侧操作面板right-panel类名的z-index为40000,tooltip需要大于它才能显示
|
||||
z-index: 41000 !important;
|
||||
}
|
||||
|
||||
/* nprogress 适配 element-plus 的主题色 */
|
||||
#nprogress {
|
||||
& .bar {
|
||||
|
@ -7,6 +7,12 @@
|
||||
:root {
|
||||
/* 左侧菜单展开、收起动画时长 */
|
||||
--pure-transition-duration: 0.3s;
|
||||
|
||||
/* 常用border-color 需要时可取用 */
|
||||
--pure-border-color: rgb(5 5 5 / 6%);
|
||||
|
||||
/* switch关闭状态下的color 需要时可取用 */
|
||||
--pure-switch-off-color: #a6a6a6;
|
||||
}
|
||||
|
||||
/* 灰色模式 */
|
||||
|
@ -4,15 +4,10 @@ import { getTime } from "@pureadmin/utils";
|
||||
import { Play, Pause, Forward, Rewind } from "./svg";
|
||||
import { ref, onMounted, onBeforeUnmount } from "vue";
|
||||
|
||||
import "tippy.js/dist/tippy.css";
|
||||
import "tippy.js/animations/scale.css";
|
||||
import { directive as tippy } from "vue-tippy";
|
||||
|
||||
defineOptions({
|
||||
name: "Wavesurfer"
|
||||
});
|
||||
|
||||
const vTippy = tippy;
|
||||
const loading = ref(true);
|
||||
const wavesurfer = ref(null);
|
||||
const wavesurferRef = ref();
|
||||
@ -114,8 +109,7 @@ onBeforeUnmount(() => {
|
||||
<Rewind
|
||||
v-tippy="{
|
||||
content: '快退(可长按)',
|
||||
placement: 'bottom',
|
||||
animation: 'scale'
|
||||
placement: 'bottom'
|
||||
}"
|
||||
v-longpress:0:100="() => wavesurfer?.skip(-1)"
|
||||
class="cursor-pointer"
|
||||
@ -123,8 +117,7 @@ onBeforeUnmount(() => {
|
||||
<div
|
||||
v-tippy="{
|
||||
content: isPlay ? '暂停' : '播放',
|
||||
placement: 'bottom',
|
||||
animation: 'scale'
|
||||
placement: 'bottom'
|
||||
}"
|
||||
class="cursor-pointer"
|
||||
@click="wavesurfer?.playPause()"
|
||||
@ -135,8 +128,7 @@ onBeforeUnmount(() => {
|
||||
<Forward
|
||||
v-tippy="{
|
||||
content: '快进(可长按)',
|
||||
placement: 'bottom',
|
||||
animation: 'scale'
|
||||
placement: 'bottom'
|
||||
}"
|
||||
v-longpress:0:100="() => wavesurfer?.skip(1)"
|
||||
class="cursor-pointer"
|
||||
|
Loading…
x
Reference in New Issue
Block a user