fix:修改图表问题
This commit is contained in:
parent
501742b95a
commit
70d91689eb
2
.gitignore
vendored
2
.gitignore
vendored
@ -27,3 +27,5 @@ yarn-error.log*
|
|||||||
node_modules.zip
|
node_modules.zip
|
||||||
apaas-custom-mydemo.zip
|
apaas-custom-mydemo.zip
|
||||||
apaas-custom-mydemo-1.zip
|
apaas-custom-mydemo-1.zip
|
||||||
|
eslint-report.html
|
||||||
|
fix-echarts-install.bat
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
28083
package-lock.json
generated
Normal file
28083
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -13,12 +13,13 @@
|
|||||||
"cm": "git-cz"
|
"cm": "git-cz"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@x-ui/x-dcloud-ui": "^0.2.1",
|
|
||||||
"@x-apaas/x-dcloud-page-web": "rc",
|
|
||||||
"@x-apaas/x-dcloud-page-engine": "rc",
|
|
||||||
"@x-apaas/x-apaas-frontend-i18n": "rc",
|
"@x-apaas/x-apaas-frontend-i18n": "rc",
|
||||||
|
"@x-apaas/x-dcloud-page-engine": "rc",
|
||||||
|
"@x-apaas/x-dcloud-page-web": "rc",
|
||||||
|
"@x-ui/x-dcloud-ui": "^0.2.1",
|
||||||
"core-js": "^3.6.4",
|
"core-js": "^3.6.4",
|
||||||
"dayjs": "^1.8.27",
|
"dayjs": "^1.8.27",
|
||||||
|
"echarts": "^5.6.0",
|
||||||
"element-ui": "^2.13.2",
|
"element-ui": "^2.13.2",
|
||||||
"js-file-download": "^0.4.12",
|
"js-file-download": "^0.4.12",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
@ -55,6 +56,7 @@
|
|||||||
"cz-conventional-changelog": "^3.2.0",
|
"cz-conventional-changelog": "^3.2.0",
|
||||||
"cz-customizable": "^6.2.0",
|
"cz-customizable": "^6.2.0",
|
||||||
"eslint": "^6.7.2",
|
"eslint": "^6.7.2",
|
||||||
|
"eslint-html-reporter": "^0.7.4",
|
||||||
"eslint-plugin-prettier": "^3.1.1",
|
"eslint-plugin-prettier": "^3.1.1",
|
||||||
"eslint-plugin-vue": "^6.2.2",
|
"eslint-plugin-vue": "^6.2.2",
|
||||||
"husky": "^4.2.5",
|
"husky": "^4.2.5",
|
||||||
|
|||||||
@ -147,5 +147,5 @@ export default {
|
|||||||
url: '/xdap-app/form/query/formComponent',
|
url: '/xdap-app/form/query/formComponent',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
disableSuccessMsg: true
|
disableSuccessMsg: true
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ export default {
|
|||||||
url: '/custom/permission/updateRole?userID=',
|
url: '/custom/permission/updateRole?userID=',
|
||||||
method: 'post'
|
method: 'post'
|
||||||
},
|
},
|
||||||
//获取引擎列表
|
// 获取引擎列表
|
||||||
GET_ENGINE_LIST_SELF: {
|
GET_ENGINE_LIST_SELF: {
|
||||||
url: '/custom/dataEntryEngineModel/selectByPage',
|
url: '/custom/dataEntryEngineModel/selectByPage',
|
||||||
method: 'post'
|
method: 'post'
|
||||||
@ -16,17 +16,17 @@ export default {
|
|||||||
url: '/custom/dataEntryEngineModel/excelExport',
|
url: '/custom/dataEntryEngineModel/excelExport',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
},
|
},
|
||||||
//添加引擎
|
// 添加引擎
|
||||||
ADD_ENGINE_MODEL: {
|
ADD_ENGINE_MODEL: {
|
||||||
url: '/custom/dataEntryEngineModel/insert',
|
url: '/custom/dataEntryEngineModel/insert',
|
||||||
method: 'post'
|
method: 'post'
|
||||||
},
|
},
|
||||||
//导入引擎
|
// 导入引擎
|
||||||
IMPORT_ENGINE_MODEL: {
|
IMPORT_ENGINE_MODEL: {
|
||||||
url: '/custom/dataEntryEngineModel/import',
|
url: '/custom/dataEntryEngineModel/import',
|
||||||
method: 'post'
|
method: 'post'
|
||||||
},
|
},
|
||||||
//获取参数列表
|
// 获取参数列表
|
||||||
GET_PARAM_LIST: {
|
GET_PARAM_LIST: {
|
||||||
url: '/custom/engineParamDetailPojo/selectParamList',
|
url: '/custom/engineParamDetailPojo/selectParamList',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
@ -35,7 +35,7 @@ export default {
|
|||||||
url: '/custom/dataEntryEngineModel/excelImport',
|
url: '/custom/dataEntryEngineModel/excelImport',
|
||||||
method: 'post'
|
method: 'post'
|
||||||
},
|
},
|
||||||
//获取引擎详情
|
// 获取引擎详情
|
||||||
GET_ENGINE_DETAIL: {
|
GET_ENGINE_DETAIL: {
|
||||||
url: '/custom/engineParamDetailPojo/selectValueByMoreParam',
|
url: '/custom/engineParamDetailPojo/selectValueByMoreParam',
|
||||||
method: 'post'
|
method: 'post'
|
||||||
|
|||||||
@ -1,31 +1,31 @@
|
|||||||
export default {
|
export default {
|
||||||
//权限管理相关接口
|
// 权限管理相关接口
|
||||||
//获取权限管理列表
|
// 获取权限管理列表
|
||||||
GET_PERMISSION_DATA: {
|
GET_PERMISSION_DATA: {
|
||||||
url: '/custom/permission/getUserRoleAndPermission',
|
url: '/custom/permission/getUserRoleAndPermission',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
},
|
},
|
||||||
//保存权限管理
|
// 保存权限管理
|
||||||
SAVE_PERMISSION_DATA: {
|
SAVE_PERMISSION_DATA: {
|
||||||
url: '/custom/permission/insertRole',
|
url: '/custom/permission/insertRole',
|
||||||
method: 'post'
|
method: 'post'
|
||||||
},
|
},
|
||||||
//修改权限管理
|
// 修改权限管理
|
||||||
EDIT_PERMISSION_DATA: {
|
EDIT_PERMISSION_DATA: {
|
||||||
url: '/custom/permission/updatePermission',
|
url: '/custom/permission/updatePermission',
|
||||||
method: 'post'
|
method: 'post'
|
||||||
},
|
},
|
||||||
//删除权限管理
|
// 删除权限管理
|
||||||
DELETE_PERMISSION_DATA: {
|
DELETE_PERMISSION_DATA: {
|
||||||
url: '/custom/permission/deletePermission',
|
url: '/custom/permission/deletePermission',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
},
|
},
|
||||||
//获取所有权限表
|
// 获取所有权限表
|
||||||
GET_ALL_PERMISSION_LIST: {
|
GET_ALL_PERMISSION_LIST: {
|
||||||
url: '/custom/permission/getAllPermission',
|
url: '/custom/permission/getAllPermission',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
},
|
},
|
||||||
DELETE_PERMISSION_DATA: {
|
DELETE_ROLE_DATA: {
|
||||||
url: '/custom/permission/deleteRole',
|
url: '/custom/permission/deleteRole',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
},
|
},
|
||||||
|
|||||||
@ -243,6 +243,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 图表区域列表 -->
|
<!-- 图表区域列表 -->
|
||||||
|
<div v-if="chartList.length == 0" class="chart-area empty-chart-area">
|
||||||
|
|
||||||
|
</div>
|
||||||
<div v-for="(chart, index) in chartList" :key="chart.id" class="chart-area">
|
<div v-for="(chart, index) in chartList" :key="chart.id" class="chart-area">
|
||||||
<div class="chart-header">
|
<div class="chart-header">
|
||||||
<div class="chart-title-section">
|
<div class="chart-title-section">
|
||||||
@ -299,6 +302,7 @@
|
|||||||
<div class="config-item canshu">
|
<div class="config-item canshu">
|
||||||
<span class="config-label">Y轴(参数):</span>
|
<span class="config-label">Y轴(参数):</span>
|
||||||
<el-select
|
<el-select
|
||||||
|
:key="`y-axis-param-${chart.id}`"
|
||||||
v-model="chart.yAxisParam"
|
v-model="chart.yAxisParam"
|
||||||
filterable
|
filterable
|
||||||
multiple
|
multiple
|
||||||
@ -620,7 +624,52 @@ export default {
|
|||||||
this.formulaFormData.operator &&
|
this.formulaFormData.operator &&
|
||||||
this.formulaFormData.param1 !== this.formulaFormData.param2
|
this.formulaFormData.param1 !== this.formulaFormData.param2
|
||||||
)
|
)
|
||||||
},
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
activeTab: {
|
||||||
|
immediate: true,
|
||||||
|
handler(newVal, oldVal) {
|
||||||
|
if (newVal === 'statistics') {
|
||||||
|
window.addEventListener('resize', this.handleResize)
|
||||||
|
// 加载Y轴参数选项
|
||||||
|
this.loadYAxisParams()
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
// 延迟一点,确保 DOM 完全渲染
|
||||||
|
setTimeout(() => {
|
||||||
|
this.chartList.forEach((chart, index) => {
|
||||||
|
if (!chart.chartInstance) {
|
||||||
|
// 如果有待初始化标记,清除它
|
||||||
|
if (chart._pendingInit) {
|
||||||
|
delete chart._pendingInit
|
||||||
|
delete chart._pendingInitIndex
|
||||||
|
}
|
||||||
|
this.initChart(index)
|
||||||
|
} else {
|
||||||
|
chart.chartInstance.resize()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 100)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else if (oldVal === 'statistics') {
|
||||||
|
window.removeEventListener('resize', this.handleResize)
|
||||||
|
this.cleanupResizeListeners()
|
||||||
|
this.disposeAllCharts()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
window.removeEventListener('resize', this.handleResize)
|
||||||
|
this.cleanupResizeListeners()
|
||||||
|
this.disposeAllCharts()
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// this.handleSearch()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
// 穿梭框过滤方法
|
// 穿梭框过滤方法
|
||||||
filterTransferMethod(query, item) {
|
filterTransferMethod(query, item) {
|
||||||
// 确保 query 是字符串类型
|
// 确保 query 是字符串类型
|
||||||
@ -655,42 +704,7 @@ export default {
|
|||||||
series.includes(searchText) ||
|
series.includes(searchText) ||
|
||||||
label.includes(searchText)
|
label.includes(searchText)
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
activeTab: {
|
|
||||||
immediate: true,
|
|
||||||
handler(newVal, oldVal) {
|
|
||||||
if (newVal === 'statistics') {
|
|
||||||
window.addEventListener('resize', this.handleResize)
|
|
||||||
// 加载Y轴参数选项
|
|
||||||
this.loadYAxisParams()
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.chartList.forEach((chart, index) => {
|
|
||||||
if (!chart.chartInstance) {
|
|
||||||
this.initChart(index)
|
|
||||||
} else {
|
|
||||||
chart.chartInstance.resize()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
} else if (oldVal === 'statistics') {
|
|
||||||
window.removeEventListener('resize', this.handleResize)
|
|
||||||
this.cleanupResizeListeners()
|
|
||||||
this.disposeAllCharts()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
beforeDestroy() {
|
|
||||||
window.removeEventListener('resize', this.handleResize)
|
|
||||||
this.cleanupResizeListeners()
|
|
||||||
this.disposeAllCharts()
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
// this.handleSearch()
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
// 加载Y轴参数选项(首次进入页面时调用)
|
// 加载Y轴参数选项(首次进入页面时调用)
|
||||||
loadYAxisParams() {
|
loadYAxisParams() {
|
||||||
// 如果已经加载过,不再重复调用
|
// 如果已经加载过,不再重复调用
|
||||||
@ -768,16 +782,29 @@ export default {
|
|||||||
newSelectedModels: [] // 新选择的机型,用于标记需要查询的机型
|
newSelectedModels: [] // 新选择的机型,用于标记需要查询的机型
|
||||||
}
|
}
|
||||||
// 新增的图表展示在第一个
|
// 新增的图表展示在第一个
|
||||||
this.chartList.unshift(newChart)
|
// 确保响应式更新:先创建新数组,再赋值(特别是在执行过查询后可能影响响应式)
|
||||||
|
const newChartList = [newChart, ...this.chartList]
|
||||||
|
this.chartList = newChartList
|
||||||
|
// 强制更新视图,确保 DOM 完全更新(特别是在执行过查询后)
|
||||||
|
this.$forceUpdate()
|
||||||
|
// 使用多重 nextTick 和 requestAnimationFrame 确保 DOM 完全渲染(特别是从空列表添加第一个图表时)
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
// 优先初始化新加的图表
|
|
||||||
this.initChart(0)
|
|
||||||
// 如果存在其他未初始化的图表,补充初始化一次,避免索引变动导致未挂载
|
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.chartList.forEach((chart, idx) => {
|
// 使用 requestAnimationFrame 确保在下一帧渲染后再初始化
|
||||||
if (!chart.chartInstance) {
|
requestAnimationFrame(() => {
|
||||||
this.initChart(idx)
|
requestAnimationFrame(() => {
|
||||||
}
|
// 再延迟一点,确保容器已经渲染并有尺寸
|
||||||
|
setTimeout(() => {
|
||||||
|
// 优先初始化新加的图表
|
||||||
|
this.initChart(0)
|
||||||
|
// 如果存在其他未初始化的图表,补充初始化一次,避免索引变动导致未挂载
|
||||||
|
this.chartList.forEach((chart, idx) => {
|
||||||
|
if (idx !== 0 && chart && !chart.chartInstance) {
|
||||||
|
this.initChart(idx)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 300) // 增加延迟时间,确保 DOM 完全渲染
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -803,24 +830,62 @@ export default {
|
|||||||
},
|
},
|
||||||
handleDeleteChart(index) {
|
handleDeleteChart(index) {
|
||||||
const chart = this.chartList[index]
|
const chart = this.chartList[index]
|
||||||
if (chart?.chartInstance) {
|
if (!chart) return
|
||||||
chart.chartInstance.dispose()
|
|
||||||
|
// 先清理图表实例
|
||||||
|
if (chart.chartInstance) {
|
||||||
|
try {
|
||||||
|
chart.chartInstance.dispose()
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('销毁图表实例时出错:', e)
|
||||||
|
}
|
||||||
chart.chartInstance = null
|
chart.chartInstance = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 清理图表相关的数据
|
||||||
|
chart.selectedModels = []
|
||||||
|
chart.chartDataList = []
|
||||||
|
chart.cachedModelData = {}
|
||||||
|
chart.newSelectedModels = []
|
||||||
|
|
||||||
|
// 删除图表
|
||||||
this.chartList.splice(index, 1)
|
this.chartList.splice(index, 1)
|
||||||
// 删除后重新检查剩余图表的初始化状态
|
|
||||||
|
// 删除后强制更新视图,确保所有组件都被正确清理
|
||||||
|
// 特别是删除最后一个图表后,需要确保视图完全更新
|
||||||
|
this.$forceUpdate()
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.chartList.forEach((c, idx) => {
|
this.$forceUpdate()
|
||||||
if (c && !c.chartInstance) {
|
|
||||||
this.initChart(idx)
|
// 删除后重新检查剩余图表的初始化状态
|
||||||
}
|
// 使用双重 nextTick 确保 DOM 完全更新
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.chartList.forEach((c, idx) => {
|
||||||
|
if (c && !c.chartInstance) {
|
||||||
|
// 确保容器引用正确
|
||||||
|
const refName = `chartContainer-${idx}`
|
||||||
|
const containerRef = this.$refs[refName]
|
||||||
|
if (containerRef) {
|
||||||
|
this.initChart(idx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
handleClearAllCharts() {
|
handleClearAllCharts() {
|
||||||
this.disposeAllCharts()
|
this.disposeAllCharts()
|
||||||
this.chartList = []
|
// 清空列表 - 使用 splice 确保响应式更新
|
||||||
|
this.chartList.splice(0, this.chartList.length)
|
||||||
this.floatingPanelExpanded = false // 清空后重置悬浮框状态
|
this.floatingPanelExpanded = false // 清空后重置悬浮框状态
|
||||||
|
// 强制更新视图,确保所有组件都被正确清理
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$forceUpdate()
|
||||||
|
// 再次确保视图更新
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$forceUpdate()
|
||||||
|
})
|
||||||
|
})
|
||||||
},
|
},
|
||||||
// 头部筛选下拉框的过滤方法 - 产品型号
|
// 头部筛选下拉框的过滤方法 - 产品型号
|
||||||
filterModelNameOptions(query) {
|
filterModelNameOptions(query) {
|
||||||
@ -914,18 +979,19 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
// Y轴参数选择下拉框的过滤方法
|
// Y轴参数选择下拉框的过滤方法
|
||||||
// Y轴参数选择下拉框的过滤方法
|
|
||||||
handleFilterYAxisParam(query) {
|
handleFilterYAxisParam(query) {
|
||||||
if (!query || query.trim() === '') {
|
// 确保 query 是字符串类型
|
||||||
|
if (!query || typeof query !== 'string' || query.trim() === '') {
|
||||||
// 如果查询为空,显示所有选项
|
// 如果查询为空,显示所有选项
|
||||||
this.filteredYAxisParamOptions = this.yAxisParamOptions
|
this.filteredYAxisParamOptions = this.yAxisParamOptions || []
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 将查询字符串转为小写进行不区分大小写的模糊匹配
|
// 将查询字符串转为小写进行不区分大小写的模糊匹配
|
||||||
const queryLower = query.toLowerCase().trim()
|
const queryLower = query.toLowerCase().trim()
|
||||||
this.filteredYAxisParamOptions = this.yAxisParamOptions.filter((option) => {
|
const options = this.yAxisParamOptions || []
|
||||||
|
this.filteredYAxisParamOptions = options.filter((option) => {
|
||||||
// 在 label 中查找是否包含查询字符串
|
// 在 label 中查找是否包含查询字符串
|
||||||
return option.label && option.label.toLowerCase().includes(queryLower)
|
return option && option.label && option.label.toLowerCase().includes(queryLower)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
// 根据机型列表构建头部筛选下拉选项(仅首次调用)
|
// 根据机型列表构建头部筛选下拉选项(仅首次调用)
|
||||||
@ -1096,12 +1162,310 @@ export default {
|
|||||||
if (!chart.chartHeight) {
|
if (!chart.chartHeight) {
|
||||||
chart.chartHeight = 400
|
chart.chartHeight = 400
|
||||||
}
|
}
|
||||||
|
|
||||||
const refName = `chartContainer-${index}`
|
const refName = `chartContainer-${index}`
|
||||||
const containerRef = this.$refs[refName]
|
const getContainer = () => {
|
||||||
if (!containerRef || (Array.isArray(containerRef) && !containerRef[0])) return
|
// 优先使用 $refs
|
||||||
const container = Array.isArray(containerRef) ? containerRef[0] : containerRef
|
const containerRef = this.$refs[refName]
|
||||||
chart.chartInstance = echarts.init(container)
|
if (containerRef) {
|
||||||
this.updateChart(index)
|
return Array.isArray(containerRef) ? containerRef[0] : containerRef
|
||||||
|
}
|
||||||
|
// 如果 $refs 获取不到,尝试使用 querySelector 作为备选方案
|
||||||
|
const chartAreas = document.querySelectorAll('.chart-area')
|
||||||
|
if (chartAreas && chartAreas[index]) {
|
||||||
|
const container = chartAreas[index].querySelector('.chart-container')
|
||||||
|
if (container) {
|
||||||
|
return container
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用递归重试机制,确保容器存在且有尺寸
|
||||||
|
const tryInitChart = (retryCount = 0, maxRetries = 30) => {
|
||||||
|
const container = getContainer()
|
||||||
|
|
||||||
|
if (!container) {
|
||||||
|
if (retryCount >= maxRetries) {
|
||||||
|
console.warn(`初始化图表失败,已重试 ${maxRetries} 次,无法找到容器,索引: ${index}`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 容器不存在,延迟后重试
|
||||||
|
setTimeout(() => {
|
||||||
|
tryInitChart(retryCount + 1, maxRetries)
|
||||||
|
}, 150)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查容器是否可见
|
||||||
|
const style = window.getComputedStyle(container)
|
||||||
|
const isVisible = style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0'
|
||||||
|
|
||||||
|
// 使用多种方式检查容器尺寸(更可靠)
|
||||||
|
const rect = container.getBoundingClientRect()
|
||||||
|
const hasSize = (container.offsetWidth > 0 && container.offsetHeight > 0) ||
|
||||||
|
(rect.width > 0 && rect.height > 0) ||
|
||||||
|
(container.clientWidth > 0 && container.clientHeight > 0)
|
||||||
|
|
||||||
|
// 如果容器不可见,需要等待
|
||||||
|
if (!isVisible) {
|
||||||
|
if (retryCount >= maxRetries) {
|
||||||
|
console.warn(`容器不可见,无法初始化图表,索引: ${index}`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
tryInitChart(retryCount + 1, maxRetries)
|
||||||
|
}, 150)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasSize) {
|
||||||
|
// 检查父元素是否有尺寸
|
||||||
|
const parent = container.parentElement
|
||||||
|
const parentHasSize = parent && (parent.offsetWidth > 0 || parent.clientWidth > 0)
|
||||||
|
|
||||||
|
// 如果父元素有尺寸但容器没有,可能是样式还没应用,尝试强制触发重排
|
||||||
|
if (parentHasSize && retryCount < maxRetries - 3) {
|
||||||
|
// 强制触发重排
|
||||||
|
void container.offsetHeight
|
||||||
|
// 延迟后重试
|
||||||
|
setTimeout(() => {
|
||||||
|
tryInitChart(retryCount + 1, maxRetries)
|
||||||
|
}, 150)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在最后几次重试时,使用 ResizeObserver 监听尺寸变化
|
||||||
|
if (retryCount >= maxRetries - 5 && typeof ResizeObserver !== 'undefined' && !container._resizeObserver) {
|
||||||
|
container._resizeObserver = new ResizeObserver((entries) => {
|
||||||
|
for (const entry of entries) {
|
||||||
|
const target = entry.target
|
||||||
|
const targetRect = target.getBoundingClientRect()
|
||||||
|
const targetHasSize = (target.offsetWidth > 0 && target.offsetHeight > 0) ||
|
||||||
|
(targetRect.width > 0 && targetRect.height > 0)
|
||||||
|
|
||||||
|
if (targetHasSize && !chart.chartInstance) {
|
||||||
|
// 容器有尺寸了,初始化图表
|
||||||
|
this.initChartWithContainer(index, target)
|
||||||
|
// 清理观察者
|
||||||
|
if (target._resizeObserver) {
|
||||||
|
target._resizeObserver.disconnect()
|
||||||
|
delete target._resizeObserver
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
container._resizeObserver.observe(container)
|
||||||
|
|
||||||
|
// 设置超时,如果3秒后还没有尺寸,就尝试强制初始化
|
||||||
|
setTimeout(() => {
|
||||||
|
if (container._resizeObserver) {
|
||||||
|
container._resizeObserver.disconnect()
|
||||||
|
delete container._resizeObserver
|
||||||
|
}
|
||||||
|
if (!chart.chartInstance) {
|
||||||
|
// 最后尝试:即使没有尺寸也初始化,并监听 resize 事件
|
||||||
|
this.initChartWithResizeObserver(index, container, chart)
|
||||||
|
}
|
||||||
|
}, 3000)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retryCount >= maxRetries) {
|
||||||
|
// 最后尝试:即使没有尺寸也初始化
|
||||||
|
this.initChartWithResizeObserver(index, container, chart)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 容器没有尺寸,延迟后重试
|
||||||
|
setTimeout(() => {
|
||||||
|
tryInitChart(retryCount + 1, maxRetries)
|
||||||
|
}, 150)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 容器存在且有尺寸,可以初始化
|
||||||
|
this.initChartWithContainer(index, container)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 先尝试立即初始化
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
tryInitChart(0, 30) // 最多重试30次,每次150ms,总共最多4.5秒
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 使用容器初始化图表的内部方法
|
||||||
|
initChartWithContainer(index, container) {
|
||||||
|
const chart = this.chartList[index]
|
||||||
|
if (!chart || !container) return
|
||||||
|
|
||||||
|
// 使用多种方式检查容器是否有尺寸(更可靠)
|
||||||
|
const rect = container.getBoundingClientRect()
|
||||||
|
const hasSize = (container.offsetWidth > 0 && container.offsetHeight > 0) ||
|
||||||
|
(rect.width > 0 && rect.height > 0) ||
|
||||||
|
(container.clientWidth > 0 && container.clientHeight > 0)
|
||||||
|
|
||||||
|
// 再次确认容器有尺寸(双重保险)
|
||||||
|
if (!hasSize) {
|
||||||
|
// 容器没有尺寸,使用 ResizeObserver 监听
|
||||||
|
this.initChartWithResizeObserver(index, container, chart)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果已经有实例,先销毁
|
||||||
|
if (chart.chartInstance) {
|
||||||
|
try {
|
||||||
|
chart.chartInstance.dispose()
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('销毁图表实例时出错:', e)
|
||||||
|
}
|
||||||
|
chart.chartInstance = null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化图表实例(确保容器有尺寸)
|
||||||
|
try {
|
||||||
|
chart.chartInstance = echarts.init(container)
|
||||||
|
this.updateChart(index)
|
||||||
|
} catch (e) {
|
||||||
|
console.error('初始化图表失败:', e)
|
||||||
|
// 如果初始化失败,可能是容器尺寸问题,尝试使用 ResizeObserver
|
||||||
|
if (e.message && e.message.includes('width or height')) {
|
||||||
|
this.initChartWithResizeObserver(index, container, chart)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 当容器没有尺寸时,使用 ResizeObserver 监听并初始化
|
||||||
|
initChartWithResizeObserver(index, container, chart) {
|
||||||
|
if (!container || !chart) return
|
||||||
|
|
||||||
|
// 检查容器是否在可见的tab中
|
||||||
|
const isStatisticsTab = this.activeTab === 'statistics'
|
||||||
|
if (!isStatisticsTab) {
|
||||||
|
// 不在统计tab中,标记为待初始化,等待tab切换
|
||||||
|
chart._pendingInit = true
|
||||||
|
chart._pendingInitIndex = index
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查容器及其父元素是否可见
|
||||||
|
const style = window.getComputedStyle(container)
|
||||||
|
const isVisible = style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0'
|
||||||
|
|
||||||
|
// 检查父元素
|
||||||
|
let parent = container.parentElement
|
||||||
|
let parentVisible = true
|
||||||
|
while (parent && parent !== document.body) {
|
||||||
|
const parentStyle = window.getComputedStyle(parent)
|
||||||
|
if (parentStyle.display === 'none' || parentStyle.visibility === 'hidden') {
|
||||||
|
parentVisible = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
parent = parent.parentElement
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isVisible || !parentVisible) {
|
||||||
|
// 容器不可见,标记为待初始化,等待可见后再初始化
|
||||||
|
chart._pendingInit = true
|
||||||
|
chart._pendingInitIndex = index
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 先检查容器是否有尺寸
|
||||||
|
const rect = container.getBoundingClientRect()
|
||||||
|
const hasSize = (container.offsetWidth > 0 && container.offsetHeight > 0) ||
|
||||||
|
(rect.width > 0 && rect.height > 0)
|
||||||
|
|
||||||
|
if (hasSize) {
|
||||||
|
// 容器有尺寸,直接初始化
|
||||||
|
this.initChartWithContainer(index, container)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 容器没有尺寸,使用 ResizeObserver 监听,等待有尺寸后再初始化
|
||||||
|
if (typeof ResizeObserver !== 'undefined') {
|
||||||
|
const observer = new ResizeObserver((entries) => {
|
||||||
|
for (const entry of entries) {
|
||||||
|
const target = entry.target
|
||||||
|
const targetRect = target.getBoundingClientRect()
|
||||||
|
const targetHasSize = (target.offsetWidth > 0 && target.offsetHeight > 0) ||
|
||||||
|
(targetRect.width > 0 && targetRect.height > 0)
|
||||||
|
|
||||||
|
if (targetHasSize && !chart.chartInstance) {
|
||||||
|
// 容器有尺寸了,初始化图表
|
||||||
|
try {
|
||||||
|
this.initChartWithContainer(index, target)
|
||||||
|
// 初始化成功后,清理观察者
|
||||||
|
if (target._chartResizeObserver) {
|
||||||
|
target._chartResizeObserver.disconnect()
|
||||||
|
delete target._chartResizeObserver
|
||||||
|
}
|
||||||
|
// 清除待初始化标记
|
||||||
|
delete chart._pendingInit
|
||||||
|
delete chart._pendingInitIndex
|
||||||
|
} catch (e) {
|
||||||
|
console.error('图表初始化失败:', e)
|
||||||
|
}
|
||||||
|
} else if (targetHasSize && chart.chartInstance) {
|
||||||
|
// 容器有尺寸且图表已初始化,调整大小
|
||||||
|
chart.chartInstance.resize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
observer.observe(container)
|
||||||
|
// 保存观察者引用,以便后续清理
|
||||||
|
container._chartResizeObserver = observer
|
||||||
|
|
||||||
|
// 设置超时,如果30秒后还没有尺寸,就放弃(增加等待时间)
|
||||||
|
setTimeout(() => {
|
||||||
|
if (container._chartResizeObserver === observer && !chart.chartInstance) {
|
||||||
|
container._chartResizeObserver.disconnect()
|
||||||
|
delete container._chartResizeObserver
|
||||||
|
// 输出更详细的调试信息
|
||||||
|
const rect = container.getBoundingClientRect()
|
||||||
|
const style = window.getComputedStyle(container)
|
||||||
|
console.warn(`容器在30秒内仍没有尺寸,放弃初始化图表,索引: ${index}`, {
|
||||||
|
offsetWidth: container.offsetWidth,
|
||||||
|
offsetHeight: container.offsetHeight,
|
||||||
|
clientWidth: container.clientWidth,
|
||||||
|
clientHeight: container.clientHeight,
|
||||||
|
rectWidth: rect.width,
|
||||||
|
rectHeight: rect.height,
|
||||||
|
display: style.display,
|
||||||
|
visibility: style.visibility,
|
||||||
|
opacity: style.opacity,
|
||||||
|
activeTab: this.activeTab
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, 30000) // 增加到30秒
|
||||||
|
} else {
|
||||||
|
// 不支持 ResizeObserver,使用轮询方式检查
|
||||||
|
let checkCount = 0
|
||||||
|
const maxChecks = 150 // 30秒 / 200ms = 150次
|
||||||
|
const checkInterval = setInterval(() => {
|
||||||
|
checkCount++
|
||||||
|
const rect = container.getBoundingClientRect()
|
||||||
|
const hasSize = (container.offsetWidth > 0 && container.offsetHeight > 0) ||
|
||||||
|
(rect.width > 0 && rect.height > 0)
|
||||||
|
|
||||||
|
if (hasSize && !chart.chartInstance) {
|
||||||
|
clearInterval(checkInterval)
|
||||||
|
this.initChartWithContainer(index, container)
|
||||||
|
// 清除待初始化标记
|
||||||
|
delete chart._pendingInit
|
||||||
|
delete chart._pendingInitIndex
|
||||||
|
} else if (checkCount >= maxChecks) {
|
||||||
|
clearInterval(checkInterval)
|
||||||
|
if (!chart.chartInstance) {
|
||||||
|
const style = window.getComputedStyle(container)
|
||||||
|
console.warn(`容器在30秒内仍没有尺寸,放弃初始化图表,索引: ${index}`, {
|
||||||
|
offsetWidth: container.offsetWidth,
|
||||||
|
offsetHeight: container.offsetHeight,
|
||||||
|
activeTab: this.activeTab,
|
||||||
|
display: style.display
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 200)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
handleResize() {
|
handleResize() {
|
||||||
this.chartList.forEach((chart) => {
|
this.chartList.forEach((chart) => {
|
||||||
@ -1414,7 +1778,6 @@ export default {
|
|||||||
|
|
||||||
// 清空新选择的机型标记(查询完成后)
|
// 清空新选择的机型标记(查询完成后)
|
||||||
chart.newSelectedModels = []
|
chart.newSelectedModels = []
|
||||||
|
|
||||||
// 根据当前选择的机型,从缓存中获取数据并更新图表
|
// 根据当前选择的机型,从缓存中获取数据并更新图表
|
||||||
this.updateChartDataFromCache(index)
|
this.updateChartDataFromCache(index)
|
||||||
|
|
||||||
@ -2394,11 +2757,30 @@ export default {
|
|||||||
this.resizingChartIndex = -1
|
this.resizingChartIndex = -1
|
||||||
},
|
},
|
||||||
disposeAllCharts() {
|
disposeAllCharts() {
|
||||||
this.chartList.forEach((chart) => {
|
this.chartList.forEach((chart, index) => {
|
||||||
if (chart.chartInstance) {
|
if (chart.chartInstance) {
|
||||||
chart.chartInstance.dispose()
|
chart.chartInstance.dispose()
|
||||||
chart.chartInstance = null
|
chart.chartInstance = null
|
||||||
}
|
}
|
||||||
|
// 清理 resize 事件监听器
|
||||||
|
if (chart._resizeHandler) {
|
||||||
|
window.removeEventListener('resize', chart._resizeHandler)
|
||||||
|
delete chart._resizeHandler
|
||||||
|
}
|
||||||
|
// 清理容器的 ResizeObserver
|
||||||
|
const refName = `chartContainer-${index}`
|
||||||
|
const containerRef = this.$refs[refName]
|
||||||
|
if (containerRef) {
|
||||||
|
const container = Array.isArray(containerRef) ? containerRef[0] : containerRef
|
||||||
|
if (container && container._chartResizeObserver) {
|
||||||
|
container._chartResizeObserver.disconnect()
|
||||||
|
delete container._chartResizeObserver
|
||||||
|
}
|
||||||
|
if (container && container._resizeObserver) {
|
||||||
|
container._resizeObserver.disconnect()
|
||||||
|
delete container._resizeObserver
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2705,11 +3087,19 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.empty-chart-area {
|
||||||
|
min-height: 2px;
|
||||||
|
padding: 0 !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
border-radius: 0 !important;
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
.chart-area {
|
.chart-area {
|
||||||
background: white;
|
background: white;
|
||||||
margin: 20px;
|
margin: 20px;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
|
min-height: 2px;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
|||||||
@ -1456,8 +1456,6 @@ export default {
|
|||||||
|
|
||||||
if (matchedSubsystemName) {
|
if (matchedSubsystemName) {
|
||||||
const partsNames = subsystemPartsMap.get(matchedSubsystemName)
|
const partsNames = subsystemPartsMap.get(matchedSubsystemName)
|
||||||
const subsystemName = matchedSubsystemName
|
|
||||||
|
|
||||||
// 检查是否有 partsName 为 '/' 的情况(应该选中子系统节点本身)
|
// 检查是否有 partsName 为 '/' 的情况(应该选中子系统节点本身)
|
||||||
if (partsNames.has('/')) {
|
if (partsNames.has('/')) {
|
||||||
// 如果 partsName 是 '/',选中子系统节点(一级节点)
|
// 如果 partsName 是 '/',选中子系统节点(一级节点)
|
||||||
|
|||||||
@ -36,7 +36,6 @@ const SearchComponentMixin = {
|
|||||||
return this.searchValue
|
return this.searchValue
|
||||||
},
|
},
|
||||||
set: function (value) {
|
set: function (value) {
|
||||||
debugger
|
|
||||||
this.$emit('change', value)
|
this.$emit('change', value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -94,4 +94,3 @@ export function clearUserRole() {
|
|||||||
export function hasUserRole() {
|
export function hasUserRole() {
|
||||||
return localStorage.getItem(USER_ROLE_STORAGE_KEY) !== null
|
return localStorage.getItem(USER_ROLE_STORAGE_KEY) !== null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import Vue from 'vue'
|
|||||||
// import i18n from '@/locale'
|
// import i18n from '@/locale'
|
||||||
export const GLOABL_MENU_ACTION = {
|
export const GLOABL_MENU_ACTION = {
|
||||||
TO_ROUTER: (engine, event) => {
|
TO_ROUTER: (engine, event) => {
|
||||||
debugger
|
|
||||||
const { menu } = event
|
const { menu } = event
|
||||||
let needRefresh = true
|
let needRefresh = true
|
||||||
if (engine.layoutConfig.keepAliveRouter) {
|
if (engine.layoutConfig.keepAliveRouter) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user