diff --git a/app/resources/js/components/projects/BulkActionsBar.vue b/app/resources/js/components/projects/BulkActionsBar.vue
index 4ea5166b..afdd6d1f 100644
--- a/app/resources/js/components/projects/BulkActionsBar.vue
+++ b/app/resources/js/components/projects/BulkActionsBar.vue
@@ -29,11 +29,11 @@
- Архивировать
+ Удалить
@@ -92,11 +92,10 @@ const skipToastText = ref('');
const messages: Record = {
pause: 'Приостановить выбранные проекты?',
resume: 'Возобновить выбранные проекты?',
- archive:
- 'Архивировать выбранные проекты?\nДействие необратимо в Plan 5 (восстановление потребует ручного запроса).',
+ delete: 'Удалить выбранные проекты? Действие необратимо. Проекты со сделками будут пропущены.',
};
-async function confirmAndRun(action: 'pause' | 'resume' | 'archive') {
+async function confirmAndRun(action: 'pause' | 'resume' | 'delete') {
if (!window.confirm(messages[action])) return;
await runBulk({ action });
}
diff --git a/app/resources/js/components/projects/ProjectCard.story.vue b/app/resources/js/components/projects/ProjectCard.story.vue
index 8b757eca..c6b6ce71 100644
--- a/app/resources/js/components/projects/ProjectCard.story.vue
+++ b/app/resources/js/components/projects/ProjectCard.story.vue
@@ -9,7 +9,6 @@ const base = {
daily_limit_target: 50,
delivered_today: 32,
is_active: true,
- archived_at: null,
sync_status: 'ok' as const,
};
diff --git a/app/resources/js/components/projects/ProjectCard.vue b/app/resources/js/components/projects/ProjectCard.vue
index 817567cf..2e102bc8 100644
--- a/app/resources/js/components/projects/ProjectCard.vue
+++ b/app/resources/js/components/projects/ProjectCard.vue
@@ -48,9 +48,9 @@
mdi-refresh
Синхронизировать
-
- mdi-archive
- Архивировать
+
+ mdi-delete
+ Удалить
@@ -97,7 +97,7 @@ defineEmits<{
edit: [project: Project];
'toggle-active': [project: Project];
'sync-now': [project: Project];
- archive: [project: Project];
+ delete: [project: Project];
}>();
const typeLabel = computed(() => ({ site: 'Сайт', call: 'Звонок', sms: 'СМС' })[props.project.signal_type]);
diff --git a/app/resources/js/components/projects/ProjectDetailsDrawer.vue b/app/resources/js/components/projects/ProjectDetailsDrawer.vue
index 47b6cc68..81195bfb 100644
--- a/app/resources/js/components/projects/ProjectDetailsDrawer.vue
+++ b/app/resources/js/components/projects/ProjectDetailsDrawer.vue
@@ -63,10 +63,10 @@ async function onPause(): Promise {
async function onDelete(): Promise {
if (!props.project) return;
const ok = window.confirm(
- 'Архивировать проект? Действие необратимо в Plan 5 (восстановление потребует ручного запроса).',
+ 'Удалить проект? Действие необратимо. Если по проекту есть сделки — удаление будет заблокировано.',
);
if (!ok) return;
- await store.archive(props.project.id);
+ await store.del(props.project.id);
emit('close');
}
diff --git a/app/resources/js/plugins/vuetify.ts b/app/resources/js/plugins/vuetify.ts
index 02746fda..e15c09c8 100644
--- a/app/resources/js/plugins/vuetify.ts
+++ b/app/resources/js/plugins/vuetify.ts
@@ -168,6 +168,7 @@ const lucideMap: Record = {
'mdi-content-save-outline': Save,
'mdi-credit-card-outline': CreditCard,
'mdi-currency-rub': RussianRuble,
+ 'mdi-delete': Trash2,
'mdi-delete-outline': Trash2,
'mdi-dots-vertical': MoreVertical,
'mdi-download': Download,
diff --git a/app/resources/js/stores/projectsStore.ts b/app/resources/js/stores/projectsStore.ts
index c4c04b8c..bdd9281e 100644
--- a/app/resources/js/stores/projectsStore.ts
+++ b/app/resources/js/stores/projectsStore.ts
@@ -13,7 +13,6 @@ export interface Project {
delivered_today: number;
delivered_in_month?: number;
is_active: boolean;
- archived_at: string | null;
region_mask?: number;
region_mode?: string;
regions?: number[]; // Plan 6 — subject codes 1..89; пустой массив = вся РФ
@@ -65,7 +64,7 @@ export const useProjectsStore = defineStore('projects', () => {
return data.data;
}
- async function archive(id: number) {
+ async function del(id: number) {
await axios.delete(`/api/projects/${id}`);
await fetch();
}
@@ -94,7 +93,7 @@ export const useProjectsStore = defineStore('projects', () => {
selectedIds.value.clear();
}
- async function bulkAction(action: 'pause' | 'resume' | 'archive') {
+ async function bulkAction(action: 'pause' | 'resume' | 'delete') {
const ids = Array.from(selectedIds.value);
if (!ids.length) return;
await axios.post('/api/projects/bulk', { action, ids });
@@ -103,7 +102,7 @@ export const useProjectsStore = defineStore('projects', () => {
}
interface BulkPayload {
- action: 'pause' | 'resume' | 'archive' | 'update_regions' | 'update_days' | 'update_limit';
+ action: 'pause' | 'resume' | 'delete' | 'update_regions' | 'update_days' | 'update_limit';
add?: number;
remove?: number;
// Plan 6.5 — update_regions оперирует кодами субъектов (1..89), не bitmask ФО.
@@ -200,7 +199,7 @@ export const useProjectsStore = defineStore('projects', () => {
fetch,
create,
update,
- archive,
+ del,
syncNow,
toggleActive,
toggleSelect,
diff --git a/app/resources/js/views/ProjectsView.vue b/app/resources/js/views/ProjectsView.vue
index ff5276c2..b8ba60c6 100644
--- a/app/resources/js/views/ProjectsView.vue
+++ b/app/resources/js/views/ProjectsView.vue
@@ -71,7 +71,7 @@
@edit="openEdit"
@toggle-active="store.toggleActive"
@sync-now="(p: Project) => store.syncNow(p.id)"
- @archive="(p: Project) => store.archive(p.id)"
+ @delete="(p: Project) => store.del(p.id)"
/>
@@ -123,7 +123,6 @@ const typeFilters = [
const statusFilters = [
{ title: 'Активные', value: 'active' },
{ title: 'На паузе', value: 'paused' },
- { title: 'Архивные', value: 'archived' },
];
let searchTimer: ReturnType | null = null;
diff --git a/app/resources/js/views/projects/NewProjectDialog.story.vue b/app/resources/js/views/projects/NewProjectDialog.story.vue
index b7afd52a..f84f33a4 100644
--- a/app/resources/js/views/projects/NewProjectDialog.story.vue
+++ b/app/resources/js/views/projects/NewProjectDialog.story.vue
@@ -25,7 +25,6 @@ const sampleProject = {
daily_limit_target: 50,
delivered_today: 12,
is_active: true,
- archived_at: null,
sync_status: 'ok' as const,
region_mask: 0,
region_mode: 'include' as const,
diff --git a/app/tests/Frontend/BulkActionsBar.spec.ts b/app/tests/Frontend/BulkActionsBar.spec.ts
index da07913d..486bf71a 100644
--- a/app/tests/Frontend/BulkActionsBar.spec.ts
+++ b/app/tests/Frontend/BulkActionsBar.spec.ts
@@ -169,7 +169,7 @@ describe('BulkActionsBar — extended', () => {
expect((wrapper.vm as unknown as { regionsOpen: boolean }).regionsOpen).toBe(true);
});
- it('keeps existing pause/resume/archive buttons', async () => {
+ it('keeps existing pause/resume/delete buttons', async () => {
setActivePinia(createPinia());
vi.mocked(axios.post).mockResolvedValue({ data: { updated: 1, skipped: [], warnings: [] } });
vi.mocked(axios.get).mockResolvedValue({ data: { data: [], meta: { total: 0 } } });
@@ -184,6 +184,6 @@ describe('BulkActionsBar — extended', () => {
});
expect(wrapper.find('[data-testid="bulk-pause"]').exists()).toBe(true);
expect(wrapper.find('[data-testid="bulk-resume"]').exists()).toBe(true);
- expect(wrapper.find('[data-testid="bulk-archive"]').exists()).toBe(true);
+ expect(wrapper.find('[data-testid="bulk-delete"]').exists()).toBe(true);
});
});
diff --git a/app/tests/Frontend/EditProjectDialog.spec.ts b/app/tests/Frontend/EditProjectDialog.spec.ts
index 3b3899a2..470bd98a 100644
--- a/app/tests/Frontend/EditProjectDialog.spec.ts
+++ b/app/tests/Frontend/EditProjectDialog.spec.ts
@@ -23,7 +23,6 @@ const sampleProject = {
daily_limit_target: 10,
delivered_today: 0,
is_active: true,
- archived_at: null,
sync_status: 'ok' as const,
region_mask: 0,
region_mode: 'include',
diff --git a/app/tests/Frontend/ProjectCard.spec.ts b/app/tests/Frontend/ProjectCard.spec.ts
index f5f9eb38..0df50650 100644
--- a/app/tests/Frontend/ProjectCard.spec.ts
+++ b/app/tests/Frontend/ProjectCard.spec.ts
@@ -12,7 +12,6 @@ const baseProject = {
daily_limit_target: 50,
delivered_today: 32,
is_active: true,
- archived_at: null,
sync_status: 'ok' as const,
};
diff --git a/app/tests/Frontend/ProjectCardRedesign.spec.ts b/app/tests/Frontend/ProjectCardRedesign.spec.ts
index 9c7516a2..e15258c2 100644
--- a/app/tests/Frontend/ProjectCardRedesign.spec.ts
+++ b/app/tests/Frontend/ProjectCardRedesign.spec.ts
@@ -11,7 +11,6 @@ const sample = {
is_active: true,
daily_limit_target: 50,
delivered_today: 12,
- archived_at: null,
sync_status: 'ok' as const,
};
diff --git a/app/tests/Frontend/ProjectDetailsDrawer.spec.ts b/app/tests/Frontend/ProjectDetailsDrawer.spec.ts
index e2fd9ff7..4e92d001 100644
--- a/app/tests/Frontend/ProjectDetailsDrawer.spec.ts
+++ b/app/tests/Frontend/ProjectDetailsDrawer.spec.ts
@@ -21,7 +21,6 @@ const sampleProject: Project = {
daily_limit_target: 30,
delivered_today: 0,
is_active: true,
- archived_at: null,
region_mask: 0,
region_mode: 'include',
regions: [],
@@ -152,10 +151,10 @@ describe('ProjectDetailsDrawer', () => {
expect(wrapper.get('[data-testid="pdd-pause"]').text()).toContain('Приостановить');
});
- it('Delete: confirm=true → archive + close emit', async () => {
+ it('Delete: confirm=true → del + close emit', async () => {
const wrapper = mount(ProjectDetailsDrawer, { props: { project: sampleProject } });
const store = useProjectsStore();
- const spy = vi.spyOn(store, 'archive').mockResolvedValueOnce(undefined);
+ const spy = vi.spyOn(store, 'del').mockResolvedValueOnce(undefined);
vi.stubGlobal('confirm', () => true);
await wrapper.get('[data-testid="pdd-delete"]').trigger('click');
@@ -166,10 +165,10 @@ describe('ProjectDetailsDrawer', () => {
vi.unstubAllGlobals();
});
- it('Delete: confirm=false → no archive, no close', async () => {
+ it('Delete: confirm=false → no del, no close', async () => {
const wrapper = mount(ProjectDetailsDrawer, { props: { project: sampleProject } });
const store = useProjectsStore();
- const spy = vi.spyOn(store, 'archive').mockResolvedValueOnce(undefined);
+ const spy = vi.spyOn(store, 'del').mockResolvedValueOnce(undefined);
vi.stubGlobal('confirm', () => false);
await wrapper.get('[data-testid="pdd-delete"]').trigger('click');
diff --git a/app/tests/Frontend/ProjectsView.spec.ts b/app/tests/Frontend/ProjectsView.spec.ts
index 1e198b64..06ccbe62 100644
--- a/app/tests/Frontend/ProjectsView.spec.ts
+++ b/app/tests/Frontend/ProjectsView.spec.ts
@@ -52,7 +52,6 @@ describe('ProjectsView', () => {
daily_limit_target: 10,
delivered_today: 0,
is_active: true,
- archived_at: null,
sync_status: 'ok',
},
],
@@ -82,7 +81,6 @@ describe('ProjectsView', () => {
daily_limit_target: 10,
delivered_today: 0,
is_active: true,
- archived_at: null,
sync_status: 'ok',
},
{
@@ -93,7 +91,6 @@ describe('ProjectsView', () => {
daily_limit_target: 10,
delivered_today: 0,
is_active: true,
- archived_at: null,
sync_status: 'ok',
},
],
@@ -127,7 +124,6 @@ describe('ProjectsView × ProjectDetailsDrawer integration', () => {
daily_limit_target: 10,
delivered_today: 0,
is_active: true,
- archived_at: null,
sync_status: 'ok' as const,
};
const projectB = {
@@ -138,7 +134,6 @@ describe('ProjectsView × ProjectDetailsDrawer integration', () => {
daily_limit_target: 10,
delivered_today: 0,
is_active: true,
- archived_at: null,
sync_status: 'ok' as const,
};
diff --git a/app/tests/Frontend/ProjectsView.toolbar.spec.ts b/app/tests/Frontend/ProjectsView.toolbar.spec.ts
index 4b748974..b46021a2 100644
--- a/app/tests/Frontend/ProjectsView.toolbar.spec.ts
+++ b/app/tests/Frontend/ProjectsView.toolbar.spec.ts
@@ -20,7 +20,6 @@ const mountView = async () => {
daily_limit_target: 100,
delivered_today: 0,
is_active: true,
- archived_at: null,
region_mask: 1,
region_mode: 'include',
delivery_days_mask: 31,
@@ -34,7 +33,6 @@ const mountView = async () => {
daily_limit_target: 100,
delivered_today: 0,
is_active: true,
- archived_at: null,
region_mask: 1,
region_mode: 'include',
delivery_days_mask: 31,
diff --git a/app/tests/Frontend/projectsStore.spec.ts b/app/tests/Frontend/projectsStore.spec.ts
index 387ad11b..9df4cc85 100644
--- a/app/tests/Frontend/projectsStore.spec.ts
+++ b/app/tests/Frontend/projectsStore.spec.ts
@@ -66,6 +66,14 @@ describe('projectsStore (no polling)', () => {
expect(store.selectedIds.has(1)).toBe(false);
});
+ it('del() calls DELETE /api/projects/{id}', async () => {
+ const store = useProjectsStore();
+ vi.spyOn(axios, 'delete').mockResolvedValue({ data: null });
+ vi.spyOn(axios, 'get').mockResolvedValue({ data: { data: [], meta: { total: 0 } } });
+ await store.del(7);
+ expect(axios.delete).toHaveBeenCalledWith('/api/projects/7');
+ });
+
it('bulkAction sends array of ids and clears selection', async () => {
(axios.post as unknown as ReturnType).mockResolvedValue({ data: { updated: 2 } });
(axios.get as unknown as ReturnType).mockResolvedValue({
@@ -104,7 +112,6 @@ describe('projectsStore (polling)', () => {
daily_limit_target: 10,
delivered_today: 0,
is_active: true,
- archived_at: null,
region_mask: 0,
region_mode: 'include',
delivery_days_mask: 127,
@@ -133,7 +140,6 @@ describe('projectsStore (polling)', () => {
daily_limit_target: 10,
delivered_today: 0,
is_active: true,
- archived_at: null,
region_mask: 0,
region_mode: 'include',
delivery_days_mask: 127,