jiangAB 2 months ago
parent
commit
a05f704884
  1. 92
      public/map/components/CompanyShorePower.vue
  2. 236
      public/map/components/PortOverview.vue
  3. 284
      public/map/components/ShipHistoryDialog.vue
  4. 10
      public/map/components/ShipShorePower.vue
  5. 4
      public/map/components/ShorePowerHistoryDialog.vue
  6. 874
      public/map/components/ShorePowerUsage.vue
  7. 1222
      public/map/components/cesiumMap.vue
  8. 13
      public/map/components/charts/WaveLineChart.vue
  9. 9
      public/map/components/dictionaryTable.ts
  10. 48
      public/map/components/utils.ts
  11. 309
      public/map/index.vue

92
public/map/components/CompanyShorePower.vue

@ -9,10 +9,10 @@
<img src="@/assets/svgs/data.svg" class="title-icon" />
<span class="title-text">码头与泊位信息</span>
</div>
<div>
<!-- <div>
<el-date-picker type="daterange" range-separator="" start-placeholder="开始日期" end-placeholder="结束日期"
format="YYYY-MM-DD" value-format="YYYY-MM-DD" class="date-range-picker" />
</div>
</div> -->
</div>
@ -20,11 +20,13 @@
<div v-for="company in companyComparisonData" :key="company.name" class="company-section">
<div class="company-header">
<div class="company-name">{{ company.name }}</div>
<div class="company-total">总量: {{ company.value }}</div>
<div class="company-total">总量: {{ calculateTotal(company.children).toFixed(2) }}</div>
</div>
<div class="overview-grid">
<div v-for="(berth, index) in (company.children || [])" :key="index" class="overview-item">
<div class="overview-value">{{ berth.value }}</div>
<div v-for="(berth, index) in (company.children || [])" :key="index" class="overview-item"
@click="showShorePowerHistory(berth)">
<div class="overview-value">{{ berth.measureValue?.toFixed(2)
|| 0 }}</div>
<div class="overview-label">{{ berth.name }}</div>
@ -34,24 +36,97 @@
</div>
</div>
</div>
<ship-history-dialog v-model="historyVisible.visible" :ship-param="historyVisible.searchParams"
:realtime-device-data="realtimeDeviceData" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { MapApi } from "@/api/shorepower/map";
import ShipHistoryDialog from './ShipHistoryDialog.vue';
import { RealtimeDeviceData } from '@/types/shorepower';
//
interface ChartDataItem {
name: string;
value: number;
value?: number;
measureValue?: number;
children?: ChartDataItem[];
}
const historyVisible = ref({
visible: false,
searchParams: {
shipId: 0 as number | null,
ids: [] as number[] | null,
type: 1 as number
}
})
//
const calculateTotal = (children?: ChartDataItem[]) => {
if (!children || children.length === 0) return 0;
return children.reduce((total, item) => {
return total + (item.measureValue || 0);
}, 0);
};
//
const showShorePowerHistory = (berth: ChartDataItem) => {
console.log(berth)
// console.log('shorepower', shorepower)
// currentShorePower.value = shorepower
/* shorePowerHistoryVisible.value = {
visible: true,
shorePowerId: shorepower.id || 0
} */
historyVisible.value = {
visible: true,
searchParams: {
shipId: null,
ids: [berth.id],
type: 4,
}
}
}
interface Props {
companyComparisonData: ChartDataItem[];
companyComparisonData?: ChartDataItem[];
realtimeDeviceData: RealtimeDeviceData[];
}
const props = defineProps<Props>()
const companyComparisonData = ref<ChartDataItem[]>([])
const handleGetBuildData = async () => {
const dockList = await MapApi.getDockIdAndNameList()
const berthList = await MapApi.getBerthIdAndNameList()
const buildData = dockList.map(dock => ({
...dock,
children: berthList.filter(berth => berth.dockId === dock.id).map(berth => ({
...berth,
...props.realtimeDeviceData.find(item => (item.id === berth.id) && (item.deviceCode.includes('Kwh')))
}))
}))
console.log('buildData', buildData)
console.log('props.realtimeDeviceData', props.realtimeDeviceData)
companyComparisonData.value = buildData
/* MapApi.getBerthIdAndNameList().then(res => {
console.log(res)
const buildData = res.map(item => ({
...item,
children: props.realtimeDeviceData.filter(item => item.id === item.id)
}))
}) */
}
watch(() => props.realtimeDeviceData, (newVal) => {
handleGetBuildData()
})
onMounted(() => {
// console.log(props.realtimeDeviceData)
handleGetBuildData()
})
</script>
<style scoped>
@ -92,6 +167,7 @@ const props = defineProps<Props>()
}
.overview-item {
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;

236
public/map/components/PortOverview.vue

@ -10,7 +10,7 @@
<span class="title-text">岸电箱状态</span>
</div>
<input class="search-container" type="text" placeholder="搜索岸电设备" v-model="storeSearchKeyword"
@input="handleSearch" />
@input="handlStoreSearch" />
</div>
<div class=" card-content">
@ -21,7 +21,7 @@
<div class="ship-table-column ship-status-header">历史</div>
</div>
<div class="ship-table-body">
<div v-for="shorepower in ShorePowerList" :key="shorepower.id" class="ship-table-row"
<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>
@ -66,7 +66,7 @@
</div>
<div class="ship-table-body">
<div v-for="ship in filteredShipStatusData" :key="ship.id" class="ship-table-row"
@click="handleSwitch(ship, 'ship')">
@click="handleSelectItem(ship)">
<div class="ship-table-column ship-name">
<div class="ship-icon">🚢</div>
<span class="ship-name-text">{{ ship.shipBasicInfo.name }}</span>
@ -92,7 +92,8 @@
</div>
</div>
</div>
<div class="right" :style="`width: ${show_type === 'ship' ? '45%' : '20%'}`">
<div v-if="shipSelectedItem || shorepowerSelectedItem" class="right"
:style="`width: ${show_type === 'ship' ? '45%' : '20%'}`">
<div v-if="shipSelectedItem && show_type === 'ship'" class="right-two-row">
<div class="card digital-twin-card--deep-blue">
<div class="card-title">
@ -263,27 +264,6 @@
</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 class="detail-item">
<span class="label">停泊状态:</span>
<span class="value">{{ selectedItem.shorePowerAndShip.type === 'left' ? '左舷停泊' :
selectedItem.shorePowerAndShip.type === 'right' ? '右舷停泊' : selectedItem.shorePowerAndShip.type
}}</span>
</div>
<div class="detail-item">
<span class="label">靠泊状态:</span>
<span class="value">{{ getShorePowerStatusText(selectedItem.shorePowerAndShip.status) }}</span>
</div>
</div>
</div>
</div> -->
</div>
<!-- <div v-else class="card digital-twin-card--deep-blue" style="flex: 1;">
@ -297,28 +277,17 @@
</div>
</div> -->
</div>
<!-- 岸电箱历史记录弹窗 -->
<ShorePowerHistoryDialog v-model="shorePowerHistoryVisible.visible" :data="shorePowerHistoryData"
:ship-connection-data="shorePowerConnectionData" @search="handleShorePowerHistorySearch"
@ship-connection-search="handleShorePowerConnectionSearch"
:shore-power-id="shorePowerHistoryVisible.shorePowerId" />
<!-- 船舶历史记录弹窗 -->
<ShipHistoryDialog v-model="shipHistoryVisible.visible" :berthing-data="shipHistoryData"
:shore-power-connection-data="shipShorePowerConnectionData" @berthing-search="handleShipHistorySearch"
@shore-power-connection-search="handleShipShorePowerConnectionSearch" :ship-id="shipHistoryVisible.shipId"
<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 ShorePowerHistoryDialog from './ShorePowerHistoryDialog.vue'
import ShipHistoryDialog from './ShipHistoryDialog.vue'
import { MapApi } from "@/api/shorepower/map";
import { RealtimeDeviceData, ShipRespVo, ShorePowerBerth } from '@/types/shorepower';
import { BERTH_TYPE, DOCK_DISTRICT, getOperationTypeLabel, HARBOR_DISTRICT, SHORE_POWER_STATUS, UNUSED_SHORE_POWER_REASON } from './dictionaryTable';
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; };
@ -327,6 +296,8 @@ interface Props {
shipStatusData: ShipItem[];
shorePowerStatusData: ShipItem[];
realtimeDeviceData: RealtimeDeviceData[];
shorePowerList: (ShorePowerBerth & { position: string; })[];
shipDataList: ShipRespVo[];
// selectedItem: ShipItem | null;
}
@ -339,77 +310,41 @@ const show_type = ref('ship')
const shipSelectedItem = ref<ShipItem | null>(null)
const shorepowerSelectedItem = ref<ShorePowerBerth & { position: string; } | null>(null)
//
const shorePowerHistoryVisible = ref({
visible: false,
shorePowerId: 0
})
const shipHistoryVisible = ref({
visible: false,
shipId: 0
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 ShorePowerList = ref<(ShorePowerBerth & { position: string; })[]>([])
//
const filteredShipStatusData = computed(() => {
if (!searchKeyword.value) {
return props.shipStatusData
return props.shipDataList
}
return props.shipStatusData.filter(ship =>
return props.shipDataList.filter(ship =>
ship.shipBasicInfo.name.toLowerCase().includes(searchKeyword.value.toLowerCase())
)
})
//
const shorePowerHistoryData = ref<any[]>([
{ id: 1, time: '2023-05-01 08:30:00', operation: '连接', voltage: '380', current: '120', power: '45.6', energy: '12.5' },
{ id: 2, time: '2023-05-01 12:15:00', operation: '运行', voltage: '382', current: '118', power: '45.1', energy: '35.2' },
{ id: 3, time: '2023-05-01 16:45:00', operation: '断开', voltage: '0', current: '0', power: '0', energy: '0' },
{ id: 4, time: '2023-05-02 09:20:00', operation: '连接', voltage: '379', current: '122', power: '46.3', energy: '8.7' },
{ id: 5, time: '2023-05-02 14:30:00', operation: '运行', voltage: '381', current: '119', power: '45.4', energy: '28.9' },
{ id: 6, time: '2023-05-02 18:50:00', operation: '断开', voltage: '0', current: '0', power: '0', energy: '0' },
{ id: 7, time: '2023-05-03 07:45:00', operation: '连接', voltage: '380', current: '121', power: '45.9', energy: '15.3' },
{ id: 8, time: '2023-05-03 13:20:00', operation: '运行', voltage: '382', current: '120', power: '45.8', energy: '42.1' },
{ id: 9, time: '2023-05-03 17:30:00', operation: '断开', voltage: '0', current: '0', power: '0', energy: '0' },
{ id: 10, time: '2023-05-04 10:15:00', operation: '连接', voltage: '378', current: '123', power: '46.5', energy: '9.8' }
])
//
const shipHistoryData = ref<any[]>([
{ id: 1, time: '2023-04-15 09:30:00', operation: '靠泊', berthPosition: '1号泊位', duration: '12.5', powerConsumption: '125.6' },
{ id: 2, time: '2023-04-16 14:20:00', operation: '离泊', berthPosition: '1号泊位', duration: '0', powerConsumption: '0' },
{ id: 3, time: '2023-04-20 08:45:00', operation: '靠泊', berthPosition: '3号泊位', duration: '8.2', powerConsumption: '89.3' },
{ id: 4, time: '2023-04-21 16:30:00', operation: '离泊', berthPosition: '3号泊位', duration: '0', powerConsumption: '0' },
{ id: 5, time: '2023-04-25 11:15:00', operation: '靠泊', berthPosition: '2号泊位', duration: '15.7', powerConsumption: '156.8' },
{ id: 6, time: '2023-04-26 18:40:00', operation: '离泊', berthPosition: '2号泊位', duration: '0', powerConsumption: '0' },
{ id: 7, time: '2023-05-01 07:20:00', operation: '靠泊', berthPosition: '1号泊位', duration: '18.3', powerConsumption: '189.2' },
{ id: 8, time: '2023-05-02 15:50:00', operation: '离泊', berthPosition: '1号泊位', duration: '0', powerConsumption: '0' },
{ id: 9, time: '2023-05-05 09:10:00', operation: '靠泊', berthPosition: '4号泊位', duration: '6.4', powerConsumption: '67.5' },
{ id: 10, time: '2023-05-06 13:45:00', operation: '离泊', berthPosition: '4号泊位', duration: '0', powerConsumption: '0' }
])
//
const shorePowerConnectionData = ref<any[]>([
{ id: 1, shipName: '远航号', time: '2023-05-01 08:30:00', duration: '4.5', powerConsumption: '125.6', status: '已断开' },
{ id: 2, shipName: '海鹰号', time: '2023-05-01 12:15:00', duration: '3.2', powerConsumption: '89.3', status: '已断开' },
{ id: 3, shipName: '巨轮号', time: '2023-05-02 09:20:00', duration: '6.8', powerConsumption: '189.2', status: '连接中' },
{ id: 4, shipName: '远洋号', time: '2023-05-03 07:45:00', duration: '2.1', powerConsumption: '67.5', status: '已断开' },
{ id: 5, shipName: '海豚号', time: '2023-05-04 10:15:00', duration: '5.3', powerConsumption: '156.8', status: '连接中' }
])
//
const shipShorePowerConnectionData = ref<any[]>([
{ id: 1, shorePowerName: '1号岸电箱', time: '2023-05-01 08:30:00', duration: '4.5', powerConsumption: '125.6', status: '已断开' },
{ id: 2, shorePowerName: '2号岸电箱', time: '2023-05-01 12:15:00', duration: '3.2', powerConsumption: '89.3', status: '已断开' },
{ id: 3, shorePowerName: '1号岸电箱', time: '2023-05-02 09:20:00', duration: '6.8', powerConsumption: '189.2', status: '连接中' },
{ id: 4, shorePowerName: '3号岸电箱', time: '2023-05-03 07:45:00', duration: '2.1', powerConsumption: '67.5', status: '已断开' },
{ id: 5, shorePowerName: '2号岸电箱', time: '2023-05-04 10:15:00', duration: '5.3', powerConsumption: '156.8', status: '连接中' }
])
//
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: ShipItem) => {
const handleSelectItem = async (item: ShipRespVo) => {
const deviceId = item.shorePower?.totalPowerDeviceId;
const res = await MapApi.getRealtimeDataByIdList({ ids: deviceId })
console.log(res)
@ -420,29 +355,37 @@ const handleSelectItem = async (item: ShipItem) => {
'measureValue': res[0].measureValue || 'N/A',
}
}
emit('item-click', {
type: 'ship',
item: item
})
}
const filteredShorePowerStatusData = computed(() => {
if (!storeSearchKeyword.value) {
return props.shipStatusData
}
return props.shipStatusData.filter(ship =>
ship.shorePowerEquipment.name.toLowerCase().includes(storeSearchKeyword.value.toLowerCase())
)
})
//
const handleSearch = () => {
//
}
//
const handlStoreSearch = () => {
//
}
//
const showShorePowerHistory = (shorepower: ShorePowerBerth) => {
console.log('shorepower', shorepower)
currentShorePower.value = shorepower
shorePowerHistoryVisible.value = {
/* shorePowerHistoryVisible.value = {
visible: true,
shorePowerId: shorepower.id || 0
} */
shipHistoryVisible.value = {
visible: true,
searchParams: {
shipId: null,
ids: [shorepower.id],
type: 5,
}
}
}
@ -452,53 +395,18 @@ const showShipHistory = (ship: ShipItem) => {
currentShip.value = ship
shipHistoryVisible.value = {
visible: true,
shipId: ship.shipBasicInfo.id
searchParams: {
shipId: ship.shipBasicInfo.id,
ids: null,
type: 1,
}
}
}
//
const handleShorePowerHistorySearch = (params: any) => {
console.log('岸电箱历史记录搜索参数:', params)
//
//
setTimeout(() => {
console.log('岸电箱历史记录搜索完成')
}, 500)
}
//
const handleShipHistorySearch = (params: any) => {
console.log('船舶历史记录搜索参数:', params)
//
//
setTimeout(() => {
console.log('船舶历史记录搜索完成')
}, 500)
}
//
const handleShorePowerConnectionSearch = (params: any) => {
console.log('岸电箱连接船舶记录搜索参数:', params)
//
//
setTimeout(() => {
console.log('岸电箱连接船舶记录搜索完成')
}, 500)
}
//
const handleShipShorePowerConnectionSearch = (params: any) => {
console.log('船舶连接岸电箱记录搜索参数:', params)
//
//
setTimeout(() => {
console.log('船舶连接岸电箱记录搜索完成')
}, 500)
}
//
const emit = defineEmits<{
(e: 'switch-ship', ship: ShipItem): void;
(e: 'item-click', item: any): void;
// handleSelectItem(ship)
}>()
@ -516,21 +424,14 @@ const handleSelectShorePower = async (shorepower: ShorePowerBerth & { position:
// selectedItem.value = shorepower
shorepowerSelectedItem.value = shorepower
show_type.value = 'shorepower'
emit('item-click', {
type: 'shorepower_box',
item: shorepower
})
// const data = await MapApi.getRealtimeDataByIdList({ ids: shorepower.totalPowerDeviceId })
// console.log('voltageDeviceId', data)
}
const shorePowerStatusMap = {
1: '待靠泊',
2: '靠泊中',
3: '岸电接入中',
4: '用电中',
5: '岸电卸载中',
6: '岸电卸载完成',
7: '离泊',
9: '未使用岸电'
}
const StatusMap = {
1: '故障',
2: '故障',
@ -549,13 +450,6 @@ const StatusText = (status: number | string) => {
return StatusMap[statusNum] || status;
}
//
const getShorePowerStatusText = (status: number | string) => {
const statusNum = Number(status);
// console.log(status)
return shorePowerStatusMap[statusNum] || status;
}
const getStatusClass = (status: string) => {
switch (status) {
case '正常':
@ -579,22 +473,8 @@ const getStatusClass = (status: string) => {
}
}
const handleGetStorePower = async () => {
// console.log('loading')
const harborDistrictId = 1
const harborDistrictList = await HARBOR_DISTRICT()
const dockDistrictList = await DOCK_DISTRICT()
const res = await MapApi.getShorepowerIdAndNameListByHarborDistrictId(harborDistrictId)
ShorePowerList.value = res.map(item => ({
...item,
position: `${getOperationTypeLabel(harborDistrictId, harborDistrictList)}${getOperationTypeLabel(item.shorePowerEquipmentInfo.dockId, dockDistrictList)}${item.name} `,
}))
console.log('11', res)
}
onMounted(async () => {
await handleGetStorePower()
// console.log(props.shipStatusData)
watch(() => props.shipDataList, (newVal) => {
console.log('newVal', newVal)
})
onMounted(() => {

284
public/map/components/ShipHistoryDialog.vue

@ -1,44 +1,48 @@
<template>
<el-dialog v-model="visible" title="船舶历史记录" width="1200px" :before-close="handleClose">
<el-tabs v-model="activeTab">
<!-- 船舶靠泊历史记录 tab -->
<el-tab-pane label="船舶靠泊历史记录" name="shipBerthing">
<!-- 搜索和筛选区域 -->
<div class="filter-container">
<el-form :model="berthingQueryParams" label-width="80px" inline>
<el-form-item label="关键字">
<el-dialog v-model="visible" title="历史记录" width="1200px" :before-close="handleClose">
<!-- <el-tabs v-model="activeTab"> -->
<!-- 船舶靠泊历史记录 tab -->
<!-- <el-tab-pane label="船舶靠泊历史记录" name="shipBerthing"> -->
<!-- 搜索和筛选区域 -->
<div class="filter-container">
<el-form :model="berthingQueryParams" label-width="80px" inline>
<el-form-item label="类型">
<el-select v-model="berthingQueryParams.type" style="width: 120px" placeholder="请选择类型">
<el-option v-for="item in FACILITY_TYPE" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<!-- <el-form-item label="关键字">
<el-input v-model="berthingQueryParams.keyword" placeholder="请输入关键字搜索" clearable
@keyup.enter="handleBerthingSearch" />
</el-form-item>
<el-form-item label="时间范围">
<el-date-picker v-model="berthingDateRange" type="daterange" range-separator="" start-placeholder="开始日期"
end-placeholder="结束日期" value-format="YYYY-MM-DD" @change="handleBerthingDateChange" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleBerthingSearch">搜索</el-button>
<el-button @click="resetBerthingQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
</el-form-item> -->
<el-form-item label="时间范围">
<el-date-picker v-model="berthingDateRange" type="daterange" range-separator="" start-placeholder="开始日期"
end-placeholder="结束日期" value-format="YYYY-MM-DD" @change="handleBerthingDateChange" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleShorePowerConnectionSearch">搜索</el-button>
<el-button @click="resetBerthingQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
<!-- 数据表格 -->
<el-table :data="berthingTableData" border stripe style="width: 100%" v-loading="berthingLoading">
<el-table-column v-for="column in berthingColumns" :key="column.prop" :prop="column.prop" :label="column.label"
:width="column.width" :formatter="column.formatter" />
</el-table>
<!-- 分页 -->
<div class="pagination-container">
<el-pagination v-model:current-page="berthingQueryParams.pageNo" v-model:page-size="berthingQueryParams.pageSize"
:page-sizes="[10, 20, 50, 100]" :total="berthingTotal" layout="total, sizes, prev, pager, next, jumper"
@size-change="handleBerthingSizeChange" @current-change="handleBerthingCurrentChange" />
</div>
<!-- </el-tab-pane> -->
<!-- <el-tab-pane label="船舶连接岸电箱历史记录" name="shorePowerConnection">
<!-- 数据表格 -->
<el-table :data="berthingTableData" border stripe style="width: 100%" v-loading="berthingLoading">
<el-table-column v-for="column in berthingColumns" :key="column.prop" :prop="column.prop"
:label="column.label" :width="column.width" :formatter="column.formatter" />
</el-table>
<!-- 分页 -->
<div class="pagination-container">
<el-pagination v-model:current-page="berthingQueryParams.pageNo"
v-model:page-size="berthingQueryParams.pageSize" :page-sizes="[10, 20, 50, 100]" :total="berthingTotal"
layout="total, sizes, prev, pager, next, jumper" @size-change="handleBerthingSizeChange"
@current-change="handleBerthingCurrentChange" />
</div>
</el-tab-pane>
<!-- 船舶连接岸电箱历史记录 tab -->
<el-tab-pane label="船舶连接岸电箱历史记录" name="shorePowerConnection">
<!-- 搜索和筛选区域 -->
<div class="filter-container">
<el-form :model="shorePowerConnectionQueryParams" label-width="80px" inline>
<el-form-item label="关键字">
@ -57,23 +61,23 @@
</el-form>
</div>
<!-- 数据表格 -->
<el-table :data="shorePowerConnectionTableData" border stripe style="width: 100%"
v-loading="shorePowerConnectionLoading">
<el-table-column v-for="column in shorePowerConnectionColumns" :key="column.prop" :prop="column.prop"
:label="column.label" :width="column.width" :formatter="column.formatter" />
</el-table>
<!-- 分页 -->
<div class="pagination-container">
<el-pagination v-model:current-page="shorePowerConnectionQueryParams.pageNo"
v-model:page-size="shorePowerConnectionQueryParams.pageSize" :page-sizes="[10, 20, 50, 100]"
:total="shorePowerConnectionTotal" layout="total, sizes, prev, pager, next, jumper"
@size-change="handleShorePowerConnectionSizeChange"
@current-change="handleShorePowerConnectionCurrentChange" />
</div>
</el-tab-pane>
</el-tabs>
</div> -->
<!-- </el-tab-pane> -->
<!-- </el-tabs> -->
<template #footer>
<span class="dialog-footer">
@ -99,7 +103,7 @@ import {
ElTableColumn,
ElPagination
} from 'element-plus'
import { CARGO_CATEGORY, getOperationTypeLabel, OPERATION_TYPE } from './dictionaryTable';
import { CARGO_CATEGORY, FACILITY_TYPE, getOperationTypeLabel, OPERATION_TYPE } from './dictionaryTable';
import { formatDuration, formatTimestamp, showStatus } from './utils';
import { RealtimeDeviceData } from '@/types/shorepower';
@ -107,7 +111,7 @@ import { RealtimeDeviceData } from '@/types/shorepower';
interface Props {
modelValue: boolean
berthingData?: any[]
shipId?: number
shipParam?: { type: number, ids: number[] | null, shipId: number | null }
shorePowerConnectionData?: any[]
realtimeDeviceData: RealtimeDeviceData[];
}
@ -133,13 +137,14 @@ const visible = computed({
set: (val) => emit('update:modelValue', val)
})
const activeTab = ref('shipBerthing')
//
const berthingQueryParams = ref({
keyword: '',
// keyword: '',
startTime: '',
endTime: '',
ids: null as number[] | null,
shipId: null as number | null,
type: 1 as number | null,
pageNo: 1,
pageSize: 10
})
@ -225,41 +230,25 @@ const berthingColumns = ref([
])
//
const shorePowerConnectionQueryParams = ref({
keyword: '',
startTime: '',
endTime: '',
pageNo: 1,
pageSize: 10
})
const shorePowerConnectionDateRange = ref<[string, string]>(['', ''])
const shorePowerConnectionLoading = ref(false)
const shorePowerConnectionTotal = ref(0)
//
const shorePowerConnectionTableData = computed(() => {
//
// 使
return props.shorePowerConnectionData?.slice(
(shorePowerConnectionQueryParams.value.pageNo - 1) * shorePowerConnectionQueryParams.value.pageSize,
shorePowerConnectionQueryParams.value.pageNo * shorePowerConnectionQueryParams.value.pageSize
) || []
})
//
const shorePowerConnectionColumns = ref([
{ prop: 'name', label: 'name', width: 80 },
/* { prop: 'shorePowerName', label: '', width: 150 },
{ prop: 'time', label: '连接时间', width: 180 },
{ prop: 'duration', label: '连接时长(小时)', width: 120 },
{ prop: 'powerConsumption', label: '用电量(kWh)', width: 120 },
{ prop: 'status', label: '状态', width: 100 } */
])
//
const handleBerthingDateChange = (val: [string, string]) => {
if (val && val.length === 2) {
berthingQueryParams.value.startTime = val[0] + ' 00:00:00'
berthingQueryParams.value.endTime = val[1] + ' 23:59:59'
} else {
berthingQueryParams.value.startTime = ''
berthingQueryParams.value.endTime = ''
}
handleShorePowerConnectionSearch()
}
//
const handleClose = () => {
berthingQueryParams.value.ids = null
berthingQueryParams.value.shipId = null
berthingQueryParams.value.type = 1
visible.value = false
}
@ -270,69 +259,41 @@ const handleBerthingSearch = () => {
}
const resetBerthingQuery = () => {
berthingQueryParams.value.keyword = ''
// berthingQueryParams.value.keyword = ''
berthingQueryParams.value.startTime = ''
berthingQueryParams.value.endTime = ''
berthingDateRange.value = ['', '']
berthingQueryParams.value.pageNo = 1
handleBerthingSearch()
handleShorePowerConnectionSearch()
}
const handleBerthingDateChange = (val: [string, string] | null) => {
if (val && val[0] && val[1]) {
berthingQueryParams.value.startTime = val[0]
berthingQueryParams.value.endTime = val[1]
} else {
berthingQueryParams.value.startTime = ''
berthingQueryParams.value.endTime = ''
}
}
const handleBerthingSizeChange = (val: number) => {
berthingQueryParams.value.pageSize = val
berthingQueryParams.value.pageNo = 1
handleBerthingSearch()
handleShorePowerConnectionSearch()
}
const handleBerthingCurrentChange = (val: number) => {
berthingQueryParams.value.pageNo = val
handleBerthingSearch()
handleShorePowerConnectionSearch()
}
//
const handleShorePowerConnectionSearch = () => {
//
emit('shore-power-connection-search', { ...shorePowerConnectionQueryParams.value })
}
const resetShorePowerConnectionQuery = () => {
shorePowerConnectionQueryParams.value.keyword = ''
shorePowerConnectionQueryParams.value.startTime = ''
shorePowerConnectionQueryParams.value.endTime = ''
shorePowerConnectionDateRange.value = ['', '']
shorePowerConnectionQueryParams.value.pageNo = 1
handleShorePowerConnectionSearch()
}
const handleShorePowerConnectionDateChange = (val: [string, string] | null) => {
if (val && val[0] && val[1]) {
shorePowerConnectionQueryParams.value.startTime = val[0]
shorePowerConnectionQueryParams.value.endTime = val[1]
} else {
shorePowerConnectionQueryParams.value.startTime = ''
shorePowerConnectionQueryParams.value.endTime = ''
// const
const params = {
// shipId: berthingQueryParams.value.shipId,
// ids: berthingQueryParams.value.ids,
...(berthingQueryParams.value.ids ? { ids: berthingQueryParams.value.ids } : {}),
...(berthingQueryParams.value.shipId ? { shipId: berthingQueryParams.value.shipId } : {}),
type: berthingQueryParams.value.type,
pageNo: 1,
pageSize: 9999 // 便
}
}
const handleShorePowerConnectionSizeChange = (val: number) => {
shorePowerConnectionQueryParams.value.pageSize = val
shorePowerConnectionQueryParams.value.pageNo = 1
handleShorePowerConnectionSearch()
}
const handleShorePowerConnectionCurrentChange = (val: number) => {
shorePowerConnectionQueryParams.value.pageNo = val
handleShorePowerConnectionSearch()
handleGetShipHistortyList(params)
//
// emit('shore-power-connection-search', { ...shorePowerConnectionQueryParams.value })
}
//
@ -353,36 +314,95 @@ watch(
)
watch(
() => props.shipId,
(newShipId) => {
if (newShipId) {
() => props.shipParam,
(newShipParam) => {
if (newShipParam) {
// ID
berthingTableData.value = []
handleGetShipHistortyList(newShipId)
if (newShipParam.shipId) {
berthingQueryParams.value.shipId = newShipParam.shipId
} else {
berthingQueryParams.value.shipId = null
}
if (newShipParam.ids && newShipParam.ids.length > 0) {
berthingQueryParams.value.ids = newShipParam.ids
} else {
berthingQueryParams.value.ids = null
}
berthingQueryParams.value.type = newShipParam.type
// handleGetShipHistortyList()
handleShorePowerConnectionSearch()
}
}
)
const handleGetShipHistortyList = async (id) => {
console.log('handleGetShipHistortyList', id)
if (!id) return;
const handleGetShipHistortyList = async (param) => {
console.log('handleGetShipHistortyList', param)
if (!param) return;
// try {
const res = await MapApi.getShipHistoryPage({
shipId: parseInt(id, 10), //
/* shipId: param.id, // 将字符串转换为数
pageNo: 1,
pageSize: 10,
type: 4,
type: param.type, */
// ids: [parseInt(id, 10)]
...param
})
console.log(res);
const buildData = await Promise.all(res.list.map(async item => ({
//
let filteredList = [...res.list];
if (berthingQueryParams.value.startTime || berthingQueryParams.value.endTime) {
filteredList = filteredList.filter(item => {
const berthTime = item.usageRecordInfo?.actualBerthTime;
if (!berthTime) return false;
const berthTimestamp = new Date(berthTime).getTime();
const startTime = berthingQueryParams.value.startTime ? new Date(berthingQueryParams.value.startTime).getTime() : 0;
const endTime = berthingQueryParams.value.endTime ? new Date(berthingQueryParams.value.endTime).getTime() : Infinity;
//
if (berthTimestamp >= startTime && berthTimestamp <= endTime) {
return true;
}
//
if (item.usageRecordInfo?.actualDepartureTime) {
const departureTimestamp = new Date(item.usageRecordInfo.actualDepartureTime).getTime();
if (departureTimestamp >= startTime && departureTimestamp <= endTime) {
return true;
}
}
// -
if (item.usageRecordInfo?.actualDepartureTime) {
const departureTimestamp = new Date(item.usageRecordInfo.actualDepartureTime).getTime();
if (berthTimestamp <= endTime && departureTimestamp >= startTime) {
return true;
}
}
return false;
});
}
//
const totalFiltered = filteredList.length;
const pageNo = berthingQueryParams.value.pageNo;
const pageSize = berthingQueryParams.value.pageSize;
const startIndex = (pageNo - 1) * pageSize;
const endIndex = startIndex + pageSize;
const paginatedList = filteredList.slice(startIndex, endIndex);
const buildData = await Promise.all(paginatedList.map(async item => ({
...item,
})))
berthingTableData.value = buildData
berthingTotal.value = totalFiltered
}
onMounted(() => {
console.log('页面加载了!')
console.log('props.shipId', props.shipId)
// console.log('props.shipId', props.shipId)
})
</script>

10
public/map/components/ShipShorePower.vue

@ -713,7 +713,7 @@ interface ShipDataItem {
}
interface Props {
shipData: ShipDataItem[];
shipData: ShipRespVo[];
}
const props = defineProps<Props>()
@ -864,7 +864,7 @@ const formatDateTime = (timestamp: string | number | Date | undefined) => {
const showStatus = async (ship: ShipDataItem) => {
const { usageRecordInfo, applyInfo } = ship;
if (applyInfo.reason == 0 && usageRecordInfo && usageRecordInfo.beginTime) {
if (applyInfo && applyInfo.reason == 0 && usageRecordInfo && usageRecordInfo.beginTime) {
const start = new Date(usageRecordInfo.beginTime);
const end = usageRecordInfo.endTime ? new Date(usageRecordInfo.endTime) : new Date();
@ -931,7 +931,7 @@ const showStatus = async (ship: ShipDataItem) => {
statusClass: 'status-using',
status: `使用岸电${hours}小时${minutes}分钟${seconds}秒,${useValue.toFixed(2)}kWH`
}
} else if (applyInfo.reason != 0) {
} else if (applyInfo && applyInfo.reason != 0) {
// -
const statusMap: Record<string, { text: string; colorType: string }> = {
'1': { text: '岸电用电接口不匹配', colorType: 'default' },
@ -984,7 +984,7 @@ const buildData = async (ship: ShipDataItem) => {
applyInfo: ship.applyInfo,
usageRecordInfo: ship.usageRecordInfo,
shipBasicInfo: ship.shipBasicInfo,
name: ship.shipBasicInfo.name,
name: ship?.shipBasicInfo?.name,
wharf: findNameById(ship.applyInfo?.arrivalDock.toString(), dockIdAndNameList.value),
berth: findNameById(ship.applyInfo?.arrivalBerth.toString(), berthIdAndNameList.value),
beginTime: ship.usageRecordInfo?.beginTime,
@ -1007,7 +1007,7 @@ onMounted(async () => {
berthIdAndNameList.value = await MapApi.getBerthIdAndNameList()
dockIdAndNameList.value = await MapApi.getDockIdAndNameList()
harborDistrictIdAndNameList.value = await MapApi.getHarborDistrictIdAndNameList()
console.log('props.shipData', props.shipData)
// 使Promise.all
localShipData.value = await Promise.all(props.shipData.map(ship => buildData(ship)));
})

4
public/map/components/ShorePowerHistoryDialog.vue

@ -305,11 +305,11 @@ const handleGetShorePowerHistoryList = async (id) => {
if (!id) return;
// try {
const res = await MapApi.getShipHistoryPage({
shipId: parseInt(id, 10), //
// shipId: parseInt(id, 10), //
pageNo: 1,
pageSize: 10,
type: 5,
// ids: [parseInt(id, 10)]
ids: [parseInt(id, 10)]
})
console.log(res);
const buildData = await Promise.all(res.list.map(async item => ({

874
public/map/components/ShorePowerUsage.vue

File diff suppressed because it is too large

1222
public/map/components/cesiumMap.vue

File diff suppressed because it is too large

13
public/map/components/charts/WaveLineChart.vue

@ -62,6 +62,15 @@ const updateChart = () => {
textStyle: {
color: '#fff',
fontSize: props.magnifyMode ? 20 : 12
},
formatter: (params: any) => {
// params
if (params && params.length > 0) {
const time = params[0].name; //
const value = params[0].value; //
return `时间: ${time}<br/>数值: ${value}`;
}
return '';
}
},
xAxis: {
@ -179,6 +188,10 @@ const updateChart = () => {
width: props.magnifyMode ? 2 : 1,
type: 'dashed'
},
// tooltip
tooltip: {
show: false
},
//
label: {
show: false

9
public/map/components/dictionaryTable.ts

@ -72,3 +72,12 @@ export const BERTH_TYPE = [
{ label: '左舷停舶', value: 'left' },
{ label: '右舷停舶', value: 'right' },
]
// 设施类型
export const FACILITY_TYPE = [
{ label: '港区', value: 1 },
{ label: '码头', value: 2 },
{ label: '岸电设施', value: 3 },
{ label: '泊位', value: 4 },
{ label: '用电接口', value: 5 },
]

48
public/map/components/utils.ts

@ -192,3 +192,51 @@ export function getValueById<T extends { id: number | string }, K extends keyof
// 否则返回原始值
return value as any;
}
export function parseRangeToTimestamp(range: string[], granularity: 'year' | 'month' | 'week' | 'day'): [number, number] | null {
if (!range || range.length !== 2) return null;
const [startStr, endStr] = range;
let startDate: Date;
let endDate: Date;
switch (granularity) {
case 'year':
// '2023' → 2023-01-01 00:00:00 ~ 2023-12-31 23:59:59
startDate = new Date(`${startStr}-01-01T00:00:00`);
endDate = new Date(`${endStr}-12-31T23:59:59`);
break;
case 'month':
// '2023-05' → 2023-05-01 00:00:00 ~ 2023-05-31 23:59:59
startDate = new Date(`${startStr}-01T00:00:00`);
// 获取该月最后一天
const yearMonth = startStr.split('-');
const nextMonth = new Date(+yearMonth[0], +yearMonth[1], 0); // 本月最后一天
endDate = new Date(nextMonth.getFullYear(), nextMonth.getMonth(), nextMonth.getDate(), 23, 59, 59);
// 同样处理 endStr
const endYearMonth = endStr.split('-');
const endNextMonth = new Date(+endYearMonth[0], +endYearMonth[1], 0);
endDate = new Date(endNextMonth.getFullYear(), endNextMonth.getMonth(), endNextMonth.getDate(), 23, 59, 59);
break;
case 'week':
case 'day':
default:
// '2023-05-01' → 2023-05-01 00:00:00 ~ 2023-05-01 23:59:59(week 实际也是日期)
startDate = new Date(`${startStr}T00:00:00`);
endDate = new Date(`${endStr}T23:59:59`);
break;
}
const start = startDate.getTime();
const end = endDate.getTime();
if (isNaN(start) || isNaN(end)) {
console.error('日期解析失败:', range, granularity);
return null;
}
return [start, end];
}

309
public/map/index.vue

@ -1,6 +1,12 @@
<template>
<div>
<PublicMapComponents ref="mapComponentRef" class="map-base" />
<PublicMapComponents ref="mapComponentRef" class="map-base" :shore-power-list="ShorePowerList"
:ship-data-list="shipDataList" v-if="dataLoad" :on-instance-click="handleElectricalBoxClick" />
<div v-else class="loading">
<div style="margin: 0 auto">
loading
</div>
</div>
<div class="head">
<div class="head-title">
<span>曹妃甸港区船舶岸电监管平台</span>
@ -20,7 +26,8 @@
<!-- 港区概览 -->
<template v-if="activeHeadGroup === 0">
<PortOverview :ship-status-data="shipStatusData" :shore-power-status-data="shorePowerStatusData"
@item-click="handleSwitch" :realtime-device-data="realtimeDeviceData" />
@item-click="handleSwitch" :realtime-device-data="realtimeDeviceData" :shore-power-list="ShorePowerList"
:ship-data-list="shipDataList" />
</template>
<!-- 港口岸电使用情况 -->
@ -31,64 +38,197 @@
<!-- 港口企业岸电使用 -->
<template v-if="activeHeadGroup === 2">
<CompanyShorePower :companyComparisonData="companyComparisonData" />
<CompanyShorePower :companyComparisonData="companyComparisonData" :realtime-device-data="realtimeDeviceData" />
</template>
<!-- 船舶岸电使用情况 -->
<template v-if="activeHeadGroup === 3">
<ShipShorePower :ship-data="shipStatusData" :selected-ship="selectedShip" @item-click="handleSwitch" />
<ShipShorePower :ship-data="shipDataList" :selected-ship="selectedShip" @item-click="handleSwitch" />
</template>
<template v-if="activeHeadGroup === 4">
<div class="right" style="width: 500px;">
<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>
<el-button class="close-btn" size="small" @click="closeElectricalBoxInfo"
style="margin-left: auto;">×</el-button>
</div>
<div class="card-content">
<div class="ship-detail">
<div class="detail-item">
<span class="label">名称:</span>
<span class="value">{{ selectedElectricalBox?.name || '无' }}</span>
<div v-if="selectedElectricalBox.type" class="right"
:style="`width: ${selectedElectricalBox.type === 'ship' ? '45%' : '20%'}`">
<div v-if="selectedElectricalBox.type === 'ship'" class="right-two-row">
<div class="card digital-twin-card--deep-blue">
<div class="card-title">
<el-button class="close-btn" size="small" type="text" @click="closeElectricalBoxInfo">×</el-button>
<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">{{ selectedElectricalBox.data.shipBasicInfo.name + '-' +
selectedElectricalBox.data.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">{{ selectedElectricalBox.data.shipBasicInfo.length }} </span>
</div>
<div class="detail-item">
<span class="label">宽度:</span>
<span class="value">{{ selectedElectricalBox.data.shipBasicInfo.width }} </span>
</div>
<div class="detail-item">
<span class="label">吨位:</span>
<span class="value">{{ selectedElectricalBox.data.shipBasicInfo.tonnage }} </span>
</div>
<div class="detail-item">
<span class="label">满载吃水深度:</span>
<span class="value">{{ selectedElectricalBox.data.shipBasicInfo.fullLoadDraft }} </span>
</div>
<div class="detail-item">
<span class="label">电压:</span>
<span class="value">{{ getValueById(realtimeDeviceData,
selectedElectricalBox.data.shorePower.voltageDeviceId,
'measureValue') }}</span>
</div>
<div class="detail-item">
<span class="label">电流:</span>
<span class="value">{{ getValueById(realtimeDeviceData,
selectedElectricalBox.data.shorePower.currentDeviceId,
'measureValue') }}</span>
</div>
<div class="detail-item">
<span class="label">频率:</span>
<span class="value">{{ getValueById(realtimeDeviceData,
selectedElectricalBox.data.shorePower.frequencyDeviceId,
'measureValue') }}</span>
</div>
<div class="detail-item">
<span class="label">靠泊状态:</span>
<span class="value">{{ getOperationTypeLabel(selectedElectricalBox.data.shorePowerAndShip.status,
SHORE_POWER_STATUS,
) }}</span>
</div>
<div class="detail-item">
<span class="label">靠泊类型:</span>
<span class="value">{{ getOperationTypeLabel(selectedElectricalBox.data.shorePowerAndShip.type,
BERTH_TYPE)
}}</span>
</div>
<div class="detail-item">
<span class="label">停泊时间:</span>
<span class="value">{{
formatTimestamp(selectedElectricalBox.data?.usageRecordInfo?.actualDepartureTime) }}</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">{{ selectedElectricalBox?.location || '曹妃甸港区华能码头' }}</span>
<span class="label">岸电联系人:</span>
<span class="value">{{ shipSelectedItem.shipBasicInfo.shorePowerContact }}</span>
</div>
<div class="detail-item">
<span class="label">状态:</span>
<span class="value">{{ selectedElectricalBox?.status || '在线' }}</span>
<span class="label">联系方式:</span>
<span class="value">{{ shipSelectedItem.shipBasicInfo.shorePowerContactPhone }}</span>
</div>
<!-- 当前使用数据 -->
<div class="section-title">当前使用数据</div>
<div class="detail-item">
<span class="label">当前使用功率:</span>
<span class="value">{{ selectedElectricalBox?.currentPower || '120' }} kW</span>
<span class="label">船检登记号:</span>
<span class="value">{{ shipSelectedItem.shipBasicInfo.inspectionNo }}</span>
</div>
<div class="detail-item">
<span class="label">当前使用电量:</span>
<span class="value">{{ selectedElectricalBox?.currentEnergy || '45.5' }} kWh</span>
<span class="label">创建时间:</span>
<span class="value">{{ new Date(shipSelectedItem.shipBasicInfo.createTime).toLocaleString() }}</span>
</div> -->
</div>
<!-- 累计历史数据 -->
<div class="section-title">累计历史数据</div>
<div class="detail-item">
<span class="label">累计历史用电:</span>
<span class="value">{{ selectedElectricalBox?.totalEnergy || '1250.8' }} kWh</span>
</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 class="detail-item">
<span class="label">岸电使用时长:</span>
<span class="value">{{ formatDuration(selectedElectricalBox?.data?.usageRecordInfo?.beginTime,
selectedElectricalBox?.data?.usageRecordInfo?.endTime
) }}</span>
</div>
<div v-if="selectedElectricalBox?.data?.applyInfo?.reason === 0" class="detail-item">
<span class="label">岸电使用时长:</span>
<span class="value">{{ showStatus(selectedElectricalBox?.data, realtimeDeviceData)?.status }}</span>
</div>
<div v-if="selectedElectricalBox?.data?.applyInfo?.reason != 0" class="detail-item">
<span class="label">未使用岸电原因:</span>
<span class="value">{{ getOperationTypeLabel(selectedElectricalBox?.data?.applyInfo?.reason,
UNUSED_SHORE_POWER_REASON) }}</span>
</div>
</div>
<div class="detail-item">
<span class="label">累计服务次数:</span>
<span class="value">{{ selectedElectricalBox?.serviceCount || '86' }} </span>
</div>
</div>
</div>
<div v-if="selectedElectricalBox.type === 'shorepower_box'" class="right-two-row">
<div class="card digital-twin-card--deep-blue">
<div class="card-title">
<el-button class="close-btn" size="small" type="text" @click="closeElectricalBoxInfo">×</el-button>
<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">{{ selectedElectricalBox.data?.name }}</span>
</div>
<div class="detail-item">
<span class="label">位置:</span>
<span class="value">{{ selectedElectricalBox.data?.position }}</span>
</div>
<div class="detail-item">
<span class="label">电压:</span>
<span class="value">{{ selectedElectricalBox.data?.shorePowerEquipmentInfo?.voltage }}</span>
</div>
<div class="detail-item">
<span class="label">频率:</span>
<span class="value">{{ selectedElectricalBox.data?.shorePowerEquipmentInfo?.frequency }} </span>
</div>
<div class="detail-item">
<span class="label">容量:</span>
<span class="value">{{ selectedElectricalBox.data?.shorePowerEquipmentInfo?.capacity }}</span>
</div>
<div class="detail-item">
<span class="label">当前电压:</span>
<span class="value">{{ getValueById(realtimeDeviceData, selectedElectricalBox.data?.voltageDeviceId,
'measureValue') }}</span>
</div>
<div class="detail-item">
<span class="label">当前电流:</span>
<span class="value">{{ getValueById(realtimeDeviceData, selectedElectricalBox.data?.currentDeviceId,
'measureValue') }}</span>
</div>
<div class="detail-item">
<span class="label">当前频率:</span>
<span class="value">{{ getValueById(realtimeDeviceData, selectedElectricalBox.data?.frequencyDeviceId,
'measureValue') }}</span>
</div>
<div class="detail-item">
<span class="label">当前总用量:</span>
<span class="value">{{ getValueById(realtimeDeviceData,
selectedElectricalBox.data?.totalPowerDeviceId,
'measureValue') }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
</div>
@ -104,7 +244,9 @@ import ShipShorePower from './components/ShipShorePower.vue'
import dayjs from 'dayjs'
import { onMounted, onUnmounted, ref, computed, watch } from 'vue'
import { MapApi } from "@/api/shorepower/map";
import { RealtimeDeviceData } from '@/types/shorepower'
import { RealtimeDeviceData, ShipBasicInfoRespVO, ShipRespVo, ShorePowerBerth } from '@/types/shorepower'
import { BERTH_TYPE, DOCK_DISTRICT, getOperationTypeLabel, HARBOR_DISTRICT, SHORE_POWER_STATUS } from './components/dictionaryTable'
import { formatDuration, formatTimestamp, getValueById, showStatus } from './components/utils'
defineOptions({ name: 'PublicMap' })
let getRealtimeIntervalId: NodeJS.Timeout | null = null
const headGroupList = ref<{ value: number, label: string }[]>([
@ -133,8 +275,8 @@ const selectHeadGroup = async (value: number) => {
}
activeHeadGroup.value = value
if (value === 1) {
const deviceStatus = await MapApi.getDeviceStatusByIds(totalPowerDeviceId.value)
console.log('deviceStatus', deviceStatus)
// const deviceStatus = await MapApi.getDeviceStatusByIds(totalPowerDeviceId.value)
// console.log('deviceStatus', deviceStatus)
}
}
@ -145,6 +287,11 @@ const currentTime = ref<string>(dayjs().format('YYYY-MM-DD HH:mm:ss'))
//
const realtimeDeviceData = ref<RealtimeDeviceData[]>([])
const ShorePowerList = ref<(ShorePowerBerth & { position: string; })[]>([])
const shipDataList = ref<ShipRespVo[]>([])
const dataLoad = ref<boolean>(false)
//
const scrollContainerRef = ref<HTMLElement | null>(null)
@ -159,7 +306,10 @@ const updateTime = () => {
}
const selectedShip = ref(null)
const selectedElectricalBox = ref(null)
const selectedElectricalBox = ref({
type: '',
data: null
})
/* 回到初始视角 */
const handleOverviewClick = () => {
@ -170,22 +320,33 @@ const handleOverviewClick = () => {
const handleSwitch = (item) => {
console.log(item)
// selectedShip.value = item
mapComponentRef.value?.switchModelView(item.modelInstance)
mapComponentRef.value?.switchModelView(item)
}
/* const handleFlyToitem = (item) => {
mapComponentRef.value?.switchModelView(item)
} */
//
const handleElectricalBoxClick = (data) => {
activeHeadGroup.value = 4
console.log('岸电箱被点击:', data);
//
selectedElectricalBox.value = data;
// selectedElectricalBox.value = data;
selectedElectricalBox.value = {
type: data.type,
data: data.data
}
//
};
//
const closeElectricalBoxInfo = () => {
activeHeadGroup.value = -1;
selectedElectricalBox.value = null;
selectedElectricalBox.value = {
type: '',
data: null
};
};
//
@ -195,6 +356,7 @@ onMounted(() => {
//
if (mapComponentRef.value) {
console.log('mapComponentRef.value', mapComponentRef.value)
mapComponentRef.value.setElectricalBoxClickCallback(handleElectricalBoxClick);
}
})
@ -341,10 +503,33 @@ const handleGetRealtimeAllData = async () => {
}
const handleGetStorePower = async () => {
// console.log('loading')
const harborDistrictId = 1
const harborDistrictList = await HARBOR_DISTRICT()
const dockDistrictList = await DOCK_DISTRICT()
const res = await MapApi.getShorepowerIdAndNameListByHarborDistrictId(harborDistrictId)
ShorePowerList.value = res.map(item => ({
...item,
position: `${getOperationTypeLabel(harborDistrictId, harborDistrictList)}${getOperationTypeLabel(item.shorePowerEquipmentInfo.dockId, dockDistrictList)}${item.name} `,
}))
// console.log('11', res)
}
const handleGetShipData = async () => {
const shipData = await MapApi.getShipInfo({
harborDistrictId: 1
})
shipDataList.value = shipData
}
//
onMounted(() => {
onMounted(async () => {
// DOM
handleGetRealtimeAllData()
await handleGetRealtimeAllData()
await handleGetStorePower()
await handleGetShipData()
dataLoad.value = true
getRealtimeIntervalId = setInterval(() => {
handleGetRealtimeAllData()
}, 5000)
@ -620,6 +805,27 @@ const shipStatusData = computed(() => {
display: flex;
align-items: center;
margin-bottom: 8px;
position: relative;
.close-btn {
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
color: #FFF;
font-size: 20px;
padding: 0;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
&:hover {
color: #ff4d4f;
background-color: rgba(255, 77, 79, 0.1);
}
}
.vertical-line {
width: 2px;
@ -707,6 +913,13 @@ const shipStatusData = computed(() => {
white-space: nowrap;
}
.right-two-row {
display: flex;
gap: 10px;
height: 100%;
}
.ship-name {
width: 20%;
}

Loading…
Cancel
Save