mirror of
https://github.com/jumpserver/lina.git
synced 2026-01-15 14:24:39 +00:00
perf: update pam
This commit is contained in:
@@ -132,7 +132,7 @@ export default {
|
||||
columnsDefault: {
|
||||
type: Array,
|
||||
default: () => ([
|
||||
'name', 'username', 'secret', 'asset', 'platform', 'date_updated', 'connect'
|
||||
'name', 'username', 'secret', 'asset', 'platform', 'connect'
|
||||
])
|
||||
},
|
||||
headerExtraActions: {
|
||||
@@ -210,6 +210,7 @@ export default {
|
||||
},
|
||||
platform: {
|
||||
label: this.$t('Platform'),
|
||||
width: '120px',
|
||||
formatter: PlatformFormatter,
|
||||
formatterArgs: {
|
||||
platformAttr: 'asset.platform'
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
height="300"
|
||||
title="Processing"
|
||||
width="300"
|
||||
class="processing-dialog"
|
||||
>
|
||||
<div id="load">
|
||||
<div class="spinner" />
|
||||
@@ -40,12 +41,18 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.processing-dialog {
|
||||
::v-deep .el-dialog__body {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.spinner {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border: 5px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 50%;
|
||||
border-top-color: #3498db;
|
||||
border-top-color: var(--color-primary);
|
||||
animation: spin 1s infinite linear;
|
||||
}
|
||||
|
||||
|
||||
69
src/components/Dialog/RemoteProcessingDialog.vue
Normal file
69
src/components/Dialog/RemoteProcessingDialog.vue
Normal file
@@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<Dialog
|
||||
:visible="iVisible"
|
||||
height="300"
|
||||
title="Processing"
|
||||
width="300"
|
||||
class="processing-dialog"
|
||||
>
|
||||
<div id="load">
|
||||
<div class="spinner" />
|
||||
</div>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Dialog from './index.vue'
|
||||
|
||||
export default {
|
||||
name: 'RemoteProcessingDialog',
|
||||
components: { Dialog },
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
iVisible: {
|
||||
get() {
|
||||
return this.visible
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('update:visible', val)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.processing-dialog {
|
||||
::v-deep .el-dialog__body {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.spinner {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border: 5px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 50%;
|
||||
border-top-color: var(--color-primary);
|
||||
animation: spin 1s infinite linear;
|
||||
}
|
||||
|
||||
#load {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -6,15 +6,15 @@
|
||||
<el-input
|
||||
v-show="isShow"
|
||||
v-model.trim="curValue"
|
||||
:disabled="disabled"
|
||||
:placeholder="placeholder"
|
||||
:type="type"
|
||||
:disabled="disabled"
|
||||
class="password-input"
|
||||
show-password
|
||||
@change="onChange"
|
||||
/>
|
||||
<el-button size="small" type="text" :disabled="disabled" @click="randomPassword">
|
||||
<i class="fa fa-retweet" />
|
||||
<el-button :disabled="disabled" size="small" type="text" @click="randomPassword">
|
||||
<i class="fa fa-refresh" />
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -7,6 +7,18 @@
|
||||
"notAlphanumericUnderscore": "Only alphanumeric characters and underscores are allowed.",
|
||||
"notParenthesis": "Parentheses are not allowed.",
|
||||
"InvalidJson": "Invalid JSON format.",
|
||||
"requiredHasUserNameMapped": "Username attr is required."
|
||||
"requiredHasUserNameMapped": "Username attr is required.",
|
||||
"NewFound": "New Found",
|
||||
"LastLoginTime": "Last login time",
|
||||
"Diff": "Difference",
|
||||
"LastChangeTime": "Last change time",
|
||||
"AccountDeleted": "Account deleted",
|
||||
"WeakPassword": "Weak password",
|
||||
"RepeatPassword": "Repeat password",
|
||||
"LeakPassword": "Password leaked",
|
||||
"Other": "Other",
|
||||
"Details": "Details",
|
||||
"Confirm": "Confirm",
|
||||
"Ignore": "Ignore"
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
{
|
||||
"FieldRequiredError": "这个字段是必需的。",
|
||||
"InputEmailAddress": "输入一个电子邮件地址。",
|
||||
"ServerError": "服务错误,请联系管理员。",
|
||||
"FormatError": "格式错误。",
|
||||
"NotSpecialEmoji": "不支持表情字符。",
|
||||
"notAlphanumericUnderscore": "仅支持字母、数字和下划线。",
|
||||
"notParenthesis": "不能包含括号。",
|
||||
"InvalidJson": "JSON 格式错误.",
|
||||
"requiredHasUserNameMapped": "用户名属性是必需的。"
|
||||
"FieldRequiredError": "这个字段是必需的。",
|
||||
"InputEmailAddress": "输入一个电子邮件地址。",
|
||||
"ServerError": "服务错误,请联系管理员。",
|
||||
"FormatError": "格式错误。",
|
||||
"NotSpecialEmoji": "不支持表情字符。",
|
||||
"notAlphanumericUnderscore": "仅支持字母、数字和下划线。",
|
||||
"notParenthesis": "不能包含括号。",
|
||||
"InvalidJson": "JSON 格式错误.",
|
||||
"requiredHasUserNameMapped": "用户名属性是必需的。",
|
||||
"Diff": ""
|
||||
}
|
||||
|
||||
@@ -7,5 +7,17 @@
|
||||
"notAlphanumericUnderscore": "仅支持字母、数字和下划线。",
|
||||
"notParenthesis": "不能包含括号。",
|
||||
"InvalidJson": "JSON 格式错误.",
|
||||
"requiredHasUserNameMapped": "用户名属性是必需的。"
|
||||
"requiredHasUserNameMapped": "用户名属性是必需的。",
|
||||
"NewFound": "新发现",
|
||||
"LastLoginTime": "最后登录时间",
|
||||
"Diff": "差异",
|
||||
"LastChangeTime": "最后修改时间",
|
||||
"AccountDeleted": "账户已删除",
|
||||
"WeakPassword": "弱密码",
|
||||
"RepeatPassword": "重复密码",
|
||||
"LeakPassword": "密码泄露",
|
||||
"Other": "其他",
|
||||
"Details": "详情",
|
||||
"Confirm": "确认",
|
||||
"Ignore": "忽略"
|
||||
}
|
||||
|
||||
@@ -102,8 +102,11 @@ const actions = {
|
||||
const recentPlatformIds = state.recentPlatformIds
|
||||
return new Promise(resolve => {
|
||||
dispatch('getPlatforms').then(platforms => {
|
||||
const recentPlatforms = platforms.filter(p => recentPlatformIds.includes(p.id))
|
||||
.sort((a, b) => recentPlatformIds.indexOf(a.id) - recentPlatformIds.indexOf(b.id))
|
||||
const platformsMap = {}
|
||||
platforms.forEach(p => {
|
||||
platformsMap[p.id] = p
|
||||
})
|
||||
const recentPlatforms = recentPlatformIds.map(id => platformsMap[id]).filter(p => p)
|
||||
resolve(recentPlatforms)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -252,10 +252,9 @@ export default {
|
||||
},
|
||||
async setRecentPlatforms() {
|
||||
const recentPlatforms = await this.$store.dispatch('assets/getRecentPlatforms')
|
||||
const recentIds = recentPlatforms.map(item => item.id)
|
||||
let allPlatforms = await this.$store.dispatch('assets/getPlatforms')
|
||||
allPlatforms = allPlatforms.filter(item => !recentIds.includes(item.id))
|
||||
let platforms = [...recentPlatforms, ...allPlatforms]
|
||||
const allPlatforms = await this.$store.dispatch('assets/getPlatforms')
|
||||
const otherPlatforms = allPlatforms.filter(item => !this.recentPlatformIds.includes(item.id))
|
||||
let platforms = [...recentPlatforms, ...otherPlatforms]
|
||||
if (this.category !== 'all') {
|
||||
platforms = platforms.filter(item => item.category.value === this.category)
|
||||
}
|
||||
|
||||
@@ -72,8 +72,6 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dashboard-container {
|
||||
padding: 1.25rem;
|
||||
|
||||
.top-summary,
|
||||
.middle-section,
|
||||
.bottom-section {
|
||||
@@ -108,7 +106,7 @@ export default {
|
||||
background: #fff;
|
||||
padding: 1.25rem;
|
||||
height: 100%;
|
||||
box-shadow: 0 1px 4px rgba(0,21,41,.08);
|
||||
box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
|
||||
transition: all .3s;
|
||||
|
||||
::v-deep .card-content {
|
||||
@@ -124,14 +122,14 @@ export default {
|
||||
.mission-summary {
|
||||
background: #fff;
|
||||
padding: 1.25rem;
|
||||
box-shadow: 0 1px 4px rgba(0,21,41,.08);
|
||||
box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
|
||||
}
|
||||
|
||||
.secret-summary {
|
||||
background: #fff;
|
||||
padding: 1.25rem;
|
||||
margin-bottom: 1.25rem;
|
||||
box-shadow: 0 1px 4px rgba(0,21,41,.08);
|
||||
box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1200px) {
|
||||
|
||||
@@ -15,6 +15,7 @@ export default {
|
||||
fields: [
|
||||
[this.$t('Basic'), ['name', 'scope']],
|
||||
[this.$t('Other'), ['comment']]
|
||||
|
||||
],
|
||||
createSuccessNextRoute: {
|
||||
name: 'Template'
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
:title="$t('Details')"
|
||||
:visible.sync="iVisible"
|
||||
append-to-body
|
||||
class="drawer"
|
||||
destroy-on-close
|
||||
direction="rtl"
|
||||
style="z-index: 999"
|
||||
@@ -10,7 +11,9 @@
|
||||
>
|
||||
<div class="drawer-body">
|
||||
<div v-for="r in iRows" :key="r.id">
|
||||
<div class="host-username">{{ r.asset ? r.asset.name : r }} - {{ r.username }}</div>
|
||||
<div class="host-username">
|
||||
{{ r.username }}@{{ r.asset ? r.asset.name : r }}
|
||||
</div>
|
||||
<el-timeline :reverse="true">
|
||||
<el-timeline-item
|
||||
v-for="detail in r.details"
|
||||
@@ -54,13 +57,14 @@ export default {
|
||||
default: true
|
||||
},
|
||||
rows: {
|
||||
type: Array,
|
||||
type: Array, // 可能会批量 review 所以有了它
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
riskActions
|
||||
riskActions,
|
||||
title: this.$t('Details of')
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -128,23 +132,29 @@ export default {
|
||||
handleInit(row, detail) {
|
||||
switch (row.risk.value) {
|
||||
case 'new_found':
|
||||
return this.$tc('New found')
|
||||
return this.$tc('NewFound')
|
||||
case 'long_time_no_login':
|
||||
return this.$tc('Last login time') + ': ' + this.formatTimestamp(detail.date)
|
||||
return this.$tc('LastLoginTime') + ': ' + this.formatTimestamp(detail.date)
|
||||
case 'group_changed':
|
||||
case 'sudoers_changed':
|
||||
case 'authorized_key_changed':
|
||||
return `变更:
|
||||
return this.$t('Diff') + `:
|
||||
<pre>
|
||||
${detail.diff}
|
||||
</pre>
|
||||
`
|
||||
case 'long_time_password':
|
||||
return this.$t('Last change time') + ': ' + this.formatTimestamp(detail.date)
|
||||
return this.$t('LastChangeTime') + ': ' + this.formatTimestamp(detail.date)
|
||||
case 'account_deleted':
|
||||
return this.$t('Account deleted')
|
||||
return this.$t('AccountDeleted')
|
||||
case 'weak_password':
|
||||
return this.$t('WeakPassword')
|
||||
case 'repeat_password':
|
||||
return this.$t('RepeatPassword')
|
||||
case 'leak_password':
|
||||
return this.$t('LeakPassword')
|
||||
default:
|
||||
return '其它'
|
||||
return this.$t('Other')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,12 +162,21 @@ ${detail.diff}
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
.drawer {
|
||||
::v-deep {
|
||||
.el-drawer__header {
|
||||
padding: 15px 20px 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.drawer-body {
|
||||
height: calc(100% - 40px - 40px);
|
||||
height: calc(100% - 40px - 30px);
|
||||
overflow: auto;
|
||||
|
||||
::v-deep .el-drawer__body {
|
||||
overflow: auto;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
::v-deep pre {
|
||||
@@ -165,18 +184,19 @@ ${detail.diff}
|
||||
}
|
||||
|
||||
.host-username {
|
||||
font-size: 13px;
|
||||
margin-left: 40px;
|
||||
margin-bottom: 10px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.drawer-footer {
|
||||
border-top: solid 1px var(--color-border);
|
||||
height: 70px;
|
||||
padding: 15px 30px;
|
||||
height: 60px;
|
||||
line-height: 60px;
|
||||
padding: 0 30px;
|
||||
|
||||
.buttons {
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -35,7 +35,7 @@
|
||||
</template>
|
||||
<script>
|
||||
import BaseFormatter from '@/components/Table/TableFormatters/base.vue'
|
||||
import ReviewDraw from '@/views/pam/RiskDetect/RiskHandlerFormatter/ReviewDraw.vue'
|
||||
import ReviewDraw from '@/views/pam/RiskDetect/RiskHandlerFormatter/ReviewDrawer.vue'
|
||||
import ProcessingDialog from '@/components/Dialog/ProcessingDialog.vue'
|
||||
import { riskActions } from './const'
|
||||
import { sleep } from '@/utils/time'
|
||||
|
||||
Reference in New Issue
Block a user