feat(users): выбор колонок в реестре пользователей + кликабельная Оценка и доработанный график истории
Реестр /users: - кнопка «Колонки» — чекбоксы базовых колонок и кастомных полей профиля (Оценка, Средняя оценка и др.), скрытые ключи в localStorage; - /api/users/list?includeFieldValues=1 — значения полей текущей страницы; - поля типа history-number (Оценка) кликабельны — открывают график истории. График истории (FieldHistoryDialog): - точки красные и крупные (на тёмном фоне дефолтные не видны), линия primary; - клик по точке — под графиком список оценок за бакет со ссылками на задачи (название задачи → /forms/<formId>/tasks/<id>); - API field-history возвращает entries (value, taskId, taskTitle, formId, bucket).
This commit is contained in:
@@ -17,7 +17,7 @@ import {
|
||||
bulkAssignDelegate,
|
||||
} from "../services/delegation.service";
|
||||
import { db } from "../db";
|
||||
import { roles, roleMembers, userStatuses, insertUserStatusSchema, updateUserStatusSchema } from "@shared/schema";
|
||||
import { roles, roleMembers, userStatuses, userProfileFieldValues, insertUserStatusSchema, updateUserStatusSchema } from "@shared/schema";
|
||||
import { eq, and, inArray } from "drizzle-orm";
|
||||
|
||||
export function registerUserRoutes(router: ReturnType<typeof import("express").Router>): void {
|
||||
@@ -135,6 +135,21 @@ export function registerUserRoutes(router: ReturnType<typeof import("express").R
|
||||
rolesByUser.get(ur.userId)!.push({ id: ur.roleId, name: ur.roleName });
|
||||
}
|
||||
|
||||
// Значения кастомных полей профиля — для реестра пользователей (выбор колонок).
|
||||
// Только для текущей страницы (userIds), опционально по includeFieldValues=1.
|
||||
const includeFieldValues = req.query.includeFieldValues === '1';
|
||||
const fieldValuesByUser = new Map<number, Record<number, unknown>>();
|
||||
if (includeFieldValues && userIds.length > 0) {
|
||||
const fvRows = await db
|
||||
.select({ userId: userProfileFieldValues.userId, fieldId: userProfileFieldValues.fieldId, value: userProfileFieldValues.value })
|
||||
.from(userProfileFieldValues)
|
||||
.where(inArray(userProfileFieldValues.userId, userIds));
|
||||
for (const row of fvRows) {
|
||||
if (!fieldValuesByUser.has(row.userId)) fieldValuesByUser.set(row.userId, {});
|
||||
fieldValuesByUser.get(row.userId)![row.fieldId] = row.value;
|
||||
}
|
||||
}
|
||||
|
||||
const allStatuses = await userStatusesStorage.listByOrganization(req.organizationId!);
|
||||
const statusById = new Map(allStatuses.map(s => [s.id, s]));
|
||||
|
||||
@@ -158,6 +173,7 @@ export function registerUserRoutes(router: ReturnType<typeof import("express").R
|
||||
lastLogin: u.lastLogin,
|
||||
createdAt: u.createdAt,
|
||||
organizationalRoles: rolesByUser.get(u.id) || [],
|
||||
...(includeFieldValues ? { fieldValues: fieldValuesByUser.get(u.id) || {} } : {}),
|
||||
};
|
||||
}),
|
||||
total: managedIds === null ? result.total : filteredUsers.length,
|
||||
|
||||
Reference in New Issue
Block a user