4 Commits

32 changed files with 496 additions and 119 deletions

View File

@ -2,6 +2,26 @@
🎉🎉🔥 `vue-next-admin` 基于 vue3.x 、Typescript、vite、Element plus 等适配手机、平板、pc 的后台开源免费模板库vue2.x 请切换 vue-prev-admin 分支)
## 1.0.16
`2021.08.14`
- 🌟 更新 依赖更新最新版本
- 🎯 优化 菜单高亮(详情且详情设置了 meta.isHide 时,顶级菜单高亮),感谢群友@YourObject
- 🎯 优化 详情路径写法:如父级(/pages/filtering那么详情为/pages/filtering/details?id=1。这样写可实现详情时父级菜单高亮否则写成/pages/filteringDetails?id=1顶级菜单将不会高亮。可参考`页面/过滤筛选组件`,点击当前图片进行测试
- 🎯 优化 tagsView 右键菜单全屏时,打开的界面高度问题
- 🎯 优化 图表批量 resize 问题
- 🐞 修复 菜单收起时设置全局主题primary 且有二级菜单时),文字高亮颜色不对
- 🐞 修复 国际化 <a href="https://gitee.com/lyt-top/vue-next-admin/issues/I43NPE" target="_blank">#I43NPE</a>。可参考:`页面/过滤筛选组件`,点击顶部语言切换,进行底部分页国际化查看
## 1.0.15
`2021.08.06`
- 🌟 更新 依赖更新最新版本
- 🎯 优化 tagsView 右键菜单点击时的字段名id 已修改成 contextMenuClickId与路由中返回的 id 名冲突问题,感谢群友@伯牙已遇钟子期
- 🎉 新增 多个 form 表单验证界面演示
## 1.0.14
`2021.07.29`

View File

@ -71,11 +71,18 @@ cnpm run build
#### 💯 学习交流加 QQ 群
- 若加群了没同意(一般不会超过一天),那就是群满了,请换一个群试试
- 查看开发文档、<a href="https://lyt-top.gitee.io/vue-next-admin-preview/#/login" target="_blank">vue-next-admin</a> 开发文档正在编写中...
- 群号码:<a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=RdUY97Vx0T0vZ_1OOu-X1yFNkWgDwbjC&jump_from=webapi">665452019</a>
- 群号码:
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>
<a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=RdUY97Vx0T0vZ_1OOu-X1yFNkWgDwbjC&jump_from=webapi">
<img src="https://gitee.com/lyt-top/vue-next-admin-images/raw/master/user/qqs.png" width="220" alt="vue-next-admin 讨论群" title="vue-next-admin 讨论群"/></a>
<a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=RdUY97Vx0T0vZ_1OOu-X1yFNkWgDwbjC&jump_from=webapi">
<img src="https://gitee.com/lyt-top/vue-next-admin-images/raw/master/user/qq1.png" width="220" height="220" alt="vue-next-admin 讨论群" 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://gitee.com/lyt-top/vue-next-admin-images/raw/master/user/qq2.png" width="220" height="220" alt="vue-next-admin 讨论群" title="vue-next-admin 讨论群2"/>
</a>
#### ❤️ 鸣谢列表

View File

@ -1,6 +1,6 @@
{
"name": "vue-next-admin",
"version": "1.0.14",
"version": "1.0.16",
"scripts": {
"dev": "vite",
"build": "vite build",
@ -11,9 +11,9 @@
"countup.js": "^2.0.8",
"cropperjs": "^1.5.12",
"echarts": "^5.1.2",
"echarts-gl": "^2.0.7",
"echarts-gl": "^2.0.8",
"echarts-wordcloud": "^2.0.0",
"element-plus": "^1.0.2-beta.65",
"element-plus": "^1.0.2-beta.70",
"mitt": "^3.0.0",
"nprogress": "^0.2.0",
"print-js": "^1.6.0",
@ -33,18 +33,18 @@
"devDependencies": {
"@types/axios": "^0.14.0",
"@types/clipboard": "^2.0.1",
"@types/node": "^16.4.9",
"@types/node": "^16.6.1",
"@types/nprogress": "^0.2.0",
"@types/sortablejs": "^1.10.7",
"@typescript-eslint/eslint-plugin": "^4.28.5",
"@typescript-eslint/parser": "^4.28.5",
"@vitejs/plugin-vue": "^1.3.0",
"@vue/compiler-sfc": "^3.1.5",
"@typescript-eslint/eslint-plugin": "^4.29.1",
"@typescript-eslint/parser": "^4.29.1",
"@vitejs/plugin-vue": "^1.4.0",
"@vue/compiler-sfc": "^3.2.2",
"dotenv": "^10.0.0",
"eslint": "^7.32.0",
"eslint-plugin-vue": "^7.15.0",
"eslint-plugin-vue": "^7.16.0",
"prettier": "^2.3.2",
"sass": "^1.37.0",
"sass": "^1.37.5",
"sass-loader": "^12.1.0",
"typescript": "^4.3.5",
"vite": "^2.4.4",

View File

@ -1,12 +1,14 @@
<template>
<router-view v-show="getThemeConfig.lockScreenTime !== 0" />
<LockScreen v-if="getThemeConfig.isLockScreen" />
<Setings ref="setingsRef" v-show="getThemeConfig.lockScreenTime !== 0" />
<CloseFull />
<el-config-provider :locale="i18nLocale">
<router-view v-show="getThemeConfig.lockScreenTime !== 0" />
<LockScreen v-if="getThemeConfig.isLockScreen" />
<Setings ref="setingsRef" v-show="getThemeConfig.lockScreenTime !== 0" />
<CloseFull />
</el-config-provider>
</template>
<script lang="ts">
import { computed, ref, getCurrentInstance, onBeforeMount, onMounted, onUnmounted, nextTick, defineComponent, watch } from 'vue';
import { computed, ref, getCurrentInstance, onBeforeMount, onMounted, onUnmounted, nextTick, defineComponent, watch, reactive, toRefs } from 'vue';
import { useRoute } from 'vue-router';
import { useStore } from '/@/store/index';
import { useTitle } from '/@/utils/setWebTitle';
@ -24,6 +26,9 @@ export default defineComponent({
const route = useRoute();
const store = useStore();
const title = useTitle();
const state = reactive({
i18nLocale: null,
});
// 获取布局配置信息
const getThemeConfig = computed(() => {
return store.state.themeConfig.themeConfig;
@ -46,6 +51,10 @@ export default defineComponent({
proxy.mittBus.on('openSetingsDrawer', () => {
openSetingsDrawer();
});
// 设置 i18nApp.vue 中的 el-config-provider
proxy.mittBus.on('getI18nConfig', (locale: string) => {
state.i18nLocale = locale;
});
// 获取缓存中的布局配置
if (Local.get('themeConfig')) {
store.dispatch('themeConfig/setThemeConfig', Local.get('themeConfig'));
@ -53,9 +62,10 @@ export default defineComponent({
}
});
});
// 页面销毁时,关闭监听布局配置
// 页面销毁时,关闭监听布局配置/i18n监听
onUnmounted(() => {
proxy.mittBus.off('openSetingsDrawer', () => {});
proxy.mittBus.off('getI18nConfig', () => {});
});
// 监听路由的变化,设置网站标题
watch(
@ -67,6 +77,7 @@ export default defineComponent({
return {
setingsRef,
getThemeConfig,
...toRefs(state),
};
},
});

View File

@ -26,7 +26,7 @@ import pagesFormI18nZhtw from '/@/i18n/pages/formI18n/zh-tw';
*/
const messages = {
[zhcnLocale.name]: {
el: zhcnLocale.el,
...zhcnLocale,
message: {
...nextZhcn,
...pagesHomeZhcn,
@ -35,7 +35,7 @@ const messages = {
},
},
[enLocale.name]: {
el: enLocale.el,
...enLocale,
message: {
...nextEn,
...pagesHomeEn,
@ -44,7 +44,7 @@ const messages = {
},
},
[zhtwLocale.name]: {
el: zhtwLocale.el,
...zhtwLocale,
message: {
...nextZhtw,
...pagesHomeZhtw,

View File

@ -44,6 +44,7 @@ export default {
pagesCityLinkage: 'CityLinkage',
pagesFormAdapt: 'FormAdapt',
pagesFormI18n: 'FormI18n',
pagesFormRules: 'Multi form validation',
pagesListAdapt: 'ListAdapt',
pagesWaterfall: 'Waterfall',
pagesSteps: 'Steps',

View File

@ -44,6 +44,7 @@ export default {
pagesCityLinkage: '城市多级联动',
pagesFormAdapt: '表单自适应',
pagesFormI18n: '表单国际化',
pagesFormRules: '多表单验证',
pagesListAdapt: '列表自适应',
pagesWaterfall: '瀑布屏',
pagesSteps: '步骤条',

View File

@ -44,6 +44,7 @@ export default {
pagesCityLinkage: '都市多級聯動',
pagesFormAdapt: '表單自我調整',
pagesFormI18n: '表單國際化',
pagesFormRules: '多表單驗證',
pagesListAdapt: '清單自我調整',
pagesWaterfall: '瀑布屏',
pagesSteps: '步驟條',

View File

@ -194,17 +194,24 @@ export default {
initI18n();
title();
};
// 设置 element plus 组件的国际化
const setI18nConfig = (locale: string) => {
proxy.mittBus.emit('getI18nConfig', proxy.$i18n.messages[locale]);
};
// 初始化言语国际化
const initI18n = () => {
switch (Local.get('themeConfig').globalI18n) {
case 'zh-cn':
state.disabledI18n = 'zh-cn';
setI18nConfig('zh-cn');
break;
case 'en':
state.disabledI18n = 'en';
setI18nConfig('en');
break;
case 'zh-tw':
state.disabledI18n = 'zh-tw';
setI18nConfig('zh-tw');
break;
}
};

View File

@ -11,7 +11,14 @@
>
<ul class="el-dropdown-menu">
<template v-for="(v, k) in dropdownList">
<li class="el-dropdown-menu__item" aria-disabled="false" tabindex="-1" :key="k" v-if="!v.affix" @click="onCurrentContextmenuClick(v.id)">
<li
class="el-dropdown-menu__item"
aria-disabled="false"
tabindex="-1"
:key="k"
v-if="!v.affix"
@click="onCurrentContextmenuClick(v.contextMenuClickId)"
>
<i :class="v.icon"></i>
<span>{{ $t(v.txt) }}</span>
</li>
@ -35,12 +42,12 @@ export default defineComponent({
const state = reactive({
isShow: false,
dropdownList: [
{ id: 0, txt: 'message.tagsView.refresh', affix: false, icon: 'el-icon-refresh-right' },
{ id: 1, txt: 'message.tagsView.close', affix: false, icon: 'el-icon-close' },
{ id: 2, txt: 'message.tagsView.closeOther', affix: false, icon: 'el-icon-circle-close' },
{ id: 3, txt: 'message.tagsView.closeAll', affix: false, icon: 'el-icon-folder-delete' },
{ contextMenuClickId: 0, txt: 'message.tagsView.refresh', affix: false, icon: 'el-icon-refresh-right' },
{ contextMenuClickId: 1, txt: 'message.tagsView.close', affix: false, icon: 'el-icon-close' },
{ contextMenuClickId: 2, txt: 'message.tagsView.closeOther', affix: false, icon: 'el-icon-circle-close' },
{ contextMenuClickId: 3, txt: 'message.tagsView.closeAll', affix: false, icon: 'el-icon-folder-delete' },
{
id: 4,
contextMenuClickId: 4,
txt: 'message.tagsView.fullscreen',
affix: false,
icon: 'iconfont icon-fullscreen',
@ -53,8 +60,8 @@ export default defineComponent({
return props.dropdown;
});
// 当前项菜单点击
const onCurrentContextmenuClick = (id: number) => {
emit('currentContextmenuClick', Object.assign({}, { id }, state.item));
const onCurrentContextmenuClick = (contextMenuClickId: number) => {
emit('currentContextmenuClick', Object.assign({}, { contextMenuClickId }, state.item));
};
// 打开右键菜单:判断是否固定,固定则不显示关闭按钮
const openContextmenu = (item: any) => {

View File

@ -46,7 +46,6 @@ import Sortable from 'sortablejs';
import { ElMessage } from 'element-plus';
import { useStore } from '/@/store/index';
import { Session } from '/@/utils/storage';
import { NextLoading } from '/@/utils/loading';
import { isObjectValueEqual } from '/@/utils/arrayOperation';
import Contextmenu from '/@/layout/navBars/tagsView/contextmenu.vue';
export default {
@ -242,19 +241,7 @@ export default {
const item = state.tagsViewList.find((v: any) => (getThemeConfig.value.isShareTagsView ? v.path === path : v.url === path));
if (item.meta.isDynamic) await router.push({ name: item.name, params: item.params });
else await router.push({ name: item.name, query: item.query });
NextLoading.start();
setTimeout(() => {
nextTick(() => {
store.dispatch('tagsViewRoutes/setCurrenFullscreen', true);
if (store.state.tagsViewRoutes.isTagsViewCurrenFull) {
const element = document.querySelector('.layout-main .layout-view-bg-white') as HTMLElement;
if (!element) return false;
// 非当前页开启 iframes 高度会有问题
if (route.path === '/iframes') element.style.height = `100vh`;
else element.style.height = `calc(100vh - 30px)`;
}
});
}, 1000);
store.dispatch('tagsViewRoutes/setCurrenFullscreen', true);
};
// 当前项右键菜单点击,拿当前点击的路由路径对比 浏览器缓存中的 tagsView 路由数组,取当前点击项的详细路由信息
// 防止 tagsView 非当前页演示时,操作异常
@ -279,7 +266,7 @@ export default {
const cParams = item.meta.isDynamic ? item.params : item.query;
if (!getCurrentRouteItem(item.path, cParams)) return ElMessage({ type: 'warning', message: '请正确输入路径及完整参数query、params' });
const { path, name, params, query, meta, url } = getCurrentRouteItem(item.path, cParams);
switch (item.id) {
switch (item.contextMenuClickId) {
case 0:
// 刷新当前
if (meta.isDynamic) await router.push({ name, params });

View File

@ -66,15 +66,6 @@ export default defineComponent({
proxy.$refs.elMenuHorizontalScrollRef.$refs.wrap.scrollLeft = els.offsetLeft;
});
};
// 设置页面当前路由高亮
const setCurrentRouterHighlight = (path: string) => {
const currentPathSplit = path.split('/');
if (store.state.themeConfig.themeConfig.layout === 'classic') {
state.defaultActive = `/${currentPathSplit[1]}`;
} else {
state.defaultActive = path;
}
};
// 路由过滤递归函数
const filterRoutesFun = (arr: Array<object>) => {
return arr
@ -99,15 +90,26 @@ export default defineComponent({
});
return currentData;
};
// 设置页面当前路由高亮
const setCurrentRouterHighlight = (currentRoute) => {
const { path, meta } = currentRoute;
if (store.state.themeConfig.themeConfig.layout === 'classic') {
state.defaultActive = `/${path.split('/')[1]}`;
} else {
const pathSplit = meta.isDynamic ? meta.isDynamicPath.split('/') : path.split('/');
if (pathSplit.length >= 4 && meta.isHide) state.defaultActive = pathSplit.splice(0, 3).join('/');
else state.defaultActive = path;
}
};
// 页面加载时
onMounted(() => {
initElMenuOffsetLeft();
setCurrentRouterHighlight(route.meta.isDynamic ? route.meta.isDynamicPath : route.path);
setCurrentRouterHighlight(route);
});
// 路由更新时
onBeforeRouteUpdate((to) => {
// 修复https://gitee.com/lyt-top/vue-next-admin/issues/I3YX6G
setCurrentRouterHighlight(to.meta.isDynamic ? to.meta.isDynamicPath : to.path);
setCurrentRouterHighlight(to);
proxy.mittBus.emit('onMenuClick');
// 修复经典布局开启切割菜单时点击tagsView后左侧导航菜单数据不变的问题
let { layout, isClassicSplitMenu } = store.state.themeConfig.themeConfig;

View File

@ -29,7 +29,7 @@
</template>
<script lang="ts">
import { toRefs, reactive, computed, defineComponent, getCurrentInstance } from 'vue';
import { toRefs, reactive, computed, defineComponent, getCurrentInstance, onMounted } from 'vue';
import { useRoute, onBeforeRouteUpdate } from 'vue-router';
import { useStore } from '/@/store/index';
import SubItem from '/@/layout/navMenu/subItem.vue';
@ -62,10 +62,21 @@ export default defineComponent({
const setIsCollapse = computed(() => {
return document.body.clientWidth < 1000 ? false : getThemeConfig.value.isCollapse;
});
// 菜单高亮(详情时,父级高亮)
const setParentHighlight = (currentRoute) => {
const { path, meta } = currentRoute;
const pathSplit = meta.isDynamic ? meta.isDynamicPath.split('/') : path.split('/');
if (pathSplit.length >= 4 && meta.isHide) return pathSplit.splice(0, 3).join('/');
else return path;
};
// 页面加载时
onMounted(() => {
state.defaultActive = setParentHighlight(route);
});
// 路由更新时
onBeforeRouteUpdate((to) => {
// 修复https://gitee.com/lyt-top/vue-next-admin/issues/I3YX6G
state.defaultActive = to.meta.isDynamic ? to.meta.isDynamicPath : to.path;
state.defaultActive = setParentHighlight(to);
proxy.mittBus.emit('onMenuClick');
const clientWidth = document.body.clientWidth;
if (clientWidth < 1000) getThemeConfig.value.isCollapse = false;

View File

@ -32,8 +32,13 @@ export default defineComponent({
// 设置 iframe 的高度
const setIframeHeight = computed(() => {
let { isTagsview } = store.state.themeConfig.themeConfig;
if (isTagsview) return `84px`;
else return `50px`;
let { isTagsViewCurrenFull } = store.state.tagsViewRoutes;
if (isTagsViewCurrenFull) {
return `0px`;
} else {
if (isTagsview) return `84px`;
else return `50px`;
}
});
// 页面加载时
onMounted(() => {

View File

@ -574,24 +574,32 @@ export const dynamicRoutes: Array<RouteRecordRaw> = [
auth: ['admin', 'test'],
icon: 'el-icon-sell',
},
/**
* 注意此处详情写法:
* 1、嵌套进父级里时面包屑显示为首页/页面/过滤筛选组件/过滤筛选组件详情
* 2、不嵌套进父级时面包屑显示为首页/页面/过滤筛选组件/过滤筛选组件详情
* 3、想要父级不高亮面包屑显示为首页/页面/过滤筛选组件详情,设置路径为:/pages/filteringDetails
*/
children: [
{
path: '/pages/filtering/details',
name: 'pagesFilteringDetails',
component: () => import('/@/views/pages/filtering/details.vue'),
meta: {
title: 'message.router.pagesFilteringDetails',
isLink: '',
isHide: true,
isKeepAlive: false,
isAffix: false,
isIframe: false,
auth: ['admin', 'test'],
icon: 'el-icon-s-order',
},
},
],
},
{
path: '/pages/filteringDetails',
name: 'pagesFilteringDetails',
component: () => import('/@/views/pages/filtering/details.vue'),
meta: {
title: 'message.router.pagesFilteringDetails',
isLink: '',
isHide: true,
isKeepAlive: false,
isAffix: false,
isIframe: false,
auth: ['admin', 'test'],
icon: 'el-icon-s-order',
},
},
{
path: '/pages/filteringDetails1',
path: '/pages/filtering/details1',
name: 'pagesFilteringDetails1',
component: () => import('/@/views/pages/filtering/details1.vue'),
meta: {
@ -695,6 +703,21 @@ export const dynamicRoutes: Array<RouteRecordRaw> = [
icon: 'iconfont icon-diqiu',
},
},
{
path: '/pages/formRules',
name: 'pagesFormRules',
component: () => import('/@/views/pages/formRules/index.vue'),
meta: {
title: 'message.router.pagesFormRules',
isLink: '',
isHide: false,
isKeepAlive: true,
isAffix: false,
isIframe: false,
auth: ['admin', 'test'],
icon: 'iconfont icon-shuxing',
},
},
{
path: '/pages/listAdapt',
name: 'pagesListAdapt',

View File

@ -798,8 +798,9 @@
color: set-color(primary);
}
}
// 高亮时
.el-menu-item.is-active {
// 高亮时/菜单收起时
.el-menu-item.is-active,
.el-menu--collapse .el-submenu.is-active i {
color: set-color(primary);
}
.el-active-extend {

View File

@ -202,7 +202,7 @@
</template>
<script lang="ts">
import { toRefs, reactive, computed, onMounted, getCurrentInstance, watch, nextTick } from 'vue';
import { toRefs, reactive, computed, onMounted, getCurrentInstance, watch, nextTick, onActivated } from 'vue';
import { useStore } from '/@/store/index';
import ChartHead from '/@/views/chart/head.vue';
import * as echarts from 'echarts';
@ -225,8 +225,13 @@ export default {
// 设置主内容的高度
const initTagViewHeight = computed(() => {
let { isTagsview } = store.state.themeConfig.themeConfig;
if (isTagsview) return `114px`;
else return `80px`;
let { isTagsViewCurrenFull } = store.state.tagsViewRoutes;
if (isTagsViewCurrenFull) {
return `30px`;
} else {
if (isTagsview) return `114px`;
else return `80px`;
}
});
// 初始化中间图表1
const initChartsCenterOne = () => {
@ -440,13 +445,17 @@ export default {
state.myCharts.push(myChart);
};
// 批量设置 echarts resize
const initEchartsResize = () => {
window.addEventListener('resize', () => {
const initEchartsResizeFun = () => {
nextTick(() => {
for (let i = 0; i < state.myCharts.length; i++) {
state.myCharts[i].resize();
}
});
};
// 批量设置 echarts resize
const initEchartsResize = () => {
window.addEventListener('resize', initEchartsResizeFun);
};
// 页面加载时
onMounted(() => {
initChartsCenterOne();
@ -456,15 +465,15 @@ export default {
initChartsInvestment();
initEchartsResize();
});
// 由于页面缓存原因keep-alive
onActivated(() => {
initEchartsResizeFun();
});
// 监听 vuex 中的 tagsview 开启全屏变化,重新 resize 图表,防止不出现/大小不变等
watch(
() => store.state.tagsViewRoutes.isTagsViewCurrenFull,
() => {
nextTick(() => {
for (let i = 0; i < state.myCharts.length; i++) {
state.myCharts[i].resize();
}
});
initEchartsResizeFun();
}
);
return {

View File

@ -23,8 +23,13 @@ export default {
// 设置主内容的高度
const initTagViewHeight = computed(() => {
let { isTagsview } = store.state.themeConfig.themeConfig;
if (isTagsview) return `114px`;
else return `80px`;
let { isTagsViewCurrenFull } = store.state.tagsViewRoutes;
if (isTagsViewCurrenFull) {
return `30px`;
} else {
if (isTagsview) return `114px`;
else return `80px`;
}
});
// echartsMap 将坐标信息和对应物理量的值合在一起
const convertData = (data) => {

View File

@ -51,23 +51,23 @@ export default {
// 0 刷新当前1 关闭当前2 关闭其它3 关闭全部 4 当前页全屏
// 1、刷新当前 tagsView
const refreshCurrentTagsView = () => {
proxy.mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { id: 0, ...route }));
proxy.mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 0, ...route }));
};
// 2、关闭当前 tagsView
const closeCurrentTagsView = () => {
proxy.mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { id: 1, ...route }));
proxy.mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 1, ...route }));
};
// 3、关闭其它 tagsView
const closeOtherTagsView = () => {
proxy.mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { id: 2, ...route }));
proxy.mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 2, ...route }));
};
// 4、关闭全部 tagsView
const closeAllTagsView = () => {
proxy.mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { id: 3, ...route }));
proxy.mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 3, ...route }));
};
// 5、开启当前页面全屏
const openCurrenFullscreen = () => {
proxy.mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { id: 4, ...route }));
proxy.mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 4, ...route }));
};
return {
refreshCurrentTagsView,

View File

@ -23,8 +23,13 @@ export default {
// 设置主内容的高度
const initTagViewHeight = computed(() => {
let { isTagsview } = store.state.themeConfig.themeConfig;
if (isTagsview) return `114px`;
else return `80px`;
let { isTagsViewCurrenFull } = store.state.tagsViewRoutes;
if (isTagsViewCurrenFull) {
return `30px`;
} else {
if (isTagsview) return `114px`;
else return `80px`;
}
});
// 初始化数据
const initEchartsTree = () => {

View File

@ -96,7 +96,7 @@
</template>
<script lang="ts">
import { toRefs, reactive, onMounted, nextTick, computed, getCurrentInstance, watch } from 'vue';
import { toRefs, reactive, onMounted, nextTick, computed, getCurrentInstance, watch, onActivated } from 'vue';
import * as echarts from 'echarts';
import { CountUp } from 'countup.js';
import { formatAxis } from '/@/utils/formatTime';
@ -290,13 +290,17 @@ export default {
state.myCharts.push(myChart);
};
// 批量设置 echarts resize
const initEchartsResize = () => {
window.addEventListener('resize', () => {
const initEchartsResizeFun = () => {
nextTick(() => {
for (let i = 0; i < state.myCharts.length; i++) {
state.myCharts[i].resize();
}
});
};
// 批量设置 echarts resize
const initEchartsResize = () => {
window.addEventListener('resize', initEchartsResizeFun);
};
// 页面加载时
onMounted(() => {
initNumCountUp();
@ -304,15 +308,15 @@ export default {
initHomeOvertime();
initEchartsResize();
});
// 由于页面缓存原因keep-alive
onActivated(() => {
initEchartsResizeFun();
});
// 监听 vuex 中的 tagsview 开启全屏变化,重新 resize 图表,防止不出现/大小不变等
watch(
() => store.state.tagsViewRoutes.isTagsViewCurrenFull,
() => {
nextTick(() => {
for (let i = 0; i < state.myCharts.length; i++) {
state.myCharts[i].resize();
}
});
initEchartsResizeFun();
}
);
return {

View File

@ -21,8 +21,13 @@ export default {
// 设置主内容的高度
const initTagViewHeight = computed(() => {
let { isTagsview } = store.state.themeConfig.themeConfig;
if (isTagsview) return `114px`;
else return `80px`;
let { isTagsViewCurrenFull } = store.state.tagsViewRoutes;
if (isTagsViewCurrenFull) {
return `30px`;
} else {
if (isTagsview) return `114px`;
else return `80px`;
}
});
return {
initTagViewHeight,

View File

@ -21,8 +21,13 @@ export default {
// 设置主内容的高度
const initTagViewHeight = computed(() => {
let { isTagsview } = store.state.themeConfig.themeConfig;
if (isTagsview) return `114px`;
else return `80px`;
let { isTagsViewCurrenFull } = store.state.tagsViewRoutes;
if (isTagsViewCurrenFull) {
return `30px`;
} else {
if (isTagsview) return `114px`;
else return `80px`;
}
});
return {
initTagViewHeight,

View File

@ -145,12 +145,12 @@ export default {
const onTableItemClick = (v: object) => {
if (v.id === 1) {
router.push({
path: '/pages/filteringDetails',
path: '/pages/filtering/details',
query: { id: v.id },
});
} else {
router.push({
path: '/pages/filteringDetails1',
path: '/pages/filtering/details1',
query: { id: v.id },
});
}

View File

@ -0,0 +1,67 @@
<template>
<div class="form-rules-one-container">
<el-form :model="form" :rules="rules" ref="formRulesOneRef" size="small" label-width="100px" class="mt35">
<el-row :gutter="35">
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" placeholder="请输入姓名" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入用户邮箱" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="登陆账户名" prop="autograph">
<el-input v-model="form.autograph" placeholder="请输入登陆账户名" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="职务" prop="occupation">
<el-select v-model="form.occupation" placeholder="请选择职务" clearable class="w100">
<el-option label="计算机 / 互联网 / 通信" value="1"></el-option>
<el-option label="生产 / 工艺 / 制造" value="2"></el-option>
<el-option label="医疗 / 护理 / 制药" value="3"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</template>
<script lang="ts">
import { toRefs, reactive, onMounted } from 'vue';
export default {
name: 'pagesFormRulesOne',
props: {
data: {
type: Object,
default: () => {},
},
},
setup(props) {
const state = reactive({
form: {},
rules: {
name: { required: true, message: '请输入姓名', trigger: 'blur' },
email: { required: true, message: '请输入用户邮箱', trigger: 'blur' },
autograph: { required: true, message: '请输入登陆账户名', trigger: 'blur' },
occupation: { required: true, message: '请选择职务', trigger: 'change' },
},
});
// 赋值回显
const initForm = () => {
state.form = props.data;
};
// 页面加载时
onMounted(() => {
initForm();
});
return {
...toRefs(state),
};
},
};
</script>

View File

@ -0,0 +1,49 @@
<template>
<div class="form-rules-three-container">
<el-form :model="form" :rules="rules" ref="formRulesThreeRef" size="small" label-width="100px" class="mt35">
<el-row :gutter="35">
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="创建用户" prop="createUser">
<el-input v-model="form.createUser" placeholder="请输入创建用户" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="修改用户" prop="editUser">
<el-input v-model="form.editUser" placeholder="请输入修改用户" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="所属用户" prop="user">
<el-input v-model="form.user" placeholder="请输入所属用户" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="所属部门" prop="department">
<el-input v-model="form.department" placeholder="请输入所属部门" clearable></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</template>
<script lang="ts">
import { toRefs, reactive } from 'vue';
export default {
name: 'pagesFormRulesThree',
setup() {
const state = reactive({
form: {},
rules: {
createUser: { required: true, message: '请输入创建用户', trigger: 'blur' },
editUser: { required: true, message: '请输入修改用户', trigger: 'blur' },
user: { required: true, message: '请输入所属用户', trigger: 'blur' },
department: { required: true, message: '请输入所属部门', trigger: 'blur' },
},
});
return {
...toRefs(state),
};
},
};
</script>

View File

@ -0,0 +1,51 @@
<template>
<div class="form-rules-two-container">
<el-form :model="form" :rules="rules" ref="formRulesTwoRef" size="small" label-width="100px" class="mt35">
<el-row :gutter="35">
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="手机" prop="phone">
<el-input v-model="form.phone" placeholder="请输入手机" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="性别">
<el-select v-model="form.sex" placeholder="请选择性别" clearable class="w100">
<el-option label="男" value="1"></el-option>
<el-option label="女" value="2"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="登录密码" prop="password">
<el-input v-model="form.password" placeholder="请输入登录密码" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="权限角色" prop="auth">
<el-input v-model="form.auth" placeholder="请输入权限角色" clearable></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</template>
<script lang="ts">
import { toRefs, reactive } from 'vue';
export default {
name: 'pagesFormRulesTwo',
setup() {
const state = reactive({
form: {},
rules: {
phone: { required: true, message: '请输入手机', trigger: 'blur' },
password: { required: true, message: '请输入登录密码', trigger: 'blur' },
auth: { required: true, message: '请输入权限角色', trigger: 'blur' },
},
});
return {
...toRefs(state),
};
},
};
</script>

View File

@ -0,0 +1,73 @@
<template>
<div class="form-rules-container">
<el-card shadow="hover" header="表单组件1"> <FormRulesOne :data="formRulesOneData" ref="pagesFormRulesOneRef" /></el-card>
<el-card shadow="hover" header="表单组件2" class="mt15"><FormRulesTwo ref="pagesFormRulesTwoRef" /> </el-card>
<el-card shadow="hover" header="表单组件3" class="mt15"> <FormRulesThree ref="pagesFormRulesThreeRef" /></el-card>
<el-row class="flex mt15">
<div class="flex-margin">
<el-button size="small" icon="el-icon-refresh-right" @click="onResetForm">重置表单</el-button>
<el-button size="small" type="primary" icon="iconfont icon-shuxing" @click="onSubmitForm">验证表单</el-button>
</div>
</el-row>
</div>
</template>
<script lang="ts">
import { toRefs, reactive, defineComponent, getCurrentInstance } from 'vue';
import { ElMessage } from 'element-plus';
import FormRulesOne from '/@/views/pages/formRules/component/formRulesOne.vue';
import FormRulesTwo from '/@/views/pages/formRules/component/formRulesTwo.vue';
import FormRulesThree from '/@/views/pages/formRules/component/formRulesThree.vue';
export default defineComponent({
name: 'pagesFormRules',
components: {
FormRulesOne,
FormRulesTwo,
FormRulesThree,
},
setup() {
const { proxy } = getCurrentInstance() as any;
const state = reactive({
formRulesOneData: {
name: 'lyt',
email: 'lyt123@.com',
autograph: 'lyt123456',
occupation: '1',
},
});
// 表单组件验证
const formRulesValidate = (pageRef, sonRef) => {
return new Promise((resolve) => {
proxy.$refs[pageRef].$refs[sonRef].validate((valid) => {
if (valid) resolve(valid);
});
});
};
// 表单组件重置
const formRulesResetFields = () => {
proxy.$refs.pagesFormRulesOneRef.$refs.formRulesOneRef.resetFields();
proxy.$refs.pagesFormRulesTwoRef.$refs.formRulesTwoRef.resetFields();
proxy.$refs.pagesFormRulesThreeRef.$refs.formRulesThreeRef.resetFields();
};
// 验证表单
const onSubmitForm = () => {
Promise.all([
formRulesValidate('pagesFormRulesOneRef', 'formRulesOneRef'),
formRulesValidate('pagesFormRulesTwoRef', 'formRulesTwoRef'),
formRulesValidate('pagesFormRulesThreeRef', 'formRulesThreeRef'),
]).then(() => {
ElMessage.success('表单全部验证成功');
});
};
// 重置表单
const onResetForm = () => {
formRulesResetFields();
};
return {
onSubmitForm,
onResetForm,
...toRefs(state),
};
},
});
</script>

View File

@ -23,8 +23,13 @@ export default defineComponent({
// 设置 view 的高度
const setViewHeight = computed(() => {
let { isTagsview } = store.state.themeConfig.themeConfig;
if (isTagsview) return `114px`;
else return `80px`;
let { isTagsViewCurrenFull } = store.state.tagsViewRoutes;
if (isTagsViewCurrenFull) {
return `30px`;
} else {
if (isTagsview) return `114px`;
else return `80px`;
}
});
// 页面加载时
onMounted(() => {

View File

@ -26,8 +26,13 @@ export default defineComponent({
// 设置 view 的高度
const setViewHeight = computed(() => {
let { isTagsview } = store.state.themeConfig.themeConfig;
if (isTagsview) return `114px`;
else return `80px`;
let { isTagsViewCurrenFull } = store.state.tagsViewRoutes;
if (isTagsViewCurrenFull) {
return `30px`;
} else {
if (isTagsview) return `114px`;
else return `80px`;
}
});
// 跳转到详情
const onGoDetailsClick = () => {

View File

@ -23,8 +23,13 @@ export default defineComponent({
// 设置 view 的高度
const setViewHeight = computed(() => {
let { isTagsview } = store.state.themeConfig.themeConfig;
if (isTagsview) return `114px`;
else return `80px`;
let { isTagsViewCurrenFull } = store.state.tagsViewRoutes;
if (isTagsViewCurrenFull) {
return `30px`;
} else {
if (isTagsview) return `114px`;
else return `80px`;
}
});
// 页面加载时
onMounted(() => {

View File

@ -26,8 +26,13 @@ export default defineComponent({
// 设置 view 的高度
const setViewHeight = computed(() => {
let { isTagsview } = store.state.themeConfig.themeConfig;
if (isTagsview) return `114px`;
else return `80px`;
let { isTagsViewCurrenFull } = store.state.tagsViewRoutes;
if (isTagsViewCurrenFull) {
return `30px`;
} else {
if (isTagsview) return `114px`;
else return `80px`;
}
});
// 跳转到详情
const onGoDetailsClick = () => {