|
|
|
@ -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 }[]) => { |
|
|
|
// 处理undefined或null值 |
|
|
|
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> |
|
|
|
|
|
|
|
|