소스 검색

系统邮件

Tree 4 시간 전
부모
커밋
6a2614d2f7

+ 105 - 0
app/Http/Controllers/Admin/NoticeController.php

@@ -389,4 +389,109 @@ class NoticeController extends Controller
         }
         return view('admin.notice.horse_race_lamp_update', compact('info', 'id'));
     }
+
+    public function routeMailList()
+    {
+        $list = DB::connection('write')->table('QPAccountsDB.dbo.RouteMailConfig')
+            ->orderBy('ID', 'desc')
+            ->paginate(20);
+
+        return view('admin.notice.route_mail', compact('list'));
+    }
+
+    public function routeMailAdd(Request $request)
+    {
+        if ($request->isMethod('post')) {
+            $mark = trim((string) $request->input('MailMark', ''));
+            $title = trim((string) $request->input('TitleString', ''));
+            $text = trim((string) $request->input('TextString', ''));
+            $status = (int) $request->input('Status', 1);
+
+            if ($mark === '' || $title === '' || $text === '') {
+                return $this->json(500, 'Mail mark, title and content are required');
+            }
+
+            if (!preg_match('/^[A-Za-z0-9_\-]{1,100}$/', $mark)) {
+                return $this->json(500, 'Mail mark only allows letters, numbers, underscore and dash, max length 100');
+            }
+
+            $now = date('Y-m-d H:i:s');
+            try {
+                DB::connection('write')->table('QPAccountsDB.dbo.RouteMailConfig')->insert([
+                    'MailMark' => $mark,
+                    'TitleString' => $title,
+                    'TextString' => mb_strlen($text) > 500 ? mb_substr($text, 0, 500) : $text,
+                    'Status' => $status ? 1 : 0,
+                    'CreatedAt' => $now,
+                    'UpdatedAt' => $now,
+                ]);
+            } catch (\Throwable $exception) {
+                return $this->json(500, 'Save failed, mail mark may already exist');
+            }
+
+            return apiReturnSuc();
+        }
+
+        return view('admin.notice.route_mail_form', ['info' => null]);
+    }
+
+    public function routeMailUpdate(Request $request, $id)
+    {
+        if ($request->isMethod('post')) {
+            $title = trim((string) $request->input('TitleString', ''));
+            $text = trim((string) $request->input('TextString', ''));
+            $status = (int) $request->input('Status', 1);
+
+            if ($title === '' || $text === '') {
+                return $this->json(500, 'Title and content are required');
+            }
+
+            DB::connection('write')->table('QPAccountsDB.dbo.RouteMailConfig')
+                ->where('ID', $id)
+                ->update([
+                    'TitleString' => $title,
+                    'TextString' => mb_strlen($text) > 500 ? mb_substr($text, 0, 500) : $text,
+                    'Status' => $status ? 1 : 0,
+                    'UpdatedAt' => date('Y-m-d H:i:s'),
+                ]);
+
+            return apiReturnSuc();
+        }
+
+        $info = DB::connection('write')->table('QPAccountsDB.dbo.RouteMailConfig')->where('ID', $id)->first();
+        return view('admin.notice.route_mail_form', compact('info'));
+    }
+
+    public function routeMailSwitch($id)
+    {
+        $info = DB::connection('write')->table('QPAccountsDB.dbo.RouteMailConfig')->where('ID', $id)->first();
+        if (!$info) {
+            return $this->json(500, 'Config not found');
+        }
+
+        DB::connection('write')->table('QPAccountsDB.dbo.RouteMailConfig')
+            ->where('ID', $id)
+            ->update([
+                'Status' => $info->Status ? 0 : 1,
+                'UpdatedAt' => date('Y-m-d H:i:s'),
+            ]);
+
+        return apiReturnSuc();
+    }
+
+    public function routeMailDelete($id)
+    {
+        $info = DB::connection('write')->table('QPAccountsDB.dbo.RouteMailConfig')->where('ID', $id)->first();
+        if (!$info) {
+            return $this->json(500, 'Config not found');
+        }
+
+        DB::connection('write')->transaction(function () use ($id, $info) {
+            DB::connection('write')->table('QPAccountsDB.dbo.RouteMailConfig')->where('ID', $id)->delete();
+            DB::connection('write')->table('QPAccountsDB.dbo.RouteMailSendLog')->where('MailMark', $info->MailMark)->delete();
+        });
+
+        return apiReturnSuc();
+    }
+
 }

+ 2 - 0
app/Http/Controllers/Game/WebRouteController.php

@@ -26,6 +26,7 @@ use App\Http\helper\NumConfig;
 use App\IpLocation;
 use App\Models\AccountsInfo;
 use App\Models\AccountLoginDomain;
+use App\Models\RouteMailConfig;
 use App\Models\SystemStatusInfo;
 use App\Jobs\IpRiskDetection;
 use App\Services\ApkService;
@@ -98,6 +99,7 @@ class WebRouteController extends Controller
         $user = GlobalUserInfo::$me;//LoginController::checkLogin($request);
         if ($user) {
             $this->recordLoginDomain($request, $user->UserID ?? 0, $user->Channel ?? 0);
+            RouteMailConfig::sendPendingForUser($user->UserID ?? 0);
             $ua = $request->userAgent();
             if (stripos($ua, 'iPhone') !== false) {
                 $mobileBand = 'iPhone';

+ 87 - 0
app/Models/RouteMailConfig.php

@@ -0,0 +1,87 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Log;
+
+class RouteMailConfig extends Model
+{
+    const TABLE = 'QPAccountsDB.dbo.RouteMailConfig';
+
+    protected $table = self::TABLE;
+
+    public $timestamps = false;
+
+    protected $fillable = [
+        'MailMark',
+        'TitleString',
+        'TextString',
+        'Status',
+        'CreatedAt',
+        'UpdatedAt',
+    ];
+
+    public static function sendPendingForUser($userId)
+    {
+        $userId = (int) $userId;
+        if ($userId <= 0) {
+            return;
+        }
+
+        try {
+            $configs = DB::connection('write')->table(self::TABLE)
+                ->where('Status', 1)
+                ->orderBy('ID')
+                ->get();
+        } catch (\Throwable $exception) {
+            Log::warning('route_mail_config_load_failed', [
+                'UserID' => $userId,
+                'message' => $exception->getMessage(),
+            ]);
+
+            return;
+        }
+
+        foreach ($configs as $config) {
+            self::sendOnce($userId, $config);
+        }
+    }
+
+    private static function sendOnce($userId, $config)
+    {
+        $mark = trim((string) ($config->MailMark ?? ''));
+        if ($mark === '') {
+            return;
+        }
+
+        if (!RouteMailSendLog::markSent($userId, $mark)) {
+            return;
+        }
+
+        try {
+            PrivateMail::sendMail(
+                2,
+                $userId,
+                (string) $config->TitleString,
+                (string) $config->TextString,
+                '',
+                'route_mail_' . $mark . '_' . $userId,
+                0,
+                3
+            );
+        } catch (\Throwable $exception) {
+            DB::connection('write')->table(RouteMailSendLog::TABLE)
+                ->where('UserID', $userId)
+                ->where('MailMark', $mark)
+                ->delete();
+
+            Log::warning('route_mail_send_failed', [
+                'UserID' => $userId,
+                'MailMark' => $mark,
+                'message' => $exception->getMessage(),
+            ]);
+        }
+    }
+}

+ 41 - 0
app/Models/RouteMailSendLog.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Log;
+
+class RouteMailSendLog extends Model
+{
+    const TABLE = 'QPAccountsDB.dbo.RouteMailSendLog';
+
+    protected $table = self::TABLE;
+
+    public $timestamps = false;
+
+    protected $fillable = [
+        'UserID',
+        'MailMark',
+        'CreatedAt',
+    ];
+
+    public static function markSent($userId, $mark)
+    {
+        try {
+            return DB::connection('write')->table(self::TABLE)->insert([
+                'UserID' => (int) $userId,
+                'MailMark' => (string) $mark,
+                'CreatedAt' => date('Y-m-d H:i:s'),
+            ]);
+        } catch (\Throwable $exception) {
+            Log::info('route_mail_already_sent', [
+                'UserID' => $userId,
+                'MailMark' => $mark,
+                'message' => $exception->getMessage(),
+            ]);
+
+            return false;
+        }
+    }
+}

+ 110 - 0
resources/views/admin/notice/route_mail.blade.php

@@ -0,0 +1,110 @@
+@extends('base.base')
+@section('base')
+    <div class="main-panel">
+        <div class="content-wrapper">
+            <div class="page-header">
+                <h3 class="page-title">
+                    <span class="page-title-icon bg-gradient-primary text-white mr-2">
+                        <i class="mdi mdi-email"></i>
+                    </span>
+                    Route Mail Config
+                </h3>
+            </div>
+            <div class="row">
+                <div class="col-lg-12 grid-margin stretch-card">
+                    <div class="card">
+                        <div class="card-body">
+                            <div style="margin-bottom: 15px;">
+                                <button type="button" class="btn btn-sm btn-gradient-success btn-icon-text" onclick="add()">
+                                    <i class="mdi mdi-plus btn-icon-prepend"></i>
+                                    Add Mail
+                                </button>
+                            </div>
+                            <table class="table table-bordered">
+                                <thead>
+                                <tr>
+                                    <th>ID</th>
+                                    <th>Mark</th>
+                                    <th>Title</th>
+                                    <th>Content</th>
+                                    <th>Status</th>
+                                    <th>Updated At</th>
+                                    <th>Actions</th>
+                                </tr>
+                                </thead>
+                                <tbody>
+                                @foreach($list as $item)
+                                    <tr>
+                                        <td>{{ $item->ID }}</td>
+                                        <td>{{ $item->MailMark }}</td>
+                                        <td>{{ $item->TitleString }}</td>
+                                        <td style="max-width: 360px; white-space: normal;">{{ $item->TextString }}</td>
+                                        <td>{{ $item->Status ? 'Enabled' : 'Disabled' }}</td>
+                                        <td>{{ $item->UpdatedAt }}</td>
+                                        <td>
+                                            <button type="button" class="btn btn-sm btn-gradient-dark" onclick="update({{ $item->ID }})">Edit</button>
+                                            <button type="button" class="btn btn-sm btn-gradient-warning" onclick="switchStatus({{ $item->ID }})">
+                                                {{ $item->Status ? 'Disable' : 'Enable' }}
+                                            </button>
+                                            <button type="button" class="btn btn-sm btn-gradient-danger" onclick="del({{ $item->ID }})">Delete</button>
+                                        </td>
+                                    </tr>
+                                @endforeach
+                                </tbody>
+                            </table>
+                            <div class="box-footer clearfix">
+                                Total <b>{{ $list->total() }}</b> rows, <b>{{ $list->lastPage() }}</b> pages
+                                {!! $list->links() !!}
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    <script>
+        function add() {
+            layer.open({
+                type: 2,
+                title: 'Add Route Mail',
+                shadeClose: true,
+                shade: 0.8,
+                area: ['60%', '75%'],
+                content: '/admin/notice/route_mail/add'
+            });
+        }
+
+        function update(id) {
+            layer.open({
+                type: 2,
+                title: 'Edit Route Mail',
+                shadeClose: true,
+                shade: 0.8,
+                area: ['60%', '75%'],
+                content: '/admin/notice/route_mail/update/' + id
+            });
+        }
+
+        function switchStatus(id) {
+            myConfirm('Confirm status change?', function () {
+                myRequest('/admin/notice/route_mail/switch/' + id, 'post', {}, function (res) {
+                    layer.msg(res.msg);
+                    setTimeout(function () {
+                        window.location.reload();
+                    }, 1000);
+                });
+            });
+        }
+
+        function del(id) {
+            myConfirm('Delete config and related send logs?', function () {
+                myRequest('/admin/notice/route_mail/delete/' + id, 'post', {}, function (res) {
+                    layer.msg(res.msg);
+                    setTimeout(function () {
+                        window.location.reload();
+                    }, 1000);
+                });
+            });
+        }
+    </script>
+@endsection

+ 71 - 0
resources/views/admin/notice/route_mail_form.blade.php

@@ -0,0 +1,71 @@
+@extends('base.base')
+@section('base')
+    <div class="main-panel">
+        <div class="content-wrapper">
+            <div class="row">
+                <div class="col-12 grid-margin stretch-card">
+                    <div class="card">
+                        <div class="card-body">
+                            <h4 class="card-title">{{ $info ? 'Edit Route Mail' : 'Add Route Mail' }}</h4>
+                            <form class="forms-sample" id="form">
+                                <div class="form-group">
+                                    <label>* Mark</label>
+                                    <input type="text"
+                                           class="form-control required"
+                                           name="MailMark"
+                                           placeholder="e.g. welcome_v1"
+                                           value="{{ $info->MailMark ?? '' }}"
+                                           @if($info) disabled @endif>
+                                    <small class="form-text text-muted">The same mark is sent only once per user. Editing content will not resend to users who already received it.</small>
+                                </div>
+                                <div class="form-group">
+                                    <label>* Title</label>
+                                    <input type="text" class="form-control required" name="TitleString" value="{{ $info->TitleString ?? '' }}">
+                                </div>
+                                <div class="form-group">
+                                    <label>* Content</label>
+                                    <textarea class="form-control required" name="TextString" rows="8">{{ $info->TextString ?? '' }}</textarea>
+                                </div>
+                                <div class="form-group">
+                                    <label>* Status</label>
+                                    <select class="form-control" name="Status">
+                                        <option value="1" @if(!$info || $info->Status) selected @endif>Enabled</option>
+                                        <option value="0" @if($info && !$info->Status) selected @endif>Disabled</option>
+                                    </select>
+                                </div>
+                                <button type="button" onclick="commit()" class="btn btn-sm btn-gradient-primary btn-icon-text">
+                                    <i class="mdi mdi-file-check btn-icon-prepend"></i>
+                                    Submit
+                                </button>
+                                <button type="button" onclick="cancel()" class="btn btn-sm btn-gradient-warning btn-icon-text">
+                                    <i class="mdi mdi-reload btn-icon-prepend"></i>
+                                    Cancel
+                                </button>
+                            </form>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    <script>
+        function commit() {
+            if (!checkForm()) {
+                return false;
+            }
+
+            var url = '{{ $info ? "/admin/notice/route_mail/update/" . $info->ID : "/admin/notice/route_mail/add" }}';
+            var data = $("#form").serializeObject();
+            myRequest(url, 'post', data, function (res) {
+                layer.msg(res.msg);
+                setTimeout(function () {
+                    parent.location.reload();
+                }, 1000);
+            });
+        }
+
+        function cancel() {
+            parent.location.reload();
+        }
+    </script>
+@endsection

+ 5 - 0
routes/web.php

@@ -168,6 +168,11 @@ Route::group([
         $route->any('/notice/hall_announcement_del/{id}', 'Admin\NoticeController@hallAnnouncementDel');
         $route->any('/notice/horse_race_lamp', 'Admin\NoticeController@horse_race_lamp');
         $route->any('/notice/horse_race_lamp_update/{id}', 'Admin\NoticeController@horse_race_lamp_update');
+        $route->get('/notice/route_mail', 'Admin\NoticeController@routeMailList')->defaults('name', 'Route Mail Config');
+        $route->any('/notice/route_mail/add', 'Admin\NoticeController@routeMailAdd');
+        $route->any('/notice/route_mail/update/{id}', 'Admin\NoticeController@routeMailUpdate');
+        $route->post('/notice/route_mail/switch/{id}', 'Admin\NoticeController@routeMailSwitch');
+        $route->post('/notice/route_mail/delete/{id}', 'Admin\NoticeController@routeMailDelete');
 
 
         $route->get('/notice/version', 'Admin\NoticeController@versionList');