13 changed files with 3459 additions and 261 deletions
@ -0,0 +1,174 @@ |
|||
<template> |
|||
<el-dialog v-model="visible" :title="title" width="1200px" :before-close="handleClose"> |
|||
<!-- 搜索和筛选区域 --> |
|||
<div class="filter-container"> |
|||
<el-form :model="queryParams" label-width="80px" inline> |
|||
<el-form-item label="关键字"> |
|||
<el-input v-model="queryParams.keyword" placeholder="请输入关键字搜索" clearable @keyup.enter="handleSearch" /> |
|||
</el-form-item> |
|||
<el-form-item label="时间范围"> |
|||
<el-date-picker v-model="dateRange" type="daterange" range-separator="至" start-placeholder="开始日期" |
|||
end-placeholder="结束日期" value-format="YYYY-MM-DD" @change="handleDateChange" /> |
|||
</el-form-item> |
|||
<el-form-item> |
|||
<el-button type="primary" @click="handleSearch">搜索</el-button> |
|||
<el-button @click="resetQuery">重置</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
</div> |
|||
|
|||
<!-- 数据表格 --> |
|||
<el-table :data="tableData" 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> |
|||
|
|||
<!-- 分页 --> |
|||
<div class="pagination-container"> |
|||
<el-pagination v-model:current-page="queryParams.pageNo" v-model:page-size="queryParams.pageSize" |
|||
:page-sizes="[10, 20, 50, 100]" :total="total" layout="total, sizes, prev, pager, next, jumper" |
|||
@size-change="handleSizeChange" @current-change="handleCurrentChange" /> |
|||
</div> |
|||
|
|||
<template #footer> |
|||
<span class="dialog-footer"> |
|||
<el-button @click="handleClose">关闭</el-button> |
|||
</span> |
|||
</template> |
|||
</el-dialog> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { ref, computed, watch } from 'vue' |
|||
import { ElDialog, ElForm, ElFormItem, ElInput, ElDatePicker, ElButton, ElTable, ElTableColumn, ElPagination } from 'element-plus' |
|||
|
|||
// 定义组件属性 |
|||
interface Props { |
|||
modelValue: boolean |
|||
title?: string |
|||
columns: Array<{ |
|||
prop: string |
|||
label: string |
|||
width?: string | number |
|||
formatter?: (row: any, column: any, cellValue: any) => string |
|||
}> |
|||
data: any[] |
|||
} |
|||
|
|||
// 定义事件 |
|||
const emit = defineEmits<{ |
|||
(e: 'update:modelValue', value: boolean): void |
|||
(e: 'search', params: any): void |
|||
}>() |
|||
|
|||
// 属性定义 |
|||
const props = withDefaults(defineProps<Props>(), { |
|||
modelValue: false, |
|||
title: '历史记录', |
|||
columns: () => [], |
|||
data: () => [] |
|||
}) |
|||
|
|||
// 响应式数据 |
|||
const visible = computed({ |
|||
get: () => props.modelValue, |
|||
set: (val) => emit('update:modelValue', val) |
|||
}) |
|||
|
|||
const queryParams = ref({ |
|||
keyword: '', |
|||
startTime: '', |
|||
endTime: '', |
|||
pageNo: 1, |
|||
pageSize: 10 |
|||
}) |
|||
|
|||
const dateRange = ref<[string, string]>(['', '']) |
|||
const loading = ref(false) |
|||
const total = ref(0) |
|||
|
|||
// 表格数据计算属性 |
|||
const tableData = computed(() => { |
|||
// 在实际应用中,这里应该是从服务器获取的数据 |
|||
// 当前为了演示,我们使用传入的模拟数据 |
|||
return props.data.slice( |
|||
(queryParams.value.pageNo - 1) * queryParams.value.pageSize, |
|||
queryParams.value.pageNo * queryParams.value.pageSize |
|||
) |
|||
}) |
|||
|
|||
// 表格列 |
|||
const tableColumns = computed(() => props.columns) |
|||
|
|||
// 处理关闭 |
|||
const handleClose = () => { |
|||
visible.value = false |
|||
} |
|||
|
|||
// 处理搜索 |
|||
const handleSearch = () => { |
|||
// 发送搜索事件给父组件 |
|||
emit('search', { ...queryParams.value }) |
|||
} |
|||
|
|||
// 重置查询条件 |
|||
const resetQuery = () => { |
|||
queryParams.value.keyword = '' |
|||
queryParams.value.startTime = '' |
|||
queryParams.value.endTime = '' |
|||
dateRange.value = ['', ''] |
|||
queryParams.value.pageNo = 1 |
|||
handleSearch() |
|||
} |
|||
|
|||
// 处理日期变化 |
|||
const handleDateChange = (val: [string, string] | null) => { |
|||
if (val && val[0] && val[1]) { |
|||
queryParams.value.startTime = val[0] |
|||
queryParams.value.endTime = val[1] |
|||
} else { |
|||
queryParams.value.startTime = '' |
|||
queryParams.value.endTime = '' |
|||
} |
|||
} |
|||
|
|||
// 处理分页大小变化 |
|||
const handleSizeChange = (val: number) => { |
|||
queryParams.value.pageSize = val |
|||
queryParams.value.pageNo = 1 |
|||
handleSearch() |
|||
} |
|||
|
|||
// 处理当前页变化 |
|||
const handleCurrentChange = (val: number) => { |
|||
queryParams.value.pageNo = val |
|||
handleSearch() |
|||
} |
|||
|
|||
// 监听数据变化并更新总数 |
|||
watch( |
|||
() => props.data, |
|||
(newData) => { |
|||
total.value = newData.length |
|||
}, |
|||
{ immediate: true } |
|||
) |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.filter-container { |
|||
margin-bottom: 20px; |
|||
} |
|||
|
|||
.pagination-container { |
|||
margin-top: 20px; |
|||
display: flex; |
|||
justify-content: flex-end; |
|||
} |
|||
|
|||
.dialog-footer { |
|||
display: flex; |
|||
justify-content: flex-end; |
|||
gap: 10px; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,303 @@ |
|||
<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-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-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="关键字"> |
|||
<el-input v-model="shorePowerConnectionQueryParams.keyword" placeholder="请输入关键字搜索" clearable |
|||
@keyup.enter="handleShorePowerConnectionSearch" /> |
|||
</el-form-item> |
|||
<el-form-item label="时间范围"> |
|||
<el-date-picker v-model="shorePowerConnectionDateRange" type="daterange" range-separator="至" |
|||
start-placeholder="开始日期" end-placeholder="结束日期" value-format="YYYY-MM-DD" |
|||
@change="handleShorePowerConnectionDateChange" /> |
|||
</el-form-item> |
|||
<el-form-item> |
|||
<el-button type="primary" @click="handleShorePowerConnectionSearch">搜索</el-button> |
|||
<el-button @click="resetShorePowerConnectionQuery">重置</el-button> |
|||
</el-form-item> |
|||
</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> |
|||
|
|||
<template #footer> |
|||
<span class="dialog-footer"> |
|||
<el-button @click="handleClose">关闭</el-button> |
|||
</span> |
|||
</template> |
|||
</el-dialog> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { ref, computed, watch } from 'vue' |
|||
import { |
|||
ElDialog, |
|||
ElTabs, |
|||
ElTabPane, |
|||
ElForm, |
|||
ElFormItem, |
|||
ElInput, |
|||
ElDatePicker, |
|||
ElButton, |
|||
ElTable, |
|||
ElTableColumn, |
|||
ElPagination |
|||
} from 'element-plus' |
|||
|
|||
// 定义组件属性 |
|||
interface Props { |
|||
modelValue: boolean |
|||
berthingData?: any[] |
|||
shorePowerConnectionData?: any[] |
|||
} |
|||
|
|||
// 定义事件 |
|||
const emit = defineEmits<{ |
|||
(e: 'update:modelValue', value: boolean): void |
|||
(e: 'berthing-search', params: any): void |
|||
(e: 'shore-power-connection-search', params: any): void |
|||
}>() |
|||
|
|||
// 属性定义 |
|||
const props = withDefaults(defineProps<Props>(), { |
|||
modelValue: false, |
|||
berthingData: () => [], |
|||
shorePowerConnectionData: () => [] |
|||
}) |
|||
|
|||
// 响应式数据 |
|||
const visible = computed({ |
|||
get: () => props.modelValue, |
|||
set: (val) => emit('update:modelValue', val) |
|||
}) |
|||
|
|||
const activeTab = ref('shipBerthing') |
|||
|
|||
// 船舶靠泊历史记录相关数据 |
|||
const berthingQueryParams = ref({ |
|||
keyword: '', |
|||
startTime: '', |
|||
endTime: '', |
|||
pageNo: 1, |
|||
pageSize: 10 |
|||
}) |
|||
|
|||
const berthingDateRange = ref<[string, string]>(['', '']) |
|||
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 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)' } |
|||
]) |
|||
|
|||
// 船舶连接岸电箱历史记录相关数据 |
|||
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: 'id', label: '记录ID', 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 handleClose = () => { |
|||
visible.value = false |
|||
} |
|||
|
|||
// 船舶靠泊历史记录相关方法 |
|||
const handleBerthingSearch = () => { |
|||
// 发送搜索事件给父组件 |
|||
emit('berthing-search', { ...berthingQueryParams.value }) |
|||
} |
|||
|
|||
const resetBerthingQuery = () => { |
|||
berthingQueryParams.value.keyword = '' |
|||
berthingQueryParams.value.startTime = '' |
|||
berthingQueryParams.value.endTime = '' |
|||
berthingDateRange.value = ['', ''] |
|||
berthingQueryParams.value.pageNo = 1 |
|||
handleBerthingSearch() |
|||
} |
|||
|
|||
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() |
|||
} |
|||
|
|||
const handleBerthingCurrentChange = (val: number) => { |
|||
berthingQueryParams.value.pageNo = val |
|||
handleBerthingSearch() |
|||
} |
|||
|
|||
// 船舶连接岸电箱历史记录相关方法 |
|||
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 handleShorePowerConnectionSizeChange = (val: number) => { |
|||
shorePowerConnectionQueryParams.value.pageSize = val |
|||
shorePowerConnectionQueryParams.value.pageNo = 1 |
|||
handleShorePowerConnectionSearch() |
|||
} |
|||
|
|||
const handleShorePowerConnectionCurrentChange = (val: number) => { |
|||
shorePowerConnectionQueryParams.value.pageNo = val |
|||
handleShorePowerConnectionSearch() |
|||
} |
|||
|
|||
// 监听数据变化并更新总数 |
|||
watch( |
|||
() => props.berthingData, |
|||
(newData) => { |
|||
berthingTotal.value = newData?.length || 0 |
|||
}, |
|||
{ immediate: true } |
|||
) |
|||
|
|||
watch( |
|||
() => props.shorePowerConnectionData, |
|||
(newData) => { |
|||
shorePowerConnectionTotal.value = newData?.length || 0 |
|||
}, |
|||
{ immediate: true } |
|||
) |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.filter-container { |
|||
margin-bottom: 20px; |
|||
} |
|||
|
|||
.pagination-container { |
|||
margin-top: 20px; |
|||
display: flex; |
|||
justify-content: flex-end; |
|||
} |
|||
|
|||
.dialog-footer { |
|||
display: flex; |
|||
justify-content: flex-end; |
|||
gap: 10px; |
|||
} |
|||
</style> |
|||
File diff suppressed because it is too large
@ -0,0 +1,304 @@ |
|||
<template> |
|||
<el-dialog v-model="visible" title="岸电箱历史记录" width="1200px" :before-close="handleClose"> |
|||
<el-tabs v-model="activeTab"> |
|||
<!-- 岸电箱历史记录 tab --> |
|||
<el-tab-pane label="岸电箱历史记录" name="shorePower"> |
|||
<!-- 搜索和筛选区域 --> |
|||
<div class="filter-container"> |
|||
<el-form :model="queryParams" label-width="80px" inline> |
|||
<el-form-item label="关键字"> |
|||
<el-input v-model="queryParams.keyword" placeholder="请输入关键字搜索" clearable @keyup.enter="handleSearch" /> |
|||
</el-form-item> |
|||
<el-form-item label="时间范围"> |
|||
<el-date-picker v-model="dateRange" type="daterange" range-separator="至" start-placeholder="开始日期" |
|||
end-placeholder="结束日期" value-format="YYYY-MM-DD" @change="handleDateChange" /> |
|||
</el-form-item> |
|||
<el-form-item> |
|||
<el-button type="primary" @click="handleSearch">搜索</el-button> |
|||
<el-button @click="resetQuery">重置</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
</div> |
|||
|
|||
<!-- 数据表格 --> |
|||
<el-table :data="tableData" 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> |
|||
|
|||
<!-- 分页 --> |
|||
<div class="pagination-container"> |
|||
<el-pagination v-model:current-page="queryParams.pageNo" v-model:page-size="queryParams.pageSize" |
|||
:page-sizes="[10, 20, 50, 100]" :total="total" layout="total, sizes, prev, pager, next, jumper" |
|||
@size-change="handleSizeChange" @current-change="handleCurrentChange" /> |
|||
</div> |
|||
</el-tab-pane> |
|||
|
|||
<!-- 岸电箱连接船舶记录 tab --> |
|||
<el-tab-pane label="岸电箱连接船舶记录" name="shipConnection"> |
|||
<!-- 搜索和筛选区域 --> |
|||
<div class="filter-container"> |
|||
<el-form :model="shipConnectionQueryParams" label-width="80px" inline> |
|||
<el-form-item label="关键字"> |
|||
<el-input v-model="shipConnectionQueryParams.keyword" placeholder="请输入关键字搜索" clearable |
|||
@keyup.enter="handleShipConnectionSearch" /> |
|||
</el-form-item> |
|||
<el-form-item label="时间范围"> |
|||
<el-date-picker v-model="shipConnectionDateRange" type="daterange" range-separator="至" |
|||
start-placeholder="开始日期" end-placeholder="结束日期" value-format="YYYY-MM-DD" |
|||
@change="handleShipConnectionDateChange" /> |
|||
</el-form-item> |
|||
<el-form-item> |
|||
<el-button type="primary" @click="handleShipConnectionSearch">搜索</el-button> |
|||
<el-button @click="resetShipConnectionQuery">重置</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
</div> |
|||
|
|||
<!-- 数据表格 --> |
|||
<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> |
|||
|
|||
<!-- 分页 --> |
|||
<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" |
|||
@size-change="handleShipConnectionSizeChange" @current-change="handleShipConnectionCurrentChange" /> |
|||
</div> |
|||
</el-tab-pane> |
|||
</el-tabs> |
|||
|
|||
<template #footer> |
|||
<span class="dialog-footer"> |
|||
<el-button @click="handleClose">关闭</el-button> |
|||
</span> |
|||
</template> |
|||
</el-dialog> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { ref, computed, watch } from 'vue' |
|||
import { |
|||
ElDialog, |
|||
ElTabs, |
|||
ElTabPane, |
|||
ElForm, |
|||
ElFormItem, |
|||
ElInput, |
|||
ElDatePicker, |
|||
ElButton, |
|||
ElTable, |
|||
ElTableColumn, |
|||
ElPagination |
|||
} from 'element-plus' |
|||
|
|||
// 定义组件属性 |
|||
interface Props { |
|||
modelValue: boolean |
|||
data?: any[] |
|||
shipConnectionData?: any[] |
|||
} |
|||
|
|||
// 定义事件 |
|||
const emit = defineEmits<{ |
|||
(e: 'update:modelValue', value: boolean): void |
|||
(e: 'search', params: any): void |
|||
(e: 'ship-connection-search', params: any): void |
|||
}>() |
|||
|
|||
// 属性定义 |
|||
const props = withDefaults(defineProps<Props>(), { |
|||
modelValue: false, |
|||
data: () => [], |
|||
shipConnectionData: () => [] |
|||
}) |
|||
|
|||
// 响应式数据 |
|||
const visible = computed({ |
|||
get: () => props.modelValue, |
|||
set: (val) => emit('update:modelValue', val) |
|||
}) |
|||
|
|||
const activeTab = ref('shorePower') |
|||
|
|||
// 岸电箱历史记录相关数据 |
|||
const queryParams = ref({ |
|||
keyword: '', |
|||
startTime: '', |
|||
endTime: '', |
|||
pageNo: 1, |
|||
pageSize: 10 |
|||
}) |
|||
|
|||
const dateRange = ref<[string, string]>(['', '']) |
|||
const loading = ref(false) |
|||
const total = ref(0) |
|||
|
|||
// 表格数据计算属性 |
|||
const tableData = computed(() => { |
|||
// 在实际应用中,这里应该是从服务器获取的数据 |
|||
// 当前为了演示,我们使用传入的模拟数据 |
|||
return props.data?.slice( |
|||
(queryParams.value.pageNo - 1) * queryParams.value.pageSize, |
|||
queryParams.value.pageNo * queryParams.value.pageSize |
|||
) || [] |
|||
}) |
|||
|
|||
// 表格列 |
|||
const tableColumns = ref([ |
|||
{ 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 shipConnectionQueryParams = ref({ |
|||
keyword: '', |
|||
startTime: '', |
|||
endTime: '', |
|||
pageNo: 1, |
|||
pageSize: 10 |
|||
}) |
|||
|
|||
const shipConnectionDateRange = ref<[string, string]>(['', '']) |
|||
const shipConnectionLoading = ref(false) |
|||
const shipConnectionTotal = ref(0) |
|||
|
|||
// 岸电箱连接船舶记录表格数据 |
|||
const shipConnectionTableData = computed(() => { |
|||
// 在实际应用中,这里应该是从服务器获取的数据 |
|||
// 当前为了演示,我们使用传入的模拟数据 |
|||
return props.shipConnectionData?.slice( |
|||
(shipConnectionQueryParams.value.pageNo - 1) * shipConnectionQueryParams.value.pageSize, |
|||
shipConnectionQueryParams.value.pageNo * shipConnectionQueryParams.value.pageSize |
|||
) || [] |
|||
}) |
|||
|
|||
// 岸电箱连接船舶记录表格列 |
|||
const shipConnectionColumns = ref([ |
|||
{ prop: 'id', label: '记录ID', width: 80 }, |
|||
{ prop: 'shipName', 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 handleClose = () => { |
|||
visible.value = false |
|||
} |
|||
|
|||
// 岸电箱历史记录相关方法 |
|||
const handleSearch = () => { |
|||
// 发送搜索事件给父组件 |
|||
emit('search', { ...queryParams.value }) |
|||
} |
|||
|
|||
const resetQuery = () => { |
|||
queryParams.value.keyword = '' |
|||
queryParams.value.startTime = '' |
|||
queryParams.value.endTime = '' |
|||
dateRange.value = ['', ''] |
|||
queryParams.value.pageNo = 1 |
|||
handleSearch() |
|||
} |
|||
|
|||
const handleDateChange = (val: [string, string] | null) => { |
|||
if (val && val[0] && val[1]) { |
|||
queryParams.value.startTime = val[0] |
|||
queryParams.value.endTime = val[1] |
|||
} else { |
|||
queryParams.value.startTime = '' |
|||
queryParams.value.endTime = '' |
|||
} |
|||
} |
|||
|
|||
const handleSizeChange = (val: number) => { |
|||
queryParams.value.pageSize = val |
|||
queryParams.value.pageNo = 1 |
|||
handleSearch() |
|||
} |
|||
|
|||
const handleCurrentChange = (val: number) => { |
|||
queryParams.value.pageNo = val |
|||
handleSearch() |
|||
} |
|||
|
|||
// 岸电箱连接船舶记录相关方法 |
|||
const handleShipConnectionSearch = () => { |
|||
// 发送搜索事件给父组件 |
|||
emit('ship-connection-search', { ...shipConnectionQueryParams.value }) |
|||
} |
|||
|
|||
const resetShipConnectionQuery = () => { |
|||
shipConnectionQueryParams.value.keyword = '' |
|||
shipConnectionQueryParams.value.startTime = '' |
|||
shipConnectionQueryParams.value.endTime = '' |
|||
shipConnectionDateRange.value = ['', ''] |
|||
shipConnectionQueryParams.value.pageNo = 1 |
|||
handleShipConnectionSearch() |
|||
} |
|||
|
|||
const handleShipConnectionDateChange = (val: [string, string] | null) => { |
|||
if (val && val[0] && val[1]) { |
|||
shipConnectionQueryParams.value.startTime = val[0] |
|||
shipConnectionQueryParams.value.endTime = val[1] |
|||
} else { |
|||
shipConnectionQueryParams.value.startTime = '' |
|||
shipConnectionQueryParams.value.endTime = '' |
|||
} |
|||
} |
|||
|
|||
const handleShipConnectionSizeChange = (val: number) => { |
|||
shipConnectionQueryParams.value.pageSize = val |
|||
shipConnectionQueryParams.value.pageNo = 1 |
|||
handleShipConnectionSearch() |
|||
} |
|||
|
|||
const handleShipConnectionCurrentChange = (val: number) => { |
|||
shipConnectionQueryParams.value.pageNo = val |
|||
handleShipConnectionSearch() |
|||
} |
|||
|
|||
// 监听数据变化并更新总数 |
|||
watch( |
|||
() => props.data, |
|||
(newData) => { |
|||
total.value = newData?.length || 0 |
|||
}, |
|||
{ immediate: true } |
|||
) |
|||
|
|||
watch( |
|||
() => props.shipConnectionData, |
|||
(newData) => { |
|||
shipConnectionTotal.value = newData?.length || 0 |
|||
}, |
|||
{ immediate: true } |
|||
) |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.filter-container { |
|||
margin-bottom: 20px; |
|||
} |
|||
|
|||
.pagination-container { |
|||
margin-top: 20px; |
|||
display: flex; |
|||
justify-content: flex-end; |
|||
} |
|||
|
|||
.dialog-footer { |
|||
display: flex; |
|||
justify-content: flex-end; |
|||
gap: 10px; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,240 @@ |
|||
<template> |
|||
<div ref="chartContainer" class="wave-line-chart-container"></div> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { ref, onMounted, onBeforeUnmount, watch } from 'vue' |
|||
import * as echarts from 'echarts' |
|||
|
|||
// 定义组件属性 |
|||
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 |
|||
}) |
|||
|
|||
// 图表容器引用和实例 |
|||
const chartContainer = ref<HTMLDivElement | null>(null) |
|||
let chartInstance: echarts.ECharts | null = null |
|||
|
|||
// 初始化图表 |
|||
const initChart = () => { |
|||
if (chartContainer.value) { |
|||
chartInstance = echarts.init(chartContainer.value) |
|||
updateChart() |
|||
} |
|||
} |
|||
|
|||
// 更新图表 |
|||
const updateChart = () => { |
|||
if (!chartInstance || !props.chartData.length) return |
|||
|
|||
// 创建波浪效果的数据点 |
|||
const waveData = props.chartData.map(item => { |
|||
return { |
|||
...item, |
|||
value: item.value |
|||
} |
|||
}) |
|||
|
|||
const option = { |
|||
title: { |
|||
// text: props.title, |
|||
textStyle: { |
|||
color: '#fff', |
|||
fontSize: props.magnifyMode ? 24 : 14 |
|||
}, |
|||
left: 'center' |
|||
}, |
|||
tooltip: { |
|||
trigger: 'axis', |
|||
backgroundColor: 'rgba(0, 0, 0, 0.7)', |
|||
borderColor: 'rgba(30, 120, 255, 0.4)', |
|||
borderWidth: 1, |
|||
textStyle: { |
|||
color: '#fff', |
|||
fontSize: props.magnifyMode ? 20 : 12 |
|||
} |
|||
}, |
|||
xAxis: { |
|||
type: 'category', |
|||
data: props.chartData.map(item => item.name), |
|||
axisLine: { |
|||
lineStyle: { |
|||
color: 'rgba(255, 255, 255, 0.3)' |
|||
} |
|||
}, |
|||
axisLabel: { |
|||
color: 'rgba(255, 255, 255, 0.7)', |
|||
fontSize: props.magnifyMode ? 18 : 10, |
|||
rotate: 0, |
|||
interval: Math.ceil(props.chartData.length / 12), // 减少间隔以显示更多标签 |
|||
formatter: (value: string) => { |
|||
// 更灵活的时间格式化 |
|||
if (value.includes(':')) { |
|||
const parts = value.split(':'); |
|||
if (parts.length >= 2) { |
|||
// 如果是完整的时间格式 HH:mm:ss |
|||
if (parts[2] && parts[2] === '00') { |
|||
return parts[0] + ':' + parts[1]; |
|||
} |
|||
// 如果是 HH:mm 格式 |
|||
return parts[0] + ':' + parts[1]; |
|||
} |
|||
} |
|||
return value; |
|||
}, |
|||
margin: 10 |
|||
} |
|||
}, |
|||
yAxis: { |
|||
type: 'value', |
|||
// 设置 Y 轴最小值略低于数据中的最小值,以提供更好的可视化效果 |
|||
min: (value: any) => { |
|||
if (props.chartData && props.chartData.length > 0) { |
|||
const minValue = props.chartData[0].value |
|||
// 计算一个合适的最小值,略低于实际最小值 |
|||
// const range = value.max - minValue; |
|||
return minValue; // 最小值不低于0 |
|||
} |
|||
return undefined; |
|||
}, |
|||
axisLine: { |
|||
lineStyle: { |
|||
color: 'rgba(255, 255, 255, 0.3)' |
|||
} |
|||
}, |
|||
splitLine: { |
|||
lineStyle: { |
|||
color: 'rgba(255, 255, 255, 0.1)' |
|||
} |
|||
}, |
|||
axisLabel: { |
|||
color: 'rgba(255, 255, 255, 0.7)', |
|||
fontSize: props.magnifyMode ? 18 : 10 |
|||
} |
|||
}, |
|||
series: [ |
|||
{ |
|||
data: waveData.map(item => item.value), |
|||
type: 'line', |
|||
smooth: true, |
|||
showSymbol: true, |
|||
symbol: 'circle', |
|||
symbolSize: props.magnifyMode ? 8 : 4, |
|||
lineStyle: { |
|||
color: props.color, |
|||
width: props.magnifyMode ? 4 : 2 |
|||
}, |
|||
areaStyle: { |
|||
color: { |
|||
type: 'linear', |
|||
x: 0, |
|||
y: 0, |
|||
x2: 0, |
|||
y2: 1, |
|||
colorStops: [ |
|||
{ |
|||
offset: 0, |
|||
color: props.color + '80' // 添加透明度 |
|||
}, |
|||
{ |
|||
offset: 1, |
|||
color: props.color + '00' // 透明 |
|||
} |
|||
] |
|||
} |
|||
}, |
|||
// 添加波浪效果的特殊配置 |
|||
emphasis: { |
|||
focus: 'series' |
|||
}, |
|||
// 显示数据点和数值 |
|||
label: { |
|||
show: true, |
|||
position: 'top', |
|||
color: '#fff', |
|||
fontSize: props.magnifyMode ? 16 : 10, |
|||
formatter: '{c}', |
|||
distance: props.magnifyMode ? 10 : 5 |
|||
} |
|||
}, |
|||
// 添加一个辅助系列来增强波浪视觉效果 |
|||
{ |
|||
data: props.chartData.map(item => item.value), |
|||
type: 'line', |
|||
smooth: true, |
|||
showSymbol: false, |
|||
lineStyle: { |
|||
color: props.color + '60', |
|||
width: props.magnifyMode ? 2 : 1, |
|||
type: 'dashed' |
|||
}, |
|||
// 辅助系列不显示数据标签以避免重叠 |
|||
label: { |
|||
show: false |
|||
} |
|||
} |
|||
], |
|||
grid: { |
|||
left: '1%', |
|||
right: '1%', |
|||
top: props.title ? (props.magnifyMode ? '10%' : '15%') : '5%', |
|||
bottom: '1%', |
|||
containLabel: true |
|||
} |
|||
} |
|||
|
|||
chartInstance.setOption(option) |
|||
} |
|||
|
|||
// 监听数据变化 |
|||
watch( |
|||
() => props.chartData, |
|||
() => { |
|||
updateChart() |
|||
}, |
|||
{ deep: true } |
|||
) |
|||
|
|||
// 窗口大小改变时重绘图表 |
|||
const handleResize = () => { |
|||
if (chartInstance) { |
|||
chartInstance.resize() |
|||
} |
|||
} |
|||
|
|||
// 组件挂载时初始化图表 |
|||
onMounted(() => { |
|||
// 延迟初始化,确保DOM已经完全渲染 |
|||
setTimeout(() => { |
|||
initChart() |
|||
}, 200) |
|||
window.addEventListener('resize', handleResize) |
|||
}) |
|||
|
|||
// 组件销毁前清理资源 |
|||
onBeforeUnmount(() => { |
|||
window.removeEventListener('resize', handleResize) |
|||
if (chartInstance) { |
|||
chartInstance.dispose() |
|||
chartInstance = null |
|||
} |
|||
}) |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.wave-line-chart-container { |
|||
width: 100%; |
|||
height: 100%; |
|||
min-height: 0; |
|||
} |
|||
</style> |
|||
Loading…
Reference in new issue