fix: persist and re-apply contact saved filters correctly
This commit is contained in:
@@ -39,6 +39,8 @@ const busy = ref(false);
|
|||||||
const saveOpen = ref(false);
|
const saveOpen = ref(false);
|
||||||
const saveName = ref('');
|
const saveName = ref('');
|
||||||
const saveShared = ref(false);
|
const saveShared = ref(false);
|
||||||
|
/** عکس فیلترهای اعمالشده در لحظهٔ باز شدن مودال ذخیره */
|
||||||
|
const saveFilters = ref<Record<string, unknown>>({});
|
||||||
|
|
||||||
const activeView = computed(
|
const activeView = computed(
|
||||||
() => views.value.find((v) => v.id === activeId.value) ?? null,
|
() => 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() {
|
async function loadViews() {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
@@ -71,10 +108,19 @@ function onPick(id: unknown) {
|
|||||||
activeId.value = next || undefined;
|
activeId.value = next || undefined;
|
||||||
if (!next) return;
|
if (!next) return;
|
||||||
const view = views.value.find((v) => v.id === next);
|
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() {
|
function openSave() {
|
||||||
|
saveFilters.value = compactFilters(props.currentFilters);
|
||||||
|
if (!Object.keys(saveFilters.value).length) {
|
||||||
|
message.warning(
|
||||||
|
'ابتدا فیلترها را از دکمهٔ «فیلتر» اعمال کنید (یا جستجو بزنید)، بعد ذخیره کنید.',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
saveName.value = activeView.value?.name ?? '';
|
saveName.value = activeView.value?.name ?? '';
|
||||||
saveShared.value = activeView.value?.isShared ?? false;
|
saveShared.value = activeView.value?.isShared ?? false;
|
||||||
saveOpen.value = true;
|
saveOpen.value = true;
|
||||||
@@ -83,12 +129,17 @@ function openSave() {
|
|||||||
async function saveView() {
|
async function saveView() {
|
||||||
const name = saveName.value.trim();
|
const name = saveName.value.trim();
|
||||||
if (name.length < 2 || busy.value) return;
|
if (name.length < 2 || busy.value) return;
|
||||||
|
const filters = compactFilters(saveFilters.value);
|
||||||
|
if (!Object.keys(filters).length) {
|
||||||
|
message.warning('چیزی برای ذخیره نیست؛ اول فیلتر را روی صفحه اعمال کنید.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
busy.value = true;
|
busy.value = true;
|
||||||
try {
|
try {
|
||||||
const body = {
|
const body = {
|
||||||
name,
|
name,
|
||||||
scope: props.scope,
|
scope: props.scope,
|
||||||
filters: props.currentFilters,
|
filters,
|
||||||
isShared: saveShared.value,
|
isShared: saveShared.value,
|
||||||
};
|
};
|
||||||
if (activeId.value) {
|
if (activeId.value) {
|
||||||
@@ -160,11 +211,11 @@ onMounted(() => {
|
|||||||
:disabled="loading"
|
:disabled="loading"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:options="selectOptions"
|
:options="selectOptions"
|
||||||
:placeholder="compact ? 'فیلتر ذخیرهشده' : '— انتخاب —'"
|
:placeholder="compact ? 'فیلتر ذخیرهشده' : 'فیلتر ذخیرهشده را انتخاب کنید'"
|
||||||
:style="{ flex: 1, minWidth: 0, width: '100%' }"
|
:style="{ flex: 1, minWidth: 0, width: '100%' }"
|
||||||
@update:value="onPick"
|
@update:value="onPick"
|
||||||
/>
|
/>
|
||||||
<a-button :disabled="loading" title="ذخیره فیلتر فعلی" @click="openSave">
|
<a-button :disabled="loading" title="ذخیره فیلتر فعلی صفحه" @click="openSave">
|
||||||
<template #icon><FlagOutlined /></template>
|
<template #icon><FlagOutlined /></template>
|
||||||
ذخیره
|
ذخیره
|
||||||
</a-button>
|
</a-button>
|
||||||
@@ -193,9 +244,14 @@ onMounted(() => {
|
|||||||
<a-input
|
<a-input
|
||||||
v-model:value="saveName"
|
v-model:value="saveName"
|
||||||
:maxlength="120"
|
:maxlength="120"
|
||||||
placeholder="مثلاً سرنخهای این هفته"
|
placeholder="مثلاً بنکداران بازار"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</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-form-item :style="{ marginBottom: 0 }">
|
||||||
<a-checkbox v-model:checked="saveShared">اشتراک با سازمان</a-checkbox>
|
<a-checkbox v-model:checked="saveShared">اشتراک با سازمان</a-checkbox>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|||||||
@@ -174,32 +174,58 @@ function onPageSize(size: number) {
|
|||||||
if (page.value === 1) void load();
|
if (page.value === 1) void load();
|
||||||
}
|
}
|
||||||
|
|
||||||
const peopleSavedFilters = computed(() => ({
|
const peopleSavedFilters = computed(() => {
|
||||||
q: q.value.trim() || undefined,
|
const out: Record<string, string> = {};
|
||||||
sort: sort.value === 'name' ? undefined : sort.value,
|
const nextQ = q.value.trim();
|
||||||
mood: csv(moodFilters.value),
|
if (nextQ) out.q = nextQ;
|
||||||
source: csv(sourceFilters.value),
|
if (sort.value !== 'name') out.sort = sort.value;
|
||||||
disc: discFilter.value || undefined,
|
const mood = csv(moodFilters.value);
|
||||||
group: csv(groupFilters.value),
|
if (mood) out.mood = mood;
|
||||||
}));
|
const source = csv(sourceFilters.value);
|
||||||
|
if (source) out.source = source;
|
||||||
|
if (discFilter.value) out.disc = discFilter.value;
|
||||||
|
const group = csv(groupFilters.value);
|
||||||
|
if (group) out.group = group;
|
||||||
|
return out;
|
||||||
|
});
|
||||||
|
|
||||||
function savedText(raw: unknown): string | undefined {
|
/** مقدار ذخیرهشده: رشته یا آرایه → رشتهٔ کاماجدا برای URL */
|
||||||
return typeof raw === 'string' && raw.trim() ? raw.trim() : undefined;
|
function savedCsv(raw: unknown): string | undefined {
|
||||||
|
if (Array.isArray(raw)) {
|
||||||
|
const list = raw.map((v) => String(v).trim()).filter(Boolean);
|
||||||
|
return list.length ? list.join(',') : undefined;
|
||||||
|
}
|
||||||
|
if (typeof raw === 'string' && raw.trim()) return raw.trim();
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyPeopleSavedFilters(filters: Record<string, unknown>) {
|
function applyPeopleSavedFilters(filters: Record<string, unknown>) {
|
||||||
const nextQ = typeof filters.q === 'string' ? filters.q : '';
|
const nextQ = typeof filters.q === 'string' ? filters.q : '';
|
||||||
q.value = nextQ;
|
q.value = nextQ;
|
||||||
const nextSort = filters.sort === 'newest' ? 'newest' : 'name';
|
// کلیدهای فیلتر را از نو میسازیم تا فیلتر قبلی روی صفحه نماند
|
||||||
patchQuery({
|
const query: Record<string, string | string[]> = {};
|
||||||
q: nextQ.trim() || undefined,
|
for (const [key, value] of Object.entries(route.query)) {
|
||||||
sort: nextSort === 'name' ? undefined : nextSort,
|
if (['q', 'sort', 'mood', 'source', 'disc', 'group', 'page', 'tab'].includes(key)) continue;
|
||||||
mood: savedText(filters.mood),
|
if (value == null || value === '') continue;
|
||||||
source: savedText(filters.source),
|
if (Array.isArray(value)) {
|
||||||
disc: savedText(filters.disc),
|
const list = value.filter((v): v is string => typeof v === 'string' && v !== '');
|
||||||
group: savedText(filters.group),
|
if (list.length) query[key] = list;
|
||||||
page: undefined,
|
} else if (typeof value === 'string') {
|
||||||
tab: undefined,
|
query[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nextQ.trim()) query.q = nextQ.trim();
|
||||||
|
if (filters.sort === 'newest') query.sort = 'newest';
|
||||||
|
const mood = savedCsv(filters.mood);
|
||||||
|
if (mood) query.mood = mood;
|
||||||
|
const source = savedCsv(filters.source);
|
||||||
|
if (source) query.source = source;
|
||||||
|
const disc = savedCsv(filters.disc);
|
||||||
|
if (disc) query.disc = disc;
|
||||||
|
const group = savedCsv(filters.group);
|
||||||
|
if (group) query.group = group;
|
||||||
|
void router.replace({ name: 'contacts', query }).then(() => {
|
||||||
|
void load();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user