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('批量上传已完成')
       }
     },
   },