You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1356 lines
42 KiB

<template>
<div class="ship-shore-power">
4 weeks ago
<div class="left" style="width: 70%;">
<div class="card digital-twin-card--deep-blue" style="flex: 1;">
<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="overview-grid">
<div class="overview-item">
<div class="overview-value">{{ berthingShips }}</div>
<div class="overview-label">在泊船舶数量</div>
</div>
<div class="overview-item">
<div class="overview-value">{{ shorePowerShips }}</div>
<div class="overview-label">使用岸电船舶数量</div>
</div>
<div class="overview-item">
<div class="overview-value">{{ noShorePowerShips }}</div>
<div class="overview-label">未使用岸电船舶数量</div>
</div>
</div>
</div>
</div>
4 weeks ago
<div class="card digital-twin-card--deep-blue" style="flex: 3;">
<div class="card-title data-card-title">
<div class="title-section">
<div class="vertical-line"></div>
<img src="@/assets/svgs/data.svg" class="title-icon" />
<span class="title-text">数据</span>
</div>
<div class="filter-controls">
<el-select v-model="statusFilter" placeholder="状态筛选" style="width: 120px; margin-right: 10px;"
@change="handleStatusFilterChange">
<el-option label="全部" value="all" />
<el-option label="使用岸电" value="using" />
<el-option label="未使用岸电" value="not-using" />
</el-select>
<el-date-picker v-model="dateRange" type="daterange" range-separator="" start-placeholder="开始日期"
end-placeholder="结束日期" format="YYYY-MM-DD" value-format="YYYY-MM-DD" @change="handleDateRangeChange"
class="date-range-picker" />
<el-button @click="resetFilter" style="margin-left: 10px;">重置筛选</el-button>
</div>
</div>
<div class="card-content">
1 month ago
<div class="ship-data-table-container">
4 weeks ago
<el-table :data="filteredShipData" class="ship-data-table" @row-click="handleShipClick"
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="beginTime" label="开始用电时间">
<template #default="scope">
<span>{{ formatDateTime(scope.row.beginTime) }}</span>
</template>
</el-table-column>
<el-table-column prop="endTime" label="结束用电时间">
<template #default="scope">
<span>{{ formatDateTime(scope.row.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>
</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>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</div>
4 weeks ago
<!-- 船舶详情对话框 -->
<el-dialog 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">
4 weeks ago
<!-- 船舶代理信息 -->
<h3>船舶代理信息</h3>
4 weeks ago
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="船方代理单位:">
<span>{{ selectedShip.applyInfo?.agentCompany || '-' }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="代理人联系方式:">
<span>{{ selectedShip.applyInfo?.agentContact || '-' }}</span>
</el-form-item>
</el-col>
</el-row>
4 weeks ago
<!-- 航行计划信息 -->
<h3>航行计划信息</h3>
4 weeks ago
<el-row :gutter="20">
<el-col :span="12">
4 weeks ago
<el-form-item label="起运港:">
<span>{{ selectedShip.applyInfo?.departureHarborDistrict || '-' }}</span>
4 weeks ago
</el-form-item>
</el-col>
<el-col :span="12">
4 weeks ago
<el-form-item label="到达港:">
<span>{{ findNameById(selectedShip.applyInfo?.arrivalHarborDistrict, harborDistrictIdAndNameList)
}}</span>
4 weeks ago
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="到达码头:">
<span>{{ findNameById(selectedShip.applyInfo?.arrivalDock, dockIdAndNameList) }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
4 weeks ago
<el-form-item label="到达泊位:">
<span>{{ findNameById(selectedShip.applyInfo?.arrivalBerth, berthIdAndNameList) }}</span>
4 weeks ago
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
4 weeks ago
<el-form-item label="计划靠泊时间:">
<span>{{ selectedShip.applyInfo?.plannedBerthTime ? new
Date(selectedShip.applyInfo.plannedBerthTime).toLocaleString() : '-' }}</span>
4 weeks ago
</el-form-item>
</el-col>
4 weeks ago
<el-col :span="12">
<el-form-item label="计划离泊时间:">
<span>{{ selectedShip.applyInfo?.plannedDepartureTime ? new
Date(selectedShip.applyInfo.plannedDepartureTime).toLocaleString() : '-' }}</span>
4 weeks ago
</el-form-item>
4 weeks ago
</el-col>
4 weeks ago
</el-row>
<el-row :gutter="20">
<el-col :span="12">
4 weeks ago
<el-form-item label="航次:">
<span>{{ selectedShip.applyInfo?.voyage || '-' }}</span>
4 weeks ago
</el-form-item>
</el-col>
4 weeks ago
</el-row>
<!-- 货物信息 -->
<h3>货物信息</h3>
<el-row :gutter="20">
4 weeks ago
<el-col :span="12">
4 weeks ago
<el-form-item label="装货/卸货:">
<span>{{ getOperationTypeLabel(selectedShip.applyInfo?.operationType, OPERATION_TYPE) || '-' }}</span>
4 weeks ago
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
4 weeks ago
<el-form-item label="货物类型(装货):">
<span>{{ getOperationTypeLabel(selectedShip.applyInfo?.loadingCargoCategory, CARGO_CATEGORY) || '-'
}}</span>
4 weeks ago
</el-form-item>
</el-col>
<el-col :span="12">
4 weeks ago
<el-form-item label="货物名称(装货):">
<span>{{ selectedShip.applyInfo?.loadingCargoName || '-' }}</span>
4 weeks ago
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
4 weeks ago
<el-form-item label="货物吨数(装货):">
<span>{{ selectedShip.applyInfo?.loadingCargoTonnage || '-' }}</span>
4 weeks ago
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
4 weeks ago
<el-form-item label="货物类型(卸货):">
<span>{{ getOperationTypeLabel(selectedShip.applyInfo?.unloadingCargoCategory, CARGO_CATEGORY) || '-'
}}</span>
4 weeks ago
</el-form-item>
</el-col>
4 weeks ago
<el-col :span="12">
<el-form-item label="货物名称(卸货):">
<span>{{ selectedShip.applyInfo?.unloadingCargoName || '-' }}</span>
4 weeks ago
</el-form-item>
4 weeks ago
</el-col>
4 weeks ago
</el-row>
<el-row :gutter="20">
<el-col :span="12">
4 weeks ago
<el-form-item label="货物吨数(卸货):">
<span>{{ selectedShip.applyInfo?.unloadingCargoTonnage || '-' }}</span>
4 weeks ago
</el-form-item>
</el-col>
</el-row>
4 weeks ago
<!-- 岸电申请状态 -->
<h3>岸电申请状态</h3>
4 weeks ago
<el-row :gutter="20">
<el-col :span="12">
4 weeks ago
<el-form-item label="是否申请使用岸电:">
<span>{{ selectedShip.applyInfo?.applyShorePower ? '是' : '否' }}</span>
4 weeks ago
</el-form-item>
</el-col>
4 weeks ago
<el-col :span="12" v-if="selectedShip.applyInfo?.reason !== 0">
<el-form-item label="未使用岸电原因:">
<span>{{ getOperationTypeLabel(selectedShip.applyInfo?.reason, UNUSED_SHORE_POWER_REASON) || '-'
}}</span>
4 weeks ago
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
4 weeks ago
<el-form-item label="申请状态:">
<span>{{ getOperationTypeLabel(selectedShip.applyInfo?.status, APPLY_STATUS) || '-' }}</span>
4 weeks ago
</el-form-item>
</el-col>
<el-col :span="12">
4 weeks ago
<el-form-item label="内贸/外贸:">
<span>{{ getOperationTypeLabel(selectedShip.applyInfo?.tradeType, TRADE_TYPE) || '-' }}</span>
4 weeks ago
</el-form-item>
</el-col>
</el-row>
4 weeks ago
<!-- 其他信息 -->
<h3>其他信息</h3>
4 weeks ago
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="创建时间:">
<span>{{ selectedShip.applyInfo?.createTime ? new
Date(selectedShip.applyInfo.createTime).toLocaleString()
: '-' }}</span>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-tab-pane>
<el-tab-pane label="船舶用电信息" name="usageRecordInfo">
<el-form :model="selectedShip.usageRecordInfo" label-width="200px">
4 weeks ago
<!-- 用电时间信息 -->
<h3>用电时间信息</h3>
4 weeks ago
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="实际靠泊时间:">
<span>{{ formatDateTime(selectedShip.usageRecordInfo?.actualBerthTime) }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="实际离泊时间:">
<span>{{ formatDateTime(selectedShip.usageRecordInfo?.actualDepartureTime) }}</span>
</el-form-item>
</el-col>
</el-row>
4 weeks ago
<el-row :gutter="20">
4 weeks ago
<el-col :span="12">
4 weeks ago
<el-form-item label="用电开始时间:">
<span>{{ formatDateTime(selectedShip.usageRecordInfo?.beginTime) }}</span>
4 weeks ago
</el-form-item>
</el-col>
<el-col :span="12">
4 weeks ago
<el-form-item label="用电结束时间:">
<span>{{ formatDateTime(selectedShip.usageRecordInfo?.endTime) }}</span>
4 weeks ago
</el-form-item>
</el-col>
4 weeks ago
</el-row>
4 weeks ago
4 weeks ago
<!-- 电量读数信息 -->
<h3>电量读数信息</h3>
4 weeks ago
<el-row :gutter="20">
4 weeks ago
<el-col :span="12">
<el-form-item label="用电开始时间人工读数:">
<span>{{ selectedShip.usageRecordInfo?.powerStartManualReading !== undefined ?
selectedShip.usageRecordInfo?.powerStartManualReading : '-' }}</span>
4 weeks ago
</el-form-item>
4 weeks ago
</el-col>
4 weeks ago
<el-col :span="12">
4 weeks ago
<el-form-item label="用电开始时间系统读数:">
<span>{{ selectedShip.usageRecordInfo?.powerStartSystemReading !== undefined ?
selectedShip.usageRecordInfo?.powerStartSystemReading : '-' }}</span>
4 weeks ago
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
4 weeks ago
<el-col :span="12">
<el-form-item label="用电结束时间人工读数:">
<span>{{ selectedShip.usageRecordInfo?.powerEndManualReading !== undefined ?
selectedShip.usageRecordInfo?.powerEndManualReading : '-' }}</span>
4 weeks ago
</el-form-item>
4 weeks ago
</el-col>
4 weeks ago
<el-col :span="12">
4 weeks ago
<el-form-item label="用电结束时间系统读数:">
<span>{{ selectedShip.usageRecordInfo?.powerEndSystemReading !== undefined ?
selectedShip.usageRecordInfo?.powerEndSystemReading : '-' }}</span>
4 weeks ago
</el-form-item>
</el-col>
</el-row>
4 weeks ago
<!-- 操作人员信息 -->
<h3>操作人员信息</h3>
<el-row :gutter="20">
4 weeks ago
<el-col :span="12">
4 weeks ago
<el-form-item label="用电开始时供电方操作人:">
<span>{{ selectedShip.usageRecordInfo?.beginPowerSupplyOperator || '-' }}</span>
4 weeks ago
</el-form-item>
</el-col>
<el-col :span="12">
4 weeks ago
<el-form-item label="用电开始时用电方操作人:">
<span>{{ selectedShip.usageRecordInfo?.beginPowerUsageOperator || '-' }}</span>
4 weeks ago
</el-form-item>
</el-col>
4 weeks ago
</el-row>
4 weeks ago
4 weeks ago
<el-row :gutter="20">
4 weeks ago
<el-col :span="12">
4 weeks ago
<el-form-item label="用电结束时供电方操作人:">
<span>{{ selectedShip.usageRecordInfo?.overPowerSupplyOperator || '-' }}</span>
4 weeks ago
</el-form-item>
</el-col>
<el-col :span="12">
4 weeks ago
<el-form-item label="用电结束时用电方操作人:">
<span>{{ selectedShip.usageRecordInfo?.overPowerUsageOperator || '-' }}</span>
4 weeks ago
</el-form-item>
</el-col>
4 weeks ago
</el-row>
4 weeks ago
4 weeks ago
<!-- 状态信息 -->
<h3>状态信息</h3>
4 weeks ago
<el-row :gutter="20">
<el-col :span="12">
4 weeks ago
<el-form-item label="作业单状态:">
<span>{{ getOperationTypeLabel(selectedShip.usageRecordInfo?.status, WORK_STATUS) || '-' }}</span>
4 weeks ago
</el-form-item>
</el-col>
</el-row>
4 weeks ago
<!-- 关联信息 -->
<h3>其他信息</h3>
<!-- <el-row :gutter="20">
4 weeks ago
<el-col :span="12">
4 weeks ago
<el-form-item label="用电申请编号:">
<span>{{ selectedShip.usageRecordInfo?.applyId || '-' }}</span>
4 weeks ago
</el-form-item>
</el-col>
4 weeks ago
<el-col :span="12">
4 weeks ago
<el-form-item label="船舶编号:">
<span>{{ selectedShip.usageRecordInfo?.shipId || '-' }}</span>
</el-form-item>
4 weeks ago
</el-col>
</el-row> -->
4 weeks ago
<el-row :gutter="20">
<el-col :span="12">
4 weeks ago
<el-form-item label="创建时间:">
<span>{{ formatDateTime(selectedShip.usageRecordInfo?.createTime) }}</span>
4 weeks ago
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-tab-pane>
<el-tab-pane label="船舶基础信息" name="shipBasicInfo">
<el-form :model="selectedShip.shipBasicInfo" label-width="200px">
4 weeks ago
<!-- 船舶识别信息 -->
<h3>船舶识别信息</h3>
4 weeks ago
<el-row :gutter="20">
<el-col :span="12">
4 weeks ago
<el-form-item label="船名:">
<span>{{ selectedShip.shipBasicInfo?.name || '-' }}</span>
4 weeks ago
</el-form-item>
</el-col>
<el-col :span="12">
4 weeks ago
<el-form-item label="英文船名:">
<span>{{ selectedShip.shipBasicInfo?.nameEn || '-' }}</span>
4 weeks ago
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
4 weeks ago
<el-form-item label="船舶呼号:">
<span>{{ selectedShip.shipBasicInfo?.callSign || '-' }}</span>
4 weeks ago
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="船检登记号:">
<span>{{ selectedShip.shipBasicInfo?.inspectionNo || '-' }}</span>
</el-form-item>
</el-col>
4 weeks ago
</el-row>
<!-- 船舶技术参数 -->
<h3>船舶技术参数</h3>
<el-row :gutter="20">
4 weeks ago
<el-col :span="12">
<el-form-item label="船舶长度:">
<span>{{ selectedShip.shipBasicInfo?.length !== undefined ? selectedShip.shipBasicInfo?.length : '-'
4 weeks ago
}}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="船舶宽度:">
<span>{{ selectedShip.shipBasicInfo?.width !== undefined ? selectedShip.shipBasicInfo?.width : '-'
}}</span>
4 weeks ago
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
4 weeks ago
<el-form-item label="船舶吨位:">
<span>{{ selectedShip.shipBasicInfo?.tonnage !== undefined ? selectedShip.shipBasicInfo?.tonnage : '-'
}}</span>
4 weeks ago
</el-form-item>
</el-col>
<el-col :span="12">
4 weeks ago
<el-form-item label="满载吃水深度:">
<span>{{ selectedShip.shipBasicInfo?.fullLoadDraft !== undefined ?
selectedShip.shipBasicInfo?.fullLoadDraft : '-' }}</span>
4 weeks ago
</el-form-item>
</el-col>
</el-row>
4 weeks ago
<!-- 联系信息 -->
<h3>联系信息</h3>
<el-row :gutter="20">
4 weeks ago
<el-col :span="12">
<el-form-item label="岸电负责人:">
<span>{{ selectedShip.shipBasicInfo?.shorePowerContact || '-' }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系方式:">
<span>{{ selectedShip.shipBasicInfo?.shorePowerContactPhone || '-' }}</span>
</el-form-item>
</el-col>
4 weeks ago
</el-row>
<!-- 运营信息 -->
<h3>运营信息</h3>
<el-row :gutter="20">
4 weeks ago
<el-col :span="12">
4 weeks ago
<el-form-item label="航运单位名称:">
<span>{{ selectedShip.shipBasicInfo?.shippingCompany || '-' }}</span>
4 weeks ago
</el-form-item>
</el-col>
</el-row>
4 weeks ago
<!-- 系统信息 -->
<h3>系统信息</h3>
4 weeks ago
<el-row :gutter="20">
<el-col :span="12">
4 weeks ago
<el-form-item label="创建时间:">
<span>{{ formatDateTime(selectedShip.shipBasicInfo?.createTime) }}</span>
4 weeks ago
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-tab-pane>
</el-tabs>
<template #footer>
<span class="dialog-footer">
<el-button @click="detailDialogVisible = false">关闭</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
4 weeks ago
import { ref, computed, onMounted } from 'vue'
import { MapApi } from "@/api/shorepower/map";
import dayjs from 'dayjs';
4 weeks ago
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;
4 weeks ago
departureHarborDistrict: string;
arrivalHarborDistrict: string;
4 weeks ago
beginTime?: Date;
endTime?: Date;
4 weeks ago
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 {
4 weeks ago
shipData: ShipRespVo[];
}
const props = defineProps<Props>()
4 weeks ago
// 定义组件事件
const emit = defineEmits<{
(e: 'switch-ship', ship: ShipDataItem): void;
(e: 'item-click', ship: ShipDataItem): void;
}>()
const localShipData = ref<ShipDataItem[]>([])
const dateRange = ref<[string, string] | []>([])
const statusFilter = ref<string>('all') // 'all', 'using', 'not-using'
// 控制详情对话框显示
const detailDialogVisible = ref(false)
// 存储当前选中的船舶数据
const selectedShip = ref<ShipDataItem | 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 }[]>([])
// 从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)
// 从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');
} else if (statusFilter.value === 'not-using') {
statusFilteredData = localShipData.value.filter(ship => ship.statusClass !== 'status-using');
}
// 再按日期范围筛选
if (!dateRange.value || dateRange.value.length !== 2) {
return statusFilteredData;
}
const [startDate, endDate] = dateRange.value;
if (!startDate || !endDate) {
return statusFilteredData;
}
// 将字符串日期转换为时间戳进行比较
const startTimestamp = new Date(startDate).getTime();
const endTimestamp = new Date(endDate).getTime();
return statusFilteredData.filter(ship => {
// 检查船舶的开始用电时间是否存在
const beginTime = ship.beginTime ? new Date(ship.beginTime).getTime() : null;
// 如果开始时间不存在,则不包含在结果中
if (!beginTime) {
return false;
}
// 检查结束用电时间是否存在
const endTime = ship.endTime ? new Date(ship.endTime).getTime() : null;
// 如果开始时间和结束时间都存在,则检查是否在范围内
if (beginTime && endTime) {
return (beginTime >= startTimestamp && beginTime <= endTimestamp) ||
(endTime >= startTimestamp && endTime <= endTimestamp) ||
(beginTime <= startTimestamp && endTime >= endTimestamp); // 跨越整个范围的情况
}
// 如果只有开始时间存在
if (beginTime && !endTime) {
return beginTime >= startTimestamp && beginTime <= endTimestamp;
}
// 默认情况(应该不会到达这里)
return false;
});
});
// 处理日期范围变化
const handleDateRangeChange = (val: [string, string] | []) => {
dateRange.value = val;
};
// 处理状态筛选变化
const handleStatusFilterChange = (val: string) => {
statusFilter.value = val;
};
// 重置筛选
const resetFilter = () => {
dateRange.value = [];
statusFilter.value = 'all';
};
// 处理船舶列表点击事件
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 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;
4 weeks ago
if (applyInfo && applyInfo.reason !== undefined && applyInfo.reason == 0 && usageRecordInfo && usageRecordInfo.beginTime) {
4 weeks ago
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`
}
4 weeks ago
} else if (applyInfo && applyInfo.reason !== undefined && applyInfo.reason != 0) {
4 weeks ago
// 状态码映射表 - 包含状态文本和颜色类型
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' }
}
4 weeks ago
const reasonKey = applyInfo.reason!.toString()
const statusInfo = statusMap[reasonKey] || { text: applyInfo.reason!, colorType: 'default' }
4 weeks ago
// 根据颜色类型设置对应的状态类
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,
4 weeks ago
name: ship?.shipBasicInfo?.name,
4 weeks ago
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) => {
console.log('first')
selectedShip.value = row
detailDialogVisible.value = true
}
onMounted(async () => {
// 从API获取字典数据
berthIdAndNameList.value = await MapApi.getBerthIdAndNameList()
dockIdAndNameList.value = await MapApi.getDockIdAndNameList()
harborDistrictIdAndNameList.value = await MapApi.getHarborDistrictIdAndNameList()
4 weeks ago
console.log('props.shipData', props.shipData)
4 weeks ago
// 构建本地数据,使用Promise.all等待所有异步操作完成
localShipData.value = await Promise.all(props.shipData.map(ship => buildData(ship)));
})
</script>
<style scoped>
.ship-shore-power {
display: flex;
height: 100%;
gap: 10px;
4 weeks ago
color: #ffffff;
background-color: transparent;
}
.ship-data-table-container {
height: 100%;
overflow-y: auto;
4 weeks ago
background-color: transparent !important;
overflow-x: hidden;
}
.ship-data-table {
width: 100%;
4 weeks ago
background-color: transparent !important;
color: #ffffff !important;
table-layout: auto;
}
4 weeks ago
.ship-data-table :deep(*) {
background-color: transparent !important;
}
4 weeks ago
.ship-data-table :deep(.el-table) {
background-color: transparent !important;
color: #ffffff !important;
width: 100%;
}
.ship-data-table :deep(.el-table__body) {
background-color: transparent !important;
color: #ffffff !important;
}
.ship-data-table :deep(.el-table__header) {
background-color: transparent !important;
color: #ffffff !important;
}
.ship-data-table :deep(.el-table__body .shore-power-status.status-on) {
color: #4CAF50 !important;
}
.ship-data-table :deep(.el-table__body .shore-power-status.status-off) {
color: #F44336 !important;
}
.ship-data-table :deep(.el-table__body .shore-power-status.status-danger) {
color: #F44336 !important;
}
.ship-data-table :deep(.el-table__body .shore-power-status.status-warning) {
color: #FFC107 !important;
}
.ship-data-table :deep(.el-table__body .shore-power-status.status-success) {
color: #4CAF50 !important;
}
.ship-data-table :deep(.el-table__body .shore-power-status.status-cable) {
color: #2196F3 !important;
}
.ship-data-table :deep(.el-table__cell) {
background-color: transparent !important;
}
.ship-data-table :deep(.el-table__header-wrapper) {
background-color: rgba(30, 120, 255, 0.2) !important;
font-weight: bold;
border-bottom: 2px solid rgba(255, 255, 255, 0.3);
}
.ship-data-table :deep(.el-table__header th) {
background-color: transparent !important;
color: #fff !important;
1 month ago
font-size: 16px;
4 weeks ago
padding: 12px 0;
white-space: nowrap;
}
.ship-data-table :deep(.el-table__body td .shore-power-status) {
font-weight: bold;
white-space: nowrap;
display: inline-block;
}
.ship-data-table :deep(.el-table__body td) {
background-color: transparent !important;
font-size: 16px;
padding: 12px 0;
border-bottom: 1px solid rgba(255, 255, 255, 0.1) !important;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.ship-data-table :deep(.el-table__body td .shore-power-status) {
font-weight: bold;
}
.ship-data-table :deep(.el-table__body-wrapper tr) {
background-color: transparent !important;
}
.ship-data-table :deep(.el-table__row) {
background-color: transparent !important;
}
.ship-data-table :deep(.el-table__row:hover) {
background-color: rgba(255, 255, 255, 0.1) !important;
cursor: pointer;
}
.ship-data-table :deep(.el-table__row.current-row) {
background-color: rgba(255, 255, 255, 0.05) !important;
}
.ship-data-table :deep(.el-table__body-wrapper) {
background-color: transparent !important;
}
.ship-data-table :deep(.el-table__inner-wrapper::before) {
background-color: transparent !important;
}
.ship-data-table :deep(.el-table__header-wrapper tr th) {
background-color: rgba(30, 120, 255, 0.2) !important;
color: #ffffff !important;
}
.ship-data-table :deep(table) {
background-color: transparent !important;
color: #ffffff !important;
}
.ship-data-table :deep(.el-table__empty-block) {
background-color: transparent !important;
}
.ship-data-table :deep(.el-table__placeholder) {
background-color: transparent !important;
color: #ffffff !important;
}
.ship-data-table :deep(.el-table__expanded-cell) {
background-color: transparent !important;
color: #ffffff !important;
}
.ship-data-table :deep(.el-table__footer-wrapper) {
background-color: transparent !important;
}
/* 数据卡片标题样式 */
.data-card-title {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 10px;
}
.title-section {
display: flex;
align-items: center;
min-width: 0;
/* 允许标题部分收缩 */
1 month ago
}
4 weeks ago
.filter-controls {
display: flex;
align-items: center;
gap: 10px;
}
.date-range-picker {
width: 200px;
flex-shrink: 0;
/* 防止日期选择器收缩 */
}
/* 响应式设计:当屏幕较小时调整布局 */
@media (max-width: 1200px) {
.data-card-title {
flex-direction: column;
align-items: stretch;
}
.title-section {
justify-content: center;
margin-bottom: 10px;
}
.filter-controls {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
gap: 10px;
margin-bottom: 10px;
}
.date-range-picker {
width: 100%;
max-width: 200px;
align-self: center;
}
}
.shore-power-status {
font-weight: bold;
}
.shore-power-status.status-on {
4 weeks ago
color: #4CAF50 !important;
}
.shore-power-status.status-off {
4 weeks ago
color: #F44336 !important;
}
.shore-power-status.status-danger {
color: #F44336 !important;
}
.shore-power-status.status-warning {
color: #FFC107 !important;
}
.shore-power-status.status-success {
color: #4CAF50 !important;
}
.shore-power-status.status-cable {
color: #2196F3 !important;
}
1 month ago
.overview-value {
4 weeks ago
font-size: 42px;
1 month ago
font-weight: 700;
}
.overview-label {
4 weeks ago
font-size: 32px;
1 month ago
font-weight: 700;
4 weeks ago
}
.overview-grid {
display: flex;
justify-content: space-between;
gap: 20px;
}
.overview-item {
flex: 1;
text-align: center;
}
/* 船舶详情对话框样式 */
.ship-detail-dialog :deep(.el-dialog) {
background-color: rgba(0, 0, 0, 0.8);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 8px;
color: #ffffff;
}
.ship-detail-dialog :deep(.el-dialog__header) {
background-color: rgba(30, 120, 255, 0.2);
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
padding: 15px 20px;
}
.ship-detail-dialog :deep(.el-dialog__title) {
color: #ffffff;
font-size: 18px;
font-weight: bold;
}
.ship-detail-dialog :deep(.el-dialog__body) {
padding: 20px;
}
.ship-detail-dialog :deep(.el-form-item__label) {
color: #ffffff;
font-weight: bold;
}
.ship-detail-dialog :deep(.el-form-item__content) {
color: #ffffff;
}
.ship-detail-dialog :deep(.el-row) {
margin-bottom: 10px;
}
.ship-detail-dialog :deep(h3) {
color: #409EFF;
margin: 15px 0;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
padding-bottom: 5px;
}
.ship-detail-dialog :deep(.el-dialog__footer) {
background-color: rgba(0, 0, 0, 0.3);
border-top: 1px solid rgba(255, 255, 255, 0.1);
padding: 15px 20px;
}
.dialog-footer :deep(.el-button) {
background-color: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.3);
color: #ffffff;
}
1 month ago
4 weeks ago
.dialog-footer :deep(.el-button:hover) {
background-color: rgba(255, 255, 255, 0.2);
border: 1px solid rgba(255, 255, 255, 0.5);
1 month ago
}
</style>