diff --git a/application/core/behavior/ApiAuthBehavior.php b/application/core/behavior/ApiAuthBehavior.php new file mode 100644 index 00000000..7f186de5 --- /dev/null +++ b/application/core/behavior/ApiAuthBehavior.php @@ -0,0 +1,103 @@ +request=Request::instance(); + //开启路由 + $hash = $this->request->routeInfo(); + if(Config::get('url_route_on') && isset($hash['rule'][1])){ + $hash=$hash['rule'][1]; + }else{ + //未开启路由或者开启路由并没有使用路由 + $hash=UtilService::getCurrentController($this->request); + } + //检测访问接口是否存在,并读取接口详细信息 + if(Cache::has(ApiLogs::AB_API_INFO . $hash)){ + $apiInfo=Cache::get(ApiLogs::AB_API_INFO.$hash); + }else { + $apiInfo = ApiMenus::getHash(['hash' => $hash]); + if (!$apiInfo) return JsonService::returnData(ReturnCode::DB_READ_ERROR, '获取接口配置数据失败!'); + Cache::set(ApiLogs::AB_API_INFO.$hash,$apiInfo,ApiLogs::EXPIRE); + } + //是否验证accessToken 是测试则不验证 + if ($apiInfo['access_token'] && !$apiInfo['is_test']) if($accessRes = $this->checkAccessToken()) return $accessRes; + //是否为测试模式 + if (!$apiInfo['is_test']) if($versionRes = $this->checkVersion()) return $versionRes; + //验证用户token信息 + $loginRes = $this->checkLogin($apiInfo['need_login']); + if ($loginRes) return $loginRes; + } + + /* + * 验证access_token不存在则返回错误信息 + * @return array || boolean + * */ + public function checkAccessToken() + { + if($this->request===null) $this->request=Request::instance(); + $access_token = $this->request->header(ApiLogs::ACCESS_TOKEN,''); + if($access_token==='') return JsonService::returnData(ReturnCode::ACCESS_TOKEN_TIMEOUT, '缺少参数access-token!'); + if(!Cache::has(ApiLogs::ACCESS_TOKEN_PREFIX.$access_token)) return JsonService::returnData(ReturnCode::ACCESS_TOKEN_TIMEOUT,'access-token已失效!'); + //执行更多验证信息 + + return false; + } + + /* + * 验证Api参数版本检测 + * @return array || boolean + * */ + public function checkVersion() + { + if($this->request===null) $this->request=Request::instance(); + $version = $this->request->header(ApiLogs::API_VERSION,''); + if($version==='') return JsonService::returnData(ReturnCode::EMPTY_PARAMS,'缺少API版本号!'); + if($version != Config::get('ebApi.API_VERSION')) return JsonService::returnData(ReturnCode::VERSION_INVALID,'API版本号与系统版本号不匹配'); + return false; + } + + /* + * 验证用户token信息 + * @param number $needLogin 是否验证用户token + * */ + public function checkLogin($needLogin) + { + if($this->request===null) $this->request=Request::instance(); + $userToken = $this->request->header(ApiLogs::USER_TOKEN, ''); + if(!$userToken && !$needLogin) return JsonService::returnData(ReturnCode::ERROR,'请传入token验证您的身份信息'); + //验证token + $Tokencheck=TokenService::checkToken($userToken,$needLogin); + if($Tokencheck===true){ + return ['uid'=>0]; + }else if(is_array($Tokencheck)){ + list($uid)=$Tokencheck; + $userInfo = User::get($uid); + }else return JsonService::returnData(ReturnCode::USER_TOKEN_ERROR,'没有获取到用户信息,请传入token验证您的身份信息'); + if((!$userInfo || !isset($userInfo)) && !$needLogin) return JsonService::returnData(ReturnCode::ERROR,'用户信息获取失败,没有这样的用户!'); + if(isset($userInfo->status) && !$userInfo->status) return JsonService::returnData(ReturnCode::USER_STATUS_ERROR,'您已被禁止登录'); + } + +} \ No newline at end of file diff --git a/application/core/behavior/ApiPermissionBehavior.php b/application/core/behavior/ApiPermissionBehavior.php new file mode 100644 index 00000000..8f2ca1b7 --- /dev/null +++ b/application/core/behavior/ApiPermissionBehavior.php @@ -0,0 +1,23 @@ + + * Date: 2019/4/8 5:41 PM + */ + +namespace app\core\behavior; + +use app\ebapi\model\store\StoreOrder; +use app\ebapi\model\user\User; +use app\ebapi\model\user\WechatUser; +use app\ebapi\model\user\UserAddress; +use app\admin\model\order\StoreOrder as StoreOrderAdminModel; +use app\core\util\SystemConfigService; +use app\core\util\WechatTemplateService; + +class GoodsBehavior +{ + /** + * 取消点赞产品后 + * @param $productId + * @param $uid + */ + public static function storeProductUnLikeAfter($productId, $uid) + { + + } + + /** + * 点赞产品后 + * @param $product + * @param $uid + */ + public static function storeProductLikeAfter($product, $uid) + { + + } + /** + * 用户确认收货 + * @param $order + * @param $uid + */ + public static function storeProductOrderUserTakeDelivery($order, $uid) + { + $res1 = StoreOrder::gainUserIntegral($order); + $res2 = User::backOrderBrokerage($order); + StoreOrder::orderTakeAfter($order); + $giveCouponMinPrice = SystemConfigService::get('store_give_con_min_price'); + if($order['total_price'] >= $giveCouponMinPrice) WechatUser::userTakeOrderGiveCoupon($uid); + $res = $res1 && $res2; + if(!$res) exception('收货失败!'); + } + /** + * 订单创建成功后 + * @param $oid + */ + public static function storeProductOrderCreate($order,$group) + { + UserAddress::be(['is_default'=>1,'uid'=>$order['uid']]) || UserAddress::setDefaultAddress($group['addressId'],$order['uid']); + } + + /** + * 修改发货状态 为送货 + * @param $data + * $data array 送货方式 送货人姓名 送货人电话 + * @param $oid + * $oid string store_order表中的id + */ +// public static function storeProductOrderDeliveryAfter($data,$oid){ +// StoreOrder::orderPostageAfter($data,$oid); +// } + + /** + * 修改发货状态 为发货 + * @param $data + * $data array 发货方式 送货人姓名 送货人电话 + * @param $oid + * $oid string store_order表中的id + */ +// public static function storeProductOrderDeliveryGoodsAfter($data,$oid){ +// StoreOrder::orderPostageAfter($data,$oid); +// RoutineTemplate::sendOrderGoods($oid,$data); +// } + + /** + * 修改状态 为已收货 + * @param $data + * $data array status 状态为 已收货 + * @param $oid + * $oid string store_order表中的id + */ + public static function storeProductOrderTakeDeliveryAfter($order,$oid) + { + $res1 = StoreOrder::gainUserIntegral($order); + $res2 = User::backOrderBrokerage($order); + StoreOrder::orderTakeAfter($order); + if(!($res1 && $res2)) exception('收货失败!'); + } + + /** + * 线下付款 + * @param $id + * $id 订单id + */ + public static function storeProductOrderOffline($id){ + + } + + /** + * 修改状态为 已退款 + * @param $data + * $data array type 1 直接退款 2 退款后返回原状态 refund_price 退款金额 + * @param $oid + * $oid string store_order表中的id + */ + public static function storeProductOrderRefundYAfter($data,$oid){ + StoreOrderAdminModel::refundTemplate($data,$oid); + } + + /** + * 修改状态为 不退款 + * @param $data + * $data string 退款原因 + * @param $oid + * $oid string store_order表中的id + */ + public static function storeProductOrderRefundNAfter($data,$oid){ + + } + + + /** + * 修改订单状态 + * @param $data + * data total_price 商品总价 pay_price 实际支付 + * @param $oid + * oid 订单id + */ + public static function storeProductOrderEditAfter($data,$oid){ + + } + /** + * 修改送货信息 + * @param $data + * $data array 送货人姓名/快递公司 送货人电话/快递单号 + * @param $oid + * $oid string store_order表中的id + */ + public static function storeProductOrderDistributionAfter($data,$oid){ + + } + + /** + * 用户申请退款 + * @param $oid + * @param $uid + */ + public static function storeProductOrderApplyRefundAfter($oid, $uid) + { + $order = StoreOrder::where('id',$oid)->find(); + WechatTemplateService::sendAdminNoticeTemplate([ + 'first'=>"亲,您有一个订单申请退款 \n订单号:{$order['order_id']}", + 'keyword1'=>'申请退款', + 'keyword2'=>'待处理', + 'keyword3'=>date('Y/m/d H:i',time()), + 'remark'=>'请及时处理' + ]); + } + + + /** + * 评价产品 + * @param $replyInfo + * @param $cartInfo + */ + public static function storeProductOrderReply($replyInfo, $cartInfo) + { + StoreOrder::checkOrderOver($cartInfo['oid']); + } + + /** + * 订单全部产品评价完 + * @param $oid + */ + public static function storeProductOrderOver($oid) + { + + } + + /** + * 退积分 + * @param $product + * $product 商品信息 + * @param $back_integral + * $back_integral 退多少积分 + */ + public static function storeOrderIntegralBack($product,$back_integral){ + + } + + /** + * 加入购物车成功之后 + * @param array $cartInfo 购物车信息 + * @param array $userInfo 用户信息 + */ + public static function storeProductSetCartAfterAfter($cartInfo, $userInfo) + { + + } +} \ No newline at end of file diff --git a/application/core/behavior/OrderBehavior.php b/application/core/behavior/OrderBehavior.php new file mode 100644 index 00000000..54557ca5 --- /dev/null +++ b/application/core/behavior/OrderBehavior.php @@ -0,0 +1,220 @@ + + * Date: 2019/4/8 5:41 PM + */ + +namespace app\core\behavior; + +use app\ebapi\model\store\StoreOrder; +use app\ebapi\model\user\User; +use app\ebapi\model\user\WechatUser; +use app\ebapi\model\user\UserAddress; +use app\admin\model\order\StoreOrder as StoreOrderAdminModel; +use app\core\util\SystemConfigService; +use app\core\logic\Template; + +class OrderBehavior +{ + /** + * 用户确认收货 + * @param $order + * @param $uid + */ + public static function storeProductOrderUserTakeDelivery($order, $uid) + { + $res1 = StoreOrder::gainUserIntegral($order); + $res2 = User::backOrderBrokerage($order); + StoreOrder::orderTakeAfter($order); + $giveCouponMinPrice = SystemConfigService::get('store_give_con_min_price'); + if($order['total_price'] >= $giveCouponMinPrice) WechatUser::userTakeOrderGiveCoupon($uid); + if(!($res1 && $res2)) exception('收货失败!'); + } + /** + * 订单创建成功后 + * @param $oid + */ + public static function storeProductOrderCreate($order,$group) + { + UserAddress::be(['is_default'=>1,'uid'=>$order['uid']]) || UserAddress::setDefaultAddress($group['addressId'],$order['uid']); + } + + /** + * 修改发货状态 为送货 + * @param $data + * $data array 送货方式 送货人姓名 送货人电话 + * @param $oid + * $oid string store_order表中的id + */ +// public static function storeProductOrderDeliveryAfter($data,$oid){ +// StoreOrder::orderPostageAfter($data,$oid); +// } + + /** + * 修改发货状态 为发货 + * @param $data + * $data array 发货方式 送货人姓名 送货人电话 + * @param $oid + * $oid string store_order表中的id + */ +// public static function storeProductOrderDeliveryGoodsAfter($data,$oid){ +// StoreOrder::orderPostageAfter($data,$oid); +// RoutineTemplate::sendOrderGoods($oid,$data); +// } + + /** + * 修改状态 为已收货 + * @param $data + * $data array status 状态为 已收货 + * @param $oid + * $oid string store_order表中的id + */ + public static function storeProductOrderTakeDeliveryAfter($order,$oid) + { + $res1 = StoreOrder::gainUserIntegral($order); + $res2 = User::backOrderBrokerage($order); + StoreOrder::orderTakeAfter($order); + if(!($res1 && $res2)) exception('收货失败!'); + } + + /** + * 线下付款 + * @param $id + * $id 订单id + */ + public static function storeProductOrderOffline($id){ + + } + + /** + * 修改状态为 已退款 + * @param $data + * $data array type 1 直接退款 2 退款后返回原状态 refund_price 退款金额 + * @param $oid + * $oid string store_order表中的id + */ + public static function storeProductOrderRefundYAfter($data,$oid){ + StoreOrderAdminModel::refundTemplate($data,$oid); + } + + /** + * 修改状态为 不退款 + * @param $data + * $data string 退款原因 + * @param $oid + * $oid string store_order表中的id + */ + public static function storeProductOrderRefundNAfter($data,$oid){ + + } + + + /** + * 修改订单状态 + * @param $data + * data total_price 商品总价 pay_price 实际支付 + * @param $oid + * oid 订单id + */ + public static function storeProductOrderEditAfter($data,$oid){ + + } + /** + * 修改送货信息 + * @param $data + * $data array 送货人姓名/快递公司 送货人电话/快递单号 + * @param $oid + * $oid string store_order表中的id + */ + public static function storeProductOrderDistributionAfter($data,$oid){ + + } + + /** + * 用户申请退款 + * @param $oid + * @param $uid + */ + public static function storeProductOrderApplyRefundAfter($oid, $uid) + { + //待完善 + $order = StoreOrder::where('id',$oid)->find(); +// Template::sendAdminNoticeTemplate([ +// 'first'=>"亲,您有一个订单申请退款 \n订单号:{$order['order_id']}", +// 'keyword1'=>'申请退款', +// 'keyword2'=>'待处理', +// 'keyword3'=>date('Y/m/d H:i',time()), +// 'remark'=>'请及时处理' +// ]); + } + + + /** + * 评价产品 + * @param $replyInfo + * @param $cartInfo + */ + public static function storeProductOrderReply($replyInfo, $cartInfo) + { + StoreOrder::checkOrderOver($cartInfo['oid']); + } + + /** + * 订单全部产品评价完 + * @param $oid + */ + public static function storeProductOrderOver($oid) + { + + } + + /** + * 退积分 + * @param array $order + * + */ + public static function storeOrderRegressionIntegralAfter($order) + { + return StoreOrder::RegressionIntegral($order); + } + + /** + * 退销量 + * @param array $order + * + */ + public static function storeOrderRegressionStockAfter($order) + { + return StoreOrder::RegressionStock($order); + } + + /** + * 退优惠券 + * @param array $order + * + */ + public static function storeOrderRegressionCouponAfter($order) + { + return StoreOrder::RegressionCoupon($order); + } + + /* + * 回退所有 + * @param array $order + * */ + public static function storeOrderRegressionAllAfter($order) + { + return StoreOrder::RegressionStock($order) && StoreOrder::RegressionIntegral($order) && StoreOrder::RegressionCoupon($order); + } + + /** + * 加入购物车成功之后 + * @param array $cartInfo 购物车信息 + * @param array $userInfo 用户信息 + */ + public static function storeProductSetCartAfterAfter($cartInfo, $userInfo) + { + + } +} \ No newline at end of file diff --git a/application/core/behavior/PaymentBehavior.php b/application/core/behavior/PaymentBehavior.php new file mode 100644 index 00000000..b0c47212 --- /dev/null +++ b/application/core/behavior/PaymentBehavior.php @@ -0,0 +1,135 @@ + + * @day: 2017/12/26 + */ + +namespace app\core\behavior; + +use app\ebapi\model\store\StoreOrder as StoreOrderRoutineModel; +use app\ebapi\model\store\StoreOrder as StoreOrderWapModel; //待完善 +use app\ebapi\model\user\UserRecharge; +use service\HookService; +use app\core\util\MiniProgramService; +use app\core\util\WechatService; + +//待完善 +class PaymentBehavior +{ + + /** + * 下单成功之后 + * @param $order + * @param $prepay_id + */ + public static function wechatPaymentPrepare($order, $prepay_id) + { + + } + + /** + * 支付成功后 + * @param $notify + * @return bool|mixed + */ + public static function wechatPaySuccess($notify) + { + if(isset($notify->attach) && $notify->attach){ + return HookService::listen('wechat_pay_success_'.strtolower($notify->attach),$notify->out_trade_no,$notify,true,self::class); + } + return false; + } + + /** + * 商品订单支付成功后 微信公众号 + * @param $orderId + * @param $notify + * @return bool + */ + public static function wechatPaySuccessProduct($orderId, $notify) + { + try{ + if(StoreOrderWapModel::be(['order_id'=>$orderId,'paid'=>1])) return true; + return StoreOrderWapModel::paySuccess($orderId); + }catch (\Exception $e){ + return false; + } + } + + + /** + * 商品订单支付成功后 小程序 + * @param $orderId + * @param $notify + * @return bool + */ + public static function wechatPaySuccessProductr($orderId, $notify) + { + try{ + if(StoreOrderRoutineModel::be(['order_id'=>$orderId,'paid'=>1])) return true; + return StoreOrderRoutineModel::paySuccess($orderId); + }catch (\Exception $e){ + return false; + } + } + + /** + * 用户充值成功后 + * @param $orderId + * @param $notify + * @return bool + */ + public static function wechatPaySuccessUserRecharge($orderId, $notify) + { + try{ + if(UserRecharge::be(['order_id'=>$orderId,'paid'=>1])) return true; + return UserRecharge::rechargeSuccess($orderId); + }catch (\Exception $e){ + return false; + } + } + + /** + * 使用余额支付订单时 + * @param $userInfo + * @param $orderInfo + */ + public static function yuePayProduct($userInfo, $orderInfo) + { + + + } + + + /** + * 微信支付订单退款 + * @param $orderNo + * @param array $opt + */ + public static function wechatPayOrderRefund($orderNo, array $opt) + { + WechatService::payOrderRefund($orderNo,$opt); + } + + /** + * 小程序支付订单退款 + * @param $orderNo + * @param array $opt + */ + public static function routinePayOrderRefund($orderNo, array $opt) + { + MiniProgramService::payOrderRefund($orderNo,$opt); + } + + /** + * 微信支付充值退款 + * @param $orderNo + * @param array $opt + */ + + public static function userRechargeRefund($orderNo, array $opt) + { + WechatService::payOrderRefund($orderNo,$opt); + } +} \ No newline at end of file diff --git a/application/core/behavior/RequestFilterBehavior.php b/application/core/behavior/RequestFilterBehavior.php new file mode 100644 index 00000000..c6de4b96 --- /dev/null +++ b/application/core/behavior/RequestFilterBehavior.php @@ -0,0 +1,61 @@ +method()); + switch ($method) { + case 'GET': + $data = $request->get(); + break; + case 'POST': + $data = $request->post(); + break; + case 'DELETE': + $data = $request->delete(); + break; + case 'PUT': + $data = $request->put(); + break; + default : + $data = []; + break; + } + //开启路由 + $hash = $request->routeInfo(); + if(Config::get('url_route_on') && isset($hash['rule'][1])){ + + }else{ + $module=$request->module(); + $controller=$request->controller(); + $action=$request->action(); + + } + } + + +} \ No newline at end of file diff --git a/application/core/behavior/UserBehavior.php b/application/core/behavior/UserBehavior.php new file mode 100644 index 00000000..2a8797ab --- /dev/null +++ b/application/core/behavior/UserBehavior.php @@ -0,0 +1,78 @@ + + * Date: 2019/4/8 5:41 PM + */ + +namespace app\core\behavior; + +use app\core\model\user\UserLevel; +use service\HookService; +use app\core\model\user\User; +use think\Request; + +class UserBehavior +{ + /** 用户访问记录 + * @param $userinfo + */ + public static function init($userinfo) + { + $request=Request::instance(); + User::edit(['last_time'=>time(),'last_ip'=>$request->ip()],$userinfo->uid,'uid'); + } + /** + * 管理员后台给用户添加金额 + * @param $user + * $user 用户信息 + * @param $money + * $money 添加的金额 + */ + public static function adminAddMoneyAfter($user,$money){ + + } + + /** + * 管理员后台给用户减少金额 + * @param $user + * $user 用户信息 + * @param $money + * $money 减少的金额 + */ + public static function adminSubMoneyAfter($user,$money){ + + } + + /** + * 管理员后台给用户增加的积分 + * @param $user + * $user 用户信息 + * @param $integral + * $integral 增加的积分 + */ + public static function adminAddIntegralAfter($user,$integral){ + + } + + /** + * 管理员后台给用户减少的积分 + * @param $user + * $user 用户信息 + * @param $integral + * $integral 减少的积分 + */ + public static function adminSubIntegralAfter($user,$integral){ + + } + + /* + * 用是否可成为Vip + * @param object $user 用户信息 + * */ + public static function userLevelAfter($user,$number) + { + return UserLevel::setLevelComplete($user['uid'],$number); + } + +} \ No newline at end of file diff --git a/application/core/implement/BehaviorIntterface.php b/application/core/implement/BehaviorIntterface.php new file mode 100644 index 00000000..0a3dd95b --- /dev/null +++ b/application/core/implement/BehaviorIntterface.php @@ -0,0 +1,20 @@ + + * Date: 2019/4/8 7:29 PM + */ + +namespace app\core\logic; + +use app\core\traits\LogicTrait; +use service\JsonService; + +class Login +{ + use LogicTrait; + + protected $providers=[ + \app\core\logic\routine\RoutineLogin::class, + ]; + + public static function login_ing($action) + { + if($action instanceof Login){ + return self::instance()->$action->login(); + }else{ + return JsonService::fail('访问的方法不存在!'); + } + + } + +} \ No newline at end of file diff --git a/application/core/logic/Pay.php b/application/core/logic/Pay.php new file mode 100644 index 00000000..2fe8be79 --- /dev/null +++ b/application/core/logic/Pay.php @@ -0,0 +1,30 @@ + + * Date: 2019/4/8 5:48 PM + */ +class Pay +{ + public static function notify(){ + $request=Request::instance(); + switch (strtolower($request->param('notify_type','wenxin'))){ + case 'wenxin': + break; + case 'routine': //小程序支付回调 + MiniProgramService::handleNotify(); + break; + case 'alipay': + break; + default: + echo 121; + break; + } + } +} \ No newline at end of file diff --git a/application/core/logic/Qrcode.php b/application/core/logic/Qrcode.php new file mode 100644 index 00000000..2e9be81f --- /dev/null +++ b/application/core/logic/Qrcode.php @@ -0,0 +1,34 @@ + + * Date: 2019/4/8 7:30 PM + */ +use app\admin\model\wechat\WechatQrcode as QrcodeModel;//待完善 + +class Qrcode +{ + /** + * 获取临时二维码 单个 + * */ + public static function getTemporaryQrcode($type,$id){ + return QrcodeModel::getTemporaryQrcode($type,$id)->toArray(); + } + /** + * 获取永久二维码 单个 + * */ + public static function getForeverQrcode($type,$id){ + return QrcodeModel::getForeverQrcode($type,$id)->toArray(); + } + + public static function getQrcode($id,$type = 'id') + { + return QrcodeModel::getQrcode($id,$type); + } + + public static function scanQrcode($id,$type = 'id') + { + return QrcodeModel::scanQrcode($id,$type); + } +} \ No newline at end of file diff --git a/application/core/logic/Template.php b/application/core/logic/Template.php new file mode 100644 index 00000000..4c033d46 --- /dev/null +++ b/application/core/logic/Template.php @@ -0,0 +1,13 @@ + + * Date: 2019/4/8 5:48 PM + */ +namespace app\core\logic; + +class Template +{ + +} \ No newline at end of file diff --git a/application/core/logic/routine/RoutineLogin.php b/application/core/logic/routine/RoutineLogin.php new file mode 100644 index 00000000..78a77b3e --- /dev/null +++ b/application/core/logic/routine/RoutineLogin.php @@ -0,0 +1,22 @@ + + * Date: 2019/4/8 5:45 PM + */ diff --git a/application/core/model/ApiMenus.php b/application/core/model/ApiMenus.php new file mode 100644 index 00000000..fabf3b98 --- /dev/null +++ b/application/core/model/ApiMenus.php @@ -0,0 +1,37 @@ +appCodeUnlimit($res->id,$page,280); + if($resCode){ + $dataQrcode['status'] = 1; + $dataQrcode['url_time'] = time(); + $res = RoutineQrcode::setRoutineQrcodeFind($res->id,$dataQrcode); + if($res) return $resCode; + else return false; + }else return false; + } + /** + * TODO 获取小程序页面带参数二维码不保存数据库 + * @param $thirdId + * @param $thirdType + * @param $page + * @param $imgUrl + * @return bool + */ + public static function getPageCode($page = '', $pramam = "?uid=1&product=1",$width = 280){ + return MiniProgramService::qrcodeService()->appCodeUnlimit($pramam,$page,$width); + } + + + /** + * 获取分销二维码 + * @param int $uid yonghuID + * @param array $color 二维码线条颜色 + * @return mixed + */ + public static function getCode($uid = 0,$imgUrl = '',$color = array(),$page = '',$thirdType = 'spread'){ + $accessToken = RoutineServer::get_access_token(); + $res = RoutineQrcode::setRoutineQrcodeForever($uid,$thirdType,$page,$imgUrl); + if($res){ + $url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=".$accessToken; + if($uid) $data['scene'] = $res->id; + else $data['scene'] = 0; + if(empty($color)){ + $color['r'] = 0; + $color['g'] = 0; + $color['b'] = 0; + } + $data['page'] = $page; + $data['width'] = 430; + $data['auto_color'] = false; + $data['line_color'] = $color; + $data['is_hyaline'] = false; + $resCode = RoutineServer::curlPost($url,json_encode($data)); + if($resCode){ + $dataQrcode['status'] = 1; + $dataQrcode['url_time'] = time(); + $res = RoutineQrcode::setRoutineQrcodeFind($res->id,$dataQrcode); + if($res) return $resCode; + else return false; + }else return false; + }else return false; + } + + /** + * 获取小程序内访问页面的二维码 + * @param string $path + * @param int $width + * @return mixed + */ + public static function getPages($path = '',$width = 430){ + $accessToken = RoutineServer::get_access_token(); + $url = "https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=".$accessToken; + $data['path'] = $path; + $data['width'] = $width; + return RoutineServer::curlPost($url,json_encode($data)); + } +} \ No newline at end of file diff --git a/application/core/model/routine/RoutineFormId.php b/application/core/model/routine/RoutineFormId.php new file mode 100644 index 00000000..78a39737 --- /dev/null +++ b/application/core/model/routine/RoutineFormId.php @@ -0,0 +1,60 @@ +where('stop_time','LT',time())->delete(); + } + + /** + * 获取一个可以使用的formId + * @return bool|mixed + */ + public static function getFormIdOne($uid = 0,$isArray=false){ + $formId = self::where('status',1)->where('stop_time','GT',time())->where('uid',$uid)->order('id asc')->find(); + if($isArray) return $formId; + if($formId) return $formId['form_id']; + else return false; + } + + /** + * 修改一个FormID为已使用 + * @param string $formId + * @return $this|bool + */ + public static function delFormIdOne($formId = ''){ + if($formId == '') return true; + return self::where('form_id',$formId)->update(['status'=>2]); + } + + /* + * 创建formid + * @param string $formId + * @param int $uid + * @return array + * */ + public static function SetFormId($formId,$uid) + { + if(!strlen(trim($formId)) || $formId == 'the formId is a mock one') return false; + $data['form_id'] = $formId; + $data['uid'] = $uid; + $data['status'] = 1; + $data['stop_time'] = bcadd(time(),bcmul(6,86400,0),0); + return self::set($data); + } +} \ No newline at end of file diff --git a/application/core/model/routine/RoutineQrcode.php b/application/core/model/routine/RoutineQrcode.php new file mode 100644 index 00000000..df9b9144 --- /dev/null +++ b/application/core/model/routine/RoutineQrcode.php @@ -0,0 +1,92 @@ +where('third_type',$thirdType)->count(); + if($count) return self::where('third_id',$thirdId)->where('third_type',$thirdType)->field('id')->find(); + return self::setRoutineQrcodeForever($thirdId,$thirdType,$page,$qrCodeLink); + } + + /** + * 添加二维码记录 + * @param string $thirdType + * @param int $thirdId + * @return object + */ + public static function setRoutineQrcodeForever($thirdId = 0,$thirdType = 'spread',$page = '',$qrCodeLink = ''){ + $data['third_type'] = $thirdType; + $data['third_id'] = $thirdId; + $data['status'] = 0; + $data['add_time'] = time(); + $data['page'] = $page; + $data['url_time'] = ''; + $data['qrcode_url'] = $qrCodeLink; + return self::set($data); + } + + /** + * 修改二维码地址 + * @param int $id + * @param array $data + * @return bool + */ + public static function setRoutineQrcodeFind($id = 0,$data = array()){ + if(!$id) return false; + $count = self::getRoutineQrcodeFind($id); + if(!$count) return false; + return self::edit($data,$id,'id'); + } + + /** + * 获取二维码是否存在 + * @param int $id + * @return int|string + */ + public static function getRoutineQrcodeFind($id = 0){ + if(!$id) return 0; + return self::where('id',$id)->count(); + } + + /** + * 获取小程序二维码信息 + * @param int $id + * @param string $field + * @return array|bool|false|\PDOStatement|string|\think\Model + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\exception\DbException + */ + public static function getRoutineQrcodeFindType($id = 0,$field = 'third_type,third_id,page'){ + if(!$id) return false; + $count = self::getRoutineQrcodeFind($id); + if(!$count) return false; + return self::where('id',$id)->where('status',1)->field($field)->find(); + } + + +} \ No newline at end of file diff --git a/application/core/model/routine/RoutineTemplate.php b/application/core/model/routine/RoutineTemplate.php new file mode 100644 index 00000000..6c1cfb20 --- /dev/null +++ b/application/core/model/routine/RoutineTemplate.php @@ -0,0 +1,133 @@ +find(); + $data['keyword1'] = $orderId; + $data['keyword2'] = date('Y-m-d H:i:s',time()); + $data['keyword3'] = '已支付'; + $data['keyword4'] = $order['pay_price']; + if($order['pay_type'] == 'yue') $data['keyword5'] = '余额支付'; + else if($order['pay_type'] == 'weixin') $data['keyword5'] = '微信支付'; + return self::sendOut('ORDER_PAY_SUCCESS',$order['uid'],$data,$formId,'/pages/order_details/index?order_id='.$orderId); + } + + /* + * 发送模板消息 + * @param string $TempCode 模板消息常量名称 + * @param int $uid 用户uid + * @param array $data 模板内容 + * @param string $formId formId + * @param string $link 跳转链接 + * */ + public static function sendOut($TempCode,$uid=null,$data=null,$formId = '',$link='') + { + try{ + $openid=WechatUser::uidToOpenid($uid); + if(!$formId){ + $form= RoutineFormId::getFormIdOne($uid,true); + if(!$form) return false; + if(isset($form['id'])) RoutineFormId::where('id',$form['id'])->delete(); + }else{ + $form['form_id']=$formId; + } + return Template::instance()->routine_two->sendTemplate($TempCode,$openid,$data,$form['form_id'],$link); + }catch (\Exception $e){ + return false; + } + } +} \ No newline at end of file diff --git a/application/core/model/routine/Token.php b/application/core/model/routine/Token.php new file mode 100644 index 00000000..261bb353 --- /dev/null +++ b/application/core/model/routine/Token.php @@ -0,0 +1,38 @@ +$uid])) self::where('uid',$uid)->delete(); + return self::set(['uid'=>$uid,'rand_string'=>$randstring,'add_time'=>time()]); + } + + /* + * 验证当前token是否被篡改 + * @param int $uid 用户uid + * @param string $randstring 随机字符串 + * @return Boolean + * */ + public static function checkRandString($uid,$randstring) + { + return self::where('uid',$uid)->value('rand_string') === $randstring; + } +} \ No newline at end of file diff --git a/application/core/model/system/SystemUserLevel.php b/application/core/model/system/SystemUserLevel.php new file mode 100644 index 00000000..2ca8a19b --- /dev/null +++ b/application/core/model/system/SystemUserLevel.php @@ -0,0 +1,150 @@ +alias($alert); + $alert=$alert ? $alert.'.': ''; + return $model->where("{$alert}is_show",1)->where("{$alert}is_del",0); + } + + /* + * 获取某个等级的折扣 + * */ + public static function getLevelDiscount($id=0) + { + $model=self::setWhere(); + if($id) $model=$model->where('id',$id); + else $model=$model->order('grade asc'); + return $model->value('discount'); + } + + /* + * 获取用户等级和当前等级 + * @param int $uid 用户uid + * @param Boolean $isArray 是否查找任务列表 + * @return array + * */ + public static function getLevelInfo($uid,$isArray=false){ + $level=['id'=>0];$task=[]; + $id=UserLevel::getUserLevel($uid); + if($id!==false) $level=UserLevel::getUserLevelInfo($id); + $list=self::getLevelListAndGrade($level['id'],$isArray); + if(isset($list[0]) && $isArray) $task=SystemUserTask::getTashList($list[0]['id'],$uid,$level); + if($isArray) return [$list,$task]; + else return $level['id'] && $id !== false ? $level : false; + } + + /* + * 获取会员等级级别 + * @param int $leval_id 等级id + * @return Array + * */ + public static function getLevelGrade($leval_id) + { + return self::setWhere()->where('id',$leval_id)->value('grade'); + } + /* + * 获取会员等级列表 + * @param int $levael_id 用户等级 + * @param Boolean $isArray 是否查找任务列表 + * @return Array + * */ + public static function getLevelListAndGrade($leval_id,$isArray,$expire=1400) + { + if($isArray && Cache::has('LevelListArrayTask')){ + return Cache::get('LevelListArrayTask'); + }else if(Cache::has('LevelListArray')){ + return Cache::get('LevelListArray'); + } + $grade=0; + $list=self::setWhere()->field(['name','discount','image','icon','explain','id','grade'])->order('grade asc')->select(); + $list=count($list) ? $list->toArray() : []; + foreach ($list as &$item){ + if($item['id']==$leval_id) $grade=$item['grade']; + if($isArray) $item['task_list']=SystemUserTask::getTashList($item['id']); + } + foreach ($list as &$item){ + if($grade < $item['grade']) $item['is_clear']=true; + else $item['is_clear']=false; + } + if($isArray) + Cache::set('LevelListArrayTask',$list,$expire); + else + Cache::set('LevelListArray',$list,$expire); + return $list; + } + + public static function getClear($leval_id,$list=null) + { + $list=$list===null ? self::getLevelListAndGrade($leval_id,false) : $list; + foreach ($list as $item){ + if($item['id']==$leval_id) return $item['is_clear']; + } + return false; + } + + /* + * 获取当前vipid 的下一个会员id + * @param int $leval_id 当前用户的会员id + * @return int + * */ + public static function getNextLevelId($leval_id) + { + $list=self::getLevelListAndGrade($leval_id,false); + $grade=0; + $leveal=[]; + foreach ($list as $item){ + if($item['id']==$leval_id) $grade=$item['grade']; + } + foreach ($list as $item){ + if($grade < $item['grade']) array_push($leveal,$item['id']); + } + return isset($leveal[0]) ? $leveal[0] : 0; + } + + /* + * 获取会员等级列表 + * @parma int $uid 用户uid + * @return Array + * */ + public static function getLevelList($uid){ + list($list,$task)=self::getLevelInfo($uid,true); + return ['list'=>$list,'task'=>$task]; + } + + + + +} \ No newline at end of file diff --git a/application/core/model/system/SystemUserTask.php b/application/core/model/system/SystemUserTask.php new file mode 100644 index 00000000..064d1c44 --- /dev/null +++ b/application/core/model/system/SystemUserTask.php @@ -0,0 +1,412 @@ +'SatisfactionIntegral', + 'name'=>'满足积分{$num}', + 'real_name'=>'积分数', + 'max_number'=>0, + 'min_number'=>0, + 'unit'=>'分' + ], + [ + 'type'=>'ConsumptionAmount', + 'name'=>'消费满{$num}', + 'real_name'=>'消费金额', + 'max_number'=>0, + 'min_number'=>0, + 'unit'=>'元' + ], + [ + 'type'=>'ConsumptionFrequency', + 'name'=>'消费{$num}', + 'real_name'=>'消费次数', + 'max_number'=>0, + 'min_number'=>0, + 'unit'=>'次' + ], + [ + 'type'=>'CumulativeAttendance', + 'name'=>'累计签到{$num}', + 'real_name'=>'累计签到', + 'max_number'=>365, + 'min_number'=>1, + 'unit'=>'天' + ], + [ + 'type'=>'SharingTimes', + 'name'=>'分享给朋友{$num}', + 'real_name'=>'分享给朋友', + 'max_number'=>1000, + 'min_number'=>1, + 'unit'=>'次' + ], + [ + 'type'=>'InviteGoodFriends', + 'name'=>'邀请好友{$num}成为下线', + 'real_name'=>'邀请好友成为下线', + 'max_number'=>1000, + 'min_number'=>1, + 'unit'=>'人' + ], + [ + 'type'=>'InviteGoodFriendsLevel', + 'name'=>'邀请好友{$num}成为会员', + 'real_name'=>'邀请好友成为会员', + 'max_number'=>1000, + 'min_number'=>1, + 'unit'=>'人' + ], + ]; + + public function profile() + { + return $this->hasOne('SystemUserLevel','level_id','id')->field('name'); + } + + public static function getTaskTypeAll() + { + return self::$TaskType; + } + + /* + * 获取某个任务 + * @param string $type 任务类型 + * @return array + * */ + public static function getTaskType($type) + { + foreach (self::$TaskType as $item){ + if($item['type']==$type) return $item; + } + } + + /* + * 设置任务名 + * @param string $type 任务类型 + * @param int $num 预设值 + * @return string + * */ + public static function setTaskName($type,$num) + { + $systemType=self::getTaskType($type); + return str_replace('{$num}',$num.$systemType['unit'],$systemType['name']); + } + + /* + * 累计消费金额 + * @param int $task_id 任务id + * @param int $uid 用户id + * @param int $start_time 开始时间 + * @param int $number 限定时间 + * @return boolean + * */ + public static function ConsumptionAmount($task_id,$uid=0,$start_time=0,$number=0) + { + $isComplete=false; + $SumPayPrice=self::getDb('store_order')->where('paid',1)->where('refund_status',0)->where('is_del',0)->where('uid',$uid)->sum('pay_price'); + if($SumPayPrice >= $number) $isComplete=UserTaskFinish::setFinish($uid,$task_id) ? true : false; + return ['还需消费{$num}元',$SumPayPrice,$isComplete]; + } + + /* + * 累计消费次数 + * @param int $task_id 任务id + * @param int $uid 用户id + * @param int $start_time 开始时间 + * @param int $number 限定时间 + * @return boolean + * */ + public static function ConsumptionFrequency($task_id,$uid=0,$start_time=0,$number=0) + { + $isComplete=false; + $countPay=self::getDb('store_order')->where('paid',1)->where('refund_status',0)->where('is_del',0)->where('uid',$uid)->count(); + if($countPay >= $number) $isComplete=UserTaskFinish::setFinish($uid,$task_id) ? true : false; + return ['还需消费{$num}次',$countPay,$isComplete]; + } + + /* + * 邀请好友成为会员 + * @param int $task_id 任务id + * @param int $uid 用户id + * @param int $start_time 开始时间 + * @param int $number 限定时间 + * @return boolean + * */ + public static function InviteGoodFriendsLevel($task_id,$uid=0,$start_time=0,$number=0) + { + $isComplete=false; + $uids=User::where('spread_uid',$uid)->where('spread_time','>',$start_time)->column('uid'); + $levelCount=count($uids) ? UserLevel::setUserLevelCount($uids) : 0; + if($levelCount >= $number) $isComplete=serTaskFinish::setFinish($uid,$task_id) ? true : false; + return ['还需邀请{$num}人成为会员',$levelCount,$isComplete]; + } + + /* + * 邀请好友成为下线 + * @param int $task_id 任务id + * @param int $uid 用户id + * @param int $start_time 查询开始时间 + * @param int $number 限定数量 + * */ + public static function InviteGoodFriends($task_id,$uid=0,$start_time=0,$number=0) + { + $isComplete=false; + $spreadCount=User::where('spread_uid',$uid)->where('spread_time','>',$start_time)->count(); + if($spreadCount >= $number) $isComplete=UserTaskFinish::setFinish($uid,$task_id) ? true : false; + return ['还需邀请{$num}人成为下线',$spreadCount,$isComplete]; + } + + /* + * 满足积分 + * @param int $task_id 任务id + * @param int $uid 用户id + * @param int $start_time 查询开始时间 + * @param int $number 限定数量 + * @return Boolean + * */ + public static function SatisfactionIntegral($task_id,$uid=0,$start_time=0,$number=0) + { + $isComplete=false; + $sumNumber=UserBill::where(['uid'=>$uid,'category'=>'integral','pm'=>1])->where('type','in',['system_add','sign'])->sum('number'); + if($sumNumber >= $number) $isComplete=UserTaskFinish::setFinish($uid,$task_id) ? true : false; + return ['还需要{$num}经验',$sumNumber,$isComplete]; + } + + /* + * 分享给朋友次数完成情况 + * @param int $task_id 任务id + * @param int $uid 用户id + * @param int $start_time 查询开始时间 + * @param int $number 限定数量 + * @return Boolean + * */ + public static function SharingTimes($task_id,$uid=0,$start_time=0,$number=0) + { + $isComplete=false; + $sumCount=UserBill::where(['uid'=>$uid,'category'=>'share','pm'=>1])->where('add_time','>',$start_time)->where('type','in',['share'])->count(); + if($sumCount >= $number) $isComplete=UserTaskFinish::setFinish($uid,$task_id) ? true :false; + return ['还需分享{$num}次',$sumCount,$isComplete]; + } + + /* + * 累计签到 + * @param int $task_id 任务id + * @param int $uid 用户id + * @param int $start_time 查询开始时间 + * @param int $number 限定数量 + * @return Boolean + * */ + public static function CumulativeAttendance($task_id,$uid=0,$start_time=0,$number=0) + { + $isComplete=false; + $sumCount=UserBill::where(['uid'=>$uid,'category'=>'integral','pm'=>1])->where('type','in',['sign'])->count(); + if($sumCount >= $number) $isComplete=UserTaskFinish::setFinish($uid,$task_id) ? true : false; + return ['还需签到{$num}天',$sumCount,$isComplete]; + } + + /* + * 设置任务完成情况 + * @param int $task_id 任务id + * @param int $uid 用户uid + * @param int $start_time 查询开始时间 + * @return Boolean + * */ + public static function setTaskFinish($task_id=0,$uid=0,$start_time=0) + { + if(!$task_id) return self::setErrorInfo('缺少任务id参数'); + if(!$uid) return self::setErrorInfo('缺少用户uid'); + $task=self::where('id',$task_id)->where('is_show',1)->find(); + if(!$task) return self::setErrorInfo('任务不存在'); + $task_type=$task->task_type; + if($task_type && method_exists(self::class,$task_type)){ + try{ + return self::$task_type($task_id,$uid,$start_time,$task->number); + }catch (\Exception $e){ + return self::setErrorInfo($e->getMessage()); + } + } + return self::setErrorInfo('没有此任务'); + } + + /* + * 设置任务显示条件 + * @param string $alert 表别名 + * @param object $model 模型实例 + * @return object + * */ + public static function visibleWhere($alert='',$model=null) + { + $model=$model===null ? new self() : $model; + if($alert) $model=$model->alias($alert); + $alert=$alert ? $alert.'.': ''; + return $model->where("{$alert}is_show",1); + } + /* + * 获取等级会员任务列表 + * @param int $level_id 会员等级id + * @param int $uid 用户id + * @return array + * */ + public static function getTashList($level_id,$uid=0,$level=null,$expire=1400) + { + $level_id=is_string($level_id) ? (int)$level_id : $level_id; + if(Cache::has('Tash_list_common_'.$level_id)) + $list=Cache::get('Tash_list_common_'.$level_id); + else{ + $list=self::visibleWhere()->where('level_id',$level_id)->field(['name','real_name','task_type','illustrate','number','id'])->order('sort desc')->select(); + $list=count($list) ? $list->toArray() : []; + Cache::set('Tash_list_common_'.$level_id,$list,$expire); + } + if($uid==0) return $list; + if($level===null) $level=SystemUserLevel::getLevelInfo($uid); + $add_time=self::getDb('user')->where('uid',$uid)->value('add_time'); + if($level===false) $startTime=$add_time; + else $startTime=isset($level['add_time']) ? $level['add_time'] : $add_time; + $LeveId=SystemUserLevel::getNextLevelId($level['id']); + $is_clear=SystemUserLevel::getClear($level['id']); + if($is_clear==false && $LeveId==$level_id) $is_clear=true; + $reach_count=self::getTaskComplete($level_id,$uid,true); + return ['reach_count'=>$reach_count,'task'=>self::tidyTask($list,$uid,$is_clear,$startTime)]; + } + + /* + * 获取未完成任务的详细值 + * @param array $item 任务 + * @param int $uid 用户id + * @param int $startTime 开始时间 + * @return array + * */ + protected static function set_task_type($item,$uid,$startTime=0){ + $task=['task_type_title'=>'','new_number'=>0,'speed'=>0,'finish'=>0]; + $task_type=$item['task_type']; + switch ($task_type) { + case 'SatisfactionIntegral': + case 'ConsumptionAmount': + case 'ConsumptionFrequency': + case 'CumulativeAttendance': + case 'SharingTimes': + case 'InviteGoodFriends': + case 'InviteGoodFriendsLevel': + try{ + list($task_type_title,$num,$isComplete)=self::$task_type($item['id'],$uid,$startTime,$item['number']); + if($isComplete){ + $task['finish']=1; + $task['speed']=100; + $task['speed']=$item['number']; + $task['new_number']=$item['number']; + }else{ + $numdata=bcsub($item['number'],$num,0); + $task['task_type_title']=str_replace('{$num}',$numdata,$task_type_title); + $task['speed']=bcdiv($num,$item['number'],2); + $task['speed']=bcmul($task['speed'],100,0); + $task['new_number']=$num; + } + }catch (\Exception $e){} + break; + } + return [$task['new_number'],$task['speed'],$task['task_type_title'],$task['finish']]; + } + + + /* + * 设置任务完成状态,已被使用 + * @param int $level_id 会员id + * @param int $uid 用户id + * @return Boolean + * */ + public static function setTarkStatus($level_id,$uid) + { + $taskIds=self::visibleWhere()->where('level_id',$level_id)->column('id'); + if(!count($taskIds)) return true; + return self::getDb('user_task_finish')->where('uid',$uid)->where('task_id','in',$taskIds)->update(['status'=>1]); + } + /* + * 检查当前等级是否完成全部任务 + * @param int $level_id 会员id + * @param int $uid 用户uid + * @return boolean + * */ + public static function getTaskComplete($level_id,$uid,$isCount=false) + { + $taskIds=self::visibleWhere()->where('level_id',$level_id)->column('id'); + $taskIdsCount=count($taskIds); + //如果当前会员没有任务默认为直接升级为下一等级 + if($taskIdsCount){ + if($isCount){ + return self::getDb('user_task_finish')->group('task_id')->where('uid',$uid)->where('task_id','in',$taskIds)->count(); + }else{ + $finishCount=self::getDb('user_task_finish')->group('task_id')->where('status',$isCount ? 1 : 0)->where('uid',$uid)->where('task_id','in',$taskIds)->count(); + } + //如果当前任务有完成其一的,查询当前完成的任务数量,如果有任务完成则达成当前vip + if(self::visibleWhere()->where('id','in',$taskIds)->where('is_must',0)->count() && $finishCount){ + return true; + } + return $finishCount >= $taskIdsCount; + } + if($isCount) return 0; + //如果没有设置任务当前等级无需购买则返回false + if(SystemUserLevel::be(['id'=>$level_id,'is_pay'=>0])) return false; + return true; + } + /* + * 设置任务内容完成情况 + * @param array $task 任务列表 + * @param int $uid 用户id + * @热图图呢 array + * */ + public static function tidyTask($task,$uid,$is_clear,$startTime){ + if(!is_array($task)) return $task; + foreach ($task as &$item){ + //如果已完成该任务进度直接为100 + if(self::getDb('user_task_finish')->where('uid',$uid)->where('task_id',$item['id'])->count()){ + $item['new_number']=$item['number']; + $item['speed']=100; + $item['finish']=1; + $item['task_type_title']=''; + }else{ + if($is_clear){ + list($new_number, $speed, $task_type_title, $finish) = self::set_task_type($item, $uid, $startTime); + $item['new_number'] = $new_number; + $item['speed'] = $speed; + $item['task_type_title'] = $task_type_title; + $item['finish'] = $finish; + }else { + list($new_number, $speed, $task_type_title, $finish) = self::set_task_type($item,-1,time()+86400); + $item['new_number'] = $new_number; + $item['speed'] = $speed; + $item['task_type_title'] = $task_type_title; + $item['finish'] = $finish; + } + } + } + return $task; + } + +} \ No newline at end of file diff --git a/application/core/model/user/User.php b/application/core/model/user/User.php new file mode 100644 index 00000000..ae883c75 --- /dev/null +++ b/application/core/model/user/User.php @@ -0,0 +1,19 @@ + + * Date: 2019/4/3 9:13 + */ + + +namespace app\core\model\user; + +use traits\ModelTrait; +use basic\ModelBasic; + +class User extends ModelBasic +{ + use ModelTrait; + +} \ No newline at end of file diff --git a/application/core/model/user/UserBill.php b/application/core/model/user/UserBill.php new file mode 100644 index 00000000..692d6be0 --- /dev/null +++ b/application/core/model/user/UserBill.php @@ -0,0 +1,247 @@ + + * Date: 2019/3/27 21:44 + */ +namespace app\core\model\user; + +use behavior\user\UserBehavior; +use service\HookService; +use think\Cache; +use traits\ModelTrait; +use basic\ModelBasic; +/** + * 用户消费新增金额明细 model + * Class User + * @package app\core\model\user + */ + +class UserBill extends ModelBasic +{ + use ModelTrait; + + protected $insert = ['add_time']; + + protected function setAddTimeAttr() + { + return time(); + } + + public static function income($title,$uid,$category,$type,$number,$link_id = 0,$balance = 0,$mark = '',$status = 1) + { + $pm = 1; + return self::set(compact('title','uid','link_id','category','type','number','balance','mark','status','pm')); + } + + public static function expend($title,$uid,$category,$type,$number,$link_id = 0,$balance = 0,$mark = '',$status = 1) + { + $pm = 0; + return self::set(compact('title','uid','link_id','category','type','number','balance','mark','status','pm')); + } + /** + * 积分使用记录 + * @param int $uid + * @param int $page + * @param int $limit + * @return \think\response\Json + */ + public static function userBillList($uid,$page,$limit,$category='integral') + { + $list=self::where('uid',$uid)->where('category',$category) + ->field('mark,pm,number,add_time') + ->where('status',1)->order('add_time DESC')->page((int)$page,(int)$limit)->select(); + $list=count($list) ? $list->toArray() : []; + foreach ($list as &$v){ + $v['add_time'] = date('Y/m/d H:i',$v['add_time']); + $v['number'] = floatval($v['number']); + } + return $list; + } + /* + * 获取昨日佣金 + * @param int $uid 用户uid + * */ + public static function yesterdayCommissionSum($uid) + { + return self::where('uid',$uid)->where('category','now_money')->where('type','brokerage')->where('pm',1) + ->where('status',1)->whereTime('add_time', 'yesterday')->sum('number'); + } + + /* + * 获取总佣金 + * */ + public static function getBrokerage($uid) + { + return self::where('uid',$uid)->where('category','now_money')->where('type','brokerage')->where('pm',1) + ->where('status',1)->sum('number'); + } + + + /* + * 累计充值 + * */ + public static function getRecharge($uid) + { + return self::where(['uid'=>$uid,'category'=>'now_money','type'=>'recharge','pm'=>1,'status'=>1])->sum('number'); + } + + /* + * 获取用户账单明细 + * @param int $uid 用户uid + * @param int $page 页码 + * @param int $limit 展示多少条 + * @param int $type 展示类型 + * @return array + * */ + public static function getUserBillList($uid,$page,$limit,$type) + { + $model=self::where('uid',$uid)->where('category','now_money')->order('add_time desc') + ->field(['FROM_UNIXTIME(add_time,"%Y-%m") as time','group_concat(id SEPARATOR ",") ids'])->group('time'); + switch ((int)$type){ + case 0: + $model=$model->where('type','in',['recharge','brokerage','pay_product','system_add','pay_product_refund','system_sub']); + break; + case 1: + $model=$model->where('type','pay_product'); + break; + case 2: + $model=$model->where('type','recharge'); + break; + case 3: + $model=$model->where('type','brokerage'); + break; + case 4: + $model=$model->where('type','extract'); + break; + } + $list=($list=$model->page((int)$page,(int)$limit)->select()) ? $list->toArray() : []; + $data=[]; + foreach ($list as $item){ + $value['money']=$item['time']; + $value['list']=self::where('id','in',$item['ids'])->field(['FROM_UNIXTIME(add_time,"%Y-%m-%d %H:%i") as add_time','title','number','pm'])->order('add_time DESC')->select(); + array_push($data,$value); + } + return $data; + } + + /** + * TODO 获取用户记录 按月查找 + * @param $uid $uid 用户编号 + * @param int $first $first 起始值 + * @param int $limit $limit 查询条数 + * @param string $category $category 记录类型 + * @param string $type $type 记录分类 + * @return mixed + */ + public static function getRecordList($uid,$first = 0,$limit = 8,$category = 'now_money',$type = ''){ + $model = new self; + $model = $model->field("FROM_UNIXTIME(add_time, '%Y-%m') as time"); + $model = $model->where('uid','IN',$uid); + $model = $model->where('category',$category); + if(strlen(trim($type))) $model = $model->where('type','in',$type); + $model = $model->group("FROM_UNIXTIME(add_time, '%Y-%m')"); + $model = $model->limit($first,$limit); + $model = $model->order('time desc'); + $list = $model->select(); + if($list) return $list->toArray(); + else []; + } + + /** + * TODO 按月份查找用户记录 + * @param $uid $uid 用户编号 + * @param int $addTime $addTime 月份 + * @param string $category $category 记录类型 + * @param string $type $type 记录分类 + * @return mixed + */ + public static function getRecordListDraw($uid, $addTime = 0,$category = 'now_money',$type = ''){ + if(!$uid) []; + $model = new self; + $model = $model->field("title,FROM_UNIXTIME(add_time, '%Y-%m-%d %H:%i') as time,number,pm"); + $model = $model->where('uid',$uid); + $model = $model->where("FROM_UNIXTIME(add_time, '%Y-%m')= '{$addTime}'"); + $model = $model->where('category',$category); + if(strlen(trim($type))) $model = $model->where('type','in',$type); + $model = $model->order('add_time desc'); + $list = $model->select(); + if($list) return $list->toArray(); + else []; + } + + /** + * TODO 获取订单返佣记录 + * @param $uid + * @param int $addTime + * @param string $category + * @param string $type + * @return mixed + */ + public static function getRecordOrderListDraw($uid, $addTime = 0,$category = 'now_money',$type = 'brokerage'){ + if(!strlen(trim($uid))) []; + $model = new self; + $model = $model->field("o.order_id,FROM_UNIXTIME(o.add_time, '%Y-%m-%d %H:%i') as time,b.number,u.avatar,u.nickname"); + $model = $model->alias('b'); + $model = $model->join('StoreOrder o','o.id=b.link_id'); + $model = $model->join('User u','u.uid=o.uid','right'); + $model = $model->where('b.uid','IN',$uid); + $model = $model->where("FROM_UNIXTIME(b.add_time, '%Y-%m')= '{$addTime}'"); + $model = $model->where('b.category',$category); + $model = $model->where('b.type','in',$type); + $model = $model->order('time desc'); + $list = $model->select(); + if($list) return $list->toArray(); + else []; + } + + /** + * TODO 获取用户记录总和 + * @param $uid + * @param string $category + * @param string $type + * @return mixed + */ + public static function getRecordCount($uid, $category = 'now_money', $type = '',$time=''){ + $model = new self; + $model = $model->where('uid','IN',$uid); + $model = $model->where('category',$category); + if(strlen(trim($type))) $model = $model->where('type','in',$type); + if($time) $model=$model->whereTime('add_time',$time); + return $model->sum('number'); + } + + /** + * TODO 获取订单返佣记录总数 + * @param $uid + * @param string $category + * @param string $type + * @return mixed + */ + public static function getRecordOrderCount($uid, $category = 'now_money', $type = 'brokerage'){ + $model = new self; + $model = $model->where('uid','IN',$uid); + $model = $model->where('category',$category); + if(strlen(trim($type))) $model = $model->where('type','in',$type); + return $model->count(); + } + + /* + * 记录分享次数 + * @param int $uid 用户uid + * @param int $cd 冷却时间 + * @return Boolean + * */ + public static function setUserShare($uid,$cd=300){ + $user=User::where('uid',$uid)->find(); + if(!$user) return self::setErrorInfo('用户不存在!'); + $cachename='Share_'.$uid; + if(Cache::has($cachename)) return false; + $res=self::income('用户分享记录',$uid,'share',1,0,0,date('Y-m-d H:i:s',time()).':用户分享'); + Cache::set($cachename,1,$cd); + HookService::afterListen('user_leve',$user,false,UserBehavior::class); + return true; + } + +} diff --git a/application/core/model/user/UserLevel.php b/application/core/model/user/UserLevel.php new file mode 100644 index 00000000..b9042484 --- /dev/null +++ b/application/core/model/user/UserLevel.php @@ -0,0 +1,177 @@ +where('uid','in',$uids); + else $model=$model->where('uid',$uids); + return $model->count(); + } + + /* + * 设置查询初始化条件 + * @param string $alias 表别名 + * @param object $model 模型实例化对象 + * @return object + * */ + public static function valiWhere($alias='',$model=null) + { + $model=is_null($model) ? new self() : $model; + if($alias){ + $model=$model->alias($alias); + $alias.='.'; + } + return $model->where(["{$alias}status"=>1,"{$alias}is_del"=>0]); + } + /* + * 设置会员等级 + * @param int $uid 用户uid + * @param int $level_id 等级id + * @return boolean | array + * */ + public static function setUserLevel($uid,$level_id){ + $vipinfo=SystemUserLevel::get($level_id); + if(!$vipinfo) return false; + $userinfo=self::getDb('user')->find($uid); + if(!$userinfo) return false; + $add_valid_time=(int)$vipinfo->valid_date*86400; + $uservipinfo=self::valiWhere()->where(['uid'=>$uid,'level_id'=>$level_id])->find(); + //检查是否购买过 + if($uservipinfo){ + $stay=0; + //剩余时间 + if(time() < $uservipinfo->valid_time) $stay=$uservipinfo->valid_time-time(); + //如果购买过当前等级的会员过期了.从当前时间开始计算 + //过期时效: 剩余时间+当前会员等级时间+当前time + $add_valid_time=$stay+$add_valid_time+time(); + $data['is_forever']=$vipinfo->is_forever; + $data['valid_time']=$add_valid_time; + return self::where(['uid'=>$uid,'level_id'=>$level_id])->update($data); + }else{ + $data=[ + 'is_forever'=>$vipinfo->is_forever, + 'status'=>1, + 'is_del'=>0, + 'grade'=>$vipinfo->grade, + 'uid'=>$uid, + 'add_time'=>time(), + 'level_id'=>$level_id, + 'discount'=>$vipinfo->discount, + ]; + if($data['is_forever']) + $data['valid_time']=0; + else + $data['valid_time']=$add_valid_time; + $data['mark']='尊敬的用户'.$userinfo['nickname'].'在'.date('Y-m-d H:i:s',time()).'成为了'.$vipinfo['name']; + return self::set($data); + } + } + + /* + * 获取当前用户会员等级返回当前用户等级id + * @param int $uid 用户uid + * @return int 会员id + * */ + public static function getUserLevel($uid,$grade=0) + { + $model = self::valiWhere(); + if ($grade) $model = $model->where('grade', '<', $grade); + $level = $model->where('uid', $uid)->order('grade desc')->field('level_id,is_forever,valid_time,id')->find(); + if (!$level) return false; + if ($level->is_forever) return $level->id; + //会员已经过期 + if (time() < $level->valid_time){ + if($level->status==1){ + $level->status=0; + $level->save(); + } + return self::getUserLevel($uid, $level->grade); + }else + //会员没有过期 + return $level->id; + } + + /* + * 获取会员详细信息 + * @param int $id 会员记录id + * @param string $keyName 字段名 + * @return array + * */ + public static function getUserLevelInfo($id,$keyName=''){ + $vipinfo=self::valiWhere('a')->where('a.id',$id)->field('l.id,a.add_time,a.discount,a.level_id,l.name,l.money,l.icon,l.is_pay') + ->join('__SYSTEM_USER_LEVEL__ l','l.id=a.level_id')->find(); + if($keyName) if(isset($vipinfo[$keyName])) return $vipinfo[$keyName]; else return ''; + return $vipinfo; + } + + /* + * 获取当前用户已成为的vip id + * @param int $uid 用户id + * @return array + * */ + public static function getUserLevelIds($uid) + { + return self::valiWhere()->group('level_id')->where('uid',$uid)->order('grade asc')->column('level_id'); + } + + /* + * 检查是否能成为会员 + * @param int $uid 用户 + * */ + public static function setLevelComplete($uid,$leveNowId=false) + { + $user=User::where('uid',$uid)->find(); + if(!$user) return self::setErrorInfo('没有此用户,无法检测升级会员'); + $level=self::getUserLevel($uid); + if($level===false) + $level_id=0; + else + $level_id=self::getUserLevelInfo($level,'level_id'); + $leveNowId=SystemUserLevel::getNextLevelId($level_id); + if($leveNowId===0) return self::setErrorInfo('暂无可升会员'); + //查找当前需要升级的会员任务 + $taskAll=SystemUserTask::visibleWhere()->where('level_id',$leveNowId)->column('id'); + self::startTrans(); + $res2=true; + try{ + if($level===false){ + //没有成为会员的从用户添加的时间开始算起 + $add_time=$user['add_time']; + }else{ + $add_time=self::getUserLevelInfo($level,'add_time'); + } + //查询并记录任务 + foreach ($taskAll as $id){ + $res=SystemUserTask::setTaskFinish($id,$uid,$add_time); + if(!$res) return self::setErrorInfo(SystemUserTask::getErrorInfo(),true); + } + //获取需要成为会员的任务完成度 + if(SystemUserTask::getTaskComplete($leveNowId,$uid)){ + //设置任务已使用 + $res=SystemUserTask::setTarkStatus($leveNowId,$uid); + if(!$res) return self::setErrorInfo('设置任务状态失败',true); + //记录会员 + $res2=self::setUserLevel($uid,$leveNowId); + } + self::commitTrans(); + return $res2; + }catch (\Exception $e){ + self::rollbackTrans(); + return self::setErrorInfo($e->getMessage()); + } + } + +} \ No newline at end of file diff --git a/application/core/model/user/UserSign.php b/application/core/model/user/UserSign.php new file mode 100644 index 00000000..cb4e016a --- /dev/null +++ b/application/core/model/user/UserSign.php @@ -0,0 +1,143 @@ +'integral','a.type'=>'sign','a.status'=>1,'a.uid'=>$uid]) + ->alias('a')->join("__USER__ u",'u.uid=a.uid')->order('a.add_time desc') + ->field(['FROM_UNIXTIME(a.add_time,"%Y-%m-%d") as add_time','a.title','a.number']) + ->page((int)$page,(int)$limit)->select(); + } + + /* + * 获取用户累计签到次数 + * @Parma int $uid 用户id + * @return int + * */ + public static function getSignSumDay($uid) + { + return self::where(['uid'=>$uid])->count(); + } + + /* + * 获取用户今天是否签到 + * @param int $uid + * */ + public static function getToDayIsSign($uid) + { + return self::where(['uid'=>$uid])->whereTime('add_time','today')->count() ? true : false; + } + + /* + * 获取用户昨天是否签到 + * @param int $uid + * */ + public static function getYesterDayIsSign($uid) + { + return self::where(['uid'=>$uid])->whereTime('add_time','yesterday')->count() ? true : false; + } + + /* + * 获取签到配置 + * @param string + * */ + public static function getSignSystemList($key='sign_day_num') + { + return \app\core\util\GroupDataService::getData($key) ? : []; + } + + /* + * 用户签到 + * @param int $uid 用户uid + * @return boolean + * */ + public static function sign($uid) + { + $sign_list=self::getSignSystemList(); + if(!count($sign_list)) return self::setErrorInfo('请先配置签到天数'); + $user=User::where('uid',$uid)->find(); + $sign_num=0; + //检测昨天是否签到 + if(self::getYesterDayIsSign($uid)){ + if($user->sign_num > (count($sign_list) -1)) $user->sign_num=0; + }else{ + //如果昨天没签到,回退到第一天 + $user->sign_num=0; + } + foreach ($sign_list as $key=>$item){ + if($key==$user->sign_num){ + $sign_num=$item['sign_num']; + break; + } + } + $user->sign_num+=1; + if($user->sign_num == count($sign_list)) + $res1 = self::setSignData($uid,'连续签到奖励',$sign_num,$user->integral); + else + $res1 = self::setSignData($uid,'用户累计签到第'.(self::getSignSumDay($uid)+1).'天',$sign_num,$user->integral); + $res2= User::bcInc($uid,'integral',$sign_num,'uid'); + $res3=$user->save(); + $res = $res1 && $res2 && $res3!==false; + ModelBasic::checkTrans($res); + HookService::afterListen('user_level',$user,false,UserBehavior::class); + if($res) + return $sign_num; + else + return false; + } + + /* + * 获取签到列表按月加载 + * @param int $uid 用户uid + * @param int $page 页码 + * @param int $limit 显示多少条 + * @return array + * */ + public static function getSignMonthList($uid,$page=1,$limit=8) + { + $list=UserBill::where(['uid'=>$uid,'category'=>'integral','type'=>'sign'])->field(['FROM_UNIXTIME(add_time,"%Y-%m") as time','group_concat(id SEPARATOR ",") ids']) + ->group('time')->order('time asc')->page((int)$page,(int)$limit)->select(); + $data=[]; + foreach ($list as $item){ + $value['month']=$item['time']; + $value['list']=UserBill::where('id','in',$item['ids'])->field(['FROM_UNIXTIME(add_time,"%Y-%m-%d") as add_time','title','number'])->select(); + array_push($data,$value); + } + $page++; + return compact('data','page'); + } +} \ No newline at end of file diff --git a/application/core/model/user/UserTaskFinish.php b/application/core/model/user/UserTaskFinish.php new file mode 100644 index 00000000..87506e3e --- /dev/null +++ b/application/core/model/user/UserTaskFinish.php @@ -0,0 +1 @@ + * Date: 2019/3/27 21:42 */ namespace app\core\model\user; use traits\ModelTrait; use basic\ModelBasic; /** * 用户等级完成任务记录 model * Class UserTaskFinish * @package app\core\model\user */ class UserTaskFinish extends ModelBasic { use ModelTrait; /* * 设置任务完成情况 * @param int $uid 用户uid * @param int $task_id 任务id * @return Boolean * */ public static function setFinish($uid,$task_id) { $add_time=time(); if(self::be(['uid'=>$uid,'task_id'=>$task_id])) return true; return self::set(compact('uid','task_id','add_time')); } } \ No newline at end of file diff --git a/application/core/traits/LogicTrait.php b/application/core/traits/LogicTrait.php new file mode 100644 index 00000000..8853bcad --- /dev/null +++ b/application/core/traits/LogicTrait.php @@ -0,0 +1,131 @@ +$carryoutname(); + }catch (\Exception $e){ + return false; + } + } + + /* + * 配置参数 + * + * */ + protected function setConfig(array $config=[]) + { + foreach ($config as $key => $value) { + $this->set($this->items,$key, $value); + } + } + + /* + * 设置参数 + * @param array $array + * @param string $key + * @param string $value + * */ + protected function set(&$array, $key, $value) + { + if (is_null($key)) return $array = $value; + $keys = explode('.', $key); + while (count($keys) > 1) { + $key = array_shift($keys); + if (!isset($array[$key]) || !is_array($array[$key])) { + $array[$key] = []; + } + $array = &$array[$key]; + } + $array[array_shift($keys)] = $value; + return $array; + } + + /* + * 实例化类 + * + * */ + protected function registerProviders() + { + foreach ($this->providers as $key=>$provider) + { + $this->register(new $provider(),$key); + } + } + + /* + * 获取类内配置信息 + * @param object $pimple + * @return this + * */ + protected function register($pimple,$key) + { + $response=$pimple->register($this->items); + if(is_array($response)) { + list($key,$provider)=$response; + $this->$key= $provider; + }else if(is_string($key)){ + $this->$key= $pimple; + } + return $this; + } + + /* + * 实例化本类 + * @param array $config + * @return this + * */ + public static function instance($config=[]) + { + $that=new self(); + $that->setConfig($config); + $that->registerProviders(); + return $that; + } +} \ No newline at end of file diff --git a/application/core/util/ApiLogs.php b/application/core/util/ApiLogs.php new file mode 100644 index 00000000..a08624e0 --- /dev/null +++ b/application/core/util/ApiLogs.php @@ -0,0 +1,110 @@ +getConstants(); + if($code) return isset($stants[$code]) ? $stants[$code] : ''; + else return $stants; + } + + /* + * 错误日志记录 + * + * */ + public static function recodeErrorLog(Exception $exception) + { + $data=[ + 'code'=>$exception->getCode(), + 'msg'=>$exception->getMessage(), + 'file'=>$exception->getFile(), + 'line'=>$exception->getLine(), + ]; + $log="[{$data['code']}] {$data['msg']} [{$data['file']} : {$data['line']}]"; + self::writeLog($log,'e'); + } + /* + * 记录日志 + * $param string $contentlog 日志内容 + * $param string $typeLog 日志类型 + * $param string $dirLog 日志目录 + * */ + public static function writeLog($contentlog='',$typeLog='',$dirLog='ebapi') + { + Log::init([ + 'type' => 'File', + 'path' => LOG_PATH.($dirLog ? $dirLog.'/' : '') + ]); + if($contentlog==='') $contentlog=self::$logInfo; + if($contentlog===null) return false; + if(is_array($contentlog)) $contentlog=var_export($contentlog,true); + if(is_object($contentlog)) $contentlog=var_export($contentlog,true); + switch (strtoupper($typeLog)){ + case 'SQL':case 'S': + Log::sql($contentlog); + break; + case 'ERROR':case 'E': + Log::error($contentlog); + break; + case 'INFO':case 'I': + Log::info($contentlog); + break; + case 'NOTICE':case 'N': + Log::notice($contentlog); + break; + case 'ALERT':case 'A': + Log::alert($contentlog); + break; + case 'LOG':case 'L': + Log::log($contentlog); + break; + } + } + +} \ No newline at end of file diff --git a/application/core/util/GroupDataService.php b/application/core/util/GroupDataService.php new file mode 100644 index 00000000..7f112c13 --- /dev/null +++ b/application/core/util/GroupDataService.php @@ -0,0 +1,67 @@ + + * @day: 2018/01/15 + */ + +namespace app\core\util; + + +use app\admin\model\system\SystemGroupData; +use think\Cache; + +class GroupDataService +{ + protected static $isCaChe=true; + /**获取单个组数据 + * @param $config_name + * @param int $limit + * @return array|bool|false|\PDOStatement|string|\think\Model + */ + public static function getGroupData($config_name,$limit = 0) + { + $cacheName=$limit ? $config_name.'_'.$limit : $config_name; + if(Cache::has($cacheName)){ + return Cache::get($cacheName); + }else { + $data=SystemGroupData::getGroupData($config_name, $limit); + if(self::$isCaChe) Cache::set($cacheName,$data); + return $data; + } + } + + /**获取单个值 + * @param $config_name + * @param int $limit + * @return mixed + */ + public static function getData($config_name,$limit = 0) + { + $cacheName=$limit ? $config_name.'_'.$limit : $config_name; + if(Cache::has($cacheName)){ + return Cache::get($cacheName); + }else{ + $data=SystemGroupData::getAllValue($config_name,$limit); + if(self::$isCaChe) Cache::set($cacheName,$data); + return $data; + } + } + + /** + * TODO 获取单个值 根据id + * @param $id + * @return mixed + */ + public static function getDataNumber($id,$cacheA='eb_data_') + { + $cacheName=$cacheA.$id; + if(Cache::has($cacheName)){ + return Cache::get($cacheName); + }else { + $data=SystemGroupData::getDateValue($id); + if(self::$isCaChe) Cache::set($cacheName,$data); + return $data; + } + } +} \ No newline at end of file diff --git a/application/core/util/MiniProgramService.php b/application/core/util/MiniProgramService.php new file mode 100644 index 00000000..e4c4efe6 --- /dev/null +++ b/application/core/util/MiniProgramService.php @@ -0,0 +1,314 @@ + + * @day: 2017/11/23 + */ + +namespace app\core\util; + +use app\core\behavior\PaymentBehavior; +use EasyWeChat\Foundation\Application; +use EasyWeChat\Payment\Order; +use think\Url; +use service\HookService; +use app\core\implement\ProviderInterface; + +/**微信小程序接口 + * Class WechatMinService + * @package service + */ +class MiniProgramService implements ProviderInterface +{ + private static $instance = null; + + public function register($config) + { + return ['mini_program',new self()]; + } + + public static function options() + { + $wechat = SystemConfigService::more(['site_url','routine_appId','routine_appsecret']); + $payment = SystemConfigService::more(['pay_routine_mchid','pay_routine_key','pay_routine_client_cert','pay_routine_client_key','pay_weixin_open']); + $config = []; + $config['mini_program'] = [ + 'app_id'=>isset($wechat['routine_appId']) ? $wechat['routine_appId']:'', + 'secret'=>isset($wechat['routine_appsecret']) ? $wechat['routine_appsecret']:'', + 'token'=>isset($wechat['wechat_token']) ? $wechat['wechat_token']:'', + 'aes_key'=> isset($wechat['wechat_encodingaeskey']) ? $wechat['wechat_encodingaeskey']:'' + ]; + if(isset($payment['pay_weixin_open']) && $payment['pay_weixin_open'] == 1){ + $config['payment'] = [ + 'app_id'=>isset($wechat['routine_appId']) ? $wechat['routine_appId']:'', + 'merchant_id'=>$payment['pay_routine_mchid'], + 'key'=>$payment['pay_routine_key'], + 'cert_path'=>realpath('.'.$payment['pay_routine_client_cert']), + 'key_path'=>realpath('.'.$payment['pay_routine_client_key']), + 'notify_url'=>$wechat['site_url'].Url::build('/ebapi/notify/notify',['notify_type'=>'routine']) + ]; + } + return $config; + } + public static function application($cache = false) + { + (self::$instance === null || $cache === true) && (self::$instance = new Application(self::options())); + return self::$instance; + } + /** + * 小程序接口 + * @return \EasyWeChat\MiniProgram\MiniProgram + */ + public static function miniprogram() + { + return self::application()->mini_program; + } + + /** + * 获得用户信息 根据code 获取session_key + * @param array|string $openid + * @return $userInfo + */ + public static function getUserInfo($code) + { + $userInfo = self::miniprogram()->sns->getSessionKey($code); + return $userInfo; + } + + /** + * 加密数据解密 + * @param $sessionKey + * @param $iv + * @param $encryptData + * @return $userInfo + */ + public static function encryptor($sessionKey, $iv, $encryptData){ + return self::miniprogram()->encryptor->decryptData($sessionKey, $iv, $encryptData); + } + + /** + * 上传临时素材接口 + * @return \EasyWeChat\Material\Temporary + */ + public static function materialTemporaryService() + { + return self::miniprogram()->material_temporary; + } + + /** + * 客服消息接口 + * @param null $to + * @param null $message + */ + public static function staffService() + { + return self::miniprogram()->staff; + } + + /** + * 微信小程序二维码生成接口 + * @return \EasyWeChat\QRCode\QRCode + */ + public static function qrcodeService() + { + return self::miniprogram()->qrcode; + } + + /**微信小程序二维码生成接口不限量永久 + * @param $scene + * @param null $page + * @param null $width + * @param null $autoColor + * @param array $lineColor + * @return \Psr\Http\Message\StreamInterface + */ + public static function appCodeUnlimitService($scene, $page = null, $width = 430, $autoColor = false, $lineColor = ['r' => 0, 'g' => 0, 'b' => 0]) + { + return self::qrcodeService()->appCodeUnlimit($scene,$page,$width,$autoColor,$lineColor); + } + + + /** + * 模板消息接口 + * @return \EasyWeChat\Notice\Notice + */ + public static function noticeService() + { + return self::miniprogram()->notice; + } + + /**发送小程序模版消息 + * @param $openid + * @param $templateId + * @param array $data + * @param null $url + * @param null $defaultColor + * @return mixed + */ + public static function sendTemplate($openid,$templateId,array $data,$form_id,$link = null,$defaultColor = null) + { + $notice = self::noticeService()->to($openid)->template($templateId)->formId($form_id)->andData($data); + $message = []; + if($link !== null) $message = ['page'=>$link]; + if($defaultColor !== null) $notice->defaultColor($defaultColor); + return $notice->send($message); + } + + + /** + * 支付 + * @return \EasyWeChat\Payment\Payment + */ + public static function paymentService() + { + return self::application()->payment; + } + + /** + * 生成支付订单对象 + * @param $openid + * @param $out_trade_no + * @param $total_fee + * @param $attach + * @param $body + * @param string $detail + * @param string $trade_type + * @param array $options + * @return Order + */ + protected static function paymentOrder($openid,$out_trade_no,$total_fee,$attach,$body,$detail='',$trade_type='JSAPI',$options = []) + { + $total_fee = bcmul($total_fee,100,0); + $order = array_merge(compact('openid','out_trade_no','total_fee','attach','body','detail','trade_type'),$options); + if($order['detail'] == '') unset($order['detail']); + return new Order($order); + } + + /** + * 获得下单ID + * @param $openid + * @param $out_trade_no + * @param $total_fee + * @param $attach + * @param $body + * @param string $detail + * @param string $trade_type + * @param array $options + * @return mixed + */ + public static function paymentPrepare($openid, $out_trade_no, $total_fee, $attach, $body, $detail='', $trade_type='JSAPI', $options = []) + { + $order = self::paymentOrder($openid,$out_trade_no,$total_fee,$attach,$body,$detail,$trade_type,$options); + $result = self::paymentService()->prepare($order); + if ($result->return_code == 'SUCCESS' && $result->result_code == 'SUCCESS'){ + try{ + HookService::listen('wechat_payment_prepare_program',$order,$result->prepay_id,false,PaymentBehavior::class); + }catch (\Exception $e){} + return $result->prepay_id; + }else{ + if($result->return_code == 'FAIL'){ + exception('微信支付错误返回:'.$result->return_msg); + }else if(isset($result->err_code)){ + exception('微信支付错误返回:'.$result->err_code_des); + }else{ + exception('没有获取微信支付的预支付ID,请重新发起支付!'); + } + exit; + } + + } + + /** + * 获得jsSdk支付参数 + * @param $openid + * @param $out_trade_no + * @param $total_fee + * @param $attach + * @param $body + * @param string $detail + * @param string $trade_type + * @param array $options + * @return array|string + */ + public static function jsPay($openid, $out_trade_no, $total_fee, $attach, $body, $detail='', $trade_type='JSAPI', $options = []) + { + return self::paymentService()->configForJSSDKPayment(self::paymentPrepare($openid,$out_trade_no,$total_fee,$attach,$body,$detail,$trade_type,$options)); + } + + /** + * 使用商户订单号退款 + * @param $orderNo + * @param $refundNo + * @param $totalFee + * @param null $refundFee + * @param null $opUserId + * @param string $refundReason + * @param string $type + * @param string $refundAccount + */ + public static function refund($orderNo, $refundNo, $totalFee, $refundFee = null, $opUserId = null, $refundReason = '' , $type = 'out_trade_no', $refundAccount = 'REFUND_SOURCE_UNSETTLED_FUNDS') + { + $totalFee = floatval($totalFee); + $refundFee = floatval($refundFee); + return self::paymentService()->refund($orderNo,$refundNo,$totalFee,$refundFee,$opUserId,$type,$refundAccount,$refundReason); + } + + /** 根据订单号退款 + * @param $orderNo + * @param array $opt + * @return bool + */ + public static function payOrderRefund($orderNo, array $opt) + { + if(!isset($opt['pay_price'])) exception('缺少pay_price'); + $totalFee = floatval(bcmul($opt['pay_price'],100,0)); + $refundFee = isset($opt['refund_price']) ? floatval(bcmul($opt['refund_price'],100,0)) : null; + $refundReason = isset($opt['desc']) ? $opt['desc'] : ''; + $refundNo = isset($opt['refund_id']) ? $opt['refund_id'] : $orderNo; + $opUserId = isset($opt['op_user_id']) ? $opt['op_user_id'] : null; + $type = isset($opt['type']) ? $opt['type'] : 'out_trade_no'; + /*仅针对老资金流商户使用 + REFUND_SOURCE_UNSETTLED_FUNDS---未结算资金退款(默认使用未结算资金退款) + REFUND_SOURCE_RECHARGE_FUNDS---可用余额退款*/ + $refundAccount = isset($opt['refund_account']) ? $opt['refund_account'] : 'REFUND_SOURCE_UNSETTLED_FUNDS'; + try{ + $res = (self::refund($orderNo,$refundNo,$totalFee,$refundFee,$opUserId,$refundReason,$type,$refundAccount)); + if($res->return_code == 'FAIL') exception('退款失败:'.$res->return_msg); + if(isset($res->err_code)) exception('退款失败:'.$res->err_code_des); + }catch (\Exception $e){ + exception($e->getMessage()); + } + return true; + } + + /** + * 微信支付成功回调接口 + */ + public static function handleNotify() + { + self::paymentService()->handleNotify(function($notify, $successful){ + if($successful && isset($notify->out_trade_no)){ + return HookService::listen('wechat_pay_success',$notify,null,true,PaymentBehavior::class); + } + }); + } + + /** + * 作为客服消息发送 + * @param $to + * @param $message + * @return bool + */ + public static function staffTo($to, $message) + { + $staff = self::staffService(); + $staff = is_callable($message) ? $staff->message($message()) : $staff->message($message); + $res = $staff->to($to)->send(); + HookService::afterListen('wechat_staff_to',compact('to','message'),$res); + return $res; + } + + + + +} \ No newline at end of file diff --git a/application/core/util/ProgramTemplateService.php b/application/core/util/ProgramTemplateService.php new file mode 100644 index 00000000..5b4a326a --- /dev/null +++ b/application/core/util/ProgramTemplateService.php @@ -0,0 +1,202 @@ +getConstants(); + if($code) return isset($stants[$code]) ? $stants[$code] : ''; + else return $stants; + } + + public function register($config) + { + + } + + /** + * 根据模板编号获取模板ID + * @param string $tempKey + * @return mixed|string + */ + public static function setTemplateId($tempKey = ''){ + if($tempKey == '') return ''; + return \think\Db::name('RoutineTemplate')->where('tempkey',$tempKey)->where('status',1)->value('tempid'); + } + + /** + * 发送模板消息 + * @param string $tempCode 所需下发的模板编号 + * @param string $openId 接收者(用户)的 openid + * @param array $dataKey 模板内容,不填则下发空模板 + * @param string $formId 表单提交场景下,为 submit 事件带上的 formId;支付场景下,为本次支付的 prepay_id + * @param string $link 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。 + * @param string $emphasisKeyword 模板需要放大的关键词,不填则默认无放大 + * @return bool|mixed + */ + public static function sendTemplate($tempCode = '',$openId = '',$dataKey = array(),$formId = '',$link = '',$defaultColor=null) + { + + if($openId == '' || $tempCode == '' || $formId == '') return false; + try{ + return MiniProgramService::sendTemplate($openId,trim(self::setTemplateId(self::getConstants($tempCode))),$dataKey,$formId,$link,$defaultColor); + }catch (\Exception $e){ + return false; + } + + } + + /**服务进度通知 + * @param array $data + * @param null $url + * @param string $defaultColor + * @return bool + */ + public static function sendAdminNoticeTemplate(array $data,$url = null,$defaultColor = '') + { + $adminIds = explode(',',trim(SystemConfigService::get('site_store_admin_uids'))); + $kefuIds = ServiceModel::where('notify',1)->column('uid'); + if(empty($adminIds[0])){ + $adminList = array_unique($kefuIds); + }else{ + $adminList = array_unique(array_merge($adminIds,$kefuIds)); + } + if(!is_array($adminList) || empty($adminList)) return false; + foreach ($adminList as $uid){ + try{ + $openid = WechatUser::uidToRoutineOpenid($uid); + }catch (\Exception $e){ + continue; + } +// self::sendTemplate($openid,self::ADMIN_NOTICE,$data,$url,$defaultColor); + } + } + + /** + * 返回所有支持的行业列表 + * @return \EasyWeChat\Support\Collection + */ + public static function getIndustry() + { + return MiniProgramService::noticeService()->getIndustry(); + } + + /** + * 修改账号所属行业 + * 主行业 副行业 代码 + * IT科技 互联网/电子商务 1 + * IT科技 IT软件与服务 2 + * IT科技 IT硬件与设备 3 + * IT科技 电子技术 4 + * IT科技 通信与运营商 5 + * IT科技 网络游戏 6 + * 金融业 银行 7 + * 金融业 基金|理财|信托 8 + * 金融业 保险 9 + * 餐饮 餐饮 10 + * 酒店旅游 酒店 11 + * 酒店旅游 旅游 12 + * 运输与仓储 快递 13 + * 运输与仓储 物流 14 + * 运输与仓储 仓储 15 + * 教育 培训 16 + * 教育 院校 17 + * 政府与公共事业 学术科研 18 + * 政府与公共事业 交警 19 + * 政府与公共事业 博物馆 20 + * 政府与公共事业 公共事业|非盈利机构 21 + * 医药护理 医药医疗 22 + * 医药护理 护理美容 23 + * 医药护理 保健与卫生 24 + * 交通工具 汽车相关 25 + * 交通工具 摩托车相关 26 + * 交通工具 火车相关 27 + * 交通工具 飞机相关 28 + * 房地产 建筑 29 + * 房地产 物业 30 + * 消费品 消费品 31 + * 商业服务 法律 32 + * 商业服务 会展 33 + * 商业服务 中介服务 34 + * 商业服务 认证 35 + * 商业服务 审计 36 + * 文体娱乐 传媒 37 + * 文体娱乐 体育 38 + * 文体娱乐 娱乐休闲 39 + * 印刷 印刷 40 + * 其它 其它 41 + * @param $industryId1 + * @param $industryId2 + * @return \EasyWeChat\Support\Collection + */ + public static function setIndustry($industryId1, $industryId2) + { + return MiniProgramService::noticeService()->setIndustry($industryId1, $industryId2); + } + + /** + * 获取所有模板列表 + * @return \EasyWeChat\Support\Collection + */ + public static function getPrivateTemplates() + { + return MiniProgramService::noticeService()->getPrivateTemplates(); + } + + /** + * 删除指定ID的模板 + * @param $templateId + * @return \EasyWeChat\Support\Collection + */ + public static function deletePrivateTemplate($templateId) + { + return MiniProgramService::noticeService()->deletePrivateTemplate($templateId); + } + + + /** + * 添加模板并获取模板ID + * @param $shortId + * @return \EasyWeChat\Support\Collection + */ + public static function addTemplate($shortId) + { + return MiniProgramService::noticeService()->addTemplate($shortId); + } +} \ No newline at end of file diff --git a/application/core/util/QrcodeService.php b/application/core/util/QrcodeService.php new file mode 100644 index 00000000..d30ef9d3 --- /dev/null +++ b/application/core/util/QrcodeService.php @@ -0,0 +1,36 @@ + + * @day: 2017/10/24 + */ + +namespace app\core\util; + + +use app\admin\model\wechat\WechatQrcode as QrcodeModel; + +class QrcodeService +{ + /** + * 获取临时二维码 单个 + * */ + public static function getTemporaryQrcode($type,$id){ + return QrcodeModel::getTemporaryQrcode($type,$id)->toArray(); + }/** + * 获取永久二维码 单个 + * */ + public static function getForeverQrcode($type,$id){ + return QrcodeModel::getForeverQrcode($type,$id)->toArray(); + } + + public static function getQrcode($id,$type = 'id') + { + return QrcodeModel::getQrcode($id,$type); + } + + public static function scanQrcode($id,$type = 'id') + { + return QrcodeModel::scanQrcode($id,$type); + } +} \ No newline at end of file diff --git a/application/core/util/ReturnCode.php b/application/core/util/ReturnCode.php new file mode 100644 index 00000000..0c31b92b --- /dev/null +++ b/application/core/util/ReturnCode.php @@ -0,0 +1,41 @@ + + * Date: 2019/4/3 16:36 + */ + +namespace app\core\util; + +class ReturnCode +{ + //操作成功 + const SUCCESS = 200; + //普通错误 + const ERROR = 400; + //系统错误 + const SYSTEM_ERROR=405; + //用户token验证成功,用户信息获取失败 + const USER_TOKEN_ERROR=402; + //用户被禁止登录 + const USER_STATUS_ERROR=402; + //access_token验证失效 + const ACCESS_TOKEN_TIMEOUT=-100; + //数据库保存失败 + const DB_SAVE_ERROR = -1; + //数据库查询失败 + const DB_READ_ERROR = -2; + //api版本号不存在 + const EMPTY_PARAMS = -3; + //api版本号不匹配 + const VERSION_INVALID = -4; + + public static function getConstants($code='') { + $oClass = new \ReflectionClass(__CLASS__); + $stants=$oClass->getConstants(); + if($code) return isset($stants[$code]) ? $stants[$code] : ''; + else return $stants; + } + +} \ No newline at end of file diff --git a/application/core/util/SystemConfigService.php b/application/core/util/SystemConfigService.php new file mode 100644 index 00000000..af87e9d5 --- /dev/null +++ b/application/core/util/SystemConfigService.php @@ -0,0 +1,64 @@ + + * @day: 2017/11/23 + */ + +namespace app\core\util; + + +use app\admin\model\system\SystemConfig; + +/** 获取系统配置服务类 + * Class SystemConfigService + * @package service + */ +class SystemConfigService +{ + protected static $configList = null; + + public static $ProtectedKey=[ + 'wechat_appid','wechat_appsecret','wechat_token','wechat_encodingaeskey','wechat_encode', + 'pay_weixin_mchid','pay_weixin_client_cert','pay_weixin_client_key','pay_weixin_key','pay_weixin_open', + 'routine_appId','routine_appsecret', + 'pay_routine_mchid','pay_routine_key','pay_routine_client_cert','pay_routine_client_key','pay_weixin_open' + ]; + + /**获取系统配置 + * @param $key + * @return mixed|null + */ + public static function config($key) + { + if(self::$configList === null) self::$configList = self::getAll(); + return isset(self::$configList[$key]) ? self::$configList[$key] : null; + } + + /**获取单个配置效率更高 + * @param $key + * @return bool|mixed + */ + public static function get($key) + { + return SystemConfig::getValue($key); + } + + /** 获取多个配置 + * @param $keys ',' 隔开 + * @return array + */ + public static function more($keys) + { + return SystemConfig::getMore($keys); + } + + /**获取全部配置 + * @return array + */ + public static function getAll() + { + return SystemConfig::getAllConfig()?:[]; + } + +} \ No newline at end of file diff --git a/application/core/util/Template.php b/application/core/util/Template.php new file mode 100644 index 00000000..c1f47824 --- /dev/null +++ b/application/core/util/Template.php @@ -0,0 +1,25 @@ + + * Date: 2019/4/3 16:36 + */ + +namespace app\core\util; + +use app\core\traits\LogicTrait; + +/** 模版消息类 + * Class Template + * @package app\core\util + */ +class Template +{ + use LogicTrait; + + protected $providers=[ + 'routine_two'=>ProgramTemplateService::class, + ]; + +} \ No newline at end of file diff --git a/application/core/util/TokenService.php b/application/core/util/TokenService.php new file mode 100644 index 00000000..181d25f5 --- /dev/null +++ b/application/core/util/TokenService.php @@ -0,0 +1,237 @@ + $value) { + $key < $strCount && $strArr[$key].=$value; + } + return str_replace('=', 'O0O0O', join('', $strArr)); + } + + /** + * 通用解密 + * @param String $string 需要解密的字串 + * @param String $skey 解密KEY + * @return String + */ + private static function deCode($string) { + $skey = array_reverse(str_split(self::$KEY)); + $strArr = str_split(str_replace('O0O0O', '=', $string), 2); + $strCount = count($strArr); + foreach ($skey as $key => $value) { + $key < $strCount && $strArr[$key] = rtrim($strArr[$key], $value); + } + return base64_decode(join('', $strArr)); + } + + /* + * DES 加密 + * @param string $data 待加密明文 + * @param string $deskey 加密秘钥 + * @return string + **/ + private static function DesNncrypt($data, $key='') + { + $deskey=$key=='' ? self::$sKey : $key; + if(strlen($deskey) > 8) $deskey=substr($deskey,0,8);//php加密秘钥只能为8位 + if(function_exists('openssl_encrypt')){ + $data = openssl_encrypt($data, 'AES-128-ECB', $deskey, OPENSSL_RAW_DATA); + $data = strtolower(bin2hex($data)); + return $data; + }else{ + $blocksize = mcrypt_get_block_size(MCRYPT_DES,MCRYPT_MODE_ECB); + $pad = $blocksize - (strlen($data) % $blocksize); + $data1 = $data. str_repeat(chr($pad),$pad); + $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_DES,MCRYPT_MODE_ECB),MCRYPT_RAND); //初始化向量 + $data_encrypt = mcrypt_encrypt(MCRYPT_DES,$deskey,$data1,MCRYPT_MODE_ECB);//加密函数 + $datastr = bin2hex($data_encrypt); + return $datastr; + } + + } + /* + * DES 解密 + * @param string $data 待解密密文 + * @param string $deskey 加密秘钥 + * @return string + */ + private static function DesDecrypt($endata,$deskey=''){ + $deskey=$deskey=='' ? self::$sKey : $deskey; + if(strlen($deskey) > 8) $deskey=substr($deskey,0,8);//php加密秘钥只能为8位 + if(function_exists('openssl_encrypt')){ + $decrypted = openssl_decrypt(hex2bin($endata), 'AES-128-ECB', $deskey, OPENSSL_RAW_DATA); + return $decrypted; + }else{ + $de_datastr = $endata !== false && preg_match('/^[0-9a-fA-F]+$/i',$endata) ? pack('H*',$endata):false; + $data_decrypt = mcrypt_decrypt(MCRYPT_DES,$deskey,$de_datastr,MCRYPT_MODE_ECB,null);//解密函数 + $ret = self::_pkcs5Unpad($data_decrypt); + $de_data = trim($ret); + return $de_data; + } + } + + private static function _pkcs5Unpad($text){ + $pad = ord($text{strlen($text)-1}); + if($pad > strlen($text)) return false; + if(strspn($text,chr($pad),strlen($text)-$pad) != $pad) return false; + $ret = substr($text,0,-1*$pad); + return trim($ret); + } + /** + * 生成随机填充码 + * @return string 10位 + * @return string + */ + private static function createNonceStr($length = 5) + { + $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + $str = ""; + for ($i = 0; $i < $length; $i++) { + $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1); + } + return "crmeb".$str; + } +} \ No newline at end of file diff --git a/application/core/util/WechatService.php b/application/core/util/WechatService.php new file mode 100644 index 00000000..fadb7c77 --- /dev/null +++ b/application/core/util/WechatService.php @@ -0,0 +1,559 @@ + + * @day: 2017/11/23 + */ + +namespace app\core\util; + +use app\admin\model\wechat\WechatMessage; +use behavior\wechat\MessageBehavior; +use behavior\wechat\PaymentBehavior; +use EasyWeChat\Foundation\Application; +use EasyWeChat\Message\Article; +use EasyWeChat\Message\Image; +use EasyWeChat\Message\Material; +use EasyWeChat\Message\News; +use EasyWeChat\Message\Text; +use EasyWeChat\Message\Video; +use EasyWeChat\Message\Voice; +use EasyWeChat\Payment\Order; +use EasyWeChat\Server\Guard; +use EasyWeChat\Support\XML; +use think\Url; +use think\Request; +use service\HookService; + +class WechatService +{ + private static $instance = null; + + public static function options() + { + $wechat = SystemConfigService::more(['wechat_appid','wechat_appsecret','wechat_token','wechat_encodingaeskey','wechat_encode']); + $payment = SystemConfigService::more(['pay_weixin_mchid','pay_weixin_client_cert','pay_weixin_client_key','pay_weixin_key','pay_weixin_open']); + $config = [ + 'app_id'=>isset($wechat['wechat_appid']) ? $wechat['wechat_appid']:'', + 'secret'=>isset($wechat['wechat_appsecret']) ? $wechat['wechat_appsecret']:'', + 'token'=>isset($wechat['wechat_token']) ? $wechat['wechat_token']:'', + 'guzzle' => [ + 'timeout' => 10.0, // 超时时间(秒) + ], + ]; + if(isset($wechat['wechat_encode']) && (int)$wechat['wechat_encode']>0 && isset($wechat['wechat_encodingaeskey']) && !empty($wechat['wechat_encodingaeskey'])) + $config['aes_key'] = $wechat['wechat_encodingaeskey']; + if(isset($payment['pay_weixin_open']) && $payment['pay_weixin_open'] == 1){ + $config['payment'] = [ + 'merchant_id'=>$payment['pay_weixin_mchid'], + 'key'=>$payment['pay_weixin_key'], + 'cert_path'=>realpath('.'.$payment['pay_weixin_client_cert']), + 'key_path'=>realpath('.'.$payment['pay_weixin_client_key']), + //'notify_url'=>SystemConfigService::get('site_url').Url::build('wap/Wechat/notify') + 'notify_url'=>Request::instance()->domain().Url::build('wap/Wechat/notify') + ]; + } + return $config; + } + + + + public static function application($cache = false) + { + (self::$instance === null || $cache === true) && (self::$instance = new Application(self::options())); + return self::$instance; + } + + public static function serve() + { + $wechat = self::application(true); + $server = $wechat->server; + self::hook($server); + $response = $server->serve(); + exit($response->getContent()); + } + + /** + * 监听行为 + * @param Guard $server + */ + private static function hook($server) + { + $server->setMessageHandler(function($message){ + $behavior = MessageBehavior::class; + HookService::beforeListen('wechat_message',$message,null,true,$behavior); + switch ($message->MsgType){ + case 'event': + switch (strtolower($message->Event)){ + case 'subscribe': + if(isset($message->EventKey)){ + $response = HookService::resultListen('wechat_event_scan_subscribe',$message,$message->EventKey,true,$behavior); + }else{ + $response = HookService::resultListen('wechat_event_subscribe',$message,null,true,$behavior); + } + break; + case 'unsubscribe': + $response = HookService::resultListen('wechat_event_unsubscribe',$message,null,true,$behavior); + break; + case 'scan': + $response = HookService::resultListen('wechat_event_scan',$message,$message->EventKey,true,$behavior); + break; + case 'location': + $response = HookService::resultListen('wechat_event_location',$message,null,true,$behavior); + break; + case 'click': + $response = HookService::resultListen('wechat_event_click',$message,null,true,$behavior); + break; + case 'view': + $response = HookService::resultListen('wechat_event_view',$message,null,true,$behavior); + break; + } + break; + case 'text': + $response = HookService::resultListen('wechat_message_text',$message,null,true,$behavior); + break; + case 'image': + $response = HookService::resultListen('wechat_message_image',$message,null,true,$behavior); + break; + case 'voice': + $response = HookService::resultListen('wechat_message_voice',$message,null,true,$behavior); + break; + case 'video': + $response = HookService::resultListen('wechat_message_video',$message,null,true,$behavior); + break; + case 'location': + $response = HookService::resultListen('wechat_message_location',$message,null,true,$behavior); + break; + case 'link': + $response = HookService::resultListen('wechat_message_link',$message,null,true,$behavior); + break; + // ... 其它消息 + default: + $response = HookService::resultListen('wechat_message_other',$message,null,true,$behavior); + break; + } + + return $response; + }); + } + + + /** + * 多客服消息转发 + * @param string $account + * @return \EasyWeChat\Message\Transfer + */ + public static function transfer($account = '') + { + $transfer = new \EasyWeChat\Message\Transfer(); + return empty($account) ? $transfer : $transfer->to($account); + } + + + /** + * 上传永久素材接口 + * @return \EasyWeChat\Material\Material + */ + public static function materialService() + { + return self::application()->material; + } + + /** + * 上传临时素材接口 + * @return \EasyWeChat\Material\Temporary + */ + public static function materialTemporaryService() + { + return self::application()->material_temporary; + } + + /** + * 用户接口 + * @return \EasyWeChat\User\User + */ + public static function userService() + { + return self::application()->user; + } + + + /** + * 客服消息接口 + * @param null $to + * @param null $message + */ + public static function staffService() + { + return self::application()->staff; + } + + /** + * 微信公众号菜单接口 + * @return \EasyWeChat\Menu\Menu + */ + public static function menuService() + { + return self::application()->menu; + } + + /** + * 微信二维码生成接口 + * @return \EasyWeChat\QRCode\QRCode + */ + public static function qrcodeService() + { + return self::application()->qrcode; + } + + /** + * 短链接生成接口 + * @return \EasyWeChat\Url\Url + */ + public static function urlService() + { + return self::application()->url; + } + + /** + * 用户授权 + * @return \Overtrue\Socialite\Providers\WeChatProvider + */ + public static function oauthService() + { + return self::application()->oauth; + } + + /** + * 模板消息接口 + * @return \EasyWeChat\Notice\Notice + */ + public static function noticeService() + { + return self::application()->notice; + } + + public static function sendTemplate($openid,$templateId,array $data,$url = null,$defaultColor = null) + { + $notice = self::noticeService()->to($openid)->template($templateId)->andData($data); + if($url !== null) $notice->url($url); + if($defaultColor !== null) $notice->defaultColor($defaultColor); + return $notice->send(); + } + + + /** + * 支付 + * @return \EasyWeChat\Payment\Payment + */ + public static function paymentService() + { + return self::application()->payment; + } + + public static function downloadBill($day,$type = 'ALL') + { +// $payment = self::paymentService(); +// $merchant = $payment->getMerchant(); +// $params = [ +// 'appid' => $merchant->app_id, +// 'bill_date'=>$day, +// 'bill_type'=>strtoupper($type), +// 'mch_id'=> $merchant->merchant_id, +// 'nonce_str' => uniqid() +// ]; +// $params['sign'] = \EasyWeChat\Payment\generate_sign($params, $merchant->key, 'md5'); +// $xml = XML::build($params); +// dump(self::paymentService()->downloadBill($day)->getContents()); +// dump($payment->getHttp()->request('https://api.mch.weixin.qq.com/pay/downloadbill','POST',[ +// 'body' => $xml, +// 'stream'=>true +// ])->getBody()->getContents()); + } + + public static function userTagService() + { + return self::application()->user_tag; + } + + public static function userGroupService() + { + return self::application()->user_group; + } + + /** + * 生成支付订单对象 + * @param $openid + * @param $out_trade_no + * @param $total_fee + * @param $attach + * @param $body + * @param string $detail + * @param string $trade_type + * @param array $options + * @return Order + */ + protected static function paymentOrder($openid,$out_trade_no,$total_fee,$attach,$body,$detail='',$trade_type='JSAPI',$options = []) + { + $total_fee = bcmul($total_fee,100,0); + $order = array_merge(compact('openid','out_trade_no','total_fee','attach','body','detail','trade_type'),$options); + if($order['detail'] == '') unset($order['detail']); + return new Order($order); + } + + /** + * 获得下单ID + * @param $openid + * @param $out_trade_no + * @param $total_fee + * @param $attach + * @param $body + * @param string $detail + * @param string $trade_type + * @param array $options + * @return mixed + */ + public static function paymentPrepare($openid, $out_trade_no, $total_fee, $attach, $body, $detail='', $trade_type='JSAPI', $options = []) + { + $order = self::paymentOrder($openid,$out_trade_no,$total_fee,$attach,$body,$detail,$trade_type,$options); + $result = self::paymentService()->prepare($order); + if ($result->return_code == 'SUCCESS' && $result->result_code == 'SUCCESS'){ + try{ + HookService::listen('wechat_payment_prepare',$order,$result->prepay_id,false,PaymentBehavior::class); + }catch (\Exception $e){} + return $result->prepay_id; + }else{ + if($result->return_code == 'FAIL'){ + exception('微信支付错误返回:'.$result->return_msg); + }else if(isset($result->err_code)){ + exception('微信支付错误返回:'.$result->err_code_des); + }else{ + exception('没有获取微信支付的预支付ID,请重新发起支付!'); + } + exit; + } + + } + + /** + * 获得jsSdk支付参数 + * @param $openid + * @param $out_trade_no + * @param $total_fee + * @param $attach + * @param $body + * @param string $detail + * @param string $trade_type + * @param array $options + * @return array|string + */ + public static function jsPay($openid, $out_trade_no, $total_fee, $attach, $body, $detail='', $trade_type='JSAPI', $options = []) + { + return self::paymentService()->configForJSSDKPayment(self::paymentPrepare($openid,$out_trade_no,$total_fee,$attach,$body,$detail,$trade_type,$options)); + } + + /** + * 使用商户订单号退款 + * @param $orderNo + * @param $refundNo + * @param $totalFee + * @param null $refundFee + * @param null $opUserId + * @param string $refundReason + * @param string $type + * @param string $refundAccount + */ + public static function refund($orderNo, $refundNo, $totalFee, $refundFee = null, $opUserId = null, $refundReason = '' , $type = 'out_trade_no', $refundAccount = 'REFUND_SOURCE_UNSETTLED_FUNDS') + { + $totalFee = floatval($totalFee); + $refundFee = floatval($refundFee); + return self::paymentService()->refund($orderNo,$refundNo,$totalFee,$refundFee,$opUserId,$type,$refundAccount,$refundReason); + } + + public static function payOrderRefund($orderNo, array $opt) + { + if(!isset($opt['pay_price'])) exception('缺少pay_price'); + $totalFee = floatval(bcmul($opt['pay_price'],100,0)); + $refundFee = isset($opt['refund_price']) ? floatval(bcmul($opt['refund_price'],100,0)) : null; + $refundReason = isset($opt['desc']) ? $opt['desc'] : ''; + $refundNo = isset($opt['refund_id']) ? $opt['refund_id'] : $orderNo; + $opUserId = isset($opt['op_user_id']) ? $opt['op_user_id'] : null; + $type = isset($opt['type']) ? $opt['type'] : 'out_trade_no'; + /*仅针对老资金流商户使用 + REFUND_SOURCE_UNSETTLED_FUNDS---未结算资金退款(默认使用未结算资金退款) + REFUND_SOURCE_RECHARGE_FUNDS---可用余额退款*/ + $refundAccount = isset($opt['refund_account']) ? $opt['refund_account'] : 'REFUND_SOURCE_UNSETTLED_FUNDS'; + try{ + $res = (self::refund($orderNo,$refundNo,$totalFee,$refundFee,$opUserId,$refundReason,$type,$refundAccount)); + if($res->return_code == 'FAIL') exception('退款失败:'.$res->return_msg); + if(isset($res->err_code)) exception('退款失败:'.$res->err_code_des); + }catch (\Exception $e){ + exception($e->getMessage()); + } + return true; + } + + /** + * 微信支付成功回调接口 + */ + public static function handleNotify() + { + self::paymentService()->handleNotify(function($notify, $successful){ + if($successful && isset($notify->out_trade_no)){ + WechatMessage::setOnceMessage($notify,$notify->openid,'payment_success',$notify->out_trade_no); + return HookService::listen('wechat_pay_success',$notify,null,true,PaymentBehavior::class); + } + }); + } + + /** + * jsSdk + * @return \EasyWeChat\Js\Js + */ + public static function jsService() + { + return self::application()->js; + } + + public static function jsSdk($url = '') + { + $apiList = ['onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareWeibo', 'onMenuShareQZone', 'startRecord', 'stopRecord', 'onVoiceRecordEnd', 'playVoice', 'pauseVoice', 'stopVoice', 'onVoicePlayEnd', 'uploadVoice', 'downloadVoice', 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'translateVoice', 'getNetworkType', 'openLocation', 'getLocation', 'hideOptionMenu', 'showOptionMenu', 'hideMenuItems', 'showMenuItems', 'hideAllNonBaseMenuItem', 'showAllNonBaseMenuItem', 'closeWindow', 'scanQRCode', 'chooseWXPay', 'openProductSpecificView', 'addCard', 'chooseCard', 'openCard']; + $jsService = self::jsService(); + if($url) $jsService->setUrl($url); + try{ + return $jsService->config($apiList); + }catch (\Exception $e){ + return '{}'; + } + + } + + + /** + * 回复文本消息 + * @param string $content 文本内容 + * @return Text + */ + public static function textMessage($content) + { + return new Text(compact('content')); + } + + /** + * 回复图片消息 + * @param string $media_id 媒体资源 ID + * @return Image + */ + public static function imageMessage($media_id) + { + return new Image(compact('media_id')); + } + + /** + * 回复视频消息 + * @param string $media_id 媒体资源 ID + * @param string $title 标题 + * @param string $description 描述 + * @param null $thumb_media_id 封面资源 ID + * @return Video + */ + public static function videoMessage($media_id, $title = '', $description = '...', $thumb_media_id = null) + { + return new Video(compact('media_id','title','description','thumb_media_id')); + } + + /** + * 回复声音消息 + * @param string $media_id 媒体资源 ID + * @return Voice + */ + public static function voiceMessage($media_id) + { + return new Voice(compact('media_id')); + } + + /** + * 回复图文消息 + * @param string|array $title 标题 + * @param string $description 描述 + * @param string $url URL + * @param string $image 图片链接 + */ + public static function newsMessage($title, $description = '...', $url = '', $image = '') + { + if(is_array($title)){ + if(isset($title[0]) && is_array($title[0])){ + $newsList = []; + foreach ($title as $news){ + $newsList[] = self::newsMessage($news); + } + return $newsList; + }else{ + $data = $title; + } + }else{ + $data = compact('title','description','url','image'); + } + return new News($data); + } + + /** + * 回复文章消息 + * @param string|array $title 标题 + * @param string $thumb_media_id 图文消息的封面图片素材id(必须是永久 media_ID) + * @param string $source_url 图文消息的原文地址,即点击“阅读原文”后的URL + * @param string $content 图文消息的具体内容,支持HTML标签,必须少于2万字符,小于1M,且此处会去除JS + * @param string $author 作者 + * @param string $digest 图文消息的摘要,仅有单图文消息才有摘要,多图文此处为空 + * @param int $show_cover_pic 是否显示封面,0为false,即不显示,1为true,即显示 + * @param int $need_open_comment 是否打开评论,0不打开,1打开 + * @param int $only_fans_can_comment 是否粉丝才可评论,0所有人可评论,1粉丝才可评论 + * @return Article + */ + public static function articleMessage($title, $thumb_media_id, $source_url, $content = '', $author = '', $digest = '', $show_cover_pic = 0, $need_open_comment = 0, $only_fans_can_comment = 1) + { + $data = is_array($title) ? $title : compact('title','thumb_media_id','source_url','content','author','digest','show_cover_pic','need_open_comment','only_fans_can_comment'); + return new Article($data); + } + + /** + * 回复素材消息 + * @param string $type [mpnews、 mpvideo、voice、image] + * @param string $media_id 素材 ID + * @return Material + */ + public static function materialMessage($type, $media_id) + { + return new Material($type,$media_id); + } + + /** + * 作为客服消息发送 + * @param $to + * @param $message + * @return bool + */ + public static function staffTo($to, $message) + { + $staff = self::staffService(); + $staff = is_callable($message) ? $staff->message($message()) : $staff->message($message); + $res = $staff->to($to)->send(); + HookService::afterListen('wechat_staff_to',compact('to','message'),$res); + return $res; + } + + /** + * 获得用户信息 + * @param array|string $openid + * @return \EasyWeChat\Support\Collection + */ + public static function getUserInfo($openid) + { + $userService = self::userService(); + $userInfo = is_array($openid) ? $userService->batchGet($openid) : $userService->get($openid); + return $userInfo; + } + + + +} \ No newline at end of file diff --git a/application/core/util/WechatTemplateService.php b/application/core/util/WechatTemplateService.php new file mode 100644 index 00000000..1dbcb131 --- /dev/null +++ b/application/core/util/WechatTemplateService.php @@ -0,0 +1,189 @@ + + * @day: 2018/01/06 + */ + +namespace app\core\util; + +use app\wap\model\user\WechatUser; +use app\admin\model\wechat\WechatTemplate as WechatTemplateModel;//待完善 +use app\admin\model\wechat\StoreService as ServiceModel; + +class WechatTemplateService +{ + /** + * 主营行业:IT科技 互联网|电子商务 + * 副营行业:IT科技 IT软件与服务 + */ + + //订单生成通知 + const ORDER_CREATE = 'OPENTM205213550'; + + //订单支付成功 + const ORDER_PAY_SUCCESS = 'OPENTM207791277'; + + //订单发货提醒(快递) + const ORDER_POSTAGE_SUCCESS = 'OPENTM200565259'; + + //订单发货提醒(送货) + const ORDER_DELIVER_SUCCESS = 'OPENTM207707249'; + + //订单收货通知 + const ORDER_TAKE_SUCCESS = 'OPENTM413386489'; + + //退款进度通知 + const ORDER_REFUND_STATUS = 'OPENTM410119152'; + + //帐户资金变动提醒 + const USER_BALANCE_CHANGE = 'OPENTM405847076'; + + //客服通知提醒 + const SERVICE_NOTICE = 'OPENTM204431262'; + + //服务进度提醒 + const ADMIN_NOTICE = 'OPENTM408237350'; + + //拼团成功通知 + const ORDER_USER_GROUPS_SUCCESS = 'OPENTM407456411'; + + //拼团失败通知 + const ORDER_USER_GROUPS_LOSE = 'OPENTM401113750'; + + public static function getConstants($code='') { + $oClass = new \ReflectionClass(__CLASS__); + $stants=$oClass->getConstants(); + if($code) return isset($stants[$code]) ? $stants[$code] : ''; + else return $stants; + } + + public static function sendTemplate($openid,$templateId,array $data,$url = null,$defaultColor = '') + { + $tempid = WechatTemplateModel::where('tempkey',$templateId)->where('status',1)->value('tempid'); + if(!$tempid) return false; + try{ + return WechatService::sendTemplate($openid,$tempid,$data,$url,$defaultColor); + }catch (\Exception $e){ + return false; + } + } + + /**服务进度通知 + * @param array $data + * @param null $url + * @param string $defaultColor + * @return bool + */ + public static function sendAdminNoticeTemplate(array $data,$url = null,$defaultColor = '') + { + $adminIds = explode(',',trim(SystemConfigService::get('site_store_admin_uids'))); + $kefuIds = ServiceModel::where('notify',1)->column('uid'); + if(empty($adminIds[0])){ + $adminList = array_unique($kefuIds); + }else{ + $adminList = array_unique(array_merge($adminIds,$kefuIds)); + } + if(!is_array($adminList) || empty($adminList)) return false; + foreach ($adminList as $uid){ + try{ + $openid = WechatUser::uidToOpenid($uid); + }catch (\Exception $e){ + continue; + } + self::sendTemplate($openid,self::ADMIN_NOTICE,$data,$url,$defaultColor); + } + } + + /** + * 返回所有支持的行业列表 + * @return \EasyWeChat\Support\Collection + */ + public static function getIndustry() + { + return WechatService::noticeService()->getIndustry(); + } + + /** + * 修改账号所属行业 + * 主行业 副行业 代码 + * IT科技 互联网/电子商务 1 + * IT科技 IT软件与服务 2 + * IT科技 IT硬件与设备 3 + * IT科技 电子技术 4 + * IT科技 通信与运营商 5 + * IT科技 网络游戏 6 + * 金融业 银行 7 + * 金融业 基金|理财|信托 8 + * 金融业 保险 9 + * 餐饮 餐饮 10 + * 酒店旅游 酒店 11 + * 酒店旅游 旅游 12 + * 运输与仓储 快递 13 + * 运输与仓储 物流 14 + * 运输与仓储 仓储 15 + * 教育 培训 16 + * 教育 院校 17 + * 政府与公共事业 学术科研 18 + * 政府与公共事业 交警 19 + * 政府与公共事业 博物馆 20 + * 政府与公共事业 公共事业|非盈利机构 21 + * 医药护理 医药医疗 22 + * 医药护理 护理美容 23 + * 医药护理 保健与卫生 24 + * 交通工具 汽车相关 25 + * 交通工具 摩托车相关 26 + * 交通工具 火车相关 27 + * 交通工具 飞机相关 28 + * 房地产 建筑 29 + * 房地产 物业 30 + * 消费品 消费品 31 + * 商业服务 法律 32 + * 商业服务 会展 33 + * 商业服务 中介服务 34 + * 商业服务 认证 35 + * 商业服务 审计 36 + * 文体娱乐 传媒 37 + * 文体娱乐 体育 38 + * 文体娱乐 娱乐休闲 39 + * 印刷 印刷 40 + * 其它 其它 41 + * @param $industryId1 + * @param $industryId2 + * @return \EasyWeChat\Support\Collection + */ + public static function setIndustry($industryId1, $industryId2) + { + return WechatService::noticeService()->setIndustry($industryId1, $industryId2); + } + + /** + * 获取所有模板列表 + * @return \EasyWeChat\Support\Collection + */ + public static function getPrivateTemplates() + { + return WechatService::noticeService()->getPrivateTemplates(); + } + + /** + * 删除指定ID的模板 + * @param $templateId + * @return \EasyWeChat\Support\Collection + */ + public static function deletePrivateTemplate($templateId) + { + return WechatService::noticeService()->deletePrivateTemplate($templateId); + } + + + /** + * 添加模板并获取模板ID + * @param $shortId + * @return \EasyWeChat\Support\Collection + */ + public static function addTemplate($shortId) + { + return WechatService::noticeService()->addTemplate($shortId); + } +} \ No newline at end of file