Browse Source

update

feature
jiangAB 4 weeks ago
parent
commit
f8f85d653f
  1. 102
      public/map/components/CompanyShorePower.vue
  2. 610
      public/map/components/ShipShorePower.vue
  3. 10
      public/map/components/ShorePowerUsage.vue
  4. 6
      public/map/components/cesiumMap.vue
  5. 9
      public/map/components/dictionaryTable.ts
  6. 98
      public/map/index.vue
  7. 5
      src/types/shorepower.d.ts

102
public/map/components/CompanyShorePower.vue

@ -24,7 +24,7 @@
</div>
<div class="overview-grid">
<div v-for="(berth, index) in (company.children || [])" :key="index" class="overview-item"
@click="showShorePowerHistory(berth)">
@click="handleClickBerthItem(berth)">
<div class="overview-value">{{ berth.measureValue?.toFixed(2)
|| 0 }}</div>
@ -36,6 +36,70 @@
</div>
</div>
</div>
<div class="right" v-if="selectedShorePowerItem">
<div class="card digital-twin-card--deep-blue">
<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">岸电箱详情</span>
</div>
<div style="ma">
<el-button type="primary" @click="handleOpenHistory">查看历史记录</el-button>
</div>
</div>
<div class="card-content">
<div class="ship-detail">
<div class="detail-item">
<span class="label">名称:</span>
<span class="value">{{ selectedShorePowerItem?.name }}</span>
</div>
<div class="detail-item">
<span class="label">位置:</span>
<span class="value">{{ selectedShorePowerItem?.position }}</span>
</div>
<div class="detail-item">
<span class="label">电压:</span>
<span class="value">{{ selectedShorePowerItem?.shorePowerEquipmentInfo?.voltage }}</span>
</div>
<div class="detail-item">
<span class="label">频率:</span>
<span class="value">{{ selectedShorePowerItem?.shorePowerEquipmentInfo?.frequency }} </span>
</div>
<div class="detail-item">
<span class="label">容量:</span>
<span class="value">{{ selectedShorePowerItem?.shorePowerEquipmentInfo?.capacity }}</span>
</div>
<div class="detail-item">
<span class="label">当前电压:</span>
<span class="value">{{ getValueById(realtimeDeviceData, selectedShorePowerItem.voltageDeviceId,
'measureValue') }}</span>
</div>
<div class="detail-item">
<span class="label">当前电流:</span>
<span class="value">{{ getValueById(realtimeDeviceData, selectedShorePowerItem.currentDeviceId,
'measureValue') }}</span>
</div>
<div class="detail-item">
<span class="label">当前频率:</span>
<span class="value">{{ getValueById(realtimeDeviceData, selectedShorePowerItem.frequencyDeviceId,
'measureValue') }}</span>
</div>
<div class="detail-item">
<span class="label">当前总用量:</span>
<span class="value">{{ getValueById(realtimeDeviceData, selectedShorePowerItem.totalPowerDeviceId,
'measureValue') }}</span>
</div>
<div class="detail-item">
<span class="label">当前状态:</span>
<span class="value">{{ selectedShorePowerItem.storePowerStatus }}</span>
</div>
</div>
</div>
</div>
</div>
<ship-history-dialog v-if="historyVisible.visible" v-model="historyVisible.visible"
:ship-param="historyVisible.searchParams" :realtime-device-data="realtimeDeviceData" />
</div>
@ -45,9 +109,11 @@
import { ref } from 'vue'
import { MapApi } from "@/api/shorepower/map";
import ShipHistoryDialog from './ShipHistoryDialog.vue';
import { RealtimeDeviceData } from '@/types/shorepower';
import { RealtimeDeviceData, ShorePowerBerth } from '@/types/shorepower';
import { getValueById } from './utils';
//
interface ChartDataItem {
id: number;
name: string;
value?: number;
measureValue?: number;
@ -63,6 +129,14 @@ const historyVisible = ref({
}
})
interface Props {
realtimeDeviceData: RealtimeDeviceData[];
shorePowerList: ShorePowerBerth[];
}
const props = defineProps<Props>()
const selectedShorePowerItem = ref<ShorePowerBerth>()
//
const calculateTotal = (children?: ChartDataItem[]) => {
if (!children || children.length === 0) return 0;
@ -71,6 +145,21 @@ const calculateTotal = (children?: ChartDataItem[]) => {
}, 0);
};
/* 点击泊位box */
const handleClickBerthItem = (berth: ChartDataItem) => {
console.log(props.shorePowerList)
console.log(berth)
const shorePower = props.shorePowerList.find(item => item.id === berth.id)
selectedShorePowerItem.value = shorePower
console.log(shorePower)
}
const handleOpenHistory = () => {
if (selectedShorePowerItem.value) {
showShorePowerHistory(selectedShorePowerItem.value)
}
}
//
const showShorePowerHistory = (berth: ChartDataItem) => {
console.log(berth)
@ -89,13 +178,6 @@ const showShorePowerHistory = (berth: ChartDataItem) => {
}
}
}
interface Props {
companyComparisonData?: ChartDataItem[];
realtimeDeviceData: RealtimeDeviceData[];
}
const props = defineProps<Props>()
const companyComparisonData = ref<ChartDataItem[]>([])
const handleGetBuildData = async () => {
const dockList = await MapApi.getDockIdAndNameList()
@ -107,8 +189,6 @@ const handleGetBuildData = async () => {
...props.realtimeDeviceData.find(item => (item.id === berth.id) && (item.deviceCode.includes('Kwh')))
}))
}))
console.log('buildData', buildData)
console.log('props.realtimeDeviceData', props.realtimeDeviceData)
companyComparisonData.value = buildData
/* MapApi.getBerthIdAndNameList().then(res => {
console.log(res)

610
public/map/components/ShipShorePower.vue

@ -11,7 +11,7 @@
<div class="overview-grid">
<div class="overview-item">
<div class="overview-value">{{ berthingShips }}</div>
<div class="overview-label">船舶数量</div>
<div class="overview-label">船舶数量</div>
</div>
<div class="overview-item">
<div class="overview-value">{{ shorePowerShips }}</div>
@ -46,28 +46,46 @@
</div>
<div class="card-content">
<div class="ship-data-table-container">
<el-table :data="filteredShipData" class="ship-data-table" @row-click="handleShipClick"
<el-table :data="filteredShipData" class="ship-data-table" @row-click="handleClickShipItem"
highlight-current-row>
<el-table-column prop="name" label="船名" />
<el-table-column prop="wharf" label="码头" />
<el-table-column prop="berth" label="泊位" />
<el-table-column prop="shipBasicInfo.name" label="船名" />
<el-table-column prop="applyInfo.arrivalDock" label="码头">
<template #default="scope">
<span>{{ getOperationTypeLabel(scope.row.applyInfo?.arrivalDock, dockIdAndNameList) }}</span>
</template>
</el-table-column>
<el-table-column prop="applyInfo.arrivalBerth" label="泊位">
<template #default="scope">
<span>{{ getOperationTypeLabel(scope.row.applyInfo?.arrivalBerth, berthIdAndNameList) }}</span>
</template>
</el-table-column>
<el-table-column prop="beginTime" label="开始用电时间">
<template #default="scope">
<span>{{ formatDateTime(scope.row.beginTime) }}</span>
<span>{{ formatDateTime(scope.row?.usageRecordInfo?.beginTime) }}</span>
</template>
</el-table-column>
<el-table-column prop="endTime" label="结束用电时间">
<template #default="scope">
<span>{{ formatDateTime(scope.row.endTime) }}</span>
<span>{{ formatDateTime(scope.row?.usageRecordInfo?.endTime) }}</span>
</template>
</el-table-column>
<el-table-column prop="status" label="岸电状态" width="400">
<template #default="scope">
<span :class="['shore-power-status', scope.row.statusClass]">{{ scope.row.status }}</span>
<span v-if="scope.row.applyInfo?.reason === 0"
:class="['shore-power-status', showStatus(scope.row, realtimeDeviceData)?.statusClass]">{{
showStatus(scope.row, realtimeDeviceData)?.status }}</span>
<span v-if="scope.row.applyInfo?.reason != 0" class="shore-power-status status-off">{{
getOperationTypeLabel(scope.row.applyInfo?.reason,
UNUSED_SHORE_POWER_REASON) }}</span>
</template>
</el-table-column>
<el-table-column prop="applyInfo.departureHarborDistrict" label="起运港" />
<el-table-column prop="arrivalHarborDistrict" label="到达港">
<template #default="scope">
<span>{{ getOperationTypeLabel(scope.row.applyInfo?.arrivalHarborDistrict,
harborDistrictIdAndNameList) }}</span>
</template>
</el-table-column>
<el-table-column prop="departureHarborDistrict" label="起运港" />
<el-table-column prop="arrivalHarborDistrict" label="到达港" />
<el-table-column label="操作" width="100">
<template #default="scope">
<el-button type="primary" size="small" @click.stop="showDetail(scope.row)">更多</el-button>
@ -78,8 +96,98 @@
</div>
</div>
</div>
<div class="right" v-if="selectedShip">
<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>
</div>
<div class="card-content">
<div class="ship-detail">
<div class="detail-item">
<span class="label">名称:</span>
<span class="value">{{ selectedShip.shipBasicInfo.name + '-' + selectedShip.shipBasicInfo.nameEn
}}</span>
</div>
<div class="detail-item">
<span class="label">长度:</span>
<span class="value">{{ selectedShip.shipBasicInfo.length }} </span>
</div>
<div class="detail-item">
<span class="label">宽度:</span>
<span class="value">{{ selectedShip.shipBasicInfo.width }} </span>
</div>
<div class="detail-item">
<span class="label">吨位:</span>
<span class="value">{{ selectedShip.shipBasicInfo.tonnage }} </span>
</div>
<div class="detail-item">
<span class="label">满载吃水深度:</span>
<span class="value">{{ selectedShip.shipBasicInfo.fullLoadDraft }} </span>
</div>
<div class="detail-item">
<span class="label">电压:</span>
<span class="value">{{ getValueById(realtimeDeviceData, selectedShip.shorePower.voltageDeviceId,
'measureValue') }}</span>
</div>
<div class="detail-item">
<span class="label">电流:</span>
<span class="value">{{ getValueById(realtimeDeviceData, selectedShip.shorePower.currentDeviceId,
'measureValue') }}</span>
</div>
<div class="detail-item">
<span class="label">频率:</span>
<span class="value">{{ getValueById(realtimeDeviceData, selectedShip.shorePower.frequencyDeviceId,
'measureValue') }}</span>
</div>
<div class="detail-item">
<span class="label">靠泊状态:</span>
<span class="value">{{ getOperationTypeLabel(selectedShip.shorePowerAndShip.status,
SHORE_POWER_STATUS,
) }}</span>
</div>
<div class="detail-item">
<span class="label">靠泊类型:</span>
<span class="value">{{ getOperationTypeLabel(selectedShip.shorePowerAndShip.type, BERTH_TYPE)
}}</span>
</div>
<div class="detail-item">
<span class="label">靠泊时间:</span>
<span class="value">{{ formatTimestamp(selectedShip?.usageRecordInfo?.actualBerthTime) }}</span>
</div>
<div class="detail-item">
<span class="label">当前状态:</span>
<span class="value">{{ selectedShip.shipStatus }}</span>
</div>
<div v-if="selectedShip.applyInfo.reason === 0" class="detail-item">
<span class="label">岸电使用时长:</span>
<span class="value">{{ showStatus(selectedShip, realtimeDeviceData)?.useTime }}</span>
</div>
<div v-if="selectedShip.applyInfo.reason === 0" class="detail-item">
<span class="label">岸电使用用量:</span>
<span class="value">{{ showStatus(selectedShip, realtimeDeviceData)?.useValue }}</span>
</div>
<div v-if="selectedShip.applyInfo.reason != 0" class="detail-item">
<span class="label">未使用岸电原因:</span>
<span class="value">{{ getOperationTypeLabel(selectedShip?.applyInfo?.reason,
UNUSED_SHORE_POWER_REASON) }}</span>
</div>
<div class="detail-item">
<span class="label">岸电联系人:</span>
<span class="value">{{ selectedShip.shipBasicInfo.shorePowerContact }}</span>
</div>
<div class="detail-item">
<span class="label">联系方式:</span>
<span class="value">{{ selectedShip.shipBasicInfo.shorePowerContactPhone }}</span>
</div>
</div>
</div>
</div>
</div>
<!-- 船舶详情对话框 -->
<el-dialog v-model="detailDialogVisible" title="更多信息" width="1000px" class="ship-detail-dialog">
<el-dialog v-if="detailDialogVisible" v-model="detailDialogVisible" title="更多信息" width="1000px"
class="ship-detail-dialog">
<el-tabs v-if="selectedShip" v-model="activeTab">
<el-tab-pane label="用电申请信息" name="applyInfo">
<el-form :model="selectedShip.applyInfo" label-width="200px">
@ -108,7 +216,8 @@
</el-col>
<el-col :span="12">
<el-form-item label="到达港:">
<span>{{ findNameById(selectedShip.applyInfo?.arrivalHarborDistrict, harborDistrictIdAndNameList)
<span>{{ getOperationTypeLabel(selectedShip.applyInfo?.arrivalHarborDistrict,
harborDistrictIdAndNameList)
}}</span>
</el-form-item>
</el-col>
@ -117,12 +226,12 @@
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="到达码头:">
<span>{{ findNameById(selectedShip.applyInfo?.arrivalDock, dockIdAndNameList) }}</span>
<span>{{ getOperationTypeLabel(selectedShip.applyInfo?.arrivalDock, dockIdAndNameList) }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="到达泊位:">
<span>{{ findNameById(selectedShip.applyInfo?.arrivalBerth, berthIdAndNameList) }}</span>
<span>{{ getOperationTypeLabel(selectedShip.applyInfo?.arrivalBerth, berthIdAndNameList) }}</span>
</el-form-item>
</el-col>
</el-row>
@ -164,7 +273,7 @@
<el-col :span="12">
<el-form-item label="货物类型(装货):">
<span>{{ getOperationTypeLabel(selectedShip.applyInfo?.loadingCargoCategory, CARGO_CATEGORY) || '-'
}}</span>
}}</span>
</el-form-item>
</el-col>
<el-col :span="12">
@ -186,7 +295,7 @@
<el-col :span="12">
<el-form-item label="货物类型(卸货):">
<span>{{ getOperationTypeLabel(selectedShip.applyInfo?.unloadingCargoCategory, CARGO_CATEGORY) || '-'
}}</span>
}}</span>
</el-form-item>
</el-col>
<el-col :span="12">
@ -215,7 +324,7 @@
<el-col :span="12" v-if="selectedShip.applyInfo?.reason !== 0">
<el-form-item label="未使用岸电原因:">
<span>{{ getOperationTypeLabel(selectedShip.applyInfo?.reason, UNUSED_SHORE_POWER_REASON) || '-'
}}</span>
}}</span>
</el-form-item>
</el-col>
</el-row>
@ -406,13 +515,13 @@
<el-col :span="12">
<el-form-item label="船舶长度:">
<span>{{ selectedShip.shipBasicInfo?.length !== undefined ? selectedShip.shipBasicInfo?.length : '-'
}}</span>
}}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="船舶宽度:">
<span>{{ selectedShip.shipBasicInfo?.width !== undefined ? selectedShip.shipBasicInfo?.width : '-'
}}</span>
}}</span>
</el-form-item>
</el-col>
</el-row>
@ -421,7 +530,7 @@
<el-col :span="12">
<el-form-item label="船舶吨位:">
<span>{{ selectedShip.shipBasicInfo?.tonnage !== undefined ? selectedShip.shipBasicInfo?.tonnage : '-'
}}</span>
}}</span>
</el-form-item>
</el-col>
<el-col :span="12">
@ -481,295 +590,52 @@
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { MapApi } from "@/api/shorepower/map";
import dayjs from 'dayjs';
import { ShipRespVo } from '@/types/shorepower';
import { APPLY_STATUS, CARGO_CATEGORY, getOperationTypeLabel, OPERATION_TYPE, TRADE_TYPE, UNUSED_SHORE_POWER_REASON, WORK_STATUS } from './dictionaryTable';
//
interface ShipDataItem {
name: string;
wharf: string;
berth: string;
status: string;
statusClass: string;
departureHarborDistrict: string;
arrivalHarborDistrict: string;
beginTime?: Date;
endTime?: Date;
shipBasicInfo?: {
/**
* 船舶呼号
*/
callSign: string;
/**
* 创建时间
*/
createTime: Date;
/**
* 满载吃水深度
*/
fullLoadDraft: number;
/**
* 编号
*/
id: number;
/**
* 船检登记号
*/
inspectionNo: string;
/**
* 船舶长度
*/
length: number;
/**
* 船名
*/
name: string;
/**
* 英文船名
*/
nameEn: string;
/**
* 航运单位名称
*/
shippingCompany: string;
/**
* 岸电负责人
*/
shorePowerContact: string;
/**
* 联系方式
*/
shorePowerContactPhone: string;
/**
* 船舶吨位
*/
tonnage: number;
/**
* 船舶宽度
*/
width: number;
[property: string]: any;
}
applyInfo?: {
/**
* 船方代理单位
*/
agentCompany: string;
/**
* 代理人联系方式
*/
agentContact: string;
/**
* 是否申请使用岸电
*/
applyShorePower: boolean;
/**
* 到达泊位
*/
arrivalBerth: number;
/**
* 到达码头
*/
arrivalDock: number;
/**
* 到达港
*/
arrivalHarborDistrict: number;
/**
* 创建时间
*/
createTime: Date;
/**
* 起运港
*/
departureHarborDistrict: string;
/**
* 编号
*/
id: number;
/**
* 货物类型装货
*/
loadingCargoCategory: number;
/**
* 货物名称装货
*/
loadingCargoName: string;
/**
* 货物吨数装货
*/
loadingCargoTonnage: number;
/**
* 装货/卸货
*/
operationType: number;
/**
* 计划靠泊时间
*/
plannedBerthTime: Date;
/**
* 计划离泊时间
*/
plannedDepartureTime: Date;
/**
* 未使用岸电原因
*/
reason?: number;
/**
* 备注
*/
remark?: string;
/**
* 船舶编号
*/
shipId: number;
/**
* 申请状态
*/
status: number;
/**
* 内贸/外贸
*/
tradeType: number;
/**
* 货物类型(卸货)
*/
unloadingCargoCategory: number;
/**
* 货物名称(卸货)
*/
unloadingCargoName: string;
/**
* 货物吨数(卸货)
*/
unloadingCargoTonnage: number;
/**
* 航次
*/
voyage: string;
[property: string]: any;
}
usageRecordInfo?: {
/**
* 实际靠泊时间
*/
actualBerthTime?: Date;
/**
* 实际离泊时间
*/
actualDepartureTime?: Date;
/**
* 用电申请编号
*/
applyId: number;
/**
* 用电开始时供电方操作人
*/
beginPowerSupplyOperator?: string;
/**
* 用电开始时用电方操作人
*/
beginPowerUsageOperator?: string;
/**
* 用电开始时间
*/
beginTime?: Date;
/**
* 创建时间
*/
createTime: Date;
/**
* 用电结束时间
*/
endTime?: Date;
/**
* 编号
*/
id: number;
/**
* 用电结束时供电方操作人
*/
overPowerSupplyOperator?: string;
/**
* 用电结束时用电方操作人
*/
overPowerUsageOperator?: string;
/**
* 用电结束时间人工读数
*/
powerEndManualReading?: number;
/**
* 用电结束时间系统读数
*/
powerEndSystemReading?: number;
/**
* 用电开始时间人工读数
*/
powerStartManualReading?: number;
/**
* 用电开始时间系统读数
*/
powerStartSystemReading?: number;
/**
* 船舶编号
*/
shipId: number;
/**
* 作业单状态
*/
status: number;
[property: string]: any;
}
shorePower?: {
totalPowerDeviceId: string;
};
}
import { RealtimeDeviceData, ShipRespVo } from '@/types/shorepower';
import { APPLY_STATUS, BERTH_DISTRICT, BERTH_TYPE, CARGO_CATEGORY, DOCK_DISTRICT, getOperationTypeLabel, HARBOR_DISTRICT, OPERATION_TYPE, SHORE_POWER_STATUS, TRADE_TYPE, UNUSED_SHORE_POWER_REASON, WORK_STATUS } from './dictionaryTable';
import { formatTimestamp, getValueById, showStatus } from './utils';
interface Props {
shipData: ShipRespVo[];
realtimeDeviceData: RealtimeDeviceData[];
}
const props = defineProps<Props>()
//
const emit = defineEmits<{
(e: 'switch-ship', ship: ShipDataItem): void;
(e: 'item-click', ship: ShipDataItem): void;
(e: 'switch-ship', ship: ShipRespVo): void;
(e: 'item-click', ship: ShipRespVo): void;
}>()
const localShipData = ref<ShipDataItem[]>([])
const localShipData = ref<(ShipRespVo)[]>([])
const dateRange = ref<[string, string] | []>([])
const statusFilter = ref<string>('all') // 'all', 'using', 'not-using'
//
const detailDialogVisible = ref(false)
//
const selectedShip = ref<ShipDataItem | null>(null)
const selectedShip = ref<ShipRespVo | null>(null)
// tab
const activeTab = ref('applyInfo')
// API
const berthIdAndNameList = ref<{ id: string, name: string }[]>([])
const dockIdAndNameList = ref<{ id: string, name: string }[]>([])
const harborDistrictIdAndNameList = ref<{ id: string, name: string }[]>([])
const berthIdAndNameList = ref<{ value: number, label: string }[]>([])
const dockIdAndNameList = ref<{ value: number, label: string }[]>([])
const harborDistrictIdAndNameList = ref<{ value: number, label: string }[]>([])
// localShipData
const berthingShips = computed(() => localShipData.value.length)
const shorePowerShips = computed(() => localShipData.value.filter(ship => ship.statusClass === 'status-using').length)
const noShorePowerShips = computed(() => berthingShips.value - shorePowerShips.value)
const shorePowerShips = computed(() => localShipData.value.filter(ship => ship.applyInfo.reason === 0).length)
const noShorePowerShips = computed(() => localShipData.value.filter(ship => ship.applyInfo.reason !== 0).length)
// filteredShipData
const filteredBerthingShips = computed(() => filteredShipData.value.length)
const filteredShorePowerShips = computed(() => filteredShipData.value.filter(ship => ship.statusClass === 'status-using').length)
const filteredNoShorePowerShips = computed(() => filteredBerthingShips.value - filteredShorePowerShips.value)
//
const filteredShipData = computed(() => {
//
let statusFilteredData = localShipData.value;
if (statusFilter.value === 'using') {
statusFilteredData = localShipData.value.filter(ship => ship.statusClass === 'status-using');
statusFilteredData = localShipData.value.filter(ship => ship.applyInfo.reason === 0);
} else if (statusFilter.value === 'not-using') {
statusFilteredData = localShipData.value.filter(ship => ship.statusClass !== 'status-using');
statusFilteredData = localShipData.value.filter(ship => ship.applyInfo.reason !== 0);
}
//
@ -832,42 +698,9 @@ const resetFilter = () => {
};
//
const handleShipClick = (row: ShipDataItem, column: any, event: Event) => {
// emit('switch-ship', row)
emit('item-click', row)
}
// ID
const findNameById = (id: string | number | undefined, list: { id: string, name: string }[]) => {
// undefinednull
if (id === undefined || id === null) {
return '-';
}
//
const idStr = id.toString();
const item = list.find(item => item.id == idStr)
return item ? item.name : idStr // ID
}
// 使
const getReasonText = (reason: number | undefined) => {
if (reason === undefined) return '-';
//
const reasonMap: Record<number, string> = {
1: '岸电用电接口不匹配',
2: '岸电设施电压/频率不匹配',
3: '电缆长度不匹配',
4: '气象因素禁止作业',
5: '船电设施损坏',
6: '岸电设施维护中',
7: '无受电设备',
8: '拒绝使用岸电',
9: '其他'
}
return reasonMap[reason] || reason.toString()
const handleClickShipItem = (row: ShipRespVo) => {
console.log(row)
selectedShip.value = row
}
//
@ -875,142 +708,8 @@ const formatDateTime = (timestamp: string | number | Date | undefined) => {
if (!timestamp) return '-';
return dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss');
}
const showStatus = async (ship: ShipDataItem) => {
const { usageRecordInfo, applyInfo } = ship;
if (applyInfo && applyInfo.reason !== undefined && applyInfo.reason == 0 && usageRecordInfo && usageRecordInfo.beginTime) {
const start = new Date(usageRecordInfo.beginTime);
const end = usageRecordInfo.endTime ? new Date(usageRecordInfo.endTime) : new Date();
//
if (isNaN(start.getTime()) || isNaN(end.getTime())) {
return null;
}
//
if (end < start) {
return null; //
}
//
const diffMs = end.getTime() - start.getTime();
//
const totalSeconds = Math.floor(diffMs / 1000);
const hours = Math.floor(totalSeconds / 3600);
const minutes = Math.floor((totalSeconds % 3600) / 60);
const seconds = totalSeconds % 60;
let useValue = 0;
//
const hasEndReading = usageRecordInfo.powerEndManualReading || usageRecordInfo.powerEndSystemReading;
if (hasEndReading) {
// 使
//
const manualDiff = usageRecordInfo.powerStartManualReading !== undefined && usageRecordInfo.powerEndManualReading !== undefined
? usageRecordInfo.powerEndManualReading - usageRecordInfo.powerStartManualReading
: null;
//
const systemDiff = usageRecordInfo.powerStartSystemReading !== undefined && usageRecordInfo.powerEndSystemReading !== undefined
? usageRecordInfo.powerEndSystemReading - usageRecordInfo.powerStartSystemReading
: null;
// 使0
useValue = manualDiff ?? systemDiff ?? 0;
} else {
// 使
const deviceId = ship.shorePower?.totalPowerDeviceId;
if (deviceId) {
try {
// API
const realtimeData = await MapApi.getRealtimeDataByIdList({ ids: deviceId });
if (realtimeData && realtimeData.length > 0) {
const measureValue = realtimeData[0].measureValue;
// 使
const startReading = usageRecordInfo.powerStartManualReading ?? usageRecordInfo.powerStartSystemReading ?? 0;
useValue = measureValue - startReading;
}
} catch (error) {
console.error('获取实时数据失败:', error);
useValue = 0;
}
}
}
return {
statusClass: 'status-using',
status: `使用岸电${hours}小时${minutes}分钟${seconds}秒,${useValue.toFixed(2)}kWH`
}
} else if (applyInfo && applyInfo.reason !== undefined && applyInfo.reason != 0) {
// -
const statusMap: Record<string, { text: string; colorType: string }> = {
'1': { text: '岸电用电接口不匹配', colorType: 'default' },
'2': { text: '岸电设施电压/频率不匹配', colorType: 'success' },
'3': { text: '电缆长度不匹配', colorType: 'success' },
'4': { text: '气象因素禁止作业', colorType: 'success' },
'5': { text: '船电设施损坏', colorType: 'warning' },
'6': { text: '岸电设施维护中', colorType: 'warning' },
'7': { text: '无受电设备', colorType: 'danger' },
'8': { text: '拒绝使用岸电', colorType: 'danger' },
'9': { text: '其他', colorType: 'danger' }
}
const reasonKey = applyInfo.reason!.toString()
const statusInfo = statusMap[reasonKey] || { text: applyInfo.reason!, colorType: 'default' }
//
let statusClass = 'status-cable'
switch (statusInfo.colorType) {
case 'danger':
statusClass = 'status-danger'
break
case 'warning':
statusClass = 'status-warning'
break
case 'success':
statusClass = 'status-success'
break
default:
statusClass = 'status-cable'
}
return {
statusClass: statusClass,
status: statusInfo.text
}
} else {
return {
statusClass: '',
status: 'unknown'
}
}
}
const buildData = async (ship: ShipDataItem) => {
// const { name, wharf, berth, status, statusClass, usageRecordInfo } = ship;
const statusResult = await showStatus(ship) || {};
const { statusClass, status } = statusResult;
return {
applyInfo: ship.applyInfo,
usageRecordInfo: ship.usageRecordInfo,
shipBasicInfo: ship.shipBasicInfo,
name: ship?.shipBasicInfo?.name,
wharf: findNameById(ship.applyInfo?.arrivalDock.toString(), dockIdAndNameList.value),
berth: findNameById(ship.applyInfo?.arrivalBerth.toString(), berthIdAndNameList.value),
beginTime: ship.usageRecordInfo?.beginTime,
endTime: ship.usageRecordInfo?.endTime,
departureHarborDistrict: ship.applyInfo?.departureHarborDistrict,
arrivalHarborDistrict: findNameById(ship.applyInfo?.arrivalHarborDistrict.toString(), harborDistrictIdAndNameList.value),
status: status,
statusClass: statusClass,
}
}
//
const showDetail = (row: ShipDataItem) => {
const showDetail = (row: ShipRespVo) => {
console.log('first')
selectedShip.value = row
detailDialogVisible.value = true
@ -1018,12 +717,11 @@ const showDetail = (row: ShipDataItem) => {
onMounted(async () => {
// API
berthIdAndNameList.value = await MapApi.getBerthIdAndNameList()
dockIdAndNameList.value = await MapApi.getDockIdAndNameList()
harborDistrictIdAndNameList.value = await MapApi.getHarborDistrictIdAndNameList()
berthIdAndNameList.value = await BERTH_DISTRICT()
dockIdAndNameList.value = await DOCK_DISTRICT()
harborDistrictIdAndNameList.value = await HARBOR_DISTRICT()
console.log('props.shipData', props.shipData)
// 使Promise.all
localShipData.value = await Promise.all(props.shipData.map(ship => buildData(ship)));
localShipData.value = props.shipData
})
</script>

10
public/map/components/ShorePowerUsage.vue

@ -849,16 +849,14 @@ const getHistoryChartData = (cardId: string): ChartDataItem[] => {
}
//
const timeRange = ref<'realtime' | 'day' | 'week' | 'month' | 'quarter' | 'year'>('realtime')
const timeRange = ref<'realtime' | 'day' | 'month' | 'quarter' | 'year'>('day')
//
const timeRangeOptions = [
{ value: 'realtime', label: '总' },
{ value: 'day', label: '本日' },
{ value: 'week', label: '本周' },
{ value: 'month', label: '本月' },
// { value: 'quarter', label: '' },
{ value: 'year', label: '本年' }
{ value: 'year', label: '本年' },
{ value: 'realtime', label: '总' },
]
//
@ -1168,7 +1166,7 @@ onBeforeUnmount(() => {
}
.magnify {
width: 100%;
width: 40%;
padding: 12px;
height: calc(100vh - 72px);
position: absolute;

6
public/map/components/cesiumMap.vue

@ -915,7 +915,7 @@ onMounted(async () => {
position: labelPosition, // 10
label: {
text: dataObj.name || `Marker-${item.id || index}`,
font: '16px sans-serif',
font: '22px sans-serif',
fillColor: Cesium.Color.WHITE,
outlineColor: Cesium.Color.BLACK,
outlineWidth: 2,
@ -1036,9 +1036,9 @@ onMounted(async () => {
viewer.entities.add({
// 使 3D
position: labelPosition,
name: '岸电箱 Label',
name: '配电室',
label: {
text: '岸电箱',
text: '配电室',
font: '24px sans-serif',
fillColor: Cesium.Color.WHITE,
outlineColor: Cesium.Color.BLACK,

9
public/map/components/dictionaryTable.ts

@ -60,6 +60,15 @@ export const DOCK_DISTRICT = async () => {
value: item.id
}))
}
// 泊位map
export const BERTH_DISTRICT = async () => {
const res = await MapApi.getBerthIdAndNameList()
return res.map(item => ({
...item,
label: item.name,
value: item.id
}))
}
// 岸电状态
export const SHORE_POWER_STATUS = [

98
public/map/index.vue

@ -24,28 +24,29 @@
</div>
<!-- 港区概览 -->
<template v-if="activeHeadGroup === 0">
<PortOverview :ship-status-data="shipStatusData" :shore-power-status-data="shorePowerStatusData"
@item-click="handleSwitch" :realtime-device-data="realtimeDeviceData" :shore-power-list="ShorePowerList"
:ship-data-list="shipDataList" />
</template>
<!-- <template v-if="activeHeadGroup === 0"> -->
<!-- <PortOverview v-show="activeHeadGroup === 0" :ship-status-data="shipStatusData"
:shore-power-status-data="shorePowerStatusData" @item-click="handleSwitch"
:realtime-device-data="realtimeDeviceData" :shore-power-list="ShorePowerList" :ship-data-list="shipDataList" /> -->
<!-- </template> -->
<!-- 港口岸电使用情况 -->
<!-- <template v-if="activeHeadGroup === 1"> -->
<ShorePowerUsage v-show="activeHeadGroup === 1" :realtime-device-data="realtimeDeviceData"
:active-head-group="activeHeadGroup" />
:active-head-group="activeHeadGroup" v-if="dataLoad" />
<!-- </template> -->
<!-- 港口企业岸电使用 -->
<!-- <template v-if="activeHeadGroup === 2"> -->
<CompanyShorePower v-show="activeHeadGroup === 2" :companyComparisonData="companyComparisonData"
:realtime-device-data="realtimeDeviceData" />
<CompanyShorePower v-show="activeHeadGroup === 2" :realtime-device-data="realtimeDeviceData"
:shore-power-list="ShorePowerList" />
<!-- </template> -->
<!-- 船舶岸电使用情况 -->
<template v-if="activeHeadGroup === 3">
<ShipShorePower :ship-data="shipDataList" :selected-ship="selectedShip" @item-click="handleSwitch" />
</template>
<!-- <template > -->
<ShipShorePower v-show="activeHeadGroup === 3" :ship-data="shipDataList" :selected-ship="selectedShip"
@item-click="handleSwitch" :realtime-device-data="realtimeDeviceData" v-if="dataLoad" />
<!-- </template> -->
<template v-if="activeHeadGroup === 4">
<div v-if="selectedElectricalBox.type" class="right" style="width: 20%">
@ -247,7 +248,7 @@ import { formatDuration, formatTimestamp, getValueById, showStatus } from './com
defineOptions({ name: 'PublicMap' })
let getRealtimeIntervalId: NodeJS.Timeout | null = null
const headGroupList = ref<{ value: number, label: string }[]>([
{ value: 0, label: '港区概览' },
// { value: 0, label: '' },
{ value: 1, label: '港口岸电使用情况' },
{ value: 2, label: '港口企业岸电使用' },
{ value: 3, label: '船舶岸电使用情况' },
@ -629,79 +630,6 @@ watch(
{ deep: true }
)
// 使
const companyComparisonData = ref([
{
name: '华能码头',
value: 234277.33,
children: [
{ name: '1泊位', value: 80000 },
{ name: '2泊位', value: 60000 },
{ name: '3泊位', value: 40000 },
{ name: '4泊位', value: 30000 },
{ name: '5泊位', value: 24277.33 }
]
},
{
name: '国投码头',
value: 417203.39,
children: [
{ name: '101泊位', value: 150000 },
{ name: '102泊位', value: 100000 },
{ name: '103泊位', value: 80000 },
{ name: '104泊位', value: 50000 },
{ name: '105泊位', value: 37203.39 },
{ name: '106泊位', value: 5433 },
{ name: '107泊位', value: 34567 },
{ name: '108泊位', value: 50000 },
{ name: '109泊位', value: 50000 },
{ name: '110泊位', value: 50000 },
]
},
{
name: '华电码头(储运)',
value: 191340.14,
children: [
{ name: '11泊位', value: 80000 },
{ name: '12泊位', value: 60000 },
{ name: '13泊位', value: 40000 },
{ name: '14泊位', value: 30000 },
{ name: '15泊位', value: 24277.33 }
]
}
])
//
const selectedCompany = ref('华能码头')
//
const pieChartData = ref<Array<{ name: string; value: number }>>([])
//
onMounted(async () => {
//
const defaultCompany = companyComparisonData.value.find(company => company.name === selectedCompany.value)
if (defaultCompany && defaultCompany.children) {
pieChartData.value = defaultCompany.children
}
/* console.log('totalPowerDeviceId', totalPowerDeviceId.value)
const deviceStatus = await MapApi.getDeviceStatusByIds(totalPowerDeviceId.value)
console.log('deviceStatus', deviceStatus) */
})
const totalPowerDeviceId = computed(() => {
if (!mapComponentRef.value || !mapComponentRef.value.dataWithModels) {
return []
}
const ids = mapComponentRef.value.dataWithModels
.filter(item => item.modelType === 'ship')
.map(item => item.shorePower?.totalPowerDeviceId)
.filter(id => id !== undefined && id !== null)
//
return [...new Set(ids)]
})
//
const shorePowerStatusData = computed(() => {
if (!mapComponentRef.value || !mapComponentRef.value.dataWithModels) {

5
src/types/shorepower.d.ts

@ -11,6 +11,7 @@ interface ShorePowerBerth {
createTime: number // Unix timestamp in milliseconds
shorePowerEquipmentInfo: ShorePowerEquipmentInfo
storePowerStatus?: string
position?: string
}
interface ShorePowerEquipmentInfo {
@ -397,11 +398,11 @@ export interface UsageRecordRespVO {
/**
*
*/
actualBerthTime?: Date
actualBerthTime?: number
/**
*
*/
actualDepartureTime?: number | null | undefined
actualDepartureTime?: number
/**
*
*/

Loading…
Cancel
Save