diff --git a/composer.json b/composer.json index dd412015c..c7a06a5f4 100644 --- a/composer.json +++ b/composer.json @@ -59,6 +59,8 @@ "Webkul\\Attribute\\": "packages/Webkul/Attribute/src", "Webkul\\Contact\\": "packages/Webkul/Contact/src", "Webkul\\Core\\": "packages/Webkul/Core/src", + "Webkul\\DataGrid\\": "packages/Webkul/DataGrid/src", + "Webkul\\DataTransfer\\": "packages/Webkul/DataTransfer/src", "Webkul\\Email\\": "packages/Webkul/Email/src", "Webkul\\EmailTemplate\\": "packages/Webkul/EmailTemplate/src", "Webkul\\Installer\\": "packages/Webkul/Installer/src", @@ -69,8 +71,7 @@ "Webkul\\User\\": "packages/Webkul/User/src", "Webkul\\Warehouse\\": "packages/Webkul/Warehouse/src", "Webkul\\WebForm\\": "packages/Webkul/WebForm/src", - "Webkul\\Automation\\": "packages/Webkul/Automation/src", - "Webkul\\DataGrid\\": "packages/Webkul/DataGrid/src" + "Webkul\\Automation\\": "packages/Webkul/Automation/src" } }, "autoload-dev": { diff --git a/config/app.php b/config/app.php index a518d9891..8e1b03bb3 100644 --- a/config/app.php +++ b/config/app.php @@ -206,6 +206,7 @@ Webkul\Contact\Providers\ContactServiceProvider::class, Webkul\Core\Providers\CoreServiceProvider::class, Webkul\DataGrid\Providers\DataGridServiceProvider::class, + Webkul\DataTransfer\Providers\DataTransferServiceProvider::class, Webkul\EmailTemplate\Providers\EmailTemplateServiceProvider::class, Webkul\Email\Providers\EmailServiceProvider::class, Webkul\Installer\Providers\InstallerServiceProvider::class, diff --git a/config/concord.php b/config/concord.php index 1ef9a6004..5f20fa25f 100644 --- a/config/concord.php +++ b/config/concord.php @@ -18,6 +18,7 @@ \Webkul\User\Providers\ModuleServiceProvider::class, \Webkul\Warehouse\Providers\ModuleServiceProvider::class, \Webkul\WebForm\Providers\ModuleServiceProvider::class, + \Webkul\DataTransfer\Providers\ModuleServiceProvider::class, ], 'register_route_models' => true, diff --git a/database/migrations/2024_09_09_094040_create_job_batches_table.php b/database/migrations/2024_09_09_094040_create_job_batches_table.php new file mode 100644 index 000000000..226e64000 --- /dev/null +++ b/database/migrations/2024_09_09_094040_create_job_batches_table.php @@ -0,0 +1,39 @@ +string('id')->primary(); + $table->string('name'); + $table->integer('total_jobs'); + $table->integer('pending_jobs'); + $table->integer('failed_jobs'); + $table->text('failed_job_ids'); + $table->mediumText('options')->nullable(); + $table->integer('cancelled_at')->nullable(); + $table->integer('created_at'); + $table->integer('finished_at')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('job_batches'); + } +}; diff --git a/database/migrations/2024_09_09_094042_create_jobs_table.php b/database/migrations/2024_09_09_094042_create_jobs_table.php new file mode 100644 index 000000000..a786a8910 --- /dev/null +++ b/database/migrations/2024_09_09_094042_create_jobs_table.php @@ -0,0 +1,36 @@ +bigIncrements('id'); + $table->string('queue')->index(); + $table->longText('payload'); + $table->unsignedTinyInteger('attempts'); + $table->unsignedInteger('reserved_at')->nullable(); + $table->unsignedInteger('available_at'); + $table->unsignedInteger('created_at'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('jobs'); + } +}; diff --git a/packages/Webkul/Admin/src/Config/acl.php b/packages/Webkul/Admin/src/Config/acl.php index c5e246bab..e75195cca 100644 --- a/packages/Webkul/Admin/src/Config/acl.php +++ b/packages/Webkul/Admin/src/Config/acl.php @@ -452,7 +452,39 @@ 'name' => 'admin::app.acl.delete', 'route' => ['admin.settings.tags.delete', 'admin.settings.tags.mass_delete', 'admin.leads.tags.detach'], 'sort' => 2, + ], + [ + 'key' => 'settings.data_transfer', + 'name' => 'admin::app.acl.data-transfer', + 'route' => 'admin.settings.data_transfer.imports.index', + 'sort' => 10, + ], [ + 'key' => 'settings.data_transfer.imports', + 'name' => 'admin::app.acl.imports', + 'route' => 'admin.settings.data_transfer.imports.index', + 'sort' => 1, + ], [ + 'key' => 'settings.data_transfer.imports.create', + 'name' => 'admin::app.acl.create', + 'route' => 'admin.settings.data_transfer.imports.create', + 'sort' => 1, ], [ + 'key' => 'settings.data_transfer.imports.edit', + 'name' => 'admin::app.acl.edit', + 'route' => 'admin.settings.data_transfer.imports.edit', + 'sort' => 2, + ], [ + 'key' => 'settings.data_transfer.imports.delete', + 'name' => 'admin::app.acl.delete', + 'route' => 'admin.settings.data_transfer.imports.delete', + 'sort' => 3, + ], [ + 'key' => 'settings.data_transfer.imports.import', + 'name' => 'admin::app.acl.import', + 'route' => 'admin.settings.data_transfer.imports.imports', + 'sort' => 4, + ], + [ 'key' => 'configuration', 'name' => 'admin::app.acl.configuration', 'route' => 'admin.configuration.index', diff --git a/packages/Webkul/Admin/src/Config/menu.php b/packages/Webkul/Admin/src/Config/menu.php index 1e0432d73..4d6519f3f 100644 --- a/packages/Webkul/Admin/src/Config/menu.php +++ b/packages/Webkul/Admin/src/Config/menu.php @@ -247,6 +247,14 @@ 'route' => 'admin.settings.workflows.index', 'sort' => 3, 'icon-class' => 'icon-settings-flow', + ], + [ + 'key' => 'settings.automation.data_transfer', + 'name' => 'admin::app.layouts.data_transfer', + 'info' => 'admin::app.layouts.data_transfer_info', + 'route' => 'admin.settings.data_transfer.imports.index', + 'sort' => 4, + 'icon-class' => 'icon-download', ], [ 'key' => 'settings.other_settings', 'name' => 'admin::app.layouts.other-settings', @@ -273,4 +281,5 @@ 'sort' => 9, 'icon-class' => 'icon-configuration', ], + ]; diff --git a/packages/Webkul/Admin/src/DataGrids/Settings/DataTransfer/ImportDataGrid.php b/packages/Webkul/Admin/src/DataGrids/Settings/DataTransfer/ImportDataGrid.php new file mode 100644 index 000000000..f2539d350 --- /dev/null +++ b/packages/Webkul/Admin/src/DataGrids/Settings/DataTransfer/ImportDataGrid.php @@ -0,0 +1,161 @@ +select( + 'id', + 'state', + 'file_path', + 'error_file_path', + 'started_at', + 'completed_at', + 'type', + 'summary', + ); + } + + /** + * Prepare Columns. + */ + public function prepareColumns(): void + { + $this->addColumn([ + 'index' => 'id', + 'label' => trans('admin::app.settings.data-transfer.imports.index.datagrid.id'), + 'type' => 'integer', + 'filterable' => true, + 'sortable' => true, + ]); + + $this->addColumn([ + 'index' => 'type', + 'label' => trans('admin::app.settings.data-transfer.imports.index.datagrid.type'), + 'type' => 'string', + 'filterable' => true, + 'sortable' => true, + ]); + + $this->addColumn([ + 'index' => 'state', + 'label' => trans('admin::app.settings.data-transfer.imports.index.datagrid.state'), + 'type' => 'string', + 'filterable' => true, + 'sortable' => true, + ]); + + $this->addColumn([ + 'index' => 'file_path', + 'label' => trans('admin::app.settings.data-transfer.imports.index.datagrid.uploaded-file'), + 'type' => 'string', + 'closure' => function ($row) { + return ''.$row->file_path.''; + }, + ]); + + $this->addColumn([ + 'index' => 'error_file_path', + 'label' => trans('admin::app.settings.data-transfer.imports.index.datagrid.error-file'), + 'type' => 'string', + 'closure' => function ($row) { + if (empty($row->error_file_path)) { + return ''; + } + + return ''.$row->error_file_path.''; + }, + ]); + + $this->addColumn([ + 'index' => 'started_at', + 'label' => trans('admin::app.settings.data-transfer.imports.index.datagrid.started-at'), + 'type' => 'date', + 'filterable' => true, + 'filterable_type' => 'date_range', + 'sortable' => true, + ]); + + $this->addColumn([ + 'index' => 'completed_at', + 'label' => trans('admin::app.settings.data-transfer.imports.index.datagrid.completed-at'), + 'type' => 'date', + 'filterable' => true, + 'filterable_type' => 'date_range', + 'sortable' => true, + ]); + + $this->addColumn([ + 'index' => 'summary', + 'label' => trans('admin::app.settings.data-transfer.imports.index.datagrid.summary'), + 'type' => 'string', + 'closure' => function ($row) { + if (empty($row->summary)) { + return ''; + } + + $summary = json_decode($row->summary, true); + + $stats = []; + + foreach ($summary as $type => $value) { + $stats[] = trans('admin::app.settings.data-transfer.imports.index.datagrid.'.$type).': '.$summary[$type]; + } + + return implode(', ', $stats); + }, + ]); + } + + /** + * Prepare actions. + */ + public function prepareActions(): void + { + if (bouncer()->hasPermission('settings.data_transfer.imports.import')) { + $this->addAction([ + 'index' => 'import', + 'icon' => 'icon-import', + 'title' => trans('admin::app.settings.data-transfer.imports.index.datagrid.import'), + 'method' => 'GET', + 'url' => function ($row) { + return route('admin.settings.data_transfer.imports.import', $row->id); + }, + ]); + } + + if (bouncer()->hasPermission('settings.data_transfer.imports.edit')) { + $this->addAction([ + 'index' => 'edit', + 'icon' => 'icon-edit', + 'title' => trans('admin::app.settings.data-transfer.imports.index.datagrid.edit'), + 'method' => 'GET', + 'url' => function ($row) { + return route('admin.settings.data_transfer.imports.edit', $row->id); + }, + ]); + } + + if (bouncer()->hasPermission('settings.data_transfer.imports.delete')) { + $this->addAction([ + 'index' => 'delete', + 'icon' => 'icon-delete', + 'title' => trans('admin::app.settings.data-transfer.imports.index.datagrid.delete'), + 'method' => 'DELETE', + 'url' => function ($row) { + return route('admin.settings.data_transfer.imports.delete', $row->id); + }, + ]); + } + } +} diff --git a/packages/Webkul/Admin/src/Http/Controllers/Contact/Persons/PersonController.php b/packages/Webkul/Admin/src/Http/Controllers/Contact/Persons/PersonController.php index 507fa2fbc..d796152da 100644 --- a/packages/Webkul/Admin/src/Http/Controllers/Contact/Persons/PersonController.php +++ b/packages/Webkul/Admin/src/Http/Controllers/Contact/Persons/PersonController.php @@ -186,8 +186,12 @@ private function sanitizeRequestedPersonData(array $data): array $data['organization_id'] = null; } + $data['unique_id'] = $data['user_id'].'|'.$data['organization_id'].'|'.$data['emails'][0]['value']; + if (isset($data['contact_numbers'])) { $data['contact_numbers'] = collect($data['contact_numbers'])->filter(fn ($number) => ! is_null($number['value']))->toArray(); + + $data['unique_id'] .= '|'.$data['contact_numbers'][0]['value']; } return $data; diff --git a/packages/Webkul/Admin/src/Http/Controllers/Settings/DataTransfer/ImportController.php b/packages/Webkul/Admin/src/Http/Controllers/Settings/DataTransfer/ImportController.php new file mode 100755 index 000000000..242d54a14 --- /dev/null +++ b/packages/Webkul/Admin/src/Http/Controllers/Settings/DataTransfer/ImportController.php @@ -0,0 +1,491 @@ +ajax()) { + return datagrid(ImportDataGrid::class)->process(); + } + + return view('admin::settings.data-transfer.imports.index'); + } + + /** + * Show the form for creating a new resource. + */ + public function create(): View + { + return view('admin::settings.data-transfer.imports.create'); + } + + /** + * Store a newly created resource in storage. + */ + public function store(): RedirectResponse + { + $importers = array_keys(config('importers')); + + $this->validate(request(), [ + 'type' => 'required|in:'.implode(',', $importers), + 'action' => 'required:in:append,delete', + 'validation_strategy' => 'required:in:stop-on-errors,skip-errors', + 'allowed_errors' => 'required|integer|min:0', + 'field_separator' => 'required', + 'file' => 'required|mimes:csv,xls,xlsx,txt', + ]); + + Event::dispatch('data_transfer.imports.create.before'); + + $data = request()->only([ + 'type', + 'action', + 'process_in_queue', + 'validation_strategy', + 'validation_strategy', + 'allowed_errors', + 'field_separator', + ]); + + if (! isset($data['process_in_queue'])) { + $data['process_in_queue'] = false; + } else { + $data['process_in_queue'] = true; + } + + $import = $this->importRepository->create( + array_merge( + [ + 'file_path' => request()->file('file')->storeAs( + 'imports', + time().'-'.request()->file('file')->getClientOriginalName(), + 'public' + ), + ], + $data + ) + ); + + Event::dispatch('data_transfer.imports.create.after', $import); + + session()->flash('success', trans('admin::app.settings.data-transfer.imports.create-success')); + + return redirect()->route('admin.settings.data_transfer.imports.import', $import->id); + } + + /** + * Show the form for editing a new resource. + */ + public function edit(int $id): View + { + $import = $this->importRepository->findOrFail($id); + + return view('admin::settings.data-transfer.imports.edit', compact('import')); + } + + /** + * Update a resource in storage. + */ + public function update(int $id): RedirectResponse + { + $importers = array_keys(config('importers')); + + $import = $this->importRepository->findOrFail($id); + + $this->validate(request(), [ + 'type' => 'required|in:'.implode(',', $importers), + 'action' => 'required:in:append,delete', + 'validation_strategy' => 'required:in:stop-on-errors,skip-errors', + 'allowed_errors' => 'required|integer|min:0', + 'field_separator' => 'required', + 'file' => 'mimes:csv,xls,xlsx,txt', + ]); + + Event::dispatch('data_transfer.imports.update.before'); + + $data = array_merge( + request()->only([ + 'type', + 'action', + 'process_in_queue', + 'validation_strategy', + 'validation_strategy', + 'allowed_errors', + 'field_separator', + ]), + [ + 'state' => 'pending', + 'processed_rows_count' => 0, + 'invalid_rows_count' => 0, + 'errors_count' => 0, + 'errors' => null, + 'error_file_path' => null, + 'started_at' => null, + 'completed_at' => null, + 'summary' => null, + ] + ); + + Storage::disk('public')->delete($import->error_file_path ?? ''); + + if (request()->file('file') && request()->file('file')->isValid()) { + Storage::disk('public')->delete($import->file_path); + + $data['file_path'] = request()->file('file')->storeAs( + 'imports', + time().'-'.request()->file('file')->getClientOriginalName(), + 'public' + ); + } + + if (! isset($data['process_in_queue'])) { + $data['process_in_queue'] = false; + } + + $import = $this->importRepository->update($data, $import->id); + + Event::dispatch('data_transfer.imports.update.after', $import); + + session()->flash('success', trans('admin::app.settings.data-transfer.imports.update-success')); + + return redirect()->route('admin.settings.data_transfer.imports.import', $import->id); + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(int $id): JsonResponse + { + $import = $this->importRepository->findOrFail($id); + + try { + Storage::disk('public')->delete($import->file_path); + + Storage::disk('public')->delete($import->error_file_path ?? ''); + + $this->importRepository->delete($id); + + return response()->json([ + 'message' => trans('admin::app.settings.data-transfer.imports.delete-success'), + ]); + } catch (\Exception $e) { + } + + return response()->json([ + 'message' => trans('admin::app.settings.data-transfer.imports.delete-failed'), + ], 500); + } + + /** + * Show the form for creating a new resource. + */ + public function import(int $id): View + { + $import = $this->importRepository->findOrFail($id); + + $isValid = $this->importHelper + ->setImport($import) + ->isValid(); + + if ($import->state == Import::STATE_LINKING) { + if ($this->importHelper->isIndexingRequired()) { + $state = Import::STATE_INDEXING; + } else { + $state = Import::STATE_COMPLETED; + } + } elseif ($import->state == Import::STATE_INDEXING) { + $state = Import::STATE_COMPLETED; + } else { + $state = Import::STATE_COMPLETED; + } + + $stats = $this->importHelper->stats($state); + + $import->unsetRelations(); + + return view('admin::settings.data-transfer.imports.import', compact('import', 'isValid', 'stats')); + } + + /** + * Store a newly created resource in storage. + */ + public function validateImport(int $id): JsonResponse + { + $import = $this->importRepository->findOrFail($id); + + $isValid = $this->importHelper + ->setImport($import) + ->validate(); + + return new JsonResponse([ + 'is_valid' => $isValid, + 'import' => $this->importHelper->getImport()->unsetRelations(), + ]); + } + + /** + * Store a newly created resource in storage. + */ + public function start(int $id): JsonResponse + { + $import = $this->importRepository->findOrFail($id); + + if (! $import->processed_rows_count) { + return new JsonResponse([ + 'message' => trans('admin::app.settings.data-transfer.imports.nothing-to-import'), + ], 400); + } + + $this->importHelper->setImport($import); + + if (! $this->importHelper->isValid()) { + return new JsonResponse([ + 'message' => trans('admin::app.settings.data-transfer.imports.not-valid'), + ], 400); + } + + if ( + $import->process_in_queue + && config('queue.default') == 'sync' + ) { + return new JsonResponse([ + 'message' => trans('admin::app.settings.data-transfer.imports.setup-queue-error'), + ], 400); + } + + /** + * Set the import state to processing + */ + if ($import->state == Import::STATE_VALIDATED) { + $this->importHelper->started(); + } + + /** + * Get the first pending batch to import + */ + $importBatch = $import->batches->where('state', Import::STATE_PENDING)->first(); + + if ($importBatch) { + /** + * Start the import process + */ + try { + if ($import->process_in_queue) { + $this->importHelper->start(); + } else { + $this->importHelper->start($importBatch); + } + } catch (\Exception $e) { + return new JsonResponse([ + 'message' => $e->getMessage(), + ], 400); + } + } else { + if ($this->importHelper->isLinkingRequired()) { + $this->importHelper->linking(); + } elseif ($this->importHelper->isIndexingRequired()) { + $this->importHelper->indexing(); + } else { + $this->importHelper->completed(); + } + } + + return new JsonResponse([ + 'stats' => $this->importHelper->stats(Import::STATE_PROCESSED), + 'import' => $this->importHelper->getImport()->unsetRelations(), + ]); + } + + /** + * Store a newly created resource in storage. + */ + public function link(int $id): JsonResponse + { + $import = $this->importRepository->findOrFail($id); + + if (! $import->processed_rows_count) { + return new JsonResponse([ + 'message' => trans('admin::app.settings.data-transfer.imports.nothing-to-import'), + ], 400); + } + + $this->importHelper->setImport($import); + + if (! $this->importHelper->isValid()) { + return new JsonResponse([ + 'message' => trans('admin::app.settings.data-transfer.imports.not-valid'), + ], 400); + } + + /** + * Set the import state to linking + */ + if ($import->state == Import::STATE_PROCESSED) { + $this->importHelper->linking(); + } + + /** + * Get the first processing batch to link + */ + $importBatch = $import->batches->where('state', Import::STATE_PROCESSED)->first(); + + /** + * Set the import state to linking/completed + */ + if ($importBatch) { + /** + * Start the resource linking process + */ + try { + $this->importHelper->link($importBatch); + } catch (\Exception $e) { + return new JsonResponse([ + 'message' => $e->getMessage(), + ], 400); + } + } else { + if ($this->importHelper->isIndexingRequired()) { + $this->importHelper->indexing(); + } else { + $this->importHelper->completed(); + } + } + + return new JsonResponse([ + 'stats' => $this->importHelper->stats(Import::STATE_LINKED), + 'import' => $this->importHelper->getImport()->unsetRelations(), + ]); + } + + /** + * Store a newly created resource in storage. + */ + public function indexData(int $id): JsonResponse + { + $import = $this->importRepository->findOrFail($id); + + if (! $import->processed_rows_count) { + return new JsonResponse([ + 'message' => trans('admin::app.settings.data-transfer.imports.nothing-to-import'), + ], 400); + } + + $this->importHelper->setImport($import); + + if (! $this->importHelper->isValid()) { + return new JsonResponse([ + 'message' => trans('admin::app.settings.data-transfer.imports.not-valid'), + ], 400); + } + + /** + * Set the import state to linking + */ + if ($import->state == Import::STATE_LINKED) { + $this->importHelper->indexing(); + } + + /** + * Get the first processing batch to link + */ + $importBatch = $import->batches->where('state', Import::STATE_LINKED)->first(); + + /** + * Set the import state to linking/completed + */ + if ($importBatch) { + /** + * Start the resource linking process + */ + try { + $this->importHelper->index($importBatch); + } catch (\Exception $e) { + return new JsonResponse([ + 'message' => $e->getMessage(), + ], 400); + } + } else { + /** + * Set the import state to completed + */ + $this->importHelper->completed(); + } + + return new JsonResponse([ + 'stats' => $this->importHelper->stats(Import::STATE_INDEXED), + 'import' => $this->importHelper->getImport()->unsetRelations(), + ]); + } + + /** + * Returns import stats + */ + public function stats(int $id, string $state = Import::STATE_PROCESSED): JsonResponse + { + $import = $this->importRepository->findOrFail($id); + + $stats = $this->importHelper + ->setImport($import) + ->stats($state); + + return new JsonResponse([ + 'stats' => $stats, + 'import' => $this->importHelper->getImport()->unsetRelations(), + ]); + } + + /** + * Download import error report + */ + public function downloadSample(string $type) + { + $importer = config('importers.'.$type); + + return Storage::download($importer['sample_path']); + } + + /** + * Download import error report + */ + public function download(int $id) + { + $import = $this->importRepository->findOrFail($id); + + return Storage::disk('public')->download($import->file_path); + } + + /** + * Download import error report + */ + public function downloadErrorReport(int $id) + { + $import = $this->importRepository->findOrFail($id); + + return Storage::disk('public')->download($import->file_path); + } +} diff --git a/packages/Webkul/Admin/src/Resources/lang/ar/app.php b/packages/Webkul/Admin/src/Resources/lang/ar/app.php index 3c5fab695..53fb6209e 100644 --- a/packages/Webkul/Admin/src/Resources/lang/ar/app.php +++ b/packages/Webkul/Admin/src/Resources/lang/ar/app.php @@ -39,6 +39,9 @@ 'delete' => 'حذف', 'export' => 'تصدير', 'mass-delete' => 'حذف جماعي', + 'data-transfer' => 'نقل البيانات', + 'imports' => 'الواردات', + 'import' => 'استيراد', ], 'users' => [ @@ -1487,6 +1490,109 @@ 'actions' => 'الإجراءات', ], ], + + 'data-transfer' => [ + 'imports' => [ + 'create' => [ + 'action' => 'إجراء', + 'allowed-errors' => 'الأخطاء المسموح بها', + 'back-btn' => 'عودة', + 'create-update' => 'إنشاء/تحديث', + 'delete' => 'حذف', + 'download-sample' => 'تنزيل العينة', + 'field-separator' => 'فاصل الحقول', + 'file' => 'ملف', + 'general' => 'عام', + 'images-directory' => 'مسار دليل الصور', + 'process-in-queue' => 'معالجة في قائمة الانتظار', + 'results' => 'النتائج', + 'save-btn' => 'حفظ الاستيراد', + 'settings' => 'الإعدادات', + 'skip-errors' => 'تخطي الأخطاء', + 'stop-on-errors' => 'التوقف عند الأخطاء', + 'title' => 'إنشاء استيراد', + 'type' => 'النوع', + 'validation-strategy' => 'استراتيجية التحقق', + ], + + 'edit' => [ + 'action' => 'إجراء', + 'allowed-errors' => 'الأخطاء المسموح بها', + 'back-btn' => 'عودة', + 'create-update' => 'إنشاء/تحديث', + 'delete' => 'حذف', + 'download-sample' => 'تنزيل العينة', + 'field-separator' => 'فاصل الحقول', + 'file' => 'ملف', + 'general' => 'عام', + 'images-directory' => 'مسار دليل الصور', + 'process-in-queue' => 'معالجة في قائمة الانتظار', + 'results' => 'النتائج', + 'save-btn' => 'حفظ الاستيراد', + 'settings' => 'الإعدادات', + 'skip-errors' => 'تخطي الأخطاء', + 'stop-on-errors' => 'التوقف عند الأخطاء', + 'title' => 'تحرير الاستيراد', + 'type' => 'النوع', + 'validation-strategy' => 'استراتيجية التحقق', + ], + + 'index' => [ + 'button-title' => 'إنشاء استيراد', + 'title' => 'الاستيرادات', + + 'datagrid' => [ + 'actions' => 'الإجراءات', + 'completed-at' => 'اكتمل في', + 'created' => 'تم الإنشاء', + 'delete' => 'حذف', + 'deleted' => 'تم الحذف', + 'edit' => 'تحرير', + 'error-file' => 'ملف الأخطاء', + 'id' => 'الرقم التعريفي', + 'started-at' => 'بدأ في', + 'state' => 'الحالة', + 'summary' => 'الملخص', + 'type' => 'النوع', + 'updated' => 'تم التحديث', + 'uploaded-file' => 'الملف المرفوع', + ], + ], + + 'import' => [ + 'back-btn' => 'عودة', + 'completed-batches' => 'إجمالي الدفعات المكتملة:', + 'download-error-report' => 'تنزيل التقرير الكامل', + 'edit-btn' => 'تحرير', + 'imported-info' => 'تهانينا! تم استيرادك بنجاح.', + 'importing-info' => 'الاستيراد قيد المعالجة', + 'indexing-info' => 'تجميع الموارد (الأسعار، المخزون و Elastic Search) جارٍ', + 'linking-info' => 'ربط الموارد جارٍ', + 'progress' => 'التقدم:', + 'title' => 'استيراد', + 'total-batches' => 'إجمالي الدفعات:', + 'total-created' => 'إجمالي السجلات التي تم إنشاؤها:', + 'total-deleted' => 'إجمالي السجلات المحذوفة:', + 'total-errors' => 'إجمالي الأخطاء:', + 'total-invalid-rows' => 'إجمالي الصفوف غير الصالحة:', + 'total-rows-processed' => 'إجمالي الصفوف المعالجة:', + 'total-updated' => 'إجمالي السجلات التي تم تحديثها:', + 'validate' => 'التحقق', + 'validate-info' => 'انقر على التحقق من البيانات لفحص الاستيراد.', + 'validating-info' => 'بدأت قراءة البيانات والتحقق منها', + 'validation-failed-info' => 'استيرادك غير صالح. يرجى إصلاح الأخطاء التالية والمحاولة مرة أخرى.', + 'validation-success-info' => 'استيرادك صالح. انقر على استيراد لبدء عملية الاستيراد.', + ], + + 'create-success' => 'تم إنشاء الاستيراد بنجاح.', + 'delete-failed' => 'فشل حذف الاستيراد بشكل غير متوقع.', + 'delete-success' => 'تم حذف الاستيراد بنجاح.', + 'not-valid' => 'الاستيراد غير صالح', + 'nothing-to-import' => 'لا توجد موارد لاستيرادها.', + 'setup-queue-error' => 'يرجى تغيير برنامج تشغيل قائمة الانتظار إلى "قاعدة البيانات" أو "ريديس" لبدء عملية الاستيراد.', + 'update-success' => 'تم تحديث الاستيراد بنجاح.', + ], + ], ], 'activities' => [ @@ -1978,6 +2084,8 @@ 'warehouses' => 'المستودعات', 'warehouse' => 'مستودع', 'warehouses-info' => 'إضافة أو تعديل أو حذف المستودعات من نظام CRM', + 'data_transfer' => 'نقل البيانات', + 'data_transfer_info' => 'إدارة إعدادات نقل البيانات المتعلقة بالأشخاص والمنتجات والعملاء المحتملين في إدارة علاقات العملاء (CRM)', ], 'user' => [ @@ -2021,6 +2129,12 @@ ], ], + 'validations' => [ + 'message' => [ + 'decimal' => ':attribute يجب أن يكون رقمًا عشريًا.', + ], + ], + 'errors' => [ 'dashboard' => 'لوحة التحكم', 'go-back' => 'العودة', diff --git a/packages/Webkul/Admin/src/Resources/lang/en/app.php b/packages/Webkul/Admin/src/Resources/lang/en/app.php index 29b89b357..1aad6eca8 100644 --- a/packages/Webkul/Admin/src/Resources/lang/en/app.php +++ b/packages/Webkul/Admin/src/Resources/lang/en/app.php @@ -39,6 +39,9 @@ 'delete' => 'Delete', 'export' => 'Export', 'mass-delete' => 'Mass Delete', + 'data-transfer' => 'Data Transfer', + 'imports' => 'Imports', + 'import' => 'Import', ], 'users' => [ @@ -1487,6 +1490,109 @@ 'actions' => 'Actions', ], ], + + 'data-transfer' => [ + 'imports' => [ + 'create' => [ + 'action' => 'Action', + 'allowed-errors' => 'Allowed Errors', + 'back-btn' => 'Back', + 'create-update' => 'Create/Update', + 'delete' => 'Delete', + 'download-sample' => 'Download Sample', + 'field-separator' => 'Field Separator', + 'file' => 'File', + 'general' => 'General', + 'images-directory' => 'Images Directory Path', + 'process-in-queue' => 'Process In Queue', + 'results' => 'Results', + 'save-btn' => 'Save Import', + 'settings' => 'Settings', + 'skip-errors' => 'Skip Errors', + 'stop-on-errors' => 'Stop on Errors', + 'title' => 'Create Import', + 'type' => 'Type', + 'validation-strategy' => 'Validation Strategy', + ], + + 'edit' => [ + 'action' => 'Action', + 'allowed-errors' => 'Allowed Errors', + 'back-btn' => 'Back', + 'create-update' => 'Create/Update', + 'delete' => 'Delete', + 'download-sample' => 'Download Sample', + 'field-separator' => 'Field Separator', + 'file' => 'File', + 'general' => 'General', + 'images-directory' => 'Images Directory Path', + 'process-in-queue' => 'Process In Queue', + 'results' => 'Results', + 'save-btn' => 'Save Import', + 'settings' => 'Settings', + 'skip-errors' => 'Skip Errors', + 'stop-on-errors' => 'Stop on Errors', + 'title' => 'Edit Import', + 'type' => 'Type', + 'validation-strategy' => 'Validation Strategy', + ], + + 'index' => [ + 'button-title' => 'Create Import', + 'title' => 'Imports', + + 'datagrid' => [ + 'actions' => 'Actions', + 'completed-at' => 'Completed At', + 'created' => 'Created', + 'delete' => 'Delete', + 'deleted' => 'Deleted', + 'edit' => 'Edit', + 'error-file' => 'Error File', + 'id' => 'ID', + 'started-at' => 'Started At', + 'state' => 'State', + 'summary' => 'Summary', + 'type' => 'Type', + 'updated' => 'Updated', + 'uploaded-file' => 'Uploaded File', + ], + ], + + 'import' => [ + 'back-btn' => 'Back', + 'completed-batches' => 'Total Batches Completed:', + 'download-error-report' => 'Download Full Report', + 'edit-btn' => 'Edit', + 'imported-info' => 'Congratulations! Your import was successful.', + 'importing-info' => 'Import In Process', + 'indexing-info' => 'Resources Indexing (Price, Inventory and Elastic Search) In Progress', + 'linking-info' => 'Resources Linking In Progress', + 'progress' => 'Progress:', + 'title' => 'Import', + 'total-batches' => 'Total Batches:', + 'total-created' => 'Total Records Created:', + 'total-deleted' => 'Total Records Deleted:', + 'total-errors' => 'Total Errors:', + 'total-invalid-rows' => 'Total Invalid Rows:', + 'total-rows-processed' => 'Total Rows Processed:', + 'total-updated' => 'Total Records Updated:', + 'validate' => 'Validate', + 'validate-info' => 'Click on Validate Data to check your import.', + 'validating-info' => 'The data started reading and Validating', + 'validation-failed-info' => 'Your import is invalid. Please fix the following errors and try again.', + 'validation-success-info' => 'Your import is valid. Click on Import to start the import process.', + ], + + 'create-success' => 'Import created successfully.', + 'delete-failed' => 'Import deletion failed unexpectedly.', + 'delete-success' => 'Import deleted successfully.', + 'not-valid' => 'Import is invalid', + 'nothing-to-import' => 'There are no resources to import.', + 'setup-queue-error' => 'Please change your queue driver to "database" or "redis" to start the import process.', + 'update-success' => 'Import updated successfully.', + ], + ], ], 'activities' => [ @@ -1978,6 +2084,8 @@ 'warehouses' => 'Warehouses', 'warehouse' => 'Warehouse', 'warehouses-info' => 'Add, edit or delete warehouses from CRM', + 'data_transfer' => 'Data Transfer', + 'data_transfer_info' => 'Manage persons, products and leads data transfer related settings in the CRM', ], 'user' => [ @@ -2021,6 +2129,12 @@ ], ], + 'validations' => [ + 'message' => [ + 'decimal' => 'The :attribute must be a decimal.', + ], + ], + 'errors' => [ 'dashboard' => 'Dashboard', 'go-back' => 'Go Back', diff --git a/packages/Webkul/Admin/src/Resources/lang/es/app.php b/packages/Webkul/Admin/src/Resources/lang/es/app.php index 04441ac70..452885ffd 100644 --- a/packages/Webkul/Admin/src/Resources/lang/es/app.php +++ b/packages/Webkul/Admin/src/Resources/lang/es/app.php @@ -39,6 +39,9 @@ 'delete' => 'Eliminar', 'export' => 'Exportar', 'mass-delete' => 'Eliminar en masa', + 'data-transfer' => 'Transferencia de Datos', + 'imports' => 'Importaciones', + 'import' => 'Importar', ], 'users' => [ @@ -1487,6 +1490,109 @@ 'actions' => 'Acciones', ], ], + + 'data-transfer' => [ + 'imports' => [ + 'create' => [ + 'action' => 'Acción', + 'allowed-errors' => 'Errores Permitidos', + 'back-btn' => 'Atrás', + 'create-update' => 'Crear/Actualizar', + 'delete' => 'Eliminar', + 'download-sample' => 'Descargar Muestra', + 'field-separator' => 'Separador de Campos', + 'file' => 'Archivo', + 'general' => 'General', + 'images-directory' => 'Ruta del Directorio de Imágenes', + 'process-in-queue' => 'Procesar en Cola', + 'results' => 'Resultados', + 'save-btn' => 'Guardar Importación', + 'settings' => 'Configuraciones', + 'skip-errors' => 'Omitir Errores', + 'stop-on-errors' => 'Detener en Errores', + 'title' => 'Crear Importación', + 'type' => 'Tipo', + 'validation-strategy' => 'Estrategia de Validación', + ], + + 'edit' => [ + 'action' => 'Acción', + 'allowed-errors' => 'Errores Permitidos', + 'back-btn' => 'Atrás', + 'create-update' => 'Crear/Actualizar', + 'delete' => 'Eliminar', + 'download-sample' => 'Descargar Muestra', + 'field-separator' => 'Separador de Campos', + 'file' => 'Archivo', + 'general' => 'General', + 'images-directory' => 'Ruta del Directorio de Imágenes', + 'process-in-queue' => 'Procesar en Cola', + 'results' => 'Resultados', + 'save-btn' => 'Guardar Importación', + 'settings' => 'Configuraciones', + 'skip-errors' => 'Omitir Errores', + 'stop-on-errors' => 'Detener en Errores', + 'title' => 'Editar Importación', + 'type' => 'Tipo', + 'validation-strategy' => 'Estrategia de Validación', + ], + + 'index' => [ + 'button-title' => 'Crear Importación', + 'title' => 'Importaciones', + + 'datagrid' => [ + 'actions' => 'Acciones', + 'completed-at' => 'Completado en', + 'created' => 'Creado', + 'delete' => 'Eliminar', + 'deleted' => 'Eliminado', + 'edit' => 'Editar', + 'error-file' => 'Archivo de Errores', + 'id' => 'ID', + 'started-at' => 'Iniciado en', + 'state' => 'Estado', + 'summary' => 'Resumen', + 'type' => 'Tipo', + 'updated' => 'Actualizado', + 'uploaded-file' => 'Archivo Subido', + ], + ], + + 'import' => [ + 'back-btn' => 'Atrás', + 'completed-batches' => 'Total de Lotes Completados:', + 'download-error-report' => 'Descargar Informe Completo', + 'edit-btn' => 'Editar', + 'imported-info' => '¡Felicidades! Tu importación fue exitosa.', + 'importing-info' => 'Importación en Proceso', + 'indexing-info' => 'Indexación de Recursos (Precios, Inventario y Elastic Search) en Progreso', + 'linking-info' => 'Vinculación de Recursos en Progreso', + 'progress' => 'Progreso:', + 'title' => 'Importación', + 'total-batches' => 'Total de Lotes:', + 'total-created' => 'Total de Registros Creados:', + 'total-deleted' => 'Total de Registros Eliminados:', + 'total-errors' => 'Total de Errores:', + 'total-invalid-rows' => 'Total de Filas Inválidas:', + 'total-rows-processed' => 'Total de Filas Procesadas:', + 'total-updated' => 'Total de Registros Actualizados:', + 'validate' => 'Validar', + 'validate-info' => 'Haz clic en Validar Datos para comprobar tu importación.', + 'validating-info' => 'La lectura y validación de los datos ha comenzado', + 'validation-failed-info' => 'Tu importación no es válida. Por favor, corrige los siguientes errores e intenta de nuevo.', + 'validation-success-info' => 'Tu importación es válida. Haz clic en Importar para iniciar el proceso de importación.', + ], + + 'create-success' => 'Importación creada exitosamente.', + 'delete-failed' => 'La eliminación de la importación falló inesperadamente.', + 'delete-success' => 'Importación eliminada exitosamente.', + 'not-valid' => 'La importación no es válida', + 'nothing-to-import' => 'No hay recursos para importar.', + 'setup-queue-error' => 'Por favor, cambia tu controlador de cola a "database" o "redis" para iniciar el proceso de importación.', + 'update-success' => 'Importación actualizada exitosamente.', + ], + ], ], 'activities' => [ @@ -1978,6 +2084,8 @@ 'warehouses' => 'Almacenes', 'warehouse' => 'Almacén', 'warehouses-info' => 'Agregar, editar o eliminar almacenes del CRM', + 'data_transfer' => 'Transferencia de Datos', + 'data_transfer_info' => 'Gestionar la configuración relacionada con la transferencia de datos de personas, productos y clientes potenciales en el CRM', ], 'user' => [ @@ -2021,6 +2129,12 @@ ], ], + 'validations' => [ + 'message' => [ + 'decimal' => 'El :attribute debe ser un número decimal.', + ], + ], + 'errors' => [ 'dashboard' => 'Tablero', 'go-back' => 'Volver', diff --git a/packages/Webkul/Admin/src/Resources/lang/fa/app.php b/packages/Webkul/Admin/src/Resources/lang/fa/app.php index 9ad982ab5..eb705d389 100644 --- a/packages/Webkul/Admin/src/Resources/lang/fa/app.php +++ b/packages/Webkul/Admin/src/Resources/lang/fa/app.php @@ -39,6 +39,9 @@ 'delete' => 'حذف', 'export' => 'صادر کردن', 'mass-delete' => 'حذف انبوه', + 'data-transfer' => 'انتقال داده', + 'imports' => 'واردات', + 'import' => 'وارد کردن', ], 'users' => [ @@ -1487,6 +1490,109 @@ 'actions' => 'عملیات', ], ], + + 'data-transfer' => [ + 'imports' => [ + 'create' => [ + 'action' => 'عملیات', + 'allowed-errors' => 'خطاهای مجاز', + 'back-btn' => 'بازگشت', + 'create-update' => 'ایجاد/به‌روزرسانی', + 'delete' => 'حذف', + 'download-sample' => 'دانلود نمونه', + 'field-separator' => 'جداکننده فیلد', + 'file' => 'فایل', + 'general' => 'عمومی', + 'images-directory' => 'مسیر پوشه تصاویر', + 'process-in-queue' => 'پردازش در صف', + 'results' => 'نتایج', + 'save-btn' => 'ذخیره واردات', + 'settings' => 'تنظیمات', + 'skip-errors' => 'رد کردن خطاها', + 'stop-on-errors' => 'توقف در صورت خطا', + 'title' => 'ایجاد واردات', + 'type' => 'نوع', + 'validation-strategy' => 'استراتژی اعتبارسنجی', + ], + + 'edit' => [ + 'action' => 'عملیات', + 'allowed-errors' => 'خطاهای مجاز', + 'back-btn' => 'بازگشت', + 'create-update' => 'ایجاد/به‌روزرسانی', + 'delete' => 'حذف', + 'download-sample' => 'دانلود نمونه', + 'field-separator' => 'جداکننده فیلد', + 'file' => 'فایل', + 'general' => 'عمومی', + 'images-directory' => 'مسیر پوشه تصاویر', + 'process-in-queue' => 'پردازش در صف', + 'results' => 'نتایج', + 'save-btn' => 'ذخیره واردات', + 'settings' => 'تنظیمات', + 'skip-errors' => 'رد کردن خطاها', + 'stop-on-errors' => 'توقف در صورت خطا', + 'title' => 'ویرایش واردات', + 'type' => 'نوع', + 'validation-strategy' => 'استراتژی اعتبارسنجی', + ], + + 'index' => [ + 'button-title' => 'ایجاد واردات', + 'title' => 'واردات‌ها', + + 'datagrid' => [ + 'actions' => 'عملیات', + 'completed-at' => 'تکمیل شده در', + 'created' => 'ایجاد شده', + 'delete' => 'حذف', + 'deleted' => 'حذف شده', + 'edit' => 'ویرایش', + 'error-file' => 'فایل خطا', + 'id' => 'شناسه', + 'started-at' => 'شروع شده در', + 'state' => 'وضعیت', + 'summary' => 'خلاصه', + 'type' => 'نوع', + 'updated' => 'به‌روزرسانی شده', + 'uploaded-file' => 'فایل آپلود شده', + ], + ], + + 'import' => [ + 'back-btn' => 'بازگشت', + 'completed-batches' => 'کل دسته‌های تکمیل شده:', + 'download-error-report' => 'دانلود گزارش کامل', + 'edit-btn' => 'ویرایش', + 'imported-info' => 'تبریک! واردات شما با موفقیت انجام شد.', + 'importing-info' => 'واردات در حال انجام است', + 'indexing-info' => 'ایندکس‌گذاری منابع (قیمت، موجودی و Elastic Search) در حال پیشرفت است', + 'linking-info' => 'پیونددهی منابع در حال انجام است', + 'progress' => 'پیشرفت:', + 'title' => 'واردات', + 'total-batches' => 'کل دسته‌ها:', + 'total-created' => 'کل رکوردهای ایجاد شده:', + 'total-deleted' => 'کل رکوردهای حذف شده:', + 'total-errors' => 'کل خطاها:', + 'total-invalid-rows' => 'کل ردیف‌های نامعتبر:', + 'total-rows-processed' => 'کل ردیف‌های پردازش شده:', + 'total-updated' => 'کل رکوردهای به‌روزرسانی شده:', + 'validate' => 'اعتبارسنجی', + 'validate-info' => 'برای بررسی واردات خود، روی "اعتبارسنجی داده‌ها" کلیک کنید.', + 'validating-info' => 'خواندن و اعتبارسنجی داده‌ها آغاز شده است', + 'validation-failed-info' => 'واردات شما نامعتبر است. لطفاً خطاهای زیر را رفع کرده و دوباره تلاش کنید.', + 'validation-success-info' => 'واردات شما معتبر است. برای شروع فرآیند واردات، روی "واردات" کلیک کنید.', + ], + + 'create-success' => 'واردات با موفقیت ایجاد شد.', + 'delete-failed' => 'حذف واردات به طور غیرمنتظره‌ای ناکام ماند.', + 'delete-success' => 'واردات با موفقیت حذف شد.', + 'not-valid' => 'واردات نامعتبر است', + 'nothing-to-import' => 'هیچ منبعی برای واردات وجود ندارد.', + 'setup-queue-error' => 'لطفاً درایور صف خود را به "database" یا "redis" تغییر دهید تا فرآیند واردات شروع شود.', + 'update-success' => 'واردات با موفقیت به‌روزرسانی شد.', + ], + ], ], 'activities' => [ @@ -1978,6 +2084,8 @@ 'warehouses' => 'انبارها', 'warehouse' => 'انبار', 'warehouses-info' => 'اضافه، ویرایش یا حذف انبارها از CRM', + 'data_transfer' => 'انتقال داده', + 'data_transfer_info' => 'مدیریت تنظیمات مربوط به انتقال داده‌های اشخاص، محصولات و سرنخ‌ها در CRM', ], 'user' => [ @@ -2021,6 +2129,12 @@ ], ], + 'validations' => [ + 'message' => [ + 'decimal' => ':attribute باید یک عدد اعشاری باشد.', + ], + ], + 'errors' => [ 'dashboard' => 'داشبورد', 'go-back' => 'بازگشت', diff --git a/packages/Webkul/Admin/src/Resources/lang/tr/app.php b/packages/Webkul/Admin/src/Resources/lang/tr/app.php index 231400597..f2d52e341 100644 --- a/packages/Webkul/Admin/src/Resources/lang/tr/app.php +++ b/packages/Webkul/Admin/src/Resources/lang/tr/app.php @@ -39,6 +39,9 @@ 'delete' => 'Sil', 'export' => 'Dışa Aktar', 'mass-delete' => 'Toplu Sil', + 'data-transfer' => 'Veri Transferi', + 'imports' => 'İthalatlar', + 'import' => 'İthalat', ], 'users' => [ @@ -1487,6 +1490,109 @@ 'actions' => 'İşlemler', ], ], + + 'data-transfer' => [ + 'imports' => [ + 'create' => [ + 'action' => 'Eylem', + 'allowed-errors' => 'İzin Verilen Hatalar', + 'back-btn' => 'Geri', + 'create-update' => 'Oluştur/Güncelle', + 'delete' => 'Sil', + 'download-sample' => 'Örneği İndir', + 'field-separator' => 'Alan Ayırıcı', + 'file' => 'Dosya', + 'general' => 'Genel', + 'images-directory' => 'Resim Dizini Yolu', + 'process-in-queue' => 'Kuyrukta İşle', + 'results' => 'Sonuçlar', + 'save-btn' => 'İthalatı Kaydet', + 'settings' => 'Ayarlar', + 'skip-errors' => 'Hataları Atla', + 'stop-on-errors' => 'Hatalarda Durdur', + 'title' => 'İthalat Oluştur', + 'type' => 'Tür', + 'validation-strategy' => 'Doğrulama Stratejisi', + ], + + 'edit' => [ + 'action' => 'Eylem', + 'allowed-errors' => 'İzin Verilen Hatalar', + 'back-btn' => 'Geri', + 'create-update' => 'Oluştur/Güncelle', + 'delete' => 'Sil', + 'download-sample' => 'Örneği İndir', + 'field-separator' => 'Alan Ayırıcı', + 'file' => 'Dosya', + 'general' => 'Genel', + 'images-directory' => 'Resim Dizini Yolu', + 'process-in-queue' => 'Kuyrukta İşle', + 'results' => 'Sonuçlar', + 'save-btn' => 'İthalatı Kaydet', + 'settings' => 'Ayarlar', + 'skip-errors' => 'Hataları Atla', + 'stop-on-errors' => 'Hatalarda Durdur', + 'title' => 'İthalatı Düzenle', + 'type' => 'Tür', + 'validation-strategy' => 'Doğrulama Stratejisi', + ], + + 'index' => [ + 'button-title' => 'İthalat Oluştur', + 'title' => 'İthalatlar', + + 'datagrid' => [ + 'actions' => 'Eylemler', + 'completed-at' => 'Tamamlandığı Zaman', + 'created' => 'Oluşturuldu', + 'delete' => 'Sil', + 'deleted' => 'Silindi', + 'edit' => 'Düzenle', + 'error-file' => 'Hata Dosyası', + 'id' => 'Kimlik', + 'started-at' => 'Başlama Zamanı', + 'state' => 'Durum', + 'summary' => 'Özet', + 'type' => 'Tür', + 'updated' => 'Güncellendi', + 'uploaded-file' => 'Yüklenen Dosya', + ], + ], + + 'import' => [ + 'back-btn' => 'Geri', + 'completed-batches' => 'Tamamlanan Toplam Gruplar:', + 'download-error-report' => 'Tam Raporu İndir', + 'edit-btn' => 'Düzenle', + 'imported-info' => 'Tebrikler! İthalatınız başarılı oldu.', + 'importing-info' => 'İthalat İşlemde', + 'indexing-info' => 'Kaynaklar İndeksleniyor (Fiyat, Stok ve Elastic Search) İlerliyor', + 'linking-info' => 'Kaynaklar Bağlanıyor', + 'progress' => 'İlerleme:', + 'title' => 'İthalat', + 'total-batches' => 'Toplam Gruplar:', + 'total-created' => 'Oluşturulan Toplam Kayıtlar:', + 'total-deleted' => 'Silinen Toplam Kayıtlar:', + 'total-errors' => 'Toplam Hatalar:', + 'total-invalid-rows' => 'Geçersiz Satırların Toplamı:', + 'total-rows-processed' => 'İşlenen Toplam Satırlar:', + 'total-updated' => 'Güncellenen Toplam Kayıtlar:', + 'validate' => 'Doğrula', + 'validate-info' => 'İthalatınızı kontrol etmek için Verileri Doğrula\'ya tıklayın.', + 'validating-info' => 'Veriler okunmaya ve doğrulanmaya başlandı', + 'validation-failed-info' => 'İthalatınız geçersiz. Lütfen aşağıdaki hataları düzeltin ve tekrar deneyin.', + 'validation-success-info' => 'İthalatınız geçerli. İthalat işlemini başlatmak için İthalat\'a tıklayın.', + ], + + 'create-success' => 'İthalat başarıyla oluşturuldu.', + 'delete-failed' => 'İthalatı silme beklenmedik bir şekilde başarısız oldu.', + 'delete-success' => 'İthalat başarıyla silindi.', + 'not-valid' => 'İthalat geçersiz', + 'nothing-to-import' => 'İthal edilecek kaynak yok.', + 'setup-queue-error' => 'İthalat işlemini başlatmak için kuyruk sürücünüzü "veritabanı" veya "redis" olarak değiştirin.', + 'update-success' => 'İthalat başarıyla güncellendi.', + ], + ], ], 'activities' => [ @@ -1978,6 +2084,8 @@ 'warehouses' => 'Depolar', 'warehouse' => 'Depo', 'warehouses-info' => 'CRM’den depoları ekleyin, düzenleyin veya silin', + 'data_transfer' => 'Veri Transferi', + 'data_transfer_info' => 'CRM’de kişiler, ürünler ve potansiyel müşterilere ilişkin veri transferi ayarlarını yönetin', ], 'user' => [ @@ -2021,6 +2129,12 @@ ], ], + 'validations' => [ + 'message' => [ + 'decimal' => ':attribute ondalıklı bir sayı olmalıdır.', + ], + ], + 'errors' => [ 'dashboard' => 'Kontrol Paneli', 'go-back' => 'Geri Dön', diff --git a/packages/Webkul/Admin/src/Resources/views/components/form/control-group/control.blade.php b/packages/Webkul/Admin/src/Resources/views/components/form/control-group/control.blade.php index d26b16f01..6b02734bc 100644 --- a/packages/Webkul/Admin/src/Resources/views/components/form/control-group/control.blade.php +++ b/packages/Webkul/Admin/src/Resources/views/components/form/control-group/control.blade.php @@ -210,7 +210,7 @@ class="peer sr-only" {{ $attributes ->except(['value', ':value', 'v-model', 'rules', ':rules', 'label', ':label', 'key', ':key']) - ->merge(['class' => 'text-gray-500 icon-checkbox-outline peer-checked:icon-checkbox-select text-2xl peer-checked:text-blue-600']) + ->merge(['class' => 'text-gray-500 icon-checkbox-outline peer-checked:icon-checkbox-select text-2xl peer-checked:text-brandColor']) ->merge(['class' => $attributes->get('disabled') ? 'cursor-not-allowed opacity-70' : 'cursor-pointer']) }} > @@ -219,7 +219,7 @@ class="peer sr-only" @break @case('radio') - diff --git a/packages/Webkul/Admin/src/Resources/views/contacts/persons/view/organization.blade.php b/packages/Webkul/Admin/src/Resources/views/contacts/persons/view/organization.blade.php index 70b78b610..14a3727b0 100644 --- a/packages/Webkul/Admin/src/Resources/views/contacts/persons/view/organization.blade.php +++ b/packages/Webkul/Admin/src/Resources/views/contacts/persons/view/organization.blade.php @@ -44,11 +44,11 @@ class="icon-edit rounded-md p-1 text-2xl transition-all hover:bg-gray-100 dark:h - {{ core()->state_name($person->organization->address['state']) }} + {{ core()->state_name($person->organization->address['state'] ?? '') }} - {{ core()->country_name($person->organization->address['country']) }} + {{ core()->country_name($person->organization->address['country'] ?? '') }} @endif diff --git a/packages/Webkul/Admin/src/Resources/views/settings/data-transfer/imports/create.blade.php b/packages/Webkul/Admin/src/Resources/views/settings/data-transfer/imports/create.blade.php new file mode 100644 index 000000000..f64935ebf --- /dev/null +++ b/packages/Webkul/Admin/src/Resources/views/settings/data-transfer/imports/create.blade.php @@ -0,0 +1,234 @@ + + + + @lang('admin::app.settings.data-transfer.imports.create.title') + + + {!! view_render_event('admin.settings.data_transfer.imports.create.before') !!} + + + {!! view_render_event('admin.settings.data_transfer.imports.create.create_form_controls.before') !!} + + +
+
+
+ {!! view_render_event('admin.settings.data_transfers.create.breadcrumbs.before') !!} + + + + + {!! view_render_event('admin.settings.data_transfers.create.breadcrumbs.after') !!} +
+ +
+ @lang('admin::app.settings.data-transfer.imports.create.title') +
+
+ +
+ +
+ {!! view_render_event('admin.settings.data_transfers.create.save_button.before') !!} + + @if (bouncer()->hasPermission('settings.data_transfer.imports.create')) + + + @endif + + {!! view_render_event('admin.settings.data_transfers.create.save_button.after') !!} +
+
+
+ + +
+ +
+ {!! view_render_event('admin.settings.data_transfer.imports.create.card.general.before') !!} + + + + + {!! view_render_event('admin.settings.data_transfer.imports.create.card.general.after') !!} +
+ + +
+ {!! view_render_event('admin.settings.data_transfer.imports.create.card.accordion.settings.before') !!} + + + + +
+

+ @lang('admin::app.settings.data-transfer.imports.create.settings') +

+
+ + + + + + + @lang('admin::app.settings.data-transfer.imports.create.action') + + + + + + + + + + + + + + @lang('admin::app.settings.data-transfer.imports.create.validation-strategy') + + + + + + + + + + + + + + @lang('admin::app.settings.data-transfer.imports.create.allowed-errors') + + + + + + + + + + + @lang('admin::app.settings.data-transfer.imports.create.field-separator') + + + + + + + + + + + @lang('admin::app.settings.data-transfer.imports.create.process-in-queue') + + + + + + + +
+ + {!! view_render_event('admin.settings.data_transfer.imports.create.card.accordion.settings.after') !!} +
+
+ + {!! view_render_event('admin.settings.data_transfer.imports.create.create_form_controls.after') !!} + + diff --git a/packages/Webkul/Admin/src/Resources/views/settings/data-transfer/imports/edit.blade.php b/packages/Webkul/Admin/src/Resources/views/settings/data-transfer/imports/edit.blade.php new file mode 100644 index 000000000..7467cbff7 --- /dev/null +++ b/packages/Webkul/Admin/src/Resources/views/settings/data-transfer/imports/edit.blade.php @@ -0,0 +1,237 @@ + + + + @lang('admin::app.settings.data-transfer.imports.edit.title') + + + {!! view_render_event('admin.settings.data_transfer.imports.edit.before', ['import' => $import]) !!} + + + {!! view_render_event('admin.settings.data_transfer.imports.edit.edit_form_controls.before', ['import' => $import]) !!} + + +
+
+
+ {!! view_render_event('admin.settings.data_transfers.edit.breadcrumbs.before') !!} + + + + + {!! view_render_event('admin.settings.data_transfers.edit.breadcrumbs.after') !!} +
+ +
+ @lang('admin::app.settings.data-transfer.imports.edit.title') +
+
+ +
+ +
+ {!! view_render_event('admin.settings.data_transfers.edit.save_button.before') !!} + + @if (bouncer()->hasPermission('settings.data_transfer.imports.edit')) + + + @endif + + {!! view_render_event('admin.settings.data_transfers.edit.save_button.after') !!} +
+
+
+ + +
+ +
+ {!! view_render_event('admin.settings.data_transfer.imports.edit.card.general.before', ['import' => $import]) !!} + + +
+

+ @lang('admin::app.settings.data-transfer.imports.edit.general') +

+ + + + + @lang('admin::app.settings.data-transfer.imports.edit.type') + + + + @foreach (config('importers') as $code => $importer) + + @endforeach + + + + + @lang('admin::app.settings.data-transfer.imports.edit.download-sample') + + + + + + + + + @lang('admin::app.settings.data-transfer.imports.edit.file') + + + + + + +
+ + {!! view_render_event('admin.settings.data_transfer.imports.edit.card.general.after', ['import' => $import]) !!} +
+ + +
+ {!! view_render_event('admin.settings.data_transfer.imports.edit.card.accordion.settings.before', ['import' => $import]) !!} + + + + +
+

+ @lang('admin::app.settings.data-transfer.imports.edit.settings') +

+
+ + + + + + + @lang('admin::app.settings.data-transfer.imports.edit.action') + + + + + + + + + + + + + + @lang('admin::app.settings.data-transfer.imports.edit.validation-strategy') + + + + + + + + + + + + + + @lang('admin::app.settings.data-transfer.imports.edit.allowed-errors') + + + + + + + + + + + @lang('admin::app.settings.data-transfer.imports.edit.field-separator') + + + + + + + + + + + @lang('admin::app.settings.data-transfer.imports.edit.process-in-queue') + + + + + + + +
+ + {!! view_render_event('admin.settings.data_transfer.imports.edit.card.accordion.settings.after', ['import' => $import]) !!} +
+
+ + {!! view_render_event('admin.settings.data_transfer.imports.edit.edit_form_controls.after', ['import' => $import]) !!} +
+
diff --git a/packages/Webkul/Admin/src/Resources/views/settings/data-transfer/imports/import.blade.php b/packages/Webkul/Admin/src/Resources/views/settings/data-transfer/imports/import.blade.php new file mode 100644 index 000000000..3025e260a --- /dev/null +++ b/packages/Webkul/Admin/src/Resources/views/settings/data-transfer/imports/import.blade.php @@ -0,0 +1,541 @@ + + + @lang('admin::app.settings.data-transfer.imports.import.title') + + + +
+
+
+ {!! view_render_event('admin.settings.data_transfers.import.breadcrumbs.before') !!} + + + + + {!! view_render_event('admin.settings.data_transfers.import.breadcrumbs.after') !!} +
+ +
+ @lang('admin::app.settings.data-transfer.imports.import.title') +
+
+ +
+ +
+ {!! view_render_event('admin.settings.data_transfers.import.edit_button.before') !!} + + + @if (bouncer()->hasPermission('settings.data_transfer.imports.edit')) + + @lang('admin::app.settings.data-transfer.imports.import.edit-btn') + + @endif + + {!! view_render_event('admin.settings.data_transfers.import.edit_button.after') !!} +
+
+
+ + + + + @pushOnce('scripts') + + + + @endPushOnce +
diff --git a/packages/Webkul/Admin/src/Resources/views/settings/data-transfer/imports/index.blade.php b/packages/Webkul/Admin/src/Resources/views/settings/data-transfer/imports/index.blade.php new file mode 100644 index 000000000..fc0373e09 --- /dev/null +++ b/packages/Webkul/Admin/src/Resources/views/settings/data-transfer/imports/index.blade.php @@ -0,0 +1,52 @@ + + + @lang('admin::app.settings.data-transfer.imports.index.title') + + +
+
+
+
+ {!! view_render_event('admin.settings.data_transfers.index.breadcrumbs.before') !!} + + + + + {!! view_render_event('admin.settings.data_transfers.index.breadcrumbs.after') !!} +
+ +
+ @lang('admin::app.settings.data-transfer.imports.index.title') +
+
+ +
+ +
+ {!! view_render_event('admin.settings.data_transfers.index.create_button.before') !!} + + @if (bouncer()->hasPermission('settings.data_transfer.imports.create')) + + @lang('admin::app.settings.data-transfer.imports.index.button-title') + + @endif + + {!! view_render_event('admin.settings.data_transfers.index.create_button.after') !!} +
+
+
+ + {!! view_render_event('admin.settings.data_transfers.index.datagrid.before') !!} + + + + + + + + {!! view_render_event('admin.settings.data_transfers.index.datagrid.after') !!} +
+
diff --git a/packages/Webkul/Admin/src/Routes/Admin/settings-routes.php b/packages/Webkul/Admin/src/Routes/Admin/settings-routes.php index 972c30544..9c7bca85d 100644 --- a/packages/Webkul/Admin/src/Routes/Admin/settings-routes.php +++ b/packages/Webkul/Admin/src/Routes/Admin/settings-routes.php @@ -2,6 +2,7 @@ use Illuminate\Support\Facades\Route; use Webkul\Admin\Http\Controllers\Settings\AttributeController; +use Webkul\Admin\Http\Controllers\Settings\DataTransfer\ImportController; use Webkul\Admin\Http\Controllers\Settings\EmailTemplateController; use Webkul\Admin\Http\Controllers\Settings\GroupController; use Webkul\Admin\Http\Controllers\Settings\LocationController; @@ -289,4 +290,41 @@ Route::delete('{id}', 'destroy')->name('admin.settings.email_templates.delete'); }); + + Route::prefix('data-transfer')->group(function () { + /** + * Import routes. + */ + Route::controller(ImportController::class)->prefix('imports')->group(function () { + Route::get('', 'index')->name('admin.settings.data_transfer.imports.index'); + + Route::get('create', 'create')->name('admin.settings.data_transfer.imports.create'); + + Route::post('create', 'store')->name('admin.settings.data_transfer.imports.store'); + + Route::get('edit/{id}', 'edit')->name('admin.settings.data_transfer.imports.edit'); + + Route::put('update/{id}', 'update')->name('admin.settings.data_transfer.imports.update'); + + Route::delete('destroy/{id}', 'destroy')->name('admin.settings.data_transfer.imports.delete'); + + Route::get('import/{id}', 'import')->name('admin.settings.data_transfer.imports.import'); + + Route::get('validate/{id}', 'validateImport')->name('admin.settings.data_transfer.imports.validate'); + + Route::get('start/{id}', 'start')->name('admin.settings.data_transfer.imports.start'); + + Route::get('link/{id}', 'link')->name('admin.settings.data_transfer.imports.link'); + + Route::get('index/{id}', 'indexData')->name('admin.settings.data_transfer.imports.index_data'); + + Route::get('stats/{id}/{state?}', 'stats')->name('admin.settings.data_transfer.imports.stats'); + + Route::get('download-sample/{sample?}', 'downloadSample')->name('admin.settings.data_transfer.imports.download_sample'); + + Route::get('download/{id}', 'download')->name('admin.settings.data_transfer.imports.download'); + + Route::get('download-error-report/{id}', 'downloadErrorReport')->name('admin.settings.data_transfer.imports.download_error_report'); + }); + }); }); diff --git a/packages/Webkul/Contact/src/Database/Migrations/2024_09_09_112201_add_unique_id_to_person_table.php b/packages/Webkul/Contact/src/Database/Migrations/2024_09_09_112201_add_unique_id_to_person_table.php new file mode 100644 index 000000000..fff8e031a --- /dev/null +++ b/packages/Webkul/Contact/src/Database/Migrations/2024_09_09_112201_add_unique_id_to_person_table.php @@ -0,0 +1,39 @@ +string('unique_id')->nullable()->unique(); + }); + + DB::statement(" + UPDATE persons + SET unique_id = CONCAT( + user_id, '|', + organization_id, '|', + JSON_UNQUOTE(JSON_EXTRACT(emails, '$[0].value')), '|', + JSON_UNQUOTE(JSON_EXTRACT(contact_numbers, '$[0].value')) + ) + "); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('persons', function (Blueprint $table) { + $table->dropColumn('unique_id'); + }); + } +}; diff --git a/packages/Webkul/Contact/src/Models/Person.php b/packages/Webkul/Contact/src/Models/Person.php index 796c8140c..f548e8495 100644 --- a/packages/Webkul/Contact/src/Models/Person.php +++ b/packages/Webkul/Contact/src/Models/Person.php @@ -52,6 +52,7 @@ class Person extends Model implements PersonContract 'job_title', 'user_id', 'organization_id', + 'unique_id', ]; /** diff --git a/packages/Webkul/Core/src/Config/concord.php b/packages/Webkul/Core/src/Config/concord.php index 1ef9a6004..5f20fa25f 100644 --- a/packages/Webkul/Core/src/Config/concord.php +++ b/packages/Webkul/Core/src/Config/concord.php @@ -18,6 +18,7 @@ \Webkul\User\Providers\ModuleServiceProvider::class, \Webkul\Warehouse\Providers\ModuleServiceProvider::class, \Webkul\WebForm\Providers\ModuleServiceProvider::class, + \Webkul\DataTransfer\Providers\ModuleServiceProvider::class, ], 'register_route_models' => true, diff --git a/packages/Webkul/Core/src/Contracts/Validations/Decimal.php b/packages/Webkul/Core/src/Contracts/Validations/Decimal.php index 1b7c8b318..aa7dec0bf 100755 --- a/packages/Webkul/Core/src/Contracts/Validations/Decimal.php +++ b/packages/Webkul/Core/src/Contracts/Validations/Decimal.php @@ -2,29 +2,20 @@ namespace Webkul\Core\Contracts\Validations; -use Illuminate\Contracts\Validation\Rule; +use Closure; +use Illuminate\Contracts\Validation\ValidationRule; -class Decimal implements Rule +class Decimal implements ValidationRule { /** - * Determine if the validation rule passes. + * Run the validation rule. * - * @param string $attribute - * @param mixed $value - * @return bool + * @param \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString $fail */ - public function passes($attribute, $value) + public function validate(string $attribute, mixed $value, Closure $fail): void { - return preg_match('/^\d*(\.\d{1,4})?$/', $value); - } - - /** - * Get the validation error message. - * - * @return string - */ - public function message() - { - return trans('core::validation.decimal'); + if (! preg_match('/^\d*(\.\d{1,4})?$/', $value)) { + $fail(trans('admin::app.validations.message.decimal', ['attribute' => $attribute])); + } } } diff --git a/packages/Webkul/DataTransfer/src/Config/importers.php b/packages/Webkul/DataTransfer/src/Config/importers.php new file mode 100644 index 000000000..61cdf3cd6 --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Config/importers.php @@ -0,0 +1,21 @@ + [ + 'title' => 'data_transfer::app.importers.persons.title', + 'importer' => 'Webkul\DataTransfer\Helpers\Importers\Persons\Importer', + 'sample_path' => 'data-transfer/samples/persons.csv', + ], + + 'products' => [ + 'title' => 'data_transfer::app.importers.products.title', + 'importer' => 'Webkul\DataTransfer\Helpers\Importers\Products\Importer', + 'sample_path' => 'data-transfer/samples/products.csv', + ], + + 'leads' => [ + 'title' => 'data_transfer::app.importers.leads.title', + 'importer' => 'Webkul\DataTransfer\Helpers\Importers\Leads\Importer', + 'sample_path' => 'data-transfer/samples/leads.csv', + ], +]; diff --git a/packages/Webkul/DataTransfer/src/Contracts/Import.php b/packages/Webkul/DataTransfer/src/Contracts/Import.php new file mode 100644 index 000000000..d9f02b865 --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Contracts/Import.php @@ -0,0 +1,5 @@ +increments('id'); + $table->string('state')->default('pending'); + $table->boolean('process_in_queue')->default(1); + $table->string('type'); + $table->string('action'); + $table->string('validation_strategy'); + $table->integer('allowed_errors')->default(0); + $table->integer('processed_rows_count')->default(0); + $table->integer('invalid_rows_count')->default(0); + $table->integer('errors_count')->default(0); + $table->json('errors')->nullable(); + $table->string('field_separator'); + $table->string('file_path'); + $table->string('error_file_path')->nullable(); + $table->json('summary')->nullable(); + + $table->datetime('started_at')->nullable(); + $table->datetime('completed_at')->nullable(); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('imports'); + } +}; diff --git a/packages/Webkul/DataTransfer/src/Database/Migrations/2024_01_11_154741_create_import_batches_table.php b/packages/Webkul/DataTransfer/src/Database/Migrations/2024_01_11_154741_create_import_batches_table.php new file mode 100644 index 000000000..013954180 --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Database/Migrations/2024_01_11_154741_create_import_batches_table.php @@ -0,0 +1,32 @@ +increments('id'); + $table->string('state')->default('pending'); + $table->json('data'); + $table->json('summary')->nullable(); + $table->integer('import_id')->unsigned(); + + $table->foreign('import_id')->references('id')->on('imports')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('import_batches'); + } +}; diff --git a/packages/Webkul/DataTransfer/src/Helpers/Error.php b/packages/Webkul/DataTransfer/src/Helpers/Error.php new file mode 100644 index 000000000..3683d39ee --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Helpers/Error.php @@ -0,0 +1,186 @@ +messageTemplate[$code] = $template; + + return $this; + } + + /** + * Add error message. + */ + public function addError(string $code, ?int $rowNumber = null, ?string $columnName = null, ?string $message = null): self + { + if ($this->isErrorAlreadyAdded($rowNumber, $code, $columnName)) { + return $this; + } + + $this->addRowToInvalid($rowNumber); + + $message = $this->getErrorMessage($code, $message, $columnName); + + $this->items[$rowNumber][] = [ + 'code' => $code, + 'column' => $columnName, + 'message' => $message, + ]; + + $this->errorsCount++; + + return $this; + } + + /** + * Check if error is already added for the row, code and column. + */ + public function isErrorAlreadyAdded(?int $rowNumber, string $code, ?string $columnName): bool + { + return collect($this->items[$rowNumber] ?? []) + ->where('code', $code) + ->where('column', $columnName) + ->isNotEmpty(); + } + + /** + * Add specific row to invalid list via row number. + */ + protected function addRowToInvalid(?int $rowNumber): self + { + if (is_null($rowNumber)) { + return $this; + } + + if (! in_array($rowNumber, $this->invalidRows)) { + $this->invalidRows[] = $rowNumber; + } + + return $this; + } + + /** + * Add specific row to invalid list via row number. + */ + public function addRowToSkip(?int $rowNumber): self + { + if (is_null($rowNumber)) { + return $this; + } + + if (! in_array($rowNumber, $this->skippedRows)) { + $this->skippedRows[] = $rowNumber; + } + + return $this; + } + + /** + * Check if row is invalid by row number. + */ + public function isRowInvalid(int $rowNumber): bool + { + return in_array($rowNumber, array_merge($this->invalidRows, $this->skippedRows)); + } + + /** + * Build an error message via code, message and column name. + */ + protected function getErrorMessage(?string $code, ?string $message, ?string $columnName): string + { + if ( + empty($message) + && isset($this->messageTemplate[$code]) + ) { + $message = (string) $this->messageTemplate[$code]; + } + + if ( + $columnName + && $message + ) { + $message = sprintf($message, $columnName); + } + + if (! $message) { + $message = $code; + } + + return $message; + } + + /** + * Get number of invalid rows. + */ + public function getInvalidRowsCount(): int + { + return count($this->invalidRows); + } + + /** + * Get current error count. + */ + public function getErrorsCount(): int + { + return $this->errorsCount; + } + + /** + * Get all errors from an import process. + */ + public function getAllErrors(): array + { + return $this->items; + } + + /** + * Return all errors grouped by code. + */ + public function getAllErrorsGroupedByCode(): array + { + $errors = []; + + foreach ($this->items as $rowNumber => $rowErrors) { + foreach ($rowErrors as $error) { + if ($rowNumber === '') { + $errors[$error['code']][$error['message']] = null; + } else { + $errors[$error['code']][$error['message']][] = $rowNumber; + } + } + } + + return $errors; + } +} diff --git a/packages/Webkul/DataTransfer/src/Helpers/Import.php b/packages/Webkul/DataTransfer/src/Helpers/Import.php new file mode 100644 index 000000000..aad39cb78 --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Helpers/Import.php @@ -0,0 +1,573 @@ +import = $import; + + return $this; + } + + /** + * Returns import instance. + */ + public function getImport(): ImportContract + { + return $this->import; + } + + /** + * Returns error helper instance. + * + * @return \Webkul\DataTransfer\Helpers\Error + */ + public function getErrorHelper() + { + return $this->errorHelper; + } + + /** + * Returns source helper instance. + */ + public function getSource(): AbstractSource + { + if (Str::contains($this->import->file_path, '.csv')) { + $source = new CSVSource( + $this->import->file_path, + $this->import->field_separator, + ); + } else { + $source = new ExcelSource( + $this->import->file_path, + $this->import->field_separator, + ); + } + + return $source; + } + + /** + * Validates import and returns validation result. + */ + public function validate(): bool + { + try { + $source = $this->getSource(); + + $typeImporter = $this->getTypeImporter()->setSource($source); + + $typeImporter->validateData(); + } catch (\Exception $e) { + $this->errorHelper->addError( + AbstractImporter::ERROR_CODE_SYSTEM_EXCEPTION, + null, + null, + $e->getMessage() + ); + } + + $import = $this->importRepository->update([ + 'state' => self::STATE_VALIDATED, + 'processed_rows_count' => $this->getProcessedRowsCount(), + 'invalid_rows_count' => $this->errorHelper->getInvalidRowsCount(), + 'errors_count' => $this->errorHelper->getErrorsCount(), + 'errors' => $this->getFormattedErrors(), + 'error_file_path' => $this->uploadErrorReport(), + ], $this->import->id); + + $this->setImport($import); + + return $this->isValid(); + } + + /** + * Starts import process. + */ + public function isValid(): bool + { + if ($this->isErrorLimitExceeded()) { + return false; + } + + if ($this->import->processed_rows_count <= $this->import->invalid_rows_count) { + return false; + } + + return true; + } + + /** + * Check if error limit has been exceeded. + */ + public function isErrorLimitExceeded(): bool + { + if ( + $this->import->validation_strategy == self::VALIDATION_STRATEGY_STOP_ON_ERROR + && $this->import->errors_count > $this->import->allowed_errors + ) { + return true; + } + + return false; + } + + /** + * Starts import process. + */ + public function start(?ImportBatchContract $importBatch = null): bool + { + DB::beginTransaction(); + + try { + $typeImporter = $this->getTypeImporter(); + + $typeImporter->importData($importBatch); + } catch (\Exception $e) { + /** + * Rollback transaction. + */ + DB::rollBack(); + + throw $e; + } finally { + /** + * Commit transaction. + */ + DB::commit(); + } + + return true; + } + + /** + * Link import resources. + */ + public function link(ImportBatchContract $importBatch): bool + { + DB::beginTransaction(); + + try { + $typeImporter = $this->getTypeImporter(); + + $typeImporter->linkData($importBatch); + } catch (\Exception $e) { + /** + * Rollback transaction. + */ + DB::rollBack(); + + throw $e; + } finally { + /** + * Commit transaction. + */ + DB::commit(); + } + + return true; + } + + /** + * Index import resources. + */ + public function index(ImportBatchContract $importBatch): bool + { + DB::beginTransaction(); + + try { + $typeImporter = $this->getTypeImporter(); + + $typeImporter->indexData($importBatch); + } catch (\Exception $e) { + /** + * Rollback transaction. + */ + DB::rollBack(); + + throw $e; + } finally { + /** + * Commit transaction. + */ + DB::commit(); + } + + return true; + } + + /** + * Started the import process. + */ + public function started(): void + { + $import = $this->importRepository->update([ + 'state' => self::STATE_PROCESSING, + 'started_at' => now(), + 'summary' => [], + ], $this->import->id); + + $this->setImport($import); + + Event::dispatch('data_transfer.imports.started', $import); + } + + /** + * Started the import linking process. + */ + public function linking(): void + { + $import = $this->importRepository->update([ + 'state' => self::STATE_LINKING, + ], $this->import->id); + + $this->setImport($import); + + Event::dispatch('data_transfer.imports.linking', $import); + } + + /** + * Started the import indexing process. + */ + public function indexing(): void + { + $import = $this->importRepository->update([ + 'state' => self::STATE_INDEXING, + ], $this->import->id); + + $this->setImport($import); + + Event::dispatch('data_transfer.imports.indexing', $import); + } + + /** + * Start the import process. + */ + public function completed(): void + { + $summary = $this->importBatchRepository + ->select( + DB::raw('SUM(json_unquote(json_extract(summary, \'$."created"\'))) AS created'), + DB::raw('SUM(json_unquote(json_extract(summary, \'$."updated"\'))) AS updated'), + DB::raw('SUM(json_unquote(json_extract(summary, \'$."deleted"\'))) AS deleted'), + ) + ->where('import_id', $this->import->id) + ->groupBy('import_id') + ->first() + ->toArray(); + + $import = $this->importRepository->update([ + 'state' => self::STATE_COMPLETED, + 'summary' => $summary, + 'completed_at' => now(), + ], $this->import->id); + + $this->setImport($import); + + Event::dispatch('data_transfer.imports.completed', $import); + } + + /** + * Returns import stats. + */ + public function stats(string $state): array + { + $total = $this->import->batches->count(); + + $completed = $this->import->batches->where('state', $state)->count(); + + $progress = $total + ? round($completed / $total * 100) + : 0; + + $summary = $this->importBatchRepository + ->select( + DB::raw('SUM(json_unquote(json_extract(summary, \'$."created"\'))) AS created'), + DB::raw('SUM(json_unquote(json_extract(summary, \'$."updated"\'))) AS updated'), + DB::raw('SUM(json_unquote(json_extract(summary, \'$."deleted"\'))) AS deleted'), + ) + ->where('import_id', $this->import->id) + ->where('state', $state) + ->groupBy('import_id') + ->first() + ?->toArray(); + + return [ + 'batches' => [ + 'total' => $total, + 'completed' => $completed, + 'remaining' => $total - $completed, + ], + 'progress' => $progress, + 'summary' => $summary ?? [ + 'created' => 0, + 'updated' => 0, + 'deleted' => 0, + ], + ]; + } + + /** + * Return all error grouped by error code. + */ + public function getFormattedErrors(): array + { + $errors = []; + + foreach ($this->errorHelper->getAllErrorsGroupedByCode() as $groupedErrors) { + foreach ($groupedErrors as $errorMessage => $rowNumbers) { + if (! empty($rowNumbers)) { + $errors[] = 'Row(s) '.implode(', ', $rowNumbers).': '.$errorMessage; + } else { + $errors[] = $errorMessage; + } + } + } + + return $errors; + } + + /** + * Uploads error report and save the path to the database. + */ + public function uploadErrorReport(): ?string + { + /** + * Return null if there are no errors. + */ + if (! $this->errorHelper->getErrorsCount()) { + return null; + } + + /** + * Return null if there are no invalid rows. + */ + if (! $this->errorHelper->getInvalidRowsCount()) { + return null; + } + + $errors = $this->errorHelper->getAllErrors(); + + $source = $this->getTypeImporter()->getSource(); + + $source->rewind(); + + $spreadsheet = new Spreadsheet; + + $sheet = $spreadsheet->getActiveSheet(); + + /** + * Add headers with extra error column. + */ + $sheet->fromArray( + [array_merge($source->getColumnNames(), [ + 'error', + ])], + null, + 'A1' + ); + + $rowNumber = 2; + + while ($source->valid()) { + try { + $rowData = $source->current(); + } catch (\InvalidArgumentException $e) { + $source->next(); + + continue; + } + + $rowErrors = $errors[$source->getCurrentRowNumber()] ?? []; + + if (! empty($rowErrors)) { + $rowErrors = Arr::pluck($rowErrors, 'message'); + } + + $rowData[] = implode('|', $rowErrors); + + $sheet->fromArray([$rowData], null, 'A'.$rowNumber++); + + $source->next(); + } + + $fileType = pathinfo($this->import->file_path, PATHINFO_EXTENSION); + + switch ($fileType) { + case 'csv': + $writer = new Csv($spreadsheet); + + $writer->setDelimiter($this->import->field_separator); + + break; + + case 'xls': + $writer = new Xls($spreadsheet); + + case 'xlsx': + $writer = new Xlsx($spreadsheet); + + break; + + default: + throw new \InvalidArgumentException("Unsupported file type: $fileType"); + } + + $errorFilePath = 'imports/'.time().'-error-report.'.$fileType; + + $writer->save(Storage::disk('public')->path($errorFilePath)); + + return $errorFilePath; + } + + /** + * Validates source file and returns validation result. + */ + public function getTypeImporter(): AbstractImporter + { + if (! $this->typeImporter) { + $importerConfig = config('importers.'.$this->import->type); + + $this->typeImporter = app()->make($importerConfig['importer']) + ->setImport($this->import) + ->setErrorHelper($this->errorHelper); + } + + return $this->typeImporter; + } + + /** + * Returns number of checked rows. + */ + public function getProcessedRowsCount(): int + { + return $this->getTypeImporter()->getProcessedRowsCount(); + } + + /** + * Is linking resource required for the import operation. + */ + public function isLinkingRequired(): bool + { + return $this->getTypeImporter()->isLinkingRequired(); + } + + /** + * Is indexing resource required for the import operation. + */ + public function isIndexingRequired(): bool + { + return $this->getTypeImporter()->isIndexingRequired(); + } +} diff --git a/packages/Webkul/DataTransfer/src/Helpers/Importers/AbstractImporter.php b/packages/Webkul/DataTransfer/src/Helpers/Importers/AbstractImporter.php new file mode 100644 index 000000000..bb38b4f20 --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Helpers/Importers/AbstractImporter.php @@ -0,0 +1,551 @@ + 'data_transfer::app.validation.errors.system', + self::ERROR_CODE_COLUMN_NOT_FOUND => 'data_transfer::app.validation.errors.column-not-found', + self::ERROR_CODE_COLUMN_EMPTY_HEADER => 'data_transfer::app.validation.errors.column-empty-headers', + self::ERROR_CODE_COLUMN_NAME_INVALID => 'data_transfer::app.validation.errors.column-name-invalid', + self::ERROR_CODE_INVALID_ATTRIBUTE => 'data_transfer::app.validation.errors.invalid-attribute', + self::ERROR_CODE_WRONG_QUOTES => 'data_transfer::app.validation.errors.wrong-quotes', + self::ERROR_CODE_COLUMNS_NUMBER => 'data_transfer::app.validation.errors.column-numbers', + ]; + + public const BATCH_SIZE = 100; + + /** + * Is linking required. + */ + protected bool $linkingRequired = false; + + /** + * Is indexing required. + */ + protected bool $indexingRequired = false; + + /** + * Error helper instance. + * + * @var \Webkul\DataTransfer\Helpers\Error + */ + protected $errorHelper; + + /** + * Import instance. + */ + protected ImportContract $import; + + /** + * Source instance. + * + * @var \Webkul\DataTransfer\Helpers\Source + */ + protected $source; + + /** + * Valid column names. + */ + protected array $validColumnNames = []; + + /** + * Array of numbers of validated rows as keys and boolean TRUE as values. + */ + protected array $validatedRows = []; + + /** + * Number of rows processed by validation. + */ + protected int $processedRowsCount = 0; + + /** + * Number of created items. + */ + protected int $createdItemsCount = 0; + + /** + * Number of updated items. + */ + protected int $updatedItemsCount = 0; + + /** + * Number of deleted items. + */ + protected int $deletedItemsCount = 0; + + /** + * Create a new helper instance. + * + * @return void + */ + public function __construct( + protected ImportBatchRepository $importBatchRepository, + protected AttributeRepository $attributeRepository, + protected AttributeValueRepository $attributeValueRepository + ) {} + + /** + * Validate data row. + */ + abstract public function validateRow(array $rowData, int $rowNumber): bool; + + /** + * Import data rows. + */ + abstract public function importBatch(ImportBatchContract $importBatchContract): bool; + + /** + * Initialize Product error messages. + */ + protected function initErrorMessages(): void + { + foreach ($this->errorMessages as $errorCode => $message) { + $this->errorHelper->addErrorMessage($errorCode, trans($message)); + } + } + + /** + * Import instance. + */ + public function setImport(ImportContract $import): self + { + $this->import = $import; + + return $this; + } + + /** + * Import instance. + * + * @param \Webkul\DataTransfer\Helpers\Source $errorHelper + */ + public function setSource($source) + { + $this->source = $source; + + return $this; + } + + /** + * Import instance. + * + * @param \Webkul\DataTransfer\Helpers\Error $errorHelper + */ + public function setErrorHelper($errorHelper): self + { + $this->errorHelper = $errorHelper; + + $this->initErrorMessages(); + + return $this; + } + + /** + * Import instance. + * + * @return \Webkul\DataTransfer\Helpers\Source + */ + public function getSource() + { + return $this->source; + } + + /** + * Retrieve valid column names. + */ + public function getValidColumnNames(): array + { + return $this->validColumnNames; + } + + /** + * Validate data. + */ + public function validateData(): void + { + Event::dispatch('data_transfer.imports.validate.before', $this->import); + + $errors = []; + + $absentColumns = array_diff($this->permanentAttributes, $columns = $this->getSource()->getColumnNames()); + + if (! empty($absentColumns)) { + $errors[self::ERROR_CODE_COLUMN_NOT_FOUND] = $absentColumns; + } + + foreach ($columns as $columnNumber => $columnName) { + if (empty($columnName)) { + $errors[self::ERROR_CODE_COLUMN_EMPTY_HEADER][] = $columnNumber + 1; + } elseif (! preg_match('/^[a-z][a-z0-9_]*$/', $columnName)) { + $errors[self::ERROR_CODE_COLUMN_NAME_INVALID][] = $columnName; + } elseif (! in_array($columnName, $this->getValidColumnNames())) { + $errors[self::ERROR_CODE_INVALID_ATTRIBUTE][] = $columnName; + } + } + + /** + * Add Columns Errors. + */ + foreach ($errors as $errorCode => $error) { + $this->addErrors($errorCode, $error); + } + + if (! $this->errorHelper->getErrorsCount()) { + $this->saveValidatedBatches(); + } + + Event::dispatch('data_transfer.imports.validate.after', $this->import); + } + + /** + * Save validated batches. + */ + protected function saveValidatedBatches(): self + { + $source = $this->getSource(); + + $batchRows = []; + + $source->rewind(); + + /** + * Clean previous saved batches. + */ + $this->importBatchRepository->deleteWhere([ + 'import_id' => $this->import->id, + ]); + + while ( + $source->valid() + || count($batchRows) + ) { + if ( + count($batchRows) == self::BATCH_SIZE + || ! $source->valid() + ) { + $this->importBatchRepository->create([ + 'import_id' => $this->import->id, + 'data' => $batchRows, + ]); + + $batchRows = []; + } + + if ($source->valid()) { + $rowData = $source->current(); + + if ($this->validateRow($rowData, $source->getCurrentRowNumber())) { + $batchRows[] = $this->prepareRowForDb($rowData); + } + + $this->processedRowsCount++; + + $source->next(); + } + } + + return $this; + } + + /** + * Prepare validation rules. + */ + public function getValidationRules(string $entityType, array $rowData): array + { + if (empty($entityType)) { + return []; + } + + $rules = []; + + $attributes = $this->attributeRepository->scopeQuery(fn ($query) => $query->whereIn('code', array_keys($rowData))->where('entity_type', $entityType))->get(); + + foreach ($attributes as $attribute) { + $validations = []; + + if ($attribute->type == 'boolean') { + continue; + } elseif ($attribute->type == 'address') { + if (! $attribute->is_required) { + continue; + } + + $validations = [ + $attribute->code.'.address' => 'required', + $attribute->code.'.country' => 'required', + $attribute->code.'.state' => 'required', + $attribute->code.'.city' => 'required', + $attribute->code.'.postcode' => 'required', + ]; + } elseif ($attribute->type == 'email') { + $validations = [ + $attribute->code => [$attribute->is_required ? 'required' : 'nullable'], + $attribute->code.'.*.value' => [$attribute->is_required ? 'required' : 'nullable', 'email'], + $attribute->code.'.*.label' => $attribute->is_required ? 'required' : 'nullable', + ]; + } elseif ($attribute->type == 'phone') { + $validations = [ + $attribute->code => [$attribute->is_required ? 'required' : 'nullable'], + $attribute->code.'.*.value' => [$attribute->is_required ? 'required' : 'nullable'], + $attribute->code.'.*.label' => $attribute->is_required ? 'required' : 'nullable', + ]; + } else { + $validations[$attribute->code] = [$attribute->is_required ? 'required' : 'nullable']; + + if ($attribute->type == 'text' && $attribute->validation) { + array_push($validations[$attribute->code], + $attribute->validation == 'decimal' + ? new Decimal + : $attribute->validation + ); + } + + if ($attribute->type == 'price') { + array_push($validations[$attribute->code], new Decimal); + } + } + + if ($attribute->is_unique) { + array_push($validations[in_array($attribute->type, ['email', 'phone']) + ? $attribute->code.'.*.value' + : $attribute->code + ], function ($field, $value, $fail) use ($attribute) { + if (! $this->attributeValueRepository->isValueUnique(null, $attribute->entity_type, $attribute, $field)) { + $fail(trans('data_transfer::app.validation.errors.already-exists', ['attribute' => $attribute->name])); + } + }); + } + + $rules = [ + ...$rules, + ...$validations, + ]; + } + + return $rules; + } + + /** + * Start the import process. + */ + public function importData(?ImportBatchContract $importBatch = null): bool + { + if ($importBatch) { + $this->importBatch($importBatch); + + return true; + } + + $typeBatches = []; + + foreach ($this->import->batches as $batch) { + $typeBatches['import'][] = new ImportBatchJob($batch); + + if ($this->isLinkingRequired()) { + $typeBatches['link'][] = new LinkBatchJob($batch); + } + + if ($this->isIndexingRequired()) { + $typeBatches['index'][] = new IndexBatchJob($batch); + } + } + + $chain[] = Bus::batch($typeBatches['import']); + + if (! empty($typeBatches['link'])) { + $chain[] = new LinkingJob($this->import); + + $chain[] = Bus::batch($typeBatches['link']); + } + + if (! empty($typeBatches['index'])) { + $chain[] = new IndexingJob($this->import); + + $chain[] = Bus::batch($typeBatches['index']); + } + + $chain[] = new CompletedJob($this->import); + + Bus::chain($chain)->dispatch(); + + return true; + } + + /** + * Link resource data. + */ + public function linkData(ImportBatchContract $importBatch): bool + { + $this->linkBatch($importBatch); + + return true; + } + + /** + * Index resource data. + */ + public function indexData(ImportBatchContract $importBatch): bool + { + $this->indexBatch($importBatch); + + return true; + } + + /** + * Add errors to error aggregator. + */ + protected function addErrors(string $code, mixed $errors): void + { + $this->errorHelper->addError( + $code, + null, + implode('", "', $errors) + ); + } + + /** + * Add row as skipped. + * + * @param int|null $rowNumber + * @param string|null $columnName + * @param string|null $errorMessage + * @return $this + */ + protected function skipRow($rowNumber, string $errorCode, $columnName = null, $errorMessage = null): self + { + $this->errorHelper->addError( + $errorCode, + $rowNumber, + $columnName, + $errorMessage + ); + + $this->errorHelper->addRowToSkip($rowNumber); + + return $this; + } + + /** + * Prepare row data to save into the database. + */ + protected function prepareRowForDb(array $rowData): array + { + $rowData = array_map(function ($value) { + return $value === '' ? null : $value; + }, $rowData); + + return $rowData; + } + + /** + * Returns number of checked rows. + */ + public function getProcessedRowsCount(): int + { + return $this->processedRowsCount; + } + + /** + * Returns number of created items count. + */ + public function getCreatedItemsCount(): int + { + return $this->createdItemsCount; + } + + /** + * Returns number of updated items count. + */ + public function getUpdatedItemsCount(): int + { + return $this->updatedItemsCount; + } + + /** + * Returns number of deleted items count. + */ + public function getDeletedItemsCount(): int + { + return $this->deletedItemsCount; + } + + /** + * Is linking resource required for the import operation. + */ + public function isLinkingRequired(): bool + { + if ($this->import->action == Import::ACTION_DELETE) { + return false; + } + + return $this->linkingRequired; + } + + /** + * Is indexing resource required for the import operation. + */ + public function isIndexingRequired(): bool + { + if ($this->import->action == Import::ACTION_DELETE) { + return false; + } + + return $this->indexingRequired; + } +} diff --git a/packages/Webkul/DataTransfer/src/Helpers/Importers/Leads/Importer.php b/packages/Webkul/DataTransfer/src/Helpers/Importers/Leads/Importer.php new file mode 100644 index 000000000..15e412190 --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Helpers/Importers/Leads/Importer.php @@ -0,0 +1,515 @@ + 'data_transfer::app.importers.leads.validation.errors.id-not-found', + ]; + + /** + * Permanent entity columns. + * + * @var string[] + */ + protected $permanentAttributes = ['title']; + + /** + * Permanent entity column. + */ + protected string $masterAttributeCode = 'id'; + + /** + * Is linking required + */ + protected bool $linkingRequired = true; + + /** + * Create a new helper instance. + * + * @return void + */ + public function __construct( + protected ImportBatchRepository $importBatchRepository, + protected LeadRepository $leadRepository, + protected LeadProductRepository $leadProductRepository, + protected AttributeRepository $attributeRepository, + protected AttributeValueRepository $attributeValueRepository, + protected Storage $leadsStorage, + ) { + parent::__construct( + $importBatchRepository, + $attributeRepository, + $attributeValueRepository, + ); + } + + /** + * Initialize leads error templates. + */ + protected function initErrorMessages(): void + { + foreach ($this->messages as $errorCode => $message) { + $this->errorHelper->addErrorMessage($errorCode, trans($message)); + } + + parent::initErrorMessages(); + } + + /** + * Validate data. + */ + public function validateData(): void + { + $this->leadsStorage->init(); + + parent::validateData(); + } + + /** + * Validates row. + */ + public function validateRow(array $rowData, int $rowNumber): bool + { + /** + * If row is already validated than no need for further validation. + */ + if (isset($this->validatedRows[$rowNumber])) { + return ! $this->errorHelper->isRowInvalid($rowNumber); + } + + $this->validatedRows[$rowNumber] = true; + + /** + * If import action is delete than no need for further validation. + */ + if ($this->import->action == Import::ACTION_DELETE) { + if (! $this->isTitleExist($rowData['title'])) { + $this->skipRow($rowNumber, self::ERROR_ID_NOT_FOUND_FOR_DELETE, 'id'); + + return false; + } + + return true; + } + + if (! empty($rowData['product'])) { + $product = $this->parseProducts($rowData['product']); + + $validator = Validator::make($product, [ + 'id' => 'required|exists:products,id', + 'price' => 'required', + 'quantity' => 'required', + ]); + + if ($validator->fails()) { + $failedAttributes = $validator->failed(); + + foreach ($validator->errors()->getMessages() as $attributeCode => $message) { + $errorCode = array_key_first($failedAttributes[$attributeCode] ?? []); + + $this->skipRow($rowNumber, $errorCode, $attributeCode, current($message)); + } + } + } + + /** + * Validate leads attributes. + */ + $validator = Validator::make($rowData, [ + ...$this->getValidationRules('leads|persons', $rowData), + 'id' => 'numeric', + 'status' => 'sometimes|required|in:0,1', + 'user_id' => 'required|exists:users,id', + 'person_id' => 'required|exists:persons,id', + 'lead_source_id' => 'required|exists:lead_sources,id', + 'lead_type_id' => 'required|exists:lead_types,id', + 'lead_pipeline_id' => 'required|exists:lead_pipelines,id', + 'lead_pipeline_stage_id' => 'required|exists:lead_pipeline_stages,id', + ]); + + if ($validator->fails()) { + $failedAttributes = $validator->failed(); + + foreach ($validator->errors()->getMessages() as $attributeCode => $message) { + $errorCode = array_key_first($failedAttributes[$attributeCode] ?? []); + + $this->skipRow($rowNumber, $errorCode, $attributeCode, current($message)); + } + } + + return ! $this->errorHelper->isRowInvalid($rowNumber); + } + + /** + * Prepare row data for lead product. + */ + protected function parseProducts(?string $products): array + { + $productData = []; + + $productArray = explode(',', $products); + + foreach ($productArray as $product) { + if (empty($product)) { + continue; + } + + [$key, $value] = explode('=', $product); + + $productData[$key] = $value; + } + + if ( + isset($productData['price']) + && isset($productData['quantity']) + ) { + $productData['amount'] = $productData['price'] * $productData['quantity']; + } + + return $productData; + } + + /** + * Get validation rules. + */ + public function getValidationRules(string $entityTypes, array $rowData): array + { + $rules = []; + + foreach (explode('|', $entityTypes) as $entityType) { + $attributes = $this->attributeRepository->scopeQuery(fn ($query) => $query->whereIn('code', array_keys($rowData))->where('entity_type', $entityType))->get(); + + foreach ($attributes as $attribute) { + if ($entityType == 'persons') { + $attribute->code = 'person.'.$attribute->code; + } + + $validations = []; + + if ($attribute->type == 'boolean') { + continue; + } elseif ($attribute->type == 'address') { + if (! $attribute->is_required) { + continue; + } + + $validations = [ + $attribute->code.'.address' => 'required', + $attribute->code.'.country' => 'required', + $attribute->code.'.state' => 'required', + $attribute->code.'.city' => 'required', + $attribute->code.'.postcode' => 'required', + ]; + } elseif ($attribute->type == 'email') { + $validations = [ + $attribute->code => [$attribute->is_required ? 'required' : 'nullable'], + $attribute->code.'.*.value' => [$attribute->is_required ? 'required' : 'nullable', 'email'], + $attribute->code.'.*.label' => $attribute->is_required ? 'required' : 'nullable', + ]; + } elseif ($attribute->type == 'phone') { + $validations = [ + $attribute->code => [$attribute->is_required ? 'required' : 'nullable'], + $attribute->code.'.*.value' => [$attribute->is_required ? 'required' : 'nullable'], + $attribute->code.'.*.label' => $attribute->is_required ? 'required' : 'nullable', + ]; + } else { + $validations[$attribute->code] = [$attribute->is_required ? 'required' : 'nullable']; + + if ($attribute->type == 'text' && $attribute->validation) { + array_push($validations[$attribute->code], + $attribute->validation == 'decimal' + ? new Decimal + : $attribute->validation + ); + } + + if ($attribute->type == 'price') { + array_push($validations[$attribute->code], new Decimal); + } + } + + if ($attribute->is_unique) { + array_push($validations[in_array($attribute->type, ['email', 'phone']) + ? $attribute->code.'.*.value' + : $attribute->code + ], function ($field, $value, $fail) use ($attribute) { + if (! $this->attributeValueRepository->isValueUnique( + null, + $attribute->entity_type, + $attribute, + request($field) + ) + ) { + $fail(trans('data_transfer::app.validation.errors.already-exists', ['attribute' => $attribute->name])); + } + }); + } + + $rules = [ + ...$rules, + ...$validations, + ]; + } + } + + return $rules; + } + + /** + * Start the import process. + */ + public function importBatch(ImportBatchContract $batch): bool + { + Event::dispatch('data_transfer.imports.batch.import.before', $batch); + + if ($batch->import->action == Import::ACTION_DELETE) { + $this->deleteLeads($batch); + } else { + $this->saveLeads($batch); + } + + /** + * Update import batch summary. + */ + $batch = $this->importBatchRepository->update([ + 'state' => Import::STATE_PROCESSED, + + 'summary' => [ + 'created' => $this->getCreatedItemsCount(), + 'updated' => $this->getUpdatedItemsCount(), + 'deleted' => $this->getDeletedItemsCount(), + ], + ], $batch->id); + + Event::dispatch('data_transfer.imports.batch.import.after', $batch); + + return true; + } + + /** + * Start the products linking process + */ + public function linkBatch(ImportBatchContract $batch): bool + { + Event::dispatch('data_transfer.imports.batch.linking.before', $batch); + + /** + * Load leads storage with batch ids. + */ + $this->leadsStorage->load(Arr::pluck($batch->data, 'title')); + + $products = []; + + foreach ($batch->data as $rowData) { + /** + * Prepare products. + */ + $this->prepareProducts($rowData, $products); + } + + $this->saveProducts($products); + + /** + * Update import batch summary + */ + $this->importBatchRepository->update([ + 'state' => Import::STATE_LINKED, + ], $batch->id); + + Event::dispatch('data_transfer.imports.batch.linking.after', $batch); + + return true; + } + + /** + * Prepare products. + */ + public function prepareProducts($rowData, &$product): void + { + if (! empty($rowData['product'])) { + $product[$rowData['title']] = $this->parseProducts($rowData['product']); + } + } + + /** + * Save products. + */ + public function saveProducts(array $products): void + { + $leadProducts = []; + + foreach ($products as $title => $product) { + $lead = $this->leadsStorage->get($title); + + $leadProducts['insert'][] = [ + 'lead_id' => $lead['id'], + 'product_id' => $product['id'], + 'price' => $product['price'], + 'quantity' => $product['quantity'], + 'amount' => $product['amount'], + ]; + } + + foreach ($leadProducts['insert'] as $key => $leadProduct) { + $this->leadProductRepository->deleteWhere([ + 'lead_id' => $leadProduct['lead_id'], + 'product_id' => $leadProduct['product_id'], + ]); + } + + $this->leadProductRepository->upsert($leadProducts['insert'], ['lead_id', 'product_id']); + } + + /** + * Delete leads from current batch. + */ + protected function deleteLeads(ImportBatchContract $batch): bool + { + /** + * Load leads storage with batch ids. + */ + $this->leadsStorage->load(Arr::pluck($batch->data, 'title')); + + $idsToDelete = []; + + foreach ($batch->data as $rowData) { + if (! $this->isTitleExist($rowData['title'])) { + continue; + } + + $idsToDelete[] = $this->leadsStorage->get($rowData['title']); + } + + $idsToDelete = array_unique($idsToDelete); + + $this->deletedItemsCount = count($idsToDelete); + + $this->leadRepository->deleteWhere([['id', 'IN', $idsToDelete]]); + + return true; + } + + /** + * Save leads from current batch. + */ + protected function saveLeads(ImportBatchContract $batch): bool + { + /** + * Load lead storage with batch unique title. + */ + $this->leadsStorage->load(Arr::pluck($batch->data, 'title')); + + $leads = []; + + /** + * Prepare leads for import. + */ + foreach ($batch->data as $rowData) { + if (isset($rowData['id'])) { + $leads['update'][$rowData['id']] = Arr::except($rowData, ['product']); + } else { + $leads['insert'][$rowData['title']] = [ + ...Arr::except($rowData, ['id', 'product']), + 'created_at' => $rowData['created_at'] ?? now(), + 'updated_at' => $rowData['updated_at'] ?? now(), + ]; + } + } + + if (! empty($leads['update'])) { + $this->updatedItemsCount += count($leads['update']); + + $this->leadRepository->upsert( + $leads['update'], + $this->masterAttributeCode + ); + } + + if (! empty($leads['insert'])) { + $this->createdItemsCount += count($leads['insert']); + + $this->leadRepository->insert($leads['insert']); + + /** + * Update the sku storage with newly created products + */ + $newLeads = $this->leadRepository->findWhereIn( + 'title', + array_keys($leads['insert']), + [ + 'id', + 'title', + ] + ); + + foreach ($newLeads as $lead) { + $this->leadsStorage->set($lead->title, [ + 'id' => $lead->id, + 'title' => $lead->title, + ]); + } + } + + return true; + } + + /** + * Check if title exists. + */ + public function isTitleExist(string $title): bool + { + return $this->leadsStorage->has($title); + } + + /** + * Prepare row data to save into the database. + */ + protected function prepareRowForDb(array $rowData): array + { + return parent::prepareRowForDb($rowData); + } +} diff --git a/packages/Webkul/DataTransfer/src/Helpers/Importers/Leads/Storage.php b/packages/Webkul/DataTransfer/src/Helpers/Importers/Leads/Storage.php new file mode 100644 index 000000000..f9d657d0d --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Helpers/Importers/Leads/Storage.php @@ -0,0 +1,97 @@ +items = []; + + $this->load(); + } + + /** + * Load the leads. + */ + public function load(array $titles = []): void + { + if (empty($titles)) { + $leads = $this->leadRepository->all($this->selectColumns); + } else { + $leads = $this->leadRepository->findWhereIn('title', $titles, $this->selectColumns); + } + + foreach ($leads as $lead) { + $this->set($lead->title, [ + 'id' => $lead->id, + 'title' => $lead->title, + ]); + } + } + + /** + * Get Ids and Unique Id. + */ + public function set(string $title, array $data): self + { + $this->items[$title] = $data; + + return $this; + } + + /** + * Check if unique id exists. + */ + public function has(string $title): bool + { + return isset($this->items[$title]); + } + + /** + * Get unique id information. + */ + public function get(string $title): ?array + { + if (! $this->has($title)) { + return null; + } + + return $this->items[$title]; + } + + public function getItems(): array + { + return $this->items; + } + + /** + * Is storage is empty. + */ + public function isEmpty(): bool + { + return empty($this->items); + } +} diff --git a/packages/Webkul/DataTransfer/src/Helpers/Importers/Persons/Importer.php b/packages/Webkul/DataTransfer/src/Helpers/Importers/Persons/Importer.php new file mode 100644 index 000000000..4896af480 --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Helpers/Importers/Persons/Importer.php @@ -0,0 +1,391 @@ + 'data_transfer::app.importers.persons.validation.errors.email-not-found', + self::ERROR_DUPLICATE_EMAIL => 'data_transfer::app.importers.persons.validation.errors.duplicate-email', + self::ERROR_DUPLICATE_PHONE => 'data_transfer::app.importers.persons.validation.errors.duplicate-phone', + ]; + + /** + * Permanent entity columns. + * + * @var string[] + */ + protected $permanentAttributes = ['emails']; + + /** + * Permanent entity column. + */ + protected string $masterAttributeCode = 'unique_id'; + + /** + * Emails storage. + */ + protected array $emails = []; + + /** + * Phones storage. + */ + protected array $phones = []; + + /** + * Create a new helper instance. + * + * @return void + */ + public function __construct( + protected ImportBatchRepository $importBatchRepository, + protected PersonRepository $personRepository, + protected AttributeRepository $attributeRepository, + protected AttributeValueRepository $attributeValueRepository, + protected Storage $personStorage, + ) { + parent::__construct( + $importBatchRepository, + $attributeRepository, + $attributeValueRepository, + ); + } + + /** + * Initialize Product error templates. + */ + protected function initErrorMessages(): void + { + foreach ($this->messages as $errorCode => $message) { + $this->errorHelper->addErrorMessage($errorCode, trans($message)); + } + + parent::initErrorMessages(); + } + + /** + * Validate data. + */ + public function validateData(): void + { + $this->personStorage->init(); + + parent::validateData(); + } + + /** + * Validates row. + */ + public function validateRow(array $rowData, int $rowNumber): bool + { + $rowData = $this->parsedRowData($rowData); + + /** + * If row is already validated than no need for further validation. + */ + if (isset($this->validatedRows[$rowNumber])) { + return ! $this->errorHelper->isRowInvalid($rowNumber); + } + + $this->validatedRows[$rowNumber] = true; + + /** + * If import action is delete than no need for further validation. + */ + if ($this->import->action == Import::ACTION_DELETE) { + foreach ($rowData['emails'] as $email) { + if (! $this->isEmailExist($email['value'])) { + $this->skipRow($rowNumber, self::ERROR_EMAIL_NOT_FOUND_FOR_DELETE, 'email'); + + return false; + } + + return true; + } + } + + /** + * Validate row data. + */ + $validator = Validator::make($rowData, [ + ...$this->getValidationRules('persons', $rowData), + 'organization_id' => 'required|exists:organizations,id', + 'user_id' => 'required|exists:users,id', + 'contact_numbers' => 'required|array', + 'contact_numbers.*.value' => 'required|numeric', + 'contact_numbers.*.label' => 'required|in:home,work', + 'emails' => 'required|array', + 'emails.*.value' => 'required|email', + 'emails.*.label' => 'required|in:home,work', + ]); + + if ($validator->fails()) { + $failedAttributes = $validator->failed(); + + foreach ($validator->errors()->getMessages() as $attributeCode => $message) { + $errorCode = array_key_first($failedAttributes[$attributeCode] ?? []); + + $this->skipRow($rowNumber, $errorCode, $attributeCode, current($message)); + } + } + + /** + * Check if email is unique. + */ + if (! empty($emails = $rowData['emails'])) { + foreach ($emails as $email) { + if (! in_array($email['value'], $this->emails)) { + $this->emails[] = $email['value']; + } else { + $message = sprintf( + trans($this->messages[self::ERROR_DUPLICATE_EMAIL]), + $email['value'] + ); + + $this->skipRow($rowNumber, self::ERROR_DUPLICATE_EMAIL, 'email', $message); + } + } + } + + /** + * Check if phone(s) are unique. + */ + if (! empty($rowData['contact_numbers'])) { + foreach ($rowData['contact_numbers'] as $phone) { + if (! in_array($phone['value'], $this->phones)) { + if (! empty($phone['value'])) { + $this->phones[] = $phone['value']; + } + } else { + $message = sprintf( + trans($this->messages[self::ERROR_DUPLICATE_PHONE]), + $phone['value'] + ); + + $this->skipRow($rowNumber, self::ERROR_DUPLICATE_PHONE, 'phone', $message); + } + } + } + + return ! $this->errorHelper->isRowInvalid($rowNumber); + } + + /** + * Start the import process. + */ + public function importBatch(ImportBatchContract $batch): bool + { + Event::dispatch('data_transfer.imports.batch.import.before', $batch); + + if ($batch->import->action == Import::ACTION_DELETE) { + $this->deletePersons($batch); + } else { + $this->savePersonData($batch); + } + + /** + * Update import batch summary. + */ + $batch = $this->importBatchRepository->update([ + 'state' => Import::STATE_PROCESSED, + + 'summary' => [ + 'created' => $this->getCreatedItemsCount(), + 'updated' => $this->getUpdatedItemsCount(), + 'deleted' => $this->getDeletedItemsCount(), + ], + ], $batch->id); + + Event::dispatch('data_transfer.imports.batch.import.after', $batch); + + return true; + } + + /** + * Delete persons from current batch. + */ + protected function deletePersons(ImportBatchContract $batch): bool + { + /** + * Load person storage with batch emails. + */ + $emails = collect(Arr::pluck($batch->data, 'emails')) + ->map(function ($emails) { + $emails = json_decode($emails, true); + + foreach ($emails as $email) { + return $email['value']; + } + }); + + $this->personStorage->load($emails->toArray()); + + $idsToDelete = []; + + foreach ($batch->data as $rowData) { + $rowData = $this->parsedRowData($rowData); + + foreach ($rowData['emails'] as $email) { + if (! $this->isEmailExist($email['value'])) { + continue; + } + + $idsToDelete[] = $this->personStorage->get($email['value']); + } + } + + $idsToDelete = array_unique($idsToDelete); + + $this->deletedItemsCount = count($idsToDelete); + + $this->personRepository->deleteWhere([['id', 'IN', $idsToDelete]]); + + return true; + } + + /** + * Save person from current batch. + */ + protected function savePersonData(ImportBatchContract $batch): bool + { + /** + * Load person storage with batch email. + */ + $emails = collect(Arr::pluck($batch->data, 'emails')) + ->map(function ($emails) { + $emails = json_decode($emails, true); + + foreach ($emails as $email) { + return $email['value']; + } + }); + + $this->personStorage->load($emails->toArray()); + + $persons = []; + + /** + * Prepare persons for import. + */ + foreach ($batch->data as $rowData) { + $this->preparePersons($rowData, $persons); + } + + $this->savePersons($persons); + + return true; + } + + /** + * Prepare persons from current batch. + */ + public function preparePersons(array $rowData, array &$persons): void + { + $emails = collect($rowData['emails']) + ->map(function ($emails) { + $emails = json_decode($emails, true); + + foreach ($emails as $email) { + return $email['value']; + } + }); + + foreach ($emails as $email) { + $contactNumber = json_decode($rowData['contact_numbers'], true); + + $rowData['unique_id'] = "{$rowData['user_id']}|{$rowData['organization_id']}|{$email}|{$contactNumber[0]['value']}"; + + if ($this->isEmailExist($email)) { + $persons['update'][$email] = $rowData; + } else { + $persons['insert'][$email] = [ + ...$rowData, + 'created_at' => $rowData['created_at'] ?? now(), + 'updated_at' => $rowData['updated_at'] ?? now(), + ]; + } + } + } + + /** + * Save persons from current batch. + */ + public function savePersons(array $persons): void + { + if (! empty($persons['update'])) { + $this->updatedItemsCount += count($persons['update']); + + $this->personRepository->upsert( + $persons['update'], + $this->masterAttributeCode, + ); + } + + if (! empty($persons['insert'])) { + $this->createdItemsCount += count($persons['insert']); + + $this->personRepository->insert($persons['insert']); + } + } + + /** + * Check if email exists. + */ + public function isEmailExist(string $email): bool + { + return $this->personStorage->has($email); + } + + /** + * Get parsed email and phone. + */ + private function parsedRowData(array $rowData): array + { + $rowData['emails'] = json_decode($rowData['emails'], true); + + $rowData['contact_numbers'] = json_decode($rowData['contact_numbers'], true); + + return $rowData; + } +} diff --git a/packages/Webkul/DataTransfer/src/Helpers/Importers/Persons/Storage.php b/packages/Webkul/DataTransfer/src/Helpers/Importers/Persons/Storage.php new file mode 100644 index 000000000..f18761b96 --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Helpers/Importers/Persons/Storage.php @@ -0,0 +1,99 @@ +items = []; + + $this->load(); + } + + /** + * Load the Emails. + */ + public function load(array $emails = []): void + { + if (empty($emails)) { + $persons = $this->personRepository->all($this->selectColumns); + } else { + $persons = $this->personRepository->scopeQuery(function ($query) use ($emails) { + return $query->where(function ($subQuery) use ($emails) { + foreach ($emails as $email) { + $subQuery->orWhereJsonContains('emails', ['value' => $email]); + } + }); + })->all($this->selectColumns); + } + + $persons->each(function ($person) { + collect($person->emails) + ->each(fn ($email) => $this->set($email['value'], $person->id)); + }); + } + + /** + * Get email information. + */ + public function set(string $email, int $id): self + { + $this->items[$email] = $id; + + return $this; + } + + /** + * Check if email exists. + */ + public function has(string $email): bool + { + return isset($this->items[$email]); + } + + /** + * Get email information. + */ + public function get(string $email): ?int + { + if (! $this->has($email)) { + return null; + } + + return $this->items[$email]; + } + + /** + * Is storage is empty. + */ + public function isEmpty(): int + { + return empty($this->items); + } +} diff --git a/packages/Webkul/DataTransfer/src/Helpers/Importers/Products/Importer.php b/packages/Webkul/DataTransfer/src/Helpers/Importers/Products/Importer.php new file mode 100644 index 000000000..9048bea8b --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Helpers/Importers/Products/Importer.php @@ -0,0 +1,369 @@ + 'data_transfer::app.importers.products.validation.errors.sku-not-found', + ]; + + /** + * Permanent entity columns. + */ + protected array $permanentAttributes = ['sku']; + + /** + * Permanent entity column. + */ + protected string $masterAttributeCode = 'sku'; + + /** + * Cached attributes. + */ + protected mixed $attributes = []; + + /** + * Valid csv columns. + */ + protected array $validColumnNames = [ + 'sku', + 'name', + 'description', + 'quantity', + 'price', + ]; + + /** + * Create a new helper instance. + * + * @return void + */ + public function __construct( + protected ImportBatchRepository $importBatchRepository, + protected AttributeRepository $attributeRepository, + protected AttributeOptionRepository $attributeOptionRepository, + protected ProductRepository $productRepository, + protected ProductInventoryRepository $productInventoryRepository, + protected AttributeValueRepository $attributeValueRepository, + protected SKUStorage $skuStorage + ) { + parent::__construct( + $importBatchRepository, + $attributeRepository, + $attributeValueRepository + ); + + $this->initAttributes(); + } + + /** + * Load all attributes and families to use later. + */ + protected function initAttributes(): void + { + $this->attributes = $this->attributeRepository->all(); + + foreach ($this->attributes as $attribute) { + $this->validColumnNames[] = $attribute->code; + } + } + + /** + * Initialize Product error templates. + */ + protected function initErrorMessages(): void + { + foreach ($this->messages as $errorCode => $message) { + $this->errorHelper->addErrorMessage($errorCode, trans($message)); + } + + parent::initErrorMessages(); + } + + /** + * Save validated batches. + */ + protected function saveValidatedBatches(): self + { + $source = $this->getSource(); + + $source->rewind(); + + $this->skuStorage->init(); + + while ($source->valid()) { + try { + $rowData = $source->current(); + } catch (\InvalidArgumentException $e) { + $source->next(); + + continue; + } + + $this->validateRow($rowData, $source->getCurrentRowNumber()); + + $source->next(); + } + + parent::saveValidatedBatches(); + + return $this; + } + + /** + * Validates row. + */ + public function validateRow(array $rowData, int $rowNumber): bool + { + /** + * If row is already validated than no need for further validation. + */ + if (isset($this->validatedRows[$rowNumber])) { + return ! $this->errorHelper->isRowInvalid($rowNumber); + } + + $this->validatedRows[$rowNumber] = true; + + /** + * If import action is delete than no need for further validation. + */ + if ($this->import->action == Import::ACTION_DELETE) { + if (! $this->isSKUExist($rowData['sku'])) { + $this->skipRow($rowNumber, self::ERROR_SKU_NOT_FOUND_FOR_DELETE, 'sku'); + + return false; + } + + return true; + } + + /** + * Validate product attributes + */ + $validator = Validator::make($rowData, $this->getValidationRules('products', $rowData)); + + if ($validator->fails()) { + foreach ($validator->errors()->getMessages() as $attributeCode => $message) { + $failedAttributes = $validator->failed(); + + $errorCode = array_key_first($failedAttributes[$attributeCode] ?? []); + + $this->skipRow($rowNumber, $errorCode, $attributeCode, current($message)); + } + } + + return ! $this->errorHelper->isRowInvalid($rowNumber); + } + + /** + * Start the import process. + */ + public function importBatch(ImportBatchContract $batch): bool + { + Event::dispatch('data_transfer.imports.batch.import.before', $batch); + + if ($batch->import->action == Import::ACTION_DELETE) { + $this->deleteProducts($batch); + } else { + $this->saveProductsData($batch); + } + + /** + * Update import batch summary. + */ + $batch = $this->importBatchRepository->update([ + 'state' => Import::STATE_PROCESSED, + + 'summary' => [ + 'created' => $this->getCreatedItemsCount(), + 'updated' => $this->getUpdatedItemsCount(), + 'deleted' => $this->getDeletedItemsCount(), + ], + ], $batch->id); + + Event::dispatch('data_transfer.imports.batch.import.after', $batch); + + return true; + } + + /** + * Delete products from current batch. + */ + protected function deleteProducts(ImportBatchContract $batch): bool + { + /** + * Load SKU storage with batch skus. + */ + $this->skuStorage->load(Arr::pluck($batch->data, 'sku')); + + $idsToDelete = []; + + foreach ($batch->data as $rowData) { + if (! $this->isSKUExist($rowData['sku'])) { + continue; + } + + $product = $this->skuStorage->get($rowData['sku']); + + $idsToDelete[] = $product['id']; + } + + $idsToDelete = array_unique($idsToDelete); + + $this->deletedItemsCount = count($idsToDelete); + + $this->productRepository->deleteWhere([['id', 'IN', $idsToDelete]]); + + return true; + } + + /** + * Save products from current batch. + */ + protected function saveProductsData(ImportBatchContract $batch): bool + { + /** + * Load SKU storage with batch skus. + */ + $this->skuStorage->load(Arr::pluck($batch->data, 'sku')); + + $products = []; + + /** + * Prepare products for import. + */ + foreach ($batch->data as $rowData) { + $this->prepareProducts($rowData, $products); + } + + $this->saveProducts($products); + + return true; + } + + /** + * Prepare products from current batch. + */ + public function prepareProducts(array $rowData, array &$products): void + { + if ($this->isSKUExist($rowData['sku'])) { + $products['update'][$rowData['sku']] = $rowData; + } else { + $products['insert'][$rowData['sku']] = [ + ...$rowData, + 'created_at' => $rowData['created_at'] ?? now(), + 'updated_at' => $rowData['updated_at'] ?? now(), + ]; + } + } + + /** + * Save products from current batch. + */ + public function saveProducts(array $products): void + { + if (! empty($products['update'])) { + $this->updatedItemsCount += count($products['update']); + + $this->productRepository->upsert( + $products['update'], + $this->masterAttributeCode + ); + } + + if (! empty($products['insert'])) { + $this->createdItemsCount += count($products['insert']); + + $this->productRepository->insert($products['insert']); + } + } + + /** + * Save channels from current batch. + */ + public function saveChannels(array $channels): void + { + $productChannels = []; + + foreach ($channels as $sku => $channelIds) { + $product = $this->skuStorage->get($sku); + + foreach (array_unique($channelIds) as $channelId) { + $productChannels[] = [ + 'product_id' => $product['id'], + 'channel_id' => $channelId, + ]; + } + } + + DB::table('product_channels')->upsert( + $productChannels, + [ + 'product_id', + 'channel_id', + ], + ); + } + + /** + * Save links. + */ + public function loadUnloadedSKUs(array $skus): void + { + $notLoadedSkus = []; + + foreach ($skus as $sku) { + if ($this->skuStorage->has($sku)) { + continue; + } + + $notLoadedSkus[] = $sku; + } + + /** + * Load not loaded SKUs to the sku storage. + */ + if (! empty($notLoadedSkus)) { + $this->skuStorage->load($notLoadedSkus); + } + } + + /** + * Check if SKU exists. + */ + public function isSKUExist(string $sku): bool + { + return $this->skuStorage->has($sku); + } + + /** + * Prepare row data to save into the database. + */ + protected function prepareRowForDb(array $rowData): array + { + return parent::prepareRowForDb($rowData); + } +} diff --git a/packages/Webkul/DataTransfer/src/Helpers/Importers/Products/SKUStorage.php b/packages/Webkul/DataTransfer/src/Helpers/Importers/Products/SKUStorage.php new file mode 100644 index 000000000..792d0c0d4 --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Helpers/Importers/Products/SKUStorage.php @@ -0,0 +1,107 @@ +items = []; + + $this->load(); + } + + /** + * Load the SKU. + */ + public function load(array $skus = []): void + { + if (empty($skus)) { + $products = $this->productRepository->all($this->selectColumns); + } else { + $products = $this->productRepository->findWhereIn('sku', $skus, $this->selectColumns); + } + + foreach ($products as $product) { + $this->set($product->sku, [ + 'id' => $product->id, + 'sku' => $product->sku, + ]); + } + } + + /** + * Get SKU information. + */ + public function set(string $sku, array $data): self + { + $this->items[$sku] = implode(self::DELIMITER, [ + $data['id'], + $data['sku'], + ]); + + return $this; + } + + /** + * Check if SKU exists. + */ + public function has(string $sku): bool + { + return isset($this->items[$sku]); + } + + /** + * Get SKU information. + */ + public function get(string $sku): ?array + { + if (! $this->has($sku)) { + return null; + } + + $data = explode(self::DELIMITER, $this->items[$sku]); + + return [ + 'id' => $data[0], + ]; + } + + /** + * Is storage is empty. + */ + public function isEmpty(): int + { + return empty($this->items); + } +} diff --git a/packages/Webkul/DataTransfer/src/Helpers/Sources/AbstractSource.php b/packages/Webkul/DataTransfer/src/Helpers/Sources/AbstractSource.php new file mode 100644 index 000000000..6d4689da7 --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Helpers/Sources/AbstractSource.php @@ -0,0 +1,120 @@ +currentRowNumber; + } + + /** + * Checks if current position is valid. + */ + public function valid(): bool + { + return $this->currentRowNumber !== -1; + } + + /** + * Read next line from source. + */ + public function current(): array + { + $row = $this->currentRowData; + + if (count($row) != $this->totalColumns) { + if ($this->foundWrongQuoteFlag) { + throw new \InvalidArgumentException(AbstractImporter::ERROR_CODE_WRONG_QUOTES); + } else { + throw new \InvalidArgumentException(AbstractImporter::ERROR_CODE_COLUMNS_NUMBER); + } + } + + return array_combine($this->columnNames, $row); + } + + /** + * Read next line from source. + */ + public function next(): void + { + $this->currentRowNumber++; + + $row = $this->getNextRow(); + + if ($row === false || $row === []) { + $this->currentRowData = []; + + $this->currentRowNumber = -1; + } else { + $this->currentRowData = $row; + } + } + + /** + * Rewind the iterator to the first row. + */ + public function rewind(): void + { + $this->currentRowNumber = 0; + + $this->currentRowData = []; + + $this->getNextRow(); + + $this->next(); + } + + /** + * Column names getter. + */ + public function getColumnNames(): array + { + return $this->columnNames; + } + + /** + * Column names getter. + */ + public function getTotalColumns(): int + { + return count($this->columnNames); + } +} diff --git a/packages/Webkul/DataTransfer/src/Helpers/Sources/CSV.php b/packages/Webkul/DataTransfer/src/Helpers/Sources/CSV.php new file mode 100644 index 000000000..eee5e88f2 --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Helpers/Sources/CSV.php @@ -0,0 +1,79 @@ +reader = fopen(Storage::disk('public')->path($filePath), 'r'); + + $this->columnNames = fgetcsv($this->reader, 4096, $delimiter); + + $this->totalColumns = count($this->columnNames); + } catch (\Exception $e) { + throw new \LogicException("Unable to open file: '{$filePath}'"); + } + } + + /** + * Close file handle. + * + * @return void + */ + public function __destruct() + { + if (! is_object($this->reader)) { + return; + } + + $this->reader->close(); + } + + /** + * Read next line from csv. + */ + protected function getNextRow(): array + { + $parsed = fgetcsv($this->reader, 4096, $this->delimiter); + + if (is_array($parsed) && count($parsed) != $this->totalColumns) { + foreach ($parsed as $element) { + if ($element && strpos($element, "'") !== false) { + $this->foundWrongQuoteFlag = true; + + break; + } + } + } else { + $this->foundWrongQuoteFlag = false; + } + + return is_array($parsed) ? $parsed : []; + } + + /** + * Rewind the iterator to the first row. + */ + public function rewind(): void + { + rewind($this->reader); + + parent::rewind(); + } +} diff --git a/packages/Webkul/DataTransfer/src/Helpers/Sources/Excel.php b/packages/Webkul/DataTransfer/src/Helpers/Sources/Excel.php new file mode 100644 index 000000000..1d9e66a52 --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Helpers/Sources/Excel.php @@ -0,0 +1,70 @@ +path($filePath)); + + $this->reader = $factory->getActiveSheet(); + + $highestColumn = $this->reader->getHighestColumn(); + + $this->totalColumns = Coordinate::columnIndexFromString($highestColumn); + + $this->columnNames = $this->getNextRow(); + } catch (\Exception $e) { + throw new \LogicException("Unable to open file: '{$filePath}'"); + } + } + + /** + * Read next line from csv. + */ + protected function getNextRow(): array|bool + { + for ($column = 1; $column <= $this->totalColumns; $column++) { + $rowData[] = $this->reader->getCellByColumnAndRow($column, $this->currentRowNumber)->getValue(); + } + + $filteredRowData = array_filter($rowData); + + if (empty($filteredRowData)) { + return false; + } + + return $rowData; + } + + /** + * Rewind the iterator to the first row. + */ + public function rewind(): void + { + $this->currentRowNumber = 1; + + $this->next(); + } +} diff --git a/packages/Webkul/DataTransfer/src/Jobs/Import/Completed.php b/packages/Webkul/DataTransfer/src/Jobs/Import/Completed.php new file mode 100644 index 000000000..75f466d50 --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Jobs/Import/Completed.php @@ -0,0 +1,38 @@ +import = $import; + } + + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + app(ImportHelper::class) + ->setImport($this->import) + ->completed(); + } +} diff --git a/packages/Webkul/DataTransfer/src/Jobs/Import/ImportBatch.php b/packages/Webkul/DataTransfer/src/Jobs/Import/ImportBatch.php new file mode 100644 index 000000000..595dcc749 --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Jobs/Import/ImportBatch.php @@ -0,0 +1,41 @@ +importBatch = $importBatch; + } + + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + $typeImported = app(ImportHelper::class) + ->setImport($this->importBatch->import) + ->getTypeImporter(); + + $typeImported->importBatch($this->importBatch); + } +} diff --git a/packages/Webkul/DataTransfer/src/Jobs/Import/IndexBatch.php b/packages/Webkul/DataTransfer/src/Jobs/Import/IndexBatch.php new file mode 100644 index 000000000..971893b81 --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Jobs/Import/IndexBatch.php @@ -0,0 +1,41 @@ +importBatch = $importBatch; + } + + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + $typeImported = app(ImportHelper::class) + ->setImport($this->importBatch->import) + ->getTypeImporter(); + + $typeImported->indexBatch($this->importBatch); + } +} diff --git a/packages/Webkul/DataTransfer/src/Jobs/Import/Indexing.php b/packages/Webkul/DataTransfer/src/Jobs/Import/Indexing.php new file mode 100644 index 000000000..b4ed9aa01 --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Jobs/Import/Indexing.php @@ -0,0 +1,38 @@ +import = $import; + } + + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + app(ImportHelper::class) + ->setImport($this->import) + ->indexing(); + } +} diff --git a/packages/Webkul/DataTransfer/src/Jobs/Import/LinkBatch.php b/packages/Webkul/DataTransfer/src/Jobs/Import/LinkBatch.php new file mode 100644 index 000000000..c02f2cd01 --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Jobs/Import/LinkBatch.php @@ -0,0 +1,41 @@ +importBatch = $importBatch; + } + + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + $typeImported = app(ImportHelper::class) + ->setImport($this->importBatch->import) + ->getTypeImporter(); + + $typeImported->linkBatch($this->importBatch); + } +} diff --git a/packages/Webkul/DataTransfer/src/Jobs/Import/Linking.php b/packages/Webkul/DataTransfer/src/Jobs/Import/Linking.php new file mode 100644 index 000000000..e826cf228 --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Jobs/Import/Linking.php @@ -0,0 +1,38 @@ +import = $import; + } + + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + app(ImportHelper::class) + ->setImport($this->import) + ->linking(); + } +} diff --git a/packages/Webkul/DataTransfer/src/Models/Import.php b/packages/Webkul/DataTransfer/src/Models/Import.php new file mode 100755 index 000000000..7d5521aba --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Models/Import.php @@ -0,0 +1,55 @@ + 'array', + 'errors' => 'array', + 'started_at' => 'datetime', + 'completed_at' => 'datetime', + ]; + + /** + * Get the options. + */ + public function batches(): HasMany + { + return $this->hasMany(ImportBatchProxy::modelClass()); + } +} diff --git a/packages/Webkul/DataTransfer/src/Models/ImportBatch.php b/packages/Webkul/DataTransfer/src/Models/ImportBatch.php new file mode 100755 index 000000000..da31c34fa --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Models/ImportBatch.php @@ -0,0 +1,48 @@ + 'array', + 'data' => 'array', + ]; + + /** + * Get the import that owns the import batch. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function import() + { + return $this->belongsTo(ImportProxy::modelClass()); + } +} diff --git a/packages/Webkul/DataTransfer/src/Models/ImportBatchProxy.php b/packages/Webkul/DataTransfer/src/Models/ImportBatchProxy.php new file mode 100644 index 000000000..47b0988a9 --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Models/ImportBatchProxy.php @@ -0,0 +1,7 @@ +loadTranslationsFrom(__DIR__.'/../Resources/lang', 'data_transfer'); + + $this->loadMigrationsFrom(__DIR__.'/../Database/Migrations'); + } + + /** + * Register any application services. + */ + public function register(): void + { + $this->mergeConfigFrom(dirname(__DIR__).'/Config/importers.php', 'importers'); + } +} diff --git a/packages/Webkul/DataTransfer/src/Providers/ModuleServiceProvider.php b/packages/Webkul/DataTransfer/src/Providers/ModuleServiceProvider.php new file mode 100644 index 000000000..0219650c4 --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Providers/ModuleServiceProvider.php @@ -0,0 +1,18 @@ + [ + 'persons' => [ + 'title' => 'الأشخاص', + + 'validation' => [ + 'errors' => [ + 'duplicate-email' => 'البريد الإلكتروني: \'%s\' تم العثور عليه أكثر من مرة في ملف الاستيراد.', + 'duplicate-phone' => 'الهاتف: \'%s\' تم العثور عليه أكثر من مرة في ملف الاستيراد.', + 'email-not-found' => 'البريد الإلكتروني: \'%s\' لم يتم العثور عليه في النظام.', + ], + ], + ], + + 'products' => [ + 'title' => 'المنتجات', + + 'validation' => [ + 'errors' => [ + 'sku-not-found' => 'المنتج ذو الكود المحدد لم يتم العثور عليه.', + ], + ], + ], + + 'leads' => [ + 'title' => 'العملاء المحتملون', + + 'validation' => [ + 'errors' => [ + 'id-not-found' => 'المعرف: \'%s\' غير موجود في النظام.', + ], + ], + ], + ], + + 'validation' => [ + 'errors' => [ + 'column-empty-headers' => 'الأعمدة رقم "%s" تحتوي على رؤوس فارغة.', + 'column-name-invalid' => 'أسماء الأعمدة غير صالحة: "%s".', + 'column-not-found' => 'الأعمدة المطلوبة غير موجودة: %s.', + 'column-numbers' => 'عدد الأعمدة لا يتوافق مع عدد الصفوف في الرأس.', + 'invalid-attribute' => 'الرأس يحتوي على سمة غير صالحة: "%s".', + 'system' => 'حدث خطأ غير متوقع في النظام.', + 'wrong-quotes' => 'تم استخدام علامات الاقتباس الملتوية بدلاً من الاقتباسات المستقيمة.', + ], + ], +]; diff --git a/packages/Webkul/DataTransfer/src/Resources/lang/en/app.php b/packages/Webkul/DataTransfer/src/Resources/lang/en/app.php new file mode 100644 index 000000000..d226d0507 --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Resources/lang/en/app.php @@ -0,0 +1,50 @@ + [ + 'persons' => [ + 'title' => 'Persons', + + 'validation' => [ + 'errors' => [ + 'duplicate-email' => 'Email : \'%s\' is found more than once in the import file.', + 'duplicate-phone' => 'Phone : \'%s\' is found more than once in the import file.', + 'email-not-found' => 'Email : \'%s\' not found in the system.', + ], + ], + ], + + 'products' => [ + 'title' => 'Products', + + 'validation' => [ + 'errors' => [ + 'sku-not-found' => 'Product with specified SKU not found', + ], + ], + ], + + 'leads' => [ + 'title' => 'Leads', + + 'validation' => [ + 'errors' => [ + 'id-not-found' => 'ID : \'%s\' not found in the system.', + ], + ], + ], + ], + + 'validation' => [ + 'errors' => [ + 'column-empty-headers' => 'Columns number "%s" have empty headers.', + 'column-name-invalid' => 'Invalid column names: "%s".', + 'column-not-found' => 'Required columns not found: %s.', + 'column-numbers' => 'Number of columns does not correspond to the number of rows in the header.', + 'invalid-attribute' => 'Header contains invalid attribute(s): "%s".', + 'system' => 'An unexpected system error occurred.', + 'wrong-quotes' => 'Curly quotes used instead of straight quotes.', + 'already-exists' => 'The :attribute already exists.', + ], + ], +]; diff --git a/packages/Webkul/DataTransfer/src/Resources/lang/es/app.php b/packages/Webkul/DataTransfer/src/Resources/lang/es/app.php new file mode 100644 index 000000000..c4453b5b0 --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Resources/lang/es/app.php @@ -0,0 +1,49 @@ + [ + 'persons' => [ + 'title' => 'Personas', + + 'validation' => [ + 'errors' => [ + 'duplicate-email' => 'Correo electrónico: \'%s\' se encontró más de una vez en el archivo de importación.', + 'duplicate-phone' => 'Teléfono: \'%s\' se encontró más de una vez en el archivo de importación.', + 'email-not-found' => 'Correo electrónico: \'%s\' no se encontró en el sistema.', + ], + ], + ], + + 'products' => [ + 'title' => 'Productos', + + 'validation' => [ + 'errors' => [ + 'sku-not-found' => 'Producto con el SKU especificado no encontrado.', + ], + ], + ], + + 'leads' => [ + 'title' => 'Clientes Potenciales', + + 'validation' => [ + 'errors' => [ + 'id-not-found' => 'ID: \'%s\' no se encuentra en el sistema.', + ], + ], + ], + ], + + 'validation' => [ + 'errors' => [ + 'column-empty-headers' => 'Las columnas número "%s" tienen encabezados vacíos.', + 'column-name-invalid' => 'Nombres de columnas no válidos: "%s".', + 'column-not-found' => 'No se encontraron las columnas requeridas: %s.', + 'column-numbers' => 'El número de columnas no corresponde al número de filas en el encabezado.', + 'invalid-attribute' => 'El encabezado contiene atributos no válidos: "%s".', + 'system' => 'Ocurrió un error inesperado en el sistema.', + 'wrong-quotes' => 'Se usaron comillas curvas en lugar de comillas rectas.', + ], + ], +]; diff --git a/packages/Webkul/DataTransfer/src/Resources/lang/fa/app.php b/packages/Webkul/DataTransfer/src/Resources/lang/fa/app.php new file mode 100644 index 000000000..a3f8562ef --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Resources/lang/fa/app.php @@ -0,0 +1,49 @@ + [ + 'persons' => [ + 'title' => 'افراد', + + 'validation' => [ + 'errors' => [ + 'duplicate-email' => 'ایمیل: \'%s\' بیش از یک بار در فایل واردات یافت شد.', + 'duplicate-phone' => 'تلفن: \'%s\' بیش از یک بار در فایل واردات یافت شد.', + 'email-not-found' => 'ایمیل: \'%s\' در سیستم یافت نشد.', + ], + ], + ], + + 'products' => [ + 'title' => 'محصولات', + + 'validation' => [ + 'errors' => [ + 'sku-not-found' => 'محصول با کد SKU مشخص شده یافت نشد.', + ], + ], + ], + + 'leads' => [ + 'title' => 'سرنخ‌ها', + + 'validation' => [ + 'errors' => [ + 'id-not-found' => 'شناسه: \'%s\' در سیستم یافت نشد.', + ], + ], + ], + ], + + 'validation' => [ + 'errors' => [ + 'column-empty-headers' => 'ستون‌های شماره "%s" دارای سرصفحه‌های خالی هستند.', + 'column-name-invalid' => 'نام‌های ستون نامعتبر: "%s".', + 'column-not-found' => 'ستون‌های مورد نیاز یافت نشد: %s.', + 'column-numbers' => 'تعداد ستون‌ها با تعداد سطرهای سرصفحه مطابقت ندارد.', + 'invalid-attribute' => 'سرصفحه شامل ویژگی‌های نامعتبر است: "%s".', + 'system' => 'خطای غیرمنتظره‌ای در سیستم رخ داد.', + 'wrong-quotes' => 'به جای گیومه‌های مستقیم از گیومه‌های خمیده استفاده شده است.', + ], + ], +]; diff --git a/packages/Webkul/DataTransfer/src/Resources/lang/tr/app.php b/packages/Webkul/DataTransfer/src/Resources/lang/tr/app.php new file mode 100644 index 000000000..31430b408 --- /dev/null +++ b/packages/Webkul/DataTransfer/src/Resources/lang/tr/app.php @@ -0,0 +1,49 @@ + [ + 'persons' => [ + 'title' => 'Kişiler', + + 'validation' => [ + 'errors' => [ + 'duplicate-email' => 'E-posta: \'%s\' içe aktarma dosyasında birden fazla kez bulundu.', + 'duplicate-phone' => 'Telefon: \'%s\' içe aktarma dosyasında birden fazla kez bulundu.', + 'email-not-found' => 'E-posta: \'%s\' sistemde bulunamadı.', + ], + ], + ], + + 'products' => [ + 'title' => 'Ürünler', + + 'validation' => [ + 'errors' => [ + 'sku-not-found' => 'Belirtilen SKU\'ya sahip ürün bulunamadı.', + ], + ], + ], + + 'leads' => [ + 'title' => 'Müşteri Adayları', + + 'validation' => [ + 'errors' => [ + 'id-not-found' => 'ID: \'%s\' sistemde bulunamadı.', + ], + ], + ], + ], + + 'validation' => [ + 'errors' => [ + 'column-empty-headers' => '"%s" numaralı sütunların başlıkları boş.', + 'column-name-invalid' => 'Geçersiz sütun adları: "%s".', + 'column-not-found' => 'Gerekli sütunlar bulunamadı: %s.', + 'column-numbers' => 'Sütun sayısı başlıktaki satır sayısına karşılık gelmiyor.', + 'invalid-attribute' => 'Başlık geçersiz öznitelikler içeriyor: "%s".', + 'system' => 'Beklenmeyen bir sistem hatası oluştu.', + 'wrong-quotes' => 'Doğru olmayan tırnak işaretleri kullanıldı.', + ], + ], +]; diff --git a/public/admin/build/assets/app-116eea9b.js b/public/admin/build/assets/app-116eea9b.js deleted file mode 100644 index 6ff79e0b1..000000000 --- a/public/admin/build/assets/app-116eea9b.js +++ /dev/null @@ -1,77 +0,0 @@ -const My="modulepreload",Iy=function(e,n){return e[0]==="."?new URL(e,n).href:e},If={},Pe=function(n,t,i){if(!t||t.length===0)return n();const r=document.getElementsByTagName("link");return Promise.all(t.map(o=>{if(o=Iy(o,i),o in If)return;If[o]=!0;const s=o.endsWith(".css"),a=s?'[rel="stylesheet"]':"";if(!!i)for(let u=r.length-1;u>=0;u--){const f=r[u];if(f.href===o&&(!s||f.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${o}"]${a}`))return;const c=document.createElement("link");if(c.rel=s?"stylesheet":My,s||(c.as="script",c.crossOrigin=""),c.href=o,document.head.appendChild(c),s)return new Promise((u,f)=>{c.addEventListener("load",u),c.addEventListener("error",()=>f(new Error(`Unable to preload CSS for ${o}`)))})})).then(()=>n()).catch(o=>{const s=new Event("vite:preloadError",{cancelable:!0});if(s.payload=o,window.dispatchEvent(s),!s.defaultPrevented)throw o})};/** -* @vue/shared v3.4.32 -* (c) 2018-present Yuxi (Evan) You and Vue contributors -* @license MIT -**//*! #__NO_SIDE_EFFECTS__ */function jt(e,n){const t=new Set(e.split(","));return n?i=>t.has(i.toLowerCase()):i=>t.has(i)}const Ze={},Gi=[],wt=()=>{},Eo=()=>!1,Ri=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&(e.charCodeAt(2)>122||e.charCodeAt(2)<97),La=e=>e.startsWith("onUpdate:"),Ke=Object.assign,ka=(e,n)=>{const t=e.indexOf(n);t>-1&&e.splice(t,1)},Ny=Object.prototype.hasOwnProperty,ze=(e,n)=>Ny.call(e,n),pe=Array.isArray,Zi=e=>mr(e)==="[object Map]",Li=e=>mr(e)==="[object Set]",dc=e=>mr(e)==="[object Date]",Qh=e=>mr(e)==="[object RegExp]",Ce=e=>typeof e=="function",Me=e=>typeof e=="string",cn=e=>typeof e=="symbol",et=e=>e!==null&&typeof e=="object",Fa=e=>(et(e)||Ce(e))&&Ce(e.then)&&Ce(e.catch),nu=Object.prototype.toString,mr=e=>nu.call(e),qh=e=>mr(e).slice(8,-1),iu=e=>mr(e)==="[object Object]",Va=e=>Me(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,ii=jt(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),ep=jt("bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text,memo"),Ba=e=>{const n=Object.create(null);return t=>n[t]||(n[t]=e(t))},Py=/-(\w)/g,ut=Ba(e=>e.replace(Py,(n,t)=>t?t.toUpperCase():"")),Ry=/\B([A-Z])/g,Yt=Ba(e=>e.replace(Ry,"-$1").toLowerCase()),ki=Ba(e=>e.charAt(0).toUpperCase()+e.slice(1)),Ji=Ba(e=>e?`on${ki(e)}`:""),Mn=(e,n)=>!Object.is(e,n),Qi=(e,...n)=>{for(let t=0;t{Object.defineProperty(e,n,{configurable:!0,enumerable:!1,writable:i,value:t})},Po=e=>{const n=parseFloat(e);return isNaN(n)?e:n},Ro=e=>{const n=Me(e)?Number(e):NaN;return isNaN(n)?e:n};let Nf;const ou=()=>Nf||(Nf=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{}),Ly=/^[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*$/;function ky(e){return Ly.test(e)?`__props.${e}`:`__props[${JSON.stringify(e)}]`}const Fy={TEXT:1,1:"TEXT",CLASS:2,2:"CLASS",STYLE:4,4:"STYLE",PROPS:8,8:"PROPS",FULL_PROPS:16,16:"FULL_PROPS",NEED_HYDRATION:32,32:"NEED_HYDRATION",STABLE_FRAGMENT:64,64:"STABLE_FRAGMENT",KEYED_FRAGMENT:128,128:"KEYED_FRAGMENT",UNKEYED_FRAGMENT:256,256:"UNKEYED_FRAGMENT",NEED_PATCH:512,512:"NEED_PATCH",DYNAMIC_SLOTS:1024,1024:"DYNAMIC_SLOTS",DEV_ROOT_FRAGMENT:2048,2048:"DEV_ROOT_FRAGMENT",HOISTED:-1,"-1":"HOISTED",BAIL:-2,"-2":"BAIL"},su={1:"TEXT",2:"CLASS",4:"STYLE",8:"PROPS",16:"FULL_PROPS",32:"NEED_HYDRATION",64:"STABLE_FRAGMENT",128:"KEYED_FRAGMENT",256:"UNKEYED_FRAGMENT",512:"NEED_PATCH",1024:"DYNAMIC_SLOTS",2048:"DEV_ROOT_FRAGMENT",[-1]:"HOISTED",[-2]:"BAIL"},Vy={ELEMENT:1,1:"ELEMENT",FUNCTIONAL_COMPONENT:2,2:"FUNCTIONAL_COMPONENT",STATEFUL_COMPONENT:4,4:"STATEFUL_COMPONENT",TEXT_CHILDREN:8,8:"TEXT_CHILDREN",ARRAY_CHILDREN:16,16:"ARRAY_CHILDREN",SLOTS_CHILDREN:32,32:"SLOTS_CHILDREN",TELEPORT:64,64:"TELEPORT",SUSPENSE:128,128:"SUSPENSE",COMPONENT_SHOULD_KEEP_ALIVE:256,256:"COMPONENT_SHOULD_KEEP_ALIVE",COMPONENT_KEPT_ALIVE:512,512:"COMPONENT_KEPT_ALIVE",COMPONENT:6,6:"COMPONENT"},By={STABLE:1,1:"STABLE",DYNAMIC:2,2:"DYNAMIC",FORWARDED:3,3:"FORWARDED"},jy={1:"STABLE",2:"DYNAMIC",3:"FORWARDED"},$y="Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,console,Error",au=jt($y),Hy=au,Pf=2;function tp(e,n=0,t=e.length){if(n=Math.max(0,Math.min(n,e.length)),t=Math.max(0,Math.min(t,e.length)),n>t)return"";let i=e.split(/(\r?\n)/);const r=i.filter((a,l)=>l%2===1);i=i.filter((a,l)=>l%2===0);let o=0;const s=[];for(let a=0;a=n){for(let l=a-Pf;l<=a+Pf||t>o;l++){if(l<0||l>=i.length)continue;const c=l+1;s.push(`${c}${" ".repeat(Math.max(3-String(c).length,0))}| ${i[l]}`);const u=i[l].length,f=r[l]&&r[l].length||0;if(l===a){const h=n-(o-(u+f)),p=Math.max(1,t>o?u-h:t-n);s.push(" | "+" ".repeat(h)+"^".repeat(p))}else if(l>a){if(t>o){const h=Math.max(Math.min(t-o,u),1);s.push(" | "+"^".repeat(h))}o+=u+f}}break}return s.join(` -`)}function zr(e){if(pe(e)){const n={};for(let t=0;t{if(t){const i=t.split(Wy);i.length>1&&(n[i[0].trim()]=i[1].trim())}}),n}function zy(e){let n="";if(!e||Me(e))return n;for(const t in e){const i=e[t];if(Me(i)||typeof i=="number"){const r=t.startsWith("--")?t:Yt(t);n+=`${r}:${i};`}}return n}function Kr(e){let n="";if(Me(e))n=e;else if(pe(e))for(let t=0;t/="'\u0009\u000a\u000c\u0020]/,Ml={};function qy(e){if(Ml.hasOwnProperty(e))return Ml[e];const n=Qy.test(e);return n&&console.error(`unsafe attribute name: ${e}`),Ml[e]=!n}const eE={acceptCharset:"accept-charset",className:"class",htmlFor:"for",httpEquiv:"http-equiv"},tE=jt("accept,accept-charset,accesskey,action,align,allow,alt,async,autocapitalize,autocomplete,autofocus,autoplay,background,bgcolor,border,buffered,capture,challenge,charset,checked,cite,class,code,codebase,color,cols,colspan,content,contenteditable,contextmenu,controls,coords,crossorigin,csp,data,datetime,decoding,default,defer,dir,dirname,disabled,download,draggable,dropzone,enctype,enterkeyhint,for,form,formaction,formenctype,formmethod,formnovalidate,formtarget,headers,height,hidden,high,href,hreflang,http-equiv,icon,id,importance,inert,integrity,ismap,itemprop,keytype,kind,label,lang,language,loading,list,loop,low,manifest,max,maxlength,minlength,media,min,multiple,muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,preload,radiogroup,readonly,referrerpolicy,rel,required,reversed,rows,rowspan,sandbox,scope,scoped,selected,shape,size,sizes,slot,span,spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,target,title,translate,type,usemap,value,width,wrap"),nE=jt("xmlns,accent-height,accumulate,additive,alignment-baseline,alphabetic,amplitude,arabic-form,ascent,attributeName,attributeType,azimuth,baseFrequency,baseline-shift,baseProfile,bbox,begin,bias,by,calcMode,cap-height,class,clip,clipPathUnits,clip-path,clip-rule,color,color-interpolation,color-interpolation-filters,color-profile,color-rendering,contentScriptType,contentStyleType,crossorigin,cursor,cx,cy,d,decelerate,descent,diffuseConstant,direction,display,divisor,dominant-baseline,dur,dx,dy,edgeMode,elevation,enable-background,end,exponent,fill,fill-opacity,fill-rule,filter,filterRes,filterUnits,flood-color,flood-opacity,font-family,font-size,font-size-adjust,font-stretch,font-style,font-variant,font-weight,format,from,fr,fx,fy,g1,g2,glyph-name,glyph-orientation-horizontal,glyph-orientation-vertical,glyphRef,gradientTransform,gradientUnits,hanging,height,href,hreflang,horiz-adv-x,horiz-origin-x,id,ideographic,image-rendering,in,in2,intercept,k,k1,k2,k3,k4,kernelMatrix,kernelUnitLength,kerning,keyPoints,keySplines,keyTimes,lang,lengthAdjust,letter-spacing,lighting-color,limitingConeAngle,local,marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mask,maskContentUnits,maskUnits,mathematical,max,media,method,min,mode,name,numOctaves,offset,opacity,operator,order,orient,orientation,origin,overflow,overline-position,overline-thickness,panose-1,paint-order,path,pathLength,patternContentUnits,patternTransform,patternUnits,ping,pointer-events,points,pointsAtX,pointsAtY,pointsAtZ,preserveAlpha,preserveAspectRatio,primitiveUnits,r,radius,referrerPolicy,refX,refY,rel,rendering-intent,repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,result,rotate,rx,ry,scale,seed,shape-rendering,slope,spacing,specularConstant,specularExponent,speed,spreadMethod,startOffset,stdDeviation,stemh,stemv,stitchTiles,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,string,stroke,stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,stroke-width,style,surfaceScale,systemLanguage,tabindex,tableValues,target,targetX,targetY,text-anchor,text-decoration,text-rendering,textLength,to,transform,transform-origin,type,u1,u2,underline-position,underline-thickness,unicode,unicode-bidi,unicode-range,units-per-em,v-alphabetic,v-hanging,v-ideographic,v-mathematical,values,vector-effect,version,vert-adv-y,vert-origin-x,vert-origin-y,viewBox,viewTarget,visibility,width,widths,word-spacing,writing-mode,x,x-height,x1,x2,xChannelSelector,xlink:actuate,xlink:arcrole,xlink:href,xlink:role,xlink:show,xlink:title,xlink:type,xmlns:xlink,xml:base,xml:lang,xml:space,y,y1,y2,yChannelSelector,z,zoomAndPan");function iE(e){if(e==null)return!1;const n=typeof e;return n==="string"||n==="number"||n==="boolean"}const rE=/["'&<>]/;function oE(e){const n=""+e,t=rE.exec(n);if(!t)return n;let i="",r,o,s=0;for(o=t.index;o||--!>|ci(t,n))}const cp=e=>!!(e&&e.__v_isRef===!0),uu=e=>Me(e)?e:e==null?"":pe(e)||et(e)&&(e.toString===nu||!Ce(e.toString))?cp(e)?uu(e.value):JSON.stringify(e,up,2):String(e),up=(e,n)=>cp(n)?up(e,n.value):Zi(n)?{[`Map(${n.size})`]:[...n.entries()].reduce((t,[i,r],o)=>(t[Il(i,o)+" =>"]=r,t),{})}:Li(n)?{[`Set(${n.size})`]:[...n.values()].map(t=>Il(t))}:cn(n)?Il(n):et(n)&&!pe(n)&&!iu(n)?String(n):n,Il=(e,n="")=>{var t;return cn(e)?`Symbol(${(t=e.description)!=null?t:n})`:e},cE=Object.freeze(Object.defineProperty({__proto__:null,EMPTY_ARR:Gi,EMPTY_OBJ:Ze,NO:Eo,NOOP:wt,PatchFlagNames:su,PatchFlags:Fy,ShapeFlags:Vy,SlotFlags:By,camelize:ut,capitalize:ki,def:ru,escapeHtml:oE,escapeHtmlComment:aE,extend:Ke,genPropsAccessExp:ky,generateCodeFrame:tp,getGlobalThis:ou,hasChanged:Mn,hasOwn:ze,hyphenate:Yt,includeBooleanAttr:cu,invokeArrayFns:Qi,isArray:pe,isBooleanAttr:Jy,isBuiltInDirective:ep,isDate:dc,isFunction:Ce,isGloballyAllowed:au,isGloballyWhitelisted:Hy,isHTMLTag:ip,isIntegerKey:Va,isKnownHtmlAttr:tE,isKnownSvgAttr:nE,isMap:Zi,isMathMLTag:op,isModelListener:La,isObject:et,isOn:Ri,isPlainObject:iu,isPromise:Fa,isRegExp:Qh,isRenderableAttrValue:iE,isReservedProp:ii,isSSRSafeAttrName:qy,isSVGTag:rp,isSet:Li,isSpecialBooleanAttr:lp,isString:Me,isSymbol:cn,isVoidTag:sp,looseEqual:ci,looseIndexOf:Zo,looseToNumber:Po,makeMap:jt,normalizeClass:Kr,normalizeProps:np,normalizeStyle:zr,objectToString:nu,parseStringStyle:lu,propsToAttrMap:eE,remove:ka,slotFlagsText:jy,stringifyStyle:zy,toDisplayString:uu,toHandlerKey:Ji,toNumber:Ro,toRawType:qh,toTypeString:mr},Symbol.toStringTag,{value:"Module"}));/** -* @vue/reactivity v3.4.32 -* (c) 2018-present Yuxi (Evan) You and Vue contributors -* @license MIT -**/let gn;class fu{constructor(n=!1){this.detached=n,this._active=!0,this.effects=[],this.cleanups=[],this.parent=gn,!n&&gn&&(this.index=(gn.scopes||(gn.scopes=[])).push(this)-1)}get active(){return this._active}run(n){if(this._active){const t=gn;try{return gn=this,n()}finally{gn=t}}}on(){gn=this}off(){gn=this.parent}stop(n){if(this._active){let t,i;for(t=0,i=this.effects.length;t=4))break}this._dirtyLevel===1&&(this._dirtyLevel=0),Vi()}return this._dirtyLevel>=4}set dirty(n){this._dirtyLevel=n?4:0}run(){if(this._dirtyLevel=0,!this.active)return this.fn();let n=Ai,t=qi;try{return Ai=!0,qi=this,this._runnings++,Rf(this),this.fn()}finally{Lf(this),this._runnings--,qi=t,Ai=n}}stop(){this.active&&(Rf(this),Lf(this),this.onStop&&this.onStop(),this.active=!1)}}function dE(e){return e.value}function Rf(e){e._trackId++,e._depsLength=0}function Lf(e){if(e.deps.length>e._depsLength){for(let n=e._depsLength;n{t.dirty&&t.run()});n&&(Ke(t,n),n.scope&&fp(t,n.scope)),(!n||!n.lazy)&&t.run();const i=t.run.bind(t);return i.effect=t,i}function pE(e){e.effect.stop()}let Ai=!0,hc=0;const pp=[];function Fi(){pp.push(Ai),Ai=!1}function Vi(){const e=pp.pop();Ai=e===void 0?!0:e}function du(){hc++}function hu(){for(hc--;!hc&&pc.length;)pc.shift()()}function mp(e,n,t){if(n.get(e)!==e._trackId){n.set(e,e._trackId);const i=e.deps[e._depsLength];i!==n?(i&&hp(i,e),e.deps[e._depsLength++]=n):e._depsLength++}}const pc=[];function gp(e,n,t){du();for(const i of e.keys()){let r;i._dirtyLevel{const t=new Map;return t.cleanup=e,t.computed=n,t},ra=new WeakMap,er=Symbol(""),mc=Symbol("");function un(e,n,t){if(Ai&&qi){let i=ra.get(e);i||ra.set(e,i=new Map);let r=i.get(t);r||i.set(t,r=vp(()=>i.delete(t))),mp(qi,r)}}function ri(e,n,t,i,r,o){const s=ra.get(e);if(!s)return;let a=[];if(n==="clear")a=[...s.values()];else if(t==="length"&&pe(e)){const l=Number(i);s.forEach((c,u)=>{(u==="length"||!cn(u)&&u>=l)&&a.push(c)})}else switch(t!==void 0&&a.push(s.get(t)),n){case"add":pe(e)?Va(t)&&a.push(s.get("length")):(a.push(s.get(er)),Zi(e)&&a.push(s.get(mc)));break;case"delete":pe(e)||(a.push(s.get(er)),Zi(e)&&a.push(s.get(mc)));break;case"set":Zi(e)&&a.push(s.get(er));break}du();for(const l of a)l&&gp(l,4);hu()}function mE(e,n){const t=ra.get(e);return t&&t.get(n)}const gE=jt("__proto__,__v_isRef,__isVue"),yp=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(cn)),kf=vE();function vE(){const e={};return["includes","indexOf","lastIndexOf"].forEach(n=>{e[n]=function(...t){const i=Xe(this);for(let o=0,s=this.length;o{e[n]=function(...t){Fi(),du();const i=Xe(this)[n].apply(this,t);return hu(),Vi(),i}}),e}function yE(e){cn(e)||(e=String(e));const n=Xe(this);return un(n,"has",e),n.hasOwnProperty(e)}class Ep{constructor(n=!1,t=!1){this._isReadonly=n,this._isShallow=t}get(n,t,i){const r=this._isReadonly,o=this._isShallow;if(t==="__v_isReactive")return!r;if(t==="__v_isReadonly")return r;if(t==="__v_isShallow")return o;if(t==="__v_raw")return i===(r?o?Cp:Dp:o?wp:Tp).get(n)||Object.getPrototypeOf(n)===Object.getPrototypeOf(i)?n:void 0;const s=pe(n);if(!r){if(s&&ze(kf,t))return Reflect.get(kf,t,i);if(t==="hasOwnProperty")return yE}const a=Reflect.get(n,t,i);return(cn(t)?yp.has(t):gE(t))||(r||un(n,"get",t),o)?a:Bt(a)?s&&Va(t)?a:a.value:et(a)?r?mu(a):Ha(a):a}}class bp extends Ep{constructor(n=!1){super(!1,n)}set(n,t,i,r){let o=n[t];if(!this._isShallow){const l=_i(o);if(!sr(i)&&!_i(i)&&(o=Xe(o),i=Xe(i)),!pe(n)&&Bt(o)&&!Bt(i))return l?!1:(o.value=i,!0)}const s=pe(n)&&Va(t)?Number(t)e,ja=e=>Reflect.getPrototypeOf(e);function fs(e,n,t=!1,i=!1){e=e.__v_raw;const r=Xe(e),o=Xe(n);t||(Mn(n,o)&&un(r,"get",n),un(r,"get",o));const{has:s}=ja(r),a=i?pu:t?vu:Lo;if(s.call(r,n))return a(e.get(n));if(s.call(r,o))return a(e.get(o));e!==r&&e.get(n)}function ds(e,n=!1){const t=this.__v_raw,i=Xe(t),r=Xe(e);return n||(Mn(e,r)&&un(i,"has",e),un(i,"has",r)),e===r?t.has(e):t.has(e)||t.has(r)}function hs(e,n=!1){return e=e.__v_raw,!n&&un(Xe(e),"iterate",er),Reflect.get(e,"size",e)}function Ff(e,n=!1){!n&&!sr(e)&&!_i(e)&&(e=Xe(e));const t=Xe(this);return ja(t).has.call(t,e)||(t.add(e),ri(t,"add",e,e)),this}function Vf(e,n,t=!1){!t&&!sr(n)&&!_i(n)&&(n=Xe(n));const i=Xe(this),{has:r,get:o}=ja(i);let s=r.call(i,e);s||(e=Xe(e),s=r.call(i,e));const a=o.call(i,e);return i.set(e,n),s?Mn(n,a)&&ri(i,"set",e,n):ri(i,"add",e,n),this}function Bf(e){const n=Xe(this),{has:t,get:i}=ja(n);let r=t.call(n,e);r||(e=Xe(e),r=t.call(n,e)),i&&i.call(n,e);const o=n.delete(e);return r&&ri(n,"delete",e,void 0),o}function jf(){const e=Xe(this),n=e.size!==0,t=e.clear();return n&&ri(e,"clear",void 0,void 0),t}function ps(e,n){return function(i,r){const o=this,s=o.__v_raw,a=Xe(s),l=n?pu:e?vu:Lo;return!e&&un(a,"iterate",er),s.forEach((c,u)=>i.call(r,l(c),l(u),o))}}function ms(e,n,t){return function(...i){const r=this.__v_raw,o=Xe(r),s=Zi(o),a=e==="entries"||e===Symbol.iterator&&s,l=e==="keys"&&s,c=r[e](...i),u=t?pu:n?vu:Lo;return!n&&un(o,"iterate",l?mc:er),{next(){const{value:f,done:h}=c.next();return h?{value:f,done:h}:{value:a?[u(f[0]),u(f[1])]:u(f),done:h}},[Symbol.iterator](){return this}}}}function hi(e){return function(...n){return e==="delete"?!1:e==="clear"?void 0:this}}function wE(){const e={get(o){return fs(this,o)},get size(){return hs(this)},has:ds,add:Ff,set:Vf,delete:Bf,clear:jf,forEach:ps(!1,!1)},n={get(o){return fs(this,o,!1,!0)},get size(){return hs(this)},has:ds,add(o){return Ff.call(this,o,!0)},set(o,s){return Vf.call(this,o,s,!0)},delete:Bf,clear:jf,forEach:ps(!1,!0)},t={get(o){return fs(this,o,!0)},get size(){return hs(this,!0)},has(o){return ds.call(this,o,!0)},add:hi("add"),set:hi("set"),delete:hi("delete"),clear:hi("clear"),forEach:ps(!0,!1)},i={get(o){return fs(this,o,!0,!0)},get size(){return hs(this,!0)},has(o){return ds.call(this,o,!0)},add:hi("add"),set:hi("set"),delete:hi("delete"),clear:hi("clear"),forEach:ps(!0,!0)};return["keys","values","entries",Symbol.iterator].forEach(o=>{e[o]=ms(o,!1,!1),t[o]=ms(o,!0,!1),n[o]=ms(o,!1,!0),i[o]=ms(o,!0,!0)}),[e,t,n,i]}const[DE,CE,OE,AE]=wE();function $a(e,n){const t=n?e?AE:OE:e?CE:DE;return(i,r,o)=>r==="__v_isReactive"?!e:r==="__v_isReadonly"?e:r==="__v_raw"?i:Reflect.get(ze(t,r)&&r in i?t:i,r,o)}const xE={get:$a(!1,!1)},_E={get:$a(!1,!0)},ME={get:$a(!0,!1)},IE={get:$a(!0,!0)},Tp=new WeakMap,wp=new WeakMap,Dp=new WeakMap,Cp=new WeakMap;function NE(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function PE(e){return e.__v_skip||!Object.isExtensible(e)?0:NE(qh(e))}function Ha(e){return _i(e)?e:Ua(e,!1,EE,xE,Tp)}function Op(e){return Ua(e,!1,SE,_E,wp)}function mu(e){return Ua(e,!0,bE,ME,Dp)}function RE(e){return Ua(e,!0,TE,IE,Cp)}function Ua(e,n,t,i,r){if(!et(e)||e.__v_raw&&!(n&&e.__v_isReactive))return e;const o=r.get(e);if(o)return o;const s=PE(e);if(s===0)return e;const a=new Proxy(e,s===2?i:t);return r.set(e,a),a}function tr(e){return _i(e)?tr(e.__v_raw):!!(e&&e.__v_isReactive)}function _i(e){return!!(e&&e.__v_isReadonly)}function sr(e){return!!(e&&e.__v_isShallow)}function gu(e){return e?!!e.__v_raw:!1}function Xe(e){const n=e&&e.__v_raw;return n?Xe(n):e}function Ap(e){return Object.isExtensible(e)&&ru(e,"__v_skip",!0),e}const Lo=e=>et(e)?Ha(e):e,vu=e=>et(e)?mu(e):e;class xp{constructor(n,t,i,r){this.getter=n,this._setter=t,this.dep=void 0,this.__v_isRef=!0,this.__v_isReadonly=!1,this.effect=new Rr(()=>n(this._value),()=>Ar(this,this.effect._dirtyLevel===2?2:3)),this.effect.computed=this,this.effect.active=this._cacheable=!r,this.__v_isReadonly=i}get value(){const n=Xe(this);return(!n._cacheable||n.effect.dirty)&&Mn(n._value,n._value=n.effect.run())&&Ar(n,4),yu(n),n.effect._dirtyLevel>=2&&Ar(n,2),n._value}set value(n){this._setter(n)}get _dirty(){return this.effect.dirty}set _dirty(n){this.effect.dirty=n}}function LE(e,n,t=!1){let i,r;const o=Ce(e);return o?(i=e,r=wt):(i=e.get,r=e.set),new xp(i,r,o||!r,t)}function yu(e){var n;Ai&&qi&&(e=Xe(e),mp(qi,(n=e.dep)!=null?n:e.dep=vp(()=>e.dep=void 0,e instanceof xp?e:void 0)))}function Ar(e,n=4,t,i){e=Xe(e);const r=e.dep;r&&gp(r,n)}function Bt(e){return!!(e&&e.__v_isRef===!0)}function bo(e){return _p(e,!1)}function kE(e){return _p(e,!0)}function _p(e,n){return Bt(e)?e:new FE(e,n)}class FE{constructor(n,t){this.__v_isShallow=t,this.dep=void 0,this.__v_isRef=!0,this._rawValue=t?n:Xe(n),this._value=t?n:Lo(n)}get value(){return yu(this),this._value}set value(n){const t=this.__v_isShallow||sr(n)||_i(n);n=t?n:Xe(n),Mn(n,this._rawValue)&&(this._rawValue,this._rawValue=n,this._value=t?n:Lo(n),Ar(this,4))}}function VE(e){Ar(e,4)}function Eu(e){return Bt(e)?e.value:e}function BE(e){return Ce(e)?e():Eu(e)}const jE={get:(e,n,t)=>Eu(Reflect.get(e,n,t)),set:(e,n,t,i)=>{const r=e[n];return Bt(r)&&!Bt(t)?(r.value=t,!0):Reflect.set(e,n,t,i)}};function bu(e){return tr(e)?e:new Proxy(e,jE)}class $E{constructor(n){this.dep=void 0,this.__v_isRef=!0;const{get:t,set:i}=n(()=>yu(this),()=>Ar(this));this._get=t,this._set=i}get value(){return this._get()}set value(n){this._set(n)}}function Mp(e){return new $E(e)}function HE(e){const n=pe(e)?new Array(e.length):{};for(const t in e)n[t]=Ip(e,t);return n}class UE{constructor(n,t,i){this._object=n,this._key=t,this._defaultValue=i,this.__v_isRef=!0}get value(){const n=this._object[this._key];return n===void 0?this._defaultValue:n}set value(n){this._object[this._key]=n}get dep(){return mE(Xe(this._object),this._key)}}class WE{constructor(n){this._getter=n,this.__v_isRef=!0,this.__v_isReadonly=!0}get value(){return this._getter()}}function YE(e,n,t){return Bt(e)?e:Ce(e)?new WE(e):et(e)&&arguments.length>1?Ip(e,n,t):bo(e)}function Ip(e,n,t){const i=e[n];return Bt(i)?i:new UE(e,n,t)}const zE={GET:"get",HAS:"has",ITERATE:"iterate"},KE={SET:"set",ADD:"add",DELETE:"delete",CLEAR:"clear"};/** -* @vue/runtime-core v3.4.32 -* (c) 2018-present Yuxi (Evan) You and Vue contributors -* @license MIT -**/function XE(e,n){}const GE={SETUP_FUNCTION:0,0:"SETUP_FUNCTION",RENDER_FUNCTION:1,1:"RENDER_FUNCTION",WATCH_GETTER:2,2:"WATCH_GETTER",WATCH_CALLBACK:3,3:"WATCH_CALLBACK",WATCH_CLEANUP:4,4:"WATCH_CLEANUP",NATIVE_EVENT_HANDLER:5,5:"NATIVE_EVENT_HANDLER",COMPONENT_EVENT_HANDLER:6,6:"COMPONENT_EVENT_HANDLER",VNODE_HOOK:7,7:"VNODE_HOOK",DIRECTIVE_HOOK:8,8:"DIRECTIVE_HOOK",TRANSITION_HOOK:9,9:"TRANSITION_HOOK",APP_ERROR_HANDLER:10,10:"APP_ERROR_HANDLER",APP_WARN_HANDLER:11,11:"APP_WARN_HANDLER",FUNCTION_REF:12,12:"FUNCTION_REF",ASYNC_COMPONENT_LOADER:13,13:"ASYNC_COMPONENT_LOADER",SCHEDULER:14,14:"SCHEDULER",COMPONENT_UPDATE:15,15:"COMPONENT_UPDATE"},ZE={sp:"serverPrefetch hook",bc:"beforeCreate hook",c:"created hook",bm:"beforeMount hook",m:"mounted hook",bu:"beforeUpdate hook",u:"updated",bum:"beforeUnmount hook",um:"unmounted hook",a:"activated hook",da:"deactivated hook",ec:"errorCaptured hook",rtc:"renderTracked hook",rtg:"renderTriggered hook",0:"setup function",1:"render function",2:"watcher getter",3:"watcher callback",4:"watcher cleanup function",5:"native event handler",6:"component event handler",7:"vnode hook",8:"directive hook",9:"transition hook",10:"app errorHandler",11:"app warnHandler",12:"ref function",13:"async component loader",14:"scheduler flush",15:"component update"};function oi(e,n,t,i){try{return i?e(...i):e()}catch(r){gr(r,n,t)}}function Tn(e,n,t,i){if(Ce(e)){const r=oi(e,n,t,i);return r&&Fa(r)&&r.catch(o=>{gr(o,n,t)}),r}if(pe(e)){const r=[];for(let o=0;o>>1,r=zt[i],o=Fo(r);oWn&&zt.splice(n,1)}function oa(e){pe(e)?xr.push(...e):(!yi||!yi.includes(e,e.allowRecurse?Yi+1:Yi))&&xr.push(e),Pp()}function $f(e,n,t=ko?Wn+1:0){for(;tFo(t)-Fo(i));if(xr.length=0,yi){yi.push(...n);return}for(yi=n,Yi=0;Yie.id==null?1/0:e.id,eb=(e,n)=>{const t=Fo(e)-Fo(n);if(t===0){if(e.pre&&!n.pre)return-1;if(n.pre&&!e.pre)return 1}return t};function Rp(e){gc=!1,ko=!0,zt.sort(eb);const n=wt;try{for(Wn=0;WnDr.emit(r,...o)),gs=[]):typeof window<"u"&&window.HTMLElement&&!((i=(t=window.navigator)==null?void 0:t.userAgent)!=null&&i.includes("jsdom"))?((n.__VUE_DEVTOOLS_HOOK_REPLAY__=n.__VUE_DEVTOOLS_HOOK_REPLAY__||[]).push(o=>{Lp(o,n)}),setTimeout(()=>{Dr||(n.__VUE_DEVTOOLS_HOOK_REPLAY__=null,gs=[])},3e3)):gs=[]}let It=null,za=null;function Vo(e){const n=It;return It=e,za=e&&e.type.__scopeId||null,n}function tb(e){za=e}function nb(){za=null}const ib=e=>Tu;function Tu(e,n=It,t){if(!n||e._n)return e;const i=(...r)=>{i._d&&Cc(-1);const o=Vo(n);let s;try{s=e(...r)}finally{Vo(o),i._d&&Cc(1)}return s};return i._n=!0,i._c=!0,i._d=!0,i}function rb(e,n){if(It===null)return e;const t=ts(It),i=e.dirs||(e.dirs=[]);for(let r=0;r{e.isMounted=!0}),Za(()=>{e.isUnmounting=!0}),e}const wn=[Function,Array],Du={mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:wn,onEnter:wn,onAfterEnter:wn,onEnterCancelled:wn,onBeforeLeave:wn,onLeave:wn,onAfterLeave:wn,onLeaveCancelled:wn,onBeforeAppear:wn,onAppear:wn,onAfterAppear:wn,onAppearCancelled:wn},kp=e=>{const n=e.subTree;return n.component?kp(n.component):n},ob={name:"BaseTransition",props:Du,setup(e,{slots:n}){const t=fi(),i=wu();return()=>{const r=n.default&&Ka(n.default(),!0);if(!r||!r.length)return;let o=r[0];if(r.length>1){for(const h of r)if(h.type!==Rt){o=h;break}}const s=Xe(e),{mode:a}=s;if(i.isLeaving)return Nl(o);const l=Hf(o);if(!l)return Nl(o);let c=Lr(l,s,i,t,h=>c=h);Mi(l,c);const u=t.subTree,f=u&&Hf(u);if(f&&f.type!==Rt&&!Fn(l,f)&&kp(t).type!==Rt){const h=Lr(f,s,i,t);if(Mi(f,h),a==="out-in"&&l.type!==Rt)return i.isLeaving=!0,h.afterLeave=()=>{i.isLeaving=!1,t.update.active!==!1&&(t.effect.dirty=!0,t.update())},Nl(o);a==="in-out"&&l.type!==Rt&&(h.delayLeave=(p,m,g)=>{const E=Vp(i,f);E[String(f.key)]=f,p[Ei]=()=>{m(),p[Ei]=void 0,delete c.delayedLeave},c.delayedLeave=g})}return o}}},Fp=ob;function Vp(e,n){const{leavingVNodes:t}=e;let i=t.get(n.type);return i||(i=Object.create(null),t.set(n.type,i)),i}function Lr(e,n,t,i,r){const{appear:o,mode:s,persisted:a=!1,onBeforeEnter:l,onEnter:c,onAfterEnter:u,onEnterCancelled:f,onBeforeLeave:h,onLeave:p,onAfterLeave:m,onLeaveCancelled:g,onBeforeAppear:E,onAppear:D,onAfterAppear:T,onAppearCancelled:b}=n,w=String(e.key),x=Vp(t,e),A=(O,I)=>{O&&Tn(O,i,9,I)},k=(O,I)=>{const j=I[1];A(O,I),pe(O)?O.every(R=>R.length<=1)&&j():O.length<=1&&j()},F={mode:s,persisted:a,beforeEnter(O){let I=l;if(!t.isMounted)if(o)I=E||l;else return;O[Ei]&&O[Ei](!0);const j=x[w];j&&Fn(e,j)&&j.el[Ei]&&j.el[Ei](),A(I,[O])},enter(O){let I=c,j=u,R=f;if(!t.isMounted)if(o)I=D||c,j=T||u,R=b||f;else return;let L=!1;const $=O[vs]=G=>{L||(L=!0,G?A(R,[O]):A(j,[O]),F.delayedLeave&&F.delayedLeave(),O[vs]=void 0)};I?k(I,[O,$]):$()},leave(O,I){const j=String(e.key);if(O[vs]&&O[vs](!0),t.isUnmounting)return I();A(h,[O]);let R=!1;const L=O[Ei]=$=>{R||(R=!0,I(),$?A(g,[O]):A(m,[O]),O[Ei]=void 0,x[j]===e&&delete x[j])};x[j]=e,p?k(p,[O,L]):L()},clone(O){const I=Lr(O,n,t,i,r);return r&&r(I),I}};return F}function Nl(e){if(Jo(e))return e=zn(e),e.children=null,e}function Hf(e){if(!Jo(e))return e;const{shapeFlag:n,children:t}=e;if(t){if(n&16)return t[0];if(n&32&&Ce(t.default))return t.default()}}function Mi(e,n){e.shapeFlag&6&&e.component?Mi(e.component.subTree,n):e.shapeFlag&128?(e.ssContent.transition=n.clone(e.ssContent),e.ssFallback.transition=n.clone(e.ssFallback)):e.transition=n}function Ka(e,n=!1,t){let i=[],r=0;for(let o=0;o1)for(let o=0;oKe({name:e.name},n,{setup:e}))():e}const nr=e=>!!e.type.__asyncLoader;/*! #__NO_SIDE_EFFECTS__ */function sb(e){Ce(e)&&(e={loader:e});const{loader:n,loadingComponent:t,errorComponent:i,delay:r=200,timeout:o,suspensible:s=!0,onError:a}=e;let l=null,c,u=0;const f=()=>(u++,l=null,h()),h=()=>{let p;return l||(p=l=n().catch(m=>{if(m=m instanceof Error?m:new Error(String(m)),a)return new Promise((g,E)=>{a(m,()=>g(f()),()=>E(m),u+1)});throw m}).then(m=>p!==l&&l?l:(m&&(m.__esModule||m[Symbol.toStringTag]==="Module")&&(m=m.default),c=m,m)))};return Cu({name:"AsyncComponentWrapper",__asyncLoader:h,get __asyncResolved(){return c},setup(){const p=Mt;if(c)return()=>Pl(c,p);const m=T=>{l=null,gr(T,p,13,!i)};if(s&&p.suspense||es)return h().then(T=>()=>Pl(T,p)).catch(T=>(m(T),()=>i?ct(i,{error:T}):null));const g=bo(!1),E=bo(),D=bo(!!r);return r&&setTimeout(()=>{D.value=!1},r),o!=null&&setTimeout(()=>{if(!g.value&&!E.value){const T=new Error(`Async component timed out after ${o}ms.`);m(T),E.value=T}},o),h().then(()=>{g.value=!0,p.parent&&Jo(p.parent.vnode)&&(p.parent.effect.dirty=!0,Ya(p.parent.update))}).catch(T=>{m(T),E.value=T}),()=>{if(g.value&&c)return Pl(c,p);if(E.value&&i)return ct(i,{error:E.value});if(t&&!D.value)return ct(t)}}})}function Pl(e,n){const{ref:t,props:i,children:r,ce:o}=n.vnode,s=ct(e,i,r);return s.ref=t,s.ce=o,delete n.vnode.ce,s}const Jo=e=>e.type.__isKeepAlive,ab={name:"KeepAlive",__isKeepAlive:!0,props:{include:[String,RegExp,Array],exclude:[String,RegExp,Array],max:[String,Number]},setup(e,{slots:n}){const t=fi(),i=t.ctx;if(!i.renderer)return()=>{const T=n.default&&n.default();return T&&T.length===1?T[0]:T};const r=new Map,o=new Set;let s=null;const a=t.suspense,{renderer:{p:l,m:c,um:u,o:{createElement:f}}}=i,h=f("div");i.activate=(T,b,w,x,A)=>{const k=T.component;c(T,b,w,0,a),l(k.vnode,T,b,w,k,a,x,T.slotScopeIds,A),Pt(()=>{k.isDeactivated=!1,k.a&&Qi(k.a);const F=T.props&&T.props.onVnodeMounted;F&&on(F,k.parent,T)},a)},i.deactivate=T=>{const b=T.component;ca(b.m),ca(b.a),c(T,h,null,1,a),Pt(()=>{b.da&&Qi(b.da);const w=T.props&&T.props.onVnodeUnmounted;w&&on(w,b.parent,T),b.isDeactivated=!0},a)};function p(T){Rl(T),u(T,t,a,!0)}function m(T){r.forEach((b,w)=>{const x=Mc(b.type);x&&(!T||!T(x))&&g(w)})}function g(T){const b=r.get(T);!s||!Fn(b,s)?p(b):s&&Rl(s),r.delete(T),o.delete(T)}Do(()=>[e.include,e.exclude],([T,b])=>{T&&m(w=>co(T,w)),b&&m(w=>!co(b,w))},{flush:"post",deep:!0});let E=null;const D=()=>{E!=null&&(wc(t.subTree.type)?Pt(()=>{r.set(E,ys(t.subTree))},t.subTree.suspense):r.set(E,ys(t.subTree)))};return Qo(D),Ga(D),Za(()=>{r.forEach(T=>{const{subTree:b,suspense:w}=t,x=ys(b);if(T.type===x.type&&T.key===x.key){Rl(x);const A=x.component.da;A&&Pt(A,w);return}p(T)})}),()=>{if(E=null,!n.default)return null;const T=n.default(),b=T[0];if(T.length>1)return s=null,T;if(!Ii(b)||!(b.shapeFlag&4)&&!(b.shapeFlag&128))return s=null,b;let w=ys(b);const x=w.type,A=Mc(nr(w)?w.type.__asyncResolved||{}:x),{include:k,exclude:F,max:O}=e;if(k&&(!A||!co(k,A))||F&&A&&co(F,A))return s=w,b;const I=w.key==null?x:w.key,j=r.get(I);return w.el&&(w=zn(w),b.shapeFlag&128&&(b.ssContent=w)),E=I,j?(w.el=j.el,w.component=j.component,w.transition&&Mi(w,w.transition),w.shapeFlag|=512,o.delete(I),o.add(I)):(o.add(I),O&&o.size>parseInt(O,10)&&g(o.values().next().value)),w.shapeFlag|=256,s=w,wc(b.type)?b:w}}},lb=ab;function co(e,n){return pe(e)?e.some(t=>co(t,n)):Me(e)?e.split(",").includes(n):Qh(e)?e.test(n):!1}function Bp(e,n){$p(e,"a",n)}function jp(e,n){$p(e,"da",n)}function $p(e,n,t=Mt){const i=e.__wdc||(e.__wdc=()=>{let r=t;for(;r;){if(r.isDeactivated)return;r=r.parent}return e()});if(Xa(n,i,t),t){let r=t.parent;for(;r&&r.parent;)Jo(r.parent.vnode)&&cb(i,n,t,r),r=r.parent}}function cb(e,n,t,i){const r=Xa(n,e,i,!0);Ja(()=>{ka(i[n],r)},t)}function Rl(e){e.shapeFlag&=-257,e.shapeFlag&=-513}function ys(e){return e.shapeFlag&128?e.ssContent:e}function Xa(e,n,t=Mt,i=!1){if(t){const r=t[e]||(t[e]=[]),o=n.__weh||(n.__weh=(...s)=>{Fi();const a=lr(t),l=Tn(n,t,e,s);return a(),Vi(),l});return i?r.unshift(o):r.push(o),o}}const ui=e=>(n,t=Mt)=>{(!es||e==="sp")&&Xa(e,(...i)=>n(...i),t)},Hp=ui("bm"),Qo=ui("m"),Up=ui("bu"),Ga=ui("u"),Za=ui("bum"),Ja=ui("um"),Wp=ui("sp"),Yp=ui("rtg"),zp=ui("rtc");function Kp(e,n=Mt){Xa("ec",e,n)}const Ou="components",ub="directives";function Xp(e,n){return Au(Ou,e,!0,n)||e}const Gp=Symbol.for("v-ndc");function fb(e){return Me(e)?Au(Ou,e,!1)||e:e||Gp}function db(e){return Au(ub,e)}function Au(e,n,t=!0,i=!1){const r=It||Mt;if(r){const o=r.type;if(e===Ou){const a=Mc(o,!1);if(a&&(a===n||a===ut(n)||a===ki(ut(n))))return o}const s=Uf(r[e]||o[e],n)||Uf(r.appContext[e],n);return!s&&i?o:s}}function Uf(e,n){return e&&(e[n]||e[ut(n)]||e[ki(ut(n))])}function hb(e,n,t,i){let r;const o=t&&t[i];if(pe(e)||Me(e)){r=new Array(e.length);for(let s=0,a=e.length;sn(s,a,void 0,o&&o[a]));else{const s=Object.keys(e);r=new Array(s.length);for(let a=0,l=s.length;a{const o=i.fn(...r);return o&&(o.key=i.key),o}:i.fn)}return e}function mb(e,n,t={},i,r){if(It.isCE||It.parent&&nr(It.parent)&&It.parent.isCE)return n!=="default"&&(t.name=n),ct("slot",t,i&&i());let o=e[n];o&&o._c&&(o._d=!1),qa();const s=o&&Zp(o(t)),a=Nu(Vt,{key:(t.key||s&&s.key||`_${n}`)+(!s&&i?"_fb":"")},s||(i?i():[]),s&&e._===1?64:-2);return!r&&a.scopeId&&(a.slotScopeIds=[a.scopeId+"-s"]),o&&o._c&&(o._d=!0),a}function Zp(e){return e.some(n=>Ii(n)?!(n.type===Rt||n.type===Vt&&!Zp(n.children)):!0)?e:null}function gb(e,n){const t={};for(const i in e)t[n&&/[A-Z]/.test(i)?`on:${i}`:Ji(i)]=e[i];return t}const vc=e=>e?Nm(e)?ts(e):vc(e.parent):null,So=Ke(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>vc(e.parent),$root:e=>vc(e.root),$emit:e=>e.emit,$options:e=>xu(e),$forceUpdate:e=>e.f||(e.f=()=>{e.effect.dirty=!0,Ya(e.update)}),$nextTick:e=>e.n||(e.n=Wa.bind(e.proxy)),$watch:e=>e0.bind(e)}),Ll=(e,n)=>e!==Ze&&!e.__isScriptSetup&&ze(e,n),yc={get({_:e},n){if(n==="__v_skip")return!0;const{ctx:t,setupState:i,data:r,props:o,accessCache:s,type:a,appContext:l}=e;let c;if(n[0]!=="$"){const p=s[n];if(p!==void 0)switch(p){case 1:return i[n];case 2:return r[n];case 4:return t[n];case 3:return o[n]}else{if(Ll(i,n))return s[n]=1,i[n];if(r!==Ze&&ze(r,n))return s[n]=2,r[n];if((c=e.propsOptions[0])&&ze(c,n))return s[n]=3,o[n];if(t!==Ze&&ze(t,n))return s[n]=4,t[n];Ec&&(s[n]=0)}}const u=So[n];let f,h;if(u)return n==="$attrs"&&un(e.attrs,"get",""),u(e);if((f=a.__cssModules)&&(f=f[n]))return f;if(t!==Ze&&ze(t,n))return s[n]=4,t[n];if(h=l.config.globalProperties,ze(h,n))return h[n]},set({_:e},n,t){const{data:i,setupState:r,ctx:o}=e;return Ll(r,n)?(r[n]=t,!0):i!==Ze&&ze(i,n)?(i[n]=t,!0):ze(e.props,n)||n[0]==="$"&&n.slice(1)in e?!1:(o[n]=t,!0)},has({_:{data:e,setupState:n,accessCache:t,ctx:i,appContext:r,propsOptions:o}},s){let a;return!!t[s]||e!==Ze&&ze(e,s)||Ll(n,s)||(a=o[0])&&ze(a,s)||ze(i,s)||ze(So,s)||ze(r.config.globalProperties,s)},defineProperty(e,n,t){return t.get!=null?e._.accessCache[n]=0:ze(t,"value")&&this.set(e,n,t.value,null),Reflect.defineProperty(e,n,t)}},vb=Ke({},yc,{get(e,n){if(n!==Symbol.unscopables)return yc.get(e,n,e)},has(e,n){return n[0]!=="_"&&!au(n)}});function yb(){return null}function Eb(){return null}function bb(e){}function Sb(e){}function Tb(){return null}function wb(){}function Db(e,n){return null}function Cb(){return Jp().slots}function Ob(){return Jp().attrs}function Jp(){const e=fi();return e.setupContext||(e.setupContext=km(e))}function Bo(e){return pe(e)?e.reduce((n,t)=>(n[t]=null,n),{}):e}function Ab(e,n){const t=Bo(e);for(const i in n){if(i.startsWith("__skip"))continue;let r=t[i];r?pe(r)||Ce(r)?r=t[i]={type:r,default:n[i]}:r.default=n[i]:r===null&&(r=t[i]={default:n[i]}),r&&n[`__skip_${i}`]&&(r.skipFactory=!0)}return t}function xb(e,n){return!e||!n?e||n:pe(e)&&pe(n)?e.concat(n):Ke({},Bo(e),Bo(n))}function _b(e,n){const t={};for(const i in e)n.includes(i)||Object.defineProperty(t,i,{enumerable:!0,get:()=>e[i]});return t}function Mb(e){const n=fi();let t=e();return Ac(),Fa(t)&&(t=t.catch(i=>{throw lr(n),i})),[t,()=>lr(n)]}let Ec=!0;function Ib(e){const n=xu(e),t=e.proxy,i=e.ctx;Ec=!1,n.beforeCreate&&Wf(n.beforeCreate,e,"bc");const{data:r,computed:o,methods:s,watch:a,provide:l,inject:c,created:u,beforeMount:f,mounted:h,beforeUpdate:p,updated:m,activated:g,deactivated:E,beforeDestroy:D,beforeUnmount:T,destroyed:b,unmounted:w,render:x,renderTracked:A,renderTriggered:k,errorCaptured:F,serverPrefetch:O,expose:I,inheritAttrs:j,components:R,directives:L,filters:$}=n;if(c&&Nb(c,i,null),s)for(const Y in s){const Q=s[Y];Ce(Q)&&(i[Y]=Q.bind(t))}if(r){const Y=r.call(t,t);et(Y)&&(e.data=Ha(Y))}if(Ec=!0,o)for(const Y in o){const Q=o[Y],De=Ce(Q)?Q.bind(t,t):Ce(Q.get)?Q.get.bind(t,t):wt,Ge=!Ce(Q)&&Ce(Q.set)?Q.set.bind(t):wt,Ie=Fm({get:De,set:Ge});Object.defineProperty(i,Y,{enumerable:!0,configurable:!0,get:()=>Ie.value,set:Be=>Ie.value=Be})}if(a)for(const Y in a)Qp(a[Y],i,t,Y);if(l){const Y=Ce(l)?l.call(t):l;Reflect.ownKeys(Y).forEach(Q=>{em(Q,Y[Q])})}u&&Wf(u,e,"c");function B(Y,Q){pe(Q)?Q.forEach(De=>Y(De.bind(t))):Q&&Y(Q.bind(t))}if(B(Hp,f),B(Qo,h),B(Up,p),B(Ga,m),B(Bp,g),B(jp,E),B(Kp,F),B(zp,A),B(Yp,k),B(Za,T),B(Ja,w),B(Wp,O),pe(I))if(I.length){const Y=e.exposed||(e.exposed={});I.forEach(Q=>{Object.defineProperty(Y,Q,{get:()=>t[Q],set:De=>t[Q]=De})})}else e.exposed||(e.exposed={});x&&e.render===wt&&(e.render=x),j!=null&&(e.inheritAttrs=j),R&&(e.components=R),L&&(e.directives=L)}function Nb(e,n,t=wt){pe(e)&&(e=bc(e));for(const i in e){const r=e[i];let o;et(r)?"default"in r?o=To(r.from||i,r.default,!0):o=To(r.from||i):o=To(r),Bt(o)?Object.defineProperty(n,i,{enumerable:!0,configurable:!0,get:()=>o.value,set:s=>o.value=s}):n[i]=o}}function Wf(e,n,t){Tn(pe(e)?e.map(i=>i.bind(n.proxy)):e.bind(n.proxy),n,t)}function Qp(e,n,t,i){const r=i.includes(".")?Sm(t,i):()=>t[i];if(Me(e)){const o=n[e];Ce(o)&&Do(r,o)}else if(Ce(e))Do(r,e.bind(t));else if(et(e))if(pe(e))e.forEach(o=>Qp(o,n,t,i));else{const o=Ce(e.handler)?e.handler.bind(t):n[e.handler];Ce(o)&&Do(r,o,e)}}function xu(e){const n=e.type,{mixins:t,extends:i}=n,{mixins:r,optionsCache:o,config:{optionMergeStrategies:s}}=e.appContext,a=o.get(n);let l;return a?l=a:!r.length&&!t&&!i?l=n:(l={},r.length&&r.forEach(c=>aa(l,c,s,!0)),aa(l,n,s)),et(n)&&o.set(n,l),l}function aa(e,n,t,i=!1){const{mixins:r,extends:o}=n;o&&aa(e,o,t,!0),r&&r.forEach(s=>aa(e,s,t,!0));for(const s in n)if(!(i&&s==="expose")){const a=Pb[s]||t&&t[s];e[s]=a?a(e[s],n[s]):n[s]}return e}const Pb={data:Yf,props:zf,emits:zf,methods:uo,computed:uo,beforeCreate:Jt,created:Jt,beforeMount:Jt,mounted:Jt,beforeUpdate:Jt,updated:Jt,beforeDestroy:Jt,beforeUnmount:Jt,destroyed:Jt,unmounted:Jt,activated:Jt,deactivated:Jt,errorCaptured:Jt,serverPrefetch:Jt,components:uo,directives:uo,watch:Lb,provide:Yf,inject:Rb};function Yf(e,n){return n?e?function(){return Ke(Ce(e)?e.call(this,this):e,Ce(n)?n.call(this,this):n)}:n:e}function Rb(e,n){return uo(bc(e),bc(n))}function bc(e){if(pe(e)){const n={};for(let t=0;t1)return t&&Ce(n)?n.call(i&&i.proxy):n}}function Vb(){return!!(Mt||It||_r)}const tm={},nm=()=>Object.create(tm),im=e=>Object.getPrototypeOf(e)===tm;function Bb(e,n,t,i=!1){const r={},o=nm();e.propsDefaults=Object.create(null),rm(e,n,r,o);for(const s in e.propsOptions[0])s in r||(r[s]=void 0);t?e.props=i?r:Op(r):e.type.props?e.props=r:e.props=o,e.attrs=o}function jb(e,n,t,i){const{props:r,attrs:o,vnode:{patchFlag:s}}=e,a=Xe(r),[l]=e.propsOptions;let c=!1;if((i||s>0)&&!(s&16)){if(s&8){const u=e.vnode.dynamicProps;for(let f=0;f{l=!0;const[h,p]=om(f,n,!0);Ke(s,h),p&&a.push(...p)};!t&&n.mixins.length&&n.mixins.forEach(u),e.extends&&u(e.extends),e.mixins&&e.mixins.forEach(u)}if(!o&&!l)return et(e)&&i.set(e,Gi),Gi;if(pe(o))for(let u=0;u-1,p[1]=g<0||m-1||ze(p,"default"))&&a.push(f)}}}const c=[s,a];return et(e)&&i.set(e,c),c}function Kf(e){return e[0]!=="$"&&!ii(e)}function Xf(e){return e===null?"null":typeof e=="function"?e.name||"":typeof e=="object"&&e.constructor&&e.constructor.name||""}function Gf(e,n){return Xf(e)===Xf(n)}function Zf(e,n){return pe(n)?n.findIndex(t=>Gf(t,e)):Ce(n)&&Gf(n,e)?0:-1}const sm=e=>e[0]==="_"||e==="$stable",_u=e=>pe(e)?e.map(an):[an(e)],Hb=(e,n,t)=>{if(n._n)return n;const i=Tu((...r)=>_u(n(...r)),t);return i._c=!1,i},am=(e,n,t)=>{const i=e._ctx;for(const r in e){if(sm(r))continue;const o=e[r];if(Ce(o))n[r]=Hb(r,o,i);else if(o!=null){const s=_u(o);n[r]=()=>s}}},lm=(e,n)=>{const t=_u(n);e.slots.default=()=>t},cm=(e,n,t)=>{for(const i in n)(t||i!=="_")&&(e[i]=n[i])},Ub=(e,n,t)=>{const i=e.slots=nm();if(e.vnode.shapeFlag&32){const r=n._;r?(cm(i,n,t),t&&ru(i,"_",r,!0)):am(n,i)}else n&&lm(e,n)},Wb=(e,n,t)=>{const{vnode:i,slots:r}=e;let o=!0,s=Ze;if(i.shapeFlag&32){const a=n._;a?t&&a===1?o=!1:cm(r,n,t):(o=!n.$stable,am(n,r)),s=n}else n&&(lm(e,n),s={default:1});if(o)for(const a in r)!sm(a)&&s[a]==null&&delete r[a]};function la(e,n,t,i,r=!1){if(pe(e)){e.forEach((h,p)=>la(h,n&&(pe(n)?n[p]:n),t,i,r));return}if(nr(i)&&!r)return;const o=i.shapeFlag&4?ts(i.component):i.el,s=r?null:o,{i:a,r:l}=e,c=n&&n.r,u=a.refs===Ze?a.refs={}:a.refs,f=a.setupState;if(c!=null&&c!==l&&(Me(c)?(u[c]=null,ze(f,c)&&(f[c]=null)):Bt(c)&&(c.value=null)),Ce(l))oi(l,a,12,[s,u]);else{const h=Me(l),p=Bt(l);if(h||p){const m=()=>{if(e.f){const g=h?ze(f,l)?f[l]:u[l]:l.value;r?pe(g)&&ka(g,o):pe(g)?g.includes(o)||g.push(o):h?(u[l]=[o],ze(f,l)&&(f[l]=u[l])):(l.value=[o],e.k&&(u[e.k]=l.value))}else h?(u[l]=s,ze(f,l)&&(f[l]=s)):p&&(l.value=s,e.k&&(u[e.k]=s))};s?(m.id=-1,Pt(m,t)):m()}}}const um=Symbol("_vte"),Yb=e=>e.__isTeleport,wo=e=>e&&(e.disabled||e.disabled===""),Jf=e=>typeof SVGElement<"u"&&e instanceof SVGElement,Qf=e=>typeof MathMLElement=="function"&&e instanceof MathMLElement,Tc=(e,n)=>{const t=e&&e.to;return Me(t)?n?n(t):null:t},zb={name:"Teleport",__isTeleport:!0,process(e,n,t,i,r,o,s,a,l,c){const{mc:u,pc:f,pbc:h,o:{insert:p,querySelector:m,createText:g,createComment:E}}=c,D=wo(n.props);let{shapeFlag:T,children:b,dynamicChildren:w}=n;if(e==null){const x=n.el=g(""),A=n.anchor=g(""),k=n.target=Tc(n.props,m),F=n.targetStart=g(""),O=n.targetAnchor=g("");p(x,t,i),p(A,t,i),F[um]=O,k&&(p(F,k),p(O,k),s==="svg"||Jf(k)?s="svg":(s==="mathml"||Qf(k))&&(s="mathml"));const I=(j,R)=>{T&16&&u(b,j,R,r,o,s,a,l)};D?I(t,A):k&&I(k,O)}else{n.el=e.el,n.targetStart=e.targetStart;const x=n.anchor=e.anchor,A=n.target=e.target,k=n.targetAnchor=e.targetAnchor,F=wo(e.props),O=F?t:A,I=F?x:k;if(s==="svg"||Jf(A)?s="svg":(s==="mathml"||Qf(A))&&(s="mathml"),w?(h(e.dynamicChildren,w,O,r,o,s,a),Mu(e,n,!0)):l||f(e,n,O,I,r,o,s,a,!1),D)F?n.props&&e.props&&n.props.to!==e.props.to&&(n.props.to=e.props.to):Es(n,t,x,c,1);else if((n.props&&n.props.to)!==(e.props&&e.props.to)){const j=n.target=Tc(n.props,m);j&&Es(n,j,null,c,0)}else F&&Es(n,A,k,c,1)}fm(n)},remove(e,n,t,{um:i,o:{remove:r}},o){const{shapeFlag:s,children:a,anchor:l,targetStart:c,targetAnchor:u,target:f,props:h}=e;if(f&&(r(c),r(u)),o&&r(l),s&16){const p=o||!wo(h);for(let m=0;m{qf||(console.error("Hydration completed but contains mismatches."),qf=!0)},Gb=e=>e.namespaceURI.includes("svg")&&e.tagName!=="foreignObject",Zb=e=>e.namespaceURI.includes("MathML"),bs=e=>{if(Gb(e))return"svg";if(Zb(e))return"mathml"},Ss=e=>e.nodeType===8;function Jb(e){const{mt:n,p:t,o:{patchProp:i,createText:r,nextSibling:o,parentNode:s,remove:a,insert:l,createComment:c}}=e,u=(b,w)=>{if(!w.hasChildNodes()){t(null,b,w),sa(),w._vnode=b;return}f(w.firstChild,b,null,null,null),sa(),w._vnode=b},f=(b,w,x,A,k,F=!1)=>{F=F||!!w.dynamicChildren;const O=Ss(b)&&b.data==="[",I=()=>g(b,w,x,A,k,O),{type:j,ref:R,shapeFlag:L,patchFlag:$}=w;let G=b.nodeType;w.el=b,$===-2&&(F=!1,w.dynamicChildren=null);let B=null;switch(j){case xi:G!==3?w.children===""?(l(w.el=r(""),s(b),b),B=b):B=I():(b.data!==w.children&&(yr(),b.data=w.children),B=o(b));break;case Rt:T(b)?(B=o(b),D(w.el=b.content.firstChild,b,x)):G!==8||O?B=I():B=o(b);break;case ir:if(O&&(b=o(b),G=b.nodeType),G===1||G===3){B=b;const Y=!w.children.length;for(let Q=0;Q{F=F||!!w.dynamicChildren;const{type:O,props:I,patchFlag:j,shapeFlag:R,dirs:L,transition:$}=w,G=O==="input"||O==="option";if(G||j!==-1){L&&Un(w,null,x,"created");let B=!1;if(T(b)){B=mm(A,$)&&x&&x.vnode.props&&x.vnode.props.appear;const Q=b.content.firstChild;B&&$.beforeEnter(Q),D(Q,b,x),w.el=b=Q}if(R&16&&!(I&&(I.innerHTML||I.textContent))){let Q=p(b.firstChild,w,b,x,A,k,F);for(;Q;){yr();const De=Q;Q=Q.nextSibling,a(De)}}else R&8&&b.textContent!==w.children&&(yr(),b.textContent=w.children);if(I){if(G||!F||j&48)for(const Q in I)(G&&(Q.endsWith("value")||Q==="indeterminate")||Ri(Q)&&!ii(Q)||Q[0]===".")&&i(b,Q,null,I[Q],void 0,x);else if(I.onClick)i(b,"onClick",null,I.onClick,void 0,x);else if(j&4&&tr(I.style))for(const Q in I.style)I.style[Q]}let Y;(Y=I&&I.onVnodeBeforeMount)&&on(Y,x,w),L&&Un(w,null,x,"beforeMount"),((Y=I&&I.onVnodeMounted)||L||B)&&Cm(()=>{Y&&on(Y,x,w),B&&$.enter(b),L&&Un(w,null,x,"mounted")},A)}return b.nextSibling},p=(b,w,x,A,k,F,O)=>{O=O||!!w.dynamicChildren;const I=w.children,j=I.length;for(let R=0;R{const{slotScopeIds:O}=w;O&&(k=k?k.concat(O):O);const I=s(b),j=p(o(b),w,I,x,A,k,F);return j&&Ss(j)&&j.data==="]"?o(w.anchor=j):(yr(),l(w.anchor=c("]"),I,j),j)},g=(b,w,x,A,k,F)=>{if(yr(),w.el=null,F){const j=E(b);for(;;){const R=o(b);if(R&&R!==j)a(R);else break}}const O=o(b),I=s(b);return a(b),t(null,w,I,O,x,A,bs(I),k),O},E=(b,w="[",x="]")=>{let A=0;for(;b;)if(b=o(b),b&&Ss(b)&&(b.data===w&&A++,b.data===x)){if(A===0)return o(b);A--}return b},D=(b,w,x)=>{const A=w.parentNode;A&&A.replaceChild(b,w);let k=x;for(;k;)k.vnode.el===w&&(k.vnode.el=k.subTree.el=b),k=k.parent},T=b=>b.nodeType===1&&b.tagName.toLowerCase()==="template";return[u,f]}const Pt=Cm;function dm(e){return pm(e)}function hm(e){return pm(e,Jb)}function pm(e,n){const t=ou();t.__VUE__=!0;const{insert:i,remove:r,patchProp:o,createElement:s,createText:a,createComment:l,setText:c,setElementText:u,parentNode:f,nextSibling:h,setScopeId:p=wt,insertStaticContent:m}=e,g=(M,N,H,Z=null,K=null,q=null,ie=void 0,ne=null,re=!!N.dynamicChildren)=>{if(M===N)return;M&&!Fn(M,N)&&(Z=ue(M),Be(M,K,q,!0),M=null),N.patchFlag===-2&&(re=!1,N.dynamicChildren=null);const{type:J,ref:le,shapeFlag:ge}=N;switch(J){case xi:E(M,N,H,Z);break;case Rt:D(M,N,H,Z);break;case ir:M==null&&T(N,H,Z,ie);break;case Vt:R(M,N,H,Z,K,q,ie,ne,re);break;default:ge&1?x(M,N,H,Z,K,q,ie,ne,re):ge&6?L(M,N,H,Z,K,q,ie,ne,re):(ge&64||ge&128)&&J.process(M,N,H,Z,K,q,ie,ne,re,it)}le!=null&&K&&la(le,M&&M.ref,q,N||M,!N)},E=(M,N,H,Z)=>{if(M==null)i(N.el=a(N.children),H,Z);else{const K=N.el=M.el;N.children!==M.children&&c(K,N.children)}},D=(M,N,H,Z)=>{M==null?i(N.el=l(N.children||""),H,Z):N.el=M.el},T=(M,N,H,Z)=>{[M.el,M.anchor]=m(M.children,N,H,Z,M.el,M.anchor)},b=({el:M,anchor:N},H,Z)=>{let K;for(;M&&M!==N;)K=h(M),i(M,H,Z),M=K;i(N,H,Z)},w=({el:M,anchor:N})=>{let H;for(;M&&M!==N;)H=h(M),r(M),M=H;r(N)},x=(M,N,H,Z,K,q,ie,ne,re)=>{N.type==="svg"?ie="svg":N.type==="math"&&(ie="mathml"),M==null?A(N,H,Z,K,q,ie,ne,re):O(M,N,K,q,ie,ne,re)},A=(M,N,H,Z,K,q,ie,ne)=>{let re,J;const{props:le,shapeFlag:ge,transition:fe,dirs:we}=M;if(re=M.el=s(M.type,q,le&&le.is,le),ge&8?u(re,M.children):ge&16&&F(M.children,re,null,Z,K,kl(M,q),ie,ne),we&&Un(M,null,Z,"created"),k(re,M,M.scopeId,ie,Z),le){for(const We in le)We!=="value"&&!ii(We)&&o(re,We,null,le[We],q,Z);"value"in le&&o(re,"value",null,le.value,q),(J=le.onVnodeBeforeMount)&&on(J,Z,M)}we&&Un(M,null,Z,"beforeMount");const Ae=mm(K,fe);Ae&&fe.beforeEnter(re),i(re,N,H),((J=le&&le.onVnodeMounted)||Ae||we)&&Pt(()=>{J&&on(J,Z,M),Ae&&fe.enter(re),we&&Un(M,null,Z,"mounted")},K)},k=(M,N,H,Z,K)=>{if(H&&p(M,H),Z)for(let q=0;q{for(let J=re;J{const ne=N.el=M.el;let{patchFlag:re,dynamicChildren:J,dirs:le}=N;re|=M.patchFlag&16;const ge=M.props||Ze,fe=N.props||Ze;let we;if(H&&Bi(H,!1),(we=fe.onVnodeBeforeUpdate)&&on(we,H,N,M),le&&Un(N,M,H,"beforeUpdate"),H&&Bi(H,!0),(ge.innerHTML&&fe.innerHTML==null||ge.textContent&&fe.textContent==null)&&u(ne,""),J?I(M.dynamicChildren,J,ne,H,Z,kl(N,K),q):ie||Q(M,N,ne,null,H,Z,kl(N,K),q,!1),re>0){if(re&16)j(ne,ge,fe,H,K);else if(re&2&&ge.class!==fe.class&&o(ne,"class",null,fe.class,K),re&4&&o(ne,"style",ge.style,fe.style,K),re&8){const Ae=N.dynamicProps;for(let We=0;We{we&&on(we,H,N,M),le&&Un(N,M,H,"updated")},Z)},I=(M,N,H,Z,K,q,ie)=>{for(let ne=0;ne{if(N!==H){if(N!==Ze)for(const q in N)!ii(q)&&!(q in H)&&o(M,q,N[q],null,K,Z);for(const q in H){if(ii(q))continue;const ie=H[q],ne=N[q];ie!==ne&&q!=="value"&&o(M,q,ne,ie,K,Z)}"value"in H&&o(M,"value",N.value,H.value,K)}},R=(M,N,H,Z,K,q,ie,ne,re)=>{const J=N.el=M?M.el:a(""),le=N.anchor=M?M.anchor:a("");let{patchFlag:ge,dynamicChildren:fe,slotScopeIds:we}=N;we&&(ne=ne?ne.concat(we):we),M==null?(i(J,H,Z),i(le,H,Z),F(N.children||[],H,le,K,q,ie,ne,re)):ge>0&&ge&64&&fe&&M.dynamicChildren?(I(M.dynamicChildren,fe,H,K,q,ie,ne),(N.key!=null||K&&N===K.subTree)&&Mu(M,N,!0)):Q(M,N,H,le,K,q,ie,ne,re)},L=(M,N,H,Z,K,q,ie,ne,re)=>{N.slotScopeIds=ne,M==null?N.shapeFlag&512?K.ctx.activate(N,H,Z,ie,re):$(N,H,Z,K,q,ie,re):G(M,N,re)},$=(M,N,H,Z,K,q,ie)=>{const ne=M.component=Im(M,Z,K);if(Jo(M)&&(ne.ctx.renderer=it),Pm(ne,!1,ie),ne.asyncDep){if(K&&K.registerDep(ne,B,ie),!M.el){const re=ne.subTree=ct(Rt);D(null,re,N,H)}}else B(ne,M,N,H,K,q,ie)},G=(M,N,H)=>{const Z=N.component=M.component;if(s0(M,N,H))if(Z.asyncDep&&!Z.asyncResolved){Y(Z,N,H);return}else Z.next=N,qE(Z.update),Z.effect.dirty=!0,Z.update();else N.el=M.el,Z.vnode=N},B=(M,N,H,Z,K,q,ie)=>{const ne=()=>{if(M.isMounted){let{next:le,bu:ge,u:fe,parent:we,vnode:Ae}=M;{const V=gm(M);if(V){le&&(le.el=Ae.el,Y(M,le,ie)),V.asyncDep.then(()=>{M.isUnmounted||ne()});return}}let We=le,v;Bi(M,!1),le?(le.el=Ae.el,Y(M,le,ie)):le=Ae,ge&&Qi(ge),(v=le.props&&le.props.onVnodeBeforeUpdate)&&on(v,we,le,Ae),Bi(M,!0);const y=$s(M),_=M.subTree;M.subTree=y,g(_,y,f(_.el),ue(_),M,K,q),le.el=y.el,We===null&&Iu(M,y.el),fe&&Pt(fe,K),(v=le.props&&le.props.onVnodeUpdated)&&Pt(()=>on(v,we,le,Ae),K)}else{let le;const{el:ge,props:fe}=N,{bm:we,m:Ae,parent:We}=M,v=nr(N);if(Bi(M,!1),we&&Qi(we),!v&&(le=fe&&fe.onVnodeBeforeMount)&&on(le,We,N),Bi(M,!0),ge&&rt){const y=()=>{M.subTree=$s(M),rt(ge,M.subTree,M,K,null)};v?N.type.__asyncLoader().then(()=>!M.isUnmounted&&y()):y()}else{const y=M.subTree=$s(M);g(null,y,H,Z,M,K,q),N.el=y.el}if(Ae&&Pt(Ae,K),!v&&(le=fe&&fe.onVnodeMounted)){const y=N;Pt(()=>on(le,We,y),K)}(N.shapeFlag&256||We&&nr(We.vnode)&&We.vnode.shapeFlag&256)&&M.a&&Pt(M.a,K),M.isMounted=!0,N=H=Z=null}},re=M.effect=new Rr(ne,wt,()=>Ya(J),M.scope),J=M.update=()=>{re.dirty&&re.run()};J.i=M,J.id=M.uid,Bi(M,!0),J()},Y=(M,N,H)=>{N.component=M;const Z=M.vnode.props;M.vnode=N,M.next=null,jb(M,N.props,Z,H),Wb(M,N.children,H),Fi(),$f(M),Vi()},Q=(M,N,H,Z,K,q,ie,ne,re=!1)=>{const J=M&&M.children,le=M?M.shapeFlag:0,ge=N.children,{patchFlag:fe,shapeFlag:we}=N;if(fe>0){if(fe&128){Ge(J,ge,H,Z,K,q,ie,ne,re);return}else if(fe&256){De(J,ge,H,Z,K,q,ie,ne,re);return}}we&8?(le&16&&ee(J,K,q),ge!==J&&u(H,ge)):le&16?we&16?Ge(J,ge,H,Z,K,q,ie,ne,re):ee(J,K,q,!0):(le&8&&u(H,""),we&16&&F(ge,H,Z,K,q,ie,ne,re))},De=(M,N,H,Z,K,q,ie,ne,re)=>{M=M||Gi,N=N||Gi;const J=M.length,le=N.length,ge=Math.min(J,le);let fe;for(fe=0;fele?ee(M,K,q,!0,!1,ge):F(N,H,Z,K,q,ie,ne,re,ge)},Ge=(M,N,H,Z,K,q,ie,ne,re)=>{let J=0;const le=N.length;let ge=M.length-1,fe=le-1;for(;J<=ge&&J<=fe;){const we=M[J],Ae=N[J]=re?bi(N[J]):an(N[J]);if(Fn(we,Ae))g(we,Ae,H,null,K,q,ie,ne,re);else break;J++}for(;J<=ge&&J<=fe;){const we=M[ge],Ae=N[fe]=re?bi(N[fe]):an(N[fe]);if(Fn(we,Ae))g(we,Ae,H,null,K,q,ie,ne,re);else break;ge--,fe--}if(J>ge){if(J<=fe){const we=fe+1,Ae=wefe)for(;J<=ge;)Be(M[J],K,q,!0),J++;else{const we=J,Ae=J,We=new Map;for(J=Ae;J<=fe;J++){const ce=N[J]=re?bi(N[J]):an(N[J]);ce.key!=null&&We.set(ce.key,J)}let v,y=0;const _=fe-Ae+1;let V=!1,X=0;const te=new Array(_);for(J=0;J<_;J++)te[J]=0;for(J=we;J<=ge;J++){const ce=M[J];if(y>=_){Be(ce,K,q,!0);continue}let Se;if(ce.key!=null)Se=We.get(ce.key);else for(v=Ae;v<=fe;v++)if(te[v-Ae]===0&&Fn(ce,N[v])){Se=v;break}Se===void 0?Be(ce,K,q,!0):(te[Se-Ae]=J+1,Se>=X?X=Se:V=!0,g(ce,N[Se],H,null,K,q,ie,ne,re),y++)}const z=V?Qb(te):Gi;for(v=z.length-1,J=_-1;J>=0;J--){const ce=Ae+J,Se=N[ce],me=ce+1{const{el:q,type:ie,transition:ne,children:re,shapeFlag:J}=M;if(J&6){Ie(M.component.subTree,N,H,Z);return}if(J&128){M.suspense.move(N,H,Z);return}if(J&64){ie.move(M,N,H,it);return}if(ie===Vt){i(q,N,H);for(let ge=0;gene.enter(q),K);else{const{leave:ge,delayLeave:fe,afterLeave:we}=ne,Ae=()=>i(q,N,H),We=()=>{ge(q,()=>{Ae(),we&&we()})};fe?fe(q,Ae,We):We()}else i(q,N,H)},Be=(M,N,H,Z=!1,K=!1)=>{const{type:q,props:ie,ref:ne,children:re,dynamicChildren:J,shapeFlag:le,patchFlag:ge,dirs:fe,cacheIndex:we}=M;if(ge===-2&&(K=!1),ne!=null&&la(ne,null,H,M,!0),we!=null&&(N.renderCache[we]=void 0),le&256){N.ctx.deactivate(M);return}const Ae=le&1&&fe,We=!nr(M);let v;if(We&&(v=ie&&ie.onVnodeBeforeUnmount)&&on(v,N,M),le&6)Je(M.component,H,Z);else{if(le&128){M.suspense.unmount(H,Z);return}Ae&&Un(M,null,N,"beforeUnmount"),le&64?M.type.remove(M,N,H,it,Z):J&&!J.hasOnce&&(q!==Vt||ge>0&&ge&64)?ee(J,N,H,!1,!0):(q===Vt&&ge&384||!K&&le&16)&&ee(re,N,H),Z&&tt(M)}(We&&(v=ie&&ie.onVnodeUnmounted)||Ae)&&Pt(()=>{v&&on(v,N,M),Ae&&Un(M,null,N,"unmounted")},H)},tt=M=>{const{type:N,el:H,anchor:Z,transition:K}=M;if(N===Vt){He(H,Z);return}if(N===ir){w(M);return}const q=()=>{r(H),K&&!K.persisted&&K.afterLeave&&K.afterLeave()};if(M.shapeFlag&1&&K&&!K.persisted){const{leave:ie,delayLeave:ne}=K,re=()=>ie(H,q);ne?ne(M.el,q,re):re()}else q()},He=(M,N)=>{let H;for(;M!==N;)H=h(M),r(M),M=H;r(N)},Je=(M,N,H)=>{const{bum:Z,scope:K,update:q,subTree:ie,um:ne,m:re,a:J}=M;ca(re),ca(J),Z&&Qi(Z),K.stop(),q&&(q.active=!1,Be(ie,M,N,H)),ne&&Pt(ne,N),Pt(()=>{M.isUnmounted=!0},N),N&&N.pendingBranch&&!N.isUnmounted&&M.asyncDep&&!M.asyncResolved&&M.suspenseId===N.pendingId&&(N.deps--,N.deps===0&&N.resolve())},ee=(M,N,H,Z=!1,K=!1,q=0)=>{for(let ie=q;ie{if(M.shapeFlag&6)return ue(M.component.subTree);if(M.shapeFlag&128)return M.suspense.next();const N=h(M.anchor||M.el),H=N&&N[um];return H?h(H):N};let Ne=!1;const Te=(M,N,H)=>{M==null?N._vnode&&Be(N._vnode,null,null,!0):g(N._vnode||null,M,N,null,null,null,H),Ne||(Ne=!0,$f(),sa(),Ne=!1),N._vnode=M},it={p:g,um:Be,m:Ie,r:tt,mt:$,mc:F,pc:Q,pbc:I,n:ue,o:e};let st,rt;return n&&([st,rt]=n(it)),{render:Te,hydrate:st,createApp:Fb(Te,st)}}function kl({type:e,props:n},t){return t==="svg"&&e==="foreignObject"||t==="mathml"&&e==="annotation-xml"&&n&&n.encoding&&n.encoding.includes("html")?void 0:t}function Bi({effect:e,update:n},t){e.allowRecurse=n.allowRecurse=t}function mm(e,n){return(!e||e&&!e.pendingBranch)&&n&&!n.persisted}function Mu(e,n,t=!1){const i=e.children,r=n.children;if(pe(i)&&pe(r))for(let o=0;o>1,e[t[a]]0&&(n[i]=t[o-1]),t[o]=i)}}for(o=t.length,s=t[o-1];o-- >0;)t[o]=s,s=n[s];return t}function gm(e){const n=e.subTree.component;if(n)return n.asyncDep&&!n.asyncResolved?n:gm(n)}function ca(e){if(e)for(let n=0;nTo(vm);function qb(e,n){return qo(e,null,n)}function Em(e,n){return qo(e,null,{flush:"post"})}function bm(e,n){return qo(e,null,{flush:"sync"})}const Ts={};function Do(e,n,t){return qo(e,n,t)}function qo(e,n,{immediate:t,deep:i,flush:r,once:o,onTrack:s,onTrigger:a}=Ze){if(n&&o){const A=n;n=(...k)=>{A(...k),x()}}const l=Mt,c=A=>i===!0?A:wi(A,i===!1?1:void 0);let u,f=!1,h=!1;if(Bt(e)?(u=()=>e.value,f=sr(e)):tr(e)?(u=()=>c(e),f=!0):pe(e)?(h=!0,f=e.some(A=>tr(A)||sr(A)),u=()=>e.map(A=>{if(Bt(A))return A.value;if(tr(A))return c(A);if(Ce(A))return oi(A,l,2)})):Ce(e)?n?u=()=>oi(e,l,2):u=()=>(p&&p(),Tn(e,l,3,[m])):u=wt,n&&i){const A=u;u=()=>wi(A())}let p,m=A=>{p=b.onStop=()=>{oi(A,l,4),p=b.onStop=void 0}},g;if(es)if(m=wt,n?t&&Tn(n,l,3,[u(),h?[]:void 0,m]):u(),r==="sync"){const A=ym();g=A.__watcherHandles||(A.__watcherHandles=[])}else return wt;let E=h?new Array(e.length).fill(Ts):Ts;const D=()=>{if(!(!b.active||!b.dirty))if(n){const A=b.run();(i||f||(h?A.some((k,F)=>Mn(k,E[F])):Mn(A,E)))&&(p&&p(),Tn(n,l,3,[A,E===Ts?void 0:h&&E[0]===Ts?[]:E,m]),E=A)}else b.run()};D.allowRecurse=!!n;let T;r==="sync"?T=D:r==="post"?T=()=>Pt(D,l&&l.suspense):(D.pre=!0,l&&(D.id=l.uid),T=()=>Ya(D));const b=new Rr(u,wt,T),w=dp(),x=()=>{b.stop(),w&&ka(w.effects,b)};return n?t?D():E=b.run():r==="post"?Pt(b.run.bind(b),l&&l.suspense):b.run(),g&&g.push(x),x}function e0(e,n,t){const i=this.proxy,r=Me(e)?e.includes(".")?Sm(i,e):()=>i[e]:e.bind(i,i);let o;Ce(n)?o=n:(o=n.handler,t=n);const s=lr(this),a=qo(r,o.bind(i),t);return s(),a}function Sm(e,n){const t=n.split(".");return()=>{let i=e;for(let r=0;r{wi(i,n,t)});else if(iu(e)){for(const i in e)wi(e[i],n,t);for(const i of Object.getOwnPropertySymbols(e))Object.prototype.propertyIsEnumerable.call(e,i)&&wi(e[i],n,t)}return e}function t0(e,n,t=Ze){const i=fi(),r=ut(n),o=Yt(n),s=Tm(e,n),a=Mp((l,c)=>{let u,f,h;return bm(()=>{const p=e[n];Mn(u,p)&&(u=p,c())}),{get(){return l(),t.get?t.get(u):u},set(p){if(!Mn(p,u))return;const m=i.vnode.props;m&&(n in m||r in m||o in m)&&(`onUpdate:${n}`in m||`onUpdate:${r}`in m||`onUpdate:${o}`in m)||(u=p,c());const g=t.set?t.set(p):p;i.emit(`update:${n}`,g),p!==g&&p!==f&&g===h&&c(),f=p,h=g}}});return a[Symbol.iterator]=()=>{let l=0;return{next(){return l<2?{value:l++?s||Ze:a,done:!1}:{done:!0}}}},a}const Tm=(e,n)=>n==="modelValue"||n==="model-value"?e.modelModifiers:e[`${n}Modifiers`]||e[`${ut(n)}Modifiers`]||e[`${Yt(n)}Modifiers`];function n0(e,n,...t){if(e.isUnmounted)return;const i=e.vnode.props||Ze;let r=t;const o=n.startsWith("update:"),s=o&&Tm(i,n.slice(7));s&&(s.trim&&(r=t.map(u=>Me(u)?u.trim():u)),s.number&&(r=t.map(Po)));let a,l=i[a=Ji(n)]||i[a=Ji(ut(n))];!l&&o&&(l=i[a=Ji(Yt(n))]),l&&Tn(l,e,6,r);const c=i[a+"Once"];if(c){if(!e.emitted)e.emitted={};else if(e.emitted[a])return;e.emitted[a]=!0,Tn(c,e,6,r)}}function wm(e,n,t=!1){const i=n.emitsCache,r=i.get(e);if(r!==void 0)return r;const o=e.emits;let s={},a=!1;if(!Ce(e)){const l=c=>{const u=wm(c,n,!0);u&&(a=!0,Ke(s,u))};!t&&n.mixins.length&&n.mixins.forEach(l),e.extends&&l(e.extends),e.mixins&&e.mixins.forEach(l)}return!o&&!a?(et(e)&&i.set(e,null),null):(pe(o)?o.forEach(l=>s[l]=null):Ke(s,o),et(e)&&i.set(e,s),s)}function Qa(e,n){return!e||!Ri(n)?!1:(n=n.slice(2).replace(/Once$/,""),ze(e,n[0].toLowerCase()+n.slice(1))||ze(e,Yt(n))||ze(e,n))}function $s(e){const{type:n,vnode:t,proxy:i,withProxy:r,propsOptions:[o],slots:s,attrs:a,emit:l,render:c,renderCache:u,props:f,data:h,setupState:p,ctx:m,inheritAttrs:g}=e,E=Vo(e);let D,T;try{if(t.shapeFlag&4){const w=r||i,x=w;D=an(c.call(x,w,u,f,p,h,m)),T=a}else{const w=n;D=an(w.length>1?w(f,{attrs:a,slots:s,emit:l}):w(f,null)),T=n.props?a:r0(a)}}catch(w){Co.length=0,gr(w,e,1),D=ct(Rt)}let b=D;if(T&&g!==!1){const w=Object.keys(T),{shapeFlag:x}=b;w.length&&x&7&&(o&&w.some(La)&&(T=o0(T,o)),b=zn(b,T,!1,!0))}return t.dirs&&(b=zn(b,null,!1,!0),b.dirs=b.dirs?b.dirs.concat(t.dirs):t.dirs),t.transition&&(b.transition=t.transition),D=b,Vo(E),D}function i0(e,n=!0){let t;for(let i=0;i{let n;for(const t in e)(t==="class"||t==="style"||Ri(t))&&((n||(n={}))[t]=e[t]);return n},o0=(e,n)=>{const t={};for(const i in e)(!La(i)||!(i.slice(9)in n))&&(t[i]=e[i]);return t};function s0(e,n,t){const{props:i,children:r,component:o}=e,{props:s,children:a,patchFlag:l}=n,c=o.emitsOptions;if(n.dirs||n.transition)return!0;if(t&&l>=0){if(l&1024)return!0;if(l&16)return i?ed(i,s,c):!!s;if(l&8){const u=n.dynamicProps;for(let f=0;fe.__isSuspense;let Dc=0;const a0={name:"Suspense",__isSuspense:!0,process(e,n,t,i,r,o,s,a,l,c){if(e==null)c0(n,t,i,r,o,s,a,l,c);else{if(o&&o.deps>0&&!e.suspense.isInFallback){n.suspense=e.suspense,n.suspense.vnode=n,n.el=e.el;return}u0(e,n,t,i,r,s,a,l,c)}},hydrate:f0,normalize:d0},l0=a0;function jo(e,n){const t=e.props&&e.props[n];Ce(t)&&t()}function c0(e,n,t,i,r,o,s,a,l){const{p:c,o:{createElement:u}}=l,f=u("div"),h=e.suspense=Dm(e,r,i,n,f,t,o,s,a,l);c(null,h.pendingBranch=e.ssContent,f,null,i,h,o,s),h.deps>0?(jo(e,"onPending"),jo(e,"onFallback"),c(null,e.ssFallback,n,t,i,null,o,s),Mr(h,e.ssFallback)):h.resolve(!1,!0)}function u0(e,n,t,i,r,o,s,a,{p:l,um:c,o:{createElement:u}}){const f=n.suspense=e.suspense;f.vnode=n,n.el=e.el;const h=n.ssContent,p=n.ssFallback,{activeBranch:m,pendingBranch:g,isInFallback:E,isHydrating:D}=f;if(g)f.pendingBranch=h,Fn(h,g)?(l(g,h,f.hiddenContainer,null,r,f,o,s,a),f.deps<=0?f.resolve():E&&(D||(l(m,p,t,i,r,null,o,s,a),Mr(f,p)))):(f.pendingId=Dc++,D?(f.isHydrating=!1,f.activeBranch=g):c(g,r,f),f.deps=0,f.effects.length=0,f.hiddenContainer=u("div"),E?(l(null,h,f.hiddenContainer,null,r,f,o,s,a),f.deps<=0?f.resolve():(l(m,p,t,i,r,null,o,s,a),Mr(f,p))):m&&Fn(h,m)?(l(m,h,t,i,r,f,o,s,a),f.resolve(!0)):(l(null,h,f.hiddenContainer,null,r,f,o,s,a),f.deps<=0&&f.resolve()));else if(m&&Fn(h,m))l(m,h,t,i,r,f,o,s,a),Mr(f,h);else if(jo(n,"onPending"),f.pendingBranch=h,h.shapeFlag&512?f.pendingId=h.component.suspenseId:f.pendingId=Dc++,l(null,h,f.hiddenContainer,null,r,f,o,s,a),f.deps<=0)f.resolve();else{const{timeout:T,pendingId:b}=f;T>0?setTimeout(()=>{f.pendingId===b&&f.fallback(p)},T):T===0&&f.fallback(p)}}function Dm(e,n,t,i,r,o,s,a,l,c,u=!1){const{p:f,m:h,um:p,n:m,o:{parentNode:g,remove:E}}=c;let D;const T=h0(e);T&&n&&n.pendingBranch&&(D=n.pendingId,n.deps++);const b=e.props?Ro(e.props.timeout):void 0,w=o,x={vnode:e,parent:n,parentComponent:t,namespace:s,container:i,hiddenContainer:r,deps:0,pendingId:Dc++,timeout:typeof b=="number"?b:-1,activeBranch:null,pendingBranch:null,isInFallback:!u,isHydrating:u,isUnmounted:!1,effects:[],resolve(A=!1,k=!1){const{vnode:F,activeBranch:O,pendingBranch:I,pendingId:j,effects:R,parentComponent:L,container:$}=x;let G=!1;x.isHydrating?x.isHydrating=!1:A||(G=O&&I.transition&&I.transition.mode==="out-in",G&&(O.transition.afterLeave=()=>{j===x.pendingId&&(h(I,$,o===w?m(O):o,0),oa(R))}),O&&(g(O.el)!==x.hiddenContainer&&(o=m(O)),p(O,L,x,!0)),G||h(I,$,o,0)),Mr(x,I),x.pendingBranch=null,x.isInFallback=!1;let B=x.parent,Y=!1;for(;B;){if(B.pendingBranch){B.effects.push(...R),Y=!0;break}B=B.parent}!Y&&!G&&oa(R),x.effects=[],T&&n&&n.pendingBranch&&D===n.pendingId&&(n.deps--,n.deps===0&&!k&&n.resolve()),jo(F,"onResolve")},fallback(A){if(!x.pendingBranch)return;const{vnode:k,activeBranch:F,parentComponent:O,container:I,namespace:j}=x;jo(k,"onFallback");const R=m(F),L=()=>{x.isInFallback&&(f(null,A,I,R,O,null,j,a,l),Mr(x,A))},$=A.transition&&A.transition.mode==="out-in";$&&(F.transition.afterLeave=L),x.isInFallback=!0,p(F,O,null,!0),$||L()},move(A,k,F){x.activeBranch&&h(x.activeBranch,A,k,F),x.container=A},next(){return x.activeBranch&&m(x.activeBranch)},registerDep(A,k,F){const O=!!x.pendingBranch;O&&x.deps++;const I=A.vnode.el;A.asyncDep.catch(j=>{gr(j,A,0)}).then(j=>{if(A.isUnmounted||x.isUnmounted||x.pendingId!==A.suspenseId)return;A.asyncResolved=!0;const{vnode:R}=A;xc(A,j,!1),I&&(R.el=I);const L=!I&&A.subTree.el;k(A,R,g(I||A.subTree.el),I?null:m(A.subTree),x,s,F),L&&E(L),Iu(A,R.el),O&&--x.deps===0&&x.resolve()})},unmount(A,k){x.isUnmounted=!0,x.activeBranch&&p(x.activeBranch,t,A,k),x.pendingBranch&&p(x.pendingBranch,t,A,k)}};return x}function f0(e,n,t,i,r,o,s,a,l){const c=n.suspense=Dm(n,i,t,e.parentNode,document.createElement("div"),null,r,o,s,a,!0),u=l(e,c.pendingBranch=n.ssContent,t,c,o,s);return c.deps===0&&c.resolve(!1,!0),u}function d0(e){const{shapeFlag:n,children:t}=e,i=n&32;e.ssContent=td(i?t.default:t),e.ssFallback=i?td(t.fallback):ct(Rt)}function td(e){let n;if(Ce(e)){const t=ar&&e._c;t&&(e._d=!1,qa()),e=e(),t&&(e._d=!0,n=Xt,Om())}return pe(e)&&(e=i0(e)),e=an(e),n&&!e.dynamicChildren&&(e.dynamicChildren=n.filter(t=>t!==e)),e}function Cm(e,n){n&&n.pendingBranch?pe(e)?n.effects.push(...e):n.effects.push(e):oa(e)}function Mr(e,n){e.activeBranch=n;const{vnode:t,parentComponent:i}=e;let r=n.el;for(;!r&&n.component;)n=n.component.subTree,r=n.el;t.el=r,i&&i.subTree===t&&(i.vnode.el=r,Iu(i,r))}function h0(e){const n=e.props&&e.props.suspensible;return n!=null&&n!==!1}const Vt=Symbol.for("v-fgt"),xi=Symbol.for("v-txt"),Rt=Symbol.for("v-cmt"),ir=Symbol.for("v-stc"),Co=[];let Xt=null;function qa(e=!1){Co.push(Xt=e?null:[])}function Om(){Co.pop(),Xt=Co[Co.length-1]||null}let ar=1;function Cc(e){ar+=e,e<0&&Xt&&(Xt.hasOnce=!0)}function Am(e){return e.dynamicChildren=ar>0?Xt||Gi:null,Om(),ar>0&&Xt&&Xt.push(e),e}function p0(e,n,t,i,r,o){return Am(Pu(e,n,t,i,r,o,!0))}function Nu(e,n,t,i,r){return Am(ct(e,n,t,i,r,!0))}function Ii(e){return e?e.__v_isVNode===!0:!1}function Fn(e,n){return e.type===n.type&&e.key===n.key}function m0(e){}const xm=({key:e})=>e??null,Hs=({ref:e,ref_key:n,ref_for:t})=>(typeof e=="number"&&(e=""+e),e!=null?Me(e)||Bt(e)||Ce(e)?{i:It,r:e,k:n,f:!!t}:e:null);function Pu(e,n=null,t=null,i=0,r=null,o=e===Vt?0:1,s=!1,a=!1){const l={__v_isVNode:!0,__v_skip:!0,type:e,props:n,key:n&&xm(n),ref:n&&Hs(n),scopeId:za,slotScopeIds:null,children:t,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetStart:null,targetAnchor:null,staticCount:0,shapeFlag:o,patchFlag:i,dynamicProps:r,dynamicChildren:null,appContext:null,ctx:It};return a?(Lu(l,t),o&128&&e.normalize(l)):t&&(l.shapeFlag|=Me(t)?8:16),ar>0&&!s&&Xt&&(l.patchFlag>0||o&6)&&l.patchFlag!==32&&Xt.push(l),l}const ct=g0;function g0(e,n=null,t=null,i=0,r=null,o=!1){if((!e||e===Gp)&&(e=Rt),Ii(e)){const a=zn(e,n,!0);return t&&Lu(a,t),ar>0&&!o&&Xt&&(a.shapeFlag&6?Xt[Xt.indexOf(e)]=a:Xt.push(a)),a.patchFlag=-2,a}if(D0(e)&&(e=e.__vccOpts),n){n=_m(n);let{class:a,style:l}=n;a&&!Me(a)&&(n.class=Kr(a)),et(l)&&(gu(l)&&!pe(l)&&(l=Ke({},l)),n.style=zr(l))}const s=Me(e)?1:wc(e)?128:Yb(e)?64:et(e)?4:Ce(e)?2:0;return Pu(e,n,t,i,r,s,o,!0)}function _m(e){return e?gu(e)||im(e)?Ke({},e):e:null}function zn(e,n,t=!1,i=!1){const{props:r,ref:o,patchFlag:s,children:a,transition:l}=e,c=n?Mm(r||{},n):r,u={__v_isVNode:!0,__v_skip:!0,type:e.type,props:c,key:c&&xm(c),ref:n&&n.ref?t&&o?pe(o)?o.concat(Hs(n)):[o,Hs(n)]:Hs(n):o,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:a,target:e.target,targetStart:e.targetStart,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:n&&e.type!==Vt?s===-1?16:s|16:s,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:l,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&zn(e.ssContent),ssFallback:e.ssFallback&&zn(e.ssFallback),el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce};return l&&i&&Mi(u,l.clone(u)),u}function Ru(e=" ",n=0){return ct(xi,null,e,n)}function v0(e,n){const t=ct(ir,null,e);return t.staticCount=n,t}function y0(e="",n=!1){return n?(qa(),Nu(Rt,null,e)):ct(Rt,null,e)}function an(e){return e==null||typeof e=="boolean"?ct(Rt):pe(e)?ct(Vt,null,e.slice()):typeof e=="object"?bi(e):ct(xi,null,String(e))}function bi(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:zn(e)}function Lu(e,n){let t=0;const{shapeFlag:i}=e;if(n==null)n=null;else if(pe(n))t=16;else if(typeof n=="object")if(i&65){const r=n.default;r&&(r._c&&(r._d=!1),Lu(e,r()),r._c&&(r._d=!0));return}else{t=32;const r=n._;!r&&!im(n)?n._ctx=It:r===3&&It&&(It.slots._===1?n._=1:(n._=2,e.patchFlag|=1024))}else Ce(n)?(n={default:n,_ctx:It},t=32):(n=String(n),i&64?(t=16,n=[Ru(n)]):t=8);e.children=n,e.shapeFlag|=t}function Mm(...e){const n={};for(let t=0;tMt||It;let ua,Oc;{const e=ou(),n=(t,i)=>{let r;return(r=e[t])||(r=e[t]=[]),r.push(i),o=>{r.length>1?r.forEach(s=>s(o)):r[0](o)}};ua=n("__VUE_INSTANCE_SETTERS__",t=>Mt=t),Oc=n("__VUE_SSR_SETTERS__",t=>es=t)}const lr=e=>{const n=Mt;return ua(e),e.scope.on(),()=>{e.scope.off(),ua(n)}},Ac=()=>{Mt&&Mt.scope.off(),ua(null)};function Nm(e){return e.vnode.shapeFlag&4}let es=!1;function Pm(e,n=!1,t=!1){n&&Oc(n);const{props:i,children:r}=e.vnode,o=Nm(e);Bb(e,i,o,n),Ub(e,r,t);const s=o?S0(e,n):void 0;return n&&Oc(!1),s}function S0(e,n){const t=e.type;e.accessCache=Object.create(null),e.proxy=new Proxy(e.ctx,yc);const{setup:i}=t;if(i){const r=e.setupContext=i.length>1?km(e):null,o=lr(e);Fi();const s=oi(i,e,0,[e.props,r]);if(Vi(),o(),Fa(s)){if(s.then(Ac,Ac),n)return s.then(a=>{xc(e,a,n)}).catch(a=>{gr(a,e,0)});e.asyncDep=s}else xc(e,s,n)}else Lm(e,n)}function xc(e,n,t){Ce(n)?e.type.__ssrInlineRender?e.ssrRender=n:e.render=n:et(n)&&(e.setupState=bu(n)),Lm(e,t)}let fa,_c;function Rm(e){fa=e,_c=n=>{n.render._rc&&(n.withProxy=new Proxy(n.ctx,vb))}}const T0=()=>!fa;function Lm(e,n,t){const i=e.type;if(!e.render){if(!n&&fa&&!i.render){const r=i.template||xu(e).template;if(r){const{isCustomElement:o,compilerOptions:s}=e.appContext.config,{delimiters:a,compilerOptions:l}=i,c=Ke(Ke({isCustomElement:o,delimiters:a},s),l);i.render=fa(r,c)}}e.render=i.render||wt,_c&&_c(e)}{const r=lr(e);Fi();try{Ib(e)}finally{Vi(),r()}}}const w0={get(e,n){return un(e,"get",""),e[n]}};function km(e){const n=t=>{e.exposed=t||{}};return{attrs:new Proxy(e.attrs,w0),slots:e.slots,emit:e.emit,expose:n}}function ts(e){return e.exposed?e.exposeProxy||(e.exposeProxy=new Proxy(bu(Ap(e.exposed)),{get(n,t){if(t in n)return n[t];if(t in So)return So[t](e)},has(n,t){return t in n||t in So}})):e.proxy}function Mc(e,n=!0){return Ce(e)?e.displayName||e.name:e.name||n&&e.__name}function D0(e){return Ce(e)&&"__vccOpts"in e}const Fm=(e,n)=>LE(e,n,es);function ku(e,n,t){const i=arguments.length;return i===2?et(n)&&!pe(n)?Ii(n)?ct(e,null,[n]):ct(e,n):ct(e,null,n):(i>3?t=Array.prototype.slice.call(arguments,2):i===3&&Ii(t)&&(t=[t]),ct(e,n,t))}function C0(){}function O0(e,n,t,i){const r=t[i];if(r&&Vm(r,e))return r;const o=n();return o.memo=e.slice(),o.cacheIndex=i,t[i]=o}function Vm(e,n){const t=e.memo;if(t.length!=n.length)return!1;for(let i=0;i0&&Xt&&Xt.push(e),!0}const Bm="3.4.32",A0=wt,x0=ZE,_0=Dr,M0=Lp,I0={createComponentInstance:Im,setupComponent:Pm,renderComponentRoot:$s,setCurrentRenderingInstance:Vo,isVNode:Ii,normalizeVNode:an,getComponentPublicInstance:ts},N0=I0,P0=null,R0=null,L0=null;/** -* @vue/runtime-dom v3.4.32 -* (c) 2018-present Yuxi (Evan) You and Vue contributors -* @license MIT -**/const k0="http://www.w3.org/2000/svg",F0="http://www.w3.org/1998/Math/MathML",qn=typeof document<"u"?document:null,nd=qn&&qn.createElement("template"),V0={insert:(e,n,t)=>{n.insertBefore(e,t||null)},remove:e=>{const n=e.parentNode;n&&n.removeChild(e)},createElement:(e,n,t,i)=>{const r=n==="svg"?qn.createElementNS(k0,e):n==="mathml"?qn.createElementNS(F0,e):t?qn.createElement(e,{is:t}):qn.createElement(e);return e==="select"&&i&&i.multiple!=null&&r.setAttribute("multiple",i.multiple),r},createText:e=>qn.createTextNode(e),createComment:e=>qn.createComment(e),setText:(e,n)=>{e.nodeValue=n},setElementText:(e,n)=>{e.textContent=n},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>qn.querySelector(e),setScopeId(e,n){e.setAttribute(n,"")},insertStaticContent(e,n,t,i,r,o){const s=t?t.previousSibling:n.lastChild;if(r&&(r===o||r.nextSibling))for(;n.insertBefore(r.cloneNode(!0),t),!(r===o||!(r=r.nextSibling)););else{nd.innerHTML=i==="svg"?`${e}`:i==="mathml"?`${e}`:e;const a=nd.content;if(i==="svg"||i==="mathml"){const l=a.firstChild;for(;l.firstChild;)a.appendChild(l.firstChild);a.removeChild(l)}n.insertBefore(a,t)}return[s?s.nextSibling:n.firstChild,t?t.previousSibling:n.lastChild]}},pi="transition",eo="animation",kr=Symbol("_vtc"),Fu=(e,{slots:n})=>ku(Fp,$m(e),n);Fu.displayName="Transition";const jm={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String},B0=Fu.props=Ke({},Du,jm),ji=(e,n=[])=>{pe(e)?e.forEach(t=>t(...n)):e&&e(...n)},id=e=>e?pe(e)?e.some(n=>n.length>1):e.length>1:!1;function $m(e){const n={};for(const R in e)R in jm||(n[R]=e[R]);if(e.css===!1)return n;const{name:t="v",type:i,duration:r,enterFromClass:o=`${t}-enter-from`,enterActiveClass:s=`${t}-enter-active`,enterToClass:a=`${t}-enter-to`,appearFromClass:l=o,appearActiveClass:c=s,appearToClass:u=a,leaveFromClass:f=`${t}-leave-from`,leaveActiveClass:h=`${t}-leave-active`,leaveToClass:p=`${t}-leave-to`}=e,m=j0(r),g=m&&m[0],E=m&&m[1],{onBeforeEnter:D,onEnter:T,onEnterCancelled:b,onLeave:w,onLeaveCancelled:x,onBeforeAppear:A=D,onAppear:k=T,onAppearCancelled:F=b}=n,O=(R,L,$)=>{vi(R,L?u:a),vi(R,L?c:s),$&&$()},I=(R,L)=>{R._isLeaving=!1,vi(R,f),vi(R,p),vi(R,h),L&&L()},j=R=>(L,$)=>{const G=R?k:T,B=()=>O(L,R,$);ji(G,[L,B]),rd(()=>{vi(L,R?l:o),Gn(L,R?u:a),id(G)||od(L,i,g,B)})};return Ke(n,{onBeforeEnter(R){ji(D,[R]),Gn(R,o),Gn(R,s)},onBeforeAppear(R){ji(A,[R]),Gn(R,l),Gn(R,c)},onEnter:j(!1),onAppear:j(!0),onLeave(R,L){R._isLeaving=!0;const $=()=>I(R,L);Gn(R,f),Gn(R,h),Um(),rd(()=>{R._isLeaving&&(vi(R,f),Gn(R,p),id(w)||od(R,i,E,$))}),ji(w,[R,$])},onEnterCancelled(R){O(R,!1),ji(b,[R])},onAppearCancelled(R){O(R,!0),ji(F,[R])},onLeaveCancelled(R){I(R),ji(x,[R])}})}function j0(e){if(e==null)return null;if(et(e))return[Fl(e.enter),Fl(e.leave)];{const n=Fl(e);return[n,n]}}function Fl(e){return Ro(e)}function Gn(e,n){n.split(/\s+/).forEach(t=>t&&e.classList.add(t)),(e[kr]||(e[kr]=new Set)).add(n)}function vi(e,n){n.split(/\s+/).forEach(i=>i&&e.classList.remove(i));const t=e[kr];t&&(t.delete(n),t.size||(e[kr]=void 0))}function rd(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let $0=0;function od(e,n,t,i){const r=e._endId=++$0,o=()=>{r===e._endId&&i()};if(t)return setTimeout(o,t);const{type:s,timeout:a,propCount:l}=Hm(e,n);if(!s)return i();const c=s+"end";let u=0;const f=()=>{e.removeEventListener(c,h),o()},h=p=>{p.target===e&&++u>=l&&f()};setTimeout(()=>{u(t[m]||"").split(", "),r=i(`${pi}Delay`),o=i(`${pi}Duration`),s=sd(r,o),a=i(`${eo}Delay`),l=i(`${eo}Duration`),c=sd(a,l);let u=null,f=0,h=0;n===pi?s>0&&(u=pi,f=s,h=o.length):n===eo?c>0&&(u=eo,f=c,h=l.length):(f=Math.max(s,c),u=f>0?s>c?pi:eo:null,h=u?u===pi?o.length:l.length:0);const p=u===pi&&/\b(transform|all)(,|$)/.test(i(`${pi}Property`).toString());return{type:u,timeout:f,propCount:h,hasTransform:p}}function sd(e,n){for(;e.lengthad(t)+ad(e[i])))}function ad(e){return e==="auto"?0:Number(e.slice(0,-1).replace(",","."))*1e3}function Um(){return document.body.offsetHeight}function H0(e,n,t){const i=e[kr];i&&(n=(n?[n,...i]:[...i]).join(" ")),n==null?e.removeAttribute("class"):t?e.setAttribute("class",n):e.className=n}const da=Symbol("_vod"),Wm=Symbol("_vsh"),Ym={beforeMount(e,{value:n},{transition:t}){e[da]=e.style.display==="none"?"":e.style.display,t&&n?t.beforeEnter(e):to(e,n)},mounted(e,{value:n},{transition:t}){t&&n&&t.enter(e)},updated(e,{value:n,oldValue:t},{transition:i}){!n!=!t&&(i?n?(i.beforeEnter(e),to(e,!0),i.enter(e)):i.leave(e,()=>{to(e,!1)}):to(e,n))},beforeUnmount(e,{value:n}){to(e,n)}};function to(e,n){e.style.display=n?e[da]:"none",e[Wm]=!n}function U0(){Ym.getSSRProps=({value:e})=>{if(!e)return{style:{display:"none"}}}}const zm=Symbol("");function W0(e){const n=fi();if(!n)return;const t=n.ut=(r=e(n.proxy))=>{Array.from(document.querySelectorAll(`[data-v-owner="${n.uid}"]`)).forEach(o=>Nc(o,r))},i=()=>{const r=e(n.proxy);Ic(n.subTree,r),t(r)};Qo(()=>{Em(i);const r=new MutationObserver(i);r.observe(n.subTree.el.parentNode,{childList:!0}),Ja(()=>r.disconnect())})}function Ic(e,n){if(e.shapeFlag&128){const t=e.suspense;e=t.activeBranch,t.pendingBranch&&!t.isHydrating&&t.effects.push(()=>{Ic(t.activeBranch,n)})}for(;e.component;)e=e.component.subTree;if(e.shapeFlag&1&&e.el)Nc(e.el,n);else if(e.type===Vt)e.children.forEach(t=>Ic(t,n));else if(e.type===ir){let{el:t,anchor:i}=e;for(;t&&(Nc(t,n),t!==i);)t=t.nextSibling}}function Nc(e,n){if(e.nodeType===1){const t=e.style;let i="";for(const r in n)t.setProperty(`--${r}`,n[r]),i+=`--${r}: ${n[r]};`;t[zm]=i}}const Y0=/(^|;)\s*display\s*:/;function z0(e,n,t){const i=e.style,r=Me(t);let o=!1;if(t&&!r){if(n)if(Me(n))for(const s of n.split(";")){const a=s.slice(0,s.indexOf(":")).trim();t[a]==null&&Us(i,a,"")}else for(const s in n)t[s]==null&&Us(i,s,"");for(const s in t)s==="display"&&(o=!0),Us(i,s,t[s])}else if(r){if(n!==t){const s=i[zm];s&&(t+=";"+s),i.cssText=t,o=Y0.test(t)}}else n&&e.removeAttribute("style");da in e&&(e[da]=o?i.display:"",e[Wm]&&(i.display="none"))}const ld=/\s*!important$/;function Us(e,n,t){if(pe(t))t.forEach(i=>Us(e,n,i));else if(t==null&&(t=""),n.startsWith("--"))e.setProperty(n,t);else{const i=K0(e,n);ld.test(t)?e.setProperty(Yt(i),t.replace(ld,""),"important"):e[i]=t}}const cd=["Webkit","Moz","ms"],Vl={};function K0(e,n){const t=Vl[n];if(t)return t;let i=ut(n);if(i!=="filter"&&i in e)return Vl[n]=i;i=ki(i);for(let r=0;rBl||(Q0.then(()=>Bl=0),Bl=Date.now());function eS(e,n){const t=i=>{if(!i._vts)i._vts=Date.now();else if(i._vts<=t.attached)return;Tn(tS(i,t.value),n,5,[i])};return t.value=e,t.attached=q0(),t}function tS(e,n){if(pe(n)){const t=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{t.call(e),e._stopped=!0},n.map(i=>r=>!r._stopped&&i&&i(r))}else return n}const pd=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&e.charCodeAt(2)>96&&e.charCodeAt(2)<123,nS=(e,n,t,i,r,o)=>{const s=r==="svg";n==="class"?H0(e,i,s):n==="style"?z0(e,t,i):Ri(n)?La(n)||Z0(e,n,t,i,o):(n[0]==="."?(n=n.slice(1),!0):n[0]==="^"?(n=n.slice(1),!1):iS(e,n,i,s))?(X0(e,n,i),!e.tagName.includes("-")&&(n==="value"||n==="checked"||n==="selected")&&fd(e,n,i,s,o,n!=="value")):(n==="true-value"?e._trueValue=i:n==="false-value"&&(e._falseValue=i),fd(e,n,i,s))};function iS(e,n,t,i){if(i)return!!(n==="innerHTML"||n==="textContent"||n in e&&pd(n)&&Ce(t));if(n==="spellcheck"||n==="draggable"||n==="translate"||n==="form"||n==="list"&&e.tagName==="INPUT"||n==="type"&&e.tagName==="TEXTAREA")return!1;if(n==="width"||n==="height"){const r=e.tagName;if(r==="IMG"||r==="VIDEO"||r==="CANVAS"||r==="SOURCE")return!1}return pd(n)&&Me(t)?!1:n in e}/*! #__NO_SIDE_EFFECTS__ */function Km(e,n,t){const i=Cu(e,n);class r extends el{constructor(s){super(i,s,t)}}return r.def=i,r}/*! #__NO_SIDE_EFFECTS__ */const rS=(e,n)=>Km(e,n,rg),oS=typeof HTMLElement<"u"?HTMLElement:class{};class el extends oS{constructor(n,t={},i){super(),this._def=n,this._props=t,this._instance=null,this._connected=!1,this._resolved=!1,this._numberProps=null,this._ob=null,this.shadowRoot&&i?i(this._createVNode(),this.shadowRoot):(this.attachShadow({mode:"open"}),this._def.__asyncLoader||this._resolveProps(this._def))}connectedCallback(){this._connected=!0,this._instance||(this._resolved?this._update():this._resolveDef())}disconnectedCallback(){this._connected=!1,Wa(()=>{this._connected||(this._ob&&(this._ob.disconnect(),this._ob=null),Pc(null,this.shadowRoot),this._instance=null)})}_resolveDef(){this._resolved=!0;for(let i=0;i{for(const r of i)this._setAttr(r.attributeName)}),this._ob.observe(this,{attributes:!0});const n=(i,r=!1)=>{const{props:o,styles:s}=i;let a;if(o&&!pe(o))for(const l in o){const c=o[l];(c===Number||c&&c.type===Number)&&(l in this._props&&(this._props[l]=Ro(this._props[l])),(a||(a=Object.create(null)))[ut(l)]=!0)}this._numberProps=a,r&&this._resolveProps(i),this._applyStyles(s),this._update()},t=this._def.__asyncLoader;t?t().then(i=>n(i,!0)):n(this._def)}_resolveProps(n){const{props:t}=n,i=pe(t)?t:Object.keys(t||{});for(const r of Object.keys(this))r[0]!=="_"&&i.includes(r)&&this._setProp(r,this[r],!0,!1);for(const r of i.map(ut))Object.defineProperty(this,r,{get(){return this._getProp(r)},set(o){this._setProp(r,o)}})}_setAttr(n){let t=this.hasAttribute(n)?this.getAttribute(n):void 0;const i=ut(n);this._numberProps&&this._numberProps[i]&&(t=Ro(t)),this._setProp(i,t,!1)}_getProp(n){return this._props[n]}_setProp(n,t,i=!0,r=!0){t!==this._props[n]&&(this._props[n]=t,r&&this._instance&&this._update(),i&&(t===!0?this.setAttribute(Yt(n),""):typeof t=="string"||typeof t=="number"?this.setAttribute(Yt(n),t+""):t||this.removeAttribute(Yt(n))))}_update(){Pc(this._createVNode(),this.shadowRoot)}_createVNode(){const n=ct(this._def,Ke({},this._props));return this._instance||(n.ce=t=>{this._instance=t,t.isCE=!0;const i=(o,s)=>{this.dispatchEvent(new CustomEvent(o,{detail:s}))};t.emit=(o,...s)=>{i(o,s),Yt(o)!==o&&i(Yt(o),s)};let r=this;for(;r=r&&(r.parentNode||r.host);)if(r instanceof el){t.parent=r._instance,t.provides=r._instance.provides;break}}),n}_applyStyles(n){n&&n.forEach(t=>{const i=document.createElement("style");i.textContent=t,this.shadowRoot.appendChild(i)})}}function sS(e="$style"){{const n=fi();if(!n)return Ze;const t=n.type.__cssModules;if(!t)return Ze;const i=t[e];return i||Ze}}const Xm=new WeakMap,Gm=new WeakMap,ha=Symbol("_moveCb"),md=Symbol("_enterCb"),Zm={name:"TransitionGroup",props:Ke({},B0,{tag:String,moveClass:String}),setup(e,{slots:n}){const t=fi(),i=wu();let r,o;return Ga(()=>{if(!r.length)return;const s=e.moveClass||`${e.name||"v"}-move`;if(!dS(r[0].el,t.vnode.el,s))return;r.forEach(cS),r.forEach(uS);const a=r.filter(fS);Um(),a.forEach(l=>{const c=l.el,u=c.style;Gn(c,s),u.transform=u.webkitTransform=u.transitionDuration="";const f=c[ha]=h=>{h&&h.target!==c||(!h||/transform$/.test(h.propertyName))&&(c.removeEventListener("transitionend",f),c[ha]=null,vi(c,s))};c.addEventListener("transitionend",f)})}),()=>{const s=Xe(e),a=$m(s);let l=s.tag||Vt;if(r=[],o)for(let c=0;cdelete e.mode;Zm.props;const lS=Zm;function cS(e){const n=e.el;n[ha]&&n[ha](),n[md]&&n[md]()}function uS(e){Gm.set(e,e.el.getBoundingClientRect())}function fS(e){const n=Xm.get(e),t=Gm.get(e),i=n.left-t.left,r=n.top-t.top;if(i||r){const o=e.el.style;return o.transform=o.webkitTransform=`translate(${i}px,${r}px)`,o.transitionDuration="0s",e}}function dS(e,n,t){const i=e.cloneNode(),r=e[kr];r&&r.forEach(a=>{a.split(/\s+/).forEach(l=>l&&i.classList.remove(l))}),t.split(/\s+/).forEach(a=>a&&i.classList.add(a)),i.style.display="none";const o=n.nodeType===1?n:n.parentNode;o.appendChild(i);const{hasTransform:s}=Hm(i);return o.removeChild(i),s}const Ni=e=>{const n=e.props["onUpdate:modelValue"]||!1;return pe(n)?t=>Qi(n,t):n};function hS(e){e.target.composing=!0}function gd(e){const n=e.target;n.composing&&(n.composing=!1,n.dispatchEvent(new Event("input")))}const An=Symbol("_assign"),pa={created(e,{modifiers:{lazy:n,trim:t,number:i}},r){e[An]=Ni(r);const o=i||r.props&&r.props.type==="number";ei(e,n?"change":"input",s=>{if(s.target.composing)return;let a=e.value;t&&(a=a.trim()),o&&(a=Po(a)),e[An](a)}),t&&ei(e,"change",()=>{e.value=e.value.trim()}),n||(ei(e,"compositionstart",hS),ei(e,"compositionend",gd),ei(e,"change",gd))},mounted(e,{value:n}){e.value=n??""},beforeUpdate(e,{value:n,oldValue:t,modifiers:{lazy:i,trim:r,number:o}},s){if(e[An]=Ni(s),e.composing)return;const a=(o||e.type==="number")&&!/^0\d/.test(e.value)?Po(e.value):e.value,l=n??"";a!==l&&(document.activeElement===e&&e.type!=="range"&&(i&&n===t||r&&e.value.trim()===l)||(e.value=l))}},Vu={deep:!0,created(e,n,t){e[An]=Ni(t),ei(e,"change",()=>{const i=e._modelValue,r=Fr(e),o=e.checked,s=e[An];if(pe(i)){const a=Zo(i,r),l=a!==-1;if(o&&!l)s(i.concat(r));else if(!o&&l){const c=[...i];c.splice(a,1),s(c)}}else if(Li(i)){const a=new Set(i);o?a.add(r):a.delete(r),s(a)}else s(Qm(e,o))})},mounted:vd,beforeUpdate(e,n,t){e[An]=Ni(t),vd(e,n,t)}};function vd(e,{value:n,oldValue:t},i){e._modelValue=n,pe(n)?e.checked=Zo(n,i.props.value)>-1:Li(n)?e.checked=n.has(i.props.value):n!==t&&(e.checked=ci(n,Qm(e,!0)))}const Bu={created(e,{value:n},t){e.checked=ci(n,t.props.value),e[An]=Ni(t),ei(e,"change",()=>{e[An](Fr(e))})},beforeUpdate(e,{value:n,oldValue:t},i){e[An]=Ni(i),n!==t&&(e.checked=ci(n,i.props.value))}},Jm={deep:!0,created(e,{value:n,modifiers:{number:t}},i){const r=Li(n);ei(e,"change",()=>{const o=Array.prototype.filter.call(e.options,s=>s.selected).map(s=>t?Po(Fr(s)):Fr(s));e[An](e.multiple?r?new Set(o):o:o[0]),e._assigning=!0,Wa(()=>{e._assigning=!1})}),e[An]=Ni(i)},mounted(e,{value:n,modifiers:{number:t}}){yd(e,n)},beforeUpdate(e,n,t){e[An]=Ni(t)},updated(e,{value:n,modifiers:{number:t}}){e._assigning||yd(e,n)}};function yd(e,n,t){const i=e.multiple,r=pe(n);if(!(i&&!r&&!Li(n))){for(let o=0,s=e.options.length;oString(u)===String(l)):a.selected=Zo(n,l)>-1}else a.selected=n.has(l);else if(ci(Fr(a),n)){e.selectedIndex!==o&&(e.selectedIndex=o);return}}!i&&e.selectedIndex!==-1&&(e.selectedIndex=-1)}}function Fr(e){return"_value"in e?e._value:e.value}function Qm(e,n){const t=n?"_trueValue":"_falseValue";return t in e?e[t]:n}const qm={created(e,n,t){ws(e,n,t,null,"created")},mounted(e,n,t){ws(e,n,t,null,"mounted")},beforeUpdate(e,n,t,i){ws(e,n,t,i,"beforeUpdate")},updated(e,n,t,i){ws(e,n,t,i,"updated")}};function eg(e,n){switch(e){case"SELECT":return Jm;case"TEXTAREA":return pa;default:switch(n){case"checkbox":return Vu;case"radio":return Bu;default:return pa}}}function ws(e,n,t,i,r){const s=eg(e.tagName,t.props&&t.props.type)[r];s&&s(e,n,t,i)}function pS(){pa.getSSRProps=({value:e})=>({value:e}),Bu.getSSRProps=({value:e},n)=>{if(n.props&&ci(n.props.value,e))return{checked:!0}},Vu.getSSRProps=({value:e},n)=>{if(pe(e)){if(n.props&&Zo(e,n.props.value)>-1)return{checked:!0}}else if(Li(e)){if(n.props&&e.has(n.props.value))return{checked:!0}}else if(e)return{checked:!0}},qm.getSSRProps=(e,n)=>{if(typeof n.type!="string")return;const t=eg(n.type.toUpperCase(),n.props&&n.props.type);if(t.getSSRProps)return t.getSSRProps(e,n)}}const mS=["ctrl","shift","alt","meta"],gS={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&e.button!==0,middle:e=>"button"in e&&e.button!==1,right:e=>"button"in e&&e.button!==2,exact:(e,n)=>mS.some(t=>e[`${t}Key`]&&!n.includes(t))},vS=(e,n)=>{const t=e._withMods||(e._withMods={}),i=n.join(".");return t[i]||(t[i]=(r,...o)=>{for(let s=0;s{const t=e._withKeys||(e._withKeys={}),i=n.join(".");return t[i]||(t[i]=r=>{if(!("key"in r))return;const o=Yt(r.key);if(n.some(s=>s===o||yS[s]===o))return e(r)})},tg=Ke({patchProp:nS},V0);let Oo,Ed=!1;function ng(){return Oo||(Oo=dm(tg))}function ig(){return Oo=Ed?Oo:hm(tg),Ed=!0,Oo}const Pc=(...e)=>{ng().render(...e)},rg=(...e)=>{ig().hydrate(...e)},og=(...e)=>{const n=ng().createApp(...e),{mount:t}=n;return n.mount=i=>{const r=ag(i);if(!r)return;const o=n._component;!Ce(o)&&!o.render&&!o.template&&(o.template=r.innerHTML),r.innerHTML="";const s=t(r,!1,sg(r));return r instanceof Element&&(r.removeAttribute("v-cloak"),r.setAttribute("data-v-app","")),s},n},bS=(...e)=>{const n=ig().createApp(...e),{mount:t}=n;return n.mount=i=>{const r=ag(i);if(r)return t(r,!0,sg(r))},n};function sg(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function ag(e){return Me(e)?document.querySelector(e):e}let bd=!1;const SS=()=>{bd||(bd=!0,pS(),U0())},lg=Object.freeze(Object.defineProperty({__proto__:null,BaseTransition:Fp,BaseTransitionPropsValidators:Du,Comment:Rt,DeprecationTypes:L0,EffectScope:fu,ErrorCodes:GE,ErrorTypeStrings:x0,Fragment:Vt,KeepAlive:lb,ReactiveEffect:Rr,Static:ir,Suspense:l0,Teleport:Xb,Text:xi,TrackOpTypes:zE,Transition:Fu,TransitionGroup:lS,TriggerOpTypes:KE,VueElement:el,assertNumber:XE,callWithAsyncErrorHandling:Tn,callWithErrorHandling:oi,camelize:ut,capitalize:ki,cloneVNode:zn,compatUtils:R0,computed:Fm,createApp:og,createBlock:Nu,createCommentVNode:y0,createElementBlock:p0,createElementVNode:Pu,createHydrationRenderer:hm,createPropsRestProxy:_b,createRenderer:dm,createSSRApp:bS,createSlots:pb,createStaticVNode:v0,createTextVNode:Ru,createVNode:ct,customRef:Mp,defineAsyncComponent:sb,defineComponent:Cu,defineCustomElement:Km,defineEmits:Eb,defineExpose:bb,defineModel:wb,defineOptions:Sb,defineProps:yb,defineSSRCustomElement:rS,defineSlots:Tb,devtools:_0,effect:hE,effectScope:uE,getCurrentInstance:fi,getCurrentScope:dp,getTransitionRawChildren:Ka,guardReactiveProps:_m,h:ku,handleError:gr,hasInjectionContext:Vb,hydrate:rg,initCustomFormatter:C0,initDirectivesForSSR:SS,inject:To,isMemoSame:Vm,isProxy:gu,isReactive:tr,isReadonly:_i,isRef:Bt,isRuntimeOnly:T0,isShallow:sr,isVNode:Ii,markRaw:Ap,mergeDefaults:Ab,mergeModels:xb,mergeProps:Mm,nextTick:Wa,normalizeClass:Kr,normalizeProps:np,normalizeStyle:zr,onActivated:Bp,onBeforeMount:Hp,onBeforeUnmount:Za,onBeforeUpdate:Up,onDeactivated:jp,onErrorCaptured:Kp,onMounted:Qo,onRenderTracked:zp,onRenderTriggered:Yp,onScopeDispose:fE,onServerPrefetch:Wp,onUnmounted:Ja,onUpdated:Ga,openBlock:qa,popScopeId:nb,provide:em,proxyRefs:bu,pushScopeId:tb,queuePostFlushCb:oa,reactive:Ha,readonly:mu,ref:bo,registerRuntimeCompiler:Rm,render:Pc,renderList:hb,renderSlot:mb,resolveComponent:Xp,resolveDirective:db,resolveDynamicComponent:fb,resolveFilter:P0,resolveTransitionHooks:Lr,setBlockTracking:Cc,setDevtoolsHook:M0,setTransitionHooks:Mi,shallowReactive:Op,shallowReadonly:RE,shallowRef:kE,ssrContextKey:vm,ssrUtils:N0,stop:pE,toDisplayString:uu,toHandlerKey:Ji,toHandlers:gb,toRaw:Xe,toRef:YE,toRefs:HE,toValue:BE,transformVNodeArgs:m0,triggerRef:VE,unref:Eu,useAttrs:Ob,useCssModule:sS,useCssVars:W0,useModel:t0,useSSRContext:ym,useSlots:Cb,useTransitionState:wu,vModelCheckbox:Vu,vModelDynamic:qm,vModelRadio:Bu,vModelSelect:Jm,vModelText:pa,vShow:Ym,version:Bm,warn:A0,watch:Do,watchEffect:qb,watchPostEffect:Em,watchSyncEffect:bm,withAsyncContext:Mb,withCtx:Tu,withDefaults:Db,withDirectives:rb,withKeys:ES,withMemo:O0,withModifiers:vS,withScopeId:ib},Symbol.toStringTag,{value:"Module"}));/** -* @vue/compiler-core v3.4.32 -* (c) 2018-present Yuxi (Evan) You and Vue contributors -* @license MIT -**/const Vr=Symbol(""),Ir=Symbol(""),tl=Symbol(""),$o=Symbol(""),ju=Symbol(""),Pi=Symbol(""),$u=Symbol(""),Hu=Symbol(""),nl=Symbol(""),il=Symbol(""),Xr=Symbol(""),rl=Symbol(""),Uu=Symbol(""),ol=Symbol(""),sl=Symbol(""),al=Symbol(""),ll=Symbol(""),cl=Symbol(""),ul=Symbol(""),Wu=Symbol(""),Yu=Symbol(""),ns=Symbol(""),Ho=Symbol(""),fl=Symbol(""),dl=Symbol(""),Br=Symbol(""),Gr=Symbol(""),hl=Symbol(""),ma=Symbol(""),cg=Symbol(""),ga=Symbol(""),Uo=Symbol(""),ug=Symbol(""),fg=Symbol(""),pl=Symbol(""),dg=Symbol(""),hg=Symbol(""),ml=Symbol(""),zu=Symbol(""),cr={[Vr]:"Fragment",[Ir]:"Teleport",[tl]:"Suspense",[$o]:"KeepAlive",[ju]:"BaseTransition",[Pi]:"openBlock",[$u]:"createBlock",[Hu]:"createElementBlock",[nl]:"createVNode",[il]:"createElementVNode",[Xr]:"createCommentVNode",[rl]:"createTextVNode",[Uu]:"createStaticVNode",[ol]:"resolveComponent",[sl]:"resolveDynamicComponent",[al]:"resolveDirective",[ll]:"resolveFilter",[cl]:"withDirectives",[ul]:"renderList",[Wu]:"renderSlot",[Yu]:"createSlots",[ns]:"toDisplayString",[Ho]:"mergeProps",[fl]:"normalizeClass",[dl]:"normalizeStyle",[Br]:"normalizeProps",[Gr]:"guardReactiveProps",[hl]:"toHandlers",[ma]:"camelize",[cg]:"capitalize",[ga]:"toHandlerKey",[Uo]:"setBlockTracking",[ug]:"pushScopeId",[fg]:"popScopeId",[pl]:"withCtx",[dg]:"unref",[hg]:"isRef",[ml]:"withMemo",[zu]:"isMemoSame"};function pg(e){Object.getOwnPropertySymbols(e).forEach(n=>{cr[n]=e[n]})}const TS={HTML:0,0:"HTML",SVG:1,1:"SVG",MATH_ML:2,2:"MATH_ML"},wS={ROOT:0,0:"ROOT",ELEMENT:1,1:"ELEMENT",TEXT:2,2:"TEXT",COMMENT:3,3:"COMMENT",SIMPLE_EXPRESSION:4,4:"SIMPLE_EXPRESSION",INTERPOLATION:5,5:"INTERPOLATION",ATTRIBUTE:6,6:"ATTRIBUTE",DIRECTIVE:7,7:"DIRECTIVE",COMPOUND_EXPRESSION:8,8:"COMPOUND_EXPRESSION",IF:9,9:"IF",IF_BRANCH:10,10:"IF_BRANCH",FOR:11,11:"FOR",TEXT_CALL:12,12:"TEXT_CALL",VNODE_CALL:13,13:"VNODE_CALL",JS_CALL_EXPRESSION:14,14:"JS_CALL_EXPRESSION",JS_OBJECT_EXPRESSION:15,15:"JS_OBJECT_EXPRESSION",JS_PROPERTY:16,16:"JS_PROPERTY",JS_ARRAY_EXPRESSION:17,17:"JS_ARRAY_EXPRESSION",JS_FUNCTION_EXPRESSION:18,18:"JS_FUNCTION_EXPRESSION",JS_CONDITIONAL_EXPRESSION:19,19:"JS_CONDITIONAL_EXPRESSION",JS_CACHE_EXPRESSION:20,20:"JS_CACHE_EXPRESSION",JS_BLOCK_STATEMENT:21,21:"JS_BLOCK_STATEMENT",JS_TEMPLATE_LITERAL:22,22:"JS_TEMPLATE_LITERAL",JS_IF_STATEMENT:23,23:"JS_IF_STATEMENT",JS_ASSIGNMENT_EXPRESSION:24,24:"JS_ASSIGNMENT_EXPRESSION",JS_SEQUENCE_EXPRESSION:25,25:"JS_SEQUENCE_EXPRESSION",JS_RETURN_STATEMENT:26,26:"JS_RETURN_STATEMENT"},DS={ELEMENT:0,0:"ELEMENT",COMPONENT:1,1:"COMPONENT",SLOT:2,2:"SLOT",TEMPLATE:3,3:"TEMPLATE"},CS={NOT_CONSTANT:0,0:"NOT_CONSTANT",CAN_SKIP_PATCH:1,1:"CAN_SKIP_PATCH",CAN_HOIST:2,2:"CAN_HOIST",CAN_STRINGIFY:3,3:"CAN_STRINGIFY"},Nt={start:{line:1,column:1,offset:0},end:{line:1,column:1,offset:0},source:""};function mg(e,n=""){return{type:0,source:n,children:e,helpers:new Set,components:[],directives:[],hoists:[],imports:[],cached:0,temps:0,codegenNode:void 0,loc:Nt}}function jr(e,n,t,i,r,o,s,a=!1,l=!1,c=!1,u=Nt){return e&&(a?(e.helper(Pi),e.helper(dr(e.inSSR,c))):e.helper(fr(e.inSSR,c)),s&&e.helper(cl)),{type:13,tag:n,props:t,children:i,patchFlag:r,dynamicProps:o,directives:s,isBlock:a,disableTracking:l,isComponent:c,loc:u}}function Zr(e,n=Nt){return{type:17,loc:n,elements:e}}function bn(e,n=Nt){return{type:15,loc:n,properties:e}}function Dt(e,n){return{type:16,loc:Nt,key:Me(e)?Fe(e,!0):e,value:n}}function Fe(e,n=!1,t=Nt,i=0){return{type:4,loc:t,content:e,isStatic:n,constType:n?3:i}}function OS(e,n){return{type:5,loc:n,content:Me(e)?Fe(e,!1,n):e}}function xn(e,n=Nt){return{type:8,loc:n,children:e}}function At(e,n=[],t=Nt){return{type:14,loc:t,callee:e,arguments:n}}function ur(e,n=void 0,t=!1,i=!1,r=Nt){return{type:18,params:e,returns:n,newline:t,isSlot:i,loc:r}}function va(e,n,t,i=!0){return{type:19,test:e,consequent:n,alternate:t,newline:i,loc:Nt}}function gg(e,n,t=!1){return{type:20,index:e,value:n,isVOnce:t,loc:Nt}}function vg(e){return{type:21,body:e,loc:Nt}}function AS(e){return{type:22,elements:e,loc:Nt}}function xS(e,n,t){return{type:23,test:e,consequent:n,alternate:t,loc:Nt}}function _S(e,n){return{type:24,left:e,right:n,loc:Nt}}function MS(e){return{type:25,expressions:e,loc:Nt}}function IS(e){return{type:26,returns:e,loc:Nt}}function fr(e,n){return e||n?nl:il}function dr(e,n){return e||n?$u:Hu}function gl(e,{helper:n,removeHelper:t,inSSR:i}){e.isBlock||(e.isBlock=!0,t(fr(i,e.isComponent)),n(Pi),n(dr(i,e.isComponent)))}const Sd=new Uint8Array([123,123]),Td=new Uint8Array([125,125]);function wd(e){return e>=97&&e<=122||e>=65&&e<=90}function yn(e){return e===32||e===10||e===9||e===12||e===13}function mi(e){return e===47||e===62||yn(e)}function ya(e){const n=new Uint8Array(e.length);for(let t=0;t=0;r--){const o=this.newlines[r];if(n>o){t=r+2,i=n-o;break}}return{column:i,line:t,offset:n}}peek(){return this.buffer.charCodeAt(this.index+1)}stateText(n){n===60?(this.index>this.sectionStart&&this.cbs.ontext(this.sectionStart,this.index),this.state=5,this.sectionStart=this.index):!this.inVPre&&n===this.delimiterOpen[0]&&(this.state=2,this.delimiterIndex=0,this.stateInterpolationOpen(n))}stateInterpolationOpen(n){if(n===this.delimiterOpen[this.delimiterIndex])if(this.delimiterIndex===this.delimiterOpen.length-1){const t=this.index+1-this.delimiterOpen.length;t>this.sectionStart&&this.cbs.ontext(this.sectionStart,t),this.state=3,this.sectionStart=t}else this.delimiterIndex++;else this.inRCDATA?(this.state=32,this.stateInRCDATA(n)):(this.state=1,this.stateText(n))}stateInterpolation(n){n===this.delimiterClose[0]&&(this.state=4,this.delimiterIndex=0,this.stateInterpolationClose(n))}stateInterpolationClose(n){n===this.delimiterClose[this.delimiterIndex]?this.delimiterIndex===this.delimiterClose.length-1?(this.cbs.oninterpolation(this.sectionStart,this.index+1),this.inRCDATA?this.state=32:this.state=1,this.sectionStart=this.index+1):this.delimiterIndex++:(this.state=3,this.stateInterpolation(n))}stateSpecialStartSequence(n){const t=this.sequenceIndex===this.currentSequence.length;if(!(t?mi(n):(n|32)===this.currentSequence[this.sequenceIndex]))this.inRCDATA=!1;else if(!t){this.sequenceIndex++;return}this.sequenceIndex=0,this.state=6,this.stateInTagName(n)}stateInRCDATA(n){if(this.sequenceIndex===this.currentSequence.length){if(n===62||yn(n)){const t=this.index-this.currentSequence.length;if(this.sectionStart=n||(this.state===28?this.currentSequence===$t.CdataEnd?this.cbs.oncdata(this.sectionStart,n):this.cbs.oncomment(this.sectionStart,n):this.state===6||this.state===11||this.state===18||this.state===17||this.state===12||this.state===13||this.state===14||this.state===15||this.state===16||this.state===20||this.state===19||this.state===21||this.state===9||this.cbs.ontext(this.sectionStart,n))}emitCodePoint(n,t){}}const PS={COMPILER_IS_ON_ELEMENT:"COMPILER_IS_ON_ELEMENT",COMPILER_V_BIND_SYNC:"COMPILER_V_BIND_SYNC",COMPILER_V_BIND_OBJECT_ORDER:"COMPILER_V_BIND_OBJECT_ORDER",COMPILER_V_ON_NATIVE:"COMPILER_V_ON_NATIVE",COMPILER_V_IF_V_FOR_PRECEDENCE:"COMPILER_V_IF_V_FOR_PRECEDENCE",COMPILER_NATIVE_TEMPLATE:"COMPILER_NATIVE_TEMPLATE",COMPILER_INLINE_TEMPLATE:"COMPILER_INLINE_TEMPLATE",COMPILER_FILTERS:"COMPILER_FILTERS"},RS={COMPILER_IS_ON_ELEMENT:{message:'Platform-native elements with "is" prop will no longer be treated as components in Vue 3 unless the "is" value is explicitly prefixed with "vue:".',link:"https://v3-migration.vuejs.org/breaking-changes/custom-elements-interop.html"},COMPILER_V_BIND_SYNC:{message:e=>`.sync modifier for v-bind has been removed. Use v-model with argument instead. \`v-bind:${e}.sync\` should be changed to \`v-model:${e}\`.`,link:"https://v3-migration.vuejs.org/breaking-changes/v-model.html"},COMPILER_V_BIND_OBJECT_ORDER:{message:'v-bind="obj" usage is now order sensitive and behaves like JavaScript object spread: it will now overwrite an existing non-mergeable attribute that appears before v-bind in the case of conflict. To retain 2.x behavior, move v-bind to make it the first attribute. You can also suppress this warning if the usage is intended.',link:"https://v3-migration.vuejs.org/breaking-changes/v-bind.html"},COMPILER_V_ON_NATIVE:{message:".native modifier for v-on has been removed as is no longer necessary.",link:"https://v3-migration.vuejs.org/breaking-changes/v-on-native-modifier-removed.html"},COMPILER_V_IF_V_FOR_PRECEDENCE:{message:"v-if / v-for precedence when used on the same element has changed in Vue 3: v-if now takes higher precedence and will no longer have access to v-for scope variables. It is best to avoid the ambiguity with