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