jiangAB 4 weeks ago
parent
commit
56f42a1c17
  1. 2
      .env.dev
  2. 2
      .env.local
  3. 2
      .env.prod
  4. 2
      .env.stage
  5. 2
      .env.test
  6. 46
      public/map/components/CompanyShorePower.vue
  7. 262
      public/map/components/PortOverview.vue
  8. 184
      public/map/components/ShipHistoryDialog.vue
  9. 52
      public/map/components/ShipShorePower.vue
  10. 73
      public/map/components/ShorePowerHistoryDialog.vue
  11. 59
      public/map/components/ShorePowerUsage.vue
  12. 2
      public/map/components/bk/map_index.vue
  13. 198
      public/map/components/cesiumMap.vue
  14. 24
      public/map/components/charts/BarChartMinute.vue
  15. 3
      public/map/components/charts/WaveLineChart.vue
  16. 74
      public/map/components/dictionaryTable.ts
  17. 194
      public/map/components/utils.ts
  18. 88
      public/map/index.vue
  19. 35
      src/api/shorepower/map/index.ts
  20. 474
      src/types/shorepower.d.ts

2
.env.dev

@ -22,7 +22,7 @@ VITE_DROP_CONSOLE=false
VITE_SOURCEMAP=true
# 打包路径
VITE_BASE_PATH='http://server.ayaojies.com.cn:48080'
VITE_BASE_PATH='http://106.118.88.15:48080'
# 输出路径
VITE_OUT_DIR=dist

2
.env.local

@ -4,7 +4,7 @@ NODE_ENV=development
VITE_DEV=true
# 请求路径
VITE_BASE_URL='http://server.ayaojies.com.cn:48080'
VITE_BASE_URL='http://106.118.88.15:48080'
# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持 S3 服务
VITE_UPLOAD_TYPE=server

2
.env.prod

@ -4,7 +4,7 @@ NODE_ENV=production
VITE_DEV=false
# 请求路径
VITE_BASE_URL='http://server.ayaojies.com.cn:48080'
VITE_BASE_URL='http://106.118.88.15:48080'
# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持S3服务
VITE_UPLOAD_TYPE=server

2
.env.stage

@ -4,7 +4,7 @@ NODE_ENV=production
VITE_DEV=false
# 请求路径
VITE_BASE_URL='http://server.ayaojies.com.cn:48080'
VITE_BASE_URL='http://106.118.88.15:48080'
# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持S3服务
VITE_UPLOAD_TYPE=server

2
.env.test

@ -4,7 +4,7 @@ NODE_ENV=production
VITE_DEV=false
# 请求路径
VITE_BASE_URL='http://server.ayaojies.com.cn:48080'
VITE_BASE_URL='http://106.118.88.15:48080'
# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持S3服务
VITE_UPLOAD_TYPE=server

46
public/map/components/CompanyShorePower.vue

@ -1,25 +1,31 @@
<template>
<div class="company-shore-power">
<div class="left" style="width: 40%;">
<div class="left" style="width: 1000px;">
<!-- 码头信息卡片 -->
<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 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>
<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="company-header">
<div class="company-name">{{ company.name }}</div>
<div class="company-total">总量: {{ company.value }}</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 class="overview-label">{{ berth.name }}</div>
</div>
@ -56,10 +62,10 @@ const props = defineProps<Props>()
}
.left {
display: flex;
/* display: flex;
flex-direction: column;
height: 100%;
gap: 10px;
gap: 10px; */
}
.card {
@ -72,6 +78,7 @@ const props = defineProps<Props>()
flex: 1;
height: 100%;
min-height: 0;
padding-bottom: 50px;
overflow-y: auto;
}
@ -151,4 +158,23 @@ const props = defineProps<Props>()
padding: 2px 8px;
border-radius: 4px;
}
/* 自定义滚动条样式 */
.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);
}
</style>

262
public/map/components/PortOverview.vue

@ -21,15 +21,15 @@
<div class="ship-table-column ship-status-header">历史</div>
</div>
<div class="ship-table-body">
<div v-for="shorepower in filteredShorePowerStatusData" :key="shorepower.id" class="ship-table-row"
@click="handleSwitch(shorepower, 'shorepower')">
<div v-for="shorepower in ShorePowerList" :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.shorePowerEquipment.name }}</span>
<span class="ship-name-text">{{ shorepower.name }}</span>
</div>
<div class="ship-table-column ship-status">
<div class="status-tag" :class="getStatusClass('正常')">
正常
<div class="status-tag" :class="getStatusClass(StatusText(shorepower.status))">
{{ StatusText(shorepower.status) }}
</div>
<!-- <div class="status-tag" :class="getStatusClass('空闲')">
空闲
@ -93,7 +93,7 @@
</div>
</div>
<div class="right" :style="`width: ${show_type === 'ship' ? '45%' : '20%'}`">
<div v-if="selectedItem && show_type === 'ship'" class="right-two-row">
<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>
@ -103,53 +103,84 @@
<div class="card-content">
<div class="ship-detail">
<div class="detail-item">
<span class="label">船名:</span>
<span class="value">{{ selectedItem.shipBasicInfo.name }}</span>
<span class="label">名称:</span>
<span class="value">{{ shipSelectedItem.shipBasicInfo.name + '-' + shipSelectedItem.shipBasicInfo.nameEn
}}</span>
</div>
<div class="detail-item">
<!-- <div class="detail-item">
<span class="label">英文船名:</span>
<span class="value">{{ selectedItem.shipBasicInfo.nameEn }}</span>
</div>
<div class="detail-item">
</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">{{ selectedItem.shipBasicInfo.length }} </span>
<span class="label">宽度:</span>
<span class="value">{{ shipSelectedItem.shipBasicInfo.width }} </span>
</div>
<div class="detail-item">
<span class="label">船宽:</span>
<span class="value">{{ selectedItem.shipBasicInfo.width }} </span>
<span class="label">吨位:</span>
<span class="value">{{ shipSelectedItem.shipBasicInfo.tonnage }} </span>
</div>
<div class="detail-item">
<span class="label">满载吃水深度:</span>
<span class="value">{{ selectedItem.shipBasicInfo.fullLoadDraft }} </span>
<span class="value">{{ shipSelectedItem.shipBasicInfo.fullLoadDraft }} </span>
</div>
<div class="detail-item">
<span class="label">吨位:</span>
<span class="value">{{ selectedItem.shipBasicInfo.tonnage }} </span>
<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?.actualDepartureTime) }}</span>
</div>
<!-- <div class="detail-item">
<span class="label">航运单位:</span>
<span class="value">{{ selectedItem.shipBasicInfo.shippingCompany }}</span>
<span class="value">{{ shipSelectedItem.shipBasicInfo.shippingCompany }}</span>
</div>
<div class="detail-item">
<span class="label">岸电联系人:</span>
<span class="value">{{ selectedItem.shipBasicInfo.shorePowerContact }}</span>
<span class="value">{{ shipSelectedItem.shipBasicInfo.shorePowerContact }}</span>
</div>
<div class="detail-item">
<span class="label">联系方式:</span>
<span class="value">{{ selectedItem.shipBasicInfo.shorePowerContactPhone }}</span>
<span class="value">{{ shipSelectedItem.shipBasicInfo.shorePowerContactPhone }}</span>
</div>
<div class="detail-item">
<span class="label">船检登记号:</span>
<span class="value">{{ selectedItem.shipBasicInfo.inspectionNo }}</span>
<span class="value">{{ shipSelectedItem.shipBasicInfo.inspectionNo }}</span>
</div>
<div class="detail-item">
<span class="label">创建时间:</span>
<span class="value">{{ new Date(selectedItem.shipBasicInfo.createTime).toLocaleString() }}</span>
</div>
<span class="value">{{ new Date(shipSelectedItem.shipBasicInfo.createTime).toLocaleString() }}</span>
</div> -->
</div>
</div>
</div>
@ -157,25 +188,30 @@
<div class="card-title">
<div class="vertical-line"></div>
<img src="@/assets/svgs/data.svg" class="title-icon" />
<span class="title-text">岸电信息</span>
<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>
<span class="label">岸电使用时长:</span>
<span class="value">{{ formatDuration(shipSelectedItem?.usageRecordInfo?.beginTime,
shipSelectedItem?.usageRecordInfo?.endTime
) }}</span>
</div>
<div class="detail-item">
<span class="label">靠泊状态:</span>
<span class="value">{{ getShorePowerStatusText(selectedItem.shorePowerAndShip.status) }}</span>
<div v-if="shipSelectedItem.applyInfo.reason === 0" class="detail-item">
<span class="label">岸电使用时长:</span>
<span class="value">{{ showStatus(shipSelectedItem, realtimeDeviceData)?.status }}</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>
</div>
</div>
</div>
<div v-else-if="selectedItem && show_type === 'shorepower'" class="right-two-row">
<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>
@ -186,39 +222,43 @@
<div class="ship-detail">
<div class="detail-item">
<span class="label">名称:</span>
<span class="value">{{ selectedItem.shorePowerEquipment.name }}</span>
<span class="value">{{ shorepowerSelectedItem?.name }}</span>
</div>
<div class="detail-item">
<span class="label">位置:</span>
<span class="value">{{ selectedItem.shorePowerEquipment.position }}</span>
<span class="value">{{ shorepowerSelectedItem?.position }}</span>
</div>
<div class="detail-item">
<span class="label">电压:</span>
<span class="value">{{ selectedItem.shorePowerEquipment.voltage }}</span>
<span class="value">{{ shorepowerSelectedItem?.shorePowerEquipmentInfo?.voltage }}</span>
</div>
<div class="detail-item">
<span class="label">频率:</span>
<span class="value">{{ selectedItem.shorePowerEquipment.frequency }} </span>
<span class="value">{{ shorepowerSelectedItem?.shorePowerEquipmentInfo?.frequency }} </span>
</div>
<div class="detail-item">
<span class="label">容量:</span>
<span class="value">{{ selectedItem.shorePowerEquipment.capacity }}</span>
<span class="value">{{ shorepowerSelectedItem?.shorePowerEquipmentInfo?.capacity }}</span>
</div>
<div class="detail-item">
<span class="label">当前电压:</span>
<span class="value"></span>
<span class="value">{{ getValueById(realtimeDeviceData, shorepowerSelectedItem.voltageDeviceId,
'measureValue') }}</span>
</div>
<div class="detail-item">
<span class="label">当前电流:</span>
<span class="value"></span>
<span class="value">{{ getValueById(realtimeDeviceData, shorepowerSelectedItem.currentDeviceId,
'measureValue') }}</span>
</div>
<div class="detail-item">
<span class="label">当前频率:</span>
<span class="value"></span>
<span class="value">{{ getValueById(realtimeDeviceData, shorepowerSelectedItem.frequencyDeviceId,
'measureValue') }}</span>
</div>
<div class="detail-item">
<span class="label">当前总用量:</span>
<span class="value">{{ selectedItem.shorePowerEquipment.measureValue }}</span>
<span class="value">{{ getValueById(realtimeDeviceData, shorepowerSelectedItem.totalPowerDeviceId,
'measureValue') }}</span>
</div>
</div>
</div>
@ -246,7 +286,7 @@
</div> -->
</div>
<div v-else class="card digital-twin-card--deep-blue" style="flex: 1;">
<!-- <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" />
@ -255,18 +295,20 @@
<div class="card-content">
<div class="no-selection">请选择设备以查看详细信息</div>
</div>
</div>
</div> -->
</div>
<!-- 岸电箱历史记录弹窗 -->
<ShorePowerHistoryDialog v-model="shorePowerHistoryVisible" :data="shorePowerHistoryData"
<ShorePowerHistoryDialog v-model="shorePowerHistoryVisible.visible" :data="shorePowerHistoryData"
:ship-connection-data="shorePowerConnectionData" @search="handleShorePowerHistorySearch"
@ship-connection-search="handleShorePowerConnectionSearch" />
@ship-connection-search="handleShorePowerConnectionSearch"
:shore-power-id="shorePowerHistoryVisible.shorePowerId" />
<!-- 船舶历史记录弹窗 -->
<ShipHistoryDialog v-model="shipHistoryVisible" :berthing-data="shipHistoryData"
<ShipHistoryDialog v-model="shipHistoryVisible.visible" :berthing-data="shipHistoryData"
:shore-power-connection-data="shipShorePowerConnectionData" @berthing-search="handleShipHistorySearch"
@shore-power-connection-search="handleShipShorePowerConnectionSearch" />
@shore-power-connection-search="handleShipShorePowerConnectionSearch" :ship-id="shipHistoryVisible.shipId"
:realtime-device-data="realtimeDeviceData" />
</div>
</template>
@ -275,26 +317,16 @@ 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 { formatDuration, formatTimestamp, getValueById, showStatus } from './utils';
//
interface ShipItem {
id: string;
shipBasicInfo: {
name: string;
};
shorePowerEquipment: {
name: string;
measureValue: string;
};
shorePowerAndShip?: {
status?: string;
powerUsage?: number;
};
modelInstance?: any;
}
type ShipItem = ShipRespVo & { id: string; modelInstance?: any; };
interface Props {
shipStatusData: ShipItem[];
shorePowerStatusData: ShipItem[];
realtimeDeviceData: RealtimeDeviceData[];
// selectedItem: ShipItem | null;
}
@ -304,34 +336,23 @@ const props = defineProps<Props>()
const searchKeyword = ref('')
const storeSearchKeyword = ref('')
const show_type = ref('ship')
const selectedItem = ref<ShipItem | null>(null)
const shipSelectedItem = ref<ShipItem | null>(null)
const shorepowerSelectedItem = ref<ShorePowerBerth & { position: string; } | null>(null)
//
const shorePowerHistoryVisible = ref(false)
const shipHistoryVisible = ref(false)
const currentShorePower = ref<ShipItem | null>(null)
const shorePowerHistoryVisible = ref({
visible: false,
shorePowerId: 0
})
const shipHistoryVisible = ref({
visible: false,
shipId: 0
})
const currentShorePower = ref<ShorePowerBerth | null>(null)
const currentShip = ref<ShipItem | null>(null)
//
const shorePowerHistoryColumns = [
{ prop: 'id', label: '记录ID', width: 80 },
{ prop: 'time', label: '时间', width: 180 },
{ prop: 'operation', label: '操作类型' },
{ prop: 'voltage', label: '电压(V)' },
{ prop: 'current', label: '电流(A)' },
{ prop: 'power', label: '功率(kW)' },
{ prop: 'energy', label: '用电量(kWh)' }
]
//
const shipHistoryColumns = [
{ prop: 'id', label: '记录ID', width: 80 },
{ prop: 'time', label: '时间', width: 180 },
{ prop: 'operation', label: '操作类型' },
{ prop: 'berthPosition', label: '泊位位置' },
{ prop: 'duration', label: '停泊时长(小时)' },
{ prop: 'powerConsumption', label: '用电量(kWh)' }
]
const ShorePowerList = ref<(ShorePowerBerth & { position: string; })[]>([])
//
const filteredShipStatusData = computed(() => {
if (!searchKeyword.value) {
@ -392,7 +413,7 @@ const handleSelectItem = async (item: ShipItem) => {
const deviceId = item.shorePower?.totalPowerDeviceId;
const res = await MapApi.getRealtimeDataByIdList({ ids: deviceId })
console.log(res)
selectedItem.value = {
shipSelectedItem.value = {
...item,
shorePowerEquipment: {
...item.shorePowerEquipment,
@ -416,15 +437,23 @@ const handleSearch = () => {
}
//
const showShorePowerHistory = (shorepower: ShipItem) => {
const showShorePowerHistory = (shorepower: ShorePowerBerth) => {
console.log('shorepower', shorepower)
currentShorePower.value = shorepower
shorePowerHistoryVisible.value = true
shorePowerHistoryVisible.value = {
visible: true,
shorePowerId: shorepower.id || 0
}
}
//
const showShipHistory = (ship: ShipItem) => {
console.log('ship', ship)
currentShip.value = ship
shipHistoryVisible.value = true
shipHistoryVisible.value = {
visible: true,
shipId: ship.shipBasicInfo.id
}
}
//
@ -482,6 +511,15 @@ const handleSwitch = (ship: ShipItem, type: string) => {
handleSelectItem(ship)
}
const handleSelectShorePower = async (shorepower: ShorePowerBerth & { position: string }) => {
console.log('shorepower', shorepower)
// selectedItem.value = shorepower
shorepowerSelectedItem.value = shorepower
show_type.value = 'shorepower'
// const data = await MapApi.getRealtimeDataByIdList({ ids: shorepower.totalPowerDeviceId })
// console.log('voltageDeviceId', data)
}
const shorePowerStatusMap = {
1: '待靠泊',
2: '靠泊中',
@ -493,10 +531,28 @@ const shorePowerStatusMap = {
9: '未使用岸电'
}
const StatusMap = {
1: '故障',
2: '故障',
3: '在线',
4: '在线',
5: '离线',
6: '在线',
8: '故障',
9: '离线',
}
//
const StatusText = (status: number | string) => {
const statusNum = Number(status);
// console.log(status)
return StatusMap[statusNum] || status;
}
//
const getShorePowerStatusText = (status: number | string) => {
const statusNum = Number(status);
console.log(status)
// console.log(status)
return shorePowerStatusMap[statusNum] || status;
}
@ -504,6 +560,8 @@ const getStatusClass = (status: string) => {
switch (status) {
case '正常':
return 'status-normal'
case '在线':
return 'status-normal'
case '空闲':
return 'status-idle'
case '故障':
@ -521,12 +579,26 @@ const getStatusClass = (status: string) => {
}
}
onMounted(() => {
console.log(props.shipStatusData)
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)
})
onMounted(() => {
console.log(props.shorePowerStatusData)
// console.log(props.shorePowerStatusData)
})
</script>

184
public/map/components/ShipHistoryDialog.vue

@ -7,7 +7,8 @@
<div class="filter-container">
<el-form :model="berthingQueryParams" label-width="80px" inline>
<el-form-item label="关键字">
<el-input v-model="berthingQueryParams.keyword" placeholder="请输入关键字搜索" clearable @keyup.enter="handleBerthingSearch" />
<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="开始日期"
@ -22,15 +23,16 @@
<!-- 数据表格 -->
<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-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" />
<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>
@ -56,16 +58,19 @@
</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 :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" />
<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>
@ -80,25 +85,31 @@
<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import {
ElDialog,
ElTabs,
ElTabPane,
ElForm,
ElFormItem,
ElInput,
ElDatePicker,
ElButton,
ElTable,
ElTableColumn,
ElPagination
import { MapApi } from "@/api/shorepower/map";
import {
ElDialog,
ElTabs,
ElTabPane,
ElForm,
ElFormItem,
ElInput,
ElDatePicker,
ElButton,
ElTable,
ElTableColumn,
ElPagination
} from 'element-plus'
import { CARGO_CATEGORY, getOperationTypeLabel, OPERATION_TYPE } from './dictionaryTable';
import { formatDuration, formatTimestamp, showStatus } from './utils';
import { RealtimeDeviceData } from '@/types/shorepower';
//
interface Props {
modelValue: boolean
berthingData?: any[]
shipId?: number
shorePowerConnectionData?: any[]
realtimeDeviceData: RealtimeDeviceData[];
}
//
@ -111,6 +122,7 @@ const emit = defineEmits<{
//
const props = withDefaults(defineProps<Props>(), {
modelValue: false,
shipId: 0,
berthingData: () => [],
shorePowerConnectionData: () => []
})
@ -137,23 +149,80 @@ const berthingLoading = ref(false)
const berthingTotal = ref(0)
//
const berthingTableData = computed(() => {
//
// 使
return props.berthingData?.slice(
(berthingQueryParams.value.pageNo - 1) * berthingQueryParams.value.pageSize,
berthingQueryParams.value.pageNo * berthingQueryParams.value.pageSize
) || []
})
const berthingTableData = ref<any[]>([])
//
const berthingColumns = ref([
{ prop: 'id', label: '记录ID', width: 80 },
{ prop: 'time', label: '时间', width: 180 },
{ prop: 'operation', label: '操作类型' },
{ prop: 'berthPosition', label: '泊位位置' },
{ prop: 'duration', label: '停泊时长(小时)' },
{ prop: 'powerConsumption', label: '用电量(kWh)' }
{
prop: 'shipBasicInfo',
label: '船舶名称-英文名称',
width: 200,
formatter: (row) => {
const name = row.shipBasicInfo?.name || '';
const nameEn = row.shipBasicInfo?.nameEn || '';
return `${name}${name && nameEn ? '-' : ''}${nameEn}`;
}
},
{ prop: 'shipBasicInfo.length', label: '船长', width: 200 },
{ prop: 'shipBasicInfo.width', label: '船宽', width: 150 },
{ prop: 'shipBasicInfo.tonnage', label: '最大载重', width: 150 },
{ prop: 'shipBasicInfo.voyage', label: '航线', width: 150 },
{ prop: 'applyInfo.departureHarborDistrict', label: '起运港', width: 150 },
{ prop: 'applyInfo.arrivalHarborDistrict', label: '到达港', width: 150 },
{ prop: 'applyInfo.operationType', label: '靠泊类型', width: 150, formatter: (_row, _column, cellValue) => getOperationTypeLabel(cellValue, OPERATION_TYPE) },
{ prop: '', label: '作业内容', width: 180 },
{
prop: 'applyInfo.loadingCargoCategory', label: '货物类型', width: 180,
formatter: (row) => {
if (row.applyInfo.operationType === 1) {
return row.applyInfo.loadingCargoCategory;
} else if (row.applyInfo.operationType === 2) {
return row.applyInfo.unloadingCargoCategory;
} else if (row.applyInfo.operationType === 3) {
return '装' + row.applyInfo.loadingCargoCategory + '-卸' + row.applyInfo.unloadingCargoCategory
}
return '';
}
},
{
prop: 'applyInfo.loadingCargoCategory', label: '货物名称', width: 180,
formatter: (row) => {
if (row.applyInfo.operationType === 1) {
const label = getOperationTypeLabel(row.applyInfo.loadingCargoCategory, CARGO_CATEGORY);
return label;
} else if (row.applyInfo.operationType === 2) {
const label = getOperationTypeLabel(row.applyInfo.unloadingCargoCategory, CARGO_CATEGORY);
return label;
} else if (row.applyInfo.operationType === 3) {
return '装' + getOperationTypeLabel(row.applyInfo.loadingCargoCategory, CARGO_CATEGORY) + '-卸' + getOperationTypeLabel(row.applyInfo.unloadingCargoCategory, CARGO_CATEGORY)
}
return '';
}
},
{
prop: 'applyInfo.loadingCargoCategory', label: '货物吨数', width: 180,
formatter: (row) => {
if (row.applyInfo.operationType === 1) {
return row.applyInfo.loadingCargoTonnage;
} else if (row.applyInfo.operationType === 2) {
return row.applyInfo.unloadingCargoTonnage;
} else if (row.applyInfo.operationType === 3) {
return '装' + row.applyInfo.loadingCargoTonnage + '-卸' + row.applyInfo.unloadingCargoTonnage
}
return '';
}
},
{ prop: 'usageRecordInfo.actualBerthTime', label: '靠泊时间', width: 180, formatter: (row) => formatTimestamp(row.usageRecordInfo.actualBerthTime) },
{ prop: 'usageRecordInfo.actualDepartureTime', label: '离泊时间', width: 180, formatter: (row) => formatTimestamp(row.usageRecordInfo.actualDepartureTime) },
{
prop: 'useStatus.status', label: '岸电使用情况', width: 180,
formatter: (row) => {
const status = showStatus(row, props.realtimeDeviceData);
return status?.status || '';
}
},
])
//
@ -181,12 +250,12 @@ const shorePowerConnectionTableData = computed(() => {
//
const shorePowerConnectionColumns = ref([
{ prop: 'id', label: '记录ID', width: 80 },
{ prop: 'shorePowerName', label: '岸电箱名称', width: 150 },
{ 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 }
{ prop: 'status', label: '状态', width: 100 } */
])
//
@ -282,6 +351,39 @@ watch(
},
{ immediate: true }
)
watch(
() => props.shipId,
(newShipId) => {
if (newShipId) {
// ID
berthingTableData.value = []
handleGetShipHistortyList(newShipId)
}
}
)
const handleGetShipHistortyList = async (id) => {
console.log('handleGetShipHistortyList', id)
if (!id) return;
// try {
const res = await MapApi.getShipHistoryPage({
shipId: parseInt(id, 10), //
pageNo: 1,
pageSize: 10,
type: 4,
// ids: [parseInt(id, 10)]
})
console.log(res);
const buildData = await Promise.all(res.list.map(async item => ({
...item,
})))
berthingTableData.value = buildData
}
onMounted(() => {
console.log('页面加载了!')
console.log('props.shipId', props.shipId)
})
</script>
<style scoped>

52
public/map/components/ShipShorePower.vue

@ -118,7 +118,7 @@
<el-col :span="12">
<el-form-item label="到达港:">
<span>{{ findNameById(selectedShip.applyInfo?.arrivalHarborDistrict, harborDistrictIdAndNameList)
}}</span>
}}</span>
</el-form-item>
</el-col>
</el-row>
@ -129,11 +129,11 @@
<span>{{ selectedShip.applyInfo?.departureHarborDistrict || '-' }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<!-- <el-col :span="12">
<el-form-item label="编号:">
<span>{{ selectedShip.applyInfo?.id || '-' }}</span>
</el-form-item>
</el-col>
</el-col> -->
</el-row>
<el-row :gutter="20">
@ -183,19 +183,19 @@
<span>{{ getReasonText(selectedShip.applyInfo?.reason) }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<!-- <el-col :span="12">
<el-form-item label="备注:">
<span>{{ selectedShip.applyInfo?.remark || '-' }}</span>
</el-form-item>
</el-col>
</el-col> -->
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<!-- <el-col :span="12">
<el-form-item label="船舶编号:">
<span>{{ selectedShip.applyInfo?.shipId || '-' }}</span>
</el-form-item>
</el-col>
</el-col> -->
<el-col :span="12">
<el-form-item label="申请状态:">
<span>{{ selectedShip.applyInfo?.status || '-' }}</span>
@ -260,7 +260,7 @@
</el-col>
</el-row>
<el-row :gutter="20">
<!-- <el-row :gutter="20">
<el-col :span="12">
<el-form-item label="用电申请编号:">
<span>{{ selectedShip.usageRecordInfo?.applyId || '-' }}</span>
@ -271,14 +271,14 @@
<span>{{ selectedShip.usageRecordInfo?.beginPowerSupplyOperator || '-' }}</span>
</el-form-item>
</el-col>
</el-row>
</el-row> -->
<el-row :gutter="20">
<el-col :span="12">
<!-- <el-col :span="12">
<el-form-item label="用电开始时用电方操作人:">
<span>{{ selectedShip.usageRecordInfo?.beginPowerUsageOperator || '-' }}</span>
</el-form-item>
</el-col>
</el-col> -->
<el-col :span="12">
<el-form-item label="用电开始时间:">
<span>{{ formatDateTime(selectedShip.usageRecordInfo?.beginTime) }}</span>
@ -287,11 +287,11 @@
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<!-- <el-col :span="12">
<el-form-item label="创建时间:">
<span>{{ formatDateTime(selectedShip.usageRecordInfo?.createTime) }}</span>
</el-form-item>
</el-col>
</el-col> -->
<el-col :span="12">
<el-form-item label="用电结束时间:">
<span>{{ formatDateTime(selectedShip.usageRecordInfo?.endTime) }}</span>
@ -299,7 +299,7 @@
</el-col>
</el-row>
<el-row :gutter="20">
<!-- <el-row :gutter="20">
<el-col :span="12">
<el-form-item label="编号:">
<span>{{ selectedShip.usageRecordInfo?.id || '-' }}</span>
@ -310,9 +310,9 @@
<span>{{ selectedShip.usageRecordInfo?.overPowerSupplyOperator || '-' }}</span>
</el-form-item>
</el-col>
</el-row>
</el-row> -->
<el-row :gutter="20">
<!-- <el-row :gutter="20">
<el-col :span="12">
<el-form-item label="用电结束时用电方操作人:">
<span>{{ selectedShip.usageRecordInfo?.overPowerUsageOperator || '-' }}</span>
@ -324,7 +324,7 @@
selectedShip.usageRecordInfo?.powerEndManualReading : '-' }}</span>
</el-form-item>
</el-col>
</el-row>
</el-row> -->
<el-row :gutter="20">
<el-col :span="12">
@ -348,11 +348,11 @@
selectedShip.usageRecordInfo?.powerStartSystemReading : '-' }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<!-- <el-col :span="12">
<el-form-item label="船舶编号:">
<span>{{ selectedShip.usageRecordInfo?.shipId || '-' }}</span>
</el-form-item>
</el-col>
</el-col> -->
</el-row>
<el-row :gutter="20">
@ -386,11 +386,11 @@
selectedShip.shipBasicInfo?.fullLoadDraft : '-' }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<!-- <el-col :span="12">
<el-form-item label="编号:">
<span>{{ selectedShip.shipBasicInfo?.id || '-' }}</span>
</el-form-item>
</el-col>
</el-col> -->
</el-row>
<el-row :gutter="20">
@ -402,7 +402,7 @@
<el-col :span="12">
<el-form-item label="船舶长度:">
<span>{{ selectedShip.shipBasicInfo?.length !== undefined ? selectedShip.shipBasicInfo?.length : '-'
}}</span>
}}</span>
</el-form-item>
</el-col>
</el-row>
@ -420,7 +420,7 @@
</el-col>
</el-row>
<el-row :gutter="20">
<!-- <el-row :gutter="20">
<el-col :span="12">
<el-form-item label="航运单位名称:">
<span>{{ selectedShip.shipBasicInfo?.shippingCompany || '-' }}</span>
@ -431,7 +431,7 @@
<span>{{ selectedShip.shipBasicInfo?.shorePowerContact || '-' }}</span>
</el-form-item>
</el-col>
</el-row>
</el-row> -->
<el-row :gutter="20">
<el-col :span="12">
@ -442,7 +442,7 @@
<el-col :span="12">
<el-form-item label="船舶吨位:">
<span>{{ selectedShip.shipBasicInfo?.tonnage !== undefined ? selectedShip.shipBasicInfo?.tonnage : '-'
}}</span>
}}</span>
</el-form-item>
</el-col>
</el-row>
@ -451,7 +451,7 @@
<el-col :span="12">
<el-form-item label="船舶宽度:">
<span>{{ selectedShip.shipBasicInfo?.width !== undefined ? selectedShip.shipBasicInfo?.width : '-'
}}</span>
}}</span>
</el-form-item>
</el-col>
</el-row>

73
public/map/components/ShorePowerHistoryDialog.vue

@ -21,7 +21,7 @@
</div>
<!-- 数据表格 -->
<el-table :data="tableData" border stripe style="width: 100%" v-loading="loading">
<el-table :data="shorePowerTableData" border stripe style="width: 100%" v-loading="loading">
<el-table-column v-for="column in tableColumns" :key="column.prop" :prop="column.prop" :label="column.label"
:width="column.width" :formatter="column.formatter" />
</el-table>
@ -57,14 +57,15 @@
<!-- 数据表格 -->
<el-table :data="shipConnectionTableData" border stripe style="width: 100%" v-loading="shipConnectionLoading">
<el-table-column v-for="column in shipConnectionColumns" :key="column.prop" :prop="column.prop" :label="column.label"
:width="column.width" :formatter="column.formatter" />
<el-table-column v-for="column in shipConnectionColumns" :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="shipConnectionQueryParams.pageNo" v-model:page-size="shipConnectionQueryParams.pageSize"
:page-sizes="[10, 20, 50, 100]" :total="shipConnectionTotal" layout="total, sizes, prev, pager, next, jumper"
<el-pagination v-model:current-page="shipConnectionQueryParams.pageNo"
v-model:page-size="shipConnectionQueryParams.pageSize" :page-sizes="[10, 20, 50, 100]"
:total="shipConnectionTotal" layout="total, sizes, prev, pager, next, jumper"
@size-change="handleShipConnectionSizeChange" @current-change="handleShipConnectionCurrentChange" />
</div>
</el-tab-pane>
@ -80,25 +81,27 @@
<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import {
ElDialog,
ElTabs,
ElTabPane,
ElForm,
ElFormItem,
ElInput,
ElDatePicker,
ElButton,
ElTable,
ElTableColumn,
ElPagination
import {
ElDialog,
ElTabs,
ElTabPane,
ElForm,
ElFormItem,
ElInput,
ElDatePicker,
ElButton,
ElTable,
ElTableColumn,
ElPagination
} from 'element-plus'
import { MapApi } from "@/api/shorepower/map";
//
interface Props {
modelValue: boolean
data?: any[]
shipConnectionData?: any[]
shorePowerId: number
}
//
@ -111,6 +114,7 @@ const emit = defineEmits<{
//
const props = withDefaults(defineProps<Props>(), {
modelValue: false,
shorePowerId: 0,
data: () => [],
shipConnectionData: () => []
})
@ -121,6 +125,7 @@ const visible = computed({
set: (val) => emit('update:modelValue', val)
})
const shorePowerTableData = ref<any[]>([])
const activeTab = ref('shorePower')
//
@ -283,6 +288,40 @@ watch(
},
{ immediate: true }
)
watch(
() => props.shorePowerId,
(newShorePowerId) => {
if (newShorePowerId) {
// ID
shorePowerTableData.value = []
handleGetShorePowerHistoryList(newShorePowerId)
}
}
)
const handleGetShorePowerHistoryList = async (id) => {
console.log('handleGetShorePowerHistoryList', id)
if (!id) return;
// try {
const res = await MapApi.getShipHistoryPage({
shipId: parseInt(id, 10), //
pageNo: 1,
pageSize: 10,
type: 5,
// ids: [parseInt(id, 10)]
})
console.log(res);
const buildData = await Promise.all(res.list.map(async item => ({
...item,
})))
shorePowerTableData.value = buildData
}
onMounted(() => {
console.log('页面加载了!')
console.log('props.shipId', props.shorePowerId)
})
</script>
<style scoped>

59
public/map/components/ShorePowerUsage.vue

@ -12,6 +12,8 @@
<span class="title-text">{{ card.title }}</span>
</div>
<div v-if="card.type === 'overview'" class="time-range-selector">
<el-date-picker type="daterange" range-separator="" start-placeholder="开始日期" end-placeholder="结束日期"
format="YYYY-MM-DD" value-format="YYYY-MM-DD" class="date-range-picker" @click.stop />
<button v-for="option in timeRangeOptions" :key="option.value"
:class="['time-range-btn', { active: timeRange === option.value }]"
@click.stop="handleTimeRangeChange(option.value)">
@ -65,6 +67,8 @@
<span class="title-text">{{ card.title }}</span>
</div>
<div v-if="card.type === 'overview'" class="time-range-selector">
<el-date-picker type="daterange" range-separator="" start-placeholder="开始日期" end-placeholder="结束日期"
format="YYYY-MM-DD" value-format="YYYY-MM-DD" class="date-range-picker" @click.stop />
<button v-for="option in timeRangeOptions" :key="option.value"
:class="['time-range-btn', { active: timeRange === option.value }]"
@click.stop="handleTimeRangeChange(option.value)">
@ -114,7 +118,7 @@
<div v-if="displayMode === 'magnify'" class="magnify">
<div class="big">
<div v-for="card in cards.filter(c => c.id === selectedCard)" :key="card.id"
class="card digital-twin-card--deep-blue" @click="handleSelectCard(card.id)">
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>
@ -122,6 +126,8 @@
<span class="title-text">{{ card.title }}</span>
</div>
<div v-if="card.type === 'overview'" class="time-range-selector">
<el-date-picker type="daterange" range-separator="" start-placeholder="开始日期" end-placeholder="结束日期"
format="YYYY-MM-DD" value-format="YYYY-MM-DD" class="date-range-picker" />
<button v-for="option in timeRangeOptions" :key="option.value"
:class="['time-range-btn', { active: timeRange === option.value }]"
@click.stop="handleTimeRangeChange(option.value)">
@ -228,7 +234,15 @@ import { ref, onMounted, onBeforeUnmount } from 'vue'
import WaveLineChart from './charts/WaveLineChart.vue'
import { MapApi } from "@/api/shorepower/map";
import dayjs from 'dayjs';
import { RealtimeDeviceData } from '@/types/shorepower';
interface Props {
realtimeDeviceData: RealtimeDeviceData[];
activeHeadGroup?: number;
}
const props = defineProps<Props>()
//
interface ChartDataItem {
name: string;
@ -501,22 +515,22 @@ const appendNewData = () => {
})
}
const handleGetRealTimeAllData = async () => {
const handleGetRealTimeAllData = async (realtimeDeviceData: RealtimeDeviceData[]) => {
try {
const res: deviceData = await MapApi.getRealtimeAllData({})
const ids = Object.values(res).map(item => item.id);
const res: RealtimeDeviceData[] = realtimeDeviceData.filter(item => item.deviceCode.includes('Kwh'));
const ids = res.map(item => item.id);
console.log(ids);
const params = {
ids: ids.join(','),
// year: new Date().getFullYear()
}
const yearDataRes: deviceData = await MapApi.getYearDataByIdList(params);
const weekDataRes: deviceData = await MapApi.getWeekDataByIdList(params);
const monthDataRes: deviceData = await MapApi.getMonthDataByIdList(params);
const dayDataRes: deviceData = await MapApi.getDayDataByIdList(params);
const yearDataRes: RealtimeDeviceData[] = await MapApi.getYearDataByIdList(params);
const weekDataRes: RealtimeDeviceData[] = await MapApi.getWeekDataByIdList(params);
const monthDataRes: RealtimeDeviceData[] = await MapApi.getMonthDataByIdList(params);
const dayDataRes: RealtimeDeviceData[] = await MapApi.getDayDataByIdList(params);
// const quarterDataRes: deviceData = await MapApi.getQuarterDataByIdList(params);
const realTimeSum = Object.values(res).reduce((acc, item) => acc + item.measureValue, 0);
const realTimeSum = res.reduce((acc, item) => acc + item.measureValue, 0);
const daySum = realTimeSum - Object.values(dayDataRes).reduce((acc, item) => acc + item.measureValue, 0);
const weekSum = realTimeSum - Object.values(weekDataRes).reduce((acc, item) => acc + item.measureValue, 0);
const monthSum = realTimeSum - Object.values(monthDataRes).reduce((acc, item) => acc + item.measureValue, 0);
@ -636,24 +650,29 @@ const handleGetAllDeviceDataByTimeRange = async () => {
}
}
watch(() => props.realtimeDeviceData, (newValue) => {
handleGetRealTimeAllData(newValue)
})
//
onMounted(() => {
handleGetAllDeviceDataByTimeRange()
// commonChartData.value = generateInitialData()
// timer = window.setInterval(appendNewData, 1000)
let i = 1
handleGetRealTimeAllData()
timer = setInterval(() => {
handleGetRealTimeAllData(i)
i++
}, 5000)
handleGetRealTimeAllData(props.realtimeDeviceData)
})
// activeHeadGroup resize
watch(() => props.activeHeadGroup, (newVal) => {
if (newVal === 1) {
// resize DOM
setTimeout(() => {
window.dispatchEvent(new Event('resize'))
}, 100)
}
}, { immediate: true })
//
onBeforeUnmount(() => {
if (timer) {
window.clearInterval(timer)
}
})
</script>

2
public/map/components/bk/map_index.vue

@ -366,7 +366,7 @@ const buildDlData = () => {
}
const updateDataDate = (number: number) => {
if (number == 5) {
window.open("http://server.ayaojies.com.cn:801/login", '_blank');
window.open("http://106.118.88.15:801/login", '_blank');
} else {
dataDate.value = number
usedDl.value = 835229.9 * number

198
public/map/components/cesiumMap.vue

@ -23,6 +23,110 @@ import { toRaw } from 'vue'
// window 访 Cesium
const Cesium = window.Cesium;
// 线
class PolylineFlowMaterialProperty {
constructor(options) {
options = options || {};
this._definitionChanged = new Cesium.Event();
this._color = undefined;
this._colorSubscription = undefined;
this.color = options.color || Cesium.Color.YELLOW;
this.duration = options.duration || 2000; // 2000ms1000ms
this.percent = options.percent || 0.1;
this.gradient = options.gradient || 0.01;
this._time = (new Date()).getTime();
}
get isConstant() {
return false;
}
get definitionChanged() {
return this._definitionChanged;
}
getType() {
return 'PolylineFlow';
}
getValue(time, result) {
if (!result) {
result = {};
}
result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE, result.color);
result.image = undefined;
result.time = ((new Date()).getTime() - this._time) % this.duration / this.duration;
result.percent = this.percent;
result.gradient = this.gradient;
return result;
}
equals(other) {
return this === other ||
(other instanceof PolylineFlowMaterialProperty &&
Cesium.Property.equals(this._color, other._color) &&
this.duration === other.duration &&
this.percent === other.percent &&
this.gradient === other.gradient);
}
}
Object.defineProperties(PolylineFlowMaterialProperty.prototype, {
color: Cesium.createPropertyDescriptor('color')
});
//
Cesium.Material.PolylineFlowType = 'PolylineFlow';
Cesium.Material._materialCache.addMaterial(Cesium.Material.PolylineFlowType, {
fabric: {
type: Cesium.Material.PolylineFlowType,
uniforms: {
color: new Cesium.Color(1.0, 1.0, 0.0, 1.0),
time: 0,
percent: 0.1,
gradient: 0.01
},
source: `
czm_material czm_getMaterial(czm_materialInput materialInput)
{
czm_material material = czm_getDefaultMaterial(materialInput);
vec2 st = materialInput.st;
float t = time * 3.0; //
// 线线
vec3 baseColor = color.rgb;
//
float alpha = 0.2; //
//
float arrowPos1 = mod(t - st.s * 5.0, 5.0);
float arrow1 = smoothstep(0.7, 0.9, arrowPos1) * (1.0 - smoothstep(0.9, 1.1, arrowPos1));
float arrowHead1 = smoothstep(0.4, 0.9, arrowPos1) * (1.0 - smoothstep(0.9, 1.3, arrowPos1));
float arrowPos2 = mod(t - st.s * 5.0 + 2.5, 5.0);
float arrow2 = smoothstep(0.7, 0.9, arrowPos2) * (1.0 - smoothstep(0.9, 1.1, arrowPos2));
float arrowHead2 = smoothstep(0.4, 0.9, arrowPos2) * (1.0 - smoothstep(0.9, 1.3, arrowPos2));
//
float arrowEffect = max(max(arrow1, arrowHead1), max(arrow2, arrowHead2));
//
alpha = 0.2 + arrowEffect * 0.8;
material.alpha = alpha;
material.diffuse = baseColor;
return material;
}
`
},
translucent: function (material) {
return true;
}
});
let viewer = null;
const cesiumContainerRef = ref(null); // DOM
const history = ref(null); //
@ -165,6 +269,7 @@ onMounted(async () => {
// const unitedData =
// dataInfo
let arr = []
const addMarkersFromDataInfo = (dataInfo) => {
//
if (!dataInfo || !Array.isArray(dataInfo) || dataInfo.length === 0) {
@ -369,6 +474,10 @@ onMounted(async () => {
backFaceCulling: true
},
});
console.log(item)
if (item.name.includes('国投-206泊位-插座箱') || item.name.includes('国投-207泊位-插座箱')) {
arr.push(electricalBoxModel)
}
//
itemWithModel.modelInstance = electricalBoxModel;
@ -470,15 +579,104 @@ onMounted(async () => {
}
});
return dataWithModelsArray;
};
// 3: Viewer
viewer.imageryLayers.addImageryProvider(gaodeImage);
//
dataWithModels.value = addMarkersFromDataInfo(dataInfo);
// const xitemShipInfo = shipData.find(shipItem => (shipItem.shorePower.id === item.parentId) && item.type === 5)
console.log('111arr', arr)
const wgsCoords = coordtransform.wgs84togcj02(118.452068408873, 38.94922323975237);
const xposition = Cesium.Cartesian3.fromDegrees(wgsCoords[0], wgsCoords[1], 1);
const xlabelPosition = Cesium.Cartesian3.fromDegrees(wgsCoords[0], wgsCoords[1], 5);
//
const xelectricalBoxModel = viewer.entities.add({
name: '岸电箱',
position: xposition,
//
properties: {
modelType: 'electrical_box',
// data: itemWithModel
},
orientation: Cesium.Transforms.headingPitchRollQuaternion(
xposition,
new Cesium.HeadingPitchRoll(
Cesium.Math.toRadians(150), // (Z)
Cesium.Math.toRadians(0), // (Y)
Cesium.Math.toRadians(0) // (X)
)
),
model: {
uri: '/model/electrical_box.glb',
scale: 1.5, //
// minimumPixelSize: 10, // 50
// 使
enableDepthTest: true,
//
backFaceCulling: true
},
});
viewer.entities.add({
// pickable: false,
position: xlabelPosition, // 10
properties: {
modelType: 'electrical_box',
// data: itemWithModel
},
label: {
text: '岸电箱',
font: '16px sans-serif',
fillColor: Cesium.Color.WHITE,
outlineColor: Cesium.Color.BLACK,
outlineWidth: 2,
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
pixelOffset: new Cesium.Cartesian2(0, -30), //
disableDepthTestDistance: Number.POSITIVE_INFINITY //
}
});
// 线
function createFlowMaterial() {
return new PolylineFlowMaterialProperty({
color: Cesium.Color.YELLOW,
duration: 2000, // ()
percent: 0.1, // 线
gradient: 0.1 //
});
}
// 线xelectricalBoxModelarr
arr.forEach((entity, index) => {
// 线ID
const lineEntity = viewer.entities.add({
name: `connection_line_${index}`,
polyline: {
positions: new Cesium.CallbackProperty(() => {
//
const mainPosition = xelectricalBoxModel.position.getValue(viewer.clock.currentTime);
//
const targetPosition = entity.position.getValue(viewer.clock.currentTime);
//
return [mainPosition, targetPosition];
}, false),
width: 3,
material: createFlowMaterial(),
// 使线
enableDepthTest: true
}
});
console.log('lineEntity', lineEntity)
});
//
viewer.camera.flyTo(createView(presetViews.overview));
//

24
public/map/components/charts/BarChartMinute.vue

@ -11,14 +11,12 @@ interface Props {
chartData?: Array<{ name: string; value: number }>
title?: string
color?: string
magnifyMode?: boolean
}
const props = withDefaults(defineProps<Props>(), {
chartData: () => [],
title: '',
color: '#1296DB', // 使
magnifyMode: false
color: '#4CAF50' // 使绿
})
//
@ -61,7 +59,7 @@ const updateChart = () => {
grid: {
left: '1%',
right: '1%',
top: '10%',
top: '5%',
bottom: '1%',
containLabel: true
},
@ -110,7 +108,7 @@ const updateChart = () => {
{
type: 'bar',
data: props.chartData.map(item => item.value),
barWidth: props.magnifyMode ? 100 : 25, //
barWidth: 1, // 1px
itemStyle: {
color: {
type: 'linear',
@ -121,29 +119,19 @@ const updateChart = () => {
colorStops: [
{
offset: 0,
color: props.color // 使
color: '#4CAF50' // 使绿
},
{
offset: 1,
color: props.color + '80' //
color: '#4CAF5080' // 绿
}
]
},
borderRadius: [1, 1, 0, 0]
},
label: {
show: true,
position: 'top',
color: 'rgba(255, 255, 255, 0.7)',
fontSize: props.magnifyMode ? 32 : 8,
formatter: '+{c}',
labelLayout: {
hideOverlap: true
}
},
emphasis: {
itemStyle: {
color: props.color // 使
color: '#4CAF50' // 使绿
}
}
}

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

@ -100,7 +100,8 @@ const updateChart = () => {
// Y
min: (value: any) => {
if (props.chartData && props.chartData.length > 0) {
const minValue = props.chartData[0].value
//
const minValue = Math.min(...props.chartData.map(item => item.value));
//
// const range = value.max - minValue;
return minValue; // 0

74
public/map/components/dictionaryTable.ts

@ -0,0 +1,74 @@
import { MapApi } from "@/api/shorepower/map";
export const getOperationTypeLabel = (value: string | number | undefined | null, options: { label: string, value: string | number }[]) => {
const item = options.find(opt => opt.value === value);
return item ? item.label : '';
};
// 装货/卸货
export const OPERATION_TYPE = [
{ label: '装货', value: 1 },
{ label: '卸货', value: 2 },
{ label: '卸货并装货', value: 2 },
]
// 获取类型
export const CARGO_CATEGORY = [
{ label: '空船', value: 0 },
{ label: '散货', value: 1 },
{ label: '集装箱', value: 2 },
{ label: '液体货物', value: 3 },
{ label: '件杂货', value: 4 },
{ label: '危险品', value: 5 },
{ label: '冷藏货物', value: 6 },
]
// 未使用岸电原因
export const UNUSED_SHORE_POWER_REASON = [
{ label: '岸电用电接口不匹配', value: 1 },
{ label: '岸电设施电压/频率不匹配', value: 2 },
{ label: '电缆长度不匹配', value: 3 },
{ label: '气象因素禁止作业', value: 4 },
{ label: '船电设施损坏', value: 5 },
{ label: '岸电设施维护中', value: 6 },
{ label: '无受电设备', value: 7 },
{ label: '拒绝使用岸电', value: 8 },
{ label: '其他', value: 9 },
]
// 港区map
export const HARBOR_DISTRICT = async () => {
const res = await MapApi.getHarborDistrictIdAndNameList()
return res.map(item => ({
...item,
label: item.name,
value: item.id
}))
}
// doc 码头map
export const DOCK_DISTRICT = async () => {
const res = await MapApi.getDockIdAndNameList()
return res.map(item => ({
...item,
label: item.name,
value: item.id
}))
}
// 岸电状态
export const SHORE_POWER_STATUS = [
{ label: '待靠泊', value: 1 },
{ label: '靠泊中', value: 2 },
{ label: '岸电接入中', value: 3 },
{ label: '用电中', value: 4 },
{ label: '岸电卸载中', value: 5 },
{ label: '岸电卸载完成', value: 6 },
{ label: '离泊', value: 7 },
{ label: '未使用岸电', value: 9 }
]
export const BERTH_TYPE = [
{ label: '左舷停舶', value: 'left' },
{ label: '右舷停舶', value: 'right' },
]

194
public/map/components/utils.ts

@ -0,0 +1,194 @@
import { RealtimeDeviceData, ShipRespVo } from "@/types/shorepower";
import dayjs from "dayjs";
import { MapApi } from "@/api/shorepower/map";
/**
* 'YYYY/MM/DD HH:mm:ss'
* @param timestamp
* @returns
*/
export const formatTimestamp = (
timestamp: number | null | undefined,
format = 'YYYY/MM/DD HH:mm:ss'
): string => {
if (!timestamp) return '';
// 处理秒级时间戳(10位数字)
if (timestamp < 1e12) {
timestamp *= 1000;
}
return dayjs(timestamp).format(format);
};
/**
* "X小时Y分钟Z秒"
* @param {number} startTime -
* @param {number} endTime -
* @returns {string} "2小时30分钟15秒"
*/
export function formatDuration(startTime?: number, endTime?: number): string {
if (!startTime || !endTime) return '--';
const diffMs = Math.max(0, endTime - startTime);
const totalSeconds = Math.floor(diffMs / 1000);
const hours = Math.floor(totalSeconds / 3600);
const minutes = Math.floor((totalSeconds % 3600) / 60);
const seconds = totalSeconds % 60;
let result = '';
if (hours > 0) result += `${hours}小时`;
if (minutes > 0) result += `${minutes}分钟`;
if (seconds > 0 || result === '') result += `${seconds}`;
return result || '0秒';
}
// 岸电使用文本构建
export function showStatus(ship: ShipRespVo, realtimeDeviceData?: RealtimeDeviceData[]): { statusClass: string, status: string } | null {
const { usageRecordInfo, applyInfo } = ship;
if (!applyInfo || !usageRecordInfo || !usageRecordInfo.beginTime) {
return null;
}
if (applyInfo.reason == 0 && usageRecordInfo && usageRecordInfo.beginTime) {
const start = new Date(usageRecordInfo.beginTime);
const end = usageRecordInfo.endTime ? new Date(usageRecordInfo.endTime) : new Date();
// 校验日期有效性
if (isNaN(start.getTime()) || isNaN(end.getTime())) {
return null;
}
// 校验时间顺序
if (end < start) {
return null; // 或抛出错误、记录日志等
}
// 计算总毫秒差
const diffMs = end.getTime() - start.getTime();
// 转换为秒
const totalSeconds = Math.floor(diffMs / 1000);
const hours = Math.floor(totalSeconds / 3600);
const minutes = Math.floor((totalSeconds % 3600) / 60);
const seconds = totalSeconds % 60;
let useValue = 0;
// 检查是否有结束读数
const hasEndReading = usageRecordInfo.powerEndManualReading || usageRecordInfo.powerEndSystemReading;
if (hasEndReading) {
// 有结束读数,使用常规计算方式
// 优先计算人工差值
const manualDiff = usageRecordInfo.powerStartManualReading !== undefined && usageRecordInfo.powerEndManualReading !== undefined
? usageRecordInfo.powerEndManualReading - usageRecordInfo.powerStartManualReading
: null;
// 然后计算系统差值
const systemDiff = usageRecordInfo.powerStartSystemReading !== undefined && usageRecordInfo.powerEndSystemReading !== undefined
? usageRecordInfo.powerEndSystemReading - usageRecordInfo.powerStartSystemReading
: null;
// 使用人工差值优先,然后系统差值,最后默认0
useValue = manualDiff ?? systemDiff ?? 0;
} else {
// 没有结束读数,使用实时数据计算
const deviceId = ship.shorePower?.totalPowerDeviceId;
if (deviceId) {
try {
// 调用API获取实时数据
const measureValueStr = getValueById(realtimeDeviceData || [], deviceId,
'measureValue')
if (measureValueStr !== undefined) {
// 优先使用人工开始读数,然后系统开始读数
const startReading = usageRecordInfo.powerStartManualReading ?? usageRecordInfo.powerStartSystemReading ?? 0;
const measureValue = typeof measureValueStr === 'string' ? parseFloat(measureValueStr) : measureValueStr;
useValue = measureValue - startReading;
}
} catch (error) {
console.error('获取实时数据失败:', error);
useValue = 0;
}
}
}
return {
statusClass: 'status-using',
status: `使用岸电${hours}小时${minutes}分钟${seconds}秒,${useValue.toFixed(2)}kWH`
}
} else if (applyInfo.reason != 0) {
// 状态码映射表 - 包含状态文本和颜色类型
const statusMap: Record<string, { text: string; colorType: string }> = {
'-1': { text: '未知错误', colorType: 'default' },
'1': { text: '岸电用电接口不匹配', colorType: 'default' },
'2': { text: '岸电设施电压/频率不匹配', colorType: 'success' },
'3': { text: '电缆长度不匹配', colorType: 'success' },
'4': { text: '气象因素禁止作业', colorType: 'success' },
'5': { text: '船电设施损坏', colorType: 'warning' },
'6': { text: '岸电设施维护中', colorType: 'warning' },
'7': { text: '无受电设备', colorType: 'danger' },
'8': { text: '拒绝使用岸电', colorType: 'danger' },
'9': { text: '其他', colorType: 'danger' }
}
const reasonKey = applyInfo.reason?.toString() || '-1'
const statusInfo = statusMap[reasonKey] || { text: applyInfo.reason, colorType: 'default' }
// 根据颜色类型设置对应的状态类
let statusClass = 'status-cable'
switch (statusInfo.colorType) {
case 'danger':
statusClass = 'status-danger'
break
case 'warning':
statusClass = 'status-warning'
break
case 'success':
statusClass = 'status-success'
break
default:
statusClass = 'status-cable'
}
return {
statusClass: statusClass,
status: statusInfo.text
}
} else {
return {
statusClass: '',
status: 'unknown'
}
}
}
/**
* id
* @param list - id
* @param id - id
* @param valueField - id key
* @returns undefined
*/
export function getValueById<T extends { id: number | string }, K extends keyof Omit<T, 'id'>>(
list: T[],
id: T['id'],
valueField: K
): T[K] extends number | string ? string | undefined : T[K] | undefined {
const item = list.find(item => item.id === id);
if (!item) return undefined;
const value = item[valueField];
// 如果值是数字或可以转换为数字的字符串,则保留两位小数
if (typeof value === 'number') {
return Number(value).toFixed(2) as any;
}
if (typeof value === 'string' && !isNaN(Number(value))) {
return Number(value).toFixed(2) as any;
}
// 否则返回原始值
return value as any;
}

88
public/map/index.vue

@ -20,13 +20,14 @@
<!-- 港区概览 -->
<template v-if="activeHeadGroup === 0">
<PortOverview :ship-status-data="shipStatusData" :shore-power-status-data="shorePowerStatusData"
@item-click="handleSwitch" />
@item-click="handleSwitch" :realtime-device-data="realtimeDeviceData" />
</template>
<!-- 港口岸电使用情况 -->
<template v-if="activeHeadGroup === 1">
<ShorePowerUsage />
</template>
<!-- <template v-if="activeHeadGroup === 1"> -->
<ShorePowerUsage v-show="activeHeadGroup === 1" :realtime-device-data="realtimeDeviceData"
:active-head-group="activeHeadGroup" />
<!-- </template> -->
<!-- 港口企业岸电使用 -->
<template v-if="activeHeadGroup === 2">
@ -103,8 +104,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'
defineOptions({ name: 'PublicMap' })
let getRealtimeIntervalId: NodeJS.Timeout | null = null
const headGroupList = ref<{ value: number, label: string }[]>([
{ value: 0, label: '港区概览' },
{ value: 1, label: '港口岸电使用情况' },
@ -136,54 +138,13 @@ const selectHeadGroup = async (value: number) => {
}
}
//
const currentTime = ref<string>(dayjs().format('YYYY-MM-DD HH:mm:ss'))
//
// const totalPower = ref<number>(857525.45)
// const fuelReduction = ref<number>(108.04)
// const co2Reduction = ref<number>(574542.06)
// const pm25Reduction = ref<number>(1251.99)
// const noxReduction = ref<number>(15521.21)
// const so2Reduction = ref<number>(9004.03)
// 使
const berthingShips = ref<number>(13)
const shorePowerShips = ref<number>(3)
const noShorePowerShips = ref<number>(10)
//
const shipData = ref([
{ name: '华元503', wharf: '华能码头', berth: '3泊位', status: '使用岸电21小时45分钟,2479kWH', statusClass: 'status-using' },
{ name: '信洋新征程', wharf: '国投码头', berth: '202#泊位', status: '无受电设备', statusClass: 'status-no-equipment' },
{ name: '华海航2', wharf: '华电码头(储运)', berth: '806泊位', status: '船电设施损坏,预计2025-11-30恢复', statusClass: 'status-damaged' },
{ name: '东亿603', wharf: '国投码头', berth: '205#泊位', status: '电缆长度不匹配', statusClass: 'status-cable' },
{ name: '恒远88', wharf: '华能码头', berth: '5泊位', status: '使用岸电12小时30分钟,1850kWH', statusClass: 'status-using' },
{ name: '海昌10', wharf: '国投码头', berth: '103#泊位', status: '无受电设备', statusClass: 'status-no-equipment' },
{ name: '长航99', wharf: '华电码头(储运)', berth: '702泊位', status: '使用岸电8小时15分钟,1200kWH', statusClass: 'status-using' },
{ name: '中远之星', wharf: '华能码头', berth: '1泊位', status: '电缆接口不匹配', statusClass: 'status-cable' },
{ name: '渤海1号', wharf: '国投码头', berth: '301#泊位', status: '使用岸电15小时20分钟,2100kWH', statusClass: 'status-using' },
{ name: '津港101', wharf: '华电码头(储运)', berth: '608泊位', status: '船电设施维护中', statusClass: 'status-damaged' },
{ name: '胜利888', wharf: '华能码头', berth: '4泊位', status: '无受电设备', statusClass: 'status-no-equipment' },
{ name: '东方明珠', wharf: '国投码头', berth: '208#泊位', status: '使用岸电20小时10分钟,2750kWH', statusClass: 'status-using' },
{ name: '海洋之星', wharf: '华电码头(储运)', berth: '901泊位', status: '电缆长度不足', statusClass: 'status-cable' },
{ name: '中远海1', wharf: '华能码头', berth: '2泊位', status: '使用岸电18小时40分钟,2500kWH', statusClass: 'status-using' },
{ name: '大连先锋', wharf: '国投码头', berth: '105#泊位', status: '无受电设备', statusClass: 'status-no-equipment' },
{ name: '青岛港9', wharf: '华电码头(储运)', berth: '505泊位', status: '船电设施故障', statusClass: 'status-damaged' },
{ name: '上海号', wharf: '华能码头', berth: '6泊位', status: '使用岸电14小时30分钟,1950kWH', statusClass: 'status-using' },
{ name: '广州先锋', wharf: '国投码头', berth: '305#泊位', status: '电缆接口问题', statusClass: 'status-cable' },
{ name: '深圳港7', wharf: '华电码头(储运)', berth: '801泊位', status: '使用岸电9小时25分钟,1350kWH', statusClass: 'status-using' },
{ name: '宁波号', wharf: '华能码头', berth: '7泊位', status: '无受电设备', statusClass: 'status-no-equipment' },
{ name: '厦门先锋', wharf: '国投码头', berth: '210#泊位', status: '使用岸电16小时15分钟,2200kWH', statusClass: 'status-using' },
{ name: '福州港8', wharf: '华电码头(储运)', berth: '705泊位', status: '船电设施维护', statusClass: 'status-damaged' },
{ name: '天津号', wharf: '华能码头', berth: '8泊位', status: '使用岸电11小时50分钟,1650kWH', statusClass: 'status-using' },
{ name: '秦皇岛先锋', wharf: '国投码头', berth: '109#泊位', status: '电缆长度不匹配', statusClass: 'status-cable' },
{ name: '唐山港6', wharf: '华电码头(储运)', berth: '603泊位', status: '使用岸电13小时25分钟,1850kWH', statusClass: 'status-using' },
{ name: '黄骅港5', wharf: '华能码头', berth: '9泊位', status: '无受电设备', statusClass: 'status-no-equipment' },
{ name: '曹妃甸1', wharf: '国投码头', berth: '312#泊位', status: '使用岸电19小时30分钟,2600kWH', statusClass: 'status-using' },
{ name: '京唐港4', wharf: '华电码头(储运)', berth: '508泊位', status: '船电设施故障', statusClass: 'status-damaged' },
{ name: '营口港3', wharf: '华能码头', berth: '10泊位', status: '使用岸电10小时45分钟,1500kWH', statusClass: 'status-using' }
])
//
const realtimeDeviceData = ref<RealtimeDeviceData[]>([])
//
const scrollContainerRef = ref<HTMLElement | null>(null)
@ -372,6 +333,33 @@ const startAutoScroll = () => {
console.log('Auto scroll started')
}
const handleGetRealtimeAllData = async () => {
const data = await MapApi.getRealtimeAllData({})
const arrayOfObjects = Object.values(data) as RealtimeDeviceData[]
realtimeDeviceData.value = arrayOfObjects
// console.log('getRealtimeAllData', arrayOfObjects)
}
//
onMounted(() => {
// DOM
handleGetRealtimeAllData()
getRealtimeIntervalId = setInterval(() => {
handleGetRealtimeAllData()
}, 5000)
})
//
onUnmounted(() => {
if (getRealtimeIntervalId) {
clearInterval(getRealtimeIntervalId)
getRealtimeIntervalId = null
}
})
//
onMounted(() => {
timer = setInterval(updateTime, 1000)

35
src/api/shorepower/map/index.ts

@ -1,4 +1,11 @@
import request from '@/config/axios'
import {
apiResponse,
PageResultShipRespVo,
shipHistoryPageRequest,
ShipRespVo,
ShorePowerBerth
} from '@/types/shorepower'
/** 地图信息 */
export interface Map {
@ -70,7 +77,7 @@ export const MapApi = {
// 查询用电接口设备状态
getDeviceStatusByIds: async (ids: any) => {
return await request.get({
url: `/energy/device/getDeviceStatusByIds?ids=${ids.join(',')}`,
url: `/energy/device/getDeviceStatusByIds?ids=${ids.join(',')}`
// params
})
},
@ -125,26 +132,26 @@ export const MapApi = {
// 查询所有船舶和岸电设备ID和名称列表
getBerthIdAndNameList: async () => {
return await request.get({
url: `/shorepower/berth/expand/selectIdAndNameList`,
url: `/shorepower/berth/expand/selectIdAndNameList`
})
},
getShorepowerIdAndNameList: async () => {
return await request.get({
url: `/shorepower/berth/expand/selectIdAndNameList`,
url: `/shorepower/berth/expand/selectIdAndNameList`
})
},
// 查询所有码头和名称列表
getDockIdAndNameList: async () => {
return await request.get({
url: `/shorepower/dock/expand/selectIdAndNameList`,
url: `/shorepower/dock/expand/selectIdAndNameList`
})
},
// 查询所有起运港和到达港和名称列表
getHarborDistrictIdAndNameList: async () => {
return await request.get({
url: `/shorepower/harbor-district/expand/selectIdAndNameList`,
url: `/shorepower/harbor-district/expand/selectIdAndNameList`
})
},
@ -155,4 +162,22 @@ export const MapApi = {
})
},
// 查询所有码头和名称列表
getShorepowerIdAndNameListByHarborDistrictId: async (
harborDistrictId: number
): Promise<ShorePowerBerth[]> => {
return await request.get({
url: `/shorepower/shore-power/expand/selectAllByHarborDistrict?harborDistrictId=${harborDistrictId}`
})
},
// 查询船舶历史数据分页
getShipHistoryPage: async (
params: shipHistoryPageRequest
): Promise<apiResponse<PageResultShipRespVo<ShipRespVo>>> => {
return await request.post({
url: `/shorepower/shore-power-and-ship/expand/getHistoryPage`,
params
})
}
}

474
src/types/shorepower.d.ts

@ -0,0 +1,474 @@
interface ShorePowerBerth {
id: number
berthId: number
equipmentId: number
name: string
totalPowerDeviceId: number
frequencyDeviceId: number
voltageDeviceId: number
currentDeviceId: number
status: number
createTime: number // Unix timestamp in milliseconds
shorePowerEquipmentInfo: ShorePowerEquipmentInfo
}
interface ShorePowerEquipmentInfo {
id: number
dockId: number
name: string
capacity: string // 可考虑转为 number,但原始数据为字符串 "2000"
voltage: string // 如 "0.4/0.44"
frequency: string // 如 "50/60"
createTime: number // Unix timestamp in milliseconds
}
interface shipHistoryPageRequest {
/**
*
*/
ids?: number[]
/**
* 1
*/
pageNo: number
/**
* 100
*/
pageSize: number
/**
*
*/
shipId?: number
/**
*
*/
type?: number
[property: string]: any
}
/**
* CommonResultPageResultShipRespVo
*/
interface apiResponse<T> {
code?: number
data?: T
msg?: string
[property: string]: any
}
/**
* PageResultShipRespVo
*/
interface PageResultShipRespVo<T> {
/**
*
*/
list: T[]
/**
*
*/
total: number
[property: string]: any
}
/**
* ShipRespVo - 使 Response VO
*/
export interface ShipRespVo {
/**
*
*/
applyInfo: ApplyRespVO
/**
*
*/
shipBasicInfo: ShipBasicInfoRespVO
/**
*
*/
shorePower: ShorePowerRespVO
/**
*
*/
shorePowerAndShip: ShorePowerAndShipRespVO
/**
*
*/
shorePowerEquipment: ShorePowerEquipmentRespVO
/**
*
*/
usageRecordInfo: UsageRecordRespVO
[property: string]: any
}
/**
*
*
* ApplyRespVO - Response VO
*/
export interface ApplyRespVO {
/**
*
*/
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
}
/**
*
*
* ShipBasicInfoRespVO - Response VO
*/
export interface ShipBasicInfoRespVO {
/**
*
*/
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
}
/**
*
*
* ShorePowerRespVO - Response VO
*/
export interface ShorePowerRespVO {
/**
*
*/
berthId: number
/**
*
*/
createTime: Date
/**
*
*/
equipmentId: number
/**
*
*/
frequencyDeviceId: number
/**
*
*/
id: number
/**
*
*/
name: string
/**
*
*/
totalPowerDeviceId: number
/**
*
*/
voltageDeviceId: number
[property: string]: any
}
/**
*
*
* ShorePowerAndShipRespVO - Response VO
*/
export interface ShorePowerAndShipRespVO {
/**
*
*/
applyId: number
/**
*
*/
createTime: Date
/**
*
*/
id: number
/**
*
*/
shipId: number
/**
*
*/
shorePowerId: number
/**
*
*/
status: number
/**
*
*/
type: string
[property: string]: any
}
/**
*
*
* ShorePowerEquipmentRespVO - Response VO
*/
export interface ShorePowerEquipmentRespVO {
/**
*
*/
capacity: string
/**
*
*/
createTime: Date
/**
*
*/
dockId: number
/**
*
*/
frequency: string
/**
*
*/
id: number
/**
*
*/
name: string
/**
*
*/
voltage: string
[property: string]: any
}
/**
*
*
* UsageRecordRespVO - Response VO
*/
export interface UsageRecordRespVO {
/**
*
*/
actualBerthTime?: Date
/**
*
*/
actualDepartureTime?: number | null | undefined
/**
*
*/
applyId: number
/**
*
*/
beginPowerSupplyOperator?: string
/**
*
*/
beginPowerUsageOperator?: string
/**
*
*/
beginTime?: number
/**
*
*/
createTime: Date
/**
*
*/
endTime?: number
/**
*
*/
id: number
/**
*
*/
overPowerSupplyOperator?: string
/**
*
*/
overPowerUsageOperator?: string
/**
*
*/
powerEndManualReading?: number
/**
*
*/
powerEndSystemReading?: number
/**
*
*/
powerStartManualReading?: number
/**
*
*/
powerStartSystemReading?: number
/**
*
*/
shipId: number
/**
*
*/
status: number
[property: string]: any
}
interface RealtimeDeviceData {
createTime: number // 时间戳(毫秒)
deviceCode: string
deviceId: number
deviceName: string
deviceStatus: number
id: number
incrementCost: number
incrementValue: number
measureTime: number // 时间戳(毫秒)
measureValue: number
}
Loading…
Cancel
Save