0.0.8 • Published 6 years ago

@crpt/relation-tree v0.0.8

Weekly downloads
4
License
MIT
Repository
-
Last release
6 years ago

Getting started

###Build Run yarn install to install all dependencies.

Make some changes, run yarn run test to run both tslint and karma tests.

Package the library with yarn run build.

###Set NPM to use the cloned project In your cloned relation-tree project, type yarn link.

This will do a symbolic link from the global node_modules version to point to this folder.

You should see your changes reflected in the application.

Add this raw @import "~relation-tree/bundles/main.css"; to your application css main file.

Dependencies

Required Peer Dependencies

Component parameters

    // Content passed in via props

export interface IRelationTreeContainerProp<T extends ITreeFilter> {
  height: number; // Высота области, которую занимает компонент дерева
  nodeSize: {  
    nodeHeight: number, // Высота узла дерева
    nodeWidth: number // Ширина узла дерева
  };
  translation: any; // Данные для перевода. См описание пиже
  locale: string; // Текущий язык
  onInnChange?: (inn: String) => void; // Коллбэк, вызывается когда в дереве нажимают кнопку "Дерево владельца" и происходит перестроение дерева
  initialFilter: T; // Объект фильтра с начальными настройками. Описание см. ниже
  loadDataSettings: {
    getFullTreeCallback?: (filter: T) => Promise<TreeNodeBase>; // Опциональный колбэк для режима, когда дерево со всеми данными подгружается сразу
    loadTreePagesCallback?: (filter: T, inn: String, depth: number, pagesize: number, startIndex: number) => Promise<TreeNodeBase>; // Колбэк для подгрузки узла дерева вместе с указанным числом детей. См. ниже
    getNodesChildrenCountCallback?: (filter: T, inns: String[]) => Promise<Map<String, number>>; // Опциональный колбэк, для подгрузки числа детей у узлов. Вызывается в случае если метод loadTreePagesCallback возвращает узлы без заполненного поля "число детей"
    loadNodeInfo?: (filter: T, inn: String, parentInn: String) => Promise<INodeAttributes>; // Колбэк для подгрузки подробной информации об узле. Используется, когда нажимаем на узел и вылезает окошко с информацией
    downloadReportCallback?: (filter: T, inn: String, parentInn: String) => Promise<{ url: String }>; // Колбэк для выгрузки отчета. Возвращает ссылку, по которой можно загрузить отчет.
  };
  customFilterComponent?: (onFilterChange: (filter: T) => void, initFilter: T) => React.ReactNode; // Функция для переопределения компонента фильтра дерева (шапка с выбором дат и типом - покупатель/продавей)
  statusComponent?: () => React.ReactNode; // Кастомный элемент межжу фильтрами и деревом, отображающий статусное состояние и возможно другую информацию
  showLoading?: { onStartLoading: () => void, onEndLoading: () => void }; // Набор функций для переобпределения стандартного поведения гуи при загрузке данных. Сейчас вылезает всплывающее окошко.
  treeNodeCustomization?: {
    edgeWidthFunction?: (node: TreeNodeBase, parent: TreeNodeBase) => number; //Кастомная Функция для определения толщины ребер дерева. Сейчас толщина считается относительно видимых узлов родителя текущего уровня
    edgeCustomComponent?: (node: TreeNodeBase, parent: TreeNodeBase, isSelected: boolean, parentTop: number, x_size: number, y_size: number) => React.ReactNode; // Функция для переопределения компонента ребра графа
    customTreeNodeComponent?: (node: TreeNodeBase, collapsed: boolean) => React.ReactNode; // Функция для переопределения внешнего вида узла дерева
  };
  onErrorCallback?: (error, info) => void; // Колбэк, который дергается при ошибках компонента
  nodeInformationWidth: number; // Ширина информационной панели справа
  onClickTreeNodeLabelCallback: (node: TreeNode, treeFilter: ITreeFilter) => void; // колбэк на нажатие по узел дерева
}

Component methods

  closeInformationInfo() // вызывать для закрытия информационной панели
  changeInn(node: TreeNode) // Вызывать для смены корня дерева
Локализация
translation - объект с набором локализации 

{
  'ua': {
           "members": {
             "title": "Учасники",
             "showdatafrom": "Показати дані з",
             "showdatato": "по",
             "buyer": "Покупець",
             "seller": "Продавець",
             "inn": "ИНН",
             "products": "Products",
             "cost": "Cost",
             "tp_number_in_packs": "Кількість ТП (в пачках), шт.",
             "tp_sum_in_packs": "Сума по всій ТП (включаючи ПДВ), руб.",
             "goods_count": "Найменувань товарів, шт.",
             "marks_count": "Коди маркувань, шт.",
             "download": "Завантажити",
             "cancel": "Відміна",
             "traders": "Учасники обороту",
             "member": "Учасник",
             "registered": "З нами",
             "common_info": "Загальна інформація",
             "documents": "Документи",
             "relation_tree":"Дерево зв'язків",
             "loading":"Загрузка",
             "showdataQuarterYear": "Выберите год",
             "showdataQuarter": "Выберите квартал",
             "next": "Далее",
             "prev": "Назад",
             "owner_tree":"Дерево владельца"
           }
         },
  'en': {...},
  'fr': {...},
  'de': {...},
  'ru': {...}
}

locale - один из ключей объекта translation. Изменение языка извне можно делать либо изменением этого параметра, либо вызвав

TreeTranslatorContext.setLocale("ru")

При использовании внутри кастомных компонентов дерева значений, которые нужно перевести, можно использовать компонент

<TreeTranslate contentKey="members.inn">Текст который будет отображаться если перевод по ключу не найден</TreeTranslate>
Фильтр

Объект фильтра, передаваемого в параметре initialFilter должен представлять интерфейс

export interface ITreeFilter {
  rootNode: { inn: String, name: String }; // Инн участника, от которого мы строим дерево и название участника
  pageSize: number; // Размер страницы подгрузки детей, определяющий еще и максимальное число детей, показываемое на странице (само число детей высчитывается в зависимости от размеров области динамически)
}

По умолчанию используется базовый фильтр

export class TreeFilter implements ITreeFilter {
  dateFrom: Date;
  dateTo: Date;
  buyType: BuyType; //Тип контрагента
  rootNode: { inn: String, name: String };
  pageSize: number;
  needQuarter: boolean = false; // Поквартальный фильтр
  quarter: Quarter;
}
export enum BuyType {
  SELLER = 'SELLER',
  BUYER = 'BUYER'
}

export class Quarter {
  year: number;
  quarter: QuarterNum;
}

export enum QuarterNum {
  FIRST = '1',
  SECOND = '2',
  THIRD = '3',
  FORTH = '4'
}

Подсунув свою реализацию ITreeFilter нужно также подменить компонент фильтра

customFilterComponent?: (onFilterChange: (filter: T) => void, initFilter: T) => React.ReactNode;

Кроме того, колбэки для загрузки данных должны уметь работать с этой реализацией ITreeFilter

Загрузка данных

Подгруженные данные живут в рамках текущего значения фильтра. При изменении фильтра, дерево заново подгружается. Данные кешируются. Есть вариант сразу выгрузить все дерево. Есть вариант выгружать дерево постранично,

loadTreePagesCallback?: (filter: T, inn: String, depth: number, pagesize: number, startIndex: number) => Promise<TreeNodeBase>; // Колбэк для подгрузки узла дерева вместе с указанным числом детей. См. ниже

указывая инн узла, глубину вложенности детей(depth), количество детей, подгружаемое в каждом из уровней вложенности(pagesize), смещение у первого уровня детей указанного участника(startIndex)

export class TreeNodeBase{
  name: String;
  attributes: INodeAttributes;
  children: TreeNodeBase[];
  childrenCount: number;
}
export interface INodeAttributes{
  inn: String;
}

export class NodeAttributes implements INodeAttributes{
  inn: String;
  state: String;
  role: String;
  description: String;
  tp_count: number;
  tp_sum: number;
  goods_count: number;
  marks_count: number;
}

Методы подгрузки данных должны возвращать объекты типа TreeNodeBase. Если хотим высчитывать число детей узла отдельным запросом, нужно в колбэке у TreeNodeBase не заполнять поле childrenCount (чтобы было null), тогда будет вызываться колбэк getNodesChildrenCountCallback. В поле attributes должна быть реализация интерфейса INodeAttributes. По умолчанию используется реализация NodeAttributes. При изменении полей аттрибутов узла, необходимо не забыть переопределить параметры

memberInfoComponent?: (node: TreeNodeBase, parentInn: String, changeInn: (inn: String) => void) => React.ReactNode; // Функция для переопределения всплывающего окошка с подробной информацией об узле
customTreeNodeComponent?: (node: TreeNodeBase, collapsed: boolean) => React.ReactNode; // Функция для переопределения внешнего вида узла дерева

Кроме того, сейчас поле tp_sum аттрибутов, используется для подсчета толщины ребра, поэтому при удалении этого поля, нужно не забыть переопределить параметр

edgeWidthFunction?: (node: TreeNodeBase, parent: TreeNodeBase) => number; //Кастомная Функция для определения толщины ребер дерева. Сейчас толщина считается относительно видимых узлов родителя текущего уровня

Также есть возможно переопредить компонент отрисовки дерева

edgeCustomComponent?: (node: TreeNodeBase, parent: TreeNodeBase, isSelected: boolean, parentTop: number, x_size: number, y_size: number) => React.ReactNode; // Функция для переопределения компонента ребра графа

Пример использования:

import { BuyType, Quarter, QuarterNum, RelationTreeContainer, TreeFilter } from 'relation-tree';

...
<RelationTreeContainer height={500} nodeSize={{ nodeWidth: 217, nodeHeight: 58 }}
                                   memberInfoSize={{ width: 360, height: 210 }}
                                   translation={treeTranslations}
                                   locale={currentLocale}
                                   loadDataSettings={{
                                     loadTreePagesCallback: membersApi.loadTreePages,
                                     loadNodeInfo: membersApi.getNodeInfo,
                                     getNodesChildrenCountCallback: membersApi.getNodesChildrenCount,
                                     downloadReportCallback: membersApi.downloadReport
                                   }}
                                   initialFilter={initialFilter}
                                   onErrorCallback={this.onErrorCallback}
                                   goToMemberPage={(inn: String) => {
                                     // tslint:disable-next-line
                                     console.info('open page for inn' + inn);
                                   }}
            />

В данном примере membersApi реализует интерфейс:

export interface IApiService {
  downloadReport?(filter: ITreeFilter, inn: String, parentInn: String): Promise<{ url: String }>;
  getNodeInfo?(filter: ITreeFilter, inn: String): Promise<INodeAttributes>;
  getNodesChildrenCount?(filter: ITreeFilter, inns: String[]): Promise<Map<String, number>>;
  loadTreePages?(filter: ITreeFilter, inn: String, depth: number, pagesize: number, startIndex: number): Promise<TreeNodeBase>;
}

И

initialFilter = new TreeFilter(BuyType.BUYER, { inn: '14505458023', name: 'kaka' }, 10, true, new Quarter(2018, QuarterNum.FIRST), null, null);
currentLocale = 'ru';