fix: числовая сортировка date/datetime/number полей в реестре задач
Сортировка кастомных полей шла лексикографически по отображаемой строке: даты «ДД.ММ.ГГГГ» сортировались по дню («01.12.2025» < «02.01.2024»), числа как строки («10» < «9»). Теперь для field_<id> типов date/datetime/number сравнение идёт по сырому значению (timestamp/число), пустые — всегда в конец.
This commit is contained in:
@@ -267,6 +267,30 @@ export function registerTaskCrudListRoutes(router: ReturnType<typeof import("exp
|
|||||||
|
|
||||||
const DATE_COLS = new Set(['createdAt', 'updatedAt', 'dueDate', 'completedAt']);
|
const DATE_COLS = new Set(['createdAt', 'updatedAt', 'dueDate', 'completedAt']);
|
||||||
|
|
||||||
|
// Числовые и датовые кастомные поля сортируем по сырому значению,
|
||||||
|
// а не по отображаемой строке (иначе «01.12.2025» < «02.01.2024» и «10» < «9»)
|
||||||
|
type TaskWithFV = Task & { fieldValues?: Record<number, unknown> };
|
||||||
|
let numericFieldId: number | null = null;
|
||||||
|
let numericFieldIsDate = false;
|
||||||
|
if (sortColumn.startsWith('field_')) {
|
||||||
|
const fieldId = parseInt(sortColumn.replace('field_', ''));
|
||||||
|
const field = formFields.find((f) => f.id === fieldId);
|
||||||
|
if (field && ['date', 'datetime', 'number'].includes(field.type)) {
|
||||||
|
numericFieldId = fieldId;
|
||||||
|
numericFieldIsDate = field.type === 'date' || field.type === 'datetime';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const toSortNumber = (t: TaskWithFV): number | null => {
|
||||||
|
const v = t.fieldValues?.[numericFieldId!];
|
||||||
|
if (v === undefined || v === null || v === '') return null;
|
||||||
|
if (numericFieldIsDate) {
|
||||||
|
const ts = new Date(String(v)).getTime();
|
||||||
|
return isNaN(ts) ? null : ts;
|
||||||
|
}
|
||||||
|
const n = Number(String(v).replace(/\s/g, ''));
|
||||||
|
return isNaN(n) ? null : n;
|
||||||
|
};
|
||||||
|
|
||||||
tasks = [...tasks].sort((a, b) => {
|
tasks = [...tasks].sort((a, b) => {
|
||||||
if (DATE_COLS.has(sortColumn)) {
|
if (DATE_COLS.has(sortColumn)) {
|
||||||
const _a = (a as Record<string, unknown>)[sortColumn];
|
const _a = (a as Record<string, unknown>)[sortColumn];
|
||||||
@@ -275,6 +299,15 @@ export function registerTaskCrudListRoutes(router: ReturnType<typeof import("exp
|
|||||||
const bv = _b ? new Date(String(_b)).getTime() : 0;
|
const bv = _b ? new Date(String(_b)).getTime() : 0;
|
||||||
return sortDir === 'asc' ? av - bv : bv - av;
|
return sortDir === 'asc' ? av - bv : bv - av;
|
||||||
}
|
}
|
||||||
|
if (numericFieldId !== null) {
|
||||||
|
const av = toSortNumber(a as TaskWithFV);
|
||||||
|
const bv = toSortNumber(b as TaskWithFV);
|
||||||
|
// Пустые значения всегда в конец независимо от направления
|
||||||
|
if (av === null && bv === null) return 0;
|
||||||
|
if (av === null) return 1;
|
||||||
|
if (bv === null) return -1;
|
||||||
|
return sortDir === 'asc' ? av - bv : bv - av;
|
||||||
|
}
|
||||||
const av = getTaskColumnValue(a, sortColumn, statusMap, userMap, formFields, roleMap, undefined, legalEntityMap, taskTitleMap).toLowerCase();
|
const av = getTaskColumnValue(a, sortColumn, statusMap, userMap, formFields, roleMap, undefined, legalEntityMap, taskTitleMap).toLowerCase();
|
||||||
const bv = getTaskColumnValue(b, sortColumn, statusMap, userMap, formFields, roleMap, undefined, legalEntityMap, taskTitleMap).toLowerCase();
|
const bv = getTaskColumnValue(b, sortColumn, statusMap, userMap, formFields, roleMap, undefined, legalEntityMap, taskTitleMap).toLowerCase();
|
||||||
const cmp = av.localeCompare(bv, 'ru');
|
const cmp = av.localeCompare(bv, 'ru');
|
||||||
|
|||||||
Reference in New Issue
Block a user