mirror of
				https://github.com/veops/cmdb.git
				synced 2025-11-04 13:46:17 +08:00 
			
		
		
		
	Merge pull request #594 from veops/dev_ui_240820
feat(ui): add bool and reference type
This commit is contained in:
		@@ -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.
										
									
								
							
							
								
								
									
										18
									
								
								cmdb-ui/src/api/cmdb.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								cmdb-ui/src/api/cmdb.js
									
									
									
									
									
										Normal file
									
								
							@@ -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 {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										178
									
								
								cmdb-ui/src/components/ciReferenceAttr/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								cmdb-ui/src/components/ciReferenceAttr/index.vue
									
									
									
									
									
										Normal file
									
								
							@@ -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: {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user