|
@@ -0,0 +1,660 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+declare(strict_types=1);
|
|
|
+
|
|
|
+namespace App\Controller\Api\v1;
|
|
|
+
|
|
|
+use App\Controller\AbstractController;
|
|
|
+use App\Controller\Business\DistanceBusiness;
|
|
|
+use App\Controller\Business\DriverTypeBusiness;
|
|
|
+use App\Master\Framework\Library\GeTui\Push;
|
|
|
+use App\Model\Arts\CarSeatModel;
|
|
|
+use App\Model\Arts\DriverCarModel;
|
|
|
+use App\Model\Arts\DriverMessageModel;
|
|
|
+use App\Model\Arts\OrderDriverModel;
|
|
|
+use App\Model\Arts\OrderModel;
|
|
|
+use App\Model\Arts\UserCouponModel;
|
|
|
+use App\Model\Arts\UserModel;
|
|
|
+use App\Model\Arts\UserWalletModel;
|
|
|
+use App\Request\Api\v1\Order\AddMoneyRequest;
|
|
|
+use App\Request\Api\v1\Order\CancelRequest;
|
|
|
+use App\Request\Api\v1\Order\DetailRequest;
|
|
|
+use App\Request\Api\v1\Order\ListRequest;
|
|
|
+use App\Request\Api\v1\Order\PageRequest;
|
|
|
+use App\Request\Api\v1\Order\SubmitRequest;
|
|
|
+use App\Request\Api\v1\Order\TailwindDriverInfoRequest;
|
|
|
+use App\Request\Api\v1\Order\TailwindDriverRequest;
|
|
|
+use App\Request\Api\v1\Order\TailwindInviteRequest;
|
|
|
+use App\Service\QueueService;
|
|
|
+use App\Utils\AppResult;
|
|
|
+use App\Utils\Control\AuthUser;
|
|
|
+use Hyperf\DbConnection\Db;
|
|
|
+use Hyperf\Di\Annotation\Inject;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 用户管理
|
|
|
+ * UserController
|
|
|
+ */
|
|
|
+class OrderController extends AbstractController
|
|
|
+{
|
|
|
+ // 日志模块名称
|
|
|
+ const LOG_MODULE = 'v1/OrderController';
|
|
|
+
|
|
|
+ #[Inject]
|
|
|
+ protected QueueService $service;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 预下单(快车 接送机)
|
|
|
+ * @param PageRequest $request
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ public function page(PageRequest $request)
|
|
|
+ {
|
|
|
+ $params = $request->validated();// 获取校验通过的参数
|
|
|
+ $user = AuthUser::getInstance()->get();
|
|
|
+
|
|
|
+ $point = $params['point'];
|
|
|
+ $people_num = !empty($params['people_num']) ? $params['people_num'] : 1;
|
|
|
+ $luggage_num = !empty($params['luggage_num']) ? $params['luggage_num'] : 0;
|
|
|
+ $is_back = !empty($params['is_back']) ? $params['is_back'] : 0;
|
|
|
+ $is_exclusive = !empty($params['is_exclusive']) ? $params['is_exclusive'] : 0;
|
|
|
+ $appointment_time = !empty($params['appointment_time']) ? strtotime($params['appointment_time']) : 0;
|
|
|
+ $appointment_time = $params['type'] == 30 && empty($appointment_time) ? time() : $appointment_time;// 如果是顺风车 且未选择时间,则默认为当前时间
|
|
|
+
|
|
|
+ // 计算公里数
|
|
|
+ $distanceBusiness = new DistanceBusiness();
|
|
|
+ if (!$distanceBusiness->computeRoutes($point, $appointment_time)) {
|
|
|
+ return AppResult::error($distanceBusiness->getMessage() ?? '计算距离错误');
|
|
|
+ }
|
|
|
+ $mapData = $distanceBusiness->getData();
|
|
|
+ // 获取计算距离
|
|
|
+ $distance = $mapData['distance'];// 距离m
|
|
|
+ $duration = $mapData['duration'];// 时长s
|
|
|
+
|
|
|
+ // 计算对应订单类型的价格
|
|
|
+ $driverTypeBusiness = new DriverTypeBusiness();
|
|
|
+ if (!$driverTypeBusiness->calculate((int)$params['type'], $distance, $duration, $point, $appointment_time, $is_back, $is_exclusive)) {
|
|
|
+ return AppResult::error($driverTypeBusiness->getMessage() ?? '计算失败');
|
|
|
+ }
|
|
|
+ $res = $driverTypeBusiness->getData();
|
|
|
+
|
|
|
+ if ($params['type'] == 50) {
|
|
|
+ $total_amount = (string)round((float)$res['total_amount']);// 四舍五入
|
|
|
+ $rmb_total_amount = (string)round((float)bcmul($total_amount, site('dollar_to_rmb'), 2));// 四舍五入
|
|
|
+ // 跑腿订单
|
|
|
+ $data = [
|
|
|
+ 'errand' => [
|
|
|
+ 'total_amount' => $total_amount,
|
|
|
+ 'rmb_total_amount' => $rmb_total_amount
|
|
|
+ ]
|
|
|
+ ];
|
|
|
+ } else {
|
|
|
+ $airport_fee_min_price = site('airport_fee_min_price');// 接送机最低消费
|
|
|
+ $carSeat = new CarSeatModel();
|
|
|
+ $list = $carSeat->getList(orderBy: ['weight' => 'desc']);
|
|
|
+ foreach ($list as $key => $val) {
|
|
|
+ $basics_amount = bcsub(bcmul((string)$res['basics_amount'], (string)$val['subsidy_multiple'], 2),(string)$res['basics_amount'],2);// 计算车型补贴:公里数价格 * 补贴比例
|
|
|
+ $total_amount = bcadd((string)$res['total_amount'], $basics_amount, 2);
|
|
|
+ // 预约费
|
|
|
+ $platform_subscribe_price = (string)($total_amount >= site('platform_subscribe_min') ? $val['platform_subscribe_price'] : '0');
|
|
|
+ $total_amount = (string)round((float)bcadd($total_amount,$platform_subscribe_price,2));// 美元 四舍五入
|
|
|
+ if ($params['type'] == 20 || ($params['type'] == 10 && $res['is_at_airport'] == 1)){
|
|
|
+ $total_amount = max($total_amount,$airport_fee_min_price);// 接送机最低消费
|
|
|
+ }
|
|
|
+
|
|
|
+ $rmb_total_amount = (string)round((float)bcmul($total_amount, site('dollar_to_rmb'), 2));// 人民币 四舍五入
|
|
|
+ $list[$key]['image'] = cdn_url($val['image']);
|
|
|
+ $list[$key]['total_amount'] = $total_amount;
|
|
|
+ $list[$key]['rmb_total_amount'] = $rmb_total_amount;
|
|
|
+ $list[$key]['is_show'] = $val['people_num'] >= $people_num && $val['luggage_num'] >= $luggage_num ? 1 : 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 往返提示说明
|
|
|
+ $come_explain = '';
|
|
|
+ if ($is_back == 1){
|
|
|
+ $come_explain = $params['type'] == 10 ? site('wf_taxi_explain') : site('wf_airport_explain');
|
|
|
+ }
|
|
|
+
|
|
|
+ $data = [
|
|
|
+ 'distance' => bcdiv((string)$distance,'1000'),
|
|
|
+ 'come_explain' => $come_explain,
|
|
|
+ 'car_seat_list' => $list,
|
|
|
+ 'tailwind' => [
|
|
|
+ [
|
|
|
+ 'image' => cdn_url('/assets/img/shun_che1.png'),
|
|
|
+ 'total_amount' => (string)round((float)$res['total_amount']),
|
|
|
+ 'rmb_total_amount' => (string)round((float)bcmul($res['total_amount'], site('dollar_to_rmb'), 2)),
|
|
|
+ 'name' => '拼车',
|
|
|
+ 'is_exclusive' => 0,
|
|
|
+ ],
|
|
|
+ [
|
|
|
+ 'image' => cdn_url('/assets/img/shun_che2.png'),
|
|
|
+ 'total_amount' => (string)round((float)bcadd($res['total_amount'], site('tailwind_exclusive'), 2)),
|
|
|
+ 'rmb_total_amount' => (string)round((float)bcmul(bcadd($res['total_amount'], site('tailwind_exclusive'), 2),site('dollar_to_rmb'), 2)),
|
|
|
+ 'name' => '独享',
|
|
|
+ 'is_exclusive' => 1,
|
|
|
+ ]
|
|
|
+ ],
|
|
|
+ 'substitute' => [
|
|
|
+ 'total_amount' => (string)round((float)$res['total_amount']),
|
|
|
+ 'rmb_total_amount' => (string)round((float)bcmul($res['total_amount'], site('dollar_to_rmb'), 2)),
|
|
|
+ 'image' => cdn_url('/assets/img/dai_toup1.png'),
|
|
|
+ ]
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 汇率
|
|
|
+ $data['dollar_to_rmb'] = site('dollar_to_rmb');
|
|
|
+
|
|
|
+ if ($appointment_time == 0){
|
|
|
+ // 如果有实时订单则提示是否继续接单
|
|
|
+ $model = new OrderModel();
|
|
|
+ if ($model->getDetail(params: ['user_id' => $user['id'],'status_in' => [10,20,30],'appointment_time_zero' => 0])){
|
|
|
+ return AppResult::response_fast(2,"您有一条正在进行订单,确定要继续下单吗?", $data);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return AppResult::success('success', $data);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 提交订单(快车 接送机)
|
|
|
+ * @param SubmitRequest $request
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ public function submit(SubmitRequest $request)
|
|
|
+ {
|
|
|
+ $params = $request->validated();// 获取校验通过的参数
|
|
|
+ $user = AuthUser::getInstance()->get();
|
|
|
+
|
|
|
+ // 如果是会员 则可设置一口价
|
|
|
+ if ($user['is_vip'] != 1 && !empty($params['pay_amount'])){
|
|
|
+ return AppResult::error('暂无设置一口价权限');
|
|
|
+ }
|
|
|
+ if ($user['is_vip'] == 1 && !empty($params['pay_amount']) && !in_array($params['type'], [10, 20])){
|
|
|
+ return AppResult::error('仅支持快车或接送机设置一口价');
|
|
|
+ }
|
|
|
+
|
|
|
+ $point = $params['point'];
|
|
|
+ $people_num = !empty($params['people_num']) ? $params['people_num'] : 1;// 乘车人数
|
|
|
+ $luggage_num = !empty($params['luggage_num']) ? $params['luggage_num'] : 0;// 行李数
|
|
|
+ $is_back = !empty($params['is_back']) ? $params['is_back'] : 0;// 是否往返
|
|
|
+ $is_exclusive = !empty($params['is_exclusive']) ? $params['is_exclusive'] : 0;// 是否独享
|
|
|
+ $appointment_time = !empty($params['appointment_time']) ? strtotime($params['appointment_time']) : 0;// 出发时间
|
|
|
+ $appointment_time = $params['type'] == 30 && empty($appointment_time) ? time() : $appointment_time;// 如果是顺风车 且未选择时间,则默认为当前时间
|
|
|
+
|
|
|
+ // 计算公里数
|
|
|
+ $distanceBusiness = new DistanceBusiness();
|
|
|
+ if (!$distanceBusiness->computeRoutes($point, $appointment_time)) {
|
|
|
+ return AppResult::error($distanceBusiness->getMessage() ?? '计算距离错误');
|
|
|
+ }
|
|
|
+ $mapData = $distanceBusiness->getData();
|
|
|
+ // 获取计算距离
|
|
|
+ $distance = $mapData['distance'];// 距离m
|
|
|
+ $duration = $mapData['duration'];// 时长s
|
|
|
+
|
|
|
+ // 如果是会员 且是快车 或 接送机 则可设置一口价
|
|
|
+ if ($user['is_vip'] == 1 && !empty($params['pay_amount']) && in_array($params['type'], [10, 20])){
|
|
|
+ $carSeat = new CarSeatModel();
|
|
|
+ $info = $carSeat->getDetail(params: ['id' => $params['car_seat_id']]);
|
|
|
+ if (!($info['people_num'] >= $people_num && $info['luggage_num'] >= $luggage_num)) {
|
|
|
+ return AppResult::error('当前车型不支持选择的人数行李数');
|
|
|
+ }
|
|
|
+ $pay_amount = $total_amount = $params['pay_amount'];
|
|
|
+ // 预约费 vip预约费已经包含在
|
|
|
+ $platform_subscribe_price = (string)($total_amount >= site('platform_subscribe_min') ? $info['platform_subscribe_price'] : '0');
|
|
|
+ }else{
|
|
|
+ // 计算对应订单类型的价格
|
|
|
+ $driverTypeBusiness = new DriverTypeBusiness();
|
|
|
+ if (!$driverTypeBusiness->calculate((int)$params['type'], $distance, $duration, $point, $appointment_time, $is_back, $is_exclusive)) {
|
|
|
+ return AppResult::error($driverTypeBusiness->getMessage() ?? '计算失败');
|
|
|
+ }
|
|
|
+ $res = $driverTypeBusiness->getData();
|
|
|
+
|
|
|
+ // 如果是接送机 快车 则根据车型计算价格
|
|
|
+ if (in_array($params['type'], [10, 20])) {
|
|
|
+ $carSeat = new CarSeatModel();
|
|
|
+ $info = $carSeat->getDetail(params: ['id' => $params['car_seat_id']]);
|
|
|
+ if (!($info['people_num'] >= $people_num && $info['luggage_num'] >= $luggage_num)) {
|
|
|
+ return AppResult::error('当前车型不支持选择的人数行李数');
|
|
|
+ }
|
|
|
+ $basics_amount = bcsub(bcmul((string)$res['basics_amount'], (string)$info['subsidy_multiple'], 2),(string)$res['basics_amount'],2);// 计算车型补贴:公里数价格 * 补贴比例
|
|
|
+ $total_amount = bcadd((string)$res['total_amount'], $basics_amount, 2);
|
|
|
+ // 预约费
|
|
|
+ $platform_subscribe_price = (string)($total_amount >= site('platform_subscribe_min') ? $info['platform_subscribe_price'] : '0');
|
|
|
+ $total_amount = bcadd($total_amount,$platform_subscribe_price,2);
|
|
|
+ if ($params['type'] == 20 || ($params['type'] == 10 && $res['is_at_airport'] == 1)){
|
|
|
+ $airport_fee_min_price = site('airport_fee_min_price');// 接送机最低消费
|
|
|
+ $total_amount = max($total_amount,$airport_fee_min_price);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果是 代驾 顺风车 跑腿 则无需单独增加价格
|
|
|
+ if (in_array($params['type'], [30, 40, 50])) {
|
|
|
+ $total_amount = $res['total_amount'];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!isset($total_amount)) {
|
|
|
+ return AppResult::error('操作异常');
|
|
|
+ }
|
|
|
+
|
|
|
+ $pay_amount = $total_amount = (string)round((float)$total_amount);// 支付金额 四舍五入
|
|
|
+ // 优惠券核销
|
|
|
+ if (!empty($params['coupon_id'])){
|
|
|
+ $order_coupons = (new UserCouponModel())->getOrderCoupon($user['id'],(int)$params['type'],(int)$params['coupon_id'],$total_amount);
|
|
|
+ if ($total_amount >= $order_coupons['min_money']){
|
|
|
+ $pay_amount = bcsub($total_amount,$order_coupons['money'],2);
|
|
|
+ $discount_amount = $order_coupons['money'];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 在线支付需校验金额
|
|
|
+ if ($params['pay_type'] == 1) {
|
|
|
+ $money = UserWalletModel::getOne($user['id'], 'money');
|
|
|
+ if ($money < $pay_amount) {
|
|
|
+ return AppResult::error('余额不足');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $data = [
|
|
|
+ 'type' => $params['type'],
|
|
|
+ 'flight_type' => $params['flight_type'] ?? 0,
|
|
|
+ 'distance' => (int)$distance,
|
|
|
+ 'duration' => (int)$duration,
|
|
|
+ 'total_amount' => $total_amount,
|
|
|
+ 'dollar_to_rmb' => site('dollar_to_rmb'),
|
|
|
+ 'pay_amount' => $pay_amount,
|
|
|
+ 'discount_amount' => $discount_amount ?? 0,
|
|
|
+ 'pay_type' => $params['pay_type'],
|
|
|
+ 'is_pay' => $params['pay_type'] == 1 ? 1 : 0,
|
|
|
+ 'coupon_id' => $params['coupon_id'] ?? 0,
|
|
|
+ 'car_seat_id' => $params['car_seat_id'] ?? 0,
|
|
|
+ 'name' => $params['name'] ?? $user['nickname'],
|
|
|
+ 'phone' => $params['phone'] ?? "{$user['area_code']} {$user['mobile']}",
|
|
|
+ 'people_num' => $people_num,
|
|
|
+ 'luggage_num' => $luggage_num,
|
|
|
+ 'start_lng' => $point[0]['lng'],
|
|
|
+ 'start_lat' => $point[0]['lat'],
|
|
|
+ 'end_lng' => end($point)['lng'],
|
|
|
+ 'end_lat' => end($point)['lat'],
|
|
|
+ 'is_back' => $is_back,
|
|
|
+ 'is_exclusive' => $is_exclusive,
|
|
|
+ 'is_child' => $params['is_child'] ?? 0,
|
|
|
+ 'appointment_time' => $appointment_time,
|
|
|
+ 'flight_no' => $params['flight_no'] ?? '',
|
|
|
+ 'basics_amount' => $res['basics_amount'] ?? '0.00',
|
|
|
+ 'city_subsidy_price' => $res['city_subsidy_price'] ?? '0.00',
|
|
|
+ 'peak_price' => $res['peak_price'] ?? '0.00',
|
|
|
+ 'night_price' => $res['night_price'] ?? '0.00',
|
|
|
+ 'exclusive_price' => $res['exclusive_price'] ?? '0.00',
|
|
|
+ 'platform_subscribe_price' => $platform_subscribe_price ?? '0.00',
|
|
|
+ 'remark' => $params['remark'] ?? '',
|
|
|
+ 'freight_name' => $params['freight_name'] ?? '',
|
|
|
+ 'image' => $params['image'] ?? '',
|
|
|
+ ];
|
|
|
+
|
|
|
+ Db::beginTransaction();
|
|
|
+ // 在线支付需要提前扣费
|
|
|
+ if ($params['pay_type'] == 1) {
|
|
|
+ $type_name = DriverTypeBusiness::type[$params['type']] ?? '';
|
|
|
+ $wallet = new UserWalletModel();
|
|
|
+ if (!$wallet->change($user['id'], (float)$data['pay_amount'], "{$type_name}订单消费")) {
|
|
|
+ Db::rollBack();
|
|
|
+ return AppResult::error($wallet->getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 使用优惠券
|
|
|
+ if (!empty($params['coupon_id'])) {
|
|
|
+ $coupon = UserCouponModel::query()
|
|
|
+ ->where('id',$params['coupon_id'])
|
|
|
+ ->where('type',$params['type'])
|
|
|
+ ->where('is_use',0)
|
|
|
+ ->where('status',1)
|
|
|
+ ->where('valid_at', '>', time())
|
|
|
+ ->update(['is_use' => 1, 'use_at' => time()]);
|
|
|
+ if (!$coupon) {
|
|
|
+ Db::rollBack();
|
|
|
+ return AppResult::error('优惠券核销失败,请校验优惠券');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 增加用户订单数
|
|
|
+ UserModel::query()->where('id', $user['id'])->increment('order_num');
|
|
|
+ // 创建订单
|
|
|
+ $model = new OrderModel();
|
|
|
+ if (!$model->createOrder($user['id'], $data, $point)) {
|
|
|
+ Db::rollBack();
|
|
|
+ return AppResult::error($model->getMessage());
|
|
|
+ }
|
|
|
+ Db::commit();
|
|
|
+
|
|
|
+ // 加入提醒司机接单队列
|
|
|
+ if (!empty($model->getData()['order_no'])){
|
|
|
+ $this->service->pushOrder([
|
|
|
+ 'order_no' => $model->getData()['order_no']
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 加入超时订单取消队列
|
|
|
+ if (in_array($params['type'],[10,20,30,40,50])){
|
|
|
+ $delay = $appointment_time > 0 ? 600 : 300;// 延迟时间 单位秒
|
|
|
+ if ($params['type'] == 30){
|
|
|
+ $delay = $appointment_time - time();
|
|
|
+ $delay = max($delay, 600);
|
|
|
+ }
|
|
|
+ $this->service->cancelOrder([
|
|
|
+ 'order_no' => $model->getData()['order_no']
|
|
|
+ ],$delay);
|
|
|
+ }
|
|
|
+
|
|
|
+ return AppResult::success($model->getMessage(), $model->getData());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 订单列表
|
|
|
+ * @param ListRequest $request
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ public function list(ListRequest $request)
|
|
|
+ {
|
|
|
+ $params = $request->validated();
|
|
|
+ $user = AuthUser::getInstance()->get();
|
|
|
+ $params['user_id'] = $user['id'];
|
|
|
+
|
|
|
+ // 列表筛选
|
|
|
+ switch ($params['status_type']) {
|
|
|
+ case 1:
|
|
|
+ $params['status_in'] = [10, 20];
|
|
|
+ $params['appointment_time_not'] = 1;
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ $params['status_in'] = [10, 20, 30];
|
|
|
+ break;
|
|
|
+ case 3:
|
|
|
+ $params['status_in'] = [40];
|
|
|
+ }
|
|
|
+
|
|
|
+ $model = new OrderModel();
|
|
|
+ $model->setSelect([
|
|
|
+ 'id', 'user_id', 'driver_id', 'type', 'order_no', 'driver_order_id', 'total_amount', 'pay_amount', 'appointment_time', 'create_time',
|
|
|
+ 'driver_status', 'status'
|
|
|
+ ]);
|
|
|
+ $list = $model->getList(
|
|
|
+ params : $params,
|
|
|
+ orderBy: ['id' => 'desc'],
|
|
|
+ with : [
|
|
|
+ 'points' => function ($query) {
|
|
|
+ $query->select('id', 'order_id', 'type', 'lng', 'lat', 'address', 'postal_code', 'is_in_city', 'is_at_airport')->where('status', 1)->orderBy('id', 'asc');
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ );
|
|
|
+ foreach ($list as $key => $val) {
|
|
|
+ $list[$key]['start_time'] = date('Y-m-d H:i', !empty($val['appointment_time']) ? $val['appointment_time'] : $val['create_time']);
|
|
|
+ $list[$key]['create_time'] = strtotime($list[$key]['start_time']);
|
|
|
+ }
|
|
|
+ return AppResult::success(result: $list);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 订单详情
|
|
|
+ * @param DetailRequest $request
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ public function detail(DetailRequest $request)
|
|
|
+ {
|
|
|
+ $params = $request->validated();// 获取校验通过的参数
|
|
|
+ $user = AuthUser::getInstance()->get();
|
|
|
+ $model = new OrderModel();
|
|
|
+ $model->setSelect([
|
|
|
+ 'id', 'user_id', 'driver_id', 'type', 'flight_type', 'order_no', 'driver_order_id', 'total_amount', 'pay_amount', 'is_pay', 'raise_amount',
|
|
|
+ 'pay_type', 'car_seat_id', 'name', 'phone', 'people_num', 'luggage_num', 'remark', 'distance', 'duration', 'is_back', 'is_exclusive', 'is_child',
|
|
|
+ 'appointment_time', 'flight_no', 'car_no', 'car_color', 'car_brand', 'take_time', 'driver_status', 'status', 'create_time', 'start_driver_time', 'end_driver_time'
|
|
|
+ ]);
|
|
|
+ $info = $model->getDetail(
|
|
|
+ params: ['order_no' => $params['order_no'], 'user_id' => $user['id']],
|
|
|
+ with : [
|
|
|
+ 'driver' => function ($query) {
|
|
|
+ $query->select('id', 'name', 'area_code', 'mobile', 'avatar');
|
|
|
+ },
|
|
|
+ 'points' => function ($query) {
|
|
|
+ $query->select('id', 'order_id', 'type', 'lng', 'lat', 'address', 'postal_code', 'is_in_city', 'is_at_airport')->where('status', 1)->orderBy('id', 'asc');
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ );
|
|
|
+ if (!$info) {
|
|
|
+ return AppResult::error('订单不存在');
|
|
|
+ }
|
|
|
+ $car_img = DriverCarModel::query()->where('driver_id',$info['driver']['id'] ?? 0)->value('car_img');
|
|
|
+ $info['end_driver_time'] = $info['driver_status'] == 2 ? time_hour(!empty($info['end_driver_time']) ? $info['end_driver_time'] : ($info['end_driver_time'] + $info['duration'])) : 0;
|
|
|
+ $info['driver_name'] = $info['driver']['name'] ?? '';
|
|
|
+ $info['driver_avatar'] = $car_img ?? '';
|
|
|
+ $info['driver_mobile'] = ($info['driver']['area_code'] ?? '') . ' ' . ($info['driver']['mobile'] ?? '');
|
|
|
+ $info['service_telephone'] = site('service_telephone');// 客服电话
|
|
|
+ unset($info['driver']);
|
|
|
+ return AppResult::success('success', $info);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 加价
|
|
|
+ * @param AddMoneyRequest $request
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ public function add_money(AddMoneyRequest $request)
|
|
|
+ {
|
|
|
+ $params = $request->validated();// 获取校验通过的参数
|
|
|
+ $user = AuthUser::getInstance()->get();
|
|
|
+ $model = new OrderModel();
|
|
|
+ $info = $model->getDetail(
|
|
|
+ params: ['order_no' => $params['order_no'], 'user_id' => $user['id'], 'status' => 10],
|
|
|
+ );
|
|
|
+ if (!$info) {
|
|
|
+ return AppResult::error('订单不存在或已被接单');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 在线支付需校验金额
|
|
|
+ if ($info['pay_type'] == 1) {
|
|
|
+ $money = UserWalletModel::getOne($user['id'], 'money');
|
|
|
+ if ($money < $params['amount']) {
|
|
|
+ return AppResult::error('余额不足');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Db::beginTransaction();
|
|
|
+ // 在线支付需要提前扣费
|
|
|
+ if ($info['pay_type'] == 1) {
|
|
|
+ $type_name = DriverTypeBusiness::type[$info['type']] ?? '';
|
|
|
+ $wallet = new UserWalletModel();
|
|
|
+ if (!$wallet->change($user['id'], (float)$params['amount'], "{$type_name}订单加价消费")) {
|
|
|
+ Db::rollBack();
|
|
|
+ return AppResult::error($wallet->getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!$model->addMoney($info['id'], (float)$params['amount'])) {
|
|
|
+ Db::rollBack();
|
|
|
+ return AppResult::error($model->getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ Db::commit();
|
|
|
+
|
|
|
+ return AppResult::success($model->getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 取消订单
|
|
|
+ * @param DetailRequest $request
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ public function cancel(CancelRequest $request)
|
|
|
+ {
|
|
|
+ $params = $request->validated();// 获取校验通过的参数
|
|
|
+ $user = AuthUser::getInstance()->get();
|
|
|
+ Db::beginTransaction();
|
|
|
+ $model = new OrderModel();
|
|
|
+ if (!$model->cancel(order_no: $params['order_no'], user_id: $user['id'],reason: $params['reason'])) {
|
|
|
+ Db::rollBack();
|
|
|
+ return AppResult::error($model->getMessage());
|
|
|
+ }
|
|
|
+ Db::commit();
|
|
|
+ return AppResult::success($model->getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 司机发布顺风车
|
|
|
+ * @param TailwindDriverRequest $request
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ public function tailwind_driver(TailwindDriverRequest $request)
|
|
|
+ {
|
|
|
+ $params = $request->validated();// 获取校验通过的参数
|
|
|
+ $user = AuthUser::getInstance()->get();
|
|
|
+
|
|
|
+ $start_lng = $params['point'][0]['lng'] ?? '';
|
|
|
+ $start_lat = $params['point'][0]['lat'] ?? '';
|
|
|
+ $end_lng = $params['point'][1]['lng'] ?? '0.00';
|
|
|
+ $end_lat = $params['point'][1]['lat'] ?? '0.00';
|
|
|
+ unset($params['point']);
|
|
|
+ $params['status'] = 1;
|
|
|
+ $params['start_time_gt'] = time();
|
|
|
+ $model = new OrderDriverModel();
|
|
|
+ $model->setSelect([
|
|
|
+ 'id', 'driver_id', 'car_no', 'remark', 'start_time', 'people_num', 'people_at_num', 'start_address', 'start_lng', 'start_lat',
|
|
|
+ 'end_address', 'end_lng', 'end_lat', 'status', 'create_time',
|
|
|
+ Db::raw("(st_distance(point ({$start_lng}, {$start_lat}),point(start_lng,start_lat))*111195) as start_distance"),
|
|
|
+ Db::raw("(st_distance(point ({$end_lng}, {$end_lat}),point(end_lng,end_lat))*111195) as end_distance"),
|
|
|
+ ]);
|
|
|
+ $list = $model->getList(
|
|
|
+ params : $params,
|
|
|
+ orderBy: ['start_time'=>'asc','start_distance' => 'asc', 'end_distance' => 'asc'],
|
|
|
+ with : [
|
|
|
+ 'order' => function ($query) use ($user) {
|
|
|
+ $query->select('id', 'driver_order_id', 'user_id', 'driver_id', 'status')->where('user_id', $user['id'] ?? 0)->whereIn('status', [10, 20, 30, 40]);
|
|
|
+ },
|
|
|
+ 'driver' => function ($query) {
|
|
|
+ $query->select('id', 'name', 'avatar');
|
|
|
+ },
|
|
|
+ 'car' => function ($query) {
|
|
|
+ $query->select('driver_id', 'car_color', 'car_brand');
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ );
|
|
|
+
|
|
|
+ foreach ($list as $key => $val) {
|
|
|
+ // 起点终点总距离差
|
|
|
+ $total_distance = bcadd((string)$val['start_distance'], (string)($val['end_distance'] ?? 0), 2);
|
|
|
+ $list[$key]['total_distance'] = $total_distance;
|
|
|
+ // 起点距离
|
|
|
+ $stat_distance = 0;
|
|
|
+ if (isset($val['start_distance'])) {
|
|
|
+ if ($val['start_distance'] >= 1000) {
|
|
|
+ $stat_distance = round(($val['start_distance'] / 1000), 2) . 'km';
|
|
|
+ } else {
|
|
|
+ $stat_distance = round($val['start_distance'], 1) . 'm';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $list[$key]['start_distance'] = $stat_distance;
|
|
|
+
|
|
|
+ // 终点距离
|
|
|
+ $end_distance = 0;
|
|
|
+ if (isset($val['end_distance'])) {
|
|
|
+ if ($val['end_distance'] >= 1000) {
|
|
|
+ $end_distance = round(($val['end_distance'] / 1000), 2) . 'km';
|
|
|
+ } else {
|
|
|
+ $end_distance = round($val['end_distance'], 1) . 'm';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $list[$key]['end_distance'] = $end_distance;
|
|
|
+
|
|
|
+ $list[$key]['start_time'] = time_hour($val['start_time']);
|
|
|
+ $list[$key]['is_subscribe'] = !empty($val['order']) ? 1 : 0;
|
|
|
+
|
|
|
+ $list[$key]['car_color'] = $val['car']['car_color'] ?? '';
|
|
|
+ $list[$key]['car_brand'] = $val['car']['car_brand'] ?? '';
|
|
|
+ $list[$key]['driver_name'] = $val['driver']['name'] ?? '';
|
|
|
+ $list[$key]['driver_avatar'] = !empty($val['driver']['avatar']) ? cdn_url($val['driver']['avatar']) : '';
|
|
|
+ unset($list[$key]['car'], $list[$key]['driver']);
|
|
|
+ }
|
|
|
+
|
|
|
+ return AppResult::success('success', $list);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 司机发布顺风车详情
|
|
|
+ * @param TailwindDriverInfoRequest $request
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ public function tailwind_driver_info(TailwindDriverInfoRequest $request)
|
|
|
+ {
|
|
|
+ $params = $request->validated();// 获取校验通过的参数
|
|
|
+ $user = AuthUser::getInstance()->get();
|
|
|
+ $params['status'] = 1;
|
|
|
+ $model = new OrderDriverModel();
|
|
|
+ $model->setSelect([
|
|
|
+ 'id', 'driver_id', 'car_no', 'remark', 'start_time', 'people_num', 'people_at_num', 'start_address', 'start_lng', 'start_lat',
|
|
|
+ 'end_address', 'end_lng', 'end_lat', 'status', 'create_time'
|
|
|
+ ]);
|
|
|
+ $info = $model->getDetail(
|
|
|
+ params : $params,
|
|
|
+ with : [
|
|
|
+ 'order' => function ($query) use ($user) {
|
|
|
+ $query->select('id', 'driver_order_id', 'user_id', 'driver_id', 'status')->where('user_id', $user['id'] ?? 0)->whereIn('status', [10, 20, 30, 40]);
|
|
|
+ },
|
|
|
+ 'driver' => function ($query) {
|
|
|
+ $query->select('id', 'name', 'avatar');
|
|
|
+ },
|
|
|
+ 'car' => function ($query) {
|
|
|
+ $query->select('driver_id', 'car_color', 'car_brand');
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ );
|
|
|
+
|
|
|
+ $info['start_time'] = time_hour($info['start_time']);
|
|
|
+ $info['is_subscribe'] = !empty($info['order']) ? 1 : 0;
|
|
|
+ $info['car_color'] = $info['car']['car_color'] ?? '';
|
|
|
+ $info['car_brand'] = $info['car']['car_brand'] ?? '';
|
|
|
+ $info['driver_name'] = $info['driver']['name'] ?? '';
|
|
|
+ $info['driver_avatar'] = !empty($info['driver']['avatar']) ? cdn_url($info['driver']['avatar']) : '';
|
|
|
+ unset($info['car'], $info['driver']);
|
|
|
+
|
|
|
+ return AppResult::success('success', $info);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 邀请司机接单
|
|
|
+ * @param TailwindInviteRequest $request
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ public function tailwind_invite(TailwindInviteRequest $request)
|
|
|
+ {
|
|
|
+ $params = $request->validated();// 获取校验通过的参数
|
|
|
+ $user = AuthUser::getInstance()->get();
|
|
|
+
|
|
|
+ $model = new OrderModel();
|
|
|
+ $info = $model->getDetail(
|
|
|
+ params: ['order_no' => $params['order_no'], 'user_id' => $user['id'], 'status' => 10],
|
|
|
+ );
|
|
|
+ if (!$info) {
|
|
|
+ return AppResult::error('订单不存在或已被接单');
|
|
|
+ }
|
|
|
+
|
|
|
+ $driver_order = OrderDriverModel::query()->where('id', $params['driver_order_id'])->where('status',1)->first();
|
|
|
+ if (!$driver_order){
|
|
|
+ return AppResult::error('当前拼车路线不存在或行程已出发');
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!$model->tailwind_invite($info['id'], $params['driver_order_id'])) {
|
|
|
+ return AppResult::error($model->getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 发送系统消息
|
|
|
+ DriverMessageModel::add([
|
|
|
+ 'driver_id' => $driver_order['driver_id'],
|
|
|
+ 'type' => 1,
|
|
|
+ 'name' => "顺风车有新订单",
|
|
|
+ 'content' => "用户邀请您同行,请前往顺风车行程中查看详情",
|
|
|
+ 'value' => $params['order_no']
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return AppResult::success($model->getMessage());
|
|
|
+ }
|
|
|
+}
|