Add deal co-assignees and saved filters on people/pipeline lists.

Deals keep a primary owner plus shared assignees with matching visibility; Contacts and Pipeline can save and reuse filter presets.
This commit is contained in:
2026-09-27 14:25:32 +03:30
parent 00f8b91d78
commit c06c92b333
19 changed files with 553 additions and 20 deletions
+32
View File
@@ -18,6 +18,7 @@ import {
import UiIcon from '@/components/UiIcon.vue';
import PersonFormView from '@/views/PersonFormView.vue';
import CompanyFormView from '@/views/CompanyFormView.vue';
import SavedFiltersBar from '@/components/SavedFiltersBar.vue';
import type {
CompanyDto,
ImportContactsResult,
@@ -65,6 +66,30 @@ const total = computed(() =>
);
const pageCount = computed(() => Math.max(1, Math.ceil(total.value / PAGE_SIZE)));
const peopleSavedFilters = computed(() => ({
q: q.value.trim() || undefined,
sort: sort.value === 'name' ? undefined : sort.value,
mood: moodFilter.value === 'all' ? undefined : moodFilter.value,
}));
function applyPeopleSavedFilters(filters: Record<string, unknown>) {
const nextQ = typeof filters.q === 'string' ? filters.q : '';
q.value = nextQ;
const nextSort = filters.sort === 'newest' ? 'newest' : 'name';
const nextMood =
typeof filters.mood === 'string' &&
PERSON_MOODS.includes(filters.mood as PersonMood)
? (filters.mood as PersonMood)
: 'all';
patchQuery({
q: nextQ.trim() || undefined,
sort: nextSort === 'name' ? undefined : nextSort,
mood: nextMood === 'all' ? undefined : nextMood,
page: undefined,
tab: undefined,
});
}
function moodOf(person: PersonDto): PersonMood {
return person.mood || 'newcomer';
}
@@ -360,6 +385,13 @@ onMounted(load);
</div>
</div>
<SavedFiltersBar
v-if="tab === 'people'"
scope="people"
:current-filters="peopleSavedFilters"
@apply="applyPeopleSavedFilters"
/>
<p v-if="importMsg" class="ok">{{ importMsg }}</p>
<p v-if="error" class="error">{{ error }}</p>
<p v-else-if="loading" class="muted">در حال بارگذاری…</p>