TRƯỜNG ĐẠI HỌC THUỶ LỢI KHOA CÔNG NGHỆ THÔNG TIN BẢN MÔ TẢ QUÁ TRÌNH THỰC HIỆN ĐỒ ÁN Tên đề tài: Xây dựng website quản lý nhà ăn trường Đại học Thủy Lợi Job 4: Code chức năng Quản lý loạ
Trang 1TRƯỜNG ĐẠI HỌC THUỶ LỢI
KHOA CÔNG NGHỆ THÔNG TIN
BẢN MÔ TẢ QUÁ TRÌNH THỰC HIỆN ĐỒ ÁN
Tên đề tài: Xây dựng website quản lý nhà ăn trường Đại học Thủy Lợi
Job 4: Code chức năng Quản lý loại món ăn và Quản lý món ăn
Sinh viên thực hiện: Bùi Quang Huy
Figma là một phần mềm biên tập đồ họa vector và dựng prototype, gồm nhiều công cụ thiết
kế mạnh mẽ, hoạt động trên nền tảng website Figma có tất cả các công cụ hỗ trợ và tính năng mạnh mẽ giúp designer có thể thiết kế và quản lý các dự án một cách hiệu quả Vì thế Figma là công cụ rất thích hợp trong việc thiết kế, người dùng có thể biến ý tưởng của mình về bố cục các thành phần, màu sắc, font chữ, cỡ chữ, hình ảnh, hiệu ứng,… của website thành một bản thiết kế
cụ thể, từ đó hỗ trợ trong việc làm Front-end một cách dễ dàng.
Trang 22 Laravel
Laravel là một framework phát triển ứng dụng web mã nguồn mở được viết bằng PHP Nó được tạo ra bởi Taylor Otwell và được phát hành lần đầu vào năm 2011 Laravel là một trong những framework phát triển web phổ biến nhất hiện nay, được sử dụng rộng rãi cho việc xây dựng các ứng dụng web hiện đại và mạnh mẽ Tuân thủ theo mô hình MVC, cú pháp rõ ràng và
dễ hiểu, hệ thống routing linh hoạt, ORM tích hợp sẵn, dễ dàng kiểm thử,… là những tính năng của Laravel khiến nó trở thành công cụ rất thích hợp trong việc làm Back-end.
3 Bootstrap – SCSS
Bootstrap là một framework CSS phổ biến được sử dụng để phát triển giao diện người dùng cho các ứng dụng web và di động Bootstrap cung cấp các tập hợp các lớp CSS, JavaScript, và các mẫu HTML mà bạn có thể sử dụng để xây dựng các thành phần giao diện như button, form, navigation bar, grid system và nhiều hơn nữa một cách dễ dàng và nhanh chóng
SCSS (Sassy CSS) là một loại cú pháp mở rộng cho CSS, cho phép bạn sử dụng các tính năng như biến, nesting, mixins, và các module, giúp làm cho mã CSS của bạn dễ đọc hơn và quản lý dễ dàng hơn SCSS được Bootstrap sử dụng để viết mã CSS của nó.
Việc sử dụng SCSS thay vì CSS giúp cho người dùng linh hoạt hơn trong việc sử dụng Bootstrap Bootstrap đã được xây dựng sẵn các một số thuộc tính (VD: màu $primary của Bootstrap được xây dựng mặc định là $blue), và vì đã được xây dựng thuộc tính mặc định, người dùng rất khó có thể thay đổi các thuộc tính này SCSS cho phép người dùng truy cập vào các biến của Bootstrap để thay đổi những thuộc tính mặc định khi cần thiết, như là thay đổi màu
$primary của Bootstrap thành $red hay tất cả những thuộc tính khác liên quan đến màu sắc, size, font-weight, margin, border, padding… Vì thế, SCSS là công cụ hoàn hảo giúp người dùng
font-sử dụng Bootstrap một cách dễ dàng hơn.
Trang 3II Quá trình thực hiện
1 Thiết kế CSDL cho chức năng Quản lý loại món ăn, Quản
lý món ăn, Quản lý nguyên liệu (23/4)
- Dùng câu lệnh
“php artisan make:model DishType –m”
“php artisan make:model Ingredient –m”
“php artisan make:model Dish –m”
“php artisan make:model Menu –m”
“php artisan make:model DishIngredient –m”
“php artisan make:model MenuDish –m”
12 tập tin mới được tạo ra trong dự án Laravel bao gồm:
Trang 4database/migrations/ 2024_04_23_135234_create_dish_types_table.php; database/migrations/ 2024_04_23_135222_create_ingredients_table.php; database/migrations/ 2024_04_23_135244_create_dishes_table.php;
database/migrations/ 2024_05_01_200240_create_menus_table.php;
database/migrations/ 2024_05_01_094224_create_dish_ingredients_table.php; database/migrations/ 2024_05_01_200720_create_menu_dishes_table.php;
- Cấu hình các tệp tin:
Dish.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Dish extends Model
public $timestamps = true;
public function dish_type()
Trang 5{
return $this->belongsToMany(Ingredient::class,
'dish_ingredients', 'Dish_ID', 'Ingredient_ID')->withPivot('Amount'); }
}
Ingredient.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Ingredient extends Model
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Menu extends Model
{
use HasFactory;
protected $fillable = ['Date', 'NumberOfTotalPortions'];
public function dishes()
{
Trang 6return $this->belongsToMany(Dish::class, 'menu_dishes',
'Menu_ID', 'Dish_ID')->withPivot('NumberOfPortions');
$table->string('IngredientName',50);
$table->integer('Price');
$table->unsignedBigInteger('Unit_ID');
$table->foreign('Unit_ID')->references('id')->on('units'
$table->string('DishName',50)->unique();
$table->unsignedBigInteger('DishType_ID');
$table->foreign('DishType_ID')->references('id'
)->on('dish_types')->onDelete('cascade');
$table->timestamps();
Trang 7$table->unsignedBigInteger('Dish_ID');
$table->foreign('Dish_ID')->references('id')->on('dishes'
)->onDelete('cascade');
$table->unsignedBigInteger('Ingredient_ID');
$table->foreign('Ingredient_ID')->references('id'
)->on('ingredients')->onDelete('cascade');
$table->decimal('Amount', , )->nullable();
$table->date('Date');
$table->integer('NumberOfTotalPortions')->nullable();
Trang 8$table->foreign('Menu_ID')->references('id')->on('menus'
)->onDelete('cascade');
$table->unsignedBigInteger('Dish_ID');
$table->foreign('Dish_ID')->references('id')->on('dishes'
- Chạy lệnh “php artisan migrate” để chạy các migrations, cập nhật các bảng vào CSDL.
- Thêm dữ liệu vào bảng:
‘ingredients’:
‘dish_types’:
Trang 9‘dish_ingredients’:
‘menu_dishes’:
Trang 102 Code Back-end cho chức năng Quản lý loại món ăn, Quản
lý món ăn, Quản lý nguyên liệu (23/4-25/4)
- Tạo Controller: Chạy lệnh
“php artisan make:controller IngredientController resource”,
“php artisan make:controller DishTypeController resource”,
“php artisan make:controller DishController resource”,
“php artisan make:controller MenuController resource”
- Sau đó tệp tin app/Http/Controllers/ IngredientController.php, app/Http/Controllers/ DishTypeController.php, app/Http/Controllers/ DishController.php,
app/Http/Controllers/ MenuController.php với các phương thức liên quan đến CRUD
được tạo.
- Cấu hình tệp tin IngredientController.php:
<?php
Trang 11namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Ingredient;
use App\Models\Unit;
class IngredientController extends Controller
$ingredients = Ingredient::all();
return view('menu.ingredients.index', compact('ingredients')); }
$units = Unit::all();
return view('menu.ingredients.create',compact('units'));
$ingredient = new Ingredient;
$ingredient->IngredientName = $request->IngredientName;
$ingredient->Price = $request->Price;
$ingredient->Unit_ID = $request->Unit_ID;
$ingredient->save();
Trang 12
$ingredient = Ingredient::find($id);
$units = Unit::all();
Trang 13use Illuminate\Http\Request;
use App\Models\DishType;
class DishTypeController extends Controller
$dishtypes = DishType::all();
return view('menu.dishtypes.index', compact('dishtypes')); }
Trang 14return view('menu.dishtypes.create');
$dishtype = new DishType;
$dishtype->DishTypeName = $request->DishTypeName;
$dishtype = DishType::find($id);
return view('menu.dishtypes.edit',compact('dishtype')); }
/**
* Update the specified resource in storage
*/
Trang 15public function update(Request $request, string $id)
use Illuminate\Http\Request;
use App\Models\Dish;
use App\Models\DishType;
use App\Models\Ingredient;
class DishController extends Controller
{
/**
* Display a listing of the resource
*/
Trang 16public function index()
{
$dishes = Dish::with('ingredients')->get();
$dishtypes = DishType::all();
$query = Dish::query();
$dishtypes = DishType::all();
$dishes = $query->with('ingredients'
)->with(['dish_type'])->get();
Trang 17$ingredients = Ingredient::all();
return view('menu.dishes.create',
compact('dishtypes','ingredients'));
}
public function create()
{
$dishtypes = DishType::all();
$ingredients = Ingredient::all();
$dish = Dish::create([
'DishName' => $request->input('DishName'),
'DishType_ID' => $request->input('dishtype')
]);
$ingredients = $request->input('ingredient');
$amounts = $request->input('amount');
// Lặp qua mỗGi nguyên liệu và thêm vào món ăn với sỗN lượng tương ứng
foreach ($ingredients as $key => $ingredientId) {
$amount = $amounts[$key];
$dish->ingredients()->attach($ingredientId, ['amount' =>
$amount]);
}
return redirect()->route('dishes.index');
}
Trang 18$dishtypes = DishType::all();
$dish = Dish::where('id', '=', $id)->select('*')->first();
$ingredients = Ingredient::all();
return view('menu.dishes.show',compact('dish',
$dish = Dish::find($id);
$dishtypes = DishType::all();
$ingredients = Ingredient::all();
Trang 19$dish->update([
'DishName' => $request->input('DishName'),
'DishType_ID' => $request->input('DishType_ID'),
$amount = $request->input('amount')[$key];
$ingredientData[$ingredientID] = ['Amount' => $amount]; }
$dish->ingredients()->sync($ingredientData);
$dish = Dish::findOrFail($id);
$dish->ingredients()->detach();
Trang 20namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use App\Models\Menu;
use App\Models\Dish;
use App\Models\Ingredient;
class MenuController extends Controller
$menus = Menu::with('dishes')->get();
$dates = Menu::distinct()->pluck('Date');
return view('menu.menus.index',compact('menus','dates'));
}
public function filterMenu(Request $request)
{
$query = Menu::query();
$dates = Menu::select('Date')->distinct()->pluck('Date');
if ($request->ajax()) {
if (!empty($request->date)){
$menus = $query->with('dishes')->where('Date', $request
$menus = $query->get();
return view('menu.menus.index', compact('menus', 'dates'));
Trang 21$dishes = Dish::with('ingredients')->get();
$menus = Menu::all();
$ingredients = Ingredient::all();
$dishIngredients = DB::table('dish_ingredients'
)->select('Dish_ID', 'Ingredient_ID', 'Amount')->get();
$dishes = Dish::with('ingredients')->get();
$menus = Menu::all();
$ingredients = Ingredient::all();
$dishIngredients = DB::table('dish_ingredients'
)->select('Dish_ID', 'Ingredient_ID', 'Amount')->get();
Trang 22'NumberOfTotalPortions' => 'required|integer|min:1', ]);
$menu = new Menu();
$menu->Date = $request->input('Date');
$menu->NumberOfTotalPortions = $request
->input('NumberOfTotalPortions');
$menu->save();
$dishesData = $request->input('dishes');
foreach ($dishesData as $dishData) {
$dishId = $dishData['id'];
$numberOfPortions = $dishData['numberOfPortions'];
// Lưu thỗng tin món ăn vào baVng trung gian
$menu->dishes()->attach($dishId, ['NumberOfPortions' =>
Trang 23$menu = Menu::find($id);
$dishes = Dish::with('ingredients')->get();
$ingredients = Ingredient::all();
$dishIngredients = DB::table('dish_ingredients'
)->select('Dish_ID', 'Ingredient_ID', 'Amount')->get();
$dish = Dish::findOrFail($dishId);
$ingredients = $dish->ingredients()->select('IngredientName',
$menu = Menu::findOrFail($id);
$menu->fill($request->only(['Date', 'NumberOfTotalPortions'])); $menu->save();
// Lưu giá trị Amount tương ứng vào baVng trung gian
dish_ingredients
if ($request->has('dishes')) {
$dishData = [];
foreach ($request->input('dishes') as $key => $dish) {
$dishID = $dish['id'];
$numberOfPortions = $dish['numberOfPortions'];
$dishData[$dishID] = ['NumberOfPortions' =>
$numberOfPortions];
}
Trang 24$menu->dishes()->sync($dishData); } else {
$menu->dishes()->detach();
$menu = Menu::findOrFail($id);
$menu->dishes()->detach();
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\EmployeeController;
use App\Http\Controllers\FoodTypeController;
use App\Http\Controllers\ImportedFoodController;
use App\Http\Controllers\IngredientController;
use App\Http\Controllers\DishController;
use App\Http\Controllers\DishTypeController;
use App\Http\Controllers\MenuController;
use App\Http\Controllers\RevenueController;
Route::get('/', function () {
return view('home');
Trang 25Route::resource('employees',EmployeeController::class);
Route::resource('foodtypes',FoodTypeController::class);
Route::resource('importedfood',ImportedFoodController::class);
Route::get('/filter-imported-food', [ImportedFoodController::class,
'filterImportedFood'])->name('filter.imported_food');
Route::get('importedfood/create/{foodtype}/{date}',
[ImportedFoodController::class, 'create'])->name('importedfood.create');
Route::get('importedfood/create', [ImportedFoodController::class,
'createWithoutParams'])->name('importedfood.createWithoutParams');
Route::resource('ingredients',IngredientController::class);
Route::resource('dishtypes',DishTypeController::class);
Route::resource('dishes',DishController::class);
Route::get('/filter-dishes', [DishController::class, 'filterDish'
])->name('filter.dishes');
Route::get('dishes/create', [DishController::class,
'createWithoutParams'])->name('dishes.createWithoutParams');
Route::get('dishes/create/{dishtype}', [DishController::class,
'create'])->name('dishes.create');
Route::resource('menus',MenuController::class);
Route::get('/filter-menus', [MenuController::class, 'filterMenu'
])->name('filter.menus');
Route::get('menus/create', [MenuController::class,
'createWithoutParams'])->name('menus.createWithoutParams');
Route::get('menus/create/{date}', [MenuController::class, 'create'
])->name('menus.create');
Route::resource('revenues',RevenueController::class);
Route::get('/filter-revenues', [RevenueController::class,
'filterRevenue'])->name('filter.revenues');
Trang 26- Tạo ra thêm những tệp tin sau:
resources/views/menu/ingredients/index.blade.php: Giao diện trang quản lý nguyên liệu
@extends('base')
@section('title','Danh sách nguyên liệu')
@section('main')
<section class="slide-section pt-3">
<div class="container text-center">
<ul class="nav nav-tabs justify-content-center">
<a class="nav-link active" href="{{
route('ingredients.index') }}">QuaVn lý nguyên liệu</a
</li>
</ul>
</div>
<div class="text-center pb-2 pt-2">
<h2>Danh sách nguyên liệu</h2>
</div>
<div class="container">
<table class="table table-striped m-2" style="border: 2px solid; border-radius: 10px">
<thead>
Trang 27<tr>
<th scope="col">STT</th>
<th scope="col">Tên nguyên liệu</th>
<th scope="col">Đơn giá</th>
<th scope="col">Đơn vị tính</th>
< href="{{ route('ingredients.show',
$ingredient->id) }}"><img
src="{{
URL('images/ShowIcon.svg') }}" alt="Show Icon"></a>
< href="{{ route('ingredients.edit',
$ingredient->id) }}"><img
<div class="modal-dialog">
Trang 28<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="exampleModalLabel">Xóa thỗng tin nguyên liệu
<div class="modal-body">
Bạn có chăNc chăNn muỗNn xóanguyên liệu này khỗng?
</div>
<div class="modal-footer">
<button type="button"class="btn btn-secondary"
data-bs-dismiss="modal">HuVy</button>
<form method="POST"
Trang 29</tbody>
</table>
</div>
<div class="container text-center pt-2 pb-2">
<a href= {{route('ingredients.create')}}" class="btn warning">Thêm mới nguyên liệu</a>
<section class="slide-section">
<div class="container border rounded border-secondary">
<div class="container text-center pt-2">
<h2>Thêm mới nguyên liệu</h2>
</div>
<div class="container">
<form class="" method="POST" action="{{
<label for="formGroupExampleInput"
class="form-label">STT</label>
<input type="text" readonly class=control" id="formGroupExampleInput"
name="id" value="" placeholder="STT tự động tăng (khỗng cầln nhập)">
</div>
<div class="mb-3">
Trang 30<label for="formGroupExampleInput2"
class="form-label">Tên nguyên liệu</label>
<input type="text" class="form-control"
id="formGroupExampleInput2" name="IngredientName"
value="" placeholder="Nhập tên nguyên liệu">
</div>
<div class="mb-3">
<label for="formGroupExampleInput2"
class="form-label">Đơn giá</label>
<input type="text" class="form-control"
id="formGroupExampleInput2" name="Price"
value="" placeholder="Nhập đơn giá">
@foreach ($units as $unit)
<option value="{{ $unit->id }}" unit-id= {{ $unit->id }}">{{ $unit->UnitName }}</option>
<div class="text-center pb-2 mx-2">
<button type="button" onclick="goBack()"class="btn btn-warning">Quay lại</button>
</div>
<div class="text-center pb-2 mx-2">
<button type=submit class="btn
btn-warning">Thêm mới</button>
Trang 31var select = document.getElementById("unit");
var UnitIdInput = document.getElementById("unit_id");
var selectedOption = select.options[select.selectedIndex]; var unitID = selectedOption.getAttribute("data-unit-id"); UnitIdInput.value = unitID;
<section class="slide-section">
<div class="container border rounded border-secondary">
<div class="container text-center pt-2">
<h2>Chi tiêNt thỗng tin nguyên liệu</h2>
</div>
<div class="container">
<div class="row justify-content-center mx-auto"
style="width:80%">
Trang 32<div class="text-center pb-2">
<a href= {{ route('ingredients.index') }}" class="btnbtn-warning"> Quay lại</a
Trang 33resources/views/menu/ingredients/edit.blade.php: Giao diện trang chỉnh sửa nguyên liệu
@extends('base')
@section('title','ChỉVnh sưVa thỗng tin nguyên liệu ')
@section('main')
<section class="slide-section">
<div class="container border rounded border-secondary">
<div class="container text-center pt-2">
<h2>ChỉVnh sưVa thỗng tin nguyên liệu</h2>
<input type="text" readonly class="form-control"
id="formGroupExampleInput" name="id"
value="{{ $ingredient->id }}" title="Khỗng thêV chỉVnh sưVa STT">
</div>
<div class="mb-3">
<label for="formGroupExampleInput2" class=label">Tên nguyên liệu</label>
<input type="text" class="form-control"
id="formGroupExampleInput2" name="IngredientName"
value="{{ $ingredient->IngredientName }}"placeholder="Nhập tên nguyên liệu">
</div>
<div class="mb-3">
<label for="formGroupExampleInput2" class=label">Đơn giá</label>
<input type="text" class="form-control"
id="formGroupExampleInput2" name="Price"
Trang 34value="{{ $ingredient->Price }}"
placeholder="Nhập đơn giá">
<option value="">Chọn loại thực phầVm</option>
@foreach ($units as $unit)
<option value="{{ $unit->id }}" unit-id= {{ $unit->id }}"
@if ($ingredient->unit->UnitName ==
$unit->UnitName) selected @endif>{{ $unit->UnitName }}
</option>
@endforeach
</select>
<input type="hidden" id="unit_id" name="Unit_ID"
value="{{ $unit->Unit_ID }}">
</div>
</div>
<div class="container d-flex justify-content-center align-items-center">
<div class="text-center pb-2 mx-2">
< href="{{ route('ingredients.index') }}"
class="btn btn-warning"> Quay lại</a>
</div>
<div class="text-center pb-2 mx-2">
<button type=submit class="btn btn-warning">Cập nhật</button>
Trang 35var select = document.getElementById("unit");
var UnitIdInput = document.getElementById("unit_id");
var selectedOption = select.options[select.selectedIndex]; var unitID = selectedOption.getAttribute("data-unit-id"); UnitIdInput.value = unitID;
<section class="slide-section">
<div class="container text-center">
<ul class="nav nav-tabs justify-content-center">
<a class="nav-link" href= {{
route('ingredients.index') }}">QuaVn lý nguyên liệu</a
Trang 36</li>
</ul>
</div>
<div class="container">
<div class="text-center pb-2 pt-2">
<h2>Các loại món ăn hiện có tại nhà ăn</h2>
</div>
<div class="container">
<table class="table table-striped m-2" style="border: 2pxsolid; border-radius: 10px">
Trang 37<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="exampleModalLabel">Xóa
<div class="modal-body">
Bạn có chăNc chăNn muỗNn xóaloại món ăn này khỗng?
</div>
<div class="modal-footer">
<button type="button"class="btn btn-secondary"
data-bs-dismiss="modal">HuVy</button>
<form method="POST"
Trang 38<div class="container text-center pt-2">
<a href= {{ route('dishtypes.create') }}" class="btn warning">Thêm mới loại món ăn</a>
<section class="slide-section">
<div class="container border rounded border-secondary">
<div class="container text-center pt-2">
<h2>Thêm mới loại món ăn</h2>
</div>
<div class="container">
<form class="" method="POST" action="{{
<input type="text" readonly class="form-control"
id="formGroupExampleInput" name="id" value="" placeholder="STT tự động tăng (khỗng cầln nhập)">
Trang 39</div>
<div class="mb-3">
<label for="formGroupExampleInput2" class=label">Loại món ăn</label>
<input type="text" class="form-control"
id="formGroupExampleInput2" name="DishTypeName" value=""
placeholder="Nhập tên loại món ăn">
</div>
</div>
<div class="container d-flex justify-content-center align-items-center">
<div class="text-center pb-2 mx-2">
< href="{{ route('dishtypes.index') }}"
class="btn btn-warning"> Quay lại</a>
</div>
<div class="text-center pb-2 mx-2">
<button type=submit class="btn btn-warning">Thêm mới</button>
<section class="slide-section">
<div class="container border rounded border-secondary">
<div class="container text-center pt-2">
<h2>Chi tiêNt thỗng tin loại món ăn</h2>
</div>
<div class="container">
Trang 40<div class="row justify-content-center mx-auto"
<div class="text-center pb-2">
<a href= {{ route('dishtypes.index') }}" class="btn btn-warning"> Quay lại</a
<section class="slide-section">
<div class="container border rounded border-secondary">
<div class="container text-center pt-2">
<h2>ChỉVnh sưVa thỗng tin loại món ăn</h2>
</div>