fix: persist and re-apply contact saved filters correctly

This commit is contained in:
2026-10-21 18:46:12 +03:30
parent 50d7cad66e
commit 1c2da34983
2 changed files with 107 additions and 25 deletions
+61 -5
View File
@@ -39,6 +39,8 @@ const busy = ref(false);
const saveOpen = ref(false);
const saveName = ref('');
const saveShared = ref(false);
/** عکس فیلترهای اعمال‌شده در لحظهٔ باز شدن مودال ذخیره */
const saveFilters = ref<Record<string, unknown>>({});
const activeView = computed(
() => views.value.find((v) => v.id === activeId.value) ?? null,
@@ -51,6 +53,41 @@ const selectOptions = computed(() =>
})),
);
const saveFilterCount = computed(() => Object.keys(saveFilters.value).length);
const saveFilterSummary = computed(() => {
const parts: string[] = [];
const f = saveFilters.value;
if (typeof f.q === 'string' && f.q) parts.push(`جستجو: ${f.q}`);
if (typeof f.group === 'string' && f.group) {
parts.push(`گروه (${f.group.split(',').filter(Boolean).length})`);
}
if (typeof f.source === 'string' && f.source) {
parts.push(`منبع (${f.source.split(',').filter(Boolean).length})`);
}
if (typeof f.mood === 'string' && f.mood) {
parts.push(`وضعیت (${f.mood.split(',').filter(Boolean).length})`);
}
if (typeof f.disc === 'string' && f.disc) parts.push(`DISC: ${f.disc}`);
if (typeof f.sort === 'string' && f.sort) parts.push(`مرتب‌سازی: ${f.sort}`);
if (typeof f.viewMode === 'string' && f.viewMode) parts.push(`نمایش: ${f.viewMode}`);
if (typeof f.pipelineId === 'string' && f.pipelineId) parts.push('مسیر فروش');
if (f.amountMin != null && f.amountMin !== '') parts.push(`حداقل مبلغ`);
if (f.amountMax != null && f.amountMax !== '') parts.push(`حداکثر مبلغ`);
return parts.length ? parts.join(' · ') : 'هیچ فیلتری اعمال نشده';
});
/** فقط کلیدهای پر؛ برای JSON و جلوگیری از ذخیرهٔ خالی */
function compactFilters(raw: Record<string, unknown> | null | undefined): Record<string, unknown> {
const out: Record<string, unknown> = {};
for (const [key, value] of Object.entries(raw ?? {})) {
if (value == null || value === '') continue;
if (Array.isArray(value) && value.length === 0) continue;
out[key] = value;
}
return out;
}
async function loadViews() {
loading.value = true;
try {
@@ -71,10 +108,19 @@ function onPick(id: unknown) {
activeId.value = next || undefined;
if (!next) return;
const view = views.value.find((v) => v.id === next);
if (view) emit('apply', view.filters ?? {});
if (!view) return;
// کپی ساده تا مصرف‌کننده همان آبجکت ری‌اکتیو را دستکاری نکند
emit('apply', compactFilters(view.filters ?? {}));
}
function openSave() {
saveFilters.value = compactFilters(props.currentFilters);
if (!Object.keys(saveFilters.value).length) {
message.warning(
'ابتدا فیلترها را از دکمهٔ «فیلتر» اعمال کنید (یا جستجو بزنید)، بعد ذخیره کنید.',
);
return;
}
saveName.value = activeView.value?.name ?? '';
saveShared.value = activeView.value?.isShared ?? false;
saveOpen.value = true;
@@ -83,12 +129,17 @@ function openSave() {
async function saveView() {
const name = saveName.value.trim();
if (name.length < 2 || busy.value) return;
const filters = compactFilters(saveFilters.value);
if (!Object.keys(filters).length) {
message.warning('چیزی برای ذخیره نیست؛ اول فیلتر را روی صفحه اعمال کنید.');
return;
}
busy.value = true;
try {
const body = {
name,
scope: props.scope,
filters: props.currentFilters,
filters,
isShared: saveShared.value,
};
if (activeId.value) {
@@ -160,11 +211,11 @@ onMounted(() => {
:disabled="loading"
:loading="loading"
:options="selectOptions"
:placeholder="compact ? 'فیلتر ذخیره‌شده' : '— انتخاب —'"
:placeholder="compact ? 'فیلتر ذخیره‌شده' : 'فیلتر ذخیره‌شده را انتخاب کنید'"
:style="{ flex: 1, minWidth: 0, width: '100%' }"
@update:value="onPick"
/>
<a-button :disabled="loading" title="ذخیره فیلتر فعلی" @click="openSave">
<a-button :disabled="loading" title="ذخیره فیلتر فعلی صفحه" @click="openSave">
<template #icon><FlagOutlined /></template>
ذخیره
</a-button>
@@ -193,9 +244,14 @@ onMounted(() => {
<a-input
v-model:value="saveName"
:maxlength="120"
placeholder="مثلاً سرنخ‌های این هفته"
placeholder="مثلاً بنکداران بازار"
/>
</a-form-item>
<a-form-item :label="`محتوای فیلتر (${saveFilterCount} مورد)`">
<p :style="{ margin: 0, color: 'var(--ant-color-text-secondary, #64748b)' }">
{{ saveFilterSummary }}
</p>
</a-form-item>
<a-form-item :style="{ marginBottom: 0 }">
<a-checkbox v-model:checked="saveShared">اشتراک با سازمان</a-checkbox>
</a-form-item>