Merge branch 'develop' of gitea.hmily.club:liutk/internet-everythings-agricultural into develop
commit
2660bd86bc
|
|
@ -86,6 +86,10 @@ class Components extends BaseRenderer {
|
|||
->options(Keyword::getByParentKey($typeKey)->pluck('name', 'id')->toArray());
|
||||
}
|
||||
|
||||
public function keywordsTag($label = '标签'){
|
||||
return amisMake()->Tag()->label($label)->displayMode('rounded')->color('inactive');
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成统计图config
|
||||
* 折线图或者柱状图
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ class CustomRegionController extends AdminController
|
|||
}
|
||||
|
||||
private function regionList($categoryId){
|
||||
$regionList = Region::with('devices')->where('category_id', $categoryId)->get();
|
||||
$regionList = Region::with('monitorModes')->where('category_id', $categoryId)->get();
|
||||
$resList = [];
|
||||
foreach($regionList as $region){
|
||||
$tabs = Region::regionTabConfig($region);
|
||||
|
|
|
|||
|
|
@ -2,12 +2,13 @@
|
|||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use Slowlyo\OwlAdmin\Renderers\{Button, Form, Page, TableColumn, TextControl, Component, CRUDTable, Card, Video, DateRangeControl};
|
||||
use Slowlyo\OwlAdmin\Renderers\{Button, Form, Page, TableColumn, TextControl, Json, Component, CRUDTable, Card, Video, DateRangeControl, Mapping, SelectControl};
|
||||
use Slowlyo\OwlAdmin\Controllers\AdminController;
|
||||
use App\Services\Admin\DeviceService;
|
||||
use App\Models\Device;
|
||||
use App\Models\Keyword;
|
||||
use App\Admin\Components;
|
||||
use App\Models\MonitorMode;
|
||||
use App\Models\Region;
|
||||
|
||||
class DeviceController extends AdminController
|
||||
{
|
||||
|
|
@ -33,24 +34,19 @@ class DeviceController extends AdminController
|
|||
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'),
|
||||
Components::make()->keywordsTagControl('group_tags', '分组', 'device-group')->size('md'),
|
||||
Button::make()->label(__('admin.reset'))->actionType('clear-and-submit'),
|
||||
amis('submit')->label(__('admin.search'))->level('primary'),
|
||||
]))
|
||||
->quickSaveItemApi(admin_url('quick-edit/devices/$id'))
|
||||
->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('is_enable')->type('switch')->label('显示')->quickEdit(Components::make()->enableControl('is_enable', '', 'inline')->saveImmediately(true)),
|
||||
TableColumn::make()->name('is_recommend')->type('switch')->label('推荐')->quickEdit(Components::make()->enableControl('is_recommend', '', 'inline')->saveImmediately(true)),
|
||||
TableColumn::make()->name('sort')->label(__('admin.order'))->align('center')->quickEdit(Components::make()->sortControl('sort', __('admin.order'))->saveImmediately(true)),
|
||||
TableColumn::make()->name('created_at')->label('创建时间')->type('datetime')->sortable(true),
|
||||
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);
|
||||
}
|
||||
|
|
@ -59,7 +55,7 @@ class DeviceController extends AdminController
|
|||
{
|
||||
return $this->baseForm()->body([
|
||||
TextControl::make()->name('name')->label('名称')->required(true),
|
||||
TextControl::make()->name('sn')->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),
|
||||
|
|
@ -68,11 +64,6 @@ class DeviceController extends AdminController
|
|||
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')),
|
||||
|
||||
Components::make()->keywordsTagControl('group_tags', '分组', 'device-group'),
|
||||
Components::make()->sortControl('sort', __('admin.order')),
|
||||
TextControl::make()->name('is_enable')->type('switch')->default(1)->label('显示'),
|
||||
TextControl::make()->name('is_recommend')->type('switch')->default(0)->label('推荐'),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -82,6 +73,12 @@ class DeviceController extends AdminController
|
|||
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('更新时间')
|
||||
]);
|
||||
|
|
@ -95,6 +92,13 @@ class DeviceController extends AdminController
|
|||
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()
|
||||
|
|
@ -107,7 +111,7 @@ class DeviceController extends AdminController
|
|||
->footerToolbar(['statistics', 'pagination'])
|
||||
->headerToolbar([])
|
||||
->filter($this->baseFilter()->actions([])->body([
|
||||
TextControl::make()->name('name')->label('点位名称')->size('md'),
|
||||
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'),
|
||||
]))
|
||||
|
|
|
|||
|
|
@ -0,0 +1,216 @@
|
|||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use Slowlyo\OwlAdmin\Renderers\Page;
|
||||
use Slowlyo\OwlAdmin\Renderers\Form;
|
||||
use Slowlyo\OwlAdmin\Renderers\TableColumn;
|
||||
use Slowlyo\OwlAdmin\Renderers\TextControl;
|
||||
use Slowlyo\OwlAdmin\Controllers\AdminController;
|
||||
use App\Services\Admin\MonitorModeService;
|
||||
use App\Admin\Components;
|
||||
use App\Models\MonitorMode;
|
||||
use App\Models\Device;
|
||||
use App\Models\Keyword;
|
||||
|
||||
/**
|
||||
* @property MonitorModeService $service
|
||||
*/
|
||||
class MonitorModeController extends AdminController
|
||||
{
|
||||
protected string $serviceName = MonitorModeService::class;
|
||||
|
||||
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('type')->label('类型')->options(MonitorMode::typeMap())->size('md'),
|
||||
Components::make()->keywordsTagControl('group_tags', '分组', 'monitor-mode-group')->size('md'),
|
||||
amis('button')->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('type')->type('mapping')->map(MonitorMode::typeMap())->label('类型'),
|
||||
TableColumn::make()->name('tags')->type('mapping')->map(Keyword::tagsMap('monitor-mode-group'))->label('分组'),
|
||||
TableColumn::make()->name('created_at')->label(__('admin.created_at'))->type('datetime')->sortable(true),
|
||||
amisMake()->Operation()->label(__('admin.actions'))->buttons([
|
||||
$this->setAboutDevice(),
|
||||
$this->rowEditButton(true, 'lg'),
|
||||
$this->rowDeleteButton()
|
||||
]),
|
||||
]);
|
||||
|
||||
return $this->baseList($crud);
|
||||
}
|
||||
|
||||
public function form(): Form
|
||||
{
|
||||
return $this->baseForm()->body([
|
||||
TextControl::make()->name('name')->label('名称'),
|
||||
\amisMake()->RadiosControl()->name('type')->label('类型')->options(MonitorMode::typeMap())->required(true)->disabledOn('data.id > 0'),
|
||||
Components::make()->keywordsTagControl('group_tags', '分组', 'monitor-mode-group'),
|
||||
Components::make()->sortControl('sort', __('admin.order')),
|
||||
TextControl::make()->name('is_enable')->type('switch')->default(1)->label('显示'),
|
||||
TextControl::make()->name('is_recommend')->type('switch')->default(0)->label('推荐'),
|
||||
]);
|
||||
}
|
||||
|
||||
private function setAboutDevice(){
|
||||
return amisMake()->DrawerAction()->label('设置监测设备')->icon('fa-solid fa-gear')->level('link')->drawer(
|
||||
amisMake()->Drawer()->title('设置监测设备')->resizable(true)->closeOnOutside(true)->closeOnEsc(true)->body([
|
||||
amisMake()
|
||||
->Form()
|
||||
->api(admin_url('monitor-mode-save-devices'))
|
||||
->initApi($this->getEditGetDataPath())
|
||||
->mode('normal')
|
||||
->data(['id' => '${id}'])
|
||||
->body([
|
||||
amisMake()->RadiosControl()->name('type')->label('类型')->options(MonitorMode::typeMap())->disabled(true),
|
||||
amisMake()->PickerControl('picker_devices', '监控设备')->visibleOn('data.type == '.MonitorMode::TYPE_MONITOR)
|
||||
->valueField('id')
|
||||
->labelField('name')
|
||||
->multiple(true)->joinValues(false)->extractValue(true)
|
||||
->size('lg')
|
||||
->source([
|
||||
'method' => 'get',
|
||||
'url' => admin_url('devices?_action=getData&type='.Device::TYPE_MONITOR),
|
||||
'data' => [
|
||||
'name'=>'${device_name}',
|
||||
]
|
||||
])
|
||||
->pickerSchema(
|
||||
[
|
||||
'mode' => 'table',
|
||||
'name' => 'monitor_list',
|
||||
'headerToolbar' => amisMake()->form()
|
||||
->wrapWithPanel(false)
|
||||
->className('text-right')
|
||||
->target('monitor_list')
|
||||
->mode('inline')
|
||||
->body([
|
||||
amisMake()->TextControl('device_name', '名称')->addOn(
|
||||
amis('submit')->label(__('admin.search'))->level('primary')
|
||||
)
|
||||
]),
|
||||
'columns' => [
|
||||
TableColumn::make()->name('id')->label('ID')->sortable(true),
|
||||
TableColumn::make()->name('name')->label('名称'),
|
||||
TableColumn::make()->name('sn')->label('编号'),
|
||||
TableColumn::make()->name('created_at')->label('创建时间')->type('datetime')->sortable(true),
|
||||
TableColumn::make()->name('updated_at')->label('更新时间')->type('datetime')->sortable(true),
|
||||
]
|
||||
]
|
||||
),
|
||||
amisMake()->ArrayControl('array_devices', '土壤监测')->visibleOn('data.type == '.MonitorMode::TYPE_SOIL)
|
||||
->items(
|
||||
amisMake()->ComboControl()->items([
|
||||
\amisMake()->CheckboxesControl('device_fields', '监测字段')->checkAll(true)->options(MonitorMode::fieldMap(MonitorMode::TYPE_SOIL)),
|
||||
\amisMake()->SelectControl('device_id', '监测设备')->options(Device::where('type', Device::TYPE_SOIL)->get()->pluck('name', 'id')),
|
||||
]),
|
||||
),
|
||||
amisMake()->ArrayControl('array_devices', '水质监测')->visibleOn('data.type == '.MonitorMode::TYPE_WATER_QUALITY)
|
||||
->items(
|
||||
amisMake()->ComboControl()->items([
|
||||
\amisMake()->CheckboxesControl('device_fields', '监测字段')->checkAll(true)->options(MonitorMode::fieldMap(MonitorMode::TYPE_WATER_QUALITY)),
|
||||
\amisMake()->SelectControl('device_id', '监测设备'),
|
||||
]),
|
||||
),
|
||||
amisMake()->ArrayControl('array_devices', '气象监测')->visibleOn('data.type == '.MonitorMode::TYPE_METEOROLOGICAL)
|
||||
->items(
|
||||
amisMake()->ComboControl()->items([
|
||||
\amisMake()->CheckboxesControl('device_fields', '监测字段')->checkAll(true)->options(MonitorMode::fieldMap(MonitorMode::TYPE_METEOROLOGICAL)),
|
||||
\amisMake()->SelectControl('device_id', '监测设备'),
|
||||
]),
|
||||
),
|
||||
amisMake()->PickerControl('picker_devices', '通风设备')->visibleOn('data.type == '.MonitorMode::TYPE_AIR)
|
||||
->valueField('id')
|
||||
->labelField('name')
|
||||
->multiple(true)
|
||||
->size('lg')
|
||||
->source([
|
||||
'method' => 'get',
|
||||
'url' => admin_url('devices?_action=getData&type='.Device::TYPE_AIR),
|
||||
'data' => [
|
||||
'name'=>'${device_name}',
|
||||
]
|
||||
])
|
||||
->pickerSchema(
|
||||
[
|
||||
'mode' => 'table',
|
||||
'name' => 'monitor_list',
|
||||
'headerToolbar' => amisMake()->form()
|
||||
->wrapWithPanel(false)
|
||||
->className('text-right')
|
||||
->target('monitor_list')
|
||||
->mode('inline')
|
||||
->body([
|
||||
amisMake()->TextControl('device_name', '名称')->addOn(
|
||||
amis('submit')->label(__('admin.search'))->level('primary')
|
||||
)
|
||||
]),
|
||||
'columns' => [
|
||||
TableColumn::make()->name('id')->label('ID')->sortable(true),
|
||||
TableColumn::make()->name('name')->label('名称'),
|
||||
TableColumn::make()->name('sn')->label('编号'),
|
||||
TableColumn::make()->name('created_at')->label('创建时间')->type('datetime')->sortable(true),
|
||||
TableColumn::make()->name('updated_at')->label('更新时间')->type('datetime')->sortable(true),
|
||||
]
|
||||
]
|
||||
),
|
||||
amisMake()->PickerControl('picker_devices', '喷雾设备')->visibleOn('data.type == '.MonitorMode::TYPE_ATOMIZING)
|
||||
->valueField('id')
|
||||
->labelField('name')
|
||||
->multiple(true)
|
||||
->size('lg')
|
||||
->source([
|
||||
'method' => 'get',
|
||||
'url' => admin_url('devices?_action=getData&type='.Device::TYPE_ATOMIZING),
|
||||
'data' => [
|
||||
'name'=>'${device_name}',
|
||||
]
|
||||
])
|
||||
->pickerSchema(
|
||||
[
|
||||
'mode' => 'table',
|
||||
'name' => 'monitor_list',
|
||||
'headerToolbar' => amisMake()->form()
|
||||
->wrapWithPanel(false)
|
||||
->className('text-right')
|
||||
->target('monitor_list')
|
||||
->mode('inline')
|
||||
->body([
|
||||
amisMake()->TextControl('device_name', '名称')->addOn(
|
||||
amis('submit')->label(__('admin.search'))->level('primary')
|
||||
)
|
||||
]),
|
||||
'columns' => [
|
||||
TableColumn::make()->name('id')->label('ID')->sortable(true),
|
||||
TableColumn::make()->name('name')->label('名称'),
|
||||
TableColumn::make()->name('sn')->label('编号'),
|
||||
TableColumn::make()->name('created_at')->label('创建时间')->type('datetime')->sortable(true),
|
||||
TableColumn::make()->name('updated_at')->label('更新时间')->type('datetime')->sortable(true),
|
||||
]
|
||||
]
|
||||
),
|
||||
])
|
||||
])->footer([
|
||||
amisMake()->Button()->label('保存')->type('submit')->level('primary'),
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
public function saveDevices()
|
||||
{
|
||||
$result = $this->service->saveDevices(request('id'), request());
|
||||
|
||||
return $this->autoResponse($result, __('admin.save'));
|
||||
}
|
||||
}
|
||||
|
|
@ -5,16 +5,12 @@ namespace App\Admin\Controllers;
|
|||
use Slowlyo\OwlAdmin\Renderers\Page;
|
||||
use Slowlyo\OwlAdmin\Renderers\Form;
|
||||
use Slowlyo\OwlAdmin\Renderers\TableColumn;
|
||||
use Slowlyo\OwlAdmin\Renderers\TextControl;
|
||||
use Slowlyo\OwlAdmin\Controllers\AdminController;
|
||||
use App\Services\Admin\RegionService;
|
||||
use Slowlyo\OwlAdmin\Renderers\Button;
|
||||
use Slowlyo\OwlAdmin\Renderers\Image;
|
||||
use App\Admin\Components;
|
||||
use App\Models\Device;
|
||||
use App\Models\Region;
|
||||
use Slowlyo\OwlAdmin\Renderers\Html;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\MonitorMode;
|
||||
|
||||
class RegionController extends AdminController
|
||||
{
|
||||
|
|
@ -46,7 +42,6 @@ class RegionController extends AdminController
|
|||
TableColumn::make()->name('category.name')->label('分类')->className('text-primary'),
|
||||
TableColumn::make()->name('director')->label('负责人'),
|
||||
TableColumn::make()->name('area')->label('面积m²'),
|
||||
TableColumn::make()->name('devices_count')->label('设备数量'),
|
||||
TableColumn::make()->name('is_enable')->type('switch')->label('显示')->quickEdit(Components::make()->enableControl('is_enable', '', 'inline')->saveImmediately(true)),
|
||||
TableColumn::make()->name('created_at')->label('创建时间')->type('datetime')->sortable(true),
|
||||
// TableColumn::make()->name('updated_at')->label('更新时间')->type('datetime')->sortable(true),
|
||||
|
|
@ -55,7 +50,6 @@ class RegionController extends AdminController
|
|||
$this->rowEditButton(true, 'lg'),
|
||||
$this->rowDeleteButton()
|
||||
]),
|
||||
|
||||
]);
|
||||
|
||||
return $this->baseList($crud);
|
||||
|
|
@ -63,12 +57,12 @@ class RegionController extends AdminController
|
|||
|
||||
public function form(): Form
|
||||
{
|
||||
$deviceType = [];
|
||||
$devices = Device::get()->groupBy('type');
|
||||
foreach(Device::typeMap() as $key => $item) {;
|
||||
$deviceType[] = [
|
||||
$monitorModeType = [];
|
||||
$monitorModes = MonitorMode::get()->groupBy('type');
|
||||
foreach(MonitorMode::typeMap() as $key => $item) {;
|
||||
$monitorModeType[] = [
|
||||
'label' => $item,
|
||||
'children' => $devices->get($key)?->pluck('name', 'id')->toArray(),
|
||||
'children' => $monitorModes->get($key)?->pluck('name', 'id')->toArray(),
|
||||
];
|
||||
}
|
||||
return $this->baseForm()->body([
|
||||
|
|
@ -80,25 +74,10 @@ class RegionController extends AdminController
|
|||
Components::make()->decimalControl('area', '面积m²'),
|
||||
Components::make()->sortControl(),
|
||||
\amisMake()->SwitchControl()->name('is_enable')->value(1)->label('显示'),
|
||||
\amisMake()->TransferControl()->name('devices')->label('关联设备')
|
||||
\amisMake()->TransferControl()->name('monitorModes')->label('关联监测')
|
||||
->selectMode('chained')->searchable(true)
|
||||
->joinValues(false)->extractValue(true)
|
||||
->options($deviceType),
|
||||
]);
|
||||
}
|
||||
|
||||
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('category.name')->label('分类'),
|
||||
TextControl::make()->static(true)->name('director')->label('负责人'),
|
||||
TextControl::make()->name('cover')->label('封面')->static(true)->staticSchema(Image::make()),
|
||||
TextControl::make()->static(true)->name('area')->label('面积m²'),
|
||||
TextControl::make()->name('description')->label('内容介绍')->static(true)->staticSchema(Html::make()),
|
||||
TextControl::make()->static(true)->name('created_at')->label('创建时间'),
|
||||
TextControl::make()->static(true)->name('updated_at')->label('更新时间')
|
||||
->options($monitorModeType),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,11 +44,15 @@ Route::group([
|
|||
$router->resource('keywords', \App\Admin\Controllers\KeywordController::class);
|
||||
//设备管理
|
||||
$router->resource('devices', \App\Admin\Controllers\DeviceController::class);
|
||||
$router->post('quick-edit/devices/{device}',[\App\Admin\Controllers\DeviceController::class, 'update']);
|
||||
|
||||
//设备预警
|
||||
$router->get('warning-setting', '\App\Admin\Controllers\WarningSettingController@settingIndex');
|
||||
$router->get('warning-notice', '\App\Admin\Controllers\WarningNoticeController@index');
|
||||
|
||||
//监测点位
|
||||
$router->resource('monitor-modes', \App\Admin\Controllers\MonitorModeController::class);
|
||||
$router->post('monitor-mode-save-devices', '\App\Admin\Controllers\MonitorModeController@saveDevices');
|
||||
|
||||
//区域分类
|
||||
$router->resource('region-categories', \App\Admin\Controllers\RegionCategoryController::class);
|
||||
$router->post('quick-edit/region-categories/{region_category}', '\App\Admin\Controllers\RegionCategoryController@update');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Device;
|
||||
use App\Models\MeteorologicalDailyReport;
|
||||
use App\Models\MeteorologicalReport;
|
||||
use App\Models\WaterQualityDailyReport;
|
||||
use App\Models\WaterQualityReport;
|
||||
use App\Services\DeviceLogService;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class DeviceLogDailyReportCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'device-log:daily-report
|
||||
{factory}
|
||||
{--sleep=300 : 监控报告生产后的休眠时间(秒)}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '按设备厂商生成监控报告';
|
||||
|
||||
/**
|
||||
* @var \App\Services\DeviceLogService
|
||||
*/
|
||||
protected $deviceLogService;
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle(DeviceLogService $deviceLogService)
|
||||
{
|
||||
$this->deviceLogService = $deviceLogService;
|
||||
|
||||
$factory = $this->argument('factory');
|
||||
|
||||
$sleep = (int) value(fn ($sleep) => is_numeric($sleep) ? $sleep : 300, $this->option('sleep'));
|
||||
|
||||
while (true) {
|
||||
/** @var \Illuminate\Database\Eloquent\Collection */
|
||||
$devices = Device::with(['factory'])->poweredBy($factory)->get();
|
||||
|
||||
foreach ($devices as $device) {
|
||||
switch ($device->factory?->key) {
|
||||
case 'link-os':
|
||||
$this->createReportToLinkosDevice($device);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sleep($sleep);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 linkos 设备报告
|
||||
*/
|
||||
protected function createReportToLinkosDevice(Device $device): void
|
||||
{
|
||||
$lastReportedAt = null;
|
||||
|
||||
switch ($device->type) {
|
||||
case Device::TYPE_WATER_QUALITY:
|
||||
$lastReportedAt = WaterQualityDailyReport::where('device_id', $device->id)
|
||||
->latest('reported_at')
|
||||
->value('reported_at');
|
||||
|
||||
$lastReportedAt ??= WaterQualityReport::where('device_id', $device->id)
|
||||
->oldest('reported_at')
|
||||
->value('reported_at');
|
||||
break;
|
||||
|
||||
case Device::TYPE_METEOROLOGICAL:
|
||||
$lastReportedAt = MeteorologicalDailyReport::where('device_id', $device->id)
|
||||
->latest('reported_at')
|
||||
->value('reported_at');
|
||||
|
||||
$lastReportedAt ??= MeteorologicalReport::where('device_id', $device->id)
|
||||
->oldest('reported_at')
|
||||
->value('reported_at');
|
||||
break;
|
||||
}
|
||||
|
||||
if ($lastReportedAt === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$latestReportedAt = null;
|
||||
|
||||
switch ($device->type) {
|
||||
case Device::TYPE_WATER_QUALITY:
|
||||
$latestReportedAt = WaterQualityReport::where('device_id', $device->id)
|
||||
->latest('reported_at')
|
||||
->value('reported_at');
|
||||
break;
|
||||
|
||||
case Device::TYPE_METEOROLOGICAL:
|
||||
$latestReportedAt = MeteorologicalReport::where('device_id', $device->id)
|
||||
->latest('reported_at')
|
||||
->value('reported_at');
|
||||
break;
|
||||
}
|
||||
|
||||
if ($latestReportedAt === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var \Carbon\Carbon */
|
||||
$startAt = $lastReportedAt->copy()->startOfDay();
|
||||
|
||||
do {
|
||||
$this->deviceLogService->createDailyReportToLinkosDevice($device, $startAt->copy());
|
||||
|
||||
$startAt->addDay();
|
||||
} while ($latestReportedAt->gte($startAt));
|
||||
}
|
||||
}
|
||||
|
|
@ -4,10 +4,9 @@ namespace App\Console\Commands;
|
|||
|
||||
use App\Models\Device;
|
||||
use App\Models\MeteorologicalReport;
|
||||
use App\Models\SoilReport;
|
||||
use App\Models\WaterQualityReport;
|
||||
use App\Services\DeviceLogService;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class DeviceLogReportCommand extends Command
|
||||
{
|
||||
|
|
@ -27,11 +26,18 @@ class DeviceLogReportCommand extends Command
|
|||
*/
|
||||
protected $description = '按设备厂商生成监控报告';
|
||||
|
||||
/**
|
||||
* @var \App\Services\DeviceLogService
|
||||
*/
|
||||
protected $deviceLogService;
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
public function handle(DeviceLogService $deviceLogService)
|
||||
{
|
||||
$this->deviceLogService = $deviceLogService;
|
||||
|
||||
$factory = $this->argument('factory');
|
||||
|
||||
$sleep = (int) value(fn ($sleep) => is_numeric($sleep) ? $sleep : 300, $this->option('sleep'));
|
||||
|
|
@ -52,225 +58,32 @@ class DeviceLogReportCommand extends Command
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 linkos 设备报告
|
||||
*/
|
||||
protected function createReportToLinkosDevice(Device $device): void
|
||||
{
|
||||
switch ($device->type) {
|
||||
case Device::TYPE_SOIL:
|
||||
$this->createReportToLinkosSoilDevice($device);
|
||||
break;
|
||||
$lastReportedAt = match ($device->type) {
|
||||
Device::TYPE_WATER_QUALITY => WaterQualityReport::where('device_id', $device->id)->latest('reported_at')->value('reported_at'),
|
||||
Device::TYPE_METEOROLOGICAL => MeteorologicalReport::where('device_id', $device->id)->latest('reported_at')->value('reported_at'),
|
||||
default => null,
|
||||
};
|
||||
|
||||
case Device::TYPE_METEOROLOGICAL:
|
||||
$this->createReportToLinkosMeteorologicalDevice($device);
|
||||
break;
|
||||
|
||||
case Device::TYPE_WATER_QUALITY:
|
||||
$this->createReportToLinkosWaterQualityDevice($device);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected function createReportToLinkosSoilDevice(Device $device): void
|
||||
{
|
||||
$lastSoilReport = SoilReport::where('device_id', $device->id)
|
||||
->latest('reported_at')
|
||||
->first();
|
||||
|
||||
$lastReportedAt = $lastSoilReport?->reported_at
|
||||
?: $device->logs()->oldest('reported_at')->value('reported_at');
|
||||
|
||||
if ($lastReportedAt === null) {
|
||||
if (is_null($lastReportedAt ??= $device->logs()->oldest('reported_at')->value('reported_at'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$latestReportedAt = $device->logs()->latest('reported_at')->value('reported_at');
|
||||
|
||||
if ($latestReportedAt === null) {
|
||||
if (is_null($latestReportedAt = $device->logs()->latest('reported_at')->value('reported_at'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var \Carbon\Carbon */
|
||||
$startAt = $lastReportedAt->copy()->startOfHour();
|
||||
/** @var \Carbon\Carbon */
|
||||
$endAt = $latestReportedAt->copy()->startOfHour();
|
||||
|
||||
do {
|
||||
/** @var \Illuminate\Database\Eloquent\Collection */
|
||||
$logs = $device->logs()
|
||||
->whereBetween('reported_at', [$startAt, $startAt->copy()->endOfHour()])
|
||||
->oldest('reported_at')
|
||||
->get();
|
||||
|
||||
if ($logs->isNotEmpty()) {
|
||||
$soilReport = SoilReport::firstOrCreate(
|
||||
[
|
||||
'device_id' => $device->id,
|
||||
'reported_at' => $startAt,
|
||||
],
|
||||
Arr::except($lastSoilReport?->setHidden([])?->attributesToArray() ?: [], ['reported_at'])
|
||||
);
|
||||
|
||||
/** @var \App\Models\DeviceLog */
|
||||
foreach ($logs as $log) {
|
||||
foreach ([
|
||||
'conductivity' => 'conductivity',
|
||||
'soil_humidity' => 'humidity',
|
||||
'soil_temperature' => 'temperature',
|
||||
'nitrogen_content' => 'n',
|
||||
'potassium_content' => 'k',
|
||||
'phosphorus_content' => 'p',
|
||||
] as $key => $attribute) {
|
||||
if (! is_array($log->data) || ! array_key_exists($key, $log->data)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$soilReport->{$attribute} = $log->data[$key];
|
||||
}
|
||||
|
||||
$lastSoilReport = tap($soilReport)->save();
|
||||
}
|
||||
}
|
||||
$this->deviceLogService->createReportToLinkosDevice($device, $startAt->copy());
|
||||
|
||||
$startAt->addHour();
|
||||
} while ($endAt->gte($startAt));
|
||||
}
|
||||
|
||||
protected function createReportToLinkosMeteorologicalDevice(Device $device): void
|
||||
{
|
||||
$lastMeteorologicalReport = MeteorologicalReport::where('device_id', $device->id)
|
||||
->latest('reported_at')
|
||||
->first();
|
||||
|
||||
$lastReportedAt = $lastMeteorologicalReport?->reported_at
|
||||
?: $device->logs()->oldest('reported_at')->value('reported_at');
|
||||
|
||||
if ($lastReportedAt === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$latestReportedAt = $device->logs()->latest('reported_at')->value('reported_at');
|
||||
|
||||
if ($latestReportedAt === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var \Carbon\Carbon */
|
||||
$startAt = $lastReportedAt->copy()->startOfHour();
|
||||
/** @var \Carbon\Carbon */
|
||||
$endAt = $latestReportedAt->copy()->startOfHour();
|
||||
|
||||
do {
|
||||
/** @var \Illuminate\Database\Eloquent\Collection */
|
||||
$logs = $device->logs()
|
||||
->whereBetween('reported_at', [$startAt, $startAt->copy()->endOfHour()])
|
||||
->oldest('reported_at')
|
||||
->get();
|
||||
|
||||
if ($logs->isNotEmpty()) {
|
||||
$meteorologicalReport = MeteorologicalReport::firstOrCreate(
|
||||
[
|
||||
'device_id' => $device->id,
|
||||
'reported_at' => $startAt,
|
||||
],
|
||||
Arr::except($lastMeteorologicalReport?->setHidden([])?->attributesToArray() ?: [], ['reported_at'])
|
||||
);
|
||||
|
||||
/** @var \App\Models\DeviceLog */
|
||||
foreach ($logs as $log) {
|
||||
foreach ([
|
||||
'current_rainfall' => 'today_rainfall',
|
||||
'day_rainfall' => 'yesterday_rainfall',
|
||||
'accumulate_rainfall' => 'accumulate_rainfall',
|
||||
'moment_rainfall' => 'moment_rainfall',
|
||||
'pm10_concentration' => 'pm10',
|
||||
'pm25_concentration' => 'pm25',
|
||||
'box_illumination' => 'box_illumination',
|
||||
'box_pressure' => 'box_pressure',
|
||||
'box_carbon' => 'box_co2',
|
||||
'box_temperature' => 'box_temperature',
|
||||
'box_humidity' => 'box_humidity',
|
||||
'box_noise' => 'box_noise',
|
||||
'wind_degree' => 'wind_degree',
|
||||
'wind_direction' => 'wind_direction',
|
||||
'wind_power' => 'wind_power',
|
||||
'wind_speed' => 'wind_speed',
|
||||
] as $key => $attribute) {
|
||||
if (! is_array($log->data) || ! array_key_exists($key, $log->data)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$meteorologicalReport->{$attribute} = $log->data[$key];
|
||||
}
|
||||
|
||||
$lastMeteorologicalReport = tap($meteorologicalReport)->save();
|
||||
}
|
||||
}
|
||||
|
||||
$startAt->addHour();
|
||||
} while ($endAt->gte($startAt));
|
||||
}
|
||||
|
||||
protected function createReportToLinkosWaterQualityDevice(Device $device): void
|
||||
{
|
||||
$lastWaterQualityReport = WaterQualityReport::where('device_id', $device->id)
|
||||
->latest('reported_at')
|
||||
->first();
|
||||
|
||||
$lastReportedAt = $lastWaterQualityReport?->reported_at
|
||||
?: $device->logs()->oldest('reported_at')->value('reported_at');
|
||||
|
||||
if ($lastReportedAt === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$latestReportedAt = $device->logs()->latest('reported_at')->value('reported_at');
|
||||
|
||||
if ($latestReportedAt === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var \Carbon\Carbon */
|
||||
$startAt = $lastReportedAt->copy()->startOfHour();
|
||||
/** @var \Carbon\Carbon */
|
||||
$endAt = $latestReportedAt->copy()->startOfHour();
|
||||
|
||||
do {
|
||||
/** @var \Illuminate\Database\Eloquent\Collection */
|
||||
$logs = $device->logs()
|
||||
->whereBetween('reported_at', [$startAt, $startAt->copy()->endOfHour()])
|
||||
->oldest('reported_at')
|
||||
->get();
|
||||
|
||||
if ($logs->isNotEmpty()) {
|
||||
$waterQualityReport = WaterQualityReport::firstOrCreate(
|
||||
[
|
||||
'device_id' => $device->id,
|
||||
'reported_at' => $startAt,
|
||||
],
|
||||
Arr::except($lastWaterQualityReport?->setHidden([])?->attributesToArray() ?: [], ['reported_at'])
|
||||
);
|
||||
|
||||
/** @var \App\Models\DeviceLog */
|
||||
foreach ($logs as $log) {
|
||||
foreach ([
|
||||
'chlorine' => 'chlorine',
|
||||
'conductivity' => 'conductivity',
|
||||
'oxygen' => 'oxygen',
|
||||
'ph' => 'ph',
|
||||
'temp' => 'temperature',
|
||||
'turbidity' => 'turbidity',
|
||||
] as $key => $attribute) {
|
||||
if (! is_array($log->data) || ! array_key_exists($key, $log->data)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$waterQualityReport->{$attribute} = $log->data[$key];
|
||||
}
|
||||
|
||||
$lastWaterQualityReport = tap($waterQualityReport)->save();
|
||||
}
|
||||
}
|
||||
|
||||
$startAt->addHour();
|
||||
} while ($endAt->gte($startAt));
|
||||
} while ($latestReportedAt->gte($startAt));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ namespace App\Filters\Admin;
|
|||
|
||||
use EloquentFilter\ModelFilter;
|
||||
use App\Models\Device;
|
||||
use App\Models\MonitorMode;
|
||||
|
||||
class DeviceFilter extends ModelFilter
|
||||
{
|
||||
|
|
@ -28,6 +29,13 @@ class DeviceFilter extends ModelFilter
|
|||
return $this->where('type', $type);
|
||||
}
|
||||
|
||||
public function monitorMode($monitorMode){
|
||||
if($monitorMode){
|
||||
$deviceIds = MonitorMode::find($monitorMode)?->devices()->get()->pluck('id')->toArray();
|
||||
}
|
||||
return $this->whereIn('id', $deviceIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace App\Filters\Admin;
|
||||
|
||||
use EloquentFilter\ModelFilter;
|
||||
use App\Models\Device;
|
||||
|
||||
class MonitorModeFilter extends ModelFilter
|
||||
{
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
public function name($name){
|
||||
return $this->where('name', 'like', '%'.$name.'%');
|
||||
}
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
public function type($type){
|
||||
return $this->where('type', $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
public function typeName($typeName){
|
||||
$type = 0;
|
||||
foreach(Device::typeMap() as $key => $item){
|
||||
if($item == $typeName){
|
||||
$type = $key;
|
||||
break;
|
||||
}
|
||||
};
|
||||
return $this->where('type', $type);
|
||||
}
|
||||
/**
|
||||
* 分组
|
||||
*/
|
||||
public function groupTags($groupTags){
|
||||
return $this->whereRaw("FIND_IN_SET(group_tags,'$groupTags')");
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@ class Device extends Model
|
|||
public const TYPE_METEOROLOGICAL = 4; //气象设备
|
||||
public const TYPE_AIR = 5; //通风设备
|
||||
public const TYPE_ATOMIZING = 6; //喷雾设备
|
||||
public const TYPE_INSECT = 7; //虫情监测
|
||||
|
||||
public const STATE_DISABLED = 0;
|
||||
public const STATE_ONLINE = 1;
|
||||
|
|
@ -28,9 +29,7 @@ class Device extends Model
|
|||
];
|
||||
|
||||
protected $fillable = [
|
||||
'name', 'sn', 'powered_by', 'type', 'model_sn', 'state', 'extends',
|
||||
'is_enable', 'sort', 'is_recommend',
|
||||
'group_tags'
|
||||
'name', 'sn', 'powered_by', 'type', 'model_sn', 'state', 'extends'
|
||||
];
|
||||
|
||||
public function scopePoweredBy(Builder $query, string $factory): void
|
||||
|
|
@ -48,10 +47,11 @@ class Device extends Model
|
|||
return [
|
||||
self::TYPE_MONITOR => '监控设备',
|
||||
self::TYPE_SOIL => '土壤设备',
|
||||
self::TYPE_WATER_QUALITY => '水质设备',
|
||||
// self::TYPE_WATER_QUALITY => '水质设备',
|
||||
self::TYPE_METEOROLOGICAL => '气象设备',
|
||||
self::TYPE_AIR => '通风设备',
|
||||
self::TYPE_ATOMIZING => '喷雾设备'
|
||||
self::TYPE_ATOMIZING => '喷雾设备',
|
||||
self::TYPE_INSECT => '虫情监测',
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|||
use Illuminate\Database\Eloquent\Model;
|
||||
use EloquentFilter\Filterable;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use App\Admin\Components;
|
||||
|
||||
class Keyword extends Model
|
||||
{
|
||||
|
|
@ -54,4 +55,10 @@ class Keyword extends Model
|
|||
return self::query()->where('type_key', $key)->get();
|
||||
}
|
||||
|
||||
public static function tagsMap(String $key){
|
||||
$list = self::query()->where('type_key', $key)->get()->pluck('name', 'id')->toArray();
|
||||
return array_map(function($item){
|
||||
return Components::make()->keywordsTag($item);
|
||||
}, $list);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class MeteorologicalDailyReport extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
const WIND_DIRECTION_NORTH = 0;
|
||||
const WIND_DIRECTION_NORTHEAST = 1;
|
||||
const WIND_DIRECTION_EAST = 2;
|
||||
const WIND_DIRECTION_SOUTHEAST = 3;
|
||||
const WIND_DIRECTION_SOUTH = 4;
|
||||
const WIND_DIRECTION_SOUTHWEST = 5;
|
||||
const WIND_DIRECTION_WEST = 6;
|
||||
const WIND_DIRECTION_NORTHWEST = 7;
|
||||
|
||||
protected $casts = [
|
||||
'reported_at' => 'date'
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
'device_id',
|
||||
'today_rainfall',
|
||||
'yesterday_rainfall',
|
||||
'accumulate_rainfall',
|
||||
'moment_rainfall',
|
||||
'pm10',
|
||||
'pm25',
|
||||
'box_illumination',
|
||||
'box_pressure',
|
||||
'box_co2',
|
||||
'box_temperature',
|
||||
'box_humidity',
|
||||
'box_noise',
|
||||
'wind_degree',
|
||||
'wind_direction',
|
||||
'wind_power',
|
||||
'wind_speed',
|
||||
'reported_at',
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class MonitorDevice extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
public $timestamps = false;
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use EloquentFilter\Filterable;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
|
||||
class MonitorMode extends Model
|
||||
{
|
||||
use Filterable;
|
||||
|
||||
protected $fillable = [
|
||||
'name', 'type',
|
||||
'is_enable', 'sort', 'is_recommend',
|
||||
'group_tags'
|
||||
];
|
||||
|
||||
protected $appends = ['tags'];
|
||||
|
||||
public const TYPE_MONITOR = 1; //视频监控
|
||||
public const TYPE_SOIL = 2; //土壤监测
|
||||
public const TYPE_WATER_QUALITY = 3; //水质监测
|
||||
public const TYPE_METEOROLOGICAL = 4; //气象监测
|
||||
public const TYPE_AIR = 5; //通风控制
|
||||
public const TYPE_ATOMIZING = 6; //喷雾控制
|
||||
public const TYPE_INSECT = 7; //虫情监测
|
||||
|
||||
public static function typeMap()
|
||||
{
|
||||
return [
|
||||
self::TYPE_MONITOR => '视频监控',
|
||||
self::TYPE_SOIL => '土壤监测',
|
||||
// self::TYPE_WATER_QUALITY => '水质监测',
|
||||
self::TYPE_METEOROLOGICAL => '气象监测',
|
||||
self::TYPE_AIR => '通风控制',
|
||||
self::TYPE_ATOMIZING => '喷雾控制',
|
||||
self::TYPE_INSECT => '虫情监测',
|
||||
];
|
||||
}
|
||||
|
||||
public static function fieldMap($type)
|
||||
{
|
||||
$arr = [];
|
||||
switch ($type) {
|
||||
case self::TYPE_SOIL:
|
||||
$arr = [
|
||||
'conductivity'=>'导电率',
|
||||
'humidity'=>'湿度',
|
||||
'temperature'=>'温度',
|
||||
'n'=>'氮',
|
||||
'p'=>'磷',
|
||||
'k'=>'钾'
|
||||
];
|
||||
break;
|
||||
case self::TYPE_WATER_QUALITY:
|
||||
$arr = [
|
||||
];
|
||||
break;
|
||||
case self::TYPE_METEOROLOGICAL:
|
||||
$arr = [
|
||||
'box_temperature' => '温度',
|
||||
'box_humidity' => '湿度',
|
||||
'box_illumination' => '光照强度',
|
||||
'moment_rainfall' => '降雨量',
|
||||
'wind_speed' => '风速',
|
||||
'wind_direction' => '风向',
|
||||
'box_noise' => '噪音',
|
||||
'pm10' => 'PM10',
|
||||
'pm25' => 'PM25',
|
||||
'box_co2' => 'CO2'
|
||||
];
|
||||
break;
|
||||
}
|
||||
return $arr;
|
||||
}
|
||||
|
||||
protected function serializeDate(\DateTimeInterface $date){
|
||||
return $date->format('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
protected function tags():Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn($value) => $this->group_tags ? explode(',', $this->group_tags) : [],
|
||||
);
|
||||
}
|
||||
|
||||
public function devices(){
|
||||
return $this->belongsToMany(Device::class, MonitorDevice::class, 'monitor_id', 'device_id')->withPivot('fields');
|
||||
}
|
||||
}
|
||||
|
|
@ -12,7 +12,6 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|||
*/
|
||||
class Region extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use Filterable;
|
||||
|
||||
protected $fillable = [
|
||||
|
|
@ -44,10 +43,8 @@ class Region extends Model
|
|||
return $this->belongsTo(RegionCategory::class, 'category_id');
|
||||
}
|
||||
|
||||
// 关联设备
|
||||
public function devices()
|
||||
{
|
||||
return $this->belongsToMany(Device::class, RegionDevice::class, 'region_id', 'device_id')->withTimestamps();
|
||||
public function monitorModes(){
|
||||
return $this->belongsToMany(MonitorMode::class, RegionMonitor::class, 'region_id', 'monitor_id')->withTimestamps();
|
||||
}
|
||||
|
||||
// 种植记录
|
||||
|
|
@ -78,47 +75,47 @@ class Region extends Model
|
|||
'sort' => 0,
|
||||
],
|
||||
];
|
||||
if($region?->devices){
|
||||
foreach($region->devices as $device){
|
||||
switch($device->type)
|
||||
if($region?->monitorModes){
|
||||
foreach($region->monitorModes as $monitorMode){
|
||||
switch($monitorMode->type)
|
||||
{
|
||||
case Device::TYPE_MONITOR:
|
||||
case MonitorMode::TYPE_MONITOR:
|
||||
$tabs[] = [//有监控设备才有
|
||||
'title' => '监控视频',
|
||||
'value' => 'monitor',
|
||||
'tab'=>\amisMake()->Service()->schemaApi(admin_url('custom-region-monitor?id='.$region->id)),
|
||||
'tab'=>\amisMake()->Service()->schemaApi(admin_url('custom-region-monitor?region_id='.$region->id)),
|
||||
'unmountOnExit' => true,//每次切换tab都要销毁
|
||||
'sort' => 1,
|
||||
];
|
||||
break;
|
||||
case Device::TYPE_SOIL:
|
||||
case MonitorMode::TYPE_SOIL:
|
||||
$tabs[] = [//有土壤设备才有
|
||||
'title' => '土壤数据',
|
||||
'value' => 'turang',
|
||||
'value' => 'soil',
|
||||
'tab'=>\amisMake()->Service()->schemaApi(admin_url('custom-region-soil?id='.$region->id)),
|
||||
'unmountOnExit' => true,//每次切换tab都要销毁
|
||||
'sort' => 2,
|
||||
];
|
||||
break;
|
||||
case Device::TYPE_WATER_QUALITY:
|
||||
case MonitorMode::TYPE_WATER_QUALITY:
|
||||
$tabs[] = [//有水质设备才有
|
||||
'title' => '水质数据',
|
||||
'value' => 'shuizi',
|
||||
'value' => 'quality',
|
||||
'tab'=>\amisMake()->Service()->schemaApi(admin_url('custom-region-water?id='.$region->id)),
|
||||
'unmountOnExit' => true,//每次切换tab都要销毁
|
||||
'sort' => 3,
|
||||
];
|
||||
break;
|
||||
case Device::TYPE_METEOROLOGICAL:
|
||||
case MonitorMode::TYPE_METEOROLOGICAL:
|
||||
$tabs[] = [//有气象设备才有
|
||||
'title' => '气象数据',
|
||||
'value' => 'qixiang',
|
||||
'value' => 'meteorological',
|
||||
'tab'=>\amisMake()->Service()->schemaApi(admin_url('custom-region-meteorological?id='.$region->id)),
|
||||
'unmountOnExit' => true,//每次切换tab都要销毁
|
||||
'sort' => 4,
|
||||
];
|
||||
break;
|
||||
case Device::TYPE_AIR:
|
||||
case MonitorMode::TYPE_AIR:
|
||||
$tabs[] = [//有通风设备才有
|
||||
'title' => '通风设备',
|
||||
'value' => 'air',
|
||||
|
|
@ -127,11 +124,11 @@ class Region extends Model
|
|||
'sort' => 5,
|
||||
];
|
||||
break;
|
||||
case Device::TYPE_ATOMIZING:
|
||||
case MonitorMode::TYPE_ATOMIZING:
|
||||
$tabs[] = [//有喷雾设备才有
|
||||
'title' => '喷雾设备',
|
||||
'value' => 'wasserstrahl',
|
||||
'tab'=>\amisMake()->Service()->schemaApi(admin_url('custom-region-wasserstrahl?id='.$region->id)),
|
||||
'value' => 'atomizing',
|
||||
'tab'=>\amisMake()->Service()->schemaApi(admin_url('custom-region-atomizing?id='.$region->id)),
|
||||
'unmountOnExit' => true,//每次切换tab都要销毁
|
||||
'sort' => 6,
|
||||
];
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace App\Models;
|
|||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class RegionDevice extends Model
|
||||
class RegionMonitor extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class WaterQualityDailyReport extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $casts = [
|
||||
'reported_at' => 'date'
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
'device_id',
|
||||
'chlorine',
|
||||
'conductivity',
|
||||
'oxygen',
|
||||
'ph',
|
||||
'temperature',
|
||||
'turbidity',
|
||||
'reported_at',
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\Admin;
|
||||
|
||||
use App\Models\MonitorMode;
|
||||
use App\Filters\Admin\MonitorModeFilter;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
/**
|
||||
* @method MonitorMode getModel()
|
||||
* @method MonitorMode|\Illuminate\Database\Query\Builder query()
|
||||
*/
|
||||
class MonitorModeService extends BaseService
|
||||
{
|
||||
protected string $modelName = MonitorMode::class;
|
||||
|
||||
protected string $modelFilterName = MonitorModeFilter::class;
|
||||
|
||||
public function getEditData($id): Model|\Illuminate\Database\Eloquent\Collection|Builder|array|null
|
||||
{
|
||||
$region = parent::getEditData($id);
|
||||
//处理详情数据;
|
||||
$region->load('devices');
|
||||
|
||||
switch($region->type) {
|
||||
case MonitorMode::TYPE_MONITOR:
|
||||
case MonitorMode::TYPE_AIR:
|
||||
case MonitorMode::TYPE_ATOMIZING:
|
||||
$region->offsetSet('picker_devices', $region->devices->pluck('id')->toArray());
|
||||
break;
|
||||
case MonitorMode::TYPE_SOIL:
|
||||
case MonitorMode::TYPE_WATER_QUALITY:
|
||||
case MonitorMode::TYPE_METEOROLOGICAL:
|
||||
$region->offsetSet('array_devices', $region->devices->map(function($item, $key){
|
||||
return [
|
||||
'device_id' => $item->id,
|
||||
'device_fields' => explode(',', $item->pivot->fields ?? ''),
|
||||
];
|
||||
}));
|
||||
break;
|
||||
}
|
||||
|
||||
return $region;
|
||||
}
|
||||
|
||||
public function saveDevices($primaryKey, $params){
|
||||
$model = $this->query()->whereKey($primaryKey)->first();
|
||||
$type = $params['type'] ?? null;
|
||||
$syncData = [];
|
||||
switch($type){
|
||||
case MonitorMode::TYPE_MONITOR:
|
||||
case MonitorMode::TYPE_AIR:
|
||||
case MonitorMode::TYPE_ATOMIZING:
|
||||
$syncData = $params['picker_devices'] ?? [];
|
||||
break;
|
||||
case MonitorMode::TYPE_SOIL:
|
||||
case MonitorMode::TYPE_WATER_QUALITY:
|
||||
case MonitorMode::TYPE_METEOROLOGICAL:
|
||||
$arrayDevices = $params['array_devices'] ?? [];
|
||||
if($arrayDevices){
|
||||
foreach($arrayDevices as $arrayDevice){
|
||||
//过滤重复设备
|
||||
if(isset($syncData[$arrayDevice['device_id']])){
|
||||
return $this->setError('请勿重复选择监测设备');
|
||||
}
|
||||
$syncData[$arrayDevice['device_id']] = [
|
||||
'fields' => $arrayDevice['device_fields']
|
||||
];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $model->devices()->sync($syncData);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -25,7 +25,7 @@ class RegionService extends BaseService
|
|||
public function getEditData($id): Model|\Illuminate\Database\Eloquent\Collection|Builder|array|null
|
||||
{
|
||||
$region = parent::getEditData($id);
|
||||
$region->devices = $region->devices()->selectRaw('devices.id as value, devices.name as label')->get()->toArray();
|
||||
$region->monitorModes = $region->monitorModes()->get()->pluck('id')->toArray();
|
||||
return $region;
|
||||
}
|
||||
|
||||
|
|
@ -45,8 +45,8 @@ class RegionService extends BaseService
|
|||
DB::beginTransaction();
|
||||
if($model->save()){
|
||||
//处理关联设备
|
||||
$devices = Arr::get($data, 'devices');
|
||||
$model->devices()->sync($devices ?? []);
|
||||
$monitorModes = Arr::get($data, 'monitorModes');
|
||||
$model->monitorModes()->sync($monitorModes ?? []);
|
||||
}
|
||||
DB::commit();
|
||||
return true;
|
||||
|
|
@ -73,8 +73,8 @@ class RegionService extends BaseService
|
|||
DB::beginTransaction();
|
||||
if($model->save()){
|
||||
//处理关联设备
|
||||
$devices = Arr::get($data, 'devices');
|
||||
$model->devices()->sync($devices ?? []);
|
||||
$monitorModes = Arr::get($data, 'monitorModes');
|
||||
$model->monitorModes()->sync($monitorModes ?? []);
|
||||
}
|
||||
DB::commit();
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@ namespace App\Services;
|
|||
|
||||
use App\Iot\Linkos\HttpClient as LinkosHttpClient;
|
||||
use App\Models\Device;
|
||||
use App\Models\DeviceLog;
|
||||
use App\Models\MeteorologicalDailyReport;
|
||||
use App\Models\MeteorologicalReport;
|
||||
use App\Models\WaterQualityDailyReport;
|
||||
use App\Models\WaterQualityReport;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
|
|
@ -73,4 +78,353 @@ class DeviceLogService
|
|||
$page++;
|
||||
} while ($countResults === $perPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 linkos 设备报告
|
||||
*/
|
||||
public function createReportToLinkosDevice(Device $device, Carbon $time): void
|
||||
{
|
||||
switch ($device->type) {
|
||||
case Device::TYPE_METEOROLOGICAL:
|
||||
$this->createReportToLinkosMeteorologicalDevice($device, $time);
|
||||
break;
|
||||
|
||||
case Device::TYPE_WATER_QUALITY:
|
||||
$this->createReportToLinkosWaterQualityDevice($device, $time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 linkos 气象设备报告
|
||||
*/
|
||||
protected function createReportToLinkosMeteorologicalDevice(Device $device, Carbon $time): void
|
||||
{
|
||||
$reportedAt = $time->copy()->startOfHour();
|
||||
|
||||
/** @var \Illuminate\Database\Eloquent\Collection */
|
||||
$logs = $device->logs()
|
||||
->whereBetween('reported_at', [$reportedAt, $reportedAt->copy()->endOfHour()])
|
||||
->oldest('reported_at')
|
||||
->get();
|
||||
|
||||
if ($logs->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$attributes = $logs->reduce(function (array $attributes, DeviceLog $log) {
|
||||
if (is_array($data = $log->data)) {
|
||||
foreach ($data as $k => $v) {
|
||||
$attribute = match ($k) {
|
||||
'current_rainfall' => 'today_rainfall',
|
||||
'day_rainfall' => 'yesterday_rainfall',
|
||||
'accumulate_rainfall' => 'accumulate_rainfall',
|
||||
'moment_rainfall' => 'moment_rainfall',
|
||||
'pm10_concentration' => 'pm10',
|
||||
'pm25_concentration' => 'pm25',
|
||||
'box_illumination' => 'box_illumination',
|
||||
'box_pressure' => 'box_pressure',
|
||||
'box_carbon' => 'box_co2',
|
||||
'box_temperature' => 'box_temperature',
|
||||
'box_humidity' => 'box_humidity',
|
||||
'box_noise' => 'box_noise',
|
||||
'wind_degree' => 'wind_degree',
|
||||
'wind_direction' => 'wind_direction',
|
||||
'wind_power' => 'wind_power',
|
||||
'wind_speed' => 'wind_speed',
|
||||
default => null,
|
||||
};
|
||||
|
||||
if ($attribute) {
|
||||
$attributes[$attribute] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}, []);
|
||||
|
||||
$meteorologicalReport = MeteorologicalReport::where([
|
||||
'device_id' => $device->id,
|
||||
'reported_at' => $reportedAt,
|
||||
])->first();
|
||||
|
||||
if ($meteorologicalReport === null) {
|
||||
$lastMeteorologicalReport = MeteorologicalReport::where([
|
||||
'device_id' => $device->id,
|
||||
'reported_at' => $reportedAt->copy()->subHour(),
|
||||
])->first();
|
||||
|
||||
$meteorologicalReport = $lastMeteorologicalReport?->replicate() ?: new MeteorologicalReport();
|
||||
|
||||
$meteorologicalReport->fill([
|
||||
'device_id' => $device->id,
|
||||
'reported_at' => $reportedAt,
|
||||
]);
|
||||
}
|
||||
|
||||
$meteorologicalReport->fill($attributes)->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 linkos 水质设备报告
|
||||
*/
|
||||
protected function createReportToLinkosWaterQualityDevice(Device $device, Carbon $time): void
|
||||
{
|
||||
$reportedAt = $time->copy()->startOfHour();
|
||||
|
||||
/** @var \Illuminate\Database\Eloquent\Collection */
|
||||
$logs = $device->logs()
|
||||
->whereBetween('reported_at', [$reportedAt, $reportedAt->copy()->endOfHour()])
|
||||
->oldest('reported_at')
|
||||
->get();
|
||||
|
||||
if ($logs->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$attributes = $logs->reduce(function (array $attributes, DeviceLog $log) {
|
||||
if (is_array($data = $log->data)) {
|
||||
foreach ($data as $k => $v) {
|
||||
$attribute = match ($k) {
|
||||
'chlorine' => 'chlorine',
|
||||
'conductivity' => 'conductivity',
|
||||
'oxygen' => 'oxygen',
|
||||
'ph' => 'ph',
|
||||
'temp' => 'temperature',
|
||||
'turbidity' => 'turbidity',
|
||||
default => null,
|
||||
};
|
||||
|
||||
if ($attribute) {
|
||||
$attributes[$attribute] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}, []);
|
||||
|
||||
$waterQualityReport = WaterQualityReport::where([
|
||||
'device_id' => $device->id,
|
||||
'reported_at' => $reportedAt,
|
||||
])->first();
|
||||
|
||||
if ($waterQualityReport === null) {
|
||||
$lastWaterQualityReport = WaterQualityReport::where([
|
||||
'device_id' => $device->id,
|
||||
'reported_at' => $reportedAt->copy()->subHour(),
|
||||
])->first();
|
||||
|
||||
$waterQualityReport = $lastWaterQualityReport?->replicate() ?: new WaterQualityReport();
|
||||
|
||||
$waterQualityReport->fill([
|
||||
'device_id' => $device->id,
|
||||
'reported_at' => $reportedAt,
|
||||
]);
|
||||
}
|
||||
|
||||
$waterQualityReport->fill($attributes)->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 linkos 设备每日报告
|
||||
*/
|
||||
public function createDailyReportToLinkosDevice(Device $device, Carbon $time): void
|
||||
{
|
||||
switch ($device->type) {
|
||||
case Device::TYPE_METEOROLOGICAL:
|
||||
$this->createDailyReportToLinkosMeteorologicalDevice($device, $time);
|
||||
break;
|
||||
|
||||
case Device::TYPE_WATER_QUALITY:
|
||||
$this->createDailyReportToLinkosWaterQualityDevice($device, $time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 linkos 气象设备每日报告
|
||||
*/
|
||||
protected function createDailyReportToLinkosMeteorologicalDevice(Device $device, Carbon $date): void
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Collection */
|
||||
$meteorologicalReports = MeteorologicalReport::where('device_id', $device->id)
|
||||
->whereDate('reported_at', $date)
|
||||
->oldest('reported_at')
|
||||
->get();
|
||||
|
||||
if ($meteorologicalReports->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$attributes = value(function ($meteorologicalReports) {
|
||||
$data = [
|
||||
'today_rainfall' => ['sum' => 0, 'count' => 0],
|
||||
'yesterday_rainfall' => ['sum' => 0, 'count' => 0],
|
||||
'accumulate_rainfall' => ['sum' => 0, 'count' => 0],
|
||||
'moment_rainfall' => ['sum' => 0, 'count' => 0],
|
||||
'pm10' => ['sum' => 0, 'count' => 0],
|
||||
'pm25' => ['sum' => 0, 'count' => 0],
|
||||
'box_illumination' => ['sum' => 0, 'count' => 0],
|
||||
'box_pressure' => ['sum' => 0, 'count' => 0],
|
||||
'box_co2' => ['sum' => 0, 'count' => 0],
|
||||
'box_temperature' => ['sum' => 0, 'count' => 0],
|
||||
'box_humidity' => ['sum' => 0, 'count' => 0],
|
||||
'box_noise' => ['sum' => 0, 'count' => 0],
|
||||
'wind_samples' => [],
|
||||
];
|
||||
|
||||
foreach ($meteorologicalReports as $meteorologicalReport) {
|
||||
foreach ($data as $k => $item) {
|
||||
if ($k === 'wind_samples') {
|
||||
if (is_null($meteorologicalReport->wind_degree) || is_null($meteorologicalReport->wind_speed)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$item[] = [
|
||||
'wind_degree' => $meteorologicalReport->wind_degree, // 风向度数
|
||||
'wind_speed' => $meteorologicalReport->wind_speed, // 风速
|
||||
];
|
||||
} elseif (! is_null($v = $meteorologicalReport->{$k})) {
|
||||
$item['sum'] = bcadd($item['sum'], $v, 2);
|
||||
$item['count']++;
|
||||
}
|
||||
|
||||
$data[$k] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
$attributes = [];
|
||||
|
||||
foreach ($data as $key => $item) {
|
||||
switch ($key) {
|
||||
case 'wind_samples':
|
||||
$attributes['wind_degree'] = value(function (array $windSamples) {
|
||||
$x = 0;
|
||||
$y = 0;
|
||||
|
||||
foreach ($windSamples as $sample) {
|
||||
if ($sample['wind_degree'] == 0 && $sample['wind_speed'] == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 角度转弧度
|
||||
$radian = deg2rad($sample['wind_degree']);
|
||||
|
||||
// $x += $sample['wind_speed'] * sin($radian);
|
||||
// $y += $sample['wind_speed'] * cos($radian);
|
||||
$x += sin($radian);
|
||||
$y += cos($radian);
|
||||
}
|
||||
|
||||
$degree = round(rad2deg(atan2($y, $x)));
|
||||
|
||||
if (($x > 0 || $x < 0) && $y < 0) {
|
||||
$degree += 180;
|
||||
} elseif ($x < 0 && $y > 0) {
|
||||
$degree += 360;
|
||||
}
|
||||
|
||||
return $degree;
|
||||
}, $item);
|
||||
|
||||
$attributes['wind_direction'] = value(function ($windDegree) {
|
||||
if ($windDegree >= 22.5 && $windDegree < 67.5) {
|
||||
return MeteorologicalDailyReport::WIND_DIRECTION_NORTHEAST;
|
||||
} elseif ($windDegree >= 67.5 && $windDegree < 112.5) {
|
||||
return MeteorologicalDailyReport::WIND_DIRECTION_EAST;
|
||||
} elseif ($windDegree >= 112.5 && $windDegree < 157.5) {
|
||||
return MeteorologicalDailyReport::WIND_DIRECTION_SOUTHEAST;
|
||||
} elseif ($windDegree >= 157.5 && $windDegree < 202.5) {
|
||||
return MeteorologicalDailyReport::WIND_DIRECTION_SOUTH;
|
||||
} elseif ($windDegree >= 202.5 && $windDegree < 247.5) {
|
||||
return MeteorologicalDailyReport::WIND_DIRECTION_SOUTHWEST;
|
||||
} elseif ($windDegree >= 247.5 && $windDegree < 292.5) {
|
||||
return MeteorologicalDailyReport::WIND_DIRECTION_WEST;
|
||||
} elseif ($windDegree >= 292.5 && $windDegree < 337.5) {
|
||||
return MeteorologicalDailyReport::WIND_DIRECTION_NORTHWEST;
|
||||
}
|
||||
|
||||
return MeteorologicalDailyReport::WIND_DIRECTION_NORTH;
|
||||
}, $attributes['wind_degree']);
|
||||
break;
|
||||
|
||||
default:
|
||||
$attributes[$key] = $item['count'] > 0 ? round(bcdiv($item['sum'], $item['count'], 2), 2) : null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}, $meteorologicalReports);
|
||||
|
||||
/** @var \App\Models\MeteorologicalDailyReport */
|
||||
$meteorologicalDailyReport = MeteorologicalDailyReport::firstOrCreate([
|
||||
'device_id' => $device->id,
|
||||
'reported_at' => $date,
|
||||
], $attributes);
|
||||
|
||||
if (! $meteorologicalDailyReport->wasRecentlyCreated) {
|
||||
$meteorologicalDailyReport->update($attributes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 linkos 水质设备每日报告
|
||||
*/
|
||||
protected function createDailyReportToLinkosWaterQualityDevice(Device $device, Carbon $date): void
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Collection */
|
||||
$waterQualityReports = WaterQualityReport::where('device_id', $device->id)
|
||||
->whereDate('reported_at', $date)
|
||||
->oldest('reported_at')
|
||||
->get();
|
||||
|
||||
if ($waterQualityReports->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$attributes = value(function ($waterQualityReports) {
|
||||
$data = [
|
||||
'chlorine' => ['sum' => 0, 'count' => 0],
|
||||
'conductivity' => ['sum' => 0, 'count' => 0],
|
||||
'oxygen' => ['sum' => 0, 'count' => 0],
|
||||
'ph' => ['sum' => 0, 'count' => 0],
|
||||
'temperature' => ['sum' => 0, 'count' => 0],
|
||||
'turbidity' => ['sum' => 0, 'count' => 0],
|
||||
];
|
||||
|
||||
foreach ($waterQualityReports as $waterQualityReport) {
|
||||
foreach ($data as $k => $item) {
|
||||
if (is_null($v = $waterQualityReport->{$k})) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$item['sum'] = bcadd($item['sum'], $v, 2);
|
||||
$item['count']++;
|
||||
|
||||
$data[$k] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
$attributes = [];
|
||||
|
||||
foreach ($data as $key => $item) {
|
||||
$attributes[$key] = $item['count'] > 0 ? round(bcdiv($item['sum'], $item['count'], 2), 2) : null;
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}, $waterQualityReports);
|
||||
|
||||
/** @var \App\Models\WaterQualityDailyReport */
|
||||
$waterQualityDailyReport = WaterQualityDailyReport::firstOrCreate([
|
||||
'device_id' => $device->id,
|
||||
'reported_at' => $date->format('Y-m-d'),
|
||||
], $attributes);
|
||||
|
||||
if (! $waterQualityDailyReport->wasRecentlyCreated) {
|
||||
$waterQualityDailyReport->update($attributes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,18 +14,15 @@ return new class extends Migration
|
|||
public function up()
|
||||
{
|
||||
Schema::create('devices', function (Blueprint $table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->id();
|
||||
$table->string('name')->comment('设备名称');
|
||||
$table->string('sn')->comment('设备唯一编码');
|
||||
$table->string('powered_by')->nullable()->comment('厂家');
|
||||
$table->unsignedBigInteger('powered_by')->nullable()->comment('厂家');
|
||||
$table->string('model_sn')->nullable()->comment('型号');
|
||||
$table->unsignedTinyInteger('type')->comment('类型: 1 监控设备, 2 土壤设备, 3 水质设备, 4 气象设备');
|
||||
$table->unsignedTinyInteger('state')->default(2)->comment('状态: 0 禁用, 1 在线, 2 离线, 3 故障');
|
||||
$table->text('extends')->nullable()->comment('扩展信息');
|
||||
$table->unsignedTinyInteger('is_recommend')->default(0)->comment('推荐开关');
|
||||
$table->unsignedTinyInteger('is_enable')->default(1)->comment('显示开关');
|
||||
$table->unsignedInteger('sort')->default(0)->comment('排序');
|
||||
$table->string('group_tags')->nullable()->comment('分组标签');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ return new class extends Migration
|
|||
public function up()
|
||||
{
|
||||
Schema::create('regions', function (Blueprint $table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('cover')->nullable()->comment('封面图');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('water_quality_daily_reports', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('device_id')->comment('设备ID');
|
||||
$table->decimal('chlorine', 8, 2)->nullable()->comment('余氯(单位: mg/L)');
|
||||
$table->decimal('conductivity', 8, 2)->nullable()->comment('电导率(单位: us/cm)');
|
||||
$table->decimal('oxygen', 8, 2)->nullable()->comment('溶解氧(单位: mg/L)');
|
||||
$table->decimal('ph', 8, 2)->nullable()->comment('PH');
|
||||
$table->decimal('temperature', 8, 2)->nullable()->comment('温度(单位: ℃)');
|
||||
$table->decimal('turbidity', 8, 2)->nullable()->comment('浊度(单位: NTU)');
|
||||
$table->date('reported_at')->comment('报告日期');
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['device_id', 'reported_at']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('water_quality_daily_reports');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('meteorological_daily_reports', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('device_id');
|
||||
$table->decimal('today_rainfall', 8, 2)->nullable()->comment('今日积雨量 (单位: mm)');
|
||||
$table->decimal('yesterday_rainfall', 8, 2)->nullable()->comment('昨日积雨量 (单位: mm)');
|
||||
$table->decimal('accumulate_rainfall', 8, 2)->nullable()->comment('累积雨量 (单位: mm)');
|
||||
$table->decimal('moment_rainfall', 8, 2)->nullable()->comment('瞬时雨量 (单位: mm)');
|
||||
$table->decimal('pm10', 8, 2)->nullable()->comment('PM10浓度 (单位: ug/m3)');
|
||||
$table->decimal('pm25', 8, 2)->nullable()->comment('PM2.5浓度 (单位: ug/m3)');
|
||||
$table->decimal('box_illumination', 10, 2)->nullable()->comment('百叶箱光照度 (单位: Lux)');
|
||||
$table->decimal('box_pressure', 8, 2)->nullable()->comment('百叶箱大气压力 (单位: Kpa)');
|
||||
$table->decimal('box_co2', 8, 2)->nullable()->comment('百叶箱CO2浓度 (单位: ppm)');
|
||||
$table->decimal('box_temperature', 8, 2)->nullable()->comment('百叶箱温度 (单位: ℃)');
|
||||
$table->decimal('box_humidity', 8, 2)->nullable()->comment('百叶箱湿度 (单位: %RH)');
|
||||
$table->decimal('box_noise', 8, 2)->nullable()->comment('百叶箱噪声 (单位: db)');
|
||||
$table->integer('wind_degree')->nullable()->comment('风向度数');
|
||||
$table->tinyInteger('wind_direction')->nullable()->comment('风向: 0 北风, 1 东北风, 2 东风, 3 东南风, 4 南风, 5 西南风, 6 西风, 7 西北风');
|
||||
$table->integer('wind_power')->nullable()->comment('风力 (单位: 级)');
|
||||
$table->decimal('wind_speed', 8, 2)->nullable()->comment('风速 (单位: m/s)');
|
||||
$table->date('reported_at')->comment('报告日期');
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['device_id', 'reported_at']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('meteorological_daily_reports');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('monitor_modes', function (Blueprint $table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->id();
|
||||
$table->string('name')->comment('名称');
|
||||
$table->unsignedTinyInteger('type')->comment('类型: 1 视频监控, 2 土壤监测, 3 水质监测, 4 气象监测, 5 通风控制');
|
||||
$table->unsignedTinyInteger('is_recommend')->default(0)->comment('推荐开关');
|
||||
$table->unsignedTinyInteger('is_enable')->default(1)->comment('显示开关');
|
||||
$table->unsignedInteger('sort')->default(0)->comment('排序');
|
||||
$table->string('group_tags')->nullable()->comment('分组标签');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('monitor_modes');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('monitor_devices', function (Blueprint $table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('monitor_id');
|
||||
$table->unsignedBigInteger('device_id');
|
||||
$table->text('fields')->nullable()->comment('监测字段');
|
||||
$table->unsignedInteger('sort')->default(0)->comment('排序');
|
||||
|
||||
$table->foreign('monitor_id')->references('id')->on('monitor_modes')->onDelete('cascade');
|
||||
$table->foreign('device_id')->references('id')->on('devices')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('monitor_devices');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('region_monitors', function (Blueprint $table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('region_id');
|
||||
$table->unsignedBigInteger('monitor_id');
|
||||
$table->text('config')->nullable()->comment('配置信息');
|
||||
$table->timestamps();
|
||||
|
||||
$table->foreign('monitor_id')->references('id')->on('monitor_modes')->onDelete('cascade');
|
||||
$table->foreign('region_id')->references('id')->on('regions')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('region_monitors');
|
||||
}
|
||||
};
|
||||
|
|
@ -48,22 +48,26 @@ class AdminMenuSeeder extends Seeder
|
|||
['title' => '稻田列表', 'icon' => 'icon-park:more-app', 'url' => '/custom-region/daotian', 'order'=>2],
|
||||
]
|
||||
],
|
||||
|
||||
['title' => '设备管理', 'icon' => 'icon-park:devices', 'url' => '/devices', 'order'=>6],
|
||||
['title' => '设备数据', 'icon' => 'icon-park:data-switching', 'url' => '', 'order'=>7,
|
||||
['title' => '监测管理', 'icon' => 'icon-park:monitor-one', 'url' => '', 'order'=>6,
|
||||
'children' => [
|
||||
['title' => '监测点位', 'icon' => 'icon-park:monitor-camera', 'url' => '/monitor-modes', 'order'=>1],
|
||||
['title' => '设备管理', 'icon' => 'icon-park:devices', 'url' => '/devices', 'order'=>2],
|
||||
]
|
||||
],
|
||||
['title' => '监测数据', 'icon' => 'icon-park:data-switching', 'url' => '', 'order'=>7,
|
||||
'children' => [
|
||||
['title' => '实时监控', 'icon'=>'icon-park:videocamera', 'url'=> '/custom-region-monitor', 'order'=>1],
|
||||
['title' => '历史视频', 'icon'=>'icon-park:film', 'url'=> '/custom-region-monitor-video', 'order'=>2],
|
||||
['title' => '气象数据', 'icon'=>'icon-park:brightness', 'url'=> '/custom-region-meteorological', 'order'=>3],
|
||||
['title' => '土壤数据', 'icon'=>'icon-park:floor-tile', 'url'=> '/custom-region-water', 'order'=>4],
|
||||
['title' => '气象监测', 'icon'=>'icon-park:brightness', 'url'=> '/custom-region-meteorological', 'order'=>3],
|
||||
['title' => '土壤监测', 'icon'=>'icon-park:floor-tile', 'url'=> '/custom-region-water', 'order'=>4],
|
||||
// ['title' => '水质数据', 'icon'=>'icon-park:diving-bottle', 'url'=> '/custom-region-soil', 'order'=>5],
|
||||
]
|
||||
],
|
||||
['title' => '设备预警', 'icon' => 'icon-park:alarm', 'url' => '', 'order'=>8,
|
||||
['title' => '监测预警', 'icon' => 'icon-park:alarm', 'url' => '', 'order'=>8,
|
||||
'children' => [
|
||||
['title' => '预警设置', 'icon'=>'icon-park:six-circular-connection', 'url'=> '/warning-setting', 'order'=>1],
|
||||
['title' => '报警记录', 'icon'=>'icon-park:massage-chair-one', 'url'=> '/warning-notice', 'order'=>2],
|
||||
]
|
||||
]
|
||||
],
|
||||
// ['title' => '友情链接', 'icon' => 'icon-park:copy-link', 'url' => '/friend-links', 'order'=>9],
|
||||
['title' => '系统管理', 'icon' => 'icon-park:setting', 'url' => '/system', 'order'=>10,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ class KeywordSeeder extends Seeder
|
|||
['key' => 'device-factory', 'name' => '厂家', 'list' => [
|
||||
['name' => 'LINK-OS', 'key'=>'link-os']
|
||||
]],
|
||||
['key' => 'device-group', 'name' => '设备组', 'list' => [
|
||||
['key' => 'monitor-mode-group', 'name' => '监测组', 'list' => [
|
||||
['name' => '农机', 'key'=>'machinery']
|
||||
]],
|
||||
];
|
||||
|
|
|
|||
Loading…
Reference in New Issue