Пакетные операции с записями¶
Предупреждение
Пакетные операции не являются частью бизнес-процессов и запускаются напрямую.
Точка расширения UEBulkOperationSettingsStore предназначена для пакетных действий над записями.
Базовый инструмент для реализации пакетных операций - BulkOperationStore.
Основные задачи точки расширения:
Получить список дескрипторов операций (чтобы пользователь мог выбрать операцию).
Инициировать выбранную операцию для настройки, создать для нее хранилище. История конкретной операции - это точка расширения пользователя по его идентификатору типа
UEBulkOperationSettingsStore
.Запуск выполнения операции с контекстом, полученным из хранилища.
Пример работы с этим хранилищем: компонент Операции в разделе "Данные" - выпадающий список действий при выборе нескольких записей.
Пример UEBulkOperationSettingsStore:
import {UeModuleBase} from '../../userexit/type/UeModuleBase';
import {IBulkOperationSettings} from '../IBulkOperationSettings';
import {ClassCtor} from '@unidata/core';
interface IBulkOperationSettings {
/**
* Шаги для работы мастера с настройками операций
*/
readonly wizardSteps: WizardStep[];
/**
* Общее хранилище пакетных операций (с методом execute)
*/
readonly bulkOperationStore: BulkOperationStore;
/**
* Метод получения содержимого для выполнения операции
*/
getContent(): Promise<any>; // Полезная нагрузка для операции BE (зависит от операций)
}
export type UEBulkOperationSettingsStore = UeModuleBase & {
'default': {
fn: () => ClassCtor<IBulkOperationSettings>;
};
}
Пакетная операция по удалению записей¶
Кнопка Удалить записи появляется, когда вы выбираете необходимые записи в таблице результатов поиска.
DeleteRecordsStore
отвечает за пакетную операцию удаления записей - точка типа UEBulkOperationSettingsStore (см. выше).
Пример реализации:
import {Res, ResourceManager, Right, UEBulkOperationSettingsStore} from '@unidata/core-app';
import {DeleteRecordsStore} from './DeleteRecordsStore';
import {UEList} from '@unidata/types';
import {dataRecordBulkPayload} from '@universe-se/data/src/utils/dataRecordBulkPayload'; // Утилита, которая может получить DataRecordBulkPayload
export const UEDeleteRecordBulkOpStore: UEBulkOperationSettingsStore = {
'default': {
type: UEList.BulkOperationSettingsStore,
moduleId: 'com.unidata.mdm.bulk.remove.records[operation]',
active: true,
system: false,
meta: {},
resolver: () => {
return ResourceManager.userHasRight(Res.DATA_OPERATIONS_MANAGEMENT, Right.DELETE);
},
fn: () => {
return DeleteRecordsStore;
}
}
};
Пакетная операция модификации записей¶
Кнопка "Модификация записей" появляется в секции "Действия", когда пользователь выбирает необходимые записи в таблице результатов поиска.
ModifyRecordsOperationStore
отвечает за массовую операцию модификации записей - точка типа UEBulkOperationSettingsStore (см. выше).
Пример реализации:
export const UEModifyRecordsBulkOpStore: UEBulkOperationSettingsStore = {
'default': {
type: UEList.BulkOperationSettingsStore,
moduleId: 'com.universe.mdm.bulk.modify.records[operation]',
active: true,
system: false,
meta: {},
resolver: (searchStore: AbstractSearchStore<AbstractSearchPanelStore, AbstractSearchColumnsStore>) => {
if (!(searchStore instanceof DataSearchStore)) {
return false;
}
const {typeName} = searchStore;
return ResourceManager.userHasRight(
ResourceUtil.stringifyResourceId(ResourceCategory.DATA, typeName),
Right.UPDATE
);
},
fn: () => {
return ModifyRecordsOperationStore;
}
}
};
Рисунок 1 - Выпадающий список действий при выборе нескольких записей и кнопка "Удалить записи"
Пакетная операция без участия сервера¶
Точка расширения UESearchPageOperationMenuItem позволяет добавить в меню пакетных операций над записями дополнительные функции, которые не требуют серверных задач.
Описание UESearchPageOperationMenuItem:
export type SearchPageMenuItemArgs = {
routerStore: RouterStore;
searchStore: AbstractSearchStore<
AbstractSearchPanelStore,
AbstractSearchColumnsStore
>;
};
export type UESearchPageOperationMenuItem = UeModuleBase & {
default: {
fn: (args: SearchPageMenuItemArgs) => void;
resolver: (args: SearchPageMenuItemArgs) => boolean;
meta: {
isActive?: (args: SearchPageMenuItemArgs) => boolean;
getTitle: (args: SearchPageMenuItemArgs) => string;
};
};
};
Пример реализации кнопки сравнения записей:
export const compareMenuItem: UESearchPageOperationMenuItem = {
'default': {
type: UEList.SearchPageOperationMenuItem,
resolver: ({searchStore}: SearchPageMenuItemArgs) => {
if (!(searchStore instanceof DataSearchStore)) {
return false;
}
const {checkedSearchHits} = searchStore.searchResult;
const hasDataRight = MetaDataRightUtils.userHasDataRight(searchStore.typeName, Right.READ);
const checkedCount = checkedSearchHits.size;
return checkedCount > 1 && hasDataRight; // Показывать только в том случае, если отмечено более 1 записи и пользователь имеет права на чтение выбранного типа актива
},
active: true,
system: false,
moduleId: 'search_page_compare_menu_item',
fn: MenuItemCompare.openCompareDrawer, // Функция для открытия модального окна с CompareTable или другим маршрутом
meta: {
getTitle: () => 'Compare Records'
}
}
};
Расширение пакетной модификации записей¶
Точка расширения UEModifyRecords предназначена для добавления фрагмента к запросу операции пакетной модификации записей и вывода в мастере операции интерфейса для изменения передаваемых во фрагменте параметров.
Используемые типы:
interface IModifyInnerStore {
/*
* Добавляемые в мастер операции 1+ вкладка/и, компонент параметров будет рендерится в ней/них
*/
tabs: TabItem[];
/*
* Возвращает фрагмент запроса
*/
getContent: () => {};
/*
* True, если заданные во фрагменте параметры позволяют запустить операцию
*/
allowConfirm: boolean;
/*
* True, если заданные во фрагменте параметры запрещают запуск операции
*/
hasErrors: boolean;
/*
* Ключ, под которым в запрос будет добавлен фрагмент
*/
payloadKey: string;
}
type UEModifyRecordsResolver = (modifyOperationStore: ModifyRecordsOperationStore) => boolean;
type UEModifyRecordsMeta = {
/*
* @param key - передается meta.key текущего User Exit
*/
getStore: (modifyOperationStore: ModifyRecordsOperationStore, key: string) => IModifyInnerStore;
key: string;
};
type UEModifyRecords = UeModuleBase<UEModifyRecordsResolver, UEModifyRecordsMeta> & {
component: ComponentType<{modifyStore: ModifyRecordsOperationStore}>;
};
Пример UEModifyRecords:
type Props = {
modifyStore: ModifyRecordsOperationStore
}
class ModifyRecordAdditionalStore implements IModifyInnerStore {
public readonly payloadKey: string;
@observable
public modificationProperty1: boolean = false;
@observable
public modificationProperty2: string = '';
@observable
public modificationProperty3: number = 0;
constructor (payloadKey: string) {
this.payloadKey = payloadKey;
}
@computed
get allowConfirm () {
return this.modificationProperty2 !== '';
}
@computed
get hasErrors () {
return this.modificationProperty1 && this.modificationProperty3 === 0;
}
get tabs () {
return [
{
key: this.payloadKey,
tab: 'Дополнительные параметры'
}
];
}
@action
setFieldValue = (name: 'modificationProperty1' | 'modificationProperty2' | 'modificationProperty3', value: any) => {
this[name] = value as
typeof name extends 'modificationProperty1' ? string :
typeof name extends 'modificationProperty2' ? number :
typeof name extends 'modificationProperty3' ? boolean :
never;
}
getContent(): {} {
const {
modificationProperty1,
modificationProperty2,
modificationProperty3
} = this;
return {
modificationProperty1,
modificationProperty2,
modificationProperty3
};
}
}
@observer
class CloneRecordUserExit extends React.Component<Props> {
get store () {
const {modifyStore} = this.props;
return modifyStore.getStore(PAYLOAD_KEY) as ModifyRecordAdditionalStore;
}
override render () {
const {store} = this;
return (
<>
<Field.Checkbox
label={'Параметр 1'}
name={'modificationProperty1'}
defaultChecked={store.modificationProperty1}
onChange={store.setFieldValue}
/>
<Field.Input
label={'Параметр 2'}
name={'modificationProperty2'}
type={'text'}
disabled={false}
readOnly={false}
defaultValue={store.modificationProperty2}
onChange={store.setFieldValue}
/>
<Field.Input
label={'Параметр 3'}
name={'modificationProperty3'}
type={'number'}
disabled={false}
readOnly={false}
defaultValue={store.modificationProperty3}
onChange={store.setFieldValue}
/>
</>
);
}
}
const PAYLOAD_KEY = 'modify-records-additional-fragment-v1';
ueModuleManager.addModule('ModifyRecords', {
active: true,
component: CloneRecordUserExit,
meta: {
getStore: () => {
return new ModifyRecordAdditionalStore(PAYLOAD_KEY)
},
key: PAYLOAD_KEY
},
moduleId: PAYLOAD_KEY,
resolver: (modifyOperationStore: ModifyRecordsOperationStore) => {
const dataRecordInnerStore = modifyOperationStore.dataCardStore.getInnerStore('data-record-additional-store');
return dataRecordInnerStore !== undefined;
},
system: false
});