Browse Source

20220826 reCaptcha, bootstrap 3 to 5

LuluFJ.Ho 2 years ago
parent
commit
187cfe0d10

+ 32
- 0
app/Http/Controllers/Auth/ForgotPasswordController.php View File

1
+<?php
2
+
3
+namespace App\Http\Controllers\Auth;
4
+
5
+use App\Http\Controllers\Controller;
6
+use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
7
+
8
+class ForgotPasswordController extends Controller
9
+{
10
+    /*
11
+    |--------------------------------------------------------------------------
12
+    | Password Reset Controller
13
+    |--------------------------------------------------------------------------
14
+    |
15
+    | This controller is responsible for handling password reset emails and
16
+    | includes a trait which assists in sending these notifications from
17
+    | your application to your users. Feel free to explore this trait.
18
+    |
19
+    */
20
+
21
+    use SendsPasswordResetEmails;
22
+
23
+    /**
24
+     * Create a new controller instance.
25
+     *
26
+     * @return void
27
+     */
28
+    public function __construct()
29
+    {
30
+        $this->middleware('guest');
31
+    }
32
+}

+ 66
- 0
app/Http/Controllers/Auth/LoginController.php View File

1
+<?php
2
+
3
+namespace App\Http\Controllers\Auth;
4
+
5
+use App\Http\Controllers\Controller;
6
+use Illuminate\Http\Request;
7
+use Illuminate\Foundation\Auth\AuthenticatesUsers;
8
+use Illuminate\Support\Facades\Auth;
9
+use Illuminate\Validation\ValidationException;
10
+use Redirect;
11
+use Session;
12
+
13
+class LoginController extends Controller
14
+{
15
+    /*
16
+    |--------------------------------------------------------------------------
17
+    | Login Controller
18
+    |--------------------------------------------------------------------------
19
+    |
20
+    | This controller handles authenticating users for the application and
21
+    | redirecting them to your home screen. The controller uses a trait
22
+    | to conveniently provide its functionality to your applications.
23
+    |
24
+    */
25
+
26
+    use AuthenticatesUsers;
27
+
28
+    /**
29
+     * Where to redirect users after login.
30
+     *
31
+     * @var string
32
+     */
33
+    protected $redirectTo = '/backend';
34
+
35
+    protected $maxAttempts = 5;
36
+    protected $decayMinutes = 10;
37
+
38
+    /**
39
+     * Create a new controller instance.
40
+     *
41
+     * @return void
42
+     */
43
+    public function __construct()
44
+    {
45
+        $this->middleware('guest', ['except' => 'logout']);
46
+    }
47
+    
48
+    protected function validateLogin(Request $request)
49
+    {
50
+        $validateRules = [
51
+            'g-recaptcha-response' => 'required',
52
+        ];
53
+
54
+        $validateMessage = [
55
+            'g-recaptcha-response.required' => '請點選我不是機器人',
56
+        ];
57
+
58
+        $request->validate($validateRules, $validateMessage);
59
+
60
+        $recaptcha = new \ReCaptcha\ReCaptcha('6LfDoKIhAAAAABrav1PgguhuAZCHgJibpDD8tbQZ');
61
+        $resp = $recaptcha->verify($request->input('g-recaptcha-response'), $request->ip());
62
+        if (!$resp->isSuccess()) {
63
+            throw ValidationException::withMessages(['error' => 'recaptcha 驗證失敗']);
64
+        }
65
+    }
66
+}

+ 71
- 0
app/Http/Controllers/Auth/RegisterController.php View File

1
+<?php
2
+
3
+namespace App\Http\Controllers\Auth;
4
+
5
+use App\User;
6
+use App\Http\Controllers\Controller;
7
+use Illuminate\Support\Facades\Validator;
8
+use Illuminate\Foundation\Auth\RegistersUsers;
9
+
10
+class RegisterController extends Controller
11
+{
12
+    /*
13
+    |--------------------------------------------------------------------------
14
+    | Register Controller
15
+    |--------------------------------------------------------------------------
16
+    |
17
+    | This controller handles the registration of new users as well as their
18
+    | validation and creation. By default this controller uses a trait to
19
+    | provide this functionality without requiring any additional code.
20
+    |
21
+    */
22
+
23
+    use RegistersUsers;
24
+
25
+    /**
26
+     * Where to redirect users after registration.
27
+     *
28
+     * @var string
29
+     */
30
+    protected $redirectTo = '/backend';
31
+
32
+    /**
33
+     * Create a new controller instance.
34
+     *
35
+     * @return void
36
+     */
37
+    public function __construct()
38
+    {
39
+        $this->middleware('guest');
40
+    }
41
+
42
+    /**
43
+     * Get a validator for an incoming registration request.
44
+     *
45
+     * @param  array  $data
46
+     * @return \Illuminate\Contracts\Validation\Validator
47
+     */
48
+    protected function validator(array $data)
49
+    {
50
+        return Validator::make($data, [
51
+            'name' => 'required|max:255',
52
+            'email' => 'required|email|max:255|unique:users',
53
+            'password' => 'required|min:6|confirmed',
54
+        ]);
55
+    }
56
+
57
+    /**
58
+     * Create a new user instance after a valid registration.
59
+     *
60
+     * @param  array  $data
61
+     * @return User
62
+     */
63
+    protected function create(array $data)
64
+    {
65
+        return User::create([
66
+            'name' => $data['name'],
67
+            'email' => $data['email'],
68
+            'password' => bcrypt($data['password']),
69
+        ]);
70
+    }
71
+}

+ 39
- 0
app/Http/Controllers/Auth/ResetPasswordController.php View File

1
+<?php
2
+
3
+namespace App\Http\Controllers\Auth;
4
+
5
+use App\Http\Controllers\Controller;
6
+use Illuminate\Foundation\Auth\ResetsPasswords;
7
+
8
+class ResetPasswordController extends Controller
9
+{
10
+    /*
11
+    |--------------------------------------------------------------------------
12
+    | Password Reset Controller
13
+    |--------------------------------------------------------------------------
14
+    |
15
+    | This controller is responsible for handling password reset requests
16
+    | and uses a simple trait to include this behavior. You're free to
17
+    | explore this trait and override any methods you wish to tweak.
18
+    |
19
+    */
20
+
21
+    use ResetsPasswords;
22
+
23
+    /**
24
+     * Where to redirect users after resetting their password.
25
+     *
26
+     * @var string
27
+     */
28
+    protected $redirectTo = '/backend';
29
+
30
+    /**
31
+     * Create a new controller instance.
32
+     *
33
+     * @return void
34
+     */
35
+    public function __construct()
36
+    {
37
+        $this->middleware('guest');
38
+    }
39
+}

+ 2
- 2
config/app.php View File

67
     |
67
     |
68
     */
68
     */
69
 
69
 
70
-    'timezone' => 'UTC',
70
+    'timezone' => 'Asia/Taipei',
71
 
71
 
72
     /*
72
     /*
73
     |--------------------------------------------------------------------------
73
     |--------------------------------------------------------------------------
80
     |
80
     |
81
     */
81
     */
82
 
82
 
83
-    'locale' => 'en',
83
+    'locale' => 'zh-TW',
84
 
84
 
85
     /*
85
     /*
86
     |--------------------------------------------------------------------------
86
     |--------------------------------------------------------------------------

+ 186
- 13
public/assets/css/bootstrap-override.css View File

138
    font-size: 12px;
138
    font-size: 12px;
139
    padding: 7px 10px;
139
    padding: 7px 10px;
140
    height: auto;
140
    height: auto;
141
-   margin-top: 3px;
142
 }
141
 }
143
 
142
 
144
 .input-lg {
143
 .input-lg {
165
    padding: 5px 10px;
164
    padding: 5px 10px;
166
 }
165
 }
167
 
166
 
168
-.btn-xs {
167
+.btn-sm {
169
    padding: 2px 10px;
168
    padding: 2px 10px;
170
 }
169
 }
171
 
170
 
173
    padding: 12px 20px;
172
    padding: 12px 20px;
174
 }
173
 }
175
 
174
 
176
-.btn-default {
175
+.btn-secondary {
177
    background: #e4e7ea;
176
    background: #e4e7ea;
178
    color: #636e7b;
177
    color: #636e7b;
179
 }
178
 }
180
 
179
 
181
-.btn-default:hover,
182
-.btn-default:focus,
183
-.btn-default:active,
184
-.btn-default.active,
185
-.open .dropdown-toggle.btn-default {
180
+.btn-secondary:hover,
181
+.btn-secondary:focus,
182
+.btn-secondary:active,
183
+.btn-secondary.active,
184
+.open .dropdown-toggle.btn-secondary {
186
    background: #f7f7f7;
185
    background: #f7f7f7;
187
    border-color: #ccc;
186
    border-color: #ccc;
188
    -moz-box-shadow: none;
187
    -moz-box-shadow: none;
228
    background: #f7f7f7;
227
    background: #f7f7f7;
229
 }
228
 }
230
 
229
 
231
-.btn-default-alt {
230
+.btn-secondary-alt {
232
    border: 2px solid #999;
231
    border: 2px solid #999;
233
    color: #999;
232
    color: #999;
234
    text-transform: uppercase;
233
    text-transform: uppercase;
236
    font-size: 12px;
235
    font-size: 12px;
237
 }
236
 }
238
 
237
 
239
-.btn-default-alt:hover,
240
-.btn-default-alt:active,
241
-.btn-default-alt:focus {
238
+.btn-secondary-alt:hover,
239
+.btn-secondary-alt:active,
240
+.btn-secondary-alt:focus {
242
    border-color: #666;
241
    border-color: #666;
243
    color: #666;
242
    color: #666;
244
 }
243
 }
575
    box-shadow: 0 3px 0 rgba(12,12,12,0.03);
574
    box-shadow: 0 3px 0 rgba(12,12,12,0.03);
576
 }
575
 }
577
 
576
 
577
+.panel-footer {
578
+   padding: 10px 15px;
579
+   background-color: #f5f5f5;
580
+   border-top: 1px solid #ddd;
581
+   border-bottom-right-radius: 3px;
582
+   border-bottom-left-radius: 3px;
583
+}
584
+
578
 .panel-heading,
585
 .panel-heading,
579
 .panel-footer {
586
 .panel-footer {
580
    background: #fff;
587
    background: #fff;
581
-   border-color: #eee;
588
+   /*border-color: #eee;*/
582
 }
589
 }
583
 
590
 
584
 .panel-heading {
591
 .panel-heading {
1044
    color: #fff;
1051
    color: #fff;
1045
 }
1052
 }
1046
 
1053
 
1054
+.nav-primary {
1055
+    background: #428BCA;
1056
+ }
1057
+ 
1058
+ .nav-primary > li > a {
1059
+    color: #fff;
1060
+ }
1061
+ 
1062
+ .nav-primary > li > a:hover {
1063
+    color: #1d2939;
1064
+ }
1065
+
1047
 .nav-tabs.nav-justified > li > a {
1066
 .nav-tabs.nav-justified > li > a {
1048
    border-bottom: 0;
1067
    border-bottom: 0;
1049
 }
1068
 }
1308
    -webkit-box-shadow: none;
1327
    -webkit-box-shadow: none;
1309
    box-shadow: none;
1328
    box-shadow: none;
1310
 }
1329
 }
1330
+
1331
+
1332
+
1333
+
1334
+/* add by Yong reference bootstrap3 */
1335
+.btn-group-vertical>.btn-group:after, .btn-group-vertical>.btn-group:before, .btn-toolbar:after, .btn-toolbar:before, .clearfix:after, .clearfix:before, .container-fluid:after, .container-fluid:before, .container:after, .container:before, .dl-horizontal dd:after, .dl-horizontal dd:before, .form-horizontal .form-group:after, .form-horizontal .form-group:before, .modal-footer:after, .modal-footer:before, ._nav:after, ._nav:before, .navbar-collapse:after, .navbar-collapse:before, .navbar-header:after, .navbar-header:before, .navbar:after, .navbar:before, .pager:after, .pager:before, .panel-body:after, .panel-body:before, .row:after, .row:before {
1336
+   display: table;
1337
+   content: " ";
1338
+}
1339
+
1340
+@font-face {
1341
+   font-family: 'Glyphicons Halflings';
1342
+
1343
+   src: url('../fonts/glyphicons-halflings-regular.eot');
1344
+   src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
1345
+}
1346
+._glyphicon {
1347
+   position: relative;
1348
+   top: 1px;
1349
+   display: inline-block;
1350
+   font-family: 'Glyphicons Halflings';
1351
+   font-style: normal;
1352
+   font-weight: normal;
1353
+   line-height: 1;
1354
+
1355
+   -webkit-font-smoothing: antialiased;
1356
+   -moz-osx-font-smoothing: grayscale;
1357
+}
1358
+._glyphicon-log-out:before {
1359
+   content: "\e163";
1360
+}
1361
+._glyphicon-search:before {
1362
+   content: "\e003";
1363
+}
1364
+._glyphicon-pencil:before {
1365
+   content: "\270f";
1366
+}
1367
+._glyphicon-calendar:before {
1368
+   content: "\e109";
1369
+}
1370
+._glyphicon-plus:before {
1371
+   content: "\2b";
1372
+}
1373
+._glyphicon-minus:before {
1374
+   content: "\2212";
1375
+}
1376
+._glyphicon-alert:before {
1377
+   content: "\e209";
1378
+}
1379
+._glyphicon-tag:before {
1380
+   content: "\e041";
1381
+}
1382
+._glyphicon-remove:before {
1383
+   content: "\e014";
1384
+}
1385
+._glyphicon-pencil:before {
1386
+   content: "\270f";
1387
+}
1388
+._glyphicon-book:before {
1389
+   content: "\e043";
1390
+}
1391
+._glyphicon-user:before {
1392
+   content: "\e008";
1393
+}
1394
+._glyphicon-log-out:before {
1395
+   content: "\e163";
1396
+}
1397
+._glyphicon-object-align-vertical:before {
1398
+   content: "\e248";
1399
+}
1400
+._glyphicon-bullhorn:before {
1401
+   content: "\e122";
1402
+}
1403
+._glyphicon-list:before {
1404
+   content: "\e056";
1405
+}
1406
+._glyphicon-ok:before {
1407
+   content: "\e013";
1408
+}
1409
+._glyphicon-edit:before {
1410
+   content: "\e065";
1411
+}
1412
+._glyphicon-eye-open:before {
1413
+   content: "\e105";
1414
+}
1415
+._glyphicon-eye-close:before {
1416
+   content: "\e106";
1417
+}
1418
+
1419
+
1420
+
1421
+._nav {
1422
+   padding-left: 0;
1423
+   margin-bottom: 0;
1424
+   list-style: none;
1425
+}
1426
+._nav-pills>li {
1427
+   float: left;
1428
+}
1429
+._nav-stacked>li {
1430
+   float: none;
1431
+}
1432
+._nav>li {
1433
+   position: relative;
1434
+   display: block;
1435
+}
1436
+._nav>li>a {
1437
+   position: relative;
1438
+   display: block;
1439
+   padding: 10px 15px;
1440
+}
1441
+
1442
+
1443
+
1444
+._panel-heading {
1445
+   border-bottom: 1px solid transparent;
1446
+   border-top-left-radius: 3px;
1447
+   border-top-right-radius: 3px;
1448
+}
1449
+
1450
+._panel-primary>._panel-heading {
1451
+   color: #fff;
1452
+   background-color: #337ab7;
1453
+   border-color: #337ab7;
1454
+}
1455
+
1456
+._panel-primary .panel-title, .panel-success .panel-title, .panel-warning .panel-title, .panel-danger .panel-title, .panel-info .panel-title, .panel-dark .panel-title {
1457
+   color: #fff;
1458
+}
1459
+
1460
+._form-group {
1461
+   margin-bottom: 15px;
1462
+}
1463
+
1464
+a {
1465
+   color: #337ab7;
1466
+   text-decoration: none;
1467
+}
1468
+
1469
+._btn-info {
1470
+   color: #fff;
1471
+   background-color: #5bc0de;
1472
+   border-color: #46b8da;
1473
+}
1474
+
1475
+._btn-warning {
1476
+   color: #fff;
1477
+   background-color: #f0ad4e;
1478
+   border-color: #eea236;
1479
+}
1480
+
1481
+._fz-12 {
1482
+   font-size: 12px;
1483
+}

public/assets/css/bootstrap.min.css → public/assets/css/bootstrap.min.v3.css View File


+ 7
- 0
public/assets/css/bootstrap.min.v5.css
File diff suppressed because it is too large
View File


+ 4614
- 0
public/assets/css/style.default.v3.css
File diff suppressed because it is too large
View File


+ 4614
- 0
public/assets/css/style.default.v5.css
File diff suppressed because it is too large
View File


+ 7
- 0
public/assets/js/bootstrap.bundle.min.v5.js
File diff suppressed because it is too large
View File


+ 4412
- 1713
public/assets/js/bootstrap.js
File diff suppressed because it is too large
View File


public/assets/js/bootstrap.min.js → public/assets/js/bootstrap.min.v3.js View File


+ 7
- 0
public/assets/js/bootstrap.min.v5.js
File diff suppressed because it is too large
View File


+ 5016
- 0
public/assets/js/bootstrapV3.js
File diff suppressed because it is too large
View File


+ 5
- 1
resources/views/admin/uc/foot.blade.php View File

1
-<script src="{{url('assets/js/bootstrap.min.js')}}"></script>
1
++@if (request('v') == 3)
2
++    <script src="{{url('assets/js/bootstrap.min.v3.js')}}"></script>
3
++@else
4
++    <script src="{{url('assets/js/bootstrap.bundle.min.v5.js')}}"></script>
5
++@endif
2
 <script src="{{url('assets/js/modernizr.min.js')}}"></script>
6
 <script src="{{url('assets/js/modernizr.min.js')}}"></script>
3
 <script src="{{url('assets/js/jquery.sparkline.min.js')}}"></script>
7
 <script src="{{url('assets/js/jquery.sparkline.min.js')}}"></script>
4
 <script src="{{url('assets/js/toggles.min.js')}}"></script>
8
 <script src="{{url('assets/js/toggles.min.js')}}"></script>

+ 3
- 1
resources/views/admin/uc/head.blade.php View File

3
 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
3
 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
4
 <link rel="shortcut icon" href="{{url('assets/images/favicon.png')}}" type="image/png" />
4
 <link rel="shortcut icon" href="{{url('assets/images/favicon.png')}}" type="image/png" />
5
 <title>{{ env('APP_NAME') }}</title>
5
 <title>{{ env('APP_NAME') }}</title>
6
-<link rel="Stylesheet" type="text/css" href="{{url('assets/css/style.default.css')}}"/>
6
+
7
+<link rel="Stylesheet" type="text/css" href="{{ asset('assets/css/style.default.v5.css') }}"/>  
8
+
7
 <!--<link rel="Stylesheet" type="text/css" href="{{url('assets/css/style.darkknight.css')}}"/>-->
9
 <!--<link rel="Stylesheet" type="text/css" href="{{url('assets/css/style.darkknight.css')}}"/>-->
8
 <script src="{{url('assets/js/jquery-1.11.1.min.js')}}"></script>
10
 <script src="{{url('assets/js/jquery-1.11.1.min.js')}}"></script>
9
 <script src="{{url('assets/js/jquery-migrate-1.2.1.min.js')}}"></script>
11
 <script src="{{url('assets/js/jquery-migrate-1.2.1.min.js')}}"></script>

+ 6
- 6
resources/views/admin/uc/leftmenu.blade.php View File

14
 				</div>
14
 				</div>
15
 			</div>
15
 			</div>
16
 		</div>
16
 		</div>
17
-        <h5 class="sidebartitle">Navigation</h5>
18
-		<ul id="navLeftMenu" class="nav nav-pills nav-stacked nav-bracket">
17
+        <h5 class="sidebartitle mt-2">Navigation</h5>
18
+		<ul id="navLeftMenu" class="_nav _nav-pills _nav-stacked nav-bracket">
19
 			<!-- 選單區段 -->
19
 			<!-- 選單區段 -->
20
-			<li class='nav-link' id="Dashboard"><a href='{{ url('backend/') }}' class="dashboard"><i class='fa fa-dashboard'></i><span>DashBoard</span></a></li>
20
+			<li class='' id="Dashboard"><a href='{{ url('backend/') }}' class="dashboard text-decoration-none"><i class='fa fa-dashboard'></i><span>Dashboard</span></a></li>
21
             @foreach($leftmenu as $data)
21
             @foreach($leftmenu as $data)
22
-                <li class='nav-parent'><a href='' class='parent-name'><i class='{{ $data->icon }}'></i><span>{{ $data->menuname }}</span></a><ul class='children'>
22
+                <li class='nav-parent'><a href='' class='parent-name text-decoration-none'><i class='{{ $data->icon }}'></i><span>{{ $data->menuname }}</span></a><ul class='children'>
23
                 @for($i = 0; $i< count(explode(",",$data->submenuname)); $i++)
23
                 @for($i = 0; $i< count(explode(",",$data->submenuname)); $i++)
24
                     <li id='{{ str_replace("/", "_", explode(",",$data->submenulink)[$i]) }}' data-level='two'>
24
                     <li id='{{ str_replace("/", "_", explode(",",$data->submenulink)[$i]) }}' data-level='two'>
25
-                        <a href='{{ url('backend/'.explode(",",$data->submenulink)[$i]) }}'>
25
+                        <a class="text-decoration-none" href='{{ url('backend/'.explode(",",$data->submenulink)[$i]) }}'>
26
                             <i class='fa fa-caret-right'></i>
26
                             <i class='fa fa-caret-right'></i>
27
                             <span>{{ explode(",",$data->submenuname)[$i] }}</span>
27
                             <span>{{ explode(",",$data->submenuname)[$i] }}</span>
28
                         </a>
28
                         </a>
33
 		</ul>
33
 		</ul>
34
 	</div>
34
 	</div>
35
 	<!-- leftpanelinner -->
35
 	<!-- leftpanelinner -->
36
-</div>
36
+</div>

+ 15
- 3
resources/views/auth/login.blade.php View File

4
 		@include('admin.uc.head')
4
 		@include('admin.uc.head')
5
 	</head>
5
 	</head>
6
 	<body class="signin">
6
 	<body class="signin">
7
+	@if ($errors->any())
8
+		<div class="alert alert-danger">
9
+			<ul>
10
+				@foreach ($errors->all() as $error)
11
+					<li>{{ $error }}</li>
12
+				@endforeach
13
+			</ul>
14
+		</div>
15
+	@endif
16
+
7
 		<section>
17
 		<section>
8
 			<div class="signinpanel">
18
 			<div class="signinpanel">
9
 				<div class="row">
19
 				<div class="row">
17
 							<label class="error" for="email"></label>
27
 							<label class="error" for="email"></label>
18
 							<input id="qpassword" name="password" placeholder="Password" class="form-control pword" maxlength="20" type="password" />
28
 							<input id="qpassword" name="password" placeholder="Password" class="form-control pword" maxlength="20" type="password" />
19
 							<label class="error" for="password"></label>
29
 							<label class="error" for="password"></label>
30
+							<br>
31
+							<div>
32
+								<div id="recaptcha" class="g-recaptcha" data-sitekey="6LfvggUgAAAAALUwCxdJd372UNW3xrMrVfgNJEOF"></div>
33
+							</div>
20
 							<input id="btnSignIn" name="btnSignIn" value="Login" class="btn btn-block btn-success" type="submit" onclick="submitForm();" />
34
 							<input id="btnSignIn" name="btnSignIn" value="Login" class="btn btn-block btn-success" type="submit" onclick="submitForm();" />
21
 						</form>
35
 						</form>
22
 					</div>
36
 					</div>
23
 					<div class="col-md-3"></div>
37
 					<div class="col-md-3"></div>
24
-					<!-- col-sm-5 -->
25
 				</div>
38
 				</div>
26
-				<!-- row -->
27
 				<div class="signup-footer">
39
 				<div class="signup-footer">
28
 					<div class="pull-left">
40
 					<div class="pull-left">
29
 						<?php echo env('COPY_RIGHT')?>
41
 						<?php echo env('COPY_RIGHT')?>
33
 					</div>
45
 					</div>
34
 				</div>
46
 				</div>
35
 			</div>
47
 			</div>
36
-			<!-- signin -->
37
 		</section>
48
 		</section>
38
 		@include('admin.uc.foot')
49
 		@include('admin.uc.foot')
39
 		<!-- 表單JS -->
50
 		<!-- 表單JS -->
51
+		<script src="https://www.google.com/recaptcha/api.js" async defer></script>
40
 		<script>
52
 		<script>
41
 			//逐個偵錯
53
 			//逐個偵錯
42
 			$(function () {
54
 			$(function () {