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>
<div class="overview-grid"> <div class="overview-grid">
<div v-for="(berth, index) in (company.children || [])" :key="index" class="overview-item" <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) <div class="overview-value">{{ berth.measureValue?.toFixed(2)
|| 0 }}</div> || 0 }}</div>
@ -36,6 +36,70 @@
</div> </div>
</div> </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-history-dialog v-if="historyVisible.visible" v-model="historyVisible.visible"
:ship-param="historyVisible.searchParams" :realtime-device-data="realtimeDeviceData" /> :ship-param="historyVisible.searchParams" :realtime-device-data="realtimeDeviceData" />
</div> </div>
@ -45,9 +109,11 @@
import { ref } from 'vue' import { ref } from 'vue'
import { MapApi } from "@/api/shorepower/map"; import { MapApi } from "@/api/shorepower/map";
import ShipHistoryDialog from './ShipHistoryDialog.vue'; import ShipHistoryDialog from './ShipHistoryDialog.vue';
import { RealtimeDeviceData } from '@/types/shorepower'; import { RealtimeDeviceData, ShorePowerBerth } from '@/types/shorepower';
import { getValueById } from './utils';
// //
interface ChartDataItem { interface ChartDataItem {
id: number;
name: string; name: string;
value?: number; value?: number;
measureValue?: 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[]) => { const calculateTotal = (children?: ChartDataItem[]) => {
if (!children || children.length === 0) return 0; if (!children || children.length === 0) return 0;
@ -71,6 +145,21 @@ const calculateTotal = (children?: ChartDataItem[]) => {
}, 0); }, 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) => { const showShorePowerHistory = (berth: ChartDataItem) => {
console.log(berth) 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 companyComparisonData = ref<ChartDataItem[]>([])
const handleGetBuildData = async () => { const handleGetBuildData = async () => {
const dockList = await MapApi.getDockIdAndNameList() const dockList = await MapApi.getDockIdAndNameList()
@ -107,8 +189,6 @@ const handleGetBuildData = async () => {
...props.realtimeDeviceData.find(item => (item.id === berth.id) && (item.deviceCode.includes('Kwh'))) ...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 companyComparisonData.value = buildData
/* MapApi.getBerthIdAndNameList().then(res => { /* MapApi.getBerthIdAndNameList().then(res => {
console.log(res) console.log(res)

610
public/map/components/ShipShorePower.vue

@ -11,7 +11,7 @@
<div class="overview-grid"> <div class="overview-grid">
<div class="overview-item"> <div class="overview-item">
<div class="overview-value">{{ berthingShips }}</div> <div class="overview-value">{{ berthingShips }}</div>
<div class="overview-label">船舶数量</div> <div class="overview-label">船舶数量</div>
</div> </div>
<div class="overview-item"> <div class="overview-item">
<div class="overview-value">{{ shorePowerShips }}</div> <div class="overview-value">{{ shorePowerShips }}</div>
@ -46,28 +46,46 @@
</div> </div>
<div class="card-content"> <div class="card-content">
<div class="ship-data-table-container"> <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> highlight-current-row>
<el-table-column prop="name" label="船名" /> <el-table-column prop="shipBasicInfo.name" label="船名" />
<el-table-column prop="wharf" label="码头" /> <el-table-column prop="applyInfo.arrivalDock" label="码头">
<el-table-column prop="berth" 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="开始用电时间"> <el-table-column prop="beginTime" label="开始用电时间">
<template #default="scope"> <template #default="scope">
<span>{{ formatDateTime(scope.row.beginTime) }}</span> <span>{{ formatDateTime(scope.row?.usageRecordInfo?.beginTime) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="endTime" label="结束用电时间"> <el-table-column prop="endTime" label="结束用电时间">
<template #default="scope"> <template #default="scope">
<span>{{ formatDateTime(scope.row.endTime) }}</span> <span>{{ formatDateTime(scope.row?.usageRecordInfo?.endTime) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="status" label="岸电状态" width="400"> <el-table-column prop="status" label="岸电状态" width="400">
<template #default="scope"> <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> </template>
</el-table-column> </el-table-column>
<el-table-column prop="departureHarborDistrict" label="起运港" />
<el-table-column prop="arrivalHarborDistrict" label="到达港" />
<el-table-column label="操作" width="100"> <el-table-column label="操作" width="100">
<template #default="scope"> <template #default="scope">
<el-button type="primary" size="small" @click.stop="showDetail(scope.row)">更多</el-button> <el-button type="primary" size="small" @click.stop="showDetail(scope.row)">更多</el-button>
@ -78,8 +96,98 @@
</div> </div>
</div> </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-tabs v-if="selectedShip" v-model="activeTab">
<el-tab-pane label="用电申请信息" name="applyInfo"> <el-tab-pane label="用电申请信息" name="applyInfo">
<el-form :model="selectedShip.applyInfo" label-width="200px"> <el-form :model="selectedShip.applyInfo" label-width="200px">
@ -108,7 +216,8 @@
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="到达港:"> <el-form-item label="到达港:">
<span>{{ findNameById(selectedShip.applyInfo?.arrivalHarborDistrict, harborDistrictIdAndNameList) <span>{{ getOperationTypeLabel(selectedShip.applyInfo?.arrivalHarborDistrict,
harborDistrictIdAndNameList)
}}</span> }}</span>
</el-form-item> </el-form-item>
</el-col> </el-col>
@ -117,12 +226,12 @@
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="到达码头:"> <el-form-item label="到达码头:">
<span>{{ findNameById(selectedShip.applyInfo?.arrivalDock, dockIdAndNameList) }}</span> <span>{{ getOperationTypeLabel(selectedShip.applyInfo?.arrivalDock, dockIdAndNameList) }}</span>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="到达泊位:"> <el-form-item label="到达泊位:">
<span>{{ findNameById(selectedShip.applyInfo?.arrivalBerth, berthIdAndNameList) }}</span> <span>{{ getOperationTypeLabel(selectedShip.applyInfo?.arrivalBerth, berthIdAndNameList) }}</span>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -164,7 +273,7 @@
<el-col :span="12"> <el-col :span="12">
<el-form-item label="货物类型(装货):"> <el-form-item label="货物类型(装货):">
<span>{{ getOperationTypeLabel(selectedShip.applyInfo?.loadingCargoCategory, CARGO_CATEGORY) || '-' <span>{{ getOperationTypeLabel(selectedShip.applyInfo?.loadingCargoCategory, CARGO_CATEGORY) || '-'
}}</span> }}</span>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@ -186,7 +295,7 @@
<el-col :span="12"> <el-col :span="12">
<el-form-item label="货物类型(卸货):"> <el-form-item label="货物类型(卸货):">
<span>{{ getOperationTypeLabel(selectedShip.applyInfo?.unloadingCargoCategory, CARGO_CATEGORY) || '-' <span>{{ getOperationTypeLabel(selectedShip.applyInfo?.unloadingCargoCategory, CARGO_CATEGORY) || '-'
}}</span> }}</span>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@ -215,7 +324,7 @@
<el-col :span="12" v-if="selectedShip.applyInfo?.reason !== 0"> <el-col :span="12" v-if="selectedShip.applyInfo?.reason !== 0">
<el-form-item label="未使用岸电原因:"> <el-form-item label="未使用岸电原因:">
<span>{{ getOperationTypeLabel(selectedShip.applyInfo?.reason, UNUSED_SHORE_POWER_REASON) || '-' <span>{{ getOperationTypeLabel(selectedShip.applyInfo?.reason, UNUSED_SHORE_POWER_REASON) || '-'
}}</span> }}</span>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -406,13 +515,13 @@
<el-col :span="12"> <el-col :span="12">
<el-form-item label="船舶长度:"> <el-form-item label="船舶长度:">
<span>{{ selectedShip.shipBasicInfo?.length !== undefined ? selectedShip.shipBasicInfo?.length : '-' <span>{{ selectedShip.shipBasicInfo?.length !== undefined ? selectedShip.shipBasicInfo?.length : '-'
}}</span> }}</span>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="船舶宽度:"> <el-form-item label="船舶宽度:">
<span>{{ selectedShip.shipBasicInfo?.width !== undefined ? selectedShip.shipBasicInfo?.width : '-' <span>{{ selectedShip.shipBasicInfo?.width !== undefined ? selectedShip.shipBasicInfo?.width : '-'
}}</span> }}</span>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -421,7 +530,7 @@
<el-col :span="12"> <el-col :span="12">
<el-form-item label="船舶吨位:"> <el-form-item label="船舶吨位:">
<span>{{ selectedShip.shipBasicInfo?.tonnage !== undefined ? selectedShip.shipBasicInfo?.tonnage : '-' <span>{{ selectedShip.shipBasicInfo?.tonnage !== undefined ? selectedShip.shipBasicInfo?.tonnage : '-'
}}</span> }}</span>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@ -481,295 +590,52 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, onMounted } from 'vue' import { ref, computed, onMounted } from 'vue'
import { MapApi } from "@/api/shorepower/map";
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { ShipRespVo } from '@/types/shorepower'; import { RealtimeDeviceData, ShipRespVo } from '@/types/shorepower';
import { APPLY_STATUS, CARGO_CATEGORY, getOperationTypeLabel, OPERATION_TYPE, TRADE_TYPE, UNUSED_SHORE_POWER_REASON, WORK_STATUS } from './dictionaryTable'; 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 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;
};
}
interface Props { interface Props {
shipData: ShipRespVo[]; shipData: ShipRespVo[];
realtimeDeviceData: RealtimeDeviceData[];
} }
const props = defineProps<Props>() const props = defineProps<Props>()
// //
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'switch-ship', ship: ShipDataItem): void; (e: 'switch-ship', ship: ShipRespVo): void;
(e: 'item-click', ship: ShipDataItem): void; (e: 'item-click', ship: ShipRespVo): void;
}>() }>()
const localShipData = ref<ShipDataItem[]>([]) const localShipData = ref<(ShipRespVo)[]>([])
const dateRange = ref<[string, string] | []>([]) const dateRange = ref<[string, string] | []>([])
const statusFilter = ref<string>('all') // 'all', 'using', 'not-using' const statusFilter = ref<string>('all') // 'all', 'using', 'not-using'
// //
const detailDialogVisible = ref(false) const detailDialogVisible = ref(false)
// //
const selectedShip = ref<ShipDataItem | null>(null) const selectedShip = ref<ShipRespVo | null>(null)
// tab // tab
const activeTab = ref('applyInfo') const activeTab = ref('applyInfo')
// API // API
const berthIdAndNameList = ref<{ id: string, name: string }[]>([]) const berthIdAndNameList = ref<{ value: number, label: string }[]>([])
const dockIdAndNameList = ref<{ id: string, name: string }[]>([]) const dockIdAndNameList = ref<{ value: number, label: string }[]>([])
const harborDistrictIdAndNameList = ref<{ id: string, name: string }[]>([]) const harborDistrictIdAndNameList = ref<{ value: number, label: string }[]>([])
// localShipData // localShipData
const berthingShips = computed(() => localShipData.value.length) const berthingShips = computed(() => localShipData.value.length)
const shorePowerShips = computed(() => localShipData.value.filter(ship => ship.statusClass === 'status-using').length) const shorePowerShips = computed(() => localShipData.value.filter(ship => ship.applyInfo.reason === 0).length)
const noShorePowerShips = computed(() => berthingShips.value - shorePowerShips.value) 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(() => { const filteredShipData = computed(() => {
// //
let statusFilteredData = localShipData.value; let statusFilteredData = localShipData.value;
if (statusFilter.value === 'using') { 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') { } 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) => { const handleClickShipItem = (row: ShipRespVo) => {
// emit('switch-ship', row) console.log(row)
emit('item-click', row) selectedShip.value = 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()
} }
// //
@ -875,142 +708,8 @@ const formatDateTime = (timestamp: string | number | Date | undefined) => {
if (!timestamp) return '-'; if (!timestamp) return '-';
return dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss'); 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') console.log('first')
selectedShip.value = row selectedShip.value = row
detailDialogVisible.value = true detailDialogVisible.value = true
@ -1018,12 +717,11 @@ const showDetail = (row: ShipDataItem) => {
onMounted(async () => { onMounted(async () => {
// API // API
berthIdAndNameList.value = await MapApi.getBerthIdAndNameList() berthIdAndNameList.value = await BERTH_DISTRICT()
dockIdAndNameList.value = await MapApi.getDockIdAndNameList() dockIdAndNameList.value = await DOCK_DISTRICT()
harborDistrictIdAndNameList.value = await MapApi.getHarborDistrictIdAndNameList() harborDistrictIdAndNameList.value = await HARBOR_DISTRICT()
console.log('props.shipData', props.shipData) console.log('props.shipData', props.shipData)
// 使Promise.all localShipData.value = props.shipData
localShipData.value = await Promise.all(props.shipData.map(ship => buildData(ship)));
}) })
</script> </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 = [ const timeRangeOptions = [
{ value: 'realtime', label: '总' },
{ value: 'day', label: '本日' }, { value: 'day', label: '本日' },
{ value: 'week', label: '本周' },
{ value: 'month', label: '本月' }, { value: 'month', label: '本月' },
// { value: 'quarter', label: '' }, { value: 'year', label: '本年' },
{ value: 'year', label: '本年' } { value: 'realtime', label: '总' },
] ]
// //
@ -1168,7 +1166,7 @@ onBeforeUnmount(() => {
} }
.magnify { .magnify {
width: 100%; width: 40%;
padding: 12px; padding: 12px;
height: calc(100vh - 72px); height: calc(100vh - 72px);
position: absolute; position: absolute;

6
public/map/components/cesiumMap.vue

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

9
public/map/components/dictionaryTable.ts

@ -60,6 +60,15 @@ export const DOCK_DISTRICT = async () => {
value: item.id 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 = [ export const SHORE_POWER_STATUS = [

98
public/map/index.vue

@ -24,28 +24,29 @@
</div> </div>
<!-- 港区概览 --> <!-- 港区概览 -->
<template v-if="activeHeadGroup === 0"> <!-- <template v-if="activeHeadGroup === 0"> -->
<PortOverview :ship-status-data="shipStatusData" :shore-power-status-data="shorePowerStatusData" <!-- <PortOverview v-show="activeHeadGroup === 0" :ship-status-data="shipStatusData"
@item-click="handleSwitch" :realtime-device-data="realtimeDeviceData" :shore-power-list="ShorePowerList" :shore-power-status-data="shorePowerStatusData" @item-click="handleSwitch"
:ship-data-list="shipDataList" /> :realtime-device-data="realtimeDeviceData" :shore-power-list="ShorePowerList" :ship-data-list="shipDataList" /> -->
</template> <!-- </template> -->
<!-- 港口岸电使用情况 --> <!-- 港口岸电使用情况 -->
<!-- <template v-if="activeHeadGroup === 1"> --> <!-- <template v-if="activeHeadGroup === 1"> -->
<ShorePowerUsage v-show="activeHeadGroup === 1" :realtime-device-data="realtimeDeviceData" <ShorePowerUsage v-show="activeHeadGroup === 1" :realtime-device-data="realtimeDeviceData"
:active-head-group="activeHeadGroup" /> :active-head-group="activeHeadGroup" v-if="dataLoad" />
<!-- </template> --> <!-- </template> -->
<!-- 港口企业岸电使用 --> <!-- 港口企业岸电使用 -->
<!-- <template v-if="activeHeadGroup === 2"> --> <!-- <template v-if="activeHeadGroup === 2"> -->
<CompanyShorePower v-show="activeHeadGroup === 2" :companyComparisonData="companyComparisonData" <CompanyShorePower v-show="activeHeadGroup === 2" :realtime-device-data="realtimeDeviceData"
:realtime-device-data="realtimeDeviceData" /> :shore-power-list="ShorePowerList" />
<!-- </template> --> <!-- </template> -->
<!-- 船舶岸电使用情况 --> <!-- 船舶岸电使用情况 -->
<template v-if="activeHeadGroup === 3"> <!-- <template > -->
<ShipShorePower :ship-data="shipDataList" :selected-ship="selectedShip" @item-click="handleSwitch" /> <ShipShorePower v-show="activeHeadGroup === 3" :ship-data="shipDataList" :selected-ship="selectedShip"
</template> @item-click="handleSwitch" :realtime-device-data="realtimeDeviceData" v-if="dataLoad" />
<!-- </template> -->
<template v-if="activeHeadGroup === 4"> <template v-if="activeHeadGroup === 4">
<div v-if="selectedElectricalBox.type" class="right" style="width: 20%"> <div v-if="selectedElectricalBox.type" class="right" style="width: 20%">
@ -247,7 +248,7 @@ import { formatDuration, formatTimestamp, getValueById, showStatus } from './com
defineOptions({ name: 'PublicMap' }) defineOptions({ name: 'PublicMap' })
let getRealtimeIntervalId: NodeJS.Timeout | null = null let getRealtimeIntervalId: NodeJS.Timeout | null = null
const headGroupList = ref<{ value: number, label: string }[]>([ const headGroupList = ref<{ value: number, label: string }[]>([
{ value: 0, label: '港区概览' }, // { value: 0, label: '' },
{ value: 1, label: '港口岸电使用情况' }, { value: 1, label: '港口岸电使用情况' },
{ value: 2, label: '港口企业岸电使用' }, { value: 2, label: '港口企业岸电使用' },
{ value: 3, label: '船舶岸电使用情况' }, { value: 3, label: '船舶岸电使用情况' },
@ -629,79 +630,6 @@ watch(
{ deep: true } { 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(() => { const shorePowerStatusData = computed(() => {
if (!mapComponentRef.value || !mapComponentRef.value.dataWithModels) { if (!mapComponentRef.value || !mapComponentRef.value.dataWithModels) {

5
src/types/shorepower.d.ts

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

Loading…
Cancel
Save