added invoice seeder

added device pie chart
optimized order & invoice table struct
pull/44/head
A1Gard 4 months ago
parent 597beda443
commit e8993dcd81

@ -46,6 +46,9 @@ class HomeController extends Controller
$item = date('Y-m-d', $x); $item = date('Y-m-d', $x);
} }
}); });
return view('home',compact('dates','visits'));
$mobiles_count = Visitor::where('created_at', '>=', Carbon::now()->subMonth())->where('is_mobile',1)->count();
$all_visitor = Visitor::where('created_at', '>=', Carbon::now()->subMonth())->count();
return view('home',compact('dates','visits','all_visitor','mobiles_count'));
} }
} }

@ -17,6 +17,11 @@ class Invoice extends Model
return 'hash'; return 'hash';
} }
public function orders()
{
return $this->hasMany(Order::class);
}
protected static function boot() protected static function boot()
{ {
parent::boot(); parent::boot();

@ -58,19 +58,49 @@ class User extends Authenticatable
{ {
return $this->hasMany(Post::class); return $this->hasMany(Post::class);
} }
public function postsPercent()
{
if (Post::count() == 0) {
return 100;
}
return $this->posts()->count() * 100 / Post::count();
}
public function products() public function products()
{ {
return $this->hasMany(Product::class); return $this->hasMany(Product::class);
} }
public function productsPercent()
{
if (Product::count() == 0) {
return 100;
}
return $this->products()->count() * 100 / Product::count();
}
public function tickets() public function tickets()
{ {
return $this->hasMany(Ticket::class); return $this->hasMany(Ticket::class);
} }
public function ticketsPercent()
{
if (Ticket::count() == 0) {
return 100;
}
return $this->tickets()->count() * 100 / Ticket::count();
}
public function comments() public function comments()
{ {
return $this->morphMany(Comment::class,'commentator'); return $this->morphMany(Comment::class,'commentator');
} }
public function commentsPercent()
{
if (Comment::count() == 0) {
return 100;
}
return $this->comments()->count() * 100 / Comment::count();
}
public function logs() public function logs()
{ {
return $this->hasMany(AdminLog::class, 'user_id', 'id'); return $this->hasMany(AdminLog::class, 'user_id', 'id');

@ -2,6 +2,8 @@
namespace Database\Factories; namespace Database\Factories;
use App\Models\Customer;
use App\Models\Invoice;
use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Database\Eloquent\Factories\Factory;
/** /**
@ -16,8 +18,17 @@ class InvoiceFactory extends Factory
*/ */
public function definition(): array public function definition(): array
{ {
$date = $this->faker->dateTimeBetween('-1 months', 'now');
return [ return [
// 'customer_id' => Customer::inRandomOrder()->first()->id,
'status' => Invoice::$invoiceStatus[rand(0,count(Invoice::$invoiceStatus)-1)],
'desc' => $this->faker->realText(),
'address_id' => null,
'transport_id' => null,
'transport_price' => 0,
'created_at' => $date,
'updated_at' => $date,
'total_price' => 0,
]; ];
} }
} }

@ -17,6 +17,7 @@ return new class extends Migration
$table->unsignedBigInteger('customer_id'); $table->unsignedBigInteger('customer_id');
$table->enum("status",\App\Models\Invoice::$invoiceStatus)->nullable()->default("PENDING"); $table->enum("status",\App\Models\Invoice::$invoiceStatus)->nullable()->default("PENDING");
$table->unsignedBigInteger('total_price')->nullable()->default(0); $table->unsignedBigInteger('total_price')->nullable()->default(0);
$table->integer('count')->nullable()->default(0);
$table->json('meta')->nullable(); $table->json('meta')->nullable();
$table->unsignedBigInteger('discount_id')->nullable()->default(null); $table->unsignedBigInteger('discount_id')->nullable()->default(null);
$table->text('desc')->nullable()->default(null); $table->text('desc')->nullable()->default(null);

@ -15,7 +15,7 @@ return new class extends Migration
$table->id(); $table->id();
$table->unsignedBigInteger('invoice_id'); $table->unsignedBigInteger('invoice_id');
$table->unsignedBigInteger('product_id'); $table->unsignedBigInteger('product_id');
$table->unsignedBigInteger('quantity_id'); $table->unsignedBigInteger('quantity_id')->nullable();
$table->integer('count')->nullable()->default(1); $table->integer('count')->nullable()->default(1);
$table->unsignedInteger('price_total'); $table->unsignedInteger('price_total');
$table->json('data')->nullable()->default(null);; $table->json('data')->nullable()->default(null);;

@ -37,6 +37,7 @@ class DatabaseSeeder extends Seeder
GfxSeeder::class, GfxSeeder::class,
AreaSeeder::class, AreaSeeder::class,
PartSeeder::class, PartSeeder::class,
InvoiceSeeder::class,
VisitorSeeder::class VisitorSeeder::class
] ]
); );

@ -2,6 +2,9 @@
namespace Database\Seeders; namespace Database\Seeders;
use App\Models\Invoice;
use App\Models\Order;
use App\Models\Product;
use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder; use Illuminate\Database\Seeder;
@ -13,5 +16,22 @@ class InvoiceSeeder extends Seeder
public function run(): void public function run(): void
{ {
// //
Invoice::factory(70)->create();
foreach (Invoice::all() as $it){
$total = 0;
for ($i = 0; $i <= rand(1,4); $i++) {
$order = new Order();
$order->product_id = Product::inRandomOrder()->first()->id;
$order->count = 1;
$order->price_total = rand(100,2000).'000';
$total = $order->price_total ;
$order->invoice_id = $it->id;
$order->save();
}
$it->total_price = $total;
$it->count = $it->orders()->count();
$it->save();
}
} }
} }

@ -30,6 +30,17 @@ import './panel/setting-section-controller.js';
import './panel/sotable-controller.js'; import './panel/sotable-controller.js';
import './panel/prototypes.js'; import './panel/prototypes.js';
// chartjs.defaults.defaultFontFamily = "Vazir";
// chartjs.defaults.defaultFontSize = 18;
// chartjs.defaults.backgroundColor = '#0097ff';
chartjs.defaults.borderColor = 'rgba(255,255,255,0.05)';
chartjs.defaults.color = '#fff';
chartjs.defaults.font.family = 'Vazir';
// chartjs.defaults.font.size = '14';
// chartjs.defaults.font.weight = '100';
window.chartjs = chartjs; window.chartjs = chartjs;
window.isPaintedChart = false; window.isPaintedChart = false;

@ -272,3 +272,5 @@ a.btn,a.action-btn,a.circle-btn{
flex-wrap: wrap; flex-wrap: wrap;
} }
} }

@ -12,7 +12,7 @@
<img src="{{asset('panel/images/xshop-logo.svg')}}" class="avatar-x64" alt=""> <img src="{{asset('panel/images/xshop-logo.svg')}}" class="avatar-x64" alt="">
</div> </div>
<div class="col-9 pt-1"> <div class="col-9 pt-1">
{{__("Welcome bak")}} {{__("Welcome back")}}
<h4 class="mt-2"> <h4 class="mt-2">
{{auth()->user()->name}} {{auth()->user()->name}}
</h4> </h4>
@ -24,24 +24,40 @@
{{__("Posts")}} {{__("Posts")}}
</h5> </h5>
{{number_format(auth()->user()->posts()->count())}} {{number_format(auth()->user()->posts()->count())}}
<div class="progress" role="progressbar" style="height: 3px">
<div class="progress-bar"
style="width: {{auth()->user()->postsPercent()}}%"></div>
</div>
</div> </div>
<div class="col-6 mt-3"> <div class="col-6 mt-3">
<h5> <h5>
{{__("Products")}} {{__("Products")}}
</h5> </h5>
{{number_format(auth()->user()->products()->count())}} {{number_format(auth()->user()->products()->count())}}
<div class="progress" role="progressbar" style="height: 3px">
<div class="progress-bar bg-warning"
style="width: {{auth()->user()->productsPercent()}}%"></div>
</div>
</div> </div>
<div class="col-6 mt-3"> <div class="col-6 mt-3">
<h5> <h5>
{{__("Comments")}} {{__("Comments")}}
</h5> </h5>
{{number_format(auth()->user()->comments()->count())}} {{number_format(auth()->user()->comments()->count())}}
<div class="progress" role="progressbar" style="height: 3px">
<div class="progress-bar bg-danger"
style="width: {{auth()->user()->commentsPercent()}}%"></div>
</div>
</div> </div>
<div class="col-6 mt-3"> <div class="col-6 mt-3">
<h5> <h5>
{{__("Tickets")}} {{__("Tickets")}}
</h5> </h5>
{{number_format(auth()->user()->tickets()->count())}} {{number_format(auth()->user()->tickets()->count())}}
<div class="progress" role="progressbar" style="height: 3px">
<div class="progress-bar bg-success"
style="width: {{auth()->user()->ticketsPercent()}}%"></div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -58,7 +74,7 @@
<a href="#"> <a href="#">
<i class="ri-shopping-bag-4-line"></i> <i class="ri-shopping-bag-4-line"></i>
<h2> <h2>
{{number_format(\App\Models\Ticket::where('status','PAID')->count())}} {{number_format(\App\Models\Invoice::where('status','PAID')->count())}}
</h2> </h2>
</a> </a>
</div> </div>
@ -73,7 +89,7 @@
<a href="{{route('admin.ticket.index')}}"> <a href="{{route('admin.ticket.index')}}">
<i class="ri-customer-service-2-line"></i> <i class="ri-customer-service-2-line"></i>
<h2> <h2>
{{number_format(\App\Models\Invoice::where('status','PENDING')->count())}} {{number_format(\App\Models\Ticket::where('status','PENDING')->count())}}
</h2> </h2>
</a> </a>
</div> </div>
@ -83,17 +99,40 @@
<div class="row"> <div class="row">
<div class="col-lg-12 mb-3 p-0" id="visitor-container"> <div class="col-lg-12 mb-3 p-0" id="visitor-container">
<div class="card"> <div class="card skewed-container">
<i class="ri-bar-chart-box-line skewed-icon"></i>
<div class="card-header"> <div class="card-header">
{{__("last month visits")}} {{__("last month visits")}}
</div> </div>
<div class="card-body"> <div class="card-body">
<canvas id="visitor-chart" height="300"></canvas> <canvas id="visitor-chart"></canvas>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-4 p-0 pe-lg-2 mb-3">
<div class="card skewed-container h-100">
<i class="ri-computer-line skewed-icon"></i>
<div class="card-header">
{{__("Last month visitors devices")}}
</div>
<div class="card-body">
<canvas id="visitor-device"></canvas>
</div>
</div>
</div>
<div class="col-lg-8 p-0 ps-lg-2 mb-3">
<div class="card skewed-container h-100">
<i class="ri-shopping-bag-3-line skewed-icon"></i>
<div class="card-header">
{{__("Last week orders")}}
</div>
<div class="card-body">
<canvas id="orders-chart"></canvas>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@endsection @endsection
@ -102,6 +141,11 @@
<script> <script>
window.addEventListener('resize', function () {
// window.vchart.resize(1,1);
window.vchart.resize(null, 300);
});
window.addEventListener('load', function () { window.addEventListener('load', function () {
if (isPaintedChart) { if (isPaintedChart) {
@ -110,10 +154,10 @@
isPaintedChart = true; isPaintedChart = true;
let ctx = document.getElementById('visitor-chart').getContext('2d');
let visits = @json($visits); let visits = @json($visits);
document.getElementById('visitor-chart').setAttribute('width', document.querySelector('#visitor-container').clientWidth - 45); let ctx = document.getElementById('visitor-chart').getContext('2d');
let chart = new window.chartjs(ctx, { // document.getElementById('visitor-chart').setAttribute('width', document.querySelector('#visitor-container').clientWidth - 45);
window.vchart = new window.chartjs(ctx, {
// The type of chart we want to create // The type of chart we want to create
type: 'line', // also try bar or other graph types type: 'line', // also try bar or other graph types
@ -141,6 +185,9 @@
// Configuration options // Configuration options
options: { options: {
maintainAspectRatio: false,
resizeDelay: 1000,
// aspectRatio: 6,
layout: { layout: {
padding: 10, padding: 10,
}, },
@ -149,10 +196,52 @@
}, },
title: { title: {
display: true, display: true,
text: 'Precipitation in Toronto' text: 'Website visits traffic'
} }
} }
}); });
let ctx2 = document.getElementById('visitor-device').getContext('2d');
// document.getElementById('visitor-chart').setAttribute('width', document.querySelector('#visitor-container').clientWidth - 45);
window.dchart = new window.chartjs(ctx2, {
// The type of chart we want to create
type: 'pie', // also try bar or other graph types
// The data for our dataset
data: {
labels: ['All visitors','Desktop', 'Mobile / Tablet',],
datasets: [
{
label:"{{__('Devices')}}",
data: [{{$all_visitor}},{{$all_visitor - $mobiles_count}}, {{$mobiles_count}}],
backgroundColor: ['rgba(255,128,0,0.69)', 'rgba(255,0,54,0.56)','rgba(0,202,202,0.56)'],
hoverBackgroundColor: ['rgba(255,128,0,0.9)', 'rgba(255,0,54,0.9)','rgba(0,202,202,0.9)'],
borderWidth: 1,
borderColor: '#00000011'
}
]
},
// Configuration options
options: {
maintainAspectRatio: false,
resizeDelay: 1000,
// aspectRatio: 6,
layout: {
padding: 10
},
legend: {
position: 'bottom',
},
title: {
display: true,
text: 'Visitor device'
}
}
});
window.dispatchEvent(new Event('resize'));
}); });
</script> </script>

Loading…
Cancel
Save