|
@@ -1,10 +1,8 @@
|
|
|
<template>
|
|
<template>
|
|
|
<div class="power-use-container">
|
|
<div class="power-use-container">
|
|
|
<el-tabs v-model="activeName" class="main-tabs" @tab-click="handleTabClick">
|
|
<el-tabs v-model="activeName" class="main-tabs" @tab-click="handleTabClick">
|
|
|
- <!-- 总览 Tab -->
|
|
|
|
|
<el-tab-pane label="总览" name="summary">
|
|
<el-tab-pane label="总览" name="summary">
|
|
|
<div class="summary-section">
|
|
<div class="summary-section">
|
|
|
- <!-- 时间范围切换 -->
|
|
|
|
|
<div class="time-range-bar">
|
|
<div class="time-range-bar">
|
|
|
<div class="time-buttons">
|
|
<div class="time-buttons">
|
|
|
<el-button
|
|
<el-button
|
|
@@ -23,7 +21,6 @@
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <!-- 统计卡片 -->
|
|
|
|
|
<div class="stat-cards">
|
|
<div class="stat-cards">
|
|
|
<el-row :gutter="16">
|
|
<el-row :gutter="16">
|
|
|
<el-col :span="6">
|
|
<el-col :span="6">
|
|
@@ -112,7 +109,6 @@
|
|
|
</el-row>
|
|
</el-row>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <!-- 图表和表格区域 -->
|
|
|
|
|
<el-row :gutter="20" class="content-row">
|
|
<el-row :gutter="20" class="content-row">
|
|
|
<el-col :span="14">
|
|
<el-col :span="14">
|
|
|
<div class="chart-panel">
|
|
<div class="chart-panel">
|
|
@@ -172,7 +168,6 @@
|
|
|
</div>
|
|
</div>
|
|
|
</el-tab-pane>
|
|
</el-tab-pane>
|
|
|
|
|
|
|
|
- <!-- 设施分类 Tabs (动态生成) - 修复:使用独立的 detail-pane 组件或唯一ref -->
|
|
|
|
|
<el-tab-pane
|
|
<el-tab-pane
|
|
|
v-for="item in facsCategoryOptions"
|
|
v-for="item in facsCategoryOptions"
|
|
|
:key="item.code"
|
|
:key="item.code"
|
|
@@ -181,46 +176,50 @@
|
|
|
:lazy="true"
|
|
:lazy="true"
|
|
|
>
|
|
>
|
|
|
<el-row :gutter="20">
|
|
<el-row :gutter="20">
|
|
|
- <!-- 左侧区域树 -->
|
|
|
|
|
<el-col :span="5">
|
|
<el-col :span="5">
|
|
|
- <div class="tree-panel">
|
|
|
|
|
- <div class="tree-search">
|
|
|
|
|
- <el-input
|
|
|
|
|
- v-model="areaKeyword"
|
|
|
|
|
- placeholder="搜索区域"
|
|
|
|
|
- clearable
|
|
|
|
|
- size="small"
|
|
|
|
|
- prefix-icon="el-icon-search"
|
|
|
|
|
- @input="filterAreaTree"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="tree-content">
|
|
|
|
|
- <el-tree
|
|
|
|
|
- :ref="'areaTree_' + item.code"
|
|
|
|
|
- :data="areaTreeData"
|
|
|
|
|
- :props="treeProps"
|
|
|
|
|
- :expand-on-click-node="false"
|
|
|
|
|
- :filter-node-method="filterNode"
|
|
|
|
|
- node-key="id"
|
|
|
|
|
- default-expand-all
|
|
|
|
|
- highlight-current
|
|
|
|
|
- @node-click="handleAreaNodeClick"
|
|
|
|
|
- >
|
|
|
|
|
- <template #default="{ node, data }">
|
|
|
|
|
- <div class="tree-node-item">
|
|
|
|
|
- <i :class="getTreeNodeIcon(data)" class="node-icon"></i>
|
|
|
|
|
- <span class="node-label">{{ node.label }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </template>
|
|
|
|
|
- </el-tree>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <div class="head-container">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="areaKeyword"
|
|
|
|
|
+ placeholder="搜索区域"
|
|
|
|
|
+ clearable
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ prefix-icon="el-icon-search"
|
|
|
|
|
+ style="margin-bottom: 20px"
|
|
|
|
|
+ @input="filterAreaTree"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="head-container tree-container">
|
|
|
|
|
+ <el-tree
|
|
|
|
|
+ :ref="'areaTree_' + item.code"
|
|
|
|
|
+ :data="areaTreeData"
|
|
|
|
|
+ :props="treeProps"
|
|
|
|
|
+ :expand-on-click-node="false"
|
|
|
|
|
+ :filter-node-method="filterNode"
|
|
|
|
|
+ node-key="id"
|
|
|
|
|
+ :default-expanded-keys="defaultExpandedKeys"
|
|
|
|
|
+ highlight-current
|
|
|
|
|
+ @node-click="handleAreaNodeClick"
|
|
|
|
|
+ >
|
|
|
|
|
+ <span class="custom-tree-node" slot-scope="{ node, data }">
|
|
|
|
|
+ <span class="tree-label">
|
|
|
|
|
+ <i :class="getTreeNodeIcon(data)" class="tree-icon"></i>
|
|
|
|
|
+ {{ node.label }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ <el-tag
|
|
|
|
|
+ v-if="data.id !== '-1'"
|
|
|
|
|
+ size="mini"
|
|
|
|
|
+ effect="plain"
|
|
|
|
|
+ class="tree-tag"
|
|
|
|
|
+ >
|
|
|
|
|
+ 区域
|
|
|
|
|
+ </el-tag>
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </el-tree>
|
|
|
</div>
|
|
</div>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
|
|
|
|
|
- <!-- 右侧内容区 -->
|
|
|
|
|
<el-col :span="19">
|
|
<el-col :span="19">
|
|
|
<div class="detail-content">
|
|
<div class="detail-content">
|
|
|
- <!-- 筛选条件 -->
|
|
|
|
|
<div class="filter-section">
|
|
<div class="filter-section">
|
|
|
<div class="filter-left">
|
|
<div class="filter-left">
|
|
|
<span class="current-area">
|
|
<span class="current-area">
|
|
@@ -259,7 +258,6 @@
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <!-- 设施汇总表格 -->
|
|
|
|
|
<div class="detail-table-section">
|
|
<div class="detail-table-section">
|
|
|
<div class="section-header">
|
|
<div class="section-header">
|
|
|
<h3 class="section-title"><i class="el-icon-s-grid"></i> 设施用电汇总</h3>
|
|
<h3 class="section-title"><i class="el-icon-s-grid"></i> 设施用电汇总</h3>
|
|
@@ -313,7 +311,6 @@
|
|
|
</el-table>
|
|
</el-table>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <!-- 设施时段电耗图表 - 核心修复:使用动态ref -->
|
|
|
|
|
<div class="detail-chart-section">
|
|
<div class="detail-chart-section">
|
|
|
<div class="section-header">
|
|
<div class="section-header">
|
|
|
<h3 class="section-title"><i class="el-icon-data-line"></i> 设施时段电耗对比</h3>
|
|
<h3 class="section-title"><i class="el-icon-data-line"></i> 设施时段电耗对比</h3>
|
|
@@ -337,7 +334,6 @@
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="chart-container" v-loading="detailChartLoading">
|
|
<div class="chart-container" v-loading="detailChartLoading">
|
|
|
- <!-- 关键修复:每个tab使用独立的ref名称 -->
|
|
|
|
|
<div
|
|
<div
|
|
|
:ref="'detailChart_' + item.code"
|
|
:ref="'detailChart_' + item.code"
|
|
|
class="chart-canvas"
|
|
class="chart-canvas"
|
|
@@ -394,10 +390,11 @@ export default {
|
|
|
// ========== 设施分类 ==========
|
|
// ========== 设施分类 ==========
|
|
|
facsCategoryOptions: [],
|
|
facsCategoryOptions: [],
|
|
|
|
|
|
|
|
- // ========== 区域树 ==========
|
|
|
|
|
|
|
+ // ========== 区域树 (更新配置) ==========
|
|
|
areaKeyword: '',
|
|
areaKeyword: '',
|
|
|
areaTreeData: [],
|
|
areaTreeData: [],
|
|
|
treeProps: { children: 'children', label: 'label' },
|
|
treeProps: { children: 'children', label: 'label' },
|
|
|
|
|
+ defaultExpandedKeys: ['-1'], // 默认展开全部
|
|
|
selectedAreaCode: '-1',
|
|
selectedAreaCode: '-1',
|
|
|
selectedAreaLabel: '全部',
|
|
selectedAreaLabel: '全部',
|
|
|
|
|
|
|
@@ -506,7 +503,7 @@ export default {
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
methods: {
|
|
methods: {
|
|
|
- // ==================== 工具方法 ====================
|
|
|
|
|
|
|
+ // ... (保留原有的 formatNumber, formatSmartNumber 等工具方法) ...
|
|
|
formatSmartNumber(value) {
|
|
formatSmartNumber(value) {
|
|
|
if (value === null || value === undefined) {
|
|
if (value === null || value === undefined) {
|
|
|
return { display: '0', suffix: '', full: '0', isShortened: false }
|
|
return { display: '0', suffix: '', full: '0', isShortened: false }
|
|
@@ -572,26 +569,19 @@ export default {
|
|
|
return `${dayjs(this.overviewDateRange[0]).format('MM-DD HH:mm')} 至 ${dayjs(this.overviewDateRange[1]).format('MM-DD HH:mm')}`
|
|
return `${dayjs(this.overviewDateRange[0]).format('MM-DD HH:mm')} 至 ${dayjs(this.overviewDateRange[1]).format('MM-DD HH:mm')}`
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
- // ==================== 获取图表DOM(核心修复) ====================
|
|
|
|
|
getDetailChartDom() {
|
|
getDetailChartDom() {
|
|
|
const refName = 'detailChart_' + this.activeName
|
|
const refName = 'detailChart_' + this.activeName
|
|
|
const chartRef = this.$refs[refName]
|
|
const chartRef = this.$refs[refName]
|
|
|
-
|
|
|
|
|
- console.log('[getDetailChartDom] refName:', refName, 'chartRef:', chartRef)
|
|
|
|
|
-
|
|
|
|
|
- // v-for 中的 ref 在 Vue2 中返回数组
|
|
|
|
|
if (Array.isArray(chartRef)) {
|
|
if (Array.isArray(chartRef)) {
|
|
|
return chartRef[0]
|
|
return chartRef[0]
|
|
|
}
|
|
}
|
|
|
return chartRef
|
|
return chartRef
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
- // ==================== 数据加载 ====================
|
|
|
|
|
async loadFacsCategories() {
|
|
async loadFacsCategories() {
|
|
|
try {
|
|
try {
|
|
|
const response = await getFacsCategorygetByCode('Z')
|
|
const response = await getFacsCategorygetByCode('Z')
|
|
|
this.facsCategoryOptions = response.data?.subtypeList || []
|
|
this.facsCategoryOptions = response.data?.subtypeList || []
|
|
|
- console.log('设施分类:', this.facsCategoryOptions)
|
|
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
console.error('加载设施分类失败', error)
|
|
console.error('加载设施分类失败', error)
|
|
|
}
|
|
}
|
|
@@ -610,17 +600,15 @@ export default {
|
|
|
const response = await listFacsMeterHourSta(params)
|
|
const response = await listFacsMeterHourSta(params)
|
|
|
const data = response.data || []
|
|
const data = response.data || []
|
|
|
|
|
|
|
|
- // 修改:字段从 quantity 改为 totalElecQuantity
|
|
|
|
|
this.overviewTableData = data
|
|
this.overviewTableData = data
|
|
|
.map(item => ({
|
|
.map(item => ({
|
|
|
objCode: item.objCode,
|
|
objCode: item.objCode,
|
|
|
objName: item.objName,
|
|
objName: item.objName,
|
|
|
- quantity: item.totalElecQuantity || 0 // 修改此处
|
|
|
|
|
|
|
+ quantity: item.totalElecQuantity || 0
|
|
|
}))
|
|
}))
|
|
|
.filter(item => item.quantity > 0)
|
|
.filter(item => item.quantity > 0)
|
|
|
.sort((a, b) => b.quantity - a.quantity)
|
|
.sort((a, b) => b.quantity - a.quantity)
|
|
|
|
|
|
|
|
- // 修改:利用新字段获取分时电量统计
|
|
|
|
|
const totalQuantity = data.reduce((sum, item) => sum + (item.totalElecQuantity || 0), 0)
|
|
const totalQuantity = data.reduce((sum, item) => sum + (item.totalElecQuantity || 0), 0)
|
|
|
const peakQuantity = data.reduce((sum, item) => sum + (item.peakQuantity || 0) + (item.sharpPeakQuantity || 0), 0)
|
|
const peakQuantity = data.reduce((sum, item) => sum + (item.peakQuantity || 0) + (item.sharpPeakQuantity || 0), 0)
|
|
|
const valleyQuantity = data.reduce((sum, item) => sum + (item.valleyQuantity || 0) + (item.deepValleyQuantity || 0), 0)
|
|
const valleyQuantity = data.reduce((sum, item) => sum + (item.valleyQuantity || 0) + (item.deepValleyQuantity || 0), 0)
|
|
@@ -629,10 +617,10 @@ export default {
|
|
|
|
|
|
|
|
this.overviewSummary = {
|
|
this.overviewSummary = {
|
|
|
totalQuantity: totalQuantity,
|
|
totalQuantity: totalQuantity,
|
|
|
- peakQuantity: peakQuantity, // 现在可以正确显示峰时用电
|
|
|
|
|
- valleyQuantity: valleyQuantity, // 现在可以正确显示谷时用电
|
|
|
|
|
|
|
+ peakQuantity: peakQuantity,
|
|
|
|
|
+ valleyQuantity: valleyQuantity,
|
|
|
normalQuantity: normalQuantity,
|
|
normalQuantity: normalQuantity,
|
|
|
- totalCost: totalCost // 现在可以正确显示总电费
|
|
|
|
|
|
|
+ totalCost: totalCost
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
this.$nextTick(() => this.renderOverviewChart())
|
|
this.$nextTick(() => this.renderOverviewChart())
|
|
@@ -644,26 +632,22 @@ export default {
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
|
|
+ // 树数据加载:只负责加载数据,不负责业务重置
|
|
|
async loadAreaTree() {
|
|
async loadAreaTree() {
|
|
|
try {
|
|
try {
|
|
|
const response = await areaTreeByFacsCategory('Z', this.queryParams.facsSubCategory, false)
|
|
const response = await areaTreeByFacsCategory('Z', this.queryParams.facsSubCategory, false)
|
|
|
|
|
+ // 使用 ID -1 确保 key 唯一
|
|
|
this.areaTreeData = [{ id: '-1', label: '全部', children: response.data || [] }]
|
|
this.areaTreeData = [{ id: '-1', label: '全部', children: response.data || [] }]
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
console.error('加载区域树失败', error)
|
|
console.error('加载区域树失败', error)
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * 加载详情数据 - 核心方法
|
|
|
|
|
- */
|
|
|
|
|
async loadDetailData() {
|
|
async loadDetailData() {
|
|
|
if (!this.queryParams.facsSubCategory) {
|
|
if (!this.queryParams.facsSubCategory) {
|
|
|
- console.warn('[loadDetailData] facsSubCategory 未设置')
|
|
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- console.log('[loadDetailData] 开始加载, facsSubCategory:', this.queryParams.facsSubCategory)
|
|
|
|
|
-
|
|
|
|
|
this.detailLoading = true
|
|
this.detailLoading = true
|
|
|
this.detailChartLoading = true
|
|
this.detailChartLoading = true
|
|
|
|
|
|
|
@@ -677,21 +661,14 @@ export default {
|
|
|
facsSubCategory: this.queryParams.facsSubCategory
|
|
facsSubCategory: this.queryParams.facsSubCategory
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- console.log('[loadDetailData] 请求参数:', baseParams)
|
|
|
|
|
-
|
|
|
|
|
- // 1. 加载设施汇总数据
|
|
|
|
|
const summaryRes = await listFacsMeterHourSta(baseParams)
|
|
const summaryRes = await listFacsMeterHourSta(baseParams)
|
|
|
- console.log('[loadDetailData] 设施汇总响应:', summaryRes)
|
|
|
|
|
|
|
|
|
|
- // 修改:字段从 quantity 改为 totalElecQuantity
|
|
|
|
|
this.facsSummaryList = (summaryRes.data || []).map(item => ({
|
|
this.facsSummaryList = (summaryRes.data || []).map(item => ({
|
|
|
objCode: item.objCode,
|
|
objCode: item.objCode,
|
|
|
objName: item.objName,
|
|
objName: item.objName,
|
|
|
- quantity: item.totalElecQuantity || 0 // 修改此处
|
|
|
|
|
|
|
+ quantity: item.totalElecQuantity || 0
|
|
|
}))
|
|
}))
|
|
|
- console.log('[loadDetailData] 设施汇总数据:', this.facsSummaryList)
|
|
|
|
|
|
|
|
|
|
- // 更新设施下拉选项
|
|
|
|
|
this.facsOptions = this.facsSummaryList.map(item => ({
|
|
this.facsOptions = this.facsSummaryList.map(item => ({
|
|
|
objCode: item.objCode,
|
|
objCode: item.objCode,
|
|
|
objName: item.objName
|
|
objName: item.objName
|
|
@@ -699,13 +676,10 @@ export default {
|
|
|
|
|
|
|
|
this.detailLoading = false
|
|
this.detailLoading = false
|
|
|
|
|
|
|
|
- // 2. 加载时段电耗数据 - 分别获取每个设施的小时数据
|
|
|
|
|
await this.loadHourlyDataByFacs(baseParams)
|
|
await this.loadHourlyDataByFacs(baseParams)
|
|
|
|
|
|
|
|
- // 3. 渲染图表 - 使用更长的延迟确保DOM已渲染
|
|
|
|
|
this.$nextTick(() => {
|
|
this.$nextTick(() => {
|
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
|
- console.log('[loadDetailData] 准备渲染图表')
|
|
|
|
|
this.renderDetailChart()
|
|
this.renderDetailChart()
|
|
|
}, 300)
|
|
}, 300)
|
|
|
})
|
|
})
|
|
@@ -718,20 +692,11 @@ export default {
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * 分别加载每个设施的小时数据 - 关键修复
|
|
|
|
|
- */
|
|
|
|
|
async loadHourlyDataByFacs(baseParams) {
|
|
async loadHourlyDataByFacs(baseParams) {
|
|
|
- console.log('[loadHourlyDataByFacs] 开始加载小时数据')
|
|
|
|
|
-
|
|
|
|
|
- // 如果选择了具体设施,只查该设施
|
|
|
|
|
if (this.selectedObjCode) {
|
|
if (this.selectedObjCode) {
|
|
|
const params = { ...baseParams, objCode: this.selectedObjCode }
|
|
const params = { ...baseParams, objCode: this.selectedObjCode }
|
|
|
- console.log('[loadHourlyDataByFacs] 查询单个设施:', this.selectedObjCode)
|
|
|
|
|
-
|
|
|
|
|
const hourlyRes = await listFacsElecHourMeter(params)
|
|
const hourlyRes = await listFacsElecHourMeter(params)
|
|
|
const rawData = hourlyRes.rows || []
|
|
const rawData = hourlyRes.rows || []
|
|
|
-
|
|
|
|
|
const facs = this.facsSummaryList.find(f => f.objCode === this.selectedObjCode)
|
|
const facs = this.facsSummaryList.find(f => f.objCode === this.selectedObjCode)
|
|
|
const facsName = facs ? facs.objName : this.selectedObjCode
|
|
const facsName = facs ? facs.objName : this.selectedObjCode
|
|
|
|
|
|
|
@@ -740,16 +705,12 @@ export default {
|
|
|
objName: facsName,
|
|
objName: facsName,
|
|
|
hourlyData: this.processHourlyData(rawData)
|
|
hourlyData: this.processHourlyData(rawData)
|
|
|
}]
|
|
}]
|
|
|
- console.log('[loadHourlyDataByFacs] 单设施时段数据:', this.hourlyDataByFacs)
|
|
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 没有选择具体设施时,分别获取每个设施的数据
|
|
|
|
|
const facsListToQuery = this.facsSummaryList.length > 0 ? this.facsSummaryList : []
|
|
const facsListToQuery = this.facsSummaryList.length > 0 ? this.facsSummaryList : []
|
|
|
- console.log('[loadHourlyDataByFacs] 需要查询的设施列表:', facsListToQuery)
|
|
|
|
|
|
|
|
|
|
if (facsListToQuery.length === 0) {
|
|
if (facsListToQuery.length === 0) {
|
|
|
- // 没有设施时,尝试按区域获取汇总数据
|
|
|
|
|
const hourlyRes = await listFacsElecHourMeter(baseParams)
|
|
const hourlyRes = await listFacsElecHourMeter(baseParams)
|
|
|
const rawData = hourlyRes.rows || []
|
|
const rawData = hourlyRes.rows || []
|
|
|
|
|
|
|
@@ -758,16 +719,12 @@ export default {
|
|
|
} else {
|
|
} else {
|
|
|
this.hourlyDataByFacs = []
|
|
this.hourlyDataByFacs = []
|
|
|
}
|
|
}
|
|
|
- console.log('[loadHourlyDataByFacs] 汇总时段数据(按区域分组):', this.hourlyDataByFacs)
|
|
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 并行请求所有设施的小时数据
|
|
|
|
|
const hourlyPromises = facsListToQuery.map(async(facs) => {
|
|
const hourlyPromises = facsListToQuery.map(async(facs) => {
|
|
|
try {
|
|
try {
|
|
|
const params = { ...baseParams, objCode: facs.objCode }
|
|
const params = { ...baseParams, objCode: facs.objCode }
|
|
|
- console.log('[loadHourlyDataByFacs] 请求设施小时数据:', facs.objCode)
|
|
|
|
|
-
|
|
|
|
|
const hourlyRes = await listFacsElecHourMeter(params)
|
|
const hourlyRes = await listFacsElecHourMeter(params)
|
|
|
const rawData = hourlyRes.rows || []
|
|
const rawData = hourlyRes.rows || []
|
|
|
|
|
|
|
@@ -777,7 +734,6 @@ export default {
|
|
|
hourlyData: this.processHourlyData(rawData)
|
|
hourlyData: this.processHourlyData(rawData)
|
|
|
}
|
|
}
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
- console.error(`加载设施 ${facs.objCode} 小时数据失败:`, error)
|
|
|
|
|
return {
|
|
return {
|
|
|
objCode: facs.objCode,
|
|
objCode: facs.objCode,
|
|
|
objName: facs.objName,
|
|
objName: facs.objName,
|
|
@@ -787,21 +743,15 @@ export default {
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
const results = await Promise.all(hourlyPromises)
|
|
const results = await Promise.all(hourlyPromises)
|
|
|
-
|
|
|
|
|
- // 过滤掉没有数据的设施
|
|
|
|
|
this.hourlyDataByFacs = results.filter(item => item.hourlyData.length > 0)
|
|
this.hourlyDataByFacs = results.filter(item => item.hourlyData.length > 0)
|
|
|
- console.log('[loadHourlyDataByFacs] 多设施时段数据:', this.hourlyDataByFacs)
|
|
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * 处理小时数据
|
|
|
|
|
- */
|
|
|
|
|
processHourlyData(rawData) {
|
|
processHourlyData(rawData) {
|
|
|
if (!rawData || rawData.length === 0) return []
|
|
if (!rawData || rawData.length === 0) return []
|
|
|
|
|
|
|
|
return rawData
|
|
return rawData
|
|
|
.map(item => ({
|
|
.map(item => ({
|
|
|
- time: item.time ? item.time.substring(0, 5) : '', // "15:00:00" -> "15:00"
|
|
|
|
|
|
|
+ time: item.time ? item.time.substring(0, 5) : '',
|
|
|
value: parseFloat(item.elecQuantity) || 0,
|
|
value: parseFloat(item.elecQuantity) || 0,
|
|
|
recordTime: item.recordTime
|
|
recordTime: item.recordTime
|
|
|
}))
|
|
}))
|
|
@@ -809,16 +759,11 @@ export default {
|
|
|
.sort((a, b) => a.time.localeCompare(b.time))
|
|
.sort((a, b) => a.time.localeCompare(b.time))
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * 按区域代码分组数据
|
|
|
|
|
- */
|
|
|
|
|
groupByAreaCode(rawData) {
|
|
groupByAreaCode(rawData) {
|
|
|
const grouped = {}
|
|
const grouped = {}
|
|
|
-
|
|
|
|
|
rawData.forEach(item => {
|
|
rawData.forEach(item => {
|
|
|
const areaCode = item.areaCode || 'unknown'
|
|
const areaCode = item.areaCode || 'unknown'
|
|
|
const areaName = item.deviceName || areaCode
|
|
const areaName = item.deviceName || areaCode
|
|
|
-
|
|
|
|
|
if (!grouped[areaCode]) {
|
|
if (!grouped[areaCode]) {
|
|
|
grouped[areaCode] = {
|
|
grouped[areaCode] = {
|
|
|
objCode: areaCode,
|
|
objCode: areaCode,
|
|
@@ -826,24 +771,18 @@ export default {
|
|
|
hourlyData: []
|
|
hourlyData: []
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
grouped[areaCode].hourlyData.push({
|
|
grouped[areaCode].hourlyData.push({
|
|
|
time: item.time ? item.time.substring(0, 5) : '',
|
|
time: item.time ? item.time.substring(0, 5) : '',
|
|
|
value: parseFloat(item.elecQuantity) || 0,
|
|
value: parseFloat(item.elecQuantity) || 0,
|
|
|
recordTime: item.recordTime
|
|
recordTime: item.recordTime
|
|
|
})
|
|
})
|
|
|
})
|
|
})
|
|
|
-
|
|
|
|
|
Object.values(grouped).forEach(area => {
|
|
Object.values(grouped).forEach(area => {
|
|
|
area.hourlyData.sort((a, b) => a.time.localeCompare(b.time))
|
|
area.hourlyData.sort((a, b) => a.time.localeCompare(b.time))
|
|
|
})
|
|
})
|
|
|
-
|
|
|
|
|
return Object.values(grouped)
|
|
return Object.values(grouped)
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * 设施选择变化
|
|
|
|
|
- */
|
|
|
|
|
handleFacsChange() {
|
|
handleFacsChange() {
|
|
|
this.detailChartLoading = true
|
|
this.detailChartLoading = true
|
|
|
this.loadHourlyDataByFacs({
|
|
this.loadHourlyDataByFacs({
|
|
@@ -859,7 +798,6 @@ export default {
|
|
|
})
|
|
})
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
- // ==================== 图表渲染 ====================
|
|
|
|
|
renderOverviewChart() {
|
|
renderOverviewChart() {
|
|
|
const chartDom = this.$refs.overviewChartRef
|
|
const chartDom = this.$refs.overviewChartRef
|
|
|
if (!chartDom || this.overviewTableData.length === 0) return
|
|
if (!chartDom || this.overviewTableData.length === 0) return
|
|
@@ -882,6 +820,7 @@ export default {
|
|
|
this.overviewChartInstance.setOption(option)
|
|
this.overviewChartInstance.setOption(option)
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
|
|
+ // ... (保留图表Option配置方法) ...
|
|
|
getPieChartOption(data) {
|
|
getPieChartOption(data) {
|
|
|
const total = data.reduce((sum, item) => sum + item.value, 0)
|
|
const total = data.reduce((sum, item) => sum + item.value, 0)
|
|
|
return {
|
|
return {
|
|
@@ -910,7 +849,6 @@ export default {
|
|
|
}]
|
|
}]
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
-
|
|
|
|
|
getBarChartOption(data) {
|
|
getBarChartOption(data) {
|
|
|
return {
|
|
return {
|
|
|
tooltip: {
|
|
tooltip: {
|
|
@@ -946,26 +884,11 @@ export default {
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * 渲染详情图表 - 多设施对比(核心修复版)
|
|
|
|
|
- */
|
|
|
|
|
renderDetailChart() {
|
|
renderDetailChart() {
|
|
|
- console.log('[renderDetailChart] 开始渲染, activeName:', this.activeName)
|
|
|
|
|
-
|
|
|
|
|
- // 使用修复后的方法获取DOM
|
|
|
|
|
const chartDom = this.getDetailChartDom()
|
|
const chartDom = this.getDetailChartDom()
|
|
|
-
|
|
|
|
|
- if (!chartDom) {
|
|
|
|
|
- console.warn('[renderDetailChart] 图表DOM不存在, activeName:', this.activeName)
|
|
|
|
|
- console.log('[renderDetailChart] 当前所有refs:', Object.keys(this.$refs))
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- console.log('[renderDetailChart] chartDom:', chartDom)
|
|
|
|
|
- console.log('[renderDetailChart] hourlyDataByFacs.length:', this.hourlyDataByFacs.length)
|
|
|
|
|
|
|
+ if (!chartDom) return
|
|
|
|
|
|
|
|
if (this.hourlyDataByFacs.length === 0) {
|
|
if (this.hourlyDataByFacs.length === 0) {
|
|
|
- console.warn('[renderDetailChart] 无时段数据')
|
|
|
|
|
if (this.detailChartInstance) {
|
|
if (this.detailChartInstance) {
|
|
|
this.detailChartInstance.dispose()
|
|
this.detailChartInstance.dispose()
|
|
|
this.detailChartInstance = null
|
|
this.detailChartInstance = null
|
|
@@ -973,46 +896,31 @@ export default {
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 检查DOM尺寸
|
|
|
|
|
const width = chartDom.offsetWidth
|
|
const width = chartDom.offsetWidth
|
|
|
const height = chartDom.offsetHeight
|
|
const height = chartDom.offsetHeight
|
|
|
- console.log('[renderDetailChart] DOM尺寸:', width, 'x', height)
|
|
|
|
|
|
|
|
|
|
if (!width || !height) {
|
|
if (!width || !height) {
|
|
|
- console.log('[renderDetailChart] DOM尺寸为0,延迟200ms重试')
|
|
|
|
|
setTimeout(() => this.renderDetailChart(), 200)
|
|
setTimeout(() => this.renderDetailChart(), 200)
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 销毁旧实例
|
|
|
|
|
if (this.detailChartInstance) {
|
|
if (this.detailChartInstance) {
|
|
|
this.detailChartInstance.dispose()
|
|
this.detailChartInstance.dispose()
|
|
|
this.detailChartInstance = null
|
|
this.detailChartInstance = null
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 初始化新实例
|
|
|
|
|
this.detailChartInstance = echarts.init(chartDom)
|
|
this.detailChartInstance = echarts.init(chartDom)
|
|
|
- console.log('[renderDetailChart] ECharts实例已创建')
|
|
|
|
|
-
|
|
|
|
|
- // 收集所有时间点并排序
|
|
|
|
|
const allTimes = new Set()
|
|
const allTimes = new Set()
|
|
|
this.hourlyDataByFacs.forEach(facs => {
|
|
this.hourlyDataByFacs.forEach(facs => {
|
|
|
facs.hourlyData.forEach(d => allTimes.add(d.time))
|
|
facs.hourlyData.forEach(d => allTimes.add(d.time))
|
|
|
})
|
|
})
|
|
|
const xAxisData = Array.from(allTimes).sort()
|
|
const xAxisData = Array.from(allTimes).sort()
|
|
|
|
|
|
|
|
- console.log('[renderDetailChart] X轴时间点:', xAxisData)
|
|
|
|
|
-
|
|
|
|
|
- // 构建多系列数据
|
|
|
|
|
const legendData = this.hourlyDataByFacs.map(f => f.objName)
|
|
const legendData = this.hourlyDataByFacs.map(f => f.objName)
|
|
|
const series = this.hourlyDataByFacs.map((facs, index) => {
|
|
const series = this.hourlyDataByFacs.map((facs, index) => {
|
|
|
const baseColor = this.getSeriesColor(index)
|
|
const baseColor = this.getSeriesColor(index)
|
|
|
-
|
|
|
|
|
- // 将小时数据转为Map
|
|
|
|
|
const hourlyMap = new Map()
|
|
const hourlyMap = new Map()
|
|
|
facs.hourlyData.forEach(d => hourlyMap.set(d.time, d.value))
|
|
facs.hourlyData.forEach(d => hourlyMap.set(d.time, d.value))
|
|
|
-
|
|
|
|
|
- // 按统一时间轴生成数据
|
|
|
|
|
const seriesData = xAxisData.map(time => hourlyMap.get(time) || 0)
|
|
const seriesData = xAxisData.map(time => hourlyMap.get(time) || 0)
|
|
|
|
|
|
|
|
return {
|
|
return {
|
|
@@ -1056,7 +964,6 @@ export default {
|
|
|
<div style="margin-bottom:8px;font-weight:600;border-bottom:1px solid rgba(255,255,255,0.2);padding-bottom:6px;">
|
|
<div style="margin-bottom:8px;font-weight:600;border-bottom:1px solid rgba(255,255,255,0.2);padding-bottom:6px;">
|
|
|
${params[0].axisValue}
|
|
${params[0].axisValue}
|
|
|
</div>`
|
|
</div>`
|
|
|
-
|
|
|
|
|
let total = 0
|
|
let total = 0
|
|
|
params.forEach(p => {
|
|
params.forEach(p => {
|
|
|
total += p.value || 0
|
|
total += p.value || 0
|
|
@@ -1065,14 +972,12 @@ export default {
|
|
|
<span style="font-weight:600;margin-left:20px;">${this.formatNumber(p.value)} kW·h</span>
|
|
<span style="font-weight:600;margin-left:20px;">${this.formatNumber(p.value)} kW·h</span>
|
|
|
</div>`
|
|
</div>`
|
|
|
})
|
|
})
|
|
|
-
|
|
|
|
|
if (params.length > 1) {
|
|
if (params.length > 1) {
|
|
|
html += `<div style="margin-top:8px;padding-top:6px;border-top:1px solid rgba(255,255,255,0.2);display:flex;justify-content:space-between;">
|
|
html += `<div style="margin-top:8px;padding-top:6px;border-top:1px solid rgba(255,255,255,0.2);display:flex;justify-content:space-between;">
|
|
|
<span>合计</span>
|
|
<span>合计</span>
|
|
|
<span style="font-weight:700;color:#4facfe;">${this.formatNumber(total)} kW·h</span>
|
|
<span style="font-weight:700;color:#4facfe;">${this.formatNumber(total)} kW·h</span>
|
|
|
</div>`
|
|
</div>`
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
html += '</div>'
|
|
html += '</div>'
|
|
|
return html
|
|
return html
|
|
|
}
|
|
}
|
|
@@ -1114,38 +1019,30 @@ export default {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
this.detailChartInstance.setOption(option)
|
|
this.detailChartInstance.setOption(option)
|
|
|
- console.log('[renderDetailChart] 图表渲染完成,系列数:', series.length, '时间点:', xAxisData.length)
|
|
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
- // ==================== 颜色相关 ====================
|
|
|
|
|
getChartColor(index) {
|
|
getChartColor(index) {
|
|
|
const colors = ['#4facfe', '#43e97b', '#fa709a', '#fee140', '#30cfd0', '#667eea', '#f093fb', '#f5576c', '#00f2fe', '#38f9d7', '#f77062', '#fe5196']
|
|
const colors = ['#4facfe', '#43e97b', '#fa709a', '#fee140', '#30cfd0', '#667eea', '#f093fb', '#f5576c', '#00f2fe', '#38f9d7', '#f77062', '#fe5196']
|
|
|
return colors[index % colors.length]
|
|
return colors[index % colors.length]
|
|
|
},
|
|
},
|
|
|
-
|
|
|
|
|
getSeriesColor(index) {
|
|
getSeriesColor(index) {
|
|
|
const colors = ['#4facfe', '#43e97b', '#fa709a', '#fee140', '#667eea', '#30cfd0', '#f093fb', '#f5576c']
|
|
const colors = ['#4facfe', '#43e97b', '#fa709a', '#fee140', '#667eea', '#30cfd0', '#f093fb', '#f5576c']
|
|
|
return colors[index % colors.length]
|
|
return colors[index % colors.length]
|
|
|
},
|
|
},
|
|
|
-
|
|
|
|
|
adjustColorAlpha(hex, alpha) {
|
|
adjustColorAlpha(hex, alpha) {
|
|
|
const r = parseInt(hex.slice(1, 3), 16)
|
|
const r = parseInt(hex.slice(1, 3), 16)
|
|
|
const g = parseInt(hex.slice(3, 5), 16)
|
|
const g = parseInt(hex.slice(3, 5), 16)
|
|
|
const b = parseInt(hex.slice(5, 7), 16)
|
|
const b = parseInt(hex.slice(5, 7), 16)
|
|
|
return `rgba(${r}, ${g}, ${b}, ${alpha})`
|
|
return `rgba(${r}, ${g}, ${b}, ${alpha})`
|
|
|
},
|
|
},
|
|
|
-
|
|
|
|
|
getProgressColor(percentage) {
|
|
getProgressColor(percentage) {
|
|
|
if (percentage >= 30) return '#f56c6c'
|
|
if (percentage >= 30) return '#f56c6c'
|
|
|
if (percentage >= 15) return '#e6a23c'
|
|
if (percentage >= 15) return '#e6a23c'
|
|
|
return '#409eff'
|
|
return '#409eff'
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
- // ==================== 事件处理 ====================
|
|
|
|
|
|
|
+ // 交互逻辑修改:在切换Tab时,手动设置当前树的高亮,防止状态丢失
|
|
|
handleTabClick(tab) {
|
|
handleTabClick(tab) {
|
|
|
- console.log('[handleTabClick] 切换Tab:', tab.name)
|
|
|
|
|
-
|
|
|
|
|
- // 销毁旧图表实例
|
|
|
|
|
if (this.detailChartInstance) {
|
|
if (this.detailChartInstance) {
|
|
|
this.detailChartInstance.dispose()
|
|
this.detailChartInstance.dispose()
|
|
|
this.detailChartInstance = null
|
|
this.detailChartInstance = null
|
|
@@ -1155,15 +1052,24 @@ export default {
|
|
|
this.$nextTick(() => this.loadOverviewData())
|
|
this.$nextTick(() => this.loadOverviewData())
|
|
|
} else {
|
|
} else {
|
|
|
this.queryParams.facsSubCategory = tab.name
|
|
this.queryParams.facsSubCategory = tab.name
|
|
|
- console.log('[handleTabClick] 切换到设施分类:', tab.name)
|
|
|
|
|
-
|
|
|
|
|
this.resetDetailState()
|
|
this.resetDetailState()
|
|
|
- this.loadAreaTree()
|
|
|
|
|
|
|
|
|
|
- // 增加延迟确保 tab-pane 完全渲染
|
|
|
|
|
|
|
+ // 1. 加载树数据
|
|
|
|
|
+ this.loadAreaTree().then(() => {
|
|
|
|
|
+ // 2. 确保 "全部" 节点被高亮
|
|
|
|
|
+ this.$nextTick(() => {
|
|
|
|
|
+ const refName = 'areaTree_' + tab.name
|
|
|
|
|
+ const treeRef = this.$refs[refName]
|
|
|
|
|
+ // v-for 中的 ref 是数组
|
|
|
|
|
+ const tree = Array.isArray(treeRef) ? treeRef[0] : treeRef
|
|
|
|
|
+ if (tree) {
|
|
|
|
|
+ tree.setCurrentKey('-1')
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
this.$nextTick(() => {
|
|
this.$nextTick(() => {
|
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
|
- console.log('[handleTabClick] 开始加载详情数据')
|
|
|
|
|
this.loadDetailData()
|
|
this.loadDetailData()
|
|
|
}, 400)
|
|
}, 400)
|
|
|
})
|
|
})
|
|
@@ -1204,26 +1110,22 @@ export default {
|
|
|
return data.label && data.label.indexOf(value) !== -1
|
|
return data.label && data.label.indexOf(value) !== -1
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
- // ==================== 表格相关 ====================
|
|
|
|
|
getRankClass(index) {
|
|
getRankClass(index) {
|
|
|
if (index === 0) return 'rank-first'
|
|
if (index === 0) return 'rank-first'
|
|
|
if (index === 1) return 'rank-second'
|
|
if (index === 1) return 'rank-second'
|
|
|
if (index === 2) return 'rank-third'
|
|
if (index === 2) return 'rank-third'
|
|
|
return 'rank-normal'
|
|
return 'rank-normal'
|
|
|
},
|
|
},
|
|
|
-
|
|
|
|
|
getPercentage(value) {
|
|
getPercentage(value) {
|
|
|
const total = this.overviewSummary.totalQuantity || 0
|
|
const total = this.overviewSummary.totalQuantity || 0
|
|
|
if (total === 0) return 0
|
|
if (total === 0) return 0
|
|
|
return ((value || 0) / total) * 100
|
|
return ((value || 0) / total) * 100
|
|
|
},
|
|
},
|
|
|
-
|
|
|
|
|
getFacsPercentage(value) {
|
|
getFacsPercentage(value) {
|
|
|
const total = this.facsSummaryTotal || 0
|
|
const total = this.facsSummaryTotal || 0
|
|
|
if (total === 0) return 0
|
|
if (total === 0) return 0
|
|
|
return ((value || 0) / total) * 100
|
|
return ((value || 0) / total) * 100
|
|
|
},
|
|
},
|
|
|
-
|
|
|
|
|
getOverviewSummaries({ columns }) {
|
|
getOverviewSummaries({ columns }) {
|
|
|
const sums = []
|
|
const sums = []
|
|
|
columns.forEach((column, index) => {
|
|
columns.forEach((column, index) => {
|
|
@@ -1243,7 +1145,6 @@ export default {
|
|
|
})
|
|
})
|
|
|
return sums
|
|
return sums
|
|
|
},
|
|
},
|
|
|
-
|
|
|
|
|
getFacsSummaries({ columns }) {
|
|
getFacsSummaries({ columns }) {
|
|
|
const sums = []
|
|
const sums = []
|
|
|
columns.forEach((column, index) => {
|
|
columns.forEach((column, index) => {
|
|
@@ -1264,13 +1165,13 @@ export default {
|
|
|
return sums
|
|
return sums
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
|
|
+ // 树图标逻辑:保持与源网侧一致
|
|
|
getTreeNodeIcon(data) {
|
|
getTreeNodeIcon(data) {
|
|
|
if (data.id === '-1') return 'el-icon-s-home'
|
|
if (data.id === '-1') return 'el-icon-s-home'
|
|
|
- if (data.children && data.children.length > 0) return 'el-icon-folder'
|
|
|
|
|
- return 'el-icon-place'
|
|
|
|
|
|
|
+ if (data.children && data.children.length > 0) return 'el-icon-office-building'
|
|
|
|
|
+ return 'el-icon-location-information'
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
- // ==================== 生命周期 ====================
|
|
|
|
|
handleResize() {
|
|
handleResize() {
|
|
|
if (this.overviewChartInstance) this.overviewChartInstance.resize()
|
|
if (this.overviewChartInstance) this.overviewChartInstance.resize()
|
|
|
if (this.detailChartInstance) this.detailChartInstance.resize()
|
|
if (this.detailChartInstance) this.detailChartInstance.resize()
|
|
@@ -1296,6 +1197,7 @@ export default {
|
|
|
background: linear-gradient(135deg, #f5f7fa 0%, #e8ecf1 100%);
|
|
background: linear-gradient(135deg, #f5f7fa 0%, #e8ecf1 100%);
|
|
|
min-height: calc(100vh - 84px);
|
|
min-height: calc(100vh - 84px);
|
|
|
|
|
|
|
|
|
|
+ // ... (保留 main-tabs, summary-section 等其他原有样式) ...
|
|
|
.main-tabs {
|
|
.main-tabs {
|
|
|
::v-deep .el-tabs__header {
|
|
::v-deep .el-tabs__header {
|
|
|
background: #fff;
|
|
background: #fff;
|
|
@@ -1474,48 +1376,88 @@ export default {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- .tree-panel {
|
|
|
|
|
|
|
+ .head-container {
|
|
|
background: #fff;
|
|
background: #fff;
|
|
|
- border-radius: 10px;
|
|
|
|
|
- border: 1px solid #ebeef5;
|
|
|
|
|
- overflow: hidden;
|
|
|
|
|
-
|
|
|
|
|
- .tree-search {
|
|
|
|
|
- padding: 12px;
|
|
|
|
|
- border-bottom: 1px solid #ebeef5;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .tree-content {
|
|
|
|
|
- max-height: calc(100vh - 280px);
|
|
|
|
|
|
|
+ padding: 15px;
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ margin-bottom: 15px;
|
|
|
|
|
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
|
|
|
+ border: 1px solid #ebeef5; // 增加边框以匹配整体风格
|
|
|
|
|
+
|
|
|
|
|
+ &.tree-container {
|
|
|
|
|
+ max-height: calc(100vh - 350px);
|
|
|
overflow-y: auto;
|
|
overflow-y: auto;
|
|
|
- padding: 8px;
|
|
|
|
|
-
|
|
|
|
|
- .tree-node-item {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- padding: 4px 0;
|
|
|
|
|
-
|
|
|
|
|
- .node-icon {
|
|
|
|
|
- margin-right: 8px;
|
|
|
|
|
- color: #409eff;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .node-label {
|
|
|
|
|
- font-size: 13px;
|
|
|
|
|
- overflow: hidden;
|
|
|
|
|
- text-overflow: ellipsis;
|
|
|
|
|
- white-space: nowrap;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
|
|
+ // 滚动条样式
|
|
|
&::-webkit-scrollbar {
|
|
&::-webkit-scrollbar {
|
|
|
width: 6px;
|
|
width: 6px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ &::-webkit-scrollbar-track {
|
|
|
|
|
+ background: #f1f1f1;
|
|
|
|
|
+ border-radius: 3px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
&::-webkit-scrollbar-thumb {
|
|
&::-webkit-scrollbar-thumb {
|
|
|
background: #c1c1c1;
|
|
background: #c1c1c1;
|
|
|
border-radius: 3px;
|
|
border-radius: 3px;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ &::-webkit-scrollbar-thumb:hover {
|
|
|
|
|
+ background: #a8a8a8;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ::v-deep .el-tree {
|
|
|
|
|
+ background: transparent;
|
|
|
|
|
+
|
|
|
|
|
+ .el-tree-node__content {
|
|
|
|
|
+ height: 40px;
|
|
|
|
|
+ padding: 0 8px;
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ background-color: #f5f7fa;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* 核心 CSS 修复:仅选中节点高亮 */
|
|
|
|
|
+ .el-tree-node.is-current > .el-tree-node__content {
|
|
|
|
|
+ background-color: #ecf5ff;
|
|
|
|
|
+ color: #409eff;
|
|
|
|
|
+
|
|
|
|
|
+ .tree-icon {
|
|
|
|
|
+ color: #409eff !important;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .custom-tree-node {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+
|
|
|
|
|
+ .tree-label {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+
|
|
|
|
|
+ .tree-icon {
|
|
|
|
|
+ margin-right: 8px;
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ color: #409eff;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .tree-tag {
|
|
|
|
|
+ margin-right: 8px;
|
|
|
|
|
+
|
|
|
|
|
+ &.warning {
|
|
|
|
|
+ color: #e6a23c;
|
|
|
|
|
+ background: #fdf6ec;
|
|
|
|
|
+ border-color: #f5dab1;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|