diff --git a/cmdb-ui/src/modules/cmdb/lang/en.js b/cmdb-ui/src/modules/cmdb/lang/en.js index 9ceb9fb8..97d47e2e 100644 --- a/cmdb-ui/src/modules/cmdb/lang/en.js +++ b/cmdb-ui/src/modules/cmdb/lang/en.js @@ -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 diff --git a/cmdb-ui/src/modules/cmdb/lang/zh.js b/cmdb-ui/src/modules/cmdb/lang/zh.js index 66aaba6a..8ddee976 100644 --- a/cmdb-ui/src/modules/cmdb/lang/zh.js +++ b/cmdb-ui/src/modules/cmdb/lang/zh.js @@ -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 diff --git a/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/assignForm.vue b/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/assignForm.vue index 45ce2768..940e8d71 100644 --- a/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/assignForm.vue +++ b/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/assignForm.vue @@ -3,6 +3,7 @@ :visible="visible" :width="700" :title="$t('cmdb.ipam.addressAssign')" + :confirmLoading="confirmLoading" @ok="handleOk" @cancel="handleCancel" > @@ -17,7 +18,7 @@ - {{ ipData.ip }} + {{ ipList.join(', ') }} [] - }, - 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; + } } diff --git a/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/index.vue b/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/index.vue index 24135754..a726a5bf 100644 --- a/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/index.vue +++ b/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/index.vue @@ -9,12 +9,11 @@
{{ $t(addressNullTip) }}
-
- - {{ $t('loading') }} -
- - + @@ -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; - } - } } diff --git a/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/tableIP.vue b/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/tableIP.vue index 062eb012..d9b2de00 100644 --- a/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/tableIP.vue +++ b/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/tableIP.vue @@ -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" > item.ip) + this.$emit('selectChange', ips) + }, + + onSelectRangeEnd({ records }) { + const ips = records?.map?.((item) => item.ip) || [] + this.$emit('selectChange', ips) }, } }