bx-rest 0.23.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +578 -0
- package/README.md +110 -84
- package/esm2022/map/calendar/event.mjs +29 -15
- package/esm2022/map/calendar/section.mjs +13 -6
- package/esm2022/map/crm/calllist.mjs +16 -9
- package/esm2022/request-navvy/calendar/event.mjs +20 -8
- package/esm2022/request-navvy/calendar/section.mjs +10 -4
- package/esm2022/request-navvy/crm/calllist/index.mjs +9 -5
- package/esm2022/services/base.mjs +163 -6
- package/esm2022/typification/rest/calendar/event/get.mjs +1 -1
- package/fesm2022/bx-rest.mjs +253 -45
- package/fesm2022/bx-rest.mjs.map +1 -1
- package/map/calendar/event.d.ts +13 -3
- package/map/calendar/section.d.ts +9 -2
- package/map/crm/calllist.d.ts +11 -4
- package/package.json +6 -2
- package/request-navvy/calendar/event.d.ts +11 -5
- package/request-navvy/calendar/section.d.ts +8 -2
- package/request-navvy/crm/calllist/index.d.ts +6 -2
- package/services/base.d.ts +27 -3
- package/typification/rest/calendar/event/get.d.ts +2 -2
package/README.md
CHANGED
|
@@ -1,51 +1,54 @@
|
|
|
1
|
-
|
|
1
|
+
🇷🇺 **Русский** | 🇬🇧 [English](README.en.md)
|
|
2
|
+
|
|
3
|
+
# bx-rest — REST API клиент Bitrix24 для TypeScript, Angular, Vue и React
|
|
2
4
|
|
|
3
5
|
[](https://www.npmjs.com/package/bx-rest)
|
|
4
6
|
[](https://www.npmjs.com/package/bx-rest)
|
|
5
7
|
[](https://github.com/Aricatofuka/bx-rest/blob/main/LICENSE)
|
|
6
8
|
|
|
7
|
-
`bx-rest`
|
|
9
|
+
`bx-rest` — SDK на TypeScript для REST API Bitrix24. Помогает вызывать методы BX24 REST, работать с токенами авторизации, sessid, OAuth2, пагинацией, мапперами и типизированными API-запросами.
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
Также известен как: REST-клиент Bitrix24, BX24 REST SDK, API-клиент Bitrix24, Bitrix REST TypeScript библиотека.
|
|
10
12
|
|
|
11
|
-
##
|
|
13
|
+
## Содержание
|
|
12
14
|
|
|
13
|
-
- [
|
|
14
|
-
- [
|
|
15
|
-
- [
|
|
16
|
-
- [
|
|
17
|
-
- [
|
|
18
|
-
- [
|
|
19
|
-
- [
|
|
15
|
+
- [Установка](#установка)
|
|
16
|
+
- [Требования](#требования)
|
|
17
|
+
- [Быстрый старт](#быстрый-старт)
|
|
18
|
+
- [Режимы результата](#режимы-результата)
|
|
19
|
+
- [Аутентификация и OAuth2](#аутентификация-и-oauth2)
|
|
20
|
+
- [Обработка ошибок](#обработка-ошибок)
|
|
21
|
+
- [Использование в Angular](#использование-в-angular)
|
|
20
22
|
- [SessionKeyServices](#sessionkeyservices)
|
|
21
|
-
- [
|
|
22
|
-
- [
|
|
23
|
-
- [
|
|
23
|
+
- [Использование в Vue](#использование-в-vue)
|
|
24
|
+
- [Использование в React](#использование-в-react)
|
|
25
|
+
- [Кастомные REST-методы](#кастомные-rest-методы)
|
|
24
26
|
- [Mapper](#mapper)
|
|
25
|
-
- [
|
|
26
|
-
- [
|
|
27
|
-
- [
|
|
27
|
+
- [Кастомный метод с `simple()`](#кастомный-метод-с-simple)
|
|
28
|
+
- [Пагинированный кастомный метод с `pagNav()`](#пагинированный-кастомный-метод-с-pagnav)
|
|
29
|
+
- [Специфичные методы](#специфичные-методы)
|
|
28
30
|
- [`tasks.task.list`](#taskstasklist)
|
|
29
|
-
- [
|
|
30
|
-
- [
|
|
31
|
+
- [Парсинг дат](#парсинг-дат)
|
|
32
|
+
- [Планы на будущее](#планы-на-будущее)
|
|
33
|
+
- [Лицензия](#лицензия)
|
|
31
34
|
|
|
32
|
-
##
|
|
35
|
+
## Установка
|
|
33
36
|
|
|
34
37
|
```shell
|
|
35
38
|
npm install bx-rest
|
|
36
39
|
```
|
|
37
40
|
|
|
38
|
-
##
|
|
41
|
+
## Требования
|
|
39
42
|
|
|
40
|
-
-
|
|
41
|
-
- **TypeScript:**
|
|
42
|
-
- **RxJS:** `rxjs` (^7.8)
|
|
43
|
-
-
|
|
44
|
-
-
|
|
43
|
+
- **Формат модулей:** `bx-rest` поставляется только в виде ES-модулей — сборки CommonJS/`require` нет. Используйте его через ESM-совместимый бандлер (Angular CLI, Vite, webpack 5+, Next.js, ...) или нативный `import()`. Обычный `require('bx-rest')` (старые конфигурации Jest без поддержки ESM, `ts-node` в режиме CJS и т.п.) пакет не разрешит.
|
|
44
|
+
- **TypeScript:** разработан под TypeScript 5.5+. Рекомендуется режим `strict` — встроенная типизация опирается на него для точных типов полей.
|
|
45
|
+
- **RxJS:** `rxjs` (^7.8) — обычная зависимость, поставляемая вместе с пакетом, а не `peerDependency`, поэтому конкретная версия у хоста не требуется. Каждый REST-вызов возвращает RxJS `Observable`.
|
|
46
|
+
- **Фреймворки:** примеры для Angular, Vue и React ниже написаны под API Angular 18/19, Vue 3 и React 18+ (версии, на которых собирается и тестируется библиотека). Ни один из этих фреймворков не объявлен как `peerDependencies` — `bx-rest` не имеет жёсткой зависимости ни от одного из них, — но показанные паттерны DI/композиции рассчитаны именно на эти мажорные версии.
|
|
47
|
+
- **Окружение:** `bx-rest` ориентирован на браузер. Источники авторизации `cookies`/`localStorage`/`sessid` и `SessionKeyServices` напрямую читают `window`, `document` и `localStorage`. В приложении с серверным рендерингом (Angular Universal, Next.js и т.п.) выполняйте эти участки кода только в браузере (например, под защитой `isPlatformBrowser`/`typeof window !== 'undefined'`), либо используйте источник авторизации, не обращающийся к браузерным глобальным объектам, например `source: () => accessToken` или `source: 'off'`.
|
|
45
48
|
|
|
46
|
-
##
|
|
49
|
+
## Быстрый старт
|
|
47
50
|
|
|
48
|
-
|
|
51
|
+
Один раз настройте URL портала и источник access-токена, затем создайте клиент и подпишитесь на возвращённый RxJS `Observable`. Указывайте полный URL, включая `https://`.
|
|
49
52
|
|
|
50
53
|
```typescript
|
|
51
54
|
import { firstValueFrom } from 'rxjs'
|
|
@@ -78,41 +81,41 @@ const deals = await firstValueFrom(
|
|
|
78
81
|
console.log(deals)
|
|
79
82
|
```
|
|
80
83
|
|
|
81
|
-
|
|
84
|
+
Не хардкодьте и не коммитьте боевой access-токен. Передавайте его из потока авторизации вашего приложения, ответа сервера или защищённой конфигурации времени выполнения.
|
|
82
85
|
|
|
83
|
-
###
|
|
86
|
+
### Режимы результата
|
|
84
87
|
|
|
85
|
-
REST
|
|
88
|
+
REST-вызовы ленивые: запрос начинается, когда на возвращённый `Observable` подписываются или передают его в `firstValueFrom`.
|
|
86
89
|
|
|
87
|
-
|
|
|
90
|
+
| Метод | Результат |
|
|
88
91
|
| --- | --- |
|
|
89
|
-
| `.res(options?)` |
|
|
90
|
-
| `.resAll()` |
|
|
91
|
-
| `.resVanilla()` |
|
|
92
|
-
| `.mapForVanilla()` |
|
|
92
|
+
| `.res(options?)` | Разворачивает ответ Bitrix и применяет настроенный маппер. Для пагинированных методов возвращает текущую страницу. |
|
|
93
|
+
| `.resAll()` | Загружает и объединяет все страницы. Доступен для пагинированных Navvy-хелперов. |
|
|
94
|
+
| `.resVanilla()` | Возвращает сырой ответ Bitrix, включая такие поля, как `result`, `total` и `next`. |
|
|
95
|
+
| `.mapForVanilla()` | Сохраняет исходную обёртку ответа, но применяет маппер к её `result`. |
|
|
93
96
|
|
|
94
|
-
`.res()`
|
|
97
|
+
`.res()` принимает необязательный объект опций:
|
|
95
98
|
|
|
96
|
-
|
|
|
99
|
+
| Опция | По умолчанию | Эффект |
|
|
97
100
|
| --- | --- | --- |
|
|
98
|
-
| `throwOnApiError` | `false` |
|
|
101
|
+
| `throwOnApiError` | `false` | При `true` ошибка API-уровня Bitrix приводит к тому, что возвращённый `Observable` завершается ошибкой `BXRestApiError` вместо резолва в `undefined`. См. [Обработка ошибок](#обработка-ошибок). |
|
|
99
102
|
|
|
100
|
-
##
|
|
103
|
+
## Аутентификация и OAuth2
|
|
101
104
|
|
|
102
|
-
`auth.source`
|
|
105
|
+
`auth.source` определяет, откуда читаются учётные данные. `auth.key` определяет имя параметра запроса, за исключением специального режима учётных данных через куки `OAuth2`.
|
|
103
106
|
|
|
104
|
-
|
|
|
107
|
+
| Сценарий | `auth.source` | `auth.key` | Поведение |
|
|
105
108
|
| --- | --- | --- | --- |
|
|
106
|
-
| Access
|
|
107
|
-
| Access
|
|
108
|
-
| Access
|
|
109
|
-
|
|
|
110
|
-
|
|
|
111
|
-
|
|
|
109
|
+
| Access-токен из состояния приложения | `() => accessToken` | `auth` | Вызывает функцию перед каждым запросом и отправляет её значение в параметре `auth`. Рекомендуется для OAuth2 access-токенов, которыми управляет приложение. |
|
|
110
|
+
| Access-токен в local storage | `localStorage` | `auth` | Читает `localStorage["auth"]` и отправляет его как `auth`. |
|
|
111
|
+
| Access-токен в куке | `cookies` | `auth` | Читает куку `auth` и отправляет её как `auth`. |
|
|
112
|
+
| Встроенная страница Bitrix / локальная сессия | `cookies` | `sessid` | Пробует `window.BX.bitrix_sessid()`, query-параметр `sessid`, `localStorage.sessid`, затем куку `auth`. Отправляет полученное значение как `sessid`. |
|
|
113
|
+
| Входящий вебхук или URL, уже содержащий авторизацию | `off` | Любое значение | Пропускает поиск учётных данных и не добавляет параметр авторизации. |
|
|
114
|
+
| Запрос учётных данных через куки | Любой источник, возвращающий непустое значение | `OAuth2` | Не добавляет полученное значение в параметры запроса и включает `withCredentials` в Axios. Используйте только если портал и политика CORS поддерживают куки с учётными данными. |
|
|
112
115
|
|
|
113
|
-
|
|
116
|
+
Для обычного OAuth2 `access_token` Bitrix используйте `auth.key: 'auth'` и передавайте текущий токен через функцию или `localStorage`. Специальный режим `auth.key: 'OAuth2'` предназначен для куки с учётными данными; сам по себе он не отправляет OAuth access-токен.
|
|
114
117
|
|
|
115
|
-
|
|
118
|
+
Для URL входящего вебхука сохраните полный путь вебхука в `urls.key`, установите `additional_part` в пустую строку и отключите дополнительную авторизацию:
|
|
116
119
|
|
|
117
120
|
```typescript
|
|
118
121
|
BXRestSettings.update({
|
|
@@ -128,18 +131,18 @@ BXRestSettings.update({
|
|
|
128
131
|
})
|
|
129
132
|
```
|
|
130
133
|
|
|
131
|
-
##
|
|
134
|
+
## Обработка ошибок
|
|
132
135
|
|
|
133
|
-
`bx-rest`
|
|
136
|
+
`bx-rest` показывает два разных вида сбоев, и `.res()` реагирует только на один из них.
|
|
134
137
|
|
|
135
|
-
|
|
|
138
|
+
| Сбой | Когда происходит | Как проявляется в `.res()` |
|
|
136
139
|
| --- | --- | --- |
|
|
137
|
-
|
|
|
138
|
-
|
|
|
140
|
+
| Ошибки транспорта / конфигурации — сбой сети, отсутствие авторизации, отсутствие базового URL | До или во время HTTP-вызова | Возвращённый `Observable` завершается ошибкой. Обрабатывайте её через RxJS `catchError` или колбэк `error` у `subscribe()`. |
|
|
141
|
+
| Ошибки API Bitrix — `{ error, error_description }`, например `INSUFFICIENT_SCOPE`, `expired_token` | HTTP-ответ 200, тело которого не является успешным payload'ом | По умолчанию `.res()` резолвится обычным образом со значением `undefined` — **исключение не выбрасывается**. Передайте `{ throwOnApiError: true }`, чтобы вместо этого выбрасывалось `BXRestApiError`. |
|
|
139
142
|
|
|
140
|
-
|
|
143
|
+
Поскольку ошибка уровня Bitrix по умолчанию резолвится как `undefined`, а не как ошибка `Observable`, не полагайтесь только на голый `.res()`, чтобы отличить «нет записей» от «запрос не удался». Есть два варианта.
|
|
141
144
|
|
|
142
|
-
|
|
145
|
+
**Вариант 1 — включить выброс исключения через `.res({ throwOnApiError: true })`.** `Observable` завершается ошибкой `BXRestApiError`, предоставляющей `error` и `error_description`, поэтому её можно обработать вместе с транспортными ошибками в одном колбэке `catchError`/`error`:
|
|
143
146
|
|
|
144
147
|
```typescript
|
|
145
148
|
import { BXRestNavvy, BXRestApiError } from 'bx-rest'
|
|
@@ -162,7 +165,7 @@ bxRest.crm.deal.list({
|
|
|
162
165
|
})
|
|
163
166
|
```
|
|
164
167
|
|
|
165
|
-
|
|
168
|
+
**Вариант 2 — оставить поведение по умолчанию и проверять сырой ответ.** Вызовите `.resVanilla()` и проверьте ответ с помощью экспортируемого type guard `isBXRestAnswerSuccess()`:
|
|
166
169
|
|
|
167
170
|
```typescript
|
|
168
171
|
import { firstValueFrom } from 'rxjs'
|
|
@@ -185,7 +188,7 @@ if (!answer || !isBXRestAnswerSuccess(answer)) {
|
|
|
185
188
|
}
|
|
186
189
|
```
|
|
187
190
|
|
|
188
|
-
|
|
191
|
+
Независимо от `throwOnApiError`, ошибки транспортного уровня всегда всплывают как ошибки `Observable` и могут быть перехвачены обычным способом RxJS:
|
|
189
192
|
|
|
190
193
|
```typescript
|
|
191
194
|
bxRest.crm.deal.list({
|
|
@@ -198,9 +201,9 @@ bxRest.crm.deal.list({
|
|
|
198
201
|
})
|
|
199
202
|
```
|
|
200
203
|
|
|
201
|
-
##
|
|
204
|
+
## Использование в Angular
|
|
202
205
|
|
|
203
|
-
|
|
206
|
+
Зарегистрируйте публичные клиенты и `Navvy`, когда нужно внедрять их в сервисы или компоненты Angular:
|
|
204
207
|
|
|
205
208
|
```typescript
|
|
206
209
|
import { ApplicationConfig, Provider } from '@angular/core'
|
|
@@ -241,7 +244,7 @@ export const appConfig: ApplicationConfig = {
|
|
|
241
244
|
}
|
|
242
245
|
```
|
|
243
246
|
|
|
244
|
-
|
|
247
|
+
Пример компонента:
|
|
245
248
|
|
|
246
249
|
```typescript
|
|
247
250
|
import { Component, inject } from '@angular/core'
|
|
@@ -266,7 +269,7 @@ export class ListComponent {
|
|
|
266
269
|
|
|
267
270
|
## SessionKeyServices
|
|
268
271
|
|
|
269
|
-
`SessionKeyServices`
|
|
272
|
+
`SessionKeyServices` доступен из публичного API и может использоваться, когда нужно проверить текущие данные авторизации перед выполнением REST-запросов.
|
|
270
273
|
|
|
271
274
|
```typescript
|
|
272
275
|
import { BXRestSettings, SessionKeyServices, SessionKeyError } from 'bx-rest'
|
|
@@ -305,7 +308,7 @@ session.getBaseUrl().subscribe((baseUrl) => {
|
|
|
305
308
|
})
|
|
306
309
|
```
|
|
307
310
|
|
|
308
|
-
##
|
|
311
|
+
## Использование в Vue
|
|
309
312
|
|
|
310
313
|
```typescript
|
|
311
314
|
import type { Plugin } from 'vue'
|
|
@@ -348,9 +351,9 @@ app.use(bxRestPlugin)
|
|
|
348
351
|
app.mount('#app')
|
|
349
352
|
```
|
|
350
353
|
|
|
351
|
-
##
|
|
354
|
+
## Использование в React
|
|
352
355
|
|
|
353
|
-
|
|
356
|
+
Создавайте клиент вне компонента и отписывайтесь при размонтировании компонента:
|
|
354
357
|
|
|
355
358
|
```tsx
|
|
356
359
|
import { useEffect, useState } from 'react'
|
|
@@ -378,15 +381,15 @@ export function Deals() {
|
|
|
378
381
|
}
|
|
379
382
|
```
|
|
380
383
|
|
|
381
|
-
##
|
|
384
|
+
## Кастомные REST-методы
|
|
382
385
|
|
|
383
|
-
`Navvy`
|
|
386
|
+
`Navvy` экспортируется из `bx-rest`. В Angular зарегистрируйте показанный выше `NavvyProvider` и внедрите `Navvy` в ваш кастомный API-сервис. URL метода представлен массивом и перед отправкой запроса соединяется точками.
|
|
384
387
|
|
|
385
|
-
|
|
388
|
+
Для регистрации кастомных REST-методов см. [документацию Bitrix24](https://dev.1c-bitrix.ru/learning/course/index.php?COURSE_ID=99&LESSON_ID=7985).
|
|
386
389
|
|
|
387
390
|
### Mapper
|
|
388
391
|
|
|
389
|
-
|
|
392
|
+
Маппер — это обычная функция. Ей не нужно наследоваться от `BXRestMap`.
|
|
390
393
|
|
|
391
394
|
```typescript
|
|
392
395
|
import {
|
|
@@ -406,9 +409,9 @@ export class BXCustomBlogMap {
|
|
|
406
409
|
}
|
|
407
410
|
```
|
|
408
411
|
|
|
409
|
-
###
|
|
412
|
+
### Кастомный метод с `simple()`
|
|
410
413
|
|
|
411
|
-
|
|
414
|
+
Используйте `simple()`, когда метод возвращает один ответ без автоматической пагинации:
|
|
412
415
|
|
|
413
416
|
```typescript
|
|
414
417
|
import { inject, Injectable } from '@angular/core'
|
|
@@ -444,11 +447,11 @@ export class BXRestNavvyCustomApiBlog {
|
|
|
444
447
|
}
|
|
445
448
|
```
|
|
446
449
|
|
|
447
|
-
|
|
450
|
+
Возвращённый хелпер поддерживает `.res()`, `.resVanilla()` и `.mapForVanilla()`.
|
|
448
451
|
|
|
449
|
-
###
|
|
452
|
+
### Пагинированный кастомный метод с `pagNav()`
|
|
450
453
|
|
|
451
|
-
|
|
454
|
+
Используйте `pagNav()`, когда ответ Bitrix содержит массив и стандартные поля пагинации `start`, `next` и `total`. Тип параметра должен поддерживать `start?: number`.
|
|
452
455
|
|
|
453
456
|
```typescript
|
|
454
457
|
import { inject, Injectable } from '@angular/core'
|
|
@@ -488,13 +491,13 @@ export class BXRestNavvyCustomApiBlogList {
|
|
|
488
491
|
}
|
|
489
492
|
```
|
|
490
493
|
|
|
491
|
-
|
|
494
|
+
Возвращённый хелпер дополнительно поддерживает `.resAll()` для загрузки и объединения всех страниц.
|
|
492
495
|
|
|
493
|
-
##
|
|
496
|
+
## Специфичные методы
|
|
494
497
|
|
|
495
498
|
### `tasks.task.list`
|
|
496
499
|
|
|
497
|
-
|
|
500
|
+
Первый generic-аргумент выбирает встроенные поля задачи. Второй добавляет пользовательские поля, специфичные для проекта:
|
|
498
501
|
|
|
499
502
|
```typescript
|
|
500
503
|
import { BXRestNavvy } from 'bx-rest'
|
|
@@ -541,12 +544,35 @@ const tasks$ = bxRest.tasks.task.list<
|
|
|
541
544
|
}).res()
|
|
542
545
|
```
|
|
543
546
|
|
|
544
|
-
##
|
|
545
|
-
|
|
546
|
-
-
|
|
547
|
+
## Парсинг дат
|
|
548
|
+
|
|
549
|
+
Некоторые REST-поля Bitrix24 (в частности `calendar.section.get`, `calendar.event.get` и `crm.calllist.*`) возвращают даты в виде обычных строк, отформатированных согласно собственным настройкам даты/времени портала (Настройки → формат даты и времени), а не в фиксированном формате ISO. Поскольку этот формат — настройка конкретного портала, `bx-rest` не может знать его заранее, поэтому `BXBaseServices.toDate()` (используется этими мапперами внутренне) разрешает неоднозначную строку в три шага, по порядку:
|
|
550
|
+
|
|
551
|
+
1. **Формат, который вы указали.** Если вы (или маппер) передаёте явный `format` (например, `'dd.MM.yyyy HH:mm:ss'`), он проверяется первым, токен за токеном (`yyyy`, `MM`, `dd`, `HH`, `mm`, `ss` и их однобуквенные варианты) с буквальными разделителями из строки формата.
|
|
552
|
+
2. **Небольшой список известных форматов Bitrix24** (`'dd.MM.yyyy HH:mm:ss'`, `'yyyy-MM-dd HH:mm:ss'`, `'dd.MM.yyyy'`, `'yyyy-MM-dd'`) — проверяется, если шаг 1 не подошёл, поскольку разные порталы обычно присылают один из этих форматов.
|
|
553
|
+
3. **Позиционная эвристика** как последний вариант — она находит год по его однозначной 4-значной длине (независимо от того, на каком конце даты он стоит), считает средний сегмент месяцем (это верно и для ISO, и для европейского формата даты) и распознаёт любой разделитель (`.`, `-`, `/`, пробел...). Она **не** пытается угадать в единственном действительно неоднозначном случае — чисто числовой порядок `MM/dd` против `dd/MM`, когда оба сегмента ≤ 12, — и проверяет диапазоны значений (месяц 1-12, день 1-31, час/минута/секунда), а не позволяет `Date` молча перевести некорректное значение на следующий месяц/год.
|
|
554
|
+
|
|
555
|
+
Если вы точно знаете формат вашего портала, передавайте его явно вместо того, чтобы полагаться на автоопределение — он всегда проверяется первым и полностью пропускает шаги 2-3. Мапперы календаря и списка звонков принимают его как единственный необязательный завершающий аргумент `dateTimeFormat`, и он также передаётся через соответствующие методы `BXRestNavvy`. Там, где у маппера есть ещё и поля только с датой (`EXDATE`/`RRULE.UNTIL` у `calendar.event`), их формат выводится из `dateTimeFormat` отбрасыванием `HH:mm:ss` — порядок день/месяц/год всегда одинаков для обоих на конкретном портале, поэтому передавать дополнительно нечего:
|
|
556
|
+
|
|
557
|
+
```typescript
|
|
558
|
+
import { BXRestNavvy } from 'bx-rest'
|
|
559
|
+
|
|
560
|
+
const bxRest = new BXRestNavvy()
|
|
561
|
+
|
|
562
|
+
// Формат даты/времени конкретного портала, например из Настройки → формат даты и времени.
|
|
563
|
+
const dateTimeFormat = 'yyyy-MM-dd HH:mm:ss'
|
|
564
|
+
|
|
565
|
+
bxRest.calendar.event.get({ FROM: '01.01.2026', TO: '31.01.2026' }, dateTimeFormat).res()
|
|
566
|
+
bxRest.calendar.section.get({}, dateTimeFormat).res()
|
|
567
|
+
bxRest.crm.callList.get({ ID: 1 }, dateTimeFormat).res()
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
## Планы на будущее
|
|
571
|
+
- Автоматическое получение токена
|
|
572
|
+
- Мапперы для типов нормализации
|
|
547
573
|
|
|
548
|
-
|
|
574
|
+
Есть предложение по функциональности или нашли баг? Посмотрите [существующие issues](https://github.com/Aricatofuka/bx-rest/issues) или создайте новый.
|
|
549
575
|
|
|
550
|
-
##
|
|
576
|
+
## Лицензия
|
|
551
577
|
|
|
552
|
-
[MIT](https://github.com/Aricatofuka/bx-rest/blob/main/LICENSE) © Aricatofuka
|
|
578
|
+
[MIT](https://github.com/Aricatofuka/bx-rest/blob/main/LICENSE) © Aricatofuka
|
|
@@ -1,12 +1,23 @@
|
|
|
1
|
-
import { toDate, toNum } from '../../services/base';
|
|
1
|
+
import { deriveDateOnlyFormat, toDate, toNum } from '../../services/base';
|
|
2
2
|
export class BXRestMapCalendarEvent {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* @param item
|
|
5
|
+
* @param dateTimeFormat Формат полей с датой и временем (`DATE_CREATE`, `DATE_FROM`, `DATE_TO`, `TIMESTAMP_X`
|
|
6
|
+
* и т.д.). По умолчанию — распространённый на многих порталах `'dd.MM.yyyy HH:mm:ss'`, но реальный формат
|
|
7
|
+
* зависит от настроек портала (Настройки → формат даты и времени) — если он известен, передавайте его явно.
|
|
8
|
+
* Формат для полей только с датой (`EXDATE`, `RRULE.UNTIL`) выводится из этого же значения
|
|
9
|
+
* (отбрасыванием `HH:mm:ss`) — передавать его отдельно не нужно.
|
|
10
|
+
*/
|
|
11
|
+
static getById(item, dateTimeFormat = 'dd.MM.yyyy HH:mm:ss') {
|
|
12
|
+
return (item) ? BXRestMapCalendarEvent.CalendarEventGetAnswerHttpToCalendarEventGetAnswer(item, dateTimeFormat) : undefined;
|
|
5
13
|
}
|
|
6
|
-
|
|
7
|
-
|
|
14
|
+
/** @see getById */
|
|
15
|
+
static get(item, dateTimeFormat = 'dd.MM.yyyy HH:mm:ss') {
|
|
16
|
+
return (item) ? item.map(i => BXRestMapCalendarEvent.CalendarEventGetAnswerHttpToCalendarEventGetAnswer(i, dateTimeFormat)) : undefined;
|
|
8
17
|
}
|
|
9
|
-
|
|
18
|
+
/** @see getById */
|
|
19
|
+
static CalendarEventGetAnswerHttpToCalendarEventGetAnswer(item, dateTimeFormat = 'dd.MM.yyyy HH:mm:ss') {
|
|
20
|
+
const dateFormat = deriveDateOnlyFormat(dateTimeFormat);
|
|
10
21
|
return {
|
|
11
22
|
...item,
|
|
12
23
|
ID: toNum(item.ID),
|
|
@@ -19,24 +30,27 @@ export class BXRestMapCalendarEvent {
|
|
|
19
30
|
TZ_OFFSET_FROM: toNum(item.TZ_OFFSET_FROM),
|
|
20
31
|
TZ_OFFSET_TO: toNum(item.TZ_OFFSET_TO),
|
|
21
32
|
VERSION: toNum(item.VERSION),
|
|
22
|
-
DATE_CREATE: toDate(item.DATE_CREATE,
|
|
23
|
-
DATE_FROM: toDate(item.DATE_FROM,
|
|
33
|
+
DATE_CREATE: toDate(item.DATE_CREATE, dateTimeFormat),
|
|
34
|
+
DATE_FROM: toDate(item.DATE_FROM, dateTimeFormat),
|
|
24
35
|
ORIGINAL_DATE_FROM: (item.ORIGINAL_DATE_FROM)
|
|
25
|
-
? toDate(item.ORIGINAL_DATE_FROM,
|
|
36
|
+
? toDate(item.ORIGINAL_DATE_FROM, dateTimeFormat)
|
|
26
37
|
: null,
|
|
27
|
-
DATE_TO: toDate(item.DATE_TO,
|
|
28
|
-
TIMESTAMP_X: toDate(item.TIMESTAMP_X,
|
|
38
|
+
DATE_TO: toDate(item.DATE_TO, dateTimeFormat),
|
|
39
|
+
TIMESTAMP_X: toDate(item.TIMESTAMP_X, dateTimeFormat),
|
|
29
40
|
DATE_FROM_TS_UTC: toNum(item.DATE_FROM_TS_UTC),
|
|
30
41
|
DATE_TO_TS_UTC: toNum(item.DATE_TO_TS_UTC),
|
|
31
42
|
DELETED: item.DELETED === 'Y',
|
|
32
43
|
DT_LENGTH: toNum(item.DT_LENGTH),
|
|
33
44
|
DT_SKIP_TIME: item.DT_SKIP_TIME === 'Y',
|
|
34
45
|
MEETING_STATUS: item.MEETING_STATUS === 'Y',
|
|
35
|
-
EXDATE
|
|
46
|
+
// EXDATE и RRULE.UNTIL/'~UNTIL' у Bitrix нередко приходят пустой строкой (нет исключённых
|
|
47
|
+
// дат повторения / правило повторения ограничено через COUNT, а не датой) — пустую строку
|
|
48
|
+
// toDate() распарсить не может ни при каком формате, поэтому такие поля пропускаем до вызова
|
|
49
|
+
EXDATE: item.EXDATE ? item.EXDATE.split(';').filter(Boolean).map(dateStr => toDate(dateStr, dateFormat)) : [],
|
|
36
50
|
RRULE: (item.RRULE && typeof item.RRULE !== 'string') ? {
|
|
37
51
|
...item.RRULE,
|
|
38
|
-
UNTIL: toDate(item.RRULE.UNTIL,
|
|
39
|
-
'~UNTIL': toDate(item.RRULE['~UNTIL'],
|
|
52
|
+
UNTIL: item.RRULE.UNTIL ? toDate(item.RRULE.UNTIL, dateFormat) : null,
|
|
53
|
+
'~UNTIL': item.RRULE['~UNTIL'] ? toDate(item.RRULE['~UNTIL'], dateFormat) : null
|
|
40
54
|
} : null,
|
|
41
55
|
ATTENDEE_LIST: (item.ATTENDEE_LIST) ? item.ATTENDEE_LIST.map(i => {
|
|
42
56
|
return { id: i.id, entryId: toNum(i.entryId), status: i.status };
|
|
@@ -44,4 +58,4 @@ export class BXRestMapCalendarEvent {
|
|
|
44
58
|
};
|
|
45
59
|
}
|
|
46
60
|
}
|
|
47
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
61
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXZlbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9ieC1yZXN0L3NyYy9tYXAvY2FsZW5kYXIvZXZlbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQTtBQU16RSxNQUFNLE9BQU8sc0JBQXNCO0lBRWpDOzs7Ozs7O09BT0c7SUFDSCxNQUFNLENBQUMsT0FBTyxDQUNaLElBQTBELEVBQzFELGNBQWMsR0FBRyxxQkFBcUI7UUFFdEMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxzQkFBc0IsQ0FBQyxrREFBa0QsQ0FBQyxJQUFJLEVBQUUsY0FBYyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQTtJQUM3SCxDQUFDO0lBRUQsbUJBQW1CO0lBQ25CLE1BQU0sQ0FBQyxHQUFHLENBQ1IsSUFBcUQsRUFDckQsY0FBYyxHQUFHLHFCQUFxQjtRQUV0QyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxzQkFBc0IsQ0FBQyxrREFBa0QsQ0FBQyxDQUFDLEVBQUUsY0FBYyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFBO0lBQ3pJLENBQUM7SUFFRCxtQkFBbUI7SUFDbkIsTUFBTSxDQUFDLGtEQUFrRCxDQUN2RCxJQUF1QyxFQUN2QyxjQUFjLEdBQUcscUJBQXFCO1FBRXRDLE1BQU0sVUFBVSxHQUFHLG9CQUFvQixDQUFDLGNBQWMsQ0FBQyxDQUFBO1FBRXZELE9BQU87WUFDTCxHQUFHLElBQUk7WUFDUCxFQUFFLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDbEIsWUFBWSxFQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDO1lBQ3RDLFFBQVEs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Q0FBQyxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFDLENBQUE7WUFDaEUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUU7U0FDUixDQUFBO0lBQ0gsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZGVyaXZlRGF0ZU9ubHlGb3JtYXQsIHRvRGF0ZSwgdG9OdW0gfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9iYXNlJ1xyXG5pbXBvcnQge1xyXG4gIGlCWFJlc3RDYWxlbmRhckV2ZW50R2V0QW5zd2VyLFxyXG4gIGlCWFJlc3RDYWxlbmRhckV2ZW50R2V0QW5zd2VySHR0cFxyXG59IGZyb20gJy4uLy4uL3R5cGlmaWNhdGlvbi9yZXN0L2NhbGVuZGFyL2V2ZW50L2dldCdcclxuXHJcbmV4cG9ydCBjbGFzcyBCWFJlc3RNYXBDYWxlbmRhckV2ZW50IHtcclxuXHJcbiAgLyoqXHJcbiAgICogQHBhcmFtIGl0ZW1cclxuICAgKiBAcGFyYW0gZGF0ZVRpbWVGb3JtYXQg0KTQvtGA0LzQsNGCINC/0L7Qu9C10Lkg0YEg0LTQsNGC0L7QuSDQuCDQstGA0LXQvNC10L3QtdC8IChgREFURV9DUkVBVEVgLCBgREFURV9GUk9NYCwgYERBVEVfVE9gLCBgVElNRVNUQU1QX1hgXHJcbiAgICogICDQuCDRgi7QtC4pLiDQn9C+INGD0LzQvtC70YfQsNC90LjRjiDigJQg0YDQsNGB0L/RgNC+0YHRgtGA0LDQvdGR0L3QvdGL0Lkg0L3QsCDQvNC90L7Qs9C40YUg0L/QvtGA0YLQsNC70LDRhSBgJ2RkLk1NLnl5eXkgSEg6bW06c3MnYCwg0L3QviDRgNC10LDQu9GM0L3Ri9C5INGE0L7RgNC80LDRglxyXG4gICAqICAg0LfQsNCy0LjRgdC40YIg0L7RgiDQvdCw0YHRgtGA0L7QtdC6INC/0L7RgNGC0LDQu9CwICjQndCw0YHRgtGA0L7QudC60Lgg4oaSINGE0L7RgNC80LDRgiDQtNCw0YLRiyDQuCDQstGA0LXQvNC10L3QuCkg4oCUINC10YHQu9C4INC+0L0g0LjQt9Cy0LXRgdGC0LXQvSwg0L/QtdGA0LXQtNCw0LLQsNC50YLQtSDQtdCz0L4g0Y/QstC90L4uXHJcbiAgICogICDQpNC+0YDQvNCw0YIg0LTQu9GPINC/0L7Qu9C10Lkg0YLQvtC70YzQutC+INGBINC00LDRgtC+0LkgKGBFWERBVEVgLCBgUlJVTEUuVU5USUxgKSDQstGL0LLQvtC00LjRgtGB0Y8g0LjQtyDRjdGC0L7Qs9C+INC20LUg0LfQvdCw0YfQtdC90LjRj1xyXG4gICAqICAgKNC+0YLQsdGA0LDRgdGL0LLQsNC90LjQtdC8IGBISDptbTpzc2ApIOKAlCDQv9C10YDQtdC00LDQstCw0YLRjCDQtdCz0L4g0L7RgtC00LXQu9GM0L3QviDQvdC1INC90YPQttC90L4uXHJcbiAgICovXHJcbiAgc3RhdGljIGdldEJ5SWQoXHJcbiAgICBpdGVtOiBpQlhSZXN0Q2FsZW5kYXJFdmVudEdldEFuc3dlckh0dHAgfCB1bmRlZmluZWQgfCBudWxsLFxyXG4gICAgZGF0ZVRpbWVGb3JtYXQgPSAnZGQuTU0ueXl5eSBISDptbTpzcydcclxuICApOiBpQlhSZXN0Q2FsZW5kYXJFdmVudEdldEFuc3dlciB8IHVuZGVmaW5lZCB7XHJcbiAgICByZXR1cm4gKGl0ZW0pID8gQlhSZXN0TWFwQ2FsZW5kYXJFdmVudC5DYWxlbmRhckV2ZW50R2V0QW5zd2VySHR0cFRvQ2FsZW5kYXJFdmVudEdldEFuc3dlcihpdGVtLCBkYXRlVGltZUZvcm1hdCkgOiB1bmRlZmluZWRcclxuICB9XHJcblxyXG4gIC8qKiBAc2VlIGdldEJ5SWQgKi9cclxuICBzdGF0aWMgZ2V0KFxyXG4gICAgaXRlbTogaUJYUmVzdENhbGVuZGFyRXZlbnRHZXRBbnN3ZXJIdHRwW10gfCB1bmRlZmluZWQsXHJcbiAgICBkYXRlVGltZUZvcm1hdCA9ICdkZC5NTS55eXl5IEhIOm1tOnNzJ1xyXG4gICk6IGlCWFJlc3RDYWxlbmRhckV2ZW50R2V0QW5zd2VyW10gfCB1bmRlZmluZWQge1xyXG4gICAgcmV0dXJuIChpdGVtKSA/IGl0ZW0ubWFwKGkgPT4gQlhSZXN0TWFwQ2FsZW5kYXJFdmVudC5DYWxlbmRhckV2ZW50R2V0QW5zd2VySHR0cFRvQ2FsZW5kYXJFdmVudEdldEFuc3dlcihpLCBkYXRlVGltZUZvcm1hdCkpIDogdW5kZWZpbmVkXHJcbiAgfVxyXG5cclxuICAvKiogQHNlZSBnZXRCeUlkICovXHJcbiAgc3RhdGljIENhbGVuZGFyRXZlbnRHZXRBbnN3ZXJIdHRwVG9DYWxlbmRhckV2ZW50R2V0QW5zd2VyKFxyXG4gICAgaXRlbTogaUJYUmVzdENhbGVuZGFyRXZlbnRHZXRBbnN3ZXJIdHRwLFxyXG4gICAgZGF0ZVRpbWVGb3JtYXQgPSAnZGQuTU0ueXl5eSBISDptbTpzcydcclxuICApOiBpQlhSZXN0Q2FsZW5kYXJFdmVudEdldEFuc3dlciB7XHJcbiAgICBjb25zdCBkYXRlRm9ybWF0ID0gZGVyaXZlRGF0ZU9ubHlGb3JtYXQoZGF0ZVRpbWVGb3JtYXQpXHJcblxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgLi4uaXRlbSxcclxuICAgICAgSUQ6IHRvTnVtKGl0ZW0uSUQpLFxyXG4gICAgICBNRUVUSU5HX0hPU1Q6IHRvTnVtKGl0ZW0uTUVFVElOR19IT1NUKSxcclxuICAgICAgT1dORVJfSUQ6IHRvTnVtKGl0ZW0uT1dORVJfSUQpLFxyXG4gICAgICBQQVJFTlRfSUQ6IHRvTnVtKGl0ZW0uUEFSRU5UX0lEKSxcclxuICAgICAgUkVDVVJSRU5DRV9JRDogdG9OdW0oaXRlbS5SRUNVUlJFTkNFX0lEKSxcclxuICAgICAgU0VDVF9JRDogdG9OdW0oaXRlbS5TRUNUX0lEKSxcclxuICAgICAgU0VDVElPTl9JRDogdG9OdW0oaXRlbS5TRUNUSU9OX0lEKSxcclxuICAgICAgVFpfT0ZGU0VUX0ZST006IHRvTnVtKGl0ZW0uVFpfT0ZGU0VUX0ZST00pLFxyXG4gICAgICBUWl9PRkZTRVRfVE86IHRvTnVtKGl0ZW0uVFpfT0ZGU0VUX1RPKSxcclxuICAgICAgVkVSU0lPTjogdG9OdW0oaXRlbS5WRVJTSU9OKSxcclxuICAgICAgREFURV9DUkVBVEU6IHRvRGF0ZShpdGVtLkRBVEVfQ1JFQVRFLCBkYXRlVGltZUZvcm1hdCksXHJcbiAgICAgIERBVEVfRlJPTTogdG9EYXRlKGl0ZW0uREFURV9GUk9NLCBkYXRlVGltZUZvcm1hdCksXHJcbiAgICAgIE9SSUdJTkFMX0RBVEVfRlJPTTogKGl0ZW0uT1JJR0lOQUxfREFURV9GUk9NKVxyXG4gICAgICAgID8gdG9EYXRlKGl0ZW0uT1JJR0lOQUxfREFURV9GUk9NLCBkYXRlVGltZUZvcm1hdClcclxuICAgICAgICA6IG51bGwsXHJcbiAgICAgIERBVEVfVE86IHRvRGF0ZShpdGVtLkRBVEVfVE8sIGRhdGVUaW1lRm9ybWF0KSxcclxuICAgICAgVElNRVNUQU1QX1g6IHRvRGF0ZShpdGVtLlRJTUVTVEFNUF9YLCBkYXRlVGltZUZvcm1hdCksXHJcbiAgICAgIERBVEVfRlJPTV9UU19VVEM6IHRvTnVtKGl0ZW0uREFURV9GUk9NX1RTX1VUQyksXHJcbiAgICAgIERBVEVfVE9fVFNfVVRDOiB0b051bShpdGVtLkRBVEVfVE9fVFNfVVRDKSxcclxuICAgICAgREVMRVRFRDogaXRlbS5ERUxFVEVEID09PSAnWScsXHJcbiAgICAgIERUX0xFTkdUSDogdG9OdW0oaXRlbS5EVF9MRU5HVEgpLFxyXG4gICAgICBEVF9TS0lQX1RJTUU6IGl0ZW0uRFRfU0tJUF9USU1FID09PSAnWScsXHJcbiAgICAgIE1FRVRJTkdfU1RBVFVTOiBpdGVtLk1FRVRJTkdfU1RBVFVTID09PSAnWScsXHJcbiAgICAgIC8vIEVYREFURSDQuCBSUlVMRS5VTlRJTC8nflVOVElMJyDRgyBCaXRyaXgg0L3QtdGA0LXQtNC60L4g0L/RgNC40YXQvtC00Y/RgiDQv9GD0YHRgtC+0Lkg0YHRgtGA0L7QutC+0LkgKNC90LXRgiDQuNGB0LrQu9GO0YfRkdC90L3Ri9GFXHJcbiAgICAgIC8vINC00LDRgiDQv9C+0LLRgtC+0YDQtdC90LjRjyAvINC/0YDQsNCy0LjQu9C+INC/0L7QstGC0L7RgNC10L3QuNGPINC+0LPRgNCw0L3QuNGH0LXQvdC+INGH0LXRgNC10LcgQ09VTlQsINCwINC90LUg0LTQsNGC0L7QuSkg4oCUINC/0YPRgdGC0YPRjiDRgdGC0YDQvtC60YNcclxuICAgICAgLy8gdG9EYXRlKCkg0YDQsNGB0L/QsNGA0YHQuNGC0Ywg0L3QtSDQvNC+0LbQtdGCINC90Lgg0L/RgNC4INC60LDQutC+0Lwg0YTQvtGA0LzQsNGC0LUsINC/0L7RjdGC0L7QvNGDINGC0LDQutC40LUg0L/QvtC70Y8g0L/RgNC+0L/Rg9GB0LrQsNC10Lwg0LTQviDQstGL0LfQvtCy0LBcclxuICAgICAgRVhEQVRFOiBpdGVtLkVYREFURSA/IGl0ZW0uRVhEQVRFLnNwbGl0KCc7JykuZmlsdGVyKEJvb2xlYW4pLm1hcChkYXRlU3RyID0+IHRvRGF0ZShkYXRlU3RyLCBkYXRlRm9ybWF0KSkgOiBbXSxcclxuICAgICAgUlJVTEU6IChpdGVtLlJSVUxFICYmIHR5cGVvZiBpdGVtLlJSVUxFICE9PSAnc3RyaW5nJykgPyB7XHJcbiAgICAgICAgLi4uaXRlbS5SUlVMRSxcclxuICAgICAgICBVTlRJTDogaXRlbS5SUlVMRS5VTlRJTCA/IHRvRGF0ZShpdGVtLlJSVUxFLlVOVElMLCBkYXRlRm9ybWF0KSA6IG51bGwsXHJcbiAgICAgICAgJ35VTlRJTCc6IGl0ZW0uUlJVTEVbJ35VTlRJTCddID8gdG9EYXRlKGl0ZW0uUlJVTEVbJ35VTlRJTCddLCBkYXRlRm9ybWF0KSA6IG51bGxcclxuICAgICAgfSA6IG51bGwsXHJcbiAgICAgIEFUVEVOREVFX0xJU1Q6IChpdGVtLkFUVEVOREVFX0xJU1QpID8gaXRlbS5BVFRFTkRFRV9MSVNULm1hcChpID0+IHtcclxuICAgICAgICByZXR1cm4ge2lkOiBpLmlkLCBlbnRyeUlkOiB0b051bShpLmVudHJ5SWQpLCBzdGF0dXM6IGkuc3RhdHVzfVxyXG4gICAgICB9KSA6IFtdXHJcbiAgICB9XHJcbiAgfVxyXG59XHJcbiJdfQ==
|
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
import { toDate, toNum } from '../../services/base';
|
|
2
2
|
export class BXRestMapCalendarSection {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* @param item
|
|
5
|
+
* @param dateTimeFormat Формат полей `DATE_CREATE`/`TIMESTAMP_X`. По умолчанию — распространённый на многих
|
|
6
|
+
* порталах `'dd.MM.yyyy HH:mm:ss'`, но реальный формат зависит от настроек портала (Настройки → формат
|
|
7
|
+
* даты и времени) — если он известен, передавайте его явно.
|
|
8
|
+
*/
|
|
9
|
+
static get(item, dateTimeFormat = 'dd.MM.yyyy HH:mm:ss') {
|
|
10
|
+
return (item) ? item.map(i => BXRestMapCalendarSection.CalendarSectionGetHttpToCalendarSectionGetHttp(i, dateTimeFormat)) : undefined;
|
|
5
11
|
}
|
|
6
|
-
|
|
12
|
+
/** @see get */
|
|
13
|
+
static CalendarSectionGetHttpToCalendarSectionGetHttp(item, dateTimeFormat = 'dd.MM.yyyy HH:mm:ss') {
|
|
7
14
|
return {
|
|
8
15
|
...item,
|
|
9
16
|
ID: toNum(item.ID),
|
|
10
17
|
OWNER_ID: toNum(item.OWNER_ID),
|
|
11
18
|
CREATED_BY: toNum(item.CREATED_BY),
|
|
12
|
-
DATE_CREATE: toDate(item.DATE_CREATE,
|
|
13
|
-
TIMESTAMP_X: toDate(item.TIMESTAMP_X,
|
|
19
|
+
DATE_CREATE: toDate(item.DATE_CREATE, dateTimeFormat),
|
|
20
|
+
TIMESTAMP_X: toDate(item.TIMESTAMP_X, dateTimeFormat)
|
|
14
21
|
};
|
|
15
22
|
}
|
|
16
23
|
}
|
|
17
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
24
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VjdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2J4LXJlc3Qvc3JjL21hcC9jYWxlbmRhci9zZWN0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFFbkQsTUFBTSxPQUFPLHdCQUF3QjtJQUVuQzs7Ozs7T0FLRztJQUNILE1BQU0sQ0FBQyxHQUFHLENBQ1IsSUFBaUQsRUFDakQsY0FBYyxHQUFHLHFCQUFxQjtRQUV0QyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyx3QkFBd0IsQ0FBQyw4Q0FBOEMsQ0FBQyxDQUFDLEVBQUUsY0FBYyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFBO0lBQ3ZJLENBQUM7SUFFRCxlQUFlO0lBQ2YsTUFBTSxDQUFDLDhDQUE4QyxDQUNuRCxJQUFtQyxFQUNuQyxjQUFjLEdBQUcscUJBQXFCO1FBRXRDLE9BQU87WUFDTCxHQUFHLElBQUk7WUFDUCxFQUFFLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDbEIsUUFBUSxFQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDO1lBQzlCLFVBQVUsRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQztZQUNsQyxXQUFXLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsY0FBYyxDQUFDO1lBQ3JELFdBQVcsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxjQUFjLENBQUM7U0FDdEQsQ0FBQTtJQUNILENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGlCWFJlc3RDYWxlbmRhclNlY3Rpb25HZXQsIGlCWFJlc3RDYWxlbmRhclNlY3Rpb25HZXRIdHRwIH0gZnJvbSAnLi4vLi4vdHlwaWZpY2F0aW9uL3Jlc3QvY2FsZW5kYXIvc2VjdGlvbi9nZXQnXHJcbmltcG9ydCB7IHRvRGF0ZSwgdG9OdW0gfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9iYXNlJ1xyXG5cclxuZXhwb3J0IGNsYXNzIEJYUmVzdE1hcENhbGVuZGFyU2VjdGlvbiB7XHJcblxyXG4gIC8qKlxyXG4gICAqIEBwYXJhbSBpdGVtXHJcbiAgICogQHBhcmFtIGRhdGVUaW1lRm9ybWF0INCk0L7RgNC80LDRgiDQv9C+0LvQtdC5IGBEQVRFX0NSRUFURWAvYFRJTUVTVEFNUF9YYC4g0J/QviDRg9C80L7Qu9GH0LDQvdC40Y4g4oCUINGA0LDRgdC/0YDQvtGB0YLRgNCw0L3RkdC90L3Ri9C5INC90LAg0LzQvdC+0LPQuNGFXHJcbiAgICogICDQv9C+0YDRgtCw0LvQsNGFIGAnZGQuTU0ueXl5eSBISDptbTpzcydgLCDQvdC+INGA0LXQsNC70YzQvdGL0Lkg0YTQvtGA0LzQsNGCINC30LDQstC40YHQuNGCINC+0YIg0L3QsNGB0YLRgNC+0LXQuiDQv9C+0YDRgtCw0LvQsCAo0J3QsNGB0YLRgNC+0LnQutC4IOKGkiDRhNC+0YDQvNCw0YJcclxuICAgKiAgINC00LDRgtGLINC4INCy0YDQtdC80LXQvdC4KSDigJQg0LXRgdC70Lgg0L7QvSDQuNC30LLQtdGB0YLQtdC9LCDQv9C10YDQtdC00LDQstCw0LnRgtC1INC10LPQviDRj9Cy0L3Qvi5cclxuICAgKi9cclxuICBzdGF0aWMgZ2V0KFxyXG4gICAgaXRlbTogaUJYUmVzdENhbGVuZGFyU2VjdGlvbkdldEh0dHBbXSB8IHVuZGVmaW5lZCxcclxuICAgIGRhdGVUaW1lRm9ybWF0ID0gJ2RkLk1NLnl5eXkgSEg6bW06c3MnXHJcbiAgKTogaUJYUmVzdENhbGVuZGFyU2VjdGlvbkdldFtdIHwgdW5kZWZpbmVke1xyXG4gICAgcmV0dXJuIChpdGVtKSA/IGl0ZW0ubWFwKGkgPT4gQlhSZXN0TWFwQ2FsZW5kYXJTZWN0aW9uLkNhbGVuZGFyU2VjdGlvbkdldEh0dHBUb0NhbGVuZGFyU2VjdGlvbkdldEh0dHAoaSwgZGF0ZVRpbWVGb3JtYXQpKSA6IHVuZGVmaW5lZFxyXG4gIH1cclxuXHJcbiAgLyoqIEBzZWUgZ2V0ICovXHJcbiAgc3RhdGljIENhbGVuZGFyU2VjdGlvbkdldEh0dHBUb0NhbGVuZGFyU2VjdGlvbkdldEh0dHAoXHJcbiAgICBpdGVtOiBpQlhSZXN0Q2FsZW5kYXJTZWN0aW9uR2V0SHR0cCxcclxuICAgIGRhdGVUaW1lRm9ybWF0ID0gJ2RkLk1NLnl5eXkgSEg6bW06c3MnXHJcbiAgKTogaUJYUmVzdENhbGVuZGFyU2VjdGlvbkdldCB7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICAuLi5pdGVtLFxyXG4gICAgICBJRDogdG9OdW0oaXRlbS5JRCksXHJcbiAgICAgIE9XTkVSX0lEOiB0b051bShpdGVtLk9XTkVSX0lEKSxcclxuICAgICAgQ1JFQVRFRF9CWTogdG9OdW0oaXRlbS5DUkVBVEVEX0JZKSxcclxuICAgICAgREFURV9DUkVBVEU6IHRvRGF0ZShpdGVtLkRBVEVfQ1JFQVRFLCBkYXRlVGltZUZvcm1hdCksXHJcbiAgICAgIFRJTUVTVEFNUF9YOiB0b0RhdGUoaXRlbS5USU1FU1RBTVBfWCwgZGF0ZVRpbWVGb3JtYXQpXHJcbiAgICB9XHJcbiAgfVxyXG59XHJcbiJdfQ==
|
|
@@ -1,22 +1,29 @@
|
|
|
1
1
|
import clone from 'just-clone';
|
|
2
2
|
import { toDate, toNum } from '../../services/base';
|
|
3
3
|
export class BXRestMapCrmCallList {
|
|
4
|
-
/**
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Преобразует данные списка обзвона из формата Bitrix24 в локальный формат.
|
|
6
|
+
*
|
|
7
|
+
* @param value
|
|
8
|
+
* @param dateTimeFormat Формат поля `DATE_CREATE`. По умолчанию — `'yyyy-MM-dd HH:mm:ss'`, но реальный
|
|
9
|
+
* формат зависит от настроек портала (Настройки → формат даты и времени) — если он известен,
|
|
10
|
+
* передавайте его явно.
|
|
11
|
+
*/
|
|
12
|
+
static get(value, dateTimeFormat = 'yyyy-MM-dd HH:mm:ss') {
|
|
13
|
+
return this.mapItem(value, dateTimeFormat);
|
|
7
14
|
}
|
|
8
|
-
/** Преобразует список обзвонов с учетом полей, выбранных через `SELECT`. */
|
|
9
|
-
static list(value) {
|
|
10
|
-
return value?.map(item => this.mapItem(item));
|
|
15
|
+
/** Преобразует список обзвонов с учетом полей, выбранных через `SELECT`. @see get */
|
|
16
|
+
static list(value, dateTimeFormat = 'yyyy-MM-dd HH:mm:ss') {
|
|
17
|
+
return value?.map(item => this.mapItem(item, dateTimeFormat));
|
|
11
18
|
}
|
|
12
|
-
static mapItem(value) {
|
|
19
|
+
static mapItem(value, dateTimeFormat = 'yyyy-MM-dd HH:mm:ss') {
|
|
13
20
|
if (!value)
|
|
14
21
|
return undefined;
|
|
15
22
|
const result = clone(value);
|
|
16
23
|
if (value.ID !== undefined)
|
|
17
24
|
result.ID = toNum(value.ID);
|
|
18
25
|
if (value.DATE_CREATE !== undefined) {
|
|
19
|
-
result.DATE_CREATE = toDate(value.DATE_CREATE,
|
|
26
|
+
result.DATE_CREATE = toDate(value.DATE_CREATE, dateTimeFormat);
|
|
20
27
|
}
|
|
21
28
|
if (value.CREATED_BY_ID !== undefined)
|
|
22
29
|
result.CREATED_BY_ID = toNum(value.CREATED_BY_ID);
|
|
@@ -27,4 +34,4 @@ export class BXRestMapCrmCallList {
|
|
|
27
34
|
return result;
|
|
28
35
|
}
|
|
29
36
|
}
|
|
30
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
37
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FsbGxpc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9ieC1yZXN0L3NyYy9tYXAvY3JtL2NhbGxsaXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxNQUFNLFlBQVksQ0FBQTtBQU85QixPQUFPLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxNQUFNLHFCQUFxQixDQUFBO0FBRW5ELE1BQU0sT0FBTyxvQkFBb0I7SUFDL0I7Ozs7Ozs7T0FPRztJQUNILE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBeUMsRUFBRSxjQUFjLEdBQUcscUJBQXFCO1FBQzFGLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsY0FBYyxDQUFtQyxDQUFBO0lBQzlFLENBQUM7SUFFRCxxRkFBcUY7SUFDckYsTUFBTSxDQUFDLElBQUksQ0FDVCxLQUFtRCxFQUNuRCxjQUFjLEdBQUcscUJBQXFCO1FBRXRDLE9BQU8sS0FBSyxFQUFFLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLGNBQWMsQ0FBK0IsQ0FBQyxDQUFBO0lBQzdGLENBQUM7SUFFTyxNQUFNLENBQUMsT0FBTyxDQUNwQixLQUFpRCxFQUNqRCxjQUFjLEdBQUcscUJBQXFCO1FBRXRDLElBQUksQ0FBQyxLQUFLO1lBQUUsT0FBTyxTQUFTLENBQUE7UUFFNUIsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBMEMsQ0FBQTtRQUVwRSxJQUFJLEtBQUssQ0FBQyxFQUFFLEtBQUssU0FBUztZQUFFLE1BQU0sQ0FBQyxFQUFFLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQTtRQUN2RCxJQUFJLEtBQUssQ0FBQyxXQUFXLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDcEMsTUFBTSxDQUFDLFdBQVcsR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLFdBQVcsRUFBRSxjQUFjLENBQUMsQ0FBQTtRQUNoRSxDQUFDO1FBQ0QsSUFBSSxLQUFLLENBQUMsYUFBYSxLQUFLLFNBQVM7WUFBRSxNQUFNLENBQUMsYUFBYSxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLENBQUE7UUFDeEYsSUFBSSxLQUFLLENBQUMsVUFBVSxLQUFLLFNBQVM7WUFBRSxNQUFNLENBQUMsVUFBVSxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUE7UUFDL0UsSUFBSSxLQUFLLENBQUMsY0FBYyxLQUFLLFNBQVM7WUFBRSxNQUFNLENBQUMsY0FBYyxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUFVLENBQUE7UUFFcEcsT0FBTyxNQUFNLENBQUE7SUFDZixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgY2xvbmUgZnJvbSAnanVzdC1jbG9uZSdcbmltcG9ydCB7XG4gIGlCWFJlc3RDcm1DYWxsTGlzdCxcbiAgaUJYUmVzdENybUNhbGxMaXN0SHR0cCxcbiAgaUJYUmVzdENybUNhbGxMaXN0TGlzdEl0ZW0sXG4gIGlCWFJlc3RDcm1DYWxsTGlzdExpc3RJdGVtSHR0cFxufSBmcm9tICcuLi8uLi90eXBpZmljYXRpb24vcmVzdC9jcm0nXG5pbXBvcnQgeyB0b0RhdGUsIHRvTnVtIH0gZnJvbSAnLi4vLi4vc2VydmljZXMvYmFzZSdcblxuZXhwb3J0IGNsYXNzIEJYUmVzdE1hcENybUNhbGxMaXN0IHtcbiAgLyoqXG4gICAqINCf0YDQtdC+0LHRgNCw0LfRg9C10YIg0LTQsNC90L3Ri9C1INGB0L/QuNGB0LrQsCDQvtCx0LfQstC+0L3QsCDQuNC3INGE0L7RgNC80LDRgtCwIEJpdHJpeDI0INCyINC70L7QutCw0LvRjNC90YvQuSDRhNC+0YDQvNCw0YIuXG4gICAqXG4gICAqIEBwYXJhbSB2YWx1ZVxuICAgKiBAcGFyYW0gZGF0ZVRpbWVGb3JtYXQg0KTQvtGA0LzQsNGCINC/0L7Qu9GPIGBEQVRFX0NSRUFURWAuINCf0L4g0YPQvNC+0LvRh9Cw0L3QuNGOIOKAlCBgJ3l5eXktTU0tZGQgSEg6bW06c3MnYCwg0L3QviDRgNC10LDQu9GM0L3Ri9C5XG4gICAqICAg0YTQvtGA0LzQsNGCINC30LDQstC40YHQuNGCINC+0YIg0L3QsNGB0YLRgNC+0LXQuiDQv9C+0YDRgtCw0LvQsCAo0J3QsNGB0YLRgNC+0LnQutC4IOKGkiDRhNC+0YDQvNCw0YIg0LTQsNGC0Ysg0Lgg0LLRgNC10LzQtdC90LgpIOKAlCDQtdGB0LvQuCDQvtC9INC40LfQstC10YHRgtC10L0sXG4gICAqICAg0L/QtdGA0LXQtNCw0LLQsNC50YLQtSDQtdCz0L4g0Y/QstC90L4uXG4gICAqL1xuICBzdGF0aWMgZ2V0KHZhbHVlOiBpQlhSZXN0Q3JtQ2FsbExpc3RIdHRwIHwgdW5kZWZpbmVkLCBkYXRlVGltZUZvcm1hdCA9ICd5eXl5LU1NLWRkIEhIOm1tOnNzJyk6IGlCWFJlc3RDcm1DYWxsTGlzdCB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMubWFwSXRlbSh2YWx1ZSwgZGF0ZVRpbWVGb3JtYXQpIGFzIGlCWFJlc3RDcm1DYWxsTGlzdCB8IHVuZGVmaW5lZFxuICB9XG5cbiAgLyoqINCf0YDQtdC+0LHRgNCw0LfRg9C10YIg0YHQv9C40YHQvtC6INC+0LHQt9Cy0L7QvdC+0LIg0YEg0YPRh9C10YLQvtC8INC/0L7Qu9C10LksINCy0YvQsdGA0LDQvdC90YvRhSDRh9C10YDQtdC3IGBTRUxFQ1RgLiBAc2VlIGdldCAqL1xuICBzdGF0aWMgbGlzdChcbiAgICB2YWx1ZTogaUJYUmVzdENybUNhbGxMaXN0TGlzdEl0ZW1IdHRwW10gfCB1bmRlZmluZWQsXG4gICAgZGF0ZVRpbWVGb3JtYXQgPSAneXl5eS1NTS1kZCBISDptbTpzcydcbiAgKTogaUJYUmVzdENybUNhbGxMaXN0TGlzdEl0ZW1bXSB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHZhbHVlPy5tYXAoaXRlbSA9PiB0aGlzLm1hcEl0ZW0oaXRlbSwgZGF0ZVRpbWVGb3JtYXQpIGFzIGlCWFJlc3RDcm1DYWxsTGlzdExpc3RJdGVtKVxuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgbWFwSXRlbShcbiAgICB2YWx1ZTogaUJYUmVzdENybUNhbGxMaXN0TGlzdEl0ZW1IdHRwIHwgdW5kZWZpbmVkLFxuICAgIGRhdGVUaW1lRm9ybWF0ID0gJ3l5eXktTU0tZGQgSEg6bW06c3MnXG4gICk6IGlCWFJlc3RDcm1DYWxsTGlzdExpc3RJdGVtIHwgdW5kZWZpbmVkIHtcbiAgICBpZiAoIXZhbHVlKSByZXR1cm4gdW5kZWZpbmVkXG5cbiAgICBjb25zdCByZXN1bHQgPSBjbG9uZSh2YWx1ZSkgYXMgdW5rbm93biBhcyBpQlhSZXN0Q3JtQ2FsbExpc3RMaXN0SXRlbVxuXG4gICAgaWYgKHZhbHVlLklEICE9PSB1bmRlZmluZWQpIHJlc3VsdC5JRCA9IHRvTnVtKHZhbHVlLklEKVxuICAgIGlmICh2YWx1ZS5EQVRFX0NSRUFURSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICByZXN1bHQuREFURV9DUkVBVEUgPSB0b0RhdGUodmFsdWUuREFURV9DUkVBVEUsIGRhdGVUaW1lRm9ybWF0KVxuICAgIH1cbiAgICBpZiAodmFsdWUuQ1JFQVRFRF9CWV9JRCAhPT0gdW5kZWZpbmVkKSByZXN1bHQuQ1JFQVRFRF9CWV9JRCA9IHRvTnVtKHZhbHVlLkNSRUFURURfQllfSUQpXG4gICAgaWYgKHZhbHVlLldFQkZPUk1fSUQgIT09IHVuZGVmaW5lZCkgcmVzdWx0LldFQkZPUk1fSUQgPSB0b051bSh2YWx1ZS5XRUJGT1JNX0lEKVxuICAgIGlmICh2YWx1ZS5FTlRJVFlfVFlQRV9JRCAhPT0gdW5kZWZpbmVkKSByZXN1bHQuRU5USVRZX1RZUEVfSUQgPSB0b051bSh2YWx1ZS5FTlRJVFlfVFlQRV9JRCkgYXMgMyB8IDRcblxuICAgIHJldHVybiByZXN1bHRcbiAgfVxufVxuIl19
|