Add ServiceController for managing customer services; implement index, show, and detachCustomer methods
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin\Service;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Service;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ServiceController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$perPage = min((int) ($request->per_page ?? 15), 100);
|
||||
|
||||
$query = Service::with(['customer:id,uuid,fullname,email', 'product:id,uuid,name', 'invoice:id,invoice_number', 'vmware:id,name,module_ip_address'])
|
||||
->when($request->filter, fn($q, $v) => $q->where('server_name', 'like', "%{$v}%"))
|
||||
->when($request->status, fn($q, $v) => $q->where('status', $v))
|
||||
->when($request->customer_id, fn($q, $v) => $q->where('customer_id', $v));
|
||||
|
||||
$paginator = $query->latest()->paginate($perPage);
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'data' => [
|
||||
'items' => $paginator->items(),
|
||||
'total' => $paginator->total(),
|
||||
'per_page' => $paginator->perPage(),
|
||||
'current_page' => $paginator->currentPage(),
|
||||
'last_page' => $paginator->lastPage(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function show(int $id): JsonResponse
|
||||
{
|
||||
$service = Service::with(['customer', 'product', 'orderItem', 'invoice', 'vmware', 'addons'])
|
||||
->findOrFail($id);
|
||||
|
||||
return response()->json(['error' => false, 'data' => $service]);
|
||||
}
|
||||
|
||||
public function detachCustomer(int $id): JsonResponse
|
||||
{
|
||||
$service = Service::findOrFail($id);
|
||||
$service->update(['customer_id' => null]);
|
||||
|
||||
return response()->json(['error' => false, 'message' => 'Đã gỡ khách hàng khỏi dịch vụ.']);
|
||||
}
|
||||
}
|
||||
@@ -1,63 +1,188 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="vi">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Cập nhật mật khẩu — {{ $appName }}</title>
|
||||
<style>
|
||||
* { box-sizing: border-box; }
|
||||
body { font-family: 'Segoe UI', Arial, sans-serif; background: #f0f4f8; margin: 0; padding: 0; color: #374151; }
|
||||
.wrapper { max-width: 620px; margin: 30px auto; }
|
||||
.card { background: #fff; border-radius: 12px; overflow: hidden; box-shadow: 0 4px 20px rgba(0,0,0,0.08); }
|
||||
.header { background: linear-gradient(135deg, #16a34a 0%, #15803d 100%); padding: 32px 40px; text-align: center; }
|
||||
.header .icon { font-size: 44px; margin-bottom: 8px; }
|
||||
.header h1 { color: #fff; margin: 0; font-size: 22px; font-weight: 700; }
|
||||
.body { padding: 32px 40px; line-height: 1.6; }
|
||||
.credentials { background: #f9fafb; border: 1px dashed #d1d5db; border-radius: 8px; padding: 16px 18px; margin: 18px 0; font-size: 14px; }
|
||||
.credentials .row { margin: 4px 0; }
|
||||
.credentials .value { font-family: 'Menlo','Consolas',monospace; font-weight: 700; color: #111827; }
|
||||
.footer { text-align: center; padding: 18px 40px; border-top: 1px solid #f3f4f6; font-size: 12px; color: #9ca3af; }
|
||||
.cta-wrap { text-align: center; margin: 24px 0 4px; }
|
||||
.cta-btn { display: inline-block; background-color: #16a34a; color: #ffffff !important; text-decoration: none; padding: 12px 26px; border-radius: 8px; font-size: 14px; font-weight: 600; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<div class="card">
|
||||
<div class="header">
|
||||
<div class="icon">🔐</div>
|
||||
<h1>Mật khẩu của bạn đã được cập nhật</h1>
|
||||
</div>
|
||||
@php
|
||||
$appName = $appName ?? config('app.name', 'Thế Giới Số');
|
||||
$fullName = $fullName ?? 'Quý khách';
|
||||
$email = $email ?? '';
|
||||
$password = $password ?? '';
|
||||
$loginUrl = $loginUrl ?? rtrim((string) env('FRONTEND_URL', config('app.url')), '/') . '/dang-nhap';
|
||||
$supportEmail = $supportEmail ?? 'support@tgs.com.vn';
|
||||
$supportPhone = $supportPhone ?? '1900. 6119';
|
||||
@endphp
|
||||
|
||||
<div class="body">
|
||||
<p style="margin:0 0 12px 0;">
|
||||
Xin chào <strong>{{ $fullName }}</strong>,
|
||||
</p>
|
||||
<p style="margin:0 0 12px 0;">
|
||||
Quản trị viên của <strong>{{ $appName }}</strong> vừa cấp lại mật khẩu mới cho tài khoản của bạn.
|
||||
Vui lòng sử dụng thông tin bên dưới để đăng nhập và đổi lại mật khẩu của bạn ngay sau đó.
|
||||
</p>
|
||||
|
||||
<div class="credentials">
|
||||
<div class="row">Tài khoản: <span class="value">{{ $email }}</span></div>
|
||||
<div class="row">Mật khẩu mới: <span class="value">{{ $password }}</span></div>
|
||||
</div>
|
||||
|
||||
<div class="cta-wrap">
|
||||
<a href="{{ $loginUrl }}" class="cta-btn">Đăng nhập ngay</a>
|
||||
</div>
|
||||
|
||||
<p style="margin:18px 0 0 0;color:#6b7280;">
|
||||
Nếu bạn không yêu cầu thao tác này, vui lòng liên hệ ngay với chúng tôi qua
|
||||
<strong>{{ $supportEmail }}</strong>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
Email này được gửi tự động. Vui lòng không trả lời email này.<br>
|
||||
Cần hỗ trợ? Liên hệ <strong>{{ $supportEmail }}</strong> hoặc <strong>{{ $supportPhone }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<table style="border-collapse: collapse; width: 100%; background-color: #efefef;" border="0" cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="padding: 20px;" align="center" valign="top">
|
||||
<table style="padding-top: 20px; padding-bottom: 20px; border-collapse: collapse; background-color: #ffffff; width: 700px;" border="0" cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr class="NoiDungKM">
|
||||
<td style="width: 700px;" valign="top">
|
||||
<table style="border-collapse: collapse; width: 100%;" border="0" cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="background-color: #f06824; padding: 34px 30px 30px; text-align: center; font-family: Arial, Helvetica, sans-serif; color: #ffffff;" align="center" valign="top" bgcolor="#f06824">
|
||||
<div style="font-size: 42px; line-height: 1; margin-bottom: 12px;">🔐</div>
|
||||
<h1 style="margin: 0 0 8px; padding: 0; color: #ffffff; font-family: Arial, Helvetica, sans-serif; font-size: 24px; line-height: 1.35; font-weight: 700;">
|
||||
Mật khẩu của bạn đã được cập nhật
|
||||
</h1>
|
||||
<div style="font-size: 14px; line-height: 1.6; color: #ffffff;">
|
||||
Quản trị viên vừa cấp lại mật khẩu mới cho tài khoản của bạn
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="MXH">
|
||||
<td style="text-align: center; padding: 0 30px;" align="center" valign="top">
|
||||
<table style="border-collapse: collapse; background-color: #ffffff; width: 100%;" border="0" cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="height: 15px; font-family: Arial, Helvetica, sans-serif; font-size: 14px; line-height: 1.7; color: #000000;" valign="top" height="15">
|
||||
<div style="text-align: left;"> </div>
|
||||
<div style="text-align: left;">Xin chào <strong>{{ $fullName }}</strong>,</div>
|
||||
<div style="text-align: left;"> </div>
|
||||
<div style="text-align: left;">
|
||||
Quản trị viên của <strong>{{ $appName }}</strong> vừa cấp lại mật khẩu mới cho tài khoản của bạn.
|
||||
Vui lòng sử dụng thông tin bên dưới để đăng nhập và đổi lại mật khẩu của bạn ngay sau đó.
|
||||
</div>
|
||||
<div style="text-align: left;"> </div>
|
||||
<table style="border-collapse: collapse; width: 100%; background-color: #f9fafb; border: 1px dashed #d1d5db; border-radius: 6px;" border="0" cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="padding: 14px 18px; font-family: Arial, Helvetica, sans-serif; font-size: 14px; line-height: 1.8; color: #000000;">
|
||||
<div>Tài khoản: <strong style="font-family: 'Menlo','Consolas',monospace; color: #111827;">{{ $email }}</strong></div>
|
||||
<div>Mật khẩu mới: <strong style="font-family: 'Menlo','Consolas',monospace; color: #111827;">{{ $password }}</strong></div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div style="text-align: left;"> </div>
|
||||
<div style="text-align: center;">
|
||||
<a style="display: inline-block; background-color: #f06824; color: #ffffff !important; text-decoration: none; padding: 12px 28px; border-radius: 3px; font-family: Arial, Helvetica, sans-serif; font-size: 14px; font-weight: 700;" href="{{ $loginUrl }}" target="_blank" rel="noopener">
|
||||
Đăng nhập ngay
|
||||
</a>
|
||||
</div>
|
||||
<div style="text-align: left;"> </div>
|
||||
<div style="text-align: left; color: #6b7280; font-size: 13px;">
|
||||
Nếu bạn không yêu cầu thao tác này, vui lòng liên hệ ngay với chúng tôi qua <strong>{{ $supportEmail }}</strong>.
|
||||
</div>
|
||||
<div style="text-align: left;"> </div>
|
||||
<div style="text-align: left; color: #666666; font-size: 13px;">
|
||||
Email này được gửi tự động. Vui lòng không trả lời email này.
|
||||
</div>
|
||||
<div style="text-align: left;"> </div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="CacDV">
|
||||
<td style="background-color: #f06824; width: 700px; color: #ffffff;" valign="top" bgcolor="#f06824">
|
||||
<table style="border-collapse: collapse; background-color: #f06824; width: 100%; color: #ffffff;" border="0" cellspacing="0" cellpadding="0" align="left" bgcolor="#f06824">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="padding: 0;" width="100%">
|
||||
<table style="border-collapse: collapse; width: 100%;" border="0" cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 100%; height: 1px; background: #ffffff;" bgcolor="#ffffff" width="100%" height="1"><span style="font-size: 14px; color: #ffffff;"> </span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="height: 10px; color: #ffffff;" valign="top" height="10"><span style="font-size: 14px; color: #ffffff;"> </span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 0; text-align: left; font-family: Helvetica, Arial, sans-serif; color: #ffffff; font-size: 16px; line-height: 150%;" align="center" valign="top">
|
||||
<table style="border-collapse: collapse; color: #ffffff;" border="0" cellspacing="0" cellpadding="0" align="center">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 3%; color: #ffffff;"><span style="color: #ffffff;"> </span></td>
|
||||
<td style="vertical-align: middle; text-align: center; padding: 5px 10px; border: 1px solid #ffffff; color: #ffffff;" valign="top">
|
||||
<a style="color: #ffffff; font-family: Helvetica, Arial, sans-serif; font-size: 10px; line-height: 1; font-weight: normal; text-transform: uppercase; word-wrap: break-word; text-decoration: none;" href="https://tgs.com.vn/premium-hosting/" target="_blank" rel="noopener"><span style="color: #ffffff;">Premium HOSTING</span></a>
|
||||
</td>
|
||||
<td style="width: 3%; color: #ffffff;"><span style="color: #ffffff;"> </span></td>
|
||||
<td style="vertical-align: middle; text-align: center; padding: 5px 10px; border: 1px solid #ffffff; color: #ffffff;" valign="top">
|
||||
<a style="color: #ffffff; font-family: Helvetica, Arial, sans-serif; font-size: 10px; line-height: 1; font-weight: normal; text-transform: uppercase; word-wrap: break-word; text-decoration: none;" href="https://tgs.com.vn/cloud-server/" target="_blank" rel="noopener"><span style="color: #ffffff;">Cloud SERVER</span></a>
|
||||
</td>
|
||||
<td style="width: 3%; color: #ffffff;"><span style="color: #ffffff;"> </span></td>
|
||||
<td style="vertical-align: middle; text-align: center; padding: 5px 10px; border: 1px solid #ffffff; color: #ffffff;" valign="top">
|
||||
<a style="color: #ffffff; font-family: Helvetica, Arial, sans-serif; font-size: 10px; line-height: 1; font-weight: normal; text-transform: uppercase; word-wrap: break-word; text-decoration: none;" href="https://cloudemail.vn/" target="_blank" rel="noopener"><span style="color: #ffffff;">EMAIL DOANH NGHIỆP</span></a>
|
||||
</td>
|
||||
<td style="width: 3%; color: #ffffff;"><span style="color: #ffffff;"> </span></td>
|
||||
<td style="vertical-align: middle; text-align: center; padding: 5px 10px; border: 1px solid #ffffff; color: #ffffff;" valign="top">
|
||||
<a style="color: #ffffff; font-family: Helvetica, Arial, sans-serif; font-size: 10px; line-height: 1; font-weight: normal; text-transform: uppercase; word-wrap: break-word; text-decoration: none;" href="https://tgs.com.vn/thiet-ke-website/" target="_blank" rel="noopener"><span style="color: #ffffff;">Thiết Kế WEBSITE</span></a>
|
||||
</td>
|
||||
<td style="width: 3%; color: #ffffff;"><span style="color: #ffffff;"> </span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="height: 10px; color: #ffffff;" valign="top" height="10"><span style="font-size: 14px; color: #ffffff;"> </span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 0;" width="100%">
|
||||
<table style="border-collapse: collapse; width: 100%;" border="0" cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 100%; height: 1px; background: #ffffff;" bgcolor="#ffffff" width="100%" height="1"><span style="font-size: 14px; color: #ffffff;"> </span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="ThongTin">
|
||||
<td align="center" valign="top" bgcolor="#065d88">
|
||||
<table style="border-collapse: collapse; background-color: #f06824; border-top: 0; border-bottom: 0; width: 100%;" border="0" cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 30px;">
|
||||
<td style="height: 30px;" valign="top" height="10"> </td>
|
||||
</tr>
|
||||
<tr style="height: 148px;">
|
||||
<td style="padding: 0; font-family: Helvetica, Arial, sans-serif; text-decoration: none; color: #e7e7e7; font-size: 16px; font-weight: normal; line-height: 150%; vertical-align: top; text-align: center; height: 148px;" align="center">
|
||||
<p style="margin: 0; padding: 0; font-family: Helvetica, Arial, sans-serif; color: white; font-size: 11pt; line-height: 200%;">
|
||||
<span style="color: #ffffff; font-family: 'times new roman', times, serif;"><strong style="font-size: 20px;">CÔNG TY CỔ PHẦN GIẢI PHÁP CÔNG NGHỆ THẾ GIỚI SỐ</strong></span><br>
|
||||
<span style="color: #ffffff; font-family: arial, helvetica, sans-serif; font-size: 12pt;">Địa chỉ: 128/38 Tân Hương, Phường Phú Thọ Hòa, Thành Phố Hồ Chí Minh</span><br>
|
||||
<span style="color: #ffffff; font-family: arial, helvetica, sans-serif; font-size: 12pt;">Tel: (028) 7309. 7379 - Tổng đài: {{ $supportPhone }}</span><br>
|
||||
<span style="font-family: arial, helvetica, sans-serif; font-size: 12pt;">Email: <span style="color: #ffffff;"><a style="color: #ffffff; text-decoration: none;" href="mailto:{{ $supportEmail }}">{{ $supportEmail }}</a></span></span><br>
|
||||
<span style="text-decoration: none; font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #ffffff !important;">
|
||||
<a style="color: #ffffff !important; text-decoration: none;" href="https://www.tgs.com.vn">www.TGS.com.vn</a> &
|
||||
<a style="color: #ffffff !important; text-decoration: none;" href="https://www.thegioiso.cloud">www.thegioiso.CLOUD</a> &
|
||||
<a style="color: #ffffff !important; text-decoration: none;" href="https://www.thegioiserver.com">www.thegioiSERVER.com</a> &
|
||||
<a style="color: #ffffff !important; text-decoration: none;" href="https://www.cloudemail.vn">www.CloudEmail.vn</a>
|
||||
</span>
|
||||
</p>
|
||||
<p style="margin: 0; padding: 0; font-family: Helvetica, Arial, sans-serif; color: white; font-size: 11pt; line-height: 200%;">
|
||||
<span style="text-decoration: none; font-family: 'times new roman', times, serif; color: #ffffff !important; font-size: 12pt;">
|
||||
<span style="color: #ffffff; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 10pt;">
|
||||
<span style="text-decoration: none; font-family: 'times new roman', times, serif; color: #ffffff !important;">
|
||||
<span style="font-family: arial, sans-serif;"><strong>🥇Thế Giới Số🥇</strong>- Premium HOSTING • CLOUD • SERVER & WEBSITE | 15+ năm Phụng Sự 🚀</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="height: 30px; color: #ffffff;" valign="top" height="30"><span style="font-size: 14px; color: #ffffff;"> </span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -19,6 +19,7 @@ use App\Http\Controllers\Api\Admin\Addon\AddonController;
|
||||
use App\Http\Controllers\Api\Admin\WebDesign\WebDesignQuoteController;
|
||||
use App\Http\Controllers\Api\Admin\Product\ProductCategoryController;
|
||||
use App\Http\Controllers\Api\Admin\Product\ProductController;
|
||||
use App\Http\Controllers\Api\Admin\Service\ServiceController;
|
||||
use App\Http\Controllers\Api\Admin\VPS\VPSController;
|
||||
use App\Http\Controllers\Api\Admin\VCenter\VCenterController;
|
||||
use App\Http\Controllers\Api\Admin\DnsManager\ServerController as DnsServerController;
|
||||
@@ -148,6 +149,13 @@ Route::prefix('v1')
|
||||
Route::delete('{uuid}/force', 'forceDelete')->middleware('perm:customer.destroy');
|
||||
});
|
||||
|
||||
// Services (module: customer)
|
||||
Route::prefix('services')->controller(ServiceController::class)->group(function () {
|
||||
Route::get('/', 'index')->middleware('perm:customer.view');
|
||||
Route::get('{id}', 'show')->middleware('perm:customer.view');
|
||||
Route::patch('{id}/detach-customer', 'detachCustomer')->middleware('perm:customer.edit');
|
||||
});
|
||||
|
||||
// Products (module: product-service)
|
||||
Route::prefix('products')
|
||||
->controller(ProductController::class)
|
||||
|
||||
Reference in New Issue
Block a user