Compare commits
2 Commits
master
...
ant-design
| Author | SHA1 | Date |
|---|---|---|
|
|
1fcd938cf9 | |
|
|
544ddeae22 |
|
|
@ -15,10 +15,12 @@
|
||||||
"lint:prettier": "prettier --write \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\""
|
"lint:prettier": "prettier --write \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\""
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@ant-design/icons-vue": "^6.1.0",
|
||||||
"@better-scroll/core": "^2.4.2",
|
"@better-scroll/core": "^2.4.2",
|
||||||
"@vueuse/core": "^9.1.1",
|
"@vueuse/core": "^9.1.1",
|
||||||
"@wangeditor/editor": "^5.1.14",
|
"@wangeditor/editor": "^5.1.14",
|
||||||
"@wangeditor/editor-for-vue": "^5.1.12",
|
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||||
|
"ant-design-vue": "^3.2.12",
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"clipboard": "^2.0.10",
|
"clipboard": "^2.0.10",
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
/**
|
||||||
|
* copy from element-ui
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Scrollbar from './src/Scrollbar.vue';
|
||||||
|
|
||||||
|
export { Scrollbar };
|
||||||
|
export type { ScrollbarType } from './src/types';
|
||||||
|
|
@ -0,0 +1,207 @@
|
||||||
|
<template>
|
||||||
|
<div class="scrollbar">
|
||||||
|
<div
|
||||||
|
ref="wrap"
|
||||||
|
:class="[wrapClass, 'scrollbar__wrap', native ? '' : 'scrollbar__wrap--hidden-default']"
|
||||||
|
:style="style"
|
||||||
|
@scroll="handleScroll"
|
||||||
|
>
|
||||||
|
<component :is="tag" ref="resize" :class="['scrollbar__view', viewClass]" :style="viewStyle">
|
||||||
|
<slot></slot>
|
||||||
|
</component>
|
||||||
|
</div>
|
||||||
|
<template v-if="!native">
|
||||||
|
<bar :move="moveX" :size="sizeWidth" />
|
||||||
|
<bar vertical :move="moveY" :size="sizeHeight" />
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { addResizeListener, removeResizeListener } from './event';
|
||||||
|
// import componentSetting from '/@/settings/componentSetting';
|
||||||
|
// const { scrollbar } = componentSetting;
|
||||||
|
import { toObject } from './util';
|
||||||
|
import {
|
||||||
|
defineComponent,
|
||||||
|
ref,
|
||||||
|
onMounted,
|
||||||
|
onBeforeUnmount,
|
||||||
|
nextTick,
|
||||||
|
provide,
|
||||||
|
computed,
|
||||||
|
unref,
|
||||||
|
} from 'vue';
|
||||||
|
import Bar from './bar';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'Scrollbar',
|
||||||
|
// inheritAttrs: false,
|
||||||
|
components: { Bar },
|
||||||
|
props: {
|
||||||
|
native: {
|
||||||
|
type: Boolean,
|
||||||
|
// default: scrollbar?.native ?? false,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
wrapStyle: {
|
||||||
|
type: [String, Array],
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
wrapClass: {
|
||||||
|
type: [String, Array],
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
viewClass: {
|
||||||
|
type: [String, Array],
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
viewStyle: {
|
||||||
|
type: [String, Array],
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
noresize: Boolean, // 如果 container 尺寸不会发生变化,最好设置它可以优化性能
|
||||||
|
tag: {
|
||||||
|
type: String,
|
||||||
|
default: 'div',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const sizeWidth = ref('0');
|
||||||
|
const sizeHeight = ref('0');
|
||||||
|
const moveX = ref(0);
|
||||||
|
const moveY = ref(0);
|
||||||
|
const wrap = ref();
|
||||||
|
const resize = ref();
|
||||||
|
|
||||||
|
provide('scroll-bar-wrap', wrap);
|
||||||
|
|
||||||
|
const style = computed(() => {
|
||||||
|
if (Array.isArray(props.wrapStyle)) {
|
||||||
|
return toObject(props.wrapStyle);
|
||||||
|
}
|
||||||
|
return props.wrapStyle;
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleScroll = () => {
|
||||||
|
if (!props.native) {
|
||||||
|
moveY.value = (unref(wrap).scrollTop * 100) / unref(wrap).clientHeight;
|
||||||
|
moveX.value = (unref(wrap).scrollLeft * 100) / unref(wrap).clientWidth;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const update = () => {
|
||||||
|
if (!unref(wrap)) return;
|
||||||
|
|
||||||
|
const heightPercentage = (unref(wrap).clientHeight * 100) / unref(wrap).scrollHeight;
|
||||||
|
const widthPercentage = (unref(wrap).clientWidth * 100) / unref(wrap).scrollWidth;
|
||||||
|
|
||||||
|
sizeHeight.value = heightPercentage < 100 ? heightPercentage + '%' : '';
|
||||||
|
sizeWidth.value = widthPercentage < 100 ? widthPercentage + '%' : '';
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (props.native) return;
|
||||||
|
nextTick(update);
|
||||||
|
if (!props.noresize) {
|
||||||
|
addResizeListener(unref(resize), update);
|
||||||
|
addResizeListener(unref(wrap), update);
|
||||||
|
addEventListener('resize', update);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (props.native) return;
|
||||||
|
if (!props.noresize) {
|
||||||
|
removeResizeListener(unref(resize), update);
|
||||||
|
removeResizeListener(unref(wrap), update);
|
||||||
|
removeEventListener('resize', update);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
moveX,
|
||||||
|
moveY,
|
||||||
|
sizeWidth,
|
||||||
|
sizeHeight,
|
||||||
|
style,
|
||||||
|
wrap,
|
||||||
|
resize,
|
||||||
|
update,
|
||||||
|
handleScroll,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.scrollbar {
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&__wrap {
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
&--hidden-default {
|
||||||
|
scrollbar-width: none;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
opacity: 0%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__thumb {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: rgb(144 147 153 / 30%);
|
||||||
|
border-radius: inherit;
|
||||||
|
transition: 0.3s background-color;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgb(144 147 153 / 50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__bar {
|
||||||
|
position: absolute;
|
||||||
|
right: 2px;
|
||||||
|
bottom: 2px;
|
||||||
|
z-index: 1;
|
||||||
|
border-radius: 4px;
|
||||||
|
opacity: 0%;
|
||||||
|
transition: opacity 80ms ease;
|
||||||
|
|
||||||
|
&.is-vertical {
|
||||||
|
top: 2px;
|
||||||
|
width: 6px;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-horizontal {
|
||||||
|
left: 2px;
|
||||||
|
height: 6px;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar:active > .scrollbar__bar,
|
||||||
|
.scrollbar:focus > .scrollbar__bar,
|
||||||
|
.scrollbar:hover > .scrollbar__bar {
|
||||||
|
opacity: 100%;
|
||||||
|
transition: opacity 340ms ease-out;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
import {
|
||||||
|
defineComponent,
|
||||||
|
h,
|
||||||
|
computed,
|
||||||
|
ref,
|
||||||
|
getCurrentInstance,
|
||||||
|
onUnmounted,
|
||||||
|
inject,
|
||||||
|
Ref,
|
||||||
|
} from 'vue';
|
||||||
|
import { on, off } from './domUtils';
|
||||||
|
|
||||||
|
import { renderThumbStyle, BAR_MAP } from './util';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'Bar',
|
||||||
|
|
||||||
|
props: {
|
||||||
|
vertical: Boolean,
|
||||||
|
size: String,
|
||||||
|
move: Number,
|
||||||
|
},
|
||||||
|
|
||||||
|
setup(props) {
|
||||||
|
const instance = getCurrentInstance();
|
||||||
|
const thumb = ref();
|
||||||
|
const wrap = inject('scroll-bar-wrap', {} as Ref<Nullable<HTMLElement>>) as any;
|
||||||
|
const bar = computed(() => {
|
||||||
|
return BAR_MAP[props.vertical ? 'vertical' : 'horizontal'];
|
||||||
|
});
|
||||||
|
const barStore = ref<Recordable>({});
|
||||||
|
const cursorDown = ref();
|
||||||
|
const clickThumbHandler = (e: any) => {
|
||||||
|
// prevent click event of right button
|
||||||
|
if (e.ctrlKey || e.button === 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.getSelection()?.removeAllRanges();
|
||||||
|
startDrag(e);
|
||||||
|
barStore.value[bar.value.axis] =
|
||||||
|
e.currentTarget[bar.value.offset] -
|
||||||
|
(e[bar.value.client] - e.currentTarget.getBoundingClientRect()[bar.value.direction]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const clickTrackHandler = (e: any) => {
|
||||||
|
const offset = Math.abs(
|
||||||
|
e.target.getBoundingClientRect()[bar.value.direction] - e[bar.value.client],
|
||||||
|
);
|
||||||
|
const thumbHalf = thumb.value[bar.value.offset] / 2;
|
||||||
|
const thumbPositionPercentage =
|
||||||
|
((offset - thumbHalf) * 100) / instance?.vnode.el?.[bar.value.offset];
|
||||||
|
|
||||||
|
wrap.value[bar.value.scroll] =
|
||||||
|
(thumbPositionPercentage * wrap.value[bar.value.scrollSize]) / 100;
|
||||||
|
};
|
||||||
|
const startDrag = (e: any) => {
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
cursorDown.value = true;
|
||||||
|
on(document, 'mousemove', mouseMoveDocumentHandler);
|
||||||
|
on(document, 'mouseup', mouseUpDocumentHandler);
|
||||||
|
document.onselectstart = () => false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const mouseMoveDocumentHandler = (e: any) => {
|
||||||
|
if (cursorDown.value === false) return;
|
||||||
|
const prevPage = barStore.value[bar.value.axis];
|
||||||
|
|
||||||
|
if (!prevPage) return;
|
||||||
|
|
||||||
|
const offset =
|
||||||
|
(instance?.vnode.el?.getBoundingClientRect()[bar.value.direction] - e[bar.value.client]) *
|
||||||
|
-1;
|
||||||
|
const thumbClickPosition = thumb.value[bar.value.offset] - prevPage;
|
||||||
|
const thumbPositionPercentage =
|
||||||
|
((offset - thumbClickPosition) * 100) / instance?.vnode.el?.[bar.value.offset];
|
||||||
|
wrap.value[bar.value.scroll] =
|
||||||
|
(thumbPositionPercentage * wrap.value[bar.value.scrollSize]) / 100;
|
||||||
|
};
|
||||||
|
|
||||||
|
function mouseUpDocumentHandler() {
|
||||||
|
cursorDown.value = false;
|
||||||
|
barStore.value[bar.value.axis] = 0;
|
||||||
|
off(document, 'mousemove', mouseMoveDocumentHandler);
|
||||||
|
document.onselectstart = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
off(document, 'mouseup', mouseUpDocumentHandler);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () =>
|
||||||
|
h(
|
||||||
|
'div',
|
||||||
|
{
|
||||||
|
class: ['scrollbar__bar', 'is-' + bar.value.key],
|
||||||
|
onMousedown: clickTrackHandler,
|
||||||
|
},
|
||||||
|
h('div', {
|
||||||
|
ref: thumb,
|
||||||
|
class: 'scrollbar__thumb',
|
||||||
|
onMousedown: clickThumbHandler,
|
||||||
|
style: renderThumbStyle({
|
||||||
|
size: props.size,
|
||||||
|
move: props.move,
|
||||||
|
bar: bar.value,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,180 @@
|
||||||
|
import type { FunctionArgs } from '@vueuse/core';
|
||||||
|
import { upperFirst } from 'lodash-es';
|
||||||
|
|
||||||
|
export interface ViewportOffsetResult {
|
||||||
|
left: number;
|
||||||
|
top: number;
|
||||||
|
right: number;
|
||||||
|
bottom: number;
|
||||||
|
rightIncludeBody: number;
|
||||||
|
bottomIncludeBody: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBoundingClientRect(element: Element): DOMRect | number {
|
||||||
|
if (!element || !element.getBoundingClientRect) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return element.getBoundingClientRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
function trim(string: string) {
|
||||||
|
return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
export function hasClass(el: Element, cls: string) {
|
||||||
|
if (!el || !cls) return false;
|
||||||
|
if (cls.indexOf(' ') !== -1) throw new Error('className should not contain space.');
|
||||||
|
if (el.classList) {
|
||||||
|
return el.classList.contains(cls);
|
||||||
|
} else {
|
||||||
|
return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
export function addClass(el: Element, cls: string) {
|
||||||
|
if (!el) return;
|
||||||
|
let curClass = el.className;
|
||||||
|
const classes = (cls || '').split(' ');
|
||||||
|
|
||||||
|
for (let i = 0, j = classes.length; i < j; i++) {
|
||||||
|
const clsName = classes[i];
|
||||||
|
if (!clsName) continue;
|
||||||
|
|
||||||
|
if (el.classList) {
|
||||||
|
el.classList.add(clsName);
|
||||||
|
} else if (!hasClass(el, clsName)) {
|
||||||
|
curClass += ' ' + clsName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!el.classList) {
|
||||||
|
el.className = curClass;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
export function removeClass(el: Element, cls: string) {
|
||||||
|
if (!el || !cls) return;
|
||||||
|
const classes = cls.split(' ');
|
||||||
|
let curClass = ' ' + el.className + ' ';
|
||||||
|
|
||||||
|
for (let i = 0, j = classes.length; i < j; i++) {
|
||||||
|
const clsName = classes[i];
|
||||||
|
if (!clsName) continue;
|
||||||
|
|
||||||
|
if (el.classList) {
|
||||||
|
el.classList.remove(clsName);
|
||||||
|
} else if (hasClass(el, clsName)) {
|
||||||
|
curClass = curClass.replace(' ' + clsName + ' ', ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!el.classList) {
|
||||||
|
el.className = trim(curClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get the left and top offset of the current element
|
||||||
|
* left: the distance between the leftmost element and the left side of the document
|
||||||
|
* top: the distance from the top of the element to the top of the document
|
||||||
|
* right: the distance from the far right of the element to the right of the document
|
||||||
|
* bottom: the distance from the bottom of the element to the bottom of the document
|
||||||
|
* rightIncludeBody: the distance between the leftmost element and the right side of the document
|
||||||
|
* bottomIncludeBody: the distance from the bottom of the element to the bottom of the document
|
||||||
|
*
|
||||||
|
* @description:
|
||||||
|
*/
|
||||||
|
export function getViewportOffset(element: Element): ViewportOffsetResult {
|
||||||
|
const doc = document.documentElement;
|
||||||
|
|
||||||
|
const docScrollLeft = doc.scrollLeft;
|
||||||
|
const docScrollTop = doc.scrollTop;
|
||||||
|
const docClientLeft = doc.clientLeft;
|
||||||
|
const docClientTop = doc.clientTop;
|
||||||
|
|
||||||
|
const pageXOffset = window.pageXOffset;
|
||||||
|
const pageYOffset = window.pageYOffset;
|
||||||
|
|
||||||
|
const box = getBoundingClientRect(element);
|
||||||
|
|
||||||
|
const { left: retLeft, top: rectTop, width: rectWidth, height: rectHeight } = box as DOMRect;
|
||||||
|
|
||||||
|
const scrollLeft = (pageXOffset || docScrollLeft) - (docClientLeft || 0);
|
||||||
|
const scrollTop = (pageYOffset || docScrollTop) - (docClientTop || 0);
|
||||||
|
const offsetLeft = retLeft + pageXOffset;
|
||||||
|
const offsetTop = rectTop + pageYOffset;
|
||||||
|
|
||||||
|
const left = offsetLeft - scrollLeft;
|
||||||
|
const top = offsetTop - scrollTop;
|
||||||
|
|
||||||
|
const clientWidth = window.document.documentElement.clientWidth;
|
||||||
|
const clientHeight = window.document.documentElement.clientHeight;
|
||||||
|
return {
|
||||||
|
left: left,
|
||||||
|
top: top,
|
||||||
|
right: clientWidth - rectWidth - left,
|
||||||
|
bottom: clientHeight - rectHeight - top,
|
||||||
|
rightIncludeBody: clientWidth - left,
|
||||||
|
bottomIncludeBody: clientHeight - top,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hackCss(attr: string, value: string) {
|
||||||
|
const prefix: string[] = ['webkit', 'Moz', 'ms', 'OT'];
|
||||||
|
|
||||||
|
const styleObj: any = {};
|
||||||
|
prefix.forEach((item) => {
|
||||||
|
styleObj[`${item}${upperFirst(attr)}`] = value;
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
...styleObj,
|
||||||
|
[attr]: value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
export function on(
|
||||||
|
element: Element | HTMLElement | Document | Window,
|
||||||
|
event: string,
|
||||||
|
handler: EventListenerOrEventListenerObject,
|
||||||
|
): void {
|
||||||
|
if (element && event && handler) {
|
||||||
|
element.addEventListener(event, handler, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
export function off(
|
||||||
|
element: Element | HTMLElement | Document | Window,
|
||||||
|
event: string,
|
||||||
|
handler: Fn,
|
||||||
|
): void {
|
||||||
|
if (element && event && handler) {
|
||||||
|
element.removeEventListener(event, handler, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
export function once(el: HTMLElement, event: string, fn: EventListener): void {
|
||||||
|
const listener = function (this: any, ...args: unknown[]) {
|
||||||
|
if (fn) {
|
||||||
|
fn.apply(this, args);
|
||||||
|
}
|
||||||
|
off(el, event, listener);
|
||||||
|
};
|
||||||
|
on(el, event, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useRafThrottle<T extends FunctionArgs>(fn: T): T {
|
||||||
|
let locked = false;
|
||||||
|
// @ts-ignore
|
||||||
|
return function (...args: any[]) {
|
||||||
|
if (locked) return;
|
||||||
|
locked = true;
|
||||||
|
window.requestAnimationFrame(() => {
|
||||||
|
// @ts-ignore
|
||||||
|
fn.apply(this, args);
|
||||||
|
locked = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
import ResizeObserver from 'resize-observer-polyfill';
|
||||||
|
|
||||||
|
const isServer = typeof window === 'undefined';
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
function resizeHandler(entries: any[]) {
|
||||||
|
for (const entry of entries) {
|
||||||
|
const listeners = entry.target.__resizeListeners__ || [];
|
||||||
|
if (listeners.length) {
|
||||||
|
listeners.forEach((fn: () => any) => {
|
||||||
|
fn();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
export function addResizeListener(element: any, fn: () => any) {
|
||||||
|
if (isServer) return;
|
||||||
|
if (!element.__resizeListeners__) {
|
||||||
|
element.__resizeListeners__ = [];
|
||||||
|
element.__ro__ = new ResizeObserver(resizeHandler);
|
||||||
|
element.__ro__.observe(element);
|
||||||
|
}
|
||||||
|
element.__resizeListeners__.push(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
export function removeResizeListener(element: any, fn: () => any) {
|
||||||
|
if (!element || !element.__resizeListeners__) return;
|
||||||
|
element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
|
||||||
|
if (!element.__resizeListeners__.length) {
|
||||||
|
element.__ro__.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function triggerWindowResize() {
|
||||||
|
const event = document.createEvent('HTMLEvents');
|
||||||
|
event.initEvent('resize', true, true);
|
||||||
|
(event as any).eventType = 'message';
|
||||||
|
window.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
export interface BarMapItem {
|
||||||
|
offset: string;
|
||||||
|
scroll: string;
|
||||||
|
scrollSize: string;
|
||||||
|
size: string;
|
||||||
|
key: string;
|
||||||
|
axis: string;
|
||||||
|
client: string;
|
||||||
|
direction: string;
|
||||||
|
}
|
||||||
|
export interface BarMap {
|
||||||
|
vertical: BarMapItem;
|
||||||
|
horizontal: BarMapItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScrollbarType {
|
||||||
|
wrap: ElRef;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
import type { BarMap } from './types';
|
||||||
|
export const BAR_MAP: BarMap = {
|
||||||
|
vertical: {
|
||||||
|
offset: 'offsetHeight',
|
||||||
|
scroll: 'scrollTop',
|
||||||
|
scrollSize: 'scrollHeight',
|
||||||
|
size: 'height',
|
||||||
|
key: 'vertical',
|
||||||
|
axis: 'Y',
|
||||||
|
client: 'clientY',
|
||||||
|
direction: 'top',
|
||||||
|
},
|
||||||
|
horizontal: {
|
||||||
|
offset: 'offsetWidth',
|
||||||
|
scroll: 'scrollLeft',
|
||||||
|
scrollSize: 'scrollWidth',
|
||||||
|
size: 'width',
|
||||||
|
key: 'horizontal',
|
||||||
|
axis: 'X',
|
||||||
|
client: 'clientX',
|
||||||
|
direction: 'left',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
export function renderThumbStyle({ move, size, bar }) {
|
||||||
|
const style = {} as any;
|
||||||
|
const translate = `translate${bar.axis}(${move}%)`;
|
||||||
|
|
||||||
|
style[bar.size] = size;
|
||||||
|
style.transform = translate;
|
||||||
|
style.msTransform = translate;
|
||||||
|
style.webkitTransform = translate;
|
||||||
|
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extend<T, K>(to: T, _from: K): T & K {
|
||||||
|
return Object.assign(to, _from);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toObject<T>(arr: Array<T>): Recordable<T> {
|
||||||
|
const res = {};
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
if (arr[i]) {
|
||||||
|
extend(res, arr[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<section class="app-main" v-if="isReload">
|
<section class="app-main" v-if="isReload">
|
||||||
<router-view v-slot="{ Component, route }">
|
<router-view v-slot="{ Component, route }">
|
||||||
<transition name="fade-slide" mode="out-in" appear>
|
<transition name="fade-slide" mode="out-in">
|
||||||
<keep-alive v-if="route.meta && route.meta.keepAlive">
|
<keep-alive v-if="route.meta && route.meta.keepAlive">
|
||||||
<component :is="Component" :key="route.path" />
|
<component :is="Component" :key="route.path" />
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ defineProps<{ isCollapse: boolean }>();
|
||||||
background: #2b2f3a;
|
background: #2b2f3a;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
& .sidebar-logo-link {
|
& .sidebar-logo-link {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
@ -37,17 +36,16 @@ defineProps<{ isCollapse: boolean }>();
|
||||||
& .sidebar-logo {
|
& .sidebar-logo {
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
margin-right: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
& .sidebar-title {
|
& .sidebar-title {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
margin-left: 12px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.collapse {
|
&.collapse {
|
||||||
.sidebar-logo {
|
.sidebar-logo {
|
||||||
margin-right: 0px;
|
margin-right: 0px;
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,39 @@
|
||||||
<template>
|
<template>
|
||||||
<el-menu
|
<div>
|
||||||
:default-active="activeMenu"
|
<a-menu
|
||||||
active-text-color="#ffd04b"
|
v-model:openKeys="state.openKeys"
|
||||||
background-color="#304156"
|
v-model:selectedKeys="state.selectedKeys"
|
||||||
text-color="#fff"
|
mode="inline"
|
||||||
:mode="mode"
|
theme="dark"
|
||||||
:collapse-transition="false"
|
:inline-collapsed="isCollapse"
|
||||||
class="el-menu-vertical-demo"
|
|
||||||
:collapse="isCollapse"
|
|
||||||
>
|
>
|
||||||
|
<a-menu-item key="1">
|
||||||
|
<template #icon>
|
||||||
|
<PieChartOutlined />
|
||||||
|
</template>
|
||||||
|
<span>Option 1</span>
|
||||||
|
</a-menu-item>
|
||||||
<sub-item
|
<sub-item
|
||||||
v-for="route in permission_routes"
|
v-for="route in permission_routes"
|
||||||
:key="route.path"
|
:key="route.path"
|
||||||
:item="route"
|
:item="route"
|
||||||
:base-path="route.path"
|
:base-path="route.path"
|
||||||
/>
|
/>
|
||||||
</el-menu>
|
</a-menu>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import SubItem from './SubItem.vue'
|
import SubItem from './SubItem.vue'
|
||||||
|
import { defineComponent, reactive, toRefs, watch } from 'vue';
|
||||||
|
import {
|
||||||
|
MenuFoldOutlined,
|
||||||
|
MenuUnfoldOutlined,
|
||||||
|
PieChartOutlined,
|
||||||
|
MailOutlined,
|
||||||
|
DesktopOutlined,
|
||||||
|
InboxOutlined,
|
||||||
|
AppstoreOutlined,
|
||||||
|
} from '@ant-design/icons-vue';
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import {usePermissionStore} from "@/store/modules/permission"
|
import {usePermissionStore} from "@/store/modules/permission"
|
||||||
import {useSettingStore} from "@/store/modules/setting"
|
import {useSettingStore} from "@/store/modules/setting"
|
||||||
|
|
@ -49,4 +63,27 @@
|
||||||
|
|
||||||
// 横向
|
// 横向
|
||||||
const mode = computed(() => SettingStore.themeConfig.mode)
|
const mode = computed(() => SettingStore.themeConfig.mode)
|
||||||
|
const state = reactive({
|
||||||
|
collapsed: false,
|
||||||
|
selectedKeys: ['1'],
|
||||||
|
openKeys: ['sub1'],
|
||||||
|
preOpenKeys: ['sub1'],
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => state.openKeys,
|
||||||
|
(_val, oldVal) => {
|
||||||
|
state.preOpenKeys = oldVal;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const toggleCollapsed = () => {
|
||||||
|
state.collapsed = !state.collapsed;
|
||||||
|
state.openKeys = state.collapsed ? [] : state.preOpenKeys;
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.ant-menu.ant-menu-inline-collapsed{
|
||||||
|
width: 60px!important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,18 +1,20 @@
|
||||||
<template>
|
<template>
|
||||||
<template v-if="!item.hidden">
|
<template v-if="!item.hidden">
|
||||||
<template v-if="!item.alwaysShow && hasOneShowingChild(item.children, item)">
|
<template v-if="!item.alwaysShow && hasOneShowingChild(item.children, item)">
|
||||||
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
|
<a-menu-item :key="resolvePath(onlyOneChild.path)" v-if="onlyOneChild.meta">
|
||||||
<el-menu-item :index="resolvePath(onlyOneChild.path)">
|
<template #icon>
|
||||||
<el-icon :size="20">
|
<span :style="{fontSize: '16px', width:'16px'}">
|
||||||
<component :is="onlyOneChild?.meta.icon" ></component>
|
<component :is="onlyOneChild?.meta.icon" ></component>
|
||||||
</el-icon>
|
</span>
|
||||||
<template #title>{{ onlyOneChild.meta && onlyOneChild.meta.title }}</template>
|
|
||||||
</el-menu-item>
|
|
||||||
</app-link>
|
|
||||||
</template>
|
</template>
|
||||||
<el-sub-menu :index="resolvePath(item.path)" v-else popper-append-to-body>
|
<app-link :to="resolvePath(onlyOneChild.path)">
|
||||||
|
<span>{{ onlyOneChild.meta && onlyOneChild.meta.title }}</span>
|
||||||
|
</app-link>
|
||||||
|
</a-menu-item>
|
||||||
|
</template>
|
||||||
|
<a-sub-menu :key="resolvePath(item.path)" v-else popper-append-to-body>
|
||||||
|
<template #icon> <component :is="item.meta?.icon" :style="{fontSize: '16px', width:'16px'}"></component></template>
|
||||||
<template #title>
|
<template #title>
|
||||||
<el-icon :size="20"> <component :is="item.meta?.icon"></component></el-icon>
|
|
||||||
<span>{{ item.meta && item.meta.title }}</span>
|
<span>{{ item.meta && item.meta.title }}</span>
|
||||||
</template>
|
</template>
|
||||||
<sub-item
|
<sub-item
|
||||||
|
|
@ -21,7 +23,7 @@
|
||||||
:item="child"
|
:item="child"
|
||||||
:base-path="resolvePath(child.path)"
|
:base-path="resolvePath(child.path)"
|
||||||
/>
|
/>
|
||||||
</el-sub-menu>
|
</a-sub-menu>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="{ 'has-logo': themeConfig.showLogo }">
|
<div :class="{ 'has-logo': themeConfig.showLogo }">
|
||||||
<logo :isCollapse="isCollapse" v-if="themeConfig.showLogo"/>
|
<logo :isCollapse="isCollapse" v-if="themeConfig.showLogo"/>
|
||||||
<el-scrollbar wrap-class="scrollbar-wrapper">
|
<Scrollbar wrap-class="scrollbar-wrapper">
|
||||||
<u-menu/>
|
<u-menu/>
|
||||||
</el-scrollbar>
|
</Scrollbar>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import UMenu from './components/Menu.vue'
|
import UMenu from './components/Menu.vue'
|
||||||
import logo from './components/Logo.vue'
|
import logo from './components/Logo.vue'
|
||||||
|
import {Scrollbar} from '@/components/Scrollbar'
|
||||||
import {useSettingStore} from "@/store/modules/setting"
|
import {useSettingStore} from "@/store/modules/setting"
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
<template>
|
||||||
|
<component :is="type" v-bind="linkProps(to)">
|
||||||
|
<slot />
|
||||||
|
</component>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { isExternal } from '@/utils/validate.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
to: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isExternal() {
|
||||||
|
return isExternal(this.to)
|
||||||
|
},
|
||||||
|
type() {
|
||||||
|
if (this.isExternal) {
|
||||||
|
return 'a'
|
||||||
|
}
|
||||||
|
return 'router-link'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
linkProps(to) {
|
||||||
|
if (this.isExternal) {
|
||||||
|
return {
|
||||||
|
href: to,
|
||||||
|
target: '_blank',
|
||||||
|
rel: 'noopener',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
to: to,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
<template>
|
||||||
|
<div class="sidebar-logo-container" >
|
||||||
|
<transition name="sidebarLogoFade">
|
||||||
|
<router-link v-if="isCollapse" key="collapse" class="sidebar-logo-link" to="/">
|
||||||
|
<img src="@/assets/logo.png" class="sidebar-logo">
|
||||||
|
</router-link>
|
||||||
|
<router-link v-else key="expand" class="sidebar-logo-link" to="/">
|
||||||
|
<img src="@/assets/logo.png" class="sidebar-logo">
|
||||||
|
<h1 class="sidebar-title">Vue Admin Perfect</h1>
|
||||||
|
</router-link>
|
||||||
|
</transition>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
defineProps<{ isCollapse: boolean }>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.sidebar-logo-container {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 60px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background: #2b2f3a;
|
||||||
|
text-align: center;
|
||||||
|
overflow: hidden;
|
||||||
|
& .sidebar-logo-link {
|
||||||
|
text-decoration: none;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
& .sidebar-logo {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
|
||||||
|
}
|
||||||
|
& .sidebar-title {
|
||||||
|
color: #fff;
|
||||||
|
margin-left: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.collapse {
|
||||||
|
.sidebar-logo {
|
||||||
|
margin-right: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
<template>
|
||||||
|
<el-menu
|
||||||
|
:default-active="activeMenu"
|
||||||
|
active-text-color="#ffd04b"
|
||||||
|
background-color="#304156"
|
||||||
|
text-color="#fff"
|
||||||
|
:mode="mode"
|
||||||
|
:collapse-transition="false"
|
||||||
|
class="el-menu-vertical-demo"
|
||||||
|
:collapse="isCollapse"
|
||||||
|
>
|
||||||
|
<sub-item
|
||||||
|
v-for="route in permission_routes"
|
||||||
|
:key="route.path"
|
||||||
|
:item="route"
|
||||||
|
:base-path="route.path"
|
||||||
|
/>
|
||||||
|
</el-menu>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import SubItem from './SubItem.vue'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
import {usePermissionStore} from "@/store/modules/permission"
|
||||||
|
import {useSettingStore} from "@/store/modules/setting"
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
|
||||||
|
// 在setup中获取store
|
||||||
|
const route = useRoute()
|
||||||
|
const PermissionStore = usePermissionStore()
|
||||||
|
const SettingStore = useSettingStore()
|
||||||
|
|
||||||
|
// 获取路由
|
||||||
|
const permission_routes = computed(() => PermissionStore.permission_routes)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const activeMenu = computed(() => {
|
||||||
|
const { meta, path } = route
|
||||||
|
// if set path, the sidebar will highlight the path you set
|
||||||
|
if (meta.activeMenu) {
|
||||||
|
return meta.activeMenu
|
||||||
|
}
|
||||||
|
return path
|
||||||
|
})
|
||||||
|
|
||||||
|
// 是否折叠
|
||||||
|
const isCollapse = computed(() => !SettingStore.isCollapse)
|
||||||
|
|
||||||
|
// 横向
|
||||||
|
const mode = computed(() => SettingStore.themeConfig.mode)
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
<template>
|
||||||
|
<template v-if="!item.hidden">
|
||||||
|
<template v-if="!item.alwaysShow && hasOneShowingChild(item.children, item)">
|
||||||
|
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
|
||||||
|
<el-menu-item :index="resolvePath(onlyOneChild.path)">
|
||||||
|
<el-icon :size="20">
|
||||||
|
<component :is="onlyOneChild?.meta.icon"></component>
|
||||||
|
</el-icon>
|
||||||
|
<template #title>{{ onlyOneChild.meta && onlyOneChild.meta.title }}</template>
|
||||||
|
</el-menu-item>
|
||||||
|
</app-link>
|
||||||
|
</template>
|
||||||
|
<el-sub-menu :index="resolvePath(item.path)" v-else popper-append-to-body>
|
||||||
|
<template #title>
|
||||||
|
<el-icon :size="20"> <component :is="item.meta?.icon"></component></el-icon>
|
||||||
|
<span>{{ item.meta && item.meta.title }}</span>
|
||||||
|
</template>
|
||||||
|
<sub-item
|
||||||
|
v-for="child in item.children"
|
||||||
|
:key="child.path"
|
||||||
|
:item="child"
|
||||||
|
:base-path="resolvePath(child.path)"
|
||||||
|
/>
|
||||||
|
</el-sub-menu>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { isExternal } from '@/utils/validate.js'
|
||||||
|
import AppLink from './Link.vue'
|
||||||
|
import path from 'path-browserify'
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
const props = defineProps({
|
||||||
|
item: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
basePath: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const onlyOneChild = ref(null)
|
||||||
|
const hasOneShowingChild = (children = [], parent) => {
|
||||||
|
const showingChildren = children.filter((item) => {
|
||||||
|
// 过滤掉需要隐藏的菜单
|
||||||
|
if (item.hidden) {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
// 临时设置(如果只有一个显示子项,则将使用)
|
||||||
|
onlyOneChild.value = item
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 当只有一个子路由器时,默认情况下会显示该子路由器
|
||||||
|
if (showingChildren.length === 1) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// 如果没有要显示的子路由器,则显示父路由器
|
||||||
|
if (showingChildren.length === 0) {
|
||||||
|
onlyOneChild.value = { ...parent, path: '', noShowingChildren: true }
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolvePath = (routePath) => {
|
||||||
|
if (isExternal(routePath)) {
|
||||||
|
return routePath
|
||||||
|
}
|
||||||
|
if (isExternal(props.basePath)) {
|
||||||
|
return props.basePath
|
||||||
|
}
|
||||||
|
return path.resolve(props.basePath, routePath)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
<template>
|
||||||
|
<div :class="{ 'has-logo': themeConfig.showLogo }">
|
||||||
|
<logo :isCollapse="isCollapse" v-if="themeConfig.showLogo"/>
|
||||||
|
<el-scrollbar wrap-class="scrollbar-wrapper">
|
||||||
|
<u-menu/>
|
||||||
|
</el-scrollbar>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import UMenu from './components/Menu.vue'
|
||||||
|
import logo from './components/Logo.vue'
|
||||||
|
import {useSettingStore} from "@/store/modules/setting"
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
|
||||||
|
const SettingStore = useSettingStore()
|
||||||
|
// 是否折叠
|
||||||
|
const isCollapse = computed(() => !SettingStore.isCollapse)
|
||||||
|
// 设置
|
||||||
|
const themeConfig = computed(() =>SettingStore.themeConfig )
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.el-menu-vertical-demo:not(.el-menu--collapse) {
|
||||||
|
//width: 200px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.crollbar-wrapper {
|
||||||
|
height: 100%;
|
||||||
|
.el-scrollbar__view {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -17,6 +17,10 @@ import 'element-plus/theme-chalk/dark/css-vars.css'
|
||||||
// 自定义暗黑模式
|
// 自定义暗黑模式
|
||||||
import "@/styles/element-dark.scss";
|
import "@/styles/element-dark.scss";
|
||||||
|
|
||||||
|
// 引入 ant-design-vue
|
||||||
|
import Antd from 'ant-design-vue';
|
||||||
|
import 'ant-design-vue/dist/antd.css';
|
||||||
|
|
||||||
// 引入全局组件布局
|
// 引入全局组件布局
|
||||||
import UContainerLayout from '@/components/u-container-layout/index.vue'
|
import UContainerLayout from '@/components/u-container-layout/index.vue'
|
||||||
|
|
||||||
|
|
@ -35,6 +39,7 @@ Object.keys(ElIconsModules).forEach((key) => {//循环遍历组件名称
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
app.use(pinia)
|
app.use(pinia)
|
||||||
|
app.use(Antd)
|
||||||
app.use(router)
|
app.use(router)
|
||||||
|
|
||||||
app.use(ElementPlus).mount('#app')
|
app.use(ElementPlus).mount('#app')
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
.sidebar-container {
|
.sidebar-container {
|
||||||
transition: width 0.28s;
|
transition: width 0.28s;
|
||||||
width: $sideBarWidth !important;
|
width: $sideBarWidth !important;
|
||||||
background-color: $menuBg;
|
//background-color: $menuBg;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
font-size: 0px;
|
font-size: 0px;
|
||||||
|
|
@ -61,43 +61,43 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.svg-icon {
|
//.svg-icon {
|
||||||
margin-right: 16px;
|
// margin-right: 16px;
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
|
//.sub-el-icon {
|
||||||
|
// margin-right: 12px;
|
||||||
|
// margin-left: -2px;
|
||||||
|
//}
|
||||||
|
|
||||||
.sub-el-icon {
|
//.el-menu {
|
||||||
margin-right: 12px;
|
// border: none;
|
||||||
margin-left: -2px;
|
// height: 100%;
|
||||||
}
|
// width: 100% !important;
|
||||||
|
// background: none;
|
||||||
.el-menu {
|
//}
|
||||||
border: none;
|
//
|
||||||
height: 100%;
|
//// menu hover
|
||||||
width: 100% !important;
|
//.sub-menu-title-noDropdown,
|
||||||
background: none;
|
//.el-sub-menu__title {
|
||||||
}
|
// &:hover {
|
||||||
|
// background-color: $menuHover !important;
|
||||||
// menu hover
|
// }
|
||||||
.sub-menu-title-noDropdown,
|
//}
|
||||||
.el-sub-menu__title {
|
//
|
||||||
&:hover {
|
//.is-active > .el-sub-menu__title {
|
||||||
background-color: $menuHover !important;
|
// color: $subMenuActiveText !important;
|
||||||
}
|
//}
|
||||||
}
|
//
|
||||||
|
//& .nest-menu .el-sub-menu > .el-sub-menu__title,
|
||||||
.is-active > .el-sub-menu__title {
|
//& .el-sub-menu .el-menu-item {
|
||||||
color: $subMenuActiveText !important;
|
// min-width: $sideBarWidth !important;
|
||||||
}
|
// background-color: $subMenuBg !important;
|
||||||
|
//
|
||||||
& .nest-menu .el-sub-menu > .el-sub-menu__title,
|
// &:hover {
|
||||||
& .el-sub-menu .el-menu-item {
|
// background-color: $subMenuHover !important;
|
||||||
min-width: $sideBarWidth !important;
|
// }
|
||||||
background-color: $subMenuBg !important;
|
//}
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: $subMenuHover !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.hideSidebar {
|
.hideSidebar {
|
||||||
|
|
@ -161,74 +161,74 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-menu--collapse .el-menu .el-sub-menu {
|
//.el-menu--collapse .el-menu .el-sub-menu {
|
||||||
min-width: $sideBarWidth !important;
|
// min-width: $sideBarWidth !important;
|
||||||
}
|
//}
|
||||||
|
|
||||||
// mobile responsive
|
// mobile responsive
|
||||||
.mobile {
|
//.mobile {
|
||||||
.main-container {
|
// .main-container {
|
||||||
margin-left: 0px;
|
// margin-left: 0px;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
// .sidebar-container {
|
||||||
|
// transition: transform 0.28s;
|
||||||
|
// width: $sideBarWidth !important;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// &.hideSidebar {
|
||||||
|
// .sidebar-container {
|
||||||
|
// pointer-events: none;
|
||||||
|
// transition-duration: 0.3s;
|
||||||
|
// transform: translate3d(-$sideBarWidth, 0, 0);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
.sidebar-container {
|
//.withoutAnimation {
|
||||||
transition: transform 0.28s;
|
// .main-container,
|
||||||
width: $sideBarWidth !important;
|
// .sidebar-container {
|
||||||
}
|
// transition: none;
|
||||||
|
// }
|
||||||
&.hideSidebar {
|
//}
|
||||||
.sidebar-container {
|
|
||||||
pointer-events: none;
|
|
||||||
transition-duration: 0.3s;
|
|
||||||
transform: translate3d(-$sideBarWidth, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.withoutAnimation {
|
|
||||||
.main-container,
|
|
||||||
.sidebar-container {
|
|
||||||
transition: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// when menu collapsed
|
// when menu collapsed
|
||||||
.el-menu--vertical {
|
//.el-menu--vertical {
|
||||||
& > .el-menu {
|
// & > .el-menu {
|
||||||
.svg-icon {
|
// .svg-icon {
|
||||||
margin-right: 16px;
|
// margin-right: 16px;
|
||||||
}
|
// }
|
||||||
.sub-el-icon {
|
// .sub-el-icon {
|
||||||
margin-right: 12px;
|
// margin-right: 12px;
|
||||||
margin-left: -2px;
|
// margin-left: -2px;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
.nest-menu .el-sub-menu > .el-sub-menu__title,
|
// .nest-menu .el-sub-menu > .el-sub-menu__title,
|
||||||
.el-menu-item {
|
// .el-menu-item {
|
||||||
&:hover {
|
// &:hover {
|
||||||
// you can use $subMenuHover
|
// // you can use $subMenuHover
|
||||||
background-color: $menuHover !important;
|
// background-color: $menuHover !important;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// the scroll bar appears when the subMenu is too long
|
// // the scroll bar appears when the subMenu is too long
|
||||||
> .el-menu--popup {
|
// > .el-menu--popup {
|
||||||
max-height: 100vh;
|
// max-height: 100vh;
|
||||||
overflow-y: auto;
|
// overflow-y: auto;
|
||||||
|
//
|
||||||
&::-webkit-scrollbar-track-piece {
|
// &::-webkit-scrollbar-track-piece {
|
||||||
background: #d3dce6;
|
// background: #d3dce6;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
&::-webkit-scrollbar {
|
// &::-webkit-scrollbar {
|
||||||
width: 6px;
|
// width: 6px;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
&::-webkit-scrollbar-thumb {
|
// &::-webkit-scrollbar-thumb {
|
||||||
background: #99a9bf;
|
// background: #99a9bf;
|
||||||
border-radius: 20px;
|
// border-radius: 20px;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
// logo动画
|
// logo动画
|
||||||
.sidebarLogoFade-enter-active {
|
.sidebarLogoFade-enter-active {
|
||||||
transition: opacity 1.5s;
|
transition: opacity 2s;
|
||||||
}
|
}
|
||||||
.sidebarLogoFade-enter-from{
|
.sidebarLogoFade-enter-from{
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|
@ -42,7 +42,7 @@
|
||||||
|
|
||||||
// 面包屑动画
|
// 面包屑动画
|
||||||
.breadcrumb-enter-active {
|
.breadcrumb-enter-active {
|
||||||
transition: all 0.25s;
|
transition: all 0.2s;
|
||||||
}
|
}
|
||||||
.breadcrumb-enter-from,
|
.breadcrumb-enter-from,
|
||||||
.breadcrumb-leave-active {
|
.breadcrumb-leave-active {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
/**
|
|
||||||
* Created by PanJiaChen on 16/11/18.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the time to string
|
* Parse the time to string
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
/**
|
|
||||||
* Created by PanJiaChen on 16/11/18.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} path
|
* @param {string} path
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<div style="padding: 30px">
|
<div style="padding: 30px">
|
||||||
<el-alert title="menu 1" :closable="false">
|
<el-alert title="menu 1" :closable="false">
|
||||||
<router-view />
|
<router-view v-slot="{ Component }">
|
||||||
|
<component :is="Component" />
|
||||||
|
</router-view>
|
||||||
</el-alert>
|
</el-alert>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<div style="padding: 30px">
|
<div style="padding: 30px">
|
||||||
<el-alert title="menu 1-1" type="success" :closable="false">
|
<el-alert title="menu 1-1" type="success" :closable="false">
|
||||||
<router-view />
|
<router-view v-slot="{ Component }">
|
||||||
|
<component :is="Component" />
|
||||||
|
</router-view>
|
||||||
</el-alert>
|
</el-alert>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<div style="padding: 30px">
|
<div style="padding: 30px">
|
||||||
<el-alert title="menu 1-2" type="success" :closable="false">
|
<el-alert title="menu 1-2" type="success" :closable="false">
|
||||||
<router-view />
|
<router-view v-slot="{ Component }">
|
||||||
|
<component :is="Component" />
|
||||||
|
</router-view>
|
||||||
</el-alert>
|
</el-alert>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
137
yarn.lock
137
yarn.lock
|
|
@ -2,6 +2,26 @@
|
||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
"@ant-design/colors@^6.0.0":
|
||||||
|
version "6.0.0"
|
||||||
|
resolved "https://registry.npmmirror.com/@ant-design/colors/-/colors-6.0.0.tgz#9b9366257cffcc47db42b9d0203bb592c13c0298"
|
||||||
|
integrity sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==
|
||||||
|
dependencies:
|
||||||
|
"@ctrl/tinycolor" "^3.4.0"
|
||||||
|
|
||||||
|
"@ant-design/icons-svg@^4.2.1":
|
||||||
|
version "4.2.1"
|
||||||
|
resolved "https://registry.npmmirror.com/@ant-design/icons-svg/-/icons-svg-4.2.1.tgz#8630da8eb4471a4aabdaed7d1ff6a97dcb2cf05a"
|
||||||
|
integrity sha512-EB0iwlKDGpG93hW8f85CTJTs4SvMX7tt5ceupvhALp1IF44SeUFOMhKUOYqpsoYWQKAOuTRDMqn75rEaKDp0Xw==
|
||||||
|
|
||||||
|
"@ant-design/icons-vue@^6.1.0":
|
||||||
|
version "6.1.0"
|
||||||
|
resolved "https://registry.npmmirror.com/@ant-design/icons-vue/-/icons-vue-6.1.0.tgz#f9324fdc0eb4cea943cf626d2bf3db9a4ff4c074"
|
||||||
|
integrity sha512-EX6bYm56V+ZrKN7+3MT/ubDkvJ5rK/O2t380WFRflDcVFgsvl3NLH7Wxeau6R8DbrO5jWR6DSTC3B6gYFp77AA==
|
||||||
|
dependencies:
|
||||||
|
"@ant-design/colors" "^6.0.0"
|
||||||
|
"@ant-design/icons-svg" "^4.2.1"
|
||||||
|
|
||||||
"@antfu/utils@^0.5.2":
|
"@antfu/utils@^0.5.2":
|
||||||
version "0.5.2"
|
version "0.5.2"
|
||||||
resolved "https://registry.npmmirror.com/@antfu/utils/-/utils-0.5.2.tgz#8c2d931ff927be0ebe740169874a3d4004ab414b"
|
resolved "https://registry.npmmirror.com/@antfu/utils/-/utils-0.5.2.tgz#8c2d931ff927be0ebe740169874a3d4004ab414b"
|
||||||
|
|
@ -12,6 +32,13 @@
|
||||||
resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.18.10.tgz#94b5f8522356e69e8277276adf67ed280c90ecc1"
|
resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.18.10.tgz#94b5f8522356e69e8277276adf67ed280c90ecc1"
|
||||||
integrity sha512-TYk3OA0HKL6qNryUayb5UUEhM/rkOQozIBEA5ITXh5DWrSp0TlUQXMyZmnWxG/DizSWBeeQ0Zbc5z8UGaaqoeg==
|
integrity sha512-TYk3OA0HKL6qNryUayb5UUEhM/rkOQozIBEA5ITXh5DWrSp0TlUQXMyZmnWxG/DizSWBeeQ0Zbc5z8UGaaqoeg==
|
||||||
|
|
||||||
|
"@babel/runtime@^7.10.5":
|
||||||
|
version "7.19.0"
|
||||||
|
resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259"
|
||||||
|
integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==
|
||||||
|
dependencies:
|
||||||
|
regenerator-runtime "^0.13.4"
|
||||||
|
|
||||||
"@babel/runtime@^7.12.0":
|
"@babel/runtime@^7.12.0":
|
||||||
version "7.18.9"
|
version "7.18.9"
|
||||||
resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a"
|
resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a"
|
||||||
|
|
@ -31,7 +58,7 @@
|
||||||
resolved "https://registry.npmmirror.com/@better-scroll/shared-utils/-/shared-utils-2.4.2.tgz#1ac5c97495727093a22a8009560795dd5e3c18da"
|
resolved "https://registry.npmmirror.com/@better-scroll/shared-utils/-/shared-utils-2.4.2.tgz#1ac5c97495727093a22a8009560795dd5e3c18da"
|
||||||
integrity sha512-Gy/Jfbpu+hq0u+PcjkTqyXGqAf+0dexTzEZ5IDXEVwJVLmd3cx8A73oTcAZ8QZgk4wSHvlMjXecSaptkhnNPEw==
|
integrity sha512-Gy/Jfbpu+hq0u+PcjkTqyXGqAf+0dexTzEZ5IDXEVwJVLmd3cx8A73oTcAZ8QZgk4wSHvlMjXecSaptkhnNPEw==
|
||||||
|
|
||||||
"@ctrl/tinycolor@^3.4.1":
|
"@ctrl/tinycolor@^3.4.0", "@ctrl/tinycolor@^3.4.1":
|
||||||
version "3.4.1"
|
version "3.4.1"
|
||||||
resolved "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz#75b4c27948c81e88ccd3a8902047bcd797f38d32"
|
resolved "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz#75b4c27948c81e88ccd3a8902047bcd797f38d32"
|
||||||
integrity sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==
|
integrity sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==
|
||||||
|
|
@ -151,6 +178,14 @@
|
||||||
estree-walker "^2.0.1"
|
estree-walker "^2.0.1"
|
||||||
picomatch "^2.2.2"
|
picomatch "^2.2.2"
|
||||||
|
|
||||||
|
"@simonwep/pickr@~1.8.0":
|
||||||
|
version "1.8.2"
|
||||||
|
resolved "https://registry.npmmirror.com/@simonwep/pickr/-/pickr-1.8.2.tgz#96dc86675940d7cad63d69c22083dd1cbb9797cb"
|
||||||
|
integrity sha512-/l5w8BIkrpP6n1xsetx9MWPWlU6OblN5YgZZphxan0Tq4BByTCETL6lyIeY8lagalS2Nbt4F2W034KHLIiunKA==
|
||||||
|
dependencies:
|
||||||
|
core-js "^3.15.1"
|
||||||
|
nanopop "^2.1.0"
|
||||||
|
|
||||||
"@transloadit/prettier-bytes@0.0.7":
|
"@transloadit/prettier-bytes@0.0.7":
|
||||||
version "0.0.7"
|
version "0.0.7"
|
||||||
resolved "https://registry.npmmirror.com/@transloadit/prettier-bytes/-/prettier-bytes-0.0.7.tgz#cdb5399f445fdd606ed833872fa0cabdbc51686b"
|
resolved "https://registry.npmmirror.com/@transloadit/prettier-bytes/-/prettier-bytes-0.0.7.tgz#cdb5399f445fdd606ed833872fa0cabdbc51686b"
|
||||||
|
|
@ -614,6 +649,29 @@ ansi-styles@^4.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
color-convert "^2.0.1"
|
color-convert "^2.0.1"
|
||||||
|
|
||||||
|
ant-design-vue@^3.2.12:
|
||||||
|
version "3.2.12"
|
||||||
|
resolved "https://registry.npmmirror.com/ant-design-vue/-/ant-design-vue-3.2.12.tgz#996361982884b1d0d82186dba67962983bc1fbac"
|
||||||
|
integrity sha512-CPsoWJ3t+sqq/EPINPXb4fC5/9iKkUdYOfK9M9kLKbXlRN3MAoVwWUbaFnUqc+ngtbEpn/d69hTF/Eh7MeWMhQ==
|
||||||
|
dependencies:
|
||||||
|
"@ant-design/colors" "^6.0.0"
|
||||||
|
"@ant-design/icons-vue" "^6.1.0"
|
||||||
|
"@babel/runtime" "^7.10.5"
|
||||||
|
"@ctrl/tinycolor" "^3.4.0"
|
||||||
|
"@simonwep/pickr" "~1.8.0"
|
||||||
|
array-tree-filter "^2.1.0"
|
||||||
|
async-validator "^4.0.0"
|
||||||
|
dayjs "^1.10.5"
|
||||||
|
dom-align "^1.12.1"
|
||||||
|
dom-scroll-into-view "^2.0.0"
|
||||||
|
lodash "^4.17.21"
|
||||||
|
lodash-es "^4.17.15"
|
||||||
|
resize-observer-polyfill "^1.5.1"
|
||||||
|
scroll-into-view-if-needed "^2.2.25"
|
||||||
|
shallow-equal "^1.0.0"
|
||||||
|
vue-types "^3.0.0"
|
||||||
|
warning "^4.0.0"
|
||||||
|
|
||||||
anymatch@~3.1.2:
|
anymatch@~3.1.2:
|
||||||
version "3.1.2"
|
version "3.1.2"
|
||||||
resolved "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
|
resolved "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
|
||||||
|
|
@ -671,6 +729,11 @@ arr-union@^3.1.0:
|
||||||
resolved "https://registry.npmmirror.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
|
resolved "https://registry.npmmirror.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
|
||||||
integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==
|
integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==
|
||||||
|
|
||||||
|
array-tree-filter@^2.1.0:
|
||||||
|
version "2.1.0"
|
||||||
|
resolved "https://registry.npmmirror.com/array-tree-filter/-/array-tree-filter-2.1.0.tgz#873ac00fec83749f255ac8dd083814b4f6329190"
|
||||||
|
integrity sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==
|
||||||
|
|
||||||
array-union@^2.1.0:
|
array-union@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.npmmirror.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
|
resolved "https://registry.npmmirror.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
|
||||||
|
|
@ -686,7 +749,7 @@ assign-symbols@^1.0.0:
|
||||||
resolved "https://registry.npmmirror.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
|
resolved "https://registry.npmmirror.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
|
||||||
integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==
|
integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==
|
||||||
|
|
||||||
async-validator@^4.2.5:
|
async-validator@^4.0.0, async-validator@^4.2.5:
|
||||||
version "4.2.5"
|
version "4.2.5"
|
||||||
resolved "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz#c96ea3332a521699d0afaaceed510a54656c6339"
|
resolved "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz#c96ea3332a521699d0afaaceed510a54656c6339"
|
||||||
integrity sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==
|
integrity sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==
|
||||||
|
|
@ -1010,6 +1073,11 @@ copy-descriptor@^0.1.0:
|
||||||
resolved "https://registry.npmmirror.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
|
resolved "https://registry.npmmirror.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
|
||||||
integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==
|
integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==
|
||||||
|
|
||||||
|
core-js@^3.15.1:
|
||||||
|
version "3.25.1"
|
||||||
|
resolved "https://registry.npmmirror.com/core-js/-/core-js-3.25.1.tgz#5818e09de0db8956e16bf10e2a7141e931b7c69c"
|
||||||
|
integrity sha512-sr0FY4lnO1hkQ4gLDr24K0DGnweGO1QwSj5BpfQjpSJPdqWalja4cTps29Y/PJVG/P7FYlPDkH3hO+Tr0CvDgQ==
|
||||||
|
|
||||||
core-js@^3.6.5:
|
core-js@^3.6.5:
|
||||||
version "3.24.1"
|
version "3.24.1"
|
||||||
resolved "https://registry.npmmirror.com/core-js/-/core-js-3.24.1.tgz#cf7724d41724154010a6576b7b57d94c5d66e64f"
|
resolved "https://registry.npmmirror.com/core-js/-/core-js-3.24.1.tgz#cf7724d41724154010a6576b7b57d94c5d66e64f"
|
||||||
|
|
@ -1116,6 +1184,11 @@ dart-sass@^1.25.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
chokidar ">=2.0.0 <4.0.0"
|
chokidar ">=2.0.0 <4.0.0"
|
||||||
|
|
||||||
|
dayjs@^1.10.5:
|
||||||
|
version "1.11.5"
|
||||||
|
resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.5.tgz#00e8cc627f231f9499c19b38af49f56dc0ac5e93"
|
||||||
|
integrity sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA==
|
||||||
|
|
||||||
dayjs@^1.11.3, dayjs@^1.11.4, dayjs@^1.8.34:
|
dayjs@^1.11.3, dayjs@^1.11.4, dayjs@^1.8.34:
|
||||||
version "1.11.4"
|
version "1.11.4"
|
||||||
resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.4.tgz#3b3c10ca378140d8917e06ebc13a4922af4f433e"
|
resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.4.tgz#3b3c10ca378140d8917e06ebc13a4922af4f433e"
|
||||||
|
|
@ -1208,6 +1281,16 @@ doctrine@^3.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
esutils "^2.0.2"
|
esutils "^2.0.2"
|
||||||
|
|
||||||
|
dom-align@^1.12.1:
|
||||||
|
version "1.12.3"
|
||||||
|
resolved "https://registry.npmmirror.com/dom-align/-/dom-align-1.12.3.tgz#a36d02531dae0eefa2abb0c4db6595250526f103"
|
||||||
|
integrity sha512-Gj9hZN3a07cbR6zviMUBOMPdWxYhbMI+x+WS0NAIu2zFZmbK8ys9R79g+iG9qLnlCwpFoaB+fKy8Pdv470GsPA==
|
||||||
|
|
||||||
|
dom-scroll-into-view@^2.0.0:
|
||||||
|
version "2.0.1"
|
||||||
|
resolved "https://registry.npmmirror.com/dom-scroll-into-view/-/dom-scroll-into-view-2.0.1.tgz#0decc8522801fd8d3f1c6ba355a74d382c5f989b"
|
||||||
|
integrity sha512-bvVTQe1lfaUr1oFzZX80ce9KLDlZ3iU+XGNE/bz9HnGdklTieqsbmsLHe+rT2XWqopvL0PckkYqN7ksmm5pe3w==
|
||||||
|
|
||||||
dom-serializer@0:
|
dom-serializer@0:
|
||||||
version "0.2.2"
|
version "0.2.2"
|
||||||
resolved "https://registry.npmmirror.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51"
|
resolved "https://registry.npmmirror.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51"
|
||||||
|
|
@ -2247,6 +2330,11 @@ is-plain-obj@^1.1:
|
||||||
resolved "https://registry.npmmirror.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
|
resolved "https://registry.npmmirror.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
|
||||||
integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==
|
integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==
|
||||||
|
|
||||||
|
is-plain-object@3.0.1:
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "https://registry.npmmirror.com/is-plain-object/-/is-plain-object-3.0.1.tgz#662d92d24c0aa4302407b0d45d21f2251c85f85b"
|
||||||
|
integrity sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==
|
||||||
|
|
||||||
is-plain-object@^2.0.3, is-plain-object@^2.0.4:
|
is-plain-object@^2.0.3, is-plain-object@^2.0.4:
|
||||||
version "2.0.4"
|
version "2.0.4"
|
||||||
resolved "https://registry.npmmirror.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
|
resolved "https://registry.npmmirror.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
|
||||||
|
|
@ -2301,6 +2389,11 @@ js-binary-schema-parser@^2.0.2:
|
||||||
resolved "https://registry.npmmirror.com/js-binary-schema-parser/-/js-binary-schema-parser-2.0.3.tgz#3d7848748e8586e63b34e8911b643f59cfb6396e"
|
resolved "https://registry.npmmirror.com/js-binary-schema-parser/-/js-binary-schema-parser-2.0.3.tgz#3d7848748e8586e63b34e8911b643f59cfb6396e"
|
||||||
integrity sha512-xezGJmOb4lk/M1ZZLTR/jaBHQ4gG/lqQnJqdIv4721DMggsa1bDVlHXNeHYogaIEHD9vCRv0fcL4hMA+Coarkg==
|
integrity sha512-xezGJmOb4lk/M1ZZLTR/jaBHQ4gG/lqQnJqdIv4721DMggsa1bDVlHXNeHYogaIEHD9vCRv0fcL4hMA+Coarkg==
|
||||||
|
|
||||||
|
"js-tokens@^3.0.0 || ^4.0.0":
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||||
|
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
|
||||||
|
|
||||||
js-yaml@^4.1.0:
|
js-yaml@^4.1.0:
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
|
resolved "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
|
||||||
|
|
@ -2421,7 +2514,7 @@ locate-path@^6.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
p-locate "^5.0.0"
|
p-locate "^5.0.0"
|
||||||
|
|
||||||
lodash-es@^4.17.21:
|
lodash-es@^4.17.15, lodash-es@^4.17.21:
|
||||||
version "4.17.21"
|
version "4.17.21"
|
||||||
resolved "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
|
resolved "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
|
||||||
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
|
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
|
||||||
|
|
@ -2536,6 +2629,13 @@ lodash@^4.17.21:
|
||||||
resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||||
|
|
||||||
|
loose-envify@^1.0.0:
|
||||||
|
version "1.4.0"
|
||||||
|
resolved "https://registry.npmmirror.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||||
|
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||||
|
dependencies:
|
||||||
|
js-tokens "^3.0.0 || ^4.0.0"
|
||||||
|
|
||||||
lru-cache@^6.0.0:
|
lru-cache@^6.0.0:
|
||||||
version "6.0.0"
|
version "6.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
|
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
|
||||||
|
|
@ -2738,6 +2838,11 @@ nanomatch@^1.2.1:
|
||||||
snapdragon "^0.8.1"
|
snapdragon "^0.8.1"
|
||||||
to-regex "^3.0.1"
|
to-regex "^3.0.1"
|
||||||
|
|
||||||
|
nanopop@^2.1.0:
|
||||||
|
version "2.2.0"
|
||||||
|
resolved "https://registry.npmmirror.com/nanopop/-/nanopop-2.2.0.tgz#bd1c25588a7beaf68865bc2df19db4c58c77dcc9"
|
||||||
|
integrity sha512-E9JaHcxh3ere8/BEZHAcnuD10RluTSPyTToBvoFWS9/7DcCx6gyKjbn7M7Bx7E1veCxCuY1iO6h4+gdAf1j73Q==
|
||||||
|
|
||||||
natural-compare@^1.4.0:
|
natural-compare@^1.4.0:
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
resolved "https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
||||||
|
|
@ -3132,6 +3237,11 @@ repeat-string@^1.6.1:
|
||||||
resolved "https://registry.npmmirror.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
|
resolved "https://registry.npmmirror.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
|
||||||
integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==
|
integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==
|
||||||
|
|
||||||
|
resize-observer-polyfill@^1.5.1:
|
||||||
|
version "1.5.1"
|
||||||
|
resolved "https://registry.npmmirror.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
|
||||||
|
integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
|
||||||
|
|
||||||
resolve-from@^4.0.0:
|
resolve-from@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
|
resolved "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
|
||||||
|
|
@ -3222,7 +3332,7 @@ saxes@^5.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
xmlchars "^2.2.0"
|
xmlchars "^2.2.0"
|
||||||
|
|
||||||
scroll-into-view-if-needed@^2.2.28:
|
scroll-into-view-if-needed@^2.2.25, scroll-into-view-if-needed@^2.2.28:
|
||||||
version "2.2.29"
|
version "2.2.29"
|
||||||
resolved "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.29.tgz#551791a84b7e2287706511f8c68161e4990ab885"
|
resolved "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.29.tgz#551791a84b7e2287706511f8c68161e4990ab885"
|
||||||
integrity sha512-hxpAR6AN+Gh53AdAimHM6C8oTN1ppwVZITihix+WqalywBeFcQ6LdQP5ABNl26nX8GTEL7VT+b8lKpdqq65wXg==
|
integrity sha512-hxpAR6AN+Gh53AdAimHM6C8oTN1ppwVZITihix+WqalywBeFcQ6LdQP5ABNl26nX8GTEL7VT+b8lKpdqq65wXg==
|
||||||
|
|
@ -3261,6 +3371,11 @@ setimmediate@^1.0.5, setimmediate@~1.0.4:
|
||||||
resolved "https://registry.npmmirror.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
|
resolved "https://registry.npmmirror.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
|
||||||
integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==
|
integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==
|
||||||
|
|
||||||
|
shallow-equal@^1.0.0:
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.npmmirror.com/shallow-equal/-/shallow-equal-1.2.1.tgz#4c16abfa56043aa20d050324efa68940b0da79da"
|
||||||
|
integrity sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==
|
||||||
|
|
||||||
shebang-command@^2.0.0:
|
shebang-command@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
|
resolved "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
|
||||||
|
|
@ -3959,6 +4074,13 @@ vue-tsc@^0.38.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
"@volar/vue-typescript" "0.38.9"
|
"@volar/vue-typescript" "0.38.9"
|
||||||
|
|
||||||
|
vue-types@^3.0.0:
|
||||||
|
version "3.0.2"
|
||||||
|
resolved "https://registry.npmmirror.com/vue-types/-/vue-types-3.0.2.tgz#ec16e05d412c038262fc1efa4ceb9647e7fb601d"
|
||||||
|
integrity sha512-IwUC0Aq2zwaXqy74h4WCvFCUtoV0iSWr0snWnE9TnU18S66GAQyqQbRf2qfJtUuiFsBf6qp0MEwdonlwznlcrw==
|
||||||
|
dependencies:
|
||||||
|
is-plain-object "3.0.1"
|
||||||
|
|
||||||
vue@^3.0.0:
|
vue@^3.0.0:
|
||||||
version "3.2.37"
|
version "3.2.37"
|
||||||
resolved "https://registry.npmmirror.com/vue/-/vue-3.2.37.tgz#da220ccb618d78579d25b06c7c21498ca4e5452e"
|
resolved "https://registry.npmmirror.com/vue/-/vue-3.2.37.tgz#da220ccb618d78579d25b06c7c21498ca4e5452e"
|
||||||
|
|
@ -3984,6 +4106,13 @@ vuex@^4.0.0-0:
|
||||||
dependencies:
|
dependencies:
|
||||||
"@vue/devtools-api" "^6.0.0-beta.11"
|
"@vue/devtools-api" "^6.0.0-beta.11"
|
||||||
|
|
||||||
|
warning@^4.0.0:
|
||||||
|
version "4.0.3"
|
||||||
|
resolved "https://registry.npmmirror.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
|
||||||
|
integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==
|
||||||
|
dependencies:
|
||||||
|
loose-envify "^1.0.0"
|
||||||
|
|
||||||
webpack-sources@^3.2.3:
|
webpack-sources@^3.2.3:
|
||||||
version "3.2.3"
|
version "3.2.3"
|
||||||
resolved "https://registry.npmmirror.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
|
resolved "https://registry.npmmirror.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue