feat: driver

This commit is contained in:
2025-04-01 11:49:50 +08:00
parent a7b99e2cf4
commit b68ad879c8
11 changed files with 554 additions and 124 deletions

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Constants\Common;
class DriverCode
{
/**
* @var int 状态 1 出发 2 目的地 99 异常
*/
CONST INT DEPARTURES = 1;
CONST INT DESTINATION = 2;
CONST INT EXCEPTIONS = 99;
}

View File

@@ -8,7 +8,7 @@ class OrderCode
* @var int 状态:1=未支付,11=未出,21=出餐,31=已出发,41=待取餐,51=完成,97=未完成退款,98=完成退款,99=取消 * @var int 状态:1=未支付,11=未出,21=出餐,31=已出发,41=待取餐,51=完成,97=未完成退款,98=完成退款,99=取消
*/ */
CONST int WAIT_PAY = 1; //待支付 CONST int WAIT_PAY = 1; //待支付
CONST int PAYED = 11; //已支付待写入配餐数据 CONST int PAYED = 11; //已支付
// CONST int WAIT_CATERING = 16; //已支付待出餐 // CONST int WAIT_CATERING = 16; //已支付待出餐
CONST int PLAN = 21; //出餐未出发 CONST int PLAN = 21; //出餐未出发
CONST int DEPART = 31; //已出发 CONST int DEPART = 31; //已出发

View File

@@ -9,9 +9,9 @@ use App\Service\Admin\Catering\Meal\CheckService;
use App\Service\Admin\Catering\Option\CompleteListService; use App\Service\Admin\Catering\Option\CompleteListService;
use App\Service\Admin\Catering\Option\CompletePrintService; use App\Service\Admin\Catering\Option\CompletePrintService;
use App\Service\Admin\Catering\Meal\CycleListService as MealCycleListService; use App\Service\Admin\Catering\Meal\CycleListService as MealCycleListService;
use APP\Service\Admin\Catering\Meal\CateringService as MealCateringService;
use App\Service\Admin\Catering\Option\CycleListService as OptionCycleListService; use App\Service\Admin\Catering\Option\CycleListService as OptionCycleListService;
use App\Service\Admin\Catering\Option\CateringService as OptionCateringService; use App\Service\Admin\Catering\Option\CateringService as OptionCateringService;
use App\Service\Admin\Catering\Meal\CateringService as MealCateringService;
use App\Service\Admin\Catering\Option\PrintService; use App\Service\Admin\Catering\Option\PrintService;
use Hyperf\HttpServer\Annotation\Controller; use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\Middlewares; use Hyperf\HttpServer\Annotation\Middlewares;
@@ -94,7 +94,7 @@ class CateringController
#[Scene(scene: "meal_catering")] #[Scene(scene: "meal_catering")]
public function mealCatering() public function mealCatering()
{ {
return (new MealCateringService)->handle(); return (new MealCateringService())->handle();
} }
/** /**

View File

@@ -6,7 +6,10 @@ namespace App\Controller\Api;
use App\Controller\AbstractController; use App\Controller\AbstractController;
use App\Middleware\Api\JwtAuthMiddleware; use App\Middleware\Api\JwtAuthMiddleware;
use App\Service\Api\Driver\AbnormalReportingService;
use App\Service\Api\Driver\DeliverService;
use App\Service\Api\Driver\GetSiteListService; use App\Service\Api\Driver\GetSiteListService;
use App\Service\Api\Driver\LoadActionService;
use Hyperf\HttpServer\Annotation\Controller; use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\Middlewares; use Hyperf\HttpServer\Annotation\Middlewares;
use Hyperf\HttpServer\Annotation\RequestMapping; use Hyperf\HttpServer\Annotation\RequestMapping;
@@ -18,10 +21,47 @@ use Hyperf\Validation\Annotation\Scene;
])] ])]
class DriverController extends AbstractController class DriverController extends AbstractController
{ {
/**
* 获取信息
* @return array
*/
#[RequestMapping(path: 'get_site_list',methods: 'GET')] #[RequestMapping(path: 'get_site_list',methods: 'GET')]
#[Scene(scene: 'get_site_list')] #[Scene(scene: 'get_site_list')]
public function get_site_list() public function get_site_list()
{ {
return (new GetSiteListService)->handle(); return (new GetSiteListService)->handle();
} }
/**
* 装车出餐
* @return array
*/
#[RequestMapping(path: 'load_action',methods: 'GET')]
#[Scene(scene: 'load_action')]
public function load_action()
{
return (new LoadActionService)->handle();
}
/**
* 异常上报
* @return array
*/
#[RequestMapping(path: 'abnormal_reporting',methods: 'POST')]
#[Scene(scene: 'abnormal_reporting')]
public function abnormal_reporting()
{
return (new AbnormalReportingService)->handle();
}
/**
* 送达
* @return array
*/
#[RequestMapping(path: 'deliver',methods: 'GET')]
#[Scene(scene: 'deliver')]
public function deliver()
{
return (new DeliverService)->handle();
}
} }

View File

@@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace App\Model;
use Hyperf\DbConnection\Model\Model;
/**
* @property int $id
* @property int $cycle_id
* @property int $site_id
* @property int $driver_id
* @property string $exceptions_msg
* @property int $image_id
* @property string $create_time
*/
class DriverException extends Model
{
/**
* The table associated with the model.
*/
protected ?string $table = 'driver_exceptions';
/**
* The attributes that are mass assignable.
*/
protected array $fillable = [];
/**
* The attributes that should be cast to native types.
*/
protected array $casts = ['id' => 'integer', 'cycle_id' => 'integer', 'site_id' => 'integer', 'driver_id' => 'integer', 'image_id' => 'integer'];
}

View File

@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace App\Model;
use Hyperf\DbConnection\Model\Model;
/**
* @property int $id
* @property int $cycle_id
* @property int $site_id
* @property int $driver_id
* @property string $site_name
* @property string $line_name
* @property int $meal_order_quantity
* @property int $meal_add_staple_food_num
* @property string $meal_list
* @property int $option_order_quantity
* @property int $option_add_staple_food_num
* @property int $status
* @property string $create_time
* @property string $update_time
*/
class DriverStatus extends Model
{
/**
* The table associated with the model.
*/
protected ?string $table = 'driver_status';
/**
* The attributes that are mass assignable.
*/
protected array $fillable = [];
/**
* The attributes that should be cast to native types.
*/
protected array $casts = ['id' => 'integer', 'cycle_id' => 'integer', 'site_id' => 'integer', 'driver_id' => 'integer', 'meal_order_quantity' => 'integer', 'meal_add_staple_food_num' => 'integer', 'option_order_quantity' => 'integer', 'option_add_staple_food_num' => 'integer', 'status' => 'integer'];
}

View File

@@ -0,0 +1,74 @@
<?php
/**
* This service file is part of item.
*
* @author ctexthuang
* @contact ctexthuang@qq.com
*/
declare(strict_types=1);
namespace App\Service\Api\Driver;
use App\Constants\Common\DriverCode;
use App\Exception\ErrException;
use App\Model\DriverException;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
class AbnormalReportingService extends BaseDriverService
{
/**
* @var DriverException
*/
#[Inject]
protected DriverException $driverExceptionModel;
/**
* @return array
*/
public function handle(): array
{
$info = $this->driverStatusModel
->where('cycle_id',$this->cycleId)
->where('site_id',$this->request->input('site_id'))
->where('driver_id',$this->adminInfo->id)
->first();
if (empty($info)) throw new ErrException('今日无该点位的送餐数据');
if ($info->status == DriverCode::DESTINATION) throw new ErrException('该点位已送达,无需上报异常信息');
$todaySiteIds = $this->driverStatusModel
->where('cycle_id',$this->cycleId)
->where('driver_id',$this->adminInfo->id)
->whereIn('status',[DriverCode::DEPARTURES,DriverCode::EXCEPTIONS])
->pluck('site_id')
->toArray();
if (empty($todaySiteIds)) throw new ErrException('数据错误-1');
$insertData = [];
foreach ($todaySiteIds as $siteId) {
$insertData[] = [
'cycle_id' => $this->cycleId,
'site_id' => $siteId,
'driver_id' => $this->adminInfo->id,
'exceptions_msg' => $this->request->input('exceptions_msg'),
'image_id' => $this->request->input('image_id'),
'create_time' => date('Y-m-d H:i:s')
];
}
if (empty($insertData)) throw new ErrException('数据错误-2');
Db::transaction(function () use ($todaySiteIds,$insertData) {
$this->driverExceptionModel->insert($insertData);
$this->driverStatusModel->update([
'status' => DriverCode::EXCEPTIONS,
]);
});
return $this->return->success();
}
}

View File

@@ -10,9 +10,15 @@ declare(strict_types=1);
namespace App\Service\Api\Driver; namespace App\Service\Api\Driver;
use App\Constants\Admin\CateringCode;
use App\Constants\Common\GoodCode;
use App\Constants\Common\RoleCode; use App\Constants\Common\RoleCode;
use App\Exception\ErrException; use App\Exception\ErrException;
use App\Model\AdminUser; use App\Model\AdminUser;
use App\Model\DriverStatus;
use App\Model\OrderMealCateringLog;
use App\Model\OrderOptionCateringLog;
use App\Model\Site;
use App\Service\Api\BaseService; use App\Service\Api\BaseService;
use App\Service\ServiceTrait\Common\CycleTrait; use App\Service\ServiceTrait\Common\CycleTrait;
use Hyperf\Database\Model\Builder; use Hyperf\Database\Model\Builder;
@@ -31,6 +37,40 @@ abstract class BaseDriverService extends BaseService
#[Inject] #[Inject]
protected AdminUser $adminUserModel; protected AdminUser $adminUserModel;
/**
* @var Site
*/
#[Inject]
protected Site $siteModel;
/**
* @var OrderMealCateringLog
*/
#[Inject]
protected OrderMealCateringLog $orderMealCateringLogModel;
/**
* @var OrderOptionCateringLog
*/
#[Inject]
protected OrderOptionCateringLog $orderOptionCateringLogModel;
/**
* @var DriverStatus
*/
#[Inject]
protected DriverStatus $driverStatusModel;
/**
* @var array
*/
protected array $siteIds;
/**
* @var array
*/
protected array $siteArr;
/** /**
* @var Builder|Model|AdminUser|null * @var Builder|Model|AdminUser|null
*/ */
@@ -50,7 +90,148 @@ abstract class BaseDriverService extends BaseService
$this->adminInfo = $this->adminUserModel->getAdminInfoByBindUserId($this->userId); $this->adminInfo = $this->adminUserModel->getAdminInfoByBindUserId($this->userId);
if ($this->adminInfo->role_id != RoleCode::DRIVER) throw new ErrException('暂无权限,请联系客服并提供相关信息绑定账号'); if ($this->adminInfo->role_id != RoleCode::DRIVER) throw new ErrException('暂无权限,请联系客服并提供相关信息绑定账号');
$siteArr = $this->siteModel
->where('delivered_id',$this->adminInfo->id)
->orderBy('sequence')
->get();
if ($siteArr->isEmpty()) throw new ErrException('该司机并未绑定站点');
$this->siteArr = array_column($siteArr->toArray(),null,'id');
$this->siteIds = array_keys($siteArr);
} }
abstract public function handle(); abstract public function handle();
/**
* @return array
*/
protected function getTodayList(): array
{
$info = $this->driverStatusModel
->where('driver_id',$this->adminInfo->id)
->where('cycle_id',$this->cycleId)
->whereIn('site_id',$this->siteIds)
->get();
if ($info->isEmpty()) return [];
$info = $info->toArray();
foreach ($info as $infoItem) {
$info['meal_list'] = json_decode($info['meal_list'], true);
}
return $info;
}
/**
* @return array
*/
protected function getMealData(): array
{
$mealArr = $this->orderMealCateringLogModel
->where('cycle_id',$this->cycleId)
->where('status',CateringCode::CATERING_STATUS_FINISH)
->whereIn('site_id', $this->siteIds)
->select(['quantity','site_id','sku_id'])
->get();
if ($mealArr->isEmpty()) $mealArr = [];
$mealArr = $mealArr->toArray();
$skuIds = array_column($mealArr, 'sku_id');
$skuArr = $this->skuModel->getDataArrByIds($skuIds);
$skuArr = array_column($skuArr,null,'id');
$res = [];
foreach ($mealArr as $oneLog) {
if (empty($res[$oneLog['site_id']])) {
$res[$oneLog['site_id']] = [
'total_copies' => 0,
'add_staple_food_num' => 0,
'sku' => []
];
}
if (empty($res[$oneLog['site_id']]['sku'][$oneLog['sku_id']])) {
$res[$oneLog['site_id']]['sku'][$oneLog['sku_id']] = [
'sku_id' => $oneLog['sku_id'],
'sku_name' => $skuArr[$oneLog['sku_id']]['title'] ?? '',
'quantity' => 0,
];
}
if ($skuArr[$oneLog['sku_id']]['is_add_staple_food'] == GoodCode::IS_ADD_STAPLE_FOOD) {
$res[$oneLog['site_id']]['add_staple_food_num'] += $oneLog['quantity'];
} else {
$res[$oneLog['site_id']]['total_copies'] += $oneLog['quantity'];
}
$res[$oneLog['site_id']]['sku'][$oneLog['sku_id']]['quantity'] += $oneLog['quantity'];
}
return $res;
}
/**
* @return array
*/
protected function getOptionData(): array
{
$optionArr = $this->orderOptionCateringLogModel
->where('cycle_id',$this->cycleId)
->where('status',CateringCode::CATERING_STATUS_FINISH)
->whereIn('site_id', $this->siteIds)
->select(['quantity','site_id','add_staple_food_num'])
->get();
if ($optionArr->isEmpty()) $optionArr = [];
$optionArr = $optionArr->toArray();
$res = [];
foreach ($optionArr as $oneSite) {
if (empty($res[$oneSite['site_id']])) {
$res[$oneSite['site_id']] = [
'copies' => 0,
'add_staple_food_num' => 0
];
}
$res[$oneSite['site_id']]['copies'] = $oneSite['quantity'] + $res[$oneSite['site_id']]['copies'];
$res[$oneSite['site_id']]['add_staple_food_num'] = $oneSite['add_staple_food_num'] + $res[$oneSite['site_id']]['add_staple_food_num'];
}
return $res;
}
/**
* @return array
*/
protected function buildListData(): array
{
$optionArr = $this->getOptionData();
$mealArr = $this->getMealData();
$res = [];
$dateTime = date('Y-m-d H:i:s');
foreach ($this->siteArr as $site) {
$res[] = [
'cycle_id' => $this->cycleId,
'site_id' => $site['id'],
'site_name' => $site['name'],
'driver_id' => $this->adminInfo->id,
'line_name' => '',
'meal_order_quantity' => $mealArr[$site['id']]['quantity'] ?? 0,
'meal_add_staple_food_num' => $mealArr[$site['id']]['add_staple_food_num'] ?? 0,
'meal_list' => $mealArr[$site['id']]['sku'] ?? [],
'option_order_quantity' => $optionArr[$site['id']]['quantity'] ?? 0,
'option_add_staple_food_num' => $optionArr[$site['id']]['add_staple_food_num'] ?? 0,
'create_time' => $dateTime,
'update_time' => $dateTime,
];
}
return $res;
}
} }

View File

@@ -0,0 +1,78 @@
<?php
/**
* This service file is part of item.
*
* @author ctexthuang
* @contact ctexthuang@qq.com
*/
declare(strict_types=1);
namespace App\Service\Api\Driver;
use App\Constants\Common\DriverCode;
use App\Constants\Common\OrderCode;
use App\Exception\ErrException;
use App\Model\Order;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
class DeliverService extends BaseDriverService
{
/**
* @var Order
*/
#[Inject]
protected Order $orderModel;
/**
* @var int
*/
private int $siteId;
/**
* @return array
*/
public function handle(): array
{
$this->siteId = (int)$this->request->input('site_id');
$info = $this->driverStatusModel
->where('cycle_id',$this->cycleId)
->where('site_id',$this->siteId)
->where('driver_id',$this->adminInfo->id)
->first();
if (empty($info)) throw new ErrException('今日无该点位的送餐数据');
if ($info->status == DriverCode::DESTINATION) throw new ErrException('该点位已送达');
$orderIds = $this->orderModel
->where('cycle_id',$this->cycleId)
->where('status',OrderCode::DEPART)
->where('site_id',$this->siteId)
->pluck('id')
->toArray();
Db::transaction(function () use ($info,$orderIds) {
// $this->orderModel->whereIn('id', $orderIds)->update([
// 'status' => OrderCode::DEPART,
// 'set_out_time' => date('Y-m-d H:i:s'),
// ]);
$info->status = DriverCode::DESTINATION;
if (!$info->save()) throw new ErrException('送达失败-01');
$dateTime = date('Y-m-d H:i:s');
foreach (array_chunk($orderIds, 500) as $chunk) {
$this->orderModel->whereIn('id', $chunk)->update([
'status' => OrderCode::ARRIVE,
'delivery_time' => $dateTime,
]);
}
});
return $this->return->success();
}
}

View File

@@ -21,23 +21,6 @@ use Hyperf\Di\Annotation\Inject;
class GetSiteListService extends BaseDriverService class GetSiteListService extends BaseDriverService
{ {
/**
* @var Site
*/
#[Inject]
protected Site $siteModel;
/**
* @var OrderMealCateringLog
*/
#[Inject]
protected OrderMealCateringLog $orderMealCateringLogModel;
/**
* @var OrderOptionCateringLog
*/
#[Inject]
protected OrderOptionCateringLog $orderOptionCateringLogModel;
/** /**
* @var Sku * @var Sku
@@ -50,117 +33,18 @@ class GetSiteListService extends BaseDriverService
*/ */
protected array $siteIds; protected array $siteIds;
public function handle(): void
{
}
private function setCache()
{
$siteArr = $this->siteModel
->where('delivered_id',$this->adminInfo->id)
->orderBy('sequence')
->get();
if ($siteArr->isEmpty()) throw new ErrException('该司机并未绑定站点');
$siteArr = array_column($siteArr->toArray(),null,'id');
$this->siteIds = array_keys($siteArr);
$optionArr = $this->getOptionData();
$mealArr = $this->getMealData();
$res = [];
foreach ($siteArr as $site) {
if (empty($res[$site['id']])) {
$res[$site['id']] = [
'site_id' => $site['id'],
'site_name' => $site['name'],
'name' => '',
'meal_order_quantity' => 0,
'meal_add_staple_food_num' => 0,
'option_order_quantity' => 0,
'option_add_staple_food_num' => 0,
];
}
}
}
/** /**
* @return array * @return array
*/ */
private function getMealData(): array public function handle(): array
{ {
$mealArr = $this->orderMealCateringLogModel $res = $this->getTodayList();
->where('cycle_id',$this->cycleId)
->where('status',CateringCode::CATERING_STATUS_FINISH)
->whereIn('site_id', $this->siteIds)
->select(['quantity','site_id','sku_id'])
->get();
if ($mealArr->isEmpty()) $mealArr = [];
$mealArr = $mealArr->toArray();
$skuIds = array_column($mealArr, 'sku_id'); if (empty($res)) $res = $this->buildListData();
$skuArr = $this->skuModel->getDataArrByIds($skuIds);
$skuArr = array_column($skuArr,null,'id');
return $this->return->success('success', ['list' => $res]);
$res = [];
foreach ($mealArr as $oneLog) {
if (empty($res[$oneLog['site_id']])) {
$res[$oneLog['site_id']] = [
'total_copies' => 0,
'add_staple_food_num' => 0,
'sku' => []
];
} }
if (empty($res[$oneLog['site_id']]['sku'][$oneLog['sku_id']])) { // private function setCache() {} //todo 赶时间 后续优化
$res[$oneLog['site_id']]['sku'][$oneLog['sku_id']] = [
'sku_id' => $oneLog['sku_id'],
'sku_name' => $skuArr[$oneLog['sku_id']]['title'] ?? '',
'quantity' => 0,
];
}
if ($skuArr[$oneLog['sku_id']]['is_add_staple_food'] == GoodCode::IS_ADD_STAPLE_FOOD) {
$res[$oneLog['site_id']]['add_staple_food_num'] += $oneLog['quantity'];
} else {
$res[$oneLog['site_id']]['total_copies'] += $oneLog['quantity'];
}
$res[$oneLog['site_id']]['sku'][$oneLog['sku_id']]['quantity'] += $oneLog['quantity'];
}
return $res;
}
/**
* @return array
*/
private function getOptionData(): array
{
$optionArr = $this->orderOptionCateringLogModel
->where('cycle_id',$this->cycleId)
->where('status',CateringCode::CATERING_STATUS_FINISH)
->whereIn('site_id', $this->siteIds)
->select(['quantity','site_id','add_staple_food_num'])
->get();
if ($optionArr->isEmpty()) $optionArr = [];
$optionArr = $optionArr->toArray();
$res = [];
foreach ($optionArr as $oneSite) {
if (empty($res[$oneSite['site_id']])) {
$res[$oneSite['site_id']] = [
'copies' => 0,
'add_staple_food_num' => 0
];
}
$res[$oneSite['site_id']]['copies'] = $oneSite['quantity'] + $res[$oneSite['site_id']]['copies'];
$res[$oneSite['site_id']]['add_staple_food_num'] = $oneSite['add_staple_food_num'] + $res[$oneSite['site_id']]['add_staple_food_num'];
}
return $res;
}
} }

View File

@@ -0,0 +1,85 @@
<?php
/**
* This service file is part of item.
*
* @author ctexthuang
* @contact ctexthuang@qq.com
*/
declare(strict_types=1);
namespace App\Service\Api\Driver;
use App\Constants\Admin\CateringCode;
use App\Constants\Common\OrderCode;
use App\Exception\ErrException;
use App\Model\Order;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
class LoadActionService extends BaseDriverService
{
/**
* @var Order
*/
#[Inject]
protected Order $orderModel;
/**
* @return array
*/
public function handle(): array
{
if (
($this->orderOptionCateringLogModel
->where('cycle_id',$this->cycleId)
->where('status',CateringCode::CATERING_STATUS_UNDERWAY)
->whereIn('site_id', $this->siteIds)
->where('quantity','>',0)
->sum('quantity') ?? 0) > 0
) throw new ErrException('自选配餐还未完成');
if (
($this->orderMealCateringLogModel
->where('cycle_id',$this->cycleId)
->where('status',CateringCode::CATERING_STATUS_UNDERWAY)
->whereIn('site_id', $this->siteIds)
->where('quantity','>',0)
->sum('quantity') ?? 0) > 0
) throw new ErrException('套餐配餐还未完成');
$orderIds = $this->orderModel
->where('cycle_id',$this->cycleId)
->where('status',OrderCode::PLAN)
->whereIn('site_id',$this->siteIds)
->pluck('id')
->toArray();
if (empty($orderIds)) throw new ErrException('数据不存在');
$list = $this->buildListData();
foreach ($list as &$one) {
$one['meal_list'] = json_encode($one['meal_list']);
}
Db::transaction(function () use ($orderIds,$list) {
// $this->orderModel->whereIn('id', $orderIds)->update([
// 'status' => OrderCode::DEPART,
// 'set_out_time' => date('Y-m-d H:i:s'),
// ]);
$this->driverStatusModel->insert($list);
$dateTime = date('Y-m-d H:i:s');
foreach (array_chunk($orderIds, 500) as $chunk) {
$this->orderModel->whereIn('id', $chunk)->update([
'status' => OrderCode::DEPART,
'set_out_time' => $dateTime,
]);
}
});
return $this->return->success();
}
}