feat(profile): add counterparty card with dadata search and cart gating
This commit is contained in:
@@ -1,42 +1,136 @@
|
||||
<script setup lang="ts">
|
||||
import { useMutation, useQuery } from '@vue/apollo-composable';
|
||||
import { MeDocument, MyMessengerConnectionsDocument, RegisterSelfDocument } from '~/composables/graphql/generated';
|
||||
import {
|
||||
MeDocument,
|
||||
MyCounterpartyProfileDocument,
|
||||
MyMessengerConnectionsDocument,
|
||||
RegisterSelfDocument,
|
||||
UpsertMyCounterpartyProfileDocument,
|
||||
} from '~/composables/graphql/generated';
|
||||
import { buildMessengerBotStartUrl } from '~/composables/useMessengerBotLink';
|
||||
import { isCounterpartyProfileComplete } from '~/composables/useCounterpartyProfile';
|
||||
|
||||
type MessengerItem = {
|
||||
type: 'TELEGRAM' | 'MAX';
|
||||
isActive: boolean;
|
||||
channelId: string;
|
||||
};
|
||||
|
||||
type PartySuggestion = {
|
||||
value: string;
|
||||
unrestricted_value?: string;
|
||||
data?: {
|
||||
inn?: string;
|
||||
kpp?: string;
|
||||
ogrn?: string;
|
||||
address?: { value?: string };
|
||||
management?: {
|
||||
name?: string;
|
||||
post?: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
type BankSuggestion = {
|
||||
value: string;
|
||||
unrestricted_value?: string;
|
||||
data?: {
|
||||
bic?: string;
|
||||
correspondent_account?: string;
|
||||
};
|
||||
};
|
||||
|
||||
const companyName = ref('');
|
||||
const inn = ref('');
|
||||
const contactName = ref('');
|
||||
const email = ref('');
|
||||
const config = useRuntimeConfig();
|
||||
|
||||
const registerMutation = useMutation(RegisterSelfDocument);
|
||||
const registerForm = reactive({
|
||||
companyName: '',
|
||||
inn: '',
|
||||
contactName: '',
|
||||
email: '',
|
||||
});
|
||||
|
||||
const counterpartyForm = reactive({
|
||||
companyName: '',
|
||||
companyFullName: '',
|
||||
inn: '',
|
||||
kpp: '',
|
||||
ogrn: '',
|
||||
legalAddress: '',
|
||||
bankName: '',
|
||||
bik: '',
|
||||
correspondentAccount: '',
|
||||
checkingAccount: '',
|
||||
signerFullName: '',
|
||||
signerPosition: '',
|
||||
signerBasis: '',
|
||||
});
|
||||
|
||||
const registerFeedback = ref('');
|
||||
const registerFeedbackTone = ref<'success' | 'error'>('success');
|
||||
const profileFeedback = ref('');
|
||||
const profileFeedbackTone = ref<'success' | 'error'>('success');
|
||||
|
||||
const meQuery = useQuery(MeDocument);
|
||||
const profileQuery = useQuery(MyCounterpartyProfileDocument);
|
||||
const connectionsQuery = useQuery(MyMessengerConnectionsDocument);
|
||||
|
||||
const message = ref('');
|
||||
const messageTone = ref<'success' | 'error'>('success');
|
||||
const registerMutation = useMutation(RegisterSelfDocument, { throws: 'never' });
|
||||
const saveCounterpartyMutation = useMutation(UpsertMyCounterpartyProfileDocument, { throws: 'never' });
|
||||
|
||||
registerMutation.onDone(() => {
|
||||
message.value = 'Заявка на регистрацию отправлена менеджеру';
|
||||
messageTone.value = 'success';
|
||||
});
|
||||
const companySearch = ref('');
|
||||
const partySuggestions = ref<PartySuggestion[]>([]);
|
||||
const partyLoading = ref(false);
|
||||
const partyOpen = ref(false);
|
||||
const partySearchTimer = ref<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
registerMutation.onError((error) => {
|
||||
message.value = error.message;
|
||||
messageTone.value = 'error';
|
||||
});
|
||||
const bankSearch = ref('');
|
||||
const bankSuggestions = ref<BankSuggestion[]>([]);
|
||||
const bankLoading = ref(false);
|
||||
const bankOpen = ref(false);
|
||||
const bankSearchTimer = ref<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
const partyDropdownRef = ref<HTMLElement | null>(null);
|
||||
const bankDropdownRef = ref<HTMLElement | null>(null);
|
||||
|
||||
watch(
|
||||
() => profileQuery.result.value?.myCounterpartyProfile,
|
||||
(profile) => {
|
||||
if (!profile) {
|
||||
return;
|
||||
}
|
||||
|
||||
counterpartyForm.companyName = profile.companyName;
|
||||
counterpartyForm.companyFullName = profile.companyFullName;
|
||||
counterpartyForm.inn = profile.inn;
|
||||
counterpartyForm.kpp = profile.kpp ?? '';
|
||||
counterpartyForm.ogrn = profile.ogrn ?? '';
|
||||
counterpartyForm.legalAddress = profile.legalAddress;
|
||||
counterpartyForm.bankName = profile.bankName;
|
||||
counterpartyForm.bik = profile.bik;
|
||||
counterpartyForm.correspondentAccount = profile.correspondentAccount;
|
||||
counterpartyForm.checkingAccount = profile.checkingAccount;
|
||||
counterpartyForm.signerFullName = profile.signerFullName;
|
||||
counterpartyForm.signerPosition = profile.signerPosition;
|
||||
counterpartyForm.signerBasis = profile.signerBasis;
|
||||
|
||||
companySearch.value = profile.companyName;
|
||||
bankSearch.value = profile.bankName;
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
const profileUpdatedAt = computed(() => profileQuery.result.value?.myCounterpartyProfile?.updatedAt ?? null);
|
||||
const profileIsComplete = computed(() => isCounterpartyProfileComplete(counterpartyForm));
|
||||
|
||||
const telegramConnection = computed(() =>
|
||||
connectionsQuery.result.value?.myMessengerConnections?.find(
|
||||
(item: { type: 'TELEGRAM' | 'MAX'; isActive: boolean; channelId: string }) =>
|
||||
item.type === 'TELEGRAM' && item.isActive,
|
||||
(item: MessengerItem) => item.type === 'TELEGRAM' && item.isActive,
|
||||
),
|
||||
);
|
||||
|
||||
const maxConnection = computed(() =>
|
||||
connectionsQuery.result.value?.myMessengerConnections?.find(
|
||||
(item: { type: 'TELEGRAM' | 'MAX'; isActive: boolean; channelId: string }) =>
|
||||
item.type === 'MAX' && item.isActive,
|
||||
(item: MessengerItem) => item.type === 'MAX' && item.isActive,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -52,37 +146,221 @@ function buildBotConnectUrl(baseUrl: string) {
|
||||
const telegramConnectUrl = computed(() => buildBotConnectUrl(config.public.telegramBotUrl || ''));
|
||||
const maxConnectUrl = computed(() => buildBotConnectUrl(config.public.maxBotUrl || ''));
|
||||
|
||||
function register() {
|
||||
message.value = '';
|
||||
registerMutation.mutate({
|
||||
function clearPartyTimer() {
|
||||
if (!partySearchTimer.value) {
|
||||
return;
|
||||
}
|
||||
clearTimeout(partySearchTimer.value);
|
||||
partySearchTimer.value = null;
|
||||
}
|
||||
|
||||
function clearBankTimer() {
|
||||
if (!bankSearchTimer.value) {
|
||||
return;
|
||||
}
|
||||
clearTimeout(bankSearchTimer.value);
|
||||
bankSearchTimer.value = null;
|
||||
}
|
||||
|
||||
async function fetchPartySuggestions() {
|
||||
const query = companySearch.value.trim();
|
||||
if (query.length < 2) {
|
||||
partySuggestions.value = [];
|
||||
partyOpen.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
partyLoading.value = true;
|
||||
await $fetch<{ suggestions: PartySuggestion[] }>('/api/dadata/party', {
|
||||
method: 'POST',
|
||||
body: { query },
|
||||
})
|
||||
.then((response) => {
|
||||
partySuggestions.value = response.suggestions || [];
|
||||
partyOpen.value = partySuggestions.value.length > 0;
|
||||
})
|
||||
.finally(() => {
|
||||
partyLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
async function fetchBankSuggestions() {
|
||||
const query = bankSearch.value.trim();
|
||||
if (query.length < 2) {
|
||||
bankSuggestions.value = [];
|
||||
bankOpen.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
bankLoading.value = true;
|
||||
await $fetch<{ suggestions: BankSuggestion[] }>('/api/dadata/bank', {
|
||||
method: 'POST',
|
||||
body: { query },
|
||||
})
|
||||
.then((response) => {
|
||||
bankSuggestions.value = response.suggestions || [];
|
||||
bankOpen.value = bankSuggestions.value.length > 0;
|
||||
})
|
||||
.finally(() => {
|
||||
bankLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function schedulePartySuggest() {
|
||||
clearPartyTimer();
|
||||
partySearchTimer.value = setTimeout(() => {
|
||||
void fetchPartySuggestions();
|
||||
}, 250);
|
||||
}
|
||||
|
||||
function scheduleBankSuggest() {
|
||||
clearBankTimer();
|
||||
bankSearchTimer.value = setTimeout(() => {
|
||||
void fetchBankSuggestions();
|
||||
}, 250);
|
||||
}
|
||||
|
||||
function applyPartySuggestion(item: PartySuggestion) {
|
||||
partyOpen.value = false;
|
||||
companySearch.value = item.value;
|
||||
|
||||
counterpartyForm.companyName = item.value;
|
||||
counterpartyForm.companyFullName = item.unrestricted_value || item.value;
|
||||
counterpartyForm.inn = item.data?.inn || '';
|
||||
counterpartyForm.kpp = item.data?.kpp || '';
|
||||
counterpartyForm.ogrn = item.data?.ogrn || '';
|
||||
counterpartyForm.legalAddress = item.data?.address?.value || '';
|
||||
|
||||
if (!counterpartyForm.signerFullName && item.data?.management?.name) {
|
||||
counterpartyForm.signerFullName = item.data.management.name;
|
||||
}
|
||||
if (!counterpartyForm.signerPosition && item.data?.management?.post) {
|
||||
counterpartyForm.signerPosition = item.data.management.post;
|
||||
}
|
||||
}
|
||||
|
||||
function applyBankSuggestion(item: BankSuggestion) {
|
||||
bankOpen.value = false;
|
||||
bankSearch.value = item.value;
|
||||
|
||||
counterpartyForm.bankName = item.value;
|
||||
counterpartyForm.bik = item.data?.bic || '';
|
||||
counterpartyForm.correspondentAccount = item.data?.correspondent_account || '';
|
||||
}
|
||||
|
||||
function closeDropdownsFromOutside(event: MouseEvent) {
|
||||
const target = event.target as Node | null;
|
||||
if (partyDropdownRef.value && target && !partyDropdownRef.value.contains(target)) {
|
||||
partyOpen.value = false;
|
||||
}
|
||||
if (bankDropdownRef.value && target && !bankDropdownRef.value.contains(target)) {
|
||||
bankOpen.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function registerSelf() {
|
||||
registerFeedback.value = '';
|
||||
const result = await registerMutation.mutate({
|
||||
input: {
|
||||
companyName: companyName.value,
|
||||
inn: inn.value || null,
|
||||
contactName: contactName.value,
|
||||
email: email.value,
|
||||
companyName: registerForm.companyName,
|
||||
inn: registerForm.inn.trim() ? registerForm.inn.trim() : null,
|
||||
contactName: registerForm.contactName,
|
||||
email: registerForm.email,
|
||||
},
|
||||
});
|
||||
|
||||
const payload = result?.data?.registerSelf;
|
||||
if (!payload) {
|
||||
registerFeedbackTone.value = 'error';
|
||||
registerFeedback.value = registerMutation.error.value?.message || 'Не удалось отправить заявку.';
|
||||
return;
|
||||
}
|
||||
|
||||
registerFeedbackTone.value = 'success';
|
||||
registerFeedback.value = 'Заявка на регистрацию отправлена менеджеру.';
|
||||
}
|
||||
|
||||
async function saveCounterpartyProfile() {
|
||||
profileFeedback.value = '';
|
||||
const result = await saveCounterpartyMutation.mutate({
|
||||
input: {
|
||||
companyName: counterpartyForm.companyName,
|
||||
companyFullName: counterpartyForm.companyFullName,
|
||||
inn: counterpartyForm.inn,
|
||||
kpp: counterpartyForm.kpp.trim() ? counterpartyForm.kpp.trim() : null,
|
||||
ogrn: counterpartyForm.ogrn.trim() ? counterpartyForm.ogrn.trim() : null,
|
||||
legalAddress: counterpartyForm.legalAddress,
|
||||
bankName: counterpartyForm.bankName,
|
||||
bik: counterpartyForm.bik,
|
||||
correspondentAccount: counterpartyForm.correspondentAccount,
|
||||
checkingAccount: counterpartyForm.checkingAccount,
|
||||
signerFullName: counterpartyForm.signerFullName,
|
||||
signerPosition: counterpartyForm.signerPosition,
|
||||
signerBasis: counterpartyForm.signerBasis,
|
||||
},
|
||||
});
|
||||
|
||||
const payload = result?.data?.upsertMyCounterpartyProfile;
|
||||
if (!payload) {
|
||||
profileFeedbackTone.value = 'error';
|
||||
profileFeedback.value = saveCounterpartyMutation.error.value?.message || 'Не удалось сохранить карточку контрагента.';
|
||||
return;
|
||||
}
|
||||
|
||||
profileFeedbackTone.value = 'success';
|
||||
profileFeedback.value = 'Карточка контрагента сохранена.';
|
||||
await profileQuery.refetch();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener('click', closeDropdownsFromOutside);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
document.removeEventListener('click', closeDropdownsFromOutside);
|
||||
clearPartyTimer();
|
||||
clearBankTimer();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="space-y-6">
|
||||
<div>
|
||||
<h1 class="text-3xl font-extrabold text-[#0f2f20]">Профиль</h1>
|
||||
<p class="mt-1 text-sm text-[#28543f]/80">Регистрация компании и подключение каналов уведомлений.</p>
|
||||
<p class="mt-1 text-sm text-[#28543f]/80">Заполните карточку контрагента, чтобы можно было оформлять заявки из корзины.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-4 lg:grid-cols-2">
|
||||
<div class="surface-card rounded-3xl p-5">
|
||||
<h2 class="text-xl font-bold text-[#123824]">Самостоятельная регистрация</h2>
|
||||
<div class="mt-4 space-y-3">
|
||||
<input v-model="companyName" type="text" placeholder="Компания" class="input input-bordered w-full border-[#d0e8d8] bg-white/80">
|
||||
<input v-model="inn" type="text" placeholder="ИНН" class="input input-bordered w-full border-[#d0e8d8] bg-white/80">
|
||||
<input v-model="contactName" type="text" placeholder="Контактное лицо" class="input input-bordered w-full border-[#d0e8d8] bg-white/80">
|
||||
<input v-model="email" type="email" placeholder="Email" class="input input-bordered w-full border-[#d0e8d8] bg-white/80">
|
||||
<button class="btn w-full border-0 bg-[#139957] text-white hover:bg-[#0d854a]" :disabled="registerMutation.loading.value" @click="register">
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">Компания</legend>
|
||||
<input v-model="registerForm.companyName" type="text" class="input input-bordered w-full" placeholder="ООО Пример" >
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">ИНН</legend>
|
||||
<input v-model="registerForm.inn" type="text" class="input input-bordered w-full" placeholder="7701234567" >
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">Контактное лицо</legend>
|
||||
<input v-model="registerForm.contactName" type="text" class="input input-bordered w-full" placeholder="Иванов Иван" >
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">E-mail</legend>
|
||||
<input v-model="registerForm.email" type="email" class="input input-bordered w-full" placeholder="name@company.com" >
|
||||
</fieldset>
|
||||
|
||||
<button class="btn btn-primary w-full" :disabled="registerMutation.loading.value" @click="registerSelf">
|
||||
{{ registerMutation.loading.value ? 'Отправляем…' : 'Отправить заявку' }}
|
||||
</button>
|
||||
|
||||
<div v-if="registerFeedback" class="alert" :class="registerFeedbackTone === 'success' ? 'alert-success' : 'alert-error'">
|
||||
{{ registerFeedback }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -124,12 +402,182 @@ function register() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="message"
|
||||
class="alert"
|
||||
:class="messageTone === 'success' ? 'alert-success' : 'alert-error'"
|
||||
>
|
||||
{{ message }}
|
||||
<div class="surface-card rounded-3xl p-5">
|
||||
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||
<h2 class="text-xl font-bold text-[#123824]">Карточка контрагента</h2>
|
||||
<span class="badge" :class="profileIsComplete ? 'badge-success' : 'badge-warning'">
|
||||
{{ profileIsComplete ? 'Заполнена' : 'Не заполнена' }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 grid gap-4 xl:grid-cols-3">
|
||||
<div class="rounded-2xl border border-base-300 bg-base-100 p-4">
|
||||
<h3 class="mb-3 text-base font-bold">1. Контрагент (Dadata)</h3>
|
||||
|
||||
<div ref="partyDropdownRef" class="relative">
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">Поиск компании</legend>
|
||||
<input
|
||||
v-model="companySearch"
|
||||
type="text"
|
||||
class="input input-bordered w-full"
|
||||
placeholder="Введите название или ИНН"
|
||||
@input="schedulePartySuggest"
|
||||
@focus="partyOpen = partySuggestions.length > 0"
|
||||
>
|
||||
</fieldset>
|
||||
|
||||
<span v-if="partyLoading" class="loading loading-spinner loading-sm absolute right-3 top-1/2 -translate-y-1/2" />
|
||||
|
||||
<div
|
||||
v-if="partyOpen && partySuggestions.length > 0"
|
||||
class="absolute z-30 mt-2 max-h-72 w-full overflow-auto rounded-box border border-base-300 bg-base-100 p-2 shadow-xl"
|
||||
>
|
||||
<button
|
||||
v-for="item in partySuggestions"
|
||||
:key="`${item.value}-${item.data?.inn || ''}`"
|
||||
type="button"
|
||||
class="btn btn-ghost mb-1 h-auto min-h-0 w-full justify-start whitespace-normal px-3 py-2 text-left"
|
||||
@click="applyPartySuggestion(item)"
|
||||
>
|
||||
<span>
|
||||
<span class="block text-sm font-semibold">{{ item.value }}</span>
|
||||
<span class="block text-xs opacity-70">ИНН: {{ item.data?.inn || '—' }} <span v-if="item.data?.kpp">• КПП: {{ item.data.kpp }}</span></span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">Краткое наименование</legend>
|
||||
<input v-model="counterpartyForm.companyName" type="text" class="input input-bordered w-full" >
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">Полное наименование</legend>
|
||||
<input v-model="counterpartyForm.companyFullName" type="text" class="input input-bordered w-full" >
|
||||
</fieldset>
|
||||
|
||||
<div class="grid gap-3 sm:grid-cols-3">
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">ИНН</legend>
|
||||
<input v-model="counterpartyForm.inn" type="text" class="input input-bordered w-full" >
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">КПП</legend>
|
||||
<input v-model="counterpartyForm.kpp" type="text" class="input input-bordered w-full" >
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">ОГРН</legend>
|
||||
<input v-model="counterpartyForm.ogrn" type="text" class="input input-bordered w-full" >
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">Юридический адрес</legend>
|
||||
<textarea v-model="counterpartyForm.legalAddress" class="textarea textarea-bordered min-h-24 w-full" />
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<div class="rounded-2xl border border-base-300 bg-base-100 p-4">
|
||||
<h3 class="mb-3 text-base font-bold">2. Банк (Dadata)</h3>
|
||||
|
||||
<div ref="bankDropdownRef" class="relative">
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">Поиск банка</legend>
|
||||
<input
|
||||
v-model="bankSearch"
|
||||
type="text"
|
||||
class="input input-bordered w-full"
|
||||
placeholder="Введите название банка"
|
||||
@input="scheduleBankSuggest"
|
||||
@focus="bankOpen = bankSuggestions.length > 0"
|
||||
>
|
||||
</fieldset>
|
||||
|
||||
<span v-if="bankLoading" class="loading loading-spinner loading-sm absolute right-3 top-1/2 -translate-y-1/2" />
|
||||
|
||||
<div
|
||||
v-if="bankOpen && bankSuggestions.length > 0"
|
||||
class="absolute z-30 mt-2 max-h-72 w-full overflow-auto rounded-box border border-base-300 bg-base-100 p-2 shadow-xl"
|
||||
>
|
||||
<button
|
||||
v-for="item in bankSuggestions"
|
||||
:key="`${item.value}-${item.data?.bic || ''}`"
|
||||
type="button"
|
||||
class="btn btn-ghost mb-1 h-auto min-h-0 w-full justify-start whitespace-normal px-3 py-2 text-left"
|
||||
@click="applyBankSuggestion(item)"
|
||||
>
|
||||
<span>
|
||||
<span class="block text-sm font-semibold">{{ item.value }}</span>
|
||||
<span class="block text-xs opacity-70">БИК: {{ item.data?.bic || '—' }}</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">Банк</legend>
|
||||
<input v-model="counterpartyForm.bankName" type="text" class="input input-bordered w-full" >
|
||||
</fieldset>
|
||||
|
||||
<div class="grid gap-3 sm:grid-cols-2">
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">БИК</legend>
|
||||
<input v-model="counterpartyForm.bik" type="text" class="input input-bordered w-full" >
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">Корр. счет</legend>
|
||||
<input v-model="counterpartyForm.correspondentAccount" type="text" class="input input-bordered w-full" >
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">Расчетный счет</legend>
|
||||
<input v-model="counterpartyForm.checkingAccount" type="text" class="input input-bordered w-full" >
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<div class="rounded-2xl border border-base-300 bg-base-100 p-4">
|
||||
<h3 class="mb-3 text-base font-bold">3. Подписант и основание</h3>
|
||||
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">ФИО подписанта</legend>
|
||||
<input v-model="counterpartyForm.signerFullName" type="text" class="input input-bordered w-full" placeholder="Иванов Иван Иванович" >
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">Должность</legend>
|
||||
<input v-model="counterpartyForm.signerPosition" type="text" class="input input-bordered w-full" placeholder="Генеральный директор" >
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">Основание полномочий</legend>
|
||||
<textarea v-model="counterpartyForm.signerBasis" class="textarea textarea-bordered min-h-24 w-full" placeholder="Действует на основании Устава" />
|
||||
</fieldset>
|
||||
|
||||
<button class="btn btn-primary mt-4 w-full" :disabled="saveCounterpartyMutation.loading.value || !profileIsComplete" @click="saveCounterpartyProfile">
|
||||
{{ saveCounterpartyMutation.loading.value ? 'Сохраняем…' : 'Сохранить карточку' }}
|
||||
</button>
|
||||
|
||||
<p v-if="profileUpdatedAt" class="mt-2 text-xs opacity-70">Обновлено: {{ new Date(profileUpdatedAt).toLocaleString() }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="profileFeedback" class="alert mt-4" :class="profileFeedbackTone === 'success' ? 'alert-success' : 'alert-error'">
|
||||
{{ profileFeedback }}
|
||||
</div>
|
||||
|
||||
<div class="alert mt-4" :class="profileIsComplete ? 'alert-success' : 'alert-warning'">
|
||||
{{
|
||||
profileIsComplete
|
||||
? 'Карточка контрагента заполнена. Оформление заявки в корзине доступно.'
|
||||
: 'Пока карточка не заполнена полностью, оформление заявки в корзине будет заблокировано.'
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user