feat: request portal — bespoke forms + approval mechanism

This commit is contained in:
Тимур Городецкий
2026-08-03 09:35:14 +05:00
commit bc91c9861d
110 changed files with 30562 additions and 0 deletions
@@ -0,0 +1,53 @@
/**
* Описание одной колонки списка SharePoint — единый источник правды.
* Из этих описаний провижинер создаёт колонки в списке (см. provisioning/),
* а позже те же описания будут питать чтение/запись данных формы.
*
* ВАЖНО про имена: internalName — латиница без пробелов, ≤32 символов
* (иначе SharePoint закодирует пробелы в "_x0020_" и обращения к полю сломаются).
* title — отображаемое имя, может быть на русском и с пробелами.
*/
export type SpFieldType =
| 'Text' // однострочный текст
| 'Note' // многострочный текст
| 'Number' // число
| 'Choice' // выбор из вариантов
| 'DateTime' // дата/время
| 'Boolean' // да/нет
| 'User' // пользователь
| 'Lookup'; // подстановка (связь с другим списком)
export interface IColumnDef {
/** Внутреннее имя в SharePoint: латиница, без пробелов, ≤32 символов. */
internalName: string;
/** Отображаемое имя колонки (можно рус., с пробелами). */
title: string;
/** Тип колонки. */
type: SpFieldType;
/** Обязательная ли колонка. По умолчанию — нет. */
required?: boolean;
/** Варианты для type === 'Choice'. */
choices?: string[];
/** Знаков после запятой для type === 'Number'. По умолчанию — авто. */
decimals?: number;
/** Для type === 'DateTime': только дата, без времени. */
dateOnly?: boolean;
/** Заголовок списка-источника для type === 'Lookup'. */
lookupList?: string;
/** Какое поле источника показывать в подстановке. По умолчанию — 'Title'. */
lookupShowField?: string;
/** Для type === 'User': кого можно выбирать. По умолчанию — как в SharePoint. */
userSelectionMode?: 'PeopleOnly' | 'PeopleAndGroups';
/** Для type === 'User': разрешить выбор нескольких (создаётся колонка UserMulti). */
allowMultiple?: boolean;
}
/** Манифест провижининга формы: список данных + его колонки. */
export interface IFormProvisioning {
/** Отображаемое имя списка данных формы. */
dataListTitle: string;
/** Переименовать стандартную колонку Title (если задано). */
titleColumnName?: string;
/** Колонки списка данных. */
columns: IColumnDef[];
}
@@ -0,0 +1,35 @@
import { WebPartContext } from '@microsoft/sp-webpart-base';
import { IconName } from '../shared/ui/Icon/iconNames';
/** Идентификатор типа заявки — ключ в реестре форм (formRegistry). */
export type RequestTypeId = string;
/** Категория верхнего уровня в портале (ряд вкладок сверху). */
export interface ICategory {
id: string;
title: string;
icon: IconName;
}
/** Тип заявки — плитка внутри категории. */
export interface IRequestType {
id: RequestTypeId;
categoryId: string;
title: string;
/** Короткое пояснение под заголовком плитки. Необязательно. */
description?: string;
icon: IconName;
}
/**
* Пропсы, которые получает каждая bespoke-форма от корня портала.
* Форма сама владеет записью в SharePoint (через getSP()), поэтому
* получает контекст (нужен и people picker'у), а не generic onSubmit.
*/
export interface IRequestFormProps {
requestType: IRequestType;
context: WebPartContext;
onCancel: () => void;
/** Необязательное уведомление родителя после успешного сохранения. */
onSaved?: () => void;
}