mirror of https://github.com/veops/cmdb.git
feat(ui): update auto discovery
This commit is contained in:
parent
1336a24044
commit
e4c3a4bee1
|
@ -5322,9 +5322,9 @@
|
|||
<pre><code class="language-css"
|
||||
>@font-face {
|
||||
font-family: 'iconfont';
|
||||
src: url('iconfont.woff2?t=1721640768584') format('woff2'),
|
||||
url('iconfont.woff?t=1721640768584') format('woff'),
|
||||
url('iconfont.ttf?t=1721640768584') format('truetype');
|
||||
src: url('iconfont.woff2?t=1721959219377') format('woff2'),
|
||||
url('iconfont.woff?t=1721959219377') format('woff'),
|
||||
url('iconfont.ttf?t=1721959219377') format('truetype');
|
||||
}
|
||||
</code></pre>
|
||||
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 3857903 */
|
||||
src: url('iconfont.woff2?t=1721640768584') format('woff2'),
|
||||
url('iconfont.woff?t=1721640768584') format('woff'),
|
||||
url('iconfont.ttf?t=1721640768584') format('truetype');
|
||||
src: url('iconfont.woff2?t=1721959219377') format('woff2'),
|
||||
url('iconfont.woff?t=1721959219377') format('woff'),
|
||||
url('iconfont.ttf?t=1721959219377') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -905,6 +905,33 @@ export const multicolorIconList = [
|
|||
value: 'caise-application',
|
||||
label: '应用',
|
||||
list: [{
|
||||
value: 'caise-data_center',
|
||||
label: '数据中心'
|
||||
}, {
|
||||
value: 'caise-folder',
|
||||
label: '文件夹'
|
||||
}, {
|
||||
value: 'caise-resource_pool',
|
||||
label: '资源池'
|
||||
}, {
|
||||
value: 'caise-network',
|
||||
label: '网络'
|
||||
}, {
|
||||
value: 'caise-distributed_switch',
|
||||
label: '分布式交换机'
|
||||
}, {
|
||||
value: 'caise-standard_switch',
|
||||
label: '标准式交换机'
|
||||
}, {
|
||||
value: 'caise-host_cluster',
|
||||
label: '主机集群'
|
||||
}, {
|
||||
value: 'caise-storage_cluster',
|
||||
label: '数据存储集群'
|
||||
}, {
|
||||
value: 'caise-data_storage',
|
||||
label: '数据存储'
|
||||
}, {
|
||||
value: 'caise-yilianjie',
|
||||
label: '已连接'
|
||||
}, {
|
||||
|
|
|
@ -21,15 +21,15 @@
|
|||
>
|
||||
*
|
||||
</span>
|
||||
<vxe-select
|
||||
filterable
|
||||
clearable
|
||||
<a-select
|
||||
v-model="row.attr"
|
||||
type="text"
|
||||
:options="ciTypeAttributes"
|
||||
transfer
|
||||
:placeholder="$t('cmdb.ciType.attrMapTableAttrPlaceholder')"
|
||||
></vxe-select>
|
||||
showSearch
|
||||
allowClear
|
||||
:options="ciTypeAttributes"
|
||||
style="width: 100%; height: 28px; line-height: 28px;"
|
||||
class="attr-map-table-left-select"
|
||||
></a-select>
|
||||
</div>
|
||||
</template>
|
||||
</vxe-column>
|
||||
|
@ -49,7 +49,7 @@
|
|||
>
|
||||
<vxe-column field="name" :title="$t('name')"></vxe-column>
|
||||
<vxe-column field="type" :title="$t('type')"></vxe-column>
|
||||
<vxe-column v-if="ruleType !== 'agent'" field="example" :title="$t('cmdb.components.example')">
|
||||
<vxe-column v-if="ruleType !== DISCOVERY_CATEGORY_TYPE.AGENT" field="example" :title="$t('cmdb.components.example')">
|
||||
<template #default="{row}">
|
||||
<span v-if="row.type === 'json'">{{ JSON.stringify(row.example) }}</span>
|
||||
<span v-else>{{ row.example }}</span>
|
||||
|
@ -72,6 +72,8 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { DISCOVERY_CATEGORY_TYPE } from '@/modules/cmdb/views/discovery/constants.js'
|
||||
|
||||
export default {
|
||||
name: 'AttrMapTable',
|
||||
props: {
|
||||
|
@ -93,7 +95,9 @@ export default {
|
|||
}
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
return {
|
||||
DISCOVERY_CATEGORY_TYPE
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getTableData() {
|
||||
|
@ -123,6 +127,18 @@ export default {
|
|||
|
||||
&-left {
|
||||
width: 30%;
|
||||
|
||||
&-select {
|
||||
/deep/ .ant-select-selection {
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
|
||||
.ant-select-selection__rendered {
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-right {
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
<script>
|
||||
import _ from 'lodash'
|
||||
import { getHttpCategories, getHttpAttributes, getSnmpAttributes, getHttpAttrMapping } from '../../api/discovery'
|
||||
import { DISCOVERY_CATEGORY_TYPE } from '@/modules/cmdb/views/discovery/constants.js'
|
||||
import AttrMapTable from '@/modules/cmdb/components/attrMapTable/index.vue'
|
||||
import ADPreviewTable from './adPreviewTable.vue'
|
||||
import HttpADCategory from './httpADCategory.vue'
|
||||
|
@ -101,7 +102,7 @@ export default {
|
|||
}
|
||||
},
|
||||
isCloud() {
|
||||
return ['http', 'private_cloud'].includes(this.ruleType)
|
||||
return [DISCOVERY_CATEGORY_TYPE.HTTP, DISCOVERY_CATEGORY_TYPE.PRIVATE_CLOUD].includes(this.ruleType)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
@ -119,7 +120,7 @@ export default {
|
|||
this.currentCate = ''
|
||||
this.$nextTick(() => {
|
||||
const { ruleType, ruleName } = newVal
|
||||
if (['snmp', 'components'].includes(ruleType) && ruleName) {
|
||||
if ([DISCOVERY_CATEGORY_TYPE.SNMP, DISCOVERY_CATEGORY_TYPE.COMPONENT].includes(ruleType) && ruleName) {
|
||||
getSnmpAttributes(ruleType, ruleName).then((res) => {
|
||||
if (this.isEdit) {
|
||||
this.formatTableData(res)
|
||||
|
|
|
@ -1,53 +1,27 @@
|
|||
<template>
|
||||
<div class="node-setting-wrap">
|
||||
<a-row v-for="(node) in nodes" :key="node.id">
|
||||
<a-col :span="6">
|
||||
<a-form-item :label="$t('cmdb.ciType.nodeSettingIp')">
|
||||
<a-input
|
||||
allowClear
|
||||
v-decorator="[
|
||||
`node_ip_${node.id}`,
|
||||
{
|
||||
rules: [
|
||||
{ required: false, message: $t('cmdb.ciType.nodeSettingIpTip') },
|
||||
{
|
||||
pattern:
|
||||
'^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$',
|
||||
message: $t('cmdb.ciType.nodeSettingIpTip1'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
]"
|
||||
:placeholder="$t('cmdb.ciType.nodeSettingIpTip')"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="6">
|
||||
<a-form-item :label="$t('cmdb.ciType.nodeSettingCommunity')">
|
||||
<a-input
|
||||
allowClear
|
||||
v-decorator="[
|
||||
`node_community_${node.id}`,
|
||||
{
|
||||
rules: [{ required: false, message: $t('cmdb.ciType.nodeSettingCommunityTip') }],
|
||||
},
|
||||
]"
|
||||
:placeholder="$t('cmdb.ciType.nodeSettingCommunityTip')"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="5">
|
||||
<a-form-item :label="$t('cmdb.ciType.nodeSettingVersion')">
|
||||
<ops-table
|
||||
:data="nodes"
|
||||
size="mini"
|
||||
show-header-overflow
|
||||
:row-config="{ height: 42 }"
|
||||
border
|
||||
:min-height="78"
|
||||
>
|
||||
<vxe-column width="170" :title="$t('cmdb.ciType.nodeSettingIp')">
|
||||
<template #default="{ row }">
|
||||
<a-input v-model="row.ip"></a-input>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column width="170" :title="$t('cmdb.ciType.nodeSettingCommunity')">
|
||||
<template #default="{ row }">
|
||||
<a-input v-model="row.community"></a-input>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column width="170" :title="$t('cmdb.ciType.nodeSettingVersion')">
|
||||
<template #default="{ row }">
|
||||
<a-select
|
||||
v-decorator="[
|
||||
`node_version_${node.id}`,
|
||||
{
|
||||
rules: [{ required: false, message: $t('cmdb.ciType.nodeSettingVersionTip') }],
|
||||
},
|
||||
]"
|
||||
v-model="row.version"
|
||||
:placeholder="$t('cmdb.ciType.nodeSettingVersionTip')"
|
||||
allowClear
|
||||
class="node-setting-select"
|
||||
|
@ -58,26 +32,25 @@
|
|||
<a-select-option value="2c">
|
||||
v2c
|
||||
</a-select-option>
|
||||
<a-select-option value="3">
|
||||
v3
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="3">
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column wdith="170">
|
||||
<template #default="{ row }">
|
||||
<div class="action">
|
||||
<a @click="() => copyNode(node.id)">
|
||||
<a @click="() => copyNode(row.id)">
|
||||
<a-icon type="copy" />
|
||||
</a>
|
||||
<a @click="() => removeNode(node.id, 1)">
|
||||
<a @click="() => removeNode(row.id, 1)">
|
||||
<a-icon type="minus-circle" />
|
||||
</a>
|
||||
<a @click="addNode">
|
||||
<a-icon type="plus-circle" />
|
||||
</a>
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
</vxe-column>
|
||||
</ops-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -110,17 +83,10 @@ export default {
|
|||
const newNode = {
|
||||
id: uuidv4(),
|
||||
ip: '',
|
||||
community: '',
|
||||
community: 'public',
|
||||
version: '',
|
||||
}
|
||||
this.nodes.push(newNode)
|
||||
this.$nextTick(() => {
|
||||
this.form.setFieldsValue({
|
||||
[`node_ip_${newNode.id}`]: newNode.ip,
|
||||
[`node_community_${newNode.id}`]: newNode.community,
|
||||
[`node_version_${newNode.id}`]: newNode.version,
|
||||
})
|
||||
})
|
||||
},
|
||||
removeNode(removeId, minLength) {
|
||||
if (this.nodes.length <= minLength) {
|
||||
|
@ -133,45 +99,20 @@ export default {
|
|||
}
|
||||
},
|
||||
copyNode(id) {
|
||||
const copyNode = this.nodes.find((item) => item.id === id)
|
||||
if (copyNode) {
|
||||
const newNode = {
|
||||
...copyNode,
|
||||
id: uuidv4(),
|
||||
ip: this.form.getFieldValue(`node_ip_${id}`),
|
||||
community: this.form.getFieldValue(`node_community_${id}`),
|
||||
version: this.form.getFieldValue(`node_version_${id}`),
|
||||
}
|
||||
this.nodes.push(newNode)
|
||||
this.$nextTick(() => {
|
||||
this.form.setFieldsValue({
|
||||
[`node_ip_${newNode.id}`]: newNode.ip,
|
||||
[`node_community_${newNode.id}`]: newNode.community,
|
||||
[`node_version_${newNode.id}`]: newNode.version,
|
||||
})
|
||||
})
|
||||
},
|
||||
getInfoValuesFromForm(values) {
|
||||
return this.nodes.map((item) => {
|
||||
return {
|
||||
id: item.id,
|
||||
ip: values[`node_ip_${item.id}`],
|
||||
community: values[`node_community_${item.id}`],
|
||||
version: values[`node_version_${item.id}`],
|
||||
}
|
||||
})
|
||||
},
|
||||
setNodeField() {
|
||||
if (this.nodes && this.nodes.length) {
|
||||
this.nodes.forEach((item) => {
|
||||
this.form.setFieldsValue({
|
||||
[`node_ip_${item.id}`]: item.ip,
|
||||
[`node_community_${item.id}`]: item.community,
|
||||
[`node_version_${item.id}`]: item.version,
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
getNodeValue() {
|
||||
const values = this.form.getFieldsValue()
|
||||
return this.getInfoValuesFromForm(values)
|
||||
const nodes = this.nodes.map((node) => {
|
||||
return _.pick(node, ['ip', 'community', 'version'])
|
||||
})
|
||||
return nodes
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -180,10 +121,9 @@ export default {
|
|||
<style lang="less" scoped>
|
||||
.node-setting-wrap {
|
||||
margin-left: 17px;
|
||||
width: 600px;
|
||||
|
||||
.ant-row {
|
||||
// display: flex;
|
||||
|
||||
/deep/ .ant-input-clear-icon {
|
||||
color: rgba(0,0,0,.25);
|
||||
|
||||
|
|
|
@ -236,7 +236,7 @@ const cmdb_en = {
|
|||
checkModalColumn4: 'Last checkup time',
|
||||
testModalTitle: 'Automated discovery testing',
|
||||
attrMapTableAttrPlaceholder: 'Please edit the name',
|
||||
nodeSettingIp: 'IP Addresses',
|
||||
nodeSettingIp: 'Network device IP address',
|
||||
nodeSettingIpTip: 'Please enter the ip address',
|
||||
nodeSettingIpTip1: 'ip address format error',
|
||||
nodeSettingCommunity: 'Community',
|
||||
|
@ -264,6 +264,18 @@ const cmdb_en = {
|
|||
resourceSearchTip3: 'Note 2: If you do not need to filter, please click the grey button to copy and paste directly to configure for all nodes',
|
||||
enable: 'Enable',
|
||||
enableTip: 'Confirm switching on?',
|
||||
portScanConfig: 'Port Scan Config',
|
||||
portScanLabel1: 'CIDR',
|
||||
portScanLabel2: 'Port Range',
|
||||
portScanLabel3: 'AgentID',
|
||||
viewAllAttr: 'View All Prop',
|
||||
attrGroup: 'Attr Group',
|
||||
attrName: 'Attr Name',
|
||||
attrAlias: 'Attr Alias',
|
||||
attrCode: 'Attr Code',
|
||||
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`,
|
||||
example: 'Example'
|
||||
},
|
||||
components: {
|
||||
unselectAttributes: 'Unselected',
|
||||
|
|
|
@ -236,7 +236,7 @@ const cmdb_zh = {
|
|||
checkModalColumn4: '最近检查时间',
|
||||
testModalTitle: '自动发现测试',
|
||||
attrMapTableAttrPlaceholder: '请编辑名称',
|
||||
nodeSettingIp: 'ip地址',
|
||||
nodeSettingIp: '网络设备IP地址',
|
||||
nodeSettingIpTip: '请输入 ip 地址',
|
||||
nodeSettingIpTip1: 'ip地址格式错误',
|
||||
nodeSettingCommunity: 'Community',
|
||||
|
@ -264,6 +264,18 @@ const cmdb_zh = {
|
|||
resourceSearchTip3: '注2:如不需要筛选,请直接点击灰色按钮进行复制粘贴,即可配置为所有节点',
|
||||
enable: '开启',
|
||||
enableTip: '确定切换开启状态吗',
|
||||
portScanConfig: '端口扫描配置',
|
||||
portScanLabel1: 'CIDR',
|
||||
portScanLabel2: '端口范围',
|
||||
portScanLabel3: 'AgentID',
|
||||
viewAllAttr: '查看所有属性',
|
||||
attrGroup: '属性分组',
|
||||
attrName: '属性名称',
|
||||
attrAlias: '属性别名',
|
||||
attrCode: '属性代码',
|
||||
computedAttrTip1: '引用属性遵循jinja2语法',
|
||||
computedAttrTip2: `多值属性(列表)默认呈现包括[ ], 如果要去掉, 引用方法为: """{{ attr_name | join(',')}}""" 其中逗号为分隔符`,
|
||||
example: '例如'
|
||||
},
|
||||
components: {
|
||||
unselectAttributes: '未选属性',
|
||||
|
|
|
@ -140,6 +140,7 @@
|
|||
:mode="col.is_list ? 'multiple' : 'default'"
|
||||
class="ci-table-edit-select"
|
||||
allowClear
|
||||
showSearch
|
||||
>
|
||||
<a-select-option
|
||||
:value="choice[0]"
|
||||
|
@ -161,7 +162,7 @@
|
|||
:type="choice[1].icon.name"
|
||||
/>
|
||||
</template>
|
||||
{{ choice[0] }}
|
||||
<span>{{ choice[0] }}</span>
|
||||
</span>
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
|
@ -199,6 +200,7 @@
|
|||
borderRadius: '4px',
|
||||
padding: '1px 5px',
|
||||
margin: '2px',
|
||||
verticalAlign: 'bottom',
|
||||
...getChoiceValueStyle(col, value),
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
|
@ -210,7 +212,7 @@
|
|||
:style="{ maxHeight: '13px', maxWidth: '13px', marginRight: '5px' }"
|
||||
/>
|
||||
<ops-icon
|
||||
v-else
|
||||
v-else-if="getChoiceValueIcon(col, value).name"
|
||||
:style="{ color: getChoiceValueIcon(col, value).color, marginRight: '5px' }"
|
||||
:type="getChoiceValueIcon(col, value).name"
|
||||
/>{{ value }}
|
||||
|
@ -222,6 +224,7 @@
|
|||
borderRadius: '4px',
|
||||
padding: '1px 5px',
|
||||
margin: '2px 0',
|
||||
verticalAlign: 'bottom',
|
||||
...getChoiceValueStyle(col, row[col.field]),
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
|
@ -233,7 +236,7 @@
|
|||
:style="{ maxHeight: '13px', maxWidth: '13px', marginRight: '5px' }"
|
||||
/>
|
||||
<ops-icon
|
||||
v-else
|
||||
v-else-if="getChoiceValueIcon(col, row[col.field]).name"
|
||||
:style="{ color: getChoiceValueIcon(col, row[col.field]).color, marginRight: '5px' }"
|
||||
:type="getChoiceValueIcon(col, row[col.field]).name"
|
||||
/>
|
||||
|
|
|
@ -105,7 +105,7 @@ export default {
|
|||
default: true,
|
||||
},
|
||||
attrList: {
|
||||
type: Array,
|
||||
type: Function,
|
||||
default: () => [],
|
||||
}
|
||||
},
|
||||
|
|
|
@ -132,6 +132,10 @@ export default {
|
|||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
initQueryLoading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -145,129 +149,13 @@ export default {
|
|||
firstCIJsonAttr: {},
|
||||
secondCIJsonAttr: {},
|
||||
canEdit: {},
|
||||
topoData: {
|
||||
nodes: {},
|
||||
edges: []
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
topoData() {
|
||||
const ci_types_list = this.ci_types()
|
||||
const _findCiType = ci_types_list.find((item) => item.id === this.typeId)
|
||||
const unique_id = _findCiType.show_id || this.attributes().unique_id
|
||||
const unique_name = _findCiType.show_name || this.attributes().unique
|
||||
const _findUnique = this.attrList().find((attr) => attr.id === unique_id)
|
||||
const unique_alias = _findUnique?.alias || _findUnique?.name || ''
|
||||
const nodes = {
|
||||
isRoot: true,
|
||||
id: `Root_${this.typeId}`,
|
||||
title: _findCiType.alias || _findCiType.name, // 中文名
|
||||
name: _findCiType.name, // 英文名
|
||||
Class: Node,
|
||||
unique_alias,
|
||||
unique_name,
|
||||
unique_value: this.ci[unique_name],
|
||||
icon: _findCiType?.icon || '',
|
||||
endpoints: [
|
||||
{
|
||||
id: 'left',
|
||||
orientation: [-1, 0],
|
||||
pos: [0, 0.5],
|
||||
},
|
||||
{
|
||||
id: 'right',
|
||||
orientation: [1, 0],
|
||||
pos: [0, 0.5],
|
||||
},
|
||||
],
|
||||
children: [],
|
||||
}
|
||||
const edges = []
|
||||
this.parentCITypes.forEach((parent) => {
|
||||
const _findCiType = ci_types_list.find((item) => item.id === parent.id)
|
||||
if (this.firstCIs[parent.name] && _findCiType) {
|
||||
const unique_id = _findCiType.show_id || _findCiType.unique_id
|
||||
const _findUnique = parent.attributes.find((attr) => attr.id === unique_id)
|
||||
const unique_name = _findUnique?.name
|
||||
const unique_alias = _findUnique?.alias || _findUnique?.name || ''
|
||||
this.firstCIs[parent.name].forEach((parentCi) => {
|
||||
nodes.children.push({
|
||||
id: `${parentCi._id}`,
|
||||
Class: Node,
|
||||
title: parent.alias || parent.name,
|
||||
name: parent.name,
|
||||
side: 'left',
|
||||
unique_alias,
|
||||
unique_name,
|
||||
unique_value: parentCi[unique_name],
|
||||
children: [],
|
||||
icon: _findCiType?.icon || '',
|
||||
endpoints: [
|
||||
{
|
||||
id: 'left',
|
||||
orientation: [-1, 0],
|
||||
pos: [0, 0.5],
|
||||
},
|
||||
{
|
||||
id: 'right',
|
||||
orientation: [1, 0],
|
||||
pos: [0, 0.5],
|
||||
},
|
||||
],
|
||||
})
|
||||
edges.push({
|
||||
id: `${parentCi._id}_Root`,
|
||||
source: 'right',
|
||||
target: 'left',
|
||||
sourceNode: `${parentCi._id}`,
|
||||
targetNode: `Root_${this.typeId}`,
|
||||
type: 'endpoint',
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
this.childCITypes.forEach((child) => {
|
||||
const _findCiType = ci_types_list.find((item) => item.id === child.id)
|
||||
if (this.secondCIs[child.name] && _findCiType) {
|
||||
const unique_id = _findCiType.show_id || _findCiType.unique_id
|
||||
const _findUnique = child.attributes.find((attr) => attr.id === unique_id)
|
||||
const unique_name = _findUnique?.name
|
||||
const unique_alias = _findUnique?.alias || _findUnique?.name || ''
|
||||
this.secondCIs[child.name].forEach((childCi) => {
|
||||
nodes.children.push({
|
||||
id: `${childCi._id}`,
|
||||
Class: Node,
|
||||
title: child.alias || child.name,
|
||||
name: child.name,
|
||||
side: 'right',
|
||||
unique_alias,
|
||||
unique_name,
|
||||
unique_value: childCi[unique_name],
|
||||
children: [],
|
||||
icon: _findCiType?.icon || '',
|
||||
endpoints: [
|
||||
{
|
||||
id: 'left',
|
||||
orientation: [-1, 0],
|
||||
pos: [0, 0.5],
|
||||
},
|
||||
{
|
||||
id: 'right',
|
||||
orientation: [1, 0],
|
||||
pos: [0, 0.5],
|
||||
},
|
||||
],
|
||||
})
|
||||
edges.push({
|
||||
id: `Root_${childCi._id}`,
|
||||
source: 'right',
|
||||
target: 'left',
|
||||
sourceNode: `Root_${this.typeId}`,
|
||||
targetNode: `${childCi._id}`,
|
||||
type: 'endpoint',
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
return { nodes, edges }
|
||||
},
|
||||
exsited_ci() {
|
||||
const _exsited_ci = [this.ciId]
|
||||
this.parentCITypes.forEach((parent) => {
|
||||
|
@ -297,20 +185,28 @@ export default {
|
|||
},
|
||||
},
|
||||
mounted() {
|
||||
if (!this.initQueryLoading) {
|
||||
this.init(true)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async init(isFirst) {
|
||||
await Promise.all([this.getParentCITypes(), this.getChildCITypes()])
|
||||
Promise.all([this.getFirstCIs(), this.getSecondCIs()]).then(() => {
|
||||
if (isFirst && this.$refs.ciDetailRelationTopo) {
|
||||
const ci_types_list = this.ci_types()
|
||||
this.handleTopoData()
|
||||
if (
|
||||
isFirst &&
|
||||
this.$refs.ciDetailRelationTopo &&
|
||||
ci_types_list.length
|
||||
) {
|
||||
this.$refs.ciDetailRelationTopo.exsited_ci = this.exsited_ci
|
||||
this.$refs.ciDetailRelationTopo.setTopoData(this.topoData)
|
||||
}
|
||||
})
|
||||
},
|
||||
async getFirstCIs() {
|
||||
await searchCIRelation(`root_id=${Number(this.ciId)}&&level=1&&reverse=1&&count=10000`)
|
||||
await searchCIRelation(`root_id=${Number(this.ciId)}&level=1&reverse=1&count=10000`)
|
||||
.then((res) => {
|
||||
const firstCIs = {}
|
||||
res.result.forEach((item) => {
|
||||
|
@ -328,7 +224,7 @@ export default {
|
|||
.catch((e) => {})
|
||||
},
|
||||
async getSecondCIs() {
|
||||
await searchCIRelation(`root_id=${Number(this.ciId)}&&level=1&&reverse=0&&count=10000`)
|
||||
await searchCIRelation(`root_id=${Number(this.ciId)}&level=1&reverse=0&count=10000`)
|
||||
.then((res) => {
|
||||
const secondCIs = {}
|
||||
res.result.forEach((item) => {
|
||||
|
@ -445,6 +341,137 @@ export default {
|
|||
})
|
||||
}
|
||||
},
|
||||
handleTopoData() {
|
||||
const ci_types_list = this.ci_types()
|
||||
if (!ci_types_list?.length) {
|
||||
this.$set(this, 'topoData', {
|
||||
nodes: {},
|
||||
edges: []
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const _findCiType = ci_types_list.find((item) => item.id === this.typeId)
|
||||
const unique_id = _findCiType.show_id || this.attributes().unique_id
|
||||
const unique_name = _findCiType.show_name || this.attributes().unique
|
||||
const _findUnique = this.attrList().find((attr) => attr.id === unique_id)
|
||||
const unique_alias = _findUnique?.alias || _findUnique?.name || ''
|
||||
const nodes = {
|
||||
isRoot: true,
|
||||
id: `Root_${this.typeId}`,
|
||||
title: _findCiType.alias || _findCiType.name, // 中文名
|
||||
name: _findCiType.name, // 英文名
|
||||
Class: Node,
|
||||
unique_alias,
|
||||
unique_name,
|
||||
unique_value: this.ci[unique_name],
|
||||
icon: _findCiType?.icon || '',
|
||||
endpoints: [
|
||||
{
|
||||
id: 'left',
|
||||
orientation: [-1, 0],
|
||||
pos: [0, 0.5],
|
||||
},
|
||||
{
|
||||
id: 'right',
|
||||
orientation: [1, 0],
|
||||
pos: [0, 0.5],
|
||||
},
|
||||
],
|
||||
children: [],
|
||||
}
|
||||
const edges = []
|
||||
this.parentCITypes.forEach((parent) => {
|
||||
const _findCiType = ci_types_list.find((item) => item.id === parent.id)
|
||||
if (this.firstCIs[parent.name] && _findCiType) {
|
||||
const unique_id = _findCiType.show_id || _findCiType.unique_id
|
||||
const _findUnique = parent.attributes.find((attr) => attr.id === unique_id)
|
||||
const unique_name = _findUnique?.name
|
||||
const unique_alias = _findUnique?.alias || _findUnique?.name || ''
|
||||
this.firstCIs[parent.name].forEach((parentCi) => {
|
||||
nodes.children.push({
|
||||
id: `${parentCi._id}`,
|
||||
Class: Node,
|
||||
title: parent.alias || parent.name,
|
||||
name: parent.name,
|
||||
side: 'left',
|
||||
unique_alias,
|
||||
unique_name,
|
||||
unique_value: parentCi[unique_name],
|
||||
children: [],
|
||||
icon: _findCiType?.icon || '',
|
||||
endpoints: [
|
||||
{
|
||||
id: 'left',
|
||||
orientation: [-1, 0],
|
||||
pos: [0, 0.5],
|
||||
},
|
||||
{
|
||||
id: 'right',
|
||||
orientation: [1, 0],
|
||||
pos: [0, 0.5],
|
||||
},
|
||||
],
|
||||
})
|
||||
edges.push({
|
||||
id: `${parentCi._id}_Root`,
|
||||
source: 'right',
|
||||
target: 'left',
|
||||
sourceNode: `${parentCi._id}`,
|
||||
targetNode: `Root_${this.typeId}`,
|
||||
type: 'endpoint',
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
this.childCITypes.forEach((child) => {
|
||||
const _findCiType = ci_types_list.find((item) => item.id === child.id)
|
||||
if (this.secondCIs[child.name] && _findCiType) {
|
||||
const unique_id = _findCiType.show_id || _findCiType.unique_id
|
||||
const _findUnique = child.attributes.find((attr) => attr.id === unique_id)
|
||||
const unique_name = _findUnique?.name
|
||||
const unique_alias = _findUnique?.alias || _findUnique?.name || ''
|
||||
this.secondCIs[child.name].forEach((childCi) => {
|
||||
nodes.children.push({
|
||||
id: `${childCi._id}`,
|
||||
Class: Node,
|
||||
title: child.alias || child.name,
|
||||
name: child.name,
|
||||
side: 'right',
|
||||
unique_alias,
|
||||
unique_name,
|
||||
unique_value: childCi[unique_name],
|
||||
children: [],
|
||||
icon: _findCiType?.icon || '',
|
||||
endpoints: [
|
||||
{
|
||||
id: 'left',
|
||||
orientation: [-1, 0],
|
||||
pos: [0, 0.5],
|
||||
},
|
||||
{
|
||||
id: 'right',
|
||||
orientation: [1, 0],
|
||||
pos: [0, 0.5],
|
||||
},
|
||||
],
|
||||
})
|
||||
edges.push({
|
||||
id: `Root_${childCi._id}`,
|
||||
source: 'right',
|
||||
target: 'left',
|
||||
sourceNode: `Root_${this.typeId}`,
|
||||
targetNode: `${childCi._id}`,
|
||||
type: 'endpoint',
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
this.$set(this, 'topoData', {
|
||||
nodes,
|
||||
edges
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
border: 1px solid #d9d9d9;
|
||||
border-radius: 2px;
|
||||
padding: 4px 8px;
|
||||
width: 100px;
|
||||
width: auto;
|
||||
text-align: center;
|
||||
.title {
|
||||
font-size: 16px;
|
||||
|
@ -73,7 +73,7 @@
|
|||
}
|
||||
}
|
||||
.root {
|
||||
width: 100px;
|
||||
width: auto;
|
||||
border-color: @primary-color;
|
||||
font-weight: 700;
|
||||
padding: 4px 8px;
|
||||
|
|
|
@ -29,6 +29,10 @@ export default {
|
|||
methods: {
|
||||
init() {
|
||||
const root = document.getElementById('ci-detail-relation-topo')
|
||||
const canvas = document.createElement('canvas')
|
||||
const context = canvas.getContext('2d')
|
||||
context.font = '16px'
|
||||
|
||||
this.canvas = new TreeCanvas({
|
||||
root: root,
|
||||
disLinkable: false, // 可删除连线
|
||||
|
@ -54,7 +58,15 @@ export default {
|
|||
return 10
|
||||
},
|
||||
getWidth(d) {
|
||||
return 40
|
||||
const metrics = context.measureText(d?.title || '')
|
||||
const width = metrics.width
|
||||
/**
|
||||
* width 文字宽度
|
||||
* 20 icon 宽度
|
||||
* 4 盒子内边距
|
||||
* 40 节点间距
|
||||
*/
|
||||
return width + 20 + 4 + 40
|
||||
},
|
||||
getHGap(d) {
|
||||
return 80
|
||||
|
@ -69,22 +81,27 @@ export default {
|
|||
this.canvas.on('events', ({ type, data }) => {
|
||||
const sourceNode = data?.id || null
|
||||
if (type === 'custom:clickLeft') {
|
||||
searchCIRelation(`root_id=${Number(sourceNode)}&&level=1&&reverse=1&&count=10000`).then((res) => {
|
||||
searchCIRelation(`root_id=${Number(sourceNode)}&level=1&reverse=1&count=10000`).then((res) => {
|
||||
this.redrawData(res, sourceNode, 'left')
|
||||
})
|
||||
}
|
||||
if (type === 'custom:clickRight') {
|
||||
searchCIRelation(`root_id=${Number(sourceNode)}&&level=1&&reverse=0&&count=10000`).then((res) => {
|
||||
searchCIRelation(`root_id=${Number(sourceNode)}&level=1&reverse=0&count=10000`).then((res) => {
|
||||
this.redrawData(res, sourceNode, 'right')
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
setTopoData(data) {
|
||||
const root = document.getElementById('ci-detail-relation-topo')
|
||||
if (root && root?.innerHTML) {
|
||||
root.innerHTML = ''
|
||||
}
|
||||
this.canvas = null
|
||||
this.init()
|
||||
this.topoData = _.cloneDeep(data)
|
||||
this.canvas.draw(data, {}, () => {
|
||||
|
||||
this.canvas.redraw(data, {}, () => {
|
||||
this.canvas.focusCenterWithAnimate()
|
||||
})
|
||||
},
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
<a-tab-pane key="tab_2">
|
||||
<span slot="tab"><a-icon type="branches" />{{ $t('cmdb.relation') }}</span>
|
||||
<div :style="{ height: '100%', padding: '24px', overflow: 'auto' }">
|
||||
<ci-detail-relation ref="ciDetailRelation" :ciId="ciId" :typeId="typeId" :ci="ci" />
|
||||
<ci-detail-relation ref="ciDetailRelation" :ciId="ciId" :typeId="typeId" :ci="ci" :initQueryLoading="initQueryLoading" />
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="tab_3">
|
||||
|
@ -181,6 +181,7 @@ export default {
|
|||
hasPermission: true,
|
||||
itsmInstalled: true,
|
||||
tableHeight: this.attributeHistoryTableHeight || (this.$store.state.windowHeight - 120),
|
||||
initQueryLoading: true,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -218,6 +219,7 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
async create(ciId, activeTabKey = 'tab_1', ciDetailRelationKey = '1') {
|
||||
this.initQueryLoading = true
|
||||
this.activeTabKey = activeTabKey
|
||||
if (activeTabKey === 'tab_2') {
|
||||
this.$nextTick(() => {
|
||||
|
@ -230,10 +232,13 @@ export default {
|
|||
if (this.hasPermission) {
|
||||
this.getAttributes()
|
||||
this.getCIHistory()
|
||||
getCITypes().then((res) => {
|
||||
this.ci_types = res.ci_types
|
||||
})
|
||||
const ciTypeRes = await getCITypes()
|
||||
this.ci_types = ciTypeRes.ci_types
|
||||
if (this.activeTabKey === 'tab_2') {
|
||||
this.$refs.ciDetailRelation.init(true)
|
||||
}
|
||||
}
|
||||
this.initQueryLoading = false
|
||||
},
|
||||
getAttributes() {
|
||||
getCITypeGroupById(this.typeId, { need_other: 1 })
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
<template>
|
||||
<CustomDrawer
|
||||
:title="$t('cmdb.ciType.viewAllAttr')"
|
||||
:visible="visible"
|
||||
placement="right"
|
||||
width="800"
|
||||
:bodyStyle="{ height: '100vh' }"
|
||||
@close="handleClose"
|
||||
>
|
||||
<vxe-table
|
||||
resizable
|
||||
size="mini"
|
||||
:span-method="mergeRowMethod"
|
||||
:data="tableData"
|
||||
show-overflow
|
||||
show-header-overflow
|
||||
border
|
||||
class="ops-stripe-table"
|
||||
:height="windowHeight - 160"
|
||||
>
|
||||
<vxe-table-column align="center" field="groupId" :title="$t('cmdb.ciType.attrGroup')" :width="100">
|
||||
<template #default="{row}">
|
||||
<span>{{ row.groupName }}</span>
|
||||
</template>
|
||||
</vxe-table-column>
|
||||
<vxe-table-column field="name" :title="$t('cmdb.ciType.attrName')" :width="150"></vxe-table-column>
|
||||
<vxe-table-column field="alias" :title="$t('cmdb.ciType.attrAlias')" :width="150"></vxe-table-column>
|
||||
<vxe-table-column field="typeText" :title="$t('type')" :width="100"></vxe-table-column>
|
||||
<vxe-table-column field="code" :title="$t('cmdb.ciType.attrCode')">
|
||||
<template #default="{row}">
|
||||
<a @click="copyText(row.code)" >{{ row.code }}</a>
|
||||
</template>
|
||||
</vxe-table-column>
|
||||
</vxe-table>
|
||||
</CustomDrawer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import _ from 'lodash'
|
||||
import { valueTypeMap } from '@/modules/cmdb/utils/const'
|
||||
|
||||
export default {
|
||||
name: 'AllAttrDrawer',
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
tableData: [],
|
||||
}
|
||||
},
|
||||
inject: ['providerGroupsData'],
|
||||
computed: {
|
||||
...mapState({
|
||||
windowHeight: (state) => state.windowHeight,
|
||||
}),
|
||||
},
|
||||
methods: {
|
||||
async open() {
|
||||
this.visible = true
|
||||
const tableData = []
|
||||
const typeMap = valueTypeMap()
|
||||
const providerGroupsData = _.cloneDeep(this.providerGroupsData() || {})
|
||||
const groupsData = providerGroupsData?.CITypeGroups || []
|
||||
const otherAttrData = providerGroupsData?.otherGroupAttributes || []
|
||||
|
||||
groupsData.forEach((group) => {
|
||||
if (group?.attributes?.length) {
|
||||
const attrArr = group.attributes.map((attr) => {
|
||||
if (attr.is_password) {
|
||||
attr.value_type = '7'
|
||||
}
|
||||
if (attr.is_link) {
|
||||
attr.value_type = '8'
|
||||
}
|
||||
attr.groupId = group.id
|
||||
attr.groupName = group.name
|
||||
attr.code = ['0', '1', '6'].includes(attr.value_type) ? `{{ ${attr.name} }}` : `'''{{ ${attr.name} }}'''`
|
||||
attr.typeText = typeMap?.[attr.value_type] ?? ''
|
||||
|
||||
return attr
|
||||
})
|
||||
tableData.push(...attrArr)
|
||||
}
|
||||
})
|
||||
|
||||
otherAttrData.forEach((attr) => {
|
||||
if (attr.is_password) {
|
||||
attr.value_type = '7'
|
||||
}
|
||||
if (attr.is_link) {
|
||||
attr.value_type = '8'
|
||||
}
|
||||
|
||||
attr.groupId = -1
|
||||
attr.groupName = '其他'
|
||||
attr.code = `{{ ${attr.name} }}`
|
||||
attr.typeText = typeMap?.[attr.value_type] ?? ''
|
||||
})
|
||||
tableData.push(...otherAttrData)
|
||||
|
||||
this.tableData = tableData
|
||||
},
|
||||
|
||||
mergeRowMethod({ row, _rowIndex, column, visibleData }) {
|
||||
const fields = ['groupId']
|
||||
const currentValue = row.groupId
|
||||
|
||||
if (currentValue && fields.includes(column.property)) {
|
||||
const prevRow = visibleData[_rowIndex - 1]
|
||||
let nextRow = visibleData[_rowIndex + 1]
|
||||
if (prevRow && prevRow.groupId === currentValue) {
|
||||
return { rowspan: 0, colspan: 0 }
|
||||
} else {
|
||||
let countRowspan = 1
|
||||
while (nextRow && nextRow.groupId === currentValue) {
|
||||
nextRow = visibleData[++countRowspan + _rowIndex]
|
||||
}
|
||||
if (countRowspan > 1) {
|
||||
return { rowspan: countRowspan, colspan: 1 }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
handleClose() {
|
||||
this.visible = false
|
||||
},
|
||||
|
||||
copyText(text) {
|
||||
this.$copyText(text)
|
||||
.then(() => {
|
||||
this.$message.success(this.$t('copySuccess'))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
</style>
|
|
@ -0,0 +1,156 @@
|
|||
<template>
|
||||
<a-row class="attr-ad-form">
|
||||
<a-col :span="24">
|
||||
<a-form-item
|
||||
label="CIDR"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="{ span: 18 }"
|
||||
labelAlign="right"
|
||||
style="width: 100%; margin-top: 20px"
|
||||
>
|
||||
<div class="cidr-tag">
|
||||
<div
|
||||
v-for="(item) in list"
|
||||
:key="item.id"
|
||||
class="cidr-tag-item"
|
||||
>
|
||||
<a-tooltip :title="item.value">
|
||||
<span class="cidr-tag-text">{{ item.value }}</span>
|
||||
</a-tooltip>
|
||||
<a-icon
|
||||
class="cidrv-tag-close"
|
||||
type="close"
|
||||
@click.stop="clickClose(item.id)"
|
||||
/>
|
||||
</div>
|
||||
<a-input
|
||||
v-if="showAddInput"
|
||||
class="cidr-tag-input"
|
||||
autofocus
|
||||
@blur="addPreValue"
|
||||
@pressEnter="showAddInput = false"
|
||||
></a-input>
|
||||
<a v-else class="cidr-tag-add" @click="showAddInput = true">+ {{ $t('new') }}</a>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
|
||||
export default {
|
||||
name: 'CIDRTags',
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'change',
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showAddInput: false,
|
||||
}
|
||||
},
|
||||
inject: ['provide_labelCol'],
|
||||
computed: {
|
||||
list: {
|
||||
get() {
|
||||
return this.value
|
||||
},
|
||||
set(newValue) {
|
||||
this.$emit('change', newValue)
|
||||
}
|
||||
},
|
||||
labelCol() {
|
||||
return this.provide_labelCol()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
clickClose(id) {
|
||||
const list = _.cloneDeep(this.value)
|
||||
const index = list.findIndex((item) => item.id === id)
|
||||
if (index !== -1) {
|
||||
list.splice(index, 1)
|
||||
this.$emit('change', list)
|
||||
}
|
||||
},
|
||||
addPreValue(e) {
|
||||
this.showAddInput = false
|
||||
const val = e.target.value
|
||||
if (!val) {
|
||||
return
|
||||
}
|
||||
const list = _.cloneDeep(this.value)
|
||||
list.push({
|
||||
value: val,
|
||||
id: uuidv4()
|
||||
})
|
||||
this.$emit('change', list)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.cidr-tag {
|
||||
width: max-content;
|
||||
max-width: 100%;
|
||||
padding: 6px 9px;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #E4E7ED;
|
||||
background: #FFF;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
|
||||
&-item {
|
||||
padding: 3px 6px;
|
||||
background-color: #F0F5FF;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&-text {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: #1D2129;
|
||||
line-height: 18px;
|
||||
text-overflow: ellipsis;
|
||||
word-break: break-all;
|
||||
white-space: nowrap;
|
||||
max-width: 100px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&-close {
|
||||
font-size: 12px;
|
||||
color: #1D2129;
|
||||
margin-left: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&-input {
|
||||
max-width: 120px;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
padding: 3px 6px;
|
||||
}
|
||||
|
||||
&-add {
|
||||
border: dashed 1px #e4e7ed;
|
||||
padding: 3px 6px;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: #1D2129;
|
||||
line-height: 18px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,52 @@
|
|||
<template>
|
||||
<a-form-model
|
||||
:model="formData"
|
||||
labelAlign="right"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="{ span: 6 }"
|
||||
class="attr-ad-form"
|
||||
>
|
||||
<a-form-model-item :extra="`${$t('cmdb.ciType.example')}: 192.168.0.0/16`" :label="$t('cmdb.ciType.portScanLabel1')">
|
||||
<a-input v-model="formData.cidr" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item :extra="`${$t('cmdb.ciType.example')}: 8000-8800`" :label="$t('cmdb.ciType.portScanLabel2')">
|
||||
<a-input v-model="formData.ports" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item :extra="`${$t('cmdb.ciType.example')}: 0x1234`" :label="$t('cmdb.ciType.portScanLabel3')">
|
||||
<a-input v-model="formData.enable_cidr" />
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'PortScanConfig',
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'change',
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
inject: ['provide_labelCol'],
|
||||
computed: {
|
||||
formData: {
|
||||
get() {
|
||||
return this.value
|
||||
},
|
||||
set(newValue) {
|
||||
this.$emit('change', newValue)
|
||||
}
|
||||
},
|
||||
labelCol() {
|
||||
return this.provide_labelCol()
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
</style>
|
|
@ -6,7 +6,7 @@
|
|||
/>
|
||||
<a-form-model
|
||||
:model="formData"
|
||||
labelAlign="left"
|
||||
labelAlign="right"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="{ span: 6 }"
|
||||
class="attr-ad-form"
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
/>
|
||||
<a-form-model
|
||||
:model="formData"
|
||||
labelAlign="left"
|
||||
labelAlign="right"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="{ span: 6 }"
|
||||
class="attr-ad-form"
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
</div>
|
||||
<div class="attr-ad-attributemap-main">
|
||||
<AttrMapTable
|
||||
v-if="adrType === 'agent'"
|
||||
v-if="adrType === DISCOVERY_CATEGORY_TYPE.AGENT"
|
||||
ref="attrMapTable"
|
||||
:ruleType="adrType"
|
||||
:tableData="tableData"
|
||||
|
@ -53,17 +53,18 @@
|
|||
:style="{ marginBottom: '20px' }"
|
||||
/>
|
||||
</div>
|
||||
<template v-if="adrType === 'snmp'">
|
||||
<template v-if="adrType === DISCOVERY_CATEGORY_TYPE.SNMP">
|
||||
<div class="attr-ad-header">{{ $t('cmdb.ciType.nodeConfig') }}</div>
|
||||
<a-form :form="form3" layout="inline" class="attr-ad-snmp-form">
|
||||
<NodeSetting ref="nodeSetting" :initNodes="nodes" :form="form3" />
|
||||
<a-form :form="nodeSettingForm" layout="inline" class="attr-ad-snmp-form">
|
||||
<NodeSetting ref="nodeSetting" :initNodes="nodes" />
|
||||
<CIDRTags v-model="cidrList" />
|
||||
</a-form>
|
||||
</template>
|
||||
<div class="attr-ad-header">{{ $t('cmdb.ciType.adExecConfig') }}</div>
|
||||
<a-form-model
|
||||
:model="form"
|
||||
:labelCol="labelCol"
|
||||
labelAlign="left"
|
||||
labelAlign="right"
|
||||
:wrapperCol="{ span: 14 }"
|
||||
class="attr-ad-form"
|
||||
>
|
||||
|
@ -127,7 +128,7 @@
|
|||
</el-popover>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
<template v-if="adrType === 'http'">
|
||||
<template v-if="adrType === DISCOVERY_CATEGORY_TYPE.HTTP">
|
||||
<template v-if="isPrivateCloud">
|
||||
<template v-if="privateCloudName === PRIVATE_CLOUD_NAME.VCenter">
|
||||
<div class="attr-ad-header">{{ $t('cmdb.ciType.privateCloud') }}</div>
|
||||
|
@ -142,12 +143,17 @@
|
|||
<div class="attr-ad-header">{{ $t('cmdb.ciType.cloudAccessKey') }}</div>
|
||||
<!-- <div class="public-cloud-info">{{ $t('cmdb.ciType.cloudAccessKeyTip') }}</div> -->
|
||||
<PublicCloud
|
||||
v-model="form2"
|
||||
v-model="publicCloudForm"
|
||||
ref="httpForm"
|
||||
/>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<template v-if="adrType === DISCOVERY_CATEGORY_TYPE.COMPONENT">
|
||||
<div class="attr-ad-header">{{ $t('cmdb.ciType.portScanConfig') }}</div>
|
||||
<PortScanConfig v-model="portScanConfigForm" />
|
||||
</template>
|
||||
|
||||
<AttrADTest
|
||||
:adtId="currentAdt.id"
|
||||
/>
|
||||
|
@ -165,7 +171,7 @@ import { v4 as uuidv4 } from 'uuid'
|
|||
import { mapState } from 'vuex'
|
||||
import Vcrontab from '@/components/Crontab'
|
||||
import { putCITypeDiscovery, postCITypeDiscovery } from '../../api/discovery'
|
||||
import { PRIVATE_CLOUD_NAME } from '@/modules/cmdb/views/discovery/constants.js'
|
||||
import { DISCOVERY_CATEGORY_TYPE, PRIVATE_CLOUD_NAME } from '@/modules/cmdb/views/discovery/constants.js'
|
||||
import { TAB_KEY } from './attrAD/constants.js'
|
||||
|
||||
import HttpSnmpAD from '../../components/httpSnmpAD'
|
||||
|
@ -176,6 +182,8 @@ import AttrADTest from './attrADTest.vue'
|
|||
import { Popover } from 'element-ui'
|
||||
import VcenterForm from './attrAD/privateCloud/vcenterForm.vue'
|
||||
import PublicCloud from './attrAD/publicCloud/index.vue'
|
||||
import PortScanConfig from './attrAD/portScanConfig/index.vue'
|
||||
import CIDRTags from './attrAD/cidrTags/index.vue'
|
||||
|
||||
export default {
|
||||
name: 'AttrADTabpane',
|
||||
|
@ -188,7 +196,9 @@ export default {
|
|||
AttrADTest,
|
||||
ElPopover: Popover,
|
||||
VcenterForm,
|
||||
PublicCloud
|
||||
PublicCloud,
|
||||
PortScanConfig,
|
||||
CIDRTags
|
||||
},
|
||||
props: {
|
||||
adr_id: {
|
||||
|
@ -229,7 +239,7 @@ export default {
|
|||
query_expr: '',
|
||||
enabled: true,
|
||||
},
|
||||
form2: {
|
||||
publicCloudForm: {
|
||||
key: '',
|
||||
secret: '',
|
||||
_reference: '',
|
||||
|
@ -244,25 +254,31 @@ export default {
|
|||
_reference: '',
|
||||
tabActive: TAB_KEY.CUSTOM,
|
||||
},
|
||||
interval: 'cron', // interval cron
|
||||
portScanConfigForm: {
|
||||
cidr: '',
|
||||
ports: '',
|
||||
enable_cidr: '',
|
||||
},
|
||||
cron: '',
|
||||
cronVisible: false,
|
||||
intervalValue: 3,
|
||||
agent_type: 'agent_id',
|
||||
nodes: [
|
||||
{
|
||||
id: uuidv4(),
|
||||
ip: '',
|
||||
community: '',
|
||||
community: 'public',
|
||||
version: '',
|
||||
},
|
||||
],
|
||||
form3: this.$form.createForm(this, { name: 'snmp_form' }),
|
||||
cronVisible: false,
|
||||
nodeSettingForm: this.$form.createForm(this, { name: 'snmp_form' }),
|
||||
uniqueKey: '',
|
||||
isPrivateCloud: false,
|
||||
privateCloudName: '',
|
||||
PRIVATE_CLOUD_NAME,
|
||||
DISCOVERY_CATEGORY_TYPE,
|
||||
isClient: false, // 是否前端新增临时数据
|
||||
cidrList: [],
|
||||
}
|
||||
},
|
||||
provide() {
|
||||
|
@ -293,26 +309,28 @@ export default {
|
|||
]
|
||||
|
||||
const permissions = this?.user?.roles?.permissions
|
||||
if ((permissions.includes('cmdb_admin') || permissions.includes('admin')) && this.adrType === 'agent') {
|
||||
if ((permissions.includes('cmdb_admin') || permissions.includes('admin')) && this.adrType === DISCOVERY_CATEGORY_TYPE.AGENT) {
|
||||
radios.unshift({ value: 'all', label: this.$t('cmdb.ciType.allNodes') })
|
||||
}
|
||||
|
||||
if (this.adrType !== 'agent' || this?.currentAdr?.is_plugin) {
|
||||
if (this.adrType !== DISCOVERY_CATEGORY_TYPE.AGENTv || this?.currentAdr?.is_plugin) {
|
||||
radios.unshift({ value: 'master', label: this.$t('cmdb.ciType.masterNode') })
|
||||
}
|
||||
|
||||
return radios
|
||||
},
|
||||
radioList() {
|
||||
return [
|
||||
{ value: 'interval', label: this.$t('cmdb.ciType.byInterval') },
|
||||
{ value: 'cron', label: '按cron', layout: 'vertical' },
|
||||
]
|
||||
},
|
||||
labelCol() {
|
||||
const span = this.$i18n.locale === 'en' ? 5 : 3
|
||||
const isEn = this.$i18n.locale === 'en'
|
||||
return {
|
||||
span
|
||||
xl: {
|
||||
span: isEn ? 4 : 2
|
||||
},
|
||||
lg: {
|
||||
span: isEn ? 5 : 3
|
||||
},
|
||||
sm: {
|
||||
span: isEn ? 6 : 4
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -324,7 +342,7 @@ export default {
|
|||
this.uniqueKey = _find?.unique_key ?? ''
|
||||
this.isClient = _findADT?.isClient ?? false
|
||||
|
||||
if (this.adrType === 'http') {
|
||||
if (this.adrType === DISCOVERY_CATEGORY_TYPE.HTTP) {
|
||||
const {
|
||||
category = undefined,
|
||||
key = '',
|
||||
|
@ -358,7 +376,7 @@ export default {
|
|||
}
|
||||
} else {
|
||||
this.isPrivateCloud = false
|
||||
this.form2 = {
|
||||
this.publicCloudForm = {
|
||||
key,
|
||||
secret,
|
||||
_reference,
|
||||
|
@ -371,23 +389,47 @@ export default {
|
|||
this.$refs.httpForm.init(this.adr_id)
|
||||
})
|
||||
}
|
||||
if (this.adrType === 'snmp') {
|
||||
this.nodes = _findADT?.extra_option?.nodes?.length ? _findADT?.extra_option?.nodes : [
|
||||
|
||||
if (this.adrType === DISCOVERY_CATEGORY_TYPE.COMPONENT) {
|
||||
const {
|
||||
cidr = '',
|
||||
ports = '',
|
||||
enable_cidr = '',
|
||||
} = _findADT?.extra_option ?? {}
|
||||
this.portScanConfigForm = {
|
||||
cidr,
|
||||
ports,
|
||||
enable_cidr
|
||||
}
|
||||
}
|
||||
|
||||
if (this.adrType === DISCOVERY_CATEGORY_TYPE.SNMP) {
|
||||
const nodes = _findADT?.extra_option?.nodes?.length ? _findADT?.extra_option?.nodes : [
|
||||
{
|
||||
id: uuidv4(),
|
||||
ip: '',
|
||||
community: '',
|
||||
community: 'public',
|
||||
version: '',
|
||||
},
|
||||
]
|
||||
this.nodes = nodes
|
||||
this.$nextTick(() => {
|
||||
this.$refs.nodeSetting.initNodesFunc()
|
||||
this.$nextTick(() => {
|
||||
this.$refs.nodeSetting.setNodeField()
|
||||
})
|
||||
|
||||
let cidrList = []
|
||||
const cidr = _findADT?.extra_option?.cidr
|
||||
if (Array.isArray(cidr) && cidr?.length) {
|
||||
cidrList = cidr.map((v) => {
|
||||
return {
|
||||
id: uuidv4(),
|
||||
value: v?.value ? v.value : v
|
||||
}
|
||||
})
|
||||
}
|
||||
if (this.adrType === 'agent') {
|
||||
this.cidrList = cidrList
|
||||
}
|
||||
if (this.adrType === DISCOVERY_CATEGORY_TYPE.AGENT) {
|
||||
this.tableData = (_find?.attributes || []).map((item) => {
|
||||
if (_findADT.attributes) {
|
||||
return {
|
||||
|
@ -420,7 +462,6 @@ export default {
|
|||
this.agent_type = this.agentTypeRadioList[0].value
|
||||
}
|
||||
|
||||
this.interval = 'cron'
|
||||
this.cron = _findADT?.cron || ''
|
||||
},
|
||||
|
||||
|
@ -431,13 +472,12 @@ export default {
|
|||
const { currentAdt } = this
|
||||
let params
|
||||
|
||||
// 校验 HTTP 表单
|
||||
if (this.adrType === DISCOVERY_CATEGORY_TYPE.HTTP) {
|
||||
const { isError, data: cloudOption } = this.validateHTTPForm()
|
||||
if (isError) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.adrType === 'http') {
|
||||
params = {
|
||||
extra_option: {
|
||||
...cloudOption,
|
||||
|
@ -445,12 +485,25 @@ export default {
|
|||
},
|
||||
}
|
||||
}
|
||||
if (this.adrType === 'snmp') {
|
||||
|
||||
if (this.adrType === DISCOVERY_CATEGORY_TYPE.COMPONENT) {
|
||||
const portScanConfigForm = _.omitBy(this.portScanConfigForm, _.isEmpty) || {}
|
||||
params = {
|
||||
extra_option: { nodes: this.$refs.nodeSetting?.getNodeValue() ?? [] },
|
||||
extra_option: {
|
||||
...portScanConfigForm,
|
||||
},
|
||||
}
|
||||
}
|
||||
if (this.adrType === 'agent') {
|
||||
|
||||
if (this.adrType === DISCOVERY_CATEGORY_TYPE.SNMP) {
|
||||
params = {
|
||||
extra_option: {
|
||||
nodes: this.$refs.nodeSetting?.getNodeValue() ?? [],
|
||||
cidr: this?.cidrList?.map((item) => item.value) || []
|
||||
},
|
||||
}
|
||||
}
|
||||
if (this.adrType === DISCOVERY_CATEGORY_TYPE.AGENT) {
|
||||
const $table = this.$refs.attrMapTable
|
||||
const { fullData: _tableData } = $table.getTableData()
|
||||
const attributes = {}
|
||||
|
@ -481,7 +534,7 @@ export default {
|
|||
...params,
|
||||
...this.form,
|
||||
adr_id: currentAdt.adr_id,
|
||||
cron: this.interval === 'cron' ? this.cron : null,
|
||||
cron: this.cron,
|
||||
}
|
||||
|
||||
if (this.agent_type === 'agent_id' || this.agent_type === 'all') {
|
||||
|
@ -534,12 +587,15 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* HTTP 表单校验
|
||||
* 公有云 私有云
|
||||
*/
|
||||
validateHTTPForm() {
|
||||
let isError = false
|
||||
let data = {}
|
||||
|
||||
if (this.adrType === 'http') {
|
||||
const formData = this?.[this.isPrivateCloud ? 'privateCloudForm' : 'form2']
|
||||
const formData = this?.[this.isPrivateCloud ? 'privateCloudForm' : 'publicCloudForm']
|
||||
if (formData.tabActive === TAB_KEY.CONFIG) {
|
||||
if (!formData._reference) {
|
||||
isError = true
|
||||
|
@ -572,18 +628,17 @@ export default {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
data = _.pick(this.form2, ['key', 'secret'])
|
||||
data = _.pick(this.publicCloudForm, ['key', 'secret'])
|
||||
const publicCloudErros = {
|
||||
'key': `${this.$t('placeholder1')} key`,
|
||||
'secret': `${this.$t('placeholder1')} secret`
|
||||
}
|
||||
const findError = Object.keys(this.form2).find((key) => !this.form2[key] && publicCloudErros[key])
|
||||
const findError = Object.keys(this.publicCloudForm).find((key) => !this.publicCloudForm[key] && publicCloudErros[key])
|
||||
if (findError) {
|
||||
isError = true
|
||||
this.$message.error(this.$t(publicCloudErros[findError]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
isError,
|
||||
|
@ -591,6 +646,9 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 去除多余旧配置
|
||||
*/
|
||||
handleOldExtraOption(option) {
|
||||
let extra_option = _.cloneDeep(option)
|
||||
|
||||
|
@ -600,7 +658,7 @@ export default {
|
|||
}
|
||||
|
||||
// 根据 HTTP 选项去除多余属性
|
||||
const formData = this?.[this.isPrivateCloud ? 'privateCloudForm' : 'form2']
|
||||
const formData = this?.[this.isPrivateCloud ? 'privateCloudForm' : 'publicCloudForm']
|
||||
switch (formData.tabActive) {
|
||||
case TAB_KEY.CUSTOM:
|
||||
Reflect.deleteProperty(extra_option, '_reference')
|
||||
|
@ -694,6 +752,7 @@ export default {
|
|||
.radio-master-tip {
|
||||
font-size: 12px;
|
||||
color: #86909c;
|
||||
line-height: 14px;
|
||||
}
|
||||
}
|
||||
.attr-ad-snmp-form {
|
||||
|
|
|
@ -375,6 +375,10 @@
|
|||
name="is_computed"
|
||||
v-decorator="['is_computed', { rules: [], valuePropName: 'checked' }]"
|
||||
/>
|
||||
<div v-show="isShowComputedArea" class="computed-attr-tip">
|
||||
<div>1. {{ $t('cmdb.ciType.computedAttrTip1') }}</div>
|
||||
<div>2. {{ $t('cmdb.ciType.computedAttrTip2') }}</div>
|
||||
</div>
|
||||
<ComputedArea
|
||||
showCalcComputed
|
||||
ref="computedArea"
|
||||
|
@ -795,7 +799,13 @@ export default {
|
|||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
<style lang="less" scoped>
|
||||
.computed-attr-tip {
|
||||
font-size: 12px;
|
||||
line-height: 22px;
|
||||
color: #a5a9bc;
|
||||
}
|
||||
</style>
|
||||
<style lang="less">
|
||||
.attribute-edit-form {
|
||||
.jsoneditor-outer {
|
||||
|
|
|
@ -255,6 +255,12 @@ export default {
|
|||
show_id: () => {
|
||||
return this.show_id
|
||||
},
|
||||
providerGroupsData: () => {
|
||||
return {
|
||||
CITypeGroups: this.CITypeGroups,
|
||||
otherGroupAttributes: this.otherGroupAttributes
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeCreate() {},
|
||||
|
|
|
@ -363,6 +363,10 @@
|
|||
name="is_computed"
|
||||
v-decorator="['is_computed', { rules: [], valuePropName: 'checked' }]"
|
||||
/>
|
||||
<div v-show="isShowComputedArea" class="computed-attr-tip">
|
||||
<div>1. {{ $t('cmdb.ciType.computedAttrTip1') }}</div>
|
||||
<div>2. {{ $t('cmdb.ciType.computedAttrTip2') }}</div>
|
||||
</div>
|
||||
<ComputedArea ref="computedArea" v-if="isShowComputedArea" :canDefineComputed="canDefineComputed" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
@ -610,6 +614,13 @@ export default {
|
|||
},
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.computed-attr-tip {
|
||||
font-size: 12px;
|
||||
line-height: 22px;
|
||||
color: #a5a9bc;
|
||||
}
|
||||
</style>
|
||||
<style lang="less">
|
||||
.create-new-attribute {
|
||||
.jsoneditor-outer {
|
||||
|
|
|
@ -13,18 +13,26 @@
|
|||
@input="onCodeChange"
|
||||
></codemirror>
|
||||
</a-tab-pane>
|
||||
<template slot="tabBarExtraContent" v-if="showCalcComputed">
|
||||
<a-button type="primary" size="small" @click="handleCalcComputed">
|
||||
<template slot="tabBarExtraContent">
|
||||
<a-button size="small" @click="showAllPropDrawer">
|
||||
{{ $t('cmdb.ciType.viewAllAttr') }}
|
||||
</a-button>
|
||||
<AllAttrDrawer ref="allAttrDrawer" />
|
||||
|
||||
<template v-if="showCalcComputed">
|
||||
<a-button style="margin: 0px 5px;" type="primary" size="small" @click="handleCalcComputed">
|
||||
{{ $t('cmdb.ciType.apply') }}
|
||||
</a-button>
|
||||
<a-tooltip :title="$t('cmdb.ciType.computeForAllCITips')">
|
||||
<a-icon type="question-circle" style="margin-left:5px" />
|
||||
<a-icon type="question-circle" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</template>
|
||||
</a-tabs>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AllAttrDrawer from './allAttrDrawer.vue'
|
||||
import { codemirror } from 'vue-codemirror'
|
||||
import 'codemirror/lib/codemirror.css'
|
||||
import 'codemirror/theme/monokai.css'
|
||||
|
@ -32,7 +40,10 @@ import 'codemirror/theme/monokai.css'
|
|||
require('codemirror/mode/python/python.js')
|
||||
export default {
|
||||
name: 'ComputedArea',
|
||||
components: { codemirror },
|
||||
components: {
|
||||
codemirror,
|
||||
AllAttrDrawer
|
||||
},
|
||||
props: {
|
||||
canDefineComputed: {
|
||||
type: Boolean,
|
||||
|
@ -108,6 +119,9 @@ export default {
|
|||
},
|
||||
onCodeChange(v) {
|
||||
this.compute_script = v.replace('\t', ' ')
|
||||
},
|
||||
showAllPropDrawer() {
|
||||
this.$refs.allAttrDrawer.open()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
@ -388,7 +388,7 @@ export default {
|
|||
this.logModalVisible = true
|
||||
const logRes = await getAdcExecHistories({
|
||||
type_id: this.currentType,
|
||||
page_size: 1000
|
||||
last_size: 1000
|
||||
})
|
||||
let logTextArray = []
|
||||
if (logRes?.result?.length) {
|
||||
|
|
Loading…
Reference in New Issue