fix(boards): keep card order inside a column and show activity priority
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -32,6 +32,7 @@ import {
|
||||
import { api } from '@/lib/api';
|
||||
import { formatJalaliNumeric, toFaDigits } from '@/lib/jalali';
|
||||
import { canManageSettings } from '@/lib/roles';
|
||||
import { pointerDropIndex } from '@/lib/pipeline-board';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import type { LeadBoardColumnDto, LeadDto, LeadStageDto } from '@mento/shared';
|
||||
|
||||
@@ -481,28 +482,41 @@ function onDragOver(stageId: string, event: DragEvent) {
|
||||
if (event.dataTransfer) event.dataTransfer.dropEffect = 'move';
|
||||
}
|
||||
|
||||
async function onDrop(stageId: string, event: DragEvent) {
|
||||
async function onDrop(stageId: string, event: DragEvent, index?: number) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const leadId =
|
||||
event.dataTransfer?.getData('text/plain') || draggingId.value || '';
|
||||
draggingId.value = null;
|
||||
dropStageId.value = null;
|
||||
if (!leadId) return;
|
||||
if (!leadId || moving.value) return;
|
||||
|
||||
const fromCol = columns.value.find((c) =>
|
||||
c.leads.some((l) => l.id === leadId),
|
||||
);
|
||||
if (!fromCol || fromCol.stage.id === stageId) return;
|
||||
|
||||
const lead = fromCol.leads.find((l) => l.id === leadId);
|
||||
const target = columns.value.find((c) => c.stage.id === stageId);
|
||||
if (!fromCol || !target) return;
|
||||
const fromIndex = fromCol.leads.findIndex((l) => l.id === leadId);
|
||||
const lead = fromCol.leads[fromIndex];
|
||||
if (!lead) return;
|
||||
|
||||
const same = fromCol.stage.id === stageId;
|
||||
if (same && index == null) return;
|
||||
const without = (same ? fromCol.leads : target.leads).filter((l) => l.id !== leadId);
|
||||
let insertAt = index == null || index < 0 ? 0 : index;
|
||||
if (same && index != null && index > fromIndex) insertAt -= 1;
|
||||
insertAt = Math.max(0, Math.min(insertAt, without.length));
|
||||
if (same && insertAt === fromIndex) return;
|
||||
const nextLeads = [...without];
|
||||
nextLeads.splice(insertAt, 0, { ...lead, stageId, stageName: target.stage.name });
|
||||
|
||||
const prev = columns.value.map((c) => ({
|
||||
...c,
|
||||
leads: [...c.leads],
|
||||
}));
|
||||
|
||||
columns.value = columns.value.map((c) => {
|
||||
if (same && c.stage.id === stageId) return { ...c, leads: nextLeads };
|
||||
if (c.stage.id === fromCol.stage.id) {
|
||||
return {
|
||||
...c,
|
||||
@@ -511,11 +525,7 @@ async function onDrop(stageId: string, event: DragEvent) {
|
||||
};
|
||||
}
|
||||
if (c.stage.id === stageId) {
|
||||
return {
|
||||
...c,
|
||||
total: c.total + 1,
|
||||
leads: [{ ...lead, stageId, stageName: c.stage.name }, ...c.leads],
|
||||
};
|
||||
return { ...c, total: c.total + 1, leads: nextLeads };
|
||||
}
|
||||
return c;
|
||||
});
|
||||
@@ -523,7 +533,7 @@ async function onDrop(stageId: string, event: DragEvent) {
|
||||
moving.value = true;
|
||||
error.value = '';
|
||||
try {
|
||||
await api.patch(`/leads/${leadId}/move`, { stageId });
|
||||
await api.patch(`/leads/${leadId}/move`, { stageId, position: insertAt });
|
||||
} catch {
|
||||
columns.value = prev;
|
||||
error.value = 'جابهجایی لید ناموفق بود.';
|
||||
@@ -543,7 +553,7 @@ onMounted(load);
|
||||
مسیر لیدها
|
||||
</a-typography-title>
|
||||
<a-typography-text type="secondary">
|
||||
کشیدن کارت برای تغییر وضعیت. از منوی هر ستون میتوانید نام، ترتیب و حذف را عوض کنید.
|
||||
کشیدن کارت برای تغییر ستون یا جابهجایی داخل همان ستون. از منوی هر ستون میتوانید نام، ترتیب و حذف را عوض کنید.
|
||||
</a-typography-text>
|
||||
</div>
|
||||
<a-space :size="GAP">
|
||||
@@ -647,9 +657,13 @@ onMounted(load);
|
||||
</div>
|
||||
|
||||
<div :style="columnBodyStyle">
|
||||
<a-card
|
||||
v-for="lead in col.leads"
|
||||
<div
|
||||
v-for="(lead, index) in col.leads"
|
||||
:key="lead.id"
|
||||
@dragover.prevent="onDragOver(col.stage.id, $event)"
|
||||
@drop.stop="onDrop(col.stage.id, $event, pointerDropIndex(index, $event))"
|
||||
>
|
||||
<a-card
|
||||
hoverable
|
||||
:bordered="true"
|
||||
:body-style="cardBodyStyle"
|
||||
@@ -789,6 +803,7 @@ onMounted(load);
|
||||
</a-flex>
|
||||
</a-flex>
|
||||
</a-card>
|
||||
</div>
|
||||
|
||||
<a-typography-text
|
||||
v-if="!col.leads.length"
|
||||
|
||||
@@ -312,11 +312,18 @@ async function onDrop(stageId: string, event: DragEvent, index?: number) {
|
||||
const dealId = raw;
|
||||
if (!dealId || moving.value) return;
|
||||
|
||||
const current = stages.value.find((s) => s.deals.some((d) => d.id === dealId));
|
||||
const currentIndex = current?.deals.findIndex((d) => d.id === dealId) ?? -1;
|
||||
if (current?.id === stageId && (index == null || index === currentIndex)) {
|
||||
return;
|
||||
}
|
||||
const current = stages.value.find((stage) => stage.deals.some((deal) => deal.id === dealId));
|
||||
if (current?.id === stageId && index == null) return;
|
||||
|
||||
const next = updateDealStage(stages.value, dealId, stageId, index);
|
||||
const unchanged = next.every((stage, stageIndex) => {
|
||||
const prev = stages.value[stageIndex];
|
||||
return (
|
||||
stage.deals.length === (prev?.deals.length ?? -1) &&
|
||||
stage.deals.every((deal, dealIndex) => deal.id === prev?.deals[dealIndex]?.id)
|
||||
);
|
||||
});
|
||||
if (unchanged) return;
|
||||
|
||||
await applyUpdateDealStage(dealId, stageId, index);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user