mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-06-05 22:19:35 +08:00
✨ feat(data-grid): 筛选面板新增多字段排序功能并支持启用禁用
- 排序扩展:SortInfo 类型从单字段扩展为数组,SQL 和 MongoDB 均支持多字段 ORDER BY - 筛选面板:新增排序配置区域,支持动态添加/删除多个排序字段及启用/禁用 - 表头联动:启用 Ant Design 多列排序模式,表头排序图标与筛选面板双向同步 - 增量更新:表头点击排序时在现有排序数组中增量更新,不覆盖其他字段 - 循环优化:表头排序从"升序→降序→取消"改为"升序↔降序"切换 - 布局优化:操作按钮栏增加分隔符分组,排序区域与按钮间增加视觉分隔 - refs #279
This commit is contained in:
@@ -1,10 +1,13 @@
|
||||
import type { FilterCondition } from './sql';
|
||||
import { parseListValues } from './sql';
|
||||
|
||||
type SortInfo = {
|
||||
type SortInfoItem = {
|
||||
columnKey?: string;
|
||||
order?: string;
|
||||
} | null | undefined;
|
||||
enabled?: boolean;
|
||||
};
|
||||
|
||||
type SortInfo = SortInfoItem | SortInfoItem[] | null | undefined;
|
||||
|
||||
type ShellConvertResult = {
|
||||
recognized: boolean;
|
||||
@@ -607,14 +610,24 @@ export const buildMongoSort = (
|
||||
sortInfo: SortInfo,
|
||||
fallbackColumns: string[] = [],
|
||||
): Record<string, 1 | -1> | undefined => {
|
||||
const sortColumn = String(sortInfo?.columnKey || '').trim();
|
||||
const sortOrder = String(sortInfo?.order || '');
|
||||
if (sortColumn && (sortOrder === 'ascend' || sortOrder === 'descend')) {
|
||||
return { [sortColumn]: sortOrder === 'ascend' ? 1 : -1 };
|
||||
const items = Array.isArray(sortInfo) ? sortInfo : (sortInfo ? [sortInfo] : []);
|
||||
const sort: Record<string, 1 | -1> = {};
|
||||
const seen = new Set<string>();
|
||||
for (const item of items) {
|
||||
if (item?.enabled === false) continue;
|
||||
const col = String(item?.columnKey || '').trim();
|
||||
const order = String(item?.order || '');
|
||||
if (col && (order === 'ascend' || order === 'descend')) {
|
||||
const key = col.toLowerCase();
|
||||
if (!seen.has(key)) {
|
||||
seen.add(key);
|
||||
sort[col] = order === 'ascend' ? 1 : -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Object.keys(sort).length > 0) return sort;
|
||||
|
||||
const uniqueColumns: string[] = [];
|
||||
const seen = new Set<string>();
|
||||
(fallbackColumns || []).forEach((col) => {
|
||||
const key = String(col || '').trim();
|
||||
if (!key) return;
|
||||
@@ -625,7 +638,6 @@ export const buildMongoSort = (
|
||||
});
|
||||
if (uniqueColumns.length === 0) return undefined;
|
||||
|
||||
const sort: Record<string, 1 | -1> = {};
|
||||
uniqueColumns.forEach((col) => {
|
||||
sort[col] = 1;
|
||||
});
|
||||
|
||||
@@ -69,10 +69,13 @@ export const quoteQualifiedIdent = (dbType: string, ident: string) => {
|
||||
|
||||
export const escapeLiteral = (val: string) => (val || '').replace(/'/g, "''");
|
||||
|
||||
type SortInfo = {
|
||||
type SortInfoItem = {
|
||||
columnKey?: string;
|
||||
order?: string;
|
||||
} | null | undefined;
|
||||
enabled?: boolean;
|
||||
};
|
||||
|
||||
type SortInfo = SortInfoItem | SortInfoItem[] | null | undefined;
|
||||
|
||||
// 为排序查询按库类型注入 sort_buffer 提升参数(仅影响当前语句)。
|
||||
// MySQL: 使用 Optimizer Hint `SET_VAR`。
|
||||
@@ -101,17 +104,50 @@ export const withSortBufferTuningSQL = (
|
||||
return rawSql;
|
||||
};
|
||||
|
||||
/** 将 SortInfo(单字段或多字段)标准化为 SortInfoItem 数组 */
|
||||
const normalizeSortInfoItems = (sortInfo: SortInfo): SortInfoItem[] => {
|
||||
if (!sortInfo) return [];
|
||||
if (Array.isArray(sortInfo)) return sortInfo;
|
||||
return [sortInfo];
|
||||
};
|
||||
|
||||
/** 判断 SortInfo 中是否存在至少一个有效排序 */
|
||||
export const hasExplicitSort = (sortInfo: SortInfo): boolean => {
|
||||
const items = normalizeSortInfoItems(sortInfo);
|
||||
return items.some(item => {
|
||||
if (item?.enabled === false) return false;
|
||||
const col = String(item?.columnKey || '').trim();
|
||||
const order = String(item?.order || '');
|
||||
return !!col && (order === 'ascend' || order === 'descend');
|
||||
});
|
||||
};
|
||||
|
||||
export const buildOrderBySQL = (
|
||||
dbType: string,
|
||||
sortInfo: SortInfo,
|
||||
fallbackColumns: string[] = [],
|
||||
) => {
|
||||
const dbTypeLower = String(dbType || '').trim().toLowerCase();
|
||||
const sortColumn = normalizeIdentPart(String(sortInfo?.columnKey || ''));
|
||||
const sortOrder = String(sortInfo?.order || '');
|
||||
const direction = sortOrder === 'ascend' ? 'ASC' : sortOrder === 'descend' ? 'DESC' : '';
|
||||
if (sortColumn && direction) {
|
||||
return ` ORDER BY ${quoteIdentPart(dbType, sortColumn)} ${direction}`;
|
||||
const items = normalizeSortInfoItems(sortInfo);
|
||||
const seen = new Set<string>();
|
||||
const sortParts: string[] = [];
|
||||
|
||||
for (const item of items) {
|
||||
if (item?.enabled === false) continue;
|
||||
const sortColumn = normalizeIdentPart(String(item?.columnKey || ''));
|
||||
const sortOrder = String(item?.order || '');
|
||||
const direction = sortOrder === 'ascend' ? 'ASC' : sortOrder === 'descend' ? 'DESC' : '';
|
||||
if (sortColumn && direction) {
|
||||
const key = sortColumn.toLowerCase();
|
||||
if (!seen.has(key)) {
|
||||
seen.add(key);
|
||||
sortParts.push(`${quoteIdentPart(dbType, sortColumn)} ${direction}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sortParts.length > 0) {
|
||||
return ` ORDER BY ${sortParts.join(', ')}`;
|
||||
}
|
||||
|
||||
// MySQL/MariaDB 大表在无显式排序需求时强制 ORDER BY(即使按主键)可能触发 filesort,
|
||||
@@ -121,7 +157,6 @@ export const buildOrderBySQL = (
|
||||
return '';
|
||||
}
|
||||
|
||||
const seen = new Set<string>();
|
||||
const stableColumns = (fallbackColumns || [])
|
||||
.map((col) => normalizeIdentPart(String(col || '')))
|
||||
.filter((col) => {
|
||||
|
||||
Reference in New Issue
Block a user