diff --git a/backend/prisma/schema.prisma b/backend/prisma/schema.prisma new file mode 100644 index 0000000..cbb9f0f --- /dev/null +++ b/backend/prisma/schema.prisma @@ -0,0 +1,205 @@ +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +generator client { + provider = "prisma-client-js" +} + +enum EquipmentStatus { + Active + Repair + Reserve + WriteOff +} + +enum laborOperation { + Manual + MachineManual + Machine +} + +enum EnumPeriodicityTO { + Ежедневное + Еженедельное + Ежемесячное + Полугодовое + Годовое +} + +enum Role { + Исполнитель + Подписант + Пользователь +} + +enum CategoryPart { + Расходник + Запчасть + Инструмент + Спецодежда +} + +enum EquipmentType { + Производственное + Энергетическое + Насосное + Компрессорное +} + +enum RepairKind { + TO + TR + TRE + KR + AR + MP +} + +enum RepairOrderStatus { + Draft + Approved + InWork + Done + Cancelled +} + +model Equipment { + id String @id @default(uuid()) + name String + serialNumber String + dateOfInspection DateTime? @db.Date + inventoryNumber String @unique + equipmentType EquipmentType + periodicityTO EnumPeriodicityTO + status EquipmentStatus @default(Active) + commissionedAt DateTime? @db.Date + totalEngineHours Decimal? + engineHoursSinceLastRepair Decimal? + lastRepairAt DateTime? @db.Date + notes String? + workAsPartOf laborOperation? + fuelСonsumed Float? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + // Relations + repairOrders RepairOrder[] + changeEquipmentStatuses ChangeEquipmentStatus[] + consumptionRegistrations ConsumptionRegistration[] +} + +model Employee { + code String @id + fullName String + role Role + position String + price Float? + phoneNumber Float? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + // Self-referential relation for boss/subordinates + bossCode String? + boss Employee? @relation("EmployeeBoss", fields: [bossCode], references: [code]) + subordinates Employee[] @relation("EmployeeBoss") + + // Relations + confirmationDocuments ConfirmationDocument[] + categoryResources CategoryResource[] +} + +model Part { + id String @id @default(uuid()) + name String + categories CategoryPart? + price Float? + description String? + serialNumber String? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + // Relations + categoryResources CategoryResource[] +} + +model CategoryResource { + id String @id @default(uuid()) + partId String? + employeeCode String? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + // Relations + part Part? @relation(fields: [partId], references: [id]) + employee Employee? @relation(fields: [employeeCode], references: [code]) +} + +model RepairOrder { + id String @id @default(uuid()) + number String @unique + date DateTime @db.Date + equipmentId String + repairKind RepairKind + status RepairOrderStatus @default(Draft) + plannedAt DateTime @db.Date + startedAt DateTime? @db.Date + completedAt DateTime? @db.Date + contractor String? + engineHoursAtRepair Decimal? + description String? + notes String? + confirmed Boolean? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + // Relations + equipment Equipment @relation(fields: [equipmentId], references: [id]) + confirmationDocuments ConfirmationDocument[] +} + +model ChangeEquipmentStatus { + id String @id @default(uuid()) + equipmentId String + newStatus EquipmentStatus + number String? + comment String? + date DateTime @db.Date + responsible String? + document String? // Storing file path/URL + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + // Relations + equipment Equipment @relation(fields: [equipmentId], references: [id]) +} + +model ConfirmationDocument { + id String @id @default(uuid()) + number String? + date DateTime @db.Date + managerCode String? + orderId String + confirmed Boolean? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + // Relations + manager Employee? @relation(fields: [managerCode], references: [code]) + order RepairOrder @relation(fields: [orderId], references: [id]) +} + +model ConsumptionRegistration { + id String @id @default(uuid()) + number String? + date DateTime @db.Date + equipmentId String + totalEngineHours Decimal? + fuelConsumption Float? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + // Relations + equipment Equipment @relation(fields: [equipmentId], references: [id]) +} diff --git a/backend/src/app.module.ts b/backend/src/app.module.ts new file mode 100644 index 0000000..c5aba89 --- /dev/null +++ b/backend/src/app.module.ts @@ -0,0 +1,27 @@ +import { Module } from '@nestjs/common'; +import { EquipmentModule } from './equipment/equipment.module'; +import { EmployeeModule } from './employee/employee.module'; +import { PartModule } from './part/part.module'; +import { CategoryResourceModule } from './category-resource/category-resource.module'; +import { RepairOrderModule } from './repair-order/repair-order.module'; +import { ChangeEquipmentStatusModule } from './change-equipment-status/change-equipment-status.module'; +import { ConfirmationDocumentModule } from './confirmation-document/confirmation-document.module'; +import { ConsumptionRegistrationModule } from './consumption-registration/consumption-registration.module'; +import { AuthModule } from './auth/auth.module'; +import { PrismaService } from './prisma/prisma.service'; + +@Module({ + imports: [ + AuthModule, + EquipmentModule, + EmployeeModule, + PartModule, + CategoryResourceModule, + RepairOrderModule, + ChangeEquipmentStatusModule, + ConfirmationDocumentModule, + ConsumptionRegistrationModule, + ], + providers: [PrismaService], +}) +export class AppModule {} \ No newline at end of file diff --git a/backend/src/category-resource/category-resource.controller.ts b/backend/src/category-resource/category-resource.controller.ts new file mode 100644 index 0000000..66c9e42 --- /dev/null +++ b/backend/src/category-resource/category-resource.controller.ts @@ -0,0 +1,54 @@ +import { Controller, Get, Post, Body, Patch, Param, Delete, Query, UseGuards } from '@nestjs/common'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { CategoryResourceService } from './category-resource.service'; +import { CreateCategoryResourceDto } from './dto/create-category-resource.dto'; +import { UpdateCategoryResourceDto } from './dto/update-category-resource.dto'; +import { JwtAuthGuard } from '../auth/jwt-auth.guard'; + +const parseJson = (value?: string): T | undefined => { + if (!value) return undefined; + try { return JSON.parse(value) as T; } catch { return undefined; } +}; + +@ApiTags('category-resource') +@ApiBearerAuth() +@UseGuards(JwtAuthGuard) +@Controller('category-resource') +export class CategoryResourceController { + constructor(private readonly categoryResourceService: CategoryResourceService) {} + + @Get() + findAll( + @Query('skip') skip?: string, + @Query('take') take?: string, + @Query('orderBy') orderBy?: string, + @Query('where') where?: string, + ) { + return this.categoryResourceService.findAll({ + skip: skip ? Number(skip) : 0, + take: take ? Number(take) : 25, + orderBy: parseJson(orderBy), + where: parseJson(where), + }); + } + + @Get(':id') + findOne(@Param('id') id: string) { + return this.categoryResourceService.findOne({ id }); + } + + @Post() + create(@Body() dto: CreateCategoryResourceDto) { + return this.categoryResourceService.create(dto); + } + + @Patch(':id') + update(@Param('id') id: string, @Body() dto: UpdateCategoryResourceDto) { + return this.categoryResourceService.update({ where: { id }, data: dto }); + } + + @Delete(':id') + remove(@Param('id') id: string) { + return this.categoryResourceService.remove({ id }); + } +} \ No newline at end of file diff --git a/backend/src/category-resource/category-resource.module.ts b/backend/src/category-resource/category-resource.module.ts new file mode 100644 index 0000000..093bd07 --- /dev/null +++ b/backend/src/category-resource/category-resource.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { CategoryResourceService } from './category-resource.service'; +import { CategoryResourceController } from './category-resource.controller'; +import { PrismaService } from '../prisma/prisma.service'; + +@Module({ + controllers: [CategoryResourceController], + providers: [CategoryResourceService, PrismaService], +}) +export class CategoryResourceModule {} \ No newline at end of file diff --git a/backend/src/category-resource/category-resource.service.ts b/backend/src/category-resource/category-resource.service.ts new file mode 100644 index 0000000..b0460fe --- /dev/null +++ b/backend/src/category-resource/category-resource.service.ts @@ -0,0 +1,41 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../prisma/prisma.service'; +import { CategoryResource, Prisma } from '@prisma/client'; + +@Injectable() +export class CategoryResourceService { + constructor(private prisma: PrismaService) {} + + async findAll(params: { + skip?: number; + take?: number; + where?: Prisma.CategoryResourceWhereInput; + orderBy?: Prisma.CategoryResourceOrderByWithRelationInput; + }): Promise<{ data: CategoryResource[]; total: number }> { + const { skip, take, where, orderBy } = params; + const [data, total] = await this.prisma.$transaction([ + this.prisma.categoryResource.findMany({ skip, take, where, orderBy }), + this.prisma.categoryResource.count({ where }), + ]); + return { data, total }; + } + + async findOne(where: Prisma.CategoryResourceWhereUniqueInput): Promise { + return this.prisma.categoryResource.findUnique({ where }); + } + + async create(data: Prisma.CategoryResourceCreateInput): Promise { + return this.prisma.categoryResource.create({ data }); + } + + async update(params: { + where: Prisma.CategoryResourceWhereUniqueInput; + data: Prisma.CategoryResourceUpdateInput; + }): Promise { + return this.prisma.categoryResource.update(params); + } + + async remove(where: Prisma.CategoryResourceWhereUniqueInput): Promise { + return this.prisma.categoryResource.delete({ where }); + } +} \ No newline at end of file diff --git a/backend/src/category-resource/dto/create-category-resource.dto.ts b/backend/src/category-resource/dto/create-category-resource.dto.ts new file mode 100644 index 0000000..ebd6f30 --- /dev/null +++ b/backend/src/category-resource/dto/create-category-resource.dto.ts @@ -0,0 +1,14 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsString, IsOptional } from 'class-validator'; + +export class CreateCategoryResourceDto { + @ApiProperty({ description: 'Идентификатор ЗИП/ТМЦ', required: false }) + @IsString() + @IsOptional() + partId?: string; + + @ApiProperty({ description: 'Код сотрудника', required: false }) + @IsString() + @IsOptional() + employeeCode?: string; +} \ No newline at end of file diff --git a/backend/src/category-resource/dto/update-category-resource.dto.ts b/backend/src/category-resource/dto/update-category-resource.dto.ts new file mode 100644 index 0000000..fb0d3e0 --- /dev/null +++ b/backend/src/category-resource/dto/update-category-resource.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/mapped-types'; +import { CreateCategoryResourceDto } from './create-category-resource.dto'; + +export class UpdateCategoryResourceDto extends PartialType(CreateCategoryResourceDto) {} \ No newline at end of file diff --git a/backend/src/change-equipment-status/change-equipment-status.controller.ts b/backend/src/change-equipment-status/change-equipment-status.controller.ts new file mode 100644 index 0000000..ab1e663 --- /dev/null +++ b/backend/src/change-equipment-status/change-equipment-status.controller.ts @@ -0,0 +1,54 @@ +import { Controller, Get, Post, Body, Patch, Param, Delete, Query, UseGuards } from '@nestjs/common'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { ChangeEquipmentStatusService } from './change-equipment-status.service'; +import { CreateChangeEquipmentStatusDto } from './dto/create-change-equipment-status.dto'; +import { UpdateChangeEquipmentStatusDto } from './dto/update-change-equipment-status.dto'; +import { JwtAuthGuard } from '../auth/jwt-auth.guard'; + +const parseJson = (value?: string): T | undefined => { + if (!value) return undefined; + try { return JSON.parse(value) as T; } catch { return undefined; } +}; + +@ApiTags('change-equipment-status') +@ApiBearerAuth() +@UseGuards(JwtAuthGuard) +@Controller('change-equipment-status') +export class ChangeEquipmentStatusController { + constructor(private readonly changeEquipmentStatusService: ChangeEquipmentStatusService) {} + + @Get() + findAll( + @Query('skip') skip?: string, + @Query('take') take?: string, + @Query('orderBy') orderBy?: string, + @Query('where') where?: string, + ) { + return this.changeEquipmentStatusService.findAll({ + skip: skip ? Number(skip) : 0, + take: take ? Number(take) : 25, + orderBy: parseJson(orderBy), + where: parseJson(where), + }); + } + + @Get(':id') + findOne(@Param('id') id: string) { + return this.changeEquipmentStatusService.findOne({ id }); + } + + @Post() + create(@Body() dto: CreateChangeEquipmentStatusDto) { + return this.changeEquipmentStatusService.create(dto); + } + + @Patch(':id') + update(@Param('id') id: string, @Body() dto: UpdateChangeEquipmentStatusDto) { + return this.changeEquipmentStatusService.update({ where: { id }, data: dto }); + } + + @Delete(':id') + remove(@Param('id') id: string) { + return this.changeEquipmentStatusService.remove({ id }); + } +} \ No newline at end of file diff --git a/backend/src/change-equipment-status/change-equipment-status.module.ts b/backend/src/change-equipment-status/change-equipment-status.module.ts new file mode 100644 index 0000000..27bf136 --- /dev/null +++ b/backend/src/change-equipment-status/change-equipment-status.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { ChangeEquipmentStatusService } from './change-equipment-status.service'; +import { ChangeEquipmentStatusController } from './change-equipment-status.controller'; +import { PrismaService } from '../prisma/prisma.service'; + +@Module({ + controllers: [ChangeEquipmentStatusController], + providers: [ChangeEquipmentStatusService, PrismaService], +}) +export class ChangeEquipmentStatusModule {} \ No newline at end of file diff --git a/backend/src/change-equipment-status/change-equipment-status.service.ts b/backend/src/change-equipment-status/change-equipment-status.service.ts new file mode 100644 index 0000000..972f1b2 --- /dev/null +++ b/backend/src/change-equipment-status/change-equipment-status.service.ts @@ -0,0 +1,41 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../prisma/prisma.service'; +import { ChangeEquipmentStatus, Prisma } from '@prisma/client'; + +@Injectable() +export class ChangeEquipmentStatusService { + constructor(private prisma: PrismaService) {} + + async findAll(params: { + skip?: number; + take?: number; + where?: Prisma.ChangeEquipmentStatusWhereInput; + orderBy?: Prisma.ChangeEquipmentStatusOrderByWithRelationInput; + }): Promise<{ data: ChangeEquipmentStatus[]; total: number }> { + const { skip, take, where, orderBy } = params; + const [data, total] = await this.prisma.$transaction([ + this.prisma.changeEquipmentStatus.findMany({ skip, take, where, orderBy }), + this.prisma.changeEquipmentStatus.count({ where }), + ]); + return { data, total }; + } + + async findOne(where: Prisma.ChangeEquipmentStatusWhereUniqueInput): Promise { + return this.prisma.changeEquipmentStatus.findUnique({ where }); + } + + async create(data: Prisma.ChangeEquipmentStatusCreateInput): Promise { + return this.prisma.changeEquipmentStatus.create({ data }); + } + + async update(params: { + where: Prisma.ChangeEquipmentStatusWhereUniqueInput; + data: Prisma.ChangeEquipmentStatusUpdateInput; + }): Promise { + return this.prisma.changeEquipmentStatus.update(params); + } + + async remove(where: Prisma.ChangeEquipmentStatusWhereUniqueInput): Promise { + return this.prisma.changeEquipmentStatus.delete({ where }); + } +} \ No newline at end of file diff --git a/backend/src/change-equipment-status/dto/create-change-equipment-status.dto.ts b/backend/src/change-equipment-status/dto/create-change-equipment-status.dto.ts new file mode 100644 index 0000000..418ac1c --- /dev/null +++ b/backend/src/change-equipment-status/dto/create-change-equipment-status.dto.ts @@ -0,0 +1,40 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Type } from 'class-transformer'; +import { IsString, IsNotEmpty, IsEnum, IsISO8601, IsOptional } from 'class-validator'; +import { EquipmentStatus } from '@prisma/client'; + +export class CreateChangeEquipmentStatusDto { + @ApiProperty({ description: 'Идентификатор оборудования' }) + @IsString() + @IsNotEmpty() + equipmentId: string; + + @ApiProperty({ enum: EquipmentStatus, enumName: 'EquipmentStatus', description: 'Новый статус' }) + @IsEnum(EquipmentStatus) + newStatus: EquipmentStatus; + + @ApiProperty({ description: 'Номер', required: false }) + @IsString() + @IsOptional() + number?: string; + + @ApiProperty({ description: 'Комментарий', required: false }) + @IsString() + @IsOptional() + comment?: string; + + @ApiProperty({ description: 'Дата изменения статуса' }) + @IsISO8601() + @Type(() => Date) + date: Date; + + @ApiProperty({ description: 'Ответственный', required: false }) + @IsString() + @IsOptional() + responsible?: string; + + @ApiProperty({ description: 'Прикрепить документ (путь/URL)', required: false }) + @IsString() + @IsOptional() + document?: string; +} \ No newline at end of file diff --git a/backend/src/change-equipment-status/dto/update-change-equipment-status.dto.ts b/backend/src/change-equipment-status/dto/update-change-equipment-status.dto.ts new file mode 100644 index 0000000..662bc07 --- /dev/null +++ b/backend/src/change-equipment-status/dto/update-change-equipment-status.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/mapped-types'; +import { CreateChangeEquipmentStatusDto } from './create-change-equipment-status.dto'; + +export class UpdateChangeEquipmentStatusDto extends PartialType(CreateChangeEquipmentStatusDto) {} \ No newline at end of file diff --git a/backend/src/confirmation-document/confirmation-document.controller.ts b/backend/src/confirmation-document/confirmation-document.controller.ts new file mode 100644 index 0000000..ca14c6c --- /dev/null +++ b/backend/src/confirmation-document/confirmation-document.controller.ts @@ -0,0 +1,54 @@ +import { Controller, Get, Post, Body, Patch, Param, Delete, Query, UseGuards } from '@nestjs/common'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { ConfirmationDocumentService } from './confirmation-document.service'; +import { CreateConfirmationDocumentDto } from './dto/create-confirmation-document.dto'; +import { UpdateConfirmationDocumentDto } from './dto/update-confirmation-document.dto'; +import { JwtAuthGuard } from '../auth/jwt-auth.guard'; + +const parseJson = (value?: string): T | undefined => { + if (!value) return undefined; + try { return JSON.parse(value) as T; } catch { return undefined; } +}; + +@ApiTags('confirmation-document') +@ApiBearerAuth() +@UseGuards(JwtAuthGuard) +@Controller('confirmation-document') +export class ConfirmationDocumentController { + constructor(private readonly confirmationDocumentService: ConfirmationDocumentService) {} + + @Get() + findAll( + @Query('skip') skip?: string, + @Query('take') take?: string, + @Query('orderBy') orderBy?: string, + @Query('where') where?: string, + ) { + return this.confirmationDocumentService.findAll({ + skip: skip ? Number(skip) : 0, + take: take ? Number(take) : 25, + orderBy: parseJson(orderBy), + where: parseJson(where), + }); + } + + @Get(':id') + findOne(@Param('id') id: string) { + return this.confirmationDocumentService.findOne({ id }); + } + + @Post() + create(@Body() dto: CreateConfirmationDocumentDto) { + return this.confirmationDocumentService.create(dto); + } + + @Patch(':id') + update(@Param('id') id: string, @Body() dto: UpdateConfirmationDocumentDto) { + return this.confirmationDocumentService.update({ where: { id }, data: dto }); + } + + @Delete(':id') + remove(@Param('id') id: string) { + return this.confirmationDocumentService.remove({ id }); + } +} \ No newline at end of file diff --git a/backend/src/confirmation-document/confirmation-document.module.ts b/backend/src/confirmation-document/confirmation-document.module.ts new file mode 100644 index 0000000..e594c3d --- /dev/null +++ b/backend/src/confirmation-document/confirmation-document.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { ConfirmationDocumentService } from './confirmation-document.service'; +import { ConfirmationDocumentController } from './confirmation-document.controller'; +import { PrismaService } from '../prisma/prisma.service'; + +@Module({ + controllers: [ConfirmationDocumentController], + providers: [ConfirmationDocumentService, PrismaService], +}) +export class ConfirmationDocumentModule {} \ No newline at end of file diff --git a/backend/src/confirmation-document/confirmation-document.service.ts b/backend/src/confirmation-document/confirmation-document.service.ts new file mode 100644 index 0000000..6d4029e --- /dev/null +++ b/backend/src/confirmation-document/confirmation-document.service.ts @@ -0,0 +1,41 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../prisma/prisma.service'; +import { ConfirmationDocument, Prisma } from '@prisma/client'; + +@Injectable() +export class ConfirmationDocumentService { + constructor(private prisma: PrismaService) {} + + async findAll(params: { + skip?: number; + take?: number; + where?: Prisma.ConfirmationDocumentWhereInput; + orderBy?: Prisma.ConfirmationDocumentOrderByWithRelationInput; + }): Promise<{ data: ConfirmationDocument[]; total: number }> { + const { skip, take, where, orderBy } = params; + const [data, total] = await this.prisma.$transaction([ + this.prisma.confirmationDocument.findMany({ skip, take, where, orderBy }), + this.prisma.confirmationDocument.count({ where }), + ]); + return { data, total }; + } + + async findOne(where: Prisma.ConfirmationDocumentWhereUniqueInput): Promise { + return this.prisma.confirmationDocument.findUnique({ where }); + } + + async create(data: Prisma.ConfirmationDocumentCreateInput): Promise { + return this.prisma.confirmationDocument.create({ data }); + } + + async update(params: { + where: Prisma.ConfirmationDocumentWhereUniqueInput; + data: Prisma.ConfirmationDocumentUpdateInput; + }): Promise { + return this.prisma.confirmationDocument.update(params); + } + + async remove(where: Prisma.ConfirmationDocumentWhereUniqueInput): Promise { + return this.prisma.confirmationDocument.delete({ where }); + } +} \ No newline at end of file diff --git a/backend/src/confirmation-document/dto/create-confirmation-document.dto.ts b/backend/src/confirmation-document/dto/create-confirmation-document.dto.ts new file mode 100644 index 0000000..4d20659 --- /dev/null +++ b/backend/src/confirmation-document/dto/create-confirmation-document.dto.ts @@ -0,0 +1,30 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Type } from 'class-transformer'; +import { IsString, IsNotEmpty, IsISO8601, IsOptional, IsBoolean } from 'class-validator'; + +export class CreateConfirmationDocumentDto { + @ApiProperty({ description: 'Номер', required: false }) + @IsString() + @IsOptional() + number?: string; + + @ApiProperty({ description: 'Дата согласования' }) + @IsISO8601() + @Type(() => Date) + date: Date; + + @ApiProperty({ description: 'Код руководителя, который согласовал', required: false }) + @IsString() + @IsOptional() + managerCode?: string; + + @ApiProperty({ description: 'Идентификатор заявки, которую согласовал' }) + @IsString() + @IsNotEmpty() + orderId: string; + + @ApiProperty({ description: 'Согласовано/Не согласовано', required: false }) + @IsBoolean() + @IsOptional() + confirmed?: boolean; +} \ No newline at end of file diff --git a/backend/src/confirmation-document/dto/update-confirmation-document.dto.ts b/backend/src/confirmation-document/dto/update-confirmation-document.dto.ts new file mode 100644 index 0000000..0e9a805 --- /dev/null +++ b/backend/src/confirmation-document/dto/update-confirmation-document.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/mapped-types'; +import { CreateConfirmationDocumentDto } from './create-confirmation-document.dto'; + +export class UpdateConfirmationDocumentDto extends PartialType(CreateConfirmationDocumentDto) {} \ No newline at end of file diff --git a/backend/src/consumption-registration/consumption-registration.controller.ts b/backend/src/consumption-registration/consumption-registration.controller.ts new file mode 100644 index 0000000..8446fe0 --- /dev/null +++ b/backend/src/consumption-registration/consumption-registration.controller.ts @@ -0,0 +1,54 @@ +import { Controller, Get, Post, Body, Patch, Param, Delete, Query, UseGuards } from '@nestjs/common'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { ConsumptionRegistrationService } from './consumption-registration.service'; +import { CreateConsumptionRegistrationDto } from './dto/create-consumption-registration.dto'; +import { UpdateConsumptionRegistrationDto } from './dto/update-consumption-registration.dto'; +import { JwtAuthGuard } from '../auth/jwt-auth.guard'; + +const parseJson = (value?: string): T | undefined => { + if (!value) return undefined; + try { return JSON.parse(value) as T; } catch { return undefined; } +}; + +@ApiTags('consumption-registration') +@ApiBearerAuth() +@UseGuards(JwtAuthGuard) +@Controller('consumption-registration') +export class ConsumptionRegistrationController { + constructor(private readonly consumptionRegistrationService: ConsumptionRegistrationService) {} + + @Get() + findAll( + @Query('skip') skip?: string, + @Query('take') take?: string, + @Query('orderBy') orderBy?: string, + @Query('where') where?: string, + ) { + return this.consumptionRegistrationService.findAll({ + skip: skip ? Number(skip) : 0, + take: take ? Number(take) : 25, + orderBy: parseJson(orderBy), + where: parseJson(where), + }); + } + + @Get(':id') + findOne(@Param('id') id: string) { + return this.consumptionRegistrationService.findOne({ id }); + } + + @Post() + create(@Body() dto: CreateConsumptionRegistrationDto) { + return this.consumptionRegistrationService.create(dto); + } + + @Patch(':id') + update(@Param('id') id: string, @Body() dto: UpdateConsumptionRegistrationDto) { + return this.consumptionRegistrationService.update({ where: { id }, data: dto }); + } + + @Delete(':id') + remove(@Param('id') id: string) { + return this.consumptionRegistrationService.remove({ id }); + } +} \ No newline at end of file diff --git a/backend/src/consumption-registration/consumption-registration.module.ts b/backend/src/consumption-registration/consumption-registration.module.ts new file mode 100644 index 0000000..f2d1d67 --- /dev/null +++ b/backend/src/consumption-registration/consumption-registration.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { ConsumptionRegistrationService } from './consumption-registration.service'; +import { ConsumptionRegistrationController } from './consumption-registration.controller'; +import { PrismaService } from '../prisma/prisma.service'; + +@Module({ + controllers: [ConsumptionRegistrationController], + providers: [ConsumptionRegistrationService, PrismaService], +}) +export class ConsumptionRegistrationModule {} \ No newline at end of file diff --git a/backend/src/consumption-registration/consumption-registration.service.ts b/backend/src/consumption-registration/consumption-registration.service.ts new file mode 100644 index 0000000..f54fa7d --- /dev/null +++ b/backend/src/consumption-registration/consumption-registration.service.ts @@ -0,0 +1,41 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../prisma/prisma.service'; +import { ConsumptionRegistration, Prisma } from '@prisma/client'; + +@Injectable() +export class ConsumptionRegistrationService { + constructor(private prisma: PrismaService) {} + + async findAll(params: { + skip?: number; + take?: number; + where?: Prisma.ConsumptionRegistrationWhereInput; + orderBy?: Prisma.ConsumptionRegistrationOrderByWithRelationInput; + }): Promise<{ data: ConsumptionRegistration[]; total: number }> { + const { skip, take, where, orderBy } = params; + const [data, total] = await this.prisma.$transaction([ + this.prisma.consumptionRegistration.findMany({ skip, take, where, orderBy }), + this.prisma.consumptionRegistration.count({ where }), + ]); + return { data, total }; + } + + async findOne(where: Prisma.ConsumptionRegistrationWhereUniqueInput): Promise { + return this.prisma.consumptionRegistration.findUnique({ where }); + } + + async create(data: Prisma.ConsumptionRegistrationCreateInput): Promise { + return this.prisma.consumptionRegistration.create({ data }); + } + + async update(params: { + where: Prisma.ConsumptionRegistrationWhereUniqueInput; + data: Prisma.ConsumptionRegistrationUpdateInput; + }): Promise { + return this.prisma.consumptionRegistration.update(params); + } + + async remove(where: Prisma.ConsumptionRegistrationWhereUniqueInput): Promise { + return this.prisma.consumptionRegistration.delete({ where }); + } +} \ No newline at end of file diff --git a/backend/src/consumption-registration/dto/create-consumption-registration.dto.ts b/backend/src/consumption-registration/dto/create-consumption-registration.dto.ts new file mode 100644 index 0000000..5e84055 --- /dev/null +++ b/backend/src/consumption-registration/dto/create-consumption-registration.dto.ts @@ -0,0 +1,29 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Type } from 'class-transformer'; +import { IsString, IsNotEmpty, IsISO8601, IsOptional, IsNumber } from 'class-validator'; + +export class CreateConsumptionRegistrationDto { + @ApiProperty({ description: 'Номер', required: false }) + @IsString() + @IsOptional() + number?: string; + + @ApiProperty({ description: 'Дата регистрации' }) + @IsISO8601() + @Type(() => Date) + date: Date; + + @ApiProperty({ description: 'Идентификатор оборудования' }) + @IsString() + @IsNotEmpty() + equipmentId: string; + + @ApiProperty({ description: 'Наработка', required: false }) + @IsOptional() + totalEngineHours?: any; + + @ApiProperty({ description: 'Расход топлива', required: false }) + @IsNumber() + @IsOptional() + fuelConsumption?: number; +} \ No newline at end of file diff --git a/backend/src/consumption-registration/dto/update-consumption-registration.dto.ts b/backend/src/consumption-registration/dto/update-consumption-registration.dto.ts new file mode 100644 index 0000000..e03517a --- /dev/null +++ b/backend/src/consumption-registration/dto/update-consumption-registration.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/mapped-types'; +import { CreateConsumptionRegistrationDto } from './create-consumption-registration.dto'; + +export class UpdateConsumptionRegistrationDto extends PartialType(CreateConsumptionRegistrationDto) {} \ No newline at end of file diff --git a/backend/src/employee/dto/create-employee.dto.ts b/backend/src/employee/dto/create-employee.dto.ts new file mode 100644 index 0000000..da74f68 --- /dev/null +++ b/backend/src/employee/dto/create-employee.dto.ts @@ -0,0 +1,39 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsString, IsNotEmpty, IsEnum, IsOptional, IsNumber } from 'class-validator'; +import { Role } from '@prisma/client'; + +export class CreateEmployeeDto { + @ApiProperty({ description: 'Номер сотрудника (Табельный номер)' }) + @IsString() + @IsNotEmpty() + code: string; + + @ApiProperty({ description: 'ФИО сотрудника' }) + @IsString() + @IsNotEmpty() + fullName: string; + + @ApiProperty({ enum: Role, enumName: 'Role', description: 'Роль сотрудника' }) + @IsEnum(Role) + role: Role; + + @ApiProperty({ description: 'Должность сотрудника' }) + @IsString() + @IsNotEmpty() + position: string; + + @ApiProperty({ description: 'Код руководителя', required: false }) + @IsString() + @IsOptional() + bossCode?: string; + + @ApiProperty({ description: 'Стоимость часа работы сотрудника', required: false }) + @IsNumber() + @IsOptional() + price?: number; + + @ApiProperty({ description: 'Номер телефона', required: false }) + @IsNumber() + @IsOptional() + phoneNumber?: number; +} \ No newline at end of file diff --git a/backend/src/employee/dto/update-employee.dto.ts b/backend/src/employee/dto/update-employee.dto.ts new file mode 100644 index 0000000..7180917 --- /dev/null +++ b/backend/src/employee/dto/update-employee.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/mapped-types'; +import { CreateEmployeeDto } from './create-employee.dto'; + +export class UpdateEmployeeDto extends PartialType(CreateEmployeeDto) {} \ No newline at end of file diff --git a/backend/src/employee/employee.controller.ts b/backend/src/employee/employee.controller.ts new file mode 100644 index 0000000..3c4a50b --- /dev/null +++ b/backend/src/employee/employee.controller.ts @@ -0,0 +1,54 @@ +import { Controller, Get, Post, Body, Patch, Param, Delete, Query, UseGuards } from '@nestjs/common'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { EmployeeService } from './employee.service'; +import { CreateEmployeeDto } from './dto/create-employee.dto'; +import { UpdateEmployeeDto } from './dto/update-employee.dto'; +import { JwtAuthGuard } from '../auth/jwt-auth.guard'; + +const parseJson = (value?: string): T | undefined => { + if (!value) return undefined; + try { return JSON.parse(value) as T; } catch { return undefined; } +}; + +@ApiTags('employee') +@ApiBearerAuth() +@UseGuards(JwtAuthGuard) +@Controller('employee') +export class EmployeeController { + constructor(private readonly employeeService: EmployeeService) {} + + @Get() + findAll( + @Query('skip') skip?: string, + @Query('take') take?: string, + @Query('orderBy') orderBy?: string, + @Query('where') where?: string, + ) { + return this.employeeService.findAll({ + skip: skip ? Number(skip) : 0, + take: take ? Number(take) : 25, + orderBy: parseJson(orderBy), + where: parseJson(where), + }); + } + + @Get(':code') + findOne(@Param('code') code: string) { + return this.employeeService.findOne({ code }); + } + + @Post() + create(@Body() dto: CreateEmployeeDto) { + return this.employeeService.create(dto); + } + + @Patch(':code') + update(@Param('code') code: string, @Body() dto: UpdateEmployeeDto) { + return this.employeeService.update({ where: { code }, data: dto }); + } + + @Delete(':code') + remove(@Param('code') code: string) { + return this.employeeService.remove({ code }); + } +} \ No newline at end of file diff --git a/backend/src/employee/employee.module.ts b/backend/src/employee/employee.module.ts new file mode 100644 index 0000000..d5b87d0 --- /dev/null +++ b/backend/src/employee/employee.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { EmployeeService } from './employee.service'; +import { EmployeeController } from './employee.controller'; +import { PrismaService } from '../prisma/prisma.service'; + +@Module({ + controllers: [EmployeeController], + providers: [EmployeeService, PrismaService], +}) +export class EmployeeModule {} \ No newline at end of file diff --git a/backend/src/employee/employee.service.ts b/backend/src/employee/employee.service.ts new file mode 100644 index 0000000..59b71e3 --- /dev/null +++ b/backend/src/employee/employee.service.ts @@ -0,0 +1,41 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../prisma/prisma.service'; +import { Employee, Prisma } from '@prisma/client'; + +@Injectable() +export class EmployeeService { + constructor(private prisma: PrismaService) {} + + async findAll(params: { + skip?: number; + take?: number; + where?: Prisma.EmployeeWhereInput; + orderBy?: Prisma.EmployeeOrderByWithRelationInput; + }): Promise<{ data: Employee[]; total: number }> { + const { skip, take, where, orderBy } = params; + const [data, total] = await this.prisma.$transaction([ + this.prisma.employee.findMany({ skip, take, where, orderBy }), + this.prisma.employee.count({ where }), + ]); + return { data, total }; + } + + async findOne(where: Prisma.EmployeeWhereUniqueInput): Promise { + return this.prisma.employee.findUnique({ where }); + } + + async create(data: Prisma.EmployeeCreateInput): Promise { + return this.prisma.employee.create({ data }); + } + + async update(params: { + where: Prisma.EmployeeWhereUniqueInput; + data: Prisma.EmployeeUpdateInput; + }): Promise { + return this.prisma.employee.update(params); + } + + async remove(where: Prisma.EmployeeWhereUniqueInput): Promise { + return this.prisma.employee.delete({ where }); + } +} \ No newline at end of file diff --git a/backend/src/equipment/dto/create-equipment.dto.ts b/backend/src/equipment/dto/create-equipment.dto.ts new file mode 100644 index 0000000..a174643 --- /dev/null +++ b/backend/src/equipment/dto/create-equipment.dto.ts @@ -0,0 +1,75 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Type } from 'class-transformer'; +import { IsString, IsNotEmpty, IsEnum, IsISO8601, IsOptional, IsNumber } from 'class-validator'; +import { EquipmentType, EnumPeriodicityTO, EquipmentStatus, laborOperation } from '@prisma/client'; + +export class CreateEquipmentDto { + @ApiProperty({ description: 'Название оборудования' }) + @IsString() + @IsNotEmpty() + name: string; + + @ApiProperty({ description: 'Заводской (серийный) номер' }) + @IsString() + @IsNotEmpty() + serialNumber: string; + + @ApiProperty({ description: 'Инвентарный номер', required: true }) + @IsString() + @IsNotEmpty() + inventoryNumber: string; + + @ApiProperty({ enum: EquipmentType, enumName: 'EquipmentType', description: 'Тип оборудования' }) + @IsEnum(EquipmentType) + equipmentType: EquipmentType; + + @ApiProperty({ enum: EnumPeriodicityTO, enumName: 'EnumPeriodicityTO', description: 'Периодичность ТО' }) + @IsEnum(EnumPeriodicityTO) + periodicityTO: EnumPeriodicityTO; + + @ApiProperty({ enum: EquipmentStatus, enumName: 'EquipmentStatus', description: 'Текущий статус', required: false }) + @IsEnum(EquipmentStatus) + @IsOptional() + status?: EquipmentStatus; + + @ApiProperty({ description: 'Дата проверки', required: false }) + @IsISO8601() + @Type(() => Date) + @IsOptional() + dateOfInspection?: Date; + + @ApiProperty({ description: 'Год изготовления', required: false }) + @IsISO8601() + @Type(() => Date) + @IsOptional() + commissionedAt?: Date; + + @ApiProperty({ description: 'Общая наработка, моточасов', required: false }) + @IsOptional() + totalEngineHours?: any; + + @ApiProperty({ description: 'Наработка с последнего ремонта, моточасов', required: false }) + @IsOptional() + engineHoursSinceLastRepair?: any; + + @ApiProperty({ description: 'Дата последнего ремонта', required: false }) + @IsISO8601() + @Type(() => Date) + @IsOptional() + lastRepairAt?: Date; + + @ApiProperty({ description: 'Примечания', required: false }) + @IsString() + @IsOptional() + notes?: string; + + @ApiProperty({ enum: laborOperation, enumName: 'laborOperation', description: 'Работы в составе', required: false }) + @IsEnum(laborOperation) + @IsOptional() + workAsPartOf?: laborOperation; + + @ApiProperty({ description: 'Расход топлива', required: false }) + @IsNumber() + @IsOptional() + fuelСonsumed?: number; +} \ No newline at end of file diff --git a/backend/src/equipment/dto/update-equipment.dto.ts b/backend/src/equipment/dto/update-equipment.dto.ts new file mode 100644 index 0000000..b6c9a4b --- /dev/null +++ b/backend/src/equipment/dto/update-equipment.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/mapped-types'; +import { CreateEquipmentDto } from './create-equipment.dto'; + +export class UpdateEquipmentDto extends PartialType(CreateEquipmentDto) {} \ No newline at end of file diff --git a/backend/src/equipment/equipment.controller.ts b/backend/src/equipment/equipment.controller.ts new file mode 100644 index 0000000..5afc1cb --- /dev/null +++ b/backend/src/equipment/equipment.controller.ts @@ -0,0 +1,54 @@ +import { Controller, Get, Post, Body, Patch, Param, Delete, Query, UseGuards } from '@nestjs/common'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { EquipmentService } from './equipment.service'; +import { CreateEquipmentDto } from './dto/create-equipment.dto'; +import { UpdateEquipmentDto } from './dto/update-equipment.dto'; +import { JwtAuthGuard } from '../auth/jwt-auth.guard'; + +const parseJson = (value?: string): T | undefined => { + if (!value) return undefined; + try { return JSON.parse(value) as T; } catch { return undefined; } +}; + +@ApiTags('equipment') +@ApiBearerAuth() +@UseGuards(JwtAuthGuard) +@Controller('equipment') +export class EquipmentController { + constructor(private readonly equipmentService: EquipmentService) {} + + @Get() + findAll( + @Query('skip') skip?: string, + @Query('take') take?: string, + @Query('orderBy') orderBy?: string, + @Query('where') where?: string, + ) { + return this.equipmentService.findAll({ + skip: skip ? Number(skip) : 0, + take: take ? Number(take) : 25, + orderBy: parseJson(orderBy), + where: parseJson(where), + }); + } + + @Get(':id') + findOne(@Param('id') id: string) { + return this.equipmentService.findOne({ id }); + } + + @Post() + create(@Body() dto: CreateEquipmentDto) { + return this.equipmentService.create(dto); + } + + @Patch(':id') + update(@Param('id') id: string, @Body() dto: UpdateEquipmentDto) { + return this.equipmentService.update({ where: { id }, data: dto }); + } + + @Delete(':id') + remove(@Param('id') id: string) { + return this.equipmentService.remove({ id }); + } +} \ No newline at end of file diff --git a/backend/src/equipment/equipment.module.ts b/backend/src/equipment/equipment.module.ts new file mode 100644 index 0000000..4b324f7 --- /dev/null +++ b/backend/src/equipment/equipment.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { EquipmentService } from './equipment.service'; +import { EquipmentController } from './equipment.controller'; +import { PrismaService } from '../prisma/prisma.service'; + +@Module({ + controllers: [EquipmentController], + providers: [EquipmentService, PrismaService], +}) +export class EquipmentModule {} \ No newline at end of file diff --git a/backend/src/equipment/equipment.service.ts b/backend/src/equipment/equipment.service.ts new file mode 100644 index 0000000..26098ec --- /dev/null +++ b/backend/src/equipment/equipment.service.ts @@ -0,0 +1,41 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../prisma/prisma.service'; +import { Equipment, Prisma } from '@prisma/client'; + +@Injectable() +export class EquipmentService { + constructor(private prisma: PrismaService) {} + + async findAll(params: { + skip?: number; + take?: number; + where?: Prisma.EquipmentWhereInput; + orderBy?: Prisma.EquipmentOrderByWithRelationInput; + }): Promise<{ data: Equipment[]; total: number }> { + const { skip, take, where, orderBy } = params; + const [data, total] = await this.prisma.$transaction([ + this.prisma.equipment.findMany({ skip, take, where, orderBy }), + this.prisma.equipment.count({ where }), + ]); + return { data, total }; + } + + async findOne(where: Prisma.EquipmentWhereUniqueInput): Promise { + return this.prisma.equipment.findUnique({ where }); + } + + async create(data: Prisma.EquipmentCreateInput): Promise { + return this.prisma.equipment.create({ data }); + } + + async update(params: { + where: Prisma.EquipmentWhereUniqueInput; + data: Prisma.EquipmentUpdateInput; + }): Promise { + return this.prisma.equipment.update(params); + } + + async remove(where: Prisma.EquipmentWhereUniqueInput): Promise { + return this.prisma.equipment.delete({ where }); + } +} \ No newline at end of file diff --git a/backend/src/part/dto/create-part.dto.ts b/backend/src/part/dto/create-part.dto.ts new file mode 100644 index 0000000..6d9d673 --- /dev/null +++ b/backend/src/part/dto/create-part.dto.ts @@ -0,0 +1,30 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsString, IsNotEmpty, IsEnum, IsOptional, IsNumber } from 'class-validator'; +import { CategoryPart } from '@prisma/client'; + +export class CreatePartDto { + @ApiProperty({ description: 'Название' }) + @IsString() + @IsNotEmpty() + name: string; + + @ApiProperty({ enum: CategoryPart, enumName: 'CategoryPart', description: 'Категории', required: false }) + @IsEnum(CategoryPart) + @IsOptional() + categories?: CategoryPart; + + @ApiProperty({ description: 'Стоимость ЗИП/ТМЦ', required: false }) + @IsNumber() + @IsOptional() + price?: number; + + @ApiProperty({ description: 'Описание ЗИП/ТМЦ', required: false }) + @IsString() + @IsOptional() + description?: string; + + @ApiProperty({ description: 'Серийный номер запасных частей / инструментов / расходников', required: false }) + @IsString() + @IsOptional() + serialNumber?: string; +} \ No newline at end of file diff --git a/backend/src/part/dto/update-part.dto.ts b/backend/src/part/dto/update-part.dto.ts new file mode 100644 index 0000000..bba96fe --- /dev/null +++ b/backend/src/part/dto/update-part.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/mapped-types'; +import { CreatePartDto } from './create-part.dto'; + +export class UpdatePartDto extends PartialType(CreatePartDto) {} \ No newline at end of file diff --git a/backend/src/part/part.controller.ts b/backend/src/part/part.controller.ts new file mode 100644 index 0000000..89b49b6 --- /dev/null +++ b/backend/src/part/part.controller.ts @@ -0,0 +1,54 @@ +import { Controller, Get, Post, Body, Patch, Param, Delete, Query, UseGuards } from '@nestjs/common'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { PartService } from './part.service'; +import { CreatePartDto } from './dto/create-part.dto'; +import { UpdatePartDto } from './dto/update-part.dto'; +import { JwtAuthGuard } from '../auth/jwt-auth.guard'; + +const parseJson = (value?: string): T | undefined => { + if (!value) return undefined; + try { return JSON.parse(value) as T; } catch { return undefined; } +}; + +@ApiTags('part') +@ApiBearerAuth() +@UseGuards(JwtAuthGuard) +@Controller('part') +export class PartController { + constructor(private readonly partService: PartService) {} + + @Get() + findAll( + @Query('skip') skip?: string, + @Query('take') take?: string, + @Query('orderBy') orderBy?: string, + @Query('where') where?: string, + ) { + return this.partService.findAll({ + skip: skip ? Number(skip) : 0, + take: take ? Number(take) : 25, + orderBy: parseJson(orderBy), + where: parseJson(where), + }); + } + + @Get(':id') + findOne(@Param('id') id: string) { + return this.partService.findOne({ id }); + } + + @Post() + create(@Body() dto: CreatePartDto) { + return this.partService.create(dto); + } + + @Patch(':id') + update(@Param('id') id: string, @Body() dto: UpdatePartDto) { + return this.partService.update({ where: { id }, data: dto }); + } + + @Delete(':id') + remove(@Param('id') id: string) { + return this.partService.remove({ id }); + } +} \ No newline at end of file diff --git a/backend/src/part/part.module.ts b/backend/src/part/part.module.ts new file mode 100644 index 0000000..94f417f --- /dev/null +++ b/backend/src/part/part.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { PartService } from './part.service'; +import { PartController } from './part.controller'; +import { PrismaService } from '../prisma/prisma.service'; + +@Module({ + controllers: [PartController], + providers: [PartService, PrismaService], +}) +export class PartModule {} \ No newline at end of file diff --git a/backend/src/part/part.service.ts b/backend/src/part/part.service.ts new file mode 100644 index 0000000..7c08f11 --- /dev/null +++ b/backend/src/part/part.service.ts @@ -0,0 +1,41 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../prisma/prisma.service'; +import { Part, Prisma } from '@prisma/client'; + +@Injectable() +export class PartService { + constructor(private prisma: PrismaService) {} + + async findAll(params: { + skip?: number; + take?: number; + where?: Prisma.PartWhereInput; + orderBy?: Prisma.PartOrderByWithRelationInput; + }): Promise<{ data: Part[]; total: number }> { + const { skip, take, where, orderBy } = params; + const [data, total] = await this.prisma.$transaction([ + this.prisma.part.findMany({ skip, take, where, orderBy }), + this.prisma.part.count({ where }), + ]); + return { data, total }; + } + + async findOne(where: Prisma.PartWhereUniqueInput): Promise { + return this.prisma.part.findUnique({ where }); + } + + async create(data: Prisma.PartCreateInput): Promise { + return this.prisma.part.create({ data }); + } + + async update(params: { + where: Prisma.PartWhereUniqueInput; + data: Prisma.PartUpdateInput; + }): Promise { + return this.prisma.part.update(params); + } + + async remove(where: Prisma.PartWhereUniqueInput): Promise { + return this.prisma.part.delete({ where }); + } +} \ No newline at end of file diff --git a/backend/src/repair-order/dto/create-repair-order.dto.ts b/backend/src/repair-order/dto/create-repair-order.dto.ts new file mode 100644 index 0000000..00ed1dd --- /dev/null +++ b/backend/src/repair-order/dto/create-repair-order.dto.ts @@ -0,0 +1,71 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Type } from 'class-transformer'; +import { IsString, IsNotEmpty, IsEnum, IsISO8601, IsOptional, IsBoolean } from 'class-validator'; +import { RepairKind, RepairOrderStatus } from '@prisma/client'; + +export class CreateRepairOrderDto { + @ApiProperty({ description: 'Номер заявки' }) + @IsString() + @IsNotEmpty() + number: string; + + @ApiProperty({ description: 'Дата заявки' }) + @IsISO8601() + @Type(() => Date) + date: Date; + + @ApiProperty({ description: 'Идентификатор оборудования' }) + @IsString() + @IsNotEmpty() + equipmentId: string; + + @ApiProperty({ enum: RepairKind, enumName: 'RepairKind', description: 'Вид ремонта' }) + @IsEnum(RepairKind) + repairKind: RepairKind; + + @ApiProperty({ enum: RepairOrderStatus, enumName: 'RepairOrderStatus', description: 'Статус заявки', required: false }) + @IsEnum(RepairOrderStatus) + @IsOptional() + status?: RepairOrderStatus; + + @ApiProperty({ description: 'Плановая дата начала' }) + @IsISO8601() + @Type(() => Date) + plannedAt: Date; + + @ApiProperty({ description: 'Фактическая дата начала', required: false }) + @IsISO8601() + @Type(() => Date) + @IsOptional() + startedAt?: Date; + + @ApiProperty({ description: 'Фактическая дата завершения', required: false }) + @IsISO8601() + @Type(() => Date) + @IsOptional() + completedAt?: Date; + + @ApiProperty({ description: 'Подрядная организация (если внешний ремонт)', required: false }) + @IsString() + @IsOptional() + contractor?: string; + + @ApiProperty({ description: 'Наработка на момент ремонта, моточасов', required: false }) + @IsOptional() + engineHoursAtRepair?: any; + + @ApiProperty({ description: 'Описание работ / дефекта', required: false }) + @IsString() + @IsOptional() + description?: string; + + @ApiProperty({ description: 'Примечания', required: false }) + @IsString() + @IsOptional() + notes?: string; + + @ApiProperty({ description: 'Согласовано/Не согласовано', required: false }) + @IsBoolean() + @IsOptional() + confirmed?: boolean; +} \ No newline at end of file diff --git a/backend/src/repair-order/dto/update-repair-order.dto.ts b/backend/src/repair-order/dto/update-repair-order.dto.ts new file mode 100644 index 0000000..dc04866 --- /dev/null +++ b/backend/src/repair-order/dto/update-repair-order.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/mapped-types'; +import { CreateRepairOrderDto } from './create-repair-order.dto'; + +export class UpdateRepairOrderDto extends PartialType(CreateRepairOrderDto) {} \ No newline at end of file diff --git a/backend/src/repair-order/repair-order.controller.ts b/backend/src/repair-order/repair-order.controller.ts new file mode 100644 index 0000000..889da59 --- /dev/null +++ b/backend/src/repair-order/repair-order.controller.ts @@ -0,0 +1,54 @@ +import { Controller, Get, Post, Body, Patch, Param, Delete, Query, UseGuards } from '@nestjs/common'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { RepairOrderService } from './repair-order.service'; +import { CreateRepairOrderDto } from './dto/create-repair-order.dto'; +import { UpdateRepairOrderDto } from './dto/update-repair-order.dto'; +import { JwtAuthGuard } from '../auth/jwt-auth.guard'; + +const parseJson = (value?: string): T | undefined => { + if (!value) return undefined; + try { return JSON.parse(value) as T; } catch { return undefined; } +}; + +@ApiTags('repair-order') +@ApiBearerAuth() +@UseGuards(JwtAuthGuard) +@Controller('repair-order') +export class RepairOrderController { + constructor(private readonly repairOrderService: RepairOrderService) {} + + @Get() + findAll( + @Query('skip') skip?: string, + @Query('take') take?: string, + @Query('orderBy') orderBy?: string, + @Query('where') where?: string, + ) { + return this.repairOrderService.findAll({ + skip: skip ? Number(skip) : 0, + take: take ? Number(take) : 25, + orderBy: parseJson(orderBy), + where: parseJson(where), + }); + } + + @Get(':id') + findOne(@Param('id') id: string) { + return this.repairOrderService.findOne({ id }); + } + + @Post() + create(@Body() dto: CreateRepairOrderDto) { + return this.repairOrderService.create(dto); + } + + @Patch(':id') + update(@Param('id') id: string, @Body() dto: UpdateRepairOrderDto) { + return this.repairOrderService.update({ where: { id }, data: dto }); + } + + @Delete(':id') + remove(@Param('id') id: string) { + return this.repairOrderService.remove({ id }); + } +} \ No newline at end of file diff --git a/backend/src/repair-order/repair-order.module.ts b/backend/src/repair-order/repair-order.module.ts new file mode 100644 index 0000000..a30fd57 --- /dev/null +++ b/backend/src/repair-order/repair-order.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { RepairOrderService } from './repair-order.service'; +import { RepairOrderController } from './repair-order.controller'; +import { PrismaService } from '../prisma/prisma.service'; + +@Module({ + controllers: [RepairOrderController], + providers: [RepairOrderService, PrismaService], +}) +export class RepairOrderModule {} \ No newline at end of file diff --git a/backend/src/repair-order/repair-order.service.ts b/backend/src/repair-order/repair-order.service.ts new file mode 100644 index 0000000..493d9ac --- /dev/null +++ b/backend/src/repair-order/repair-order.service.ts @@ -0,0 +1,41 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../prisma/prisma.service'; +import { RepairOrder, Prisma } from '@prisma/client'; + +@Injectable() +export class RepairOrderService { + constructor(private prisma: PrismaService) {} + + async findAll(params: { + skip?: number; + take?: number; + where?: Prisma.RepairOrderWhereInput; + orderBy?: Prisma.RepairOrderOrderByWithRelationInput; + }): Promise<{ data: RepairOrder[]; total: number }> { + const { skip, take, where, orderBy } = params; + const [data, total] = await this.prisma.$transaction([ + this.prisma.repairOrder.findMany({ skip, take, where, orderBy }), + this.prisma.repairOrder.count({ where }), + ]); + return { data, total }; + } + + async findOne(where: Prisma.RepairOrderWhereUniqueInput): Promise { + return this.prisma.repairOrder.findUnique({ where }); + } + + async create(data: Prisma.RepairOrderCreateInput): Promise { + return this.prisma.repairOrder.create({ data }); + } + + async update(params: { + where: Prisma.RepairOrderWhereUniqueInput; + data: Prisma.RepairOrderUpdateInput; + }): Promise { + return this.prisma.repairOrder.update(params); + } + + async remove(where: Prisma.RepairOrderWhereUniqueInput): Promise { + return this.prisma.repairOrder.delete({ where }); + } +} \ No newline at end of file diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx new file mode 100644 index 0000000..83d6af7 --- /dev/null +++ b/frontend/src/App.tsx @@ -0,0 +1,90 @@ +import { Admin, Resource } from 'react-admin'; +import { dataProvider } from './dataProvider'; +import { authProvider } from './authProvider'; + +// Equipment +import { EquipmentList, EquipmentCreate, EquipmentEdit, EquipmentShow } from './resources/equipment'; + +// Employee +import { EmployeeList, EmployeeCreate, EmployeeEdit, EmployeeShow } from './resources/employee'; + +// Part +import { PartList, PartCreate, PartEdit, PartShow } from './resources/part'; + +// CategoryResource +import { CategoryResourceList, CategoryResourceCreate, CategoryResourceEdit, CategoryResourceShow } from './resources/category-resource'; + +// RepairOrder +import { RepairOrderList, RepairOrderCreate, RepairOrderEdit, RepairOrderShow } from './resources/repair-order'; + +// ChangeEquipmentStatus +import { ChangeEquipmentStatusList, ChangeEquipmentStatusCreate, ChangeEquipmentStatusEdit, ChangeEquipmentStatusShow } from './resources/change-equipment-status'; + +// ConfirmationDocument +import { ConfirmationDocumentList, ConfirmationDocumentCreate, ConfirmationDocumentEdit, ConfirmationDocumentShow } from './resources/confirmation-document'; + +// ConsumptionRegistration +import { ConsumptionRegistrationList, ConsumptionRegistrationCreate, ConsumptionRegistrationEdit, ConsumptionRegistrationShow } from './resources/consumption-registration'; + +const App = () => ( + + + + + + + + + + +); + +export default App; \ No newline at end of file diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx new file mode 100644 index 0000000..7a4e4db --- /dev/null +++ b/frontend/src/main.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App'; +import { initKeycloak } from './authProvider'; + +// Initialize Keycloak before rendering the app +initKeycloak().then(() => { + ReactDOM.createRoot(document.getElementById('root')!).render( + + + + ); +}).catch((error) => { + console.error('Failed to initialize Keycloak:', error); +}); \ No newline at end of file diff --git a/frontend/src/resources/category-resource/CategoryResourceCreate.tsx b/frontend/src/resources/category-resource/CategoryResourceCreate.tsx new file mode 100644 index 0000000..a00f591 --- /dev/null +++ b/frontend/src/resources/category-resource/CategoryResourceCreate.tsx @@ -0,0 +1,14 @@ +import { Create, SimpleForm, ReferenceInput, SelectInput } from 'react-admin'; + +export const CategoryResourceCreate = () => ( + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/category-resource/CategoryResourceEdit.tsx b/frontend/src/resources/category-resource/CategoryResourceEdit.tsx new file mode 100644 index 0000000..e751754 --- /dev/null +++ b/frontend/src/resources/category-resource/CategoryResourceEdit.tsx @@ -0,0 +1,14 @@ +import { Edit, SimpleForm, ReferenceInput, SelectInput } from 'react-admin'; + +export const CategoryResourceEdit = () => ( + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/category-resource/CategoryResourceList.tsx b/frontend/src/resources/category-resource/CategoryResourceList.tsx new file mode 100644 index 0000000..028e64a --- /dev/null +++ b/frontend/src/resources/category-resource/CategoryResourceList.tsx @@ -0,0 +1,12 @@ +import { List, DataTable, TextField, ReferenceField, EditButton } from 'react-admin'; + +export const CategoryResourceList = () => ( + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/category-resource/CategoryResourceShow.tsx b/frontend/src/resources/category-resource/CategoryResourceShow.tsx new file mode 100644 index 0000000..3c170b2 --- /dev/null +++ b/frontend/src/resources/category-resource/CategoryResourceShow.tsx @@ -0,0 +1,17 @@ +import { Show, SimpleShowLayout, TextField, ReferenceField, DateField } from 'react-admin'; + +export const CategoryResourceShow = () => ( + + + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/category-resource/index.ts b/frontend/src/resources/category-resource/index.ts new file mode 100644 index 0000000..d195feb --- /dev/null +++ b/frontend/src/resources/category-resource/index.ts @@ -0,0 +1,4 @@ +export { CategoryResourceList } from './CategoryResourceList'; +export { CategoryResourceCreate } from './CategoryResourceCreate'; +export { CategoryResourceEdit } from './CategoryResourceEdit'; +export { CategoryResourceShow } from './CategoryResourceShow'; \ No newline at end of file diff --git a/frontend/src/resources/change-equipment-status/ChangeEquipmentStatusCreate.tsx b/frontend/src/resources/change-equipment-status/ChangeEquipmentStatusCreate.tsx new file mode 100644 index 0000000..c90ea0d --- /dev/null +++ b/frontend/src/resources/change-equipment-status/ChangeEquipmentStatusCreate.tsx @@ -0,0 +1,24 @@ +import { Create, SimpleForm, TextInput, DateInput, SelectInput, ReferenceInput } from 'react-admin'; + +const equipmentStatusChoices = [ + { id: 'Active', name: 'В эксплуатации' }, + { id: 'Repair', name: 'В ремонте' }, + { id: 'Reserve', name: 'В резерве' }, + { id: 'WriteOff', name: 'Списано' }, +]; + +export const ChangeEquipmentStatusCreate = () => ( + + + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/change-equipment-status/ChangeEquipmentStatusEdit.tsx b/frontend/src/resources/change-equipment-status/ChangeEquipmentStatusEdit.tsx new file mode 100644 index 0000000..b55c450 --- /dev/null +++ b/frontend/src/resources/change-equipment-status/ChangeEquipmentStatusEdit.tsx @@ -0,0 +1,25 @@ +import { Edit, SimpleForm, TextInput, DateInput, SelectInput, ReferenceInput } from 'react-admin'; + +const equipmentStatusChoices = [ + { id: 'Active', name: 'В эксплуатации' }, + { id: 'Repair', name: 'В ремонте' }, + { id: 'Reserve', name: 'В резерве' }, + { id: 'WriteOff', name: 'Списано' }, +]; + +export const ChangeEquipmentStatusEdit = () => ( + + + + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/change-equipment-status/ChangeEquipmentStatusList.tsx b/frontend/src/resources/change-equipment-status/ChangeEquipmentStatusList.tsx new file mode 100644 index 0000000..de45322 --- /dev/null +++ b/frontend/src/resources/change-equipment-status/ChangeEquipmentStatusList.tsx @@ -0,0 +1,15 @@ +import { List, DataTable, TextField, DateField, EditButton } from 'react-admin'; + +export const ChangeEquipmentStatusList = () => ( + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/change-equipment-status/ChangeEquipmentStatusShow.tsx b/frontend/src/resources/change-equipment-status/ChangeEquipmentStatusShow.tsx new file mode 100644 index 0000000..0e6ff6a --- /dev/null +++ b/frontend/src/resources/change-equipment-status/ChangeEquipmentStatusShow.tsx @@ -0,0 +1,20 @@ +import { Show, SimpleShowLayout, TextField, DateField, ReferenceField } from 'react-admin'; + +export const ChangeEquipmentStatusShow = () => ( + + + + + + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/change-equipment-status/index.ts b/frontend/src/resources/change-equipment-status/index.ts new file mode 100644 index 0000000..1960ad0 --- /dev/null +++ b/frontend/src/resources/change-equipment-status/index.ts @@ -0,0 +1,4 @@ +export { ChangeEquipmentStatusList } from './ChangeEquipmentStatusList'; +export { ChangeEquipmentStatusCreate } from './ChangeEquipmentStatusCreate'; +export { ChangeEquipmentStatusEdit } from './ChangeEquipmentStatusEdit'; +export { ChangeEquipmentStatusShow } from './ChangeEquipmentStatusShow'; \ No newline at end of file diff --git a/frontend/src/resources/confirmation-document/ConfirmationDocumentCreate.tsx b/frontend/src/resources/confirmation-document/ConfirmationDocumentCreate.tsx new file mode 100644 index 0000000..eac28c5 --- /dev/null +++ b/frontend/src/resources/confirmation-document/ConfirmationDocumentCreate.tsx @@ -0,0 +1,17 @@ +import { Create, SimpleForm, TextInput, DateInput, BooleanInput, ReferenceInput, SelectInput } from 'react-admin'; + +export const ConfirmationDocumentCreate = () => ( + + + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/confirmation-document/ConfirmationDocumentEdit.tsx b/frontend/src/resources/confirmation-document/ConfirmationDocumentEdit.tsx new file mode 100644 index 0000000..ecc41bf --- /dev/null +++ b/frontend/src/resources/confirmation-document/ConfirmationDocumentEdit.tsx @@ -0,0 +1,18 @@ +import { Edit, SimpleForm, TextInput, DateInput, BooleanInput, ReferenceInput, SelectInput } from 'react-admin'; + +export const ConfirmationDocumentEdit = () => ( + + + + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/confirmation-document/ConfirmationDocumentList.tsx b/frontend/src/resources/confirmation-document/ConfirmationDocumentList.tsx new file mode 100644 index 0000000..ccd1398 --- /dev/null +++ b/frontend/src/resources/confirmation-document/ConfirmationDocumentList.tsx @@ -0,0 +1,15 @@ +import { List, DataTable, TextField, DateField, BooleanField, EditButton } from 'react-admin'; + +export const ConfirmationDocumentList = () => ( + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/confirmation-document/ConfirmationDocumentShow.tsx b/frontend/src/resources/confirmation-document/ConfirmationDocumentShow.tsx new file mode 100644 index 0000000..75fd471 --- /dev/null +++ b/frontend/src/resources/confirmation-document/ConfirmationDocumentShow.tsx @@ -0,0 +1,20 @@ +import { Show, SimpleShowLayout, TextField, DateField, BooleanField, ReferenceField } from 'react-admin'; + +export const ConfirmationDocumentShow = () => ( + + + + + + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/confirmation-document/index.ts b/frontend/src/resources/confirmation-document/index.ts new file mode 100644 index 0000000..8e3f843 --- /dev/null +++ b/frontend/src/resources/confirmation-document/index.ts @@ -0,0 +1,4 @@ +export { ConfirmationDocumentList } from './ConfirmationDocumentList'; +export { ConfirmationDocumentCreate } from './ConfirmationDocumentCreate'; +export { ConfirmationDocumentEdit } from './ConfirmationDocumentEdit'; +export { ConfirmationDocumentShow } from './ConfirmationDocumentShow'; \ No newline at end of file diff --git a/frontend/src/resources/consumption-registration/ConsumptionRegistrationCreate.tsx b/frontend/src/resources/consumption-registration/ConsumptionRegistrationCreate.tsx new file mode 100644 index 0000000..7dbbaac --- /dev/null +++ b/frontend/src/resources/consumption-registration/ConsumptionRegistrationCreate.tsx @@ -0,0 +1,15 @@ +import { Create, SimpleForm, TextInput, DateInput, NumberInput, ReferenceInput, SelectInput } from 'react-admin'; + +export const ConsumptionRegistrationCreate = () => ( + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/consumption-registration/ConsumptionRegistrationEdit.tsx b/frontend/src/resources/consumption-registration/ConsumptionRegistrationEdit.tsx new file mode 100644 index 0000000..35b6bbb --- /dev/null +++ b/frontend/src/resources/consumption-registration/ConsumptionRegistrationEdit.tsx @@ -0,0 +1,16 @@ +import { Edit, SimpleForm, TextInput, DateInput, NumberInput, ReferenceInput, SelectInput } from 'react-admin'; + +export const ConsumptionRegistrationEdit = () => ( + + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/consumption-registration/ConsumptionRegistrationList.tsx b/frontend/src/resources/consumption-registration/ConsumptionRegistrationList.tsx new file mode 100644 index 0000000..2e1837a --- /dev/null +++ b/frontend/src/resources/consumption-registration/ConsumptionRegistrationList.tsx @@ -0,0 +1,15 @@ +import { List, DataTable, TextField, DateField, NumberField, EditButton } from 'react-admin'; + +export const ConsumptionRegistrationList = () => ( + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/consumption-registration/ConsumptionRegistrationShow.tsx b/frontend/src/resources/consumption-registration/ConsumptionRegistrationShow.tsx new file mode 100644 index 0000000..2f0f0d3 --- /dev/null +++ b/frontend/src/resources/consumption-registration/ConsumptionRegistrationShow.tsx @@ -0,0 +1,18 @@ +import { Show, SimpleShowLayout, TextField, DateField, NumberField, ReferenceField } from 'react-admin'; + +export const ConsumptionRegistrationShow = () => ( + + + + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/consumption-registration/index.ts b/frontend/src/resources/consumption-registration/index.ts new file mode 100644 index 0000000..f2d3906 --- /dev/null +++ b/frontend/src/resources/consumption-registration/index.ts @@ -0,0 +1,4 @@ +export { ConsumptionRegistrationList } from './ConsumptionRegistrationList'; +export { ConsumptionRegistrationCreate } from './ConsumptionRegistrationCreate'; +export { ConsumptionRegistrationEdit } from './ConsumptionRegistrationEdit'; +export { ConsumptionRegistrationShow } from './ConsumptionRegistrationShow'; \ No newline at end of file diff --git a/frontend/src/resources/employee/EmployeeCreate.tsx b/frontend/src/resources/employee/EmployeeCreate.tsx new file mode 100644 index 0000000..3471883 --- /dev/null +++ b/frontend/src/resources/employee/EmployeeCreate.tsx @@ -0,0 +1,23 @@ +import { Create, SimpleForm, TextInput, NumberInput, SelectInput, ReferenceInput } from 'react-admin'; + +const roleChoices = [ + { id: 'Исполнитель', name: 'Исполнитель' }, + { id: 'Подписант', name: 'Подписант' }, + { id: 'Пользователь', name: 'Пользователь' }, +]; + +export const EmployeeCreate = () => ( + + + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/employee/EmployeeEdit.tsx b/frontend/src/resources/employee/EmployeeEdit.tsx new file mode 100644 index 0000000..ffbf54c --- /dev/null +++ b/frontend/src/resources/employee/EmployeeEdit.tsx @@ -0,0 +1,23 @@ +import { Edit, SimpleForm, TextInput, NumberInput, SelectInput, ReferenceInput } from 'react-admin'; + +const roleChoices = [ + { id: 'Исполнитель', name: 'Исполнитель' }, + { id: 'Подписант', name: 'Подписант' }, + { id: 'Пользователь', name: 'Пользователь' }, +]; + +export const EmployeeEdit = () => ( + + + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/employee/EmployeeList.tsx b/frontend/src/resources/employee/EmployeeList.tsx new file mode 100644 index 0000000..b6bf51a --- /dev/null +++ b/frontend/src/resources/employee/EmployeeList.tsx @@ -0,0 +1,16 @@ +import { List, DataTable, TextField, NumberField, EditButton } from 'react-admin'; + +export const EmployeeList = () => ( + + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/employee/EmployeeShow.tsx b/frontend/src/resources/employee/EmployeeShow.tsx new file mode 100644 index 0000000..e471470 --- /dev/null +++ b/frontend/src/resources/employee/EmployeeShow.tsx @@ -0,0 +1,19 @@ +import { Show, SimpleShowLayout, TextField, NumberField, DateField, ReferenceField } from 'react-admin'; + +export const EmployeeShow = () => ( + + + + + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/employee/index.ts b/frontend/src/resources/employee/index.ts new file mode 100644 index 0000000..e93c622 --- /dev/null +++ b/frontend/src/resources/employee/index.ts @@ -0,0 +1,4 @@ +export { EmployeeList } from './EmployeeList'; +export { EmployeeCreate } from './EmployeeCreate'; +export { EmployeeEdit } from './EmployeeEdit'; +export { EmployeeShow } from './EmployeeShow'; \ No newline at end of file diff --git a/frontend/src/resources/equipment/EquipmentCreate.tsx b/frontend/src/resources/equipment/EquipmentCreate.tsx new file mode 100644 index 0000000..024571b --- /dev/null +++ b/frontend/src/resources/equipment/EquipmentCreate.tsx @@ -0,0 +1,50 @@ +import { Create, SimpleForm, TextInput, DateInput, NumberInput, SelectInput } from 'react-admin'; + +const equipmentTypeChoices = [ + { id: 'Производственное', name: 'Производственное' }, + { id: 'Энергетическое', name: 'Энергетическое' }, + { id: 'Насосное', name: 'Насосное' }, + { id: 'Компрессорное', name: 'Компрессорное' }, +]; + +const equipmentStatusChoices = [ + { id: 'Active', name: 'В эксплуатации' }, + { id: 'Repair', name: 'В ремонте' }, + { id: 'Reserve', name: 'В резерве' }, + { id: 'WriteOff', name: 'Списано' }, +]; + +const periodicityTOChoices = [ + { id: 'Ежедневное', name: 'Ежедневное' }, + { id: 'Еженедельное', name: 'Еженедельное' }, + { id: 'Ежемесячное', name: 'Ежемесячное' }, + { id: 'Полугодовое', name: 'Полугодовое' }, + { id: 'Годовое', name: 'Годовое' }, +]; + +const laborOperationChoices = [ + { id: 'Manual', name: 'Ручные' }, + { id: 'MachineManual', name: 'Машинно-ручные' }, + { id: 'Machine', name: 'Машинные' }, +]; + +export const EquipmentCreate = () => ( + + + + + + + + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/equipment/EquipmentEdit.tsx b/frontend/src/resources/equipment/EquipmentEdit.tsx new file mode 100644 index 0000000..bd8e8dd --- /dev/null +++ b/frontend/src/resources/equipment/EquipmentEdit.tsx @@ -0,0 +1,51 @@ +import { Edit, SimpleForm, TextInput, DateInput, NumberInput, SelectInput } from 'react-admin'; + +const equipmentTypeChoices = [ + { id: 'Производственное', name: 'Производственное' }, + { id: 'Энергетическое', name: 'Энергетическое' }, + { id: 'Насосное', name: 'Насосное' }, + { id: 'Компрессорное', name: 'Компрессорное' }, +]; + +const equipmentStatusChoices = [ + { id: 'Active', name: 'В эксплуатации' }, + { id: 'Repair', name: 'В ремонте' }, + { id: 'Reserve', name: 'В резерве' }, + { id: 'WriteOff', name: 'Списано' }, +]; + +const periodicityTOChoices = [ + { id: 'Ежедневное', name: 'Ежедневное' }, + { id: 'Еженедельное', name: 'Еженедельное' }, + { id: 'Ежемесячное', name: 'Ежемесячное' }, + { id: 'Полугодовое', name: 'Полугодовое' }, + { id: 'Годовое', name: 'Годовое' }, +]; + +const laborOperationChoices = [ + { id: 'Manual', name: 'Ручные' }, + { id: 'MachineManual', name: 'Машинно-ручные' }, + { id: 'Machine', name: 'Машинные' }, +]; + +export const EquipmentEdit = () => ( + + + + + + + + + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/equipment/EquipmentList.tsx b/frontend/src/resources/equipment/EquipmentList.tsx new file mode 100644 index 0000000..c06f84f --- /dev/null +++ b/frontend/src/resources/equipment/EquipmentList.tsx @@ -0,0 +1,21 @@ +import { List, DataTable, TextField, DateField, NumberField, EditButton } from 'react-admin'; + +export const EquipmentList = () => ( + + + + + + + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/equipment/EquipmentShow.tsx b/frontend/src/resources/equipment/EquipmentShow.tsx new file mode 100644 index 0000000..aafde7f --- /dev/null +++ b/frontend/src/resources/equipment/EquipmentShow.tsx @@ -0,0 +1,25 @@ +import { Show, SimpleShowLayout, TextField, DateField, NumberField } from 'react-admin'; + +export const EquipmentShow = () => ( + + + + + + + + + + + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/equipment/index.ts b/frontend/src/resources/equipment/index.ts new file mode 100644 index 0000000..a98271f --- /dev/null +++ b/frontend/src/resources/equipment/index.ts @@ -0,0 +1,4 @@ +export { EquipmentList } from './EquipmentList'; +export { EquipmentCreate } from './EquipmentCreate'; +export { EquipmentEdit } from './EquipmentEdit'; +export { EquipmentShow } from './EquipmentShow'; \ No newline at end of file diff --git a/frontend/src/resources/part/PartCreate.tsx b/frontend/src/resources/part/PartCreate.tsx new file mode 100644 index 0000000..024e759 --- /dev/null +++ b/frontend/src/resources/part/PartCreate.tsx @@ -0,0 +1,20 @@ +import { Create, SimpleForm, TextInput, NumberInput, SelectInput } from 'react-admin'; + +const categoryPartChoices = [ + { id: 'Расходник', name: 'Расходник' }, + { id: 'Запчасть', name: 'Запчасть' }, + { id: 'Инструмент', name: 'Инструмент' }, + { id: 'Спецодежда', name: 'Спецодежда' }, +]; + +export const PartCreate = () => ( + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/part/PartEdit.tsx b/frontend/src/resources/part/PartEdit.tsx new file mode 100644 index 0000000..43e4215 --- /dev/null +++ b/frontend/src/resources/part/PartEdit.tsx @@ -0,0 +1,21 @@ +import { Edit, SimpleForm, TextInput, NumberInput, SelectInput } from 'react-admin'; + +const categoryPartChoices = [ + { id: 'Расходник', name: 'Расходник' }, + { id: 'Запчасть', name: 'Запчасть' }, + { id: 'Инструмент', name: 'Инструмент' }, + { id: 'Спецодежда', name: 'Спецодежда' }, +]; + +export const PartEdit = () => ( + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/part/PartList.tsx b/frontend/src/resources/part/PartList.tsx new file mode 100644 index 0000000..424e668 --- /dev/null +++ b/frontend/src/resources/part/PartList.tsx @@ -0,0 +1,15 @@ +import { List, DataTable, TextField, NumberField, EditButton } from 'react-admin'; + +export const PartList = () => ( + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/part/PartShow.tsx b/frontend/src/resources/part/PartShow.tsx new file mode 100644 index 0000000..f5218bf --- /dev/null +++ b/frontend/src/resources/part/PartShow.tsx @@ -0,0 +1,16 @@ +import { Show, SimpleShowLayout, TextField, NumberField, DateField } from 'react-admin'; + +export const PartShow = () => ( + + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/part/index.ts b/frontend/src/resources/part/index.ts new file mode 100644 index 0000000..45ddc1c --- /dev/null +++ b/frontend/src/resources/part/index.ts @@ -0,0 +1,4 @@ +export { PartList } from './PartList'; +export { PartCreate } from './PartCreate'; +export { PartEdit } from './PartEdit'; +export { PartShow } from './PartShow'; \ No newline at end of file diff --git a/frontend/src/resources/repair-order/RepairOrderCreate.tsx b/frontend/src/resources/repair-order/RepairOrderCreate.tsx new file mode 100644 index 0000000..7ccd128 --- /dev/null +++ b/frontend/src/resources/repair-order/RepairOrderCreate.tsx @@ -0,0 +1,40 @@ +import { Create, SimpleForm, TextInput, DateInput, NumberInput, BooleanInput, SelectInput, ReferenceInput } from 'react-admin'; + +const repairKindChoices = [ + { id: 'TO', name: 'Техническое обслуживание' }, + { id: 'TR', name: 'Текущий ремонт' }, + { id: 'TRE', name: 'Текущий расширенный ремонт' }, + { id: 'KR', name: 'Капитальный ремонт' }, + { id: 'AR', name: 'Аварийный ремонт' }, + { id: 'MP', name: 'Метрологическая поверка' }, +]; + +const repairOrderStatusChoices = [ + { id: 'Draft', name: 'Черновик' }, + { id: 'Approved', name: 'Утверждена' }, + { id: 'InWork', name: 'В работе' }, + { id: 'Done', name: 'Выполнена' }, + { id: 'Cancelled', name: 'Отменена' }, +]; + +export const RepairOrderCreate = () => ( + + + + + + + + + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/repair-order/RepairOrderEdit.tsx b/frontend/src/resources/repair-order/RepairOrderEdit.tsx new file mode 100644 index 0000000..dc36978 --- /dev/null +++ b/frontend/src/resources/repair-order/RepairOrderEdit.tsx @@ -0,0 +1,41 @@ +import { Edit, SimpleForm, TextInput, DateInput, NumberInput, BooleanInput, SelectInput, ReferenceInput } from 'react-admin'; + +const repairKindChoices = [ + { id: 'TO', name: 'Техническое обслуживание' }, + { id: 'TR', name: 'Текущий ремонт' }, + { id: 'TRE', name: 'Текущий расширенный ремонт' }, + { id: 'KR', name: 'Капитальный ремонт' }, + { id: 'AR', name: 'Аварийный ремонт' }, + { id: 'MP', name: 'Метрологическая поверка' }, +]; + +const repairOrderStatusChoices = [ + { id: 'Draft', name: 'Черновик' }, + { id: 'Approved', name: 'Утверждена' }, + { id: 'InWork', name: 'В работе' }, + { id: 'Done', name: 'Выполнена' }, + { id: 'Cancelled', name: 'Отменена' }, +]; + +export const RepairOrderEdit = () => ( + + + + + + + + + + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/repair-order/RepairOrderList.tsx b/frontend/src/resources/repair-order/RepairOrderList.tsx new file mode 100644 index 0000000..367e3c1 --- /dev/null +++ b/frontend/src/resources/repair-order/RepairOrderList.tsx @@ -0,0 +1,21 @@ +import { List, DataTable, TextField, DateField, NumberField, BooleanField, EditButton } from 'react-admin'; + +export const RepairOrderList = () => ( + + + + + + + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/repair-order/RepairOrderShow.tsx b/frontend/src/resources/repair-order/RepairOrderShow.tsx new file mode 100644 index 0000000..1890b16 --- /dev/null +++ b/frontend/src/resources/repair-order/RepairOrderShow.tsx @@ -0,0 +1,26 @@ +import { Show, SimpleShowLayout, TextField, DateField, NumberField, BooleanField, ReferenceField } from 'react-admin'; + +export const RepairOrderShow = () => ( + + + + + + + + + + + + + + + + + + + + + + +); \ No newline at end of file diff --git a/frontend/src/resources/repair-order/index.ts b/frontend/src/resources/repair-order/index.ts new file mode 100644 index 0000000..1d8fbda --- /dev/null +++ b/frontend/src/resources/repair-order/index.ts @@ -0,0 +1,4 @@ +export { RepairOrderList } from './RepairOrderList'; +export { RepairOrderCreate } from './RepairOrderCreate'; +export { RepairOrderEdit } from './RepairOrderEdit'; +export { RepairOrderShow } from './RepairOrderShow'; \ No newline at end of file