Table of Contents

Выбор объекта

См. пример SDK/Web/Samples/Client/polynom-select-demo.

Структуры данных

Описание типов, общих для диалогов выбора и поиска, приведено ниже. Большая часть типов объявлена в библиотеке @ascon/polynom-integration; часть из них реэкспортируется через @ascon/polynom-select.

Перечисление типов объектов ПОЛИНОМ:MDM, подлежащих выбору (пакет @ascon/polynom-integration):

/**
 * Типы данных объектов ПОЛИНОМ:MDM которые можно выбрать.
 */
export enum SelectPolynomObjectTypes {
  // Без типа.
  None = 0,

  // Элемент.
  Element = 4,

  // Группа.
  ElementGroup = 39,

  // Каталог.
  ElementCatalog = 40,

  // Справочник.
  Reference = 48,

  // Документ.
  Document = 71,

  // Каталог документов.
  DocumentCatalog = 69,

  // Группа документов.
  DocumentGroup = 70,

  // Каталог представлений.
  ViewpointCatalog = 91,

  // Группа представлений.
  ViewpointGroup = 92,

  // Представление.
  Viewpoint = 93
}

Базовое сообщение интеграции:

/**
 * Представляет сообщение интеграции с ПОЛИНОМ:MDM.
 */
export type IIntegrationResponse = {
  /** Идентификатор сообщений ПОЛИНОМ:MDM. */
  messageId: string;
};

Структура данных справочника, каталога, группы:

/*
 * Данные идентифицирующие объект.
 */
export type IIdentifierData = {
  /* Идентификатор объекта. */
  identifier?: IIdentifiableObject;

  /* Строка расположения объекта. */
  location?: string;
};

Структура данных понятия:

/*
 * Данные идентифицирующие понятие.
 */
export type IConceptIdentifierData = {
  /* Идентификатор понятия. */
  identifier?: IIdentifiableObject;

  /* Абсолютный код понятия. */
  absoluteCode?: string;
};

Структура данных фильтра:

/**
 * Контейнер фильтра.
 */
export type IFilterContainer = {
  /* Список допустимых типов объектов для выбора. */
  objectTypes: SelectPolynomObjectTypes[];

  /* Список справочников, каталогов, групп из которых допустим выбор. */
  scopes: IIdentifierData[];

  /* Список элементов для добавления в области выбора. */
  elements: IIdentifierData[];

  /* Список допустимых понятий для объектов. */
  concepts: IConceptIdentifierData[];
};

Структура данных опций диалога выбора:

/**
 * Параметры выбора.
 */
export type ISelectDialogOption = {
  /**
   * Идентификатор хранилища.
   */
  storageId: string | null;

  /**
   * Токен доступа.
   */
  accessToken: string | null;

  /**
   * Данные фильтра.
   */
  filter: Partial<IFilterContainer>;

  /**
   * Строка расположения объекта котором нужно выбрать в дереве.
   */
  location: string | null;

  /**
   * Режим только для просмотра.
   */
  readonly: boolean;

  /**
   * Признак режима множественного выбора.
   */
  multiselectMode: boolean;

  /**
   * Признак отображения сортамента.
   */
  sortamentInstanceMode: boolean;

  /**
   * Указывает на базовый тип сортамента.
   */
  sortamentInstanceBase: SortamentInstanceBase;

  /**
   * Режим открытия окна на вкладке Все размеры.
   */
  allSizesMode: boolean;

  /**
   * Значения всех доступных свойств.
   */
  allSizePropertyValues: Map<string, string>;

  /**
   * Признак открытия окна ПОЛИНОМ в режиме поиска.
   */
  searchMode: boolean;

  /**
   * Режим учета применяемости.
   */
  useApplicability: boolean;

  /**
   * Подсказка
   */
  hint?: string;

  /**
   * Изменения видимости блока фильтрации над деревом классификации
   */
  hideFilterScopeLabel?: boolean;
};

Структура данных, получаемая при авторизации в ПОЛИНОМ:MDM:

/**
 * Представляет данные авторизации ПОЛИНОМ:MDM.
 */
export type IAuthDataResponse = IIntegrationResponse & {
  /** Жетон доступа к ПОЛИНОМ:MDM. */
  accessToken: string;
};

Структура данных, получаемая при выборе объекта в дереве классификации ПОЛИНОМ:MDM:

/**
 * Представляет идентифицируемый объект.
 */
export type IIdentifiableObject = {
  /**
   * Идентификатор объекта.
   */
  objectId: number;
  /**
   * Тип объекта.
   */
  typeId: IdentifiableObjectType;
};
/**
 * Представляет объект с применяемостью.
 */
export type IHaveApplicability = {
  /**
   * Применяемость.
   */
  applicability: Applicability;
};
/**
 * Представляет данные выбранного объекта ПОЛИНОМ:MDM.
 */
export type IPolynomObjectData = INamedObject &
  IHaveApplicability & {
    /** Строка расположения объекта.  */
    location: string;
  };

Структура данных результата диалога выбора:

/**
 * Представляет результата выбора.
 */
export type ISelectDialogResult = {
  /**
   * Данные выбранного объекта.
   */
  polynomObject: IPolynomObjectData | null;

  /**
   * Данные выбранных объектов.
   */
  polynomObjects: IPolynomObjectData[];

  /**
   * Данные авторизации.
   */
  polynomAuthData: IAuthDataResponse;
};

Структура данных конфигурации вторичных диалогов (SelectLinkScopeDialog, SelectObjectPropertyDialog и других):

export type ISelectConfig = {
  /** Текущий элемент, некоторые деревья строятся внутри 1 справочника, необходим элемент справочника */
  currentElement: IIdentifiableObject | null;

  /** Ранее выбранные узлы, чтобы исключить повторный выбор и настроить их отображение */
  alreadySelectedNodes: IIdentifiableObject[];

  /** Надо ли отображать чекбоксы (используется в множественном выборе) */
  isShowCheckboxes: boolean;

  /** Проверять права доступа к объектам */
  isCheckAccessRight: boolean;

  /** Надо ли проверять права на создание объекта */
  isCheckCreateAccess: boolean;

  /** Есть ли множественный выбор объектов */
  isMultiSelect: boolean;

  /** Типы объектов для выбора */
  typesObjectToSelectable: IdentifiableObjectType[];

  /** Вызов окна в сервисе для интеграции */
  isIntegration: boolean;

  /** Выключить выбор корневого узла */
  isEnabledRootNode?: boolean;
};

Настройка проекта перед использованием библиотеки @ascon/polynom-select

Создайте проект с помощью NX:

npx create-nx-workspace polynom-select-demo --preset=angular-standalone

Требуемые зависимости:

{
  "dependencies": {
    "@ascon/core": "24.1.126",
    "@ascon/polynom-api": "~24.1.14404",
    "@ascon/polynom-api-client": "~24.1.14404",
    "@ascon/polynom-integration": "~24.1.14404",
    "@ascon/polynom-login": "~24.1.14404",
    "@ascon/polynom-select": "~24.1.14404",
    "@ascon/polynom-trees": "~24.1.14404",
    "@ascon/polynom-ui": "~24.1.14404",
    "@ascon/primeng": "24.0.2",
    "@ascon/qwebchannel-bridge": "^6.8.3",
    "@ascon/ui": "24.1.126"
  }
}

Расположение библиотек @ascon/polynom-select, @ascon/polynom-integration, @ascon/polynom-api и их зависимостей

SDK/Web/Samples/Client/libs/

Варианты доставки библиотек ASCON

  1. Вы можете опубликовать библиотеки в собственный локальный репозиторий npm пакетов и выполнить команды установки.
npm install @ascon/polynom-select@24.1.14404
npm install @ascon/polynom-integration@24.1.14404
npm install @ascon/polynom-login@24.1.14404
  1. Вы можете скопировать библиотеки в **node_modules/@ascon** своего проекта из SDK/Web/Samples/Client/libs/ и установить транзитивные зависимости.
npm install

Подключение активов библиотек к проекту

В файл project.json добавьте:

{
  "targets": {
    "build": {
      "options": {
        "assets": [
          {
            "glob": "**/*",
            "input": "node_modules/@ascon/theme/assets",
            "output": "./assets"
          },
          {
            "glob": "**/*",
            "input": "node_modules/@ascon/polynom-api/assets",
            "output": "/assets"
          },
          {
            "glob": "**/*",
            "input": "node_modules/@ascon/polynom-core/assets",
            "output": "./assets"
          },
          {
            "glob": "**/*",
            "input": "node_modules/@ascon/polynom-ui/assets",
            "output": "./assets"
          },
          {
            "glob": "**/*",
            "input": "node_modules/@ascon/polynom-trees/assets",
            "output": "./assets"
          },
          {
            "glob": "**/*",
            "input": "node_modules/@ascon/polynom-login/assets",
            "output": "./assets"
          },
          {
            "glob": "**/*",
            "input": "node_modules/@ascon/polynom-select/assets",
            "output": "./assets"
          },
          {
            "glob": "**/*",
            "input": "src/assets",
            "output": "./assets"
          }
        ],
        "styles": [
          {
            "input": "node_modules/@ascon/theme/theme.css",
            "inject": false,
            "bundleName": "theme"
          },
          {
            "input": "node_modules/@ascon/polynom-theme/styles/polynom-theme.css",
            "inject": true,
            "bundleName": "app-styles"
          },
          {
            "input": "node_modules/@ascon/polynom-trees/styles/polynom-trees.css",
            "inject": true,
            "bundleName": "app-styles"
          },
          {
            "input": "node_modules/@ascon/polynom-ui/styles/polynom-ui.css",
            "inject": true,
            "bundleName": "app-styles"
          },
          {
            "input": "node_modules/@ascon/polynom-login/styles/polynom-login.css",
            "inject": true,
            "bundleName": "app-styles"
          },
          {
            "input": "src/styles.scss",
            "inject": false,
            "bundleName": "app-styles"
          }
        ]
      }
    }
  }
}

В файл index.html добавьте:

<html lang="ru">
  <head>
    <link
      href="theme.css"
      id="theme-link"
      media="all"
      onload="this.media='all'"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="app-styles.css"
      id="app-link"
      media="all"
      onload="this.media='all'"
      rel="stylesheet"
      type="text/css"
    />
  </head>
</html>

Подключение провайдера providePolynomSelect()

Диалоги выбора подключаются через функцию providePolynomSelect(), которая регистрирует необходимые провайдеры (в том числе providePolynomApi()). Добавьте её в appConfig:

// app.config.ts
import { APP_BASE_HREF } from "@angular/common";
import { provideHttpClient, withInterceptors } from "@angular/common/http";
import { ApplicationConfig, isDevMode } from "@angular/core";
import { provideAnimations } from "@angular/platform-browser/animations";
import { provideRouter } from "@angular/router";
import { provideLocalization, provideStorages } from "@ascon/core";
import { providePolynomSelect } from "@ascon/polynom-select";
import { jwtInterceptor } from "./helpers/jwt.interceptor";
import { appRoutes } from "./app.routes";

export const appConfig: ApplicationConfig = {
  providers: [
    provideAnimations(),
    provideHttpClient(withInterceptors([jwtInterceptor])),
    provideStorages(),
    provideLocalization({
      availableLangs: ["ru", "en"],
      defaultLang: "ru",
      prodMode: !isDevMode(),
      scopes: [
        "polynom/polynom-select-demo",
        "polynom/polynom-api",
        "polynom/polynom-select",
        "polynom/polynom-login",
        "polynom/polynom-trees",
        "polynom/polynom-ui",
        "polynom/polynom-core"
      ]
    }),
    { provide: APP_BASE_HREF, useValue: "/select-demo" },
    providePolynomSelect(),
    provideRouter(appRoutes)
  ]
};

Настройка адреса веб-сервера ПОЛИНОМ:MDM

Перед запуском диалогового окна нужно указать адрес веб-сервера ПОЛИНОМ:MDM (например, веб-сервер ПОЛИНОМ:MDM работает на 127.0.0.1:5100):

import { inject } from "@angular/core";
import { PolynomApiConfig } from "@ascon/polynom-api";

// Параметры WEB API ПОЛИНОМ:MDM
const polynomApiConfig: PolynomApiConfig = inject(PolynomApiConfig);

polynomApiConfig.setHost("http://localhost:5100");

Или в компоненте, из которого вызывается окно выбора ПОЛИНОМ:MDM:

import { Component, inject, OnInit } from "@angular/core";
import { LoginService, PolynomApiConfig } from "@ascon/polynom-api";

@Component({
  selector: "mdm-select-object",
  standalone: true,
  imports: [CommonModule],
  templateUrl: "./select-object.component.html",
  styleUrl: "./select-object.component.scss"
})
export class SelectObjectComponent implements OnInit {
  // Сервис авторизации ПОЛИНОМ:MDM.
  private readonly _loginService: LoginService = inject(LoginService);

  // Параметры WEB API ПОЛИНОМ:MDM.
  private readonly _polynomApiConfig: PolynomApiConfig = inject(PolynomApiConfig);

  public ngOnInit(): void {
    this._polynomApiConfig.setHost("http://127.0.0.1:5100");
  }
}

Примеры вызова ПОЛИНОМ:MDM

Подготовка компонента

Импорт классов, интерфейсов, сервисов:

import { ChangeDetectionStrategy, Component, inject, signal } from "@angular/core";
import { FormsModule } from "@angular/forms";
import { LoginService } from "@ascon/polynom-api";
import { IPolynomObjectData, SelectPolynomObjectTypes } from "@ascon/polynom-integration";
import { SelectDialog } from "@ascon/polynom-select";
import { ButtonDirective } from "@ascon/primeng/button";
import { DialogService } from "@ascon/primeng/dynamicdialog";
import { PrimengModule, UiModule } from "@ascon/ui";
import { take } from "rxjs";

Обратите внимание: DialogService подключается из @ascon/primeng/dynamicdialog, а provideLocalization и provideStorages — из @ascon/core.

Получите экземпляры глобальных сервисов:

// Сервис диалогов.
private readonly _dialogService: DialogService = inject(DialogService);

// Сервис авторизации ПОЛИНОМ:MDM.
private readonly _loginService: LoginService = inject(LoginService);

Поля данных, получаемых из диалога выбора объекта ПОЛИНОМ:MDM:

// Данные выбранного объекта ПОЛИНОМ:MDM.
private _polynomObject: IPolynomObjectData | null = null;

Вызов окна выбора объекта ПОЛИНОМ:MDM

selectObject(): void {
  // Строка расположения объекта, который должен быть открыт в окне ПОЛИНОМ:MDM
  const location = "<строка расположения объекта>";

  // Указываем типы объектов справочника, которые нужно выбрать
  const filterObjectIds = [SelectPolynomObjectTypes.Element];

  SelectDialog.show(this._dialogService, {
    accessToken: this._loginService.accessToken,
    filter: { objectTypes: filterObjectIds },
    useApplicability: true,
    location: location,
    hint: "Подсказка"
  })
    .pipe(take(1))
    .subscribe({
      next: (value) => {
        if (!value?.polynomObject) {
          return;
        }

        this.location = value.polynomObject.location;
      }
    });
}

Множественный выбор

Для включения множественного выбора укажите multiselectMode: true. Результат выбора доступен в поле polynomObjects:

selectObjects(): void {
  const filterObjectIds = [SelectPolynomObjectTypes.Element];

  SelectDialog.show(this._dialogService, {
    accessToken: this._loginService.accessToken,
    filter: { objectTypes: filterObjectIds },
    useApplicability: true,
    multiselectMode: true
  })
    .pipe(take(1))
    .subscribe({
      next: (value) => {
        if (value.polynomObjects.length === 0) {
          return;
        }

        this.selectObjects = value.polynomObjects;
      }
    });
}

Выбор на вкладке «Все размеры»

Для открытия окна на вкладке «Все размеры» используются параметры allSizesMode и allSizePropertyValues:

selectAllSizes(): void {
  const filterObjectIds = [SelectPolynomObjectTypes.Element];

  SelectDialog.show(this._dialogService, {
    accessToken: this._loginService.accessToken,
    filter: { objectTypes: filterObjectIds },
    location: this.location,
    allSizesMode: true,
    allSizePropertyValues: this.allSizePropertyValues,
    useApplicability: true
  })
    .pipe(take(1))
    .subscribe({
      next: (value) => {
        if (!value?.polynomObject) {
          return;
        }

        this.selectResult = value;
      }
    });
}

Выбор с ограничением области

Область выбора задаётся списком scopes в фильтре. Видимость блока фильтрации над деревом классификации управляется параметром hideFilterScopeLabel:

selectWithScope(): void {
  const filterObjectIds = [SelectPolynomObjectTypes.Element];

  SelectDialog.show(this._dialogService, {
    accessToken: this._loginService.accessToken,
    filter: {
      objectTypes: filterObjectIds,
      scopes: this.filterScopes
    },
    hideFilterScopeLabel: true,
    location: this.location
  })
    .pipe(take(1))
    .subscribe({
      next: (value) => {
        if (!value?.polynomObject) {
          return;
        }

        this.location = value.polynomObject.location;
      }
    });
}

Вызов окна выбора объекта с предварительной авторизацией

accessToken может быть получен из общего сервиса авторизации или из web api ПОЛИНОМ:MDM. storageId необходим для указания хранилища.

selectPolynom(): void {
  const filterObjectIds = [SelectPolynomObjectTypes.Element];

  SelectDialog.show(this._dialogService, {
    storageId: this._loginService.storageId,
    accessToken: this._loginService.accessToken,
    filter: { objectTypes: filterObjectIds },
    location: this.location
  })
    .pipe(take(1))
    .subscribe({
      next: (value) => {
        if (!value?.polynomObject) {
          return;
        }

        this.location = value.polynomObject.location;
      }
    });
}

Выбор сортамента

Для открытия окна в режиме сортамента используется sortamentInstanceMode, а базовый тип сортамента задаётся параметром sortamentInstanceBase:

selectSortament(): void {
  SelectDialog.show(this._dialogService, {
    accessToken: this._loginService.accessToken,
    filter: { objectTypes: [SelectPolynomObjectTypes.Element] },
    sortamentInstanceMode: true,
    sortamentInstanceBase: SortamentInstanceBase.Assortment
  })
    .pipe(take(1))
    .subscribe({
      next: (value) => {
        if (!value?.polynomObject) {
          return;
        }

        this.location = value.polynomObject.location;
      }
    });
}

Дополнительные диалоги

Помимо основного окна выбора доступны специализированные диалоги: выбор области связи, типа связи, свойства, понятия, объекта классификации и группы классификации. Все они принимают DialogService, объект конфигурации ISelectConfig и заголовок. Результат диалога (ISelectCloseResult) содержит buttonEvent (CloseResult.Cancel или CloseResult.Select) и массив values.

Выбор области связи

selectLinkScope(): void {
  SelectLinkScopeDialog.show(this._dialogService, {}, translate("Select link scope"))
    .pipe(take(1))
    .subscribe({
      next: (value) => {
        if (!value || value.buttonEvent === CloseResult.Cancel) {
          return;
        }

        if (value.buttonEvent === CloseResult.Select) {
          this.linkScopeResult = value.values;
          return;
        }
      }
    });
}

Выбор типа связи

selectLinkType(): void {
  SelectTypeLinkDialog.show(this._dialogService, {}, translate("Select link type"))
    .pipe(take(1))
    .subscribe({
      next: (value) => {
        if (!value || value.buttonEvent === CloseResult.Cancel) {
          return;
        }

        if (value.buttonEvent === CloseResult.Select) {
          this.linkTypeSelectionResult = value.values;
          return;
        }
      }
    });
}

Выбор свойства

Для включения множественного выбора свойства используется параметр isMultiSelect:

selectObjectProperty(): void {
  SelectObjectPropertyDialog.show(
    this._dialogService,
    {
      isIntegration: true,
      isMultiSelect: this.multiselectMode
    },
    translate("Select properties")
  )
    .pipe(take(1))
    .subscribe({
      next: (value) => {
        if (!value || value.buttonEvent === CloseResult.Cancel) {
          return;
        }

        if (value.buttonEvent === CloseResult.Select) {
          this.objectPropertyResult = value.values;
          return;
        }
      }
    });
}

Выбор объекта классификации

selectClassificationObject(): void {
  SelectClassificationObjectDialog.show(this._dialogService, {}, translate("Select object"))
    .pipe(take(1))
    .subscribe({
      next: (value) => {
        if (!value || value.buttonEvent === CloseResult.Cancel) {
          return;
        }

        if (value.buttonEvent === CloseResult.Select) {
          this.objectSelectionResult = value.values;
          return;
        }
      }
    });
}

Выбор понятия

selectConcept(): void {
  SelectConceptDialog.show(
    this._dialogService,
    {
      isIntegration: true,
      isMultiSelect: this.multiselectMode
    },
    translate("Select concepts")
  )
    .pipe(take(1))
    .subscribe({
      next: (value) => {
        if (!value || value.buttonEvent === CloseResult.Cancel) {
          return;
        }

        if (value.buttonEvent === CloseResult.Select) {
          this.conceptClassificationSelectionResult = value.values;
          return;
        }
      }
    });
}

Выбор группы классификации

selectClassificationGroup(): void {
  SelectClassificationGroupDialog.show(
    this._dialogService,
    { isEnabledRootNode: false },
    translate("Select classification scope")
  )
    .pipe(take(1))
    .subscribe({
      next: (value) => {
        if (!value || value.buttonEvent === CloseResult.Cancel) {
          return;
        }

        if (value.buttonEvent === CloseResult.Select) {
          this.classificationGroupSelectionResult = value.values;
          return;
        }
      }
    });
}