mirror of https://github.com/veops/cmdb.git
feat(ui): add bool and reference type
This commit is contained in:
parent
23c3ac44bf
commit
09b10eec45
|
@ -54,6 +54,12 @@
|
|||
<div class="content unicode" style="display: block;">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">duose-changwenben (1)</div>
|
||||
<div class="code-name">&#xe997;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">duose-quote</div>
|
||||
|
@ -5508,9 +5514,9 @@
|
|||
<pre><code class="language-css"
|
||||
>@font-face {
|
||||
font-family: 'iconfont';
|
||||
src: url('iconfont.woff2?t=1723012344599') format('woff2'),
|
||||
url('iconfont.woff?t=1723012344599') format('woff'),
|
||||
url('iconfont.ttf?t=1723012344599') format('truetype');
|
||||
src: url('iconfont.woff2?t=1724135954264') format('woff2'),
|
||||
url('iconfont.woff?t=1724135954264') format('woff'),
|
||||
url('iconfont.ttf?t=1724135954264') format('truetype');
|
||||
}
|
||||
</code></pre>
|
||||
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
|
||||
|
@ -5536,6 +5542,15 @@
|
|||
<div class="content font-class">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont duose-changwenben1"></span>
|
||||
<div class="name">
|
||||
duose-changwenben (1)
|
||||
</div>
|
||||
<div class="code-name">.duose-changwenben1
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont duose-quote"></span>
|
||||
<div class="name">
|
||||
|
@ -13717,6 +13732,14 @@
|
|||
<div class="content symbol">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#duose-changwenben1"></use>
|
||||
</svg>
|
||||
<div class="name">duose-changwenben (1)</div>
|
||||
<div class="code-name">#duose-changwenben1</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#duose-quote"></use>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 3857903 */
|
||||
src: url('iconfont.woff2?t=1723012344599') format('woff2'),
|
||||
url('iconfont.woff?t=1723012344599') format('woff'),
|
||||
url('iconfont.ttf?t=1723012344599') format('truetype');
|
||||
src: url('iconfont.woff2?t=1724135954264') format('woff2'),
|
||||
url('iconfont.woff?t=1724135954264') format('woff'),
|
||||
url('iconfont.ttf?t=1724135954264') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
|
@ -13,6 +13,10 @@
|
|||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.duose-changwenben1:before {
|
||||
content: "\e997";
|
||||
}
|
||||
|
||||
.duose-quote:before {
|
||||
content: "\e995";
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -5,6 +5,13 @@
|
|||
"css_prefix_text": "",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "41437322",
|
||||
"name": "duose-changwenben (1)",
|
||||
"font_class": "duose-changwenben1",
|
||||
"unicode": "e997",
|
||||
"unicode_decimal": 59799
|
||||
},
|
||||
{
|
||||
"icon_id": "41363381",
|
||||
"name": "duose-quote",
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,18 @@
|
|||
import { axios } from '@/utils/request'
|
||||
|
||||
export function searchCI(params, isShowMessage = true) {
|
||||
return axios({
|
||||
url: `/v0.1/ci/s`,
|
||||
method: 'GET',
|
||||
params: params,
|
||||
isShowMessage
|
||||
})
|
||||
}
|
||||
|
||||
export function getCIType(CITypeName, parameter) {
|
||||
return axios({
|
||||
url: `/v0.1/ci_types/${CITypeName}`,
|
||||
method: 'GET',
|
||||
params: parameter
|
||||
})
|
||||
}
|
|
@ -1,346 +1,389 @@
|
|||
<template>
|
||||
<div>
|
||||
<a-space :style="{ display: 'flex', marginBottom: '10px' }" v-for="(item, index) in ruleList" :key="item.id">
|
||||
<div :style="{ width: '70px', height: '24px', position: 'relative' }">
|
||||
<treeselect
|
||||
v-if="index"
|
||||
class="custom-treeselect"
|
||||
:style="{ width: '70px', '--custom-height': '24px', position: 'absolute', top: '-17px', left: 0 }"
|
||||
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: '130px', '--custom-height': '24px' }"
|
||||
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
|
||||
:title="node.label"
|
||||
slot="option-label"
|
||||
slot-scope="{ node }"
|
||||
:style="{ width: '100%', whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' }"
|
||||
>
|
||||
<ValueTypeMapIcon :attr="node.raw" />
|
||||
{{ node.label }}
|
||||
</div>
|
||||
<div
|
||||
:style="{ width: '100%', whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' }"
|
||||
slot="value-label"
|
||||
slot-scope="{ node }"
|
||||
>
|
||||
<ValueTypeMapIcon :attr="node.raw" /> {{ node.label }}
|
||||
</div>
|
||||
</treeselect>
|
||||
<treeselect
|
||||
class="custom-treeselect"
|
||||
:style="{ width: '100px', '--custom-height': '24px' }"
|
||||
v-model="item.exp"
|
||||
:multiple="false"
|
||||
:clearable="false"
|
||||
searchable
|
||||
:options="[...getExpListByProperty(item.property), ...advancedExpList]"
|
||||
:normalizer="
|
||||
(node) => {
|
||||
return {
|
||||
id: node.value,
|
||||
label: node.label,
|
||||
children: node.children,
|
||||
}
|
||||
}
|
||||
"
|
||||
@select="(value) => handleChangeExp(value, item, index)"
|
||||
appendToBody
|
||||
:zIndex="1050"
|
||||
:disabled="disabled"
|
||||
>
|
||||
</treeselect>
|
||||
<treeselect
|
||||
class="custom-treeselect"
|
||||
:style="{ width: '175px', '--custom-height': '24px' }"
|
||||
v-model="item.value"
|
||||
:multiple="false"
|
||||
:clearable="false"
|
||||
searchable
|
||||
v-if="isChoiceByProperty(item.property) && (item.exp === 'is' || item.exp === '~is')"
|
||||
:options="getChoiceValueByProperty(item.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>
|
||||
<a-input-group
|
||||
size="small"
|
||||
compact
|
||||
v-else-if="item.exp === 'range' || item.exp === '~range'"
|
||||
:style="{ width: '175px' }"
|
||||
>
|
||||
<a-input
|
||||
class="ops-input"
|
||||
size="small"
|
||||
v-model="item.min"
|
||||
:style="{ width: '78px' }"
|
||||
:placeholder="$t('min')"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
~
|
||||
<a-input
|
||||
class="ops-input"
|
||||
size="small"
|
||||
v-model="item.max"
|
||||
:style="{ width: '78px' }"
|
||||
:placeholder="$t('max')"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
</a-input-group>
|
||||
<a-input-group size="small" compact v-else-if="item.exp === 'compare'" :style="{ width: '175px' }">
|
||||
<treeselect
|
||||
class="custom-treeselect"
|
||||
:style="{ width: '60px', '--custom-height': '24px' }"
|
||||
v-model="item.compareType"
|
||||
: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 class="ops-input" v-model="item.value" size="small" style="width: 113px" />
|
||||
</a-input-group>
|
||||
<a-input
|
||||
v-else-if="item.exp !== 'value' && item.exp !== '~value'"
|
||||
size="small"
|
||||
v-model="item.value"
|
||||
:placeholder="item.exp === 'in' || item.exp === '~in' ? $t('cmdbFilterComp.split', { separator: ';' }) : ''"
|
||||
class="ops-input"
|
||||
:style="{ width: '175px' }"
|
||||
:disabled="disabled"
|
||||
></a-input>
|
||||
<div v-else :style="{ width: '175px' }"></div>
|
||||
<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)"><ops-icon type="icon-xianxing-delete"/></a>
|
||||
</a-tooltip>
|
||||
<a-tooltip :title="$t('cmdbFilterComp.addHere')" v-if="needAddHere">
|
||||
<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">
|
||||
<a @click="handleAddRule">+ {{ $t('new') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { ruleTypeList, expList, advancedExpList, compareTypeList } from './constants'
|
||||
import ValueTypeMapIcon from '../CMDBValueTypeMapIcon'
|
||||
|
||||
export default {
|
||||
name: 'Expression',
|
||||
components: { ValueTypeMapIcon },
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'change',
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
canSearchPreferenceAttrList: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => [],
|
||||
},
|
||||
needAddHere: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
compareTypeList,
|
||||
}
|
||||
},
|
||||
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) {
|
||||
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') },
|
||||
]
|
||||
}
|
||||
return this.expList
|
||||
}
|
||||
return this.expList
|
||||
},
|
||||
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, 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)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
<template>
|
||||
<div>
|
||||
<a-space :style="{ display: 'flex', marginBottom: '10px' }" v-for="(item, index) in ruleList" :key="item.id">
|
||||
<div :style="{ width: '70px', height: '24px', position: 'relative' }">
|
||||
<treeselect
|
||||
v-if="index"
|
||||
class="custom-treeselect"
|
||||
:style="{ width: '70px', '--custom-height': '24px', position: 'absolute', top: '-17px', left: 0 }"
|
||||
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: '130px', '--custom-height': '24px' }"
|
||||
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
|
||||
:title="node.label"
|
||||
slot="option-label"
|
||||
slot-scope="{ node }"
|
||||
:style="{ width: '100%', whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' }"
|
||||
>
|
||||
<ValueTypeMapIcon :attr="node.raw" />
|
||||
{{ node.label }}
|
||||
</div>
|
||||
<div
|
||||
:style="{ width: '100%', whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' }"
|
||||
slot="value-label"
|
||||
slot-scope="{ node }"
|
||||
>
|
||||
<ValueTypeMapIcon :attr="node.raw" /> {{ node.label }}
|
||||
</div>
|
||||
</treeselect>
|
||||
<treeselect
|
||||
class="custom-treeselect"
|
||||
:style="{ width: '100px', '--custom-height': '24px' }"
|
||||
v-model="item.exp"
|
||||
:multiple="false"
|
||||
:clearable="false"
|
||||
searchable
|
||||
:options="[...getExpListByProperty(item.property), ...advancedExpList]"
|
||||
:normalizer="
|
||||
(node) => {
|
||||
return {
|
||||
id: node.value,
|
||||
label: node.label,
|
||||
children: node.children,
|
||||
}
|
||||
}
|
||||
"
|
||||
@select="(value) => handleChangeExp(value, item, index)"
|
||||
appendToBody
|
||||
:zIndex="1050"
|
||||
:disabled="disabled"
|
||||
>
|
||||
</treeselect>
|
||||
<CIReferenceAttr
|
||||
v-if="getAttr(item.property).is_reference && (item.exp === 'is' || item.exp === '~is')"
|
||||
:style="{ width: '175px' }"
|
||||
class="select-filter-component"
|
||||
:referenceTypeId="getAttr(item.property).reference_type_id"
|
||||
:disabled="disabled"
|
||||
v-model="item.value"
|
||||
/>
|
||||
<a-select
|
||||
v-else-if="getAttr(item.property).is_bool && (item.exp === 'is' || item.exp === '~is')"
|
||||
v-model="item.value"
|
||||
class="select-filter-component"
|
||||
:style="{ width: '175px' }"
|
||||
:disabled="disabled"
|
||||
:placeholder="$t('placeholder2')"
|
||||
>
|
||||
<a-select-option key="1">
|
||||
true
|
||||
</a-select-option>
|
||||
<a-select-option key="0">
|
||||
false
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<treeselect
|
||||
class="custom-treeselect"
|
||||
:style="{ width: '175px', '--custom-height': '24px' }"
|
||||
v-model="item.value"
|
||||
:multiple="false"
|
||||
:clearable="false"
|
||||
searchable
|
||||
v-else-if="isChoiceByProperty(item.property) && (item.exp === 'is' || item.exp === '~is')"
|
||||
:options="getChoiceValueByProperty(item.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>
|
||||
<a-input-group
|
||||
size="small"
|
||||
compact
|
||||
v-else-if="item.exp === 'range' || item.exp === '~range'"
|
||||
:style="{ width: '175px' }"
|
||||
>
|
||||
<a-input
|
||||
class="ops-input"
|
||||
size="small"
|
||||
v-model="item.min"
|
||||
:style="{ width: '78px' }"
|
||||
:placeholder="$t('min')"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
~
|
||||
<a-input
|
||||
class="ops-input"
|
||||
size="small"
|
||||
v-model="item.max"
|
||||
:style="{ width: '78px' }"
|
||||
:placeholder="$t('max')"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
</a-input-group>
|
||||
<a-input-group size="small" compact v-else-if="item.exp === 'compare'" :style="{ width: '175px' }">
|
||||
<treeselect
|
||||
class="custom-treeselect"
|
||||
:style="{ width: '60px', '--custom-height': '24px' }"
|
||||
v-model="item.compareType"
|
||||
: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 class="ops-input" v-model="item.value" size="small" style="width: 113px" />
|
||||
</a-input-group>
|
||||
<a-input
|
||||
v-else-if="item.exp !== 'value' && item.exp !== '~value'"
|
||||
size="small"
|
||||
v-model="item.value"
|
||||
:placeholder="item.exp === 'in' || item.exp === '~in' ? $t('cmdbFilterComp.split', { separator: ';' }) : ''"
|
||||
class="ops-input"
|
||||
:style="{ width: '175px' }"
|
||||
:disabled="disabled"
|
||||
></a-input>
|
||||
<div v-else :style="{ width: '175px' }"></div>
|
||||
<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)"><ops-icon type="icon-xianxing-delete"/></a>
|
||||
</a-tooltip>
|
||||
<a-tooltip :title="$t('cmdbFilterComp.addHere')" v-if="needAddHere">
|
||||
<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">
|
||||
<a @click="handleAddRule">+ {{ $t('new') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { ruleTypeList, expList, advancedExpList, compareTypeList } from './constants'
|
||||
import ValueTypeMapIcon from '../CMDBValueTypeMapIcon'
|
||||
import CIReferenceAttr from '../ciReferenceAttr/index.vue'
|
||||
|
||||
export default {
|
||||
name: 'Expression',
|
||||
components: { ValueTypeMapIcon, CIReferenceAttr },
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'change',
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
canSearchPreferenceAttrList: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => [],
|
||||
},
|
||||
needAddHere: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
compareTypeList,
|
||||
}
|
||||
},
|
||||
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) {
|
||||
const _find = this.canSearchPreferenceAttrList.find((item) => item.name === property)
|
||||
if (_find && (['0', '1', '3', '4', '5'].includes(_find.value_type) || _find.is_reference || _find.is_bool)) {
|
||||
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') },
|
||||
]
|
||||
}
|
||||
return this.expList
|
||||
}
|
||||
return this.expList
|
||||
},
|
||||
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, 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 []
|
||||
},
|
||||
getAttr(property) {
|
||||
return this.canSearchPreferenceAttrList.find((item) => item.name === property) || {}
|
||||
},
|
||||
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)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.select-filter-component {
|
||||
height: 24px;
|
||||
|
||||
/deep/ .ant-select-selection {
|
||||
height: 24px;
|
||||
background: #f7f8fa;
|
||||
line-height: 24px;
|
||||
border: none;
|
||||
|
||||
.ant-select-selection__rendered {
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,49 +1,77 @@
|
|||
<template>
|
||||
<span>
|
||||
<ops-icon :type="getPropertyIcon(attr)" />
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ValueTypeIcon',
|
||||
props: {
|
||||
attr: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getPropertyIcon(attr) {
|
||||
switch (attr.value_type) {
|
||||
case '0':
|
||||
return 'duose-shishu'
|
||||
case '1':
|
||||
return 'duose-fudianshu'
|
||||
case '2':
|
||||
if (attr.is_password) {
|
||||
return 'duose-password'
|
||||
}
|
||||
if (attr.is_link) {
|
||||
return 'duose-link'
|
||||
}
|
||||
return 'duose-wenben'
|
||||
case '3':
|
||||
return 'duose-datetime'
|
||||
case '4':
|
||||
return 'duose-date'
|
||||
case '5':
|
||||
return 'duose-time'
|
||||
case '6':
|
||||
return 'duose-json'
|
||||
case '7':
|
||||
return 'duose-password'
|
||||
case '8':
|
||||
return 'duose-link'
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
<template>
|
||||
<span>
|
||||
<ops-icon :type="getPropertyIcon(attr)" />
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ValueTypeIcon',
|
||||
props: {
|
||||
attr: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getPropertyIcon(attr) {
|
||||
let valueType = attr.value_type
|
||||
|
||||
if (valueType === '2') {
|
||||
if (attr.is_password) {
|
||||
valueType = '7'
|
||||
} else if (attr.is_link) {
|
||||
valueType = '8'
|
||||
} else if (!attr.is_index) {
|
||||
valueType = '9'
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
valueType === '7' &&
|
||||
attr.is_bool
|
||||
) {
|
||||
valueType = '10'
|
||||
}
|
||||
|
||||
if (
|
||||
valueType === '0' &&
|
||||
attr.is_reference
|
||||
) {
|
||||
valueType = '11'
|
||||
}
|
||||
|
||||
switch (valueType) {
|
||||
case '0':
|
||||
return 'duose-shishu'
|
||||
case '1':
|
||||
return 'duose-fudianshu'
|
||||
case '2':
|
||||
return 'duose-wenben'
|
||||
case '3':
|
||||
return 'duose-datetime'
|
||||
case '4':
|
||||
return 'duose-date'
|
||||
case '5':
|
||||
return 'duose-time'
|
||||
case '6':
|
||||
return 'duose-json'
|
||||
case '7':
|
||||
return 'duose-password'
|
||||
case '8':
|
||||
return 'duose-link'
|
||||
case '9':
|
||||
return 'duose-changwenben1'
|
||||
case '10':
|
||||
return 'duose-boole'
|
||||
case '11':
|
||||
return 'duose-quote'
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
|
|
@ -61,7 +61,13 @@
|
|||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<a-input ref="regInput" :placeholder="$t('regexSelect.placeholder')" :value="current.label" @change="changeLabel">
|
||||
<a-input
|
||||
ref="regInput"
|
||||
:placeholder="$t('regexSelect.placeholder')"
|
||||
:value="current.label"
|
||||
:disabled="disabled"
|
||||
@change="changeLabel"
|
||||
>
|
||||
</a-input>
|
||||
</a-popover>
|
||||
</template>
|
||||
|
@ -88,6 +94,10 @@ export default {
|
|||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
<template>
|
||||
<div class="reference-attr-select-wrap">
|
||||
<a-select
|
||||
v-bind="$attrs"
|
||||
v-model="selectCIIds"
|
||||
optionFilterProp="title"
|
||||
:mode="isList ? 'multiple' : 'default'"
|
||||
showSearch
|
||||
allowClear
|
||||
:getPopupContainer="(trigger) => trigger.parentElement"
|
||||
class="reference-attr-select"
|
||||
:maxTagCount="2"
|
||||
@dropdownVisibleChange="handleDropdownVisibleChange"
|
||||
@search="handleSearch"
|
||||
@change="handleChange"
|
||||
>
|
||||
<template v-if="!isInit">
|
||||
<a-select-option
|
||||
v-for="(item) in initSelectOption"
|
||||
:key="item.key"
|
||||
:title="item.title"
|
||||
>
|
||||
{{ item.title }}
|
||||
</a-select-option>
|
||||
</template>
|
||||
<a-select-option
|
||||
v-for="(item) in options"
|
||||
:key="item.key"
|
||||
:title="item.title"
|
||||
>
|
||||
{{ item.title }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import debounce from 'lodash/debounce'
|
||||
import { searchCI, getCIType } from '@/api/cmdb'
|
||||
|
||||
export default {
|
||||
name: 'CIReferenceAttr',
|
||||
props: {
|
||||
value: {
|
||||
type: [Number, String, Array],
|
||||
default: () => '',
|
||||
},
|
||||
isList: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
referenceShowAttrName: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
referenceTypeId: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
initSelectOption: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'change',
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isInit: false,
|
||||
options: [],
|
||||
innerReferenceShowAttrName: ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
referenceTypeId: {
|
||||
immediate: true,
|
||||
deep: true,
|
||||
handler() {
|
||||
this.isInit = false
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
selectCIIds: {
|
||||
get() {
|
||||
if (this.isList) {
|
||||
return this.value || []
|
||||
} else {
|
||||
return this.value ? Number(this.value) : ''
|
||||
}
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('change', val ?? (this.isList ? [] : null))
|
||||
return val
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async handleDropdownVisibleChange(open) {
|
||||
if (!this.isInit && open && this.referenceTypeId) {
|
||||
this.isInit = true
|
||||
|
||||
if (!this.referenceShowAttrName) {
|
||||
const res = await getCIType(this.referenceTypeId)
|
||||
const ciType = res?.ci_types?.[0]
|
||||
this.innerReferenceShowAttrName = ciType?.show_name || ciType?.unique_name || ''
|
||||
}
|
||||
|
||||
const attrName = this.referenceShowAttrName || this.innerReferenceShowAttrName || ''
|
||||
if (!attrName) {
|
||||
return
|
||||
}
|
||||
|
||||
const res = await searchCI({
|
||||
q: `_type:${this.referenceTypeId}`,
|
||||
fl: attrName,
|
||||
count: 25,
|
||||
})
|
||||
|
||||
let options = res?.result?.map((item) => {
|
||||
return {
|
||||
key: item._id,
|
||||
title: String(item?.[attrName] ?? '')
|
||||
}
|
||||
})
|
||||
|
||||
options = _.uniqBy([...this.initSelectOption, ...options], 'key')
|
||||
|
||||
this.options = options
|
||||
}
|
||||
},
|
||||
|
||||
handleSearch: debounce(async function(v) {
|
||||
const attrName = this.referenceShowAttrName || this.innerReferenceShowAttrName || ''
|
||||
|
||||
if (!attrName || !this.referenceTypeId) {
|
||||
return
|
||||
}
|
||||
|
||||
const res = await searchCI({
|
||||
q: `_type:${this.referenceTypeId}${v ? ',*' + v + '*' : ''}`,
|
||||
fl: attrName,
|
||||
count: v ? 100 : 25,
|
||||
})
|
||||
|
||||
this.options = res?.result?.map((item) => {
|
||||
return {
|
||||
key: item._id,
|
||||
title: String(item?.[attrName] ?? '')
|
||||
}
|
||||
})
|
||||
}, 300),
|
||||
|
||||
handleChange(v) {
|
||||
if (Array.isArray(v) ? !v.length : !v) {
|
||||
this.handleSearch()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.reference-attr-select-wrap {
|
||||
width: 100%;
|
||||
|
||||
.reference-attr-select {
|
||||
width: 100%;
|
||||
|
||||
/deep/ .ant-select-dropdown {
|
||||
z-index: 15;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -8,6 +8,7 @@
|
|||
resizable
|
||||
ref="xTable"
|
||||
size="small"
|
||||
:data="data"
|
||||
:loading="loading"
|
||||
:row-config="{ useKey: true, keyField: '_id' }"
|
||||
show-header-overflow
|
||||
|
@ -56,8 +57,20 @@
|
|||
<span>{{ col.title }}</span>
|
||||
</span>
|
||||
</template>
|
||||
<template v-if="col.is_choice || col.is_password" #edit="{ row }">
|
||||
<vxe-input v-if="col.is_password" v-model="passwordValue[col.field]" />
|
||||
<template v-if="col.is_choice || col.is_password || col.is_bool || col.is_reference" #edit="{ row }">
|
||||
<CIReferenceAttr
|
||||
v-if="col.is_reference"
|
||||
:referenceTypeId="col.reference_type_id"
|
||||
:isList="col.is_list"
|
||||
:referenceShowAttrName="referenceShowAttrNameMap[col.reference_type_id] || ''"
|
||||
:initSelectOption="getInitReferenceSelectOption(row[col.field], col)"
|
||||
v-model="row[col.field]"
|
||||
/>
|
||||
<a-switch
|
||||
v-else-if="col.is_bool"
|
||||
v-model="row[col.field]"
|
||||
/>
|
||||
<vxe-input v-else-if="col.is_password" v-model="passwordValue[col.field]" />
|
||||
<a-select
|
||||
v-if="col.is_choice"
|
||||
v-model="row[col.field]"
|
||||
|
@ -100,10 +113,20 @@
|
|||
</a-select>
|
||||
</template>
|
||||
<template
|
||||
v-if="col.value_type === '6' || col.is_link || col.is_password || col.is_choice"
|
||||
v-if="col.value_type === '6' || col.is_link || col.is_password || col.is_choice || col.is_reference"
|
||||
#default="{ row }"
|
||||
>
|
||||
<span v-if="col.value_type === '6' && row[col.field]">{{ row[col.field] }}</span>
|
||||
<template v-if="col.is_reference" >
|
||||
<a
|
||||
v-for="(ciId) in (col.is_list ? row[col.field] : [row[col.field]])"
|
||||
:key="ciId"
|
||||
:href="`/cmdb/cidetail/${col.reference_type_id}/${ciId}`"
|
||||
target="_blank"
|
||||
>
|
||||
{{ getReferenceAttrValue(ciId, col) }}
|
||||
</a>
|
||||
</template>
|
||||
<span v-else-if="col.value_type === '6' && row[col.field]">{{ row[col.field] }}</span>
|
||||
<template v-else-if="col.is_link && row[col.field]">
|
||||
<a
|
||||
v-for="(item, linkIndex) in (col.is_list ? row[col.field] : [row[col.field]])"
|
||||
|
@ -187,16 +210,21 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import { getCITypes } from '@/modules/cmdb/api/CIType'
|
||||
import { searchCI } from '@/modules/cmdb/api/ci'
|
||||
import JsonEditor from '../JsonEditor/jsonEditor.vue'
|
||||
import PasswordField from '../passwordField/index.vue'
|
||||
import { ops_move_icon as OpsMoveIcon } from '@/core/icons'
|
||||
import CIReferenceAttr from '@/components/ciReferenceAttr/index.vue'
|
||||
|
||||
export default {
|
||||
name: 'CITable',
|
||||
components: {
|
||||
JsonEditor,
|
||||
PasswordField,
|
||||
OpsMoveIcon
|
||||
OpsMoveIcon,
|
||||
CIReferenceAttr
|
||||
},
|
||||
props: {
|
||||
// table ID
|
||||
|
@ -237,6 +265,18 @@ export default {
|
|||
showDelete: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 表格数据
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
referenceShowAttrNameMap: {},
|
||||
referenceCIIdMap: {},
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -245,6 +285,46 @@ export default {
|
|||
const idx = this.columns.findIndex((item) => item.is_fixed)
|
||||
return idx > -1
|
||||
},
|
||||
tableDataWatch() {
|
||||
return {
|
||||
data: this.data,
|
||||
columns: this.columns
|
||||
}
|
||||
},
|
||||
referenceCIIdWatch() {
|
||||
const referenceTypeCol = this.columns?.filter((col) => col?.is_reference && col?.reference_type_id) || []
|
||||
if (!this.data?.length || !referenceTypeCol?.length) {
|
||||
return []
|
||||
}
|
||||
|
||||
const ids = []
|
||||
this.data.forEach((row) => {
|
||||
referenceTypeCol.forEach((col) => {
|
||||
if (row[col.field]) {
|
||||
ids.push(...(Array.isArray(row[col.field]) ? row[col.field] : [row[col.field]]))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return _.uniq(ids)
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
columns: {
|
||||
immediate: true,
|
||||
deep: true,
|
||||
handler(newVal) {
|
||||
this.handleReferenceShowAttrName(newVal)
|
||||
}
|
||||
},
|
||||
referenceCIIdWatch: {
|
||||
immediate: true,
|
||||
deep: true,
|
||||
handler() {
|
||||
this.handleReferenceCIIdMap()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
@ -330,6 +410,101 @@ export default {
|
|||
|
||||
getRowSeq(row) {
|
||||
return this.getVxetableRef().getRowSeq(row)
|
||||
},
|
||||
|
||||
async handleReferenceShowAttrName(columns) {
|
||||
const needRequiredCITypeIds = columns?.filter((col) => col?.is_reference && col?.reference_type_id).map((col) => col.reference_type_id) || []
|
||||
if (!needRequiredCITypeIds.length) {
|
||||
this.referenceShowAttrNameMap = {}
|
||||
return
|
||||
}
|
||||
|
||||
const res = await getCITypes({
|
||||
type_ids: needRequiredCITypeIds.join(',')
|
||||
})
|
||||
|
||||
const map = {}
|
||||
res.ci_types.forEach((ciType) => {
|
||||
map[ciType.id] = ciType?.show_name || ciType?.unique_name || ''
|
||||
})
|
||||
|
||||
this.referenceShowAttrNameMap = map
|
||||
},
|
||||
|
||||
async handleReferenceCIIdMap() {
|
||||
const referenceTypeCol = this.columns.filter((col) => col?.is_reference && col?.reference_type_id) || []
|
||||
if (!this.data?.length || !referenceTypeCol?.length) {
|
||||
this.referenceCIIdMap = {}
|
||||
return
|
||||
}
|
||||
|
||||
const map = {}
|
||||
this.data.forEach((row) => {
|
||||
referenceTypeCol.forEach((col) => {
|
||||
const ids = Array.isArray(row[col.field]) ? row[col.field] : row[col.field] ? [row[col.field]] : []
|
||||
if (ids.length) {
|
||||
if (!map?.[col.reference_type_id]) {
|
||||
map[col.reference_type_id] = {}
|
||||
}
|
||||
ids.forEach((id) => {
|
||||
map[col.reference_type_id][id] = {}
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
if (!Object.keys(map).length) {
|
||||
this.referenceCIIdMap = {}
|
||||
return
|
||||
}
|
||||
|
||||
const allRes = await Promise.all(
|
||||
Object.keys(map).map((key) => {
|
||||
return searchCI({
|
||||
q: `_type:${key},_id:(${Object.keys(map[key]).join(';')})`,
|
||||
count: 9999
|
||||
})
|
||||
})
|
||||
)
|
||||
|
||||
allRes.forEach((res) => {
|
||||
res.result.forEach((item) => {
|
||||
if (map?.[item._type]?.[item._id]) {
|
||||
map[item._type][item._id] = item
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
this.referenceCIIdMap = map
|
||||
},
|
||||
|
||||
getReferenceAttrValue(id, col) {
|
||||
const ci = this?.referenceCIIdMap?.[col?.reference_type_id]?.[id]
|
||||
if (!ci) {
|
||||
return id
|
||||
}
|
||||
|
||||
const attrName = this.referenceShowAttrNameMap?.[col.reference_type_id]
|
||||
return ci?.[attrName] || id
|
||||
},
|
||||
|
||||
getInitReferenceSelectOption(value, col) {
|
||||
const ids = Array.isArray(value) ? value : value ? [value] : []
|
||||
if (!ids.length) {
|
||||
return []
|
||||
}
|
||||
|
||||
const map = this?.referenceCIIdMap?.[col?.reference_type_id]
|
||||
const attrName = this.referenceShowAttrNameMap?.[col?.reference_type_id]
|
||||
|
||||
const option = (Array.isArray(value) ? value : [value]).map((id) => {
|
||||
return {
|
||||
key: id,
|
||||
title: map?.[id]?.[attrName] || id
|
||||
}
|
||||
})
|
||||
|
||||
return option
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,6 +113,11 @@ export default {
|
|||
this.editor.insertNode(node)
|
||||
}
|
||||
},
|
||||
destroy() {
|
||||
const editor = this.editor
|
||||
if (editor == null) return
|
||||
editor.destroy()
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -189,6 +189,14 @@ const cmdb_en = {
|
|||
confirmDeleteTrigger: 'Are you sure to delete this trigger?',
|
||||
int: 'Integer',
|
||||
float: 'Float',
|
||||
longText: 'Long Text',
|
||||
shortText: 'Short Text',
|
||||
shortTextTip: 'Text length <= 128',
|
||||
referenceModel: 'Reference Model',
|
||||
referenceModelTip: 'Please select reference model',
|
||||
referenceModelTip1: 'For quick view of referenced model instances',
|
||||
bool: 'Bool',
|
||||
reference: 'Reference',
|
||||
text: 'Text',
|
||||
datetime: 'DateTime',
|
||||
date: 'Date',
|
||||
|
@ -206,7 +214,7 @@ const cmdb_en = {
|
|||
otherGroupTips: 'Non sortable within the other group',
|
||||
filterTips: 'click to show {name}',
|
||||
attributeAssociation: 'Attribute Association',
|
||||
attributeAssociationTip1: 'Automatically establish relationships through the attributes except password, json and multiple of two models',
|
||||
attributeAssociationTip1: 'Automatically establish relationships through attribute values (except password, json, multi-value, long text, boolean, reference) of two models',
|
||||
attributeAssociationTip2: 'Double click to edit',
|
||||
attributeAssociationTip3: 'Two Attributes must be selected',
|
||||
attributeAssociationTip4: 'Please select a attribute from Source CIType',
|
||||
|
@ -282,6 +290,9 @@ const cmdb_en = {
|
|||
rule: 'Rule',
|
||||
cascadeAttr: 'Cascade',
|
||||
cascadeAttrTip: 'Cascading attributes note the order',
|
||||
enumValue: 'Value',
|
||||
label: 'Label',
|
||||
valueInputTip: 'Please input value'
|
||||
},
|
||||
components: {
|
||||
unselectAttributes: 'Unselected',
|
||||
|
@ -323,7 +334,7 @@ const cmdb_en = {
|
|||
pleaseSearch: 'Please search',
|
||||
conditionFilter: 'Conditional filtering',
|
||||
attributeDesc: 'Attribute Description',
|
||||
ciSearchTips: '1. JSON/password/link attributes cannot be searched\n2. If the search content includes commas, they need to be escaped\n3. Only index attributes are searched, non-index attributes use conditional filtering',
|
||||
ciSearchTips: '1. JSON/password/link/longText/reference attributes cannot be searched\n2. If the search content includes commas, they need to be escaped\n3. Only index attributes are searched, non-index attributes use conditional filtering',
|
||||
ciSearchTips2: 'For example: q=hostname:*0.0.0.0*',
|
||||
subCIType: 'Subscription CIType',
|
||||
already: 'already',
|
||||
|
@ -548,7 +559,7 @@ class AutoDiscovery(object):
|
|||
"""
|
||||
Define attribute fields
|
||||
:return: Returns a list of attribute fields. The list items are (name, type, description). The name must be in English.
|
||||
type: String Integer Float Date DateTime Time JSON
|
||||
type: String Integer Float Date DateTime Time JSON Bool Reference
|
||||
For example:
|
||||
return [
|
||||
("ci_type", "String", "CIType name"),
|
||||
|
|
|
@ -189,6 +189,14 @@ const cmdb_zh = {
|
|||
confirmDeleteTrigger: '确认删除该触发器吗?',
|
||||
int: '整数',
|
||||
float: '浮点数',
|
||||
longText: '长文本',
|
||||
shortText: '短文本',
|
||||
shortTextTip: '文本长度 <= 128',
|
||||
referenceModel: '引用模型',
|
||||
referenceModelTip: '请选择引用模型',
|
||||
referenceModelTip1: '用于快捷查看引用模型实例',
|
||||
bool: '布尔',
|
||||
reference: '引用',
|
||||
text: '文本',
|
||||
datetime: '日期时间',
|
||||
date: '日期',
|
||||
|
@ -206,7 +214,7 @@ const cmdb_zh = {
|
|||
otherGroupTips: '其他分组属性不可排序',
|
||||
filterTips: '点击可仅查看{name}属性',
|
||||
attributeAssociation: '属性关联',
|
||||
attributeAssociationTip1: '通过2个模型的属性值(除密码、json、多值)来自动建立关系',
|
||||
attributeAssociationTip1: '通过2个模型的属性值(除密码、json、多值、长文本、布尔、引用)来自动建立关系',
|
||||
attributeAssociationTip2: '双击可编辑',
|
||||
attributeAssociationTip3: '属性关联必须选择两个属性',
|
||||
attributeAssociationTip4: '请选择原模型属性',
|
||||
|
@ -282,6 +290,9 @@ const cmdb_zh = {
|
|||
rule: '规则',
|
||||
cascadeAttr: '级联',
|
||||
cascadeAttrTip: '级联属性注意顺序',
|
||||
enumValue: '枚举值',
|
||||
label: '标签',
|
||||
valueInputTip: '请输入枚举值'
|
||||
},
|
||||
components: {
|
||||
unselectAttributes: '未选属性',
|
||||
|
@ -323,7 +334,7 @@ const cmdb_zh = {
|
|||
pleaseSearch: '请查找',
|
||||
conditionFilter: '条件过滤',
|
||||
attributeDesc: '属性说明',
|
||||
ciSearchTips: '1. json、密码、链接属性不能搜索\n2. 搜索内容包括逗号, 则需转义\n3. 只搜索索引属性, 非索引属性使用条件过滤',
|
||||
ciSearchTips: '1. json、密码、链接、长文本、引用属性不能搜索\n2. 搜索内容包括逗号, 则需转义\n3. 只搜索索引属性, 非索引属性使用条件过滤',
|
||||
ciSearchTips2: '例: q=hostname:*0.0.0.0*',
|
||||
subCIType: '订阅模型',
|
||||
already: '已',
|
||||
|
@ -547,7 +558,7 @@ class AutoDiscovery(object):
|
|||
"""
|
||||
Define attribute fields
|
||||
:return: Returns a list of attribute fields. The list items are (name, type, description). The name must be in English.
|
||||
type: String Integer Float Date DateTime Time JSON
|
||||
type: String Integer Float Date DateTime Time JSON Bool Reference
|
||||
For example:
|
||||
return [
|
||||
("ci_type", "String", "CIType name"),
|
||||
|
|
|
@ -4,13 +4,16 @@ export const valueTypeMap = () => {
|
|||
return {
|
||||
'0': i18n.t('cmdb.ciType.int'),
|
||||
'1': i18n.t('cmdb.ciType.float'),
|
||||
'2': i18n.t('cmdb.ciType.text'),
|
||||
'2': i18n.t('cmdb.ciType.shortText'),
|
||||
'3': i18n.t('cmdb.ciType.datetime'),
|
||||
'4': i18n.t('cmdb.ciType.date'),
|
||||
'5': i18n.t('cmdb.ciType.time'),
|
||||
'6': 'JSON',
|
||||
'7': i18n.t('cmdb.ciType.password'),
|
||||
'8': i18n.t('cmdb.ciType.link')
|
||||
'8': i18n.t('cmdb.ciType.link'),
|
||||
'9': i18n.t('cmdb.ciType.longText'),
|
||||
'10': i18n.t('cmdb.ciType.bool'),
|
||||
'11': i18n.t('cmdb.ciType.reference'),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,219 +1,269 @@
|
|||
/* eslint-disable */
|
||||
import _ from 'lodash'
|
||||
import XLSX from 'xlsx'
|
||||
import XLSXS from 'xlsx-js-style'
|
||||
export function sum(arr) {
|
||||
if (!arr.length) {
|
||||
return 0
|
||||
}
|
||||
return arr.reduce(function (prev, curr, idx, arr) {
|
||||
return prev + curr
|
||||
})
|
||||
}
|
||||
|
||||
const strLength = (fData) => {
|
||||
|
||||
if (!fData) {
|
||||
return 0
|
||||
}
|
||||
if (fData.length && typeof fData === 'object') {
|
||||
fData = fData.join(' ')
|
||||
}
|
||||
let intLength = 0
|
||||
for (let i = 0; i < fData.length; i++) {
|
||||
if ((fData.charCodeAt(i) < 0) || (fData.charCodeAt(i) > 255)) {
|
||||
intLength = intLength + 2
|
||||
}
|
||||
else {
|
||||
intLength = intLength + 1
|
||||
}
|
||||
|
||||
}
|
||||
return Math.floor(intLength * 7)
|
||||
}
|
||||
|
||||
String.prototype.pxWidth = function (font) {
|
||||
// re-use canvas object for better performance
|
||||
const canvas = String.prototype.pxWidth.canvas || (String.prototype.pxWidth.canvas = document.createElement("canvas")),
|
||||
context = canvas.getContext("2d");
|
||||
|
||||
font && (context.font = font);
|
||||
const metrics = context.measureText(this);
|
||||
|
||||
return metrics.width;
|
||||
}
|
||||
|
||||
export function getCITableColumns(data, attrList, width = 1600, height) {
|
||||
// 计算出来 主table的列表 布局属性
|
||||
|
||||
const _attrList = _.orderBy(attrList, ['is_fixed'], ['desc'])
|
||||
const columns = []
|
||||
for (let attr of _attrList) {
|
||||
const editRender = { name: 'input' }
|
||||
switch (attr.value_type) {
|
||||
case '0':
|
||||
editRender['props'] = { 'type': 'float' }
|
||||
break
|
||||
case '1':
|
||||
editRender['props'] = { 'type': 'float' }
|
||||
break
|
||||
case '2':
|
||||
editRender['attrs'] = { 'type': 'text' }
|
||||
break
|
||||
case '3':
|
||||
editRender['props'] = { 'type': 'datetime' }
|
||||
break
|
||||
case "4":
|
||||
editRender['props'] = { 'type': 'date' }
|
||||
break
|
||||
case '5':
|
||||
editRender['props'] = { 'type': 'time' }
|
||||
break
|
||||
case '6':
|
||||
editRender['props'] = { 'type': 'text' }
|
||||
break
|
||||
default:
|
||||
editRender['props'] = { 'type': 'text' }
|
||||
break
|
||||
}
|
||||
|
||||
if (attr.is_choice) {
|
||||
editRender.name = '$select'
|
||||
editRender.options = attr.choice_value ? attr.choice_value.map(item => { return { label: item, value: item } }) : []
|
||||
delete editRender.props
|
||||
|
||||
}
|
||||
columns.push({
|
||||
attr_id: attr.id,
|
||||
editRender,
|
||||
title: attr.alias || attr.name,
|
||||
field: attr.name,
|
||||
value_type: attr.value_type,
|
||||
sortable: !!attr.is_sortable,
|
||||
filters: attr.is_choice ? attr.choice_value : null,
|
||||
width: Math.min(Math.max(100, ...data.map(item => strLength(item[attr.name]))), 350),
|
||||
is_link: attr.is_link,
|
||||
is_password: attr.is_password,
|
||||
is_list: attr.is_list,
|
||||
is_choice: attr.is_choice,
|
||||
is_fixed: attr.is_fixed,
|
||||
})
|
||||
}
|
||||
|
||||
const totalWidth = sum(columns.map(col => col.width))
|
||||
if (totalWidth < width) {
|
||||
columns.map(item => {
|
||||
// if (item.width === 100) {
|
||||
delete item.width
|
||||
// }
|
||||
})
|
||||
}
|
||||
return columns
|
||||
}
|
||||
|
||||
export const getPropertyStyle = (attr) => {
|
||||
switch (attr.value_type) {
|
||||
case '0':
|
||||
return { color: '#cf1322', backgroundColor: '#fff1f0' }
|
||||
case '1':
|
||||
return { color: '#d4b106', backgroundColor: '#feffe6' }
|
||||
case '2':
|
||||
return { color: '#d46b08', backgroundColor: '#fff7e6' }
|
||||
case '3':
|
||||
return { color: '#531dab', backgroundColor: '#f9f0ff' }
|
||||
case '4':
|
||||
return { color: '#389e0d', backgroundColor: '#f6ffed' }
|
||||
case '5':
|
||||
return { color: '#08979c', backgroundColor: '#e6fffb' }
|
||||
case '6':
|
||||
return { color: '#c41d7f', backgroundColor: '#fff0f6' }
|
||||
case '7':
|
||||
return { color: '#0390CC', backgroundColor: '#e6fffb' }
|
||||
case '8':
|
||||
return { color: '#144BD9', backgroundColor: '#fff0f6' }
|
||||
}
|
||||
}
|
||||
|
||||
export const getPropertyIcon = (attr) => {
|
||||
switch (attr.value_type) {
|
||||
case '0':
|
||||
return 'duose-shishu'
|
||||
case '1':
|
||||
return 'duose-fudianshu'
|
||||
case '2':
|
||||
if (attr.is_password) {
|
||||
return 'duose-password'
|
||||
}
|
||||
if (attr.is_link) {
|
||||
return 'duose-link'
|
||||
}
|
||||
return 'duose-wenben'
|
||||
case '3':
|
||||
return 'duose-datetime'
|
||||
case '4':
|
||||
return 'duose-date'
|
||||
case '5':
|
||||
return 'duose-time'
|
||||
case '6':
|
||||
return 'duose-json'
|
||||
case '7':
|
||||
return 'duose-password'
|
||||
case '8':
|
||||
return 'duose-link'
|
||||
}
|
||||
}
|
||||
|
||||
export const getLastLayout = (data, x1 = 0, y1 = 0, w1 = 0) => {
|
||||
const _tempData = _.orderBy(data, ['y', 'x'], ['asc', 'asc'])
|
||||
if (!_tempData.length) {
|
||||
return { xLast: 0, yLast: 0, wLast: 0 }
|
||||
}
|
||||
const { x, y, w } = _tempData[_tempData.length - 1]
|
||||
if (y < y1) {
|
||||
return { xLast: x1, yLast: y1, wLast: w1 }
|
||||
} else if (y > y1) {
|
||||
return { xLast: x, yLast: y, wLast: w }
|
||||
} else {
|
||||
const xLast = _.max([x, x1])
|
||||
return { xLast, yLast: y, wLast: xLast === x ? w : w1 }
|
||||
}
|
||||
}
|
||||
|
||||
// 数字加逗号
|
||||
export const toThousands = (num = 0) => {
|
||||
return num.toString().replace(/\d+/, function (n) {
|
||||
return n.replace(/(\d)(?=(?:\d{3})+$)/g, '$1,')
|
||||
})
|
||||
}
|
||||
|
||||
export const downloadExcel = (data, fileName = `${moment().format('YYYY-MM-DD HH:mm:ss')}.xls`) => {
|
||||
// STEP 1: Create a new workbook
|
||||
const wb = XLSXS.utils.book_new()
|
||||
// STEP 2: Create data rows and styles
|
||||
const rowArray = data
|
||||
// STEP 3: Create worksheet with rows; Add worksheet to workbook
|
||||
const ws = XLSXS.utils.aoa_to_sheet(rowArray)
|
||||
XLSXS.utils.book_append_sheet(wb, ws, fileName)
|
||||
|
||||
let maxColumnNumber = 1 // 默认最大列数
|
||||
rowArray.forEach(item => { if (item.length > maxColumnNumber) { maxColumnNumber = item.length } })
|
||||
|
||||
// 添加列宽
|
||||
ws['!cols'] = (rowArray[0].map(item => {
|
||||
return { width: 22 }
|
||||
}))
|
||||
// // 添加行高
|
||||
// ws['!rows'] = [{ 'hpt': 80 }]
|
||||
// STEP 4: Write Excel file to browser #导出
|
||||
XLSXS.writeFile(wb, fileName + '.xlsx')
|
||||
}
|
||||
|
||||
export const getAllParentNodesLabel = (node, label) => {
|
||||
if (node.parentNode) {
|
||||
return getAllParentNodesLabel(node.parentNode, `${node.parentNode.label}-${label}`)
|
||||
}
|
||||
return label
|
||||
}
|
||||
export const getTreeSelectLabel = (node) => {
|
||||
return `${getAllParentNodesLabel(node, node.label)}`
|
||||
/* eslint-disable */
|
||||
import _ from 'lodash'
|
||||
import XLSX from 'xlsx'
|
||||
import XLSXS from 'xlsx-js-style'
|
||||
export function sum(arr) {
|
||||
if (!arr.length) {
|
||||
return 0
|
||||
}
|
||||
return arr.reduce(function (prev, curr, idx, arr) {
|
||||
return prev + curr
|
||||
})
|
||||
}
|
||||
|
||||
const strLength = (fData) => {
|
||||
|
||||
if (!fData) {
|
||||
return 0
|
||||
}
|
||||
if (fData.length && typeof fData === 'object') {
|
||||
fData = fData.join(' ')
|
||||
}
|
||||
let intLength = 0
|
||||
for (let i = 0; i < fData.length; i++) {
|
||||
if ((fData.charCodeAt(i) < 0) || (fData.charCodeAt(i) > 255)) {
|
||||
intLength = intLength + 2
|
||||
}
|
||||
else {
|
||||
intLength = intLength + 1
|
||||
}
|
||||
|
||||
}
|
||||
return Math.floor(intLength * 7)
|
||||
}
|
||||
|
||||
String.prototype.pxWidth = function (font) {
|
||||
// re-use canvas object for better performance
|
||||
const canvas = String.prototype.pxWidth.canvas || (String.prototype.pxWidth.canvas = document.createElement("canvas")),
|
||||
context = canvas.getContext("2d");
|
||||
|
||||
font && (context.font = font);
|
||||
const metrics = context.measureText(this);
|
||||
|
||||
return metrics.width;
|
||||
}
|
||||
|
||||
export function getCITableColumns(data, attrList, width = 1600, height) {
|
||||
// 计算出来 主table的列表 布局属性
|
||||
|
||||
const _attrList = _.orderBy(attrList, ['is_fixed'], ['desc'])
|
||||
const columns = []
|
||||
for (let attr of _attrList) {
|
||||
const editRender = { name: 'input' }
|
||||
switch (attr.value_type) {
|
||||
case '0':
|
||||
editRender['props'] = { 'type': 'float' }
|
||||
break
|
||||
case '1':
|
||||
editRender['props'] = { 'type': 'float' }
|
||||
break
|
||||
case '2':
|
||||
editRender['attrs'] = { 'type': 'text' }
|
||||
break
|
||||
case '3':
|
||||
editRender['props'] = { 'type': 'datetime' }
|
||||
break
|
||||
case "4":
|
||||
editRender['props'] = { 'type': 'date' }
|
||||
break
|
||||
case '5':
|
||||
editRender['props'] = { 'type': 'time' }
|
||||
break
|
||||
case '6':
|
||||
editRender['props'] = { 'type': 'text' }
|
||||
break
|
||||
default:
|
||||
editRender['props'] = { 'type': 'text' }
|
||||
break
|
||||
}
|
||||
|
||||
if (attr.is_choice) {
|
||||
editRender.name = '$select'
|
||||
editRender.options = attr.choice_value ? attr.choice_value.map(item => { return { label: item, value: item } }) : []
|
||||
delete editRender.props
|
||||
|
||||
}
|
||||
columns.push({
|
||||
attr_id: attr.id,
|
||||
editRender,
|
||||
title: attr.alias || attr.name,
|
||||
field: attr.name,
|
||||
value_type: attr.value_type,
|
||||
sortable: !!attr.is_sortable,
|
||||
filters: attr.is_choice ? attr.choice_value : null,
|
||||
width: Math.min(Math.max(100, ...data.map(item => strLength(item[attr.name]))), 350),
|
||||
is_link: attr.is_link,
|
||||
is_password: attr.is_password,
|
||||
is_list: attr.is_list,
|
||||
is_choice: attr.is_choice,
|
||||
is_fixed: attr.is_fixed,
|
||||
is_bool: attr.is_bool,
|
||||
is_reference: attr.is_reference,
|
||||
reference_type_id: attr.reference_type_id
|
||||
})
|
||||
}
|
||||
|
||||
const totalWidth = sum(columns.map(col => col.width))
|
||||
if (totalWidth < width) {
|
||||
columns.map(item => {
|
||||
// if (item.width === 100) {
|
||||
delete item.width
|
||||
// }
|
||||
})
|
||||
}
|
||||
return columns
|
||||
}
|
||||
|
||||
export const getPropertyStyle = (attr) => {
|
||||
switch (attr.value_type) {
|
||||
case '0':
|
||||
return { color: '#cf1322', backgroundColor: '#fff1f0' }
|
||||
case '1':
|
||||
return { color: '#d4b106', backgroundColor: '#feffe6' }
|
||||
case '2':
|
||||
return { color: '#d46b08', backgroundColor: '#fff7e6' }
|
||||
case '3':
|
||||
return { color: '#531dab', backgroundColor: '#f9f0ff' }
|
||||
case '4':
|
||||
return { color: '#389e0d', backgroundColor: '#f6ffed' }
|
||||
case '5':
|
||||
return { color: '#08979c', backgroundColor: '#e6fffb' }
|
||||
case '6':
|
||||
return { color: '#c41d7f', backgroundColor: '#fff0f6' }
|
||||
case '7':
|
||||
return { color: '#0390CC', backgroundColor: '#e6fffb' }
|
||||
case '8':
|
||||
return { color: '#144BD9', backgroundColor: '#fff0f6' }
|
||||
}
|
||||
}
|
||||
|
||||
export const getPropertyIcon = (attr) => {
|
||||
switch (attr.value_type) {
|
||||
case '0':
|
||||
if (attr.is_reference) {
|
||||
return 'duose-quote'
|
||||
}
|
||||
|
||||
return 'duose-shishu'
|
||||
case '1':
|
||||
return 'duose-fudianshu'
|
||||
case '2':
|
||||
if (attr.is_password) {
|
||||
return 'duose-password'
|
||||
}
|
||||
if (attr.is_link) {
|
||||
return 'duose-link'
|
||||
}
|
||||
if (attr.is_index === false) {
|
||||
return 'duose-changwenben1'
|
||||
}
|
||||
return 'duose-wenben'
|
||||
case '3':
|
||||
return 'duose-datetime'
|
||||
case '4':
|
||||
return 'duose-date'
|
||||
case '5':
|
||||
return 'duose-time'
|
||||
case '6':
|
||||
return 'duose-json'
|
||||
case '7':
|
||||
if (attr.is_bool) {
|
||||
return 'duose-boole'
|
||||
}
|
||||
return 'duose-password'
|
||||
case '8':
|
||||
return 'duose-link'
|
||||
case '9':
|
||||
return 'duose-changwenben1'
|
||||
case '10':
|
||||
return 'duose-boole'
|
||||
case '11':
|
||||
return 'duose-quote'
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
export const getPropertyType = (attr) => {
|
||||
if (attr.is_password) {
|
||||
return '7'
|
||||
}
|
||||
if (attr.is_link) {
|
||||
return '8'
|
||||
}
|
||||
|
||||
switch (attr.value_type) {
|
||||
case '0':
|
||||
if (attr.is_reference) {
|
||||
return '11'
|
||||
}
|
||||
return '0'
|
||||
case '2':
|
||||
if (!attr.is_index) {
|
||||
return '9'
|
||||
}
|
||||
return '2'
|
||||
case '7':
|
||||
if (attr.is_bool) {
|
||||
return '10'
|
||||
}
|
||||
return '7'
|
||||
default:
|
||||
return attr?.value_type ?? ''
|
||||
}
|
||||
}
|
||||
|
||||
export const getLastLayout = (data, x1 = 0, y1 = 0, w1 = 0) => {
|
||||
const _tempData = _.orderBy(data, ['y', 'x'], ['asc', 'asc'])
|
||||
if (!_tempData.length) {
|
||||
return { xLast: 0, yLast: 0, wLast: 0 }
|
||||
}
|
||||
const { x, y, w } = _tempData[_tempData.length - 1]
|
||||
if (y < y1) {
|
||||
return { xLast: x1, yLast: y1, wLast: w1 }
|
||||
} else if (y > y1) {
|
||||
return { xLast: x, yLast: y, wLast: w }
|
||||
} else {
|
||||
const xLast = _.max([x, x1])
|
||||
return { xLast, yLast: y, wLast: xLast === x ? w : w1 }
|
||||
}
|
||||
}
|
||||
|
||||
// 数字加逗号
|
||||
export const toThousands = (num = 0) => {
|
||||
return num.toString().replace(/\d+/, function (n) {
|
||||
return n.replace(/(\d)(?=(?:\d{3})+$)/g, '$1,')
|
||||
})
|
||||
}
|
||||
|
||||
export const downloadExcel = (data, fileName = `${moment().format('YYYY-MM-DD HH:mm:ss')}.xls`) => {
|
||||
// STEP 1: Create a new workbook
|
||||
const wb = XLSXS.utils.book_new()
|
||||
// STEP 2: Create data rows and styles
|
||||
const rowArray = data
|
||||
// STEP 3: Create worksheet with rows; Add worksheet to workbook
|
||||
const ws = XLSXS.utils.aoa_to_sheet(rowArray)
|
||||
XLSXS.utils.book_append_sheet(wb, ws, fileName)
|
||||
|
||||
let maxColumnNumber = 1 // 默认最大列数
|
||||
rowArray.forEach(item => { if (item.length > maxColumnNumber) { maxColumnNumber = item.length } })
|
||||
|
||||
// 添加列宽
|
||||
ws['!cols'] = (rowArray[0].map(item => {
|
||||
return { width: 22 }
|
||||
}))
|
||||
// // 添加行高
|
||||
// ws['!rows'] = [{ 'hpt': 80 }]
|
||||
// STEP 4: Write Excel file to browser #导出
|
||||
XLSXS.writeFile(wb, fileName + '.xlsx')
|
||||
}
|
||||
|
||||
export const getAllParentNodesLabel = (node, label) => {
|
||||
if (node.parentNode) {
|
||||
return getAllParentNodesLabel(node.parentNode, `${node.parentNode.label}-${label}`)
|
||||
}
|
||||
return label
|
||||
}
|
||||
export const getTreeSelectLabel = (node) => {
|
||||
return `${getAllParentNodesLabel(node, node.label)}`
|
||||
}
|
|
@ -465,13 +465,12 @@ export default {
|
|||
this.loadTip = this.$t('cmdb.ci.batchUpdateInProgress') + '...'
|
||||
const payload = {}
|
||||
Object.keys(values).forEach((key) => {
|
||||
if (values[key] || values[key] === 0) {
|
||||
payload[key] = values[key]
|
||||
}
|
||||
// Field values support blanking
|
||||
// There are currently field values that do not support blanking and will be returned by the backend.
|
||||
if (values[key] === undefined || values[key] === null) {
|
||||
payload[key] = null
|
||||
} else {
|
||||
payload[key] = values[key]
|
||||
}
|
||||
})
|
||||
this.$refs.create.visible = false
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
<a-select v-model="parentsForm[item.name].attr">
|
||||
<a-select-option
|
||||
:title="attr.alias || attr.name"
|
||||
v-for="attr in item.attributes"
|
||||
v-for="attr in filterAttributes(item.attributes)"
|
||||
:key="attr.name"
|
||||
:value="attr.name"
|
||||
>
|
||||
|
@ -87,11 +87,32 @@
|
|||
</a-col>
|
||||
<a-col :span="showListOperation(list.name) ? 10 : 13">
|
||||
<a-form-item>
|
||||
<CIReferenceAttr
|
||||
v-if="getAttr(list.name).is_reference"
|
||||
:referenceTypeId="getAttr(list.name).reference_type_id"
|
||||
:isList="getAttr(list.name).is_list"
|
||||
v-decorator="[
|
||||
list.name,
|
||||
{
|
||||
initialValue: getAttr(list.name).is_list ? [] : ''
|
||||
}
|
||||
]"
|
||||
/>
|
||||
<a-switch
|
||||
v-else-if="getAttr(list.name).is_bool"
|
||||
v-decorator="[
|
||||
list.name,
|
||||
{
|
||||
valuePropName: 'checked',
|
||||
initialValue: false
|
||||
}
|
||||
]"
|
||||
/>
|
||||
<a-select
|
||||
:style="{ width: '100%' }"
|
||||
v-decorator="[list.name, { rules: getDecoratorRules(list) }]"
|
||||
:placeholder="$t('placeholder2')"
|
||||
v-if="getFieldType(list.name).split('%%')[0] === 'select'"
|
||||
v-else-if="getFieldType(list.name).split('%%')[0] === 'select'"
|
||||
:mode="getFieldType(list.name).split('%%')[1] === 'multiple' ? 'multiple' : 'default'"
|
||||
showSearch
|
||||
allowClear
|
||||
|
@ -114,18 +135,18 @@
|
|||
<a-input-number
|
||||
v-decorator="[list.name, { rules: getDecoratorRules(list) }]"
|
||||
style="width: 100%"
|
||||
v-if="getFieldType(list.name) === 'input_number'"
|
||||
v-else-if="getFieldType(list.name) === 'input_number'"
|
||||
/>
|
||||
<a-date-picker
|
||||
v-decorator="[list.name, { rules: getDecoratorRules(list) }]"
|
||||
style="width: 100%"
|
||||
: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'"
|
||||
v-if="getFieldType(list.name) === '4' || getFieldType(list.name) === '3'"
|
||||
v-else-if="getFieldType(list.name) === '4' || getFieldType(list.name) === '3'"
|
||||
:showTime="getFieldType(list.name) === '4' ? false : { format: 'HH:mm:ss' }"
|
||||
/>
|
||||
<a-input
|
||||
v-if="getFieldType(list.name) === 'input'"
|
||||
v-else-if="getFieldType(list.name) === 'input'"
|
||||
@focus="(e) => handleFocusInput(e, list)"
|
||||
v-decorator="[list.name, { rules: getDecoratorRules(list) }]"
|
||||
/>
|
||||
|
@ -156,6 +177,7 @@ import JsonEditor from '../../../components/JsonEditor/jsonEditor.vue'
|
|||
import { valueTypeMap } from '../../../utils/const'
|
||||
import CreateInstanceFormByGroup from './createInstanceFormByGroup.vue'
|
||||
import { getCITypeParent, getCanEditByParentIdChildId } from '@/modules/cmdb/api/CITypeRelation'
|
||||
import CIReferenceAttr from '@/components/ciReferenceAttr/index.vue'
|
||||
|
||||
export default {
|
||||
name: 'CreateInstanceForm',
|
||||
|
@ -164,6 +186,7 @@ export default {
|
|||
ElOption: Option,
|
||||
JsonEditor,
|
||||
CreateInstanceFormByGroup,
|
||||
CIReferenceAttr
|
||||
},
|
||||
props: {
|
||||
typeIdFromRelation: {
|
||||
|
@ -261,6 +284,11 @@ export default {
|
|||
}
|
||||
Object.keys(values).forEach((k) => {
|
||||
const _tempFind = this.attributeList.find((item) => item.name === k)
|
||||
|
||||
if (_tempFind.is_reference) {
|
||||
values[k] = values[k] ? values[k] : null
|
||||
}
|
||||
|
||||
if (
|
||||
_tempFind.value_type === '3' &&
|
||||
values[k] &&
|
||||
|
@ -309,6 +337,11 @@ export default {
|
|||
|
||||
Object.keys(values).forEach((k) => {
|
||||
const _tempFind = this.attributeList.find((item) => item.name === k)
|
||||
|
||||
if (_tempFind.is_reference) {
|
||||
values[k] = values[k] ? values[k] : null
|
||||
}
|
||||
|
||||
if (
|
||||
_tempFind.value_type === '3' &&
|
||||
values[k] &&
|
||||
|
@ -426,6 +459,9 @@ export default {
|
|||
}
|
||||
return 'input'
|
||||
},
|
||||
getAttr(name) {
|
||||
return this.attributeList.find((item) => item.name === name) ?? {}
|
||||
},
|
||||
getSelectFieldOptions(name) {
|
||||
const _find = this.attributeList.find((item) => item.name === name)
|
||||
if (_find) {
|
||||
|
@ -487,7 +523,12 @@ export default {
|
|||
}
|
||||
|
||||
return rules
|
||||
}
|
||||
},
|
||||
filterAttributes(attributes) {
|
||||
return attributes.filter((attr) => {
|
||||
return !attr.is_bool && !attr.is_reference
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
@ -498,7 +539,7 @@ export default {
|
|||
}
|
||||
.ant-drawer-body {
|
||||
overflow-y: auto;
|
||||
max-height: calc(100vh - 110px);
|
||||
height: calc(100vh - 110px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -79,6 +79,8 @@
|
|||
import XEUtils from 'xe-utils'
|
||||
import { getCITypeAttributesByName } from '@/modules/cmdb/api/CITypeAttr'
|
||||
import { valueTypeMap } from '@/modules/cmdb/utils/const'
|
||||
import { getPropertyType } from '@/modules/cmdb/utils/helper'
|
||||
|
||||
export default {
|
||||
name: 'MetadataDrawer',
|
||||
data() {
|
||||
|
@ -187,12 +189,7 @@ export default {
|
|||
this.loading = true
|
||||
const { attributes = [] } = await getCITypeAttributesByName(this.typeId)
|
||||
this.tableData = attributes.map((attr) => {
|
||||
if (attr.is_password) {
|
||||
attr.value_type = '7'
|
||||
}
|
||||
if (attr.is_link) {
|
||||
attr.value_type = '8'
|
||||
}
|
||||
attr.value_type = getPropertyType(attr)
|
||||
return attr
|
||||
})
|
||||
this.loading = false
|
||||
|
|
|
@ -1,9 +1,19 @@
|
|||
<template>
|
||||
<span :id="`ci-detail-attr-${attr.name}`">
|
||||
<span v-if="!isEdit || attr.value_type === '6'">
|
||||
<template v-if="attr.is_reference" >
|
||||
<a
|
||||
v-for="(ciId) in (attr.is_list ? ci[attr.name] : [ci[attr.name]])"
|
||||
:key="ciId"
|
||||
:href="`/cmdb/cidetail/${attr.reference_type_id}/${ciId}`"
|
||||
target="_blank"
|
||||
>
|
||||
{{ attr.referenceShowAttrNameMap ? attr.referenceShowAttrNameMap[ciId] || ciId : ciId }}
|
||||
</a>
|
||||
</template>
|
||||
<PasswordField
|
||||
:style="{ display: 'inline-block' }"
|
||||
v-if="attr.is_password && ci[attr.name]"
|
||||
v-else-if="attr.is_password && ci[attr.name]"
|
||||
:ci_id="ci._id"
|
||||
:attr_id="attr.id"
|
||||
></PasswordField>
|
||||
|
@ -67,6 +77,29 @@
|
|||
<template v-else>
|
||||
<a-form :form="form">
|
||||
<a-form-item label="" :colon="false">
|
||||
<CIReferenceAttr
|
||||
v-if="attr.is_reference"
|
||||
:referenceTypeId="attr.reference_type_id"
|
||||
:isList="attr.is_list"
|
||||
:referenceShowAttrName="attr.showAttrName"
|
||||
:initSelectOption="getInitReferenceSelectOption(attr)"
|
||||
v-decorator="[
|
||||
attr.name,
|
||||
{
|
||||
rules: [{ required: attr.is_required, message: $t('placeholder2') + `${attr.alias || attr.name}` }],
|
||||
}
|
||||
]"
|
||||
/>
|
||||
<a-switch
|
||||
v-else-if="attr.is_bool"
|
||||
v-decorator="[
|
||||
attr.name,
|
||||
{
|
||||
rules: [{ required: attr.is_required }],
|
||||
valuePropName: 'checked',
|
||||
}
|
||||
]"
|
||||
/>
|
||||
<a-select
|
||||
:style="{ width: '100%' }"
|
||||
v-decorator="[
|
||||
|
@ -76,7 +109,7 @@
|
|||
},
|
||||
]"
|
||||
:placeholder="$t('placeholder2')"
|
||||
v-if="attr.is_choice"
|
||||
v-else-if="attr.is_choice"
|
||||
:mode="attr.is_list ? 'multiple' : 'default'"
|
||||
showSearch
|
||||
allowClear
|
||||
|
@ -157,10 +190,11 @@ import { updateCI } from '@/modules/cmdb/api/ci'
|
|||
import JsonEditor from '../../../components/JsonEditor/jsonEditor.vue'
|
||||
import PasswordField from '../../../components/passwordField/index.vue'
|
||||
import { getAttrPassword } from '../../../api/CITypeAttr'
|
||||
import CIReferenceAttr from '@/components/ciReferenceAttr/index.vue'
|
||||
|
||||
export default {
|
||||
name: 'CiDetailAttrContent',
|
||||
components: { JsonEditor, PasswordField },
|
||||
components: { JsonEditor, PasswordField, CIReferenceAttr },
|
||||
props: {
|
||||
ci: {
|
||||
type: Object,
|
||||
|
@ -209,7 +243,7 @@ export default {
|
|||
}
|
||||
this.isEdit = true
|
||||
this.$nextTick(async () => {
|
||||
if (this.attr.is_list && !this.attr.is_choice) {
|
||||
if (this.attr.is_list && !this.attr.is_choice && !this.attr.is_reference) {
|
||||
this.form.setFieldsValue({
|
||||
[`${this.attr.name}`]: Array.isArray(this.ci[this.attr.name])
|
||||
? this.ci[this.attr.name].join(',')
|
||||
|
@ -237,6 +271,10 @@ export default {
|
|||
.then(() => {
|
||||
this.$message.success(this.$t('updateSuccess'))
|
||||
this.$emit('updateCIByself', { [`${this.attr.name}`]: newData }, this.attr.name)
|
||||
|
||||
if (this.attr.is_reference) {
|
||||
this.$emit('refreshReferenceAttr')
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.$emit('refresh', this.attr.name)
|
||||
|
@ -283,6 +321,16 @@ export default {
|
|||
getName(name) {
|
||||
return name ?? ''
|
||||
},
|
||||
|
||||
getInitReferenceSelectOption(attr) {
|
||||
const option = Object.keys(attr?.referenceShowAttrNameMap || {}).map((key) => {
|
||||
return {
|
||||
key: Number(key),
|
||||
title: attr?.referenceShowAttrNameMap?.[key] ?? ''
|
||||
}
|
||||
})
|
||||
return option
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -38,6 +38,16 @@
|
|||
resizable
|
||||
class="ops-stripe-table"
|
||||
>
|
||||
<template #reference_default="{ row, column }">
|
||||
<a
|
||||
v-for="(id) in (column.params.attr.is_list ? row[column.field] : [row[column.field]])"
|
||||
:key="id"
|
||||
:href="`/cmdb/cidetail/${column.params.attr.reference_type_id}/${id}`"
|
||||
target="_blank"
|
||||
>
|
||||
{{ id }}
|
||||
</a>
|
||||
</template>
|
||||
<template #operation_default="{ row }">
|
||||
<a-popconfirm
|
||||
arrowPointAtCenter
|
||||
|
@ -85,6 +95,16 @@
|
|||
resizable
|
||||
class="ops-stripe-table"
|
||||
>
|
||||
<template #reference_default="{ row, column }">
|
||||
<a
|
||||
v-for="(id) in (column.params.attr.is_list ? row[column.field] : [row[column.field]])"
|
||||
:key="id"
|
||||
:href="`/cmdb/cidetail/${column.params.attr.reference_type_id}/${id}`"
|
||||
target="_blank"
|
||||
>
|
||||
{{ id }}
|
||||
</a>
|
||||
</template>
|
||||
<template #operation_default="{ row }">
|
||||
<a-popconfirm
|
||||
arrowPointAtCenter
|
||||
|
@ -258,7 +278,22 @@ export default {
|
|||
const columns = []
|
||||
const jsonAttr = []
|
||||
item.attributes.forEach((attr) => {
|
||||
columns.push({ key: 'p_' + attr.id, field: attr.name, title: attr.alias, minWidth: '100px' })
|
||||
const column = {
|
||||
key: 'p_' + attr.id,
|
||||
field: attr.name,
|
||||
title: attr.alias,
|
||||
minWidth: '100px',
|
||||
params: {
|
||||
attr
|
||||
},
|
||||
}
|
||||
if (attr.is_reference) {
|
||||
column.slots = {
|
||||
default: 'reference_default'
|
||||
}
|
||||
}
|
||||
columns.push(column)
|
||||
|
||||
if (attr.value_type === '6') {
|
||||
jsonAttr.push(attr.name)
|
||||
}
|
||||
|
@ -299,7 +334,22 @@ export default {
|
|||
const columns = []
|
||||
const jsonAttr = []
|
||||
item.attributes.forEach((attr) => {
|
||||
columns.push({ key: 'c_' + attr.id, field: attr.name, title: attr.alias, minWidth: '100px' })
|
||||
const column = {
|
||||
key: 'c_' + attr.id,
|
||||
field: attr.name,
|
||||
title: attr.alias,
|
||||
minWidth: '100px',
|
||||
params: {
|
||||
attr
|
||||
},
|
||||
}
|
||||
if (attr.is_reference) {
|
||||
column.slots = {
|
||||
default: 'reference_default'
|
||||
}
|
||||
}
|
||||
columns.push(column)
|
||||
|
||||
if (attr.value_type === '6') {
|
||||
jsonAttr.push(attr.name)
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
:key="attr.name"
|
||||
v-for="attr in group.attributes"
|
||||
>
|
||||
<ci-detail-attr-content :ci="ci" :attr="attr" @refresh="refresh" @updateCIByself="updateCIByself" />
|
||||
<ci-detail-attr-content :ci="ci" :attr="attr" @refresh="refresh" @updateCIByself="updateCIByself" @refreshReferenceAttr="handleReferenceAttr" />
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
@ -137,7 +137,7 @@ import _ from 'lodash'
|
|||
import { Descriptions, DescriptionsItem } from 'element-ui'
|
||||
import { getCITypeGroupById, getCITypes } from '@/modules/cmdb/api/CIType'
|
||||
import { getCIHistory, judgeItsmInstalled } from '@/modules/cmdb/api/history'
|
||||
import { getCIById } from '@/modules/cmdb/api/ci'
|
||||
import { getCIById, searchCI } from '@/modules/cmdb/api/ci'
|
||||
import CiDetailAttrContent from './ciDetailAttrContent.vue'
|
||||
import CiDetailRelation from './ciDetailRelation.vue'
|
||||
import TriggerTable from '../../operation_history/modules/triggerTable.vue'
|
||||
|
@ -244,9 +244,78 @@ export default {
|
|||
getCITypeGroupById(this.typeId, { need_other: 1 })
|
||||
.then((res) => {
|
||||
this.attributeGroups = res
|
||||
|
||||
this.handleReferenceAttr()
|
||||
})
|
||||
.catch((e) => {})
|
||||
},
|
||||
|
||||
async handleReferenceAttr() {
|
||||
const map = {}
|
||||
this.attributeGroups.forEach((group) => {
|
||||
group.attributes.forEach((attr) => {
|
||||
if (attr?.is_reference && attr?.reference_type_id && this.ci[attr.name]) {
|
||||
const ids = Array.isArray(this.ci[attr.name]) ? this.ci[attr.name] : this.ci[attr.name] ? [this.ci[attr.name]] : []
|
||||
if (ids.length) {
|
||||
if (!map?.[attr.reference_type_id]) {
|
||||
map[attr.reference_type_id] = {}
|
||||
}
|
||||
ids.forEach((id) => {
|
||||
map[attr.reference_type_id][id] = {}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
if (!Object.keys(map).length) {
|
||||
return
|
||||
}
|
||||
|
||||
const ciTypesRes = await getCITypes({
|
||||
type_ids: Object.keys(map).join(',')
|
||||
})
|
||||
const showAttrNameMap = {}
|
||||
ciTypesRes.ci_types.forEach((ciType) => {
|
||||
showAttrNameMap[ciType.id] = ciType?.show_name || ciType?.unique_name || ''
|
||||
})
|
||||
|
||||
const allRes = await Promise.all(
|
||||
Object.keys(map).map((key) => {
|
||||
return searchCI({
|
||||
q: `_type:${key},_id:(${Object.keys(map[key]).join(';')})`,
|
||||
count: 9999
|
||||
})
|
||||
})
|
||||
)
|
||||
|
||||
const ciNameMap = {}
|
||||
allRes.forEach((res) => {
|
||||
res.result.forEach((item) => {
|
||||
ciNameMap[item._id] = item
|
||||
})
|
||||
})
|
||||
|
||||
const newAttrGroups = _.cloneDeep(this.attributeGroups)
|
||||
|
||||
newAttrGroups.forEach((group) => {
|
||||
group.attributes.forEach((attr) => {
|
||||
if (attr?.is_reference && attr?.reference_type_id) {
|
||||
attr.showAttrName = showAttrNameMap?.[attr?.reference_type_id] || ''
|
||||
|
||||
const referenceShowAttrNameMap = {}
|
||||
const referenceCIIds = this.ci[attr.name];
|
||||
(Array.isArray(referenceCIIds) ? referenceCIIds : referenceCIIds ? [referenceCIIds] : []).forEach((id) => {
|
||||
referenceShowAttrNameMap[id] = ciNameMap?.[id]?.[attr.showAttrName] ?? id
|
||||
})
|
||||
attr.referenceShowAttrNameMap = referenceShowAttrNameMap
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
this.$set(this, 'attributeGroups', newAttrGroups)
|
||||
},
|
||||
|
||||
async getCI() {
|
||||
await getCIById(this.ciId)
|
||||
.then((res) => {
|
||||
|
|
|
@ -16,6 +16,29 @@
|
|||
:key="attr.name + attr_idx"
|
||||
>
|
||||
<a-form-item :label="attr.alias || attr.name" :colon="false">
|
||||
<CIReferenceAttr
|
||||
v-if="attr.is_reference"
|
||||
:referenceTypeId="attr.reference_type_id"
|
||||
:isList="attr.is_list"
|
||||
v-decorator="[
|
||||
attr.name,
|
||||
{
|
||||
rules: [{ required: attr.is_required, message: $t('placeholder2') + `${attr.alias || attr.name}` }],
|
||||
initialValue: attr.is_list ? [] : ''
|
||||
}
|
||||
]"
|
||||
/>
|
||||
<a-switch
|
||||
v-else-if="attr.is_bool"
|
||||
v-decorator="[
|
||||
attr.name,
|
||||
{
|
||||
rules: [{ required: false }],
|
||||
valuePropName: 'checked',
|
||||
initialValue: attr.default ? Boolean(attr.default.default) : false
|
||||
}
|
||||
]"
|
||||
/>
|
||||
<a-select
|
||||
:style="{ width: '100%' }"
|
||||
v-decorator="[
|
||||
|
@ -33,7 +56,7 @@
|
|||
},
|
||||
]"
|
||||
:placeholder="$t('placeholder2')"
|
||||
v-if="attr.is_choice"
|
||||
v-else-if="attr.is_choice"
|
||||
:mode="attr.is_list ? 'multiple' : 'default'"
|
||||
showSearch
|
||||
allowClear
|
||||
|
@ -133,10 +156,14 @@
|
|||
import _ from 'lodash'
|
||||
import moment from 'moment'
|
||||
import JsonEditor from '../../../components/JsonEditor/jsonEditor.vue'
|
||||
import CIReferenceAttr from '@/components/ciReferenceAttr/index.vue'
|
||||
|
||||
export default {
|
||||
name: 'CreateInstanceFormByGroup',
|
||||
components: { JsonEditor },
|
||||
components: {
|
||||
JsonEditor,
|
||||
CIReferenceAttr
|
||||
},
|
||||
props: {
|
||||
group: {
|
||||
type: Object,
|
||||
|
@ -146,6 +173,10 @@ export default {
|
|||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
ciTypeId: {
|
||||
type: [Number, String],
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
inject: ['getFieldType'],
|
||||
data() {
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
import { mapState } from 'vuex'
|
||||
import _ from 'lodash'
|
||||
import { valueTypeMap } from '@/modules/cmdb/utils/const'
|
||||
import { getPropertyType } from '@/modules/cmdb/utils/helper'
|
||||
|
||||
export default {
|
||||
name: 'AllAttrDrawer',
|
||||
|
@ -84,12 +85,7 @@ export default {
|
|||
})
|
||||
|
||||
otherAttrData.forEach((attr) => {
|
||||
if (attr.is_password) {
|
||||
attr.value_type = '7'
|
||||
}
|
||||
if (attr.is_link) {
|
||||
attr.value_type = '8'
|
||||
}
|
||||
attr.value_type = getPropertyType(attr)
|
||||
|
||||
attr.groupId = -1
|
||||
attr.groupName = this.$t('other')
|
||||
|
|
|
@ -21,9 +21,7 @@
|
|||
<div :class="{ 'attribute-card-name': true, 'attribute-card-name-default-show': property.default_show }">
|
||||
{{ property.alias || property.name }}
|
||||
</div>
|
||||
<div v-if="property.is_password" class="attribute-card_value-type">{{ $t('cmdb.ciType.password') }}</div>
|
||||
<div v-else-if="property.is_link" class="attribute-card_value-type">{{ $t('cmdb.ciType.link') }}</div>
|
||||
<div v-else class="attribute-card_value-type">{{ valueTypeMap[property.value_type] }}</div>
|
||||
<div class="attribute-card_value-type">{{ valueTypeMap[getPropertyType(property)] }}</div>
|
||||
</div>
|
||||
<div
|
||||
class="attribute-card-trigger"
|
||||
|
@ -74,7 +72,9 @@
|
|||
!isUnique &&
|
||||
!['6'].includes(property.value_type) &&
|
||||
!property.is_password &&
|
||||
!property.is_list
|
||||
!property.is_list &&
|
||||
!property.is_reference &&
|
||||
!property.is_bool
|
||||
"
|
||||
:title="$t(isShowId ? 'cmdb.ciType.cancelSetAsShow' : 'cmdb.ciType.setAsShow')"
|
||||
>
|
||||
|
@ -101,6 +101,8 @@ import ValueTypeIcon from '@/components/CMDBValueTypeMapIcon'
|
|||
import { valueTypeMap } from '../../utils/const'
|
||||
import TriggerForm from './triggerForm.vue'
|
||||
import { updateCIType } from '@/modules/cmdb/api/CIType'
|
||||
import { getPropertyType } from '../../utils/helper'
|
||||
|
||||
export default {
|
||||
name: 'AttributeCard',
|
||||
inject: {
|
||||
|
@ -191,6 +193,7 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
getPropertyType,
|
||||
handleEdit() {
|
||||
this.$emit('edit')
|
||||
},
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
<template>
|
||||
<a-form-item
|
||||
:label="$t('cmdb.ciType.referenceModel')"
|
||||
:extra="$t('cmdb.ciType.referenceModelTip1')"
|
||||
:label-col="formItemLayout.labelCol"
|
||||
:wrapper-col="formItemLayout.wrapperCol"
|
||||
>
|
||||
<a-select
|
||||
allowClear
|
||||
v-decorator="['reference_type_id', {
|
||||
rules: [{ required: true, message: $t('cmdb.ciType.referenceModelTip') }],
|
||||
initialValue: ''
|
||||
}]"
|
||||
showSearch
|
||||
optionFilterProp="title"
|
||||
@dropdownVisibleChange="handleDropdownVisibleChange"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(item) in options"
|
||||
:key="item.value"
|
||||
:title="item.label"
|
||||
>
|
||||
{{ item.label }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getCITypes } from '@/modules/cmdb/api/CIType'
|
||||
|
||||
export default {
|
||||
name: 'ReferenceModelSelect',
|
||||
props: {
|
||||
form: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
isLazyRequire: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
formItemLayout: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isInit: false,
|
||||
options: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (!this.isLazyRequire) {
|
||||
this.getSelectOptions()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleDropdownVisibleChange(open) {
|
||||
if (!this.isInit && open) {
|
||||
this.getSelectOptions()
|
||||
}
|
||||
},
|
||||
async getSelectOptions() {
|
||||
this.isInit = true
|
||||
const res = await getCITypes()
|
||||
|
||||
this.options = res.ci_types.map((ciType) => {
|
||||
return {
|
||||
value: ciType.id,
|
||||
label: ciType?.alias || ciType?.name || ''
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -60,11 +60,17 @@
|
|||
v-decorator="['value_type', { rules: [{ required: true }] }]"
|
||||
@change="handleChangeValueType"
|
||||
>
|
||||
<a-select-option :value="key" :key="key" v-for="(value, key) in valueTypeMap">{{ value }}</a-select-option>
|
||||
<a-select-option :value="key" :key="key" v-for="(value, key) in valueTypeMap">
|
||||
<ops-icon :type="getPropertyIcon({ value_type: key })" />
|
||||
<span class="value-type-text">{{ value }}</span>
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item></a-col
|
||||
>
|
||||
<a-col :span="currentValueType === '6' ? 24 : 12">
|
||||
<a-col
|
||||
v-if="currentValueType !== '11'"
|
||||
:span="currentValueType === '6' ? 24 : 12"
|
||||
>
|
||||
<a-form-item
|
||||
:label-col="{ span: currentValueType === '6' ? 4 : 8 }"
|
||||
:wrapper-col="{ span: currentValueType === '6' ? 18 : 12 }"
|
||||
|
@ -77,6 +83,10 @@
|
|||
v-decorator="['default_value', { rules: [{ required: false }] }]"
|
||||
>
|
||||
</a-input>
|
||||
<a-switch
|
||||
v-else-if="currentValueType === '10'"
|
||||
v-decorator="['default_value', { rules: [{ required: false }], valuePropName: 'checked' }]"
|
||||
/>
|
||||
<a-select
|
||||
v-decorator="['default_value', { rules: [{ required: false }] }]"
|
||||
mode="tags"
|
||||
|
@ -95,12 +105,7 @@
|
|||
</a-input-number>
|
||||
<a-input
|
||||
style="width: 100%"
|
||||
v-else-if="
|
||||
currentValueType === '2' ||
|
||||
currentValueType === '5' ||
|
||||
currentValueType === '7' ||
|
||||
currentValueType === '8'
|
||||
"
|
||||
v-else-if="['2', '5', '7', '8', '9'].includes(currentValueType)"
|
||||
v-decorator="['default_value', { rules: [{ required: false }] }]"
|
||||
>
|
||||
</a-input>
|
||||
|
@ -157,7 +162,18 @@
|
|||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="currentValueType === '2' ? 6 : 0" v-if="currentValueType !== '6'">
|
||||
<a-col
|
||||
v-if="currentValueType === '11'"
|
||||
:span="12"
|
||||
>
|
||||
<ReferenceModelSelect
|
||||
:form="form"
|
||||
:isLazyRequire="false"
|
||||
:formItemLayout="formItemLayout"
|
||||
/>
|
||||
</a-col>
|
||||
|
||||
<!-- <a-col :span="currentValueType === '2' ? 6 : 0" v-if="currentValueType !== '6'">
|
||||
<a-form-item
|
||||
:hidden="currentValueType === '2' ? false : true"
|
||||
:label-col="horizontalFormItemLayout.labelCol"
|
||||
|
@ -189,10 +205,10 @@
|
|||
v-decorator="['is_index', { rules: [], valuePropName: 'checked' }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-col> -->
|
||||
<a-col :span="6" v-if="currentValueType !== '6' && currentValueType !== '7'">
|
||||
<a-form-item
|
||||
:label-col="currentValueType === '2' ? { span: 8 } : horizontalFormItemLayout.labelCol"
|
||||
:label-col="horizontalFormItemLayout.labelCol"
|
||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||
:label="$t('cmdb.ciType.unique')"
|
||||
>
|
||||
|
@ -206,7 +222,7 @@
|
|||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-form-item
|
||||
:label-col="['2', '6', '7'].findIndex(i => currentValueType === i) === -1 ? { span: 8 } : horizontalFormItemLayout.labelCol"
|
||||
:label-col="horizontalFormItemLayout.labelCol"
|
||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||
:label="$t('required')"
|
||||
>
|
||||
|
@ -219,7 +235,7 @@
|
|||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-form-item
|
||||
:label-col="currentValueType === '2' ? { span: 12 } : horizontalFormItemLayout.labelCol"
|
||||
:label-col="horizontalFormItemLayout.labelCol"
|
||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||
>
|
||||
<template slot="label">
|
||||
|
@ -228,8 +244,8 @@
|
|||
>{{ $t('cmdb.ciType.defaultShow') }}
|
||||
<a-tooltip :title="$t('cmdb.ciType.defaultShowTips')">
|
||||
<a-icon
|
||||
style="position:absolute;top:2px;left:-17px;color:#2f54eb;"
|
||||
type="question-circle"
|
||||
style="position:absolute;top:2px;left:-17px;color:#A5A9BC;"
|
||||
type="info-circle"
|
||||
theme="filled"
|
||||
@click="
|
||||
(e) => {
|
||||
|
@ -250,7 +266,7 @@
|
|||
</a-col>
|
||||
<a-col :span="6" v-if="currentValueType !== '6' && currentValueType !== '7'">
|
||||
<a-form-item
|
||||
:label-col="currentValueType === '2' ? horizontalFormItemLayout.labelCol : { span: 8 }"
|
||||
:label-col="horizontalFormItemLayout.labelCol"
|
||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||
:label="$t('cmdb.ciType.isSortable')"
|
||||
>
|
||||
|
@ -263,7 +279,7 @@
|
|||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="6" v-if="currentValueType !== '6' && currentValueType !== '7'">
|
||||
<a-col :span="6" v-if="!['6', '7', '10'].includes(currentValueType)">
|
||||
<a-form-item
|
||||
:label-col="currentValueType === '2' ? { span: 8 } : horizontalFormItemLayout.labelCol"
|
||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||
|
@ -274,8 +290,8 @@
|
|||
>{{ $t('cmdb.ciType.list') }}
|
||||
<a-tooltip :title="$t('cmdb.ciType.listTips')">
|
||||
<a-icon
|
||||
style="position:absolute;top:3px;left:-17px;color:#2f54eb;"
|
||||
type="question-circle"
|
||||
style="position:absolute;top:3px;left:-17px;color:#A5A9BC;"
|
||||
type="info-circle"
|
||||
theme="filled"
|
||||
@click="
|
||||
(e) => {
|
||||
|
@ -297,7 +313,7 @@
|
|||
</a-col>
|
||||
<a-col span="6">
|
||||
<a-form-item
|
||||
:label-col="['2', '6', '7'].findIndex(i => currentValueType === i) === -1 ? { span: 12 } : horizontalFormItemLayout.labelCol"
|
||||
:label-col="horizontalFormItemLayout.labelCol"
|
||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||
>
|
||||
<template slot="label">
|
||||
|
@ -306,8 +322,8 @@
|
|||
>{{ $t('cmdb.ciType.isDynamic') }}
|
||||
<a-tooltip :title="$t('cmdb.ciType.dynamicTips')">
|
||||
<a-icon
|
||||
style="position:absolute;top:3px;left:-17px;color:#2f54eb;"
|
||||
type="question-circle"
|
||||
style="position:absolute;top:3px;left:-17px;color:#A5A9BC;"
|
||||
type="info-circle"
|
||||
theme="filled"
|
||||
@click="
|
||||
(e) => {
|
||||
|
@ -328,17 +344,22 @@
|
|||
</a-col>
|
||||
<a-divider style="font-size:14px;margin-top:6px;">{{ $t('cmdb.ciType.advancedSettings') }}</a-divider>
|
||||
<a-row>
|
||||
<a-col :span="24" v-if="!['6'].includes(currentValueType)">
|
||||
<a-col :span="24">
|
||||
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 12 }" :label="$t('cmdb.ciType.reg')">
|
||||
<RegSelect :isShowErrorMsg="false" v-model="re_check" :limitedFormat="getLimitedFormat()" />
|
||||
<RegSelect
|
||||
:isShowErrorMsg="false"
|
||||
:limitedFormat="getLimitedFormat()"
|
||||
:disabled="['6', '10', '11'].includes(currentValueType)"
|
||||
v-model="re_check"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }" :label="$t('cmdb.ciType.font')">
|
||||
<FontArea ref="fontArea" />
|
||||
<FontArea ref="fontArea" :fontColorDisabled="['8', '11'].includes(currentValueType)" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24" v-if="!['6', '7'].includes(currentValueType)">
|
||||
<a-col :span="24" v-if="!['6', '7', '10', '11'].includes(currentValueType)">
|
||||
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }" :label="$t('cmdb.ciType.choiceValue')">
|
||||
<PreValueArea
|
||||
v-if="drawerVisible"
|
||||
|
@ -349,7 +370,7 @@
|
|||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24" v-if="!['6', '7'].includes(currentValueType)">
|
||||
<a-col :span="24" v-if="!['6', '7', '10', '11'].includes(currentValueType)">
|
||||
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
|
||||
<template slot="label">
|
||||
<span
|
||||
|
@ -357,8 +378,8 @@
|
|||
>{{ $t('cmdb.ciType.computedAttribute') }}
|
||||
<a-tooltip :title="$t('cmdb.ciType.computedAttributeTips')">
|
||||
<a-icon
|
||||
style="position:absolute;top:3px;left:-17px;color:#2f54eb;"
|
||||
type="question-circle"
|
||||
style="position:absolute;top:3px;left:-17px;color:#A5A9BC;"
|
||||
type="info-circle"
|
||||
theme="filled"
|
||||
@click="
|
||||
(e) => {
|
||||
|
@ -415,14 +436,16 @@ import {
|
|||
calcComputedAttribute,
|
||||
} from '@/modules/cmdb/api/CITypeAttr'
|
||||
import { valueTypeMap } from '../../utils/const'
|
||||
import { getPropertyType, getPropertyIcon } from '../../utils/helper'
|
||||
import ComputedArea from './computedArea.vue'
|
||||
import PreValueArea from './preValueArea.vue'
|
||||
import FontArea from './fontArea.vue'
|
||||
import RegSelect from '@/components/RegexSelect'
|
||||
import ReferenceModelSelect from './attributeEdit/referenceModelSelect.vue'
|
||||
|
||||
export default {
|
||||
name: 'AttributeEditForm',
|
||||
components: { ComputedArea, PreValueArea, vueJsonEditor, FontArea, RegSelect },
|
||||
components: { ComputedArea, PreValueArea, vueJsonEditor, FontArea, RegSelect, ReferenceModelSelect },
|
||||
props: {
|
||||
CITypeId: {
|
||||
type: Number,
|
||||
|
@ -467,7 +490,7 @@ export default {
|
|||
return formLayout === 'horizontal'
|
||||
? {
|
||||
labelCol: { span: 8 },
|
||||
wrapperCol: { span: 12 },
|
||||
wrapperCol: { span: 15 },
|
||||
}
|
||||
: {}
|
||||
},
|
||||
|
@ -484,6 +507,7 @@ export default {
|
|||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
getPropertyIcon,
|
||||
async handleCreate() {
|
||||
try {
|
||||
await canDefineComputed()
|
||||
|
@ -516,9 +540,7 @@ export default {
|
|||
}
|
||||
}
|
||||
if (property === 'is_list') {
|
||||
this.form.setFieldsValue({
|
||||
default_value: checked ? [] : '',
|
||||
})
|
||||
this.handleSwitchIsList(checked)
|
||||
}
|
||||
if (checked && property === 'is_sortable') {
|
||||
this.$message.warning(this.$t('cmdb.ciType.addAttributeTips1'))
|
||||
|
@ -536,6 +558,26 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
handleSwitchIsList(checked) {
|
||||
let defaultValue = checked ? [] : ''
|
||||
|
||||
switch (this.currentValueType) {
|
||||
case '2':
|
||||
case '9':
|
||||
defaultValue = ''
|
||||
break
|
||||
case '10':
|
||||
defaultValue = checked ? '' : false
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
this.form.setFieldsValue({
|
||||
default_value: defaultValue,
|
||||
})
|
||||
},
|
||||
|
||||
async handleEdit(record, attributes) {
|
||||
try {
|
||||
await canDefineComputed()
|
||||
|
@ -544,12 +586,7 @@ export default {
|
|||
this.canDefineComputed = false
|
||||
}
|
||||
const _record = _.cloneDeep(record)
|
||||
if (_record.is_password) {
|
||||
_record.value_type = '7'
|
||||
}
|
||||
if (_record.is_link) {
|
||||
_record.value_type = '8'
|
||||
}
|
||||
_record.value_type = getPropertyType(_record)
|
||||
this.drawerTitle = this.$t('cmdb.ciType.editAttribute')
|
||||
this.drawerVisible = true
|
||||
this.record = _record
|
||||
|
@ -573,8 +610,13 @@ export default {
|
|||
is_dynamic: _record.is_dynamic,
|
||||
})
|
||||
}
|
||||
if (_record.value_type === '11') {
|
||||
this.form.setFieldsValue({
|
||||
reference_type_id: _record.reference_type_id
|
||||
})
|
||||
}
|
||||
console.log(_record)
|
||||
if (!['6'].includes(_record.value_type) && _record.re_check) {
|
||||
if (!['6', '10', '11'].includes(_record.value_type) && _record.re_check) {
|
||||
this.re_check = {
|
||||
value: _record.re_check,
|
||||
}
|
||||
|
@ -583,7 +625,11 @@ export default {
|
|||
}
|
||||
if (_record.default) {
|
||||
this.$nextTick(() => {
|
||||
if (_record.value_type === '0') {
|
||||
if (_record.value_type === '10') {
|
||||
this.form.setFieldsValue({
|
||||
default_value: Boolean(_record.default.default),
|
||||
})
|
||||
} else if (_record.value_type === '0') {
|
||||
if (_record.is_list) {
|
||||
this.$nextTick(() => {
|
||||
this.form.setFieldsValue({
|
||||
|
@ -639,7 +685,7 @@ export default {
|
|||
})
|
||||
}
|
||||
const _find = attributes.find((item) => item.id === _record.id)
|
||||
if (!['6', '7'].includes(_record.value_type)) {
|
||||
if (!['6', '7', '10', '11'].includes(_record.value_type)) {
|
||||
this.$refs.preValueArea.setData({
|
||||
choice_value: (_find || {}).choice_value || [],
|
||||
choice_web_hook: _record.choice_web_hook,
|
||||
|
@ -672,7 +718,9 @@ export default {
|
|||
delete values['default_show']
|
||||
delete values['is_required']
|
||||
const { default_value } = values
|
||||
if (values.value_type === '0' && default_value) {
|
||||
if (values.value_type === '10') {
|
||||
values.default = { default: values.is_list ? default_value : Boolean(default_value) }
|
||||
} else if (values.value_type === '0' && default_value) {
|
||||
if (values.is_list) {
|
||||
values.default = { default: default_value || null }
|
||||
} else {
|
||||
|
@ -706,23 +754,42 @@ export default {
|
|||
values = { ...values, ...computedAreaData }
|
||||
} else {
|
||||
// If it is a non-computed attribute, check to see if there is a predefined value
|
||||
if (!['6', '7'].includes(values.value_type)) {
|
||||
if (!['6', '7', '10', '11'].includes(values.value_type)) {
|
||||
const preValueAreaData = this.$refs.preValueArea.getData()
|
||||
values = { ...values, ...preValueAreaData }
|
||||
}
|
||||
}
|
||||
const fontOptions = this.$refs.fontArea.getData()
|
||||
if (values.value_type === '7') {
|
||||
values.value_type = '2'
|
||||
values.is_password = true
|
||||
}
|
||||
if (values.value_type === '8') {
|
||||
values.value_type = '2'
|
||||
values.is_link = true
|
||||
}
|
||||
if (values.value_type !== '6') {
|
||||
|
||||
if (!['6', '10', '11'].includes(values.value_type)) {
|
||||
values.re_check = this.re_check?.value ?? null
|
||||
}
|
||||
|
||||
// 重置数据类型
|
||||
switch (values.value_type) {
|
||||
case '7':
|
||||
values.value_type = '2'
|
||||
values.is_password = true
|
||||
break
|
||||
case '8':
|
||||
values.value_type = '2'
|
||||
values.is_link = true
|
||||
break
|
||||
case '9':
|
||||
values.value_type = '2'
|
||||
break
|
||||
case '10':
|
||||
values.value_type = '7'
|
||||
values.is_bool = true
|
||||
break
|
||||
case '11':
|
||||
values.value_type = '0'
|
||||
values.is_reference = true
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
if (values.id) {
|
||||
await this.updateAttribute(values.id, { ...values, option: { fontOptions } }, isCalcComputed)
|
||||
} else {
|
||||
|
@ -806,6 +873,9 @@ export default {
|
|||
line-height: 22px;
|
||||
color: #a5a9bc;
|
||||
}
|
||||
.value-type-text {
|
||||
margin-left: 4px;
|
||||
}
|
||||
</style>
|
||||
<style lang="less">
|
||||
.attribute-edit-form {
|
||||
|
|
|
@ -16,21 +16,21 @@
|
|||
<a-space style="margin-bottom: 10px">
|
||||
<a-button @click="handleAddGroup" size="small" icon="plus">{{ $t('cmdb.ciType.group') }}</a-button>
|
||||
<a-button @click="handleOpenUniqueConstraint" size="small">{{ $t('cmdb.ciType.uniqueConstraint') }}</a-button>
|
||||
<div>
|
||||
<div class="ci-types-attributes-flex">
|
||||
<a-tooltip
|
||||
v-for="typeKey in Object.keys(valueTypeMap)"
|
||||
:key="typeKey"
|
||||
:title="$t('cmdb.ciType.filterTips', { name: valueTypeMap[typeKey] })"
|
||||
v-for="item in valueTypeMap"
|
||||
:key="item.key"
|
||||
:title="$t('cmdb.ciType.filterTips', { name: item.value })"
|
||||
>
|
||||
<span
|
||||
@click="handleFilterType(typeKey)"
|
||||
@click="handleFilterType(item.key)"
|
||||
:class="{
|
||||
'ci-types-attributes-filter': true,
|
||||
'ci-types-attributes-filter-selected': attrTypeFilter.includes(typeKey),
|
||||
'ci-types-attributes-filter-selected': attrTypeFilter.includes(item.key),
|
||||
}"
|
||||
>
|
||||
<ops-icon :type="getPropertyIcon({ value_type: typeKey })" />
|
||||
{{ valueTypeMap[typeKey] }}
|
||||
<ops-icon :type="getPropertyIcon({ value_type: item.key })" />
|
||||
{{ item.value }}
|
||||
</span>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
|
@ -200,7 +200,7 @@ import AttributeEditForm from './attributeEditForm.vue'
|
|||
import NewCiTypeAttrModal from './newCiTypeAttrModal.vue'
|
||||
import UniqueConstraint from './uniqueConstraint.vue'
|
||||
import { valueTypeMap } from '../../utils/const'
|
||||
import { getPropertyIcon } from '../../utils/helper'
|
||||
import { getPropertyIcon, getPropertyType } from '../../utils/helper'
|
||||
|
||||
export default {
|
||||
name: 'AttributesTable',
|
||||
|
@ -243,7 +243,12 @@ export default {
|
|||
return this.$store.state.windowHeight
|
||||
},
|
||||
valueTypeMap() {
|
||||
return valueTypeMap()
|
||||
const map = valueTypeMap()
|
||||
const keys = ['0', '1', '2', '9', '3', '4', '5', '6', '7', '8', '10', '11']
|
||||
return keys.map((key) => ({
|
||||
key,
|
||||
value: map[key]
|
||||
}))
|
||||
},
|
||||
},
|
||||
provide() {
|
||||
|
@ -585,23 +590,8 @@ export default {
|
|||
if (!attrTypeFilter.length) {
|
||||
return true
|
||||
} else {
|
||||
if (attrTypeFilter.includes('7') && attr.is_password) {
|
||||
return true
|
||||
}
|
||||
if (attrTypeFilter.includes('8') && attr.is_link) {
|
||||
return true
|
||||
}
|
||||
if (
|
||||
attrTypeFilter.includes(attr.value_type) &&
|
||||
attr.value_type === '2' &&
|
||||
(attr.is_password || attr.is_link)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
if (attrTypeFilter.includes(attr.value_type)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
const valueType = getPropertyType(attr)
|
||||
return attrTypeFilter.includes(valueType)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
@ -618,6 +608,12 @@ export default {
|
|||
.ci-types-attributes {
|
||||
padding: 0 20px;
|
||||
overflow-y: auto;
|
||||
|
||||
&-flex {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.ci-types-attributes-filter {
|
||||
color: @text-color_4;
|
||||
cursor: pointer;
|
||||
|
|
|
@ -46,16 +46,21 @@
|
|||
v-decorator="['value_type', { rules: [{ required: true }], initialValue: '2' }]"
|
||||
@change="handleChangeValueType"
|
||||
>
|
||||
<a-select-option :value="key" :key="key" v-for="(value, key) in valueTypeMap">
|
||||
{{ value }}
|
||||
<span class="value-type-des" v-if="key === '3'">yyyy-mm-dd HH:MM:SS</span>
|
||||
<span class="value-type-des" v-if="key === '4'">yyyy-mm-dd</span>
|
||||
<span class="value-type-des" v-if="key === '5'">HH:MM:SS</span>
|
||||
<a-select-option :value="item.key" :key="item.key" v-for="(item) in valueTypeMap">
|
||||
<ops-icon :type="getPropertyIcon({ value_type: item.key })" />
|
||||
<span class="value-type-text">{{ item.value }}</span>
|
||||
<span class="value-type-des" v-if="item.key === '2'">{{ $t('cmdb.ciType.shortTextTip') }}</span>
|
||||
<span class="value-type-des" v-if="item.key === '3'">yyyy-mm-dd HH:MM:SS</span>
|
||||
<span class="value-type-des" v-if="item.key === '4'">yyyy-mm-dd</span>
|
||||
<span class="value-type-des" v-if="item.key === '5'">HH:MM:SS</span>
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="currentValueType === '6' ? 24 : 12">
|
||||
<a-col
|
||||
v-if="currentValueType !== '11'"
|
||||
:span="currentValueType === '6' ? 24 : 12"
|
||||
>
|
||||
<a-form-item
|
||||
:label-col="{ span: currentValueType === '6' ? 4 : 8 }"
|
||||
:wrapper-col="{ span: currentValueType === '6' ? 18 : 15 }"
|
||||
|
@ -68,6 +73,10 @@
|
|||
v-decorator="['default_value', { rules: [{ required: false }] }]"
|
||||
>
|
||||
</a-input>
|
||||
<a-switch
|
||||
v-else-if="currentValueType === '10'"
|
||||
v-decorator="['default_value', { rules: [{ required: false }], valuePropName: 'checked' }]"
|
||||
/>
|
||||
<a-input-number
|
||||
style="width: 100%"
|
||||
v-else-if="currentValueType === '1'"
|
||||
|
@ -86,12 +95,7 @@
|
|||
</a-select>
|
||||
<a-input
|
||||
style="width: 100%"
|
||||
v-else-if="
|
||||
currentValueType === '2' ||
|
||||
currentValueType === '5' ||
|
||||
currentValueType === '7' ||
|
||||
currentValueType === '8'
|
||||
"
|
||||
v-else-if="['2', '5', '7', '8', '9'].includes(currentValueType)"
|
||||
v-decorator="['default_value', { rules: [{ required: false }] }]"
|
||||
>
|
||||
</a-input>
|
||||
|
@ -148,9 +152,19 @@
|
|||
</template>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col
|
||||
v-if="currentValueType === '11'"
|
||||
:span="12"
|
||||
>
|
||||
<ReferenceModelSelect
|
||||
:form="form"
|
||||
:formItemLayout="formItemLayout"
|
||||
/>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-col :span="currentValueType === '2' ? 6 : 0" v-if="currentValueType !== '6'">
|
||||
<!-- <a-col :span="currentValueType === '2' ? 6 : 0" v-if="currentValueType !== '6'">
|
||||
<a-form-item
|
||||
:hidden="currentValueType === '2' ? false : true"
|
||||
:label-col="horizontalFormItemLayout.labelCol"
|
||||
|
@ -182,10 +196,10 @@
|
|||
v-decorator="['is_index', { rules: [], valuePropName: 'checked', initialValue: true }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-col> -->
|
||||
<a-col :span="6" v-if="currentValueType !== '6' && currentValueType !== '7'">
|
||||
<a-form-item
|
||||
:label-col="currentValueType === '2' ? { span: 8 } : horizontalFormItemLayout.labelCol"
|
||||
:label-col="horizontalFormItemLayout.labelCol"
|
||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||
:label="$t('cmdb.ciType.unique')"
|
||||
>
|
||||
|
@ -199,7 +213,7 @@
|
|||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-form-item
|
||||
:label-col="['2', '6', '7'].findIndex(i => currentValueType === i) === -1 ? { span: 8 } : horizontalFormItemLayout.labelCol"
|
||||
:label-col="horizontalFormItemLayout.labelCol"
|
||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||
:label="$t('required')"
|
||||
>
|
||||
|
@ -212,7 +226,7 @@
|
|||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-form-item
|
||||
:label-col="currentValueType === '2' ? { span: 12 } : horizontalFormItemLayout.labelCol"
|
||||
:label-col="horizontalFormItemLayout.labelCol"
|
||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||
>
|
||||
<template slot="label">
|
||||
|
@ -221,8 +235,8 @@
|
|||
>{{ $t('cmdb.ciType.defaultShow') }}
|
||||
<a-tooltip :title="$t('cmdb.ciType.defaultShowTips')">
|
||||
<a-icon
|
||||
style="position:absolute;top:2px;left:-17px;color:#2f54eb;"
|
||||
type="question-circle"
|
||||
style="position:absolute;top:2px;left:-17px;color:#A5A9BC;"
|
||||
type="info-circle"
|
||||
theme="filled"
|
||||
@click="
|
||||
(e) => {
|
||||
|
@ -243,7 +257,7 @@
|
|||
</a-col>
|
||||
<a-col :span="6" v-if="currentValueType !== '6' && currentValueType !== '7'">
|
||||
<a-form-item
|
||||
:label-col="currentValueType === '2' ? horizontalFormItemLayout.labelCol : { span: 8 }"
|
||||
:label-col="horizontalFormItemLayout.labelCol"
|
||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||
:label="$t('cmdb.ciType.isSortable')"
|
||||
>
|
||||
|
@ -256,7 +270,7 @@
|
|||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="6" v-if="currentValueType !== '6' && currentValueType !== '7'">
|
||||
<a-col :span="6" v-if="!['6', '7', '10'].includes(currentValueType)">
|
||||
<a-form-item
|
||||
:label-col="currentValueType === '2' ? { span: 8 } : horizontalFormItemLayout.labelCol"
|
||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||
|
@ -264,11 +278,11 @@
|
|||
<template slot="label">
|
||||
<span
|
||||
style="position:relative;white-space:pre;"
|
||||
>{{ $t('cmdb.ciType.list') }}
|
||||
>
|
||||
<a-tooltip :title="$t('cmdb.ciType.listTips')">
|
||||
<a-icon
|
||||
style="position:absolute;top:3px;left:-17px;color:#2f54eb;"
|
||||
type="question-circle"
|
||||
style="position:absolute;top:3px;left:-17px;color:#A5A9BC;"
|
||||
type="info-circle"
|
||||
theme="filled"
|
||||
@click="
|
||||
(e) => {
|
||||
|
@ -278,6 +292,7 @@
|
|||
"
|
||||
/>
|
||||
</a-tooltip>
|
||||
{{ $t('cmdb.ciType.list') }}
|
||||
</span>
|
||||
</template>
|
||||
<a-switch
|
||||
|
@ -290,17 +305,17 @@
|
|||
</a-col>
|
||||
<a-col span="6">
|
||||
<a-form-item
|
||||
:label-col="['2', '6', '7'].findIndex(i => currentValueType === i) === -1 ? { span: 12 } : horizontalFormItemLayout.labelCol"
|
||||
:label-col="horizontalFormItemLayout.labelCol"
|
||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||
>
|
||||
<template slot="label">
|
||||
<span
|
||||
style="position:relative;white-space:pre;"
|
||||
>{{ $t('cmdb.ciType.isDynamic') }}
|
||||
>
|
||||
<a-tooltip :title="$t('cmdb.ciType.dynamicTips')">
|
||||
<a-icon
|
||||
style="position:absolute;top:3px;left:-17px;color:#2f54eb;"
|
||||
type="question-circle"
|
||||
style="position:absolute;top:3px;left:-17px;color:#A5A9BC;"
|
||||
type="info-circle"
|
||||
theme="filled"
|
||||
@click="
|
||||
(e) => {
|
||||
|
@ -310,6 +325,7 @@
|
|||
"
|
||||
/>
|
||||
</a-tooltip>
|
||||
{{ $t('cmdb.ciType.isDynamic') }}
|
||||
</span>
|
||||
</template>
|
||||
<a-switch
|
||||
|
@ -321,17 +337,22 @@
|
|||
</a-col>
|
||||
<a-divider style="font-size:14px;margin-top:6px;">{{ $t('cmdb.ciType.advancedSettings') }}</a-divider>
|
||||
<a-row>
|
||||
<a-col :span="24" v-if="!['6'].includes(currentValueType)">
|
||||
<a-col :span="24">
|
||||
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 12 }" :label="$t('cmdb.ciType.reg')">
|
||||
<RegSelect :isShowErrorMsg="false" v-model="re_check" :limitedFormat="getLimitedFormat()" />
|
||||
<RegSelect
|
||||
v-model="re_check"
|
||||
:isShowErrorMsg="false"
|
||||
:limitedFormat="getLimitedFormat()"
|
||||
:disabled="['6', '10', '11'].includes(currentValueType)"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }" :label="$t('cmdb.ciType.font')">
|
||||
<FontArea ref="fontArea" />
|
||||
<FontArea ref="fontArea" :fontColorDisabled="['8', '11'].includes(currentValueType)" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24" v-if="!['6', '7'].includes(currentValueType)">
|
||||
<a-col :span="24" v-if="!['6', '7', '10', '11'].includes(currentValueType)">
|
||||
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }" :label="$t('cmdb.ciType.choiceValue')">
|
||||
<PreValueArea
|
||||
ref="preValueArea"
|
||||
|
@ -341,16 +362,16 @@
|
|||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24" v-if="!['6', '7'].includes(currentValueType)">
|
||||
<a-col :span="24" v-if="!['6', '7', '10', '11'].includes(currentValueType)">
|
||||
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
|
||||
<template slot="label">
|
||||
<span
|
||||
style="position:relative;white-space:pre;"
|
||||
>{{ $t('cmdb.ciType.computedAttribute') }}
|
||||
>
|
||||
<a-tooltip :title="$t('cmdb.ciType.computedAttributeTips')">
|
||||
<a-icon
|
||||
style="position:absolute;top:3px;left:-17px;color:#2f54eb;"
|
||||
type="question-circle"
|
||||
style="position:absolute;top:3px;left:-17px;color:#A5A9BC;"
|
||||
type="info-circle"
|
||||
theme="filled"
|
||||
@click="
|
||||
(e) => {
|
||||
|
@ -360,6 +381,7 @@
|
|||
"
|
||||
/>
|
||||
</a-tooltip>
|
||||
{{ $t('cmdb.ciType.computedAttribute') }}
|
||||
</span>
|
||||
</template>
|
||||
<a-switch
|
||||
|
@ -392,6 +414,8 @@ import ComputedArea from './computedArea.vue'
|
|||
import PreValueArea from './preValueArea.vue'
|
||||
import FontArea from './fontArea.vue'
|
||||
import RegSelect from '@/components/RegexSelect'
|
||||
import { getPropertyIcon } from '../../utils/helper'
|
||||
import ReferenceModelSelect from './attributeEdit/referenceModelSelect.vue'
|
||||
|
||||
export default {
|
||||
name: 'CreateNewAttribute',
|
||||
|
@ -401,6 +425,7 @@ export default {
|
|||
vueJsonEditor,
|
||||
FontArea,
|
||||
RegSelect,
|
||||
ReferenceModelSelect,
|
||||
},
|
||||
props: {
|
||||
hasFooter: {
|
||||
|
@ -437,13 +462,19 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
valueTypeMap() {
|
||||
return valueTypeMap()
|
||||
const map = valueTypeMap()
|
||||
const keys = ['0', '1', '2', '9', '3', '4', '5', '6', '7', '8', '10', '11']
|
||||
return keys.map((key) => ({
|
||||
key,
|
||||
value: map[key]
|
||||
}))
|
||||
},
|
||||
canDefineScript() {
|
||||
return this.canDefineComputed
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getPropertyIcon,
|
||||
handleSubmit(isCloseModal = true) {
|
||||
this.form.validateFields(async (err, values) => {
|
||||
if (!err) {
|
||||
|
@ -456,7 +487,9 @@ export default {
|
|||
const data = { is_required, default_show, is_dynamic }
|
||||
delete values.is_required
|
||||
delete values.default_show
|
||||
if (values.value_type === '0' && default_value) {
|
||||
if (values.value_type === '10') {
|
||||
values.default = { default: values.is_list ? (default_value || null) : Boolean(default_value) }
|
||||
} else if (values.value_type === '0' && default_value) {
|
||||
if (values.is_list) {
|
||||
values.default = { default: default_value || null }
|
||||
} else {
|
||||
|
@ -489,39 +522,48 @@ export default {
|
|||
values = { ...values, ...computedAreaData }
|
||||
} else {
|
||||
// If it is a non-computed attribute, check to see if there is a predefined value
|
||||
if (!['6', '7'].includes(values.value_type)) {
|
||||
if (!['6', '7', '10', '11'].includes(values.value_type)) {
|
||||
const preValueAreaData = this.$refs.preValueArea.getData()
|
||||
values = { ...values, ...preValueAreaData }
|
||||
}
|
||||
}
|
||||
const fontOptions = this.$refs.fontArea.getData()
|
||||
|
||||
// is_index: except for text, the index is hidden, text index default is true
|
||||
// 5 types in the box, is_index=true
|
||||
// json, password, link is_index=false
|
||||
if (['6', '7', '8'].includes(values.value_type)) {
|
||||
values.is_index = false
|
||||
} else if (values.value_type !== '2') {
|
||||
values.is_index = true
|
||||
}
|
||||
if (values.value_type === '7') {
|
||||
values.value_type = '2'
|
||||
values.is_password = true
|
||||
}
|
||||
if (values.value_type === '8') {
|
||||
values.value_type = '2'
|
||||
values.is_link = true
|
||||
}
|
||||
if (values.value_type !== '6') {
|
||||
values.re_check = this.re_check?.value ?? null
|
||||
// 索引
|
||||
values.is_index = !['6', '7', '8', '9', '11'].includes(values.value_type)
|
||||
|
||||
// 重置数据类型
|
||||
switch (values.value_type) {
|
||||
case '7':
|
||||
values.value_type = '2'
|
||||
values.is_password = true
|
||||
break
|
||||
case '8':
|
||||
values.value_type = '2'
|
||||
values.is_link = true
|
||||
break
|
||||
case '9':
|
||||
values.value_type = '2'
|
||||
break
|
||||
case '10':
|
||||
values.value_type = '7'
|
||||
values.is_bool = true
|
||||
break
|
||||
case '11':
|
||||
values.value_type = '0'
|
||||
values.is_reference = true
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
const { attr_id } = await createAttribute({ ...values, option: { fontOptions } })
|
||||
|
||||
this.form.resetFields()
|
||||
this.currentValueType = '2'
|
||||
if (!['6'].includes(values.value_type) && !values.is_password) {
|
||||
if (this?.$refs?.preValueArea) {
|
||||
this.$refs.preValueArea.valueList = []
|
||||
}
|
||||
this.currentValueType = '2'
|
||||
this.$emit('done', attr_id, data, isCloseModal)
|
||||
} else {
|
||||
throw new Error()
|
||||
|
@ -540,11 +582,12 @@ export default {
|
|||
}
|
||||
},
|
||||
handleChangeValueType(value) {
|
||||
this.currentValueType = value
|
||||
this.$nextTick(() => {
|
||||
this.form.setFieldsValue({
|
||||
default_value: this.form.getFieldValue('is_list') || value === '0' ? [] : null,
|
||||
})
|
||||
this.currentValueType = value
|
||||
if (['6', '10', '11'].includes(value)) {
|
||||
this.re_check = {}
|
||||
}
|
||||
this.handleSwitchType({ valueType: value })
|
||||
})
|
||||
},
|
||||
onChange(checked, property) {
|
||||
|
@ -560,9 +603,7 @@ export default {
|
|||
}
|
||||
}
|
||||
if (property === 'is_list') {
|
||||
this.form.setFieldsValue({
|
||||
default_value: checked ? [] : '',
|
||||
})
|
||||
this.handleSwitchType({ checked })
|
||||
}
|
||||
if (checked && property === 'is_sortable') {
|
||||
this.$message.warning(this.$t('cmdb.ciType.addAttributeTips1'))
|
||||
|
@ -579,6 +620,33 @@ export default {
|
|||
})
|
||||
}
|
||||
},
|
||||
|
||||
handleSwitchType({
|
||||
checked,
|
||||
valueType
|
||||
}) {
|
||||
checked = checked ?? this.form.getFieldValue('is_list')
|
||||
valueType = valueType ?? this.currentValueType
|
||||
|
||||
let defaultValue = checked || valueType === '0' ? [] : ''
|
||||
|
||||
switch (valueType) {
|
||||
case '2':
|
||||
case '9':
|
||||
defaultValue = ''
|
||||
break
|
||||
case '10':
|
||||
defaultValue = checked ? '' : false
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
this.form.setFieldsValue({
|
||||
default_value: defaultValue,
|
||||
})
|
||||
},
|
||||
|
||||
onJsonChange(value) {
|
||||
this.default_value_json_right = true
|
||||
},
|
||||
|
@ -629,6 +697,9 @@ export default {
|
|||
line-height: 22px;
|
||||
color: #a5a9bc;
|
||||
}
|
||||
.value-type-text {
|
||||
margin: 0 4px;
|
||||
}
|
||||
</style>
|
||||
<style lang="less">
|
||||
.create-new-attribute {
|
||||
|
|
|
@ -21,7 +21,13 @@
|
|||
<a-icon type="underline" />
|
||||
</div>
|
||||
<div :style="{ width: '100px', marginLeft: '10px', display: 'inline-flex', alignItems: 'center' }">
|
||||
<a-icon type="font-colors" /><el-color-picker size="mini" v-model="fontOptions.color"> </el-color-picker>
|
||||
<a-icon type="font-colors" />
|
||||
<el-color-picker
|
||||
size="mini"
|
||||
:disabled="fontColorDisabled"
|
||||
v-model="fontOptions.color"
|
||||
>
|
||||
</el-color-picker>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -30,6 +36,12 @@
|
|||
import _ from 'lodash'
|
||||
export default {
|
||||
name: 'FontArea',
|
||||
props: {
|
||||
fontColorDisabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
fontOptions: {
|
||||
|
@ -57,7 +69,11 @@ export default {
|
|||
if (flag) {
|
||||
return undefined
|
||||
} else {
|
||||
return this.fontOptions
|
||||
const fontOptions = _.cloneDeep(this.fontOptions)
|
||||
if (this.fontColorDisabled) {
|
||||
Reflect.deleteProperty(fontOptions, 'color')
|
||||
}
|
||||
return fontOptions
|
||||
}
|
||||
},
|
||||
setData({ fontOptions = {} }) {
|
||||
|
|
|
@ -545,7 +545,7 @@ export default {
|
|||
},
|
||||
showIdSelectOptions() {
|
||||
const _showIdSelectOptions = this.currentTypeAttrs.filter(
|
||||
(item) => item.id !== this.unique_id && !['6'].includes(item.value_type) && !item.is_password && !item.is_list
|
||||
(item) => item.id !== this.unique_id && !['6'].includes(item.value_type) && !item.is_password && !item.is_list && !item.is_bool && !item.is_reference
|
||||
)
|
||||
if (this.showIdFilterInput) {
|
||||
return _showIdSelectOptions.filter(
|
||||
|
@ -898,6 +898,7 @@ export default {
|
|||
this.loadCITypes()
|
||||
this.loading = false
|
||||
this.drawerVisible = false
|
||||
this.isInherit = false
|
||||
}, 1000)
|
||||
},
|
||||
async updateCIType(CITypeId, data) {
|
||||
|
@ -916,6 +917,7 @@ export default {
|
|||
this.loadCITypes()
|
||||
this.loading = false
|
||||
this.drawerVisible = false
|
||||
this.isInherit = false
|
||||
}, 1000)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -47,9 +47,32 @@
|
|||
>
|
||||
<ops-icon class="text-group-icon" type="veops-text" />
|
||||
</div>
|
||||
<CIReferenceAttr
|
||||
v-if="getAttr(rule.property).is_reference && (rule.exp === 'is' || rule.exp === '~is')"
|
||||
class="select-filter"
|
||||
:referenceTypeId="getAttr(rule.property).reference_type_id"
|
||||
:value="rule.value"
|
||||
:disabled="disabled"
|
||||
@change="(value) => handleChange('value', value)"
|
||||
/>
|
||||
<a-select
|
||||
v-else-if="getAttr(rule.property).is_bool && (rule.exp === 'is' || rule.exp === '~is')"
|
||||
class="select-filter"
|
||||
:disabled="disabled"
|
||||
:placeholder="$t('placeholder2')"
|
||||
:value="rule.value"
|
||||
@change="(value) => handleChange('value', value)"
|
||||
>
|
||||
<a-select-option key="1">
|
||||
true
|
||||
</a-select-option>
|
||||
<a-select-option key="0">
|
||||
false
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<div
|
||||
class="input-group"
|
||||
v-if="isChoiceByProperty(rule.property) && (rule.exp === 'is' || rule.exp === '~is')"
|
||||
v-else-if="isChoiceByProperty(rule.property) && (rule.exp === 'is' || rule.exp === '~is')"
|
||||
>
|
||||
<treeselect
|
||||
class="custom-treeselect"
|
||||
|
@ -148,9 +171,13 @@
|
|||
|
||||
<script>
|
||||
import { compareTypeList } from '../constants.js'
|
||||
import CIReferenceAttr from '@/components/ciReferenceAttr/index.vue'
|
||||
|
||||
export default {
|
||||
name: 'ValueControls',
|
||||
components: {
|
||||
CIReferenceAttr
|
||||
},
|
||||
props: {
|
||||
rule: {
|
||||
type: Object,
|
||||
|
@ -215,7 +242,10 @@ export default {
|
|||
...this.rule,
|
||||
[key]: value
|
||||
})
|
||||
}
|
||||
},
|
||||
getAttr(property) {
|
||||
return this.attrList.find((item) => item.name === property) || {}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -270,4 +300,21 @@ export default {
|
|||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
.select-filter {
|
||||
height: 36px;
|
||||
width: 136px;
|
||||
|
||||
/deep/ .ant-select-selection {
|
||||
height: 36px;
|
||||
background: #f7f8fa;
|
||||
line-height: 36px;
|
||||
border: none;
|
||||
|
||||
.ant-select-selection__rendered {
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -137,6 +137,7 @@ import {
|
|||
getCITypeChildren,
|
||||
getCITypeParent
|
||||
} from '../../api/CITypeRelation.js'
|
||||
import { getCITypeAttributesById } from '../../api/CITypeAttr'
|
||||
|
||||
export default {
|
||||
name: 'RelationAutoDiscovery',
|
||||
|
@ -169,7 +170,18 @@ export default {
|
|||
methods: {
|
||||
async getCITypeAttributes() {
|
||||
const res = await getCITypeAttributes(this.CITypeId)
|
||||
this.ciTypeADTAttributes = res.map((item) => {
|
||||
const attr = await getCITypeAttributesById(this.CITypeId)
|
||||
|
||||
const filterAttr = res.filter((name) => {
|
||||
const currentAttr = attr?.attributes?.find((item) => item?.name === name)
|
||||
if (!currentAttr) {
|
||||
return true
|
||||
}
|
||||
|
||||
return this.filterAttributes(name)
|
||||
})
|
||||
|
||||
this.ciTypeADTAttributes = filterAttr.map((item) => {
|
||||
return {
|
||||
id: item,
|
||||
value: item,
|
||||
|
@ -239,7 +251,7 @@ export default {
|
|||
const peer_type_id = item.peer_type_id
|
||||
const attributes = this?.relationOptions?.find((option) => option?.value === peer_type_id)?.attributes
|
||||
|
||||
item.attributes = attributes
|
||||
item.attributes = attributes.filter((attr) => this.filterAttributes(attr))
|
||||
item.peer_attr_id = undefined
|
||||
})
|
||||
},
|
||||
|
@ -288,6 +300,15 @@ export default {
|
|||
this.getCITypeRelations()
|
||||
}
|
||||
},
|
||||
|
||||
filterAttributes(attr) {
|
||||
// filter password/json/is_list/longText/bool/reference
|
||||
if (attr?.value_type === '2' && !attr?.is_index) {
|
||||
return false
|
||||
}
|
||||
|
||||
return !attr?.is_password && !attr?.is_list && attr?.value_type !== '6' && !attr?.is_bool && !attr?.is_reference
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -598,8 +598,14 @@ export default {
|
|||
})
|
||||
},
|
||||
filterAttributes(attributes) {
|
||||
// filter password/json/is_list
|
||||
return attributes.filter((attr) => !attr.is_password && !attr.is_list && attr.value_type !== '6')
|
||||
// filter password/json/is_list/longText/bool/reference
|
||||
return attributes.filter((attr) => {
|
||||
if (attr.value_type === '2' && !attr.is_index) {
|
||||
return false
|
||||
}
|
||||
|
||||
return !attr.is_password && !attr.is_list && attr.value_type !== '6' && !attr.is_bool && !attr.is_reference
|
||||
})
|
||||
},
|
||||
addTableAttr() {
|
||||
this.tableAttrList.push({
|
||||
|
|
|
@ -471,10 +471,15 @@ export default {
|
|||
this.dateForm = _.cloneDeep(this.defaultDateForm)
|
||||
this.notifies = _.cloneDeep(this.defaultNotify)
|
||||
this.category = 1
|
||||
this.triggerAction = '1'
|
||||
this.filterExp = ''
|
||||
this.selectedBot = undefined
|
||||
this.visible = false
|
||||
if (this.$refs.noticeContent) {
|
||||
this.$refs.noticeContent.destroy()
|
||||
}
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.visible = false
|
||||
})
|
||||
},
|
||||
filterChange(value) {
|
||||
this.filterValue = value
|
||||
|
|
|
@ -364,8 +364,14 @@ export default {
|
|||
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
},
|
||||
filterAttributes(attributes) {
|
||||
// filter password/json/is_list
|
||||
return attributes.filter((attr) => !attr.is_password && !attr.is_list && attr.value_type !== '6')
|
||||
// filter password/json/is_list/longText/bool/reference
|
||||
return attributes.filter((attr) => {
|
||||
if (attr.value_type === '2' && !attr.is_index) {
|
||||
return false
|
||||
}
|
||||
|
||||
return !attr.is_password && !attr.is_list && attr.value_type !== '6' && !attr.is_bool && !attr.is_reference
|
||||
})
|
||||
},
|
||||
|
||||
addModalAttr() {
|
||||
|
|
|
@ -306,8 +306,14 @@ export default {
|
|||
return _find?.alias ?? _find?.name ?? id
|
||||
},
|
||||
filterAttributes(attributes) {
|
||||
// filter password/json/is_list
|
||||
return attributes.filter((attr) => !attr.is_password && !attr.is_list && attr.value_type !== '6')
|
||||
// filter password/json/is_list/longText/bool/reference
|
||||
return attributes.filter((attr) => {
|
||||
if (attr.value_type === '2' && !attr.is_index) {
|
||||
return false
|
||||
}
|
||||
|
||||
return !attr.is_password && !attr.is_list && attr.value_type !== '6' && !attr.is_bool && !attr.is_reference
|
||||
})
|
||||
},
|
||||
|
||||
addTableAttr() {
|
||||
|
|
|
@ -1,250 +1,260 @@
|
|||
<template>
|
||||
<a-modal
|
||||
v-model="visible"
|
||||
width="90%"
|
||||
:closable="false"
|
||||
:centered="true"
|
||||
:maskClosable="false"
|
||||
:destroyOnClose="true"
|
||||
@cancel="handleClose"
|
||||
@ok="handleOk"
|
||||
>
|
||||
<div :style="{ width: '100%' }" id="add-table-modal">
|
||||
<a-spin :spinning="loading">
|
||||
<SearchForm
|
||||
ref="searchForm"
|
||||
:typeId="addTypeId"
|
||||
:preferenceAttrList="preferenceAttrList"
|
||||
@refresh="handleSearch"
|
||||
>
|
||||
<a-button
|
||||
@click="
|
||||
() => {
|
||||
$refs.createInstanceForm.handleOpen(true, 'create')
|
||||
}
|
||||
"
|
||||
slot="extraContent"
|
||||
type="primary"
|
||||
size="small"
|
||||
>新增</a-button
|
||||
>
|
||||
</SearchForm>
|
||||
<vxe-table
|
||||
ref="xTable"
|
||||
row-id="_id"
|
||||
:data="tableData"
|
||||
:height="tableHeight"
|
||||
highlight-hover-row
|
||||
:checkbox-config="{ reserve: true }"
|
||||
@checkbox-change="onSelectChange"
|
||||
@checkbox-all="onSelectChange"
|
||||
show-overflow="tooltip"
|
||||
show-header-overflow="tooltip"
|
||||
:scroll-y="{ enabled: true, gt: 50 }"
|
||||
:scroll-x="{ enabled: true, gt: 0 }"
|
||||
class="ops-stripe-table"
|
||||
>
|
||||
<vxe-column align="center" type="checkbox" width="60" fixed="left"></vxe-column>
|
||||
<vxe-table-column
|
||||
v-for="col in columns"
|
||||
:key="col.field"
|
||||
:title="col.title"
|
||||
:field="col.field"
|
||||
:width="col.width"
|
||||
:sortable="col.sortable"
|
||||
>
|
||||
<template #default="{row}" v-if="col.value_type === '6'">
|
||||
<span v-if="col.value_type === '6' && row[col.field]">{{ JSON.stringify(row[col.field]) }}</span>
|
||||
</template>
|
||||
</vxe-table-column>
|
||||
</vxe-table>
|
||||
<a-pagination
|
||||
v-model="currentPage"
|
||||
size="small"
|
||||
:total="totalNumber"
|
||||
show-quick-jumper
|
||||
:page-size="50"
|
||||
:show-total="
|
||||
(total, range) =>
|
||||
$t('pagination.total', {
|
||||
range0: range[0],
|
||||
range1: range[1],
|
||||
total,
|
||||
})
|
||||
"
|
||||
:style="{ textAlign: 'right', marginTop: '10px' }"
|
||||
@change="handleChangePage"
|
||||
/>
|
||||
</a-spin>
|
||||
</div>
|
||||
<CreateInstanceForm
|
||||
ref="createInstanceForm"
|
||||
:typeIdFromRelation="addTypeId"
|
||||
@reload="
|
||||
() => {
|
||||
currentPage = 1
|
||||
getTableData(true)
|
||||
}
|
||||
"
|
||||
/>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { searchCI } from '@/modules/cmdb/api/ci'
|
||||
import { getSubscribeAttributes } from '@/modules/cmdb/api/preference'
|
||||
import { batchUpdateCIRelationChildren, batchUpdateCIRelationParents } from '@/modules/cmdb/api/CIRelation'
|
||||
import { getCITableColumns } from '../../../utils/helper'
|
||||
import SearchForm from '../../../components/searchForm/SearchForm.vue'
|
||||
import CreateInstanceForm from '../../ci/modules/CreateInstanceForm.vue'
|
||||
import { getCITypeAttributesById } from '@/modules/cmdb/api/CITypeAttr'
|
||||
|
||||
export default {
|
||||
name: 'AddTableModal',
|
||||
components: { SearchForm, CreateInstanceForm },
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
currentPage: 1,
|
||||
totalNumber: 0,
|
||||
tableData: [],
|
||||
columns: [],
|
||||
ciObj: {},
|
||||
ciId: null,
|
||||
addTypeId: null,
|
||||
loading: false,
|
||||
expression: '',
|
||||
isFocusExpression: false,
|
||||
type: 'children',
|
||||
preferenceAttrList: [],
|
||||
ancestor_ids: undefined,
|
||||
attrList1: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
tableHeight() {
|
||||
return this.$store.state.windowHeight - 250
|
||||
},
|
||||
placeholder() {
|
||||
return this.isFocusExpression ? this.$t('cmdb.serviceTreetips1') : this.$t('cmdb.serviceTreetips2')
|
||||
},
|
||||
width() {
|
||||
return this.isFocusExpression ? '500px' : '100px'
|
||||
},
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
attrList: () => {
|
||||
return this.attrList
|
||||
},
|
||||
}
|
||||
},
|
||||
watch: {},
|
||||
methods: {
|
||||
async openModal(ciObj, ciId, addTypeId, type, ancestor_ids = undefined) {
|
||||
console.log(ciObj, ciId, addTypeId, type)
|
||||
this.visible = true
|
||||
this.ciObj = ciObj
|
||||
this.ciId = ciId
|
||||
this.addTypeId = addTypeId
|
||||
this.type = type
|
||||
this.ancestor_ids = ancestor_ids
|
||||
await getSubscribeAttributes(addTypeId).then((res) => {
|
||||
this.preferenceAttrList = res.attributes // 已经订阅的全部列
|
||||
})
|
||||
getCITypeAttributesById(addTypeId).then((res) => {
|
||||
this.attrList = res.attributes
|
||||
})
|
||||
this.getTableData(true)
|
||||
},
|
||||
async getTableData(isInit) {
|
||||
if (this.addTypeId) {
|
||||
await this.fetchData(isInit)
|
||||
}
|
||||
},
|
||||
async fetchData(isInit) {
|
||||
this.loading = true
|
||||
// if (isInit) {
|
||||
// const subscribed = await getSubscribeAttributes(this.addTypeId)
|
||||
// this.preferenceAttrList = subscribed.attributes // 已经订阅的全部列
|
||||
// }
|
||||
let sort, fuzzySearch, expression, exp
|
||||
if (!isInit) {
|
||||
fuzzySearch = this.$refs['searchForm'].fuzzySearch
|
||||
expression = this.$refs['searchForm'].expression || ''
|
||||
const regQ = /(?<=q=).+(?=&)|(?<=q=).+$/g
|
||||
|
||||
exp = expression.match(regQ) ? expression.match(regQ)[0] : null
|
||||
}
|
||||
|
||||
await searchCI({
|
||||
q: `_type:${this.addTypeId}${exp ? `,${exp}` : ''}${fuzzySearch ? `,*${fuzzySearch}*` : ''}`,
|
||||
count: 50,
|
||||
page: this.currentPage,
|
||||
sort,
|
||||
})
|
||||
.then((res) => {
|
||||
this.tableData = res.result
|
||||
this.totalNumber = res.numfound
|
||||
this.columns = this.getColumns(res.result, this.preferenceAttrList)
|
||||
this.$nextTick(() => {
|
||||
const _table = this.$refs.xTable
|
||||
if (_table) {
|
||||
_table.refreshColumn()
|
||||
}
|
||||
this.loading = false
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
getColumns(data, attrList) {
|
||||
const modalDom = document.getElementById('add-table-modal')
|
||||
if (modalDom) {
|
||||
const width = modalDom.clientWidth - 50
|
||||
return getCITableColumns(data, attrList, width)
|
||||
}
|
||||
return []
|
||||
},
|
||||
onSelectChange() {},
|
||||
handleClose() {
|
||||
this.$refs.xTable.clearCheckboxRow()
|
||||
this.currentPage = 1
|
||||
this.expression = ''
|
||||
this.isFocusExpression = false
|
||||
this.visible = false
|
||||
},
|
||||
async handleOk() {
|
||||
const selectRecordsCurrent = this.$refs.xTable.getCheckboxRecords()
|
||||
const selectRecordsReserved = this.$refs.xTable.getCheckboxReserveRecords()
|
||||
const ciIds = [...selectRecordsCurrent, ...selectRecordsReserved].map((record) => record._id)
|
||||
if (ciIds.length) {
|
||||
if (this.type === 'children') {
|
||||
await batchUpdateCIRelationChildren(ciIds, [this.ciId], this.ancestor_ids)
|
||||
} else {
|
||||
await batchUpdateCIRelationParents(ciIds, [this.ciId])
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.$message.success(this.$t('addSuccess'))
|
||||
this.handleClose()
|
||||
this.$emit('reload')
|
||||
}, 500)
|
||||
} else {
|
||||
this.handleClose()
|
||||
this.$emit('reload')
|
||||
}
|
||||
},
|
||||
handleSearch() {
|
||||
this.currentPage = 1
|
||||
this.fetchData()
|
||||
},
|
||||
handleChangePage(page, pageSize) {
|
||||
this.currentPage = page
|
||||
this.fetchData()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
<template>
|
||||
<a-modal
|
||||
v-model="visible"
|
||||
width="90%"
|
||||
:closable="false"
|
||||
:centered="true"
|
||||
:maskClosable="false"
|
||||
:destroyOnClose="true"
|
||||
@cancel="handleClose"
|
||||
@ok="handleOk"
|
||||
>
|
||||
<div :style="{ width: '100%' }" id="add-table-modal">
|
||||
<a-spin :spinning="loading">
|
||||
<SearchForm
|
||||
ref="searchForm"
|
||||
:typeId="addTypeId"
|
||||
:preferenceAttrList="preferenceAttrList"
|
||||
@refresh="handleSearch"
|
||||
>
|
||||
<a-button
|
||||
@click="
|
||||
() => {
|
||||
$refs.createInstanceForm.handleOpen(true, 'create')
|
||||
}
|
||||
"
|
||||
slot="extraContent"
|
||||
type="primary"
|
||||
size="small"
|
||||
>新增</a-button
|
||||
>
|
||||
</SearchForm>
|
||||
<vxe-table
|
||||
ref="xTable"
|
||||
row-id="_id"
|
||||
:data="tableData"
|
||||
:height="tableHeight"
|
||||
highlight-hover-row
|
||||
:checkbox-config="{ reserve: true }"
|
||||
@checkbox-change="onSelectChange"
|
||||
@checkbox-all="onSelectChange"
|
||||
show-overflow="tooltip"
|
||||
show-header-overflow="tooltip"
|
||||
:scroll-y="{ enabled: true, gt: 50 }"
|
||||
:scroll-x="{ enabled: true, gt: 0 }"
|
||||
class="ops-stripe-table"
|
||||
>
|
||||
<vxe-column align="center" type="checkbox" width="60" fixed="left"></vxe-column>
|
||||
<vxe-table-column
|
||||
v-for="col in columns"
|
||||
:key="col.field"
|
||||
:title="col.title"
|
||||
:field="col.field"
|
||||
:width="col.width"
|
||||
:sortable="col.sortable"
|
||||
>
|
||||
<template v-if="col.is_reference" #default="{row}">
|
||||
<a
|
||||
v-for="(id) in (col.is_list ? row[col.field] : [row[col.field]])"
|
||||
:key="id"
|
||||
:href="`/cmdb/cidetail/${col.reference_type_id}/${id}`"
|
||||
target="_blank"
|
||||
>
|
||||
{{ id }}
|
||||
</a>
|
||||
</template>
|
||||
<template #default="{row}" v-else-if="col.value_type == '6'">
|
||||
<span v-if="col.value_type == '6' && row[col.field]">{{ JSON.stringify(row[col.field]) }}</span>
|
||||
</template>
|
||||
</vxe-table-column>
|
||||
</vxe-table>
|
||||
<a-pagination
|
||||
v-model="currentPage"
|
||||
size="small"
|
||||
:total="totalNumber"
|
||||
show-quick-jumper
|
||||
:page-size="50"
|
||||
:show-total="
|
||||
(total, range) =>
|
||||
$t('pagination.total', {
|
||||
range0: range[0],
|
||||
range1: range[1],
|
||||
total,
|
||||
})
|
||||
"
|
||||
:style="{ textAlign: 'right', marginTop: '10px' }"
|
||||
@change="handleChangePage"
|
||||
/>
|
||||
</a-spin>
|
||||
</div>
|
||||
<CreateInstanceForm
|
||||
ref="createInstanceForm"
|
||||
:typeIdFromRelation="addTypeId"
|
||||
@reload="
|
||||
() => {
|
||||
currentPage = 1
|
||||
getTableData(true)
|
||||
}
|
||||
"
|
||||
/>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { searchCI } from '@/modules/cmdb/api/ci'
|
||||
import { getSubscribeAttributes } from '@/modules/cmdb/api/preference'
|
||||
import { batchUpdateCIRelationChildren, batchUpdateCIRelationParents } from '@/modules/cmdb/api/CIRelation'
|
||||
import { getCITableColumns } from '../../../utils/helper'
|
||||
import SearchForm from '../../../components/searchForm/SearchForm.vue'
|
||||
import CreateInstanceForm from '../../ci/modules/CreateInstanceForm.vue'
|
||||
import { getCITypeAttributesById } from '@/modules/cmdb/api/CITypeAttr'
|
||||
|
||||
export default {
|
||||
name: 'AddTableModal',
|
||||
components: { SearchForm, CreateInstanceForm },
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
currentPage: 1,
|
||||
totalNumber: 0,
|
||||
tableData: [],
|
||||
columns: [],
|
||||
ciObj: {},
|
||||
ciId: null,
|
||||
addTypeId: null,
|
||||
loading: false,
|
||||
expression: '',
|
||||
isFocusExpression: false,
|
||||
type: 'children',
|
||||
preferenceAttrList: [],
|
||||
ancestor_ids: undefined,
|
||||
attrList1: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
tableHeight() {
|
||||
return this.$store.state.windowHeight - 250
|
||||
},
|
||||
placeholder() {
|
||||
return this.isFocusExpression ? this.$t('cmdb.serviceTreetips1') : this.$t('cmdb.serviceTreetips2')
|
||||
},
|
||||
width() {
|
||||
return this.isFocusExpression ? '500px' : '100px'
|
||||
},
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
attrList: () => {
|
||||
return this.attrList
|
||||
},
|
||||
}
|
||||
},
|
||||
watch: {},
|
||||
methods: {
|
||||
async openModal(ciObj, ciId, addTypeId, type, ancestor_ids = undefined) {
|
||||
console.log(ciObj, ciId, addTypeId, type)
|
||||
this.visible = true
|
||||
this.ciObj = ciObj
|
||||
this.ciId = ciId
|
||||
this.addTypeId = addTypeId
|
||||
this.type = type
|
||||
this.ancestor_ids = ancestor_ids
|
||||
await getSubscribeAttributes(addTypeId).then((res) => {
|
||||
this.preferenceAttrList = res.attributes // 已经订阅的全部列
|
||||
})
|
||||
getCITypeAttributesById(addTypeId).then((res) => {
|
||||
this.attrList = res.attributes
|
||||
})
|
||||
this.getTableData(true)
|
||||
},
|
||||
async getTableData(isInit) {
|
||||
if (this.addTypeId) {
|
||||
await this.fetchData(isInit)
|
||||
}
|
||||
},
|
||||
async fetchData(isInit) {
|
||||
this.loading = true
|
||||
// if (isInit) {
|
||||
// const subscribed = await getSubscribeAttributes(this.addTypeId)
|
||||
// this.preferenceAttrList = subscribed.attributes // 已经订阅的全部列
|
||||
// }
|
||||
let sort, fuzzySearch, expression, exp
|
||||
if (!isInit) {
|
||||
fuzzySearch = this.$refs['searchForm'].fuzzySearch
|
||||
expression = this.$refs['searchForm'].expression || ''
|
||||
const regQ = /(?<=q=).+(?=&)|(?<=q=).+$/g
|
||||
|
||||
exp = expression.match(regQ) ? expression.match(regQ)[0] : null
|
||||
}
|
||||
|
||||
await searchCI({
|
||||
q: `_type:${this.addTypeId}${exp ? `,${exp}` : ''}${fuzzySearch ? `,*${fuzzySearch}*` : ''}`,
|
||||
count: 50,
|
||||
page: this.currentPage,
|
||||
sort,
|
||||
})
|
||||
.then((res) => {
|
||||
this.tableData = res.result
|
||||
this.totalNumber = res.numfound
|
||||
this.columns = this.getColumns(res.result, this.preferenceAttrList)
|
||||
this.$nextTick(() => {
|
||||
const _table = this.$refs.xTable
|
||||
if (_table) {
|
||||
_table.refreshColumn()
|
||||
}
|
||||
this.loading = false
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
getColumns(data, attrList) {
|
||||
const modalDom = document.getElementById('add-table-modal')
|
||||
if (modalDom) {
|
||||
const width = modalDom.clientWidth - 50
|
||||
return getCITableColumns(data, attrList, width)
|
||||
}
|
||||
return []
|
||||
},
|
||||
onSelectChange() {},
|
||||
handleClose() {
|
||||
this.$refs.xTable.clearCheckboxRow()
|
||||
this.currentPage = 1
|
||||
this.expression = ''
|
||||
this.isFocusExpression = false
|
||||
this.visible = false
|
||||
},
|
||||
async handleOk() {
|
||||
const selectRecordsCurrent = this.$refs.xTable.getCheckboxRecords()
|
||||
const selectRecordsReserved = this.$refs.xTable.getCheckboxReserveRecords()
|
||||
const ciIds = [...selectRecordsCurrent, ...selectRecordsReserved].map((record) => record._id)
|
||||
if (ciIds.length) {
|
||||
if (this.type === 'children') {
|
||||
await batchUpdateCIRelationChildren(ciIds, [this.ciId], this.ancestor_ids)
|
||||
} else {
|
||||
await batchUpdateCIRelationParents(ciIds, [this.ciId])
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.$message.success(this.$t('addSuccess'))
|
||||
this.handleClose()
|
||||
this.$emit('reload')
|
||||
}, 500)
|
||||
} else {
|
||||
this.handleClose()
|
||||
this.$emit('reload')
|
||||
}
|
||||
},
|
||||
handleSearch() {
|
||||
this.currentPage = 1
|
||||
this.fetchData()
|
||||
},
|
||||
handleChangePage(page, pageSize) {
|
||||
this.currentPage = page
|
||||
this.fetchData()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
|
|
|
@ -101,8 +101,18 @@
|
|||
:minWidth="100"
|
||||
:cell-type="col.value_type === '2' ? 'string' : 'auto'"
|
||||
>
|
||||
<template v-if="col.value_type === '6' || col.is_link || col.is_password || col.is_choice" #default="{row}">
|
||||
<span v-if="col.value_type === '6' && row[col.field]">{{ JSON.stringify(row[col.field]) }}</span>
|
||||
<template v-if="col.value_type === '6' || col.is_link || col.is_password || col.is_choice || col.is_reference" #default="{row}">
|
||||
<template v-if="col.is_reference && row[col.field]" >
|
||||
<a
|
||||
v-for="(ciId) in (col.is_list ? row[col.field] : [row[col.field]])"
|
||||
:key="ciId"
|
||||
:href="`/cmdb/cidetail/${col.reference_type_id}/${ciId}`"
|
||||
target="_blank"
|
||||
>
|
||||
{{ getReferenceAttrValue(ciId, col) }}
|
||||
</a>
|
||||
</template>
|
||||
<span v-else-if="col.value_type === '6' && row[col.field]">{{ JSON.stringify(row[col.field]) }}</span>
|
||||
<template v-else-if="col.is_link && row[col.field]">
|
||||
<a
|
||||
v-for="(item, linkIndex) in (col.is_list ? row[col.field] : [row[col.field]])"
|
||||
|
@ -254,6 +264,8 @@ export default {
|
|||
sortByTable: undefined,
|
||||
loading: false,
|
||||
columnsGroup: [],
|
||||
referenceShowAttrNameMap: {},
|
||||
referenceCIIdMap: {},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -433,12 +445,99 @@ export default {
|
|||
await Promise.all(promises1).then(() => {
|
||||
this.columnsGroup = [..._commonColumnsGroup, ..._columnsGroup]
|
||||
this.instanceList = res['result']
|
||||
this.handlePerference()
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
handlePerference() {
|
||||
let needRequiredCIType = []
|
||||
this.columnsGroup.forEach((group) => {
|
||||
group.children.forEach((col) => {
|
||||
if (col?.is_reference && col?.reference_type_id) {
|
||||
needRequiredCIType.push(col)
|
||||
}
|
||||
})
|
||||
})
|
||||
needRequiredCIType = _.uniq(needRequiredCIType)
|
||||
|
||||
if (!needRequiredCIType.length) {
|
||||
this.referenceShowAttrNameMap = {}
|
||||
this.referenceCIIdMap = {}
|
||||
return
|
||||
}
|
||||
|
||||
this.handleReferenceShowAttrName(needRequiredCIType)
|
||||
this.handleReferenceCIIdMap(needRequiredCIType)
|
||||
},
|
||||
|
||||
async handleReferenceShowAttrName(needRequiredCIType) {
|
||||
const res = await getCITypes({
|
||||
type_ids: needRequiredCIType.map((col) => col.reference_type_id).join(',')
|
||||
})
|
||||
|
||||
const map = {}
|
||||
res.ci_types.forEach((ciType) => {
|
||||
map[ciType.id] = ciType?.show_name || ciType?.unique_name || ''
|
||||
})
|
||||
|
||||
this.referenceShowAttrNameMap = map
|
||||
},
|
||||
|
||||
async handleReferenceCIIdMap(needRequiredCIType) {
|
||||
const map = {}
|
||||
this.instanceList.forEach((row) => {
|
||||
needRequiredCIType.forEach((col) => {
|
||||
const ids = Array.isArray(row[col.field]) ? row[col.field] : row[col.field] ? [row[col.field]] : []
|
||||
if (ids.length) {
|
||||
if (!map?.[col.reference_type_id]) {
|
||||
map[col.reference_type_id] = {}
|
||||
}
|
||||
ids.forEach((id) => {
|
||||
map[col.reference_type_id][id] = {}
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
if (!Object.keys(map).length) {
|
||||
this.referenceCIIdMap = {}
|
||||
return
|
||||
}
|
||||
|
||||
const allRes = await Promise.all(
|
||||
Object.keys(map).map((key) => {
|
||||
return searchCI({
|
||||
q: `_type:${key},_id:(${Object.keys(map[key]).join(';')})`,
|
||||
count: 9999
|
||||
})
|
||||
})
|
||||
)
|
||||
|
||||
allRes.forEach((res) => {
|
||||
res.result.forEach((item) => {
|
||||
if (map?.[item._type]?.[item._id]) {
|
||||
map[item._type][item._id] = item
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
this.referenceCIIdMap = map
|
||||
},
|
||||
|
||||
getReferenceAttrValue(id, col) {
|
||||
const ci = this?.referenceCIIdMap?.[col?.reference_type_id]?.[id]
|
||||
if (!ci) {
|
||||
return id
|
||||
}
|
||||
|
||||
const attrName = this.referenceShowAttrNameMap?.[col.reference_type_id]
|
||||
return ci?.[attrName] || id
|
||||
},
|
||||
|
||||
getColumns(data, attrList) {
|
||||
const width = document.getElementById('resource_search').clientWidth - 50
|
||||
return getCITableColumns(data, attrList, width).map((item) => {
|
||||
|
|
|
@ -14,7 +14,7 @@ export default {
|
|||
name: 'TreeViewsNode',
|
||||
props: {
|
||||
title: {
|
||||
type: [String, Number],
|
||||
type: [String, Number, Boolean],
|
||||
default: '',
|
||||
},
|
||||
treeKey: {
|
||||
|
|
Loading…
Reference in New Issue