From a494b5308e0770b0cd85dfcec035b886b96412bc Mon Sep 17 00:00:00 2001 From: Mahdi Date: Thu, 15 Oct 2026 14:18:56 +0330 Subject: [PATCH] fix: make the user activity log readable and show Montact Co-authored-by: Cursor --- apps/web/src/views/ActivityDetailView.vue | 3 +- apps/web/src/views/AuditLogsView.vue | 721 +++++++++++++++++++--- apps/web/src/views/ProfileView.vue | 2 +- 3 files changed, 630 insertions(+), 96 deletions(-) diff --git a/apps/web/src/views/ActivityDetailView.vue b/apps/web/src/views/ActivityDetailView.vue index a962ab4..80953ba 100644 --- a/apps/web/src/views/ActivityDetailView.vue +++ b/apps/web/src/views/ActivityDetailView.vue @@ -23,6 +23,7 @@ import type { import { useAuthStore } from '@/stores/auth'; import { canReassignRecords } from '@/lib/roles'; import { activityTypeView, typeColorStyle, useActivityTypes } from '@/lib/activity-types'; +import { brand } from '@mento/shared'; const route = useRoute(); const router = useRouter(); @@ -290,7 +291,7 @@ onMounted(() => { - mento + {{ brand.name }}
+ + + +
+ + + ذخیره
+

+ تا پایان این مدت می‌توان مورد را برگرداند. «هرگز» یعنی فقط با حذف کامل از بین می‌رود. +

+ +
+ + + + + + +
+ اعمال فیلتر +
+
+
+ +

{{ okMsg }}

{{ error }}

- +

لطفاً صبر کنید.

+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
زمانانجام‌دهندهنوععنوانشرح
+ {{ formatClockFa(new Date(item.deletedAt)) }} + {{ formatJalaliNumeric(new Date(item.deletedAt)) }} + {{ item.deletedByName || 'سیستم' }}{{ item.modelLabel }} + {{ item.label }} + + {{ deletionStory(item) }} + + + بازگردانی + + + حذف کامل + +
+
+ +
+
@@ -119,52 +444,76 @@ onMounted(() => {
- + - - + + + - - - - + + + - - + + +
زمانزمان کاربر عملیاتمنبعخلاصهموضوعشرح
{{ formatJalaliNumeric(new Date(row.createdAt)) }}{{ row.actor?.fullName ?? '—' }} +
+ {{ formatClockFa(new Date(row.createdAt)) }} + {{ formatJalaliNumeric(new Date(row.createdAt)) }} + {{ row.actor?.fullName ?? '—' }} {{ row.action }} {{ row.entityType ?? '—' }}{{ row.summary }} + + {{ rowName(row) || entityLabel(row.entityType) }} + + + {{ rowStory(row) }} + + +
- -
- - قبلی - - - صفحه {{ toFaDigits(page) }} از {{ toFaDigits(totalPages) }} - · {{ toFaDigits(data.total) }} مورد - - - بعدی - -
+ + + +

+ «{{ purgeItem.label }}» برای همیشه پاک شود؟ بعد از این دیگر قابل بازگشت نیست. +

+ +
@@ -173,49 +522,149 @@ onMounted(() => { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1rem; + min-width: 0; +} +.tabs { + display: flex; + width: 100%; + min-width: 0; + overflow-x: auto; + border-bottom: 1px solid #e2e8f0; +} +.tabs button { + flex: 1 1 0; + min-width: 4.5rem; + border: 0; + background: none; + padding: 0.55rem 0.35rem 0.7rem; + color: #64748b; + font: inherit; + font-weight: 700; + cursor: pointer; + box-shadow: inset 0 -2px 0 transparent; +} +.tabs button.on { + color: #0f766e; + box-shadow: inset 0 -2px 0 #14b8a6; +} +.retention { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 0.6rem; +} +.retention label { + font-weight: 700; +} +.retention select, +.actor { + border: 1px solid #e2e8f0; + border-radius: 10px; + background: #fff; + color: #0f172a; + font: inherit; + padding: 0.45rem 0.7rem; + min-width: 0; + max-width: 100%; +} +.retention select { + width: auto; + min-width: 8.5rem; +} +.actor { + width: 100%; +} +.hint, +.muted { + margin: 0.55rem 0 0; + color: #64748b; + font-size: 0.85rem; } .filters-grid { - display: grid; - grid-template-columns: 1.4fr 1fr auto; - gap: 0.75rem; + display: flex; + flex-wrap: wrap; align-items: end; + gap: 0.75rem; +} +.filters-grid :deep(.ui-field) { + flex: 1 1 14rem; + min-width: 0; +} +.filters-grid :deep(.ui-field:nth-child(2)) { + flex: 0 1 16rem; + max-width: 16rem; } .filters-actions { display: flex; align-items: end; } +.filters-actions :deep(button) { + min-height: 2.4rem; +} +.ok { + margin: 0; + color: #0f766e; + font-weight: 700; +} .error { color: #b91c1c; margin: 0; font-weight: 600; } -.muted { - color: #64748b; - margin: 0; -} .table-wrap { overflow: auto; + max-width: 100%; } table { width: 100%; + min-width: 46rem; border-collapse: collapse; font-size: 0.9rem; + table-layout: fixed; } th, td { text-align: right; padding: 0.65rem 0.55rem; border-bottom: 1px solid #eef2f7; - vertical-align: top; + vertical-align: middle; +} +.when-col, +.when { + width: 6.2rem; +} +.when span { + display: block; + line-height: 1.35; +} +.clock { + font-weight: 800; +} +.actions, +td.ops { + width: 11rem; + text-align: left; +} +.clip { + display: block; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } th { color: #64748b; font-weight: 700; font-size: 0.8rem; + white-space: nowrap; } .nowrap { white-space: nowrap; } +.detail { + color: #334155; + line-height: 1.7; +} .pill { display: inline-flex; padding: 0.15rem 0.55rem; @@ -225,17 +674,101 @@ th { font-weight: 700; font-size: 0.8rem; } -.pager { +.ops { display: flex; - align-items: center; - justify-content: space-between; - gap: 0.75rem; - margin-top: 0.85rem; - flex-wrap: wrap; + justify-content: flex-end; + flex-wrap: nowrap; + gap: 0.4rem; + white-space: nowrap; } -@media (max-width: 860px) { - .filters-grid { - grid-template-columns: 1fr; +tr.link { + cursor: pointer; +} +tr.link:hover td { + background: #f8fffd; +} +.view { + border: 0; + background: none; + padding: 0; + color: #0f766e; + font: inherit; + font-size: 0.85rem; + font-weight: 700; + cursor: pointer; +} +.confirm { + margin: 0; + line-height: 1.8; +} + +@media (max-width: 720px) { + .filters-grid :deep(.ui-field), + .filters-grid :deep(.ui-field:nth-child(2)) { + flex: 1 1 100%; + max-width: none; + } + .filters-actions, + .filters-actions :deep(button) { + width: 100%; + } + .table-wrap { + overflow: visible; + } + table { + min-width: 0; + } + table thead { + display: none; + } + table, + tbody, + tr, + td { + display: block; + width: auto; + } + tbody tr { + border: 1px solid #e7eef2; + border-radius: 14px; + margin-bottom: 0.65rem; + padding: 0.35rem 0.7rem 0.55rem; + background: #fff; + } + td { + display: flex; + justify-content: space-between; + gap: 0.75rem; + border-bottom: 0; + padding: 0.35rem 0; + text-align: start; + } + td::before { + content: attr(data-label); + flex: 0 0 auto; + color: #64748b; + font-size: 0.75rem; + font-weight: 700; + } + td.ops { + justify-content: flex-end; + } + .view { + display: none; + } + tr.link { + cursor: pointer; + } + .when { + flex-direction: column; + align-items: flex-end; + width: auto; + } + .clip { + white-space: normal; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; } } diff --git a/apps/web/src/views/ProfileView.vue b/apps/web/src/views/ProfileView.vue index 54203f9..ea2ebe3 100644 --- a/apps/web/src/views/ProfileView.vue +++ b/apps/web/src/views/ProfileView.vue @@ -470,7 +470,7 @@ watch( - mento + {{ brand.name }}