Browse Source

签到功能

jun 6 tháng trước cách đây
mục cha
commit
fa0f2a9087

+ 230 - 0
app/Http/Controllers/Admin/CustomClockinRecord.php

@@ -0,0 +1,230 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\Custom as Request;
+use App\Models\City;
+use App\Models\Custom as Custom;
+use Illuminate\Support\Carbon;
+use App\Models\WeiBan\Follow as WeiBanFollow;
+use App\Models\FilesManager;
+use App\Models\WeiBan\External as WeiBanExternal;
+use App\Models\CustomClockinRecord as Model;
+
+/**
+ * 客户签到记录
+ *
+ * @author    jun
+ *
+ */
+class CustomClockinRecord extends Auth{
+
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','积分管理');
+		$this->assign('breadcrumb2','打卡记录');
+	}
+
+	/**
+	 * 列表页
+	 * 
+	 * */
+    public function index(Model $Model,Custom $Custom,CustomScore $CustomScore,WeiBanFollow $WeiBanFollow,City $City){
+ 		// 接受参数
+		$code					= request('custom_code','');
+		$phone					= request('phone','');
+		$username				= request('username','');
+		$weibanId				= request('weiban_extid','');
+		$cityId					= request('city_id',0);
+		$status					= request('status');
+		$startTime				= request('start_time','');
+		// 编码转ID
+		$uid					= $Custom->codeToId($code);
+		// 查询条件
+		$map 					= [];
+		// 编码ID
+		if( $uid )				$map[] = ['custom.uid','=',$uid];
+		if( $phone )			$map[] = ['custom.phone','=',$phone];
+		if( $username )			$map[] = ['custom.username','=',$username];
+		if( $cityId )			$map[] = ['custom.city_id','=',$cityId];
+		if( $weibanId )			$map[] = ['custom.weiban_extid','=',$weibanId];
+		if( $startTime )		$map[] = ['custom_clockin_record.insert_time','>=',Carbon::createFromFormat('Y-m-d',$startTime)->startOfDay()->getTimestamp()];
+		if( $startTime )		$map[] = ['custom_clockin_record.nsert_time','<=',Carbon::createFromFormat('Y-m-d',$startTime)->endOfDay()->getTimestamp()];
+		if( !is_null($status) )	$map[] = ['custom_clockin_record.status','=',$status];
+		// 查询数据
+		$list					= $Model->query()
+            ->leftJoin('custom','custom.uid','=','custom_clockin_record.custom_uid')
+            ->leftJoin('score_clockin_active','score_clockin_active.id','=','custom_clockin_record.active_id')
+            ->where($map)
+            ->select(['custom.*','score_clockin_active.name as active_name','custom_clockin_record.*'])
+            ->orderByDesc('custom_clockin_record.id')
+            ->paginate(config('page_num',10))
+            ->appends(request()->all());
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// 城市名
+			$value['city_name'] 	= $value['city_id'] ? $City->getOne($value['city_id'],'name') : '';
+			// id转编号
+			$value['custom_code'] 	= $Custom->idToCode($value['uid']);
+            // 如果不存在微伴ID
+            if( !$value['weiban_extid'] )	{
+                // 通过手机号查询注册的账号
+                $value['weiban_extid'] 	= (string) $WeiBanFollow->query()->where([['phone_number','=',$value['phone']]])->value('weiban_extid');
+                // 如果存在的话,修正
+                if( $value['weiban_extid'] ) $Model->edit($value['uid'],['weiban_extid'=>$value['weiban_extid']]);
+            }
+			// 重组
+			$list[$key]				= $value;
+		}
+		// 获取列表
+		$cityList					= $City->getCityList();
+		// 分配数据
+		$this->assign('cityList',$cityList);
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list',$list);
+		// 加载模板
+		return 						$this->fetch();
+    }
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add(Request $request,Model $Model){
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 接收数据
+			// 接收数据
+			$data['username']		= request('username','');
+			$data['phone']			= request('phone','');
+			// 写入数据表
+			$uid					= $Model->add($data);
+			// 如果操作失败
+			if( !$uid ) 			return json_send(['code'=>'error','msg'=>'新增失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$uid,1,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+		}
+		// 分配数据
+		$this->assign('crumbs','新增');
+		// 加载模板
+		return						$this->fetch(); 
+	}
+
+	/**
+	 * 修改
+	 * 
+	 * */
+	public function edit(Request $request,Model $Model,City $City){
+		// 接收参数
+		$uid						= request('uid',0);
+		// 查询用户
+		$oldData					= $Model->where(['uid'=>$uid])->first();
+		// 修改
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('edit')->validate();
+			// 如果用户不存在
+			if( !$oldData )			return json_send(['code'=>'error','msg'=>'用户不存在']);
+			// 转数组
+			$oldData				= $oldData->toArray();
+			// 接收数据
+			$data['username']		= request('username','');
+			$data['phone']			= request('phone','');
+			$data['city_id']		= request('city_id',0);
+			$data['weiban_extid']	= request('weiban_extid','');
+			// 写入数据表
+			$result					= $Model->edit($uid,$data);
+			// 如果操作失败
+			if( !$result ) 			return json_send(['code'=>'error','msg'=>'新增失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$uid,2,$oldData,$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);
+		}
+		// 错误告知
+		if( !$oldData )				return $this->error('查无数据');
+		// 获取列表
+		$cityList					= $City->getCityList();
+		// 分配数据
+		$this->assign('cityList',$cityList);
+		$this->assign('oldData',$oldData);
+		$this->assign('crumbs','修改');
+		// 加载模板
+		return						$this->fetch();
+	}
+
+	/**
+	 * 修改状态
+	 * 
+	 * */
+	public function set_status(Request $request,Model $Model){
+		// 验证参数
+		$request->scene('set_status')->validate();
+		// 设置状态
+		$uid				= request('uid',0);
+		$status				= request('status',0);
+		// 查询用户
+		$oldData			= $Model->where(['uid'=>$uid])->first();
+		// 如果用户不存在
+		if( !$oldData )		return json_send(['code'=>'error','msg'=>'用户不存在']);
+		// 执行修改
+		$result				= $Model->edit($uid,['status'=>$status]);		
+		// 提示新增失败
+		if( !$result )		return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 记录行为
+		$this->addAdminHistory(admin('uid'),$Model->getTable(),$uid,2,$oldData,['status'=>$status]);
+		// 告知结果
+		return 				json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+	/**
+	 * 表格导入
+	 * 
+	 * */
+	public function import_execl( Request $request,Model $Model,FilesManager $FilesManager,City $City,CustomAddr $CustomAddr,WeiBanExternal $WeiBanExternal){
+		// 验证参数
+		$request->scene('import_execl')->validate();
+		// 获取表格信息
+		$file								= request()->file('custom_file');
+		// 返回结果
+		$sheetList							= $FilesManager->excelToCustom($file);
+		// 如果不存在结果
+		if( isset($sheetList['error']) )	return json_send(['code'=>'error','msg'=>$sheetList['error']]);
+		// 循环表格数据
+		foreach ($sheetList as $value) 		{
+			// 获取城市ID
+			$value['city_id']				= 0;
+			// 存在城市名称,查询城市ID
+			if( $value['contact_city'] )	{
+				// 获取城市ID
+				$value['city_id']			= (int) $City->getIdByName($value['contact_city']);
+				// 如果城市不存在的话
+				if ( !$value['city_id'] )	return json_send(['code'=>'error','msg'=>$value['contact_city'].' => 未找到匹配的城市,请核对城市全称']);
+			}
+			// 获取手机号,查询是否用客户
+			$custom							= $Model->getOneByPhone($value['phone']);
+			// 组装数据
+			$data							= ['weiban_extid'=>$value['weiban_extid'],'username'=>$value['username']];
+			// 如果客户不存在
+			if( !$custom )					$data['phone'] = $value['phone'];
+			// 如果存在城市ID,才修改城市
+			if( $value['city_id'] )			$data['city_id'] = $value['city_id'];
+			// 如果存在手机号
+			$uid							= $custom ? $Model->edit($custom['uid'],$data) : $Model->add($data);
+			// 如果客户存在
+			if( !$uid )						return json_send(['code'=>'error','msg'=>$value['username'].'【'.$value['phone'].'】'.'用户创建或者更新失败']);
+			// 存在详细地址,才创建地址库
+			if( $value['contact_name'] && $value['contact_phone'] && $value['contact_province'] && $value['contact_city'] && $value['contact_area'] && $value['contact_addr'] )	{
+				// 收件地址是否存在
+				$oldAddr					= $CustomAddr->query()->where([['custom_uid','=',$uid]])->first();
+				// 如果不存在地址
+				if( !$oldAddr )				$CustomAddr->add(['custom_uid'=>$uid,'contact_name'=>$value['contact_name'],'contact_shop'=>$value['contact_shop'],'contact_phone'=>$value['contact_phone'],'contact_province'=>$value['contact_province'],'contact_city'=>$value['contact_city'],'contact_area'=>$value['contact_area'],'contact_addr'=>$value['contact_addr']]);
+			}
+		}
+		// 提示成功
+		return								json_send(['code'=>'success','msg'=>'批量导入成功','path'=>'']);
+	}
+
+}

+ 27 - 4
app/Http/Controllers/Admin/ScoreClockin.php

@@ -2,6 +2,7 @@
 
 use App\Http\Requests\Admin\ScoreClockin as Request;
 use App\Models\Score\Clockin as Model;
+use App\Models\Coupon as Coupon;
 
 
 
@@ -23,14 +24,25 @@ class ScoreClockin extends Auth{
 	 * 首页列表
 	 * 
 	 * */
-    public function index(Model $Model){
+    public function index(Model $Model, Coupon $Coupon){
+        $activeId					= request('active_id',0);
 		// 组合查询条件
 		$map			= [];
+        if( $activeId )				$map[] = ['active_id','=',$activeId];
 		// 查询数据
 		$list			= $Model->where($map)->orderBy('what_day')->orderBy('id')->paginate(request('limit',config('page_num',10)))->appends(request()->all());
-		// 分配数据
+		foreach ($list as $k=>$v){
+            if ($v['coupon_id']) {
+                $v['coupon_code']   = $Coupon->idToCode($v['coupon_id']);
+                $coupon             = $Coupon->getOne($v['coupon_id']);
+                if ($coupon)    $v['coupon_name']   = $coupon['name'];
+            }
+            $list[$k] = $v;
+        }
+        // 分配数据
 		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
 		$this->assign('list', $list);
+		$this->assign('active_id', $activeId);
 		// 加载模板
 		return $this->fetch();   
     }
@@ -39,13 +51,18 @@ class ScoreClockin extends Auth{
 	 * 添加
 	 * 
 	 * */
-	public function add( Request $request,Model $Model ){
+	public function add( Request $request,Model $Model,Coupon $Coupon){
 		if( request()->isMethod('post') ){
 			// 验证参数
 			$request->scene('add')->validate();
 			// 组合数据
 			$data['what_day']		= (int) request('what_day',0);
 			$data['reward']			= (int) request('reward',0);
+            $data['active_id']		= request('active_id',0);
+            $data['status']		    = 0;
+            $coupon_code	        = request('coupon_code',0);
+            if ($coupon_code)
+                $data['coupon_id']  = $Coupon->codeToId($coupon_code);
 			// 写入用户表
 			$result					= $Model->add($data);
 			// 提示新增失败
@@ -63,7 +80,7 @@ class ScoreClockin extends Auth{
 	 * 编辑
 	 * 
 	 * */
-	public function edit( Request $request,Model $Model ){
+	public function edit( Request $request,Model $Model,Coupon $Coupon){
 		// 接收参数
 		$id							= request('id',0);
 		// 如果是post
@@ -72,6 +89,9 @@ class ScoreClockin extends Auth{
 			$request->scene('edit')->validate();
 			$data['what_day']		= (int) request('what_day',0);
 			$data['reward']			= (int) request('reward',0);
+            $coupon_code	        = request('coupon_code',0);
+            if ($coupon_code)
+                $data['coupon_id']  = $Coupon->codeToId($coupon_code);
 			// 写入用户表
 			$result					= $Model->edit($id,$data);
 			// 提示新增失败
@@ -81,6 +101,9 @@ class ScoreClockin extends Auth{
 		}
 		// 查询数据
 		$oldData					= $Model->where(['id'=>$id])->first();
+        if ($oldData['coupon_id']) {
+            $oldData['coupon_code'] = $Coupon->idToCode($oldData['coupon_id']);
+        }
 		// 如果是没有数据
 		if( !$oldData )				return $this->error('查无数据');
 		// 分配数据

+ 214 - 0
app/Http/Controllers/Admin/ScoreClockinActive.php

@@ -0,0 +1,214 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Facades\Servers\WechatMini\Mini;
+use App\Http\Requests\Admin\ScoreClockinActive as Request;
+use App\Models\City;
+use App\Models\Coupon\ActiveCoupon as ActiveCoupon;
+use App\Models\Score\ClockinActive as Model;
+use App\Models\WeiBan\Tags as WeiBanTags;
+
+
+/**
+ * 打卡活动
+ *
+ * @author    jun
+ * 
+ */
+class ScoreClockinActive extends Auth{
+
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','任务打卡');
+		$this->assign('breadcrumb2','打卡任务');
+	}
+
+    /**
+     * 列表页
+     *
+     * */
+    public function index(Request $request, Model $Model, City $City){
+        // 接收参数
+        $name					= request('name','');
+        // 查询条件
+        $map 					= [];
+        // 组合条件
+        if( $name )				$map[] = ['name','=',$name];
+        // 查询数据
+        $list					= $Model->query()->where($map)->orderByDesc('id')->paginate(config('page_num',10));
+        // 循环处理数据
+        foreach ($list as $key => $value) {
+            // 小程序链接
+            $value['mp_urllink']= $this->getUrlLink($value['id']);
+            if( $value['city_ids'] ) {
+                // 解析数组
+                $cityids			= explode(',',$value['city_ids']);
+                // 获取城市
+                foreach ($cityids as $kk=>$vv) 	{
+                    // 获取值
+                    $vv				= $City->getOne($vv,'name');
+                    // 获取城市名
+                    $cityids[$kk]	= $vv;
+                }
+                // 城市列表
+                $value['city_ids']	= implode('、',$cityids);
+            }
+            // 重组
+            $list[$key]			= $value;
+        }
+        // 分配数据
+        $this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+        $this->assign('list',$list);
+        // 加载模板
+        return 					$this->fetch();
+    }
+
+    /**
+     * 获取小程序链接
+     *
+     */
+    private function getUrlLink($id){
+        // 结果数据
+        $link                  = cache('admin:clockin:active:urllink:'.$id);
+        // 不存在数据
+        if ( is_null($link) ) {
+            // 从数据库获取数据
+            $link              = Mini::getUrlLink('pages/clockin/active','?id='.$id);
+            // 存起来
+            cache(['admin:clockin:active:urllink:'.$id=>$link],$link ? now()->addDays(28) : now()->addMinutes(3));
+        }
+        // 返回结果
+        return                  $link;
+
+    }
+
+    /**
+     * 添加
+     *
+     * */
+    public function add(\App\Http\Requests\Admin\Coupon\Active $request, Model $Model, City $City, WeiBanTags $WeiBanTags){
+        if( request()->isMethod('post') ){
+            // 验证参数
+            $request->scene('add')->validate();
+            // 接收数据
+            $data['banner_img']		= request('banner_img','');
+            $data['name']			= request('name','');
+            $data['active_rule']	= request('active_rule','');
+            $data['start_time']		= request('start_time','');
+            $data['end_time']		= request('end_time','');
+            $data['start_time']		= $data['start_time'] ? strtotime($data['start_time']) : 0;
+            $data['end_time']		= $data['end_time'] ? strtotime($data['end_time']) : 0;
+            $cityIds				= request('city_ids',[]);
+            $tagScope				= request('tag_scope',[]);
+            $data['city_ids']		= implode(',',$cityIds);
+            $data['tag_scope']		= implode(',',$tagScope);
+            $data['status']			= 1;
+            // 写入数据表
+            $id						= $Model->add($data);
+            // 如果操作失败
+            if( !$id ) 				return json_send(['code'=>'error','msg'=>'新增失败']);
+            // 记录行为
+            $this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
+            // 告知结果
+            return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+        }
+        // 获取列表
+        $cityList					= $City->getCityList();
+        // 标签列表
+        $tagData					= $WeiBanTags->query()->groupBy('group')->groupBy('name')->get(['group','name'])->toArray();
+        // 标签列表
+        $tagList					= [];
+        // 循环数据
+        foreach ($tagData as $value) {
+            $tagList[$value['group']][] = $value['name'];
+        }
+        // 分配数据
+        $this->assign('cityList',$cityList);
+        $this->assign('tagList',$tagList);
+        $this->assign('crumbs','新增');
+        // 加载模板
+        return						$this->fetch();
+    }
+
+    /**
+     * 修改
+     *
+     * */
+    public function edit(Request $request,Model $Model,City $City,WeiBanTags $WeiBanTags){
+        // 接收参数
+        $id							= request('id',0);
+        // 查询用户
+        $oldData					= $Model->where(['id'=>$id])->first();
+        // 修改
+        if(request()->isMethod('post')){
+            // 验证参数
+            $request->scene('edit')->validate();
+            // 接收数据
+            $data['banner_img']		= request('banner_img','');
+            $data['name']			= request('name','');
+            $data['active_rule']	= request('active_rule','');
+            $data['start_time']		= request('start_time','');
+            $data['end_time']		= request('end_time','');
+            $data['start_time']		= $data['start_time'] ? strtotime($data['start_time']) : 0;
+            $data['end_time']		= $data['end_time'] ? strtotime($data['end_time']) : 0;
+            $cityIds				= request('city_ids',[]);
+            $tagScope				= request('tag_scope',[]);
+            $data['city_ids']		= implode(',',$cityIds);
+            $data['tag_scope']		= implode(',',$tagScope);
+            // 写入数据表
+            $result					= $Model->edit($id,$data);
+            // 如果操作失败
+            if( !$result ) 			return json_send(['code'=>'error','msg'=>'修改失败']);
+            // 记录行为
+            $this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,$oldData,$data);
+            // 告知结果
+            return					json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);
+        }
+        // 错误告知
+        if( !$oldData )				return $this->error('查无数据');
+        // 获取城市ID
+        $oldData['city_ids']		= explode(',',$oldData['city_ids']);
+        $oldData['tag_scope']		= explode(',',$oldData['tag_scope']);
+        // 获取列表
+        $cityList					= $City->getCityList();
+        // 标签列表
+        $tagData					= $WeiBanTags->query()->groupBy('group')->groupBy('name')->get(['group','name'])->toArray();
+        // 标签列表
+        $tagList					= [];
+        // 循环数据
+        foreach ($tagData as $value) {
+            $tagList[$value['group']][] = $value['name'];
+        }
+        // 分配数据
+        $this->assign('cityList',$cityList);
+        $this->assign('tagList',$tagList);
+        $this->assign('oldData',$oldData);
+        $this->assign('crumbs','修改');
+        // 加载模板
+        return						$this->fetch();
+    }
+
+    /**
+     * 修改状态
+     *
+     * */
+    public function set_status(Request $request,Model $Model,ActiveCoupon $ActiveCoupon){
+        // 验证参数
+        $request->scene('set_status')->validate();
+        // 设置状态
+        $id				= request('id',0);
+        $status			= request('status',0);
+        // 查询用户
+        $oldData		= $Model->where(['id'=>$id])->first();
+        // 如果用户不存在
+        if( !$oldData )	return json_send(['code'=>'error','msg'=>'数据不存在']);
+        // 执行修改
+        $result			= $Model->edit($id,['status'=>$status]);
+        // 提示新增失败
+        if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+        // 记录行为
+        $this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,$oldData,['status'=>$status]);
+        // 告知结果
+        return 			json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+    }
+
+}

+ 95 - 6
app/Http/Controllers/Api/Score/Clockin.php

@@ -1,7 +1,12 @@
 <?php namespace App\Http\Controllers\Api\Score;
 
 use App\Http\Controllers\Api\Api;
+use App\Models\Custom as Custom;
 use App\Models\Score\Clockin as Model;
+use App\Models\Score\ClockinActive as ClockinActive;
+use App\Models\WeiBan\Tags as WeiBanTags;
+use App\Models\CustomClockinRecord;
+use Illuminate\Support\Carbon;
 
 /**
  * 任务-打卡
@@ -15,7 +20,7 @@ class Clockin extends Api
      * 列表                     /api/score_clockin/get_list
      * 
      */
-    public function get_list(Model $Model)
+    /*public function get_list(Model $Model)
     {
         // 接口验签
 		// $this->verify_sign();
@@ -36,20 +41,104 @@ class Clockin extends Api
         $list                       = array_values($list);
         // 返回结果
         return                      json_send(['code'=>'success','msg'=>'获取成功','data'=>['list'=>$list,'is_mark'=>$isMark]]);
-    }
+    }*/
+    public function get_list(Model $Model, Custom $Custom, ClockinActive $ClockinActive, WeiBanTags  $WeiBanTags, CustomClockinRecord $CustomClockinRecord)
+    {
+        // 接口验签
+        // $this->verify_sign();
+        // 验证登录
+        $uid						= $this->getUid();
+        // 获取客户信息
+        $custom						= $uid ? $Custom->getOne($uid) : [];
+        //客户的城市ID 如果不存在的话
+        if( !$custom['city_id'] )	return json_send(['code'=>'error','msg'=>'请选择所在城市','data'=>['error'=>'请选择所在城市']]);
+        $cityId						= $custom['city_id'];
+        // 查询用户标签
+        $tags						= $WeiBanTags->getListByWeibanExtid($custom['weiban_extid']);
+        //获取打卡活动列表
+        $activeList					= $ClockinActive->getList();
+        if (!$activeList)           return json_send(['code'=>'error','msg'=>'暂无签到活动','data'=>['error'=>'暂无签到活动']]);
+        $activeInfo = [];
+        foreach ($activeList as $value){
+            $city_ids			= $value['city_ids'] ? explode(',',$value['city_ids']) : [];
+            $tag_scope			= $value['tag_scope'] ? explode(',',$value['tag_scope']) : [];
+            if( !$city_ids || in_array($cityId,$city_ids) ) {
+                if ($tag_scope){
+                    foreach ($tags as $tag) 	{
+                        // 标签范围内
+                        if( in_array($tag['name'],$tag_scope) ) {
+                            $activeInfo = $value;
+                            break;
+                        }
+                    }
+                }else{
+                    $activeInfo = $value;
+                    break;
+                }
+            }
 
+        }
+        if (!$activeInfo) return json_send(['code'=>'error','msg'=>'暂无签到活动','data'=>['error'=>'暂无签到活动']]);
+        // 获取列表
+        $list               = $Model->getActiveList($activeInfo['id']);
+        $isMark             = $CustomClockinRecord->isMarkClock($uid);
+        $isMark['finish_day']       = empty($isMark['finish_day'])?0:$isMark['finish_day'];
+        // 循环处理
+        foreach ( $list as $key => $value ) {
+            // 是否已打卡,打卡天数内(含)为已打卡
+            $value['is_finish']     = $isMark['finish_day'] >= $value['what_day'] ? 1 : 0;
+            // 重新赋值
+            $list[$key]             = $value;
+        }
+        // 去除主键
+        $list                       = array_values($list);
+        $list                       = array_chunk($list,28);
+        // 返回结果
+        return                      json_send(['code'=>'success','msg'=>'获取成功','data'=>['list'=>$list,'is_mark'=>$isMark]]);
+    }
     /**
      * 打卡                         /api/score_clockin/finish
      * 
      */
-    public function finish(Model $Model)
+    public function finish(Model $Model,Custom $Custom,WeiBanTags $WeiBanTags,ClockinActive $ClockinActive,CustomClockinRecord $CustomClockinRecord)
     {
         // 接口验签
 		// $this->verify_sign();
-		// 验证登录
-		$uid						    = $this->checkLogin();
+        // 验证登录
+        $uid						= $this->getUid();
+        // 获取客户信息
+        $custom						= $uid ? $Custom->getOne($uid) : [];
+        //客户的城市ID 如果不存在的话
+        if( !$custom['city_id'] )	return json_send(['code'=>'error','msg'=>'请选择所在城市','data'=>['error'=>'请选择所在城市']]);
+        $cityId						= $custom['city_id'];
+        // 查询用户标签
+        $tags							= $WeiBanTags->getListByWeibanExtid($custom['weiban_extid']);
+        //获取打卡活动列表
+        $activeList					= $ClockinActive->getList();
+        if (!$activeList)           return json_send(['code'=>'error','msg'=>'暂无签到活动','data'=>['error'=>'暂无签到活动']]);
+        $activeInfo = [];
+        foreach ($activeList as $value){
+            $city_ids			= $value['city_ids'] ? explode(',',$value['city_ids']) : [];
+            $tag_scope			= $value['tag_scope'] ? explode(',',$value['tag_scope']) : [];
+            if( !$city_ids || in_array($cityId,$city_ids) ) {
+                if ($tag_scope){
+                    foreach ($tags as $tag) 	{
+                        // 标签范围内
+                        if( in_array($tag['name'],$tag_scope) ) {
+                            $activeInfo = $value;
+                            break;
+                        }
+                    }
+                }else{
+                    $activeInfo = $value;
+                    break;
+                }
+            }
+
+        }
+        if (!$activeInfo) return json_send(['code'=>'error','msg'=>'暂无签到活动','data'=>['error'=>'暂无签到活动']]);
         // 获取打卡次数
-        $result                         = $Model->finish($uid);
+        $result                         = $CustomClockinRecord->finish($uid,$activeInfo['id']);
         // 失败结束
         if( isset($result['error']) )   return json_send(['code'=>'error','msg'=>$result['error'],'data'=>'']);
         // 返回结果

+ 1 - 1
app/Http/Requests/Admin/ScoreClockin.php

@@ -19,7 +19,7 @@ class ScoreClockin extends BaseRequest
         return      [
             // 有时候我们希望某个字段在第一次验证失败后就停止运行验证规则,只需要将 bail 添加到规则中:
             // 验证字段,验证规则,提示信息
-            'what_day' 	        => 'required|integer|gt:0|unique:score_clockin,what_day,'.request('id',0),
+            'what_day' 	        => 'required|integer|gt:0',
 	        'id'                => 'required|integer|gt:0',
             'status'            => 'required|integer|gte:0',
         ];

+ 51 - 0
app/Http/Requests/Admin/ScoreClockinActive.php

@@ -0,0 +1,51 @@
+<?php namespace App\Http\Requests\Admin;
+
+use App\Http\Requests\BaseRequest;
+
+/**
+ * 积分打卡验证器
+ * 
+ */
+class ScoreClockinActive extends BaseRequest
+{
+	/**
+     * 获取应用于请求的规则
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        // 返回结果
+        return      [
+            // 有时候我们希望某个字段在第一次验证失败后就停止运行验证规则,只需要将 bail 添加到规则中:
+            // 验证字段,验证规则,提示信息
+            'name' 			    => 'required|unique:score_clockin_active,name,'.request('id',0),
+            'id'                => 'required|integer|gt:0',
+        ];
+    }
+
+
+    // 场景列表
+    protected   $scenes         = [
+        'add'  		            => ['name'],
+        'edit'  		        => ['id','name'],
+        'set_status'  		    => ['id'],
+    ];
+
+    /**
+     * 获取已定义验证规则的错误消息
+     *
+     * @return array
+     */
+    public function messages()
+    {
+        return [
+            'name.required'     => '活动名称必填',
+            'name.unique'	    => '活动名称已经存在',
+            'id.required'       => 'ID未知',
+            'id.integer'        => 'ID格式错误',
+            'id.gt'   		    => 'ID格式错误',
+        ];
+    }
+}
+?>

+ 1 - 1
app/Models/Coupon.php

@@ -69,7 +69,7 @@ class Coupon extends Model
      * 
      */
     public function idToCode($id){
-        return 'klyhq'. str_pad($id, 9, '0', STR_PAD_LEFT);;
+        return 'klyhq'. str_pad($id, 9, '0', STR_PAD_LEFT);
     }
 
 

+ 232 - 0
app/Models/CustomClockinRecord.php

@@ -0,0 +1,232 @@
+<?php namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use App\Facades\Servers\Redis\Redis;
+use App\Models\CustomScore;
+use App\Models\Score\Clockin;
+use Illuminate\Support\Carbon;
+use Illuminate\Support\Facades\DB;
+
+/**
+ * 打卡活动
+ * 
+ */
+class CustomClockinRecord extends Model
+{
+    use HasFactory;
+
+    // 与模型关联的表名
+    protected $table = 'custom_clockin_record';
+    // 是否主动维护时间戳
+    public $timestamps = false;
+    // 定义时间戳字段名
+    // const CREATED_AT = 'insert_time';
+    // const UPDATED_AT = 'update_time';
+
+    /**
+     * 添加数据
+     *
+     */
+    public function add($data)
+    {
+        // 时间
+        $data['insert_time']				= time();
+        $data['update_time']				= time();
+        // 写入数据表
+        $id						            = $this->query()->insertGetId($data);
+        // 返回结果
+        return                              $id;
+    }
+
+    /**
+     * 添加数据
+     *
+     */
+    public function edit($id,$data)
+    {
+        // 更新时间
+        $data['update_time']                = time();
+        // 写入数据表
+        $result						        = $this->query()->where(['id'=>$id])->update($data);
+        // 如果操作失败
+        if( !$result )                      return $result;
+        // 更新缓存
+        $this->getList(true);
+        // 返回结果
+        return                              $result;
+    }
+
+    /**
+     * 获取列表
+     * @param   Bool    $force  是否强制更新
+     *
+     */
+    public function getList($force = false)
+    {
+        // 结果数据
+        $list                   = $force ? [] : cache('admin:clockin:active:list');
+        $where[]                = ['status'=>0];
+        $where[]                = ['end_time','>=',time()];
+        // 不存在数据
+        if ( !$list ) {
+            // 从数据库获取数据
+            $data              = $this->query()->where($where)->get(['id','name','banner_img','active_rule','status','start_time','end_time','tag_scope','city_ids']);
+            // 是否有数据
+            $data              = $data ? $data->toArray() : [];
+            // 循环处理数据
+            $list              = [];
+            // 进行更新
+            foreach ($data as $value) {
+                // 重组数据
+                $list[$value['id']] = $value;
+            }
+            // 存起来
+            cache(['admin:clockin:active:list'=>$list]);
+        }
+        // 返回结果
+        return                  $list;
+    }
+
+    /**
+     * 今日是否已签到
+     *
+     * @param   int    $uid         用户ID
+     *
+     */
+    public function isMarkClock($uid){
+        // 如果没有id
+        if( !$uid )         return ['is_clockin'=>0,'finish_day'=>0];
+        // 获取缓存
+        //$record             = cache('score:clockin:mark:uid:'.$uid,[]);
+        // 返回结果
+        // if( $record )       return $record;
+        // 通过查询今日打卡积分记录
+        $record             = $this->query()->where([['custom_uid','=',$uid],['clockin_time','>=',Carbon::now()->startOfDay()->getTimestamp()]])->first(['id','custom_uid','clockin_day','clockin_time']);
+        // 如果没有记录
+        $record             = $record ? ['is_clockin'=>1,'finish_day'=>$record['clockin_day']] : ['is_clockin'=>0,'finish_day'=>0];
+        // 如果没有打卡天数
+        if( !$record['finish_day'] ) {
+            // 获取昨天的打卡记录。以获取已打卡天数
+            $record['finish_day']   = (int) $this->query()->where([['custom_uid','=',$uid],['clockin_time','>=',Carbon::now()->addDays(-1)->startOfDay()->getTimestamp()],['clockin_time','<=',Carbon::now()->addDays(-1)->endOfDay()->getTimestamp()]])->value('clockin_day');
+        }
+        // 标记
+        //$this->setMarkClock($uid,$record);
+        // 返回结果
+        return              $record;
+    }
+    /**
+     * 打卡操作
+     *
+     * @param   int    $uid         用户ID
+     *
+     */
+    public function finish($uid,$activeId)
+    {
+        // 获取打卡任务列表,并获取最大天数
+        $maxDay                         = $this->getMaxDay($activeId);
+        // 如果是0,没有需要签到的任务
+        if( !$maxDay )                  return ['error'=>'无签到任务'];
+        // 是否已签到
+        $isMark                         = $this->isMarkClock($uid);
+        // 如果已经签到,不进行后续操作,返回已打卡
+        if( $isMark['is_clockin'] )     return ['error'=>'今日已打卡'];
+        // 如果当前已签到天数大于最大天数,从1开始计算签到天数
+        $finishDay                      = $isMark['finish_day'] >= $maxDay ? 1 : $isMark['finish_day'] +1;
+        // 通过今日天数查找对应的打卡奖励
+        $list                           = $this->getOne($finishDay,$activeId);
+        if (!$list)                     return ['error'=>'今日签到没有奖励'];
+        $reward                         =  $list['reward'] ?? 0;
+        $coupon_id                      =  $list['coupon_id'] ?? 0;
+        // 组合数据,写入订单表,子表
+        DB::beginTransaction();
+        // 写入数据
+        try {
+            // 成功继续
+            if ($reward){
+                $result                     = (new CustomScore())->trade($uid,0,$reward,2,$finishDay);
+                // 失败结束
+                if( isset($result['error']) )   {
+                    // 回退数据
+                    DB::rollBack();
+                    // 下单失败提示
+                    return					['error'=>$result['error']];
+                }
+            }
+            if ($coupon_id){
+                $data = [
+                    'coupon_id'     =>  $coupon_id,
+                    'custom_uid'    =>  $uid,
+                ];
+                $result                     = (new CustomCoupon())->add($data);
+                // 失败结束
+                if( !$result )   {
+                    // 回退数据
+                    DB::rollBack();
+                    // 下单失败提示
+                    return					['error'=>'签到赠送优惠券失败'];
+                }
+            }
+            //打卡签到记录
+            $recordInfo = [
+                'custom_uid'        => $uid,
+                'active_id'         => $activeId,
+                'clockin_day'       => $finishDay,
+                'clockin_time'      => time(),
+                'score'             => $reward,
+                'coupon_id'         => $coupon_id,
+            ];
+            $re                 = (new CustomClockinRecord())->add($recordInfo);;
+            // 失败结束
+            if( !$re )   {
+                // 回退数据
+                DB::rollBack();
+                // 下单失败提示
+                return					['error'=>'打卡签到记录失败'];
+            }
+            // 提交数据
+            DB::commit();
+            // 打卡通过
+            $isMark['is_clockin']       = 1;
+            $isMark['finish_day']       = $finishDay;
+            // 奖励返回
+            $isMark['reward']           = $reward;
+            $isMark['coupon']           = $coupon_id;
+            // 返回打卡结果与奖励
+            return                      $isMark;
+        } catch (\Throwable $th) {
+            // 回退数据
+            DB::rollBack();
+            // 下单失败提示
+            return						['error'=>'打卡失败'];
+        }
+    }
+    /**
+     * 获取最大的打卡天数
+     *
+     */
+    public  function getMaxDay($activeId){
+        // 查询数据
+        $data                = (new Clockin())->getActiveList($activeId);
+        // 获取天数字段
+        $days                = array_column($data,'what_day');
+        // 获取第一个
+        $maxDay              = $days ? max($days) : 0;
+        // 返回结果
+        return               (int) $maxDay;
+    }
+    /**
+     * 根据天数获取
+     *
+     */
+    public function getOne($whatDay,$activeId=0,$field=''){
+        // 获取列表数据
+        $list                   = (new Clockin())->getActiveList($activeId);
+        // 获取数据
+        $one                    = isset($list[$whatDay]) ? $list[$whatDay] : [];
+        // 返回值
+        return                  empty($field) ? $one : ( isset($one[$field]) ? $one[$field] : null);
+
+    }
+
+}

+ 36 - 1
app/Models/Score/Clockin.php

@@ -213,6 +213,41 @@ class Clockin extends Model
 		}
     }
 
-    
+    /**
+     * 获取活动打卡列表
+     *@param   int    $active_id         打卡活动id
+     *
+     */
+    public function getActiveList($active_id=0,$force=true)
+    {
+        // 结果数据
+        $list                  = $force ? [] : cache('score:clockin:list:'.$active_id);
+        $where = [
+            'status'=>0,
+            'active_id'=>$active_id
+        ];
+        // 不存在数据
+        if ( !$list ) {
+            // 从数据库获取数据
+            $data              = $this->query()
+                ->where($where)
+                ->orderBy('what_day')
+                ->orderBy('id')
+                ->get(['id','what_day','status','reward','active_id','coupon_id']);
+            // 是否有数据
+            $data              = $data ? $data->toArray() : [];
+            // 循环处理数据
+            $list              = [];
+            // 进行更新
+            foreach ($data as $value) {
+                // 重组数据
+                $list[$value['what_day']] = $value;
+            }
+            // 存起来
+            cache(['score:clockin:list:'.$active_id=>$list]);
+        }
+        // 返回结果
+        return                  $list;
+    }
 
 }

+ 110 - 0
app/Models/Score/ClockinActive.php

@@ -0,0 +1,110 @@
+<?php namespace App\Models\Score;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use App\Facades\Servers\Redis\Redis;
+use App\Models\CustomScore;
+use Illuminate\Support\Carbon;
+use Illuminate\Support\Facades\DB;
+
+/**
+ * 打卡活动
+ * 
+ */
+class ClockinActive extends Model
+{
+    use HasFactory;
+
+    // 与模型关联的表名
+    protected $table = 'score_clockin_active';
+    // 是否主动维护时间戳
+    public $timestamps = false;
+
+    /**
+     * 添加数据
+     *
+     */
+    public function add($data)
+    {
+        // 时间
+        $data['insert_time']				= time();
+        $data['update_time']				= time();
+        // 写入数据表
+        $id						            = $this->query()->insertGetId($data);
+        // 如果操作失败
+        if( !$id )                          return $id;
+        // 更新缓存
+        $this->getList(true);
+        // 返回结果
+        return                              $id;
+    }
+
+    /**
+     * 添加数据
+     *
+     */
+    public function edit($id,$data)
+    {
+        // 更新时间
+        $data['update_time']                = time();
+        // 写入数据表
+        $result						        = $this->query()->where(['id'=>$id])->update($data);
+        // 如果操作失败
+        if( !$result )                      return $result;
+        // 更新缓存
+        $this->getList(true);
+        // 返回结果
+        return                              $result;
+    }
+
+    /**
+     * 获取列表
+     * @param   Bool    $force  是否强制更新
+     *
+     */
+    public function getList($force = false)
+    {
+        // 结果数据
+        //$list                   = $force ? [] : cache('admin:clockin:active:list');
+        $where[]                = ['status'=>0];
+        $where[]                = ['end_time','>=',time()];
+        // 不存在数据
+        //if ( !$list ) {
+            // 从数据库获取数据
+            $data              = $this->query()->where($where)->get(['id','name','banner_img','active_rule','status','start_time','end_time','tag_scope','city_ids']);
+            // 是否有数据
+            $data              = $data ? $data->toArray() : [];
+            // 循环处理数据
+            $list              = [];
+            // 进行更新
+            foreach ($data as $value) {
+                // 重组数据
+                $list[$value['id']] = $value;
+            }
+            // 存起来
+            //cache(['admin:clockin:active:list'=>$list]);
+        //}
+        // 返回结果
+        return                  $list;
+    }
+
+    /**
+     * 获取配置平台对应的应用数据
+     *
+     * @param   Array      用户ID
+     * @param   String     指定字段
+     *
+     */
+    public function getOne($id,$field='')
+    {
+        // 获取列表数据
+        $list                   = $this->getList();
+        // 获取数据
+        $one                    = isset($list[$id]) ? $list[$id] : [];
+        // 返回值
+        return                  empty($field) ? $one : ( isset($one[$field]) ? $one[$field] : null);
+    }
+
+    
+
+}

+ 58 - 0
app/Models/Score/CustomClockin.php

@@ -0,0 +1,58 @@
+<?php namespace App\Models\Score;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use App\Facades\Servers\Redis\Redis;
+use App\Models\Score\ClockinActive;
+use App\Models\CustomScore;
+use App\Models\CustomCoupon;
+use App\Models\CustomClockinRecord;
+use Illuminate\Support\Carbon;
+use Illuminate\Support\Facades\DB;
+
+/**
+ * 用户连续打卡记录
+ * 
+ */
+class CustomClockin extends Model
+{
+    use HasFactory;
+
+    // 与模型关联的表名
+    protected $table = 'custom_clockin';
+    // 是否主动维护时间戳
+    public $timestamps = false;
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function add($data)
+    {
+        // 时间
+        $data['insert_time']				= time();
+        $data['update_time']				= time();
+        // 写入数据表
+        $id						            = $this->query()->insertGetId($data);
+        // 如果操作失败
+        if( !$id )                          return ['error'=>'新增失败'];
+        // 返回结果
+        return                              $id;
+    }
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function edit($id,$data)
+    {
+        // 更新时间
+        $data['update_time']                = time();
+        // 写入数据表
+        $result						        = $this->query()->where(['id'=>$id])->update($data);
+        // 如果操作失败
+        if( !$result )                      return ['error'=>'修改失败'];
+        // 返回结果
+        return                              $result;
+    }
+}

+ 179 - 0
resources/views/admin/custom_clockin_record/index.blade.php

@@ -0,0 +1,179 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+<form action="" method="get" class="form-horizontal form-line">
+	<div class="form-group col col-lg-2 col-md-2 col-sm-2 col-xs-2" style="margin-right: 2px;">
+		<input type="text" class="form-control" name="custom_code" value="{{request('custom_code','')}}" placeholder="请输入客户编码查询" />
+	</div>
+	<div class="form-group col col-lg-2 col-md-2 col-sm-2 col-xs-2" style="margin-right: 2px;">
+		<input type="text" class="form-control" name="phone" value="{{request('phone','')}}" placeholder="请输入联系方式查询" />
+	</div>
+	<div class="form-group col col-lg-2 col-md-2 col-sm-2 col-xs-2" style="margin-right: 2px;">
+	<select name="city_id" class="form-control selectpicker" data-max-options="20" data-live-search="true" data-live-search-placeholder="搜索城市" data-none-results-text="未搜索到 {0}" title="选择城市">
+			@foreach ($cityList as $group)
+			<optgroup label="{{$group['name']}}">
+				@foreach ($group['city'] as $city)
+				<option value="{{$city['id']}}" @if( $city['id'] == request('city_id',0) ) selected @endif >{{$city['name']}}</option>
+				@endforeach
+			</optgroup>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col col-lg-2 col-md-2 col-sm-2 col-xs-2" style="margin-right: 2px;">
+		<input type="date" class="form-control" name="start_time" value="{{request('start_time','')}}" placeholder="请输入创建时间查询" />
+	</div>
+	<input type="submit" class="btn btn-sm btn-primary" value="查询"/>
+	<a href="{{url('admin/custom/index')}}" class="btn btn-sm btn-default" >重置</a>
+</form>
+
+<div class="row">
+	<div class="col-xs-12">	
+		<div class="table-responsive">
+			<table class="table table-striped table-bordered table-hover">
+				<thead>
+					<tr>
+						<th>记录ID</th>
+						<th>客户编码</th>
+						<th>客户昵称</th>
+						<th>活动名称</th>
+						<th>联系方式</th>
+						<th>微伴ID</th>
+						<th>客户城市</th>
+						<th>客户状态</th>
+						<th>打卡时间</th>
+						<th>连续打卡天数</th>
+					</tr>
+				</thead>
+				
+				<tbody>
+						@foreach ($list as $a)
+						<tr>
+							<th> {{$a['id']}} </th>
+							<th> {{$a['custom_code']}} </th>
+							<td> {{$a['username']}} </td>
+							<td> {{$a['active_name']}} </td>
+							<td> {{$a['phone']}} </td>
+							<td> <a href="{{url('admin/weiban_external/index?'.http_build_query(['id'=>$a['weiban_extid']]))}}">{{$a['weiban_extid']}}</a></td>
+							<td> {{$a['city_name']}} </td>
+							<td> {{$a['status']?'禁用':'正常'}} </td>
+							<td> {{date('Y/m/d H:i:s',$a['clockin_time'])}}</td>
+							<td> {{$a['clockin_day']}} </td>
+						</tr>  
+						@endforeach
+						<tr>
+							<td colspan="20" class="page">{{$list->render()}}</td>
+						</tr>
+						<tr>
+							<td colspan="20">总计 {{$list->total()}} 个记录</td>
+						</tr>
+				</tbody>
+				
+			</table>
+		</div>
+	</div>
+</div>
+@endsection
+@section('javascript')
+<script src="/static/fileupload/jquery.ui.widget.js"></script>
+<script src="/static/fileupload/jquery.fileupload.js"></script>
+<script type="text/javascript">
+ $(function(){
+	$('.upload').on('click', function() {
+		$('#form-upload').remove();
+		$('body').prepend('<form enctype="multipart/form-data" id="form-upload" style="display: none;"><input osctype="btn_upload_file" type="file" name="custom_file" multiple="multiple" /></form>');
+		$('#form-upload input[name=\'custom_file\']').trigger('click');
+		$('[osctype="btn_upload_file"]').fileupload({
+			dataType: 'json',
+			url: "{{url('admin/custom/import_execl')}}",
+			singleFileUploads: false,
+			beforeSend: function() {
+				art.dialog({
+					id: 'loading',
+					lock: true,
+					title: '文件上传中'
+				});
+			},
+			done: function(e, data) {
+				art.dialog.list['loading'].close();
+				var result = data.result;
+				if (result.code == 'error') {
+					art.dialog({
+						content: result.msg,
+						lock: true,
+						ok: function() {}
+					});
+				}
+				if (result.code == 'success') {
+					art.dialog({
+						content: result.msg,
+						lock: true,
+						ok: function() {
+							location.reload();
+						}
+					});
+				}
+			},
+			fail: function(e,c) {
+				art.dialog.list['loading'].close();
+				art.dialog({
+					content: '<p>'+c.jqXHR.status+'=>'+c.jqXHR.statusText+'</p>',
+					lock: true,
+					ok: function() {}
+				});
+			}
+		});
+	});
+ })
+</script>
+<script type="text/javascript">
+ $(function(){
+	$('.upload_score').on('click', function() {
+		$('#form-upload').remove();
+		$('body').prepend('<form enctype="multipart/form-data" id="form-upload" style="display: none;"><input osctype="btn_upload_file" type="file" name="score_file" multiple="multiple" /></form>');
+		$('#form-upload input[name=\'score_file\']').trigger('click');
+		$('[osctype="btn_upload_file"]').fileupload({
+			dataType: 'json',
+			url: "{{url('admin/custom_score/import_execl')}}",
+			singleFileUploads: false,
+			beforeSend: function() {
+				art.dialog({
+					id: 'loading',
+					lock: true,
+					title: '文件上传中'
+				});
+			},
+			done: function(e, data) {
+				art.dialog.list['loading'].close();
+				var result = data.result;
+				if (result.code == 'error') {
+					art.dialog({
+						content: result.msg,
+						lock: true,
+						ok: function() {}
+					});
+				}
+				if (result.code == 'success') {
+					art.dialog({
+						content: result.msg,
+						lock: true,
+						ok: function() {
+							location.reload();
+						}
+					});
+				}
+			},
+			fail: function(e,c) {
+				art.dialog.list['loading'].close();
+				art.dialog({
+					content: '<p>'+c.jqXHR.status+'=>'+c.jqXHR.statusText+'</p>',
+					lock: true,
+					ok: function() {}
+				});
+			}
+		});
+	});
+ })
+</script>
+@endsection

+ 5 - 1
resources/views/admin/score_clockin/add.blade.php

@@ -6,12 +6,16 @@ style="margin: 0 auto;width: 96%;padding: 30px 0px;"
 <form class="post-form" action="" method="post">
 	<div class="form-group col-sm-12">
 		<label class="control-label">任务天数</label>
-		<input class="form-control" type="number" placeholder="任务天数,第几天" required=""  min="1" max="7" name="what_day" value="" />
+		<input class="form-control" type="number" placeholder="任务天数,第几天" required=""  min="1" name="what_day" value="" />
 	</div>
 	<div class="form-group col-sm-12">
 		<label class="control-label">奖励积分</label>
 		<input class="form-control" type="number" placeholder="奖励积分" required="" min="1" max="65535" name="reward" value="" />
 	</div>
+	<div class="form-group col-sm-12">
+		<label class="control-label">奖励券</label>
+		<input class="form-control" type="text" placeholder="优惠券编码" maxlength="45" name="coupon_code" value="" />
+	</div>
 	<div class="form-group col-sm-12">
 		@csrf
 		<input id="send" type="submit" value="提交" class="btn btn-primary btn-block" />

+ 4 - 0
resources/views/admin/score_clockin/edit.blade.php

@@ -12,6 +12,10 @@ style="margin: 0 auto;width: 96%;padding: 30px 0px;"
 		<label class="control-label">奖励积分</label>
 		<input class="form-control" type="number" placeholder="奖励积分" required="" min="1" max="65535" name="reward" value="{{$oldData['reward']}}" />
 	</div>
+	<div class="form-group col-sm-12">
+		<label class="control-label">奖励券</label>
+		<input class="form-control" type="text" placeholder="优惠券编码" required="" maxlength="45"  name="coupon_code" value="{{$oldData['coupon_code']}}" />
+	</div>
 	<div class="form-group col-sm-12">
 		@csrf
 		<input type="hidden" name="id" id="id" value="{{$oldData['id']}}" />

+ 3 - 1
resources/views/admin/score_clockin/index.blade.php

@@ -4,7 +4,7 @@ style="margin: 0 auto;width: 96%;padding: 30px 0px;"
 @endsection
 @section('content')
 <div class="page-header">
-	<a href="{{url('admin/score_clockin/add')}}" class="btn btn-primary">新增</a>
+	<a href="{{url('admin/score_clockin/add?'.http_build_query(['active_id'=>request('active_id',0)]))}}" class="btn btn-primary">新增</a>
 </div>
 <form action="" method="get" class="form-horizontal form-line">
 	
@@ -18,6 +18,7 @@ style="margin: 0 auto;width: 96%;padding: 30px 0px;"
 						<th>ID</th>
 						<th>打卡天数</th>
 						<th>奖励积分</th>
+						<th>奖励卷</th>
 						<th>修改时间</th>
 						<th>操作</th>
 					</tr>
@@ -28,6 +29,7 @@ style="margin: 0 auto;width: 96%;padding: 30px 0px;"
 						<td>{{$a['id']}}</td>
 						<td>{{$a['what_day']}}</td>
 						<td>{{$a['reward']}}</td>
+						<td>{{$a['coupon_name'] ? $a['coupon_name'].'('.$a['coupon_code'].')':''}}</td>
 						<td>{{date('Y-m-d H:i:s',$a['update_time'])}}</td>
 						<td>
 							<a class="btn btn-sm btn-warning" href="{{url('admin/score_clockin/edit?'.http_build_query(['id'=>$a['id']]))}}">

+ 61 - 0
resources/views/admin/score_clockin_active/add.blade.php

@@ -0,0 +1,61 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+<form class="post-form" action="" method="post">
+	<div class="form-group col-sm-2">
+		<label class="control-label">活动首图 [1180*490]</label>
+		<div id="banner_img">
+			<a id="banner_img-image" href="#" data-toggle="image" class="img-thumb">
+				<img src="{{path_compat('')}}" width="120" />
+			</a>
+			<input type="hidden" name="banner_img" value="" id="input-banner_img" />
+		</div>
+	</div>
+	<div class="form-group col-sm-4">
+		<label class="control-label">活动名称</label>
+		<input class="form-control" required="required" type="text" placeholder="活动名称" name="name" maxlength="45" value="" />
+	</div>
+	<div class="form-group col-sm-3">
+		<label class="control-label">开始时间</label>
+		<input class="form-control" required="required" type="datetime-local" placeholder="开始时间"  name="start_time" value="" />
+	</div>
+	<div class="form-group col-sm-3">
+		<label class="control-label">结束时间</label>
+		<input class="form-control" required="required" type="datetime-local" placeholder="结束时间" name="end_time" value="" />
+	</div>
+	<div class="form-group col-sm-5">
+		<label class="control-label">活动城市</label>
+		<select name="city_ids[]" class="form-control selectpicker" data-max-options="20" data-live-search="true" data-live-search-placeholder="搜索城市" data-none-results-text="未搜索到 {0}" title="选择城市" multiple>
+			@foreach ($cityList as $group)
+			<optgroup label="{{$group['name']}}">
+				@foreach ($group['city'] as $city)
+				<option value="{{$city['id']}}" >{{$city['name']}}</option>
+				@endforeach
+			</optgroup>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col-sm-5">
+		<label class="control-label">标签范围(标签存在延迟,请慎用)</label>
+		<select name="tag_scope[]" class="form-control selectpicker" data-max-options="10" data-live-search="true" data-live-search-placeholder="搜索标签" data-none-results-text="未搜索到 {0}" title="选择标签" multiple>
+			@foreach ($tagList as $group=>$tags)
+			<optgroup label="{{$group}}">
+				@foreach ($tags as $tag)
+				<option value="{{$tag}}" >{{$tag}}</option>
+				@endforeach
+			</optgroup>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col-sm-12">
+		<label class="control-label">活动规则</label>
+		<textarea class="form-control" name="active_rule" rows="10" placeholder="请输入活动规则" maxlength="255" ></textarea>
+	</div>
+	<div class="form-group col-sm-12">
+		@csrf
+		<input id="send" type="submit" value="提交" class="btn btn-primary btn-block" />
+	</div>
+</form>
+@endsection

+ 62 - 0
resources/views/admin/score_clockin_active/edit.blade.php

@@ -0,0 +1,62 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+<form class="post-form" action="" method="post">
+	<div class="form-group col-sm-2">
+		<label class="control-label">活动首图 [1180*490]</label>
+		<div id="banner_img">
+			<a id="banner_img-image" href="#" data-toggle="image" class="img-thumb">
+				<img src="{{path_compat($oldData['banner_img'])}}" width="120" />
+			</a>
+			<input type="hidden" name="banner_img" value="{{$oldData['banner_img']}}" id="input-banner_img" />
+		</div>
+	</div>
+	<div class="form-group col-sm-4">
+		<label class="control-label">活动名称</label>
+		<input class="form-control" required="required" type="text" placeholder="活动名称" name="name" maxlength="45" value="{{$oldData['name']}}" />
+	</div>
+	<div class="form-group col-sm-3">
+		<label class="control-label">开始时间</label>
+		<input class="form-control" required="required" type="datetime-local" placeholder="开始时间"  name="start_time" value="{{date('Y-m-d H:i',$oldData['start_time'])}}" />
+	</div>
+	<div class="form-group col-sm-3">
+		<label class="control-label">结束时间</label>
+		<input class="form-control" required="required" type="datetime-local" placeholder="结束时间" name="end_time" value="{{date('Y-m-d H:i',$oldData['end_time'])}}" />
+	</div>
+	<div class="form-group col-sm-5">
+		<label class="control-label">活动城市</label>
+		<select name="city_ids[]" class="form-control selectpicker" data-max-options="20" data-live-search="true" data-live-search-placeholder="搜索城市" data-none-results-text="未搜索到 {0}" title="选择城市" multiple>
+			@foreach ($cityList as $group)
+			<optgroup label="{{$group['name']}}">
+				@foreach ($group['city'] as $city)
+				<option value="{{$city['id']}}"  @if(in_array($city['id'],$oldData['city_ids'])) selected @endif >{{$city['name']}}</option>
+				@endforeach
+			</optgroup>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col-sm-5">
+		<label class="control-label">标签范围(标签存在延迟,请慎用)</label>
+		<select name="tag_scope[]" class="form-control selectpicker" data-max-options="10" data-live-search="true" data-live-search-placeholder="搜索标签" data-none-results-text="未搜索到 {0}" title="选择标签" multiple>
+			@foreach ($tagList as $group=>$tags)
+			<optgroup label="{{$group}}">
+				@foreach ($tags as $tag)
+				<option value="{{$tag}}"  @if(in_array($tag,$oldData['tag_scope'])) selected @endif >{{$tag}}</option>
+				@endforeach
+			</optgroup>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col-sm-12">
+		<label class="control-label">活动规则</label>
+		<textarea class="form-control" name="active_rule" rows="10" placeholder="请输入活动规则" >{{$oldData['active_rule']}}</textarea>
+	</div>
+	<div class="form-group col-sm-12">
+		@csrf
+		<input type="hidden" name="id" id="id" value="{{$oldData['id']}}" />
+		<input id="send" type="submit" value="提交" class="btn btn-primary btn-block" />
+	</div>
+</form>
+@endsection

+ 97 - 0
resources/views/admin/score_clockin_active/index.blade.php

@@ -0,0 +1,97 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+
+@if(check_auth('admin/score_clockin_active/add'))
+	<div class="page-header">
+		<a href="{{url('admin/score_clockin_active/add')}}" class="btn btn-primary">新增</a>
+	</div>
+@endif
+
+<form action="" method="get" class="form-horizontal form-line">
+	<div class="form-group col col-lg-2 col-md-2 col-sm-2 col-xs-2" style="margin-right: 2px;">
+		<input type="text" class="form-control" name="name" value="{{request('name','')}}" placeholder="请输入活动名称查询" />
+	</div>
+	<input type="submit" class="btn btn-sm btn-primary" value="查询"/>
+	<a href="{{url('admin/score_clockin_active/index')}}" class="btn btn-sm btn-default" >重置</a>
+</form>
+
+<div class="row">
+	<div class="col-xs-12">	
+		<div class="table-responsive">
+			<table class="table table-striped table-bordered table-hover">
+				<thead>
+					<tr>
+						<th>活动ID</th>
+						<th>活动名称</th>
+						<th>活动城市</th>
+						<th>标签范围</th>
+						<th>开始时间</th>
+						<th>结束时间</th>
+						<th>内部跳转</th>
+						<th>宣发链接</th>
+						<th>活动状态</th>
+						<th>修改时间</th>
+						<th>操作</th>									
+					</tr>
+				</thead>
+				
+				<tbody>
+						@foreach ($list as $a)
+						<tr>
+							<th>{{$a['id']}}</th>
+							<td>{{$a['name']}}</td>
+							<td>{{$a['city_ids']}}</td>
+							<td>{{$a['tag_scope']}}</td>
+							<td>{{date('Y/m/d H:i:s',$a['start_time'])}}</td>
+							<td>{{date('Y/m/d H:i:s',$a['end_time'])}}</td>
+							<td>/pages/coupon/active?id={{$a['id']}}</td>
+							<td>{{$a['mp_urllink']}}</td>
+							<td>
+								@if( $a['status'] )
+								停用
+								@else
+									@if( $a['start_time'] <= time() && $a['end_time'] <= time() )
+										已结束
+									@endif
+									@if( $a['start_time'] <= time() && $a['end_time'] > time() )
+										进行中
+									@endif
+									@if( $a['start_time'] > time() )
+										待进行
+									@endif
+								@endif
+							</td>
+							<td> {{date('Y/m/d H:i:s',$a['update_time'])}}</td>
+							<td>
+								@if(check_auth('admin/score_clockin/index'))
+								<a href="{{url('admin/score_clockin/index?'.http_build_query(['active_id'=>$a['id']]))}}" class="btn btn-sm btn-primary" >打卡配置</a>
+								@endif
+								@if(check_auth('admin/score_clockin_active/edit'))
+								<a href="{{url('admin/score_clockin_active/edit?'.http_build_query(['id'=>$a['id']]))}}" class="btn btn-sm btn-warning" >编辑</a>
+								@endif
+								@if(check_auth('admin/score_clockin_active/set_status'))
+									@if($a['status'])
+									<a data-url="{{url('admin/score_clockin_active/set_status?'.http_build_query(['id'=>$a['id'],'status'=>0]))}}" class="set_status btn btn-sm btn-success" >启用</a>
+									@else
+									<a data-url="{{url('admin/score_clockin_active/set_status?'.http_build_query(['id'=>$a['id'],'status'=>1]))}}" class="set_status btn btn-sm btn-danger" >停用</a>
+									@endif
+								@endif
+							</td>							
+						</tr>  
+						@endforeach
+						<tr>
+							<td colspan="20" class="page">{{$list->render()}}</td>
+						</tr>
+						<tr>
+							<td colspan="20">总计 {{$list->total()}} 个商店</td>
+						</tr>
+				</tbody>
+				
+			</table>
+		</div>
+	</div>
+</div>
+@endsection

+ 12 - 0
routes/web.php

@@ -415,4 +415,16 @@ Route::middleware('admin')->prefix('admin')->group(function(){
     // 状态
     Route::any('lottery_order_product/set_status',[App\Http\Controllers\Admin\LotteryOrderProduct::class,'set_status']);
 
+    /* 打卡活动 */
+    // 列表
+    Route::any('score_clockin_active/index',[App\Http\Controllers\Admin\ScoreClockinActive::class,'index']);
+    // 详情
+    Route::any('score_clockin_active/add',[App\Http\Controllers\Admin\ScoreClockinActive::class,'add']);
+    // 详情
+    Route::any('score_clockin_active/edit',[App\Http\Controllers\Admin\ScoreClockinActive::class,'edit']);
+    // 状态
+    Route::any('score_clockin_active/set_status',[App\Http\Controllers\Admin\ScoreClockinActive::class,'set_status']);
+
+    //打卡记录
+    Route::any('custom_clockin_record/index',[App\Http\Controllers\Admin\CustomClockinRecord::class,'index']);
 });