feat: Implement Plesk domain and hosting services

- Added PleskDomainService for managing domain operations (create, update, remove, get info).
- Introduced PleskHostingService for provisioning hosting accounts and notifying customers.
- Created PleskService for handling API requests to Plesk.
- Added migration to include 'type' column in dns_manager_servers table.
- Created migration for module_hosting_accounts table to track hosting subscriptions.
- Created migration for module_hosting_plesk_clients table to manage Plesk client credentials.
- Added email templates for notifying customers and admins about hosting account creation.
This commit is contained in:
baodev0
2026-08-06 17:24:01 +07:00
parent 79f06c2fa2
commit d6d63e5152
29 changed files with 1744 additions and 113 deletions
@@ -0,0 +1,130 @@
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Thông báo hosting mới</title>
<style>
* { box-sizing: border-box; }
body { font-family: 'Segoe UI', Arial, sans-serif; background: #f0f4f8; margin: 0; padding: 0; }
.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, #f06824 0%, #d9531a 100%); padding: 36px 40px; text-align: center; }
.header .icon { font-size: 48px; margin-bottom: 12px; }
.header h1 { color: #fff; margin: 0 0 6px; font-size: 22px; font-weight: 700; }
.header p { color: #fde3d3; margin: 0; font-size: 14px; }
.body { padding: 36px 40px; }
.section-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: #9ca3af; margin: 24px 0 10px; }
.section-label:first-child { margin-top: 0; }
.info-table { width: 100%; border-collapse: collapse; background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 8px; overflow: hidden; }
.info-table td { padding: 10px 16px; font-size: 14px; border-bottom: 1px solid #f3f4f6; }
.info-table tr:last-child td { border-bottom: none; }
.info-table td:first-child { color: #6b7280; width: 45%; }
.info-table td:last-child { font-weight: 600; color: #111827; }
.badge { display: inline-block; padding: 2px 10px; border-radius: 999px; font-size: 12px; font-weight: 600; }
.badge-green { background: #dcfce7; color: #15803d; }
.cred-box { background: #fff7ed; border: 1.5px solid #fdba74; border-radius: 10px; padding: 20px 24px; margin-top: 10px; }
.cred-row { display: flex; align-items: center; padding: 8px 0; border-bottom: 1px solid #fed7aa; }
.cred-row:last-child { border-bottom: none; }
.cred-label { color: #c2410c; font-size: 13px; width: 150px; flex-shrink: 0; }
.cred-value { font-family: 'Courier New', monospace; font-size: 14px; font-weight: 700; color: #111827; word-break: break-all; }
.note { margin-top: 16px; font-size: 12px; color: #9ca3af; }
.footer { text-align: center; padding: 20px 40px; border-top: 1px solid #f3f4f6; font-size: 12px; color: #9ca3af; }
</style>
</head>
<body>
<div class="wrapper">
<div class="card">
<div class="header">
<div class="icon">🖥️</div>
<h1>Hosting account mới được khởi tạo</h1>
<p>{{ $domain_name ?? 'N/A' }} — {{ $created_at ?? now()->format('d/m/Y H:i:s') }}</p>
</div>
<div class="body">
<div class="section-label">Thông tin khách hàng</div>
<table class="info-table">
<tr>
<td>Tên khách hàng</td>
<td>{{ $customer_name ?? 'N/A' }}</td>
</tr>
<tr>
<td>Email</td>
<td>{{ $customer_email ?? 'N/A' }}</td>
</tr>
</table>
<div class="section-label">Thông tin dịch vụ Hosting</div>
<table class="info-table">
<tr>
<td>Tên miền</td>
<td>{{ $domain_name ?? 'N/A' }}</td>
</tr>
<tr>
<td>Gói hosting</td>
<td>{{ $hosting_plan ?? 'N/A' }}</td>
</tr>
<tr>
<td>Server</td>
<td>{{ $server_name ?? 'N/A' }} ({{ $server_ip ?? 'N/A' }})</td>
</tr>
<tr>
<td>Plesk Client ID</td>
<td>{{ $plesk_client_id ?? 'N/A' }}</td>
</tr>
<tr>
<td>Plesk Subscription ID</td>
<td>{{ $plesk_subscription_id ?? 'N/A' }}</td>
</tr>
<tr>
<td>Trạng thái</td>
<td><span class="badge badge-green">✅ Active</span></td>
</tr>
</table>
<div class="section-label">Tài khoản FTP / System User (đã gửi cho khách)</div>
<div class="cred-box">
<div class="cred-row">
<span class="cred-label">👤 FTP Username</span>
<span class="cred-value">{{ $ftp_username ?? 'N/A' }}</span>
</div>
@if(!empty($ftp_password))
<div class="cred-row">
<span class="cred-label">🔑 FTP Password</span>
<span class="cred-value">{{ $ftp_password }}</span>
</div>
@endif
</div>
<div class="section-label">Tài khoản đăng nhập Plesk Panel của khách hàng</div>
<div class="cred-box">
<div class="cred-row">
<span class="cred-label">🌐 Panel URL</span>
<span class="cred-value">{{ $plesk_panel_url ?? 'N/A' }}</span>
</div>
<div class="cred-row">
<span class="cred-label">👤 Login</span>
<span class="cred-value">{{ $plesk_login ?? 'N/A' }}</span>
</div>
@if(!empty($plesk_password))
<div class="cred-row">
<span class="cred-label">🔑 Password</span>
<span class="cred-value">{{ $plesk_password }}</span>
</div>
@endif
</div>
<div class="note">
Đây là tài khoản Plesk riêng của khách hàng (đã gửi kèm cho khách), khác với tài khoản quản trị
của server dùng chung — tài khoản quản trị server không được đính kèm trong email này vì lý do
bảo mật.
</div>
</div>
<div class="footer">
© {{ date('Y') }} {{ $company_name ?? 'Portal Admin' }} — Hệ thống quản lý dịch vụ<br>
Email này được gửi tự động. Vui lòng không trả lời.
</div>
</div>
</div>
</body>
</html>
@@ -0,0 +1,231 @@
@php
$appName = $appName ?? config('app.name', 'Thế Giới Số');
$fullName = $fullName ?? 'Quý khách';
$domainName = $domainName ?? '';
$hostingPlan = $hostingPlan ?? '';
$serverHost = $serverHost ?? '';
$ftpUsername = $ftpUsername ?? '';
$ftpPassword = $ftpPassword ?? '';
$pleskLogin = $pleskLogin ?? '';
$pleskPassword = $pleskPassword ?? '';
$pleskPanelUrl = $pleskPanelUrl ?? '';
$loginUrl = $loginUrl ?? rtrim(config('app.frontend_url', ''), '/') . '/dang-nhap';
$supportEmail = $supportEmail ?? 'support@tgs.com.vn';
$supportPhone = $supportPhone ?? '1900. 6119';
@endphp
<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;">
Hosting của bạn đã sẵn sàng
</h1>
<div style="font-size: 14px; line-height: 1.6; color: #ffffff;">
Gói hosting cho tên miền <strong>{{ $domainName }}</strong> đã được khởi tạo thành công
</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;">&nbsp;</div>
<div style="text-align: left;">Xin chào <strong>{{ $fullName }}</strong>,</div>
<div style="text-align: left;">&nbsp;</div>
<div style="text-align: left;">
Dịch vụ hosting của bạn tại <strong>{{ $appName }}</strong> đã được khởi tạo thành công. Dưới đây là thông tin truy cập:
</div>
<div style="text-align: left;">&nbsp;</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ên miền: <strong style="font-family: 'Menlo','Consolas',monospace; color: #111827;">{{ $domainName }}</strong></div>
<div>Gói hosting: <strong style="color: #111827;">{{ $hostingPlan }}</strong></div>
@if($serverHost)
<div>Máy chủ / FTP Host: <strong style="font-family: 'Menlo','Consolas',monospace; color: #111827;">{{ $serverHost }}</strong></div>
@endif
@if($ftpUsername)
<div>Tài khoản FTP: <strong style="font-family: 'Menlo','Consolas',monospace; color: #111827;">{{ $ftpUsername }}</strong></div>
@endif
@if($ftpPassword)
<div>Mật khẩu FTP: <strong style="font-family: 'Menlo','Consolas',monospace; color: #111827;">{{ $ftpPassword }}</strong></div>
@endif
<div>Trạng thái: <strong style="color: #16a34a;">Đang hoạt động ✓</strong></div>
</td>
</tr>
</tbody>
</table>
<div style="text-align: left;">&nbsp;</div>
@if($ftpPassword)
<div style="text-align: left; color: #b45309; font-size: 13px;">
⚠️ Vì lý do bảo mật, mật khẩu FTP chỉ được gửi một lần duy nhất qua email và không được lưu trữ trên hệ thống. Vui lòng lưu lại ở nơi an toàn.
</div>
<div style="text-align: left;">&nbsp;</div>
@endif
@if($pleskLogin)
<div style="text-align: left;"><strong>Tài khoản đăng nhập Plesk Panel</strong> (để tự quản lý domain, DNS, database, mail...):</div>
<div style="text-align: left;">&nbsp;</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>Địa chỉ Panel: <strong><a style="color: #f06824; text-decoration: none;" href="{{ $pleskPanelUrl }}" target="_blank" rel="noopener">{{ $pleskPanelUrl }}</a></strong></div>
<div>Tên đăng nhập: <strong style="font-family: 'Menlo','Consolas',monospace; color: #111827;">{{ $pleskLogin }}</strong></div>
@if($pleskPassword)
<div>Mật khẩu: <strong style="font-family: 'Menlo','Consolas',monospace; color: #111827;">{{ $pleskPassword }}</strong></div>
@endif
</td>
</tr>
</tbody>
</table>
<div style="text-align: left;">&nbsp;</div>
@endif
<div style="text-align: left;">
Bạn có thể đăng nhập vào cổng quản lý để theo dõi và quản lý dịch vụ của mình.
</div>
<div style="text-align: left;">&nbsp;</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;">&nbsp;</div>
<div style="text-align: left; color: #6b7280; font-size: 13px;">
Nếu bạn không yêu cầu dịch vụ này, vui lòng liên hệ ngay với chúng tôi qua <strong>{{ $supportEmail }}</strong> hoặc <strong>{{ $supportPhone }}</strong>.
</div>
<div style="text-align: left;">&nbsp;</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;">&nbsp;</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;">&nbsp;</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;">&nbsp;</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;">&nbsp;</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;">&nbsp;</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;">&nbsp;</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;">&nbsp;</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;">&nbsp;</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;">&nbsp;</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;">&nbsp;</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">&nbsp;</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> &amp;
<a style="color: #ffffff !important; text-decoration: none;" href="https://www.thegioiso.cloud">www.thegioiso.CLOUD</a> &amp;
<a style="color: #ffffff !important; text-decoration: none;" href="https://www.thegioiserver.com">www.thegioiSERVER.com</a> &amp;
<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 &amp; 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;">&nbsp;</span></td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>