Compare commits

..

No commits in common. "b79e99246eaf4ba10d0ccf8e6bda64c056be98f5" and "7a4f574a38733144e527c4f0b470000720090653" have entirely different histories.

View File

@ -17,9 +17,9 @@ const entries = ref<AuditEntry[]>([]);
const loading = ref(false); const loading = ref(false);
const ENTITY_LABELS: Record<string, string> = { const ENTITY_LABELS: Record<string, string> = {
lead: 'Лида', lead: 'лида',
user: 'Пользователя', user: 'пользователя',
system: 'Систему', system: 'систему',
}; };
interface ActionMeta { interface ActionMeta {
@ -29,12 +29,12 @@ interface ActionMeta {
} }
const ACTIONS: Record<string, ActionMeta> = { const ACTIONS: Record<string, ActionMeta> = {
create: { label: 'создал', tone: 'success', icon: '+' }, create: { label: 'создал', tone: 'success', icon: '+' },
delete: { label: 'удалил', tone: 'danger', icon: '×' }, delete: { label: 'удалил', tone: 'danger', icon: '🗑' },
reassign: { label: 'переназначил', tone: 'warning', icon: '↻' }, reassign: { label: 'переназначил', tone: 'warning', icon: '↻' },
reset_password: { label: 'сменил пароль', tone: 'warning', icon: '⚿' }, reset_password: { label: 'сменил пароль', tone: 'warning', icon: '🔑' },
change_role: { label: 'изменил роль', tone: 'warning', icon: '⚙' }, change_role: { label: 'изменил роль', tone: 'warning', icon: '👤' },
recalc: { label: 'пересчитал score', tone: 'neutral', icon: '∑' }, recalc: { label: 'пересчитал score', tone: 'neutral', icon: '⟳' },
}; };
function actionMeta(a: string): ActionMeta { function actionMeta(a: string): ActionMeta {
@ -132,6 +132,11 @@ const grouped = computed(() => {
return groups; return groups;
}); });
function initials(name: string): string {
const parts = name.split(/[\s._-]+/).filter(Boolean).slice(0, 2);
return parts.map((p) => p[0]?.toUpperCase() ?? '').join('') || name[0]?.toUpperCase() || '?';
}
function shortId(id: string): string { function shortId(id: string): string {
return id.length > 10 ? id.slice(0, 8) + '…' : id; return id.length > 10 ? id.slice(0, 8) + '…' : id;
} }
@ -189,26 +194,26 @@ onMounted(load);
> >
Событий не найдено. Событий не найдено.
</div> </div>
<div v-else class="space-y-6"> <div v-else class="space-y-8">
<section <div
v-for="group in grouped" v-for="group in grouped"
:key="group.day" :key="group.day"
class="space-y-2" class="space-y-3"
>
<h2
class="text-[10px] font-semibold uppercase tracking-[0.18em] text-gray-400 px-1"
> >
<div class="sticky top-16 z-10 bg-gradient-to-b from-white via-white to-white/0 pb-1">
<div class="text-[11px] font-semibold uppercase tracking-widest text-gray-400">
{{ group.day }} {{ group.day }}
</h2> </div>
</div>
<div class="card divide-y divide-gray-100"> <div class="card divide-y divide-gray-100">
<div <div
v-for="e in group.items" v-for="e in group.items"
:key="e.id" :key="e.id"
class="flex items-center gap-3 px-4 py-3 hover:bg-gray-50/70 transition" class="flex items-center gap-4 px-4 py-3 hover:bg-gray-50/70 transition"
> >
<div <div
class="w-8 h-8 rounded-full flex items-center justify-center text-sm font-semibold ring-1 shrink-0 leading-none" class="w-9 h-9 rounded-full flex items-center justify-center text-base ring-1 shrink-0"
:class="[ :class="[
TONE_CLASSES[actionMeta(e.action).tone].bg, TONE_CLASSES[actionMeta(e.action).tone].bg,
TONE_CLASSES[actionMeta(e.action).tone].ring, TONE_CLASSES[actionMeta(e.action).tone].ring,
@ -219,37 +224,39 @@ onMounted(load);
{{ actionMeta(e.action).icon }} {{ actionMeta(e.action).icon }}
</div> </div>
<p <div class="flex items-center gap-2 shrink-0">
class="flex-1 min-w-0 text-sm text-gray-700 leading-snug truncate" <div
class="w-7 h-7 rounded-full bg-gray-100 text-gray-700 flex items-center justify-center text-[11px] font-semibold"
:title="e.actor"
> >
<span class="font-semibold text-gray-900">{{ e.actor }}</span> {{ initials(e.actor) }}
<span class="mx-1.5">{{ actionMeta(e.action).label }}</span> </div>
<span class="text-gray-500">{{ ENTITY_LABELS[e.entity] ?? e.entity }}</span> <span class="text-sm font-medium text-gray-900">{{ e.actor }}</span>
</div>
<div class="flex-1 min-w-0 text-sm text-gray-700 truncate">
<span>{{ actionMeta(e.action).label }}</span>
<span class="text-gray-500"> {{ ENTITY_LABELS[e.entity] ?? e.entity }} </span>
<button <button
v-if="e.entity === 'lead'" v-if="e.entity === 'lead'"
type="button" type="button"
class="ml-1.5 font-mono text-xs text-sky-600 hover:underline align-middle" class="font-mono text-sky-600 hover:underline"
@click="gotoEntity(e)" @click="gotoEntity(e)"
> >
{{ shortId(e.entity_id) }} {{ shortId(e.entity_id) }}
</button> </button>
<span <span v-else class="font-mono text-gray-600">{{ e.entity_id }}</span>
v-else </div>
class="ml-1.5 font-mono text-xs text-gray-500 align-middle"
>
{{ e.entity_id }}
</span>
</p>
<time <div
class="text-[11px] text-gray-400 tabular-nums shrink-0 leading-none" class="text-xs text-gray-400 tabular-nums shrink-0"
:title="fmtFullTime(e.created_at)" :title="fmtFullTime(e.created_at)"
> >
{{ relativeTime(e.created_at) }} {{ relativeTime(e.created_at) }}
</time>
</div> </div>
</div> </div>
</section> </div>
</div>
</div> </div>
</div> </div>
</template> </template>