490 lines
24 KiB
PHP
490 lines
24 KiB
PHP
<?php
|
||
|
||
namespace App\Admin\Controllers;
|
||
|
||
use Slowlyo\OwlAdmin\Renderers\{Button, Form, Page, TableColumn, TextControl, Json, Component, CRUDTable, Card, Video, InputDatetimeRange, DateTimeControl, Mapping, SelectControl};
|
||
use Slowlyo\OwlAdmin\Controllers\AdminController;
|
||
use App\Services\Admin\DeviceService;
|
||
use App\Admin\Components;
|
||
use App\Models\Device;
|
||
use App\Models\Keyword;
|
||
use App\Models\MonitorMode;
|
||
use App\Models\RegionMonitor;
|
||
use App\Models\Region;
|
||
use Illuminate\Http\Request;
|
||
use App\Services\MqttService;
|
||
|
||
class DeviceController extends AdminController
|
||
{
|
||
protected string $serviceName = DeviceService::class;
|
||
|
||
protected string $pageTitle = '设备管理';
|
||
|
||
public function options(){
|
||
$list = $this->service->listQuery()->select(['id as value', 'name as label'])->get();
|
||
|
||
return $this->response()->success($list);
|
||
}
|
||
|
||
public function list(): Page
|
||
{
|
||
$crud = $this->baseCRUD()
|
||
->filterTogglable(false)
|
||
->headerToolbar([
|
||
$this->createButton(true, 'lg'),
|
||
...$this->baseHeaderToolBar(),
|
||
])
|
||
->filter($this->baseFilter()->actions([])->body([
|
||
TextControl::make()->name('name')->label('名称')->size('md'),
|
||
amisMake()->SelectControl()->name('factory')->label('厂家')->options(Keyword::getByParentKey('device-factory')->pluck('name', 'id')->toArray())->size('md'),
|
||
amisMake()->SelectControl()->name('type')->label('类型')->options(Device::typeMap())->size('md'),
|
||
Button::make()->label(__('admin.reset'))->actionType('clear-and-submit'),
|
||
amis('submit')->label(__('admin.search'))->level('primary'),
|
||
]))
|
||
->columns([
|
||
TableColumn::make()->name('id')->label('ID')->sortable(true),
|
||
TableColumn::make()->name('name')->label('名称'),
|
||
TableColumn::make()->name('factory.name')->label('厂家'),
|
||
TableColumn::make()->name('sn')->label('编号'),
|
||
TableColumn::make()->name('type')->type('mapping')->map(Device::typeMap())->label('类型'),
|
||
TableColumn::make()->name('created_at')->label('创建时间')->type('datetime')->sortable(true),
|
||
TableColumn::make()->name('updated_at')->label('更新时间')->type('datetime')->sortable(true),
|
||
$this->rowActions(true, 'lg'),
|
||
])->debug(true);
|
||
|
||
return $this->baseList($crud);
|
||
}
|
||
|
||
public function form(): Form
|
||
{
|
||
return $this->baseForm()->body([
|
||
TextControl::make()->name('name')->label('名称')->required(true),
|
||
TextControl::make()->name('sn')->label('设备编号')->required(true),
|
||
\amisMake()->SelectControl()->name('powered_by')->label('厂家')->options(Keyword::getByParentKey('device-factory')->pluck('name', 'id')->toArray())->required(true),
|
||
TextControl::make()->name('model_sn')->label('型号'),
|
||
\amisMake()->RadiosControl()->name('type')->label('类型')->options(Device::typeMap())->required(true),
|
||
// 监控设备-额外参数
|
||
// rtsp://admin:lcdx12345@172.16.40.2:554/Streaming/Channels/5201
|
||
TextControl::make()->name('extends.rtsp_url')->hiddenOn('data.type != '.Device::TYPE_MONITOR)->label(__('device.rtsp_url')),
|
||
// rtsp://admin:lcdx12345@172.16.40.2:554/Streaming/tracks/5201
|
||
TextControl::make()->name('extends.rtsp_history')->hiddenOn('data.type != '.Device::TYPE_MONITOR)->label(__('device.rtsp_history')),
|
||
]);
|
||
}
|
||
|
||
public function detail(): Form
|
||
{
|
||
return $this->baseDetail()->body([
|
||
TextControl::make()->static(true)->name('id')->label('ID'),
|
||
TextControl::make()->static(true)->name('name')->label('名称'),
|
||
TextControl::make()->static(true)->name('sn')->label('编号'),
|
||
TextControl::make()->static(true)->name('factory.name')->label('厂家'),
|
||
TextControl::make()->static(true)->name('model_sn')->label('型号'),
|
||
TextControl::make()->static(true)->name('type')->label('类型')->staticSchema(
|
||
Mapping::make()->map(Device::typeMap())),
|
||
TextControl::make()->static(true)->name('extends')->label('扩展信息')->staticSchema(
|
||
Json::make()),
|
||
TextControl::make()->static(true)->name('created_at')->label('创建时间'),
|
||
TextControl::make()->static(true)->name('updated_at')->label('更新时间')
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 监控设备列表
|
||
*/
|
||
public function monitorList()
|
||
{
|
||
if ($this->actionOfGetData()) {
|
||
return $this->response()->success($this->service->list());
|
||
}
|
||
$regionId = request()->input('region_id', 0);
|
||
if($regionId){
|
||
$region = Region::find($regionId);
|
||
$query = $region->monitorModes()->where('type', MonitorMode::TYPE_MONITOR)->pluck('name','monitor_id');
|
||
}else{
|
||
$query = MonitorMode::where('type', MonitorMode::TYPE_MONITOR)->pluck('name','id');
|
||
}
|
||
return CRUDTable::make()
|
||
->mode('cards')
|
||
->hideCheckToggler()
|
||
->columnsCount(3)
|
||
->perPage(6)
|
||
->affixHeader(false)
|
||
->filterTogglable(true)
|
||
->set('primaryField', $this->service->primaryKey())
|
||
->api(admin_url($this->queryPath . '?_action=getData&_type=' . Device::TYPE_MONITOR))
|
||
->footerToolbar(['statistics', 'pagination'])
|
||
->headerToolbar([])
|
||
->filter($this->baseFilter()->actions([])->body([
|
||
amisMake()->SelectControl('monitor_mode', '点位名称')->size('md')->options($query->toArray())->selectFirst(true),
|
||
Button::make()->label(__('admin.reset'))->actionType('clear-and-submit'),
|
||
Component::make()->setType('submit')->label(__('admin.search'))->level('primary'),
|
||
]))
|
||
->actions([])
|
||
->itemClassName('col-sm-4')
|
||
->card(Card::make()->header(['title' => '$name'])->body(Video::make()->videoType('video/x-flv')->muted(true)->autoPlay(true)->src('${src}')));
|
||
}
|
||
|
||
/**
|
||
* 监控历史视频
|
||
*/
|
||
public function monitorVideoList()
|
||
{
|
||
if ($this->actionOfGetData()) {
|
||
return $this->response()->success($this->service->list());
|
||
}
|
||
$regionId = request()->input('region_id', 0);
|
||
if($regionId){
|
||
$region = Region::find($regionId);
|
||
$query = $region->monitorModes()->where('type', MonitorMode::TYPE_MONITOR)->pluck('name','monitor_id');
|
||
}else{
|
||
$query = MonitorMode::where('type', MonitorMode::TYPE_MONITOR)->pluck('name','id');
|
||
}
|
||
return CRUDTable::make()
|
||
->mode('cards')
|
||
->hideCheckToggler()
|
||
->columnsCount(3)
|
||
->perPage(6)
|
||
->affixHeader(false)
|
||
->filterTogglable(true)
|
||
->set('primaryField', $this->service->primaryKey())
|
||
->api(admin_url($this->queryPath . '?_action=getData&_type=' . Device::TYPE_MONITOR . '&_mode=history'))
|
||
->footerToolbar(['statistics', 'pagination'])
|
||
->headerToolbar([])
|
||
->filter($this->baseFilter()->actions([])->body([
|
||
amisMake()->SelectControl('monitor_mode', '点位名称')->size('md')->options($query->toArray())->selectFirst(true),
|
||
InputDatetimeRange::make()->name('date')->label('日期')->maxDate('now')->size('md'),
|
||
Button::make()->label(__('admin.reset'))->actionType('clear-and-submit'),
|
||
Component::make()->setType('submit')->label(__('admin.search'))->level('primary'),
|
||
]))
|
||
->actions([])
|
||
->itemClassName('col-sm-4')
|
||
->card(Card::make()->header(['title' => '$name'])->body(Video::make()->videoType('video/x-flv')->muted(true)->autoPlay(true)->src('${src}')));
|
||
}
|
||
|
||
/**
|
||
* 气象图表
|
||
*/
|
||
public function meteorologicalChart(){
|
||
$regionId = request()->input('region_id', 0);
|
||
if($regionId){
|
||
$region = Region::find($regionId);
|
||
$options = $region->monitorModes()->where('type', MonitorMode::TYPE_METEOROLOGICAL)->pluck('name','monitor_id')->toArray();
|
||
}else{
|
||
$options = MonitorMode::where('type', MonitorMode::TYPE_METEOROLOGICAL)->pluck('name','id')->toArray();
|
||
}
|
||
|
||
return $this->basePage()->title('')->body([
|
||
\amisMake()->grid()->columns([
|
||
\amisMake()->Form()->title('搜索条件')->mode('inline')->body([
|
||
amisMake()->SelectControl('monitor_mode', '监测点位')->size('md')->options($options)->selectFirst(true)->required(),
|
||
\amisMake()->DateRangeControl('date_range', '时间范围')->clearable(false)->value('today,today')->required(),
|
||
amis('submit')->label(__('admin.search'))->level('primary'),
|
||
])->target('meteorological_chart'),
|
||
]),
|
||
amisMake()->Service()->name('meteorological_chart')
|
||
->data([
|
||
'monitor_mode'=>array_key_first($options),
|
||
'date_range'=>mktime(0,0,0,date('m'),date('d'),date('Y')).','.mktime(0,0,0,date('m'),date('d'),date('Y'))
|
||
])->schemaApi(
|
||
admin_url('device-chart?monitor_mode=${monitor_mode}&date_range=${date_range}')
|
||
),
|
||
]);
|
||
}
|
||
|
||
public function deviceChart(Request $request)
|
||
{
|
||
$dateRange = $request->input('date_range');
|
||
if (!$dateRange) {
|
||
$startTime = now()->startOfDay()->timestamp;
|
||
$endTime = now()->endOfDay()->timestamp;
|
||
} else {
|
||
list($startTime, $endTime) = explode(',', $dateRange);
|
||
}
|
||
$startTime = date('Y-m-d', $startTime);
|
||
$endTime = date('Y-m-d', $endTime);
|
||
|
||
$monitorMode = $request->monitor_mode ?? 0;
|
||
$monitorMode = MonitorMode::find($monitorMode);
|
||
|
||
$data = $monitorMode ? $this->service->getMonitorModeDeviceChartConfig($monitorMode, $startTime.' 00:00:00', $endTime.' 23:59:59', 2):[];
|
||
|
||
return $this->response()->success($data);
|
||
}
|
||
|
||
/**
|
||
* 水质图表
|
||
*/
|
||
public function waterChart(){
|
||
$regionId = request()->input('region_id', 0);
|
||
if($regionId){
|
||
$region = Region::find($regionId);
|
||
$options = $region->monitorModes()->where('type', MonitorMode::TYPE_WATER_QUALITY)->pluck('name','monitor_id')->toArray();
|
||
}else{
|
||
$options = MonitorMode::where('type', MonitorMode::TYPE_WATER_QUALITY)->pluck('name','id')->toArray();
|
||
}
|
||
|
||
return $this->basePage()->title('')->body([
|
||
\amisMake()->grid()->columns([
|
||
\amisMake()->Form()->title('搜索条件')->mode('inline')->body([
|
||
amisMake()->SelectControl('monitor_mode', '监测点位')->size('md')->options($options)->selectFirst(true),
|
||
\amisMake()->DateRangeControl('date_range', '时间范围')->value('today,today'),
|
||
amis('submit')->label(__('admin.search'))->level('primary'),
|
||
])->target('water_chart'),
|
||
]),
|
||
amisMake()->Service()->name('water_chart')
|
||
->data([
|
||
'monitor_mode'=>array_key_first($options),
|
||
'date_range'=>mktime(0,0,0,date('m'),date('d'),date('Y')).','.mktime(0,0,0,date('m'),date('d'),date('Y'))
|
||
])->schemaApi(
|
||
admin_url('device-chart?monitor_mode=${monitor_mode}&date_range=${date_range}')
|
||
),
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 土壤图表
|
||
*/
|
||
public function soilChart(){
|
||
$regionId = request()->input('region_id', 0);
|
||
if($regionId){
|
||
$region = Region::find($regionId);
|
||
$options = $region->monitorModes()->where('type', MonitorMode::TYPE_SOIL)->pluck('name','monitor_id')->toArray();
|
||
}else{
|
||
$options = MonitorMode::where('type', MonitorMode::TYPE_SOIL)->pluck('name','id')->toArray();
|
||
}
|
||
|
||
return $this->basePage()->title('')->body([
|
||
\amisMake()->grid()->columns([
|
||
\amisMake()->Form()->title('搜索条件')->mode('inline')->body([
|
||
amisMake()->SelectControl('monitor_mode', '监测点位')->size('md')->options($options)->selectFirst(true),
|
||
\amisMake()->DateRangeControl('date_range', '时间范围')->value('today,today'),
|
||
amis('submit')->label(__('admin.search'))->level('primary'),
|
||
])->target('soil_chart'),
|
||
]),
|
||
amisMake()->Service()->name('soil_chart')
|
||
->data([
|
||
'monitor_mode'=>array_key_first($options),
|
||
'date_range'=>mktime(0,0,0,date('m'),date('d'),date('Y')).','.mktime(0,0,0,date('m'),date('d'),date('Y'))
|
||
])->schemaApi(
|
||
admin_url('device-chart?monitor_mode=${monitor_mode}&date_range=${date_range}')
|
||
),
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 空气条件设置
|
||
*/
|
||
public function airDetail(){
|
||
$regionId = request()->input('region_id', 0);
|
||
$config = null;
|
||
$device = null;
|
||
if($regionId){
|
||
$region = Region::find($regionId);
|
||
if($region){
|
||
$monitorMode = $region->monitorModes()->where('type', MonitorMode::TYPE_AIR)->first();
|
||
$device = $monitorMode->devices()->first();
|
||
$config = $device?->extends ?? null;
|
||
}
|
||
}
|
||
return amisMake()->Grid()->columns([
|
||
amisMake()->Wrapper()->sm(6)->body([
|
||
amisMake()->Panel()->title('智能开关设置')
|
||
->labelWidth(100)
|
||
->body([
|
||
\amisMake()->Form()->title('')->mode('horizontal')
|
||
->api([
|
||
'method'=>'post',
|
||
'url'=>admin_url('save-region-config').'/'.$regionId.'?type='.MonitorMode::TYPE_AIR,
|
||
'data'=>[
|
||
'open_is_enable' => '${open_is_enable}',
|
||
'open_config' => '${open_config}',
|
||
'close_is_enable' => '${close_is_enable}',
|
||
'close_config' => '${close_config}',
|
||
]
|
||
])
|
||
->data($config ? $config : [])
|
||
->body([
|
||
amisMake()->FieldSetControl()->title('智能开启')->body([
|
||
\amisMake()->SwitchControl()->name('open_is_enable')->label('开关'),
|
||
\amisMake()->ConditionBuilderControl()->name('open_config')->label('条件')->fields([
|
||
[
|
||
'label' => '温度', 'type'=>'number','step'=>'0.01','name'=>'box_temperature',
|
||
'operators'=> [
|
||
'less', 'less_or_equal', 'greater', 'greater_or_equal'
|
||
// 'is_empty', 'is_not_empty'
|
||
]
|
||
],
|
||
[
|
||
'label' => '湿度', 'type'=>'number','step'=>'0.01','name'=>'box_humidity',
|
||
'operators'=> [
|
||
'less', 'less_or_equal', 'greater', 'greater_or_equal'
|
||
// 'is_empty', 'is_not_empty'
|
||
]
|
||
],
|
||
]),
|
||
]),
|
||
amisMake()->FieldSetControl()->title('智能关闭')->body([
|
||
\amisMake()->SwitchControl()->name('close_is_enable')->label('开关'),
|
||
\amisMake()->ConditionBuilderControl()->name('close_config')->label('条件')->fields([
|
||
[
|
||
'label' => '温度', 'type'=>'number','step'=>'0.01','name'=>'box_temperature',
|
||
'operators'=> [
|
||
'less', 'less_or_equal', 'greater', 'greater_or_equal',
|
||
// 'is_empty', 'is_not_empty'
|
||
]
|
||
],
|
||
[
|
||
'label' => '湿度', 'type'=>'number','step'=>'0.01','name'=>'box_humidity',
|
||
'operators'=> [
|
||
'less', 'less_or_equal', 'greater', 'greater_or_equal'
|
||
// 'is_empty', 'is_not_empty'
|
||
]
|
||
],
|
||
]),
|
||
]),
|
||
]),
|
||
])
|
||
]),
|
||
amisMake()->Wrapper()->sm(6)->body([
|
||
amisMake()->Panel()->title('开关记录')
|
||
->body([
|
||
\amisMake()->CRUDTable()
|
||
->api(admin_url('air-logs').'?_action=getData&device_id='.($device?->id ?? 0))
|
||
->title('')
|
||
->columns([
|
||
amisMake()->TableColumn()->name('content')->label('触发条件'),
|
||
amisMake()->TableColumn()->name('type')->type('mapping')->map([
|
||
"0"=>"<span class='label label-info'>未知</span>",
|
||
"1"=>"<span class='label label-success'>开启</span>",
|
||
"2"=>"<span class='label label-danger'>关闭</span>",
|
||
"*"=> '其他:${type}'
|
||
])->label('动作'),
|
||
amisMake()->TableColumn()->name('created_at')->type('datetime')->label('执行时间'),
|
||
])
|
||
])
|
||
]),
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 喷雾
|
||
*/
|
||
public function atomizingDetail(){
|
||
$regionId = request()->input('region_id', 0);
|
||
$config = null;
|
||
$statusStr = '未知';
|
||
$device = null;
|
||
if($regionId){
|
||
$region = Region::find($regionId);
|
||
if($region){
|
||
$monitorMode = $region->monitorModes()->where('type', MonitorMode::TYPE_ATOMIZING)->first();
|
||
$device = $monitorMode->devices()->first();
|
||
$config = $device?->extends ?? null;
|
||
|
||
if($monitorMode){
|
||
//判断设备状态是否离线;
|
||
$device = $monitorMode->devices()->first();
|
||
if($device->state == Device::STATE_ONLINE){
|
||
$res = (new MqttService())->getStatus();
|
||
if($res['error']){
|
||
switch($res['error']){
|
||
case 1:
|
||
$statusStr = '急停';
|
||
break;
|
||
case 2:
|
||
$statusStr = '低水位报警';
|
||
break;
|
||
}
|
||
}else{
|
||
if($res['is_running']){
|
||
if($res['yv1']){
|
||
$statusStr = '区域A运行中,喷雾量:'.$res['speed1'].'%';
|
||
}elseif(['yv2']){
|
||
$statusStr = '区域B运行中,喷雾量:'.$res['speed2'].'%';
|
||
}
|
||
}else{
|
||
$statusStr = '未运行';
|
||
}
|
||
}
|
||
}else{
|
||
$statusStr = Device::stateMap()[$device->state];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return amisMake()->Grid()->columns([
|
||
amisMake()->Wrapper()->sm(6)->body([
|
||
amisMake()->Panel()->title('智能喷灌设置')
|
||
->subFormMode('horizontal')
|
||
->labelWidth(80)
|
||
->body([
|
||
\amisMake()->Form()->title('')->mode('horizontal')
|
||
->api([
|
||
'method'=>'post',
|
||
'url'=>admin_url('save-region-config').'/'.$regionId.'?type='.MonitorMode::TYPE_ATOMIZING,
|
||
'data'=>[
|
||
'is_enable' => '${is_enable}',
|
||
'config' => '${config}'
|
||
]
|
||
])
|
||
->data($config ? $config : [])
|
||
->body([
|
||
amisMake()->FieldSetControl()->title('当前状态')->body([
|
||
amisMake()->TextControl('status', '状态')->value($statusStr),
|
||
])->static(),
|
||
amisMake()->FieldSetControl()->className('mt-10')->title('定时喷灌')->body([
|
||
\amisMake()->SwitchControl()->name('is_enable')->label('开关'),
|
||
\amisMake()->ArrayControl()->name('config')->label('定时')->items([
|
||
amisMake()->ComboControl()->items([
|
||
amisMake()->SelectControl('value')->options([
|
||
'a'=>'区域A','b'=>'区域B'
|
||
]),
|
||
\amisMake()->InputTimeRange()->name('time_zone'),
|
||
Components::make()->decimalControl('input', '喷雾量%')->value(70)->percision(0)->step(1)->max(100)
|
||
]),
|
||
]),
|
||
]),
|
||
]),
|
||
])
|
||
]),
|
||
amisMake()->Wrapper()->sm(6)->body([
|
||
amisMake()->Panel()->title('开关记录')
|
||
->body([
|
||
\amisMake()->CRUDTable()
|
||
->api(admin_url('atomizing-logs').'?_action=getData&device_id='.($device?->id ?? 0))
|
||
->title('')
|
||
->columns([
|
||
amisMake()->TableColumn()->name('type')->type('mapping')->map([
|
||
"0"=>"<span class='label label-info'>未知</span>",
|
||
"1"=>"<span class='label label-success'>开启</span>",
|
||
"2"=>"<span class='label label-danger'>关闭</span>",
|
||
"*"=> '其他:${type}'
|
||
])->label('动作'),
|
||
amisMake()->TableColumn()->name('content')->label('描述内容'),
|
||
amisMake()->TableColumn()->name('created_at')->type('datetime')->label('操作时间'),
|
||
])
|
||
])
|
||
]),
|
||
]);
|
||
}
|
||
|
||
public function saveRegionConfig($id, Request $request)
|
||
{
|
||
if($id){
|
||
$region = Region::find($id);
|
||
if($region){
|
||
$type = $request->input('type', 0);
|
||
$monitorMode = $region->monitorModes()->where('type', $type)->first();
|
||
$config = $request->input() ?? null;
|
||
unset($config['type']);
|
||
$res = $monitorMode->devices()->update([
|
||
'extends' => $config,
|
||
]);
|
||
}
|
||
}
|
||
|
||
return $this->autoResponse($res, __('admin.save'));
|
||
}
|
||
}
|