old-hotel-new/app/Admin/Controllers/HomeController.php

300 lines
10 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace App\Admin\Controllers;
use Illuminate\Http\JsonResponse;
use Slowlyo\OwlAdmin\Renderers\Card;
use Slowlyo\OwlAdmin\Renderers\Flex;
use Slowlyo\OwlAdmin\Renderers\Html;
use Slowlyo\OwlAdmin\Renderers\Grid;
use Slowlyo\OwlAdmin\Renderers\Chart;
use Slowlyo\OwlAdmin\Renderers\Image;
use Slowlyo\OwlAdmin\Renderers\Action;
use Slowlyo\OwlAdmin\Renderers\Custom;
use Slowlyo\OwlAdmin\Renderers\Wrapper;
use Illuminate\Http\Resources\Json\JsonResource;
use Slowlyo\OwlAdmin\Controllers\AdminController;
use App\Admin\Components;
use App\Models\Oldmen;
use App\Models\ConstFlow;
use App\Models\Keyword;
use Carbon\Carbon;
use DB;
class HomeController extends AdminController
{
public function index(): JsonResponse|JsonResource
{
$page = $this->basePage()->css($this->css())->body([
Grid::make()->columns([
$this->frameworkInfo()->md(8),
Flex::make()->items([
$this->clock(),
$this->hitokoto(),
])->direction('column'),
]),
Grid::make()->columns([
$this->lineChart()->md(6),
$this->pieChart()->md(6),
]),
]);
return $this->response()->success($page);
}
/**
* 一言
*/
public function hitokoto()
{
return Card::make()
->className('h-full clear-card-mb')
->body(
Custom::make()->html(<<<HTML
<div class="h-full flex flex-col mt-5 py-6 px-7">
<div>『</div>
<div class="flex flex-1 items-center w-full justify-center" id="hitokoto">
<a class="text-dark" href="#" id="hitokoto_text" target="_blank"></a>
</div>
<div class="flex justify-end">』</div>
</div>
<div class="flex justify-end mt-3">
——&nbsp;
<span id="hitokoto_from_who"></span>
<span>「</span>
<span id="hitokoto_from"></span>
<span>」</span>
</div>
HTML
)->onMount(<<<JS
fetch('https://v1.hitokoto.cn?c=i')
.then(response => response.json())
.then(data => {
const hitokoto = document.querySelector('#hitokoto_text')
hitokoto.href = `https://hitokoto.cn/?uuid=\${data.uuid}`
hitokoto.innerText = data.hitokoto
document.querySelector('#hitokoto_from_who').innerText = data.from_who
document.querySelector('#hitokoto_from').innerText = data.from
})
.catch(console.error)
JS
)
);
}
public function clock(): Card
{
return Card::make()->className('h-full bg-blingbling')->header([
'title' => '时钟',
])->body([
Custom::make()
->name('clock')
->html('<div id="clock" class="text-5xl"></div><div id="clock-date" class="mt-5"></div>')
->onMount(<<<JS
const clock = document.getElementById('clock');
const tick = () => {
clock.innerHTML = (new Date()).toLocaleTimeString();
requestAnimationFrame(tick);
};
tick();
const clockDate = document.getElementById('clock-date');
clockDate.innerHTML = (new Date()).toLocaleDateString();
JS
),
]);
}
public function frameworkInfo(): Card
{
return Card::make()->className('h-96')->body(
Wrapper::make()->className('h-full')->body([
Flex::make()->className('h-full')->direction('column')->justify('center')->items([
Image::make()->src(url(config('admin.logo'))),
Wrapper::make()->className('text-3xl mt-9')->body(config('admin.name')),
Flex::make()->className('w-64 mt-5')->justify('space-around')->items([
Action::make()
->level('link')
->label('客人入住')
->actionType('url')
->link('live-in-do'),
Action::make()
->level('link')
->label('客人续住')
->actionType('url')
->link('live-continue-do'),
Action::make()
->level('link')
->label('退住结算')
->actionType('url')
->link('live-exit-do'),
]),
]),
])
);
}
public function pieChart(): Card
{
$lvList = Keyword::getByParentKey('nurse_lv')->pluck('name', 'value');
$listData = Oldmen::select(DB::raw('`nurse_lv`, count(`id`) as num'))->where('live_in', Oldmen::STATUS_LIVE)->groupBy('nurse_lv')->get()->keyBy('nurse_lv')->toArray();
$data = [];
foreach($lvList as $lv=>$name){
$data[] = [
"name"=>$name, "value"=>$listData[$lv]['num'] ?? 0
];
}
return Card::make()->className('h-96')->body(
Chart::make()->height(350)->config(Components::make()->chartPieConfig('当前护理占比', $data))
);
}
public function lineChart(): Card
{
$endDay = now()->format('Y-m-d');
$startDay = now()->subDays(7)->format('Y-m-d');
$data = [];
list($day, $diffDays, $xKeys) = $this->makeChartXkeys($startDay, $endDay);
$listData = ConstFlow::select(DB::raw('DATE_FORMAT(`start_at`, "%Y-%m-%d") as ymd, count(`oldman_id`) as num'))
->where('const_type', ConstFlow::TYPE_IN)->whereBetween('start_at', [$startDay.' 00:00:00', $endDay.' 23:59:59'])->groupBy('ymd')->get()->keyBy('ymd')->toArray();
foreach($xKeys as $key){
$data[] = $listData[$key]['num'] ?? 0;
}
$chart = amisMake()->Chart()->config(Components::make()->chartLineBarConfig('入住情况', $xKeys, [
[
'name'=> '入住情况',
'type'=>'line',
'data' => $data,
'color' => '#3491fa',
'unit' => '人'
]
]));
return Card::make()->height(380)->className('h-96')->body($chart);
}
public function cube(): Card
{
return Card::make()->className('h-96 ml-4 w-8/12')->body(
Html::make()->html(<<<HTML
<style>
.cube-box{ height: 300px; display: flex; align-items: center; justify-content: center; }
.cube { width: 100px; height: 100px; position: relative; transform-style: preserve-3d; animation: rotate 10s linear infinite; }
.cube:after {
content: '';
width: 100%;
height: 100%;
box-shadow: 0 0 50px rgba(0, 0, 0, 0.2);
position: absolute;
transform-origin: bottom;
transform-style: preserve-3d;
transform: rotateX(90deg) translateY(50px) translateZ(-50px);
background-color: rgba(0, 0, 0, 0.1);
}
.cube div {
background-color: rgba(64, 158, 255, 0.7);
position: absolute;
width: 100%;
height: 100%;
border: 1px solid rgb(27, 99, 170);
box-shadow: 0 0 60px rgba(64, 158, 255, 0.7);
}
.cube div:nth-child(1) { transform: translateZ(-50px); animation: shade 10s -5s linear infinite; }
.cube div:nth-child(2) { transform: translateZ(50px) rotateY(180deg); animation: shade 10s linear infinite; }
.cube div:nth-child(3) { transform-origin: right; transform: translateZ(50px) rotateY(270deg); animation: shade 10s -2.5s linear infinite; }
.cube div:nth-child(4) { transform-origin: left; transform: translateZ(50px) rotateY(90deg); animation: shade 10s -7.5s linear infinite; }
.cube div:nth-child(5) { transform-origin: bottom; transform: translateZ(50px) rotateX(90deg); background-color: rgba(0, 0, 0, 0.7); }
.cube div:nth-child(6) { transform-origin: top; transform: translateZ(50px) rotateX(270deg); }
@keyframes rotate {
0% { transform: rotateX(-15deg) rotateY(0deg); }
100% { transform: rotateX(-15deg) rotateY(360deg); }
}
@keyframes shade { 50% { background-color: rgba(0, 0, 0, 0.7); } }
</style>
<div class="cube-box">
<div class="cube">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
HTML
)
);
}
private function css(): array
{
return [
'.clear-card-mb' => [
'margin-bottom' => '0 !important',
],
'.cxd-Image' => [
'border' => '0',
],
'.bg-blingbling' => [
'color' => '#fff',
'background' => 'linear-gradient(to bottom right, #2C3E50, #FD746C, #FF8235, #ffff1c, #92FE9D, #00C9FF, #a044ff, #e73827)',
'background-repeat' => 'no-repeat',
'background-size' => '1000% 1000%',
'animation' => 'gradient 60s ease infinite',
],
'@keyframes gradient' => [
'0%{background-position:0% 0%}
50%{background-position:100% 100%}
100%{background-position:0% 0%}',
],
'.bg-blingbling .cxd-Card-title' => [
'color' => '#fff',
],
];
}
/**
* 根据时间处理X轴横坐标
*/
private function makeChartXkeys($startTime = null, $endTime = null){
$diffDays = 0;
$day = date('Y-m-d');
$xKeys = [];
if($startTime && $endTime){
if($startTime == $endTime){//查询某一天
$day = $startTime;
}else{
$startDay = Carbon::parse($startTime);
$endDay = Carbon::parse($endTime);
$diffDays = $startDay->diffInDays($endDay, false);
}
}
$xKeys = [];
if($diffDays){
for ($i = 0; $i<=$diffDays; $i++) {
$xKeys[] =(clone $startDay)->addDays($i)->startOfDay()->format('Y-m-d');
}
}else{
//调整截至到当前小时
$h = 23;
if($day == date('Y-m-d')){
$h = date('H');
}
for ($i = 0; $i < ($h+1); $i++) {
$xKeys[] = str_pad($i, 2, '0', STR_PAD_LEFT).':00';
}
}
return array($day, $diffDays, $xKeys);
}
}