From 88e729aa8715ed17e2128ed4648f1171d2e94dec Mon Sep 17 00:00:00 2001 From: F4ilji Date: Wed, 9 Apr 2025 15:58:29 +0500 Subject: [PATCH] added API VICON integration for updating admission plans via admin panel (queued). Updated exams and contests display on programs/show page. Added relevant enums for admission plans. --- app/Enums/BudgetEducation.php | 52 ++++++- app/Enums/FormEducation.php | 10 +- app/Enums/TypeExam.php | 45 ++++++ .../Pages/ListAdmissionCampaigns.php | 18 +-- .../Resources/AdmissionPlanResource.php | 62 ++++---- .../Pages/ListAdmissionPlans.php | 48 +++++- app/Http/Controllers/IconController.php | 10 -- .../UpdateAdmissionPlansDataApiController.php | 23 +++ .../UpdateEduDataApiController.php | 6 - app/Jobs/CreateAdmissionPlan.php | 139 +++++++++++++++++ app/Jobs/CreateEducationalProgram.php | 5 +- .../App/Breadcrumb/BreadcrumbService.php | 3 +- .../DirectionStudy/AdmissionPlanService.php | 145 ++++++++++++++++++ .../EducationalProgramService.php | 2 +- resources/js/Enum/BudgetEducation.js | 97 +++++++++++- resources/js/Enum/EducationForm.js | 4 +- resources/js/Enum/TypeExam.js | 48 ++++++ resources/js/Pages/Client/Programs/Show.vue | 55 +++++-- routes/api.php | 12 +- 19 files changed, 684 insertions(+), 100 deletions(-) create mode 100644 app/Enums/TypeExam.php delete mode 100644 app/Http/Controllers/IconController.php create mode 100644 app/Http/Controllers/UpdateAdmissionPlansDataApiController.php create mode 100644 app/Jobs/CreateAdmissionPlan.php create mode 100644 app/Services/Vicon/DirectionStudy/AdmissionPlanService.php create mode 100644 resources/js/Enum/TypeExam.js diff --git a/app/Enums/BudgetEducation.php b/app/Enums/BudgetEducation.php index 214e442..cb3f450 100644 --- a/app/Enums/BudgetEducation.php +++ b/app/Enums/BudgetEducation.php @@ -7,13 +7,31 @@ use Filament\Support\Contracts\HasColor; enum BudgetEducation: int implements HasLabel, HasColor { - case budget_quantity_position = 1; - case non_budget_quantity_position = 2; + case MAIN_QUOTA = 1; + case TARGET_QUOTA = 2; + case SPECIAL_QUOTA = 3; + case PAID_EDUCATION = 4; + case OTHER_SOURCES = 5; + case SEPARATE_QUOTA = 6; + case COMBINED_QUOTA_ALL = 7; + case COMBINED_QUOTA_TARGET_SPECIAL = 8; + case COMBINED_QUOTA_TARGET_SEPARATE = 9; + case COMBINED_QUOTA_SPECIAL_SEPARATE = 10; + case DETAILED_TARGET_QUOTA = 11; public static function fromName(string $name): ?self { return match ($name) { - 'budget_quantity_position' => self::budget_quantity_position, - 'non_budget_quantity_position' => self::non_budget_quantity_position, + 'MAIN_QUOTA' => self::MAIN_QUOTA, + 'TARGET_QUOTA' => self::TARGET_QUOTA, + 'SPECIAL_QUOTA' => self::SPECIAL_QUOTA, + 'PAID_EDUCATION' => self::PAID_EDUCATION, + 'OTHER_SOURCES' => self::OTHER_SOURCES, + 'SEPARATE_QUOTA' => self::SEPARATE_QUOTA, + 'COMBINED_QUOTA_ALL' => self::COMBINED_QUOTA_ALL, + 'COMBINED_QUOTA_TARGET_SPECIAL' => self::COMBINED_QUOTA_TARGET_SPECIAL, + 'COMBINED_QUOTA_TARGET_SEPARATE' => self::COMBINED_QUOTA_TARGET_SEPARATE, + 'COMBINED_QUOTA_SPECIAL_SEPARATE' => self::COMBINED_QUOTA_SPECIAL_SEPARATE, + 'DETAILED_TARGET_QUOTA' => self::DETAILED_TARGET_QUOTA, default => null, }; } @@ -21,16 +39,34 @@ enum BudgetEducation: int implements HasLabel, HasColor public function getLabel(): ?string { return match ($this) { - self::budget_quantity_position => 'Бюджетные места', - self::non_budget_quantity_position => 'С оплатой обучения', + self::MAIN_QUOTA => 'Основные места', + self::TARGET_QUOTA => 'Целевая квота', + self::SPECIAL_QUOTA => 'Особая квота', + self::PAID_EDUCATION => 'С оплатой обучения', + self::OTHER_SOURCES => 'За счёт иных средств', + self::SEPARATE_QUOTA => 'Отдельная квота', + self::COMBINED_QUOTA_ALL => 'Совмещенная квота (целевая, особая и отдельная квоты)', + self::COMBINED_QUOTA_TARGET_SPECIAL => 'Совмещенная квота (целевая и особая квоты)', + self::COMBINED_QUOTA_TARGET_SEPARATE => 'Совмещенная квота (целевая и отдельная квоты)', + self::COMBINED_QUOTA_SPECIAL_SEPARATE => 'Совмещенная квота (особая и отдельная квоты)', + self::DETAILED_TARGET_QUOTA => 'Детализированная целевая квота', }; } public function getColor(): string|array|null { return match ($this) { - self::budget_quantity_position => 'success', // Цвет для очной формы - self::non_budget_quantity_position => 'warning', // Цвет для заочной формы + self::MAIN_QUOTA => 'primary', + self::TARGET_QUOTA => 'info', + self::SPECIAL_QUOTA => 'danger', + self::PAID_EDUCATION => 'warning', + self::OTHER_SOURCES => 'gray', + self::SEPARATE_QUOTA => 'success', + self::COMBINED_QUOTA_ALL => 'indigo', + self::COMBINED_QUOTA_TARGET_SPECIAL => 'violet', + self::COMBINED_QUOTA_TARGET_SEPARATE => 'fuchsia', + self::COMBINED_QUOTA_SPECIAL_SEPARATE => 'pink', + self::DETAILED_TARGET_QUOTA => 'amber', }; } } \ No newline at end of file diff --git a/app/Enums/FormEducation.php b/app/Enums/FormEducation.php index 3404387..987901a 100644 --- a/app/Enums/FormEducation.php +++ b/app/Enums/FormEducation.php @@ -8,16 +8,18 @@ use Filament\Support\Contracts\HasColor; enum FormEducation: int implements HasLabel, HasColor { case FULL_TIME = 1; // Очная форма обучения - case PART_TIME = 2; // Заочная форма обучения - case FULL_PART_TIME = 3; // Заочная форма обучения + case FULL_PART_TIME = 2; // Заочная форма обучения + + case PART_TIME = 3; // Заочная форма обучения + public static function fromName(string $name): ?self { return match ($name) { 'FULL_TIME' => self::FULL_TIME, - 'PART_TIME' => self::PART_TIME, 'FULL_PART_TIME' => self::FULL_PART_TIME, + 'PART_TIME' => self::PART_TIME, default => null, }; } @@ -26,8 +28,8 @@ enum FormEducation: int implements HasLabel, HasColor { return match ($this) { self::FULL_TIME => 'Очная форма обучения', + self::FULL_PART_TIME => 'Очно-заочная форма обучения', self::PART_TIME => 'Заочная форма обучения', - self::FULL_PART_TIME => 'Очно-заочная форма обучения' }; } diff --git a/app/Enums/TypeExam.php b/app/Enums/TypeExam.php new file mode 100644 index 0000000..741a9a4 --- /dev/null +++ b/app/Enums/TypeExam.php @@ -0,0 +1,45 @@ + 'ЕГЭ', + self::INTERNAL_EXAM => 'ВИ, проводимое организацией самостоятельно', + self::AVG_SCORE => 'Ср. балл документа об образовании', + self::ACCREDITATION => 'Аккредитация', + }; + } + + public function getColor(): string|array|null + { + return match ($this) { + self::EGE => 'primary', + self::INTERNAL_EXAM => 'info', + self::AVG_SCORE => 'success', + self::ACCREDITATION => 'warning', + }; + } + + public static function fromName(string $name): ?self + { + return match ($name) { + 'EGE' => self::EGE, + 'INTERNAL_EXAM' => self::INTERNAL_EXAM, + 'AVG_SCORE' => self::AVG_SCORE, + 'ACCREDITATION' => self::ACCREDITATION, + default => null, + }; + } +} \ No newline at end of file diff --git a/app/Filament/Resources/AdmissionCampaignResource/Pages/ListAdmissionCampaigns.php b/app/Filament/Resources/AdmissionCampaignResource/Pages/ListAdmissionCampaigns.php index 04e6a84..6c1bb7e 100644 --- a/app/Filament/Resources/AdmissionCampaignResource/Pages/ListAdmissionCampaigns.php +++ b/app/Filament/Resources/AdmissionCampaignResource/Pages/ListAdmissionCampaigns.php @@ -22,32 +22,32 @@ class ListAdmissionCampaigns extends ListRecords ->action(function () { // Отправляем запрос в фоновом режиме $this->js(<< response.json()) - .then(data => { + .then(() => { // Показываем уведомление об успешном завершении window.dispatchEvent(new CustomEvent('filament-notify', { detail: { type: 'success', title: 'Данные обновлены', - body: 'Данные успешно обновлены.', - }, + body: 'Данные успешно обновлены.' + } })); }) - .catch(error => { + .catch(() => { // Показываем уведомление об ошибке window.dispatchEvent(new CustomEvent('filament-notify', { detail: { type: 'danger', title: 'Ошибка', - body: 'Произошла ошибка при обновлении данных.', - }, + body: 'Произошла ошибка при обновлении данных.' + } })); }); JS); diff --git a/app/Filament/Resources/AdmissionPlanResource.php b/app/Filament/Resources/AdmissionPlanResource.php index 9740d27..8eeb072 100644 --- a/app/Filament/Resources/AdmissionPlanResource.php +++ b/app/Filament/Resources/AdmissionPlanResource.php @@ -5,6 +5,7 @@ namespace App\Filament\Resources; use App\Enums\BudgetEducation; use App\Enums\EducationalProgramStatus; use App\Enums\FormEducation; +use App\Enums\TypeExam; use App\Filament\Resources\AdmissionPlanResource\Pages; use App\Models\AdmissionCampaign; use App\Models\AdmissionPlan; @@ -82,20 +83,23 @@ class AdmissionPlanResource extends Resource ->maxLength(100) ->placeholder('Например: Математика') ->helperText('Название вступительного испытания'), + TextInput::make('priority') + ->label('Приоритет предмета') + ->required() + ->numeric() + ->columnSpanFull() + ->maxLength(10), - Repeater::make('exam')->schema([ - Select::make('type_exam') + Repeater::make('types')->schema([ + Select::make('type') ->label('Тип испытания') ->required() - ->options([ - 'ege' => 'ЕГЭ', - 'internal_test' => 'Внутреннее испытание', - ]) + ->options(TypeExam::class) ->native(false) ->placeholder('Выберите тип') ->helperText('Тип вступительного испытания'), - TextInput::make('min_score') + TextInput::make('min_ball') ->label('Минимальный балл') ->required() ->numeric() @@ -134,38 +138,33 @@ class AdmissionPlanResource extends Resource ->placeholder('Выберите форму') ->columnSpanFull() ->helperText('Форма обучения для данной группы'), + Section::make()->schema([ + Select::make('places.form_budget') + ->label('Форма финансирования') + ->options(BudgetEducation::class) + ->required() + ->native(false) + ->placeholder('Выберите тип') + ->helperText('Бюджетные или платные места'), - Repeater::make('places') - ->label('Места') - ->schema([ - Select::make('form_budget') - ->label('Форма финансирования') - ->options(BudgetEducation::class) - ->required() - ->native(false) - ->placeholder('Выберите тип') - ->helperText('Бюджетные или платные места'), - - TextInput::make('count') - ->label('Количество мест') - ->required() - ->numeric() - ->minValue(0) - ->placeholder('Укажите количество') - ->helperText('Количество доступных мест'), - ]) - ->columnSpanFull() - ->maxItems(2) - ->addActionLabel('Добавить тип мест') + TextInput::make('places.count') + ->label('Количество мест') + ->required() + ->numeric() + ->minValue(0) + ->placeholder('Укажите количество') + ->helperText('Количество доступных мест'), + ]), ]) ->columns(2) - ->maxItems(3) + ->maxItems(4) // Adjust if needed based on your actual requirements ->collapsible() ->collapsed() ->addActionLabel('Добавить группу') ->helperText('Добавьте группы с условиями поступления'); } + public static function table(Table $table): Table { return $table @@ -187,6 +186,9 @@ class AdmissionPlanResource extends Resource ]); } + + + public static function getRelations(): array { return [ diff --git a/app/Filament/Resources/AdmissionPlanResource/Pages/ListAdmissionPlans.php b/app/Filament/Resources/AdmissionPlanResource/Pages/ListAdmissionPlans.php index 2ba6fdc..6f69dad 100644 --- a/app/Filament/Resources/AdmissionPlanResource/Pages/ListAdmissionPlans.php +++ b/app/Filament/Resources/AdmissionPlanResource/Pages/ListAdmissionPlans.php @@ -4,6 +4,7 @@ namespace App\Filament\Resources\AdmissionPlanResource\Pages; use App\Filament\Resources\AdmissionPlanResource; use Filament\Actions; +use Filament\Notifications\Notification; use Filament\Resources\Pages\ListRecords; class ListAdmissionPlans extends ListRecords @@ -13,7 +14,52 @@ class ListAdmissionPlans extends ListRecords protected function getHeaderActions(): array { return [ - Actions\CreateAction::make(), + Actions\CreateAction::make(), // Стандартная кнопка "Создать" + Actions\Action::make('fetchData') // Кастомная кнопка + ->label('Обновить данные') + ->color('primary') // Цвет кнопки + ->icon('heroicon-o-arrow-path') // Иконка + ->action(function () { + // Отправляем запрос в фоновом режиме + $this->js(<< response.json()) + .then(() => { + // Показываем уведомление об успешном завершении + window.dispatchEvent(new CustomEvent('filament-notify', { + detail: { + type: 'success', + title: 'Данные обновлены', + body: 'Данные успешно обновлены.' + } + })); + }) + .catch(() => { + // Показываем уведомление об ошибке + window.dispatchEvent(new CustomEvent('filament-notify', { + detail: { + type: 'danger', + title: 'Ошибка', + body: 'Произошла ошибка при обновлении данных.' + } + })); + }); + JS); + + // Показываем уведомление + Notification::make() + ->title('Данные обновляются') + ->body('Данные обновляются в фоновом режиме.') + ->success() + ->send(); + }), ]; } + } diff --git a/app/Http/Controllers/IconController.php b/app/Http/Controllers/IconController.php deleted file mode 100644 index 620cd85..0000000 --- a/app/Http/Controllers/IconController.php +++ /dev/null @@ -1,10 +0,0 @@ -clearAndCreateAdmissionPlans(); + return redirect()->route('index'); + } + + private function clearAndCreateAdmissionPlans() : void + { + dispatch(new CreateAdmissionPlan()); + } +} diff --git a/app/Http/Controllers/UpdateEduDataApiController.php b/app/Http/Controllers/UpdateEduDataApiController.php index daebb13..1d996d0 100644 --- a/app/Http/Controllers/UpdateEduDataApiController.php +++ b/app/Http/Controllers/UpdateEduDataApiController.php @@ -8,12 +8,6 @@ use App\Services\Vicon\EducationalProgram\EducationalProgramService; class UpdateEduDataApiController extends Controller { - private $programService; - - public function __construct() - { - $this->programService = new EducationalProgramService(); - } public function index() { diff --git a/app/Jobs/CreateAdmissionPlan.php b/app/Jobs/CreateAdmissionPlan.php new file mode 100644 index 0000000..7efa496 --- /dev/null +++ b/app/Jobs/CreateAdmissionPlan.php @@ -0,0 +1,139 @@ +admissionPlanService = app(AdmissionPlanService::class); + } + + /** + * Execute the job. + */ + public function handle(): void + { + try { + $items = $this->admissionPlanService->getCampaigns(); + + if (empty($items)) { + Log::warning('Empty campaigns list received'); + return; // или обработка пустого случая + } + + $campaign = $this->admissionPlanService->findActiveCampaign($items); + + if (empty($campaign)) { + Log::warning('No active campaign found in the list'); + return; + } + + $levels_codes = $this->admissionPlanService->getLevelEducationCodes($campaign); + + if (empty($levels_codes)) { + Log::warning('No education level codes found for campaign'); + return; + } + + foreach ($levels_codes as $code) { + $admissionPlans = $this->admissionPlanService->getAdmissionPlans($code); + + // Проверка на пустой результат или отсутствие нужного свойства + if (empty($admissionPlans) || !isset($admissionPlans->competitons_groups)) { + Log::warning("Empty admission plans or missing property for code: {$code}", [ + 'admissionPlans' => $admissionPlans + ]); + continue; + } + + $filteredPlans = $this->admissionPlanService->filterEmptyNaprOrProg($admissionPlans->competitons_groups); + + if (empty($filteredPlans)) { + Log::info("No valid plans after filtering for code: {$code}"); + continue; + } + + $items = $this->admissionPlanService->transformData($filteredPlans); + + if (empty($items)) { + Log::info("No items after transformation for code: {$code}"); + continue; + } + + foreach ($items as $item) { + // Проверка структуры $item + if (!isset($item['id'], $item['plan']->competitions, $item['plan']->exams)) { + Log::warning("Invalid item structure", ['item' => $item]); + continue; + } + + $eduPrograms = EducationalProgram::where('inner_code', $item['id'])->get(); + + if ($eduPrograms->isEmpty()) { + Log::info("No educational programs found for inner_code: {$item['id']}"); + continue; + } + + try { + $contestData = $this->admissionPlanService->convertToSaveContestData($item['plan']->competitions); + $examData = $this->admissionPlanService->convertToSaveExamData($item['plan']->exams); + + foreach ($eduPrograms as $eduProgram) { + $eduProgram->admission_plans()->create([ + 'admission_campaigns_id' => $this->getActiveCampaign()->id, + 'exams' => $examData, + 'contests' => $contestData, + ]); + } + } catch (\Exception $e) { + Log::error("Error processing admission plan for item: {$item['id']}", [ + 'error' => $e->getMessage(), + 'item' => $item + ]); + continue; + } + } + } + } catch (\Exception $e) { + Log::error('Error in admission plans processing', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + } + } + + + private function getActiveCampaign() + { + $activeCampaign = AdmissionCampaign::where('status', 1)->first(); + + if (!$activeCampaign) { + throw new \Exception('No active admission campaign found'); + } + + return $activeCampaign; + } +} \ No newline at end of file diff --git a/app/Jobs/CreateEducationalProgram.php b/app/Jobs/CreateEducationalProgram.php index 50a0064..09cd9c1 100644 --- a/app/Jobs/CreateEducationalProgram.php +++ b/app/Jobs/CreateEducationalProgram.php @@ -18,14 +18,15 @@ class CreateEducationalProgram implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - private $educatinalProgramService; /** * Create a new job instance. */ + + private EducationalProgramService $educatinalProgramService; public function __construct() { - $this->educatinalProgramService = new EducationalProgramService(); + $this->educatinalProgramService = app(EducationalProgramService::class); } /** diff --git a/app/Services/App/Breadcrumb/BreadcrumbService.php b/app/Services/App/Breadcrumb/BreadcrumbService.php index ba73d33..12379cc 100644 --- a/app/Services/App/Breadcrumb/BreadcrumbService.php +++ b/app/Services/App/Breadcrumb/BreadcrumbService.php @@ -45,7 +45,8 @@ class BreadcrumbService ]; } - private function generatePath(string $routeName): ?string + + private function generatePath(?string $routeName): string|null { if ($routeName === 'page.view') { return request()->path(); diff --git a/app/Services/Vicon/DirectionStudy/AdmissionPlanService.php b/app/Services/Vicon/DirectionStudy/AdmissionPlanService.php new file mode 100644 index 0000000..3c00132 --- /dev/null +++ b/app/Services/Vicon/DirectionStudy/AdmissionPlanService.php @@ -0,0 +1,145 @@ +campaign_levels_code; + }, $campaign->groups); + } + + public function findActiveCampaign(array $campaigns): object|null + { + return array_reduce($campaigns, function($carry, $item) { + return $carry ?? ($item->status == 1 ? $item : null); + }); + } + + public function getCampaigns(): array + { + try { + $response = $this->callAPI( + "https://db-nica.ru/api/v1/campaigns", + env('VICON_TOKEN') + ); + if (!is_array($response)) { + Log::warning('Unexpected response type in getCampaigns', [ + 'type' => gettype($response), + 'response' => $response + ]); + } + + return $response; + } catch (\Exception $e) { + Log::error('API call failed in getCampaigns', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + return []; // или вернуть пустой объект (object)[] + } + } + + public function getAdmissionPlans(int $campaign_levels_code): object|array + { + try { + $response = $this->callAPI( + "https://db-nica.ru/api/v1/planPriema/$campaign_levels_code", + env('VICON_TOKEN') + ); + + if (!is_object($response)) { + Log::warning('Unexpected response type in getAdmissionPlans', [ + 'expected' => 'object', + 'actual' => gettype($response), + 'campaign_levels_code' => $campaign_levels_code, + 'response' => $response + ]); + + return []; + } + + return $response; + } catch (\Exception $e) { + Log::error('API call failed in getAdmissionPlans', [ + 'error' => $e->getMessage(), + 'campaign_levels_code' => $campaign_levels_code, + 'trace' => $e->getTraceAsString() + ]); + return []; + } + } + + public function filterEmptyNaprOrProg(array $array): array + { + return array_values(array_filter($array, function ($item) { + return !empty($item->napr_or_prog); + })); + } + + public function transformData(array $data) : array + { + return array_map(function ($item) { + $array = []; + $array['id'] = $item->napr_or_prog[0]->inner_code; + $array['plan'] = $item->groups_condition[0]; + return $array; + }, $data); + } + + + public function convertToSaveExamData(array $data) : array + { + return array_map(function ($item) { + $array = []; + $array['title'] = $item->exam_name; + $array['priority'] = $item->priority; + $array['types'] = array_map(function ($i) { + return [ + 'type' => $i->type, + 'min_ball' => $i->min_ball, + ]; + }, $item->types); + return $array; + }, $data); + } + + public function convertToSaveContestData(array $data) : array + { + return array_map(function ($item) { + $array = []; + $array['form_education'] = $item->form_obuch; + $array['places'] = [ + 'form_budget' => $item->source, + 'count' => $item->count_places + ]; + return $array; + + }, $data); + } + + private function callAPI(string $endpoint, string $token = null): object|array + { + try { + $response = Http::withToken($token)->get($endpoint); + $data = $response->object(); + + if (isset($data->message)) { + throw new \Exception($data->message); + } + + return $data; + } catch (\Exception $e) { + Log::error('Ошибка при вызове API: ' . $e->getMessage()); + throw $e; // Перебрасываем исключение + } + } + +} \ No newline at end of file diff --git a/app/Services/Vicon/EducationalProgram/EducationalProgramService.php b/app/Services/Vicon/EducationalProgram/EducationalProgramService.php index 2f4d400..582de3f 100644 --- a/app/Services/Vicon/EducationalProgram/EducationalProgramService.php +++ b/app/Services/Vicon/EducationalProgram/EducationalProgramService.php @@ -20,7 +20,7 @@ class EducationalProgramService $programs = array_merge($programs, $data->rows); } foreach ($programs as $program) { - array_push($programsUuid, $program->uuid); + $programsUuid[] = $program->uuid; } return $programsUuid; } diff --git a/resources/js/Enum/BudgetEducation.js b/resources/js/Enum/BudgetEducation.js index d7b9300..928560f 100644 --- a/resources/js/Enum/BudgetEducation.js +++ b/resources/js/Enum/BudgetEducation.js @@ -1,6 +1,80 @@ class EducationForm { - static BUDGET_QUANTITY_POSITION = { value: 1, label: 'Бюджетные места', color: 'info', name: 'BUDGET_QUANTITY_POSITION' }; - static NON_BUDGET_QUANTITY_POSITION = { value: 2, label: 'С оплатой обучения', color: 'primary', name: 'NON_BUDGET_QUANTITY_POSITION' }; + static MAIN_QUOTA = { + value: 1, + label: 'Основные места', + color: 'primary', + name: 'MAIN_QUOTA' + }; + + static TARGET_QUOTA = { + value: 2, + label: 'Целевая квота', + color: 'info', + name: 'TARGET_QUOTA' + }; + + static SPECIAL_QUOTA = { + value: 3, + label: 'Особая квота', + color: 'danger', + name: 'SPECIAL_QUOTA' + }; + + static PAID_EDUCATION = { + value: 4, + label: 'С оплатой обучения', + color: 'warning', + name: 'PAID_EDUCATION' + }; + + static OTHER_SOURCES = { + value: 5, + label: 'За счёт иных средств', + color: 'gray', + name: 'OTHER_SOURCES' + }; + + static SEPARATE_QUOTA = { + value: 6, + label: 'Отдельная квота', + color: 'success', + name: 'SEPARATE_QUOTA' + }; + + static COMBINED_QUOTA_ALL = { + value: 7, + label: 'Совмещенная квота (целевая, особая и отдельная квоты)', + color: 'indigo', + name: 'COMBINED_QUOTA_ALL' + }; + + static COMBINED_QUOTA_TARGET_SPECIAL = { + value: 8, + label: 'Совмещенная квота (целевая и особая квоты)', + color: 'violet', + name: 'COMBINED_QUOTA_TARGET_SPECIAL' + }; + + static COMBINED_QUOTA_TARGET_SEPARATE = { + value: 9, + label: 'Совмещенная квота (целевая и отдельная квоты)', + color: 'fuchsia', + name: 'COMBINED_QUOTA_TARGET_SEPARATE' + }; + + static COMBINED_QUOTA_SPECIAL_SEPARATE = { + value: 10, + label: 'Совмещенная квота (особая и отдельная квоты)', + color: 'pink', + name: 'COMBINED_QUOTA_SPECIAL_SEPARATE' + }; + + static DETAILED_TARGET_QUOTA = { + value: 11, + label: 'Детализированная целевая квота', + color: 'amber', + name: 'DETAILED_TARGET_QUOTA' + }; // Метод для получения статуса по имени static fromName(name) { @@ -11,10 +85,21 @@ class EducationForm { return Object.values(this).find(item => item.value == value) || null; } - - // Метод для получения имени - getName() { - return this.name; + // Метод для получения всех значений + static getAll() { + return [ + this.MAIN_QUOTA, + this.TARGET_QUOTA, + this.SPECIAL_QUOTA, + this.PAID_EDUCATION, + this.OTHER_SOURCES, + this.SEPARATE_QUOTA, + this.COMBINED_QUOTA_ALL, + this.COMBINED_QUOTA_TARGET_SPECIAL, + this.COMBINED_QUOTA_TARGET_SEPARATE, + this.COMBINED_QUOTA_SPECIAL_SEPARATE, + this.DETAILED_TARGET_QUOTA + ]; } } diff --git a/resources/js/Enum/EducationForm.js b/resources/js/Enum/EducationForm.js index 7e2227d..b55f0e7 100644 --- a/resources/js/Enum/EducationForm.js +++ b/resources/js/Enum/EducationForm.js @@ -1,7 +1,7 @@ class EducationForm { static FULL_TIME = { value: 1, label: 'Очное обучение', color: 'info', name: 'FULL_TIME', type_label: 'Форма обучения' }; - static PART_TIME = { value: 2, label: 'Заочное обучение', color: 'primary', name: 'PART_TIME', type_label: 'Форма обучения' }; - static FULL_PART_TIME = { value: 3, label: 'Очно-заочное обучение', color: 'success', name: 'FULL_PART_TIME', type_label: 'Форма обучения' }; + static FULL_PART_TIME = { value: 2, label: 'Очно-заочное обучение', color: 'success', name: 'FULL_PART_TIME', type_label: 'Форма обучения' }; + static PART_TIME = { value: 3, label: 'Заочное обучение', color: 'primary', name: 'PART_TIME', type_label: 'Форма обучения' }; // Метод для получения статуса по имени static fromName(name) { diff --git a/resources/js/Enum/TypeExam.js b/resources/js/Enum/TypeExam.js new file mode 100644 index 0000000..47db1e5 --- /dev/null +++ b/resources/js/Enum/TypeExam.js @@ -0,0 +1,48 @@ +class TypeExam { + static EGE = { + value: 1, + label: 'ЕГЭ', + color: 'primary', + name: 'EGE' + }; + + static INTERNAL_EXAM = { + value: 2, + label: 'Вступительное испытание', + color: 'info', + name: 'INTERNAL_EXAM' + }; + + static AVG_SCORE = { + value: 3, + label: 'Ср. балл аттестата', + color: 'success', + name: 'AVG_SCORE' + }; + + static ACCREDITATION = { + value: 4, + label: 'Аккредитация', + color: 'warning', + name: 'ACCREDITATION' + }; + + static fromName(name) { + return this[name] || null; + } + + static fromValue(value) { + return Object.values(this).find(item => item.value == value) || null; + } + + static getAll() { + return [ + this.EGE, + this.INTERNAL_EXAM, + this.AVG_SCORE, + this.ACCREDITATION + ]; + } +} + +export default TypeExam; \ No newline at end of file diff --git a/resources/js/Pages/Client/Programs/Show.vue b/resources/js/Pages/Client/Programs/Show.vue index afb6cd3..8d84e0f 100644 --- a/resources/js/Pages/Client/Programs/Show.vue +++ b/resources/js/Pages/Client/Programs/Show.vue @@ -10,6 +10,7 @@ import BasicTitle from "@/componentss/ui/titles/BasicTitle.vue"; import ProgramItemBreadcrumbs from "@/componentss/features/educationalPrograms/components/ProgramItemBreadcrumbs.vue"; import ProgramTitle from "@/componentss/features/educationalPrograms/components/ProgramTitle.vue"; import BudgetEducation from "@/Enum/BudgetEducation.js"; +import TypeExam from "@/Enum/TypeExam.js"; export default { @@ -21,10 +22,28 @@ export default { BudgetForm() { return BudgetEducation }, + TypeExam() { + return TypeExam + }, }, methods: { - typeExam(type) { - return (type === 'ege' ? 'ЕГЭ' : 'ВИ') + groupExamsByPriority(exams) { + return exams.reduce((groups, exam) => { + if (!groups[exam.priority]) { + groups[exam.priority] = []; + } + groups[exam.priority].push(exam); + return groups; + }, {}); + }, + groupContestsByFormEducation(contests) { + return contests.reduce((groups, contest) => { + if (!groups[contest.form_education]) { + groups[contest.form_education] = []; + } + groups[contest.form_education].push(contest); + return groups; + }, {}); } }, components: { @@ -119,10 +138,12 @@ export default {

Количество мест на прием