diff --git a/app/Enums/Client/ClientGender.php b/app/Enums/Client/ClientGender.php new file mode 100644 index 0000000..2f57a62 --- /dev/null +++ b/app/Enums/Client/ClientGender.php @@ -0,0 +1,17 @@ + 'Nam', + self::FEMALE => 'Nữ', + }; + } +} diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 8e7fbd1..bfb5955 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -34,8 +34,33 @@ class Handler extends ExceptionHandler */ public function register() { - $this->reportable(function (Throwable $e) { - // + $this->renderable(function (\Symfony\Component\HttpKernel\Exception\NotFoundHttpException $e, $request) { + if (!$request->expectsJson() && !$request->is('v1/*') && !$request->is('api/*')) { + return null; + } + + $previous = $e->getPrevious(); + + if ($previous instanceof \Illuminate\Database\Eloquent\ModelNotFoundException) { + $modelClass = $previous->getModel(); + $pageType = match ($modelClass) { + \App\Models\Product::class => 'service', + \App\Models\Customer::class => 'client', + \App\Models\Post::class => 'post', + default => 'unknown', + }; + + return response()->json([ + 'error' => true, + 'message' => 'Dữ liệu không tồn tại', + 'page_type' => $pageType, + ], 404); + } + + return response()->json([ + 'error' => true, + 'message' => 'API Route not found', + ], 404); }); } } diff --git a/app/Http/Controllers/Api/Service/ServiceController.php b/app/Http/Controllers/Api/Service/ServiceController.php new file mode 100644 index 0000000..1ac362d --- /dev/null +++ b/app/Http/Controllers/Api/Service/ServiceController.php @@ -0,0 +1,45 @@ +serviceService = $serviceService; + } + + /** + * Lấy danh sách dịch vụ (sản phẩm) đang hoạt động + */ + public function getService() + { + $services = $this->serviceService->getActiveServices(); + + return response()->json([ + 'error' => false, + 'message' => 'Lấy dữ liệu thành công', + 'page_type' => 'service', + 'data' => ServiceResource::collection($services), + ]); + } + + public function getDetailService(Product $product) + { + $product->load(['osVersions.osGroup', 'category', 'pricings' => fn ($q) => $q->where('is_active', 1)]); + + return response()->json([ + 'error' => false, + 'message' => 'Lấy dữ liệu thành công', + 'page_type' => 'service', + 'data' => new ServiceResource($product), + ]); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/admin/package/Datacenter.php b/app/Http/Controllers/admin/package/Datacenter.php index df5f922..4613172 100644 --- a/app/Http/Controllers/admin/package/Datacenter.php +++ b/app/Http/Controllers/admin/package/Datacenter.php @@ -131,7 +131,7 @@ class Datacenter extends Controller ->addColumn( 'action', function ($d) { - return view('administrator.pages.package.datacenter.datatable.edit', ['row' => $d])->render(); + return view('administrator.pages.package.datacenter.datatable.action', ['row' => $d])->render(); } ) ->filterColumn('v_center.host', function ($query, $keyword) { diff --git a/app/Http/Resources/Api/Client/ClientResource.php b/app/Http/Resources/Api/Client/ClientResource.php index 0191a62..809fc16 100644 --- a/app/Http/Resources/Api/Client/ClientResource.php +++ b/app/Http/Resources/Api/Client/ClientResource.php @@ -25,19 +25,15 @@ class ClientResource extends JsonResource 'phone' => $this->phone, 'address' => $this->address, 'city' => $this->city, - 'ward' => $this->ward, - 'province' => $this->province, - 'active_phone' => 1, - 'active_zalo' => 1, - 'gender' => $this->gender, + 'ward' => $this->ward->name, + 'province' => $this->province->name, + 'gender' => $this->gender_label, 'date' => $this->created_at ? $this->created_at->format('Y-m-d H:i:s') : null, 'company' => $this->company ?? '', - 'mst' => null, 'avatar' => $this->avatar, - 'cmnd_after' => $this->cmnd_after, - 'cmnd_before' => $this->cmnd_before, - 'cmnd_active' => (bool) $this->identity_number, - 'cmnd' => $this->cmnd, + 'cmnd_after' => $this->front_identity_number, + 'cmnd_before' => $this->back_identity_number, + 'cmnd' => $this->identity_number, 'fb_link' => null, 'active_2fa' => 0, 'off_mail_marketing' => $this->off_mail_marketing, diff --git a/app/Http/Resources/Api/Service/ServiceResource.php b/app/Http/Resources/Api/Service/ServiceResource.php new file mode 100644 index 0000000..12c8130 --- /dev/null +++ b/app/Http/Resources/Api/Service/ServiceResource.php @@ -0,0 +1,49 @@ + + */ + public function toArray(Request $request): array + { + return [ + 'uuid' => $this->uuid, + 'name' => $this->name, + 'slug' => $this->slug, + 'short_description' => $this->short_description, + 'description' => $this->description, + 'thumbnail' => $this->thumbnail ? asset($this->thumbnail) : null, + 'product_type' => $this->product_type, + 'specs' => [ + 'cpu' => $this->cpu, + 'ram' => $this->ram, + 'disk' => $this->disk, + 'bandwidth' => $this->bandwidth, + 'gpu' => $this->gpu + ], + 'stock' => $this->stock, + 'price' => $this->price, + 'price_sale' => $this->price_sale, + 'group' => $this->category->name, + 'os' => $this->osVersions->groupBy('os_group_id')->map(function ($versions) { + $group = $versions->first()->osGroup; + return [ + 'name' => $group?->name, + 'thumbnail' => $group?->thumbnail, + 'versions' => $versions->map(fn($os) => [ + 'version' => $os->version, + 'name' => $os->name, + ])->values(), + ]; + })->values(), + ]; + } +} diff --git a/app/Models/Customer.php b/app/Models/Customer.php index 4cf9c34..1b77cd6 100644 --- a/app/Models/Customer.php +++ b/app/Models/Customer.php @@ -57,6 +57,11 @@ class Customer extends Authenticatable 'first_name', 'last_name', 'point', + 'gender_label', + ]; + + protected $casts = [ + 'gender' => \App\Enums\Client\ClientGender::class, ]; /** @@ -219,4 +224,9 @@ class Customer extends Authenticatable { return $this->belongsTo(Ward::class, 'ward_code', 'code'); } + + public function getGenderLabelAttribute() + { + return $this->gender?->label() ?? 'Khác'; + } } diff --git a/app/Providers/RepositoryProvider.php b/app/Providers/RepositoryProvider.php index 938db95..c9abae5 100644 --- a/app/Providers/RepositoryProvider.php +++ b/app/Providers/RepositoryProvider.php @@ -365,6 +365,12 @@ class RepositoryProvider extends ServiceProvider \App\Repositories\Api\Client\ClientRepositoryInterface::class, \App\Repositories\Api\Client\ClientRepository::class ); + + // Service API + $this->app->bind( + \App\Repositories\Api\Service\ServiceRepositoryInterface::class, + \App\Repositories\Api\Service\ServiceRepository::class + ); } /** diff --git a/app/Repositories/Api/Service/ServiceRepository.php b/app/Repositories/Api/Service/ServiceRepository.php new file mode 100644 index 0000000..875dfed --- /dev/null +++ b/app/Repositories/Api/Service/ServiceRepository.php @@ -0,0 +1,35 @@ +model + ->with(['osVersions.osGroup', 'category']) + ->where('is_active', 1) + ->orderBy('sort_order', 'asc') + ->get(); + } + + public function findActiveBySlug(string $slug) + { + return $this->model + ->with(['osVersions.osGroup', 'category', 'pricings' => fn ($q) => $q->where('is_active', 1)]) + ->where('slug', $slug) + ->where('is_active', 1) + ->first(); + } +} diff --git a/app/Repositories/Api/Service/ServiceRepositoryInterface.php b/app/Repositories/Api/Service/ServiceRepositoryInterface.php new file mode 100644 index 0000000..e1d8740 --- /dev/null +++ b/app/Repositories/Api/Service/ServiceRepositoryInterface.php @@ -0,0 +1,15 @@ +serviceRepository = $serviceRepository; + } + + /** + * Lấy danh sách dịch vụ đang hoạt động + */ + public function getActiveServices() + { + return $this->serviceRepository->getActiveServices(); + } + + public function findActiveBySlug(string $slug) + { + return $this->serviceRepository->findActiveBySlug($slug); + } +} diff --git a/database/seeders/OsSeeder.php b/database/seeders/OsSeeder.php new file mode 100644 index 0000000..2a144c0 --- /dev/null +++ b/database/seeders/OsSeeder.php @@ -0,0 +1,93 @@ + 'Ubuntu', + 'thumbnail' => 'ubuntu.png', + 'module_host_id' => 1, + 'status' => 1, + 'versions' => [ + '20.04 LTS', + '22.04 LTS', + '24.04 LTS', + ], + ], + [ + 'name' => 'CentOS', + 'thumbnail' => 'centos.png', + 'module_host_id' => 1, + 'status' => 1, + 'versions' => [ + '7', + '8 Stream', + ], + ], + [ + 'name' => 'Debian', + 'thumbnail' => 'debian.png', + 'module_host_id' => 1, + 'status' => 1, + 'versions' => [ + '10', + '11', + '12', + ], + ], + [ + 'name' => 'Windows Server', + 'thumbnail' => 'windows.png', + 'module_host_id' => 1, + 'status' => 1, + 'versions' => [ + '2016', + '2019', + '2022', + ], + ], + ]; + + foreach ($data as $groupData) { + + /** + * Create or Update OS Group + */ + $group = OsGroup::updateOrCreate( + ['name' => $groupData['name']], + [ + 'thumbnail' => $groupData['thumbnail'], + 'module_host_id' => $groupData['module_host_id'], + 'status' => $groupData['status'], + ] + ); + + /** + * Create OS versions + */ + foreach ($groupData['versions'] as $version) { + Os::updateOrCreate( + [ + 'os_group_id' => $group->id, + 'version' => $version, + ], + [ + 'template_id' => null, + 'status' => 1, + ] + ); + } + } + } +} diff --git a/public/uploads/images/centos-svgrepo-com.svg b/public/uploads/images/centos.svg similarity index 100% rename from public/uploads/images/centos-svgrepo-com.svg rename to public/uploads/images/centos.svg diff --git a/public/uploads/images/ubuntu-svgrepo-com.svg b/public/uploads/images/icon-ubuntu.svg similarity index 100% rename from public/uploads/images/ubuntu-svgrepo-com.svg rename to public/uploads/images/icon-ubuntu.svg diff --git a/resources/images/os/icon-centos.svg b/resources/images/os/icon-centos.svg new file mode 100644 index 0000000..c1897d8 --- /dev/null +++ b/resources/images/os/icon-centos.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/resources/images/os/icon-ubuntu.svg b/resources/images/os/icon-ubuntu.svg new file mode 100644 index 0000000..02e8546 --- /dev/null +++ b/resources/images/os/icon-ubuntu.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/resources/images/os/icon-windows.svg b/resources/images/os/icon-windows.svg new file mode 100644 index 0000000..fb53a50 --- /dev/null +++ b/resources/images/os/icon-windows.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/views/administrator/pages/block/Sync/All.blade.php b/resources/views/administrator/pages/block/Sync/All.blade.php index a701a80..80301ce 100644 --- a/resources/views/administrator/pages/block/Sync/All.blade.php +++ b/resources/views/administrator/pages/block/Sync/All.blade.php @@ -1 +1,2 @@ -Sync All Package \ No newline at end of file +Sync All + Package \ No newline at end of file diff --git a/resources/views/administrator/pages/block/Sync/VM.blade.php b/resources/views/administrator/pages/block/Sync/VM.blade.php index 7357adf..c18ba71 100644 --- a/resources/views/administrator/pages/block/Sync/VM.blade.php +++ b/resources/views/administrator/pages/block/Sync/VM.blade.php @@ -1,5 +1,7 @@ -Add - VM -@include("administrator.pages.block.Sync.All") -Sync - VM \ No newline at end of file +
+ Add + VM + @include("administrator.pages.block.Sync.All") + Sync + VM +
\ No newline at end of file diff --git a/resources/views/administrator/pages/module/vcenter/datatable/action.blade.php b/resources/views/administrator/pages/module/vcenter/datatable/action.blade.php index 2bbee98..ce60ed7 100644 --- a/resources/views/administrator/pages/module/vcenter/datatable/action.blade.php +++ b/resources/views/administrator/pages/module/vcenter/datatable/action.blade.php @@ -1,5 +1,4 @@
- Edit + + +
\ No newline at end of file diff --git a/resources/views/administrator/pages/package/datacenter/datatable/edit.blade.php b/resources/views/administrator/pages/package/datacenter/datatable/edit.blade.php deleted file mode 100644 index 0566df8..0000000 --- a/resources/views/administrator/pages/package/datacenter/datatable/edit.blade.php +++ /dev/null @@ -1,2 +0,0 @@ -Edit -Delete \ No newline at end of file diff --git a/resources/views/administrator/pages/package/network/index.blade.php b/resources/views/administrator/pages/package/network/index.blade.php index 8e36ca2..75cdc6b 100644 --- a/resources/views/administrator/pages/package/network/index.blade.php +++ b/resources/views/administrator/pages/package/network/index.blade.php @@ -18,15 +18,15 @@ @section('content') @if(auth()->guard('admins')->user()->can("manager package module"))
-
+
@include("administrator.pages.block.Sync.Network")
+ ['key' => 'name', 'label' => 'Name'], + ['key' => 'host.datacenter.v_center.host', 'label' => 'Vcenter Host'], + ['key' => 'action', 'label' => 'Action'] + ]" />
@else diff --git a/resources/views/administrator/pages/package/vm/datatable/action.blade.php b/resources/views/administrator/pages/package/vm/datatable/action.blade.php index 3c5a354..0b48d43 100644 --- a/resources/views/administrator/pages/package/vm/datatable/action.blade.php +++ b/resources/views/administrator/pages/package/vm/datatable/action.blade.php @@ -1,2 +1,6 @@ -Edit -Delete \ No newline at end of file +
+ Edit + Delete +
\ No newline at end of file diff --git a/routes/client.php b/routes/client.php index 1856977..5395c48 100644 --- a/routes/client.php +++ b/routes/client.php @@ -1,7 +1,7 @@ group(function () { @@ -18,6 +18,13 @@ Route::prefix('v1')->group(function () { }); }); }); + + Route::prefix('services')->middleware('api.auth')->as('services.')->group(function () { + Route::controller(ServiceController::class)->group(function () { + Route::get('get-list', 'getService')->name('getList'); + Route::get('{product:slug}', 'getDetailService')->name('detail'); + }); + }); });