Browse Source

Merge branch 'coupon_rebate'

# Conflicts:
#	.gitignore
#	Envoy.blade.php
#	app/Constants/ErrorCode.php
#	app/Controller/CouponController.php
#	app/Listener/ValidatorFactoryResolvedListener.php
#	app/Service/UserService.php
#	app/Service/UserServiceInterface.php
#	composer.json
#	config/autoload/dependencies.php
#	config/autoload/exceptions.php
#	config/autoload/middlewares.php
#	config/autoload/server.php
#	config/routes.php
master
weigang 5 years ago
parent
commit
6b7e98a92d
  1. 2
      .gitignore
  2. 2
      Envoy.blade.php
  3. 46
      app/Amqp/Consumer/couponRebateConsumer.php
  4. 88
      app/Commons/Log.php
  5. 5
      app/Constants/ErrorCode.php
  6. 21
      app/Constants/LogLabel.php
  7. 39
      app/Constants/SsdbKeysPrefix.php
  8. 8
      app/Controller/AbstractController.php
  9. 27
      app/Controller/AdController.php
  10. 78
      app/Controller/CouponController.php
  11. 86
      app/Controller/CouponRebateController.php
  12. 40
      app/Controller/ParamsTokenController.php
  13. 60
      app/Controller/TestController.php
  14. 33
      app/Exception/Handler/SsdbExceptionHandler.php
  15. 18
      app/Exception/SsdbException.php
  16. 622
      app/Libs/SimpleSSDB.php
  17. 31
      app/Listener/ValidatorFactoryResolvedListener.php
  18. 2
      app/Middleware/Auth/ApiMiddleware.php
  19. 34
      app/Middleware/CorsMiddleware.php
  20. 70
      app/Model/Ad.php
  21. 10
      app/Model/OrderMain.php
  22. 45
      app/Request/CouponGetListRequest.php
  23. 45
      app/Request/CouponRebateReceiveRequest.php
  24. 48
      app/Request/CouponRebateTieRequest.php
  25. 20
      app/Service/AdService.php
  26. 11
      app/Service/AdServiceInterface.php
  27. 25
      app/Service/CommonService.php
  28. 407
      app/Service/CouponRebateService.php
  29. 22
      app/Service/CouponRebateServiceInterface.php
  30. 160
      app/Service/CouponService.php
  31. 18
      app/Service/CouponServiceInterface.php
  32. 20
      app/Service/ParamsTokenServiceInterface.php
  33. 84
      app/Service/ParamsTokenSsdbService.php
  34. 46
      app/TaskWorker/SSDBTask.php
  35. 7
      composer.json
  36. 33
      config/autoload/amqp.php
  37. 9
      config/autoload/dependencies.php
  38. 3
      config/autoload/exceptions.php
  39. 1
      config/autoload/middlewares.php
  40. 3
      config/autoload/server.php
  41. 4
      config/routes.php

2
.gitignore

@ -12,4 +12,4 @@ vendor/
*.lock
.phpunit*
/watch
.vscode/settings.json
.vscode/

2
Envoy.blade.php

@ -21,7 +21,7 @@
cd /lanzu_api
git pull origin master
@if($composer == true)
composer update --lock
composer update --no-dev --lock
@endif
supervisorctl restart lanzu_api
@endtask

46
app/Amqp/Consumer/couponRebateConsumer.php

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace App\Amqp\Consumer;
use App\Constants\SsdbKeysPrefix;
use Hyperf\Amqp\Result;
use Hyperf\Amqp\Annotation\Consumer;
use Hyperf\Amqp\Message\ConsumerMessage;
use Hyperf\Utils\ApplicationContext;
use PhpAmqpLib\Message\AMQPMessage;
use App\Service\CouponRebateService;
use App\Service\CouponRebateServiceInterface;
use Hyperf\Di\Annotation\Inject;
/**
* @Consumer(exchange="couponRebate1", routingKey="couponRebate1", queue="couponRebate1", name ="couponRebateConsumer", nums=1)
*/
class couponRebateConsumer extends ConsumerMessage
{
/**
* @Inject
* @var CouponRebateService
*/
protected $CouponRebateService;
public function consumeMessage($data, AMQPMessage $message): string
{
//var_dump($data);
//ar_dump($rebate_id);
//var_dump($message->getBody());
$res = $this->CouponRebateService->couponRebate($data);
//var_dump($res);
if (!$res) {
return Result::REQUEUE;
}
return Result::ACK;
}
public function isEnable(): bool
{
return parent::isEnable();
}
}

88
app/Commons/Log.php

@ -0,0 +1,88 @@
<?php
namespace App\Commons;
use Hyperf\Guzzle\ClientFactory;
class Log
{
/**
* @var \Hyperf\Guzzle\ClientFactory
*/
private $clientFactory;
public function __construct(ClientFactory $clientFactory)
{
$this->clientFactory = $clientFactory;
}
public function getClient()
{
// $options 等同于 GuzzleHttp\Client 构造函数的 $config 参数
$options = [
'timeout' => 2.0,
];
// $client 为协程化的 GuzzleHttp\Client 对象
$client = $this->clientFactory->create($options);
return $client;
}
public function event($labels=null,$datas){
co(function () use ($labels,$datas){
$client = $this->getClient();
$kv = [];
foreach ($datas as $key => $value) {
$kv[] = $key."=".$value;
}
$pushLabels = [];
$event_name = 'event_'.env('APP_ENV');
if(!empty($labels)) $pushLabels[$event_name] = $labels;
/*
* data format:
curl -v -H "Content-Type: application/json" -XPOST -s "http://39.96.12.39:3100/loki/api/v1/push" --data-raw \
'{"streams": [{ "stream": { "foo": "bar2" }, "values": [ [ "1596274538882028800", "fizzbuzz" ] ] }]}'
*/
$ts = $this->getMsecTime() . '000000';
$datas = implode("&",$kv);
$values = [[$ts,$datas]];
$app_name = env('APP_NAME').'_'.env('APP_ENV');
$pushLabels['app']= $app_name;
$pushDatas = [
'streams'=>[
[
'stream'=>$pushLabels,
'values'=>$values,
]
]
];
$client->post(
'http://39.96.12.39:3100/loki/api/v1/push',
[
'headers'=>[
'Content-Type'=>'application/json'
],
'body' => json_encode($pushDatas)
]
);
//var_dump(json_encode($pushDatas) );
});
}
public function push($datas){
$this->event(null,$datas);
}
public function getMsecTime()
{
list($msec, $sec) = explode(' ', microtime());
$msectime = (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
return $msectime;
}
}

5
app/Constants/ErrorCode.php

@ -33,4 +33,9 @@ class ErrorCode extends AbstractConstants
* @Message("Save failure!");
*/
const SAVE_FAILURE = 100;
/**
* @Message("Ssdb Error!")
*/
const SSDB_ERROR = 600;
}

21
app/Constants/LogLabel.php

@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Constants;
use Hyperf\Constants\AbstractConstants;
use Hyperf\Constants\Annotation\Constants;
/**
* @Constants
*/
class LogLabel extends AbstractConstants
{
/**
* @Message("Ssdb Log Label")
*/
const SSDB_LOG = 'ssdb_log';
const COUPON_LOG = 'coupon_log';
}

39
app/Constants/SsdbKeysPrefix.php

@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace App\Constants;
use Hyperf\Constants\AbstractConstants;
use Hyperf\Constants\Annotation\Constants;
/**
* @Constants
*/
class SsdbKeysPrefix extends AbstractConstants
{
/**
* @Message("Params Token Key Prefix")
*/
const PARAMS_TOKEN = 'params_token_';
/**
* @Message("Coupon rebate Key Prefix")
*/
const COUPON_REBATE_RECEIVE = 'coupon_rebate_receive_';
/**
* @Message("Coupon rebate Key Prefix")
*/
const COUPON_REBATE_FORWARD = 'coupon_rebate_forward_';
/**
* @Message("Coupon rebate Key Prefix")
*/
const COUPON_REBATE_REPAY = 'coupon_rebate_repay_';
/**
* @Message("Coupon rebate Key Prefix")
*/
const COUPON_REBATE_ACTIVITY = 'coupon_rebate_activity';
}

8
app/Controller/AbstractController.php

@ -15,9 +15,17 @@ use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Psr\Container\ContainerInterface;
use App\Commons\Log;
abstract class AbstractController
{
/**
* @Inject
* @var Log
*/
protected $log;
/**
* @Inject
* @var ContainerInterface

27
app/Controller/AdController.php

@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace App\Controller;
use App\Service\AdServiceInterface;
use Hyperf\Di\Annotation\Inject;
/**
* 系统AD广告/宣传图控制器
* Class AdController
* @package App\Controller
*/
class AdController extends BaseController
{
/**
* @Inject
* @var AdServiceInterface
*/
protected $adService;
public function banners()
{
return $this->success($this->adService->banners());
}
}

78
app/Controller/CouponController.php

@ -12,85 +12,33 @@ declare(strict_types=1);
namespace App\Controller;
use Hyperf\Di\Annotation\Inject;
use App\Model\CouponUserRecType;
use App\Model\Coupon;
use App\Model\CouponRec;
use Hyperf\DbConnection\Db;
use Hyperf\Redis\Redis;
use Hyperf\Utils\ApplicationContext;
use App\Request\CouponGetListRequest;
use App\Service\CouponServiceInterface;
class CouponController extends BaseController
{
/**
* @Inject
* @var CouponServiceInterface
*/
protected $couponService;
/**
* 获取用户可领取优惠卷接口
*/
public function getSystemCouponUserList()
public function getSystemCouponUserList(CouponGetListRequest $validator)
{
$user_id = $this->request->input('user_id', 0);
$receive_type = $this->request->input('receive_type', 0);
if ($this->empty($user_id) || $this->empty($receive_type)) {
return $this->success(['not_reveive' => []]);
}
$c_ids = [];
// 渠道开启,查询该渠道可以领取的优惠券ID
// 渠道未开启,查询所有优惠券
if (env('SUB_CHANNEL') == 1) {
$c_ids = CouponUserRecType::where('receive_type', $receive_type)->pluck('system_coupon_user_id');
} else {
$c_ids = Coupon::pluck('id');
}
$nowTime = time();
$where = [
['user_id',"=",$user_id]
];
// 渠道开启,查询该用户在此渠道领过的优惠券ID
if (env('SUB_CHANNEL') == 1) {
array_push($where, ['receive_type', "=", $receive_type]);
}
$cr_ids = CouponRec::where($where)->pluck('system_coupon_user_id');
//领过券的ID
$c_ids = $c_ids->toArray();
$cr_ids = $cr_ids->toArray();
// 当前用户可领的优惠券ID
$couponIds = array_diff($c_ids, $cr_ids);
$whereC = [
['u.end_time','>',$nowTime],
['u.start_time','<=',$nowTime],
['u.status','=',1],
];
if (env('SUB_CHANNEL') == 1) {
array_push($whereC, ['type.receive_type','=',$receive_type]);
}
$c = Db::table('ims_system_coupon_user as u')
->where($whereC)
->join('ims_system_coupon_user_receivetype as type', 'u.id', '=', 'type.system_coupon_user_id')
->whereRaw('u.inventory_use < u.inventory and u.inventory-u.inventory_use >= type.one_receive_number')
// ->whereIn('u.id',$c_ids)
// ->whereNotIn('u.id',$cr_ids)
->whereIn('u.id', $couponIds)
->select('u.*','type.one_receive_number')
->orderBy('u.weigh','desc')
// ->orderByRaw('FIELD(u.id, '.implode(", " , $ids).')')
->limit(4)
->get();
foreach ($c as $k => &$v){
if($v->discount_type == 2){
$v->discounts = floatval($v->discounts);
}
}
return $this->success(['not_reveive'=>$c]);
$userId = $this->request->input('user_id', 0);
$receiveType = $this->request->input('receive_type', 0);
$res = $this->couponService->getSystemCouponUserList($userId,$receiveType);
return $this->success($res);
}
//统计用户

86
app/Controller/CouponRebateController.php

@ -0,0 +1,86 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://doc.hyperf.io
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace App\Controller;
use App\Service\CouponRebateServiceInterface;
use Hyperf\Di\Annotation\Inject;
use App\Request\CouponRebateReceiveRequest;
use App\Request\CouponRebateTieRequest;
class CouponRebateController extends BaseController
{
/**
* @Inject
* @var CouponRebateServiceInterface
*/
protected $CouponRebateService;
/**
* 用户是否领取过领取优惠券
*/
public function isCouponRebate()
{
$user_id = $this->request->input('user_id', 0);
$res = $this->CouponRebateService->isCouponRebate($user_id);
return $this->success($res);
}
/**
* 返回活动信息
*/
public function getActiveInfo()
{
$res = $this->CouponRebateService->getActiveInfo();
return $this->success($res);
}
/**
* 用户领取优惠券
*/
public function userReceiveCoupon(CouponRebateReceiveRequest $validator)
{
return $this->success($this->CouponRebateService->userReceiveCoupon($this->request->all()));
}
public function couponRebate()
{
$order_id = $this->request->input('order_id', 0);
$res = $this->CouponRebateService->couponRebate($order_id);
return $this->success($res);
}
/**
* 将优惠券绑定活动
*/
public function tieCouponActive(CouponRebateTieRequest $validator)
{
$couponForward = $this->request->input('coupon_forward_ids',[]);
$couponForward = is_array($couponForward) ? implode(',',$couponForward) : $couponForward ;
$couponRepay = $this->request->input('coupon_repay_id',0);
$couponActivity = $this->request->input('coupon_activity',0);
$res = $this->CouponRebateService->tieCouponActive($couponActivity,$couponForward,$couponRepay);
return $this->success($res);
}
/**
* 清优惠券领取记录(SSDB)
*/
public function clearSsdbCouponReceiveByName(){
$activity = $this->request->input('activity_type',0);
$userId = $this->request->input('user_id',0);
$get = $this->request->input('get',0);
$isAll = $this->request->input('is_all',0);;
return $this->success($this->CouponRebateService->clearSsdbCouponReceiveByName($activity,$userId, $get, $isAll));
}
}

40
app/Controller/ParamsTokenController.php

@ -0,0 +1,40 @@
<?php
namespace App\Controller;
use App\Service\ParamsTokenServiceInterface;
use Hyperf\Di\Annotation\Inject;
/**
* 参数token控制器
* Class ParamsTokenController
* @package App\Controller
*/
class ParamsTokenController extends BaseController
{
/**
* @Inject
* @var ParamsTokenServiceInterface
*/
protected $paramsTokenService;
/**
* 生成token存储对应参数数据
* @return \Psr\Http\Message\ResponseInterface
*/
public function generate()
{
$token = $this->paramsTokenService->generate($this->request->all());
return $this->success(['token' => $token]);
}
/**
* 解析token获取对应参数数据
* @return \Psr\Http\Message\ResponseInterface
*/
public function analyze()
{
$params = $this->paramsTokenService->analyze($this->request->input('token'));
return $this->success($params);
}
}

60
app/Controller/TestController.php

@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace App\Controller;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\Utils\Coroutine;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Task\TaskExecutor;
use Hyperf\Task\Task;
use App\TaskWorker\SSDBTask;
use App\Commons\Log;
/**
* @AutoController()
* Class TestController
* @package App\Controller
*/
class TestController extends AbstractController
{
private $name = 'default action';
public function index1(RequestInterface $request)
{
// $container = ApplicationContext::getContainer();
// $exec = $container->get(TaskExecutor::class);
// $result = $exec->execute(new Task([MethodTask::class, 'handle'], [Coroutine::id()]));
// $client = ApplicationContext::getContainer()->get(SSDBTask::class);
// $result = $client->exec("set","bar","1234");
// $result = $client->exec("get","bar");
// $client = ApplicationContext::getContainer()->get(MethodTask::class);
// $result = $client->handle("set");
//$log = ApplicationContext::getContainer()->get(Log::class);
$log = $this->log;
$log->push(['test'=>1,'user_id'=>290,'msg'=>'order']);
$log->event('t1',['test'=>1,'user_id'=>290,'msg'=>'order']);
//$this->name = 'index1 action '. $result;
return $this->name;
}
public function index2(RequestInterface $request)
{
$this->name = 'index2 action';
return $this->name;
}
public function index3(RequestInterface $request)
{
return $this->name;
}
}

33
app/Exception/Handler/SsdbExceptionHandler.php

@ -0,0 +1,33 @@
<?php
namespace App\Exception\Handler;
use App\Exception\SsdbException;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Psr\Http\Message\ResponseInterface;
use Throwable;
use App\Constants\ErrorCode;
use Hyperf\HttpMessage\Stream\SwooleStream;
class SsdbExceptionHandler extends ExceptionHandler
{
public function handle(Throwable $throwable, ResponseInterface $response)
{
$this->stopPropagation();
$content = json_encode([
"status" => 'error',
"code" => $throwable->getCode(),
"result" => [],
"message" => $throwable->getMessage()
]);
return $response->withHeader('Content-Type', 'application/json')->withBody(new SwooleStream($content));
}
public function isValid(Throwable $throwable): bool
{
return $throwable instanceof SsdbException;
}
}

18
app/Exception/SsdbException.php

@ -0,0 +1,18 @@
<?php
namespace App\Exception;
use App\Constants\ErrorCode;
use Hyperf\Server\Exception\ServerException;
class SsdbException extends ServerException
{
public function __construct(int $code = 0, string $message = null, Throwable $previous = null)
{
if (is_null($message)) {
$message = ErrorCode::getMessage($code);
}
parent::__construct($message, $code, $previous);
}
}

622
app/Libs/SimpleSSDB.php

@ -0,0 +1,622 @@
<?php
/**
* Copyright (c) 2012, ideawu
* All rights reserved.
* @author: ideawu
* @link: http://www.ideawu.com/
*
* SSDB PHP client SDK.
*/
namespace App\Libs;
use Exception;
class SSDBException extends Exception
{
}
class SSDBTimeoutException extends SSDBException
{
}
/**
* All methods(except *exists) returns false on error,
* so one should use Identical(if($ret === false)) to test the return value.
*/
class SimpleSSDB extends SSDB
{
function __construct($host, $port, $timeout_ms=2000){
parent::__construct($host, $port, $timeout_ms);
$this->easy();
}
}
class SSDB_Response
{
public $cmd;
public $code;
public $data = null;
public $message;
function __construct($code='ok', $data_or_message=null){
$this->code = $code;
if($code == 'ok'){
$this->data = $data_or_message;
}else{
$this->message = $data_or_message;
}
}
function __toString(){
if($this->code == 'ok'){
$s = $this->data === null? '' : json_encode($this->data);
}else{
$s = $this->message;
}
return sprintf('%-13s %12s %s', $this->cmd, $this->code, $s);
}
function ok(){
return $this->code == 'ok';
}
function not_found(){
return $this->code == 'not_found';
}
}
// Depricated, use SimpleSSDB instead!
class SSDB
{
private $debug = false;
public $sock = null;
private $_closed = false;
private $recv_buf = '';
private $_easy = false;
public $last_resp = null;
function __construct($host, $port, $timeout_ms=2000){
$timeout_f = (float)$timeout_ms/1000;
$this->sock = @stream_socket_client("$host:$port", $errno, $errstr, $timeout_f);
if(!$this->sock){
throw new SSDBException("$errno: $errstr");
}
$timeout_sec = intval($timeout_ms/1000);
$timeout_usec = ($timeout_ms - $timeout_sec * 1000) * 1000;
@stream_set_timeout($this->sock, $timeout_sec, $timeout_usec);
if(function_exists('stream_set_chunk_size')){
@stream_set_chunk_size($this->sock, 1024 * 1024);
}
}
function set_timeout($timeout_ms){
$timeout_sec = intval($timeout_ms/1000);
$timeout_usec = ($timeout_ms - $timeout_sec * 1000) * 1000;
@stream_set_timeout($this->sock, $timeout_sec, $timeout_usec);
}
/**
* After this method invoked with yesno=true, all requesting methods
* will not return a SSDB_Response object.
* And some certain methods like get/zget will return false
* when response is not ok(not_found, etc)
*/
function easy(){
$this->_easy = true;
}
function close(){
if(!$this->_closed){
@fclose($this->sock);
$this->_closed = true;
$this->sock = null;
}
}
function closed(){
return $this->_closed;
}
private $batch_mode = false;
private $batch_cmds = array();
function batch(){
$this->batch_mode = true;
$this->batch_cmds = array();
return $this;
}
function multi(){
return $this->batch();
}
function exec(){
$ret = array();
foreach($this->batch_cmds as $op){
list($cmd, $params) = $op;
$this->send_req($cmd, $params);
}
foreach($this->batch_cmds as $op){
list($cmd, $params) = $op;
$resp = $this->recv_resp($cmd, $params);
$resp = $this->check_easy_resp($cmd, $resp);
$ret[] = $resp;
}
$this->batch_mode = false;
$this->batch_cmds = array();
return $ret;
}
function request(){
$args = func_get_args();
$cmd = array_shift($args);
return $this->__call($cmd, $args);
}
private $async_auth_password = null;
function auth($password){
$this->async_auth_password = $password;
return null;
}
function __call($cmd, $params=array()){
$cmd = strtolower($cmd);
if($this->async_auth_password !== null){
$pass = $this->async_auth_password;
$this->async_auth_password = null;
$auth = $this->__call('auth', array($pass));
if($auth !== true){
throw new Exception("Authentication failed");
}
}
if($this->batch_mode){
$this->batch_cmds[] = array($cmd, $params);
return $this;
}
try{
if($this->send_req($cmd, $params) === false){
$resp = new SSDB_Response('error', 'send error');
}else{
$resp = $this->recv_resp($cmd, $params);
}
}catch(SSDBException $e){
if($this->_easy){
throw $e;
}else{
$resp = new SSDB_Response('error', $e->getMessage());
}
}
if($resp->code == 'noauth'){
$msg = $resp->message;
throw new Exception($msg);
}
$resp = $this->check_easy_resp($cmd, $resp);
return $resp;
}
private function check_easy_resp($cmd, $resp){
$this->last_resp = $resp;
if($this->_easy){
if($resp->not_found()){
return NULL;
}else if(!$resp->ok() && !is_array($resp->data)){
return false;
}else{
return $resp->data;
}
}else{
$resp->cmd = $cmd;
return $resp;
}
}
function multi_set($kvs=array()){
$args = array();
foreach($kvs as $k=>$v){
$args[] = $k;
$args[] = $v;
}
return $this->__call(__FUNCTION__, $args);
}
function multi_hset($name, $kvs=array()){
$args = array($name);
foreach($kvs as $k=>$v){
$args[] = $k;
$args[] = $v;
}
return $this->__call(__FUNCTION__, $args);
}
function multi_zset($name, $kvs=array()){
$args = array($name);
foreach($kvs as $k=>$v){
$args[] = $k;
$args[] = $v;
}
return $this->__call(__FUNCTION__, $args);
}
function incr($key, $val=1){
$args = func_get_args();
return $this->__call(__FUNCTION__, $args);
}
function decr($key, $val=1){
$args = func_get_args();
return $this->__call(__FUNCTION__, $args);
}
function zincr($name, $key, $score=1){
$args = func_get_args();
return $this->__call(__FUNCTION__, $args);
}
function zdecr($name, $key, $score=1){
$args = func_get_args();
return $this->__call(__FUNCTION__, $args);
}
function zadd($key, $score, $value){
$args = array($key, $value, $score);
return $this->__call('zset', $args);
}
function zRevRank($name, $key){
$args = func_get_args();
return $this->__call("zrrank", $args);
}
function zRevRange($name, $offset, $limit){
$args = func_get_args();
return $this->__call("zrrange", $args);
}
function hincr($name, $key, $val=1){
$args = func_get_args();
return $this->__call(__FUNCTION__, $args);
}
function hdecr($name, $key, $val=1){
$args = func_get_args();
return $this->__call(__FUNCTION__, $args);
}
private function send_req($cmd, $params){
$req = array($cmd);
foreach($params as $p){
if(is_array($p)){
$req = array_merge($req, $p);
}else{
$req[] = $p;
}
}
return $this->send($req);
}
private function recv_resp($cmd, $params){
$resp = $this->recv();
if($resp === false){
return new SSDB_Response('error', 'Unknown error');
}else if(!$resp){
return new SSDB_Response('disconnected', 'Connection closed');
}
if($resp[0] == 'noauth'){
$errmsg = isset($resp[1])? $resp[1] : '';
return new SSDB_Response($resp[0], $errmsg);
}
switch($cmd){
case 'dbsize':
case 'ping':
case 'qset':
case 'getbit':
case 'setbit':
case 'countbit':
case 'strlen':
case 'set':
case 'setx':
case 'setnx':
case 'zset':
case 'hset':
case 'qpush':
case 'qpush_front':
case 'qpush_back':
case 'qtrim_front':
case 'qtrim_back':
case 'del':
case 'zdel':
case 'hdel':
case 'hsize':
case 'zsize':
case 'qsize':
case 'hclear':
case 'zclear':
case 'qclear':
case 'multi_set':
case 'multi_del':
case 'multi_hset':
case 'multi_hdel':
case 'multi_zset':
case 'multi_zdel':
case 'incr':
case 'decr':
case 'zincr':
case 'zdecr':
case 'hincr':
case 'hdecr':
case 'zget':
case 'zrank':
case 'zrrank':
case 'zcount':
case 'zsum':
case 'zremrangebyrank':
case 'zremrangebyscore':
case 'ttl':
case 'expire':
if($resp[0] == 'ok'){
$val = isset($resp[1])? intval($resp[1]) : 0;
return new SSDB_Response($resp[0], $val);
}else{
$errmsg = isset($resp[1])? $resp[1] : '';
return new SSDB_Response($resp[0], $errmsg);
}
case 'zavg':
if($resp[0] == 'ok'){
$val = isset($resp[1])? floatval($resp[1]) : (float)0;
return new SSDB_Response($resp[0], $val);
}else{
$errmsg = isset($resp[1])? $resp[1] : '';
return new SSDB_Response($resp[0], $errmsg);
}
case 'get':
case 'substr':
case 'getset':
case 'hget':
case 'qget':
case 'qfront':
case 'qback':
if($resp[0] == 'ok'){
if(count($resp) == 2){
return new SSDB_Response('ok', $resp[1]);
}else{
return new SSDB_Response('server_error', 'Invalid response');
}
}else{
$errmsg = isset($resp[1])? $resp[1] : '';
return new SSDB_Response($resp[0], $errmsg);
}
break;
case 'qpop':
case 'qpop_front':
case 'qpop_back':
if($resp[0] == 'ok'){
$size = 1;
if(isset($params[1])){
$size = intval($params[1]);
}
if($size <= 1){
if(count($resp) == 2){
return new SSDB_Response('ok', $resp[1]);
}else{
return new SSDB_Response('server_error', 'Invalid response');
}
}else{
$data = array_slice($resp, 1);
return new SSDB_Response('ok', $data);
}
}else{
$errmsg = isset($resp[1])? $resp[1] : '';
return new SSDB_Response($resp[0], $errmsg);
}
break;
case 'keys':
case 'zkeys':
case 'hkeys':
case 'hlist':
case 'zlist':
case 'qslice':
if($resp[0] == 'ok'){
$data = array();
if($resp[0] == 'ok'){
$data = array_slice($resp, 1);
}
return new SSDB_Response($resp[0], $data);
}else{
$errmsg = isset($resp[1])? $resp[1] : '';
return new SSDB_Response($resp[0], $errmsg);
}
case 'auth':
case 'exists':
case 'hexists':
case 'zexists':
if($resp[0] == 'ok'){
if(count($resp) == 2){
return new SSDB_Response('ok', (bool)$resp[1]);
}else{
return new SSDB_Response('server_error', 'Invalid response');
}
}else{
$errmsg = isset($resp[1])? $resp[1] : '';
return new SSDB_Response($resp[0], $errmsg);
}
break;
case 'multi_exists':
case 'multi_hexists':
case 'multi_zexists':
if($resp[0] == 'ok'){
if(count($resp) % 2 == 1){
$data = array();
for($i=1; $i<count($resp); $i+=2){
$data[$resp[$i]] = (bool)$resp[$i + 1];
}
return new SSDB_Response('ok', $data);
}else{
return new SSDB_Response('server_error', 'Invalid response');
}
}else{
$errmsg = isset($resp[1])? $resp[1] : '';
return new SSDB_Response($resp[0], $errmsg);
}
break;
case 'scan':
case 'rscan':
case 'zscan':
case 'zrscan':
case 'zrange':
case 'zrrange':
case 'hscan':
case 'hrscan':
case 'hgetall':
case 'multi_hsize':
case 'multi_zsize':
case 'multi_get':
case 'multi_hget':
case 'multi_zget':
case 'zpop_front':
case 'zpop_back':
if($resp[0] == 'ok'){
if(count($resp) % 2 == 1){
$data = array();
for($i=1; $i<count($resp); $i+=2){
if($cmd[0] == 'z'){
$data[$resp[$i]] = intval($resp[$i + 1]);
}else{
$data[$resp[$i]] = $resp[$i + 1];
}
}
return new SSDB_Response('ok', $data);
}else{
return new SSDB_Response('server_error', 'Invalid response');
}
}else{
$errmsg = isset($resp[1])? $resp[1] : '';
return new SSDB_Response($resp[0], $errmsg);
}
break;
default:
return new SSDB_Response($resp[0], array_slice($resp, 1));
}
return new SSDB_Response('error', 'Unknown command: $cmd');
}
function send($data){
$ps = array();
foreach($data as $p){
$ps[] = strlen($p);
$ps[] = $p;
}
$s = join("\n", $ps) . "\n\n";
if($this->debug){
echo '> ' . str_replace(array("\r", "\n"), array('\r', '\n'), $s) . "\n";
}
try{
while(true){
$ret = @fwrite($this->sock, $s);
if($ret === false || $ret === 0){
$this->close();
throw new SSDBException('Connection lost');
}
$s = substr($s, $ret);
if(strlen($s) == 0){
break;
}
@fflush($this->sock);
}
}catch(Exception $e){
$this->close();
throw new SSDBException($e->getMessage());
}
return $ret;
}
function recv(){
$this->step = self::STEP_SIZE;
while(true){
$ret = $this->parse();
if($ret === null){
try{
$data = @fread($this->sock, 1024 * 1024);
if($this->debug){
echo '< ' . str_replace(array("\r", "\n"), array('\r', '\n'), $data) . "\n";
}
}catch(Exception $e){
$data = '';
}
if($data === false || $data === ''){
if(feof($this->sock)){
$this->close();
throw new SSDBException('Connection lost');
}else{
throw new SSDBTimeoutException('Connection timeout');
}
}
$this->recv_buf .= $data;
# echo "read " . strlen($data) . " total: " . strlen($this->recv_buf) . "\n";
}else{
return $ret;
}
}
}
const STEP_SIZE = 0;
const STEP_DATA = 1;
public $resp = array();
public $step;
public $block_size;
private function parse(){
$spos = 0;
$epos = 0;
$buf_size = strlen($this->recv_buf);
// performance issue for large reponse
//$this->recv_buf = ltrim($this->recv_buf);
while(true){
$spos = $epos;
if($this->step === self::STEP_SIZE){
$epos = strpos($this->recv_buf, "\n", $spos);
if($epos === false){
break;
}
$epos += 1;
$line = substr($this->recv_buf, $spos, $epos - $spos);
$spos = $epos;
$line = trim($line);
if(strlen($line) == 0){ // head end
$this->recv_buf = substr($this->recv_buf, $spos);
$ret = $this->resp;
$this->resp = array();
return $ret;
}
$this->block_size = intval($line);
$this->step = self::STEP_DATA;
}
if($this->step === self::STEP_DATA){
$epos = $spos + $this->block_size;
if($epos <= $buf_size){
$n = strpos($this->recv_buf, "\n", $epos);
if($n !== false){
$data = substr($this->recv_buf, $spos, $epos - $spos);
$this->resp[] = $data;
$epos = $n + 1;
$this->step = self::STEP_SIZE;
continue;
}
}
break;
}
}
// packet not ready
if($spos > 0){
$this->recv_buf = substr($this->recv_buf, $spos);
}
return null;
}
}

31
app/Listener/ValidatorFactoryResolvedListener.php

@ -48,6 +48,36 @@ class ValidatorFactoryResolvedListener implements ListenerInterface
return $message;
});
// 注册了 base64 验证器规则
$validatorFactory->extend('base64', function ($attribute, $value, $parameters, $validator) {
preg_match('/^(data:\s*image\/(\w+);base64,)/', $value, $result);
if (empty($result)) {
return false;
}
if (
in_array('image', $parameters)
&& !in_array($result[2], ['jpg','jpeg','png','gif','svg','bmp'])
) {
return false;
}
return true;
});
// 注册了 ext_not_in 验证器规则
$validatorFactory->extend('ext_not_in', function ($attribute, $value, $parameters, $validator) {
if (empty($parameters)) {
$parameters = ['', 'php', 'exe', 'sql', 'sh', 'bat', 'py', 'go', 'c', 'cpp'];
}
return !in_array($value->getExtension(), $parameters);
});
// 注册了 exists_enable 验证器规则,参数是table,field,where1,where2...
$validatorFactory->extend('exists_enable', function ($attribute, $value, $parameters, $validator) {
@ -79,6 +109,5 @@ class ValidatorFactoryResolvedListener implements ListenerInterface
return $builder->exists();
});
}
}

2
app/Middleware/Auth/ApiMiddleware.php

@ -39,7 +39,7 @@ class ApiMiddleware implements MiddlewareInterface
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
if (env('APP_ENV') == 'dev') {
if (env('APP_ENV') == 'dev' || env('APP_ENV') == 'local') {
return $handler->handle($request);
}

34
app/Middleware/CorsMiddleware.php

@ -0,0 +1,34 @@
<?php
namespace App\Middleware;
use Hyperf\Utils\Context;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
class CorsMiddleware implements MiddlewareInterface
{
/**
* @inheritDoc
*/
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$response = Context::get(ResponseInterface::class);
$response = $response->withHeader('Access-Control-Allow-Origin', '*')
->withHeader('Access-Control-Allow-Credentials', 'true')
// Headers 可以根据实际情况进行改写。
->withHeader('Access-Control-Allow-Headers', 'DNT,Keep-Alive,User-Agent,Cache-Control,Content-Type,Authorization');
Context::set(ResponseInterface::class, $response);
if ($request->getMethod() == 'OPTIONS') {
return $response;
}
return $handler->handle($request);
}
}

70
app/Model/Ad.php

@ -0,0 +1,70 @@
<?php
declare (strict_types=1);
namespace App\Model;
use Hyperf\DbConnection\Model\Model;
/**
*/
class Ad extends Model
{
/**
* 跳转类型及说明
*/
const ITEM = [
1 => 'page',
2 => 'webview',
3 => 'applet',
];
/**
* 类型 1 = 首页banners
*/
const TYPE_BANNER = 1;
/**
* 启用状态
*/
const STATUS_YES = 1;
const STATUS_NO = 2;
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'ims_cjdc_ad';
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [];
protected $appends = [
'item_text',
'redirect_url'
];
/**
* 获取跳转说明
*/
public function getItemTextAttribute()
{
return self::ITEM[$this->item];
}
/**
* 获取跳转连接
*/
public function getRedirectUrlAttribute()
{
return $this->src ?: $this->src2;
}
}

10
app/Model/OrderMain.php

@ -0,0 +1,10 @@
<?php
namespace App\Model;
class OrderMain extends Model
{
protected $table = 'ims_cjdc_order_main';
}

45
app/Request/CouponGetListRequest.php

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace App\Request;
use Hyperf\Validation\Request\FormRequest;
class CouponGetListRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*/
public function rules(): array
{
return [
'user_id' => 'required|nonempty|integer|exists_enable:ims_cjdc_user,id',
'receive_type' => 'required|nonempty|integer'
];
}
public function messages(): array
{
return [
'user_id.*' => ':attribute信息不正确',
'receive_type.*' => ':attribute必须'
];
}
public function attributes(): array
{
return [
'user_id' => '用户ID',
'receive_type' => '领取方式'
];
}
}

45
app/Request/CouponRebateReceiveRequest.php

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace App\Request;
use Hyperf\Validation\Request\FormRequest;
class CouponRebateReceiveRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*/
public function rules(): array
{
return [
'user_id' => 'required|nonempty|integer|exists_enable:ims_cjdc_user,id',
'receive_type' => 'required|nonempty|integer',
];
}
public function messages(): array
{
return [
'user_id.*' => ':attribute信息不正确',
'receive_type.*' => ':attribute必须',
];
}
public function attributes(): array
{
return [
'user_id' => '领取用户ID',
'receive_type' => '领取方式',
];
}
}

48
app/Request/CouponRebateTieRequest.php

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace App\Request;
use Hyperf\Validation\Request\FormRequest;
class CouponRebateTieRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*/
public function rules(): array
{
return [
'coupon_activity' => 'required|nonempty',
'coupon_forward_ids' => 'required|nonempty',
'coupon_repay_id' => 'required|nonempty',
];
}
public function messages(): array
{
return [
'coupon_activity.*' => ':attribute必须',
'coupon_forward_ids.*' => ':attribute必须',
'coupon_repay_id.*' => ':attribute必须',
];
}
public function attributes(): array
{
return [
'coupon_activity' => '优惠券活动',
'coupon_forward_ids' => '领取类型优惠券',
'coupon_repay_id' => '返还类型优惠券',
];
}
}

20
app/Service/AdService.php

@ -0,0 +1,20 @@
<?php
namespace App\Service;
use App\Model\Ad;
class AdService implements AdServiceInterface
{
/**
* 跳转类型、跳转连接、标题、图片地址
*/
public function banners()
{
return Ad::query()->select(['id','title','logo','item','src','src2'])
->where([
'type' => Ad::TYPE_BANNER,
'status' => Ad::STATUS_YES
])->get();
}
}

11
app/Service/AdServiceInterface.php

@ -0,0 +1,11 @@
<?php
namespace App\Service;
interface AdServiceInterface
{
/**
* 获取首页banners
*/
public function banners();
}

25
app/Service/CommonService.php

@ -0,0 +1,25 @@
<?php
namespace App\Service;
class CommonService
{
/**
* 请求参数判空
* @param mixed $var 参数
*/
public function empty($var)
{
return ! (
isset($var)
&& $var
&& !empty($var)
&& !is_null($var)
&& $var != 'undefined'
&& $var != 'unknown'
&& $var != 'null'
&& $var != 'false'
);
}
}

407
app/Service/CouponRebateService.php

@ -0,0 +1,407 @@
<?php
namespace App\Service;
use Hyperf\Di\Annotation\Inject;
use Hyperf\DbConnection\Db;
use App\Model\Coupon;
use App\Model\CouponUserRecType;
use App\Model\CouponRec;
use App\Constants\LogLabel;
use App\Commons\Log;
use Hyperf\Utils\ApplicationContext;
use App\TaskWorker\SSDBTask;
use App\Constants\SsdbKeysPrefix;
use Exception;
use App\Service\CommonService;
use function AlibabaCloud\Client\json;
class CouponRebateService implements CouponRebateServiceInterface
{
/**
* @Inject
* @var Log
*/
protected $log;
/**
* @Inject
* @var CommonService
*/
protected $commonService;
/**
* 领取优惠券
* 返券活动领取
* 一次可领取多张优惠券
* 一个用户不可重复领取
*/
public function userReceiveCoupon($params)
{
$userId = $params["user_id"];
$receiveType = $params["receive_type"];
$sendUserId = $params["send_user_id"];
$phone = $params["phone"];
// status: 0领取成功 >0领取失败
$result = [
'status' => 1,
'coupon_text' => '活动已过期~'
];
/* 如果请求的优惠券ids为空,则返回过期提示 */
if($this->commonService->empty($params["ids"])){
return $result;
}
$ids = $params["ids"];
$idsData = is_array($ids) ? $ids : explode(',',$ids);
// 错误日志记录
$errorData = [
'coupon_ids' =>$ids,
'user_id' =>$userId,
'receiveType' =>$receiveType,
'sendUserId' =>$sendUserId,
'phone' =>$phone
];
$ssdb = ApplicationContext::getContainer()->get(SSDBTask::class);
$activity = $ssdb->exec('hget', SsdbKeysPrefix::COUPON_REBATE_ACTIVITY ,'activity');
// ssdb 键值
$ssdbKey = 'activity_'.$activity.'_user_'.$userId;
$receiveSsdb = [];
// 判断是否已全部领取过
$userReceive = $ssdb->exec('hget', SsdbKeysPrefix::COUPON_REBATE_RECEIVE,$ssdbKey);
if($userReceive === false){
$ids = $idsData;
}else{
$userReceiveCouponIds = empty($userReceive) ? [] : explode(',',$userReceive) ;
$ids = array_diff($idsData, $userReceiveCouponIds);
$receiveSsdb = $userReceiveCouponIds;
}
if(count($ids) > 0){
try{
Db::transaction( function() use ($ids,$receiveType,$userId,$sendUserId,$phone,&$result,&$errorData,&$receiveSsdb) {
$now = time();
$success = [];
//获取优惠券信息 (读写锁,完全控制,性能低)
$coupons = Coupon::whereIn('id', $ids)->lockForUpdate()
->where('active_type',2)
->where('status',1)
->where('start_time', '<=', $now)
->where('end_time', '>=', $now)
->whereRaw('inventory > inventory_use')
->select('id','title','inventory','inventory_use','full_amount','discounts','active_type')
->get();
foreach($coupons as $coupon){
$errorData['coupon_id'] = $coupon->id;
// 查询一次能领取的数量
$couponReceiveType = CouponUserRecType::where('system_coupon_user_id',$coupon->id)->select('one_receive_number');
if (env('SUB_CHANNEL') == 1) {
$couponReceiveType->where('receive_type',$receiveType);
}
$couponReceiveType = $couponReceiveType->first();
// 优惠券可领取数量 >= 本次领取数量
if($coupon->inventory - $coupon->inventory_use >= $couponReceiveType->one_receive_number){
// 判断是否领取过 存在记录则领取过
$isReceive = CouponRec::select('id')
->where('system_coupon_user_id',$coupon->id)
->where('user_id',$userId)
->exists();
if(!$isReceive){
//记录已领取的数量
$coupon->inventory_use += $couponReceiveType->one_receive_number;
$couponReceive = new CouponRec;
$couponReceive->user_id = $userId;
$couponReceive->system_coupon_user_id = $coupon->id;
$couponReceive->order_main_id = 0;
$couponReceive->receive_time = $now;
$couponReceive->number = $couponReceiveType->one_receive_number;
$couponReceive->number_remain = $couponReceiveType->one_receive_number;
$couponReceive->status = 0;
$couponReceive->update_time = $now;
$couponReceive->receive_type = $receiveType;
$couponReceive->send_user_id = $sendUserId;
$couponReceive->phone = $phone;
if ( $couponReceive->save() && $coupon->save() ) {
$success[] = $coupon;
$receiveSsdb[] = $coupon->id;
}else{
$errorData['msg'] = '添加优惠券到用户领取表或者记录已领取数量失败';
$this->log->event(
LogLabel::COUPON_LOG,
$errorData
);
}
}
}
}
if(count($success) > 0){
$result['status'] = 0;
$result['coupon_text'] = '恭喜您领取成功!';
}
});
} catch (Exception $e){
$errorData['msg'] = $e->getMessage();
$this->log->event(
LogLabel::COUPON_LOG,
$errorData
);
}
if(count($receiveSsdb) > 0){
$saveSsdb = [
$ssdbKey,
implode(',',$receiveSsdb)
];
if(false === $ssdb->exec('hset',SsdbKeysPrefix::COUPON_REBATE_RECEIVE, $saveSsdb)){
$errorData['msg'] = '记录领取优惠券到ssdb失败';
$this->log->event(
LogLabel::COUPON_LOG,
$errorData
);
};
}
}else{
$result['status'] = 2;
$result['coupon_text'] = '您已领取!赶快去下单吧~';
}
return $result;
}
/*
* 判断用户是否已领取过优惠券
* */
public function isCouponRebate($user_id)
{
//获取SSDB上的活动信息
$ssdb = ApplicationContext::getContainer()->get(SSDBTask::class);
$active = $ssdb->exec('hgetall',SsdbKeysPrefix::COUPON_REBATE_ACTIVITY);
$coupon_ids = explode(',',$active['forward']);
$res = Db::table('ims_system_coupon_user as u')
->leftjoin('ims_system_coupon_user_receive as r', 'u.id', '=', 'r.system_coupon_user_id')
->whereIn('r.system_coupon_user_id',$coupon_ids)
->where([
['r.user_id', '=', $user_id],
['r.receive_type', '=', 4],
['u.active_type', '=', 2],
])
->select('r.id')
->first();
return $res;
}
/*
*获取活动信息
*/
public function getActiveInfo()
{
//获取SSDB上的活动信息
$ssdb = ApplicationContext::getContainer()->get(SSDBTask::class);
$active = $ssdb->exec('hgetall',SsdbKeysPrefix::COUPON_REBATE_ACTIVITY);
$coupon_ids = explode(',',$active['forward']);
$time = time();
$res = Db::table('ims_system_coupon_user')
->whereIn('id',$coupon_ids)
->where([
['status', '=', 1],
['active_type', '=', 2],
['start_time', '<=', $time],
['end_time', '>', $time],
])
->whereRaw('inventory > inventory_use')
->orderBy('weigh', 'desc')
->orderBy('addtime', 'desc')
->get();
return $res;
}
/**
* 将优惠券绑定活动
* 领取优惠券 COUPON_REBATE_FORWARD 可多张
* 返还优惠券 COUPON_REBATE_REPAY 只一张
*/
public function tieCouponActive($couponActivity, $couponForward, $couponRepay)
{
$ssdb = ApplicationContext::getContainer()->get(SSDBTask::class);
$data = [
'activity', $couponActivity,
'forward' , $couponForward,
'repay' , $couponRepay
];
$result = [
'result' => ($ssdb->exec('multi_hset', SsdbKeysPrefix::COUPON_REBATE_ACTIVITY, $data) === false) ? false : true ,
'data' => $ssdb->exec('hgetall', SsdbKeysPrefix::COUPON_REBATE_ACTIVITY)
];
return $result;
}
/*
* 支付成功 返券
*/
public function couponRebate($order_id)
{
//获取SSDB上的活动信息
$ssdb = ApplicationContext::getContainer()->get(SSDBTask::class);
$active = $ssdb->execWithoutTask('hgetall',SsdbKeysPrefix::COUPON_REBATE_ACTIVITY);
//判断返券优惠券是否有库存
$inventory = Db::table('ims_system_coupon_user')
->where('id',$active['repay'])
->whereRaw('inventory > inventory_use')
->exists();
if(!$inventory){
//库存不足
return false;
}
//获取活动发放优惠券id
$coupon_ids = explode(',',$active['forward']);
/* 判断被使用的优惠券类型是否为转发活动优惠券 */
$coupon = Db::table('ims_system_coupon_user_receive as r')
->leftjoin('ims_system_coupon_user_use as u', 'u.user_receive_id', '=', 'r.id')
->where([
['u.order_main_id', '=', $order_id],
['r.send_user_id', '>', 0],
['r.rebate_type', '=', 1],
['r.receive_type', '=', 4],
])
->whereIn('r.system_coupon_user_id',$coupon_ids)
->select('r.user_id', 'r.send_user_id')
->first();
/* 如果使用的优惠券为转发活动优惠券 则给赠送者返一张优惠券*/
if (isset($coupon->send_user_id) && ($coupon->send_user_id) > 0) {
//是否已返过券
$exists_coupon_rebate = Db::table('ims_system_coupon_user_receive')
->where([
['system_coupon_user_id' ,'=', $active['repay']],
['user_id' ,'=', $coupon->send_user_id],
['receive_type' ,'=', 5],
])
->select('id','status')
->first();
//开启事务
Db::beginTransaction();
try {
//返券
if($exists_coupon_rebate->id){
//如果已有该优惠券 则领取数量 和 可用数量 自增1
Db::table('ims_system_coupon_user_receive')
->where([
['id' ,'=', $exists_coupon_rebate->id],
])
->increment('number');
Db::table('ims_system_coupon_user_receive')
->where([
['id' ,'=', $exists_coupon_rebate->id],
])
->increment('number_remain');
//如果该用户在领取表中 status为已用完状态 2 则改为已用部分 1
if($exists_coupon_rebate->status == 2){
Db::table('ims_system_coupon_user_receive')
->where([
['id' ,'=', $exists_coupon_rebate->id],
])
->update(['status' => 1]);;
}
}else {
//否则新增一条返券记录
$nowTime = time();
Db::table('ims_system_coupon_user_receive')->insert([
[
'user_id' => $coupon->send_user_id,
'system_coupon_user_id' => $active['repay'],
'receive_type' => 5,
'status' => 0,
'number' => 1,
'number_remain' => 1,
'order_main_id' => $order_id,
'receive_time' => $nowTime,
'update_time' => $nowTime,
'created_at' => $nowTime,
'updated_at' => $nowTime,
]
]);
}
//首次返券更新rebate_type字段 防止重复返券
Db::table('ims_system_coupon_user_receive')
->where([
['user_id','=',$coupon->user_id],
['receive_type','=',4],
])
->whereIn('system_coupon_user_id',$coupon_ids)
->update(['rebate_type' => 2]);
//更新库存操作
Db::table('ims_system_coupon_user')
->where('id', $active['repay']['repay'])
->increment('inventory_use');
// 提交
Db::commit();
} catch (\Exception $e) {
// 回滚
Db::rollBack();
$log_Data = array();
$log_Data['name'] = '返券';
$log_Data['order_main_id'] = $order_id;
$log_Data['msg'] = '返券失败';
$this->log->event(
LogLabel::COUPON_LOG,
$log_Data
);
}
}
$log_Data = array();
$log_Data['name'] = '返券';
$log_Data['user_id'] = $order_id;
$log_Data['send_user_id'] = $coupon->send_user_id;
$log_Data['order_main_id'] = $order_id;
$log_Data['msg'] = '返券成功';
$this->log->event(
LogLabel::COUPON_LOG,
$log_Data
);
return true;
}
/**
* 清优惠券领取记录(SSDB)
*/
public function clearSsdbCouponReceiveByName($activity, $userId, $get = 0, $isAll = 0){
$key = 'activity_'.$activity.'_user_'.$userId;
$ssdb = ApplicationContext::getContainer()->get(SSDBTask::class);
if($isAll > 0){
if($get > 0){
return $ssdb->exec('hgetAll', SsdbKeysPrefix::COUPON_REBATE_RECEIVE);
}else{
return ( $ssdb->exec('hclear', SsdbKeysPrefix::COUPON_REBATE_RECEIVE) === false) ? false : true ;
}
}else {
if($get > 0){
return $ssdb->exec('hget', SsdbKeysPrefix::COUPON_REBATE_RECEIVE, $key);
}else{
return ( $ssdb->exec('hdel', SsdbKeysPrefix::COUPON_REBATE_RECEIVE, $key) === false) ? false : true ;
}
}
}
}

22
app/Service/CouponRebateServiceInterface.php

@ -0,0 +1,22 @@
<?php
namespace App\Service;
interface CouponRebateServiceInterface
{
/**
* 领取优惠券
*/
public function userReceiveCoupon($params);
public function isCouponRebate($user_id);
public function getActiveInfo();
public function tieCouponActive($couponActivity,$couponForward,$couponRepay);
public function couponRebate($order_id);
public function clearSsdbCouponReceiveByName($activity, $userId, $get = 0, $isAll = 0);
}

160
app/Service/CouponService.php

@ -0,0 +1,160 @@
<?php
namespace App\Service;
use Hyperf\Di\Annotation\Inject;
use Hyperf\DbConnection\Db;
use App\Model\CouponUserRecType;
use App\Model\Coupon;
use App\Model\CouponRec;
use Hyperf\Utils\ApplicationContext;
use App\TaskWorker\SSDBTask;
use App\Constants\SsdbKeysPrefix;
use App\Constants\LogLabel;
use App\Commons\Log;
use Exception;
use App\Service\CommonService;
class CouponService implements CouponServiceInterface
{
/**
* @Inject
* @var Log
*/
protected $log;
/**
* @Inject
* @var CommonService
*/
protected $commonService;
/**
* 获取用户可领取优惠卷接口
*/
public function getSystemCouponUserList($userId,$receiveType)
{
/* 优惠券活动标志 2 */
$ssdb = ApplicationContext::getContainer()->get(SSDBTask::class);
$couponActivity = $ssdb->exec('hgetall', SsdbKeysPrefix::COUPON_REBATE_ACTIVITY);
$activityType = $couponActivity === false ? 0 : $couponActivity['activity'];
$result = [
'active_type' => 1,
'not_receive' => [],
'jump_data' => [
'src' => "/zh_cjdianc/pages/couponrebate/index?activity_type=".$activityType,
'src2' => "/zh_cjdianc/pages/couponrebate/index?activity_type=".$activityType,
'share_bg' => env('OSS_IMG_HOST').'/static/img/coupon_bg.png',
'receive_bg' => env('OSS_IMG_HOST').'/static/img/coupon_share.png',
'coupons' => []
]
];
$nowTime = time();
$c_ids = [];
$whereC = [
['end_time','>',$nowTime],
['start_time','<=',$nowTime],
['status','=',1]
];
// 渠道开启,查询该渠道可以领取的优惠券ID
// 渠道未开启,查询所有优惠券
if (env('SUB_CHANNEL') == 1) {
$c_ids = CouponUserRecType::where('receive_type', $receiveType)->where($whereC)->pluck('system_coupon_user_id');
} else {
$c_ids = Coupon::where($whereC)->pluck('id');
}
$couponReceive = CouponRec::where('user_id',$userId);
// 渠道开启,查询该用户在此渠道领过的优惠券ID
if (env('SUB_CHANNEL') == 1) {
$couponReceive->where('receive_type', $receiveType);
}
$cr_ids = $couponReceive->pluck('system_coupon_user_id');
// 可领取的券ID
$c_ids = $c_ids->toArray();
// 已经领取的券ID
$cr_ids = $cr_ids->toArray();
// 当前用户可领的优惠券ID
$couponIds = array_diff($c_ids, $cr_ids);
// 转发型优惠券
$couponReceiveIds = ($couponActivity === false || $this->commonService->empty($couponActivity['forward']) )? [] : explode(',',$couponActivity['forward']);
// 所有优惠券
$couponIds = array_merge($couponIds,$couponReceiveIds);
$whereC = [
['u.end_time','>',$nowTime],
['u.start_time','<=',$nowTime],
['u.status','=',1]
];
// 查询领取型1 和 转发型2
$whereActiveType = [1,2];
if (env('SUB_CHANNEL') == 1) {
array_push($whereC, ['type.receive_type','=', $receiveType]);
}
$coupons = Db::table('ims_system_coupon_user as u')
->join('ims_system_coupon_user_receivetype as type', 'u.id', '=', 'type.system_coupon_user_id')
->whereIn('u.id', $couponIds)
->whereIn('u.active_type', $whereActiveType)
->where($whereC)
->whereRaw('u.inventory_use < u.inventory and u.inventory-u.inventory_use >= type.one_receive_number')
->select('u.*','type.one_receive_number')
->orderBy('u.weigh','desc')
->get();
foreach ($coupons as $k => &$v){
if($v->active_type == 1 && count($result['not_receive']) < 4){
$result['not_receive'][] = $v;
}else if($v->active_type == 2 && in_array($v->id,$couponReceiveIds)){
$result['jump_data']['coupons'][] = $v->id;
}
if($v->discount_type == 2){
$v->discounts = floatval($v->discounts);
}
}
$result['active_type'] = count($result['jump_data']['coupons']) > 0 ? 2 : $result['active_type'] ;
return $result;
}
//统计用户
public function userCouponAccount()
{
}
/**
* 用户领取优惠卷
*/
public function userReceiveCoupon()
{
}
/**
* 获取用户已经领取的优惠卷列表
*/
public function getUserReceiveCouponList()
{
}
/**
* 获取用户当前订单可用的优惠券列表
* 按分类(1订单 等优惠)分组返回
*/
public function getUserAvailableCoupons()
{
}
}

18
app/Service/CouponServiceInterface.php

@ -0,0 +1,18 @@
<?php
namespace App\Service;
interface CouponServiceInterface
{
public function getSystemCouponUserList($userId,$receiveType);
public function userCouponAccount();
public function userReceiveCoupon();
public function getUserReceiveCouponList();
public function getUserAvailableCoupons();
}

20
app/Service/ParamsTokenServiceInterface.php

@ -0,0 +1,20 @@
<?php
namespace App\Service;
interface ParamsTokenServiceInterface
{
/**
* 生成并存储token
* @param $params
* @return mixed
*/
public function generate($params);
/**
* 通过token解析返回参数
* @param $token
* @return mixed
*/
public function analyze($token);
}

84
app/Service/ParamsTokenSsdbService.php

@ -0,0 +1,84 @@
<?php
namespace App\Service;
use App\Constants\ErrorCode;
use App\Constants\LogLabel;
use App\Constants\SsdbKeysPrefix;
use App\Exception\SsdbException;
use Hyperf\Utils\ApplicationContext;
use App\TaskWorker\SSDBTask;
use Hyperf\Di\Annotation\Inject;
use App\Commons\Log;
class ParamsTokenSsdbService implements ParamsTokenServiceInterface
{
/**
* @Inject
* @var Log
*/
protected $log;
/**
* 生成token并存储对应数据
* @param $params
*/
public function generate($params)
{
$token = $params['token_name'] ?? md5(json_encode($params));
$ssdb = ApplicationContext::getContainer()->get(SSDBTask::class);
$kvs = [];
foreach ($params as $key => $value) {
$kvs[] = $key;
$kvs[] = $value;
}
if(false === $ssdb->exec('multi_hset', SsdbKeysPrefix::PARAMS_TOKEN.$token, $kvs)) {
$this->log->event(
LogLabel::SSDB_LOG,
['method' => 'multi_hset', 'key' => SsdbKeysPrefix::PARAMS_TOKEN.$token, 'kvs' => $kvs]
);
throw new SsdbException(ErrorCode::SSDB_ERROR, 'token生成失败');
}
return $token;
}
/**
* 解析token获取对应数据参数
* @param $token
*/
public function analyze($token)
{
$ssdb = ApplicationContext::getContainer()->get(SSDBTask::class);
$params = $ssdb->exec('hgetall', SsdbKeysPrefix::PARAMS_TOKEN.$token);
if (false === $params) {
$this->log->event(
LogLabel::SSDB_LOG,
['method' => 'hgetall', 'key' => SsdbKeysPrefix::PARAMS_TOKEN.$token, 'params' => $params]
);
throw new SsdbException(ErrorCode::SSDB_ERROR, 'token解析失败');
}
if (empty($params)) {
$this->log->event(
LogLabel::SSDB_LOG,
['method' => 'hgetall', 'key' => SsdbKeysPrefix::PARAMS_TOKEN.$token, 'params' => $params]
);
throw new SsdbException(ErrorCode::SSDB_ERROR, 'token不存在');
}
return $params;
}
}

46
app/TaskWorker/SSDBTask.php

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace App\TaskWorker;
use Hyperf\Utils\ApplicationContext;
use App\Libs\SimpleSSDB;
use Hyperf\Task\Annotation\Task;
class SSDBTask
{
/**
* @var SimpleSSDB
*/
public $ss = null;
/**
* @Task
*/
public function exec($method,...$args)
{
$result = $this->client()->__call($method,$args);
return $result;
}
public function execWithoutTask($method,...$args)
{
$result = $this->client()->__call($method,$args);
return $result;
}
protected function client(){
if ($this->ss instanceof SimpleSSDB) {
return $this->ss;
}
$this->ss = new SimpleSSDB(env('SSDB_HOST'), env('SSDB_PORT'));
$this->ss->auth(env('SSDB_AUTH'));
return $this->ss;
}
}

7
composer.json

@ -19,7 +19,7 @@
"hyperf/config": "~2.0.0",
"hyperf/db-connection": "~2.0.0",
"hyperf/framework": "~2.0.0",
"hyperf/guzzle": "~2.0.0",
"hyperf/guzzle": "^2.0",
"hyperf/http-server": "~2.0.0",
"hyperf/logger": "~2.0.0",
"hyperf/memory": "~2.0.0",
@ -27,7 +27,10 @@
"hyperf/redis": "~2.0.0",
"hyperf/constants": "~2.0.0",
"hyperf/model-cache": "~2.0.0",
"hyperf/validation": "^2.0",
"hyperf/filesystem": "^2.0",
"xxtime/flysystem-aliyun-oss": "^1.5",
"hyperf/validation": "^2.0",
"hyperf/task": "^2.0",
"hyperf/paginator": "^2.0"
},
"require-dev": {

33
config/autoload/amqp.php

@ -0,0 +1,33 @@
<?php
return [
'default' => [
'host' => env('RQM_HOST', 'localhost'),
'port' => 5672,
'user' => env('RQM_USER','guest'),
'password' => env('RQM_PASSWORD','guest'),
'vhost' => '/',
'concurrent' => [
'limit' => 1,
],
'pool' => [
'min_connections' => 1,
'max_connections' => 10,
'connect_timeout' => 10.0,
'wait_timeout' => 3.0,
'heartbeat' => -1,
],
'params' => [
'insist' => false,
'login_method' => 'AMQPLAIN',
'login_response' => null,
'locale' => 'en_US',
'connection_timeout' => 3.0,
'read_write_timeout' => 6.0,
'context' => null,
'keepalive' => false,
'heartbeat' => 3,
'close_on_destruct' => false,
],
]
];

9
config/autoload/dependencies.php

@ -10,5 +10,12 @@ declare(strict_types=1);
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
return [
\App\Service\ServiceEvaluateServiceInterface::class => \App\Service\ServiceEvaluateService::class
\App\Service\ServiceEvaluateServiceInterface::class => \App\Service\ServiceEvaluateService::class,
\App\Service\AttachmentServiceInterface::class => \App\Service\AttachmentService::class,
\App\Service\ParamsTokenServiceInterface::class => \App\Service\ParamsTokenSsdbService::class,
\App\Service\AdServiceInterface::class => \App\Service\AdService::class,
\App\Commons\Log::class => \App\Commons\Log::class,
\App\Service\CouponRebateServiceInterface::class => \App\Service\CouponRebateService::class,
\App\Service\UserServiceInterface::class => \App\Service\UserService::class,
\App\Service\CouponServiceInterface::class => \App\Service\CouponService::class,
];

3
config/autoload/exceptions.php

@ -14,7 +14,8 @@ return [
'http' => [
Hyperf\HttpServer\Exception\Handler\HttpExceptionHandler::class,
App\Exception\Handler\AppExceptionHandler::class,
\App\Exception\Handler\ValidationExceptionHandler::class,
App\Exception\Handler\ValidationExceptionHandler::class,
App\Exception\Handler\SsdbExceptionHandler::class,
],
],
];

1
config/autoload/middlewares.php

@ -11,6 +11,7 @@ declare(strict_types=1);
*/
return [
'http' => [
\App\Middleware\CorsMiddleware::class,
\App\Middleware\Auth\ApiMiddleware::class,
\Hyperf\Validation\Middleware\ValidationMiddleware::class,
],

3
config/autoload/server.php

@ -36,16 +36,13 @@ return [
'max_request' => 100000,
'socket_buffer_size' => 2 * 1024 * 1024,
'buffer_output_size' => 2 * 1024 * 1024,
// Task Worker 数量,根据您的服务器配置而配置适当的数量
'task_worker_num' => 8,
// 因为 `Task` 主要处理无法协程化的方法,所以这里推荐设为 `false`,避免协程下出现数据混淆的情况
'task_enable_coroutine' => false,
],
'callbacks' => [
SwooleEvent::ON_WORKER_START => [Hyperf\Framework\Bootstrap\WorkerStartCallback::class, 'onWorkerStart'],
SwooleEvent::ON_PIPE_MESSAGE => [Hyperf\Framework\Bootstrap\PipeMessageCallback::class, 'onPipeMessage'],
SwooleEvent::ON_WORKER_EXIT => [Hyperf\Framework\Bootstrap\WorkerExitCallback::class, 'onWorkerExit'],
// Task callbacks
SwooleEvent::ON_TASK => [Hyperf\Framework\Bootstrap\TaskCallback::class, 'onTask'],
SwooleEvent::ON_FINISH => [Hyperf\Framework\Bootstrap\FinishCallback::class, 'onFinish'],
],

4
config/routes.php

@ -35,12 +35,12 @@ Router::addGroup('/v1/',function (){
Router::post('CouponRebate/tieCouponActive', 'App\Controller\CouponRebateController@tieCouponActive');
Router::post('CouponRebate/couponRebate', 'App\Controller\CouponRebateController@couponRebate');
Router::post('CouponRebate/clearSsdbReceive', 'App\Controller\CouponRebateController@clearSsdbCouponReceiveByName');
//鎾�姤鍣ㄧ浉鍏�
//播报器相关
Router::post('Device/bind', 'App\Controller\DeviceController@bind');
Router::post('Device/list', 'App\Controller\DeviceController@list');
Router::post('Device/unbind', 'App\Controller\DeviceController@unbind');
//娴嬭瘯璺�敱
//测试路由
Router::get('test/index1', 'App\Controller\TestController@index1');
Router::post('Store/applyEntry', 'App\Controller\StoreController@applyEntry');

Loading…
Cancel
Save