Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
so-manage-ui
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
smart-operation
so-manage-ui
Commits
c11a241c
Commit
c11a241c
authored
Jun 20, 2023
by
张耀
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'dev' into zy
parents
2669e8be
07cf72aa
Changes
31
Hide whitespace changes
Inline
Side-by-side
Showing
31 changed files
with
6093 additions
and
206 deletions
+6093
-206
.prettierignore
.prettierignore
+10
-0
.prettierrc
.prettierrc
+7
-0
.prettierrc.js
.prettierrc.js
+1
-1
.vscode/settings.json
.vscode/settings.json
+14
-1
jsconfig.json
jsconfig.json
+13
-0
src/App.vue
src/App.vue
+3
-1
src/assets/css/common.scss
src/assets/css/common.scss
+45
-0
src/bg-ui/bg-table-btns2.vue
src/bg-ui/bg-table-btns2.vue
+78
-76
src/components/login-by-account.vue
src/components/login-by-account.vue
+16
-13
src/components/login-by-code.vue
src/components/login-by-code.vue
+15
-18
src/main.js
src/main.js
+3
-7
src/page/main/auto-maintenance/task-manage/index.vue
src/page/main/auto-maintenance/task-manage/index.vue
+441
-3
src/page/main/config/dict/index.vue
src/page/main/config/dict/index.vue
+16
-47
src/page/main/config/preference/index.vue
src/page/main/config/preference/index.vue
+7
-20
src/page/main/system-admin/dict/index.vue
src/page/main/system-admin/dict/index.vue
+700
-3
src/page/main/system-admin/log/index.vue
src/page/main/system-admin/log/index.vue
+0
-7
src/page/main/system-admin/log/system-log/index.vue
src/page/main/system-admin/log/system-log/index.vue
+244
-0
src/page/main/system-admin/log/userAccount/index.vue
src/page/main/system-admin/log/userAccount/index.vue
+468
-0
src/page/main/system-admin/log/userBehavior/detail/index.vue
src/page/main/system-admin/log/userBehavior/detail/index.vue
+157
-0
src/page/main/system-admin/log/userBehavior/index.vue
src/page/main/system-admin/log/userBehavior/index.vue
+487
-0
src/page/main/system-admin/menu/index.vue
src/page/main/system-admin/menu/index.vue
+652
-3
src/page/main/system-admin/menu/menu-form.vue
src/page/main/system-admin/menu/menu-form.vue
+367
-0
src/page/main/system-admin/preference/authorityForm.vue
src/page/main/system-admin/preference/authorityForm.vue
+73
-0
src/page/main/system-admin/preference/index.vue
src/page/main/system-admin/preference/index.vue
+307
-3
src/page/main/system-admin/preference/loginPageForm.vue
src/page/main/system-admin/preference/loginPageForm.vue
+134
-0
src/page/main/system-admin/preference/registerForm.vue
src/page/main/system-admin/preference/registerForm.vue
+95
-0
src/page/main/system-admin/preference/secureForm.vue
src/page/main/system-admin/preference/secureForm.vue
+110
-0
src/page/main/system-admin/visit-control/add/index.vue
src/page/main/system-admin/visit-control/add/index.vue
+508
-0
src/page/main/system-admin/visit-control/edit/index.vue
src/page/main/system-admin/visit-control/edit/index.vue
+543
-0
src/page/main/system-admin/visit-control/index.vue
src/page/main/system-admin/visit-control/index.vue
+576
-3
src/router/function.js
src/router/function.js
+3
-0
No files found.
.prettierignore
0 → 100644
View file @
c11a241c
node_modules
dist
pnpm-lock.yaml
auto-imports.d.ts
components.d.ts
env.d.ts
*.md
iconfont.js
.DS_Store
.history
.prettierrc
0 → 100644
View file @
c11a241c
{
"$schema": "http://json.schemastore.org/prettierrc",
"semi": true,
"singleQuote": false,
"bracketSameLine": true
}
\ No newline at end of file
.prettierrc.js
View file @
c11a241c
...
@@ -12,7 +12,7 @@ module.exports = {
...
@@ -12,7 +12,7 @@ module.exports = {
htmlWhitespaceSensitivity
:
"
css
"
,
htmlWhitespaceSensitivity
:
"
css
"
,
insertPragma
:
false
,
insertPragma
:
false
,
jsxSingleQuote
:
false
,
jsxSingleQuote
:
false
,
printWidth
:
10
0
,
// 如果属性过多需要换行,减少该值
printWidth
:
8
0
,
// 如果属性过多需要换行,减少该值
proseWrap
:
"
preserve
"
,
proseWrap
:
"
preserve
"
,
quoteProps
:
"
as-needed
"
,
quoteProps
:
"
as-needed
"
,
requirePragma
:
false
,
requirePragma
:
false
,
...
...
.vscode/settings.json
View file @
c11a241c
{
{
"editor.defaultFormatter"
:
"esbenp.prettier-vscode"
,
"editor.defaultFormatter"
:
"esbenp.prettier-vscode"
,
"GitCommitPlugin.ShowEmoji"
:
false
"GitCommitPlugin.ShowEmoji"
:
false
,
"editor.formatOnSave"
:
false
,
"editor.codeActionsOnSave"
:
{
"source.fixAll.eslint"
:
true
},
"volar.inlayHints.eventArgumentInInlineHandlers"
:
false
,
//
"path-intellisense.mappings"
:
{
//
"@"
:
"${workspaceFolder}/src"
//
},
//
文件保存自动格式化
"editor.formatOnSave"
:
true
,
"[vue]"
:
{
"editor.defaultFormatter"
:
"esbenp.prettier-vscode"
}
}
}
jsconfig.json
0 → 100644
View file @
c11a241c
//
https://code.visualstudio.com/docs/languages/jsconfig
{
"compilerOptions"
:
{
"baseUrl"
:
"."
,
"module"
:
"commonjs"
,
"target"
:
"es6"
,
"paths"
:
{
"@/*"
:
[
"./src/*"
]
}
},
"exclude"
:
[
".git"
,
"node_modules"
,
"dist"
]
}
\ No newline at end of file
src/App.vue
View file @
c11a241c
...
@@ -98,7 +98,7 @@ export default {
...
@@ -98,7 +98,7 @@ export default {
},
},
userInfo
:
{
userInfo
:
{
handler
()
{
handler
()
{
this
.
initMsg
();
//
this.initMsg();
},
},
deep
:
true
,
deep
:
true
,
},
},
...
@@ -126,6 +126,8 @@ export default {
...
@@ -126,6 +126,8 @@ export default {
this
.
readFlag
=
!
this
.
readFlag
;
this
.
readFlag
=
!
this
.
readFlag
;
},
},
initMsg
()
{
initMsg
()
{
console
.
log
(
this
.
userInfo
);
console
.
log
(
this
.
$trace
);
if
(
this
.
userInfo
&&
this
.
userInfo
.
system_id
)
{
if
(
this
.
userInfo
&&
this
.
userInfo
.
system_id
)
{
this
.
$trace
.
setOptionValue
(
"
userId
"
,
this
.
userInfo
.
system_id
);
this
.
$trace
.
setOptionValue
(
"
userId
"
,
this
.
userInfo
.
system_id
);
// this.$trace.setOptionValue('userType',this.userInfo.userType)
// this.$trace.setOptionValue('userType',this.userInfo.userType)
...
...
src/assets/css/common.scss
0 → 100644
View file @
c11a241c
.detail_container
{
width
:
100%
;
padding
:
0
24px
;
min-height
:
100%
;
display
:
flex
;
flex-direction
:
column
;
justify-content
:
flex-start
;
align-items
:
stretch
;
.main_container
{
flex-grow
:
1
;
width
:
100%
;
display
:
flex
;
flex-direction
:
column
;
justify-content
:
flex-start
;
align-items
:
stretch
;
background-color
:
#fff
;
box-shadow
:
0
1px
4px
0
rgba
(
0
,
7
,
101
,
0
.15
);
border-radius
:
6px
;
padding
:
0
0
16px
0
;
margin-bottom
:
16px
;
position
:
relative
;
.table_container
{
padding
:
0
16px
;
.el-table
{
flex
:
1
;
.mock_tip
{
display
:
inline-block
;
font-size
:
12px
;
color
:
#2b4695
;
width
:
43px
;
height
:
20px
;
text-align
:
center
;
background-color
:
#eff2fa
;
border-radius
:
3px
;
border
:
solid
1px
#b0bee8
;
margin-left
:
4px
;
}
}
}
}
}
\ No newline at end of file
src/bg-ui/bg-table-btns2.vue
View file @
c11a241c
<
template
>
<
template
>
<div
class=
"bg-table-btns"
ref=
"bgTableBtnsRef
"
>
<div
ref=
"bgTableBtnsRef"
class=
"bg-table-btns
"
>
<slot></slot>
<slot></slot>
<span
<el-popover
:popper-style=
"bgTablePopover"
trigger=
"hover"
:hide-after=
"50"
>
class=
"bg-table-btn more"
<div
class=
"more-box"
:style=
"state.style"
>
id=
"more_btn"
<span
v-if=
"state.children.length > limit"
v-for=
"(item, index) in state.lastChildren"
ref=
"lastEl"
:key=
"'as' + index"
@
mouseenter=
"showMoreBtns"
:class=
"item.disabled ? 'disabled' : ''"
@
mouseleave=
"hideMoreBtns"
>
@
click=
"action(item.onClick, item.disabled)"
<bg-icon
style=
"font-size: 12px; color: #2b4695"
icon=
"#bg-ic-s-more"
/>
>
{{
item
.
name
}}
</span
<teleport
to=
"body"
>
>
<div
</div>
class=
"more-box"
<template
#reference
>
:style=
"state.style"
<span
v-if=
"state.children.length - 1 > limit"
id=
"more_btn"
ref=
"lastEl"
class=
"bg-table-btn more"
>
v-if=
"state.showMore"
<bg-icon
style=
"font-size: 12px; color: #2b4695"
icon=
"#bg-ic-s-more"
/>
@
mouseenter=
"showMoreBtns"
</span>
@
mouseleave=
"hideMoreBtns"
>
<!-- 解决不需显示时警告问题 -->
<span
<span
v-else
></span>
v-for=
"(item, index) in state.lastChildren"
</
template
>
:key=
"'as' + index"
</el-popover>
@
click=
"action(item.onClick, item.disabled)"
:class=
"item.disabled ? 'disabled' : ''"
>
{{
item
.
name
}}
</span
>
</div>
</teleport>
</span>
</div>
</div>
</template>
</template>
<
script
setup
>
<
script
setup
>
import
{
reactive
,
ref
,
onBeforeMount
,
onMounted
,
toRefs
,
provide
,
useSlots
,
h
,
render
,
nextTick
}
from
"
vue
"
;
import
{
reactive
,
ref
,
onBeforeMount
,
onMounted
,
toRefs
,
provide
,
useSlots
,
watch
,
nextTick
}
from
"
vue
"
;
const
slots
=
useSlots
();
const
slots
=
useSlots
();
const
props
=
defineProps
({
const
props
=
defineProps
({
...
@@ -38,6 +31,10 @@ const props = defineProps({
...
@@ -38,6 +31,10 @@ const props = defineProps({
type
:
Number
,
type
:
Number
,
default
:
3
,
default
:
3
,
},
},
tableData
:
{
type
:
Array
,
default
:
()
=>
[],
},
});
});
const
bgTableBtnsRef
=
ref
(
null
);
const
bgTableBtnsRef
=
ref
(
null
);
...
@@ -51,60 +48,72 @@ const state = reactive({
...
@@ -51,60 +48,72 @@ const state = reactive({
showMore
:
false
,
showMore
:
false
,
});
});
watch
(
()
=>
props
.
tableData
,
()
=>
{
nextTick
(()
=>
{
calcTabs
();
dealData
();
});
},
{
deep
:
true
,
}
);
const
action
=
(
event
,
disable
)
=>
{
const
action
=
(
event
,
disable
)
=>
{
if
(
disable
)
{
if
(
disable
)
{
return
;
return
;
}
}
event
();
event
();
state
.
showMore
=
false
state
.
showMore
=
false
;
};
};
const
calcTabs
=
()
=>
{
const
calcTabs
=
()
=>
{
let
tabSlots
=
slots
.
default
()
||
[];
let
tabSlots
=
slots
.
default
()
||
[];
let
tempSlots
=
[];
state
.
lastChildren
=
[];
state
.
lastChildren
=
[];
if
(
tabSlots
)
{
tabSlots
.
forEach
((
e
)
=>
{
tabSlots
.
forEach
((
e
,
idx
)
=>
{
//注释和v-if忽略
if
(
idx
+
2
>
props
.
limit
&&
tabSlots
.
length
>
props
.
limit
&&
e
.
props
)
{
if
(
Object
.
prototype
.
toString
.
call
(
e
.
children
)
==
"
[object String]
"
)
{
//v-for 再次遍历
}
else
if
(
Object
.
prototype
.
toString
.
call
(
e
.
children
)
==
"
[object Array]
"
)
{
let
children
=
e
.
children
||
[];
children
.
forEach
((
el
)
=>
{
//注释和v-if忽略
if
(
Object
.
prototype
.
toString
.
call
(
e
.
children
)
==
"
[object String]
"
)
{
console
.
log
(
el
.
type
);
}
else
{
tempSlots
.
push
(
el
);
}
});
//普通节点
}
else
{
tempSlots
.
push
(
e
);
}
});
// debugger;
if
(
tempSlots
)
{
tempSlots
.
forEach
((
e
,
idx
)
=>
{
if
(
idx
+
2
>
props
.
limit
&&
tempSlots
.
length
>
props
.
limit
&&
e
.
props
)
{
// console.log(e);
// console.log(e.props);
state
.
lastChildren
.
push
(
e
.
props
);
state
.
lastChildren
.
push
(
e
.
props
);
}
}
});
});
}
}
};
};
const
showMoreBtns
=
()
=>
{
calcTabs
();
dealData
();
nextTick
(()
=>
{
updateSytle
();
if
(
state
.
timer
)
clearTimeout
(
state
.
timer
);
state
.
showMore
=
true
;
});
};
const
hideMoreBtns
=
()
=>
{
if
(
state
.
timer
)
clearTimeout
(
state
.
timer
);
state
.
timer
=
setTimeout
(()
=>
{
state
.
showMore
=
false
;
},
50
);
};
const
updateSytle
=
()
=>
{
let
{
top
,
right
}
=
lastEl
.
value
.
getBoundingClientRect
();
let
{
width
}
=
window
.
document
.
body
.
getBoundingClientRect
();
state
.
style
=
{
top
:
`
${
top
+
16
}
px`
,
right
:
`
${
width
-
right
-
16
}
px`
,
};
};
const
dealData
=
()
=>
{
const
dealData
=
()
=>
{
let
children
=
bgTableBtnsRef
.
value
.
children
||
[];
let
children
=
bgTableBtnsRef
.
value
.
children
||
[];
state
.
children
=
children
;
state
.
children
=
children
;
if
(
children
.
length
>
props
.
limit
)
{
if
(
children
.
length
-
1
>
props
.
limit
)
{
children
[
props
.
limit
-
1
].
style
.
display
=
"
none
"
;
children
[
props
.
limit
-
1
].
style
.
display
=
"
none
"
;
children
[
props
.
limit
-
1
].
style
.
width
=
"
0px
"
;
children
[
props
.
limit
-
1
].
style
.
width
=
"
0px
"
;
state
.
index
=
props
.
limit
-
2
;
state
.
index
=
props
.
limit
-
2
;
state
.
lastChildren
[
0
].
name
=
children
[
props
.
limit
-
1
].
innerText
;
state
.
lastChildren
[
0
].
name
=
children
[
props
.
limit
-
1
].
innerText
;
}
}
for
(
let
index
=
0
;
index
<
children
.
length
;
index
++
)
{
for
(
let
index
=
0
;
index
<
children
.
length
-
1
;
index
++
)
{
const
e
=
children
[
index
];
const
e
=
children
[
index
];
if
(
index
+
1
>
props
.
limit
&&
e
.
tagName
==
"
A
"
&&
e
.
className
.
indexOf
(
"
bg-table-btn
"
)
!==
-
1
)
{
if
(
index
+
1
>
props
.
limit
&&
e
.
tagName
==
"
A
"
&&
e
.
className
.
indexOf
(
"
bg-table-btn
"
)
!==
-
1
)
{
e
.
style
.
display
=
"
none
"
;
e
.
style
.
display
=
"
none
"
;
...
@@ -114,6 +123,14 @@ const dealData = () => {
...
@@ -114,6 +123,14 @@ const dealData = () => {
}
}
};
};
const
bgTablePopover
=
{
width
:
"
auto
"
,
maxWidth
:
"
96px
"
,
padding
:
"
4px 0
"
,
minWidth
:
"
60px
"
,
marginTop
:
"
-5px
"
,
};
onMounted
(()
=>
{
onMounted
(()
=>
{
calcTabs
();
calcTabs
();
dealData
();
dealData
();
...
@@ -126,35 +143,20 @@ onMounted(() => {
...
@@ -126,35 +143,20 @@ onMounted(() => {
z-index
:
200
;
z-index
:
200
;
}
}
.more-box
{
position
:
fixed
;
padding
:
4px
0
;
background-color
:
#ffffff
;
box-shadow
:
0px
4px
12px
0px
rgba
(
18
,
30
,
63
,
0.1
);
border-radius
:
4px
;
border
:
solid
1px
#e6e9ef
;
width
:
88px
;
z-index
:
300
;
}
.more-box
span
{
.more-box
span
{
display
:
block
;
display
:
block
;
overflow
:
hidden
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
text-overflow
:
ellipsis
;
word-break
:
break-all
;
word-break
:
break-all
;
white-space
:
nowrap
;
white-space
:
nowrap
;
display
:
block
;
padding
:
10px
16px
;
padding
:
0
16px
;
color
:
#404a62
;
margin
:
0
;
line-height
:
1
;
color
:
#202531
;
font-size
:
14px
;
line-height
:
34px
;
padding-left
:
16px
;
font-size
:
16px
;
cursor
:
pointer
;
cursor
:
pointer
;
}
}
.more-box
span
:hover
{
.more-box
span
:hover
{
background-color
:
#f2f3f7
;
background-color
:
#f2f3f7
;
color
:
#202531
;
}
}
.more-box
.disabled
{
.more-box
.disabled
{
color
:
#a9b1c7
;
color
:
#a9b1c7
;
...
...
src/components/login-by-account.vue
View file @
c11a241c
...
@@ -2,20 +2,22 @@
...
@@ -2,20 +2,22 @@
<div
class=
"login-by-account"
>
<div
class=
"login-by-account"
>
<el-form
ref=
"loginFormRef"
label-position=
"top"
:model=
"loginForm"
:rules=
"steploginFormRules"
>
<el-form
ref=
"loginFormRef"
label-position=
"top"
:model=
"loginForm"
:rules=
"steploginFormRules"
>
<el-form-item
prop=
"userid"
>
<el-form-item
prop=
"userid"
>
<el-input
v-model=
"loginForm.userid"
placeholder=
"请输入账号"
@
keyup.enter
.native
=
"loginAction()"
/>
<el-input
v-model=
"loginForm.userid"
placeholder=
"请输入账号"
@
keyup.enter=
"loginAction()"
/>
</el-form-item>
</el-form-item>
<el-form-item
prop=
"password"
>
<el-form-item
prop=
"password"
>
<el-input
<el-input
:type=
"hidePassword ? 'password' : 'text'"
:type=
"hidePassword ? 'password' : 'text'"
v-model=
"loginForm.password"
v-model=
"loginForm.password"
placeholder=
"请输入密码"
placeholder=
"请输入密码"
@
keyup.enter.native=
"loginAction()"
>
@
keyup.enter=
"loginAction()"
>
<span
<template
#suffix
>
slot=
"suffix"
<span
:title=
"!hidePassword ? '隐藏密码' : '显示密码'"
>
:title=
"hidePassword ? '显示密码' : '隐藏密码'"
<bg-icon
:class=
"hidePassword ? 'hide-password' : 'show-password'"
@
click=
"hidePassword = !hidePassword"
@
click=
"hidePassword = !hidePassword"
style=
"font-size: 16px; color: #a9b1c7; cursor: pointer"
style=
"cursor: pointer"
></span>
:icon=
"hidePassword ? '#bg-ic-eye' : '#bg-ic-eye-close'"
></bg-icon>
</span>
</
template
>
</el-input>
</el-input>
</el-form-item>
</el-form-item>
<el-form-item
prop=
"yzm"
>
<el-form-item
prop=
"yzm"
>
...
@@ -23,7 +25,7 @@
...
@@ -23,7 +25,7 @@
<el-input
<el-input
v-model=
"loginForm.yzm"
v-model=
"loginForm.yzm"
placeholder=
"请输入验证码"
placeholder=
"请输入验证码"
@
keyup.enter
.native
=
"loginAction()"
@
keyup.enter=
"loginAction()"
style=
"width: 240px"
/>
style=
"width: 240px"
/>
<div
class=
"yzm_img"
>
<div
class=
"yzm_img"
>
<img
title=
"看不清?换一张"
:src=
"imgSrc"
@
click=
"getImg()"
style=
"width: 100%"
/>
<img
title=
"看不清?换一张"
:src=
"imgSrc"
@
click=
"getImg()"
style=
"width: 100%"
/>
...
@@ -57,6 +59,9 @@ import { ElMessage } from "element-plus";
...
@@ -57,6 +59,9 @@ import { ElMessage } from "element-plus";
import
axios
from
"
@/request/http.js
"
;
import
axios
from
"
@/request/http.js
"
;
import
{
Encrypt
}
from
"
@/services/secret.js
"
;
import
{
Encrypt
}
from
"
@/services/secret.js
"
;
import
{
useStore
}
from
"
vuex
"
;
import
{
useStore
}
from
"
vuex
"
;
import
{
useRouter
}
from
"
vue-router
"
;
const
router
=
useRouter
();
const
state
=
reactive
({
const
state
=
reactive
({
loginForm
:
{
loginForm
:
{
...
@@ -125,7 +130,7 @@ const getMenu = (search) => {
...
@@ -125,7 +130,7 @@ const getMenu = (search) => {
return
axios
.
get
(
`/apaas/system/v5/menu/user/tree?search=
${
search
}
`
);
return
axios
.
get
(
`/apaas/system/v5/menu/user/tree?search=
${
search
}
`
);
};
};
const
getUser
=
()
=>
{
const
getUser
=
()
=>
{
Promise
.
all
([
getUserInfo
(),
getMenu
(
"
dadb2d3f-e263-48d1-9389-42acb9ea49f8
"
)]).
then
((
res
)
=>
{
Promise
.
all
([
getUserInfo
(),
getMenu
(
"
79a8f214-db78-4db7-9c28-db66276b4be2
"
)]).
then
((
res
)
=>
{
if
(
res
[
0
].
data
.
code
==
200
&&
res
[
1
].
data
.
code
==
200
)
{
if
(
res
[
0
].
data
.
code
==
200
&&
res
[
1
].
data
.
code
==
200
)
{
let
data
=
(
res
[
1
].
data
.
data
&&
res
[
1
].
data
.
data
[
0
].
children
)
||
[];
let
data
=
(
res
[
1
].
data
.
data
&&
res
[
1
].
data
.
data
[
0
].
children
)
||
[];
store
.
commit
(
"
setUserInfo
"
,
res
[
0
].
data
.
data
);
store
.
commit
(
"
setUserInfo
"
,
res
[
0
].
data
.
data
);
...
@@ -143,9 +148,7 @@ const getUser = () => {
...
@@ -143,9 +148,7 @@ const getUser = () => {
store
.
commit
(
"
setMenuObj
"
,
menuObj
);
store
.
commit
(
"
setMenuObj
"
,
menuObj
);
// }
// }
generateRoutes
();
generateRoutes
();
// this.$router.push("/");
router
.
push
(
"
/
"
);
//跳转到工作台页面
window
.
location
.
href
=
"
/apaas/portal/ui/#/
"
;
}
}
});
});
};
};
...
...
src/components/login-by-code.vue
View file @
c11a241c
...
@@ -6,14 +6,14 @@
...
@@ -6,14 +6,14 @@
v-model=
"loginForm.mobile"
v-model=
"loginForm.mobile"
autofocus=
"autofocus"
autofocus=
"autofocus"
placeholder=
"请输入手机号码"
placeholder=
"请输入手机号码"
@
keyup.enter
.native
=
"loginAction()"
/>
@
keyup.enter=
"loginAction()"
/>
</el-form-item>
</el-form-item>
<el-form-item
prop=
"code"
>
<el-form-item
prop=
"code"
>
<div
class=
"msg-code"
>
<div
class=
"msg-code"
>
<el-input
<el-input
v-model=
"loginForm.code"
v-model=
"loginForm.code"
placeholder=
"请输入验证码"
placeholder=
"请输入验证码"
@
keyup.enter
.native
=
"loginAction()"
@
keyup.enter=
"loginAction()"
style=
"width: 280px"
>
style=
"width: 280px"
>
</el-input>
</el-input>
<div
class=
"yzm_img"
>
<div
class=
"yzm_img"
>
...
@@ -34,9 +34,7 @@
...
@@ -34,9 +34,7 @@
</div>
</div>
</el-form-item>
</el-form-item>
<el-form-item>
<el-form-item>
<el-button
type=
"primary"
@
click.prevent=
"loginAction()"
style=
"width: 100%"
>
<el-button
type=
"primary"
@
click.prevent=
"loginAction()"
style=
"width: 100%"
>
登 录
</el-button>
登 录
</el-button>
</el-form-item>
</el-form-item>
<el-form-item>
<el-form-item>
<el-button
class=
"register_btn"
@
click.prevent=
"$emit('register')"
style=
"width: 100%"
>
<el-button
class=
"register_btn"
@
click.prevent=
"$emit('register')"
style=
"width: 100%"
>
...
@@ -58,6 +56,9 @@ import { generateRoutes } from "../router/index";
...
@@ -58,6 +56,9 @@ import { generateRoutes } from "../router/index";
import
{
ElMessage
}
from
"
element-plus
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
axios
from
"
@/request/http.js
"
;
import
axios
from
"
@/request/http.js
"
;
import
{
useStore
}
from
"
vuex
"
;
import
{
useStore
}
from
"
vuex
"
;
import
{
useRouter
}
from
"
vue-router
"
;
const
router
=
useRouter
();
const
validatePhone
=
(
rule
,
value
,
callback
)
=>
{
const
validatePhone
=
(
rule
,
value
,
callback
)
=>
{
const
reg
=
/^
(?:(?:\+
|00
)
86
)?
1
[
3-9
]\d{9}
$/
;
const
reg
=
/^
(?:(?:\+
|00
)
86
)?
1
[
3-9
]\d{9}
$/
;
...
@@ -93,15 +94,13 @@ const loginFormRef = ref(null);
...
@@ -93,15 +94,13 @@ const loginFormRef = ref(null);
const
getMsgCode
=
()
=>
{
const
getMsgCode
=
()
=>
{
loginFormRef
.
value
.
validateField
(
"
mobile
"
,
(
valid
)
=>
{
loginFormRef
.
value
.
validateField
(
"
mobile
"
,
(
valid
)
=>
{
if
(
valid
)
{
if
(
valid
)
{
axios
axios
.
post
(
"
/apaas/system/v5/sms/verifyCode
"
,
{
phone
:
state
.
loginForm
.
mobile
}).
then
(({
data
})
=>
{
.
post
(
"
/apaas/system/v5/sms/verifyCode
"
,
{
phone
:
state
.
loginForm
.
mobile
})
if
(
data
.
code
==
200
)
{
.
then
(({
data
})
=>
{
countDownAction
();
if
(
data
.
code
==
200
)
{
}
else
{
countDownAction
();
ElMessage
.
error
(
data
.
data
);
}
else
{
}
ElMessage
.
error
(
data
.
data
);
});
}
});
}
}
});
});
};
// 获取验证码
};
// 获取验证码
...
@@ -149,7 +148,7 @@ const getMenu = (search) => {
...
@@ -149,7 +148,7 @@ const getMenu = (search) => {
return
axios
.
get
(
`/apaas/system/v5/menu/user/tree?search=
${
search
}
`
);
return
axios
.
get
(
`/apaas/system/v5/menu/user/tree?search=
${
search
}
`
);
};
};
const
getUser
=
()
=>
{
const
getUser
=
()
=>
{
Promise
.
all
([
getUserInfo
(),
getMenu
(
"
dadb2d3f-e263-48d1-9389-42acb9ea49f8
"
)]).
then
((
res
)
=>
{
Promise
.
all
([
getUserInfo
(),
getMenu
(
"
79a8f214-db78-4db7-9c28-db66276b4be2
"
)]).
then
((
res
)
=>
{
if
(
res
[
0
].
data
.
code
==
200
&&
res
[
1
].
data
.
code
==
200
)
{
if
(
res
[
0
].
data
.
code
==
200
&&
res
[
1
].
data
.
code
==
200
)
{
let
data
=
(
res
[
1
].
data
.
data
&&
res
[
1
].
data
.
data
[
0
].
children
)
||
[];
let
data
=
(
res
[
1
].
data
.
data
&&
res
[
1
].
data
.
data
[
0
].
children
)
||
[];
store
.
commit
(
"
setUserInfo
"
,
res
[
0
].
data
.
data
);
store
.
commit
(
"
setUserInfo
"
,
res
[
0
].
data
.
data
);
...
@@ -167,9 +166,7 @@ const getUser = () => {
...
@@ -167,9 +166,7 @@ const getUser = () => {
store
.
commit
(
"
setMenuObj
"
,
menuObj
);
store
.
commit
(
"
setMenuObj
"
,
menuObj
);
// }
// }
generateRoutes
();
generateRoutes
();
// this.$router.push("/");
router
.
push
(
"
/
"
);
//跳转到工作台页面
window
.
location
.
href
=
"
/apaas/portal/ui/#/
"
;
}
}
});
});
};
};
...
...
src/main.js
View file @
c11a241c
...
@@ -12,6 +12,8 @@ import * as ElementPlusIconsVue from "@element-plus/icons-vue";
...
@@ -12,6 +12,8 @@ import * as ElementPlusIconsVue from "@element-plus/icons-vue";
import
bgui
from
"
@/bg-ui
"
;
import
bgui
from
"
@/bg-ui
"
;
import
"
@/bg-ui/index.scss
"
;
import
"
@/bg-ui/index.scss
"
;
import
"
./assets/css/common.scss
"
;
import
msgSdk
from
"
./msg-sdk/index.js
"
;
import
msgSdk
from
"
./msg-sdk/index.js
"
;
import
App
from
"
./App.vue
"
;
import
App
from
"
./App.vue
"
;
...
@@ -107,13 +109,7 @@ Promise.all([getUser(), getMenu("79a8f214-db78-4db7-9c28-db66276b4be2")])
...
@@ -107,13 +109,7 @@ Promise.all([getUser(), getMenu("79a8f214-db78-4db7-9c28-db66276b4be2")])
console
.
error
(
e
);
console
.
error
(
e
);
})
})
.
finally
(()
=>
{
.
finally
(()
=>
{
createVue
createVue
.
use
(
ElementPlus
,
{
locale
}).
use
(
store
).
use
(
router
).
use
(
i18n
).
use
(
bgui
).
use
(
mavonEditor
);
.
use
(
ElementPlus
,
{
locale
})
.
use
(
store
)
.
use
(
router
)
.
use
(
i18n
)
.
use
(
bgui
)
.
use
(
mavonEditor
);
createVue
.
mount
(
"
#app
"
);
createVue
.
mount
(
"
#app
"
);
});
});
...
...
src/page/main/auto-maintenance/task-manage/index.vue
View file @
c11a241c
<
template
>
<
template
>
<div>
任务管理
</div>
<div
class=
"detail_container"
>
<bg-breadcrumb></bg-breadcrumb>
<div
class=
"main_container"
>
<bg-filter-group
@
search=
"changeSearch"
v-model=
"filter.search"
placeholder=
"请输入关键字"
>
<template
v-slot:left_action
>
<div
class=
"apaas_button"
>
<el-button
type=
"primary"
@
click=
"register"
>
<bg-icon
style=
"font-size: 12px; color: #fff; margin-right: 8px"
icon=
"#bg-ic-add"
></bg-icon>
新增
</el-button>
<el-button
type=
"default"
@
click=
"deleteAllTips"
>
批量删除
</el-button>
<span
class=
"header_info"
>
已选择
<span
style=
"color: #202531; font-weight: bold"
>
{{
state
.
selected
.
length
}}
</span>
项
</span>
<span
class=
"header_info can_click_text"
@
click=
"clearSelected"
>
清空
</span>
</div>
</
template
>
<
template
v-slot:filter_group
>
<div
class=
"left-filter filter_list"
>
<div
class=
"filter_item"
>
<span
class=
"filter_title"
>
创建时间
</span>
<el-date-picker
v-model=
"filter.time"
type=
"daterange"
value-format=
"yyyy-MM-DD"
range-separator=
"至"
start-placeholder=
"开始日期"
end-placeholder=
"结束日期"
/>
</div>
</div>
<div
class=
"right-action apaas_button"
>
<el-button
type=
"primary"
@
click=
"filterAction"
>
查询
</el-button>
<el-button
type=
"default"
@
click=
"filterClear"
>
重置
</el-button>
</div>
</
template
>
</bg-filter-group>
<div
class=
"table_container"
>
<div
class=
"table bg-scroll"
>
<bg-table
ref=
"dataTable"
:headers=
"headers"
:rows=
"tableRows"
@
selectAc=
"selectRows"
:isIndex=
"true"
:select=
"true"
:stripe=
"true"
>
<
template
v-slot:name=
"{ row }"
>
<span
class=
"can_click_text"
@
click=
"getChildren(row)"
v-if=
"row.children"
>
{{
row
.
name
}}
</span>
<span
v-else
>
{{
row
.
name
}}
</span>
</
template
>
<
template
v-slot:updated_time=
"{ row }"
>
{{
row
.
updated_time
.
split
(
"
+
"
)[
0
].
replace
(
"
T
"
,
"
"
).
replace
(
"
Z
"
,
"
"
)
}}
</
template
>
<
template
v-slot:action=
"{ row }"
>
<bg-table-btns2
:limit=
"3"
:tableData=
"tableRows"
>
<bg-table-btn
@
click=
"useRow(row)"
>
执行任务
</bg-table-btn>
<bg-table-btn
@
click=
"editRow(row)"
>
编辑
</bg-table-btn>
<bg-table-btn
@
click=
"copyRow(row, 1)"
>
复制
</bg-table-btn>
<bg-table-btn
@
click=
"deleteRow(row, 2)"
>
删除
</bg-table-btn>
</bg-table-btns2>
</
template
>
</bg-table>
</div>
<bg-pagination
:page=
"filter.page"
:size=
"filter.size"
:total=
"tableTotal"
@
change-page=
"changePage"
@
change-size=
"changeSize"
>
</bg-pagination>
</div>
</div>
<!-- 新增/编辑弹窗 -->
<!-- <el-dialog
class="dialog_box"
:title="addType == 1 ? '新增' : '编辑'"
v-model="addDialog"
width="758px">
<el-form ref="bgForm" :model="formData" :rules="rules" label-width="80px" class="bg_form">
<el-form-item label="名称" prop="name">
<el-input
v-model.trim="formData.name"
show-word-limit
:maxlength="
nodeClassifyId == 'eb9c7d70-c123-42b7-8e61-dde1b022b669'
? 6
: nodeClassifyId == 'efd9ec3b-7f18-49e2-9d88-bcca022243bb'
? 4
: nodeClassifyId == '949a1138-4995-464e-97a9-424d097eb271'
? 2
: 20
"
placeholder="请输入名称"></el-input>
</el-form-item>
<el-form-item label="描述" prop="describe">
<el-input
v-model="formData.describe"
type="textarea"
:autosize="{ minRows: 5 }"
show-word-limit
maxlength="200"
resize="vertical"
placeholder="请输入描述"></el-input>
</el-form-item>
<el-form-item label="是否启用" prop="state" style="margin-bottom: 0px">
<el-switch
class="bg-switch-ele"
v-model="formData.state"
:active-value="1"
:inactive-value="0"
inline-prompt
active-text="是"
inactive-text="否" />
</el-form-item>
</el-form>
<template v-slot:footer>
<div class="apaas_button">
<el-button type="default" @click="addDialog = false">取 消</el-button>
<el-button type="primary" @click="addConfirm">保 存</el-button>
</div>
</template>
</el-dialog> -->
<!-- 删除弹窗 -->
<!-- <el-dialog
class="dialog_box"
title="提示"
v-model="dialogDelete"
width="400px"
:before-close="
() => {
dialogDelete = false;
}
">
<div>确定要删除此字典值吗?</div>
<template v-slot:footer>
<div class="apaas_button">
<el-button type="default" @click="dialogDelete = false">取 消</el-button>
<el-button type="primary" @click="deleteData">确 定</el-button>
</div>
</template>
</el-dialog> -->
</div>
</template>
</template>
<
script
setup
></
script
>
<
script
setup
>
import
{
reactive
,
ref
,
onBeforeMount
,
toRefs
,
computed
,
watch
,
nextTick
,
watchEffect
}
from
"
vue
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
axios
from
"
@/request/http.js
"
;
import
{
Search
}
from
"
@element-plus/icons-vue
"
;
import
bgBreadcrumb
from
"
@/components/bg-breadcrumb.vue
"
;
const
bgForm
=
ref
(
null
);
const
dataTable
=
ref
(
null
);
const
headers
=
[
{
label
:
"
任务名称
"
,
prop
:
"
name
"
,
},
{
label
:
"
执行次数
"
,
prop
:
"
times
"
,
},
{
label
:
"
描述
"
,
prop
:
"
describe
"
,
minWidth
:
360
,
},
{
label
:
"
创建人
"
,
prop
:
"
person
"
,
},
{
label
:
"
创建时间
"
,
prop
:
"
updated_time
"
,
width
:
220
,
},
{
label
:
"
操作
"
,
prop
:
"
action
"
,
width
:
200
,
fixed
:
"
right
"
,
},
];
<
style
lang=
"scss"
scoped
></
style
>
const
state
=
reactive
({
bgForm
,
typeList
:
[],
// 分类数据
typeKeyword
:
""
,
// 分类删选关键词
nodeClassifyId
:
null
,
// 当前选中分类的uuid 用于新增字典
nodeId
:
null
,
// 当前选中分类的id 用于请求列表
timer
:
null
,
// 定时器
tableRows
:
[],
// 表格数据
selected
:
[],
//选择数据
tableTotal
:
0
,
// 表格数据条数
filter
:
{
time
:
""
,
search
:
""
,
page
:
1
,
limit
:
10
,
},
// 表格筛选项
stateOptions
:
[
{
name
:
"
全部
"
,
value
:
""
,
},
{
name
:
"
启用
"
,
value
:
"
1
"
,
},
{
name
:
"
禁用
"
,
value
:
"
0
"
,
},
],
// 启用禁用
actionRow
:
null
,
// 当前操作的数据
dialogDelete
:
false
,
// 删除弹窗
addType
:
0
,
//
addDialog
:
false
,
formData
:
{
name
:
""
,
describe
:
""
,
state
:
1
,
p_dict_id
:
""
,
},
rules
:
{
name
:
[{
required
:
true
,
message
:
"
请输入名称
"
,
trigger
:
"
blur
"
}],
describe
:
[
{
required
:
true
,
message
:
"
请输入描述
"
,
trigger
:
"
blur
"
},
{
max
:
200
,
message
:
"
描述最大为200字
"
,
trigger
:
"
blur
"
},
],
state
:
[{
required
:
true
,
message
:
"
请选择是否启用
"
,
trigger
:
"
change
"
}],
},
fatherRow
:
null
,
});
const
selectRows
=
(
data
)
=>
{
state
.
selected
=
data
.
selection
;
};
const
clearSelected
=
()
=>
{
dataTable
.
value
.
clearTable
();
};
const
deleteAllTips
=
()
=>
{};
const
dictLevel
=
ref
(
1
);
const
getChildren
=
(
row
)
=>
{
dictLevel
.
value
=
2
;
state
.
tableRows
=
row
.
children
||
[];
state
.
tableTotal
=
row
.
total_children
;
state
.
fatherRow
=
row
;
};
const
getTypeList
=
()
=>
{
let
params
=
{
name
:
state
.
typeKeyword
,
};
axios
.
get
(
`/apaas/system/v5/dictionary/classify/list`
,
{
params
})
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
state
.
typeList
=
res
.
data
.
data
||
[];
state
.
nodeClassifyId
=
state
.
typeList
[
0
].
classify_id
||
null
;
state
.
nodeId
=
state
.
typeList
[
0
].
id
||
null
;
if
(
state
.
nodeId
)
{
getTableRows
();
}
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
})
.
catch
((
err
)
=>
{
console
.
log
(
err
);
});
};
// 获取字典分类
const
changeSearch
=
(
val
)
=>
{
state
.
filter
.
search
=
val
;
changePage
(
1
);
};
// 表格关键字筛选
const
filterAction
=
()
=>
{
changePage
(
1
);
};
// 查询按钮
const
filterClear
=
()
=>
{
state
.
filter
=
{
time
:
""
,
search
:
""
,
limit
:
10
,
page
:
1
,
};
changePage
(
1
);
};
// 重置筛选项
const
getTableRows
=
()
=>
{
let
params
=
{
...
state
.
filter
};
params
.
id
=
state
.
nodeId
;
axios
.
get
(
`/apaas/system/v5/dictionary/list`
,
{
params
,
})
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
let
data
=
res
.
data
.
data
||
[];
if
(
dictLevel
.
value
==
1
)
{
state
.
tableRows
=
data
;
state
.
tableTotal
=
res
.
data
.
total
;
}
else
{
let
row
=
data
.
filter
((
e
)
=>
{
return
e
.
dict_id
==
state
.
fatherRow
.
dict_id
;
});
state
.
tableRows
=
row
[
0
].
children
;
state
.
tableTotal
=
row
[
0
].
total_children
;
}
if
(
state
.
tableRows
.
length
>
0
)
{
state
.
tableRows
.
forEach
((
e
)
=>
{
e
.
canMoveUp
=
true
;
e
.
canMoveDown
=
true
;
});
state
.
tableRows
[
0
].
canMoveUp
=
false
;
state
.
tableRows
[
state
.
tableRows
.
length
-
1
].
canMoveDown
=
false
;
}
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
// 获取表格数据
const
changePage
=
(
page
)
=>
{
state
.
filter
.
page
=
page
;
getTableRows
();
};
// 改变页码
const
changeSize
=
(
size
)
=>
{
state
.
filter
.
limit
=
size
;
changePage
(
1
);
};
// 改变每页条数
const
register
=
()
=>
{
state
.
formData
=
{
name
:
""
,
describe
:
""
,
state
:
1
,
p_dict_id
:
state
.
fatherRow
?
state
.
fatherRow
.
dict_id
:
""
,
};
if
(
state
.
bgForm
)
{
nextTick
().
then
(()
=>
{
state
.
bgForm
.
validate
((
valid
)
=>
{
if
(
!
valid
)
{
state
.
bgForm
.
clearValidate
();
}
});
});
}
state
.
addType
=
1
;
state
.
addDialog
=
true
;
};
// 新增字典按钮
onBeforeMount
(()
=>
{
getTypeList
();
});
const
{
tableRows
,
tableTotal
,
filter
}
=
toRefs
(
state
);
</
script
>
<
style
lang=
"scss"
scoped
>
.detail_container
{
width
:
100%
;
height
:
calc
(
100vh
-
56px
);
padding
:
0
24px
;
min-height
:
100%
;
display
:
flex
;
flex-direction
:
column
;
justify-content
:
flex-start
;
align-items
:
stretch
;
.main_container
{
height
:
100%
;
.filter-group
{
.left-filter
{
flex
:
1
;
display
:
flex
;
justify-content
:
start
;
flex-wrap
:
wrap
;
}
.right-action
{
width
:
144px
;
padding-bottom
:
16px
;
.el-button
{
width
:
64px
;
}
}
}
.table_container
{
height
:
calc
(
100%
-
70px
);
width
:
100%
;
padding
:
0
16px
;
.table
{
max-height
:
calc
(
100%
-
64px
);
}
}
}
.bg_form
{
width
:
100%
;
box-sizing
:
border-box
;
.el-form-item
{
margin-bottom
:
24px
;
:deep
()
.el-form-item__label
{
line-height
:
36px
;
height
:
36px
;
}
.el-form-item__content
{
width
:
100%
;
.el-textarea
{
:deep
()
.el-input__count
{
bottom
:
-16px
;
right
:
4px
;
font-family
:
Roboto-Regular
;
color
:
#a9b1c7
;
}
}
.bg-switch-ele
{
width
:
52px
;
height
:
24px
;
:deep
()
.el-switch__core
{
width
:
100%
;
height
:
24px
;
.el-switch__inner
,
.el-switch__action
{
top
:
3px
;
}
}
}
}
}
}
}
</
style
>
src/page/main/config/dict/index.vue
View file @
c11a241c
...
@@ -25,22 +25,15 @@
...
@@ -25,22 +25,15 @@
</div>
</div>
<div
class=
"flex_right"
>
<div
class=
"flex_right"
>
<div
class=
"main_container"
>
<div
class=
"main_container"
>
<bg-filter-group
<bg-filter-group
@
search=
"changeSearch"
v-model=
"filter.search"
placeholder=
"请输入关键字"
>
@
search=
"changeSearch"
<template
v-slot:left_action
v-if=
"nodeClassifyId != '263758a4-0349-4d49-a816-e8ff8d33a8bb'"
>
v-model=
"filter.search"
placeholder=
"请输入关键字"
>
<template
v-slot:left_action
v-if=
"nodeClassifyId != '263758a4-0349-4d49-a816-e8ff8d33a8bb'"
>
<div
class=
"apaas_button"
>
<div
class=
"apaas_button"
>
<el-button
type=
"primary"
@
click=
"backDict"
v-if=
"dictLevel != 1"
>
<el-button
type=
"primary"
@
click=
"backDict"
v-if=
"dictLevel != 1"
>
<!--
<bg-icon
style=
"font-size: 12px; color: #fff; margin-right: 8px"
icon=
"#bg-ic-add"
></bg-icon>
-->
<!--
<bg-icon
style=
"font-size: 12px; color: #fff; margin-right: 8px"
icon=
"#bg-ic-add"
></bg-icon>
-->
返回上级
返回上级
</el-button>
</el-button>
<el-button
type=
"primary"
@
click=
"register"
>
<el-button
type=
"primary"
@
click=
"register"
>
<bg-icon
<bg-icon
style=
"font-size: 12px; color: #fff; margin-right: 8px"
icon=
"#bg-ic-add"
></bg-icon>
style=
"font-size: 12px; color: #fff; margin-right: 8px"
icon=
"#bg-ic-add"
></bg-icon>
新增
新增
</el-button>
</el-button>
</div>
</div>
...
@@ -67,12 +60,7 @@
...
@@ -67,12 +60,7 @@
</bg-filter-group>
</bg-filter-group>
<div
class=
"table_container"
>
<div
class=
"table_container"
>
<div
class=
"table bg-scroll"
>
<div
class=
"table bg-scroll"
>
<bg-table
<bg-table
ref=
"bgTable"
:headers=
"headers"
:rows=
"tableRows"
:isIndex=
"true"
:stripe=
"true"
>
ref=
"bgTable"
:headers=
"headers"
:rows=
"tableRows"
:isIndex=
"true"
:stripe=
"true"
>
<
template
v-slot:name=
"{ row }"
>
<
template
v-slot:name=
"{ row }"
>
<span
class=
"can_click_text"
@
click=
"getChildren(row)"
v-if=
"row.children"
>
<span
class=
"can_click_text"
@
click=
"getChildren(row)"
v-if=
"row.children"
>
{{
row
.
name
}}
{{
row
.
name
}}
...
@@ -93,33 +81,17 @@
...
@@ -93,33 +81,17 @@
</
template
>
</
template
>
<
template
v-slot:action=
"{ row }"
>
<
template
v-slot:action=
"{ row }"
>
<!-- 除技术类型之外的字典可以删除 -->
<!-- 除技术类型之外的字典可以删除 -->
<bg-table-btns2
<bg-table-btns2
:limit=
"3"
v-if=
"nodeClassifyId !== '263758a4-0349-4d49-a816-e8ff8d33a8bb'"
>
:limit=
"3"
<bg-table-btn
@
click=
"edit_row(row)"
:disabled=
"row.state == 1"
>
编辑
</bg-table-btn>
v-if=
"nodeClassifyId !== '263758a4-0349-4d49-a816-e8ff8d33a8bb'"
>
<bg-table-btn
@
click=
"delete_row(row)"
:disabled=
"row.state == 1"
>
删除
</bg-table-btn>
<bg-table-btn
@
click=
"edit_row(row)"
:disabled=
"row.state == 1"
<bg-table-btn
@
click=
"moveRow(row, 1)"
:disabled=
"!row.canMoveUp"
>
上移
</bg-table-btn>
>
编辑
</bg-table-btn
<bg-table-btn
@
click=
"moveRow(row, 2)"
:disabled=
"!row.canMoveDown"
>
下移
</bg-table-btn>
>
<bg-table-btn
@
click=
"delete_row(row)"
:disabled=
"row.state == 1"
>
删除
</bg-table-btn
>
<bg-table-btn
@
click=
"moveRow(row, 1)"
:disabled=
"!row.canMoveUp"
>
上移
</bg-table-btn
>
<bg-table-btn
@
click=
"moveRow(row, 2)"
:disabled=
"!row.canMoveDown"
>
下移
</bg-table-btn
>
</bg-table-btns2>
</bg-table-btns2>
<!-- 技术类型字典不可删除 -->
<!-- 技术类型字典不可删除 -->
<bg-table-btns2
:limit=
"3"
v-else
>
<bg-table-btns2
:limit=
"3"
v-else
>
<bg-table-btn
@
click=
"edit_row(row)"
:disabled=
"row.state == 1"
<bg-table-btn
@
click=
"edit_row(row)"
:disabled=
"row.state == 1"
>
编辑
</bg-table-btn>
>
编辑
</bg-table-btn
<bg-table-btn
@
click=
"moveRow(row, 1)"
:disabled=
"!row.canMoveUp"
>
上移
</bg-table-btn>
>
<bg-table-btn
@
click=
"moveRow(row, 2)"
:disabled=
"!row.canMoveDown"
>
下移
</bg-table-btn>
<bg-table-btn
@
click=
"moveRow(row, 1)"
:disabled=
"!row.canMoveUp"
>
上移
</bg-table-btn
>
<bg-table-btn
@
click=
"moveRow(row, 2)"
:disabled=
"!row.canMoveDown"
>
下移
</bg-table-btn
>
</bg-table-btns2>
</bg-table-btns2>
</
template
>
</
template
>
</bg-table>
</bg-table>
...
@@ -136,11 +108,7 @@
...
@@ -136,11 +108,7 @@
</div>
</div>
</div>
</div>
<!-- 新增/编辑弹窗 -->
<!-- 新增/编辑弹窗 -->
<el-dialog
<el-dialog
class=
"dialog_box"
:title=
"addType == 1 ? '新增' : '编辑'"
v-model=
"addDialog"
width=
"758px"
>
class=
"dialog_box"
:title=
"addType == 1 ? '新增' : '编辑'"
v-model=
"addDialog"
width=
"758px"
>
<el-form
ref=
"bgForm"
:model=
"formData"
:rules=
"rules"
label-width=
"80px"
class=
"bg_form"
>
<el-form
ref=
"bgForm"
:model=
"formData"
:rules=
"rules"
label-width=
"80px"
class=
"bg_form"
>
<el-form-item
label=
"名称"
prop=
"name"
>
<el-form-item
label=
"名称"
prop=
"name"
>
<el-input
<el-input
...
@@ -208,11 +176,12 @@
...
@@ -208,11 +176,12 @@
</template>
</template>
<
script
setup
>
<
script
setup
>
import
{
reactive
,
ref
,
onBeforeMount
,
toRefs
,
computed
,
watch
,
nextTick
,
watchEffect
}
from
"
vue
"
;
import
{
reactive
,
ref
,
onBeforeMount
,
toRefs
,
computed
,
nextTick
}
from
"
vue
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
axios
from
"
../../../../request/http.js
"
;
import
{
Search
}
from
"
@element-plus/icons-vue
"
;
import
{
Search
}
from
"
@element-plus/icons-vue
"
;
import
bgBreadcrumb
from
"
@/components/bg-breadcrumb.vue
"
;
import
bgBreadcrumb
from
"
@/components/bg-breadcrumb.vue
"
;
import
axios
from
"
../../../../request/http.js
"
;
const
bgForm
=
ref
(
null
);
const
bgForm
=
ref
(
null
);
const
headers
=
computed
(()
=>
{
const
headers
=
computed
(()
=>
{
...
...
src/page/main/config/preference/index.vue
View file @
c11a241c
...
@@ -28,10 +28,7 @@
...
@@ -28,10 +28,7 @@
<el-input
disabled
v-model=
"authorizeFormData.system_version"
/>
<el-input
disabled
v-model=
"authorizeFormData.system_version"
/>
</el-form-item>
</el-form-item>
<el-form-item
label=
"User"
prop=
"system_user"
>
<el-form-item
label=
"User"
prop=
"system_user"
>
<el-input
<el-input
placeholder=
"统一管理用户认证平台"
v-model=
"authorizeFormData.system_user"
maxlength=
"30"
/>
placeholder=
"统一管理用户认证平台"
v-model=
"authorizeFormData.system_user"
maxlength=
"30"
/>
</el-form-item>
</el-form-item>
<el-form-item
label=
"Key"
prop=
"license"
>
<el-form-item
label=
"Key"
prop=
"license"
>
<el-input
<el-input
...
@@ -45,15 +42,12 @@
...
@@ -45,15 +42,12 @@
<el-input
disabled
v-model=
"authorizeFormData.license_dead_date"
/>
<el-input
disabled
v-model=
"authorizeFormData.license_dead_date"
/>
</el-form-item>
</el-form-item>
<el-form-item
label=
"剩余有效期提醒"
prop=
"license_inform_day"
>
<el-form-item
label=
"剩余有效期提醒"
prop=
"license_inform_day"
>
<el-input
<el-input
placeholder=
"请输入"
v-model.trim.number=
"authorizeFormData.license_inform_day"
>
placeholder=
"请输入"
v-model.trim.number=
"authorizeFormData.license_inform_day"
>
<template
#append
>
天
</
template
>
<template
#append
>
天
</
template
>
</el-input>
</el-input>
<el-tooltip
placement=
"top-start"
effect=
"light"
>
<el-tooltip
placement=
"top-start"
effect=
"light"
>
<
template
#content
>
<
template
#content
>
范围(0~90),单位:天,
范围(0~90),单位:天, 当剩余有效期在配置区间内时,系统会在用户登录系统时发出提醒,0表示不提醒
当剩余有效期在配置区间内时,系统会在用户登录系统时发出提醒,0表示不提醒
</
template
>
</
template
>
<div
class=
"tip-image"
></div>
<div
class=
"tip-image"
></div>
</el-tooltip>
</el-tooltip>
...
@@ -97,19 +91,14 @@
...
@@ -97,19 +91,14 @@
</el-form-item>
</el-form-item>
</div>
</div>
<el-form-item
label=
"密码有效期"
prop=
"pwd_validity"
>
<el-form-item
label=
"密码有效期"
prop=
"pwd_validity"
>
<el-input
<el-input
placeholder=
"请输入"
v-model.trim.number=
"secureFormData.pwd_validity"
maxlength=
"3"
>
placeholder=
"请输入"
v-model.trim.number=
"secureFormData.pwd_validity"
maxlength=
"3"
>
<
template
#append
>
天
</
template
>
<
template
#append
>
天
</
template
>
</el-input>
</el-input>
<el-tooltip
placement=
"top-start"
effect=
"light"
>
<el-tooltip
placement=
"top-start"
effect=
"light"
>
<
template
#content
>
<
template
#content
>
<span>
单位,天
</span>
<span>
单位,天
</span>
<br
/>
<br
/>
<span
<span>
密码有效期是指强制修改密码的周期,例如60天表示用户需要每60天修改一次密码。
</span>
>
密码有效期是指强制修改密码的周期,例如60天表示用户需要每60天修改一次密码。
</span
>
<br
/>
<br
/>
<span>
若配置为0,表示密码有效期为永久
</span>
<span>
若配置为0,表示密码有效期为永久
</span>
</
template
>
</
template
>
...
@@ -122,7 +111,7 @@
...
@@ -122,7 +111,7 @@
</el-input>
</el-input>
<el-tooltip
placement=
"top-start"
effect=
"light"
>
<el-tooltip
placement=
"top-start"
effect=
"light"
>
<
template
#content
>
<
template
#content
>
<span>
{{
`范围(10~${session_validity_max
}
)`
}}
<
/span>
<span>
{{
`范围(10~${session_validity_max
}
)`
}}
<
/span>
<
br
/>
<
br
/>
<
span
>
单位,分钟
<
/span>
<
span
>
单位,分钟
<
/span>
<
br
/>
<
br
/>
...
@@ -242,9 +231,7 @@ const state = reactive({
...
@@ -242,9 +231,7 @@ const state = reactive({
}
,
}
,
//授权表单校验规则
//授权表单校验规则
authorizeRules
:
{
authorizeRules
:
{
license_inform_day
:
[
license_inform_day
:
[{
type
:
"
number
"
,
min
:
0
,
max
:
90
,
message
:
"
请输入0~90的整数
"
,
trigger
:
"
blur
"
}
],
{
type
:
"
number
"
,
min
:
0
,
max
:
90
,
message
:
"
请输入0~90的整数
"
,
trigger
:
"
blur
"
}
,
],
}
,
}
,
//安全相关信息表单
//安全相关信息表单
...
...
src/page/main/system-admin/dict/index.vue
View file @
c11a241c
<
template
>
<
template
>
<div>
字典管理
</div>
<div
class=
"detail_container"
>
<bg-breadcrumb></bg-breadcrumb>
<div
class=
"flex_row"
>
<div
class=
"flex_left"
>
<div
class=
"box"
>
<el-input
class=
"type-input"
v-model.trim=
"typeKeyword"
@
input=
"searchType"
:prefix-icon=
"Search"
placeholder=
"请输入搜索内容"
></el-input>
<div
class=
"type_station bg-scroll"
>
<div
class=
"type-box"
:class=
"
{ 'current-type': nodeClassifyId == item.classify_id }"
@click="nodeClick(item)"
v-for="(item, index) in typeList"
:key="'type' + index + 200">
{{
item
.
classify_name
}}
</div>
</div>
</div>
</div>
<div
class=
"flex_right"
>
<div
class=
"main_container"
>
<bg-filter-group
@
search=
"changeSearch"
v-model=
"filter.search"
placeholder=
"请输入关键字"
>
<template
v-slot:left_action
v-if=
"nodeClassifyId != '263758a4-0349-4d49-a816-e8ff8d33a8bb'"
>
<div
class=
"apaas_button"
>
<el-button
type=
"primary"
@
click=
"backDict"
v-if=
"dictLevel != 1"
>
<!--
<bg-icon
style=
"font-size: 12px; color: #fff; margin-right: 8px"
icon=
"#bg-ic-add"
></bg-icon>
-->
返回上级
</el-button>
<el-button
type=
"primary"
@
click=
"register"
>
<bg-icon
style=
"font-size: 12px; color: #fff; margin-right: 8px"
icon=
"#bg-ic-add"
></bg-icon>
新增
</el-button>
</div>
</
template
>
<
template
v-slot:filter_group
>
<div
class=
"left-filter filter_list"
>
<div
class=
"filter_item"
>
<span
class=
"filter_title"
>
状态
</span>
<el-select
v-model=
"filter.state"
placeholder=
"请选择"
style=
"width: 300px"
>
<el-option
v-for=
"(item, index) in stateOptions"
:key=
"'pushOptions' + index"
:label=
"item.name"
:value=
"item.value"
>
</el-option>
</el-select>
</div>
</div>
<div
class=
"right-action apaas_button"
>
<el-button
type=
"primary"
@
click=
"filterAction"
>
查询
</el-button>
<el-button
type=
"default"
@
click=
"filterClear"
>
重置
</el-button>
</div>
</
template
>
</bg-filter-group>
<div
class=
"table_container"
>
<div
class=
"table bg-scroll"
>
<bg-table
ref=
"bgTable"
:headers=
"headers"
:rows=
"tableRows"
:isIndex=
"true"
:stripe=
"true"
>
<
template
v-slot:name=
"{ row }"
>
<span
class=
"can_click_text"
@
click=
"getChildren(row)"
v-if=
"row.children"
>
{{
row
.
name
}}
</span>
<span
v-else
>
{{
row
.
name
}}
</span>
</
template
>
<
template
v-slot:updated_time=
"{ row }"
>
{{
row
.
updated_time
.
split
(
"
+
"
)[
0
].
replace
(
"
T
"
,
"
"
).
replace
(
"
Z
"
,
"
"
)
}}
</
template
>
<
template
v-slot:state=
"{ row }"
>
<bg-switch
@
click=
"changeUseRow(row)"
:labels=
"['否', '是']"
:values=
"[0, 1]"
v-model=
"row.state"
></bg-switch>
</
template
>
<
template
v-slot:action=
"{ row }"
>
<!-- 除技术类型之外的字典可以删除 -->
<bg-table-btns2
:limit=
"3"
v-if=
"nodeClassifyId !== '263758a4-0349-4d49-a816-e8ff8d33a8bb'"
>
<bg-table-btn
@
click=
"edit_row(row)"
:disabled=
"row.state == 1"
>
编辑
</bg-table-btn>
<bg-table-btn
@
click=
"delete_row(row)"
:disabled=
"row.state == 1"
>
删除
</bg-table-btn>
<bg-table-btn
@
click=
"moveRow(row, 1)"
:disabled=
"!row.canMoveUp"
>
上移
</bg-table-btn>
<bg-table-btn
@
click=
"moveRow(row, 2)"
:disabled=
"!row.canMoveDown"
>
下移
</bg-table-btn>
</bg-table-btns2>
<!-- 技术类型字典不可删除 -->
<bg-table-btns2
:limit=
"3"
v-else
>
<bg-table-btn
@
click=
"edit_row(row)"
:disabled=
"row.state == 1"
>
编辑
</bg-table-btn>
<bg-table-btn
@
click=
"moveRow(row, 1)"
:disabled=
"!row.canMoveUp"
>
上移
</bg-table-btn>
<bg-table-btn
@
click=
"moveRow(row, 2)"
:disabled=
"!row.canMoveDown"
>
下移
</bg-table-btn>
</bg-table-btns2>
</
template
>
</bg-table>
</div>
<bg-pagination
:page=
"filter.page"
:size=
"filter.size"
:total=
"tableTotal"
@
change-page=
"changePage"
@
change-size=
"changeSize"
>
</bg-pagination>
</div>
</div>
</div>
</div>
<!-- 新增/编辑弹窗 -->
<el-dialog
class=
"dialog_box"
:title=
"addType == 1 ? '新增' : '编辑'"
v-model=
"addDialog"
width=
"758px"
>
<el-form
ref=
"bgForm"
:model=
"formData"
:rules=
"rules"
label-width=
"80px"
class=
"bg_form"
>
<el-form-item
label=
"名称"
prop=
"name"
>
<el-input
v-model.trim=
"formData.name"
show-word-limit
:maxlength=
"
nodeClassifyId == 'eb9c7d70-c123-42b7-8e61-dde1b022b669'
? 6
: nodeClassifyId == 'efd9ec3b-7f18-49e2-9d88-bcca022243bb'
? 4
: nodeClassifyId == '949a1138-4995-464e-97a9-424d097eb271'
? 2
: 20
"
placeholder=
"请输入名称"
></el-input>
</el-form-item>
<el-form-item
label=
"描述"
prop=
"describe"
>
<el-input
v-model=
"formData.describe"
type=
"textarea"
:autosize=
"{ minRows: 5 }"
show-word-limit
maxlength=
"200"
resize=
"vertical"
placeholder=
"请输入描述"
></el-input>
</el-form-item>
<el-form-item
label=
"是否启用"
prop=
"state"
style=
"margin-bottom: 0px"
>
<el-switch
class=
"bg-switch-ele"
v-model=
"formData.state"
:active-value=
"1"
:inactive-value=
"0"
inline-prompt
active-text=
"是"
inactive-text=
"否"
/>
</el-form-item>
</el-form>
<
template
v-slot:footer
>
<div
class=
"apaas_button"
>
<el-button
type=
"default"
@
click=
"addDialog = false"
>
取 消
</el-button>
<el-button
type=
"primary"
@
click=
"addConfirm"
>
保 存
</el-button>
</div>
</
template
>
</el-dialog>
<!-- 删除弹窗 -->
<el-dialog
class=
"dialog_box"
title=
"提示"
v-model=
"dialogDelete"
width=
"400px"
:before-close=
"
() => {
dialogDelete = false;
}
"
>
<div>
确定要删除此字典值吗?
</div>
<
template
v-slot:footer
>
<div
class=
"apaas_button"
>
<el-button
type=
"default"
@
click=
"dialogDelete = false"
>
取 消
</el-button>
<el-button
type=
"primary"
@
click=
"deleteData"
>
确 定
</el-button>
</div>
</
template
>
</el-dialog>
</div>
</template>
</template>
<
script
setup
></
script
>
<
script
setup
>
import
{
reactive
,
ref
,
onBeforeMount
,
toRefs
,
computed
,
watch
,
nextTick
,
watchEffect
}
from
"
vue
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
axios
from
"
../../../../request/http.js
"
;
import
{
Search
}
from
"
@element-plus/icons-vue
"
;
import
bgBreadcrumb
from
"
@/components/bg-breadcrumb.vue
"
;
const
bgForm
=
ref
(
null
);
const
headers
=
computed
(()
=>
{
let
_headers
=
[
{
label
:
"
名称
"
,
prop
:
"
name
"
,
},
{
label
:
"
描述
"
,
prop
:
"
describe
"
,
minWidth
:
360
,
},
{
label
:
"
更新时间
"
,
prop
:
"
updated_time
"
,
width
:
220
,
},
{
label
:
"
是否启用
"
,
prop
:
"
state
"
,
},
{
label
:
"
操作
"
,
prop
:
"
action
"
,
width
:
176
,
fixed
:
"
right
"
,
},
];
if
(
state
.
nodeClassifyId
===
"
59315100-5c2a-4381-83fe-32934605f0a9
"
)
{
_headers
.
splice
(
1
,
0
,
{
label
:
"
版本数
"
,
prop
:
"
total_children
"
,
});
}
if
(
state
.
nodeClassifyId
===
"
b3a083ee-a8c1-8ca4-f9a1-ea01692a0f1a
"
)
{
_headers
.
splice
(
1
,
0
,
{
label
:
"
服务名称
"
,
prop
:
"
service_name
"
,
});
}
return
_headers
;
});
const
state
=
reactive
({
bgForm
,
typeList
:
[],
// 分类数据
typeKeyword
:
""
,
// 分类删选关键词
nodeClassifyId
:
null
,
// 当前选中分类的uuid 用于新增字典
nodeId
:
null
,
// 当前选中分类的id 用于请求列表
timer
:
null
,
// 定时器
tableRows
:
[],
// 表格数据
tableTotal
:
0
,
// 表格数据条数
filter
:
{
state
:
""
,
search
:
""
,
page
:
1
,
limit
:
10
,
},
// 表格筛选项
stateOptions
:
[
{
name
:
"
全部
"
,
value
:
""
,
},
{
name
:
"
启用
"
,
value
:
"
1
"
,
},
{
name
:
"
禁用
"
,
value
:
"
0
"
,
},
],
// 启用禁用
actionRow
:
null
,
// 当前操作的数据
dialogDelete
:
false
,
// 删除弹窗
addType
:
0
,
//
addDialog
:
false
,
formData
:
{
name
:
""
,
describe
:
""
,
state
:
1
,
p_dict_id
:
""
,
},
rules
:
{
name
:
[{
required
:
true
,
message
:
"
请输入名称
"
,
trigger
:
"
blur
"
}],
describe
:
[
{
required
:
true
,
message
:
"
请输入描述
"
,
trigger
:
"
blur
"
},
{
max
:
200
,
message
:
"
描述最大为200字
"
,
trigger
:
"
blur
"
},
],
state
:
[{
required
:
true
,
message
:
"
请选择是否启用
"
,
trigger
:
"
change
"
}],
},
fatherRow
:
null
,
});
const
dictLevel
=
ref
(
1
);
const
getChildren
=
(
row
)
=>
{
dictLevel
.
value
=
2
;
state
.
tableRows
=
row
.
children
||
[];
state
.
tableTotal
=
row
.
total_children
;
state
.
fatherRow
=
row
;
};
const
backDict
=
()
=>
{
dictLevel
.
value
=
1
;
state
.
fatherRow
=
null
;
changePage
(
1
);
};
const
nodeClick
=
(
item
)
=>
{
state
.
nodeId
=
item
.
id
;
dictLevel
.
value
=
1
;
state
.
fatherRow
=
null
;
state
.
nodeClassifyId
=
item
.
classify_id
;
state
.
filter
=
{
state
:
""
,
search
:
""
,
page
:
1
,
limit
:
10
,
};
changePage
(
1
);
};
// 切换字典分类
const
searchType
=
()
=>
{
if
(
state
.
timer
)
{
clearTimeout
(
state
.
timer
);
}
state
.
timer
=
setTimeout
(()
=>
{
getTypeList
();
},
500
);
};
// 字典分类筛选
const
getTypeList
=
()
=>
{
let
params
=
{
name
:
state
.
typeKeyword
,
};
axios
.
get
(
`/apaas/system/v5/dictionary/classify/list`
,
{
params
})
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
state
.
typeList
=
res
.
data
.
data
||
[];
state
.
nodeClassifyId
=
state
.
typeList
[
0
].
classify_id
||
null
;
state
.
nodeId
=
state
.
typeList
[
0
].
id
||
null
;
if
(
state
.
nodeId
)
{
getTableRows
();
}
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
})
.
catch
((
err
)
=>
{
console
.
log
(
err
);
});
};
// 获取字典分类
const
changeSearch
=
(
val
)
=>
{
state
.
filter
.
search
=
val
;
changePage
(
1
);
};
// 表格关键字筛选
const
filterAction
=
()
=>
{
changePage
(
1
);
};
// 查询按钮
const
filterClear
=
()
=>
{
state
.
filter
=
{
state
:
""
,
search
:
""
,
limit
:
10
,
page
:
1
,
};
changePage
(
1
);
};
// 重置筛选项
const
getTableRows
=
()
=>
{
let
params
=
{
...
state
.
filter
};
params
.
id
=
state
.
nodeId
;
axios
.
get
(
`/apaas/system/v5/dictionary/list`
,
{
params
,
})
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
let
data
=
res
.
data
.
data
||
[];
if
(
dictLevel
.
value
==
1
)
{
state
.
tableRows
=
data
;
state
.
tableTotal
=
res
.
data
.
total
;
}
else
{
let
row
=
data
.
filter
((
e
)
=>
{
return
e
.
dict_id
==
state
.
fatherRow
.
dict_id
;
});
state
.
tableRows
=
row
[
0
].
children
;
state
.
tableTotal
=
row
[
0
].
total_children
;
}
if
(
state
.
tableRows
.
length
>
0
)
{
state
.
tableRows
.
forEach
((
e
)
=>
{
e
.
canMoveUp
=
true
;
e
.
canMoveDown
=
true
;
});
state
.
tableRows
[
0
].
canMoveUp
=
false
;
state
.
tableRows
[
state
.
tableRows
.
length
-
1
].
canMoveDown
=
false
;
}
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
// 获取表格数据
const
changeUseRow
=
(
row
)
=>
{
axios
.
put
(
`/apaas/system/v5/dictionary/state?id=
${
row
.
id
}
&state=
${
row
.
state
}
`
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
ElMessage
.
success
(
res
.
data
.
msg
);
changePage
(
1
);
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
row
.
state
=
row
.
state
==
0
?
1
:
0
;
}
});
};
// 启用禁用
const
changePage
=
(
page
)
=>
{
state
.
filter
.
page
=
page
;
getTableRows
();
};
// 改变页码
const
changeSize
=
(
size
)
=>
{
state
.
filter
.
limit
=
size
;
changePage
(
1
);
};
// 改变每页条数
const
register
=
()
=>
{
state
.
formData
=
{
name
:
""
,
describe
:
""
,
state
:
1
,
p_dict_id
:
state
.
fatherRow
?
state
.
fatherRow
.
dict_id
:
""
,
};
if
(
state
.
bgForm
)
{
nextTick
().
then
(()
=>
{
state
.
bgForm
.
validate
((
valid
)
=>
{
if
(
!
valid
)
{
state
.
bgForm
.
clearValidate
();
}
});
});
}
state
.
addType
=
1
;
state
.
addDialog
=
true
;
};
// 新增字典按钮
const
edit_row
=
(
row
)
=>
{
axios
.
get
(
`/apaas/system/v5/dictionary/
${
row
.
id
}
`
)
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
state
.
actionRow
=
res
.
data
.
data
;
state
.
formData
=
{
name
:
state
.
actionRow
.
name
,
describe
:
state
.
actionRow
.
describe
,
state
:
state
.
actionRow
.
state
,
p_dict_id
:
state
.
actionRow
.
p_dict_id
,
};
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
})
.
catch
((
err
)
=>
{
console
.
log
(
err
);
});
if
(
state
.
bgForm
)
{
nextTick
().
then
(()
=>
{
state
.
bgForm
.
validate
((
valid
)
=>
{
if
(
!
valid
)
{
state
.
bgForm
.
clearValidate
();
}
});
});
}
state
.
addType
=
2
;
state
.
addDialog
=
true
;
};
// 编辑按钮
const
addConfirm
=
()
=>
{
state
.
bgForm
.
validate
((
valid
)
=>
{
if
(
valid
)
{
if
(
state
.
addType
==
1
)
{
// 新增
let
params
=
{
classify_id
:
state
.
nodeClassifyId
,
...
state
.
formData
,
};
axios
.
post
(
`/apaas/system/v5/dictionary/add`
,
params
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
ElMessage
.
success
(
res
.
data
.
msg
);
state
.
addDialog
=
false
;
changePage
(
1
);
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
}
else
{
// 编辑
let
params
=
{
id
:
state
.
actionRow
.
id
,
...
state
.
formData
,
};
axios
.
put
(
`/apaas/system/v5/dictionary/update`
,
params
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
ElMessage
.
success
(
res
.
data
.
msg
);
state
.
addDialog
=
false
;
changePage
(
1
);
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
}
}
});
};
// 确定新增/编辑
const
delete_row
=
(
row
)
=>
{
state
.
dialogDelete
=
true
;
state
.
actionRow
=
row
;
};
// 删除按钮
const
deleteData
=
()
=>
{
axios
.
delete
(
`/apaas/system/v5/dictionary/
${
state
.
actionRow
.
id
}
`
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
ElMessage
.
success
(
res
.
data
.
msg
);
state
.
dialogDelete
=
false
;
changePage
(
1
);
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
// 确定删除
const
moveRow
=
(
row
,
type
)
=>
{
let
index
;
state
.
tableRows
.
forEach
((
e
,
i
)
=>
{
if
(
e
.
id
==
row
.
id
)
{
index
=
i
;
}
});
let
nextRow
;
if
(
type
==
1
)
{
// 上移
nextRow
=
state
.
tableRows
[
index
-
1
];
}
else
{
// 下移
nextRow
=
state
.
tableRows
[
index
+
1
];
}
let
params
=
[
{
id
:
row
.
id
,
sort
:
nextRow
.
sort
,
},
{
id
:
nextRow
.
id
,
sort
:
row
.
sort
,
},
];
axios
.
put
(
`/apaas/system/v5/dictionary/sort`
,
[...
params
])
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
ElMessage
.
success
(
res
.
data
.
msg
);
changePage
(
1
);
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
})
.
catch
((
err
)
=>
{
console
.
log
(
err
);
});
};
onBeforeMount
(()
=>
{
getTypeList
();
});
const
{
typeList
,
typeKeyword
,
nodeClassifyId
,
tableRows
,
tableTotal
,
filter
,
stateOptions
,
dialogDelete
,
addType
,
addDialog
,
formData
,
rules
,
}
=
toRefs
(
state
);
</
script
>
<
style
lang=
"scss"
scoped
>
.detail_container
{
width
:
100%
;
height
:
calc
(
100vh
-
56px
);
padding
:
0
24px
;
min-height
:
100%
;
display
:
flex
;
flex-direction
:
column
;
justify-content
:
flex-start
;
align-items
:
stretch
;
.flex_row
{
// flex-grow: 1;
width
:
100%
;
display
:
flex
;
margin-bottom
:
16px
;
position
:
relative
;
height
:
calc
(
100%
-
62px
);
.flex_left
{
width
:
240px
;
background-color
:
#fff
;
margin-right
:
16px
;
border-radius
:
6px
;
padding
:
16px
;
height
:
100%
;
box-shadow
:
0px
1px
4px
0px
rgba
(
0
,
7
,
101
,
0
.15
);
overflow
:
hidden
;
.box
{
width
:
208px
;
height
:
100%
;
overflow
:
hidden
;
.type_station
{
width
:
100%
;
margin-top
:
16px
;
height
:
calc
(
100%
-
50px
);
.type-box
{
height
:
32px
;
line-height
:
32px
;
text-align
:
center
;
font-size
:
14px
;
color
:
#404a62
;
cursor
:
pointer
;
&
:hover
{
background-color
:
#f2f3f7
;
}
}
.current-type
{
background-color
:
#f2f3f7
;
border-radius
:
4px
;
}
}
}
}
.flex_right
{
flex
:
1
;
background-color
:
#fff
;
border-radius
:
6px
;
box-shadow
:
0px
1px
4px
0px
rgba
(
0
,
7
,
101
,
0
.15
);
height
:
100%
;
.main_container
{
height
:
100%
;
.filter-group
{
.left-filter
{
flex
:
1
;
display
:
flex
;
justify-content
:
start
;
flex-wrap
:
wrap
;
}
.right-action
{
width
:
144px
;
padding-bottom
:
16px
;
.el-button
{
width
:
64px
;
}
}
}
.table_container
{
height
:
calc
(
100%
-
70px
);
width
:
100%
;
padding
:
0
16px
;
.table
{
max-height
:
calc
(
100%
-
64px
);
}
}
}
}
}
<
style
lang=
"scss"
scoped
></
style
>
.bg_form
{
width
:
100%
;
box-sizing
:
border-box
;
.el-form-item
{
margin-bottom
:
24px
;
:deep
()
.el-form-item__label
{
line-height
:
36px
;
height
:
36px
;
}
.el-form-item__content
{
width
:
100%
;
.el-textarea
{
:deep
()
.el-input__count
{
bottom
:
-16px
;
right
:
4px
;
font-family
:
Roboto-Regular
;
color
:
#a9b1c7
;
}
}
.bg-switch-ele
{
width
:
52px
;
height
:
24px
;
:deep
()
.el-switch__core
{
width
:
100%
;
height
:
24px
;
.el-switch__inner
,
.el-switch__action
{
top
:
3px
;
}
}
}
}
}
}
}
</
style
>
src/page/main/system-admin/log/index.vue
deleted
100644 → 0
View file @
2669e8be
<
template
>
<div>
日志管理
</div>
</
template
>
<
script
setup
></
script
>
<
style
lang=
"scss"
scoped
></
style
>
src/page/main/system-admin/log/system-log/index.vue
0 → 100644
View file @
c11a241c
<
template
>
<div
class=
"detail_container"
>
<bg-breadcrumb></bg-breadcrumb>
<div
class=
"flex_row"
>
<div
class=
"flex_left"
>
<div
class=
"box"
>
<el-date-picker
style=
"width: 100%"
type=
"date"
value-format=
"YYYY-MM-DD"
v-model=
"date"
placeholder=
"请选择日期"
/>
<div
class=
"type_station bg-scroll"
>
<div
class=
"type-box"
:class=
"
{ 'current-type': selectedNodeContainer == item.value }"
@click="nodeClick(item)"
v-for="(item, index) in containerList"
:key="index"
:title="item.name">
{{
item
.
name
}}
</div>
</div>
</div>
</div>
<div
class=
"flex_right"
>
<div
class=
"form-filter"
>
<el-form
:model=
"filterForm"
inline
>
<el-form-item
label=
"级别"
>
<el-select
placeholder=
"全部"
style=
"width: 160px"
v-model=
"filterForm.level"
>
<el-option
label=
"info"
value=
"info"
>
</el-option>
<el-option
label=
"warning"
value=
"warning"
>
</el-option>
<el-option
label=
"error"
value=
"error"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item
label=
"关键字"
>
<el-input
placeholder=
"请输入"
maxlength=
"100"
style=
"width: 240px"
v-model=
"filterForm.search"
></el-input>
</el-form-item>
</el-form>
<div
class=
"operate_btns"
>
<el-button
type=
"primary"
@
click=
"search"
>
查询
</el-button>
<el-button
type=
"default"
@
click=
"reset"
>
重置
</el-button>
</div>
</div>
<div
class=
"search-result"
>
<div
class=
"item-container apaas_scroll"
>
<p
v-for=
"(item, index) in logList"
:key=
"index"
>
{{
item
}}
</p>
</div>
</div>
</div>
</div>
</div>
</
template
>
<
script
setup
>
import
{
reactive
,
watch
,
onBeforeMount
,
toRefs
}
from
"
vue
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
axios
from
"
@/request/http.js
"
;
import
bgBreadcrumb
from
"
@/components/bg-breadcrumb.vue
"
;
const
state
=
reactive
({
date
:
""
,
containerList
:
[],
// 容器数据
selectedNodeContainer
:
""
,
filterForm
:
{
level
:
""
,
search
:
""
,
},
logList
:
[],
});
watch
(
()
=>
state
.
date
,
(
val
)
=>
{
state
.
selectedNodeContainer
=
""
;
getContainerList
();
}
);
const
nodeClick
=
(
item
)
=>
{
state
.
selectedNodeContainer
=
item
.
value
;
reset
();
};
// 获取容器列表
const
getContainerList
=
()
=>
{
let
params
=
{
date
:
state
.
date
,
};
axios
.
get
(
"
/apaas/system/v5/log/system/tree
"
,
{
params
})
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
state
.
containerList
=
res
.
data
.
data
||
[];
state
.
selectedNodeContainer
=
state
.
containerList
.
length
?
state
.
containerList
[
0
].
value
:
""
;
state
.
selectedNodeContainer
?
reset
()
:
(
state
.
logList
=
[]);
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
})
.
catch
((
err
)
=>
{
console
.
error
(
err
);
});
};
//查询
const
search
=
()
=>
{
let
params
=
{
index
:
state
.
selectedNodeContainer
,
...
state
.
filterForm
,
};
axios
.
get
(
"
/apaas/system/v5/log/system/log
"
,
{
params
})
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
state
.
logList
=
(
res
.
data
.
data
||
[]).
map
((
item
)
=>
JSON
.
stringify
(
item
));
state
.
logList
=
state
.
logList
.
concat
(
state
.
logList
);
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
})
.
catch
((
err
)
=>
{
console
.
error
(
err
);
});
};
//重置
const
reset
=
()
=>
{
state
.
filterForm
=
{
level
:
""
,
search
:
""
,
};
search
();
};
onBeforeMount
(()
=>
{
getContainerList
();
});
const
{
date
,
containerList
,
selectedNodeContainer
,
filterForm
,
logList
}
=
toRefs
(
state
);
</
script
>
<
style
lang=
"scss"
scoped
>
.detail_container
{
width
:
100%
;
height
:
calc
(
100vh
-
56px
);
padding
:
0
24px
;
min-height
:
100%
;
display
:
flex
;
flex-direction
:
column
;
justify-content
:
flex-start
;
align-items
:
stretch
;
.flex_row
{
// flex-grow: 1;
width
:
100%
;
display
:
flex
;
margin-bottom
:
16px
;
position
:
relative
;
height
:
calc
(
100%
-
62px
);
.flex_left
{
width
:
240px
;
background-color
:
#fff
;
margin-right
:
16px
;
border-radius
:
6px
;
padding
:
16px
;
height
:
100%
;
box-shadow
:
0px
1px
4px
0px
rgba
(
0
,
7
,
101
,
0
.15
);
overflow
:
hidden
;
.box
{
width
:
208px
;
height
:
100%
;
overflow
:
hidden
;
.type_station
{
width
:
100%
;
margin-top
:
16px
;
height
:
calc
(
100%
-
50px
);
.type-box
{
overflow
:
hidden
;
text-overflow
:
ellipsis
;
height
:
32px
;
white-space
:
nowrap
;
line-height
:
32px
;
text-align
:
center
;
font-size
:
14px
;
color
:
#404a62
;
cursor
:
pointer
;
&
:hover
{
background-color
:
#f2f3f7
;
}
}
.current-type
{
background-color
:
#f2f3f7
;
border-radius
:
4px
;
}
}
}
}
.flex_right
{
flex
:
1
;
height
:
100%
;
.form-filter
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
margin-bottom
:
16px
;
height
:
68px
;
width
:
100%
;
padding
:
16px
16px
16px
24px
;
background-color
:
#ffffff
;
box-shadow
:
0px
1px
4px
0px
rgba
(
0
,
7
,
101
,
0
.15
);
border-radius
:
6px
;
.el-form
{
width
:
calc
(
100%
-
144px
);
}
.el-form-item
{
margin-bottom
:
0px
;
}
.operate_btns
{
width
:
144px
;
}
}
.search-result
{
width
:
100%
;
height
:
calc
(
100%
-
84px
);
padding
:
15px
0
;
color
:
#fff
;
background-color
:
#1a1a1a
;
box-shadow
:
0px
1px
4px
0px
rgba
(
0
,
7
,
101
,
0
.1
);
border-radius
:
6px
;
.item-container
{
overflow
:
auto
;
padding
:
0
15px
;
height
:
100%
;
}
p
{
word-wrap
:
break-word
;
word-break
:
break-all
;
}
}
}
}
}
</
style
>
src/page/main/system-admin/log/userAccount/index.vue
0 → 100644
View file @
c11a241c
<
template
>
<div
class=
"page_container"
>
<bg-breadcrumb></bg-breadcrumb>
<div
class=
"main_container"
>
<bg-filter-group
@
search=
"changeSearch"
v-model=
"filter.search"
placeholder=
"请输入账号、手机号和所属组织"
>
<template
v-slot:left_action
>
<div
class=
"apaas_button"
>
<el-button
type=
"primary"
@
click=
"exportFile"
>
<bg-icon
style=
"font-size: 12px; color: #fff; margin-right: 8px"
icon=
"#bg-ic-file-send"
></bg-icon>
导出
</el-button>
<el-popconfirm
class=
"force-modify-btn"
width=
"220"
icon-color=
"#ff9900"
title=
"确认修改密码吗?"
@
confirm=
"forceModifyPwd"
>
<template
#reference
>
<el-button
slot=
"reference"
type=
"primary"
>
<span>
强制修改密码
</span>
</el-button>
</
template
>
</el-popconfirm>
<span
class=
"sleceted_tip"
>
已选
<span
class=
"num"
>
{{ selectedNum }}
</span
>
项
</span
>
<span
class=
"clean"
@
click=
"cleanSelected"
>
清空
</span>
</div>
</template>
<
template
v-slot:filter_group
>
<div
class=
"left-filter filter_list"
>
<div
class=
"filter_item"
>
<span
class=
"filter_title"
>
用户类型
</span>
<el-select
v-model=
"filter.is_admin"
placeholder=
"请选择"
style=
"width: 300px"
>
<el-option
v-for=
"(item, index) in userTypeList"
:key=
"index"
:label=
"item.label"
:value=
"item.value"
>
</el-option>
</el-select>
</div>
<div
class=
"filter_item"
>
<span
class=
"filter_title"
>
上次访问时间
</span>
<el-date-picker
v-model=
"filter.time"
type=
"daterange"
range-separator=
"至"
start-placeholder=
"开始日期"
end-placeholder=
"结束日期"
value-format=
"YYYY-MM-DD"
style=
"width: 300px"
/>
</div>
<div
class=
"filter_item"
>
<span
class=
"filter_title"
>
活跃度
</span>
<el-select
v-model=
"filter.active"
placeholder=
"请选择"
style=
"width: 300px"
>
<el-option
v-for=
"(item, index) in activeOptions"
:key=
"index"
:label=
"item.label"
:value=
"item.value"
>
</el-option>
</el-select>
</div>
<div
class=
"filter_item"
>
<span
class=
"filter_title"
>
密码强度
</span>
<el-select
v-model=
"filter.pwd_level"
placeholder=
"请选择"
style=
"width: 300px"
>
<el-option
v-for=
"(item, index) in pwdLevelList"
:key=
"index"
:label=
"item.label"
:value=
"item.value"
>
</el-option>
</el-select>
</div>
</div>
<div
class=
"right-action apaas_button"
>
<el-button
type=
"primary"
@
click=
"filterAction"
>
查询
</el-button>
<el-button
type=
"default"
@
click=
"filterClear"
>
重置
</el-button>
</div>
</
template
>
</bg-filter-group>
<div
class=
"table_container"
>
<bg-table
ref=
"accountTable"
:headers=
"headers"
:rows=
"tableRows"
:stripe=
"true"
select
@
selectAc=
"selectChange"
>
<
template
v-slot:active=
"{ row }"
>
<span
class=
"active"
:class=
"
{
active_weak: row.active === '低',
active_middle: row.active === '中',
active_heigh: row.active === '高',
}"
>
{{
row
.
active
}}
</span
>
</
template
>
<
template
v-slot:pwd_level=
"{ row }"
>
<div
class=
"pwd_level-sign"
>
<span
:class=
"
{
pwd_level: true,
pwd_level_weak: row.pwd_level === '弱',
pwd_level_middle: row.pwd_level === '中',
pwd_level_heigh: row.pwd_level === '强',
}">
{{
row
.
pwd_level
===
"
弱
"
?
row
.
pwd_level
:
""
}}
</span
>
<span
:class=
"
{
pwd_level: true,
pwd_level_middle: row.pwd_level === '中',
pwd_level_heigh: row.pwd_level === '强',
}"
>
{{
row
.
pwd_level
===
"
中
"
?
row
.
pwd_level
:
""
}}
</span
>
<span
:class=
"
{
pwd_level: true,
pwd_level_heigh: row.pwd_level === '强',
}"
>
{{
row
.
pwd_level
===
"
强
"
?
row
.
pwd_level
:
""
}}
</span
>
</div>
</
template
>
</bg-table>
<bg-pagination
:page=
"filter.page"
:size=
"filter.limit"
:total=
"filter.total"
@
change-page=
"changePage"
@
change-size=
"changeSize"
>
</bg-pagination>
</div>
</div>
</div>
</template>
<
script
setup
>
import
{
reactive
,
toRefs
,
ref
,
computed
,
onBeforeMount
}
from
"
vue
"
;
import
{
useStore
}
from
"
vuex
"
;
import
bgBreadcrumb
from
"
@/components/bg-breadcrumb.vue
"
;
import
axios
from
"
@/request/http.js
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
{
downloadBlob
}
from
"
@/services/helper.js
"
;
const
{
getters
}
=
useStore
();
const
userTypeList
=
computed
(()
=>
{
const
temp
=
getters
.
getUserTypeConfig
||
{};
return
Object
.
keys
(
temp
).
map
((
key
)
=>
({
label
:
temp
[
key
],
value
:
+
key
,
}));
});
const
accountTable
=
ref
(
null
);
const
state
=
reactive
({
filter
:
{
search
:
""
,
is_admin
:
""
,
time
:
[],
active
:
0
,
pwd_level
:
""
,
page
:
1
,
limit
:
10
,
total
:
0
,
},
activeOptions
:
[
{
label
:
"
全部
"
,
value
:
""
},
{
label
:
"
低
"
,
value
:
1
},
{
label
:
"
中
"
,
value
:
2
},
{
label
:
"
高
"
,
value
:
3
},
],
pwdLevelList
:
[
{
label
:
"
全部
"
,
value
:
""
},
{
label
:
"
弱
"
,
value
:
1
},
{
label
:
"
中
"
,
value
:
2
},
{
label
:
"
强
"
,
value
:
3
},
],
headers
:
[
{
label
:
"
账号
"
,
prop
:
"
system_account
"
,
// minWidth: 280,
},
{
label
:
"
手机号
"
,
prop
:
"
contact_phone
"
,
// minWidth: 360,
},
{
label
:
"
用户类型
"
,
prop
:
"
is_admin
"
,
// width: 200,
},
{
label
:
"
所属组织
"
,
prop
:
"
name
"
,
// width: 120,
},
{
label
:
"
活跃度
"
,
prop
:
"
active
"
,
// width: 120,
},
{
label
:
"
密码强度
"
,
prop
:
"
pwd_level
"
,
width
:
240
,
},
{
label
:
"
密码使用时长(天)
"
,
prop
:
"
pwd_is_used
"
,
width
:
240
,
},
{
label
:
"
创建时间
"
,
prop
:
"
created_time
"
,
width
:
240
,
},
],
tableRows
:
[],
//选中数量
selectedNum
:
0
,
actionRow
:
{},
dialogDetail
:
false
,
cacheDialog
:
false
,
});
const
{
filter
,
activeOptions
,
pwdLevelList
,
headers
,
tableRows
,
selectedNum
}
=
toRefs
(
state
);
//选择项发生变化
const
selectChange
=
(
params
)
=>
{
state
.
selectedNum
=
params
.
allLength
;
};
//导出
const
exportFile
=
()
=>
{
let
params
=
{
...
state
.
filter
};
params
.
start_at
=
params
.
time
?
params
.
time
[
0
]
||
""
:
""
;
params
.
end_at
=
params
.
time
?
params
.
time
[
1
]
||
""
:
""
;
delete
params
.
time
;
axios
.
get
(
`/apaas/system/v5/log/userAccountAudit/list/export`
,
{
params
,
responseType
:
"
blob
"
,
})
.
then
((
res
)
=>
{
if
(
res
.
status
===
200
)
{
const
type
=
"
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8
"
;
downloadBlob
(
res
.
data
,
type
);
}
else
{
ElMessage
.
error
(
res
.
statusText
);
}
});
};
//强制修改密码
const
forceModifyPwd
=
()
=>
{
const
selectedObj
=
accountTable
.
value
.
dealSelectData
();
const
selectedRows
=
Object
.
values
(
selectedObj
);
if
(
!
selectedRows
.
length
)
return
ElMessage
.
warning
(
"
请先选择修改项
"
);
const
ids
=
selectedRows
.
map
((
item
)
=>
item
.
id
);
axios
.
post
(
"
/apaas/system/v5/user/resetpwd
"
,
{
ids
}).
then
((
res
)
=>
{
if
(
res
.
data
.
code
===
200
)
{
ElMessage
.
success
(
res
.
data
.
msg
);
cleanSelected
();
getTableRows
();
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
//清空
const
cleanSelected
=
()
=>
{
accountTable
.
value
.
clearTable
();
};
const
changeSearch
=
(
val
)
=>
{
state
.
filter
.
search
=
val
;
changePage
(
1
);
};
const
changePage
=
(
page
)
=>
{
state
.
filter
.
page
=
page
;
getTableRows
();
};
const
getTableRows
=
()
=>
{
let
params
=
{
...
state
.
filter
};
params
.
start_at
=
params
.
time
?
params
.
time
[
0
]
||
""
:
""
;
params
.
end_at
=
params
.
time
?
params
.
time
[
1
]
||
""
:
""
;
delete
params
.
time
;
axios
.
get
(
`/apaas/system/v5/log/userAccountAudit/list`
,
{
params
,
})
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
state
.
tableRows
=
res
.
data
.
data
||
[];
state
.
filter
.
total
=
res
.
data
.
total
;
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
const
filterAction
=
()
=>
{
changePage
(
1
);
};
const
changeSize
=
(
size
)
=>
{
state
.
filter
.
limit
=
size
;
changePage
(
1
);
};
const
filterClear
=
()
=>
{
state
.
filter
=
{
search
:
""
,
is_admin
:
""
,
time
:
[],
active
:
0
,
pwd_level
:
""
,
page
:
1
,
limit
:
10
,
total
:
0
,
};
changePage
(
1
);
};
onBeforeMount
(()
=>
{
getTableRows
();
});
</
script
>
<
style
lang=
"scss"
scoped
>
.page_container
{
display
:
flex
;
flex-direction
:
column
;
justify-content
:
flex-start
;
align-items
:
stretch
;
width
:
100%
;
padding
:
0
24px
;
min-height
:
100%
;
.main_container
{
display
:
flex
;
flex-direction
:
column
;
justify-content
:
flex-start
;
align-items
:
stretch
;
flex-grow
:
1
;
width
:
100%
;
background-color
:
#fff
;
box-shadow
:
0px
1px
4px
0px
rgba
(
0
,
7
,
101
,
0
.15
);
border-radius
:
6px
;
padding
:
0
0
16px
0
;
margin-bottom
:
16px
;
position
:
relative
;
.sleceted_tip
{
margin
:
0
24px
0
40px
;
vertical-align
:
middle
;
font-size
:
14px
;
color
:
#404a62
;
.num
{
margin
:
0
3px
0
3px
;
font-weight
:
600
;
color
:
#202531
;
}
}
.clean
{
vertical-align
:
middle
;
font-size
:
14px
;
color
:
#3759be
;
cursor
:
pointer
;
}
.filter-group
{
.left-filter
{
flex
:
1
;
display
:
flex
;
justify-content
:
start
;
flex-wrap
:
wrap
;
.filter_item
{
display
:
flex
;
align-items
:
center
;
.filter_title
{
width
:
84px
;
white-space
:
pre-wrap
;
font-weight
:
normal
;
}
}
}
.right-action
{
width
:
144px
;
padding-bottom
:
16px
;
.el-button
{
width
:
64px
;
}
}
}
.table_container
{
padding
:
0
16px
;
.el-table
{
flex
:
1
;
:deep
()
td
{
padding
:
9px
0
!
important
;
}
.active
{
display
:
inline-block
;
width
:
48px
;
height
:
24px
;
text-align
:
center
;
line-height
:
24px
;
font-size
:
12px
;
border-radius
:
3px
;
&
.active_weak
{
color
:
#dd6955
;
background-color
:
#fcf0ee
;
border
:
solid
1px
#eba599
;
}
&
.active_middle
{
color
:
#ea7d19
;
background-color
:
#fffae8
;
border
:
solid
1px
#fac066
;
}
&
.active_heigh
{
color
:
#429e8a
;
background-color
:
#f1f9f7
;
border
:
solid
1px
#9ad5c8
;
}
}
.pwd_level-sign
{
display
:
flex
;
align-items
:
center
;
}
.pwd_level
{
display
:
inline-block
;
width
:
40px
;
height
:
14px
;
line-height
:
14px
;
color
:
#fff
;
text-align
:
center
;
font-size
:
12px
;
background-color
:
#dadee7
;
border-radius
:
3px
;
&
:not
(
:first-child
)
{
margin-left
:
4px
;
}
&
.pwd_level_weak
{
background-color
:
#dd6955
;
}
&
.pwd_level_middle
{
background-color
:
#ea7d19
;
}
&
.pwd_level_heigh
{
background-color
:
#429e8a
;
}
}
}
}
}
}
</
style
>
src/page/main/system-admin/log/userBehavior/detail/index.vue
0 → 100644
View file @
c11a241c
<
template
>
<div
class=
"page_container"
>
<bg-breadcrumb></bg-breadcrumb>
<div
class=
"page_content"
>
<bg-form-gap
title=
"详情"
></bg-form-gap>
<bg-detail-table2
class=
"detail_info"
:list=
"instanceData.detailInfo"
>
<template
#req_url_value
="
{ data }">
<el-popover
placement=
"top-start"
:width=
"600"
trigger=
"hover"
:content=
"data.value"
>
<template
#reference
>
<p
class=
"show_in_line"
>
{{
data
.
value
}}
</p>
</
template
>
</el-popover>
</template>
<
template
#res_fields_value
="{
data
}"
>
<el-popover
placement=
"bottom-start"
:width=
"800"
trigger=
"hover"
:content=
"data.value"
>
<template
#reference
>
<p
class=
"show_in_line"
>
{{
data
.
value
}}
</p>
</
template
>
</el-popover>
</template>
</bg-detail-table2>
</div>
</div>
</template>
<
script
setup
>
import
{
reactive
,
onBeforeMount
}
from
"
vue
"
;
import
bgBreadcrumb
from
"
@/components/bg-breadcrumb.vue
"
;
import
{
useRoute
}
from
"
vue-router
"
;
import
axios
from
"
@/request/http.js
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
const
route
=
useRoute
();
const
instanceData
=
reactive
({
detailInfo
:
[
{
key
:
"
system_account
"
,
label
:
"
账号
"
,
value
:
""
,
// slot: "approvalStatus",
},
{
key
:
"
phone
"
,
label
:
"
手机号
"
,
value
:
""
,
},
{
key
:
"
user_type
"
,
label
:
"
用户类型
"
,
value
:
""
,
},
{
key
:
"
org_name
"
,
label
:
"
所属组织
"
,
value
:
""
,
},
{
key
:
"
system_module
"
,
label
:
"
系统模块
"
,
value
:
""
,
},
{
key
:
"
created_time
"
,
label
:
"
操作时间
"
,
value
:
""
,
},
{
key
:
"
operate_type
"
,
label
:
"
操作类型
"
,
value
:
""
,
},
{
key
:
"
req_method_str
"
,
label
:
"
请求方式
"
,
value
:
""
,
},
{
key
:
"
operate_status_str
"
,
label
:
"
操作状态
"
,
value
:
""
,
},
{
key
:
"
operate_ip
"
,
label
:
"
操作地址
"
,
value
:
""
,
},
{
key
:
"
operate_addr
"
,
label
:
"
操作地点
"
,
value
:
""
,
width
:
"
100%
"
,
},
{
key
:
"
req_url
"
,
label
:
"
请求地址
"
,
value
:
""
,
width
:
"
100%
"
,
childSlot
:
"
req_url_value
"
,
},
{
key
:
"
req_param
"
,
label
:
"
请求参数
"
,
value
:
""
,
},
{
key
:
"
operate_method
"
,
label
:
"
操作方法
"
,
value
:
""
,
},
{
key
:
"
res_fields
"
,
label
:
"
返回参数
"
,
value
:
""
,
childSlot
:
"
res_fields_value
"
,
},
],
});
onBeforeMount
(()
=>
{
getDetailInfo
();
});
const
getDetailInfo
=
()
=>
{
axios
.
get
(
`/apaas/system/v5/log/userBehavior/detail/
${
route
.
query
.
id
}
`
)
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
const
result
=
res
.
data
.
data
||
{};
instanceData
.
detailInfo
.
forEach
((
item
)
=>
{
item
.
value
=
result
[
item
.
key
];
});
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
})
.
catch
((
err
)
=>
{
ElMessage
.
error
(
err
);
});
};
</
script
>
<
style
lang=
"scss"
scoped
>
.page_content
{
position
:
relative
;
padding
:
24px
0
68px
24px
;
.detail_info
,
.approve_info
{
margin-bottom
:
24px
;
width
:
960px
;
}
.show_in_line
{
overflow
:
hidden
;
width
:
824px
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
}
</
style
>
src/page/main/system-admin/log/userBehavior/index.vue
0 → 100644
View file @
c11a241c
<
template
>
<div
class=
"page_container"
>
<bg-breadcrumb></bg-breadcrumb>
<div
class=
"main_container"
>
<bg-filter-group
@
search=
"changeSearch"
v-model=
"filter.search"
placeholder=
"请输入账号、手机号和所属组织"
>
<template
v-slot:left_action
>
<div
class=
"apaas_button"
>
<el-button
type=
"primary"
@
click=
"exportFile"
>
<bg-icon
style=
"font-size: 12px; color: #fff; margin-right: 8px"
icon=
"#bg-ic-file-send"
></bg-icon>
导出
</el-button>
<el-button
@
click=
"deleteBatch"
>
批量删除
</el-button>
<span
class=
"sleceted_tip"
>
已选
<span
class=
"num"
>
{{
selectedNum
}}
</span
>
项
</span
>
<span
class=
"clean"
@
click=
"cleanSelected"
>
清空
</span>
</div>
</
template
>
<
template
v-slot:filter_group
>
<div
class=
"left-filter filter_list"
>
<div
class=
"filter_item"
>
<span
class=
"filter_title"
>
用户类型
</span>
<el-select
v-model=
"filter.is_admin"
placeholder=
"请选择"
style=
"width: 300px"
>
<el-option
v-for=
"(item, index) in userTypeList"
:key=
"index"
:label=
"item.label"
:value=
"item.value"
>
</el-option>
</el-select>
</div>
<div
class=
"filter_item"
>
<span
class=
"filter_title"
>
操作时间
</span>
<el-date-picker
v-model=
"filter.time"
type=
"daterange"
range-separator=
"至"
start-placeholder=
"开始日期"
end-placeholder=
"结束日期"
value-format=
"YYYY-MM-DD"
style=
"width: 300px"
/>
</div>
<div
class=
"filter_item"
>
<span
class=
"filter_title"
>
操作类型
</span>
<el-select
v-model=
"filter.operate_type"
placeholder=
"请选择"
style=
"width: 300px"
>
<el-option
v-for=
"(item, index) in operateTypeList"
:key=
"index"
:label=
"item.label"
:value=
"item.value"
>
</el-option>
</el-select>
</div>
<div
class=
"filter_item"
>
<span
class=
"filter_title"
>
请求方式
</span>
<el-select
v-model=
"filter.req_method"
placeholder=
"请选择"
style=
"width: 300px"
>
<el-option
v-for=
"(item, index) in reqMethodList"
:key=
"index"
:label=
"item.label"
:value=
"item.value"
>
</el-option>
</el-select>
</div>
<div
class=
"filter_item"
>
<span
class=
"filter_title"
>
操作状态
</span>
<el-select
v-model=
"filter.operate_status"
placeholder=
"请选择"
style=
"width: 300px"
>
<el-option
v-for=
"(item, index) in operateStatusList"
:key=
"index"
:label=
"item.label"
:value=
"item.value"
>
</el-option>
</el-select>
</div>
</div>
<div
class=
"right-action apaas_button"
>
<el-button
type=
"primary"
@
click=
"filterAction"
>
查询
</el-button>
<el-button
type=
"default"
@
click=
"filterClear"
>
重置
</el-button>
</div>
</
template
>
</bg-filter-group>
<div
class=
"table_container"
>
<bg-table
ref=
"userTable"
:headers=
"headers"
:rows=
"tableRows"
:stripe=
"true"
select
@
selectAc=
"selectChange"
>
<
template
v-slot:is_admin=
"{ row }"
>
<span>
{{
userTypeConfig
[
row
.
is_admin
]
}}
</span>
</
template
>
<
template
v-slot:operate_type=
"{ row }"
>
<span>
{{
filterOperateType
(
row
.
operate_type
)
}}
</span>
</
template
>
<
template
v-slot:req_method=
"{ row }"
><span>
{{
filterReqMethod
(
row
.
req_method
)
}}
</span></
template
>
<
template
v-slot:operate_status=
"{ row }"
><span
class=
"operate_status"
:class=
"
{ fail: row.operate_status === 2 }">
{{
row
.
operate_status
===
1
?
"
成功
"
:
"
失败
"
}}
</span></
template
>
<
template
v-slot:action=
"{ row }"
>
<bg-table-btns2
:limit=
"3"
:key=
"row.id"
>
<bg-table-btn
@
click=
"goDetail(row)"
>
详情
</bg-table-btn>
<bg-table-btn
@
click=
"deleteCurrent(row)"
>
删除
</bg-table-btn>
</bg-table-btns2>
</
template
>
</bg-table>
<bg-pagination
:page=
"filter.page"
:size=
"filter.limit"
:total=
"filter.total"
@
change-page=
"changePage"
@
change-size=
"changeSize"
>
</bg-pagination>
</div>
</div>
<el-dialog
class=
"dialog_box"
title=
"提示"
v-model=
"deleteDialog"
width=
"400px"
>
<div
style=
"font-size: 16px; color: #404a62"
>
{{ deleteTips }}
</div>
<
template
v-slot:footer
>
<div
class=
"apaas_button"
>
<el-button
type=
"default"
@
click=
"deleteDialog = false"
>
取 消
</el-button>
<el-button
type=
"primary"
@
click=
"confirmDelete"
>
确 定
</el-button>
</div>
</
template
>
</el-dialog>
</div>
</template>
<
script
setup
>
import
{
reactive
,
ref
,
toRefs
,
computed
,
onBeforeMount
}
from
"
vue
"
;
import
{
useStore
}
from
"
vuex
"
;
import
{
useRouter
}
from
"
vue-router
"
;
import
bgBreadcrumb
from
"
@/components/bg-breadcrumb.vue
"
;
import
axios
from
"
@/request/http.js
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
{
operateTypeList
,
reqMethodList
}
from
"
@/services/enumList.js
"
;
import
{
downloadBlob
}
from
"
@/services/helper.js
"
;
const
{
getters
}
=
useStore
();
const
router
=
useRouter
();
const
userTable
=
ref
(
null
);
const
userTypeConfig
=
computed
(()
=>
getters
.
getUserTypeConfig
||
{});
const
userTypeList
=
computed
(()
=>
{
const
temp
=
getters
.
getUserTypeConfig
||
{};
return
Object
.
keys
(
temp
).
map
((
key
)
=>
({
label
:
temp
[
key
],
value
:
+
key
,
}));
});
const
state
=
reactive
({
filter
:
{
search
:
""
,
is_admin
:
""
,
time
:
[],
operate_type
:
""
,
req_method
:
""
,
operate_status
:
""
,
page
:
1
,
limit
:
10
,
total
:
0
,
},
operateStatusList
:
[
{
label
:
"
全部
"
,
value
:
""
},
{
label
:
"
成功
"
,
value
:
1
},
{
label
:
"
失败
"
,
value
:
2
},
],
headers
:
[
{
label
:
"
账号
"
,
prop
:
"
system_account
"
,
// minWidth: 280,
},
{
label
:
"
用户类型
"
,
prop
:
"
is_admin
"
,
// minWidth: 360,
},
{
label
:
"
系统模块
"
,
prop
:
"
system_module
"
,
// width: 200,
},
{
label
:
"
操作类型
"
,
prop
:
"
operate_type
"
,
// width: 120,
},
{
label
:
"
请求方式
"
,
prop
:
"
req_method
"
,
// width: 120,
},
{
label
:
"
操作状态
"
,
prop
:
"
operate_status
"
,
// width: 240,
},
{
label
:
"
操作地点
"
,
prop
:
"
operate_addr
"
,
// width: 240,
},
{
label
:
"
操作时间
"
,
prop
:
"
created_time
"
,
// width: 240,
},
{
label
:
"
操作
"
,
prop
:
"
action
"
,
width
:
120
,
},
],
//选中数量
selectedNum
:
0
,
detailHeaders
:
[
{
label
:
"
账号
"
,
prop
:
"
ability_name
"
,
// minWidth: 280,
},
{
label
:
"
类型
"
,
prop
:
"
synopsis
"
,
// minWidth: 360,
},
{
label
:
"
用户手机号
"
,
prop
:
"
created_time
"
,
// width: 200,
},
{
label
:
"
所属组织
"
,
prop
:
"
ability_state
"
,
// width: 120,
},
],
tableRows
:
[],
tableTotal
:
0
,
//选中项
selectedRows
:
[],
actionRow
:
{},
dialogDetail
:
false
,
deleteDialog
:
false
,
deleteTips
:
""
,
});
const
{
filter
,
operateStatusList
,
headers
,
selectedNum
,
tableRows
,
deleteDialog
,
deleteTips
}
=
toRefs
(
state
);
//导出
const
exportFile
=
()
=>
{
let
params
=
{
...
state
.
filter
};
params
.
start_at
=
params
.
time
?
params
.
time
[
0
]
||
""
:
""
;
params
.
end_at
=
params
.
time
?
params
.
time
[
1
]
||
""
:
""
;
delete
params
.
time
;
delete
params
.
total
;
axios
.
get
(
`/apaas/system/v5/log/userBehavior/list/export`
,
{
params
,
responseType
:
"
blob
"
,
})
.
then
((
res
)
=>
{
if
(
res
.
status
===
200
)
{
const
type
=
"
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8
"
;
downloadBlob
(
res
.
data
,
type
);
}
else
{
ElMessage
.
error
(
res
.
statusText
);
}
});
};
//请求方式过滤器
const
filterReqMethod
=
(
value
)
=>
{
const
findItem
=
reqMethodList
.
find
((
item
)
=>
item
.
value
===
value
);
return
(
findItem
||
{}).
label
;
};
//操作类型过滤器
const
filterOperateType
=
(
value
)
=>
{
const
findItem
=
operateTypeList
.
find
((
item
)
=>
item
.
value
===
value
);
return
(
findItem
||
{}).
label
;
};
//选择项发生变化
const
selectChange
=
(
params
)
=>
{
state
.
selectedNum
=
params
.
allLength
;
};
//批量删除
const
deleteBatch
=
()
=>
{
state
.
selectedRows
=
[];
const
selectedObj
=
userTable
.
value
.
dealSelectData
();
state
.
selectedRows
=
Object
.
values
(
selectedObj
);
if
(
!
state
.
selectedRows
.
length
)
return
ElMessage
.
warning
(
"
请先选择删除项
"
);
state
.
deleteTips
=
"
确定要删除选中项吗?
"
;
state
.
deleteDialog
=
true
;
};
//删除当前行
const
deleteCurrent
=
(
row
)
=>
{
state
.
selectedRows
=
[
row
];
state
.
deleteTips
=
"
确定要删除当前行吗?
"
;
state
.
deleteDialog
=
true
;
};
//确定删除
const
confirmDelete
=
()
=>
{
const
ids
=
state
.
selectedRows
.
map
((
item
)
=>
item
.
id
);
axios
.
delete
(
`/apaas/system/v5/log/userBehavior/delete?ids=
${
ids
.
join
(
"
,
"
)}
`
)
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
===
200
)
{
ElMessage
.
success
(
res
.
data
.
data
);
cleanSelected
();
getTableRows
();
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
})
.
finally
(()
=>
{
state
.
deleteDialog
=
false
;
});
};
//清空
const
cleanSelected
=
()
=>
{
userTable
.
value
.
clearTable
();
};
const
changeSearch
=
(
val
)
=>
{
state
.
filter
.
search
=
val
;
changePage
(
1
);
};
const
changePage
=
(
page
)
=>
{
state
.
filter
.
page
=
page
;
getTableRows
();
};
const
getTableRows
=
()
=>
{
let
params
=
{
...
state
.
filter
};
params
.
start_at
=
params
.
time
?
params
.
time
[
0
]
||
""
:
""
;
params
.
end_at
=
params
.
time
?
params
.
time
[
1
]
||
""
:
""
;
delete
params
.
time
;
axios
.
get
(
`/apaas/system/v5/log/userBehavior/list`
,
{
params
,
})
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
state
.
tableRows
=
res
.
data
.
data
||
[];
state
.
filter
.
total
=
res
.
data
.
total
;
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
const
filterAction
=
()
=>
{
changePage
(
1
);
};
const
changeSize
=
(
size
)
=>
{
state
.
filter
.
limit
=
size
;
changePage
(
1
);
};
const
filterClear
=
()
=>
{
state
.
filter
=
{
search
:
""
,
is_admin
:
""
,
time
:
[],
operate_type
:
""
,
req_method
:
""
,
operate_status
:
""
,
page
:
1
,
limit
:
10
,
total
:
0
,
};
changePage
(
1
);
};
const
goDetail
=
(
row
)
=>
{
router
.
push
({
path
:
"
/log/userBehavior/detail
"
,
query
:
{
id
:
row
.
id
,
},
});
};
onBeforeMount
(()
=>
{
getTableRows
();
});
</
script
>
<
style
lang=
"scss"
scoped
>
.page_container
{
display
:
flex
;
flex-direction
:
column
;
justify-content
:
flex-start
;
align-items
:
stretch
;
width
:
100%
;
padding
:
0
24px
;
min-height
:
100%
;
.main_container
{
display
:
flex
;
flex-direction
:
column
;
justify-content
:
flex-start
;
align-items
:
stretch
;
flex-grow
:
1
;
width
:
100%
;
background-color
:
#fff
;
box-shadow
:
0px
1px
4px
0px
rgba
(
0
,
7
,
101
,
0
.15
);
border-radius
:
6px
;
padding
:
0
0
16px
0
;
margin-bottom
:
16px
;
position
:
relative
;
.sleceted_tip
{
margin
:
0
24px
0
40px
;
vertical-align
:
middle
;
font-size
:
14px
;
color
:
#404a62
;
.num
{
margin
:
0
3px
0
3px
;
font-weight
:
600
;
color
:
#202531
;
}
}
.clean
{
vertical-align
:
middle
;
font-size
:
14px
;
color
:
#3759be
;
cursor
:
pointer
;
}
.filter-group
{
.left-filter
{
flex
:
1
;
display
:
flex
;
justify-content
:
start
;
flex-wrap
:
wrap
;
.filter_item
{
display
:
flex
;
align-items
:
center
;
.filter_title
{
width
:
84px
;
white-space
:
pre-wrap
;
font-weight
:
normal
;
}
}
}
.right-action
{
width
:
144px
;
padding-bottom
:
16px
;
.el-button
{
width
:
64px
;
}
}
}
.table_container
{
padding
:
0
16px
;
.el-table
{
flex
:
1
;
:deep
()
td
{
padding
:
9px
0
!
important
;
}
}
.operate_status
{
&
:
:
before
{
display
:
inline-block
;
content
:
""
;
width
:
6px
;
height
:
6px
;
margin-right
:
6px
;
vertical-align
:
middle
;
background-color
:
#48ad97
;
border-radius
:
50%
;
}
&.
fail
:
:
before
{
background-color
:
#dd6955
;
}
}
}
}
}
</
style
>
src/page/main/system-admin/menu/index.vue
View file @
c11a241c
<
template
>
<
template
>
<div>
菜单管理
</div>
<div
class=
"page_container"
>
<bg-breadcrumb></bg-breadcrumb>
<div
class=
"flex_row"
>
<div
class=
"flex_left"
>
<div
class=
"tree_content"
>
<div
class=
"search"
>
<el-input
v-model.trim=
"search"
placeholder=
"请输入内容"
:prefix-icon=
"Search"
/>
</div>
<div
class=
"tree"
>
<el-tree
class=
"file-tree"
:data=
"data"
:props=
"defaultProps"
@
node-click=
"handleNodeClick"
:default-expand-all=
"true"
:highlight-current=
"true"
node-key=
"menu_id"
ref=
"menuTree"
:filter-node-method=
"filterNode"
:expand-on-click-node=
"false"
>
<template
#default
="
{ node, data }">
<div
class=
"custom-tree-node"
pointer-events=
"none"
>
<span
class=
"label-text text_clip"
:title=
"data.menu_name"
>
{{
data
.
menu_name
}}
</span>
</div>
<span
class=
"tree-action-box"
:class=
"
{ position_sticky: isSticky(data.name) }"
@click.stop="showAction($event, data, node)">
<bg-icon
class=
"tree-more"
icon=
"#bg-ic-s-more"
></bg-icon>
</span>
</
template
>
</el-tree>
<Teleport
to=
"body"
>
<div
class=
"tree-action"
ref=
"treeAction"
v-show=
"actionFlag"
:style=
"{ top: acTop, left: acLeft, bottom: acBottom }"
>
<div
class=
"action"
@
click=
"fileAction(1, selectData, selectParentData)"
>
新增本级
</div>
<div
class=
"action"
@
click=
"fileAction(2, selectData, selectParentData)"
>
新增下级
</div>
<div
class=
"action"
@
click=
"fileAction(3, selectData, selectParentData)"
>
删除
</div>
<div
class=
"action"
:class=
"{ disable: moveIndex == 0 }"
@
click=
"fileAction(4, selectData, selectParentData, moveIndex == 0)"
>
上移
</div>
<div
class=
"action"
:class=
"{
disable: !selectParentData
? moveIndex == data.length - 1
: moveIndex == selectParentData.Child.length - 1,
}"
@
click=
"
fileAction(
5,
selectData,
selectParentData,
!selectParentData ? moveIndex == data.length - 1 : moveIndex == selectParentData.Child.length - 1
)
"
>
下移
</div>
</div>
</Teleport>
</div>
</div>
</div>
<div
class=
"flex_right"
>
<div
class=
"main_container"
>
<div
class=
"base-info bg-scroll"
>
<menuForm
ref=
"menuFormRef"
:data=
"menuFormData"
></menuForm>
</div>
<div
class=
"base-btn"
>
<el-button
type=
"primary"
@
click=
"saveMenu(menuFormRef, addType)"
>
保存
</el-button>
</div>
</div>
</div>
</div>
<!-- 删除弹窗 -->
<el-dialog
class=
"dialog_box"
title=
"提示"
v-model=
"delDialog"
width=
"400px"
>
<div>
确定要删除此菜单吗?
</div>
<
template
v-slot:footer
>
<div
class=
"apaas_button"
>
<el-button
type=
"default"
@
click=
"delDialog = false"
>
取 消
</el-button>
<el-button
type=
"primary"
@
click=
"deleteData"
>
确 定
</el-button>
</div>
</
template
>
</el-dialog>
</div>
</template>
</template>
<
script
setup
></
script
>
<
script
setup
>
import
{
Search
}
from
"
@element-plus/icons-vue
"
;
import
{
reactive
,
toRefs
,
ref
,
nextTick
,
computed
,
onBeforeMount
,
onBeforeUnmount
,
watch
}
from
"
vue
"
;
import
{
useRouter
}
from
"
vue-router
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
axios
from
"
@/request/http.js
"
;
import
menuForm
from
"
./menu-form.vue
"
;
import
bgBreadcrumb
from
"
@/components/bg-breadcrumb.vue
"
;
const
router
=
useRouter
();
<
style
lang=
"scss"
scoped
></
style
>
const
menuTree
=
ref
(
null
);
// 树形
const
treeAction
=
ref
(
null
);
// 树形操作弹出框
const
menuFormRef
=
ref
(
null
);
// 右侧表单
const
acTop
=
ref
(
""
);
const
acLeft
=
ref
(
""
);
const
acBottom
=
ref
(
""
);
const
actionFlag
=
ref
(
false
);
// 弹出框状态标识
const
state
=
reactive
({
data
:
[],
// 树形数据
search
:
""
,
// 树形搜索
selectData
:
null
,
// 当前选中的节点
selectParentData
:
null
,
// 当前选中节点的父节点
treeAction
,
menuTree
,
bottomGap
:
30
,
//弹窗吸底高度
defaultProps
:
{
children
:
"
Child
"
,
label
:
"
menu_name
"
,
},
// 树形配置
actionDataIndex
:
0
,
// 当前选中节点在本级的位置,用来判断是否可以上下移动
menuFormData
:
null
,
// 菜单数据
addType
:
1
,
// 1-新增本级 2-新增下级
newMenuId
:
0
,
// 新增菜单时用来指定menu_id,达到选中效果
timer
:
null
,
// 定时器
delDialog
:
false
,
});
const
moveIndex
=
computed
({
get
:
()
=>
{
let
index
=
0
;
if
(
state
.
selectData
)
{
findIndex
(
state
.
selectData
.
menu_id
,
state
.
data
);
index
=
state
.
actionDataIndex
;
}
return
index
;
},
});
// 计算上下移动
watch
(
()
=>
state
.
search
,
(
n
,
o
)
=>
{
if
(
state
.
timer
)
{
clearTimeout
(
state
.
timer
);
}
state
.
timer
=
setTimeout
(()
=>
{
state
.
menuTree
.
filter
(
n
);
},
500
);
}
);
// 树形搜索值
const
getMenuTree
=
(
type
,
id
)
=>
{
axios
.
get
(
`/apaas/system/v5/menu/tree`
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
state
.
data
=
res
.
data
.
data
||
[];
nextTick
().
then
(()
=>
{
if
(
type
)
{
if
(
type
==
1
)
{
// 删除数据后默认选中父节点或第一个节点
state
.
menuTree
&&
state
.
menuTree
.
setCurrentKey
(
state
.
selectParentData
.
menu_id
);
handleNodeClick
(
state
.
selectParentData
);
nextTick
().
then
(()
=>
{
setScroll
();
});
}
else
{
state
.
menuTree
&&
state
.
menuTree
.
setCurrentKey
(
state
.
data
[
0
].
menu_id
);
handleNodeClick
(
state
.
data
[
0
]);
}
}
else
{
// 上下移,初始化时默认选中节点 新增选中新增的节点
if
(
id
)
{
findData
(
state
.
data
,
id
);
}
if
(
state
.
selectData
)
{
state
.
menuTree
&&
state
.
menuTree
.
setCurrentKey
(
state
.
selectData
.
menu_id
);
handleNodeClick
(
state
.
selectData
);
nextTick
().
then
(()
=>
{
setScroll
();
});
}
else
{
state
.
menuTree
&&
state
.
menuTree
.
setCurrentKey
(
state
.
data
[
0
].
menu_id
);
handleNodeClick
(
state
.
data
[
0
]);
}
}
});
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
// 获取菜单树
const
setScroll
=
()
=>
{
setTimeout
(()
=>
{
var
nodeOffsetTop
=
document
.
querySelector
(
"
.file-tree .is-current
"
).
offsetTop
;
var
treeScroll
=
document
.
querySelector
(
"
.tree
"
);
var
parentHeight
=
treeScroll
.
clientHeight
;
if
(
nodeOffsetTop
>
parentHeight
)
{
treeScroll
.
scrollTop
=
nodeOffsetTop
-
parentHeight
/
2
;
}
},
300
);
};
const
findData
=
(
arr
,
id
)
=>
{
arr
.
forEach
((
e
)
=>
{
if
(
e
.
menu_id
==
id
)
{
state
.
selectData
=
e
;
}
else
{
if
(
e
.
Child
&&
e
.
Child
.
length
>
0
)
{
findData
(
e
.
Child
,
id
);
}
}
});
};
// 处理数据 用于新增菜单后选中新增的菜单
const
findIndex
=
(
code
,
arr
)
=>
{
arr
.
forEach
((
e
,
i
)
=>
{
if
(
e
.
menu_id
==
code
)
{
state
.
actionDataIndex
=
i
;
}
else
{
if
(
e
.
Child
&&
e
.
Child
.
length
>
0
)
{
findIndex
(
code
,
e
.
Child
);
}
}
});
};
// 处理数据 用于判断能否上下移
const
isSticky
=
(
data
)
=>
{
const
canvas
=
document
.
createElement
(
"
canvas
"
);
const
context
=
canvas
.
getContext
(
"
2d
"
);
context
.
font
=
"
14px MicrosoftYaHei
"
;
const
{
width
}
=
context
.
measureText
(
data
);
return
width
>
255
?
true
:
false
;
};
const
showAction
=
(
e
,
data
,
node
)
=>
{
acTop
.
value
=
""
;
acLeft
.
value
=
""
;
acBottom
.
value
=
""
;
const
rect
=
e
.
target
.
getBoundingClientRect
();
//获取点击的dom的位置
var
allHeight
=
document
.
body
.
scrollHeight
;
actionFlag
.
value
=
true
;
state
.
selectData
=
data
;
if
(
node
.
parent
.
data
.
Child
)
{
state
.
selectParentData
=
node
.
parent
.
data
;
}
else
{
//没有children则是最上层元素
state
.
selectParentData
=
null
;
}
nextTick
().
then
(()
=>
{
setTimeout
(()
=>
{
var
height
=
window
.
getComputedStyle
(
state
.
treeAction
).
height
;
height
=
parseInt
(
height
);
//判断弹窗位置是否超过屏幕,超过则吸底展示
if
(
height
+
rect
.
y
-
17
>
allHeight
-
state
.
bottomGap
)
{
acBottom
.
value
=
state
.
bottomGap
+
"
px
"
;
acLeft
.
value
=
rect
.
x
+
35
+
"
px
"
;
}
else
{
acTop
.
value
=
rect
.
y
-
17
+
"
px
"
;
acLeft
.
value
=
rect
.
x
+
35
+
"
px
"
;
}
});
});
};
// 树形操作框
const
handleNodeClick
=
(
data
)
=>
{
if
(
state
.
selectData
&&
state
.
selectData
.
menu_id
==
data
.
menu_id
)
{
return
;
}
state
.
selectData
=
data
;
menuFormRef
.
value
.
setForm
(
state
.
selectData
);
closeAction
();
if
(
menuFormRef
)
{
nextTick
().
then
(()
=>
{
menuFormRef
.
value
.
menuRef
.
validate
((
valid
)
=>
{
if
(
!
valid
)
{
menuFormRef
.
value
.
menuRef
.
clearValidate
();
}
});
});
}
// 清除表单验证
};
// 菜单树节点点击
const
filterNode
=
(
val
,
data
)
=>
{
if
(
!
val
)
{
return
true
;
}
return
data
.
menu_name
.
includes
(
val
);
};
// 树形筛选
const
fileAction
=
(
val
,
data
,
parent
,
disabled
=
false
)
=>
{
if
(
val
==
1
)
{
// 新增本级菜单
state
.
addType
=
1
;
let
newChild
=
{
menu_name
:
"
新菜单
"
,
// 菜单名称
menu_id
:
"
new
"
+
state
.
newMenuId
,
// 菜单id,用于新增后选中
menu_type
:
!
parent
?
0
:
parent
.
menu_type
==
0
?
0
:
2
,
// 新增本级的类型
dict_group_id
:
parent
?
parent
.
dict_group_id
:
""
,
// 父级的分组 有则继承,无则自选
state
:
1
,
// 启用状态
menu_url
:
""
,
// 路径
menu_logo
:
""
,
// 图标
source
:
""
,
level
:
data
.
level
,
// 当前的level
p_menu_type
:
parent
?
parent
.
menu_type
:
0
,
// 父级的类型,用于判断菜单下不能建目录
system_type
:
""
,
// 系统类型
new_window
:
0
,
remark
:
""
,
};
state
.
menuTree
.
insertAfter
(
newChild
,
parent
?
parent
.
Child
[
parent
.
Child
.
length
-
1
]
:
state
.
data
[
state
.
data
.
length
-
1
]
);
state
.
menuTree
&&
state
.
menuTree
.
setCurrentKey
(
newChild
.
menu_id
);
handleNodeClick
(
newChild
);
state
.
newMenuId
++
;
}
else
if
(
val
==
2
)
{
// 新增下级菜单
if
(
disabled
)
{
return
;
}
state
.
addType
=
2
;
let
newChild
=
{
menu_name
:
"
新菜单
"
,
menu_id
:
"
new
"
+
state
.
newMenuId
,
menu_type
:
data
.
menu_type
==
0
?
0
:
2
,
dict_group_id
:
data
.
dict_group_id
,
state
:
1
,
menu_url
:
""
,
menu_logo
:
""
,
source
:
""
,
p_menu_type
:
data
.
menu_type
,
level
:
data
.
level
+
1
,
system_type
:
""
,
// 系统类型
new_window
:
0
,
remark
:
""
,
};
state
.
menuTree
.
append
(
newChild
,
data
);
state
.
menuTree
&&
state
.
menuTree
.
setCurrentKey
(
newChild
.
menu_id
);
handleNodeClick
(
newChild
);
state
.
selectParentData
=
data
;
state
.
newMenuId
++
;
}
else
if
(
val
==
3
)
{
// 删除菜单
if
(
data
.
id
)
{
if
(
data
.
state
==
1
)
{
ElMessage
.
error
(
"
删除内容中有启用状态的数据,不可删除!
"
);
return
;
}
state
.
delDialog
=
true
;
}
else
{
state
.
delDialog
=
true
;
}
}
else
if
(
val
==
4
)
{
// 菜单上移
if
(
disabled
)
{
return
;
}
let
nextObj
=
null
;
if
(
parent
)
{
parent
.
Child
.
forEach
((
e
,
i
)
=>
{
if
(
data
.
id
==
e
.
id
)
{
nextObj
=
parent
.
Child
[
i
-
1
];
}
});
}
else
{
state
.
data
.
forEach
((
e
,
i
)
=>
{
if
(
data
.
id
==
e
.
id
)
{
nextObj
=
state
.
data
[
i
-
1
];
}
});
}
changeSort
(
data
,
nextObj
);
}
else
{
// 菜单下移
if
(
disabled
)
{
return
;
}
let
nextObj
=
null
;
if
(
parent
)
{
parent
.
Child
.
forEach
((
e
,
i
)
=>
{
if
(
data
.
id
==
e
.
id
)
{
nextObj
=
parent
.
Child
[
i
+
1
];
}
});
}
else
{
state
.
data
.
forEach
((
e
,
i
)
=>
{
if
(
data
.
id
==
e
.
id
)
{
nextObj
=
state
.
data
[
i
+
1
];
}
});
}
changeSort
(
data
,
nextObj
);
}
if
(
menuFormRef
)
{
nextTick
().
then
(()
=>
{
menuFormRef
.
value
.
menuRef
.
validate
((
valid
)
=>
{
if
(
!
valid
)
{
menuFormRef
.
value
.
menuRef
.
clearValidate
();
}
});
});
}
// 清除表单验证
};
// 各种操作按钮
const
deleteData
=
()
=>
{
if
(
state
.
selectData
.
id
)
{
axios
.
delete
(
`/apaas/system/v5/menu/
${
state
.
selectData
.
id
}
`
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
ElMessage
.
success
(
res
.
data
.
msg
);
state
.
selectData
=
null
;
let
type
=
state
.
selectParentData
?
1
:
2
;
// 1--有父级 2--无父级
getMenuTree
(
type
);
state
.
delDialog
=
false
;
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
}
else
{
state
.
menuTree
.
remove
(
state
.
selectData
);
state
.
selectData
=
null
;
let
type
=
state
.
selectParentData
?
1
:
2
;
// 1--有父级 2--无父级
if
(
type
==
1
)
{
state
.
menuTree
&&
state
.
menuTree
.
setCurrentKey
(
state
.
selectParentData
.
menu_id
);
handleNodeClick
(
state
.
selectParentData
);
}
else
{
state
.
menuTree
&&
state
.
menuTree
.
setCurrentKey
(
state
.
data
[
0
].
menu_id
);
handleNodeClick
(
state
.
data
[
0
]);
}
state
.
delDialog
=
false
;
}
};
const
changeSort
=
(
data
,
nextObj
)
=>
{
let
params
=
[
{
id
:
data
.
id
,
sort
:
nextObj
.
sort
,
},
{
id
:
nextObj
.
id
,
sort
:
data
.
sort
,
},
];
axios
.
put
(
`/apaas/system/v5/menu/sort`
,
params
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
ElMessage
.
success
(
res
.
data
.
msg
);
getMenuTree
();
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
// 菜单上下移
const
closeAction
=
()
=>
{
actionFlag
.
value
=
false
;
};
// 点击其他地方,菜单操作框关闭
const
saveMenu
=
(
el
,
type
)
=>
{
el
.
menuRef
.
validate
((
valid
)
=>
{
if
(
valid
)
{
let
params
=
{
menu_name
:
el
.
menuForm
.
menu_name
,
menu_type
:
el
.
menuForm
.
menu_type
,
dict_group_id
:
el
.
menuForm
.
dict_group_id
,
state
:
el
.
menuForm
.
state
,
menu_url
:
el
.
menuForm
.
menu_url
,
menu_logo
:
el
.
menuForm
.
menu_logo
,
source
:
el
.
menuForm
.
menu_type
==
0
?
""
:
el
.
menuForm
.
source
,
system_type
:
el
.
menuForm
.
system_type
,
new_window
:
el
.
menuForm
.
new_window
,
remark
:
el
.
menuForm
.
remark
,
};
if
(
state
.
selectData
.
id
)
{
// 编辑
axios
.
put
(
`/apaas/system/v5/menu/
${
state
.
selectData
.
id
}
`
,
params
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
ElMessage
.
success
(
res
.
data
.
msg
);
getMenuTree
();
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
}
else
{
// 新增
if
(
state
.
selectParentData
)
{
if
(
state
.
selectParentData
.
menu_type
==
1
&&
el
.
menuForm
.
menu_type
==
0
)
{
ElMessage
.
error
(
"
菜单之下不可以新增目录
"
);
return
;
}
}
if
(
type
==
1
)
{
// 新增本级
params
.
p_menu_id
=
state
.
selectParentData
?
state
.
selectParentData
.
menu_id
:
""
;
}
else
{
// 新增下级
params
.
p_menu_id
=
state
.
selectParentData
.
menu_id
;
}
axios
.
post
(
`/apaas/system/v5/menu/add`
,
params
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
ElMessage
.
success
(
res
.
data
.
msg
);
state
.
selectData
=
null
;
getMenuTree
(
null
,
res
.
data
.
data
);
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
}
}
});
};
// 保存按钮,新增或编辑菜单
onBeforeMount
(()
=>
{
window
.
addEventListener
(
"
click
"
,
closeAction
);
window
.
addEventListener
(
"
scroll
"
,
closeAction
,
true
);
getMenuTree
();
});
onBeforeUnmount
(()
=>
{
window
.
removeEventListener
(
"
click
"
,
closeAction
);
window
.
removeEventListener
(
"
scroll
"
,
closeAction
);
});
const
{
data
,
search
,
defaultProps
,
selectParentData
,
selectData
,
menuFormData
,
addType
,
delDialog
}
=
toRefs
(
state
);
</
script
>
<
style
scoped
>
.flex_left
{
background-color
:
#fff
;
height
:
calc
(
100%
-
16px
);
width
:
320px
;
box-shadow
:
0px
1px
4px
0px
rgba
(
0
,
7
,
101
,
0.15
);
border-radius
:
6px
;
margin-right
:
10px
;
overflow
:
hidden
;
}
.flex_right
{
background-color
:
#fff
;
height
:
calc
(
100%
-
16px
);
flex
:
1
;
box-shadow
:
0px
1px
4px
0px
rgba
(
0
,
7
,
101
,
0.15
);
border-radius
:
6px
;
overflow
:
hidden
;
}
.tree_content
{
overflow
:
hidden
;
height
:
calc
(
100%
-
4px
);
position
:
relative
;
}
.search
{
padding
:
16px
16px
10px
;
}
.tree
{
overflow
:
auto
;
height
:
calc
(
100%
-
65px
);
}
.tree
:deep
()
.el-tree-node
>
.el-tree-node__content
{
/* padding: 0 16px!important; */
}
.tree
:deep
()
.el-tree-node
>
.el-tree-node__children
{
overflow
:
unset
;
/* padding-left: 16px; */
}
.file-tree
:deep
()
.el-tree-node__content
{
position
:
relative
;
}
.tree-action-box
{
display
:
none
;
position
:
absolute
;
right
:
0px
;
top
:
0px
;
background-color
:
#f2f3f7
;
width
:
44px
;
text-align
:
center
;
height
:
36px
;
line-height
:
36px
;
}
.position_sticky
{
position
:
sticky
;
position
:
-webkit-sticky
;
}
.tree
.el-tree-node__content
:hover
.tree-action-box
{
display
:
inline-block
;
}
.tree
.el-tree
{
position
:
static
!important
;
}
.tree
.el-tree
:deep
()
.el-tree-node__content
{
height
:
36px
!important
;
}
.tree
.el-tree
:deep
()
.el-tree-node__content
:hover
{
background-image
:
linear-gradient
(
90deg
,
rgba
(
255
,
255
,
255
,
0.05
)
83%
,
rgba
(
0
,
0
,
0
,
0.05
)
86%
);
}
.tree-more
{
font-size
:
12px
;
color
:
#3759be
;
}
.tree-action
{
width
:
144px
;
background-color
:
#ffffff
;
box-shadow
:
0px
1px
4px
0px
rgba
(
0
,
7
,
101
,
0.15
);
padding
:
4px
0
;
border-radius
:
4px
;
position
:
fixed
;
z-index
:
9
;
}
.tree-action
.action
{
width
:
100%
;
height
:
34px
;
line-height
:
34px
;
padding-left
:
16px
;
font-size
:
14px
;
color
:
#202531
;
cursor
:
pointer
;
}
.tree-action
.action
:hover
{
background-color
:
#f2f3f7
;
color
:
#3759be
;
}
.tree-action
.disable
{
cursor
:
not-allowed
;
color
:
#616f94
;
}
.tree-action
.disable
:hover
{
background-color
:
#fff
;
color
:
#616f94
;
}
.main_container
{
height
:
100%
;
}
</
style
>
<
style
lang=
"scss"
scoped
>
.main_container
{
.base-info
{
height
:
calc
(
100%
-
68px
);
padding
:
40px
0
0
40px
;
}
.base-btn
{
height
:
68px
;
border-top
:
1px
solid
#e6e9ef
;
text-align
:
right
;
padding
:
16px
;
.el-button
{
width
:
92px
;
}
}
}
</
style
>
src/page/main/system-admin/menu/menu-form.vue
0 → 100644
View file @
c11a241c
<
template
>
<el-form
:label-position=
"'right'"
label-width=
"68px"
:model=
"menuForm"
:rules=
"formRules"
ref=
"menuRef"
style=
"width: 856px"
class=
"menu_form"
>
<el-form-item
label=
"菜单名称"
prop=
"menu_name"
>
<el-input
v-model.trim=
"menuForm.menu_name"
show-word-limit
maxlength=
"8"
placeholder=
"请输入菜单名称"
/>
</el-form-item>
<el-form-item
label=
"类型"
prop=
"menu_type"
v-if=
"!topLevel"
>
<el-radio-group
v-model=
"menuForm.menu_type"
:disabled=
"radioDisabled"
>
<el-radio
:label=
"0"
:disabled=
"typeDisFlag != 0"
>
目录
</el-radio>
<el-radio
:label=
"1"
:disabled=
"typeDisFlag != 2 && typeDisFlag != 0"
>
菜单
</el-radio>
<el-radio
:label=
"2"
>
子页面
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
label=
"分组"
prop=
"dict_group_id"
v-if=
"!topLevel"
>
<el-select
v-model=
"menuForm.dict_group_id"
:disabled=
"groupFlag"
placeholder=
"请选择分组"
>
<el-option
v-for=
"item in groupList"
:key=
"item.dict_id"
:label=
"item.dict_name"
:value=
"item.dict_id"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"跳转方式"
prop=
"new_window"
v-if=
"menuForm.menu_type != 0"
>
<el-radio-group
v-model=
"menuForm.new_window"
>
<el-radio
:label=
"0"
>
当前窗口
</el-radio>
<el-radio
:label=
"1"
>
新窗口
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
label=
"备注"
prop=
"remark"
>
<el-input
v-model=
"menuForm.remark"
show-word-limit
maxlength=
"8"
placeholder=
"请输入备注"
/>
</el-form-item>
<el-form-item
label=
"系统类型"
prop=
"system_type"
v-if=
"topLevel"
>
<el-select
v-model=
"menuForm.system_type"
placeholder=
"请选择系统类型"
>
<el-option
v-for=
"item in systemGroupList"
:key=
"item.dict_id"
:label=
"item.dict_name"
:value=
"item.dict_id"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"是否启用"
prop=
"state"
>
<el-switch
class=
"bg-switch-ele"
v-model=
"menuForm.state"
:active-value=
"1"
:inactive-value=
"0"
inline-prompt
active-text=
"是"
inactive-text=
"否"
:disabled=
"disabledSwitch"
/>
</el-form-item>
<el-form-item
label=
"菜单路径"
:prop=
"topLevel ? '' : 'menu_url'"
>
<el-input
v-model=
"menuForm.menu_url"
show-word-limit
maxlength=
"200"
placeholder=
"请输入菜单路径"
/>
</el-form-item>
<el-form-item
label=
"菜单图标"
prop=
"menu_logo"
>
<div
class=
"iconBox"
:style=
"iconFlag ?
{ 'border-color': '#2b4695' } : {}" @click="openIconbox">
<div>
<span>
<bg-icon
class=
"bgIcon"
style=
"margin-right: 8px"
:icon=
"'#' + menuForm.menu_logo"
></bg-icon>
<span>
{{
menuForm
.
menu_logo
.
replace
(
"
bg-ic-
"
,
""
)
}}
</span>
</span>
</div>
<div>
<bg-icon
class=
"bgIcon clearIcon"
icon=
"#bg-ic-circle-close"
v-if=
"menuForm.menu_logo != ''"
@
click.stop=
"clearIcon"
></bg-icon>
<bg-icon
class=
"bgIcon"
:icon=
"iconFlag ? '#bg-ic-caret-top' : '#bg-ic-caret-bottom'"
></bg-icon>
</div>
</div>
<div
class=
"icon_box"
v-show=
"iconFlag"
>
<div
class=
"input_box"
>
<el-input
placeholder=
"请输入内容"
:prefix-icon=
"Search"
v-model=
"icon_search"
@
input=
"searchIcon"
>
</el-input>
</div>
<div
class=
"icon_content bg-scroll"
>
<div
class=
"icon_item"
v-for=
"(e, i) in showIconArr"
:key=
"i + 100"
@
click=
"changeIcon(e)"
>
<span
:title=
"e.name"
>
<bg-icon
class=
"selectBgIcon"
:icon=
"'#' + e.icon"
></bg-icon>
{{
e
.
name
}}
</span>
</div>
</div>
</div>
</el-form-item>
<el-form-item
label=
"资源路径"
v-if=
"menuForm.menu_type != 0"
>
<el-input
v-model=
"menuForm.source"
show-word-limit
maxlength=
"200"
placeholder=
"请输入资源路径"
/>
</el-form-item>
</el-form>
</
template
>
<
script
setup
>
import
{
Search
}
from
"
@element-plus/icons-vue
"
;
import
{
reactive
,
ref
,
onMounted
,
toRefs
}
from
"
vue
"
;
import
axios
from
"
../../../../request/http.js
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
allIconArr
from
"
@/assets/js/bg_icon.js
"
;
const
menuRef
=
ref
(
null
);
const
props
=
defineProps
({
data
:
{
type
:
Object
,
default
:
null
,
},
});
const
state
=
reactive
({
menuRef
,
menuForm
:
{
menu_name
:
""
,
menu_type
:
0
,
dict_group_id
:
""
,
state
:
1
,
menu_url
:
""
,
menu_logo
:
""
,
source
:
""
,
system_type
:
""
,
new_window
:
0
,
remark
:
""
,
},
formRules
:
{
menu_name
:
[{
required
:
true
,
message
:
"
请输入菜单名称
"
,
trigger
:
"
blur
"
}],
menu_type
:
[{
required
:
true
,
message
:
"
请选择菜单类型
"
,
trigger
:
"
change
"
}],
dict_group_id
:
[{
required
:
true
,
message
:
"
请选择菜单分组
"
,
trigger
:
"
change
"
}],
system_type
:
[{
required
:
true
,
message
:
"
请选择系统类型
"
,
trigger
:
"
change
"
}],
menu_url
:
[{
required
:
true
,
message
:
"
请输入菜单路径
"
,
trigger
:
"
blur
"
}],
new_window
:
[{
required
:
true
,
message
:
"
请选择跳转方式
"
,
trigger
:
"
change
"
}],
},
groupList
:
[],
// 菜单分组
systemGroupList
:
[],
// 系统类型--顶级菜单使用
iconFlag
:
false
,
// 图标盒子
icon_search
:
""
,
// 图标筛选
iconArr
:
[],
// 所有的图标
showIconArr
:
[],
// 展示的图标
timer
:
null
,
radioDisabled
:
false
,
topLevel
:
false
,
typeDisFlag
:
null
,
groupFlag
:
true
,
disabledSwitch
:
false
,
// 内置菜单built_in为1-不可禁用 0或不存在-可禁用
});
const
getGroupList
=
()
=>
{
axios
.
get
(
`/apaas/system/v5/menu/group/dict`
)
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
state
.
groupList
=
res
.
data
.
data
||
[];
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
})
.
catch
((
err
)
=>
{
console
.
log
(
err
);
});
};
// 获取分组数据
const
getSystemGroup
=
()
=>
{
axios
.
get
(
`/apaas/system/v5/menu/system/dict`
)
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
state
.
systemGroupList
=
res
.
data
.
data
||
[];
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
})
.
catch
((
err
)
=>
{
console
.
log
(
err
);
});
};
// 获取系统类型数据
const
openIconbox
=
()
=>
{
state
.
iconFlag
=
!
state
.
iconFlag
;
state
.
icon_search
=
""
;
searchIcon
();
};
// 打开/关闭图标盒子
const
searchIcon
=
()
=>
{
if
(
state
.
timer
)
{
clearTimeout
(
state
.
timer
);
}
state
.
timer
=
setTimeout
(()
=>
{
let
iconList
=
[];
if
(
state
.
icon_search
==
""
)
{
state
.
showIconArr
=
state
.
iconArr
;
}
else
{
state
.
iconArr
.
map
((
e
)
=>
{
if
(
e
.
name
.
indexOf
(
state
.
icon_search
)
!==
-
1
)
{
iconList
.
push
(
e
);
}
});
state
.
showIconArr
=
iconList
;
}
},
500
);
};
// 图标筛选
const
setForm
=
(
data
)
=>
{
if
(
data
.
level
&&
data
.
level
==
1
)
{
state
.
topLevel
=
true
;
}
else
{
state
.
topLevel
=
false
;
if
(
data
.
level
==
2
)
{
state
.
groupFlag
=
false
;
}
else
{
state
.
groupFlag
=
true
;
}
}
state
.
typeDisFlag
=
data
.
p_menu_type
;
if
(
data
.
id
)
{
// 编辑状态
state
.
radioDisabled
=
true
;
}
else
{
state
.
radioDisabled
=
false
;
}
state
.
disabledSwitch
=
data
.
built_in
&&
data
.
built_in
==
1
?
true
:
false
;
state
.
menuForm
=
Object
.
assign
(
state
.
menuForm
,
data
);
};
// 表单赋值
const
clearIcon
=
()
=>
{
state
.
menuForm
.
menu_logo
=
""
;
};
// 清除选中的图标
const
changeIcon
=
(
e
)
=>
{
state
.
menuForm
.
menu_logo
=
e
.
icon
;
state
.
iconFlag
=
false
;
state
.
icon_search
=
""
;
searchIcon
();
};
// 选中图标
onMounted
(()
=>
{
// 处理图标数据
allIconArr
.
forEach
((
e
)
=>
{
state
.
iconArr
.
push
({
icon
:
e
,
name
:
e
.
replace
(
"
bg-ic-
"
,
""
),
});
});
state
.
showIconArr
=
state
.
iconArr
;
getGroupList
();
getSystemGroup
();
});
const
{
menuForm
,
formRules
,
groupList
,
iconFlag
,
showIconArr
,
icon_search
,
radioDisabled
,
topLevel
,
typeDisFlag
,
groupFlag
,
systemGroupList
,
disabledSwitch
,
}
=
toRefs
(
state
);
defineExpose
({
setForm
,
menuForm
,
menuRef
});
</
script
>
<
style
lang=
"scss"
scoped
>
.menu_form
{
.el-form-item
{
margin-bottom
:
24px
;
:deep
()
.el-form-item__label
{
padding
:
0
;
margin-right
:
8px
;
}
.el-form-item__content
{
.el-input
,
.el-select
{
width
:
100%
;
}
.bg-switch-ele
{
width
:
52px
;
height
:
24px
;
:deep
()
.el-switch__core
{
width
:
100%
;
height
:
24px
;
.el-switch__inner
,
.el-switch__action
{
top
:
3px
;
}
}
}
.iconBox
{
width
:
100%
;
display
:
flex
;
padding
:
0
12px
;
height
:
36px
;
line-height
:
36px
;
justify-content
:
space-between
;
border
:
1px
solid
#dadee7
;
border-radius
:
4px
;
cursor
:
pointer
;
.bgIcon
{
color
:
#202531
;
width
:
8px
;
margin-top
:
11px
;
}
.clearIcon
{
margin-right
:
8px
;
width
:
14px
;
display
:
none
;
}
&
:hover
,
&
:focus
,
&
:active
{
border-color
:
#2b4695
;
.clearIcon
{
display
:
inline-block
;
}
}
&
:hover
{
border-color
:
#a9b1c7
;
}
}
.icon_box
{
width
:
100%
;
height
:
236px
;
box-shadow
:
0px
4px
12px
0px
rgba
(
18
,
30
,
63
,
0
.1
);
border-radius
:
4px
;
border
:
solid
1px
#e6e9ef
;
margin-top
:
10px
;
padding
:
12px
0px
12px
8px
;
.input_box
{
margin-right
:
8px
;
}
.icon_content
{
width
:
100%
;
height
:
168px
;
display
:
flex
;
flex-wrap
:
wrap
;
margin-top
:
8px
;
align-content
:
flex-start
;
.icon_item
{
display
:
inline-block
;
border
:
1px
solid
#dadee7
;
border-radius
:
3px
;
width
:
182px
;
height
:
36px
;
margin
:
0
8px
8px
0
;
color
:
#202531
;
padding
:
0
16px
;
line-height
:
36px
;
cursor
:
pointer
;
&
:hover
,
&
:active
{
background-color
:
#eaedf5
;
border-color
:
#95a3ca
;
}
&
:nth-child
(
4n
)
{
margin-right
:
0
;
}
.selectBgIcon
{
width
:
14px
;
margin-right
:
10px
;
}
span
{
display
:
inline-block
;
width
:
100%
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
overflow
:
hidden
;
}
}
}
}
}
}
}
</
style
>
src/page/main/system-admin/preference/authorityForm.vue
0 → 100644
View file @
c11a241c
<
template
>
<el-form
ref=
"authorizeFormRef"
:model=
"authorizeFormData"
:rules=
"authorizeRules"
label-width=
"110px"
class=
"authorizeForm"
>
<el-form-item
label=
"当前版本号"
prop=
"system_version"
>
<el-input
disabled
v-model=
"authorizeFormData.system_version"
/>
</el-form-item>
<el-form-item
label=
"User"
prop=
"system_user"
>
<el-input
placeholder=
"统一管理用户认证平台"
v-model=
"authorizeFormData.system_user"
maxlength=
"30"
/>
</el-form-item>
<el-form-item
label=
"Key"
prop=
"license"
>
<el-input
placeholder=
"请输入"
rows=
"5"
v-model=
"authorizeFormData.license"
type=
"textarea"
@
blur=
"getLicenseInfo"
/>
</el-form-item>
<el-form-item
label=
"有效期至"
prop=
"license_dead_date"
>
<el-input
disabled
v-model=
"authorizeFormData.license_dead_date"
/>
</el-form-item>
<el-form-item
label=
"剩余有效期提醒"
prop=
"license_inform_day"
>
<el-input
placeholder=
"请输入"
v-model.trim.number=
"authorizeFormData.license_inform_day"
>
<template
#append
>
天
</
template
>
</el-input>
<el-tooltip
placement=
"top-start"
effect=
"light"
>
<
template
#content
>
范围(0~90),单位:天, 当剩余有效期在配置区间内时,系统会在用户登录系统时发出提醒,0表示不提醒
</
template
>
<div
class=
"tip-image"
></div>
</el-tooltip>
</el-form-item>
</el-form>
</template>
<
script
setup
>
import
{
reactive
,
toRefs
}
from
"
vue
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
axios
from
"
@/request/http.js
"
;
const
props
=
defineProps
({
authorizeFormData
:
{
type
:
Object
,
default
:
()
=>
({}),
},
});
const
state
=
reactive
({
authorizeRules
:
{
license_inform_day
:
[{
type
:
"
number
"
,
min
:
0
,
max
:
90
,
message
:
"
请输入0~90的整数
"
,
trigger
:
"
blur
"
}],
},
});
//根据license获取授权信息
const
getLicenseInfo
=
()
=>
{
if
(
!
state
.
authorizeFormData
.
license
)
return
;
axios
.
post
(
"
/apaas/system/v5/sysOptions/getLicenseInfo
"
,
{
license
:
state
.
authorizeFormData
.
license
,
})
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
const
data
=
res
.
data
.
data
||
{};
state
.
authorizeFormData
.
system_version
=
data
.
version
;
state
.
authorizeFormData
.
license_dead_date
=
data
.
deadDate
;
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
const
{
authorizeRules
}
=
toRefs
(
state
);
</
script
>
src/page/main/system-admin/preference/index.vue
View file @
c11a241c
<
template
>
<
template
>
<div>
首选项配置
</div>
<div
class=
"page_container"
>
<bg-breadcrumb></bg-breadcrumb>
<div
class=
"parent_container"
>
<div
class=
"left_container bgc_white"
>
<el-menu
default-active=
"1"
@
select=
"switchMenu"
>
<el-menu-item
index=
"1"
>
<span>
license授权
</span>
</el-menu-item>
<el-menu-item
index=
"2"
>
<span>
登录页管理
</span>
</el-menu-item>
<el-menu-item
index=
"3"
>
<span>
安全相关
</span>
</el-menu-item>
<el-menu-item
index=
"4"
>
<span>
登录注册配置
</span>
</el-menu-item>
</el-menu>
</div>
<div
class=
"right_container bgc_white"
>
<!-- license授权表单 -->
<authorityForm
v-if=
"activeIndex == 1"
:authorizeFormData=
"authorizeFormData"
></authorityForm>
<loginPageForm
v-if=
"activeIndex == 2"
:loginPageFormData=
"loginPageFormData"
></loginPageForm>
<!-- 安全相关表单 -->
<secureForm
v-if=
"activeIndex == 3"
:secureFormData=
"secureFormData"
></secureForm>
<!-- 登录注册配置表单 -->
<registerForm
v-if=
"activeIndex == 4"
:registerFormData=
"registerFormData"
></registerForm>
<div
class=
"operate_btns"
>
<el-button
type=
"primary"
@
click=
"save"
>
保存
</el-button>
</div>
</div>
</div>
<el-dialog
class=
"dialog_box"
title=
"提示"
v-model=
"restoreDialog"
width=
"420px"
>
<div>
该操作将还原所有锁定账号和输错次数,是否继续?
</div>
<template
v-slot:footer
>
<div
class=
"apaas_button"
>
<el-button
type=
"default"
@
click=
"restoreDialog = false"
>
取 消
</el-button>
<el-button
type=
"primary"
@
click=
"confirm"
>
确 定
</el-button>
</div>
</
template
>
</el-dialog>
</div>
</template>
</template>
<
script
setup
></
script
>
<
script
setup
>
import
{
reactive
,
toRefs
,
onBeforeMount
,
ref
}
from
"
vue
"
;
import
bgBreadcrumb
from
"
@/components/bg-breadcrumb.vue
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
authorityForm
from
"
./authorityForm.vue
"
;
import
loginPageForm
from
"
./loginPageForm.vue
"
;
import
secureForm
from
"
./secureForm.vue
"
;
import
registerForm
from
"
./registerForm.vue
"
;
import
axios
from
"
@/request/http.js
"
;
const
authorizeFormRef
=
ref
(
null
);
const
secureFormRef
=
ref
(
null
);
const
registerFormRef
=
ref
(
null
);
const
state
=
reactive
({
//授权信息表单
authorizeFormData
:
{
id
:
""
,
system_version
:
""
,
system_user
:
""
,
license
:
""
,
license_dead_date
:
""
,
license_inform_day
:
""
,
},
//登录页表单
loginPageFormData
:
{
logoUrl
:
[],
backgroundUrl
:
[],
patent
:
""
,
icpFiling
:
""
,
icpUrl
:
""
,
publicSecurityFiling
:
""
,
publicSecurityUrl
:
""
,
legalStatementUrl
:
""
,
privacyPolicyUrl
:
""
,
},
//安全相关信息表单
secureFormData
:
{
id
:
""
,
min_pwd_level
:
""
,
force_update_state
:
0
,
pwd_validity
:
""
,
session_validity
:
""
,
access_rule_state
:
""
,
},
//登录注册配置表单
registerFormData
:
{
id
:
""
,
login_config_state
:
0
,
login_limit_time
:
""
,
login_pwd_error
:
""
,
login_lock_time
:
""
,
register_config_state
:
0
,
},
//选中项索引
activeIndex
:
1
,
restoreDialog
:
false
,
});
const
{
authorizeFormData
,
loginPageFormData
,
secureFormData
,
registerFormData
,
activeIndex
,
restoreDialog
}
=
toRefs
(
state
);
onBeforeMount
(()
=>
{
getPreferenceConfig
();
});
//切换菜单选项
const
switchMenu
=
(
index
)
=>
{
state
.
activeIndex
=
index
;
};
//获取首选项配置
const
getPreferenceConfig
=
()
=>
{
axios
.
get
(
"
/apaas/system/v5/sysOptions
"
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
let
data
=
res
.
data
.
data
;
Object
.
keys
(
state
.
authorizeFormData
).
forEach
((
item
)
=>
{
state
.
authorizeFormData
[
item
]
=
data
[
item
];
});
Object
.
keys
(
state
.
secureFormData
).
forEach
((
item
)
=>
{
state
.
secureFormData
[
item
]
=
data
[
item
];
});
Object
.
keys
(
state
.
registerFormData
).
forEach
((
item
)
=>
{
state
.
registerFormData
[
item
]
=
data
[
item
];
});
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
//保存表单项
const
save
=
()
=>
{
let
params
=
{};
if
(
state
.
activeIndex
==
1
)
{
authorizeFormRef
.
value
.
validate
((
valid
)
=>
{
if
(
valid
)
{
params
=
{
...
state
.
authorizeFormData
,
};
postData
(
"
/apaas/system/v5/sysOptions/licenseOpts
"
,
params
);
}
});
}
else
if
(
state
.
activeIndex
==
2
)
{
secureFormRef
.
value
.
validate
((
valid
)
=>
{
if
(
valid
)
{
params
=
{
...
state
.
secureFormData
,
};
postData
(
"
/apaas/system/v5/sysOptions/safeOpts
"
,
params
);
}
});
}
else
{
registerFormRef
.
value
.
validate
((
valid
)
=>
{
if
(
valid
)
{
params
=
{
...
state
.
registerFormData
,
};
if
(
params
.
login_config_state
==
0
)
{
params
.
login_limit_time
=
0
;
params
.
login_pwd_error
=
0
;
params
.
login_lock_time
=
0
;
}
postData
(
"
/apaas/system/v5/sysOptions/loginOpts
"
,
params
);
}
});
}
};
// 请求接口发送消息
const
postData
=
(
url
,
params
)
=>
{
axios
.
post
(
url
,
params
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
ElMessage
.
success
(
res
.
data
.
msg
);
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
const
confirm
=
()
=>
{
axios
.
post
(
`/apaas/system/v5/sysOptions/reStartConfig`
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
ElMessage
.
success
(
res
.
data
.
msg
);
state
.
restoreDialog
=
false
;
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
</
script
>
<
style
lang=
"scss"
scoped
>
.parent_container
{
display
:
flex
;
justify-content
:
space-between
;
height
:
calc
(
100%
-
46px
-
20px
);
.left_container
{
width
:
240px
;
height
:
100%
;
padding
:
24px
16px
0
;
.el-menu
{
border
:
none
;
.el-menu-item
{
justify-content
:
center
;
height
:
36px
;
color
:
#404a62
!
important
;
&
.is-active
,
&
:hover
{
background-color
:
#f2f3f7
;
border-radius
:
4px
;
}
}
}
}
.right_container
{
position
:
relative
;
width
:
calc
(
100%
-
250px
);
min-width
:
852px
;
height
:
100%
;
padding
:
32px
0
68px
24px
;
margin-left
:
16px
;
.authorizeForm
,
.secureForm
,
.registerForm
{
:deep
()
.el-form-item
{
margin-bottom
:
24px
;
width
:
54%
;
min-width
:
580px
;
font-size
:
14px
;
.el-form-item__label
,
.el-radio__label
{
color
:
var
(
--
el-text-color-primary
);
}
.el-select
{
width
:
100%
;
}
.el-input-group__append
{
width
:
60px
;
color
:
#404a62
;
border-radius
:
0
6px
6px
0
;
background
:
#f7f7f9
;
}
}
}
:deep
()
.secureForm
{
.passwordItem
{
display
:
flex
;
align-items
:
center
;
.el-form-item
:nth-of-type
(
1
)
{
flex-shrink
:
0
;
margin-right
:
56px
;
}
.el-form-item
:nth-of-type
(
2
)
{
min-width
:
auto
;
}
}
}
:deep
()
.registerForm
{
.input_password_config
{
position
:
relative
;
display
:
flex
;
align-items
:
center
;
width
:
798px
;
margin-bottom
:
24px
;
font-size
:
14px
;
color
:
var
(
--
el-text-color-primary
);
.el-form-item
{
margin
:
0px
8px
;
min-width
:
auto
;
&
:nth-of-type
(
1
),
&
:nth-of-type
(
3
)
{
flex
:
0
;
min-width
:
110px
;
width
:
120px
;
}
&
:nth-of-type
(
2
)
{
flex
:
0
;
min-width
:
140px
;
width
:
150px
;
}
}
.el-button
{
margin-left
:
18px
;
}
}
.el-radio
{
margin-right
:
54px
;
}
}
<
style
lang=
"scss"
scoped
></
style
>
.operate_btns
{
position
:
absolute
;
bottom
:
0
;
left
:
0
;
width
:
100%
;
height
:
68px
;
padding-right
:
16px
;
line-height
:
68px
;
text-align
:
right
;
border-top
:
solid
1px
#e6e9ef
;
.el-button
{
width
:
92px
;
}
}
}
}
</
style
>
src/page/main/system-admin/preference/loginPageForm.vue
0 → 100644
View file @
c11a241c
<
template
>
<div
class=
"form_content apaas_scroll_nor"
>
<el-form
ref=
"loginPageRef"
:model=
"loginPageFormData"
:rules=
"loginPageRules"
label-width=
"96px"
class=
"registerForm"
>
<el-form-item
label=
"LOGO"
prop=
"logoUrl"
>
<bg-upload-image
v-model=
"loginPageFormData.logoUrl"
:showTips=
"true"
customTips=
"请选择图片上传:支持jpg、png等格式,图片需小于500KB"
:fileSize=
"500"
:fileSizeUnit=
"'KB'"
:limit=
"1"
listType=
"picture-card"
@
change=
"changeLogo"
:accept=
"['.jpg', '.jpeg', '.png']"
></bg-upload-image>
</el-form-item>
<el-form-item
label=
"登录背景图"
prop=
"backgroundUrl"
>
<bg-upload-image
v-model=
"loginPageFormData.backgroundUrl"
:fileSize=
"2"
:showTips=
"true"
customTips=
"请选择图片上传:大小1920 * 1026像素支持jpg、png等格式,图片需小于2MB"
:limit=
"1"
listType=
"picture-card"
@
change=
"changeBanner"
:accept=
"['.jpg', '.jpeg', '.png']"
></bg-upload-image>
</el-form-item>
<bg-form-gap
title=
"底部所有权内容"
></bg-form-gap>
<el-form-item
label=
"内容"
prop=
"patent"
>
<el-input
v-model.trim=
"loginPageFormData.patent"
placeholder=
"例如:Copyright © 某某大数据, All Rights Reserved."
></el-input>
</el-form-item>
<bg-form-gap
title=
"底部ICP备案"
></bg-form-gap>
<el-form-item
label=
"内容"
prop=
"icpFiling"
>
<el-input
placeholder=
"请输入"
v-model.trim=
"loginPageFormData.icpFiling"
></el-input>
</el-form-item>
<el-form-item
label=
"跳转连接"
prop=
"icpUrl"
>
<el-input
placeholder=
"例如:https://...或http://..."
v-model.trim=
"loginPageFormData.icpUrl"
></el-input>
</el-form-item>
<bg-form-gap
title=
"底部公安网备案"
></bg-form-gap>
<el-form-item
label=
"内容"
prop=
"publicSecurityFiling"
>
<el-input
placeholder=
"请输入"
v-model.trim=
"loginPageFormData.publicSecurityFiling"
></el-input>
</el-form-item>
<el-form-item
label=
"跳转连接"
prop=
"publicSecurityUrl"
>
<el-input
placeholder=
"例如:https://...或http://..."
v-model.trim=
"loginPageFormData.publicSecurityUrl"
></el-input>
</el-form-item>
<bg-form-gap
title=
"法律声明"
></bg-form-gap>
<el-form-item
label=
"跳转连接"
prop=
"legalStatementUrl"
>
<el-input
placeholder=
"例如:https://...或http://..."
v-model.trim=
"loginPageFormData.legalStatementUrl"
></el-input>
</el-form-item>
<bg-form-gap
title=
"隐私政策"
></bg-form-gap>
<el-form-item
label=
"跳转连接"
prop=
"privacyPolicyUrl"
>
<el-input
placeholder=
"例如:https://...或http://..."
v-model.trim=
"loginPageFormData.privacyPolicyUrl"
></el-input>
</el-form-item>
</el-form>
</div>
</
template
>
<
script
setup
>
import
{
reactive
,
ref
,
toRefs
}
from
"
vue
"
;
import
{
validateLink
}
from
"
@/services/rules.js
"
;
const
props
=
defineProps
({
loginPageFormData
:
{
type
:
Object
,
default
:
()
=>
({}),
},
});
const
loginPageRef
=
ref
(
null
);
const
state
=
reactive
({
loginPageRules
:
{
logoUrl
:
[{
required
:
true
,
message
:
"
请上传Logo
"
,
trigger
:
"
change
"
}],
backgroundUrl
:
[{
required
:
true
,
message
:
"
请上传背景图
"
,
trigger
:
"
change
"
}],
icpUrl
:
[{
validator
:
validateLink
,
trigger
:
"
blur
"
}],
publicSecurityUrl
:
[{
validator
:
validateLink
,
trigger
:
"
blur
"
}],
legalStatementUrl
:
[{
validator
:
validateLink
,
trigger
:
"
blur
"
}],
privacyPolicyUrl
:
[{
validator
:
validateLink
,
trigger
:
"
blur
"
}],
},
});
const
changeLogo
=
(
value
)
=>
{
if
(
value
&&
value
.
length
>
0
)
{
loginPageRef
.
value
.
clearValidate
(
"
logoUrl
"
);
}
};
const
changeBanner
=
(
value
)
=>
{
if
(
value
&&
value
.
length
>
0
)
{
refForm
.
value
.
clearValidate
(
"
backgroundUrl
"
);
}
};
const
{
loginPageRules
}
=
toRefs
(
state
);
</
script
>
<
style
lang=
"scss"
scoped
>
.form_content
{
overflow
:
auto
;
height
:
100%
;
padding-left
:
24px
;
.el-form
{
width
:
60%
;
:deep
()
.el-form-item
{
&
:nth-of-type
(
1
)
{
.el-upload--picture-card
{
width
:
120px
;
height
:
120px
;
}
}
&
:nth-of-type
(
2
)
{
.el-upload--picture-card
{
width
:
367px
;
height
:
196px
;
}
}
}
}
:deep
()
.gap-title
{
font-size
:
16px
;
color
:
#202531
;
}
}
</
style
>
src/page/main/system-admin/preference/registerForm.vue
0 → 100644
View file @
c11a241c
<
template
>
<el-form
ref=
"registerFormRef"
:model=
"registerFormData"
:rules=
"registerRules"
label-width=
"125px"
class=
"registerForm"
>
<bg-form-gap
title=
"登录受限配置"
></bg-form-gap>
<el-form-item
label=
"登录受限是否启用"
prop=
"login_config_state"
>
<bg-switch
:labels=
"['否', '是']"
:values=
"[0, 1]"
v-model=
"registerFormData.login_config_state"
></bg-switch>
</el-form-item>
<div
class=
"input_password_config"
v-if=
"registerFormData.login_config_state == 1"
>
<span>
在
</span>
<el-form-item
prop=
"login_limit_time"
label-width=
"0"
>
<el-input
placeholder=
"请输入小时数"
v-model.trim.number=
"registerFormData.login_limit_time"
maxlength=
"3"
></el-input>
</el-form-item>
<span>
小时内
</span>
<el-form-item
prop=
"login_pwd_error"
label-width=
"0"
>
<el-input
placeholder=
"请输入密码输错次数"
v-model.trim.number=
"registerFormData.login_pwd_error"
maxlength=
"3"
></el-input>
</el-form-item>
<span>
次输错密码,自动锁定
</span>
<el-form-item
prop=
"login_lock_time"
label-width=
"0"
>
<el-input
placeholder=
"请输入分钟数"
v-model.trim.number=
"registerFormData.login_lock_time"
maxlength=
"3"
></el-input>
</el-form-item>
<span>
分钟
</span>
<el-button
type=
"primary"
@
click=
"restoreDialog = true"
>
一键还原受限
</el-button>
<el-tooltip
placement=
"top-start"
effect=
"light"
>
<template
#content
>
<span>
必须为大于0的正整数且不能为空
</span>
<br
/>
<span>
一键还原按钮将所有锁定的账号解锁并将输错次数还原
</span>
</
template
>
<div
class=
"tip-image"
></div>
</el-tooltip>
</div>
<bg-form-gap
title=
"注册配置"
></bg-form-gap>
<el-form-item
label=
"允许注册"
prop=
"register_config_state"
>
<el-radio-group
v-model=
"registerFormData.register_config_state"
>
<el-radio
:label=
"1"
>
是
</el-radio>
<el-radio
:label=
"0"
>
否
</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
</template>
<
script
setup
>
import
{
reactive
,
toRefs
}
from
"
vue
"
;
const
props
=
defineProps
({
registerFormData
:
{
type
:
Object
,
default
:
()
=>
({}),
},
});
const
state
=
reactive
({
registerRules
:
{
login_limit_time
:
[
{
type
:
"
number
"
,
min
:
1
,
message
:
"
请输入正整数
"
,
trigger
:
"
blur
"
,
},
],
login_pwd_error
:
[
{
type
:
"
number
"
,
min
:
1
,
message
:
"
请输入正整数
"
,
trigger
:
"
blur
"
,
},
],
login_lock_time
:
[
{
type
:
"
number
"
,
min
:
1
,
message
:
"
请输入正整数
"
,
trigger
:
"
blur
"
,
},
],
},
});
const
{
registerRules
}
=
toRefs
(
state
);
</
script
>
src/page/main/system-admin/preference/secureForm.vue
0 → 100644
View file @
c11a241c
<
template
>
<el-form
ref=
"secureFormRef"
:model=
"secureFormData"
:rules=
"secureRules"
label-width=
"110px"
class=
"secureForm"
>
<div
class=
"passwordItem"
>
<el-form-item
label=
"最低密码强度"
prop=
"min_pwd_level"
>
<el-select
v-model=
"secureFormData.min_pwd_level"
placeholder=
"请选择"
>
<el-option
label=
"弱"
:value=
"1"
/>
<el-option
label=
"中"
:value=
"2"
/>
<el-option
label=
"强"
:value=
"3"
/>
</el-select>
<el-tooltip
placement=
"top-start"
effect=
"light"
>
<template
#content
>
<span>
支持大写字母/小写字符/数字/特殊符号
</span>
<br
/>
<span>
密码长度应至少8位字符
</span>
<br
/>
<span>
弱:至少包含一种组合。
</span>
<br
/>
<span>
中:至少包含两种组合。
</span>
<br
/>
<span>
强:至少包含三种及以上组合。
</span>
</
template
>
<div
class=
"tip-image"
></div>
</el-tooltip>
</el-form-item>
<el-form-item
label=
"是否强制修改"
prop=
"force_update_state"
>
<bg-switch
:labels=
"['否', '是']"
:values=
"[0, 1]"
v-model=
"secureFormData.force_update_state"
></bg-switch>
</el-form-item>
</div>
<el-form-item
label=
"密码有效期"
prop=
"pwd_validity"
>
<el-input
placeholder=
"请输入"
v-model.trim.number=
"secureFormData.pwd_validity"
maxlength=
"3"
>
<
template
#append
>
天
</
template
>
</el-input>
<el-tooltip
placement=
"top-start"
effect=
"light"
>
<
template
#content
>
<span>
单位,天
</span>
<br
/>
<span>
密码有效期是指强制修改密码的周期,例如60天表示用户需要每60天修改一次密码。
</span>
<br
/>
<span>
若配置为0,表示密码有效期为永久
</span>
</
template
>
<div
class=
"tip-image"
></div>
</el-tooltip>
</el-form-item>
<el-form-item
label=
"会话有效期"
prop=
"session_validity"
>
<el-input
placeholder=
"请输入"
v-model.trim.number=
"secureFormData.session_validity"
>
<
template
#append
>
分钟
</
template
>
</el-input>
<el-tooltip
placement=
"top-start"
effect=
"light"
>
<
template
#content
>
<span>
{{
`范围(10~${session_validity_max
}
)`
}}
<
/span
>
<
br
/>
<
span
>
单位,分钟
<
/span
>
<
br
/>
<
span
>
会话有效期是指您登录后,一定时间内无操作,系统将自动登出
<
/span
>
<
/template
>
<
div
class
=
"
tip-image
"
><
/div
>
<
/el-tooltip
>
<
/el-form-item
>
<
el
-
form
-
item
label
=
"
访问规则模式
"
prop
=
"
access_rule_state
"
>
<
el
-
select
placeholder
=
"
请选择
"
v
-
model
=
"
secureFormData.access_rule_state
"
>
<
el
-
option
label
=
"
关闭
"
:
value
=
"
0
"
>
<
/el-option
>
<
el
-
option
label
=
"
打开
"
:
value
=
"
1
"
>
<
/el-option
>
<
/el-select
>
<
el
-
tooltip
placement
=
"
top-start
"
effect
=
"
light
"
>
<
template
#
content
>
<
span
>
访问规则模式开启后,按照【访问规则管理】配置执行。
<
/span
>
<
br
/>
<
span
>
该模式针对超管无效
<
/span
>
<
/template
>
<
div
class
=
"
tip-image
"
><
/div
>
<
/el-tooltip
>
<
/el-form-item
>
<
/el-form
>
<
/template
>
<
script
setup
>
import
{
reactive
,
toRefs
}
from
"
vue
"
;
const
props
=
defineProps
({
secureFormData
:
{
type
:
Object
,
default
:
()
=>
({
}
),
}
,
}
);
const
session_validity_max
=
window
.
defaultConfig
.
session_validity_max
;
const
state
=
reactive
({
//安全相关表单校验规则
secureRules
:
{
pwd_validity
:
[
{
type
:
"
number
"
,
message
:
"
请输入大于或等于0的整数
"
,
trigger
:
"
blur
"
,
}
,
],
session_validity
:
[
{
type
:
"
number
"
,
min
:
10
,
max
:
session_validity_max
,
message
:
`请输入10~${session_validity_max
}
的整数`
,
trigger
:
"
blur
"
,
}
,
],
}
,
}
);
const
{
secureRules
}
=
toRefs
(
state
);
<
/script
>
src/page/main/system-admin/visit-control/add/index.vue
0 → 100644
View file @
c11a241c
<!-- 角色管理 -->
<
template
>
<div
class=
"page_container"
>
<bg-breadcrumb></bg-breadcrumb>
<div
class=
"main_container"
>
<div
class=
"form_content apaas_scroll_nor"
>
<el-form
ref=
"refForm"
label-position=
"left"
:model=
"formData"
:rules=
"rules"
label-width=
"82px"
>
<div
class=
"top_content"
>
<el-form-item
label=
"规则名称"
prop=
"ruleName"
>
<el-input
placeholder=
"请输入"
maxlength=
"100"
v-model=
"formData.ruleName"
></el-input>
</el-form-item>
<el-form-item
label=
"规则类型"
prop=
"ruleType"
>
<el-select
placeholder=
"请选择"
style=
"width: 100%"
v-model=
"formData.ruleType"
>
<el-option
label=
"IP"
:value=
"1"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item
label=
"规则"
prop=
"ruleDetail"
>
<el-input
placeholder=
"请输入"
rows=
"5"
maxlength=
"300"
show-word-limit
type=
"textarea"
v-model=
"formData.ruleDetail"
/>
<el-tooltip
placement=
"top-start"
effect=
"light"
>
<template
#content
>
<span>
输入IP段,不可重复,例如:192.168.0.0/24
</span><br
/>
<span
>
输入IP地址,例如192.168.0.1(支持ipv4地址,配置多个IP时使用回车符分隔)
</span
>
</
template
>
<div
class=
"tip-image"
></div>
</el-tooltip>
</el-form-item>
<el-form-item
class=
"switch-item"
label=
"是否启用"
prop=
"state"
required
>
<bg-switch
:labels=
"['否', '是']"
:values=
"[0, 1]"
v-model=
"formData.state"
></bg-switch>
</el-form-item>
</div>
<el-form-item
class=
"userScope"
label=
"用户范围"
prop=
"userScope"
>
<el-button
type=
"primary"
@
click=
"userMaintain"
>
用户维护
</el-button>
<div
class=
"table_content clearfix"
>
<bg-table
ref=
"bgTable"
:headers=
"detailHeaders"
:rows=
"tableRows"
height=
"550"
:stripe=
"true"
>
<
template
v-slot:isAdmin=
"{ row }"
>
<span>
{{
userTypeConfig
[
row
.
isAdmin
]
}}
</span>
</
template
>
</bg-table>
<bg-pagination
:page=
"pageConfig.page"
:size=
"pageConfig.limit"
:total=
"pageConfig.total"
@
change-page=
"changePage"
@
change-size=
"changeSize"
>
</bg-pagination>
</div>
</el-form-item>
</el-form>
<el-dialog
class=
"dialog_box_maintain"
title=
"用户维护"
v-model=
"dialogMaintain"
width=
"1062px"
>
<div
class=
"content_detail"
>
<div
class=
"form_filter"
>
<div
class=
"left"
>
<span
class=
"sleceted_tip"
>
已选择
<span
class=
"num"
>
{{ selectedNum }}
</span
>
项
</span
>
<span
class=
"clean"
@
click=
"cleanSelected"
>
清空
</span>
</div>
<div
class=
"right"
>
<el-select
placeholder=
"全部类型"
v-model=
"dialogFilterData.isAdmin"
style=
"width: 200px; margin-left: 16px"
>
<el-option
v-for=
"option in userTypeList"
:key=
"option.value"
:label=
"option.label"
:value=
"option.value"
>
</el-option>
</el-select>
<el-tree-select
style=
"width: 200px; margin-left: 16px"
placeholder=
"请选择所属组织"
v-model=
"dialogFilterData.organizationId"
:data=
"orgData"
:props=
"treeProps"
:render-after-expand=
"false"
></el-tree-select>
<el-input
placeholder=
"请输入关键词"
v-model=
"dialogFilterData.search"
style=
"width: 200px; margin: 0 16px 0"
:prefix-icon=
"Search"
/>
<el-button
type=
"primary"
@
click=
"dialogChangePage(1)"
>
查询
</el-button>
<el-button
type=
"default"
@
click=
"resetFilter"
>
重置
</el-button>
</div>
</div>
<div
class=
"table_content clearfix"
>
<bg-table
ref=
"dialogBgTable"
height=
"430"
select
rowKey=
"systemId"
:headers=
"detailHeaders"
:rows=
"dialogTableRows"
:stripe=
"true"
@
selectAc=
"selectChange"
>
<
template
v-slot:isAdmin=
"{ row }"
>
<span>
{{
userTypeConfig
[
row
.
isAdmin
]
}}
</span>
</
template
>
</bg-table>
<bg-pagination
:page=
"dialogPageConfig.page"
:size=
"dialogPageConfig.limit"
:total=
"dialogPageConfig.total"
@
change-page=
"dialogChangePage"
@
change-size=
"dialogChangeSize"
>
</bg-pagination>
</div>
<div
class=
"operate_btns"
style=
"border-top: none"
>
<el-button
@
click=
"dialogMaintain = false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"save"
>
保存
</el-button>
</div>
</div>
</el-dialog>
</div>
<div
class=
"operate_btns"
>
<el-button
type=
"primary"
@
click=
"submit"
>
保存
</el-button>
</div>
</div>
</div>
</template>
<
script
setup
>
import
{
Search
}
from
"
@element-plus/icons-vue
"
;
import
{
reactive
,
toRefs
,
computed
,
ref
,
onBeforeMount
,
nextTick
}
from
"
vue
"
;
import
{
useRouter
}
from
"
vue-router
"
;
import
{
useStore
}
from
"
vuex
"
;
import
axios
from
"
../../../../../request/http.js
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
bgBreadcrumb
from
"
@/components/bg-breadcrumb.vue
"
;
const
router
=
useRouter
();
const
{
getters
}
=
useStore
();
const
userTypeConfig
=
computed
(()
=>
getters
.
getUserTypeConfig
||
{});
const
userTypeList
=
computed
(()
=>
Object
.
keys
(
userTypeConfig
.
value
).
map
((
key
)
=>
({
label
:
userTypeConfig
.
value
[
key
],
value
:
+
key
,
}))
);
const
dialogBgTable
=
ref
(
null
);
const
state
=
reactive
({
//表单数据
formData
:
{
ruleName
:
""
,
ruleType
:
""
,
ruleDetail
:
""
,
state
:
0
,
userScope
:
[],
},
//表单校验规则
rules
:
{
ruleName
:
[
{
required
:
true
,
message
:
"
请输入
"
,
trigger
:
"
blur
"
,
},
],
ruleType
:
[
{
required
:
true
,
message
:
"
请选择
"
,
trigger
:
"
blur
"
,
},
],
ruleDetail
:
[
{
required
:
true
,
message
:
"
请输入
"
,
trigger
:
"
blur
"
,
},
],
userScope
:
[
{
required
:
true
,
message
:
"
请选择
"
,
blur
:
"
change
"
,
},
],
},
dialogFilterData
:
{
isAdmin
:
""
,
organizationId
:
""
,
search
:
""
,
},
pageConfig
:
{
page
:
1
,
limit
:
10
,
total
:
0
,
},
//弹框中表格分页配置项
dialogPageConfig
:
{
page
:
1
,
limit
:
10
,
total
:
0
,
},
//表格数据
tableRows
:
[],
//被选中的所有数据
selectedRows
:
{},
//弹框中表格数据
dialogTableRows
:
[],
//已选择数据条数
selectedNum
:
0
,
detailHeaders
:
[
{
label
:
"
账号
"
,
prop
:
"
systemAccount
"
,
// minWidth: 280,
},
{
label
:
"
类型
"
,
prop
:
"
isAdmin
"
,
// minWidth: 360,
},
{
label
:
"
用户手机号
"
,
prop
:
"
phone
"
,
// width: 200,
},
{
label
:
"
所属组织
"
,
prop
:
"
name
"
,
// width: 120,
},
],
orgData
:
[],
treeProps
:
{
label
:
"
name
"
,
children
:
"
Child
"
,
value
:
"
organization_id
"
,
},
//用户维护弹框
dialogMaintain
:
false
,
});
const
{
formData
,
rules
,
dialogFilterData
,
pageConfig
,
dialogPageConfig
,
tableRows
,
dialogTableRows
,
selectedNum
,
detailHeaders
,
orgData
,
treeProps
,
dialogMaintain
,
}
=
toRefs
(
state
);
onBeforeMount
(()
=>
{
getOrgTree
();
getTableList
();
});
//用户维护
const
userMaintain
=
()
=>
{
state
.
dialogMaintain
=
true
;
};
//获取所属组织级联数据
const
getOrgTree
=
()
=>
{
axios
.
get
(
`/apaas/system/v5/org/tree`
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
const
orgDataTemp
=
res
.
data
.
data
||
[];
state
.
orgData
=
orgDataTemp
;
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
const
changePage
=
(
page
)
=>
{
state
.
pageConfig
.
page
=
page
;
state
.
tableRows
=
state
.
selectedRows
.
slice
(
(
page
-
1
)
*
state
.
pageConfig
.
limit
,
page
*
state
.
pageConfig
.
limit
);
};
const
changeSize
=
(
size
)
=>
{
state
.
pageConfig
.
limit
=
size
;
changePage
(
1
);
};
const
dialogChangePage
=
(
page
)
=>
{
state
.
dialogPageConfig
.
page
=
page
;
getTableList
();
};
const
dialogChangeSize
=
(
size
)
=>
{
state
.
dialogPageConfig
.
limit
=
size
;
dialogChangePage
(
1
);
};
//获取用户维护数据
const
getTableList
=
()
=>
{
const
params
=
{
limit
:
state
.
dialogPageConfig
.
limit
,
page
:
state
.
dialogPageConfig
.
page
,
disp
:
1
,
...
state
.
dialogFilterData
,
};
axios
.
get
(
"
/apaas/system/v5/accessRule/listRuleUser
"
,
{
params
}).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
state
.
dialogTableRows
=
res
.
data
.
data
||
[];
state
.
dialogPageConfig
.
total
=
res
.
data
.
total
||
0
;
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
//重置查询参数
const
resetFilter
=
()
=>
{
Object
.
keys
(
state
.
dialogFilterData
).
forEach
((
key
)
=>
{
state
.
dialogFilterData
[
key
]
=
""
;
});
dialogChangePage
(
1
);
};
//用户维护弹框中清空
const
cleanSelected
=
()
=>
{
dialogBgTable
.
value
.
clearTable
();
};
//用户维护选择项发生变化
const
selectChange
=
(
params
)
=>
{
state
.
selectedNum
=
params
.
allLength
;
};
//保存
const
save
=
()
=>
{
state
.
dialogMaintain
=
false
;
const
res
=
dialogBgTable
.
value
.
dealSelectData
();
state
.
selectedRows
=
Object
.
values
(
res
);
state
.
formData
.
userScope
=
state
.
selectedRows
.
map
((
item
)
=>
({
systemId
:
item
.
systemId
,
}));
state
.
pageConfig
.
total
=
state
.
formData
.
userScope
.
length
;
changePage
(
1
);
};
//提交
const
submit
=
()
=>
{
axios
.
post
(
"
/apaas/system/v5/accessRule/addAccessRule
"
,
state
.
formData
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
ElMessage
.
success
(
"
添加成功
"
);
router
.
push
(
"
/config/accessRule
"
);
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
</
script
>
<
style
lang=
"scss"
scoped
>
.page_container
{
.main_container
{
position
:
relative
;
margin
:
0
0
16px
;
width
:
100%
;
height
:
calc
(
100%
-
62px
);
padding
:
40px
0
70px
;
overflow
:
auto
;
background-color
:
#fff
;
box-shadow
:
0px
1px
4px
0px
rgba
(
0
,
7
,
101
,
0
.15
);
border-radius
:
6px
;
.form_content
{
overflow
:
auto
;
height
:
100%
;
padding-left
:
40px
;
.el-form
{
::v-deep
.el-form-item
{
display
:
block
;
margin-bottom
:
24px
;
width
:
60%
;
.el-form-item__label
{
display
:
block
;
margin-bottom
:
6px
;
height
:
14px
;
line-height
:
14px
;
}
&
.switch-item
{
display
:
flex
;
align-items
:
center
;
.el-form-item__label
{
display
:
inline-flex
;
margin-bottom
:
0px
;
}
.el-switch
{
height
:
24px
;
}
}
&
.userScope
{
width
:
100%
;
margin-bottom
:
16px
;
.el-button
{
width
:
92px
;
}
.el-form-item__label
{
margin-bottom
:
16px
;
}
.el-form-item__content
{
display
:
block
;
}
.table_content
{
padding-right
:
40px
;
margin-top
:
16px
;
}
}
}
}
}
::v-deep
.dialog_box_maintain
{
.el-dialog__body
{
padding
:
0
0
70px
0
;
height
:
630px
;
}
.form_filter
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
margin-bottom
:
8px
;
height
:
69px
;
border-bottom
:
1px
solid
#e6e9ef
;
.left
{
font-size
:
0px
;
.sleceted_tip
{
margin
:
0
24px
0
;
vertical-align
:
middle
;
font-size
:
14px
;
color
:
#404a62
;
.num
{
margin
:
0
3px
0
3px
;
font-weight
:
600
;
color
:
#202531
;
}
}
.clean
{
vertical-align
:
middle
;
font-size
:
14px
;
color
:
#3759be
;
cursor
:
pointer
;
}
}
.right
{
margin-right
:
16px
;
.el-button
{
width
:
64px
;
&
:last-child
{
margin-left
:
16px
;
}
}
}
}
.table_content
{
padding
:
0
16px
;
}
.operate_btns
{
.el-button
{
width
:
64px
;
&
:first-child
{
margin-right
:
4px
;
}
}
}
}
.operate_btns
{
position
:
absolute
;
bottom
:
0
;
width
:
100%
;
height
:
70px
;
text-align
:
right
;
line-height
:
68px
;
border-top
:
solid
1px
#e6e9ef
;
.el-button
{
width
:
92px
;
margin-right
:
16px
;
}
}
}
}
</
style
>
src/page/main/system-admin/visit-control/edit/index.vue
0 → 100644
View file @
c11a241c
<!-- 角色管理 -->
<
template
>
<div
class=
"page_container"
>
<bg-breadcrumb></bg-breadcrumb>
<div
class=
"main_container"
>
<div
class=
"form_content apaas_scroll_nor"
>
<el-form
ref=
"refForm"
label-position=
"left"
:model=
"formData"
:rules=
"rules"
label-width=
"82px"
>
<div
class=
"top_content"
>
<el-form-item
label=
"规则名称"
prop=
"ruleName"
>
<el-input
placeholder=
"请输入"
maxlength=
"100"
v-model=
"formData.ruleName"
></el-input>
</el-form-item>
<el-form-item
label=
"规则类型"
prop=
"ruleType"
>
<el-select
placeholder=
"请选择"
style=
"width: 100%"
v-model=
"formData.ruleType"
>
<el-option
label=
"IP"
:value=
"1"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item
label=
"规则"
prop=
"ruleDetail"
>
<el-input
placeholder=
"请输入"
rows=
"5"
maxlength=
"300"
show-word-limit
type=
"textarea"
v-model=
"formData.ruleDetail"
/>
<el-tooltip
placement=
"top-start"
effect=
"light"
>
<template
#content
>
<span>
输入IP段,不可重复,例如:192.168.0.0/24
</span><br
/>
<span
>
输入IP地址,例如192.168.0.1(支持ipv4地址,配置多个IP时使用回车符分隔)
</span
>
</
template
>
<div
class=
"tip-image"
></div>
</el-tooltip>
</el-form-item>
<el-form-item
class=
"switch-item"
label=
"是否启用"
prop=
"state"
required
>
<bg-switch
:labels=
"['否', '是']"
:values=
"[0, 1]"
v-model=
"formData.state"
></bg-switch>
</el-form-item>
</div>
<el-form-item
class=
"userScope"
label=
"用户范围"
prop=
"userScope"
>
<el-button
type=
"primary"
@
click=
"userMaintain"
>
用户维护
</el-button>
<div
class=
"table_content clearfix"
>
<bg-table
ref=
"bgTable"
:headers=
"detailHeaders"
:rows=
"tableRows"
height=
"550"
:stripe=
"true"
>
<
template
v-slot:isAdmin=
"{ row }"
>
<span>
{{
userTypeConfig
[
row
.
isAdmin
]
}}
</span>
</
template
>
</bg-table>
<bg-pagination
:page=
"pageConfig.page"
:size=
"pageConfig.limit"
:total=
"pageConfig.total"
@
change-page=
"changePage"
@
change-size=
"changeSize"
>
</bg-pagination>
</div>
</el-form-item>
</el-form>
<el-dialog
class=
"dialog_box_maintain"
title=
"用户维护"
v-model=
"dialogMaintain"
width=
"1062px"
>
<div
class=
"content_detail"
>
<div
class=
"form_filter"
>
<div
class=
"left"
>
<span
class=
"sleceted_tip"
>
已选择
<span
class=
"num"
>
{{ selectedNum }}
</span
>
项
</span
>
<span
class=
"clean"
@
click=
"cleanSelected"
>
清空
</span>
</div>
<div
class=
"right"
>
<el-select
placeholder=
"全部类型"
v-model=
"dialogFilterData.isAdmin"
style=
"width: 200px; margin-left: 16px"
>
<el-option
v-for=
"option in userTypeList"
:key=
"option.value"
:label=
"option.label"
:value=
"option.value"
>
</el-option>
</el-select>
<el-tree-select
style=
"width: 200px; margin-left: 16px"
placeholder=
"请选择所属组织"
v-model=
"dialogFilterData.organizationId"
:data=
"orgData"
:props=
"treeProps"
:render-after-expand=
"false"
></el-tree-select>
<el-input
placeholder=
"请输入关键词"
v-model=
"dialogFilterData.search"
style=
"width: 200px; margin: 0 16px 0"
:prefix-icon=
"Search"
/>
<el-button
type=
"primary"
@
click=
"dialogChangePage(1)"
>
查询
</el-button>
<el-button
type=
"default"
@
click=
"resetFilter"
>
重置
</el-button>
</div>
</div>
<div
class=
"table_content clearfix"
>
<bg-table
ref=
"dialogBgTable"
height=
"430"
select
rowKey=
"systemId"
:headers=
"detailHeaders"
:rows=
"dialogTableRows"
:originSelectedData=
"selectedRows"
:stripe=
"true"
@
selectAc=
"selectChange"
>
<
template
v-slot:isAdmin=
"{ row }"
>
<span>
{{
userTypeConfig
[
row
.
isAdmin
]
}}
</span>
</
template
>
</bg-table>
<bg-pagination
:page=
"dialogPageConfig.page"
:size=
"dialogPageConfig.limit"
:total=
"dialogPageConfig.total"
@
change-page=
"dialogChangePage"
@
change-size=
"dialogChangeSize"
>
</bg-pagination>
</div>
<div
class=
"operate_btns"
style=
"border-top: none"
>
<el-button
@
click=
"dialogMaintain = false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"save"
>
保存
</el-button>
</div>
</div>
</el-dialog>
</div>
<div
class=
"operate_btns"
>
<el-button
type=
"primary"
@
click=
"submit"
>
保存
</el-button>
</div>
</div>
</div>
</template>
<
script
setup
>
import
{
Search
}
from
"
@element-plus/icons-vue
"
;
import
{
reactive
,
toRefs
,
computed
,
ref
,
onBeforeMount
,
nextTick
}
from
"
vue
"
;
import
{
useRoute
,
useRouter
}
from
"
vue-router
"
;
import
{
useStore
}
from
"
vuex
"
;
import
axios
from
"
../../../../../request/http.js
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
bgBreadcrumb
from
"
@/components/bg-breadcrumb.vue
"
;
const
route
=
useRoute
();
const
router
=
useRouter
();
const
{
getters
}
=
useStore
();
const
userTypeConfig
=
computed
(()
=>
getters
.
getUserTypeConfig
||
{});
const
userTypeList
=
computed
(()
=>
Object
.
keys
(
userTypeConfig
.
value
).
map
((
key
)
=>
({
label
:
userTypeConfig
.
value
[
key
],
value
:
+
key
,
}))
);
const
dialogBgTable
=
ref
(
null
);
const
state
=
reactive
({
//表单数据
formData
:
{
ruleName
:
""
,
ruleType
:
""
,
ruleDetail
:
""
,
state
:
0
,
userScope
:
[],
},
//表单校验规则
rules
:
{
ruleName
:
[
{
required
:
true
,
message
:
"
请输入
"
,
trigger
:
"
blur
"
,
},
],
ruleType
:
[
{
required
:
true
,
message
:
"
请选择
"
,
trigger
:
"
blur
"
,
},
],
ruleDetail
:
[
{
required
:
true
,
message
:
"
请输入
"
,
trigger
:
"
blur
"
,
},
],
userScope
:
[
{
required
:
true
,
message
:
"
请选择
"
,
blur
:
"
change
"
,
},
],
},
dialogFilterData
:
{
isAdmin
:
""
,
organizationId
:
""
,
search
:
""
,
},
pageConfig
:
{
page
:
1
,
limit
:
10
,
total
:
0
,
},
//弹框中表格分页配置项
dialogPageConfig
:
{
page
:
1
,
limit
:
10
,
total
:
0
,
},
//表格数据
tableRows
:
[],
//被选中的所有数据
selectedRows
:
{},
//弹框中表格数据
dialogTableRows
:
[],
//已选择数据条数
selectedNum
:
0
,
detailHeaders
:
[
{
label
:
"
账号
"
,
prop
:
"
systemAccount
"
,
// minWidth: 280,
},
{
label
:
"
类型
"
,
prop
:
"
isAdmin
"
,
// minWidth: 360,
},
{
label
:
"
用户手机号
"
,
prop
:
"
phone
"
,
// width: 200,
},
{
label
:
"
所属组织
"
,
prop
:
"
name
"
,
// width: 120,
},
],
orgData
:
[],
treeProps
:
{
label
:
"
name
"
,
children
:
"
Child
"
,
value
:
"
organization_id
"
,
},
//用户维护弹框
dialogMaintain
:
false
,
});
const
{
formData
,
rules
,
dialogFilterData
,
pageConfig
,
dialogPageConfig
,
tableRows
,
selectedRows
,
dialogTableRows
,
selectedNum
,
detailHeaders
,
orgData
,
treeProps
,
dialogMaintain
,
}
=
toRefs
(
state
);
onBeforeMount
(()
=>
{
echoFormData
();
getOrgTree
();
getTableList
();
});
//回显编辑数据
const
echoFormData
=
()
=>
{
const
query
=
route
.
query
;
getUserScopeList
();
state
.
formData
.
ruleName
=
query
.
ruleName
;
state
.
formData
.
state
=
+
query
.
state
;
state
.
formData
.
ruleType
=
+
query
.
ruleType
;
state
.
formData
.
ruleDetail
=
query
.
ruleDetail
;
};
//用户维护
const
userMaintain
=
()
=>
{
state
.
dialogMaintain
=
true
;
};
//获取所属组织级联数据
const
getOrgTree
=
()
=>
{
axios
.
get
(
`/apaas/system/v5/org/tree`
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
const
orgDataTemp
=
res
.
data
.
data
||
[];
state
.
orgData
=
orgDataTemp
;
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
const
changePage
=
(
page
)
=>
{
state
.
pageConfig
.
page
=
page
;
state
.
tableRows
=
state
.
selectedRows
.
slice
(
(
page
-
1
)
*
state
.
pageConfig
.
limit
,
page
*
state
.
pageConfig
.
limit
);
};
const
changeSize
=
(
size
)
=>
{
state
.
pageConfig
.
limit
=
size
;
changePage
(
1
);
};
const
dialogChangePage
=
(
page
)
=>
{
state
.
dialogPageConfig
.
page
=
page
;
getTableList
();
};
const
dialogChangeSize
=
(
size
)
=>
{
state
.
dialogPageConfig
.
limit
=
size
;
dialogChangePage
(
1
);
};
//编辑时回显用户范围数据
const
getUserScopeList
=
()
=>
{
const
params
=
{
limit
:
10000
,
page
:
1
,
id
:
route
.
query
.
id
,
disp
:
0
,
};
axios
.
get
(
"
/apaas/system/v5/accessRule/listRuleUser
"
,
{
params
}).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
state
.
selectedRows
=
res
.
data
.
data
||
[];
state
.
pageConfig
.
total
=
state
.
selectedRows
.
length
;
state
.
selectedNum
=
state
.
selectedRows
.
length
;
changePage
(
1
);
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
//获取用户维护数据
const
getTableList
=
()
=>
{
const
params
=
{
limit
:
state
.
dialogPageConfig
.
limit
,
page
:
state
.
dialogPageConfig
.
page
,
disp
:
1
,
...
state
.
dialogFilterData
,
};
axios
.
get
(
"
/apaas/system/v5/accessRule/listRuleUser
"
,
{
params
}).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
state
.
dialogTableRows
=
res
.
data
.
data
||
[];
state
.
dialogPageConfig
.
total
=
res
.
data
.
total
||
0
;
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
//重置查询参数
const
resetFilter
=
()
=>
{
Object
.
keys
(
state
.
dialogFilterData
).
forEach
((
key
)
=>
{
state
.
dialogFilterData
[
key
]
=
""
;
});
dialogChangePage
(
1
);
};
//用户维护弹框中清空
const
cleanSelected
=
()
=>
{
dialogBgTable
.
value
.
clearTable
();
};
//用户维护选择项发生变化
const
selectChange
=
(
params
)
=>
{
state
.
selectedNum
=
params
.
allLength
;
};
//保存
const
save
=
()
=>
{
state
.
dialogMaintain
=
false
;
const
res
=
dialogBgTable
.
value
.
dealSelectData
();
state
.
selectedRows
=
Object
.
values
(
res
);
state
.
formData
.
userScope
=
state
.
selectedRows
.
map
((
item
)
=>
({
systemId
:
item
.
systemId
,
}));
state
.
pageConfig
.
total
=
state
.
formData
.
userScope
.
length
;
changePage
(
1
);
};
//提交
const
submit
=
()
=>
{
const
params
=
{
ruleId
:
route
.
query
.
ruleId
,
...
state
.
formData
,
};
axios
.
put
(
"
/apaas/system/v5/accessRule/updateAccessRule
"
,
params
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
ElMessage
.
success
(
"
更新成功
"
);
router
.
push
(
"
/config/accessRule
"
);
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
</
script
>
<
style
lang=
"scss"
scoped
>
.page_container
{
.main_container
{
position
:
relative
;
margin
:
0
0
16px
;
width
:
100%
;
height
:
calc
(
100%
-
62px
);
padding
:
40px
0
70px
;
overflow
:
auto
;
background-color
:
#fff
;
box-shadow
:
0px
1px
4px
0px
rgba
(
0
,
7
,
101
,
0
.15
);
border-radius
:
6px
;
.form_content
{
overflow
:
auto
;
height
:
100%
;
padding-left
:
40px
;
.el-form
{
::v-deep
.el-form-item
{
display
:
block
;
margin-bottom
:
24px
;
width
:
60%
;
.el-form-item__label
{
display
:
block
;
margin-bottom
:
6px
;
height
:
14px
;
line-height
:
14px
;
}
&
.switch-item
{
display
:
flex
;
align-items
:
center
;
.el-form-item__label
{
display
:
inline-flex
;
margin-bottom
:
0px
;
}
.el-switch
{
height
:
24px
;
}
}
&
.userScope
{
width
:
100%
;
margin-bottom
:
16px
;
.el-button
{
width
:
92px
;
}
.el-form-item__label
{
margin-bottom
:
16px
;
}
.el-form-item__content
{
display
:
block
;
}
.table_content
{
padding-right
:
40px
;
margin-top
:
16px
;
}
}
}
}
}
::v-deep
.dialog_box_maintain
{
.el-dialog__body
{
padding
:
0
0
70px
0
;
height
:
630px
;
}
.form_filter
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
margin-bottom
:
8px
;
height
:
69px
;
border-bottom
:
1px
solid
#e6e9ef
;
.left
{
font-size
:
0px
;
.sleceted_tip
{
margin
:
0
24px
0
;
vertical-align
:
middle
;
font-size
:
14px
;
color
:
#404a62
;
.num
{
margin
:
0
3px
0
3px
;
font-weight
:
600
;
color
:
#202531
;
}
}
.clean
{
vertical-align
:
middle
;
font-size
:
14px
;
color
:
#3759be
;
cursor
:
pointer
;
}
}
.right
{
margin-right
:
16px
;
.el-button
{
width
:
64px
;
&
:last-child
{
margin-left
:
16px
;
}
}
}
}
.table_content
{
padding
:
0
16px
;
}
.operate_btns
{
.el-button
{
width
:
64px
;
&
:first-child
{
margin-right
:
4px
;
}
}
}
}
.operate_btns
{
position
:
absolute
;
bottom
:
0
;
width
:
100%
;
height
:
70px
;
text-align
:
right
;
line-height
:
68px
;
border-top
:
solid
1px
#e6e9ef
;
.el-button
{
width
:
92px
;
margin-right
:
16px
;
}
}
}
}
</
style
>
src/page/main/system-admin/visit-control/index.vue
View file @
c11a241c
<
template
>
<
template
>
<div>
访问控制管理
</div>
<div
class=
"page_container"
>
<bg-breadcrumb></bg-breadcrumb>
<div
class=
"main_container"
>
<bg-filter-group
@
search=
"changeSearch"
v-model=
"filter.search"
placeholder=
"请输入规则名称或规则"
>
<template
v-slot:left_action
>
<div
class=
"apaas_button"
>
<el-button
type=
"primary"
@
click=
"addRule"
>
<bg-icon
style=
"font-size: 12px; color: #fff; margin-right: 8px"
icon=
"#bg-ic-add"
></bg-icon>
新增
</el-button>
<el-button
@
click=
"openDeleteDialog(2)"
>
批量删除
</el-button>
<span
class=
"sleceted_tip"
>
已选
<span
class=
"num"
>
{{
selectedNum
}}
</span
>
项
</span
>
<span
class=
"clean"
@
click=
"cleanSelected"
>
清空
</span>
</div>
</
template
>
<
template
v-slot:filter_group
>
<div
class=
"left-filter filter_list"
>
<div
class=
"filter_item"
>
<span
class=
"filter_title"
>
修改时间
</span>
<el-date-picker
v-model=
"filter.time"
type=
"daterange"
range-separator=
"至"
start-placeholder=
"开始日期"
end-placeholder=
"结束日期"
value-format=
"YYYY-MM-DD"
style=
"width: 300px"
/>
</div>
</div>
<div
class=
"right-action apaas_button"
>
<el-button
type=
"primary"
@
click=
"filterAction"
>
查询
</el-button>
<el-button
type=
"default"
@
click=
"filterClear"
>
重置
</el-button>
</div>
</
template
>
</bg-filter-group>
<div
class=
"table_container"
>
<bg-table
ref=
"rulesTable"
:headers=
"headers"
:rows=
"tableRows"
:stripe=
"true"
select
@
selectAc=
"selectRows"
canEdit
canEditFlag=
"state"
>
<
template
v-slot:rule_type=
"{ row }"
>
<span>
{{
[
""
,
"
IP
"
][
row
.
rule_type
]
}}
</span>
</
template
>
<
template
v-slot:num_user=
"{ row }"
>
<span
class=
"can_click_text under_line"
@
click=
"openUserDialog(row)"
>
{{
row
.
num_user
}}
</span>
</
template
>
<
template
v-slot:state=
"{ row }"
>
<bg-switch
@
click=
"stateChange(row)"
:labels=
"['否', '是']"
:values=
"[0, 1]"
v-model=
"row.state"
></bg-switch>
</
template
>
<
template
v-slot:updated_time=
"{ row }"
>
<span>
{{
dateStringTransform
(
row
.
updated_time
)
}}
</span>
</
template
>
<
template
v-slot:action=
"{ row }"
>
<bg-table-btns2
:limit=
"3"
:key=
"row.id"
>
<bg-table-btn
@
click=
"edit(row)"
>
编辑
</bg-table-btn>
<bg-table-btn
:disabled=
"row.state == 1"
@
click=
"openDeleteDialog(1, row)"
>
删除
</bg-table-btn>
</bg-table-btns2>
</
template
>
</bg-table>
<bg-pagination
:page=
"filter.page"
:size=
"filter.limit"
:total=
"tableTotal"
@
change-page=
"changePage"
@
change-size=
"changeSize"
>
</bg-pagination>
</div>
</div>
<el-dialog
class=
"dialog_box_detail"
title=
"用户详情"
v-model=
"dialogDetail"
width=
"1062px"
>
<div
class=
"content_detail"
>
<div
class=
"form_filter"
>
<div
class=
"left"
>
<el-select
v-model=
"userFilter.isAdmin"
placeholder=
"请选择"
style=
"width: 200px; margin-left: 16px"
>
<el-option
v-for=
"(item, index) in userTypeList"
:key=
"'pushOptions' + index"
:label=
"item.name"
:value=
"item.value"
>
</el-option>
</el-select>
<el-cascader
v-model=
"userFilter.organizationId"
:options=
"orgList"
placeholder=
"请选择组织"
:props=
"{
expandTrigger: 'hover',
label: 'name',
value: 'organization_id',
emitPath: false,
checkStrictly: true,
children: 'Child',
}"
:clearable=
"true"
collapse-tags
style=
"width: 200px; margin-left: 16px"
>
<
template
#default
="{
data
}"
>
<span>
{{
data
.
name
}}
</span>
</
template
>
</el-cascader>
<el-input
placeholder=
"请输入关键词"
v-model.trim=
"userFilter.search"
style=
"width: 200px; margin-left: 16px"
:prefix-icon=
"Search"
/>
</div>
<div
class=
"right"
>
<el-button
type=
"primary"
@
click=
"searchUsers"
>
查询
</el-button>
<el-button
type=
"default"
@
click=
"clearAction"
>
重置
</el-button>
</div>
</div>
<div
class=
"table_content"
>
<bg-table
ref=
"bgUserTable"
:headers=
"userHeaders"
:rows=
"userTableRows"
height=
"430"
:stripe=
"true"
>
<
template
v-slot:isAdmin=
"{ row }"
>
<span>
{{
[
""
,
"
业务系统用户
"
,
"
组织管理员
"
,
"
平台用户
"
][
row
.
isAdmin
]
}}
</span>
</
template
>
</bg-table>
<bg-pagination
:page=
"userFilter.page"
:size=
"userFilter.limit"
:total=
"userTableTotal"
@
change-page=
"changeUserPage"
@
change-size=
"changeUserSize"
>
</bg-pagination>
</div>
</div>
</el-dialog>
<el-dialog
class=
"dialog_box"
:title=
"deleteDialogConfig.title"
v-model=
"dialogDelete"
width=
"400px"
>
<div
style=
"text-align: center"
>
{{ deleteDialogConfig.tips }}
</div>
<
template
v-slot:footer
>
<div
class=
"apaas_button"
>
<el-button
type=
"default"
@
click=
"dialogDelete = false"
>
取 消
</el-button>
<el-button
type=
"primary"
@
click=
"confimDelete"
>
确 定
</el-button>
</div>
</
template
>
</el-dialog>
</div>
</template>
</template>
<
script
setup
></
script
>
<
script
setup
>
import
{
reactive
,
toRefs
,
computed
,
onBeforeMount
,
ref
}
from
"
vue
"
;
import
{
Search
}
from
"
@element-plus/icons-vue
"
;
import
{
useRouter
}
from
"
vue-router
"
;
import
bgBreadcrumb
from
"
@/components/bg-breadcrumb.vue
"
;
import
axios
from
"
@/request/http.js
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
{
dateStringTransform
}
from
"
@/services/helper.js
"
;
const
router
=
useRouter
();
const
rulesTable
=
ref
(
null
);
const
state
=
reactive
({
filter
:
{
search
:
""
,
page
:
1
,
limit
:
10
,
time
:
[],
},
headers
:
[
{
label
:
"
规则名称
"
,
prop
:
"
rule_name
"
,
},
{
label
:
"
规则类型
"
,
prop
:
"
rule_type
"
,
},
{
label
:
"
用户数量
"
,
prop
:
"
num_user
"
,
},
{
label
:
"
规则
"
,
prop
:
"
rule_detail
"
,
},
{
label
:
"
是否启用
"
,
prop
:
"
state
"
,
},
{
label
:
"
修改时间
"
,
prop
:
"
updated_time
"
,
width
:
240
,
},
{
label
:
"
操作
"
,
prop
:
"
action
"
,
width
:
120
,
fixed
:
"
right
"
,
},
],
tableRows
:
[],
tableTotal
:
0
,
selectedNum
:
0
,
actionRow
:
{},
dialogDetail
:
false
,
userFilter
:
{
page
:
1
,
limit
:
10
,
search
:
""
,
isAdmin
:
""
,
organizationId
:
""
,
disp
:
0
,
},
userTypeList
:
[
{
name
:
"
全部类型
"
,
value
:
""
,
},
{
name
:
"
业务系统用户
"
,
value
:
1
,
},
{
name
:
"
组织管理员
"
,
value
:
2
,
},
{
name
:
"
平台用户
"
,
value
:
3
,
},
],
orgList
:
[],
userHeaders
:
[
{
label
:
"
账号
"
,
prop
:
"
systemAccount
"
,
},
{
label
:
"
类型
"
,
prop
:
"
isAdmin
"
,
},
{
label
:
"
用户手机号
"
,
prop
:
"
phone
"
,
},
{
label
:
"
所属组织
"
,
prop
:
"
name
"
,
},
],
userTableRows
:
[],
userTableTotal
:
0
,
selection
:
[],
dialogDelete
:
false
,
deleteDialogConfig
:
{
title
:
"
删除
"
,
ruleId
:
[],
tips
:
"
确定要删除当前行数据吗?
"
,
},
});
const
getOrgList
=
()
=>
{
axios
.
get
(
`/apaas/system/v5/org/tree`
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
state
.
orgList
=
res
.
data
.
data
||
[];
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
// 获取组织
const
changeSearch
=
(
val
)
=>
{
state
.
filter
.
search
=
val
;
changePage
(
1
);
};
// 关键字
const
changePage
=
(
page
)
=>
{
state
.
filter
.
page
=
page
;
getTableRows
();
};
// 改变页码
const
changeSize
=
(
size
)
=>
{
state
.
filter
.
limit
=
size
;
changePage
(
1
);
};
// 改变每页条数
const
filterAction
=
()
=>
{
changePage
(
1
);
};
// 高级搜索中查询
const
filterClear
=
()
=>
{
state
.
filter
=
{
search
:
""
,
page
:
1
,
limit
:
10
,
time
:
[],
};
changePage
(
1
);
};
// 高级搜索中重置
const
getTableRows
=
()
=>
{
let
params
=
{
...
state
.
filter
};
params
.
updatedTimeFrom
=
params
.
time
?
params
.
time
[
0
]
||
""
:
""
;
params
.
updatedTimeTo
=
params
.
time
?
params
.
time
[
1
]
||
""
:
""
;
delete
params
.
time
;
axios
.
get
(
`/apaas/system/v5/accessRule/listAccessRule`
,
{
params
,
})
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
state
.
tableRows
=
res
.
data
.
data
||
[];
state
.
tableTotal
=
res
.
data
.
total
;
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
// 获取表格数据
const
selectRows
=
(
data
)
=>
{
state
.
selectedNum
=
data
.
allLength
;
state
.
selection
=
data
.
selection
;
};
// 新增规则跳转
const
addRule
=
()
=>
{
router
.
push
(
"
/system-admin/visit-control/add
"
);
};
const
cleanSelected
=
()
=>
{
rulesTable
.
value
.
clearTable
();
};
//清空
// 改变规则状态
const
stateChange
=
(
row
)
=>
{
axios
.
put
(
`/apaas/system/v5/accessRule/updateState?id=
${
row
.
id
}
&state=
${
row
.
state
}
`
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
ElMessage
.
success
(
res
.
data
.
msg
);
changePage
(
1
);
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
row
.
state
=
row
.
state
==
0
?
1
:
0
;
}
});
};
// 打开用户弹窗
const
openUserDialog
=
(
row
)
=>
{
state
.
dialogDetail
=
true
;
state
.
actionRow
=
row
;
clearAction
();
};
const
searchUsers
=
()
=>
{
changeUserPage
(
1
);
};
// 用户弹窗查询
// 用户弹窗重置
const
clearAction
=
()
=>
{
state
.
userFilter
=
{
page
:
1
,
limit
:
10
,
search
:
""
,
isAdmin
:
""
,
organizationId
:
""
,
disp
:
0
,
};
changeUserPage
(
1
);
};
// 用户详情改变分页
const
changeUserPage
=
(
page
)
=>
{
state
.
userFilter
.
page
=
page
;
getUserTableRows
();
};
const
changeUserSize
=
(
size
)
=>
{
state
.
userFilter
.
limit
=
size
;
changeUserPage
(
1
);
};
// 用户详情弹窗数据
const
getUserTableRows
=
()
=>
{
let
params
=
{
...
state
.
userFilter
,
id
:
state
.
actionRow
.
id
,
};
axios
.
get
(
`/apaas/system/v5/accessRule/listRuleUser`
,
{
params
}).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
state
.
userTableRows
=
res
.
data
.
data
||
[];
state
.
userTableTotal
=
res
.
data
.
total
;
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
const
edit
=
(
row
)
=>
{
router
.
push
({
path
:
"
/system-admin/visit-control/edit
"
,
query
:
{
id
:
row
.
id
,
ruleId
:
row
.
rule_id
,
ruleName
:
row
.
rule_name
,
state
:
row
.
state
,
ruleType
:
row
.
rule_type
,
ruleDetail
:
row
.
rule_detail
,
},
});
};
//编辑
//打开删除弹窗
const
openDeleteDialog
=
(
type
,
row
)
=>
{
if
(
type
===
2
)
{
const
res
=
rulesTable
.
value
.
dealSelectData
();
const
list
=
Object
.
values
(
res
);
if
(
list
.
length
===
0
)
return
ElMessage
.
warning
(
"
请选择要删除的数据
"
);
state
.
dialogDelete
=
true
;
const
ruleId
=
list
.
map
((
item
)
=>
item
.
rule_id
);
state
.
deleteDialogConfig
=
{
title
:
"
批量删除
"
,
ruleId
,
tips
:
"
确定要删除所选数据吗?
"
};
return
;
}
state
.
dialogDelete
=
true
;
state
.
deleteDialogConfig
=
{
title
:
"
删除
"
,
ruleId
:
[
row
.
rule_id
],
tips
:
"
确定要删除当前行数据吗?
"
,
};
};
//确定删除
const
confimDelete
=
()
=>
{
axios
.
delete
(
"
/apaas/system/v5/accessRule/delAccessRule
"
,
{
data
:
{
ruleId
:
state
.
deleteDialogConfig
.
ruleId
,
},
})
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
ElMessage
.
success
(
"
删除成功
"
);
changePage
(
1
);
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
})
.
finally
(()
=>
{
state
.
dialogDelete
=
false
;
});
};
const
{
filter
,
headers
,
userHeaders
,
tableRows
,
tableTotal
,
selectedNum
,
dialogDetail
,
userTableRows
,
userTableTotal
,
userFilter
,
userTypeList
,
orgList
,
selection
,
dialogDelete
,
deleteDialogConfig
,
}
=
toRefs
(
state
);
onBeforeMount
(()
=>
{
getTableRows
();
getOrgList
();
});
</
script
>
<
style
lang=
"scss"
scoped
>
.page_container
{
display
:
flex
;
flex-direction
:
column
;
justify-content
:
flex-start
;
align-items
:
stretch
;
width
:
100%
;
padding
:
0
24px
;
min-height
:
100%
;
.main_container
{
display
:
flex
;
flex-direction
:
column
;
justify-content
:
flex-start
;
align-items
:
stretch
;
flex-grow
:
1
;
width
:
100%
;
background-color
:
#fff
;
box-shadow
:
0px
1px
4px
0px
rgba
(
0
,
7
,
101
,
0
.15
);
border-radius
:
6px
;
padding
:
0
0
16px
0
;
margin-bottom
:
16px
;
position
:
relative
;
.sleceted_tip
{
margin
:
0
24px
0
40px
;
vertical-align
:
middle
;
font-size
:
14px
;
color
:
#404a62
;
.num
{
margin
:
0
3px
0
3px
;
font-weight
:
600
;
color
:
#202531
;
}
}
.clean
{
vertical-align
:
middle
;
font-size
:
14px
;
color
:
#3759be
;
cursor
:
pointer
;
}
.filter-group
{
.left-filter
{
flex
:
1
;
display
:
flex
;
justify-content
:
start
;
flex-wrap
:
wrap
;
.filter_item
{
display
:
flex
;
align-items
:
center
;
.filter_title
{
width
:
84px
;
white-space
:
pre-wrap
;
font-weight
:
normal
;
}
}
}
.right-action
{
width
:
144px
;
padding-bottom
:
16px
;
.el-button
{
width
:
64px
;
}
}
}
.table_container
{
padding
:
0
16px
;
.el-table
{
flex
:
1
;
.under_line
{
text-decoration
:
underline
;
}
}
}
}
:deep
()
.dialog_box_detail
{
.el-dialog__body
{
padding
:
0
0
18px
0
;
height
:
580px
;
}
<
style
lang=
"scss"
scoped
></
style
>
.form_filter
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
height
:
69px
;
border-bottom
:
1px
solid
#e6e9ef
;
.right
{
margin-right
:
16px
;
.el-button
{
width
:
64px
;
&
:last-child
{
margin-left
:
16px
;
}
}
}
}
.table_content
{
padding
:
0
16px
;
}
}
}
</
style
>
src/router/function.js
View file @
c11a241c
...
@@ -278,6 +278,9 @@ function getViews(path) {
...
@@ -278,6 +278,9 @@ function getViews(path) {
var
menuToRouter
=
(
menu
)
=>
{
var
menuToRouter
=
(
menu
)
=>
{
menu
.
forEach
((
e
)
=>
{
menu
.
forEach
((
e
)
=>
{
e
.
name
=
getName
(
e
.
path
);
e
.
name
=
getName
(
e
.
path
);
if
(
e
.
path
.
indexOf
(
"
#
"
)
!=
-
1
)
{
e
.
path
=
e
.
path
.
split
(
"
#
"
)[
1
];
}
if
(
e
.
children
&&
e
.
menuType
==
0
)
{
if
(
e
.
children
&&
e
.
menuType
==
0
)
{
// 其他层级作为文件夹,只提供父级
// 其他层级作为文件夹,只提供父级
e
.
component
=
()
=>
import
(
"
../page/parent/parent.vue
"
);
e
.
component
=
()
=>
import
(
"
../page/parent/parent.vue
"
);
...
...
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