set admin result 0817

This commit is contained in:
imadhigp 2026-08-17 09:30:26 +05:30
parent 3207bbddac
commit 876c896478
8 changed files with 821 additions and 8 deletions

View File

@ -3,13 +3,40 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Models\Result; // Adjust based on your model name use App\Models\Result;
use App\Imports\ResultsImport;
use Maatwebsite\Excel\Facades\Excel;
class AdminResultsController extends Controller class AdminResultsController extends Controller
{ {
public function index() public function index(Request $request)
{ {
$results = Result::orderBy('id', 'desc')->get(); $query = Result::query();
// 1. Student Log ID, Module Code, හෝ Module Name මගින් Search කිරීම
if ($request->filled('search')) {
$search = $request->search;
$query->where(function ($q) use ($search) {
$q->where('student_log_id', 'like', "%{$search}%")
->orWhere('module_code', 'like', "%{$search}%")
->orWhere('module_name', 'like', "%{$search}%");
});
}
// 2. Academic Year මගින් Filter කිරීම
if ($request->filled('academic_year')) {
$query->where('academic_year', 'like', "%{$request->academic_year}%");
}
// 3. Pass/Fail Status මගින් Filter කිරීම
if ($request->filled('status')) {
$query->where('status', $request->status);
}
// Filter වූ Data Pagination (පිටුවකට 15 බැගින්) සමග ලබා ගැනීම
// (Pagination අවශ්‍ය නැතිනම් ->paginate(15) වෙනුවට ->get() භාවිතා කරන්න)
$results = $query->orderBy('id', 'desc')->paginate(15)->withQueryString();
return view('admin.adminresults', compact('results')); return view('admin.adminresults', compact('results'));
} }
@ -57,4 +84,17 @@ class AdminResultsController extends Controller
return redirect()->route('admin.results')->with('success', 'Exam result deleted successfully.'); return redirect()->route('admin.results')->with('success', 'Exam result deleted successfully.');
} }
public function import(Request $request)
{
$request->validate([
'excel_file' => 'required|mimes:xlsx,xls,csv|max:2048'
]);
// Excel file එක Import කිරීම
Excel::import(new ResultsImport, $request->file('excel_file'));
// Upload වූ පසු කෙලින්ම Admin Results Table එකට Redirect කිරීම
return redirect()->route('admin.results')->with('success', 'Excel file imported successfully!');
}
} }

View File

@ -0,0 +1,24 @@
<?php
namespace App\Imports;
use App\Models\Result;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
class ResultsImport implements ToModel, WithHeadingRow
{
public function model(array $row)
{
return new Result([
'student_log_id' => $row['student_log_id'],
'module_code' => $row['module_code'],
'module_name' => $row['module_name'],
'academic_year' => $row['academic_year'],
'semester' => $row['semester'],
'marks' => $row['marks'],
'grade' => $row['grade'],
'status' => $row['status'],
]);
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class CourseAssignStudent extends Model
{
use HasFactory;
// Database table name
protected $table = 'course_assign_student';
// Mass assignable attributes
protected $fillable = [
'student_details_id',
'course_id',
];
/**
* Relationship: Student Details
*/
public function studentDetail()
{
return $this->belongsTo(StudentDetail::class, 'student_details_id');
}
/**
* Relationship: Course
*/
public function course()
{
return $this->belongsTo(Course::class, 'course_id');
}
}

View File

@ -9,7 +9,8 @@
"php": "^8.2", "php": "^8.2",
"barryvdh/laravel-dompdf": "^3.1", "barryvdh/laravel-dompdf": "^3.1",
"laravel/framework": "^12.0", "laravel/framework": "^12.0",
"laravel/tinker": "^2.10.1" "laravel/tinker": "^2.10.1",
"maatwebsite/excel": "^3.1"
}, },
"require-dev": { "require-dev": {
"fakerphp/faker": "^1.23", "fakerphp/faker": "^1.23",

590
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "bf969a713724ba1caaf90ec885c262c2", "content-hash": "27e347a8b5690b9553d03455e725edaa",
"packages": [ "packages": [
{ {
"name": "barryvdh/laravel-dompdf", "name": "barryvdh/laravel-dompdf",
@ -212,6 +212,159 @@
], ],
"time": "2024-02-09T16:56:22+00:00" "time": "2024-02-09T16:56:22+00:00"
}, },
{
"name": "composer/pcre",
"version": "3.4.0",
"source": {
"type": "git",
"url": "https://github.com/composer/pcre.git",
"reference": "d5a341b3fb61f3001970940afb1d332968a183ed"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/pcre/zipball/d5a341b3fb61f3001970940afb1d332968a183ed",
"reference": "d5a341b3fb61f3001970940afb1d332968a183ed",
"shasum": ""
},
"require": {
"php": "^7.4 || ^8.0"
},
"conflict": {
"phpstan/phpstan": "<2.2.2"
},
"require-dev": {
"phpstan/phpstan": "^2",
"phpstan/phpstan-deprecation-rules": "^2",
"phpstan/phpstan-strict-rules": "^2",
"phpunit/phpunit": "^9"
},
"type": "library",
"extra": {
"phpstan": {
"includes": [
"extension.neon"
]
},
"branch-alias": {
"dev-main": "3.x-dev"
}
},
"autoload": {
"psr-4": {
"Composer\\Pcre\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
}
],
"description": "PCRE wrapping library that offers type-safe preg_* replacements.",
"keywords": [
"PCRE",
"preg",
"regex",
"regular expression"
],
"support": {
"issues": "https://github.com/composer/pcre/issues",
"source": "https://github.com/composer/pcre/tree/3.4.0"
},
"funding": [
{
"url": "https://packagist.com",
"type": "custom"
},
{
"url": "https://github.com/composer",
"type": "github"
}
],
"time": "2026-06-07T11:47:49+00:00"
},
{
"name": "composer/semver",
"version": "3.4.4",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
"reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95",
"reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95",
"shasum": ""
},
"require": {
"php": "^5.3.2 || ^7.0 || ^8.0"
},
"require-dev": {
"phpstan/phpstan": "^1.11",
"symfony/phpunit-bridge": "^3 || ^7"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.x-dev"
}
},
"autoload": {
"psr-4": {
"Composer\\Semver\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nils Adermann",
"email": "naderman@naderman.de",
"homepage": "http://www.naderman.de"
},
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
},
{
"name": "Rob Bast",
"email": "rob.bast@gmail.com",
"homepage": "http://robbast.nl"
}
],
"description": "Semver library that offers utilities, version constraint parsing and validation.",
"keywords": [
"semantic",
"semver",
"validation",
"versioning"
],
"support": {
"irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/semver/issues",
"source": "https://github.com/composer/semver/tree/3.4.4"
},
"funding": [
{
"url": "https://packagist.com",
"type": "custom"
},
{
"url": "https://github.com/composer",
"type": "github"
}
],
"time": "2025-08-20T19:15:30+00:00"
},
{ {
"name": "dflydev/dot-access-data", "name": "dflydev/dot-access-data",
"version": "v3.0.3", "version": "v3.0.3",
@ -740,6 +893,67 @@
], ],
"time": "2025-03-06T22:45:56+00:00" "time": "2025-03-06T22:45:56+00:00"
}, },
{
"name": "ezyang/htmlpurifier",
"version": "v4.19.0",
"source": {
"type": "git",
"url": "https://github.com/ezyang/htmlpurifier.git",
"reference": "b287d2a16aceffbf6e0295559b39662612b77fcf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/b287d2a16aceffbf6e0295559b39662612b77fcf",
"reference": "b287d2a16aceffbf6e0295559b39662612b77fcf",
"shasum": ""
},
"require": {
"php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0"
},
"require-dev": {
"cerdic/css-tidy": "^1.7 || ^2.0",
"simpletest/simpletest": "dev-master"
},
"suggest": {
"cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.",
"ext-bcmath": "Used for unit conversion and imagecrash protection",
"ext-iconv": "Converts text to and from non-UTF-8 encodings",
"ext-tidy": "Used for pretty-printing HTML"
},
"type": "library",
"autoload": {
"files": [
"library/HTMLPurifier.composer.php"
],
"psr-0": {
"HTMLPurifier": "library/"
},
"exclude-from-classmap": [
"/library/HTMLPurifier/Language/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1-or-later"
],
"authors": [
{
"name": "Edward Z. Yang",
"email": "admin@htmlpurifier.org",
"homepage": "http://ezyang.com"
}
],
"description": "Standards compliant HTML filter written in PHP",
"homepage": "http://htmlpurifier.org/",
"keywords": [
"html"
],
"support": {
"issues": "https://github.com/ezyang/htmlpurifier/issues",
"source": "https://github.com/ezyang/htmlpurifier/tree/v4.19.0"
},
"time": "2025-10-17T16:34:55+00:00"
},
{ {
"name": "fruitcake/php-cors", "name": "fruitcake/php-cors",
"version": "v1.4.0", "version": "v1.4.0",
@ -2257,6 +2471,272 @@
], ],
"time": "2026-03-08T20:05:35+00:00" "time": "2026-03-08T20:05:35+00:00"
}, },
{
"name": "maatwebsite/excel",
"version": "3.1.70",
"source": {
"type": "git",
"url": "https://github.com/SpartnerNL/Laravel-Excel.git",
"reference": "b5cafdfcf7ec63924e83303763be8fcae340f70b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/SpartnerNL/Laravel-Excel/zipball/b5cafdfcf7ec63924e83303763be8fcae340f70b",
"reference": "b5cafdfcf7ec63924e83303763be8fcae340f70b",
"shasum": ""
},
"require": {
"composer/semver": "^3.3",
"ext-json": "*",
"illuminate/support": "5.8.*||^6.0||^7.0||^8.0||^9.0||^10.0||^11.0||^12.0||^13.0",
"php": "^7.0||^8.0",
"phpoffice/phpspreadsheet": "^1.30.5",
"psr/simple-cache": "^1.0||^2.0||^3.0"
},
"require-dev": {
"laravel/scout": "^7.0||^8.0||^9.0||^10.0||^11.0",
"orchestra/testbench": "^6.0||^7.0||^8.0||^9.0||^10.0||^11.0",
"predis/predis": "^1.1"
},
"type": "library",
"extra": {
"laravel": {
"aliases": {
"Excel": "Maatwebsite\\Excel\\Facades\\Excel"
},
"providers": [
"Maatwebsite\\Excel\\ExcelServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Maatwebsite\\Excel\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Patrick Brouwers",
"email": "patrick@spartner.nl"
}
],
"description": "Supercharged Excel exports and imports in Laravel",
"keywords": [
"PHPExcel",
"batch",
"csv",
"excel",
"export",
"import",
"laravel",
"php",
"phpspreadsheet"
],
"support": {
"issues": "https://github.com/SpartnerNL/Laravel-Excel/issues",
"source": "https://github.com/SpartnerNL/Laravel-Excel/tree/3.1.70"
},
"funding": [
{
"url": "https://laravel-excel.com/commercial-support",
"type": "custom"
},
{
"url": "https://github.com/patrickbrouwers",
"type": "github"
}
],
"time": "2026-08-13T09:11:54+00:00"
},
{
"name": "maennchen/zipstream-php",
"version": "3.1.2",
"source": {
"type": "git",
"url": "https://github.com/maennchen/ZipStream-PHP.git",
"reference": "aeadcf5c412332eb426c0f9b4485f6accba2a99f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/aeadcf5c412332eb426c0f9b4485f6accba2a99f",
"reference": "aeadcf5c412332eb426c0f9b4485f6accba2a99f",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"ext-zlib": "*",
"php-64bit": "^8.2"
},
"require-dev": {
"brianium/paratest": "^7.7",
"ext-zip": "*",
"friendsofphp/php-cs-fixer": "^3.16",
"guzzlehttp/guzzle": "^7.5",
"mikey179/vfsstream": "^1.6",
"php-coveralls/php-coveralls": "^2.5",
"phpunit/phpunit": "^11.0",
"vimeo/psalm": "^6.0"
},
"suggest": {
"guzzlehttp/psr7": "^2.4",
"psr/http-message": "^2.0"
},
"type": "library",
"autoload": {
"psr-4": {
"ZipStream\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Paul Duncan",
"email": "pabs@pablotron.org"
},
{
"name": "Jonatan Männchen",
"email": "jonatan@maennchen.ch"
},
{
"name": "Jesse Donat",
"email": "donatj@gmail.com"
},
{
"name": "András Kolesár",
"email": "kolesar@kolesar.hu"
}
],
"description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.",
"keywords": [
"stream",
"zip"
],
"support": {
"issues": "https://github.com/maennchen/ZipStream-PHP/issues",
"source": "https://github.com/maennchen/ZipStream-PHP/tree/3.1.2"
},
"funding": [
{
"url": "https://github.com/maennchen",
"type": "github"
}
],
"time": "2025-01-27T12:07:53+00:00"
},
{
"name": "markbaker/complex",
"version": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/MarkBaker/PHPComplex.git",
"reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/95c56caa1cf5c766ad6d65b6344b807c1e8405b9",
"reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "dev-master",
"phpcompatibility/php-compatibility": "^9.3",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
"squizlabs/php_codesniffer": "^3.7"
},
"type": "library",
"autoload": {
"psr-4": {
"Complex\\": "classes/src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mark Baker",
"email": "mark@lange.demon.co.uk"
}
],
"description": "PHP Class for working with complex numbers",
"homepage": "https://github.com/MarkBaker/PHPComplex",
"keywords": [
"complex",
"mathematics"
],
"support": {
"issues": "https://github.com/MarkBaker/PHPComplex/issues",
"source": "https://github.com/MarkBaker/PHPComplex/tree/3.0.2"
},
"time": "2022-12-06T16:21:08+00:00"
},
{
"name": "markbaker/matrix",
"version": "3.0.1",
"source": {
"type": "git",
"url": "https://github.com/MarkBaker/PHPMatrix.git",
"reference": "728434227fe21be27ff6d86621a1b13107a2562c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/728434227fe21be27ff6d86621a1b13107a2562c",
"reference": "728434227fe21be27ff6d86621a1b13107a2562c",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "dev-master",
"phpcompatibility/php-compatibility": "^9.3",
"phpdocumentor/phpdocumentor": "2.*",
"phploc/phploc": "^4.0",
"phpmd/phpmd": "2.*",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
"sebastian/phpcpd": "^4.0",
"squizlabs/php_codesniffer": "^3.7"
},
"type": "library",
"autoload": {
"psr-4": {
"Matrix\\": "classes/src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mark Baker",
"email": "mark@demon-angel.eu"
}
],
"description": "PHP Class for working with matrices",
"homepage": "https://github.com/MarkBaker/PHPMatrix",
"keywords": [
"mathematics",
"matrix",
"vector"
],
"support": {
"issues": "https://github.com/MarkBaker/PHPMatrix/issues",
"source": "https://github.com/MarkBaker/PHPMatrix/tree/3.0.1"
},
"time": "2022-12-02T22:17:43+00:00"
},
{ {
"name": "masterminds/html5", "name": "masterminds/html5",
"version": "2.10.1", "version": "2.10.1",
@ -2834,6 +3314,114 @@
], ],
"time": "2026-02-16T23:10:27+00:00" "time": "2026-02-16T23:10:27+00:00"
}, },
{
"name": "phpoffice/phpspreadsheet",
"version": "1.30.6",
"source": {
"type": "git",
"url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
"reference": "a416375ffc8bf5b661c1bb4e6c60d8f3fddbe5ce"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/a416375ffc8bf5b661c1bb4e6c60d8f3fddbe5ce",
"reference": "a416375ffc8bf5b661c1bb4e6c60d8f3fddbe5ce",
"shasum": ""
},
"require": {
"composer/pcre": "^1||^2||^3",
"ext-ctype": "*",
"ext-dom": "*",
"ext-fileinfo": "*",
"ext-gd": "*",
"ext-iconv": "*",
"ext-libxml": "*",
"ext-mbstring": "*",
"ext-simplexml": "*",
"ext-xml": "*",
"ext-xmlreader": "*",
"ext-xmlwriter": "*",
"ext-zip": "*",
"ext-zlib": "*",
"ezyang/htmlpurifier": "^4.15",
"maennchen/zipstream-php": "^2.1 || ^3.0",
"markbaker/complex": "^3.0",
"markbaker/matrix": "^3.0",
"php": ">=7.4.0 <8.5.0",
"psr/simple-cache": "^1.0 || ^2.0 || ^3.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "dev-main",
"doctrine/instantiator": "^1.5",
"dompdf/dompdf": "^1.0 || ^2.0 || ^3.0",
"friendsofphp/php-cs-fixer": "^3.2",
"mitoteam/jpgraph": "^10.3",
"mpdf/mpdf": "^8.1.1",
"phpcompatibility/php-compatibility": "^9.3",
"phpstan/phpstan": "^1.1",
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^8.5 || ^9.0",
"squizlabs/php_codesniffer": "^3.7",
"tecnickcom/tcpdf": "^6.5"
},
"suggest": {
"dompdf/dompdf": "Option for rendering PDF with PDF Writer",
"ext-intl": "PHP Internationalization Functions",
"mitoteam/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers",
"mpdf/mpdf": "Option for rendering PDF with PDF Writer",
"tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer"
},
"type": "library",
"autoload": {
"psr-4": {
"PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Maarten Balliauw",
"homepage": "https://blog.maartenballiauw.be"
},
{
"name": "Mark Baker",
"homepage": "https://markbakeruk.net"
},
{
"name": "Franck Lefevre",
"homepage": "https://rootslabs.net"
},
{
"name": "Erik Tilt"
},
{
"name": "Adrien Crivelli"
},
{
"name": "Owen Leibman"
}
],
"description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine",
"homepage": "https://github.com/PHPOffice/PhpSpreadsheet",
"keywords": [
"OpenXML",
"excel",
"gnumeric",
"ods",
"php",
"spreadsheet",
"xls",
"xlsx"
],
"support": {
"issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues",
"source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.30.6"
},
"time": "2026-07-12T19:59:31+00:00"
},
{ {
"name": "phpoption/phpoption", "name": "phpoption/phpoption",
"version": "1.9.5", "version": "1.9.5",

View File

@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('modules', function (Blueprint $table) {
$table->id();
$table->foreignId('course_id')->constrained()->onDelete('cascade');
$table->string('title');
$table->text('description')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('modules');
}
};

View File

@ -8,9 +8,16 @@
<h3 class="fw-bold text-navy"> <h3 class="fw-bold text-navy">
<i class="fa-solid fa-square-poll-vertical me-2"></i>Exam Results Management <i class="fa-solid fa-square-poll-vertical me-2"></i>Exam Results Management
</h3> </h3>
<button class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#addResultModal"> <div>
<i class="fa-solid fa-plus me-1"></i> Add New Result <!-- Import Excel Button -->
</button> <button class="btn btn-success me-2" data-bs-toggle="modal" data-bs-target="#importExcelModal">
<i class="fa-solid fa-file-excel me-1"></i> Import Excel
</button>
<!-- Add Single Result Button -->
<button class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#addResultModal">
<i class="fa-solid fa-plus me-1"></i> Add New Result
</button>
</div>
</div> </div>
@if(session('success')) @if(session('success'))
@ -32,6 +39,52 @@
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div> </div>
@endif @endif
<!-- Filter & Search Section -->
<div class="card border-0 shadow-sm rounded-3 mb-4">
<div class="card-body">
<form action="{{ route('admin.results.index') }}" method="GET">
<div class="row g-3 align-items-end">
<!-- Search Box -->
<div class="col-md-4">
<label class="form-label fw-bold small text-secondary">Search</label>
<div class="input-group">
<span class="input-group-text bg-white"><i class="fa-solid fa-magnifying-glass text-muted"></i></span>
<input type="text" name="search" class="form-control" placeholder="Student ID, Module Code/Name..." value="{{ request('search') }}">
</div>
</div>
<!-- Academic Year Filter -->
<div class="col-md-3">
<label class="form-label fw-bold small text-secondary">Academic Year</label>
<input type="text" name="academic_year" class="form-control" placeholder="e.g. 2025/2026" value="{{ request('academic_year') }}">
</div>
<!-- Status Filter -->
<div class="col-md-3">
<label class="form-label fw-bold small text-secondary">Status</label>
<select name="status" class="form-select">
<option value="">All Statuses</option>
<option value="Pass" {{ request('status') == 'Pass' ? 'selected' : '' }}>Pass</option>
<option value="Fail" {{ request('status') == 'Fail' ? 'selected' : '' }}>Fail</option>
</select>
</div>
<!-- Filter & Reset Buttons -->
<div class="col-md-2 d-flex gap-2">
<button type="submit" class="btn btn-navy text-white w-100" style="background-color: #0a192f;">
<i class="fa-solid fa-filter me-1"></i> Filter
</button>
<a href="{{ route('admin.results.index') }}" class="btn btn-outline-secondary" title="Reset Filters">
<i class="fa-solid fa-rotate-left"></i>
</a>
</div>
</div>
</form>
</div>
</div>
<!-- Results Table --> <!-- Results Table -->
<div class="card border-0 shadow-sm rounded-3"> <div class="card border-0 shadow-sm rounded-3">
@ -161,6 +214,35 @@
</div> </div>
</div> </div>
<!-- Import Excel Modal -->
<div class="modal fade" id="importExcelModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-success text-white">
<h5 class="modal-title"><i class="fa-solid fa-file-excel me-2"></i>Import Results Excel File</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="{{ route('admin.results.import') }}" method="POST" enctype="multipart/form-data">
@csrf
<div class="modal-body">
<div class="mb-3">
<label class="form-label fw-bold">Choose Excel File (.xlsx, .xls, .csv)</label>
<input type="file" name="excel_file" class="form-control" accept=".xlsx, .xls, .csv" required>
</div>
<div class="alert alert-info py-2 small mb-0">
<i class="fa-solid fa-circle-info me-1"></i>This Excel <strong>Headers</strong>that should be included in the file for successful import:
<br><code>student_log_id</code>, <code>module_code</code>, <code>module_name</code>, <code>academic_year</code>, <code>semester</code>, <code>marks</code>, <code>grade</code>, <code>status</code>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="submit" class="btn btn-success"><i class="fa-solid fa-upload me-1"></i> Upload & Process</button>
</div>
</form>
</div>
</div>
</div>
<!-- Add Result Modal --> <!-- Add Result Modal -->
<div class="modal fade" id="addResultModal" tabindex="-1" aria-hidden="true"> <div class="modal fade" id="addResultModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg"> <div class="modal-dialog modal-lg">
@ -218,4 +300,8 @@
</div> </div>
</div> </div>
</div> </div>
@endsection @endsection

View File

@ -174,4 +174,12 @@ Route::middleware(['web'])->prefix('admin')->group(function () {
Route::get('/profile', [AdminProfileController::class, 'index'])->name('admin.profile'); Route::get('/profile', [AdminProfileController::class, 'index'])->name('admin.profile');
Route::put('/profile/update', [AdminProfileController::class, 'update'])->name('admin.profile.update'); Route::put('/profile/update', [AdminProfileController::class, 'update'])->name('admin.profile.update');
Route::put('/profile/password', [AdminProfileController::class, 'updatePassword'])->name('admin.profile.password'); Route::put('/profile/password', [AdminProfileController::class, 'updatePassword'])->name('admin.profile.password');
Route::prefix('admin')->name('admin.')->group(function () {
Route::get('/results', [AdminResultsController::class, 'index'])->name('results.index');
Route::post('/results/import', [AdminResultsController::class, 'import'])->name('results.import');
Route::post('/admin/courses/assign', [adminmycoursesController::class, 'assignCourse'])->name('admin.courses.assign');
});
}); });