feat: separate prior records behind an owner switch and count last-period questions
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { RouterLink, useRoute, useRouter } from 'vue-router';
|
||||
import { api } from '@/lib/api';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { formatCompactMoney, formatMoney } from '@/lib/money';
|
||||
import {
|
||||
calendarDaysBetween,
|
||||
@@ -60,6 +61,7 @@ type TimelineRow = {
|
||||
tone: TimelineTone;
|
||||
href: string;
|
||||
at: number;
|
||||
prior?: boolean;
|
||||
};
|
||||
|
||||
type AttachmentRow = {
|
||||
@@ -180,6 +182,27 @@ const previousSourceLabel = computed(() => {
|
||||
return SOURCE_LABELS[src] || src;
|
||||
});
|
||||
|
||||
const auth = useAuthStore();
|
||||
const priorArchiveOn = computed(() => Boolean(auth.user?.priorArchive));
|
||||
|
||||
function isPriorActivity(row: ActivityDto) {
|
||||
if (row.importSource !== 'didar') return false;
|
||||
if (row.status === 'open' && row.dueAt && new Date(row.dueAt).getTime() > Date.now()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function isPriorDeal(row: DealDto) {
|
||||
if (row.importSource !== 'didar') return false;
|
||||
if (
|
||||
row.status === 'open' &&
|
||||
row.expectedCloseAt &&
|
||||
new Date(row.expectedCloseAt).getTime() > Date.now()
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const lastCallAt = computed(() => {
|
||||
const calls = activities.value
|
||||
.filter((a) => a.type === 'call')
|
||||
@@ -210,6 +233,12 @@ const nextActivity = computed(() => {
|
||||
});
|
||||
|
||||
const openDeals = computed(() => deals.value.filter((d) => d.status === 'open'));
|
||||
const currentDeals = computed(() =>
|
||||
priorArchiveOn.value ? deals.value.filter((d) => !isPriorDeal(d)) : deals.value,
|
||||
);
|
||||
const priorDeals = computed(() =>
|
||||
priorArchiveOn.value ? deals.value.filter((d) => isPriorDeal(d)) : [],
|
||||
);
|
||||
|
||||
const lastQuote = computed(
|
||||
() =>
|
||||
@@ -308,6 +337,7 @@ const timeline = computed<TimelineRow[]>(() => {
|
||||
tone: activityTone(a),
|
||||
href: `/activities/${a.id}`,
|
||||
at,
|
||||
prior: isPriorActivity(a),
|
||||
});
|
||||
}
|
||||
for (const n of notes.value) {
|
||||
@@ -340,7 +370,17 @@ const visibleTimeline = computed(() => {
|
||||
historyFilter.value === 'all'
|
||||
? timeline.value
|
||||
: timeline.value.filter((row) => row.tone === historyFilter.value);
|
||||
return rows.slice(0, 8);
|
||||
const current = priorArchiveOn.value ? rows.filter((row) => !row.prior) : rows;
|
||||
return current.slice(0, 8);
|
||||
});
|
||||
|
||||
const priorTimeline = computed(() => {
|
||||
if (!priorArchiveOn.value) return [];
|
||||
const rows =
|
||||
historyFilter.value === 'all'
|
||||
? timeline.value
|
||||
: timeline.value.filter((row) => row.tone === historyFilter.value);
|
||||
return rows.filter((row) => row.prior).slice(0, 8);
|
||||
});
|
||||
|
||||
function fileKind(name: string, mime: string): AttachmentRow['kind'] {
|
||||
@@ -442,7 +482,7 @@ async function load() {
|
||||
api.get<PaginatedResponse<MemoryItemDto>>('/memory', {
|
||||
params: { personId: id.value, limit: 50 },
|
||||
}),
|
||||
api.get<PipelineBoardDto>('/pipelines/board'),
|
||||
api.get<PipelineBoardDto>('/pipelines/board', { params: { prior: 'all' } }),
|
||||
]);
|
||||
person.value = personRes.data;
|
||||
activities.value = actRes.data.items;
|
||||
@@ -832,7 +872,24 @@ watch(() => route.query.tab, readTab, { immediate: true });
|
||||
</RouterLink>
|
||||
</li>
|
||||
</ol>
|
||||
<p v-else class="empty">موردی با این فیلتر نیست.</p>
|
||||
<p v-else-if="!priorTimeline.length" class="empty">موردی با این فیلتر نیست.</p>
|
||||
<template v-if="priorTimeline.length">
|
||||
<h3 class="prior-head">بایگانی اطلاعات قبل</h3>
|
||||
<ol class="tl">
|
||||
<li v-for="row in priorTimeline" :key="row.key">
|
||||
<RouterLink :to="row.href">
|
||||
<span class="dot" :class="row.tone">
|
||||
<UiIcon :name="timelineIcon(row.tone)" :size="14" />
|
||||
</span>
|
||||
<div>
|
||||
<time>{{ row.when }}</time>
|
||||
<strong>{{ row.title }}</strong>
|
||||
<p v-if="row.body">{{ row.body }}</p>
|
||||
</div>
|
||||
</RouterLink>
|
||||
</li>
|
||||
</ol>
|
||||
</template>
|
||||
<RouterLink class="see-all" :to="{ name: 'activities', query: { filter: 'all' } }">
|
||||
مشاهده همه فعالیتها
|
||||
</RouterLink>
|
||||
@@ -896,7 +953,7 @@ watch(() => route.query.tab, readTab, { immediate: true });
|
||||
/>
|
||||
<div v-if="!dealsEmpty">
|
||||
<RouterLink
|
||||
v-for="deal in deals"
|
||||
v-for="deal in currentDeals"
|
||||
:key="deal.id"
|
||||
class="row-card"
|
||||
:to="{ name: 'deal-detail', params: { id: deal.id } }"
|
||||
@@ -905,6 +962,19 @@ watch(() => route.query.tab, readTab, { immediate: true });
|
||||
<span>{{ deal.amount != null ? formatCompactMoney(deal.amount, deal.currency) : 'بدون مبلغ' }}</span>
|
||||
<em>{{ dealStatusLabel[deal.status] ?? deal.status }}</em>
|
||||
</RouterLink>
|
||||
<div v-if="priorDeals.length" class="subblock">
|
||||
<h3>بایگانی اطلاعات قبل</h3>
|
||||
<RouterLink
|
||||
v-for="deal in priorDeals"
|
||||
:key="deal.id"
|
||||
class="row-card"
|
||||
:to="{ name: 'deal-detail', params: { id: deal.id } }"
|
||||
>
|
||||
<strong>{{ deal.title }}</strong>
|
||||
<span>{{ deal.amount != null ? formatCompactMoney(deal.amount, deal.currency) : 'بدون مبلغ' }}</span>
|
||||
<em>{{ dealStatusLabel[deal.status] ?? deal.status }}</em>
|
||||
</RouterLink>
|
||||
</div>
|
||||
<div v-if="invoices.length" class="subblock">
|
||||
<h3>فاکتورها</h3>
|
||||
<RouterLink
|
||||
|
||||
@@ -584,6 +584,19 @@ onMounted(() => {
|
||||
حرفهای (چندشاخه، شرط روی پاسخ فرم، تقسیم نوبتی)
|
||||
</label>
|
||||
</div>
|
||||
<div class="mod-group">
|
||||
<div class="mod-group-head">
|
||||
<span>بایگانی اطلاعات قبل</span>
|
||||
</div>
|
||||
<label class="mod-item">
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="moduleDraft.includes('prior_data_archive')"
|
||||
@change="toggleModule('prior_data_archive')"
|
||||
/>
|
||||
بایگانی اطلاعات قبل
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chat-settings">
|
||||
|
||||
Reference in New Issue
Block a user