mirror of
https://github.com/pure-admin/vue-pure-admin.git
synced 2025-06-09 01:47:20 +08:00
Merge branch 'main' of github.com:pure-admin/vue-pure-admin into gitee
This commit is contained in:
commit
c77ec6bda3
3
.env
3
.env
@ -1,2 +1,5 @@
|
||||
# 平台本地运行端口号
|
||||
VITE_PORT = 8848
|
||||
|
||||
# 是否隐藏首页 隐藏 true 不隐藏 false (勿删除,VITE_HIDE_HOME只需在.env文件配置)
|
||||
VITE_HIDE_HOME = false
|
||||
|
@ -13,4 +13,4 @@ VITE_CDN = true
|
||||
# 是否启用gzip压缩或brotli压缩(分两种情况,删除原始文件和不删除原始文件)
|
||||
# 压缩时不删除原始文件的配置:gzip、brotli、both(同时开启 gzip 与 brotli 压缩)、none(不开启压缩,默认)
|
||||
# 压缩时删除原始文件的配置:gzip-clear、brotli-clear、both-clear(同时开启 gzip 与 brotli 压缩)、none(不开启压缩,默认)
|
||||
VITE_COMPRESSION = "both-clear"
|
||||
VITE_COMPRESSION = "none"
|
||||
|
@ -1,3 +1,4 @@
|
||||
/dist/*
|
||||
/public/*
|
||||
public/*
|
||||
public/*
|
||||
src/style/reset.scss
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 pure-admin
|
||||
Copyright (c) 2020-present, pure-admin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -150,7 +150,7 @@ If you think this project is helpful to you, you can help the author buy a glass
|
||||
|
||||
In principle, no fees and copyrights are charged, and you can use it with confidence, but if you need secondary open source, please contact the author for permission!
|
||||
|
||||
[MIT © xiaoxian521-2023](./LICENSE)
|
||||
[MIT © 2020-present, pure-admin](./LICENSE)
|
||||
|
||||
## Backers
|
||||
|
||||
|
@ -154,7 +154,7 @@ pnpm build
|
||||
|
||||
原则上不收取任何费用及版权,可以放心使用,不过如需二次开源(比如用此平台二次开发并开源)请联系作者获取许可!
|
||||
|
||||
[MIT © xiaoxian521-2023](./LICENSE)
|
||||
[MIT © 2020-present, pure-admin](./LICENSE)
|
||||
|
||||
## 支持者
|
||||
|
||||
|
@ -6,6 +6,7 @@ const warpperEnv = (envConf: Recordable): ViteEnv => {
|
||||
VITE_PUBLIC_PATH: "",
|
||||
VITE_ROUTER_HISTORY: "",
|
||||
VITE_CDN: false,
|
||||
VITE_HIDE_HOME: "false",
|
||||
VITE_COMPRESSION: "none"
|
||||
};
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import type { Plugin } from "vite";
|
||||
import dayjs, { Dayjs } from "dayjs";
|
||||
import utils from "@pureadmin/utils";
|
||||
import duration from "dayjs/plugin/duration";
|
||||
import { green, blue, bold } from "picocolors";
|
||||
import { getPackageSize } from "@pureadmin/utils";
|
||||
dayjs.extend(duration);
|
||||
|
||||
export function viteBuildInfo(): Plugin {
|
||||
@ -33,7 +33,7 @@ export function viteBuildInfo(): Plugin {
|
||||
closeBundle() {
|
||||
if (config.command === "build") {
|
||||
endTime = dayjs(new Date());
|
||||
getPackageSize({
|
||||
utils.getPackageSize({
|
||||
folder: outDir,
|
||||
callback: (size: string) => {
|
||||
console.log(
|
||||
|
@ -12,7 +12,6 @@ const include = [
|
||||
"axios",
|
||||
"pinia",
|
||||
"swiper",
|
||||
"echarts",
|
||||
"intro.js",
|
||||
"vue-i18n",
|
||||
"js-cookie",
|
||||
@ -38,11 +37,7 @@ const include = [
|
||||
"@amap/amap-jsapi-loader",
|
||||
"el-table-infinite-scroll",
|
||||
"@wangeditor/editor-for-vue",
|
||||
"xgplayer/dist/simple_player",
|
||||
"xgplayer/es/controls/volume",
|
||||
"vuedraggable/src/vuedraggable",
|
||||
"xgplayer/es/controls/screenShot",
|
||||
"xgplayer/es/controls/playbackRate"
|
||||
"vuedraggable/src/vuedraggable"
|
||||
];
|
||||
|
||||
/**
|
||||
|
38
index.html
38
index.html
@ -21,54 +21,54 @@
|
||||
html,
|
||||
body,
|
||||
#app {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
position: relative;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.loader,
|
||||
.loader:before,
|
||||
.loader:after {
|
||||
border-radius: 50%;
|
||||
.loader::before,
|
||||
.loader::after {
|
||||
width: 2.5em;
|
||||
height: 2.5em;
|
||||
border-radius: 50%;
|
||||
animation: load-animation 1.8s infinite ease-in-out;
|
||||
animation-fill-mode: both;
|
||||
animation: loadAnimation 1.8s infinite ease-in-out;
|
||||
}
|
||||
|
||||
.loader {
|
||||
color: #406eeb;
|
||||
font-size: 10px;
|
||||
margin: 80px auto;
|
||||
position: relative;
|
||||
top: 0;
|
||||
margin: 80px auto;
|
||||
font-size: 10px;
|
||||
color: #406eeb;
|
||||
text-indent: -9999em;
|
||||
transform: translateZ(0);
|
||||
animation-delay: -0.16s;
|
||||
top: 0;
|
||||
transform: translate(-50%, 0);
|
||||
animation-delay: -0.16s;
|
||||
}
|
||||
|
||||
.loader:before,
|
||||
.loader:after {
|
||||
content: "";
|
||||
.loader::before,
|
||||
.loader::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.loader:before {
|
||||
.loader::before {
|
||||
left: -3.5em;
|
||||
animation-delay: -0.32s;
|
||||
}
|
||||
|
||||
.loader:after {
|
||||
.loader::after {
|
||||
left: 3.5em;
|
||||
}
|
||||
|
||||
@keyframes loadAnimation {
|
||||
@keyframes load-animation {
|
||||
0%,
|
||||
80%,
|
||||
100% {
|
||||
|
@ -36,6 +36,7 @@ menus:
|
||||
hsfourZeroOne: "403"
|
||||
hsFive: "500"
|
||||
hscomponents: Components
|
||||
hsdialog: Dialog Components
|
||||
hsmessage: Message Tips Components
|
||||
hsvideo: Video Components
|
||||
hsmap: Map Components
|
||||
|
@ -36,6 +36,7 @@ menus:
|
||||
hsfourZeroOne: "403"
|
||||
hsFive: "500"
|
||||
hscomponents: 组件
|
||||
hsdialog: 函数式弹框组件
|
||||
hsmessage: 消息提示组件
|
||||
hsvideo: 视频组件
|
||||
hsmap: 地图组件
|
||||
|
130
package.json
130
package.json
@ -15,8 +15,8 @@
|
||||
"cloc": "NODE_OPTIONS=--max-old-space-size=4096 cloc . --exclude-dir=node_modules --exclude-lang=YAML",
|
||||
"clean:cache": "rm -rf node_modules && rm -rf .eslintcache && pnpm install",
|
||||
"lint:eslint": "eslint --cache --max-warnings 0 \"{src,mock,build}/**/*.{vue,js,ts,tsx}\" --fix",
|
||||
"lint:prettier": "prettier --write \"src/**/*.{js,ts,json,tsx,css,less,scss,vue,html,md}\"",
|
||||
"lint:stylelint": "stylelint --cache --fix \"**/*.{vue,css,scss,postcss,less}\" --cache --cache-location node_modules/.cache/stylelint/",
|
||||
"lint:prettier": "prettier --write \"src/**/*.{js,ts,json,tsx,css,scss,vue,html,md}\"",
|
||||
"lint:stylelint": "stylelint --cache --fix \"**/*.{html,vue,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
|
||||
"lint:lint-staged": "lint-staged -c ./.husky/lintstagedrc.js",
|
||||
"lint:pretty": "pretty-quick --staged",
|
||||
"lint": "pnpm lint:eslint && pnpm lint:prettier && pnpm lint:stylelint",
|
||||
@ -29,121 +29,131 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"@amap/amap-jsapi-loader": "^1.0.1",
|
||||
"@howdyjs/mouse-menu": "^2.0.5",
|
||||
"@logicflow/core": "^1.1.30",
|
||||
"@logicflow/extension": "^1.1.30",
|
||||
"@howdyjs/mouse-menu": "^2.0.7",
|
||||
"@logicflow/core": "^1.2.5",
|
||||
"@logicflow/extension": "^1.2.5",
|
||||
"@pureadmin/descriptions": "^1.1.1",
|
||||
"@pureadmin/table": "^2.0.0",
|
||||
"@pureadmin/utils": "^1.8.5",
|
||||
"@vueuse/core": "^9.13.0",
|
||||
"@pureadmin/utils": "^1.8.9",
|
||||
"@vueuse/core": "^10.1.2",
|
||||
"@vueuse/motion": "2.0.0-beta.12",
|
||||
"@wangeditor/editor": "^5.1.21",
|
||||
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||
"animate.css": "^4.1.1",
|
||||
"axios": "^1.2.2",
|
||||
"axios": "^1.4.0",
|
||||
"china-area-data": "^5.0.1",
|
||||
"cropperjs": "^1.5.12",
|
||||
"cropperjs": "^1.5.13",
|
||||
"dayjs": "^1.11.7",
|
||||
"echarts": "^5.4.2",
|
||||
"el-table-infinite-scroll": "^3.0.1",
|
||||
"element-plus": "^2.3.1",
|
||||
"element-plus": "^2.3.4",
|
||||
"element-resize-detector": "^1.2.4",
|
||||
"intro.js": "^6.0.0",
|
||||
"js-cookie": "^3.0.1",
|
||||
"intro.js": "^7.0.1",
|
||||
"js-cookie": "^3.0.5",
|
||||
"jsbarcode": "^3.11.5",
|
||||
"md-editor-v3": "^2.7.2",
|
||||
"md-editor-v3": "^3.0.1",
|
||||
"mitt": "^3.0.0",
|
||||
"mockjs": "^1.1.0",
|
||||
"nprogress": "^0.2.0",
|
||||
"path": "^0.12.7",
|
||||
"pinia": "^2.0.33",
|
||||
"qrcode": "^1.5.1",
|
||||
"qs": "^6.11.0",
|
||||
"pinia": "^2.0.35",
|
||||
"qrcode": "^1.5.3",
|
||||
"qs": "^6.11.1",
|
||||
"responsive-storage": "^2.2.0",
|
||||
"sortablejs": "^1.15.0",
|
||||
"swiper": "^9.1.0",
|
||||
"swiper": "^9.2.4",
|
||||
"typeit": "^8.7.1",
|
||||
"v-contextmenu": "3.0.0",
|
||||
"vue": "^3.2.47",
|
||||
"vue-i18n": "^9.2.2",
|
||||
"vue-json-pretty": "^2.2.3",
|
||||
"vue-pdf-embed": "^1.1.5",
|
||||
"vue-json-pretty": "^2.2.4",
|
||||
"vue-pdf-embed": "^1.1.6",
|
||||
"vue-router": "^4.1.6",
|
||||
"vue-types": "^5.0.2",
|
||||
"vue-virtual-scroller": "2.0.0-beta.7",
|
||||
"vue3-danmaku": "^1.2.0",
|
||||
"vue3-danmaku": "1.4.0-beta.1",
|
||||
"vuedraggable": "^4.1.0",
|
||||
"xgplayer": "^2.32.2",
|
||||
"xgplayer": "^3.0.2",
|
||||
"xlsx": "^0.18.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "13.1.0",
|
||||
"@commitlint/config-conventional": "13.1.0",
|
||||
"@iconify-icons/ep": "^1.2.10",
|
||||
"@iconify-icons/ri": "^1.2.4",
|
||||
"@iconify/vue": "^4.0.2",
|
||||
"@commitlint/cli": "^17.6.3",
|
||||
"@commitlint/config-conventional": "^17.6.3",
|
||||
"@iconify-icons/ep": "^1.2.11",
|
||||
"@iconify-icons/ri": "^1.2.7",
|
||||
"@iconify/vue": "^4.1.1",
|
||||
"@intlify/unplugin-vue-i18n": "^0.10.0",
|
||||
"@pureadmin/theme": "^3.0.0",
|
||||
"@types/element-resize-detector": "1.1.3",
|
||||
"@types/intro.js": "^5.1.0",
|
||||
"@types/js-cookie": "^3.0.1",
|
||||
"@types/intro.js": "^5.1.1",
|
||||
"@types/js-cookie": "^3.0.3",
|
||||
"@types/mockjs": "^1.0.7",
|
||||
"@types/node": "^18.11.9",
|
||||
"@types/node": "^18.15.12",
|
||||
"@types/nprogress": "0.2.0",
|
||||
"@types/qrcode": "^1.4.2",
|
||||
"@types/qrcode": "^1.5.0",
|
||||
"@types/qs": "^6.9.7",
|
||||
"@types/sortablejs": "^1.15.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.43.0",
|
||||
"@typescript-eslint/parser": "^5.43.0",
|
||||
"@vitejs/plugin-vue": "^4.1.0",
|
||||
"@types/sortablejs": "^1.15.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.2",
|
||||
"@typescript-eslint/parser": "^5.59.2",
|
||||
"@vitejs/plugin-vue": "^4.2.1",
|
||||
"@vitejs/plugin-vue-jsx": "^3.0.1",
|
||||
"@vue/eslint-config-prettier": "^7.0.0",
|
||||
"@vue/eslint-config-typescript": "^11.0.2",
|
||||
"@vue/eslint-config-prettier": "^7.1.0",
|
||||
"@vue/eslint-config-typescript": "^11.0.3",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"cloc": "^2.11.0",
|
||||
"cssnano": "^6.0.0",
|
||||
"eslint": "^8.8.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-vue": "^9.7.0",
|
||||
"husky": "^7.0.4",
|
||||
"lint-staged": "11.1.2",
|
||||
"cssnano": "^6.0.1",
|
||||
"eslint": "^8.40.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-vue": "^9.11.1",
|
||||
"husky": "^8.0.3",
|
||||
"lint-staged": "^13.2.2",
|
||||
"picocolors": "^1.0.0",
|
||||
"postcss": "^8.4.21",
|
||||
"postcss": "^8.4.23",
|
||||
"postcss-html": "^1.5.0",
|
||||
"postcss-import": "^15.1.0",
|
||||
"postcss-scss": "^4.0.6",
|
||||
"prettier": "^2.5.1",
|
||||
"prettier": "^2.8.7",
|
||||
"pretty-quick": "3.1.1",
|
||||
"rimraf": "^4.4.1",
|
||||
"rimraf": "^5.0.0",
|
||||
"rollup-plugin-visualizer": "^5.9.0",
|
||||
"sass": "^1.60.0",
|
||||
"sass": "^1.62.1",
|
||||
"sass-loader": "^13.2.2",
|
||||
"stylelint": "^14.3.0",
|
||||
"stylelint-config-html": "^1.0.0",
|
||||
"stylelint-config-prettier": "^9.0.3",
|
||||
"stylelint-config-recommended": "^9.0.0",
|
||||
"stylelint-config-standard": "^29.0.0",
|
||||
"stylelint-order": "^5.0.0",
|
||||
"stylelint": "^15.6.1",
|
||||
"stylelint-config-html": "^1.1.0",
|
||||
"stylelint-config-recess-order": "^4.0.0",
|
||||
"stylelint-config-recommended": "^12.0.0",
|
||||
"stylelint-config-recommended-scss": "^11.0.0",
|
||||
"stylelint-config-recommended-vue": "^1.4.0",
|
||||
"stylelint-config-standard": "^33.0.0",
|
||||
"stylelint-config-standard-scss": "^9.0.0",
|
||||
"stylelint-order": "^6.0.3",
|
||||
"stylelint-prettier": "^3.0.0",
|
||||
"stylelint-scss": "^5.0.0",
|
||||
"svgo": "^3.0.2",
|
||||
"tailwindcss": "^3.2.7",
|
||||
"terser": "^5.16.8",
|
||||
"typescript": "^5.0.2",
|
||||
"unplugin-vue-define-options": "^1.0.0",
|
||||
"vite": "^4.2.1",
|
||||
"tailwindcss": "^3.3.2",
|
||||
"terser": "^5.17.1",
|
||||
"typescript": "^5.0.4",
|
||||
"unplugin-vue-define-options": "1.1.6",
|
||||
"vite": "^4.3.5",
|
||||
"vite-plugin-cdn-import": "^0.3.5",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-mock": "^2.9.6",
|
||||
"vite-plugin-remove-console": "^2.1.0",
|
||||
"vite-plugin-remove-console": "^2.1.1",
|
||||
"vite-svg-loader": "^4.0.0",
|
||||
"vue-eslint-parser": "^9.1.0",
|
||||
"vue-eslint-parser": "^9.2.1",
|
||||
"vue-tsc": "^1.2.0"
|
||||
},
|
||||
"pnpm": {
|
||||
"peerDependencyRules": {
|
||||
"ignoreMissing": [
|
||||
"rollup",
|
||||
"webpack"
|
||||
"webpack",
|
||||
"core-js"
|
||||
]
|
||||
},
|
||||
"allowedDeprecatedVersions": {
|
||||
"sourcemap-codec": "*",
|
||||
"stable": "*"
|
||||
}
|
||||
},
|
||||
"repository": "git@github.com:pure-admin/vue-pure-admin.git",
|
||||
|
6731
pnpm-lock.yaml
generated
6731
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,7 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
"postcss-import": {},
|
||||
"tailwindcss/nesting": {},
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
...(process.env.NODE_ENV === "production" ? { cssnano: {} } : {})
|
||||
|
@ -19,6 +19,7 @@
|
||||
"MenuArrowIconNoTransition": true,
|
||||
"CachingAsyncRoutes": false,
|
||||
"TooltipEffect": "light",
|
||||
"ResponsiveStorageNameSpace": "responsive-",
|
||||
"MapConfigure": {
|
||||
"amapKey": "97b3248d1553172e81f168cf94ea667e",
|
||||
"options": {
|
||||
|
@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<el-config-provider :locale="currentLocale">
|
||||
<router-view />
|
||||
<ReDialog />
|
||||
</el-config-provider>
|
||||
</template>
|
||||
|
||||
@ -9,10 +10,12 @@ import { defineComponent } from "vue";
|
||||
import { ElConfigProvider } from "element-plus";
|
||||
import zhCn from "element-plus/lib/locale/lang/zh-cn";
|
||||
import en from "element-plus/lib/locale/lang/en";
|
||||
import { ReDialog } from "@/components/ReDialog";
|
||||
export default defineComponent({
|
||||
name: "app",
|
||||
components: {
|
||||
[ElConfigProvider.name]: ElConfigProvider
|
||||
[ElConfigProvider.name]: ElConfigProvider,
|
||||
ReDialog
|
||||
},
|
||||
computed: {
|
||||
currentLocale() {
|
||||
|
39
src/components/ReDialog/index.ts
Normal file
39
src/components/ReDialog/index.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { ref } from "vue";
|
||||
import reDialog from "./index.vue";
|
||||
import { useTimeoutFn } from "@vueuse/core";
|
||||
import { withInstall } from "@pureadmin/utils";
|
||||
import type {
|
||||
EventType,
|
||||
ArgsType,
|
||||
DialogProps,
|
||||
ButtonProps,
|
||||
DialogOptions
|
||||
} from "./type";
|
||||
|
||||
const dialogStore = ref<Array<DialogOptions>>([]);
|
||||
|
||||
const addDialog = (options: DialogOptions) => {
|
||||
const open = () =>
|
||||
dialogStore.value.push(Object.assign(options, { visible: true }));
|
||||
if (options?.openDelay) {
|
||||
useTimeoutFn(() => {
|
||||
open();
|
||||
}, options.openDelay);
|
||||
} else {
|
||||
open();
|
||||
}
|
||||
};
|
||||
|
||||
const closeDialog = (options: DialogOptions, index: number, args?: any) => {
|
||||
dialogStore.value.splice(index, 1);
|
||||
options.closeCallBack && options.closeCallBack({ options, index, args });
|
||||
};
|
||||
|
||||
const closeAllDialog = () => {
|
||||
dialogStore.value = [];
|
||||
};
|
||||
|
||||
const ReDialog = withInstall(reDialog);
|
||||
|
||||
export type { EventType, ArgsType, DialogProps, ButtonProps, DialogOptions };
|
||||
export { ReDialog, dialogStore, addDialog, closeDialog, closeAllDialog };
|
106
src/components/ReDialog/index.vue
Normal file
106
src/components/ReDialog/index.vue
Normal file
@ -0,0 +1,106 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
import { isFunction } from "@pureadmin/utils";
|
||||
import {
|
||||
type DialogOptions,
|
||||
type ButtonProps,
|
||||
type EventType,
|
||||
dialogStore,
|
||||
closeDialog
|
||||
} from "./index";
|
||||
|
||||
const footerButtons = computed(() => {
|
||||
return (options: DialogOptions) => {
|
||||
return options?.footerButtons?.length > 0
|
||||
? options.footerButtons
|
||||
: ([
|
||||
{
|
||||
label: "取消",
|
||||
text: true,
|
||||
bg: true,
|
||||
btnClick: ({ dialog: { options, index } }) => {
|
||||
closeDialog(options, index, { command: "cancel" });
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "确定",
|
||||
type: "primary",
|
||||
text: true,
|
||||
bg: true,
|
||||
btnClick: ({ dialog: { options, index } }) => {
|
||||
closeDialog(options, index, { command: "sure" });
|
||||
}
|
||||
}
|
||||
] as Array<ButtonProps>);
|
||||
};
|
||||
});
|
||||
|
||||
function eventsCallBack(
|
||||
event: EventType,
|
||||
options: DialogOptions,
|
||||
index: number
|
||||
) {
|
||||
if (options?.[event] && isFunction(options?.[event])) {
|
||||
return options?.[event]({ options, index });
|
||||
}
|
||||
}
|
||||
|
||||
function handleClose(
|
||||
options: DialogOptions,
|
||||
index: number,
|
||||
args = { command: "close" }
|
||||
) {
|
||||
closeDialog(options, index, args);
|
||||
eventsCallBack("close", options, index);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-dialog
|
||||
v-for="(options, index) in dialogStore"
|
||||
:key="index"
|
||||
v-bind="options"
|
||||
v-model="options.visible"
|
||||
@opened="eventsCallBack('open', options, index)"
|
||||
@close="handleClose(options, index)"
|
||||
@openAutoFocus="eventsCallBack('openAutoFocus', options, index)"
|
||||
@closeAutoFocus="eventsCallBack('closeAutoFocus', options, index)"
|
||||
>
|
||||
<!-- header -->
|
||||
<template
|
||||
v-if="options?.headerRenderer"
|
||||
#header="{ close, titleId, titleClass }"
|
||||
>
|
||||
<component
|
||||
:is="options?.headerRenderer({ close, titleId, titleClass })"
|
||||
/>
|
||||
</template>
|
||||
<!-- default -->
|
||||
<component
|
||||
v-bind="options?.props"
|
||||
:is="options.contentRenderer({ options, index })"
|
||||
@close="args => handleClose(options, index, args)"
|
||||
/>
|
||||
<!-- footer -->
|
||||
<template v-if="!options?.hideFooter" #footer>
|
||||
<template v-if="options?.footerRenderer">
|
||||
<component :is="options?.footerRenderer({ options, index })" />
|
||||
</template>
|
||||
<span v-else>
|
||||
<el-button
|
||||
v-for="(btn, key) in footerButtons(options)"
|
||||
:key="key"
|
||||
v-bind="btn"
|
||||
@click="
|
||||
btn.btnClick({
|
||||
dialog: { options, index },
|
||||
button: { btn, index: key }
|
||||
})
|
||||
"
|
||||
>
|
||||
{{ btn?.label }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
194
src/components/ReDialog/type.ts
Normal file
194
src/components/ReDialog/type.ts
Normal file
@ -0,0 +1,194 @@
|
||||
import type { CSSProperties, VNode, Component } from "vue";
|
||||
|
||||
type DoneFn = (cancel?: boolean) => void;
|
||||
type EventType = "open" | "close" | "openAutoFocus" | "closeAutoFocus";
|
||||
type ArgsType = {
|
||||
/** `cancel` 点击取消按钮、`sure` 点击确定按钮、`close` 点击右上角关闭按钮或者空白页 */
|
||||
command: "cancel" | "sure" | "close";
|
||||
};
|
||||
|
||||
/** https://element-plus.org/zh-CN/component/dialog.html#attributes */
|
||||
type DialogProps = {
|
||||
/** `Dialog` 的显示与隐藏 */
|
||||
visible?: boolean;
|
||||
/** `Dialog` 的标题 */
|
||||
title?: string;
|
||||
/** `Dialog` 的宽度,默认 `50%` */
|
||||
width?: string | number;
|
||||
/** 是否为全屏 `Dialog`,默认 `false` */
|
||||
fullscreen?: boolean;
|
||||
/** `Dialog CSS` 中的 `margin-top` 值,默认 `15vh` */
|
||||
top?: string;
|
||||
/** 是否需要遮罩层,默认 `true` */
|
||||
modal?: boolean;
|
||||
/** `Dialog` 自身是否插入至 `body` 元素上。嵌套的 `Dialog` 必须指定该属性并赋值为 `true`,默认 `false` */
|
||||
appendToBody?: boolean;
|
||||
/** 是否在 `Dialog` 出现时将 `body` 滚动锁定,默认 `true` */
|
||||
lockScroll?: boolean;
|
||||
/** `Dialog` 的自定义类名 */
|
||||
class?: string;
|
||||
/** `Dialog` 的自定义样式 */
|
||||
style?: CSSProperties;
|
||||
/** `Dialog` 打开的延时时间,单位毫秒,默认 `0` */
|
||||
openDelay?: number;
|
||||
/** `Dialog` 关闭的延时时间,单位毫秒,默认 `0` */
|
||||
closeDelay?: number;
|
||||
/** 是否可以通过点击 `modal` 关闭 `Dialog`,默认 `true` */
|
||||
closeOnClickModal?: boolean;
|
||||
/** 是否可以通过按下 `ESC` 关闭 `Dialog`,默认 `true` */
|
||||
closeOnPressEscape?: boolean;
|
||||
/** 是否显示关闭按钮,默认 `true` */
|
||||
showClose?: boolean;
|
||||
/** 关闭前的回调,会暂停 `Dialog` 的关闭. 回调函数内执行 `done` 参数方法的时候才是真正关闭对话框的时候 */
|
||||
beforeClose?: (done: DoneFn) => void;
|
||||
/** 为 `Dialog` 启用可拖拽功能,默认 `false` */
|
||||
draggable?: boolean;
|
||||
/** 是否让 `Dialog` 的 `header` 和 `footer` 部分居中排列,默认 `false` */
|
||||
center?: boolean;
|
||||
/** 是否水平垂直对齐对话框,默认 `false` */
|
||||
alignCenter?: boolean;
|
||||
/** 当关闭 `Dialog` 时,销毁其中的元素,默认 `false` */
|
||||
destroyOnClose?: boolean;
|
||||
};
|
||||
|
||||
type BtnClickDialog = {
|
||||
options?: DialogOptions;
|
||||
index?: number;
|
||||
};
|
||||
type BtnClickButton = {
|
||||
btn?: ButtonProps;
|
||||
index?: number;
|
||||
};
|
||||
/** https://element-plus.org/zh-CN/component/button.html#button-attributes */
|
||||
type ButtonProps = {
|
||||
/** 按钮文字 */
|
||||
label: string;
|
||||
/** 按钮尺寸 */
|
||||
size?: "large" | "default" | "small";
|
||||
/** 按钮类型 */
|
||||
type?: "primary" | "success" | "warning" | "danger" | "info";
|
||||
/** 是否为朴素按钮,默认 `false` */
|
||||
plain?: boolean;
|
||||
/** 是否为文字按钮,默认 `false` */
|
||||
text?: boolean;
|
||||
/** 是否显示文字按钮背景颜色,默认 `false` */
|
||||
bg?: boolean;
|
||||
/** 是否为链接按钮,默认 `false` */
|
||||
link?: boolean;
|
||||
/** 是否为圆角按钮,默认 `false` */
|
||||
round?: boolean;
|
||||
/** 是否为圆形按钮,默认 `false` */
|
||||
circle?: boolean;
|
||||
/** 是否为加载中状态,默认 `false` */
|
||||
loading?: boolean;
|
||||
/** 自定义加载中状态图标组件 */
|
||||
loadingIcon?: string | Component;
|
||||
/** 按钮是否为禁用状态,默认 `false` */
|
||||
disabled?: boolean;
|
||||
/** 图标组件 */
|
||||
icon?: string | Component;
|
||||
/** 是否开启原生 `autofocus` 属性,默认 `false` */
|
||||
autofocus?: boolean;
|
||||
/** 原生 `type` 属性,默认 `button` */
|
||||
nativeType?: "button" | "submit" | "reset";
|
||||
/** 自动在两个中文字符之间插入空格 */
|
||||
autoInsertSpace?: boolean;
|
||||
/** 自定义按钮颜色, 并自动计算 `hover` 和 `active` 触发后的颜色 */
|
||||
color?: string;
|
||||
/** `dark` 模式, 意味着自动设置 `color` 为 `dark` 模式的颜色,默认 `false` */
|
||||
dark?: boolean;
|
||||
/** 自定义元素标签 */
|
||||
tag?: string | Component;
|
||||
/** 点击按钮后触发的回调 */
|
||||
btnClick?: ({
|
||||
dialog,
|
||||
button
|
||||
}: {
|
||||
/** 当前 `Dialog` 信息 */
|
||||
dialog: BtnClickDialog;
|
||||
/** 当前 `button` 信息 */
|
||||
button: BtnClickButton;
|
||||
}) => void;
|
||||
};
|
||||
|
||||
interface DialogOptions extends DialogProps {
|
||||
/** 内容区组件的 `props`,可通过 `defineProps` 接收 */
|
||||
props?: any;
|
||||
/** 是否隐藏 `Dialog` 按钮操作区的内容 */
|
||||
hideFooter?: boolean;
|
||||
/**
|
||||
* @description 自定义对话框标题的内容渲染器
|
||||
* @see {@link https://element-plus.org/zh-CN/component/dialog.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E5%A4%B4%E9%83%A8}
|
||||
*/
|
||||
headerRenderer?: ({
|
||||
close,
|
||||
titleId,
|
||||
titleClass
|
||||
}: {
|
||||
close: Function;
|
||||
titleId: string;
|
||||
titleClass: string;
|
||||
}) => VNode;
|
||||
/** 自定义内容渲染器 */
|
||||
contentRenderer?: ({
|
||||
options,
|
||||
index
|
||||
}: {
|
||||
options: DialogOptions;
|
||||
index: number;
|
||||
}) => VNode;
|
||||
/** 自定义按钮操作区的内容渲染器,会覆盖`footerButtons`以及默认的 `取消` 和 `确定` 按钮 */
|
||||
footerRenderer?: ({
|
||||
options,
|
||||
index
|
||||
}: {
|
||||
options: DialogOptions;
|
||||
index: number;
|
||||
}) => VNode;
|
||||
/** 自定义底部按钮操作 */
|
||||
footerButtons?: Array<ButtonProps>;
|
||||
/** `Dialog` 打开后的回调 */
|
||||
open?: ({
|
||||
options,
|
||||
index
|
||||
}: {
|
||||
options: DialogOptions;
|
||||
index: number;
|
||||
}) => void;
|
||||
/** `Dialog` 关闭后的回调(只有点击右上角关闭按钮或者空白页关闭页面时才会触发) */
|
||||
close?: ({
|
||||
options,
|
||||
index
|
||||
}: {
|
||||
options: DialogOptions;
|
||||
index: number;
|
||||
}) => void;
|
||||
/** `Dialog` 关闭后的回调。 `args` 返回的 `command` 值解析:`cancel` 点击取消按钮、`sure` 点击确定按钮、`close` 点击右上角关闭按钮或者空白页 */
|
||||
closeCallBack?: ({
|
||||
options,
|
||||
index,
|
||||
args
|
||||
}: {
|
||||
options: DialogOptions;
|
||||
index: number;
|
||||
args: any;
|
||||
}) => void;
|
||||
/** 输入焦点聚焦在 `Dialog` 内容时的回调 */
|
||||
openAutoFocus?: ({
|
||||
options,
|
||||
index
|
||||
}: {
|
||||
options: DialogOptions;
|
||||
index: number;
|
||||
}) => void;
|
||||
/** 输入焦点从 `Dialog` 内容失焦时的回调 */
|
||||
closeAutoFocus?: ({
|
||||
options,
|
||||
index
|
||||
}: {
|
||||
options: DialogOptions;
|
||||
index: number;
|
||||
}) => void;
|
||||
}
|
||||
|
||||
export type { EventType, ArgsType, DialogProps, ButtonProps, DialogOptions };
|
@ -123,9 +123,9 @@ onUnmounted(() => {
|
||||
|
||||
.flip-clock em {
|
||||
display: inline-block;
|
||||
line-height: 102px;
|
||||
font-size: 66px;
|
||||
font-style: normal;
|
||||
line-height: 102px;
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
|
@ -132,10 +132,10 @@ onMounted(() => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@import "./assets/iconfont/iconfont.css";
|
||||
@import url("./assets/iconfont/iconfont.css");
|
||||
|
||||
.control-container {
|
||||
background: hsla(0, 0%, 100%, 0.8);
|
||||
background: hsl(0deg 0% 100% / 80%);
|
||||
box-shadow: 0 1px 4px rgb(0 0 0 / 20%);
|
||||
}
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
@ -200,8 +200,8 @@ watch(
|
||||
|
||||
.icon-item {
|
||||
&:hover {
|
||||
border-color: var(--el-color-primary);
|
||||
color: var(--el-color-primary);
|
||||
border-color: var(--el-color-primary);
|
||||
transition: all 0.4s;
|
||||
transform: scaleX(1.05);
|
||||
}
|
||||
@ -224,15 +224,15 @@ watch(
|
||||
}
|
||||
|
||||
:deep(.el-tabs__item) {
|
||||
height: 30px;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__header),
|
||||
:deep(.el-tabs__nav-wrap) {
|
||||
margin: 0;
|
||||
position: static;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,6 +1,7 @@
|
||||
.qrcode {
|
||||
&--disabled {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
background: rgb(255 255 255 / 95%);
|
||||
|
||||
& > div {
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
@ -8,42 +8,48 @@ $--element-tree-line-width: 1px !default;
|
||||
}
|
||||
|
||||
.element-tree-node-label-wrapper {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.element-tree-node-label {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.element-tree-node-line-ver {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: block;
|
||||
height: 100%;
|
||||
border-left: $--element-tree-line-width $--element-tree-line-style
|
||||
$--element-tree-line-color;
|
||||
|
||||
&.last-node-line {
|
||||
border-left: $--element-tree-line-width $--element-tree-line-style
|
||||
transparent;
|
||||
}
|
||||
|
||||
&.last-node-isLeaf-line {
|
||||
height: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.element-tree-node-line-hor {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
display: block;
|
||||
height: 0;
|
||||
border-bottom: $--element-tree-line-width $--element-tree-line-style
|
||||
$--element-tree-line-color;
|
||||
}
|
||||
|
||||
.element-tree-node-label-line {
|
||||
flex: 1;
|
||||
border-top: $--element-tree-line-width $--element-tree-line-style
|
||||
$--element-tree-line-color;
|
||||
align-self: center;
|
||||
margin: 0 10px;
|
||||
border-top: $--element-tree-line-width $--element-tree-line-style
|
||||
$--element-tree-line-color;
|
||||
}
|
||||
|
@ -49,4 +49,7 @@ export const getServerConfig = async (app: App): Promise<undefined> => {
|
||||
});
|
||||
};
|
||||
|
||||
export { getConfig, setConfig };
|
||||
/** 本地响应式存储的命名空间 */
|
||||
const responsiveStorageNameSpace = () => getConfig().ResponsiveStorageNameSpace;
|
||||
|
||||
export { getConfig, setConfig, responsiveStorageNameSpace };
|
||||
|
@ -130,16 +130,16 @@ const transitionMain = defineComponent({
|
||||
|
||||
<style scoped>
|
||||
.app-main {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
position: relative;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.app-main-nofixed-header {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
|
@ -121,28 +121,28 @@ const { t, locale, translationCh, translationEn } = useTranslationLang();
|
||||
overflow: hidden;
|
||||
|
||||
.hamburger-container {
|
||||
line-height: 48px;
|
||||
height: 100%;
|
||||
float: left;
|
||||
height: 100%;
|
||||
line-height: 48px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vertical-header-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
min-width: 280px;
|
||||
height: 48px;
|
||||
align-items: center;
|
||||
color: #000000d9;
|
||||
justify-content: flex-end;
|
||||
|
||||
.el-dropdown-link {
|
||||
height: 48px;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
cursor: pointer;
|
||||
height: 48px;
|
||||
padding: 10px;
|
||||
color: #000000d9;
|
||||
cursor: pointer;
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
@ -182,9 +182,9 @@ const { t, locale, translationCh, translationEn } = useTranslationLang();
|
||||
max-width: 120px;
|
||||
|
||||
::v-deep(.el-dropdown-menu__item) {
|
||||
min-width: 100%;
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
min-width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -46,8 +46,8 @@ notices.value.map(v => (noticesNum.value += v.list.length));
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 48px;
|
||||
width: 60px;
|
||||
height: 48px;
|
||||
cursor: pointer;
|
||||
|
||||
.header-notice-icon {
|
||||
@ -59,7 +59,7 @@ notices.value.map(v => (noticesNum.value += v.list.length));
|
||||
width: 330px;
|
||||
|
||||
.noticeList-container {
|
||||
padding: 15px 24px 0 24px;
|
||||
padding: 15px 24px 0;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__header) {
|
||||
@ -71,7 +71,7 @@ notices.value.map(v => (noticesNum.value += v.list.length));
|
||||
}
|
||||
|
||||
:deep(.el-tabs__nav-wrap) {
|
||||
padding: 0 36px 0 36px;
|
||||
padding: 0 36px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -118,6 +118,7 @@ function hoverDescription(event, description) {
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
padding: 12px 0;
|
||||
|
||||
// border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
.notice-container-avatar {
|
||||
@ -127,15 +128,15 @@ function hoverDescription(event, description) {
|
||||
|
||||
.notice-container-text {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
flex: 1;
|
||||
|
||||
.notice-text-title {
|
||||
display: flex;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 1.5715;
|
||||
cursor: pointer;
|
||||
|
||||
@ -143,8 +144,8 @@ function hoverDescription(event, description) {
|
||||
flex: 1;
|
||||
width: 200px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.notice-title-extra {
|
||||
@ -162,8 +163,8 @@ function hoverDescription(event, description) {
|
||||
|
||||
.notice-text-description {
|
||||
display: -webkit-box;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
@ -60,9 +60,9 @@ emitter.on("openPanel", () => {
|
||||
|
||||
<style>
|
||||
.showright-panel {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
width: calc(100% - 15px);
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -71,23 +71,23 @@ emitter.on("openPanel", () => {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: -1;
|
||||
background: rgb(0 0 0 / 20%);
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s cubic-bezier(0.7, 0.3, 0.1, 1);
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.right-panel {
|
||||
width: 100%;
|
||||
max-width: 315px;
|
||||
height: 100vh;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.05);
|
||||
z-index: 40000;
|
||||
width: 100%;
|
||||
max-width: 315px;
|
||||
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);
|
||||
transform: translate(100%);
|
||||
z-index: 40000;
|
||||
}
|
||||
|
||||
.show {
|
||||
@ -95,9 +95,9 @@ emitter.on("openPanel", () => {
|
||||
|
||||
.right-panel-background {
|
||||
z-index: 20000;
|
||||
opacity: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.right-panel {
|
||||
@ -106,20 +106,20 @@ emitter.on("openPanel", () => {
|
||||
}
|
||||
|
||||
.handle-button {
|
||||
position: absolute;
|
||||
top: 45%;
|
||||
left: -48px;
|
||||
z-index: 0;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
position: absolute;
|
||||
left: -48px;
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
border-radius: 6px 0 0 6px !important;
|
||||
z-index: 0;
|
||||
line-height: 48px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
pointer-events: auto;
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
line-height: 48px;
|
||||
top: 45%;
|
||||
background: rgb(24, 144, 255);
|
||||
background: rgb(24 144 255);
|
||||
border-radius: 6px 0 0 6px !important;
|
||||
|
||||
i {
|
||||
font-size: 24px;
|
||||
@ -128,24 +128,24 @@ emitter.on("openPanel", () => {
|
||||
}
|
||||
|
||||
.right-panel-items {
|
||||
margin-top: 60px;
|
||||
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;
|
||||
position: fixed;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
top: 15px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
:deep(.el-divider--horizontal) {
|
||||
width: 90%;
|
||||
margin: 20px auto 0 auto;
|
||||
margin: 20px auto 0;
|
||||
}
|
||||
</style>
|
||||
|
@ -84,11 +84,11 @@ function handleTo() {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 56px;
|
||||
margin-top: 8px;
|
||||
padding: 14px;
|
||||
border-radius: 4px;
|
||||
margin-top: 8px;
|
||||
cursor: pointer;
|
||||
border: 0.1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
transition: all 0.3s;
|
||||
|
||||
&-title {
|
||||
|
@ -418,35 +418,35 @@ onBeforeMount(() => {
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 25px;
|
||||
}
|
||||
}
|
||||
|
||||
.pure-datatheme {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
text-align: center;
|
||||
display: block;
|
||||
padding-top: 25px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pure-theme {
|
||||
margin-top: 25px;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-around;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
margin-top: 25px;
|
||||
|
||||
li {
|
||||
position: relative;
|
||||
width: 18%;
|
||||
height: 45px;
|
||||
background: #f0f2f5;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
background: #f0f2f5;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 2.5px 0 rgb(0 0 0 / 18%);
|
||||
|
||||
@ -459,13 +459,13 @@ onBeforeMount(() => {
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
width: 70%;
|
||||
height: 30%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 70%;
|
||||
height: 30%;
|
||||
background: #fff;
|
||||
box-shadow: 0 0 1px #888;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -491,13 +491,13 @@ onBeforeMount(() => {
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
width: 30%;
|
||||
height: 70%;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 30%;
|
||||
height: 70%;
|
||||
background: #fff;
|
||||
box-shadow: 0 0 1px #888;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -505,11 +505,11 @@ onBeforeMount(() => {
|
||||
}
|
||||
|
||||
.theme-color {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
li {
|
||||
float: left;
|
||||
@ -519,8 +519,8 @@ onBeforeMount(() => {
|
||||
margin-right: 8px;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
border-radius: 2px;
|
||||
|
||||
&:nth-child(2) {
|
||||
border: 1px solid #ddd;
|
||||
|
@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { isEqual } from "@pureadmin/utils";
|
||||
import { routerArrays } from "@/layout/types";
|
||||
import { transformI18n } from "@/plugins/i18n";
|
||||
import { ref, watch, onMounted, toRaw } from "vue";
|
||||
import { getParentPaths, findRouteByPath } from "@/router/utils";
|
||||
@ -10,14 +11,9 @@ const route = useRoute();
|
||||
const levelList = ref([]);
|
||||
const router = useRouter();
|
||||
const routes: any = router.options.routes;
|
||||
const { VITE_HIDE_HOME } = import.meta.env;
|
||||
const multiTags: any = useMultiTagsStoreHook().multiTags;
|
||||
|
||||
const isDashboard = (route: RouteLocationMatched): boolean | string => {
|
||||
const name = route && (route.name as string);
|
||||
if (!name) return false;
|
||||
return name.trim().toLocaleLowerCase() === "Welcome".toLocaleLowerCase();
|
||||
};
|
||||
|
||||
const getBreadcrumb = (): void => {
|
||||
// 当前路由信息
|
||||
let currentRoute;
|
||||
@ -35,12 +31,17 @@ const getBreadcrumb = (): void => {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
currentRoute = findRouteByPath(router.currentRoute.value.path, multiTags);
|
||||
currentRoute = findRouteByPath(router.currentRoute.value.path, routes);
|
||||
}
|
||||
// 当前路由的父级路径组成的数组
|
||||
const parentRoutes = getParentPaths(router.currentRoute.value.path, routes);
|
||||
const parentRoutes = getParentPaths(
|
||||
router.currentRoute.value.name as string,
|
||||
routes,
|
||||
"name"
|
||||
);
|
||||
// 存放组成面包屑的数组
|
||||
let matched = [];
|
||||
|
||||
// 获取每个父级路径对应的路由信息
|
||||
parentRoutes.forEach(path => {
|
||||
if (path !== "/") matched.push(findRouteByPath(path, routes));
|
||||
@ -48,15 +49,7 @@ const getBreadcrumb = (): void => {
|
||||
|
||||
if (currentRoute?.path !== "/welcome") matched.push(currentRoute);
|
||||
|
||||
if (!isDashboard(matched[0])) {
|
||||
matched = [
|
||||
{
|
||||
path: "/welcome",
|
||||
parentPath: "/",
|
||||
meta: { title: "menus.hshome" }
|
||||
} as unknown as RouteLocationMatched
|
||||
].concat(matched);
|
||||
}
|
||||
if (VITE_HIDE_HOME === "false") matched = routerArrays.concat(matched);
|
||||
|
||||
matched.forEach((item, index) => {
|
||||
if (currentRoute?.query || currentRoute?.params) return;
|
||||
|
@ -19,7 +19,7 @@ const {
|
||||
title,
|
||||
routers,
|
||||
logout,
|
||||
backHome,
|
||||
backTopMenu,
|
||||
onPanel,
|
||||
menuSelect,
|
||||
username,
|
||||
@ -45,7 +45,7 @@ watch(
|
||||
v-loading="usePermissionStoreHook().wholeMenus.length === 0"
|
||||
class="horizontal-header"
|
||||
>
|
||||
<div class="horizontal-header-left" @click="backHome">
|
||||
<div class="horizontal-header-left" @click="backTopMenu">
|
||||
<img src="/logo.svg" alt="logo" />
|
||||
<span>{{ title }}</span>
|
||||
</div>
|
||||
@ -156,9 +156,9 @@ watch(
|
||||
max-width: 120px;
|
||||
|
||||
::v-deep(.el-dropdown-menu__item) {
|
||||
min-width: 100%;
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
min-width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,4 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { getTopMenu } from "@/router/utils";
|
||||
import { useNav } from "@/layout/hooks/useNav";
|
||||
|
||||
const props = defineProps({
|
||||
@ -6,6 +7,7 @@ const props = defineProps({
|
||||
});
|
||||
|
||||
const { title } = useNav();
|
||||
const topPath = getTopMenu().path;
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -16,7 +18,7 @@ const { title } = useNav();
|
||||
key="props.collapse"
|
||||
:title="title"
|
||||
class="sidebar-logo-link"
|
||||
to="/"
|
||||
:to="topPath"
|
||||
>
|
||||
<img src="/logo.svg" alt="logo" />
|
||||
<span class="sidebar-title">{{ title }}</span>
|
||||
@ -26,7 +28,7 @@ const { title } = useNav();
|
||||
key="expand"
|
||||
:title="title"
|
||||
class="sidebar-logo-link"
|
||||
to="/"
|
||||
:to="topPath"
|
||||
>
|
||||
<img src="/logo.svg" alt="logo" />
|
||||
<span class="sidebar-title">{{ title }}</span>
|
||||
@ -37,33 +39,33 @@ const { title } = useNav();
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.sidebar-logo-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
.sidebar-logo-link {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
|
||||
img {
|
||||
height: 32px;
|
||||
display: inline-block;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.sidebar-title {
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
margin: 2px 0 0 12px;
|
||||
color: $subMenuActiveText;
|
||||
display: inline-block;
|
||||
height: 32px;
|
||||
margin: 2px 0 0 12px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
line-height: 32px;
|
||||
color: $subMenuActiveText;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -188,9 +188,9 @@ watch(
|
||||
max-width: 120px;
|
||||
|
||||
::v-deep(.el-dropdown-menu__item) {
|
||||
min-width: 100%;
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
min-width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,8 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import path from "path";
|
||||
import { getConfig } from "@/config";
|
||||
import { menuType } from "../../types";
|
||||
import extraIcon from "./extraIcon.vue";
|
||||
import { childrenType } from "../../types";
|
||||
import { useNav } from "@/layout/hooks/useNav";
|
||||
import { transformI18n } from "@/plugins/i18n";
|
||||
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
|
||||
@ -17,7 +17,7 @@ const { layout, isCollapse, tooltipEffect, getDivStyle } = useNav();
|
||||
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: Object as PropType<childrenType>
|
||||
type: Object as PropType<menuType>
|
||||
},
|
||||
isNest: {
|
||||
type: Boolean,
|
||||
@ -112,7 +112,7 @@ const expandCloseIcon = computed(() => {
|
||||
};
|
||||
});
|
||||
|
||||
const onlyOneChild: childrenType = ref(null);
|
||||
const onlyOneChild: menuType = ref(null);
|
||||
// 存放菜单是否存在showTooltip属性标识
|
||||
const hoverMenuMap = new WeakMap();
|
||||
// 存储菜单文本dom元素
|
||||
@ -149,10 +149,7 @@ function overflowSlice(text, item?: any) {
|
||||
return newText;
|
||||
}
|
||||
|
||||
function hasOneShowingChild(
|
||||
children: childrenType[] = [],
|
||||
parent: childrenType
|
||||
) {
|
||||
function hasOneShowingChild(children: menuType[] = [], parent: menuType) {
|
||||
const showingChildren = children.filter((item: any) => {
|
||||
onlyOneChild.value = item;
|
||||
return true;
|
||||
|
@ -6,14 +6,16 @@ import SidebarItem from "./sidebarItem.vue";
|
||||
import leftCollapse from "./leftCollapse.vue";
|
||||
import { useNav } from "@/layout/hooks/useNav";
|
||||
import { storageLocal } from "@pureadmin/utils";
|
||||
import { responsiveStorageNameSpace } from "@/config";
|
||||
import { ref, computed, watch, onBeforeMount } from "vue";
|
||||
import { findRouteByPath, getParentPaths } from "@/router/utils";
|
||||
import { usePermissionStoreHook } from "@/store/modules/permission";
|
||||
|
||||
const route = useRoute();
|
||||
const showLogo = ref(
|
||||
storageLocal().getItem<StorageConfigs>("responsive-configure")?.showLogo ??
|
||||
true
|
||||
storageLocal().getItem<StorageConfigs>(
|
||||
`${responsiveStorageNameSpace()}configure`
|
||||
)?.showLogo ?? true
|
||||
);
|
||||
|
||||
const { routers, device, pureApp, isCollapse, menuSelect, toggleSideBar } =
|
||||
@ -32,6 +34,7 @@ const loading = computed(() =>
|
||||
);
|
||||
|
||||
function getSubMenuData(path: string) {
|
||||
subMenuData.value = [];
|
||||
// path的上级路由组成的数组
|
||||
const parentPathArr = getParentPaths(
|
||||
path,
|
||||
|
@ -1,4 +1,4 @@
|
||||
@keyframes scheduleInWidth {
|
||||
@keyframes schedule-in-width {
|
||||
from {
|
||||
width: 0;
|
||||
}
|
||||
@ -8,7 +8,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes scheduleOutWidth {
|
||||
@keyframes schedule-out-width {
|
||||
from {
|
||||
width: 100%;
|
||||
}
|
||||
@ -39,41 +39,41 @@
|
||||
}
|
||||
|
||||
.tags-view {
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
color: var(--el-text-color-primary);
|
||||
background: #fff;
|
||||
position: relative;
|
||||
box-shadow: 0 0 1px #888;
|
||||
|
||||
.scroll-item {
|
||||
border-radius: 3px 3px 0 0;
|
||||
padding: 0 6px;
|
||||
box-shadow: 0 0 1px #888;
|
||||
position: relative;
|
||||
margin-right: 4px;
|
||||
height: 28px;
|
||||
display: inline-block;
|
||||
height: 28px;
|
||||
padding: 0 6px;
|
||||
margin-right: 4px;
|
||||
line-height: 28px;
|
||||
transition: all 0.4s;
|
||||
cursor: pointer;
|
||||
border-radius: 3px 3px 0 0;
|
||||
box-shadow: 0 0 1px #888;
|
||||
transition: all 0.4s;
|
||||
|
||||
.el-icon-close {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
font-size: 10px;
|
||||
color: var(--el-color-primary);
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
transition: font-size 0.2s;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
&:hover {
|
||||
border-radius: 50%;
|
||||
font-size: 13px;
|
||||
color: #fff;
|
||||
background: #b4bccc;
|
||||
font-size: 13px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,24 +91,24 @@
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: var(--el-text-color-primary);
|
||||
padding: 0 4px;
|
||||
color: var(--el-text-color-primary);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.scroll-container {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
padding: 5px 0;
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
flex: 1;
|
||||
padding: 5px 0;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
||||
.tab {
|
||||
position: relative;
|
||||
float: left;
|
||||
list-style: none;
|
||||
overflow: visible;
|
||||
white-space: nowrap;
|
||||
list-style: none;
|
||||
transition: transform 0.5s ease-in-out;
|
||||
|
||||
.scroll-item {
|
||||
@ -123,29 +123,28 @@
|
||||
|
||||
/* 右键菜单 */
|
||||
.contextmenu {
|
||||
margin: 0;
|
||||
background: #fff;
|
||||
position: absolute;
|
||||
list-style-type: none;
|
||||
padding: 5px 0;
|
||||
border-radius: 4px;
|
||||
color: var(--el-text-color-primary);
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
color: var(--el-text-color-primary);
|
||||
white-space: nowrap;
|
||||
list-style-type: none;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
outline: 0;
|
||||
box-shadow: 0 2px 8px rgb(0 0 0 / 15%);
|
||||
|
||||
li {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 7px 12px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 7px 12px;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
// background: var(--el-color-primary-light-9);
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
@ -159,11 +158,11 @@
|
||||
|
||||
.el-dropdown-menu {
|
||||
li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
svg {
|
||||
display: block;
|
||||
@ -184,6 +183,7 @@
|
||||
:deep(.el-dropdown-menu__item--divided) {
|
||||
margin: 1px 0;
|
||||
}
|
||||
|
||||
.el-dropdown-menu__item--divided::before {
|
||||
margin: 0;
|
||||
}
|
||||
@ -193,7 +193,6 @@
|
||||
}
|
||||
|
||||
.scroll-item.is-active {
|
||||
// background-color: var(--el-color-primary-light-9);
|
||||
position: relative;
|
||||
color: #fff;
|
||||
|
||||
@ -213,16 +212,16 @@
|
||||
.arrow-left,
|
||||
.arrow-right,
|
||||
.arrow-down {
|
||||
position: relative;
|
||||
width: 40px;
|
||||
height: 38px;
|
||||
color: var(--el-text-color-primary);
|
||||
position: relative;
|
||||
|
||||
svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
transform: translate(-50%, 50%);
|
||||
}
|
||||
}
|
||||
@ -236,8 +235,8 @@
|
||||
}
|
||||
|
||||
.arrow-right {
|
||||
box-shadow: -5px 0 5px -6px #ccc;
|
||||
border-right: 0.5px solid #ccc;
|
||||
box-shadow: -5px 0 5px -6px #ccc;
|
||||
|
||||
&:hover {
|
||||
cursor: e-resize;
|
||||
@ -255,8 +254,8 @@
|
||||
|
||||
/* 卡片模式下鼠标移出隐藏蓝色边框 */
|
||||
.card-out {
|
||||
border: none;
|
||||
color: #666;
|
||||
border: none;
|
||||
|
||||
a {
|
||||
color: #666;
|
||||
@ -265,32 +264,32 @@
|
||||
|
||||
/* 灵动模式 */
|
||||
.schedule-active {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
background: var(--el-color-primary);
|
||||
}
|
||||
|
||||
/* 灵动模式下鼠标移入显示蓝色进度条 */
|
||||
.schedule-in {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
background: var(--el-color-primary);
|
||||
animation: scheduleInWidth 200ms ease-in;
|
||||
animation: schedule-in-width 200ms ease-in;
|
||||
}
|
||||
|
||||
/* 灵动模式下鼠标移出隐藏蓝色进度条 */
|
||||
.schedule-out {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 0;
|
||||
height: 2px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
background: var(--el-color-primary);
|
||||
animation: scheduleOutWidth 200ms ease-in;
|
||||
animation: schedule-out-width 200ms ease-in;
|
||||
}
|
||||
|
@ -5,10 +5,10 @@ import { RouteConfigs } from "../../types";
|
||||
import { useTags } from "../../hooks/useTag";
|
||||
import { routerArrays } from "@/layout/types";
|
||||
import { isEqual, isAllEmpty } from "@pureadmin/utils";
|
||||
import { handleAliveRoute, getTopMenu } from "@/router/utils";
|
||||
import { useSettingStoreHook } from "@/store/modules/settings";
|
||||
import { ref, watch, unref, nextTick, onBeforeMount } from "vue";
|
||||
import { handleAliveRoute, delAliveRoutes } from "@/router/utils";
|
||||
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
|
||||
import { ref, watch, unref, toRaw, nextTick, onBeforeMount } from "vue";
|
||||
import { useResizeObserver, useDebounceFn, useFullscreen } from "@vueuse/core";
|
||||
|
||||
import ExitFullscreen from "@iconify-icons/ri/fullscreen-exit-fill";
|
||||
@ -50,6 +50,8 @@ const tabDom = ref();
|
||||
const containerDom = ref();
|
||||
const scrollbarDom = ref();
|
||||
const isShowArrow = ref(false);
|
||||
const topPath = getTopMenu().path;
|
||||
const { VITE_HIDE_HOME } = import.meta.env;
|
||||
const { isFullscreen, toggle } = useFullscreen();
|
||||
|
||||
const dynamicTagView = () => {
|
||||
@ -165,13 +167,11 @@ function onFresh() {
|
||||
const { fullPath, query } = unref(route);
|
||||
router.replace({
|
||||
path: "/redirect" + fullPath,
|
||||
query: query
|
||||
query
|
||||
});
|
||||
}
|
||||
|
||||
function deleteDynamicTag(obj: any, current: any, tag?: string) {
|
||||
// 存放被删除的缓存路由
|
||||
let delAliveRouteList = [];
|
||||
const valueIndex: number = multiTags.value.findIndex((item: any) => {
|
||||
if (item.query) {
|
||||
if (item.path === obj.path) {
|
||||
@ -192,9 +192,12 @@ function deleteDynamicTag(obj: any, current: any, tag?: string) {
|
||||
other?: boolean
|
||||
): void => {
|
||||
if (other) {
|
||||
useMultiTagsStoreHook().handleTags("equal", [routerArrays[0], obj]);
|
||||
useMultiTagsStoreHook().handleTags("equal", [
|
||||
VITE_HIDE_HOME === "false" ? routerArrays[0] : toRaw(getTopMenu()),
|
||||
obj
|
||||
]);
|
||||
} else {
|
||||
delAliveRouteList = useMultiTagsStoreHook().handleTags("splice", "", {
|
||||
useMultiTagsStoreHook().handleTags("splice", "", {
|
||||
startIndex,
|
||||
length
|
||||
}) as any;
|
||||
@ -214,10 +217,6 @@ function deleteDynamicTag(obj: any, current: any, tag?: string) {
|
||||
}
|
||||
const newRoute = useMultiTagsStoreHook().handleTags("slice");
|
||||
if (current === route.path) {
|
||||
// 删除缓存路由
|
||||
tag
|
||||
? delAliveRoutes(delAliveRouteList)
|
||||
: handleAliveRoute(route.matched, "delete");
|
||||
// 如果删除当前激活tag就自动切换到最后一个tag
|
||||
if (tag === "left") return;
|
||||
if (newRoute[0]?.query) {
|
||||
@ -228,8 +227,6 @@ function deleteDynamicTag(obj: any, current: any, tag?: string) {
|
||||
router.push({ path: newRoute[0].path });
|
||||
}
|
||||
} else {
|
||||
// 删除缓存路由
|
||||
tag ? delAliveRoutes(delAliveRouteList) : delAliveRoutes([obj]);
|
||||
if (!multiTags.value.length) return;
|
||||
if (multiTags.value.some(item => item.path === route.path)) return;
|
||||
if (newRoute[0]?.query) {
|
||||
@ -244,6 +241,7 @@ function deleteDynamicTag(obj: any, current: any, tag?: string) {
|
||||
|
||||
function deleteMenu(item, tag?: string) {
|
||||
deleteDynamicTag(item, item.path, tag);
|
||||
handleAliveRoute(route as toRouteType);
|
||||
}
|
||||
|
||||
function onClickDrop(key, item, selectRoute?: RouteConfigs) {
|
||||
@ -290,7 +288,8 @@ function onClickDrop(key, item, selectRoute?: RouteConfigs) {
|
||||
startIndex: 1,
|
||||
length: multiTags.value.length
|
||||
});
|
||||
router.push("/welcome");
|
||||
router.push(topPath);
|
||||
handleAliveRoute(route as toRouteType);
|
||||
break;
|
||||
case 6:
|
||||
// 整体页面全屏
|
||||
@ -346,7 +345,7 @@ function disabledMenus(value: boolean) {
|
||||
});
|
||||
}
|
||||
|
||||
/** 检查当前右键的菜单两边是否存在别的菜单,如果左侧的菜单是首页,则不显示关闭左侧标签页,如果右侧没有菜单,则不显示关闭右侧标签页 */
|
||||
/** 检查当前右键的菜单两边是否存在别的菜单,如果左侧的菜单是顶级菜单,则不显示关闭左侧标签页,如果右侧没有菜单,则不显示关闭右侧标签页 */
|
||||
function showMenuModel(
|
||||
currentPath: string,
|
||||
query: object = {},
|
||||
@ -368,11 +367,11 @@ function showMenuModel(
|
||||
}
|
||||
|
||||
/**
|
||||
* currentIndex为1时,左侧的菜单是首页,则不显示关闭左侧标签页
|
||||
* currentIndex为1时,左侧的菜单顶级菜单,则不显示关闭左侧标签页
|
||||
* 如果currentIndex等于routeLength-1,右侧没有菜单,则不显示关闭右侧标签页
|
||||
*/
|
||||
if (currentIndex === 1 && routeLength !== 2) {
|
||||
// 左侧的菜单是首页,右侧存在别的菜单
|
||||
// 左侧的菜单是顶级菜单,右侧存在别的菜单
|
||||
tagsViews[2].show = false;
|
||||
Array.of(1, 3, 4, 5).forEach(v => {
|
||||
tagsViews[v].disabled = false;
|
||||
@ -380,7 +379,7 @@ function showMenuModel(
|
||||
tagsViews[2].disabled = true;
|
||||
} else if (currentIndex === 1 && routeLength === 2) {
|
||||
disabledMenus(false);
|
||||
// 左侧的菜单是首页,右侧不存在别的菜单
|
||||
// 左侧的菜单是顶级菜单,右侧不存在别的菜单
|
||||
Array.of(2, 3, 4).forEach(v => {
|
||||
tagsViews[v].show = false;
|
||||
tagsViews[v].disabled = true;
|
||||
@ -392,8 +391,8 @@ function showMenuModel(
|
||||
tagsViews[v].disabled = false;
|
||||
});
|
||||
tagsViews[3].disabled = true;
|
||||
} else if (currentIndex === 0 || currentPath === "/redirect/welcome") {
|
||||
// 当前路由为首页
|
||||
} else if (currentIndex === 0 || currentPath === `/redirect${topPath}`) {
|
||||
// 当前路由为顶级菜单
|
||||
disabledMenus(true);
|
||||
} else {
|
||||
disabledMenus(false);
|
||||
@ -402,8 +401,8 @@ function showMenuModel(
|
||||
|
||||
function openMenu(tag, e) {
|
||||
closeMenu();
|
||||
if (tag.path === "/welcome") {
|
||||
// 右键菜单为首页,只显示刷新
|
||||
if (tag.path === topPath) {
|
||||
// 右键菜单为顶级菜单,只显示刷新
|
||||
showMenus(false);
|
||||
tagsViews[0].show = true;
|
||||
} else if (route.path !== tag.path && route.name !== tag.name) {
|
||||
@ -609,5 +608,5 @@ onMounted(() => {
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "./index.scss";
|
||||
@import url("./index.scss");
|
||||
</style>
|
||||
|
@ -56,15 +56,15 @@ onMounted(() => {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.frame {
|
||||
height: calc(100vh - 88px);
|
||||
z-index: 998;
|
||||
height: calc(100vh - 88px);
|
||||
|
||||
.frame-iframe {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
border: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ import { getConfig } from "@/config";
|
||||
import { useRouter } from "vue-router";
|
||||
import { emitter } from "@/utils/mitt";
|
||||
import { routeMetaType } from "../types";
|
||||
import { getTopMenu } from "@/router/utils";
|
||||
import { useGlobal } from "@pureadmin/utils";
|
||||
import { transformI18n } from "@/plugins/i18n";
|
||||
import { router, remainingPaths } from "@/router";
|
||||
@ -85,8 +86,8 @@ export function useNav() {
|
||||
useUserStoreHook().logOut();
|
||||
}
|
||||
|
||||
function backHome() {
|
||||
router.push("/welcome");
|
||||
function backTopMenu() {
|
||||
router.push(getTopMenu().path);
|
||||
}
|
||||
|
||||
function onPanel() {
|
||||
@ -154,7 +155,7 @@ export function useNav() {
|
||||
logout,
|
||||
routers,
|
||||
$storage,
|
||||
backHome,
|
||||
backTopMenu,
|
||||
onPanel,
|
||||
getDivStyle,
|
||||
changeTitle,
|
||||
|
@ -12,6 +12,7 @@ import { tagsViewsType } from "../types";
|
||||
import { useEventListener } from "@vueuse/core";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { transformI18n, $t } from "@/plugins/i18n";
|
||||
import { responsiveStorageNameSpace } from "@/config";
|
||||
import { useSettingStoreHook } from "@/store/modules/settings";
|
||||
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
|
||||
import {
|
||||
@ -46,13 +47,16 @@ export function useTags() {
|
||||
|
||||
/** 显示模式,默认灵动模式 */
|
||||
const showModel = ref(
|
||||
storageLocal().getItem<StorageConfigs>("responsive-configure")?.showModel ||
|
||||
"smart"
|
||||
storageLocal().getItem<StorageConfigs>(
|
||||
`${responsiveStorageNameSpace()}configure`
|
||||
)?.showModel || "smart"
|
||||
);
|
||||
/** 是否隐藏标签页,默认显示 */
|
||||
const showTags =
|
||||
ref(
|
||||
storageLocal().getItem<StorageConfigs>("responsive-configure").hideTabs
|
||||
storageLocal().getItem<StorageConfigs>(
|
||||
`${responsiveStorageNameSpace()}configure`
|
||||
).hideTabs
|
||||
) ?? ref("false");
|
||||
const multiTags: any = computed(() => {
|
||||
return useMultiTagsStoreHook().multiTags;
|
||||
@ -201,10 +205,13 @@ export function useTags() {
|
||||
onMounted(() => {
|
||||
if (!showModel.value) {
|
||||
const configure = storageLocal().getItem<StorageConfigs>(
|
||||
"responsive-configure"
|
||||
`${responsiveStorageNameSpace()}configure`
|
||||
);
|
||||
configure.showModel = "card";
|
||||
storageLocal().setItem("responsive-configure", configure);
|
||||
storageLocal().setItem(
|
||||
`${responsiveStorageNameSpace()}configure`,
|
||||
configure
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -179,20 +179,16 @@ const layoutHeader = defineComponent({
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@mixin clearfix {
|
||||
.app-wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
content: "";
|
||||
}
|
||||
}
|
||||
|
||||
.app-wrapper {
|
||||
@include clearfix;
|
||||
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
&.mobile.openSidebar {
|
||||
position: fixed;
|
||||
@ -201,13 +197,13 @@ const layoutHeader = defineComponent({
|
||||
}
|
||||
|
||||
.app-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
z-index: 999;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #000;
|
||||
opacity: 0.3;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.re-screen {
|
||||
|
@ -1,15 +1,19 @@
|
||||
import type { IconifyIcon } from "@iconify/vue";
|
||||
const { VITE_HIDE_HOME } = import.meta.env;
|
||||
|
||||
export const routerArrays: Array<RouteConfigs> = [
|
||||
{
|
||||
path: "/welcome",
|
||||
parentPath: "/",
|
||||
meta: {
|
||||
title: "menus.hshome",
|
||||
icon: "homeFilled"
|
||||
}
|
||||
}
|
||||
];
|
||||
export const routerArrays: Array<RouteConfigs> =
|
||||
VITE_HIDE_HOME === "false"
|
||||
? [
|
||||
{
|
||||
path: "/welcome",
|
||||
parentPath: "/",
|
||||
meta: {
|
||||
title: "menus.hshome",
|
||||
icon: "homeFilled"
|
||||
}
|
||||
}
|
||||
]
|
||||
: [];
|
||||
|
||||
export type routeMetaType = {
|
||||
title?: string;
|
||||
@ -58,20 +62,23 @@ export interface setType {
|
||||
hideTabs: boolean;
|
||||
}
|
||||
|
||||
export type childrenType = {
|
||||
export type menuType = {
|
||||
id?: number;
|
||||
path?: string;
|
||||
noShowingChildren?: boolean;
|
||||
children?: childrenType[];
|
||||
children?: menuType[];
|
||||
value: unknown;
|
||||
meta?: {
|
||||
icon?: string;
|
||||
title?: string;
|
||||
rank?: number;
|
||||
showParent?: boolean;
|
||||
extraIcon?: string;
|
||||
};
|
||||
showTooltip?: boolean;
|
||||
parentId?: number;
|
||||
pathList?: number[];
|
||||
redirect?: string;
|
||||
};
|
||||
|
||||
export type themeColorsType = {
|
||||
|
@ -2,6 +2,7 @@
|
||||
import { App, WritableComputedRef } from "vue";
|
||||
import { storageLocal } from "@pureadmin/utils";
|
||||
import { type I18n, createI18n } from "vue-i18n";
|
||||
import { responsiveStorageNameSpace } from "@/config";
|
||||
|
||||
// element-plus国际化
|
||||
import enLocale from "element-plus/lib/locale/lang/en";
|
||||
@ -63,7 +64,9 @@ export const $t = (key: string) => key;
|
||||
export const i18n: I18n = createI18n({
|
||||
legacy: false,
|
||||
locale:
|
||||
storageLocal().getItem<StorageConfigs>("responsive-locale")?.locale ?? "zh",
|
||||
storageLocal().getItem<StorageConfigs>(
|
||||
`${responsiveStorageNameSpace()}locale`
|
||||
)?.locale ?? "zh",
|
||||
fallbackLocale: "en",
|
||||
messages: localesConfigs
|
||||
});
|
||||
|
@ -13,6 +13,7 @@ import {
|
||||
} from "vue-router";
|
||||
import {
|
||||
ascending,
|
||||
getTopMenu,
|
||||
initRouter,
|
||||
isOneOfArray,
|
||||
getHistoryMode,
|
||||
@ -96,13 +97,14 @@ export function resetRouter() {
|
||||
/** 路由白名单 */
|
||||
const whiteList = ["/login"];
|
||||
|
||||
const { VITE_HIDE_HOME } = import.meta.env;
|
||||
|
||||
router.beforeEach((to: toRouteType, _from, next) => {
|
||||
if (to.meta?.keepAlive) {
|
||||
const newMatched = to.matched;
|
||||
handleAliveRoute(newMatched, "add");
|
||||
handleAliveRoute(to, "add");
|
||||
// 页面整体刷新和点击标签页刷新
|
||||
if (_from.name === undefined || _from.name === "Redirect") {
|
||||
handleAliveRoute(newMatched);
|
||||
handleAliveRoute(to);
|
||||
}
|
||||
}
|
||||
const userInfo = storageSession().getItem<DataInfo<number>>(sessionKey);
|
||||
@ -126,6 +128,10 @@ router.beforeEach((to: toRouteType, _from, next) => {
|
||||
if (to.meta?.roles && !isOneOfArray(to.meta?.roles, userInfo?.roles)) {
|
||||
next({ path: "/error/403" });
|
||||
}
|
||||
// 开启隐藏首页后在浏览器地址栏手动输入首页welcome路由则跳转到404页面
|
||||
if (VITE_HIDE_HOME === "true" && to.fullPath === "/welcome") {
|
||||
next({ path: "/error/404" });
|
||||
}
|
||||
if (_from?.name) {
|
||||
// name为超链接
|
||||
if (externalLink) {
|
||||
@ -147,6 +153,7 @@ router.beforeEach((to: toRouteType, _from, next) => {
|
||||
path,
|
||||
router.options.routes[0].children
|
||||
);
|
||||
getTopMenu(true);
|
||||
// query、params模式路由传参数的标签页不在此处处理
|
||||
if (route && route.meta?.title) {
|
||||
useMultiTagsStoreHook().handleTags("push", {
|
||||
|
@ -11,11 +11,11 @@ export default {
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/components/message",
|
||||
name: "Message",
|
||||
component: () => import("@/views/components/message/index.vue"),
|
||||
path: "/components/dialog",
|
||||
name: "Dialog",
|
||||
component: () => import("@/views/components/dialog/index.vue"),
|
||||
meta: {
|
||||
title: $t("menus.hsmessage"),
|
||||
title: $t("menus.hsdialog"),
|
||||
extraIcon: "IF-pure-iconfont-new svg",
|
||||
transition: {
|
||||
enterTransition: "animate__fadeInLeft",
|
||||
@ -23,6 +23,14 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/components/message",
|
||||
name: "Message",
|
||||
component: () => import("@/views/components/message/index.vue"),
|
||||
meta: {
|
||||
title: $t("menus.hsmessage")
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/components/video",
|
||||
name: "Video",
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { $t } from "@/plugins/i18n";
|
||||
import { home } from "@/router/enums";
|
||||
const { VITE_HIDE_HOME } = import.meta.env;
|
||||
const Layout = () => import("@/layout/index.vue");
|
||||
|
||||
export default {
|
||||
@ -18,7 +19,8 @@ export default {
|
||||
name: "Welcome",
|
||||
component: () => import("@/views/welcome/index.vue"),
|
||||
meta: {
|
||||
title: $t("menus.hshome")
|
||||
title: $t("menus.hshome"),
|
||||
showLink: VITE_HIDE_HOME === "true" ? false : true
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -16,8 +16,7 @@ export default [
|
||||
path: "/redirect",
|
||||
component: Layout,
|
||||
meta: {
|
||||
icon: "homeFilled",
|
||||
title: $t("menus.hshome"),
|
||||
title: $t("status.hsLoad"),
|
||||
showLink: false,
|
||||
rank: 102
|
||||
},
|
||||
|
@ -3,13 +3,11 @@ import {
|
||||
RouteRecordRaw,
|
||||
RouteComponent,
|
||||
createWebHistory,
|
||||
createWebHashHistory,
|
||||
RouteRecordNormalized
|
||||
createWebHashHistory
|
||||
} from "vue-router";
|
||||
import { router } from "./index";
|
||||
import { isProxy, toRaw } from "vue";
|
||||
import { useTimeoutFn } from "@vueuse/core";
|
||||
import { RouteConfigs } from "@/layout/types";
|
||||
import {
|
||||
isString,
|
||||
cloneDeep,
|
||||
@ -19,8 +17,10 @@ import {
|
||||
isIncludeAllChildren
|
||||
} from "@pureadmin/utils";
|
||||
import { getConfig } from "@/config";
|
||||
import { menuType } from "@/layout/types";
|
||||
import { buildHierarchyTree } from "@/utils/tree";
|
||||
import { sessionKey, type DataInfo } from "@/utils/auth";
|
||||
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
|
||||
import { usePermissionStoreHook } from "@/store/modules/permission";
|
||||
const IFrame = () => import("@/layout/frameView.vue");
|
||||
// https://cn.vitejs.dev/guide/features.html#glob-import
|
||||
@ -94,30 +94,20 @@ function filterNoPermissionTree(data: RouteComponent[]) {
|
||||
return filterChildrenTree(newTree);
|
||||
}
|
||||
|
||||
/** 批量删除缓存路由(keepalive) */
|
||||
function delAliveRoutes(delAliveRouteList: Array<RouteConfigs>) {
|
||||
delAliveRouteList.forEach(route => {
|
||||
usePermissionStoreHook().cacheOperate({
|
||||
mode: "delete",
|
||||
name: route?.name
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 通过path获取父级路径 */
|
||||
function getParentPaths(path: string, routes: RouteRecordRaw[]) {
|
||||
/** 通过指定 `key` 获取父级路径集合,默认 `key` 为 `path` */
|
||||
function getParentPaths(value: string, routes: RouteRecordRaw[], key = "path") {
|
||||
// 深度遍历查找
|
||||
function dfs(routes: RouteRecordRaw[], path: string, parents: string[]) {
|
||||
function dfs(routes: RouteRecordRaw[], value: string, parents: string[]) {
|
||||
for (let i = 0; i < routes.length; i++) {
|
||||
const item = routes[i];
|
||||
// 找到path则返回父级path
|
||||
if (item.path === path) return parents;
|
||||
// 返回父级path
|
||||
if (item[key] === value) return parents;
|
||||
// children不存在或为空则不递归
|
||||
if (!item.children || !item.children.length) continue;
|
||||
// 往下查找时将当前path入栈
|
||||
parents.push(item.path);
|
||||
|
||||
if (dfs(item.children, path, parents).length) return parents;
|
||||
if (dfs(item.children, value, parents).length) return parents;
|
||||
// 深度遍历查找未找到时当前path 出栈
|
||||
parents.pop();
|
||||
}
|
||||
@ -125,10 +115,10 @@ function getParentPaths(path: string, routes: RouteRecordRaw[]) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return dfs(routes, path, []);
|
||||
return dfs(routes, value, []);
|
||||
}
|
||||
|
||||
/** 查找对应path的路由信息 */
|
||||
/** 查找对应 `path` 的路由信息 */
|
||||
function findRouteByPath(path: string, routes: RouteRecordRaw[]) {
|
||||
let res = routes.find((item: { path: string }) => item.path == path);
|
||||
if (res) {
|
||||
@ -266,27 +256,29 @@ function formatTwoStageRoutes(routesList: RouteRecordRaw[]) {
|
||||
}
|
||||
|
||||
/** 处理缓存路由(添加、删除、刷新) */
|
||||
function handleAliveRoute(matched: RouteRecordNormalized[], mode?: string) {
|
||||
function handleAliveRoute({ name }: toRouteType, mode?: string) {
|
||||
switch (mode) {
|
||||
case "add":
|
||||
matched.forEach(v => {
|
||||
usePermissionStoreHook().cacheOperate({ mode: "add", name: v.name });
|
||||
usePermissionStoreHook().cacheOperate({
|
||||
mode: "add",
|
||||
name
|
||||
});
|
||||
break;
|
||||
case "delete":
|
||||
usePermissionStoreHook().cacheOperate({
|
||||
mode: "delete",
|
||||
name: matched[matched.length - 1].name
|
||||
name
|
||||
});
|
||||
break;
|
||||
default:
|
||||
usePermissionStoreHook().cacheOperate({
|
||||
mode: "delete",
|
||||
name: matched[matched.length - 1].name
|
||||
name
|
||||
});
|
||||
useTimeoutFn(() => {
|
||||
matched.forEach(v => {
|
||||
usePermissionStoreHook().cacheOperate({ mode: "add", name: v.name });
|
||||
usePermissionStoreHook().cacheOperate({
|
||||
mode: "add",
|
||||
name
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
@ -361,17 +353,24 @@ function hasAuth(value: string | Array<string>): boolean {
|
||||
return isAuths ? true : false;
|
||||
}
|
||||
|
||||
/** 获取所有菜单中的第一个菜单(顶级菜单)*/
|
||||
function getTopMenu(tag = false): menuType {
|
||||
const topMenu = usePermissionStoreHook().wholeMenus[0]?.children[0];
|
||||
tag && useMultiTagsStoreHook().handleTags("push", topMenu);
|
||||
return topMenu;
|
||||
}
|
||||
|
||||
export {
|
||||
hasAuth,
|
||||
getAuths,
|
||||
ascending,
|
||||
filterTree,
|
||||
initRouter,
|
||||
getTopMenu,
|
||||
addPathMatch,
|
||||
isOneOfArray,
|
||||
getHistoryMode,
|
||||
addAsyncRoutes,
|
||||
delAliveRoutes,
|
||||
getParentPaths,
|
||||
findRouteByPath,
|
||||
handleAliveRoute,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { store } from "@/store";
|
||||
import { appType } from "./types";
|
||||
import { defineStore } from "pinia";
|
||||
import { getConfig } from "@/config";
|
||||
import { getConfig, responsiveStorageNameSpace } from "@/config";
|
||||
import { deviceDetection, storageLocal } from "@pureadmin/utils";
|
||||
|
||||
export const useAppStore = defineStore({
|
||||
@ -9,15 +9,17 @@ export const useAppStore = defineStore({
|
||||
state: (): appType => ({
|
||||
sidebar: {
|
||||
opened:
|
||||
storageLocal().getItem<StorageConfigs>("responsive-layout")
|
||||
?.sidebarStatus ?? getConfig().SidebarStatus,
|
||||
storageLocal().getItem<StorageConfigs>(
|
||||
`${responsiveStorageNameSpace()}layout`
|
||||
)?.sidebarStatus ?? getConfig().SidebarStatus,
|
||||
withoutAnimation: false,
|
||||
isClickCollapse: false
|
||||
},
|
||||
// 这里的layout用于监听容器拖拉后恢复对应的导航模式
|
||||
layout:
|
||||
storageLocal().getItem<StorageConfigs>("responsive-layout")?.layout ??
|
||||
getConfig().Layout,
|
||||
storageLocal().getItem<StorageConfigs>(
|
||||
`${responsiveStorageNameSpace()}layout`
|
||||
)?.layout ?? getConfig().Layout,
|
||||
device: deviceDetection() ? "mobile" : "desktop",
|
||||
// 作用于 src/views/components/draggable/index.vue 页面,当离开页面并不会销毁 new Swap(),sortablejs 官网也没有提供任何销毁的 api
|
||||
sortSwap: false
|
||||
@ -32,8 +34,9 @@ export const useAppStore = defineStore({
|
||||
},
|
||||
actions: {
|
||||
TOGGLE_SIDEBAR(opened?: boolean, resize?: string) {
|
||||
const layout =
|
||||
storageLocal().getItem<StorageConfigs>("responsive-layout");
|
||||
const layout = storageLocal().getItem<StorageConfigs>(
|
||||
`${responsiveStorageNameSpace()}layout`
|
||||
);
|
||||
if (opened && resize) {
|
||||
this.sidebar.withoutAnimation = true;
|
||||
this.sidebar.opened = true;
|
||||
@ -48,7 +51,7 @@ export const useAppStore = defineStore({
|
||||
this.sidebar.isClickCollapse = !this.sidebar.opened;
|
||||
layout.sidebarStatus = this.sidebar.opened;
|
||||
}
|
||||
storageLocal().setItem("responsive-layout", layout);
|
||||
storageLocal().setItem(`${responsiveStorageNameSpace()}layout`, layout);
|
||||
},
|
||||
async toggleSideBar(opened?: boolean, resize?: string) {
|
||||
await this.TOGGLE_SIDEBAR(opened, resize);
|
||||
|
@ -1,17 +1,19 @@
|
||||
import { store } from "@/store";
|
||||
import { defineStore } from "pinia";
|
||||
import { getConfig } from "@/config";
|
||||
import { storageLocal } from "@pureadmin/utils";
|
||||
import { getConfig, responsiveStorageNameSpace } from "@/config";
|
||||
|
||||
export const useEpThemeStore = defineStore({
|
||||
id: "pure-epTheme",
|
||||
state: () => ({
|
||||
epThemeColor:
|
||||
storageLocal().getItem<StorageConfigs>("responsive-layout")
|
||||
?.epThemeColor ?? getConfig().EpThemeColor,
|
||||
storageLocal().getItem<StorageConfigs>(
|
||||
`${responsiveStorageNameSpace()}layout`
|
||||
)?.epThemeColor ?? getConfig().EpThemeColor,
|
||||
epTheme:
|
||||
storageLocal().getItem<StorageConfigs>("responsive-layout")?.theme ??
|
||||
getConfig().Theme
|
||||
storageLocal().getItem<StorageConfigs>(
|
||||
`${responsiveStorageNameSpace()}layout`
|
||||
)?.theme ?? getConfig().Theme
|
||||
}),
|
||||
getters: {
|
||||
getEpThemeColor(state) {
|
||||
@ -30,13 +32,14 @@ export const useEpThemeStore = defineStore({
|
||||
},
|
||||
actions: {
|
||||
setEpThemeColor(newColor: string): void {
|
||||
const layout =
|
||||
storageLocal().getItem<StorageConfigs>("responsive-layout");
|
||||
const layout = storageLocal().getItem<StorageConfigs>(
|
||||
`${responsiveStorageNameSpace()}layout`
|
||||
);
|
||||
this.epTheme = layout?.theme;
|
||||
this.epThemeColor = newColor;
|
||||
if (!layout) return;
|
||||
layout.epThemeColor = newColor;
|
||||
storageLocal().setItem("responsive-layout", layout);
|
||||
storageLocal().setItem(`${responsiveStorageNameSpace()}layout`, layout);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -2,18 +2,22 @@ import { defineStore } from "pinia";
|
||||
import { store } from "@/store";
|
||||
import { routerArrays } from "@/layout/types";
|
||||
import { multiType, positionType } from "./types";
|
||||
import { responsiveStorageNameSpace } from "@/config";
|
||||
import { isEqual, isBoolean, isUrl, storageLocal } from "@pureadmin/utils";
|
||||
|
||||
export const useMultiTagsStore = defineStore({
|
||||
id: "pure-multiTags",
|
||||
state: () => ({
|
||||
// 存储标签页信息(路由信息)
|
||||
multiTags: storageLocal().getItem<StorageConfigs>("responsive-configure")
|
||||
?.multiTagsCache
|
||||
? storageLocal().getItem<StorageConfigs>("responsive-tags")
|
||||
multiTags: storageLocal().getItem<StorageConfigs>(
|
||||
`${responsiveStorageNameSpace()}configure`
|
||||
)?.multiTagsCache
|
||||
? storageLocal().getItem<StorageConfigs>(
|
||||
`${responsiveStorageNameSpace()}tags`
|
||||
)
|
||||
: [...routerArrays],
|
||||
multiTagsCache: storageLocal().getItem<StorageConfigs>(
|
||||
"responsive-configure"
|
||||
`${responsiveStorageNameSpace()}configure`
|
||||
)?.multiTagsCache
|
||||
}),
|
||||
getters: {
|
||||
@ -25,14 +29,20 @@ export const useMultiTagsStore = defineStore({
|
||||
multiTagsCacheChange(multiTagsCache: boolean) {
|
||||
this.multiTagsCache = multiTagsCache;
|
||||
if (multiTagsCache) {
|
||||
storageLocal().setItem("responsive-tags", this.multiTags);
|
||||
storageLocal().setItem(
|
||||
`${responsiveStorageNameSpace()}tags`,
|
||||
this.multiTags
|
||||
);
|
||||
} else {
|
||||
storageLocal().removeItem("responsive-tags");
|
||||
storageLocal().removeItem(`${responsiveStorageNameSpace()}tags`);
|
||||
}
|
||||
},
|
||||
tagsCache(multiTags) {
|
||||
this.getMultiTagsCache &&
|
||||
storageLocal().setItem("responsive-tags", multiTags);
|
||||
storageLocal().setItem(
|
||||
`${responsiveStorageNameSpace()}tags`,
|
||||
multiTags
|
||||
);
|
||||
},
|
||||
handleTags<T>(
|
||||
mode: string,
|
||||
|
@ -2,6 +2,8 @@ import { defineStore } from "pinia";
|
||||
import { store } from "@/store";
|
||||
import { cacheType } from "./types";
|
||||
import { constantMenus } from "@/router";
|
||||
import { getKeyList } from "@pureadmin/utils";
|
||||
import { useMultiTagsStoreHook } from "./multiTags";
|
||||
import { ascending, filterTree, filterNoPermissionTree } from "@/router/utils";
|
||||
|
||||
export const usePermissionStore = defineStore({
|
||||
@ -25,7 +27,6 @@ export const usePermissionStore = defineStore({
|
||||
switch (mode) {
|
||||
case "add":
|
||||
this.cachePageList.push(name);
|
||||
this.cachePageList = [...new Set(this.cachePageList)];
|
||||
break;
|
||||
case "delete":
|
||||
// eslint-disable-next-line no-case-declarations
|
||||
@ -33,6 +34,20 @@ export const usePermissionStore = defineStore({
|
||||
delIndex !== -1 && this.cachePageList.splice(delIndex, 1);
|
||||
break;
|
||||
}
|
||||
/** 监听缓存页面是否存在于标签页,不存在则删除 */
|
||||
(() => {
|
||||
let cacheLength = this.cachePageList.length;
|
||||
const nameList = getKeyList(useMultiTagsStoreHook().multiTags, "name");
|
||||
while (cacheLength > 0) {
|
||||
nameList.findIndex(v => v === this.cachePageList[cacheLength - 1]) ===
|
||||
-1 &&
|
||||
this.cachePageList.splice(
|
||||
this.cachePageList.indexOf(this.cachePageList[cacheLength - 1]),
|
||||
1
|
||||
);
|
||||
cacheLength--;
|
||||
}
|
||||
})();
|
||||
},
|
||||
/** 清空缓存页面 */
|
||||
clearAllCachePage() {
|
||||
|
@ -32,8 +32,8 @@ html.dark {
|
||||
.tags-view {
|
||||
.arrow-left,
|
||||
.arrow-right {
|
||||
box-shadow: none;
|
||||
border-right: 1px solid $border-style;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.arrow-right {
|
||||
@ -46,6 +46,7 @@ html.dark {
|
||||
.el-divider__text {
|
||||
--el-bg-color: var(--el-bg-color);
|
||||
}
|
||||
|
||||
.el-divider--horizontal {
|
||||
border-top: none;
|
||||
}
|
||||
@ -63,10 +64,10 @@ html.dark {
|
||||
}
|
||||
|
||||
.form-edit-widget-label a {
|
||||
color: $color-white;
|
||||
background: var(--el-color-primary);
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
color: $color-white;
|
||||
}
|
||||
|
||||
.el-aside {
|
||||
@ -84,14 +85,18 @@ html.dark {
|
||||
.el-table__cell {
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
|
||||
.el-card {
|
||||
--el-card-bg-color: var(--el-bg-color);
|
||||
|
||||
// border: none !important;
|
||||
}
|
||||
|
||||
.el-backtop {
|
||||
--el-backtop-bg-color: var(--el-color-primary-light-9);
|
||||
--el-backtop-hover-bg-color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
.el-dropdown-menu__item:not(.is-disabled):hover {
|
||||
background: transparent;
|
||||
}
|
||||
@ -103,18 +108,18 @@ html.dark {
|
||||
&.el-message-box__close,
|
||||
&.el-notification__closeBtn {
|
||||
&:hover {
|
||||
color: rgba(255, 255, 255, 0.85) !important;
|
||||
background-color: rgba(255, 255, 255, 0.12);
|
||||
color: rgb(255 255 255 / 85%) !important;
|
||||
background-color: rgb(255 255 255 / 12%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 克隆并自定义 ElMessage 样式,不会影响 ElMessage 原本样式,在 src/utils/message.ts 中调用自定义样式 ElMessage 方法即可,非暗黑模式在 src/style/element-plus.scss 文件进行了适配 */
|
||||
.pure-message {
|
||||
background-color: rgb(36 37 37) !important;
|
||||
background-image: initial !important;
|
||||
background-color: rgb(36, 37, 37) !important;
|
||||
box-shadow: rgb(13 13 13 / 12%) 0px 3px 6px -4px,
|
||||
rgb(13 13 13 / 8%) 0px 6px 16px 0px, rgb(13 13 13 / 5%) 0px 9px 28px 8px !important;
|
||||
box-shadow: rgb(13 13 13 / 12%) 0 3px 6px -4px,
|
||||
rgb(13 13 13 / 8%) 0 6px 16px 0, rgb(13 13 13 / 5%) 0 9px 28px 8px !important;
|
||||
|
||||
& .el-message__content {
|
||||
color: $color-white !important;
|
||||
@ -124,8 +129,8 @@ html.dark {
|
||||
|
||||
& .el-message__closeBtn {
|
||||
&:hover {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
background-color: rgba(255, 255, 255, 0.12);
|
||||
color: rgb(255 255 255 / 85%);
|
||||
background-color: rgb(255 255 255 / 12%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,6 +78,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-icon {
|
||||
&.el-dialog__close,
|
||||
&.el-drawer__close,
|
||||
@ -85,22 +86,23 @@
|
||||
&.el-notification__closeBtn {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
outline: none;
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
transition: background-color 0.2s, color 0.2s;
|
||||
|
||||
&:hover {
|
||||
color: rgba(0, 0, 0, 0.88) !important;
|
||||
background-color: rgba(0, 0, 0, 0.06);
|
||||
color: rgb(0 0 0 / 88%) !important;
|
||||
text-decoration: none;
|
||||
background-color: rgb(0 0 0 / 6%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 克隆并自定义 ElMessage 样式,不会影响 ElMessage 原本样式,在 src/utils/message.ts 中调用自定义样式 ElMessage 方法即可,暗黑模式在 src/style/dark.scss 文件进行了适配 */
|
||||
.pure-message {
|
||||
border-width: 0 !important;
|
||||
background: #fff !important;
|
||||
padding: 10px 13px !important;
|
||||
background: #fff !important;
|
||||
border-width: 0 !important;
|
||||
box-shadow: 0 3px 6px -4px #0000001f, 0 6px 16px #00000014,
|
||||
0 9px 28px 8px #0000000d !important;
|
||||
|
||||
@ -119,13 +121,13 @@
|
||||
}
|
||||
|
||||
& .el-message__closeBtn {
|
||||
outline: none;
|
||||
border-radius: 4px;
|
||||
right: 9px !important;
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
transition: background-color 0.2s, color 0.2s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.06);
|
||||
background-color: rgb(0 0 0 / 6%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
@import "./mixin.scss";
|
||||
@import "./transition.scss";
|
||||
@import "./element-plus.scss";
|
||||
@import "./sidebar.scss";
|
||||
@import "./dark.scss";
|
||||
@import "./transition";
|
||||
@import "./element-plus";
|
||||
@import "./sidebar";
|
||||
@import "./dark";
|
||||
|
||||
/* 自定义全局 CssVar */
|
||||
:root {
|
||||
|
@ -1,28 +0,0 @@
|
||||
@mixin clearfix {
|
||||
&::after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin relative {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@mixin scrollBar {
|
||||
&::-webkit-scrollbar-track-piece {
|
||||
background: #d3dce6;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #99a9bf;
|
||||
border-radius: 20px;
|
||||
}
|
||||
}
|
@ -2,9 +2,9 @@
|
||||
::before,
|
||||
::after {
|
||||
box-sizing: border-box;
|
||||
border-width: 0;
|
||||
border-style: solid;
|
||||
border-color: currentColor;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
#app {
|
||||
@ -13,25 +13,24 @@
|
||||
}
|
||||
|
||||
html {
|
||||
line-height: 1.5;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-moz-tab-size: 4;
|
||||
tab-size: 4;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
line-height: 1.5;
|
||||
tab-size: 4;
|
||||
text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
line-height: inherit;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB",
|
||||
"Microsoft YaHei", "微软雅黑", Arial, sans-serif;
|
||||
line-height: inherit;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizelegibility;
|
||||
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB",
|
||||
"Microsoft YaHei", "微软雅黑", Arial, sans-serif;
|
||||
}
|
||||
|
||||
hr {
|
||||
@ -69,9 +68,9 @@ small {
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
@ -85,8 +84,8 @@ sup {
|
||||
|
||||
table {
|
||||
text-indent: 0;
|
||||
border-color: inherit;
|
||||
border-collapse: collapse;
|
||||
border-color: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
@ -94,12 +93,12 @@ input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: 100%;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
button,
|
||||
@ -160,8 +159,8 @@ pre {
|
||||
}
|
||||
|
||||
fieldset {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
@ -171,9 +170,9 @@ legend {
|
||||
ol,
|
||||
ul,
|
||||
menu {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
@ -182,8 +181,8 @@ textarea {
|
||||
|
||||
input::placeholder,
|
||||
textarea::placeholder {
|
||||
opacity: 1;
|
||||
color: #9ca3af;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
button,
|
||||
@ -238,9 +237,9 @@ a:active {
|
||||
a,
|
||||
a:focus,
|
||||
a:hover {
|
||||
cursor: pointer;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div:focus {
|
||||
@ -249,11 +248,11 @@ div:focus {
|
||||
|
||||
.clearfix {
|
||||
&::after {
|
||||
visibility: hidden;
|
||||
display: block;
|
||||
font-size: 0;
|
||||
content: " ";
|
||||
clear: both;
|
||||
height: 0;
|
||||
clear: both;
|
||||
font-size: 0;
|
||||
visibility: hidden;
|
||||
content: " ";
|
||||
}
|
||||
}
|
||||
|
@ -2,20 +2,21 @@
|
||||
@mixin merge-style($sideBarWidth) {
|
||||
$menuActiveText: #7a80b4;
|
||||
|
||||
@media screen and (min-width: 150px) and (max-width: 420px) {
|
||||
@media screen and (width >= 150px) and (width <= 420px) {
|
||||
.app-main-nofixed-header {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 420px) {
|
||||
|
||||
@media screen and (width >= 420px) {
|
||||
.app-main-nofixed-header {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.sub-menu-icon {
|
||||
font-size: 18px;
|
||||
margin-right: 5px;
|
||||
font-size: 18px;
|
||||
|
||||
svg {
|
||||
width: 18px;
|
||||
@ -24,26 +25,27 @@
|
||||
}
|
||||
|
||||
.set-icon {
|
||||
height: 48px;
|
||||
width: 40px;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 48px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.main-container {
|
||||
position: relative;
|
||||
height: 100vh;
|
||||
min-height: 100%;
|
||||
/* main-content 属性动画 */
|
||||
transition: margin-left var(--pure-transition-duration);
|
||||
margin-left: $sideBarWidth;
|
||||
position: relative;
|
||||
background: #f0f2f5;
|
||||
|
||||
/* main-content 属性动画 */
|
||||
transition: margin-left var(--pure-transition-duration);
|
||||
|
||||
.el-scrollbar__wrap {
|
||||
overflow: auto;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,6 +55,7 @@
|
||||
right: 0;
|
||||
z-index: 998;
|
||||
width: calc(100% - 210px);
|
||||
|
||||
/* fixed-header 属性左上角动画 */
|
||||
transition: width var(--pure-transition-duration);
|
||||
}
|
||||
@ -70,20 +73,21 @@
|
||||
}
|
||||
|
||||
.sidebar-container {
|
||||
/* 展开动画 */
|
||||
transition: width var(--pure-transition-duration);
|
||||
width: $sideBarWidth !important;
|
||||
background: $menuBg;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
font-size: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1001;
|
||||
width: $sideBarWidth !important;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
font-size: 0;
|
||||
background: $menuBg;
|
||||
box-shadow: 0 0 1px #888;
|
||||
|
||||
/* 展开动画 */
|
||||
transition: width var(--pure-transition-duration);
|
||||
|
||||
.scrollbar-wrapper {
|
||||
overflow-x: hidden !important;
|
||||
}
|
||||
@ -101,6 +105,7 @@
|
||||
/* logo: 48px、leftCollapse: 40px、leftCollapse-shadow: 4px */
|
||||
height: calc(100% - 92px);
|
||||
}
|
||||
|
||||
.el-scrollbar.mobile {
|
||||
height: 100%;
|
||||
}
|
||||
@ -113,15 +118,15 @@
|
||||
a {
|
||||
display: inline-block;
|
||||
display: flex;
|
||||
padding-left: 10px;
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.el-menu {
|
||||
border: none;
|
||||
height: 100%;
|
||||
background-color: transparent !important;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.el-menu-item,
|
||||
@ -158,8 +163,8 @@
|
||||
}
|
||||
|
||||
.is-active {
|
||||
transition: color 0.3s;
|
||||
color: $subMenuActiveText !important;
|
||||
transition: color 0.3s;
|
||||
}
|
||||
|
||||
.el-menu-item.is-active.nest-menu > * {
|
||||
@ -168,22 +173,19 @@
|
||||
}
|
||||
|
||||
.el-menu-item.is-active.nest-menu::before {
|
||||
content: "";
|
||||
clear: both;
|
||||
position: absolute;
|
||||
left: 8px;
|
||||
right: 8px;
|
||||
inset: 0 8px;
|
||||
margin: 4px 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
border-radius: 3px;
|
||||
clear: both;
|
||||
content: "";
|
||||
background: var(--el-color-primary) !important;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.el-menu .el-menu--inline .el-sub-menu__title,
|
||||
& .el-sub-menu .el-menu-item {
|
||||
font-size: 12px;
|
||||
min-width: $sideBarWidth !important;
|
||||
font-size: 12px;
|
||||
background-color: $subMenuBg !important;
|
||||
}
|
||||
|
||||
@ -196,21 +198,21 @@
|
||||
left: 0;
|
||||
width: 2px;
|
||||
height: 100%;
|
||||
background-color: $menuActiveBefore;
|
||||
content: "";
|
||||
clear: both;
|
||||
content: "";
|
||||
background-color: $menuActiveBefore;
|
||||
transition: all var(--pure-transition-duration) ease-in-out;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.el-menu--collapse .outer-most.el-sub-menu > .el-sub-menu__title::before {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
height: 0;
|
||||
width: 3px;
|
||||
transform: translateY(-50%);
|
||||
top: 50%;
|
||||
display: block;
|
||||
width: 3px;
|
||||
height: 0;
|
||||
content: "";
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
/* 无子集的激活菜单背景 */
|
||||
@ -219,17 +221,15 @@
|
||||
color: #fff;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.is-active.submenu-title-noDropdown.outer-most::before {
|
||||
content: "";
|
||||
clear: both;
|
||||
position: absolute;
|
||||
left: 8px;
|
||||
right: 8px;
|
||||
inset: 0 8px;
|
||||
margin: 4px 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
border-radius: 3px;
|
||||
clear: both;
|
||||
content: "";
|
||||
background: var(--el-color-primary) !important;
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,8 +262,8 @@
|
||||
|
||||
/* 子菜单中还有子菜单 */
|
||||
.el-menu .el-sub-menu__title {
|
||||
font-size: 12px;
|
||||
min-width: $sideBarWidth !important;
|
||||
font-size: 12px;
|
||||
background-color: $subMenuBg !important;
|
||||
}
|
||||
|
||||
@ -280,8 +280,8 @@
|
||||
}
|
||||
|
||||
.is-active {
|
||||
transition: color 0.3s;
|
||||
color: $subMenuActiveText !important;
|
||||
transition: color 0.3s;
|
||||
}
|
||||
|
||||
.el-menu-item.is-active.nest-menu > * {
|
||||
@ -290,15 +290,12 @@
|
||||
}
|
||||
|
||||
.el-menu-item.is-active.nest-menu::before {
|
||||
content: "";
|
||||
clear: both;
|
||||
position: absolute;
|
||||
left: 8px;
|
||||
right: 8px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
border-radius: 3px;
|
||||
inset: 0 8px;
|
||||
clear: both;
|
||||
content: "";
|
||||
background: var(--el-color-primary) !important;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.el-menu-item,
|
||||
@ -346,8 +343,8 @@
|
||||
|
||||
/* 子菜单中还有子菜单 */
|
||||
.el-menu .el-sub-menu__title {
|
||||
font-size: 12px;
|
||||
min-width: $sideBarWidth !important;
|
||||
font-size: 12px;
|
||||
background-color: $subMenuBg !important;
|
||||
|
||||
&:hover {
|
||||
@ -372,8 +369,8 @@
|
||||
}
|
||||
|
||||
.el-menu-item.is-active {
|
||||
transition: color 0.3s;
|
||||
color: $subMenuActiveText !important;
|
||||
transition: color 0.3s;
|
||||
}
|
||||
|
||||
.el-menu-item.is-active.nest-menu > * {
|
||||
@ -382,68 +379,65 @@
|
||||
}
|
||||
|
||||
.el-menu-item.is-active.nest-menu::before {
|
||||
content: "";
|
||||
clear: both;
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
right: 5px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
border-radius: 3px;
|
||||
inset: 0 5px;
|
||||
clear: both;
|
||||
content: "";
|
||||
background: var(--el-color-primary) !important;
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.horizontal-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
background: $menuBg;
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
align-items: center;
|
||||
background: $menuBg;
|
||||
|
||||
.horizontal-header-left {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
width: auto;
|
||||
min-width: 200px;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
padding-left: 10px;
|
||||
cursor: pointer;
|
||||
transition: all var(--pure-transition-duration) ease;
|
||||
|
||||
img {
|
||||
height: 32px;
|
||||
display: inline-block;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
span {
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
margin: 2px 0 0 12px;
|
||||
color: $subMenuActiveText;
|
||||
display: inline-block;
|
||||
height: 32px;
|
||||
margin: 2px 0 0 12px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
line-height: 32px;
|
||||
color: $subMenuActiveText;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.horizontal-header-menu {
|
||||
height: 100%;
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.horizontal-header-right {
|
||||
display: flex;
|
||||
min-width: 340px;
|
||||
align-items: center;
|
||||
color: $subMenuActiveText;
|
||||
justify-content: flex-end;
|
||||
min-width: 340px;
|
||||
color: $subMenuActiveText;
|
||||
|
||||
/* 搜索 */
|
||||
.search-container,
|
||||
@ -469,19 +463,19 @@
|
||||
width: 40px;
|
||||
height: 48px;
|
||||
padding: 11px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
color: $subMenuActiveText;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.el-dropdown-link {
|
||||
height: 48px;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
height: 48px;
|
||||
padding: 10px;
|
||||
color: $subMenuActiveText;
|
||||
cursor: pointer;
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
@ -496,10 +490,10 @@
|
||||
}
|
||||
|
||||
.el-menu {
|
||||
border: none;
|
||||
height: 100%;
|
||||
width: 100% !important;
|
||||
height: 100%;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.el-menu-item,
|
||||
@ -533,8 +527,8 @@
|
||||
}
|
||||
|
||||
.is-active {
|
||||
transition: color 0.3s;
|
||||
color: $subMenuActiveText !important;
|
||||
transition: color 0.3s;
|
||||
}
|
||||
}
|
||||
|
||||
@ -554,8 +548,8 @@
|
||||
}
|
||||
|
||||
.sidebar-container {
|
||||
transition: transform var(--pure-transition-duration);
|
||||
width: $sideBarWidth;
|
||||
transition: transform var(--pure-transition-duration);
|
||||
}
|
||||
|
||||
&.hideSidebar {
|
||||
@ -570,6 +564,7 @@
|
||||
|
||||
body[layout="vertical"] {
|
||||
$sideBarWidth: 210px;
|
||||
|
||||
@include merge-style($sideBarWidth);
|
||||
|
||||
.el-menu--collapse {
|
||||
@ -587,8 +582,8 @@ body[layout="vertical"] {
|
||||
}
|
||||
|
||||
.sidebar-container {
|
||||
transition: width var(--pure-transition-duration);
|
||||
width: 54px !important;
|
||||
transition: width var(--pure-transition-duration);
|
||||
|
||||
.is-active.submenu-title-noDropdown.outer-most {
|
||||
background: transparent !important;
|
||||
@ -604,8 +599,8 @@ body[layout="vertical"] {
|
||||
.el-sub-menu {
|
||||
& > .el-sub-menu__title {
|
||||
& > span {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
visibility: visible;
|
||||
}
|
||||
@ -644,6 +639,7 @@ body[layout="vertical"] {
|
||||
|
||||
body[layout="horizontal"] {
|
||||
$sideBarWidth: 0;
|
||||
|
||||
@include merge-style($sideBarWidth);
|
||||
|
||||
.fixed-header,
|
||||
@ -658,6 +654,7 @@ body[layout="horizontal"] {
|
||||
|
||||
body[layout="mix"] {
|
||||
$sideBarWidth: 210px;
|
||||
|
||||
@include merge-style($sideBarWidth);
|
||||
|
||||
.el-menu--collapse {
|
||||
@ -675,8 +672,8 @@ body[layout="mix"] {
|
||||
}
|
||||
|
||||
.sidebar-container {
|
||||
transition: width var(--pure-transition-duration);
|
||||
width: 54px !important;
|
||||
transition: width var(--pure-transition-duration);
|
||||
|
||||
.is-active.submenu-title-noDropdown.outer-most {
|
||||
background: transparent !important;
|
||||
@ -692,9 +689,10 @@ body[layout="mix"] {
|
||||
.el-sub-menu {
|
||||
& > .el-sub-menu__title {
|
||||
padding: 0;
|
||||
|
||||
& > span {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
visibility: visible;
|
||||
}
|
||||
|
@ -31,6 +31,7 @@
|
||||
}
|
||||
|
||||
.breadcrumb-leave-active {
|
||||
position: absolute;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
@ -40,10 +41,6 @@
|
||||
transform: translateX(20px);
|
||||
}
|
||||
|
||||
.breadcrumb-leave-active {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 重置el-menu的展开收起动画时长
|
||||
*/
|
||||
|
@ -60,7 +60,7 @@ class PureHttp {
|
||||
/** 请求拦截 */
|
||||
private httpInterceptorsRequest(): void {
|
||||
PureHttp.axiosInstance.interceptors.request.use(
|
||||
async (config: PureHttpRequestConfig) => {
|
||||
async (config: PureHttpRequestConfig): Promise<any> => {
|
||||
// 开启进度条动画
|
||||
NProgress.start();
|
||||
// 优先判断post/get等方法是否传入回掉,否则执行初始化设置等回掉
|
||||
|
@ -2,10 +2,10 @@
|
||||
import { App } from "vue";
|
||||
import Storage from "responsive-storage";
|
||||
import { routerArrays } from "@/layout/types";
|
||||
|
||||
const nameSpace = "responsive-";
|
||||
import { responsiveStorageNameSpace } from "@/config";
|
||||
|
||||
export const injectResponsiveStorage = (app: App, config: ServerConfigs) => {
|
||||
const nameSpace = responsiveStorageNameSpace();
|
||||
const configObj = Object.assign(
|
||||
{
|
||||
// 国际化 默认中文zh
|
||||
@ -31,7 +31,7 @@ export const injectResponsiveStorage = (app: App, config: ServerConfigs) => {
|
||||
},
|
||||
config.MultiTagsCache
|
||||
? {
|
||||
// 默认显示首页tag
|
||||
// 默认显示顶级菜单tag
|
||||
tags: Storage.getData("tags", nameSpace) ?? routerArrays
|
||||
}
|
||||
: {}
|
||||
|
@ -38,7 +38,7 @@ const barcodes = [
|
||||
<el-link
|
||||
href="https://lindell.me/JsBarcode/"
|
||||
target="_blank"
|
||||
style="font-size: 16px; margin: 0 5px 4px 0"
|
||||
style="margin: 0 5px 4px 0; font-size: 16px"
|
||||
>
|
||||
JsBarcode
|
||||
</el-link>
|
||||
|
@ -76,7 +76,7 @@ const exportExcel = () => {
|
||||
<el-link
|
||||
href="https://github.com/SheetJS/sheetjs"
|
||||
target="_blank"
|
||||
style="font-size: 16px; margin: 0 5px 4px 0"
|
||||
style="margin: 0 5px 4px 0; font-size: 16px"
|
||||
>
|
||||
github地址
|
||||
</el-link>
|
||||
|
@ -39,7 +39,7 @@ const load = () => {
|
||||
<el-link
|
||||
href="https://github.com/yujinpan/el-table-infinite-scroll"
|
||||
target="_blank"
|
||||
style="font-size: 16px; margin: 0 5px 4px 0"
|
||||
style="margin: 0 5px 4px 0; font-size: 16px"
|
||||
>
|
||||
github地址
|
||||
</el-link>
|
||||
|
@ -52,7 +52,7 @@ const filterMethod = (query: string, node: treeNode) => {
|
||||
href="https://element-plus.gitee.io/zh-CN/component/tree-v2.html"
|
||||
target="_blank"
|
||||
:icon="useRenderIcon(NodeTree)"
|
||||
style="font-size: 16px; margin: 0 5px 4px 0"
|
||||
style="margin: 0 5px 4px 0; font-size: 16px"
|
||||
>
|
||||
Tree V2
|
||||
</el-link>
|
||||
|
@ -41,7 +41,7 @@ const onPrint = () => {
|
||||
<el-link
|
||||
href="https://github.com/hrynko/vue-pdf-embed"
|
||||
target="_blank"
|
||||
style="font-size: 16px; margin: 0 5px 4px 0"
|
||||
style="margin: 0 5px 4px 0; font-size: 16px"
|
||||
>
|
||||
github地址
|
||||
</el-link>
|
||||
|
@ -201,7 +201,7 @@ const tableData: User[] = [
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
|
@ -30,7 +30,7 @@ const disabledClick = () => {
|
||||
<el-link
|
||||
href="https://github.com/soldair/node-qrcode"
|
||||
target="_blank"
|
||||
style="font-size: 16px; margin: 0 5px 4px 0"
|
||||
style="margin: 0 5px 4px 0; font-size: 16px"
|
||||
>
|
||||
qrcode
|
||||
</el-link>
|
||||
|
@ -91,7 +91,7 @@ const swiperExample: any[] = [
|
||||
<el-link
|
||||
href="https://github.com/nolimits4web/swiper"
|
||||
target="_blank"
|
||||
style="font-size: 16px; margin: 0 5px 4px 0"
|
||||
style="margin: 0 5px 4px 0; font-size: 16px"
|
||||
>
|
||||
github地址
|
||||
</el-link>
|
||||
|
@ -80,26 +80,26 @@ const activities = [
|
||||
|
||||
<style scoped>
|
||||
.message {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
width: 200px;
|
||||
padding: 5px 12px;
|
||||
line-height: 18px;
|
||||
color: #fff;
|
||||
word-break: break-all;
|
||||
background-color: var(--el-color-primary);
|
||||
border-color: var(--el-color-primary);
|
||||
color: #fff;
|
||||
line-height: 18px;
|
||||
padding: 5px 12px 5px 12px;
|
||||
box-sizing: border-box;
|
||||
border-radius: 6px;
|
||||
position: relative;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.message::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: -10px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
content: "";
|
||||
border-color: var(--el-color-primary) transparent transparent;
|
||||
border-style: solid dashed dashed;
|
||||
border-width: 10px;
|
||||
|
@ -65,9 +65,9 @@ const filteredItems = computed(() => {
|
||||
|
||||
<style scoped>
|
||||
.dynamic-scroller-demo {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.scroller {
|
||||
@ -81,10 +81,10 @@ const filteredItems = computed(() => {
|
||||
}
|
||||
|
||||
.message {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 32px;
|
||||
padding: 12px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||
|
@ -16,7 +16,7 @@ defineOptions({
|
||||
<el-link
|
||||
href="https://github.com/Akryum/vue-virtual-scroller/tree/next/packages/vue-virtual-scroller"
|
||||
target="_blank"
|
||||
style="font-size: 16px; margin: 0 5px 4px 0"
|
||||
style="margin: 0 5px 4px 0; font-size: 16px"
|
||||
>
|
||||
github地址
|
||||
</el-link>
|
||||
|
@ -60,9 +60,9 @@ const filteredItems = computed(() => {
|
||||
|
||||
<style scoped>
|
||||
.dynamic-scroller-demo {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.scroller {
|
||||
@ -70,9 +70,9 @@ const filteredItems = computed(() => {
|
||||
}
|
||||
|
||||
.message {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
min-height: 32px;
|
||||
padding: 12px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||
|
@ -57,10 +57,11 @@ export function useColumns() {
|
||||
label: "QQ交流群",
|
||||
cellRenderer: () => {
|
||||
return (
|
||||
<a href="https://jq.qq.com/?_wv=1027&k=E9fwmFGr" target="_blank">
|
||||
<span style="color: var(--el-color-primary)">
|
||||
点击链接加入群聊【Pure Admin】
|
||||
</span>
|
||||
<a
|
||||
href="https://yiming_chang.gitee.io/pure-admin-doc/pages/support/#qq-%E4%BA%A4%E6%B5%81%E7%BE%A4"
|
||||
target="_blank"
|
||||
>
|
||||
<span style="color: var(--el-color-primary)">点击加群</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
@ -63,12 +63,12 @@ export default defineComponent({
|
||||
<style scoped>
|
||||
.wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
border: 3px dashed rgba(90, 167, 164, 0.9);
|
||||
background-color: rgb(90 167 164 / 20%);
|
||||
border: 3px dashed rgb(90 167 164 / 90%);
|
||||
border-radius: 8px;
|
||||
background-color: rgba(90, 167, 164, 0.2);
|
||||
}
|
||||
</style>
|
||||
|
@ -98,13 +98,13 @@ export default defineComponent({
|
||||
<style scoped>
|
||||
.wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
margin-bottom: 30px;
|
||||
border: 3px dashed rgba(90, 167, 164, 0.9);
|
||||
background-color: rgb(90 167 164 / 20%);
|
||||
border: 3px dashed rgb(90 167 164 / 90%);
|
||||
border-radius: 8px;
|
||||
background-color: rgba(90, 167, 164, 0.2);
|
||||
}
|
||||
</style>
|
||||
|
@ -60,12 +60,12 @@ export default ExampleSFC;
|
||||
<style scoped>
|
||||
.wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
border: 3px dashed rgba(90, 167, 164, 0.9);
|
||||
background-color: rgb(90 167 164 / 20%);
|
||||
border: 3px dashed rgb(90 167 164 / 90%);
|
||||
border-radius: 8px;
|
||||
background-color: rgba(90, 167, 164, 0.2);
|
||||
}
|
||||
</style>
|
||||
|
@ -44,8 +44,8 @@ const onCropper = (): void => {
|
||||
<style scoped>
|
||||
.cropper-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
|
@ -110,7 +110,7 @@ function addDanmu() {
|
||||
<el-link
|
||||
href="https://github.com/hellodigua/vue-danmaku/tree/vue3"
|
||||
target="_blank"
|
||||
style="font-size: 16px; margin: 0 4px 5px"
|
||||
style="margin: 0 4px 5px; font-size: 16px"
|
||||
>
|
||||
vue3-danmaku
|
||||
</el-link>
|
||||
@ -197,10 +197,10 @@ function addDanmu() {
|
||||
align-items: center;
|
||||
|
||||
.img {
|
||||
height: 25px;
|
||||
width: 25px;
|
||||
border-radius: 50%;
|
||||
height: 25px;
|
||||
margin-right: 5px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
271
src/views/components/dialog/index.vue
Normal file
271
src/views/components/dialog/index.vue
Normal file
@ -0,0 +1,271 @@
|
||||
<script setup lang="tsx">
|
||||
import { h, createVNode } from "vue";
|
||||
import { message } from "@/utils/message";
|
||||
import { addDialog, closeDialog, closeAllDialog } from "@/components/ReDialog";
|
||||
|
||||
defineOptions({
|
||||
name: "Dialog"
|
||||
});
|
||||
|
||||
function onBaseClick() {
|
||||
addDialog({
|
||||
title: "基本使用",
|
||||
contentRenderer: () => <p>弹框内容-基本使用</p> // jsx 语法 (注意在.vue文件启用jsx语法,需要在script开启lang="tsx")
|
||||
});
|
||||
}
|
||||
|
||||
function onDraggableClick() {
|
||||
addDialog({
|
||||
title: "可拖拽",
|
||||
draggable: true,
|
||||
contentRenderer: () => h("p", "弹框内容-可拖拽") // h 渲染函数 https://cn.vuejs.org/api/render-function.html#h
|
||||
});
|
||||
}
|
||||
|
||||
function onFullscreenClick() {
|
||||
addDialog({
|
||||
title: "全屏",
|
||||
fullscreen: true,
|
||||
contentRenderer: () => createVNode("p", null, "弹框内容-全屏") // createVNode 渲染函数 https://cn.vuejs.org/guide/extras/render-function.html#creating-vnodes
|
||||
});
|
||||
}
|
||||
|
||||
function onModalClick() {
|
||||
addDialog({
|
||||
title: "无背景遮罩层",
|
||||
modal: false,
|
||||
contentRenderer: () => <p>弹框内容-无背景遮罩层</p>
|
||||
});
|
||||
}
|
||||
|
||||
function onStyleClick() {
|
||||
addDialog({
|
||||
title: "自定义弹出位置",
|
||||
top: "60vh",
|
||||
style: { marginRight: "20px" },
|
||||
contentRenderer: () => <p>弹框内容-自定义弹出位置</p>
|
||||
});
|
||||
}
|
||||
|
||||
function onoOpenDelayClick() {
|
||||
addDialog({
|
||||
title: "延时2秒打开弹框",
|
||||
openDelay: 2000,
|
||||
contentRenderer: () => <p>弹框内容-延时2秒打开弹框</p>
|
||||
});
|
||||
}
|
||||
|
||||
function onCloseDelayClick() {
|
||||
addDialog({
|
||||
title: "延时2秒关闭弹框",
|
||||
closeDelay: 2000,
|
||||
contentRenderer: () => <p>弹框内容-延时2秒关闭弹框</p>
|
||||
});
|
||||
}
|
||||
|
||||
function onShowCloseClick() {
|
||||
addDialog({
|
||||
title: "不显示右上角关闭按钮图标",
|
||||
showClose: false,
|
||||
contentRenderer: () => <p>弹框内容-不显示右上角关闭按钮图标</p>
|
||||
});
|
||||
}
|
||||
|
||||
function onBeforeCloseClick() {
|
||||
addDialog({
|
||||
title: "禁止通过键盘ESC关闭",
|
||||
closeOnPressEscape: false,
|
||||
contentRenderer: () => <p>弹框内容-禁止通过键盘ESC关闭</p>
|
||||
});
|
||||
}
|
||||
|
||||
function onCloseOnClickModalClick() {
|
||||
addDialog({
|
||||
title: "禁止通过点击modal关闭",
|
||||
closeOnClickModal: false,
|
||||
contentRenderer: () => <p>弹框内容-禁止通过点击modal关闭</p>
|
||||
});
|
||||
}
|
||||
|
||||
function onHideFooterClick() {
|
||||
addDialog({
|
||||
title: "隐藏底部取消、确定按钮",
|
||||
hideFooter: true,
|
||||
contentRenderer: () => <p>弹框内容-隐藏底部取消、确定按钮</p>
|
||||
});
|
||||
}
|
||||
|
||||
function onHeaderRendererClick() {
|
||||
addDialog({
|
||||
title: "自定义头部",
|
||||
showClose: false,
|
||||
headerRenderer: ({ close, titleId, titleClass }) => (
|
||||
// jsx 语法
|
||||
<div class="flex flex-row justify-between">
|
||||
<h4 id={titleId} class={titleClass}>
|
||||
自定义头部
|
||||
</h4>
|
||||
<el-button type="danger" onClick={close}>
|
||||
关闭
|
||||
</el-button>
|
||||
</div>
|
||||
),
|
||||
contentRenderer: () => <p>弹框内容-自定义头部</p>
|
||||
});
|
||||
}
|
||||
|
||||
function onFooterRendererClick() {
|
||||
addDialog({
|
||||
title: "自定义底部",
|
||||
footerRenderer: ({ options, index }) => (
|
||||
<el-button onClick={() => closeDialog(options, index)}>
|
||||
{options.title}-{index}
|
||||
</el-button>
|
||||
),
|
||||
contentRenderer: () => <p>弹框内容-自定义底部</p>
|
||||
});
|
||||
}
|
||||
|
||||
function onFooterButtonsClick() {
|
||||
addDialog({
|
||||
title: "自定义底部按钮",
|
||||
footerButtons: [
|
||||
{
|
||||
label: "按钮1",
|
||||
size: "small",
|
||||
type: "success",
|
||||
btnClick: ({ dialog: { options, index }, button }) => {
|
||||
console.log(options, index, button);
|
||||
closeDialog(options, index);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "按钮2",
|
||||
text: true,
|
||||
bg: true,
|
||||
btnClick: ({ dialog: { options, index }, button }) => {
|
||||
console.log(options, index, button);
|
||||
closeDialog(options, index);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "按钮3",
|
||||
size: "large",
|
||||
type: "warning",
|
||||
btnClick: ({ dialog: { options, index }, button }) => {
|
||||
console.log(options, index, button);
|
||||
closeDialog(options, index);
|
||||
}
|
||||
}
|
||||
],
|
||||
contentRenderer: () => <p>弹框内容-自定义底部按钮</p>
|
||||
});
|
||||
}
|
||||
|
||||
function onOpenClick() {
|
||||
addDialog({
|
||||
title: "打开后的回调",
|
||||
open: ({ options, index }) => message({ options, index } as any),
|
||||
contentRenderer: () => <p>弹框内容-打开后的回调</p>
|
||||
});
|
||||
}
|
||||
|
||||
function onCloseCallBackClick() {
|
||||
addDialog({
|
||||
title: "关闭后的回调",
|
||||
closeCallBack: ({ options, index, args }) => {
|
||||
console.log(options, index, args);
|
||||
let text = "";
|
||||
if (args?.command === "cancel") {
|
||||
text = "您点击了取消按钮";
|
||||
} else if (args?.command === "sure") {
|
||||
text = "您点击了确定按钮";
|
||||
} else {
|
||||
text = "您点击了右上角关闭按钮或者空白页";
|
||||
}
|
||||
message(text);
|
||||
},
|
||||
contentRenderer: () => <p>弹框内容-关闭后的回调</p>
|
||||
});
|
||||
}
|
||||
|
||||
function onNestingClick() {
|
||||
addDialog({
|
||||
title: "嵌套的弹框",
|
||||
contentRenderer: ({ index }) => (
|
||||
<el-button
|
||||
onClick={() =>
|
||||
addDialog({
|
||||
title: `第${index + 1}个子弹框`,
|
||||
width: "40%",
|
||||
contentRenderer: ({ index }) => (
|
||||
<el-button
|
||||
onClick={() =>
|
||||
addDialog({
|
||||
title: `第${index + 1}个子弹框`,
|
||||
width: "30%",
|
||||
contentRenderer: () => (
|
||||
<>
|
||||
<el-button round onClick={() => closeAllDialog()}>
|
||||
哎呦,你干嘛,赶快关闭所有弹框
|
||||
</el-button>
|
||||
</>
|
||||
)
|
||||
})
|
||||
}
|
||||
>
|
||||
点击打开第{index + 1}个子弹框
|
||||
</el-button>
|
||||
)
|
||||
})
|
||||
}
|
||||
>
|
||||
点击打开第{index + 1}个子弹框
|
||||
</el-button>
|
||||
)
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="font-medium">
|
||||
二次封装 element-plus 的
|
||||
<el-link
|
||||
href="https://element-plus.org/zh-CN/component/dialog.html"
|
||||
target="_blank"
|
||||
style="margin: 0 4px 5px; font-size: 16px"
|
||||
>
|
||||
Dialog
|
||||
</el-link>
|
||||
,采用函数式调用弹框组件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-space wrap>
|
||||
<el-button @click="onBaseClick"> 基本使用 </el-button>
|
||||
<el-button @click="onDraggableClick"> 可拖拽 </el-button>
|
||||
<el-button @click="onFullscreenClick"> 全屏 </el-button>
|
||||
<el-button @click="onModalClick"> 无背景遮罩层 </el-button>
|
||||
<el-button @click="onStyleClick"> 自定义弹出位置 </el-button>
|
||||
<el-button @click="onoOpenDelayClick"> 延时2秒打开弹框 </el-button>
|
||||
<el-button @click="onCloseDelayClick"> 延时2秒关闭弹框 </el-button>
|
||||
<el-button @click="onShowCloseClick">
|
||||
不显示右上角关闭按钮图标
|
||||
</el-button>
|
||||
<el-button @click="onBeforeCloseClick"> 禁止通过键盘ESC关闭 </el-button>
|
||||
<el-button @click="onCloseOnClickModalClick">
|
||||
禁止通过点击modal关闭
|
||||
</el-button>
|
||||
<el-button @click="onHideFooterClick"> 隐藏底部取消、确定按钮 </el-button>
|
||||
<el-button @click="onHeaderRendererClick"> 自定义头部 </el-button>
|
||||
<el-button @click="onFooterRendererClick"> 自定义底部 </el-button>
|
||||
<el-button @click="onFooterButtonsClick"> 自定义底部按钮 </el-button>
|
||||
<el-button @click="onOpenClick"> 打开后的回调 </el-button>
|
||||
<el-button @click="onCloseCallBackClick"> 关闭后的回调 </el-button>
|
||||
<el-button @click="onNestingClick"> 嵌套的弹框 </el-button>
|
||||
</el-space>
|
||||
</el-card>
|
||||
</template>
|
@ -65,7 +65,7 @@ onMounted(() => {
|
||||
href="https://sortablejs.github.io/vue.draggable.next/#/simple"
|
||||
target="_blank"
|
||||
:icon="useRenderIcon(Rank)"
|
||||
style="font-size: 16px; margin: 0 4px 5px"
|
||||
style="margin: 0 4px 5px; font-size: 16px"
|
||||
>
|
||||
vuedraggable
|
||||
</el-link>
|
||||
@ -150,35 +150,36 @@ onMounted(() => {
|
||||
/* grid列表拖拽 */
|
||||
.grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: 33.3% 33.3% 33.3%;
|
||||
grid-template-rows: 33.3% 33.3% 33.3%;
|
||||
grid-template-columns: 33.3% 33.3% 33.3%;
|
||||
}
|
||||
|
||||
.item-single {
|
||||
font-size: 1.5em;
|
||||
height: 77px;
|
||||
text-align: center;
|
||||
font-size: 1.5em;
|
||||
line-height: 85px;
|
||||
border: 1px solid #e5e4e9;
|
||||
text-align: center;
|
||||
cursor: move;
|
||||
border: 1px solid #e5e4e9;
|
||||
}
|
||||
|
||||
.item-cut {
|
||||
font-size: 1.5em;
|
||||
height: 77px;
|
||||
font-size: 1.5em;
|
||||
line-height: 77px;
|
||||
text-align: center;
|
||||
border: 1px solid #e5e4e9;
|
||||
cursor: move;
|
||||
border: 1px solid #e5e4e9;
|
||||
}
|
||||
|
||||
.item {
|
||||
font-size: 2em;
|
||||
text-align: center;
|
||||
line-height: 100px;
|
||||
border: 1px solid #e5e4e9;
|
||||
text-align: center;
|
||||
cursor: move;
|
||||
@media screen and (max-width: 750px) {
|
||||
border: 1px solid #e5e4e9;
|
||||
|
||||
@media screen and (width <= 750px) {
|
||||
line-height: 90px;
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ watch(
|
||||
<el-link
|
||||
href="https://github.com/leezng/vue-json-pretty"
|
||||
target="_blank"
|
||||
style="font-size: 16px; margin: 0 4px 5px"
|
||||
style="margin: 0 4px 5px; font-size: 16px"
|
||||
>
|
||||
vue-json-pretty
|
||||
</el-link>
|
||||
@ -91,7 +91,7 @@ watch(
|
||||
<el-link
|
||||
href="https://github.com/surmon-china/vue-codemirror"
|
||||
target="_blank"
|
||||
style="font-size: 16px; margin: 0 4px 5px"
|
||||
style="margin: 0 4px 5px; font-size: 16px"
|
||||
>
|
||||
codemirror6
|
||||
</el-link>
|
||||
|
@ -125,8 +125,8 @@ function changeDirection(val) {
|
||||
<style lang="scss" scoped>
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
span {
|
||||
margin-right: 20px;
|
||||
@ -134,23 +134,23 @@ function changeDirection(val) {
|
||||
}
|
||||
|
||||
.warp {
|
||||
height: 270px;
|
||||
width: 360px;
|
||||
height: 270px;
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0 auto;
|
||||
list-style: none;
|
||||
|
||||
li,
|
||||
a {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
height: 30px;
|
||||
font-size: 15px;
|
||||
line-height: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,9 +57,9 @@ $H: 70vh;
|
||||
.split-pane {
|
||||
width: 70vw;
|
||||
height: $H;
|
||||
text-align: center;
|
||||
font-size: 50px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
border: 1px solid #e5e6eb;
|
||||
|
||||
.dv-a,
|
||||
@ -67,8 +67,8 @@ $H: 70vh;
|
||||
.dv-c {
|
||||
width: $W;
|
||||
height: $W;
|
||||
color: rgba($color: dodgerblue, $alpha: 0.8);
|
||||
line-height: $H;
|
||||
color: rgba($color: dodgerblue, $alpha: 80%);
|
||||
}
|
||||
|
||||
.dv-b,
|
||||
@ -77,11 +77,11 @@ $H: 70vh;
|
||||
}
|
||||
|
||||
.dv-b {
|
||||
color: rgba($color: #000, $alpha: 0.8);
|
||||
color: rgba($color: #000, $alpha: 80%);
|
||||
}
|
||||
|
||||
.dv-c {
|
||||
color: rgba($color: #ce272d, $alpha: 0.8);
|
||||
color: rgba($color: #ce272d, $alpha: 80%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,13 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted } from "vue";
|
||||
import Player from "xgplayer/dist/simple_player";
|
||||
import volume from "xgplayer/es/controls/volume";
|
||||
import { deviceDetection } from "@pureadmin/utils";
|
||||
import screenShot from "xgplayer/es/controls/screenShot";
|
||||
import playbackRate from "xgplayer/es/controls/playbackRate";
|
||||
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
|
||||
import VideoPlay from "@iconify-icons/ep/video-play";
|
||||
|
||||
import Player from "xgplayer";
|
||||
import "xgplayer/dist/index.min.css";
|
||||
|
||||
defineOptions({
|
||||
name: "Video"
|
||||
});
|
||||
@ -15,15 +14,18 @@ defineOptions({
|
||||
onMounted(() => {
|
||||
new Player({
|
||||
id: "mse",
|
||||
lang: "zh",
|
||||
// 默认静音
|
||||
volume: 0,
|
||||
autoplay: false,
|
||||
screenShot: true,
|
||||
videoAttributes: {
|
||||
crossOrigin: "anonymous"
|
||||
},
|
||||
url: "https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4",
|
||||
poster:
|
||||
"https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/poster.jpg",
|
||||
fluid: deviceDetection(),
|
||||
controlPlugins: [volume, playbackRate, screenShot],
|
||||
//传入倍速可选数组
|
||||
playbackRate: [0.5, 0.75, 1, 1.5, 2]
|
||||
});
|
||||
@ -37,10 +39,10 @@ onMounted(() => {
|
||||
<span class="font-medium">
|
||||
视频组件,采用开源的
|
||||
<el-link
|
||||
href="https://v2.h5player.bytedance.com"
|
||||
href="https://v3.h5player.bytedance.com/"
|
||||
target="_blank"
|
||||
:icon="useRenderIcon(VideoPlay)"
|
||||
style="font-size: 16px; margin: 0 4px 5px"
|
||||
style="margin: 0 4px 5px; font-size: 16px"
|
||||
>
|
||||
西瓜播放器
|
||||
</el-link>
|
||||
|
@ -48,7 +48,7 @@ const handleCreated = editor => {
|
||||
href="https://www.wangeditor.com"
|
||||
target="_blank"
|
||||
:icon="useRenderIcon(Edit)"
|
||||
style="font-size: 16px; margin: 0 4px 5px"
|
||||
style="margin: 0 4px 5px; font-size: 16px"
|
||||
>
|
||||
Wangeditor
|
||||
</el-link>
|
||||
|
@ -18,21 +18,21 @@ defineOptions({
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.back {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
cursor: pointer;
|
||||
border-radius: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
cursor: pointer;
|
||||
background: rgb(138 150 160 / 8%);
|
||||
border-radius: 18px;
|
||||
transform: translate(-50%, -50%);
|
||||
background: rgba(138, 150, 160, 0.08);
|
||||
|
||||
&:hover {
|
||||
background: rgba(138, 150, 160, 0.2);
|
||||
background: rgb(138 150 160 / 20%);
|
||||
transition: background 0.6s;
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ function initLf() {
|
||||
LogicFlow.use(Menu);
|
||||
const domLf = new LogicFlow({
|
||||
...unref(config),
|
||||
container: document.querySelector("#LF-Turbo")
|
||||
container: document.querySelector("#turbo")
|
||||
});
|
||||
lf.value = domLf;
|
||||
// 设置边类型bpmn:sequenceFlow为默认类型
|
||||
@ -74,7 +74,7 @@ onMounted(() => {
|
||||
href="http://logic-flow.org/"
|
||||
target="_blank"
|
||||
:icon="useRenderIcon(SetUp)"
|
||||
style="font-size: 16px; margin: 0 4px 5px"
|
||||
style="margin: 0 4px 5px; font-size: 16px"
|
||||
>
|
||||
LogicFlow
|
||||
</el-link>
|
||||
@ -93,7 +93,7 @@ onMounted(() => {
|
||||
<!-- 节点面板 -->
|
||||
<NodePanel :lf="lf" :nodeList="nodeList" />
|
||||
<!-- 画布 -->
|
||||
<div id="LF-Turbo" />
|
||||
<div id="turbo" />
|
||||
<!-- 数据查看面板 -->
|
||||
<el-dialog
|
||||
class="flow-dialog"
|
||||
@ -110,19 +110,19 @@ onMounted(() => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
#LF-Turbo {
|
||||
#turbo {
|
||||
width: 100%;
|
||||
height: 70vh;
|
||||
}
|
||||
|
||||
.logic-flow-view {
|
||||
margin: 10px;
|
||||
position: relative;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.demo-title {
|
||||
text-align: center;
|
||||
margin: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.demo-control {
|
||||
@ -139,23 +139,23 @@ onMounted(() => {
|
||||
.add-panel {
|
||||
position: absolute;
|
||||
z-index: 11;
|
||||
background-color: white;
|
||||
padding: 10px 5px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.el-drawer__body {
|
||||
height: 80%;
|
||||
overflow: auto;
|
||||
margin-top: -30px;
|
||||
z-index: 3;
|
||||
height: 80%;
|
||||
margin-top: -30px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
:deep(.flow-dialog) {
|
||||
transform: none;
|
||||
left: 0;
|
||||
top: 5vh;
|
||||
position: relative;
|
||||
top: 5vh;
|
||||
left: 0;
|
||||
margin: 0 auto;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
:deep(.flow-dialog) .el-dialog__body {
|
||||
|
@ -94,25 +94,25 @@ const cardLogoClass = computed(() => [
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 12px;
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
border-radius: 3px;
|
||||
|
||||
&_detail {
|
||||
flex: 1;
|
||||
padding: 24px 32px;
|
||||
min-height: 140px;
|
||||
padding: 24px 32px;
|
||||
|
||||
&--logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: #e0ebff;
|
||||
font-size: 32px;
|
||||
color: #0052d9;
|
||||
background: #e0ebff;
|
||||
border-radius: 50%;
|
||||
|
||||
&__disabled {
|
||||
color: #a1c4ff;
|
||||
@ -129,21 +129,21 @@ const cardLogoClass = computed(() => [
|
||||
}
|
||||
|
||||
&--name {
|
||||
margin: 24px 0 8px 0;
|
||||
margin: 24px 0 8px;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
&--desc {
|
||||
display: -webkit-box;
|
||||
height: 40px;
|
||||
margin-bottom: 24px;
|
||||
overflow: hidden;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
margin-bottom: 24px;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,13 +18,13 @@ import TypeIt from "@/components/ReTypeit";
|
||||
import qrCode from "./components/qrCode.vue";
|
||||
import regist from "./components/regist.vue";
|
||||
import update from "./components/update.vue";
|
||||
import { initRouter } from "@/router/utils";
|
||||
import { useNav } from "@/layout/hooks/useNav";
|
||||
import type { FormInstance } from "element-plus";
|
||||
import { $t, transformI18n } from "@/plugins/i18n";
|
||||
import { operates, thirdParty } from "./utils/enums";
|
||||
import { useLayout } from "@/layout/hooks/useLayout";
|
||||
import { useUserStoreHook } from "@/store/modules/user";
|
||||
import { initRouter, getTopMenu } from "@/router/utils";
|
||||
import { bg, avatar, illustration } from "./utils/static";
|
||||
import { ReImageVerify } from "@/components/ReImageVerify";
|
||||
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
|
||||
@ -76,7 +76,7 @@ const onLogin = async (formEl: FormInstance | undefined) => {
|
||||
if (res.success) {
|
||||
// 获取后端路由
|
||||
initRouter().then(() => {
|
||||
router.push("/");
|
||||
router.push(getTopMenu(true).path);
|
||||
message("登录成功", { type: "success" });
|
||||
});
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ function tabClick({ index }) {
|
||||
<el-link
|
||||
href="https://github.com/pure-admin/pure-admin-table"
|
||||
target="_blank"
|
||||
style="font-size: 16px; margin: 0 4px 5px"
|
||||
style="margin: 0 4px 5px; font-size: 16px"
|
||||
>
|
||||
@pureadmin/table
|
||||
</el-link>
|
||||
|
@ -24,7 +24,7 @@ function tabClick({ index }) {
|
||||
<el-link
|
||||
href="https://github.com/pure-admin/pure-admin-table"
|
||||
target="_blank"
|
||||
style="font-size: 16px; margin: 0 4px 5px"
|
||||
style="margin: 0 4px 5px; font-size: 16px"
|
||||
>
|
||||
@pureadmin/table
|
||||
</el-link>
|
||||
|
@ -58,7 +58,7 @@ const columns = [
|
||||
role="img"
|
||||
aria-label="dingding"
|
||||
class="anticon anticon-dingding flex items-center cursor-pointer"
|
||||
style="color: rgb(0, 160, 233); margin-left: 8px"
|
||||
style="margin-left: 8px; color: rgb(0 160 233)"
|
||||
>
|
||||
<svg
|
||||
viewBox="64 64 896 896"
|
||||
|
@ -281,6 +281,6 @@ axios
|
||||
}
|
||||
|
||||
.main-content {
|
||||
margin: 20px 20px 0 20px !important;
|
||||
margin: 20px 20px 0 !important;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,20 +1,39 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
plugins: ["stylelint-order"],
|
||||
customSyntax: "postcss-html",
|
||||
extends: ["stylelint-config-standard", "stylelint-config-prettier"],
|
||||
extends: [
|
||||
"stylelint-config-standard",
|
||||
"stylelint-config-html/vue",
|
||||
"stylelint-config-recess-order"
|
||||
],
|
||||
plugins: ["stylelint-order", "stylelint-prettier", "stylelint-scss"],
|
||||
overrides: [
|
||||
{
|
||||
files: ["**/*.(css|html|vue)"],
|
||||
customSyntax: "postcss-html"
|
||||
},
|
||||
{
|
||||
files: ["*.scss", "**/*.scss"],
|
||||
customSyntax: "postcss-scss",
|
||||
extends: [
|
||||
"stylelint-config-standard-scss",
|
||||
"stylelint-config-recommended-vue/scss"
|
||||
]
|
||||
}
|
||||
],
|
||||
rules: {
|
||||
"selector-class-pattern": null,
|
||||
"no-descending-specificity": null,
|
||||
"scss/dollar-variable-pattern": null,
|
||||
"selector-pseudo-class-no-unknown": [
|
||||
true,
|
||||
{
|
||||
ignorePseudoClasses: ["global"]
|
||||
ignorePseudoClasses: ["deep", "global"]
|
||||
}
|
||||
],
|
||||
"selector-pseudo-element-no-unknown": [
|
||||
true,
|
||||
{
|
||||
ignorePseudoElements: ["v-deep"]
|
||||
ignorePseudoElements: ["v-deep", "v-global", "v-slotted"]
|
||||
}
|
||||
],
|
||||
"at-rule-no-unknown": [
|
||||
@ -30,17 +49,11 @@ module.exports = {
|
||||
"if",
|
||||
"each",
|
||||
"include",
|
||||
"mixin"
|
||||
"mixin",
|
||||
"use"
|
||||
]
|
||||
}
|
||||
],
|
||||
"no-empty-source": null,
|
||||
"named-grid-areas-no-invalid": null,
|
||||
"unicode-bom": "never",
|
||||
"no-descending-specificity": null,
|
||||
"font-family-no-missing-generic-family-keyword": null,
|
||||
"declaration-colon-space-after": "always-single-line",
|
||||
"declaration-colon-space-before": "never",
|
||||
"rule-empty-line-before": [
|
||||
"always",
|
||||
{
|
||||
@ -67,26 +80,5 @@ module.exports = {
|
||||
{ severity: "warning" }
|
||||
]
|
||||
},
|
||||
ignoreFiles: ["**/*.js", "**/*.jsx", "**/*.tsx", "**/*.ts", "**/*.json"],
|
||||
overrides: [
|
||||
{
|
||||
files: ["*.vue", "**/*.vue", "*.html", "**/*.html"],
|
||||
extends: ["stylelint-config-recommended", "stylelint-config-html"],
|
||||
rules: {
|
||||
"keyframes-name-pattern": null,
|
||||
"selector-pseudo-class-no-unknown": [
|
||||
true,
|
||||
{
|
||||
ignorePseudoClasses: ["deep", "global"]
|
||||
}
|
||||
],
|
||||
"selector-pseudo-element-no-unknown": [
|
||||
true,
|
||||
{
|
||||
ignorePseudoElements: ["v-deep", "v-global", "v-slotted"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
ignoreFiles: ["**/*.js", "**/*.ts", "**/*.jsx", "**/*.tsx"]
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user