Kaynağa Gözat

促销活动功能

jun 5 ay önce
ebeveyn
işleme
e3ee722bac

+ 326 - 0
app/Http/Controllers/Admin/Promo.php

@@ -0,0 +1,326 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\Promo as Request;
+use App\Models\Promo as Model;
+use App\Models\PromoRebate;
+use App\Models\Product;
+use Illuminate\Support\Facades\DB;
+use App\Models\City;
+use App\Models\WeiBan\Tags as WeiBanTags;
+
+/**
+ * 产品促销活动
+ *
+ * @author    刘相欣
+ *
+ */
+class Promo extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','营销管理');
+		$this->assign('breadcrumb2','产品促销活动');
+	}
+
+	/**
+	 * 首页列表
+	 * 
+	 * */
+    public function index(Model $Model,City $City,PromoRebate $PromoRebate){
+		// 接受参数
+		$code					= request('promo_code','');
+		$promoName				= request('promo_name','');
+		$status					= request('status');
+		$startTime				= request('start_time','');
+		$endTime				= request('end_time','');
+		// 编码转ID
+		$id						= $code ? $Model->codeToId($code) : 0;
+		// 查询条件
+		$map 					= [];
+		// 编码ID
+		if( $id )				$map[] = ['id','=',$id];
+		if( $promoName )		$map[] = ['name','=',$promoName];
+		if( $startTime )		$map[] = ['start_time','>=',strtotime($startTime)];
+		if( $endTime )			$map[] = ['end_time','<=',strtotime($endTime)];
+		if( !is_null($status) )	$map[] = ['status','=',$status];
+		// 查询数据
+		$list					= $Model->query()->where($map)->orderByDesc('id')->paginate(request('limit',config('page_num',10)))->appends(request()->all());
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// id转编号
+			$value['promo_code']= $Model->idToCode($value['id']);
+			// 发放类型
+			$value['gant_name']  = $Model->getGrantType($value['grant_type'],'name');
+			// 如果已经到了结束时间。活动结束
+			if( $value['status'] == 0 && $value['end_time'] <= time() ) {
+				// 状态设置
+				$Model->edit($value['id'],['status'=>3]);
+				// 状态设置
+				$value['status'] = 3;
+			}
+			// 判断是不是可以参与
+			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);
+			}
+			// 赠品
+			if( $value['rebate_type'] == 3 ) {
+				// 返回结果
+				$value['rebate'] 	= (string) $PromoRebate->query()->join('product','promo_rebate.product_id','=','product.id')->where([['promo_id','=',$value['id']]])->value('product.name');
+			}
+			// 重组
+			$list[$key]				= $value;
+		}
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list', $list);
+		// 加载模板
+		return					$this->fetch();
+    }
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add( Request $request, Model $Model,City $City,PromoRebate $PromoRebate,Product $Product,WeiBanTags $WeiBanTags){
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 组合数据
+			$data['name']			= request('name',0);
+			$data['rebate_type']	= request('rebate_type',0);
+			$data['std_pay']		= request('std_pay',0);
+			$data['rebate']			= request('rebate',0);
+			$data['start_time']		= request('start_time','');
+			$data['end_time'] 		= request('end_time','');
+			$data['status']			= request('status',2);
+			$data['type_id']		= request('type_id',0);
+			$cityIds				= request('city_ids',[]);
+            $tagScope				= request('tag_scope',[]);
+			$data['city_ids']		= implode(',',$cityIds);
+            $data['tag_scope']		= implode(',',$tagScope);
+			// 转换时间,默认现在现在生效
+			$data['start_time']		= $data['start_time'] ? strtotime($data['start_time']) : time();
+			// 转换时间,默认无结束时间
+			$data['end_time']		= $data['end_time'] ? strtotime($data['end_time']) : 0;
+			// 验证信息
+			if( $data['rebate_type'] == 2 && $data['rebate'] > 9.99 ) return json_send(['code'=>'error','msg'=>'不能设置大于9.99折']);
+			if( $data['start_time'] < 0 ) return json_send(['code'=>'error','msg'=>'请填写活动开始时间']);
+			if( $data['end_time'] 	< time() ) return json_send(['code'=>'error','msg'=>'活动时间必须大于当前时间']);
+			// 赠品ID
+			$rebateId				= 0;
+			// 如果是赠品表的话。处理赠品逻辑
+			if( $data['rebate_type'] == 3 ) {
+				// 产品编码
+				$rebateId 			= $Product->codeToId($data['rebate']);
+				// 赠品ID不存在
+				if( !$rebateId )	return json_send(['code'=>'error','msg'=>'赠品编码格式有误']);
+				// 设置为0,避免数据异常
+				$data['rebate']     = 0;
+			}
+			// 组合数据,写入订单表,子表
+			DB::beginTransaction();
+			try {
+				// 写入
+				$id						= $Model->add($data);
+				// 提示新增失败
+				if( !$id )				{
+					// 回滚
+					DB::rollBack();
+					// 提示
+					return json_send(['code'=>'error','msg'=>'新增失败']);
+				}
+				// 如果是赠品
+				if( $rebateId )			{
+					// 写入数据
+					$result 			= $PromoRebate->add(['promo_id'=>$id,'product_id'=>$rebateId,'rebate_num'=>1]);
+					// 提示新增失败
+					if( !$result )		{
+						// 回滚
+						DB::rollBack();
+						// 提示失败
+						return			json_send(['code'=>'error','msg'=>'赠品结果写入失败']);
+					}
+				}
+				// 提交
+				DB::commit();
+				// 记录行为
+				$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
+				// 告知结果
+				return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+			} catch (\Throwable $th) 	{
+				// 回滚
+				DB::rollBack();
+				// 提示失败
+				return					json_send(['code'=>'error','msg'=>'内部错误,请重试','data'=>['error'=>$th->getMessage()]]);
+			}
+		}
+		// 获取列表
+		$cityList					= $City->getCityList();
+        // 标签列表
+        $tagData					= $WeiBanTags->query()->groupBy('group')->groupBy('name')->get(['group','name'])->toArray();
+        $tagList					= [];
+        // 循环数据
+        foreach ($tagData as $value) {
+            $tagList[$value['group']][] = $value['name'];
+        }
+		$grantList					= $Model->getGrantTypeList();
+		// 分配数据
+		$this->assign('cityList',$cityList);
+		$this->assign('grantList',$grantList);
+		$this->assign('tagList',$tagList);
+		$this->assign('crumbs','新增');
+		// 加载模板
+		return 						$this->fetch();
+	}
+	
+	/**
+	 * 编辑
+	 * 
+	 * */
+	public function edit( Request $request, Model $Model,City $City,PromoRebate $PromoRebate,Product $Product,WeiBanTags $WeiBanTags){
+		// 接收参数
+		$id							= request('id',0);
+		// 查询数据
+		$oldData					= $Model->where(['id'=>$id])->first();
+		// 修改
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('edit')->validate();
+			// 组合数据
+			$data['name']			= request('name',0);
+			$data['rebate_type']	= request('rebate_type',0);
+			$data['std_pay']		= request('std_pay',0);
+			$data['rebate']			= request('rebate',0);
+			$data['start_time']		= request('start_time','');
+			$data['end_time'] 		= request('end_time','');
+            $data['type_id']		= request('type_id',1);
+			$cityIds				= request('city_ids',[]);
+            $tagScope				= request('tag_scope',[]);
+            $data['city_ids']		= implode(',',$cityIds);
+            $data['tag_scope']		= implode(',',$tagScope);
+			// 转换时间,默认现在现在生效
+			$data['start_time']		= $data['start_time'] ? strtotime($data['start_time']) : time();
+			// 转换时间,默认无结束时间
+			$data['end_time']		= $data['end_time'] ? strtotime($data['end_time']) : 0;
+			// 赠品ID
+			$rebateId				= 0;
+			// 如果是赠品表的话。处理赠品逻辑
+			if( $data['rebate_type'] == 3 ) {
+				// 产品编码
+				$rebateId 			= $Product->codeToId($data['rebate']);
+				// 赠品ID不存在
+				if( !$rebateId )	return json_send(['code'=>'error','msg'=>'赠品编码格式有误']);
+				// 设置为0,避免数据异常
+				$data['rebate']     = 0;
+			}
+			// 验证信息
+			if( $data['rebate_type'] == 2 && $data['rebate'] > 9.99 ) return json_send(['code'=>'error','msg'=>'不能设置大于9.99折']);
+			if( $data['start_time'] < 0 ) return json_send(['code'=>'error','msg'=>'请填写活动开始时间']);
+			if( $data['end_time'] 	< time() ) return json_send(['code'=>'error','msg'=>'活动时间必须大于当前时间']);
+			// 组合数据,写入订单表,子表
+			DB::beginTransaction();
+			try {
+				// 写入
+				$result				= $Model->edit($id,$data);
+				// 提示新增失败
+				if( !$result )		{
+					// 回滚
+					DB::rollBack();
+					// 提示
+					return json_send(['code'=>'error','msg'=>'编辑失败']);
+				}
+				// 如果是赠品券
+				if( $rebateId )		{
+					// 查询旧的
+					$oldRebateId 	= $PromoRebate->query()->where([['promo_id','=',$id],['product_id','=',$rebateId]])->value('id');
+					// 有旧的修改,无则添加新的
+					$result 		= $oldRebateId ? $PromoRebate->edit($oldRebateId,['product_id'=>$rebateId,'rebate_num'=>1]) : $PromoRebate->add(['promo_id'=>$id,'product_id'=>$rebateId,'rebate_num'=>1]);
+					// 提示新增失败
+					if( !$result )	{
+						// 回滚
+						DB::rollBack();
+						// 提示失败
+						return	json_send(['code'=>'error','msg'=>'赠品结果写入失败']);
+					}
+				}
+				// 提交
+				DB::commit();
+				// 记录行为
+				$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],$data);
+				// 告知结果
+				return				json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);
+			} catch (\Throwable $th) {
+				// 回滚
+				DB::rollBack();
+				// 提示失败
+				return				json_send(['code'=>'error','msg'=>'内部错误,请重试','data'=>['error'=>$th->getMessage()]]);
+			}
+		}
+		// 如果是没有数据
+		if( !$oldData ) 			return $this->error('查无数据');
+		// 如果是赠品表的话。处理赠品逻辑
+		if( $oldData['rebate_type'] == 3 ) {
+			// 产品编码
+			$rebateId 			= $PromoRebate->getProductByCouponId($oldData['id']);
+			// 产品ID
+			$rebateId 			= isset($rebateId[0]['product_id']) ? $Product->idToCode($rebateId[0]['product_id']) : '';
+			// 设置为0,避免数据异常
+			$oldData['rebate']  = $rebateId;
+		}
+		// 城市处理
+		$oldData['city_ids']	= explode(',',$oldData['city_ids']);
+        $oldData['tag_scope']	= explode(',',$oldData['tag_scope']);
+		// 有效期,时间戳或者时间为0表示的时间段,否则表示领取后N天
+		$oldData['exp_type']	= $oldData['exp_time'] > 1000 ? 2 : 1;
+		// 获取列表
+		$cityList					= $City->getCityList();
+		$grantList					= $Model->getGrantTypeList();
+        // 标签列表
+        $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('grantList',$grantList);
+		$this->assign('tagList',$tagList);
+		$this->assign('oldData',$oldData);
+		$this->assign('crumbs','修改');
+		// 加载模板
+		return 					$this->fetch();
+	}
+
+	/**
+	 * 状态
+	 * 
+	 * */
+	public function set_status( Request $request, Model $Model){
+		// 验证参数
+		$request->scene('set_status')->validate();
+		// 接收参数
+		$id				= request('id',0);
+		$status			= request('status',0);
+		// 查询数据
+		$result			= $Model->edit($id,['status'=>$status]);
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 记录行为
+		$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],['status'=>$status]);
+		// 告知结果
+		return			json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+}

+ 164 - 0
app/Http/Controllers/Admin/PromoProduct.php

@@ -0,0 +1,164 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\PromoProduct as Request;
+use App\Models\Product;
+use App\Models\PromoProduct as Model;
+use App\Models\Promo;
+
+/**
+ * 优惠券自动发放规则产品范围
+ *
+ * @author    刘相欣
+ *
+ */
+class PromoProduct extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','营销管理');
+		$this->assign('breadcrumb2','促销活动商品');
+	}
+
+	/**
+	 * 列表页
+	 * 
+	 * */
+    public function index(Model $Model,Promo $Promo,Product $Product){
+		// 接收参数
+		$promoCode				= request('promo_code','');
+		$productCode			= request('product_code','');
+		$productId				= $Product->codeToId($productCode);
+        $promoId				= $Promo->codeToId($promoCode);
+		// 查询条件
+		$map 					= [];
+		// 组合条件
+		if( $promoId )			$map[] = ['promo_product.promo_id','=',$promoId];
+		if( $productId )		$map[] = ['product.id','=',$productId];
+		// 查询数据
+		$list					= $Model->query()
+									->join('product','promo_product.product_id','=','product.id')
+									->join('promo','promo.id','=','promo_product.promo_id')
+									->where($map)
+									->orderByDesc('id')
+									->select(['promo_product.*','product.name as product_name','promo.name as promo_name'])
+									->paginate(config('page_num',10));
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			$value['promo_code'] = $Promo->idToCode($value['promo_id']);
+			$value['product_code'] = $Product->idToCode($value['product_id']);
+			// 重组
+			$list[$key]			= $value;
+		}
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list',$list);
+		// 加载模板
+		return 					$this->fetch();
+    }
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add(Request $request,Model $Model,Product $Product,Promo $Promo){
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 接收数据
+			$productCode			= request('product_code','');
+			$promoCode				= request('promo_code','');
+			$data['product_id']		= $Product->codeToId($productCode);
+			$data['promo_id']		= $Promo->codeToId($promoCode);
+			// 如果操作失败
+			if( !$data['product_id'] ) return json_send(['code'=>'error','msg'=>'请填写正确的产品编码']);
+			if( !$data['promo_id'] )    return json_send(['code'=>'error','msg'=>'请填写正确的促销活动编码']);
+			// 查询产品ID是否存在
+			$oldId					= $Model->query()->where([['promo_id','=',$data['promo_id']],['product_id','=',$data['product_id']]])->value('id');
+			// 重复提醒
+			if( $oldId ) 			return json_send(['code'=>'error','msg'=>'产品编码已存在']);
+			// 写入数据表
+			$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']);
+		}
+		// 分配数据
+		$this->assign('crumbs','新增');
+		// 加载模板
+		return						$this->fetch(); 
+	}
+
+	/**
+	 * 修改
+	 * 
+	 * */
+	public function edit(Request $request,Model $Model,Product $Product,Promo $Promo){
+		// 接收参数
+		$id							= request('id',0);
+		// 查询用户
+		$oldData					= $Model->where(['id'=>$id])->first();
+		// 修改
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('edit')->validate();
+			// 接收数据
+			$productCode			= request('product_code','');
+			$promoCode				= request('promo_code','');
+			$data['product_id']		= $Product->codeToId($productCode);
+			$data['promo_id']		= $Promo->codeToId($promoCode);
+			// 如果操作失败
+			if( !$data['product_id'] )  return json_send(['code'=>'error','msg'=>'请填写正确的产品编码']);
+			if( !$data['promo_id'] )    return json_send(['code'=>'error','msg'=>'请填写正确的活动编码']);
+			// 查询产品ID是否存在
+			$oldId					= $Model->query()->where([['promo_id','=',$data['promo_id']],['product_id','=',$data['product_id']]])->value('id');
+			// 重复提醒
+			if( $oldId && $oldId != $id ) return json_send(['code'=>'error','msg'=>'产品编码已存在']);
+			// 写入数据表
+			$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('查无数据');
+		// 产品编码
+		$oldData['product_code'] 	= $Product->idToCode($oldData['product_id']);
+		$oldData['promo_code']  	= $Promo->idToCode($oldData['promo_id']);
+		// 分配数据
+		$this->assign('oldData',$oldData);
+		$this->assign('crumbs','修改');
+		// 加载模板
+		return						$this->fetch();
+	}
+
+	/**
+	 * 修改状态
+	 * 
+	 * */
+	public function set_status(Request $request,Model $Model){
+		// 验证参数
+		$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'=>'']);
+	}
+
+}

+ 32 - 2
app/Http/Controllers/Api/Orders.php

@@ -19,6 +19,8 @@ use App\Models\RegimentRecord;
 use App\Models\ShopCart;
 use Illuminate\Support\Facades\DB;
 use App\Models\WeiBan\Tags as WeiBanTags;
+use App\Models\PromoProduct as PromoProduct;
+use Monolog\Handler\IFTTTHandler;
 
 /**
  * 订单接口
@@ -32,7 +34,7 @@ class Orders extends Api{
 	 * 创建订单						 	/api/orders/create
 	 * 
 	 * */
-	public function create(Request $request,Custom $Custom,City $City,Model $Model,WeiBanTags $WeiBanTags,OrdersAddr $OrdersAddr,OrdersProduct $OrdersProduct,Product $Product,ProductSkus $ProductSkus,CustomCoupon $CustomCoupon,ShopCart $ShopCart,CustomAddr $CustomAddr,CustomScore $CustomScore){
+	public function create(Request $request,Custom $Custom,City $City,Model $Model,WeiBanTags $WeiBanTags,OrdersAddr $OrdersAddr,OrdersProduct $OrdersProduct,Product $Product,ProductSkus $ProductSkus,CustomCoupon $CustomCoupon,ShopCart $ShopCart,CustomAddr $CustomAddr,CustomScore $CustomScore,PromoProduct $PromoProduct){
 		// 接口验签
 		// $this->verify_sign();
 		// 验证参数
@@ -69,7 +71,7 @@ class Orders extends Api{
 		$province						= $City->getOne($pid,'name');
 		// 判断选择的城市名称是不是一致
 		if( $cityName != $addr['contact_city'] ) return json_send(['code'=>'error','msg'=>'收货地址请选择'.$province.'/'.$cityName,'data'=>['error'=>'收货地址需与您所选城市一致']]);
-		// 商品购买数量
+        // 商品购买数量
 		$buyNum							= [];
 		// 循环购买信息
 		foreach ($buyList as $key => $value) {
@@ -167,6 +169,11 @@ class Orders extends Api{
 		$productPrice					= $couponRebate['product_price'];
 		// 获取优惠券赠品信息
 		$rebateProduct					= $couponRebate['rebate_product'];
+        /*活动优惠数据*/
+        $promoList					    = $PromoProduct->getRebatePrice(array_column($buyList,'product_id'),$uid,$productPrice,$cityId,$tags);
+        $promoProductPrice				= $promoList['product_price'];
+        $promoRebateProduct				= $promoList['rebate_product'];
+        $promoReductionTotal			= $promoList['reduction_total'];
 		// 组合订单数据
 		foreach ($orderProduct as $key => $order) {
 			// 判断哪一家的赠品
@@ -183,8 +190,31 @@ class Orders extends Api{
 					$order['product_list'][] = ['is_rebate'=>1,'custom_uid'=>$uid,'business_id'=>$value['business_id'],'product_id'=>$value['product_id'],'buy_num'=>$value['buy_num'],'price_total'=>$value['price_total'],'pay_total'=>$value['pay_total'],'coupon_total'=>$value['coupon_total'],'product_name'=>$value['product_name'],'sku_attr_names'=>$value['sku_attr_names'],'product_thumb'=>$value['product_thumb']];
 				}
 			}
+            // 促销活动判断哪一家的赠品
+            if( isset($promoRebateProduct[$order['business_id']]) ){
+                // 循环赠品
+                foreach ( $promoRebateProduct[$order['business_id']] as $value) {
+                    // 没有对应的产品
+                    if( !isset($productList[$value['product_id']]) )  $productList[$value['product_id']] = ['id'=>$value['id'],'stock'=>$value['stock']];
+                    // 判断库存,如果库存不足,只赠送最后的库存
+                    if( $productList[$value['product_id']]['stock'] <= $value['buy_num'] )  $value['buy_num'] = $productList[$value['product_id']]['stock'];
+                    // 库存扣减
+                    $productList[$value['product_id']]['decr']  = empty($productList[$value['product_id']]['decr']) ? $value['buy_num'] : $productList[$value['product_id']]['decr'] + $value['buy_num'];
+                    // 追加到订单表
+                    $order['product_list'][] = ['is_rebate'=>1,'custom_uid'=>$uid,'business_id'=>$value['business_id'],'product_id'=>$value['product_id'],'buy_num'=>$value['buy_num'],'price_total'=>$value['price_total'],'pay_total'=>$value['pay_total'],'coupon_total'=>$value['coupon_total'],'sku_attr_names'=>$value['sku_attr_names'],'product_name'=>$value['name'],'product_thumb'=>$value['thumb']];
+                }
+            }
 			// 计算总价格
 			foreach ($order['product_list'] as $k=>$product) {
+                //促销活动扣减
+                if (isset($promoProductPrice[$product['product_id']]['promo_rebate_price']) && $promoProductPrice[$product['product_id']]['promo_rebate_price']> 0){
+                    // 总优惠增加
+                    $order['coupon_total']	 = $order['coupon_total']  + $promoProductPrice[$product['product_id']]['promo_rebate_price'];
+                    // 当前商品的优惠折扣计算
+                    $product['coupon_total'] = number_format( $promoProductPrice[$product['product_id']]['rebate_price'] * ($product['price_total'] / $promoProductPrice[$product['product_id']]['price_total']) , 2 , '.' ,'');
+                    // 成交小计
+                    $product['pay_total']	 = $product['pay_total'] -  $product['coupon_total'];
+                }
 				// 商品不存在,不进行扣减
 				if( empty($productPrice[$product['product_id']]['rebate_price']) ) {
 					// 重组

+ 121 - 4
app/Http/Controllers/Api/Product.php

@@ -10,8 +10,12 @@ use App\Models\Product\City as ProductCity;
 use App\Models\Product\Spec as ProductSpec;
 use App\Models\Product\Skus as ProductSkus;
 use App\Models\ProductPhoto;
+use App\Models\Promo;
+use App\Models\PromoProduct;
+use App\Models\PromoRebate;
 use App\Models\RegimentActive;
 use App\Models\Regiment;
+use App\Models\WeiBan\Tags as WeiBanTags;
 
 /**
  * 产品接口
@@ -29,7 +33,7 @@ class Product extends Api{
 	 * @param	int		$limit			每页条数,默认10条
 	 * 
 	 * */
-	public function get_list(Request $request,Model $Model,Custom $Custom,RegimentActive $RegimentActive){
+	public function get_list(Request $request,Model $Model,Custom $Custom,RegimentActive $RegimentActive,WeiBanTags $WeiBanTags){
 		// 接口验签
 		// $this->verify_sign();
         // 验证参数
@@ -62,7 +66,32 @@ class Product extends Api{
 		$data['per_page']			= $Paginator->perPage();
 		$data['last_page']			= $Paginator->lastPage();
 		$data['data']				= $Paginator->items();
-        $time = time();
+        //产品促销活动
+        $productIds                 = array_column($Paginator->items(),'id');
+        $time                       = time();
+        $where                      = [
+                                            ['promo.status','=','0'],
+                                            ['promo.start_time','<=',$time],
+                                            ['promo.end_time','>=',$time],
+                                            ['promo_product.status','=',0],
+                                        ];
+        $promoList                  = PromoProduct::query()
+            ->join('promo','promo.id','=','promo_product.promo_id')
+            ->where($where)
+            ->whereIn('promo_product.product_id',$productIds)
+            ->select('promo.*','promo_product.product_id','promo_product.id as promo_product_id')
+            ->get()
+            ->toArray();
+        if ($promoList){
+            $promoList  =   array_column($promoList,NULL,'product_id');
+        }
+        // 查询用户标签
+        $tags                       =   [];
+        $cityId                     =   '';
+        if ($custom){
+            $tags					= $WeiBanTags->getListByWeibanExtid($custom['weiban_extid']);
+            $cityId					= $custom['city_id'];
+        }
 		// 处理请求
 		foreach ( $data['data'] as $key => $value ) {
 			// 处理数据
@@ -76,6 +105,45 @@ class Product extends Api{
 				$value['regiment_active_id']= $regiment['id'];
 				$value['regiment_title']    = $regiment['automatic'] == 1 ? '多人团' : $regiment['number'].'人团';
 			}
+            if ($promoList && $cityId){
+                if (isset($promoList[$value['id']])){
+                    $promoInfo          =   $promoList[$value['id']];
+                    $promoTitle         =   "满". $promoInfo['std_pay']. "元";
+                    if ($promoInfo['rebate_type'] == 1){
+                        $promoTitle     .=  "减". $promoInfo['rebate']. "元";
+                    }elseif ($promoInfo['rebate_type'] == 2){
+                        $promoTitle     .=  "打". $promoInfo['rebate']. "折";
+                    }elseif ($promoInfo['rebate_type'] == 3){
+                        $rebate 	= (string) PromoRebate::query()->join('product','promo_rebate.product_id','=','product.id')->where([['promo_id','=',$promoInfo['id']]])->value('product.name');
+
+                        $promoTitle     .=  "赠送". $rebate;
+                    }
+                    $promoInfoCity      =   explode(',',$promoInfo['city_ids']);
+                    // 判断是不是可以参与
+                    if (in_array($cityId,$promoInfoCity)){
+                        if( $promoInfo['tag_scope']) {
+                            // 解析数组
+                            $promoInfo['tag_scope']	= explode(',',$promoInfo['tag_scope']);
+                            // 标签范围限定时,默认不能参与
+                            $allowJoin 					= 0;
+                            // 判断标签是不是存在
+                            if ($tags){
+                                foreach ($tags as $v) 	{
+                                    // 标签范围内,允许参加
+                                    if( in_array($v['name'],$promoInfo['tag_scope']) )  $allowJoin = 1;
+                                }
+                                // 在范围
+                                if( $allowJoin ) {
+                                    $value['promo_title']     =   $promoTitle;
+                                }
+                            }
+                        }else{
+                            $value['promo_title']     =   $promoTitle;
+                        }
+                    }
+                }
+
+            }
 			// 重组数据
 			$data['data'][$key]		= $value;
 		}
@@ -90,13 +158,15 @@ class Product extends Api{
 	 * @param	int     $id		        产品id
 	 * 
 	 * */
-	public function get_detail(Request $request,Model $Model,ProductPhoto $ProductPhoto,Business $Business,ProductAttr $ProductAttr,ProductSpec $ProductSpec,ProductSkus $ProductSkus,RegimentActive $RegimentActive,Regiment $Regiment ){
+	public function get_detail(Request $request,Model $Model,ProductPhoto $ProductPhoto,Business $Business,ProductAttr $ProductAttr,ProductSpec $ProductSpec,ProductSkus $ProductSkus,RegimentActive $RegimentActive,Regiment $Regiment,Custom $Custom,WeiBanTags $WeiBanTags,PromoProduct $PromoProduct){
 		// 接口验签
 		// $this->verify_sign();
         // 验证参数
 		$request->scene('get_detail')->validate();
 		// 检查登录
-		// $uid						= $this->checkLogin();
+		$uid						= $this->checkLogin();
+        // 获取客户信息
+        $custom						= $uid ? $Custom->getOne($uid) : [];
 		// 接收参数
 		$id						    = request('id',0);
 		// 显示
@@ -199,6 +269,53 @@ class Product extends Api{
             $data['regiment_active_id'] = null;
             $data['regiment_type']      = 0;
         }
+
+        // 查询用户标签
+        $tags                       =   [];
+        $cityId                     =   '';
+        if ($custom){
+            $tags					= $WeiBanTags->getListByWeibanExtid($custom['weiban_extid']);
+            $cityId					= $custom['city_id'];
+        }
+        //促销活动信息
+        $promoInfo  =   $PromoProduct->getListById($data['id']);
+        if ($promoInfo && $cityId){
+            $promoTitle         =   "满". $promoInfo['std_pay']. "元";
+            if ($promoInfo['rebate_type'] == 1){
+                $promoTitle     .=  "减". $promoInfo['rebate']. "元";
+            }elseif ($promoInfo['rebate_type'] == 2){
+                $promoTitle     .=  "打". $promoInfo['rebate']. "折";
+            }elseif ($promoInfo['rebate_type'] == 3){
+                $rebate 	= (string) PromoRebate::query()->join('product','promo_rebate.product_id','=','product.id')->where([['promo_id','=',$promoInfo['id']]])->value('product.name');
+
+                $promoTitle     .=  "赠送". $rebate;
+            }
+            $promoInfoCity      =   explode(',',$promoInfo['city_ids']);
+            // 判断是不是可以参与
+            if (in_array($cityId,$promoInfoCity)){
+                if( $promoInfo['tag_scope']) {
+                    // 解析数组
+                    $promoInfo['tag_scope']	= explode(',',$promoInfo['tag_scope']);
+                    // 标签范围限定时,默认不能参与
+                    $allowJoin 					= 0;
+                    // 判断标签是不是存在
+                    if ($tags){
+                        foreach ($tags as $v) 	{
+                            // 标签范围内,允许参加
+                            if( in_array($v['name'],$promoInfo['tag_scope']) )  $allowJoin = 1;
+                        }
+                        // 在范围
+                        if( $allowJoin ) {
+                            $data['promo_title']     =   $promoTitle;
+                        }
+                    }
+                }else{
+                    $data['promo_title']     =   $promoTitle;
+                }
+            }
+
+        }
+
 		// 返回结果
 		return						json_send(['code'=>'success','msg'=>'获取成功','data'=>$data]);
 	}

+ 153 - 3
app/Http/Controllers/Api/ShopCart.php

@@ -3,7 +3,11 @@
 use App\Http\Controllers\Api\Api;
 use App\Http\Requests\Api\ShopCart as Request;
 use App\Models\Product\Skus as ProductSkus;
+use App\Models\PromoRebate;
 use App\Models\ShopCart as Model;
+use App\Models\PromoProduct as PromoProduct;
+use App\Models\Custom as Custom;
+use App\Models\WeiBan\Tags as WeiBanTags;
 
 /**
  * 购物车接口
@@ -97,19 +101,30 @@ class ShopCart extends Api{
 	 * @param	int     $id		        购物车id
 	 * 
 	 * */
-	public function get_list(Request $request,Model $Model,ProductSkus $ProductSkus){
+	public function get_list(Request $request,Model $Model,ProductSkus $ProductSkus,PromoProduct $PromoProduct,Custom $Custom,WeiBanTags $WeiBanTags){
 		// 接口验签
 		// $this->verify_sign();
         // 验证参数
 		$request->scene('get_list')->validate();
 		// 检查登录
 		$uid						= $this->checkLogin();
+        // 获取客户信息
+        $custom						= $uid ? $Custom->getOne($uid) : [];
 		// 显示
 		$map						= [['shop_cart.custom_uid','=',$uid]];
 		// 查询
 		$list						= $Model->query()->join('product','shop_cart.product_id','=','product.id')->where($map)->get(['shop_cart.id','shop_cart.checked','shop_cart.product_id','shop_cart.skuid','shop_cart.buy_num','product.stock','product.spec','product.thumb','product.name','product.price','product.market_price','product.status as product_status'])->toArray();
 		// 判断结果
 		$skusList					= $ProductSkus->getListByIds(array_column($list,'skuid'));
+        //查询产品活动
+        $promoList					= $PromoProduct->getListByIds(array_column($list,'product_id'));
+        // 查询用户标签
+        $tags                       =   [];
+        $cityId                     =   '';
+        if ($custom){
+            $tags					= $WeiBanTags->getListByWeibanExtid($custom['weiban_extid']);
+            $cityId					= $custom['city_id'];
+        }
 		// 循环处理数据
 		foreach ($list as $key => $value) {
 			// 如果有sku
@@ -129,6 +144,45 @@ class ShopCart extends Api{
 				// 如果不存在,状态变动
 				if( !$isExist )		$value['product_status'] = 4;
 			}
+            if ($promoList && $cityId){
+                if (isset($promoList[$value['product_id']])){
+                    $promoInfo          =   $promoList[$value['product_id']];
+                    $promoTitle         =   "满". $promoInfo['std_pay']. "元";
+                    if ($promoInfo['rebate_type'] == 1){
+                        $promoTitle     .=  "减". $promoInfo['rebate']. "元";
+                    }elseif ($promoInfo['rebate_type'] == 2){
+                        $promoTitle     .=  "打". $promoInfo['rebate']. "折";
+                    }elseif ($promoInfo['rebate_type'] == 3){
+                        $rebate 	= (string) PromoRebate::query()->join('product','promo_rebate.product_id','=','product.id')->where([['promo_id','=',$promoInfo['id']]])->value('product.name');
+
+                        $promoTitle     .=  "赠送". $rebate;
+                    }
+                    $promoInfoCity      =   explode(',',$promoInfo['city_ids']);
+                    // 判断是不是可以参与
+                    if (in_array($cityId,$promoInfoCity)){
+                        if( $promoInfo['tag_scope']) {
+                            // 解析数组
+                            $promoInfo['tag_scope']	= explode(',',$promoInfo['tag_scope']);
+                            // 标签范围限定时,默认不能参与
+                            $allowJoin 					= 0;
+                            // 判断标签是不是存在
+                            if ($tags){
+                                foreach ($tags as $v) 	{
+                                    // 标签范围内,允许参加
+                                    if( in_array($v['name'],$promoInfo['tag_scope']) )  $allowJoin = 1;
+                                }
+                                // 在范围
+                                if( $allowJoin ) {
+                                    $value['promo_title']     =   $promoTitle;
+                                }
+                            }
+                        }else{
+                            $value['promo_title']     =   $promoTitle;
+                        }
+                    }
+                }
+
+            }
 			// 产品图路径
 			$value['thumb']			= path_compat($value['thumb']);
 			// 库存超出的时候
@@ -148,13 +202,15 @@ class ShopCart extends Api{
 	 * @param	int     $id		        购物车id
 	 * 
 	 * */
-	public function check_list(Request $request,Model $Model,ProductSkus $ProductSkus){
+	public function check_list(Request $request,Model $Model,ProductSkus $ProductSkus,PromoProduct $PromoProduct,Custom $Custom,WeiBanTags $WeiBanTags){
 		// 接口验签
 		// $this->verify_sign();
         // 验证参数
 		$request->scene('check_list')->validate();
 		// 检查登录
 		$uid						= $this->checkLogin();
+        // 获取客户信息
+        $custom						= $uid ? $Custom->getOne($uid) : [];
 		// 接收参数
 		$cartIds					= request('cart_ids','');
 		// 转成数组
@@ -172,6 +228,16 @@ class ShopCart extends Api{
 		$list						= $Model->query()->join('product','shop_cart.product_id','=','product.id')->whereIn('shop_cart.id',$cartIds)->where($map)->get(['shop_cart.id','shop_cart.checked','shop_cart.product_id','shop_cart.skuid','shop_cart.buy_num','product.stock','product.spec','product.thumb','product.name','product.price','product.market_price','product.status as product_status'])->toArray();
 		// 判断结果
 		$skusList					= $ProductSkus->getListByIds(array_column($list,'skuid'));
+        //查询产品活动
+        $promoList					= $PromoProduct->getListByIds(array_column($list,'product_id'));
+        // 查询用户标签
+        $tags                       =   [];
+        $cityId                     =   '';
+        if ($custom){
+            $tags					= $WeiBanTags->getListByWeibanExtid($custom['weiban_extid']);
+            $cityId					= $custom['city_id'];
+        }
+        $promoProductList           =   [];
 		// 循环处理数据
 		foreach ($list as $key => $value) {
 			// 如果有sku
@@ -199,6 +265,48 @@ class ShopCart extends Api{
 				unset($list[$key]);
 				continue;
 			}
+            if ($promoList && $cityId){
+                if (isset($promoList[$value['product_id']])){
+                    $promoInfo          =   $promoList[$value['product_id']];
+                    $promoInfo['price']      =   $value['price'] * $value['buy_num'];
+                    $promoTitle         =   "满". $promoInfo['std_pay']. "元";
+                    if ($promoInfo['rebate_type'] == 1){
+                        $promoTitle     .=  "减". $promoInfo['rebate']. "元";
+                    }elseif ($promoInfo['rebate_type'] == 2){
+                        $promoTitle     .=  "打". $promoInfo['rebate']. "折";
+                    }elseif ($promoInfo['rebate_type'] == 3){
+                        $rebate 	= (string) PromoRebate::query()->join('product','promo_rebate.product_id','=','product.id')->where([['promo_id','=',$promoInfo['id']]])->value('product.name');
+
+                        $promoTitle     .=  "赠送". $rebate;
+                    }
+                    $promoInfoCity      =   explode(',',$promoInfo['city_ids']);
+                    // 判断是不是可以参与
+                    if (in_array($cityId,$promoInfoCity)){
+                        if( $promoInfo['tag_scope']) {
+                            // 解析数组
+                            $promoInfo['tag_scope']	= explode(',',$promoInfo['tag_scope']);
+                            // 标签范围限定时,默认不能参与
+                            $allowJoin 					= 0;
+                            // 判断标签是不是存在
+                            if ($tags){
+                                foreach ($tags as $v) 	{
+                                    // 标签范围内,允许参加
+                                    if( in_array($v['name'],$promoInfo['tag_scope']) )  $allowJoin = 1;
+                                }
+                                // 在范围
+                                if( $allowJoin ) {
+                                    $value['promo_title']     =   $promoTitle;
+                                    $promoProductList[$promoInfo['id']][]    = $promoInfo;
+                                }
+                            }
+                        }else{
+                            $value['promo_title']     =   $promoTitle;
+                            $promoProductList[$promoInfo['id']][]    = $promoInfo;
+                        }
+                    }
+                }
+
+            }
 			// 产品图路径
 			$value['thumb']			= path_compat($value['thumb']);
 			// 库存超出的时候
@@ -206,10 +314,52 @@ class ShopCart extends Api{
 			// 重组
 			$list[$key]				= $value;
 		}
+        $promoRebateIds           =   [];
+        //满折扣
+        $discount       =   0;
+        //满减
+        $reduction      =   0;
+        //计算产品促销活动优惠价格
+        if ($promoProductList){
+            foreach ($promoProductList as $key => $value){
+                $priceSum  =   array_sum(array_column($value,'price'));
+                if ($priceSum >= $value[0]['std_pay']) {
+                    switch ($value[0]['rebate_type']){
+                        case 1:
+                            $reduction   +=  $value[0]['rebate'];
+                            break;
+                        case 2:
+                            $discount   +=  $priceSum - number_format($priceSum * $value[0]['rebate']/10,2);
+                            break;
+                        case 3:
+                            $promoRebateIds[]     =  $key;
+                    }
+                }
+            }
+        }
+        $promoRebateList    =   [];
+        //如果有赠品
+        if ($promoRebateIds){
+            $promoRebateList    =   PromoRebate::query()
+                ->join('product','promo_rebate.product_id','=','product.id')
+                ->where('status','=',0)
+                ->whereIn('promo_id',$promoRebateIds)
+                ->select(['promo_rebate.id as promo_rebate_id','promo_rebate.rebate_num as buy_num','product.stock','product.spec','product.thumb','product.name','product.price','product.market_price','product.status as product_status'])
+                ->get()
+                ->toArray();
+            if ($promoRebateList){
+                foreach ($promoRebateList as &$value){
+                    // 产品图路径
+                    $value['thumb']			= path_compat($value['thumb']);
+                    // 库存超出的时候
+                    if($value['buy_num'] > $value['stock'] && $value['stock'] > 0) $value['buy_num'] = $value['stock'];
+                }
+            }
+        }
 		// 重组数组
 		$list						= array_values($list);
 		// 返回结果
-		return						json_send(['code'=>'success','msg'=>'获取成功','data'=>$list]);
+		return						json_send(['code'=>'success','msg'=>'获取成功','data'=>$list,'discount'=>$discount,'reduction'=>$reduction,'promoRebateList'=>$promoRebateList]);
 	}
 
 }

+ 54 - 0
app/Http/Requests/Admin/Promo.php

@@ -0,0 +1,54 @@
+<?php namespace App\Http\Requests\Admin;
+
+use App\Http\Requests\BaseRequest;
+/**
+ * 入库验证器
+ * 
+ */
+class Promo extends BaseRequest
+{
+    /**
+     * 获取应用于请求的规则
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        // 编辑时排除ID
+        // 返回结果
+        return      [
+            // 有时候我们希望某个字段在第一次验证失败后就停止运行验证规则,只需要将 bail 添加到规则中:
+            // 验证字段,验证规则,提示信息
+            'id'            => 'required|integer|gt:0',
+            'product_code'  => 'required|size:13',
+            'status'        => 'required|integer|gte:0',
+        ];
+    }
+
+    // 场景列表
+    protected   $scenes         = [
+        'add'                   => [],
+        'edit'                  => ['id'],
+        'set_status'            => ['id','status'],
+	];
+
+    /**
+     * 获取已定义验证规则的错误消息
+     *
+     * @return array
+     */
+    public function messages()
+    {
+        return [
+            'id.required'   		    => 'ID未知',
+            'id.integer'   		        => 'ID格式错误',
+            'id.gt'   		            => 'ID格式错误',
+            'product_code.required'   	=> '产品编码必填',
+            'product_code.size'   	=> '请核对编码格式',
+            'status.required'   		=> '请选择状态',
+            'status.integer'   		    => '状态格式错误',
+            'status.gte'   		        => '状态格式错误',
+        ];
+    }
+
+}

+ 52 - 0
app/Http/Requests/Admin/PromoProduct.php

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

+ 118 - 0
app/Models/Promo.php

@@ -0,0 +1,118 @@
+<?php namespace App\Models;
+
+use App\Facades\Servers\Redis\Redis;
+use App\Facades\Servers\Redis\RedisLock;
+use App\Models\Traits\Coupon\GrantType;
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Carbon;
+
+/**
+ * 优惠券模型
+ * 
+ */
+class Promo extends Model
+{
+    use HasFactory,GrantType;
+
+    // 与模型关联的表名
+    protected $table = 'promo';
+    // 是否主动维护时间戳
+    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);
+        // 返回结果
+        return                              $result;
+    }
+
+    /**
+     * 编码转id
+     * 
+     * @param  string $code 编码
+     * 
+     */
+    public function codeToId($code){
+        return intval(str_ireplace('klcx','',$code));
+     }
+ 
+    /**
+     * id转编码
+     * 
+     * @param  int  $id 编码
+     * 
+     */
+    public function idToCode($id){
+        return 'klcx'. str_pad($id, 9, '0', STR_PAD_LEFT);
+    }
+
+
+    /**
+     * 优惠券过期时间
+     * 
+     * @param  int  $expTime 过期时间
+     * 
+     */
+    public function getExpTime($expTime){
+        // 如果存在过期时间,且小于1000,表示这是一个领取后n天的,按天数返回
+        if ( $expTime && $expTime < 1000 ) return Carbon::now()->addDays($expTime)->endOfDay()->getTimestamp();
+        // 返回时间戳
+        return                          $expTime;
+    }
+
+    /**
+     * 过期状态设置
+     * 
+     */
+    public function setStatusByExpire(){
+        // 上锁
+        if(RedisLock::lock('promo::set::status::by::expire',1,30)){
+            // 修改
+            $result                 = $this->query()->where([['status','=',0],['end_time','>',0],['end_time','<=',time()]])->update(['status'=>3,'update_time'=>time()]);
+            // 不管成功失败,都解锁
+            RedisLock::unlock('promo::set::status::by::expire',1);
+            // 返回结果
+            return                   $result;
+        }
+    }
+
+    /**
+     * 获取优惠券信息
+     * 
+     */
+    public function getOne($id,$field=''){
+        // 返回结果
+        $result                      = $this->query()->find($id);
+        // 返回结果
+        $result                      = $result ? $result->toArray() : [];
+        // 返回值
+        return                       empty($field) ? $result : ( isset($result[$field]) ? $result[$field] : null);
+    }
+
+}

+ 208 - 0
app/Models/PromoProduct.php

@@ -0,0 +1,208 @@
+<?php namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * 产品促销活动商品范围模型
+ * 
+ */
+class PromoProduct extends Model
+{
+    use HasFactory;
+
+    // 与模型关联的表名
+    protected $table = 'promo_product';
+    // 是否主动维护时间戳
+    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);
+        // 返回结果
+        return                              $result;
+    }
+
+    /**
+     * 查询多个优惠券的商品范围列表
+     * 
+     * @param   array  $couponIds  适用产品的列表
+     * 
+     */
+    public function getProductList($couponIds)
+    {
+        // 写入数据表
+        $result						        = $this->query()->whereIn('coupon_id',$couponIds)->get(['coupon_id','product_id'])->toArray();
+        // 返回结果
+        return                              $result;
+    }
+
+
+    /**
+     * 通过产品ids查询活动列表
+     *
+     */
+    public function getListByIds($productIds)
+    {
+        $time                       = time();
+        $where                      = [
+            ['promo.status','=','0'],
+            ['promo.start_time','<=',$time],
+            ['promo.end_time','>=',$time],
+            ['promo_product.status','=',0],
+        ];
+        $data                  = $this->query()
+            ->join('promo','promo.id','=','promo_product.promo_id')
+            ->where($where)
+            ->whereIn('promo_product.product_id',$productIds)
+            ->select('promo.*','promo_product.product_id','promo_product.id as promo_product_id')
+            ->get()
+            ->toArray();
+        // 列表
+        $list                   = [];
+        // 循环处理
+        foreach ($data as $value) {
+            // 重组数据
+            $list[$value['product_id']]= $value;
+        }
+        // 返回结果
+        return                  $list;
+    }
+    /**
+     * 通过产品id查询活动
+     *
+     */
+    public function getListById($productId)
+    {
+        $time                       = time();
+        $where                      = [
+            ['promo.status','=','0'],
+            ['promo.start_time','<=',$time],
+            ['promo.end_time','>=',$time],
+            ['promo_product.status','=',0],
+            ['promo_product.product_id','=',$productId],
+        ];
+        $data                  = $this->query()
+            ->join('promo','promo.id','=','promo_product.promo_id')
+            ->where($where)
+            ->select('promo.*','promo_product.product_id','promo_product.id as promo_product_id')
+            ->first()
+            ->toArray();
+        // 返回结果
+        return                  $data;
+    }
+
+    /**
+     * 获取优惠券扣减金额
+     *
+     */
+    public function getRebatePrice($productIds,$uid,$productPrice,$cityId,$tags){
+        // 如果有产品
+        if( !$productIds )			return ['is_used'=>0,'product_price'=>$productPrice,'rebate_product'=>[]];
+        // 获取产品活动
+        $promoList							= $this->getListByIds($productIds);
+        $promoProductList   =   [];
+        foreach ($promoList as $promoInfo) {
+            $promoInfoCity = explode(',', $promoInfo['city_ids']);
+            $promoInfo['price_total']      =   $productPrice[$promoInfo['product_id']]['price_total'];
+            // 判断是不是可以参与
+            if (in_array($cityId, $promoInfoCity)) {
+                if ($promoInfo['tag_scope']) {
+                    // 解析数组
+                    $promoInfo['tag_scope'] = explode(',', $promoInfo['tag_scope']);
+                    // 标签范围限定时,默认不能参与
+                    $allowJoin = 0;
+                    // 判断标签是不是存在
+                    if ($tags) {
+                        foreach ($tags as $v) {
+                            // 标签范围内,允许参加
+                            if (in_array($v['name'], $promoInfo['tag_scope'])) $allowJoin = 1;
+                        }
+                        // 在范围
+                        if ($allowJoin) {
+                            $promoProductList[$promoInfo['id']][] = $promoInfo;
+                        }
+                    }
+                } else {
+                    $promoProductList[$promoInfo['id']][] = $promoInfo;
+                }
+            }
+        }
+        if( !$promoProductList )			return ['is_used'=>0,'product_price'=>$productPrice,'rebate_product'=>[]];
+        $reductionTotal =   0;
+        $promoRebateIds =   [];
+        foreach ($promoProductList as $key => $value){
+            $reduction  =   0;
+            $priceSum   =   array_sum(array_column($value,'price_total'));
+            if ($priceSum >= $value[0]['std_pay']) {
+                switch ($value[0]['rebate_type']){
+                    case 1:
+                        $reduction        =  $value[0]['rebate'];
+                        $reductionTotal   +=  $value[0]['rebate'];
+                        break;
+                    case 2:
+                        $reduction   =  $priceSum - number_format($priceSum * $value[0]['rebate']/10,2);
+                        $reductionTotal    +=  $priceSum - number_format($priceSum * $value[0]['rebate']/10,2);
+                        break;
+                    case 3:
+                        $promoRebateIds[]     =  $key;
+                }
+            }
+            if ($reduction){
+                foreach ($value as $k=>$v){
+                    // 优惠价格 = 价格占总价的比例 * 优惠的总价
+                    $productPrice[$v['product_id']]['promo_rebate_price']          = number_format( $reduction * ($productPrice[$v['product_id']]['price_total'] / $reduction) , 2 , '.' ,'');
+                }
+            }
+        }
+        //如果有赠品
+        $list       =   [];
+        if ($promoRebateIds){
+            $promoRebateList    =   PromoRebate::query()
+                ->join('product','promo_rebate.product_id','=','product.id')
+                ->where('status','=',0)
+                ->whereIn('promo_id',$promoRebateIds)
+                ->select(['promo_rebate.id as promo_rebate_id','promo_rebate.rebate_num as buy_num','product.id as product_id','product.stock','product.business_id','product.spec','product.thumb','product.name','product.price','product.market_price','product.status as product_status','product.spec as sku_attr_names'])
+                ->get()
+                ->toArray();
+            if ($promoRebateList){
+                foreach ($promoRebateList as $value){
+                    // 库存超出的时候
+                    if($value['buy_num'] > $value['stock'] && $value['stock'] > 0) $value['buy_num'] = $value['stock'];
+                    $value['price_total']   =   $value['price'] * $value['buy_num'];
+                    $value['pay_total']   = 0;
+                    $value['coupon_total']= 0;
+                    $list[$value['business_id']][] = $value;
+                }
+            }
+        }
+        // 返回扣减结果
+        return                              ['product_price'=>$productPrice,'rebate_product'=>$list,'reduction_total'=>$reductionTotal];
+    }
+
+}

+ 78 - 0
app/Models/PromoRebate.php

@@ -0,0 +1,78 @@
+<?php namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * 优惠券赠品模型
+ * 
+ */
+class PromoRebate extends Model
+{
+    use HasFactory;
+
+    // 与模型关联的表名
+    protected $table = 'promo_rebate';
+    // 是否主动维护时间戳
+    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);
+        // 返回结果
+        return                              $result;
+    }
+
+
+    /**
+     * 优惠券赠品列表
+     * 
+     */
+    public function getProductByCouponId($couponId)
+    {
+        // 写入数据表
+        $result						        = $this->query()->where([['promo_id','=',$couponId]])->get(['product_id','rebate_num'])->toArray();
+        // 返回结果
+        return                              $result;
+    }
+
+    /**
+     * 查询赠品列表
+     * 
+     * @param   array  $couponIds  优惠券列表
+     * 
+     */
+    public function getRebatesByCouponIds($couponIds)
+    {
+        // 写入数据表
+        $result						        = $this->query()->join('product','promo_rebate.product_id','=','product.id')->whereIn('promo_id',$couponIds)->get(['promo_rebate.coupon_id','promo_rebate.product_id','promo_rebate.rebate_num','product.name as product_name','product.spec as product_spec'])->toArray();
+        // 返回结果
+        return                              $result;
+    }
+
+}

+ 98 - 0
resources/views/admin/promo/add.blade.php

@@ -0,0 +1,98 @@
+@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" enctype="multipart/form-data">
+	<div class="form-group col-sm-3">
+		<label class="control-label">活动名称 <span class="text-red">*</span></label>
+		<input class="form-control" required="required" type="text" placeholder="活动名称" maxlength="20" name="name" value="" />
+	</div>
+	<div class="form-group col-sm-3">
+		<label class="control-label">活动类型 <span class="text-red">*</span></label>
+		<select class="form-control" required="required" name="rebate_type" id="rebate_type">
+			<option value="1" >满减</option>
+			<option value="2" >折扣</option>
+			<option value="3" >满赠</option>
+		</select>
+	</div>
+	<div class="form-group col-sm-6">
+		<label class="control-label">优惠力度 <span class="text-red">*</span></label>
+		<div class="form-group col-sm-12">
+			<label class="control-label"> </label>
+			<div class="form-group col-sm-6">
+				<input  required="required" class="form-control" type="text" placeholder="满多少元" name="std_pay" value="" />
+			</div>
+			<div class="form-group col-sm-6">
+				<input  required="required" class="form-control" id="rebate" type="text" placeholder="减多少元" name="rebate" value="" />
+			</div>
+		</div>
+	</div>
+	<div class="form-group col-sm-2">
+		<label class="control-label">商品范围</label>
+		<select name="type_id" class="form-control" >
+			{{--<option value="2" >全部商品</option>--}}
+			<option value="1" >指定商品</option>
+		</select>
+	</div>
+	<div class="form-group col-sm-4">
+		<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-4">
+		<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-6">
+		<label class="control-label">活动时间 <span class="text-red">*</span></label>
+		<div class="form-group col-sm-12">
+			<div class="form-group col-sm-6">
+				<label class="control-label">开始时间 <span class="text-red">*</span></label>
+				<input  required="required" class="form-control" type="datetime-local" placeholder="开始时间" name="start_time" value="" />
+			</div>
+			<div class="form-group col-sm-6">
+				<label class="control-label">结束时间 <span class="text-red">*</span></label>
+				<input  required="required" class="form-control" type="datetime-local" placeholder="结束时间" name="end_time" value="" />
+			</div>
+		</div>
+	</div>
+	<div class="form-group col-sm-12">
+		@csrf
+		<input id="send" type="submit" value="提交" class="btn btn-primary btn-block" />
+	</div>
+</form>
+@endsection
+
+@section('javascript')
+<script>
+	$(function(){
+		// 类型变更
+		$('#rebate_type').change(function(){
+			// 获取值
+			var rebateType = $(this).val();
+			// 如果是满减
+			if( rebateType == 1 ) $('#rebate').attr('placeholder','减多少元');
+			// 如果是折扣
+			if( rebateType == 2 ) $('#rebate').attr('placeholder','打几折');
+			// 如果是赠品
+			if( rebateType == 3 ) $('#rebate').attr('placeholder','产品编码');
+		})
+	})
+</script>
+@endsection

+ 98 - 0
resources/views/admin/promo/edit.blade.php

@@ -0,0 +1,98 @@
+@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-3">
+		<label class="control-label">活动名称 <span class="text-red">*</span></label>
+		<input class="form-control" required="required" type="text" placeholder="优惠券名称" maxlength="20" name="name" value="{{$oldData['name']}}" />
+	</div>
+	<div class="form-group col-sm-3">
+		<label class="control-label">活动类型 <span class="text-red">*</span></label>
+		<select class="form-control" required="required" name="rebate_type" id="rebate_type">
+			<option value="1" @if ( $oldData['rebate_type'] == '1' ) selected="selected" @endif >满减券</option>
+			<option value="2" @if ( $oldData['rebate_type'] == '2' ) selected="selected" @endif >折扣券</option>
+			<option value="3" @if ( $oldData['rebate_type'] == '3' ) selected="selected" @endif >赠品券</option>
+		</select>
+	</div>
+	<div class="form-group col-sm-6">
+		<label class="control-label">优惠力度 <span class="text-red">*</span></label>
+		<div class="form-group col-sm-12">
+			<label class="control-label"> </label>
+			<div class="form-group col-sm-6">
+				<input  required="required" class="form-control" type="text" placeholder="满多少元" name="std_pay" value="{{$oldData['std_pay']}}" />
+			</div>
+			<div class="form-group col-sm-6">
+				<input  required="required" class="form-control" id="rebate" type="text" placeholder="{{$oldData['rebate_type']==1?'减多少元':($oldData['rebate_type']==2?'打几折':'输入产品编码')}}" name="rebate" value="{{$oldData['rebate']}}" />
+			</div>
+		</div>
+	</div>
+	<div class="form-group col-sm-2">
+		<label class="control-label">商品范围</label>
+		<select name="type_id" class="form-control" >
+			{{--<option value="2" @if ( $oldData['type_id'] == '2' ) selected="selected" @endif>全部商品</option>--}}
+			<option value="1" @if ( $oldData['type_id'] == '1' ) selected="selected" @endif>指定商品</option>
+		</select>
+	</div>
+	<div class="form-group col-sm-4">
+		<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="selected" @endif >{{$city['name']}}</option>
+				@endforeach
+			</optgroup>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col-sm-4">
+		<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-6">
+		<label class="control-label">活动时间 <span class="text-red">*</span></label>
+		<div class="form-group col-sm-12">
+			<div class="form-group col-sm-6">
+				<label class="control-label">开始时间 <span class="text-red">*</span></label>
+				<input  required="required" class="form-control" type="datetime-local" placeholder="开始时间" name="start_time" value="{{date('Y-m-d H:i',$oldData['start_time'])}}" />
+			</div>
+			<div class="form-group col-sm-6">
+				<label class="control-label">结束时间 <span class="text-red">*</span></label>
+				<input  required="required" class="form-control" type="datetime-local" placeholder="结束时间" name="end_time" value="{{date('Y-m-d H:i',$oldData['end_time'])}}" />
+			</div>
+		</div>
+	</div>
+	<div class="form-group col-sm-12">
+		@csrf
+		<input type="hidden" name="id" value="{{$oldData['id']}}" />
+		<input id="send" type="submit" value="提交" class="btn btn-primary btn-block" />
+	</div>
+</form>
+@endsection
+@section('javascript')
+<script>
+	$(function(){
+		// 类型变更
+		$('#rebate_type').change(function(){
+			// 获取值
+			var rebateType = $(this).val();
+			// 如果是满减
+			if( rebateType == 1 ) $('#rebate').attr('placeholder','减多少元');
+			// 如果是折扣
+			if( rebateType == 2 ) $('#rebate').attr('placeholder','打几折');
+			// 如果是赠品
+			if( rebateType == 3 ) $('#rebate').attr('placeholder','产品编码').val('');
+		})
+	})
+</script>
+@endsection

+ 147 - 0
resources/views/admin/promo/index.blade.php

@@ -0,0 +1,147 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+<div class="page-header">
+	@if( check_auth('admin/promo/add') )
+	<a href="{{url('admin/promo/add')}}" class="btn btn-primary">新增</a>
+	@endif
+</div>
+<form action="" method="get" class="form-horizontal form-line">
+	<div class="form-group col col-md-2" style="margin-right: 2px;">
+		<input type="text" class="form-control" name="promo_code" value="{{request('promo_code','')}}" placeholder="请输入活动编码查询" />
+	</div>
+	<div class="form-group col col-md-2" style="margin-right: 2px;">
+		<input type="text" class="form-control" name="promo_name" value="{{request('promo_name','')}}" placeholder="请输入活动名称查询" />
+	</div>
+	<div class="form-group col col-md-1" style="margin-right: 2px;">
+		<select name="status" class="form-control">
+			<option value="" >状态</option>
+			<option value="0" @if (request('status') === '0' ) selected="selected" @endif >启用</option>
+			<option value="2" @if (request('status') === '2' ) selected="selected" @endif >停用</option>
+			<option value="3" @if (request('status') === '3' ) selected="selected" @endif >结束</option>
+			<option value="4" @if (request('status') === '4' ) selected="selected" @endif >作废</option>
+		</select>
+	</div>
+	<div class="form-group col col-md-1" style="margin-right: 2px;">
+		<select name="rebate_type" class="form-control">
+			<option value="0" >优惠券类型</option>
+			<option value="1" @if (request('rebate_type') == '1' ) selected="selected" @endif >满减</option>
+			<option value="2" @if (request('rebate_type') == '2' ) selected="selected" @endif >折扣</option>
+			<option value="3" @if (request('rebate_type') == '3' ) selected="selected" @endif >赠品</option>
+		</select>
+	</div>
+	<div class="form-group col col-md-1" style="margin-right: 2px;">
+		<input type="text" class="form-control" name="start_time" value="{{request('start_time','')}}" placeholder="请输入开始时间查询" />
+	</div>
+	<div class="form-group col col-md-1" style="margin-right: 2px;">
+		<input type="text" class="form-control" name="end_time" value="{{request('end_time','')}}" placeholder="请输入结束时间查询" />
+	</div>
+	<input type="submit" class="btn btn-sm btn-primary" value="查询"/>
+	<a href="{{url('admin/coupon/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>促销活动编码</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>
+						<td> {{$a['promo_code']}}</td>
+						<td> {{$a['name']}}</td>
+						<td>
+							@if ($a['rebate_type'] == 1) 满减 @endif
+							@if ($a['rebate_type'] == 2) 折扣 @endif
+							@if ($a['rebate_type'] == 3) 满赠 @endif
+						</td>
+						<td>
+							满 {{$a['std_pay']}} 元
+							@if ($a['rebate_type'] == 1) 
+								减 {{$a['rebate']}} 元
+							@endif
+							@if ($a['rebate_type'] == 2) 
+								打 {{$a['rebate']}} 折
+							@endif
+							@if ($a['rebate_type'] == 3) 
+								赠送 {{$a['rebate']}}
+							@endif
+						</td>
+						<td> {{$a['city_ids']}}</td>
+						<td> {{$a['tag_scope']}}</td>
+						<td>
+							@if ( $a['type_id'] == 1 )
+								<a href="{{url('admin/promo_product/index?'.http_build_query(['promo_code'=>$a['promo_code']]))}}">指定商品</a>
+							@else
+								全部商品
+							@endif
+						</td>
+						<td> 
+							@if ($a['status'] == 0) 
+
+								@if ( $a['start_time']  > time() ) 
+									待开始
+								@else
+									进行中
+								@endif
+							@endif
+							@if ($a['status'] == 2) 停用 @endif
+							@if ($a['status'] == 3) 结束 @endif
+							@if ($a['status'] == 4) 作废 @endif
+						</td>
+						<td> {{date('Y/m/d H:i',$a['start_time'])}} ~ {{date('Y/m/d H:i:s',$a['end_time'])}}</td>
+						<td> {{date('Y/m/d H:i',$a['update_time'])}}</td>
+						<td>
+							@if( check_auth('admin/promo/edit') )
+							<a class="btn btn-sm btn-warning" href="{{url('admin/promo/edit?'.http_build_query(['id'=>$a['id']]))}}" title="查看">
+								编辑
+							</a>
+							@endif
+							@if( check_auth('admin/promo/set_status') )
+								@if ( $a['status'] == 2)
+									<a class="delete btn btn-sm btn-success" data-url="{{url('admin/promo/set_status?'.http_build_query(['id'=>$a['id'],'status'=>'0']))}}">
+										启用
+									</a>
+								@endif
+								@if( $a['status'] == 0)
+									<a class="delete btn btn-sm btn-danger" data-url="{{url('admin/promo/set_status?'.http_build_query(['id'=>$a['id'],'status'=>'2']))}}">
+										停用
+									</a>
+								@endif
+								@if ( $a['status'] < 3 )
+								<a class="delete btn btn-sm btn-danger" data-url="{{url('admin/promo/set_status?'.http_build_query(['id'=>$a['id'],'status'=>'4']))}}">
+									作废
+								</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

+ 20 - 0
resources/views/admin/promo_product/add.blade.php

@@ -0,0 +1,20 @@
+@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-12">
+		<label class="control-label">促销活动编码</label>
+		<input class="form-control" required="required" type="text" placeholder="优惠券编码" name="promo_code" value="{{request('promo_code','')}}" />
+	</div>
+	<div class="form-group col-sm-12">
+		<label class="control-label">产品编码</label>
+		<input class="form-control" required="required" type="text" placeholder="产品编码" name="product_code" value="" />
+	</div>
+	<div class="form-group col-sm-12">
+		@csrf
+		<input id="send" type="submit" value="提交" class="btn btn-primary btn-block" />
+	</div>
+</form>
+@endsection

+ 21 - 0
resources/views/admin/promo_product/edit.blade.php

@@ -0,0 +1,21 @@
+@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-12">
+		<label class="control-label">优惠券编码</label>
+		<input class="form-control" required="required" type="text" placeholder="促销活动编码" name="promo_code" value="{{$oldData['promo_code']}}" />
+	</div>
+	<div class="form-group col-sm-12">
+		<label class="control-label">产品编码</label>
+		<input class="form-control" required="required" type="text" placeholder="产品编码" name="product_code" value="{{$oldData['product_code']}}" />
+	</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

+ 77 - 0
resources/views/admin/promo_product/index.blade.php

@@ -0,0 +1,77 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+
+@if(check_auth('admin/promo_product/add'))
+	<div class="page-header">
+		<a href="{{url('admin/promo_product/add?'.http_build_query(['promo_code'=>request('promo_code','')]))}}" 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="promo_code" value="{{request('promo_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="product_code" value="{{request('product_code','')}}" placeholder="请输入产品编码查询" />
+	</div>
+	<input type="submit" class="btn btn-sm btn-primary" value="查询"/>
+	<a href="{{url('admin/promo_product/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>									
+					</tr>
+				</thead>
+				
+				<tbody>
+						@foreach ($list as $a)
+						<tr>
+							<th>{{$a['id']}}</th>
+							<td>{{$a['promo_code']}}</td>
+							<td>{{$a['promo_name']}}</td>
+							<td>{{$a['product_code']}}</td>
+							<td>{{$a['product_name']}}</td>
+							<td>{{$a['status']?'停用':'启用'}}</td>
+							<td> {{date('Y/m/d H:i:s',$a['update_time'])}}</td>
+							<td>
+								@if(check_auth('admin/promo_product/edit'))
+								<a href="{{url('admin/promo_product/edit?'.http_build_query(['id'=>$a['id']]))}}" class="btn btn-sm btn-warning" >编辑</a>
+								@endif
+								@if(check_auth('admin/promo_product/set_status'))
+									@if($a['status'])
+									<a data-url="{{url('admin/promo_product/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/promo_product/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

+ 19 - 0
routes/web.php

@@ -479,6 +479,25 @@ Route::middleware('admin')->prefix('admin')->group(function(){
     // 状态
     Route::any('share_message/set_status',[App\Http\Controllers\Admin\ShareMessage::class,'set_status']);
 
+    /* 产品促销活动 */
+    //活动列表
+    Route::any('promo/index',[App\Http\Controllers\Admin\Promo::class,'index']);
+    // 新增
+    Route::any('promo/add',[App\Http\Controllers\Admin\Promo::class,'add']);
+    // 编辑
+    Route::any('promo/edit',[App\Http\Controllers\Admin\Promo::class,'edit']);
+    // 状态
+    Route::any('promo/set_status',[App\Http\Controllers\Admin\Promo::class,'set_status']);
+
+    /* 产品促销活动-商品范围 */
+    // 列表
+    Route::any('promo_product/index',[App\Http\Controllers\Admin\PromoProduct::class,'index']);
+    // 新增
+    Route::any('promo_product/add',[App\Http\Controllers\Admin\PromoProduct::class,'add']);
+    // 编辑
+    Route::any('promo_product/edit',[App\Http\Controllers\Admin\PromoProduct::class,'edit']);
+    // 状态
+    Route::any('promo_product/set_status',[App\Http\Controllers\Admin\PromoProduct::class,'set_status']);
 
 
 });