Browse Source

update

feature
jiangAB 1 week ago
parent
commit
7ceb1c731c
  1. 92
      public/map/components/ShorePowerUsageRate.vue
  2. 81
      public/map/components/ShorePowerUsageSingleData.vue
  3. 6
      public/map/components/ShowData.vue
  4. 16
      public/map/components/cesiumMap.vue
  5. 24
      public/map/components/charts/ComparisonBarChart.vue
  6. 25
      public/map/components/dictionaryTable.ts
  7. 276
      public/map/index.vue
  8. 5
      src/types/shorepower.d.ts

92
public/map/components/ShorePowerUsageRate.vue

@ -40,17 +40,17 @@
<div v-if="timeRange === 'year'" class="card-content"> <div v-if="timeRange === 'year'" class="card-content">
<ComparisonBarChart :chartData="getYearlyData" title="年度用电量对比" yAxisName="用电量(kWh)" currentColor="#36A2EB" <ComparisonBarChart :chartData="getYearlyData" title="年度用电量对比" yAxisName="用电量(kWh)" currentColor="#36A2EB"
previousColor="#FF6384" /> previousColor="#FF6384" chartType="percentage" />
</div> </div>
<div v-if="timeRange === 'month'" class="card-content"> <div v-if="timeRange === 'month'" class="card-content">
<ComparisonBarChart :chartData="getMonthlyComparisonData" <ComparisonBarChart :chartData="getMonthlyComparisonData"
:title="comparisonType === 'yearOnYear' ? '月度用电量同比对比' : '月度用电量环比对比'" yAxisName="用电量(kWh)" :title="comparisonType === 'yearOnYear' ? '月度用电量同比对比' : '月度用电量环比对比'" yAxisName="用电量(kWh)"
currentColor="#36A2EB" previousColor="#FF6384" /> currentColor="#36A2EB" previousColor="#FF6384" chartType="percentage" />
</div> </div>
<div class="card-content" v-if="timeRange === 'day'"> <div class="card-content" v-if="timeRange === 'day'">
<ComparisonBarChart :chartData="getDailyComparisonData" <ComparisonBarChart :chartData="getDailyComparisonData"
:title="comparisonType === 'yearOnYear' ? '日用电量同比对比' : '日用电量环比对比'" yAxisName="用电量(kWh)" currentColor="#36A2EB" :title="comparisonType === 'yearOnYear' ? '日用电量同比对比' : '日用电量环比对比'" yAxisName="用电量(kWh)" currentColor="#36A2EB"
previousColor="#FF6384" /> previousColor="#FF6384" chartType="percentage" />
</div> </div>
</div> </div>
</div> </div>
@ -60,14 +60,14 @@
import { ref, computed, onMounted, onBeforeUnmount } from 'vue' import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
import { MapApi } from "@/api/shorepower/map"; import { MapApi } from "@/api/shorepower/map";
import ComparisonBarChart from './charts/ComparisonBarChart.vue' import ComparisonBarChart from './charts/ComparisonBarChart.vue'
import { ComparativeData, RealtimeDeviceData } from '@/types/shorepower'; import { ComparativeData, MetricData, RealtimeDeviceData } from '@/types/shorepower';
interface Props { interface Props {
// realtimeDeviceData: RealtimeDeviceData[]; // realtimeDeviceData: RealtimeDeviceData[];
// activeHeadGroup?: number; // activeHeadGroup?: number;
handleClose: () => void; handleClose: () => void;
realtimeDeviceDataTime: string; realtimeDeviceDataTime: string;
// comparativeData: ComparativeData; comparativeData: MetricData;
initialTimeRange?: 'realtime' | 'day' | 'month' | 'year'; initialTimeRange?: 'realtime' | 'day' | 'month' | 'year';
} }
@ -125,75 +125,43 @@ export interface deviceData {
const getYearlyData = computed(() => { const getYearlyData = computed(() => {
return [{ return [{
name: '本期上期对比', name: '本期上期对比',
growthRate: .11, growthRate: props.comparativeData.year.growthRate,
currentValue: 22, currentValue: convertPowerUsage(props.comparativeData.year.current.value, selectedCard.value),
previousValue: 33, previousValue: convertPowerUsage(props.comparativeData.year.previous.value, selectedCard.value),
currentPeriod: '2024', currentPeriod: props.comparativeData.year.current.period,
previousPeriod: '2025', previousPeriod: props.comparativeData.year.previous.period,
}] }]
}) })
// - //
const getDailyComparisonData = computed(() => { const getDailyComparisonData = computed(() => {
// 使 const comparisonData = comparisonType.value === 'yearOnYear'
const mockDailyData = { ? props.comparativeData.dayYearOnYear
chain: { // : props.comparativeData.day;
name: '本期上期对比',
growthRate: .52, // 5.2%
currentValue: 85.5, // 85.5%
previousValue: 81.3, // 81.3%
currentPeriod: new Date().toISOString().split('T')[0], //
previousPeriod: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString().split('T')[0], //
},
yearOnYear: { //
name: '本期去年同期对比',
growthRate: .128, // 12.8%
currentValue: 85.5, // 85.5%
previousValue: 75.8, // 75.8%
currentPeriod: new Date().toISOString().split('T')[0], //
previousPeriod: new Date(Date.now() - 365 * 24 * 60 * 60 * 1000).toISOString().split('T')[0], //
}
};
return [{ return [{
name: mockDailyData[comparisonType.value].name, name: comparisonType.value === 'yearOnYear' ? '本期去年同期对比' : '本期上期对比',
growthRate: mockDailyData[comparisonType.value].growthRate, growthRate: comparisonData.growthRate,
currentValue: convertPowerUsage(mockDailyData[comparisonType.value].currentValue, selectedCard.value), currentValue: convertPowerUsage(comparisonData.current.value, selectedCard.value),
previousValue: convertPowerUsage(mockDailyData[comparisonType.value].previousValue, selectedCard.value), previousValue: convertPowerUsage(comparisonData.previous.value, selectedCard.value),
currentPeriod: mockDailyData[comparisonType.value].currentPeriod, currentPeriod: comparisonData.current.period,
previousPeriod: mockDailyData[comparisonType.value].previousPeriod, previousPeriod: comparisonData.previous.period,
}] }]
}) })
// - //
const getMonthlyComparisonData = computed(() => { const getMonthlyComparisonData = computed(() => {
// 使 const comparisonData = comparisonType.value === 'yearOnYear'
const mockMonthlyData = { ? props.comparativeData.monthYearOnYear
chain: { // : props.comparativeData.month;
name: '本期上期对比',
growthRate: .83, // 8.3%
currentValue: 87.2, // 87.2%
previousValue: 80.5, // 80.5%
currentPeriod: new Date().toISOString().slice(0, 7), // YYYY-MM
previousPeriod: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString().slice(0, 7), // YYYY-MM
},
yearOnYear: { //
name: '本期去年同期对比',
growthRate: .156, // 15.6%
currentValue: 87.2, // 87.2%
previousValue: 75.4, // 75.4%
currentPeriod: new Date().toISOString().slice(0, 7), // YYYY-MM
previousPeriod: new Date(Date.now() - 365 * 24 * 60 * 60 * 1000).toISOString().slice(0, 7), //
}
};
return [{ return [{
name: mockMonthlyData[comparisonType.value].name, name: comparisonType.value === 'yearOnYear' ? '本期去年同期对比' : '本期上期对比',
growthRate: mockMonthlyData[comparisonType.value].growthRate, growthRate: comparisonData.growthRate,
currentValue: convertPowerUsage(mockMonthlyData[comparisonType.value].currentValue, selectedCard.value), currentValue: convertPowerUsage(comparisonData.current.value, selectedCard.value),
previousValue: convertPowerUsage(mockMonthlyData[comparisonType.value].previousValue, selectedCard.value), previousValue: convertPowerUsage(comparisonData.previous.value, selectedCard.value),
currentPeriod: mockMonthlyData[comparisonType.value].currentPeriod, currentPeriod: comparisonData.current.period,
previousPeriod: mockMonthlyData[comparisonType.value].previousPeriod, previousPeriod: comparisonData.previous.period,
}] }]
}) })

81
public/map/components/ShorePowerUsageSingleData.vue

@ -219,55 +219,6 @@
</div> </div>
</div> </div>
</div> </div>
<!-- <div class="one-row">
<div v-for="card in cards.filter(c => c.id !== selectedCard)" :key="card.id"
class="card digital-twin-card--deep-blue" @click="handleSelectCard(card.id)">
<div style="display: flex; align-items: center; justify-content: space-between;">
<div class="card-title">
<div class="vertical-line"></div>
<img src="@/assets/svgs/data.svg" class="title-icon" />
<span class="title-text">{{ card.title }}</span>
</div>
<div v-if="card.type === 'overview'" class="time-range-selector">
</div>
<div v-if="card.type === 'chart'" class="show-value">
<span class="show-value-label">{{timeRangeOptions.find(option => option.value === timeRange)?.label ||
''}}:</span>
<div class="show-value-value">{{ chartData[timeRange][card.value] }}</div>
</div>
</div>
<div class="card-content">
<div v-if="card.type === 'overview'" class="overview-grid">
<div class="overview-item">
<div class="overview-value">{{ historyData.totalPower }}</div>
<div class="overview-label">区间用电(千瓦时)</div>
</div>
<div class="overview-item">
<div class="overview-value">{{ historyData.fuel }}</div>
<div class="overview-label">减少燃油()</div>
</div>
<div class="overview-item">
<div class="overview-value">{{ historyData.co2 }}</div>
<div class="overview-label">减少二氧化碳排放(千克)</div>
</div>
<div class="overview-item">
<div class="overview-value">{{ historyData.pm25 }}</div>
<div class="overview-label">减少PM2.5排放(千克)</div>
</div>
<div class="overview-item">
<div class="overview-value">{{ historyData.nox }}</div>
<div class="overview-label">减少氮氧化物(千克)</div>
</div>
<div class="overview-item">
<div class="overview-value">{{ historyData.so2 }}</div>
<div class="overview-label">减少二氧化硫(千克)</div>
</div>
</div>
<WaveLineChart v-else :chart-data="getHistoryChartData(card.id)" :title="card.title"
:color="card.color" />
</div>
</div>
</div> -->
</div> </div>
</template> </template>
@ -280,7 +231,7 @@ import WaveLineChart from './charts/WaveLineChart.vue'
import { MapApi } from "@/api/shorepower/map"; import { MapApi } from "@/api/shorepower/map";
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import ComparisonBarChart from './charts/ComparisonBarChart.vue' import ComparisonBarChart from './charts/ComparisonBarChart.vue'
import { ComparativeData, RealtimeDeviceData } from '@/types/shorepower'; import { MetricData, RealtimeDeviceData } from '@/types/shorepower';
import { formatTimestamp, parseRangeToTimestamp } from './utils'; import { formatTimestamp, parseRangeToTimestamp } from './utils';
@ -289,7 +240,7 @@ interface Props {
activeHeadGroup?: number; activeHeadGroup?: number;
handleGoBack: () => void; handleGoBack: () => void;
realtimeDeviceDataTime: string; realtimeDeviceDataTime: string;
comparativeData: ComparativeData; comparativeData: MetricData; //
initialTimeRange?: 'realtime' | 'day' | 'month' | 'year'; initialTimeRange?: 'realtime' | 'day' | 'month' | 'year';
yearData: RealtimeDeviceData[]; yearData: RealtimeDeviceData[];
monthData: RealtimeDeviceData[]; monthData: RealtimeDeviceData[];
@ -374,35 +325,7 @@ export interface deviceData {
const pageType = ref<'realtime' | 'history'>('realtime') const pageType = ref<'realtime' | 'history'>('realtime')
const dateRange = ref<string[]>([]) const dateRange = ref<string[]>([])
const totalPower = ref<string>('0')
const fuelReduction = ref<string>('0')
const co2Reduction = ref<string>('0')
const pm25Reduction = ref<string>('0')
const noxReduction = ref<string>('0')
const so2Reduction = ref<string>('0')
// const yearlyData = ref<ComparativeData['year']>({})
const getDailyData = computed(() => {
return [{
name: '本期上期对比',
growthRate: props.comparativeData.day.growthRate,
currentValue: convertPowerUsage(props.comparativeData.day.current.value, selectedCard.value),
previousValue: convertPowerUsage(props.comparativeData.day.previous.value, selectedCard.value),
currentPeriod: props.comparativeData.day.current.period,
previousPeriod: props.comparativeData.day.previous.period,
}]
})
const getMonthlyData = computed(() => {
return [{
name: '本期上期对比',
growthRate: props.comparativeData.month.growthRate,
currentValue: convertPowerUsage(props.comparativeData.month.current.value, selectedCard.value),
previousValue: convertPowerUsage(props.comparativeData.month.previous.value, selectedCard.value),
currentPeriod: props.comparativeData.month.current.period,
previousPeriod: props.comparativeData.month.previous.period,
}]
})
const getYearlyData = computed(() => { const getYearlyData = computed(() => {
return [{ return [{
name: '本期上期对比', name: '本期上期对比',

6
public/map/components/ShowData.vue

@ -159,7 +159,8 @@
</div> </div>
</div> </div>
<div v-if="shorePowerCardShow && !showShipList" style="width: 840px"> <div v-if="shorePowerCardShow && !showShipList" style="width: 840px">
<ShorePowerUsageRate :realtimeDeviceDataTime="realtimeDeviceDataTime" :handleClose="handleCloseRate" /> <ShorePowerUsageRate :realtimeDeviceDataTime="realtimeDeviceDataTime" :comparative-data="comparativeData"
:handleClose="handleCloseRate" />
</div> </div>
<!-- <div v-if="shorePowerCardShow" class="card digital-twin-card--deep-blue" <!-- <div v-if="shorePowerCardShow" class="card digital-twin-card--deep-blue"
@ -380,7 +381,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { CompanyShorePowerData, RealtimeDeviceData, ShipRespVo, TimeRange } from '@/types/shorepower'; import { CompanyShorePowerData, MetricData, RealtimeDeviceData, ShipRespVo, TimeRange } from '@/types/shorepower';
import { ref, computed } from 'vue' import { ref, computed } from 'vue'
import { MapApi } from "@/api/shorepower/map"; import { MapApi } from "@/api/shorepower/map";
import ShipHistoryDialog from './ShipHistoryDialog.vue' import ShipHistoryDialog from './ShipHistoryDialog.vue'
@ -412,6 +413,7 @@ interface Props {
yearData: any[]; yearData: any[];
monthData: any[]; monthData: any[];
dayData: any[]; dayData: any[];
comparativeData: MetricData; // 使
} }
const props = defineProps<Props>() const props = defineProps<Props>()

16
public/map/components/cesiumMap.vue

@ -541,7 +541,9 @@ onMounted(async () => {
scaleByDistance: new Cesium.NearFarScalar(1000, 1.0, 50000, 0.1) scaleByDistance: new Cesium.NearFarScalar(1000, 1.0, 50000, 0.1)
} }
}); });
const status = props.getDeviceStatus(item.totalPowerDeviceId)
console.log(status)
// if ([1,2,5,8].includes(status)) {}
/* let statusImage = null; /* let statusImage = null;
if ([3, 4, 6].includes(item.status)) { if ([3, 4, 6].includes(item.status)) {
// 50% // 50%
@ -552,9 +554,9 @@ onMounted(async () => {
} else { } else {
// 25%线 // 25%线
statusImage = '/img/离线.png'; statusImage = '/img/离线.png';
} } */
// //
if (statusImage) { if ([1, 2, 5, 8].includes(status)) {
const overlayBillboard = viewer.entities.add({ const overlayBillboard = viewer.entities.add({
position: xposition, position: xposition,
properties: { properties: {
@ -562,7 +564,7 @@ onMounted(async () => {
data: item data: item
}, },
billboard: { billboard: {
image: statusImage, image: '/img/故障.png',
horizontalOrigin: Cesium.HorizontalOrigin.CENTER, horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.CENTER, verticalOrigin: Cesium.VerticalOrigin.CENTER,
disableDepthTestDistance: Number.POSITIVE_INFINITY, disableDepthTestDistance: Number.POSITIVE_INFINITY,
@ -574,7 +576,7 @@ onMounted(async () => {
}, false) }, false)
} }
}); });
} */ }
labelInstance.push(xelectricalBoxLabel) labelInstance.push(xelectricalBoxLabel)
}) })
shipData.forEach(item => { shipData.forEach(item => {
@ -638,7 +640,7 @@ onMounted(async () => {
data: item data: item
}) })
let labelColor = null let labelColor = null
/* let statusImage = null; let statusImage = null;
if (['在用', '正常'].includes(item.shipStatus)) { if (['在用', '正常'].includes(item.shipStatus)) {
// statusImage = null; // statusImage = null;
} else if (item.shipStatus === '超容') { } else if (item.shipStatus === '超容') {
@ -673,7 +675,7 @@ onMounted(async () => {
}, false) }, false)
} }
}); });
} */ }
const MODEL_HEIGHT_METERS = 80; const MODEL_HEIGHT_METERS = 80;
const cartographic = Cesium.Cartographic.fromCartesian(xposition); const cartographic = Cesium.Cartographic.fromCartesian(xposition);

24
public/map/components/charts/ComparisonBarChart.vue

@ -23,6 +23,7 @@ interface Props {
yAxisName?: string yAxisName?: string
currentLabel?: string currentLabel?: string
previousLabel?: string previousLabel?: string
chartType?: 'default' | 'percentage'
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
@ -33,7 +34,8 @@ const props = withDefaults(defineProps<Props>(), {
showYAxis: true, showYAxis: true,
yAxisName: '数值', yAxisName: '数值',
currentLabel: '本期', currentLabel: '本期',
previousLabel: '上期' previousLabel: '上期',
chartType: 'default'
}) })
// //
@ -42,10 +44,18 @@ let chartInstance: echarts.ECharts | null = null
// //
const createBarOption = (currentLabel: string, previousLabel: string, currentValue: number, previousValue: number) => { const createBarOption = (currentLabel: string, previousLabel: string, currentValue: number, previousValue: number) => {
//
const isPercentage = props.chartType === 'percentage';
return { return {
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
axisPointer: { type: 'shadow' } axisPointer: { type: 'shadow' },
formatter: (params: any) => {
const value = params[0].value;
const formattedValue = isPercentage ? `${(value * 100).toFixed(1)}%` : value.toFixed(2);
return `${params[0].name}: ${formattedValue}`;
}
}, },
grid: { grid: {
left: '15%', left: '15%',
@ -66,7 +76,7 @@ const createBarOption = (currentLabel: string, previousLabel: string, currentVal
yAxis: { yAxis: {
type: 'value', type: 'value',
axisLabel: { axisLabel: {
formatter: '{value}', formatter: isPercentage ? (value: number) => `${(value * 100).toFixed(0)}%` : '{value}',
color: 'rgba(255, 255, 255, 0.7)' color: 'rgba(255, 255, 255, 0.7)'
}, },
splitLine: { splitLine: {
@ -78,10 +88,11 @@ const createBarOption = (currentLabel: string, previousLabel: string, currentVal
lineStyle: { lineStyle: {
color: 'rgba(255, 255, 255, 0.3)' color: 'rgba(255, 255, 255, 0.3)'
} }
} },
max: isPercentage ? 1 : undefined
}, },
series: [{ series: [{
name: '用量', name: isPercentage ? '百分比' : '用量',
type: 'bar', type: 'bar',
barWidth: '60%', barWidth: '60%',
data: [ data: [
@ -94,7 +105,8 @@ const createBarOption = (currentLabel: string, previousLabel: string, currentVal
fontWeight: 'bold', fontWeight: 'bold',
color: '#fff', color: '#fff',
formatter: (params: any) => { formatter: (params: any) => {
return params.value > 0 ? params.value.toFixed(0) : ''; if (params.value <= 0) return '';
return isPercentage ? `${(params.value * 100).toFixed(1)}%` : params.value.toFixed(2);
} }
} }
}], }],

25
public/map/components/dictionaryTable.ts

@ -128,13 +128,6 @@ export const APPLY_STATUS = [
{ label: '已取消', value: 11 }, { label: '已取消', value: 11 },
] ]
export const SHIP_STATUS = [
{ label: '在用', value: 1 },
{ label: '故障', value: 2 },
{ label: '故障', value: 3 },
{ label: '异常', value: 4 },
]
/* 岸电一级状态 */ /* 岸电一级状态 */
export const SHORE_POWER_FIRST_STATUS = [ export const SHORE_POWER_FIRST_STATUS = [
{ label: '故障', value: 1 }, // 检修 { label: '故障', value: 1 }, // 检修
@ -156,3 +149,21 @@ export const SHORE_POWER_SECOND_STATUS_MAP = [
{ label: '无法解析设备状态', value: 8 }, { label: '无法解析设备状态', value: 8 },
{ label: '未开始采集数据', value: 9 }, { label: '未开始采集数据', value: 9 },
] ]
/* 船舶一级状态 */
export const SHIP_FIRST_STATUS = [
{ label: '在用', value: 1 },
{ label: '故障', value: 2 },
{ label: '正常', value: 3 },
{ label: '异常', value: 4 },
]
/* 船舶二级状态 */
export const SHIP_SECOND_STATUS_MAP = [
{ label: '在用', value: 1 },
{ label: '超容', value: 2 },
{ label: '故障', value: 3 },
{ label: '获取岸电容量失败', value: 4 },
{ label: '未使用岸电', value: 5 },
{ label: '跳闸', value: 6 },
]

276
public/map/index.vue

@ -36,7 +36,7 @@
:realtime-device-data-time="realtimeDeviceDataTime" :chart-data="chartData" :ship-total-data="shipTotalData" :realtime-device-data-time="realtimeDeviceDataTime" :chart-data="chartData" :ship-total-data="shipTotalData"
:ship-data-list="shipDataList" @item-click="handleSwitch" :realtime-device-data="realtimeDeviceData" :ship-data-list="shipDataList" @item-click="handleSwitch" :realtime-device-data="realtimeDeviceData"
v-if="dataLoad" :company-shore-power-data="companyComparisonData" :year-data="yearDataRes" v-if="dataLoad" :company-shore-power-data="companyComparisonData" :year-data="yearDataRes"
:month-data="monthDataRes" :day-data="dayDataRes" /> :month-data="monthDataRes" :day-data="dayDataRes" :comparative-data="comparativeData.utilizationRate" />
<!-- 港口岸电使用情况多数据 --> <!-- 港口岸电使用情况多数据 -->
<ShorePowerUsage v-show="activeHeadGroup === 1" :realtime-device-data-time="realtimeDeviceDataTime" <ShorePowerUsage v-show="activeHeadGroup === 1" :realtime-device-data-time="realtimeDeviceDataTime"
@ -48,7 +48,8 @@
<ShorePowerUsageSingleData v-if="activeHeadGroup === 5 && dataLoad" <ShorePowerUsageSingleData v-if="activeHeadGroup === 5 && dataLoad"
:realtime-device-data-time="realtimeDeviceDataTime" :realtime-device-data="realtimeDeviceData" :realtime-device-data-time="realtimeDeviceDataTime" :realtime-device-data="realtimeDeviceData"
:active-head-group="activeHeadGroup" :initial-time-range="selectedTimeRange" :handleGoBack="handleGoBack" :active-head-group="activeHeadGroup" :initial-time-range="selectedTimeRange" :handleGoBack="handleGoBack"
:comparative-data="comparativeData" :year-data="yearDataRes" :month-data="monthDataRes" :day-data="dayDataRes" /> :comparative-data="comparativeData.electricityConsumption" :year-data="yearDataRes" :month-data="monthDataRes"
:day-data="dayDataRes" />
<!-- 港口企业岸电使用 --> <!-- 港口企业岸电使用 -->
<!-- <template v-if="activeHeadGroup === 2"> --> <!-- <template v-if="activeHeadGroup === 2"> -->
@ -312,6 +313,7 @@ import { CompanyShorePowerBuildDataItem, CompanyShorePowerData, ComparativeData,
import { BERTH_TYPE, DOCK_DISTRICT, getOperationTypeLabel, HARBOR_DISTRICT, SHORE_POWER_FIRST_STATUS, SHORE_POWER_SECOND_STATUS_MAP, SHORE_POWER_STATUS, UNUSED_SHORE_POWER_REASON } from './components/dictionaryTable' import { BERTH_TYPE, DOCK_DISTRICT, getOperationTypeLabel, HARBOR_DISTRICT, SHORE_POWER_FIRST_STATUS, SHORE_POWER_SECOND_STATUS_MAP, SHORE_POWER_STATUS, UNUSED_SHORE_POWER_REASON } from './components/dictionaryTable'
import { formatDuration, formatTimestamp, getValueById, showStatus } from './components/utils' import { formatDuration, formatTimestamp, getValueById, showStatus } from './components/utils'
defineOptions({ name: 'PublicMap' }) defineOptions({ name: 'PublicMap' })
let getRealtimeIntervalId: NodeJS.Timeout | null = null let getRealtimeIntervalId: NodeJS.Timeout | null = null
@ -808,7 +810,6 @@ onMounted(async () => {
handleBuildCompanyShorePowerYear(tempBuildShipData) handleBuildCompanyShorePowerYear(tempBuildShipData)
getDistributionBoxDataList() getDistributionBoxDataList()
await handleGetBuildData() await handleGetBuildData()
buildShorePowerUsageRatio()
dataLoad.value = true dataLoad.value = true
getRealtimeIntervalId = setInterval(async () => { getRealtimeIntervalId = setInterval(async () => {
@ -1231,6 +1232,7 @@ const handleGetBuildData = async () => {
const handleBuildTimeComparison = async (): Promise<ComparativeData> => { const handleBuildTimeComparison = async (): Promise<ComparativeData> => {
const now = dayjs(); const now = dayjs();
console.log(getShorePowerIds.value, getBerthingShipsIds.value, getDepartingShipsIds.value, getElectricityUsageIds.value)
/** /**
* 计算每个分组的周期用量last.measureValue - first.measureValue 的总和 * 计算每个分组的周期用量last.measureValue - first.measureValue 的总和
*/ */
@ -1244,6 +1246,36 @@ const handleBuildTimeComparison = async (): Promise<ComparativeData> => {
}, 0); }, 0);
}; };
/**
* 计算所有分组中 measureValue 的总和即累计用量
*/
const calculateTotalUsage = (apiResponse: Record<string, { measureValue: number }[]>): number => {
const dataArrays = Object.values(apiResponse).filter(Array.isArray) as { measureValue: number }[][];
return dataArrays.reduce((total, row) => {
const rowSum = row.reduce((sum, item) => sum + item.measureValue, 0);
return total + rowSum;
}, 0);
};
/**
* 根据指定的 deviceId 数组从数据源中筛选出对应的数据
* @param {Object} dataSource - 数据源格式如 {1: [...], 2: [...], ...}
* @param {Array<number|string>} deviceIds - 要筛选的 deviceId 数组 [1, 2]
* @returns {Object} 筛选后的对象只包含 deviceIds 中存在的键
*/
function filterByDeviceIds(dataSource, deviceIds) {
const result = {};
for (const id of deviceIds) {
// 使 String(id) key
const key = String(id);
if (key in dataSource) {
result[key] = dataSource[key];
}
}
return result;
}
/** /**
* 安全计算环比增长率(current - previous) / previous * 安全计算环比增长率(current - previous) / previous
* - previous 0 current 也为 0 返回 0 * - previous 0 current 也为 0 返回 0
@ -1326,157 +1358,45 @@ const handleBuildTimeComparison = async (): Promise<ComparativeData> => {
]); ]);
// ===== ===== // ===== =====
const todayUsage = calculatePeriodUsage(todayRes); const todayUsage = calculatePeriodUsage(filterByDeviceIds(todayRes, getShorePowerIds.value));
const yesterdayUsage = calculatePeriodUsage(yesterdayRes); const yesterdayUsage = calculatePeriodUsage(filterByDeviceIds(yesterdayRes, getShorePowerIds.value));
const lastYearTodayUsage = calculatePeriodUsage(lastYearTodayRes); const lastYearTodayUsage = calculatePeriodUsage(filterByDeviceIds(lastYearTodayRes, getShorePowerIds.value));
const thisMonthUsage = calculatePeriodUsage(thisMonthRes); const thisMonthUsage = calculatePeriodUsage(filterByDeviceIds(thisMonthRes, getShorePowerIds.value));
const lastMonthUsage = calculatePeriodUsage(lastMonthRes); const lastMonthUsage = calculatePeriodUsage(filterByDeviceIds(lastMonthRes, getShorePowerIds.value));
const lastYearMonthUsage = calculatePeriodUsage(lastYearMonthRes); const lastYearMonthUsage = calculatePeriodUsage(filterByDeviceIds(lastYearMonthRes, getShorePowerIds.value));
const thisYearUsage = calculatePeriodUsage(thisYearRes); const thisYearUsage = calculatePeriodUsage(filterByDeviceIds(thisYearRes, getShorePowerIds.value));
const lastYearUsage = calculatePeriodUsage(lastYearRes); const lastYearUsage = calculatePeriodUsage(filterByDeviceIds(lastYearRes, getShorePowerIds.value));
// ===== 使 =====
const ship_todayUsage = calculateTotalUsage(filterByDeviceIds(todayRes, getElectricityUsageIds.value)) / calculateTotalUsage(filterByDeviceIds(todayRes, getBerthingShipsIds.value));
const ship_yesterdayUsage = calculateTotalUsage(filterByDeviceIds(yesterdayRes, getElectricityUsageIds.value)) / calculateTotalUsage(filterByDeviceIds(yesterdayRes, getBerthingShipsIds.value));
const ship_lastYearTodayUsage = calculateTotalUsage(filterByDeviceIds(lastYearTodayRes, getElectricityUsageIds.value)) / calculateTotalUsage(filterByDeviceIds(lastYearTodayRes, getBerthingShipsIds.value));
const ship_thisMonthUsage = calculateTotalUsage(filterByDeviceIds(thisMonthRes, getElectricityUsageIds.value)) / calculateTotalUsage(filterByDeviceIds(thisMonthRes, getBerthingShipsIds.value));
const ship_lastMonthUsage = calculateTotalUsage(filterByDeviceIds(lastMonthRes, getElectricityUsageIds.value)) / calculateTotalUsage(filterByDeviceIds(lastMonthRes, getBerthingShipsIds.value));
const ship_lastYearMonthUsage = calculateTotalUsage(filterByDeviceIds(lastYearMonthRes, getElectricityUsageIds.value)) / calculateTotalUsage(filterByDeviceIds(lastYearMonthRes, getBerthingShipsIds.value));
const ship_thisYearUsage = calculateTotalUsage(filterByDeviceIds(thisYearRes, getElectricityUsageIds.value)) / calculateTotalUsage(filterByDeviceIds(thisYearRes, getBerthingShipsIds.value));
const ship_lastYearUsage = calculateTotalUsage(filterByDeviceIds(lastYearRes, getElectricityUsageIds.value)) / calculateTotalUsage(filterByDeviceIds(lastYearRes, getBerthingShipsIds.value));
/* const ship_todayUsage = .5
const ship_yesterdayUsage = .2
const ship_lastYearTodayUsage = .3
const ship_thisMonthUsage = .4
const ship_lastMonthUsage = .1
const ship_lastYearMonthUsage = .6
const ship_thisYearUsage = .8
const ship_lastYearUsage = .9 */
/* 计算使用率 */
/* const calculateUsageRate = () => {
const aa = calculateTotalUsage(filterByDeviceIds(todayRes, getBerthingShipsIds.value))
const bb = calculateTotalUsage(filterByDeviceIds(todayRes, getElectricityUsageIds.value))
// ===== =====
return {
day: {
growthRate: calculateGrowthRate(todayUsage, yesterdayUsage),
current: { period: now.format('YYYY-MM-DD'), value: todayUsage },
previous: { period: yesterday.format('YYYY-MM-DD'), value: yesterdayUsage }
},
dayYearOnYear: {
growthRate: calculateGrowthRate(todayUsage, lastYearTodayUsage),
current: { period: now.format('YYYY-MM-DD'), value: todayUsage },
previous: { period: lastYearToday.format('YYYY-MM-DD'), value: lastYearTodayUsage }
},
month: {
growthRate: calculateGrowthRate(thisMonthUsage, lastMonthUsage),
current: { period: now.format('YYYY-MM'), value: thisMonthUsage },
previous: { period: lastMonth.format('YYYY-MM'), value: lastMonthUsage }
},
monthYearOnYear: {
growthRate: calculateGrowthRate(thisMonthUsage, lastYearMonthUsage),
current: { period: now.format('YYYY-MM'), value: thisMonthUsage },
previous: { period: lastYearMonth.format('YYYY-MM'), value: lastYearMonthUsage }
},
year: {
growthRate: calculateGrowthRate(thisYearUsage, lastYearUsage),
current: { period: now.format('YYYY'), value: thisYearUsage },
previous: { period: lastYear.format('YYYY'), value: lastYearUsage }
}
}; };
}; calculateUsageRate() */
/**
* 构建岸电使用率环比和同比
*/
const buildShorePowerUsageRatio = () => {
const handleBuildTimeComparison = async (): Promise<ComparativeData> => {
const now = dayjs();
/**
* 计算每个分组的周期用量last.measureValue - first.measureValue 的总和
*/
const calculatePeriodUsage = (apiResponse: Record<string, { measureValue: number }[]>): number => {
const dataArrays = Object.values(apiResponse).filter(Array.isArray) as { measureValue: number }[][];
return dataArrays.reduce((total, row) => {
if (row.length === 0) return total;
const firstValue = row[0].measureValue;
const lastValue = row[row.length - 1].measureValue;
return total + (lastValue - firstValue);
}, 0);
};
/**
* 安全计算环比增长率(current - previous) / previous
* - previous 0 current 也为 0 返回 0
* - previous 0 current > 0 返回 null表示新增
*/
const calculateGrowthRate = (current: number | null, previous: number | null): number => {
if (previous === 0) {
return current === 0 ? 0 : null; // null 0
}
return (current - previous) / previous;
};
// ===== =====
const todayStart = now.startOf('day').valueOf();
const todayEnd = now.valueOf();
const yesterday = now.subtract(1, 'day');
const yesterdayStart = yesterday.startOf('day').valueOf();
const yesterdayEnd = yesterday.valueOf();
// ===== =====
const lastYearToday = now.subtract(1, 'year');
const lastYearTodayStart = lastYearToday.startOf('day').valueOf();
const lastYearTodayEnd = lastYearToday.valueOf();
// ===== =====
const thisMonthStart = now.startOf('month').valueOf();
const thisMonthEnd = now.valueOf();
const lastMonth = now.subtract(1, 'month');
const lastMonthStart = lastMonth.startOf('month').valueOf();
// ""3130
const daysInLastMonth = lastMonth.daysInMonth();
const todayDate = now.date();
const alignedDay = Math.min(todayDate, daysInLastMonth);
const lastMonthEnd = lastMonth.date(alignedDay).endOf('day').valueOf();
// ===== =====
const lastYearMonth = now.subtract(1, 'year');
const lastYearMonthStart = lastYearMonth.startOf('month').valueOf();
// /
const daysInLastYearMonth = lastYearMonth.daysInMonth();
const lastYearAlignedDay = Math.min(todayDate, daysInLastYearMonth);
const lastYearMonthEnd = lastYearMonth.date(lastYearAlignedDay).endOf('day').valueOf();
// ===== =====
const thisYearStart = now.startOf('year').valueOf();
const thisYearEnd = now.valueOf();
const lastYear = now.subtract(1, 'year');
const lastYearStart = lastYear.startOf('year').valueOf();
// / 2 29
let lastYearEnd: number;
try {
//
lastYearEnd = lastYear.month(now.month()).date(now.date()).endOf('day').valueOf();
} catch {
// 2/29
lastYearEnd = lastYear.month(now.month()).endOf('month').valueOf();
}
// ===== 8 ===== // ===== =====
const [ return {
todayRes, electricityConsumption: {
yesterdayRes,
lastYearTodayRes,
thisMonthRes,
lastMonthRes,
lastYearMonthRes,
thisYearRes,
lastYearRes
] = await Promise.all([
MapApi.getByStartAndEndTimeAndTimeType({ start: todayStart, end: todayEnd, timeType: 2 }),
MapApi.getByStartAndEndTimeAndTimeType({ start: yesterdayStart, end: yesterdayEnd, timeType: 2 }),
MapApi.getByStartAndEndTimeAndTimeType({ start: lastYearTodayStart, end: lastYearTodayEnd, timeType: 2 }),
MapApi.getByStartAndEndTimeAndTimeType({ start: thisMonthStart, end: thisMonthEnd, timeType: 3 }),
MapApi.getByStartAndEndTimeAndTimeType({ start: lastMonthStart, end: lastMonthEnd, timeType: 3 }),
MapApi.getByStartAndEndTimeAndTimeType({ start: lastYearMonthStart, end: lastYearMonthEnd, timeType: 3 }),
MapApi.getByStartAndEndTimeAndTimeType({ start: thisYearStart, end: thisYearEnd, timeType: 4 }),
MapApi.getByStartAndEndTimeAndTimeType({ start: lastYearStart, end: lastYearEnd, timeType: 4 })
]);
// ===== =====
const todayUsage = calculatePeriodUsage(todayRes);
const yesterdayUsage = calculatePeriodUsage(yesterdayRes);
const lastYearTodayUsage = calculatePeriodUsage(lastYearTodayRes);
const thisMonthUsage = calculatePeriodUsage(thisMonthRes);
const lastMonthUsage = calculatePeriodUsage(lastMonthRes);
const lastYearMonthUsage = calculatePeriodUsage(lastYearMonthRes);
const thisYearUsage = calculatePeriodUsage(thisYearRes);
const lastYearUsage = calculatePeriodUsage(lastYearRes);
// ===== =====
return {
day: { day: {
growthRate: calculateGrowthRate(todayUsage, yesterdayUsage), growthRate: calculateGrowthRate(todayUsage, yesterdayUsage),
current: { period: now.format('YYYY-MM-DD'), value: todayUsage }, current: { period: now.format('YYYY-MM-DD'), value: todayUsage },
@ -1502,9 +1422,57 @@ const buildShorePowerUsageRatio = () => {
current: { period: now.format('YYYY'), value: thisYearUsage }, current: { period: now.format('YYYY'), value: thisYearUsage },
previous: { period: lastYear.format('YYYY'), value: lastYearUsage } previous: { period: lastYear.format('YYYY'), value: lastYearUsage }
} }
}; },
}; utilizationRate: {
} day: {
growthRate: calculateGrowthRate(ship_todayUsage, ship_yesterdayUsage),
current: { period: now.format('YYYY-MM-DD'), value: ship_todayUsage },
previous: { period: yesterday.format('YYYY-MM-DD'), value: ship_yesterdayUsage }
},
dayYearOnYear: {
growthRate: calculateGrowthRate(ship_todayUsage, ship_lastYearTodayUsage),
current: { period: now.format('YYYY-MM-DD'), value: ship_todayUsage },
previous: { period: lastYearToday.format('YYYY-MM-DD'), value: ship_lastYearTodayUsage }
},
month: {
growthRate: calculateGrowthRate(ship_thisMonthUsage, ship_lastMonthUsage),
current: { period: now.format('YYYY-MM'), value: ship_thisMonthUsage },
previous: { period: lastMonth.format('YYYY-MM'), value: ship_lastMonthUsage }
},
monthYearOnYear: {
growthRate: calculateGrowthRate(ship_thisMonthUsage, ship_lastYearMonthUsage),
current: { period: now.format('YYYY-MM'), value: ship_thisMonthUsage },
previous: { period: lastYearMonth.format('YYYY-MM'), value: ship_lastYearMonthUsage }
},
year: {
growthRate: calculateGrowthRate(ship_thisYearUsage, ship_lastYearUsage),
current: { period: now.format('YYYY'), value: ship_thisYearUsage },
previous: { period: lastYear.format('YYYY'), value: ship_lastYearUsage }
}
}
}
};
const getShorePowerIds = computed(() => {
return realtimeDeviceData.value.filter(item => item.deviceCode.includes('Kwh')).map(item => item.deviceId)
})
/* 靠泊数量 */
const getBerthingShipsIds = computed(() => {
return realtimeDeviceData.value.filter(item => item.deviceCode.includes('arrive')).map(item => item.deviceId)
})
/* 离泊数量 */
const getDepartingShipsIds = computed(() => {
return realtimeDeviceData.value.filter(item => item.deviceCode.includes('depart')).map(item => item.deviceId)
})
/* 用电数量 */
const getElectricityUsageIds = computed(() => {
return realtimeDeviceData.value.filter(item => item.deviceCode.includes('usage')).map(item => item.deviceId)
})
</script> </script>
<style lang="scss"> <style lang="scss">

5
src/types/shorepower.d.ts

@ -495,6 +495,11 @@ type CompanyShorePowerBuildDataItem = {
} }
interface ComparativeData { interface ComparativeData {
electricityConsumption: MetricData
utilizationRate: MetricData
}
interface MetricData {
day: { day: {
growthRate: number growthRate: number
current: { current: {

Loading…
Cancel
Save