|
|
|
|
<template>
|
|
|
|
|
<div class="company-shore-power">
|
|
|
|
|
<div class="left" style="width: 800px;" :style="{ width: selectedShorePowerItem ? '800px' : '420px' }">
|
|
|
|
|
<div style="display: flex; gap: 12px; height: 100%;">
|
|
|
|
|
<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 v-if="selectedShorePowerItem" 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>
|
|
|
|
|
<el-button class="close-btn" type="text" @click="closeShorePowerDetail">×</el-button>
|
|
|
|
|
<!-- <div style="ma">
|
|
|
|
|
<el-button type="primary" @click="handleOpenHistory">查看历史记录</el-button>
|
|
|
|
|
</div> -->
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div class="card-content">
|
|
|
|
|
<div class="ship-detail">
|
|
|
|
|
<div class="detail-item">
|
|
|
|
|
<span class="label">名称:</span>
|
|
|
|
|
<span class="value">{{ selectedShorePowerItem?.name }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="detail-item">
|
|
|
|
|
<span class="label">位置:</span>
|
|
|
|
|
<span class="value">{{ selectedShorePowerItem?.position }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="detail-item">
|
|
|
|
|
<span class="label">电压:</span>
|
|
|
|
|
<span class="value">{{ selectedShorePowerItem?.shorePowerEquipmentInfo?.voltage }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="detail-item">
|
|
|
|
|
<span class="label">频率:</span>
|
|
|
|
|
<span class="value">{{ selectedShorePowerItem?.shorePowerEquipmentInfo?.frequency }} </span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="detail-item">
|
|
|
|
|
<span class="label">容量:</span>
|
|
|
|
|
<span class="value">{{ selectedShorePowerItem?.shorePowerEquipmentInfo?.capacity }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="detail-item">
|
|
|
|
|
<span class="label">当前电压:</span>
|
|
|
|
|
<span class="value">{{ getValueById(realtimeDeviceData, selectedShorePowerItem.voltageDeviceId,
|
|
|
|
|
'measureValue') }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="detail-item">
|
|
|
|
|
<span class="label">当前电流:</span>
|
|
|
|
|
<span class="value">{{ getValueById(realtimeDeviceData, selectedShorePowerItem.currentDeviceId,
|
|
|
|
|
'measureValue') }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="detail-item">
|
|
|
|
|
<span class="label">当前频率:</span>
|
|
|
|
|
<span class="value">{{ getValueById(realtimeDeviceData, selectedShorePowerItem.frequencyDeviceId,
|
|
|
|
|
'measureValue') }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="detail-item">
|
|
|
|
|
<span class="label">当前总用量:</span>
|
|
|
|
|
<span class="value">{{ getValueById(realtimeDeviceData, selectedShorePowerItem.totalPowerDeviceId,
|
|
|
|
|
'measureValue') }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="detail-item">
|
|
|
|
|
<span class="label">当前状态:</span>
|
|
|
|
|
<span class="value">{{ selectedShorePowerItem.storePowerStatus }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="right" style="width: 1000px;">
|
|
|
|
|
<!-- 码头信息卡片 -->
|
|
|
|
|
<div class="card digital-twin-card--deep-blue">
|
|
|
|
|
<div class="card-title" 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>
|
|
|
|
|
<!-- 返回上个页面 -->
|
|
|
|
|
<el-button type="primary" @click.stop="handleGoBack()">返回</el-button>
|
|
|
|
|
|
|
|
|
|
<!-- <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 class="card-content">
|
|
|
|
|
<div v-for="company in companyComparisonData" :key="company.name" class="company-section">
|
|
|
|
|
<div class="data-update-time">起始时间: {{ getStartTimeByRange(getCompanyTimeRange(company.id)) }} 更新时间: {{
|
|
|
|
|
realtimeDeviceDataTime }}</div>
|
|
|
|
|
<div class="company-header">
|
|
|
|
|
<div class="company-info">
|
|
|
|
|
<div class="company-name">{{ company.name }}</div>
|
|
|
|
|
<div class="company-berth-count">泊位数: {{ company.shorePowerCount || 0 }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="time-range-container">
|
|
|
|
|
<button v-for="option in timeRangeOptions" :key="option.value"
|
|
|
|
|
:class="['time-range-btn', { active: getCompanyTimeRange(company.id) === option.value }]"
|
|
|
|
|
@click.stop="() => handleTimeRangeChange(company.id, option.value)">
|
|
|
|
|
{{ option.label }}
|
|
|
|
|
</button>
|
|
|
|
|
<div class="company-total">总量: {{ handGetDeviceData(company.shorePowerIds,
|
|
|
|
|
getCompanyTimeRange(company.id)) }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
<div class="shorepower-container">
|
|
|
|
|
<div class="diste-box" v-for="(disteItem, index) in (company.distributionList || [])" :key="index">
|
|
|
|
|
<div class="diste-name">{{ disteItem.name }}</div>
|
|
|
|
|
|
|
|
|
|
<div class="shorepower-box">
|
|
|
|
|
<div class="shorepower-item" v-for="(shorePower, shorePowerIndex) in (disteItem.shorePowerList || [])"
|
|
|
|
|
:key="shorePowerIndex">
|
|
|
|
|
<div class="shorepower-value" @click="handleClickhorePowerValue(shorePower)">{{
|
|
|
|
|
handGetDeviceData(shorePower.totalPowerDeviceId, getCompanyTimeRange(company.id)) || 0 }}</div>
|
|
|
|
|
|
|
|
|
|
<div class="shorepower-label" @click="handleClickShorePowerName(shorePower)">{{ shorePower.name }}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</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, computed } from 'vue'
|
|
|
|
|
import { MapApi } from "@/api/shorepower/map";
|
|
|
|
|
import ShipHistoryDialog from './ShipHistoryDialog.vue';
|
|
|
|
|
import { CompanyShorePowerData, RealtimeDeviceData, ShipRespVo, ShorePowerBerth } from '@/types/shorepower';
|
|
|
|
|
import { getValueById } from './utils';
|
|
|
|
|
// 定义组件属性
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const historyVisible = ref({
|
|
|
|
|
visible: false,
|
|
|
|
|
searchParams: {
|
|
|
|
|
shipId: 0 as number | null,
|
|
|
|
|
ids: [] as number[] | null,
|
|
|
|
|
type: 1 as number
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
interface Props {
|
|
|
|
|
realtimeDeviceData: RealtimeDeviceData[];
|
|
|
|
|
realtimeDeviceDataTime: string;
|
|
|
|
|
shorePowerList: ShorePowerBerth[];
|
|
|
|
|
handleGoBack: () => void;
|
|
|
|
|
yearData: any[];
|
|
|
|
|
monthData: any[];
|
|
|
|
|
dayData: any[];
|
|
|
|
|
companyComparisonData: CompanyShorePowerData[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const props = defineProps<Props>()
|
|
|
|
|
const selectedShorePowerItem = ref<ShorePowerBerth>()
|
|
|
|
|
const shorepowerSelectedItem = ref<ShorePowerBerth & { position: string; } | null>(null)
|
|
|
|
|
const storeSearchKeyword = ref('')
|
|
|
|
|
// 时间范围选项定义
|
|
|
|
|
interface TimeRangeOption {
|
|
|
|
|
value: 'day' | 'month' | 'year' | 'realtime';
|
|
|
|
|
label: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const timeRangeOptions: TimeRangeOption[] = [
|
|
|
|
|
{ value: 'day', label: '当日' },
|
|
|
|
|
{ value: 'month', label: '当月' },
|
|
|
|
|
{ value: 'year', label: '当年' },
|
|
|
|
|
{ value: 'realtime', label: '汇总' },
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
const closeShorePowerDetail = () => {
|
|
|
|
|
selectedShorePowerItem.value = undefined
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理岸电箱搜索输入
|
|
|
|
|
const handlStoreSearch = () => {
|
|
|
|
|
// 输入处理逻辑(如果需要额外处理可以在这里添加)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getStatusClass = (status: string | undefined) => {
|
|
|
|
|
switch (status) {
|
|
|
|
|
case '正常':
|
|
|
|
|
return 'status-normal'
|
|
|
|
|
case '在用':
|
|
|
|
|
return 'status-normal'
|
|
|
|
|
case '在线':
|
|
|
|
|
return 'status-normal'
|
|
|
|
|
case '空闲':
|
|
|
|
|
return 'status-idle'
|
|
|
|
|
case '故障':
|
|
|
|
|
return 'status-fault'
|
|
|
|
|
case '超容':
|
|
|
|
|
return 'status-maintenance'
|
|
|
|
|
case '异常':
|
|
|
|
|
return 'status-abnormal'
|
|
|
|
|
case '维修中':
|
|
|
|
|
return 'status-maintenance'
|
|
|
|
|
case '岸电使用中':
|
|
|
|
|
return 'status-shorepower'
|
|
|
|
|
// case '岸电故障':
|
|
|
|
|
// return 'status-fault'
|
|
|
|
|
default:
|
|
|
|
|
return 'status-normal'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 过滤后的岸电箱数据
|
|
|
|
|
const filteredShorePowerList = computed(() => {
|
|
|
|
|
if (!storeSearchKeyword.value) {
|
|
|
|
|
return props.shorePowerList
|
|
|
|
|
}
|
|
|
|
|
return props.shorePowerList.filter(shorepower =>
|
|
|
|
|
shorepower.name.toLowerCase().includes(storeSearchKeyword.value.toLowerCase())
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 定义事件
|
|
|
|
|
const emit = defineEmits<{
|
|
|
|
|
(e: 'switch-ship', ship: ShipRespVo): void;
|
|
|
|
|
(e: 'item-click', item: any): void;
|
|
|
|
|
// handleSelectItem(ship)
|
|
|
|
|
|
|
|
|
|
}>()
|
|
|
|
|
|
|
|
|
|
const handleSelectShorePower = async (shorepower: ShorePowerBerth & { position: string }) => {
|
|
|
|
|
// selectedItem.value = shorepower
|
|
|
|
|
shorepowerSelectedItem.value = shorepower
|
|
|
|
|
selectedShorePowerItem.value = shorepower
|
|
|
|
|
emit('item-click', {
|
|
|
|
|
type: 'shorepower_box',
|
|
|
|
|
item: shorepower
|
|
|
|
|
})
|
|
|
|
|
// const data = await MapApi.getRealtimeDataByIdList({ ids: shorepower.totalPowerDeviceId })
|
|
|
|
|
// console.log('voltageDeviceId', data)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 为每个公司维护独立的时间范围状态
|
|
|
|
|
const companyTimeRanges = ref<Record<number, 'realtime' | 'day' | 'month' | 'year'>>({})
|
|
|
|
|
|
|
|
|
|
// 获取指定公司的时间范围设置,默认为'day'
|
|
|
|
|
const getCompanyTimeRange = (companyId: number) => {
|
|
|
|
|
return companyTimeRanges.value[companyId] || 'day'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据时间粒度计算起始时间
|
|
|
|
|
const getStartTimeByRange = (range: 'realtime' | 'day' | 'month' | 'year') => {
|
|
|
|
|
const now = new Date();
|
|
|
|
|
|
|
|
|
|
switch (range) {
|
|
|
|
|
case 'day':
|
|
|
|
|
// 当天的 00:00:00
|
|
|
|
|
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
|
|
|
return formatDate(today);
|
|
|
|
|
case 'month':
|
|
|
|
|
// 当月第一天的 00:00:00
|
|
|
|
|
const firstDayOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
|
|
|
|
|
return formatDate(firstDayOfMonth);
|
|
|
|
|
case 'year':
|
|
|
|
|
// 当年第一天的 00:00:00
|
|
|
|
|
const firstDayOfYear = new Date(now.getFullYear(), 0, 1);
|
|
|
|
|
return formatDate(firstDayOfYear);
|
|
|
|
|
case 'realtime':
|
|
|
|
|
// 固定起始时间,可以根据实际需求修改
|
|
|
|
|
return '2020-01-01 00:00:00';
|
|
|
|
|
default:
|
|
|
|
|
return formatDate(new Date(now.getFullYear(), now.getMonth(), now.getDate()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 格式化日期为 YYYY-MM-DD HH:mm:ss 格式
|
|
|
|
|
const formatDate = (date: Date) => {
|
|
|
|
|
const year = date.getFullYear();
|
|
|
|
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
|
|
|
const day = String(date.getDate()).padStart(2, '0');
|
|
|
|
|
return `${year}-${month}-${day} 00:00:00`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理时间范围选择
|
|
|
|
|
const handleTimeRangeChange = (companyId: number, range: 'realtime' | 'day' | 'month' | 'year') => {
|
|
|
|
|
companyTimeRanges.value[companyId] = range
|
|
|
|
|
// 这里可以添加根据时间范围切换数据源的逻辑
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 点击泊位box */
|
|
|
|
|
const handleClickShorePowerName = (data: CompanyShorePowerData) => {
|
|
|
|
|
const shorePower = props.shorePowerList.find(item => item.id === data.id)
|
|
|
|
|
selectedShorePowerItem.value = shorePower
|
|
|
|
|
console.log(shorePower)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleClickhorePowerValue = (data: CompanyShorePowerData) => {
|
|
|
|
|
const shorePower = props.shorePowerList.find(item => item.id === data.id)
|
|
|
|
|
if (!shorePower) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
showShorePowerHistory(shorePower)
|
|
|
|
|
/* selectedShorePowerItem.value = shorePower
|
|
|
|
|
console.log(shorePower) */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const showShorePowerHistory = (berth: ShorePowerBerth) => {
|
|
|
|
|
historyVisible.value = {
|
|
|
|
|
visible: true,
|
|
|
|
|
searchParams: {
|
|
|
|
|
shipId: null,
|
|
|
|
|
ids: [berth.id],
|
|
|
|
|
type: 4,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// const companyComparisonData = ref<companyData[]>([])
|
|
|
|
|
|
|
|
|
|
// 创建一个响应式的设备数据映射,以提高查找效率并确保响应性
|
|
|
|
|
const deviceDataMap = computed(() => {
|
|
|
|
|
const map = new Map<number, RealtimeDeviceData>();
|
|
|
|
|
props.realtimeDeviceData.forEach(item => {
|
|
|
|
|
map.set(item.deviceId, item);
|
|
|
|
|
});
|
|
|
|
|
return map;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const handGetDeviceData = (deviceId: number | number[], range: 'realtime' | 'day' | 'month' | 'year') => {
|
|
|
|
|
let totalValue = 0;
|
|
|
|
|
let rangData: RealtimeDeviceData[] = []
|
|
|
|
|
if (range === 'realtime') {
|
|
|
|
|
rangData = props.realtimeDeviceData
|
|
|
|
|
} else if (range === 'day') {
|
|
|
|
|
rangData = props.dayData
|
|
|
|
|
} else if (range === 'month') {
|
|
|
|
|
rangData = props.monthData
|
|
|
|
|
} else if (range === 'year') {
|
|
|
|
|
rangData = props.yearData
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Array.isArray(deviceId)) {
|
|
|
|
|
// If deviceId is an array, sum all the measure values and subtract start values
|
|
|
|
|
|
|
|
|
|
deviceId.forEach(id => {
|
|
|
|
|
const deviceData = deviceDataMap.value.get(id);
|
|
|
|
|
const startData = rangData.find(item => item.deviceId === id)
|
|
|
|
|
|
|
|
|
|
if (deviceData?.measureValue) {
|
|
|
|
|
totalValue += deviceData.measureValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// For non-realtime ranges, subtract the start value
|
|
|
|
|
if (range !== 'realtime' && startData?.measureValue) {
|
|
|
|
|
totalValue -= startData.measureValue;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
// If deviceId is a single number, get its measure value
|
|
|
|
|
const deviceData = deviceDataMap.value.get(deviceId);
|
|
|
|
|
const startData = rangData.find(item => item.deviceId === deviceId)
|
|
|
|
|
|
|
|
|
|
if (deviceData?.measureValue) {
|
|
|
|
|
totalValue = deviceData.measureValue;
|
|
|
|
|
}
|
|
|
|
|
if (range !== 'realtime' && startData?.measureValue) {
|
|
|
|
|
totalValue -= startData.measureValue
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return totalValue.toFixed(2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// const handleGetBuildData = async () => {
|
|
|
|
|
// const dockList = await MapApi.getDockIdAndNameList()
|
|
|
|
|
// // const berthList = await MapApi.getBerthIdAndNameList()
|
|
|
|
|
// const distributionList = groupByShorePowerEquipmentId(props.shorePowerList)
|
|
|
|
|
// const buildData = dockList.map(dock => {
|
|
|
|
|
// const filterData = distributionList.filter(item => item.dockId === dock.id)
|
|
|
|
|
// const shorePowerCount = filterData.reduce((total, item) => {
|
|
|
|
|
// return total + item.shorePowerList.length
|
|
|
|
|
// }, 0)
|
|
|
|
|
// return {
|
|
|
|
|
// ...dock,
|
|
|
|
|
// shorePowerCount: shorePowerCount, // 岸电箱总数
|
|
|
|
|
// shorePowerIds: filterData.map(item => item.shorePowerList.map(shorePower => shorePower.id)).flat(),
|
|
|
|
|
// distributionList: filterData
|
|
|
|
|
// }
|
|
|
|
|
// })
|
|
|
|
|
// companyComparisonData.value = buildData
|
|
|
|
|
|
|
|
|
|
// /* 转换函数 */
|
|
|
|
|
// function groupByShorePowerEquipmentId(data) {
|
|
|
|
|
// const map = new Map();
|
|
|
|
|
// for (const item of data) {
|
|
|
|
|
// const { shorePowerEquipmentInfo, ...rest } = item;
|
|
|
|
|
// const id = shorePowerEquipmentInfo.id;
|
|
|
|
|
// if (!map.has(id)) {
|
|
|
|
|
// map.set(id, {
|
|
|
|
|
// ...shorePowerEquipmentInfo,
|
|
|
|
|
// shorePowerList: []
|
|
|
|
|
// });
|
|
|
|
|
// }
|
|
|
|
|
// map.get(id).shorePowerList.push(rest);
|
|
|
|
|
// }
|
|
|
|
|
// return Array.from(map.values());
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
// handleGetBuildData()
|
|
|
|
|
})
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
|
.company-shore-power {
|
|
|
|
|
display: flex;
|
|
|
|
|
height: 100%;
|
|
|
|
|
gap: 10px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.left {
|
|
|
|
|
/* display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
height: 100%;
|
|
|
|
|
gap: 10px; */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.card {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
height: 100%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.card-content {
|
|
|
|
|
flex: 1;
|
|
|
|
|
height: 100%;
|
|
|
|
|
min-height: 0;
|
|
|
|
|
padding-bottom: 50px;
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 总览网格样式 */
|
|
|
|
|
/* .overview-grid {
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: 1fr 1fr 1fr 1fr;
|
|
|
|
|
gap: 8px;
|
|
|
|
|
padding: 4px;
|
|
|
|
|
height: 100%;
|
|
|
|
|
} */
|
|
|
|
|
.shorepower-container {
|
|
|
|
|
display: flex;
|
|
|
|
|
gap: 8px;
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
|
|
|
|
.diste-box {
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
display: inline-block;
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
|
|
|
|
.diste-name {
|
|
|
|
|
height: 28px;
|
|
|
|
|
background-color: rgba(0, 112, 192, 0.579);
|
|
|
|
|
border-radius: 6px 6px 0 0;
|
|
|
|
|
width: 100%;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
color: #fff;
|
|
|
|
|
padding: 4px;
|
|
|
|
|
border-bottom: 1px solid rgba(255, 255, 255, 0.3);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.shorepower-box {
|
|
|
|
|
display: flex;
|
|
|
|
|
gap: 8px;
|
|
|
|
|
// flex-wrap: wrap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.shorepower-item {
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
width: 224px;
|
|
|
|
|
// display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
padding: 4px;
|
|
|
|
|
background-color: rgba(30, 120, 255, 0.15);
|
|
|
|
|
border-radius: 0 0 8px 8px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.shorepower-label {
|
|
|
|
|
text-align: center;
|
|
|
|
|
font-size: 24px;
|
|
|
|
|
color: #ccc;
|
|
|
|
|
margin-bottom: 2px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
// 上浮
|
|
|
|
|
transform: translateY(-2px);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.shorepower-value {
|
|
|
|
|
font-size: 36px;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
color: #1296db;
|
|
|
|
|
text-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
|
|
|
|
|
margin-bottom: 2px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
// 上浮
|
|
|
|
|
transform: translateY(-2px);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* 企业区块样式 */
|
|
|
|
|
.company-section {
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
padding-bottom: 16px;
|
|
|
|
|
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.company-section:last-child {
|
|
|
|
|
border-bottom: none;
|
|
|
|
|
margin-bottom: 0;
|
|
|
|
|
padding-bottom: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 企业头部样式 */
|
|
|
|
|
.company-header {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
padding: 0 4px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.company-info {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: baseline;
|
|
|
|
|
gap: 2px
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.company-name {
|
|
|
|
|
font-size: 24px;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
color: #fff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.company-berth-count {
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
color: #eee;
|
|
|
|
|
margin-top: 4px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.company-total {
|
|
|
|
|
font-size: 24px;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
color: #1296db;
|
|
|
|
|
background-color: rgba(18, 150, 219, 0.1);
|
|
|
|
|
padding: 2px 8px;
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.data-update-time {
|
|
|
|
|
margin-left: 6px;
|
|
|
|
|
font-size: 24px;
|
|
|
|
|
color: #aaa;
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 自定义滚动条样式 */
|
|
|
|
|
.card-content::-webkit-scrollbar {
|
|
|
|
|
width: 6px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.card-content::-webkit-scrollbar-track {
|
|
|
|
|
background: rgba(255, 255, 255, 0.1);
|
|
|
|
|
border-radius: 3px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.card-content::-webkit-scrollbar-thumb {
|
|
|
|
|
background: rgba(17, 138, 237, 0.7);
|
|
|
|
|
border-radius: 3px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.card-content::-webkit-scrollbar-thumb:hover {
|
|
|
|
|
background: rgba(17, 138, 237, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.time-range-container {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 4px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.close-btn {
|
|
|
|
|
width: 36px;
|
|
|
|
|
height: 36px;
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
}
|
|
|
|
|
</style>
|