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.
 
 
 
 

506 lines
20 KiB

<template>
<div class="port-overview">
<div class="left" style="width:45%;">
<div style="height: 100%; width: 100%; display: flex; gap: 8px; ">
<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>
<input class="search-container" type="text" placeholder="搜索岸电设备" v-model="storeSearchKeyword"
@input="handlStoreSearch" />
</div>
<div class=" card-content">
<div class="ship-table">
<div class="ship-table-header">
<div class="ship-table-column ship-name-header">岸电箱名称</div>
<div class="ship-table-column ship-status-header">状态</div>
<div class="ship-table-column ship-status-header">历史</div>
</div>
<div class="ship-table-body">
<div v-for="shorepower in filteredShorePowerList" :key="shorepower.id" class="ship-table-row"
@click="handleSelectShorePower(shorepower)">
<div class="ship-table-column ship-name">
<div class="ship-icon">⚡</div>
<span class="ship-name-text">{{ shorepower.name }}</span>
</div>
<div class="ship-table-column ship-status">
<div class="status-tag" :class="getStatusClass(shorepower.storePowerStatus)">
{{ shorepower.storePowerStatus }}
</div>
<!-- <div class="status-tag" :class="getStatusClass('空闲')">
空闲
</div>
<div class="status-tag" :class="getStatusClass('故障')">
故障
</div> -->
</div>
<div class="ship-table-column ship-status-header">
<el-button type="primary" link @click.stop="showShorePowerHistory(shorepower)">查看</el-button>
</div>
</div>
</div>
</div>
</div>
</div>
<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>
<input class="search-container" type="text" placeholder="搜索船舶" v-model="searchKeyword"
@input="handleSearch" />
</div>
<div class=" card-content">
<div class="ship-table">
<div class="ship-table-header">
<div class="ship-table-column ship-name-header">轮船名称</div>
<div class="ship-table-column ship-status-header">状态</div>
<div class="ship-table-column ship-status-header">历史</div>
</div>
<div class="ship-table-body">
<div v-for="ship in filteredShipStatusData" :key="ship.id" class="ship-table-row"
@click="handleSelectItem(ship)">
<div class="ship-table-column ship-name">
<div class="ship-icon">🚢</div>
<span class="ship-name-text">{{ ship.shipBasicInfo.name }}</span>
</div>
<div class="ship-table-column ship-status">
<div class="status-tag" :class="getStatusClass(ship.shipStatus)">
{{ ship.shipStatus }}
</div>
<!-- <div class="status-tag" :class="getStatusClass('空闲')">
空闲
</div>
<div class="status-tag" :class="getStatusClass('故障')">
故障
</div> -->
</div>
<div class="ship-table-column ship-status-header">
<el-button type="primary" link @click.stop="showShipHistory(ship)">查看</el-button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div v-if="shipSelectedItem || shorepowerSelectedItem" class="right" style="width: 20%">
<div v-if="shipSelectedItem && show_type === 'ship'" class="right-two-row">
<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">{{ shipSelectedItem.shipBasicInfo.name + '-' + shipSelectedItem.shipBasicInfo.nameEn
}}</span>
</div>
<!-- <div class="detail-item">
<span class="label">英文船名:</span>
<span class="value">{{ selectedItem.shipBasicInfo.nameEn }}</span>
</div> -->
<!-- <div class="detail-item">
<span class="label">船舶呼号:</span>
<span class="value">{{ selectedItem.shipBasicInfo.callSign }}</span>
</div> -->
<div class="detail-item">
<span class="label">长度:</span>
<span class="value">{{ shipSelectedItem.shipBasicInfo.length }} 米</span>
</div>
<div class="detail-item">
<span class="label">宽度:</span>
<span class="value">{{ shipSelectedItem.shipBasicInfo.width }} 米</span>
</div>
<div class="detail-item">
<span class="label">吨位:</span>
<span class="value">{{ shipSelectedItem.shipBasicInfo.tonnage }} 吨</span>
</div>
<div class="detail-item">
<span class="label">满载吃水深度:</span>
<span class="value">{{ shipSelectedItem.shipBasicInfo.fullLoadDraft }} 米</span>
</div>
<div class="detail-item">
<span class="label">电压:</span>
<span class="value">{{ getValueById(realtimeDeviceData, shipSelectedItem.shorePower.voltageDeviceId,
'measureValue') }}</span>
</div>
<div class="detail-item">
<span class="label">电流:</span>
<span class="value">{{ getValueById(realtimeDeviceData, shipSelectedItem.shorePower.currentDeviceId,
'measureValue') }}</span>
</div>
<div class="detail-item">
<span class="label">频率:</span>
<span class="value">{{ getValueById(realtimeDeviceData, shipSelectedItem.shorePower.frequencyDeviceId,
'measureValue') }}</span>
</div>
<div class="detail-item">
<span class="label">靠泊状态:</span>
<span class="value">{{ getOperationTypeLabel(shipSelectedItem.shorePowerAndShip.status,
SHORE_POWER_STATUS,
) }}</span>
</div>
<div class="detail-item">
<span class="label">靠泊类型:</span>
<span class="value">{{ getOperationTypeLabel(shipSelectedItem.shorePowerAndShip.type, BERTH_TYPE)
}}</span>
</div>
<div class="detail-item">
<span class="label">靠泊时间:</span>
<span class="value">{{ formatTimestamp(shipSelectedItem?.usageRecordInfo?.actualBerthTime) }}</span>
</div>
<div class="detail-item">
<span class="label">当前状态:</span>
<span class="value">{{ shipSelectedItem.shipStatus }}</span>
</div>
<div v-if="shipSelectedItem.applyInfo.reason === 0" class="detail-item">
<span class="label">岸电使用时长:</span>
<span class="value">{{ showStatus(shipSelectedItem, realtimeDeviceData)?.useTime }}</span>
</div>
<div v-if="shipSelectedItem.applyInfo.reason === 0" class="detail-item">
<span class="label">岸电使用用量:</span>
<span class="value">{{ showStatus(shipSelectedItem, realtimeDeviceData)?.useValue }}</span>
</div>
<div v-if="shipSelectedItem.applyInfo.reason != 0" class="detail-item">
<span class="label">未使用岸电原因:</span>
<span class="value">{{ getOperationTypeLabel(shipSelectedItem?.applyInfo?.reason,
UNUSED_SHORE_POWER_REASON) }}</span>
</div>
<div class="detail-item">
<span class="label">岸电联系人:</span>
<span class="value">{{ shipSelectedItem.shipBasicInfo.shorePowerContact }}</span>
</div>
<div class="detail-item">
<span class="label">联系方式:</span>
<span class="value">{{ shipSelectedItem.shipBasicInfo.shorePowerContactPhone }}</span>
</div>
<!-- <div class="detail-item">
<span class="label">航运单位:</span>
<span class="value">{{ shipSelectedItem.shipBasicInfo.shippingCompany }}</span>
</div>
<div class="detail-item">
<span class="label">岸电联系人:</span>
<span class="value">{{ shipSelectedItem.shipBasicInfo.shorePowerContact }}</span>
</div>
<div class="detail-item">
<span class="label">联系方式:</span>
<span class="value">{{ shipSelectedItem.shipBasicInfo.shorePowerContactPhone }}</span>
</div>
<div class="detail-item">
<span class="label">船检登记号:</span>
<span class="value">{{ shipSelectedItem.shipBasicInfo.inspectionNo }}</span>
</div>
<div class="detail-item">
<span class="label">创建时间:</span>
<span class="value">{{ new Date(shipSelectedItem.shipBasicInfo.createTime).toLocaleString() }}</span>
</div> -->
</div>
</div>
</div>
<!-- <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>
</div>
</div> -->
</div>
<div v-if="shorepowerSelectedItem && show_type === 'shorepower'" class="right-two-row">
<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">{{ shorepowerSelectedItem?.name }}</span>
</div>
<div class="detail-item">
<span class="label">位置:</span>
<span class="value">{{ shorepowerSelectedItem?.position }}</span>
</div>
<div class="detail-item">
<span class="label">电压:</span>
<span class="value">{{ shorepowerSelectedItem?.shorePowerEquipmentInfo?.voltage }}</span>
</div>
<div class="detail-item">
<span class="label">频率:</span>
<span class="value">{{ shorepowerSelectedItem?.shorePowerEquipmentInfo?.frequency }} </span>
</div>
<div class="detail-item">
<span class="label">容量:</span>
<span class="value">{{ shorepowerSelectedItem?.shorePowerEquipmentInfo?.capacity }}</span>
</div>
<div class="detail-item">
<span class="label">当前电压:</span>
<span class="value">{{ getValueById(realtimeDeviceData, shorepowerSelectedItem.voltageDeviceId,
'measureValue') }}</span>
</div>
<div class="detail-item">
<span class="label">当前电流:</span>
<span class="value">{{ getValueById(realtimeDeviceData, shorepowerSelectedItem.currentDeviceId,
'measureValue') }}</span>
</div>
<div class="detail-item">
<span class="label">当前频率:</span>
<span class="value">{{ getValueById(realtimeDeviceData, shorepowerSelectedItem.frequencyDeviceId,
'measureValue') }}</span>
</div>
<div class="detail-item">
<span class="label">当前总用量:</span>
<span class="value">{{ getValueById(realtimeDeviceData, shorepowerSelectedItem.totalPowerDeviceId,
'measureValue') }}</span>
</div>
<div class="detail-item">
<span class="label">当前状态:</span>
<span class="value">{{ shorepowerSelectedItem.storePowerStatus }}</span>
</div>
</div>
</div>
</div>
</div>
<!-- <div v-else 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="no-selection">请选择设备以查看详细信息</div>
</div>
</div> -->
</div>
<ShipHistoryDialog v-model="shipHistoryVisible.visible" :ship-param="shipHistoryVisible.searchParams"
:realtime-device-data="realtimeDeviceData" />
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import ShipHistoryDialog from './ShipHistoryDialog.vue'
import { MapApi } from "@/api/shorepower/map";
import { RealtimeDeviceData, ShipRespVo, ShorePowerBerth } from '@/types/shorepower';
import { BERTH_TYPE, getOperationTypeLabel, SHORE_POWER_STATUS, UNUSED_SHORE_POWER_REASON } from './dictionaryTable';
import { formatDuration, formatTimestamp, getValueById, showStatus } from './utils';
// 定义组件属性
type ShipItem = ShipRespVo & { id: string; modelInstance?: any; };
interface Props {
shipStatusData: ShipItem[];
shorePowerStatusData: ShipItem[];
realtimeDeviceData: RealtimeDeviceData[];
shorePowerList: (ShorePowerBerth & { position: string; })[];
shipDataList: ShipRespVo[];
// selectedItem: ShipItem | null;
}
const props = defineProps<Props>()
// 搜索关键字
const searchKeyword = ref('')
const storeSearchKeyword = ref('')
const show_type = ref('ship')
const shipSelectedItem = ref<ShipItem | null>(null)
const shorepowerSelectedItem = ref<ShorePowerBerth & { position: string; } | null>(null)
const shipHistoryVisible = ref({
visible: false,
searchParams: {
shipId: 0 as number | null,
ids: [] as number[] | null,
type: 1 as number
}
})
const currentShorePower = ref<ShorePowerBerth | null>(null)
const currentShip = ref<ShipItem | null>(null)
// const ShorePowerList = ref<(ShorePowerBerth & { position: string; })[]>([])
// 过滤后的船舶数据
const filteredShipStatusData = computed(() => {
if (!searchKeyword.value) {
return props.shipDataList
}
return props.shipDataList.filter(ship =>
ship.shipBasicInfo.name.toLowerCase().includes(searchKeyword.value.toLowerCase())
)
})
// 过滤后的岸电箱数据
const filteredShorePowerList = computed(() => {
if (!storeSearchKeyword.value) {
return props.shorePowerList
}
return props.shorePowerList.filter(shorepower =>
shorepower.name.toLowerCase().includes(storeSearchKeyword.value.toLowerCase())
)
})
const handleSelectItem = async (item: ShipRespVo) => {
show_type.value = 'ship'
const deviceId = item.shorePower?.totalPowerDeviceId;
const res = await MapApi.getRealtimeDataByIdList({ ids: deviceId })
console.log(res)
shipSelectedItem.value = {
...item,
shorePowerEquipment: {
...item.shorePowerEquipment,
'measureValue': res[0].measureValue || 'N/A',
}
}
emit('item-click', {
type: 'ship',
item: item
})
}
// 处理搜索输入
const handleSearch = () => {
// 输入处理逻辑(如果需要额外处理可以在这里添加)
}
// 处理岸电箱搜索输入
const handlStoreSearch = () => {
// 输入处理逻辑(如果需要额外处理可以在这里添加)
}
// 显示岸电箱历史记录
const showShorePowerHistory = (shorepower: ShorePowerBerth) => {
console.log('shorepower', shorepower)
currentShorePower.value = shorepower
/* shorePowerHistoryVisible.value = {
visible: true,
shorePowerId: shorepower.id || 0
} */
shipHistoryVisible.value = {
visible: true,
searchParams: {
shipId: null,
ids: [shorepower.id],
type: 5,
}
}
}
// 显示船舶历史记录
const showShipHistory = (ship: ShipItem) => {
console.log('ship', ship)
currentShip.value = ship
shipHistoryVisible.value = {
visible: true,
searchParams: {
shipId: ship.shipBasicInfo.id,
ids: null,
type: 1,
}
}
}
// 定义事件
const emit = defineEmits<{
(e: 'switch-ship', ship: ShipItem): void;
(e: 'item-click', item: any): void;
// handleSelectItem(ship)
}>()
// 处理船舶选择
const handleSwitch = (ship: ShipItem, type: string) => {
// console.log(ship)
show_type.value = type
emit('switch-ship', ship)
handleSelectItem(ship)
}
const handleSelectShorePower = async (shorepower: ShorePowerBerth & { position: string }) => {
show_type.value = 'shorepower'
// selectedItem.value = shorepower
shorepowerSelectedItem.value = shorepower
emit('item-click', {
type: 'shorepower_box',
item: shorepower
})
// const data = await MapApi.getRealtimeDataByIdList({ ids: shorepower.totalPowerDeviceId })
// console.log('voltageDeviceId', data)
}
const getStatusClass = (status: string | undefined) => {
switch (status) {
case '正常':
return 'status-normal'
case '在线':
return 'status-normal'
case '空闲':
return 'status-idle'
case '故障':
return 'status-fault'
case '超容':
return 'status-fault'
case '异常':
return 'status-abnormal'
case '维修中':
return 'status-maintenance'
case '岸电使用中':
return 'status-shorepower'
// case '岸电故障':
// return 'status-fault'
default:
return 'status-default'
}
}
watch(() => props.shipDataList, (newVal) => {
console.log('newVal', newVal)
})
onMounted(() => {
// console.log(props.shorePowerStatusData)
})
</script>
<style scoped>
.port-overview {
display: flex;
gap: 10px;
height: 100%;
}
.right-two-row {
display: flex;
gap: 10px;
height: 100%;
}
.search-container {
height: 100%;
width: 200px;
border-radius: 4px;
border: 1px solid rgb(10, 130, 170);
color: #FFF;
padding: 0 10px;
margin-bottom: 8px;
background-color: rgba(255, 255, 255, 0.1);
}
</style>