From bb6537533bf46d3e006eecaf7392ba58ed1df1a4 Mon Sep 17 00:00:00 2001 From: andrei Date: Fri, 28 Nov 2025 16:16:18 +0500 Subject: [PATCH] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20?= =?UTF-8?q?=D0=B2=20=D0=B0=D0=BF=D0=B8=20=D1=83=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BA=D1=83=D1=80=D1=81=D0=B0?= =?UTF-8?q?=D0=BC=D0=B8,=20=D1=81=D1=82=D1=83=D0=B4=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=B0=D0=BC=D0=B8=20=D0=BA=D1=83=D1=80=D1=81=D0=BE=D0=B2=20?= =?UTF-8?q?=D0=B8=20=D1=83=D1=87=D0=B8=D1=82=D0=B5=D0=BB=D1=8F=D0=BC=D0=B8?= =?UTF-8?q?=20=D0=BA=D1=83=D1=80=D1=81=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/course_teachers_repository.py | 51 +++ api/app/application/courses_repository.py | 40 ++ api/app/application/enrollments_repository.py | 43 +++ api/app/controllers/courses_router.py | 125 ++++++ api/app/domain/entities/course_teachers.py | 15 + api/app/domain/entities/courses.py | 27 ++ api/app/domain/entities/enrollments.py | 18 + api/app/domain/models/courses.py | 4 +- .../infrastructure/course_teachers_service.py | 65 ++++ api/app/infrastructure/courses_service.py | 46 +++ api/app/infrastructure/dependencies.py | 9 +- api/app/infrastructure/enrollments_service.py | 66 ++++ api/app/main.py | 2 + .../UpdateUserModalForm.jsx | 357 ++++++++++++------ 14 files changed, 749 insertions(+), 119 deletions(-) create mode 100644 api/app/application/course_teachers_repository.py create mode 100644 api/app/application/courses_repository.py create mode 100644 api/app/application/enrollments_repository.py create mode 100644 api/app/controllers/courses_router.py create mode 100644 api/app/domain/entities/course_teachers.py create mode 100644 api/app/domain/entities/courses.py create mode 100644 api/app/domain/entities/enrollments.py create mode 100644 api/app/infrastructure/course_teachers_service.py create mode 100644 api/app/infrastructure/courses_service.py create mode 100644 api/app/infrastructure/enrollments_service.py diff --git a/api/app/application/course_teachers_repository.py b/api/app/application/course_teachers_repository.py new file mode 100644 index 0000000..56a4c9f --- /dev/null +++ b/api/app/application/course_teachers_repository.py @@ -0,0 +1,51 @@ +from typing import Optional, List, Sequence + +from sqlalchemy import select +from sqlalchemy.ext.asyncio import AsyncSession + +from app.domain.models import CourseTeacher + + +class CourseTeachersRepository: + def __init__(self, db: AsyncSession): + self.db = db + + async def get_by_course_id(self, course_id: int) -> Sequence[CourseTeacher]: + query = ( + select(CourseTeacher) + .filter_by(course_id=course_id) + ) + results = await self.db.execute(query) + return results.scalars().all() + + async def get_by_teacher_id(self, teacher_id: int) -> Sequence[CourseTeacher]: + query = ( + select(CourseTeacher) + .filter_by(teacher_id=teacher_id) + ) + results = await self.db.execute(query) + return results.scalars().all() + + async def get_by_id(self, course_teacher_id: int) -> Optional[CourseTeacher]: + query = ( + select(CourseTeacher) + .filter_by(id=course_teacher_id) + ) + results = await self.db.execute(query) + return results.scalars().first() + + async def create_list(self, course_teachers: List[CourseTeacher]) -> List[CourseTeacher]: + self.db.add_all(course_teachers) + await self.db.commit() + + for course_teacher in course_teachers: + await self.db.refresh(course_teacher) + + return course_teachers + + async def delete_list(self, course_teachers: List[CourseTeacher] | Sequence[CourseTeacher]) -> List[CourseTeacher]: + for course_teacher in course_teachers: + await self.db.delete(course_teacher) + + await self.db.commit() + return course_teachers diff --git a/api/app/application/courses_repository.py b/api/app/application/courses_repository.py new file mode 100644 index 0000000..0fd4494 --- /dev/null +++ b/api/app/application/courses_repository.py @@ -0,0 +1,40 @@ +from typing import List, Optional + +from sqlalchemy import select +from sqlalchemy.ext.asyncio import AsyncSession + +from app.domain.models import Course + + +class CoursesRepository: + def __init__(self, db: AsyncSession): + self.db = db + + async def get_all(self) -> List[Course]: + query = select(Course) + result = await self.db.execute(query) + return result.scalars().all() + + async def get_by_id(self, course_id: int) -> Optional[Course]: + query = ( + select(Course) + .order_by(id=course_id) + ) + result = await self.db.execute(query) + return result.scalars().first() + + async def create(self, course: Course) -> Course: + self.db.add(course) + await self.db.commit() + await self.db.refresh(course) + return course + + async def update(self, course: Course) -> Course: + await self.db.merge(course) + await self.db.commit() + return course + + async def delete(self, course: Course) -> Course: + await self.db.delete(course) + await self.db.commit() + return course diff --git a/api/app/application/enrollments_repository.py b/api/app/application/enrollments_repository.py new file mode 100644 index 0000000..2559fb9 --- /dev/null +++ b/api/app/application/enrollments_repository.py @@ -0,0 +1,43 @@ +from typing import List, Sequence + +from sqlalchemy import select +from sqlalchemy.ext.asyncio import AsyncSession + +from app.domain.models import Enrollment + + +class EnrollmentsRepository: + def __init__(self, db: AsyncSession): + self.db = db + + async def get_by_course_id(self, course_id: int) -> Sequence[Enrollment]: + query = ( + select(Enrollment) + .filter_by(course_id=course_id) + ) + results = await self.db.execute(query) + return results.scalars().all() + + async def get_by_student_id(self, student_id: int) -> Sequence[Enrollment]: + query = ( + select(Enrollment) + .filter_by(student_id=student_id) + ) + results = await self.db.execute(query) + return results.scalars().all() + + async def create_list(self, enrollments: List[Enrollment]) -> List[Enrollment]: + self.db.add_all(enrollments) + await self.db.commit() + + for enrollment in enrollments: + await self.db.refresh(enrollment) + + return enrollments + + async def delete_list(self, enrollments: List[Enrollment] | Sequence[Enrollment]) -> List[Enrollment]: + for enrollment in enrollments: + await self.db.delete(enrollment) + + await self.db.commit() + return enrollments diff --git a/api/app/controllers/courses_router.py b/api/app/controllers/courses_router.py new file mode 100644 index 0000000..8a416b6 --- /dev/null +++ b/api/app/controllers/courses_router.py @@ -0,0 +1,125 @@ +from typing import List, Optional + +from fastapi import APIRouter, Depends, Response +from sqlalchemy.ext.asyncio import AsyncSession + +from app.database.session import get_db +from app.domain.entities.course_teachers import CourseTeacherRead, CourseTeacherCreate +from app.domain.entities.courses import CourseRead, CourseCreate, CourseUpdate +from app.domain.entities.enrollments import EnrollmentRead, EnrollmentCreate +from app.domain.models import User +from app.infrastructure.course_teachers_service import CourseTeachersService +from app.infrastructure.courses_service import CoursesService +from app.infrastructure.dependencies import require_auth_user, require_teacher +from app.infrastructure.enrollments_service import EnrollmentsService + +courses_router = APIRouter() + + +@courses_router.get( + '/', + response_model=List[CourseRead], + summary='Return all courses', + description='Return all courses', +) +async def get_all_courses( + db: AsyncSession = Depends(get_db), + user: User = Depends(require_auth_user), +): + courses_service = CoursesService(db) + return await courses_service.get_all() + + +@courses_router.post( + '/', + response_model=Optional[CourseRead], + summary='Create a new course', + description='Create a new course', +) +async def create_new_course( + course: CourseCreate, + db: AsyncSession = Depends(get_db), + user: User = Depends(require_teacher), +): + courses_service = CoursesService(db) + return await courses_service.create(course) + + +@courses_router.put( + '/{course_id}/', + response_model=Optional[CourseRead], + summary='Update a course', + description='Update a course', +) +async def update_course( + course_id: int, + course: CourseUpdate, + db: AsyncSession = Depends(get_db), + user: User = Depends(require_teacher), +): + courses_service = CoursesService(db) + return await courses_service.update(course_id, course) + + +@courses_router.get( + '/{course_id}/teachers/', + response_model=List[CourseTeacherRead], + summary='Return all teachers', + description='Return all teachers', +) +async def get_course_teachers( + course_id: int, + db: AsyncSession = Depends(get_db), + user: User = Depends(require_auth_user), +): + service = CourseTeachersService(db) + teachers = await service.get_course_teachers_by_course_id(course_id) + return teachers + + +@courses_router.put( + '/{course_id}/teachers/', + response_model=List[CourseTeacherRead], + summary='Replace all teachers in a course', + description='Replace all teachers in a course', +) +async def replace_course_teachers( + course_id: int, + teachers: List[CourseTeacherCreate], + db: AsyncSession = Depends(get_db), + user: User = Depends(require_teacher), +): + service = CourseTeachersService(db) + return await service.replace_course_teachers_list(teachers, course_id) + + +@courses_router.get( + '/{course_id}/students/', + response_model=List[EnrollmentRead], + summary='Return all students of the course', + description='Return all students enrolled in the course', +) +async def get_course_students( + course_id: int, + db: AsyncSession = Depends(get_db), + user: User = Depends(require_auth_user), +): + service = EnrollmentsService(db) + students = await service.get_course_students_by_course_id(course_id) + return students + + +@courses_router.put( + '/{course_id}/students/', + response_model=List[EnrollmentRead], + summary='Replace all students in a course', + description='Completely replace the list of enrolled students', +) +async def replace_course_students( + course_id: int, + students: List[EnrollmentCreate], + db: AsyncSession = Depends(get_db), + user: User = Depends(require_teacher), +): + service = EnrollmentsService(db) + return await service.replace_course_students_list(students, course_id) diff --git a/api/app/domain/entities/course_teachers.py b/api/app/domain/entities/course_teachers.py new file mode 100644 index 0000000..17cfeee --- /dev/null +++ b/api/app/domain/entities/course_teachers.py @@ -0,0 +1,15 @@ +from pydantic import BaseModel, EmailStr, Field + + +class CourseTeacherCreate(BaseModel): + course_id: int = Field() + teacher_id: int = Field() + + +class CourseTeacherRead(BaseModel): + id: int + course_id: int + teacher_id: int + + class Config: + from_attributes = True diff --git a/api/app/domain/entities/courses.py b/api/app/domain/entities/courses.py new file mode 100644 index 0000000..47934f9 --- /dev/null +++ b/api/app/domain/entities/courses.py @@ -0,0 +1,27 @@ +from typing import Optional, List + +from pydantic import BaseModel, EmailStr, Field + +from app.domain.entities.course_teachers import CourseTeacherRead +from app.domain.entities.enrollments import EnrollmentRead + + +class CourseCreate(BaseModel): + title: str = Field(max_length=250) + description: Optional[str] = Field(default=None, max_length=1000) + + +class CourseUpdate(CourseCreate): + pass + + +class CourseRead(BaseModel): + id: int + title: str + description: str + + teachers: List[CourseTeacherRead] + enrollments: List[EnrollmentRead] + + class Config: + from_attributes = True diff --git a/api/app/domain/entities/enrollments.py b/api/app/domain/entities/enrollments.py new file mode 100644 index 0000000..343ba20 --- /dev/null +++ b/api/app/domain/entities/enrollments.py @@ -0,0 +1,18 @@ +from datetime import datetime + +from pydantic import BaseModel, EmailStr, Field + + +class EnrollmentCreate(BaseModel): + course_id: int = Field() + student_id: int = Field() + + +class EnrollmentRead(BaseModel): + id: int + course_id: int + student_id: int + enrollment_date: datetime + + class Config: + from_attributes = True diff --git a/api/app/domain/models/courses.py b/api/app/domain/models/courses.py index 113e150..bf891c0 100644 --- a/api/app/domain/models/courses.py +++ b/api/app/domain/models/courses.py @@ -12,7 +12,7 @@ class Course(PhotoAbstract): title: Mapped[str] = mapped_column(String(250), nullable=False) description: Mapped[str] = mapped_column(String(1000), nullable=True) - teachers: Mapped[List['CourseTeacher']] = relationship('CourseTeacher', back_populates='course') - enrollments: Mapped[List['Enrollment']] = relationship('Enrollment', back_populates='course') + teachers: Mapped[List['CourseTeacher']] = relationship('CourseTeacher', back_populates='course', lazy='select') + enrollments: Mapped[List['Enrollment']] = relationship('Enrollment', back_populates='course', lazy='select') lessons: Mapped[List['Lesson']] = relationship('Lesson', back_populates='course') tasks: Mapped[List['Task']] = relationship('Task', back_populates='course') diff --git a/api/app/infrastructure/course_teachers_service.py b/api/app/infrastructure/course_teachers_service.py new file mode 100644 index 0000000..1403ba0 --- /dev/null +++ b/api/app/infrastructure/course_teachers_service.py @@ -0,0 +1,65 @@ +from typing import Optional, List +from fastapi import HTTPException, status + +from sqlalchemy.ext.asyncio import AsyncSession + +from app.application.course_teachers_repository import CourseTeachersRepository +from app.application.courses_repository import CoursesRepository +from app.application.users_repository import UsersRepository +from app.domain.entities.course_teachers import CourseTeacherRead, CourseTeacherCreate +from app.domain.models import CourseTeacher + + +class CourseTeachersService: + def __init__(self, db: AsyncSession): + self.course_teachers_repository = CourseTeachersRepository(db) + self.courses_repository = CoursesRepository(db) + self.users_repository = UsersRepository(db) + + async def get_course_teachers_by_course_id(self, course_id: int) -> Optional[List[CourseTeacherRead]]: + course = await self.courses_repository.get_by_id(course_id) + + if course is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail='Курс с таким ID не найден') + + course_teachers = await self.course_teachers_repository.get_by_course_id(course.id) + + response = [] + for course_teacher in course_teachers: + response.append( + CourseTeacherRead.model_validate(course_teacher) + ) + + return response + + async def replace_course_teachers_list( + self, course_teachers: List[CourseTeacherCreate], course_id: int + ) -> Optional[List[CourseTeacherRead]]: + course = await self.courses_repository.get_by_id(course_id) + + if course is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail='Курс с таким ID не найден') + + old_course_teachers = await self.course_teachers_repository.get_by_course_id(course.id) + await self.course_teachers_repository.delete_list(old_course_teachers) + + course_teachers_models = [] + for course_teacher in course_teachers: + teacher = await self.users_repository.get_by_id(course_teacher.teacher_id) + if teacher is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail='Пользователь с таким ID не найден') + + course_teachers_models.append(CourseTeacher( + course_id=course_id, + teacher_id=course_teacher.teacher_id, + )) + + course_teachers_models = await self.course_teachers_repository.create_list(course_teachers_models) + + response = [] + for course_teacher in course_teachers_models: + response.append( + CourseTeacherRead.model_validate(course_teacher) + ) + + return response diff --git a/api/app/infrastructure/courses_service.py b/api/app/infrastructure/courses_service.py new file mode 100644 index 0000000..db7fffd --- /dev/null +++ b/api/app/infrastructure/courses_service.py @@ -0,0 +1,46 @@ +from typing import List, Optional + +from fastapi import HTTPException, status +from sqlalchemy.ext.asyncio import AsyncSession + +from app.application.courses_repository import CoursesRepository +from app.domain.entities.courses import CourseRead, CourseCreate +from app.domain.models import Course + + +class CoursesService: + def __init__(self, db: AsyncSession): + self.courses_repository = CoursesRepository(db) + + async def get_all(self) -> List[CourseRead]: + courses = await self.courses_repository.get_all() + response = [] + for course in courses: + response.append( + CourseRead.model_validate(course) + ) + + return response + + async def create(self, course: CourseCreate) -> Optional[CourseRead]: + course_model = Course( + title=course.title, + description=course.description, + ) + + course_model = await self.courses_repository.create(course_model) + + return CourseRead.model_validate(course_model) + + async def update(self, course_id: int, course: CourseCreate) -> Optional[CourseRead]: + course_model = await self.courses_repository.get_by_id(course_id) + + if course_model is None: + raise HTTPException(status_code=404, detail='Курс с таким ID не найден') + + course_model.title = course.title + course_model.description = course.description + + course_model = await self.courses_repository.update(course_model) + + return CourseRead.model_validate(course_model) diff --git a/api/app/infrastructure/dependencies.py b/api/app/infrastructure/dependencies.py index 2dca81d..9d02695 100644 --- a/api/app/infrastructure/dependencies.py +++ b/api/app/infrastructure/dependencies.py @@ -5,7 +5,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from starlette import status from app.application.users_repository import UsersRepository -from app.core.constants import UserStatuses +from app.core.constants import UserStatuses, UserRoles from app.database.session import get_db from app.domain.models.users import User from app.settings import get_auth_data, Settings @@ -45,3 +45,10 @@ def require_admin(user: User = Depends(require_auth_user)): raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail='Ошибка доступа') return user + + +def require_teacher(user: User = Depends(require_auth_user)): + if user.role.title not in [UserRoles.TEACHER, Settings().root_role_name]: + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail='Ошибка доступа') + + return user diff --git a/api/app/infrastructure/enrollments_service.py b/api/app/infrastructure/enrollments_service.py new file mode 100644 index 0000000..a835f42 --- /dev/null +++ b/api/app/infrastructure/enrollments_service.py @@ -0,0 +1,66 @@ +from typing import Optional, List +from fastapi import HTTPException, status + +from sqlalchemy.ext.asyncio import AsyncSession + +from app.application.enrollments_repository import EnrollmentsRepository +from app.application.courses_repository import CoursesRepository +from app.application.users_repository import UsersRepository +from app.domain.entities.enrollments import EnrollmentRead, EnrollmentCreate +from app.domain.models import Enrollment + + +class EnrollmentsService: + def __init__(self, db: AsyncSession): + self.enrollments_repository = EnrollmentsRepository(db) + self.courses_repository = CoursesRepository(db) + self.users_repository = UsersRepository(db) + + async def get_course_students_by_course_id(self, course_id: int) -> Optional[List[EnrollmentRead]]: + course = await self.courses_repository.get_by_id(course_id) + + if course is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail='Курс с таким ID не найден') + + enrollments = await self.enrollments_repository.get_by_course_id(course.id) + + response = [] + for enrollment in enrollments: + response.append( + EnrollmentRead.model_validate(enrollment) + ) + + return response + + async def replace_course_students_list( + self, enrollments: List[EnrollmentCreate], course_id: int + ) -> Optional[List[EnrollmentRead]]: + course = await self.courses_repository.get_by_id(course_id) + + if course is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail='Курс с таким ID не найден') + + old_enrollments = await self.enrollments_repository.get_by_course_id(course.id) + await self.enrollments_repository.delete_list(old_enrollments) + + enrollments_models = [] + for enrollment in enrollments: + student = await self.users_repository.get_by_id(enrollment.student_id) + if student is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail='Пользователь с таким ID не найден') + + enrollments_models.append(Enrollment( + course_id=course_id, + student_id=enrollment.student_id, + enrollment_date=enrollment.enrollment_date, + )) + + enrollments_models = await self.enrollments_repository.create_list(enrollments_models) + + response = [] + for enrollment in enrollments_models: + response.append( + EnrollmentRead.model_validate(enrollment) + ) + + return response diff --git a/api/app/main.py b/api/app/main.py index 3c4f2d4..1b238a9 100644 --- a/api/app/main.py +++ b/api/app/main.py @@ -2,6 +2,7 @@ from fastapi import FastAPI from starlette.middleware.cors import CORSMiddleware from app.controllers.auth_router import auth_router +from app.controllers.courses_router import courses_router from app.controllers.register_router import register_router from app.controllers.roles_router import roles_router from app.controllers.statuses_router import statuses_router @@ -22,6 +23,7 @@ def start_app(): ) api_app.include_router(auth_router, prefix=f'{settings.prefix}/auth', tags=['auth']) + api_app.include_router(courses_router, prefix=f'{settings.prefix}/courses', tags=['courses']) api_app.include_router(register_router, prefix=f'{settings.prefix}/register', tags=['register']) api_app.include_router(roles_router, prefix=f'{settings.prefix}/roles', tags=['roles']) api_app.include_router(statuses_router, prefix=f'{settings.prefix}/statuses', tags=['statuses']) diff --git a/web/src/Components/Pages/AdminPage/UpdateUserModalForm/UpdateUserModalForm.jsx b/web/src/Components/Pages/AdminPage/UpdateUserModalForm/UpdateUserModalForm.jsx index 21966db..b364ece 100644 --- a/web/src/Components/Pages/AdminPage/UpdateUserModalForm/UpdateUserModalForm.jsx +++ b/web/src/Components/Pages/AdminPage/UpdateUserModalForm/UpdateUserModalForm.jsx @@ -1,9 +1,32 @@ -import {Button, DatePicker, Form, Input, Modal, Result, Select, Tooltip, Typography} from "antd"; -import useUpdateUserModalForm from "./useUpdateUserModalForm.js"; -import {CalendarOutlined, InfoCircleOutlined} from "@ant-design/icons"; +import { + Button, + Card, + Col, + DatePicker, + Form, + Input, + Modal, + Row, + Select, + Space, + Typography, + Avatar, + Divider, Result, +} from "antd"; +import { + UserOutlined, + MailOutlined, + LockOutlined, + CalendarOutlined, + SaveOutlined, + CrownOutlined, + TagOutlined, +} from "@ant-design/icons"; import dayjs from "dayjs"; import LoadingIndicator from "../../../Widgets/LoadingIndicator/LoadingIndicator.jsx"; +import useUpdateUserModalForm from "./useUpdateUserModalForm.js"; +const {Title, Text} = Typography; const UpdateUserModalForm = () => { const { @@ -13,135 +36,237 @@ const UpdateUserModalForm = () => { userForm, passwordForm, roles, + statusesData, isLoading, isError, isLoadingUpdate, - isErrorUpdate, handlePasswordFinish, - statusesData, } = useUpdateUserModalForm(); - if (isLoading) { - return - } - + if (isLoading) return ; if (isError) { - return + return ( + + ); } return ( + } style={{backgroundColor: "#1890ff"}}/> +
+ + Редактирование пользователя + + Изменение профиля и прав доступа +
+ + } + closeIcon={null} > -
- - - - - - - - - - - - - - - - - } - format="DD.MM.YYYY" - style={{width: "100%"}} - size="large" - maxDate={dayjs()} - /> - - - - - - - - - - -
-
- Изменение пароля - - - - ({ - validator(_, value) { - if (!value || getFieldValue("password") === value) { - return Promise.resolve(); - } - return Promise.reject(new Error("Пароли не совпадают")); - }, - }), - ]} - > - - - - - - -
+ + + Основная информация} + style={{marginBottom: 24, borderRadius: 12, boxShadow: "0 2px 8px rgba(0,0,0,0.05)"}} + > +
+ + + + } size="large" placeholder="Иванов"/> + + + + + + } size="large" placeholder="Иван"/> + + + + + + } size="large" placeholder="Иванович"/> + + + + + + } size="large" placeholder="ivan@example.com"/> + + + + + + } + format="DD.MM.YYYY" + placeholder="15.03.1995" + style={{width: "100%"}} + size="large" + maxDate={dayjs()} + /> + + + + + + } size="large"/> + + + + + Роль} + rules={[{required: true, message: "Выберите роль"}]} + > + + + + + + Статус} + rules={[{required: true, message: "Выберите статус"}]} + > + + + + + + + + + + + +
+
+ + + + Смена пароля} + style={{borderRadius: 12, boxShadow: "0 2px 8px rgba(0,0,0,0.05)"}} + > +
+ + + + } size="large" placeholder="••••••••"/> + + + + + ({ + validator(_, value) { + if (!value || getFieldValue("password") === value) { + return Promise.resolve(); + } + return Promise.reject(new Error("Пароли не совпадают")); + }, + }), + ]} + > + } size="large" placeholder="••••••••"/> + + + + + + + + + + +
+
+ +
- ) + ); }; export default UpdateUserModalForm; \ No newline at end of file