diff --git a/cmdb-ui/src/modules/cmdb/api/batch.js b/cmdb-ui/src/modules/cmdb/api/batch.js index c37efc5..7959f50 100644 --- a/cmdb-ui/src/modules/cmdb/api/batch.js +++ b/cmdb-ui/src/modules/cmdb/api/batch.js @@ -16,12 +16,14 @@ export function processFile(fileObj) { } export function uploadData(ciId, data) { - data.ci_type = ciId - data.exist_policy = 'replace' return axios({ url: '/v0.1/ci', method: 'POST', - data, + data: { + ...data, + ci_type: ciId, + exist_policy: 'replace' + }, isShowMessage: false }) } diff --git a/cmdb-ui/src/modules/cmdb/views/batch/index.vue b/cmdb-ui/src/modules/cmdb/views/batch/index.vue index 5ac90b5..c6c8420 100644 --- a/cmdb-ui/src/modules/cmdb/views/batch/index.vue +++ b/cmdb-ui/src/modules/cmdb/views/batch/index.vue @@ -1,11 +1,16 @@ <template> <div class="cmdb-batch-upload" :style="{ height: `${windowHeight - 64}px` }"> <div id="title"> - <ci-type-choice @getCiTypeAttr="showCiType" /> + <ci-type-choice ref="ciTypeChoice" @getCiTypeAttr="showCiType" /> </div> <a-row> <a-col :span="12"> - <upload-file-form :ciType="ciType" ref="uploadFileForm" @uploadDone="uploadDone"></upload-file-form> + <upload-file-form + :isUploading="isUploading" + :ciType="ciType" + ref="uploadFileForm" + @uploadDone="uploadDone" + ></upload-file-form> </a-col> <a-col :span="24" v-if="ciType && uploadData.length"> <CiUploadTable :ciTypeAttrs="ciTypeAttrs" ref="ciUploadTable" :uploadData="uploadData"></CiUploadTable> @@ -13,15 +18,19 @@ <a-space size="large"> <a-button type="primary" ghost @click="handleCancel">取消</a-button> <a-button @click="handleUpload" type="primary">上传</a-button> + <a-button v-if="hasError && !isUploading" @click="downloadError" type="primary">失败下载</a-button> </a-space> </div> </a-col> - <a-col :span="24"> + <a-col :span="24" v-if="ciType"> <upload-result ref="uploadResult" :upLoadData="uploadData" :ciType="ciType" :unique-field="uniqueField" + :isUploading="isUploading" + @uploadResultDone="uploadResultDone" + @uploadResultError="uploadResultError" ></upload-result> </a-col> </a-row> @@ -52,7 +61,8 @@ export default { ciType: 0, uniqueField: '', uniqueId: 0, - displayUpload: true, + isUploading: false, + hasError: false, } }, computed: { @@ -60,13 +70,12 @@ export default { windowHeight: (state) => state.windowHeight, }), }, - inject: ['reload'], methods: { showCiType(message) { - this.ciTypeAttrs = message - this.ciType = message.type_id - this.uniqueField = message.unique - this.uniqueId = message.unique_id + this.ciTypeAttrs = message ?? {} + this.ciType = message?.type_id ?? 0 + this.uniqueField = message?.unique ?? '' + this.uniqueId = message?.unique_id ?? 0 }, uploadDone(dataList) { const _uploadData = filterNull(dataList).map((item, i) => { @@ -77,13 +86,13 @@ export default { const _find = this.ciTypeAttrs.attributes.find( (attr) => attr.alias === dataList[0][j] || attr.name === dataList[0][j] ) - if (_find?.value_type === '4') { + if (_find?.value_type === '4' && typeof ele === 'number') { _ele[dataList[0][j]] = moment(Math.round((ele - 25569) * 86400 * 1000 - 28800000)).format('YYYY-MM-DD') - } else if (_find?.value_type === '3') { + } else if (_find?.value_type === '3' && typeof ele === 'number') { _ele[dataList[0][j]] = moment(Math.round((ele - 25569) * 86400 * 1000 - 28800000)).format( 'YYYY-MM-DD HH:mm:ss' ) - } else if (_find?.value_type === '5') { + } else if (_find?.value_type === '5' && typeof ele === 'number') { _ele[dataList[0][j]] = moment(Math.round(ele * 86400 * 1000 - 28800000)).format('HH:mm:ss') } else { _ele[dataList[0][j]] = ele @@ -95,6 +104,9 @@ export default { return item }) this.uploadData = _uploadData.slice(1) + this.hasError = false + this.isUploading = false + this.$refs.uploadResult.visible = false }, handleUpload() { if (!this.ciType) { @@ -102,6 +114,7 @@ export default { return } if (this.uploadData && this.uploadData.length > 0) { + this.isUploading = true this.$nextTick(() => { this.$refs.uploadResult.upload2Server() }) @@ -110,7 +123,24 @@ export default { } }, handleCancel() { - this.reload() + if (!this.isUploading) { + this.showCiType(null) + this.$refs.ciTypeChoice.selectNum = null + this.hasError = false + } else { + this.$message.warning('批量上传已取消') + this.isUploading = false + } + }, + uploadResultDone() { + this.isUploading = false + }, + uploadResultError(index) { + this.hasError = true + this.$refs.ciUploadTable.uploadResultError(index) + }, + downloadError() { + this.$refs.ciUploadTable.downloadError() }, }, } diff --git a/cmdb-ui/src/modules/cmdb/views/batch/modules/CiTypeChoice.vue b/cmdb-ui/src/modules/cmdb/views/batch/modules/CiTypeChoice.vue index 5a7dc39..54f9c21 100644 --- a/cmdb-ui/src/modules/cmdb/views/batch/modules/CiTypeChoice.vue +++ b/cmdb-ui/src/modules/cmdb/views/batch/modules/CiTypeChoice.vue @@ -8,6 +8,7 @@ :style="{ width: '300px' }" class="ops-select" :filter-option="filterOption" + v-model="selectNum" > <a-select-option v-for="ciType in ciTypeList" :key="ciType.name" :value="ciType.id">{{ ciType.alias @@ -99,7 +100,7 @@ export default { return { ciTypeList: [], ciTypeName: '', - selectNum: 0, + selectNum: null, selectCiTypeAttrList: [], visible: false, checkedAttrs: [], @@ -131,7 +132,6 @@ export default { methods: { selectCiType(el) { // 当选择好模板类型时的回调函数 - this.selectNum = el getCITypeAttributesById(el).then((res) => { this.$emit('getCiTypeAttr', res) this.selectCiTypeAttrList = res @@ -155,7 +155,6 @@ export default { }) } this.parentsType = res.parents.filter((parent) => this.canEdit[parent.id]) - const _parentsForm = {} res.parents.forEach((item) => { const _find = item.attributes.find((attr) => attr.id === item.unique_id) diff --git a/cmdb-ui/src/modules/cmdb/views/batch/modules/CiUploadTable.vue b/cmdb-ui/src/modules/cmdb/views/batch/modules/CiUploadTable.vue index 53eeea7..ec97359 100644 --- a/cmdb-ui/src/modules/cmdb/views/batch/modules/CiUploadTable.vue +++ b/cmdb-ui/src/modules/cmdb/views/batch/modules/CiUploadTable.vue @@ -1,6 +1,7 @@ <template> <div class="cmdb-batch-upload-table"> <vxe-table + ref="xTable" stripe show-header-overflow show-overflow="" @@ -9,6 +10,7 @@ :max-height="200" :data="dataSource" resizable + :row-style="rowStyle" > <vxe-column type="seq" width="40" /> <vxe-column @@ -37,7 +39,9 @@ export default { }, }, data() { - return {} + return { + errorIndexList: [], + } }, computed: { columns() { @@ -65,7 +69,33 @@ export default { return _.cloneDeep(this.uploadData) }, }, - methods: {}, + watch: { + uploadData() { + this.errorIndexList = [] + }, + }, + methods: { + uploadResultError(index) { + const _errorIndexList = _.cloneDeep(this.errorIndexList) + _errorIndexList.push(index) + this.errorIndexList = _errorIndexList + }, + rowStyle({ rowIndex }) { + if (this.errorIndexList.includes(rowIndex)) { + return 'color:red;' + } + }, + downloadError() { + const data = this.uploadData.filter((item, index) => this.errorIndexList.includes(index)) + this.$refs.xTable.exportData({ + data, + type: 'xlsx', + columnFilterMethod({ column }) { + return column.property + }, + }) + }, + }, } </script> <style lang="less" scoped> diff --git a/cmdb-ui/src/modules/cmdb/views/batch/modules/UploadFileForm.vue b/cmdb-ui/src/modules/cmdb/views/batch/modules/UploadFileForm.vue index 1599a3b..bac1322 100644 --- a/cmdb-ui/src/modules/cmdb/views/batch/modules/UploadFileForm.vue +++ b/cmdb-ui/src/modules/cmdb/views/batch/modules/UploadFileForm.vue @@ -7,7 +7,7 @@ accept=".xls,.xlsx" :showUploadList="false" :fileList="fileList" - :disabled="!ciType" + :disabled="!ciType || isUploading" > <img :style="{ width: '80px', height: '80px' }" src="@/assets/file_upload.png" /> <p class="ant-upload-text">点击或拖拽文件至此上传!</p> @@ -29,7 +29,11 @@ export default { ciType: { type: Number, default: 0, - } + }, + isUploading: { + type: Boolean, + default: false, + }, }, data() { return { @@ -40,7 +44,20 @@ export default { percent: 0, } }, - + watch: { + ciType: { + handler(newValue) { + if (!newValue) { + this.ciItemNum = 0 + this.fileList = [] + this.dataList = [] + this.progressStatus = 'active' + this.percent = 0 + this.$emit('uploadDone', this.dataList) + } + }, + }, + }, methods: { customRequest(data) { this.fileList = [data.file] diff --git a/cmdb-ui/src/modules/cmdb/views/batch/modules/UploadResult.vue b/cmdb-ui/src/modules/cmdb/views/batch/modules/UploadResult.vue index eee7409..55c3b54 100644 --- a/cmdb-ui/src/modules/cmdb/views/batch/modules/UploadResult.vue +++ b/cmdb-ui/src/modules/cmdb/views/batch/modules/UploadResult.vue @@ -34,6 +34,10 @@ export default { required: true, type: String, }, + isUploading: { + type: Boolean, + default: false, + }, }, data: function() { return { @@ -51,13 +55,6 @@ export default { }, }, methods: { - async sleep(n) { - return new Promise((resolve) => { - setTimeout(() => { - resolve() - }, n || 5) - }) - }, async upload2Server() { this.visible = true this.success = 0 @@ -65,22 +62,31 @@ export default { this.errorItems = [] const floor = Math.ceil(this.total / 6) for (let i = 0; i < floor; i++) { - const itemList = this.upLoadData.slice(6 * i, 6 * i + 6) - const promises = itemList.map((x) => uploadData(this.ciType, x)) - await Promise.allSettled(promises) - .then((res) => { - res.forEach((r) => { - if (r.status === 'fulfilled') { - this.success += 1 - } else { - this.errorItems.push(r?.reason?.response?.data.message ?? '请求出现错误,请稍后再试') - this.errorNum += 1 - } + if (this.isUploading) { + const itemList = this.upLoadData.slice(6 * i, 6 * i + 6) + const promises = itemList.map((x) => uploadData(this.ciType, x)) + await Promise.allSettled(promises) + .then((res) => { + res.forEach((r, j) => { + if (r.status === 'fulfilled') { + this.success += 1 + } else { + this.errorItems.push(r?.reason?.response?.data.message ?? '请求出现错误,请稍后再试') + this.errorNum += 1 + this.$emit('uploadResultError', 6 * i + j) + } + }) }) - }) - .finally(() => { - this.complete += 6 - }) + .finally(() => { + this.complete += 6 + }) + } else { + break + } + } + if (this.isUploading) { + this.$emit('uploadResultDone') + this.$message.success('批量上传已完成') } }, },