mirror of
https://github.com/jumpserver/lina.git
synced 2025-09-20 10:46:35 +00:00
merge: with v3 (#2250)
* perf: 增加celery输出 * fix: 修复网域列表资产选中后更新时不显示选中问题 * fix: 选择资产时会根据接口返回状态设置disabled * feat: 资产选择form 匹配正确的字段 * feat: 资产选择form 匹配正确的字段 * perf: 优化仪表盘环形图数据显示 * feat: 修改资产选择组件支持我的资产选择 * fix: 改密计划选择资产组件添加disabled状态 * fix: 修复资产账号点击资产树接口500问题 * fix: 更新网域选择资产组件添加disabled状态 * perf: 优化显示 * perf: 修改 Domain 列表页面 * perf: 修改网域列表网关字段跳转 * perf: 修改 GatewayList 页面 * perf: 选择资产组件弹窗显示资产详情 * perf: 修改资产详情账号列表页面 * perf: 修改资产账号详情 * fix: 修复改密详情页面报错误提示问题 * fix: 修复资产树点击资产接口报错问题 Co-authored-by: Aaron3S <chenyang@fit2cloud.com> Co-authored-by: “huailei000” <2280131253@qq.com> Co-authored-by: Bai <baijiangjie@gmail.com>
This commit is contained in:
@@ -98,11 +98,24 @@ export default {
|
||||
columnsShow: {
|
||||
min: ['name', 'username', 'actions'],
|
||||
default: [
|
||||
'name', 'hostname', 'ip', 'username',
|
||||
'version', 'privileged', 'actions'
|
||||
'name', 'username', 'version', 'privileged', 'actions', 'secret_type', 'actions'
|
||||
]
|
||||
},
|
||||
columnsMeta: {
|
||||
name: {
|
||||
showOverflowTooltip: true,
|
||||
formatter: function(row) {
|
||||
const to = {
|
||||
name: 'AssetAccountDetail',
|
||||
params: { id: row.id }
|
||||
}
|
||||
if (vm.$hasPerm('assets.view_account')) {
|
||||
return <router-link to={ to } >{ row.name }</router-link>
|
||||
} else {
|
||||
return <span>{ row.name }</span>
|
||||
}
|
||||
}
|
||||
},
|
||||
asset: {
|
||||
label: this.$t('assets.Asset'),
|
||||
showOverflowTooltip: true,
|
||||
|
@@ -31,7 +31,7 @@
|
||||
|
||||
<script>
|
||||
import TreeTable from '@/components/TreeTable'
|
||||
import { DetailFormatter } from '@/components/TableFormatters'
|
||||
import { DialogDetailFormatter } from '@/components/TableFormatters'
|
||||
import Select2 from '@/components/FormFields/Select2'
|
||||
import Dialog from '@/components/Dialog'
|
||||
|
||||
@@ -39,6 +39,14 @@ export default {
|
||||
componentName: 'AssetSelect',
|
||||
components: { TreeTable, Select2, Dialog },
|
||||
props: {
|
||||
baseUrl: {
|
||||
type: String,
|
||||
default: '/api/v1/assets/assets/'
|
||||
},
|
||||
baseNodeUrl: {
|
||||
type: String,
|
||||
default: '/api/v1/assets/nodes/'
|
||||
},
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
@@ -55,12 +63,20 @@ export default {
|
||||
}
|
||||
},
|
||||
data() {
|
||||
const iValue = []
|
||||
for (const item of this.value) {
|
||||
if (typeof item === 'object') {
|
||||
iValue.push(item.id)
|
||||
} else {
|
||||
iValue.push(item)
|
||||
}
|
||||
}
|
||||
const select2Config = {
|
||||
value: this.value,
|
||||
value: iValue,
|
||||
multiple: true,
|
||||
clearable: true,
|
||||
ajax: {
|
||||
url: '/api/v1/assets/assets/?fields_size=mini',
|
||||
url: this.baseUrl,
|
||||
transformOption: (item) => {
|
||||
return { label: item.name + '(' + item.address + ')', value: item.id }
|
||||
}
|
||||
@@ -69,24 +85,22 @@ export default {
|
||||
const vm = this
|
||||
return {
|
||||
dialogVisible: false,
|
||||
initialValue: _.cloneDeep(this.value),
|
||||
initialValue: _.cloneDeep(iValue),
|
||||
rowSelected: [],
|
||||
initSelection: null,
|
||||
treeSetting: {
|
||||
showMenu: false,
|
||||
showRefresh: true,
|
||||
showAssets: false,
|
||||
showSearch: true,
|
||||
customTreeHeader: true,
|
||||
url: '/api/v1/assets/assets/?fields_size=mini',
|
||||
nodeUrl: '/api/v1/assets/nodes/',
|
||||
url: this.baseUrl,
|
||||
nodeUrl: this.baseNodeUrl,
|
||||
// ?assets=0不显示资产. =1显示资产
|
||||
treeUrl: '/api/v1/assets/nodes/children/tree/?assets=0'
|
||||
treeUrl: `${this.baseNodeUrl}/children/tree/?assets=0`
|
||||
},
|
||||
select2Config: select2Config,
|
||||
dialogSelect2Config: select2Config,
|
||||
tableConfig: {
|
||||
url: '/api/v1/assets/assets/?fields_size=mini',
|
||||
url: this.baseUrl,
|
||||
hasTree: true,
|
||||
canSelect: this.canSelect,
|
||||
columns: [
|
||||
@@ -95,25 +109,65 @@ export default {
|
||||
label: this.$t('assets.Name'),
|
||||
sortable: true,
|
||||
showOverflowTooltip: true,
|
||||
formatter: DetailFormatter,
|
||||
formatter: DialogDetailFormatter,
|
||||
formatterArgs: {
|
||||
route: 'AssetDetail'
|
||||
getDialogTitle: function({ col, row }) { this.$t('assets.AssetDetail') }.bind(this),
|
||||
getDetailItems: function({ col, row }) {
|
||||
return [
|
||||
{
|
||||
key: this.$t('assets.Name'),
|
||||
value: row.name
|
||||
},
|
||||
{
|
||||
key: this.$t('assets.AssetAddress'),
|
||||
value: row.address
|
||||
},
|
||||
{
|
||||
key: this.$t('assets.Protocols'),
|
||||
value: row.protocols.map(item => item.name).join(', ')
|
||||
},
|
||||
{
|
||||
key: this.$t('assets.Category'),
|
||||
value: row.category.label
|
||||
},
|
||||
{
|
||||
key: this.$t('assets.Type'),
|
||||
value: row.type.label
|
||||
},
|
||||
{
|
||||
key: this.$t('assets.Platform'),
|
||||
value: row.platform?.name || ''
|
||||
},
|
||||
{
|
||||
key: this.$t('common.Active'),
|
||||
value: row.is_active
|
||||
},
|
||||
{
|
||||
key: this.$t('assets.Comment'),
|
||||
value: row.comment
|
||||
}
|
||||
]
|
||||
}.bind(this)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'ip',
|
||||
prop: 'address',
|
||||
label: this.$t('assets.ipDomain'),
|
||||
sortable: 'custom'
|
||||
},
|
||||
{
|
||||
prop: 'platform',
|
||||
label: this.$t('assets.Platform'),
|
||||
sortable: true
|
||||
sortable: true,
|
||||
formatter: function(row) {
|
||||
return row.platform.name
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'protocols',
|
||||
formatter: function(row) {
|
||||
return <span> {row.protocols?.toString()} </span>
|
||||
const data = row.protocols.map(p => <el-tag size='mini'>{p.name}/{p.port} </el-tag>)
|
||||
return <span> {data} </span>
|
||||
},
|
||||
label: this.$t('assets.Protocols')
|
||||
}
|
||||
@@ -128,7 +182,7 @@ export default {
|
||||
}
|
||||
},
|
||||
theRowDefaultIsSelected: (row) => {
|
||||
return this.value.indexOf(row.id) > -1
|
||||
return iValue.indexOf(row.id) > -1
|
||||
}
|
||||
},
|
||||
headerActions: {
|
||||
@@ -186,15 +240,15 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
.el-select {
|
||||
.el-select {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.page ::v-deep .page-heading {
|
||||
.page ::v-deep .page-heading {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.el-dialog__wrapper ::v-deep .el-dialog__body {
|
||||
.el-dialog__wrapper ::v-deep .el-dialog__body {
|
||||
padding: 0;
|
||||
|
||||
.tree-table {
|
||||
@@ -210,10 +264,9 @@ export default {
|
||||
padding: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.page ::v-deep .treebox {
|
||||
.page ::v-deep .treebox {
|
||||
height: inherit !important;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
|
@@ -128,9 +128,9 @@ export default {
|
||||
query['asset'] = ''
|
||||
url = `${this.setting.url}${combinator}node_id=${objectId}&show_current_asset=${show_current_asset}`
|
||||
} else if (treeNode.meta.type === 'asset') {
|
||||
query['asset'] = treeNode.meta.data.id
|
||||
query['asset'] = treeNode.meta.data?.id || treeNode.id
|
||||
query['node'] = ''
|
||||
url = `${this.setting.url}${combinator}asset_id=${objectId}&show_current_asset=${show_current_asset}`
|
||||
url = `${this.setting.url}${combinator}asset_id=${query.asset}&show_current_asset=${show_current_asset}`
|
||||
}
|
||||
this.$router.push({ query })
|
||||
this.$emit('urlChange', url)
|
||||
|
@@ -68,7 +68,9 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.card >>> .el-card__body {
|
||||
padding: 0
|
||||
padding: 0;
|
||||
}
|
||||
.el-card {
|
||||
border: 0!important;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
@@ -104,6 +104,7 @@
|
||||
},
|
||||
"assets": {
|
||||
"UserSwitchFrom": "User switch from",
|
||||
"AssetAddress": "IP/Host",
|
||||
"sshkeyAccount": "ssh key account",
|
||||
"passwordAccount": "Password account",
|
||||
"SelectTemplate": "Select template",
|
||||
@@ -180,6 +181,7 @@
|
||||
"DomainHelpMessage": "The domain function is added to address the fact that some environments (such as the hybrid cloud) cannot be connected directly by jumping on the gateway server.\nJMS => Domain gateway => Target assets",
|
||||
"FullName": "Full name",
|
||||
"Gateway": "Gateway",
|
||||
"GatewayList": "Gateway",
|
||||
"GatewayProtocolHelpText": "SSH protocol gateway, support proxy SSH, RDP, VNC",
|
||||
"Hostname": "Hostname",
|
||||
"IP": "IP",
|
||||
@@ -412,7 +414,6 @@
|
||||
"Push": "Push",
|
||||
"Receivers": "Receivers",
|
||||
"QuickUpdate": "Quick update",
|
||||
"QuickSelect": "Quick select",
|
||||
"RemoveSuccessMsg": "Remove success",
|
||||
"Reset": "Reset",
|
||||
"Search": "Search",
|
||||
|
@@ -109,6 +109,7 @@
|
||||
"NoSQLProtocol": "非リレーショナルデータベース"
|
||||
},
|
||||
"assets": {
|
||||
"AssetAddress": "IP/ホスト名",
|
||||
"UserSwitchFrom": "ユーザーは",
|
||||
"sshkeyAccount": "SSHキー",
|
||||
"passwordAccount": "パスワード",
|
||||
|
@@ -419,6 +419,7 @@
|
||||
"DateLast3Months": "最近三月",
|
||||
"DateLastMonth": "最近一月",
|
||||
"DateLastWeek": "最近一周",
|
||||
"DateStart": "开始日期",
|
||||
"Delete": "删除",
|
||||
"Disable": "禁用",
|
||||
"Download": "下载",
|
||||
@@ -493,7 +494,6 @@
|
||||
"dateCreated": "创建日期",
|
||||
"dateExpired": "失效日期",
|
||||
"dateFinished": "完成日期",
|
||||
"DateStart": "开始日期",
|
||||
"deleteErrorMsg": "删除失败",
|
||||
"deleteFailedMsg": "删除失败",
|
||||
"deleteSelected": "删除所选",
|
||||
@@ -1675,7 +1675,6 @@
|
||||
"OpenStack": "OpenStack",
|
||||
"GCP": "谷歌云",
|
||||
"FC": "Fusion Compute",
|
||||
"LAN": "局域网",
|
||||
"AWS_China": "AWS(中国)",
|
||||
"AWS_Int": "AWS(国际)",
|
||||
"HuaweiCloud": "华为云",
|
||||
|
@@ -33,7 +33,7 @@ export default {
|
||||
return {
|
||||
quickActions: [
|
||||
{
|
||||
title: this.$t('assets.PrivilegedTemplate'),
|
||||
title: this.$t('assets.Privileged'),
|
||||
type: 'switcher',
|
||||
attrs: {
|
||||
model: vm.object.privileged,
|
||||
|
@@ -45,7 +45,7 @@ export default {
|
||||
url = setUrlParam(url, 'asset', '')
|
||||
url = setUrlParam(url, 'node', nodeId)
|
||||
} else if (treeNode.meta.type === 'asset') {
|
||||
const assetId = treeNode.meta.data.id
|
||||
const assetId = treeNode.meta.data?.id || treeNode?.id
|
||||
url = setUrlParam(url, 'node', '')
|
||||
url = setUrlParam(url, 'asset', assetId)
|
||||
}
|
||||
|
@@ -23,8 +23,8 @@ export default {
|
||||
return {
|
||||
plan: { name: '', username: '', comment: '' },
|
||||
config: {
|
||||
activeMenu: 'ChangeAuthPlanInfo',
|
||||
url: '/api/v1/assets/change-secret-automations/',
|
||||
activeMenu: 'ChangeSecreAtutomationInfo',
|
||||
url: '/api/v1/assets/change-secret-automations',
|
||||
submenu: [
|
||||
{
|
||||
title: this.$t('common.BasicInfo'),
|
||||
|
@@ -52,6 +52,11 @@ export const getFields = () => {
|
||||
rules: [
|
||||
{ required: false }
|
||||
],
|
||||
el: {
|
||||
canSelect: (row) => {
|
||||
return row.enabled_info.change_secret_enabled
|
||||
}
|
||||
},
|
||||
label: i18n.t('xpack.Asset')
|
||||
},
|
||||
passphrase: {
|
||||
|
@@ -98,7 +98,7 @@ export default {
|
||||
url = setUrlParam(url, 'asset', '')
|
||||
url = setUrlParam(url, 'node', nodeId)
|
||||
} else if (treeNode.meta.type === 'asset') {
|
||||
const assetId = treeNode.meta.data.id
|
||||
const assetId = treeNode.meta.data?.id || treeNode.id
|
||||
url = setUrlParam(url, 'node', '')
|
||||
url = setUrlParam(url, 'asset', assetId)
|
||||
}
|
||||
|
@@ -23,7 +23,10 @@ export default {
|
||||
component: AssetSelect,
|
||||
label: this.$t('assets.Assets'),
|
||||
el: {
|
||||
value: []
|
||||
value: [],
|
||||
canSelect: (row) => {
|
||||
return row.enabled_info.domain_enabled
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@@ -55,8 +55,7 @@ export default {
|
||||
tableConfig: {
|
||||
url: `/api/v1/assets/gateways/?domain=${this.$route.params.id}`,
|
||||
columns: [
|
||||
'name', 'address', 'platform', 'password_account',
|
||||
'ssh_key_account', 'connectivity', 'is_active', 'actions'
|
||||
'name', 'address', 'platform', 'connectivity', 'is_active', 'actions'
|
||||
],
|
||||
columnsMeta: {
|
||||
name: {
|
||||
@@ -72,34 +71,6 @@ export default {
|
||||
address: {
|
||||
width: '140px'
|
||||
},
|
||||
password_account: {
|
||||
label: this.$t('assets.passwordAccount'),
|
||||
formatter: function(row) {
|
||||
const [accountInfo] = row.effective_accounts.filter(
|
||||
item => item.secret_type === 'password'
|
||||
)
|
||||
if (!accountInfo) return <span>-</span>
|
||||
const to = {
|
||||
name: 'AssetAccountDetail',
|
||||
params: { id: accountInfo.id }
|
||||
}
|
||||
return <router-link to={ to } >{ accountInfo.username }</router-link>
|
||||
}
|
||||
},
|
||||
ssh_key_account: {
|
||||
label: this.$t('assets.sshkeyAccount'),
|
||||
formatter: function(row) {
|
||||
const [accountInfo] = row.effective_accounts.filter(
|
||||
item => item.secret_type === 'ssh_key'
|
||||
)
|
||||
if (!accountInfo) return <span>-</span>
|
||||
const to = {
|
||||
name: 'AssetAccountDetail',
|
||||
params: { id: accountInfo.id }
|
||||
}
|
||||
return <router-link to={ to } >{ accountInfo.username }</router-link>
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
formatterArgs: {
|
||||
updateRoute: 'GatewayUpdate',
|
||||
|
@@ -28,7 +28,7 @@ export default {
|
||||
name: 'Detail'
|
||||
},
|
||||
{
|
||||
title: this.$t('assets.Gateway'),
|
||||
title: this.$t('assets.GatewayList'),
|
||||
name: 'GatewayList',
|
||||
hidden: () => !this.$hasPerm('assets.view_gateway')
|
||||
}
|
||||
|
@@ -15,27 +15,32 @@ export default {
|
||||
tableConfig: {
|
||||
url: '/api/v1/assets/domains/',
|
||||
columns: [
|
||||
'name', 'asset_count', 'application_count', 'gateway_count', 'date_created',
|
||||
'comment', 'org_name', 'actions'
|
||||
'name', 'asset_count', 'gateway_count', 'comment',
|
||||
'date_created', 'org_name', 'actions'
|
||||
],
|
||||
columnsShow: {
|
||||
min: ['name', 'actions'],
|
||||
default: ['name', 'asset_count', 'application_count', 'gateway_count', 'comment', 'actions']
|
||||
default: ['name', 'asset_count', 'gateway_count', 'comment', 'actions']
|
||||
},
|
||||
columnsMeta: {
|
||||
asset_count: {
|
||||
label: this.$t('assets.Assets')
|
||||
},
|
||||
application_count: {
|
||||
label: this.$t('assets.Applications')
|
||||
prop: 'assets',
|
||||
label: this.$t('assets.Assets'),
|
||||
formatter: function(row) {
|
||||
return <span> { row.assets.length } </span>
|
||||
}
|
||||
},
|
||||
gateway_count: {
|
||||
prop: 'gateways',
|
||||
label: this.$t('assets.Gateway'),
|
||||
formatter: DetailFormatter,
|
||||
formatterArgs: {
|
||||
permissions: 'assets.view_gateway',
|
||||
routeQuery: {
|
||||
activeTab: 'GatewayList'
|
||||
},
|
||||
getTitle: function({ cellValue }) {
|
||||
return cellValue.length
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,10 +1,24 @@
|
||||
<template>
|
||||
<el-row :gutter="16">
|
||||
<el-col :lg="12" :sm="12" class="margin-top-16">
|
||||
<DataCard :config="logConfig" />
|
||||
<DataCard :config="logConfig">
|
||||
<div class="custom">
|
||||
<span>{{ logConfig.total }}</span>
|
||||
<span>
|
||||
<svg-icon :icon-class="logConfig.icon" class="font" />
|
||||
</span>
|
||||
</div>
|
||||
</DataCard>
|
||||
</el-col>
|
||||
<el-col :lg="12" :sm="12" class="margin-top-16">
|
||||
<DataCard :config="assetConfig" />
|
||||
<DataCard :config="assetConfig">
|
||||
<div class="custom">
|
||||
<span>{{ assetConfig.total }}</span>
|
||||
<span>
|
||||
<svg-icon :icon-class="assetConfig.icon" class="font" />
|
||||
</span>
|
||||
</div>
|
||||
</DataCard>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
@@ -62,17 +76,22 @@ export default {
|
||||
&total_count_commands=1
|
||||
&total_count_commands_danger=1
|
||||
`)
|
||||
const logActive = data.total_count_user_login_success_logs === 0 ? 0 : ((data.total_count_user_login_success_logs / data.total_count_user_login_logs) * 100).toFixed(0)
|
||||
const logTotal = logActive === 100 ? 0 : 100 - logActive
|
||||
const logs = [
|
||||
{ name: this.$t('dashboard.ActiveUser'), value: data.total_count_user_login_logs },
|
||||
{ name: this.$t('dashboard.InActiveUser'), value: data.total_count_user_login_success_logs }
|
||||
{ name: this.$t('dashboard.ActiveUser'), value: logActive },
|
||||
{ name: this.$t('dashboard.InActiveUser'), value: logTotal }
|
||||
]
|
||||
this.$set(this.logConfig, 'data', logs)
|
||||
this.$set(this.logConfig, 'total', data.total_count_user_login_logs)
|
||||
this.$set(this.logConfig, 'active', data.total_count_user_login_success_logs)
|
||||
this.$set(this.logConfig, 'weekAdd', data.total_count_user_login_success_logs)
|
||||
|
||||
const assetActive = data.total_count_commands_danger === 0 ? 0 : ((data.total_count_commands_danger / data.total_count_commands) * 100).toFixed(0)
|
||||
const assetTotal = assetActive === 100 ? 0 : 100 - assetActive
|
||||
const assets = [
|
||||
{ name: this.$t('dashboard.ActiveAsset'), value: data.total_count_commands },
|
||||
{ name: this.$t('dashboard.InActiveAsset'), value: data.total_count_commands_danger }
|
||||
{ name: this.$t('dashboard.ActiveAsset'), value: assetActive },
|
||||
{ name: this.$t('dashboard.InActiveAsset'), value: assetTotal }
|
||||
]
|
||||
this.$set(this.assetConfig, 'data', assets)
|
||||
this.$set(this.assetConfig, 'total', data.total_count_commands)
|
||||
|
@@ -6,7 +6,7 @@
|
||||
</div>
|
||||
<LineChart v-bind="chartConfig" />
|
||||
</div>
|
||||
<SummaryCountCard :config="config" :items="summaryItems" class="margin-top-16" />
|
||||
<SummaryCountCard :config="chartTitleConfig" :items="summaryItems" class="margin-top-16" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -33,6 +33,10 @@ export default {
|
||||
title: this.$t('dashboard.SessionTrend'),
|
||||
tip: this.$t('dashboard.SessionTrend')
|
||||
},
|
||||
chartTitleConfig: {
|
||||
title: this.$t('route.BatchCommand'),
|
||||
tip: this.$t('route.BatchCommand')
|
||||
},
|
||||
chartConfig: {
|
||||
datesMetrics: [],
|
||||
secondaryName: this.$t('dashboard.IndexName'),
|
||||
|
@@ -51,22 +51,27 @@ export default {
|
||||
async init() {
|
||||
const data = await this.$axios.get(`/api/v1/index/?total_count_users=1
|
||||
&total_count_users_this_week=1
|
||||
&total_count_today_login_users=1
|
||||
&total_count_login_users=1
|
||||
&total_count_assets=1
|
||||
&total_count_assets_this_week=1
|
||||
&total_count_today_active_assets=1
|
||||
`)
|
||||
const userActive = data.total_count_login_users === 0 ? 0 : ((data.total_count_login_users / data.total_count_users) * 100).toFixed(0)
|
||||
const userTotal = userActive === 100 ? 0 : 100 - userActive
|
||||
const users = [
|
||||
{ name: this.$t('dashboard.ActiveUser'), value: data.total_count_users },
|
||||
{ name: this.$t('dashboard.InActiveUser'), value: data.total_count_today_login_users }
|
||||
{ name: this.$t('dashboard.ActiveUser'), value: userActive },
|
||||
{ name: this.$t('dashboard.InActiveUser'), value: userTotal }
|
||||
]
|
||||
this.$set(this.userConfig, 'data', users)
|
||||
this.$set(this.userConfig, 'total', data.total_count_users)
|
||||
this.$set(this.userConfig, 'active', data.total_count_today_login_users)
|
||||
this.$set(this.userConfig, 'active', data.total_count_login_users)
|
||||
this.$set(this.userConfig, 'weekAdd', data.total_count_users_this_week)
|
||||
|
||||
const assetActive = data.total_count_today_active_assets === 0 ? 0 : ((data.total_count_today_active_assets / data.total_count_assets) * 100).toFixed(0)
|
||||
const assetTotal = assetActive === 100 ? 0 : 100 - assetActive
|
||||
const assets = [
|
||||
{ name: this.$t('dashboard.ActiveAsset'), value: data.total_count_assets },
|
||||
{ name: this.$t('dashboard.InActiveAsset'), value: data.total_count_today_active_assets }
|
||||
{ name: this.$t('dashboard.ActiveAsset'), value: assetActive },
|
||||
{ name: this.$t('dashboard.InActiveAsset'), value: assetTotal }
|
||||
]
|
||||
this.$set(this.assetConfig, 'data', assets)
|
||||
this.$set(this.assetConfig, 'total', data.total_count_assets)
|
||||
|
@@ -1,10 +1,11 @@
|
||||
<template>
|
||||
<div class="card">
|
||||
<div>
|
||||
<div class="card-content">
|
||||
<div class="title">
|
||||
<Title :config="config" />
|
||||
</div>
|
||||
<div class="sub">{{ config.subTitle }}</div>
|
||||
<slot class="custom">
|
||||
<div class="num">{{ config.total }}</div>
|
||||
<div class="add">
|
||||
<span class="add-num">
|
||||
@@ -15,6 +16,7 @@
|
||||
<svg-icon v-if="config.icon" :icon-class="config.icon" class="font" />
|
||||
</span>
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
<div class="ring">
|
||||
<RingChart :config="config" />
|
||||
@@ -48,6 +50,10 @@ export default {
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
background-color: #FFF;
|
||||
.card-content {
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid #EFF0F1;
|
||||
}
|
||||
.title {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
@@ -67,8 +73,13 @@ export default {
|
||||
.add {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid #EFF0F1;
|
||||
}
|
||||
.custom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-weight: 500;
|
||||
font-size: 32px;
|
||||
padding-bottom: 18px;
|
||||
}
|
||||
.ring {
|
||||
padding: 26px 0 10px;
|
||||
|
@@ -64,7 +64,7 @@ export default {
|
||||
color: [color, 'rgba(43, 147, 124, 0.05)'],
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
||||
formatter: '{a} <br/>{b}: {d}%'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
|
@@ -59,7 +59,7 @@ export default {
|
||||
value: row.name
|
||||
},
|
||||
{
|
||||
key: this.$t('assets.Address'),
|
||||
key: this.$t('assets.AssetAddress'),
|
||||
value: row.address
|
||||
},
|
||||
{
|
||||
@@ -76,7 +76,7 @@ export default {
|
||||
},
|
||||
{
|
||||
key: this.$t('assets.Platform'),
|
||||
value: row.platform
|
||||
value: row.platform?.name || ''
|
||||
},
|
||||
{
|
||||
key: this.$t('common.Active'),
|
||||
|
@@ -31,8 +31,9 @@ export default {
|
||||
visible: false,
|
||||
width: '60%',
|
||||
tableConfig: {
|
||||
hasSelection: false,
|
||||
url: `/api/v1/ops/adhocs/`,
|
||||
columns: ['name', 'module', 'args', 'actions'],
|
||||
columns: ['name', 'module', 'args', 'comment', 'actions'],
|
||||
columnsMeta: {
|
||||
actions: {
|
||||
formatter: ActionsFormatter,
|
||||
@@ -42,7 +43,7 @@ export default {
|
||||
hasDelete: false,
|
||||
extraActions: [
|
||||
{
|
||||
title: '选择',
|
||||
title: this.$tc('common.Select'),
|
||||
name: 'select',
|
||||
can: true,
|
||||
callback: ({ row }) => {
|
||||
|
@@ -65,6 +65,10 @@ export default {
|
||||
this.showOpenAdhocDialog = true
|
||||
},
|
||||
openAdhocSaveDialog() {
|
||||
if (!this.iValue.length > 0) {
|
||||
this.$message.error(this.$tc('ops.CommandNotBeNone'))
|
||||
return
|
||||
}
|
||||
this.showOpenAdhocSaveDialog = true
|
||||
},
|
||||
onSelectAdhoc(adhoc) {
|
||||
|
@@ -86,6 +86,8 @@ export default {
|
||||
required: false
|
||||
}],
|
||||
el: {
|
||||
baseUrl: '/api/v1/perms/users/self/assets/',
|
||||
baseNodeUrl: '/api/v1/perms/users/self/nodes/',
|
||||
value: []
|
||||
}
|
||||
},
|
||||
|
@@ -4,6 +4,7 @@
|
||||
|
||||
<script type="text/jsx">
|
||||
import ListTable from '@/components/ListTable'
|
||||
import { openTaskPage } from '@/utils/jms'
|
||||
|
||||
export default {
|
||||
name: 'TaskHistory',
|
||||
@@ -21,13 +22,9 @@ export default {
|
||||
tableConfig: {
|
||||
url: `/api/v1/ops/task-executions/?task_id=${this.object.id}`,
|
||||
columns: [
|
||||
'date_start', 'date_finished', 'state', 'is_finished', 'actions'
|
||||
'date_start', 'date_finished', 'is_success', 'is_finished', 'actions'
|
||||
],
|
||||
columnsMeta: {
|
||||
state: {
|
||||
formatter: (row) => {
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
prop: 'id',
|
||||
formatterArgs: {
|
||||
@@ -38,10 +35,10 @@ export default {
|
||||
extraActions: [
|
||||
{
|
||||
name: 'detail',
|
||||
title: this.$t('ops.detail'),
|
||||
title: this.$t('ops.output'),
|
||||
type: 'primary',
|
||||
callback: function({ row, tableData }) {
|
||||
return this.$router.push({ name: 'HistoryExecutionDetail', params: { id: row.id }})
|
||||
openTaskPage(row.id)
|
||||
}
|
||||
}
|
||||
]
|
||||
|
Reference in New Issue
Block a user