ux(audit): auto-filter, drop diff column and actor filter

- Removed the "Фильтр" button; entity changes apply immediately, the
  entity_id input is debounced (250ms) and runs the same fetch.
- Removed the actor filter input — kept entity + entity_id only.
- Removed the DIFF column and the per-row expand/collapse mechanism.
  Diff JSON is no longer surfaced in the UI (backend still returns
  it; reachable via curl when needed).
This commit is contained in:
Telecom 2026-05-22 13:34:03 +05:00
parent 0a403381c5
commit 169eef90f6

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, onMounted, reactive, ref } from 'vue';
import { computed, onMounted, reactive, ref, watch } from 'vue';
import { useRouter } from 'vue-router';
import Skeleton from '@/components/Skeleton.vue';
import { listAudit, type AuditEntry } from '@/api/audit';
@ -8,10 +8,9 @@ import { useToast } from '@/composables/useToast';
const toast = useToast();
const router = useRouter();
const filters = reactive<{ entity: string; entity_id: string; actor: string }>({
const filters = reactive<{ entity: string; entity_id: string }>({
entity: '',
entity_id: '',
actor: '',
});
const entries = ref<AuditEntry[]>([]);
@ -32,21 +31,12 @@ const ACTION_LABELS: Record<string, string> = {
recalc: 'пересчёт score',
};
const expanded = ref<Set<string>>(new Set());
function toggleExpand(id: string) {
if (expanded.value.has(id)) expanded.value.delete(id);
else expanded.value.add(id);
expanded.value = new Set(expanded.value);
}
async function load() {
loading.value = true;
try {
const r = await listAudit({
entity: filters.entity || undefined,
entity_id: filters.entity_id || undefined,
actor: filters.actor || undefined,
limit: 200,
});
entries.value = r.data;
@ -60,28 +50,26 @@ async function load() {
function reset() {
filters.entity = '';
filters.entity_id = '';
filters.actor = '';
load();
}
// Auto-filter: react to entity change immediately, debounce entity_id input.
let idTimer: number | null = null;
watch(
() => filters.entity,
() => load(),
);
watch(
() => filters.entity_id,
() => {
if (idTimer !== null) window.clearTimeout(idTimer);
idTimer = window.setTimeout(load, 250);
},
);
function fmtTime(s: string): string {
return new Date(s).toLocaleString('ru-RU');
}
function hasDiff(e: AuditEntry): boolean {
if (e.diff === null || e.diff === undefined) return false;
if (typeof e.diff === 'object' && Object.keys(e.diff as object).length === 0) return false;
return true;
}
function diffString(e: AuditEntry): string {
try {
return JSON.stringify(e.diff, null, 2);
} catch {
return String(e.diff);
}
}
function gotoEntity(e: AuditEntry) {
if (e.entity === 'lead') {
router.push({ name: 'lead-card', params: { id: e.entity_id } });
@ -102,10 +90,7 @@ onMounted(load);
</p>
</div>
<form
class="card-pad grid grid-cols-1 md:grid-cols-4 gap-3"
@submit.prevent="load"
>
<div class="card-pad grid grid-cols-1 md:grid-cols-[1fr_2fr_auto] gap-3 items-end">
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">Сущность</label>
<select v-model="filters.entity" class="input-base text-sm">
@ -124,22 +109,10 @@ onMounted(load);
class="input-base text-sm"
/>
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">Кто (actor)</label>
<input
v-model="filters.actor"
type="text"
placeholder="username"
class="input-base text-sm"
/>
</div>
<div class="flex items-end gap-2">
<button type="submit" class="btn-primary text-sm">Фильтр</button>
<button type="button" class="btn-ghost text-sm" @click="reset">
Сброс
</button>
</div>
</form>
<div v-if="loading" class="card p-4">
<Skeleton :rows="6" height="36px" />
@ -156,14 +129,12 @@ onMounted(load);
<tr>
<th class="w-44">Когда</th>
<th class="w-28">Кто</th>
<th class="w-24">Сущность</th>
<th class="w-28">Сущность</th>
<th>Действие · ID</th>
<th class="w-24 text-right">Diff</th>
</tr>
</thead>
<tbody>
<template v-for="e in entries" :key="e.id">
<tr class="hover:bg-gray-50/60">
<tr v-for="e in entries" :key="e.id" class="hover:bg-gray-50/60">
<td class="px-4 py-2 text-xs text-gray-600 tabular-nums">
{{ fmtTime(e.created_at) }}
</td>
@ -192,26 +163,7 @@ onMounted(load);
{{ e.entity_id }}
</span>
</td>
<td class="px-4 py-2 text-right">
<button
v-if="hasDiff(e)"
type="button"
class="text-xs text-gray-500 hover:text-gray-900"
@click="toggleExpand(e.id)"
>
{{ expanded.has(e.id) ? 'Скрыть' : 'Показать' }}
</button>
<span v-else class="text-xs text-gray-300">—</span>
</td>
</tr>
<tr v-if="expanded.has(e.id) && hasDiff(e)">
<td colspan="5" class="px-4 py-2 bg-gray-50 border-b border-gray-100">
<pre
class="text-[11px] text-gray-700 whitespace-pre-wrap font-mono"
>{{ diffString(e) }}</pre>
</td>
</tr>
</template>
</tbody>
</table>
</div>