Try   HackMD

Универсальная таблица

Чтение

В файле `columns.tsx` создается универсальное отображение всех моделей бэкенда в виде таблицы.

Например, данные по ссылке /contracts:

[
	{
		"id": 1,
		"name": "Договор №1",
		"date": "20.08.2021",
		"jurperson": {
			"id": 1,
			"name": "ЗАО ОМЕГА, Татарстан",
			"address": "адрес: город, улица, дом, офис",
			"bankDetails": "Банковские реквизиты"
		},
		"counterpartyJurperson": {
			"id": 1,
			"name": "ООО Один",
			"address": "адрес: город, улица, дом, офис",
			"bankDetails": "Банковские реквизиты",
			"counterpartyCompany": {
				"id": 1,
				"name": "Магнит "
			}
		}
	},
]

Будут отображены в таком виде:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Сложность создаёт наличие разных типов данных внутри ячеек:

  1. примитивные данные - текст, число, дата 0й уровень вложенности
  2. объект - {id, name} 1й уровень вложенности
  3. вложенные данные, когда объект ячейки получаем из объекта другого столбца (может быть несколько уровней вложенности) 2й и 3й уровни вложенности
  4. комбинированные данные (name = shortName + fullName)
  5. частично вложенные данные, когда хотим вывести в ячейку название вложенного столбца, но сохранить ссылку на исходную модель и её экземпляр
  6. массив объектов (множество моделей)

Чтобы избежать этой сложности мы могли бы предварительно перед выводом модели сделать данные примитивным (строкой с названием). Но вместо этого мы помещаем в ячейку объект {id, name} и используем компонент отрисовки renderCell, чтобы представить там модель должным образом со всеми её параметрами. Это позволит нам открывать любую модель прямо из таблицы (например, для исправления). То есть любая ячейка таблицы связана с первоисточником.

Пример вложенных данных (3): Выплата/Должность/Точка/Контрагент. (3й уровень вложенности, пока самый глубокий)

Пример комбинированных данных (4), это Мера работы, она составляется из данных первого уровня (без использования вложенностей) name = shortName + fullName

Пример частичной вложенности (5) Выход/Должность/Профессия. Если вывести просто Должность, то будет услуга, типа "Разгрузочные работы", а нам надо указать "Грузчик", но чтобы при это сохранить ссылку на Должность по договору. Поэтому {id} попадает из Должности, а название из Профессии.

Пример многих моделей опциональные параметры работника или должности, каждый из которых является отдельной моделью.

Почему выбран подход писать универсальный компонент? Потому что очень много моделей и рутинного кода, чтобы отображать каждый из них. Если бы мы писали для каждой модели своё описание столбцов со всеми событиями, это было бы неподъемный объем рутины. В универсальном компоненте хоть и есть много отклонений от "одинаковости" в моделях, большинство кода получилось использовать однотипным.

Запись

Если читать данные удобно в "расширенных" страницах, типа "покажи всех юрлиц" и мы видим общий список и столбец "Контрагент", чтобы фильтровать их и сортировать То писать данные логично из "суженного" формата. Например, добавлять работников находясь на странице "Филиала". Потому что в универсальной странице, если мы вбиваем 10 работников, пришлось бы 10 раз указывать Филиал (каждому одинаковый), а на странице "Филиала" он и так понятен. То же самое касается Выходов им не надо выбирать каждому дату из календаря. Наоборот, мы смотрим на календарь с заранее проставленным периодом, и вписываем туда числа отработанных часов. То есть большинство информации уже подставлена (точка, должность, работник, число) и нам остаётся её немного уточнить/дополнить.

На базовом уровне запись можно разделить на 3 пункта.

  1. Вбивание текста
  2. Выбор одного (работника, точки и т.д.)
  3. Выбор многих (опциональные параметры должности)

Для записи данных мы будем использовать те же таблицы, что для чтения но с доработками:

  1. отсечение столбцов
  2. предварительная загрузка данных для выбора
  3. фильтрация данных

(1) Суть отсечения столбцов в том, что когда мы находимся на странице Контрагента и добавляем туда новые Юрлица, нам не нужен столбец Контрагент:

  • для чтения он всегда один и тот же, и это будет ненужный шум
  • для записи его нельзя менять, иначе юрлицо прикрепится к другому контрагенту

(2) Когда мы заполняем документы, например табель и нам нужно подставлять работников необходимо предварительно загрузить их. Пока данных не сильно много, это можно сделать за раз при первом открытии программы. Далее будем регулировать загружаемые данные по мере необходимости.

(3) Когда данные загружены, в конкретных документах надо фильтровать их, например, чтоб не приходилось выбирать из 100 человек, а из 10-20, по разным критериям. То же самое касается любой модели (которую приходится выбирать).

Модели

Заглянем в файлsrc/localization/ru.js, там компактно описаны все наши модели:

{
	// Организация и её настройки 
	companies: 'Компания',
	jurpersons: 'Юрлица',
	units: 'Филиалы',
	professions: 'Профессии',
	'work-params': 'Доп.параметры (должности)',
	'work-measures': 'Меры работы',
	'redemption-types': 'Типы выплат/удержаний',
	
    // Контрагенты и договоры
	'counterparty-companies': 'Контрагенты',
	'counterparty-jurpersons': 'Юрлица контрагентов',
	'counterparty-units': 'Точки контрагентов',
	contracts: 'Договоры',
	positions: 'Должности (по договору)',
	
    // Работники и события
	workers: 'Работники',
	redemptions: 'Выплаты/Удержания',
	attendances: 'Выходы (на работу)',
}

Видно, что почти все модели малочисленные (ограниченное, медленно растущее число записей). Их можно загружать при первом открытии программы и точечно обновлять при правках. Только последний блок (Работники и события) является "текучим, бесконечным", для него есть смысл создать динамическую загрузку - загружать порциями по разным сценариям (смотря какой документ открыт, какой период выставлен и т.д.).

Рабочие пространства

Запись данных происходит не в общей таблице модели, а в рабочем пространстве, где можно создавать, редактировать и выбирать много связанных моделей (с заранее проставленными данными).

Организация и настройки

Эти данные создаются, грубо говоря, 1 раз, при регистрации в системе, и почти не меняются.

Страница Контрагент

Содержит всю связанную с контрагентом информацию

  • юрлица
  • точки
  • договоры

Страница Должности по договору

Содержит все позиции (должности) со ставками. Открывается как вспомогательное окно из страницы Контрагента при нажатии на Договор.

Табель

Страница где по горизонтали выставляются работники, а по вертикали дни заданного периода. В заголовке выставляется контрагент или точка. Каждая ячейка, если заполнена, создаёт "Выход на работу" с заданным числом часов (или другой меры работы).

По удержаниям можно сделать подобный табель, либо в одном совмещать обе Модели.