feat: keep deletions restorable and confirm a pipeline's deals before it is removed
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -20,6 +20,9 @@ const pipelines = ref<PipelineListItem[]>([]);
|
||||
const name = ref('');
|
||||
const mergeOpen = ref(false);
|
||||
const mergeSourceId = ref<string | null>(null);
|
||||
const deleteTarget = ref<PipelineListItem | null>(null);
|
||||
const deleteCountReady = ref(false);
|
||||
const deleting = ref(false);
|
||||
|
||||
const canMerge = computed(() => pipelines.value.length >= 2);
|
||||
|
||||
@@ -67,6 +70,61 @@ async function createPipeline() {
|
||||
}
|
||||
}
|
||||
|
||||
function deletePrompt(pipeline: PipelineListItem) {
|
||||
if (!deleteCountReady.value) return 'در حال شمارش معاملات این مسیر…';
|
||||
const count = pipeline.dealCount ?? 0;
|
||||
const name = pipeline.name;
|
||||
if (count > 0) {
|
||||
return `مسیر «${name}» شامل ${toFaDigits(count)} معامله است. با حذف، این معاملات هم پاک میشوند. از حذف مطمئن هستید؟`;
|
||||
}
|
||||
return `مسیر «${name}» معاملهای ندارد. از حذف آن مطمئن هستید؟`;
|
||||
}
|
||||
|
||||
async function openDelete(pipeline: PipelineListItem) {
|
||||
deleteTarget.value = pipeline;
|
||||
deleteCountReady.value = pipeline.dealCount != null;
|
||||
if (deleteCountReady.value) return;
|
||||
try {
|
||||
const { data } = await api.get<{ dealCount: number }>(
|
||||
`/pipelines/${pipeline.id}/merge-preview`,
|
||||
);
|
||||
if (deleteTarget.value?.id !== pipeline.id) return;
|
||||
deleteTarget.value = { ...pipeline, dealCount: data.dealCount };
|
||||
} catch (e) {
|
||||
if (deleteTarget.value?.id === pipeline.id) {
|
||||
error.value = apiError(e, 'شمارش معاملات این مسیر ناموفق بود.');
|
||||
deleteTarget.value = null;
|
||||
}
|
||||
return;
|
||||
} finally {
|
||||
if (deleteTarget.value?.id === pipeline.id) deleteCountReady.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
function closeDelete() {
|
||||
if (deleting.value) return;
|
||||
deleteTarget.value = null;
|
||||
deleteCountReady.value = false;
|
||||
}
|
||||
|
||||
async function confirmDelete() {
|
||||
const pipeline = deleteTarget.value;
|
||||
if (!pipeline || deleting.value) return;
|
||||
deleting.value = true;
|
||||
error.value = '';
|
||||
okMsg.value = '';
|
||||
try {
|
||||
await api.delete(`/pipelines/${pipeline.id}`);
|
||||
okMsg.value = 'کاریز حذف شد.';
|
||||
deleteTarget.value = null;
|
||||
await load();
|
||||
} catch (e) {
|
||||
error.value = apiError(e, 'حذف کاریز ناموفق بود.');
|
||||
} finally {
|
||||
deleting.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function openMerge(pipeline: PipelineListItem) {
|
||||
if (!canMerge.value) return;
|
||||
mergeSourceId.value = pipeline.id;
|
||||
@@ -142,6 +200,9 @@ onMounted(load);
|
||||
>
|
||||
ادغام
|
||||
</UiButton>
|
||||
<UiButton size="sm" variant="danger" @click="openDelete(pipeline)">
|
||||
حذف
|
||||
</UiButton>
|
||||
</div>
|
||||
</div>
|
||||
</UiCard>
|
||||
@@ -153,6 +214,25 @@ onMounted(load);
|
||||
description="اولین مسیر فروش را اضافه کنید."
|
||||
/>
|
||||
|
||||
<UiModal
|
||||
:open="!!deleteTarget"
|
||||
title="حذف کاریز"
|
||||
@close="closeDelete"
|
||||
>
|
||||
<p v-if="deleteTarget" class="confirm">{{ deletePrompt(deleteTarget) }}</p>
|
||||
<template #footer>
|
||||
<UiButton variant="ghost" :disabled="deleting" @click="closeDelete">انصراف</UiButton>
|
||||
<UiButton
|
||||
variant="danger"
|
||||
:loading="deleting"
|
||||
:disabled="!deleteCountReady"
|
||||
@click="confirmDelete"
|
||||
>
|
||||
حذف کاریز
|
||||
</UiButton>
|
||||
</template>
|
||||
</UiModal>
|
||||
|
||||
<UiModal :open="mergeOpen" title="ادغام کاریز" @close="closeMerge">
|
||||
<PipelineMergeWizard
|
||||
:open="mergeOpen"
|
||||
@@ -242,6 +322,12 @@ onMounted(load);
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.confirm {
|
||||
margin: 0;
|
||||
line-height: 1.8;
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
.ok {
|
||||
color: #0f766e;
|
||||
margin: 0;
|
||||
|
||||
Reference in New Issue
Block a user