mirror of https://github.com/veops/cmdb.git
Merge pull request #588 from veops/dev_ui_240731
feat(ui): update ci type
This commit is contained in:
commit
c08e4529de
|
@ -3,3 +3,4 @@ VUE_APP_PREVIEW=false
|
||||||
VUE_APP_API_BASE_URL=http://127.0.0.1:5000/api
|
VUE_APP_API_BASE_URL=http://127.0.0.1:5000/api
|
||||||
VUE_APP_BUILD_PACKAGES="ticket,calendar,acl"
|
VUE_APP_BUILD_PACKAGES="ticket,calendar,acl"
|
||||||
VUE_APP_IS_OUTER=true
|
VUE_APP_IS_OUTER=true
|
||||||
|
VUE_APP_IS_OPEN_SOURCE=true
|
||||||
|
|
|
@ -69,6 +69,8 @@ Vue.prototype.$httpError = function (err, describe) {
|
||||||
|
|
||||||
window.$message = Vue.prototype.$message
|
window.$message = Vue.prototype.$message
|
||||||
|
|
||||||
|
Vue.prototype.isOpenSource = process.env.VUE_APP_IS_OPEN_SOURCE === 'true'
|
||||||
|
|
||||||
Vue.use(Antd)
|
Vue.use(Antd)
|
||||||
Vue.use(Viser)
|
Vue.use(Viser)
|
||||||
|
|
||||||
|
|
|
@ -122,6 +122,31 @@ export function deleteCITypeGroupById(groupId, data) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取级联属性配置
|
||||||
|
* @param {*} typeId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function getCITypeCascadeAttributes(typeId) {
|
||||||
|
return axios({
|
||||||
|
url: `/v0.1/cascade_attributes/ci_types/${typeId}`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取级联属性数据
|
||||||
|
* @param {*} typeId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function postCITypeCascadeAttributesValues(attrId, data) {
|
||||||
|
return axios({
|
||||||
|
url: `/v0.1/cascade_attributes/${attrId}/values`,
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export function getUniqueConstraintList(type_id) {
|
export function getUniqueConstraintList(type_id) {
|
||||||
return axios({
|
return axios({
|
||||||
url: `/v0.1/ci_types/${type_id}/unique_constraint`,
|
url: `/v0.1/ci_types/${type_id}/unique_constraint`,
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
class="category-side-children-item-corporate"
|
class="category-side-children-item-corporate"
|
||||||
v-if="ruleType === 'private_cloud' || (ruleType === 'http' && (categoryIndex !== 0 || itemIndex !== 0))"
|
v-if="ruleType === 'private_cloud' || (ruleType === 'http' && (categoryIndex !== 0 || itemIndex !== 0))"
|
||||||
>
|
>
|
||||||
企
|
{{ $t('cmdb.enterpriseVersionFlag') }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -67,7 +67,7 @@
|
||||||
class="corporate-flag"
|
class="corporate-flag"
|
||||||
v-if="ruleType === 'private_cloud' || (ruleType === 'http' && (categoryIndex !== 0 || itemIndex !== 0))"
|
v-if="ruleType === 'private_cloud' || (ruleType === 'http' && (categoryIndex !== 0 || itemIndex !== 0))"
|
||||||
>
|
>
|
||||||
<span class="corporate-flag-text">企</span>
|
<span class="corporate-flag-text">{{ $t('cmdb.enterpriseVersionFlag') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,6 +2,8 @@ const cmdb_en = {
|
||||||
relation: 'Relation',
|
relation: 'Relation',
|
||||||
attribute: 'Attributes',
|
attribute: 'Attributes',
|
||||||
configTable: 'Config Table',
|
configTable: 'Config Table',
|
||||||
|
enterpriseVersionFlag: 'Pro',
|
||||||
|
enterpriseVersionTip: 'Enterprise version only',
|
||||||
menu: {
|
menu: {
|
||||||
views: 'Views',
|
views: 'Views',
|
||||||
topologyView: 'Topology Views',
|
topologyView: 'Topology Views',
|
||||||
|
@ -274,8 +276,12 @@ const cmdb_en = {
|
||||||
attrAlias: 'Attr Alias',
|
attrAlias: 'Attr Alias',
|
||||||
attrCode: 'Attr Code',
|
attrCode: 'Attr Code',
|
||||||
computedAttrTip1: 'Reference attributes follow jinja2 syntax',
|
computedAttrTip1: 'Reference attributes follow jinja2 syntax',
|
||||||
computedAttrTip2: `Multi-valued attributes (lists) are rendered with [ ] included by default, if you want to remove it, the reference method is: ‘’‘{{ attr_name | join(’,‘)}}}’‘’ where commas are separators`,
|
computedAttrTip2: `Multi-valued attributes (lists) are rendered with [ ] included by default, if you want to remove it, the reference method is: """{{ attr_name | join(',') }}""" where commas are separators`,
|
||||||
example: 'Example'
|
example: 'Example',
|
||||||
|
attrFilterTip: `The third column of values allows you to select attributes of this model to cascade attributes`,
|
||||||
|
rule: 'Rule',
|
||||||
|
cascadeAttr: 'Cascade',
|
||||||
|
cascadeAttrTip: 'Cascading attributes note the order',
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
unselectAttributes: 'Unselected',
|
unselectAttributes: 'Unselected',
|
||||||
|
@ -325,6 +331,7 @@ const cmdb_en = {
|
||||||
sub: 'subscription',
|
sub: 'subscription',
|
||||||
selectBelow: 'Please select below',
|
selectBelow: 'Please select below',
|
||||||
subSuccess: 'Subscription successful',
|
subSuccess: 'Subscription successful',
|
||||||
|
subFailed: 'Subscription failed, please try again later',
|
||||||
selectMethods: 'Please select a method',
|
selectMethods: 'Please select a method',
|
||||||
noAuthRequest: 'No certification requested yet',
|
noAuthRequest: 'No certification requested yet',
|
||||||
noParamRequest: 'No parameter certification yet',
|
noParamRequest: 'No parameter certification yet',
|
||||||
|
@ -380,6 +387,8 @@ const cmdb_en = {
|
||||||
yearsAgo: 'years ago',
|
yearsAgo: 'years ago',
|
||||||
just: 'just now',
|
just: 'just now',
|
||||||
searchPlaceholder: 'Please search CIType',
|
searchPlaceholder: 'Please search CIType',
|
||||||
|
subCITable: 'Data',
|
||||||
|
subCITree: 'Tree',
|
||||||
},
|
},
|
||||||
custom_dashboard: {
|
custom_dashboard: {
|
||||||
charts: 'Chart',
|
charts: 'Chart',
|
||||||
|
@ -639,6 +648,7 @@ if __name__ == "__main__":
|
||||||
rollbackingTips: 'Rollbacking',
|
rollbackingTips: 'Rollbacking',
|
||||||
batchRollbacking: 'Deleting {total} items in total, {successNum} items successful, {errorNum} items failed',
|
batchRollbacking: 'Deleting {total} items in total, {successNum} items successful, {errorNum} items failed',
|
||||||
baselineTips: 'Changes at this point in time will also be rollbacked, Unique ID, password and dynamic attributes do not support',
|
baselineTips: 'Changes at this point in time will also be rollbacked, Unique ID, password and dynamic attributes do not support',
|
||||||
|
cover: 'Cover',
|
||||||
},
|
},
|
||||||
serviceTree: {
|
serviceTree: {
|
||||||
remove: 'Remove',
|
remove: 'Remove',
|
||||||
|
|
|
@ -2,6 +2,8 @@ const cmdb_zh = {
|
||||||
relation: '关系',
|
relation: '关系',
|
||||||
attribute: '属性',
|
attribute: '属性',
|
||||||
configTable: '配置表格',
|
configTable: '配置表格',
|
||||||
|
enterpriseVersionFlag: '企',
|
||||||
|
enterpriseVersionTip: '仅限企业版',
|
||||||
menu: {
|
menu: {
|
||||||
views: '视图',
|
views: '视图',
|
||||||
topologyView: '拓扑视图',
|
topologyView: '拓扑视图',
|
||||||
|
@ -275,7 +277,11 @@ const cmdb_zh = {
|
||||||
attrCode: '属性代码',
|
attrCode: '属性代码',
|
||||||
computedAttrTip1: '引用属性遵循jinja2语法',
|
computedAttrTip1: '引用属性遵循jinja2语法',
|
||||||
computedAttrTip2: `多值属性(列表)默认呈现包括[ ], 如果要去掉, 引用方法为: """{{ attr_name | join(',') }}""" 其中逗号为分隔符`,
|
computedAttrTip2: `多值属性(列表)默认呈现包括[ ], 如果要去掉, 引用方法为: """{{ attr_name | join(',') }}""" 其中逗号为分隔符`,
|
||||||
example: '例如'
|
example: '例如',
|
||||||
|
attrFilterTip: '第三列值可选择本模型的属性,来实现级联属性的功能',
|
||||||
|
rule: '规则',
|
||||||
|
cascadeAttr: '级联',
|
||||||
|
cascadeAttrTip: '级联属性注意顺序',
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
unselectAttributes: '未选属性',
|
unselectAttributes: '未选属性',
|
||||||
|
@ -325,6 +331,7 @@ const cmdb_zh = {
|
||||||
sub: '订阅',
|
sub: '订阅',
|
||||||
selectBelow: '请在下方进行选择',
|
selectBelow: '请在下方进行选择',
|
||||||
subSuccess: '订阅成功',
|
subSuccess: '订阅成功',
|
||||||
|
subFailed: '订阅失败,请稍后再试',
|
||||||
selectMethods: '请选择方式',
|
selectMethods: '请选择方式',
|
||||||
noAuthRequest: '暂无请求认证',
|
noAuthRequest: '暂无请求认证',
|
||||||
noParamRequest: '暂无参数认证',
|
noParamRequest: '暂无参数认证',
|
||||||
|
@ -379,6 +386,8 @@ const cmdb_zh = {
|
||||||
yearsAgo: '年前',
|
yearsAgo: '年前',
|
||||||
just: '刚刚',
|
just: '刚刚',
|
||||||
searchPlaceholder: '请搜索模型',
|
searchPlaceholder: '请搜索模型',
|
||||||
|
subCITable: '数据订阅',
|
||||||
|
subCITree: '层级订阅',
|
||||||
},
|
},
|
||||||
custom_dashboard: {
|
custom_dashboard: {
|
||||||
charts: '图表',
|
charts: '图表',
|
||||||
|
@ -638,6 +647,7 @@ if __name__ == "__main__":
|
||||||
rollbackingTips: '正在批量回滚中',
|
rollbackingTips: '正在批量回滚中',
|
||||||
batchRollbacking: '正在回滚,共{total}个,成功{successNum}个,失败{errorNum}个',
|
batchRollbacking: '正在回滚,共{total}个,成功{successNum}个,失败{errorNum}个',
|
||||||
baselineTips: '该时间点的变更也会被回滚, 唯一标识、密码属性、动态属性不支持回滚',
|
baselineTips: '该时间点的变更也会被回滚, 唯一标识、密码属性、动态属性不支持回滚',
|
||||||
|
cover: '覆盖',
|
||||||
},
|
},
|
||||||
serviceTree: {
|
serviceTree: {
|
||||||
remove: '移除',
|
remove: '移除',
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
:ref="`createInstanceFormByGroup_${group.id}`"
|
:ref="`createInstanceFormByGroup_${group.id}`"
|
||||||
:key="group.id || group.name"
|
:key="group.id || group.name"
|
||||||
:group="group"
|
:group="group"
|
||||||
@handleFocusInput="handleFocusInput"
|
|
||||||
:attributeList="attributeList"
|
:attributeList="attributeList"
|
||||||
|
@handleFocusInput="handleFocusInput"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="parentsType && parentsType.length">
|
<template v-if="parentsType && parentsType.length">
|
||||||
|
@ -57,8 +57,8 @@
|
||||||
<template v-if="action === 'update'">
|
<template v-if="action === 'update'">
|
||||||
<a-form :form="form">
|
<a-form :form="form">
|
||||||
<p>{{ $t('cmdb.ci.tips2') }}</p>
|
<p>{{ $t('cmdb.ci.tips2') }}</p>
|
||||||
<a-row :gutter="24" v-for="list in batchUpdateLists" :key="list.name">
|
<a-row :gutter="8" v-for="list in batchUpdateLists" :key="list.name">
|
||||||
<a-col :span="11">
|
<a-col :span="6">
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<el-select showSearch size="small" filterable v-model="list.name" :placeholder="$t('cmdb.ci.tips3')">
|
<el-select showSearch size="small" filterable v-model="list.name" :placeholder="$t('cmdb.ci.tips3')">
|
||||||
<el-option
|
<el-option
|
||||||
|
@ -72,11 +72,24 @@
|
||||||
</el-select>
|
</el-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="11">
|
<a-col v-if="showListOperation(list.name)" :span="3">
|
||||||
|
<a-form-item>
|
||||||
|
<el-select size="small" filterable v-model="list.operation" :placeholder="$t('placeholder2')">
|
||||||
|
<el-option
|
||||||
|
v-for="(option) in listOperationOptions"
|
||||||
|
:key="option.value"
|
||||||
|
:value="option.value"
|
||||||
|
:label="$t(option.label)"
|
||||||
|
>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="showListOperation(list.name) ? 10 : 13">
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<a-select
|
<a-select
|
||||||
:style="{ width: '100%' }"
|
:style="{ width: '100%' }"
|
||||||
v-decorator="[list.name, { rules: [{ required: false }] }]"
|
v-decorator="[list.name, { rules: getDecoratorRules(list) }]"
|
||||||
:placeholder="$t('placeholder2')"
|
:placeholder="$t('placeholder2')"
|
||||||
v-if="getFieldType(list.name).split('%%')[0] === 'select'"
|
v-if="getFieldType(list.name).split('%%')[0] === 'select'"
|
||||||
:mode="getFieldType(list.name).split('%%')[1] === 'multiple' ? 'multiple' : 'default'"
|
:mode="getFieldType(list.name).split('%%')[1] === 'multiple' ? 'multiple' : 'default'"
|
||||||
|
@ -99,12 +112,12 @@
|
||||||
</a-select-option>
|
</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
<a-input-number
|
<a-input-number
|
||||||
v-decorator="[list.name, { rules: [{ required: false }] }]"
|
v-decorator="[list.name, { rules: getDecoratorRules(list) }]"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
v-if="getFieldType(list.name) === 'input_number'"
|
v-if="getFieldType(list.name) === 'input_number'"
|
||||||
/>
|
/>
|
||||||
<a-date-picker
|
<a-date-picker
|
||||||
v-decorator="[list.name, { rules: [{ required: false }] }]"
|
v-decorator="[list.name, { rules: getDecoratorRules(list) }]"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
:format="getFieldType(list.name) == '4' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss'"
|
:format="getFieldType(list.name) == '4' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss'"
|
||||||
:valueFormat="getFieldType(list.name) == '4' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss'"
|
:valueFormat="getFieldType(list.name) == '4' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss'"
|
||||||
|
@ -114,7 +127,7 @@
|
||||||
<a-input
|
<a-input
|
||||||
v-if="getFieldType(list.name) === 'input'"
|
v-if="getFieldType(list.name) === 'input'"
|
||||||
@focus="(e) => handleFocusInput(e, list)"
|
@focus="(e) => handleFocusInput(e, list)"
|
||||||
v-decorator="[list.name, { rules: [{ required: false }] }]"
|
v-decorator="[list.name, { rules: getDecoratorRules(list) }]"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
@ -173,6 +186,20 @@ export default {
|
||||||
parentsType: [],
|
parentsType: [],
|
||||||
parentsForm: {},
|
parentsForm: {},
|
||||||
canEdit: {},
|
canEdit: {},
|
||||||
|
listOperationOptions: [
|
||||||
|
{
|
||||||
|
value: 'cover',
|
||||||
|
label: 'cmdb.ci.cover'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'add',
|
||||||
|
label: 'add'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'delete',
|
||||||
|
label: 'delete'
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -228,7 +255,7 @@ export default {
|
||||||
createInstance() {
|
createInstance() {
|
||||||
const _this = this
|
const _this = this
|
||||||
if (_this.action === 'update') {
|
if (_this.action === 'update') {
|
||||||
this.form.validateFields((err, values) => {
|
this.form.validateFields({ force: true }, (err, values) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -251,6 +278,21 @@ export default {
|
||||||
if (_tempFind.value_type === '6') {
|
if (_tempFind.value_type === '6') {
|
||||||
values[k] = values[k] ? JSON.parse(values[k]) : undefined
|
values[k] = values[k] ? JSON.parse(values[k]) : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_tempFind.is_list) {
|
||||||
|
const operation = this.batchUpdateLists?.find((item) => item.name === k)?.operation || 'cover'
|
||||||
|
switch (operation) {
|
||||||
|
case 'add':
|
||||||
|
case 'delete':
|
||||||
|
values[k] = {
|
||||||
|
op: operation,
|
||||||
|
v: values[k]
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
_this.$emit('submit', values)
|
_this.$emit('submit', values)
|
||||||
|
@ -340,7 +382,10 @@ export default {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.form.resetFields()
|
this.form.resetFields()
|
||||||
Promise.all([this.getCIType(), this.getAttributeList()]).then(() => {
|
Promise.all([this.getCIType(), this.getAttributeList()]).then(() => {
|
||||||
this.batchUpdateLists = [{ name: this.attributeList[0].name }]
|
this.batchUpdateLists = [{
|
||||||
|
name: this.attributeList?.[0]?.name || undefined,
|
||||||
|
operation: 'cover'
|
||||||
|
}]
|
||||||
})
|
})
|
||||||
if (action === 'create') {
|
if (action === 'create') {
|
||||||
getCITypeParent(this.typeId).then(async (res) => {
|
getCITypeParent(this.typeId).then(async (res) => {
|
||||||
|
@ -389,7 +434,10 @@ export default {
|
||||||
return []
|
return []
|
||||||
},
|
},
|
||||||
handleAdd() {
|
handleAdd() {
|
||||||
this.batchUpdateLists.push({ name: undefined })
|
this.batchUpdateLists.push({
|
||||||
|
name: undefined,
|
||||||
|
operation: 'cover'
|
||||||
|
})
|
||||||
},
|
},
|
||||||
handleDelete(name) {
|
handleDelete(name) {
|
||||||
const _idx = this.batchUpdateLists.findIndex((item) => item.name === name)
|
const _idx = this.batchUpdateLists.findIndex((item) => item.name === name)
|
||||||
|
@ -415,6 +463,31 @@ export default {
|
||||||
jsonEditorOk(jsonData) {
|
jsonEditorOk(jsonData) {
|
||||||
this.form.setFieldsValue({ [this.editAttr.name]: JSON.stringify(jsonData) })
|
this.form.setFieldsValue({ [this.editAttr.name]: JSON.stringify(jsonData) })
|
||||||
},
|
},
|
||||||
|
|
||||||
|
showListOperation(name) {
|
||||||
|
if (!name) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const attr = this.attributeList.find((attr) => attr.name === name)
|
||||||
|
|
||||||
|
return attr && attr.is_list
|
||||||
|
},
|
||||||
|
|
||||||
|
getDecoratorRules(data) {
|
||||||
|
const { name, operation } = data
|
||||||
|
const isList = this.showListOperation(name)
|
||||||
|
const rules = [
|
||||||
|
{ required: false }
|
||||||
|
]
|
||||||
|
if (isList && ['delete', 'add'].includes(operation)) {
|
||||||
|
rules[0] = {
|
||||||
|
required: true,
|
||||||
|
message: this.$t('placeholder1')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rules
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -92,7 +92,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
attr.groupId = -1
|
attr.groupId = -1
|
||||||
attr.groupName = '其他'
|
attr.groupName = this.$t('other')
|
||||||
attr.code = `{{ ${attr.name} }}`
|
attr.code = `{{ ${attr.name} }}`
|
||||||
attr.typeText = typeMap?.[attr.value_type] ?? ''
|
attr.typeText = typeMap?.[attr.value_type] ?? ''
|
||||||
})
|
})
|
||||||
|
|
|
@ -454,10 +454,15 @@ export default {
|
||||||
query_expr: _findADT.query_expr || '',
|
query_expr: _findADT.query_expr || '',
|
||||||
enabled: _findADT?.enabled ?? true,
|
enabled: _findADT?.enabled ?? true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const allMachineIndex = this.agentTypeRadioList.findIndex((item) => item.value === 'all')
|
||||||
|
|
||||||
if (_findADT.query_expr) {
|
if (_findADT.query_expr) {
|
||||||
this.agent_type = 'query_expr'
|
this.agent_type = 'query_expr'
|
||||||
} else if (_findADT.agent_id) {
|
} else if (_findADT.agent_id) {
|
||||||
this.agent_type = _findADT.agent_id === '0x0000' ? 'master' : 'agent_id'
|
this.agent_type = _findADT.agent_id === '0x0000' ? 'master' : 'agent_id'
|
||||||
|
} else if (_findADT.agent_id === '' && allMachineIndex !== -1) {
|
||||||
|
this.agent_type = 'all'
|
||||||
} else {
|
} else {
|
||||||
this.agent_type = this.agentTypeRadioList[0].value
|
this.agent_type = this.agentTypeRadioList[0].value
|
||||||
}
|
}
|
||||||
|
|
|
@ -345,6 +345,7 @@
|
||||||
:canDefineScript="canDefineScript"
|
:canDefineScript="canDefineScript"
|
||||||
ref="preValueArea"
|
ref="preValueArea"
|
||||||
:disabled="isShowComputedArea"
|
:disabled="isShowComputedArea"
|
||||||
|
:CITypeId="CITypeId"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
|
|
@ -18,19 +18,19 @@
|
||||||
<a-button @click="handleOpenUniqueConstraint" size="small">{{ $t('cmdb.ciType.uniqueConstraint') }}</a-button>
|
<a-button @click="handleOpenUniqueConstraint" size="small">{{ $t('cmdb.ciType.uniqueConstraint') }}</a-button>
|
||||||
<div>
|
<div>
|
||||||
<a-tooltip
|
<a-tooltip
|
||||||
v-for="type in Object.keys(valueTypeMap)"
|
v-for="typeKey in Object.keys(valueTypeMap)"
|
||||||
:key="type"
|
:key="typeKey"
|
||||||
:title="$t('cmdb.ciType.filterTips', { name: valueTypeMap[type] })"
|
:title="$t('cmdb.ciType.filterTips', { name: valueTypeMap[typeKey] })"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@click="handleFilterType(type)"
|
@click="handleFilterType(typeKey)"
|
||||||
:class="{
|
:class="{
|
||||||
'ci-types-attributes-filter': true,
|
'ci-types-attributes-filter': true,
|
||||||
'ci-types-attributes-filter-selected': attrTypeFilter.includes(type),
|
'ci-types-attributes-filter-selected': attrTypeFilter.includes(typeKey),
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<ops-icon :type="getPropertyIcon({ value_type: type })" />
|
<ops-icon :type="getPropertyIcon({ value_type: typeKey })" />
|
||||||
{{ valueTypeMap[type] }}
|
{{ valueTypeMap[typeKey] }}
|
||||||
</span>
|
</span>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -333,7 +333,12 @@
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="24" v-if="!['6', '7'].includes(currentValueType)">
|
<a-col :span="24" v-if="!['6', '7'].includes(currentValueType)">
|
||||||
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }" :label="$t('cmdb.ciType.choiceValue')">
|
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }" :label="$t('cmdb.ciType.choiceValue')">
|
||||||
<PreValueArea ref="preValueArea" :canDefineScript="canDefineScript" :disabled="isShowComputedArea" />
|
<PreValueArea
|
||||||
|
ref="preValueArea"
|
||||||
|
:canDefineScript="canDefineScript"
|
||||||
|
:disabled="isShowComputedArea"
|
||||||
|
:CITypeId="CITypeId"
|
||||||
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="24" v-if="!['6', '7'].includes(currentValueType)">
|
<a-col :span="24" v-if="!['6', '7'].includes(currentValueType)">
|
||||||
|
@ -402,6 +407,10 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
CITypeId: {
|
||||||
|
type: Number,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -32,6 +32,8 @@ import TriggerTable from './triggerTable.vue'
|
||||||
import ADTab from './adTab.vue'
|
import ADTab from './adTab.vue'
|
||||||
import GrantComp from '../../components/cmdbGrant/grantComp.vue'
|
import GrantComp from '../../components/cmdbGrant/grantComp.vue'
|
||||||
|
|
||||||
|
const ACTIVE_KEY_STORAGE_KEY = 'ops_model_config_tab_key'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CITypeDetail',
|
name: 'CITypeDetail',
|
||||||
components: {
|
components: {
|
||||||
|
@ -53,11 +55,24 @@ export default {
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
activeKey: '1',
|
activeKey: localStorage.getItem(ACTIVE_KEY_STORAGE_KEY) || '1',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeCreate() {},
|
beforeCreate() {},
|
||||||
mounted() {},
|
mounted() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
switch (this.activeKey) {
|
||||||
|
case '6':
|
||||||
|
this.$refs.triggerTable.getTableData()
|
||||||
|
break
|
||||||
|
case '5':
|
||||||
|
this.$refs.reconciliationTable.getTableData()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState({
|
||||||
windowHeight: (state) => state.windowHeight,
|
windowHeight: (state) => state.windowHeight,
|
||||||
|
@ -66,15 +81,23 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
changeTab(activeKey) {
|
changeTab(activeKey) {
|
||||||
this.activeKey = activeKey
|
this.activeKey = activeKey
|
||||||
|
localStorage.setItem(ACTIVE_KEY_STORAGE_KEY, activeKey)
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
if (activeKey === '1') {
|
switch (activeKey) {
|
||||||
|
case '1':
|
||||||
this.$refs.attributesTable.getCITypeGroupData()
|
this.$refs.attributesTable.getCITypeGroupData()
|
||||||
}
|
break
|
||||||
if (activeKey === '5') {
|
case '6':
|
||||||
this.$refs.triggerTable.getTableData()
|
this.$refs.triggerTable.getTableData()
|
||||||
|
break
|
||||||
|
case '5':
|
||||||
|
this.$refs.reconciliationTable.getTableData()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
<template>
|
<template>
|
||||||
<a-tabs v-model="activeKey" size="small" :tabBarStyle="{ borderBottom: 'none' }">
|
<a-tabs v-model="activeKey" size="small" :tabBarStyle="{ borderBottom: 'none' }" @change="handleTabsChange">
|
||||||
<a-tab-pane key="expr" :disabled="!canDefineComputed">
|
<a-tab-pane key="expr" :disabled="!canDefineComputed">
|
||||||
<span style="font-size:12px;" slot="tab">{{ $t('cmdb.ciType.expr') }}</span>
|
<span style="font-size:12px;" slot="tab">{{ $t('cmdb.ciType.expr') }}</span>
|
||||||
<a-textarea v-model="compute_expr" :placeholder="`{{a}}+{{b}}`" :rows="2" :disabled="!canDefineComputed" />
|
<a-textarea v-model="compute_expr" :placeholder="`{{a}}+{{b}}`" :rows="2" :disabled="!canDefineComputed" />
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane key="script" :disabled="!canDefineComputed">
|
<a-tab-pane key="script" :disabled="!canDefineComputed">
|
||||||
<span style="font-size:12px;" slot="tab">{{ $t('cmdb.ciType.code') }}</span>
|
<span style="font-size:12px;" slot="tab">{{ $t('cmdb.ciType.code') }}</span>
|
||||||
<codemirror
|
<CustomCodeMirror
|
||||||
style="z-index: 9999"
|
codeMirrorId="cmdb-computed-attr"
|
||||||
:options="cmOptions"
|
ref="codemirror"
|
||||||
v-model="compute_script"
|
@changeCodeContent="onCodeChange"
|
||||||
@input="onCodeChange"
|
></CustomCodeMirror>
|
||||||
></codemirror>
|
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<template slot="tabBarExtraContent">
|
<template slot="tabBarExtraContent">
|
||||||
<a-button size="small" @click="showAllPropDrawer">
|
<a-button size="small" @click="showAllPropDrawer">
|
||||||
|
@ -33,7 +32,8 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import AllAttrDrawer from './allAttrDrawer.vue'
|
import AllAttrDrawer from './allAttrDrawer.vue'
|
||||||
import { codemirror } from 'vue-codemirror'
|
|
||||||
|
import CustomCodeMirror from '@/components/CustomCodeMirror'
|
||||||
import 'codemirror/lib/codemirror.css'
|
import 'codemirror/lib/codemirror.css'
|
||||||
import 'codemirror/theme/monokai.css'
|
import 'codemirror/theme/monokai.css'
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ require('codemirror/mode/python/python.js')
|
||||||
export default {
|
export default {
|
||||||
name: 'ComputedArea',
|
name: 'ComputedArea',
|
||||||
components: {
|
components: {
|
||||||
codemirror,
|
CustomCodeMirror,
|
||||||
AllAttrDrawer
|
AllAttrDrawer
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
@ -59,33 +59,6 @@ export default {
|
||||||
activeKey: 'expr', // expr script
|
activeKey: 'expr', // expr script
|
||||||
compute_expr: '',
|
compute_expr: '',
|
||||||
compute_script: 'def computed(): \n return',
|
compute_script: 'def computed(): \n return',
|
||||||
cmOptions: {
|
|
||||||
lineNumbers: true,
|
|
||||||
mode: 'python',
|
|
||||||
height: '200px',
|
|
||||||
theme: 'monokai',
|
|
||||||
tabSize: 4,
|
|
||||||
indentUnit: 4,
|
|
||||||
lineWrapping: false,
|
|
||||||
readOnly: !this.canDefineComputed,
|
|
||||||
extraKeys: {
|
|
||||||
Tab: (cm) => {
|
|
||||||
if (cm.somethingSelected()) {
|
|
||||||
cm.indentSelection('add')
|
|
||||||
} else {
|
|
||||||
cm.replaceSelection(Array(cm.getOption('indentUnit') + 1).join(' '), 'end', '+input')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'Shift-Tab': (cm) => {
|
|
||||||
if (cm.somethingSelected()) {
|
|
||||||
cm.indentSelection('subtract')
|
|
||||||
} else {
|
|
||||||
const cursor = cm.getCursor()
|
|
||||||
cm.setCursor({ line: cursor.line, ch: cursor.ch - 4 })
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -103,6 +76,9 @@ export default {
|
||||||
this.compute_script = compute_script || 'def computed(): \n return'
|
this.compute_script = compute_script || 'def computed(): \n return'
|
||||||
if (compute_script) {
|
if (compute_script) {
|
||||||
this.activeKey = 'script'
|
this.activeKey = 'script'
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.codemirror.initCodeMirror(this.compute_script)
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
this.activeKey = 'expr'
|
this.activeKey = 'expr'
|
||||||
}
|
}
|
||||||
|
@ -122,6 +98,15 @@ export default {
|
||||||
},
|
},
|
||||||
showAllPropDrawer() {
|
showAllPropDrawer() {
|
||||||
this.$refs.allAttrDrawer.open()
|
this.$refs.allAttrDrawer.open()
|
||||||
|
},
|
||||||
|
|
||||||
|
handleTabsChange(activeKey) {
|
||||||
|
console.log('handleTabsChange', activeKey)
|
||||||
|
if (activeKey === 'script') {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.codemirror.initCodeMirror(this.compute_script)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
<a-tabs v-model="activeKey">
|
<a-tabs v-model="activeKey">
|
||||||
<a-tab-pane key="1" :tab="$t('cmdb.ciType.addAttribute')">
|
<a-tab-pane key="1" :tab="$t('cmdb.ciType.addAttribute')">
|
||||||
<div :style="{ overflow: 'auto', maxHeight: '480px' }">
|
<div :style="{ overflow: 'auto', maxHeight: '480px' }">
|
||||||
<create-new-attribute ref="createNewAttribute" :hasFooter="false" @done="handleAddNewAttr" />
|
<create-new-attribute ref="createNewAttribute" :hasFooter="false" :CITypeId="CITypeId" @done="handleAddNewAttr" />
|
||||||
</div>
|
</div>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane key="2" :tab="$t('cmdb.ciType.existedAttributes')" force-render>
|
<a-tab-pane key="2" :tab="$t('cmdb.ciType.existedAttributes')" force-render>
|
||||||
|
|
|
@ -61,12 +61,12 @@
|
||||||
<a-tab-pane key="choice_other" :disabled="disabled">
|
<a-tab-pane key="choice_other" :disabled="disabled">
|
||||||
<span style="font-size:12px;" slot="tab">{{ $t('cmdb.ciType.choiceOther') }}</span>
|
<span style="font-size:12px;" slot="tab">{{ $t('cmdb.ciType.choiceOther') }}</span>
|
||||||
<a-row :gutter="[24, 24]">
|
<a-row :gutter="[24, 24]">
|
||||||
<a-col :span="12">
|
<a-col :span="24">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:style="{ lineHeight: '24px', marginBottom: '5px' }"
|
:style="{ lineHeight: '24px', marginBottom: '5px' }"
|
||||||
:label="$t('cmdb.ciType.ciType')"
|
:label="$t('cmdb.ciType.ciType')"
|
||||||
:label-col="{ span: 4 }"
|
:label-col="{ span: 3 }"
|
||||||
:wrapper-col="{ span: 20 }"
|
:wrapper-col="{ span: 12 }"
|
||||||
>
|
>
|
||||||
<treeselect
|
<treeselect
|
||||||
:disable-branch-nodes="true"
|
:disable-branch-nodes="true"
|
||||||
|
@ -117,12 +117,12 @@
|
||||||
</treeselect>
|
</treeselect>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="12" v-if="choice_other.type_ids && choice_other.type_ids.length">
|
<a-col :span="24" v-if="choice_other.type_ids && choice_other.type_ids.length">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:style="{ marginBottom: '5px' }"
|
:style="{ marginBottom: '5px' }"
|
||||||
:label="$t('cmdb.ciType.attributes')"
|
:label="$t('cmdb.ciType.attributes')"
|
||||||
:label-col="{ span: 4 }"
|
:label-col="{ span: 3 }"
|
||||||
:wrapper-col="{ span: 20 }"
|
:wrapper-col="{ span: 12 }"
|
||||||
>
|
>
|
||||||
<treeselect
|
<treeselect
|
||||||
:disable-branch-nodes="true"
|
:disable-branch-nodes="true"
|
||||||
|
@ -162,15 +162,17 @@
|
||||||
:style="{ marginBottom: '5px' }"
|
:style="{ marginBottom: '5px' }"
|
||||||
class="pre-value-filter"
|
class="pre-value-filter"
|
||||||
:label="$t('cmdb.ciType.filter')"
|
:label="$t('cmdb.ciType.filter')"
|
||||||
:label-col="{ span: 2 }"
|
:label-col="{ span: 3 }"
|
||||||
:wrapper-col="{ span: 22 }"
|
:wrapper-col="{ span: 19 }"
|
||||||
>
|
>
|
||||||
<FilterComp
|
<AttrFilter
|
||||||
ref="filterComp"
|
ref="attrFilter"
|
||||||
:isDropdown="false"
|
:isDropdown="false"
|
||||||
:canSearchPreferenceAttrList="typeAttrs"
|
:canSearchPreferenceAttrList="typeAttrs"
|
||||||
@setExpFromFilter="setExpFromFilter"
|
:CITypeId="CITypeId"
|
||||||
:expression="filterExp ? `q=${filterExp}` : ''"
|
:expression="filterExp ? `q=${filterExp}` : ''"
|
||||||
|
:curModelAttrList="curModelAttrList"
|
||||||
|
@setExpFromFilter="setExpFromFilter"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
@ -178,6 +180,42 @@
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane key="script" :disabled="disabled || !canDefineScript">
|
<a-tab-pane key="script" :disabled="disabled || !canDefineScript">
|
||||||
<span style="font-size:12px;" slot="tab">{{ $t('cmdb.ciType.code') }}</span>
|
<span style="font-size:12px;" slot="tab">{{ $t('cmdb.ciType.code') }}</span>
|
||||||
|
<a-form-item
|
||||||
|
:style="{ marginBottom: '5px' }"
|
||||||
|
:label="$t('cmdb.ciType.cascadeAttr')"
|
||||||
|
:label-col="{ span: 3 }"
|
||||||
|
:wrapper-col="{ span: 19 }"
|
||||||
|
:extra="scriptCodeExtraText"
|
||||||
|
labelAlign="left"
|
||||||
|
>
|
||||||
|
<a-select
|
||||||
|
mode="multiple"
|
||||||
|
style="width: 100%"
|
||||||
|
placeholder="Please select"
|
||||||
|
optionFilterProp="title"
|
||||||
|
v-model="cascade_attributes"
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
v-for="attr in curModelAttrList"
|
||||||
|
:key="attr.id"
|
||||||
|
:title="attr.name"
|
||||||
|
|
||||||
|
>
|
||||||
|
{{ attr.name }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<div class="script-tip">
|
||||||
|
<div>1. {{ $t('cmdb.ciType.computedAttrTip1') }}</div>
|
||||||
|
<div>2. {{ $t('cmdb.ciType.computedAttrTip2') }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-button size="small" @click="showAllPropDrawer">
|
||||||
|
{{ $t('cmdb.ciType.viewAllAttr') }}
|
||||||
|
</a-button>
|
||||||
|
<AllAttrDrawer ref="allAttrDrawer" />
|
||||||
|
|
||||||
<CustomCodeMirror
|
<CustomCodeMirror
|
||||||
codeMirrorId="cmdb-pre-value"
|
codeMirrorId="cmdb-pre-value"
|
||||||
ref="codemirror"
|
ref="codemirror"
|
||||||
|
@ -196,16 +234,18 @@ import { defautValueColor } from '../../utils/const'
|
||||||
import ColorPicker from '../../components/colorPicker/index.vue'
|
import ColorPicker from '../../components/colorPicker/index.vue'
|
||||||
import Webhook from '../../components/webhook'
|
import Webhook from '../../components/webhook'
|
||||||
import { getCITypeGroups } from '../../api/ciTypeGroup'
|
import { getCITypeGroups } from '../../api/ciTypeGroup'
|
||||||
import { getCITypeCommonAttributesByTypeIds } from '../../api/CITypeAttr'
|
import { getCITypeCommonAttributesByTypeIds, getCITypeAttributesById } from '../../api/CITypeAttr'
|
||||||
import FilterComp from '@/components/CMDBFilterComp'
|
import AttrFilter from './preValueAttr/attrFilter/index.vue'
|
||||||
|
import AllAttrDrawer from './allAttrDrawer.vue'
|
||||||
|
|
||||||
import CustomCodeMirror from '@/components/CustomCodeMirror'
|
import CustomCodeMirror from '@/components/CustomCodeMirror'
|
||||||
import 'codemirror/lib/codemirror.css'
|
import 'codemirror/lib/codemirror.css'
|
||||||
import 'codemirror/theme/monokai.css'
|
import 'codemirror/theme/monokai.css'
|
||||||
require('codemirror/mode/python/python.js')
|
require('codemirror/mode/python/python.js')
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'PreValueArea',
|
name: 'PreValueArea',
|
||||||
components: { draggable, PreValueTag, ColorPicker, Webhook, FilterComp, CustomCodeMirror },
|
components: { draggable, PreValueTag, ColorPicker, Webhook, AttrFilter, CustomCodeMirror, AllAttrDrawer },
|
||||||
props: {
|
props: {
|
||||||
disabled: {
|
disabled: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
@ -215,6 +255,10 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
CITypeId: {
|
||||||
|
type: Number,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -242,6 +286,13 @@ export default {
|
||||||
lineWrapping: true,
|
lineWrapping: true,
|
||||||
readOnly: this.disabled || !this.canDefineScript,
|
readOnly: this.disabled || !this.canDefineScript,
|
||||||
},
|
},
|
||||||
|
curModelAttrList: [], // 当前模型属性
|
||||||
|
cascade_attributes: [] // 级联属性id列表
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
scriptCodeExtraText() {
|
||||||
|
return this.$t('cmdb.ciType.cascadeAttrTip') + (this.isOpenSource ? ` (${this.$t('cmdb.enterpriseVersionTip')})` : '')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -276,8 +327,18 @@ export default {
|
||||||
return { ..._.cloneDeep(item) }
|
return { ..._.cloneDeep(item) }
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
this.getCITypeAttributesById()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
async getCITypeAttributesById() {
|
||||||
|
const res = await getCITypeAttributesById(this.CITypeId)
|
||||||
|
let curModelAttrList = []
|
||||||
|
if (res?.attributes?.length) {
|
||||||
|
curModelAttrList = res.attributes.filter(attr => !attr.is_password)
|
||||||
|
}
|
||||||
|
this.curModelAttrList = curModelAttrList
|
||||||
|
},
|
||||||
|
|
||||||
addNewValue(newValue, newStyle, newIcon) {
|
addNewValue(newValue, newStyle, newIcon) {
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
const idx = this.valueList.findIndex((v) => v[0] === newValue)
|
const idx = this.valueList.findIndex((v) => v[0] === newValue)
|
||||||
|
@ -321,12 +382,13 @@ export default {
|
||||||
choice_web_hook: null,
|
choice_web_hook: null,
|
||||||
choice_other: {
|
choice_other: {
|
||||||
script: this.script,
|
script: this.script,
|
||||||
|
cascade_attributes: this.cascade_attributes,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let choice_other = {}
|
let choice_other = {}
|
||||||
if (this.choice_other.type_ids && this.choice_other.type_ids.length) {
|
if (this.choice_other.type_ids && this.choice_other.type_ids.length) {
|
||||||
this.$refs.filterComp.handleSubmit()
|
this.$refs.attrFilter.handleSubmit()
|
||||||
choice_other = { ...this.choice_other, filter: this.filterExp }
|
choice_other = { ...this.choice_other, filter: this.filterExp }
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
@ -355,9 +417,10 @@ export default {
|
||||||
const { type_ids, attr_id, filter } = choice_other
|
const { type_ids, attr_id, filter } = choice_other
|
||||||
this.choice_other = { type_ids, attr_id }
|
this.choice_other = { type_ids, attr_id }
|
||||||
this.filterExp = filter
|
this.filterExp = filter
|
||||||
|
this.cascade_attributes = choice_other?.cascade_attributes || []
|
||||||
if (type_ids && type_ids.length) {
|
if (type_ids && type_ids.length) {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.$refs.filterComp.visibleChange(true, false)
|
this.$refs.attrFilter.init(true, false)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -390,6 +453,10 @@ export default {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
showAllPropDrawer() {
|
||||||
|
this.$refs.allAttrDrawer.open()
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -408,6 +475,12 @@ export default {
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.script-tip {
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 22px;
|
||||||
|
color: #a5a9bc;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
|
|
@ -0,0 +1,321 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<a-space :style="{ display: 'flex', marginBottom: '10px' }" v-for="(item, index) in ruleList" :key="item.id">
|
||||||
|
<div v-if="ruleList.length > 1" :style="{ width: '60px', height: rowHeight, position: 'relative' }">
|
||||||
|
<treeselect
|
||||||
|
v-if="index !== 0"
|
||||||
|
class="custom-treeselect"
|
||||||
|
:style="{ width: '60px', '--custom-height': rowHeight, position: 'absolute', top: '-24px' }"
|
||||||
|
v-model="item.type"
|
||||||
|
:multiple="false"
|
||||||
|
:clearable="false"
|
||||||
|
searchable
|
||||||
|
:options="ruleTypeList"
|
||||||
|
:normalizer="
|
||||||
|
(node) => {
|
||||||
|
return {
|
||||||
|
id: node.value,
|
||||||
|
label: node.label,
|
||||||
|
children: node.children,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
:disabled="disabled"
|
||||||
|
>
|
||||||
|
</treeselect>
|
||||||
|
</div>
|
||||||
|
<treeselect
|
||||||
|
class="custom-treeselect"
|
||||||
|
:style="{ width: '120px', '--custom-height': rowHeight }"
|
||||||
|
v-model="item.property"
|
||||||
|
:multiple="false"
|
||||||
|
:clearable="false"
|
||||||
|
searchable
|
||||||
|
:options="canSearchPreferenceAttrList"
|
||||||
|
:normalizer="
|
||||||
|
(node) => {
|
||||||
|
return {
|
||||||
|
id: node.name,
|
||||||
|
label: node.alias || node.name,
|
||||||
|
children: node.children,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
appendToBody
|
||||||
|
:zIndex="1050"
|
||||||
|
:disabled="disabled"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="node.id !== '$count'"
|
||||||
|
:title="node.label"
|
||||||
|
slot="option-label"
|
||||||
|
slot-scope="{ node }"
|
||||||
|
class="property-label"
|
||||||
|
>
|
||||||
|
<ValueTypeMapIcon :attr="node.raw" />
|
||||||
|
{{ node.label }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
:title="node.label"
|
||||||
|
slot="option-label"
|
||||||
|
slot-scope="{ node }"
|
||||||
|
class="property-label"
|
||||||
|
:style="{ borderBottom: '1px solid #E4E7ED', marginBottom: '8px' }"
|
||||||
|
>
|
||||||
|
<ValueTypeMapIcon :attr="node.raw" />
|
||||||
|
{{ node.label }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="property-label"
|
||||||
|
slot="value-label"
|
||||||
|
slot-scope="{ node }"
|
||||||
|
>
|
||||||
|
<ValueTypeMapIcon :attr="node.raw" /> {{ node.label }}
|
||||||
|
</div>
|
||||||
|
</treeselect>
|
||||||
|
<treeselect
|
||||||
|
class="custom-treeselect"
|
||||||
|
:style="{ width: '90px', '--custom-height': rowHeight }"
|
||||||
|
v-model="item.exp"
|
||||||
|
:multiple="false"
|
||||||
|
:clearable="false"
|
||||||
|
searchable
|
||||||
|
:options="getExpListByProperty(item.property)"
|
||||||
|
:normalizer="
|
||||||
|
(node) => {
|
||||||
|
return {
|
||||||
|
id: node.value,
|
||||||
|
label: node.label,
|
||||||
|
children: node.children,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
@select="(value) => handleChangeExp(value, item, index)"
|
||||||
|
appendToBody
|
||||||
|
:zIndex="1050"
|
||||||
|
:disabled="disabled"
|
||||||
|
>
|
||||||
|
</treeselect>
|
||||||
|
<ValueControls
|
||||||
|
:rule="ruleList[index]"
|
||||||
|
:attrList="canSearchPreferenceAttrList"
|
||||||
|
:disabled="disabled"
|
||||||
|
:curModelAttrList="curModelAttrList"
|
||||||
|
:rowHeight="rowHeight"
|
||||||
|
@change="(value) => handleChangeValue(value, index)"
|
||||||
|
/>
|
||||||
|
<template v-if="!disabled">
|
||||||
|
<a-tooltip :title="$t('copy')">
|
||||||
|
<a class="operation" @click="handleCopyRule(item)"><ops-icon type="veops-copy"/></a>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-tooltip :title="$t('delete')">
|
||||||
|
<a class="operation" @click="handleDeleteRule(item)"><a-icon type="minus-circle"/></a>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-tooltip :title="$t('cmdbFilterComp.addHere')">
|
||||||
|
<a class="operation" @click="handleAddRuleAt(item)"><a-icon type="plus-circle"/></a>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
</a-space>
|
||||||
|
<div class="table-filter-add" v-if="!disabled && ruleList.length === 0">
|
||||||
|
<a @click="handleAddRule">+ {{ $t('new') }}</a>
|
||||||
|
</div>
|
||||||
|
<div class="attr-filter-tip">{{ $t('cmdb.ciType.attrFilterTip') }}{{ isOpenSource ? ` (${$t('cmdb.enterpriseVersionTip')})` : '' }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import _ from 'lodash'
|
||||||
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
import { ruleTypeList, expList, advancedExpList, compareTypeList } from '../constants.js'
|
||||||
|
import ValueTypeMapIcon from '@/components/CMDBValueTypeMapIcon'
|
||||||
|
import ValueControls from './valueControls.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Expression',
|
||||||
|
components: {
|
||||||
|
ValueTypeMapIcon,
|
||||||
|
ValueControls
|
||||||
|
},
|
||||||
|
model: {
|
||||||
|
prop: 'value',
|
||||||
|
event: 'change',
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
canSearchPreferenceAttrList: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
curModelAttrList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
compareTypeList,
|
||||||
|
rowHeight: '36px'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
ruleList: {
|
||||||
|
get() {
|
||||||
|
return this.value
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$emit('change', val)
|
||||||
|
return val
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ruleTypeList() {
|
||||||
|
return ruleTypeList()
|
||||||
|
},
|
||||||
|
expList() {
|
||||||
|
return expList()
|
||||||
|
},
|
||||||
|
advancedExpList() {
|
||||||
|
return advancedExpList()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getExpListByProperty(property) {
|
||||||
|
if (property === '$count') {
|
||||||
|
return [
|
||||||
|
{ value: 'is', label: this.$t('cmdbFilterComp.is') },
|
||||||
|
{ value: '~is', label: this.$t('cmdbFilterComp.~is') },
|
||||||
|
{ value: 'compare', label: this.$t('cmdbFilterComp.compare') }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
if (property) {
|
||||||
|
const _find = this.canSearchPreferenceAttrList.find((item) => item.name === property)
|
||||||
|
if (_find && ['0', '1', '3', '4', '5'].includes(_find.value_type)) {
|
||||||
|
return [
|
||||||
|
{ value: 'is', label: this.$t('cmdbFilterComp.is') },
|
||||||
|
{ value: '~is', label: this.$t('cmdbFilterComp.~is') },
|
||||||
|
{ value: '~value', label: this.$t('cmdbFilterComp.~value') }, // 为空的定义有点绕
|
||||||
|
{ value: 'value', label: this.$t('cmdbFilterComp.value') },
|
||||||
|
...this.advancedExpList
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [...this.expList, ...this.advancedExpList]
|
||||||
|
},
|
||||||
|
isChoiceByProperty(property) {
|
||||||
|
const _find = this.canSearchPreferenceAttrList.find((item) => item.name === property)
|
||||||
|
if (_find) {
|
||||||
|
return _find.is_choice
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
handleAddRule() {
|
||||||
|
this.ruleList.push({
|
||||||
|
id: uuidv4(),
|
||||||
|
type: 'and',
|
||||||
|
property: this.canSearchPreferenceAttrList[0]?.name,
|
||||||
|
exp: 'is',
|
||||||
|
value: null,
|
||||||
|
})
|
||||||
|
this.$emit('change', this.ruleList)
|
||||||
|
},
|
||||||
|
handleCopyRule(item) {
|
||||||
|
this.ruleList.push({ ...item, id: uuidv4() })
|
||||||
|
this.$emit('change', this.ruleList)
|
||||||
|
},
|
||||||
|
handleDeleteRule(item) {
|
||||||
|
const idx = this.ruleList.findIndex((r) => r.id === item.id)
|
||||||
|
if (idx > -1) {
|
||||||
|
this.ruleList.splice(idx, 1)
|
||||||
|
}
|
||||||
|
this.$emit('change', this.ruleList)
|
||||||
|
},
|
||||||
|
handleAddRuleAt(item) {
|
||||||
|
const idx = this.ruleList.findIndex((r) => r.id === item.id)
|
||||||
|
if (idx > -1) {
|
||||||
|
this.ruleList.splice(idx + 1, 0, {
|
||||||
|
id: uuidv4(),
|
||||||
|
type: 'and',
|
||||||
|
property: this.canSearchPreferenceAttrList[0]?.name,
|
||||||
|
exp: 'is',
|
||||||
|
value: null,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.$emit('change', this.ruleList)
|
||||||
|
},
|
||||||
|
getChoiceValueByProperty(property) {
|
||||||
|
const _find = this.canSearchPreferenceAttrList.find((item) => item.name === property)
|
||||||
|
if (_find) {
|
||||||
|
return _find.choice_value
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
},
|
||||||
|
handleChangeExp({ value }, item, index) {
|
||||||
|
const _ruleList = _.cloneDeep(this.ruleList)
|
||||||
|
if (value === 'range') {
|
||||||
|
_ruleList[index] = {
|
||||||
|
..._ruleList[index],
|
||||||
|
min: '',
|
||||||
|
max: '',
|
||||||
|
exp: value,
|
||||||
|
}
|
||||||
|
} else if (value === 'compare') {
|
||||||
|
_ruleList[index] = {
|
||||||
|
..._ruleList[index],
|
||||||
|
compareType: '1',
|
||||||
|
exp: value,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_ruleList[index] = {
|
||||||
|
..._ruleList[index],
|
||||||
|
exp: value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.ruleList = _ruleList
|
||||||
|
this.$emit('change', this.ruleList)
|
||||||
|
},
|
||||||
|
|
||||||
|
handleChangeValue(value, index) {
|
||||||
|
const _ruleList = _.cloneDeep(this.ruleList)
|
||||||
|
_ruleList[index] = value
|
||||||
|
this.$emit('change', _ruleList)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.input-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 150px;
|
||||||
|
|
||||||
|
&-range-icon {
|
||||||
|
margin: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.property-label {
|
||||||
|
width: 100%;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden
|
||||||
|
}
|
||||||
|
|
||||||
|
.attr-filter-tip {
|
||||||
|
color: #86909C;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,211 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<Expression
|
||||||
|
v-model="ruleList"
|
||||||
|
:canSearchPreferenceAttrList="canSearchPreferenceAttrList.filter((attr) => !attr.is_password)"
|
||||||
|
:disabled="false"
|
||||||
|
:curModelAttrList="curModelAttrList"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
import { compareTypeList } from '../constants.js'
|
||||||
|
|
||||||
|
import Expression from './expression.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'AttrFilter',
|
||||||
|
components: {
|
||||||
|
Expression
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
canSearchPreferenceAttrList: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
expression: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
regQ: {
|
||||||
|
type: String,
|
||||||
|
default: '(?<=q=).+(?=&)|(?<=q=).+$',
|
||||||
|
},
|
||||||
|
CITypeId: {
|
||||||
|
type: Number,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
curModelAttrList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
compareTypeList,
|
||||||
|
visible: false,
|
||||||
|
ruleList: [],
|
||||||
|
filterExp: '',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
init(open, isInitOne = true) {
|
||||||
|
// isInitOne 初始化exp为空时,ruleList是否默认给一条
|
||||||
|
// const regQ = /(?<=q=).+(?=&)|(?<=q=).+$/g
|
||||||
|
const exp = this.expression.match(new RegExp(this.regQ, 'g'))
|
||||||
|
? this.expression.match(new RegExp(this.regQ, 'g'))[0]
|
||||||
|
: null
|
||||||
|
if (open && exp) {
|
||||||
|
const expArray = exp.split(',').map((item) => {
|
||||||
|
let has_not = ''
|
||||||
|
const key = item.split(':')[0]
|
||||||
|
const val = item
|
||||||
|
.split(':')
|
||||||
|
.slice(1)
|
||||||
|
.join(':')
|
||||||
|
let type, property, exp, value, min, max, compareType
|
||||||
|
if (key.includes('-')) {
|
||||||
|
type = 'or'
|
||||||
|
if (key.includes('~')) {
|
||||||
|
property = key.substring(2)
|
||||||
|
has_not = '~'
|
||||||
|
} else {
|
||||||
|
property = key.substring(1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
type = 'and'
|
||||||
|
if (key.includes('~')) {
|
||||||
|
property = key.substring(1)
|
||||||
|
has_not = '~'
|
||||||
|
} else {
|
||||||
|
property = key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const in_reg = /(?<=\().+(?=\))/g
|
||||||
|
const range_reg = /(?<=\[).+(?=\])/g
|
||||||
|
const compare_reg = /(?<=>=|<=|>(?!=)|<(?!=)).+/
|
||||||
|
if (val === '*') {
|
||||||
|
exp = has_not + 'value'
|
||||||
|
value = ''
|
||||||
|
} else if (in_reg.test(val)) {
|
||||||
|
exp = has_not + 'in'
|
||||||
|
value = val.match(in_reg)[0]
|
||||||
|
} else if (range_reg.test(val)) {
|
||||||
|
exp = has_not + 'range'
|
||||||
|
value = val.match(range_reg)[0]
|
||||||
|
min = value.split('_TO_')[0]
|
||||||
|
max = value.split('_TO_')[1]
|
||||||
|
} else if (compare_reg.test(val)) {
|
||||||
|
exp = has_not + 'compare'
|
||||||
|
value = val.match(compare_reg)[0]
|
||||||
|
const _compareType = val.substring(0, val.match(compare_reg)['index'])
|
||||||
|
const idx = compareTypeList.findIndex((item) => item.label === _compareType)
|
||||||
|
compareType = compareTypeList[idx].value
|
||||||
|
} else if (!val.includes('*')) {
|
||||||
|
exp = has_not + 'is'
|
||||||
|
value = val
|
||||||
|
} else {
|
||||||
|
const resList = [
|
||||||
|
['contain', /(?<=\*).*(?=\*)/g],
|
||||||
|
['end_with', /(?<=\*).+/g],
|
||||||
|
['start_with', /.+(?=\*)/g],
|
||||||
|
]
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
const reg = resList[i]
|
||||||
|
if (reg[1].test(val)) {
|
||||||
|
exp = has_not + reg[0]
|
||||||
|
value = val.match(reg[1])[0]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
id: uuidv4(),
|
||||||
|
type,
|
||||||
|
property,
|
||||||
|
exp,
|
||||||
|
value,
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
compareType,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.ruleList = [...expArray]
|
||||||
|
} else if (open) {
|
||||||
|
const _canSearchPreferenceAttrList = this.canSearchPreferenceAttrList.filter((attr) => !attr.is_password)
|
||||||
|
this.ruleList = isInitOne
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
id: uuidv4(),
|
||||||
|
type: 'and',
|
||||||
|
property:
|
||||||
|
_canSearchPreferenceAttrList && _canSearchPreferenceAttrList.length
|
||||||
|
? _canSearchPreferenceAttrList[0].name
|
||||||
|
: undefined,
|
||||||
|
exp: 'is',
|
||||||
|
value: null,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSubmit() {
|
||||||
|
if (this.ruleList && this.ruleList.length) {
|
||||||
|
this.ruleList[0].type = 'and' // 增删后,以防万一第一个不是and
|
||||||
|
this.filterExp = ''
|
||||||
|
const expList = this.ruleList.map((rule) => {
|
||||||
|
let singleRuleExp = ''
|
||||||
|
let _exp = rule.exp
|
||||||
|
if (rule.type === 'or') {
|
||||||
|
singleRuleExp += '-'
|
||||||
|
}
|
||||||
|
if (rule.exp.includes('~')) {
|
||||||
|
singleRuleExp += '~'
|
||||||
|
_exp = rule.exp.split('~')[1]
|
||||||
|
}
|
||||||
|
singleRuleExp += `${rule.property}:`
|
||||||
|
if (_exp === 'is') {
|
||||||
|
singleRuleExp += `${rule.value ?? ''}`
|
||||||
|
}
|
||||||
|
if (_exp === 'contain') {
|
||||||
|
singleRuleExp += `*${rule.value ?? ''}*`
|
||||||
|
}
|
||||||
|
if (_exp === 'start_with') {
|
||||||
|
singleRuleExp += `${rule.value ?? ''}*`
|
||||||
|
}
|
||||||
|
if (_exp === 'end_with') {
|
||||||
|
singleRuleExp += `*${rule.value ?? ''}`
|
||||||
|
}
|
||||||
|
if (_exp === 'value') {
|
||||||
|
singleRuleExp += `*`
|
||||||
|
}
|
||||||
|
if (_exp === 'in') {
|
||||||
|
singleRuleExp += `(${rule.value ?? ''})`
|
||||||
|
}
|
||||||
|
if (_exp === 'range') {
|
||||||
|
singleRuleExp += `[${rule.min}_TO_${rule.max}]`
|
||||||
|
}
|
||||||
|
if (_exp === 'compare') {
|
||||||
|
const idx = compareTypeList.findIndex((item) => item.value === rule.compareType)
|
||||||
|
singleRuleExp += `${compareTypeList[idx].label}${rule.value ?? ''}`
|
||||||
|
}
|
||||||
|
return singleRuleExp
|
||||||
|
})
|
||||||
|
this.filterExp = expList.join(',')
|
||||||
|
this.$emit('setExpFromFilter', this.filterExp)
|
||||||
|
} else {
|
||||||
|
this.$emit('setExpFromFilter', '')
|
||||||
|
}
|
||||||
|
this.visible = false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
</style>
|
|
@ -0,0 +1,273 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="control-group" v-if="controlType === 'choice'" >
|
||||||
|
<div
|
||||||
|
class="choice-group"
|
||||||
|
@click="handleControlType('input')"
|
||||||
|
>
|
||||||
|
<a-icon class="choice-group-icon" type="caret-down" />
|
||||||
|
</div>
|
||||||
|
<treeselect
|
||||||
|
class="custom-treeselect input-group"
|
||||||
|
:style="{ '--custom-height': rowHeight }"
|
||||||
|
:value="choiceValue"
|
||||||
|
@input="(value) => handleChange('value', value)"
|
||||||
|
:multiple="false"
|
||||||
|
:clearable="false"
|
||||||
|
searchable
|
||||||
|
:options="curModelAttrList"
|
||||||
|
:placeholder="$t('placeholder2')"
|
||||||
|
:normalizer="
|
||||||
|
(node) => {
|
||||||
|
return {
|
||||||
|
id: node.name,
|
||||||
|
label: node.name,
|
||||||
|
children: node.children,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
appendToBody
|
||||||
|
:zIndex="1050"
|
||||||
|
:disabled="disabled"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
:title="node.label"
|
||||||
|
slot="option-label"
|
||||||
|
slot-scope="{ node }"
|
||||||
|
:style="{ width: '100%', whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' }"
|
||||||
|
>
|
||||||
|
{{ node.label }}
|
||||||
|
</div>
|
||||||
|
</treeselect>
|
||||||
|
</div>
|
||||||
|
<div class="control-group" v-else>
|
||||||
|
<div
|
||||||
|
class="text-group"
|
||||||
|
@click="handleControlType('choice')"
|
||||||
|
>
|
||||||
|
<ops-icon class="text-group-icon" type="veops-text" />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="input-group"
|
||||||
|
v-if="isChoiceByProperty(rule.property) && (rule.exp === 'is' || rule.exp === '~is')"
|
||||||
|
>
|
||||||
|
<treeselect
|
||||||
|
class="custom-treeselect"
|
||||||
|
:style="{ '--custom-height': rowHeight }"
|
||||||
|
:value="rule.value"
|
||||||
|
@input="(value) => handleChange('value', value)"
|
||||||
|
:multiple="false"
|
||||||
|
:clearable="false"
|
||||||
|
searchable
|
||||||
|
:options="getChoiceValueByProperty(rule.property)"
|
||||||
|
:placeholder="$t('placeholder2')"
|
||||||
|
:normalizer="
|
||||||
|
(node) => {
|
||||||
|
return {
|
||||||
|
id: node[0],
|
||||||
|
label: node[0],
|
||||||
|
children: node.children,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
appendToBody
|
||||||
|
:zIndex="1050"
|
||||||
|
:disabled="disabled"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
:title="node.label"
|
||||||
|
slot="option-label"
|
||||||
|
slot-scope="{ node }"
|
||||||
|
:style="{ width: '100%', whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' }"
|
||||||
|
>
|
||||||
|
{{ node.label }}
|
||||||
|
</div>
|
||||||
|
</treeselect>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
compact
|
||||||
|
v-else-if="rule.exp === 'range' || rule.exp === '~range'"
|
||||||
|
class="input-group"
|
||||||
|
>
|
||||||
|
<a-input
|
||||||
|
class="ops-input"
|
||||||
|
:placeholder="$t('min')"
|
||||||
|
:disabled="disabled"
|
||||||
|
:value="rule.min"
|
||||||
|
@change="(e) => handleChange('min', e.target.value)"
|
||||||
|
/>
|
||||||
|
<span class="input-group-range-icon">~</span>
|
||||||
|
<a-input
|
||||||
|
class="ops-input"
|
||||||
|
v-model="rule.max"
|
||||||
|
:placeholder="$t('max')"
|
||||||
|
:disabled="disabled"
|
||||||
|
:value="rule.max"
|
||||||
|
@change="(e) => handleChange('max', e.target.value)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="input-group" compact v-else-if="rule.exp === 'compare'">
|
||||||
|
<treeselect
|
||||||
|
class="custom-treeselect"
|
||||||
|
:style="{ width: '70px', '--custom-height': rowHeight, 'flex-shrink': 0 }"
|
||||||
|
:value="rule.compareType"
|
||||||
|
@input="(value) => handleChange('compareType', value)"
|
||||||
|
:multiple="false"
|
||||||
|
:clearable="false"
|
||||||
|
searchable
|
||||||
|
:options="compareTypeList"
|
||||||
|
:normalizer="
|
||||||
|
(node) => {
|
||||||
|
return {
|
||||||
|
id: node.value,
|
||||||
|
label: node.label,
|
||||||
|
children: node.children,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
appendToBody
|
||||||
|
:zIndex="1050"
|
||||||
|
:disabled="disabled"
|
||||||
|
>
|
||||||
|
</treeselect>
|
||||||
|
<a-input :value="rule.value" @change="(e) => handleChange('value', e.target.value)" class="ops-input"/>
|
||||||
|
</div>
|
||||||
|
<div class="input-group" v-else-if="rule.exp !== 'value' && rule.exp !== '~value'">
|
||||||
|
<a-input
|
||||||
|
:value="rule.value"
|
||||||
|
@change="(e) => handleChange('value', e.target.value)"
|
||||||
|
:placeholder="rule.exp === 'in' || rule.exp === '~in' ? $t('cmdbFilterComp.split', { separator: ';' }) : ''"
|
||||||
|
class="ops-input"
|
||||||
|
:disabled="disabled"
|
||||||
|
></a-input>
|
||||||
|
</div>
|
||||||
|
<div v-else :style="{ width: '136px' }"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { compareTypeList } from '../constants.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ValueControls',
|
||||||
|
props: {
|
||||||
|
rule: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
attrList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
// 当前模型属性
|
||||||
|
curModelAttrList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
// 行高
|
||||||
|
rowHeight: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
compareTypeList,
|
||||||
|
controlType: 'input',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
choiceValue() {
|
||||||
|
const regex = /\{\{([^}]+)\}\}/g
|
||||||
|
const val = regex.exec(this?.rule?.value || '')
|
||||||
|
return val ? val?.[1]?.trim() || '' : this?.value?.value || ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
isChoiceByProperty(property) {
|
||||||
|
const _find = this.attrList.find((item) => item.name === property)
|
||||||
|
if (_find) {
|
||||||
|
return _find.is_choice
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
getChoiceValueByProperty(property) {
|
||||||
|
const _find = this.attrList.find((item) => item.name === property)
|
||||||
|
if (_find) {
|
||||||
|
return _find.choice_value
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
},
|
||||||
|
handleControlType(type) {
|
||||||
|
this.controlType = type
|
||||||
|
},
|
||||||
|
handleChange(key, value) {
|
||||||
|
if (this.controlType === 'choice' && key === 'value') {
|
||||||
|
value = `{{ ${value} }}`
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$emit('change', {
|
||||||
|
...this.rule,
|
||||||
|
[key]: value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.control-group {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 136px;
|
||||||
|
|
||||||
|
&-range-icon {
|
||||||
|
margin: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.choice-group {
|
||||||
|
width: 14px;
|
||||||
|
height: 36px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background-color: #00B3CC;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&-icon {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-group {
|
||||||
|
width: 14px;
|
||||||
|
height: 36px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background-color: #2F54EB;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&-icon {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,41 @@
|
||||||
|
import i18n from '@/lang'
|
||||||
|
|
||||||
|
export const ruleTypeList = () => {
|
||||||
|
return [
|
||||||
|
{ value: 'and', label: i18n.t('cmdbFilterComp.and') },
|
||||||
|
{ value: 'or', label: i18n.t('cmdbFilterComp.or') },
|
||||||
|
// { value: 'not', label: '非' },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const expList = () => {
|
||||||
|
return [
|
||||||
|
{ value: 'is', label: i18n.t('cmdbFilterComp.is') },
|
||||||
|
{ value: '~is', label: i18n.t('cmdbFilterComp.~is') },
|
||||||
|
{ value: 'contain', label: i18n.t('cmdbFilterComp.contain') },
|
||||||
|
{ value: '~contain', label: i18n.t('cmdbFilterComp.~contain') },
|
||||||
|
{ value: 'start_with', label: i18n.t('cmdbFilterComp.start_with') },
|
||||||
|
{ value: '~start_with', label: i18n.t('cmdbFilterComp.~start_with') },
|
||||||
|
{ value: 'end_with', label: i18n.t('cmdbFilterComp.end_with') },
|
||||||
|
{ value: '~end_with', label: i18n.t('cmdbFilterComp.~end_with') },
|
||||||
|
{ value: '~value', label: i18n.t('cmdbFilterComp.~value') },
|
||||||
|
{ value: 'value', label: i18n.t('cmdbFilterComp.value') },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const advancedExpList = () => {
|
||||||
|
return [
|
||||||
|
{ value: 'in', label: i18n.t('cmdbFilterComp.in') },
|
||||||
|
{ value: '~in', label: i18n.t('cmdbFilterComp.~in') },
|
||||||
|
{ value: 'range', label: i18n.t('cmdbFilterComp.range') },
|
||||||
|
{ value: '~range', label: i18n.t('cmdbFilterComp.~range') },
|
||||||
|
{ value: 'compare', label: i18n.t('cmdbFilterComp.compare') },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const compareTypeList = [
|
||||||
|
{ value: '1', label: '>' },
|
||||||
|
{ value: '2', label: '>=' },
|
||||||
|
{ value: '3', label: '<' },
|
||||||
|
{ value: '4', label: '<=' },
|
||||||
|
]
|
|
@ -181,12 +181,19 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="cmdb-preference-footor-unsubscribed">
|
<div v-else class="cmdb-preference-footor-unsubscribed">
|
||||||
<span
|
<a
|
||||||
@click="openSubscribeSetting(item)"
|
@click="handleSubscribeCIType(item)"
|
||||||
><ops-icon :style="{ marginRight: '3px' }" type="cmdb-preference-subscribe" />{{
|
class="cmdb-preference-footor-unsubscribed-item"
|
||||||
$t('cmdb.preference.sub')
|
|
||||||
}}</span
|
|
||||||
>
|
>
|
||||||
|
<ops-icon type="cmdb-ci" />{{ $t('cmdb.preference.subCITable') }}
|
||||||
|
</a>
|
||||||
|
<span class="cmdb-preference-footor-unsubscribed-gap"></span>
|
||||||
|
<a
|
||||||
|
@click="openSubscribeSetting(item, '2')"
|
||||||
|
class="cmdb-preference-footor-unsubscribed-item"
|
||||||
|
>
|
||||||
|
<ops-icon type="cmdb-tree" />{{ $t('cmdb.preference.subCITree') }}
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<i></i><i></i><i></i><i></i><i></i>
|
<i></i><i></i><i></i><i></i><i></i>
|
||||||
|
@ -221,6 +228,7 @@ import {
|
||||||
subscribeTreeView,
|
subscribeTreeView,
|
||||||
preferenceCitypeOrder,
|
preferenceCitypeOrder,
|
||||||
} from '@/modules/cmdb/api/preference'
|
} from '@/modules/cmdb/api/preference'
|
||||||
|
import { getCITypeAttributesByName } from '@/modules/cmdb/api/CITypeAttr'
|
||||||
import CollapseTransition from '@/components/CollapseTransition'
|
import CollapseTransition from '@/components/CollapseTransition'
|
||||||
import SubscribeSetting from '../../components/subscribeSetting/subscribeSetting'
|
import SubscribeSetting from '../../components/subscribeSetting/subscribeSetting'
|
||||||
import { getCIAdcStatistics } from '../../api/ci'
|
import { getCIAdcStatistics } from '../../api/ci'
|
||||||
|
@ -381,9 +389,39 @@ export default {
|
||||||
this.getCITypes()
|
this.getCITypes()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async handleSubscribeCIType(ciType) {
|
||||||
|
try {
|
||||||
|
const res = await getCITypeAttributesByName(ciType.id)
|
||||||
|
const attributes = res?.attributes || []
|
||||||
|
const subscribeList = attributes
|
||||||
|
.filter((item) => item?.default_show)
|
||||||
|
.map((item) => {
|
||||||
|
return [item?.id?.toString(), false]
|
||||||
|
})
|
||||||
|
if (subscribeList.length === 0) {
|
||||||
|
const uniqueItem = attributes.find((item) => item?.id === res?.unique_id)
|
||||||
|
if (uniqueItem) {
|
||||||
|
subscribeList.push([uniqueItem?.id?.toString(), false])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await subscribeCIType(
|
||||||
|
ciType.id,
|
||||||
|
subscribeList
|
||||||
|
)
|
||||||
|
this.$message.success(this.$t('cmdb.components.subSuccess'))
|
||||||
|
this.resetRoute()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('handleSubscribeCIType failed', error)
|
||||||
|
this.$message.success(this.$t('cmdb.components.subFailed'))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
openSubscribeSetting(ciType, activeKey = '1') {
|
openSubscribeSetting(ciType, activeKey = '1') {
|
||||||
this.$refs.subscribeSetting.open({ ...ciType, type_id: ciType.id }, activeKey)
|
this.$refs.subscribeSetting.open({ ...ciType, type_id: ciType.id }, activeKey)
|
||||||
},
|
},
|
||||||
|
|
||||||
changeGroupExpand(group) {
|
changeGroupExpand(group) {
|
||||||
const _idx = this.expandKeys.findIndex((expand) => expand === group.id)
|
const _idx = this.expandKeys.findIndex((expand) => expand === group.id)
|
||||||
if (_idx > -1) {
|
if (_idx > -1) {
|
||||||
|
@ -653,11 +691,27 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.cmdb-preference-footor-unsubscribed {
|
.cmdb-preference-footor-unsubscribed {
|
||||||
text-align: center;
|
display: flex;
|
||||||
> span {
|
align-items: center;
|
||||||
color: @primary-color;
|
justify-content: space-between;
|
||||||
cursor: pointer;
|
padding: 0 10px;
|
||||||
|
|
||||||
|
&-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 3px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
color: rgba(0, 0, 0, 0.76);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #1890ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-gap {
|
||||||
|
width: 1px;
|
||||||
|
height: 18px;
|
||||||
|
background-color: #e8e8e8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.cmdb-preference-footor-subscribed {
|
.cmdb-preference-footor-subscribed {
|
||||||
|
|
Loading…
Reference in New Issue