diff --git a/cmdb-ui/src/assets/logo_VECMDB.png b/cmdb-ui/src/assets/logo_VECMDB.png
index 0323b3a..fc733d1 100644
Binary files a/cmdb-ui/src/assets/logo_VECMDB.png and b/cmdb-ui/src/assets/logo_VECMDB.png differ
diff --git a/cmdb-ui/src/components/TwoColumnLayout/TwoColumnLayout.vue b/cmdb-ui/src/components/TwoColumnLayout/TwoColumnLayout.vue
index 8dd4f9b..44d888d 100644
--- a/cmdb-ui/src/components/TwoColumnLayout/TwoColumnLayout.vue
+++ b/cmdb-ui/src/components/TwoColumnLayout/TwoColumnLayout.vue
@@ -59,7 +59,6 @@ export default {
width: 100%;
.two-column-layout-sidebar {
height: 100%;
- border-radius: 15px;
overflow-y: auto;
}
.two-column-layout-main {
diff --git a/cmdb-ui/src/modules/cmdb/api/CITypeRelation.js b/cmdb-ui/src/modules/cmdb/api/CITypeRelation.js
index c812506..70c115e 100644
--- a/cmdb-ui/src/modules/cmdb/api/CITypeRelation.js
+++ b/cmdb-ui/src/modules/cmdb/api/CITypeRelation.js
@@ -30,11 +30,11 @@ export function getRelationTypes(CITypeID, parameter) {
})
}
-export function createRelation(parentId, childrenId, relationTypeId, constraint) {
+export function createRelation(parentId, childrenId, data) {
return axios({
url: `/v0.1/ci_type_relations/${parentId}/${childrenId}`,
method: 'post',
- data: { relation_type_id: relationTypeId, constraint }
+ data
})
}
@@ -42,7 +42,6 @@ export function deleteRelation(parentId, childrenId) {
return axios({
url: `/v0.1/ci_type_relations/${parentId}/${childrenId}`,
method: 'delete'
-
})
}
diff --git a/cmdb-ui/src/modules/cmdb/lang/en.js b/cmdb-ui/src/modules/cmdb/lang/en.js
index ad39212..2f9664f 100644
--- a/cmdb-ui/src/modules/cmdb/lang/en.js
+++ b/cmdb-ui/src/modules/cmdb/lang/en.js
@@ -187,7 +187,14 @@ const cmdb_en = {
downloadType: 'Download CIType',
deleteCIType: 'Delete CIType',
otherGroupTips: 'Non sortable within the other group',
- filterTips: 'click to show {name}'
+ filterTips: 'click to show {name}',
+ attributeAssociation: 'Attribute Association',
+ attributeAssociationTip1: 'Automatically establish relationships through the attributes except password, json and multiple of two models',
+ attributeAssociationTip2: 'Double click to edit',
+ attributeAssociationTip3: 'Two Attributes must be selected',
+ attributeAssociationTip4: 'Please select a attribute from Source CIType',
+ attributeAssociationTip5: 'Please select a attribute from Target CIType',
+
},
components: {
unselectAttributes: 'Unselected',
diff --git a/cmdb-ui/src/modules/cmdb/lang/zh.js b/cmdb-ui/src/modules/cmdb/lang/zh.js
index 016346a..e79b1dc 100644
--- a/cmdb-ui/src/modules/cmdb/lang/zh.js
+++ b/cmdb-ui/src/modules/cmdb/lang/zh.js
@@ -129,7 +129,7 @@ const cmdb_zh = {
addRelation: '新增关系',
sourceCIType: '源模型',
sourceCITypeTips: '请选择源模型',
- dstCIType: '目标模型名',
+ dstCIType: '目标模型',
dstCITypeTips: '请选择目标模型',
relationType: '关联类型',
relationTypeTips: '请选择关联类型',
@@ -187,7 +187,13 @@ const cmdb_zh = {
downloadType: '下载模型',
deleteCIType: '删除模型',
otherGroupTips: '其他分组属性不可排序',
- filterTips: '点击可仅查看{name}属性'
+ filterTips: '点击可仅查看{name}属性',
+ attributeAssociation: '属性关联',
+ attributeAssociationTip1: '通过2个模型的属性值(除密码、json、多值)来自动建立关系',
+ attributeAssociationTip2: '双击可编辑',
+ attributeAssociationTip3: '属性关联必须选择两个属性',
+ attributeAssociationTip4: '请选择原模型属性',
+ attributeAssociationTip5: '请选择目标模型属性',
},
components: {
unselectAttributes: '未选属性',
diff --git a/cmdb-ui/src/modules/cmdb/views/ci_types/ciTypedetail.vue b/cmdb-ui/src/modules/cmdb/views/ci_types/ciTypedetail.vue
index 3f6012e..2b99166 100644
--- a/cmdb-ui/src/modules/cmdb/views/ci_types/ciTypedetail.vue
+++ b/cmdb-ui/src/modules/cmdb/views/ci_types/ciTypedetail.vue
@@ -4,7 +4,7 @@
-
+
diff --git a/cmdb-ui/src/modules/cmdb/views/ci_types/relationTable.vue b/cmdb-ui/src/modules/cmdb/views/ci_types/relationTable.vue
index 5bbd1df..679d7c4 100644
--- a/cmdb-ui/src/modules/cmdb/views/ci_types/relationTable.vue
+++ b/cmdb-ui/src/modules/cmdb/views/ci_types/relationTable.vue
@@ -15,11 +15,16 @@
:data="tableData"
size="small"
show-overflow
+ show-header-overflow
highlight-hover-row
keep-source
- :max-height="windowHeight - 180"
+ :height="windowHeight - 190"
class="ops-stripe-table"
:row-class-name="rowClass"
+ :edit-config="{ trigger: 'dblclick', mode: 'cell', showIcon: false }"
+ resizable
+ @edit-closed="handleEditClose"
+ @edit-actived="handleEditActived"
>
@@ -40,6 +45,59 @@
{{ constraintMap[row.constraint] }}
+
+
+
+
+
+
+ {{ $t('cmdb.ciType.attributeAssociation') }}
+ {{
+ $t('cmdb.ciType.attributeAssociationTip2')
+ }}
+
+
+
+ {{ getAttrNameById(row.isParent ? row.attributes : attributes, row.parent_attr_id) }}=>
+ {{ getAttrNameById(row.isParent ? attributes : row.attributes, row.child_attr_id) }}
+
+
+
+
+
+ {{ attr.alias || attr.name }}
+
+
+ =>
+
+
+ {{ attr.alias || attr.name }}
+
+
+
+
+
@@ -63,12 +121,13 @@
:visible="visible"
@cancel="onClose"
@ok="handleSubmit"
- width="500px"
+ width="700px"
>
{{ CIType.alias || CIType.name }}
@@ -95,6 +156,7 @@
{{ $t('cmdb.ciType.many2Many') }}
+
+
+
+
+
+
+ {{ attr.alias || attr.name }}
+
+
+
+
+
+ =>
+
+
+
+
+
+ {{ attr.alias || attr.name }}
+
+
+
+
+
+
@@ -133,6 +228,8 @@ import {
getRelationTypes,
} from '@/modules/cmdb/api/CITypeRelation'
import { getCITypes } from '@/modules/cmdb/api/CIType'
+import { getCITypeAttributesById } from '@/modules/cmdb/api/CITypeAttr'
+
import CMDBGrant from '../../components/cmdbGrant'
export default {
@@ -163,6 +260,10 @@ export default {
relationTypes: [],
tableData: [],
parentTableData: [],
+ attributes: [],
+ parent_attr_id: undefined,
+ child_attr_id: undefined,
+ modalChildAttributes: [],
}
},
computed: {
@@ -181,14 +282,20 @@ export default {
},
},
async mounted() {
+ getCITypeAttributesById(this.CITypeId).then((res) => {
+ this.attributes = res?.attributes ?? []
+ })
this.getCITypes()
this.getRelationTypes()
- if (!this.isInGrantComp) {
- await this.getCITypeParent()
- }
this.getData()
},
methods: {
+ async getData() {
+ if (!this.isInGrantComp) {
+ await this.getCITypeParent()
+ }
+ this.getCITypeChildren()
+ },
async getCITypeParent() {
await getCITypeParent(this.CITypeId).then((res) => {
this.parentTableData = res.parents.map((item) => {
@@ -201,7 +308,7 @@ export default {
})
})
},
- getData() {
+ getCITypeChildren() {
getCITypeChildren(this.CITypeId).then((res) => {
const data = res.children.map((obj) => {
return {
@@ -230,12 +337,9 @@ export default {
handleDelete(record) {
deleteRelation(record.source_ci_type_id, record.id).then((res) => {
this.$message.success(this.$t('deleteSuccess'))
- this.handleOk()
+ this.getData()
})
},
- handleOk() {
- this.getData()
- },
handleCreate() {
this.drawerTitle = this.$t('cmdb.ciType.addRelation')
@@ -258,14 +362,29 @@ export default {
if (!err) {
// eslint-disable-next-line no-console
console.log('Received values of form: ', values)
+ const {
+ source_ci_type_id,
+ ci_type_id,
+ relation_type_id,
+ constraint,
+ parent_attr_id = undefined,
+ child_attr_id = undefined,
+ } = values
- createRelation(values.source_ci_type_id, values.ci_type_id, values.relation_type_id, values.constraint).then(
- (res) => {
- this.$message.success(this.$t('addSuccess'))
- this.onClose()
- this.handleOk()
- }
- )
+ if ((!parent_attr_id && child_attr_id) || (parent_attr_id && !child_attr_id)) {
+ this.$message.warning(this.$t('cmdb.ciType.attributeAssociationTip3'))
+ return
+ }
+ createRelation(source_ci_type_id, ci_type_id, {
+ relation_type_id,
+ constraint,
+ parent_attr_id,
+ child_attr_id,
+ }).then((res) => {
+ this.$message.success(this.$t('addSuccess'))
+ this.onClose()
+ this.getData()
+ })
}
})
},
@@ -283,6 +402,42 @@ export default {
if (row.isDivider) return 'relation-table-divider'
if (row.isParent) return 'relation-table-parent'
},
+ handleEditActived({ row }) {
+ this.parent_attr_id = row?.parent_attr_id ?? undefined
+ this.child_attr_id = row?.child_attr_id ?? undefined
+ },
+ async handleEditClose({ row }) {
+ const { source_ci_type_id: parentId, id: childrenId, constraint, relation_type } = row
+ const { parent_attr_id, child_attr_id } = this
+ const _find = this.relationTypes.find((item) => item.name === relation_type)
+ const relation_type_id = _find?.id
+ if ((!parent_attr_id && child_attr_id) || (parent_attr_id && !child_attr_id)) {
+ this.$message.warning(this.$t('cmdb.ciType.attributeAssociationTip3'))
+ return
+ }
+ await createRelation(row.isParent ? childrenId : parentId, row.isParent ? parentId : childrenId, {
+ relation_type_id,
+ constraint,
+ parent_attr_id,
+ child_attr_id,
+ }).finally(() => {
+ this.getData()
+ })
+ },
+ getAttrNameById(attributes, id) {
+ const _find = attributes.find((attr) => attr.id === id)
+ return _find?.alias ?? _find?.name ?? id
+ },
+ changeChild(value) {
+ this.form.setFieldsValue({ child_attr_id: undefined })
+ getCITypeAttributesById(value).then((res) => {
+ this.modalChildAttributes = res?.attributes ?? []
+ })
+ },
+ filterAttributes(attributes) {
+ // filter password/json/is_list
+ return attributes.filter((attr) => !attr.is_password && !attr.is_list && attr.value_type !== '6')
+ },
},
}
diff --git a/cmdb-ui/src/modules/cmdb/views/model_relation/index.vue b/cmdb-ui/src/modules/cmdb/views/model_relation/index.vue
index d4bd8b1..4ace33e 100644
--- a/cmdb-ui/src/modules/cmdb/views/model_relation/index.vue
+++ b/cmdb-ui/src/modules/cmdb/views/model_relation/index.vue
@@ -10,7 +10,7 @@
:visible="visible"
@cancel="onClose"
@ok="handleSubmit"
- width="500px"
+ width="700px"
>
@@ -69,6 +69,39 @@
{{ $t('cmdb.ciType.many2Many') }}
+
+
+
+
+
+
+ {{ attr.alias || attr.name }}
+
+
+
+
+
+ =>
+
+
+
+
+
+ {{ attr.alias || attr.name }}
+
+
+
+
+
+
@@ -80,6 +113,8 @@ import { searchResourceType } from '@/modules/acl/api/resource'
import { getCITypeGroupsConfig } from '@/modules/cmdb/api/ciTypeGroup'
import { getCITypes } from '@/modules/cmdb/api/CIType'
import { createRelation, deleteRelation, getCITypeChildren, getRelationTypes } from '@/modules/cmdb/api/CITypeRelation'
+import { getCITypeAttributesById } from '@/modules/cmdb/api/CITypeAttr'
+
export default {
name: 'Index',
components: {
@@ -101,6 +136,9 @@ export default {
sourceCITypeId: undefined,
targetCITypeId: undefined,
+
+ modalParentAttributes: [],
+ modalChildAttributes: [],
}
},
computed: {
@@ -206,13 +244,29 @@ export default {
e.preventDefault()
this.form.validateFields((err, values) => {
if (!err) {
- createRelation(values.source_ci_type_id, values.ci_type_id, values.relation_type_id, values.constraint).then(
- (res) => {
- this.$message.success(this.$t('addSuccess'))
- this.onClose()
- this.handleOk()
- }
- )
+ const {
+ source_ci_type_id,
+ ci_type_id,
+ relation_type_id,
+ constraint,
+ parent_attr_id = undefined,
+ child_attr_id = undefined,
+ } = values
+
+ if ((!parent_attr_id && child_attr_id) || (parent_attr_id && !child_attr_id)) {
+ this.$message.warning(this.$t('cmdb.ciType.attributeAssociationTip3'))
+ return
+ }
+ createRelation(source_ci_type_id, ci_type_id, {
+ relation_type_id,
+ constraint,
+ parent_attr_id,
+ child_attr_id,
+ }).then((res) => {
+ this.$message.success(this.$t('addSuccess'))
+ this.onClose()
+ this.handleOk()
+ })
}
})
this.sourceCITypeId = undefined
@@ -230,13 +284,25 @@ export default {
},
handleSourceTypeChange(value) {
this.sourceCITypeId = value
+ this.form.setFieldsValue({ parent_attr_id: undefined })
+ getCITypeAttributesById(value).then((res) => {
+ this.modalParentAttributes = res?.attributes ?? []
+ })
},
handleTargetTypeChange(value) {
this.targetCITypeId = value
+ this.form.setFieldsValue({ child_attr_id: undefined })
+ getCITypeAttributesById(value).then((res) => {
+ this.modalChildAttributes = res?.attributes ?? []
+ })
},
filterOption(input, option) {
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
},
+ filterAttributes(attributes) {
+ // filter password/json/is_list
+ return attributes.filter((attr) => !attr.is_password && !attr.is_list && attr.value_type !== '6')
+ },
},
}
diff --git a/cmdb-ui/src/modules/cmdb/views/model_relation/modules/modelRelationTable.vue b/cmdb-ui/src/modules/cmdb/views/model_relation/modules/modelRelationTable.vue
index 69c40ae..0260f66 100644
--- a/cmdb-ui/src/modules/cmdb/views/model_relation/modules/modelRelationTable.vue
+++ b/cmdb-ui/src/modules/cmdb/views/model_relation/modules/modelRelationTable.vue
@@ -10,6 +10,9 @@
:height="`${windowHeight - 160}px`"
:data="tableData"
:sort-config="{ defaultSort: { field: 'created_at', order: 'desc' } }"
+ :edit-config="{ trigger: 'dblclick', mode: 'cell', showIcon: false }"
+ @edit-closed="handleEditClose"
+ @edit-actived="handleEditActived"
>
@@ -26,8 +29,59 @@
-
-
+
+
+ {{ handleConstraint(row.constraint) }}
+
+
+
+
+
+
+
+
+ {{ $t('cmdb.ciType.attributeAssociation') }}
+ {{
+ $t('cmdb.ciType.attributeAssociationTip2')
+ }}
+
+
+
+ {{ getAttrNameById(type2attributes[row.parent_id], row.parent_attr_id) }}=>
+ {{ getAttrNameById(type2attributes[row.child_id], row.child_attr_id) }}
+
+
+
+
+
+ {{ attr.alias || attr.name }}
+
+
+ =>
+
+
+ {{ attr.alias || attr.name }}
+
+
+
+
+
+
@@ -43,7 +97,7 @@
diff --git a/cmdb-ui/src/modules/cmdb/views/preference_relation/index.vue b/cmdb-ui/src/modules/cmdb/views/preference_relation/index.vue
index a6ecfe2..510aae5 100644
--- a/cmdb-ui/src/modules/cmdb/views/preference_relation/index.vue
+++ b/cmdb-ui/src/modules/cmdb/views/preference_relation/index.vue
@@ -154,7 +154,7 @@ export default {
this.getViewsData()
},
async getMainData() {
- const ciTypeRelations = await getCITypeRelations()
+ const { relations: ciTypeRelations } = await getCITypeRelations()
const nodes = []
const links = []
ciTypeRelations.forEach((item) => {
diff --git a/cmdb-ui/src/modules/cmdb/views/relation_views/modules/ContextMenu.vue b/cmdb-ui/src/modules/cmdb/views/relation_views/modules/ContextMenu.vue
index 1c9c8e2..6d2de06 100644
--- a/cmdb-ui/src/modules/cmdb/views/relation_views/modules/ContextMenu.vue
+++ b/cmdb-ui/src/modules/cmdb/views/relation_views/modules/ContextMenu.vue
@@ -7,7 +7,7 @@
@click="clickNode"
>
-
+
diff --git a/cmdb-ui/src/style/global.less b/cmdb-ui/src/style/global.less
index dba1ca9..0e9a600 100644
--- a/cmdb-ui/src/style/global.less
+++ b/cmdb-ui/src/style/global.less
@@ -910,6 +910,7 @@ body {
.vue-treeselect__multi-value,
.vue-treeselect__multi-value-item {
line-height: var(--custom-multiple-lineHeight);
+ line-height: 18px;
}
}
.custom-treeselect.vue-treeselect--open-below .vue-treeselect__menu {