feat(автоподбор): фронт — экран источников конкурента (выбор, ручной источник)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ import AutoFormScreen from './screens/AutoFormScreen.vue';
|
||||
import ManualFormScreen from './screens/ManualFormScreen.vue';
|
||||
import LoadingScreen from './screens/LoadingScreen.vue';
|
||||
import ListScreen from './screens/ListScreen.vue';
|
||||
import DetailScreen from './screens/DetailScreen.vue';
|
||||
|
||||
type ScreenName =
|
||||
| 'entry'
|
||||
@@ -28,6 +29,7 @@ const ctx = reactive({
|
||||
selectedSourceIds: [] as number[],
|
||||
loadMsg: '',
|
||||
loadSub: '',
|
||||
editProjectId: null as number | null,
|
||||
});
|
||||
|
||||
function go(name: ScreenName) {
|
||||
@@ -43,6 +45,7 @@ const screens: Partial<Record<ScreenName, any>> = {
|
||||
manualform: ManualFormScreen,
|
||||
loading: LoadingScreen,
|
||||
list: ListScreen,
|
||||
detail: DetailScreen,
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
@@ -0,0 +1,585 @@
|
||||
<script setup lang="ts">
|
||||
import { inject, onMounted, computed, ref } from 'vue';
|
||||
import { useAutopodborStore } from '../../../stores/autopodborStore';
|
||||
import type { SourceDto } from '../../../api/autopodbor';
|
||||
|
||||
const nav = inject('autopodborNav') as { go: (s: string) => void; ctx: any; screen: any };
|
||||
const store = useAutopodborStore();
|
||||
|
||||
const showAddSource = ref(false);
|
||||
const addSourceRaw = ref('');
|
||||
const addSourceLoading = ref(false);
|
||||
|
||||
onMounted(async () => {
|
||||
if (nav.ctx.competitorId) {
|
||||
await store.loadCompetitor(nav.ctx.competitorId);
|
||||
// Auto-select sources without existing project
|
||||
nav.ctx.selectedSourceIds = store.sources
|
||||
.filter((s: SourceDto) => s.existing_project_id == null)
|
||||
.map((s: SourceDto) => s.id);
|
||||
}
|
||||
});
|
||||
|
||||
const sites = computed(() =>
|
||||
store.sources.filter((s: SourceDto) => s.signal_type === 'site'),
|
||||
);
|
||||
const calls = computed(() =>
|
||||
store.sources.filter((s: SourceDto) => s.signal_type === 'call'),
|
||||
);
|
||||
|
||||
const selectedCount = computed(() => nav.ctx.selectedSourceIds.length);
|
||||
const totalCount = computed(() => store.sources.length);
|
||||
|
||||
function isSelected(id: number): boolean {
|
||||
return nav.ctx.selectedSourceIds.includes(id);
|
||||
}
|
||||
|
||||
function toggleSource(id: number) {
|
||||
const idx = nav.ctx.selectedSourceIds.indexOf(id);
|
||||
if (idx === -1) {
|
||||
nav.ctx.selectedSourceIds.push(id);
|
||||
} else {
|
||||
nav.ctx.selectedSourceIds.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
|
||||
function clearSelection() {
|
||||
nav.ctx.selectedSourceIds = [];
|
||||
}
|
||||
|
||||
function goCreate() {
|
||||
nav.go('create');
|
||||
}
|
||||
|
||||
function editProject(projectId: number) {
|
||||
nav.ctx.editProjectId = projectId;
|
||||
nav.go('editproject');
|
||||
}
|
||||
|
||||
async function doAddSource() {
|
||||
if (!addSourceRaw.value.trim() || !nav.ctx.competitorId) return;
|
||||
addSourceLoading.value = true;
|
||||
try {
|
||||
await store.addSource({ competitor_id: nav.ctx.competitorId, raw: addSourceRaw.value.trim() });
|
||||
addSourceRaw.value = '';
|
||||
showAddSource.value = false;
|
||||
} finally {
|
||||
addSourceLoading.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="ld-detail-screen">
|
||||
<!-- Topbar breadcrumb -->
|
||||
<div class="ld-topbar">
|
||||
<div class="ld-crumb">
|
||||
Автоподбор
|
||||
<template v-if="store.competitor"> · {{ store.competitor.name }}</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ld-detail-content">
|
||||
<!-- Back link -->
|
||||
<button class="ld-back" @click="nav.go('list')">← К списку конкурентов</button>
|
||||
|
||||
<!-- Competitor header -->
|
||||
<template v-if="store.competitor">
|
||||
<div class="ld-chead">
|
||||
<h1 class="ld-chead__name">
|
||||
{{ store.competitor.name }}
|
||||
<span v-if="store.competitor.is_federal" class="ld-badge ld-badge--fed">федеральный</span>
|
||||
</h1>
|
||||
<div v-if="store.competitor.relevance_pct !== null" class="ld-relbox">
|
||||
<div class="ld-relnum rel-100">{{ store.competitor.relevance_pct }}%</div>
|
||||
<div class="ld-rellbl">похожесть</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p v-if="store.competitor.studied_at" class="ld-studied">
|
||||
Изучено {{ store.competitor.studied_at }} · найдено {{ totalCount }} источников
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<!-- Explanatory note -->
|
||||
<div class="ld-note">
|
||||
Отметьте источники, по которым создать проекты. У каждого — ссылка «где нашли».
|
||||
<b>Подменный (с сайта)</b> — номер из коллтрекинга, его набирают клиенты с сайта;
|
||||
<b>настоящий</b> — линия из кода сайта или справочника. Берём оба.
|
||||
<b>Страница показывает актуальное состояние:</b>
|
||||
источники, по которым проект уже создан, помечены «✓ проект создан» — их можно изменить прямо здесь.
|
||||
</div>
|
||||
|
||||
<!-- Sites section -->
|
||||
<div v-if="sites.length" class="ld-sect">
|
||||
<div class="ld-secthd">
|
||||
🌐 Сайты
|
||||
<span class="ld-cnt">· {{ sites.length }} найдено · только головы доменов</span>
|
||||
</div>
|
||||
<div
|
||||
v-for="src in sites"
|
||||
:key="src.id"
|
||||
class="ld-row"
|
||||
:class="{ 'ld-row--used': src.existing_project_id != null }"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
class="ld-cb"
|
||||
:checked="isSelected(src.id)"
|
||||
:disabled="src.existing_project_id != null"
|
||||
@change="toggleSource(src.id)"
|
||||
>
|
||||
<div class="ld-rinfo">
|
||||
<div class="ld-rident ld-rident--site">{{ src.identifier }}</div>
|
||||
<div class="ld-rprov">
|
||||
Где нашли:
|
||||
<a v-if="src.provenance_url" :href="src.provenance_url" target="_blank" rel="noopener">
|
||||
{{ src.provenance_label || src.provenance_url }}
|
||||
</a>
|
||||
<span v-else>{{ src.provenance_label }}</span>
|
||||
</div>
|
||||
<span v-if="src.existing_project_id != null" class="ld-used">✓ проект создан</span>
|
||||
</div>
|
||||
<button
|
||||
v-if="src.existing_project_id != null"
|
||||
class="ld-btn-ghost ld-btn-ghost--sm"
|
||||
@click="editProject(src.existing_project_id!)"
|
||||
>
|
||||
Изменить проект →
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Calls section -->
|
||||
<div v-if="calls.length" class="ld-sect">
|
||||
<div class="ld-secthd">
|
||||
📞 Телефоны
|
||||
<span class="ld-cnt">· {{ calls.length }} найдено</span>
|
||||
</div>
|
||||
<div
|
||||
v-for="src in calls"
|
||||
:key="src.id"
|
||||
class="ld-row"
|
||||
:class="{ 'ld-row--used': src.existing_project_id != null }"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
class="ld-cb"
|
||||
:checked="isSelected(src.id)"
|
||||
:disabled="src.existing_project_id != null"
|
||||
@change="toggleSource(src.id)"
|
||||
>
|
||||
<div class="ld-rinfo">
|
||||
<div class="ld-rident">
|
||||
{{ src.identifier }}
|
||||
<span v-if="src.phone_kind === 'real'" class="ld-tag ld-tag--real">настоящий</span>
|
||||
<span v-if="src.phone_kind === 'substitute'" class="ld-tag ld-tag--sub">подменный · с сайта</span>
|
||||
</div>
|
||||
<div class="ld-rprov">
|
||||
Где нашли:
|
||||
<a v-if="src.provenance_url" :href="src.provenance_url" target="_blank" rel="noopener">
|
||||
{{ src.provenance_label || src.provenance_url }}
|
||||
</a>
|
||||
<span v-else>{{ src.provenance_label }}</span>
|
||||
</div>
|
||||
<span v-if="src.existing_project_id != null" class="ld-used">✓ проект создан</span>
|
||||
</div>
|
||||
<button
|
||||
v-if="src.existing_project_id != null"
|
||||
class="ld-btn-ghost ld-btn-ghost--sm"
|
||||
@click="editProject(src.existing_project_id!)"
|
||||
>
|
||||
Изменить проект →
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Manual source add -->
|
||||
<div class="ld-addbox">
|
||||
<b>Чего-то не хватает?</b>
|
||||
<p>
|
||||
Знаете ещё сайт или номер этого конкурента —
|
||||
<span v-if="!showAddSource" class="ld-addlink" @click="showAddSource = true">
|
||||
добавьте источник вручную
|
||||
</span>
|
||||
<span v-else class="ld-addlink" @click="showAddSource = false">скрыть</span>.
|
||||
</p>
|
||||
<div v-if="showAddSource" class="ld-addsrc">
|
||||
<input
|
||||
v-model="addSourceRaw"
|
||||
class="ld-inp"
|
||||
placeholder="okna-komfort.ru · или +7 843 200-00-00"
|
||||
@keydown.enter="doAddSource"
|
||||
>
|
||||
<button
|
||||
class="ld-btn-primary ld-btn-primary--sm"
|
||||
:disabled="addSourceLoading || !addSourceRaw.trim()"
|
||||
@click="doAddSource"
|
||||
>
|
||||
Добавить источник
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bottom action bar -->
|
||||
<div class="ld-actionbar">
|
||||
<div class="ld-selinfo">
|
||||
Выбрано <b>{{ selectedCount }}</b> из {{ totalCount }} источников
|
||||
</div>
|
||||
<div class="ld-actionbar__btns">
|
||||
<button class="ld-btn-ghost" @click="clearSelection">Снять выбор</button>
|
||||
<button
|
||||
class="ld-btn-primary"
|
||||
:disabled="selectedCount === 0"
|
||||
@click="goCreate"
|
||||
>
|
||||
Создать проекты →
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.ld-detail-screen {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.ld-topbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 0 14px;
|
||||
border-bottom: 1px solid #e8e2d4;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.ld-crumb {
|
||||
font-size: 13px;
|
||||
color: #7a7468;
|
||||
}
|
||||
|
||||
.ld-detail-content {
|
||||
flex: 1;
|
||||
padding-bottom: 80px;
|
||||
}
|
||||
|
||||
.ld-back {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--liderra-teal, #0f6e56);
|
||||
font-size: 13.5px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
margin-bottom: 18px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.ld-back:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.ld-chead {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 16px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.ld-chead__name {
|
||||
font-size: 22px;
|
||||
font-weight: 800;
|
||||
color: #012019;
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.ld-badge {
|
||||
font-size: 11px;
|
||||
border-radius: 4px;
|
||||
padding: 2px 7px;
|
||||
margin-left: 6px;
|
||||
font-weight: 500;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.ld-badge--fed {
|
||||
background: #edf3fb;
|
||||
color: #1a4f8a;
|
||||
border: 1px solid #c5d8ef;
|
||||
}
|
||||
|
||||
.ld-relbox {
|
||||
text-align: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.ld-relnum {
|
||||
font-size: 22px;
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.ld-rellbl {
|
||||
font-size: 11px;
|
||||
color: #9b9484;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.rel-100 { color: var(--liderra-teal, #0f6e56); }
|
||||
.rel-hi { color: #2e7d32; }
|
||||
.rel-mid { color: #b45309; }
|
||||
.rel-low { color: #9b9484; }
|
||||
|
||||
.ld-studied {
|
||||
font-size: 13px;
|
||||
color: #7a7468;
|
||||
margin: 0 0 14px;
|
||||
}
|
||||
|
||||
.ld-note {
|
||||
background: #f6f3ec;
|
||||
border: 1px solid #e8e2d4;
|
||||
border-radius: 8px;
|
||||
padding: 12px 16px;
|
||||
font-size: 13px;
|
||||
color: #4a4540;
|
||||
line-height: 1.55;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.ld-sect {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.ld-secthd {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #012019;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.ld-cnt {
|
||||
font-size: 12.5px;
|
||||
font-weight: 400;
|
||||
color: #9b9484;
|
||||
}
|
||||
|
||||
.ld-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid #e8e2d4;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 6px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.ld-row--used {
|
||||
background: #fbfaf5;
|
||||
}
|
||||
|
||||
.ld-cb {
|
||||
margin-top: 3px;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.ld-cb:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.ld-rinfo {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.ld-rident {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #012019;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.ld-rident--site {
|
||||
color: var(--liderra-teal, #0f6e56);
|
||||
}
|
||||
|
||||
.ld-rprov {
|
||||
font-size: 12px;
|
||||
color: #7a7468;
|
||||
}
|
||||
|
||||
.ld-rprov a {
|
||||
color: var(--liderra-teal, #0f6e56);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.ld-rprov a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.ld-tag {
|
||||
display: inline-block;
|
||||
font-size: 11px;
|
||||
border-radius: 4px;
|
||||
padding: 1px 6px;
|
||||
margin-left: 6px;
|
||||
font-weight: 500;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.ld-tag--real {
|
||||
background: #e8f3ee;
|
||||
color: #0c5a46;
|
||||
border: 1px solid #cfe3da;
|
||||
}
|
||||
|
||||
.ld-tag--sub {
|
||||
background: #fef9ec;
|
||||
color: #8a5c10;
|
||||
border: 1px solid #f0e0b0;
|
||||
}
|
||||
|
||||
.ld-used {
|
||||
display: inline-block;
|
||||
font-size: 11.5px;
|
||||
color: var(--liderra-teal, #0f6e56);
|
||||
font-weight: 600;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.ld-addbox {
|
||||
margin-top: 24px;
|
||||
background: #f6f3ec;
|
||||
border: 1px solid #e8e2d4;
|
||||
border-radius: 10px;
|
||||
padding: 16px 20px;
|
||||
font-size: 13.5px;
|
||||
color: #4a4540;
|
||||
}
|
||||
|
||||
.ld-addbox b {
|
||||
color: #012019;
|
||||
}
|
||||
|
||||
.ld-addbox p {
|
||||
margin: 6px 0 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.ld-addlink {
|
||||
color: var(--liderra-teal, #0f6e56);
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
text-decoration-style: dotted;
|
||||
}
|
||||
|
||||
.ld-addlink:hover {
|
||||
text-decoration-style: solid;
|
||||
}
|
||||
|
||||
.ld-addsrc {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-top: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.ld-inp {
|
||||
flex: 1;
|
||||
min-width: 200px;
|
||||
border: 1.5px solid #d5cfc2;
|
||||
border-radius: 7px;
|
||||
padding: 8px 12px;
|
||||
font-size: 13.5px;
|
||||
color: #012019;
|
||||
background: #fff;
|
||||
outline: none;
|
||||
transition: border-color 150ms;
|
||||
}
|
||||
|
||||
.ld-inp:focus {
|
||||
border-color: var(--liderra-teal, #0f6e56);
|
||||
}
|
||||
|
||||
.ld-actionbar {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: #fff;
|
||||
border-top: 1px solid #e8e2d4;
|
||||
padding: 12px 0;
|
||||
gap: 12px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.ld-selinfo {
|
||||
font-size: 13.5px;
|
||||
color: #4a4540;
|
||||
}
|
||||
|
||||
.ld-actionbar__btns {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ld-btn-primary {
|
||||
background: var(--liderra-teal, #0f6e56);
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 7px;
|
||||
padding: 9px 18px;
|
||||
font-size: 13.5px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: background 180ms ease;
|
||||
}
|
||||
|
||||
.ld-btn-primary:hover:not(:disabled) {
|
||||
background: #0b5a45;
|
||||
}
|
||||
|
||||
.ld-btn-primary:disabled {
|
||||
opacity: 0.45;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.ld-btn-primary--sm {
|
||||
padding: 8px 14px;
|
||||
}
|
||||
|
||||
.ld-btn-ghost {
|
||||
background: transparent;
|
||||
color: var(--liderra-teal, #0f6e56);
|
||||
border: 1.5px solid var(--liderra-teal, #0f6e56);
|
||||
border-radius: 7px;
|
||||
padding: 9px 18px;
|
||||
font-size: 13.5px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: background 180ms ease;
|
||||
}
|
||||
|
||||
.ld-btn-ghost:hover {
|
||||
background: rgba(15, 110, 86, 0.06);
|
||||
}
|
||||
|
||||
.ld-btn-ghost--sm {
|
||||
padding: 7px 12px;
|
||||
font-size: 12.5px;
|
||||
white-space: nowrap;
|
||||
align-self: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,75 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import { createPinia, setActivePinia } from 'pinia';
|
||||
import { createVuetify } from 'vuetify';
|
||||
import { reactive, ref } from 'vue';
|
||||
|
||||
vi.mock('../../resources/js/api/autopodbor');
|
||||
import DetailScreen from '../../resources/js/views/autopodbor/screens/DetailScreen.vue';
|
||||
import { useAutopodborStore } from '../../resources/js/stores/autopodborStore';
|
||||
|
||||
const vuetify = createVuetify();
|
||||
function makeNav(competitorId = 3) {
|
||||
return { go: vi.fn(), ctx: reactive({ runId: null, competitorId, selectedSourceIds: [] as number[], loadMsg: '', loadSub: '', editProjectId: null as number|null }), screen: ref('detail') };
|
||||
}
|
||||
function mountDetail(nav: any) {
|
||||
return mount(DetailScreen, { global: { plugins: [vuetify], provide: { autopodborNav: nav } } });
|
||||
}
|
||||
|
||||
function seed(store: any) {
|
||||
store.competitor = { id: 3, name: 'Окна Комфорт', is_federal: false, relevance_pct: 100, origin: 'auto', site_url: 'okna.ru', directory_urls: [], description: 'd', studied_at: '2026-06-28', study_run_id: 9, search_run_id: 5 };
|
||||
store.sources = [
|
||||
{ id: 11, competitor_id: 3, signal_type: 'site', identifier: 'okna-komfort-kzn.ru', phone_kind: null, provenance_url: null, provenance_label: '2ГИС', created_project_id: null, existing_project_id: null },
|
||||
{ id: 12, competitor_id: 3, signal_type: 'call', identifier: '78432001122', phone_kind: 'real', provenance_url: null, provenance_label: '2ГИС', created_project_id: null, existing_project_id: null },
|
||||
{ id: 13, competitor_id: 3, signal_type: 'call', identifier: '78003507700', phone_kind: 'substitute', provenance_url: null, provenance_label: 'футер', created_project_id: 99, existing_project_id: 99 },
|
||||
];
|
||||
}
|
||||
|
||||
describe('DetailScreen', () => {
|
||||
beforeEach(() => { setActivePinia(createPinia()); vi.clearAllMocks(); });
|
||||
|
||||
it('грузит конкурента и показывает источники', async () => {
|
||||
const store = useAutopodborStore();
|
||||
vi.spyOn(store, 'loadCompetitor').mockImplementation(async () => seed(store));
|
||||
const nav = makeNav(3);
|
||||
const w = mountDetail(nav);
|
||||
await new Promise(r => setTimeout(r, 0));
|
||||
expect(store.loadCompetitor).toHaveBeenCalledWith(3);
|
||||
expect(w.text()).toContain('okna-komfort-kzn.ru');
|
||||
expect(w.text()).toContain('проект создан'); // источник 13 с existing_project_id
|
||||
});
|
||||
|
||||
it('по умолчанию выбраны источники без проекта (11 и 12, не 13)', async () => {
|
||||
const store = useAutopodborStore();
|
||||
vi.spyOn(store, 'loadCompetitor').mockImplementation(async () => seed(store));
|
||||
const nav = makeNav(3);
|
||||
mountDetail(nav);
|
||||
await new Promise(r => setTimeout(r, 0));
|
||||
expect(nav.ctx.selectedSourceIds).toContain(11);
|
||||
expect(nav.ctx.selectedSourceIds).toContain(12);
|
||||
expect(nav.ctx.selectedSourceIds).not.toContain(13);
|
||||
});
|
||||
|
||||
it('«Создать проекты» ведёт на create', async () => {
|
||||
const store = useAutopodborStore();
|
||||
vi.spyOn(store, 'loadCompetitor').mockImplementation(async () => seed(store));
|
||||
const nav = makeNav(3);
|
||||
const w = mountDetail(nav);
|
||||
await new Promise(r => setTimeout(r, 0));
|
||||
const btn = w.findAll('button').find(b => b.text().includes('Создать проекты'));
|
||||
await btn!.trigger('click');
|
||||
expect(nav.go).toHaveBeenCalledWith('create');
|
||||
});
|
||||
|
||||
it('«Изменить проект» у созданного источника ведёт на editproject', async () => {
|
||||
const store = useAutopodborStore();
|
||||
vi.spyOn(store, 'loadCompetitor').mockImplementation(async () => seed(store));
|
||||
const nav = makeNav(3);
|
||||
const w = mountDetail(nav);
|
||||
await new Promise(r => setTimeout(r, 0));
|
||||
const btn = w.findAll('button').find(b => b.text().includes('Изменить проект'));
|
||||
await btn!.trigger('click');
|
||||
expect(nav.ctx.editProjectId).toBe(99);
|
||||
expect(nav.go).toHaveBeenCalledWith('editproject');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user