diff --git a/frontend/src/hooks/useServerSortTableData.ts b/frontend/src/hooks/useServerSortTableData.ts new file mode 100644 index 00000000..b0ad3a12 --- /dev/null +++ b/frontend/src/hooks/useServerSortTableData.ts @@ -0,0 +1,63 @@ +import { ref } from 'vue'; + +export interface SortField { + field: string; + dir: 'asc' | 'desc'; +} + +interface SortChangeInfo { + field: string; + order: 'ascend' | 'descend' | null; +} + +interface UseServerSortTableDataOptions { + /** 表格数据接口 */ + request: (params: any) => Promise; + /** 根据当前排序构造接口请求参数;返回 null/undefined 时不发请求 */ + buildSearchParams: (sort?: SortField) => any; + /** 从响应中提取表格行数组(默认兼容 data.data / data.records / data) */ + extractData?: (res: any) => T[]; +} + +/** + * data 模式表格的服务端排序封装。 + * + * BasicTable 在 data 模式下点击排序只更新箭头状态、不会重新请求接口;而 listUrl + * 模式是带 sort 参数走接口。本 hook 用于补齐 data 模式:监听 sort-change 后按当前 + * 排序重新请求接口并刷新本地数据,实现与 listUrl 模式一致的服务端排序效果。 + */ +export function useServerSortTableData( + options: UseServerSortTableDataOptions +) { + const tableData = ref([]); + const isLoading = ref(false); + + const extractRows = (res: any): T[] => { + if (options.extractData) return options.extractData(res); + return res?.data?.data || res?.data?.records || res?.data || []; + }; + + /** 按排序请求数据并刷新 tableData */ + const loadData = async (sort?: SortField) => { + const params = options.buildSearchParams(sort); + if (!params) return; + isLoading.value = true; + try { + const res = await options.request(params); + tableData.value = extractRows(res); + } finally { + isLoading.value = false; + } + }; + + /** 绑定到 BasicTable 的 @sort-change */ + const handleSortChange = (info: SortChangeInfo) => { + const sort: SortField | undefined = + info?.field && info?.order + ? { field: info.field, dir: info.order === 'ascend' ? 'asc' : 'desc' } + : undefined; + loadData(sort); + }; + + return { tableData, isLoading, loadData, handleSortChange }; +} \ No newline at end of file diff --git a/frontend/src/modules/rightSearchDrawer/monitoringTable/components/monitorInfo.vue b/frontend/src/modules/rightSearchDrawer/monitoringTable/components/monitorInfo.vue index 03ada929..4ffb64a4 100644 --- a/frontend/src/modules/rightSearchDrawer/monitoringTable/components/monitorInfo.vue +++ b/frontend/src/modules/rightSearchDrawer/monitoringTable/components/monitorInfo.vue @@ -33,6 +33,7 @@ showSizeChanger: false, showQuickJumper: false }" + @sort-change="handleSortChange" /> @@ -48,6 +49,7 @@ import { getMonitorData } from '@/api/mapModal'; import { useModelStore } from '@/store/modules/model'; import SidePanelItem from '@/components/SidePanelItem/index.vue'; import BasicTable from '@/components/BasicTable/index.vue'; +import { useServerSortTableData } from '@/hooks/useServerSortTableData'; import { DateSetting } from '@/utils/enumeration'; const uiStore = useUiStore(); @@ -55,7 +57,6 @@ const modelStore = useModelStore(); const isLoading = ref(false); const chartData = ref([]); -const tableData = ref([]); const tableRef = ref(); // ==================== 图表 ==================== @@ -403,84 +404,102 @@ const tableColumns = [ dataIndex: 'tm', width: 150, fixed: 'left', + sort: true, customRender: ({ text }: any) => text && text !== '-' ? dayjs(text).format('YYYY-MM-DD HH:mm:ss') : '-' }, { title: '坝上水位(m)', dataIndex: 'rz', - width: 100, + width: 110, + sort: true, customRender: ({ text }: any) => formatCell(text, v => v.toFixed(2)) }, { title: '坝下水位(m)', dataIndex: 'dz', - width: 100, + width: 110, + sort: true, customRender: ({ text }: any) => formatCell(text, v => v.toFixed(2)) }, { title: '入库流量(m³/s)', dataIndex: 'qi', - width: 120, + width: 130, + sort: true, customRender: ({ text }: any) => formatCell(text, v => String(Math.round(v))) }, { title: '出库流量(m³/s)', dataIndex: 'qo', - width: 120, + width: 130, + sort: true, customRender: ({ text }: any) => formatCell(text, v => String(v)) }, { title: '生态流量(m³/s)', dataIndex: 'qec', - width: 120, + width: 130, + sort: true, customRender: ({ text }: any) => formatCell(text, v => v.toFixed(1)) }, { title: '生态流量限值(m³/s)', dataIndex: 'qecLimit', - width: 140, + width: 160, + sort: true, customRender: ({ text }: any) => formatCell(text, v => v.toFixed(1)) } ]; const tableScrollX = tableColumns.reduce((s, c) => s + (c.width || 100), 0); +// 构造表格/图表请求参数(stcd + 时间范围),排序传入时叠加 sort,未传默认 tm 升序 +const buildSearchParams = (sort?: { field: string; dir: 'asc' | 'desc' }) => { + const stcd = modelStore.selectedAnchorPoint?.stcd; + if (!dateRange.value || !stcd) return null; + return { + filter: { + logic: 'and', + filters: [ + { + field: 'stcd', + operator: 'eq', + dataType: 'string', + value: stcd + }, + { + field: 'tm', + operator: 'gte', + dataType: 'date', + value: dateRange.value[0].format('YYYY-MM-DD HH:mm:ss') + }, + { + field: 'tm', + operator: 'lte', + dataType: 'date', + value: dateRange.value[1].format('YYYY-MM-DD HH:mm:ss') + } + ] + }, + sort: sort ? [sort] : [{ field: 'tm', dir: 'asc' }] + }; +}; + +// data 模式表格:点击排序时重新请求接口(服务端排序),与 listUrl 模式效果一致 +const { tableData, handleSortChange } = useServerSortTableData({ + request: getMonitorData, + buildSearchParams +}); + // 数据请求(查询参数取 modelStore.selectedAnchorPoint) const fetchData = async () => { - const stcd = modelStore.selectedAnchorPoint?.stcd; - if (!dateRange.value || !stcd) return; + const params = buildSearchParams(); + if (!params) return; isLoading.value = true; try { - const filterParams = { - filter: { - logic: 'and', - filters: [ - { - field: 'stcd', - operator: 'eq', - dataType: 'string', - value: stcd - }, - { - field: 'tm', - operator: 'gte', - dataType: 'date', - value: dateRange.value[0].format('YYYY-MM-DD HH:mm:ss') - }, - { - field: 'tm', - operator: 'lte', - dataType: 'date', - value: dateRange.value[1].format('YYYY-MM-DD HH:mm:ss') - } - ] - }, - sort: [{ field: 'tm', dir: 'asc' }] - }; - - const res = await getMonitorData(filterParams); + const res = await getMonitorData(params); const rawData = res?.data?.data || res?.data?.records || []; chartData.value = rawData;