feat(ui): support multi-value attribute associations

This commit is contained in:
LH_R
2025-08-15 15:57:59 +08:00
parent 73bdd99829
commit f7273c96dc
3 changed files with 150 additions and 26 deletions

View File

@@ -50,13 +50,18 @@
<vxe-column :width="300" field="attributeAssociation" :edit-render="{}"> <vxe-column :width="300" field="attributeAssociation" :edit-render="{}">
<template #header> <template #header>
<span> <span>
<a-tooltip :title="$t('cmdb.ciType.attributeAssociationTip1')"> <a-tooltip>
<template #title>
<div>{{ $t('cmdb.ciType.attributeAssociationTip1') }}</div>
<div>{{ $t('cmdb.ciType.attributeAssociationTip7') }}</div>
<div>{{ $t('cmdb.ciType.attributeAssociationTip8') }}</div>
</template>
<a><a-icon type="question-circle"/></a> <a><a-icon type="question-circle"/></a>
</a-tooltip> </a-tooltip>
{{ $t('cmdb.ciType.attributeAssociation') }} {{ $t('cmdb.ciType.attributeAssociation') }}
<span :style="{ fontSize: '10px', fontWeight: 'normal' }" class="text-color-4">{{ <span :style="{ fontSize: '10px', fontWeight: 'normal' }" class="text-color-4">
$t('cmdb.ciType.attributeAssociationTip2') {{ $t('cmdb.ciType.attributeAssociationTip2') }}
}}</span> </span>
</span> </span>
</template> </template>
<template #default="{row}"> <template #default="{row}">
@@ -88,7 +93,13 @@
optionFilterProp="title" optionFilterProp="title"
> >
<a-select-option <a-select-option
v-for="attr in filterAttributes(row.isParent ? row.attributes : attributes)" v-for="attr in filterAttributes(
row.isParent ? row.attributes : attributes,
item.childAttrId,
row.isParent ? attributes : row.attributes,
'parent',
row.constraint
)"
:key="attr.id" :key="attr.id"
:value="attr.id" :value="attr.id"
:title="attr.alias || attr.name" :title="attr.alias || attr.name"
@@ -107,7 +118,13 @@
optionFilterProp="title" optionFilterProp="title"
> >
<a-select-option <a-select-option
v-for="attr in filterAttributes(row.isParent ? attributes : row.attributes)" v-for="attr in filterAttributes(
row.isParent ? attributes : row.attributes,
item.parentAttrId,
row.isParent ? row.attributes : attributes,
'child',
row.constraint
)"
:key="attr.id" :key="attr.id"
:value="attr.id" :value="attr.id"
:title="attr.alias || attr.name" :title="attr.alias || attr.name"
@@ -200,6 +217,7 @@
'constraint', 'constraint',
{ rules: [{ required: true, message: $t('cmdb.ciType.relationConstraintTips') }] }, { rules: [{ required: true, message: $t('cmdb.ciType.relationConstraintTips') }] },
]" ]"
@change="handleFormConstraintChange"
> >
<a-select-option value="0">{{ $t('cmdb.ciType.one2Many') }}</a-select-option> <a-select-option value="0">{{ $t('cmdb.ciType.one2Many') }}</a-select-option>
<a-select-option value="1">{{ $t('cmdb.ciType.one2One') }}</a-select-option> <a-select-option value="1">{{ $t('cmdb.ciType.one2One') }}</a-select-option>
@@ -207,6 +225,10 @@
</a-select> </a-select>
</a-form-item> </a-form-item>
<a-form-item :label="$t('cmdb.ciType.attributeAssociation')"> <a-form-item :label="$t('cmdb.ciType.attributeAssociation')">
<template #extra>
<div>{{ $t('cmdb.ciType.attributeAssociationTip7') }}</div>
<div>{{ $t('cmdb.ciType.attributeAssociationTip8') }}</div>
</template>
<a-row <a-row
v-for="item in modalAttrList" v-for="item in modalAttrList"
:key="item.id" :key="item.id"
@@ -218,7 +240,15 @@
allowClear allowClear
v-model="item.parentAttrId" v-model="item.parentAttrId"
> >
<a-select-option v-for="attr in filterAttributes(attributes)" :key="attr.id"> <a-select-option
v-for="attr in filterAttributes(
attributes,
item.childAttrId,
modalChildAttributes,
'parent'
)"
:key="attr.id"
>
{{ attr.alias || attr.name }} {{ attr.alias || attr.name }}
</a-select-option> </a-select-option>
</a-select> </a-select>
@@ -234,7 +264,15 @@
allowClear allowClear
v-model="item.childAttrId" v-model="item.childAttrId"
> >
<a-select-option v-for="attr in filterAttributes(modalChildAttributes)" :key="attr.id"> <a-select-option
v-for="attr in filterAttributes(
modalChildAttributes,
item.parentAttrId,
attributes,
'child'
)"
:key="attr.id"
>
{{ attr.alias || attr.name }} {{ attr.alias || attr.name }}
</a-select-option> </a-select-option>
</a-select> </a-select>
@@ -594,16 +632,34 @@ export default {
}) })
} }
}, },
filterAttributes(attributes) {
// filter password/json/is_list/longText/bool/reference filterAttributes(attributes, relationAttrId, relationAttrs, type, constraint) {
return attributes.filter((attr) => { const relationAttr = relationAttrs.find((attr) => attr.id === relationAttrId)
// filter password/json/longText/bool/reference
let filterAttrs = attributes.filter((attr) => {
if (attr.value_type === '2' && !attr.is_index) { if (attr.value_type === '2' && !attr.is_index) {
return false return false
} }
return !attr.is_password && !attr.is_list && attr.value_type !== '6' && !attr.is_bool && !attr.is_reference return !attr.is_password && attr.value_type !== '6' && !attr.is_bool && !attr.is_reference
}) })
if (relationAttr) {
filterAttrs = filterAttrs.filter((attr) => attr.value_type === relationAttr?.value_type)
}
const constraintValue = Number(constraint ?? this.form.getFieldValue('constraint'))
if (
(constraintValue === 0 && type === 'child') ||
constraintValue === 1
) {
return filterAttrs.filter((attr) => !attr.is_list)
}
return filterAttrs
}, },
addTableAttr() { addTableAttr() {
this.tableAttrList.push({ this.tableAttrList.push({
id: uuidv4(), id: uuidv4(),
@@ -639,6 +695,13 @@ export default {
if (index !== -1) { if (index !== -1) {
this.modalAttrList.splice(index, 1) this.modalAttrList.splice(index, 1)
} }
},
handleFormConstraintChange() {
this.modalAttrList.forEach((item) => {
item.parentAttrId = undefined
item.childAttrId = undefined
})
} }
}, },
} }

View File

@@ -56,6 +56,7 @@
'constraint', 'constraint',
{ rules: [{ required: true, message: $t('cmdb.ciType.relationConstraintTips') }] }, { rules: [{ required: true, message: $t('cmdb.ciType.relationConstraintTips') }] },
]" ]"
@change="handleConstraintChange"
> >
<a-select-option value="0">{{ $t('cmdb.ciType.one2Many') }}</a-select-option> <a-select-option value="0">{{ $t('cmdb.ciType.one2Many') }}</a-select-option>
<a-select-option value="1">{{ $t('cmdb.ciType.one2One') }}</a-select-option> <a-select-option value="1">{{ $t('cmdb.ciType.one2One') }}</a-select-option>
@@ -63,6 +64,10 @@
</a-select> </a-select>
</a-form-item> </a-form-item>
<a-form-item :label="$t('cmdb.ciType.attributeAssociation')"> <a-form-item :label="$t('cmdb.ciType.attributeAssociation')">
<template #extra>
<div>{{ $t('cmdb.ciType.attributeAssociationTip7') }}</div>
<div>{{ $t('cmdb.ciType.attributeAssociationTip8') }}</div>
</template>
<a-row <a-row
v-for="item in modalAttrList" v-for="item in modalAttrList"
:key="item.id" :key="item.id"
@@ -74,7 +79,10 @@
allowClear allowClear
v-model="item.parentAttrId" v-model="item.parentAttrId"
> >
<a-select-option v-for="attr in filterAttributes(modalParentAttributes)" :key="attr.id"> <a-select-option
v-for="attr in filterAttributes(modalParentAttributes, item.childAttrId, modalChildAttributes, 'parent')"
:key="attr.id"
>
{{ attr.alias || attr.name }} {{ attr.alias || attr.name }}
</a-select-option> </a-select-option>
</a-select> </a-select>
@@ -90,7 +98,10 @@
allowClear allowClear
v-model="item.childAttrId" v-model="item.childAttrId"
> >
<a-select-option v-for="attr in filterAttributes(modalChildAttributes)" :key="attr.id"> <a-select-option
v-for="attr in filterAttributes(modalChildAttributes, item.parentAttrId, modalParentAttributes, 'child')"
:key="attr.id"
>
{{ attr.alias || attr.name }} {{ attr.alias || attr.name }}
</a-select-option> </a-select-option>
</a-select> </a-select>
@@ -183,7 +194,7 @@ export default {
'1': this.$t('cmdb.ciType.one2One'), '1': this.$t('cmdb.ciType.one2One'),
'2': this.$t('cmdb.ciType.many2Many'), '2': this.$t('cmdb.ciType.many2Many'),
} }
}, }
}, },
provide() { provide() {
return { return {
@@ -356,15 +367,32 @@ export default {
this.modalChildAttributes = res?.attributes ?? [] this.modalChildAttributes = res?.attributes ?? []
}) })
}, },
filterAttributes(attributes) {
// filter password/json/is_list/longText/bool/reference filterAttributes(attributes, relationAttrId, relationAttrs, type) {
return attributes.filter((attr) => { const relationAttr = relationAttrs.find((attr) => attr.id === relationAttrId)
// filter password/json/longText/bool/reference
let filterAttrs = attributes.filter((attr) => {
if (attr.value_type === '2' && !attr.is_index) { if (attr.value_type === '2' && !attr.is_index) {
return false return false
} }
return !attr.is_password && !attr.is_list && attr.value_type !== '6' && !attr.is_bool && !attr.is_reference return !attr.is_password && attr.value_type !== '6' && !attr.is_bool && !attr.is_reference
}) })
if (relationAttr) {
filterAttrs = filterAttrs.filter((attr) => attr.value_type === relationAttr?.value_type)
}
const constraintValue = Number(this.form.getFieldValue('constraint'))
if (
(constraintValue === 0 && type === 'child') ||
constraintValue === 1
) {
return filterAttrs.filter((attr) => !attr.is_list)
}
return filterAttrs
}, },
addModalAttr() { addModalAttr() {
@@ -384,6 +412,13 @@ export default {
if (index !== -1) { if (index !== -1) {
this.modalAttrList.splice(index, 1) this.modalAttrList.splice(index, 1)
} }
},
handleConstraintChange() {
this.modalAttrList.forEach((item) => {
item.parentAttrId = undefined
item.childAttrId = undefined
})
} }
}, },
} }

View File

@@ -38,7 +38,12 @@
<vxe-column :width="300" field="attributeAssociation" :edit-render="{}"> <vxe-column :width="300" field="attributeAssociation" :edit-render="{}">
<template #header> <template #header>
<span> <span>
<a-tooltip :title="$t('cmdb.ciType.attributeAssociationTip1')"> <a-tooltip>
<template #title>
<div>{{ $t('cmdb.ciType.attributeAssociationTip1') }}</div>
<div>{{ $t('cmdb.ciType.attributeAssociationTip7') }}</div>
<div>{{ $t('cmdb.ciType.attributeAssociationTip8') }}</div>
</template>
<a><a-icon type="question-circle"/></a> <a><a-icon type="question-circle"/></a>
</a-tooltip> </a-tooltip>
{{ $t('cmdb.ciType.attributeAssociation') }} {{ $t('cmdb.ciType.attributeAssociation') }}
@@ -76,7 +81,7 @@
optionFilterProp="title" optionFilterProp="title"
> >
<a-select-option <a-select-option
v-for="attr in filterAttributes(type2attributes[row.parent_id])" v-for="attr in filterAttributes(row, item.childAttrId, 'parent')"
:key="attr.id" :key="attr.id"
:value="attr.id" :value="attr.id"
:title="attr.alias || attr.name" :title="attr.alias || attr.name"
@@ -95,7 +100,7 @@
optionFilterProp="title" optionFilterProp="title"
> >
<a-select-option <a-select-option
v-for="attr in filterAttributes(type2attributes[row.child_id])" v-for="attr in filterAttributes(row, item.parentAttrId, 'child')"
:key="attr.id" :key="attr.id"
:value="attr.id" :value="attr.id"
:title="attr.alias || attr.name" :title="attr.alias || attr.name"
@@ -298,15 +303,36 @@ export default {
const _find = attributes.find((attr) => attr.id === id) const _find = attributes.find((attr) => attr.id === id)
return _find?.alias ?? _find?.name ?? id return _find?.alias ?? _find?.name ?? id
}, },
filterAttributes(attributes) {
// filter password/json/is_list/longText/bool/reference filterAttributes(row, relationAttrId, type) {
return attributes.filter((attr) => { const { parent_id, child_id, constraint } = row
const currentAttrs = this.type2attributes?.[child_id] || []
const relationAttrs = this.type2attributes?.[parent_id] || []
const relationAttr = relationAttrs.find((attr) => attr.id === relationAttrId)
// filter password/json/longText/bool/reference
let filterAttrs = currentAttrs.filter((attr) => {
if (attr.value_type === '2' && !attr.is_index) { if (attr.value_type === '2' && !attr.is_index) {
return false return false
} }
return !attr.is_password && !attr.is_list && attr.value_type !== '6' && !attr.is_bool && !attr.is_reference return !attr.is_password && attr.value_type !== '6' && !attr.is_bool && !attr.is_reference
}) })
if (relationAttr) {
filterAttrs = filterAttrs.filter((attr) => attr.value_type === relationAttr?.value_type)
}
const constraintValue = Number(constraint)
if (
(constraintValue === 0 && type === 'child') ||
constraintValue === 1
) {
return filterAttrs.filter((attr) => !attr.is_list)
}
return filterAttrs
}, },
addTableAttr() { addTableAttr() {