mirror of https://github.com/veops/cmdb.git
feat(cmdb-ui):ci type import&export,pref(cmdb-ui):download ci xlsx name, pref(cmdb-ui):ci detail history merge row method (#331)
* pref(cmdb-ui):download ci xlsx name * pref(cmdb-ui):ci detail history merge row method * feat(cmdb-ui):ci type import&export
This commit is contained in:
parent
41ad610c00
commit
5fe6676d83
|
@ -111,12 +111,14 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations('cmdbStore', ['SET_IS_TABLE_LOADING']),
|
...mapMutations('cmdbStore', ['SET_IS_TABLE_LOADING']),
|
||||||
open({ preferenceAttrList }) {
|
open({ preferenceAttrList, ciTypeName = undefined }) {
|
||||||
this.preferenceAttrList = preferenceAttrList
|
this.preferenceAttrList = preferenceAttrList
|
||||||
this.visible = true
|
this.visible = true
|
||||||
this.$nextTick((res) => {
|
this.$nextTick((res) => {
|
||||||
this.form.setFieldsValue({
|
this.form.setFieldsValue({
|
||||||
filename: `cmdb-${moment().format('YYYYMMDDHHmmss')}`,
|
filename: ciTypeName
|
||||||
|
? `cmdb-${ciTypeName}-${moment().format('YYYYMMDDHHmmss')}`
|
||||||
|
: `cmdb-${moment().format('YYYYMMDDHHmmss')}`,
|
||||||
})
|
})
|
||||||
if (this.treeType === 'tree') {
|
if (this.treeType === 'tree') {
|
||||||
const _check = ['ci_type_alias']
|
const _check = ['ci_type_alias']
|
||||||
|
|
|
@ -106,7 +106,6 @@ export default {
|
||||||
this.uploadData = _uploadData.slice(1)
|
this.uploadData = _uploadData.slice(1)
|
||||||
this.hasError = false
|
this.hasError = false
|
||||||
this.isUploading = false
|
this.isUploading = false
|
||||||
this.$refs.uploadResult.visible = false
|
|
||||||
},
|
},
|
||||||
handleUpload() {
|
handleUpload() {
|
||||||
if (!this.ciType) {
|
if (!this.ciType) {
|
||||||
|
|
|
@ -576,7 +576,10 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
async openBatchDownload() {
|
async openBatchDownload() {
|
||||||
this.$refs.batchDownload.open({ preferenceAttrList: this.preferenceAttrList })
|
this.$refs.batchDownload.open({
|
||||||
|
preferenceAttrList: this.preferenceAttrList,
|
||||||
|
ciTypeName: this.$route.meta.title || this.$route.meta.name,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
batchDownload({ filename, type, checkedKeys }) {
|
batchDownload({ filename, type, checkedKeys }) {
|
||||||
const jsonAttrList = []
|
const jsonAttrList = []
|
||||||
|
|
|
@ -276,15 +276,16 @@ export default {
|
||||||
},
|
},
|
||||||
mergeRowMethod({ row, _rowIndex, column, visibleData }) {
|
mergeRowMethod({ row, _rowIndex, column, visibleData }) {
|
||||||
const fields = ['created_at', 'username']
|
const fields = ['created_at', 'username']
|
||||||
const cellValue = row[column.property]
|
const cellValue1 = row['created_at']
|
||||||
if (cellValue && fields.includes(column.property)) {
|
const cellValue2 = row['username']
|
||||||
|
if (cellValue1 && cellValue2 && fields.includes(column.property)) {
|
||||||
const prevRow = visibleData[_rowIndex - 1]
|
const prevRow = visibleData[_rowIndex - 1]
|
||||||
let nextRow = visibleData[_rowIndex + 1]
|
let nextRow = visibleData[_rowIndex + 1]
|
||||||
if (prevRow && prevRow[column.property] === cellValue) {
|
if (prevRow && prevRow['created_at'] === cellValue1 && prevRow['username'] === cellValue2) {
|
||||||
return { rowspan: 0, colspan: 0 }
|
return { rowspan: 0, colspan: 0 }
|
||||||
} else {
|
} else {
|
||||||
let countRowspan = 1
|
let countRowspan = 1
|
||||||
while (nextRow && nextRow[column.property] === cellValue) {
|
while (nextRow && nextRow['created_at'] === cellValue1 && nextRow['username'] === cellValue2) {
|
||||||
nextRow = visibleData[++countRowspan + _rowIndex]
|
nextRow = visibleData[++countRowspan + _rowIndex]
|
||||||
}
|
}
|
||||||
if (countRowspan > 1) {
|
if (countRowspan > 1) {
|
||||||
|
|
|
@ -136,8 +136,8 @@ export default {
|
||||||
async getCITypeDiscovery(currentTab) {
|
async getCITypeDiscovery(currentTab) {
|
||||||
await getCITypeDiscovery(this.CITypeId).then((res) => {
|
await getCITypeDiscovery(this.CITypeId).then((res) => {
|
||||||
this.adCITypeList = res.filter((item) => item.adr_id)
|
this.adCITypeList = res.filter((item) => item.adr_id)
|
||||||
if (res && res.length && !this.currentTab) {
|
if (this.adCITypeList && this.adCITypeList.length && !this.currentTab) {
|
||||||
this.currentTab = res[0].id
|
this.currentTab = this.adCITypeList[0].id
|
||||||
}
|
}
|
||||||
if (currentTab) {
|
if (currentTab) {
|
||||||
this.currentTab = currentTab
|
this.currentTab = currentTab
|
||||||
|
|
|
@ -40,20 +40,18 @@
|
||||||
<a-menu-item key="0">
|
<a-menu-item key="0">
|
||||||
<a-upload
|
<a-upload
|
||||||
name="file"
|
name="file"
|
||||||
accept="json"
|
accept=".json"
|
||||||
:showUploadList="false"
|
:showUploadList="false"
|
||||||
style="display: inline-block"
|
style="display: inline-block"
|
||||||
action="/api/v0.1/ci_types/template/import/file "
|
action="/api/v0.1/ci_types/template/import/file"
|
||||||
>
|
@change="changeUploadFile"
|
||||||
<a-space
|
|
||||||
><a><a-icon type="upload"/></a><a>导入</a></a-space
|
|
||||||
>
|
>
|
||||||
|
<a><a-icon type="upload"/></a><a> 导入</a>
|
||||||
</a-upload>
|
</a-upload>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item key="1">
|
<a-menu-item key="1">
|
||||||
<a-space>
|
<a-space>
|
||||||
<a><a-icon type="download"/></a>
|
<a href="/api/v0.1/ci_types/template/export/file"><a-icon type="download" /> 导出</a>
|
||||||
<a href="/api/v0.1/ci_types/template/export/file">导出</a>
|
|
||||||
</a-space>
|
</a-space>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
</a-menu>
|
</a-menu>
|
||||||
|
@ -134,6 +132,12 @@
|
||||||
<a-space class="ci-types-left-detail-action">
|
<a-space class="ci-types-left-detail-action">
|
||||||
<a><a-icon type="user-add" @click="(e) => handlePerm(e, ci)"/></a>
|
<a><a-icon type="user-add" @click="(e) => handlePerm(e, ci)"/></a>
|
||||||
<a><a-icon type="edit" @click="(e) => handleEdit(e, ci)"/></a>
|
<a><a-icon type="edit" @click="(e) => handleEdit(e, ci)"/></a>
|
||||||
|
<a
|
||||||
|
v-if="permissions.includes('admin') || permissions.includes('cmdb_admin')"
|
||||||
|
@click="(e) => handleDownloadCiType(e, ci)"
|
||||||
|
><a-icon
|
||||||
|
type="download"
|
||||||
|
/></a>
|
||||||
<a style="color: red" @click="(e) => handleDelete(e, ci)"><a-icon type="delete"/></a>
|
<a style="color: red" @click="(e) => handleDelete(e, ci)"><a-icon type="delete"/></a>
|
||||||
</a-space>
|
</a-space>
|
||||||
</div>
|
</div>
|
||||||
|
@ -309,6 +313,7 @@ export default {
|
||||||
OpsMoveIcon,
|
OpsMoveIcon,
|
||||||
AttributeStore,
|
AttributeStore,
|
||||||
},
|
},
|
||||||
|
inject: ['reload'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
emptyImage,
|
emptyImage,
|
||||||
|
@ -716,6 +721,21 @@ export default {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
handleDownloadCiType(e, ci) {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
const x = new XMLHttpRequest()
|
||||||
|
x.open('GET', `/api/v0.1/ci_types/${ci.id}/template/export`, true)
|
||||||
|
x.responseType = 'blob'
|
||||||
|
x.onload = function(e) {
|
||||||
|
const url = window.URL.createObjectURL(x.response)
|
||||||
|
const a = document.createElement('a')
|
||||||
|
a.href = url
|
||||||
|
a.download = `${ci.alias || ci.name}.json`
|
||||||
|
a.click()
|
||||||
|
}
|
||||||
|
x.send()
|
||||||
|
},
|
||||||
resetRoute() {
|
resetRoute() {
|
||||||
resetRouter()
|
resetRouter()
|
||||||
const roles = store.getters.roles
|
const roles = store.getters.roles
|
||||||
|
@ -780,6 +800,19 @@ export default {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
changeUploadFile({ file, fileList, event }) {
|
||||||
|
const key = 'upload'
|
||||||
|
if (file.status === 'uploading') {
|
||||||
|
this.$message.loading({ content: '正在导入中', key, duration: 0 })
|
||||||
|
}
|
||||||
|
if (file.status === 'done') {
|
||||||
|
this.$message.success({ content: '导入成功', key, duration: 2 })
|
||||||
|
this.reload()
|
||||||
|
}
|
||||||
|
if (file.status === 'error') {
|
||||||
|
this.$message.error({ content: '导入失败,请稍后重试', key, duration: 2 })
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -322,6 +322,7 @@
|
||||||
v-else-if="relationViews.name2id && !relationViews.name2id.length"
|
v-else-if="relationViews.name2id && !relationViews.name2id.length"
|
||||||
></a-alert>
|
></a-alert>
|
||||||
<AddTableModal ref="addTableModal" @reload="reload" />
|
<AddTableModal ref="addTableModal" @reload="reload" />
|
||||||
|
<!-- <GrantDrawer ref="grantDrawer" resourceTypeName="RelationView" app_id="cmdb" /> -->
|
||||||
<CMDBGrant ref="cmdbGrant" resourceType="RelationView" app_id="cmdb" />
|
<CMDBGrant ref="cmdbGrant" resourceType="RelationView" app_id="cmdb" />
|
||||||
|
|
||||||
<ci-detail ref="detail" :typeId="Number(currentTypeId[0])" />
|
<ci-detail ref="detail" :typeId="Number(currentTypeId[0])" />
|
||||||
|
@ -378,6 +379,7 @@ export default {
|
||||||
SearchForm,
|
SearchForm,
|
||||||
AddTableModal,
|
AddTableModal,
|
||||||
ContextMenu,
|
ContextMenu,
|
||||||
|
// GrantDrawer,
|
||||||
CMDBGrant,
|
CMDBGrant,
|
||||||
SplitPane,
|
SplitPane,
|
||||||
ElTree: Tree,
|
ElTree: Tree,
|
||||||
|
@ -651,6 +653,9 @@ export default {
|
||||||
} else {
|
} else {
|
||||||
q = `q=_type:${this.currentTypeId[0]},` + q
|
q = `q=_type:${this.currentTypeId[0]},` + q
|
||||||
}
|
}
|
||||||
|
if (Object.values(this.level2constraint).includes('2')) {
|
||||||
|
q = q + `&&has_m2m=1`
|
||||||
|
}
|
||||||
if (this.currentTypeId[0]) {
|
if (this.currentTypeId[0]) {
|
||||||
const res = await searchCIRelation(q)
|
const res = await searchCIRelation(q)
|
||||||
|
|
||||||
|
@ -689,6 +694,7 @@ export default {
|
||||||
root_ids: key.split('%')[0],
|
root_ids: key.split('%')[0],
|
||||||
level: this.treeKeys.length - index,
|
level: this.treeKeys.length - index,
|
||||||
type_ids: this.showTypes.map((type) => type.id).join(','),
|
type_ids: this.showTypes.map((type) => type.id).join(','),
|
||||||
|
has_m2m: Number(Object.values(this.level2constraint).includes('2')),
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
let result
|
let result
|
||||||
const getTreeItem = (data, id) => {
|
const getTreeItem = (data, id) => {
|
||||||
|
@ -742,7 +748,10 @@ export default {
|
||||||
_showTypes = JSON.parse(JSON.stringify(this.origShowTypes))
|
_showTypes = JSON.parse(JSON.stringify(this.origShowTypes))
|
||||||
}
|
}
|
||||||
const promises = _showTypeIds.map((typeId) => {
|
const promises = _showTypeIds.map((typeId) => {
|
||||||
const _q = (`q=_type:${typeId},` + q).replace(/count=\d*/, 'count=1')
|
let _q = (`q=_type:${typeId},` + q).replace(/count=\d*/, 'count=1')
|
||||||
|
if (Object.values(this.level2constraint).includes('2')) {
|
||||||
|
_q = _q + `&&has_m2m=1`
|
||||||
|
}
|
||||||
console.log(_q)
|
console.log(_q)
|
||||||
if (this.treeKeys.length === 0) {
|
if (this.treeKeys.length === 0) {
|
||||||
return searchCI2(_q).then((res) => {
|
return searchCI2(_q).then((res) => {
|
||||||
|
@ -798,6 +807,7 @@ export default {
|
||||||
root_ids: ciIds.join(','),
|
root_ids: ciIds.join(','),
|
||||||
level: level,
|
level: level,
|
||||||
type_ids: this.showTypes.map((type) => type.id).join(','),
|
type_ids: this.showTypes.map((type) => type.id).join(','),
|
||||||
|
has_m2m: Number(Object.values(this.level2constraint).includes('2')),
|
||||||
}).then((num) => {
|
}).then((num) => {
|
||||||
facet.forEach((item, idx) => {
|
facet.forEach((item, idx) => {
|
||||||
item[1] += num[ciIds[idx] + '']
|
item[1] += num[ciIds[idx] + '']
|
||||||
|
@ -827,6 +837,9 @@ export default {
|
||||||
.map((item) => item.split('%')[0])
|
.map((item) => item.split('%')[0])
|
||||||
.join(',')}`
|
.join(',')}`
|
||||||
}
|
}
|
||||||
|
if (Object.values(this.level2constraint).includes('2')) {
|
||||||
|
q = q + `&&has_m2m=1`
|
||||||
|
}
|
||||||
searchCIRelation(q).then(async (res) => {
|
searchCIRelation(q).then(async (res) => {
|
||||||
const facet = []
|
const facet = []
|
||||||
const ciIds = []
|
const ciIds = []
|
||||||
|
@ -849,6 +862,7 @@ export default {
|
||||||
root_ids: ciIds.join(','),
|
root_ids: ciIds.join(','),
|
||||||
level: _level - 1,
|
level: _level - 1,
|
||||||
type_ids: this.showTypes.map((type) => type.id).join(','),
|
type_ids: this.showTypes.map((type) => type.id).join(','),
|
||||||
|
has_m2m: Number(Object.values(this.level2constraint).includes('2')),
|
||||||
}).then((num) => {
|
}).then((num) => {
|
||||||
facet.forEach((item, idx) => {
|
facet.forEach((item, idx) => {
|
||||||
item[1] += num[ciIds[idx] + '']
|
item[1] += num[ciIds[idx] + '']
|
||||||
|
@ -1322,7 +1336,10 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
async openBatchDownload() {
|
async openBatchDownload() {
|
||||||
this.$refs.batchDownload.open({ preferenceAttrList: this.preferenceAttrList })
|
this.$refs.batchDownload.open({
|
||||||
|
preferenceAttrList: this.preferenceAttrList,
|
||||||
|
ciTypeName: this.$route.meta.name,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
batchDownload({ filename, type, checkedKeys }) {
|
batchDownload({ filename, type, checkedKeys }) {
|
||||||
const jsonAttrList = []
|
const jsonAttrList = []
|
||||||
|
|
|
@ -130,12 +130,13 @@ export default {
|
||||||
exp = expression.match(regQ) ? expression.match(regQ)[0] : null
|
exp = expression.match(regQ) ? expression.match(regQ)[0] : null
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await searchCI({
|
await searchCI({
|
||||||
q: `_type:${this.addTypeId}${exp ? `,${exp}` : ''}${fuzzySearch ? `,*${fuzzySearch}*` : ''}`,
|
q: `_type:${this.addTypeId}${exp ? `,${exp}` : ''}${fuzzySearch ? `,*${fuzzySearch}*` : ''}`,
|
||||||
count: 50,
|
count: 50,
|
||||||
page: this.currentPage,
|
page: this.currentPage,
|
||||||
sort,
|
sort,
|
||||||
})
|
})
|
||||||
|
.then((res) => {
|
||||||
this.tableData = res.result
|
this.tableData = res.result
|
||||||
this.totalNumber = res.numfound
|
this.totalNumber = res.numfound
|
||||||
this.columns = this.getColumns(res.result, this.preferenceAttrList)
|
this.columns = this.getColumns(res.result, this.preferenceAttrList)
|
||||||
|
@ -146,6 +147,10 @@ export default {
|
||||||
}
|
}
|
||||||
this.loading = false
|
this.loading = false
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
},
|
},
|
||||||
getColumns(data, attrList) {
|
getColumns(data, attrList) {
|
||||||
const modalDom = document.getElementById('add-table-modal')
|
const modalDom = document.getElementById('add-table-modal')
|
||||||
|
|
|
@ -1054,7 +1054,10 @@ export default {
|
||||||
this.$refs.jsonEditor.open(column, row)
|
this.$refs.jsonEditor.open(column, row)
|
||||||
},
|
},
|
||||||
async openBatchDownload() {
|
async openBatchDownload() {
|
||||||
this.$refs.batchDownload.open({ preferenceAttrList: this.currentAttrList })
|
this.$refs.batchDownload.open({
|
||||||
|
preferenceAttrList: this.currentAttrList,
|
||||||
|
ciTypeName: this.$route.meta.title || this.$route.meta.name,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
batchDownload({ filename, type, checkedKeys }) {
|
batchDownload({ filename, type, checkedKeys }) {
|
||||||
console.log(filename, type)
|
console.log(filename, type)
|
||||||
|
|
Loading…
Reference in New Issue