@andrey4emk/npm-app-front-b24 0.1.20 → 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 +337 -0
- package/README.md +57 -14
- package/Subscriptions.vue +424 -0
- package/package.json +8 -20
- package/dist/npm-app-front-b24.es.js +0 -5984
- package/dist/npm-app-front-b24.umd.js +0 -1
- package/dist/style.css +0 -1
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
|
-
|
|
11
|
+
## Компоненты
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
### Subscriptions
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
27
|
+
Требует глобальный объект `$b24` (клиент Bitrix24 REST API).
|
|
17
28
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
43
|
+
**Props:**
|
|
24
44
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
+
```
|