1631 lines
66 KiB
PHP
1631 lines
66 KiB
PHP
|
|
<?php
|
|||
|
|
|
|||
|
|
namespace app\api\controller;
|
|||
|
|
|
|||
|
|
use app\admin\model\Admin;
|
|||
|
|
use app\admin\model\yq\alarm\Alarm;
|
|||
|
|
use app\admin\model\yq\alarm\Trend;
|
|||
|
|
use app\admin\model\yq\base_config\EventType;
|
|||
|
|
use app\admin\model\yq\electronic_waybill\Waybill;
|
|||
|
|
use app\admin\model\yq\park\Park;
|
|||
|
|
use app\admin\model\yq\perimeter\EnterpriseCheck;
|
|||
|
|
use app\admin\model\yq\vehicle\LineLog;
|
|||
|
|
use app\admin\model\yq\vehicle\ParkLineLog;
|
|||
|
|
use app\common\controller\Api;
|
|||
|
|
use app\admin\model\yq\vehicle\Vehicle;
|
|||
|
|
use app\admin\model\yq\base_config\Perimeter;
|
|||
|
|
|
|||
|
|
use fast\Date;
|
|||
|
|
use think\Db;
|
|||
|
|
|
|||
|
|
|
|||
|
|
class YqScreen extends Api
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
protected $noNeedLogin = ['*'];
|
|||
|
|
protected $noNeedRight = ['*'];
|
|||
|
|
|
|||
|
|
//登录查验
|
|||
|
|
public function login_check()
|
|||
|
|
{
|
|||
|
|
// public function login_check($param)
|
|||
|
|
// {
|
|||
|
|
//
|
|||
|
|
// if (empty($param['ad']) || empty($param['salt'])) {
|
|||
|
|
// $this->error( '异常操作!', ['status' => false]);
|
|||
|
|
// }
|
|||
|
|
// $where['admin_username'] = $param['ad'];
|
|||
|
|
// $where['admin_pwd_salt'] = $param['salt'];
|
|||
|
|
// $admin = Db::name('admin')->where($where)->find();
|
|||
|
|
|
|||
|
|
$admin = Admin::get(1);
|
|||
|
|
if ($admin) {
|
|||
|
|
$this->success('正常!', ['status' => true]);
|
|||
|
|
} else {
|
|||
|
|
$this->error('失败!', ['status' => false]);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//大屏地图车辆列表
|
|||
|
|
public function screen_list()
|
|||
|
|
{
|
|||
|
|
$map['is_del'] = array('in', '1,2');
|
|||
|
|
$field = 'id,vehicleNo,longitude,latitude,longitude_84,latitude_84,vec1,vehicle_type,is_waybill,
|
|||
|
|
is_violations,qr_color,positionTime,is_del,zai';
|
|||
|
|
$vehicle_list = Vehicle::where($map)->field($field)->select();
|
|||
|
|
|
|||
|
|
//待优化运单查询
|
|||
|
|
$w_field = 'tow_license,w_mission,waybill_loading,waybill_unloading,sale_product,cargocount,driver_tel';
|
|||
|
|
$day_waybill_list = Waybill::whereTime('waybill_date', 'd')->field($w_field)->select();
|
|||
|
|
$temp = array_column($day_waybill_list, 'tow_license');
|
|||
|
|
|
|||
|
|
if ($vehicle_list) {
|
|||
|
|
foreach ($vehicle_list as $k => $v) {
|
|||
|
|
$vehicle_list[$k]['waybill_status'] = false;
|
|||
|
|
$v_id = in_array($v['vehicleNo'], $temp);
|
|||
|
|
if ($v_id) {
|
|||
|
|
$vehicle_list[$k]['waybill_status'] = true;
|
|||
|
|
$waybill_info = Waybill::whereTime('waybill_date', 'd')->where('tow_license', $v['vehicleNo'])->field($w_field)->find();
|
|||
|
|
$vehicle_list[$k]['waybill_info'] = $waybill_info;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//明宇停车场(count车辆总数;enter_count当日进入车辆数;当日出去车辆数)
|
|||
|
|
$mingyu['count'] = Vehicle::where($map)->where('perimeter_id', 76)->field('id')->count();
|
|||
|
|
|
|||
|
|
$mingyu['enter_count'] = LineLog::whereTime('create_time', 'd')->where(['is_del' => 1, 'perimeter_id' => 76, 'type' => 1])->count();
|
|||
|
|
$mingyu['out_count'] = LineLog::whereTime('create_time', 'd')->where(['is_del' => 1, 'perimeter_id' => 76, 'type' => 2])->count();
|
|||
|
|
$data['vehicle_list'] = $vehicle_list;
|
|||
|
|
$data['mingyu'] = $mingyu;
|
|||
|
|
$this->success('请求成功!', $data);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//大屏地图车辆列表
|
|||
|
|
public function screen_list22()
|
|||
|
|
{
|
|||
|
|
$map['is_del'] = array('in', '1,2');
|
|||
|
|
$field = 'id,vehicleNo,longitude,latitude,longitude_84,latitude_84,vec1,vehicle_type,is_waybill,
|
|||
|
|
is_violations,qr_color,positionTime,is_del,zai';
|
|||
|
|
$vehicle_list = Vehicle::where($map)->field($field)->select();
|
|||
|
|
|
|||
|
|
if ($vehicle_list) {
|
|||
|
|
foreach ($vehicle_list as $k => $v) {
|
|||
|
|
$w_field = 'w_mission,waybill_loading,waybill_unloading,sale_product,cargocount,driver_tel';
|
|||
|
|
$waybill_info = Db::name('waybill_c')->whereTime('waybill_date', 'd')->where('tow_license', $v['vehicleNo'])->field($w_field)->find();
|
|||
|
|
$vehicle_list[$k]['waybill_status'] = false;
|
|||
|
|
if ($waybill_info) {
|
|||
|
|
$vehicle_list[$k]['waybill_status'] = true;
|
|||
|
|
$vehicle_list[$k]['waybill_info'] = $waybill_info;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//明宇停车场(count车辆总数;enter_count当日进入车辆数;当日出去车辆数)
|
|||
|
|
$mingyu['count'] = Vehicle::where($map)->where('perimeter_id', 76)->field('id')->count();
|
|||
|
|
$mingyu['enter_count'] = LineLog::whereTime('create_time', 'd')->where(['is_del' => 1, 'perimeter_id' => 76, 'type' => 1])->count();
|
|||
|
|
$mingyu['out_count'] = LineLog::whereTime('create_time', 'd')->where(['is_del' => 1, 'perimeter_id' => 76, 'type' => 2])->count();
|
|||
|
|
$data['vehicle_list'] = $vehicle_list;
|
|||
|
|
$data['mingyu'] = $mingyu;
|
|||
|
|
$this->success('请求成功!', $data);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//大屏-总览
|
|||
|
|
public function overview()
|
|||
|
|
{
|
|||
|
|
$map['is_del'] = 1;
|
|||
|
|
//园区基本情况
|
|||
|
|
//一级企业 二级企业 三级企业
|
|||
|
|
$info['enterprise_count'] = Perimeter::group('region_lv')->where($map)->field('region_lv,count(id) as num')->select();
|
|||
|
|
|
|||
|
|
//片区情况 - 统计每个片区的车辆数量(取前3个)
|
|||
|
|
$areaStats = $this->getAreaVehicleStatistics();
|
|||
|
|
$info['area'] = [];
|
|||
|
|
// 取前3个片区的车辆数量,如果不足3个则补0
|
|||
|
|
for ($i = 0; $i < 3; $i++) {
|
|||
|
|
$info['area'][] = isset($areaStats[$i]) ? $areaStats[$i]['value'] : 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//道路情况 - 统计道路上的车辆数量总和
|
|||
|
|
$roadStats = $this->getRoadVehicleStatistics();
|
|||
|
|
$info['road_count'] = 0;
|
|||
|
|
if ($roadStats) {
|
|||
|
|
foreach ($roadStats as $road) {
|
|||
|
|
$info['road_count'] += $road['count'];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//卡口流量统计
|
|||
|
|
$info['road_checkpoints'] = [
|
|||
|
|
'name' => ['卡1', '卡2', '卡2', '卡2', '卡2', '卡2'],//卡口名称
|
|||
|
|
'drive_in' => [35, 32, 36, 47, 14, 60],//驶入
|
|||
|
|
'drive_out' => [47, 20, 16, 52, 40, 18]//驶出
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
|
|||
|
|
//近30天报警统计
|
|||
|
|
$info['alarm_count'] = [];
|
|||
|
|
// 计算30天前的日期
|
|||
|
|
$startDate = date('Y-m-d 00:00:00', strtotime('-30 days'));
|
|||
|
|
$endDate = date('Y-m-d 23:59:59');
|
|||
|
|
|
|||
|
|
$event_type = EventType::select();
|
|||
|
|
foreach ($event_type as $k => $v) {
|
|||
|
|
$info['alarm_count'][] = [
|
|||
|
|
'name' => $v['name'],
|
|||
|
|
'value' => Alarm::where('type', $v['id'])
|
|||
|
|
->where('create_time', '>=', $startDate)
|
|||
|
|
->where('create_time', '<=', $endDate)
|
|||
|
|
->count()
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//报警处理情况 - 统计近30天的报警处理情况
|
|||
|
|
$alarmMap = [
|
|||
|
|
'is_del' => 1,
|
|||
|
|
];
|
|||
|
|
// 已处理:res_status = 1(已响应)或 feedback_status = 1(已反馈)
|
|||
|
|
$processed = Alarm::where($alarmMap)
|
|||
|
|
->where('create_time', '>=', $startDate)
|
|||
|
|
->where('create_time', '<=', $endDate)
|
|||
|
|
->where(function($query) {
|
|||
|
|
$query->where('res_status', 1)
|
|||
|
|
->whereOr('feedback_status', 1);
|
|||
|
|
})
|
|||
|
|
->count();
|
|||
|
|
|
|||
|
|
// 未处理:res_status = 0(未响应)且 feedback_status = 0(未反馈)
|
|||
|
|
$untreated = Alarm::where($alarmMap)
|
|||
|
|
->where('create_time', '>=', $startDate)
|
|||
|
|
->where('create_time', '<=', $endDate)
|
|||
|
|
->where('res_status', 0)
|
|||
|
|
->where('feedback_status', 0)
|
|||
|
|
->count();
|
|||
|
|
|
|||
|
|
$he = $processed + $untreated;
|
|||
|
|
$info['alarm_handling'] = [
|
|||
|
|
'count' => array_sum(array_column($info['alarm_count'], 'value')),
|
|||
|
|
'processed' => $processed,
|
|||
|
|
'untreated' => $untreated,
|
|||
|
|
'he' => $he,
|
|||
|
|
'processed_ratio' => $he == 0 ? 0 : round(($processed / $he) * 100, 2),
|
|||
|
|
'untreated_ratio' => $he == 0 ? 0 : round(($untreated / $he) * 100, 2),
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
//园区危化品车辆统计 - 在线/离线(根据定位时间判断,10分钟内更新为在线)
|
|||
|
|
$vehicleMap = ['is_del' => ['in', '1,2']];
|
|||
|
|
// 计算10分钟前的时间戳
|
|||
|
|
$onlineTimeThreshold = time() - 600; // 10分钟 = 600秒
|
|||
|
|
|
|||
|
|
// 查询所有车辆
|
|||
|
|
$allVehicles = Vehicle::where($vehicleMap)
|
|||
|
|
->field('id,vehicleNo,positionTime')
|
|||
|
|
->select();
|
|||
|
|
|
|||
|
|
$online = 0;
|
|||
|
|
$offline = 0;
|
|||
|
|
|
|||
|
|
if ($allVehicles) {
|
|||
|
|
foreach ($allVehicles as $vehicle) {
|
|||
|
|
if (empty($vehicle['positionTime'])) {
|
|||
|
|
$offline++;
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 将定位时间转换为时间戳
|
|||
|
|
$positionTimestamp = is_numeric($vehicle['positionTime'])
|
|||
|
|
? $vehicle['positionTime']
|
|||
|
|
: strtotime($vehicle['positionTime']);
|
|||
|
|
|
|||
|
|
// 如果定位时间在10分钟内,则是在线
|
|||
|
|
if ($positionTimestamp >= $onlineTimeThreshold) {
|
|||
|
|
$online++;
|
|||
|
|
} else {
|
|||
|
|
$offline++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$he = $online + $offline;
|
|||
|
|
$info['vehicle'] = [
|
|||
|
|
'online' => $online,
|
|||
|
|
'offline' => $offline,
|
|||
|
|
'online_ratio' => $he == 0 ? 0 : round(($online / $he) * 100, 2),
|
|||
|
|
'offline_ratio' => $he == 0 ? 0 : round(($offline / $he) * 100, 2)
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
//危化品车流量top5 - 按装货单位统计车流量(装货+卸货)
|
|||
|
|
$waybillMap = [
|
|||
|
|
'is_del' => 1,
|
|||
|
|
'waybill_loading' => ['<>', ''], // 装货单位不为空
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// 统计每个装货单位的装货数量
|
|||
|
|
$loadingStats = Db::name('waybill')
|
|||
|
|
->where($waybillMap)
|
|||
|
|
->where('w_mission', '装货')
|
|||
|
|
->field('waybill_loading, COUNT(*) as count')
|
|||
|
|
->group('waybill_loading')
|
|||
|
|
->select();
|
|||
|
|
|
|||
|
|
// 统计每个装货单位的卸货数量
|
|||
|
|
$unloadingStats = Db::name('waybill')
|
|||
|
|
->where($waybillMap)
|
|||
|
|
->where('w_mission', '卸货')
|
|||
|
|
->field('waybill_loading, COUNT(*) as count')
|
|||
|
|
->group('waybill_loading')
|
|||
|
|
->select();
|
|||
|
|
|
|||
|
|
// 构建装货单位到数量的映射
|
|||
|
|
$loadingMap = [];
|
|||
|
|
$unloadingMap = [];
|
|||
|
|
|
|||
|
|
if ($loadingStats) {
|
|||
|
|
foreach ($loadingStats as $stat) {
|
|||
|
|
$loadingMap[$stat['waybill_loading']] = intval($stat['count']);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if ($unloadingStats) {
|
|||
|
|
foreach ($unloadingStats as $stat) {
|
|||
|
|
$unloadingMap[$stat['waybill_loading']] = intval($stat['count']);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 合并所有装货单位,计算总车流量(装货+卸货)
|
|||
|
|
$allEnterprises = array_unique(array_merge(array_keys($loadingMap), array_keys($unloadingMap)));
|
|||
|
|
$trafficData = [];
|
|||
|
|
|
|||
|
|
foreach ($allEnterprises as $enterprise) {
|
|||
|
|
$loadingCount = isset($loadingMap[$enterprise]) ? $loadingMap[$enterprise] : 0;
|
|||
|
|
$unloadingCount = isset($unloadingMap[$enterprise]) ? $unloadingMap[$enterprise] : 0;
|
|||
|
|
$totalCount = $loadingCount + $unloadingCount;
|
|||
|
|
|
|||
|
|
$trafficData[] = [
|
|||
|
|
'waybill_loading' => $enterprise,
|
|||
|
|
'loading' => $loadingCount,
|
|||
|
|
'unloading' => $unloadingCount,
|
|||
|
|
'total' => $totalCount
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 按总车流量排序,取前5个
|
|||
|
|
usort($trafficData, function($a, $b) {
|
|||
|
|
return $b['total'] - $a['total'];
|
|||
|
|
});
|
|||
|
|
$top5 = array_slice($trafficData, 0, 5);
|
|||
|
|
|
|||
|
|
// 构建返回数据
|
|||
|
|
$nameList = [];
|
|||
|
|
$loadingList = [];
|
|||
|
|
$unloadingList = [];
|
|||
|
|
|
|||
|
|
foreach ($top5 as $item) {
|
|||
|
|
$nameList[] = [
|
|||
|
|
'waybill_loading' => $item['waybill_loading'],
|
|||
|
|
'count' => $item['total']
|
|||
|
|
];
|
|||
|
|
$loadingList[] = $item['loading'];
|
|||
|
|
$unloadingList[] = $item['unloading'];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果不足5个,用空数据补齐
|
|||
|
|
while (count($nameList) < 5) {
|
|||
|
|
$nameList[] = ['waybill_loading' => '', 'count' => 0];
|
|||
|
|
$loadingList[] = 0;
|
|||
|
|
$unloadingList[] = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$info['traffic_volume'] = [
|
|||
|
|
'name' => $nameList,
|
|||
|
|
'loading' => $loadingList, // 装货数量
|
|||
|
|
'unloading' => $unloadingList // 卸货数量
|
|||
|
|
];
|
|||
|
|
//全年运单统计 - 统计当前年份每个月的运单数量
|
|||
|
|
$year = date('Y');
|
|||
|
|
$startDate = "{$year}-01-01 00:00:00";
|
|||
|
|
$endDate = "{$year}-12-31 23:59:59";
|
|||
|
|
|
|||
|
|
// 查询实际数据(只统计未删除的运单)
|
|||
|
|
$waybillMap = ['is_del' => 1];
|
|||
|
|
$actualStats = Db::name('waybill')
|
|||
|
|
->where($waybillMap)
|
|||
|
|
->where('create_time', '>=', $startDate)
|
|||
|
|
->where('create_time', '<=', $endDate)
|
|||
|
|
->field("DATE_FORMAT(create_time, '%Y-%m') as month, COUNT(*) as count")
|
|||
|
|
->group("DATE_FORMAT(create_time, '%Y-%m')")
|
|||
|
|
->select();
|
|||
|
|
|
|||
|
|
$monthlyData = [];
|
|||
|
|
foreach ($actualStats as $stat) {
|
|||
|
|
$month = date('m', strtotime($stat['month']));
|
|||
|
|
$monthlyData[$month] = [
|
|||
|
|
'month' => $month,
|
|||
|
|
'year_month' => $stat['month'],
|
|||
|
|
'count' => intval($stat['count']),
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 构建完整的12个月数据(包含空月份)
|
|||
|
|
$fullYearStats = [];
|
|||
|
|
for ($i = 1; $i <= 12; $i++) {
|
|||
|
|
$month = str_pad($i, 2, '0', STR_PAD_LEFT);
|
|||
|
|
$yearMonth = "{$year}-{$month}";
|
|||
|
|
|
|||
|
|
if (isset($monthlyData[$month])) {
|
|||
|
|
// 有数据的月份
|
|||
|
|
$fullYearStats[] = $monthlyData[$month];
|
|||
|
|
} else {
|
|||
|
|
// 无数据的月份补零
|
|||
|
|
$fullYearStats[] = [
|
|||
|
|
'month' => $month,
|
|||
|
|
'year_month' => $yearMonth,
|
|||
|
|
'count' => 0,
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
$info['year'] = $fullYearStats;
|
|||
|
|
$this->success('请求成功!', $info);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//大屏-车辆码
|
|||
|
|
public function vehicle_code()
|
|||
|
|
{
|
|||
|
|
$map['is_del'] = array('in', '1,2');
|
|||
|
|
//绿码车数量
|
|||
|
|
$info['green_code_count'] = Vehicle::where($map)->where('qr_color', 1)->count();
|
|||
|
|
//黄码车数量
|
|||
|
|
$info['yellow_code_count'] = Vehicle::where($map)->where('qr_color', 2)->count();
|
|||
|
|
//红码车数量
|
|||
|
|
$info['red_code_count'] = Vehicle::where($map)->where('qr_color', 3)->count();
|
|||
|
|
|
|||
|
|
//报警列表 - 只显示当天的报警
|
|||
|
|
$wh_police['is_del'] = 1;
|
|||
|
|
$wh_police['type'] = array('in', '1,2,3,4,5,6');
|
|||
|
|
$field = 'license,name,trigger_type,create_time';
|
|||
|
|
|
|||
|
|
// 查询当天的报警
|
|||
|
|
$police_list['count'] = Alarm::where($wh_police)->whereTime('create_time', 'd')->count();
|
|||
|
|
$police_list['list'] = Alarm::where($wh_police)->whereTime('create_time', 'd')->field($field)->order('create_time desc')->select();
|
|||
|
|
|
|||
|
|
// 如果当天没有报警,显示最近7天的报警
|
|||
|
|
if ($police_list['count'] == 0) {
|
|||
|
|
$police_list['count'] = Alarm::where($wh_police)->whereTime('create_time', '-7 days')->count();
|
|||
|
|
$police_list['list'] = Alarm::where($wh_police)->whereTime('create_time', '-7 days')->field($field)->order('create_time desc')->limit(50)->select();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$data['info'] = $info;//基础信息-左
|
|||
|
|
$data['police_list'] = $police_list;//运单信息-右3
|
|||
|
|
$this->success('请求成功!', $data);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//大屏-车辆动态
|
|||
|
|
public function vehicle_trend()
|
|||
|
|
{
|
|||
|
|
$map['is_del'] = array('in', '1,2');
|
|||
|
|
$park_info = Db::name('perimeter')->where('id', 1)->field('enter_vehicle,out_vehicle')->find();
|
|||
|
|
|
|||
|
|
// 园区围栏坐标(用于判断进出园)
|
|||
|
|
$max_path_json = '[{"lng":"107.01527","lat":"29.895601"},{"lng":"106.997876","lat":"29.89281"},{"lng":"106.991391","lat":"29.887939"},{"lng":"106.985853","lat":"29.880405"},{"lng":"106.981835","lat":"29.871026"},{"lng":"106.960543","lat":"29.849142"},{"lng":"106.950737","lat":"29.83564"},{"lng":"106.945862","lat":"29.824089"},{"lng":"106.943563","lat":"29.814148"},{"lng":"106.945054","lat":"29.799754"},{"lng":"106.942764","lat":"29.783607"},{"lng":"106.970332","lat":"29.766519"},{"lng":"106.983273","lat":"29.751322"},{"lng":"107.017612","lat":"29.737776"},{"lng":"107.050425","lat":"29.734115"},{"lng":"107.064458","lat":"29.737683"},{"lng":"107.064744","lat":"29.739318"},{"lng":"107.058942","lat":"29.748447"},{"lng":"107.055205","lat":"29.762378"},{"lng":"107.071581","lat":"29.77504"},{"lng":"107.086248","lat":"29.789923"},{"lng":"107.088111","lat":"29.796775"},{"lng":"107.084106","lat":"29.807387"},{"lng":"107.080959","lat":"29.81142"},{"lng":"107.068298","lat":"29.813474"},{"lng":"107.06422","lat":"29.813406"},{"lng":"107.060435","lat":"29.82112"},{"lng":"107.050628","lat":"29.827207"},{"lng":"107.04726","lat":"29.828623"},{"lng":"107.046543","lat":"29.829966"},{"lng":"107.04701","lat":"29.830878"},{"lng":"107.04712","lat":"29.834263"},{"lng":"107.044827","lat":"29.838826"},{"lng":"107.053757","lat":"29.842875"},{"lng":"107.056479","lat":"29.849047"},{"lng":"107.057124","lat":"29.85153"},{"lng":"107.056802","lat":"29.853468"},{"lng":"107.060415","lat":"29.86047"},{"lng":"107.061665","lat":"29.864841"},{"lng":"107.054919","lat":"29.881592"},{"lng":"107.052508","lat":"29.894119"},{"lng":"107.040451","lat":"29.898403"},{"lng":"107.028579","lat":"29.89536"},{"lng":"107.014946","lat":"29.895825"},{"lng":"106.997804","lat":"29.89278"}]';
|
|||
|
|
$max_path_arr = json_decode($max_path_json, true);
|
|||
|
|
|
|||
|
|
// 初始化变量
|
|||
|
|
$enterByHour = array_fill(0, 24, 0);
|
|||
|
|
$outByHour = array_fill(0, 24, 0);
|
|||
|
|
|
|||
|
|
// 先从 vehicle_park_line_log 表查询(如果已有数据)
|
|||
|
|
// 注意:vehicle_park_line_log 表的 is_del 字段可能不存在或值不同,所以不添加 is_del 条件
|
|||
|
|
$info['enter_count'] = ParkLineLog::whereTime('create_time', 'd')->where('type', 1)->where('is_del', 1)->count();
|
|||
|
|
$info['out_count'] = ParkLineLog::whereTime('create_time', 'd')->where('type', 2)->where('is_del', 1)->count();
|
|||
|
|
|
|||
|
|
// 如果 vehicle_park_line_log 表没有数据,从轨迹数据实时统计
|
|||
|
|
if ($info['enter_count'] == 0 && $info['out_count'] == 0) {
|
|||
|
|
$enterCount = 0;
|
|||
|
|
$outCount = 0;
|
|||
|
|
|
|||
|
|
// 查询当天的轨迹数据
|
|||
|
|
$todayStart = date('Y-m-d 00:00:00');
|
|||
|
|
$todayEnd = date('Y-m-d 23:59:59');
|
|||
|
|
$vehicleLines = Db::name('vehicle_line')
|
|||
|
|
->where('create_time', '>=', $todayStart)
|
|||
|
|
->where('create_time', '<=', $todayEnd)
|
|||
|
|
->where('is_del', 1)
|
|||
|
|
->field('vehicleNo,line')
|
|||
|
|
->select();
|
|||
|
|
|
|||
|
|
if (empty($vehicleLines)) {
|
|||
|
|
// 如果没有轨迹数据,返回0
|
|||
|
|
$info['enter_count'] = 0;
|
|||
|
|
$info['out_count'] = 0;
|
|||
|
|
} else {
|
|||
|
|
foreach ($vehicleLines as $lineRecord) {
|
|||
|
|
$lineData = json_decode($lineRecord['line'], true);
|
|||
|
|
if (!is_array($lineData) || empty($lineData)) {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 遍历轨迹点,判断进出状态(允许同一辆车多次进出)
|
|||
|
|
foreach ($lineData as $o => $point) {
|
|||
|
|
if (empty($point['coordinate']) || empty($point['create_time'])) {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 解析坐标
|
|||
|
|
$coords = explode(',', $point['coordinate']);
|
|||
|
|
if (count($coords) < 2) {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$point_coord = [
|
|||
|
|
'lng' => floatval($coords[0]),
|
|||
|
|
'lat' => floatval($coords[1])
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// 判断当前点是否在园区内
|
|||
|
|
$vehicle_exist = $this->is_point_in_polygon($point_coord, $max_path_arr);
|
|||
|
|
|
|||
|
|
// 判断上一个点是否在园区内
|
|||
|
|
$up_exist = false;
|
|||
|
|
if ($o > 0 && isset($lineData[$o-1]['coordinate'])) {
|
|||
|
|
$up_coords = explode(',', $lineData[$o-1]['coordinate']);
|
|||
|
|
if (count($up_coords) >= 2) {
|
|||
|
|
$up_point = [
|
|||
|
|
'lng' => floatval($up_coords[0]),
|
|||
|
|
'lat' => floatval($up_coords[1])
|
|||
|
|
];
|
|||
|
|
$up_exist = $this->is_point_in_polygon($up_point, $max_path_arr);
|
|||
|
|
}
|
|||
|
|
} elseif ($o == 0) {
|
|||
|
|
// 第一个点,假设上一个点在园区外
|
|||
|
|
$up_exist = false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 判断是否发生进出变化
|
|||
|
|
if ($vehicle_exist && !$up_exist) {
|
|||
|
|
// 从园区外进入园区内 - 进园
|
|||
|
|
$enterCount++;
|
|||
|
|
|
|||
|
|
// 统计该小时
|
|||
|
|
$pointTime = strtotime($point['create_time']);
|
|||
|
|
if ($pointTime !== false) {
|
|||
|
|
$hour = (int)date('H', $pointTime);
|
|||
|
|
if ($hour >= 0 && $hour < 24) {
|
|||
|
|
$enterByHour[$hour]++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} elseif (!$vehicle_exist && $up_exist) {
|
|||
|
|
// 从园区内离开到园区外 - 出园
|
|||
|
|
$outCount++;
|
|||
|
|
|
|||
|
|
// 统计该小时
|
|||
|
|
$pointTime = strtotime($point['create_time']);
|
|||
|
|
if ($pointTime !== false) {
|
|||
|
|
$hour = (int)date('H', $pointTime);
|
|||
|
|
if ($hour >= 0 && $hour < 24) {
|
|||
|
|
$outByHour[$hour]++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$info['enter_count'] = $enterCount;
|
|||
|
|
$info['out_count'] = $outCount;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 统计每小时进出园次数
|
|||
|
|
$info['park'] = [];
|
|||
|
|
$time_arr = [];
|
|||
|
|
for ($x = 0; $x < 24; $x++) {
|
|||
|
|
$time_arr[$x]['s_time'] = date('Y-m-d ') . $x . ':00:00';
|
|||
|
|
$time_arr[$x]['e_time'] = date('Y-m-d ') . $x . ':59:59';
|
|||
|
|
$info['park']['time'][] = $x;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果 vehicle_park_line_log 表有数据,从表查询
|
|||
|
|
if ($info['enter_count'] > 0 || $info['out_count'] > 0) {
|
|||
|
|
foreach ($time_arr as $k => $v) {
|
|||
|
|
$enter = ParkLineLog::where('create_time', '>=', $v['s_time'])
|
|||
|
|
->where('create_time', '<=', $v['e_time'])
|
|||
|
|
->where('type', 1)
|
|||
|
|
->where('is_del', 1)
|
|||
|
|
->count();
|
|||
|
|
$out = ParkLineLog::where('create_time', '>=', $v['s_time'])
|
|||
|
|
->where('create_time', '<=', $v['e_time'])
|
|||
|
|
->where('type', 2)
|
|||
|
|
->where('is_del', 1)
|
|||
|
|
->count();
|
|||
|
|
$info['park']['enter'][] = $enter;
|
|||
|
|
$info['park']['out'][] = $out;
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
// 如果表没有数据,使用从轨迹数据统计的结果
|
|||
|
|
foreach ($time_arr as $k => $v) {
|
|||
|
|
$info['park']['enter'][] = isset($enterByHour[$k]) ? $enterByHour[$k] : 0;
|
|||
|
|
$info['park']['out'][] = isset($outByHour[$k]) ? $outByHour[$k] : 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//片区车流统计 - 统计每个企业区域(region_type=6)内的车辆数量
|
|||
|
|
$info['area'] = $this->getAreaVehicleStatistics();
|
|||
|
|
|
|||
|
|
//道路情况 - 统计每条道路上的真实车辆数量
|
|||
|
|
$info['road_count'] = $this->getRoadVehicleStatistics();
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
// //园区停止车辆数
|
|||
|
|
// $info['stop_count'] = Vehicle::where($map)->where('vec1', 0)->count();
|
|||
|
|
// //园区行驶车辆数
|
|||
|
|
// $info['driving_count'] = Vehicle::where($map)->where('vec1', '>', 0)->count();
|
|||
|
|
|
|||
|
|
// 园区内行驶停止车辆统计 - 使用轨迹数据统计每个小时的车辆数量
|
|||
|
|
// 获取园区围栏坐标(使用与 vehicle_log 相同的围栏)
|
|||
|
|
$max_path_json = '[{"lng":"107.01527","lat":"29.895601"},{"lng":"106.997876","lat":"29.89281"},{"lng":"106.991391","lat":"29.887939"},{"lng":"106.985853","lat":"29.880405"},{"lng":"106.981835","lat":"29.871026"},{"lng":"106.960543","lat":"29.849142"},{"lng":"106.950737","lat":"29.83564"},{"lng":"106.945862","lat":"29.824089"},{"lng":"106.943563","lat":"29.814148"},{"lng":"106.945054","lat":"29.799754"},{"lng":"106.942764","lat":"29.783607"},{"lng":"106.970332","lat":"29.766519"},{"lng":"106.983273","lat":"29.751322"},{"lng":"107.017612","lat":"29.737776"},{"lng":"107.050425","lat":"29.734115"},{"lng":"107.064458","lat":"29.737683"},{"lng":"107.064744","lat":"29.739318"},{"lng":"107.058942","lat":"29.748447"},{"lng":"107.055205","lat":"29.762378"},{"lng":"107.071581","lat":"29.77504"},{"lng":"107.086248","lat":"29.789923"},{"lng":"107.088111","lat":"29.796775"},{"lng":"107.084106","lat":"29.807387"},{"lng":"107.080959","lat":"29.81142"},{"lng":"107.068298","lat":"29.813474"},{"lng":"107.06422","lat":"29.813406"},{"lng":"107.060435","lat":"29.82112"},{"lng":"107.050628","lat":"29.827207"},{"lng":"107.04726","lat":"29.828623"},{"lng":"107.046543","lat":"29.829966"},{"lng":"107.04701","lat":"29.830878"},{"lng":"107.04712","lat":"29.834263"},{"lng":"107.044827","lat":"29.838826"},{"lng":"107.053757","lat":"29.842875"},{"lng":"107.056479","lat":"29.849047"},{"lng":"107.057124","lat":"29.85153"},{"lng":"107.056802","lat":"29.853468"},{"lng":"107.060415","lat":"29.86047"},{"lng":"107.061665","lat":"29.864841"},{"lng":"107.054919","lat":"29.881592"},{"lng":"107.052508","lat":"29.894119"},{"lng":"107.040451","lat":"29.898403"},{"lng":"107.028579","lat":"29.89536"},{"lng":"107.014946","lat":"29.895825"},{"lng":"106.997804","lat":"29.89278"}]';
|
|||
|
|
$max_path_arr = json_decode($max_path_json, true);
|
|||
|
|
|
|||
|
|
// 获取当前时间
|
|||
|
|
$currentTime = time();
|
|||
|
|
$currentHour = (int)date('H', $currentTime);
|
|||
|
|
$todayDate = date('Y-m-d', $currentTime);
|
|||
|
|
|
|||
|
|
// 初始化今天24小时的数据数组(00:00-23:59)
|
|||
|
|
$fullStats = [];
|
|||
|
|
$fullStats2 = [];
|
|||
|
|
for ($i = 0; $i < 24; $i++) {
|
|||
|
|
$hourTimeShort = sprintf('%02d:00', $i);
|
|||
|
|
$fullStats[] = [
|
|||
|
|
'hour_time' => $hourTimeShort,
|
|||
|
|
'order_count' => 0
|
|||
|
|
];
|
|||
|
|
$fullStats2[] = [
|
|||
|
|
'hour_time' => $hourTimeShort,
|
|||
|
|
'order_count' => 0
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 查询当天的轨迹数据
|
|||
|
|
$todayStart = date('Y-m-d 00:00:00');
|
|||
|
|
$todayEnd = date('Y-m-d 23:59:59');
|
|||
|
|
$vehicleLines = Db::name('vehicle_line')
|
|||
|
|
->where('create_time', '>=', $todayStart)
|
|||
|
|
->where('create_time', '<=', $todayEnd)
|
|||
|
|
->where('is_del', 1)
|
|||
|
|
->field('vehicleNo,line')
|
|||
|
|
->select();
|
|||
|
|
|
|||
|
|
// 批量获取所有车辆的速度信息(用于旧数据备选,如果轨迹点没有保存速度)
|
|||
|
|
$allVehicleNos = [];
|
|||
|
|
foreach ($vehicleLines as $lineRecord) {
|
|||
|
|
$allVehicleNos[] = $lineRecord['vehicleNo'];
|
|||
|
|
}
|
|||
|
|
$allVehicleNos = array_unique($allVehicleNos);
|
|||
|
|
|
|||
|
|
$vehicleSpeedMap = [];
|
|||
|
|
if (!empty($allVehicleNos)) {
|
|||
|
|
$vehicles = Db::name('vehicle')
|
|||
|
|
->where('vehicleNo', 'in', $allVehicleNos)
|
|||
|
|
->where($map)
|
|||
|
|
->field('vehicleNo,vec1')
|
|||
|
|
->select();
|
|||
|
|
foreach ($vehicles as $v) {
|
|||
|
|
$vehicleSpeedMap[$v['vehicleNo']] = $v['vec1'];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 统计每个小时的车辆数量(使用集合去重,避免同一车辆在同一小时被重复计算)
|
|||
|
|
$hourVehicleMap = []; // [小时索引 => [vehicleNo => true]]
|
|||
|
|
$speedStats = ['has_speed_in_point' => 0, 'no_speed_in_point' => 0, 'driving_count' => 0, 'stop_count' => 0];
|
|||
|
|
|
|||
|
|
foreach ($vehicleLines as $lineRecord) {
|
|||
|
|
$lineData = json_decode($lineRecord['line'], true);
|
|||
|
|
if (!is_array($lineData) || empty($lineData)) {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$vehicleNo = $lineRecord['vehicleNo'];
|
|||
|
|
$defaultSpeed = isset($vehicleSpeedMap[$vehicleNo]) ? $vehicleSpeedMap[$vehicleNo] : 0;
|
|||
|
|
|
|||
|
|
// 遍历轨迹点,按小时统计
|
|||
|
|
foreach ($lineData as $point) {
|
|||
|
|
if (empty($point['coordinate']) || empty($point['create_time'])) {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 解析坐标
|
|||
|
|
$coords = explode(',', $point['coordinate']);
|
|||
|
|
if (count($coords) < 2) {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$point_coord = [
|
|||
|
|
'lng' => floatval($coords[0]),
|
|||
|
|
'lat' => floatval($coords[1])
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// 判断是否在园区内
|
|||
|
|
if (!$this->is_point_in_polygon($point_coord, $max_path_arr)) {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取轨迹点的时间
|
|||
|
|
$pointTime = strtotime($point['create_time']);
|
|||
|
|
if ($pointTime === false) {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 计算轨迹点属于哪个小时(今天的小时)
|
|||
|
|
$pointHour = (int)date('H', $pointTime);
|
|||
|
|
$pointDate = date('Y-m-d', $pointTime);
|
|||
|
|
|
|||
|
|
// 只统计今天的数据
|
|||
|
|
if ($pointDate !== $todayDate) {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 直接使用小时作为索引(0-23)
|
|||
|
|
$index = $pointHour;
|
|||
|
|
|
|||
|
|
// 初始化小时数据
|
|||
|
|
if (!isset($hourVehicleMap[$index])) {
|
|||
|
|
$hourVehicleMap[$index] = ['stop' => [], 'driving' => []];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 优先使用轨迹点保存的速度信息
|
|||
|
|
// 如果轨迹点没有speed字段(旧数据),跳过该点,不进行统计
|
|||
|
|
// 因为使用车辆当前速度来判断历史轨迹点是不准确的
|
|||
|
|
if (!isset($point['speed'])) {
|
|||
|
|
// 旧数据没有speed字段,跳过统计
|
|||
|
|
$speedStats['no_speed_in_point']++;
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$pointSpeed = floatval($point['speed']);
|
|||
|
|
$speedStats['has_speed_in_point']++;
|
|||
|
|
|
|||
|
|
// 根据速度判断是停止还是行驶(速度大于0.1km/h视为行驶,避免浮点数精度问题)
|
|||
|
|
// 使用集合去重,同一车辆在同一小时只统计一次
|
|||
|
|
if ($pointSpeed > 0.1) {
|
|||
|
|
$hourVehicleMap[$index]['driving'][$vehicleNo] = true;
|
|||
|
|
$speedStats['driving_count']++;
|
|||
|
|
} else {
|
|||
|
|
$hourVehicleMap[$index]['stop'][$vehicleNo] = true;
|
|||
|
|
$speedStats['stop_count']++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 调试信息(可以注释掉,或记录到日志)
|
|||
|
|
// \think\Log::info('车辆行驶停止统计调试信息: ' . json_encode($speedStats, JSON_UNESCAPED_UNICODE));
|
|||
|
|
|
|||
|
|
// 将统计结果填充到数组中(24小时)
|
|||
|
|
for ($i = 0; $i < 24; $i++) {
|
|||
|
|
if (isset($hourVehicleMap[$i])) {
|
|||
|
|
$fullStats[$i]['order_count'] = count($hourVehicleMap[$i]['stop']);
|
|||
|
|
$fullStats2[$i]['order_count'] = count($hourVehicleMap[$i]['driving']);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 只返回过去12小时的数据(用于前端显示)
|
|||
|
|
// 从当前小时往前推12小时
|
|||
|
|
$resultStats = [];
|
|||
|
|
$resultStats2 = [];
|
|||
|
|
for ($i = 11; $i >= 0; $i--) {
|
|||
|
|
$targetTime = $currentTime - $i * 3600;
|
|||
|
|
$targetHour = (int)date('H', $targetTime);
|
|||
|
|
$hourTimeShort = date('H:00', $targetTime);
|
|||
|
|
|
|||
|
|
$resultStats[] = [
|
|||
|
|
'hour_time' => $hourTimeShort,
|
|||
|
|
'order_count' => isset($fullStats[$targetHour]) ? $fullStats[$targetHour]['order_count'] : 0
|
|||
|
|
];
|
|||
|
|
$resultStats2[] = [
|
|||
|
|
'hour_time' => $hourTimeShort,
|
|||
|
|
'order_count' => isset($fullStats2[$targetHour]) ? $fullStats2[$targetHour]['order_count'] : 0
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$info['stop_count'] = $resultStats;
|
|||
|
|
$info['driving_count'] = $resultStats2;
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
// 园区内车辆重载和空载
|
|||
|
|
$info['heavy'] = [];
|
|||
|
|
$info['empty'] = [];
|
|||
|
|
|
|||
|
|
$this->success('请求成功!', $info);
|
|||
|
|
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//大屏-运单
|
|||
|
|
public function waybill_trend()
|
|||
|
|
{
|
|||
|
|
//运单周数量
|
|||
|
|
// 获取当前日期(包含时间,用于精确查询)
|
|||
|
|
$endDate = date('Y-m-d 23:59:59');
|
|||
|
|
// 计算7天前的日期(从当天0点开始)
|
|||
|
|
$startDate = date('Y-m-d 00:00:00', strtotime('-6 days'));
|
|||
|
|
|
|||
|
|
// 查询实际数据(只统计未删除的运单)
|
|||
|
|
$map_waybill['is_del'] = 1;
|
|||
|
|
$actualStats = Db::name('waybill')
|
|||
|
|
->where($map_waybill)
|
|||
|
|
->where('create_time', '>=', $startDate)
|
|||
|
|
->where('create_time', '<=', $endDate)
|
|||
|
|
->field("DATE_FORMAT(create_time, '%Y-%m-%d') as date,
|
|||
|
|
COUNT(*) as count")
|
|||
|
|
->group("DATE_FORMAT(create_time, '%Y-%m-%d')")
|
|||
|
|
->select();
|
|||
|
|
|
|||
|
|
// 转换为以日期为键的数组方便查找
|
|||
|
|
$week = ['周日','周一','周二','周三','周四','周五','周六'];
|
|||
|
|
$dailyData = [];
|
|||
|
|
foreach ($actualStats as $stat) {
|
|||
|
|
$weekdayNum = date('w', strtotime($stat['date'])); // 0-6表示周日到周六
|
|||
|
|
$dailyData[$stat['date']] = [
|
|||
|
|
'date' => $stat['date'],
|
|||
|
|
'weekday' => $week[$weekdayNum], // 转换为中文星期
|
|||
|
|
'count' => intval($stat['count']),
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
// 构建完整的7天数据(包含空日期)
|
|||
|
|
$fullWeekStats = [];
|
|||
|
|
for ($i = 6; $i >= 0; $i--) {
|
|||
|
|
$currentDate = date('Y-m-d', strtotime("-{$i} days"));
|
|||
|
|
$weekdayNum = date('w', strtotime($currentDate)); // 0-6表示周日到周六
|
|||
|
|
$weekday = $week[$weekdayNum];
|
|||
|
|
if (isset($dailyData[$currentDate])) {
|
|||
|
|
// 有数据的日期
|
|||
|
|
$fullWeekStats[] = $dailyData[$currentDate];
|
|||
|
|
} else {
|
|||
|
|
// 无数据的日期补零
|
|||
|
|
$fullWeekStats[] = [
|
|||
|
|
'date' => $currentDate,
|
|||
|
|
'weekday' => $weekday,
|
|||
|
|
'count' => 0,
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
$info['waybill'] = $fullWeekStats;
|
|||
|
|
|
|||
|
|
//企业货物前10 - 按装货单位统计货物总量
|
|||
|
|
$map_enterprise['is_del'] = 1;
|
|||
|
|
$map_enterprise['waybill_loading'] = ['<>', '']; // 装货单位不为空
|
|||
|
|
|
|||
|
|
// 按装货单位分组,统计每个企业的货物总量(cargocount的SUM)
|
|||
|
|
$enterpriseList = Db::name('waybill')
|
|||
|
|
->where($map_enterprise)
|
|||
|
|
->field('waybill_loading, SUM(cargocount) as total_count')
|
|||
|
|
->group('waybill_loading')
|
|||
|
|
->order('total_count desc')
|
|||
|
|
->limit(10)
|
|||
|
|
->select();
|
|||
|
|
|
|||
|
|
$enterpriseNames = [];
|
|||
|
|
$enterpriseNums = [];
|
|||
|
|
|
|||
|
|
if ($enterpriseList) {
|
|||
|
|
foreach ($enterpriseList as $item) {
|
|||
|
|
$enterpriseNames[] = $item['waybill_loading'] ? $item['waybill_loading'] : '未知企业';
|
|||
|
|
$enterpriseNums[] = floatval($item['total_count']); // 货物总量(吨)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果数据不足10条,用空数据补齐(前端需要固定10条)
|
|||
|
|
$count = count($enterpriseNames);
|
|||
|
|
if ($count < 10) {
|
|||
|
|
for ($i = $count; $i < 10; $i++) {
|
|||
|
|
$enterpriseNames[] = '';
|
|||
|
|
$enterpriseNums[] = 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$info['enterprise'] = [
|
|||
|
|
'name' => $enterpriseNames,
|
|||
|
|
'num' => $enterpriseNums
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
//当日片区货物输入 - 统计装货的运单
|
|||
|
|
$info['in_area'] = $this->getAreaCargoStatistics('in');
|
|||
|
|
|
|||
|
|
//当日片区货物输出 - 统计卸货的运单
|
|||
|
|
$info['out_area'] = $this->getAreaCargoStatistics('out');
|
|||
|
|
$this->success('请求成功!', $info);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//大屏-未查验运单列表
|
|||
|
|
public function uncheck_waybill_list()
|
|||
|
|
{
|
|||
|
|
$limit = input('limit', 20); // 默认20条
|
|||
|
|
$map['is_del'] = 1; // 未删除
|
|||
|
|
$map['check_status'] = 0; // 未查验状态
|
|||
|
|
|
|||
|
|
$field = 'id,waybill_order,tow_license,sale_product,waybill_loading,waybill_unloading,waybill_date,create_time';
|
|||
|
|
$list = Waybill::where($map)
|
|||
|
|
->field($field)
|
|||
|
|
->order('create_time desc')
|
|||
|
|
->limit($limit)
|
|||
|
|
->select();
|
|||
|
|
|
|||
|
|
$result = [];
|
|||
|
|
if ($list) {
|
|||
|
|
foreach ($list as $k => $v) {
|
|||
|
|
// 转换为数组格式
|
|||
|
|
$item = [
|
|||
|
|
'id' => $v['id'],
|
|||
|
|
'waybill_order' => $v['waybill_order'] ? $v['waybill_order'] : '',
|
|||
|
|
'tow_license' => $v['tow_license'] ? $v['tow_license'] : '',
|
|||
|
|
'sale_product' => $v['sale_product'] ? $v['sale_product'] : '',
|
|||
|
|
'waybill_loading' => $v['waybill_loading'] ? $v['waybill_loading'] : '',
|
|||
|
|
'waybill_unloading' => $v['waybill_unloading'] ? $v['waybill_unloading'] : '',
|
|||
|
|
];
|
|||
|
|
// 格式化时间
|
|||
|
|
if ($v['waybill_date']) {
|
|||
|
|
$item['waybill_date'] = date('Y-m-d H:i:s', strtotime($v['waybill_date']));
|
|||
|
|
} else {
|
|||
|
|
$item['waybill_date'] = $v['create_time'] ? date('Y-m-d H:i:s', strtotime($v['create_time'])) : '';
|
|||
|
|
}
|
|||
|
|
$result[] = $item;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$this->success('请求成功!', $result);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//大屏-每日企业车辆进出记录
|
|||
|
|
public function enterprise_vehicle($param)
|
|||
|
|
{
|
|||
|
|
if (empty($param['id'])) {
|
|||
|
|
$this->error('异常操作!');
|
|||
|
|
}
|
|||
|
|
$data['vehicle_info'] = Db::name('perimeter')->where('id', $param['id'])->field('stop_vehicle,vehicle_count,enter_vehicle,out_vehicle')->find();
|
|||
|
|
$this->error('请求成功!', $data);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//大屏-车辆报警列表
|
|||
|
|
public function vehicle_alarm_list()
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
$page = input('page', 1);
|
|||
|
|
$limit = input('limit', 10);
|
|||
|
|
if (input('key')) {
|
|||
|
|
$map['name'] = array('like', "%" . input('key') . "%");
|
|||
|
|
}
|
|||
|
|
//获取车牌号 - 支持通过车辆ID或车牌号查询
|
|||
|
|
$map['is_del'] = array('neq', -1);
|
|||
|
|
$vehicleNo = input('vehicleNo');
|
|||
|
|
if (is_numeric($vehicleNo)) {
|
|||
|
|
// 如果是数字,当作车辆ID处理
|
|||
|
|
$map['license'] = Vehicle::where('id', $vehicleNo)->value('license');
|
|||
|
|
} else {
|
|||
|
|
// 如果是字符串,当作车牌号处理
|
|||
|
|
$map['license'] = $vehicleNo;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$list = Alarm::where($map)->order('create_time desc')->page($page)->limit($limit)->select();
|
|||
|
|
$count = Alarm::where($map)->count();
|
|||
|
|
$data['pages'] = ceil($count / $limit);
|
|||
|
|
$data['list'] = $list;
|
|||
|
|
$this->success('请求成功!', $data);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//大屏按钮-车辆详情
|
|||
|
|
public function vehicle_detail()
|
|||
|
|
{
|
|||
|
|
$param = input();
|
|||
|
|
|
|||
|
|
if (empty($param['id'])) {
|
|||
|
|
$this->error('异常操作!');
|
|||
|
|
}
|
|||
|
|
$field = 'vehicleNo,plateColor,ownerName,businessScopeName,transdCertificateCode,certificateEffdate,certificateExpdate,licenseIssueOrganCode';
|
|||
|
|
// 支持通过车辆ID或车牌号查询
|
|||
|
|
if (is_numeric($param['id'])) {
|
|||
|
|
// 如果是数字,当作车辆ID处理
|
|||
|
|
$vehicle_info = Vehicle::where('id', $param['id'])->field($field)->find();
|
|||
|
|
} else {
|
|||
|
|
// 如果是字符串,当作车牌号处理,先查询车辆ID
|
|||
|
|
$vehicleId = Vehicle::where('vehicleNo', $param['id'])->value('id');
|
|||
|
|
if (empty($vehicleId)) {
|
|||
|
|
$this->error('未找到该车辆信息!');
|
|||
|
|
}
|
|||
|
|
$vehicle_info = Vehicle::where('id', $vehicleId)->field($field)->find();
|
|||
|
|
}
|
|||
|
|
$url = 'http://47.108.219.88:5000/api/httpserver/vehicleInfo?vehicleNo=' . rawurlencode($vehicle_info['vehicleNo']) . '&plateColor=' . $vehicle_info['plateColor'];
|
|||
|
|
$header = array();
|
|||
|
|
$ch = curl_init();
|
|||
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
|
|||
|
|
curl_setopt($ch, CURLOPT_URL, $url);
|
|||
|
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
|
|||
|
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
|
|||
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
|||
|
|
$output = curl_exec($ch);
|
|||
|
|
curl_close($ch);
|
|||
|
|
|
|||
|
|
$json = json_decode($output, true);
|
|||
|
|
if (empty($json['body'])) {
|
|||
|
|
$list = [
|
|||
|
|
'vehicleNo' => '',
|
|||
|
|
'ownerName' => '',
|
|||
|
|
'licenseIssueOrganCode' => '',
|
|||
|
|
'transCertificateCode' => '',
|
|||
|
|
'transCertificateWord' => '',
|
|||
|
|
'businessScopeName' => '',
|
|||
|
|
'certificateEffdate' => '',
|
|||
|
|
'certificateExpdate' => '',
|
|||
|
|
];
|
|||
|
|
} else {
|
|||
|
|
$list = $json['body'];
|
|||
|
|
}
|
|||
|
|
$vehicle_info = array_merge($vehicle_info, $list);
|
|||
|
|
$this->success('操作成功!', $vehicle_info);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//大屏按钮-车辆入园记录列表
|
|||
|
|
public function vehicle_park_list()
|
|||
|
|
{
|
|||
|
|
// 支持通过车辆ID或车牌号查询
|
|||
|
|
$vehicleNoInput = input('vehicleNo');
|
|||
|
|
if (is_numeric($vehicleNoInput)) {
|
|||
|
|
// 如果是数字,当作车辆ID处理
|
|||
|
|
$param['vehicleNo'] = Vehicle::where('id', $vehicleNoInput)->value('vehicleNo');
|
|||
|
|
} else {
|
|||
|
|
// 如果是字符串,当作车牌号处理
|
|||
|
|
$param['vehicleNo'] = $vehicleNoInput;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (empty($param['vehicleNo'])) {
|
|||
|
|
$this->error('异常操作!');
|
|||
|
|
}
|
|||
|
|
$page = input('page', 1);
|
|||
|
|
$limit = input('limit', 10);
|
|||
|
|
$map['is_del'] = array('neq', -1);
|
|||
|
|
$map['tractor_license'] = $param['vehicleNo'];
|
|||
|
|
$field = 'tractor_license,mission,status,create_time';
|
|||
|
|
$list = Park::where($map)->order('create_time desc')->field($field)->page($page)->limit($limit)->select();
|
|||
|
|
$count = Park::where($map)->count();
|
|||
|
|
$data['pages'] = ceil($count / $limit);
|
|||
|
|
$data['list'] = $list;
|
|||
|
|
$this->success('请求成功!', $data);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//大屏按钮-车辆运单记录列表
|
|||
|
|
public function vehicle_waybill_list()
|
|||
|
|
{
|
|||
|
|
// 支持通过车辆ID或车牌号查询
|
|||
|
|
$vehicleNoInput = input('vehicleNo');
|
|||
|
|
if (is_numeric($vehicleNoInput)) {
|
|||
|
|
// 如果是数字,当作车辆ID处理
|
|||
|
|
$param['vehicleNo'] = Vehicle::where('id', $vehicleNoInput)->value('vehicleNo');
|
|||
|
|
} else {
|
|||
|
|
// 如果是字符串,当作车牌号处理
|
|||
|
|
$param['vehicleNo'] = $vehicleNoInput;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (empty($param['vehicleNo'])) {
|
|||
|
|
$this->error('异常操作!');
|
|||
|
|
}
|
|||
|
|
$page = input('page', 1);
|
|||
|
|
$limit = input('limit', 10);
|
|||
|
|
if (isset($param['mission']) && !empty($param['mission'])) {
|
|||
|
|
$map['w_mission'] = $param['mission'];
|
|||
|
|
}
|
|||
|
|
$map['is_del'] = array('neq', -1);
|
|||
|
|
$map['tow_license'] = $param['vehicleNo'];
|
|||
|
|
$list = Waybill::where($map)->order('create_time desc')->page($page)->limit($limit)->select();
|
|||
|
|
$count = Waybill::where($map)->count();
|
|||
|
|
if ($list) {
|
|||
|
|
foreach ($list as $k => &$v) {
|
|||
|
|
$v->check_name = '';
|
|||
|
|
$v->check_status_record = '';
|
|||
|
|
$record_list = EnterpriseCheck::where('waybill_id', $v['id'])->field('check_uid,check_status')->find();
|
|||
|
|
if ($record_list) {
|
|||
|
|
$v->check_name = Perimeter::where('id', $record_list['check_uid'])->value('name');
|
|||
|
|
$v->check_status_record = $record_list['check_status'];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
$data['pages'] = ceil($count / $limit);
|
|||
|
|
$data['list'] = $list;
|
|||
|
|
$this->success('请求成功!', $data);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//大屏按钮-车辆行驶轨迹
|
|||
|
|
public function vehicle_history()
|
|||
|
|
{
|
|||
|
|
$param = input();
|
|||
|
|
// 支持通过车辆ID或车牌号查询
|
|||
|
|
$vehicleNoInput = input('vehicleNo');
|
|||
|
|
if (is_numeric($vehicleNoInput)) {
|
|||
|
|
// 如果是数字,当作车辆ID处理
|
|||
|
|
$vehicleNo = Vehicle::where('id', $vehicleNoInput)->value('vehicleNo');
|
|||
|
|
} else {
|
|||
|
|
// 如果是字符串,当作车牌号处理
|
|||
|
|
$vehicleNo = $vehicleNoInput;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (empty($vehicleNo)) {
|
|||
|
|
$this->error('异常操作!');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 处理日期参数:如果提供了 reservation(日期),使用该日期;否则使用今天
|
|||
|
|
$reservation = input('reservation', '');
|
|||
|
|
if ($reservation) {
|
|||
|
|
// 验证日期格式
|
|||
|
|
$date = strtotime($reservation);
|
|||
|
|
if ($date === false) {
|
|||
|
|
$this->error('日期格式错误!');
|
|||
|
|
}
|
|||
|
|
$dateStr = date('Y-m-d', $date);
|
|||
|
|
} else {
|
|||
|
|
$dateStr = date('Y-m-d');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 查询指定日期的轨迹数据
|
|||
|
|
$table = 'vehicle_log';
|
|||
|
|
$map['vehicleNo'] = $vehicleNo;
|
|||
|
|
// 添加日期过滤:查询指定日期的数据
|
|||
|
|
// vehicle_log 表使用 positionTime 或 V_carettime 字段存储时间
|
|||
|
|
$dateStart = $dateStr . ' 00:00:00';
|
|||
|
|
$dateEnd = $dateStr . ' 23:59:59';
|
|||
|
|
|
|||
|
|
// 查询指定日期的轨迹数据
|
|||
|
|
// 优先使用 positionTime 字段,如果为空则使用 V_carettime 字段
|
|||
|
|
$list = Db::name($table)
|
|||
|
|
->where($map)
|
|||
|
|
->where(function($query) use ($dateStart, $dateEnd) {
|
|||
|
|
// 使用 positionTime 字段进行日期过滤(优先)
|
|||
|
|
$query->where('positionTime', '>=', $dateStart)
|
|||
|
|
->where('positionTime', '<=', $dateEnd);
|
|||
|
|
})
|
|||
|
|
->whereOr(function($query) use ($map, $dateStart, $dateEnd) {
|
|||
|
|
// 如果 positionTime 为空或无效,使用 V_carettime 字段
|
|||
|
|
$query->where($map)
|
|||
|
|
->where(function($q) {
|
|||
|
|
$q->where('positionTime', '')
|
|||
|
|
->whereOr('positionTime', 'null')
|
|||
|
|
->whereOr('positionTime', null);
|
|||
|
|
})
|
|||
|
|
->where('V_carettime', '>=', $dateStart)
|
|||
|
|
->where('V_carettime', '<=', $dateEnd);
|
|||
|
|
})
|
|||
|
|
->field('longitude,latitude,positionTime,V_carettime')
|
|||
|
|
->order('id asc')
|
|||
|
|
->select();
|
|||
|
|
|
|||
|
|
// 如果还是没有结果,尝试只使用 V_carettime 字段(兼容旧数据)
|
|||
|
|
if (empty($list)) {
|
|||
|
|
$list = Db::name($table)
|
|||
|
|
->where($map)
|
|||
|
|
->where('V_carettime', '>=', $dateStart)
|
|||
|
|
->where('V_carettime', '<=', $dateEnd)
|
|||
|
|
->field('longitude,latitude')
|
|||
|
|
->order('id asc')
|
|||
|
|
->select();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果仍然没有结果,尝试查询 vehicle_line 表(轨迹数据可能存储在这里)
|
|||
|
|
if (empty($list)) {
|
|||
|
|
// vehicle_line 表存储的是 JSON 格式的轨迹数据
|
|||
|
|
$lineRecord = Db::name('vehicle_line')
|
|||
|
|
->where('vehicleNo', $vehicleNo)
|
|||
|
|
->where('create_time', '>=', $dateStart)
|
|||
|
|
->where('create_time', '<=', $dateEnd)
|
|||
|
|
->where('is_del', 1)
|
|||
|
|
->field('line')
|
|||
|
|
->order('id asc')
|
|||
|
|
->select();
|
|||
|
|
|
|||
|
|
if ($lineRecord && count($lineRecord) > 0) {
|
|||
|
|
// 解析 JSON 格式的轨迹数据
|
|||
|
|
$list = [];
|
|||
|
|
foreach ($lineRecord as $record) {
|
|||
|
|
$lineData = json_decode($record['line'], true);
|
|||
|
|
if (is_array($lineData) && count($lineData) > 0) {
|
|||
|
|
foreach ($lineData as $point) {
|
|||
|
|
if (isset($point['coordinate']) && !empty($point['coordinate'])) {
|
|||
|
|
$coords = explode(',', $point['coordinate']);
|
|||
|
|
if (count($coords) >= 2) {
|
|||
|
|
$list[] = [
|
|||
|
|
'longitude' => floatval($coords[0]),
|
|||
|
|
'latitude' => floatval($coords[1])
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$coordinate = '';
|
|||
|
|
if ($list && count($list) > 0) {
|
|||
|
|
foreach ($list as $k => $v) {
|
|||
|
|
if (empty($v['longitude']) || empty($v['latitude'])) {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
$str = $this->getWgs84($v['longitude'] . ',' . $v['latitude']);
|
|||
|
|
$coordinate .= $str['lon'] . ',' . $str['lat'] . ';';
|
|||
|
|
}
|
|||
|
|
if (!empty($coordinate)) {
|
|||
|
|
$coordinate = substr($coordinate, 0, strlen($coordinate) - 1);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果没有查询到数据,返回默认值
|
|||
|
|
if (empty($coordinate)) {
|
|||
|
|
$coordinate = '106.964108,29.793287';//默认初始值
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$data['coordinate'] = $coordinate;
|
|||
|
|
$this->success('请求成功!', $data);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//车辆码 一小时请求一次
|
|||
|
|
public function getHourData()
|
|||
|
|
{
|
|||
|
|
//园区当月车辆进出列表
|
|||
|
|
$month_arr = [];
|
|||
|
|
$m = date('m');
|
|||
|
|
$y = date('Y');
|
|||
|
|
$month = Date::days_in_month(date($m), date($y));
|
|||
|
|
for ($i = 0; $i < $month; $i++) {
|
|||
|
|
// 格式化日期,确保是两位数:2025-11-01 而不是 2025-11-1
|
|||
|
|
$day = str_pad($i + 1, 2, '0', STR_PAD_LEFT);
|
|||
|
|
$month_arr[$i]['month'] = $y . '-' . $m . '-' . $day;
|
|||
|
|
$month_arr[$i]['green_count'] = 0;
|
|||
|
|
$month_arr[$i]['yellow_count'] = 0;
|
|||
|
|
$month_arr[$i]['red_count'] = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 方案1:优先使用 vehicle_park_line_log 表(如果表存在且有数据)
|
|||
|
|
// 方案2:如果 vehicle_park_line_log 表没有数据,则使用 vehicle 表统计每天首次出现的车辆
|
|||
|
|
foreach ($month_arr as $k => $v) {
|
|||
|
|
$dateStr = $v['month'];
|
|||
|
|
$dateStart = $dateStr . ' 00:00:00';
|
|||
|
|
$dateEnd = $dateStr . ' 23:59:59';
|
|||
|
|
|
|||
|
|
// 先尝试从 vehicle_park_line_log 表查询
|
|||
|
|
$park_log = ParkLineLog::where('is_del', 1)
|
|||
|
|
->where('type', 1)
|
|||
|
|
->whereTime('create_time', 'between', [$dateStart, $dateEnd])
|
|||
|
|
->field('vehicleNo,create_time')
|
|||
|
|
->select();
|
|||
|
|
|
|||
|
|
if ($park_log && count($park_log) > 0) {
|
|||
|
|
// 使用 vehicle_park_line_log 表的数据
|
|||
|
|
foreach ($park_log as $a => $b) {
|
|||
|
|
$code = Vehicle::where('vehicleNo', $b['vehicleNo'])
|
|||
|
|
->where('is_del', 'in', '1,2')
|
|||
|
|
->value('qr_color');
|
|||
|
|
if ($code == 1) {
|
|||
|
|
$month_arr[$k]['green_count'] += 1;
|
|||
|
|
} elseif ($code == 2) {
|
|||
|
|
$month_arr[$k]['yellow_count'] += 1;
|
|||
|
|
} elseif ($code == 3) {
|
|||
|
|
$month_arr[$k]['red_count'] += 1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
// 如果 vehicle_park_line_log 表没有数据,使用 vehicle 表统计
|
|||
|
|
// 统计每天首次出现的车辆(按车牌号去重)
|
|||
|
|
$vehicles = Db::name('vehicle')
|
|||
|
|
->where('is_del', 'in', '1,2')
|
|||
|
|
->where('create_time', '>=', $dateStart)
|
|||
|
|
->where('create_time', '<=', $dateEnd)
|
|||
|
|
->field('vehicleNo, qr_color')
|
|||
|
|
->group('vehicleNo')
|
|||
|
|
->select();
|
|||
|
|
|
|||
|
|
if ($vehicles) {
|
|||
|
|
foreach ($vehicles as $vehicle) {
|
|||
|
|
$code = $vehicle['qr_color'];
|
|||
|
|
if ($code == 1) {
|
|||
|
|
$month_arr[$k]['green_count'] += 1;
|
|||
|
|
} elseif ($code == 2) {
|
|||
|
|
$month_arr[$k]['yellow_count'] += 1;
|
|||
|
|
} elseif ($code == 3) {
|
|||
|
|
$month_arr[$k]['red_count'] += 1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
$info['month_arr'] = $month_arr;//车辆码 一个小时自动请求
|
|||
|
|
//当日园区进入车辆数
|
|||
|
|
$park_same_day_count = ParkLineLog::whereTime('create_time', 'd')->where(['is_del' => 1, 'type' => 1])->count();
|
|||
|
|
//当日入园上报数
|
|||
|
|
$apply_count = Park::whereTime('create_time', 'd')->where('status', 1)->count();
|
|||
|
|
//当日运单上报数
|
|||
|
|
$waybill_count = Waybill::whereTime('create_time', 'd')->where('is_del', 1)->count();
|
|||
|
|
$report_count = $apply_count + $waybill_count;
|
|||
|
|
|
|||
|
|
$info['park_same_day_count'] = $park_same_day_count;
|
|||
|
|
$info['report_count'] = $report_count;
|
|||
|
|
//当日入园未上报数
|
|||
|
|
$info['no_report_count'] = $park_same_day_count - $report_count;
|
|||
|
|
|
|||
|
|
$this->success('请求成功!', $info);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public function getWgs84($par)
|
|||
|
|
{
|
|||
|
|
$result = array(); // 转换后的结果
|
|||
|
|
$tokens = preg_split('/[\r\n]+/', $par);
|
|||
|
|
|
|||
|
|
foreach ($tokens as $token) {
|
|||
|
|
if (false !== strpos($token, '=')) {
|
|||
|
|
list($key, $value) = explode('=', $token, 2);
|
|||
|
|
$result[$key] = $value;
|
|||
|
|
} else
|
|||
|
|
$result[] = $token;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
foreach ($result as $k => $v) {
|
|||
|
|
if ($v) {
|
|||
|
|
$Varr = explode(',', $v);
|
|||
|
|
$res = $this->bd_decrypt($Varr[0], $Varr[1]);
|
|||
|
|
$arr = [
|
|||
|
|
'lon' => number_format($res['gg_lon'], 6),
|
|||
|
|
'lat' => number_format($res['gg_lat'], 6),
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return $arr;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//BD-09(百度) 坐标转换成 GCJ-02(火星,高德) 坐标
|
|||
|
|
//@param bd_lon 百度经度
|
|||
|
|
//@param bd_lat 百度纬度
|
|||
|
|
public function bd_decrypt($bd_lon, $bd_lat)
|
|||
|
|
{
|
|||
|
|
$x_pi = 3.14159265358979324 * 3000.0 / 180.0;
|
|||
|
|
$x = $bd_lon - 0.0065;
|
|||
|
|
$y = $bd_lat - 0.006;
|
|||
|
|
$z = sqrt($x * $x + $y * $y) - 0.00002 * sin($y * $x_pi);
|
|||
|
|
$theta = atan2($y, $x) - 0.000003 * cos($x * $x_pi);
|
|||
|
|
$data['gg_lon'] = $z * cos($theta);
|
|||
|
|
$data['gg_lat'] = $z * sin($theta);
|
|||
|
|
return $data;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 统计每个片区的车辆数量
|
|||
|
|
* @return array
|
|||
|
|
*/
|
|||
|
|
private function getAreaVehicleStatistics()
|
|||
|
|
{
|
|||
|
|
// 查询所有企业区域(region_type=6)作为片区
|
|||
|
|
$areas = Perimeter::where('region_type', 6)
|
|||
|
|
->where('is_del', 1)
|
|||
|
|
->where('info', '<>', '')
|
|||
|
|
->field('id,name,info')
|
|||
|
|
->select();
|
|||
|
|
|
|||
|
|
if (empty($areas)) {
|
|||
|
|
// 如果没有配置片区,返回空数组
|
|||
|
|
return [];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 查询所有车辆
|
|||
|
|
$vehicles = Vehicle::where('is_del', 'in', '1,2')
|
|||
|
|
->field('id,vehicleNo,longitude,latitude')
|
|||
|
|
->select();
|
|||
|
|
|
|||
|
|
$areaStats = [];
|
|||
|
|
|
|||
|
|
// 遍历每个片区
|
|||
|
|
foreach ($areas as $area) {
|
|||
|
|
// 解析片区坐标
|
|||
|
|
$polygon = $this->parsePerimeterCoords($area['info']);
|
|||
|
|
if (empty($polygon)) {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$vehicleCount = 0;
|
|||
|
|
|
|||
|
|
// 统计在该片区内的车辆数量
|
|||
|
|
foreach ($vehicles as $vehicle) {
|
|||
|
|
if (empty($vehicle['longitude']) || empty($vehicle['latitude'])) {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$point = [
|
|||
|
|
'lng' => floatval($vehicle['longitude']),
|
|||
|
|
'lat' => floatval($vehicle['latitude'])
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
if ($this->is_point_in_polygon($point, $polygon)) {
|
|||
|
|
$vehicleCount++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$areaStats[] = [
|
|||
|
|
'name' => $area['name'],
|
|||
|
|
'value' => $vehicleCount
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果没有统计数据,返回空数组
|
|||
|
|
return $areaStats;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 统计每条道路上的车辆数量
|
|||
|
|
* @return array
|
|||
|
|
*/
|
|||
|
|
private function getRoadVehicleStatistics()
|
|||
|
|
{
|
|||
|
|
// 查询所有道路(region_type=5)
|
|||
|
|
$roads = Perimeter::where('region_type', 5)
|
|||
|
|
->where('is_del', 1)
|
|||
|
|
->where('info', '<>', '')
|
|||
|
|
->field('id,name,info')
|
|||
|
|
->select();
|
|||
|
|
|
|||
|
|
if (empty($roads)) {
|
|||
|
|
// 如果没有配置道路,返回空数组
|
|||
|
|
return [];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 查询所有车辆
|
|||
|
|
$vehicles = Vehicle::where('is_del', 'in', '1,2')
|
|||
|
|
->field('id,vehicleNo,longitude,latitude')
|
|||
|
|
->select();
|
|||
|
|
|
|||
|
|
$roadStats = [];
|
|||
|
|
|
|||
|
|
// 遍历每条道路
|
|||
|
|
foreach ($roads as $road) {
|
|||
|
|
// 解析道路坐标
|
|||
|
|
$polygon = $this->parsePerimeterCoords($road['info']);
|
|||
|
|
if (empty($polygon)) {
|
|||
|
|
// 如果没有坐标信息,返回0
|
|||
|
|
$roadStats[] = [
|
|||
|
|
'id' => $road['id'],
|
|||
|
|
'name' => $road['name'],
|
|||
|
|
'count' => 0
|
|||
|
|
];
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$vehicleCount = 0;
|
|||
|
|
|
|||
|
|
// 统计在该道路上的车辆数量
|
|||
|
|
foreach ($vehicles as $vehicle) {
|
|||
|
|
if (empty($vehicle['longitude']) || empty($vehicle['latitude'])) {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$point = [
|
|||
|
|
'lng' => floatval($vehicle['longitude']),
|
|||
|
|
'lat' => floatval($vehicle['latitude'])
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
if ($this->is_point_in_polygon($point, $polygon)) {
|
|||
|
|
$vehicleCount++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$roadStats[] = [
|
|||
|
|
'id' => $road['id'],
|
|||
|
|
'name' => $road['name'],
|
|||
|
|
'count' => $vehicleCount
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果没有统计数据,返回空数组
|
|||
|
|
return $roadStats;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 统计片区货物输入/输出
|
|||
|
|
* @param string $type 'in' 表示货物输入(装货),'out' 表示货物输出(卸货)
|
|||
|
|
* @return array
|
|||
|
|
*/
|
|||
|
|
private function getAreaCargoStatistics($type = 'in')
|
|||
|
|
{
|
|||
|
|
// 查询所有企业区域(region_type=6)作为片区
|
|||
|
|
$areas = Perimeter::where('region_type', 6)
|
|||
|
|
->where('is_del', 1)
|
|||
|
|
->field('id,name')
|
|||
|
|
->select();
|
|||
|
|
|
|||
|
|
if (empty($areas)) {
|
|||
|
|
// 如果没有配置片区,返回空数组
|
|||
|
|
return [];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取当天的日期(使用waybill_date字段,表示提货日期)
|
|||
|
|
$todayDate = date('Y-m-d');
|
|||
|
|
|
|||
|
|
// 根据类型确定查询字段和条件
|
|||
|
|
if ($type === 'in') {
|
|||
|
|
// 货物输入:统计装货的运单
|
|||
|
|
$enterpriseField = 'waybill_loading';
|
|||
|
|
$missionCondition = '装货';
|
|||
|
|
} else {
|
|||
|
|
// 货物输出:统计卸货的运单
|
|||
|
|
$enterpriseField = 'waybill_unloading';
|
|||
|
|
$missionCondition = '卸货';
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 查询当日的运单数据(按提货日期统计)
|
|||
|
|
$waybillMap = [
|
|||
|
|
'is_del' => 1,
|
|||
|
|
'w_mission' => $missionCondition,
|
|||
|
|
$enterpriseField => ['<>', ''], // 装货/卸货单位不为空
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
$waybills = Db::name('waybill')
|
|||
|
|
->where($waybillMap)
|
|||
|
|
->whereTime('waybill_date', 'd') // 使用waybill_date字段,统计当天的运单
|
|||
|
|
->field("{$enterpriseField} as enterprise_name, SUM(cargocount) as total_count")
|
|||
|
|
->group($enterpriseField)
|
|||
|
|
->select();
|
|||
|
|
|
|||
|
|
// 构建企业名称到货物数量的映射
|
|||
|
|
$enterpriseCargoMap = [];
|
|||
|
|
if ($waybills) {
|
|||
|
|
foreach ($waybills as $waybill) {
|
|||
|
|
$enterpriseName = $waybill['enterprise_name'];
|
|||
|
|
$enterpriseCargoMap[$enterpriseName] = floatval($waybill['total_count']);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 统计每个片区的货物总量
|
|||
|
|
$areaStats = [];
|
|||
|
|
foreach ($areas as $area) {
|
|||
|
|
$areaName = $area['name'];
|
|||
|
|
$totalCargo = 0;
|
|||
|
|
|
|||
|
|
// 遍历运单数据,匹配装货/卸货单位与片区名称
|
|||
|
|
// 这里使用名称匹配,如果装货/卸货单位包含片区名称,则计入该片区
|
|||
|
|
foreach ($enterpriseCargoMap as $enterpriseName => $cargoCount) {
|
|||
|
|
// 如果企业名称与片区名称匹配(完全匹配或包含关系)
|
|||
|
|
if ($enterpriseName == $areaName || strpos($enterpriseName, $areaName) !== false || strpos($areaName, $enterpriseName) !== false) {
|
|||
|
|
$totalCargo += $cargoCount;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$areaStats[] = [
|
|||
|
|
'name' => $areaName,
|
|||
|
|
'value' => round($totalCargo, 2) // 保留2位小数
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果没有统计数据,至少返回片区名称,值为0
|
|||
|
|
if (empty($areaStats)) {
|
|||
|
|
foreach ($areas as $area) {
|
|||
|
|
$areaStats[] = [
|
|||
|
|
'name' => $area['name'],
|
|||
|
|
'value' => 0
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return $areaStats;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 解析周界坐标字符串为多边形数组
|
|||
|
|
* @param string $info 坐标字符串,格式:lng,lat;lng,lat;...
|
|||
|
|
* @return array
|
|||
|
|
*/
|
|||
|
|
private function parsePerimeterCoords($info)
|
|||
|
|
{
|
|||
|
|
if (empty($info)) {
|
|||
|
|
return [];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$polygon = [];
|
|||
|
|
$points = explode(';', $info);
|
|||
|
|
|
|||
|
|
foreach ($points as $point) {
|
|||
|
|
$coords = explode(',', $point);
|
|||
|
|
if (count($coords) >= 2) {
|
|||
|
|
$polygon[] = [
|
|||
|
|
'lng' => floatval(trim($coords[0])),
|
|||
|
|
'lat' => floatval(trim($coords[1]))
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return $polygon;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 判断一个坐标是否在一个多边形内
|
|||
|
|
* @param array $point 点坐标 ['lng' => x, 'lat' => y]
|
|||
|
|
* @param array $pts 多边形坐标数组
|
|||
|
|
* @return bool
|
|||
|
|
*/
|
|||
|
|
private function is_point_in_polygon($point, $pts)
|
|||
|
|
{
|
|||
|
|
$N = count($pts);
|
|||
|
|
if ($N < 3) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$boundOrVertex = true;
|
|||
|
|
$intersectCount = 0;
|
|||
|
|
$precision = 2e-10;
|
|||
|
|
$p1 = 0;
|
|||
|
|
$p2 = 0;
|
|||
|
|
$p = $point;
|
|||
|
|
|
|||
|
|
$p1 = $pts[0];
|
|||
|
|
for ($i = 1; $i <= $N; ++$i) {
|
|||
|
|
if ($p['lng'] == $p1['lng'] && $p['lat'] == $p1['lat']) {
|
|||
|
|
return $boundOrVertex;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$p2 = $pts[$i % $N];
|
|||
|
|
if ($p['lat'] < min($p1['lat'], $p2['lat']) || $p['lat'] > max($p1['lat'], $p2['lat'])) {
|
|||
|
|
$p1 = $p2;
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if ($p['lat'] > min($p1['lat'], $p2['lat']) && $p['lat'] < max($p1['lat'], $p2['lat'])) {
|
|||
|
|
if($p['lng'] <= max($p1['lng'], $p2['lng'])){
|
|||
|
|
if ($p1['lat'] == $p2['lat'] && $p['lng'] >= min($p1['lng'], $p2['lng'])) {
|
|||
|
|
return $boundOrVertex;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if ($p1['lng'] == $p2['lng']) {
|
|||
|
|
if ($p1['lng'] == $p['lng']) {
|
|||
|
|
return $boundOrVertex;
|
|||
|
|
} else {
|
|||
|
|
++$intersectCount;
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
$xinters = ($p['lat'] - $p1['lat']) * ($p2['lng'] - $p1['lng']) / ($p2['lat'] - $p1['lat']) + $p1['lng'];
|
|||
|
|
if (abs($p['lng'] - $xinters) < $precision) {
|
|||
|
|
return $boundOrVertex;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if ($p['lng'] < $xinters) {
|
|||
|
|
++$intersectCount;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
if ($p['lat'] == $p2['lat'] && $p['lng'] <= $p2['lng']) {
|
|||
|
|
$p3 = $pts[($i+1) % $N];
|
|||
|
|
if ($p['lat'] >= min($p1['lat'], $p3['lat']) && $p['lat'] <= max($p1['lat'], $p3['lat'])) {
|
|||
|
|
++$intersectCount;
|
|||
|
|
} else {
|
|||
|
|
$intersectCount += 2;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
$p1 = $p2;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if ($intersectCount % 2 == 0) {
|
|||
|
|
return false;
|
|||
|
|
} else {
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|