Commit ed87d995 authored by renjintao's avatar renjintao

Merge branch 'product' of git.mes123.com:zhouyx/mes-ui into product-rjt

parents 68ab455e 094fd58a
...@@ -16,14 +16,10 @@ ...@@ -16,14 +16,10 @@
<td> <td>
<ul class="table_row_ul"> <ul class="table_row_ul">
<li> <li>
<a class="a_goIndex" @click="goIndex"> <a class="a_goIndex" @click="goIndex">首页一</a>
首页一
</a>
</li> </li>
<li> <li>
<a class="a_goIndex" @click="goIndexTwo"> <a class="a_goIndex" @click="goIndexTwo">首页二</a>
首页二
</a>
</li> </li>
</ul> </ul>
</td> </td>
...@@ -35,32 +31,31 @@ ...@@ -35,32 +31,31 @@
<td> <td>
<ul class="table_row_ul"> <ul class="table_row_ul">
<li v-for="(li) in item.children"> <li v-for="(li) in item.children">
<a @click="goPage(item,li)" :class="{'active': li.id === isActive}">{{li.title}}</a> <a
@click="goPage(item,li)"
:class="{'active': li.id === isActive}"
>{{li.title}}</a>
</li> </li>
</ul> </ul>
</td> </td>
</tr> </tr>
</table> </table>
</div> </div>
</span> </span>
</a> </a>
<!-- <i-header-breadcrumb v-if="showBreadcrumb && !headerMenu && !isMobile" ref="breadcrumb" /> --> <!-- <i-header-breadcrumb v-if="showBreadcrumb && !headerMenu && !isMobile" ref="breadcrumb" /> -->
<!-- {{}} --> <!-- {{}} -->
<Breadcrumb class="i-layout-header-breadcrumb" v-if="homeMenuItem==''"> <Breadcrumb class="i-layout-header-breadcrumb" v-if="homeMenuItem==''">
<BreadcrumbItem to="/" class="white"> <BreadcrumbItem to="/" class="white">
<Icon type="ios-home" />首页 <Icon type="ios-home" />首页
</BreadcrumbItem> </BreadcrumbItem>
</Breadcrumb> </Breadcrumb>
<Breadcrumb class="i-layout-header-breadcrumb" v-else-if="homeMenuItem!=''" separator=">"> <Breadcrumb class="i-layout-header-breadcrumb" v-else-if="homeMenuItem!=''" separator=">">
<BreadcrumbItem to="/" class="white"> <BreadcrumbItem to="/" class="white">
<Icon type="ios-home" />首页 <Icon type="ios-home" />首页
</BreadcrumbItem>
<BreadcrumbItem>
{{homeMenu}}
</BreadcrumbItem>
<BreadcrumbItem :to="parthto" class="white">
{{homeMenuItem}}
</BreadcrumbItem> </BreadcrumbItem>
<BreadcrumbItem>{{homeMenu}}</BreadcrumbItem>
<BreadcrumbItem :to="parthto" class="white">{{homeMenuItem}}</BreadcrumbItem>
</Breadcrumb> </Breadcrumb>
<i-header-search v-if="showSearch && !headerMenu && !isMobile && !showBreadcrumb" /> <i-header-search v-if="showSearch && !headerMenu && !isMobile && !showBreadcrumb" />
<div class="header_right"> <div class="header_right">
...@@ -77,6 +72,11 @@ ...@@ -77,6 +72,11 @@
<i-header-setting v-if="enableSetting && !isMobile" />--> <i-header-setting v-if="enableSetting && !isMobile" />-->
</div> </div>
</Header> </Header>
<div class="i-tabs">
<transition name="fade-quick">
<i-tabs v-if="tabs" v-show="showHeader" @on-reload="handleReload" />
</transition>
</div>
<Content class="i-layout-content"> <Content class="i-layout-content">
<keep-alive :include="keepAlive"> <keep-alive :include="keepAlive">
<nuxt v-if="loadRouter" /> <nuxt v-if="loadRouter" />
...@@ -137,9 +137,9 @@ export default { ...@@ -137,9 +137,9 @@ export default {
isDelayHideSider: false, // hack,当从隐藏侧边栏的 header 切换到正常 header 时,防止 Logo 抖动 isDelayHideSider: false, // hack,当从隐藏侧边栏的 header 切换到正常 header 时,防止 Logo 抖动
loadRouter: true, loadRouter: true,
homeMenu:'', homeMenu: "",
homeMenuItem:"", homeMenuItem: "",
parthto:'', parthto: ""
}; };
}, },
computed: { computed: {
...@@ -248,7 +248,8 @@ export default { ...@@ -248,7 +248,8 @@ export default {
}, 0); }, 0);
}, },
$route(to, from) { $route(to, from) {
if (to.name === from.name) {// 相同路由,不同参数,跳转时,重载页面 if (to.name === from.name) {
// 相同路由,不同参数,跳转时,重载页面
if (Setting.sameRouteForceUpdate) { if (Setting.sameRouteForceUpdate) {
this.handleReload(); this.handleReload();
} }
...@@ -267,7 +268,8 @@ export default { ...@@ -267,7 +268,8 @@ export default {
}, },
handleScroll() { handleScroll() {
if (!this.headerHide) return; if (!this.headerHide) return;
const scrollTop = document.body.scrollTop + document.documentElement.scrollTop; const scrollTop =
document.body.scrollTop + document.documentElement.scrollTop;
if (!this.ticking) { if (!this.ticking) {
this.ticking = true; this.ticking = true;
requestAnimation(() => { requestAnimation(() => {
...@@ -294,7 +296,8 @@ export default { ...@@ -294,7 +296,8 @@ export default {
// todo $menuHead.handleGetMenuHeight(); // todo $menuHead.handleGetMenuHeight();
} }
}, },
handleReload() {// 针对缓存的页面也生效 handleReload() {
// 针对缓存的页面也生效
const isCurrentPageCache = this.keepAlive.indexOf(this.$route.name) > -1; const isCurrentPageCache = this.keepAlive.indexOf(this.$route.name) > -1;
const pageName = this.$route.name; const pageName = this.$route.name;
if (isCurrentPageCache) { if (isCurrentPageCache) {
...@@ -308,24 +311,24 @@ export default { ...@@ -308,24 +311,24 @@ export default {
} }
}); });
}, },
goPage(u,li) { goPage(u, li) {
this.$router.push(li.path) this.$router.push(li.path);
this.isActive = li.id this.isActive = li.id;
this.homeMenu = u.title this.homeMenu = u.title;
this.homeMenuItem = li.title this.homeMenuItem = li.title;
this.parthto = li.path this.parthto = li.path;
}, },
goIndex(){ goIndex() {
this.$router.push("/") this.$router.push("/");
this.homeMenu = '' this.homeMenu = "";
this.homeMenuItem = '' this.homeMenuItem = "";
this.isActive = 0 this.isActive = 0;
}, },
goIndexTwo(){ goIndexTwo() {
this.$router.push("/home") this.$router.push("/home");
this.homeMenu = '' this.homeMenu = "";
this.homeMenuItem = '' this.homeMenuItem = "";
this.isActive = 0 this.isActive = 0;
} }
}, },
mounted() { mounted() {
...@@ -341,22 +344,26 @@ export default { ...@@ -341,22 +344,26 @@ export default {
</script> </script>
<style lang="less"> <style lang="less">
.i-layout-header-breadcrumb { .i-layout-header-breadcrumb {
color: #A7B8CC!important;//wheat color: #a7b8cc !important; //wheat
} }
.i-layout-header-breadcrumb .white .ivu-breadcrumb-item-link { .i-layout-header-breadcrumb .white .ivu-breadcrumb-item-link {
color: #ffffff!important;//wheat color: #ffffff !important; //wheat
} }
.ivu-icon-ios-home{ .ivu-icon-ios-home {
font-size: 20px; font-size: 20px;
} }
.white{ .white {
color: #ffffff!important; color: #ffffff !important;
} }
.product-layout { .product-layout {
.i-layout-content { .i-layout-content {
padding: 5px 10px; padding: 5px 10px;
} }
.i-tabs {
width: 100% !important;
height: 40px;
}
.ivu-layout-header { .ivu-layout-header {
height: 50px; height: 50px;
line-height: 50px; line-height: 50px;
......
<template> <template>
<div class="i-layout-tabs" :class="classes" :style="styles"> <div class="i-layout-tabs" :class="classes" :style="styles">
<div class="i-layout-tabs-main"> <div class="i-layout-tabs-main">
<Tabs <Tabs
type="card" type="card"
:value="current" :value="current"
:animated="false" :animated="false"
closable closable
@on-click="handleClickTab" @on-click="handleClickTab"
@on-tab-remove="handleClickClose" @on-tab-remove="handleClickClose"
> >
<TabPane <TabPane
v-for="page in opened" v-for="page in opened"
:key="page.fullPath" :key="page.fullPath"
:label="(h) => tabLabel(h, page)" :label="(h) => tabLabel(h, page)"
:name="page.fullPath" :name="page.fullPath"
:closable="page.meta && page.meta.closable" :closable="page.meta && page.meta.closable"
/> />
</Tabs> </Tabs>
<Dropdown class="i-layout-tabs-close" @on-click="handleClose"> <Dropdown class="i-layout-tabs-close" @on-click="handleClose">
<div class="i-layout-tabs-close-main"> <div class="i-layout-tabs-close-main">
<Icon type="ios-arrow-down" /> <Icon type="ios-arrow-down" />
</div>
<DropdownMenu slot="list">
<DropdownItem name="left">
<Icon type="md-arrow-back" />
{{ $t('basicLayout.tabs.left') }}
</DropdownItem>
<DropdownItem name="right">
<Icon type="md-arrow-forward" />
{{ $t('basicLayout.tabs.right') }}
</DropdownItem>
<DropdownItem name="other">
<Icon type="md-close" />
{{ $t('basicLayout.tabs.other') }}
</DropdownItem>
<DropdownItem name="all">
<Icon type="md-close-circle" />
{{ $t('basicLayout.tabs.all') }}
</DropdownItem>
</DropdownMenu>
</Dropdown>
</div> </div>
<DropdownMenu slot="list">
<DropdownItem name="left">
<Icon type="md-arrow-back" />
{{ $t('basicLayout.tabs.left') }}
</DropdownItem>
<DropdownItem name="right">
<Icon type="md-arrow-forward" />
{{ $t('basicLayout.tabs.right') }}
</DropdownItem>
<DropdownItem name="other">
<Icon type="md-close" />
{{ $t('basicLayout.tabs.other') }}
</DropdownItem>
<DropdownItem name="all">
<Icon type="md-close-circle" />
{{ $t('basicLayout.tabs.all') }}
</DropdownItem>
</DropdownMenu>
</Dropdown>
</div> </div>
</div>
</template> </template>
<script> <script>
import { mapState, mapGetters, mapActions } from 'vuex'; import { mapState, mapGetters, mapActions } from "vuex";
import menuSider from '@/menu/sider'; import menuSider from "@/menu/sider";
import tTitle from '../mixins/translate-title'; import tTitle from "../mixins/translate-title";
import Setting from '@/setting'; import Setting from "@/setting";
import { getAllSiderMenu } from '@/libs/system'; import { getAllSiderMenu } from "@/libs/system";
export default { export default {
name: 'iTabs', name: "iTabs",
mixins: [ tTitle ], mixins: [tTitle],
computed: { computed: {
...mapState('admin/page', [ ...mapState("admin/page", ["opened", "current"]),
'opened', ...mapState("admin/layout", [
'current' "showTabsIcon",
]), "tabsFix",
...mapState('admin/layout', [ "tabsReload",
'showTabsIcon', "headerFix",
'tabsFix', "headerStick",
'tabsReload', "isMobile",
'headerFix', "menuCollapse"
'headerStick', ]),
'isMobile', ...mapGetters("admin/menu", ["hideSider"]),
'menuCollapse' classes() {
]), // return {
...mapGetters('admin/menu', [ // "i-layout-tabs-fix": this.tabsFix
'hideSider' // };
]), },
classes () { isHeaderStick() {
return { return this.hideSider;
'i-layout-tabs-fix': this.tabsFix },
} styles() {
}, let style = {};
isHeaderStick () { if (this.tabsFix && !this.headerFix) {
return this.hideSider; style.top = `${64 - this.scrollTop}px`;
}, }
styles () {
let style = {};
if (this.tabsFix && !this.headerFix) {
style.top = `${64 - this.scrollTop}px`;
}
const menuWidth = this.isHeaderStick ? 0 : this.menuCollapse ? 80 : Setting.menuSideWidth; const menuWidth = this.isHeaderStick
if (!this.isMobile && this.tabsFix) { ? 0
style.width = `calc(100% - ${menuWidth}px)`; : this.menuCollapse
style.left = `${menuWidth}px`; ? 80
} : Setting.menuSideWidth;
// if (!this.isMobile && this.tabsFix) {
// style.width = `calc(100% - ${menuWidth}px)`;
// style.left = `${menuWidth}px`;
// }
return style; return style;
} }
}, },
data () { data() {
return { return {
// 得到所有侧边菜单,并转为平级,查询图标用 // 得到所有侧边菜单,并转为平级,查询图标用
allSiderMenu: getAllSiderMenu(menuSider), allSiderMenu: getAllSiderMenu(menuSider),
scrollTop: 0 scrollTop: 0
} };
}, },
methods: { methods: {
...mapActions('admin/page', [ ...mapActions("admin/page", [
'close', "close",
'closeLeft', "closeLeft",
'closeRight', "closeRight",
'closeOther', "closeOther",
'closeAll' "closeAll"
]), ]),
tabLabel (h, page) { tabLabel(h, page) {
const title = h('span', this.tTitle(page.meta.title) || '未命名'); const title = h("span", this.tTitle(page.meta.title) || "未命名");
let slot = []; let slot = [];
if (this.showTabsIcon) {
const fullPathWithoutQuery = page.fullPath.indexOf('?') >= 0 ? page.fullPath.split('?')[0] : page.fullPath;
const currentMenu = this.allSiderMenu.find(menu => menu.path === fullPathWithoutQuery) || {};
let icon; if (this.showTabsIcon) {
if (currentMenu.icon) { const fullPathWithoutQuery =
icon = h('Icon', { page.fullPath.indexOf("?") >= 0
props: { ? page.fullPath.split("?")[0]
type: currentMenu.icon : page.fullPath;
} const currentMenu =
}); this.allSiderMenu.find(menu => menu.path === fullPathWithoutQuery) ||
} else if (currentMenu.custom) { {};
icon = h('Icon', {
props: {
custom: currentMenu.custom
}
});
} else if (currentMenu.img) {
icon = h('img', {
attrs: {
src: currentMenu.img
}
});
}
if (icon) slot.push(icon); let icon;
slot.push(title); if (currentMenu.icon) {
} else { icon = h("Icon", {
slot.push(title); props: {
} type: currentMenu.icon
}
});
} else if (currentMenu.custom) {
icon = h("Icon", {
props: {
custom: currentMenu.custom
}
});
} else if (currentMenu.img) {
icon = h("img", {
attrs: {
src: currentMenu.img
}
});
}
return h('div', { if (icon) slot.push(icon);
class: 'i-layout-tabs-title' slot.push(title);
}, slot); } else {
}, slot.push(title);
handleClickTab (tabName) { }
if (tabName === this.current) {
if (this.tabsReload) {
this.$emit('on-reload');
}
} else {
const page = this.opened.find(page => page.fullPath === tabName);
const { name, params, query } = page;
if (page) this.$router.push({ name, params, query }, () => {}); return h(
} "div",
}, {
handleClickClose (tagName) { class: "i-layout-tabs-title"
this.close({
tagName
});
},
handleScroll () {
if (this.tabsFix && !this.headerFix) {
const scrollTop = document.body.scrollTop + document.documentElement.scrollTop;
this.scrollTop = scrollTop > 64 ? 64 : scrollTop;
}
},
handleClose (name) {
const params = {
pageSelect: this.current
};
switch (name) {
case 'left':
this.closeLeft(params);
break;
case 'right':
this.closeRight(params);
break;
case 'other':
this.closeOther(params);
break;
case 'all':
this.closeAll();
break;
}
}
},
mounted () {
document.addEventListener('scroll', this.handleScroll, { passive: true });
this.handleScroll();
}, },
beforeDestroy () { slot
document.removeEventListener('scroll', this.handleScroll); );
},
handleClickTab(tabName) {
if (tabName === this.current) {
if (this.tabsReload) {
this.$emit("on-reload");
} }
} else {
const page = this.opened.find(page => page.fullPath === tabName);
const { name, params, query } = page;
if (page) this.$router.push({ name, params, query }, () => {});
}
},
handleClickClose(tagName) {
this.close({
tagName
});
},
handleScroll() {
// if (this.tabsFix && !this.headerFix) {
// const scrollTop = document.body.scrollTop + document.documentElement.scrollTop;
// this.scrollTop = scrollTop > 64 ? 64 : scrollTop;
// }
},
handleClose(name) {
const params = {
pageSelect: this.current
};
switch (name) {
case "left":
this.closeLeft(params);
break;
case "right":
this.closeRight(params);
break;
case "other":
this.closeOther(params);
break;
case "all":
this.closeAll();
break;
}
} }
},
mounted() {
document.addEventListener("scroll", this.handleScroll, { passive: true });
this.handleScroll();
},
beforeDestroy() {
document.removeEventListener("scroll", this.handleScroll);
}
};
</script> </script>
...@@ -363,7 +363,7 @@ export default { ...@@ -363,7 +363,7 @@ export default {
}, },
created() { created() {
this.treeHeight = window.innerHeight - 140; this.treeHeight = window.innerHeight - 140;
this.tableHeight = window.innerHeight - 210; this.tableHeight = window.innerHeight - 250;
this.newColumn = this.column; this.newColumn = this.column;
this.tableTata(this.selectName); this.tableTata(this.selectName);
}, },
...@@ -376,7 +376,7 @@ export default { ...@@ -376,7 +376,7 @@ export default {
return (() => { return (() => {
window.screenHeight = window.innerHeight; window.screenHeight = window.innerHeight;
this.treeHeight = window.screenHeight - 140; this.treeHeight = window.screenHeight - 140;
this.tableHeight = window.innerHeight - 210; this.tableHeight = window.innerHeight - 250;
})(); })();
}; };
}, },
......
...@@ -9,96 +9,117 @@ import { getAllSiderMenu, includeArray } from '@/libs/system'; ...@@ -9,96 +9,117 @@ import { getAllSiderMenu, includeArray } from '@/libs/system';
// 判定是否需要缓存 // 判定是否需要缓存
const isKeepAlive = data => get(data, 'meta.cache', false); const isKeepAlive = data => get(data, 'meta.cache', false);
export const strict=false; export const strict = false;
export const state=()=>({ export const state = () => ({
// 可以在多页 tab 模式下显示的页面 // 可以在多页 tab 模式下显示的页面
pool: [], pool: [],
// 当前显示的多页面列表 // 当前显示的多页面列表
opened: Setting.page.opened, opened: Setting.page.opened,
// 当前页面 // 当前页面
current: '', current: '',
// 需要缓存的页面 name // 需要缓存的页面 name
keepAlive: [] keepAlive: []
}) })
export const actions={ export const actions = {
/** /**
* @description 从持久化数据载入分页列表 * @description 从持久化数据载入分页列表
*/ */
openedLoad ({ state, commit, dispatch, rootState }) { openedLoad({ state, commit, dispatch, rootState }) {
return new Promise(async resolve => { return new Promise(async resolve => {
// store 赋值 // store 赋值
const value = await dispatch('admin/db/get', { const value = await dispatch('admin/db/get', {
dbName: 'sys', dbName: 'sys',
path: 'page.opened', path: 'page.opened',
defaultValue: Setting.page.opened, defaultValue: Setting.page.opened,
user: true user: true
}, { root: true }); }, { root: true });
// 在处理函数中进行数据优化 过滤掉现在已经失效的页签或者已经改变了信息的页签 // 在处理函数中进行数据优化 过滤掉现在已经失效的页签或者已经改变了信息的页签
// 以 fullPath 字段为准 // 以 fullPath 字段为准
// 如果页面过多的话可能需要优化算法 // 如果页面过多的话可能需要优化算法
// valid 有效列表 1, 1, 0, 1 => 有效, 有效, 失效, 有效 // valid 有效列表 1, 1, 0, 1 => 有效, 有效, 失效, 有效
const valid = []; const valid = [];
// 处理数据 // 处理数据
state.opened = value.map(opened => { state.opened = value.map(opened => {
// 忽略首页 // 忽略首页
if (opened.fullPath === '/index') { if (opened.fullPath === '/index') {
valid.push(1); valid.push(1);
return opened; return opened;
} }
// 尝试在所有的支持多标签页的页面里找到 name 匹配的页面 // 尝试在所有的支持多标签页的页面里找到 name 匹配的页面
const find = state.pool.find(item => item.name === opened.name); const find = state.pool.find(item => item.name === opened.name);
// 记录有效或无效信息 // 记录有效或无效信息
valid.push(find ? 1 : 0); valid.push(find ? 1 : 0);
// 返回合并后的数据 新的覆盖旧的 // 返回合并后的数据 新的覆盖旧的
// 新的数据中一般不会携带 params 和 query, 所以旧的参数会留存 // 新的数据中一般不会携带 params 和 query, 所以旧的参数会留存
return Object.assign({}, opened, find); return Object.assign({}, opened, find);
}) })
.filter((opened, index) => valid[index] === 1) .filter((opened, index) => valid[index] === 1)
// 对 menu 鉴权过滤 // 对 menu 鉴权过滤
.filter(opened => { .filter(opened => {
const allSiderMenu = getAllSiderMenu(menuSider); const allSiderMenu = getAllSiderMenu(menuSider);
const find = allSiderMenu.find(item => item.path === opened.fullPath); const find = allSiderMenu.find(item => item.path === opened.fullPath);
let state = true; let state = true;
if (find && find.auth) { if (find && find.auth) {
const userInfo = rootState.admin.user.info; const userInfo = rootState.admin.user.info;
// @权限 // @权限
const access = userInfo.access; const access = userInfo.access;
// 如果用户当前的权限,不是该 menu 对应的 权限,则过滤这个 Tab // 如果用户当前的权限,不是该 menu 对应的 权限,则过滤这个 Tab
if (access && !includeArray(find.auth, access)) state = false; if (access && !includeArray(find.auth, access)) state = false;
} }
return state; return state;
}); });
// 根据 opened 数据生成缓存设置 // 根据 opened 数据生成缓存设置
commit('keepAliveRefresh'); commit('keepAliveRefresh');
// end // end
resolve(); resolve();
}); });
}, },
/** /**
* 将 opened 属性赋值并持久化 在这之前请先确保已经更新了 state.opened * 将 opened 属性赋值并持久化 在这之前请先确保已经更新了 state.opened
*/ */
opened2db ({ state, dispatch }) { opened2db({ state, dispatch }) {
return new Promise(async resolve => { return new Promise(async resolve => {
// 设置数据 // 设置数据
dispatch('admin/db/set', { dispatch('admin/db/set', {
dbName: 'sys', dbName: 'sys',
path: 'page.opened', path: 'page.opened',
value: state.opened, value: state.opened,
user: true user: true
}, { root: true }); }, { root: true });
// end // end
resolve(); resolve();
}); });
}, },
/** /**
* @description 更新页面列表上的某一项 * @description 更新页面列表上的某一项
* @param {Object} param { index, params, query, fullPath } 路由信息 * @param {Object} param { index, params, query, fullPath } 路由信息
*/ */
openedUpdate ({ state, commit, dispatch }, { index, params, query, fullPath, meta }) { openedUpdate({ state, commit, dispatch }, { index, params, query, fullPath, meta }) {
return new Promise(async resolve => { return new Promise(async resolve => {
// 更新页面列表某一项 // 更新页面列表某一项
let page = state.opened[index];
page.params = params || page.params;
page.query = query || page.query;
page.fullPath = fullPath || page.fullPath;
page.meta = meta || page.meta;
state.opened.splice(index, 1, page);
// 持久化
await dispatch('opened2db');
// end
resolve();
});
},
/**
* @description 更新页面当前项
* @param {Object} param { params, query, fullPath } 路由信息
*/
currentUpdate({ state, commit, dispatch }, { params, query, fullPath, meta }) {
return new Promise(async resolve => {
setTimeout(async () => {
// 更新当前项
const index = state.opened.findIndex(item => item.fullPath === state.current);
let page = state.opened[index]; let page = state.opened[index];
page.params = params || page.params; page.params = params || page.params;
page.query = query || page.query; page.query = query || page.query;
...@@ -109,324 +130,314 @@ export const actions={ ...@@ -109,324 +130,314 @@ export const actions={
await dispatch('opened2db'); await dispatch('opened2db');
// end // end
resolve(); resolve();
}, 0);
});
},
/**
* @description 新增一个 tag (打开一个页面)
* @param {Object} param new tag info
*/
add({ state, commit, dispatch }, { tag, params, query, fullPath }) {
return new Promise(async resolve => {
// 设置新的 tag 在新打开一个以前没打开过的页面时使用
let newTag = tag;
newTag.params = params || newTag.params;
newTag.query = query || newTag.query;
newTag.fullPath = fullPath || newTag.fullPath;
// 添加进当前显示的页面数组
state.opened.push(newTag);
// 如果这个页面需要缓存 将其添加到缓存设置
if (isKeepAlive(newTag)) {
commit('keepAlivePush', tag.name);
}
// 持久化
await dispatch('opened2db');
// end
resolve();
});
},
/**
* @description 打开一个新的页面
* @param {Object} param 从路由钩子的 to 对象上获取 { name, params, query, fullPath } 路由信息
*/
open({ state, commit, dispatch }, { name, params, query, fullPath }) {
return new Promise(async resolve => {
// 已经打开的页面
let opened = state.opened;
// 判断此页面是否已经打开 并且记录位置
let pageOpenedIndex = 0;
const pageOpened = opened.find((page, index) => {
const same = page.fullPath === fullPath;
pageOpenedIndex = same ? index : pageOpenedIndex;
return same;
}); });
}, if (pageOpened) {
/** // 页面以前打开过
* @description 更新页面当前项 await dispatch('openedUpdate', {
* @param {Object} param { params, query, fullPath } 路由信息 index: pageOpenedIndex,
*/ params,
currentUpdate ({ state, commit, dispatch }, { params, query, fullPath, meta }) { query,
return new Promise(async resolve => { fullPath
setTimeout(async () => {
// 更新当前项
const index = state.opened.findIndex(item => item.fullPath === state.current);
let page = state.opened[index];
page.params = params || page.params;
page.query = query || page.query;
page.fullPath = fullPath || page.fullPath;
page.meta = meta || page.meta;
state.opened.splice(index, 1, page);
// 持久化
await dispatch('opened2db');
// end
resolve();
}, 0);
});
},
/**
* @description 新增一个 tag (打开一个页面)
* @param {Object} param new tag info
*/
add ({ state, commit, dispatch }, { tag, params, query, fullPath }) {
return new Promise(async resolve => {
// 设置新的 tag 在新打开一个以前没打开过的页面时使用
let newTag = tag;
newTag.params = params || newTag.params;
newTag.query = query || newTag.query;
newTag.fullPath = fullPath || newTag.fullPath;
// 添加进当前显示的页面数组
state.opened.push(newTag);
// 如果这个页面需要缓存 将其添加到缓存设置
if (isKeepAlive(newTag)) {
commit('keepAlivePush', tag.name);
}
// 持久化
await dispatch('opened2db');
// end
resolve();
});
},
/**
* @description 打开一个新的页面
* @param {Object} param 从路由钩子的 to 对象上获取 { name, params, query, fullPath } 路由信息
*/
open ({ state, commit, dispatch }, { name, params, query, fullPath }) {
return new Promise(async resolve => {
// 已经打开的页面
let opened = state.opened;
// 判断此页面是否已经打开 并且记录位置
let pageOpenedIndex = 0;
const pageOpened = opened.find((page, index) => {
const same = page.fullPath === fullPath;
pageOpenedIndex = same ? index : pageOpenedIndex;
return same;
}); });
if (pageOpened) { } else {
// 页面以前打开过 // 页面以前没有打开过
await dispatch('openedUpdate', { let page = state.pool.find(t => t.name === name);
index: pageOpenedIndex, // 如果这里没有找到 page 代表这个路由虽然在框架内 但是不参与标签页显示
if (page) {
await dispatch('add', {
tag: Object.assign({}, page),
params, params,
query, query,
fullPath fullPath
}); });
} else {
// 页面以前没有打开过
let page = state.pool.find(t => t.name === name);
// 如果这里没有找到 page 代表这个路由虽然在框架内 但是不参与标签页显示
if (page) {
await dispatch('add', {
tag: Object.assign({}, page),
params,
query,
fullPath
});
}
} }
commit('currentSet', fullPath); }
// end commit('currentSet', fullPath);
resolve(); // end
}); resolve();
}, });
/** },
* @description 关闭一个 tag (关闭一个页面) /**
* @param {Object} param { tagName: 要关闭的标签名字 } * @description 关闭一个 tag (关闭一个页面)
*/ * @param {Object} param { tagName: 要关闭的标签名字 }
close ({ state, commit, dispatch }, { tagName }) { */
return new Promise(async resolve => { close({ state, commit, dispatch }, { tagName }) {
// 下个新的页面 return new Promise(async resolve => {
let newPage = state.opened[0]; // 下个新的页面
const isCurrent = state.current === tagName; let newPage = state.opened[0];
// 如果关闭的页面就是当前显示的页面 const isCurrent = state.current === tagName;
if (isCurrent) { // 如果关闭的页面就是当前显示的页面
// 去找一个新的页面 if (isCurrent) {
let len = state.opened.length; // 去找一个新的页面
for (let i = 0; i < len; i++) { let len = state.opened.length;
if (state.opened[i].fullPath === tagName) { for (let i = 0; i < len; i++) {
// 是否只剩最后一个,是则跳首页 if (state.opened[i].fullPath === tagName) {
if (len > 1) { // 是否只剩最后一个,是则跳首页
// 如果是最后一个,则向前一个跳,否则向下一个跳 if (len > 1) {
if (i === len - 1) { // 如果是最后一个,则向前一个跳,否则向下一个跳
newPage = state.opened[i - 1]; if (i === len - 1) {
} else { newPage = state.opened[i - 1];
newPage = state.opened[i + 1];
}
} else { } else {
newPage = {}; newPage = state.opened[i + 1];
} }
break; } else {
newPage = {};
} }
break;
} }
} }
// 找到这个页面在已经打开的数据里是第几个 }
const index = state.opened.findIndex(page => page.fullPath === tagName); // 找到这个页面在已经打开的数据里是第几个
if (index >= 0) { const index = state.opened.findIndex(page => page.fullPath === tagName);
// 如果这个页面是缓存的页面 将其在缓存设置中删除 if (index >= 0) {
commit('keepAliveRemove', state.opened[index].name); // 如果这个页面是缓存的页面 将其在缓存设置中删除
// 更新数据 删除关闭的页面 commit('keepAliveRemove', state.opened[index].name);
state.opened.splice(index, 1); // 更新数据 删除关闭的页面
} state.opened.splice(index, 1);
// 持久化 }
await dispatch('opened2db'); // 持久化
// 最后需要判断是否需要跳到首页 await dispatch('opened2db');
if (isCurrent) { // 最后需要判断是否需要跳到首页
const { name = 'index', params = {}, query = {} } = newPage; if (isCurrent) {
let routerObj = { const { name = 'index', params = {}, query = {} } = newPage;
name, let routerObj = {
params, name,
query params,
}; query
$nuxt.$router.push(routerObj, () => {}); };
} $nuxt.$router.push(routerObj, () => { });
// end }
resolve(); // end
}); resolve();
}, });
/** },
* @description 关闭当前标签左边的标签 /**
* @param {Object} param { pageSelect: 当前选中的tagName } * @description 关闭当前标签左边的标签
*/ * @param {Object} param { pageSelect: 当前选中的tagName }
closeLeft ({ state, commit, dispatch }, { pageSelect } = {}) { */
return new Promise(async resolve => { closeLeft({ state, commit, dispatch }, { pageSelect } = {}) {
const pageAim = pageSelect || state.current;
let currentIndex = 0; return new Promise(async resolve => {
state.opened.forEach((page, index) => { const pageAim = pageSelect || state.current;
if (page.fullPath === pageAim) { let currentIndex = 0;
currentIndex = index; state.opened.forEach((page, index) => {
} if (page.fullPath === pageAim) {
}); currentIndex = index;
if (currentIndex > 0) {
// 删除打开的页面 并在缓存设置中删除
state.opened.splice(1, currentIndex - 1).forEach(({ name }) => commit('keepAliveRemove', name));
}
state.current = pageAim;
if ($nuxt.$router.fullPath !== pageAim) {
$nuxt.$router.push(pageAim);
} }
// 持久化
await dispatch('opened2db');
// end
resolve();
}); });
}, if (currentIndex > 0) {
/**
* @description 关闭当前标签右边的标签
* @param {Object} param { pageSelect: 当前选中的tagName }
*/
closeRight ({ state, commit, dispatch }, { pageSelect } = {}) {
return new Promise(async resolve => {
const pageAim = pageSelect || state.current;
let currentIndex = 0;
state.opened.forEach((page, index) => {
if (page.fullPath === pageAim) {
currentIndex = index;
}
});
// 删除打开的页面 并在缓存设置中删除 // 删除打开的页面 并在缓存设置中删除
state.opened.splice(currentIndex + 1).forEach(({ name }) => commit('keepAliveRemove', name)); state.opened.splice(1, currentIndex - 1).forEach(({ name }) => commit('keepAliveRemove', name));
// 设置当前的页面
state.current = pageAim; }
if ($nuxt.$router.fullPath !== pageAim) { if (state.opened.length == 2) {
$nuxt.$router.push(pageAim); state.opened.splice(0, 1);
}
state.current = pageAim;
if ($nuxt.$router.fullPath !== pageAim) {
$nuxt.$router.push(pageAim);
}
// 持久化
await dispatch('opened2db');
// end
resolve();
});
},
/**
* @description 关闭当前标签右边的标签
* @param {Object} param { pageSelect: 当前选中的tagName }
*/
closeRight({ state, commit, dispatch }, { pageSelect } = {}) {
return new Promise(async resolve => {
const pageAim = pageSelect || state.current;
let currentIndex = 0;
state.opened.forEach((page, index) => {
if (page.fullPath === pageAim) {
currentIndex = index;
} }
// 持久化
await dispatch('opened2db');
// end
resolve();
}); });
}, // 删除打开的页面 并在缓存设置中删除
/** state.opened.splice(currentIndex + 1).forEach(({ name }) => commit('keepAliveRemove', name));
* @description 关闭当前激活之外的 tag // 设置当前的页面
* @param {Object} param { pageSelect: 当前选中的tagName } state.current = pageAim;
*/ if ($nuxt.$router.fullPath !== pageAim) {
closeOther ({ state, commit, dispatch }, { pageSelect } = {}) { $nuxt.$router.push(pageAim);
return new Promise(async resolve => { }
const pageAim = pageSelect || state.current; // 持久化
let currentIndex = 0; await dispatch('opened2db');
state.opened.forEach((page, index) => { // end
if (page.fullPath === pageAim) { resolve();
currentIndex = index; });
} },
}); /**
// 删除打开的页面数据 并更新缓存设置 * @description 关闭当前激活之外的 tag
if (currentIndex === 0) { * @param {Object} param { pageSelect: 当前选中的tagName }
state.opened.splice(1).forEach(({ name }) => commit('keepAliveRemove', name)); */
} else { closeOther({ state, commit, dispatch }, { pageSelect } = {}) {
state.opened.splice(currentIndex + 1).forEach(({ name }) => commit('keepAliveRemove', name)); return new Promise(async resolve => {
state.opened.splice(1, currentIndex - 1).forEach(({ name }) => commit('keepAliveRemove', name)); const pageAim = pageSelect || state.current;
} let currentIndex = 0;
// 设置新的页面 state.opened.forEach((page, index) => {
state.current = pageAim; if (page.fullPath === pageAim) {
if ($nuxt.$router.fullPath !== pageAim) { currentIndex = index;
$nuxt.$router.push(pageAim);
} }
// 持久化
await dispatch('opened2db');
// end
resolve();
}); });
}, // 删除打开的页面数据 并更新缓存设置
/** if (currentIndex === 0) {
* @description 关闭所有 tag
* @param {Object} state vuex state
*/
closeAll ({ state, commit, dispatch }) {
return new Promise(async resolve => {
// 删除打开的页面 并在缓存设置中删除
state.opened.splice(1).forEach(({ name }) => commit('keepAliveRemove', name)); state.opened.splice(1).forEach(({ name }) => commit('keepAliveRemove', name));
// 持久化 } else {
await dispatch('opened2db'); state.opened.splice(currentIndex + 1).forEach(({ name }) => commit('keepAliveRemove', name));
// 关闭所有的标签页后需要判断一次现在是不是在首页 state.opened.splice(1, currentIndex - 1).forEach(({ name }) => commit('keepAliveRemove', name));
if ($nuxt.$router.name !== 'index') { }
$nuxt.$router.push({ if (state.opened.length == 2) {
name: 'index' state.opened.splice(0, 1);
}, () => {}); }
} // 设置新的页面
// end state.current = pageAim;
resolve(); if ($nuxt.$router.fullPath !== pageAim) {
}); $nuxt.$router.push(pageAim);
} }
// 持久化
await dispatch('opened2db');
// end
resolve();
});
},
/**
* @description 关闭所有 tag
* @param {Object} state vuex state
*/
closeAll({ state, commit, dispatch }) {
return new Promise(async resolve => {
// 删除打开的页面 并在缓存设置中删除
state.opened.splice(0).forEach(({ name }) => commit('keepAliveRemove', name));
// 持久化
await dispatch('opened2db');
// 关闭所有的标签页后需要判断一次现在是不是在首页
// if ($nuxt.$router.name !== 'index') {
// $nuxt.$router.push({
// name: 'index'
// }, () => { });
// }
// end
resolve();
});
}
} }
export const mutations={ export const mutations = {
/** /**
* @class keepAlive * @class keepAlive
* @description 从已经打开的页面记录中更新需要缓存的页面记录 * @description 从已经打开的页面记录中更新需要缓存的页面记录
* @param {Object} state vuex state * @param {Object} state vuex state
*/ */
keepAliveRefresh (state) { keepAliveRefresh(state) {
state.keepAlive = state.opened.filter(item => isKeepAlive(item)).map(e => e.name); state.keepAlive = state.opened.filter(item => isKeepAlive(item)).map(e => e.name);
}, },
/** /**
* @description 删除一个页面的缓存设置 * @description 删除一个页面的缓存设置
* @param {Object} state vuex state * @param {Object} state vuex state
* @param {String} name name * @param {String} name name
*/ */
keepAliveRemove (state, name) { keepAliveRemove(state, name) {
const list = [ ...state.keepAlive ]; const list = [...state.keepAlive];
const index = list.findIndex(item => item === name); const index = list.findIndex(item => item === name);
if (index !== -1) {
list.splice(index, 1);
state.keepAlive = list;
}
if (state.opened.length == 2) {
state.opened.splice(0, 1);
}
if (index !== -1) { },
list.splice(index, 1); /**
state.keepAlive = list; * @description 增加一个页面的缓存设置
} * @param {Object} state vuex state
}, * @param {String} name name
/** */
* @description 增加一个页面的缓存设置 keepAlivePush(state, name) {
* @param {Object} state vuex state const keep = [...state.keepAlive];
* @param {String} name name keep.push(name);
*/ state.keepAlive = keep;
keepAlivePush (state, name) { },
const keep = [ ...state.keepAlive ]; /**
keep.push(name); * @description 清空页面缓存设置
state.keepAlive = keep; * @param {Object} state vuex state
}, */
/** keepAliveClean(state) {
* @description 清空页面缓存设置 state.keepAlive = [];
* @param {Object} state vuex state },
*/ /**
keepAliveClean (state) { * @class current
state.keepAlive = []; * @description 设置当前激活的页面 fullPath
}, * @param {Object} state vuex state
/** * @param {String} fullPath new fullPath
* @class current */
* @description 设置当前激活的页面 fullPath currentSet(state, fullPath) {
* @param {Object} state vuex state state.current = fullPath;
* @param {String} fullPath new fullPath },
*/ /**
currentSet (state, fullPath) { * @class pool
state.current = fullPath; * @description 保存 pool (候选池)
}, * @param {Object} state vuex state
/** * @param {Array} routes routes
* @class pool */
* @description 保存 pool (候选池) init(state, routes) {
* @param {Object} state vuex state const pool = [];
* @param {Array} routes routes const push = function (routes) {
*/ routes.forEach(route => {
init (state, routes) { if (route.children) {
const pool = []; push(route.children);
const push = function (routes) { } else {
routes.forEach(route => { if (!route.hidden) {
if (route.children) { const { meta, name, path } = route;
push(route.children); pool.push({ meta, name, path });
} else {
if (!route.hidden) {
const { meta, name, path } = route;
pool.push({ meta, name, path });
}
} }
}) }
}; })
push(routes); };
state.pool = pool; push(routes);
} state.pool = pool;
}
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment