Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
Admin
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
周远喜
Admin
Commits
fe605615
Commit
fe605615
authored
Mar 14, 2020
by
周远喜
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
框架也处理完成。
parent
4e2fc099
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
38 additions
and
1289 deletions
+38
-1289
index.vue
layouts/basic-layout/index.vue
+2
-1
default.vue
layouts/default.vue
+6
-52
iview.js
plugins/iview.js
+3
-0
i18n.js
store/admin/i18n.js
+27
-1
index.js
store/modules/admin/index.js
+0
-16
account.js
store/modules/admin/modules/account.js
+0
-136
db.js
store/modules/admin/modules/db.js
+0
-223
i18n.js
store/modules/admin/modules/i18n.js
+0
-77
layout.js
store/modules/admin/modules/layout.js
+0
-89
log.js
store/modules/admin/modules/log.js
+0
-77
menu.js
store/modules/admin/modules/menu.js
+0
-133
page.js
store/modules/admin/modules/page.js
+0
-433
user.js
store/modules/admin/modules/user.js
+0
-51
No files found.
layouts/basic-layout/index.vue
View file @
fe605615
...
...
@@ -31,7 +31,8 @@
</transition>
<div
class=
"i-layout-content-main"
>
<keep-alive
:include=
"keepAlive"
>
<router-view
v-if=
"loadRouter"
/>
<!--
<router-view
v-if=
"loadRouter"
/>
-->
<nuxt
v-if=
"loadRouter"
/>
</keep-alive>
</div>
</Content>
...
...
layouts/default.vue
View file @
fe605615
<
template
>
<div>
<nuxt
/>
</div>
<MainLayout/>
</
template
>
<
style
>
html
{
font-family
:
'Source Sans Pro'
,
-apple-system
,
BlinkMacSystemFont
,
'Segoe UI'
,
Roboto
,
'Helvetica Neue'
,
Arial
,
sans-serif
;
font-size
:
16px
;
word-spacing
:
1px
;
-ms-text-size-adjust
:
100%
;
-webkit-text-size-adjust
:
100%
;
-moz-osx-font-smoothing
:
grayscale
;
-webkit-font-smoothing
:
antialiased
;
box-sizing
:
border-box
;
<
script
>
import
MainLayout
from
'./basic-layout'
export
default
{
components
:{
MainLayout
}
}
*,
*
:before
,
*
:after
{
box-sizing
:
border-box
;
margin
:
0
;
}
.button--green
{
display
:
inline-block
;
border-radius
:
4px
;
border
:
1px
solid
#3b8070
;
color
:
#3b8070
;
text-decoration
:
none
;
padding
:
10px
30px
;
}
.button--green
:hover
{
color
:
#fff
;
background-color
:
#3b8070
;
}
.button--grey
{
display
:
inline-block
;
border-radius
:
4px
;
border
:
1px
solid
#35495e
;
color
:
#35495e
;
text-decoration
:
none
;
padding
:
10px
30px
;
margin-left
:
15px
;
}
.button--grey
:hover
{
color
:
#fff
;
background-color
:
#35495e
;
}
</
style
>
</
script
>
\ No newline at end of file
plugins/iview.js
View file @
fe605615
...
...
@@ -10,6 +10,9 @@ import iViewPro from '../iview-pro/src/index.js';
import
'@/styles/index.less'
;
import
'@/libs/iview-pro/iview-pro.css'
;
// 内置组件
import
iLink
from
'@/components/link'
;
Vue
.
component
(
"iLink"
,
iLink
)
export
default
({
app
,
store
...
...
store/admin/i18n.js
View file @
fe605615
...
...
@@ -4,10 +4,36 @@
import
Languages
from
'@/i18n/locale'
;
import
Setting
from
'@/setting'
;
import
util
from
'@/libs/util'
;
import
{
pathInit
}
from
'@/store/modules/admin/modules/db'
;
//
import { pathInit } from '@/store/modules/admin/modules/db';
const
savedLocaleKey
=
'i18n-locale'
;
/**
* @description 检查路径是否存在 不存在的话初始化
* @param {Object} dbName {String} 数据库名称
* @param {Object} path {String} 路径
* @param {Object} user {Boolean} 区分用户
* @param {Object} validator {Function} 数据校验钩子 返回 true 表示验证通过
* @param {Object} defaultValue {*} 初始化默认值
* @returns {String} 可以直接使用的路径
*/
function
pathInit
({
dbName
=
'database'
,
path
=
''
,
user
=
true
,
validator
=
()
=>
true
,
defaultValue
=
''
})
{
const
uuid
=
util
.
cookies
.
get
(
'uuid'
)
||
'ghost-uuid'
;
const
currentPath
=
`
${
dbName
}
.
${
user
?
`user.
${
uuid
}
`
:
'public'
}${
path
?
`.
${
path
}
`
:
''
}
`
;
const
value
=
util
.
db
.
get
(
currentPath
).
value
();
if
(
!
(
value
!==
undefined
&&
validator
(
value
)))
{
util
.
db
.
set
(
currentPath
,
defaultValue
).
write
();
}
return
currentPath
;
}
export
{
pathInit
};
export
const
state
=
()
=>
({
locale
:
''
})
...
...
store/modules/admin/index.js
deleted
100644 → 0
View file @
4e2fc099
/**
* 该文件启用 `@/store/index.js` 导入所有 vuex 模块。
* 这个文件是一次性创建的,不应该被修改。
*/
const
files
=
require
.
context
(
'./modules'
,
false
,
/
\.
js$/
);
const
modules
=
{};
files
.
keys
().
forEach
(
key
=>
{
modules
[
key
.
replace
(
/
(\.\/
|
\.
js
)
/g
,
''
)]
=
files
(
key
).
default
});
export
default
{
namespaced
:
true
,
modules
};
store/modules/admin/modules/account.js
deleted
100644 → 0
View file @
4e2fc099
/**
* 注册、登录、注销
* */
import
util
from
'@/libs/util'
;
import
router
from
'@/router'
;
import
{
AccountLogin
,
AccountRegister
}
from
'@/api/account'
;
import
{
Modal
}
from
'view-design'
;
export
default
{
namespaced
:
true
,
actions
:
{
/**
* @description 登录
* @param {Object} param context
* @param {Object} param username {String} 用户账号
* @param {Object} param password {String} 密码
* @param {Object} param route {Object} 登录成功后定向的路由对象 任何 vue-router 支持的格式
*/
login
({
dispatch
},
{
username
=
''
,
password
=
''
}
=
{})
{
return
new
Promise
((
resolve
,
reject
)
=>
{
// 开始请求登录接口
AccountLogin
({
username
,
password
})
.
then
(
async
res
=>
{
// 设置 cookie 一定要存 uuid 和 token 两个 cookie
// 整个系统依赖这两个数据进行校验和存储
// uuid 是用户身份唯一标识 用户注册的时候确定 并且不可改变 不可重复
// token 代表用户当前登录状态 建议在网络请求中携带 token
// 如有必要 token 需要定时更新,默认保存一天,可在 setting.js 中修改
// 如果你的 token 不是通过 cookie 携带,而是普通字段,也可视情况存储在 localStorage
util
.
cookies
.
set
(
'uuid'
,
res
.
uuid
);
util
.
cookies
.
set
(
'token'
,
res
.
token
);
// 设置 vuex 用户信息
await
dispatch
(
'admin/user/set'
,
res
.
info
,
{
root
:
true
});
// 用户登录后从持久化数据加载一系列的设置
await
dispatch
(
'load'
);
// 结束
resolve
();
})
.
catch
(
err
=>
{
// console.log('err: ', err);
reject
(
err
);
})
})
},
/**
* @description 退出登录
* */
logout
({
commit
,
dispatch
},
{
confirm
=
false
,
vm
}
=
{})
{
async
function
logout
()
{
// 删除cookie
util
.
cookies
.
remove
(
'token'
);
util
.
cookies
.
remove
(
'uuid'
);
// 清空 vuex 用户信息
await
dispatch
(
'admin/user/set'
,
{},
{
root
:
true
});
// 跳转路由
router
.
push
({
name
:
'login'
});
}
if
(
confirm
)
{
Modal
.
confirm
({
title
:
vm
.
$t
(
'basicLayout.logout.confirmTitle'
),
content
:
vm
.
$t
(
'basicLayout.logout.confirmContent'
),
onOk
()
{
logout
();
}
});
}
else
{
logout
();
}
},
/**
* @description 注册
* @param {Object} param context
* @param {Object} param mail {String} 邮箱
* @param {Object} param password {String} 密码
* @param {Object} param mobile {String} 手机号码
* @param {Object} param captcha {String} 验证码
*/
register
({
dispatch
},
{
mail
=
''
,
password
=
''
,
mobile
=
''
,
captcha
=
''
}
=
{})
{
return
new
Promise
((
resolve
,
reject
)
=>
{
// 开始请求登录接口
AccountRegister
({
mail
,
password
,
mobile
,
captcha
})
.
then
(
async
res
=>
{
// 注册成功后,完成与登录一致的操作
// 注册也可视情况不返还 uuid、token 等数据,在注册完成后,由前端自动执行一次登录逻辑
util
.
cookies
.
set
(
'uuid'
,
res
.
uuid
);
util
.
cookies
.
set
(
'token'
,
res
.
token
);
// 设置 vuex 用户信息
await
dispatch
(
'admin/user/set'
,
res
.
info
,
{
root
:
true
});
// 用户登录后从持久化数据加载一系列的设置
await
dispatch
(
'load'
);
// 结束
resolve
();
})
.
catch
(
err
=>
{
// console.log('err: ', err);
reject
(
err
);
})
})
},
/**
* @description 用户登录后从持久化数据加载一系列的设置
* @param {Object} state vuex state
* @param {Object} dispatch vuex dispatch
*/
load
({
state
,
dispatch
})
{
return
new
Promise
(
async
resolve
=>
{
// 加载用户登录信息
await
dispatch
(
'admin/user/load'
,
null
,
{
root
:
true
});
// 持久化数据加载上次退出时的多页列表
await
dispatch
(
'admin/page/openedLoad'
,
null
,
{
root
:
true
});
// end
resolve
();
})
}
}
};
store/modules/admin/modules/db.js
deleted
100644 → 0
View file @
4e2fc099
/**
* 持久化存储
* 一般情况下,您无需修改此文件
* */
import
util
from
'@/libs/util'
;
import
router
from
'@/router'
;
import
{
cloneDeep
}
from
'lodash'
;
/**
* @description 检查路径是否存在 不存在的话初始化
* @param {Object} dbName {String} 数据库名称
* @param {Object} path {String} 路径
* @param {Object} user {Boolean} 区分用户
* @param {Object} validator {Function} 数据校验钩子 返回 true 表示验证通过
* @param {Object} defaultValue {*} 初始化默认值
* @returns {String} 可以直接使用的路径
*/
function
pathInit
({
dbName
=
'database'
,
path
=
''
,
user
=
true
,
validator
=
()
=>
true
,
defaultValue
=
''
})
{
const
uuid
=
util
.
cookies
.
get
(
'uuid'
)
||
'ghost-uuid'
;
const
currentPath
=
`
${
dbName
}
.
${
user
?
`user.
${
uuid
}
`
:
'public'
}${
path
?
`.
${
path
}
`
:
''
}
`
;
const
value
=
util
.
db
.
get
(
currentPath
).
value
();
if
(
!
(
value
!==
undefined
&&
validator
(
value
)))
{
util
.
db
.
set
(
currentPath
,
defaultValue
).
write
();
}
return
currentPath
;
}
export
{
pathInit
};
export
default
{
namespaced
:
true
,
actions
:
{
/**
* @description 将数据存储到指定位置 | 路径不存在会自动初始化
* @description 效果类似于取值 dbName.path = value
* @param context context
* @param {Object} dbName {String} 数据库名称
* @param {Object} path {String} 存储路径
* @param {Object} value {*} 需要存储的值
* @param {Object} user {Boolean} 是否区分用户
*/
set
(
context
,
{
dbName
=
'database'
,
path
=
''
,
value
=
''
,
user
=
false
})
{
util
.
db
.
set
(
pathInit
({
dbName
,
path
,
user
}),
value
).
write
()
},
/**
* @description 获取数据
* @description 效果类似于取值 dbName.path || defaultValue
* @param context context
* @param {Object} dbName {String} 数据库名称
* @param {Object} path {String} 存储路径
* @param {Object} defaultValue {*} 取值失败的默认值
* @param {Object} user {Boolean} 是否区分用户
*/
get
(
context
,
{
dbName
=
'database'
,
path
=
''
,
defaultValue
=
''
,
user
=
false
})
{
return
new
Promise
(
resolve
=>
{
resolve
(
cloneDeep
(
util
.
db
.
get
(
pathInit
({
dbName
,
path
,
user
,
defaultValue
})).
value
()))
})
},
/**
* @description 获取存储数据库对象
* @param {Object} context context
* @param {Object} user {Boolean} 是否区分用户
*/
database
(
context
,
{
user
=
false
}
=
{})
{
return
new
Promise
(
resolve
=>
{
resolve
(
util
.
db
.
get
(
pathInit
({
dbName
:
'database'
,
path
:
''
,
user
,
defaultValue
:
{}
})))
})
},
/**
* @description 清空存储数据库对象
* @param {Object} context context
* @param {Object} user {Boolean} 是否区分用户
*/
databaseClear
(
context
,
{
user
=
false
}
=
{})
{
return
new
Promise
(
resolve
=>
{
resolve
(
util
.
db
.
get
(
pathInit
({
dbName
:
'database'
,
path
:
''
,
user
,
validator
:
()
=>
false
,
defaultValue
:
{}
})))
})
},
/**
* @description 获取存储数据库对象 [ 区分页面 ]
* @param {Object} context context
* @param {Object} basis {String} 页面区分依据 [ name | path | fullPath ]
* @param {Object} user {Boolean} 是否区分用户
*/
databasePage
(
context
,
{
basis
=
'fullPath'
,
user
=
false
}
=
{})
{
return
new
Promise
(
resolve
=>
{
resolve
(
util
.
db
.
get
(
pathInit
({
dbName
:
'database'
,
path
:
`$page.
${
router
.
app
.
$route
[
basis
]}
`
,
user
,
defaultValue
:
{}
})))
})
},
/**
* @description 清空存储数据库对象 [ 区分页面 ]
* @param {Object} context context
* @param {Object} basis {String} 页面区分依据 [ name | path | fullPath ]
* @param {Object} user {Boolean} 是否区分用户
*/
databasePageClear
(
context
,
{
basis
=
'fullPath'
,
user
=
false
}
=
{})
{
return
new
Promise
(
resolve
=>
{
resolve
(
util
.
db
.
get
(
pathInit
({
dbName
:
'database'
,
path
:
`$page.
${
router
.
app
.
$route
[
basis
]}
`
,
user
,
validator
:
()
=>
false
,
defaultValue
:
{}
})))
})
},
/**
* @description 快速将页面当前的数据 ( $data ) 持久化
* @param {Object} context context
* @param {Object} instance {Object} vue 实例
* @param {Object} basis {String} 页面区分依据 [ name | path | fullPath ]
* @param {Object} user {Boolean} 是否区分用户
*/
pageSet
(
context
,
{
instance
,
basis
=
'fullPath'
,
user
=
false
})
{
return
new
Promise
(
resolve
=>
{
resolve
(
util
.
db
.
get
(
pathInit
({
dbName
:
'database'
,
path
:
`$page.
${
router
.
app
.
$route
[
basis
]}
.$data`
,
user
,
validator
:
()
=>
false
,
defaultValue
:
cloneDeep
(
instance
.
$data
)
})))
})
},
/**
* @description 快速获取页面快速持久化的数据
* @param {Object} context context
* @param {Object} instance {Object} vue 实例
* @param {Object} basis {String} 页面区分依据 [ name | path | fullPath ]
* @param {Object} user {Boolean} 是否区分用户
*/
pageGet
(
context
,
{
instance
,
basis
=
'fullPath'
,
user
=
false
})
{
return
new
Promise
(
resolve
=>
{
resolve
(
cloneDeep
(
util
.
db
.
get
(
pathInit
({
dbName
:
'database'
,
path
:
`$page.
${
router
.
app
.
$route
[
basis
]}
.$data`
,
user
,
defaultValue
:
cloneDeep
(
instance
.
$data
)
})).
value
()))
})
},
/**
* @description 清空页面快照
* @param {Object} context context
* @param {Object} basis {String} 页面区分依据 [ name | path | fullPath ]
* @param {Object} user {Boolean} 是否区分用户
*/
pageClear
(
context
,
{
basis
=
'fullPath'
,
user
=
false
})
{
return
new
Promise
(
resolve
=>
{
resolve
(
util
.
db
.
get
(
pathInit
({
dbName
:
'database'
,
path
:
`$page.
${
router
.
app
.
$route
[
basis
]}
.$data`
,
user
,
validator
:
()
=>
false
,
defaultValue
:
{}
})))
})
}
}
};
store/modules/admin/modules/i18n.js
deleted
100644 → 0
View file @
4e2fc099
/**
* 多语言
* */
import
Languages
from
'@/i18n/locale'
;
import
Setting
from
'@/setting'
;
import
util
from
'@/libs/util'
;
import
{
pathInit
}
from
'@/store/modules/admin/modules/db'
;
const
savedLocaleKey
=
'i18n-locale'
;
export
default
{
namespaced
:
true
,
state
:
{
locale
:
''
},
actions
:
{
/**
* @description 获取当前语言
* */
getLocale
({
state
})
{
let
locale
;
const
db
=
util
.
db
.
get
(
pathInit
({
dbName
:
'database'
,
path
:
''
,
user
:
true
,
defaultValue
:
{}
}));
const
savedLocale
=
db
.
get
(
savedLocaleKey
).
value
();
// 先判断本地存储是否已有语言选择
if
(
savedLocale
)
{
locale
=
savedLocale
;
}
else
{
// 判断是否开启自动识别语言
if
(
Setting
.
i18n
.
auto
)
{
// 如果自动识别的语言,本地没有该语言包,则设置为默认语言
const
navLang
=
navigator
.
language
;
if
(
Languages
[
navLang
])
{
locale
=
navLang
;
}
else
{
locale
=
Setting
.
i18n
.
default
;
}
}
else
{
locale
=
Setting
.
i18n
.
default
;
}
// 将初次的语言保存在本地
db
.
set
(
savedLocaleKey
,
locale
).
write
();
}
state
.
locale
=
locale
;
},
/**
* @description 设置当前语言
* */
setLocale
({
state
},
{
locale
=
Setting
.
i18n
.
default
,
vm
})
{
const
db
=
util
.
db
.
get
(
pathInit
({
dbName
:
'database'
,
path
:
''
,
user
:
true
,
defaultValue
:
{}
}));
// 将语言保存在本地
db
.
set
(
savedLocaleKey
,
locale
).
write
();
// 设置当前语言
state
.
locale
=
locale
;
// 设置 vue-i18n 的语言
vm
.
$i18n
.
locale
=
locale
;
// 更新网页标题
util
.
title
({
title
:
vm
.
$route
.
meta
.
title
});
}
}
};
store/modules/admin/modules/layout.js
deleted
100644 → 0
View file @
4e2fc099
/**
* 布局配置
* */
import
screenfull
from
'screenfull'
;
import
Setting
from
'@/setting'
;
export
default
{
namespaced
:
true
,
state
:
{
...
Setting
.
layout
,
isMobile
:
false
,
// 是否为手机
isTablet
:
false
,
// 是否为平板
isDesktop
:
true
,
// 是否为桌面
isFullscreen
:
false
// 是否切换到了全屏
},
mutations
:
{
/**
* @description 设置设备类型
* @param {Object} state vuex state
* @param {String} type 设备类型,可选值为 Mobile、Tablet、Desktop
*/
setDevice
(
state
,
type
)
{
state
.
isMobile
=
false
;
state
.
isTablet
=
false
;
state
.
isDesktop
=
false
;
state
[
`is
${
type
}
`
]
=
true
;
},
/**
* @description 修改 menuCollapse
* @param {Object} state vuex state
* @param {Boolean} collapse 折叠状态
* */
updateMenuCollapse
(
state
,
collapse
)
{
state
.
menuCollapse
=
collapse
;
},
/**
* @description 设置全屏状态
* @param {Object} state vuex state
* @param {Boolean} isFullscreen vuex
* */
setFullscreen
(
state
,
isFullscreen
)
{
state
.
isFullscreen
=
isFullscreen
;
},
/**
* @description 更改指定布局配置
* @param {Object} state vuex state
* @param {Object} key layout 名称,对应 Setting.layout
* @param {Object} value layout 值
* */
updateLayoutSetting
(
state
,
{
key
,
value
})
{
state
[
key
]
=
value
;
}
},
actions
:
{
/**
* @description 初始化监听全屏状态
*/
listenFullscreen
({
commit
})
{
return
new
Promise
(
resolve
=>
{
if
(
screenfull
.
enabled
)
{
screenfull
.
on
(
'change'
,
()
=>
{
if
(
!
screenfull
.
isFullscreen
)
{
commit
(
'setFullscreen'
,
false
)
}
})
}
// end
resolve
();
});
},
/**
* @description 切换全屏
*/
toggleFullscreen
({
commit
})
{
return
new
Promise
(
resolve
=>
{
if
(
screenfull
.
isFullscreen
)
{
screenfull
.
exit
();
commit
(
'setFullscreen'
,
false
);
}
else
{
screenfull
.
request
();
commit
(
'setFullscreen'
,
true
);
}
// end
resolve
();
});
}
}
};
store/modules/admin/modules/log.js
deleted
100644 → 0
View file @
4e2fc099
import
dayjs
from
'dayjs'
;
import
{
get
}
from
'lodash'
;
import
util
from
'@/libs/util.js'
;
export
default
{
namespaced
:
true
,
state
:
{
/**
* @description 错误日志,单条属性:
* message: 必填,日志信息
* type: 非必填,类型,可选值为 info(默认值)| success | warning | error,其中 error 会以具体数目强调显示,其它以点轻量显示
* time: 必填,日志记录时间
* meta: 非必填,其它携带信息
* */
log
:
[]
},
getters
:
{
/**
* @description 返回现存 log (all) 的条数
* @param {*} state vuex state
*/
length
(
state
)
{
return
state
.
log
.
length
;
},
/**
* @description 返回现存 log (error) 的条数
* @param {*} state vuex state
*/
lengthError
(
state
)
{
return
state
.
log
.
filter
(
log
=>
log
.
type
===
'error'
).
length
;
}
},
actions
:
{
/**
* @description 添加一个日志
* @param {String} param message {String} 信息
* @param {String} param type {String} 类型
* @param {Object} param meta {Object} 附带的信息
*/
push
({
rootState
,
commit
},
{
message
,
type
=
'info'
,
meta
})
{
commit
(
'push'
,
{
message
,
type
,
time
:
dayjs
().
format
(
'YYYY-MM-DD HH:mm:ss'
),
meta
:
{
// 当前用户信息
user
:
rootState
.
admin
.
user
.
info
,
// 当前用户的 uuid
uuid
:
util
.
cookies
.
get
(
'uuid'
),
// 当前的 token
token
:
util
.
cookies
.
get
(
'token'
),
// 当前地址
url
:
get
(
window
,
'location.href'
,
''
),
// 用户设置
...
meta
}
});
}
},
mutations
:
{
/**
* @description 添加日志
* @param {Object} state vuex state
* @param {Object} log data
*/
push
(
state
,
log
)
{
state
.
log
.
push
(
log
);
},
/**
* @description 清空日志
* @param {Object} state vuex state
*/
clean
(
state
)
{
state
.
log
=
[];
}
}
}
store/modules/admin/modules/menu.js
deleted
100644 → 0
View file @
4e2fc099
/**
* 菜单
* */
import
{
cloneDeep
}
from
'lodash'
;
import
{
includeArray
}
from
'@/libs/system'
;
// 根据 menu 配置的权限,过滤菜单
function
filterMenu
(
menuList
,
access
,
lastList
)
{
menuList
.
forEach
(
menu
=>
{
let
menuAccess
=
menu
.
auth
;
if
(
!
menuAccess
||
includeArray
(
menuAccess
,
access
))
{
let
newMenu
=
{};
for
(
let
i
in
menu
)
{
if
(
i
!==
'children'
)
newMenu
[
i
]
=
cloneDeep
(
menu
[
i
]);
}
if
(
menu
.
children
&&
menu
.
children
.
length
)
newMenu
.
children
=
[];
lastList
.
push
(
newMenu
);
menu
.
children
&&
filterMenu
(
menu
.
children
,
access
,
newMenu
.
children
);
}
});
return
lastList
;
}
export
default
{
namespaced
:
true
,
state
:
{
// 顶部菜单
header
:
[],
// 侧栏菜单
sider
:
[],
// 当前顶栏菜单的 name
headerName
:
''
,
// 当前所在菜单的 path
activePath
:
''
,
// 展开的子菜单 name 集合
openNames
:
[]
},
getters
:
{
/**
* @description 根据 user 里登录用户权限,对侧边菜单进行鉴权过滤
* */
filterSider
(
state
,
getters
,
rootState
)
{
const
userInfo
=
rootState
.
admin
.
user
.
info
;
// @权限
const
access
=
userInfo
.
access
;
if
(
access
&&
access
.
length
)
{
return
filterMenu
(
state
.
sider
,
access
,
[]);
}
else
{
return
filterMenu
(
state
.
sider
,
[],
[]);
}
},
/**
* @description 根据 user 里登录用户权限,对顶栏菜单进行鉴权过滤
* */
filterHeader
(
state
,
getters
,
rootState
)
{
const
userInfo
=
rootState
.
admin
.
user
.
info
;
// @权限
const
access
=
userInfo
.
access
;
if
(
access
&&
access
.
length
)
{
return
state
.
header
.
filter
(
item
=>
{
let
state
=
true
;
if
(
item
.
auth
&&
!
includeArray
(
item
.
auth
,
access
))
state
=
false
;
return
state
;
});
}
else
{
return
state
.
header
.
filter
(
item
=>
{
let
state
=
true
;
if
(
item
.
auth
&&
item
.
auth
.
length
)
state
=
false
;
return
state
;
});
}
},
/**
* @description 当前 header 的全部信息
* */
currentHeader
(
state
)
{
return
state
.
header
.
find
(
item
=>
item
.
name
===
state
.
headerName
);
},
/**
* @description 在当前 header 下,是否隐藏 sider(及折叠按钮)
* */
hideSider
(
state
,
getters
)
{
let
visible
=
false
;
if
(
getters
.
currentHeader
&&
'hideSider'
in
getters
.
currentHeader
)
visible
=
getters
.
currentHeader
.
hideSider
;
return
visible
;
}
},
mutations
:
{
/**
* @description 设置侧边栏菜单
* @param {Object} state vuex state
* @param {Array} menu menu
*/
setSider
(
state
,
menu
)
{
state
.
sider
=
menu
;
},
/**
* @description 设置顶栏菜单
* @param {Object} state vuex state
* @param {Array} menu menu
*/
setHeader
(
state
,
menu
)
{
state
.
header
=
menu
;
},
/**
* @description 设置当前顶栏菜单 name
* @param {Object} state vuex state
* @param {Array} name headerName
*/
setHeaderName
(
state
,
name
)
{
state
.
headerName
=
name
;
},
/**
* @description 设置当前所在菜单的 path,用于侧栏菜单高亮当前项
* @param {Object} state vuex state
* @param {Array} path fullPath
*/
setActivePath
(
state
,
path
)
{
state
.
activePath
=
path
;
},
/**
* @description 设置当前所在菜单的全部展开父菜单的 names 集合
* @param {Object} state vuex state
* @param {Array} names openNames
*/
setOpenNames
(
state
,
names
)
{
state
.
openNames
=
names
;
}
}
}
store/modules/admin/modules/page.js
deleted
100644 → 0
View file @
4e2fc099
/**
* 多标签页
* */
import
{
get
}
from
'lodash'
;
import
router
from
'@/router'
;
import
Setting
from
'@/setting'
;
import
menuSider
from
'@/menu/sider'
;
import
{
getAllSiderMenu
,
includeArray
}
from
'@/libs/system'
;
// 判定是否需要缓存
const
isKeepAlive
=
data
=>
get
(
data
,
'meta.cache'
,
false
);
export
default
{
namespaced
:
true
,
state
:
{
// 可以在多页 tab 模式下显示的页面
pool
:
[],
// 当前显示的多页面列表
opened
:
Setting
.
page
.
opened
,
// 当前页面
current
:
''
,
// 需要缓存的页面 name
keepAlive
:
[]
},
actions
:
{
/**
* @description 从持久化数据载入分页列表
*/
openedLoad
({
state
,
commit
,
dispatch
,
rootState
})
{
return
new
Promise
(
async
resolve
=>
{
// store 赋值
const
value
=
await
dispatch
(
'admin/db/get'
,
{
dbName
:
'sys'
,
path
:
'page.opened'
,
defaultValue
:
Setting
.
page
.
opened
,
user
:
true
},
{
root
:
true
});
// 在处理函数中进行数据优化 过滤掉现在已经失效的页签或者已经改变了信息的页签
// 以 fullPath 字段为准
// 如果页面过多的话可能需要优化算法
// valid 有效列表 1, 1, 0, 1 => 有效, 有效, 失效, 有效
const
valid
=
[];
// 处理数据
state
.
opened
=
value
.
map
(
opened
=>
{
// 忽略首页
if
(
opened
.
fullPath
===
'/index'
)
{
valid
.
push
(
1
);
return
opened
;
}
// 尝试在所有的支持多标签页的页面里找到 name 匹配的页面
const
find
=
state
.
pool
.
find
(
item
=>
item
.
name
===
opened
.
name
);
// 记录有效或无效信息
valid
.
push
(
find
?
1
:
0
);
// 返回合并后的数据 新的覆盖旧的
// 新的数据中一般不会携带 params 和 query, 所以旧的参数会留存
return
Object
.
assign
({},
opened
,
find
);
})
.
filter
((
opened
,
index
)
=>
valid
[
index
]
===
1
)
// 对 menu 鉴权过滤
.
filter
(
opened
=>
{
const
allSiderMenu
=
getAllSiderMenu
(
menuSider
);
const
find
=
allSiderMenu
.
find
(
item
=>
item
.
path
===
opened
.
fullPath
);
let
state
=
true
;
if
(
find
&&
find
.
auth
)
{
const
userInfo
=
rootState
.
admin
.
user
.
info
;
// @权限
const
access
=
userInfo
.
access
;
// 如果用户当前的权限,不是该 menu 对应的 权限,则过滤这个 Tab
if
(
access
&&
!
includeArray
(
find
.
auth
,
access
))
state
=
false
;
}
return
state
;
});
// 根据 opened 数据生成缓存设置
commit
(
'keepAliveRefresh'
);
// end
resolve
();
});
},
/**
* 将 opened 属性赋值并持久化 在这之前请先确保已经更新了 state.opened
*/
opened2db
({
state
,
dispatch
})
{
return
new
Promise
(
async
resolve
=>
{
// 设置数据
dispatch
(
'admin/db/set'
,
{
dbName
:
'sys'
,
path
:
'page.opened'
,
value
:
state
.
opened
,
user
:
true
},
{
root
:
true
});
// end
resolve
();
});
},
/**
* @description 更新页面列表上的某一项
* @param {Object} param { index, params, query, fullPath } 路由信息
*/
openedUpdate
({
state
,
commit
,
dispatch
},
{
index
,
params
,
query
,
fullPath
,
meta
})
{
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
];
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
)
{
// 页面以前打开过
await
dispatch
(
'openedUpdate'
,
{
index
:
pageOpenedIndex
,
params
,
query
,
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
resolve
();
});
},
/**
* @description 关闭一个 tag (关闭一个页面)
* @param {Object} param { tagName: 要关闭的标签名字 }
*/
close
({
state
,
commit
,
dispatch
},
{
tagName
})
{
return
new
Promise
(
async
resolve
=>
{
// 下个新的页面
let
newPage
=
state
.
opened
[
0
];
const
isCurrent
=
state
.
current
===
tagName
;
// 如果关闭的页面就是当前显示的页面
if
(
isCurrent
)
{
// 去找一个新的页面
let
len
=
state
.
opened
.
length
;
for
(
let
i
=
0
;
i
<
len
;
i
++
)
{
if
(
state
.
opened
[
i
].
fullPath
===
tagName
)
{
// 是否只剩最后一个,是则跳首页
if
(
len
>
1
)
{
// 如果是最后一个,则向前一个跳,否则向下一个跳
if
(
i
===
len
-
1
)
{
newPage
=
state
.
opened
[
i
-
1
];
}
else
{
newPage
=
state
.
opened
[
i
+
1
];
}
}
else
{
newPage
=
{};
}
break
;
}
}
}
// 找到这个页面在已经打开的数据里是第几个
const
index
=
state
.
opened
.
findIndex
(
page
=>
page
.
fullPath
===
tagName
);
if
(
index
>=
0
)
{
// 如果这个页面是缓存的页面 将其在缓存设置中删除
commit
(
'keepAliveRemove'
,
state
.
opened
[
index
].
name
);
// 更新数据 删除关闭的页面
state
.
opened
.
splice
(
index
,
1
);
}
// 持久化
await
dispatch
(
'opened2db'
);
// 最后需要判断是否需要跳到首页
if
(
isCurrent
)
{
const
{
name
=
'index'
,
params
=
{},
query
=
{}
}
=
newPage
;
let
routerObj
=
{
name
,
params
,
query
};
router
.
push
(
routerObj
,
()
=>
{});
}
// end
resolve
();
});
},
/**
* @description 关闭当前标签左边的标签
* @param {Object} param { pageSelect: 当前选中的tagName }
*/
closeLeft
({
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
;
}
});
if
(
currentIndex
>
0
)
{
// 删除打开的页面 并在缓存设置中删除
state
.
opened
.
splice
(
1
,
currentIndex
-
1
).
forEach
(({
name
})
=>
commit
(
'keepAliveRemove'
,
name
));
}
state
.
current
=
pageAim
;
if
(
router
.
app
.
$route
.
fullPath
!==
pageAim
)
{
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
;
}
});
// 删除打开的页面 并在缓存设置中删除
state
.
opened
.
splice
(
currentIndex
+
1
).
forEach
(({
name
})
=>
commit
(
'keepAliveRemove'
,
name
));
// 设置当前的页面
state
.
current
=
pageAim
;
if
(
router
.
app
.
$route
.
fullPath
!==
pageAim
)
{
router
.
push
(
pageAim
);
}
// 持久化
await
dispatch
(
'opened2db'
);
// end
resolve
();
});
},
/**
* @description 关闭当前激活之外的 tag
* @param {Object} param { pageSelect: 当前选中的tagName }
*/
closeOther
({
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
;
}
});
// 删除打开的页面数据 并更新缓存设置
if
(
currentIndex
===
0
)
{
state
.
opened
.
splice
(
1
).
forEach
(({
name
})
=>
commit
(
'keepAliveRemove'
,
name
));
}
else
{
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
(
router
.
app
.
$route
.
fullPath
!==
pageAim
)
{
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
(
1
).
forEach
(({
name
})
=>
commit
(
'keepAliveRemove'
,
name
));
// 持久化
await
dispatch
(
'opened2db'
);
// 关闭所有的标签页后需要判断一次现在是不是在首页
if
(
router
.
app
.
$route
.
name
!==
'index'
)
{
router
.
push
({
name
:
'index'
},
()
=>
{});
}
// end
resolve
();
});
}
},
mutations
:
{
/**
* @class keepAlive
* @description 从已经打开的页面记录中更新需要缓存的页面记录
* @param {Object} state vuex state
*/
keepAliveRefresh
(
state
)
{
state
.
keepAlive
=
state
.
opened
.
filter
(
item
=>
isKeepAlive
(
item
)).
map
(
e
=>
e
.
name
);
},
/**
* @description 删除一个页面的缓存设置
* @param {Object} state vuex state
* @param {String} name name
*/
keepAliveRemove
(
state
,
name
)
{
const
list
=
[
...
state
.
keepAlive
];
const
index
=
list
.
findIndex
(
item
=>
item
===
name
);
if
(
index
!==
-
1
)
{
list
.
splice
(
index
,
1
);
state
.
keepAlive
=
list
;
}
},
/**
* @description 增加一个页面的缓存设置
* @param {Object} state vuex state
* @param {String} name name
*/
keepAlivePush
(
state
,
name
)
{
const
keep
=
[
...
state
.
keepAlive
];
keep
.
push
(
name
);
state
.
keepAlive
=
keep
;
},
/**
* @description 清空页面缓存设置
* @param {Object} state vuex state
*/
keepAliveClean
(
state
)
{
state
.
keepAlive
=
[];
},
/**
* @class current
* @description 设置当前激活的页面 fullPath
* @param {Object} state vuex state
* @param {String} fullPath new fullPath
*/
currentSet
(
state
,
fullPath
)
{
state
.
current
=
fullPath
;
},
/**
* @class pool
* @description 保存 pool (候选池)
* @param {Object} state vuex state
* @param {Array} routes routes
*/
init
(
state
,
routes
)
{
const
pool
=
[];
const
push
=
function
(
routes
)
{
routes
.
forEach
(
route
=>
{
if
(
route
.
children
)
{
push
(
route
.
children
);
}
else
{
if
(
!
route
.
hidden
)
{
const
{
meta
,
name
,
path
}
=
route
;
pool
.
push
({
meta
,
name
,
path
});
}
}
})
};
push
(
routes
);
state
.
pool
=
pool
;
}
}
}
store/modules/admin/modules/user.js
deleted
100644 → 0
View file @
4e2fc099
/**
* 用户信息
* */
export
default
{
namespaced
:
true
,
state
:
{
// 用户信息
info
:
{}
},
actions
:
{
/**
* @description 设置用户数据
* @param {Object} state vuex state
* @param {Object} dispatch vuex dispatch
* @param {*} info info
*/
set
({
state
,
dispatch
},
info
)
{
return
new
Promise
(
async
resolve
=>
{
// store 赋值
state
.
info
=
info
;
// 持久化
await
dispatch
(
'admin/db/set'
,
{
dbName
:
'sys'
,
path
:
'user.info'
,
value
:
info
,
user
:
true
},
{
root
:
true
});
// end
resolve
();
})
},
/**
* @description 从数据库取用户数据
* @param {Object} state vuex state
* @param {Object} dispatch vuex dispatch
*/
load
({
state
,
dispatch
})
{
return
new
Promise
(
async
resolve
=>
{
// store 赋值
state
.
info
=
await
dispatch
(
'admin/db/get'
,
{
dbName
:
'sys'
,
path
:
'user.info'
,
defaultValue
:
{},
user
:
true
},
{
root
:
true
});
// end
resolve
();
})
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment