mirror of
https://github.com/pure-admin/vue-pure-admin.git
synced 2025-11-21 14:13:36 +08:00
Merge remote-tracking branch 'origin/main' into gitee
This commit is contained in:
@@ -7,15 +7,8 @@ defineOptions({
|
||||
name: "ReAnimateSelector"
|
||||
});
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
require: false,
|
||||
type: String
|
||||
}
|
||||
});
|
||||
const emit = defineEmits<{ (e: "update:modelValue", v: string) }>();
|
||||
const inputValue = defineModel({ type: String });
|
||||
|
||||
const inputValue = toRef(props, "modelValue");
|
||||
const animatesList = ref(animates);
|
||||
const copyAnimatesList = cloneDeep(animatesList);
|
||||
|
||||
@@ -47,11 +40,11 @@ const animateStyle = computed(
|
||||
);
|
||||
|
||||
function onChangeIcon(animate: string) {
|
||||
emit("update:modelValue", animate);
|
||||
inputValue.value = animate;
|
||||
}
|
||||
|
||||
function onClear() {
|
||||
emit("update:modelValue", "");
|
||||
inputValue.value = "";
|
||||
}
|
||||
|
||||
function filterMethod(value: any) {
|
||||
@@ -81,8 +74,8 @@ function onMouseleave() {
|
||||
placeholder="请选择动画"
|
||||
clearable
|
||||
filterable
|
||||
@clear="onClear"
|
||||
:filter-method="filterMethod"
|
||||
@clear="onClear"
|
||||
>
|
||||
<template #empty>
|
||||
<div class="w-[280px]">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PropType } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import propTypes from "@/utils/propTypes";
|
||||
export const countToProps = {
|
||||
startVal: propTypes.number.def(0),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PropType } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import propTypes from "@/utils/propTypes";
|
||||
export const reboundProps = {
|
||||
delay: propTypes.number.def(1),
|
||||
|
||||
@@ -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,16 +1,16 @@
|
||||
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,
|
||||
unref,
|
||||
computed,
|
||||
PropType,
|
||||
type PropType,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
defineComponent
|
||||
@@ -233,7 +233,6 @@ export default defineComponent({
|
||||
|
||||
const menuContent = defineComponent({
|
||||
directives: {
|
||||
tippy,
|
||||
longpress
|
||||
},
|
||||
setup() {
|
||||
|
||||
@@ -27,8 +27,11 @@ const addDialog = (options: DialogOptions) => {
|
||||
|
||||
/** 关闭弹框 */
|
||||
const closeDialog = (options: DialogOptions, index: number, args?: any) => {
|
||||
dialogStore.value.splice(index, 1);
|
||||
dialogStore.value[index].visible = false;
|
||||
options.closeCallBack && options.closeCallBack({ options, index, args });
|
||||
useTimeoutFn(() => {
|
||||
dialogStore.value.splice(index, 1);
|
||||
}, 200);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -84,11 +84,11 @@ function handleClose(
|
||||
|
||||
<template>
|
||||
<el-dialog
|
||||
class="pure-dialog"
|
||||
v-for="(options, index) in dialogStore"
|
||||
:key="index"
|
||||
v-bind="options"
|
||||
v-model="options.visible"
|
||||
class="pure-dialog"
|
||||
:fullscreen="fullscreen ? true : options?.fullscreen ? true : false"
|
||||
@close="handleClose(options, index)"
|
||||
@opened="eventsCallBack('open', options, index)"
|
||||
@@ -116,15 +116,15 @@ function handleClose(
|
||||
options?.fullscreen
|
||||
? ExitFullscreen
|
||||
: fullscreen
|
||||
? ExitFullscreen
|
||||
: Fullscreen
|
||||
? ExitFullscreen
|
||||
: Fullscreen
|
||||
"
|
||||
/>
|
||||
</i>
|
||||
</div>
|
||||
<component
|
||||
v-else
|
||||
:is="options?.headerRenderer({ close, titleId, titleClass })"
|
||||
v-else
|
||||
/>
|
||||
</template>
|
||||
<component
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import "./index.css";
|
||||
import { h, defineComponent, Component } from "vue";
|
||||
import { h, defineComponent, type Component } from "vue";
|
||||
|
||||
export interface attrsType {
|
||||
width?: string;
|
||||
|
||||
@@ -18,7 +18,6 @@ export default defineComponent({
|
||||
name: "ReFlop",
|
||||
props,
|
||||
setup(props) {
|
||||
// eslint-disable-next-line vue/no-setup-props-destructure
|
||||
const { frontText, backText, duration } = props;
|
||||
const isFlipping = ref(false);
|
||||
const flipType = ref("down");
|
||||
|
||||
@@ -35,9 +35,9 @@ const nodeDragNode = item => {
|
||||
<!-- 左侧bpmn元素选择器 -->
|
||||
<div class="node-panel">
|
||||
<div
|
||||
class="node-item dark:text-bg_color"
|
||||
v-for="item in props.nodeList"
|
||||
:key="item.text"
|
||||
class="node-item dark:text-bg_color"
|
||||
@mousedown="nodeDragNode(item)"
|
||||
>
|
||||
<div class="node-item-icon" :class="item.class">
|
||||
|
||||
@@ -10,15 +10,8 @@ defineOptions({
|
||||
name: "IconSelect"
|
||||
});
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
require: false,
|
||||
type: String
|
||||
}
|
||||
});
|
||||
const emit = defineEmits<{ (e: "update:modelValue", v: string) }>();
|
||||
const inputValue = defineModel({ type: String });
|
||||
|
||||
const inputValue = toRef(props, "modelValue");
|
||||
const iconList = ref(IconJson);
|
||||
const icon = ref();
|
||||
const currentActiveType = ref("ep:");
|
||||
@@ -68,11 +61,11 @@ const iconItemStyle = computed((): ParameterCSSProperties => {
|
||||
});
|
||||
|
||||
function setVal() {
|
||||
currentActiveType.value = props.modelValue.substring(
|
||||
currentActiveType.value = inputValue.value.substring(
|
||||
0,
|
||||
props.modelValue.indexOf(":") + 1
|
||||
inputValue.value.indexOf(":") + 1
|
||||
);
|
||||
icon.value = props.modelValue.substring(props.modelValue.indexOf(":") + 1);
|
||||
icon.value = inputValue.value.substring(inputValue.value.indexOf(":") + 1);
|
||||
}
|
||||
|
||||
function onBeforeEnter() {
|
||||
@@ -96,7 +89,7 @@ function handleClick({ props }) {
|
||||
|
||||
function onChangeIcon(item) {
|
||||
icon.value = item;
|
||||
emit("update:modelValue", currentActiveType.value + item);
|
||||
inputValue.value = currentActiveType.value + item;
|
||||
}
|
||||
|
||||
function onCurrentChange(page) {
|
||||
@@ -105,7 +98,7 @@ function onCurrentChange(page) {
|
||||
|
||||
function onClear() {
|
||||
icon.value = "";
|
||||
emit("update:modelValue", "");
|
||||
inputValue.value = "";
|
||||
}
|
||||
|
||||
watch(
|
||||
@@ -117,7 +110,7 @@ watch(
|
||||
{ immediate: true }
|
||||
);
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
() => inputValue.value,
|
||||
val => val && setVal(),
|
||||
{ immediate: true }
|
||||
);
|
||||
@@ -151,8 +144,8 @@ watch(
|
||||
</template>
|
||||
|
||||
<el-input
|
||||
class="px-2 pt-2"
|
||||
v-model="filterValue"
|
||||
class="px-2 pt-2"
|
||||
placeholder="搜索图标"
|
||||
clearable
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { iconType } from "./types";
|
||||
import { h, defineComponent, Component } from "vue";
|
||||
import type { iconType } from "./types";
|
||||
import { h, defineComponent, type Component } from "vue";
|
||||
import { IconifyIconOnline, IconifyIconOffline, FontIcon } from "../index";
|
||||
|
||||
/**
|
||||
@@ -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 attrs ? h(icon, { ...attrs }) : icon;
|
||||
} 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;
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@ import {
|
||||
watch,
|
||||
nextTick,
|
||||
computed,
|
||||
PropType,
|
||||
type PropType,
|
||||
defineComponent
|
||||
} from "vue";
|
||||
import "./index.scss";
|
||||
import propTypes from "@/utils/propTypes";
|
||||
import { isString, cloneDeep } from "@pureadmin/utils";
|
||||
import QRCode, { QRCodeRenderersOptions } from "qrcode";
|
||||
import QRCode, { type QRCodeRenderersOptions } from "qrcode";
|
||||
import RefreshRight from "@iconify-icons/ep/refresh-right";
|
||||
|
||||
interface QrcodeLogo {
|
||||
|
||||
@@ -498,16 +498,16 @@ defineExpose({
|
||||
<template>
|
||||
<div :ref="'wrap' + props.classOption['key']">
|
||||
<div
|
||||
:style="leftSwitch"
|
||||
v-if="navigation"
|
||||
:style="leftSwitch"
|
||||
:class="leftSwitchClass"
|
||||
@click="leftSwitchClick"
|
||||
>
|
||||
<slot name="left-switch" />
|
||||
</div>
|
||||
<div
|
||||
:style="rightSwitch"
|
||||
v-if="navigation"
|
||||
:style="rightSwitch"
|
||||
:class="rightSwitchClass"
|
||||
@click="rightSwitchClick"
|
||||
>
|
||||
@@ -526,7 +526,7 @@ defineExpose({
|
||||
<div :ref="'slotList' + props.classOption['key']" :style="float">
|
||||
<slot />
|
||||
</div>
|
||||
<div v-html="copyHtml" :style="float" />
|
||||
<div :style="float" v-html="copyHtml" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -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;
|
||||
/** 是否禁用 */
|
||||
|
||||
@@ -55,7 +55,6 @@ export default defineComponent({
|
||||
emits: ["selectedVal"],
|
||||
setup(props, { emit }) {
|
||||
const instance = getCurrentInstance();
|
||||
// eslint-disable-next-line vue/no-setup-props-destructure
|
||||
const currentValue = props.value;
|
||||
|
||||
const rateDisabled = computed(() => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineComponent, ref, unref, computed, PropType } from "vue";
|
||||
import { defineComponent, ref, unref, computed, type PropType } from "vue";
|
||||
import resizer from "./resizer";
|
||||
import "./index.css";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { App } from "vue";
|
||||
import type { App } from "vue";
|
||||
import axios from "axios";
|
||||
|
||||
let config: object = {};
|
||||
|
||||
@@ -50,6 +50,12 @@ const getSectionStyle = computed(() => {
|
||||
});
|
||||
|
||||
const transitionMain = defineComponent({
|
||||
props: {
|
||||
route: {
|
||||
type: undefined,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
render() {
|
||||
const transitionName =
|
||||
transitions.value(this.route)?.name || "fade-transform";
|
||||
@@ -72,12 +78,6 @@ const transitionMain = defineComponent({
|
||||
default: () => [this.$slots.default()]
|
||||
}
|
||||
);
|
||||
},
|
||||
props: {
|
||||
route: {
|
||||
type: undefined,
|
||||
required: true
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -92,7 +92,8 @@ const transitionMain = defineComponent({
|
||||
<el-scrollbar
|
||||
v-if="props.fixedHeader"
|
||||
:wrap-style="{
|
||||
display: 'flex'
|
||||
display: 'flex',
|
||||
'flex-wrap': 'wrap'
|
||||
}"
|
||||
:view-style="{
|
||||
display: 'flex',
|
||||
@@ -117,8 +118,8 @@ const transitionMain = defineComponent({
|
||||
/>
|
||||
</keep-alive>
|
||||
<component
|
||||
v-else
|
||||
:is="Component"
|
||||
v-else
|
||||
:key="route.fullPath"
|
||||
class="main-content"
|
||||
/>
|
||||
@@ -139,8 +140,8 @@ const transitionMain = defineComponent({
|
||||
/>
|
||||
</keep-alive>
|
||||
<component
|
||||
v-else
|
||||
:is="Component"
|
||||
v-else
|
||||
:key="route.fullPath"
|
||||
class="main-content"
|
||||
/>
|
||||
|
||||
@@ -62,8 +62,8 @@ const { t, locale, translationCh, translationEn } = useTranslationLang();
|
||||
@click="translationCh"
|
||||
>
|
||||
<IconifyIconOffline
|
||||
class="check-zh"
|
||||
v-show="locale === 'zh'"
|
||||
class="check-zh"
|
||||
:icon="Check"
|
||||
/>
|
||||
简体中文
|
||||
@@ -73,7 +73,7 @@ const { t, locale, translationCh, translationEn } = useTranslationLang();
|
||||
:class="['dark:!text-white', getDropdownItemClass(locale, 'en')]"
|
||||
@click="translationEn"
|
||||
>
|
||||
<span class="check-en" v-show="locale === 'en'">
|
||||
<span v-show="locale === 'en'" class="check-en">
|
||||
<IconifyIconOffline :icon="Check" />
|
||||
</span>
|
||||
English
|
||||
|
||||
@@ -23,8 +23,8 @@ notices.value.map(v => (noticesNum.value += v.list.length));
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-tabs
|
||||
:stretch="true"
|
||||
v-model="activeKey"
|
||||
:stretch="true"
|
||||
class="dropdown-tabs"
|
||||
:style="{ width: notices.length === 0 ? '200px' : '330px' }"
|
||||
>
|
||||
|
||||
@@ -15,8 +15,8 @@ const props = defineProps({
|
||||
<div v-if="props.list.length">
|
||||
<NoticeItem
|
||||
v-for="(item, index) in props.list"
|
||||
:noticeItem="item"
|
||||
:key="index"
|
||||
:noticeItem="item"
|
||||
/>
|
||||
</div>
|
||||
<el-empty v-else description="暂无数据" />
|
||||
|
||||
@@ -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: 280px;
|
||||
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>
|
||||
|
||||
@@ -146,9 +146,9 @@ onKeyStroke("ArrowDown", handleDown);
|
||||
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="show"
|
||||
top="5vh"
|
||||
class="pure-search-dialog"
|
||||
v-model="show"
|
||||
:show-close="false"
|
||||
:width="device === 'mobile' ? '80vw' : '40vw'"
|
||||
:before-close="handleClose"
|
||||
@@ -161,8 +161,8 @@ onKeyStroke("ArrowDown", handleDown);
|
||||
>
|
||||
<el-input
|
||||
ref="inputRef"
|
||||
size="large"
|
||||
v-model="keyword"
|
||||
size="large"
|
||||
clearable
|
||||
placeholder="搜索菜单(中文模式下支持拼音搜索)"
|
||||
@input="handleSearch"
|
||||
|
||||
@@ -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;
|
||||
@@ -194,7 +194,8 @@ function setLayoutModel(layout: string) {
|
||||
theme: layoutTheme.value.theme,
|
||||
darkMode: $storage.layout?.darkMode,
|
||||
sidebarStatus: $storage.layout?.sidebarStatus,
|
||||
epThemeColor: $storage.layout?.epThemeColor
|
||||
epThemeColor: $storage.layout?.epThemeColor,
|
||||
themeColor: layoutTheme.value.theme
|
||||
};
|
||||
useAppStoreHook().setLayout(layout);
|
||||
}
|
||||
@@ -234,185 +235,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
|
||||
:class="layoutTheme.layout === 'vertical' ? 'is-select' : ''"
|
||||
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
|
||||
:class="layoutTheme.layout === 'horizontal' ? 'is-select' : ''"
|
||||
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
|
||||
:class="layoutTheme.layout === 'mix' ? 'is-select' : ''"
|
||||
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"
|
||||
:key="index"
|
||||
v-show="showThemeColors(item.themeColor)"
|
||||
: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 +391,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(1) {
|
||||
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 +486,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>
|
||||
|
||||
@@ -108,9 +108,9 @@ watch(
|
||||
<el-breadcrumb class="!leading-[50px] select-none" separator="/">
|
||||
<transition-group name="breadcrumb">
|
||||
<el-breadcrumb-item
|
||||
class="!inline !items-stretch"
|
||||
v-for="item in levelList"
|
||||
:key="item.path"
|
||||
class="!inline !items-stretch"
|
||||
>
|
||||
<a @click.prevent="handleLink(item)">
|
||||
{{ transformI18n(item.meta.title) }}
|
||||
|
||||
@@ -48,8 +48,8 @@ nextTick(() => {
|
||||
<span>{{ title }}</span>
|
||||
</div>
|
||||
<el-menu
|
||||
router
|
||||
ref="menuRef"
|
||||
router
|
||||
mode="horizontal"
|
||||
class="horizontal-header-menu"
|
||||
:default-active="defaultActive"
|
||||
@@ -78,7 +78,7 @@ nextTick(() => {
|
||||
:class="['dark:!text-white', getDropdownItemClass(locale, 'zh')]"
|
||||
@click="translationCh"
|
||||
>
|
||||
<span class="check-zh" v-show="locale === 'zh'">
|
||||
<span v-show="locale === 'zh'" class="check-zh">
|
||||
<IconifyIconOffline :icon="Check" />
|
||||
</span>
|
||||
简体中文
|
||||
@@ -88,7 +88,7 @@ nextTick(() => {
|
||||
:class="['dark:!text-white', getDropdownItemClass(locale, 'en')]"
|
||||
@click="translationEn"
|
||||
>
|
||||
<span class="check-en" v-show="locale === 'en'">
|
||||
<span v-show="locale === 'en'" class="check-en">
|
||||
<IconifyIconOffline :icon="Check" />
|
||||
</span>
|
||||
English
|
||||
|
||||
@@ -66,6 +66,6 @@ const toggleClick = () => {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
box-shadow: 0 0 6px -2px var(--el-color-primary);
|
||||
box-shadow: 0 0 6px -3px var(--el-color-primary);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -61,12 +61,12 @@ watch(
|
||||
<template>
|
||||
<div
|
||||
v-if="device !== 'mobile'"
|
||||
class="horizontal-header"
|
||||
v-loading="usePermissionStoreHook().wholeMenus.length === 0"
|
||||
class="horizontal-header"
|
||||
>
|
||||
<el-menu
|
||||
router
|
||||
ref="menuRef"
|
||||
router
|
||||
mode="horizontal"
|
||||
class="horizontal-header-menu"
|
||||
:default-active="defaultActive"
|
||||
@@ -111,7 +111,7 @@ watch(
|
||||
:class="['dark:!text-white', getDropdownItemClass(locale, 'zh')]"
|
||||
@click="translationCh"
|
||||
>
|
||||
<span class="check-zh" v-show="locale === 'zh'">
|
||||
<span v-show="locale === 'zh'" class="check-zh">
|
||||
<IconifyIconOffline :icon="Check" />
|
||||
</span>
|
||||
简体中文
|
||||
@@ -121,7 +121,7 @@ watch(
|
||||
:class="['dark:!text-white', getDropdownItemClass(locale, 'en')]"
|
||||
@click="translationEn"
|
||||
>
|
||||
<span class="check-en" v-show="locale === 'en'">
|
||||
<span v-show="locale === 'en'" class="check-en">
|
||||
<IconifyIconOffline :icon="Check" />
|
||||
</span>
|
||||
English
|
||||
|
||||
@@ -60,8 +60,8 @@ const getsubMenuIconStyle = computed((): CSSProperties => {
|
||||
layout.value === "horizontal"
|
||||
? "0 5px 0 0"
|
||||
: isCollapse.value
|
||||
? "0 auto"
|
||||
: "0 5px 0 0"
|
||||
? "0 auto"
|
||||
: "0 5px 0 0"
|
||||
};
|
||||
});
|
||||
|
||||
@@ -96,8 +96,8 @@ const getSubMenuDivStyle = computed((): any => {
|
||||
item?.parentId === null
|
||||
? "center"
|
||||
: layout.value === "mix" && item?.pathList?.length === 2
|
||||
? "center"
|
||||
: ""
|
||||
? "center"
|
||||
: ""
|
||||
};
|
||||
};
|
||||
});
|
||||
@@ -275,7 +275,6 @@ function resolvePath(routePath) {
|
||||
{{ transformI18n(props.item.meta.title) }}
|
||||
</span>
|
||||
<div
|
||||
:style="getSubMenuDivStyle(props.item)"
|
||||
v-if="
|
||||
!(
|
||||
isCollapse &&
|
||||
@@ -283,6 +282,7 @@ function resolvePath(routePath) {
|
||||
props.item.parentId === null
|
||||
)
|
||||
"
|
||||
:style="getSubMenuDivStyle(props.item)"
|
||||
>
|
||||
<el-tooltip
|
||||
v-if="layout !== 'horizontal'"
|
||||
|
||||
@@ -518,15 +518,15 @@ onBeforeUnmount(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="containerDom" class="tags-view" v-if="!showTags">
|
||||
<div v-if="!showTags" ref="containerDom" class="tags-view">
|
||||
<span v-show="isShowArrow" class="arrow-left">
|
||||
<IconifyIconOffline :icon="ArrowLeftSLine" @click="handleScroll(200)" />
|
||||
</span>
|
||||
<div ref="scrollbarDom" class="scroll-container">
|
||||
<div class="tab select-none" ref="tabDom" :style="getTabStyle">
|
||||
<div ref="tabDom" class="tab select-none" :style="getTabStyle">
|
||||
<div
|
||||
:ref="'dynamic' + index"
|
||||
v-for="(item, index) in multiTags"
|
||||
:ref="'dynamic' + index"
|
||||
:key="index"
|
||||
:class="['scroll-item is-closable', linkIsActive(item)]"
|
||||
@contextmenu.prevent="openMenu(item, $event)"
|
||||
@@ -550,8 +550,8 @@ onBeforeUnmount(() => {
|
||||
<IconifyIconOffline :icon="CloseBold" />
|
||||
</span>
|
||||
<div
|
||||
:ref="'schedule' + index"
|
||||
v-if="showModel !== 'card'"
|
||||
:ref="'schedule' + index"
|
||||
:class="[scheduleIsActive(item)]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -46,11 +46,11 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="frame"
|
||||
v-loading="loading"
|
||||
class="frame"
|
||||
:element-loading-text="t('status.hsLoad')"
|
||||
>
|
||||
<iframe :src="frameSrc" class="frame-iframe" ref="frameRef" />
|
||||
<iframe ref="frameRef" :src="frameSrc" class="frame-iframe" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import { ref } from "vue";
|
||||
import { getConfig } from "@/config";
|
||||
import { useLayout } from "./useLayout";
|
||||
import { themeColorsType } from "../types";
|
||||
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,
|
||||
@@ -13,42 +18,53 @@ import {
|
||||
export function useDataThemeChange() {
|
||||
const { layoutTheme, layout } = useLayout();
|
||||
const themeColors = ref<Array<themeColorsType>>([
|
||||
/* 道奇蓝(默认) */
|
||||
{ color: "#1b2a47", themeColor: "default" },
|
||||
/* 亮白色 */
|
||||
{ color: "#ffffff", themeColor: "light" },
|
||||
/* 道奇蓝 */
|
||||
{ color: "#1b2a47", themeColor: "default" },
|
||||
/* 深紫罗兰色 */
|
||||
{ color: "#722ed1", themeColor: "saucePurple" },
|
||||
/* 深粉色 */
|
||||
{ color: "#eb2f96", themeColor: "pink" },
|
||||
/* 猩红色 */
|
||||
{ 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" }
|
||||
{ color: "#52c41a", themeColor: "auroraGreen" }
|
||||
]);
|
||||
|
||||
const { $storage } = useGlobal<GlobalPropertiesApi>();
|
||||
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") {
|
||||
function setLayoutThemeColor(
|
||||
theme = getConfig().Theme ?? "light",
|
||||
isClick = true
|
||||
) {
|
||||
layoutTheme.value.theme = theme;
|
||||
toggleTheme({
|
||||
scopeName: `layout-theme-${theme}`
|
||||
});
|
||||
// 如果非isClick,保留之前的themeColor
|
||||
const storageThemeColor = $storage.layout.themeColor;
|
||||
$storage.layout = {
|
||||
layout: layout.value,
|
||||
theme,
|
||||
darkMode: dataTheme.value,
|
||||
sidebarStatus: $storage.layout?.sidebarStatus,
|
||||
epThemeColor: $storage.layout?.epThemeColor
|
||||
epThemeColor: $storage.layout?.epThemeColor,
|
||||
themeColor: isClick ? theme : storageThemeColor
|
||||
};
|
||||
|
||||
if (theme === "default" || theme === "light") {
|
||||
@@ -78,27 +94,46 @@ export function useDataThemeChange() {
|
||||
}
|
||||
};
|
||||
|
||||
/** 日间、夜间主题切换 */
|
||||
/** 亮色、暗色整体风格切换 */
|
||||
function dataThemeChange() {
|
||||
/* 如果当前是light夜间主题,默认切换到default主题 */
|
||||
if (useEpThemeStoreHook().epTheme === "light" && dataTheme.value) {
|
||||
setLayoutThemeColor("default");
|
||||
setLayoutThemeColor("default", false);
|
||||
} else {
|
||||
setLayoutThemeColor(useEpThemeStoreHook().epTheme);
|
||||
setLayoutThemeColor(useEpThemeStoreHook().epTheme, false);
|
||||
}
|
||||
|
||||
if (dataTheme.value) {
|
||||
document.documentElement.classList.add("dark");
|
||||
} else {
|
||||
if ($storage.layout.themeColor === "light") {
|
||||
setLayoutThemeColor("light", false);
|
||||
}
|
||||
document.documentElement.classList.remove("dark");
|
||||
}
|
||||
}
|
||||
|
||||
/** 清空缓存并返回登录页 */
|
||||
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
|
||||
|
||||
@@ -24,10 +24,11 @@ export function useLayout() {
|
||||
if (!$storage.layout) {
|
||||
$storage.layout = {
|
||||
layout: $config?.Layout ?? "vertical",
|
||||
theme: $config?.Theme ?? "default",
|
||||
theme: $config?.Theme ?? "light",
|
||||
darkMode: $config?.DarkMode ?? false,
|
||||
sidebarStatus: $config?.SidebarStatus ?? true,
|
||||
epThemeColor: $config?.EpThemeColor ?? "#409EFF"
|
||||
epThemeColor: $config?.EpThemeColor ?? "#409EFF",
|
||||
themeColor: $config?.Theme ?? "light"
|
||||
};
|
||||
}
|
||||
/** 灰色模式、色弱模式、隐藏标签页 */
|
||||
|
||||
@@ -2,10 +2,10 @@ import { storeToRefs } from "pinia";
|
||||
import { getConfig } from "@/config";
|
||||
import { useRouter } from "vue-router";
|
||||
import { emitter } from "@/utils/mitt";
|
||||
import { routeMetaType } from "../types";
|
||||
import userAvatar from "@/assets/user.jpg";
|
||||
import { getTopMenu } from "@/router/utils";
|
||||
import { useGlobal } from "@pureadmin/utils";
|
||||
import type { routeMetaType } from "../types";
|
||||
import { transformI18n } from "@/plugins/i18n";
|
||||
import { router, remainingPaths } from "@/router";
|
||||
import { computed, type CSSProperties } from "vue";
|
||||
|
||||
@@ -4,10 +4,10 @@ import {
|
||||
computed,
|
||||
reactive,
|
||||
onMounted,
|
||||
CSSProperties,
|
||||
type CSSProperties,
|
||||
getCurrentInstance
|
||||
} from "vue";
|
||||
import { tagsViewsType } from "../types";
|
||||
import type { tagsViewsType } from "../types";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { transformI18n, $t } from "@/plugins/i18n";
|
||||
import { responsiveStorageNameSpace } from "@/config";
|
||||
|
||||
@@ -68,7 +68,8 @@ function setTheme(layoutModel: string) {
|
||||
theme: $storage.layout?.theme,
|
||||
darkMode: $storage.layout?.darkMode,
|
||||
sidebarStatus: $storage.layout?.sidebarStatus,
|
||||
epThemeColor: $storage.layout?.epThemeColor
|
||||
epThemeColor: $storage.layout?.epThemeColor,
|
||||
themeColor: $storage.layout?.themeColor
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,23 @@
|
||||
* @description ⚠️:此文件仅供主题插件使用,请不要在此文件中导出别的工具函数(仅在页面加载前运行)
|
||||
*/
|
||||
|
||||
import { type multipleScopeVarsOptions } from "@pureadmin/theme";
|
||||
import type { multipleScopeVarsOptions } from "@pureadmin/theme";
|
||||
|
||||
/** 预设主题色 */
|
||||
const themeColors = {
|
||||
/* 亮白色 */
|
||||
light: {
|
||||
subMenuActiveText: "#000000d9",
|
||||
menuBg: "#fff",
|
||||
menuHover: "#e0ebf6",
|
||||
subMenuBg: "#fff",
|
||||
subMenuActiveBg: "#e0ebf6",
|
||||
menuText: "rgb(0 0 0 / 60%)",
|
||||
sidebarLogo: "#fff",
|
||||
menuTitleHover: "#000",
|
||||
menuActiveBefore: "#4091f7"
|
||||
},
|
||||
/* 道奇蓝 */
|
||||
default: {
|
||||
subMenuActiveText: "#fff",
|
||||
menuBg: "#001529",
|
||||
@@ -17,72 +30,19 @@ const themeColors = {
|
||||
menuTitleHover: "#fff",
|
||||
menuActiveBefore: "#4091f7"
|
||||
},
|
||||
light: {
|
||||
subMenuActiveText: "#409eff",
|
||||
menuBg: "#fff",
|
||||
menuHover: "#e0ebf6",
|
||||
subMenuBg: "#fff",
|
||||
subMenuActiveBg: "#e0ebf6",
|
||||
menuText: "#7a80b4",
|
||||
sidebarLogo: "#fff",
|
||||
menuTitleHover: "#000",
|
||||
menuActiveBefore: "#4091f7"
|
||||
},
|
||||
dusk: {
|
||||
/* 深紫罗兰色 */
|
||||
saucePurple: {
|
||||
subMenuActiveText: "#fff",
|
||||
menuBg: "#2a0608",
|
||||
menuHover: "#e13c39",
|
||||
menuBg: "#130824",
|
||||
menuHover: "#693ac9",
|
||||
subMenuBg: "#000",
|
||||
subMenuActiveBg: "#e13c39",
|
||||
menuText: "rgb(254 254 254 / 65.1%)",
|
||||
sidebarLogo: "#42090c",
|
||||
menuTitleHover: "#fff",
|
||||
menuActiveBefore: "#e13c39"
|
||||
},
|
||||
volcano: {
|
||||
subMenuActiveText: "#fff",
|
||||
menuBg: "#2b0e05",
|
||||
menuHover: "#e85f33",
|
||||
subMenuBg: "#0f0603",
|
||||
subMenuActiveBg: "#e85f33",
|
||||
menuText: "rgb(254 254 254 / 65%)",
|
||||
sidebarLogo: "#441708",
|
||||
menuTitleHover: "#fff",
|
||||
menuActiveBefore: "#e85f33"
|
||||
},
|
||||
yellow: {
|
||||
subMenuActiveText: "#d25f00",
|
||||
menuBg: "#2b2503",
|
||||
menuHover: "#f6da4d",
|
||||
subMenuBg: "#0f0603",
|
||||
subMenuActiveBg: "#f6da4d",
|
||||
menuText: "rgb(254 254 254 / 65%)",
|
||||
sidebarLogo: "#443b05",
|
||||
menuTitleHover: "#fff",
|
||||
menuActiveBefore: "#f6da4d"
|
||||
},
|
||||
mingQing: {
|
||||
subMenuActiveText: "#fff",
|
||||
menuBg: "#032121",
|
||||
menuHover: "#59bfc1",
|
||||
subMenuBg: "#000",
|
||||
subMenuActiveBg: "#59bfc1",
|
||||
subMenuActiveBg: "#693ac9",
|
||||
menuText: "#7a80b4",
|
||||
sidebarLogo: "#053434",
|
||||
sidebarLogo: "#1f0c38",
|
||||
menuTitleHover: "#fff",
|
||||
menuActiveBefore: "#59bfc1"
|
||||
},
|
||||
auroraGreen: {
|
||||
subMenuActiveText: "#fff",
|
||||
menuBg: "#0b1e15",
|
||||
menuHover: "#60ac80",
|
||||
subMenuBg: "#000",
|
||||
subMenuActiveBg: "#60ac80",
|
||||
menuText: "#7a80b4",
|
||||
sidebarLogo: "#112f21",
|
||||
menuTitleHover: "#fff",
|
||||
menuActiveBefore: "#60ac80"
|
||||
menuActiveBefore: "#693ac9"
|
||||
},
|
||||
/* 深粉色 */
|
||||
pink: {
|
||||
subMenuActiveText: "#fff",
|
||||
menuBg: "#28081a",
|
||||
@@ -94,16 +54,53 @@ const themeColors = {
|
||||
menuTitleHover: "#fff",
|
||||
menuActiveBefore: "#d84493"
|
||||
},
|
||||
saucePurple: {
|
||||
/* 猩红色 */
|
||||
dusk: {
|
||||
subMenuActiveText: "#fff",
|
||||
menuBg: "#130824",
|
||||
menuHover: "#693ac9",
|
||||
menuBg: "#2a0608",
|
||||
menuHover: "#e13c39",
|
||||
subMenuBg: "#000",
|
||||
subMenuActiveBg: "#693ac9",
|
||||
menuText: "#7a80b4",
|
||||
sidebarLogo: "#1f0c38",
|
||||
subMenuActiveBg: "#e13c39",
|
||||
menuText: "rgb(254 254 254 / 65.1%)",
|
||||
sidebarLogo: "#42090c",
|
||||
menuTitleHover: "#fff",
|
||||
menuActiveBefore: "#693ac9"
|
||||
menuActiveBefore: "#e13c39"
|
||||
},
|
||||
/* 橙红色 */
|
||||
volcano: {
|
||||
subMenuActiveText: "#fff",
|
||||
menuBg: "#2b0e05",
|
||||
menuHover: "#e85f33",
|
||||
subMenuBg: "#0f0603",
|
||||
subMenuActiveBg: "#e85f33",
|
||||
menuText: "rgb(254 254 254 / 65%)",
|
||||
sidebarLogo: "#441708",
|
||||
menuTitleHover: "#fff",
|
||||
menuActiveBefore: "#e85f33"
|
||||
},
|
||||
/* 绿宝石 */
|
||||
mingQing: {
|
||||
subMenuActiveText: "#fff",
|
||||
menuBg: "#032121",
|
||||
menuHover: "#59bfc1",
|
||||
subMenuBg: "#000",
|
||||
subMenuActiveBg: "#59bfc1",
|
||||
menuText: "#7a80b4",
|
||||
sidebarLogo: "#053434",
|
||||
menuTitleHover: "#fff",
|
||||
menuActiveBefore: "#59bfc1"
|
||||
},
|
||||
/* 酸橙绿 */
|
||||
auroraGreen: {
|
||||
subMenuActiveText: "#fff",
|
||||
menuBg: "#0b1e15",
|
||||
menuHover: "#60ac80",
|
||||
subMenuBg: "#000",
|
||||
subMenuActiveBg: "#60ac80",
|
||||
menuText: "#7a80b4",
|
||||
sidebarLogo: "#112f21",
|
||||
menuTitleHover: "#fff",
|
||||
menuActiveBefore: "#60ac80"
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
10
src/main.ts
10
src/main.ts
@@ -4,9 +4,9 @@ import { setupStore } from "@/store";
|
||||
import ElementPlus from "element-plus";
|
||||
import { useI18n } from "@/plugins/i18n";
|
||||
import { getPlatformConfig } from "./config";
|
||||
import { createApp, Directive } from "vue";
|
||||
import { MotionPlugin } from "@vueuse/motion";
|
||||
import { useEcharts } from "@/plugins/echarts";
|
||||
import { createApp, type Directive } from "vue";
|
||||
import { injectResponsiveStorage } from "@/utils/responsive";
|
||||
|
||||
import Table from "@pureadmin/table";
|
||||
@@ -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);
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import { createProdMockServer } from "vite-plugin-mock/es/createProdMockServer";
|
||||
|
||||
const modules: Record<string, any> = import.meta.glob("../mock/*.ts", {
|
||||
eager: true
|
||||
});
|
||||
const mockModules = [];
|
||||
|
||||
Object.keys(modules).forEach(key => {
|
||||
mockModules.push(...modules[key].default);
|
||||
});
|
||||
|
||||
export function setupProdMockServer() {
|
||||
createProdMockServer(mockModules);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { App, Component } from "vue";
|
||||
import type { App, Component } from "vue";
|
||||
import {
|
||||
ElTag,
|
||||
ElAffix,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// 多组件库的国际化和本地项目国际化兼容
|
||||
import { App, WritableComputedRef } from "vue";
|
||||
import { type I18n, createI18n } from "vue-i18n";
|
||||
import type { App, WritableComputedRef } from "vue";
|
||||
import { responsiveStorageNameSpace } from "@/config";
|
||||
import { storageLocal, isObject } from "@pureadmin/utils";
|
||||
|
||||
@@ -8,16 +8,20 @@ import { storageLocal, isObject } from "@pureadmin/utils";
|
||||
import enLocale from "element-plus/dist/locale/en.mjs";
|
||||
import zhLocale from "element-plus/dist/locale/zh-cn.mjs";
|
||||
|
||||
function siphonI18n(prefix = "zh-CN") {
|
||||
return Object.fromEntries(
|
||||
const siphonI18n = (function () {
|
||||
// 仅初始化一次国际化配置
|
||||
let cache = Object.fromEntries(
|
||||
Object.entries(
|
||||
import.meta.glob("../../locales/*.y(a)?ml", { eager: true })
|
||||
).map(([key, value]: any) => {
|
||||
const matched = key.match(/([A-Za-z0-9-_]+)\./i)[1];
|
||||
return [matched, value.default];
|
||||
})
|
||||
)[prefix];
|
||||
}
|
||||
);
|
||||
return (prefix = "zh-CN") => {
|
||||
return cache[prefix];
|
||||
};
|
||||
})();
|
||||
|
||||
export const localesConfigs = {
|
||||
zh: {
|
||||
@@ -33,7 +37,7 @@ export const localesConfigs = {
|
||||
/** 获取对象中所有嵌套对象的key键,并将它们用点号分割组成字符串 */
|
||||
function getObjectKeys(obj) {
|
||||
const stack = [];
|
||||
const keys = [];
|
||||
const keys: Set<string> = new Set();
|
||||
|
||||
stack.push({ obj, key: "" });
|
||||
|
||||
@@ -46,7 +50,7 @@ function getObjectKeys(obj) {
|
||||
if (obj[k] && isObject(obj[k])) {
|
||||
stack.push({ obj: obj[k], key: newKey });
|
||||
} else {
|
||||
keys.push(newKey);
|
||||
keys.add(newKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,6 +58,17 @@ function getObjectKeys(obj) {
|
||||
return keys;
|
||||
}
|
||||
|
||||
/** 将展开的key缓存 */
|
||||
const keysCache: Map<string, Set<string>> = new Map();
|
||||
const flatI18n = (prefix = "zh-CN") => {
|
||||
let cache = keysCache.get(prefix);
|
||||
if (!cache) {
|
||||
cache = getObjectKeys(siphonI18n(prefix));
|
||||
keysCache.set(prefix, cache);
|
||||
}
|
||||
return cache;
|
||||
};
|
||||
|
||||
/**
|
||||
* 国际化转换工具函数(自动读取根目录locales文件夹下文件进行国际化匹配)
|
||||
* @param message message
|
||||
@@ -73,9 +88,9 @@ export function transformI18n(message: any = "") {
|
||||
|
||||
const key = message.match(/(\S*)\./)?.input;
|
||||
|
||||
if (key && getObjectKeys(siphonI18n("zh-CN")).find(item => item === key)) {
|
||||
if (key && flatI18n("zh-CN").has(key)) {
|
||||
return i18n.global.t.call(i18n.global.locale, message);
|
||||
} else if (!key && Object.keys(siphonI18n("zh-CN")).includes(message)) {
|
||||
} else if (!key && Object.hasOwn(siphonI18n("zh-CN"), message)) {
|
||||
// 兼容非嵌套形式的国际化写法
|
||||
return i18n.global.t.call(i18n.global.locale, message);
|
||||
} else {
|
||||
|
||||
@@ -20,10 +20,10 @@ import {
|
||||
formatFlatteningRoutes
|
||||
} from "./utils";
|
||||
import {
|
||||
Router,
|
||||
type Router,
|
||||
createRouter,
|
||||
RouteRecordRaw,
|
||||
RouteComponent
|
||||
type RouteRecordRaw,
|
||||
type RouteComponent
|
||||
} from "vue-router";
|
||||
import {
|
||||
type DataInfo,
|
||||
|
||||
@@ -183,4 +183,4 @@ export default {
|
||||
}
|
||||
}
|
||||
]
|
||||
} as RouteConfigsTable;
|
||||
} satisfies RouteConfigsTable;
|
||||
|
||||
@@ -18,4 +18,4 @@ export default {
|
||||
}
|
||||
}
|
||||
]
|
||||
} as RouteConfigsTable;
|
||||
} satisfies RouteConfigsTable;
|
||||
|
||||
@@ -171,4 +171,4 @@ export default {
|
||||
}
|
||||
}
|
||||
]
|
||||
} as RouteConfigsTable;
|
||||
} satisfies RouteConfigsTable;
|
||||
|
||||
@@ -20,4 +20,4 @@ export default {
|
||||
}
|
||||
}
|
||||
]
|
||||
} as RouteConfigsTable;
|
||||
} satisfies RouteConfigsTable;
|
||||
|
||||
@@ -36,4 +36,4 @@ export default {
|
||||
}
|
||||
}
|
||||
]
|
||||
} as RouteConfigsTable;
|
||||
} satisfies RouteConfigsTable;
|
||||
|
||||
@@ -19,4 +19,4 @@ export default {
|
||||
}
|
||||
}
|
||||
]
|
||||
} as RouteConfigsTable;
|
||||
} satisfies RouteConfigsTable;
|
||||
|
||||
@@ -22,4 +22,4 @@ export default {
|
||||
}
|
||||
}
|
||||
]
|
||||
} as RouteConfigsTable;
|
||||
} satisfies RouteConfigsTable;
|
||||
|
||||
@@ -19,4 +19,4 @@ export default {
|
||||
}
|
||||
}
|
||||
]
|
||||
} as RouteConfigsTable;
|
||||
} satisfies RouteConfigsTable;
|
||||
|
||||
@@ -24,4 +24,4 @@ export default {
|
||||
}
|
||||
}
|
||||
]
|
||||
} as RouteConfigsTable;
|
||||
} satisfies RouteConfigsTable;
|
||||
|
||||
@@ -21,4 +21,4 @@ export default {
|
||||
}
|
||||
}
|
||||
]
|
||||
} as RouteConfigsTable;
|
||||
} satisfies RouteConfigsTable;
|
||||
|
||||
@@ -19,4 +19,4 @@ export default {
|
||||
}
|
||||
}
|
||||
]
|
||||
} as RouteConfigsTable;
|
||||
} satisfies RouteConfigsTable;
|
||||
|
||||
@@ -79,4 +79,4 @@ export default {
|
||||
}
|
||||
}
|
||||
]
|
||||
} as RouteConfigsTable;
|
||||
} satisfies RouteConfigsTable;
|
||||
|
||||
@@ -21,4 +21,4 @@ export default {
|
||||
}
|
||||
}
|
||||
]
|
||||
} as RouteConfigsTable;
|
||||
} satisfies RouteConfigsTable;
|
||||
|
||||
@@ -21,4 +21,4 @@ export default {
|
||||
}
|
||||
}
|
||||
]
|
||||
} as RouteConfigsTable;
|
||||
} satisfies RouteConfigsTable;
|
||||
|
||||
@@ -21,4 +21,4 @@ export default {
|
||||
}
|
||||
}
|
||||
]
|
||||
} as RouteConfigsTable;
|
||||
} satisfies RouteConfigsTable;
|
||||
|
||||
@@ -39,4 +39,4 @@ export default [
|
||||
rank: 103
|
||||
}
|
||||
}
|
||||
] as Array<RouteConfigsTable>;
|
||||
] satisfies Array<RouteConfigsTable>;
|
||||
|
||||
@@ -27,4 +27,4 @@ export default {
|
||||
}
|
||||
}
|
||||
]
|
||||
} as RouteConfigsTable;
|
||||
} satisfies RouteConfigsTable;
|
||||
|
||||
@@ -28,4 +28,4 @@ export default {
|
||||
}
|
||||
}
|
||||
]
|
||||
} as RouteConfigsTable;
|
||||
} satisfies RouteConfigsTable;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
RouterHistory,
|
||||
RouteRecordRaw,
|
||||
RouteComponent,
|
||||
type RouterHistory,
|
||||
type RouteRecordRaw,
|
||||
type RouteComponent,
|
||||
createWebHistory,
|
||||
createWebHashHistory
|
||||
} from "vue-router";
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
isIncludeAllChildren
|
||||
} from "@pureadmin/utils";
|
||||
import { getConfig } from "@/config";
|
||||
import { menuType } from "@/layout/types";
|
||||
import type { menuType } from "@/layout/types";
|
||||
import { buildHierarchyTree } from "@/utils/tree";
|
||||
import { userKey, type DataInfo } from "@/utils/auth";
|
||||
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { store } from "@/store";
|
||||
import { appType } from "./types";
|
||||
import { defineStore } from "pinia";
|
||||
import type { appType } from "./types";
|
||||
import { getConfig, responsiveStorageNameSpace } from "@/config";
|
||||
import { deviceDetection, storageLocal } from "@pureadmin/utils";
|
||||
|
||||
|
||||
@@ -23,8 +23,6 @@ export const useEpThemeStore = defineStore({
|
||||
fill(state) {
|
||||
if (state.epTheme === "light") {
|
||||
return "#409eff";
|
||||
} else if (state.epTheme === "yellow") {
|
||||
return "#d25f00";
|
||||
} else {
|
||||
return "#fff";
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { store } from "@/store";
|
||||
import { routerArrays } from "@/layout/types";
|
||||
import { multiType, positionType } from "./types";
|
||||
import { responsiveStorageNameSpace } from "@/config";
|
||||
import type { multiType, positionType } from "./types";
|
||||
import { isEqual, isBoolean, isUrl, storageLocal } from "@pureadmin/utils";
|
||||
|
||||
export const useMultiTagsStore = defineStore({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { store } from "@/store";
|
||||
import { cacheType } from "./types";
|
||||
import type { cacheType } from "./types";
|
||||
import { constantMenus } from "@/router";
|
||||
import { useMultiTagsStoreHook } from "./multiTags";
|
||||
import { debounce, getKeyList } from "@pureadmin/utils";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { store } from "@/store";
|
||||
import { setType } from "./types";
|
||||
import { getConfig } from "@/config";
|
||||
import type { setType } from "./types";
|
||||
|
||||
export const useSettingStore = defineStore({
|
||||
id: "pure-setting",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RouteRecordName } from "vue-router";
|
||||
import type { RouteRecordName } from "vue-router";
|
||||
|
||||
export type cacheType = {
|
||||
mode: string;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { store } from "@/store";
|
||||
import { userType } from "./types";
|
||||
import type { userType } from "./types";
|
||||
import { routerArrays } from "@/layout/types";
|
||||
import { router, resetRouter } from "@/router";
|
||||
import { storageLocal } from "@pureadmin/utils";
|
||||
import { getLogin, refreshTokenApi } from "@/api/user";
|
||||
import { UserResult, RefreshTokenResult } from "@/api/user";
|
||||
import type { UserResult, RefreshTokenResult } from "@/api/user";
|
||||
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
|
||||
import { type DataInfo, setToken, removeToken, userKey } from "@/utils/auth";
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/* 灰色模式 */
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
overflow: hidden;
|
||||
font-size: 0;
|
||||
background: $menuBg;
|
||||
box-shadow: 0 0 1px #888;
|
||||
border-right: 1px solid var(--pure-border-color);
|
||||
|
||||
/* 展开动画 */
|
||||
transition: width var(--pure-transition-duration);
|
||||
@@ -193,7 +193,7 @@
|
||||
.el-menu .el-menu--inline .el-sub-menu__title,
|
||||
& .el-sub-menu .el-menu-item {
|
||||
min-width: $sideBarWidth !important;
|
||||
font-size: 12px;
|
||||
font-size: 14px;
|
||||
background-color: $subMenuBg !important;
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@
|
||||
|
||||
.el-menu-item {
|
||||
span {
|
||||
font-size: 12px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -271,7 +271,7 @@
|
||||
/* 子菜单中还有子菜单 */
|
||||
.el-menu .el-sub-menu__title {
|
||||
min-width: $sideBarWidth !important;
|
||||
font-size: 12px;
|
||||
font-size: 14px;
|
||||
background-color: $subMenuBg !important;
|
||||
}
|
||||
|
||||
@@ -334,7 +334,7 @@
|
||||
background-color: $subMenuBg;
|
||||
|
||||
span {
|
||||
font-size: 12px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,7 +352,7 @@
|
||||
/* 子菜单中还有子菜单 */
|
||||
.el-menu .el-sub-menu__title {
|
||||
min-width: $sideBarWidth !important;
|
||||
font-size: 12px;
|
||||
font-size: 14px;
|
||||
background-color: $subMenuBg !important;
|
||||
|
||||
&:hover {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import Axios, {
|
||||
AxiosInstance,
|
||||
AxiosRequestConfig,
|
||||
CustomParamsSerializer
|
||||
type AxiosInstance,
|
||||
type AxiosRequestConfig,
|
||||
type CustomParamsSerializer
|
||||
} from "axios";
|
||||
import {
|
||||
import type {
|
||||
PureHttpError,
|
||||
RequestMethods,
|
||||
PureHttpResponse,
|
||||
|
||||
2
src/utils/http/types.d.ts
vendored
2
src/utils/http/types.d.ts
vendored
@@ -1,4 +1,4 @@
|
||||
import Axios, {
|
||||
import type {
|
||||
Method,
|
||||
AxiosError,
|
||||
AxiosResponse,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import forage from "localforage";
|
||||
import { LocalForage, ProxyStorage, ExpiresData } from "./types.d";
|
||||
import type { LocalForage, ProxyStorage, ExpiresData } from "./types.d";
|
||||
|
||||
class StorageProxy implements ProxyStorage {
|
||||
protected storage: LocalForage;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type VNode } from "vue";
|
||||
import type { VNode } from "vue";
|
||||
import { isFunction } from "@pureadmin/utils";
|
||||
import { type MessageHandler, ElMessage } from "element-plus";
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ import type { CSSProperties, VNodeChild } from "vue";
|
||||
import {
|
||||
createTypes,
|
||||
toValidableType,
|
||||
VueTypesInterface,
|
||||
VueTypeValidableDef
|
||||
type VueTypesInterface,
|
||||
type VueTypeValidableDef
|
||||
} from "vue-types";
|
||||
|
||||
export type VueNode = VNodeChild | JSX.Element;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// 响应式storage
|
||||
import { App } from "vue";
|
||||
import type { App } from "vue";
|
||||
import Storage from "responsive-storage";
|
||||
import { routerArrays } from "@/layout/types";
|
||||
import { responsiveStorageNameSpace } from "@/config";
|
||||
@@ -15,11 +15,13 @@ export const injectResponsiveStorage = (app: App, config: PlatformConfigs) => {
|
||||
// layout模式以及主题
|
||||
layout: Storage.getData("layout", nameSpace) ?? {
|
||||
layout: config.Layout ?? "vertical",
|
||||
theme: config.Theme ?? "default",
|
||||
theme: config.Theme ?? "light",
|
||||
darkMode: config.DarkMode ?? false,
|
||||
sidebarStatus: config.SidebarStatus ?? true,
|
||||
epThemeColor: config.EpThemeColor ?? "#409EFF"
|
||||
epThemeColor: config.EpThemeColor ?? "#409EFF",
|
||||
themeColor: config.Theme ?? "light" // 主题色(对应项目配置中的主题色,与theme不同的是它不会受到亮色、暗色整体风格切换的影响,只会在手动点击主题色时改变)
|
||||
},
|
||||
// 项目配置-界面显示
|
||||
configure: Storage.getData("configure", nameSpace) ?? {
|
||||
grey: config.Grey ?? false,
|
||||
weak: config.Weak ?? false,
|
||||
|
||||
@@ -40,8 +40,8 @@ import { subBefore, getQueryMap } from "@pureadmin/utils";
|
||||
setToken(params);
|
||||
|
||||
// 删除不需要显示在 url 的参数
|
||||
delete params["roles"];
|
||||
delete params["accessToken"];
|
||||
delete params.roles;
|
||||
delete params.accessToken;
|
||||
|
||||
const newUrl = `${location.origin}${location.pathname}${subBefore(
|
||||
location.hash,
|
||||
|
||||
@@ -32,8 +32,8 @@ const handleChange = value => {
|
||||
<span class="imp">
|
||||
1. 二级联动(不带“全部”选项)
|
||||
<el-cascader
|
||||
:options="provinceAndCityData"
|
||||
v-model="selectedOptions1"
|
||||
:options="provinceAndCityData"
|
||||
@change="handleChange"
|
||||
/>
|
||||
</span>
|
||||
@@ -61,8 +61,8 @@ const handleChange = value => {
|
||||
<span class="imp">
|
||||
2. 二级联动(带有“全部”选项)
|
||||
<el-cascader
|
||||
:options="provinceAndCityDataPlus"
|
||||
v-model="selectedOptions3"
|
||||
:options="provinceAndCityDataPlus"
|
||||
@change="handleChange"
|
||||
/>
|
||||
</span>
|
||||
@@ -90,8 +90,8 @@ const handleChange = value => {
|
||||
<span class="imp">
|
||||
3. 三级联动(不带“全部”选项)
|
||||
<el-cascader
|
||||
:options="regionData"
|
||||
v-model="selectedOptions2"
|
||||
:options="regionData"
|
||||
@change="handleChange"
|
||||
/>
|
||||
</span>
|
||||
@@ -121,8 +121,8 @@ const handleChange = value => {
|
||||
<span class="imp">
|
||||
4. 三级联动(带"全部选项")
|
||||
<el-cascader
|
||||
:options="regionDataPlus"
|
||||
v-model="selectedOptions4"
|
||||
:options="regionDataPlus"
|
||||
@change="handleChange"
|
||||
/>
|
||||
</span>
|
||||
|
||||
@@ -62,13 +62,13 @@ function onReset() {
|
||||
<div class="mb-2">
|
||||
防抖指令(连续输入,只会执行第一次点击事件,立即执行)
|
||||
<el-input
|
||||
v-model="search"
|
||||
v-optimize="{
|
||||
event: 'input',
|
||||
fn: onInput,
|
||||
immediate: true,
|
||||
timeout: 1000
|
||||
}"
|
||||
v-model="search"
|
||||
class="!w-[200px]"
|
||||
clearable
|
||||
@clear="onInput"
|
||||
@@ -77,8 +77,8 @@ function onReset() {
|
||||
<div class="mb-2">
|
||||
防抖指令(连续输入,只会执行最后一次事件,延后执行)
|
||||
<el-input
|
||||
v-optimize="{ event: 'input', fn: onInputTwo, timeout: 400 }"
|
||||
v-model="searchTwo"
|
||||
v-optimize="{ event: 'input', fn: onInputTwo, timeout: 400 }"
|
||||
class="!w-[200px]"
|
||||
clearable
|
||||
/>
|
||||
@@ -86,13 +86,13 @@ function onReset() {
|
||||
<div>
|
||||
防抖指令(连续输入,只会执行最后一次事件,延后执行,传参用法)
|
||||
<el-input
|
||||
v-model="searchThree"
|
||||
v-optimize="{
|
||||
event: 'input',
|
||||
fn: onInputThree,
|
||||
timeout: 400,
|
||||
params: { name: '小明', sex: '男' }
|
||||
}"
|
||||
v-model="searchThree"
|
||||
class="!w-[200px]"
|
||||
clearable
|
||||
/>
|
||||
@@ -103,8 +103,8 @@ function onReset() {
|
||||
<div class="mb-2">
|
||||
节流指令(连续输入,每一秒只会执行一次事件)
|
||||
<el-input
|
||||
v-optimize:throttle="{ event: 'input', fn: onInputFour, timeout: 1000 }"
|
||||
v-model="searchFour"
|
||||
v-optimize:throttle="{ event: 'input', fn: onInputFour, timeout: 1000 }"
|
||||
class="!w-[200px]"
|
||||
clearable
|
||||
/>
|
||||
@@ -112,12 +112,12 @@ function onReset() {
|
||||
<div>
|
||||
节流指令(连续输入,每一秒只会执行一次事件,传参用法)
|
||||
<el-input
|
||||
v-model="searchFive"
|
||||
v-optimize:throttle="{
|
||||
event: 'input',
|
||||
fn: onInputFive,
|
||||
params: { name: '小明', sex: '男' }
|
||||
}"
|
||||
v-model="searchFive"
|
||||
class="!w-[200px]"
|
||||
clearable
|
||||
/>
|
||||
@@ -127,7 +127,7 @@ function onReset() {
|
||||
|
||||
<div class="mb-2">
|
||||
文本复制指令(双击输入框内容即可复制)
|
||||
<el-input v-copy="searchSix" v-model="searchSix" class="!w-[200px]" />
|
||||
<el-input v-model="searchSix" v-copy="searchSix" class="!w-[200px]" />
|
||||
</div>
|
||||
<div>
|
||||
文本复制指令(自定义触发事件,单击复制)
|
||||
|
||||
@@ -61,8 +61,8 @@ const filterMethod = (query: string, node: treeNode) => {
|
||||
</div>
|
||||
</template>
|
||||
<el-input
|
||||
class="mb-4"
|
||||
v-model="query"
|
||||
class="mb-4"
|
||||
placeholder="请输入关键字查找"
|
||||
clearable
|
||||
@input="onQueryChanged"
|
||||
|
||||
@@ -49,8 +49,8 @@ const onPrint = () => {
|
||||
</div>
|
||||
</template>
|
||||
<div
|
||||
class="h-[calc(100vh-239px)]"
|
||||
v-loading="loading"
|
||||
class="h-[calc(100vh-239px)]"
|
||||
:element-loading-text="t('status.hsLoad')"
|
||||
>
|
||||
<div class="flex justify-between items-center h-9">
|
||||
@@ -59,9 +59,9 @@ const onPrint = () => {
|
||||
</div>
|
||||
<div v-else>
|
||||
<el-pagination
|
||||
v-model:current-page="currentPage"
|
||||
background
|
||||
layout="prev, slot, next"
|
||||
v-model:current-page="currentPage"
|
||||
:page-size="1"
|
||||
:total="pageCount"
|
||||
>
|
||||
@@ -98,8 +98,8 @@ const onPrint = () => {
|
||||
</div>
|
||||
<el-scrollbar>
|
||||
<vue-pdf-embed
|
||||
class="h-full container overflow-auto"
|
||||
ref="pdfRef"
|
||||
class="h-full container overflow-auto"
|
||||
:rotation="rotations[currentRotation]"
|
||||
:page="currentPage"
|
||||
:source="source"
|
||||
|
||||
@@ -103,12 +103,12 @@ const tableData: User[] = [
|
||||
</template>
|
||||
<el-row :gutter="24">
|
||||
<el-col
|
||||
v-motion
|
||||
:xs="24"
|
||||
:sm="24"
|
||||
:md="24"
|
||||
:lg="24"
|
||||
:xl="24"
|
||||
v-motion
|
||||
:initial="{
|
||||
opacity: 0,
|
||||
y: 100
|
||||
@@ -138,12 +138,12 @@ const tableData: User[] = [
|
||||
<el-divider />
|
||||
|
||||
<el-col
|
||||
v-motion
|
||||
:xs="11"
|
||||
:sm="11"
|
||||
:md="11"
|
||||
:lg="11"
|
||||
:xl="11"
|
||||
v-motion
|
||||
:initial="{
|
||||
opacity: 0,
|
||||
y: 100
|
||||
@@ -161,12 +161,12 @@ const tableData: User[] = [
|
||||
</el-col>
|
||||
|
||||
<el-col
|
||||
v-motion
|
||||
:xs="11"
|
||||
:sm="11"
|
||||
:md="11"
|
||||
:lg="11"
|
||||
:xl="11"
|
||||
v-motion
|
||||
:initial="{
|
||||
opacity: 0,
|
||||
y: 100
|
||||
|
||||
@@ -24,7 +24,7 @@ const wasmPath = getPath("capture.worker.wasm");
|
||||
loadScript({
|
||||
src
|
||||
}).then(mgs => {
|
||||
if (mgs === "success") {
|
||||
if (mgs[0].message === "加载成功") {
|
||||
// @ts-expect-error
|
||||
captureUtil.value = cheetahCapture.initCapture({
|
||||
workerPath,
|
||||
@@ -155,9 +155,9 @@ onBeforeUnmount(() => {
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
id="canvas-container"
|
||||
v-loading="loading"
|
||||
element-loading-text="温馨提示:可左右拖拽图片并单击选取所需的帧图片"
|
||||
id="canvas-container"
|
||||
class="w-full h-[200px] overflow-hidden mt-6"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
@@ -23,9 +23,9 @@ const filteredItems = computed(() => {
|
||||
<div class="flex-ac mb-4 shadow-2xl">
|
||||
水平模式 horizontal
|
||||
<el-input
|
||||
v-model="search"
|
||||
class="mr-2 !w-[1/1.5]"
|
||||
clearable
|
||||
v-model="search"
|
||||
placeholder="Filter..."
|
||||
style="width: 300px"
|
||||
/>
|
||||
|
||||
@@ -23,9 +23,9 @@ const filteredItems = computed(() => {
|
||||
<div class="flex-ac mb-4 shadow-2xl">
|
||||
垂直模式 vertical
|
||||
<el-input
|
||||
v-model="search"
|
||||
class="!w-[350px]"
|
||||
clearable
|
||||
v-model="search"
|
||||
placeholder="Filter..."
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -42,15 +42,15 @@ onBeforeUnmount(() => {
|
||||
</template>
|
||||
<span> 请输入要创建水印的值:</span>
|
||||
<el-input
|
||||
v-model="value"
|
||||
class="mb-4 mr-4"
|
||||
style="width: 200px"
|
||||
v-model="value"
|
||||
clearable
|
||||
/>
|
||||
<span>请选择要创建水印的颜色:</span>
|
||||
<el-color-picker v-model="color" show-alpha />
|
||||
<br />
|
||||
<el-button @click="setWatermark(value, { fillStyle: color })">
|
||||
<el-button @click="setWatermark(value, { color })">
|
||||
创建整页水印
|
||||
</el-button>
|
||||
<el-button
|
||||
@@ -117,7 +117,7 @@ onBeforeUnmount(() => {
|
||||
<el-button
|
||||
@click="
|
||||
setLocalWatermark('局部水印', {
|
||||
fillStyle: color,
|
||||
color,
|
||||
width: 140,
|
||||
height: 60
|
||||
})
|
||||
|
||||
@@ -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();
|
||||
@@ -105,41 +100,38 @@ onBeforeUnmount(() => {
|
||||
element-loading-background="transparent"
|
||||
>
|
||||
<div ref="wavesurferRef" />
|
||||
<div class="flex justify-between" v-show="totalTime">
|
||||
<div v-show="totalTime" class="flex justify-between">
|
||||
<span class="text-[#81888f]">00:00</span>
|
||||
<h1 class="text-4xl mt-2">{{ curTime }}</h1>
|
||||
<span class="text-[#81888f]">{{ totalTime }}</span>
|
||||
</div>
|
||||
<div class="flex mt-2 w-[180px] justify-around m-auto" v-show="totalTime">
|
||||
<div v-show="totalTime" class="flex mt-2 w-[180px] justify-around m-auto">
|
||||
<Rewind
|
||||
class="cursor-pointer"
|
||||
v-tippy="{
|
||||
content: '快退(可长按)',
|
||||
placement: 'bottom',
|
||||
animation: 'scale'
|
||||
placement: 'bottom'
|
||||
}"
|
||||
v-longpress:0:100="() => wavesurfer?.skip(-1)"
|
||||
class="cursor-pointer"
|
||||
/>
|
||||
<div
|
||||
class="cursor-pointer"
|
||||
v-tippy="{
|
||||
content: isPlay ? '暂停' : '播放',
|
||||
placement: 'bottom',
|
||||
animation: 'scale'
|
||||
placement: 'bottom'
|
||||
}"
|
||||
class="cursor-pointer"
|
||||
@click="wavesurfer?.playPause()"
|
||||
>
|
||||
<Play v-if="isPlay" v-motion-pop />
|
||||
<Pause v-else v-motion-pop />
|
||||
</div>
|
||||
<Forward
|
||||
class="cursor-pointer"
|
||||
v-tippy="{
|
||||
content: '快进(可长按)',
|
||||
placement: 'bottom',
|
||||
animation: 'scale'
|
||||
placement: 'bottom'
|
||||
}"
|
||||
v-longpress:0:100="() => wavesurfer?.skip(1)"
|
||||
class="cursor-pointer"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -57,11 +57,11 @@ Object.keys(devDependencies).forEach(key => {
|
||||
</template>
|
||||
<el-descriptions border>
|
||||
<el-descriptions-item
|
||||
v-for="(item, index) in schema"
|
||||
:key="index"
|
||||
:label="item.label"
|
||||
label-align="left"
|
||||
align="left"
|
||||
v-for="(item, index) in schema"
|
||||
:key="index"
|
||||
>
|
||||
<a
|
||||
:href="'https://www.npmjs.com/package/' + item.label"
|
||||
@@ -81,11 +81,11 @@ Object.keys(devDependencies).forEach(key => {
|
||||
</template>
|
||||
<el-descriptions border>
|
||||
<el-descriptions-item
|
||||
v-for="(item, index) in devSchema"
|
||||
:key="index"
|
||||
:label="item.label"
|
||||
label-align="left"
|
||||
align="left"
|
||||
v-for="(item, index) in devSchema"
|
||||
:key="index"
|
||||
>
|
||||
<a
|
||||
:href="'https://www.npmjs.com/package/' + item.label"
|
||||
|
||||
@@ -120,8 +120,8 @@ function addDanmu() {
|
||||
<div class="flex gap-5">
|
||||
<vue-danmaku
|
||||
ref="danmaku"
|
||||
class="demo"
|
||||
v-model:danmus="danmus"
|
||||
class="demo"
|
||||
isSuspend
|
||||
v-bind="config"
|
||||
>
|
||||
@@ -176,9 +176,9 @@ function addDanmu() {
|
||||
</p>
|
||||
<p class="flex">
|
||||
<el-input
|
||||
v-model="danmuMsg"
|
||||
type="text"
|
||||
placeholder="输入评论后,回车发送弹幕"
|
||||
v-model="danmuMsg"
|
||||
@keyup.enter="addDanmu"
|
||||
/>
|
||||
</p>
|
||||
|
||||
@@ -27,15 +27,15 @@ const newFormInline = ref(props.formInline);
|
||||
<el-form :model="newFormInline">
|
||||
<el-form-item label="姓名">
|
||||
<el-input
|
||||
class="!w-[220px]"
|
||||
v-model="newFormInline.user"
|
||||
class="!w-[220px]"
|
||||
placeholder="请输入姓名"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="城市">
|
||||
<el-select
|
||||
class="!w-[220px]"
|
||||
v-model="newFormInline.region"
|
||||
class="!w-[220px]"
|
||||
placeholder="请选择城市"
|
||||
>
|
||||
<el-option label="上海" value="上海" />
|
||||
|
||||
@@ -18,5 +18,5 @@ const data = useVModel(props, "data", emit);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-input class="!w-[220px]" v-model="data" placeholder="请输入内容" />
|
||||
<el-input v-model="data" class="!w-[220px]" placeholder="请输入内容" />
|
||||
</template>
|
||||
|
||||
@@ -110,10 +110,10 @@ onMounted(() => {
|
||||
<draggable
|
||||
v-model="lists"
|
||||
item-key="name"
|
||||
@change="change"
|
||||
chosen-class="chosen"
|
||||
force-fallback="true"
|
||||
animation="300"
|
||||
@change="change"
|
||||
>
|
||||
<template #item="{ element, index }">
|
||||
<div class="item-single">{{ element.name }} {{ index }}</div>
|
||||
@@ -132,9 +132,9 @@ onMounted(() => {
|
||||
<!-- 拖拽实现元素位置切换 -->
|
||||
<div class="cut-container">
|
||||
<div
|
||||
class="item-cut"
|
||||
v-for="(item, index) in cutLists"
|
||||
:key="index"
|
||||
class="item-cut"
|
||||
>
|
||||
<p>{{ item.name }}</p>
|
||||
</div>
|
||||
|
||||
@@ -163,7 +163,7 @@ function onChange({ index, option }) {
|
||||
{{ optionsBasis[value].label }}
|
||||
</span>
|
||||
</p>
|
||||
<Segmented :options="optionsBasis" v-model="value" />
|
||||
<Segmented v-model="value" :options="optionsBasis" />
|
||||
<el-divider />
|
||||
<p class="mb-2">禁用</p>
|
||||
<Segmented :options="optionsDisabled" />
|
||||
|
||||
@@ -28,9 +28,9 @@ const selectedVal = ({ left, right }): void => {
|
||||
<template>
|
||||
<div>
|
||||
<el-card
|
||||
class="box-card"
|
||||
v-for="(item, key) in dataLists"
|
||||
:key="key"
|
||||
class="box-card"
|
||||
shadow="never"
|
||||
>
|
||||
<template #header>
|
||||
@@ -41,10 +41,10 @@ const selectedVal = ({ left, right }): void => {
|
||||
<Selector
|
||||
:HsKey="key"
|
||||
:echo="item.echo"
|
||||
@selectedVal="selectedVal"
|
||||
:disabled="item.disabled"
|
||||
@selectedVal="selectedVal"
|
||||
/>
|
||||
<h4 class="mt-3" v-if="!item.disabled">选中范围:{{ selectRange }}</h4>
|
||||
<h4 v-if="!item.disabled" class="mt-3">选中范围:{{ selectRange }}</h4>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user