dataease-dm/frontend/src/components/canvas/custom-component/UserView.vue
2021-10-09 00:02:06 +08:00

510 lines
17 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div
v-loading="requestStatus==='waiting'"
:class="[
{
['active']: active
},
'rect-shape'
]"
>
<!-- <i v-if="requestStatus==='success'" style="right:25px;position: absolute;z-index: 2" class="icon iconfont icon-fangda" @click.stop="openChartDetailsDialog" />-->
<div v-if="requestStatus==='error'" class="chart-error-class">
<div style="font-size: 12px; color: #9ea6b2;height: 100%;display: flex;align-items: center;justify-content: center;">
{{ message }},{{ $t('chart.chart_show_error') }}
<br>
{{ $t('chart.chart_error_tips') }}
</div>
</div>
<chart-component v-if="httpRequest.status &&chart.type && !chart.type.includes('table') && !chart.type.includes('text') && renderComponent() === 'echarts'" :ref="element.propValue.id" class="chart-class" :chart="chart" :track-menu="trackMenu" @onChartClick="chartClick" />
<chart-component-g2 v-if="httpRequest.status &&chart.type && !chart.type.includes('table') && !chart.type.includes('text') && renderComponent() === 'g2'" :ref="element.propValue.id" class="chart-class" :chart="chart" :track-menu="trackMenu" @onChartClick="chartClick" />
<!-- <chart-component :ref="element.propValue.id" class="chart-class" :chart="chart" :track-menu="trackMenu" @onChartClick="chartClick" />-->
<table-normal v-if="httpRequest.status &&chart.type && chart.type.includes('table')" :ref="element.propValue.id" :show-summary="chart.type === 'table-normal'" :chart="chart" class="table-class" />
<label-normal v-if="httpRequest.status && chart.type && chart.type.includes('text')" :ref="element.propValue.id" :chart="chart" class="table-class" />
<div style="position: absolute;left: 20px;bottom:14px;">
<drill-path :drill-filters="drillFilters" @onDrillJump="drillJump" />
</div>
</div>
</template>
<script>
import { viewData } from '@/api/panel/panel'
import { viewInfo } from '@/api/link'
import ChartComponent from '@/views/chart/components/ChartComponent.vue'
import TableNormal from '@/views/chart/components/table/TableNormal'
import LabelNormal from '../../../views/chart/components/normal/LabelNormal'
import { uuid } from 'vue-uuid'
import { mapState } from 'vuex'
import { isChange } from '@/utils/conditionUtil'
import { BASE_CHART_STRING } from '@/views/chart/chart/chart'
import eventBus from '@/components/canvas/utils/eventBus'
import { deepCopy } from '@/components/canvas/utils/utils'
import { getToken, getLinkToken } from '@/utils/auth'
import DrillPath from '@/views/chart/view/DrillPath'
import { areaMapping } from '@/api/map/map'
import ChartComponentG2 from '@/views/chart/components/ChartComponentG2'
export default {
name: 'UserView',
components: { ChartComponent, TableNormal, LabelNormal, DrillPath, ChartComponentG2 },
props: {
element: {
type: Object,
default: null
},
// filters: {
// type: Array,
// required: false,
// default: null
// },
outStyle: {
type: Object,
required: false,
default: function() {
return {}
}
},
searchCount: {
type: Number,
required: false,
default: 0
},
active: {
type: Boolean,
required: false,
default: false
},
componentIndex: {
type: Number,
required: false
}
},
data() {
return {
refId: null,
chart: BASE_CHART_STRING,
requestStatus: 'waiting',
message: null,
drillClickDimensionList: [],
drillFilters: [],
drillFields: [],
places: [],
httpRequest: {
status: true,
msg: ''
},
timeMachine: null,
changeIndex: 0
}
},
computed: {
filter() {
const filter = {}
filter.filter = this.element.filters
filter.linkageFilters = this.element.linkageFilters
filter.drill = this.drillClickDimensionList
return filter
},
filters() {
// 必要 勿删勿该 watch数组哪怕发生变化 oldValue等于newValue ,深拷贝解决
if (!this.element.filters) return []
return JSON.parse(JSON.stringify(this.element.filters))
},
linkageFilters() {
// 必要 勿删勿该 watch数组哪怕发生变化 oldValue等于newValue ,深拷贝解决
if (!this.element.linkageFilters) return []
// console.log('linkageFilters:' + JSON.stringify(this.element.linkageFilters))
return JSON.parse(JSON.stringify(this.element.linkageFilters))
},
trackMenu() {
const trackMenuInfo = []
let linkageCount = 0
this.chart.data && this.chart.data.sourceFields && this.chart.data.sourceFields.forEach(item => {
const sourceInfo = this.chart.id + '#' + item.id
if (this.nowPanelTrackInfo[sourceInfo]) {
linkageCount++
}
})
linkageCount && trackMenuInfo.push('linkage')
this.drillFields.length && trackMenuInfo.push('drill')
// console.log('trackMenuInfo' + JSON.stringify(trackMenuInfo))
return trackMenuInfo
},
chartType() {
return this.chart.type
},
hw() {
return this.outStyle.width * this.outStyle.height
},
...mapState([
'canvasStyleData',
'nowPanelTrackInfo'
])
},
watch: {
'filters': function(val1, val2) {
// this.getData(this.element.propValue.viewId)
isChange(val1, val2) && this.getData(this.element.propValue.viewId)
},
linkageFilters: {
handler(newVal, oldVal) {
// isChange(newVal, oldVal) && this.getData(this.element.propValue.viewId)
if (isChange(newVal, oldVal)) {
// if (this.chart.type === 'map') {
// this.doMapLink(newVal)
// }
this.getData(this.element.propValue.viewId)
}
},
deep: true
},
// deep监听panel 如果改变 提交到 store
canvasStyleData: {
handler(newVal, oldVla) {
// this.chart.stylePriority == panel 优先使用仪表板样式
this.mergeStyle()
},
deep: true
},
// 监听外部的样式变化 (非实时性要求)
'hw': {
handler(newVal, oldVla) {
// console.log('hw:' + newVal + '---' + oldVla)
if (newVal !== oldVla && this.$refs[this.element.propValue.id]) {
if (this.chart.type === 'map') {
this.destroyTimeMachine()
this.changeIndex++
this.chartResize(this.changeIndex)
} else {
this.$refs[this.element.propValue.id].chartResize()
}
}
},
deep: true
},
// 监听外部的样式变化 (非实时性要求)
outStyle: {
handler(newVal, oldVla) {
//
// if (this.$refs[this.element.propValue.id]) {
// this.$refs[this.element.propValue.id].chartResize()
// }
},
deep: true
},
// 监听外部计时器变化
searchCount: function(val1) {
if (val1 > 0) {
this.getData(this.element.propValue.viewId)
}
},
'chartType': function(newVal, oldVal) {
if (newVal === 'map' && newVal !== oldVal) {
this.initAreas()
}
}
},
created() {
this.refId = uuid.v1
// this.filter.filter = this.$store.getters.conditions
this.getData(this.element.propValue.viewId)
// this.initAreas()
},
mounted() {
},
methods: {
mergeStyle() {
// this.chart.stylePriority == panel 优先使用仪表板样式
if ((this.requestStatus === 'success' || this.requestStatus === 'merging') && this.chart.stylePriority === 'panel' && this.canvasStyleData.chart) {
const customAttrChart = JSON.parse(this.chart.customAttr)
const customStyleChart = JSON.parse(this.chart.customStyle)
const customAttrPanel = JSON.parse(this.canvasStyleData.chart.customAttr)
const customStylePanel = JSON.parse(this.canvasStyleData.chart.customStyle)
// 组件样式-标题设置 - 标题修改为组件自己控制
// customStyleChart.text = customStylePanel.text
// 组件样式-背景设置
customStyleChart.background = customStylePanel.background
// 图形属性-颜色设置
if (this.chart.type.includes('table')) {
customAttrChart.color = customAttrPanel.tableColor
} else {
customAttrChart.color = customAttrPanel.color
}
this.chart = {
...this.chart,
customAttr: JSON.stringify(customAttrChart),
customStyle: JSON.stringify(customStyleChart)
}
}
},
getData(id) {
if (id) {
this.requestStatus = 'waiting'
this.message = null
// 增加判断 仪表板公共连接中使用viewInfo 正常使用viewData
let method = viewData
const token = this.$store.getters.token || getToken()
const linkToken = this.$store.getters.linkToken || getLinkToken()
if (!token && linkToken) {
method = viewInfo
}
method(id, this.filter).then(response => {
// 将视图传入echart组件
if (response.success) {
this.chart = response.data
this.chart.drillFields = this.chart.drillFields ? JSON.parse(this.chart.drillFields) : []
if (!response.data.drill) {
this.drillClickDimensionList.splice(this.drillClickDimensionList.length - 1, 1)
this.resetDrill()
}
this.drillFilters = JSON.parse(JSON.stringify(response.data.drillFilters))
this.drillFields = JSON.parse(JSON.stringify(response.data.drillFields))
this.requestStatus = 'merging'
this.mergeStyle()
this.requestStatus = 'success'
this.httpRequest.status = true
} else {
this.requestStatus = 'error'
this.message = response.message
}
return true
}).catch(err => {
this.httpRequest.status = err.response.data.success
this.httpRequest.msg = err.response.data.message
this.requestStatus = 'error'
if (err && err.response && err.response.data) {
this.message = err.response.data.message
} else {
this.message = err
}
return true
})
}
},
viewIdMatch(viewIds, viewId) {
return !viewIds || viewIds.length === 0 || viewIds.includes(viewId)
},
openChartDetailsDialog() {
const tableChart = deepCopy(this.chart)
tableChart.customAttr = JSON.parse(this.chart.customAttr)
tableChart.customStyle = JSON.parse(this.chart.customStyle)
tableChart.customAttr.color.tableHeaderBgColor = '#f8f8f9'
tableChart.customAttr.color.tableItemBgColor = '#ffffff'
tableChart.customAttr.color.tableFontColor = '#7c7e81'
tableChart.customAttr.color.tableStripe = true
tableChart.customStyle.text.show = false
tableChart.customAttr = JSON.stringify(tableChart.customAttr)
tableChart.customStyle = JSON.stringify(tableChart.customStyle)
eventBus.$emit('openChartDetailsDialog', { chart: this.chart, tableChart: tableChart })
},
chartClick(param) {
if (this.drillClickDimensionList.length < this.chart.drillFields.length - 1) {
this.chart.type === 'map' && this.sendToChildren(param)
this.drillClickDimensionList.push({ dimensionList: param.data.dimensionList })
this.getData(this.element.propValue.viewId)
} else if (this.chart.drillFields.length > 0) {
this.$message({
type: 'error',
message: this.$t('chart.last_layer'),
showClose: true
})
}
},
resetDrill() {
const length = this.drillClickDimensionList.length
this.drillClickDimensionList = []
if (this.chart.type === 'map') {
this.backToParent(0, length)
const current = this.$refs[this.element.propValue.id]
current && current.registerDynamicMap && current.registerDynamicMap(null)
}
},
drillJump(index) {
const length = this.drillClickDimensionList.length
this.drillClickDimensionList = this.drillClickDimensionList.slice(0, index)
if (this.chart.type === 'map') {
this.backToParent(index, length)
}
this.getData(this.element.propValue.viewId)
},
// 回到父级地图
backToParent(index, length) {
if (length <= 0) return
const times = length - 1 - index
let temp = times
let tempNode = this.currentAcreaNode
while (temp >= 0) {
tempNode = this.findEntityByCode(tempNode.pcode, this.places)
temp--
}
this.currentAcreaNode = tempNode
const current = this.$refs[this.element.propValue.id]
current && current.registerDynamicMap && current.registerDynamicMap(this.currentAcreaNode.code)
// this.$refs.dynamicChart && this.$refs.dynamicChart.registerDynamicMap && this.$refs.dynamicChart.registerDynamicMap(this.currentAcreaNode.code)
},
// 切换下一级地图
sendToChildren(param) {
const length = param.data.dimensionList.length
const name = param.data.dimensionList[length - 1].value
let aCode = null
if (this.currentAcreaNode) {
aCode = this.currentAcreaNode.code
}
// const aCode = this.currentAcreaNode ? this.currentAcreaNode.code : null
const customAttr = JSON.parse(this.chart.customAttr)
const currentNode = this.findEntityByCode(aCode || customAttr.areaCode, this.places)
if (currentNode && currentNode.children && currentNode.children.length > 0) {
const nextNode = currentNode.children.find(item => item.name === name)
// this.view.customAttr.areaCode = nextNode.code
this.currentAcreaNode = nextNode
const current = this.$refs[this.element.propValue.id]
current && current.registerDynamicMap && current.registerDynamicMap(nextNode.code)
}
},
findEntityByCode(code, array) {
if (array === null || array.length === 0) array = this.places
for (let index = 0; index < array.length; index++) {
const node = array[index]
if (node.code === code) return node
if (node.children && node.children.length > 0) {
const temp = this.findEntityByCode(code, node.children)
if (temp) return temp
}
}
},
initAreas() {
// let mapping
// if ((mapping = localStorage.getItem('areaMapping')) !== null) {
// this.places = JSON.parse(mapping)
// return
// }
Object.keys(this.places).length === 0 && areaMapping().then(res => {
this.places = res.data
// localStorage.setItem('areaMapping', JSON.stringify(res.data))
})
},
doMapLink(linkFilters) {
if (!linkFilters && linkFilters.length === 0) return
const value = linkFilters[0].value
if (!value && value.length === 0) return
const name = value[0]
if (!name) return
const areaNode = this.findEntityByname(name, [])
if (!areaNode) return
const current = this.$refs[this.element.propValue.id]
current && current.registerDynamicMap && current.registerDynamicMap(areaNode.code)
},
// 根据地名获取areaCode
findEntityByname(name, array) {
if (array === null || array.length === 0) array = this.places
for (let index = 0; index < array.length; index++) {
const node = array[index]
if (node.name === name) return node
if (node.children && node.children.length > 0) {
const temp = this.findEntityByname(name, node.children)
if (temp) return temp
}
}
},
destroyTimeMachine() {
this.timeMachine && clearTimeout(this.timeMachine)
this.timeMachine = null
},
// 边框变化
chartResize(index) {
if (this.$refs[this.element.propValue.id]) {
this.timeMachine = setTimeout(() => {
if (index === this.changeIndex) {
this.$refs[this.element.propValue.id].chartResize()
}
this.destroyTimeMachine()
}, 50)
}
},
renderComponent() {
if (this.chart.type === 'liquid') {
return 'g2'
} else {
return 'echarts'
}
}
}
}
</script>
<style lang="scss" scoped>
.rect-shape {
width: 100%;
height: 100%;
overflow: hidden;
}
.chart-class{
height: 100%;
}
.table-class{
height: 100%;
}
.chart-error-class{
text-align: center;
height: calc(100% - 84px);
display: flex;
align-items: center;
justify-content: center;
background-color: #ece7e7;
}
.active {
}
.active >>> .icon-fangda{
z-index: 2;
display:block!important;
}
.rect-shape > i{
right: 5px;
color: gray;
position: absolute;
}
.rect-shape >>> i:hover {
color: red;
}
.rect-shape:hover >>> .icon-fangda {
z-index: 2;
display:block;
}
.rect-shape>>>.icon-fangda {
display:none
}
.rect-shape:hover >>> .icon-shezhi {
z-index: 2;
display:block;
}
.rect-shape>>>.icon-shezhi {
display:none
}
</style>