parent
c1725e0b09
commit
12c78f96d7
|
|
@ -3,14 +3,12 @@
|
||||||
# 变量必须以 VITE_ 为前缀才能暴露给外部读取
|
# 变量必须以 VITE_ 为前缀才能暴露给外部读取
|
||||||
NODE_ENV='development'
|
NODE_ENV='development'
|
||||||
|
|
||||||
VITE_APP_TITLE = 'vue3-element-admin'
|
|
||||||
VITE_APP_PORT = 3000
|
VITE_APP_PORT = 3000
|
||||||
|
|
||||||
# API请求前缀
|
# API请求前缀
|
||||||
VITE_APP_BASE_API = '/dev-api'
|
VITE_APP_BASE_API = '/dev-api'
|
||||||
|
|
||||||
# proxy代理配置
|
# proxy代理配置
|
||||||
VITE_APP_TARGET_URL = 'http://vapi.youlai.tech' # 线上接口
|
VITE_APP_API_URL = 'http://vapi.youlai.tech' # 线上接口
|
||||||
# VITE_APP_TARGET_URL = 'http://localhost:8989' # 本地接口,本地启动后端:https://gitee.com/youlaiorg/youlai-boot
|
# VITE_APP_API_URL = 'http://localhost:8989' # 本地接口,本地启动后端:https://gitee.com/youlaiorg/youlai-boot
|
||||||
# VITE_APP_TARGET_URL = 'http://localhost:3000' # 本地Mock
|
# VITE_APP_API_URL = 'http://localhost:3000' # 本地Mock
|
||||||
VITE_APP_TARGET_BASE_API = ''
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
## 生产环境
|
## 生产环境
|
||||||
|
|
||||||
VITE_APP_TITLE = 'vue3-element-admin'
|
|
||||||
VITE_APP_PORT = 3000
|
VITE_APP_PORT = 3000
|
||||||
|
|
||||||
# API请求前缀
|
# API请求前缀
|
||||||
VITE_APP_BASE_API = '/prod-api'
|
VITE_APP_BASE_API = '/prod-api'
|
||||||
|
|
||||||
# proxy代理配置
|
# proxy代理配置
|
||||||
VITE_APP_TARGET_URL = "http://vapi.youlai.tech"
|
VITE_APP_API_URL = "http://vapi.youlai.tech"
|
||||||
VITE_APP_TARGET_BASE_API = ''
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
## 模拟环境
|
|
||||||
NODE_ENV='staging'
|
|
||||||
|
|
||||||
VITE_APP_TITLE = 'vue3-element-admin'
|
|
||||||
VITE_APP_PORT = 3000
|
|
||||||
|
|
||||||
VITE_APP_TARGET_URL = 'http://localhost:3000';
|
|
||||||
VITE_APP_BASE_API = '/prod-api'
|
|
||||||
|
|
@ -83,7 +83,6 @@ module.exports = {
|
||||||
],
|
],
|
||||||
// https://eslint.org/docs/latest/use/configure/language-options#specifying-globals
|
// https://eslint.org/docs/latest/use/configure/language-options#specifying-globals
|
||||||
globals: {
|
globals: {
|
||||||
DialogOption: "readonly",
|
|
||||||
OptionType: "readonly",
|
OptionType: "readonly",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
{
|
{
|
||||||
"recommendations": ["Vue.volar"]
|
"recommendations": ["Vue.volar", "lokalise.i18n-ally","esbenp.prettier-vscode"]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ server {
|
||||||
|
|
||||||
- **接口切换 Mock**
|
- **接口切换 Mock**
|
||||||
|
|
||||||
v2.5.0 版本支持 Mock , 修改 `.env.development` 的 `VITE_APP_TARGET_URL` 值为 `http://localhost:3000` 即可 。
|
v2.5.0 版本支持 Mock , 修改 `.env.development` 的 `VITE_APP_API_URL` 值为 `http://localhost:3000` 即可 。
|
||||||
|
|
||||||
- **其他问题**
|
- **其他问题**
|
||||||
|
|
||||||
|
|
@ -142,7 +142,7 @@ server {
|
||||||
|
|
||||||
> 1. 获取基于 `Java 、SpringBoot` 开发的后端 [youlai-boot](https://gitee.com/youlaiorg/youlai-boot.git) 源码 ;
|
> 1. 获取基于 `Java 、SpringBoot` 开发的后端 [youlai-boot](https://gitee.com/youlaiorg/youlai-boot.git) 源码 ;
|
||||||
> 2. 根据后端工程说明文档 [README.md](https://gitee.com/youlaiorg/youlai-boot#%E9%A1%B9%E7%9B%AE%E8%BF%90%E8%A1%8C) 完成本地启动;
|
> 2. 根据后端工程说明文档 [README.md](https://gitee.com/youlaiorg/youlai-boot#%E9%A1%B9%E7%9B%AE%E8%BF%90%E8%A1%8C) 完成本地启动;
|
||||||
> 3. 替换 [.env.development](.env.development) 的代理目标地址 `VITE_APP_TARGET_URL` 的值 `vapi.youlai.tech` 为本地的 `localhost:8989`
|
> 3. 替换 [.env.development](.env.development) 的代理目标地址 `VITE_APP_API_URL` 的值 `vapi.youlai.tech` 为本地的 `localhost:8989`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "vue3-element-admin",
|
"name": "vue3-element-admin",
|
||||||
"private": true,
|
|
||||||
"version": "2.6.7",
|
"version": "2.6.7",
|
||||||
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"preinstall": "npx only-allow pnpm",
|
"preinstall": "npx only-allow pnpm",
|
||||||
"dev": "vite serve --mode development",
|
"dev": "vite serve --mode development",
|
||||||
|
|
@ -63,7 +63,8 @@
|
||||||
"vue": "^3.3.8",
|
"vue": "^3.3.8",
|
||||||
"vue-i18n": "9.2.2",
|
"vue-i18n": "9.2.2",
|
||||||
"vue-router": "^4.2.5",
|
"vue-router": "^4.2.5",
|
||||||
"xlsx": "^0.18.5"
|
"xlsx": "^0.18.5",
|
||||||
|
"dayjs": "^1.11.10"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^17.8.1",
|
"@commitlint/cli": "^17.8.1",
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import SvgIcon from "@/components/SvgIcon/index.vue";
|
|
||||||
import { translateRouteTitle } from "@/utils/i18n";
|
import { translateRouteTitle } from "@/utils/i18n";
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
import path from "path-browserify";
|
import path from "path-browserify";
|
||||||
import { isExternal } from "@/utils/index";
|
import { isExternal } from "@/utils/index";
|
||||||
import AppLink from "./Link.vue";
|
import AppLink from "./Link.vue";
|
||||||
|
import { RouteRecordRaw } from "vue-router";
|
||||||
|
|
||||||
import Item from "./Item.vue";
|
import Item from "./Item.vue";
|
||||||
|
|
||||||
|
|
@ -38,15 +39,19 @@ const onlyOneChild = ref(); // 临时变量,唯一子路由
|
||||||
* @param children 子路由数组
|
* @param children 子路由数组
|
||||||
* @param parent 当前路由
|
* @param parent 当前路由
|
||||||
*/
|
*/
|
||||||
function hasOneShowingChild(children = [], parent: any) {
|
function hasOneShowingChild(
|
||||||
|
children: RouteRecordRaw[] = [],
|
||||||
|
parent: RouteRecordRaw
|
||||||
|
) {
|
||||||
// 子路由集合
|
// 子路由集合
|
||||||
const showingChildren = children.filter((item: any) => {
|
const showingChildren = children.filter((route: RouteRecordRaw) => {
|
||||||
if (item.meta?.hidden) {
|
if (route.meta?.hidden) {
|
||||||
// 过滤不显示的子路由
|
// 过滤不显示的子路由
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
route.meta!.hidden = false;
|
||||||
// 临时变量(多个子路由 onlyOneChild 变量是用不上的)
|
// 临时变量(多个子路由 onlyOneChild 变量是用不上的)
|
||||||
onlyOneChild.value = item;
|
onlyOneChild.value = route;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -87,7 +92,7 @@ function resolvePath(routePath: string) {
|
||||||
<!-- 无子路由 || 目录只有一个子路由并配置始终显示为否(alwaysShow=false) -->
|
<!-- 无子路由 || 目录只有一个子路由并配置始终显示为否(alwaysShow=false) -->
|
||||||
<template
|
<template
|
||||||
v-if="
|
v-if="
|
||||||
hasOneShowingChild(item.children, item) &&
|
hasOneShowingChild(item.children, item as RouteRecordRaw) &&
|
||||||
(!onlyOneChild.children || onlyOneChild.noShowingChildren) &&
|
(!onlyOneChild.children || onlyOneChild.noShowingChildren) &&
|
||||||
!item.meta?.alwaysShow
|
!item.meta?.alwaysShow
|
||||||
"
|
"
|
||||||
|
|
|
||||||
|
|
@ -61,13 +61,6 @@ onMounted(() => {
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<!-- <sidebar-item
|
|
||||||
v-for="route in topMenu"
|
|
||||||
:key="route.path"
|
|
||||||
:item="route"
|
|
||||||
:base-path="route.path"
|
|
||||||
:is-collapse="false"
|
|
||||||
/> -->
|
|
||||||
</el-menu>
|
</el-menu>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useTagsViewStore, TagView } from "@/store/modules/tagsView";
|
import { useTagsViewStore } from "@/store/modules/tagsView";
|
||||||
|
|
||||||
const tagAndTagSpacing = ref(4);
|
const tagAndTagSpacing = ref(4);
|
||||||
const { proxy } = getCurrentInstance() as any;
|
const { proxy } = getCurrentInstance() as any;
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,76 @@
|
||||||
|
<template>
|
||||||
|
<div class="tags-container">
|
||||||
|
<scroll-pane ref="scrollPaneRef" @scroll="handleScroll">
|
||||||
|
<router-link
|
||||||
|
ref="tagRef"
|
||||||
|
v-for="tag in visitedViews"
|
||||||
|
:key="tag.path"
|
||||||
|
:class="'tags-item ' + (isActive(tag) ? 'active' : '')"
|
||||||
|
:data-path="tag.path"
|
||||||
|
:to="{ path: tag.path, query: tag.query }"
|
||||||
|
@click.middle="!isAffix(tag) ? closeSelectedTag(tag) : ''"
|
||||||
|
@contextmenu.prevent="openTagMenu(tag, $event)"
|
||||||
|
>
|
||||||
|
{{ translateRouteTitle(tag.title) }}
|
||||||
|
<span
|
||||||
|
v-if="!isAffix(tag)"
|
||||||
|
class="tags-item-close"
|
||||||
|
@click.prevent.stop="closeSelectedTag(tag)"
|
||||||
|
>
|
||||||
|
<i-ep-close size="10px" />
|
||||||
|
</span>
|
||||||
|
</router-link>
|
||||||
|
</scroll-pane>
|
||||||
|
|
||||||
|
<!-- tag标签操作菜单 -->
|
||||||
|
<ul
|
||||||
|
v-show="tagMenuVisible"
|
||||||
|
class="tag-menu"
|
||||||
|
:style="{ left: left + 'px', top: top + 'px' }"
|
||||||
|
>
|
||||||
|
<li @click="refreshSelectedTag(selectedTag)">
|
||||||
|
<svg-icon icon-class="refresh" />
|
||||||
|
刷新
|
||||||
|
</li>
|
||||||
|
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">
|
||||||
|
<svg-icon icon-class="close" />
|
||||||
|
关闭
|
||||||
|
</li>
|
||||||
|
<li @click="closeOtherTags">
|
||||||
|
<svg-icon icon-class="close_other" />
|
||||||
|
关闭其它
|
||||||
|
</li>
|
||||||
|
<li v-if="!isFirstView()" @click="closeLeftTags">
|
||||||
|
<svg-icon icon-class="close_left" />
|
||||||
|
关闭左侧
|
||||||
|
</li>
|
||||||
|
<li v-if="!isLastView()" @click="closeRightTags">
|
||||||
|
<svg-icon icon-class="close_right" />
|
||||||
|
关闭右侧
|
||||||
|
</li>
|
||||||
|
<li @click="closeAllTags(selectedTag)">
|
||||||
|
<svg-icon icon-class="close_all" />
|
||||||
|
关闭所有
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { getCurrentInstance, ComponentInternalInstance } from "vue";
|
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
|
import { useRoute, useRouter, RouteRecordRaw } from "vue-router";
|
||||||
import path from "path-browserify";
|
import { resolve } from "path-browserify";
|
||||||
|
|
||||||
import { useRoute, useRouter } from "vue-router";
|
|
||||||
|
|
||||||
import { translateRouteTitle } from "@/utils/i18n";
|
import { translateRouteTitle } from "@/utils/i18n";
|
||||||
|
|
||||||
import { usePermissionStore } from "@/store/modules/permission";
|
import { usePermissionStore } from "@/store/modules/permission";
|
||||||
import { useTagsViewStore, TagView } from "@/store/modules/tagsView";
|
import { useTagsViewStore } from "@/store/modules/tagsView";
|
||||||
import { useSettingsStore } from "@/store/modules/settings";
|
import { useSettingsStore } from "@/store/modules/settings";
|
||||||
import { useAppStore } from "@/store/modules/app";
|
import { useAppStore } from "@/store/modules/app";
|
||||||
|
|
||||||
import ScrollPane from "./ScrollPane.vue";
|
import ScrollPane from "./ScrollPane.vue";
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance()!;
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
|
|
@ -27,11 +82,19 @@ const { visitedViews } = storeToRefs(tagsViewStore);
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
const layout = computed(() => settingsStore.layout);
|
const layout = computed(() => settingsStore.layout);
|
||||||
|
|
||||||
const selectedTag = ref({});
|
const selectedTag = ref<TagView>({
|
||||||
|
path: "",
|
||||||
|
fullPath: "",
|
||||||
|
name: "",
|
||||||
|
title: "",
|
||||||
|
affix: false,
|
||||||
|
keepAlive: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const affixTags = ref<TagView[]>([]);
|
||||||
const scrollPaneRef = ref();
|
const scrollPaneRef = ref();
|
||||||
const left = ref(0);
|
const left = ref(0);
|
||||||
const top = ref(0);
|
const top = ref(0);
|
||||||
const affixTags = ref<TagView[]>([]);
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
route,
|
route,
|
||||||
|
|
@ -40,8 +103,7 @@ watch(
|
||||||
moveToCurrentTag();
|
moveToCurrentTag();
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
//初始化立即执行
|
immediate: true, //初始化立即执行
|
||||||
immediate: true,
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -54,27 +116,31 @@ watch(tagMenuVisible, (value) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function filterAffixTags(routes: any[], basePath = "/") {
|
function filterAffixTags(routes: RouteRecordRaw[], basePath = "/") {
|
||||||
let tags: TagView[] = [];
|
const processRoute = (route: RouteRecordRaw) => {
|
||||||
|
const fullPath = resolve(basePath, route.path);
|
||||||
|
|
||||||
routes.forEach((route) => {
|
const tag: TagView = {
|
||||||
if (route.meta && route.meta.affix) {
|
path: route.path,
|
||||||
const tagPath = path.resolve(basePath, route.path);
|
fullPath,
|
||||||
tags.push({
|
name: String(route.name),
|
||||||
fullPath: tagPath,
|
title: route.meta?.title || "no-name",
|
||||||
path: tagPath,
|
affix: route.meta?.affix,
|
||||||
name: route.name,
|
keepAlive: route.meta?.keepAlive,
|
||||||
meta: { ...route.meta },
|
};
|
||||||
});
|
|
||||||
|
if (tag.affix) {
|
||||||
|
tags.push(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (route.children) {
|
if (route.children) {
|
||||||
const childTags = filterAffixTags(route.children, route.path);
|
route.children.forEach(processRoute);
|
||||||
if (childTags.length >= 1) {
|
|
||||||
tags = tags.concat(childTags);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
let tags: TagView[] = [];
|
||||||
|
routes.forEach(processRoute);
|
||||||
|
|
||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,19 +156,35 @@ function initTags() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function addTags() {
|
function addTags() {
|
||||||
if (route.name) {
|
if (route.meta.title) {
|
||||||
tagsViewStore.addView(route);
|
tagsViewStore.addView({
|
||||||
|
name: route.name as string,
|
||||||
|
title: route.meta.title,
|
||||||
|
path: route.path,
|
||||||
|
fullPath: route.fullPath,
|
||||||
|
affix: route.meta?.affix,
|
||||||
|
keepAlive: route.meta?.keepAlive,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveToCurrentTag() {
|
function moveToCurrentTag() {
|
||||||
|
// 使用 nextTick() 的目的是确保在更新 tagsView 组件之前,scrollPaneRef 对象已经滚动到了正确的位置。
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
for (const r of tagsViewStore.visitedViews) {
|
for (const tag of visitedViews.value) {
|
||||||
if (r.path === route.path) {
|
if (tag.path === route.path) {
|
||||||
scrollPaneRef.value.moveToTarget(r);
|
scrollPaneRef.value.moveToTarget(tag);
|
||||||
// when query is different then update
|
// when query is different then update
|
||||||
if (r.fullPath !== route.fullPath) {
|
route.query = { ...route.query, ...tag.query };
|
||||||
tagsViewStore.updateVisitedView(route);
|
if (tag.fullPath !== route.fullPath) {
|
||||||
|
tagsViewStore.updateVisitedView({
|
||||||
|
name: route.name as string,
|
||||||
|
title: route.meta.title,
|
||||||
|
path: route.path,
|
||||||
|
fullPath: route.fullPath,
|
||||||
|
affix: route.meta?.affix,
|
||||||
|
keepAlive: route.meta?.keepAlive,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -110,19 +192,18 @@ function moveToCurrentTag() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function isActive(tag: TagView) {
|
function isActive(tag: TagView) {
|
||||||
return tag.path === route.path;
|
return tag.fullPath === route.fullPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isAffix(tag: TagView) {
|
function isAffix(tag: TagView) {
|
||||||
return tag.meta && tag.meta.affix;
|
return tag?.affix;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isFirstView() {
|
function isFirstView() {
|
||||||
try {
|
try {
|
||||||
return (
|
return (
|
||||||
(selectedTag.value as TagView).fullPath === "/dashboard" ||
|
selectedTag.value.fullPath === "/dashboard" ||
|
||||||
(selectedTag.value as TagView).fullPath ===
|
selectedTag.value.fullPath === tagsViewStore.visitedViews[1].fullPath
|
||||||
tagsViewStore.visitedViews[1].fullPath
|
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -132,7 +213,7 @@ function isFirstView() {
|
||||||
function isLastView() {
|
function isLastView() {
|
||||||
try {
|
try {
|
||||||
return (
|
return (
|
||||||
(selectedTag.value as TagView).fullPath ===
|
selectedTag.value.fullPath ===
|
||||||
tagsViewStore.visitedViews[tagsViewStore.visitedViews.length - 1].fullPath
|
tagsViewStore.visitedViews[tagsViewStore.visitedViews.length - 1].fullPath
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
@ -144,20 +225,18 @@ function refreshSelectedTag(view: TagView) {
|
||||||
tagsViewStore.delCachedView(view);
|
tagsViewStore.delCachedView(view);
|
||||||
const { fullPath } = view;
|
const { fullPath } = view;
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
router.replace({ path: "/redirect" + fullPath }).catch((err) => {
|
router.replace({ path: "/redirect" + fullPath });
|
||||||
console.warn(err);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function toLastView(visitedViews: TagView[], view?: any) {
|
function toLastView(visitedViews: TagView[], view?: TagView) {
|
||||||
const latestView = visitedViews.slice(-1)[0];
|
const latestView = visitedViews.slice(-1)[0];
|
||||||
if (latestView && latestView.fullPath) {
|
if (latestView && latestView.fullPath) {
|
||||||
router.push(latestView.fullPath);
|
router.push(latestView.fullPath);
|
||||||
} else {
|
} else {
|
||||||
// now the default is to redirect to the home page if there is no tags-view,
|
// now the default is to redirect to the home page if there is no tags-view,
|
||||||
// you can adjust it according to your needs.
|
// you can adjust it according to your needs.
|
||||||
if (view.name === "Dashboard") {
|
if (view?.name === "Dashboard") {
|
||||||
// to reload home page
|
// to reload home page
|
||||||
router.replace({ path: "/redirect" + view.fullPath });
|
router.replace({ path: "/redirect" + view.fullPath });
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -289,63 +368,6 @@ onMounted(() => {
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="tags-container">
|
|
||||||
<scroll-pane ref="scrollPaneRef" @scroll="handleScroll">
|
|
||||||
<router-link
|
|
||||||
v-for="tag in visitedViews"
|
|
||||||
:key="tag.path"
|
|
||||||
:class="'tags-item ' + (isActive(tag) ? 'active' : '')"
|
|
||||||
:data-path="tag.path"
|
|
||||||
:to="{ path: tag.path, query: tag.query }"
|
|
||||||
@click.middle="!isAffix(tag) ? closeSelectedTag(tag) : ''"
|
|
||||||
@contextmenu.prevent="openTagMenu(tag, $event)"
|
|
||||||
>
|
|
||||||
{{ translateRouteTitle(tag.meta?.title) }}
|
|
||||||
<span
|
|
||||||
v-if="!isAffix(tag)"
|
|
||||||
class="tags-item-close"
|
|
||||||
@click.prevent.stop="closeSelectedTag(tag)"
|
|
||||||
>
|
|
||||||
<i-ep-close class="text-[10px]" />
|
|
||||||
</span>
|
|
||||||
</router-link>
|
|
||||||
</scroll-pane>
|
|
||||||
|
|
||||||
<!-- tag标签操作菜单 -->
|
|
||||||
<ul
|
|
||||||
v-show="tagMenuVisible"
|
|
||||||
class="tag-menu"
|
|
||||||
:style="{ left: left + 'px', top: top + 'px' }"
|
|
||||||
>
|
|
||||||
<li @click="refreshSelectedTag(selectedTag)">
|
|
||||||
<svg-icon icon-class="refresh" />
|
|
||||||
刷新
|
|
||||||
</li>
|
|
||||||
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">
|
|
||||||
<svg-icon icon-class="close" />
|
|
||||||
关闭
|
|
||||||
</li>
|
|
||||||
<li @click="closeOtherTags">
|
|
||||||
<svg-icon icon-class="close_other" />
|
|
||||||
关闭其它
|
|
||||||
</li>
|
|
||||||
<li v-if="!isFirstView()" @click="closeLeftTags">
|
|
||||||
<svg-icon icon-class="close_left" />
|
|
||||||
关闭左侧
|
|
||||||
</li>
|
|
||||||
<li v-if="!isLastView()" @click="closeRightTags">
|
|
||||||
<svg-icon icon-class="close_right" />
|
|
||||||
关闭右侧
|
|
||||||
</li>
|
|
||||||
<li @click="closeAllTags(selectedTag)">
|
|
||||||
<svg-icon icon-class="close_all" />
|
|
||||||
关闭所有
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.tags-container {
|
.tags-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ const mixLeftMenu = computed(() => {
|
||||||
return permissionStore.mixLeftMenu;
|
return permissionStore.mixLeftMenu;
|
||||||
});
|
});
|
||||||
const layout = computed(() => settingsStore.layout);
|
const layout = computed(() => settingsStore.layout);
|
||||||
|
const watermarkEnabled = computed(() => settingsStore.watermark.enabled);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => activeTopMenu.value,
|
() => activeTopMenu.value,
|
||||||
(newVal) => {
|
(newVal) => {
|
||||||
|
|
@ -78,29 +80,31 @@ function toggleSideBar() {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="classObj" class="app-wrapper">
|
<div :class="classObj" class="app-wrapper">
|
||||||
<!-- 手机设备侧边栏打开遮罩层 -->
|
<el-watermark content="vue3-element-admin">
|
||||||
<div
|
<!-- 手机设备侧边栏打开遮罩层 -->
|
||||||
v-if="classObj.mobile && classObj.openSidebar"
|
<div
|
||||||
class="drawer-bg"
|
v-if="classObj.mobile && classObj.openSidebar"
|
||||||
@click="handleOutsideClick"
|
class="drawer-bg"
|
||||||
></div>
|
@click="handleOutsideClick"
|
||||||
|
></div>
|
||||||
|
|
||||||
<Sidebar class="sidebar-container" />
|
<Sidebar class="sidebar-container" />
|
||||||
<template v-if="layout === 'mix'">
|
<template v-if="layout === 'mix'">
|
||||||
<div class="mix-wrap">
|
<div class="mix-wrap">
|
||||||
<div class="left-wrap">
|
<div class="left-wrap">
|
||||||
<LeftMenu :menu-list="mixLeftMenu" :base-path="activeTopMenu" />
|
<LeftMenu :menu-list="mixLeftMenu" :base-path="activeTopMenu" />
|
||||||
<div class="menu-action">
|
<div class="menu-action">
|
||||||
<hamburger
|
<hamburger
|
||||||
:is-active="appStore.sidebar.opened"
|
:is-active="appStore.sidebar.opened"
|
||||||
@toggle-click="toggleSideBar"
|
@toggle-click="toggleSideBar"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<Main />
|
||||||
</div>
|
</div>
|
||||||
<Main />
|
</template>
|
||||||
</div>
|
<Main v-else />
|
||||||
</template>
|
</el-watermark>
|
||||||
<Main v-else />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,68 +1,16 @@
|
||||||
/**
|
const defaultSettings: AppSettings = {
|
||||||
* 系统设置
|
|
||||||
*/
|
|
||||||
interface DefaultSettings {
|
|
||||||
/**
|
|
||||||
* 系统标题
|
|
||||||
*/
|
|
||||||
title: string;
|
|
||||||
/**
|
|
||||||
* 系统版本
|
|
||||||
*/
|
|
||||||
version: string;
|
|
||||||
/**
|
|
||||||
* 是否显示设置
|
|
||||||
*/
|
|
||||||
showSettings: boolean;
|
|
||||||
/**
|
|
||||||
* 是否显示多标签导航
|
|
||||||
*/
|
|
||||||
tagsView: boolean;
|
|
||||||
/**
|
|
||||||
*是否固定头部
|
|
||||||
*/
|
|
||||||
fixedHeader: boolean;
|
|
||||||
/**
|
|
||||||
* 是否显示侧边栏Logo
|
|
||||||
*/
|
|
||||||
sidebarLogo: boolean;
|
|
||||||
/**
|
|
||||||
* 导航栏布局(left|top|mix)
|
|
||||||
*/
|
|
||||||
layout: string;
|
|
||||||
/**
|
|
||||||
* 主题模式(dark|light)
|
|
||||||
*/
|
|
||||||
theme: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 布局大小(default |large |small)
|
|
||||||
*/
|
|
||||||
size: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 语言( zh-cn| en)
|
|
||||||
*/
|
|
||||||
language: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 主题颜色
|
|
||||||
*/
|
|
||||||
themeColor: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const defaultSettings: DefaultSettings = {
|
|
||||||
title: "vue3-element-admin",
|
title: "vue3-element-admin",
|
||||||
version: "v2.6.7",
|
version: "v2.6.7",
|
||||||
showSettings: true,
|
showSettings: true,
|
||||||
tagsView: true,
|
tagsView: true,
|
||||||
fixedHeader: false,
|
fixedHeader: false,
|
||||||
sidebarLogo: true,
|
sidebarLogo: true,
|
||||||
layout: "left", // 默认左侧模式
|
layout: "left",
|
||||||
theme: "light", // 暗黑模式-dark 明亮模式-light
|
theme: "light",
|
||||||
size: "default",
|
size: "default",
|
||||||
language: "zh-cn",
|
language: "zh-cn",
|
||||||
themeColor: "#409EFF",
|
themeColor: "#409EFF",
|
||||||
|
watermark: { enabled: false, content: "有来技术" },
|
||||||
};
|
};
|
||||||
|
|
||||||
export default defaultSettings;
|
export default defaultSettings;
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ const hasPermission = (roles: string[], route: RouteRecordRaw) => {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return roles.some((role) => {
|
return roles.some((role) => {
|
||||||
if (route.meta?.roles !== undefined) {
|
if (route.meta?.roles) {
|
||||||
return (route.meta.roles as string[]).includes(role);
|
return route.meta.roles.includes(role);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,59 +2,53 @@ import { defineStore } from "pinia";
|
||||||
import defaultSettings from "@/settings";
|
import defaultSettings from "@/settings";
|
||||||
|
|
||||||
export const useSettingsStore = defineStore("setting", () => {
|
export const useSettingsStore = defineStore("setting", () => {
|
||||||
// state
|
const title = defaultSettings.title;
|
||||||
|
const version = defaultSettings.version;
|
||||||
|
|
||||||
const tagsView = useStorage<boolean>("tagsView", defaultSettings.tagsView);
|
const tagsView = useStorage<boolean>("tagsView", defaultSettings.tagsView);
|
||||||
|
|
||||||
const showSettings = ref<boolean>(defaultSettings.showSettings);
|
const showSettings = ref<boolean>(defaultSettings.showSettings);
|
||||||
const sidebarLogo = ref<boolean>(defaultSettings.sidebarLogo);
|
const sidebarLogo = ref<boolean>(defaultSettings.sidebarLogo);
|
||||||
|
|
||||||
const fixedHeader = useStorage<boolean>(
|
const fixedHeader = useStorage<boolean>(
|
||||||
"fixedHeader",
|
"fixedHeader",
|
||||||
defaultSettings.fixedHeader
|
defaultSettings.fixedHeader
|
||||||
);
|
);
|
||||||
|
|
||||||
const layout = useStorage<string>("layout", defaultSettings.layout);
|
const layout = useStorage<string>("layout", defaultSettings.layout);
|
||||||
const themeColor = useStorage<string>(
|
const themeColor = useStorage<string>(
|
||||||
"themeColor",
|
"themeColor",
|
||||||
defaultSettings.themeColor
|
defaultSettings.themeColor
|
||||||
);
|
);
|
||||||
|
|
||||||
const theme = useStorage<string>("theme", defaultSettings.theme);
|
const theme = useStorage<string>("theme", defaultSettings.theme);
|
||||||
|
|
||||||
// actions
|
// Whether to enable watermark
|
||||||
function changeSetting(param: { key: string; value: any }) {
|
const watermark = useStorage<any>("watermark", defaultSettings.watermark);
|
||||||
const { key, value } = param;
|
|
||||||
switch (key) {
|
const settingsMap: Record<string, Ref<any>> = {
|
||||||
case "showSettings":
|
showSettings,
|
||||||
showSettings.value = value;
|
fixedHeader,
|
||||||
break;
|
tagsView,
|
||||||
case "fixedHeader":
|
sidebarLogo,
|
||||||
fixedHeader.value = value;
|
layout,
|
||||||
break;
|
themeColor,
|
||||||
case "tagsView":
|
theme,
|
||||||
tagsView.value = value;
|
watermark: watermark.value,
|
||||||
break;
|
};
|
||||||
case "sidevarLogo":
|
|
||||||
sidebarLogo.value = value;
|
function changeSetting({ key, value }: { key: string; value: any }) {
|
||||||
break;
|
const setting = settingsMap[key];
|
||||||
case "layout":
|
if (setting !== undefined) {
|
||||||
layout.value = value;
|
setting.value = value;
|
||||||
break;
|
if (key === "theme" && value === "dark") {
|
||||||
case "themeColor":
|
document.documentElement.classList.add("dark");
|
||||||
themeColor.value = value;
|
} else {
|
||||||
break;
|
document.documentElement.classList.remove("dark");
|
||||||
case "theme":
|
}
|
||||||
theme.value = value;
|
|
||||||
if (theme.value === "dark") {
|
|
||||||
document.documentElement.classList.add("dark");
|
|
||||||
} else {
|
|
||||||
document.documentElement.classList.remove("dark");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
title,
|
||||||
|
version,
|
||||||
showSettings,
|
showSettings,
|
||||||
tagsView,
|
tagsView,
|
||||||
fixedHeader,
|
fixedHeader,
|
||||||
|
|
@ -63,5 +57,6 @@ export const useSettingsStore = defineStore("setting", () => {
|
||||||
themeColor,
|
themeColor,
|
||||||
changeSetting,
|
changeSetting,
|
||||||
theme,
|
theme,
|
||||||
|
watermark,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,45 +1,49 @@
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { RouteLocationNormalized } from "vue-router";
|
|
||||||
|
|
||||||
export interface TagView extends Partial<RouteLocationNormalized> {
|
|
||||||
title?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup
|
|
||||||
export const useTagsViewStore = defineStore("tagsView", () => {
|
export const useTagsViewStore = defineStore("tagsView", () => {
|
||||||
// state
|
|
||||||
const visitedViews = ref<TagView[]>([]);
|
const visitedViews = ref<TagView[]>([]);
|
||||||
const cachedViews = ref<string[]>([]);
|
const cachedViews = ref<string[]>([]);
|
||||||
|
|
||||||
// actions
|
/**
|
||||||
|
* 添加已访问视图到已访问视图列表中
|
||||||
|
*/
|
||||||
function addVisitedView(view: TagView) {
|
function addVisitedView(view: TagView) {
|
||||||
if (visitedViews.value.some((v) => v.path === view.path)) return;
|
// 如果已经存在于已访问的视图列表中,则不再添加
|
||||||
if (view.meta && view.meta.affix) {
|
if (visitedViews.value.some((v) => v.path === view.path)) {
|
||||||
visitedViews.value.unshift(
|
return;
|
||||||
Object.assign({}, view, {
|
}
|
||||||
title: view.meta?.title || "no-name",
|
// 如果视图是固定的(affix),则在已访问的视图列表的开头添加
|
||||||
})
|
if (view.affix) {
|
||||||
);
|
visitedViews.value.unshift(view);
|
||||||
} else {
|
} else {
|
||||||
visitedViews.value.push(
|
// 如果视图不是固定的,则在已访问的视图列表的末尾添加
|
||||||
Object.assign({}, view, {
|
visitedViews.value.push(view);
|
||||||
title: view.meta?.title || "no-name",
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加缓存视图到缓存视图列表中
|
||||||
|
*/
|
||||||
function addCachedView(view: TagView) {
|
function addCachedView(view: TagView) {
|
||||||
const viewName = view.name as string;
|
const viewName = view.name;
|
||||||
if (cachedViews.value.includes(viewName)) return;
|
// 如果缓存视图名称已经存在于缓存视图列表中,则不再添加
|
||||||
if (view.meta?.keepAlive) {
|
if (cachedViews.value.includes(viewName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果视图需要缓存(keepAlive),则将其路由名称添加到缓存视图列表中
|
||||||
|
if (view.keepAlive) {
|
||||||
cachedViews.value.push(viewName);
|
cachedViews.value.push(viewName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从已访问视图列表中删除指定的视图
|
||||||
|
*/
|
||||||
function delVisitedView(view: TagView) {
|
function delVisitedView(view: TagView) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
for (const [i, v] of visitedViews.value.entries()) {
|
for (const [i, v] of visitedViews.value.entries()) {
|
||||||
|
// 找到与指定视图路径匹配的视图,在已访问视图列表中删除该视图
|
||||||
if (v.path === view.path) {
|
if (v.path === view.path) {
|
||||||
visitedViews.value.splice(i, 1);
|
visitedViews.value.splice(i, 1);
|
||||||
break;
|
break;
|
||||||
|
|
@ -50,7 +54,7 @@ export const useTagsViewStore = defineStore("tagsView", () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
function delCachedView(view: TagView) {
|
function delCachedView(view: TagView) {
|
||||||
const viewName = view.name as string;
|
const viewName = view.name;
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const index = cachedViews.value.indexOf(viewName);
|
const index = cachedViews.value.indexOf(viewName);
|
||||||
index > -1 && cachedViews.value.splice(index, 1);
|
index > -1 && cachedViews.value.splice(index, 1);
|
||||||
|
|
@ -61,7 +65,7 @@ export const useTagsViewStore = defineStore("tagsView", () => {
|
||||||
function delOtherVisitedViews(view: TagView) {
|
function delOtherVisitedViews(view: TagView) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
visitedViews.value = visitedViews.value.filter((v) => {
|
visitedViews.value = visitedViews.value.filter((v) => {
|
||||||
return v.meta?.affix || v.path === view.path;
|
return v?.affix || v.path === view.path;
|
||||||
});
|
});
|
||||||
resolve([...visitedViews.value]);
|
resolve([...visitedViews.value]);
|
||||||
});
|
});
|
||||||
|
|
@ -126,12 +130,11 @@ export const useTagsViewStore = defineStore("tagsView", () => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
visitedViews.value = visitedViews.value.filter((item, index) => {
|
visitedViews.value = visitedViews.value.filter((item, index) => {
|
||||||
// affix:true 固定tag,例如“首页”
|
if (index >= currIndex || item?.affix) {
|
||||||
if (index >= currIndex || (item.meta && item.meta.affix)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cacheIndex = cachedViews.value.indexOf(item.name as string);
|
const cacheIndex = cachedViews.value.indexOf(item.name);
|
||||||
if (cacheIndex > -1) {
|
if (cacheIndex > -1) {
|
||||||
cachedViews.value.splice(cacheIndex, 1);
|
cachedViews.value.splice(cacheIndex, 1);
|
||||||
}
|
}
|
||||||
|
|
@ -151,16 +154,9 @@ export const useTagsViewStore = defineStore("tagsView", () => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
visitedViews.value = visitedViews.value.filter((item, index) => {
|
visitedViews.value = visitedViews.value.filter((item, index) => {
|
||||||
// affix:true 固定tag,例如“首页”
|
if (index <= currIndex || item?.affix) {
|
||||||
if (index <= currIndex || (item.meta && item.meta.affix)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cacheIndex = cachedViews.value.indexOf(item.name as string);
|
|
||||||
if (cacheIndex > -1) {
|
|
||||||
cachedViews.value.splice(cacheIndex, 1);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
});
|
||||||
resolve({
|
resolve({
|
||||||
visitedViews: [...visitedViews.value],
|
visitedViews: [...visitedViews.value],
|
||||||
|
|
@ -170,7 +166,7 @@ export const useTagsViewStore = defineStore("tagsView", () => {
|
||||||
|
|
||||||
function delAllViews() {
|
function delAllViews() {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const affixTags = visitedViews.value.filter((tag) => tag.meta?.affix);
|
const affixTags = visitedViews.value.filter((tag) => tag?.affix);
|
||||||
visitedViews.value = affixTags;
|
visitedViews.value = affixTags;
|
||||||
cachedViews.value = [];
|
cachedViews.value = [];
|
||||||
resolve({
|
resolve({
|
||||||
|
|
@ -182,7 +178,7 @@ export const useTagsViewStore = defineStore("tagsView", () => {
|
||||||
|
|
||||||
function delAllVisitedViews() {
|
function delAllVisitedViews() {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const affixTags = visitedViews.value.filter((tag) => tag.meta?.affix);
|
const affixTags = visitedViews.value.filter((tag) => tag?.affix);
|
||||||
visitedViews.value = affixTags;
|
visitedViews.value = affixTags;
|
||||||
resolve([...visitedViews.value]);
|
resolve([...visitedViews.value]);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,7 @@ declare global {
|
||||||
const EffectScope: typeof import("vue")["EffectScope"];
|
const EffectScope: typeof import("vue")["EffectScope"];
|
||||||
const ElForm: typeof import("element-plus/es")["ElForm"];
|
const ElForm: typeof import("element-plus/es")["ElForm"];
|
||||||
const ElMessage: typeof import("element-plus/es")["ElMessage"];
|
const ElMessage: typeof import("element-plus/es")["ElMessage"];
|
||||||
const ElNotification: typeof import("element-plus/es")["ElNotification"];
|
|
||||||
const ElMessageBox: typeof import("element-plus/es")["ElMessageBox"];
|
const ElMessageBox: typeof import("element-plus/es")["ElMessageBox"];
|
||||||
const ElTree: typeof import("element-plus/es")["ElTree"];
|
|
||||||
const asyncComputed: typeof import("@vueuse/core")["asyncComputed"];
|
const asyncComputed: typeof import("@vueuse/core")["asyncComputed"];
|
||||||
const autoResetRef: typeof import("@vueuse/core")["autoResetRef"];
|
const autoResetRef: typeof import("@vueuse/core")["autoResetRef"];
|
||||||
const computed: typeof import("vue")["computed"];
|
const computed: typeof import("vue")["computed"];
|
||||||
|
|
@ -41,6 +39,7 @@ declare global {
|
||||||
const h: typeof import("vue")["h"];
|
const h: typeof import("vue")["h"];
|
||||||
const ignorableWatch: typeof import("@vueuse/core")["ignorableWatch"];
|
const ignorableWatch: typeof import("@vueuse/core")["ignorableWatch"];
|
||||||
const inject: typeof import("vue")["inject"];
|
const inject: typeof import("vue")["inject"];
|
||||||
|
const injectLocal: typeof import("@vueuse/core")["injectLocal"];
|
||||||
const isDefined: typeof import("@vueuse/core")["isDefined"];
|
const isDefined: typeof import("@vueuse/core")["isDefined"];
|
||||||
const isProxy: typeof import("vue")["isProxy"];
|
const isProxy: typeof import("vue")["isProxy"];
|
||||||
const isReactive: typeof import("vue")["isReactive"];
|
const isReactive: typeof import("vue")["isReactive"];
|
||||||
|
|
@ -68,6 +67,7 @@ declare global {
|
||||||
const onUpdated: typeof import("vue")["onUpdated"];
|
const onUpdated: typeof import("vue")["onUpdated"];
|
||||||
const pausableWatch: typeof import("@vueuse/core")["pausableWatch"];
|
const pausableWatch: typeof import("@vueuse/core")["pausableWatch"];
|
||||||
const provide: typeof import("vue")["provide"];
|
const provide: typeof import("vue")["provide"];
|
||||||
|
const provideLocal: typeof import("@vueuse/core")["provideLocal"];
|
||||||
const reactify: typeof import("@vueuse/core")["reactify"];
|
const reactify: typeof import("@vueuse/core")["reactify"];
|
||||||
const reactifyObject: typeof import("@vueuse/core")["reactifyObject"];
|
const reactifyObject: typeof import("@vueuse/core")["reactifyObject"];
|
||||||
const reactive: typeof import("vue")["reactive"];
|
const reactive: typeof import("vue")["reactive"];
|
||||||
|
|
@ -287,10 +287,14 @@ declare global {
|
||||||
Component,
|
Component,
|
||||||
ComponentPublicInstance,
|
ComponentPublicInstance,
|
||||||
ComputedRef,
|
ComputedRef,
|
||||||
|
ExtractDefaultPropTypes,
|
||||||
|
ExtractPropTypes,
|
||||||
|
ExtractPublicPropTypes,
|
||||||
InjectionKey,
|
InjectionKey,
|
||||||
PropType,
|
PropType,
|
||||||
Ref,
|
Ref,
|
||||||
VNode,
|
VNode,
|
||||||
|
WritableComputedRef,
|
||||||
} from "vue";
|
} from "vue";
|
||||||
}
|
}
|
||||||
// for vue template auto import
|
// for vue template auto import
|
||||||
|
|
@ -305,7 +309,6 @@ declare module "vue" {
|
||||||
readonly ElMessageBox: UnwrapRef<
|
readonly ElMessageBox: UnwrapRef<
|
||||||
typeof import("element-plus/es")["ElMessageBox"]
|
typeof import("element-plus/es")["ElMessageBox"]
|
||||||
>;
|
>;
|
||||||
readonly ElTree: UnwrapRef<typeof import("element-plus/es")["ElTree"]>;
|
|
||||||
readonly asyncComputed: UnwrapRef<
|
readonly asyncComputed: UnwrapRef<
|
||||||
typeof import("@vueuse/core")["asyncComputed"]
|
typeof import("@vueuse/core")["asyncComputed"]
|
||||||
>;
|
>;
|
||||||
|
|
@ -385,6 +388,9 @@ declare module "vue" {
|
||||||
typeof import("@vueuse/core")["ignorableWatch"]
|
typeof import("@vueuse/core")["ignorableWatch"]
|
||||||
>;
|
>;
|
||||||
readonly inject: UnwrapRef<typeof import("vue")["inject"]>;
|
readonly inject: UnwrapRef<typeof import("vue")["inject"]>;
|
||||||
|
readonly injectLocal: UnwrapRef<
|
||||||
|
typeof import("@vueuse/core")["injectLocal"]
|
||||||
|
>;
|
||||||
readonly isDefined: UnwrapRef<typeof import("@vueuse/core")["isDefined"]>;
|
readonly isDefined: UnwrapRef<typeof import("@vueuse/core")["isDefined"]>;
|
||||||
readonly isProxy: UnwrapRef<typeof import("vue")["isProxy"]>;
|
readonly isProxy: UnwrapRef<typeof import("vue")["isProxy"]>;
|
||||||
readonly isReactive: UnwrapRef<typeof import("vue")["isReactive"]>;
|
readonly isReactive: UnwrapRef<typeof import("vue")["isReactive"]>;
|
||||||
|
|
@ -434,6 +440,9 @@ declare module "vue" {
|
||||||
typeof import("@vueuse/core")["pausableWatch"]
|
typeof import("@vueuse/core")["pausableWatch"]
|
||||||
>;
|
>;
|
||||||
readonly provide: UnwrapRef<typeof import("vue")["provide"]>;
|
readonly provide: UnwrapRef<typeof import("vue")["provide"]>;
|
||||||
|
readonly provideLocal: UnwrapRef<
|
||||||
|
typeof import("@vueuse/core")["provideLocal"]
|
||||||
|
>;
|
||||||
readonly reactify: UnwrapRef<typeof import("@vueuse/core")["reactify"]>;
|
readonly reactify: UnwrapRef<typeof import("@vueuse/core")["reactify"]>;
|
||||||
readonly reactifyObject: UnwrapRef<
|
readonly reactifyObject: UnwrapRef<
|
||||||
typeof import("@vueuse/core")["reactifyObject"]
|
typeof import("@vueuse/core")["reactifyObject"]
|
||||||
|
|
@ -951,7 +960,6 @@ declare module "@vue/runtime-core" {
|
||||||
readonly ElMessageBox: UnwrapRef<
|
readonly ElMessageBox: UnwrapRef<
|
||||||
typeof import("element-plus/es")["ElMessageBox"]
|
typeof import("element-plus/es")["ElMessageBox"]
|
||||||
>;
|
>;
|
||||||
readonly ElTree: UnwrapRef<typeof import("element-plus/es")["ElTree"]>;
|
|
||||||
readonly asyncComputed: UnwrapRef<
|
readonly asyncComputed: UnwrapRef<
|
||||||
typeof import("@vueuse/core")["asyncComputed"]
|
typeof import("@vueuse/core")["asyncComputed"]
|
||||||
>;
|
>;
|
||||||
|
|
@ -1031,6 +1039,9 @@ declare module "@vue/runtime-core" {
|
||||||
typeof import("@vueuse/core")["ignorableWatch"]
|
typeof import("@vueuse/core")["ignorableWatch"]
|
||||||
>;
|
>;
|
||||||
readonly inject: UnwrapRef<typeof import("vue")["inject"]>;
|
readonly inject: UnwrapRef<typeof import("vue")["inject"]>;
|
||||||
|
readonly injectLocal: UnwrapRef<
|
||||||
|
typeof import("@vueuse/core")["injectLocal"]
|
||||||
|
>;
|
||||||
readonly isDefined: UnwrapRef<typeof import("@vueuse/core")["isDefined"]>;
|
readonly isDefined: UnwrapRef<typeof import("@vueuse/core")["isDefined"]>;
|
||||||
readonly isProxy: UnwrapRef<typeof import("vue")["isProxy"]>;
|
readonly isProxy: UnwrapRef<typeof import("vue")["isProxy"]>;
|
||||||
readonly isReactive: UnwrapRef<typeof import("vue")["isReactive"]>;
|
readonly isReactive: UnwrapRef<typeof import("vue")["isReactive"]>;
|
||||||
|
|
@ -1080,6 +1091,9 @@ declare module "@vue/runtime-core" {
|
||||||
typeof import("@vueuse/core")["pausableWatch"]
|
typeof import("@vueuse/core")["pausableWatch"]
|
||||||
>;
|
>;
|
||||||
readonly provide: UnwrapRef<typeof import("vue")["provide"]>;
|
readonly provide: UnwrapRef<typeof import("vue")["provide"]>;
|
||||||
|
readonly provideLocal: UnwrapRef<
|
||||||
|
typeof import("@vueuse/core")["provideLocal"]
|
||||||
|
>;
|
||||||
readonly reactify: UnwrapRef<typeof import("@vueuse/core")["reactify"]>;
|
readonly reactify: UnwrapRef<typeof import("@vueuse/core")["reactify"]>;
|
||||||
readonly reactifyObject: UnwrapRef<
|
readonly reactifyObject: UnwrapRef<
|
||||||
typeof import("@vueuse/core")["reactifyObject"]
|
typeof import("@vueuse/core")["reactifyObject"]
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,10 @@ declare module "@vue/runtime-core" {
|
||||||
DeptTree: typeof import("./../views/system/user/components/dept-tree.vue")["default"];
|
DeptTree: typeof import("./../views/system/user/components/dept-tree.vue")["default"];
|
||||||
Dictionary: typeof import("./../components/Dictionary/index.vue")["default"];
|
Dictionary: typeof import("./../components/Dictionary/index.vue")["default"];
|
||||||
DictItem: typeof import("./../views/system/dict/components/dict-item.vue")["default"];
|
DictItem: typeof import("./../views/system/dict/components/dict-item.vue")["default"];
|
||||||
ElAlert: typeof import("element-plus/es")["ElAlert"];
|
|
||||||
ElBreadcrumb: typeof import("element-plus/es")["ElBreadcrumb"];
|
ElBreadcrumb: typeof import("element-plus/es")["ElBreadcrumb"];
|
||||||
ElBreadcrumbItem: typeof import("element-plus/es")["ElBreadcrumbItem"];
|
ElBreadcrumbItem: typeof import("element-plus/es")["ElBreadcrumbItem"];
|
||||||
ElButton: typeof import("element-plus/es")["ElButton"];
|
ElButton: typeof import("element-plus/es")["ElButton"];
|
||||||
ElCard: typeof import("element-plus/es")["ElCard"];
|
ElCard: typeof import("element-plus/es")["ElCard"];
|
||||||
ElCheckbox: typeof import("element-plus/es")["ElCheckbox"];
|
|
||||||
ElCheckboxGroup: typeof import("element-plus/es")["ElCheckboxGroup"];
|
|
||||||
ElCol: typeof import("element-plus/es")["ElCol"];
|
ElCol: typeof import("element-plus/es")["ElCol"];
|
||||||
ElDatePicker: typeof import("element-plus/es")["ElDatePicker"];
|
ElDatePicker: typeof import("element-plus/es")["ElDatePicker"];
|
||||||
ElDialog: typeof import("element-plus/es")["ElDialog"];
|
ElDialog: typeof import("element-plus/es")["ElDialog"];
|
||||||
|
|
@ -35,38 +32,35 @@ declare module "@vue/runtime-core" {
|
||||||
ElImage: typeof import("element-plus/es")["ElImage"];
|
ElImage: typeof import("element-plus/es")["ElImage"];
|
||||||
ElInput: typeof import("element-plus/es")["ElInput"];
|
ElInput: typeof import("element-plus/es")["ElInput"];
|
||||||
ElInputNumber: typeof import("element-plus/es")["ElInputNumber"];
|
ElInputNumber: typeof import("element-plus/es")["ElInputNumber"];
|
||||||
ElLink: typeof import("element-plus/es")["ElLink"];
|
|
||||||
ElMenu: typeof import("element-plus/es")["ElMenu"];
|
ElMenu: typeof import("element-plus/es")["ElMenu"];
|
||||||
ElMenuItem: typeof import("element-plus/es")["ElMenuItem"];
|
ElMenuItem: typeof import("element-plus/es")["ElMenuItem"];
|
||||||
ElOption: typeof import("element-plus/es")["ElOption"];
|
ElOption: typeof import("element-plus/es")["ElOption"];
|
||||||
ElPagination: typeof import("element-plus/es")["ElPagination"];
|
ElPagination: typeof import("element-plus/es")["ElPagination"];
|
||||||
ElPopover: typeof import("element-plus/es")["ElPopover"];
|
ElPopover: typeof import("element-plus/es")["ElPopover"];
|
||||||
ElRadio: typeof import("element-plus/es")["ElRadio"];
|
ElRadio: typeof import("element-plus/es")["ElRadio"];
|
||||||
ElRadioButton: typeof import("element-plus/es")["ElRadioButton"];
|
|
||||||
ElRadioGroup: typeof import("element-plus/es")["ElRadioGroup"];
|
ElRadioGroup: typeof import("element-plus/es")["ElRadioGroup"];
|
||||||
ElRate: typeof import("element-plus/es")["ElRate"];
|
|
||||||
ElRow: typeof import("element-plus/es")["ElRow"];
|
ElRow: typeof import("element-plus/es")["ElRow"];
|
||||||
ElScrollbar: typeof import("element-plus/es")["ElScrollbar"];
|
ElScrollbar: typeof import("element-plus/es")["ElScrollbar"];
|
||||||
ElSelect: typeof import("element-plus/es")["ElSelect"];
|
ElSelect: typeof import("element-plus/es")["ElSelect"];
|
||||||
|
ElStatistic: typeof import("element-plus/es")["ElStatistic"];
|
||||||
ElSubMenu: typeof import("element-plus/es")["ElSubMenu"];
|
ElSubMenu: typeof import("element-plus/es")["ElSubMenu"];
|
||||||
ElSwitch: typeof import("element-plus/es")["ElSwitch"];
|
ElSwitch: typeof import("element-plus/es")["ElSwitch"];
|
||||||
ElTable: typeof import("element-plus/es")["ElTable"];
|
ElTable: typeof import("element-plus/es")["ElTable"];
|
||||||
ElTableColumn: typeof import("element-plus/es")["ElTableColumn"];
|
ElTableColumn: typeof import("element-plus/es")["ElTableColumn"];
|
||||||
ElTabPane: typeof import("element-plus/es")["ElTabPane"];
|
|
||||||
ElTabs: typeof import("element-plus/es")["ElTabs"];
|
|
||||||
ElTag: typeof import("element-plus/es")["ElTag"];
|
ElTag: typeof import("element-plus/es")["ElTag"];
|
||||||
ElTooltip: typeof import("element-plus/es")["ElTooltip"];
|
ElTooltip: typeof import("element-plus/es")["ElTooltip"];
|
||||||
ElTree: typeof import("element-plus/es")["ElTree"];
|
ElTree: typeof import("element-plus/es")["ElTree"];
|
||||||
ElTreeSelect: typeof import("element-plus/es")["ElTreeSelect"];
|
ElTreeSelect: typeof import("element-plus/es")["ElTreeSelect"];
|
||||||
ElUpload: typeof import("element-plus/es")["ElUpload"];
|
ElUpload: typeof import("element-plus/es")["ElUpload"];
|
||||||
|
ElWatermark: typeof import("element-plus/es")["ElWatermark"];
|
||||||
FixedThead: typeof import("./../views/demo/table/dynamic-table/components/FixedThead.vue")["default"];
|
FixedThead: typeof import("./../views/demo/table/dynamic-table/components/FixedThead.vue")["default"];
|
||||||
FunnelChart: typeof import("./../views/dashboard/components/FunnelChart.vue")["default"];
|
FunnelChart: typeof import("./../views/dashboard/components/FunnelChart.vue")["default"];
|
||||||
GithubCorner: typeof import("./../components/GithubCorner/index.vue")["default"];
|
GithubCorner: typeof import("./../components/GithubCorner/index.vue")["default"];
|
||||||
Hamburger: typeof import("./../components/Hamburger/index.vue")["default"];
|
Hamburger: typeof import("./../components/Hamburger/index.vue")["default"];
|
||||||
IconSelect: typeof import("./../components/IconSelect/index.vue")["default"];
|
IconSelect: typeof import("./../components/IconSelect/index.vue")["default"];
|
||||||
IEpArrowDown: typeof import("~icons/ep/arrow-down")["default"];
|
|
||||||
IEpCaretBottom: typeof import("~icons/ep/caret-bottom")["default"];
|
IEpCaretBottom: typeof import("~icons/ep/caret-bottom")["default"];
|
||||||
IEpCaretTop: typeof import("~icons/ep/caret-top")["default"];
|
IEpCaretTop: typeof import("~icons/ep/caret-top")["default"];
|
||||||
|
IEpCheck: typeof import("~icons/ep/check")["default"];
|
||||||
IEpClose: typeof import("~icons/ep/close")["default"];
|
IEpClose: typeof import("~icons/ep/close")["default"];
|
||||||
IEpCollection: typeof import("~icons/ep/collection")["default"];
|
IEpCollection: typeof import("~icons/ep/collection")["default"];
|
||||||
IEpDelete: typeof import("~icons/ep/delete")["default"];
|
IEpDelete: typeof import("~icons/ep/delete")["default"];
|
||||||
|
|
@ -75,12 +69,11 @@ declare module "@vue/runtime-core" {
|
||||||
IEpPicture: typeof import("~icons/ep/picture")["default"];
|
IEpPicture: typeof import("~icons/ep/picture")["default"];
|
||||||
IEpPlus: typeof import("~icons/ep/plus")["default"];
|
IEpPlus: typeof import("~icons/ep/plus")["default"];
|
||||||
IEpPosition: typeof import("~icons/ep/position")["default"];
|
IEpPosition: typeof import("~icons/ep/position")["default"];
|
||||||
|
IEpQuestionFilled: typeof import("~icons/ep/question-filled")["default"];
|
||||||
IEpRefresh: typeof import("~icons/ep/refresh")["default"];
|
IEpRefresh: typeof import("~icons/ep/refresh")["default"];
|
||||||
IEpRefreshLeft: typeof import("~icons/ep/refresh-left")["default"];
|
IEpRefreshLeft: typeof import("~icons/ep/refresh-left")["default"];
|
||||||
IEpSearch: typeof import("~icons/ep/search")["default"];
|
IEpSearch: typeof import("~icons/ep/search")["default"];
|
||||||
IEpSetting: typeof import("~icons/ep/setting")["default"];
|
IEpSetting: typeof import("~icons/ep/setting")["default"];
|
||||||
IEpSortDown: typeof import("~icons/ep/sort-down")["default"];
|
|
||||||
IEpSortUp: typeof import("~icons/ep/sort-up")["default"];
|
|
||||||
IEpTop: typeof import("~icons/ep/top")["default"];
|
IEpTop: typeof import("~icons/ep/top")["default"];
|
||||||
IEpUploadFilled: typeof import("~icons/ep/upload-filled")["default"];
|
IEpUploadFilled: typeof import("~icons/ep/upload-filled")["default"];
|
||||||
Item: typeof import("./../layout/components/Sidebar/Item.vue")["default"];
|
Item: typeof import("./../layout/components/Sidebar/Item.vue")["default"];
|
||||||
|
|
@ -105,7 +98,6 @@ declare module "@vue/runtime-core" {
|
||||||
SizeSelect: typeof import("./../components/SizeSelect/index.vue")["default"];
|
SizeSelect: typeof import("./../components/SizeSelect/index.vue")["default"];
|
||||||
SvgIcon: typeof import("./../components/SvgIcon/index.vue")["default"];
|
SvgIcon: typeof import("./../components/SvgIcon/index.vue")["default"];
|
||||||
SwitchRoles: typeof import("./../views/demo/permission/components/SwitchRoles.vue")["default"];
|
SwitchRoles: typeof import("./../views/demo/permission/components/SwitchRoles.vue")["default"];
|
||||||
TagInput: typeof import("./../components/TagInput/index.vue")["default"];
|
|
||||||
TagsView: typeof import("./../layout/components/TagsView/index.vue")["default"];
|
TagsView: typeof import("./../layout/components/TagsView/index.vue")["default"];
|
||||||
TopMenu: typeof import("./../layout/components/Sidebar/TopMenu.vue")["default"];
|
TopMenu: typeof import("./../layout/components/Sidebar/TopMenu.vue")["default"];
|
||||||
UnfixedThead: typeof import("./../views/demo/table/dynamic-table/components/UnfixedThead.vue")["default"];
|
UnfixedThead: typeof import("./../views/demo/table/dynamic-table/components/UnfixedThead.vue")["default"];
|
||||||
|
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
declare global {
|
|
||||||
/**
|
|
||||||
* 分页查询参数
|
|
||||||
*/
|
|
||||||
interface PageQuery {
|
|
||||||
pageNum: number;
|
|
||||||
pageSize: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 分页响应对象
|
|
||||||
*/
|
|
||||||
interface PageResult<T> {
|
|
||||||
/**
|
|
||||||
* 数据列表
|
|
||||||
*/
|
|
||||||
list: T;
|
|
||||||
/**
|
|
||||||
* 数据总数
|
|
||||||
*/
|
|
||||||
total: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 弹窗属性
|
|
||||||
*/
|
|
||||||
interface DialogOption {
|
|
||||||
/**
|
|
||||||
* 弹窗标题
|
|
||||||
*/
|
|
||||||
title?: string;
|
|
||||||
/**
|
|
||||||
* 是否显示
|
|
||||||
*/
|
|
||||||
visible: boolean;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 组件数据源
|
|
||||||
*/
|
|
||||||
interface OptionType {
|
|
||||||
/**
|
|
||||||
* 值
|
|
||||||
*/
|
|
||||||
value: string | number;
|
|
||||||
/**
|
|
||||||
* 文本
|
|
||||||
*/
|
|
||||||
label: string;
|
|
||||||
/**
|
|
||||||
* 子列表
|
|
||||||
*/
|
|
||||||
children?: OptionType[];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export {};
|
|
||||||
|
|
@ -18,10 +18,8 @@
|
||||||
class="z-1 !border-none w-100 !bg-transparent !rounded-4% <sm:w-83"
|
class="z-1 !border-none w-100 !bg-transparent !rounded-4% <sm:w-83"
|
||||||
>
|
>
|
||||||
<div class="text-center relative">
|
<div class="text-center relative">
|
||||||
<h2>{{ defaultSettings.title }}</h2>
|
<h2>{{ title }}</h2>
|
||||||
<el-tag class="ml-2 absolute top-0 right-0">{{
|
<el-tag class="ml-2 absolute top-0 right-0">{{ version }}</el-tag>
|
||||||
defaultSettings.version
|
|
||||||
}}</el-tag>
|
|
||||||
</div>
|
</div>
|
||||||
<el-form
|
<el-form
|
||||||
ref="loginFormRef"
|
ref="loginFormRef"
|
||||||
|
|
@ -147,12 +145,13 @@ import { useAppStore } from "@/store/modules/app";
|
||||||
import { LocationQuery, LocationQueryValue, useRoute } from "vue-router";
|
import { LocationQuery, LocationQueryValue, useRoute } from "vue-router";
|
||||||
import { getCaptchaApi } from "@/api/auth";
|
import { getCaptchaApi } from "@/api/auth";
|
||||||
import { LoginData } from "@/api/auth/types";
|
import { LoginData } from "@/api/auth/types";
|
||||||
import defaultSettings from "@/settings";
|
|
||||||
|
|
||||||
|
const settingsStore = useSettingsStore();
|
||||||
|
|
||||||
|
const { title, version } = settingsStore;
|
||||||
/**
|
/**
|
||||||
* 明亮/暗黑主题切换
|
* 明亮/暗黑主题切换
|
||||||
*/
|
*/
|
||||||
const settingsStore = useSettingsStore();
|
|
||||||
const isDark = ref<boolean>(settingsStore.theme === "dark");
|
const isDark = ref<boolean>(settingsStore.theme === "dark");
|
||||||
const handleThemeChange = (isDark: any) => {
|
const handleThemeChange = (isDark: any) => {
|
||||||
useToggle(isDark);
|
useToggle(isDark);
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,10 @@ const deptFormRef = ref(ElForm);
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const ids = ref<number[]>([]);
|
const ids = ref<number[]>([]);
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = {
|
||||||
|
title: "",
|
||||||
visible: false,
|
visible: false,
|
||||||
});
|
};
|
||||||
|
|
||||||
const queryParams = reactive<DeptQuery>({});
|
const queryParams = reactive<DeptQuery>({});
|
||||||
const deptList = ref<DeptVO[]>();
|
const deptList = ref<DeptVO[]>();
|
||||||
|
|
|
||||||
|
|
@ -53,9 +53,10 @@ const queryParams = reactive<DictQuery>({
|
||||||
|
|
||||||
const dictList = ref<DictPageVO[]>();
|
const dictList = ref<DictPageVO[]>();
|
||||||
|
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = {
|
||||||
|
title: "",
|
||||||
visible: false,
|
visible: false,
|
||||||
});
|
};
|
||||||
|
|
||||||
const formData = reactive<DictForm>({
|
const formData = reactive<DictForm>({
|
||||||
status: 1,
|
status: 1,
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,10 @@ const queryParams = reactive<DictTypeQuery>({
|
||||||
|
|
||||||
const dictTypeList = ref<DictTypePageVO[]>();
|
const dictTypeList = ref<DictTypePageVO[]>();
|
||||||
|
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = {
|
||||||
|
title: "",
|
||||||
visible: false,
|
visible: false,
|
||||||
});
|
};
|
||||||
|
|
||||||
const formData = reactive<DictTypeForm>({
|
const formData = reactive<DictTypeForm>({
|
||||||
status: 1,
|
status: 1,
|
||||||
|
|
@ -148,9 +149,10 @@ function handleDelete(dictTypeId?: number) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const dictDataDialog = reactive<DialogOption>({
|
const dictDataDialog = {
|
||||||
|
title: "",
|
||||||
visible: false,
|
visible: false,
|
||||||
});
|
};
|
||||||
|
|
||||||
const selectedDictType = reactive({ typeCode: "", typeName: "" }); // 当前选中的字典类型
|
const selectedDictType = reactive({ typeCode: "", typeName: "" }); // 当前选中的字典类型
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,10 @@ const queryFormRef = ref(ElForm);
|
||||||
const menuFormRef = ref(ElForm);
|
const menuFormRef = ref(ElForm);
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = {
|
||||||
|
title: "",
|
||||||
visible: false,
|
visible: false,
|
||||||
});
|
};
|
||||||
|
|
||||||
const queryParams = reactive<MenuQuery>({});
|
const queryParams = reactive<MenuQuery>({});
|
||||||
const menuList = ref<MenuVO[]>([]);
|
const menuList = ref<MenuVO[]>([]);
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,10 @@ const queryParams = reactive<RoleQuery>({
|
||||||
|
|
||||||
const roleList = ref<RolePageVO[]>();
|
const roleList = ref<RolePageVO[]>();
|
||||||
|
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = {
|
||||||
|
title: "",
|
||||||
visible: false,
|
visible: false,
|
||||||
});
|
};
|
||||||
|
|
||||||
const formData = reactive<RoleForm>({
|
const formData = reactive<RoleForm>({
|
||||||
sort: 1,
|
sort: 1,
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
"include": [
|
"include": [
|
||||||
"src/**/*.ts",
|
"src/**/*.ts",
|
||||||
"src/**/*.vue",
|
"src/**/*.vue",
|
||||||
"src/types/**/*.d.ts",
|
"types/**/*.d.ts",
|
||||||
"mock/**/*.ts",
|
"mock/**/*.ts",
|
||||||
"vite.config.ts"
|
"vite.config.ts"
|
||||||
],
|
],
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,117 @@
|
||||||
|
/* eslint-disable */
|
||||||
|
/* prettier-ignore */
|
||||||
|
// @ts-nocheck
|
||||||
|
// Generated by unplugin-vue-components
|
||||||
|
// Read more: https://github.com/vuejs/core/pull/3399
|
||||||
|
import '@vue/runtime-core'
|
||||||
|
|
||||||
|
export {};
|
||||||
|
|
||||||
|
declare module "@vue/runtime-core" {
|
||||||
|
export interface GlobalComponents {
|
||||||
|
AppMain: typeof import("./../layout/components/AppMain.vue")["default"];
|
||||||
|
BarChart: typeof import("./../views/dashboard/components/BarChart.vue")["default"];
|
||||||
|
Breadcrumb: typeof import("./../components/Breadcrumb/index.vue")["default"];
|
||||||
|
DeptTree: typeof import("./../views/system/user/components/dept-tree.vue")["default"];
|
||||||
|
Dictionary: typeof import("./../components/Dictionary/index.vue")["default"];
|
||||||
|
DictItem: typeof import("./../views/system/dict/components/dict-item.vue")["default"];
|
||||||
|
ElAlert: typeof import("element-plus/es")["ElAlert"];
|
||||||
|
ElBreadcrumb: typeof import("element-plus/es")["ElBreadcrumb"];
|
||||||
|
ElBreadcrumbItem: typeof import("element-plus/es")["ElBreadcrumbItem"];
|
||||||
|
ElButton: typeof import("element-plus/es")["ElButton"];
|
||||||
|
ElCard: typeof import("element-plus/es")["ElCard"];
|
||||||
|
ElCheckbox: typeof import("element-plus/es")["ElCheckbox"];
|
||||||
|
ElCheckboxGroup: typeof import("element-plus/es")["ElCheckboxGroup"];
|
||||||
|
ElCol: typeof import("element-plus/es")["ElCol"];
|
||||||
|
ElDatePicker: typeof import("element-plus/es")["ElDatePicker"];
|
||||||
|
ElDialog: typeof import("element-plus/es")["ElDialog"];
|
||||||
|
ElDivider: typeof import("element-plus/es")["ElDivider"];
|
||||||
|
ElDropdown: typeof import("element-plus/es")["ElDropdown"];
|
||||||
|
ElDropdownItem: typeof import("element-plus/es")["ElDropdownItem"];
|
||||||
|
ElDropdownMenu: typeof import("element-plus/es")["ElDropdownMenu"];
|
||||||
|
ElForm: typeof import("element-plus/es")["ElForm"];
|
||||||
|
ElFormItem: typeof import("element-plus/es")["ElFormItem"];
|
||||||
|
ElIcon: typeof import("element-plus/es")["ElIcon"];
|
||||||
|
ElImage: typeof import("element-plus/es")["ElImage"];
|
||||||
|
ElInput: typeof import("element-plus/es")["ElInput"];
|
||||||
|
ElInputNumber: typeof import("element-plus/es")["ElInputNumber"];
|
||||||
|
ElLink: typeof import("element-plus/es")["ElLink"];
|
||||||
|
ElMenu: typeof import("element-plus/es")["ElMenu"];
|
||||||
|
ElMenuItem: typeof import("element-plus/es")["ElMenuItem"];
|
||||||
|
ElOption: typeof import("element-plus/es")["ElOption"];
|
||||||
|
ElPagination: typeof import("element-plus/es")["ElPagination"];
|
||||||
|
ElPopover: typeof import("element-plus/es")["ElPopover"];
|
||||||
|
ElRadio: typeof import("element-plus/es")["ElRadio"];
|
||||||
|
ElRadioButton: typeof import("element-plus/es")["ElRadioButton"];
|
||||||
|
ElRadioGroup: typeof import("element-plus/es")["ElRadioGroup"];
|
||||||
|
ElRate: typeof import("element-plus/es")["ElRate"];
|
||||||
|
ElRow: typeof import("element-plus/es")["ElRow"];
|
||||||
|
ElScrollbar: typeof import("element-plus/es")["ElScrollbar"];
|
||||||
|
ElSelect: typeof import("element-plus/es")["ElSelect"];
|
||||||
|
ElSubMenu: typeof import("element-plus/es")["ElSubMenu"];
|
||||||
|
ElSwitch: typeof import("element-plus/es")["ElSwitch"];
|
||||||
|
ElTable: typeof import("element-plus/es")["ElTable"];
|
||||||
|
ElTableColumn: typeof import("element-plus/es")["ElTableColumn"];
|
||||||
|
ElTabPane: typeof import("element-plus/es")["ElTabPane"];
|
||||||
|
ElTabs: typeof import("element-plus/es")["ElTabs"];
|
||||||
|
ElTag: typeof import("element-plus/es")["ElTag"];
|
||||||
|
ElTooltip: typeof import("element-plus/es")["ElTooltip"];
|
||||||
|
ElTree: typeof import("element-plus/es")["ElTree"];
|
||||||
|
ElTreeSelect: typeof import("element-plus/es")["ElTreeSelect"];
|
||||||
|
ElUpload: typeof import("element-plus/es")["ElUpload"];
|
||||||
|
FixedThead: typeof import("./../views/demo/table/dynamic-table/components/FixedThead.vue")["default"];
|
||||||
|
FunnelChart: typeof import("./../views/dashboard/components/FunnelChart.vue")["default"];
|
||||||
|
GithubCorner: typeof import("./../components/GithubCorner/index.vue")["default"];
|
||||||
|
Hamburger: typeof import("./../components/Hamburger/index.vue")["default"];
|
||||||
|
IconSelect: typeof import("./../components/IconSelect/index.vue")["default"];
|
||||||
|
IEpArrowDown: typeof import("~icons/ep/arrow-down")["default"];
|
||||||
|
IEpCaretBottom: typeof import("~icons/ep/caret-bottom")["default"];
|
||||||
|
IEpCaretTop: typeof import("~icons/ep/caret-top")["default"];
|
||||||
|
IEpClose: typeof import("~icons/ep/close")["default"];
|
||||||
|
IEpCollection: typeof import("~icons/ep/collection")["default"];
|
||||||
|
IEpDelete: typeof import("~icons/ep/delete")["default"];
|
||||||
|
IEpDownload: typeof import("~icons/ep/download")["default"];
|
||||||
|
IEpEdit: typeof import("~icons/ep/edit")["default"];
|
||||||
|
IEpPicture: typeof import("~icons/ep/picture")["default"];
|
||||||
|
IEpPlus: typeof import("~icons/ep/plus")["default"];
|
||||||
|
IEpPosition: typeof import("~icons/ep/position")["default"];
|
||||||
|
IEpRefresh: typeof import("~icons/ep/refresh")["default"];
|
||||||
|
IEpRefreshLeft: typeof import("~icons/ep/refresh-left")["default"];
|
||||||
|
IEpSearch: typeof import("~icons/ep/search")["default"];
|
||||||
|
IEpSetting: typeof import("~icons/ep/setting")["default"];
|
||||||
|
IEpSortDown: typeof import("~icons/ep/sort-down")["default"];
|
||||||
|
IEpSortUp: typeof import("~icons/ep/sort-up")["default"];
|
||||||
|
IEpTop: typeof import("~icons/ep/top")["default"];
|
||||||
|
IEpUploadFilled: typeof import("~icons/ep/upload-filled")["default"];
|
||||||
|
Item: typeof import("./../layout/components/Sidebar/Item.vue")["default"];
|
||||||
|
LangSelect: typeof import("./../components/LangSelect/index.vue")["default"];
|
||||||
|
LeftMenu: typeof import("./../layout/components/Sidebar/LeftMenu.vue")["default"];
|
||||||
|
Link: typeof import("./../layout/components/Sidebar/Link.vue")["default"];
|
||||||
|
Logo: typeof import("./../layout/components/Sidebar/Logo.vue")["default"];
|
||||||
|
MultiUpload: typeof import("./../components/Upload/MultiUpload.vue")["default"];
|
||||||
|
NavBar: typeof import("./../layout/components/NavBar/index.vue")["default"];
|
||||||
|
NavRight: typeof import("./../layout/components/NavBar/NavRight.vue")["default"];
|
||||||
|
Pagination: typeof import("./../components/Pagination/index.vue")["default"];
|
||||||
|
PieChart: typeof import("./../views/dashboard/components/PieChart.vue")["default"];
|
||||||
|
RadarChart: typeof import("./../views/dashboard/components/RadarChart.vue")["default"];
|
||||||
|
RightPanel: typeof import("./../components/RightPanel/index.vue")["default"];
|
||||||
|
RouterLink: typeof import("vue-router")["RouterLink"];
|
||||||
|
RouterView: typeof import("vue-router")["RouterView"];
|
||||||
|
ScrollPane: typeof import("./../layout/components/TagsView/ScrollPane.vue")["default"];
|
||||||
|
Settings: typeof import("./../layout/components/Settings/index.vue")["default"];
|
||||||
|
Sidebar: typeof import("./../layout/components/Sidebar/index.vue")["default"];
|
||||||
|
SidebarItem: typeof import("./../layout/components/Sidebar/SidebarItem.vue")["default"];
|
||||||
|
SingleUpload: typeof import("./../components/Upload/SingleUpload.vue")["default"];
|
||||||
|
SizeSelect: typeof import("./../components/SizeSelect/index.vue")["default"];
|
||||||
|
SvgIcon: typeof import("./../components/SvgIcon/index.vue")["default"];
|
||||||
|
SwitchRoles: typeof import("./../views/demo/permission/components/SwitchRoles.vue")["default"];
|
||||||
|
TagInput: typeof import("./../components/TagInput/index.vue")["default"];
|
||||||
|
TagsView: typeof import("./../layout/components/TagsView/index.vue")["default"];
|
||||||
|
TopMenu: typeof import("./../layout/components/Sidebar/TopMenu.vue")["default"];
|
||||||
|
UnfixedThead: typeof import("./../views/demo/table/dynamic-table/components/UnfixedThead.vue")["default"];
|
||||||
|
WangEditor: typeof import("./../components/WangEditor/index.vue")["default"];
|
||||||
|
}
|
||||||
|
export interface ComponentCustomProperties {
|
||||||
|
vLoading: typeof import("element-plus/es")["ElLoadingDirective"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,15 +7,14 @@ declare module "*.vue" {
|
||||||
export default component;
|
export default component;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 环境变量 TypeScript的智能提示
|
|
||||||
interface ImportMetaEnv {
|
interface ImportMetaEnv {
|
||||||
VITE_APP_TITLE: string;
|
/** 应用端口 */
|
||||||
VITE_APP_PORT: string;
|
VITE_APP_PORT: string;
|
||||||
|
/** API 基础路径 */
|
||||||
VITE_APP_BASE_API: string;
|
VITE_APP_BASE_API: string;
|
||||||
|
VITE_APP_API_URL: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ImportMeta {
|
interface ImportMeta {
|
||||||
readonly env: ImportMetaEnv;
|
readonly env: ImportMetaEnv;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module "lodash-es";
|
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
declare global {
|
||||||
|
/**
|
||||||
|
* 系统名称、版本、依赖、构建时间的类型提示
|
||||||
|
*/
|
||||||
|
const __APP_INFO__: {
|
||||||
|
pkg: {
|
||||||
|
name: string;
|
||||||
|
version: string;
|
||||||
|
dependencies: Recordable<string>;
|
||||||
|
devDependencies: Recordable<string>;
|
||||||
|
};
|
||||||
|
lastBuildTime: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询参数
|
||||||
|
*/
|
||||||
|
interface PageQuery {
|
||||||
|
pageNum: number;
|
||||||
|
pageSize: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页响应对象
|
||||||
|
*/
|
||||||
|
interface PageResult<T> {
|
||||||
|
/** 数据列表 */
|
||||||
|
list: T;
|
||||||
|
/** 总数 */
|
||||||
|
total: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页签对象
|
||||||
|
*/
|
||||||
|
interface TagView {
|
||||||
|
/** 页签名称 */
|
||||||
|
name: string;
|
||||||
|
/** 页签标题 */
|
||||||
|
title: string;
|
||||||
|
/** 页签路由路径 */
|
||||||
|
path: string;
|
||||||
|
/** 页签路由完整路径 */
|
||||||
|
fullPath: string;
|
||||||
|
/** 页签图标 */
|
||||||
|
icon?: string;
|
||||||
|
/** 是否固定页签 */
|
||||||
|
affix?: boolean;
|
||||||
|
/** 是否开启缓存 */
|
||||||
|
keepAlive?: boolean;
|
||||||
|
/** 路由查询参数 */
|
||||||
|
query?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统设置
|
||||||
|
*/
|
||||||
|
interface AppSettings {
|
||||||
|
/** 系统标题 */
|
||||||
|
title: string;
|
||||||
|
/** 系统版本 */
|
||||||
|
version: string;
|
||||||
|
/** 是否显示设置 */
|
||||||
|
showSettings: boolean;
|
||||||
|
/** 是否固定头部 */
|
||||||
|
fixedHeader: boolean;
|
||||||
|
/** 是否显示多标签导航 */
|
||||||
|
tagsView: boolean;
|
||||||
|
/** 是否显示侧边栏Logo */
|
||||||
|
sidebarLogo: boolean;
|
||||||
|
/** 导航栏布局(left|top|mix) */
|
||||||
|
layout: string;
|
||||||
|
/** 主题颜色 */
|
||||||
|
themeColor: string;
|
||||||
|
/** 主题模式(dark|light) */
|
||||||
|
theme: string;
|
||||||
|
/** 布局大小(default |large |small) */
|
||||||
|
size: string;
|
||||||
|
/** 语言( zh-cn| en) */
|
||||||
|
language: string;
|
||||||
|
/** 水印配置 */
|
||||||
|
watermark: {
|
||||||
|
/** 是否开启水印 */
|
||||||
|
enabled: boolean;
|
||||||
|
/** 水印内容 */
|
||||||
|
content: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组件数据源
|
||||||
|
*/
|
||||||
|
interface OptionType {
|
||||||
|
/** 值 */
|
||||||
|
value: string | number;
|
||||||
|
/** 文本 */
|
||||||
|
label: string;
|
||||||
|
/** 子列表 */
|
||||||
|
children?: OptionType[];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export {};
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
import "vue-router";
|
||||||
|
|
||||||
|
declare module "vue-router" {
|
||||||
|
// https://router.vuejs.org/zh/guide/advanced/meta.html#typescript
|
||||||
|
// 可以通过扩展 RouteMeta 接口来输入 meta 字段
|
||||||
|
interface RouteMeta {
|
||||||
|
/** 菜单名称 */
|
||||||
|
title: string;
|
||||||
|
/** 菜单图标 */
|
||||||
|
icon?: string;
|
||||||
|
/** 菜单是否隐藏 */
|
||||||
|
hidden?: boolean;
|
||||||
|
/** 是否固定页签 */
|
||||||
|
affix?: boolean;
|
||||||
|
/** 是否缓存页面 */
|
||||||
|
keepAlive?: boolean;
|
||||||
|
/** 是否在面包屑上隐藏 */
|
||||||
|
breadcrumb?: boolean;
|
||||||
|
/** 拥有菜单权限的角色编码集合 */
|
||||||
|
roles?: string[];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import vue from "@vitejs/plugin-vue";
|
import vue from "@vitejs/plugin-vue";
|
||||||
|
|
||||||
import { UserConfig, ConfigEnv, loadEnv, defineConfig } from "vite";
|
import { UserConfig, ConfigEnv, loadEnv, defineConfig } from "vite";
|
||||||
|
|
||||||
import AutoImport from "unplugin-auto-import/vite";
|
import AutoImport from "unplugin-auto-import/vite";
|
||||||
|
|
@ -12,14 +11,13 @@ import IconsResolver from "unplugin-icons/resolver";
|
||||||
import { createSvgIconsPlugin } from "vite-plugin-svg-icons";
|
import { createSvgIconsPlugin } from "vite-plugin-svg-icons";
|
||||||
|
|
||||||
import { viteMockServe } from "vite-plugin-mock";
|
import { viteMockServe } from "vite-plugin-mock";
|
||||||
|
|
||||||
import vueJsx from "@vitejs/plugin-vue-jsx";
|
import vueJsx from "@vitejs/plugin-vue-jsx";
|
||||||
|
|
||||||
import UnoCSS from "unocss/vite";
|
import UnoCSS from "unocss/vite";
|
||||||
import path from "path";
|
import { resolve } from "path";
|
||||||
|
|
||||||
const pathSrc = path.resolve(__dirname, "src");
|
const pathSrc = resolve(__dirname, "src");
|
||||||
// 参考Vite官方: https://cn.vitejs.dev/config
|
// https://cn.vitejs.dev/config
|
||||||
export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
|
export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
|
||||||
const env = loadEnv(mode, process.cwd());
|
const env = loadEnv(mode, process.cwd());
|
||||||
return {
|
return {
|
||||||
|
|
@ -53,17 +51,13 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
|
||||||
* http://localhost:3000/dev-api/users (F12可见请求路径) => http://localhost:8989/users (实际请求后端 API 路径)
|
* http://localhost:3000/dev-api/users (F12可见请求路径) => http://localhost:8989/users (实际请求后端 API 路径)
|
||||||
*
|
*
|
||||||
* env.VITE_APP_BASE_API: /dev-api
|
* env.VITE_APP_BASE_API: /dev-api
|
||||||
* env.VITE_APP_TARGET_URL: http://localhost:8989
|
* env.VITE_APP_API_URL: http://localhost:8989
|
||||||
* env.VITE_APP_TARGET_BASE_API: ""
|
|
||||||
*/
|
*/
|
||||||
[env.VITE_APP_BASE_API]: {
|
[env.VITE_APP_BASE_API]: {
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
target: env.VITE_APP_TARGET_URL,
|
target: env.VITE_APP_API_URL,
|
||||||
rewrite: (path) =>
|
rewrite: (path) =>
|
||||||
path.replace(
|
path.replace(new RegExp("^" + env.VITE_APP_BASE_API), ""),
|
||||||
new RegExp("^" + env.VITE_APP_BASE_API),
|
|
||||||
env.VITE_APP_TARGET_BASE_API
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -86,8 +80,8 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
|
||||||
},
|
},
|
||||||
vueTemplate: true,
|
vueTemplate: true,
|
||||||
// 配置文件生成位置(false:关闭自动生成)
|
// 配置文件生成位置(false:关闭自动生成)
|
||||||
dts: false,
|
//dts: false,
|
||||||
// dts: "src/types/auto-imports.d.ts",
|
dts: "src/types/auto-imports.d.ts",
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Components({
|
Components({
|
||||||
|
|
@ -100,8 +94,8 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
|
||||||
// 指定自定义组件位置(默认:src/components)
|
// 指定自定义组件位置(默认:src/components)
|
||||||
dirs: ["src/components", "src/**/components"],
|
dirs: ["src/components", "src/**/components"],
|
||||||
// 配置文件位置 (false:关闭自动生成)
|
// 配置文件位置 (false:关闭自动生成)
|
||||||
dts: false,
|
// dts: false,
|
||||||
// dts: "src/types/components.d.ts",
|
dts: "src/types/components.d.ts",
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Icons({
|
Icons({
|
||||||
|
|
@ -109,7 +103,7 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
|
||||||
}),
|
}),
|
||||||
createSvgIconsPlugin({
|
createSvgIconsPlugin({
|
||||||
// 指定需要缓存的图标文件夹
|
// 指定需要缓存的图标文件夹
|
||||||
iconDirs: [path.resolve(pathSrc, "assets/icons")],
|
iconDirs: [resolve(pathSrc, "assets/icons")],
|
||||||
// 指定symbolId格式
|
// 指定symbolId格式
|
||||||
symbolId: "icon-[dir]-[name]",
|
symbolId: "icon-[dir]-[name]",
|
||||||
}),
|
}),
|
||||||
|
|
@ -173,6 +167,7 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
|
||||||
"element-plus/es/components/notification/style/css",
|
"element-plus/es/components/notification/style/css",
|
||||||
"element-plus/es/components/image/style/css",
|
"element-plus/es/components/image/style/css",
|
||||||
"element-plus/es/components/statistic/style/css",
|
"element-plus/es/components/statistic/style/css",
|
||||||
|
"element-plus/es/components/watermark/style/css",
|
||||||
"@vueuse/core",
|
"@vueuse/core",
|
||||||
"sortablejs",
|
"sortablejs",
|
||||||
"path-to-regexp",
|
"path-to-regexp",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue