import { ref, computed } from 'vue' import type { AuditLog } from '~/services/dto/audit-log' import { fetchAuditLogs, type AuditLogFilters } from '~/services/audit-logs' type Range = { start: string, end: string } | null export const useAuditLogsList = () => { const items = ref([]) const total = ref(0) const page = ref(1) const perPage = ref(10) const loading = ref(false) const filterOpen = ref(false) // Applied filters (drive the fetch) const appliedEmployee = ref('') const appliedRange = ref(null) const appliedEntityTypes = ref([]) const appliedActions = ref([]) const appliedUsername = ref('') const appliedIp = ref('') const appliedDevice = ref('') // Draft filters (edited inside the drawer) const draftEmployee = ref('') const draftRange = ref(null) const draftEntityTypes = ref([]) const draftActions = ref([]) const draftUsername = ref('') const draftIp = ref('') const draftDevice = ref('') const activeFilterCount = computed(() => { let n = 0 if (appliedEmployee.value.trim() !== '') n++ if (appliedRange.value?.start || appliedRange.value?.end) n++ if (appliedEntityTypes.value.length > 0) n++ if (appliedActions.value.length > 0) n++ if (appliedUsername.value.trim() !== '') n++ if (appliedIp.value.trim() !== '') n++ if (appliedDevice.value.trim() !== '') n++ return n }) const buildFilters = (): AuditLogFilters => ({ employee: appliedEmployee.value.trim() || undefined, from: appliedRange.value?.start || undefined, to: appliedRange.value?.end || undefined, entityType: appliedEntityTypes.value.length > 0 ? [...appliedEntityTypes.value] : undefined, action: appliedActions.value.length > 0 ? [...appliedActions.value] : undefined, username: appliedUsername.value.trim() || undefined, ip: appliedIp.value.trim() || undefined, device: appliedDevice.value.trim() || undefined, page: page.value, perPage: perPage.value, }) // Race guard: only the latest request may commit its result. let requestSeq = 0 const load = async () => { const seq = ++requestSeq loading.value = true try { const result = await fetchAuditLogs(buildFilters()) if (seq !== requestSeq) return items.value = result.items total.value = result.total page.value = result.page perPage.value = result.perPage } finally { if (seq === requestSeq) loading.value = false } } const init = async () => { await load() } const goToPage = (n: number) => { page.value = n load() } const setPerPage = (n: number) => { perPage.value = n page.value = 1 load() } const openFilters = () => { draftEmployee.value = appliedEmployee.value draftRange.value = appliedRange.value ? { ...appliedRange.value } : null draftEntityTypes.value = [...appliedEntityTypes.value] draftActions.value = [...appliedActions.value] draftUsername.value = appliedUsername.value draftIp.value = appliedIp.value draftDevice.value = appliedDevice.value filterOpen.value = true } const applyFilters = () => { appliedEmployee.value = draftEmployee.value appliedRange.value = draftRange.value ? { ...draftRange.value } : null appliedEntityTypes.value = [...draftEntityTypes.value] appliedActions.value = [...draftActions.value] appliedUsername.value = draftUsername.value appliedIp.value = draftIp.value appliedDevice.value = draftDevice.value page.value = 1 filterOpen.value = false load() } const resetFilters = () => { draftEmployee.value = '' draftRange.value = null draftEntityTypes.value = [] draftActions.value = [] draftUsername.value = '' draftIp.value = '' draftDevice.value = '' appliedEmployee.value = '' appliedRange.value = null appliedEntityTypes.value = [] appliedActions.value = [] appliedUsername.value = '' appliedIp.value = '' appliedDevice.value = '' page.value = 1 load() // drawer stays open } const toggle = (arr: typeof draftEntityTypes, value: string, selected: boolean) => { arr.value = selected ? [...arr.value, value] : arr.value.filter(v => v !== value) } const toggleEntityType = (value: string, selected: boolean) => toggle(draftEntityTypes, value, selected) const toggleAction = (value: string, selected: boolean) => toggle(draftActions, value, selected) return { items, total, page, perPage, loading, filterOpen, activeFilterCount, draftEmployee, draftRange, draftEntityTypes, draftActions, draftUsername, draftIp, draftDevice, init, goToPage, setPerPage, openFilters, applyFilters, resetFilters, toggleEntityType, toggleAction, } }