|
|
|
@ -5,7 +5,7 @@ |
|
|
|
<div class="head-title"> |
|
|
|
<span>曹妃甸港区船舶岸电监管平台</span> |
|
|
|
</div> |
|
|
|
<el-button class="view-btn" size="small" type="success" @click="mapComponentRef.switchView('overview')" |
|
|
|
<el-button class="view-btn" size="small" type="success" @click="handleOverviewClick" |
|
|
|
style="margin-right: 10px;">概览视角</el-button> |
|
|
|
|
|
|
|
<div class="head-group"> |
|
|
|
@ -19,23 +19,18 @@ |
|
|
|
|
|
|
|
<!-- 港区概览 --> |
|
|
|
<template v-if="activeHeadGroup === 0"> |
|
|
|
<PortOverview :ship-status-data="shipStatusData" :selected-ship="selectedShip" @select-ship="handleSwitch" |
|
|
|
:get-status-class="getStatusClass" :get-shore-power-status-text="getShorePowerStatusText" /> |
|
|
|
<PortOverview :ship-status-data="shipStatusData" :selected-ship="selectedShip" @item-click="handleSwitch" /> |
|
|
|
</template> |
|
|
|
|
|
|
|
<!-- 港口岸电使用情况 --> |
|
|
|
<template v-if="activeHeadGroup === 1"> |
|
|
|
<ShorePowerUsage :total-power="totalPower" :fuel-reduction="fuelReduction" :co2-reduction="co2Reduction" |
|
|
|
:pm25-reduction="pm25Reduction" :nox-reduction="noxReduction" :so2-reduction="so2Reduction" |
|
|
|
:fuel-reduction-data="fuelReductionData" :co2-reduction-data="co2ReductionData" |
|
|
|
:pm25-reduction-data="pm25ReductionData" :nox-reduction-data="noxReductionData" |
|
|
|
:so2-reduction-data="so2ReductionData" /> |
|
|
|
:pm25-reduction="pm25Reduction" :nox-reduction="noxReduction" :so2-reduction="so2Reduction" /> |
|
|
|
</template> |
|
|
|
|
|
|
|
<!-- 港口企业岸电使用 --> |
|
|
|
<template v-if="activeHeadGroup === 2"> |
|
|
|
<CompanyShorePower :company-comparison-data="companyComparisonData" :selected-company="selectedCompany" |
|
|
|
:pie-chart-data="pieChartData" @update:selected-company="selectedCompany = $event" /> |
|
|
|
<CompanyShorePower :companyComparisonData="companyComparisonData" /> |
|
|
|
</template> |
|
|
|
|
|
|
|
<!-- 船舶岸电使用情况 --> |
|
|
|
@ -44,7 +39,58 @@ |
|
|
|
:no-shore-power-ships="noShorePowerShips" :ship-data="shipData" /> |
|
|
|
</template> |
|
|
|
|
|
|
|
<template v-if="activeHeadGroup === 4"> |
|
|
|
<div class="right" style="width: 500px;"> |
|
|
|
<div class="card digital-twin-card--deep-blue"> |
|
|
|
<div class="card-title"> |
|
|
|
<div class="vertical-line"></div> |
|
|
|
<img src="@/assets/svgs/data.svg" class="title-icon" /> |
|
|
|
<span class="title-text">岸电箱详情</span> |
|
|
|
<el-button class="close-btn" size="small" @click="closeElectricalBoxInfo" |
|
|
|
style="margin-left: auto;">×</el-button> |
|
|
|
</div> |
|
|
|
<div class="card-content"> |
|
|
|
<div class="ship-detail"> |
|
|
|
<div class="detail-item"> |
|
|
|
<span class="label">名称:</span> |
|
|
|
<span class="value">{{ selectedElectricalBox?.name || '无' }}</span> |
|
|
|
</div> |
|
|
|
<div class="detail-item"> |
|
|
|
<span class="label">位置:</span> |
|
|
|
<span class="value">{{ selectedElectricalBox?.location || '曹妃甸港区华能码头' }}</span> |
|
|
|
</div> |
|
|
|
<div class="detail-item"> |
|
|
|
<span class="label">状态:</span> |
|
|
|
<span class="value">{{ selectedElectricalBox?.status || '在线' }}</span> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 当前使用数据 --> |
|
|
|
<div class="section-title">当前使用数据</div> |
|
|
|
<div class="detail-item"> |
|
|
|
<span class="label">当前使用功率:</span> |
|
|
|
<span class="value">{{ selectedElectricalBox?.currentPower || '120' }} kW</span> |
|
|
|
</div> |
|
|
|
<div class="detail-item"> |
|
|
|
<span class="label">当前使用电量:</span> |
|
|
|
<span class="value">{{ selectedElectricalBox?.currentEnergy || '45.5' }} kWh</span> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 累计历史数据 --> |
|
|
|
<div class="section-title">累计历史数据</div> |
|
|
|
<div class="detail-item"> |
|
|
|
<span class="label">累计历史用电:</span> |
|
|
|
<span class="value">{{ selectedElectricalBox?.totalEnergy || '1250.8' }} kWh</span> |
|
|
|
</div> |
|
|
|
<div class="detail-item"> |
|
|
|
<span class="label">累计服务次数:</span> |
|
|
|
<span class="value">{{ selectedElectricalBox?.serviceCount || '86' }} 次</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
</template> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
|
|
|
|
@ -73,7 +119,8 @@ const activeHeadGroup = ref<number>(-1) |
|
|
|
interface PublicMapComponentsType { |
|
|
|
switchView: (viewName: string) => void |
|
|
|
dataWithModels: any[] |
|
|
|
switchModelView: () => void |
|
|
|
switchModelView: (data: any) => void |
|
|
|
setElectricalBoxClickCallback: (callback: (data: any) => void) => void |
|
|
|
} |
|
|
|
|
|
|
|
const mapComponentRef = ref<PublicMapComponentsType | null>(null) |
|
|
|
@ -94,17 +141,17 @@ const selectHeadGroup = async (value: number) => { |
|
|
|
const currentTime = ref<string>(dayjs().format('YYYY-MM-DD HH:mm:ss')) |
|
|
|
|
|
|
|
// 总览数据 |
|
|
|
const totalPower = ref<string>('857525.45') |
|
|
|
const fuelReduction = ref<string>('108.04') |
|
|
|
const co2Reduction = ref<string>('574542.06') |
|
|
|
const pm25Reduction = ref<string>('1251.99') |
|
|
|
const noxReduction = ref<string>('15521.21') |
|
|
|
const so2Reduction = ref<string>('9004.03') |
|
|
|
const totalPower = ref<number>(857525.45) |
|
|
|
const fuelReduction = ref<number>(108.04) |
|
|
|
const co2Reduction = ref<number>(574542.06) |
|
|
|
const pm25Reduction = ref<number>(1251.99) |
|
|
|
const noxReduction = ref<number>(15521.21) |
|
|
|
const so2Reduction = ref<number>(9004.03) |
|
|
|
|
|
|
|
// 船舶岸电使用情况数据 |
|
|
|
const berthingShips = ref<string>('13') |
|
|
|
const shorePowerShips = ref<string>('3') |
|
|
|
const noShorePowerShips = ref<string>('10') |
|
|
|
const berthingShips = ref<number>(13) |
|
|
|
const shorePowerShips = ref<number>(3) |
|
|
|
const noShorePowerShips = ref<number>(10) |
|
|
|
|
|
|
|
// 船舶数据列表 |
|
|
|
const shipData = ref([ |
|
|
|
@ -152,35 +199,44 @@ const updateTime = () => { |
|
|
|
} |
|
|
|
|
|
|
|
const selectedShip = ref(null) |
|
|
|
const selectedElectricalBox = ref(null) |
|
|
|
|
|
|
|
/* 回到初始视角 */ |
|
|
|
const handleOverviewClick = () => { |
|
|
|
mapComponentRef.value?.switchView('overview') |
|
|
|
} |
|
|
|
|
|
|
|
/* 切换至模型视角 */ |
|
|
|
const handleSwitch = (item) => { |
|
|
|
console.log(item) |
|
|
|
selectedShip.value = item |
|
|
|
mapComponentRef.value?.switchModelView(item.modelInstance) |
|
|
|
} |
|
|
|
|
|
|
|
const shorePowerStatusMap = { |
|
|
|
1: '待靠泊', |
|
|
|
2: '靠泊中', |
|
|
|
3: '岸电接入中', |
|
|
|
4: '用电中', |
|
|
|
5: '岸电卸载中', |
|
|
|
6: '岸电卸载完成', |
|
|
|
7: '离泊', |
|
|
|
9: '未使用岸电' |
|
|
|
} |
|
|
|
// 处理岸电箱点击事件 |
|
|
|
const handleElectricalBoxClick = (data) => { |
|
|
|
activeHeadGroup.value = 4 |
|
|
|
console.log('岸电箱被点击:', data); |
|
|
|
// 设置选中的岸电箱数据 |
|
|
|
selectedElectricalBox.value = data; |
|
|
|
// 这里可以添加更多的处理逻辑,比如切换到特定的视图等 |
|
|
|
}; |
|
|
|
|
|
|
|
// 状态转换函数 |
|
|
|
const getShorePowerStatusText = (status: number | string) => { |
|
|
|
const statusNum = Number(status); |
|
|
|
console.log(status) |
|
|
|
return shorePowerStatusMap[statusNum] || status; |
|
|
|
} |
|
|
|
// 关闭岸电箱详情面板 |
|
|
|
const closeElectricalBoxInfo = () => { |
|
|
|
activeHeadGroup.value = -1; |
|
|
|
selectedElectricalBox.value = null; |
|
|
|
}; |
|
|
|
|
|
|
|
// 启动定时器更新时间 |
|
|
|
let timer: NodeJS.Timeout |
|
|
|
onMounted(() => { |
|
|
|
timer = setInterval(updateTime, 1000) |
|
|
|
|
|
|
|
// 设置岸电箱点击回调 |
|
|
|
if (mapComponentRef.value) { |
|
|
|
mapComponentRef.value.setElectricalBoxClickCallback(handleElectricalBoxClick); |
|
|
|
} |
|
|
|
}) |
|
|
|
|
|
|
|
// 组件卸载时清除所有资源 |
|
|
|
@ -348,102 +404,6 @@ watch( |
|
|
|
{ deep: true } |
|
|
|
) |
|
|
|
|
|
|
|
// 模拟折线图数据 |
|
|
|
const lineChartData = ref([ |
|
|
|
{ name: '1月', value: 120 }, |
|
|
|
{ name: '2月', value: 132 }, |
|
|
|
{ name: '3月', value: 101 }, |
|
|
|
{ name: '4月', value: 134 }, |
|
|
|
{ name: '5月', value: 90 }, |
|
|
|
{ name: '6月', value: 230 }, |
|
|
|
{ name: '7月', value: 210 }, |
|
|
|
{ name: '8月', value: 150 }, |
|
|
|
{ name: '9月', value: 180 }, |
|
|
|
{ name: '10月', value: 200 }, |
|
|
|
{ name: '11月', value: 190 }, |
|
|
|
{ name: '12月', value: 220 } |
|
|
|
]) |
|
|
|
|
|
|
|
// 减少燃油(吨)数据 |
|
|
|
const fuelReductionData = ref([ |
|
|
|
{ name: '1月', value: 80 }, |
|
|
|
{ name: '2月', value: 85 }, |
|
|
|
{ name: '3月', value: 70 }, |
|
|
|
{ name: '4月', value: 90 }, |
|
|
|
{ name: '5月', value: 60 }, |
|
|
|
{ name: '6月', value: 150 }, |
|
|
|
{ name: '7月', value: 140 }, |
|
|
|
{ name: '8月', value: 100 }, |
|
|
|
{ name: '9月', value: 120 }, |
|
|
|
{ name: '10月', value: 130 }, |
|
|
|
{ name: '11月', value: 125 }, |
|
|
|
{ name: '12月', value: 145 } |
|
|
|
]) |
|
|
|
|
|
|
|
// 减少二氧化碳排放(千克)数据 |
|
|
|
const co2ReductionData = ref([ |
|
|
|
{ name: '1月', value: 200 }, |
|
|
|
{ name: '2月', value: 220 }, |
|
|
|
{ name: '3月', value: 180 }, |
|
|
|
{ name: '4月', value: 240 }, |
|
|
|
{ name: '5月', value: 160 }, |
|
|
|
{ name: '6月', value: 380 }, |
|
|
|
{ name: '7月', value: 350 }, |
|
|
|
{ name: '8月', value: 260 }, |
|
|
|
{ name: '9月', value: 300 }, |
|
|
|
{ name: '10月', value: 320 }, |
|
|
|
{ name: '11月', value: 310 }, |
|
|
|
{ name: '12月', value: 360 } |
|
|
|
]) |
|
|
|
|
|
|
|
// 减少PM2.5排放(千克)数据 |
|
|
|
const pm25ReductionData = ref([ |
|
|
|
{ name: '1月', value: 15 }, |
|
|
|
{ name: '2月', value: 18 }, |
|
|
|
{ name: '3月', value: 12 }, |
|
|
|
{ name: '4月', value: 20 }, |
|
|
|
{ name: '5月', value: 10 }, |
|
|
|
{ name: '6月', value: 35 }, |
|
|
|
{ name: '7月', value: 32 }, |
|
|
|
{ name: '8月', value: 22 }, |
|
|
|
{ name: '9月', value: 28 }, |
|
|
|
{ name: '10月', value: 30 }, |
|
|
|
{ name: '11月', value: 29 }, |
|
|
|
{ name: '12月', value: 33 } |
|
|
|
]) |
|
|
|
|
|
|
|
// 减少氮氧化物(千克)数据 |
|
|
|
const noxReductionData = ref([ |
|
|
|
{ name: '1月', value: 25 }, |
|
|
|
{ name: '2月', value: 28 }, |
|
|
|
{ name: '3月', value: 22 }, |
|
|
|
{ name: '4月', value: 30 }, |
|
|
|
{ name: '5月', value: 18 }, |
|
|
|
{ name: '6月', value: 45 }, |
|
|
|
{ name: '7月', value: 42 }, |
|
|
|
{ name: '8月', value: 32 }, |
|
|
|
{ name: '9月', value: 38 }, |
|
|
|
{ name: '10月', value: 40 }, |
|
|
|
{ name: '11月', value: 39 }, |
|
|
|
{ name: '12月', value: 43 } |
|
|
|
]) |
|
|
|
|
|
|
|
// 减少二氧化硫(千克)数据 |
|
|
|
const so2ReductionData = ref([ |
|
|
|
{ name: '1月', value: 20 }, |
|
|
|
{ name: '2月', value: 22 }, |
|
|
|
{ name: '3月', value: 18 }, |
|
|
|
{ name: '4月', value: 25 }, |
|
|
|
{ name: '5月', value: 15 }, |
|
|
|
{ name: '6月', value: 38 }, |
|
|
|
{ name: '7月', value: 35 }, |
|
|
|
{ name: '8月', value: 28 }, |
|
|
|
{ name: '9月', value: 32 }, |
|
|
|
{ name: '10月', value: 34 }, |
|
|
|
{ name: '11月', value: 33 }, |
|
|
|
{ name: '12月', value: 37 } |
|
|
|
]) |
|
|
|
|
|
|
|
// 三个公司的岸电使用对比数据 |
|
|
|
const companyComparisonData = ref([ |
|
|
|
{ |
|
|
|
@ -493,16 +453,6 @@ const selectedCompany = ref('华能码头') |
|
|
|
// 饼图数据 |
|
|
|
const pieChartData = ref<Array<{ name: string; value: number }>>([]) |
|
|
|
|
|
|
|
// 处理公司选择变化 |
|
|
|
const handleCompanyChange = (companyName: string) => { |
|
|
|
const selectedCompanyData = companyComparisonData.value.find(company => company.name === companyName) |
|
|
|
if (selectedCompanyData && selectedCompanyData.children) { |
|
|
|
pieChartData.value = selectedCompanyData.children |
|
|
|
} else { |
|
|
|
pieChartData.value = [] |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 初始化饼图数据 |
|
|
|
onMounted(async () => { |
|
|
|
// 默认选中华能码头的数据 |
|
|
|
@ -561,29 +511,6 @@ const shipStatusData = computed(() => { |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
// 获取状态对应的样式类 |
|
|
|
const getStatusClass = (status: string) => { |
|
|
|
switch (status) { |
|
|
|
case '正常': |
|
|
|
return 'status-normal' |
|
|
|
case '空闲': |
|
|
|
return 'status-idle' |
|
|
|
case '故障': |
|
|
|
return 'status-fault' |
|
|
|
case '异常': |
|
|
|
return 'status-abnormal' |
|
|
|
case '维修中': |
|
|
|
return 'status-maintenance' |
|
|
|
case '岸电使用中': |
|
|
|
return 'status-shorepower' |
|
|
|
// case '岸电故障': |
|
|
|
// return 'status-fault' |
|
|
|
default: |
|
|
|
return 'status-default' |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
</script> |
|
|
|
<style lang="scss"> |
|
|
|
.cesium-viewer-bottom { |
|
|
|
@ -699,36 +626,6 @@ const getStatusClass = (status: string) => { |
|
|
|
width: 100%; |
|
|
|
// padding: 10px; |
|
|
|
} |
|
|
|
|
|
|
|
.overview-grid { |
|
|
|
display: grid; |
|
|
|
grid-template-columns: 1fr 1fr; |
|
|
|
gap: 6px; |
|
|
|
padding: 2px; |
|
|
|
} |
|
|
|
|
|
|
|
.overview-item { |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
align-items: center; |
|
|
|
padding: 4px; |
|
|
|
background-color: rgba(0, 0, 0, 0.2); |
|
|
|
border-radius: 8px; |
|
|
|
} |
|
|
|
|
|
|
|
.overview-value { |
|
|
|
font-size: 18px; |
|
|
|
font-weight: bold; |
|
|
|
color: #1296db; |
|
|
|
text-shadow: 0 0 5px rgba(0, 0, 0, 0.5); |
|
|
|
margin-bottom: 5px; |
|
|
|
} |
|
|
|
|
|
|
|
.overview-label { |
|
|
|
text-align: center; |
|
|
|
font-size: 12px; |
|
|
|
color: #ccc; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* 船舶数据表格样式 */ |
|
|
|
@ -805,23 +702,6 @@ const getStatusClass = (status: string) => { |
|
|
|
width: 35%; |
|
|
|
} |
|
|
|
|
|
|
|
/* 状态样式 */ |
|
|
|
.status-using { |
|
|
|
color: #00ff00; |
|
|
|
} |
|
|
|
|
|
|
|
.status-no-equipment { |
|
|
|
color: #ff6600; |
|
|
|
} |
|
|
|
|
|
|
|
.status-damaged { |
|
|
|
color: #ff3300; |
|
|
|
} |
|
|
|
|
|
|
|
.status-cable { |
|
|
|
color: #ffcc00; |
|
|
|
} |
|
|
|
|
|
|
|
.head { |
|
|
|
display: flex; |
|
|
|
justify-content: space-between; |
|
|
|
@ -1111,4 +991,83 @@ const getStatusClass = (status: string) => { |
|
|
|
opacity: 0; |
|
|
|
transform: translateX(20px); |
|
|
|
} |
|
|
|
|
|
|
|
.overview-grid { |
|
|
|
display: grid; |
|
|
|
grid-template-columns: 1fr 1fr; |
|
|
|
gap: 6px; |
|
|
|
padding: 2px; |
|
|
|
height: 100%; |
|
|
|
} |
|
|
|
|
|
|
|
.overview-item { |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
padding: 4px; |
|
|
|
background-color: rgba(0, 0, 0, 0.2); |
|
|
|
border-radius: 8px; |
|
|
|
} |
|
|
|
|
|
|
|
.overview-value { |
|
|
|
font-size: 18px; |
|
|
|
font-weight: bold; |
|
|
|
color: #1296db; |
|
|
|
text-shadow: 0 0 5px rgba(0, 0, 0, 0.5); |
|
|
|
margin-bottom: 5px; |
|
|
|
} |
|
|
|
|
|
|
|
.overview-label { |
|
|
|
text-align: center; |
|
|
|
font-size: 12px; |
|
|
|
color: #ccc; |
|
|
|
} |
|
|
|
|
|
|
|
/* 状态样式 */ |
|
|
|
.status-using { |
|
|
|
color: #00ff00; |
|
|
|
} |
|
|
|
|
|
|
|
.status-no-equipment { |
|
|
|
color: #ff6600; |
|
|
|
} |
|
|
|
|
|
|
|
.status-damaged { |
|
|
|
color: #ff3300; |
|
|
|
} |
|
|
|
|
|
|
|
.status-cable { |
|
|
|
color: #ffcc00; |
|
|
|
} |
|
|
|
|
|
|
|
/* 岸电箱详情样式 */ |
|
|
|
.section-title { |
|
|
|
font-size: 18px; |
|
|
|
font-weight: bold; |
|
|
|
color: #1296db; |
|
|
|
margin: 15px 0 8px 0; |
|
|
|
padding-bottom: 5px; |
|
|
|
border-bottom: 1px solid rgba(18, 150, 219, 0.3); |
|
|
|
} |
|
|
|
|
|
|
|
.detail-item { |
|
|
|
display: flex; |
|
|
|
justify-content: space-between; |
|
|
|
margin-bottom: 10px; |
|
|
|
padding: 8px 12px; |
|
|
|
border-radius: 6px; |
|
|
|
background-color: rgba(0, 0, 0, 0.15); |
|
|
|
} |
|
|
|
|
|
|
|
.label { |
|
|
|
color: #ddd; |
|
|
|
font-size: 16px; |
|
|
|
} |
|
|
|
|
|
|
|
.value { |
|
|
|
color: #fff; |
|
|
|
font-size: 16px; |
|
|
|
font-weight: 600; |
|
|
|
} |
|
|
|
</style> |
|
|
|
|