mirror of https://github.com/veops/cmdb.git
feat(ui): ipam - add batch assign
This commit is contained in:
parent
6b16d393c7
commit
6532a937bf
|
@ -837,7 +837,13 @@ if __name__ == "__main__":
|
|||
onlineRatio: 'Online Ratio',
|
||||
scanEnable: 'Scan Enable',
|
||||
lastScanTime: 'Last Scan Time',
|
||||
isSuccess: 'Is Success'
|
||||
isSuccess: 'Is Success',
|
||||
batchAssign: 'Batch Assign',
|
||||
batchAssignInProgress: 'Assign in batches, {total} in total, {successNum} successful, {errorNum} failed',
|
||||
batchAssignCompleted: 'Batch Assign Completed',
|
||||
batchRecycle: 'Batch Recycle',
|
||||
batchRecycleInProgress: 'Recycle in batches, {total} in total, {successNum} successful, {errorNum} failed',
|
||||
batchRecycleCompleted: 'Batch Recycle Completed',
|
||||
}
|
||||
}
|
||||
export default cmdb_en
|
||||
|
|
|
@ -836,7 +836,13 @@ if __name__ == "__main__":
|
|||
onlineRatio: '在线率',
|
||||
scanEnable: '是否扫描',
|
||||
lastScanTime: '最后扫描时间',
|
||||
isSuccess: '是否成功'
|
||||
isSuccess: '是否成功',
|
||||
batchAssign: '批量分配',
|
||||
batchAssignInProgress: '正在批量分配,共{total}个,成功{successNum}个,失败{errorNum}个',
|
||||
batchAssignCompleted: '批量分配已完成',
|
||||
batchRecycle: '批量回收',
|
||||
batchRecycleInProgress: '正在批量回收,共{total}个,成功{successNum}个,失败{errorNum}个',
|
||||
batchRecycleCompleted: '批量回收已完成',
|
||||
}
|
||||
}
|
||||
export default cmdb_zh
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
:visible="visible"
|
||||
:width="700"
|
||||
:title="$t('cmdb.ipam.addressAssign')"
|
||||
:confirmLoading="confirmLoading"
|
||||
@ok="handleOk"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
|
@ -17,7 +18,7 @@
|
|||
<a-form-model-item
|
||||
label="IP"
|
||||
>
|
||||
{{ ipData.ip }}
|
||||
<span class="assign-form-ip" >{{ ipList.join(', ') }}</span>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item
|
||||
v-for="(item) in formList"
|
||||
|
@ -80,37 +81,29 @@ export default {
|
|||
attrList: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
subnetData: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
ipData: {},
|
||||
ipList: [],
|
||||
nodeId: -1,
|
||||
formList: [],
|
||||
form: {},
|
||||
formRules: {},
|
||||
statusSelectOption: [
|
||||
{
|
||||
value: 0,
|
||||
label: 'cmdb.ipam.assigned'
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: 'cmdb.ipam.reserved'
|
||||
}
|
||||
]
|
||||
confirmLoading: false,
|
||||
isBatch: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async open({
|
||||
ipData,
|
||||
ipList = [],
|
||||
ipData = null,
|
||||
nodeId,
|
||||
}) {
|
||||
this.isBatch = ipList.length !== 0
|
||||
this.ipList = ipList.length ? _.cloneDeep(ipList) : [ipData?.ip ?? '']
|
||||
this.ipData = ipData || {}
|
||||
this.nodeId = nodeId || -1
|
||||
this.visible = true
|
||||
|
@ -237,7 +230,8 @@ export default {
|
|||
this.form = {}
|
||||
this.formRules = {}
|
||||
this.formList = []
|
||||
this.visible = false
|
||||
this.confirmLoading = false
|
||||
this.isBatch = false
|
||||
|
||||
this.$refs.assignFormRef.clearValidate()
|
||||
},
|
||||
|
@ -248,16 +242,35 @@ export default {
|
|||
return
|
||||
}
|
||||
|
||||
await postIPAMAddress({
|
||||
ips: [this.ipData.ip],
|
||||
parent_id: this.nodeId,
|
||||
...this.form,
|
||||
subnet_mask: this?.ipData?.subnet_mask ?? undefined,
|
||||
gateway: this?.ipData?.gateway ?? undefined
|
||||
})
|
||||
this.confirmLoading = true
|
||||
|
||||
if (!this.isBatch) {
|
||||
await postIPAMAddress({
|
||||
ips: this.ipList,
|
||||
parent_id: this.nodeId,
|
||||
...this.form,
|
||||
subnet_mask: this?.ipData?.subnet_mask ?? undefined,
|
||||
gateway: this?.ipData?.gateway ?? undefined
|
||||
})
|
||||
|
||||
this.$emit('ok')
|
||||
} else {
|
||||
const ipChunk = _.chunk(this.ipList, 5)
|
||||
const paramsList = ipChunk.map((ips) => ({
|
||||
ips,
|
||||
parent_id: this.nodeId,
|
||||
...this.form,
|
||||
subnet_mask: this?.ipData?.subnet_mask ?? undefined,
|
||||
gateway: this?.ipData?.gateway ?? undefined
|
||||
}))
|
||||
this.$emit('batchAssign', {
|
||||
paramsList,
|
||||
ipList: this.ipList
|
||||
})
|
||||
}
|
||||
|
||||
this.$emit('ok')
|
||||
this.handleCancel()
|
||||
this.confirmLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
|
@ -280,5 +293,12 @@ export default {
|
|||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
|
||||
&-ip {
|
||||
max-height: 100px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -9,12 +9,11 @@
|
|||
<div class="address-null-tip2">{{ $t(addressNullTip) }}</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="loading" class="address-loading">
|
||||
<a-icon type="loading" class="address-loading-icon" />
|
||||
<span class="address-loading-text">{{ $t('loading') }}</span>
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<a-spin
|
||||
v-else
|
||||
:tip="loadTip"
|
||||
:spinning="loading"
|
||||
>
|
||||
<div class="address-header">
|
||||
<div class="address-header-left">
|
||||
<a-input-search
|
||||
|
@ -53,6 +52,15 @@
|
|||
</a-select-option>
|
||||
</a-select>
|
||||
|
||||
<div v-if="selectedIPList.length" class="ops-list-batch-action">
|
||||
<span @click="clickBatchAssign">{{ $t('cmdb.ipam.batchAssign') }}</span>
|
||||
<a-divider type="vertical" />
|
||||
<span @click="clickBatchRecycle">{{ $t('cmdb.ipam.batchRecycle') }}</span>
|
||||
<a-divider type="vertical" />
|
||||
<span @click="handleExport">{{ $t('export') }}</span>
|
||||
<span>{{ $t('cmdb.ci.selectRows', { rows: selectedIPList.length }) }}</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="currentLayout === 'grid'"
|
||||
class="address-header-status"
|
||||
|
@ -85,22 +93,12 @@
|
|||
</div>
|
||||
|
||||
<div class="address-header-right">
|
||||
<a-button
|
||||
type="primary"
|
||||
class="ops-button-ghost"
|
||||
ghost
|
||||
@click="handleExport"
|
||||
>
|
||||
<ops-icon type="veops-export" />
|
||||
{{ $t('export') }}
|
||||
</a-button>
|
||||
|
||||
<div class="address-header-layout">
|
||||
<div
|
||||
v-for="(item) in layoutList"
|
||||
:key="item.value"
|
||||
:class="['address-header-layout-item', currentLayout === item.value ?'address-header-layout-item-active' : '']"
|
||||
@click="currentLayout = item.value"
|
||||
@click="handleChangeLayout(item.value)"
|
||||
>
|
||||
<ops-icon :type="item.icon" />
|
||||
</div>
|
||||
|
@ -119,6 +117,7 @@
|
|||
:columnWidth="columnWidth"
|
||||
@openAssign="openAssign"
|
||||
@recycle="handleRecycle"
|
||||
@selectChange="handleTableSelectChange"
|
||||
/>
|
||||
|
||||
<GridIP
|
||||
|
@ -131,13 +130,13 @@
|
|||
@recycle="handleRecycle"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</a-spin>
|
||||
|
||||
<AssignForm
|
||||
ref="assignFormRef"
|
||||
:attrList="attrList"
|
||||
:subnetData="subnetData"
|
||||
@ok="getIPList"
|
||||
@batchAssign="batchAssign"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -188,6 +187,8 @@ export default {
|
|||
referenceCIIdMap: {},
|
||||
columnWidth: {},
|
||||
loading: false,
|
||||
selectedIPList: [],
|
||||
loadTip: this.$t('loading'),
|
||||
|
||||
currentStatus: 'all',
|
||||
filterOption: [
|
||||
|
@ -298,6 +299,7 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
async initData() {
|
||||
this.loadTip = this.$t('loading')
|
||||
this.loading = true
|
||||
try {
|
||||
await this.getColumns()
|
||||
|
@ -497,6 +499,7 @@ export default {
|
|||
let tableData = []
|
||||
if (this.currentLayout === 'table') {
|
||||
tableData = this.$refs.tableIPRef.getCheckedTableData()
|
||||
this.selectedIPList = []
|
||||
} else {
|
||||
tableData = this.filterIPList
|
||||
}
|
||||
|
@ -561,6 +564,143 @@ export default {
|
|||
})
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
handleChangeLayout(value) {
|
||||
if (this.currentLayout !== value) {
|
||||
if (value === 'grid') {
|
||||
this.selectedIPList = []
|
||||
}
|
||||
this.currentLayout = value
|
||||
}
|
||||
},
|
||||
|
||||
handleTableSelectChange(ips) {
|
||||
this.selectedIPList = ips
|
||||
},
|
||||
|
||||
clickBatchAssign() {
|
||||
this.$refs.assignFormRef.open({
|
||||
nodeId: this?.nodeData?._id,
|
||||
ipData: {
|
||||
subnet_mask: this?.subnetData?.subnet_mask ?? undefined,
|
||||
gateway: this?.subnetData?.gateway ?? undefined
|
||||
},
|
||||
ipList: this.selectedIPList
|
||||
})
|
||||
},
|
||||
|
||||
async batchAssign({
|
||||
paramsList,
|
||||
ipList
|
||||
}) {
|
||||
let successNum = 0
|
||||
let errorNum = 0
|
||||
|
||||
try {
|
||||
this.loading = true
|
||||
|
||||
this.loadTip = this.$t('cmdb.ipam.batchAssignInProgress', {
|
||||
total: ipList.length,
|
||||
successNum: successNum,
|
||||
errorNum: errorNum,
|
||||
})
|
||||
|
||||
await _.reduce(
|
||||
paramsList,
|
||||
(promiseChain, params) => {
|
||||
const ipCount = params?.ips?.length ?? 0
|
||||
|
||||
return promiseChain.then(() => {
|
||||
return postIPAMAddress(params).then(() => {
|
||||
successNum += ipCount
|
||||
}).catch(() => {
|
||||
errorNum += ipCount
|
||||
}).finally(() => {
|
||||
this.loadTip = this.$t('cmdb.ipam.batchAssignInProgress', {
|
||||
total: ipList.length,
|
||||
successNum: successNum,
|
||||
errorNum: errorNum,
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
Promise.resolve()
|
||||
)
|
||||
|
||||
if (this.$refs.tableIPRef) {
|
||||
this.$refs.tableIPRef.clearCheckbox()
|
||||
this.selectedIPList = []
|
||||
}
|
||||
this.$message.success(this.$t('cmdb.ipam.batchAssignCompleted'))
|
||||
this.loading = false
|
||||
this.getIPList()
|
||||
} catch (error) {
|
||||
console.log('error', error)
|
||||
}
|
||||
},
|
||||
|
||||
clickBatchRecycle() {
|
||||
this.$confirm({
|
||||
title: this.$t('warning'),
|
||||
content: this.$t('cmdb.ipam.recycleTip'),
|
||||
onOk: () => {
|
||||
this.handleBatchRecycle()
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
async handleBatchRecycle() {
|
||||
let successNum = 0
|
||||
let errorNum = 0
|
||||
|
||||
try {
|
||||
this.loading = true
|
||||
|
||||
this.loadTip = this.$t('cmdb.ipam.batchRecycleInProgress', {
|
||||
total: this.selectedIPList.length,
|
||||
successNum: successNum,
|
||||
errorNum: errorNum,
|
||||
})
|
||||
|
||||
const ipChunk = _.chunk(this.selectedIPList, 5)
|
||||
|
||||
await _.reduce(
|
||||
ipChunk,
|
||||
(promiseChain, ips) => {
|
||||
const ipCount = ips.length
|
||||
console.log('ipCount', ipCount, successNum, errorNum)
|
||||
return promiseChain.then(() => {
|
||||
return postIPAMAddress({
|
||||
ips,
|
||||
parent_id: this.nodeData._id,
|
||||
assign_status: 1
|
||||
}).then(() => {
|
||||
successNum += ipCount
|
||||
}).catch(() => {
|
||||
errorNum += ipCount
|
||||
}).finally(() => {
|
||||
this.loadTip = this.$t('cmdb.ipam.batchRecycleInProgress', {
|
||||
total: this.selectedIPList.length,
|
||||
successNum: successNum,
|
||||
errorNum: errorNum,
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
Promise.resolve()
|
||||
)
|
||||
|
||||
if (this.$refs.tableIPRef) {
|
||||
this.$refs.tableIPRef.clearCheckbox()
|
||||
this.selectedIPList = []
|
||||
}
|
||||
this.$message.success(this.$t('cmdb.ipam.batchRecycleCompleted'))
|
||||
this.loading = false
|
||||
this.getIPList()
|
||||
} catch (error) {
|
||||
console.log('error', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -570,7 +710,6 @@ export default {
|
|||
.address {
|
||||
width: 100%;
|
||||
height: fit-content;
|
||||
position: relative;
|
||||
|
||||
&-header {
|
||||
width: 100%;
|
||||
|
@ -695,27 +834,5 @@ export default {
|
|||
color: #2F54EB;
|
||||
}
|
||||
}
|
||||
|
||||
&-loading {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
color: #000000;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 10;
|
||||
|
||||
&-icon {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
&-text {
|
||||
margin-top: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
class="ops-unstripe-table checkbox-hover-table"
|
||||
@checkbox-change="onSelectChange"
|
||||
@checkbox-all="onSelectChange"
|
||||
@checkbox-range-end="onSelectChange"
|
||||
@checkbox-range-end="onSelectRangeEnd"
|
||||
>
|
||||
<vxe-table-column
|
||||
align="center"
|
||||
|
@ -241,13 +241,20 @@ export default {
|
|||
}
|
||||
|
||||
if (clearCheckbox) {
|
||||
tableRef.clearCheckboxRow()
|
||||
tableRef.clearCheckboxReserve()
|
||||
this.clearCheckbox()
|
||||
}
|
||||
|
||||
return tableData
|
||||
},
|
||||
|
||||
clearCheckbox() {
|
||||
const tableRef = this.$refs?.xTable?.getVxetableRef?.()
|
||||
if (tableRef) {
|
||||
tableRef.clearCheckboxRow()
|
||||
tableRef.clearCheckboxReserve()
|
||||
}
|
||||
},
|
||||
|
||||
getReferenceAttrValue(id, col) {
|
||||
const ci = this?.referenceCIIdMap?.[col?.reference_type_id]?.[id]
|
||||
if (!ci) {
|
||||
|
@ -267,7 +274,15 @@ export default {
|
|||
},
|
||||
|
||||
onSelectChange() {
|
||||
console.log('onSelectChange')
|
||||
const xTable = this.$refs.xTable.getVxetableRef()
|
||||
const records = [...xTable.getCheckboxRecords(), ...xTable.getCheckboxReserveRecords()]
|
||||
const ips = records.map((item) => item.ip)
|
||||
this.$emit('selectChange', ips)
|
||||
},
|
||||
|
||||
onSelectRangeEnd({ records }) {
|
||||
const ips = records?.map?.((item) => item.ip) || []
|
||||
this.$emit('selectChange', ips)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue