Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
O
oa-client
Project
Project
Details
Activity
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
朱招明
oa-client
Commits
26ca100a
Commit
26ca100a
authored
Oct 28, 2023
by
朱招明
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update
parent
fff74c5a
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
239 additions
and
101 deletions
+239
-101
index.vue
src/components/HeaderSearch/index.vue
+3
-2
index.vue
src/layout/components/Sidebar/index.vue
+1
-0
main.js
src/main.js
+7
-3
config.js
src/router/config.js
+3
-6
generator-routers.js
src/router/generator-routers.js
+23
-66
index.js
src/router/index.js
+12
-0
app.js
src/store/modules/app.js
+7
-0
error-log.js
src/utils/error-log.js
+35
-0
request.js
src/utils/request.js
+9
-1
validate.js
src/utils/validate.js
+67
-0
index.vue
src/views/redirect/index.vue
+12
-0
index.vue
src/views/system/power/menu/index.vue
+36
-23
index.vue
src/views/system/power/role/index.vue
+0
-0
index.vue
src/views/system/power/user/index.vue
+24
-0
No files found.
src/components/HeaderSearch/index.vue
View file @
26ca100a
...
...
@@ -12,7 +12,7 @@
class=
"header-search-select"
@
change=
"change"
>
<el-option
v-for=
"item in options"
:key=
"item.
path"
:value=
"item"
:label=
"
item.title.join(' > ')"
/>
<el-option
v-for=
"item in options"
:key=
"item.
item.path"
:value=
"item.item"
:label=
"item.
item.title.join(' > ')"
/>
</el-select>
</div>
</
template
>
...
...
@@ -36,7 +36,7 @@ export default {
},
computed
:
{
routes
()
{
return
this
.
$store
.
getters
.
addRouters
return
this
.
$store
.
getters
.
addRouters
.
find
(
item
=>
item
.
path
===
'/'
).
children
}
},
watch
:
{
...
...
@@ -131,6 +131,7 @@ export default {
querySearch
(
query
)
{
if
(
query
!==
''
)
{
this
.
options
=
this
.
fuse
.
search
(
query
)
console
.
log
(
this
.
options
)
}
else
{
this
.
options
=
[]
}
...
...
src/layout/components/Sidebar/index.vue
View file @
26ca100a
...
...
@@ -59,6 +59,7 @@ export default {
created
()
{
const
routes
=
this
.
addRouters
.
find
(
item
=>
item
.
path
===
'/'
)
this
.
menus
=
(
routes
&&
routes
.
children
)
||
[]
console
.
log
(
this
.
menus
)
}
}
...
...
src/main.js
View file @
26ca100a
import
Vue
from
'vue'
import
Cookies
from
'js-cookie'
import
'normalize.css/normalize.css'
// A modern alternative to CSS resets
import
ElementUI
from
'element-ui'
import
'element-ui/lib/theme-chalk/index.css'
import
locale
from
'element-ui/lib/locale/lang/en'
// lang i18n
//
import locale from 'element-ui/lib/locale/lang/en' // lang i18n
import
'@/styles/index.scss'
// global css
...
...
@@ -14,6 +15,7 @@ import router from './router'
import
'@/icons'
// icon
import
'@/permission'
// permission control
import
'./utils/error-log'
// error log
/**
* If you don't want to use mock-server
...
...
@@ -29,9 +31,11 @@ if (process.env.NODE_ENV === 'production') {
}
// set ElementUI lang to EN
Vue
.
use
(
ElementUI
,
{
locale
})
//
Vue.use(ElementUI, { locale })
// 如果想要中文版 element-ui,按如下方式声明
// Vue.use(ElementUI)
Vue
.
use
(
ElementUI
,
{
size
:
Cookies
.
get
(
'size'
)
||
'medium'
})
Vue
.
config
.
productionTip
=
false
...
...
src/router/config.js
View file @
26ca100a
// 路由标识对应页面
export
const
constantRouterComponents
=
{
// 权限管理
// SystemPowerRoleList: () => import('@/views/system/power/role/List'),
// UserList: () => import('@/views/power/user/list'),
'Dashboard'
:
()
=>
import
(
'@/views/dashboard/index'
),
'SystemPowerRoleList'
:
()
=>
import
(
'@/views/system/power/role/List'
),
'SystemPowerUserList'
:
()
=>
import
(
'@/views/system/power/user/List'
),
'SystemPowerMenuList'
:
()
=>
import
(
'@/views/system/power/menu/List'
)
'role'
:
()
=>
import
(
'@/views/system/power/role/index'
),
'user'
:
()
=>
import
(
'@/views/system/power/user/index.vue'
),
'menu'
:
()
=>
import
(
'@/views/system/power/menu/index'
)
}
src/router/generator-routers.js
View file @
26ca100a
...
...
@@ -12,16 +12,18 @@ const notFoundRouter = {
// 根级菜单
const
rootRouter
=
{
router
:
'/'
,
key
:
'Root
'
,
path
:
'/'
,
name
:
'/
'
,
component
:
Layout
,
redirect
:
'/dashboard'
,
children
:
[{
router
:
'/dashboard'
,
key
:
'Dashboard'
,
title
:
'首页'
,
icon
:
'dashboard'
,
component
:
()
=>
import
(
'@/views/dashboard/index'
)
path
:
'/dashboard'
,
name
:
'dashboard'
,
component
:
()
=>
import
(
'@/views/dashboard/index'
),
meta
:
{
title
:
'首页'
,
icon
:
'dashboard'
}
}]
}
...
...
@@ -40,13 +42,12 @@ export const generatorDynamicRouter = () => {
const
childrenNav
=
[]
// 后端数据, 根级树数组, 根级 PID
listToTree
(
menus
,
childrenNav
,
0
)
rootRouter
.
children
=
[...
rootRouter
.
children
,
...
childrenNav
]
const
routers
=
generator
(
childrenNav
)
rootRouter
.
children
=
[...
rootRouter
.
children
,
...
routers
]
menuNav
.
push
(
rootRouter
)
const
routers
=
generator
(
menuNav
)
console
.
log
(
routers
)
// const routers = []
routers
.
push
(
notFoundRouter
)
resolve
(
routers
)
console
.
log
(
menuNav
)
menuNav
.
push
(
notFoundRouter
)
resolve
(
menuNav
)
})
.
catch
(
err
=>
{
reject
(
err
)
...
...
@@ -63,73 +64,29 @@ export const generatorDynamicRouter = () => {
*/
export
const
generator
=
(
routerMap
,
parent
)
=>
{
return
routerMap
.
map
(
item
=>
{
// const { show, hideChildren, hiddenHeaderContent, target, icon } = item.meta || {}
// const path = item.path || item.key + (item.id || '')
const
component
=
item
.
component
||
constantRouterComponents
[
item
.
key
]
const
currentRouter
=
{
//
如果路由设置了 path,则作为默认 path,否则 路由地址 动态拼接生成如 /dashboard/workplace
path
:
item
.
router
||
(
item
.
key
+
'_'
+
(
item
.
id
||
''
))
,
//
上级key + 自己key
path
:
((
parent
&&
parent
.
path
)
||
''
)
+
'/'
+
item
.
key
,
// 路由名称,建议唯一
name
:
item
.
key
+
(
item
.
id
||
''
),
// 该路由对应页面的 组件 :方案1
// component: constantRouterComponents[item.component || item.key],
// 该路由对应页面的 组件 :方案2 (动态加载)
component
:
component
,
// meta: 页面标题, 菜单图标, 页面权限(供指令权限用,可去掉)
name
:
item
.
key
,
// 该路由对应页面的 组件 || 404
component
:
constantRouterComponents
[
item
.
key
]
||
(()
=>
import
(
'@/views/404'
)),
// meta: 页面标题, 菜单图标
meta
:
{
title
:
item
.
title
,
icon
:
item
.
icon
}
}
// // 是否设置了隐藏菜单
// if (show === false) {
// currentRouter.hidden = true
// }
// // 是否设置了隐藏子菜单
// if (hideChildren) {
// currentRouter.hideChildrenInMenu = true
// }
// // 为了防止出现后端返回结果不规范,处理有可能出现拼接出两个 反斜杠
// if (!currentRouter.path.startsWith('http')) {
// currentRouter.path = currentRouter.path.replace('//', '/')
// }
// 重定向
item
.
redirect
&&
(
currentRouter
.
redirect
=
item
.
redirect
)
// 是否有子菜单,并递归处理
if
(
item
.
children
&&
item
.
children
.
length
>
0
)
{
// Recursion
currentRouter
.
children
=
generator
(
item
.
children
,
currentRouter
)
if
(
item
.
key
!==
'Root'
)
{
currentRouter
.
component
=
RouteView
}
}
// 是否有功能页菜单
// const actions = constantActionRouterComponents[item.key]
// if (actions) {
// const children_action = generatorAction(actions, currentRouter)
// const children_menu = currentRouter.children || []
// console.log(children_action, children_menu)
// currentRouter.children = [...children_menu, ...children_action]
// }
return
currentRouter
})
}
export
const
generatorAction
=
(
routerMap
,
parent
)
=>
{
return
routerMap
.
map
(
item
=>
{
return
{
path
:
item
.
path
,
name
:
parent
.
name
+
'.'
+
item
.
name
,
component
:
item
.
component
,
hidden
:
true
,
meta
:
{
title
:
item
.
title
,
icon
:
item
.
icon
,
activeMenu
:
parent
.
path
}
currentRouter
.
component
=
RouteView
currentRouter
.
redirect
=
'noRedirect'
}
return
currentRouter
})
}
...
...
src/router/index.js
View file @
26ca100a
import
Vue
from
'vue'
import
Router
from
'vue-router'
import
Layout
from
'@/layout'
Vue
.
use
(
Router
)
...
...
@@ -39,6 +40,17 @@ export const constantRouterMap = [
path
:
'/404'
,
component
:
()
=>
import
(
'@/views/404'
),
hidden
:
true
},
{
path
:
'/redirect'
,
component
:
Layout
,
hidden
:
true
,
children
:
[
{
path
:
'/redirect/:path(.*)'
,
component
:
()
=>
import
(
'@/views/redirect/index'
)
}
]
}
]
...
...
src/store/modules/app.js
View file @
26ca100a
...
...
@@ -26,6 +26,10 @@ const mutations = {
},
TOGGLE_DEVICE
:
(
state
,
device
)
=>
{
state
.
device
=
device
},
SET_SIZE
:
(
state
,
size
)
=>
{
state
.
size
=
size
Cookies
.
set
(
'size'
,
size
)
}
}
...
...
@@ -38,6 +42,9 @@ const actions = {
},
toggleDevice
({
commit
},
device
)
{
commit
(
'TOGGLE_DEVICE'
,
device
)
},
setSize
({
commit
},
size
)
{
commit
(
'SET_SIZE'
,
size
)
}
}
...
...
src/utils/error-log.js
0 → 100644
View file @
26ca100a
import
Vue
from
'vue'
import
store
from
'@/store'
import
{
isString
,
isArray
}
from
'@/utils/validate'
import
settings
from
'@/settings'
// you can set in settings.js
// errorLog:'production' | ['production', 'development']
const
{
errorLog
:
needErrorLog
}
=
settings
function
checkNeed
()
{
const
env
=
process
.
env
.
NODE_ENV
if
(
isString
(
needErrorLog
))
{
return
env
===
needErrorLog
}
if
(
isArray
(
needErrorLog
))
{
return
needErrorLog
.
includes
(
env
)
}
return
false
}
if
(
checkNeed
())
{
Vue
.
config
.
errorHandler
=
function
(
err
,
vm
,
info
,
a
)
{
// Don't ask me why I use Vue.nextTick, it just a hack.
// detail see https://forum.vuejs.org/t/dispatch-in-vue-config-errorhandler-has-some-problem/23500
Vue
.
nextTick
(()
=>
{
store
.
dispatch
(
'errorLog/addErrorLog'
,
{
err
,
vm
,
info
,
url
:
window
.
location
.
href
})
console
.
error
(
err
,
info
)
})
}
}
src/utils/request.js
View file @
26ca100a
...
...
@@ -46,9 +46,17 @@ service.interceptors.response.use(
console
.
log
(
'err'
+
error
)
// for debug
const
data
=
error
.
response
.
data
const
token
=
getToken
()
const
params_errors
=
data
.
errors
switch
(
error
.
response
.
status
)
{
case
422
:
Message
.
error
(
'参数错误'
)
if
(
params_errors
)
{
for
(
const
item
in
params_errors
)
{
Message
.
error
(
params_errors
[
item
][
0
])
break
}
}
else
{
Message
.
error
(
'参数错误'
)
}
break
case
403
:
Message
.
error
(
'无权操作'
)
...
...
src/utils/validate.js
View file @
26ca100a
...
...
@@ -18,3 +18,70 @@ export function validUsername(str) {
const
valid_map
=
[
'admin'
,
'editor'
]
return
valid_map
.
indexOf
(
str
.
trim
())
>=
0
}
/**
* @param {string} url
* @returns {Boolean}
*/
export
function
validURL
(
url
)
{
const
reg
=
/^
(
https
?
|ftp
)
:
\/\/([
a-zA-Z0-9.-
]
+
(
:
[
a-zA-Z0-9.&%$-
]
+
)
*@
)
*
((
25
[
0-5
]
|2
[
0-4
][
0-9
]
|1
[
0-9
]{2}
|
[
1-9
][
0-9
]?)(\.(
25
[
0-5
]
|2
[
0-4
][
0-9
]
|1
[
0-9
]{2}
|
[
1-9
]?[
0-9
])){3}
|
([
a-zA-Z0-9-
]
+
\.)
*
[
a-zA-Z0-9-
]
+
\.(
com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|
[
a-zA-Z
]{2}))(
:
[
0-9
]
+
)
*
(\/(
$|
[
a-zA-Z0-9.,?'
\\
+&%$#=~_-
]
+
))
*$/
return
reg
.
test
(
url
)
}
/**
* @param {string} str
* @returns {Boolean}
*/
export
function
validLowerCase
(
str
)
{
const
reg
=
/^
[
a-z
]
+$/
return
reg
.
test
(
str
)
}
/**
* @param {string} str
* @returns {Boolean}
*/
export
function
validUpperCase
(
str
)
{
const
reg
=
/^
[
A-Z
]
+$/
return
reg
.
test
(
str
)
}
/**
* @param {string} str
* @returns {Boolean}
*/
export
function
validAlphabets
(
str
)
{
const
reg
=
/^
[
A-Za-z
]
+$/
return
reg
.
test
(
str
)
}
/**
* @param {string} email
* @returns {Boolean}
*/
export
function
validEmail
(
email
)
{
const
reg
=
/^
(([^
<>()
\[\]\\
.,;:
\s
@"
]
+
(\.[^
<>()
\[\]\\
.,;:
\s
@"
]
+
)
*
)
|
(
".+"
))
@
((\[[
0-9
]{1,3}\.[
0-9
]{1,3}\.[
0-9
]{1,3}\.[
0-9
]{1,3}\])
|
(([
a-zA-Z
\-
0-9
]
+
\.)
+
[
a-zA-Z
]{2,}))
$/
return
reg
.
test
(
email
)
}
/**
* @param {string} str
* @returns {Boolean}
*/
export
function
isString
(
str
)
{
if
(
typeof
str
===
'string'
||
str
instanceof
String
)
{
return
true
}
return
false
}
/**
* @param {Array} arg
* @returns {Boolean}
*/
export
function
isArray
(
arg
)
{
if
(
typeof
Array
.
isArray
===
'undefined'
)
{
return
Object
.
prototype
.
toString
.
call
(
arg
)
===
'[object Array]'
}
return
Array
.
isArray
(
arg
)
}
src/views/redirect/index.vue
0 → 100644
View file @
26ca100a
<
script
>
export
default
{
created
()
{
const
{
params
,
query
}
=
this
.
$route
const
{
path
}
=
params
this
.
$router
.
replace
({
path
:
'/'
+
path
,
query
})
},
render
:
function
(
h
)
{
return
h
()
// avoid warning message
}
}
</
script
>
src/views/system/power/menu/
List
.vue
→
src/views/system/power/menu/
index
.vue
View file @
26ca100a
...
...
@@ -4,7 +4,6 @@
<el-tree
:data=
"treeData"
node-key=
"id"
default-expand-all
:expand-on-click-node=
"false"
>
<span
slot-scope=
"
{ node, data }" class="custom-tree-node">
...
...
@@ -18,6 +17,7 @@
新增
</el-button>
<el-button
v-if=
"data.id !== 0"
type=
"text"
size=
"mini"
@
click=
"() => edit(node, data)"
...
...
@@ -25,6 +25,7 @@
编辑
</el-button>
<el-button
v-if=
"data.id !== 0"
type=
"text"
size=
"mini"
@
click=
"() => remove(node, data)"
...
...
@@ -51,18 +52,20 @@
<el-form-item
label=
"标题"
prop=
"title"
>
<el-input
v-model=
"form.title"
placeholder=
"输入标题"
/>
</el-form-item>
<el-form-item
label=
"前端页面"
prop=
"key"
>
<el-select
v-model=
"form.key"
placeholder=
"请选择前端页面"
>
<el-option
v-for=
"item in routePath"
:key=
"item.key"
:label=
"item.path"
:value=
"item.key"
/>
</el-select>
<el-form-item
label=
"路由标识"
prop=
"key"
>
<el-input
v-model=
"form.key"
placeholder=
"输入路由标识"
/>
<!--
<el-select
v-model=
"form.key"
placeholder=
"请选择前端页面"
>
-->
<!--
<el-option-->
<!-- v-for="item in routePath"-->
<!-- :key="item.key"-->
<!-- :label="item.path"-->
<!-- :value="item.key"-->
<!-- />-->
<!--
</el-select>
-->
</el-form-item>
<el-form-item
label=
"后端接口地址"
prop=
"path"
>
<el-input
v-model=
"form.
path
"
placeholder=
"输入接口地址"
/>
<el-input
v-model=
"form.
api
"
placeholder=
"输入接口地址"
/>
</el-form-item>
<el-form-item
label=
"图标"
prop=
"icon"
>
<el-input
v-model=
"form.icon"
placeholder=
"输入图标"
/>
...
...
@@ -103,10 +106,10 @@ export default {
treeData
:
[],
treeSelectData
:
[],
form
:
{
parent_id
:
''
,
parent_id
:
0
,
title
:
''
,
key
:
'Dashboard'
,
path
:
''
,
api
:
''
,
icon
:
''
,
is_menu
:
1
}
...
...
@@ -130,27 +133,37 @@ export default {
methods
:
{
resetForm
()
{
this
.
form
=
{
parent_id
:
''
,
parent_id
:
0
,
title
:
''
,
key
:
'
Dashboard
'
,
key
:
''
,
path
:
''
,
icon
:
''
,
is_menu
:
1
}
},
init
()
{
// 注册功能页路由
this
.
dialogFormVisible
=
false
menuList
().
then
(
res
=>
{
const
menus
=
res
.
data
const
rootRouter
=
{
id
:
0
,
label
:
'ROOT'
,
children
:
[]
}
const
childrenNav
=
[]
this
.
listToTree
(
menus
,
childrenNav
,
0
)
this
.
treeData
=
childrenNav
rootRouter
.
children
=
childrenNav
this
.
treeData
=
[
rootRouter
]
const
rootRouterSelect
=
{
value
:
0
,
label
:
'ROOT'
,
children
:
[]
}
const
treeChildSelectData
=
[]
this
.
listToSelectTree
(
menus
,
treeChildSelectData
,
0
)
this
.
treeSelectData
=
treeChildSelectData
this
.
dialogFormVisible
=
false
rootRouterSelect
.
children
=
treeChildSelectData
this
.
treeSelectData
=
[
rootRouterSelect
]
})
},
...
...
@@ -201,8 +214,8 @@ export default {
this
.
form
=
{
parent_id
:
this
.
form_parent_menu_id
,
title
:
''
,
key
:
'
Dashboard
'
,
path
:
''
,
key
:
''
,
api
:
''
,
icon
:
''
,
is_menu
:
1
}
...
...
@@ -226,7 +239,7 @@ export default {
parent_id
:
menu_data
.
parent_id
,
title
:
menu_data
.
title
,
key
:
menu_data
.
key
,
path
:
menu_data
.
path
,
api
:
menu_data
.
api
,
icon
:
menu_data
.
icon
,
is_menu
:
menu_data
.
is_menu
}
...
...
src/views/system/power/role/
List
.vue
→
src/views/system/power/role/
index
.vue
View file @
26ca100a
File moved
src/views/system/power/user/
List
.vue
→
src/views/system/power/user/
index
.vue
View file @
26ca100a
...
...
@@ -83,6 +83,7 @@ import { roleList } from '@/api/role'
export
default
{
data
()
{
return
{
imageUrl
:
''
,
user
:
{
username
:
''
,
password
:
''
,
...
...
@@ -202,4 +203,27 @@ export default {
margin-bottom
:
30px
;
}
}
.avatar-uploader
.el-upload
{
border
:
1px
dashed
#d9d9d9
;
border-radius
:
6px
;
cursor
:
pointer
;
position
:
relative
;
overflow
:
hidden
;
}
.avatar-uploader
.el-upload
:hover
{
border-color
:
#409EFF
;
}
.avatar-uploader-icon
{
font-size
:
28px
;
color
:
#8c939d
;
width
:
178px
;
height
:
178px
;
line-height
:
178px
;
text-align
:
center
;
}
.avatar
{
width
:
178px
;
height
:
178px
;
display
:
block
;
}
</
style
>
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