perf: optimize adhoc asset selection experience

This commit is contained in:
w940853815 2025-04-09 09:54:30 +08:00 committed by w940853815
parent 5ac386d56d
commit 39c0ae8cf7
2 changed files with 180 additions and 2 deletions

View File

@ -14,6 +14,7 @@
:visible.sync="showSetVariableDialog"
@submit="onSubmitVariable"
/>
<ConfirmRunAssetsDialog :visible.sync="showConfirmRunAssetsDialog" :assets="classifiedAssets" />
<AssetTreeTable ref="TreeTable" :tree-setting="treeSetting">
<template slot="table">
<div class="transition-box" style="width: calc(100% - 17px);">
@ -49,6 +50,7 @@ import Page from '@/layout/components/Page'
import AdhocOpenDialog from './AdhocOpenDialog.vue'
import AdhocSaveDialog from './AdhocSaveDialog.vue'
import VariableHelpDialog from './VariableHelpDialog.vue'
import ConfirmRunAssetsDialog from './components/ConfirmRunAssetsDialog.vue'
import SetVariableDialog from '@/views/ops/Template/components/SetVariableDialog.vue'
import { createJob, getJob, getTaskDetail, stopJob } from '@/api/ops'
@ -62,7 +64,8 @@ export default {
AssetTreeTable,
Page,
QuickJobTerm,
CodeEditor
CodeEditor,
ConfirmRunAssetsDialog
},
data() {
return {
@ -79,6 +82,7 @@ export default {
showOpenAdhocDialog: false,
showOpenAdhocSaveDialog: false,
showSetVariableDialog: false,
showConfirmRunAssetsDialog: false,
DataZTree: 0,
runas: '',
runasPolicy: 'skip',
@ -312,7 +316,12 @@ export default {
},
iShowTree: true,
variableFormData: [],
variableQueryParam: ''
variableQueryParam: '',
classifiedAssets: {
error: [],
runnable: [],
skipped: []
}
}
},
computed: {
@ -475,6 +484,17 @@ export default {
if (this.parameters) {
data.parameters = this.parameters
}
this.showConfirmRunAssetsDialog = true
this.$axios.post('/api/v1/ops/inventory/classified-hosts/', {
assets: hosts,
nodes: nodes,
module: this.module,
args: this.command,
runas: this.runas,
runas_policy: this.runasPolicy
}).then(data => {
this.classifiedAssets = data
})
createJob(data).then(res => {
this.executionInfo.timeCost = 0
this.executionInfo.status = { value: 'running', label: this.$t('Running') }

View File

@ -0,0 +1,158 @@
<template>
<Dialog
:title="$t('确认运行资产')"
:visible.sync="visible"
:show-buttons="true"
:show-confirm="true"
:show-cancel="true"
width="1000px"
>
<div class="confirm-run-assets-dialog">
<div class="assets-list">
<div class="asset-group">
<div class="group-title">可运行资产</div>
<el-checkbox-group v-model="selectedAssets" class="group-assets">
<el-checkbox
v-for="asset in runnableAssets"
:key="asset.id"
:label="asset.name"
class="asset-item"
>
<div class="asset-item">
<span>{{ asset.name }}</span>
<span class="asset-ip">{{ asset.ip }}</span>
</div>
</el-checkbox>
</el-checkbox-group>
</div>
</div>
<div class="asset-group">
<div class="group-title">不可运行资产</div>
<el-checkbox-group class="group-assets">
<el-checkbox
v-for="asset in failedAssets"
:key="asset.id"
:label="asset.name"
class="asset-item"
disabled
>
<div class="asset-item">
<span>{{ asset.name }}</span>
<span class="asset-status">{{ asset.error }}</span>
</div>
</el-checkbox>
</el-checkbox-group>
</div>
</div>
<div>
<div class="selected-count">已选 {{ selectedAssets.length }} 个资产</div>
</div>
</Dialog>
</template>
<script>
import Dialog from '@/components/Dialog'
export default {
name: 'ConfirmRunAssetsDialog',
components: {
Dialog
},
props: {
visible: {
type: Boolean,
default: false
},
assets: {
type: Object,
default: () => {
}
}
},
data() {
return {
searchQuery: '',
selectedAssets: []
}
},
computed: {
runnableAssets() {
return this.assets.runnable
},
failedAssets() {
return [...this.assets.skipped, ...this.assets.error]
}
},
methods: {
onCancel() {
this.$emit('update:visible', false)
},
onConfirm() {
this.$emit('confirm', this.selectedAssets)
}
}
}
</script>
<style scoped lang="scss">
.confirm-run-assets-dialog {
.assets-list {
max-height: 300px;
overflow-y: auto;
}
.asset-group {
margin-bottom: 16px;
.group-title {
font-weight: bold;
margin-bottom: 8px;
}
.group-assets {
::v-deep .el-checkbox__label {
display: inline-block;
padding-left: 10px;
line-height: 19px;
font-size: 13px;
width: 100%;
}
display: grid;
grid-template-columns: 1fr 1fr;
grid-row-gap: 5px;
justify-items: start;
.asset-item {
display: flex;
grid-template-columns: 1fr 1fr;
justify-content: space-between;
width: 100%;
.asset-ip {
padding-right: 10px;
}
.asset-status {
padding-right: 10px;
color: #ed5565
}
}
}
}
.footer {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 16px;
}
.selected-count {
color: #1ab394;
}
}
</style>