mirror of
				https://github.com/veops/cmdb.git
				synced 2025-11-04 21:56:16 +08:00 
			
		
		
		
	dashboard ui update
This commit is contained in:
		@@ -68,7 +68,8 @@ export default {
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  methods: {
 | 
					  methods: {
 | 
				
			||||||
    visibleChange(open) {
 | 
					    visibleChange(open, isInitOne = true) {
 | 
				
			||||||
 | 
					      // isInitOne  初始化exp为空时,ruleList是否默认给一条
 | 
				
			||||||
      //   const regQ = /(?<=q=).+(?=&)|(?<=q=).+$/g
 | 
					      //   const regQ = /(?<=q=).+(?=&)|(?<=q=).+$/g
 | 
				
			||||||
      const exp = this.expression.match(new RegExp(this.regQ, 'g'))
 | 
					      const exp = this.expression.match(new RegExp(this.regQ, 'g'))
 | 
				
			||||||
        ? this.expression.match(new RegExp(this.regQ, 'g'))[0]
 | 
					        ? this.expression.match(new RegExp(this.regQ, 'g'))[0]
 | 
				
			||||||
@@ -151,15 +152,20 @@ export default {
 | 
				
			|||||||
        })
 | 
					        })
 | 
				
			||||||
        this.ruleList = [...expArray]
 | 
					        this.ruleList = [...expArray]
 | 
				
			||||||
      } else if (open) {
 | 
					      } else if (open) {
 | 
				
			||||||
        this.ruleList = [
 | 
					        this.ruleList = isInitOne
 | 
				
			||||||
          {
 | 
					          ? [
 | 
				
			||||||
            id: uuidv4(),
 | 
					              {
 | 
				
			||||||
            type: 'and',
 | 
					                id: uuidv4(),
 | 
				
			||||||
            property: this.canSearchPreferenceAttrList[0].name,
 | 
					                type: 'and',
 | 
				
			||||||
            exp: 'is',
 | 
					                property:
 | 
				
			||||||
            value: null,
 | 
					                  this.canSearchPreferenceAttrList && this.canSearchPreferenceAttrList.length
 | 
				
			||||||
          },
 | 
					                    ? this.canSearchPreferenceAttrList[0].name
 | 
				
			||||||
        ]
 | 
					                    : undefined,
 | 
				
			||||||
 | 
					                exp: 'is',
 | 
				
			||||||
 | 
					                value: null,
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					          : []
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    handleClear() {
 | 
					    handleClear() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -77,6 +77,14 @@ export function getCITypeAttributesByTypeIds(params) {
 | 
				
			|||||||
  })
 | 
					  })
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function getCITypeCommonAttributesByTypeIds(params) {
 | 
				
			||||||
 | 
					  return axios({
 | 
				
			||||||
 | 
					    url: `/v0.1/ci_types/common_attributes`,
 | 
				
			||||||
 | 
					    method: 'get',
 | 
				
			||||||
 | 
					    params: params
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 删除属性
 | 
					 * 删除属性
 | 
				
			||||||
 * @param attrId
 | 
					 * @param attrId
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -61,3 +61,10 @@ export function revokeTypeRelation(first_type_id, second_type_id, rid, data) {
 | 
				
			|||||||
    data
 | 
					    data
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function getRecursive_level2children(type_id) {
 | 
				
			||||||
 | 
					  return axios({
 | 
				
			||||||
 | 
					    url: `/v0.1/ci_type_relations/${type_id}/recursive_level2children`,
 | 
				
			||||||
 | 
					    method: 'GET'
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,3 +37,11 @@ export function batchUpdateCustomDashboard(data) {
 | 
				
			|||||||
        data
 | 
					        data
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function postCustomDashboardPreview(data) {
 | 
				
			||||||
 | 
					    return axios({
 | 
				
			||||||
 | 
					        url: '/v0.1/custom_dashboard/preview',
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        data
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,55 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div :style="{ width: '100%', height: 'calc(100% - 2.2vw)' }">
 | 
					  <div
 | 
				
			||||||
    <div v-if="category === 0" class="cmdb-dashboard-grid-item-chart">
 | 
					    :id="`cmdb-dashboard-${chartId}-${editable}-${isPreview}`"
 | 
				
			||||||
 | 
					    :style="{ width: '100%', height: 'calc(100% - 2.2vw)' }"
 | 
				
			||||||
 | 
					  >
 | 
				
			||||||
 | 
					    <div
 | 
				
			||||||
 | 
					      v-if="options.chartType === 'count'"
 | 
				
			||||||
 | 
					      :style="{ color: options.fontColor || '#fff' }"
 | 
				
			||||||
 | 
					      class="cmdb-dashboard-grid-item-chart"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <div class="cmdb-dashboard-grid-item-chart-icon" v-if="options.showIcon && ciType">
 | 
				
			||||||
 | 
					        <template v-if="ciType.icon">
 | 
				
			||||||
 | 
					          <img v-if="ciType.icon.split('$$')[2]" :src="`/api/common-setting/v1/file/${ciType.icon.split('$$')[3]}`" />
 | 
				
			||||||
 | 
					          <ops-icon
 | 
				
			||||||
 | 
					            v-else
 | 
				
			||||||
 | 
					            :style="{
 | 
				
			||||||
 | 
					              color: ciType.icon.split('$$')[1],
 | 
				
			||||||
 | 
					            }"
 | 
				
			||||||
 | 
					            :type="ciType.icon.split('$$')[0]"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					        <span :style="{ color: '#2f54eb' }" v-else>{{ ciType.name[0].toUpperCase() }}</span>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
      <span :style="{ ...options.fontConfig }">{{ toThousands(data) }}</span>
 | 
					      <span :style="{ ...options.fontConfig }">{{ toThousands(data) }}</span>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					    <vxe-table
 | 
				
			||||||
 | 
					      :max-height="tableHeight"
 | 
				
			||||||
 | 
					      :data="tableData"
 | 
				
			||||||
 | 
					      :stripe="!!options.ret"
 | 
				
			||||||
 | 
					      size="mini"
 | 
				
			||||||
 | 
					      class="ops-stripe-table"
 | 
				
			||||||
 | 
					      v-if="options.chartType === 'table'"
 | 
				
			||||||
 | 
					      :span-method="mergeRowMethod"
 | 
				
			||||||
 | 
					      :border="!options.ret"
 | 
				
			||||||
 | 
					      :show-header="!!options.ret"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <template v-if="options.ret">
 | 
				
			||||||
 | 
					        <vxe-column v-for="col in columns" :key="col" :title="col" :field="col"></vxe-column>
 | 
				
			||||||
 | 
					      </template>
 | 
				
			||||||
 | 
					      <template v-else>
 | 
				
			||||||
 | 
					        <vxe-column
 | 
				
			||||||
 | 
					          v-for="(key, index) in Array(keyLength)"
 | 
				
			||||||
 | 
					          :key="`key${index}`"
 | 
				
			||||||
 | 
					          :title="`key${index}`"
 | 
				
			||||||
 | 
					          :field="`key${index}`"
 | 
				
			||||||
 | 
					        ></vxe-column>
 | 
				
			||||||
 | 
					        <vxe-column field="value" title="value"></vxe-column>
 | 
				
			||||||
 | 
					      </template>
 | 
				
			||||||
 | 
					    </vxe-table>
 | 
				
			||||||
    <div
 | 
					    <div
 | 
				
			||||||
      :id="`cmdb-dashboard-${chartId}-${editable}`"
 | 
					      :id="`cmdb-dashboard-${chartId}-${editable}`"
 | 
				
			||||||
      v-if="category === 1 || category === 2"
 | 
					      v-else-if="category === 1 || category === 2"
 | 
				
			||||||
      class="cmdb-dashboard-grid-item-chart"
 | 
					      class="cmdb-dashboard-grid-item-chart"
 | 
				
			||||||
    ></div>
 | 
					    ></div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
@@ -15,17 +59,27 @@
 | 
				
			|||||||
import * as echarts from 'echarts'
 | 
					import * as echarts from 'echarts'
 | 
				
			||||||
import { mixin } from '@/utils/mixin'
 | 
					import { mixin } from '@/utils/mixin'
 | 
				
			||||||
import { toThousands } from '../../utils/helper'
 | 
					import { toThousands } from '../../utils/helper'
 | 
				
			||||||
import { category_1_bar_options, category_1_pie_options, category_2_bar_options } from './chartOptions'
 | 
					import {
 | 
				
			||||||
 | 
					  category_1_bar_options,
 | 
				
			||||||
 | 
					  category_1_line_options,
 | 
				
			||||||
 | 
					  category_1_pie_options,
 | 
				
			||||||
 | 
					  category_2_bar_options,
 | 
				
			||||||
 | 
					  category_2_pie_options,
 | 
				
			||||||
 | 
					} from './chartOptions'
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
  name: 'Chart',
 | 
					  name: 'Chart',
 | 
				
			||||||
  mixins: [mixin],
 | 
					  mixins: [mixin],
 | 
				
			||||||
  props: {
 | 
					  props: {
 | 
				
			||||||
 | 
					    ci_types: {
 | 
				
			||||||
 | 
					      type: Array,
 | 
				
			||||||
 | 
					      default: () => [],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    chartId: {
 | 
					    chartId: {
 | 
				
			||||||
      type: Number,
 | 
					      type: Number,
 | 
				
			||||||
      default: 0,
 | 
					      default: 0,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    data: {
 | 
					    data: {
 | 
				
			||||||
      type: [Number, Object],
 | 
					      type: [Number, Object, Array],
 | 
				
			||||||
      default: 0,
 | 
					      default: 0,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    category: {
 | 
					    category: {
 | 
				
			||||||
@@ -40,20 +94,65 @@ export default {
 | 
				
			|||||||
      type: Boolean,
 | 
					      type: Boolean,
 | 
				
			||||||
      default: false,
 | 
					      default: false,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    type_id: {
 | 
				
			||||||
 | 
					      type: [Number, Array],
 | 
				
			||||||
 | 
					      default: null,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    isPreview: {
 | 
				
			||||||
 | 
					      type: Boolean,
 | 
				
			||||||
 | 
					      default: false,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  data() {
 | 
					  data() {
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      chart: null,
 | 
					      chart: null,
 | 
				
			||||||
 | 
					      columns: [],
 | 
				
			||||||
 | 
					      tableHeight: '',
 | 
				
			||||||
 | 
					      tableData: [],
 | 
				
			||||||
 | 
					      keyLength: 0,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  computed: {
 | 
				
			||||||
 | 
					    ciType() {
 | 
				
			||||||
 | 
					      if (this.type_id || this.options?.type_ids) {
 | 
				
			||||||
 | 
					        const _find = this.ci_types.find((item) => item.id === this.type_id || item.id === this.options?.type_ids[0])
 | 
				
			||||||
 | 
					        return _find || null
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return null
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  watch: {
 | 
					  watch: {
 | 
				
			||||||
    data: {
 | 
					    data: {
 | 
				
			||||||
      immediate: true,
 | 
					      immediate: true,
 | 
				
			||||||
      deep: true,
 | 
					      deep: true,
 | 
				
			||||||
      handler(newValue, oldValue) {
 | 
					      handler(newValue, oldValue) {
 | 
				
			||||||
        if (this.category === 1 || this.category === 2) {
 | 
					        if (this.category === 1 || this.category === 2) {
 | 
				
			||||||
          if (Object.prototype.toString.call(newValue) === '[object Object]') {
 | 
					          if (this.options.chartType !== 'table' && Object.prototype.toString.call(newValue) === '[object Object]') {
 | 
				
			||||||
            this.setChart()
 | 
					            if (this.isPreview) {
 | 
				
			||||||
 | 
					              this.$nextTick(() => {
 | 
				
			||||||
 | 
					                this.setChart()
 | 
				
			||||||
 | 
					              })
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              this.setChart()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (this.options.chartType === 'table') {
 | 
				
			||||||
 | 
					          this.$nextTick(() => {
 | 
				
			||||||
 | 
					            const dom = document.getElementById(`cmdb-dashboard-${this.chartId}-${this.editable}-${this.isPreview}`)
 | 
				
			||||||
 | 
					            this.tableHeight = dom.offsetHeight
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					          if (this.options.ret) {
 | 
				
			||||||
 | 
					            const excludeKeys = ['_X_ROW_KEY', 'ci_type', 'ci_type_alias', 'unique', 'unique_alias', '_id', '_type']
 | 
				
			||||||
 | 
					            if (newValue && newValue.length) {
 | 
				
			||||||
 | 
					              this.columns = Object.keys(newValue[0]).filter((keys) => !excludeKeys.includes(keys))
 | 
				
			||||||
 | 
					              this.tableData = newValue
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            const _data = []
 | 
				
			||||||
 | 
					            this.keyLength = this.options?.attr_ids?.length ?? 0
 | 
				
			||||||
 | 
					            this.formatTableData(_data, this.data, {})
 | 
				
			||||||
 | 
					            this.tableData = _data
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
@@ -81,13 +180,19 @@ export default {
 | 
				
			|||||||
        this.chart = echarts.init(document.getElementById(`cmdb-dashboard-${this.chartId}-${this.editable}`))
 | 
					        this.chart = echarts.init(document.getElementById(`cmdb-dashboard-${this.chartId}-${this.editable}`))
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (this.category === 1 && this.options.chartType === 'bar') {
 | 
					      if (this.category === 1 && this.options.chartType === 'bar') {
 | 
				
			||||||
        this.chart.setOption(category_1_bar_options(this.data), true)
 | 
					        this.chart.setOption(category_1_bar_options(this.data, this.options), true)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (this.category === 1 && this.options.chartType === 'line') {
 | 
				
			||||||
 | 
					        this.chart.setOption(category_1_line_options(this.data, this.options), true)
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (this.category === 1 && this.options.chartType === 'pie') {
 | 
					      if (this.category === 1 && this.options.chartType === 'pie') {
 | 
				
			||||||
        this.chart.setOption(category_1_pie_options(this.data), true)
 | 
					        this.chart.setOption(category_1_pie_options(this.data, this.options), true)
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (this.category === 2) {
 | 
					      if (this.category === 2 && ['bar', 'line'].includes(this.options.chartType)) {
 | 
				
			||||||
        this.chart.setOption(category_2_bar_options(this.data), true)
 | 
					        this.chart.setOption(category_2_bar_options(this.data, this.options, this.options.chartType), true)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (this.category === 2 && this.options.chartType === 'pie') {
 | 
				
			||||||
 | 
					        this.chart.setOption(category_2_pie_options(this.data, this.options), true)
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    resizeChart() {
 | 
					    resizeChart() {
 | 
				
			||||||
@@ -97,6 +202,34 @@ export default {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    formatTableData(_data, data, obj) {
 | 
				
			||||||
 | 
					      Object.keys(data).forEach((k) => {
 | 
				
			||||||
 | 
					        if (typeof data[k] === 'number') {
 | 
				
			||||||
 | 
					          _data.push({ ...obj, [`key${Object.keys(obj).length}`]: k, value: data[k] })
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          this.formatTableData(_data, data[k], { ...obj, [`key${Object.keys(obj).length}`]: k })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    mergeRowMethod({ row, _rowIndex, column, visibleData }) {
 | 
				
			||||||
 | 
					      const fields = ['key0', 'key1', 'key2']
 | 
				
			||||||
 | 
					      const cellValue = row[column.field]
 | 
				
			||||||
 | 
					      if (cellValue && fields.includes(column.field)) {
 | 
				
			||||||
 | 
					        const prevRow = visibleData[_rowIndex - 1]
 | 
				
			||||||
 | 
					        let nextRow = visibleData[_rowIndex + 1]
 | 
				
			||||||
 | 
					        if (prevRow && prevRow[column.field] === cellValue) {
 | 
				
			||||||
 | 
					          return { rowspan: 0, colspan: 0 }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          let countRowspan = 1
 | 
				
			||||||
 | 
					          while (nextRow && nextRow[column.field] === cellValue) {
 | 
				
			||||||
 | 
					            nextRow = visibleData[++countRowspan + _rowIndex]
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          if (countRowspan > 1) {
 | 
				
			||||||
 | 
					            return { rowspan: countRowspan, colspan: 1 }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
@@ -106,14 +239,28 @@ export default {
 | 
				
			|||||||
  width: 100%;
 | 
					  width: 100%;
 | 
				
			||||||
  height: 100%;
 | 
					  height: 100%;
 | 
				
			||||||
  position: relative;
 | 
					  position: relative;
 | 
				
			||||||
  padding: 10px;
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  justify-content: space-between;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
  > span {
 | 
					  > span {
 | 
				
			||||||
    font-size: 50px;
 | 
					    font-size: 50px;
 | 
				
			||||||
    font-weight: 700;
 | 
					    font-weight: 700;
 | 
				
			||||||
    position: absolute;
 | 
					  }
 | 
				
			||||||
    top: 50%;
 | 
					  .cmdb-dashboard-grid-item-chart-icon {
 | 
				
			||||||
    left: 50%;
 | 
					    > i {
 | 
				
			||||||
    transform: translate(-50%, -50%);
 | 
					      font-size: 4vw;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    > img {
 | 
				
			||||||
 | 
					      width: 4vw;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    > span {
 | 
				
			||||||
 | 
					      display: inline-block;
 | 
				
			||||||
 | 
					      width: 4vw;
 | 
				
			||||||
 | 
					      height: 4vw;
 | 
				
			||||||
 | 
					      font-size: 50px;
 | 
				
			||||||
 | 
					      text-align: center;
 | 
				
			||||||
 | 
					      line-height: 50px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,65 +1,307 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <a-modal :title="`${type === 'add' ? '新增' : '编辑'}图表`" :visible="visible" @cancel="handleclose" @ok="handleok">
 | 
					  <a-modal
 | 
				
			||||||
    <a-form-model ref="chartForm" :model="form" :rules="rules" :label-col="{ span: 6 }" :wrapper-col="{ span: 14 }">
 | 
					    width="1100px"
 | 
				
			||||||
      <a-form-model-item label="类型" prop="category">
 | 
					    :title="`${type === 'add' ? '新增' : '编辑'}图表`"
 | 
				
			||||||
        <a-select v-model="form.category" @change="changeDashboardCategory">
 | 
					    :visible="visible"
 | 
				
			||||||
          <a-select-option v-for="cate in Object.keys(dashboardCategory)" :key="cate" :value="Number(cate)">{{
 | 
					    @cancel="handleclose"
 | 
				
			||||||
            dashboardCategory[cate].label
 | 
					    @ok="handleok"
 | 
				
			||||||
          }}</a-select-option>
 | 
					    :bodyStyle="{ paddingTop: 0 }"
 | 
				
			||||||
        </a-select>
 | 
					  >
 | 
				
			||||||
      </a-form-model-item>
 | 
					    <div class="chart-wrapper">
 | 
				
			||||||
      <a-form-model-item v-if="form.category !== 0" label="名称" prop="name">
 | 
					      <div class="chart-left">
 | 
				
			||||||
        <a-input v-model="form.name" placeholder="请输入图表名称"></a-input>
 | 
					        <a-form-model ref="chartForm" :model="form" :rules="rules" :label-col="{ span: 4 }" :wrapper-col="{ span: 18 }">
 | 
				
			||||||
      </a-form-model-item>
 | 
					          <a-form-model-item label="标题" prop="name">
 | 
				
			||||||
      <a-form-model-item label="模型" prop="type_id">
 | 
					            <a-input v-model="form.name" placeholder="请输入图表标题"></a-input>
 | 
				
			||||||
        <a-select
 | 
					          </a-form-model-item>
 | 
				
			||||||
          show-search
 | 
					          <a-form-model-item label="类型" prop="category" v-if="chartType !== 'count' && chartType !== 'table'">
 | 
				
			||||||
          optionFilterProp="children"
 | 
					            <a-radio-group
 | 
				
			||||||
          @change="changeCIType"
 | 
					              @change="
 | 
				
			||||||
          v-model="form.type_id"
 | 
					                () => {
 | 
				
			||||||
          placeholder="请选择模型"
 | 
					                  resetForm()
 | 
				
			||||||
        >
 | 
					                }
 | 
				
			||||||
          <a-select-option v-for="ci_type in ci_types" :key="ci_type.id" :value="ci_type.id">{{
 | 
					              "
 | 
				
			||||||
            ci_type.alias || ci_type.name
 | 
					              :default-value="1"
 | 
				
			||||||
          }}</a-select-option>
 | 
					              v-model="form.category"
 | 
				
			||||||
        </a-select>
 | 
					            >
 | 
				
			||||||
      </a-form-model-item>
 | 
					              <a-radio-button :value="Number(key)" :key="key" v-for="key in Object.keys(dashboardCategory)">
 | 
				
			||||||
      <a-form-model-item v-if="form.category === 1" label="模型属性" prop="attr_id">
 | 
					                {{ dashboardCategory[key].label }}
 | 
				
			||||||
        <a-select show-search optionFilterProp="children" v-model="form.attr_id" placeholder="请选择模型属性">
 | 
					              </a-radio-button>
 | 
				
			||||||
          <a-select-option v-for="attr in attributes" :key="attr.id" :value="attr.id">{{
 | 
					            </a-radio-group>
 | 
				
			||||||
            attr.alias || attr.name
 | 
					          </a-form-model-item>
 | 
				
			||||||
          }}</a-select-option>
 | 
					          <a-form-model-item label="类型" prop="tableCategory" v-if="chartType === 'table'">
 | 
				
			||||||
        </a-select>
 | 
					            <a-radio-group
 | 
				
			||||||
      </a-form-model-item>
 | 
					              @change="
 | 
				
			||||||
      <a-form-model-item v-if="form.category === 1" label="图表类型" prop="chartType">
 | 
					                () => {
 | 
				
			||||||
        <a-radio-group v-model="chartType">
 | 
					                  resetForm()
 | 
				
			||||||
          <a-radio value="bar">
 | 
					                }
 | 
				
			||||||
            柱状图
 | 
					              "
 | 
				
			||||||
          </a-radio>
 | 
					              :default-value="1"
 | 
				
			||||||
          <a-radio value="pie">
 | 
					              v-model="form.tableCategory"
 | 
				
			||||||
            饼图
 | 
					            >
 | 
				
			||||||
          </a-radio>
 | 
					              <a-radio-button :value="1">
 | 
				
			||||||
        </a-radio-group>
 | 
					                计算指标
 | 
				
			||||||
      </a-form-model-item>
 | 
					              </a-radio-button>
 | 
				
			||||||
      <a-form-model-item v-if="form.category === 2" label="关系层级" prop="level">
 | 
					              <a-radio-button :value="2">
 | 
				
			||||||
        <a-input v-model="form.level" placeholder="请输入关系层级"></a-input>
 | 
					                资源数据
 | 
				
			||||||
      </a-form-model-item>
 | 
					              </a-radio-button>
 | 
				
			||||||
      <a-form-model-item v-if="form.category === 0" label="字体">
 | 
					            </a-radio-group>
 | 
				
			||||||
        <FontConfig ref="fontConfig" />
 | 
					          </a-form-model-item>
 | 
				
			||||||
      </a-form-model-item>
 | 
					          <a-form-model-item
 | 
				
			||||||
    </a-form-model>
 | 
					            v-if="(chartType !== 'table' && form.category !== 2) || (chartType === 'table' && form.tableCategory === 1)"
 | 
				
			||||||
 | 
					            label="模型"
 | 
				
			||||||
 | 
					            prop="type_ids"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <a-select
 | 
				
			||||||
 | 
					              show-search
 | 
				
			||||||
 | 
					              optionFilterProp="children"
 | 
				
			||||||
 | 
					              @change="changeCIType"
 | 
				
			||||||
 | 
					              v-model="form.type_ids"
 | 
				
			||||||
 | 
					              placeholder="请选择模型"
 | 
				
			||||||
 | 
					              mode="multiple"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <a-select-option v-for="ci_type in ci_types" :key="ci_type.id" :value="ci_type.id">{{
 | 
				
			||||||
 | 
					                ci_type.alias || ci_type.name
 | 
				
			||||||
 | 
					              }}</a-select-option>
 | 
				
			||||||
 | 
					            </a-select>
 | 
				
			||||||
 | 
					          </a-form-model-item>
 | 
				
			||||||
 | 
					          <a-form-model-item v-else label="模型" prop="type_id">
 | 
				
			||||||
 | 
					            <a-select
 | 
				
			||||||
 | 
					              show-search
 | 
				
			||||||
 | 
					              optionFilterProp="children"
 | 
				
			||||||
 | 
					              @change="changeCIType"
 | 
				
			||||||
 | 
					              v-model="form.type_id"
 | 
				
			||||||
 | 
					              placeholder="请选择模型"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <a-select-option v-for="ci_type in ci_types" :key="ci_type.id" :value="ci_type.id">{{
 | 
				
			||||||
 | 
					                ci_type.alias || ci_type.name
 | 
				
			||||||
 | 
					              }}</a-select-option>
 | 
				
			||||||
 | 
					            </a-select>
 | 
				
			||||||
 | 
					          </a-form-model-item>
 | 
				
			||||||
 | 
					          <a-form-model-item
 | 
				
			||||||
 | 
					            label="维度"
 | 
				
			||||||
 | 
					            prop="attr_ids"
 | 
				
			||||||
 | 
					            v-if="(['bar', 'line', 'pie'].includes(chartType) && form.category === 1) || chartType === 'table'"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <a-select @change="changeAttr" v-model="form.attr_ids" placeholder="请选择维度" mode="multiple" show-search>
 | 
				
			||||||
 | 
					              <a-select-option v-for="attr in commonAttributes" :key="attr.id" :value="attr.id">{{
 | 
				
			||||||
 | 
					                attr.alias || attr.name
 | 
				
			||||||
 | 
					              }}</a-select-option>
 | 
				
			||||||
 | 
					            </a-select>
 | 
				
			||||||
 | 
					          </a-form-model-item>
 | 
				
			||||||
 | 
					          <a-form-model-item
 | 
				
			||||||
 | 
					            prop="type_ids"
 | 
				
			||||||
 | 
					            label="关系模型"
 | 
				
			||||||
 | 
					            v-if="['bar', 'line', 'pie'].includes(chartType) && form.category === 2"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <a-select
 | 
				
			||||||
 | 
					              show-search
 | 
				
			||||||
 | 
					              optionFilterProp="children"
 | 
				
			||||||
 | 
					              mode="multiple"
 | 
				
			||||||
 | 
					              v-model="form.type_ids"
 | 
				
			||||||
 | 
					              placeholder="请选择模型"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <a-select-opt-group
 | 
				
			||||||
 | 
					                v-for="(key, index) in Object.keys(level2children)"
 | 
				
			||||||
 | 
					                :key="key"
 | 
				
			||||||
 | 
					                :label="`层级${index + 1}`"
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <a-select-option
 | 
				
			||||||
 | 
					                  @click="(e) => clickLevel2children(e, citype, index + 1)"
 | 
				
			||||||
 | 
					                  v-for="citype in level2children[key]"
 | 
				
			||||||
 | 
					                  :key="citype.id"
 | 
				
			||||||
 | 
					                  :value="citype.id"
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  {{ citype.alias || citype.name }}
 | 
				
			||||||
 | 
					                </a-select-option>
 | 
				
			||||||
 | 
					              </a-select-opt-group>
 | 
				
			||||||
 | 
					            </a-select>
 | 
				
			||||||
 | 
					          </a-form-model-item>
 | 
				
			||||||
 | 
					          <div class="chart-left-preview">
 | 
				
			||||||
 | 
					            <span class="chart-left-preview-operation" @click="showPreview"><a-icon type="play-circle" /> 预览</span>
 | 
				
			||||||
 | 
					            <template v-if="isShowPreview">
 | 
				
			||||||
 | 
					              <div v-if="chartType !== 'count'" class="cmdb-dashboard-grid-item-title">
 | 
				
			||||||
 | 
					                <template v-if="form.showIcon && ciType">
 | 
				
			||||||
 | 
					                  <template v-if="ciType.icon">
 | 
				
			||||||
 | 
					                    <img
 | 
				
			||||||
 | 
					                      v-if="ciType.icon.split('$$')[2]"
 | 
				
			||||||
 | 
					                      :src="`/api/common-setting/v1/file/${ciType.icon.split('$$')[3]}`"
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                    <ops-icon
 | 
				
			||||||
 | 
					                      v-else
 | 
				
			||||||
 | 
					                      :style="{
 | 
				
			||||||
 | 
					                        color: ciType.icon.split('$$')[1],
 | 
				
			||||||
 | 
					                      }"
 | 
				
			||||||
 | 
					                      :type="ciType.icon.split('$$')[0]"
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                  </template>
 | 
				
			||||||
 | 
					                  <span :style="{ color: '#2f54eb' }" v-else>{{ ciType.name[0].toUpperCase() }}</span>
 | 
				
			||||||
 | 
					                </template>
 | 
				
			||||||
 | 
					                <span :style="{ color: '#000' }"> {{ form.name }}</span>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					              <div
 | 
				
			||||||
 | 
					                class="chart-left-preview-box"
 | 
				
			||||||
 | 
					                :style="{
 | 
				
			||||||
 | 
					                  height: chartType === 'count' ? '120px' : '',
 | 
				
			||||||
 | 
					                  marginTop: chartType === 'count' ? '80px' : '',
 | 
				
			||||||
 | 
					                  background:
 | 
				
			||||||
 | 
					                    chartType === 'count'
 | 
				
			||||||
 | 
					                      ? Array.isArray(bgColor)
 | 
				
			||||||
 | 
					                        ? `linear-gradient(to bottom, ${bgColor[0]} 0%, ${bgColor[1]} 100%)`
 | 
				
			||||||
 | 
					                        : bgColor
 | 
				
			||||||
 | 
					                      : '#fafafa',
 | 
				
			||||||
 | 
					                }"
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <div :style="{ color: fontColor }">{{ form.name }}</div>
 | 
				
			||||||
 | 
					                <Chart
 | 
				
			||||||
 | 
					                  :ref="`chart_${item.id}`"
 | 
				
			||||||
 | 
					                  :chartId="item.id"
 | 
				
			||||||
 | 
					                  :data="previewData"
 | 
				
			||||||
 | 
					                  :category="form.category"
 | 
				
			||||||
 | 
					                  :options="{
 | 
				
			||||||
 | 
					                    ...item.options,
 | 
				
			||||||
 | 
					                    name: form.name,
 | 
				
			||||||
 | 
					                    fontColor: fontColor,
 | 
				
			||||||
 | 
					                    bgColor: bgColor,
 | 
				
			||||||
 | 
					                    chartType: chartType,
 | 
				
			||||||
 | 
					                    showIcon: form.showIcon,
 | 
				
			||||||
 | 
					                    barDirection: barDirection,
 | 
				
			||||||
 | 
					                    barStack: barStack,
 | 
				
			||||||
 | 
					                    chartColor: chartColor,
 | 
				
			||||||
 | 
					                    type_ids: form.type_ids,
 | 
				
			||||||
 | 
					                    attr_ids: form.attr_ids,
 | 
				
			||||||
 | 
					                    isShadow: isShadow,
 | 
				
			||||||
 | 
					                  }"
 | 
				
			||||||
 | 
					                  :editable="false"
 | 
				
			||||||
 | 
					                  :ci_types="ci_types"
 | 
				
			||||||
 | 
					                  :type_id="form.type_id || form.type_ids"
 | 
				
			||||||
 | 
					                  isPreview
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <a-form-model-item label="是否显示icon" prop="showIcon" :label-col="{ span: 5 }" :wrapper-col="{ span: 18 }">
 | 
				
			||||||
 | 
					            <a-switch v-model="form.showIcon"></a-switch>
 | 
				
			||||||
 | 
					          </a-form-model-item>
 | 
				
			||||||
 | 
					        </a-form-model>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <div class="chart-right">
 | 
				
			||||||
 | 
					        <h4>图表类型</h4>
 | 
				
			||||||
 | 
					        <div class="chart-right-type">
 | 
				
			||||||
 | 
					          <div
 | 
				
			||||||
 | 
					            :class="{ 'chart-right-type-box': true, 'chart-right-type-box-selected': chartType === t.value }"
 | 
				
			||||||
 | 
					            v-for="t in chartTypeList"
 | 
				
			||||||
 | 
					            :key="t.value"
 | 
				
			||||||
 | 
					            @click="changeChartType(t)"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <ops-icon :type="`cmdb-${t.value}`" />
 | 
				
			||||||
 | 
					            <span>{{ t.label }}</span>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <h4>数据筛选</h4>
 | 
				
			||||||
 | 
					        <FilterComp
 | 
				
			||||||
 | 
					          ref="filterComp"
 | 
				
			||||||
 | 
					          :isDropdown="false"
 | 
				
			||||||
 | 
					          :canSearchPreferenceAttrList="attributes"
 | 
				
			||||||
 | 
					          @setExpFromFilter="setExpFromFilter"
 | 
				
			||||||
 | 
					          :expression="filterExp ? `q=${filterExp}` : ''"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					        <h4>格式</h4>
 | 
				
			||||||
 | 
					        <a-form-model :colon="false" :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
 | 
				
			||||||
 | 
					          <a-form-model-item label="字体颜色" v-if="chartType === 'count'">
 | 
				
			||||||
 | 
					            <ColorPicker
 | 
				
			||||||
 | 
					              v-model="fontColor"
 | 
				
			||||||
 | 
					              :colorList="[
 | 
				
			||||||
 | 
					                '#1D2129',
 | 
				
			||||||
 | 
					                '#4E5969',
 | 
				
			||||||
 | 
					                '#103C93',
 | 
				
			||||||
 | 
					                '#86909C',
 | 
				
			||||||
 | 
					                '#ffffff',
 | 
				
			||||||
 | 
					                '#C9F2FF',
 | 
				
			||||||
 | 
					                '#FFEAC0',
 | 
				
			||||||
 | 
					                '#D6FFE6',
 | 
				
			||||||
 | 
					                '#F2DEFF',
 | 
				
			||||||
 | 
					              ]"
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </a-form-model-item>
 | 
				
			||||||
 | 
					          <a-form-model-item label="背景颜色" v-if="chartType === 'count'">
 | 
				
			||||||
 | 
					            <ColorPicker
 | 
				
			||||||
 | 
					              v-model="bgColor"
 | 
				
			||||||
 | 
					              :colorList="[
 | 
				
			||||||
 | 
					                ['#6ABFFE', '#5375EB'],
 | 
				
			||||||
 | 
					                ['#C69EFF', '#A377F9'],
 | 
				
			||||||
 | 
					                ['#85EBC9', '#4AB8D8'],
 | 
				
			||||||
 | 
					                ['#FEB58B', '#DF6463'],
 | 
				
			||||||
 | 
					                '#ffffff',
 | 
				
			||||||
 | 
					                '#FFFBF0',
 | 
				
			||||||
 | 
					                '#FFF1EC',
 | 
				
			||||||
 | 
					                '#E5FFFE',
 | 
				
			||||||
 | 
					                '#E5E7FF',
 | 
				
			||||||
 | 
					              ]"
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </a-form-model-item>
 | 
				
			||||||
 | 
					          <a-form-model-item label="图表颜色" v-else-if="chartType !== 'table'">
 | 
				
			||||||
 | 
					            <ColorListPicker v-model="chartColor" />
 | 
				
			||||||
 | 
					          </a-form-model-item>
 | 
				
			||||||
 | 
					          <a-form-model-item label="图表长度(%)">
 | 
				
			||||||
 | 
					            <a-radio-group class="chart-width" style="width:100%;" v-model="width">
 | 
				
			||||||
 | 
					              <a-radio-button :value="3">
 | 
				
			||||||
 | 
					                25
 | 
				
			||||||
 | 
					              </a-radio-button>
 | 
				
			||||||
 | 
					              <a-radio-button :value="6">
 | 
				
			||||||
 | 
					                50
 | 
				
			||||||
 | 
					              </a-radio-button>
 | 
				
			||||||
 | 
					              <a-radio-button :value="9">
 | 
				
			||||||
 | 
					                75
 | 
				
			||||||
 | 
					              </a-radio-button>
 | 
				
			||||||
 | 
					              <a-radio-button :value="12">
 | 
				
			||||||
 | 
					                100
 | 
				
			||||||
 | 
					              </a-radio-button>
 | 
				
			||||||
 | 
					            </a-radio-group>
 | 
				
			||||||
 | 
					          </a-form-model-item>
 | 
				
			||||||
 | 
					          <a-form-model-item label="柱状图类型" v-if="chartType === 'bar'">
 | 
				
			||||||
 | 
					            <a-radio-group v-model="barStack">
 | 
				
			||||||
 | 
					              <a-radio value="total">
 | 
				
			||||||
 | 
					                堆积柱状图
 | 
				
			||||||
 | 
					              </a-radio>
 | 
				
			||||||
 | 
					              <a-radio value="">
 | 
				
			||||||
 | 
					                多系列柱状图
 | 
				
			||||||
 | 
					              </a-radio>
 | 
				
			||||||
 | 
					            </a-radio-group>
 | 
				
			||||||
 | 
					          </a-form-model-item>
 | 
				
			||||||
 | 
					          <a-form-model-item label="方向" v-if="chartType === 'bar'">
 | 
				
			||||||
 | 
					            <a-radio-group v-model="barDirection">
 | 
				
			||||||
 | 
					              <a-radio value="x">
 | 
				
			||||||
 | 
					                X轴
 | 
				
			||||||
 | 
					              </a-radio>
 | 
				
			||||||
 | 
					              <a-radio value="y">
 | 
				
			||||||
 | 
					                y轴
 | 
				
			||||||
 | 
					              </a-radio>
 | 
				
			||||||
 | 
					            </a-radio-group>
 | 
				
			||||||
 | 
					          </a-form-model-item>
 | 
				
			||||||
 | 
					          <a-form-model-item label="下方阴影" v-if="chartType === 'line'">
 | 
				
			||||||
 | 
					            <a-switch v-model="isShadow" />
 | 
				
			||||||
 | 
					          </a-form-model-item>
 | 
				
			||||||
 | 
					        </a-form-model>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
  </a-modal>
 | 
					  </a-modal>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
 | 
					import Chart from './chart.vue'
 | 
				
			||||||
import { dashboardCategory } from './constant'
 | 
					import { dashboardCategory } from './constant'
 | 
				
			||||||
import { postCustomDashboard, putCustomDashboard } from '../../api/customDashboard'
 | 
					import { postCustomDashboard, putCustomDashboard, postCustomDashboardPreview } from '../../api/customDashboard'
 | 
				
			||||||
import { getCITypeAttributesById } from '../../api/CITypeAttr'
 | 
					import { getCITypeAttributesByTypeIds, getCITypeCommonAttributesByTypeIds } from '../../api/CITypeAttr'
 | 
				
			||||||
 | 
					import { getRecursive_level2children } from '../../api/CITypeRelation'
 | 
				
			||||||
import { getLastLayout } from '../../utils/helper'
 | 
					import { getLastLayout } from '../../utils/helper'
 | 
				
			||||||
import FontConfig from './fontConfig.vue'
 | 
					import FilterComp from '@/components/CMDBFilterComp'
 | 
				
			||||||
 | 
					import ColorPicker from './colorPicker.vue'
 | 
				
			||||||
 | 
					import ColorListPicker from './colorListPicker.vue'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
  name: 'ChartForm',
 | 
					  name: 'ChartForm',
 | 
				
			||||||
  components: { FontConfig },
 | 
					  components: { Chart, FilterComp, ColorPicker, ColorListPicker },
 | 
				
			||||||
  props: {
 | 
					  props: {
 | 
				
			||||||
    ci_types: {
 | 
					    ci_types: {
 | 
				
			||||||
      type: Array,
 | 
					      type: Array,
 | 
				
			||||||
@@ -67,100 +309,226 @@ export default {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  data() {
 | 
					  data() {
 | 
				
			||||||
 | 
					    const chartTypeList = [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        value: 'count',
 | 
				
			||||||
 | 
					        label: '指标',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        value: 'bar',
 | 
				
			||||||
 | 
					        label: '柱状图',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        value: 'line',
 | 
				
			||||||
 | 
					        label: '折线图',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        value: 'pie',
 | 
				
			||||||
 | 
					        label: '饼状图',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        value: 'table',
 | 
				
			||||||
 | 
					        label: '表格',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      dashboardCategory,
 | 
					      dashboardCategory,
 | 
				
			||||||
 | 
					      chartTypeList,
 | 
				
			||||||
      visible: false,
 | 
					      visible: false,
 | 
				
			||||||
      attributes: [],
 | 
					      attributes: [],
 | 
				
			||||||
      type: 'add',
 | 
					      type: 'add',
 | 
				
			||||||
      form: {
 | 
					      form: {
 | 
				
			||||||
        category: 0,
 | 
					        category: 0,
 | 
				
			||||||
 | 
					        tableCategory: 1,
 | 
				
			||||||
        name: undefined,
 | 
					        name: undefined,
 | 
				
			||||||
        type_id: undefined,
 | 
					        type_id: undefined,
 | 
				
			||||||
        attr_id: undefined,
 | 
					        type_ids: undefined,
 | 
				
			||||||
 | 
					        attr_ids: undefined,
 | 
				
			||||||
        level: undefined,
 | 
					        level: undefined,
 | 
				
			||||||
 | 
					        showIcon: false,
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      rules: {
 | 
					      rules: {
 | 
				
			||||||
        category: [{ required: true, trigger: 'change' }],
 | 
					        category: [{ required: true, trigger: 'change' }],
 | 
				
			||||||
        name: [{ required: true, message: '请输入图表名称' }],
 | 
					        name: [{ required: true, message: '请输入图表名称' }],
 | 
				
			||||||
        type_id: [{ required: true, message: '请选择模型', trigger: 'change' }],
 | 
					        type_id: [{ required: true, message: '请选择模型', trigger: 'change' }],
 | 
				
			||||||
        attr_id: [{ required: true, message: '请选择模型属性', trigger: 'change' }],
 | 
					        type_ids: [{ required: true, message: '请选择模型', trigger: 'change' }],
 | 
				
			||||||
 | 
					        attr_ids: [{ required: true, message: '请选择模型属性', trigger: 'change' }],
 | 
				
			||||||
        level: [{ required: true, message: '请输入关系层级' }],
 | 
					        level: [{ required: true, message: '请输入关系层级' }],
 | 
				
			||||||
 | 
					        showIcon: [{ required: false }],
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      item: {},
 | 
					      item: {},
 | 
				
			||||||
      chartType: 'bar',
 | 
					      chartType: 'count', // table,bar,line,pie,count
 | 
				
			||||||
 | 
					      width: 3,
 | 
				
			||||||
 | 
					      fontColor: '#ffffff',
 | 
				
			||||||
 | 
					      bgColor: ['#6ABFFE', '#5375EB'],
 | 
				
			||||||
 | 
					      chartColor: '#6592FD,#6EE3EB,#44C2FD,#5F59F7,#1A348F,#7D8FCF,#A6D1E5,#8E56DD', // 图表颜色
 | 
				
			||||||
 | 
					      isShowPreview: false,
 | 
				
			||||||
 | 
					      filterExp: undefined,
 | 
				
			||||||
 | 
					      previewData: null,
 | 
				
			||||||
 | 
					      barStack: 'total',
 | 
				
			||||||
 | 
					      barDirection: 'y',
 | 
				
			||||||
 | 
					      commonAttributes: [],
 | 
				
			||||||
 | 
					      level2children: {},
 | 
				
			||||||
 | 
					      isShadow: false,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  computed: {
 | 
				
			||||||
 | 
					    ciType() {
 | 
				
			||||||
 | 
					      if (this.form.type_id || this.form.type_ids) {
 | 
				
			||||||
 | 
					        const _find = this.ci_types.find((item) => item.id === this.form.type_id || item.id === this.form.type_ids[0])
 | 
				
			||||||
 | 
					        return _find || null
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return null
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  inject: ['layout'],
 | 
					  inject: ['layout'],
 | 
				
			||||||
  methods: {
 | 
					  methods: {
 | 
				
			||||||
    open(type, item = {}) {
 | 
					    async open(type, item = {}) {
 | 
				
			||||||
      this.visible = true
 | 
					      this.visible = true
 | 
				
			||||||
      this.type = type
 | 
					      this.type = type
 | 
				
			||||||
      this.item = item
 | 
					      this.item = item
 | 
				
			||||||
      const { category = 0, name, type_id, attr_id, level } = item
 | 
					      const { category = 0, name, type_id, attr_id, level } = item
 | 
				
			||||||
      const chartType = (item.options || {}).chartType || 'bar'
 | 
					      const chartType = (item.options || {}).chartType || 'count'
 | 
				
			||||||
 | 
					      const fontColor = (item.options || {}).fontColor || '#ffffff'
 | 
				
			||||||
 | 
					      const bgColor = (item.options || {}).bgColor || ['#6ABFFE', '#5375EB']
 | 
				
			||||||
 | 
					      const width = (item.options || {}).w
 | 
				
			||||||
 | 
					      const showIcon = (item.options || {}).showIcon
 | 
				
			||||||
 | 
					      const type_ids = item?.options?.type_ids || []
 | 
				
			||||||
 | 
					      const attr_ids = item?.options?.attr_ids || []
 | 
				
			||||||
 | 
					      const ret = item?.options?.ret || ''
 | 
				
			||||||
 | 
					      this.width = width
 | 
				
			||||||
      this.chartType = chartType
 | 
					      this.chartType = chartType
 | 
				
			||||||
      if (type_id && attr_id) {
 | 
					      this.filterExp = item?.options?.filter ?? ''
 | 
				
			||||||
        getCITypeAttributesById(type_id).then((res) => {
 | 
					      this.chartColor = item?.options?.chartColor ?? '#6592FD,#6EE3EB,#44C2FD,#5F59F7,#1A348F,#7D8FCF,#A6D1E5,#8E56DD'
 | 
				
			||||||
 | 
					      this.isShadow = item?.options?.isShadow ?? false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (chartType === 'count') {
 | 
				
			||||||
 | 
					        this.fontColor = fontColor
 | 
				
			||||||
 | 
					        this.bgColor = bgColor
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (type_ids && type_ids.length) {
 | 
				
			||||||
 | 
					        await getCITypeAttributesByTypeIds({ type_ids: type_ids.join(',') }).then((res) => {
 | 
				
			||||||
          this.attributes = res.attributes
 | 
					          this.attributes = res.attributes
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
 | 
					        if ((['bar', 'line', 'pie'].includes(chartType) && category === 1) || chartType === 'table') {
 | 
				
			||||||
 | 
					          this.barDirection = item?.options?.barDirection ?? 'y'
 | 
				
			||||||
 | 
					          this.barStack = item?.options?.barStack ?? 'total'
 | 
				
			||||||
 | 
					          await getCITypeCommonAttributesByTypeIds({
 | 
				
			||||||
 | 
					            type_ids: type_ids.join(','),
 | 
				
			||||||
 | 
					          }).then((res) => {
 | 
				
			||||||
 | 
					            this.commonAttributes = res.attributes
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      if (type_id) {
 | 
				
			||||||
 | 
					        getRecursive_level2children(type_id).then((res) => {
 | 
				
			||||||
 | 
					          this.level2children = res
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        await getCITypeCommonAttributesByTypeIds({
 | 
				
			||||||
 | 
					          type_ids: type_id,
 | 
				
			||||||
 | 
					        }).then((res) => {
 | 
				
			||||||
 | 
					          this.commonAttributes = res.attributes
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      this.$nextTick(() => {
 | 
				
			||||||
 | 
					        this.$refs.filterComp.visibleChange(true, false)
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
      const default_form = {
 | 
					      const default_form = {
 | 
				
			||||||
        category: 0,
 | 
					        category: 0,
 | 
				
			||||||
        name: undefined,
 | 
					        name: undefined,
 | 
				
			||||||
        type_id: undefined,
 | 
					        type_id: undefined,
 | 
				
			||||||
        attr_id: undefined,
 | 
					        type_ids: undefined,
 | 
				
			||||||
 | 
					        attr_ids: undefined,
 | 
				
			||||||
        level: undefined,
 | 
					        level: undefined,
 | 
				
			||||||
 | 
					        showIcon: false,
 | 
				
			||||||
 | 
					        tableCategory: 1,
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      this.form = {
 | 
					      this.form = {
 | 
				
			||||||
        ...default_form,
 | 
					        ...default_form,
 | 
				
			||||||
        category,
 | 
					        category,
 | 
				
			||||||
        name,
 | 
					        name,
 | 
				
			||||||
        type_id,
 | 
					        type_id,
 | 
				
			||||||
        attr_id,
 | 
					        type_ids,
 | 
				
			||||||
 | 
					        attr_ids,
 | 
				
			||||||
        level,
 | 
					        level,
 | 
				
			||||||
      }
 | 
					        showIcon,
 | 
				
			||||||
      if (category === 0) {
 | 
					        tableCategory: ret === 'cis' ? 2 : 1,
 | 
				
			||||||
        this.$nextTick(() => {
 | 
					 | 
				
			||||||
          this.$refs.fontConfig.setConfig((item.options || {}).fontConfig)
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    handleclose() {
 | 
					    handleclose() {
 | 
				
			||||||
      this.attributes = []
 | 
					      this.attributes = []
 | 
				
			||||||
      this.$refs.chartForm.clearValidate()
 | 
					      this.$refs.chartForm.clearValidate()
 | 
				
			||||||
 | 
					      this.isShowPreview = false
 | 
				
			||||||
      this.visible = false
 | 
					      this.visible = false
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    changeCIType(value) {
 | 
					    changeCIType(value) {
 | 
				
			||||||
      getCITypeAttributesById(value).then((res) => {
 | 
					      this.form.attr_ids = []
 | 
				
			||||||
 | 
					      this.commonAttributes = []
 | 
				
			||||||
 | 
					      getCITypeAttributesByTypeIds({ type_ids: Array.isArray(value) ? value.join(',') : value }).then((res) => {
 | 
				
			||||||
        this.attributes = res.attributes
 | 
					        this.attributes = res.attributes
 | 
				
			||||||
        this.form = {
 | 
					 | 
				
			||||||
          ...this.form,
 | 
					 | 
				
			||||||
          attr_id: undefined,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
 | 
					      if (!Array.isArray(value)) {
 | 
				
			||||||
 | 
					        getRecursive_level2children(value).then((res) => {
 | 
				
			||||||
 | 
					          this.level2children = res
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if ((['bar', 'line', 'pie'].includes(this.chartType) && this.form.category === 1) || this.chartType === 'table') {
 | 
				
			||||||
 | 
					        getCITypeCommonAttributesByTypeIds({ type_ids: Array.isArray(value) ? value.join(',') : value }).then((res) => {
 | 
				
			||||||
 | 
					          this.commonAttributes = res.attributes
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    handleok() {
 | 
					    handleok() {
 | 
				
			||||||
      this.$refs.chartForm.validate(async (valid) => {
 | 
					      this.$refs.chartForm.validate(async (valid) => {
 | 
				
			||||||
        if (valid) {
 | 
					        if (valid) {
 | 
				
			||||||
          const fontConfig = this.form.category === 0 ? this.$refs.fontConfig.getConfig() : undefined
 | 
					          const name = this.form.name
 | 
				
			||||||
          const _find = this.ci_types.find((attr) => attr.id === this.form.type_id)
 | 
					          const { chartType, fontColor, bgColor } = this
 | 
				
			||||||
          const name = this.form.name || (_find || {}).alias || (_find || {}).name
 | 
					          this.$refs.filterComp.handleSubmit()
 | 
				
			||||||
          if (this.item.id) {
 | 
					          if (this.item.id) {
 | 
				
			||||||
            await putCustomDashboard(this.item.id, {
 | 
					            const params = {
 | 
				
			||||||
              ...this.form,
 | 
					              ...this.form,
 | 
				
			||||||
              options: {
 | 
					              options: {
 | 
				
			||||||
                ...this.item.options,
 | 
					                ...this.item.options,
 | 
				
			||||||
                name,
 | 
					                name,
 | 
				
			||||||
                fontConfig,
 | 
					                w: this.width,
 | 
				
			||||||
                chartType: this.chartType,
 | 
					                chartType: this.chartType,
 | 
				
			||||||
 | 
					                showIcon: this.form.showIcon,
 | 
				
			||||||
 | 
					                type_ids: this.form.type_ids,
 | 
				
			||||||
 | 
					                filter: this.filterExp,
 | 
				
			||||||
 | 
					                isShadow: this.isShadow,
 | 
				
			||||||
              },
 | 
					              },
 | 
				
			||||||
            })
 | 
					            }
 | 
				
			||||||
 | 
					            if (chartType === 'count') {
 | 
				
			||||||
 | 
					              params.options.fontColor = fontColor
 | 
				
			||||||
 | 
					              params.options.bgColor = bgColor
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (['bar', 'line', 'pie'].includes(chartType)) {
 | 
				
			||||||
 | 
					              if (this.form.category === 1) {
 | 
				
			||||||
 | 
					                params.options.attr_ids = this.form.attr_ids
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              params.options.chartColor = this.chartColor
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (chartType === 'bar') {
 | 
				
			||||||
 | 
					              params.options.barDirection = this.barDirection
 | 
				
			||||||
 | 
					              params.options.barStack = this.barStack
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (chartType === 'table') {
 | 
				
			||||||
 | 
					              params.options.attr_ids = this.form.attr_ids
 | 
				
			||||||
 | 
					              if (this.form.tableCategory === 2) {
 | 
				
			||||||
 | 
					                params.options.ret = 'cis'
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            delete params.showIcon
 | 
				
			||||||
 | 
					            delete params.type_ids
 | 
				
			||||||
 | 
					            delete params.attr_ids
 | 
				
			||||||
 | 
					            delete params.tableCategory
 | 
				
			||||||
 | 
					            await putCustomDashboard(this.item.id, params)
 | 
				
			||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
            const { xLast, yLast, wLast } = getLastLayout(this.layout())
 | 
					            const { xLast, yLast, wLast } = getLastLayout(this.layout())
 | 
				
			||||||
            const w = 3
 | 
					            const w = this.width
 | 
				
			||||||
            const x = xLast + wLast + w > 12 ? 0 : xLast + wLast
 | 
					            const x = xLast + wLast + w > 12 ? 0 : xLast + wLast
 | 
				
			||||||
            const y = xLast + wLast + w > 12 ? yLast + 1 : yLast
 | 
					            const y = xLast + wLast + w > 12 ? yLast + 1 : yLast
 | 
				
			||||||
            await postCustomDashboard({
 | 
					            const params = {
 | 
				
			||||||
              ...this.form,
 | 
					              ...this.form,
 | 
				
			||||||
              options: {
 | 
					              options: {
 | 
				
			||||||
                x,
 | 
					                x,
 | 
				
			||||||
@@ -169,23 +537,216 @@ export default {
 | 
				
			|||||||
                h: this.form.category === 0 ? 3 : 5,
 | 
					                h: this.form.category === 0 ? 3 : 5,
 | 
				
			||||||
                name,
 | 
					                name,
 | 
				
			||||||
                chartType: this.chartType,
 | 
					                chartType: this.chartType,
 | 
				
			||||||
                fontConfig,
 | 
					                showIcon: this.form.showIcon,
 | 
				
			||||||
 | 
					                type_ids: this.form.type_ids,
 | 
				
			||||||
 | 
					                filter: this.filterExp,
 | 
				
			||||||
 | 
					                isShadow: this.isShadow,
 | 
				
			||||||
              },
 | 
					              },
 | 
				
			||||||
            })
 | 
					            }
 | 
				
			||||||
 | 
					            if (chartType === 'count') {
 | 
				
			||||||
 | 
					              params.options.fontColor = fontColor
 | 
				
			||||||
 | 
					              params.options.bgColor = bgColor
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (['bar', 'line', 'pie'].includes(chartType)) {
 | 
				
			||||||
 | 
					              if (this.form.category === 1) {
 | 
				
			||||||
 | 
					                params.options.attr_ids = this.form.attr_ids
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              params.options.chartColor = this.chartColor
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (chartType === 'bar') {
 | 
				
			||||||
 | 
					              params.options.barDirection = this.barDirection
 | 
				
			||||||
 | 
					              params.options.barStack = this.barStack
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (chartType === 'table') {
 | 
				
			||||||
 | 
					              params.options.attr_ids = this.form.attr_ids
 | 
				
			||||||
 | 
					              if (this.form.tableCategory === 2) {
 | 
				
			||||||
 | 
					                params.options.ret = 'cis'
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            delete params.showIcon
 | 
				
			||||||
 | 
					            delete params.type_ids
 | 
				
			||||||
 | 
					            delete params.attr_ids
 | 
				
			||||||
 | 
					            delete params.tableCategory
 | 
				
			||||||
 | 
					            await postCustomDashboard(params)
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          this.handleclose()
 | 
					          this.handleclose()
 | 
				
			||||||
          this.$emit('refresh')
 | 
					          this.$emit('refresh')
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    changeDashboardCategory(value) {
 | 
					    // changeDashboardCategory(value) {
 | 
				
			||||||
      this.$refs.chartForm.clearValidate()
 | 
					    //   this.$refs.chartForm.clearValidate()
 | 
				
			||||||
      if (value === 1 && this.form.type_id) {
 | 
					    //   if (value === 1 && this.form.type_id) {
 | 
				
			||||||
        this.changeCIType(this.form.type_id)
 | 
					    //     this.changeCIType(this.form.type_id)
 | 
				
			||||||
 | 
					    //   }
 | 
				
			||||||
 | 
					    // },
 | 
				
			||||||
 | 
					    changeChartType(t) {
 | 
				
			||||||
 | 
					      this.chartType = t.value
 | 
				
			||||||
 | 
					      this.isShowPreview = false
 | 
				
			||||||
 | 
					      if (t.value === 'count') {
 | 
				
			||||||
 | 
					        this.form.category = 0
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        this.form.category = 1
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      this.resetForm()
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    showPreview() {
 | 
				
			||||||
 | 
					      this.$refs.chartForm.validate(async (valid) => {
 | 
				
			||||||
 | 
					        if (valid) {
 | 
				
			||||||
 | 
					          this.isShowPreview = false
 | 
				
			||||||
 | 
					          const name = this.form.name
 | 
				
			||||||
 | 
					          const { chartType, fontColor, bgColor } = this
 | 
				
			||||||
 | 
					          this.$refs.filterComp.handleSubmit()
 | 
				
			||||||
 | 
					          const params = {
 | 
				
			||||||
 | 
					            ...this.form,
 | 
				
			||||||
 | 
					            options: {
 | 
				
			||||||
 | 
					              name,
 | 
				
			||||||
 | 
					              chartType,
 | 
				
			||||||
 | 
					              showIcon: this.form.showIcon,
 | 
				
			||||||
 | 
					              type_ids: this.form.type_ids,
 | 
				
			||||||
 | 
					              filter: this.filterExp,
 | 
				
			||||||
 | 
					              isShadow: this.isShadow,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          if (chartType === 'count') {
 | 
				
			||||||
 | 
					            params.options.fontColor = fontColor
 | 
				
			||||||
 | 
					            params.options.bgColor = bgColor
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          if (['bar', 'line', 'pie'].includes(chartType)) {
 | 
				
			||||||
 | 
					            if (this.form.category === 1) {
 | 
				
			||||||
 | 
					              params.options.attr_ids = this.form.attr_ids
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            params.options.chartColor = this.chartColor
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          if (chartType === 'bar') {
 | 
				
			||||||
 | 
					            params.options.barDirection = this.barDirection
 | 
				
			||||||
 | 
					            params.options.barStack = this.barStack
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          if (chartType === 'table') {
 | 
				
			||||||
 | 
					            params.options.attr_ids = this.form.attr_ids
 | 
				
			||||||
 | 
					            if (this.form.tableCategory === 2) {
 | 
				
			||||||
 | 
					              params.options.ret = 'cis'
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          delete params.showIcon
 | 
				
			||||||
 | 
					          delete params.type_ids
 | 
				
			||||||
 | 
					          delete params.attr_ids
 | 
				
			||||||
 | 
					          delete params.tableCategory
 | 
				
			||||||
 | 
					          postCustomDashboardPreview(params).then((res) => {
 | 
				
			||||||
 | 
					            this.isShowPreview = true
 | 
				
			||||||
 | 
					            this.previewData = res.counter
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    setExpFromFilter(filterExp) {
 | 
				
			||||||
 | 
					      if (filterExp) {
 | 
				
			||||||
 | 
					        this.filterExp = `${filterExp}`
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        this.filterExp = undefined
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    resetForm() {
 | 
				
			||||||
 | 
					      this.form.type_id = undefined
 | 
				
			||||||
 | 
					      this.form.type_ids = []
 | 
				
			||||||
 | 
					      this.form.attr_ids = []
 | 
				
			||||||
 | 
					      this.$refs.chartForm.clearValidate()
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    changeAttr(value) {
 | 
				
			||||||
 | 
					      if (value && value.length) {
 | 
				
			||||||
 | 
					        if (['line', 'pie'].includes(this.chartType)) {
 | 
				
			||||||
 | 
					          this.form.attr_ids = [value[value.length - 1]]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (['bar'].includes(this.chartType) && value.length > 2) {
 | 
				
			||||||
 | 
					          this.form.attr_ids = value.slice(value.length - 2, value.length)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (['table'].includes(this.chartType) && value.length > 3) {
 | 
				
			||||||
 | 
					          this.form.attr_ids = value.slice(value.length - 3, value.length)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    clickLevel2children(e, citype, level) {
 | 
				
			||||||
 | 
					      if (this.form.level !== level) {
 | 
				
			||||||
 | 
					        this.$nextTick(() => {
 | 
				
			||||||
 | 
					          this.form.type_ids = [citype.id]
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      this.form.level = level
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style></style>
 | 
					<style lang="less" scoped>
 | 
				
			||||||
 | 
					.chart-wrapper {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  .chart-left {
 | 
				
			||||||
 | 
					    width: 50%;
 | 
				
			||||||
 | 
					    .chart-left-preview {
 | 
				
			||||||
 | 
					      border: 1px solid #e4e7ed;
 | 
				
			||||||
 | 
					      border-radius: 2px;
 | 
				
			||||||
 | 
					      height: 280px;
 | 
				
			||||||
 | 
					      width: 92%;
 | 
				
			||||||
 | 
					      position: relative;
 | 
				
			||||||
 | 
					      padding: 12px;
 | 
				
			||||||
 | 
					      .chart-left-preview-operation {
 | 
				
			||||||
 | 
					        color: #86909c;
 | 
				
			||||||
 | 
					        position: absolute;
 | 
				
			||||||
 | 
					        top: 12px;
 | 
				
			||||||
 | 
					        right: 12px;
 | 
				
			||||||
 | 
					        cursor: pointer;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      .chart-left-preview-box {
 | 
				
			||||||
 | 
					        padding: 6px 12px;
 | 
				
			||||||
 | 
					        height: 250px;
 | 
				
			||||||
 | 
					        border-radius: 8px;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .chart-right {
 | 
				
			||||||
 | 
					    width: 50%;
 | 
				
			||||||
 | 
					    h4 {
 | 
				
			||||||
 | 
					      font-weight: 700;
 | 
				
			||||||
 | 
					      color: #000;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .chart-right-type {
 | 
				
			||||||
 | 
					      display: flex;
 | 
				
			||||||
 | 
					      justify-content: space-between;
 | 
				
			||||||
 | 
					      background-color: #f0f5ff;
 | 
				
			||||||
 | 
					      padding: 6px 12px;
 | 
				
			||||||
 | 
					      .chart-right-type-box {
 | 
				
			||||||
 | 
					        cursor: pointer;
 | 
				
			||||||
 | 
					        width: 70px;
 | 
				
			||||||
 | 
					        height: 60px;
 | 
				
			||||||
 | 
					        display: flex;
 | 
				
			||||||
 | 
					        flex-direction: column;
 | 
				
			||||||
 | 
					        align-items: center;
 | 
				
			||||||
 | 
					        justify-content: center;
 | 
				
			||||||
 | 
					        > i {
 | 
				
			||||||
 | 
					          font-size: 32px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        > span {
 | 
				
			||||||
 | 
					          font-size: 12px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      .chart-right-type-box-selected {
 | 
				
			||||||
 | 
					        background-color: #e5f1ff;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .chart-width {
 | 
				
			||||||
 | 
					      width: 100%;
 | 
				
			||||||
 | 
					      > label {
 | 
				
			||||||
 | 
					        width: 25%;
 | 
				
			||||||
 | 
					        text-align: center;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
 | 
					<style lang="less">
 | 
				
			||||||
 | 
					.chart-wrapper {
 | 
				
			||||||
 | 
					  .ant-form-item {
 | 
				
			||||||
 | 
					    margin-bottom: 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,23 +1,61 @@
 | 
				
			|||||||
export const colorList = ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc']
 | 
					export const category_1_bar_options = (data, options) => {
 | 
				
			||||||
 | 
					    // 计算一级分类
 | 
				
			||||||
export const category_1_bar_options = (data) => {
 | 
					    const xData = Object.keys(data)
 | 
				
			||||||
 | 
					    // 计算共有多少二级分类
 | 
				
			||||||
 | 
					    const secondCategory = {}
 | 
				
			||||||
 | 
					    Object.keys(data).forEach(key => {
 | 
				
			||||||
 | 
					        if (Object.prototype.toString.call(data[key]) === '[object Object]') {
 | 
				
			||||||
 | 
					            Object.keys(data[key]).forEach(key1 => {
 | 
				
			||||||
 | 
					                secondCategory[key1] = Array.from({ length: xData.length }).fill(0)
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            secondCategory['其他'] = Array.from({ length: xData.length }).fill(0)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    Object.keys(secondCategory).forEach(key => {
 | 
				
			||||||
 | 
					        xData.forEach((x, idx) => {
 | 
				
			||||||
 | 
					            if (data[x][key]) {
 | 
				
			||||||
 | 
					                secondCategory[key][idx] = data[x][key]
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (typeof data[x] === 'number') {
 | 
				
			||||||
 | 
					                secondCategory['其他'][idx] = data[x]
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
 | 
					        color: options.chartColor.split(','),
 | 
				
			||||||
        grid: {
 | 
					        grid: {
 | 
				
			||||||
            top: 15,
 | 
					            top: 15,
 | 
				
			||||||
            left: 'left',
 | 
					            left: 'left',
 | 
				
			||||||
            right: 0,
 | 
					            right: 10,
 | 
				
			||||||
            bottom: 0,
 | 
					            bottom: 20,
 | 
				
			||||||
            containLabel: true,
 | 
					            containLabel: true,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        xAxis: {
 | 
					        legend: {
 | 
				
			||||||
            type: 'category',
 | 
					            data: Object.keys(secondCategory),
 | 
				
			||||||
            data: Object.keys(data)
 | 
					            bottom: 0,
 | 
				
			||||||
 | 
					            type: 'scroll',
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        yAxis: {
 | 
					        xAxis: options.barDirection === 'y' ? {
 | 
				
			||||||
 | 
					            type: 'category',
 | 
				
			||||||
 | 
					            axisTick: { show: false },
 | 
				
			||||||
 | 
					            data: xData
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					            : {
 | 
				
			||||||
 | 
					                type: 'value',
 | 
				
			||||||
 | 
					                splitLine: {
 | 
				
			||||||
 | 
					                    show: false
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        yAxis: options.barDirection === 'y' ? {
 | 
				
			||||||
            type: 'value',
 | 
					            type: 'value',
 | 
				
			||||||
            splitLine: {
 | 
					            splitLine: {
 | 
				
			||||||
                show: false
 | 
					                show: false
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        } : {
 | 
				
			||||||
 | 
					            type: 'category',
 | 
				
			||||||
 | 
					            axisTick: { show: false },
 | 
				
			||||||
 | 
					            data: xData
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        tooltip: {
 | 
					        tooltip: {
 | 
				
			||||||
            trigger: 'axis',
 | 
					            trigger: 'axis',
 | 
				
			||||||
@@ -25,34 +63,76 @@ export const category_1_bar_options = (data) => {
 | 
				
			|||||||
                type: 'shadow'
 | 
					                type: 'shadow'
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        series: Object.keys(secondCategory).map(key => {
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                name: key,
 | 
				
			||||||
 | 
					                type: 'bar',
 | 
				
			||||||
 | 
					                stack: options?.barStack ?? 'total',
 | 
				
			||||||
 | 
					                barGap: 0,
 | 
				
			||||||
 | 
					                emphasis: {
 | 
				
			||||||
 | 
					                    focus: 'series'
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                data: secondCategory[key]
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const category_1_line_options = (data, options) => {
 | 
				
			||||||
 | 
					    const xData = Object.keys(data)
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        color: options.chartColor.split(','),
 | 
				
			||||||
 | 
					        grid: {
 | 
				
			||||||
 | 
					            top: 15,
 | 
				
			||||||
 | 
					            left: 'left',
 | 
				
			||||||
 | 
					            right: 10,
 | 
				
			||||||
 | 
					            bottom: 20,
 | 
				
			||||||
 | 
					            containLabel: true,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        tooltip: {
 | 
				
			||||||
 | 
					            trigger: 'axis'
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        xAxis: {
 | 
				
			||||||
 | 
					            type: 'category',
 | 
				
			||||||
 | 
					            data: xData
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        yAxis: {
 | 
				
			||||||
 | 
					            type: 'value'
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        series: [
 | 
					        series: [
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                data: Object.keys(data).map((key, index) => {
 | 
					                data: xData.map(item => data[item]),
 | 
				
			||||||
                    return {
 | 
					                type: 'line',
 | 
				
			||||||
                        value: data[key],
 | 
					                smooth: true,
 | 
				
			||||||
                        itemStyle: { color: colorList[0] }
 | 
					                showSymbol: false,
 | 
				
			||||||
 | 
					                areaStyle: options?.isShadow ? {
 | 
				
			||||||
 | 
					                    opacity: 0.5,
 | 
				
			||||||
 | 
					                    color: {
 | 
				
			||||||
 | 
					                        type: 'linear',
 | 
				
			||||||
 | 
					                        x: 0,
 | 
				
			||||||
 | 
					                        y: 0,
 | 
				
			||||||
 | 
					                        x2: 0,
 | 
				
			||||||
 | 
					                        y2: 1,
 | 
				
			||||||
 | 
					                        colorStops: [{
 | 
				
			||||||
 | 
					                            offset: 0, color: options.chartColor.split(',')[0] // 0% 处的颜色
 | 
				
			||||||
 | 
					                        }, {
 | 
				
			||||||
 | 
					                            offset: 1, color: '#ffffff' // 100% 处的颜色
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                        global: false // 缺省为 false
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }),
 | 
					                } : null
 | 
				
			||||||
                type: 'bar',
 | 
					 | 
				
			||||||
                label: {
 | 
					 | 
				
			||||||
                    show: true,
 | 
					 | 
				
			||||||
                    position: 'top',
 | 
					 | 
				
			||||||
                    fontSize: 10,
 | 
					 | 
				
			||||||
                    formatter(data) {
 | 
					 | 
				
			||||||
                        return `${data.value || ''}`
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const category_1_pie_options = (data) => {
 | 
					export const category_1_pie_options = (data, options) => {
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
 | 
					        color: options.chartColor.split(','),
 | 
				
			||||||
        grid: {
 | 
					        grid: {
 | 
				
			||||||
            top: 10,
 | 
					            top: 10,
 | 
				
			||||||
            left: 'left',
 | 
					            left: 'left',
 | 
				
			||||||
            right: 0,
 | 
					            right: 10,
 | 
				
			||||||
            bottom: 0,
 | 
					            bottom: 0,
 | 
				
			||||||
            containLabel: true,
 | 
					            containLabel: true,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
@@ -89,7 +169,7 @@ export const category_1_pie_options = (data) => {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const category_2_bar_options = (data) => {
 | 
					export const category_2_bar_options = (data, options, chartType) => {
 | 
				
			||||||
    const xAxisData = Object.keys(data.detail)
 | 
					    const xAxisData = Object.keys(data.detail)
 | 
				
			||||||
    const _legend = []
 | 
					    const _legend = []
 | 
				
			||||||
    xAxisData.forEach(key => {
 | 
					    xAxisData.forEach(key => {
 | 
				
			||||||
@@ -97,10 +177,11 @@ export const category_2_bar_options = (data) => {
 | 
				
			|||||||
    })
 | 
					    })
 | 
				
			||||||
    const legend = [...new Set(_legend)]
 | 
					    const legend = [...new Set(_legend)]
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
 | 
					        color: options.chartColor.split(','),
 | 
				
			||||||
        grid: {
 | 
					        grid: {
 | 
				
			||||||
            top: 15,
 | 
					            top: 15,
 | 
				
			||||||
            left: 'left',
 | 
					            left: 'left',
 | 
				
			||||||
            right: 0,
 | 
					            right: 10,
 | 
				
			||||||
            bottom: 20,
 | 
					            bottom: 20,
 | 
				
			||||||
            containLabel: true,
 | 
					            containLabel: true,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
@@ -116,41 +197,110 @@ export const category_2_bar_options = (data) => {
 | 
				
			|||||||
            type: 'scroll',
 | 
					            type: 'scroll',
 | 
				
			||||||
            data: legend
 | 
					            data: legend
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        xAxis: [
 | 
					        xAxis: options.barDirection === 'y' || chartType === 'line' ? {
 | 
				
			||||||
            {
 | 
					            type: 'category',
 | 
				
			||||||
                type: 'category',
 | 
					            axisTick: { show: false },
 | 
				
			||||||
                axisTick: { show: false },
 | 
					            data: xAxisData
 | 
				
			||||||
                data: xAxisData
 | 
					        }
 | 
				
			||||||
            }
 | 
					            : {
 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
        yAxis: [
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                type: 'value',
 | 
					                type: 'value',
 | 
				
			||||||
                splitLine: {
 | 
					                splitLine: {
 | 
				
			||||||
                    show: false
 | 
					                    show: false
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        yAxis: options.barDirection === 'y' || chartType === 'line' ? {
 | 
				
			||||||
 | 
					            type: 'value',
 | 
				
			||||||
 | 
					            splitLine: {
 | 
				
			||||||
 | 
					                show: false
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        ],
 | 
					        } : {
 | 
				
			||||||
        series: legend.map(le => {
 | 
					            type: 'category',
 | 
				
			||||||
 | 
					            axisTick: { show: false },
 | 
				
			||||||
 | 
					            data: xAxisData
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        series: legend.map((le, index) => {
 | 
				
			||||||
            return {
 | 
					            return {
 | 
				
			||||||
                name: le,
 | 
					                name: le,
 | 
				
			||||||
                type: 'bar',
 | 
					                type: chartType,
 | 
				
			||||||
                barGap: 0,
 | 
					                barGap: 0,
 | 
				
			||||||
                emphasis: {
 | 
					                emphasis: {
 | 
				
			||||||
                    focus: 'series'
 | 
					                    focus: 'series'
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
 | 
					                stack: chartType === 'line' ? '' : options?.barStack ?? 'total',
 | 
				
			||||||
                data: xAxisData.map(x => {
 | 
					                data: xAxisData.map(x => {
 | 
				
			||||||
                    return data.detail[x][le] || 0
 | 
					                    return data.detail[x][le] || 0
 | 
				
			||||||
                }),
 | 
					                }),
 | 
				
			||||||
 | 
					                smooth: true,
 | 
				
			||||||
 | 
					                showSymbol: false,
 | 
				
			||||||
                label: {
 | 
					                label: {
 | 
				
			||||||
                    show: true,
 | 
					                    show: false,
 | 
				
			||||||
                    position: 'top',
 | 
					 | 
				
			||||||
                    fontSize: 10,
 | 
					 | 
				
			||||||
                    formatter(data) {
 | 
					 | 
				
			||||||
                        return `${data.value || ''}`
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
 | 
					                areaStyle: chartType === 'line' && options?.isShadow ? {
 | 
				
			||||||
 | 
					                    opacity: 0.5,
 | 
				
			||||||
 | 
					                    color: {
 | 
				
			||||||
 | 
					                        type: 'linear',
 | 
				
			||||||
 | 
					                        x: 0,
 | 
				
			||||||
 | 
					                        y: 0,
 | 
				
			||||||
 | 
					                        x2: 0,
 | 
				
			||||||
 | 
					                        y2: 1,
 | 
				
			||||||
 | 
					                        colorStops: [{
 | 
				
			||||||
 | 
					                            offset: 0, color: options.chartColor.split(',')[index % 8] // 0% 处的颜色
 | 
				
			||||||
 | 
					                        }, {
 | 
				
			||||||
 | 
					                            offset: 1, color: '#ffffff' // 100% 处的颜色
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                        global: false // 缺省为 false
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                } : null
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const category_2_pie_options = (data, options) => {
 | 
				
			||||||
 | 
					    console.log(1111, options)
 | 
				
			||||||
 | 
					    const _legend = []
 | 
				
			||||||
 | 
					    Object.keys(data.detail).forEach(key => {
 | 
				
			||||||
 | 
					        Object.keys(data.detail[key]).forEach(key2 => {
 | 
				
			||||||
 | 
					            _legend.push({ value: data.detail[key][key2], name: `${key}-${key2}` })
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        color: options.chartColor.split(','),
 | 
				
			||||||
 | 
					        grid: {
 | 
				
			||||||
 | 
					            top: 15,
 | 
				
			||||||
 | 
					            left: 'left',
 | 
				
			||||||
 | 
					            right: 10,
 | 
				
			||||||
 | 
					            bottom: 20,
 | 
				
			||||||
 | 
					            containLabel: true,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        tooltip: {
 | 
				
			||||||
 | 
					            trigger: 'item'
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        legend: {
 | 
				
			||||||
 | 
					            orient: 'vertical',
 | 
				
			||||||
 | 
					            left: 'left',
 | 
				
			||||||
 | 
					            type: 'scroll',
 | 
				
			||||||
 | 
					            formatter: function (name) {
 | 
				
			||||||
 | 
					                const _find = _legend.find(item => item.name === name)
 | 
				
			||||||
 | 
					                return `${name}:${_find.value}`
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        series: [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                type: 'pie',
 | 
				
			||||||
 | 
					                radius: '90%',
 | 
				
			||||||
 | 
					                data: _legend,
 | 
				
			||||||
 | 
					                label: {
 | 
				
			||||||
 | 
					                    show: false,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                emphasis: {
 | 
				
			||||||
 | 
					                    itemStyle: {
 | 
				
			||||||
 | 
					                        shadowBlur: 10,
 | 
				
			||||||
 | 
					                        shadowOffsetX: 0,
 | 
				
			||||||
 | 
					                        shadowColor: 'rgba(0, 0, 0, 0.5)'
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,54 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <a-select v-model="currenColor">
 | 
				
			||||||
 | 
					    <a-select-option v-for="i in list" :value="i" :key="i">
 | 
				
			||||||
 | 
					      <div>
 | 
				
			||||||
 | 
					        <span :style="{ backgroundColor: color }" class="color-box" v-for="color in i.split(',')" :key="color"></span>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </a-select-option>
 | 
				
			||||||
 | 
					  </a-select>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					  name: 'ColorListPicker',
 | 
				
			||||||
 | 
					  model: {
 | 
				
			||||||
 | 
					    prop: 'value',
 | 
				
			||||||
 | 
					    event: 'change',
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  props: {
 | 
				
			||||||
 | 
					    value: {
 | 
				
			||||||
 | 
					      type: [String, Array],
 | 
				
			||||||
 | 
					      default: null,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  data() {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      list: [
 | 
				
			||||||
 | 
					        '#6592FD,#6EE3EB,#44C2FD,#5F59F7,#1A348F,#7D8FCF,#A6D1E5,#8E56DD',
 | 
				
			||||||
 | 
					        '#C1A9DC,#E2B5CD,#EE8EBC,#8483C3,#4D66BD,#213764,#D9B6E9,#DD88EB',
 | 
				
			||||||
 | 
					        '#6FC4DF,#9FE8CE,#16B4BE,#86E6FB,#1871A3,#E1BF8D,#ED8D8D,#DD88EB',
 | 
				
			||||||
 | 
					        '#F8B751,#FC9054,#FFE380,#DF963F,#AB5200,#EA9387,#FFBB7C,#D27467',
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  computed: {
 | 
				
			||||||
 | 
					    currenColor: {
 | 
				
			||||||
 | 
					      get() {
 | 
				
			||||||
 | 
					        return this.value
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      set(val) {
 | 
				
			||||||
 | 
					        this.$emit('change', val)
 | 
				
			||||||
 | 
					        return val
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style lang="less" scoped>
 | 
				
			||||||
 | 
					.color-box {
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  width: 40px;
 | 
				
			||||||
 | 
					  height: 10px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
@@ -0,0 +1,79 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div class="color-picker">
 | 
				
			||||||
 | 
					    <div
 | 
				
			||||||
 | 
					      :style="{
 | 
				
			||||||
 | 
					        background: Array.isArray(item) ? `linear-gradient(to bottom, ${item[0]} 0%, ${item[1]} 100%)` : item,
 | 
				
			||||||
 | 
					      }"
 | 
				
			||||||
 | 
					      :class="{ 'color-picker-box': true, 'color-picker-box-selected': isEqual(currenColor, item) }"
 | 
				
			||||||
 | 
					      v-for="item in colorList"
 | 
				
			||||||
 | 
					      :key="Array.isArray(item) ? item.join() : item"
 | 
				
			||||||
 | 
					      @click="changeColor(item)"
 | 
				
			||||||
 | 
					    ></div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					import _ from 'lodash'
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					  name: 'ColorPicker',
 | 
				
			||||||
 | 
					  model: {
 | 
				
			||||||
 | 
					    prop: 'value',
 | 
				
			||||||
 | 
					    event: 'change',
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  props: {
 | 
				
			||||||
 | 
					    value: {
 | 
				
			||||||
 | 
					      type: [String, Array],
 | 
				
			||||||
 | 
					      default: null,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    colorList: {
 | 
				
			||||||
 | 
					      type: Array,
 | 
				
			||||||
 | 
					      default: () => [],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  computed: {
 | 
				
			||||||
 | 
					    currenColor: {
 | 
				
			||||||
 | 
					      get() {
 | 
				
			||||||
 | 
					        return this.value
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      set(val) {
 | 
				
			||||||
 | 
					        this.$emit('change', val)
 | 
				
			||||||
 | 
					        return val
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  methods: {
 | 
				
			||||||
 | 
					    isEqual: _.isEqual,
 | 
				
			||||||
 | 
					    changeColor(item) {
 | 
				
			||||||
 | 
					      this.$emit('change', item)
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style lang="less" scoped>
 | 
				
			||||||
 | 
					.color-picker {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  justify-content: space-between;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  margin-top: 10px;
 | 
				
			||||||
 | 
					  .color-picker-box {
 | 
				
			||||||
 | 
					    width: 19px;
 | 
				
			||||||
 | 
					    height: 19px;
 | 
				
			||||||
 | 
					    border: 1px solid #dae2e7;
 | 
				
			||||||
 | 
					    border-radius: 1px;
 | 
				
			||||||
 | 
					    cursor: pointer;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .color-picker-box-selected {
 | 
				
			||||||
 | 
					    position: relative;
 | 
				
			||||||
 | 
					    &:after {
 | 
				
			||||||
 | 
					      content: '';
 | 
				
			||||||
 | 
					      position: absolute;
 | 
				
			||||||
 | 
					      width: 24px;
 | 
				
			||||||
 | 
					      height: 24px;
 | 
				
			||||||
 | 
					      border: 1px solid #43bbff;
 | 
				
			||||||
 | 
					      top: -3px;
 | 
				
			||||||
 | 
					      left: -3px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
@@ -1,5 +1,4 @@
 | 
				
			|||||||
export const dashboardCategory = {
 | 
					export const dashboardCategory = {
 | 
				
			||||||
    0: { label: 'CI数统计' },
 | 
					    1: { label: '默认' },
 | 
				
			||||||
    1: { label: '按属性值分类统计' },
 | 
					    2: { label: '关系' }
 | 
				
			||||||
    2: { label: '关系统计' }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,8 +11,8 @@
 | 
				
			|||||||
    <template v-if="layout && layout.length">
 | 
					    <template v-if="layout && layout.length">
 | 
				
			||||||
      <div v-if="editable">
 | 
					      <div v-if="editable">
 | 
				
			||||||
        <a-button
 | 
					        <a-button
 | 
				
			||||||
          :style="{ marginLeft: '10px' }"
 | 
					          :style="{ marginLeft: '22px', marginTop: '20px' }"
 | 
				
			||||||
          @click="openChartForm('add', {})"
 | 
					          @click="openChartForm('add', { options: { w: 3 } })"
 | 
				
			||||||
          ghost
 | 
					          ghost
 | 
				
			||||||
          type="primary"
 | 
					          type="primary"
 | 
				
			||||||
          size="small"
 | 
					          size="small"
 | 
				
			||||||
@@ -39,11 +39,44 @@
 | 
				
			|||||||
          :h="item.h"
 | 
					          :h="item.h"
 | 
				
			||||||
          :i="item.i"
 | 
					          :i="item.i"
 | 
				
			||||||
          :key="item.i"
 | 
					          :key="item.i"
 | 
				
			||||||
          :style="{ backgroundColor: '#fafafa' }"
 | 
					          :style="{
 | 
				
			||||||
 | 
					            background:
 | 
				
			||||||
 | 
					              item.options.chartType === 'count'
 | 
				
			||||||
 | 
					                ? Array.isArray(item.options.bgColor)
 | 
				
			||||||
 | 
					                  ? `linear-gradient(to bottom, ${item.options.bgColor[0]} 0%, ${item.options.bgColor[1]} 100%)`
 | 
				
			||||||
 | 
					                  : item.options.bgColor
 | 
				
			||||||
 | 
					                : '#fafafa',
 | 
				
			||||||
 | 
					          }"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <CardTitle>{{ item.options.name }}</CardTitle>
 | 
					          <div class="cmdb-dashboard-grid-item-title">
 | 
				
			||||||
 | 
					            <template v-if="item.options.chartType !== 'count' && item.options.showIcon && getCiType(item)">
 | 
				
			||||||
 | 
					              <template v-if="getCiType(item).icon">
 | 
				
			||||||
 | 
					                <img
 | 
				
			||||||
 | 
					                  v-if="getCiType(item).icon.split('$$')[2]"
 | 
				
			||||||
 | 
					                  :src="`/api/common-setting/v1/file/${getCiType(item).icon.split('$$')[3]}`"
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					                <ops-icon
 | 
				
			||||||
 | 
					                  v-else
 | 
				
			||||||
 | 
					                  :style="{
 | 
				
			||||||
 | 
					                    color: getCiType(item).icon.split('$$')[1],
 | 
				
			||||||
 | 
					                  }"
 | 
				
			||||||
 | 
					                  :type="getCiType(item).icon.split('$$')[0]"
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					              </template>
 | 
				
			||||||
 | 
					              <span :style="{ color: '#2f54eb' }" v-else>{{ getCiType(item).name[0].toUpperCase() }}</span>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					            <span :style="{ color: item.options.chartType === 'count' ? item.options.fontColor : '#000' }">{{
 | 
				
			||||||
 | 
					              item.options.name
 | 
				
			||||||
 | 
					            }}</span>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
          <a-dropdown v-if="editable">
 | 
					          <a-dropdown v-if="editable">
 | 
				
			||||||
            <a class="cmdb-dashboard-grid-item-operation"><a-icon type="menu"></a-icon></a>
 | 
					            <a
 | 
				
			||||||
 | 
					              class="cmdb-dashboard-grid-item-operation"
 | 
				
			||||||
 | 
					              :style="{
 | 
				
			||||||
 | 
					                color: item.options.chartType === 'count' ? item.options.fontColor : '',
 | 
				
			||||||
 | 
					              }"
 | 
				
			||||||
 | 
					            ><a-icon type="menu"></a-icon
 | 
				
			||||||
 | 
					            ></a>
 | 
				
			||||||
            <a-menu slot="overlay">
 | 
					            <a-menu slot="overlay">
 | 
				
			||||||
              <a-menu-item>
 | 
					              <a-menu-item>
 | 
				
			||||||
                <a @click="() => openChartForm('edit', item)"><a-icon style="margin-right:5px" type="edit" />编辑</a>
 | 
					                <a @click="() => openChartForm('edit', item)"><a-icon style="margin-right:5px" type="edit" />编辑</a>
 | 
				
			||||||
@@ -53,13 +86,13 @@
 | 
				
			|||||||
              </a-menu-item>
 | 
					              </a-menu-item>
 | 
				
			||||||
            </a-menu>
 | 
					            </a-menu>
 | 
				
			||||||
          </a-dropdown>
 | 
					          </a-dropdown>
 | 
				
			||||||
          <a
 | 
					          <!-- <a
 | 
				
			||||||
            v-if="editable && item.category === 1"
 | 
					            v-if="editable && item.category === 1"
 | 
				
			||||||
            class="cmdb-dashboard-grid-item-chart-type"
 | 
					            class="cmdb-dashboard-grid-item-chart-type"
 | 
				
			||||||
            @click="changeChartType(item)"
 | 
					            @click="changeChartType(item)"
 | 
				
			||||||
          ><a-icon
 | 
					          ><a-icon
 | 
				
			||||||
            :type="item.options.chartType === 'bar' ? 'bar-chart' : 'pie-chart'"
 | 
					            :type="item.options.chartType === 'bar' ? 'bar-chart' : 'pie-chart'"
 | 
				
			||||||
          /></a>
 | 
					          /></a> -->
 | 
				
			||||||
          <Chart
 | 
					          <Chart
 | 
				
			||||||
            :ref="`chart_${item.id}`"
 | 
					            :ref="`chart_${item.id}`"
 | 
				
			||||||
            :chartId="item.id"
 | 
					            :chartId="item.id"
 | 
				
			||||||
@@ -67,18 +100,26 @@
 | 
				
			|||||||
            :category="item.category"
 | 
					            :category="item.category"
 | 
				
			||||||
            :options="item.options"
 | 
					            :options="item.options"
 | 
				
			||||||
            :editable="editable"
 | 
					            :editable="editable"
 | 
				
			||||||
 | 
					            :ci_types="ci_types"
 | 
				
			||||||
 | 
					            :type_id="item.type_id"
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
        </GridItem>
 | 
					        </GridItem>
 | 
				
			||||||
      </GridLayout>
 | 
					      </GridLayout>
 | 
				
			||||||
    </template>
 | 
					    </template>
 | 
				
			||||||
    <div v-else class="dashboard-empty">
 | 
					    <div v-else class="dashboard-empty">
 | 
				
			||||||
      <a-empty :image="emptyImage" description=""></a-empty>
 | 
					      <a-empty :image="emptyImage" description=""></a-empty>
 | 
				
			||||||
      <a-button @click="openChartForm('add', {})" v-if="editable" size="small" type="primary" icon="plus">
 | 
					      <a-button
 | 
				
			||||||
 | 
					        @click="openChartForm('add', { options: { w: 3 } })"
 | 
				
			||||||
 | 
					        v-if="editable"
 | 
				
			||||||
 | 
					        size="small"
 | 
				
			||||||
 | 
					        type="primary"
 | 
				
			||||||
 | 
					        icon="plus"
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
        定制仪表盘
 | 
					        定制仪表盘
 | 
				
			||||||
      </a-button>
 | 
					      </a-button>
 | 
				
			||||||
      <span v-else>管理员暂未定制仪表盘</span>
 | 
					      <span v-else>管理员暂未定制仪表盘</span>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <ChartForm ref="chartForm" @refresh="refresh" :ci_types="ci_types" />
 | 
					    <ChartForm ref="chartForm" @refresh="refresh" :ci_types="ci_types" :totalData="totalData" />
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -127,12 +168,14 @@ export default {
 | 
				
			|||||||
      },
 | 
					      },
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  mounted() {
 | 
					  created() {
 | 
				
			||||||
    this.getLayout()
 | 
					 | 
				
			||||||
    getCITypes().then((res) => {
 | 
					    getCITypes().then((res) => {
 | 
				
			||||||
      this.ci_types = res.ci_types
 | 
					      this.ci_types = res.ci_types
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  mounted() {
 | 
				
			||||||
 | 
					    this.getLayout()
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  methods: {
 | 
					  methods: {
 | 
				
			||||||
    async getLayout() {
 | 
					    async getLayout() {
 | 
				
			||||||
      const res = await getCustomDashboard()
 | 
					      const res = await getCustomDashboard()
 | 
				
			||||||
@@ -196,6 +239,13 @@ export default {
 | 
				
			|||||||
        })
 | 
					        })
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    getCiType(item) {
 | 
				
			||||||
 | 
					      if (item.type_id || item.options?.type_ids) {
 | 
				
			||||||
 | 
					        const _find = this.ci_types.find((type) => type.id === item.type_id || type.id === item.options?.type_ids[0])
 | 
				
			||||||
 | 
					        return _find || null
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return null
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
@@ -206,15 +256,18 @@ export default {
 | 
				
			|||||||
  text-align: center;
 | 
					  text-align: center;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.cmdb-dashboard-grid-item {
 | 
					.cmdb-dashboard-grid-item {
 | 
				
			||||||
  border-radius: 15px;
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  padding: 6px 12px;
 | 
				
			||||||
  .cmdb-dashboard-grid-item-title {
 | 
					  .cmdb-dashboard-grid-item-title {
 | 
				
			||||||
 | 
					    overflow: hidden;
 | 
				
			||||||
 | 
					    text-overflow: ellipsis;
 | 
				
			||||||
 | 
					    white-space: nowrap;
 | 
				
			||||||
    font-weight: 700;
 | 
					    font-weight: 700;
 | 
				
			||||||
    padding-left: 6px;
 | 
					    color: #000000;
 | 
				
			||||||
    color: #000000bd;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  .cmdb-dashboard-grid-item-operation {
 | 
					  .cmdb-dashboard-grid-item-operation {
 | 
				
			||||||
    position: absolute;
 | 
					    position: absolute;
 | 
				
			||||||
    right: 6px;
 | 
					    right: 12px;
 | 
				
			||||||
    top: 6px;
 | 
					    top: 6px;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  .cmdb-dashboard-grid-item-chart-type {
 | 
					  .cmdb-dashboard-grid-item-chart-type {
 | 
				
			||||||
@@ -224,3 +277,26 @@ export default {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style lang="less">
 | 
				
			||||||
 | 
					.cmdb-dashboard-grid-item-title {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  > i {
 | 
				
			||||||
 | 
					    font-size: 16px;
 | 
				
			||||||
 | 
					    margin-right: 5px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  > img {
 | 
				
			||||||
 | 
					    width: 16px;
 | 
				
			||||||
 | 
					    margin-right: 5px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  > span:not(:last-child) {
 | 
				
			||||||
 | 
					    display: inline-block;
 | 
				
			||||||
 | 
					    width: 16px;
 | 
				
			||||||
 | 
					    height: 16px;
 | 
				
			||||||
 | 
					    font-size: 16px;
 | 
				
			||||||
 | 
					    text-align: center;
 | 
				
			||||||
 | 
					    margin-right: 5px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user