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:
parent
0a403381c5
commit
169eef90f6
@ -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>
|
||||
|
||||
Reference in New Issue
Block a user