add batch module

This commit is contained in:
shaohaojiecoder 2019-08-28 21:24:21 +08:00 committed by pycook
parent 13476128d5
commit 61f77cf311
5 changed files with 453 additions and 0 deletions

View File

@ -0,0 +1,85 @@
<template>
<div>
<div id="title">
<ci-type-choice @getCiTypeAttr="showCiType">
</ci-type-choice>
</div>
<a-row>
<a-col :span="18">
<a-card style="height: 605px">
<a-button class="ant-btn-primary" style="margin-left: 10px;" :disabled="uploadFlag" id="upload-button" @click="uploadData">上传</a-button>
<upload-file-form v-if="displayUpload" ref="fileEditor"></upload-file-form>
<ci-table v-if="editorOnline" :ciTypeAttrs="ciTypeAttrs" ref="onlineEditor"></ci-table>
</a-card>
</a-col>
<a-col :span="6">
<div style="min-height: 604px; background: white">
<a-card title="上传结果">
<upload-result v-if="beginLoad" :upLoadData="needDataList" :ciType="ciType" :unique-field="uniqueField"></upload-result>
</a-card>
</div>
</a-col>
</a-row>
</div>
</template>
<script>
import CiTypeChoice from './modules/CiTypeChoice'
import CiTable from './modules/CiTable'
import UploadFileForm from './modules/UploadFileForm'
import UploadResult from './modules/UploadResult'
import { filterNull } from '@/api/cmdb/batch'
export default {
name: 'Batch',
components: {
CiTypeChoice,
CiTable,
UploadFileForm,
UploadResult
},
data () {
return {
editorOnline: false,
uploadFlag: true,
ciTypeAttrs: [],
needDataList: [],
ciType: -1,
uniqueField: '',
uniqueId: 0,
beginLoad: false,
displayUpload: true
}
},
methods: {
showCiType (message) {
this.ciTypeAttrs = message
this.ciType = message.type_id
this.uniqueField = message.unique
this.uniqueId = message.unique_id
this.editorOnline = false
this.$nextTick(() => {
this.editorOnline = true
})
},
uploadData () {
if (this.ciType < 0) {
alert('尚未选择模板类型!')
return
}
this.beginLoad = false
const fileData = this.$refs.fileEditor.dataList
if (fileData.length > 0) {
this.needDataList = filterNull(fileData)
} else {
this.needDataList = filterNull(this.$refs.onlineEditor.getDataList())
}
this.displayUpload = false
this.$nextTick(() => {
this.beginLoad = true
this.displayUpload = true
})
}
}
}
</script>

View File

@ -0,0 +1,99 @@
<template>
<div>
<div id="hotTable" class="hotTable" style="overflow: hidden; height:275px">
<HotTable :root="root" ref="HTable" :settings="hotSettings"></HotTable>
</div>
</div>
</template>
<script>
import { HotTable } from '@handsontable-pro/vue'
export default {
name: 'Editor',
components: {
HotTable
},
props: { ciTypeAttrs: { type: Object, required: true } },
data: function () {
return {
root: 'test-hot',
dataTitle: []
}
},
computed: {
hotSettings () {
const whiteColumn = []
const aliasList = []
const dataTitle = []
this.$props.ciTypeAttrs.attributes.forEach(item => {
dataTitle.push(item.name)
aliasList.push(item.alias)
whiteColumn.push('')
})
this.dataTitle = dataTitle
const dt = {
data: [whiteColumn],
startRows: 11,
startCols: 6,
minRows: 5,
minCols: 4,
maxRows: 90,
maxCols: 90,
rowHeaders: true,
// minSpareCols: 2, //列留白
colHeaders: aliasList,
minSpareRows: 2, // 行留白
// autoWrapRow: true, // 自动换行
// 自定义右键菜单可汉化默认布尔值
contextMenu: {
items: {
row_above: {
name: '上方插入一行'
},
row_below: {
name: '下方插入一行'
},
moverow: {
name: '删除行'
},
unfreeze_column: {
name: '取消列固定'
},
hsep1: '---------', // 提供分隔线
hsep2: '---------'
}
},
// width: '100%',
// fillHandle: true, // 选中拖拽复制 possible values: true, false, "horizontal", "vertical"
fixedColumnsLeft: 0, // 固定左边列数
fixedRowsTop: 0, // 固定上边列数
manualColumnFreeze: true, // 手动固定列
// manualColumnMove: true, // 手动移动列
// manualRowMove: true, // 手动移动行
// manualColumnResize: true, // 手工更改列距
// manualRowResize: true, // 手动更改行距
comments: true, // 添加注释
customBorders: [], // 添加边框
columnSorting: true, // 排序
stretchH: 'all', // 根据宽度横向扩展last:只扩展最后一列none默认不扩展
afterChange: function (changes, source) {
if (changes !== null) {
document.getElementById('upload-button').disabled = false
}
}
}
return dt
}
},
methods: {
getDataList () {
const data = this.$refs.HTable.$data.hotInstance.getData()
data.unshift(this.dataTitle)
return data
}
}
}
</script>
<style>
@import '~handsontable/dist/handsontable.full.css';
</style>

View File

@ -0,0 +1,113 @@
<template>
<div>
<a-form :form="form" style="max-width: 500px; margin: 30px auto 0;">
<a-row>
<a-col :span="18">
<a-form-item label="模板类型" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-select
placeholder="--请选择模板类型--"
v-decorator="['ciTypes', { rules: [{required: true, message: '模板类型必须选择'}] }]"
@change="selectCiType"
>
<a-select-option v-for="ciType in ciTypeList" :key="ciType.name" :value="ciType.id">{{ ciType.alias }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item>
<a-button
style="margin-left: 20px"
:disabled="downLoadButtonDis"
@click="downLoadExcel"
>下载模板</a-button>
</a-form-item>
</a-col>
</a-row>
</a-form>
<a-divider />
</div>
</template>
<script>
import { getCITypes } from '@/api/cmdb/CIType'
import { getCITypeAttributesById } from '@/api/cmdb/CITypeAttr'
import { writeExcel } from '@/api/cmdb/batch'
export default {
name: 'CiTypeChoice',
data () {
return {
labelCol: { lg: { span: 5 }, sm: { span: 5 } },
wrapperCol: { lg: { span: 19 }, sm: { span: 19 } },
form: this.$form.createForm(this),
ciTypeList: [],
ciTypeName: '',
downLoadButtonDis: true,
selectNum: 0,
selectCiTypeAttrList: []
}
},
created: function () {
getCITypes().then(res => {
this.ciTypeList = res.ci_types
})
},
methods: {
selectCiType (el) {
// 当选择好模板类型时的回调函数
this.downLoadButtonDis = false
this.selectNum = el
getCITypeAttributesById(el).then(res => {
this.$emit('getCiTypeAttr', res)
this.selectCiTypeAttrList = res
})
this.ciTypeList.forEach(item => {
if (this.selectNum === item.id) {
this.ciTypeName = item.alias || item.name
}
})
},
downLoadExcel () {
const columns = []
this.selectCiTypeAttrList.attributes.forEach(item => {
columns.push(item.alias)
})
const excel = writeExcel(columns, this.ciTypeName)
const tempLink = document.createElement('a')
tempLink.download = this.ciTypeName + '.xls'
tempLink.style.display = 'none'
const blob = new Blob([excel])
tempLink.href = URL.createObjectURL(blob)
document.body.appendChild(tempLink)
tempLink.click()
document.body.removeChild(tempLink)
}
}
}
</script>
<style lang="less" scoped>
.step-form-style-desc {
padding: 0 56px;
color: rgba(0, 0, 0, 0.45);
h3 {
margin: 0 0 12px;
color: rgba(0, 0, 0, 0.45);
font-size: 16px;
line-height: 32px;
}
h4 {
margin: 0 0 4px;
color: rgba(0, 0, 0, 0.45);
font-size: 14px;
line-height: 22px;
}
p {
margin-top: 0;
margin-bottom: 12px;
line-height: 22px;
}
}
</style>

View File

@ -0,0 +1,61 @@
<template>
<div>
<a-form :form="form" style="max-width: 500px; margin: 40px auto 0;">
<a-upload-dragger ref="upload" :multiple="true" :customRequest="customRequest" accept=".xls">
<p class="ant-upload-drag-icon">
<a-icon type="inbox" />
</p>
<p class="ant-upload-text">点击或拖拽文件至此上传</p>
<p class="ant-upload-hint">支持文件类型xls</p>
</a-upload-dragger>
</a-form>
<a-divider>or</a-divider>
</div>
</template>
<script>
import { processFile } from '@/api/cmdb/batch'
export default {
name: 'Step2',
data () {
return {
labelCol: { lg: { span: 5 }, sm: { span: 5 } },
wrapperCol: { lg: { span: 19 }, sm: { span: 19 } },
form: this.$form.createForm(this),
loading: false,
timer: 0,
ciItemNum: 0,
dataList: []
}
},
methods: {
customRequest (data) {
processFile(data.file).then(res => {
this.ciItemNum = res.length - 1
document.getElementById('upload-button').disabled = false
this.dataList = res
})
},
handleChange (info) {
document.getElementById('load-button').disabled = false
console.log(info)
},
clear () {
console.log(this.$refs.upload.$children[0].onSuccess('', ''))
}
}
}
</script>
<style lang="less" scoped>
.stepFormText {
margin-bottom: 24px;
.ant-form-item-label,
.ant-form-item-control {
line-height: 22px;
}
}
</style>

View File

@ -0,0 +1,95 @@
<template>
<div>
<h4>&nbsp;<span style="color: blue">{{ total }}</span> ,已完成 <span style="color: lightgreen">{{ complete }}</span>
,失败 <span style="color: red">{{ errorNum }} </span></h4>
<a-progress :percent="mPercent"/>
<div class="my-box">
<span>错误信息</span>
<ol>
<li :key="item" v-for="item in errorItems">{{ item }}</li>
</ol>
</div>
</div>
</template>
<script>
import { uploadData } from '@/api/cmdb/batch'
export default {
name: 'Result',
props: {
upLoadData: {
required: true,
type: Array
},
ciType: {
required: true,
type: Number
},
uniqueField: {
required: true,
type: String
}
},
data: function () {
return {
total: 0,
complete: 0,
errorNum: 0,
errorItems: []
}
},
mounted: function () {
document.getElementById('upload-button').disabled = true
this.upload2Server()
},
computed: {
mpercent () {
return Math.round(this.complete / this.total * 10000) / 100
},
progressStatus () {
if (this.complete === this.total) {
return null
} else {
return 'active'
}
}
},
methods: {
upload2Server () {
this.total = this.$props.upLoadData.length - 1
for (let i = 0; i < this.total; i++) {
const item = {}
let itemUniqueName = 'unknown'
for (let j = 0; j < this.$props.upLoadData[0].length; j++) {
item[this.$props.upLoadData[0][j]] = this.$props.upLoadData[i + 1][j]
if (this.$props.upLoadData[0][j] === this.$props.uniqueField) {
itemUniqueName = this.$props.upLoadData[i + 1][j] || 'unknown'
}
}
uploadData(this.$props.ciType, item).then(res => {
console.log(res)
}).catch(err => {
this.errorNum += 1
console.log(err)
this.errorItems.push(itemUniqueName + ': ' + (((err.response || {}).data || {}).message || '请求出现错误,请稍后再试'))
})
this.complete += 1
}
}
}
}
</script>
<style scoped>
.my-box {
margin-top: 20px;
color: red;
border: 1px red dashed;
padding: 8px;
border-radius:5px;
height: 429px;
overflow-y: auto;
}
</style>