装备配置率

This commit is contained in:
bb_pan 2026-01-30 15:57:02 +08:00
parent 70d537e7ad
commit a93e385a16
1 changed files with 211 additions and 203 deletions

View File

@ -2,63 +2,44 @@
<div class="app-container">
<!-- 图表卡片纯div布局保留核心ref和样式类 -->
<div class="chart-card">
<div class="chart-container" ref="chartContainer">
<div class="tabs">
<div class="tab-item" :class="{ active: activeTab == 1 }" @click="handleTab(1)">总配置率</div>
<div class="tab-item" :class="{ active: activeTab == 2 }" @click="handleTab(2)">分项配置率统计</div>
</div>
<div class="chart-container" v-show="activeTab === 1">
<div ref="totalChartRef" class="echarts echarts-box"></div>
</div>
<div class="chart-container" v-show="activeTab === 2">
<div ref="chartRef" class="echarts echarts-box"></div>
</div>
</div>
<div class="table-card">
<div class="table-header">
<el-button
type="primary"
style="float: right"
icon="el-icon-download"
@click="exportTableData"
>
<el-button type="primary" style="float: right" icon="el-icon-download" @click="exportTableData">
导出数据
</el-button>
</div>
<el-table
:data="tableData"
border
stripe
:fit="true"
class="stats-table"
v-loading="tableLoading"
>
<el-table-column label="序号" type="index" width="60" align="center"/>
<el-table-column label="公司" prop="deptName" min-width="150" align="center"/>
<el-table-column
label="线路设备配置率"
prop="lineNum"
min-width="120"
align="center"
>
<el-table :data="tableData" border stripe :fit="true" class="stats-table" v-loading="tableLoading">
<el-table-column label="序号" type="index" width="60" align="center" />
<el-table-column label="公司名称" prop="deptName" min-width="150" align="center" />
<el-table-column label="线路设备配置率" prop="lineNum" min-width="120" align="center">
<template slot-scope="scope">
<span class="link" @click="handleCellClick(scope.row.deptId, 0)">{{ scope.row.lineNum }}</span>
</template>
</el-table-column>
<el-table-column
label="电缆设备配置率"
prop="cableNum"
min-width="120"
align="center"
>
<el-table-column label="电缆设备配置率" prop="cableNum" min-width="120" align="center">
<template slot-scope="scope">
<span class="link" @click="handleCellClick(scope.row.deptId, 2)">{{ scope.row.cableNum }}</span>
</template>
</el-table-column>
<el-table-column
label="变电设备配置率"
prop="substationNum"
min-width="120"
align="center"
>
<el-table-column label="变电设备配置率" prop="substationNum" min-width="120" align="center">
<template slot-scope="scope">
<span class="link" @click="handleCellClick(scope.row.deptId, 1)">{{ scope.row.substationNum }}</span>
</template>
</el-table-column>
<el-table-column label="总配置率" prop="num" min-width="100" align="center"/>
<el-table-column label="总配置率" prop="num" min-width="100" align="center" />
</el-table>
</div>
@ -70,28 +51,21 @@
top="20px"
:close-on-click-modal="false"
>
<el-table
:data="detailTableData"
border
stripe
v-loading="detailTableLoading"
max-height="600px"
>
<el-table :data="detailTableData" border stripe v-loading="detailTableLoading" max-height="600px">
<!-- 明细表格列匹配用户提供的表格结构 -->
<el-table-column label="序号" type="index" width="60" align="center"/>
<el-table-column label="装备名称" prop="typeName" min-width="120" align="center"/>
<el-table-column label="电压等级" prop="vol" min-width="100" align="center"/>
<el-table-column label="地理特征" prop="type" min-width="100" align="center"/>
<el-table-column label="配置标准(台)" prop="configValue" min-width="100" align="center"/>
<el-table-column label="装备种类" prop="jijuType" min-width="100" align="center"/>
<el-table-column label="配置说明" prop="configDescription" min-width="120" align="center"/>
<el-table-column label="装备配置率赋值" prop="configRate" min-width="120" align="center"/>
<el-table-column label="自有装配数量" prop="ownNum" min-width="120" align="center"/>
<el-table-column label="共享装备数量" prop="shareNum" min-width="120" align="center"/>
<el-table-column label="外租装备数量" prop="rentOutNum" min-width="120" align="center"/>
<el-table-column label="装备实际配置率" prop="baseAddNum" min-width="120" align="center"/>
<el-table-column label="特殊装备配备原因" prop="remark" min-width="150" align="center"/>
<el-table-column label="序号" type="index" width="60" align="center" />
<el-table-column label="装备名称" prop="typeName" min-width="120" align="center" />
<el-table-column label="电压等级" prop="vol" min-width="100" align="center" />
<el-table-column label="地理特征" prop="type" min-width="100" align="center" />
<el-table-column label="配置标准(台)" prop="configValue" min-width="100" align="center" />
<el-table-column label="装备种类" prop="jijuType" min-width="100" align="center" />
<el-table-column label="配置说明" prop="configDescription" min-width="120" align="center" />
<el-table-column label="装备配置率赋值" prop="configRate" min-width="120" align="center" />
<el-table-column label="自有装配数量" prop="ownNum" min-width="120" align="center" />
<el-table-column label="共享装备数量" prop="shareNum" min-width="120" align="center" />
<el-table-column label="外租装备数量" prop="rentOutNum" min-width="120" align="center" />
<el-table-column label="装备实际配置率" prop="baseAddNum" min-width="120" align="center" />
<el-table-column label="特殊装备配备原因" prop="remark" min-width="150" align="center" />
</el-table>
<div slot="footer" class="dialog-footer">
<el-button @click="detailDialogVisible = false">关闭</el-button>
@ -112,117 +86,14 @@ export default {
searchForm: {
companyName: '',
voltageLevel: '',
terrainType: ''
terrainType: '',
},
tableData: [],
tableLoading: false,
tableHeight: 'auto',
activeTab: 1,
chartInstance: null,
chartOption: {
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
formatter: function(params) {
let res = params[0].name
params.forEach((item) => {
const nameMap = {
xianlu: '线路配置率',
dianlan: '电缆配置率',
biandian: '变电配置率'
}
res += `<br/>${nameMap[item.seriesName] || item.seriesName}${item.value}`
})
return res
}
},
legend: {
data: ['xianlu', 'dianlan', 'biandian'],
formatter: function(name) {
const nameMap = { xianlu: '线路', dianlan: '电缆', biandian: '变电' }
return nameMap[name] || name
},
itemGap: 20,
bottom: 15, // 1px+
left: 'center',
orient: 'horizontal'
},
// 2grid.bottom15%
grid: { left: '3%', right: '4%', bottom: '15%', containLabel: true },
xAxis: {
type: 'category',
data: [],
axisLabel: {
rotate: 0,
fontSize: 12,
interval: 0,
width: 80,
lineHeight: 20,
align: 'center',
formatter: function(value) {
let str = ''
for (let i = 0; i < value.length; i++) {
str += value[i]
if ((i + 1) % 6 === 0) str += '\n'
}
return str
}
}
},
yAxis: { type: 'value', axisLabel: { formatter: '{value}' } },
series: [
{
name: 'xianlu',
type: 'bar',
data: [],
barBorderRadius: [10, 10, 0, 0], //
itemStyle: {
color: {
type: 'linear',
x: 0, y: 0,
x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: '#46A8FF' },
{ offset: 1, color: '#7BC2FF' }
]
}
}
},
{
name: 'dianlan',
type: 'bar',
data: [],
barBorderRadius: [10, 10, 0, 0], //
itemStyle: {
color: {
type: 'linear',
x: 0, y: 0,
x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: '#5EDDCA' },
{ offset: 1, color: '#32E1C6' }
]
}
}
},
{
name: 'biandian',
type: 'bar',
data: [],
barBorderRadius: [10, 10, 0, 0], //
itemStyle: {
color: {
type: 'linear',
x: 0, y: 0,
x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: '#fdbe56' },
{ offset: 1, color: '#FFC468' }
]
}
}
}
]
},
resizeTimer: null,
//
detailDialogVisible: false,
@ -230,15 +101,24 @@ export default {
detailTableLoading: false,
//
currentClickRow: null,
currentClickType: '' // line(线)/cable()/substation()
currentClickType: '', // line(线)/cable()/substation()
}
},
mounted() {
this.$nextTick(async() => {
this.$nextTick(async () => {
await this.initPage()
})
},
methods: {
handleTab(tab) {
if (this.activeTab === tab) return
this.activeTab = tab
this.$nextTick(() => {
this.initChart()
this.updateChartData(this.tableData)
})
},
//
async initPage() {
this.tableLoading = true
@ -262,58 +142,169 @@ export default {
// EChartsDOM+
initChart() {
const chartDom = this.$refs.chartRef
if (!chartDom || this.chartInstance) return
const clientWidth = chartDom.clientWidth || 600
const clientHeight = chartDom.clientHeight || 300
if (clientWidth === 0 || clientHeight === 0) {
chartDom.style.width = '100%'
chartDom.style.height = '450px'
}
if (this.chartInstance) {
this.chartInstance.dispose()
this.chartInstance = null
}
this.chartInstance = echarts.init(chartDom)
this.chartInstance.setOption(this.chartOption, true)
const dom = this.activeTab === 1 ? this.$refs.totalChartRef : this.$refs.chartRef
if (!dom) return
this.chartInstance = echarts.init(dom)
this.chartInstance.setOption(this.activeTab === 1 ? this.getTotalOption() : this.getSubOption(), true)
},
//
updateChartData(data) {
if (!this.chartInstance || !Array.isArray(data) || data.length === 0) return
console.log('🚀 ~ data:', data)
if (!this.chartInstance || !data.length) return
const xAxisData = []
const xianluData = []
const dianlanData = []
const biandianData = []
const xAxis = []
const total = []
const xianlu = []
const dianlan = []
const biandian = []
data.forEach((item) => {
xAxisData.push(item.deptName || '')
xianluData.push(item.lineNum || 0)
dianlanData.push(item.cableNum || 0)
biandianData.push(item.substationNum || 0)
xAxis.push(item.deptName)
total.push(item.num)
xianlu.push(item.lineNum)
dianlan.push(item.cableNum)
biandian.push(item.substationNum)
})
const allData = [...xianluData, ...dianlanData, ...biandianData]
const maxValue = Math.max(...allData)
const dynamicYmax = Math.ceil(maxValue * 1.1)
if (this.activeTab === 1) {
this.chartInstance.setOption({
xAxis: { data: xAxisData },
yAxis: { max: dynamicYmax },
series: [
{ name: 'xianlu', data: xianluData },
{ name: 'dianlan', data: dianlanData },
{ name: 'biandian', data: biandianData }
]
xAxis: { data: xAxis },
series: [{ name: '总配置率', data: total }],
})
} else {
this.chartInstance.setOption({
xAxis: { data: xAxis },
series: [
{ name: '线路配置率', data: xianlu },
{ name: '电缆配置率', data: dianlan },
{ name: '变电配置率', data: biandian },
],
})
}
this.chartInstance.resize()
},
/** Tab1 配置 */
getTotalOption() {
return {
tooltip: { trigger: 'axis' },
grid: { left: '3%', right: '4%', bottom: '15%', containLabel: true },
xAxis: {
type: 'category',
data: [],
axisLabel: {
interval: 0, //
formatter(value) {
const max = 6 // 6
let res = ''
for (let i = 0; i < value.length; i++) {
res += value[i]
if ((i + 1) % max === 0 && i !== value.length - 1) {
res += '\n'
}
}
return res
},
},
},
yAxis: { type: 'value' },
series: [
{
type: 'bar',
barWidth: 18,
itemStyle: {
borderRadius: [50, 50, 0, 0],
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: '#5EDDCA' },
{ offset: 1, color: '#32E1C6' },
],
},
},
data: [],
},
],
}
},
/** Tab2 配置 */
getSubOption() {
return {
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
legend: {
right: 20,
top: 10,
data: ['xianlu', 'dianlan', 'biandian'],
formatter(name) {
return { xianlu: '线路', dianlan: '电缆', biandian: '变电' }[name]
},
},
grid: { left: '3%', right: '4%', bottom: '15%', containLabel: true },
xAxis: {
type: 'category',
data: [],
axisLabel: {
interval: 0, //
formatter(value) {
const max = 6 // 6
let res = ''
for (let i = 0; i < value.length; i++) {
res += value[i]
if ((i + 1) % max === 0 && i !== value.length - 1) {
res += '\n'
}
}
return res
},
},
},
yAxis: { type: 'value' },
series: [
this.barSeries('xianlu', ['#46A8FF', '#7BC2FF']),
this.barSeries('dianlan', ['#5EDDCA', '#32E1C6']),
this.barSeries('biandian', ['#FDBE56', '#FFC468']),
],
}
},
barSeries(name, colors) {
return {
name,
type: 'bar',
barWidth: 18,
itemStyle: {
borderRadius: [50, 50, 0, 0],
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: colors[0] },
{ offset: 1, color: colors[1] },
],
},
},
data: [],
}
},
// loading
async exportTableData() {
this.$loading({ text: '正在导出,请稍候...' })
@ -344,7 +335,7 @@ export default {
// ++
const params = {
deptId: deptId,
configType: configType
configType: configType,
}
const res = await getConfigurationDetails(params)
if (res.code === 200) {
@ -357,8 +348,8 @@ export default {
} finally {
this.detailTableLoading = false
}
}
}
},
},
}
</script>
@ -431,11 +422,28 @@ export default {
}
.link {
color: #2CBAB2;
color: #2cbab2;
cursor: pointer;
}
.link:hover {
color: #23b8b1;
}
.tabs {
display: flex;
align-items: center;
.tab-item {
line-height: 24px;
margin-right: 16px;
padding: 6px 0;
font-size: 16px;
font-weight: 400;
cursor: pointer;
&.active {
color: #2cbab2;
border-bottom: 2px solid #2cbab2;
}
}
}
</style>