mirror of
https://github.com/jumpserver/lina.git
synced 2026-01-14 03:46:26 +00:00
Compare commits
114 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee55cebf0e | ||
|
|
2e5096f386 | ||
|
|
bf57ee8910 | ||
|
|
f86f08f2b6 | ||
|
|
6eb429823d | ||
|
|
d6be84026c | ||
|
|
4a7680ec7a | ||
|
|
4fd8956b0d | ||
|
|
9d75e2e6fd | ||
|
|
6317400da8 | ||
|
|
7f963e9991 | ||
|
|
8a731937cf | ||
|
|
a593da7fea | ||
|
|
b9547214b7 | ||
|
|
0e7b60a001 | ||
|
|
20f84db466 | ||
|
|
c5495d9846 | ||
|
|
332cd2c073 | ||
|
|
2b4d827789 | ||
|
|
92144e4f69 | ||
|
|
41d42c04a6 | ||
|
|
f4f42639aa | ||
|
|
a37af9ed7d | ||
|
|
1f0fe18533 | ||
|
|
bc21d7ac17 | ||
|
|
922ecbf096 | ||
|
|
a162a206bc | ||
|
|
12a85da6f7 | ||
|
|
585f5e04d6 | ||
|
|
6db90fce09 | ||
|
|
69e392b069 | ||
|
|
e5b2bd7008 | ||
|
|
c6aaaaf1fd | ||
|
|
1ab6ed6109 | ||
|
|
c17d983b2f | ||
|
|
484fb63577 | ||
|
|
2c8d8c6e66 | ||
|
|
5577051416 | ||
|
|
cd51596d45 | ||
|
|
dd5b805da9 | ||
|
|
54097f07be | ||
|
|
ef5c1b2e23 | ||
|
|
f104376e92 | ||
|
|
62ed11e7ec | ||
|
|
3fd8e23c2c | ||
|
|
a93ecac15c | ||
|
|
1fb75fbce0 | ||
|
|
1d594fc594 | ||
|
|
a4abe63ec9 | ||
|
|
4262410038 | ||
|
|
2735d638a2 | ||
|
|
f9bade6a7c | ||
|
|
eaf3c5b013 | ||
|
|
2c2e7d10f9 | ||
|
|
9243a6699c | ||
|
|
e9a2818580 | ||
|
|
4b318c0aaf | ||
|
|
e9211205cb | ||
|
|
e14a31f31c | ||
|
|
b85db6b73f | ||
|
|
6d8dc058cb | ||
|
|
2b3090b44c | ||
|
|
f08b3708d4 | ||
|
|
a8a7538655 | ||
|
|
364f2aaf12 | ||
|
|
dcb87c6216 | ||
|
|
06bd68a874 | ||
|
|
4a2b663220 | ||
|
|
59342b65c8 | ||
|
|
4edd9097ab | ||
|
|
6e10f4ccc1 | ||
|
|
9510dec9e0 | ||
|
|
31bb679a8e | ||
|
|
357b67ffe0 | ||
|
|
07036cdea7 | ||
|
|
ec2674a956 | ||
|
|
e5791c184d | ||
|
|
bcd0384baa | ||
|
|
461a385596 | ||
|
|
0c9440d835 | ||
|
|
9f7c145065 | ||
|
|
05d66c4c4f | ||
|
|
c1498d4de5 | ||
|
|
34f17beb3c | ||
|
|
c6f39c79fa | ||
|
|
ae5005ceef | ||
|
|
dad107d768 | ||
|
|
021dbe6e2e | ||
|
|
8ae14bfb37 | ||
|
|
ea2c3f1a11 | ||
|
|
dadeea6d1e | ||
|
|
05e5bcc10d | ||
|
|
87d211563f | ||
|
|
6b7f868538 | ||
|
|
d3c2d0e7e8 | ||
|
|
088dbc4e42 | ||
|
|
18016ffdba | ||
|
|
b57e65a100 | ||
|
|
8852924d45 | ||
|
|
da1f322e1c | ||
|
|
b22b01529a | ||
|
|
26ba2c091e | ||
|
|
23ee181c63 | ||
|
|
3aca8cdffd | ||
|
|
b5cd17485e | ||
|
|
4db98964dd | ||
|
|
3a1870cae1 | ||
|
|
c36cc7b15f | ||
|
|
07b69ab9a8 | ||
|
|
222eb4fcb0 | ||
|
|
632dc064d9 | ||
|
|
cc513c96f5 | ||
|
|
b3752ba867 | ||
|
|
f18e46ba22 |
@@ -1,6 +1,4 @@
|
||||
FROM node:10 as stage-build
|
||||
ARG VERSION
|
||||
ENV VERSION=$VERSION
|
||||
ARG NPM_REGISTRY="https://registry.npm.taobao.org"
|
||||
ENV NPM_REGISTY=$NPM_REGISTRY
|
||||
ARG SASS_BINARY_SITE="https://npm.taobao.org/mirrors/node-sass"
|
||||
@@ -15,6 +13,8 @@ COPY package.json yarn.lock /data/
|
||||
RUN yarn install
|
||||
RUN npm rebuild node-sass
|
||||
|
||||
ARG VERSION
|
||||
ENV VERSION=$VERSION
|
||||
ADD . /data
|
||||
RUN cd utils && bash -xieu build.sh build
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ VUE_APP_CORE_HOST = 'JUMPSERVER_APIHOST'
|
||||
$ yarn serve
|
||||
|
||||
4. 构建
|
||||
$ yarn build
|
||||
$ yarn build:prod
|
||||
```
|
||||
|
||||
## 生产中部署
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
const tokens = {
|
||||
admin: {
|
||||
token: 'admin-token'
|
||||
@@ -46,7 +45,6 @@ export default [
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// get user info
|
||||
{
|
||||
url: '/vue-admin-template/user/info\.*',
|
||||
|
||||
@@ -13,3 +13,9 @@ export function getCurrentOrg() {
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
getCurrentOrg,
|
||||
getOrgDetail
|
||||
}
|
||||
|
||||
|
||||
@@ -69,3 +69,8 @@ export function logout() {
|
||||
export function refreshSessionIdAge() {
|
||||
return getProfile()
|
||||
}
|
||||
|
||||
export default {
|
||||
getProfile,
|
||||
getUserList
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
:title="title"
|
||||
@close="onClose"
|
||||
>
|
||||
<span class="announcement-main"> {{ announcement.content }}</span>
|
||||
<span class="announcement-main">{{ announcement.content }}</span>
|
||||
<span v-if="announcement.link">
|
||||
<el-link :href="announcement.link" target="_blank" class="link-more">
|
||||
{{ $t('common.ViewMore') }}
|
||||
@@ -60,6 +60,7 @@ export default {
|
||||
}
|
||||
.announcement-main {
|
||||
word-wrap:break-word;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.link-more {
|
||||
font-size: 10px;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div :class="grouped ? 'el-button-group' : 'el-button-ungroup'" style="display: flex">
|
||||
<div :class="grouped ? 'el-button-group' : 'el-button-ungroup'" class="layout">
|
||||
<template v-for="action in iActions">
|
||||
<el-dropdown
|
||||
v-if="action.dropdown"
|
||||
@@ -15,7 +15,12 @@
|
||||
</el-button>
|
||||
<el-dropdown-menu slot="dropdown" style="overflow: auto;max-height: 60vh">
|
||||
<template v-for="option in action.dropdown">
|
||||
<div v-if="option.group" :key="'group:'+option.name" class="dropdown-menu-title" style="width:130px">
|
||||
<div
|
||||
v-if="option.group"
|
||||
:key="'group:'+option.name"
|
||||
class="dropdown-menu-title"
|
||||
style="width:130px"
|
||||
>
|
||||
{{ option.group }}
|
||||
</div>
|
||||
<el-dropdown-item
|
||||
@@ -149,6 +154,11 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.layout {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.dropdown-menu-title {
|
||||
text-align: left;
|
||||
font-size: 12px;
|
||||
@@ -165,7 +175,7 @@ export default {
|
||||
}
|
||||
|
||||
.el-button-ungroup .action-item {
|
||||
margin-left: 4px
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.el-button-ungroup .action-item:first-child {
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
<el-dialog
|
||||
:title="title"
|
||||
:top="top"
|
||||
:width="iWidth"
|
||||
class="dialog"
|
||||
v-bind="$attrs"
|
||||
append-to-body
|
||||
:append-to-body="false"
|
||||
:modal-append-to-body="false"
|
||||
v-on="$listeners"
|
||||
>
|
||||
<slot />
|
||||
@@ -39,6 +41,10 @@ export default {
|
||||
type: String,
|
||||
default: '3vh'
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: '60%'
|
||||
},
|
||||
showConfirm: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
@@ -58,6 +64,11 @@ export default {
|
||||
return {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
iWidth() {
|
||||
return this.$store.getters.isMobile ? '80%' : this.width
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onCancel() {
|
||||
this.$emit('cancel')
|
||||
|
||||
@@ -91,18 +91,22 @@ export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='less' scoped>
|
||||
<style lang='scss' scoped>
|
||||
.datepicker{
|
||||
width: 233px;
|
||||
&>>> .el-range__icon {
|
||||
margin-top: 2px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
&>>> .el-range-input {
|
||||
width: 49%;
|
||||
}
|
||||
}
|
||||
.el-input__inner{
|
||||
border: 1px solid #dcdee2;
|
||||
border-radius: 3px;
|
||||
height: 36px;
|
||||
}
|
||||
/*.el-date-editor ::v-deep .el-input__icon{*/
|
||||
/* line-height: 28px;*/
|
||||
/*}*/
|
||||
.el-date-editor ::v-deep .el-range-separator{
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
@@ -92,11 +92,11 @@ export default {
|
||||
return this.selectedRows.length > 0
|
||||
},
|
||||
tableQuery() {
|
||||
const listTableRef = this.$parent.$parent.$parent.$parent
|
||||
const listTableRef = this.$parent?.$parent?.$parent?.$parent
|
||||
if (!listTableRef) {
|
||||
return {}
|
||||
}
|
||||
const query = listTableRef.dataTable.getQuery()
|
||||
const query = listTableRef?.dataTable?.getQuery() || {}
|
||||
delete query['limit']
|
||||
delete query['offset']
|
||||
delete query['date_from']
|
||||
@@ -199,8 +199,11 @@ export default {
|
||||
this.mfaDialogShow = false
|
||||
},
|
||||
handleExportCancel() {
|
||||
this.exportDialogShow = false
|
||||
this.mfaDialogShow = false
|
||||
const vm = this
|
||||
setTimeout(() => {
|
||||
vm.exportDialogShow = false
|
||||
vm.mfaDialogShow = false
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,17 +84,17 @@ export default {
|
||||
},
|
||||
canImportCreate: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
default: false
|
||||
},
|
||||
canImportUpdate: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showImportDialog: false,
|
||||
importOption: 'create',
|
||||
importOption: this.canImportCreate && this.canImportUpdate ? 'create' : this.canImportCreate ? 'create' : 'update',
|
||||
errorMsg: '',
|
||||
loadStatus: false,
|
||||
importTypeOption: 'csv',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row>
|
||||
<el-col :span="8">
|
||||
<el-col :md="8" :sm="24">
|
||||
<div class="tableFilter">
|
||||
<el-radio-group v-model="importStatusFilter" size="small">
|
||||
<el-radio-button label="all">{{ $t('common.Total') }}</el-radio-button>
|
||||
@@ -11,7 +11,7 @@
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8" style="text-align: center">
|
||||
<el-col :md="8" :sm="24" style="text-align: center">
|
||||
<span class="summary-item summary-total"> {{ $t('common.Total') }}: {{ totalCount }}</span>
|
||||
<span class="summary-item summary-success"> {{ $t('common.Success') }}: {{ successCount }}</span>
|
||||
<span class="summary-item summary-failed"> {{ $t('common.Failed') }}: {{ failedCount }}</span>
|
||||
|
||||
@@ -76,6 +76,14 @@ export default {
|
||||
extraRightSideActions: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
canCreate: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
canBulkUpdate: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -102,7 +110,11 @@ export default {
|
||||
return this.selectedRows.length > 0
|
||||
},
|
||||
iImportOptions() {
|
||||
return assignIfNot(this.importOptions, { url: this.tableUrl })
|
||||
return assignIfNot(this.importOptions, {
|
||||
url: this.tableUrl,
|
||||
canImportCreate: this.canCreate,
|
||||
canImportUpdate: this.canBulkUpdate
|
||||
})
|
||||
},
|
||||
iExportOptions() {
|
||||
const options = assignIfNot(this.exportOptions, { url: this.tableUrl })
|
||||
@@ -164,8 +176,4 @@ export default {
|
||||
justify-content:center;
|
||||
}
|
||||
|
||||
.export-item {
|
||||
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div class="table-header clearfix">
|
||||
<div class="table-header clearfix" :class="device">
|
||||
<slot name="header">
|
||||
<LeftSide v-if="hasLeftActions" style="float: left" :class="'left-side ' + device" :selected-rows="selectedRows" :table-url="tableUrl" v-bind="$attrs" v-on="$listeners" />
|
||||
<RightSide v-if="hasRightActions" style="float: right" :selected-rows="selectedRows" :table-url="tableUrl" v-bind="$attrs" v-on="$listeners" />
|
||||
<div style="display: flex;flex-direction: row" class="search" :class="hasLeftActions ? 'right' : 'left'">
|
||||
<LeftSide v-if="hasLeftActions" class="left-side" :selected-rows="selectedRows" :table-url="tableUrl" v-bind="$attrs" v-on="$listeners" />
|
||||
<RightSide v-if="hasRightActions" class="right-side" :selected-rows="selectedRows" :table-url="tableUrl" v-bind="$attrs" v-on="$listeners" />
|
||||
<div class="search" :class="searchClass">
|
||||
<AutoDataSearch v-if="hasSearch" class="right-side-item action-search" v-bind="iSearchTableConfig" @tagSearch="handleTagSearch" />
|
||||
<DatetimeRangePicker v-if="hasDatePicker" v-bind="datePicker" class="datepicker" @dateChange="handleDateChange" />
|
||||
</div>
|
||||
@@ -77,6 +77,9 @@ export default {
|
||||
return 'mobile'
|
||||
}
|
||||
return ''
|
||||
},
|
||||
searchClass() {
|
||||
return this.hasLeftActions ? 'right' : 'left'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -143,11 +146,34 @@ export default {
|
||||
.datepicker{
|
||||
margin-left: 10px;
|
||||
}
|
||||
.left-side {
|
||||
float: left;
|
||||
display: block;
|
||||
line-height: 36px;
|
||||
}
|
||||
.right-side {
|
||||
float: right;
|
||||
}
|
||||
.search {
|
||||
display: flex;
|
||||
flex-direction: row
|
||||
}
|
||||
.mobile .search {
|
||||
display: inherit;
|
||||
}
|
||||
.mobile .search .datepicker {
|
||||
margin-left: 0;
|
||||
}
|
||||
.search.left {
|
||||
float: left;
|
||||
}
|
||||
.search.right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.mobile .search.right {
|
||||
float: left;
|
||||
}
|
||||
.mobile .right-side {
|
||||
padding-top: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -66,15 +66,16 @@ export default {
|
||||
canCreate: { action: 'add', checkRoot: true },
|
||||
canBulkDelete: { action: 'delete', checkRoot: false },
|
||||
canBulkUpdate: { action: 'change', checkRoot: true },
|
||||
hasImport: { action: 'add', checkRoot: true },
|
||||
hasImport: { action: 'add|change', checkRoot: true },
|
||||
hasExport: { action: 'view', checkRoot: false }
|
||||
}
|
||||
const defaults = {}
|
||||
for (const [k, v] of Object.entries(actions)) {
|
||||
defaults[k] = this.hasActionPerm(v.action)
|
||||
let hasPerm = v.action.split('|').some(i => this.hasActionPerm(i.trim()))
|
||||
if (v.checkRoot) {
|
||||
defaults[k] = defaults[k] && !this.currentOrgIsRoot
|
||||
hasPerm = hasPerm && !this.currentOrgIsRoot
|
||||
}
|
||||
defaults[k] = hasPerm
|
||||
}
|
||||
return Object.assign(defaults, this.headerActions)
|
||||
},
|
||||
@@ -192,6 +193,15 @@ export default {
|
||||
& >>> .el-table__header thead > tr > th {
|
||||
background-color: white;
|
||||
}
|
||||
&>>> .el-table__row .cell {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
&>>> .el-table__expanded-cell pre {
|
||||
max-height: 500px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
}
|
||||
|
||||
//修改颜色
|
||||
|
||||
@@ -10,14 +10,14 @@
|
||||
v-on="$listeners"
|
||||
>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="4">
|
||||
<el-col :md="4" :sm="24">
|
||||
<div style="line-height: 34px;text-align: center">MFA</div>
|
||||
</el-col>
|
||||
<el-col :span="14">
|
||||
<el-col :md="14" :sm="24">
|
||||
<el-input v-model="MFAToken" />
|
||||
<span class="help-tips help-block">{{ $t('common.MFARequireForSecurity') }}</span>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-col :md="4" :sm="24">
|
||||
<el-button size="mini" type="primary" style="line-height:20px " @click="verifyMFA">
|
||||
{{ this.$t('common.Confirm') }}
|
||||
</el-button>
|
||||
|
||||
82
src/components/TableFormatters/ShowKeyCopyFormatter.vue
Normal file
82
src/components/TableFormatters/ShowKeyCopyFormatter.vue
Normal file
@@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<div class="content">
|
||||
<span>{{ currentValue }}</span>
|
||||
<span class="right">
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
placement="top"
|
||||
:content="this.$t('common.View')"
|
||||
>
|
||||
<i class="el-icon-view" @click="onShow()" />
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
placement="top"
|
||||
:content="this.$t('common.Copy')"
|
||||
>
|
||||
<i class="el-icon-copy-document" @click="onCopy()" />
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BaseFormatter from './base'
|
||||
|
||||
export default {
|
||||
name: 'ShowKeyCopyFormatter',
|
||||
extends: BaseFormatter,
|
||||
proops: {
|
||||
cellValue: {
|
||||
type: String,
|
||||
default: () => ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentValue: this.switchShowValue()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
switchShowValue() {
|
||||
return '******' + this.cellValue.replace(/[\w-]/g, '')
|
||||
},
|
||||
onShow() {
|
||||
const { currentValue, cellValue, switchShowValue } = this
|
||||
this.currentValue = currentValue === cellValue ? switchShowValue() : cellValue
|
||||
},
|
||||
onCopy: _.throttle(function() {
|
||||
const inputDom = document.createElement('input')
|
||||
inputDom.id = 'creatInputDom'
|
||||
inputDom.value = this.cellValue
|
||||
document.body.appendChild(inputDom)
|
||||
inputDom.select()
|
||||
document?.execCommand('copy')
|
||||
this.$message({
|
||||
message: this.$t('common.CopySuccess'),
|
||||
type: 'success',
|
||||
duration: 1400
|
||||
})
|
||||
document.body.removeChild(inputDom)
|
||||
}, 1800)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.content {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
.right {
|
||||
float: right;
|
||||
font-size: 15px;
|
||||
cursor: pointer;
|
||||
.el-icon-view, .el-icon-copy-document {
|
||||
&:hover {
|
||||
color: #1c84c6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -7,6 +7,7 @@ import DeleteActionFormatter from './DeleteActionFormatter'
|
||||
import DateFormatter from './DateFormatter'
|
||||
import SystemUserFormatter from './GrantedSystemUsersShowFormatter'
|
||||
import ShowKeyFormatter from '@/components/TableFormatters/ShowKeyFormatter'
|
||||
import ShowKeyCopyFormatter from './ShowKeyCopyFormatter'
|
||||
import DialogDetailFormatter from './DialogDetailFormatter'
|
||||
import EditableInputFormatter from './EditableInputFormatter'
|
||||
import StatusFormatter from './StatusFormatter'
|
||||
@@ -21,6 +22,7 @@ export default {
|
||||
DateFormatter,
|
||||
SystemUserFormatter,
|
||||
ShowKeyFormatter,
|
||||
ShowKeyCopyFormatter,
|
||||
DialogDetailFormatter,
|
||||
ArrayFormatter,
|
||||
EditableInputFormatter,
|
||||
@@ -37,6 +39,7 @@ export {
|
||||
DateFormatter,
|
||||
SystemUserFormatter,
|
||||
ShowKeyFormatter,
|
||||
ShowKeyCopyFormatter,
|
||||
DialogDetailFormatter,
|
||||
ArrayFormatter,
|
||||
EditableInputFormatter,
|
||||
|
||||
@@ -4,8 +4,7 @@ import NProgress from 'nprogress' // progress bar
|
||||
import 'nprogress/nprogress.css' // progress bar style
|
||||
import { startup } from '@/utils/startup'
|
||||
import store from '@/store'
|
||||
import { getPropView, hasRouteViewPerm, isSameView } from '@/utils/jms'
|
||||
import Vue from 'vue'
|
||||
import { isSameView } from '@/utils/jms'
|
||||
|
||||
NProgress.configure({
|
||||
showSpinner: false
|
||||
@@ -30,20 +29,6 @@ function generateViewRoutesIfChange({ to, from }) {
|
||||
}
|
||||
}
|
||||
|
||||
async function changeCurrentViewIfNeed({ to, from, next }) {
|
||||
if (!to.path || isSameView(to, from)) {
|
||||
return
|
||||
}
|
||||
const hasPerm = hasRouteViewPerm(to)
|
||||
Vue.$log.debug('Change has current view, has perm: ', hasPerm)
|
||||
if (hasPerm) {
|
||||
return
|
||||
}
|
||||
const view = getPropView()
|
||||
Vue.$log.debug('Get prop view and goto: ', view)
|
||||
next(`/${view}`)
|
||||
}
|
||||
|
||||
function setPageTitle() {
|
||||
const currentRoute = router.currentRoute
|
||||
const loginTitle = store.getters.publicSettings['LOGIN_TITLE']
|
||||
@@ -53,12 +38,6 @@ function setPageTitle() {
|
||||
}
|
||||
}
|
||||
|
||||
router.beforeResolve(async(to, from, next) => {
|
||||
/* must call `next` */
|
||||
await changeCurrentViewIfNeed({ to, from, next })
|
||||
next()
|
||||
})
|
||||
|
||||
router.afterEach(async(to, from) => {
|
||||
// finish progress bar
|
||||
await setPageTitle()
|
||||
|
||||
@@ -26,5 +26,19 @@ export default {
|
||||
year: 'numeric', month: 'short', day: 'numeric',
|
||||
hour: 'numeric', minute: 'numeric', hour12: true
|
||||
}
|
||||
},
|
||||
'ja': {
|
||||
short: {
|
||||
year: 'numeric', month: 'short', day: 'numeric'
|
||||
},
|
||||
medium: {
|
||||
year: 'numeric', month: '2-digit', day: '2-digit',
|
||||
hour: '2-digit', minute: '2-digit', second: '2-digit',
|
||||
hourCycle: 'h23', hour12: false
|
||||
},
|
||||
long: {
|
||||
year: 'numeric', month: 'short', day: 'numeric',
|
||||
hour: 'numeric', minute: 'numeric', hour12: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,12 @@ import date from './date'
|
||||
import VueCookie from 'vue-cookie'
|
||||
|
||||
Vue.use(VueI18n)
|
||||
const cookieLang = VueCookie.get('django_language')
|
||||
const browserLang = navigator.systemLanguage || navigator.language
|
||||
let lang = cookieLang || browserLang || 'zh'
|
||||
lang = lang.slice(0, 2)
|
||||
const i18n = new VueI18n({
|
||||
locale: (VueCookie.get('django_language') || 'zh-hans') === 'zh-hans' ? 'cn' : 'en',
|
||||
locale: lang,
|
||||
fallbackLocale: 'en',
|
||||
silentFallbackWarn: true,
|
||||
silentTranslationWarn: true,
|
||||
|
||||
@@ -314,12 +314,15 @@
|
||||
"Delete": "Delete",
|
||||
"Disable": "Disable",
|
||||
"Download": "Download",
|
||||
"Copy": "Copy",
|
||||
"CopySuccess": "Copy success",
|
||||
"Enable": "Enable",
|
||||
"On/Off": "On/Off",
|
||||
"EnterForSearch": "Press enter to search",
|
||||
"Export": "Export",
|
||||
"Import": "Import",
|
||||
"ContinueImport": "ContinueImport",
|
||||
"ImportAll": "Import All",
|
||||
"Continue": "Continue",
|
||||
"Stop": "Stop",
|
||||
"Finished": "Finished",
|
||||
@@ -416,8 +419,9 @@
|
||||
},
|
||||
"isValid": "Is valid",
|
||||
"nav": {
|
||||
"TempPassword": "Temporary password",
|
||||
"APIKey": "API Key",
|
||||
"Workspace": "Workbench",
|
||||
"Workbench": "Workbench",
|
||||
"Navigation": "Navigation",
|
||||
"Console": "Console",
|
||||
"Audits": "Audit",
|
||||
@@ -534,6 +538,7 @@
|
||||
"Monthly": "Monthly",
|
||||
"OnlineSessions": "Online sessions",
|
||||
"OnlineUsers": "Online users",
|
||||
"ConnectUsers": "Connect users",
|
||||
"TimesWeekUnit": "times/week",
|
||||
"TopAssetsOfWeek": "Top assets of week",
|
||||
"TopUsersOfWeek": "Top user of week",
|
||||
@@ -651,6 +656,10 @@
|
||||
},
|
||||
"route": {
|
||||
"": "",
|
||||
"CreateEndpoint": "Create endpoint",
|
||||
"UpdateEndpoint": "Update endpoint",
|
||||
"CreateEndpointRule": "Create endpoint rule",
|
||||
"UpdateEndpointRule": "Update endpoint rule",
|
||||
"SystemSetting": "System setting",
|
||||
"Index": "Index",
|
||||
"Role": "Role",
|
||||
@@ -767,6 +776,7 @@
|
||||
"Activity": "Activity",
|
||||
"SessionOffline": "Sessions offline",
|
||||
"SessionOnline": "Sessions online",
|
||||
"RecentSession": "Recent session",
|
||||
"Sessions": "Sessions",
|
||||
"Settings": "Settings",
|
||||
"SystemUserCreate": "System user create",
|
||||
@@ -888,6 +898,8 @@
|
||||
}
|
||||
},
|
||||
"setting": {
|
||||
"EnableKoKoSSHHelpText": "Enabled, connect assets to display SSH Client pull-up method",
|
||||
"SettingInEndpointHelpText": "Configure the service address and port in System Settings / Terminal Settings / Service Endpoints",
|
||||
"Feature": "Feature",
|
||||
"SMSProvider": "SMS provider",
|
||||
"SMS": "SMS",
|
||||
@@ -982,6 +994,7 @@
|
||||
"LDAPUser": "LDAP User",
|
||||
"InsecureCommandAlert": "Insecure command alert",
|
||||
"helpText": {
|
||||
"TempPassword": "For a while, there is a period of 300 seconds, failure immediately after use",
|
||||
"ApiKeyList": "The API key is used to sign the request header. The header of each request is different. Please refer to the usage documentation",
|
||||
"authLdapSearchFilter": "Choice may be (cn|uid|sAMAccountName)=%(user)s)",
|
||||
"authLdapSearchOu": "Use | split User OUs",
|
||||
@@ -1057,7 +1070,7 @@
|
||||
"refreshLdapCache":"Refreshing Ldap cache ",
|
||||
"LicenseExpired": "License expired",
|
||||
"LicenseWillBe": "License will expire at ",
|
||||
"Expire": "",
|
||||
"Expire": "Expire",
|
||||
"WeCom": "WeCom",
|
||||
"DingTalk": "DingTalk",
|
||||
"dingTalkTest": "Test",
|
||||
@@ -1264,6 +1277,7 @@
|
||||
"Sender": "Sender",
|
||||
"MarkAsRead": "Mark as read",
|
||||
"OneClickRead": "Currently read",
|
||||
"AllClickRead": "All read",
|
||||
"OneClickReadMsg": "Are you sure you want to mark the current information as read?",
|
||||
"NoUnreadMsg": "No unread messages",
|
||||
"SiteMessage": "Site messages",
|
||||
@@ -1366,6 +1380,8 @@
|
||||
"AWS_China": "AWS(China)",
|
||||
"AWS_Int": "AWS(International)",
|
||||
"HuaweiCloud": "Huawei Cloud",
|
||||
"BaiduCloud": "Baidu Cloud",
|
||||
"JDCloud": "JD Cloud",
|
||||
"Azure":"Azure(China)",
|
||||
"Azure_Int": "Azure(International)",
|
||||
"HostnameStrategy": "Used to produce the asset hostname. For example, 1. Instance name (instanceDemo);2. Instance name and Partial IP (instanceDemo-250.1)",
|
||||
@@ -1432,6 +1448,8 @@
|
||||
"License": "License",
|
||||
"LicenseDetail": "License detail",
|
||||
"ComponentMonitor": "System Monitor",
|
||||
"Endpoint": "Endpoint",
|
||||
"EndpointRule": "Endpoint rule",
|
||||
"ServiceRatio": "Service ratio",
|
||||
"LoadStatus":"Status",
|
||||
"NormalLoad":"Normal",
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
import zhLocale from 'element-ui/lib/locale/lang/zh-CN'
|
||||
import enLocale from 'element-ui/lib/locale/lang/en'
|
||||
import zh from './cn.json'
|
||||
import jaLocale from 'element-ui/lib/locale/lang/ja'
|
||||
import zh from './zh.json'
|
||||
import en from './en.json'
|
||||
import ja from './ja.json'
|
||||
|
||||
export default {
|
||||
cn: {
|
||||
zh: {
|
||||
...zhLocale,
|
||||
...zh
|
||||
},
|
||||
en: {
|
||||
...enLocale,
|
||||
...en
|
||||
},
|
||||
ja: {
|
||||
...jaLocale,
|
||||
...ja
|
||||
}
|
||||
}
|
||||
|
||||
1560
src/i18n/langs/ja.json
Normal file
1560
src/i18n/langs/ja.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,8 @@ import json
|
||||
i18n_report_path = '/tmp/abc.json'
|
||||
lang_paths = {
|
||||
'cn': 'cn.json',
|
||||
'en': 'en.json'
|
||||
'en': 'en.json',
|
||||
'ja': 'ja.json'
|
||||
}
|
||||
|
||||
|
||||
@@ -51,5 +52,5 @@ def remove_keys(lang):
|
||||
f.write(data)
|
||||
|
||||
|
||||
for i in ['cn', 'en']:
|
||||
for i in ['cn', 'en', 'ja']:
|
||||
remove_keys(i)
|
||||
|
||||
@@ -254,6 +254,7 @@
|
||||
"ReLogin": "重新登录"
|
||||
},
|
||||
"common": {
|
||||
"Component": "组件",
|
||||
"PrivateCloud": "私有云",
|
||||
"PublicCloud": "公有云",
|
||||
"Correlation": "关联",
|
||||
@@ -326,12 +327,15 @@
|
||||
"Delete": "删除",
|
||||
"Disable": "禁用",
|
||||
"Download": "下载",
|
||||
"Copy": "复制",
|
||||
"CopySuccess": "复制成功",
|
||||
"Enable": "启用",
|
||||
"On/Off": "启/停",
|
||||
"EnterForSearch": "按回车进行搜索",
|
||||
"Export": "导出",
|
||||
"Import": "导入",
|
||||
"ContinueImport": "继续导入",
|
||||
"ImportAll": "导入全部",
|
||||
"Continue": "继续",
|
||||
"Stop": "停止",
|
||||
"Finished": "完成",
|
||||
@@ -428,8 +432,9 @@
|
||||
"fileType": "文件类型",
|
||||
"isValid": "有效",
|
||||
"nav": {
|
||||
"TempPassword": "临时密码",
|
||||
"APIKey": "API Key",
|
||||
"Workspace": "工作台",
|
||||
"Workbench": "工作台",
|
||||
"Navigation": "导航",
|
||||
"Console": "控制台",
|
||||
"Audits": "审计台",
|
||||
@@ -545,6 +550,7 @@
|
||||
"Monthly": "按月",
|
||||
"OnlineSessions": "在线会话",
|
||||
"OnlineUsers": "在线用户",
|
||||
"ConnectUsers": "连接用户",
|
||||
"TimesWeekUnit": "次/周",
|
||||
"TopAssetsOfWeek": "周资产 TOP10",
|
||||
"TopUsersOfWeek": "周用户 TOP10",
|
||||
@@ -661,6 +667,10 @@
|
||||
},
|
||||
"route": {
|
||||
"": "",
|
||||
"CreateEndpoint": "创建端点",
|
||||
"UpdateEndpoint": "更新端点",
|
||||
"CreateEndpointRule": "创建端点规则",
|
||||
"UpdateEndpointRule": "更新端点规则",
|
||||
"Index": "首页",
|
||||
"SystemSetting": "系统设置",
|
||||
"WorkBench": "工作台",
|
||||
@@ -783,6 +793,7 @@
|
||||
"Detail": "详情",
|
||||
"SessionOffline": "历史会话",
|
||||
"SessionOnline": "在线会话",
|
||||
"RecentSession": "最近会话",
|
||||
"Sessions": "会话管理",
|
||||
"Settings": "系统设置",
|
||||
"SystemUserCreate": "创建系统用户",
|
||||
@@ -909,6 +920,8 @@
|
||||
}
|
||||
},
|
||||
"setting": {
|
||||
"EnableKoKoSSHHelpText": "开启时连接资产会显示 SSH Client 拉起方式",
|
||||
"SettingInEndpointHelpText": "在 系统设置 / 终端设置 / 服务端点 中配置服务地址和端口",
|
||||
"Feature": "功能",
|
||||
"AlibabaCloud": "阿里云",
|
||||
"TencentCloud": "腾讯云",
|
||||
@@ -1008,6 +1021,7 @@
|
||||
"LDAPServerInfo": "LDAP 服务器",
|
||||
"LDAPUser": "LDAP 用户",
|
||||
"helpText": {
|
||||
"TempPassword": "临时密码有效期为 300 秒,使用后立刻失效",
|
||||
"ApiKeyList": "使用api key签名请求头,每个请求的头部是不一样的, 请查阅使用文档",
|
||||
"authLdapSearchFilter": "可能的选项是(cn或uid或sAMAccountName=%(user)s)",
|
||||
"authLdapSearchOu": "使用|分隔各OU",
|
||||
@@ -1304,6 +1318,7 @@
|
||||
"Sender": "发送人",
|
||||
"MarkAsRead": "标记已读",
|
||||
"OneClickRead": "当前已读",
|
||||
"AllClickRead": "全部已读",
|
||||
"OneClickReadMsg": "你确定要将当前信息标记为已读吗?",
|
||||
"NoUnreadMsg": "暂无未读消息",
|
||||
"SiteMessage": "站内信",
|
||||
@@ -1409,6 +1424,8 @@
|
||||
"AWS_China": "AWS(中国)",
|
||||
"AWS_Int": "AWS(国际)",
|
||||
"HuaweiCloud": "华为云",
|
||||
"BaiduCloud": "百度云",
|
||||
"JDCloud": "京东云",
|
||||
"Azure":"Azure(中国)",
|
||||
"Azure_Int": "Azure(国际)",
|
||||
"HostnameStrategy": "用于生成资产主机名。例如:1. 实例名称 (instanceDemo);2. 实例名称和部分IP(后两位) (instanceDemo-250.1)",
|
||||
@@ -1477,6 +1494,8 @@
|
||||
"InterfaceSettings": "界面设置",
|
||||
"License": "许可证",
|
||||
"ComponentMonitor": "组件监控",
|
||||
"Endpoint": "服务端点",
|
||||
"EndpointRule": "端点规则",
|
||||
"ServiceRatio": "组件负载统计",
|
||||
"LoadStatus":"组件状态",
|
||||
"NormalLoad":"正常",
|
||||
@@ -7,15 +7,22 @@
|
||||
:show-cancel="false"
|
||||
:show-confirm="false"
|
||||
>
|
||||
<el-row>
|
||||
<el-col :span="4">
|
||||
<el-row :gutter="20">
|
||||
<el-col :md="4" :sm="24">
|
||||
<div class="select-prop-label">
|
||||
<label>{{ selectPropertiesLabel }}</label>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="18">
|
||||
<el-col :md="18" :sm="24">
|
||||
<el-checkbox-group v-model="checkedFields" @change="handleCheckedFieldsChange">
|
||||
<el-checkbox v-for="(value, name) in iFormSetting.fieldsMeta" :key="name" :checked="true" :label="name">{{ value.label }}</el-checkbox>
|
||||
<el-checkbox
|
||||
v-for="(value, name) in iFormSetting.fieldsMeta"
|
||||
:key="name"
|
||||
:checked="true"
|
||||
:label="name"
|
||||
>
|
||||
{{ value.label }}
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -90,10 +97,10 @@ export default {
|
||||
getDefaultFormSetting() {
|
||||
const vm = this
|
||||
return {
|
||||
submitMethod: () => 'post',
|
||||
submitMethod: () => 'patch',
|
||||
cleanFormValue: function(value) {
|
||||
const filterValue = {}
|
||||
Object.keys(value).filter((key) => vm.checkedFields.includes(key)).forEach((key) => {
|
||||
Object.keys(value).filter((key) => vm.checkedFields?.includes(key)).forEach((key) => {
|
||||
filterValue[key] = value[key]
|
||||
})
|
||||
const formValue = []
|
||||
|
||||
@@ -7,9 +7,18 @@
|
||||
<i class="el-icon-arrow-down el-icon--right" />
|
||||
</span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item icon="el-icon-user" command="profile">{{ $t('common.nav.Profile') }}</el-dropdown-item>
|
||||
<el-dropdown-item v-if="$hasPerm('authentication.view_accesskey')" icon="el-icon-key" command="apiKey">{{ $t('common.nav.APIKey') }}</el-dropdown-item>
|
||||
<el-dropdown-item divided command="logout"><svg-icon icon-class="logout" style="margin-right: 4px" />{{ $t('common.nav.Logout') }}</el-dropdown-item>
|
||||
<el-dropdown-item icon="el-icon-user" command="profile">
|
||||
{{ $t('common.nav.Profile') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="$hasPerm('authentication.view_accesskey')" icon="el-icon-key" command="apiKey">
|
||||
{{ $t('common.nav.APIKey') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="$store.getters.publicSettings.AUTH_TEMP_TOKEN && $hasPerm('authentication.view_temptoken')" icon="el-icon-magic-stick" command="tempPassword">
|
||||
{{ $t('common.nav.TempPassword') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item divided command="logout"><svg-icon icon-class="logout" style="margin-right: 4px" />
|
||||
{{ $t('common.nav.Logout') }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
@@ -28,11 +37,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'currentUser',
|
||||
'currentRole',
|
||||
'currentOrgRoles',
|
||||
'orgs',
|
||||
'currentOrgPerms'
|
||||
'currentUser'
|
||||
])
|
||||
},
|
||||
created() {
|
||||
@@ -50,6 +55,8 @@ export default {
|
||||
case 'apiKey':
|
||||
this.$router.push('/profile/key')
|
||||
break
|
||||
case 'tempPassword':
|
||||
this.$router.push('/profile/temp-password')
|
||||
}
|
||||
},
|
||||
logout() {
|
||||
|
||||
@@ -25,6 +25,11 @@ export default {
|
||||
title: '中文(简体)',
|
||||
code: 'cn',
|
||||
cookieCode: 'zh-hans' // cookie code是为了让后端知道当前语言
|
||||
},
|
||||
{
|
||||
title: '日本語',
|
||||
code: 'ja',
|
||||
cookieCode: 'ja' // cookie code是为了让后端知道当前语言
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -58,6 +63,8 @@ export default {
|
||||
changeMomentLang() {
|
||||
if (this.currentLang.code.indexOf('en') > -1) {
|
||||
this.$moment.locale('en')
|
||||
} else if (this.currentLang.code.indexOf('ja') > -1) {
|
||||
this.$moment.locale('ja')
|
||||
} else {
|
||||
this.$moment.locale('zh-cn')
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<el-select
|
||||
:value="currentOrg.id"
|
||||
:value="currentOrgId"
|
||||
class="org-select organization"
|
||||
filterable
|
||||
:placeholder="$t('common.Select')"
|
||||
@@ -11,7 +11,7 @@
|
||||
</template>
|
||||
|
||||
<el-option-group
|
||||
v-for="group in orgOption"
|
||||
v-for="group in orgGroups"
|
||||
:key="group.label"
|
||||
:label="group.label"
|
||||
class="option-group"
|
||||
@@ -29,7 +29,6 @@
|
||||
</span>
|
||||
<span>{{ item.name }}</span>
|
||||
</el-option>
|
||||
|
||||
</el-option-group>
|
||||
</el-select>
|
||||
</template>
|
||||
@@ -55,15 +54,10 @@ export default {
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'currentOrg',
|
||||
'currentRole',
|
||||
'orgs'
|
||||
])
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
'usingOrgs',
|
||||
'currentViewRoute'
|
||||
]),
|
||||
orgActionsGroup() {
|
||||
const orgActions = {
|
||||
label: this.$t('xpack.Organization.OrganizationList'),
|
||||
options: [
|
||||
@@ -82,21 +76,44 @@ export default {
|
||||
]
|
||||
}
|
||||
const hasPerms = this.$hasPerm('orgs.view_organization | orgs.add_organization')
|
||||
this.orgOption = [
|
||||
(hasPerms && orgActions),
|
||||
{
|
||||
label: this.$t('xpack.Organization.AllOrganization'),
|
||||
options: this.orgs
|
||||
}
|
||||
const isConsole = this.currentViewRoute.name === 'console'
|
||||
return hasPerms && isConsole ? orgActions : {}
|
||||
},
|
||||
orgChoicesGroup() {
|
||||
return {
|
||||
label: this.$t('xpack.Organization.AllOrganization'),
|
||||
options: this.usingOrgs
|
||||
}
|
||||
},
|
||||
orgGroups() {
|
||||
return [
|
||||
this.orgActionsGroup,
|
||||
this.orgChoicesGroup
|
||||
]
|
||||
},
|
||||
currentOrgId() {
|
||||
const usingOrgIds = this.usingOrgs.map(o => o.id)
|
||||
let currentOrgId = this.currentOrg.id
|
||||
const find = usingOrgIds.indexOf(currentOrgId) > -1
|
||||
if (!find) {
|
||||
currentOrgId = null
|
||||
}
|
||||
return currentOrgId
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeOrg(orgId) {
|
||||
if (orgId === 'create') {
|
||||
this.$router.push({ name: 'OrganizationCreate' })
|
||||
} else if (orgId === 'list') {
|
||||
this.$router.push({ name: 'OrganizationList' })
|
||||
} else {
|
||||
orgUtil.changeOrg(orgId)
|
||||
const org = this.usingOrgs.find(item => item.id === orgId)
|
||||
|
||||
switch (orgId) {
|
||||
case 'create':
|
||||
this.$router.push({ name: 'OrganizationCreate' })
|
||||
break
|
||||
case 'list':
|
||||
this.$router.push({ name: 'OrganizationList' })
|
||||
break
|
||||
default:
|
||||
orgUtil.changeOrg(org)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,25 +163,25 @@ export default {
|
||||
background-color: rgba(144, 147, 152, .5);
|
||||
}
|
||||
|
||||
& > > > .el-input__prefix {
|
||||
&>>> .el-input__prefix {
|
||||
left: 8px
|
||||
}
|
||||
|
||||
& > > > .el-input--prefix .el-input__inner {
|
||||
&>>> .el-input--prefix .el-input__inner {
|
||||
line-height: 35px !important;
|
||||
height: 35px !important;
|
||||
}
|
||||
|
||||
& > > > .fa-sitemap {
|
||||
&>>> .fa-sitemap {
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
& > > > .el-input__icon {
|
||||
&>>> .el-input__icon {
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
|
||||
.option-group > > > .el-select-group__title {
|
||||
.option-group >>> .el-select-group__title {
|
||||
color: #909399 !important;
|
||||
padding-left: 15px;
|
||||
font-size: 12px;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
</el-link>
|
||||
</el-badge>
|
||||
<el-drawer
|
||||
class="drawer"
|
||||
:visible.sync="show"
|
||||
:before-close="handleClose"
|
||||
:modal="false"
|
||||
@@ -17,7 +18,7 @@
|
||||
<div slot="title">
|
||||
<span>{{ $t('notifications.SiteMessage') }}</span>
|
||||
<div v-if="unreadMsgCount !== 0" class="msg-list-all-read-btn" @click.stop="oneClickRead(messages)">
|
||||
<a> {{ $t('notifications.OneClickRead') }}</a>
|
||||
<a style="vertical-align: sub;"> {{ $t('notifications.AllClickRead') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="unreadMsgCount !== 0" class="msg-list">
|
||||
@@ -137,13 +138,22 @@ export default {
|
||||
confirmButtonClass: 'el-button--danger',
|
||||
beforeClose: async(action, instance, done) => {
|
||||
if (action !== 'confirm') return done()
|
||||
this.markAsRead(msgs)
|
||||
this.markAsReadAll(msgs)
|
||||
done()
|
||||
}
|
||||
}).catch(() => {
|
||||
/* 取消*/
|
||||
})
|
||||
},
|
||||
markAsReadAll(msgs) {
|
||||
const url = `/api/v1/notifications/site-message/mark-as-read-all/`
|
||||
this.$axios.patch(url, {}).then(res => {
|
||||
this.msgDetailVisible = false
|
||||
this.getMessages()
|
||||
}).catch(err => {
|
||||
this.$message(err.detail)
|
||||
})
|
||||
},
|
||||
markAsRead(msgs) {
|
||||
const url = `/api/v1/notifications/site-message/mark-as-read/`
|
||||
const msgIds = []
|
||||
@@ -192,6 +202,9 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.drawer {
|
||||
height: calc(100% - 40px);
|
||||
}
|
||||
.el-badge ::v-deep .el-badge__content.is-fixed{
|
||||
top:10px;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<template>
|
||||
<el-menu
|
||||
default-active="activeIndex"
|
||||
:default-active="currentViewRoute.name"
|
||||
class="menu-main"
|
||||
mode="horizontal"
|
||||
:class="mode"
|
||||
:mode="mode"
|
||||
@select="handleSelectView"
|
||||
>
|
||||
<el-submenu
|
||||
@@ -18,10 +19,9 @@
|
||||
<el-menu-item
|
||||
v-for="view of views"
|
||||
:key="view.name"
|
||||
v-perms="view.perms"
|
||||
:index="view.name"
|
||||
>
|
||||
<i class="icons" :class="view.meta.icon" />
|
||||
<i v-if="mode === 'horizontal'" class="icons" :class="view.meta.icon" />
|
||||
<span slot="title" class="icons-title">{{ view.meta.title }}</span>
|
||||
</el-menu-item>
|
||||
</el-submenu>
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import store from '@/store'
|
||||
|
||||
export default {
|
||||
name: 'ViewSwitcher',
|
||||
@@ -37,19 +38,30 @@ export default {
|
||||
showTitle: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'horizontal'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
return {
|
||||
showTip: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'currentViewRoute'
|
||||
'currentViewRoute',
|
||||
'viewRoutes'
|
||||
]),
|
||||
views() {
|
||||
return this.$store.state.permission.addRoutes.filter(
|
||||
item => item.meta?.showNavSwitcher
|
||||
)
|
||||
return this.viewRoutes.filter((item) => {
|
||||
let show = item.meta?.showNavSwitcher
|
||||
if (typeof show === 'function') {
|
||||
show = show()
|
||||
}
|
||||
return show
|
||||
})
|
||||
},
|
||||
viewsMapper() {
|
||||
const mapper = {}
|
||||
@@ -62,11 +74,12 @@ export default {
|
||||
return this.viewsMapper[this.currentViewRoute.name]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
},
|
||||
methods: {
|
||||
handleSelectView(key, keyPath) {
|
||||
async handleSelectView(key, keyPath) {
|
||||
const routeName = this.viewsMapper[key] || '/'
|
||||
localStorage.setItem('PreView', key)
|
||||
// Next 之前要重置 init 状态,否则这些路由守卫就不走了
|
||||
await store.dispatch('app/reset')
|
||||
this.$router.push(routeName)
|
||||
}
|
||||
}
|
||||
@@ -131,4 +144,7 @@ export default {
|
||||
.el-menu-item.is-active {
|
||||
font-weight: bold;
|
||||
}
|
||||
.menu-main.mobile-view-switch >>> .el-submenu__icon-arrow {
|
||||
right: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<Logo v-if="showLogo" :collapse="isCollapse" />
|
||||
</div>
|
||||
<div class="active-mobile">
|
||||
<ViewSwitcher />
|
||||
<ViewSwitcher mode="vertical" class="mobile-view-switch" />
|
||||
<Organization class="organization" />
|
||||
</div>
|
||||
<div class="nav-title" :class="{'collapsed': isCollapse}">
|
||||
@@ -174,6 +174,9 @@ export default {
|
||||
&>>> .menu-main {
|
||||
margin-left: -10px;
|
||||
}
|
||||
&>>> .title-label {
|
||||
color: white !important;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 992px) {
|
||||
.active-mobile {
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
</template>
|
||||
</PageHeading>
|
||||
<PageContent>
|
||||
<el-alert v-if="helpMessage" type="success"> <span v-html="helpMessage" /> </el-alert>
|
||||
<el-alert v-if="helpMessage" type="success">
|
||||
<span class="announcement-main" v-html="helpMessage" />
|
||||
</el-alert>
|
||||
<slot />
|
||||
</PageContent>
|
||||
</div>
|
||||
@@ -34,7 +36,6 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
iTitle() {
|
||||
// return ''
|
||||
return this.title || this.$route.meta.title
|
||||
}
|
||||
}
|
||||
@@ -52,5 +53,9 @@ export default {
|
||||
.print-margin{
|
||||
margin-top: 10px;
|
||||
}
|
||||
.announcement-main {
|
||||
word-wrap:break-word;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -30,8 +30,12 @@
|
||||
</el-tab-pane>
|
||||
</template>
|
||||
</el-tabs>
|
||||
<transition name="fade-transform" mode="out-in">
|
||||
<slot />
|
||||
<transition name="fade-transform" mode="out-in" appear>
|
||||
<slot>
|
||||
<keep-alive>
|
||||
<component :is="computeActiveComponent" />
|
||||
</keep-alive>
|
||||
</slot>
|
||||
</transition>
|
||||
</div>
|
||||
</Page>
|
||||
@@ -76,9 +80,19 @@ export default {
|
||||
}
|
||||
})
|
||||
return map
|
||||
},
|
||||
computeActiveComponent() {
|
||||
let needActiveComponent = ''
|
||||
for (const i of this.submenu) {
|
||||
if (i.component && (i.name === this.iActiveMenu)) {
|
||||
needActiveComponent = i.component
|
||||
break
|
||||
}
|
||||
}
|
||||
return needActiveComponent
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
created() {
|
||||
this.iActiveMenu = this.getPropActiveTab()
|
||||
},
|
||||
methods: {
|
||||
@@ -103,10 +117,10 @@ export default {
|
||||
]
|
||||
|
||||
for (const preTab of preActiveTabs) {
|
||||
const currentTab = typeof preTab === 'object' ? preTab.name : preTab
|
||||
const currentTab = typeof preTab === 'object' ? preTab?.name : preTab
|
||||
for (const tabName of this.tabIndices) {
|
||||
const currentTabName = tabName?.name || ''
|
||||
if (currentTab && currentTabName && currentTab.toLowerCase() === currentTabName.toLowerCase()) {
|
||||
if (currentTab?.toLowerCase() === currentTabName?.toLowerCase()) {
|
||||
return currentTabName
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import i18n from '@/i18n/i18n'
|
||||
import SessionRoutes from './sessions'
|
||||
import LogRoutes from './logs'
|
||||
import empty from '@/layout/empty'
|
||||
import store from '@/store'
|
||||
|
||||
export default {
|
||||
path: '/audit/',
|
||||
@@ -13,8 +14,10 @@ export default {
|
||||
meta: {
|
||||
title: i18n.t('common.nav.Audits'),
|
||||
icon: 'el-icon-s-claim',
|
||||
showNavSwitcher: true,
|
||||
permissions: ['rbac.view_audit'],
|
||||
showNavSwitcher: () => {
|
||||
return store.getters.auditOrgs.length > 0
|
||||
},
|
||||
permissions: [],
|
||||
view: 'audit'
|
||||
},
|
||||
children: [
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Layout from '@/layout/index'
|
||||
import i18n from '@/i18n/i18n'
|
||||
import empty from '@/layout/empty'
|
||||
import store from '@/store'
|
||||
|
||||
import UsersRoute from './users'
|
||||
import AssetsRoute from './assets'
|
||||
@@ -20,8 +21,10 @@ export default {
|
||||
icon: 'el-icon-s-operation',
|
||||
view: 'console',
|
||||
type: 'view',
|
||||
showNavSwitcher: true,
|
||||
permissions: ['rbac.view_console']
|
||||
showNavSwitcher: () => {
|
||||
return store.getters.consoleOrgs.length > 0
|
||||
},
|
||||
permissions: []
|
||||
},
|
||||
children: [
|
||||
{
|
||||
|
||||
@@ -50,15 +50,15 @@ export const constantRoutes = [
|
||||
icon: 'dashboard',
|
||||
title: i18n.t('route.Overview')
|
||||
},
|
||||
beforeEnter: (to, from, next) => {
|
||||
console.log('Enter home view')
|
||||
const preferView = getPermedPreferView()
|
||||
beforeEnter: async(to, from, next) => {
|
||||
const preferView = getPropView()
|
||||
if (preferView) {
|
||||
console.log('Go to preferView: ', preferView)
|
||||
await store.dispatch('app/reset')
|
||||
next(`/${preferView}/`)
|
||||
return false
|
||||
}
|
||||
next()
|
||||
return false
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -79,11 +79,12 @@ export const constantRoutes = [
|
||||
// 权限路由
|
||||
import consoleViewRoutes from './console'
|
||||
import auditViewRoutes from './audit'
|
||||
import workspaceViewRoutes from './workspace'
|
||||
import workbenchViewRoutes from './workbench'
|
||||
import ticketsRoutes from './tickets'
|
||||
import settingsRoutes from './settings'
|
||||
import profileRoutes from './profile'
|
||||
import { getPermedPreferView } from '@/utils/jms'
|
||||
import { getPropView } from '@/utils/jms'
|
||||
import store from '@/store'
|
||||
|
||||
/**
|
||||
* admin
|
||||
@@ -92,7 +93,7 @@ import { getPermedPreferView } from '@/utils/jms'
|
||||
export const viewRoutes = [
|
||||
consoleViewRoutes,
|
||||
auditViewRoutes,
|
||||
workspaceViewRoutes,
|
||||
workbenchViewRoutes,
|
||||
ticketsRoutes,
|
||||
settingsRoutes,
|
||||
profileRoutes
|
||||
|
||||
@@ -53,6 +53,17 @@ export default {
|
||||
resource: 'accesskey',
|
||||
app: 'authentication'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/profile/temp-password',
|
||||
component: () => import('@/views/profile/TempPassword'),
|
||||
name: 'TempPassword',
|
||||
meta: {
|
||||
title: i18n.t('common.nav.TempPassword'),
|
||||
icon: 'magic',
|
||||
hidden: ({ settings }) => !settings['AUTH_TEMP_TOKEN'],
|
||||
permissions: ['authentication.view_temptoken']
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ export default {
|
||||
component: () => import('@/views/settings/Terminal'),
|
||||
meta: {
|
||||
title: i18n.t('setting.Terminal'),
|
||||
icon: 'terminal',
|
||||
icon: 'tasks',
|
||||
permissions: ['settings.change_terminal']
|
||||
}
|
||||
},
|
||||
@@ -152,6 +152,50 @@ export default {
|
||||
permissions: ['terminal.change_commandstorage']
|
||||
},
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'endpoint/create',
|
||||
name: 'EndpointCreate',
|
||||
component: () => import('@/views/settings/Terminal/Endpoint/EndpointCreateUpdate'),
|
||||
meta: {
|
||||
title: i18n.t('route.CreateEndpoint'),
|
||||
activeMenu: '/settings/terminal',
|
||||
permissions: ['terminal.add_endpoint']
|
||||
},
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'endpoint/:id/update',
|
||||
name: 'EndpointUpdate',
|
||||
component: () => import('@/views/settings/Terminal/Endpoint/EndpointCreateUpdate'),
|
||||
meta: {
|
||||
title: i18n.t('route.UpdateEndpoint'),
|
||||
activeMenu: '/settings/terminal',
|
||||
permissions: ['terminal.change_endpoint']
|
||||
},
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'endpoint-rule/create',
|
||||
name: 'EndpointRuleCreate',
|
||||
component: () => import('@/views/settings/Terminal/EndpointRule/EndpointRuleCreateUpdate'),
|
||||
meta: {
|
||||
title: i18n.t('route.CreateEndpointRule'),
|
||||
activeMenu: '/settings/terminal',
|
||||
permissions: ['terminal.add_endpointrule']
|
||||
},
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'endpoint-rule/:id/update',
|
||||
name: 'EndpointRuleUpdate',
|
||||
component: () => import('@/views/settings/Terminal/EndpointRule/EndpointRuleCreateUpdate'),
|
||||
meta: {
|
||||
title: i18n.t('route.UpdateEndpointRule'),
|
||||
activeMenu: '/settings/terminal',
|
||||
permissions: ['terminal.change_endpointrule']
|
||||
},
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -2,25 +2,28 @@ import Layout from '@/layout'
|
||||
import i18n from '@/i18n/i18n'
|
||||
import { BASE_URL } from '@/utils/common'
|
||||
import empty from '@/layout/empty'
|
||||
import store from '@/store'
|
||||
|
||||
export default {
|
||||
path: '/workspace/',
|
||||
path: '/workbench/',
|
||||
component: Layout,
|
||||
name: 'workspace',
|
||||
redirect: '/workspace/home',
|
||||
name: 'workbench',
|
||||
redirect: '/workbench/home',
|
||||
meta: {
|
||||
title: i18n.t('common.nav.Workspace'),
|
||||
title: i18n.t('common.nav.Workbench'),
|
||||
type: 'view',
|
||||
view: 'workspace',
|
||||
view: 'workbench',
|
||||
icon: 'el-icon-user-solid',
|
||||
showNavSwitcher: true,
|
||||
showNavSwitcher: () => {
|
||||
return store.getters.workbenchOrgs.length > 0
|
||||
},
|
||||
showOrganization: true,
|
||||
permissions: ['rbac.view_workspace']
|
||||
permissions: []
|
||||
},
|
||||
children: [
|
||||
// 404 page must be placed at the end !!!
|
||||
{
|
||||
path: '/workspace/home',
|
||||
path: '/workbench/home',
|
||||
name: 'MyHome',
|
||||
component: () => import('@/views/myhome'),
|
||||
meta: {
|
||||
@@ -30,7 +33,7 @@ export default {
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/workspace/assets',
|
||||
path: '/workbench/assets',
|
||||
name: 'MyAssets',
|
||||
component: () => import('@/views/myassets'),
|
||||
meta: {
|
||||
@@ -40,7 +43,7 @@ export default {
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/workspace/apps',
|
||||
path: '/workbench/apps',
|
||||
name: 'Apps',
|
||||
component: empty,
|
||||
redirect: 'remoteapp',
|
||||
@@ -82,7 +85,7 @@ export default {
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/workspace/ops',
|
||||
path: '/workbench/ops',
|
||||
component: empty,
|
||||
meta: {
|
||||
permissions: ['ops.add_commandexecution'],
|
||||
@@ -1,7 +1,13 @@
|
||||
const getters = {
|
||||
sidebar: state => state.app.sidebar,
|
||||
device: state => state.app.device,
|
||||
inited: state => state.app.inited,
|
||||
isMobile: state => state.app.device === 'mobile',
|
||||
token: state => state.users.token,
|
||||
consoleOrgs: state => state.users.consoleOrgs,
|
||||
auditOrgs: state => state.users.auditOrgs,
|
||||
workbenchOrgs: state => state.users.workbenchOrgs,
|
||||
usingOrgs: state => state.users.usingOrgs,
|
||||
currentOrg: state => state.users.currentOrg,
|
||||
currentOrgIsDefault: state => state.users.currentOrg['is_default'],
|
||||
currentOrgIsRoot: state => {
|
||||
@@ -10,6 +16,7 @@ const getters = {
|
||||
currentRole: state => state.users.currentRole,
|
||||
currentUser: state => state.users.profile,
|
||||
currentViewRoute: state => state.permission.currentViewRoute,
|
||||
viewRoutes: state => state.permission.addRoutes,
|
||||
publicSettings: state => state.settings.publicSettings,
|
||||
currentOrgRoles: state => state.users.roles,
|
||||
currentOrgPerms: state => state.users.perms,
|
||||
@@ -18,7 +25,6 @@ const getters = {
|
||||
tableConfig: state => state.table.tableConfig,
|
||||
currentUserIsSuperAdmin: state => state.users.isSuperAdmin,
|
||||
currentUserIsAdmin: state => state.users.isAdmin,
|
||||
hasValidLicense: state => state.settings.hasValidLicense,
|
||||
orgs: state => state.users.orgs
|
||||
hasValidLicense: state => state.settings.hasValidLicense
|
||||
}
|
||||
export default getters
|
||||
|
||||
@@ -5,7 +5,8 @@ const state = {
|
||||
opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
|
||||
withoutAnimation: false
|
||||
},
|
||||
device: 'desktop'
|
||||
device: 'desktop',
|
||||
inited: false
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
@@ -25,6 +26,9 @@ const mutations = {
|
||||
},
|
||||
TOGGLE_DEVICE: (state, device) => {
|
||||
state.device = device
|
||||
},
|
||||
SET_INIT: (state, value) => {
|
||||
state.inited = value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +41,12 @@ const actions = {
|
||||
},
|
||||
toggleDevice({ commit }, device) {
|
||||
commit('TOGGLE_DEVICE', device)
|
||||
},
|
||||
init({ commit }) {
|
||||
commit('SET_INIT', true)
|
||||
},
|
||||
reset({ commit }) {
|
||||
commit('SET_INIT', false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -193,9 +193,6 @@ const actions = {
|
||||
break
|
||||
}
|
||||
}
|
||||
if (viewRoute.meta?.showNavSwitcher) {
|
||||
localStorage.setItem('PreView', viewName)
|
||||
}
|
||||
commit('SET_VIEW_ROUTE', viewRoute)
|
||||
resolve(viewRoute)
|
||||
})
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { logout, getProfile } from '@/api/users'
|
||||
import { logout, getProfile as apiGetProfile } from '@/api/users'
|
||||
import {
|
||||
getCurrentOrgLocal,
|
||||
getCurrentRoleLocal,
|
||||
getTokenFromCookie,
|
||||
saveCurrentOrgLocal,
|
||||
saveCurrentRoleLocal
|
||||
saveCurrentOrgLocal
|
||||
} from '@/utils/auth'
|
||||
import { resetRouter } from '@/router'
|
||||
import Vue from 'vue'
|
||||
|
||||
const getDefaultState = () => {
|
||||
return {
|
||||
@@ -14,10 +13,14 @@ const getDefaultState = () => {
|
||||
currentOrg: '',
|
||||
profile: {},
|
||||
username: '',
|
||||
orgs: [],
|
||||
auditOrgs: [],
|
||||
consoleOrgs: [],
|
||||
workbenchOrgs: [],
|
||||
usingOrgs: [],
|
||||
perms: [],
|
||||
MFAVerifyAt: null,
|
||||
isSuperAdmin: false,
|
||||
isAdmin: false,
|
||||
hasAdminPerm: false,
|
||||
hasAuditPerm: false
|
||||
}
|
||||
@@ -34,57 +37,37 @@ const mutations = {
|
||||
},
|
||||
SET_PROFILE: (state, profile) => {
|
||||
state.profile = profile
|
||||
const username = profile.username
|
||||
state.username = username
|
||||
state.currentOrg = getCurrentOrgLocal(username)
|
||||
state.currentRole = getCurrentRoleLocal(username)
|
||||
state.username = profile.username
|
||||
state.perms = profile.perms
|
||||
state.orgs = profile.orgs
|
||||
state.consoleOrgs = profile['console_orgs']
|
||||
state.workbenchOrgs = profile['workbench_orgs']
|
||||
state.auditOrgs = profile['audit_orgs']
|
||||
state.currentOrg = getCurrentOrgLocal(profile.username)
|
||||
},
|
||||
SET_ORGS: (state, orgs) => {
|
||||
state.orgs = orgs
|
||||
SET_USING_ORGS: (state, orgs) => {
|
||||
state.usingOrgs = orgs
|
||||
},
|
||||
MODIFY_ORG: (state, org) => {
|
||||
state.orgs = state.orgs.map(oldOrg => {
|
||||
state.consoleOrgs = state.consoleOrgs.map(oldOrg => {
|
||||
if (oldOrg.id === org.id) {
|
||||
oldOrg.name = org.name
|
||||
}
|
||||
return oldOrg
|
||||
}
|
||||
)
|
||||
})
|
||||
},
|
||||
ADD_ORG: (state, org) => {
|
||||
state.orgs.push(org)
|
||||
state.consoleOrgs.push(org)
|
||||
},
|
||||
SET_CURRENT_ORG(state, org) {
|
||||
state.currentOrg = org
|
||||
saveCurrentOrgLocal(state.username, org)
|
||||
},
|
||||
SET_CURRENT_ROLE(state, role) {
|
||||
state.currentRole = role
|
||||
saveCurrentRoleLocal(state.username, role)
|
||||
},
|
||||
SET_MFA_VERIFY(state) {
|
||||
state.MFAVerifyAt = (new Date()).valueOf()
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
// user login
|
||||
// login({ commit }, userInfo) {
|
||||
// const { username, password } = userInfo
|
||||
// return new Promise((resolve, reject) => {
|
||||
// login({ username: username.trim(), password: password }).then(response => {
|
||||
// const { data } = response
|
||||
// commit('SET_TOKEN', data.token)
|
||||
// setToken(data.token)
|
||||
// resolve()
|
||||
// }).catch(error => {
|
||||
// reject(error)
|
||||
// })
|
||||
// })
|
||||
// },
|
||||
|
||||
// get user Profile
|
||||
getProfile({ commit, state }, refresh = false) {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -92,7 +75,7 @@ const actions = {
|
||||
resolve(state.profile)
|
||||
return
|
||||
}
|
||||
getProfile().then(response => {
|
||||
apiGetProfile().then(response => {
|
||||
if (!response) {
|
||||
reject('Verification failed, please Login again.')
|
||||
}
|
||||
@@ -104,18 +87,6 @@ const actions = {
|
||||
})
|
||||
})
|
||||
},
|
||||
getInOrgs({ commit, dispatch, state }, refresh) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!refresh && state.role && state.role.length > 0) {
|
||||
return resolve(state.roles)
|
||||
}
|
||||
dispatch('getProfile').then(profile => {
|
||||
const { orgs } = profile
|
||||
commit('SET_ORGS', orgs)
|
||||
resolve(orgs)
|
||||
}).catch((e) => reject(e))
|
||||
})
|
||||
},
|
||||
addAdminOrg({ commit, state }, org) {
|
||||
commit('ADD_ORG', org)
|
||||
},
|
||||
@@ -135,23 +106,22 @@ const actions = {
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// remove token
|
||||
resetToken({ commit }) {
|
||||
return new Promise(resolve => {
|
||||
// removeToken() // must remove token first
|
||||
commit('RESET_STATE')
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
setCurrentOrg({ commit }, data) {
|
||||
commit('SET_CURRENT_ORG', data)
|
||||
},
|
||||
setCurrentRole({ commit }, role) {
|
||||
commit('SET_CURRENT_ROLE', role)
|
||||
},
|
||||
setMFAVerify({ commit }) {
|
||||
commit('SET_MFA_VERIFY')
|
||||
},
|
||||
changeToView({ commit }, viewName) {
|
||||
const mapper = {
|
||||
console: state.consoleOrgs,
|
||||
audit: state.auditOrgs,
|
||||
workbench: state.workbenchOrgs,
|
||||
tickets: state.consoleOrgs
|
||||
}
|
||||
const usingOrgs = mapper[viewName] || state.consoleOrgs
|
||||
Vue.$log.debug('Set using orgs: ', viewName, usingOrgs)
|
||||
commit('SET_USING_ORGS', usingOrgs)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -170,3 +170,11 @@ input[type=file] {
|
||||
min-width: 70px!important;
|
||||
}
|
||||
}
|
||||
|
||||
.el-col.el-col-sm-24 .ibox {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.el-pagination {
|
||||
overflow: auto;
|
||||
}
|
||||
@@ -5,7 +5,11 @@ const CURRENT_ORG_KEY = 'jms_current_org'
|
||||
const CURRENT_ROLE_KEY = 'jms_current_role'
|
||||
|
||||
export function getTokenFromCookie() {
|
||||
return VueCookie.get(TOKEN_KEY)
|
||||
let cookieNamePrefix = VueCookie.get('SESSION_COOKIE_NAME_PREFIX')
|
||||
if (!cookieNamePrefix || ['""', "''"].indexOf(cookieNamePrefix) > -1) {
|
||||
cookieNamePrefix = ''
|
||||
}
|
||||
return VueCookie.get(cookieNamePrefix + TOKEN_KEY)
|
||||
}
|
||||
|
||||
export function getCurrentRoleLocal(username) {
|
||||
|
||||
@@ -33,7 +33,7 @@ function readableSecond(offset) {
|
||||
return hours.toFixed(1) + ' ' + getTimeUnits('h')
|
||||
} else if (minutes > 1) {
|
||||
return minutes.toFixed(1) + ' ' + getTimeUnits('m')
|
||||
} else if (seconds > 1) {
|
||||
} else if (seconds >= 0) {
|
||||
return seconds.toFixed(1) + ' ' + getTimeUnits('s')
|
||||
}
|
||||
return ''
|
||||
@@ -109,7 +109,7 @@ export function getApiPath(that) {
|
||||
// ticket ...
|
||||
pagePath = pagePathArray.slice(1, pagePathArray.length).join('/')
|
||||
} else {
|
||||
// console,audit,workspace
|
||||
// console,audit,workbench
|
||||
pagePath = pagePathArray.slice(2, pagePathArray.length).join('/')
|
||||
}
|
||||
return `/api/v1/${pagePath}/`
|
||||
@@ -159,6 +159,10 @@ export function hasUUID(s) {
|
||||
return s.search(uuidPattern) !== -1
|
||||
}
|
||||
|
||||
export function replaceUUID(s, n) {
|
||||
return s.replace(uuidPattern, n)
|
||||
}
|
||||
|
||||
export function getDaysAgo(days, now) {
|
||||
if (!now) {
|
||||
now = new Date()
|
||||
@@ -276,5 +280,19 @@ const scheme = document.location.protocol
|
||||
const port = document.location.port ? ':' + document.location.port : ''
|
||||
const BASE_URL = scheme + '//' + document.location.hostname + port
|
||||
|
||||
export function groupedDropdownToCascader(group) {
|
||||
const firstType = group[0]
|
||||
return {
|
||||
value: firstType.category,
|
||||
label: firstType.group,
|
||||
children: group.map(item => {
|
||||
return {
|
||||
value: item.name,
|
||||
label: item.title
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export { BASE_URL }
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import store from '@/store'
|
||||
import Vue from 'vue'
|
||||
import { constantRoutes } from '@/router'
|
||||
|
||||
export function openTaskPage(taskId) {
|
||||
@@ -43,7 +42,6 @@ export function getResourceNameByPath(path) {
|
||||
|
||||
export function getResourceFromApiUrl(apiUrl) {
|
||||
const re = new RegExp('/api/v1/([A-Za-z0-9_-]+)/([A-Za-z0-9_-]+)/.*')
|
||||
console.log('Api url: ', apiUrl)
|
||||
const matched = apiUrl.match(re)
|
||||
if (!matched) {
|
||||
return { path: '', app: '', resource: '' }
|
||||
@@ -81,24 +79,14 @@ export function hasActionPerm(route, action) {
|
||||
return hasPermission(permsRequired)
|
||||
}
|
||||
|
||||
const viewRequirePermsMapper = {
|
||||
console: 'rbac.view_console',
|
||||
audit: 'rbac.view_audit',
|
||||
workspace: 'rbac.view_workspace'
|
||||
}
|
||||
|
||||
export function getViewRequirePerms(view) {
|
||||
return viewRequirePermsMapper[view] || 'super'
|
||||
}
|
||||
|
||||
export function getPermedPreferView() {
|
||||
for (const [view, perms] of Object.entries(viewRequirePermsMapper)) {
|
||||
const hasPerm = hasPermission(perms)
|
||||
Vue.$log.debug('Has view perm: ', view, hasPerm)
|
||||
if (hasPerm) {
|
||||
return view
|
||||
}
|
||||
}
|
||||
export function getPermedViews() {
|
||||
const viewShowMapper = [
|
||||
['console', store.getters.consoleOrgs.length > 0],
|
||||
['tickets', store.getters.consoleOrgs.length > 0],
|
||||
['audit', store.getters.auditOrgs.length > 0],
|
||||
['workbench', true]
|
||||
]
|
||||
return viewShowMapper.filter(i => i[1]).map(i => i[0])
|
||||
}
|
||||
|
||||
export function isSameView(to, from) {
|
||||
@@ -108,13 +96,13 @@ export function isSameView(to, from) {
|
||||
}
|
||||
|
||||
export function getPropView() {
|
||||
const hasPermedViews = getPermedViews()
|
||||
const preView = localStorage.getItem('PreView')
|
||||
const preViewRequirePerms = getViewRequirePerms(preView)
|
||||
const hasPerm = hasPermission(preViewRequirePerms)
|
||||
const hasPerm = hasPermedViews.indexOf(preView) > -1
|
||||
if (hasPerm) {
|
||||
return preView
|
||||
}
|
||||
const preferView = getPermedPreferView()
|
||||
const preferView = getPermedViews()[0]
|
||||
if (preferView) {
|
||||
return preferView
|
||||
}
|
||||
@@ -126,18 +114,8 @@ export function getApiUrlRequirePerms(url, action) {
|
||||
return [`${app}.${action}_${resource}`]
|
||||
}
|
||||
|
||||
export function getRouteViewRequirePerms(route) {
|
||||
const viewName = route.path.split('/')[1]
|
||||
return getViewRequirePerms(viewName)
|
||||
}
|
||||
|
||||
export function hasRouteViewPerm(route) {
|
||||
if (route.name) {
|
||||
return hasPermission(route.meta.permissions)
|
||||
}
|
||||
const viewName = route.path.split('/')[1]
|
||||
const perms = getViewRequirePerms(viewName)
|
||||
return hasPermission(perms)
|
||||
export function isViewHasOrgs(viewName) {
|
||||
return getPermedViews().indexOf(viewName) > -1
|
||||
}
|
||||
|
||||
export function getConstRouteName() {
|
||||
|
||||
@@ -1,53 +1,46 @@
|
||||
import { hasUUID, BASE_URL } from '@/utils/common'
|
||||
import { getOrgDetail } from '@/api/orgs'
|
||||
import store from '@/store'
|
||||
import { hasUUID, replaceUUID } from '@/utils/common'
|
||||
|
||||
export const DEFAULT_ORG_ID = '00000000-0000-0000-0000-000000000002'
|
||||
// const ROOT_ORG_ID = '00000000-0000-0000-0000-000000000000'
|
||||
|
||||
function getPropOrg() {
|
||||
const orgs = store.getters.orgs
|
||||
const orgs = store.getters.usingOrgs
|
||||
const defaultOrg = orgs.find((item) => item.is_default)
|
||||
if (defaultOrg) {
|
||||
return defaultOrg
|
||||
}
|
||||
return orgs[0]
|
||||
return orgs.filter(item => !item['is_root'])[0]
|
||||
}
|
||||
|
||||
function change2PropOrg() {
|
||||
async function change2PropOrg() {
|
||||
const org = getPropOrg()
|
||||
setTimeout(() => changeOrg(org.id), 100)
|
||||
await changeOrg(org)
|
||||
}
|
||||
|
||||
async function changeOrg(org) {
|
||||
await store.dispatch('users/setCurrentOrg', org)
|
||||
await store.dispatch('app/reset')
|
||||
let path = location.href
|
||||
if (hasUUID(path)) {
|
||||
path = replaceUUID(path, '')
|
||||
path = _.trimEnd(path, '/')
|
||||
location.href = path
|
||||
} else {
|
||||
setTimeout(() => location.reload(), 400)
|
||||
}
|
||||
}
|
||||
|
||||
function hasCurrentOrgPermission() {
|
||||
const currentOrg = store.getters.currentOrg
|
||||
const currentOrgId = currentOrg.id
|
||||
const orgs = store.getters.orgs
|
||||
const orgs = store.getters.usingOrgs
|
||||
return orgs.find((item) => item.id === currentOrgId)
|
||||
}
|
||||
|
||||
async function changeOrg(orgId) {
|
||||
const org = await getOrgDetail(orgId)
|
||||
if (!org) {
|
||||
console.debug('Error: org not found')
|
||||
} else {
|
||||
console.debug('Change to org: ', org)
|
||||
}
|
||||
localStorage.setItem('PreView', '')
|
||||
|
||||
store.dispatch('users/setCurrentOrg', org).then(() => {
|
||||
// console.log('Set current org to: ', org)
|
||||
if (hasUUID(location.href)) {
|
||||
location.href = BASE_URL
|
||||
} else {
|
||||
window.location.reload(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
hasCurrentOrgPermission,
|
||||
changeOrg,
|
||||
DEFAULT_ORG_ID,
|
||||
change2PropOrg
|
||||
change2PropOrg,
|
||||
changeOrg,
|
||||
getPropOrg
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Message, MessageBox } from 'element-ui'
|
||||
import store from '@/store'
|
||||
import axiosRetry from 'axios-retry'
|
||||
import router from '@/router'
|
||||
import { DEFAULT_ORG_ID } from '@/utils/org'
|
||||
|
||||
// create an axios instance
|
||||
const service = axios.create({
|
||||
@@ -22,7 +23,10 @@ function beforeRequestAddToken(config) {
|
||||
}
|
||||
const queryOrgId = router.currentRoute.query?.oid
|
||||
const storeOrgId = store.getters.currentOrg?.id
|
||||
const orgId = queryOrgId || storeOrgId
|
||||
let orgId = queryOrgId || storeOrgId
|
||||
if (!store.getters.publicSettings?.XPACK_ENABLED) {
|
||||
orgId = DEFAULT_ORG_ID
|
||||
}
|
||||
if (orgId) {
|
||||
config.headers['X-JMS-ORG'] = orgId
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
// import getPageTitle from '@/utils/get-page-title'
|
||||
import store from '@/store'
|
||||
import router from '@/router'
|
||||
import router, { resetRouter } from '@/router'
|
||||
import Vue from 'vue'
|
||||
import { Message } from 'element-ui'
|
||||
import 'nprogress/nprogress.css' // progress bar style
|
||||
import { getTokenFromCookie } from '@/utils/auth'
|
||||
import orgUtil from '@/utils/org'
|
||||
import { getCurrentOrg } from '@/api/orgs'
|
||||
import orgs from '@/api/orgs'
|
||||
import { getPropView, isViewHasOrgs } from '@/utils/jms'
|
||||
|
||||
const whiteList = ['/login', process.env.VUE_APP_LOGIN_PATH] // no redirect whitelist
|
||||
let initial = false
|
||||
|
||||
function reject(msg) {
|
||||
return new Promise((resolve, reject) => reject(msg))
|
||||
@@ -51,32 +51,34 @@ async function getPublicSetting({ to, from, next }) {
|
||||
}
|
||||
|
||||
async function refreshCurrentOrg() {
|
||||
getCurrentOrg().then(org => {
|
||||
orgs.getCurrentOrg().then(org => {
|
||||
store.dispatch('users/setCurrentOrg', org)
|
||||
})
|
||||
}
|
||||
|
||||
async function changeCurrentOrgIfNeed({ to, from, next }) {
|
||||
await store.dispatch('users/getInOrgs')
|
||||
const adminOrgs = store.getters.orgs
|
||||
if (!adminOrgs || adminOrgs.length === 0) {
|
||||
await store.dispatch('users/getProfile')
|
||||
|
||||
const usingOrgs = store.getters.usingOrgs
|
||||
if (!usingOrgs || usingOrgs.length === 0) {
|
||||
Vue.$log.debug('No using orgs, return: ', usingOrgs)
|
||||
return
|
||||
}
|
||||
await refreshCurrentOrg()
|
||||
const currentOrg = store.getters.currentOrg
|
||||
if (!currentOrg || typeof currentOrg !== 'object') {
|
||||
orgUtil.change2PropOrg()
|
||||
return reject('Change prop org')
|
||||
Vue.$log.error('Current org is null or not a object: ', currentOrg)
|
||||
await orgUtil.change2PropOrg({ to, from, next })
|
||||
}
|
||||
if (!orgUtil.hasCurrentOrgPermission()) {
|
||||
console.error('Not has current org permission')
|
||||
orgUtil.change2PropOrg()
|
||||
return reject('Change prop org')
|
||||
Vue.$log.error('Not has current org permission: ', currentOrg)
|
||||
await orgUtil.change2PropOrg({ to, from, next })
|
||||
}
|
||||
}
|
||||
|
||||
export async function generatePageRoutes({ to, from, next }) {
|
||||
// determine whether the user has obtained his permission roles through getProfile
|
||||
resetRouter()
|
||||
|
||||
try {
|
||||
// try get user profile
|
||||
@@ -113,18 +115,38 @@ export async function checkUserFirstLogin({ to, from, next }) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function startup({ to, from, next }) {
|
||||
if (initial) {
|
||||
return true
|
||||
export async function changeCurrentViewIfNeed({ to, from, next }) {
|
||||
let viewName = to.path.split('/')[1]
|
||||
// 这几个是需要检测的, 切换视图组织时,避免 404
|
||||
if (['console', 'audit', 'workbench', 'tickets', ''].indexOf(viewName) === -1) {
|
||||
Vue.$log.debug('Current view no need check', viewName)
|
||||
return
|
||||
}
|
||||
initial = true
|
||||
|
||||
const has = isViewHasOrgs(viewName)
|
||||
Vue.$log.debug('Change has current view, has perm: ', viewName, '=>', has)
|
||||
if (has) {
|
||||
await store.dispatch('users/changeToView', viewName)
|
||||
return
|
||||
}
|
||||
viewName = getPropView()
|
||||
// Next 之前要重置 init 状态,否则这些路由守卫就不走了
|
||||
await store.dispatch('app/reset')
|
||||
next(`/${viewName}/`)
|
||||
return new Promise((resolve, reject) => reject(''))
|
||||
}
|
||||
|
||||
export async function startup({ to, from, next }) {
|
||||
// if (store.getters.inited) { return true }
|
||||
if (store.getters.inited) { return true }
|
||||
await store.dispatch('app/init')
|
||||
|
||||
// set page title
|
||||
await getPublicSetting({ to, from, next })
|
||||
// await setHeadTitle({ to, from, next })
|
||||
await checkLogin({ to, from, next })
|
||||
await generatePageRoutes({ to, from, next })
|
||||
await changeCurrentViewIfNeed({ to, from, next })
|
||||
await changeCurrentOrgIfNeed({ to, from, next })
|
||||
await generatePageRoutes({ to, from, next })
|
||||
await checkUserFirstLogin({ to, from, next })
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ export default {
|
||||
name: 'retry',
|
||||
type: 'info',
|
||||
title: this.$t('xpack.ChangeAuthPlan.Retry'),
|
||||
can: this.$hasPerm('xpack.change_applicationchangeauthplantask'),
|
||||
callback: function({ row, tableData }) {
|
||||
this.$axios.put(
|
||||
`/api/v1/xpack/change-auth-plan/app-plan-execution-subtask/${row.id}/`,
|
||||
|
||||
@@ -92,7 +92,7 @@ export default {
|
||||
name: 'detail',
|
||||
title: this.$t('xpack.ChangeAuthPlan.Detail'),
|
||||
type: 'info',
|
||||
can: 'xpack.view_applicationchangeauthplantask',
|
||||
can: this.$hasPerm('xpack.view_applicationchangeauthplantask'),
|
||||
callback: function({ row }) {
|
||||
return this.$router.push({ name: 'AppChangeAuthPlanExecutionDetail', params: { id: row.id }})
|
||||
}
|
||||
|
||||
@@ -1,21 +1,14 @@
|
||||
<template>
|
||||
<TabPage :active-menu.sync="config.activeMenu" :submenu="config.submenu">
|
||||
<keep-alive>
|
||||
<component :is="config.activeMenu" />
|
||||
</keep-alive>
|
||||
</TabPage>
|
||||
<TabPage :active-menu.sync="config.activeMenu" :submenu="config.submenu" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { TabPage } from '@/layout/components'
|
||||
import AssetChangeAuthPlanList from './AssetChangeAuthPlan/ChangeAuthPlanList'
|
||||
import AppChangeAuthPlanList from './AppChangeAuthPlan/AppChangeAuthPlanList'
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
TabPage,
|
||||
AssetChangeAuthPlanList,
|
||||
AppChangeAuthPlanList
|
||||
TabPage
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -25,13 +18,14 @@ export default {
|
||||
{
|
||||
title: this.$t('xpack.ChangeAuthPlan.AssetChangeAuthPlan'),
|
||||
name: 'AssetChangeAuthPlanList',
|
||||
hidden: () => !this.$hasPerm('xpack.view_changeauthplan')
|
||||
|
||||
hidden: () => !this.$hasPerm('xpack.view_changeauthplan'),
|
||||
component: () => import('@/views/accounts/ChangeAuthPlan/AssetChangeAuthPlan/ChangeAuthPlanList.vue')
|
||||
},
|
||||
{
|
||||
title: this.$t('xpack.ChangeAuthPlan.AppChangeAuthPlan'),
|
||||
name: 'AppChangeAuthPlanList',
|
||||
hidden: () => !this.$hasPerm('xpack.view_applicationchangeauthplan')
|
||||
hidden: () => !this.$hasPerm('xpack.view_applicationchangeauthplan'),
|
||||
component: () => import('@/views/accounts/ChangeAuthPlan/AppChangeAuthPlan/AppChangeAuthPlanList.vue')
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="14">
|
||||
<el-col :md="14" :sm="24">
|
||||
<DetailCard :items="detailCardItems" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
@@ -1,21 +1,14 @@
|
||||
<template>
|
||||
<TabPage :active-menu.sync="config.activeMenu" :submenu="config.submenu">
|
||||
<keep-alive>
|
||||
<component :is="config.activeMenu" />
|
||||
</keep-alive>
|
||||
</TabPage>
|
||||
<TabPage :active-menu.sync="config.activeMenu" :submenu="config.submenu" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { TabPage } from '@/layout/components'
|
||||
import GatheredUserList from './GatheredUserList'
|
||||
import TaskList from './TaskList'
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
TabPage,
|
||||
GatheredUserList,
|
||||
TaskList
|
||||
TabPage
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -25,12 +18,14 @@ export default {
|
||||
{
|
||||
title: this.$t('xpack.GatherUser.GatherUserList'),
|
||||
name: 'GatheredUserList',
|
||||
hidden: !this.$hasPerm('assets.view_gathereduser')
|
||||
hidden: !this.$hasPerm('assets.view_gathereduser'),
|
||||
component: () => import('@/views/accounts/GatheredUser/GatheredUserList.vue')
|
||||
},
|
||||
{
|
||||
title: this.$t('xpack.GatherUser.GatherUserTaskList'),
|
||||
name: 'TaskList',
|
||||
hidden: !this.$hasPerm('xpack.view_gatherusertask')
|
||||
hidden: !this.$hasPerm('xpack.view_gatherusertask'),
|
||||
component: () => import('@/views/accounts/GatheredUser/TaskList.vue')
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="14">
|
||||
<el-col :md="14" :sm="24">
|
||||
<DetailCard :items="detailCardItems" />
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<el-col :md="10" :sm="24">
|
||||
<!-- <RelationCard ref="RelationCard" type="info" v-bind="nodeRelationConfig" />-->
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="14">
|
||||
<el-col :md="14" :sm="24">
|
||||
<DetailCard :items="detailCardItems" />
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<el-col :md="10" :sm="24">
|
||||
<QuickActions type="primary" :actions="quickActions" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
@@ -17,11 +17,6 @@ export default {
|
||||
],
|
||||
fieldsMeta: {
|
||||
type: {
|
||||
type: 'select',
|
||||
options: [{
|
||||
label: 'MySQL',
|
||||
value: 'mysql'
|
||||
}],
|
||||
disabled: true
|
||||
},
|
||||
domain: {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
<script>
|
||||
import { GenericListPage } from '@/layout/components'
|
||||
import { DATABASE } from '@/views/applications/const'
|
||||
import { DATABASE, KV_DATABASE } from '@/views/applications/const'
|
||||
|
||||
function getAppType(arr) {
|
||||
const searchAppType = []
|
||||
@@ -25,7 +25,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
const vm = this
|
||||
const appType = DATABASE
|
||||
const appType = [...DATABASE, ...KV_DATABASE]
|
||||
return {
|
||||
tableConfig: {
|
||||
url: '/api/v1/applications/applications/?category=db',
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import i18n from '@/i18n/i18n'
|
||||
import store from '@/store'
|
||||
import { groupedDropdownToCascader } from '@/utils/common'
|
||||
|
||||
export const CHROME = 'chrome'
|
||||
export const MYSQL_WORKBENCH = 'mysql_workbench'
|
||||
export const VMWARE_CLIENT = 'vmware_client'
|
||||
@@ -87,7 +89,10 @@ export const DATABASE = [
|
||||
type: 'primary',
|
||||
category: DATABASE_CATEGORY,
|
||||
has: hasLicence
|
||||
},
|
||||
}
|
||||
]
|
||||
|
||||
export const KV_DATABASE = [
|
||||
{
|
||||
name: REDIS,
|
||||
title: i18n.t(`applications.applicationsType.${REDIS}`),
|
||||
@@ -95,53 +100,17 @@ export const DATABASE = [
|
||||
category: DATABASE_CATEGORY,
|
||||
has: true,
|
||||
group: i18n.t('applications.NoSQLProtocol')
|
||||
}
|
||||
// {
|
||||
// name: MONGODB,
|
||||
// title: i18n.t(`applications.applicationsType.${MONGODB}`),
|
||||
// type: 'primary',
|
||||
// category: DATABASE_CATEGORY
|
||||
// }
|
||||
]
|
||||
|
||||
export const AppPlanDatabase = [
|
||||
{
|
||||
name: MYSQL,
|
||||
title: i18n.t(`applications.applicationsType.${MYSQL}`),
|
||||
type: 'primary',
|
||||
category: DATABASE_CATEGORY,
|
||||
has: true,
|
||||
group: i18n.t('applications.RDBProtocol')
|
||||
},
|
||||
{
|
||||
name: ORACLE,
|
||||
title: i18n.t(`applications.applicationsType.${ORACLE}`),
|
||||
type: 'primary',
|
||||
category: DATABASE_CATEGORY,
|
||||
has: hasLicence
|
||||
},
|
||||
{
|
||||
name: POSTGRESQL,
|
||||
title: i18n.t(`applications.applicationsType.${POSTGRESQL}`),
|
||||
type: 'primary',
|
||||
category: DATABASE_CATEGORY,
|
||||
has: hasLicence
|
||||
},
|
||||
{
|
||||
name: MARIADB,
|
||||
title: i18n.t(`applications.applicationsType.${MARIADB}`),
|
||||
name: MONGODB,
|
||||
title: i18n.t(`applications.applicationsType.${MONGODB}`),
|
||||
type: 'primary',
|
||||
category: DATABASE_CATEGORY
|
||||
},
|
||||
{
|
||||
name: SQLSERVER,
|
||||
title: i18n.t(`applications.applicationsType.${SQLSERVER}`),
|
||||
type: 'primary',
|
||||
category: DATABASE_CATEGORY,
|
||||
has: hasLicence
|
||||
}
|
||||
]
|
||||
|
||||
export const AppPlanDatabase = DATABASE
|
||||
|
||||
export const KUBERNETES = 'k8s'
|
||||
export const CLOUD_CATEGORY = 'cloud'
|
||||
|
||||
@@ -157,9 +126,16 @@ export const CLOUD = [
|
||||
]
|
||||
|
||||
export const ApplicationTypes = [
|
||||
...DATABASE, ...REMOTE_APP, ...CLOUD
|
||||
...DATABASE, ...KV_DATABASE, ...REMOTE_APP, ...CLOUD
|
||||
]
|
||||
|
||||
export const ApplicationSystemUserTypes = [
|
||||
...DATABASE, ...CLOUD
|
||||
...DATABASE, ...KV_DATABASE, ...CLOUD
|
||||
]
|
||||
|
||||
export const ApplicationCascader = [
|
||||
groupedDropdownToCascader(DATABASE),
|
||||
groupedDropdownToCascader(KV_DATABASE),
|
||||
groupedDropdownToCascader(REMOTE_APP),
|
||||
groupedDropdownToCascader(CLOUD)
|
||||
]
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="16">
|
||||
<el-col :md="16" :sm="24">
|
||||
<AccountListTable ref="ListTable" :url="assetUserUrl" :has-import="false" :has-clone="false" />
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-col :md="8" :sm="24">
|
||||
<QuickActions type="primary" :actions="quickActions" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="14">
|
||||
<el-col :md="14" :sm="24">
|
||||
<DetailCard :items="detailCardItems" />
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<el-col :md="10" :sm="24">
|
||||
<QuickActions type="primary" :actions="quickActions" />
|
||||
<RelationCard ref="NodeRelation" v-perms="'assets.change_asset'" type="info" style="margin-top: 15px" v-bind="nodeRelationConfig" />
|
||||
<LabelCard v-if="$hasPerm('assets.view_label')" type="warning" style="margin-top: 15px" v-bind="labelConfig" />
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="16">
|
||||
<el-col :md="16" :sm="24">
|
||||
<ListTable ref="ListTable" :table-config="tableConfig" :header-actions="headerActions" />
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-col :md="8" :sm="24">
|
||||
<PermUserGroupCard v-bind="UserGroupCardConfig" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="16">
|
||||
<el-col :md="16" :sm="24">
|
||||
<ListTable ref="ListTable" :table-config="tableConfig" :header-actions="headerActions" />
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-col :md="8" :sm="24">
|
||||
<QuickActions type="primary" :actions="quickActions" />
|
||||
<RelationCard ref="systemUserRelation" style="margin-top: 15px" v-bind="systemUserRelationConfig" />
|
||||
</el-col>
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
</GenericTreeListPage>
|
||||
<Dialog width="30%" :title="this.$t('assets.NodeInformation')" :visible.sync="nodeInfoDialogSetting.dialogVisible" :show-cancel="false" :show-confirm="false">
|
||||
<el-row v-for="item in nodeInfoDialogSetting.items" :key="'card-' + item.key" :gutter="10" class="item">
|
||||
<el-col :span="6"><div class="item-label"><label>{{ item.label }}: </label></div></el-col>
|
||||
<el-col :span="18"><div class="item-text">{{ item.value }}</div></el-col>
|
||||
<el-col :md="6" :sm="24"><div class="item-label"><label>{{ item.label }}: </label></div></el-col>
|
||||
<el-col :md="18" :sm="24"><div class="item-text">{{ item.value }}</div></el-col>
|
||||
</el-row>
|
||||
</Dialog>
|
||||
<AssetBulkUpdateDialog
|
||||
@@ -51,7 +51,11 @@
|
||||
|
||||
<script>
|
||||
import GenericTreeListPage from '@/layout/components/GenericTreeListPage/index'
|
||||
import { DetailFormatter, ActionsFormatter, TagsFormatter } from '@/components/TableFormatters'
|
||||
import {
|
||||
DetailFormatter,
|
||||
ActionsFormatter,
|
||||
TagsFormatter
|
||||
} from '@/components/TableFormatters'
|
||||
import $ from '@/utils/jquery-vendor'
|
||||
import Dialog from '@/components/Dialog'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
|
||||
<script type="text/jsx">
|
||||
import GenericListTable from '@/layout/components/GenericListTable'
|
||||
import { ACCOUNT_PROVIDER_ATTRS_MAP, aliyun, aws_china, aws_international, huaweicloud, qcloud, azure, azure_international, vmware, nutanix, qingcloud_private, huaweicloud_private, openstack, gcp } from '../const'
|
||||
import { ACCOUNT_PROVIDER_ATTRS_MAP, aliyun, aws_china, aws_international, huaweicloud, qcloud, azure, azure_international, vmware, nutanix, qingcloud_private, huaweicloud_private, openstack, gcp, baiducloud, jdcloud } from '../const'
|
||||
|
||||
export default {
|
||||
name: 'AccountList',
|
||||
components: {
|
||||
GenericListTable
|
||||
},
|
||||
@@ -85,6 +86,14 @@ export default {
|
||||
name: huaweicloud,
|
||||
title: ACCOUNT_PROVIDER_ATTRS_MAP[huaweicloud].title
|
||||
},
|
||||
{
|
||||
name: baiducloud,
|
||||
title: ACCOUNT_PROVIDER_ATTRS_MAP[baiducloud].title
|
||||
},
|
||||
{
|
||||
name: jdcloud,
|
||||
title: ACCOUNT_PROVIDER_ATTRS_MAP[jdcloud].title
|
||||
},
|
||||
{
|
||||
name: aws_china,
|
||||
title: ACCOUNT_PROVIDER_ATTRS_MAP[aws_china].title
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="14">
|
||||
<el-col :md="14" :sm="24">
|
||||
<DetailCard :items="detailCardItems" />
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<el-col :md="10" :sm="24">
|
||||
<QuickActions type="primary" :actions="quickActions" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
@@ -8,6 +8,7 @@ import { DetailFormatter } from '@/components/TableFormatters'
|
||||
import { openTaskPage } from '@/utils/jms'
|
||||
|
||||
export default {
|
||||
name: 'SyncInstanceTaskList',
|
||||
components: {
|
||||
GenericListTable
|
||||
},
|
||||
|
||||
@@ -13,6 +13,8 @@ export const qingcloud_private = 'qingcloud_private'
|
||||
export const huaweicloud_private = 'huaweicloud_private'
|
||||
export const openstack = 'openstack'
|
||||
export const gcp = 'gcp'
|
||||
export const baiducloud = 'baiducloud'
|
||||
export const jdcloud = 'jdcloud'
|
||||
|
||||
export const ACCOUNT_PROVIDER_ATTRS_MAP = {
|
||||
[aliyun]: {
|
||||
@@ -35,6 +37,16 @@ export const ACCOUNT_PROVIDER_ATTRS_MAP = {
|
||||
title: i18n.t('xpack.Cloud.HuaweiCloud'),
|
||||
attrs: ['access_key_id', 'access_key_secret']
|
||||
},
|
||||
[baiducloud]: {
|
||||
name: baiducloud,
|
||||
title: i18n.t('xpack.Cloud.BaiduCloud'),
|
||||
attrs: ['access_key_id', 'access_key_secret']
|
||||
},
|
||||
[jdcloud]: {
|
||||
name: jdcloud,
|
||||
title: i18n.t('xpack.Cloud.JDCloud'),
|
||||
attrs: ['access_key_id', 'access_key_secret']
|
||||
},
|
||||
[qcloud]: {
|
||||
name: qcloud,
|
||||
title: i18n.t('xpack.Cloud.Qcloud'),
|
||||
|
||||
@@ -1,21 +1,14 @@
|
||||
<template>
|
||||
<TabPage :active-menu.sync="config.activeMenu" :submenu="config.submenu">
|
||||
<keep-alive>
|
||||
<component :is="config.activeMenu" />
|
||||
</keep-alive>
|
||||
</TabPage>
|
||||
<TabPage :active-menu.sync="config.activeMenu" :submenu="config.submenu" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { TabPage } from '@/layout/components'
|
||||
import AccountList from './Account/AccountList'
|
||||
import SyncInstanceTaskList from './SyncInstanceTask/SyncInstanceTaskList'
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
name: 'CloudIndex',
|
||||
components: {
|
||||
TabPage,
|
||||
AccountList,
|
||||
SyncInstanceTaskList
|
||||
TabPage
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -25,13 +18,14 @@ export default {
|
||||
{
|
||||
title: this.$t('xpack.Cloud.SyncInstanceTaskList'),
|
||||
name: 'SyncInstanceTaskList',
|
||||
hidden: () => !this.$hasPerm('xpack.view_syncinstancetask')
|
||||
hidden: () => !this.$hasPerm('xpack.view_syncinstancetask'),
|
||||
component: () => import('@/views/assets/Cloud/SyncInstanceTask/SyncInstanceTaskList.vue')
|
||||
},
|
||||
{
|
||||
title: this.$t('xpack.Cloud.AccountList'),
|
||||
name: 'AccountList',
|
||||
hidden: () => !this.$hasPerm('xpack.view_account')
|
||||
|
||||
hidden: () => !this.$hasPerm('xpack.view_account'),
|
||||
component: () => import('@/views/assets/Cloud/Account/AccountList.vue')
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="14">
|
||||
<el-col :md="14" :sm="24">
|
||||
<DetailCard :items="detailCardItems" />
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<el-col :md="10" :sm="24">
|
||||
<RelationCard ref="systemUserRelation" v-bind="systemUserRelationConfig" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="14">
|
||||
<el-col :md="14" :sm="24">
|
||||
<DetailCard :items="detailCardItems" />
|
||||
</el-col>
|
||||
<el-col :span="10" />
|
||||
<el-col :md="10" :sm="24" />
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -12,14 +12,14 @@
|
||||
:destroy-on-close="true"
|
||||
>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="4">
|
||||
<div style="line-height: 34px;text-align: center">{{ $t('assets.SshPort') }}</div>
|
||||
<el-col :md="4" :sm="24">
|
||||
<div style="line-height: 34px">{{ $t('assets.SshPort') }}</div>
|
||||
</el-col>
|
||||
<el-col :span="14">
|
||||
<el-col :md="14" :sm="24">
|
||||
<el-input v-model="portInput" />
|
||||
<span class="help-tips help-block">{{ $t('assets.TestGatewayHelpMessage') }}</span>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-col :md="4" :sm="24">
|
||||
<el-button size="mini" type="primary" style="line-height:20px " :loading="buttonLoading" @click="dialogConfirm">{{ this.$t('common.Confirm') }}</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="14">
|
||||
<el-col :md="14" :sm="24">
|
||||
<DetailCard :items="detailCardItems" />
|
||||
</el-col>
|
||||
<el-col :span="10" />
|
||||
<el-col :md="10" :sm="24" />
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ export default {
|
||||
[this.$t('common.Basic'), ['name', 'protocol', 'username', 'type']],
|
||||
[this.$t('common.Auth'), ['password', 'private_key', 'passphrase']],
|
||||
[this.$t('common.Command filter'), ['cmd_filters']],
|
||||
[this.$t('assets.UserSwitch'), ['su_enabled', 'su_from']],
|
||||
[this.$t('common.Other'), ['priority', 'sftp_root', 'comment']]
|
||||
],
|
||||
fieldsMeta: {
|
||||
@@ -73,7 +74,9 @@ export default {
|
||||
rules: [Required],
|
||||
helpText: this.$t('assets.SFTPHelpMessage')
|
||||
},
|
||||
cmd_filters: fields.cmd_filters
|
||||
cmd_filters: fields.cmd_filters,
|
||||
su_enabled: fields.su_enabled,
|
||||
su_from: fields.su_from
|
||||
},
|
||||
cleanFormValue: (values) => {
|
||||
values['type'] = 'admin'
|
||||
|
||||
@@ -184,6 +184,26 @@ function getFields() {
|
||||
const type = {
|
||||
}
|
||||
|
||||
const su_enabled = {
|
||||
type: 'switch',
|
||||
hidden: (item) => item.protocol !== 'ssh'
|
||||
}
|
||||
|
||||
const su_from = {
|
||||
hidden: (item) => !item.su_enabled,
|
||||
rules: [Required],
|
||||
el: {
|
||||
multiple: false,
|
||||
clearable: true,
|
||||
ajax: {
|
||||
url: '/api/v1/assets/system-users/su-from/',
|
||||
transformOption: (item) => {
|
||||
return { label: item.name + '(' + item.username + ')', value: item.id }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
login_mode: login_mode,
|
||||
username: username,
|
||||
@@ -197,7 +217,9 @@ function getFields() {
|
||||
password: password,
|
||||
passphrase: passphrase,
|
||||
system_groups: system_groups,
|
||||
type: type
|
||||
type: type,
|
||||
su_enabled: su_enabled,
|
||||
su_from: su_from
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="20">
|
||||
<el-col :md="20" :sm="24">
|
||||
<AccountListTable ref="ListTable" :url="accountUrl" :has-import="false" :has-clone="false" />
|
||||
</el-col>
|
||||
<el-col :span="4" />
|
||||
<el-col :md="4" :sm="24" />
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="20">
|
||||
<el-col :md="20" :sm="24">
|
||||
<AppAccountListTable ref="ListTable" :url="accountUrl" :has-import="false" :has-clone="false" />
|
||||
</el-col>
|
||||
<el-col :span="4" />
|
||||
<el-col :md="4" :sm="24" />
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="16">
|
||||
<el-col :md="16" :sm="24">
|
||||
<ListTable ref="ListTable" :table-config="tableConfig" :header-actions="headerActions" />
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-col :md="8" :sm="24">
|
||||
<RelationCard ref="assetSelect" type="primary" style="margin-top: 15px" v-bind="appRelationConfig" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="16">
|
||||
<el-col :md="16" :sm="24">
|
||||
<ListTable ref="ListTable" :table-config="tableConfig" :header-actions="headerActions" />
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-col :md="8" :sm="24">
|
||||
<QuickActions type="primary" :actions="quickActions" />
|
||||
<AssetRelationCard ref="assetSelect" type="primary" style="margin-top: 15px" v-bind="assetRelationConfig" />
|
||||
<RelationCard ref="nodeRelation" type="info" style="margin-top: 15px" v-bind="nodeRelationConfig" />
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="14">
|
||||
<el-col :md="14" :sm="24">
|
||||
<DetailCard :items="detailCardItems" />
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<el-col :md="10" :sm="24">
|
||||
<QuickActions type="primary" :actions="quickActions" />
|
||||
<RelationCard
|
||||
v-if="!(object.protocol === 'rdp' || object.protocol === 'vnc')"
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
<b>{{ Tips.title }}</b>: <span>{{ Tips.body }}</span>
|
||||
</el-alert>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="20">
|
||||
<el-col :md="20" :sm="24">
|
||||
<ListTable ref="ListTable" :table-config="tableConfig" :header-actions="headerActions" />
|
||||
</el-col>
|
||||
<el-col :span="4" />
|
||||
<el-col :md="4" :sm="24" />
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import i18n from '@/i18n/i18n'
|
||||
import { groupedDropdownToCascader } from '@/utils/common'
|
||||
|
||||
export const AssetProtocols = [
|
||||
{
|
||||
@@ -28,3 +29,5 @@ export const AssetProtocols = [
|
||||
}
|
||||
]
|
||||
|
||||
export const AssetCascader = groupedDropdownToCascader(AssetProtocols)
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<script type="text/jsx">
|
||||
import GenericListPage from '@/layout/components/GenericListPage'
|
||||
import { getDayEnd, getDaysAgo } from '@/utils/common'
|
||||
import { getDaysFuture, getDaysAgo } from '@/utils/common'
|
||||
import { Dialog, ListTable } from '@/components'
|
||||
import { DisplayFormatter } from '@/components/TableFormatters'
|
||||
import { setUrlParam } from '@/utils/common'
|
||||
@@ -21,7 +21,7 @@ export default {
|
||||
data() {
|
||||
const now = new Date()
|
||||
const dateFrom = getDaysAgo(7, now).toISOString()
|
||||
const dateTo = getDayEnd(now).toISOString()
|
||||
const dateTo = getDaysFuture(1, now).toISOString()
|
||||
const vm = this
|
||||
return {
|
||||
tableConfig: {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
<script>
|
||||
import GenericListPage from '@/layout/components/GenericListPage'
|
||||
import { getDayEnd, getDaysAgo } from '@/utils/common'
|
||||
import { getDaysAgo, getDaysFuture } from '@/utils/common'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -13,7 +13,7 @@ export default {
|
||||
data() {
|
||||
const now = new Date()
|
||||
const dateFrom = getDaysAgo(7, now).toISOString()
|
||||
const dateTo = getDayEnd(now).toISOString()
|
||||
const dateTo = getDaysFuture(1, now).toISOString()
|
||||
return {
|
||||
tableConfig: {
|
||||
permissions: {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
<script>
|
||||
import GenericListPage from '@/layout/components/GenericListPage'
|
||||
import { getDayEnd, getDaysAgo } from '@/utils/common'
|
||||
import { getDaysAgo, getDaysFuture } from '@/utils/common'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -13,7 +13,7 @@ export default {
|
||||
data() {
|
||||
const now = new Date()
|
||||
const dateFrom = getDaysAgo(7, now).toISOString()
|
||||
const dateTo = getDayEnd(now).toISOString()
|
||||
const dateTo = getDaysFuture(1, now).toISOString()
|
||||
return {
|
||||
tableConfig: {
|
||||
url: '/api/v1/audits/operate-logs/',
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
<script>
|
||||
import GenericListPage from '@/layout/components/GenericListPage'
|
||||
import { getDayEnd, getDaysAgo } from '@/utils/common'
|
||||
import { getDaysAgo, getDaysFuture } from '@/utils/common'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -13,7 +13,7 @@ export default {
|
||||
data() {
|
||||
const now = new Date()
|
||||
const dateFrom = getDaysAgo(7, now).toISOString()
|
||||
const dateTo = getDayEnd(now).toISOString()
|
||||
const dateTo = getDaysFuture(1, now).toISOString()
|
||||
return {
|
||||
tableConfig: {
|
||||
url: '/api/v1/audits/password-change-logs/',
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div class="white-bg dashboard-header print-margin">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-col :md="12" :sm="24">
|
||||
<h2>{{ $t('dashboard.LoginOverview') }}</h2>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-button-group style="float: right; padding: 0">
|
||||
<el-col :md="12" :sm="24" class="clearfix">
|
||||
<el-button-group style="float: right; padding: 0" class="clearfix">
|
||||
<el-button type="default" size="mini" :class="{ 'active': active === 'weekly'}" @click="changeDates('weekly')">{{ $t('dashboard.Weekly') }}</el-button>
|
||||
<el-button type="default" size="mini" :class="{ 'active': active === 'monthly'}" @click="changeDates('monthly')">{{ $t('dashboard.Monthly') }}</el-button>
|
||||
</el-button-group>
|
||||
@@ -13,7 +13,7 @@
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :lg="18" :sm="24">
|
||||
<LoginMetric :range="active" class="card-item" style="margin-top: -30px" heigth="300px" />
|
||||
<LoginMetric :range="active" class="card-item" heigth="300px" />
|
||||
</el-col>
|
||||
<el-col :lg="6" :sm="24">
|
||||
<LoginActivePin :range="active" class="card-item" />
|
||||
|
||||
@@ -28,27 +28,28 @@ export default {
|
||||
{
|
||||
title: this.$t('dashboard.UsersTotal'),
|
||||
body: {
|
||||
route: `/users/users`,
|
||||
route: { name: 'UserList' },
|
||||
count: this.counter.total_count_users,
|
||||
comment: 'All users',
|
||||
disabled: !this.$store.state.users.hasAdmin
|
||||
comment: this.$t('dashboard.UsersTotal'),
|
||||
disabled: !this.$hasPerm('users.view_user')
|
||||
}
|
||||
},
|
||||
{
|
||||
title: this.$t('dashboard.AssetsTotal'),
|
||||
body: {
|
||||
route: `/assets/assets`,
|
||||
route: { name: 'AssetList' },
|
||||
count: this.counter.total_count_assets,
|
||||
comment: 'All assets',
|
||||
disabled: !this.$store.state.users.hasAdmin
|
||||
comment: this.$t('dashboard.AssetsTotal'),
|
||||
disabled: !this.$hasPerm('assets.view_asset')
|
||||
}
|
||||
},
|
||||
{
|
||||
title: this.$t('dashboard.OnlineUsers'),
|
||||
title: this.$t('dashboard.ConnectUsers'),
|
||||
body: {
|
||||
route: { name: `SessionList`, params: { activeMenu: 'OnlineList' }},
|
||||
count: this.counter.total_count_online_users,
|
||||
comment: 'Online users'
|
||||
comment: this.$t('dashboard.OnlineUsers'),
|
||||
disabled: !this.$hasPerm('terminal.view_session')
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -56,7 +57,8 @@ export default {
|
||||
body: {
|
||||
route: { name: `SessionList`, params: { activeMenu: 'OnlineList' }},
|
||||
count: this.counter.total_count_online_sessions,
|
||||
comment: 'Online sessions'
|
||||
comment: this.$t('dashboard.OnlineSessions'),
|
||||
disabled: !this.$hasPerm('terminal.view_session')
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<el-row :gutter="10" style="margin-bottom: 20px;margin-top: 20px">
|
||||
<el-col :md="8" :sm="12">
|
||||
<el-col :md="8" :sm="24">
|
||||
<TopUser />
|
||||
</el-col>
|
||||
<el-col :md="8" :sm="12" class="print-margin-top">
|
||||
<el-col :md="8" :sm="24" class="print-margin-top">
|
||||
<TopAssets />
|
||||
</el-col>
|
||||
<el-col :md="8" :sm="12">
|
||||
<el-col :md="8" :sm="24">
|
||||
<Latest10Sessions class="card-item print-margin-top" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<Page>
|
||||
<div v-if="this.$hasPerm('rbac.view_console|rbac.view_workspace')">
|
||||
<div v-if="this.$hasPerm('rbac.view_console|rbac.view_audit')">
|
||||
<Announcement />
|
||||
<ResourceSummary />
|
||||
<DatesLoginSummary />
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
<template>
|
||||
<div>
|
||||
<Announcement />
|
||||
<GenericTreeListPage :table-config="tableConfig" :header-actions="headerActions" :tree-setting="treeSetting" />
|
||||
<GenericTreeListPage
|
||||
:table-config="tableConfig"
|
||||
:header-actions="headerActions"
|
||||
:tree-setting="treeSetting"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GenericTreeListPage from '@/layout/components/GenericTreeListPage'
|
||||
import { Announcement } from '@/components'
|
||||
import { SystemUserFormatter, DialogDetailFormatter } from '@/components/TableFormatters'
|
||||
export default {
|
||||
components: {
|
||||
GenericTreeListPage,
|
||||
Announcement
|
||||
GenericTreeListPage
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -39,6 +40,10 @@ export default {
|
||||
url: '/api/v1/perms/users/assets/',
|
||||
hasTree: true,
|
||||
columns: ['hostname', 'ip', 'system_users', 'platform', 'comment', 'actions'],
|
||||
columnsShow: {
|
||||
default: ['hostname', 'ip', 'system_users', 'platform', 'actions'],
|
||||
min: ['hostname', 'actions']
|
||||
},
|
||||
columnsMeta: {
|
||||
hostname: {
|
||||
prop: 'hostname',
|
||||
@@ -86,7 +91,7 @@ export default {
|
||||
showOverflowTooltip: true,
|
||||
align: 'center',
|
||||
label: this.$t('assets.SystemUsers'),
|
||||
width: '150px',
|
||||
width: '120px',
|
||||
formatter: SystemUserFormatter,
|
||||
formatterArgs: {
|
||||
getUrl: ({ row }) => {
|
||||
@@ -102,6 +107,8 @@ export default {
|
||||
width: '100px'
|
||||
},
|
||||
actions: {
|
||||
width: '150px',
|
||||
align: 'center',
|
||||
formatterArgs: {
|
||||
hasDelete: false,
|
||||
loading: true,
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
</div>
|
||||
<ul class="content">
|
||||
<li v-if="announcement.content" class="item">
|
||||
<span class="item-title">【{{ announcement.subject }}】</span>
|
||||
<span>{{ announcement.content }}</span>
|
||||
<p class="item-title">【{{ announcement.subject }}】</p>
|
||||
<p class="item-content">{{ announcement.content }}</p>
|
||||
<span v-if="announcement.link">
|
||||
<el-link :href="announcement.link" target="_blank" class="item-url">
|
||||
{{ $t('common.ViewMore') }}
|
||||
@@ -70,6 +70,11 @@ ul,li {
|
||||
text-align: center;
|
||||
font-size: 15px;
|
||||
vertical-align: middle;
|
||||
margin-left: -10px;
|
||||
}
|
||||
.item-content {
|
||||
white-space: pre-wrap;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
.item-url {
|
||||
|
||||
@@ -14,7 +14,7 @@ export default {
|
||||
const vm = this
|
||||
return {
|
||||
cardConfig: {
|
||||
title: this.$t('route.SessionOffline')
|
||||
title: this.$t('route.RecentSession')
|
||||
},
|
||||
tableConfig: {
|
||||
url: '/api/v1/terminal/my-sessions/?limit=5',
|
||||
@@ -64,7 +64,7 @@ export default {
|
||||
}
|
||||
},
|
||||
hasSelection: false,
|
||||
paginationSize: 5
|
||||
paginationSize: 10
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ export default {
|
||||
}
|
||||
],
|
||||
hasSelection: false,
|
||||
paginationSize: 5
|
||||
paginationSize: 10
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -12,7 +12,10 @@
|
||||
<ul>
|
||||
<li><span class="title">{{ $t('audits.Username') }}</span>:<span>{{ users.name }}</span></li>
|
||||
<li><span class="title">{{ $t('users.Email') }}</span>:<span>{{ users.email }}</span></li>
|
||||
<li><span class="title">{{ $t('audits.LoginDate') }}</span>:<span>{{ this.$moment(users.last_login).format('YYYY-MM-DD HH:mm:ss') }}</span></li>
|
||||
<li>
|
||||
<span class="title">{{ $t('audits.LoginDate') }}</span>:
|
||||
<span>{{ $moment(users.last_login, 'YYYY-MM-DD HH:mm:ss').format('YYYY-MM-DD HH:mm:ss') }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<Page>
|
||||
<Announcement />
|
||||
<div class="home">
|
||||
<el-container class="container">
|
||||
<el-main class="main">
|
||||
@@ -8,12 +9,11 @@
|
||||
<el-row>
|
||||
<el-col :md="16" :xs="24" class="content-left">
|
||||
<Session />
|
||||
<Log />
|
||||
<Ticket v-if="hasValidLicense" />
|
||||
<Ticket v-if="$hasLicense() && $hasPerm('tickets.view_ticket')" />
|
||||
</el-col>
|
||||
<el-col :md="8" :xs="24">
|
||||
<User />
|
||||
<Announcement />
|
||||
<Log />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
@@ -26,8 +26,8 @@
|
||||
|
||||
<script>
|
||||
import { Page } from '@/layout/components'
|
||||
import { Announcement } from '@/components'
|
||||
import User from './components/User'
|
||||
import Announcement from './components/Announcement'
|
||||
import Ticket from './components/Ticket'
|
||||
import Log from './components/LoginLog'
|
||||
import Session from './components/Session'
|
||||
@@ -35,23 +35,12 @@ import Session from './components/Session'
|
||||
export default {
|
||||
name: 'Name',
|
||||
components: {
|
||||
Announcement,
|
||||
Page,
|
||||
User,
|
||||
Announcement,
|
||||
Ticket,
|
||||
Log,
|
||||
Session
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasValidLicense() {
|
||||
return this.$store.getters.hasValidLicense
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="14">
|
||||
<el-col :md="14" :sm="24">
|
||||
<DetailCard :title="cardTitle" :items="detailCardItems" />
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<el-col :md="10" :sm="24">
|
||||
<RunInfoCard type="danger" style="margin-top: 15px" v-bind="RunFailedConfig" />
|
||||
<RunInfoCard type="info" v-bind="RunSuccessConfig" style="margin-top: 15px" />
|
||||
</el-col>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user