Some checks failed
Telegram Mini App Shop Builder / Compute version metadata (push) Has been cancelled
Telegram Mini App Shop Builder / Run Frontend tests (push) Has been cancelled
Telegram Mini App Shop Builder / Run Backend tests (push) Has been cancelled
Telegram Mini App Shop Builder / Run PHP_CodeSniffer (push) Has been cancelled
Telegram Mini App Shop Builder / Build module. (push) Has been cancelled
Telegram Mini App Shop Builder / release (push) Has been cancelled
192 lines
6.5 KiB
Vue
192 lines
6.5 KiB
Vue
<template>
|
|
<div>
|
|
<DataTable
|
|
:value="logs.logs"
|
|
:loading="logs.loading"
|
|
paginator
|
|
:rows="15"
|
|
:rowsPerPageOptions="[15, 50, 100, 200]"
|
|
showGridlines
|
|
stripedRows
|
|
size="small"
|
|
sortField="datetime_raw"
|
|
:sortOrder="-1"
|
|
removableSort
|
|
paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink CurrentPageReport RowsPerPageDropdown"
|
|
:currentPageReportTemplate="`Показано {first} - {last} из {totalRecords} записей`"
|
|
>
|
|
<template #header>
|
|
<div class="tw:flex tw:items-center tw:justify-between tw:gap-2">
|
|
<span class="tw:text-sm tw:text-gray-600">Выводятся последние 100 событий</span>
|
|
<Button
|
|
icon="fa fa-refresh"
|
|
@click="logs.fetchLogsFromServer()"
|
|
v-tooltip.top="'Обновить журнал'"
|
|
size="small"
|
|
:loading="logs.loading"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<Column header="Действия" :exportable="false" headerStyle="width: 5rem">
|
|
<template #body="{ data }">
|
|
<Button
|
|
icon="fa fa-eye"
|
|
severity="secondary"
|
|
text
|
|
rounded
|
|
size="small"
|
|
@click="openLogDetails(data)"
|
|
v-tooltip.top="'Просмотреть подробности'"
|
|
/>
|
|
</template>
|
|
</Column>
|
|
|
|
<Column field="datetime" header="Дата и время" sortable sortField="datetime_raw" style="min-width: 180px">
|
|
<template #body="{ data }">
|
|
<span v-if="data.datetime">{{ data.datetime }}</span>
|
|
<span v-else class="tw:text-gray-400">—</span>
|
|
</template>
|
|
</Column>
|
|
|
|
<Column field="level" header="Уровень" style="min-width: 100px">
|
|
<template #body="{ data }">
|
|
<Badge
|
|
v-if="data.level"
|
|
:value="data.level"
|
|
:severity="getLevelSeverity(data.level)"
|
|
/>
|
|
<span v-else class="tw:text-gray-400">—</span>
|
|
</template>
|
|
</Column>
|
|
|
|
<Column field="channel" header="Канал" style="min-width: 120px">
|
|
<template #body="{ data }">
|
|
<span v-if="data.channel">{{ data.channel }}</span>
|
|
<span v-else class="tw:text-gray-400">—</span>
|
|
</template>
|
|
</Column>
|
|
|
|
<Column field="message" header="Сообщение" style="min-width: 300px">
|
|
<template #body="{ data }">
|
|
<div class="tw:break-words">{{ data.message }}</div>
|
|
</template>
|
|
</Column>
|
|
</DataTable>
|
|
|
|
<Dialog
|
|
v-model:visible="showLogDetailsDialog"
|
|
modal
|
|
header="Подробности лога"
|
|
:style="{ width: '800px', maxWidth: '90vw' }"
|
|
:closable="true"
|
|
:dismissableMask="true"
|
|
>
|
|
<div v-if="selectedLog" class="tw:space-y-4">
|
|
<div>
|
|
<label class="tw:block tw:font-semibold tw:mb-1 tw:text-sm">Дата и время:</label>
|
|
<div class="tw:text-sm">
|
|
<div v-if="selectedLog.datetime">{{ selectedLog.datetime }}</div>
|
|
<div v-if="selectedLog.datetime_raw && selectedLog.datetime_raw !== selectedLog.datetime" class="tw:text-gray-500 tw:text-xs tw:mt-1">
|
|
({{ selectedLog.datetime_raw }})
|
|
</div>
|
|
<span v-if="!selectedLog.datetime" class="tw:text-gray-400">—</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="tw:block tw:font-semibold tw:mb-1 tw:text-sm">Уровень:</label>
|
|
<span
|
|
v-if="selectedLog.level"
|
|
:class="{
|
|
'tw:text-red-600 tw:font-bold': selectedLog.level === 'ERROR' || selectedLog.level === 'CRITICAL',
|
|
'tw:text-orange-600': selectedLog.level === 'WARNING',
|
|
'tw:text-blue-600': selectedLog.level === 'INFO',
|
|
'tw:text-gray-600': selectedLog.level === 'DEBUG',
|
|
}"
|
|
class="tw:text-sm"
|
|
>
|
|
{{ selectedLog.level }}
|
|
</span>
|
|
<span v-else class="tw:text-gray-400 tw:text-sm">—</span>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="tw:block tw:font-semibold tw:mb-1 tw:text-sm">Канал:</label>
|
|
<span v-if="selectedLog.channel" class="tw:text-sm">{{ selectedLog.channel }}</span>
|
|
<span v-else class="tw:text-gray-400 tw:text-sm">—</span>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="tw:block tw:font-semibold tw:mb-1 tw:text-sm">Сообщение:</label>
|
|
<div class="tw:text-sm tw:bg-gray-50 tw:p-3 tw:rounded tw:break-words tw:whitespace-pre-wrap">{{ selectedLog.message || '—' }}</div>
|
|
</div>
|
|
|
|
<div v-if="selectedLog.context">
|
|
<label class="tw:block tw:font-semibold tw:mb-1 tw:text-sm">Контекст:</label>
|
|
<pre class="tw:text-xs tw:bg-gray-100 tw:p-3 tw:rounded tw:overflow-auto tw:max-h-96 tw:border tw:border-gray-200 tw:whitespace-pre-wrap tw:break-words">{{ JSON.stringify(selectedLog.context, null, 2) }}</pre>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="tw:block tw:font-semibold tw:mb-1 tw:text-sm">Исходная строка:</label>
|
|
<pre class="tw:text-xs tw:bg-gray-100 tw:p-3 tw:rounded tw:overflow-auto tw:max-h-48 tw:border tw:border-gray-200 tw:whitespace-pre-wrap tw:break-words">{{ selectedLog.raw }}</pre>
|
|
</div>
|
|
</div>
|
|
|
|
<template #footer>
|
|
<Button
|
|
label="Закрыть"
|
|
icon="fa fa-times"
|
|
severity="secondary"
|
|
@click="closeLogDetailsDialog"
|
|
/>
|
|
</template>
|
|
</Dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { onMounted, ref } from "vue";
|
|
import { useLogsStore } from "@/stores/logs.js";
|
|
import DataTable from "primevue/datatable";
|
|
import Column from "primevue/column";
|
|
import Button from "primevue/button";
|
|
import Dialog from "primevue/dialog";
|
|
import Badge from "primevue/badge";
|
|
|
|
const logs = useLogsStore();
|
|
const showLogDetailsDialog = ref(false);
|
|
const selectedLog = ref(null);
|
|
|
|
function openLogDetails(log) {
|
|
selectedLog.value = log;
|
|
showLogDetailsDialog.value = true;
|
|
}
|
|
|
|
function closeLogDetailsDialog() {
|
|
showLogDetailsDialog.value = false;
|
|
selectedLog.value = null;
|
|
}
|
|
|
|
function getLevelSeverity(level) {
|
|
switch (level) {
|
|
case 'ERROR':
|
|
case 'CRITICAL':
|
|
return 'danger';
|
|
case 'WARNING':
|
|
return 'warn';
|
|
case 'INFO':
|
|
return 'info';
|
|
case 'DEBUG':
|
|
return 'secondary';
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
onMounted(async () => logs.fetchLogsFromServer());
|
|
</script>
|
|
|
|
<style scoped>
|
|
</style>
|