Просмотр исходного кода

Wesmiler 校企小程序 更新 6.20

wesmiler 3 лет назад
Родитель
Сommit
b6c6e3b115

+ 23 - 0
app/api/controller/School.php

@@ -137,4 +137,27 @@ class School extends Controller
         $list = $model->getComparisonList($ids, 3);
         return $this->renderSuccess(compact('list'));
     }
+
+    /**
+     * 校园时态
+     * @return \think\response\Json
+     * @throws \think\db\exception\DbException
+     */
+    public function news(){
+        $model = new SchoolNew();
+        $pageSize = $this->request->param('pageSize', 15);
+        $list = $model->getList($this->request->param(), (int)$pageSize);
+        return $this->renderSuccess(compact('list'));
+    }
+
+    /**
+     * 校园时态
+     * @return \think\response\Json
+     * @throws \think\db\exception\DbException
+     */
+    public function newsDetail(){
+        $model = new SchoolNew();
+        $info = $model->getDetail((int)$this->request->param('news_id'));
+        return $this->renderSuccess(compact('info'));
+    }
 }

+ 70 - 2
app/api/controller/SchoolSpeciality.php

@@ -10,7 +10,6 @@ use app\common\enum\OrderType as OrderTypeEnum;
 use app\common\enum\book\order\PayType as OrderPayTypeEnum;
 use app\api\model\SchoolSpeciality as SchoolSpecialityModel;
 use app\common\service\Order as OrderService;
-use cores\exception\BaseException;
 use think\response\Json;
 
 /**
@@ -47,6 +46,17 @@ class SchoolSpeciality extends Controller
     }
 
     /**
+     * 学校专业选项
+     * @return Json
+     */
+    public function options()
+    {
+        $model = new SchoolSpecialityModel;
+        $list = $model->getOptionList($this->request->param());
+        return $this->renderSuccess(compact('list'));
+    }
+
+    /**
      * 同类专业学校
      * @return Json
      * @throws \think\db\exception\DbException
@@ -192,7 +202,7 @@ class SchoolSpeciality extends Controller
         // 订单处理
         $model = new Order;
         $orderId = $this->request->param('order_id',0);
-        if(!$model->refundOrder((int)$orderId, $this->request->param())){
+        if(!$model->setDelivery((int)$orderId, $this->request->param())){
             return $this->renderError($model->getError() ?: '订单设置发货失败');
         }
         return $this->renderSuccess(['order_id'=>$orderId], '订单设置发货成功');
@@ -278,4 +288,62 @@ class SchoolSpeciality extends Controller
         }
         return $this->renderSuccess(['order_id'=>$orderId], '订单确认退款成功');
     }
+
+    /**
+     * 修改订单信息
+     * @return Json
+     */
+    public function modifyOrder()
+    {
+        // 订单处理
+        $model = new Order;
+        $orderId = $this->request->param('order_id',0);
+        if(!$model->modifyOrder((int)$orderId, $this->request->param())){
+            return $this->renderError($model->getError() ?: '修改订单信息失败');
+        }
+        return $this->renderSuccess(['order_id'=>$orderId], '修改订单信息成功');
+    }
+
+    /**
+     * 取消订单
+     * @return Json
+     */
+    public function cancelOrder()
+    {
+        // 订单处理
+        $model = new Order;
+        $orderId = $this->request->param('order_id',0);
+        if(!$model->cancelOrder((int)$orderId, $this->request->param('remark'))){
+            return $this->renderError($model->getError() ?: '取消订单失败');
+        }
+        return $this->renderSuccess(['order_id'=>$orderId], '取消订单成功');
+    }
+
+    /**
+     * 报名订单列表
+     * @return Json
+     * @throws \app\common\exception\BaseException
+     * @throws \think\db\exception\DbException
+     */
+    public function orderList()
+    {
+        // 订单处理
+        $model = new Order;
+        $params = $this->request->param();
+        $pageSize = $this->request->param('pageSize', 15);
+        $type = $this->request->param('type', 1);
+        $userInfo = UserService::getCurrentLoginUser(true);
+        $userId = isset($userInfo['user_id'])? $userInfo['user_id'] : 0;
+        if($type == 1){
+            $params['book_user_id'] = $userId;
+        }else{
+            $params['user_id'] = $userId;
+        }
+
+        $list = $model->getList($params, (int)$pageSize);
+        return $this->renderSuccess(compact('list'));
+    }
+
+
+
 }

+ 5 - 2
app/api/controller/Setting.php

@@ -48,7 +48,10 @@ class Setting extends Controller
     {
         $payment =  Payment::getPaySetting();
         $trade = SettingModel::getItem('trade');
-        $costs = isset($trade['costs'])? $trade['costs'] : ['book_cost'=>0,'locked_cost'=>0];
-        return $this->renderSuccess(compact('payment','costs'));
+        $trade = [
+            'locked'=>isset($trade['locked'])? $trade['locked'] : ['locked_cost'=>0],
+            'books'=>isset($trade['books'])? $trade['books'] : ['book_cost'=>0,'book_limit'=>0,'fields'=>[]],
+        ];
+        return $this->renderSuccess(compact('payment','trade'));
     }
 }

+ 27 - 0
app/api/model/SchoolNew.php

@@ -32,6 +32,7 @@ class SchoolNew extends SchoolNewModel
     ];
 
     /**
+     * 显示分类列表(有数量限制)
      * @param $schoolId
      * @param int $type
      * @param int $limitRow
@@ -44,4 +45,30 @@ class SchoolNew extends SchoolNewModel
     {
         return parent::getShowList($schoolId, $type, $limitRow); // TODO: Change the autogenerated stub
     }
+
+    /**
+     * 详情
+     * @param int $id
+     * @return SchoolNew|array|null
+     */
+    public static function getDetail(int $id){
+        $info = static::detail($id,['school']);
+        if(isset($info['logo'])){
+            $info['logo_preview'] = $info['logo']? getPreview($info['logo']) : '';
+        }
+        $info->hidden(['update_time','status']);
+        if($info){
+            self::setIncViews($id);
+        }
+
+        return $info;
+    }
+
+    /**
+     * 访问量
+     * @param $id
+     */
+    public static function setIncViews($id){
+        (new static())->setInc(['news_id'=> $id], 'views', 1);
+    }
 }

+ 25 - 0
app/api/model/SchoolSpeciality.php

@@ -101,6 +101,31 @@ class SchoolSpeciality extends SchoolSpecialityModel
         });
     }
 
+    /**
+     * 获取选项列表
+     * @param array $param 查询条件
+     * @param int $listRows 分页数量
+     * @return mixed|\think\model\Collection|\think\Paginator
+     * @throws \think\db\exception\DbException
+     */
+    public function getOptionList(array $param = [], string $field='')
+    {
+        return $this->where(['status'=> 1])
+            ->where(function ($query) use ($param){
+                $keyword = isset($param['keyword'])? trim($param['keyword']) : '';
+                if($keyword){
+                    $query->where('speciality_name','like',"%{$keyword}%");
+                }
+
+                $schoolId = isset($param['school_id'])? intval($param['school_id']) : 0;
+                if($schoolId>0){
+                    $query->where('school_id','=',$schoolId);
+                }
+            })
+            ->field($field?:'speciality_id,speciality_name')
+            ->order('views desc,speciality_id desc')
+            ->select();
+    }
 
     /**
      * 获取学校的专业

+ 193 - 11
app/api/model/book/Order.php

@@ -14,20 +14,16 @@ namespace app\api\model\book;
 
 use app\api\model\School;
 use app\api\model\SchoolSpeciality;
-use app\api\model\Setting as SettingModel;
 use app\api\model\SpecialityBook;
 use app\api\model\User;
 use app\api\service\User as UserService;
-use app\common\library\helper;
 use app\common\library\wechat\WxPay;
 use app\common\model\book\Order as OrderModel;
 use app\common\model\wxapp\Setting as WxappSettingModel;
 use app\common\service\Order as OrderService;
-use app\api\service\book\PaySuccess as OrderPaySuccesService;
-use app\api\service\Order\source\Factory as OrderSourceFactory;
 use app\common\enum\book\order\PayStatus as PayStatusEnum;
-use app\common\enum\book\order\PayType as OrderPayTypeEnum;
 use app\common\exception\BaseException;
+use think\model\relation\HasOne;
 
 /**
  * 用户报名订单模型
@@ -49,20 +45,61 @@ class Order extends OrderModel
     ];
 
     /**
+     * 关联学校
+     * @return HasOne
+     */
+    public function school(): HasOne
+    {
+        return $this->HasOne('app\\common\\model\\School','id','school_id')
+            ->field('school_name,logo')
+            ->bind(['school_name as book_school_name']);
+    }
+
+    /**
+     * 关联学校
+     * @return HasOne
+     */
+    public function speciality(): HasOne
+    {
+        return $this->HasOne('app\\common\\model\\SchoolSpeciality','speciality_id','speciality_id')
+            ->bind(['speciality_name']);
+    }
+
+    /**
      * 获取订单列表
      * @return \think\Paginator
      * @throws BaseException
      * @throws \think\db\exception\DbException
      */
-    public function getList()
+    public function getList($params=[], $listRows=15)
     {
         // 当前用户ID
         $userId = UserService::getCurrentLoginUserId();
         // 获取列表数据
-        return $this->where('user_id', '=', $userId)
+        $list = $this->with(['school','speciality'])->where('book_user_id', '=', $userId)
             ->where('status', '>=', PayStatusEnum::PENDING)
+            ->where(function ($query) use($params){
+                // 用户订单
+                $userId = isset($params['book_user_id'])? $params['book_user_id'] : 0;
+                if($userId>0){
+                    $query->where('book_user_id','=', $userId);
+                }
+
+                // 老师订单
+                $teacherId = isset($params['user_id'])? $params['user_id'] : 0;
+                if($teacherId>0){
+                    $query->where('user_id','=', $teacherId);
+                }
+
+                $status = isset($params['status'])? $params['status'] : 0;
+                if($status>0 || $status == -2){
+                    $query->where('status','=', $status);
+                }
+            })
             ->order(['create_time' => 'desc'])
-            ->paginate(15);
+            ->paginate($listRows);
+        $list->hidden(['fields','']);
+        return $list;
     }
 
     /**
@@ -234,6 +271,90 @@ class Order extends OrderModel
         return $this->save($order);
     }
 
+    public function modifyOrder($orderId, $params=[])
+    {
+        if(empty($orderId)){
+            $this->error = '订单参数错误';
+            return false;
+        }
+
+        $modifyType = isset($params['type'])? $params['type'] : 0;
+        if(!in_array($modifyType, [1,2])){
+            $this->error = '订单修改类型错误';
+            return false;
+        }
+
+        $model = self::detail($orderId);
+        if(empty($model)){
+            $this->error = '订单不存在';
+            return false;
+        }
+        $data = ['update_time'=> time()];
+        if($modifyType == 1){
+            if(!in_array($model['status'],[1,2,3])){
+                $this->error = '订单状态不可操作';
+                return false;
+            }
+
+            $receiptName = isset($params['receipt_name'])? $params['receipt_name'] : '';
+            if(empty($receiptName)){
+                $this->error = '请填写收货人姓名';
+                return false;
+            }
+            $receiptMobile = isset($params['receipt_mobile'])? $params['receipt_mobile'] : '';
+            if(empty($receiptMobile)){
+                $this->error = '请填写收货人联系电话';
+                return false;
+            }
+            $receiptAddress = isset($params['receipt_address'])? $params['receipt_address'] : '';
+            if(empty($receiptAddress)){
+                $this->error = '请填写收货人地址';
+                return false;
+            }
+
+            $data = [
+                'receipt_name'=> $receiptName,
+                'receipt_mobile'=> $receiptMobile,
+                'receipt_address'=> $receiptAddress,
+            ];
+        }else if ($modifyType == 2){
+            if(!in_array($model['status'],[1,2,3])){
+                $this->error = '订单状态不可操作';
+                return false;
+            }
+
+            $specialityId = isset($params['speciality_id'])? intval(['speciality_id']) : 0;
+            if(empty($specialityId)){
+                $this->error = '请选择修改的专业';
+                return false;
+            }
+
+            // 专业参数验证
+            $speciality = SchoolSpeciality::detail($specialityId);
+            if(empty($speciality)){
+                $this->error = '报名专业不存在';
+                return false;
+            }
+            if($speciality['school_id'] != $model['school_id']){
+                $this->error = '报名专业和学校不匹配';
+                return false;
+            }
+
+            // 报名人数验证
+            $bookNum = SpecialityBook::getBooks($specialityId);
+            $remainBookNum = max(0, $speciality['recruit_num'] - $bookNum);
+            if($remainBookNum <= 0){
+                $this->error = '该专业报名人数已满';
+                return false;
+            }
+
+            $data = [
+                'speciality_id' => $specialityId
+            ];
+        }
+
+        return $model->save($data);
+    }
     /**
      * 验证支付订单
      * @param $order
@@ -246,6 +367,7 @@ class Order extends OrderModel
     {
         $orderId = isset($order['order_id'])? $order['order_id'] : 0;
         if($orderId<=0){
+            $this->error = '订单参数错误';
             return false;
         }
         $orderStatus = isset($order['status'])? $order['status'] : 0;
@@ -329,6 +451,42 @@ class Order extends OrderModel
     }
 
     /**
+     * 取消订单
+     * @param $orderId
+     * @param string $remark
+     * @return bool
+     * @throws BaseException
+     * @throws \cores\exception\BaseException
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function cancelOrder($orderId, $remark='')
+    {
+        if(empty($orderId)){
+            $this->error = '订单参数错误';
+            return false;
+        }
+        $model = new Order();
+        $model = $model::getUserOrderDetail($orderId);
+        if(!$model){
+            $this->error = '报名订单不存在';
+            return false;
+        }
+        // 订单所属老师才何以设置
+        $userInfo = UserService::getCurrentLoginUser(true);
+        if($userInfo['user_id'] != $model['book_user_id']){
+            $this->error = '订单无权操作';
+            return false;
+        }
+        if(!in_array($model['status'], [1,2])){
+            $this->error = '订单状态不可操作';
+            return false;
+        }
+
+        return $model->save(['status'=> -1,'update_time'=> time(),'remark'=> $remark]);
+    }
+    /**
      * 订单发货设置
      * @param int $orderId 订单ID
      * @param $params 发货参数:快递公司ID、快递公司名称、快递单号
@@ -372,6 +530,10 @@ class Order extends OrderModel
             $this->error = '订单无权操作';
             return false;
         }
+        if(in_array($model['status'], [1,2])){
+            $this->error = '订单未支付';
+            return false;
+        }
         if($model['status'] != 3){
             $this->error = '订单已发货或状态不可操作';
             return false;
@@ -450,7 +612,12 @@ class Order extends OrderModel
             $this->error = '订单无权操作';
             return false;
         }
-        if($model['refund_status'] != 1 || $model['status'] <=1){
+        if(in_array($model['status'], [1,2])){
+            $this->error = '订单未支付';
+            return false;
+        }
+
+        if($model['refund_status'] != 1 || !in_array($model['status'], [3,4])){
             $this->error = '订单设置为可退款或状态不可操作';
             return false;
         }
@@ -492,7 +659,13 @@ class Order extends OrderModel
             $this->error = '订单无权操作';
             return false;
         }
-        if($model['refund_status'] != 2 || $model['status'] <=1){
+
+        if(in_array($model['status'], [1,2])){
+            $this->error = '订单未支付';
+            return false;
+        }
+
+        if($model['refund_status'] != 2 || !in_array($model['status'], [3,4])){
             $this->error = '订单已申请退款或状态不可操作';
             return false;
         }
@@ -535,8 +708,17 @@ class Order extends OrderModel
             $this->error = '订单无权操作';
             return false;
         }
+        if($model['status'] == -2){
+            $this->error = '订单已退款';
+            return false;
+        }
+
+        if(in_array($model['status'], [1,2])){
+            $this->error = '订单未支付';
+            return false;
+        }
 
-        if($model['refund_status'] != 3 || $model['status'] <= 0){
+        if($model['refund_status'] != 3 || !in_array($model['status'], [3,4])){
             $this->error = '订单已退款或状态不可操作';
             return false;
         }

+ 14 - 0
app/common/enum/book/order/PayStatus.php

@@ -21,6 +21,12 @@ use app\common\enum\EnumBasics;
  */
 class PayStatus extends EnumBasics
 {
+    // 已退款
+    const REFUND = -2;
+
+    // 已取消
+    const CANCEL = -1;
+
     // 待支付
     const PENDING = 1;
 
@@ -46,6 +52,14 @@ class PayStatus extends EnumBasics
     public static function data()
     {
         return [
+            self::REFUND => [
+                'name' => '已退款',
+                'value' => self::REFUND,
+            ],
+            self::CANCEL => [
+                'name' => '已取消',
+                'value' => self::CANCEL,
+            ],
             self::PENDING => [
                 'name' => '未支付',
                 'value' => self::PENDING,

+ 2 - 0
app/common/model/School.php

@@ -26,6 +26,8 @@ use think\Paginator;
  */
 class School extends BaseModel
 {
+    protected $globalScope = [''];
+
     // 定义表名
     protected $name = 'schools';
 

+ 64 - 1
app/common/model/SchoolNew.php

@@ -13,6 +13,7 @@ declare (strict_types=1);
 namespace app\common\model;
 
 use cores\BaseModel;
+use think\model\relation\HasOne;
 
 /**
  * 学校图库模型类
@@ -30,6 +31,15 @@ class SchoolNew extends BaseModel
     protected $pk = 'news_id';
 
     /**
+     * 关联学校
+     * @return HasOne
+     */
+    public function school(): HasOne
+    {
+        return $this->HasOne('School','id','school_id')->field('id,school_name,logo')->bind(['school_name']);
+    }
+
+    /**
      * 获取学校新闻资讯列表
      * @param $schoolId
      * @param int $limitRow
@@ -64,7 +74,60 @@ class SchoolNew extends BaseModel
         return $list;
     }
 
-    public function getList($where, $limitRow= 15){
+    public function getList(array $params, $limitRow= 15){
+
+        $cacheKey = "caches:schools:newsList:{$limitRow}_".md5(json_encode($params));
+        if($list = \think\facade\Cache::get($cacheKey)){
+            return $list;
+        }
+
+        $where = ['status'=> 1];
+        $schoolId =
+        $query = self::where(['status'=>1])->where(function($query) use($params){
+            $schoolId = isset($params['school_id'])? $params['school_id'] : 0;
+            if($schoolId){
+                $query->where('school_id','=', $schoolId);
+            }
+
+            $type = isset($params['type'])? $params['type'] : 0;
+            if($type){
+                $query->where('type','=', $type);
+            }
 
+
+            $keyword = isset($params['keyword'])? $params['keyword'] : '';
+            if($keyword){
+                $query->where('title','like', "%{$keyword}%");
+            }
+
+        });
+        if($limitRow){
+            $query->limit($limitRow);
+        }
+
+        $list = $query->order('addtime desc,news_id desc')->paginate($limitRow);
+        $list->hidden(['content','update_time','status']);
+        if($list){
+            foreach ($list as &$item){
+                $item['logo_preview'] = $item['logo']? getPreview($item['logo']) : '';
+                $item['publish_time'] = $item['addtime']? date('Y/m/d', strtotime($item['addtime'])) : '';
+            }
+
+            \think\facade\Cache::set($cacheKey, $list, rand(10, 30));
+        }
+
+        return $list;
+    }
+
+    /**
+     * 详情
+     * @param int $id
+     * @param array $with
+     * @return array|null|static
+     */
+    public static function detail(int $id, array $with = [])
+    {
+        return self::get($id, $with);
     }
+
 }

+ 11 - 0
app/common/model/SpecialityBook.php

@@ -165,4 +165,15 @@ class SpecialityBook extends BaseModel
             ->field('user_id,gender,nick_name,preview_url as avatar_url')
             ->bind(['nick_name','avatar_url']);
     }
+
+    /**
+     * 批量更新订单
+     * @param $orderIds
+     * @param $data
+     * @return bool|false
+     */
+    public function onBatchUpdate($orderIds, $data): bool
+    {
+        return static::updateBase($data, [['order_id', 'in', $orderIds]]);
+    }
 }

+ 42 - 0
app/common/service/Book.php

@@ -0,0 +1,42 @@
+<?php
+// +----------------------------------------------------------------------
+// | 商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2017~2021 https://www.thinkphp.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
+// +----------------------------------------------------------------------
+// | Author: thinkphp <admin@yiovo.com>
+// +----------------------------------------------------------------------
+declare (strict_types=1);
+
+namespace app\common\service;
+
+use app\store\model\User as UserModel;
+use app\common\model\SpecialityBook as OrderModel;
+
+/**
+ * 报名订单服务类
+ * Class Book
+ * @package app\common\service
+ */
+class Book extends BaseService
+{
+    /**
+     * 生成订单号`
+     * @return string
+     */
+    public static function createOrderNo(): string
+    {
+        return date('Ymd') . substr(implode('', array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
+    }
+
+    /**
+     * 事件:订单取消
+     * @param OrderModel $order
+     */
+    public static function cancelEvent(OrderModel $order)
+    {
+        return true;
+    }
+}

+ 1 - 0
app/console/command/Timer.php

@@ -87,6 +87,7 @@ class Timer extends Command
                 // 这里执行系统预设的定时任务事件
                 echo 'timer...' . PHP_EOL;
                 Event::trigger('StoreTask');
+                Event::trigger('BookTask');
             } catch (\Throwable $e) {
                 echo 'ERROR: ' . $e->getMessage() . PHP_EOL;
                 $this->stop();

+ 138 - 0
app/console/model/Book.php

@@ -0,0 +1,138 @@
+<?php
+// +----------------------------------------------------------------------
+// | 商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2017~2021 https://www.thinkphp.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
+// +----------------------------------------------------------------------
+// | Author: thinkphp <admin@yiovo.com>
+// +----------------------------------------------------------------------
+declare (strict_types = 1);
+
+namespace app\console\model;
+
+use app\common\model\SpecialityBook as OrderModel;
+use app\common\enum\book\order\PayStatus as PayStatusEnum;
+
+/**
+ * 报名订单模型
+ * Class Book
+ * @package app\common\model
+ */
+class Book extends OrderModel
+{
+    /**
+     * 获取订单列表
+     * @param array $filter
+     * @param array $with
+     * @return \think\Collection
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function getList($filter = [], $with = [])
+    {
+        return $this->with($with)
+            ->where($filter)
+            ->where('status', '>=', PayStatusEnum::PENDING)
+            ->select();
+    }
+
+    /**
+     * 获取订单ID集
+     * @param array $filter
+     * @return array
+     */
+    public function getOrderIds($filter = [])
+    {
+        return $this->where($filter)
+            ->where('status', '>=', PayStatusEnum::PENDING)
+            ->column('order_id');
+    }
+
+    /**
+     * 查询截止时间未支付的订单列表
+     * @param int $deadlineTime 截止日期的时间戳
+     * @return \think\Collection
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function getListByClose(int $deadlineTime)
+    {
+        // 查询条件
+        $filter = [
+            ['status', '=', PayStatusEnum::PENDING],
+            ['create_time', '<=', $deadlineTime],
+        ];
+        // 查询列表记录
+        return $this->getList($filter);
+    }
+
+    /**
+     * 查询截止时间已完成的订单列表
+     * @param array $orderIds 订单ID集
+     * @return \think\Collection
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function getListByOrderIds(array $orderIds)
+    {
+        // 查询条件
+        $filter = [['order_id', 'in', $orderIds]];
+        // 查询列表记录
+        return $this->getList($filter);
+    }
+
+    /**
+     * 查询截止时间未确认收货的订单ID集
+     * @param int $deadlineTime 截止时间
+     * @return array
+     */
+    public function getOrderIdsByReceive(int $deadlineTime)
+    {
+        // 查询条件
+        $filter = [
+            ['status', '=', PayStatusEnum::DELIVERY],
+            ['delivery_time', '<=', $deadlineTime]
+        ];
+        // 查询列表记录
+        return $this->getOrderIds($filter);
+    }
+
+    /**
+     * 查询截止时间确认收货的订单列表
+     * @param int $storeId 商城ID
+     * @param int $deadlineTime 截止时间
+     * @return \think\Collection
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function getOrderListBySettled(int $deadlineTime)
+    {
+        // 查询条件
+        $filter = [
+            ['status', '=', PayStatusEnum::COMPLETE],
+            ['receipt_time', '<=', $deadlineTime],
+            ['is_settled', '=', 2]
+        ];
+        // 查询列表记录
+        return $this->getList($filter);
+    }
+
+    /**
+     * 批量更新订单状态为已收货
+     * @param array $orderIds
+     * @return false|int
+     */
+    public function onUpdateReceived(array $orderIds)
+    {
+        return $this->onBatchUpdate($orderIds, [
+            'receipt_time' => time(),
+            'status' => PayStatusEnum::COMPLETE
+        ]);
+    }
+}

+ 92 - 0
app/console/service/Book.php

@@ -0,0 +1,92 @@
+<?php
+// +----------------------------------------------------------------------
+// | 商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2017~2021 https://www.thinkphp.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
+// +----------------------------------------------------------------------
+// | Author: thinkphp <admin@yiovo.com>
+// +----------------------------------------------------------------------
+declare (strict_types=1);
+
+namespace app\console\service;
+
+use app\common\enum\book\order\PayStatus;
+use app\console\model\Book as OrderModel;
+use app\common\service\BaseService;
+use app\common\service\Book as OrderService;
+use app\common\library\helper;
+use app\console\library\Tools;
+
+/**
+ * 服务类:报名订单订单模块
+ * Class Book
+ * @package app\console\service
+ */
+class Book extends BaseService
+{
+    /**
+     * 未支付订单自动关闭
+     * @param int $storeId
+     * @param int $closeHours 自定关闭订单有效期 (小时)
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function closeEvent(int $storeId, int $closeHours)
+    {
+        // 截止时间
+        $deadlineTime = time() - ((int)$closeHours * 60 * 60);
+        // 查询截止时间未支付的订单
+        $model = new OrderModel;
+        $list = $model->getListByClose($deadlineTime);
+        // 订单ID集
+        $orderIds = helper::getArrayColumn($list, 'order_id');
+        if (!empty($orderIds)) {
+            // 取消订单事件处理
+           /* foreach ($list as $order) {
+                OrderService::cancelEvent($order);
+            }*/
+            // 批量更新订单状态为已取消
+            $model->onBatchUpdate($orderIds, ['order_status' => PayStatus::CANCEL]);
+        }
+        // 记录日志
+        Tools::taskLogs('Book', 'closeEvent', [
+            'storeId' => $storeId,
+            'closeHours' => $closeHours,
+            'deadlineTime' => $deadlineTime,
+            'orderIds' => helper::jsonEncode($orderIds)
+        ]);
+    }
+
+    /**
+     * 已发货订单自动确认收货
+     * @param int $storeId
+     * @param int $receiveDays 自动收货天数
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function receiveEvent(int $storeId, int $receiveDays)
+    {
+        // 截止时间
+        $deadlineTime = time() - ((int)$receiveDays * 86400);
+        // 查询截止时间未确认收货的订单ID集
+        $model = new OrderModel;
+        $orderIds = $model->getOrderIdsByReceive($deadlineTime);
+        // 更新订单收货状态
+        if (!empty($orderIds)) {
+            // 批量更新订单状态为已收货
+            $model->onUpdateReceived($orderIds);
+        }
+        // 记录日志
+        Tools::taskLogs('Book', 'receiveEvent', [
+            'storeId' => $storeId,
+            'receiveDays' => $receiveDays,
+            'deadlineTime' => $deadlineTime,
+            'orderIds' => helper::jsonEncode($orderIds)
+        ]);
+    }
+
+}

+ 102 - 0
app/console/task/Book.php

@@ -0,0 +1,102 @@
+<?php
+// +----------------------------------------------------------------------
+// | 商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2017~2021 https://www.thinkphp.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
+// +----------------------------------------------------------------------
+// | Author: thinkphp <admin@yiovo.com>
+// +----------------------------------------------------------------------
+declare (strict_types=1);
+
+namespace app\console\task;
+
+use app\console\service\Book as OrderService;
+use app\console\model\Setting as SettingModel;
+
+/**
+ * 定时任务:报名订单
+ * Class Book
+ * @package app\console\task
+ */
+class Book extends Task
+{
+    // 当前任务唯一标识
+    private $taskKey = 'Book';
+
+    // 任务执行间隔时长 (单位:秒)
+    protected $taskExpire = 30;
+//    protected $taskExpire = 60 * 30;
+
+    // 当前商城ID
+    private $storeId;
+
+    /**
+     * 任务处理
+     * @param array $param
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function handle(array $param)
+    {
+        ['storeId' => $this->storeId] = $param;
+        $this->setInterval($this->storeId, $this->taskKey, $this->taskExpire, function () {
+            echo $this->taskKey . PHP_EOL;
+            // 未支付订单自动关闭
+            $this->closeEvent();
+            // 已发货订单自动确认收货
+            $this->receiveEvent();
+
+        });
+    }
+
+    /**
+     * 未支付订单自动关闭
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    private function closeEvent()
+    {
+        // 自动关闭订单的有效期
+        $closeHours = (int)$this->getTradeSetting()['closeHours'];
+        // 执行自动关闭
+        if ($closeHours > 0) {
+            $service = new OrderService;
+            $service->closeEvent($this->storeId, $closeHours);
+        }
+    }
+
+    /**
+     * 自动确认收货订单的天数
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    private function receiveEvent()
+    {
+        // 取消n天以前的的未付款订单
+        $receiveDays = (int)$this->getTradeSetting()['receive_days'];
+        // 执行自动确认收货
+        if ($receiveDays > 0) {
+            $service = new OrderService;
+            $service->receiveEvent($this->storeId, $receiveDays);
+        }
+    }
+
+    /**
+     * 获取商城交易设置
+     * @return array|mixed
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    private function getTradeSetting()
+    {
+        return SettingModel::getItem('trade', $this->storeId)['order'];
+    }
+}

+ 6 - 3
app/console/task/Store.php

@@ -12,6 +12,7 @@ declare (strict_types = 1);
 
 namespace app\console\task;
 
+use think\facade\Cache;
 use think\facade\Event;
 use app\console\model\Store as StoreModel;
 
@@ -30,13 +31,15 @@ class Store extends Task
         // 遍历商城列表并执行定时任务
         $storeIds = StoreModel::getStoreIds();
         foreach ($storeIds as $storeId) {
-            // echo $storeId . PHP_EOL;
+            //echo $storeId . PHP_EOL;
             // 定时任务:商城订单
             Event::trigger('Order', ['storeId' => $storeId]);
+            // 报名订单
+            Event::trigger('Book', ['storeId' => $storeId]);
             // 定时任务:用户优惠券
-            Event::trigger('UserCoupon', ['storeId' => $storeId]);
+            //Event::trigger('UserCoupon', ['storeId' => $storeId]);
             // 定时任务:会员等级
-            Event::trigger('UserGrade', ['storeId' => $storeId]);
+            //Event::trigger('UserGrade', ['storeId' => $storeId]);
         }
     }
 }

+ 5 - 0
app/event.php

@@ -22,6 +22,11 @@ return [
             \app\console\task\Order::class
         ],
 
+        // 定时任务:报名订单
+        'Book' => [
+            \app\console\task\Book::class
+        ],
+
         // 定时任务:用户优惠券
         'UserCoupon' => [
             \app\console\task\UserCoupon::class