Введение
В этом руководстве мы создадим приложение управления кадрами с помощью Refine Framework и развернем его на платформе DigitalOcean App Platform.
По завершении этого руководства у нас будет приложение управления кадрами, включающее:
- Страницу входа: Позволяет пользователям войти как менеджерам, так и сотрудникам. Менеджеры имеют доступ к страницам
Отгул
иЗапросы
, в то время как сотрудники имеют доступ только к страницеОтгул
. - Страницы отгула: Позволяет сотрудникам запрашивать, просматривать и отменять свой отгул. Также менеджеры могут назначать новые отгулы.
- Страница запросов: Доступна только менеджерам по кадрам для утверждения или отклонения запросов на отгул.
Примечание: Вы можете получить полный исходный код приложения, которое мы создадим в этом руководстве, из этого репозитория на GitHub
В процессе работы мы будем использовать:
- REST API: Для получения и обновления данных. Refine имеет встроенные пакеты поставщиков данных и REST API, но вы также можете создать свой собственный, чтобы соответствовать вашим конкретным требованиям. В этом руководстве мы собираемся использовать NestJs CRUD в качестве нашего бэкенд-сервиса и пакет @refinedev/nestjsx-crud в качестве поставщика данных.
- Material UI: Мы будем использовать его для компонентов пользовательского интерфейса и полностью настроим его согласно нашему дизайну. Refine имеет встроенную поддержку Material UI, но вы можете использовать любую библиотеку пользовательского интерфейса, которая вам нравится.
После создания приложения мы разместим его в Интернете, используя Платформу приложений DigitalOcean, которая позволяет легко настроить, запустить и развивать приложения и статические веб-сайты. Вы можете развернуть код, просто указав на репозиторий GitHub и позволив Платформе приложений выполнить основную работу по управлению инфраструктурой, временем выполнения приложения и зависимостями.
Предварительные требования
- Локальная среда разработки для Node.js. Вы можете следовать инструкции Как установить Node.js и создать локальную среду разработки.
- Некоторое предварительное знание React и TypeScript. Можно следовать сериям Как писать код в React.js и Использование TypeScript с React.
- Учетная запись GitHub
- Учетная запись DigitalOcean
Что такое Refine?
Refine – это открытый мета-фреймворк React для создания сложных веб-приложений B2B, в основном ориентированных на управление данными, такие как внутренние инструменты, панели администратора и панели управления. Он разработан путем предоставления набора хуков и компонентов для улучшения процесса разработки с более эффективным рабочим процессом для разработчика.
Он предоставляет полностью готовые к использованию функции для приложений уровня предприятия, чтобы упростить оплачиваемые задачи, такие как управление состоянием и данными, аутентификация и контроль доступа. Это позволяет разработчикам оставаться сосредоточенными на ядре своего приложения способом, который абстрагирован от многих избыточных деталей реализации.
Шаг 1 — Настройка проекта
Мы будем использовать команду npm create refine-app
для интерактивной инициализации проекта.
Выберите следующие опции при запросе:
После завершения установки, перейдите в папку проекта и запустите приложение с помощью:
Откройте http://localhost:5173
в вашем браузере, чтобы увидеть приложение.
Подготовка проекта
Теперь, когда у нас настроен проект, давайте внесем некоторые изменения в структуру проекта и удалим ненужные файлы.
Сначала установите сторонние зависимости:
@mui/x-date-pickers
,@mui/x-date-pickers-pro
: Это компоненты выбора даты для Material UI. Мы будем использовать их для выбора диапазона дат для запросов на отпуск.react-hot-toast
: Минималистическая библиотека тостов для React. Мы будем использовать ее для отображения сообщений об успешном выполнении и ошибок.react-infinite-scroll-component
: Компонент React для упрощения бесконечной прокрутки. Мы будем использовать его для загрузки дополнительных запросов на отпуск по мере прокрутки пользователем страницы для просмотра дополнительных запросов.dayjs
: Легкая библиотека дат для разбора, валидации, манипулирования и форматирования дат.vite-tsconfig-paths
: Плагин Vite, который позволяет использовать псевдонимы путей TypeScript в вашем проекте Vite.
После установки зависимостей обновите vite.config.ts
и tsconfig.json
, чтобы использовать плагин vite-tsconfig-paths
. Это позволит использовать псевдонимы путей TypeScript в проектах Vite, позволяя импортировать с псевдонимом @
.
Затем удалим ненужные файлы и папки:
src/contexts
: Эта папка содержит один файл, который называетсяColorModeContext
. Он отвечает за темный/светлый режим приложения. Мы не будем использовать его в этом руководстве.src/components
: Эта папка содержит компонент<Header />
. Мы будем использовать пользовательский компонент заголовка в этом руководстве.
После удаления файлов и папок, App.tsx
выдает ошибку, которую мы исправим на следующих шагах.
На протяжении руководства мы рассмотрим написание основных страниц и компонент. Итак, возьмем необходимые файлы и папки из репозитория GitHub. С этими файлами у нас будет базовая структура для нашего приложения управления кадрами.
- icons: Папка с иконками, содержащая все иконки приложения.
- types:
index.ts
: Типы приложения.
- утилиты:
constants.ts
: Константы приложения.axios.ts
: Экземпляр Axios для запросов к API, обработки токенов доступа, обновления токенов и ошибок.init-dayjs.ts
: Инициализирует Day.js с необходимыми плагинами.
- провайдеры:
access-control
: Управляет разрешениями пользователей с помощьюaccessControlProvider
; контролирует видимость страницыRequests
в зависимости от роли пользователя.auth-provider
: Управляет аутентификацией с помощьюauthProvider
; гарантирует защиту всех страниц и требует входа в систему.notification-provider
: Отображает сообщения об успехе и ошибках черезreact-hot-toast
.query-client
: Пользовательский клиент запросов для полного контроля и настройки.theme-provider
: Управляет темой Material UI.
- компоненты:
layout
: Компоненты макета.loading-overlay
: Показывает наложение загрузки во время получения данных.input
: Отображает поля ввода формы.frame
: Пользовательский компонент, добавляющий рамки, заголовки и иконки к разделам страницы.modal
: Пользовательский модальный диалоговый компонент.
После копирования файлов и папок структура файлов должна выглядеть следующим образом:
└── 📁src
└── 📁components
└── 📁frame
└── 📁input
└── 📁layout
└── 📁header
└── 📁page-header
└── 📁sider
└── 📁loading-overlay
└── 📁modal
└── 📁icons
└── 📁providers
└── 📁access-control
└── 📁auth-provider
└── 📁notification-provider
└── 📁query-client
└── 📁theme-provider
└── 📁types
└── 📁utilities
└── App.tsx
└── index.tsx
└── vite-env.d.ts
Затем обновите файл App.tsx
, чтобы включить необходимые провайдеры и компоненты.
Давайте разберем важные изменения, которые мы внесли в файл App.tsx
:
<Refine />
: Основной компонент из@refinedev/core
, который оборачивает всё приложение для предоставления извлечения данных, управления состоянием и других функций.<DevtoolsProvider />
и<DevtoolsPanel />
: Используется для отладки и разработки.<ThemeProvider />
: Применяет настраиваемую тему по всему приложению.- Инициализация Day.js: Для манипулирования датой и временем.
- ресурсы: Массив, указывающий сущности данных (
employee
иmanager
), которые Refine будет извлекать. Мы используем родительские и дочерние ресурсы для организации данных и управления разрешениями. У каждого ресурса естьscope
, определяющий роль пользователя, который контролирует доступ к различным частям приложения. - queryClient: Пользовательский клиент запросов для полного контроля и настройки извлечения данных.
- syncWithLocation: Позволяет синхронизировать состояние приложения (фильтры, сортировки, пагинация и т. д.) с URL.
- warnWhenUnsavedChanges: Показывает предупреждение, когда пользователь пытается покинуть страницу с несохраненными изменениями.
<Макет />
: Пользовательский компонент макета, который оборачивает содержимое приложения. Он содержит заголовок, боковую панель и основную область содержимого. Мы объясним этот компонент на следующих этапах.
Теперь мы готовы начать создание приложения по управлению персоналом.
Шаг 2 — Настройка и стилизация
Приглядитесь к поставщику-темы
. Мы сильно настроили тему Material UI, чтобы соответствовать дизайну приложения по управлению персоналом, создав две темы: одну для менеджеров и одну для сотрудников для их различия цветами.
Также мы добавили Inter в качестве пользовательского шрифта для приложения. Чтобы установить его, вам нужно добавить следующую строку в файл index.html
:
Проверка настраиваемого <Layout />
Компонента
На предыдущем этапе мы добавили настраиваемый компонент макета в приложение. Обычно мы могли бы использовать стандартный макет пользовательского интерфейса, но мы хотим показать, как можно осуществить настройку.
Компонент макета содержит заголовок, боковую панель и основную область контента. Он использует <ThemedLayoutV2 />
в качестве базы и настраивает его для соответствия дизайну приложения управления кадрами.
<Sider />
Боковая панель содержит логотип приложения и навигационные ссылки. На мобильных устройствах это раскрывающаяся боковая панель, которая открывается, когда пользователь нажимает на значок меню. Навигационные ссылки подготовлены с помощью хука useMenu
из Refine и рендерятся на основе роли пользователя с помощью компонента <CanAccess />
.
<UserSelect />
Размещенный на боковой панели, показывает аватар и имя вошедшего пользователя. При нажатии открывается всплывающее окно с данными пользователя и кнопкой выхода. Пользователи могут переключаться между различными ролями, выбирая из выпадающего списка. Этот компонент позволяет тестировать, переключаясь между пользователями с разными ролями.
<Header />
На настольных устройствах ничего не рендерится. На мобильных устройствах показывается логотип приложения и значок меню для открытия боковой панели. Шапка закреплена и всегда видна вверху страницы.
<PageHeader />
Это показывает заголовок страницы и кнопки навигации. Заголовок страницы автоматически генерируется с помощью хука useResource
, который извлекает имя ресурса из контекста Refine. Это позволяет нам использовать одинаковый стиль и макет во всем приложении.
Шаг 3 — Реализация аутентификации и авторизации
На этом этапе мы реализуем логику аутентификации и авторизации для нашего приложения по управлению HR. Это послужит отличным примером управления доступом в корпоративных приложениях.
Когда пользователи входят как менеджеры, они могут видеть страницы Отгул
и Запросы
. Если они входят как сотрудники, они могут видеть только страницу Отгул
. Менеджеры могут утверждать или отклонять запросы на отгул на странице Запросы
.
Сотрудники могут запрашивать отпуск и просматривать свою историю на странице Time Off
. Для реализации этого мы будем использовать функции authProvider
и accessControlProvider
Refine.
Authentication
В Refine аутентификация обрабатывается с помощью authProvider
. Он позволяет определить логику аутентификации для вашего приложения. На предыдущем шаге мы уже скопировали authProvider
из репозитория GitHub и передали его компоненту <Refine />
в качестве свойства. Мы будем использовать следующие хуки и компоненты для управления поведением нашего приложения в зависимости от того, вошел пользователь в систему или нет.
useLogin
: Хук, предоставляющий функциюmutate
для входа пользователя.useLogout
: Хук, предоставляющий функциюmutate
для выхода пользователя.useIsAuthenticated
: Хук, возвращающий логическое значение, указывающее, аутентифицирован ли пользователь.<Authenticated />
: Компонент, который рендерит свои дочерние элементы только в том случае, если пользователь аутентифицирован.
Authorization
В Refine авторизация обрабатывается с помощью accessControlProvider
. Он позволяет определять роли пользователей и разрешения, а также контролировать доступ к различным частям приложения на основе роли пользователя. На предыдущем шаге мы уже скопировали accessControlProvider
из репозитория GitHub и передали его компоненту <Refine />
как свойство. Давайте ближе рассмотрим accessControlProvider
, чтобы увидеть, как он работает.
В нашем приложении есть две роли: MANAGER
и EMPLOYEE
.
Менеджеры имеют доступ к странице Requests
, в то время как сотрудники имеют доступ только к странице Time Off
. Провайдер доступа accessControlProvider
проверяет роль пользователя и область ресурса, чтобы определить, может ли пользователь получить доступ к ресурсу. Если роль пользователя соответствует области ресурса, пользователь может получить доступ к ресурсу. В противном случае доступ будет запрещен. Мы будем использовать хук useCan
и компонент <CanAccess />
для управления поведением нашего приложения на основе роли пользователя.
Настройка страницы входа
На предыдущем этапе мы добавили authProvider
к компоненту <Refine />
. authProvider
отвечает за обработку аутентификации.
Сначала нам нужно получить изображения. Мы будем использовать эти изображения в качестве фоновых изображений для страницы входа. Создайте новую папку с именем images
в папке public
и получите изображения из репозитория GitHub.
После получения изображений давайте создадим новый файл с именем index.tsx
в папке src/pages/login
и добавим следующий код:
Для упрощения процесса аутентификации мы создали объект mockUsers
с двумя массивами: managers
и employees
. Каждый массив содержит заранее определенные объекты пользователей. Когда пользователь выбирает электронную почту из выпадающего списка и нажимает кнопку Sign in
, вызывается функция login
с выбранной электронной почтой. Функция login
является мутационной функцией, предоставляемой хуком useLogin
из библиотеки Refine. Она вызывает authProvider.login
с выбранной электронной почтой.
Далее давайте импортируем компонент <PageLogin />
и обновим файл App.tsx
с выделенными изменениями.
В обновленном файле App.tsx
мы добавили компонент <Authenticated />
из библиотеки Refine. Этот компонент используется для защиты маршрутов, требующих аутентификации. Он принимает свойство key
для уникальной идентификации компонента, свойство fallback
для отображения, когда пользователь не аутентифицирован, и свойство redirectOnFail
для перенаправления пользователя на указанный маршрут при неудачной аутентификации. Под капотом он вызывает метод authProvider.check
для проверки аутентификации пользователя.
Давайте ближе рассмотрим, что у нас есть на key="auth-pages"
Компонент <Authenticated />
оборачивает маршрут «/login» для проверки статуса аутентификации пользователя.
fallback={<Outlet />}
: Если пользователь не аутентифицирован, отображается вложенный маршрут (т.е. показывается компонент<PageLogin />
).- Дочерние элементы (
<Navigate to="/" />
): Если пользователь аутентифицирован, их перенаправляют на домашнюю страницу (/
).
Давайте ближе рассмотрим, что у нас есть на key="catch-all"
<Authenticated />
компонент оборачивает маршрут path="*"
для проверки статуса аутентификации пользователя. Этот маршрут является общим для всех, он отображает компонент <ErrorComponent />
, когда пользователь аутентифицирован. Это позволяет нам показать страницу 404, когда пользователь пытается получить доступ к несуществующему маршруту.
Теперь, когда вы запустите приложение и перейдете по ссылке http://localhost:5173/login
, вы должны увидеть страницу входа с выпадающим списком для выбора пользователя.
Прямо сейчас страница «/» ничего не делает. В следующих шагах мы реализуем страницы Time Off
и Requests
.
Шаг 4 — Создание страницы Отпусков
Построение страницы списка отпусков
На этом этапе мы построим страницу Отпуска
. Сотрудники могут запрашивать отпуск и просматривать свою историю отпусков. Менеджеры также могут просматривать свою историю, но вместо запроса отпуска они могут назначить его себе напрямую. Мы сделаем это, используя accessControlProvider
, компонент <CanAccess />
и хук useCan
от Refine.

Прежде чем мы начнем создавать страницу отпусков, нам нужно создать несколько компонентов для отображения истории отпусков, предстоящих запросов на отпуск и статистики использованных отпусков. В конце этого этапа мы будем использовать эти компоненты для создания страницы отпусков.
Построение компонента <TimeOffList />
для отображения истории отпусков
Создайте новую папку под названием time-offs
в папке src/components
. Внутри папки time-offs
создайте новый файл под названием list.tsx
и добавьте следующий код:
Файл list.tsx
довольно объемный, но большая часть занимается стилизацией и представлением пользовательского интерфейса.

Мы будем использовать компонент <TimeOffList />
в трех различных контекстах:
Свойство type
определяет, какой вид списка отсутствия показывать:
inReview
: Показывает запросы на отсутствие, находящиеся на рассмотрении.upcoming
: Отображает предстоящие одобренные, но еще не наступившие отсутствия.history
: Список одобренных и уже произошедших отсутствий.
Внутри компонента мы создадим фильтры и сортировщики на основе свойства type
. Мы будем использовать эти фильтры и сортировщики для получения данных об отсутствии из API.
Давайте разберем ключевые части компонента:
1. Получение текущего пользователя
useGetIdentity<Employee>()
: Получает информацию о текущем пользователе.- Мы используем идентификатор сотрудника для фильтрации отсутствий, чтобы каждый пользователь видел только свои запросы.
2. Получение данных об отсутствии с бесконечным скроллингом
-
useInfiniteList<TimeOff>()
: Получает данные об отпусках с бесконечной прокруткой.resource
: Указывает конечную точку API.sorters
иfilters
: Настроены в соответствии сtype
для получения правильных данных.- Фильтр
employeeId
: Гарантирует получение только отпусков текущего пользователя. queryOptions.enabled
: Запускает запрос только когда данные о сотруднике доступны.
<InfiniteScroll />
: Позволяет загружать больше данных по мере прокрутки пользователем вниз.next
: Функция для загрузки следующей страницы данных.hasMore
: Указывает, доступны ли дополнительные данные.
3. Отмена запроса на отпуск
useDelete
: Предоставляет функциюtimeOffCancel
для удаления запроса на отпуск.- Используется, когда пользователь отменяет свой отпуск.
- Отображает сообщение об успешном завершении.
4. Отображение дат с <DateField />
<DateField />
: Форматирует и отображает даты удобным для пользователя способом.value
: Дата для отображения.format
: Указывает формат даты (например, “Январь 05”).
5. Создание фильтров и сортировщиков на основе type
Фильтры:
- Определяет критерии для получения временных отпусков на основе статуса и дат.
history
: Получает утвержденные временные отпуска, которые уже закончились.upcoming
: Получает утвержденные временные отпуска, которые предстоят.
Сортировщики:
- Определяет порядок полученных данных.
history
: Сортирует по дате начала в порядке убывания.
Построение компонента <TimeOffLeaveCards />
для отображения статистики использованных временных отпусков
Создайте новый файл с именем leave-cards.tsx
в папке src/components/time-offs
и добавьте следующий код:

Компонент <TimeOffLeaveCards />
отображает статистику об отпуске сотрудника. Он показывает три карточки для Ежегодного Отпуска, Больничного Отпуска и Отпуска по болезни, указывая количество доступных или использованных дней.
Давайте разберем ключевые части компонента:
1. Получение данных
- Данные сотрудника: Использует
useGetIdentity
для получения информации о текущем сотруднике, такой как доступные дни ежегодного отпуска. - Статистика отпусков: Использует
useList
для получения общего количества использованных дней по болезни и отпуску по собственному усмотрению сотрудником. УстанавливаетpageSize
равным 1, потому что нам нужно только общее количество, а не все детали.
2. Отображение Карточек
- Компонент отображает три карточки, по одной для каждого типа отпуска.
- Каждая карточка показывает:
- Тип отпуска (например, Ежегодный Отпуск).
- Количество доступных или использованных дней.
- Иконка, представляющая тип отпуска.
3. Обработка состояний загрузки
- Если данные все еще загружаются, вместо фактических чисел показывается плейсхолдер-скелетон.
- Свойство
loading
передается в карточки для управления этим состоянием.
4. Компонент Card
- Принимает
type
,value
иloading
в качестве свойств. - Использует
variantMap
для получения правильных меток, цветов и иконок в зависимости от типа отпуска. - Отображает информацию об отпуске с соответствующим оформлением.
Построение <PageEmployeeTimeOffsList />
Теперь, когда у нас есть компоненты для отображения списков отпусков и отпускных карточек, давайте создадим новый файл в папке src/pages/employee/time-offs/
с именем list.tsx
и добавим следующий код:
<PageEmployeeTimeOffsList />
– основной компонент страницы отпусков, мы будем использовать этот компонент для отображения списков отпусков и отпускных карточек, когда пользователи перейдут на маршрут /employee/time-offs
.

Давайте разберем ключевые части компонента:
1. Проверка ролей пользователя
- Использует хук
useCan
для определения, является ли текущий пользователь менеджером. - Устанавливает
isManager
вtrue
, если у пользователя есть разрешения менеджера.
2. Применение темы в зависимости от роли
- Оборачивает содержимое в
<ThemeProvider />
. - Тема меняется в зависимости от того, является ли пользователь менеджером или сотрудником.
3. Шапка страницы с условной кнопкой
- Отображает
<PageHeader />
с заголовком “Отпуск”. - Включает
<CreateButton />
, который меняется в зависимости от роли пользователя:- Если пользователь является менеджером, кнопка говорит “Назначить отпуск”.
- Если пользователь не является менеджером, она говорит “Запросить отпуск”.
- Это обрабатывается с использованием компонента
<CanAccess />
, который проверяет разрешения.
4. Отображение статистики отпусков
- Включает компонент
<TimeOffLeaveCards />
для отображения балансов и использования отпусков. - Это предоставляет сводку ежегодного, болезненного и случайного отпуска.
5. Список запросов на отпуск
- Использует макет
<Grid />
для организации контента. - Слева (
md={6}
) отображается:TimeOffList
сtype="inReview"
: Показывает ожидающие запросы на отпуск.TimeOffList
сtype="upcoming"
: Показывает предстоящие утвержденные отпуска.
- Справа (
md={6}
) отображается:TimeOffList
сtype="history"
: Показывает прошедшие отпуска, которые уже произошли.
Добавление маршрута «/employee/time-offs»
Мы готовы отобразить компонент <PageEmployeeTimeOffsList />
на маршруте /employee/time-offs
. Давайте обновим файл App.tsx
, чтобы добавить этот маршрут:
Давайте разберем ключевые части обновленного файла App.tsx
:
1. Определение ресурса отпусков
Мы добавили новый ресурс для отпусков в качестве дочернего элемента ресурса employee
. Это указывает, что отпуска связаны с сотрудниками и доступны сотрудникам.
name: 'time-offs'
: Это идентификатор ресурса, используемый внутренне Refine.list: '/employee/time-offs'
: Указывает маршрут, который отображает список ресурса.мета
: Объект, содержащий дополнительные метаданные о ресурсе.parent: 'employee'
: Группирует этот ресурс в областиemployee
, который может использоваться для организации ресурсов в пользовательском интерфейсе (например, в боковом меню) или для контроля доступа.scope: Role.EMPLOYEE
: Указывает, что этот ресурс доступен пользователям с рольюEMPLOYEE
. Мы используем это вaccessControlProvider
для управления разрешениями.label: 'Time Off'
: Наименование ресурса в пользовательском интерфейсе.icon: <TimeOffIcon />
: АссоциируетTimeOffIcon
с этим ресурсом для визуальной идентификации.
2. Перенаправление на ресурс “отпуска” при переходе пользователей на маршрут /
Мы используем компонент <NavigateToResource />
для перенаправления пользователей на ресурс time-offs
, когда они переходят на маршрут /
. Это гарантирует, что пользователи увидят список отсутствий по умолчанию.
3. Перенаправление на ресурс «time-offs» при аутентификации пользователей
При аутентификации пользователей мы перенаправляем их на ресурс time-offs
. Если пользователь не аутентифицирован, он видит страницу входа.
4. Добавление маршрута /employee/time-offs
Мы организуем страницы сотрудников с помощью вложенных маршрутов. Сначала мы создаем основной маршрут с path='employee'
, который оборачивает контент в тематику и макет, специфичные для сотрудника. Внутри этого маршрута мы добавляем path='time-offs'
, который отображает компонент PageEmployeeTimeOffsList
. Эта структура группирует все функции сотрудника под одним путем и сохраняет стиль однородным.
После внесения этих изменений вы можете перейти на маршрут /employee/time-offs
, чтобы увидеть страницу со списком временных отсутствий в действии.

В настоящее время страница со списком временных отсутствий функциональна, но не имеет возможности создавать новые запросы на отсутствие. Давайте добавим возможность создания новых запросов на отсутствие.
Создание страницы создания отсутствия
Мы создадим новую страницу для запроса или назначения отпуска. На этой странице будет форма, в которой пользователи смогут указать тип отпуска, даты начала и окончания, а также любые дополнительные заметки.
Прежде чем начать, нам нужно создать новые компоненты для использования в форме:
Создание компонента <TimeOffFormSummary />
Создайте новый файл с именем form-summary.tsx
в папке src/components/time-offs/
и добавьте следующий код:

Компонент <TimeOffFormSummary />
отображает сводку запроса на отпуск. Он показывает доступные дни ежегодного отпуска, количество запрошенных дней и оставшиеся дни. Мы будем использовать этот компонент в форме отпуска, чтобы предоставить пользователям четкий обзор их запроса.
Создание компонента <PageEmployeeTimeOffsCreate />
Создайте новый файл с именем create.tsx
в папке src/pages/employee/time-offs/
и добавьте следующий код:

Компонент <PageEmployeeTimeOffsCreate />
отображает форму для создания новых запросов на отпуск в приложении управления HR. Используют его как сотрудники, так и менеджеры для запроса или назначения отпуска. В форме есть опции для выбора типа отпуска, указания дат начала и окончания, добавления заметок, а также отображается сводка запрошенного отпуска.
Давайте разберем ключевые части компонента:
1. Проверка роли пользователя
С помощью хука useCan
мы проверяем, имеет ли текущий пользователь разрешения менеджера. Это определяет, может ли пользователь назначать отпуск или только запрашивать его. Мы будем обрабатывать отправку формы по-разному в onFinishHandler
в зависимости от роли пользователя.
2. Состояние и отправка формы
useForm
инициализирует форму со значениями по умолчанию и устанавливает уведомления об успехе в зависимости от роли пользователя. Функция onFinishHandler
обрабатывает данные формы перед их отправкой. Для менеджеров статус сразу устанавливается на APPROVED
, в то время как запросы сотрудников отправляются на рассмотрение.
3. Стилизация
В нашем дизайне основной цвет меняется в зависимости от роли пользователя. Мы используем <ThemeProvider />
для применения соответствующей темы. Текст и иконка кнопки отправки также меняются в зависимости от того, является ли пользователь менеджером или сотрудником.
4. Добавление маршрута “/employee/time-offs/create”
Нам необходимо добавить новый маршрут для страницы создания отпуска. Давайте обновим файл App.tsx
, чтобы добавить этот маршрут:
После внесения этих изменений вы сможете перейти по маршруту /employee/time-offs/create
или нажать кнопку “Assign Time Off” на странице списка отпусков, чтобы перейти к форме создания отпуска.

Шаг 5 — Создание страницы управления запросами на отгулы
На этом этапе мы создадим новую страницу для управления запросами на отгулы. Эта страница позволит менеджерам просматривать и утверждать или отклонять запросы на отгулы, отправленные сотрудниками.

Создание страницы списка запросов на отгулы
Мы создадим новую страницу для управления запросами на отгулы. На этой странице будет отображаться список запросов на отгулы, показывая детали, такие как имя сотрудника, тип отгула, запрошенные даты и текущий статус.
Прежде чем мы начнем, нам нужно создать новые компоненты для использования в списке:
Создание компонента <RequestsList />
Создайте новый файл с именем list.tsx
в папке src/components/requests/
и добавьте следующий код:
Компонент <RequestsList />
отображает список запросов на отгулы с бесконечной прокруткой. Он включает индикатор загрузки, макеты-заглушки и сообщение, когда данных нет. Этот компонент спроектирован для эффективной работы с большими наборами данных и обеспечения плавного пользовательского опыта.
Построение компонента <RequestsListItem />
Создайте новый файл с именем list-item.tsx
в папке src/components/requests/
и добавьте следующий код:
Компонент <RequestsListItem />
отображает один запрос на отпуск в списке. Он включает аватар сотрудника, имя, описание и кнопку для просмотра деталей запроса. Этот компонент является многоразовым и может использоваться для отображения каждого элемента в списке запросов на отпуск.
Построение компонента <PageManagerRequestsList />
Создайте новый файл с именем list.tsx
в папке src/pages/manager/requests/
и добавьте следующий код:
Компонент <PageManagerRequestsList />
отображает ожидающие запросы на отпуск, которые менеджеры должны утвердить. Он показывает детали, такие как имя сотрудника, тип отпуска, запрошенные даты и сколько времени назад был сделан запрос. Менеджеры могут нажать на запрос, чтобы увидеть больше деталей. Он использует <RequestsList />
и <RequestsListItem />
для отображения списка.
Этот компонент также принимает children
как свойство. Далее, мы реализуем модальный маршрут, используя <Outlet />
для отображения деталей запроса, отображая маршрут /manager/requests/:id
внутри компонента.
Добавление маршрута “/manager/requests”
Нам нужно добавить новый маршрут для страницы управления запросами на отпуск. Давайте обновим файл App.tsx
, чтобы добавить этот маршрут:
После внесения этих изменений вы сможете перейти на маршрут /manager/requests
, чтобы увидеть страницу управления запросами на отпуск в действии

Создание страницы с подробностями запроса на отпуск
На этом этапе мы создадим новую страницу для отображения подробностей запроса на отпуск. На этой странице будут отображены имя сотрудника, тип отпуска, запрошенные даты и текущий статус. Менеджеры могут одобрить или отклонить запрос с этой страницы.
Создание компонента <TimeOffRequestModal />
Сначала создайте файл с именем use-get-employee-time-off-usage
в папке src/hooks/
и добавьте следующий код:
Мы будем использовать хук useGetEmployeeTimeOffUsage
для расчета общего количества дней, которые сотрудник взял для каждого типа отпуска. Эта информация будет отображена на странице с подробностями запроса на отпуск.
После этого создайте новый файл с именем time-off-request-modal.tsx
в папке src/components/requests/
и добавьте следующий код:
Давайте разберем компонент <TimeOffRequestModal />
:
1. Получение информации об использовании отпуска сотрудником
Хук useGetEmployeeTimeOffUsage
используется для получения информации об использовании отпуска сотрудником. Этот хук вычисляет оставшиеся дни ежегодного отпуска и ранее использованные дни по болезни и личным причинам на основе истории отпусков сотрудника.
2. Получение перекрывающихся утвержденных отпусков
Хук useList
с указанными фильтрами извлекает все утвержденные отпуска, перекрывающиеся с текущим запросом на отпуск. Этот список используется для отображения сотрудников, находящихся в отпуске между запрошенными датами.
3. Обработка утверждения/отклонения запроса на отпуск
Функция handleSubmit
вызывается, когда менеджер утверждает или отклоняет запрос на отпуск.
Refine автоматически инвалидирует кэш ресурса после мутации ресурса (time-offs
в данном случае). Поскольку использование отпуска сотрудника рассчитывается на основе истории отпусков, мы также инвалидируем кэш ресурса employees
, чтобы обновить использование отпуска сотрудника.
Добавление маршрута “/manager/requests/:id”
На этом этапе мы создадим новый маршрут для отображения страницы с подробностями запроса на отпуск, где менеджеры могут утвердить или отклонить запросы.
Давайте создадим новый файл с именем edit.tsx
в папке src/pages/manager/requests/time-offs/
и добавим следующий код:
Теперь нам нужно добавить новый маршрут для отображения страницы с подробностями запроса на отпуск. Давайте обновим файл App.tsx
, чтобы включить этот маршрут:
Давайте внимательно рассмотрим внесенные изменения:
Код выше настраивает вложенную структуру маршрутов, где модальное окно отображается при переходе к определенному дочернему маршруту. Компонент <PageManagerRequestsTimeOffsEdit />
является модальным окном и рендерится как дочерний элемент компонента <PageManagerRequestsList />
. Эта структура позволяет нам отображать модальное окно поверх страницы списка, сохраняя при этом видимость страницы списка на заднем плане.
Когда вы переходите к маршруту /manager/requests/:id/edit
или нажимаете на запрос на отпуск в списке, страница с подробностями запроса на отпуск будет отображаться как модальное окно поверх страницы списка.

Шаг 6 — Реализация авторизации и контроля доступа
Авторизация является критическим компонентом в корпоративных приложениях, играя ключевую роль как в безопасности, так и в операционной эффективности. Она гарантирует, что только авторизованные пользователи могут получить доступ к определенным ресурсам, обеспечивая защиту от чувствительных данных и функционалов. Система авторизации Refine предоставляет необходимую инфраструктуру для защиты ваших ресурсов и обеспечивает взаимодействие пользователей с вашим приложением в безопасном и контролируемом режиме. На этом этапе мы реализуем авторизацию и контроль доступа для управления запросами на отпуск. Мы ограничим доступ к маршрутам /manager/requests
и /manager/requests/:id/edit
только для менеджеров с помощью компонента <CanAccess />
.
В настоящее время, когда вы входите в систему как сотрудник, вы не видите ссылку на страницу Запросы
в боковой панели, но все равно можете получить доступ к маршруту /manager/requests
, введя URL в браузере. Мы добавим защиту, чтобы предотвратить несанкционированный доступ к этим маршрутам.
Давайте обновим файл App.tsx
, чтобы добавить проверку авторизации:
В приведенном выше коде мы добавили компонент <CanAccess />
к маршруту “/manager”. Этот компонент проверяет, есть ли у пользователя роль “менеджер” перед рендерингом дочерних маршрутов. Если у пользователя нет роли “менеджер”, его перенаправят на страницу списка отпусков для сотрудников.
Теперь, когда вы войдете как сотрудник и попытаетесь получить доступ к маршруту /manager/requests
, вы будете перенаправлены на страницу списка отсутствий для сотрудников.
Шаг 7 – Развертывание на платформе DigitalOcean App
На этом этапе мы развернем приложение на платформе DigitalOcean App. Для этого мы разместим исходный код на GitHub и подключим репозиторий GitHub к платформе приложений.
Отправка кода на GitHub
Войдите в свою учетную запись GitHub и создайте новый репозиторий с именем refine-hr
. Вы можете сделать репозиторий публичным или частным:
После создания репозитория перейдите в директорию проекта и выполните следующую команду для инициализации нового репозитория Git:
Затем добавьте все файлы в репозиторий Git этой командой:
Затем зафиксируйте файлы этой командой:
Затем добавьте репозиторий GitHub в качестве удаленного репозитория этой командой:
Затем укажите, что вы хотите отправить свой код в ветку main
этой командой:
Наконец, отправьте код в репозиторий GitHub с помощью этой команды:
Когда попросят, введите учетные данные GitHub, чтобы отправить свой код.
После того как код будет отправлен в репозиторий GitHub, вы получите сообщение об успешной операции.
В этом разделе вы загрузили свой проект на GitHub, чтобы иметь к нему доступ через приложения DigitalOcean. Следующим шагом будет создание нового приложения DigitalOcean с использованием вашего проекта и настройка автоматической развертки.
Развертывание на платформе DigitalOcean App Platform
На этом этапе вы возьмете приложение React и подготовите его к развертыванию через платформу DigitalOcean App Platform. Вы подключите свой репозиторий GitHub к DigitalOcean, настроите процесс сборки приложения, а затем создадите первое развертывание проекта. После развертывания проекта, все дальнейшие изменения будут автоматически пересобраны и обновлены.
По завершении этого шага ваше приложение будет развернуто на DigitalOcean с возможностью непрерывной доставки.
Войдите в свою учетную запись DigitalOcean и перейдите на страницу Apps. Нажмите кнопку Создать приложение:
Если вы не подключили свою учетную запись GitHub к DigitalOcean, вам будет предложено это сделать. Нажмите кнопку Подключить к GitHub. Откроется новое окно, запрашивающее разрешение на доступ DigitalOcean к вашей учетной записи GitHub.
После того как вы разрешите доступ DigitalOcean, вас перенаправит обратно на страницу приложений DigitalOcean. Следующим шагом будет выбор вашего репозитория GitHub. После выбора репозитория вас попросят выбрать ветку для развертывания. Выберите ветку main
и нажмите кнопку Далее.
После этого вы увидите этапы конфигурации вашего приложения. В этом руководстве вы можете нажать кнопку Далее, чтобы пропустить шаги конфигурации. Однако вы также можете настроить ваше приложение по вашему усмотрению.
Дождитесь завершения сборки. После завершения сборки нажмите Живое приложение, чтобы получить доступ к вашему проекту в браузере. Он будет таким же, как проект, который вы тестировали локально, но он будет доступен в сети с безопасным URL. Также вы можете следовать этому руководству, доступному на сайте сообщества DigitalOcean, чтобы узнать, как развертывать приложения на основе React на платформе App.
Примечание: В случае неудачного развертывания сборки вы можете настроить свою команду сборки на DigitalOcean, используя npm install --production=false && npm run build && npm prune --production
вместо npm run build
Заключение
В этом учебнике мы создали приложение управления персоналом с нуля, используя Refine, и познакомились с тем, как создать полностью функциональное приложение CRUD.
Также мы продемонстрируем, как развернуть ваше приложение на Платформе приложений DigitalOcean.
Если вы хотите узнать больше о Refine, вы можете посмотреть документацию, и если у вас есть какие-либо вопросы или отзывы, вы можете присоединиться к серверу Discord Refine.