Co-authored-by: gorbenko.pavel <gorbenko.pavel@tansu.kz> Reviewed-on: http://git.tnsu.kz/gorbenko.pavel/tnsu-approval-route/pulls/5
This commit was merged in pull request #5.
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
import { Employee } from '../models';
|
||||
import { ISearchableOption } from '../components/ui';
|
||||
|
||||
/** Опция для SearchableSelect: ФИО — основная строка, email — маленькая подпись под ней. */
|
||||
export function toEmployeeOption(employee: Employee): ISearchableOption {
|
||||
return { value: employee.email, label: employee.fio, sublabel: employee.email };
|
||||
}
|
||||
|
||||
export function findEmployeeByEmail(employees: Employee[], email: string | null): Employee | undefined {
|
||||
if (!email) return undefined;
|
||||
const target = email.toLowerCase();
|
||||
return employees.find(e => e.email.toLowerCase() === target);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
const SHORT_GUID_LENGTH = 8;
|
||||
|
||||
/**
|
||||
* Короткий вид Guid для таблиц: 3fa85f64… вместо всех 36 символов.
|
||||
* Нужен, когда название из справочника ещё не загрузилось или запись удалили,
|
||||
* а строка таблицы не должна выглядеть пустой.
|
||||
*/
|
||||
export function shortGuid(guid: string): string {
|
||||
return guid.length > SHORT_GUID_LENGTH ? `${guid.slice(0, SHORT_GUID_LENGTH)}…` : guid;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Русское склонение существительного после числа.
|
||||
*
|
||||
* Формы передаются в порядке: 1 шаг / 2 шага / 5 шагов.
|
||||
* Пример: pluralRu(2, ['шаг', 'шага', 'шагов']) → 'шага'.
|
||||
*/
|
||||
export function pluralRu(count: number, forms: [string, string, string]): string {
|
||||
const lastTwoDigits = Math.abs(count) % 100;
|
||||
const lastDigit = lastTwoDigits % 10;
|
||||
|
||||
// 11–14 — исключение: «11 шагов», хотя последняя цифра 1.
|
||||
if (lastTwoDigits >= 11 && lastTwoDigits <= 14) return forms[2];
|
||||
if (lastDigit === 1) return forms[0];
|
||||
if (lastDigit >= 2 && lastDigit <= 4) return forms[1];
|
||||
return forms[2];
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { Employee, HeadType, ProjectRole, StepExecutorKind, TemplateRouteStep } from '../models';
|
||||
import { headTypeLabels, projectRoleLabels, texts } from '../texts';
|
||||
import { findEmployeeByEmail } from './employee';
|
||||
|
||||
/** Каким из четырёх взаимоисключающих способов у шага задан исполнитель. */
|
||||
export function detectExecutorKind(step: {
|
||||
executorEmail?: string | null;
|
||||
position?: string | null;
|
||||
projectRole?: ProjectRole | null;
|
||||
headType?: HeadType | null;
|
||||
}): StepExecutorKind {
|
||||
if (step.executorEmail) return 'email';
|
||||
if (step.position) return 'position';
|
||||
if (step.projectRole && step.projectRole !== ProjectRole.None) return 'projectRole';
|
||||
return 'headType';
|
||||
}
|
||||
|
||||
export interface StepExecutorDisplay {
|
||||
primary: string;
|
||||
/** Email под ФИО — только когда исполнитель задан конкретным сотрудником и тот найден в справочнике. */
|
||||
secondary?: string;
|
||||
}
|
||||
|
||||
/** Колонка «Исполнитель» в таблице шагов шаблона маршрута. */
|
||||
export function describeStepExecutor(step: TemplateRouteStep, employees: Employee[]): StepExecutorDisplay {
|
||||
if (step.executorEmail) {
|
||||
const employee = findEmployeeByEmail(employees, step.executorEmail);
|
||||
return employee ? { primary: employee.fio, secondary: employee.email } : { primary: step.executorEmail };
|
||||
}
|
||||
if (step.position) return { primary: step.position };
|
||||
if (step.projectRole && step.projectRole !== ProjectRole.None) {
|
||||
return { primary: texts.routeSteps.executorRole(projectRoleLabels[step.projectRole]) };
|
||||
}
|
||||
if (step.headType && step.headType !== HeadType.None) {
|
||||
return { primary: texts.routeSteps.executorHead(headTypeLabels[step.headType]) };
|
||||
}
|
||||
return { primary: texts.common.empty };
|
||||
}
|
||||
Reference in New Issue
Block a user