erp-backend/app/Services/MailService.php
2026-04-01 17:07:04 +08:00

302 lines
11 KiB
PHP

<?php
namespace App\Services;
use App\Models\SystemConfig;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Cache;
class MailService
{
/**
* 发送配对码邮件
*/
public function sendPairCode(string $email, string $code, int $expireMinutes = 10): bool
{
try {
$config = $this->getMailConfig();
if (!$config['enabled']) {
\Log::warning('邮件服务未启用');
return false;
}
$siteName = SystemConfig::getValue('system', 'site_name', 'ERP系统');
Mail::send([], [], function ($message) use ($email, $code, $expireMinutes, $config, $siteName) {
$message->to($email)
->from($config['from_email'], $config['from_name'])
->subject("{$siteName}】异地登录验证 - 配对码")
->html($this->buildPairCodeEmail($code, $expireMinutes, $siteName));
});
return true;
} catch (\Exception $e) {
\Log::error('发送配对码邮件失败: ' . $e->getMessage());
return false;
}
}
/**
* 发送邮箱修改验证码
*/
public function sendEmailChangeCode(string $newEmail, string $code, string $userName = ''): bool
{
try {
$config = $this->getMailConfig();
if (!$config['enabled']) {
\Log::warning('邮件服务未启用');
return false;
}
$siteName = SystemConfig::getValue('system', 'site_name', 'ERP系统');
Mail::send([], [], function ($message) use ($newEmail, $code, $config, $siteName, $userName) {
$message->to($newEmail)
->from($config['from_email'], $config['from_name'])
->subject("{$siteName}】邮箱修改验证码")
->html($this->buildEmailChangeEmail($code, $siteName, $userName));
});
return true;
} catch (\Exception $e) {
\Log::error('发送邮箱修改验证码邮件失败: ' . $e->getMessage());
return false;
}
}
/**
* 发送重置密码邮件
*/
public function sendResetPasswordCode(string $email, string $code, int $expireMinutes = 30): bool
{
try {
$config = $this->getMailConfig();
if (!$config['enabled']) {
\Log::warning('邮件服务未启用');
return false;
}
$siteName = SystemConfig::getValue('system', 'site_name', 'ERP系统');
Mail::send([], [], function ($message) use ($email, $code, $expireMinutes, $config, $siteName) {
$message->to($email)
->from($config['from_email'], $config['from_name'])
->subject("{$siteName}】密码重置验证码")
->html($this->buildResetPasswordEmail($code, $expireMinutes, $siteName));
});
return true;
} catch (\Exception $e) {
\Log::error('发送重置密码邮件失败: ' . $e->getMessage());
return false;
}
}
/**
* 获取邮件配置
*/
public function getMailConfig(): array
{
$cacheKey = 'mail_service_config';
return Cache::remember($cacheKey, 3600, function () {
return [
'enabled' => SystemConfig::getValue('mail', 'enabled', false),
'driver' => SystemConfig::getValue('mail', 'driver', 'smtp'),
'host' => SystemConfig::getValue('mail', 'host', ''),
'port' => (int) SystemConfig::getValue('mail', 'port', 465),
'encryption' => SystemConfig::getValue('mail', 'encryption', 'ssl'),
'username' => SystemConfig::getValue('mail', 'username', ''),
'password' => SystemConfig::getValue('mail', 'password', ''),
'from_email' => SystemConfig::getValue('mail', 'from_email', 'noreply@erp.local'),
'from_name' => SystemConfig::getValue('mail', 'from_name', 'ERP系统'),
];
});
}
/**
* 应用邮件配置到 Laravel
*/
public function applyConfig(): void
{
$config = $this->getMailConfig();
if (!$config['enabled']) {
return;
}
config([
'mail.default' => $config['driver'],
'mail.mailers.smtp.host' => $config['host'],
'mail.mailers.smtp.port' => $config['port'],
'mail.mailers.smtp.encryption' => $config['encryption'],
'mail.mailers.smtp.username' => $config['username'],
'mail.mailers.smtp.password' => $config['password'],
'mail.from.address' => $config['from_email'],
'mail.from.name' => $config['from_name'],
]);
}
/**
* 测试邮件连接
*/
public function testConnection(): array
{
try {
$config = $this->getMailConfig();
if (!$config['enabled']) {
return ['success' => false, 'message' => '邮件服务未启用'];
}
Mail::send([], [], function ($message) use ($config) {
$message->to($config['from_email'])
->from($config['from_email'], $config['from_name'])
->subject('ERP邮件服务测试')
->text('这是一封测试邮件,证明邮件服务配置正确。');
});
return ['success' => true, 'message' => '邮件发送成功'];
} catch (\Exception $e) {
return ['success' => false, 'message' => '邮件发送失败: ' . $e->getMessage()];
}
}
/**
* 构建配对码邮件内容
*/
private function buildPairCodeEmail(string $code, int $expireMinutes, string $siteName): string
{
return <<<HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body { font-family: Arial, sans-serif; background: #f5f5f5; margin: 0; padding: 20px; }
.container { max-width: 500px; margin: 0 auto; background: #fff; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
.header { background: #409eff; color: #fff; padding: 24px; text-align: center; }
.header h1 { margin: 0; font-size: 20px; }
.content { padding: 32px 24px; }
.code-box { background: #f8f9fa; border: 2px dashed #409eff; border-radius: 8px; padding: 20px; text-align: center; margin: 20px 0; }
.code { font-size: 32px; font-weight: bold; letter-spacing: 8px; color: #409eff; }
.warning { color: #e6a23c; font-size: 14px; margin-top: 16px; }
.footer { background: #f5f7fa; padding: 16px; text-align: center; font-size: 12px; color: #909399; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>【{$siteName}】异地登录验证</h1>
</div>
<div class="content">
<p>您好,您在另一台设备尝试登录您的账号。</p>
<p>以下是您的登录配对码:</p>
<div class="code-box">
<div class="code">{$code}</div>
</div>
<p class="warning">⚠️ 配对码有效期为 {$expireMinutes} 分钟,请勿告诉他人!</p>
<p>如果不是您本人操作,请忽略此邮件,并建议您尽快修改密码。</p>
</div>
<div class="footer">
<p>此邮件由系统自动发送,请勿回复。</p>
</div>
</div>
</body>
</html>
HTML;
}
/**
* 构建重置密码邮件内容
*/
private function buildResetPasswordEmail(string $code, int $expireMinutes, string $siteName): string
{
return <<<HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body { font-family: Arial, sans-serif; background: #f5f5f5; margin: 0; padding: 20px; }
.container { max-width: 500px; margin: 0 auto; background: #fff; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
.header { background: #67c23a; color: #fff; padding: 24px; text-align: center; }
.header h1 { margin: 0; font-size: 20px; }
.content { padding: 32px 24px; }
.code-box { background: #f8f9fa; border: 2px dashed #67c23a; border-radius: 8px; padding: 20px; text-align: center; margin: 20px 0; }
.code { font-size: 32px; font-weight: bold; letter-spacing: 8px; color: #67c23a; }
.warning { color: #e6a23c; font-size: 14px; margin-top: 16px; }
.footer { background: #f5f7fa; padding: 16px; text-align: center; font-size: 12px; color: #909399; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>【{$siteName}】密码重置验证码</h1>
</div>
<div class="content">
<p>您正在重置账号密码,请使用以下验证码:</p>
<div class="code-box">
<div class="code">{$code}</div>
</div>
<p class="warning">⚠️ 验证码有效期为 {$expireMinutes} 分钟,请勿告诉他人!</p>
<p>如果不是您本人操作,请忽略此邮件。</p>
</div>
<div class="footer">
<p>此邮件由系统自动发送,请勿回复。</p>
</div>
</div>
</body>
</html>
HTML;
}
/**
* 构建邮箱修改验证码邮件
*/
private function buildEmailChangeEmail(string $code, string $siteName, string $userName = ''): string
{
$greeting = $userName ? "亲爱的 {$userName}" : "您好";
return <<<HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body { font-family: Arial, sans-serif; background: #f5f5f5; margin: 0; padding: 20px; }
.container { max-width: 500px; margin: 0 auto; background: #fff; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
.header { background: #409eff; color: #fff; padding: 24px; text-align: center; }
.header h1 { margin: 0; font-size: 20px; }
.content { padding: 32px 24px; }
.code-box { background: #f8f9fa; border: 2px dashed #409eff; border-radius: 8px; padding: 20px; text-align: center; margin: 20px 0; }
.code { font-size: 32px; font-weight: bold; letter-spacing: 8px; color: #409eff; }
.warning { color: #e6a23c; font-size: 14px; margin-top: 16px; }
.footer { background: #f5f7fa; padding: 16px; text-align: center; font-size: 12px; color: #909399; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>【{$siteName}】邮箱修改验证码</h1>
</div>
<div class="content">
<p>{$greeting},您正在修改绑定邮箱,请使用以下验证码:</p>
<div class="code-box">
<div class="code">{$code}</div>
</div>
<p class="warning">⚠️ 验证码有效期为 30 分钟,请勿告诉他人!</p>
<p>如果不是您本人操作,请忽略此邮件。</p>
</div>
<div class="footer">
<p>此邮件由系统自动发送,请勿回复。</p>
</div>
</div>
</body>
</html>
HTML;
}
}