diff --git a/application/admin/controller/school/activity/Activity.php b/application/admin/controller/school/activity/Activity.php index 6fcbeff..fe96682 100644 --- a/application/admin/controller/school/activity/Activity.php +++ b/application/admin/controller/school/activity/Activity.php @@ -308,4 +308,36 @@ class Activity extends Backend $this->error(__('No rows were deleted')); } + + + + /** + * 活动取消 + * @return string + * @throws \think\Exception + * @throws \think\db\exception\BindParamException + * @throws \think\exception\DbException + * @throws \think\exception\PDOException + */ + public function cancel($ids = ''){ + $param = $this->request->param(); + if($this->request->isPost()){ + try{ + if(isset($param['ids']))$ids = $param['ids']; + //设置模拟资格 + $model = (new \app\common\model\school\activity\Activity); + $model->cancel($ids,"2",false,'admin',$this->auth->id,true); + + }catch (\Exception $e){ + $this->error($e->getMessage()); + } + $this->success('取消成功!'); + } + $row = $this->model->get($ids); + $this->view->assign('vo', $row); + return $this->view->fetch(); + } + + + } diff --git a/application/admin/controller/school/activity/order/OrderLog.php b/application/admin/controller/school/activity/order/OrderLog.php new file mode 100644 index 0000000..f42fa65 --- /dev/null +++ b/application/admin/controller/school/activity/order/OrderLog.php @@ -0,0 +1,72 @@ +model = new \app\admin\model\school\activity\order\OrderLog; + $this->view->assign("statusList", $this->model->getStatusList()); + } + + + + /** + * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法 + * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑 + * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改 + */ + + + /** + * 查看 + */ + public function index() + { + //当前是否为关联查询 + $this->relationSearch = true; + //设置过滤方法 + $this->request->filter(['strip_tags', 'trim']); + if ($this->request->isAjax()) { + //如果发送的来源是Selectpage,则转发到Selectpage + if ($this->request->request('keyField')) { + return $this->selectpage(); + } + list($where, $sort, $order, $offset, $limit) = $this->buildparams(); + + $list = $this->model + ->with(['order','user']) + ->where($where) + ->order($sort, $order) + ->paginate($limit); + + foreach ($list as $row) { + + $row->getRelation('order')->visible(['order_no']); + $row->getRelation('user')->visible(['nickname','avatar']); + } + + $result = array("total" => $list->total(), "rows" => $list->items()); + + return json($result); + } + return $this->view->fetch(); + } + +} diff --git a/application/admin/lang/zh-cn/school/activity/cate.php b/application/admin/lang/zh-cn/school/activity/cate.php index 9705b31..8e49316 100644 --- a/application/admin/lang/zh-cn/school/activity/cate.php +++ b/application/admin/lang/zh-cn/school/activity/cate.php @@ -2,6 +2,7 @@ return [ 'Name' => '分类名', + "Image" => '分类icon', 'Status' => '状态', 'Status 1' => '上架', 'Set status to 1'=> '设为上架', diff --git a/application/admin/lang/zh-cn/school/activity/order/order_log.php b/application/admin/lang/zh-cn/school/activity/order/order_log.php new file mode 100644 index 0000000..3c80489 --- /dev/null +++ b/application/admin/lang/zh-cn/school/activity/order/order_log.php @@ -0,0 +1,31 @@ + '活动订单id', + 'Status' => '订单状态', + 'Status -3' => '已取消', + 'Set status to -3' => '设为已取消', + 'Status 0' => '待支付', + 'Set status to 0' => '设为待支付', + 'Status 2' => '已报名', + 'Set status to 2' => '设为已报名', + 'Status 3' => '核销中', + 'Set status to 3' => '设为核销中', + 'Status 4' => '售后中', + 'Set status to 4' => '设为售后中', + 'Status 5' => '退款结算中', + 'Set status to 5' => '设为退款结算中', + 'Status 6' => '已退款', + 'Set status to 6' => '设为已退款', + 'Status 9' => '已完成', + 'Set status to 9' => '设为已完成', + 'Log_text' => '记录内容', + 'Oper_type' => '记录人类型', + 'Oper_id' => '记录人id', + 'Createtime' => '创建时间', + 'Updatetime' => '修改时间', + 'Deletetime' => '删除时间', + 'Order.order_no' => '订单号', + 'User.nickname' => '昵称', + 'User.avatar' => '头像' +]; diff --git a/application/admin/lang/zh-cn/school/activity/refund.php b/application/admin/lang/zh-cn/school/activity/refund.php index 5d9e7b3..97a61fd 100644 --- a/application/admin/lang/zh-cn/school/activity/refund.php +++ b/application/admin/lang/zh-cn/school/activity/refund.php @@ -1,13 +1,12 @@ '策略标题', - 'Desc' => '策略说明', - 'Refund_hour' => '退款小时', - 'Refund_scale' => '退款比例', - 'Weigh' => '权重', - 'Createtime' => '创建时间', - 'Updatetime' => '修改时间', - 'Deletetime' => '删除时间', - + 'Title' => '策略标题', + 'Desc' => '策略说明', + 'Refund_hour' => '退款小时', + 'Refund_scale_json' => '退款比例', + 'Weigh' => '权重', + 'Createtime' => '创建时间', + 'Updatetime' => '修改时间', + 'Deletetime' => '删除时间' ]; diff --git a/application/admin/model/school/activity/order/OrderLog.php b/application/admin/model/school/activity/order/OrderLog.php new file mode 100644 index 0000000..2b2be4d --- /dev/null +++ b/application/admin/model/school/activity/order/OrderLog.php @@ -0,0 +1,59 @@ + __('Status -3'), '0' => __('Status 0'), '2' => __('Status 2'), '3' => __('Status 3'), '4' => __('Status 4'), '5' => __('Status 5'), '6' => __('Status 6'), '9' => __('Status 9')]; + } + + + public function getStatusTextAttr($value, $data) + { + $value = $value ? $value : (isset($data['status']) ? $data['status'] : ''); + $list = $this->getStatusList(); + return isset($list[$value]) ? $list[$value] : ''; + } + + + + + public function order() + { + return $this->belongsTo(Order::class, 'activity_order_id', 'id', [], 'LEFT')->setEagerlyType(0); + } + + + public function user() + { + return $this->belongsTo('app\common\model\User', 'oper_id', 'id', [], 'LEFT')->setEagerlyType(0); + } +} diff --git a/application/admin/validate/school/activity/order/OrderLog.php b/application/admin/validate/school/activity/order/OrderLog.php new file mode 100644 index 0000000..e79fc45 --- /dev/null +++ b/application/admin/validate/school/activity/order/OrderLog.php @@ -0,0 +1,27 @@ + [], + 'edit' => [], + ]; + +} diff --git a/application/admin/view/school/activity/activity/add.html b/application/admin/view/school/activity/activity/add.html index 1b56b41..5471656 100644 --- a/application/admin/view/school/activity/activity/add.html +++ b/application/admin/view/school/activity/activity/add.html @@ -49,7 +49,7 @@
- + (没找到退款策略则点击按钮创建退款策略后重新下拉框选退款策略) diff --git a/application/admin/view/school/activity/activity/edit.html b/application/admin/view/school/activity/activity/edit.html index 7cb2c3d..191712a 100644 --- a/application/admin/view/school/activity/activity/edit.html +++ b/application/admin/view/school/activity/activity/edit.html @@ -52,7 +52,7 @@
- + (没找到退款策略则点击按钮创建退款策略后重新下拉框选退款策略) diff --git a/application/admin/view/school/activity/cate/add.html b/application/admin/view/school/activity/cate/add.html index 8d2e22b..d92cb19 100644 --- a/application/admin/view/school/activity/cate/add.html +++ b/application/admin/view/school/activity/cate/add.html @@ -1,5 +1,23 @@
+ +
+ +
+
+ +
+ + +
+ +
+
    +
    ( 推荐图片尺寸:100*100 )
    +
    +
    + +
    diff --git a/application/admin/view/school/activity/cate/edit.html b/application/admin/view/school/activity/cate/edit.html index 95fd384..d7e2d7c 100644 --- a/application/admin/view/school/activity/cate/edit.html +++ b/application/admin/view/school/activity/cate/edit.html @@ -1,5 +1,23 @@ +
    + +
    +
    + +
    + + +
    + +
    +
      +
      ( 推荐图片尺寸:100*100 )
      +
      +
      + + +
      diff --git a/application/admin/view/school/activity/order/order_log/add.html b/application/admin/view/school/activity/order/order_log/add.html new file mode 100644 index 0000000..08a4b9e --- /dev/null +++ b/application/admin/view/school/activity/order/order_log/add.html @@ -0,0 +1,45 @@ + + +
      + +
      + +
      +
      +
      + +
      + +
      + {foreach name="statusList" item="vo"} + + {/foreach} +
      + +
      +
      +
      + +
      + +
      +
      +
      + +
      + +
      +
      +
      + +
      + +
      +
      + + diff --git a/application/admin/view/school/activity/order/order_log/edit.html b/application/admin/view/school/activity/order/order_log/edit.html new file mode 100644 index 0000000..95ffc27 --- /dev/null +++ b/application/admin/view/school/activity/order/order_log/edit.html @@ -0,0 +1,45 @@ +
      + +
      + +
      + +
      +
      +
      + +
      + +
      + {foreach name="statusList" item="vo"} + + {/foreach} +
      + +
      +
      +
      + +
      + +
      +
      +
      + +
      + +
      +
      +
      + +
      + +
      +
      + +
      diff --git a/application/admin/view/school/activity/order/order_log/index.html b/application/admin/view/school/activity/order/order_log/index.html new file mode 100644 index 0000000..5a715b9 --- /dev/null +++ b/application/admin/view/school/activity/order/order_log/index.html @@ -0,0 +1,46 @@ +
      + +
      + {:build_heading(null,FALSE)} + +
      + + +
      +
      +
      +
      +
      + + {:__('Add')} + {:__('Edit')} + {:__('Delete')} + + + + + {:__('Recycle bin')} +
      + +
      +
      +
      + +
      +
      +
      diff --git a/application/admin/view/school/activity/order/order_log/recyclebin.html b/application/admin/view/school/activity/order/order_log/recyclebin.html new file mode 100644 index 0000000..3e1e641 --- /dev/null +++ b/application/admin/view/school/activity/order/order_log/recyclebin.html @@ -0,0 +1,25 @@ +
      + {:build_heading()} + +
      +
      +
      + +
      + +
      +
      +
      diff --git a/application/admin/view/school/activity/refund/add.html b/application/admin/view/school/activity/refund/add.html index e6ebb8e..929dec6 100644 --- a/application/admin/view/school/activity/refund/add.html +++ b/application/admin/view/school/activity/refund/add.html @@ -19,9 +19,19 @@
      - +
      - + +
      +
      + {:__('Key')} + {:__('Value')} +
      +
      {:__('Append')}
      + +
      + +
      diff --git a/application/admin/view/school/activity/refund/edit.html b/application/admin/view/school/activity/refund/edit.html index f9cbc2a..cb9bc7b 100644 --- a/application/admin/view/school/activity/refund/edit.html +++ b/application/admin/view/school/activity/refund/edit.html @@ -19,9 +19,19 @@
      - +
      - + +
      +
      + {:__('Key')} + {:__('Value')} +
      +
      {:__('Append')}
      + +
      + +
      diff --git a/application/api/controller/Crontab.php b/application/api/controller/Crontab.php index 7f556a2..fc49976 100644 --- a/application/api/controller/Crontab.php +++ b/application/api/controller/Crontab.php @@ -4,7 +4,7 @@ namespace app\api\controller; use addons\epay\library\Service; use app\common\controller\Api; use app\common\library\NightSchoolBigData; -use app\common\model\school\classes\ClassesLib; +use app\common\model\school\activity\Activity; use app\common\model\school\classes\order\Order; use app\common\model\school\classes\VisitDistribution; use bw\UrlLock; @@ -101,14 +101,16 @@ class Crontab extends Api /** - * 每五分钟执行的任务 + * 每1分钟执行的任务 */ public function minute() { try{ - $res = Order::timeoutCheck(true); - $res = \app\common\model\school\classes\activity\order\Order::timeoutCheck(true); +// $res = Order::timeoutCheck(true); +// $res = \app\common\model\school\classes\activity\order\Order::timeoutCheck(true); + Activity::timeoutCheck(true); + // $lock = new UrlLock(2,"mock-lock-suffix",5,"您的请求过于频繁,请您稍后再试!"); // $lock->lock(); diff --git a/application/api/controller/Index.php b/application/api/controller/Index.php index ff46ef6..cad68d7 100644 --- a/application/api/controller/Index.php +++ b/application/api/controller/Index.php @@ -98,6 +98,7 @@ class Index extends Api "site_city"=> Virtual::getNowCity(), "site_timezone"=>config('site.timezone'), "wx_miniapp_version"=>config("site.wx_miniapp_version"), + "activity_withdrawal_scale" => config("site.activity_withdrawal_scale"), ]; $customer_service = [ "image"=>cdnurl(config('site.customer_service_image'),true), diff --git a/application/api/controller/school/NewActivity.php b/application/api/controller/school/NewActivity.php index a030f63..39d2bff 100644 --- a/application/api/controller/school/NewActivity.php +++ b/application/api/controller/school/NewActivity.php @@ -11,7 +11,7 @@ use app\common\model\school\activity\Refund; */ class NewActivity extends Base { - protected $noNeedLogin = ['cate_list',"activity_list","detail","refund_list"]; + protected $noNeedLogin = ['cate_list',"activity_list","detail","refund_list","add"]; protected $noNeedRight = '*'; protected $model = null; @@ -258,7 +258,7 @@ class NewActivity extends Base *}) */ public function add(){ - $user_id = 0; + $user_id = 73; $user = $this->auth->getUser();//登录用户 if($user)$user_id = $user['id']; $params = []; @@ -335,5 +335,31 @@ class NewActivity extends Base $this->success('查询成功', $res); } + + + + /** + * @ApiTitle( 活动取消) + * @ApiSummary(活动取消)) + * @ApiMethod(POST) + * @ApiParams(name = "id", type = "string",required=true,description = "活动id") + * @ApiReturn({ + * + *}) + */ + public function cancel(){ + $user_id = 0; + $user = $this->auth->getUser();//登录用户 + if($user)$user_id = $user['id']; + $id = $this->request->post('id/d', ''); //订单号 + try{ + //当前申请状态 + $res = $this->model->cancel($id,"2",true,'user',$user_id,true); + }catch (\Throwable $e){ + $this->error($e->getMessage()); + } + $this->success('预约课时取消成功', $res); + } + } diff --git a/application/common/hooks.php b/application/common/hooks.php index e1ed337..a01c1c6 100644 --- a/application/common/hooks.php +++ b/application/common/hooks.php @@ -263,6 +263,9 @@ $newactivityHooks = [ 'new_activity_collect_cancel_after' => [ // 活动取消收藏后 'app\\common\\listener\\activity\\ActivityHook' ], + 'new_activity_cancel_success_after' => [ // 活动取消后 + 'app\\common\\listener\\activity\\ActivityHook' + ], ]; diff --git a/application/common/listener/activity/ActivityHook.php b/application/common/listener/activity/ActivityHook.php index ff50916..f25c3cd 100644 --- a/application/common/listener/activity/ActivityHook.php +++ b/application/common/listener/activity/ActivityHook.php @@ -1,6 +1,7 @@ $activity,"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id] = $params; + + $system_user_id = config("site.system_user_id");//系统用户 + + $user = User::where("id",$user_id)->find(); + //课程推送给老师 + $mini_type = "activity_apply"; + $to_id = $system_user_id; + $status ="activity"; + $params=[ + "event"=>"new_activity_auth_success_after", + "activity_id"=>$activity["id"], + ]; + + $param = [ + "realname"=> $user["realname"], + "nickname"=> $user["nickname"], + "mobile"=> $user["mobile"], + "title" => $activity['title'], + "address"=>$activity["address"]."(".$activity["address_detail"].")", + "price" => $activity["price"], + "start_time" => date("Y-m-d H:i",$activity["start_time"]), //格式化日期格式 $order["start_time"], //格式化日期格式 + "end_time" => date("Y-m-d H:i",$activity["end_time"]), + "sign_start_time" => date("Y-m-d H:i",$activity["sign_start_time"]), //格式化日期格式 $order["start_time"], //格式化日期格式 + "sign_end_time" => date("Y-m-d H:i",$activity["sign_end_time"]), + "reason" => $activity['reason'], + ]; + + //发给用户 + (new MessageConfig) + ->setTemplate($params["event"]) + ->setTemplateData($param) + ->setToUid($to_id) + ->setMessageStatus($status) + ->setMessageMiniType($mini_type) + ->setMessageParams($params) + ->sendMessage(); + + + + + } + + // 课程审核失败后 + public function newActivityAuthFailAfter(&$params) + { + ['activity' => $activity,"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id] = $params; + $system_user_id = config("site.system_user_id");//系统用户 + $user = User::where("id",$user_id)->find(); +//课程推送给老师 + $mini_type = "activity_apply"; + $to_id = $system_user_id; + $status ="activity"; + $params=[ + "event"=>"new_activity_auth_fail_after", + "activity_id"=>$activity["id"], + ]; + + $param = [ + "realname"=> $user["realname"], + "nickname"=> $user["nickname"], + "mobile"=> $user["mobile"], + "title" => $activity['title'], + "address"=>$activity["address"]."(".$activity["address_detail"].")", + "price" => $activity["price"], + "start_time" => date("Y-m-d H:i",$activity["start_time"]), //格式化日期格式 $order["start_time"], //格式化日期格式 + "end_time" => date("Y-m-d H:i",$activity["end_time"]), + "sign_start_time" => date("Y-m-d H:i",$activity["sign_start_time"]), //格式化日期格式 $order["start_time"], //格式化日期格式 + "sign_end_time" => date("Y-m-d H:i",$activity["sign_end_time"]), + "reason" => $activity['reason'], + ]; + + //发给用户 + (new MessageConfig) + ->setTemplate($params["event"]) + ->setTemplateData($param) + ->setToUid($to_id) + ->setMessageStatus($status) + ->setMessageMiniType($mini_type) + ->setMessageParams($params) + ->sendMessage(); + + + //调用取消活动接口 + (new Activity)->cancel($activity["id"],"1",false,$oper_type,$oper_id); + + + } + + + public function newActivityCancelSuccessAfter(&$params) + { + ['activity' => $activity,"oper_type"=>$oper_type,"oper_id"=>$oper_id] = $params; + + + $user = User::where("id",$activity["user_id"])->find(); +//课程推送给老师 + $mini_type = "activity_apply"; + $to_id = $user["id"]; + $status ="activity"; + $params=[ + "event"=>"new_activity_cancel_success_after", + "activity_id"=>$activity["id"], + ]; + + $param = [ + "realname"=> $user["realname"], + "nickname"=> $user["nickname"], + "mobile"=> $user["mobile"], + "title" => $activity['title'], + "address"=>$activity["address"]."(".$activity["address_detail"].")", + "price" => $activity["price"], + "start_time" => date("Y-m-d H:i",$activity["start_time"]), //格式化日期格式 $order["start_time"], //格式化日期格式 + "end_time" => date("Y-m-d H:i",$activity["end_time"]), + "sign_start_time" => date("Y-m-d H:i",$activity["sign_start_time"]), //格式化日期格式 $order["start_time"], //格式化日期格式 + "sign_end_time" => date("Y-m-d H:i",$activity["sign_end_time"]), + "reason" => $activity['reason'], + ]; + + //发给用户 + (new MessageConfig) + ->setTemplate($params["event"]) + ->setTemplateData($param) + ->setToUid($to_id) + ->setMessageStatus($status) + ->setMessageMiniType($mini_type) + ->setMessageParams($params) + ->sendMessage(); + + } + + + + + + + } \ No newline at end of file diff --git a/application/common/model/school/activity/Activity.php b/application/common/model/school/activity/Activity.php index e667f34..fb7b932 100644 --- a/application/common/model/school/activity/Activity.php +++ b/application/common/model/school/activity/Activity.php @@ -6,6 +6,7 @@ namespace app\common\model\school\activity; use app\common\model\BaseModel; use app\common\model\school\activity\order\Order; use app\common\model\school\classes\Collect; +use app\common\model\User; use think\Model; use traits\model\SoftDelete; @@ -97,7 +98,7 @@ class Activity extends BaseModel protected static function init() { self::afterInsert(function ($row) { - if (!$row['weigh']) { + if (empty($row['weigh'])) { $pk = $row->getPk(); $row->getQuery()->where($pk, $row[$pk])->update(['weigh' => $row[$pk]]); } @@ -402,6 +403,14 @@ class Activity extends BaseModel } + //活动开始和结束时间不能跨天 + if(date('Y-m-d',$start_time)!=date('Y-m-d',$end_time)){ + throw new \Exception("{$params["title"]}活动开始和结束时间不能跨天"); + } + + + + $rule = [ 'user_id'=>'require', @@ -428,7 +437,7 @@ class Activity extends BaseModel 'end_time' => 'require', 'sign_start_time' => 'require', 'sign_end_time' => 'require', - 'refund_id' => 'require', +// 'refund_id' => 'require', ]; @@ -463,17 +472,46 @@ class Activity extends BaseModel 'sign_start_time.require' => '报名开始时间必填', 'sign_end_time.require' => '报名结束时间必填', - 'refund_id.require' => '退款策略必填', +// 'refund_id.require' => '退款策略必填', ]; self::check($params,$rule,$rule_msg); - $refund_id = $params["refund_id"]; - $refund = Refund::where("id",$refund_id) ->find(); + if($params["price"]>0){ + if(empty($params["refund_id"])) throw new \Exception("退款策略必填"); + $refund_id = $params["refund_id"]; + $refund = Refund::where("id",$refund_id) ->find(); - if(!$refund){ - throw new \Exception("退款策略不存在"); + if(!$refund){ + throw new \Exception("退款策略不存在"); + } } + if($params["price"]<0)$params["price"]=0; + + + + + $user_id = $params["user_id"]; + $user = User::where("id",$user_id)->find(); + if(!$user){ + throw new \Exception("发布用户不存在"); + } + + + + if($row){ + //修改 + $title = self::where("id","<>",$row["id"])->where("status","not in","-1,5")->where("title",$params["title"])->find(); + if($title) throw new \Exception("活动名不允许重复"); + + }else{ + //新增 + //不在已结束和已取消的活动名title不允许重复 + $title = self::where("status","not in","-1,5")->where("title",$params["title"])->find(); + if($title) throw new \Exception("活动名不允许重复"); + } + + @@ -482,6 +520,15 @@ class Activity extends BaseModel $params["feel"] = '1'; }else{ $params["feel"] = '0'; + //得到当前的微信手续费百分比 + $activity_withdrawal_scale = config("site.activity_withdrawal_scale"); + $activity_withdrawal_scale_100 = bcmul($activity_withdrawal_scale,100,2); + //当前售价对应手续费不得低于0.01 + //计算当前售价手续费 + $fee = bcmul($params["price"],$activity_withdrawal_scale,3); + if($fee<0.01){ + throw new \Exception("当前售价手续费{$fee}按{$activity_withdrawal_scale_100}%低于0.01,请提高售价或设为免费!"); + } } $now_time = time(); @@ -515,8 +562,8 @@ class Activity extends BaseModel //后台新增: 新增审核失败,状态则为已取消 if($params["auth_status"] == 2){ - $params["status"] = '-1'; - $params["cancel_type"] = '1'; +// $params["status"] = '-1'; +// $params["cancel_type"] = '1'; if(!$row){ //新增审核 }else{ @@ -532,7 +579,7 @@ class Activity extends BaseModel $params["admin_id"] = $auth->id; }else{ //前台提交 - $params["auth_status"] = 0; +// $params["auth_status"] = 0; } @@ -552,14 +599,14 @@ class Activity extends BaseModel } } - - if(!isset($params["auth_status"]) &&$row){ //用户端不允许修改 throw new \Exception("{$params["title"]}审核通过的活动只允许手动关闭,不允许修改!"); } - - + if(!isset($params["auth_status"])){ + //前台提交 + $params["auth_status"] = 0; + } } @@ -856,6 +903,9 @@ class Activity extends BaseModel $row['classes_cate'] = $classes_cate; + $row['join_info'] = self::getJoininfo( $row["id"],$row["stock"],10); + + } $result = array("data" => $rows); return $result; @@ -869,7 +919,10 @@ class Activity extends BaseModel * @throws \think\exception\DbException */ public function detail($id,$user_id=0,$oper_type='user',$trans=false){ + //更新课程状态 + $this->updateStatus($id); $self = $this->get($id,['user']); + //只查user的名字 // $self->getRelation('user')->visible(['nickname']); @@ -907,6 +960,7 @@ class Activity extends BaseModel $self['sign_time'] = "{$self["sign_start_time_text"]} - {$self["sign_end_time_text"]}"; $self['time'] = "{$self["start_time_text"]} - {$self["end_time_text"]}"; + $self['join_info'] = self::getJoininfo($id,$self["stock"],10); return $self; } @@ -1033,10 +1087,10 @@ class Activity extends BaseModel if(!$row)throw new \Exception("找不到活动!"); $now_time = time(); - $sign_start_time = strtotime($row["sign_start_time"]); - $sign_end_time = strtotime($row["sign_end_time"]); - $start_time = strtotime($row["start_time"]); - $end_time = strtotime($row["end_time"]); + $sign_start_time = $row["sign_start_time"]; + $sign_end_time = $row["sign_end_time"]; + $start_time = $row["start_time"]; + $end_time = $row["end_time"]; //根据时间区间,设定录入的活动初始状态:1=未开始,2=报名中,3=待开始,4=进行中,5=已结束 //时间在报名开始时间之前为1=未开始 //时间在报名区间之内为2=报名中 @@ -1073,7 +1127,7 @@ class Activity extends BaseModel } throw new \Exception($e->getMessage().$e->getFile().$e->getLine()); } - return $res; + return $row; } @@ -1111,7 +1165,7 @@ class Activity extends BaseModel $this->update_check($params,null); $result = $row->allowField(true)->save($params); $this->update_classes($row["id"]); - + $row->reason = ""; //调用审核事件触发 $data = ['activity' => $row,"user_id"=>$params["user_id"],"oper_type"=>$oper_type,"oper_id"=>$oper_id]; \think\Hook::listen('new_activity_auth_need_after', $data); @@ -1128,4 +1182,123 @@ class Activity extends BaseModel } + + + /** + * 超时检测 + */ + public static function timeoutCheck($trans = false){ + $count = 0; + + //得到所有过期的队列 + $list = self::where("status",'not in',['-1'])->select(); + + if ($trans) { + self::beginTrans(); + } + try { + + + foreach ($list as $activity) + { + //更新课程状态 + (new self)->updateStatus($activity["id"]); + $count++; + } + if ($trans) { + self::commitTrans(); + } + } catch (\Exception $e) { + if ($trans) { + self::rollbackTrans(); + } + throw new \Exception($e->getMessage()); + } + return $count; + } + + + /*** 下单详情 + * @param $id + * @param $limit + * @return void + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\exception\DbException + */ + public static function getJoininfo($id,$stock,$limit=10) + { + $users = []; + //人数 + $people_number = Order::where("activity_id",$id)->where("status","in",[2,3,4,9])->order("id","desc")->sum("num"); + //查询已支付用户列表,取前10 -3=已取消,0=待支付,2=已报名,3=核销中,4=售后中,5=退款结算中,6=已退款,9=已完成 + $user_ids = Order::where("activity_id",$id)->where("status","in",[2,3,4,9])->order("id","desc")->limit($limit)->column("user_id"); + if($user_ids){ + $users = User::where("id","in",$user_ids)->field("id,nickname,avatar")->select(); + } + //百分比:人数$people_number 除以 库存$stock * 100 百分比取整,需判断掉除零异常 + $percent = 0; + try{ + $percent = intval(($people_number/$stock)*100); + }catch (\Exception $e){ + $percent = 0; + } + + return compact("users","people_number","percent","stock"); + } + + /** 取消活动 + * @param $id + * @param $check + * @param $oper_type + * @param $oper_id + * @param $trans + * @return true + * @throws \Exception + */ + public function cancel($id,$cancel_type ="2",$check=false,$oper_type='user',$oper_id=0,$trans=false){ +//判断逻辑 + + + $row = self::where("id",$id)->where("status","in",["1","2","3","4"])->find(); + + if(!$row) throw new \Exception("活动不取消或已结束"); + + if($check) { + if($oper_type=='user' && $row["user_id"] != $oper_id) throw new \Exception("您无权取消该活动"); + + } + + + if($trans){ + self::beginTrans(); + } + $res = true; + try{ + + //更新活动状态 + $row["status"] = "-1"; + $row["cancel_type"] = $cancel_type; + $row["canceltime"] = time(); + $row->save(); + //执行取消事件 + $data = ['activity' => $row,"user_id"=>$row["user_id"],"oper_type"=>$oper_type,"oper_id"=>$oper_id]; + \think\Hook::listen('new_activity_cancel_success_after', $data); + + //自动退款检测:如果有订单,则自动取消 + //...待实现 + + if($trans){ + self::commitTrans(); + } + }catch (\Exception $e){ + if($trans){ + self::rollbackTrans(); + } + throw new \Exception($e->getMessage().$e->getFile().$e->getLine()); + } + return $row; + } + + } diff --git a/application/common/model/school/activity/Cate.php b/application/common/model/school/activity/Cate.php index 141588d..c768bb7 100644 --- a/application/common/model/school/activity/Cate.php +++ b/application/common/model/school/activity/Cate.php @@ -29,7 +29,14 @@ class Cate extends BaseModel 'status_text', 'hot_text' ]; - + + + public function getImageAttr($value, $data) + { + if (!empty($value)) return cdnurl($value, true); + } + + protected static function init() { diff --git a/application/common/model/school/activity/order/OrderLog.php b/application/common/model/school/activity/order/OrderLog.php new file mode 100644 index 0000000..c0ccb4b --- /dev/null +++ b/application/common/model/school/activity/order/OrderLog.php @@ -0,0 +1,123 @@ + __('Status -3'), '0' => __('Status 0'), '2' => __('Status 2'), '3' => __('Status 3'), '4' => __('Status 4'), '5' => __('Status 5'), '6' => __('Status 6'), '9' => __('Status 9')]; + } + + + public function getStatusTextAttr($value, $data) + { + $value = $value ? $value : (isset($data['status']) ? $data['status'] : ''); + $list = $this->getStatusList(); + return isset($list[$value]) ? $list[$value] : ''; + } + + + + + public function order() + { + return $this->belongsTo(Order::class, 'activity_order_id', 'id', [], 'LEFT')->setEagerlyType(0); + } + + + public function user() + { + return $this->belongsTo('app\common\model\User', 'oper_id', 'id', [], 'LEFT')->setEagerlyType(0); + } + + + + + + /**记录订单日志 + * @param $params + * @param bool $trans + * @throws \Exception + */ + public static function log($order,$mark='更新订单状态',$oper_type='user',$oper_id = 0,$trans=false){ + if(is_numeric($order)||is_string($order))$order = Order::where('order_no|id|pay_no',$order)->find(); + if(!$order)throw new \Exception("找不到订单"); + //操作人信息(可扩展) + $data = [ + 'oper_type'=>$oper_type ?: 'user', + 'oper_id'=>$oper_id ?: $order['user_id'], + 'remark'=>$mark, + ]; + //判断逻辑 + if($trans){ + self::beginTrans(); + } + $res = true; + try{ + //事务逻辑 + $log_data = $order->toArray(); + $log_data["activity_order_id"] = $order['id']; + unset($log_data['id']); + unset($log_data['createtime']); + if($mark)$log_data['log_text'] = $mark; + + $log_data = array_merge($log_data,$data); + + $log = (new self); + $log->allowField(true)->save($log_data); + if($trans){ + self::commitTrans(); + } + }catch (\Exception $e){ + if($trans){ + self::rollbackTrans(); + } + throw new \Exception($e->getMessage()); + } + return $log; + } + + + + public static function allList($page, $limit,$params=[]){ + $with_field = [ + 'order'=>['order_no',"pay_no","activity_id","activity_order_detail_id","user_id"], + 'base'=>['*'], + ]; + + $alisa = (new self)->getWithAlisaName(); + $sort = "{$alisa}.id desc"; + $serch_where = $params; +// if($type)$serch_where['type'] = $type; + return (new self)->getBaseList($serch_where, $page, $limit,$sort,$with_field); + } +} diff --git a/public/assets/js/backend/school/activity/activity.js b/public/assets/js/backend/school/activity/activity.js index 6629e1c..f44414d 100644 --- a/public/assets/js/backend/school/activity/activity.js +++ b/public/assets/js/backend/school/activity/activity.js @@ -9,6 +9,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin add_url: 'school/activity/activity/add'+ location.search, edit_url: 'school/activity/activity/edit'+ location.search, del_url: 'school/activity/activity/del', + cancel_url: 'school/activity/activity/cancel', multi_url: 'school/activity/activity/multi', import_url: 'school/activity/activity/import', table: 'school_activity', @@ -31,6 +32,9 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin {field: 'user_id', title: __('User_id')}, {field: 'title', title: __('Title'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content}, {field: 'images', title: __('Images'), operate: false, events: Table.api.events.image, formatter: Table.api.formatter.images}, + {field: 'status', title: __('Status'), searchList: {"1":__('Status 1'),"2":__('Status 2'),"3":__('Status 3'),"4":__('Status 4'),"5":__('Status 5'),"-1":__('Status -1')}, formatter: Table.api.formatter.status}, + {field: 'auth_status', title: __('Auth_status'), searchList: {"0":__('Auth_status 0'),"1":__('Auth_status 1'),"2":__('Auth_status 2')}, formatter: Table.api.formatter.status}, + {field: 'reason', title: __('Reason'), operate: 'LIKE'}, // {field: 'address_city', title: __('Address_city'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content}, // {field: 'cate_ids', title: __('Cate_ids'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content}, @@ -48,7 +52,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin {field: 'sign_end_time', title: __('Sign_end_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime}, {field: 'price', title: __('Price'), operate:'BETWEEN'}, {field: 'stock', title: __('Stock')}, - {field: 'status', title: __('Status'), searchList: {"1":__('Status 1'),"2":__('Status 2'),"3":__('Status 3'),"4":__('Status 4'),"5":__('Status 5'),"-1":__('Status -1')}, formatter: Table.api.formatter.status}, + {field: 'cancel_type', title: __('Cancel_type'), searchList: {"1":__('Cancel_type 1'),"2":__('Cancel_type 2')}, formatter: Table.api.formatter.normal}, {field: 'weigh', title: __('Weigh'), operate: false}, {field: 'recommend', title: __('Recommend'), searchList: {"0":__('Recommend 0'),"1":__('Recommend 1')}, formatter: Table.api.formatter.normal}, @@ -64,8 +68,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin {field: 'collect', title: __('Collect')}, {field: 'createtime', title: __('Createtime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime}, {field: 'updatetime', title: __('Updatetime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime}, - {field: 'auth_status', title: __('Auth_status'), searchList: {"0":__('Auth_status 0'),"1":__('Auth_status 1'),"2":__('Auth_status 2')}, formatter: Table.api.formatter.status}, - {field: 'reason', title: __('Reason'), operate: 'LIKE'}, + {field: 'admin_id', title: __('Admin_id')}, {field: 'auth_time', title: __('Auth_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime}, {field: 'canceltime', title: __('Canceltime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime}, @@ -75,7 +78,38 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin {field: 'user.avatar', title: __('User.avatar'), operate: 'LIKE', events: Table.api.events.image, formatter: Table.api.formatter.image}, {field: 'admin.nickname', title: __('Admin.nickname'), operate: 'LIKE'}, {field: 'admin.avatar', title: __('Admin.avatar'), operate: 'LIKE', events: Table.api.events.image, formatter: Table.api.formatter.image}, - {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} + // {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} + + {field: 'operate', title: __('Operate'), table: table , buttons: [ + + {name: 'cancel', + text: '取消活动', + icon: 'fa fa-user-times', + classname: 'btn btn-xs btn-warning btn-magic btn-ajax', + url: $.fn.bootstrapTable.defaults.extend.cancel_url, + confirm: '确认取消活动', + success: function (data, ret) { + Layer.alert(ret.msg ); + $(".btn-refresh").trigger("click"); + }, + error: function (data, ret) { + Layer.alert(ret.msg); + return false; + }, + visible: function (row) { + //非免费订单只有未支付可取消 + if(row.status == '1' || row.status == '2' || row.status == '3' || row.status == '4' ){ + return true; + } + + return false; + }}, + + ], events: Table.api.events.operate, formatter: Table.api.formatter.operate}, + + + + ] ] }); diff --git a/public/assets/js/backend/school/activity/cate.js b/public/assets/js/backend/school/activity/cate.js index 6985b7e..cc42ddb 100644 --- a/public/assets/js/backend/school/activity/cate.js +++ b/public/assets/js/backend/school/activity/cate.js @@ -26,6 +26,8 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin [ {checkbox: true}, {field: 'id', title: __('Id')}, + {field: 'image', title: __('Image'), operate: false, events: Table.api.events.image, formatter: Table.api.formatter.image}, + {field: 'name', title: __('Name'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content}, {field: 'status', title: __('Status'), searchList: {"1":__('Status 1'),"2":__('Status 2')}, formatter: Table.api.formatter.status}, {field: 'hot', title: __('Hot'), searchList: {"0":__('Hot 0'),"1":__('Hot 1')}, formatter: Table.api.formatter.normal}, diff --git a/public/assets/js/backend/school/activity/order/order_log.js b/public/assets/js/backend/school/activity/order/order_log.js new file mode 100644 index 0000000..5eb8392 --- /dev/null +++ b/public/assets/js/backend/school/activity/order/order_log.js @@ -0,0 +1,120 @@ +define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) { + + var Controller = { + index: function () { + // 初始化表格参数配置 + Table.api.init({ + extend: { + index_url: 'school/activity/order/order_log/index' + location.search, + add_url: 'school/activity/order/order_log/add', + edit_url: 'school/activity/order/order_log/edit', + del_url: 'school/activity/order/order_log/del', + multi_url: 'school/activity/order/order_log/multi', + import_url: 'school/activity/order/order_log/import', + table: 'school_activity_order_log', + } + }); + + var table = $("#table"); + + // 初始化表格 + table.bootstrapTable({ + url: $.fn.bootstrapTable.defaults.extend.index_url, + pk: 'id', + sortName: 'id', + columns: [ + [ + {checkbox: true}, + {field: 'id', title: __('Id')}, + {field: 'activity_order_id', title: __('Activity_order_id')}, + {field: 'status', title: __('Status'), searchList: {"-3":__('Status -3'),"0":__('Status 0'),"2":__('Status 2'),"3":__('Status 3'),"4":__('Status 4'),"5":__('Status 5'),"6":__('Status 6'),"9":__('Status 9')}, formatter: Table.api.formatter.status}, + {field: 'log_text', title: __('Log_text'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content}, + {field: 'oper_type', title: __('Oper_type'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content}, + {field: 'oper_id', title: __('Oper_id')}, + {field: 'createtime', title: __('Createtime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime}, + {field: 'updatetime', title: __('Updatetime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime}, + {field: 'order.order_no', title: __('Order.order_no'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content}, + {field: 'user.nickname', title: __('User.nickname'), operate: 'LIKE'}, + {field: 'user.avatar', title: __('User.avatar'), operate: 'LIKE', events: Table.api.events.image, formatter: Table.api.formatter.image}, + {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} + ] + ] + }); + + // 为表格绑定事件 + Table.api.bindevent(table); + }, + recyclebin: function () { + // 初始化表格参数配置 + Table.api.init({ + extend: { + 'dragsort_url': '' + } + }); + + var table = $("#table"); + + // 初始化表格 + table.bootstrapTable({ + url: 'school/activity/order/order_log/recyclebin' + location.search, + pk: 'id', + sortName: 'id', + columns: [ + [ + {checkbox: true}, + {field: 'id', title: __('Id')}, + { + field: 'deletetime', + title: __('Deletetime'), + operate: 'RANGE', + addclass: 'datetimerange', + formatter: Table.api.formatter.datetime + }, + { + field: 'operate', + width: '140px', + title: __('Operate'), + table: table, + events: Table.api.events.operate, + buttons: [ + { + name: 'Restore', + text: __('Restore'), + classname: 'btn btn-xs btn-info btn-ajax btn-restoreit', + icon: 'fa fa-rotate-left', + url: 'school/activity/order/order_log/restore', + refresh: true + }, + { + name: 'Destroy', + text: __('Destroy'), + classname: 'btn btn-xs btn-danger btn-ajax btn-destroyit', + icon: 'fa fa-times', + url: 'school/activity/order/order_log/destroy', + refresh: true + } + ], + formatter: Table.api.formatter.operate + } + ] + ] + }); + + // 为表格绑定事件 + Table.api.bindevent(table); + }, + + add: function () { + Controller.api.bindevent(); + }, + edit: function () { + Controller.api.bindevent(); + }, + api: { + bindevent: function () { + Form.api.bindevent($("form[role=form]")); + } + } + }; + return Controller; +}); diff --git a/public/assets/js/backend/school/activity/refund.js b/public/assets/js/backend/school/activity/refund.js index e13959d..2de48f7 100644 --- a/public/assets/js/backend/school/activity/refund.js +++ b/public/assets/js/backend/school/activity/refund.js @@ -29,7 +29,6 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin {field: 'title', title: __('Title'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content}, {field: 'desc', title: __('Desc'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content}, {field: 'refund_hour', title: __('Refund_hour')}, - {field: 'refund_scale', title: __('Refund_scale'), operate:'BETWEEN'}, {field: 'weigh', title: __('Weigh'), operate: false}, {field: 'createtime', title: __('Createtime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime}, {field: 'updatetime', title: __('Updatetime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},