Các bước áp dụng themes vào Laravel 8.
Trang 1PHẦN 7: XÂY DỰNG GIAO DIỆN FRONT-END
Trong 6 phần trước chúng ta đã tập trung xây dựng cho phần Back-end (Trang dành cho người quản lý)
Nhưng phần thiết lập routes chưa được tối ưu
Hướng đề xuất:
- Trang Back-end (admin) sẽ có đường dẫn là /admin/
http://127.0.0.1/larashop/admin/loaisanpham
http://127.0.0.1/larashop/admin/loaisanpham/them
http://127.0.0.1/larashop/admin/loaisanpham/sua/1
- Trang Front-end sẽ không có /admin/ và địa chỉ thân thiện hơn
http://127.0.0.1/larashop/san-pham
http://127.0.0.1/larashop/san-pham/dien-thoai
http://127.0.0.1/larashop/san-pham/dien-thoai/iphone-12-mini-128gb
http://127.0.0.1/larashop/gio-hang/iphone-12-mini-128gb/them
http://127.0.0.1/larashop/gio-hang
http://127.0.0.1/larashop/gio-hang/cap-nhat
http://127.0.0.1/larashop/dat-hang
http://127.0.0.1/larashop/dat-hang-thanh-cong
Code routes/web.php gợi ý:
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\HomeController;
use App\Http\Controllers\AdminController;
use App\Http\Controllers\LoaiSanPhamController;
use App\Http\Controllers\SanPhamController;
use App\Http\Controllers\DonHangController;
Biên soạn: Nguyễn Hoàng Tùng Giấy phép CC BY-NC 4.0 Quốc tế
Trang 2use App\Http\Controllers\DonHangChiTietController;
use App\Http\Controllers\UserController;
Auth::routes();
// Trang chủ
Route::get('/', [HomeController::class, 'getHome'])->name('frontend');
// Trang sản phẩm
Route::get('/san-pham', [HomeController::class, 'getSanPham'])->name('frontend.sanpham');
Route::get('/san-pham/{tenloai_slug}', [HomeController::class, 'getSanPham'])->name('frontend.sanpham.danhmuc');
Route::get('/san-pham/{tenloai_slug}/{tensanpham_slug}', [HomeController::class, 'getSanPham_ChiTiet'])->name('frontend.sanpham.chitiet');
// Trang giỏ hàng
Route::get('/gio-hang', [HomeController::class, 'getGioHang'])->name('frontend.giohang');
Route::get('/gio-hang/them/{tensanpham_slug}', [HomeController::class, 'getGioHang_Them'])->name('frontend.giohang.them');
Route::get('/gio-hang/xoa', [HomeController::class, 'getGioHang_XoaTatCa'])->name('frontend.giohang.xoatatca');
Route::get('/gio-hang/xoa/{row_id}', [HomeController::class, 'getGioHang_Xoa'])->name('frontend.giohang.xoa');
Route::get('/gio-hang/giam/{row_id}', [HomeController::class, 'getGioHang_Giam'])->name('frontend.giohang.giam');
Route::get('/gio-hang/tang/{row_id}', [HomeController::class, 'getGioHang_Tang'])->name('frontend.giohang.tang');
// Trang đặt hàng
Route::get('/dat-hang', [HomeController::class, 'getDatHang'])->name('frontend.dathang');
Route::post('/dat-hang', [HomeController::class, 'postDatHang'])->name('frontend.dathang');
Route::get('/dat-hang-thanh-cong', [HomeController::class, 'getDatHangThanhCong'])->name('frontend.dathangthanhcong');
// Liên hệ
Route::get('/lien-he', [HomeController::class, 'getLienHe'])->name('frontend.lienhe');
// Trang tài khoản quản lý
Route::prefix('admin')->group(function()
// Trang chủ tài khoản quản lý
Route::get('/', [AdminController::class, 'getAdmin'])->name('admin');
// Quản lý Loại sản phẩm
Route::get('/loaisanpham', [LoaiSanPhamController::class, 'getDanhSach'])->name('loaisanpham');
Route::get('/loaisanpham/them', [LoaiSanPhamController::class, 'getThem'])->name('loaisanpham.them');
Route::post('/loaisanpham/them', [LoaiSanPhamController::class, 'postThem'])->name('loaisanpham.them');
Route::get('/loaisanpham/sua/{id}', [LoaiSanPhamController::class, 'getSua'])->name('loaisanpham.sua');
Route::post('/loaisanpham/sua/{id}', [LoaiSanPhamController::class, 'postSua'])->name('loaisanpham.sua');
Route::get('/loaisanpham/xoa/{id}', [LoaiSanPhamController::class, 'getXoa'])->name('loaisanpham.xoa');
// Quản lý Sản phẩm
Route::get('/sanpham', [SanPhamController::class, 'getDanhSach'])->name('sanpham');
Route::get('/sanpham/them', [SanPhamController::class, 'getThem'])->name('sanpham.them');
Route::post('/sanpham/them', [SanPhamController::class, 'postThem'])->name('sanpham.them');
Route::get('/sanpham/sua/{id}', [SanPhamController::class, 'getSua'])->name('sanpham.sua');
Route::post('/sanpham/sua/{id}', [SanPhamController::class, 'postSua'])->name('sanpham.sua');
Route::get('/sanpham/xoa/{id}', [SanPhamController::class, 'getXoa'])->name('sanpham.xoa');
Route::post('/sanpham/nhap', [SanPhamController::class, 'postNhap'])->name('sanpham.nhap');
Route::get('/sanpham/xuat', [SanPhamController::class, 'getXuat'])->name('sanpham.xuat');
// Quản lý Đơn hàng
Route::get('/donhang', [DonHangController::class, 'getDanhSach'])->name('donhang');
Route::get('/donhang/them', [DonHangController::class, 'getThem'])->name('donhang.them');
Route::post('/donhang/them', [DonHangController::class, 'postThem'])->name('donhang.them');
Trang 3Route::get('/donhang/sua/{id}', [DonHangController::class, 'getSua'])->name('donhang.sua');
Route::post('/donhang/sua/{id}', [DonHangController::class, 'postSua'])->name('donhang.sua');
Route::get('/donhang/xoa/{id}', [DonHangController::class, 'getXoa'])->name('donhang.xoa');
// Quản lý Đơn hàng chi tiết
Route::get('/donhang/chitiet', [DonHangChiTietController::class, 'getDanhSach'])->name('donhang.chitiet');
Route::get('/donhang/chitiet/sua/{id}', [DonHangChiTietController::class, 'getSua'])->name('donhang.chitiet.sua');
Route::post('/donhang/chitiet/sua/{id}', [DonHangChiTietController::class, 'postSua'])->name('donhang.chitiet.sua');
Route::get('/donhang/chitiet/xoa/{id}', [DonHangChiTietController::class, 'getXoa'])->name('donhang.chitiet.xoa');
// Quản lý Tài khoản người dùng
Route::get('/nguoidung', [UserController::class, 'getDanhSach'])->name('nguoidung');
Route::get('/nguoidung/them', [UserController::class, 'getThem'])->name('nguoidung.them');
Route::post('/nguoidung/them', [UserController::class, 'postThem'])->name('nguoidung.them');
Route::get('/nguoidung/sua/{id}', [UserController::class, 'getSua'])->name('nguoidung.sua');
Route::post('/nguoidung/sua/{id}', [UserController::class, 'postSua'])->name('nguoidung.sua');
Route::get('/nguoidung/xoa/{id}', [UserController::class, 'getXoa'])->name('nguoidung.xoa');
});
- Để tăng tính bảo mật, có thể sử dụng thêm middleware vào các routes
- Xem thêm: https://laravel.com/docs/8.x/middleware#assigning-middleware-to-routes
Route::prefix('admin')->middleware('auth')->group(function()
});
RouteServiceProvider quy định các thông số về URL
Chúng ta sẽ chỉnh lại một chút so với bản gốc, thêm hằng số ADMIN và chỉnh lại giá trị hằng số HOME
public const HOME = '/';
public const ADMIN = '/admin';
Tập tin này quy định: “Khi nhấn vào link Đăng nhập/Đăng ký, nếu người dùng đã đăng nhập thành công trước đó thì chuyển tới trang nào?”
public function handle(Request $request, Closure $next, $guards)
{
$guards empty($guards) ? [null] : $guards;
foreach $guards as $guard) {
if Auth::guard($guard)->check())
return redirect(RouteServiceProvider::HOME);
}
}
Trang 4return $next($request);
}
Tập tin HomeController mặc định được tạo ra và cần thiết lập không đăng nhập vẫn truy xuất được
<?php
namespace App\Http\Controllers;
use App\Models\NguoiDung;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
class HomeController extends Controller
{
public function getHome()
{
return view('frontend.index');
}
public function getSanPham($tenloai_slug '')
{
return view('frontend.sanpham');
}
public function getSanPham_ChiTiet($tenloai_slug, $tensanpham_slug)
{
return view('frontend.sanpham_chitiet');
}
public function getLienHe()
{
return view('frontend.lienhe');
}
public function getGioHang()
{
return view('frontend.giohang');
}
public function getGioHang_Them($tensanpham_slug)
{
return redirect()->route('frontend');
}
Trang 5
public function getGioHang_Xoa($row_id)
{
return redirect()->route('frontend.giohang');
}
public function getGioHang_XoaTatCa()
{
return redirect()->route('frontend.giohang');
}
public function getGioHang_Giam($row_id)
{
return redirect()->route('frontend.giohang');
}
public function getGioHang_Tang($row_id)
{
return redirect()->route('frontend.giohang');
}
public function getDatHang()
{
return view('frontend.dathang');
}
public function postDatHang(Request $request)
{
return redirect()->route('frontend.dathangthanhcong');
}
public function getDatHangThanhCong()
{
return view('frontend.dathangthanhcong');
}
}
Nội dung bên trong các hàm rỗng sẽ cập nhật ở Lab sau
Tập tin AdminController.php có thể tạo thủ công bằng copy/paste hoặc dùng lệnh artisan:
php artisan make:controller AdminController
Nội dung tập tin AdminController.php:
<?php
Trang 6namespace App\Http\Controllers;
use Illuminate\Http\Request;
class AdminController extends Controller
{
public function construct()
{
$this->middleware('auth');
}
public function getAdmin()
{
return view('admin');
}
}
Tập tin này phải đăng nhập mới truy xuất được, để tạo phân quyền cụ thể hơn, hãy tìm hiểu thêm về middleware
Trong thư mục views:
- Đổi tên tập tin home.blade.php thành admin.blade.php
- Tạo thư mục rỗng frontend chứa các views của giao diện Front-end
Trang 7Theo như code của HomeController, trong thư mục frontend sẽ có các tập tin như hình bên dưới, hiện tại code bên trong các tập tin này chưa có
Để tiện cho việc demo, tạm thời code của tập tin frontend/index.blade.php có nội dung như sau:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>{{ config('app.name', 'Laravel') }}</title>
</head>
<body>
<h3>Trang chủ {{ config('app.name', 'Laravel') }} đang cập nhật!</h3>
</body>
</html>
Khi đó, giao diện khi chạy từ trang chủ:
Trang 8Để vào trang Back-end, chỉ cần truy cập http://127.0.0.1/larashop/admin , màn hình đăng nhập sẽ được gọi:
Sau khi đăng nhập, địa chỉ các trang trong Back-end đều bắt đầu bằng /admin/
Trang 9Lab 7: Áp d ụng giao diện bán hàng cho Front-end
Có rất nhiều themes thương mại điện tử (ecommerce, shopping, store,…) trên mạng, các bạn có thể tải chúng về và áp dụng vào trang web của mình
Ví dụ này sẽ sử dụng một theme như vậy, sau đây là thông tin về theme:
Tên: Shopwise - eCommerce Bootstrap 4 HTML Template
Tác giả: Bestwebcreator
Liên kết: https://bestwebcreator.com/shopwise
Mô tả:
- Cấu trúc theme Shopwise:
Trang 10- Sử dụng Bootstrap v4.3.1 (2019), Font Awesome Pro 5.12.0, Owl Carousel v2.2.0,…
Bước 1: Giải nén và copy theme vào đúng vị trí
Copy toàn bộ thư mục assets vào thư mục larashop/public:
Bước 2: Tạo view master cho Front-end
Xác định được cái gì chung thì đưa vào master (header, footer,…)
Nếu master có nội dung dài quá thì chia nhỏ ra rồi dùng chức năng @include để nhúng vào
Trang chủ Shopwise (tập tin index.html có sẵn) có giao diện như sau:
Trang 12Bố cục code của trang chủ (collapse):
<!DOCTYPE html>
<html lang="en">
<! Phần head dùng chung - Đưa vào master >
<head>
<body>
<! Hiệu ứng tải trang - Đưa vào master >
<div class="preloader">
<! Phần header chứa logo và menu chính - Đưa vào master >
<header class="header_wrap fixed-top header_with_topbar">
<! Phần tiêu đề và đường dẫn riêng của từng trang - Không đưa vào master >
<div class="breadcrumb_section bg_gray page-title-mini">
<! Nội dung riêng của từng trang - Không đưa vào master >
<div class="main_content">
<! Phần footer dùng chung - Đưa vào master >
<footer class="footer_dark">
<! Nút quay về đầu trang - Đưa vào master >
<a href="#" class="scrollup" style="display:none;"><i class="ion-ios-arrow-up"></i></a>
<! Phần javascript dùng chung - Đưa vào master >
<script src="assets/js/jquery-1.12.4.min.js"></script>
<script src="assets/js/jquery-ui.js"></script>
<script src="assets/js/popper.min.js"></script>
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
<script src="assets/owlcarousel/js/owl.carousel.min.js"></script>
<script src="assets/js/magnific-popup.min.js"></script>
<script src="assets/js/waypoints.min.js"></script>
<script src="assets/js/parallax.js"></script>
<script src="assets/js/jquery.countdown.min.js"></script>
<script src="assets/js/hoverparallax.min.js"></script>
<script src="assets/js/jquery.countTo.js"></script>
<script src="assets/js/imagesloaded.pkgd.min.js"></script>
<script src="assets/js/isotope.min.js"></script>
<script src="assets/js/jquery.appear.js"></script>
<script src="assets/js/jquery.parallax-scroll.js"></script>
<script src="assets/js/jquery.dd.min.js"></script>
<script src="assets/js/slick.min.js"></script>
<script src="assets/js/jquery.elevatezoom.js"></script>
<script src="assets/js/scripts.js"></script>
</body>
</html>
Tạo master view với tên frontend.blade.php vào thư mục views/layouts
Trang 13Code trang master gợi ý (collapse):
<!DOCTYPE html>
<html lang="en">
<! Phần head dùng chung >
<head>
<body>
<! Hiệu ứng tải trang >
<div class="preloader">
<! Phần header chứa logo và menu chính >
<header class="header_wrap fixed-top header_with_topbar">
@yield('content')
<! Phần footer dùng chung >
<footer class="footer_dark">
<! Nút quay về đầu trang >
<a href="#" class="scrollup" style="display:none;"><i class="ion-ios-arrow-up"></i></a>
<! Phần javascript dùng chung >
<script src="assets/js/jquery-1.12.4.min.js"></script>
<script src="assets/js/jquery-ui.js"></script>
<script src="assets/js/popper.min.js"></script>
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
<script src="assets/owlcarousel/js/owl.carousel.min.js"></script>
<script src="assets/js/magnific-popup.min.js"></script>
<script src="assets/js/waypoints.min.js"></script>
<script src="assets/js/parallax.js"></script>
<script src="assets/js/jquery.countdown.min.js"></script>
<script src="assets/js/hoverparallax.min.js"></script>
<script src="assets/js/jquery.countTo.js"></script>
<script src="assets/js/imagesloaded.pkgd.min.js"></script>
<script src="assets/js/isotope.min.js"></script>
<script src="assets/js/jquery.appear.js"></script>
<script src="assets/js/jquery.parallax-scroll.js"></script>
<script src="assets/js/jquery.dd.min.js"></script>
<script src="assets/js/slick.min.js"></script>
<script src="assets/js/jquery.elevatezoom.js"></script>
<script src="assets/js/scripts.js"></script>
</body>
</html>
Chỉnh sửa các liên kết trong phần thẻ <head> cho phù hợp:
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>