问题描述
项目中通过v-for生成对应数量的容器,容器中根据条件加载对应的组件,我在加载的指标卡组件中,引入另一个tab容器组件时,发生了Unknown custom element报错,通过console,发现import后值是undefined,延迟1s打印可以获得正确结果
import tabContainer from '../tab/index.vue'
console.log('containerTab :>> ', tabContainer) // undefined
setTimeout(() => {
console.log('containerTab :>> ', tabContainer) // Object
}, 1000)
进入tabContainer文件,将其中引入的left组件删除后,可以在指标卡中正常引入
left 文件内容
<template>
<div class="grid-wrapper my-wrapper">
<grid-layout
:ref="gridLayoutName"
:line-style="{color: '#C5533A', size: '1px'}"
:layout="chartsOption"
:col-num="containerInit.colNum"
:row-height="containerInit.rowHeight"
:use-css-transforms="containerInit.useCssTransforms"
:is-draggable="!isDisDraggable"
:margin= "containerInit.margin"
>
<grid-item
v-loading="item.loading"
v-for="(item) in chartsOption"
:key="item.i"
:x="item.x"
:y="item.y || 0"
:w="item.w"
:h="item.h"
:i="item.i"
:min-h="containerInit.minH"
drag-ignore-from=".container-inner"
class="grid-item"
:class="{
active: item.selected,
[`grid-item-${item.i}`]: true,
'theme-grid-item': parseInt(item.id) === 0,
'theme-grid-item-search': parseInt(item.id) === 2,
'theme-grid-item-MetricCard': parseInt(item.id) == 0 && item.feature.chartId == '18'
}"
@click.native.stop="selectContainer(item.i)"
@resized="resizeOrMove(item.i)"
@moved="resizeOrMove(item.i)"
@mouseenter.native.stop="showTips(item.i)"
@mouseleave.native.stop="hideTips(item.i)"
>
<el-dropdown @visible-change="visibleChange" v-if="item.i == currentHoverContainerIndex && !isPreviewToggle" class="actions-btn" @click.native.stop @command="handleCommand">
<span class="iconfont icon-More"></span>
<el-dropdown-menu slot="dropdown" class="container-action-options">
<el-dropdown-item :command="'b'+item.i" v-if="item.id==0">
<span class="iconfont icon-copy"></span>
复制
</el-dropdown-item>
<el-dropdown-item :command="'a'+item.i">
<span class="iconfont icon-delect"></span>
删除
</el-dropdown-item>
<el-dropdown-item :command="'c'+item.i" v-if="item.id !== 2 && item.id !== 3">
<span class="iconfont icon-move1"></span>
移动
</el-dropdown-item>
<el-dropdown-item :command="'d'+item.i" v-if="item.id === 0">
<span class="iconfont icon-Viewdata"></span>
查看查询条件
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<div class="drag-handle" :class="{noShow: !item.nameToggle}">
<span class="tig-title-pannel theme-tig-title-pannel-underTab" v-show="item.nameToggle">
<span class="title-text theme-title-text-underTab">{{ item.name }}</span>
<span calss="title-right" v-show="hasTitleSkin"><img :src="title_right_src"></span>
<div class="newMoreData" :class="{'visualMoreData': isDisDraggable}" v-if="item.showMoreDataFlag" @click="getMoreData(item.i)">
<span class="newMoreDataLabel">更多数据</span>
<!-- <span class="newMoreDataArrow"></span> -->
<img class="newMoreDataArrow" src="/static/charts/images/newMoreData.svg">
</div>
</span>
</div>
<!--标签提示-->
<tip
:cur-chart-option="item"
:tip-style="'corner'"
:metrics-id="item.feature.metricList"
:is-tab="true"
:opacity="tipsArr[item.i]"
:class="{noTitle: !item.nameToggle}"
v-if="item.id === 0"
@handleCatQueryInfo="handleCatQueryInfo(item.i)"
@dimNumberRange="dimNumberRangeHander(item.i)"
>
</tip>
<!-- <container-inner :index="item.i">图表组件</container-inner> -->
<lazy-box :index="item.i" :key="item.i" ref="lazyBox">图表组件</lazy-box>
<border v-if="!isDisDraggable"></border>
</grid-item>
</grid-layout>
<moveContainer ref="moveContainer"></moveContainer>
<query-condition-dialog ref="queryConditionDialog"></query-condition-dialog>
<!-- <dimRangeDialog ref="dimRangeDialog" :selected-option="chartsOptionCopy"></dimRangeDialog> -->
</div>
</template>
<script>
import { GridLayout, GridItem } from '@suning/vue-grid-layout'
import { containerInit } from '../../static/configData'
import addPanel from './addPannel'
// import containerInner from './containerInner'
import lazyBox from './lazyBox'
import eventBus from '../../utils/eventBus'
import leftMixin from '../../layout/mixins/leftMixin/leftMixin'
import border from '../../layout/left/border'
import { getContainerByIndex, getGuid, isInHuiyanIframe, getHYOrigin, reportDefaultSearch } from '../../utils/utils'
import Utils from '@/components/Utils'
import api from '@/web-design/api/charts'
import bus from '../../utils/eventBus'
import moveContainer from '../../layout/moveContainer'
import queryConditionDialog from '../../layout/queryConditionDialog'
// import dimRangeDialog from '../../layout/right/focus/chartFocus/dimRangeSetting/dimRangeSettingDialog'
export default {
name: 'Left',
components: {
GridLayout,
GridItem,
addPanel,
border,
lazyBox,
moveContainer,
queryConditionDialog
// dimRangeDialog
},
mixins: [leftMixin],
props: [
'containerIndex', // 当前第几个容器
'tabIndex' // tab页面index
],
data() {
return {
containerInit,
chartsOption: [], // 必须要有本地的chartsOption,如果直接用computed里会先加载,但是dom加载在后
tipsArr: [],
currentHoverContainerIndex: -1,
showMoredataMenu: false,
lastTop: 0 // 记录移动容器上次的top
}
},
computed: {
chartsOptionCopy() {
return this.$store.state.charts.chartsOption.filter(
item => !item.hide && !item.drop && item.tabContainerIndex === this.containerIndex && item.activeTabIndex == this.tabIndex
)
},
isPreviewToggle() {
return this.$store.state.charts.previewToggle && this.$route.path !== '/visual'
},
isDisDraggable() {
return this.$route.path === '/visual' || this.$store.state.charts.previewToggle
},
isVisual() {
return this.$route.path === '/visual'
},
chartsOptionAll() {
return this.$store.state.charts.chartsOption
},
// 该layout布局在tab切中
isLayoutInTab() {
return true
},
gridLayoutName() {
return `gridLayout_${this.tabIndex}`
},
hasTitleSkin() {
// return config.title_left && config.title_right
return this.$store.state.charts.themeService
},
// title_left_src () {
// return '/static/skin/spring/image/secondTitleLeft.png'
// },
title_right_src() {
return '/static/skin/spring/image/secondTitleRight_modify.png'
},
handleContainerID() {
const handleContainerID = {}
this.chartsOptionAll.filter(item => {
return !item.drop
}).map(item => {
return item.id
}).forEach(item => {
let containerID = handleContainerID[item]
if (containerID >= 0) {
handleContainerID[item] = ++containerID
} else {
handleContainerID[item] = 1
}
})
return handleContainerID
},
systemConfig() {
return this.$store.state.charts.systemConfig
}
},
// 监听vuex上的chartsOption,实时改变本地的chartsOption
watch: {
chartsOptionCopy(value) {
this.$nextTick(() => {
this.chartsOption = value
})
}
},
mounted() {
// 等dom加载完毕后再改变本地的chartsOption
this.$nextTick(() => {
this.chartsOption = this.chartsOptionCopy
})
},
methods: {
// 跳转到更多数据页
async getMoreData(index) {
let chartsOption = getContainerByIndex(this.chartsOptionAll, index)
const selectedReport = chartsOption.selectedReport
let selectedReportVersion = chartsOption.selectedReportVersion
if (selectedReport == '' || selectedReportVersion == '') {
this.$message({
message: '未配置关联报表!',
type: 'error'
})
return
}
const selectedSystemId = chartsOption.selectedSystemId
const sourceQueryPanel = chartsOption.sourceQueryPanel
const queryPanelSelected = chartsOption.queryPanelSelected
const targetQueryPanel = chartsOption.targetQueryPanel
const customReference = chartsOption.feature.customReference
// 获取已上线的最新版本
let res = await api.getLatestOnlineVersion({ reportId: selectedReport })
// console.log(res)
if (!res) {
this.$message({
message: '更多数据打开异常!',
type: 'error'
})
return
}
if (res.statusCode == '0') {
selectedReportVersion = res.data.versionId
}
let guidstr = this.getGuidStr() // 全局唯一标识符,用来确认唯一的链接参数
let paramsObj = {
linkIndex: guidstr,
selectedReport: selectedReport,
selectedReportVersion: selectedReportVersion
}
let queryParams = {
reportId: selectedReport,
versionId: selectedReportVersion
}
if (queryPanelSelected && sourceQueryPanel && targetQueryPanel) { // 有查询面板传参
let queryInfoData = this.cloneQueryInoData(Number(sourceQueryPanel), index)
if (queryInfoData) { // 查询面板是否有参数
paramsObj.queryInfo = {
targetQurryPanel: targetQueryPanel,
value: queryInfoData
}
}
}
if (customReference && customReference.length != 0) { // 是否有自定义传参
paramsObj.customReference = customReference
}
if (paramsObj.queryInfo || paramsObj.customReference) {
queryParams.paramIndex = guidstr
this.saveDetailParams(paramsObj)
}
// 慧眼环境 or 天工环境
if (parent && isInHuiyanIframe() && !['alarm'].includes(this.$route.query.platform)) {
queryParams.other = true
let url = this.createDetailRouteUrl(queryParams, selectedSystemId)
let myJson = { type: 'openUrl', reportId: selectedReport, url: url, paramIndex: queryParams.paramIndex ? queryParams.paramIndex : '' }
let targetOrigin = getHYOrigin(window.env)
console.log('[postMessage]', `ntype: ${myJson.type}nreportId: ${myJson.reportId}nparamIndex: ${myJson.paramIndex}nurl: ${myJson.url}`)
// 发送poseMessage 给慧眼
parent.postMessage(JSON.stringify(myJson), targetOrigin)
} else {
let url = this.createDetailRouteUrl(queryParams, selectedSystemId)
// 生成的链接
window.open(url)
}
},
selectContainer(index) {
// 关闭更多指标维度弹窗
bus.$emit(`cloneDimMetric_${index}`)
let selectedContainer = this.chartsOption.filter(each => each.i === index)[0]
if (selectedContainer && selectedContainer.id === 0) {
document.getElementById('dashboard').click()
}
this.$store.commit('selectedChange', index)
},
resizeOrMove(index) {
this.$store.commit('resizeOrMove', this.chartsOption)
this.$nextTick(() => {
setTimeout(() => {
eventBus.$emit(`resizeOrMove_${index}`, index)
this.$emit('resize')
}, 200)
})
},
handleCommand(command) {
if (command[0] === 'c') { // 移动容器
this.$refs.moveContainer.showMoveContainer(command.slice(1))
return
}
if (command[0] === 'a') { // 删除容器
this.$store.commit('delContainer', command.slice(1))
}
if (command[0] === 'b') { // 复制容器
this.checkAddContainer(this.handleContainerID) &&
this.$store.commit('copyContainer', { index: command.slice(1) })
}
if (command[0] === 'd') { // 查看查询条件
this.handleCatQueryInfo(command.slice(1))
}
this.selectContainer(command.slice(1))
},
checkAddContainer(obj) {
if (!this.systemConfig.chartsNumber) return true
let currentNumber = 0
for (const key in obj) {
currentNumber += obj[key]
}
if (currentNumber >= this.systemConfig.chartsNumber) {
this.$message({ message: '已超过配置容器最大限制', type: 'warning' })
return false
}
// debugger
return true
},
/**
* 预览时的tips,当鼠标移入时显示,移出时消失
*/
showTips(index) {
if (!this.tipsArr[index] && this.$route.path === '/visual') {
this.$set(this.tipsArr, index, true)
}
if (!this.isPreviewToggle) {
this.currentHoverContainerIndex = index
}
},
visibleChange(value) {
this.showMoredataMenu = value
},
hideTips(index) {
if (this.tipsArr[index] && this.$route.path === '/visual') {
this.$set(this.tipsArr, index, false)
}
if (!this.isPreviewToggle && !this.showMoredataMenu) {
this.currentHoverContainerIndex = -1
}
},
cloneData(obj) {
let temp = null
if (obj instanceof Array) {
temp = obj.concat()
} else if (obj instanceof Function) {
// 函数是共享的是无所谓的,js也没有什么办法可以在定义后再修改函数内容
temp = obj
} else {
temp = {}
for (let item in obj) {
let val = obj[item]
temp[item] = typeof val === 'object' ? this.cloneData(val) : val // 这里也没有判断是否为函数,因为对于函数,我们将它和一般值一样处理
}
}
return temp
},
cloneQueryInoData(queryPanelId, chartId) {
if (this.$store.state.charts.chartsOption === undefined) return
let querynfoData
this.$store.state.charts.chartsOption.forEach(item => {
if (item.id.toString().trim() === '2' && item.i.toString().trim() === queryPanelId.toString().trim()) {
let featureStrObj = JSON.parse(JSON.stringify(item.feature))
querynfoData = {}
querynfoData.dataMetricData = []
// 指标
let filterMetricData = featureStrObj.dataMetricData.filter(v => !v.unRelativeCharts || (v.unRelativeCharts && !v.unRelativeCharts.includes(chartId))) // this.cloneData(item.feature.dataMetricData)
// 维度
querynfoData.dropDownData = featureStrObj.dropDownData.filter(v => !v.unRelativeCharts || (v.unRelativeCharts && !v.unRelativeCharts.includes(chartId))) // this.cloneData(item.feature.dropDownData)
// 时间
querynfoData.periodData = featureStrObj.periodData.filter(v => !v.unRelativeCharts || (v.unRelativeCharts && !v.unRelativeCharts.includes(chartId)))
// 新增可选未来时间
if (querynfoData.periodData) {
querynfoData.futureTimeEnable = featureStrObj.futureTimeEnable || false
}
// let filterMetricData = featureStrObj.dataMetricData // this.cloneData(item.feature.dataMetricData)
// querynfoData.dropDownData = featureStrObj.dropDownData // this.cloneData(item.feature.dropDownData)
// querynfoData.periodData = featureStrObj.periodData // this.cloneData(item.feature.periodData)
querynfoData.dropDownData.forEach(fropitem => {
fropitem.dimSelected = []
fropitem.dimSelected = '' // ;//删除属性
fropitem.Operator = '' // ;//删除属性
fropitem.children = '' // ;//删除属性
// fropitem.controlType = '' // ;//删除属性
fropitem.editName = '' // ;//删除属性
fropitem.father = '' // ;//删除属性
fropitem.isActive = '' // ;//删除属性
fropitem.isCommonTimeFilterDim = '' // ;//删除属性
fropitem.isTimeDim = '' // ;//删除属性
fropitem.name = '' // ;//删除属性
fropitem.type = '' // ;//删除属性
})
filterMetricData.forEach(fropitem => {
if (querynfoData.dataMetricData.filter(v => v.metricCode === fropitem.metricCode && v.selectedOper === fropitem.selectedOper).length === 0) {
querynfoData.dataMetricData.push(fropitem)
fropitem.type = '' // ;//删除属性
fropitem.Operator = '' // ;//删除属性
fropitem.editName = '' // ;//删除属性
fropitem.isActive = '' // ;//删除属性
fropitem.isMetricProperty = '' // ;//删除属性
fropitem.key = '' // ;//删除属性
fropitem.metricName = '' // ;//删除属性
fropitem.metricIndex = '' // ;//删除属性
fropitem.propertyLabel = '' // ;//删除属性
fropitem.relyMetric = '' // ;//删除属性
}
})
}
})
return querynfoData
},
saveDetailParams(data) {
if (data) {
const newParams = {
systemId: Utils.getQueryString('systemId'),
params: {},
timer: new Date(new Date().toLocaleDateString()).getTime()
}
if (window.localStorage) {
let oldParams = this.getLocalStorage('paramsToNewPage')
if (oldParams && oldParams.systemId === newParams.systemId) {
// newParams.params = oldParams.params
if (Array.isArray(oldParams.params)) {
newParams.params = {} // oldParams.params
} else {
newParams.params = oldParams.params
}
newParams.timer = oldParams.timer
}
// 处理自定义参数格式
let customReference = data.customReference || []
customReference = customReference.map(item => {
let dimValueArr = item.dimValue.split(',')
let condiName = ''
let condiValue = ''
dimValueArr.forEach(item2 => {
condiValue = (condiValue ? condiValue + ',' : condiValue) + item2.split('###')[0]
condiName = (condiName ? condiName + ',' : condiName) + item2.split('###')[1]
})
return {
condiCode: item.dimCode,
condiType: 0,
condiName: condiName,
condiValue: condiValue
}
})
newParams.params[data.linkIndex] = {
Value: customReference || [],
reportId: data.selectedReport,
versionId: data.selectedReportVersion
} // linkIndex 存储guid
if (!data.queryInfo && !customReference) return
if (data.queryInfo) {
newParams.params[data.linkIndex].queryInfo = data.queryInfo
this.setLocalStorage('paramsToNewPage', JSON.stringify(newParams))
}
this.setLocalStorage('paramsToNewPage', JSON.stringify(newParams))
}
}
},
getGuidStr() {
return getGuid()
},
getLocalStorage(key) {
var exp = 60 * 60 * 24 * 1000 // 一天的秒数
if (localStorage.getItem(key)) {
var vals = localStorage.getItem(key) // 获取本地存储的值
var dataObj = JSON.parse(vals) // 将字符串转换成JSON对象
// 如果(当前时间 - 存储的元素在创建时候设置的时间) > 过期时间
var isTimed = (new Date().getTime() - dataObj.timer) > exp
if (isTimed) {
// console.log("存储已过期")
// console.log(dataObj.timer)
localStorage.removeItem(key)
return null
} else {
var newValue = dataObj
return newValue
}
} else {
return null
}
},
setLocalStorage(key, value) {
localStorage.setItem(key, value)
},
createDetailRouteUrl(detailFilterParmas1, detailSystemid) {
let routeData1 = this.$router.resolve({
path: '/visual',
query: detailFilterParmas1
})
let searchArr = []
detailSystemid = detailSystemid === '' ? this.$store.state.design.systemId : detailSystemid
window.location.search.replace('?', '').split('&').map(item => {
item = item.toLowerCase().indexOf('systemid') >= 0 ? 'systemId=' + detailSystemid : item
searchArr.push(item)
})
let url = window.location.origin + window.location.pathname + '?' +
searchArr.join('&') + routeData1.href
return url
},
handleCatQueryInfo(commonId) {
try {
const nowCurrent = this.chartsOption.find(item => Number(item.i) === Number(commonId)) || {}
const chartId = nowCurrent.feature.chartId
const lazyBox = this.$refs['lazyBox'].find(item => Number(item.index) === Number(commonId))
const containerInner = lazyBox.$children[0]
// console.log('containerInner', containerInner)
const component = containerInner.$children[0]
// console.log('component', component)
let queryInfo = null
// 卡片、标签结构与其他不同,特殊处理
if ([2, 14].includes(chartId)) {
queryInfo = component.$refs['layout'].queryInfo
} else {
queryInfo = component.queryInfo
}
// console.log('queryInfo', queryInfo)
const { dimFilter = [], metricFilter = [] } = nowCurrent
const queryData = {
queryPanel: queryInfo,
dataRelation: {
dimFilter: [...dimFilter],
metricFilter: [...metricFilter]
}
}
// 设置报表默认不查询,清除过滤器
if (!reportDefaultSearch(window.HuiYanPermission, this.$store.state.charts.defaultSearch)) {
queryData.dataRelation.dimFilter = []
queryData.dataRelation.metricFilter = []
}
this.$refs['queryConditionDialog'].openDialog({ index: commonId, queryData })
} catch (err) {
console.log('【查看查询条件】error', err)
}
},
dimNumberRangeHander(i) {
// this.$refs['dimRangeDialog'].openDialog()
eventBus.$emit(`dimRangeDialog_${i}`)
}
}
}
</script>
有没有大佬知道是什么原因导致了我import时,没有同步返回结果, 为啥删除left组件后就可以正常返回了?