Files
tp/main_dc/yalarba/easySite/app/pages/profile/edit.vue
T
valitovgaziz 2941b14b38 flatten easySite directory: remove extra easySite/easySite nesting
- Moved contents of main_dc/yalarba/easySite/easySite/ up to easySite/
- Updated docker-compose.yml build context path
- Deleted empty nested easySite/ directory
2026-06-12 11:16:15 +05:00

413 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="profile-edit-page">
<div class="container container-large">
<div class="page-header">
<h1 class="page-title">Редактирование профиля</h1>
<p class="page-subtitle">Обновите информацию о вашем аккаунте</p>
</div>
<div v-if="auth.user.value" class="profile-layout">
<!-- Основная форма редактирования -->
<div class="profile-main">
<!-- Личная информация -->
<div class="card">
<div class="card-header">
<h2 class="card-title">Личная информация</h2>
</div>
<div class="card-body">
<form class="profile-form" @submit.prevent="saveProfile">
<div class="user-avatar-section">
<div class="user-avatar">
<span class="avatar-text">{{ userInitials }}</span>
</div>
<div class="avatar-actions">
<button type="button" class="btn btn-outline btn-sm">Изменить фото</button>
<button type="button" class="btn btn-outline btn-sm">Удалить</button>
</div>
</div>
<!-- В форме редактирования профиля -->
<div class="form-grid">
<div class="form-group">
<label for="fullName" class="form-label">Полное имя</label>
<input
id="fullName"
v-model="formData.full_name"
type="text"
class="form-input"
placeholder="Введите ваше полное имя"
autocomplete="name">
</div>
<div class="form-group">
<label for="inn" class="form-label">ИНН</label>
<input
id="inn"
v-model="formData.inn"
type="text"
class="form-input"
placeholder="Введите ваш ИНН"
maxlength="12"
autocomplete="off">
</div>
<div class="form-group">
<label for="phone" class="form-label">Телефон</label>
<input
id="phone"
v-model="formData.phone"
type="tel"
class="form-input"
placeholder="+7 (___) ___-__-__"
autocomplete="tel">
</div>
<div class="form-group">
<label for="city" class="form-label">Город</label>
<input
id="city"
v-model="formData.city"
type="text"
class="form-input"
placeholder="Введите ваш город"
autocomplete="address-level2">
</div>
<div class="form-group">
<label for="email" class="form-label">Email</label>
<div class="email-input-group">
<input
id="email"
v-model="formData.email"
type="email"
class="form-input"
:class="{ 'input-error': emailError }"
placeholder="Введите ваш email"
autocomplete="email"
required
@blur="validateEmail">
</div>
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary" :disabled="isSaving">
{{ isSaving ? 'Сохранение...' : 'Сохранить изменения' }}
</button>
<NuxtLink to="/profile" class="btn btn-outline">Отмена</NuxtLink>
</div>
</form>
</div>
</div>
<!-- Информация об организации -->
<div class="card">
<div class="card-header">
<h2 class="card-title">Информация об организации</h2>
</div>
<div class="card-body">
<div class="form-grid">
<div class="form-group">
<label for="orgType" class="form-label">Форма организации</label>
<select id="orgType" v-model="formData.org_type" class="form-select">
<option value="">Не выбрано</option>
<option value="individual">Индивидуальный предприниматель (ИП)</option>
<option value="llc">Общество с ограниченной ответственностью (ООО)</option>
<option value="jsc">Акционерное общество (АО)</option>
</select>
</div>
<div class="form-group">
<label for="orgFullName" class="form-label">Полное название организации</label>
<input
id="orgFullName"
v-model="formData.org_full_name"
type="text"
class="form-input"
placeholder="Введите полное название организации">
</div>
<div class="form-group">
<label for="orgShortName" class="form-label">Короткое название организации</label>
<input
id="orgShortName"
v-model="formData.org_short_name"
type="text"
class="form-input"
placeholder="Введите короткое название организации">
</div>
<div class="form-group">
<label for="orgInn" class="form-label">ИНН организации</label>
<input
id="orgInn"
v-model="formData.org_inn"
type="text"
class="form-input"
placeholder="Введите ИНН организации" maxlength="12">
</div>
</div>
</div>
</div>
</div>
<!-- Боковая панель -->
<div class="profile-sidebar">
<!-- Статус -->
<div class="card">
<div class="card-header">
<h3 class="card-title">Статус аккаунта</h3>
</div>
<div class="card-body">
<div class="status-item">
<span class="status-icon"></span>
<span class="status-text">Активен</span>
</div>
<div v-if="formData.org_type" class="status-item">
<span class="status-icon">🏢</span>
<span class="status-text">{{ orgTypeText }}</span>
</div>
<p class="status-note">Демо-режим</p>
</div>
</div>
<!-- Навигация -->
<div class="card">
<div class="card-header">
<h3 class="card-title">Навигация</h3>
</div>
<div class="card-body">
<div class="nav-links">
<NuxtLink to="/profile" class="nav-link-block">
👤 Мой профиль
</NuxtLink>
<NuxtLink to="/objects/my-objects" class="nav-link-block">
📝 Мои объекты
</NuxtLink>
<NuxtLink to="/objects/create" class="nav-link-block">
Добавить объект
</NuxtLink>
<NuxtLink to="/" class="nav-link-block">
🏠 Главная
</NuxtLink>
</div>
</div>
</div>
</div>
</div>
<!-- Загрузка -->
<div v-else-if="auth.loading.value" class="loading-container">
<div class="loading-spinner"/>
<p>Загрузка профиля...</p>
</div>
<!-- Ошибка -->
<div v-else class="error-container">
<p>Не удалось загрузить данные профиля</p>
<button class="btn btn-primary" @click="reload">Попробовать снова</button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
const auth = useAuth()
const router = useRouter()
// Инициализация данных пользователя
onMounted(async () => {
if (!auth.user.value) {
await auth.checkAuth()
}
// Заполняем форму данными пользователя
if (auth.user.value) {
formData.value = {
full_name: auth.user.value.full_name || '',
inn: auth.user.value.inn || '',
phone: auth.user.value.phone || '',
city: auth.user.value.city || '',
email: auth.user.value.email || '',
org_type: auth.user.value.org_type || '',
org_full_name: auth.user.value.org_full_name || '',
org_short_name: auth.user.value.org_short_name || '',
org_inn: auth.user.value.org_inn || ''
}
}
})
// Состояние формы
const formData = ref({
full_name: '',
inn: '',
phone: '',
city: '',
email: '',
org_type: '',
org_full_name: '',
org_short_name: '',
org_inn: ''
})
// Состояние для верификации email
const isEmailVerified = ref(false)
const showVerificationModal = ref(false)
const verificationCode = ref('')
const isSendingCode = ref(false)
const isVerifyingCode = ref(false)
const verificationError = ref('')
const emailError = ref('')
const isSaving = ref(false)
// Вычисляем инициалы пользователя для аватара
const userInitials = computed(() => {
if (!formData.value.full_name) return '??'
const names = formData.value.full_name.split(' ')
if (names.length >= 2 && names[0] && names[1]) {
return `${names[0][0]}${names[1][0]}`.toUpperCase()
}
return formData.value.full_name.substring(0, 2).toUpperCase()
})
// Текст для типа организации
const orgTypeText = computed(() => {
const types: Record<string, string> = {
individual: 'Индивидуальный предприниматель',
llc: 'Общество с ограниченной ответственностью',
jsc: 'Акционерное общество'
}
return types[formData.value.org_type] || 'Не указано'
})
// Валидация email
const validateEmail = () => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
if (!formData.value.email) {
emailError.value = 'Email обязателен для заполнения'
} else if (!emailRegex.test(formData.value.email)) {
emailError.value = 'Введите корректный email адрес'
} else {
emailError.value = ''
}
}
// Отправка кода верификации
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const sendVerificationCode = async () => {
isSendingCode.value = true
verificationError.value = ''
// Имитация запроса к API
try {
await new Promise(resolve => setTimeout(resolve, 1500))
showVerificationModal.value = true
console.log(`Код верификации отправлен на ${formData.value.email}`)
} catch (error) {
console.log(error)
verificationError.value = 'Ошибка при отправке кода. Попробуйте позже.'
} finally {
isSendingCode.value = false
}
}
// Верификация кода
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const verifyEmailCode = async () => {
isVerifyingCode.value = true
verificationError.value = ''
// Имитация проверки кода
try {
await new Promise(resolve => setTimeout(resolve, 1000))
// В демо-режиме любой 6-значный код считается верным
if (verificationCode.value.length === 6) {
isEmailVerified.value = true
showVerificationModal.value = false
verificationCode.value = ''
} else {
verificationError.value = 'Неверный код подтверждения'
}
} catch (error) {
console.log("debug. Error: " + error)
verificationError.value = 'Ошибка при проверке кода. Попробуйте позже.'
} finally {
isVerifyingCode.value = false
}
}
// Закрытие модального окна верификации
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const closeVerificationModal = () => {
showVerificationModal.value = false
verificationCode.value = ''
verificationError.value = ''
}
// Сохранение профиля
const saveProfile = async () => {
isSaving.value = true
// Валидация формы
validateEmail()
if (emailError.value) {
isSaving.value = false
return
}
// Имитация сохранения данных
try {
await new Promise(resolve => setTimeout(resolve, 2000))
console.log('Профиль сохранен:', formData.value)
// В реальном приложении здесь был бы запрос к API
// После успешного сохранения перенаправляем на страницу профиля
router.push('/profile')
} catch (error) {
console.error('Ошибка при сохранении профиля:', error)
} finally {
isSaving.value = false
}
}
const reload = () => {
window.location.reload()
}
</script>
<style scoped>
/* Стили остаются такими же как в оригинальном edit.vue */
/* Добавляем стили для состояний загрузки и ошибок */
.loading-container,
.error-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 4rem 2rem;
text-align: center;
}
.loading-spinner {
width: 3rem;
height: 3rem;
border: 3px solid var(--border-light);
border-top: 3px solid var(--primary-500);
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 1rem;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>