8 Commits

Author SHA1 Message Date
lyt
ccca4cd355 'admin-23.03.10:发布v2.4.31版本,更新内容查看CHANGELOG.md' 2023-03-10 22:03:13 +08:00
lyt
a894768c56 'admin-23.02.27:优化分栏布局' 2023-02-27 23:22:53 +08:00
496594578a 'admin-23.02.26:群满,请加交流群5,556254895'
Signed-off-by: lyt-Top <1105290566@qq.com>
2023-02-26 02:54:01 +00:00
lyt
1cbc0f1b4e 'admin-23.02.22:发布v2.4.3版本,感谢赞助商.驰骋工作流引擎-表单引擎-低代码开发平台' 2023-02-22 22:57:15 +08:00
bf9fce206a !44 tagsViewName正则匹配错误,匹配到含en单词
Merge pull request !44 from tony星/正则
2023-02-22 06:08:17 +00:00
9195d8367f !45 fix地址栏出现false问题
Merge pull request !45 from 随心/master
2023-02-22 06:08:05 +00:00
1b3600f394 fix地址栏出现false问题 2023-01-29 09:30:23 +08:00
16823b2ef7 update src/utils/other.ts.
Signed-off-by: tony星 <7762581+tony_tong_xin@user.noreply.gitee.com>
2023-01-09 12:22:42 +00:00
31 changed files with 966 additions and 802 deletions

View File

@ -1,5 +1,5 @@
# 本地环境
ENV = 'development'
ENV = development
# 本地环境接口地址
VITE_API_URL = 'http://localhost:8888/'
VITE_API_URL = http://localhost:8888/

View File

@ -1,5 +1,5 @@
# 线上环境
ENV = 'production'
ENV = production
# 线上环境接口地址
VITE_API_URL = 'https://lyt-top.gitee.io/vue-next-admin-preview/'
VITE_API_URL = https://lyt-top.gitee.io/vue-next-admin-preview/

View File

@ -2,6 +2,34 @@
🎉🎉🔥 `vue-next-admin` 基于 vue3.x 、Typescript、vite、Element plus 等适配手机、平板、pc 的后台开源免费模板库vue2.x 请切换 vue-prev-admin 分支)
## 2.4.31
`2023.03.10`
- 🌟 更新 依赖更新最新版本
- 🐞 修复 顶栏背景渐变设置不生效
- 🐞 修复 顶栏背景渐变、菜单背景渐变时,深色主题不生效
- 🐞 修复 顶栏搜索框移动端显示问题
- 🎯 优化 `main.ts`,相关 issues [#I6KNFH](https://gitee.com/lyt-top/vue-next-admin/issues/I6KNFH)、[#I6JRH6](https://gitee.com/lyt-top/vue-next-admin/issues/I6JRH6)
- 🎯 优化 菜单横向模式显示horizontal
- 🎯 优化 分栏布局,[希望分栏布局做一下优化,在没有二级菜单的时候,直接全屏展示一级菜单链接](https://gitee.com/lyt-top/vue-next-admin/issues/I6HW7H),感谢[@jiuping](https://gitee.com/jiuping)`tagsview` 点击时处理 `收起/展开` 菜单
## 2.4.3
`2023.02.22`
🚩🚩🚩 感谢 [驰骋工作流引擎-表单引擎-低代码开发平台](http://www.ccflow.org/) 赞助商的赞助。驰骋公司为社会提供流程引擎+表单引擎+低代码开发平台一体的开源软件解决方案,欢迎广大开发者前去体验!
- 🌟 更新 依赖更新最新版本
- 🎉 新增 赞助商组件(`/src/layout/sponsors`[项目目录结构查看](https://lyt-top.gitee.io/vue-next-admin-doc-preview/config/)
- 🐞 修复 [过滤筛选组件展开点击不了](https://gitee.com/lyt-top/vue-next-admin/issues/I688WG)
- 🐞 修复 [设置锁屏时间时直接白屏了不能恢复,除非删除主题配置才会重新加载](https://gitee.com/lyt-top/vue-next-admin/issues/I6AF8P),感谢[@baizunxian](https://gitee.com/xb_xiaobai)
- 🐞 修复 `分栏布局` 地址栏输入不存在的路由报错问题
- 🎨 合并 [!44 tagsViewName 正则匹配错误,匹配到含 en 单词](https://gitee.com/lyt-top/vue-next-admin/pulls/44/files),感谢[@tony 星](https://gitee.com/tony_tong_xin)
- 🎨 合并 [!45 fix 地址栏出现 false 问题](https://gitee.com/lyt-top/vue-next-admin/pulls/45),感谢[@随心](https://gitee.com/jiangqiang1996)
- 🎯 优化 `/src/utils/storage``key` 编写成 `${__NEXT_NAME__}:${key}`,防止部署多套系统到同一域名不同目录时,变量共用的问题(`__NEXT_NAME__``package.json` 中的 `name`
- 🎯 优化 watermark 单词拼写错误
## 2.4.21
`2022.12.12`

View File

@ -1,25 +1,31 @@
<div align="center">
<img src="https://img-blog.csdnimg.cn/9efd5420327a46b7bd6d93524a97229d.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbHl0LXRvcA==,size_14,color_FFFFFF,t_70,g_se,x_16">
<p align="center">
<a href="https://v3.vuejs.org/" target="_blank">
<img src="https://img.shields.io/badge/vue.js-vue3.x-green" alt="vue">
</a>
<a href="https://element-plus.gitee.io/#/zh-CN/component/changelog" target="_blank">
<img src="https://img.shields.io/badge/element--plus-%3E1.0.0-blue" alt="element plus">
</a>
<a href="https://v3.vuejs.org/" target="_blank">
<img src="https://img.shields.io/badge/vue.js-vue3.x-green" alt="vue">
</a>
<a href="https://element-plus.gitee.io/#/zh-CN/component/changelog" target="_blank">
<img src="https://img.shields.io/badge/element--plus-%3E1.0.0-blue" alt="element plus">
</a>
<a href="https://www.tslang.cn/" target="_blank">
<img src="https://img.shields.io/badge/typescript-%3E4.0.0-blue" alt="typescript">
</a>
<img src="https://img.shields.io/badge/typescript-%3E4.0.0-blue" alt="typescript">
</a>
<a href="https://vitejs.dev/" target="_blank">
<img src="https://img.shields.io/badge/vite-%3E2.0.0-yellow" alt="vite">
<img src="https://img.shields.io/badge/vite-%3E2.0.0-yellow" alt="vite">
</a>
<a href="https://gitee.com/lyt-top/vue-next-admin/blob/master/LICENSE" target="_blank">
<img src="https://img.shields.io/badge/license-MIT-success" alt="license">
<img src="https://img.shields.io/badge/license-MIT-success" alt="license">
</a>
</p>
<p>&nbsp;</p>
</div>
#### 💝 长期赞助商
<a href="http://www.ccflow.org/" target="_blank">
<img src="./src/assets/ccflowRightNextAdmin.png" width="50%" height="70px">
</a>
#### 🌈 介绍
基于 vue3.x + CompositionAPI setup 语法糖 + typescript + vite + element plus + vue-router-next + pinia 技术适配手机、平板、pc 的后台开源免费模板,希望减少工作量,帮助大家实现快速开发。
@ -28,6 +34,7 @@
- vue3.x 版本预览vue-next-admin<a href="https://lyt-top.gitee.io/vue-next-admin-preview/#/login" target="_blank">https://lyt-top.gitee.io/vue-next-admin-preview/#/login</a>
- vue2.x 版本预览vue-prev-admin<a href="https://lyt-top.gitee.io/vue-prev-admin-preview/#/login" target="_blank">https://lyt-top.gitee.io/vue-prev-admin-preview/#/login</a>
- vue3.x + uni-app 商城 H5vue-next-admin-shop<a href="https://lyt-top.gitee.io/vue-next-admin-shop-preview" target="_blank">https://lyt-top.gitee.io/vue-next-admin-shop-preview</a>
#### 💒 代码仓库
@ -76,25 +83,11 @@ cnpm run build
#### 💯 学习交流加 QQ 群
> 若加群了没同意一般秒过那就是群满了500 人群请换一个群试试。群会定期清理半年6 个月)未发言的群友,资源有限,请谅解。建议勿加多群,可能会误伤!微信群由于只有 `7天有效` 就不放这里了。
> 1 - 4 交流群已满,请加 vue-next-admin 交流群 5
- 1 群:<a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=RdUY97Vx0T0vZ_1OOu-X1yFNkWgDwbjC&jump_from=webapi">665452019</a>
- 2 群:<a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=zVfy3gNy7pNWVK3kMduDzwU369PZg2fw&jump_from=webapi">766356862</a>
- 3 群:<a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=02EWb5P2JkP-8iwzaDadgFdxA0HSHPpn&jump_from=webapi">795345435</a>
- 4 群:<a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=0gTFO04WwkeZZ6R4lju6gucbeXHK-wNd&jump_from=webapi">736626228</a>
群号556254895
<a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=RdUY97Vx0T0vZ_1OOu-X1yFNkWgDwbjC&jump_from=webapi">
<img src="https://img-blog.csdnimg.cn/35e00f12a3fe4820892ec630ca72f15f.png" width="220" height="220" alt="vue-next-admin 讨论群1" title="vue-next-admin 讨论群1"/>
</a>
<a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=zVfy3gNy7pNWVK3kMduDzwU369PZg2fw&jump_from=webapi">
<img src="https://img-blog.csdnimg.cn/5f1b548abd9f434eb41edde31d1c1fa9.png" width="220" height="220" alt="vue-next-admin 讨论群2" title="vue-next-admin 讨论群2"/>
</a>
<a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=02EWb5P2JkP-8iwzaDadgFdxA0HSHPpn&jump_from=webapi">
<img src="https://img-blog.csdnimg.cn/70c8a012dd304246bddeac2184c4ab3a.png" width="220" height="220" alt="vue-next-admin 讨论群3" title="vue-next-admin 讨论群3"/>
</a>
<a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=0gTFO04WwkeZZ6R4lju6gucbeXHK-wNd&jump_from=webapi">
<img src="https://img-blog.csdnimg.cn/e5c9704eed1342bc9d9e74b37203402d.png" width="220" height="220" alt="vue-next-admin 讨论群4" title="vue-next-admin 讨论群4"/>
</a>
其它交流群请查看文档首页 [vueNextAdmin 解疑问](https://lyt-top.gitee.io/vue-next-admin-doc-preview/)
#### 💒 集成后端

1315
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "vue-next-admin",
"version": "2.4.21",
"version": "2.4.31",
"description": "vue3 vite next admin template",
"author": "lyt_20201208",
"license": "MIT",
@ -10,48 +10,48 @@
"lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue src/"
},
"dependencies": {
"@element-plus/icons-vue": "^2.0.10",
"@element-plus/icons-vue": "^2.1.0",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.12",
"axios": "^1.2.1",
"countup.js": "^2.3.2",
"axios": "^1.3.4",
"countup.js": "^2.5.0",
"cropperjs": "^1.5.13",
"echarts": "^5.4.1",
"echarts-gl": "^2.0.9",
"echarts-wordcloud": "^2.1.0",
"element-plus": "^2.2.26",
"element-plus": "^2.2.36",
"js-cookie": "^3.0.1",
"js-table2excel": "^1.0.3",
"jsplumb": "^2.15.6",
"mitt": "^3.0.0",
"nprogress": "^0.2.0",
"pinia": "^2.0.28",
"pinia": "^2.0.33",
"print-js": "^1.6.0",
"qrcodejs2-fixes": "^0.0.2",
"qs": "^6.11.0",
"qs": "^6.11.1",
"screenfull": "^6.0.2",
"sortablejs": "^1.15.0",
"splitpanes": "^3.1.5",
"vue": "^3.2.45",
"vue": "^3.2.47",
"vue-clipboard3": "^2.0.0",
"vue-grid-layout": "^3.0.0-beta1",
"vue-i18n": "^9.2.2",
"vue-router": "^4.1.6"
},
"devDependencies": {
"@types/node": "^18.11.13",
"@types/node": "^18.15.0",
"@types/nprogress": "^0.2.0",
"@types/sortablejs": "^1.15.0",
"@typescript-eslint/eslint-plugin": "^5.46.0",
"@typescript-eslint/parser": "^5.46.0",
"@typescript-eslint/eslint-plugin": "^5.54.1",
"@typescript-eslint/parser": "^5.54.1",
"@vitejs/plugin-vue": "^4.0.0",
"@vue/compiler-sfc": "^3.2.45",
"eslint": "^8.29.0",
"eslint-plugin-vue": "^9.8.0",
"prettier": "^2.8.1",
"sass": "^1.56.2",
"typescript": "^4.9.4",
"vite": "^4.0.0",
"@vue/compiler-sfc": "^3.2.47",
"eslint": "^8.35.0",
"eslint-plugin-vue": "^9.9.0",
"prettier": "^2.8.4",
"sass": "^1.58.3",
"typescript": "^4.9.5",
"vite": "^4.1.4",
"vite-plugin-vue-setup-extend": "^0.4.0",
"vue-eslint-parser": "^9.1.0"
},

View File

@ -1,10 +1,11 @@
<template>
<el-config-provider :size="getGlobalComponentSize" :locale="getGlobalI18n">
<router-view v-show="themeConfig.lockScreenTime > 1" />
<router-view v-show="setLockScreen" />
<LockScreen v-if="themeConfig.isLockScreen" />
<Setings ref="setingsRef" v-show="themeConfig.lockScreenTime > 1" />
<Setings ref="setingsRef" v-show="setLockScreen" />
<CloseFull v-if="!themeConfig.isLockScreen" />
<Upgrade v-if="getVersion" />
<Sponsors />
</el-config-provider>
</template>
@ -25,6 +26,7 @@ const LockScreen = defineAsyncComponent(() => import('/@/layout/lockScreen/index
const Setings = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/setings.vue'));
const CloseFull = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/closeFull.vue'));
const Upgrade = defineAsyncComponent(() => import('/@/layout/upgrade/index.vue'));
const Sponsors = defineAsyncComponent(() => import('/@/layout/sponsors/index.vue'));
// 定义变量内容
const { messages, locale } = useI18n();
@ -34,12 +36,18 @@ const stores = useTagsViewRoutes();
const storesThemeConfig = useThemeConfig();
const { themeConfig } = storeToRefs(storesThemeConfig);
// 设置锁屏时组件显示隐藏
const setLockScreen = computed(() => {
// 防止锁屏后,刷新出现不相关界面
// https://gitee.com/lyt-top/vue-next-admin/issues/I6AF8P
return themeConfig.value.isLockScreen ? themeConfig.value.lockScreenTime > 1 : themeConfig.value.lockScreenTime >= 0;
});
// 获取版本号
const getVersion = computed(() => {
let isVersion = false;
if (route.path !== '/login') {
// @ts-ignore
if ((Local.get('version') && Local.get('version') !== __VERSION__) || !Local.get('version')) isVersion = true;
if ((Local.get('version') && Local.get('version') !== __NEXT_VERSION__) || !Local.get('version')) isVersion = true;
}
return isVersion;
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

View File

@ -107,7 +107,8 @@ const onAsideEnterLeave = (bool: Boolean) => {
let { layout } = themeConfig.value;
if (layout !== 'columns') return false;
if (!bool) mittBus.emit('restoreDefault');
stores.setColumnsMenuHover(bool);
// 开启 `分栏菜单鼠标悬停预加载` 才设置,防止 columnsAside.vue 监听 pinia.state
if (themeConfig.value.isColumnsMenuHoverPreload) stores.setColumnsMenuHover(bool);
};
// 页面加载前
onBeforeMount(() => {
@ -118,6 +119,7 @@ onBeforeMount(() => {
mittBus.on('setSendColumnsChildren', (res: MittMenu) => {
state.menuList = res.children;
});
// 开启经典布局分割菜单时,设置菜单数据
mittBus.on('setSendClassicChildren', (res: MittMenu) => {
let { layout, isClassicSplitMenu } = themeConfig.value;
if (layout === 'classic' && isClassicSplitMenu) {
@ -125,9 +127,11 @@ onBeforeMount(() => {
state.menuList = res.children;
}
});
// 开启经典布局分割菜单时,重新处理菜单数据
mittBus.on('getBreadcrumbIndexSetFilterRoutes', () => {
setFilterRoutes();
});
// 监听窗口大小改变时(适配移动端)
mittBus.on('layoutMobileResize', (res: LayoutMobileResize) => {
initMenuFixed(res.clientWidth);
closeLayoutAsideMobileMode();

View File

@ -5,7 +5,7 @@
<li
v-for="(v, k) in state.columnsAsideList"
:key="k"
@click="onColumnsAsideMenuClick(v, k)"
@click="onColumnsAsideMenuClick(v)"
@mouseenter="onColumnsAsideMenuMouseenter(v, k)"
:ref="
(el) => {
@ -74,15 +74,19 @@ const state = reactive<ColumnsAsideState>({
// 设置菜单高亮位置移动
const setColumnsAsideMove = (k: number) => {
if (k === undefined) return false;
state.liIndex = k;
columnsAsideActiveRef.value.style.top = `${columnsAsideOffsetTopRefs.value[k].offsetTop + state.difference}px`;
};
// 菜单高亮点击事件
const onColumnsAsideMenuClick = (v: RouteItem, k: number) => {
setColumnsAsideMove(k);
const onColumnsAsideMenuClick = async (v: RouteItem) => {
let { path, redirect } = v;
if (redirect) router.push(redirect);
else router.push(path);
// 一个路由设置自动收起菜单
// https://gitee.com/lyt-top/vue-next-admin/issues/I6HW7H
if (!v.children) themeConfig.value.isCollapse = true;
else if (v.children.length > 1) themeConfig.value.isCollapse = false;
};
// 鼠标移入时,显示当前的子级菜单
const onColumnsAsideMenuMouseenter = (v: RouteRecordRaw, k: number) => {
@ -97,6 +101,7 @@ const onColumnsAsideMenuMouseenter = (v: RouteRecordRaw, k: number) => {
};
// 鼠标移走时,显示原来的子级菜单
const onColumnsAsideMenuMouseleave = async () => {
if (!themeConfig.value.isColumnsMenuHoverPreload) return false;
await stores.setColumnsNavHover(false);
// 添加延时器,防止拿到的 store.state.routesList 值不是最新的
setTimeout(() => {
@ -115,6 +120,9 @@ const setFilterRoutes = () => {
const resData: MittMenu = setSendChildren(route.path);
if (Object.keys(resData).length <= 0) return false;
onColumnsAsideDown(resData.item?.k);
// 刷新时,初始化一个路由设置自动收起菜单
// https://gitee.com/lyt-top/vue-next-admin/issues/I6HW7H
resData.children.length <= 1 ? (themeConfig.value.isCollapse = true) : (themeConfig.value.isCollapse = false);
mittBus.emit('setSendColumnsChildren', resData);
};
// 传送当前子级数据到菜单中
@ -198,7 +206,8 @@ watch(
background: var(--next-bg-columnsMenuBar);
ul {
position: relative;
.layout-columns-active {
.layout-columns-active,
.layout-columns-active a {
color: var(--next-bg-columnsMenuBarColor) !important;
transition: 0.3s ease-in-out;
}

View File

@ -43,7 +43,7 @@ const initScrollBarHeight = () => {
setTimeout(() => {
updateScrollbar();
// '!' not null 断言操作符,不执行运行时检查
layoutMainRef.value!.layoutMainScrollbarRef.wrapRef.scrollTop = 0;
if (layoutMainRef.value) layoutMainRef.value!.layoutMainScrollbarRef.wrapRef.scrollTop = 0;
}, 500);
});
};

View File

@ -35,7 +35,7 @@ const updateScrollbar = () => {
// 更新父级 scrollbar
layoutScrollbarRef.value.update();
// 更新子级 scrollbar
layoutMainRef.value!.layoutMainScrollbarRef.update();
layoutMainRef.value && layoutMainRef.value!.layoutMainScrollbarRef.update();
};
// 重置滚动条高度,由于组件是异步引入的
const initScrollBarHeight = () => {

View File

@ -107,6 +107,7 @@ defineExpose({
display: none;
}
.el-dialog__footer {
width: 100%;
position: absolute;
left: 50%;
transform: translateX(-50%);

View File

@ -438,7 +438,7 @@ import { useThemeConfig } from '/@/stores/themeConfig';
import { useChangeColor } from '/@/utils/theme';
import { verifyAndSpace } from '/@/utils/toolsValidate';
import { Local } from '/@/utils/storage';
import Watermark from '/@/utils/wartermark';
import Watermark from '/@/utils/watermark';
import commonFunction from '/@/utils/commonFunction';
import other from '/@/utils/other';
import mittBus from '/@/utils/mitt';
@ -494,14 +494,16 @@ const onColumnsMenuBarGradualChange = () => {
};
// 2、菜单 / 顶栏 --> 背景渐变函数
const setGraduaFun = (el: string, bool: boolean, color: string) => {
setTimeout(() => {
let els = document.querySelector(el);
if (!els) return false;
document.documentElement.style.setProperty('--el-menu-bg-color', document.documentElement.style.getPropertyValue('--next-bg-menuBar'));
if (bool) els.setAttribute('style', `background:linear-gradient(to bottom left , ${color}, ${getLightColor(color, 0.6)}) !important;`);
else els.setAttribute('style', ``);
setLocalThemeConfig();
}, 200);
nextTick(() => {
setTimeout(() => {
let els = document.querySelector(el);
if (!els) return false;
document.documentElement.style.setProperty('--el-menu-bg-color', document.documentElement.style.getPropertyValue('--next-bg-menuBar'));
if (bool) els.setAttribute('style', `background:linear-gradient(to bottom , ${color}, ${getLightColor(color, 0.5)})`);
else els.setAttribute('style', ``);
setLocalThemeConfig();
}, 300);
});
};
// 2、分栏设置 ->
const onColumnsMenuHoverPreloadChange = () => {
@ -632,7 +634,7 @@ const onResetConfigClick = () => {
Local.clear();
window.location.reload();
// @ts-ignore
Local.set('version', __VERSION__);
Local.set('version', __NEXT_VERSION__);
};
// 初始化菜单样式等
const initSetStyle = () => {

View File

@ -56,6 +56,7 @@ import pinia from '/@/stores/index';
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
import { useThemeConfig } from '/@/stores/themeConfig';
import { useKeepALiveNames } from '/@/stores/keepAliveNames';
import { useRoutesList } from '/@/stores/routesList';
import { Session } from '/@/utils/storage';
import { isObjectValueEqual } from '/@/utils/arrayOperation';
import other from '/@/utils/other';
@ -72,8 +73,10 @@ const tagsUlRef = ref();
const stores = useTagsViewRoutes();
const storesThemeConfig = useThemeConfig();
const storesTagsViewRoutes = useTagsViewRoutes();
const storesRoutesList = useRoutesList();
const { themeConfig } = storeToRefs(storesThemeConfig);
const { tagsViewRoutes } = storeToRefs(storesTagsViewRoutes);
const { routesList } = storeToRefs(storesRoutesList);
const storesKeepALiveNames = useKeepALiveNames();
const route = useRoute();
const router = useRouter();
@ -382,6 +385,11 @@ const onMousedownMenu = (v: RouteItem, e: MouseEvent) => {
const onTagsClick = (v: RouteItem, k: number) => {
state.tagsRefsIndex = k;
router.push(v);
// 分栏布局时,收起/展开菜单
if (getThemeConfig.value.layout === 'columns') {
const item: RouteItem = routesList.value.find((r: RouteItem) => r.path.indexOf(`/${v.path.split('/')[1]}`) > -1);
!item.children ? (getThemeConfig.value.isCollapse = true) : (getThemeConfig.value.isCollapse = false);
}
};
// 处理 url地址栏链接有参数时tagsview 右键菜单刷新功能失效问题,感谢 @ZzZz-RIPPER、@dejavuuuuu
// https://gitee.com/lyt-top/vue-next-admin/issues/I5K3YO

View File

@ -1,37 +1,35 @@
<template>
<div class="el-menu-horizontal-warp">
<el-scrollbar @wheel.native.prevent="onElMenuHorizontalScroll" ref="elMenuHorizontalScrollRef">
<el-menu router :default-active="state.defaultActive" :ellipsis="false" background-color="transparent" mode="horizontal">
<template v-for="val in menuLists">
<el-sub-menu :index="val.path" v-if="val.children && val.children.length > 0" :key="val.path">
<template #title>
<el-menu router :default-active="state.defaultActive" background-color="transparent" mode="horizontal">
<template v-for="val in menuLists">
<el-sub-menu :index="val.path" v-if="val.children && val.children.length > 0" :key="val.path">
<template #title>
<SvgIcon :name="val.meta.icon" />
<span>{{ $t(val.meta.title) }}</span>
</template>
<SubItem :chil="val.children" />
</el-sub-menu>
<template v-else>
<el-menu-item :index="val.path" :key="val.path">
<template #title v-if="!val.meta.isLink || (val.meta.isLink && val.meta.isIframe)">
<SvgIcon :name="val.meta.icon" />
<span>{{ $t(val.meta.title) }}</span>
{{ $t(val.meta.title) }}
</template>
<SubItem :chil="val.children" />
</el-sub-menu>
<template v-else>
<el-menu-item :index="val.path" :key="val.path">
<template #title v-if="!val.meta.isLink || (val.meta.isLink && val.meta.isIframe)">
<template #title v-else>
<a class="w100" @click.prevent="onALinkClick(val)">
<SvgIcon :name="val.meta.icon" />
{{ $t(val.meta.title) }}
</template>
<template #title v-else>
<a class="w100" @click.prevent="onALinkClick(val)">
<SvgIcon :name="val.meta.icon" />
{{ $t(val.meta.title) }}
</a>
</template>
</el-menu-item>
</template>
</a>
</template>
</el-menu-item>
</template>
</el-menu>
</el-scrollbar>
</template>
</el-menu>
</div>
</template>
<script setup lang="ts" name="navMenuHorizontal">
import { defineAsyncComponent, reactive, computed, onMounted, nextTick, onBeforeMount, ref } from 'vue';
import { defineAsyncComponent, reactive, computed, onBeforeMount } from 'vue';
import { useRoute, onBeforeRouteUpdate, RouteRecordRaw } from 'vue-router';
import { storeToRefs } from 'pinia';
import { useRoutesList } from '/@/stores/routesList';
@ -52,7 +50,6 @@ const props = defineProps({
});
// 定义变量内容
const elMenuHorizontalScrollRef = ref();
const stores = useRoutesList();
const storesThemeConfig = useThemeConfig();
const { routesList } = storeToRefs(stores);
@ -66,19 +63,6 @@ const state = reactive({
const menuLists = computed(() => {
return <RouteItems>props.menuList;
});
// 设置横向滚动条可以鼠标滚轮滚动
const onElMenuHorizontalScroll = (e: WheelEventType) => {
const eventDelta = e.wheelDelta || -e.deltaY * 40;
elMenuHorizontalScrollRef.value.$refs.wrapRef.scrollLeft = elMenuHorizontalScrollRef.value.$refs.wrapRef.scrollLeft + eventDelta / 4;
};
// 初始化数据,页面刷新时,滚动条滚动到对应位置
const initElMenuOffsetLeft = () => {
nextTick(() => {
let els = <HTMLElement>document.querySelector('.el-menu.el-menu--horizontal li.is-active');
if (!els) return false;
elMenuHorizontalScrollRef.value.$refs.wrapRef.scrollLeft = els.offsetLeft;
});
};
// 路由过滤递归函数
const filterRoutesFun = <T extends RouteItem>(arr: T[]): T[] => {
return arr
@ -122,10 +106,6 @@ const onALinkClick = (val: RouteItem) => {
onBeforeMount(() => {
setCurrentRouterHighlight(route);
});
// 页面加载时
onMounted(() => {
initElMenuOffsetLeft();
});
// 路由更新时
onBeforeRouteUpdate((to) => {
// 修复https://gitee.com/lyt-top/vue-next-admin/issues/I3YX6G

View File

@ -2,7 +2,7 @@
<div class="layout-padding layout-padding-unset layout-iframe">
<div class="layout-padding-auto layout-padding-view">
<div class="w100" v-for="v in setIframeList" :key="v.path" v-loading="v.meta.loading" element-loading-background="white">
<transition-group :name="name" mode="out-in">
<transition-group :name="name">
<iframe
:src="v.meta.isLink"
:key="v.path"

View File

@ -0,0 +1,108 @@
<template>
<div class="sponsors-container" title="点击前往体验" v-show="state.sponsors.isShow" @click="onSponsorsClick">
<el-carousel height="240px" indicator-position="none" :arrow="setCarouselShow" @change="onCarouselChange">
<el-carousel-item v-for="(v, k) in state.sponsors.list" :key="k">
<img :src="v.url" class="sponsors-img" />
<div class="sponsors-text" v-html="v.text"></div>
</el-carousel-item>
</el-carousel>
<div class="sponsors-close">
<SvgIcon name="ele-Close" :size="12" title="关闭赞助商" @click.stop="onCloseSponsors" />
</div>
</div>
</template>
<script setup lang="ts" name="layoutSponsors">
import { reactive, computed, onMounted } from 'vue';
import sponsorsOne from '/@/assets/ccflowRightNextAdmin.png';
// 定义变量内容
const state = reactive({
sponsors: {
list: [
{
url: sponsorsOne,
text: `驰骋BPM系统包含表单引擎+流程引擎+权限控制,方便集成,配置灵活,功能强大,适合中国国情的工作流引擎.演示:http://demo.ccflow.org。右上角点star方可加群: 1060674395`,
link: 'http://www.ccflow.org/',
},
],
isShow: false,
index: 0,
},
});
// 设置轮播图箭头显示
const setCarouselShow = computed(() => {
return state.sponsors.list.length <= 1 ? 'never' : 'hover';
});
// 关闭赞助商
const onCloseSponsors = () => {
state.sponsors.isShow = false;
};
// 轮播图改变时
const onCarouselChange = (e: number) => {
state.sponsors.index = e;
};
// 当前项内容点击
const onSponsorsClick = () => {
window.open(state.sponsors.list[state.sponsors.index].link);
};
// 延迟显示,防止影响其它界面加载
const delayShow = () => {
setTimeout(() => {
state.sponsors.isShow = true;
}, 3000);
};
// 页面加载时
onMounted(() => {
delayShow();
});
</script>
<style scoped lang="scss">
.sponsors-container {
position: fixed;
right: 15px;
bottom: 15px;
z-index: 3;
width: 200px;
background-color: var(--next-bg-main-color);
box-shadow: var(--el-box-shadow-lighter);
border-radius: 5px;
overflow: hidden;
cursor: pointer;
.sponsors-img {
width: 100%;
height: 80px;
}
.sponsors-text {
padding: 10px;
color: var(--el-text-color-regular);
font-size: var(--el-dialog-content-font-size);
}
.sponsors-close {
width: 60px;
height: 60px;
border-radius: 100%;
background: rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
position: absolute;
right: -35px;
bottom: -35px;
:deep(i) {
position: absolute;
left: 9px;
top: 9px;
color: #afafaf;
transition: all 0.3s ease;
}
&:hover {
transition: all 0.3s ease;
:deep(i) {
color: var(--el-color-primary);
transition: all 0.3s ease;
}
}
}
}
</style>

View File

@ -45,7 +45,7 @@ const { themeConfig } = storeToRefs(storesThemeConfig);
const state = reactive({
isUpgrade: false,
// @ts-ignore
version: __VERSION__,
version: __NEXT_VERSION__,
isLoading: false,
btnTxt: '',
});

View File

@ -1,13 +1,12 @@
import { createApp } from 'vue';
import pinia from '/@/stores/index';
import App from './App.vue';
import router from './router';
import App from '/@/App.vue';
import router from '/@/router';
import { directive } from '/@/directive/index';
import { i18n } from '/@/i18n/index';
import other from '/@/utils/other';
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
import '/@/theme/index.scss';
import VueGridLayout from 'vue-grid-layout';
@ -16,4 +15,4 @@ const app = createApp(App);
directive(app);
other.elSvg(app);
app.use(pinia).use(router).use(ElementPlus, { i18n: i18n.global.t }).use(i18n).use(VueGridLayout).mount('#app');
app.use(pinia).use(router).use(ElementPlus).use(i18n).use(VueGridLayout).mount('#app');

View File

@ -106,9 +106,15 @@
background-color: var(--next-color-disabled) !important;
}
// topBar
.layout-navbars-breadcrumb-index {
background: none !important;
}
// menu
.layout-aside {
border-right: 1px solid var(--next-border-color-light) !important;
@extend .layout-navbars-breadcrumb-index;
}
// colorPicker

View File

@ -148,12 +148,12 @@
background: var(--next-bg-topBar);
.el-menu-item,
.el-sub-menu {
height: 50px !important;
line-height: 50px !important;
height: 48px !important;
line-height: 48px !important;
color: var(--next-bg-topBarColor);
.el-sub-menu__title {
height: 50px !important;
line-height: 50px !important;
height: 48px !important;
line-height: 48px !important;
color: var(--next-bg-topBarColor);
}
.el-popper.is-pure.is-light {
@ -180,7 +180,7 @@
width: 100% !important;
.el-menu-item,
.el-sub-menu__title {
height: 50px !important;
height: 48px !important;
color: var(--next-bg-topBarColor);
}
.el-menu-item:not(.is-active):hover,

View File

@ -1,3 +1,4 @@
@import 'element-plus/dist/index.css';
@import './app.scss';
@import 'common/transition.scss';
@import './other.scss';

View File

@ -6,6 +6,7 @@ declare module 'js-cookie';
declare module '@wangeditor/editor-for-vue';
declare module 'js-table2excel';
declare module 'qs';
declare module 'sortablejs';
// 声明一个模块,防止引入文件时报错
declare module '*.json';

View File

@ -53,8 +53,11 @@ export function useTitle() {
export function setTagsViewNameI18n(item: any) {
let tagsViewName: string = '';
const { query, params, meta } = item;
// 修复tagsViewName匹配到其他含下列单词的路由
// https://gitee.com/lyt-top/vue-next-admin/pulls/44/files
const pattern = /^\{("(zh-cn|en|zh-tw)":"[^,]+",?){1,3}}$/;
if (query?.tagsViewName || params?.tagsViewName) {
if (/\/zh-cn|en|zh-tw\//.test(query?.tagsViewName) || /\/zh-cn|en|zh-tw\//.test(params?.tagsViewName)) {
if (pattern.test(query?.tagsViewName) || pattern.test(params?.tagsViewName)) {
// 国际化
const urlTagsParams = (query?.tagsViewName && JSON.parse(query?.tagsViewName)) || (params?.tagsViewName && JSON.parse(params?.tagsViewName));
tagsViewName = urlTagsParams[i18n.global.locale.value];

View File

@ -1,4 +1,4 @@
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
import axios, { AxiosInstance } from 'axios';
import { ElMessage, ElMessageBox } from 'element-plus';
import { Session } from '/@/utils/storage';
import qs from 'qs';
@ -17,7 +17,7 @@ const service: AxiosInstance = axios.create({
// 添加请求拦截器
service.interceptors.request.use(
(config: AxiosRequestConfig) => {
(config) => {
// 在发送请求之前做些什么 token
if (Session.get('token')) {
config.headers!['Authorization'] = `${Session.get('token')}`;

View File

@ -8,18 +8,23 @@ import Cookies from 'js-cookie';
* @method clear 移除全部永久缓存
*/
export const Local = {
// 查看 v2.4.3版本更新日志
setKey(key: string) {
// @ts-ignore
return `${__NEXT_NAME__}:${key}`;
},
// 设置永久缓存
set(key: string, val: any) {
window.localStorage.setItem(key, JSON.stringify(val));
set<T>(key: string, val: T) {
window.localStorage.setItem(Local.setKey(key), JSON.stringify(val));
},
// 获取永久缓存
get(key: string) {
let json = <string>window.localStorage.getItem(key);
let json = <string>window.localStorage.getItem(Local.setKey(key));
return JSON.parse(json);
},
// 移除永久缓存
remove(key: string) {
window.localStorage.removeItem(key);
window.localStorage.removeItem(Local.setKey(key));
},
// 移除全部永久缓存
clear() {
@ -36,20 +41,20 @@ export const Local = {
*/
export const Session = {
// 设置临时缓存
set(key: string, val: any) {
set<T>(key: string, val: T) {
if (key === 'token') return Cookies.set(key, val);
window.sessionStorage.setItem(key, JSON.stringify(val));
window.sessionStorage.setItem(Local.setKey(key), JSON.stringify(val));
},
// 获取临时缓存
get(key: string) {
if (key === 'token') return Cookies.get(key);
let json = <string>window.sessionStorage.getItem(key);
let json = <string>window.sessionStorage.getItem(Local.setKey(key));
return JSON.parse(json);
},
// 移除临时缓存
remove(key: string) {
if (key === 'token') return Cookies.remove(key);
window.sessionStorage.removeItem(key);
window.sessionStorage.removeItem(Local.setKey(key));
},
// 移除全部临时缓存
clear() {

View File

@ -8,21 +8,12 @@
element-loading-background="rgba(255, 255, 255, 0.1)"
:class="{ 'min-h-360': state.tableData.data.length <= 0 }"
>
<div
v-for="(val, key) in filtering"
:key="key"
:ref="
(el) => {
if (el) dlRefs[key] = el;
}
"
class="filtering-list-flex"
>
<div v-for="(val, key) in state.filtering" :key="key" ref="dlRefs" class="filtering-list-flex">
<div class="filtering-list-title">{{ val.title }}</div>
<div class="filtering-list-item" :style="{ height: val.isMore ? 'auto' : '50px' }">
<span class="span" :class="v.active ? 'dd-active' : ''" v-for="(v, k) in val.children" :key="k" @click="onSelItem(val, v)">{{
v.label
}}</span>
<span class="span" :class="v.active ? 'dd-active' : ''" v-for="(v, k) in val.children" :key="k" @click="onSelItem(val, v)">
{{ v.label }}
</span>
<div class="dd-more" v-if="val.isShowMore" @click="val.isMore = !val.isMore">
<span>{{ val.isMore ? '收起' : '展开' }}</span>
<i :class="val.isMore ? 'el-icon-arrow-down' : 'el-icon-arrow-right'"></i>

View File

@ -56,7 +56,7 @@
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="组件路径">
<el-input v-model="state.ruleForm.component" placeholder="组件路径" clearable></el-input>
<el-input v-model="state.ruleForm.componentAlias" placeholder="组件路径" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
@ -169,6 +169,7 @@ const state = reactive({
menuType: 'menu', // 菜单类型
name: '', // 路由名称
component: '', // 组件路径
componentAlias: '', // 组件路径别名
isLink: false, // 是否外链
menuSort: 0, // 菜单排序
path: '', // 路由路径
@ -209,12 +210,8 @@ const openDialog = (type: string, row?: any) => {
if (type === 'edit') {
// 模拟数据,实际请走接口
row.menuType = 'menu';
row.menuSort = Math.random();
row.component = `${row.component} `
.match(/\'(.+)\'/g)
?.join('')
.replace(/\'/g, '');
state.ruleForm = row;
row.menuSort = Math.floor(Math.random() * 100);
state.ruleForm = JSON.parse(JSON.stringify(row));
state.dialog.title = '修改菜单';
state.dialog.submitTxt = '修 改';
} else {

View File

@ -25,7 +25,7 @@ const viteConfig = defineConfig((mode: ConfigEnv) => {
server: {
host: '0.0.0.0',
port: env.VITE_PORT as unknown as number,
open: env.VITE_OPEN,
open: JSON.parse(env.VITE_OPEN),
hmr: true,
proxy: {
'/gitee': {
@ -57,7 +57,8 @@ const viteConfig = defineConfig((mode: ConfigEnv) => {
__VUE_I18N_LEGACY_API__: JSON.stringify(false),
__VUE_I18N_FULL_INSTALL__: JSON.stringify(false),
__INTLIFY_PROD_DEVTOOLS__: JSON.stringify(false),
__VERSION__: JSON.stringify(process.env.npm_package_version),
__NEXT_VERSION__: JSON.stringify(process.env.npm_package_version),
__NEXT_NAME__: JSON.stringify(process.env.npm_package_name),
},
};
});