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
+35
View File
@@ -21,6 +21,7 @@ import UiButton from '@/components/ui/UiButton.vue';
import UiInput from '@/components/ui/UiInput.vue';
import UiModal from '@/components/ui/UiModal.vue';
import DealFormView from '@/views/DealFormView.vue';
import SavedFiltersBar from '@/components/SavedFiltersBar.vue';
import type { ImportContactsResult, PipelineBoardDto, PipelineDto } from '@mento/shared';
import { brand } from '@mento/shared';
import { useAuthStore } from '@/stores/auth';
@@ -84,6 +85,34 @@ const visibleStages = computed(() =>
}),
);
const dealsSavedFilters = computed(() => ({
q: search.value.trim() || undefined,
amountMin: amountMin.value || undefined,
amountMax: amountMax.value || undefined,
pipelineId: selectedPipelineId.value || undefined,
viewMode: viewMode.value,
}));
function applyDealsSavedFilters(filters: Record<string, unknown>) {
search.value = typeof filters.q === 'string' ? filters.q : '';
amountMin.value =
filters.amountMin == null || filters.amountMin === ''
? ''
: String(filters.amountMin);
amountMax.value =
filters.amountMax == null || filters.amountMax === ''
? ''
: String(filters.amountMax);
if (filters.viewMode === 'list' || filters.viewMode === 'kanban') {
viewMode.value = filters.viewMode;
}
const nextPipeline =
typeof filters.pipelineId === 'string' ? filters.pipelineId : '';
if (nextPipeline && nextPipeline !== selectedPipelineId.value) {
selectedPipelineId.value = nextPipeline;
}
}
function formatDealDate(iso: string) {
const d = new Date(iso);
if (Number.isNaN(d.getTime())) return iso;
@@ -480,6 +509,12 @@ defineExpose({ updateDealStage: applyUpdateDealStage });
</template>
</PipelineToolbar>
<SavedFiltersBar
scope="deals"
:current-filters="dealsSavedFilters"
@apply="applyDealsSavedFilters"
/>
<p v-if="error" class="error">{{ error }}</p>
<p v-if="importMsg" class="ok">{{ importMsg }}</p>
<p v-else-if="loading && !stages.length" class="muted">در حال بارگذاری کاریز…</p>