diff --git a/apps/web/src/components/activities/ActivitiesKanban.vue b/apps/web/src/components/activities/ActivitiesKanban.vue index 03e3b61..24c7def 100644 --- a/apps/web/src/components/activities/ActivitiesKanban.vue +++ b/apps/web/src/components/activities/ActivitiesKanban.vue @@ -142,7 +142,12 @@ function toCard(item: ActivityDto, stageId: string): PipelineDeal { title: item.title, description: [activityTypeView(item).name, party].filter(Boolean).join(' · '), amount: null, - date: item.dueAt ? formatRelativeDayLabel(item.dueAt) : 'بدون موعد', + date: + item.status === 'done' + ? 'انجام شده' + : item.dueAt + ? formatRelativeDayLabel(item.dueAt) + : 'بدون موعد', dateIso: item.dueAt ?? undefined, initials: initialsFromTitle(party || item.title), stageId, @@ -152,6 +157,7 @@ function toCard(item: ActivityDto, stageId: string): PipelineDeal { ownerId: item.assignee?.id ?? null, assigneeIds: (item.assignees ?? []).map((a) => a.id), priority: item.priority, + activityStatus: item.status, }; } diff --git a/apps/web/src/components/pipeline/DealCard.vue b/apps/web/src/components/pipeline/DealCard.vue index af9ee84..7663a26 100644 --- a/apps/web/src/components/pipeline/DealCard.vue +++ b/apps/web/src/components/pipeline/DealCard.vue @@ -103,9 +103,11 @@ function onTitleClick() { else emit('open', props.deal.id); } -/** موعد: عقب‌افتاده قرمز · امروز سبز · آینده خاکستری */ -const dueTone = computed<'overdue' | 'today' | 'upcoming' | 'none'>(() => { - if (!props.copy.quickView || !props.deal.dateIso) return 'none'; +/** موعد: انجام‌شده سبز · عقب‌افتاده قرمز · امروز زرد · آینده خاکستری */ +const dueTone = computed<'done' | 'overdue' | 'today' | 'upcoming' | 'none'>(() => { + if (!props.copy.quickView) return 'none'; + if (props.deal.activityStatus === 'done') return 'done'; + if (!props.deal.dateIso) return 'none'; const due = new Date(props.deal.dateIso); if (Number.isNaN(due.getTime())) return 'none'; const days = calendarDaysBetween(new Date(), due); @@ -115,8 +117,9 @@ const dueTone = computed<'overdue' | 'today' | 'upcoming' | 'none'>(() => { }); const dueToneColor = computed(() => { + if (dueTone.value === 'done') return token.value.colorSuccess; if (dueTone.value === 'overdue') return token.value.colorError; - if (dueTone.value === 'today') return token.value.colorSuccess; + if (dueTone.value === 'today') return token.value.colorWarning; return token.value.colorTextSecondary; }); @@ -283,7 +286,13 @@ const cardStyle = computed(() => ({ +{{ extraAssignees }} - + {{ deal.date }} diff --git a/apps/web/src/lib/jalali.ts b/apps/web/src/lib/jalali.ts index 556c2e8..1b542c9 100644 --- a/apps/web/src/lib/jalali.ts +++ b/apps/web/src/lib/jalali.ts @@ -226,7 +226,7 @@ export function formatRelativeContact(iso: string | null | undefined): string { return `${toFaDigits(days)} روز پیش`; } -/** تاریخ نسبی تقویمی برای کارت‌ها: امروز / ۳ روز پیش / ۵ روز مانده */ +/** تاریخ نسبی تقویمی برای کارت‌ها: امروز / ۳ روز عقب افتاده / ۵ روز مانده */ export function formatRelativeDayLabel(iso: string | null | undefined): string { if (!iso) return '—'; const d = new Date(iso); @@ -234,7 +234,7 @@ export function formatRelativeDayLabel(iso: string | null | undefined): string { const daysAhead = calendarDaysBetween(new Date(), d); if (daysAhead === 0) return 'امروز'; if (daysAhead > 0) return `${toFaDigits(daysAhead)} روز مانده`; - return `${toFaDigits(-daysAhead)} روز پیش`; + return `${toFaDigits(-daysAhead)} روز عقب افتاده`; } /** فعالیت بعدی: امروز ۱۶:۳۰ / فردا ۱۰:۰۰ / ۲۴ مرداد ۱۱:۲۰ */ diff --git a/apps/web/src/lib/pipeline-board.ts b/apps/web/src/lib/pipeline-board.ts index 4fec8ec..d77912d 100644 --- a/apps/web/src/lib/pipeline-board.ts +++ b/apps/web/src/lib/pipeline-board.ts @@ -2,6 +2,7 @@ import { currencySuffix } from '@/lib/money'; import { matchesSearch } from '@/lib/search'; import type { ActivityPriority, + ActivityStatus, DealActivityCue, DealActivitySummaryDto, } from '@mento/shared'; @@ -32,6 +33,8 @@ export type PipelineDeal = { searchFields?: Array; /** اولویت فعالیت؛ فقط روی کارت فعالیت نشان داده می‌شود */ priority?: ActivityPriority; + /** وضعیت فعالیت (برای کارت کانبان فعالیت: انجام‌شده و …) */ + activityStatus?: ActivityStatus; /** نشانگر وضعیت فعالیت معامله روی دکمهٔ تقویم */ activityCue?: DealActivityCue; /** خلاصه فعالیت‌ها برای پاپ‌آپ دکمهٔ تقویم */