@andrey4emk/npm-app-front-b24 0.1.19 → 0.2.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/ConfigLogs.vue ADDED
@@ -0,0 +1,337 @@
1
+ <template>
2
+ <div class="config-logs">
3
+ <h2>Уровни логирования</h2>
4
+
5
+ <div v-if="loading" class="config-logs__loading">Загрузка...</div>
6
+
7
+ <div v-else-if="error" class="config-logs__error">
8
+ <p>{{ error }}</p>
9
+ <button @click="loadConfig">Повторить</button>
10
+ </div>
11
+
12
+ <div v-else>
13
+ <table class="config-logs__table">
14
+ <thead>
15
+ <tr>
16
+ <th>Уровень</th>
17
+ <th>Включён</th>
18
+ <th>JSON-формат</th>
19
+ </tr>
20
+ </thead>
21
+ <tbody>
22
+ <tr v-for="level in levels" :key="level.key">
23
+ <td>
24
+ <span class="config-logs__level-name">{{ level.label }}</span>
25
+ <span class="config-logs__level-key">{{ level.key }}</span>
26
+ </td>
27
+ <td>
28
+ <label class="config-logs__switch">
29
+ <input
30
+ type="checkbox"
31
+ v-model="config[level.key].enabled"
32
+ />
33
+ <span class="config-logs__slider"></span>
34
+ </label>
35
+ </td>
36
+ <td>
37
+ <label class="config-logs__switch">
38
+ <input
39
+ type="checkbox"
40
+ v-model="config[level.key].json"
41
+ />
42
+ <span class="config-logs__slider"></span>
43
+ </label>
44
+ </td>
45
+ </tr>
46
+ </tbody>
47
+ </table>
48
+
49
+ <div class="config-logs__actions">
50
+ <button @click="saveConfig" :disabled="saving">
51
+ {{ saving ? "Сохранение..." : "Сохранить" }}
52
+ </button>
53
+ <button @click="loadConfig" :disabled="loading">Обновить</button>
54
+ </div>
55
+
56
+ <div v-if="message" :class="['config-logs__message', messageType === 'ok' ? 'config-logs__message--success' : 'config-logs__message--error']">
57
+ {{ message }}
58
+ </div>
59
+ </div>
60
+ </div>
61
+ </template>
62
+
63
+ <script setup>
64
+ import { ref, reactive, onMounted } from "vue";
65
+
66
+ const props = defineProps({
67
+ apiBase: {
68
+ type: String,
69
+ default: "",
70
+ },
71
+ secretKey: {
72
+ type: String,
73
+ default: "",
74
+ },
75
+ configName: {
76
+ type: String,
77
+ default: "log",
78
+ },
79
+ });
80
+
81
+ const levels = [
82
+ { key: "trace", label: "Трассировка" },
83
+ { key: "debug", label: "Отладка" },
84
+ { key: "info", label: "Информация" },
85
+ { key: "warn", label: "Предупреждения" },
86
+ { key: "error", label: "Ошибки" },
87
+ ];
88
+
89
+ const config = reactive({
90
+ trace: { enabled: false, json: true, color: "" },
91
+ debug: { enabled: true, json: true, color: "" },
92
+ info: { enabled: true, json: true, color: "" },
93
+ warn: { enabled: true, json: true, color: "" },
94
+ error: { enabled: true, json: true, color: "" },
95
+ });
96
+
97
+ const loading = ref(false);
98
+ const saving = ref(false);
99
+ const error = ref("");
100
+ const message = ref("");
101
+ const messageType = ref("ok");
102
+
103
+ function getHeaders() {
104
+ const headers = { "Content-Type": "application/json" };
105
+ if (props.secretKey) {
106
+ headers.secret = props.secretKey;
107
+ }
108
+ return headers;
109
+ }
110
+
111
+ function getUrl() {
112
+ const base = props.apiBase.replace(/\/+$/, "");
113
+ return `${base}/api/config/${props.configName}`;
114
+ }
115
+
116
+ async function loadConfig() {
117
+ loading.value = true;
118
+ error.value = "";
119
+ message.value = "";
120
+
121
+ try {
122
+ const res = await fetch(getUrl(), { headers: getHeaders() });
123
+ const json = await res.json();
124
+
125
+ if (json.status === "ok" && json.data) {
126
+ for (const level of levels) {
127
+ if (json.data[level.key]) {
128
+ config[level.key].enabled = json.data[level.key].enabled ?? false;
129
+ config[level.key].json = json.data[level.key].json ?? true;
130
+ config[level.key].color = json.data[level.key].color ?? "";
131
+ }
132
+ }
133
+ } else {
134
+ error.value = json.message || "Не удалось загрузить конфиг";
135
+ }
136
+ } catch (e) {
137
+ error.value = `Ошибка загрузки: ${e.message}`;
138
+ } finally {
139
+ loading.value = false;
140
+ }
141
+ }
142
+
143
+ async function saveConfig() {
144
+ saving.value = true;
145
+ message.value = "";
146
+
147
+ const payload = {};
148
+ for (const level of levels) {
149
+ payload[level.key] = {
150
+ enabled: config[level.key].enabled,
151
+ color: config[level.key].color,
152
+ json: config[level.key].json,
153
+ };
154
+ }
155
+
156
+ try {
157
+ const res = await fetch(getUrl(), {
158
+ method: "POST",
159
+ headers: getHeaders(),
160
+ body: JSON.stringify(payload),
161
+ });
162
+ const json = await res.json();
163
+
164
+ if (json.status === "ok") {
165
+ message.value = json.message || "Конфиг сохранён";
166
+ messageType.value = "ok";
167
+ } else {
168
+ message.value = json.message || "Ошибка сохранения";
169
+ messageType.value = "error";
170
+ }
171
+ } catch (e) {
172
+ message.value = `Ошибка сохранения: ${e.message}`;
173
+ messageType.value = "error";
174
+ } finally {
175
+ saving.value = false;
176
+ }
177
+ }
178
+
179
+ onMounted(() => {
180
+ loadConfig();
181
+ });
182
+ </script>
183
+
184
+ <style>
185
+ .config-logs {
186
+ margin: 20px 0;
187
+ padding: 16px;
188
+ border: 1px solid #ddd;
189
+ border-radius: 8px;
190
+ background: #fafafa;
191
+ }
192
+
193
+ .config-logs h2 {
194
+ margin: 0 0 16px 0;
195
+ font-size: 18px;
196
+ }
197
+
198
+ .config-logs__loading,
199
+ .config-logs__error {
200
+ padding: 12px;
201
+ text-align: center;
202
+ }
203
+
204
+ .config-logs__error {
205
+ color: #d32f2f;
206
+ }
207
+
208
+ .config-logs__table {
209
+ width: 100%;
210
+ border-collapse: collapse;
211
+ margin-bottom: 16px;
212
+ }
213
+
214
+ .config-logs__table th,
215
+ .config-logs__table td {
216
+ padding: 10px 12px;
217
+ text-align: left;
218
+ border-bottom: 1px solid #eee;
219
+ }
220
+
221
+ .config-logs__table th {
222
+ font-weight: 600;
223
+ color: #555;
224
+ font-size: 13px;
225
+ text-transform: uppercase;
226
+ }
227
+
228
+ .config-logs__level-name {
229
+ display: block;
230
+ font-weight: 500;
231
+ }
232
+
233
+ .config-logs__level-key {
234
+ display: block;
235
+ font-size: 12px;
236
+ color: #888;
237
+ font-family: monospace;
238
+ }
239
+
240
+ .config-logs__switch {
241
+ position: relative;
242
+ display: inline-block;
243
+ width: 44px;
244
+ height: 24px;
245
+ }
246
+
247
+ .config-logs__switch input {
248
+ opacity: 0;
249
+ width: 0;
250
+ height: 0;
251
+ }
252
+
253
+ .config-logs__slider {
254
+ position: absolute;
255
+ cursor: pointer;
256
+ top: 0;
257
+ left: 0;
258
+ right: 0;
259
+ bottom: 0;
260
+ background-color: #ccc;
261
+ transition: 0.3s;
262
+ border-radius: 24px;
263
+ }
264
+
265
+ .config-logs__slider::before {
266
+ content: "";
267
+ position: absolute;
268
+ height: 18px;
269
+ width: 18px;
270
+ left: 3px;
271
+ bottom: 3px;
272
+ background-color: #fff;
273
+ transition: 0.3s;
274
+ border-radius: 50%;
275
+ }
276
+
277
+ .config-logs__switch input:checked + .config-logs__slider {
278
+ background-color: #4caf50;
279
+ }
280
+
281
+ .config-logs__switch input:checked + .config-logs__slider::before {
282
+ transform: translateX(20px);
283
+ }
284
+
285
+ .config-logs__actions {
286
+ display: flex;
287
+ gap: 8px;
288
+ }
289
+
290
+ .config-logs__actions button {
291
+ padding: 8px 20px;
292
+ border: 1px solid #ccc;
293
+ border-radius: 4px;
294
+ background: #fff;
295
+ cursor: pointer;
296
+ font-size: 14px;
297
+ transition: background 0.2s;
298
+ }
299
+
300
+ .config-logs__actions button:hover:not(:disabled) {
301
+ background: #f0f0f0;
302
+ }
303
+
304
+ .config-logs__actions button:first-child {
305
+ background: #4caf50;
306
+ color: #fff;
307
+ border-color: #4caf50;
308
+ }
309
+
310
+ .config-logs__actions button:first-child:hover:not(:disabled) {
311
+ background: #43a047;
312
+ }
313
+
314
+ .config-logs__actions button:disabled {
315
+ opacity: 0.6;
316
+ cursor: not-allowed;
317
+ }
318
+
319
+ .config-logs__message {
320
+ margin-top: 12px;
321
+ padding: 8px 12px;
322
+ border-radius: 4px;
323
+ font-size: 14px;
324
+ }
325
+
326
+ .config-logs__message--success {
327
+ background: #e8f5e9;
328
+ color: #2e7d32;
329
+ border: 1px solid #a5d6a7;
330
+ }
331
+
332
+ .config-logs__message--error {
333
+ background: #ffebee;
334
+ color: #c62828;
335
+ border: 1px solid #ef9a9a;
336
+ }
337
+ </style>
package/README.md CHANGED
@@ -1,27 +1,70 @@
1
- Установка:
1
+ # @andrey4emk/npm-app-front-b24
2
+
3
+ Vue 3 компоненты для Bitrix24.
4
+
5
+ ## Установка
2
6
 
3
7
  ```bash
4
8
  npm install @andrey4emk/npm-app-front-b24
5
9
  ```
6
10
 
7
- Внимание по стилям: пакет содержит отдельный CSS-файл `dist/style.css`. Есть три варианта подключить стили в проекте-потребителе:
11
+ ## Компоненты
8
12
 
9
- 1. Явно импортировать CSS вместе с компонентом:
13
+ ### Subscriptions
10
14
 
11
- ```js
12
- import "@andrey4emk/npm-app-front-b24/dist/style.css";
13
- import { Subscriptions } from "@andrey4emk/npm-app-front-b24";
15
+ Управление подписками на события и оффлайн-сущностями Bitrix24.
16
+
17
+ ```vue
18
+ <script setup>
19
+ import Subscriptions from "@andrey4emk/npm-app-front-b24/Subscriptions.vue";
20
+ </script>
21
+
22
+ <template>
23
+ <Subscriptions />
24
+ </template>
14
25
  ```
15
26
 
16
- 2. Использовать удобный короткий импорт (поддерживается):
27
+ Требует глобальный объект `$b24` (клиент Bitrix24 REST API).
17
28
 
18
- ```js
19
- import "@andrey4emk/npm-app-front-b24/style.css";
20
- import { Subscriptions } from "@andrey4emk/npm-app-front-b24";
29
+ ### ConfigLogs
30
+
31
+ Управление уровнями логирования через `config/log.json`.
32
+
33
+ ```vue
34
+ <script setup>
35
+ import ConfigLogs from "@andrey4emk/npm-app-front-b24/ConfigLogs.vue";
36
+ </script>
37
+
38
+ <template>
39
+ <ConfigLogs api-base="" :secret-key="secretKey" />
40
+ </template>
21
41
  ```
22
42
 
23
- Рекомендация: импортируйте CSS явно. Поскольку библиотека выделяет стили в отдельный файл `dist/style.css`, автоматическое применение стилей при простом импорте JS не гарантируется во всех окружениях. Самые надёжные варианты:
43
+ **Props:**
24
44
 
25
- - `import '@andrey4emk/npm-app-front-b24/style.css'` короткий импорт (рекомендую);
26
- - `import '@andrey4emk/npm-app-front-b24/dist/style.css'` — явный путь к файлу;
27
- - подключение через `<link>` в `index.html`.
45
+ | Prop | Тип | По умолчанию | Описание |
46
+ |------|-----|-------------|----------|
47
+ | `apiBase` | String | `""` | Базовый URL сервера |
48
+ | `secretKey` | String | `""` | Ключ авторизации (заголовок `secret`) |
49
+ | `configName` | String | `"log"` | Имя конфига (без `.json`) |
50
+
51
+ ## Требования
52
+
53
+ - Vue 3 (`^3.0.0`) — peer dependency
54
+ - Проект-потребитель должен поддерживать компиляцию `.vue` файлов (Vite / webpack + vue-loader)
55
+ - `luxon` (`^3.7.2`) — используется в Subscriptions для форматирования дат
56
+
57
+ ## Важно (v0.2.0)
58
+
59
+ Начиная с версии `0.2.0` пакет поставляет **исходные `.vue` файлы** вместо скомпилированного бандла. Компиляция происходит на стороне проекта-потребителя.
60
+
61
+ Если вы обновляетесь с `0.1.x`, измените импорты:
62
+
63
+ ```js
64
+ // Было (0.1.x)
65
+ import { Subscriptions } from "@andrey4emk/npm-app-front-b24";
66
+ import "@andrey4emk/npm-app-front-b24/style.css";
67
+
68
+ // Стало (0.2.0+)
69
+ import Subscriptions from "@andrey4emk/npm-app-front-b24/Subscriptions.vue";
70
+ ```