Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 931d67cdd8 | |||
| 7107286c1a | |||
| 994add824f | |||
| 0b7e0b8e94 |
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exports;
|
||||
|
||||
use Maatwebsite\Excel\Concerns\FromArray;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
|
||||
|
||||
class VisitsExport implements FromArray, WithHeadings, ShouldAutoSize
|
||||
{
|
||||
protected $rows;
|
||||
|
||||
public function __construct(array $rows)
|
||||
{
|
||||
$this->rows = $rows;
|
||||
}
|
||||
|
||||
public function headings(): array
|
||||
{
|
||||
return [
|
||||
'شناسه',
|
||||
'نام',
|
||||
'نام خانوادگی',
|
||||
'ایمیل',
|
||||
'موبایل',
|
||||
'تاریخ ثبتنام',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public function array(): array
|
||||
{
|
||||
return $this->rows;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,16 +4,100 @@
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\AdminStoreRequest;
|
||||
use App\Http\Requests\AdminUpdateRequest;
|
||||
use App\Models\Admin;
|
||||
use App\Models\Permission;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class AdminController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$admins = Admin::query()
|
||||
->with('permissions')
|
||||
->latest()
|
||||
->paginate(10);
|
||||
|
||||
return view('admin.admins.index', compact('admins'));
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
$permissions = Permission::query()
|
||||
->orderBy('name')
|
||||
->get();
|
||||
|
||||
return view(
|
||||
'admin.admins.create',
|
||||
compact('permissions')
|
||||
);
|
||||
}
|
||||
|
||||
public function store(AdminStoreRequest $request)
|
||||
{
|
||||
$data = $request->validated();
|
||||
|
||||
$permissions = $data['permissions'] ?? [];
|
||||
|
||||
unset($data['permissions']);
|
||||
|
||||
$data['password'] = Hash::make($data['password']);
|
||||
|
||||
$admin = Admin::create($data);
|
||||
|
||||
$admin->permissions()->sync($permissions);
|
||||
|
||||
return redirect()
|
||||
->route('admin.admins.index')
|
||||
->with('success', 'مدیر با موفقیت ایجاد شد.');
|
||||
}
|
||||
|
||||
public function edit(Admin $admin)
|
||||
{
|
||||
$permissions = Permission::query()
|
||||
->orderBy('name')
|
||||
->get();
|
||||
|
||||
$admin->load('permissions');
|
||||
|
||||
return view(
|
||||
'admin.admins.edit',
|
||||
compact('admin', 'permissions')
|
||||
);
|
||||
}
|
||||
|
||||
public function update(AdminUpdateRequest $request, Admin $admin)
|
||||
{
|
||||
$data = $request->validated();
|
||||
|
||||
$permissions = $data['permissions'] ?? [];
|
||||
|
||||
unset($data['permissions']);
|
||||
|
||||
if (!empty($data['password'])) {
|
||||
$data['password'] = Hash::make($data['password']);
|
||||
} else {
|
||||
unset($data['password']);
|
||||
}
|
||||
|
||||
$admin->update($data);
|
||||
|
||||
$admin->permissions()->sync($permissions);
|
||||
|
||||
return redirect()
|
||||
->route('admin.admins.index')
|
||||
->with('success', 'اطلاعات مدیر با موفقیت ویرایش شد.');
|
||||
}
|
||||
|
||||
public function destroy(Admin $admin)
|
||||
{
|
||||
$admin->permissions()->detach();
|
||||
|
||||
$admin->delete();
|
||||
|
||||
return redirect()
|
||||
->route('admin.admins.index')
|
||||
->with('success', 'مدیر با موفقیت حذف شد.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,11 @@ use App\Models\Flight;
|
||||
use App\Models\Payment;
|
||||
use App\Models\Tour;
|
||||
use App\Models\User;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use App\Exports\VisitsExport;
|
||||
use App\Models\VisitStatistic;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Hekmatinasser\Verta\Verta;
|
||||
|
||||
class DashboardController extends Controller
|
||||
{
|
||||
@@ -39,4 +44,25 @@ class DashboardController extends Controller
|
||||
'paymentsCount'
|
||||
));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
// ۱. لیست کاربران با فیلدهایی که واقعاً در جدول users داری
|
||||
$users = User::select('id', 'first_name', 'last_name', 'email', 'mobile', 'created_at')->get();
|
||||
|
||||
|
||||
// ۲. تبدیل به آرایه برای اکسل
|
||||
$rows = $users->map(fn($user) => [
|
||||
$user->id,
|
||||
$user->first_name,
|
||||
$user->last_name,
|
||||
$user->email,
|
||||
$user->mobile,
|
||||
$user->created_at ? Verta::instance($user->created_at)->format('Y/m/d') : '-',
|
||||
])->toArray();
|
||||
|
||||
// ۳. تغییر کلاس اکسل و اسم فایل
|
||||
return Excel::download(new VisitsExport($rows), 'users-report-' . now()->format('Y-m-d') . '.xlsx');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/* ========================================
|
||||
Admin Panel
|
||||
Airline Agency
|
||||
======================================== */
|
||||
|
||||
body {
|
||||
background-color: #f5f7fb;
|
||||
}
|
||||
|
||||
|
||||
/* Main admin layout */
|
||||
|
||||
.admin-wrapper {
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
|
||||
/* Sidebar */
|
||||
|
||||
.admin-sidebar {
|
||||
width: 260px;
|
||||
min-height: 100vh;
|
||||
background: #ffffff;
|
||||
border-left: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
|
||||
/* Main content */
|
||||
|
||||
.admin-content {
|
||||
min-height: 100vh;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
|
||||
/* Cards */
|
||||
|
||||
.admin-card {
|
||||
background: #ffffff;
|
||||
border: 1px solid #e9ecef;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
|
||||
/* Dashboard stat cards */
|
||||
|
||||
.admin-stat-card {
|
||||
transition: all .2s ease;
|
||||
}
|
||||
|
||||
.admin-stat-card:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
|
||||
/* Sidebar links */
|
||||
|
||||
.admin-sidebar .nav-link {
|
||||
color: #495057;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 4px;
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.admin-sidebar .nav-link:hover {
|
||||
background-color: #f1f5f9;
|
||||
}
|
||||
|
||||
.admin-sidebar .nav-link.active {
|
||||
background-color: #eaf2ff;
|
||||
color: #0d6efd;
|
||||
}
|
||||
|
||||
|
||||
/* Airline icon box */
|
||||
|
||||
.admin-icon-box {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
|
||||
/* Tables */
|
||||
|
||||
.admin-table th {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.admin-table td {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
||||
/* Breadcrumb */
|
||||
|
||||
.admin-breadcrumb {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
|
||||
/* Responsive */
|
||||
|
||||
@media (max-width: 991px) {
|
||||
|
||||
.admin-sidebar {
|
||||
width: 100%;
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
.admin-content {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
@extends('admin.layouts.app')
|
||||
|
||||
@section('title', 'تغییر رمز کاربر')
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid pt-4">
|
||||
|
||||
@if($errors->any())
|
||||
<div class="alert alert-danger">
|
||||
<ul class="mb-0">
|
||||
@foreach($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xl-6">
|
||||
<div class="card custom-card">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">تغییر رمز عبور — {{ $user->full_name ?? $user->name }}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('admin.users.update-password', $user) }}">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">رمز عبور جدید</label>
|
||||
<input type="password" name="password"
|
||||
class="form-control @error('password') is-invalid @enderror">
|
||||
@error('password')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">تکرار رمز جدید</label>
|
||||
<input type="password" name="password_confirmation"
|
||||
class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" class="btn btn-success">ذخیره رمز</button>
|
||||
<a href="{{ route('admin.users.index') }}" class="btn btn-secondary">انصراف</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
Reference in New Issue
Block a user