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
07cf72aa
Commit
07cf72aa
authored
Jun 20, 2023
by
李鹏
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
system-admin
parent
a9f2eaef
Changes
19
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
5446 additions
and
94 deletions
+5446
-94
src/main.js
src/main.js
+2
-8
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
No files found.
src/main.js
View file @
07cf72aa
...
...
@@ -12,7 +12,7 @@ import * as ElementPlusIconsVue from "@element-plus/icons-vue";
import
bgui
from
"
@/bg-ui
"
;
import
"
@/bg-ui/index.scss
"
;
import
"
./assets/css/common.scss
"
import
"
./assets/css/common.scss
"
;
import
msgSdk
from
"
./msg-sdk/index.js
"
;
...
...
@@ -109,13 +109,7 @@ Promise.all([getUser(), getMenu("79a8f214-db78-4db7-9c28-db66276b4be2")])
console
.
error
(
e
);
})
.
finally
(()
=>
{
createVue
.
use
(
ElementPlus
,
{
locale
})
.
use
(
store
)
.
use
(
router
)
.
use
(
i18n
)
.
use
(
bgui
)
.
use
(
mavonEditor
);
createVue
.
use
(
ElementPlus
,
{
locale
}).
use
(
store
).
use
(
router
).
use
(
i18n
).
use
(
bgui
).
use
(
mavonEditor
);
createVue
.
mount
(
"
#app
"
);
});
...
...
src/page/main/config/dict/index.vue
View file @
07cf72aa
...
...
@@ -25,22 +25,15 @@
</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'"
>
<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>
<bg-icon
style=
"font-size: 12px; color: #fff; margin-right: 8px"
icon=
"#bg-ic-add"
></bg-icon>
新增
</el-button>
</div>
...
...
@@ -67,12 +60,7 @@
</bg-filter-group>
<div
class=
"table_container"
>
<div
class=
"table bg-scroll"
>
<bg-table
ref=
"bgTable"
:headers=
"headers"
:rows=
"tableRows"
:isIndex=
"true"
:stripe=
"true"
>
<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
}}
...
...
@@ -93,33 +81,17 @@
</
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
: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-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>
...
...
@@ -136,11 +108,7 @@
</div>
</div>
<!-- 新增/编辑弹窗 -->
<el-dialog
class=
"dialog_box"
:title=
"addType == 1 ? '新增' : '编辑'"
v-model=
"addDialog"
width=
"758px"
>
<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
...
...
@@ -208,11 +176,12 @@
</template>
<
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
axios
from
"
../../../../request/http.js
"
;
import
{
Search
}
from
"
@element-plus/icons-vue
"
;
import
bgBreadcrumb
from
"
@/components/bg-breadcrumb.vue
"
;
import
axios
from
"
../../../../request/http.js
"
;
const
bgForm
=
ref
(
null
);
const
headers
=
computed
(()
=>
{
...
...
src/page/main/config/preference/index.vue
View file @
07cf72aa
...
...
@@ -28,10 +28,7 @@
<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-input
placeholder=
"统一管理用户认证平台"
v-model=
"authorizeFormData.system_user"
maxlength=
"30"
/>
</el-form-item>
<el-form-item
label=
"Key"
prop=
"license"
>
<el-input
...
...
@@ -45,15 +42,12 @@
<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"
>
<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表示不提醒
范围(0~90),单位:天, 当剩余有效期在配置区间内时,系统会在用户登录系统时发出提醒,0表示不提醒
</
template
>
<div
class=
"tip-image"
></div>
</el-tooltip>
...
...
@@ -97,19 +91,14 @@
</el-form-item>
</div>
<el-form-item
label=
"密码有效期"
prop=
"pwd_validity"
>
<el-input
placeholder=
"请输入"
v-model.trim.number=
"secureFormData.pwd_validity"
maxlength=
"3"
>
<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
>
<span>
密码有效期是指强制修改密码的周期,例如60天表示用户需要每60天修改一次密码。
</span>
<br
/>
<span>
若配置为0,表示密码有效期为永久
</span>
</
template
>
...
...
@@ -122,7 +111,7 @@
</el-input>
<el-tooltip
placement=
"top-start"
effect=
"light"
>
<
template
#content
>
<span>
{{
`范围(10~${session_validity_max
}
)`
}}
<
/span>
<span>
{{
`范围(10~${session_validity_max
}
)`
}}
<
/span>
<
br
/>
<
span
>
单位,分钟
<
/span>
<
br
/>
...
...
@@ -242,9 +231,7 @@ const state = reactive({
}
,
//授权表单校验规则
authorizeRules
:
{
license_inform_day
:
[
{
type
:
"
number
"
,
min
:
0
,
max
:
90
,
message
:
"
请输入0~90的整数
"
,
trigger
:
"
blur
"
}
,
],
license_inform_day
:
[{
type
:
"
number
"
,
min
:
0
,
max
:
90
,
message
:
"
请输入0~90的整数
"
,
trigger
:
"
blur
"
}
],
}
,
//安全相关信息表单
...
...
src/page/main/system-admin/dict/index.vue
View file @
07cf72aa
<
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>
<
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 @
a9f2eaef
<
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 @
07cf72aa
<
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 @
07cf72aa
<
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 @
07cf72aa
<
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 @
07cf72aa
<
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 @
07cf72aa
<
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>
<
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 @
07cf72aa
<
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 @
07cf72aa
<
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 @
07cf72aa
<
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>
<
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 @
07cf72aa
<
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 @
07cf72aa
<
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 @
07cf72aa
<
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 @
07cf72aa
<!-- 角色管理 -->
<
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 @
07cf72aa
<!-- 角色管理 -->
<
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 @
07cf72aa
<
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>
<
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
>
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