Browse Source

合并相关代码

master
weigang 5 years ago
parent
commit
742006bc32
  1. 1
      .gitignore
  2. 2
      Envoy.blade.php
  3. 73
      app/Amqp/Consumer/DevicOrderConsumer.php
  4. 42
      app/Amqp/Consumer/couponRebateConsumer.php
  5. 88
      app/Commons/Log.php
  6. 21
      app/Constants/ErrorCode.php
  7. 36
      app/Constants/LogLabel.php
  8. 49
      app/Constants/SsdbKeysPrefix.php
  9. 16
      app/Controller/AbstractController.php
  10. 27
      app/Controller/AdController.php
  11. 68
      app/Controller/AttachmentController.php
  12. 9
      app/Controller/BaseController.php
  13. 92
      app/Controller/CouponController.php
  14. 87
      app/Controller/CouponRebateController.php
  15. 114
      app/Controller/DeviceController.php
  16. 25
      app/Controller/IndexController.php
  17. 413
      app/Controller/NotifyController.php
  18. 38
      app/Controller/OrderController.php
  19. 40
      app/Controller/ParamsTokenController.php
  20. 135
      app/Controller/PaymentController.php
  21. 86
      app/Controller/StoreController.php
  22. 81
      app/Controller/TestController.php
  23. 31
      app/Controller/UserController.php
  24. 35
      app/Exception/Handler/FilesystemExceptionHandler.php
  25. 33
      app/Exception/Handler/SsdbExceptionHandler.php
  26. 2
      app/Exception/Handler/ValidationExceptionHandler.php
  27. 18
      app/Exception/SsdbException.php
  28. 307
      app/Libs/FeiePrintClient.php
  29. 1098
      app/Libs/MQTTClient.php
  30. 622
      app/Libs/SimpleSSDB.php
  31. 31
      app/Listener/ValidatorFactoryResolvedListener.php
  32. 2
      app/Middleware/Auth/ApiMiddleware.php
  33. 34
      app/Middleware/CorsMiddleware.php
  34. 70
      app/Model/Ad.php
  35. 3
      app/Model/Coupon.php
  36. 10
      app/Model/CouponUserRec.php
  37. 10
      app/Model/CouponUserUse.php
  38. 14
      app/Model/Goods.php
  39. 12
      app/Model/Order.php
  40. 9
      app/Model/OrderGoods.php
  41. 87
      app/Model/OrderMain.php
  42. 31
      app/Model/OrderSalesStatistic.php
  43. 16
      app/Model/SpeakerDevic.php
  44. 18
      app/Model/SpecCombination.php
  45. 10
      app/Model/Store.php
  46. 9
      app/Model/StoreAccount.php
  47. 11
      app/Model/SystemConfig.php
  48. 1
      app/Model/Users.php
  49. 47
      app/Request/AttachmentRequest.php
  50. 26
      app/Request/BaseFormRequest.php
  51. 45
      app/Request/CouponGetListRequest.php
  52. 45
      app/Request/CouponRebateReceiveRequest.php
  53. 48
      app/Request/CouponRebateTieRequest.php
  54. 46
      app/Request/ImageBase64Request.php
  55. 46
      app/Request/ImageRequest.php
  56. 42
      app/Request/OrderOfflineRequest.php
  57. 70
      app/Request/OrderOnlineRequest.php
  58. 45
      app/Request/UserUnionidRequest.php
  59. 38
      app/Request/WxminiPayRequest.php
  60. 22
      app/Service/AdService.php
  61. 11
      app/Service/AdServiceInterface.php
  62. 73
      app/Service/AttachmentService.php
  63. 23
      app/Service/AttachmentServiceInterface.php
  64. 25
      app/Service/CommonService.php
  65. 531
      app/Service/CouponRebateService.php
  66. 24
      app/Service/CouponRebateServiceInterface.php
  67. 223
      app/Service/CouponService.php
  68. 30
      app/Service/CouponServiceInterface.php
  69. 135
      app/Service/DeviceServiceImp.php
  70. 12
      app/Service/DeviceServiceInterface.php
  71. 232
      app/Service/FeiePrintService.php
  72. 10
      app/Service/FeiePrintServiceInterface.php
  73. 54
      app/Service/IOTAliService.php
  74. 8
      app/Service/IOTServiceInterface.php
  75. 209
      app/Service/MiniprogramService.php
  76. 41
      app/Service/MiniprogramServiceInterface.php
  77. 29
      app/Service/MqttServiceInterface.php
  78. 81
      app/Service/MqttSpeakerService.php
  79. 536
      app/Service/OrderService.php
  80. 29
      app/Service/OrderServiceInterface.php
  81. 20
      app/Service/ParamsTokenServiceInterface.php
  82. 84
      app/Service/ParamsTokenSsdbService.php
  83. 79
      app/Service/UserService.php
  84. 29
      app/Service/UserServiceInterface.php
  85. 62
      app/TaskWorker/AliIotTask.php
  86. 46
      app/TaskWorker/SSDBTask.php
  87. 14
      composer.json
  88. 33
      config/autoload/amqp.php
  89. 15
      config/autoload/dependencies.php
  90. 4
      config/autoload/exceptions.php
  91. 94
      config/autoload/file.php
  92. 2
      config/autoload/middlewares.php
  93. 3
      config/autoload/server.php
  94. 24
      config/autoload/snowflake.php
  95. 13
      config/config.php
  96. 37
      config/routes.php

1
.gitignore

@ -12,3 +12,4 @@ vendor/
*.lock
.phpunit*
/watch
.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

73
app/Amqp/Consumer/DevicOrderConsumer.php

@ -0,0 +1,73 @@
<?php
declare(strict_types=1);
namespace App\Amqp\Consumer;
use App\Model\Order;
use App\Model\SpeakerDevic;
use App\Service\DeviceServiceInterface;
use Hyperf\Amqp\Result;
use Hyperf\Amqp\Annotation\Consumer;
use Hyperf\Amqp\Message\ConsumerMessage;
use Hyperf\DbConnection\Db;
use PhpAmqpLib\Message\AMQPMessage;
use Hyperf\Di\Annotation\Inject;
/**
* @Consumer(exchange="devicOrder", routingKey="devicOrder", queue="devicOrder", nums=4)
*/
class DevicOrderConsumer extends ConsumerMessage
{
/**
* @Inject
* @var DeviceServiceInterface
*/
protected $deviceService;
public function consumeMessage($data, AMQPMessage $message): string
{
try {
$orderMainId = $message->getBody();
$order = Order::query()
->select(['id', 'store_id', 'money'])
->where(['order_main_id' => $orderMainId, 'type' => 4, 'dm_state' => 2])
->first();
if (is_null($order)||!$order) {
return Result::ACK;
}
$deviceNames = SpeakerDevic::query()
->select(['device_name'])
->where(['store_id' => $order['store_id'], 'is_bind' => SpeakerDevic::IS_BIND_YES])
->get()
->toArray();
if (empty($deviceNames)||!$deviceNames) {
return Result::ACK;
}
$msg = "{\"msg\":\"到账".$order['money']."\"}";
$res = $this->deviceService->pubMsgToStoreByDevName($deviceNames, $msg);
if ($res == true) {
return Result::ACK;
} else {
return Result::REQUEUE;
}
} catch (\Exception $e) {
return Result::REQUEUE;
}
}
public function isEnable(): bool
{
if(env('APP_ENV') == 'local') {
return false;
}
return parent::isEnable();
}
}

42
app/Amqp/Consumer/couponRebateConsumer.php

@ -0,0 +1,42 @@
<?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="deviceCouponRebate", routingKey="deviceCouponRebate", queue="deviceCouponRebate", name ="couponRebateConsumer", nums=1)
*/
class couponRebateConsumer extends ConsumerMessage
{
/**
* @Inject
* @var CouponRebateService
*/
protected $CouponRebateService;
public function consumeMessage($data, AMQPMessage $message): string
{
$res = $this->CouponRebateService->couponRebate($data);
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(
env('LOG_HOST','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;
}
}

21
app/Constants/ErrorCode.php

@ -33,4 +33,25 @@ class ErrorCode extends AbstractConstants
* @Message("Save failure!");
*/
const SAVE_FAILURE = 100;
/**
* @Message("Ssdb Error!")
*/
const SSDB_ERROR = 600;
/**
* @Message("Upload failure!")
*/
const UPLOAD_INVALID = 200;
/**
* @Message("Order failure!")
*/
const ORDER_FAILURE = 300;
/**
* @Message("Pay failure!")
*/
const PAY_FAILURE = 400;
}

36
app/Constants/LogLabel.php

@ -0,0 +1,36 @@
<?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';
/**
* @Message("Device Speaker Log Label")
*/
const DEVICE_LOG = 'device_log';
/**
* @Message("Pay Notice Log Label")
*/
const PAY_NOTIFY_WXMINI = 'notify_wxmini';
/**
* @Message("Order Log Label")
*/
const ORDER_LOG = 'order_log';
}

49
app/Constants/SsdbKeysPrefix.php

@ -0,0 +1,49 @@
<?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';
/**
* @Message("Store New User")
*/
const STORE_NEW_USER = 'store_new_user_';
/**
* @Message("Coupon rebate List")
*/
const COUPON_REBATE_LIST = 'coupon_rebate_list_';
}

16
app/Controller/AbstractController.php

@ -15,9 +15,18 @@ use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Psr\Container\ContainerInterface;
use Hyperf\Validation\Contract\ValidatorFactoryInterface;
use App\Commons\Log;
abstract class AbstractController
{
/**
* @Inject
* @var Log
*/
protected $log;
/**
* @Inject
* @var ContainerInterface
@ -35,4 +44,11 @@ abstract class AbstractController
* @var ResponseInterface
*/
protected $response;
/**
* @Inject
* @var ValidatorFactoryInterface
*/
protected $validationFactory;
}

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());
}
}

68
app/Controller/AttachmentController.php

@ -0,0 +1,68 @@
<?php
namespace App\Controller;
use App\Request\AttachmentRequest;
use App\Request\ImageBase64Request;
use App\Service\AttachmentServiceInterface;
use Hyperf\Di\Annotation\Inject;
use App\Request\ImageRequest;
use League\Flysystem\Filesystem;
class AttachmentController extends BaseController
{
/**
* @Inject
* @var AttachmentServiceInterface
*/
protected $attachmentService;
/**
* 单文件表单上传
* @param AttachmentRequest $request
* @param Filesystem $filesystem
* @return \Psr\Http\Message\ResponseInterface
*/
public function upload(AttachmentRequest $request, Filesystem $filesystem)
{
$file = $this->request->file('upload');
$type = $this->request->input('type', '');
$fileName = $this->attachmentService->formUpload($file, $type, $filesystem, 'file');
return $this->success(['file_path' => $fileName]);
}
/**
* 单图表单上传
* @param ImageRequest $request
* @param Filesystem $filesystem
* @return \Psr\Http\Message\ResponseInterface
*/
public function uploadImage(ImageRequest $request, Filesystem $filesystem)
{
$file = $this->request->file('upload');
$type = $this->request->input('type', '');
$fileName = $this->attachmentService->formUpload($file, $type, $filesystem);
return $this->success(['file_path' => $fileName]);
}
/**
* 单图base64上传
* @param ImageBase64Request $request
* @param Filesystem $filesystem
* @return \Psr\Http\Message\ResponseInterface
*/
public function uploadImageByBase64(ImageBase64Request $request, Filesystem $filesystem)
{
$base64Code = $this->request->input('upload');
$type = $this->request->input('type', '');
$fileName = $this->attachmentService->base64Upload($base64Code, $type, $filesystem);
return $this->success(['file_path' => $fileName]);
}
}

9
app/Controller/BaseController.php

@ -13,9 +13,18 @@ namespace App\Controller;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Psr\Http\Message\ResponseInterface as Psr7ResponseInterface;
use Hyperf\HttpMessage\Stream\SwooleStream;
class BaseController extends AbstractController
{
public function w7result($statusCode,$data = ''){
return $this->response
->withHeader('Content-Type', 'application/text')
->withStatus($statusCode)
->withBody(new SwooleStream($data));
}
public function result($code, $data, $message = '成功'):Psr7ResponseInterface
{
$status = 'ok';

92
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);
}
//统计用户
@ -205,11 +153,23 @@ class CouponController extends BaseController
['receive.user_id','=',$userId],
])
->whereIn('receive.status',[0,1])
->select('u.*','receive.number_remain')
->select('u.title','u.discounts','u.full_amount','u.discount_type','u.introduce','u.usable_end_time','receive.number_remain')
->orderBy('u.weigh','desc')
->get();
foreach ($coupons as $key => $coupon) {
//拼接满减文字提示
$coupon->full_amount_text = '满' . $coupon->full_amount . "可用";
//判断是折扣优惠券还是满减优惠券
if($coupon->discount_type == 1){
$coupon->discounts_text = '¥'.$coupon->discounts;
}elseif($coupon->discount_type == 2){
$coupon->discounts_text = floatval($coupon->discounts)."";
}
//失效时间格式转换
$usable_end_time = date('Y-m-d H:i:s',$coupon->usable_end_time);
$coupon->usable_end_time_text = '有效期至:'.$usable_end_time;
if ($coupon->usable_end_time < $nowTime || $coupon->number_remain <= 0) {
$expired[] = $coupon;
} else {

87
app/Controller/CouponRebateController.php

@ -0,0 +1,87 @@
<?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;
use App\Request\UserRequest;
class CouponRebateController extends BaseController
{
/**
* @Inject
* @var CouponRebateServiceInterface
*/
protected $CouponRebateService;
/**
* 用户是否领取过领取优惠券
*/
public function isCouponRebate(UserRequest $validator)
{
$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));
}
}

114
app/Controller/DeviceController.php

@ -0,0 +1,114 @@
<?php
namespace App\Controller;
use Hyperf\Di\Annotation\Inject;
use App\Exception\BusinessException;
use App\Service\DeviceServiceInterface;
use Hyperf\Validation\ValidationException;
class DeviceController extends BaseController
{
/**
* @Inject
* @var DeviceServiceInterface
*/
protected $deviceService;
public function bind()
{
$validator = $this->validationFactory->make(
$this->request->all(),
[
'store_id' => 'required|nonempty|integer',
'device_name' => 'required|nonempty|alpha_num',
],
[
'store_id.required' => '参数不正确',
'store_id.nonempty' => '参数不正确',
'store_id.integer' => '参数不正确',
'device_name.required' => '参数不正确',
'device_name.nonempty' => '参数不正确',
'device_name.alpha_num' => '参数不正确',
]
);
if ($validator->fails()) {
// Handle exception
throw new ValidationException($validator);
return;
}
$store_id = $this->request->input('store_id');
$device_name = $this->request->input('device_name');
$sd = $this->deviceService->bindByStoreId($device_name, $store_id);
if (is_null($sd)) {
return $this->result(100, '', '绑定失败: 设备号已经被绑定或不存在');
}
return $this->success($sd, '绑定成功');
}
public function list()
{
$validator = $this->validationFactory->make(
$this->request->all(),
[
'store_id' => 'required|nonempty|integer',
],
[
'store_id.required' => '参数不正确',
'store_id.nonempty' => '参数不正确',
'store_id.integer' => '参数不正确',
]
);
if ($validator->fails()) {
// Handle exception
throw new ValidationException($validator);
return;
}
$store_id = $this->request->input('store_id');
$devices = $this->deviceService->getListByStoreId($store_id);
return $this->success($devices);
}
public function unbind()
{
$validator = $this->validationFactory->make(
$this->request->all(),
[
'bind_id' => 'required|nonempty|integer',
],
[
'bind_id.required' => '参数不正确',
'bind_id.nonempty' => '参数不正确',
'bind_id.integer' => '参数不正确',
]
);
if ($validator->fails()) {
// Handle exception
throw new ValidationException($validator);
return;
}
$bind_id = $this->request->input('bind_id');
$unbind_num = $this->deviceService->unbindById($bind_id);
if ($unbind_num == 0) {
return $this->result(100, '', '解绑失败: 设备已经解绑或不存在');
}
return $this->success(['unbind' => $unbind_num]);
}
}

25
app/Controller/IndexController.php

@ -11,6 +11,13 @@ declare(strict_types=1);
*/
namespace App\Controller;
use Hyperf\HttpServer\Annotation\AutoController;
use League\Flysystem\Filesystem;
/**
* @AutoController()
* @package App\Controller
*/
class IndexController extends AbstractController
{
public function index()
@ -20,7 +27,23 @@ class IndexController extends AbstractController
return [
'method' => $method,
'message' => "Hello22222 {$user}.",
'message' => floatval(2.00),
];
}
public function example(Filesystem $filesystem)
{
$file = $this->request->file('upload');
var_dump($file);die;
$fileContent = file_get_contents($file->getRealPath());
var_dump($fileContent);die;
$stream = fopen($file->getRealPath(),'r+');
$filesystem->writeStream('uplaods/'.$file->getClientFilename(),$stream);
fclose($stream);
}
}

413
app/Controller/NotifyController.php

@ -0,0 +1,413 @@
<?php
namespace App\Controller;
use App\Constants\LogLabel;
use App\Model\Goods;
use App\Model\Order;
use App\Model\OrderGoods;
use App\Model\OrderMain;
use App\Model\OrderSalesStatistic;
use App\Model\SpecCombination;
use App\Model\Store;
use App\Model\StoreAccount;
use App\Model\SystemConfig;
use App\Model\Users;
use App\Service\CouponRebateServiceInterface;
use App\Service\DeviceServiceInterface;
use App\Service\FeiePrintServiceInterface;
use App\Service\MiniprogramServiceInterface;
use App\Service\MqttServiceInterface;
use App\Service\UserServiceInterface;
use EasyWeChat\Factory;
use Hyperf\DbConnection\Db;
use Hyperf\Guzzle\CoroutineHandler;
use Exception;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Symfony\Component\HttpFoundation\Request;
class NotifyController extends BaseController
{
const AWARD_LIMIT_AMOUNT = 3;
/**
* @Inject
* @var MqttServiceInterface
*/
protected $mqttSpeakerService;
/**
* @Inject
* @var DeviceServiceInterface
*/
protected $deviceService;
/**
* @Inject
* @var MiniprogramServiceInterface
*/
protected $miniprogramService;
/**
* @Inject
* @var FeiePrintServiceInterface
*/
protected $feiePrintService;
/**
* @Inject
* @var UserServiceInterface
*/
protected $userService;
/**
* @Inject
* @var CouponRebateServiceInterface
*/
protected $couponRebateService;
public function wxminiOnline()
{
$config = config('wxpay');
$app = Factory::payment($config);
$app['guzzle_handler'] = CoroutineHandler::class;
$get = $this->request->getQueryParams();
$post = $this->request->getParsedBody();
$cookie = $this->request->getCookieParams();
$files = $this->request->getUploadedFiles();
$server = $this->request->getServerParams();
$xml = $this->request->getBody()->getContents();
$app['request'] = new Request($get,$post,[],$cookie,$files,$server,$xml);
// 通知回调,进行业务处理
$response = $app->handlePaidNotify(function ($message, $fail) use ($app) {
Db::beginTransaction();
try {
// 支付失败或者通知失败
if (
empty($message)
|| $message['return_code'] != 'SUCCESS'
|| !isset($message['result_code'])
|| $message['result_code'] != 'SUCCESS'
) {
$this->log->event(
LogLabel::PAY_NOTIFY_WXMINI,
$message
);
Db::rollBack();
$fail('Unknown error but FAIL');
}
// 查询订单
$orderMain = OrderMain::query()
->where([
'global_order_id' => $message['out_trade_no'],
'type' => OrderMain::ORDER_TYPE_ONLINE
])
->first();
// 订单不存在
if (empty($orderMain)) {
$this->log->event(
LogLabel::PAY_NOTIFY_WXMINI,
['global_order_id_fail' => $message['out_trade_no']]
);
Db::rollBack();
return true;
}
// 修改订单、子订单状态
$currentTime = time();
$orderMain->state = OrderMain::ORDER_STATE_UNTAKE;
$orderMain->time_pay = $currentTime;
$orderMain->pay_time = date('Y-m-d H:i:s', $currentTime);
$orderMain->save();
$upOrder = Order::query()
->where(['order_main_id' => $orderMain->id])
->update(['state' => OrderMain::ORDER_STATE_UNTAKE, 'pay_time' => $orderMain->pay_time]);
// 更新商户销量
$upStoreScore = Store::query()
->whereIn('id', explode(',', $orderMain->store_ids))
->update(['score' => Db::raw('score+1')]);
// 更新商品库存和销量
$orders = Order::query()->select(['id', 'money', 'user_id', 'store_id', 'pay_time'])
->where(['order_main_id' => $orderMain->id])
->get()
->toArray();
$orderGoods = OrderGoods::query()->select(['good_id AS id', 'number', 'combination_id'])
->whereIn('order_id', array_values(array_column($orders, 'id')))
->get()
->toArray();
foreach ($orderGoods as $key => &$goodsItem) {
$goods = Goods::find($goodsItem['id']);
// 库存处理,有规格
if ($goodsItem['combination_id']) {
$combination = SpecCombination::find($goodsItem['combination_id']);
$combination->number = $combination->number - $goodsItem['number'];
$combination->save();
} else {
$goods->inventory = $goods->inventory - $goodsItem['number'];
}
$goods->sales = $goods->sales - $goodsItem['number'];
$goods->save();
}
// 月销流水
$statistics = [];
foreach ($orders as $key => &$order) {
$statistics[] = [
'money' => $order['money'],
'user_id' => $order['user_id'],
'store_id' => $order['store_id'],
'market_id' => $orderMain->market_id,
'order_id' => $order['id'],
'createtime' => strtotime($order['pay_time']),
];
}
if (is_array($statistics) && !empty($statistics)) {
$inSalesStatistics = OrderSalesStatistic::query()->insert($statistics);
}
// 优惠券返券
$this->couponRebateService->couponRebateInTask($orderMain->id);
// 喇叭通知,兼容旧音响,MQTT+IOT
$res = $this->mqttSpeakerService->speakToStore($orderMain->id);
$this->log->event(
LogLabel::PAY_NOTIFY_WXMINI,
['fail_mqtt' => json_encode($res)]
);
$res = $this->deviceService->pubMsgToStoreByOrderMainId($orderMain->id);
$this->log->event(
LogLabel::PAY_NOTIFY_WXMINI,
['fail_device' => json_encode($res)]
);
// 公众号模板消息
$res = $this->miniprogramService->sendTemMsgForOnlineOrder($orderMain->id);
$this->log->event(
LogLabel::PAY_NOTIFY_WXMINI,
['fail_mini' => json_encode($res)]
);
// 打印订单,自动打印 TODO 后续优化调用逻辑
$res = $this->feiePrintService->feiePrint($orderMain->global_order_id);
$this->log->event(
LogLabel::PAY_NOTIFY_WXMINI,
['fail_feie' => json_encode($res)]
);
Db::commit();
return true;
} catch (Exception $e) {
$this->log->event(
LogLabel::PAY_NOTIFY_WXMINI,
['exception_fail' => $e->getMessage()]
);
Db::rollBack();
$fail('Exception');
}
});
return $this->response
->withHeader('Content-Type', 'text/xml')
->withStatus(200)
->withBody(new SwooleStream($response->getContent()));
}
public function wxminiOffline()
{
$config = config('wxpay');
$app = Factory::payment($config);
$app['guzzle_handler'] = CoroutineHandler::class;
$get = $this->request->getQueryParams();
$post = $this->request->getParsedBody();
$cookie = $this->request->getCookieParams();
$files = $this->request->getUploadedFiles();
$server = $this->request->getServerParams();
$xml = $this->request->getBody()->getContents();
$app['request'] = new Request($get,$post,[],$cookie,$files,$server,$xml);
// 通知回调,进行业务处理
$response = $app->handlePaidNotify(function ($message, $fail) use ($app) {
Db::beginTransaction();
try {
// 支付失败或者通知失败
if (
empty($message)
|| $message['return_code'] != 'SUCCESS'
|| !isset($message['result_code'])
|| $message['result_code'] != 'SUCCESS'
) {
$this->log->event(
LogLabel::PAY_NOTIFY_WXMINI,
$message
);
Db::rollBack();
$fail('Unknown error but FAIL');
}
// 查询订单
$orderMain = OrderMain::query()
->where([
'global_order_id' => $message['out_trade_no'],
'type' => OrderMain::ORDER_TYPE_OFFLINE
])
->first();
// 订单不存在
if (empty($orderMain)) {
$this->log->event(
LogLabel::PAY_NOTIFY_WXMINI,
['global_order_id_fail' => $message['out_trade_no']]
);
Db::rollBack();
return true;
}
// 修改订单、子订单状态
$currentTime = time();
$orderMain->state = OrderMain::ORDER_STATE_UNTAKE;
$orderMain->dm_state = OrderMain::ORDER_STATE_UNTAKE;
$orderMain->time_pay = $currentTime;
$orderMain->pay_time = date('Y-m-d H:i:s', $currentTime);
$orderMain->save();
$upOrder = Order::query()
->where(['order_main_id' => $orderMain->id])
->update([
'state' => OrderMain::ORDER_STATE_UNTAKE,
'dm_state' => OrderMain::ORDER_STATE_UNTAKE,
'pay_time' => date('Y-m-d H:i:s', $currentTime)
]);
// 查询子订单,当面付目前实际上只有一个子订单
$orders = Order::query()->select(['id', 'money', 'user_id', 'store_id', 'pay_time'])
->where(['order_main_id' => $orderMain->id])
->get()
->toArray();
// 商户钱包、流水资金、奖励、发布模板消息处理
foreach ($orders as $key => $orderItem) {
$recordBase = [
'user_id' => $orderItem['user_id'],
'order_id' => $orderItem['id'],
'store_id' => $orderItem['store_id'],
'type' => 1,
'time' => date('Y-m-d H:i:s', $currentTime),
'add_time' => $currentTime,
];
// 钱包
$store = Store::find($orderItem['store_id']);
$store->store_wallet = bcadd($store->store_wallet, $orderItem['money'], 2);
$store->save();
// 流水
$record = [
'money' => $orderItem['money'],
'note' => '当面付订单收入',
'category' => 2,
];
StoreAccount::query()->insert(array_merge($recordBase, $record));
// 平台新用户奖励给商户
$isStageNewUser = $this->userService->isStageNewUser($orderItem['user_id'], $orderMain->id);
$needAward = false;
$awardAmount = 0;
if ($isStageNewUser) {
$awardAmount = SystemConfig::query()->where(['type' => 1, 'menu_name' => 'award_new_user'])->value('value');
// 流水
$record = [
'money' => $awardAmount,
'note' => '新用户下单成功,平台奖励',
'category' => 3,
];
$needAward = true;
} else {
$isStoreFirstOrderToday = $this->userService->isStoreFirstOrderToday($orderItem['user_id'],$orderItem['store_id'],$orderItem['id'], self::AWARD_LIMIT_AMOUNT);
if ($isStoreFirstOrderToday && $orderItem['money'] >= self::AWARD_LIMIT_AMOUNT) {
$awardAmount = SystemConfig::query()->where(['type' => 1, 'menu_name' => 'award_each_order'])->value('value');
// 流水
$record = [
'money' => $awardAmount,
'note' => '用户下单成功,平台奖励',
'category' => 4,
];
$needAward = true;
}
}
if ($needAward && $awardAmount) {
// 奖励钱包
$store->refresh();
$store->award_money = bcadd($store->award_money, $awardAmount, 2);
$store->save();
// 流水
StoreAccount::query()->insert(array_merge($recordBase, $record));
// 发布公众号消息
$openid = Users::query()->where(['id' => $store['user_id']])->value('openid');
$res = $this->miniprogramService->sendTemMsgForAward($record['money'], $record['note'], $openid, $recordBase['time']);
}
}
// 喇叭通知,兼容旧音响,MQTT+IOT
$res = $this->mqttSpeakerService->speakToStore($orderMain->id);
$this->log->event(
LogLabel::PAY_NOTIFY_WXMINI,
['fail_mqtt' => json_encode($res)]
);
$res = $this->deviceService->pubMsgToStoreByOrderMainId($orderMain->id);
$this->log->event(
LogLabel::PAY_NOTIFY_WXMINI,
['fail_device' => json_encode($res)]
);
// 公众号模板消息
$res = $this->miniprogramService->sendTemMsgForOfflineOrder($orderMain->id);
$this->log->event(
LogLabel::PAY_NOTIFY_WXMINI,
['fail_mini' => json_encode($res)]
);
Db::commit();
return true;
} catch (Exception $e) {
$this->log->event(
LogLabel::PAY_NOTIFY_WXMINI,
['exception_fail' => $e->getMessage()]
);
Db::rollBack();
$fail('Exception');
}
});
return $this->response
->withHeader('Content-Type', 'text/xml')
->withStatus(200)
->withBody(new SwooleStream($response->getContent()));
}
}

38
app/Controller/OrderController.php

@ -0,0 +1,38 @@
<?php
namespace App\Controller;
use App\Constants\ErrorCode;
use App\Request\OrderOfflineRequest;
use App\Request\OrderOnlineRequest;
use Hyperf\Di\Annotation\Inject;
use App\Service\OrderServiceInterface;
use Hyperf\HttpMessage\Stream\SwooleStream;
class OrderController extends BaseController
{
/**
* @Inject
* @var OrderServiceInterface
*/
protected $orderService;
public function addOnlineOrder(OrderOnlineRequest $request)
{
$orderMainId = $this->orderService->addOnlineOrder($request->validated());
if (!is_int($orderMainId)) {
return $this->result(ErrorCode::ORDER_FAILURE, '', $orderMainId);
}
return $this->success(['order_id' => $orderMainId]);
}
public function addOfflineOrder(OrderOfflineRequest $request)
{
$orderMainId = $this->orderService->addOfflineOrder($request->validated());
if (!is_int($orderMainId)) {
return $this->result(ErrorCode::ORDER_FAILURE, '', $orderMainId);
}
return $this->success(['order_id' => $orderMainId]);
}
}

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);
}
}

135
app/Controller/PaymentController.php

@ -0,0 +1,135 @@
<?php
namespace App\Controller;
use App\Constants\ErrorCode;
use App\Model\OrderMain;
use App\Request\WxminiPayRequest;
use EasyWeChat\Factory;
use Hyperf\Guzzle\CoroutineHandler;
class PaymentController extends BaseController
{
public function wxminiPayOnline(WxminiPayRequest $request){
$data = $request->validated();
$config = config('wxpay');
$app = Factory::payment($config);
$app['guzzle_handler'] = CoroutineHandler::class;
// 待支付的,未超时(15min,900sec)的订单
$orderMain = OrderMain::query()
->where(['state' => OrderMain::ORDER_STATE_UNPAY, 'id' => $data['order_id']])
->where('time', '>=', date('Y-m-d H:i:s', (time()-900)))
->first();
if (empty($orderMain)) {
return $this->result(ErrorCode::PAY_FAILURE, $data,'订单不存在或已失效');
}
$result = $app->order->unify([
'body' => '懒族生活 - 外卖下单',
'out_trade_no' => $orderMain->global_order_id,
'total_fee' => bcmul(floatval($orderMain->money), 100, 0),
'notify_url' => config('site_host') . '/wechat/notify/wxminionline',
'trade_type' => 'JSAPI',
'openid' => $data['openid'],
]);
// 返回支付参数给前端
$parameters = [
'appId' => $result['appid'],
'timeStamp' => '' . time() . '',
'nonceStr' => uniqid(),
'package' => 'prepay_id=' . $result['prepay_id'],
'signType' => 'MD5'
];
$parameters['paySign'] = $this->signture($parameters, $config['key']);
return $this->success($parameters);
}
public function wxminiPayOffline(WxminiPayRequest $request){
$data = $request->validated();
$config = config('wxpay');
$app = Factory::payment($config);
$app['guzzle_handler'] = CoroutineHandler::class;
// 待支付的,未超时(15min,900sec)的订单
$orderMain = OrderMain::query()
->where(['dm_state' => OrderMain::ORDER_STATE_UNPAY, 'id' => $data['order_id']])
->first();
if (empty($orderMain)) {
return $this->result(ErrorCode::PAY_FAILURE, $data,'订单不存在或已失效');
}
$result = $app->order->unify([
'body' => '懒族生活 - 当面支付',
'out_trade_no' => $orderMain->global_order_id,
'total_fee' => bcmul(floatval($orderMain->money), 100, 0),
'notify_url' => config('site_host') . '/wechat/notify/wxminioffline',
'trade_type' => 'JSAPI',
'openid' => $data['openid'],
]);
// 返回支付参数给前端
$parameters = [
'appId' => $result['appid'],
'timeStamp' => '' . time() . '',
'nonceStr' => uniqid(),
'package' => 'prepay_id=' . $result['prepay_id'],
'signType' => 'MD5'
];
$parameters['paySign'] = $this->signture($parameters, $config['key']);
return $this->success($parameters);
}
/**
* 支付参数加签
* @param $parameters
* @param $key
* @return string
*/
private function signture($parameters, $key)
{
// 按字典序排序参数
ksort($parameters);
// http_query
$queryParams = $this->http_query($parameters);
// 加入KEY
$queryParams = $queryParams . "&key=" . $key;
// MD5加密
$queryParams = md5($queryParams);
// 字符转为大写
return strtoupper($queryParams);
}
/**
* 参数转为http query字串
* @param $parameters
* @return string
*/
private function http_query($parameters) {
$http_query = [];
foreach ($parameters as $key => $value) {
$http_query[] = $key.'='.$value;
}
return implode('&', $http_query);
}
}

86
app/Controller/StoreController.php

@ -0,0 +1,86 @@
<?php
declare(strict_types=1);
namespace App\Controller;
use Hyperf\DbConnection\Db;
use Hyperf\HttpServer\Annotation\AutoController;
use OSS\Core\OssException;
use OSS\OssClient;
/**
* @AutoController()
* Class StoreController
* @package App\Controller
*/
class StoreController extends BaseController
{
public function infoEdit()
{
$id = $this->request->input('id');
if (empty($id)) {
return $this->result(1, [], 'id不能为空');
}
if ($this->request->isMethod('post')) {
$logo = $this->request->input('logo');
$name = $this->request->input('name');
$tel = $this->request->input('tel');
$address = $this->request->input('address');
$coordinates = $this->request->input('coordinates');
$capita = $this->request->input('capita');
$start_at = $this->request->input('start_at');
$announcement = $this->request->input('announcement');
$environment = $this->request->input('environment');
//>>1上传logo到阿里云oss
//>>2.上传商家环境到阿里云oss
//>>3.保存数据到数据库存
$fileNameLogo = $object = 'public/upload/' . date('Y') . '/' . date('m-d') . '/' . rand(0, 9999999999999999) . '.jpg';
$fileUpload = new FileUpload();
$resLogo = $fileUpload->ossUpload($logo, $fileNameLogo);
if (isset($resLogo['info']['http_code']) && $resLogo['info']['http_code'] == 200) {
$logo_url = $fileNameLogo;
} else {
return $this->result(1, []);
}
$environments = explode(',', $environment);
$envPaths = [];
foreach ($environments as $env) {
$fileNameEnv = $object = 'public/upload/' . date('Y') . '/' . date('m-d') . '/' . rand(0, 9999999999999999) . '.jpg';
$resEnv = $fileUpload->ossUpload($env, $fileNameEnv);
if (isset($resEnv['info']['http_code']) && $resLogo['info']['http_code'] == 200) {
$envPaths[] = $fileNameEnv;
}
}
if (count($envPaths)) {
$envPath = implode(',', $envPaths);
}
$res = Db::table('ims_cjdc_store')->where('id', $id)->update([
'logo' => $logo_url ?? "",
'name' => $name,
'tel' => $tel,
'address' => $address,
'coordinates' => $coordinates,
'capita' => $capita,
'start_at' => $start_at,
'announcement' => $announcement,
'environment' => $envPath ?? "",
]);
return $this->success($res);
}
//'id','name','logo','tel','address','coordinates','capita','start_at','announcement','environment'
//获取店铺信息
$data = Db::table('ims_cjdc_store')
->select(['id','name','logo','tel','address','coordinates','capita','start_at','announcement','environment'])
->where('id',$id)
->first();
if ($data){
$data->site = config('site_host');
}
return $this->success($data);
}
}

81
app/Controller/TestController.php

@ -0,0 +1,81 @@
<?php
declare(strict_types=1);
namespace App\Controller;
use App\Libs\FeiePrintClient;
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';
protected $client = null;
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;
$time = time();
$msgInfo = array(
'user' => '13161443713@163.com',
'stime' => $time,
'sig' => sha1('13161443713@163.com' . 'XsaHzgePdyWTfcMX' . $time),
'apiname' => 'Open_printMsg',
'sn' => '920527381',
'content' => '1111',
'times' => 1//打印次数
);
$this->client = new FeiePrintClient('api.feieyun.cn', 80);
if (!$this->client->post('/Api/Open/', $msgInfo)) {
return '12';
} else {
//服务器返回的JSON字符串,建议要当做日志记录起来
$result = $this->client->getContent();
return $result;
}
}
public function index2(RequestInterface $request)
{
$this->name = 'index2 action';
return $this->name;
}
public function index3(RequestInterface $request)
{
return $this->name;
}
}

31
app/Controller/UserController.php

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace App\Controller;
use Hyperf\Di\Annotation\Inject;
use App\Service\UserServiceInterface;
use App\Request\UserUnionidRequest;
class UserController extends BaseController
{
/**
* @Inject
* @var UserServiceInterface
*/
protected $userService;
/**
* 根据用户的openid更新unionid信息
*/
public function saveUserUnionid(UserUnionidRequest $request)
{
$openid = $this->request->input('openid','');
$unionid = $this->request->input('unionid','');
return $this->success($this->userService->saveUserUnionid($openid,$unionid));
}
}

35
app/Exception/Handler/FilesystemExceptionHandler.php

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

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;
}
}

2
app/Exception/Handler/ValidationExceptionHandler.php

@ -24,7 +24,7 @@ class ValidationExceptionHandler extends ExceptionHandler
]);
return $response->withHeader('Content-Type', 'application/json')
->withStatus($throwable->status)
->withStatus(200)
->withBody(new SwooleStream($content));
}

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);
}
}

307
app/Libs/FeiePrintClient.php

@ -0,0 +1,307 @@
<?php
namespace App\Libs;
class FeiePrintClient {
// Request vars
var $host;
var $port;
var $path;
var $method;
var $postdata = '';
var $cookies = array();
var $referer;
var $accept = 'text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,image/jpeg,image/gif,*/*';
var $accept_encoding = 'gzip';
var $accept_language = 'en-us';
var $user_agent = 'Incutio HttpClient v0.9';
var $timeout = 20;
var $use_gzip = true;
var $persist_cookies = true;
var $persist_referers = true;
var $debug = false;
var $handle_redirects = true;
var $max_redirects = 5;
var $headers_only = false;
var $username;
var $password;
var $status;
var $headers = array();
var $content = '';
var $errormsg;
var $redirect_count = 0;
var $cookie_host = '';
function __construct($host, $port=80) {
$this->host = $host;
$this->port = $port;
}
function get($path, $data = false) {
$this->path = $path;
$this->method = 'GET';
if ($data) {
$this->path .= '?'.$this->buildQueryString($data);
}
return $this->doRequest();
}
function post($path, $data) {
$this->path = $path;
$this->method = 'POST';
$this->postdata = $this->buildQueryString($data);
return $this->doRequest();
}
function buildQueryString($data) {
$querystring = '';
if (is_array($data)) {
foreach ($data as $key => $val) {
if (is_array($val)) {
foreach ($val as $val2) {
$querystring .= urlencode($key).'='.urlencode($val2).'&';
}
} else {
$querystring .= urlencode($key).'='.urlencode($val).'&';
}
}
$querystring = substr($querystring, 0, -1); // Eliminate unnecessary &
} else {
$querystring = $data;
}
return $querystring;
}
function doRequest() {
if (!$fp = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout)) {
switch($errno) {
case -3:
$this->errormsg = 'Socket creation failed (-3)';
case -4:
$this->errormsg = 'DNS lookup failure (-4)';
case -5:
$this->errormsg = 'Connection refused or timed out (-5)';
default:
$this->errormsg = 'Connection failed ('.$errno.')';
$this->errormsg .= ' '.$errstr;
$this->debug($this->errormsg);
}
return false;
}
socket_set_timeout($fp, $this->timeout);
$request = $this->buildRequest();
$this->debug('Request', $request);
fwrite($fp, $request);
$this->headers = array();
$this->content = '';
$this->errormsg = '';
$inHeaders = true;
$atStart = true;
while (!feof($fp)) {
$line = fgets($fp, 4096);
if ($atStart) {
$atStart = false;
if (!preg_match('/HTTP\/(\\d\\.\\d)\\s*(\\d+)\\s*(.*)/', $line, $m)) {
$this->errormsg = "Status code line invalid: ".htmlentities($line);
$this->debug($this->errormsg);
return false;
}
$http_version = $m[1];
$this->status = $m[2];
$status_string = $m[3];
$this->debug(trim($line));
continue;
}
if ($inHeaders) {
if (trim($line) == '') {
$inHeaders = false;
$this->debug('Received Headers', $this->headers);
if ($this->headers_only) {
break;
}
continue;
}
if (!preg_match('/([^:]+):\\s*(.*)/', $line, $m)) {
continue;
}
$key = strtolower(trim($m[1]));
$val = trim($m[2]);
if (isset($this->headers[$key])) {
if (is_array($this->headers[$key])) {
$this->headers[$key][] = $val;
} else {
$this->headers[$key] = array($this->headers[$key], $val);
}
} else {
$this->headers[$key] = $val;
}
continue;
}
$this->content .= $line;
}
fclose($fp);
if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] == 'gzip') {
$this->debug('Content is gzip encoded, unzipping it');
$this->content = substr($this->content, 10);
$this->content = gzinflate($this->content);
}
if ($this->persist_cookies && isset($this->headers['set-cookie']) && $this->host == $this->cookie_host) {
$cookies = $this->headers['set-cookie'];
if (!is_array($cookies)) {
$cookies = array($cookies);
}
foreach ($cookies as $cookie) {
if (preg_match('/([^=]+)=([^;]+);/', $cookie, $m)) {
$this->cookies[$m[1]] = $m[2];
}
}
$this->cookie_host = $this->host;
}
if ($this->persist_referers) {
$this->debug('Persisting referer: '.$this->getRequestURL());
$this->referer = $this->getRequestURL();
}
if ($this->handle_redirects) {
if (++$this->redirect_count >= $this->max_redirects) {
$this->errormsg = 'Number of redirects exceeded maximum ('.$this->max_redirects.')';
$this->debug($this->errormsg);
$this->redirect_count = 0;
return false;
}
$location = isset($this->headers['location']) ? $this->headers['location'] : '';
$uri = isset($this->headers['uri']) ? $this->headers['uri'] : '';
if ($location || $uri) {
$url = parse_url($location.$uri);
return $this->get($url['path']);
}
}
return true;
}
function buildRequest() {
$headers = array();
$headers[] = "{$this->method} {$this->path} HTTP/1.0";
$headers[] = "Host: {$this->host}";
$headers[] = "User-Agent: {$this->user_agent}";
$headers[] = "Accept: {$this->accept}";
if ($this->use_gzip) {
$headers[] = "Accept-encoding: {$this->accept_encoding}";
}
$headers[] = "Accept-language: {$this->accept_language}";
if ($this->referer) {
$headers[] = "Referer: {$this->referer}";
}
if ($this->cookies) {
$cookie = 'Cookie: ';
foreach ($this->cookies as $key => $value) {
$cookie .= "$key=$value; ";
}
$headers[] = $cookie;
}
if ($this->username && $this->password) {
$headers[] = 'Authorization: BASIC '.base64_encode($this->username.':'.$this->password);
}
if ($this->postdata) {
$headers[] = 'Content-Type: application/x-www-form-urlencoded';
$headers[] = 'Content-Length: '.strlen($this->postdata);
}
$request = implode("\r\n", $headers)."\r\n\r\n".$this->postdata;
return $request;
}
function getStatus() {
return $this->status;
}
function getContent() {
return $this->content;
}
function getHeaders() {
return $this->headers;
}
function getHeader($header) {
$header = strtolower($header);
if (isset($this->headers[$header])) {
return $this->headers[$header];
} else {
return false;
}
}
function getError() {
return $this->errormsg;
}
function getCookies() {
return $this->cookies;
}
function getRequestURL() {
$url = 'https://'.$this->host;
if ($this->port != 80) {
$url .= ':'.$this->port;
}
$url .= $this->path;
return $url;
}
function setUserAgent($string) {
$this->user_agent = $string;
}
function setAuthorization($username, $password) {
$this->username = $username;
$this->password = $password;
}
function setCookies($array) {
$this->cookies = $array;
}
function useGzip($boolean) {
$this->use_gzip = $boolean;
}
function setPersistCookies($boolean) {
$this->persist_cookies = $boolean;
}
function setPersistReferers($boolean) {
$this->persist_referers = $boolean;
}
function setHandleRedirects($boolean) {
$this->handle_redirects = $boolean;
}
function setMaxRedirects($num) {
$this->max_redirects = $num;
}
function setHeadersOnly($boolean) {
$this->headers_only = $boolean;
}
function setDebug($boolean) {
$this->debug = $boolean;
}
function quickGet($url) {
$bits = parse_url($url);
$host = $bits['host'];
$port = isset($bits['port']) ? $bits['port'] : 80;
$path = isset($bits['path']) ? $bits['path'] : '/';
if (isset($bits['query'])) {
$path .= '?'.$bits['query'];
}
$client = new HttpClient($host, $port);
if (!$client->get($path)) {
return false;
} else {
return $client->getContent();
}
}
function quickPost($url, $data) {
$bits = parse_url($url);
$host = $bits['host'];
$port = isset($bits['port']) ? $bits['port'] : 80;
$path = isset($bits['path']) ? $bits['path'] : '/';
$client = new HttpClient($host, $port);
if (!$client->post($path, $data)) {
return false;
} else {
return $client->getContent();
}
}
function debug($msg, $object = false) {
if ($this->debug) {
print '<div style="border: 1px solid red; padding: 0.5em; margin: 0.5em;"><strong>HttpClient Debug:</strong> '.$msg;
if ($object) {
ob_start();
print_r($object);
$content = htmlentities(ob_get_contents());
ob_end_clean();
print '<pre>'.$content.'</pre>';
}
print '</div>';
}
}
}

1098
app/Libs/MQTTClient.php
File diff suppressed because it is too large
View File

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;
}
}

3
app/Model/Coupon.php

@ -6,6 +6,9 @@ use App\Model\Model;
class Coupon extends Model
{
const DISCOUNT_TYPE_CASH = 1;
const DISCOUNT_TYPE_RATE = 2;
protected $table = 'ims_system_coupon_user';
}

10
app/Model/CouponUserRec.php

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

10
app/Model/CouponUserUse.php

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

14
app/Model/Goods.php

@ -0,0 +1,14 @@
<?php
namespace App\Model;
class Goods extends Model
{
const INVENTORY_NOLIMIT = 1;
protected $table = 'ims_cjdc_goods';
public $timestamps = false;
}

12
app/Model/Order.php

@ -0,0 +1,12 @@
<?php
namespace App\Model;
class Order extends Model
{
protected $table = 'ims_cjdc_order';
public $timestamps = false;
}

9
app/Model/OrderGoods.php

@ -0,0 +1,9 @@
<?php
namespace App\Model;
class OrderGoods extends Model
{
protected $table = 'ims_cjdc_order_goods';
public $timestamps = false;
}

87
app/Model/OrderMain.php

@ -0,0 +1,87 @@
<?php
namespace App\Model;
class OrderMain extends Model
{
// 线上订单,外卖
const ORDER_TYPE_ONLINE = 1;
// 线下订单,当面付
const ORDER_TYPE_OFFLINE = 4;
// 订单状态
// 待付款
const ORDER_STATE_UNPAY = 1;
// 待接单
const ORDER_STATE_UNTAKE = 2;
// 待送达
const ORDER_STATE_DELIVERY = 3;
// 已完成
const ORDER_STATE_COMPLETE = 4;
// 已评价
const ORDER_STATE_EVALUATED = 5;
// 已取消
const ORDER_STATE_CANCEL = 6;
// 已拒单
const ORDER_STATE_REFUSE = 7;
// 退款中
const ORDER_STATE_REFUNDING = 8;
// 已退款
const ORDER_STATE_REFUNDED = 9;
// 拒绝退款
const ORDER_STATE_UNREFUND = 10;
// 订单支付方式
// 微信支付
const ORDER_PAY_WX = 1;
// 余额支付
const ORDER_PAY_BALANCE = 2;
protected $table = 'ims_cjdc_order_main';
public $timestamps = false;
protected $fillable = [
'order_num',
'delivery_no',
'dada_fee',
'market_id',
'user_id',
'money',
'box_money',
'ps_money',
'mj_money',
'xyh_money',
'yhq_money',
'yhq_money2',
'zk_money',
'tel',
'name',
'address',
'area',
'lat',
'lng',
'note',
'type',
'form_id',
'form_id2',
'delivery_time',
'pay_type',
'order_type',
'code',
'coupon_id',
'coupon_id2',
'uniacid',
'state',
'dm_state',
'time',
'time_add',
'pay_time',
'jj_note',
'global_order_id',
'store_ids',
];
}

31
app/Model/OrderSalesStatistic.php

@ -0,0 +1,31 @@
<?php
declare (strict_types=1);
namespace App\Model;
use Hyperf\DbConnection\Model\Model;
/**
*/
class OrderSalesStatistic extends Model
{
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'ims_cjdc_order_sales_statistics';
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [];
public $timestamps = false;
}

16
app/Model/SpeakerDevic.php

@ -0,0 +1,16 @@
<?php
namespace App\Model;
use App\Model\Model;
class SpeakerDevic extends Model
{
const IS_BIND_YES = 1;
const IS_BIND_NO = 0;
protected $table = 'lanzu_service_speakers';
protected $fillable = ['store_id', 'device_name', 'state', 'market_id', 'bind_time', 'is_bind'];
}

18
app/Model/SpecCombination.php

@ -0,0 +1,18 @@
<?php
namespace App\Model;
class SpecCombination extends Model
{
protected $table = 'ims_cjdc_spec_combination';
public $timestamps = false;
public function goods()
{
return $this->belongsTo(Goods::class, 'good_id', 'id');
}
}

10
app/Model/Store.php

@ -0,0 +1,10 @@
<?php
namespace App\Model;
class Store extends Model
{
protected $table = 'ims_cjdc_store';
public $timestamps = false;
}

9
app/Model/StoreAccount.php

@ -0,0 +1,9 @@
<?php
namespace App\Model;
class StoreAccount extends Model
{
protected $table = 'ims_cjdc_store_account';
public $timestamps = false;
}

11
app/Model/SystemConfig.php

@ -0,0 +1,11 @@
<?php
namespace App\Model;
class SystemConfig extends Model
{
protected $table = 'ims_cjdc_system_config';
public $timestamps = false;
}

1
app/Model/Users.php

@ -5,4 +5,5 @@ namespace App\Model;
class Users extends Model
{
protected $table = 'ims_cjdc_user';
public $timestamps = false;
}

47
app/Request/AttachmentRequest.php

@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
namespace App\Request;
use Hyperf\Validation\Request\FormRequest;
class AttachmentRequest 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 [
'upload' => 'required|nonempty|file|ext_not_in',
'type' => 'nonempty|alpha'
];
}
public function messages(): array
{
return [
'upload.required' => '未选择上传的文件',
'upload.nonempty' => '文件异常',
'upload.file' => '文件上传不成功',
'upload.ext_not_in' => '文件不允许上传',
'type.nonempty' => '文件类型参数异常',
];
}
public function attributes(): array
{
return [
'upload' => '文件'
];
}
}

26
app/Request/BaseFormRequest.php

@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace App\Request;
use Hyperf\Validation\Request\FormRequest;
use Psr\Http\Message\ResponseInterface;
class BaseFormRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
//复写返回状态,200
// public function response(): ResponseInterface
// {
// /** @var ResponseInterface $response */
// $response = Context::get(ResponseInterface::class);
// return $response->withStatus(200);
// }
}

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' => '返还类型优惠券',
];
}
}

46
app/Request/ImageBase64Request.php

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace App\Request;
use Hyperf\Validation\Request\FormRequest;
class ImageBase64Request 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 [
'upload' => 'required|nonempty|base64:image',
'type' => 'nonempty|alpha'
];
}
public function messages(): array
{
return [
'upload.required' => '未选择上传的文件',
'upload.base64' => '文件不是正常的图片',
'upload.nonempty' => '文件异常',
'type.nonempty' => '图片类型参数异常',
];
}
public function attributes(): array
{
return [
'upload' => '图片'
];
}
}

46
app/Request/ImageRequest.php

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace App\Request;
use Hyperf\Validation\Request\FormRequest;
class ImageRequest 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 [
'upload' => 'required|nonempty|file|image',
'type' => 'nonempty|alpha'
];
}
public function messages(): array
{
return [
'upload.required' => '未选择上传的文件',
'upload.image' => '文件不是正常的图片',
'upload.nonempty' => '文件异常',
'type.nonempty' => '图片类型参数异常',
];
}
public function attributes(): array
{
return [
'upload' => '图片'
];
}
}

42
app/Request/OrderOfflineRequest.php

@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace App\Request;
class OrderOfflineRequest extends BaseFormRequest
{
/**
* 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 [
'store_id' => 'required|nonempty|integer',
'user_id' => 'required|nonempty|integer',
'money' => 'required|nonempty',
];
}
public function messages(): array
{
return [
'*.*' => ':attribute 参数异常'
];
}
public function attributes(): array
{
return [
];
}
}

70
app/Request/OrderOnlineRequest.php

@ -0,0 +1,70 @@
<?php
declare(strict_types=1);
namespace App\Request;
class OrderOnlineRequest extends BaseFormRequest
{
/**
* 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 [
'order_num' => 'nonempty',
'delivery_no' => '',
'dada_fee' => 'nonempty',
'market_id' => 'required|nonempty|integer',
'user_id' => 'required|nonempty|integer',
'money' => 'required|nonempty',
'box_money' => '',
'ps_money' => '',
'mj_money' => '',
'xyh_money' => '',
'yhq_money' => '',
'yhq_money2' => '',
'zk_money' => '',
'tel' => 'required|nonempty',
'name' => 'required|nonempty',
'address' => 'required|nonempty',
'area' => '',
'lat' => 'required|nonempty',
'lng' => 'required|nonempty',
'note' => '',
'type' => 'required|nonempty',
'form_id' => '',
'form_id2' => '',
'delivery_time' => '',
'order_type' => 'nonempty',
'pay_type' => 'nonempty',
'coupon_id' => '',
'coupon_id2' => '',
'uniacid' => 'nonempty',
'store_list' => 'nonempty',
'receive_coupon_ids' => '',
];
}
public function messages(): array
{
return [
'*.*' => ':attribute 参数异常'
];
}
public function attributes(): array
{
return [
];
}
}

45
app/Request/UserUnionidRequest.php

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace App\Request;
use Hyperf\Validation\Request\FormRequest;
class UserUnionidRequest 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 [
'openid' => 'required|nonempty',
'unionid' => 'required|nonempty',
];
}
public function messages(): array
{
return [
'openid.*' => ':attribute必须',
'unionid.*' => ':attribute必须',
];
}
public function attributes(): array
{
return [
'openid' => '用户openid',
'unionid' => '用户unionid',
];
}
}

38
app/Request/WxminiPayRequest.php

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace App\Request;
use App\Request\BaseFormRequest;
class WxminiPayRequest extends BaseFormRequest
{
/**
* Get the validation rules that apply to the request.
*/
public function rules(): array
{
return [
'order_id' => 'required|nonempty|integer',
'openid' => 'required|nonempty',
'money' => 'required|nonempty',
];
}
public function messages(): array
{
return [
'*.*' => ':attribute 参数异常',
];
}
public function attributes(): array
{
return [
'order_id' => '订单',
'money' => '订单金额',
'openid' => '用户标识',
];
}
}

22
app/Service/AdService.php

@ -0,0 +1,22 @@
<?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
])
->orderBy('orderby', 'desc')
->get();
}
}

11
app/Service/AdServiceInterface.php

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

73
app/Service/AttachmentService.php

@ -0,0 +1,73 @@
<?php
namespace App\Service;
use App\Constants\ErrorCode;
use League\Flysystem\FilesystemNotFoundException;
class AttachmentService implements AttachmentServiceInterface
{
/**
* @inheritDoc
*/
public function formUpload($file, $path, $filesystem, $attachmenttype = 'image')
{
$fileRealPath = $file->getRealPath();
$fileHash = md5_file($fileRealPath);
$path = $this->getBasePath($path, $attachmenttype);
$fileName = $path . '/' . $fileHash . '.' . $file->getExtension();
$stream = fopen($fileRealPath, 'r+');
$filesystem->writeStream($fileName, $stream);
fclose($stream);
return $fileName;
}
/**
* @inheritDoc
*/
public function base64Upload($contents, $path, $filesystem)
{
preg_match('/^(data:\s*image\/(\w+);base64,)/', $contents, $result);
if (empty($result)) {
throw new FilesystemNotFoundException(ErrorCode::getMessage(ErrorCode::UPLOAD_INVALID),ErrorCode::UPLOAD_INVALID);
}
$contents = base64_decode(str_replace($result[1], '', $contents));
$fileHash = md5($contents);
$path = $this->getBasePath($path);
$fileName = $path . '/' . $fileHash . '.' . $result[2];
$filesystem->write($fileName, $contents);
return $fileName;
}
protected function getBasePath($path, $attachmenttype = 'image')
{
switch ($attachmenttype) {
case 'image':
$baseDir = env('IMAGE_BASE', '/attachment/images');
break;
case 'file':
$baseDir = env('FILES_BASE', '/attachment/files');
break;
default:
$baseDir = env('FILES_BASE', '/attachment');
break;
}
$path = $path ? '/'.$path : '';
$path .= '/'.date('Y').'/'.date('m').'/'.date('d');
return $baseDir.$path;
}
}

23
app/Service/AttachmentServiceInterface.php

@ -0,0 +1,23 @@
<?php
namespace App\Service;
interface AttachmentServiceInterface
{
/**
* 表单上传,单文件
* @param $file
* @param $path
* @param $filesystem
* @param string $attachmenttype
*/
public function formUpload($file, $path, $filesystem, $attachmenttype = 'image');
/**
* base64code上传,单文件
* @param $contents
* @param $path
* @param $filesystem
*/
public function base64Upload($contents, $path, $filesystem);
}

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'
);
}
}

531
app/Service/CouponRebateService.php

@ -0,0 +1,531 @@
<?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 = ApplicationContext::getContainer()->get(SSDBTask::class);
$activity = $ssdb->exec('hget', SsdbKeysPrefix::COUPON_REBATE_ACTIVITY ,'activity');
// ssdb 键值
$ssdbKey = 'activity_'.$activity.'_user_'.$user_id;
// 判断是否已全部领取过
$userReceive = $ssdb->exec('hget', SsdbKeysPrefix::COUPON_REBATE_RECEIVE,$ssdbKey);
if($userReceive === false || is_null($userReceive)){
return false;
}else{
return $userReceive;
}
}
/*
*获取活动信息
*/
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 ($coupon && ($coupon->user_id != $coupon->send_user_id)) {
//是否已返过券
$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){
//如果已有该优惠券 则领取数量 和 可用数量 自增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'])
->increment('inventory_use');
//添加领取记录到ssdb
$data = [
$order_id,$coupon->user_id,
];
$ssdb->execWithoutTask('multi_hset', SsdbKeysPrefix::COUPON_REBATE_LIST.$coupon->send_user_id, $data);
// 提交
Db::commit();
} catch (\Exception $e) {
//写入日志文件
$log_Data = array();
$log_Data['name'] = '返券';
$log_Data['order_id'] = $order_id;
$log_Data['msg'] = '返券失败';
$this->log->event(
LogLabel::COUPON_LOG,
$log_Data
);
// 回滚
Db::rollBack();
}
}
return true;
}
/*
* 支付成功 返券
*/
public function couponRebateInTask($order_id)
{
//获取SSDB上的活动信息
$ssdb = ApplicationContext::getContainer()->get(SSDBTask::class);
$active = $ssdb->exec('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 ($coupon && ($coupon->user_id != $coupon->send_user_id)) {
//是否已返过券
$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){
//如果已有该优惠券 则领取数量 和 可用数量 自增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'])
->increment('inventory_use');
//添加领取记录到ssdb
$data = [
$order_id,$coupon->user_id,
];
$ssdb->exec('multi_hset', SsdbKeysPrefix::COUPON_REBATE_LIST.$coupon->send_user_id, $data);
// 提交
Db::commit();
} catch (\Exception $e) {
//写入日志文件
$log_Data = array();
$log_Data['name'] = '返券';
$log_Data['order_id'] = $order_id;
$log_Data['msg'] = '返券失败';
$this->log->event(
LogLabel::COUPON_LOG,
$log_Data
);
// 回滚
Db::rollBack();
}
}
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 ;
}
}
}
}

24
app/Service/CouponRebateServiceInterface.php

@ -0,0 +1,24 @@
<?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 couponRebateInTask($order_id);
public function clearSsdbCouponReceiveByName($activity, $userId, $get = 0, $isAll = 0);
}

223
app/Service/CouponService.php

@ -0,0 +1,223 @@
<?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;
use Hyperf\Redis\Redis;
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_share.png',
'receive_bg' => env('OSS_IMG_HOST').'/static/img/coupon_bg.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()
{
}
/**
* @inheritDoc
*/
public function getOrderCanUseCoupons($orderAmount, $marketId, $userId, $fields=[], $type = 1, $storeTypeIds = [0])
{
// 用户今日使用过的优惠券
$redis = ApplicationContext::getContainer()->get(Redis::class);
$couponTodayUsedIds = $redis->sMembers('coupon_'.date('Ymd').'_used_'.$userId);
$currentTime = time();
$builder = Db::table('ims_system_coupon_user_receive as receive')
->join('ims_system_coupon_user as coupon', 'coupon.id', '=', 'receive.system_coupon_user_id', 'inner');
if (is_array($fields)&&!empty($fields)) {
$builder->select($fields);
}
if (is_array($couponTodayUsedIds)&&!empty($couponTodayUsedIds)) {
$builder->whereNotIn('coupon.id', $couponTodayUsedIds);
}
return $builder->where(['receive.user_id' => $userId])
->whereIn('receive.status', [0,1])
->where('receive.number_remain', '>', 0)
->whereIn('coupon.type', [1,$type])
->where('coupon.full_amount', '<=', $orderAmount)
->where('coupon.usable_start_time', '<=', $currentTime)
->where('coupon.usable_end_time', '>=', $currentTime)
->where('coupon.usable_number', '<=', Db::raw('receive.number_remain'))
->where('coupon.market_id', 'in', [0, $marketId])
->whereIn('coupon.storetype_id', $storeTypeIds)
->orderByRaw('coupon.discounts DESC, coupon.full_amount DESC')
->get()
->toArray();
}
/**
* 缓存优惠券今日使用情况
* @param $userId
* @param $couponId
* @param $couponRecId
* @return bool
*/
function cacheTodayCouponUsed($userId, $couponId, $couponRecId)
{
$redis = ApplicationContext::getContainer()->get(Redis::class);
$setRes = $redis->sAdd(
'coupon_'.date('Ymd').'_used_'.$userId,
$couponId
);
$expireRes = $redis->expire(
'coupon_'.date('Ymd').'_used_'.$userId,
strtotime(date('Y-m-d').' 23:59:59')-time()
);
return $setRes&&$expireRes;
}
}

30
app/Service/CouponServiceInterface.php

@ -0,0 +1,30 @@
<?php
namespace App\Service;
interface CouponServiceInterface
{
public function getSystemCouponUserList($userId,$receiveType);
public function userCouponAccount();
public function userReceiveCoupon();
public function getUserReceiveCouponList();
public function getUserAvailableCoupons();
/**
* 当前订单可用优惠券列表
* @param $orderAmount 订单金额
* @param $marketId 市场ID
* @param $userId 用户ID
* @param int $type 优惠券类型,1全平台 2线上 3线下
* @param int[] $storeTypeIds 商户类型ID数组
* @param array $fields
* @return mixed
*/
public function getOrderCanUseCoupons($orderAmount, $marketId, $userId, $fields=[], $type=1, $storeTypeIds=[0]);
}

135
app/Service/DeviceServiceImp.php

@ -0,0 +1,135 @@
<?php
namespace App\Service;
use App\Commons\Log;
use App\Constants\LogLabel;
use App\Model\Order;
use App\Model\SpeakerDevic;
use App\Model\Store;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Utils\ApplicationContext;
use App\TaskWorker\AliIotTask;
class DeviceServiceImp implements DeviceServiceInterface
{
/**
* @Inject
* @var Log
*/
protected $log;
/**
* @Inject
* @var IOTServiceInterface
*/
protected $IOTService;
/**
* 获取绑定列表
* @param $store_id
* @return \Hyperf\Database\Model\Builder[]|\Hyperf\Database\Model\Collection
*/
public function getListByStoreId($store_id)
{
return SpeakerDevic::query()->where(['store_id' => $store_id, 'is_bind' => SpeakerDevic::IS_BIND_YES])->get()->toArray();
}
/**
* 绑定
* @param $dev_name
* @param $store_id
* @return SpeakerDevic|null
* @throws \Throwable
*/
public function bindByStoreId($dev_name, $store_id)
{
$sd = null;
if ($this->checkDeviceEnable($dev_name)) {
return $sd;
}
try {
// 获取市场ID
$market_id = Store::query()->where(['id' => $store_id])->value('market_id');
$sd = SpeakerDevic::query()->updateOrCreate(
['store_id' => $store_id, 'device_name' => $dev_name],
['market_id' => $market_id, 'bind_time' => time(), 'is_bind' => SpeakerDevic::IS_BIND_YES]
);
} catch (Exception $e) {
$this->log->event(LogLabel::DEVICE_LOG, ['msg' => '绑定设备异常:'.$e->getMessage()]);
}
return $sd;
}
/**
* 解绑
* @param $bind_id
* @return int
*/
public function unbindById($bind_id)
{
return SpeakerDevic::query()->where(['id' => $bind_id])->update(['is_bind' => SpeakerDevic::IS_BIND_NO]);
}
/**
* 发布语音消息
* @param $dev_names
* @param $msg
* @return bool
*/
public function pubMsgToStoreByDevName($dev_names, $msg)
{
foreach ($dev_names as $key => $dev_name) {
$this->IOTService->pub($dev_name['device_name'], $msg);
}
return true;
}
public function pubMsgToStoreByOrderMainId($order_id, $is_main = true)
{
// 获取订单
$orders = Order::query()->select(['id','order_num','money', 'pay_type', 'store_id', 'type']);
if ($is_main) {
$orders = $orders->where(['order_main_id' => $order_id])->get()->toArray();
} else {
$orders = $orders->where(['id' => $order_id])->get()->toArray();
}
if(empty($orders)) return;
// 循环发送
foreach ($orders as $k => &$order) {
$device_names = SpeakerDevic::query()
->select(['device_name'])
->where(['store_id' => $order['store_id'], 'is_bind' => SpeakerDevic::IS_BIND_YES])
->get()
->toArray();
$msg = $order['type']==1 ? "{\"msg\":\"您有新的懒族外卖订单\"}" : "{\"msg\":\"微信到账".$order['money']."\"}";
foreach ($device_names as $key => $dev_name) {
$this->IOTService->pub($dev_name['device_name'], $msg);
}
}
return true;
}
/**
* 当前设备是否已经被绑定
* @param $dev_name
* @return bool
*/
protected function checkDeviceEnable($dev_name)
{
return SpeakerDevic::query()->where(['device_name' => $dev_name, 'is_bind' => SpeakerDevic::IS_BIND_YES])->exists();
}
}

12
app/Service/DeviceServiceInterface.php

@ -0,0 +1,12 @@
<?php
namespace App\Service;
interface DeviceServiceInterface
{
public function getListByStoreId($store_id);
public function bindByStoreId($dev_name,$store_id);
public function unbindById($bind_id);
public function pubMsgToStoreByDevName($dev_names,$msg);
public function pubMsgToStoreByOrderMainId($order_id, $is_main = true);
}

232
app/Service/FeiePrintService.php

@ -0,0 +1,232 @@
<?php
namespace App\Service;
use App\Libs\FeiePrintClient;
use App\Model\OrderMain;
use Hyperf\DbConnection\Db;
use Hyperf\Utils\ApplicationContext;
class FeiePrintService implements FeiePrintServiceInterface
{
// *必填*:飞鹅云后台注册账号
const USER = '13161443713@163.com';
// *必填*: 飞鹅云后台注册账号后生成的UKEY 【备注:这不是填打印机的KEY】
const UKEY = 'XsaHzgePdyWTfcMX';
// *必填*:打印机编号,必须要在管理后台里添加打印机或调用API接口添加之后,才能调用API
const SN = '550510805';
// 以下参数不需要修改
// 接口IP或域名
const IP = 'api.feieyun.cn';
// 接口IP端口
const PORT = 80;
// 接口路径
const PATH = '/Api/Open/';
public function feiePrint($order_num)
{
// TODO 对象数组=》二维数组
$data = Db::table('ims_cjdc_order_main as m')
->join('ims_cjdc_order as o','o.order_main_id', '=', 'm.id','inner')
->join('ims_cjdc_order_goods as g','o.id','=', 'g.order_id','inner')
->join('ims_cjdc_feprint as f','m.market_id','=', 'f.market_id','inner')
->join('ims_cjdc_store as s','s.id','=', 'o.store_id','inner')
->where('m.global_order_id', $order_num)
->selectRaw("o.note as o_note,g.name,g.number,g.money,g.good_unit,m.delivery_time as ps_time,m.address,m.note,m.name as user_name,m.dada_fee,m.money as m_money,m.yhq_money2,m.box_money,f.sn,m.tel,m.order_num,g.id,g.spec,s.name as shopname")
->orderBy('s.id')
->get()
->toArray();
foreach ($data as $key => &$item) {
$item = (array)$item;
}
$content = $this->printFormat($data, 14, 6, 3, 6);
$res = $this->printMsg($data[0]['sn'], $content, 1);
return ($res);
}
/**
* [打印订单接口 Open_printMsg]
* @param [string] $sn [打印机编号sn]
* @param [string] $content [打印内容]
* @param [string] $times [打印联数]
* @return [string] [接口返回值]
*/
protected function printMsg($sn, $content, $times = 1)
{
$time = time(); //请求时间
$msgInfo = array(
'user' => self::USER,
'stime' => $time,
'sig' => sha1(self::USER . self::UKEY . $time),
'apiname' => 'Open_printMsg',
'sn' => $sn,
'content' => $content,
'times' => $times//打印次数
);
$client = new FeiePrintClient(self::IP, self::PORT);
if (!$client->post(self::PATH, $msgInfo)) {
echo 'error';
} else {
// 服务器返回的JSON字符串,建议要当做日志记录起来
$result = $client->getContent();
return $result;
}
}
protected function printFormat($arr, $A, $B, $C, $D)
{
$orderInfo = '<CB>懒族生活</CB><BR>';
$orderInfo .= '名称 单价 数量 金额<BR>';
$orderInfo .= '--------------------------------<BR>';
$shopname = "";
$shopnum = 0;
foreach ($arr as $k5 => $v5) {
if ($shopname != $v5['shopname']) {
if ($shopname != "") {
$orderInfo .= ' <BR>';
}
$shopnum++;
$orderInfo .= "<C>(" . $shopnum . ")" .$v5['shopname'] . '</C><BR>';
$shopname = $v5['shopname'];
}
$name = $v5['name'];
if(!empty($v5['spec'])) {
$name .= "(规格:". $v5['spec'].")";
}elseif (!empty($v5['good_unit'])){
$name .= "(规格:". $v5['good_unit'].")";
}
$price = $v5['money'];
$num = $v5['number'];
$prices = sprintf("%.2f",$v5['money']*$v5['number']);
$kw3 = '';
$kw1 = '';
$kw2 = '';
$kw4 = '';
$str = $name;
$blankNum = $A;//名称控制为14个字节
$lan = mb_strlen($str,'utf-8');
$m = 0;
$j=1;
$blankNum++;
$result = array();
if(strlen($price) < $B){
$k1 = $B - strlen($price);
for($q=0;$q<$k1;$q++){
$kw1 .= ' ';
}
$price = $kw1.$price;
}
if(strlen($num) < $C){
$k2 = $C - strlen($num);
for($q=0;$q<$k2;$q++){
$kw2 .= ' ';
}
$num = $kw2.$num;
}
if(strlen($prices) < $D){
$k3 = $D - strlen($prices);
for($q=0;$q<$k3;$q++){
$kw4 .= ' ';
}
$prices = $kw4.$prices;
}
for ($i=0;$i<$lan;$i++){
$new = mb_substr($str,$m,$j,'utf-8');
$j++;
if(mb_strwidth($new,'utf-8')<$blankNum) {
if($m+$j>$lan) {
$m = $m+$j;
$tail = $new;
// $lenght = iconv("UTF-8", "GBK//IGNORE", $new);
$k = $A - mb_strwidth($new,'utf-8');
for($q=0;$q<$k;$q++){
$kw3 .= ' ';
}
if($m==$j){
$tail .= $kw3.' '.$price.' '.$num.' '.$prices;
}else{
$tail .= $kw3.'<BR>';
}
break;
}else{
$next_new = mb_substr($str,$m,$j,'utf-8');
if(mb_strwidth($next_new,'utf-8')<$blankNum) continue;
else{
$m = $i+1;
$result[] = $new;
$j=1;
}
}
}
}
$head = '';
foreach ($result as $key=>$value) {
if($key < 1){
// $v_lenght = iconv("UTF-8", "GBK//IGNORE", $value);
$v_lenght = mb_strwidth($value,'utf-8');
if($v_lenght == 13) $value = $value." ";
$head .= $value.' '.$price.' '.$num.' '.$prices;
}else{
$head .= $value.'<BR>';
}
}
$orderInfo .= $head.$tail;
if(!empty($v5['o_note'])){
$orderInfo .= '备注:'.$v5['o_note'].'<BR>';
}
}
// $time = date('Y-m-d H:i:s', time());
$orderInfo .= '--------------------------------<BR>';
if ($arr[0]['box_money'] > 0) {
$kw5 = '';
$len = 24 - strlen($arr[0]['box_money']);
for ($q = 0; $q < $len; $q++) {
$kw5 .= ' ';
}
$orderInfo .= '包装费:' . $kw5 . $arr[0]['box_money'] . '<BR>';
}
if($arr[0]['dada_fee'] > 0){
$kw5 = '';
$len = 24 - strlen($arr[0]['dada_fee']);
for ($q = 0; $q < $len; $q++) {
$kw5 .= ' ';
}
$orderInfo .= '配送费:'.$kw5.$arr[0]['dada_fee'].'<BR>';
}
if($arr[0]['yhq_money2'] > 0){
$yhq_money2 = sprintf("%.2f",$arr[0]['yhq_money2']);
$kw6 = '';
$len = 25 - strlen($yhq_money2);
for ($q = 0; $q < $len; $q++) {
$kw6 .= ' ';
}
$orderInfo .= '红包:'.$kw6.'-'.$yhq_money2.'<BR>';
}
$total = '合计:'.$arr[0]['m_money'];
$user_name = $arr[0]['user_name'];
if(strlen($user_name)>18){
$user_name=substr($user_name,0,18).'...';
}
$str = $user_name . $total;
$kw5 = '';
// $lenght = iconv("UTF-8", "GBK//IGNORE", $str);
$total_len = 32 - mb_strwidth($str,'utf-8');
for ($q = 0; $q < $total_len; $q++) {
$kw5 .= ' ';
}
$total_str = $user_name.$kw5.$total;
$orderInfo .= $total_str.'<BR>';
$orderInfo .= '送货地点:' . $arr[0]['address'] . '<BR>';
$tel = substr_replace( $arr[0]['tel'], '****', 3, 4);
$orderInfo .= '联系电话:' . $tel . '<BR>';
$orderInfo .= '配送时间:' . $arr[0]['ps_time'] . '<BR>';
if(!empty($arr[0]['note'])){
$orderInfo .= '备注:'.$arr[0]['note'].'<BR><BR>';
}
//$orderInfo .= '<QR>http://www.feieyun.com</QR>';//把解析后的二维码生成的字符串用标签套上即可自动生成二维码
return $orderInfo;
}
}

10
app/Service/FeiePrintServiceInterface.php

@ -0,0 +1,10 @@
<?php
namespace App\Service;
interface FeiePrintServiceInterface
{
public function feiePrint($order_num);
}

54
app/Service/IOTAliService.php

@ -0,0 +1,54 @@
<?php
namespace App\Service;
use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;
use App\Commons\Log;
use App\Constants\LogLabel;
use Hyperf\Di\Annotation\Inject;
class IOTAliService implements IOTServiceInterface
{
/**
* @Inject
* @var Log
*/
protected $log;
public function pub($device_name, $msg)
{
AlibabaCloud::accessKeyClient(env('ALI_IOT_KEY'), env('ALI_IOT_SECRET'))
->regionId(env('ALI_IOT_REGION'))
->asDefaultClient();
try {
AlibabaCloud::rpc()
->product('Iot')
->version('2018-01-20')
->action('Pub')
->method('POST')
->host(env('ALI_IOT_HOST'))
->options([
'query' => [
'RegionId' => "cn-shanghai",
'TopicFullName' => "/".env('ALI_IOT_PRODUCT_KEY')."/".$device_name."/user/get",
'MessageContent' => base64_encode($msg),
'ProductKey' => env('ALI_IOT_PRODUCT_KEY'),
],
])
->request();
} catch (ClientException $e) {
$this->log->event(LogLabel::DEVICE_LOG, ['msg' => 'ClientException发布失败:'.$e->getErrorMessage()]);
return false;
} catch (ServerException $e) {
$this->log->event(LogLabel::DEVICE_LOG, ['msg' => 'ServerException发布失败:'.$e->getErrorMessage()]);
return false;
}
return true;
}
}

8
app/Service/IOTServiceInterface.php

@ -0,0 +1,8 @@
<?php
namespace App\Service;
interface IOTServiceInterface
{
public function pub($device_name, $msg);
}

209
app/Service/MiniprogramService.php

@ -0,0 +1,209 @@
<?php
namespace App\Service;
use App\Model\Order;
use App\Model\OrderGoods;
use App\Model\OrderMain;
use App\Model\Store;
use App\Model\Users;
use EasyWeChat\Factory;
use Hyperf\Guzzle\CoroutineHandler;
class MiniprogramService implements MiniprogramServiceInterface
{
/**
* @inheritDoc
*/
public function sendTemMsgForOnlineOrder($order_main_id)
{
// 查询订单信息
$order = OrderMain::find($order_main_id);
$payTypes = ['1' => '微信支付', '2' => '余额支付', '3' => '积分支付', '4' => '货到付款'];
$address_store = $order['address'] . ';' .$order['name']. ';'. substr_replace($order['tel'],'****',3,4);
$address = $order['address'] . ';' .$order['name']. ';'. $order['tel'];
// 查询子订单,用于发消息给商户
$order_children = Order::query()->select(['id', 'order_num', 'store_id', 'money', 'time'])
->where(['order_main_id' => $order_main_id])
->get()
->toArray();
$goods_temp_all = [];
foreach ($order_children as $key => &$item) {
// 订单商品
$order_goods = OrderGoods::query()->select(['name', 'number', 'spec', 'good_unit'])
->where(['order_id' => $item['id']])
->get()
->toArray();
$goods_temp = [];
foreach ($order_goods as $k => &$goods) {
array_push($goods_temp, $goods['name']."*".$goods['number']."/".($goods['spec']?:$goods['good_unit']));
array_push($goods_temp_all, $goods['name']."*".$goods['number']."/".($goods['spec']?:$goods['good_unit']));
}
// 商户/门店的openid
$store = Store::query()->select(['id', 'name', 'user_id'])
->where(['id' => $item['store_id']])
->first()->toArray();
$store['openid'] = Users::query()
->where(['id' => $store['user_id']])
->value('openid');
// 模板数据
$data_store = [
'first' => ['您有新的外卖订单!订单编号:'.$item['order_num'], '#ff0000'],
'keyword' => [
["您的外卖订单详情:\r\n".implode(";\r\n",$goods_temp), '#ff0000'],
$item['money'],
$payTypes[$order['pay_type']],
$item['time']?:'',
$address_store,
],
'remark' => [$order['note'], '#4e6ef2']
];
$ret_store = $this->sendTempMsg($store['openid'], '-M7DG_ACwJxqdAvyvJuAnPpx4xaLf3VkkN0fckno71c',$data_store);
}
// 模板数据发送消息给用户
$data_user = [
'first' => '您好,下单成功!订单编号:'.$order['order_num'],
'keyword' => [
implode(";\r\n", $goods_temp_all),
$order['money'],
$payTypes[$order['pay_type']],
date('Y-m-d H:i:s', $order['time_add']),
$address,
],
'remark' => '感谢您的光临,欢迎下次再来!'
];
// 获取用户openid,发送给用户
$user_openid = Users::query()->where(['id' => $order['user_id']])->value('openid');
$ret_user = $this->sendTempMsg($user_openid,'-M7DG_ACwJxqdAvyvJuAnPpx4xaLf3VkkN0fckno71c', $data_user);
}
/**
* @inheritDoc
*/
public function sendTemMsgForOfflineOrder($order_main_id)
{
// 查询子订单,用于发消息给商户
$order_children = Order::query()->select(['id', 'order_num', 'store_id', 'money', 'time'])
->where(['order_main_id' => $order_main_id])
->get()
->toArray();
foreach ($order_children as $key => &$item) {
// 商户/门店的openid
$store = Store::query()->select(['id', 'name', 'user_id'])
->where(['id' => $item['store_id']])
->first()->toArray();
$store['openid'] = Users::query()
->where(['id' => $store['user_id']])
->value('openid');
// 模板数据
$data_store = [
'first' => '您有新订单收入!订单编号:'.$item['order_num'],
'keyword' => [
$store['name']?:'',
$item['time']?:'',
'暂无',
$item['money']
],
'remark' => '感谢您的使用!'
];
$ret_store = $this->sendTempMsg($store['openid'], 'lxVbC6PVpKbiO44bYqLmacl-BaME70D47Q0jn2Link0',$data_store);
}
}
/**
* @inheritDoc
*/
public function sendTemMsgForAward($money, $note, $openid, $time)
{
// 模板数据发送消息给用户
$data_user = [
'first' => '恭喜!您有一笔新的奖励收入!',
'keyword' => [
$money,
$note,
$time
],
'remark' => '感谢您的使用!'
];
// 获取用户openid,发送给用户
$ret_user = $this->sendTempMsg($openid,'ypZ7xdHUjWrRG8P-MD42dhpp6kUlh4Unoh7eTSrLZEg', $data_user);
}
/**
* @inheritDoc
*/
public function sendTempMsg($openid, $template_id, $data, $redirect_url = '', $applet_config = ['appid' => '', 'pagepath' => ''])
{
// 先拼个基础的
$template = [
'touser' => $openid,
'mp_template_msg' => [
'appid' => env('OFFICIAL_APP_ID'),
'template_id' => $template_id,
'url' => $redirect_url,
]
];
// 看看有没有小程序跳转的要求
$template['mp_template_msg']['miniprogram'] = $applet_config;
// 重点来了,拼接关键数据data
if (!is_array($data)) { # 数组都不是,请回去
return false;
}
if (is_array($data['first'])) {
$template['mp_template_msg']['data']['first']['value'] = $data['first'][0] ?? '';
$template['mp_template_msg']['data']['first']['color'] = $data['first'][1] ?? '';
} else {
$template['mp_template_msg']['data']['first']['value'] = $data['first'];
}
if (isset($data['keyword'])&&is_array($data['keyword'])) {
foreach ($data['keyword'] as $key => &$keyword) {
$index = $key+1;
if (is_array($keyword)) {
$template['mp_template_msg']['data']['keyword'.$index]['value'] = $keyword[0] ?? '';
$template['mp_template_msg']['data']['keyword'.$index]['color'] = $keyword[1] ?? '';
} else {
$template['mp_template_msg']['data']['keyword'.$index]['value'] = $keyword;
}
}
}
if (is_array($data['remark'])) {
$template['mp_template_msg']['data']['remark']['value'] = $data['remark'][0] ?? '';
$template['mp_template_msg']['data']['remark']['color'] = $data['remark'][1] ?? '';
} else {
$template['mp_template_msg']['data']['remark']['value'] = $data['remark'];
}
$app = Factory::miniProgram(config('wxtempmsg'));
$app['guzzle_handler'] = CoroutineHandler::class;
$app->uniform_message->send($template);
}
}

41
app/Service/MiniprogramServiceInterface.php

@ -0,0 +1,41 @@
<?php
namespace App\Service;
interface MiniprogramServiceInterface
{
/**
* 外卖线上订单模板消息
* @param $order_main_id
* @return mixed
*/
public function sendTemMsgForOnlineOrder($order_main_id);
/**
* 当面线下订单模板消息
* @param $order_main_id
* @return mixed
*/
public function sendTemMsgForOfflineOrder($order_main_id);
/**
* 奖励模板消息
* @param $money
* @param $note
* @param $openid
* @param $time
* @return mixed
*/
public function sendTemMsgForAward($money, $note, $openid, $time);
/**
* 发送模板消息
* @param $openid
* @param $template_id
* @param $data
* @param string $redirect_url
* @param string[] $applet_config
* @return mixed
*/
public function sendTempMsg($openid, $template_id, $data, $redirect_url = '', $applet_config = ['appid' => '', 'pagepath' => '']);
}

29
app/Service/MqttServiceInterface.php

@ -0,0 +1,29 @@
<?php
namespace App\Service;
interface MqttServiceInterface
{
/**
* 发布给商户
* @return mixed
*/
public function speakToStore($orderId, $isMain = true);
/**
* @param string|number $message 消息内容
* @param string $topic 发布消息到主题,主题名
* @param string $type 消息类型,cash或tts
* @param string $payId 支付方式,如“支付宝”、“微信”等
* @param string $toClientId 终端id,如IMEI码
* @param string $curClientId 当前客户端id
*/
public function publish(
$message,
$topic,
$toClientId = '',
$type = '',
$payId = '',
$curClientId = ''
);
}

81
app/Service/MqttSpeakerService.php

@ -0,0 +1,81 @@
<?php
namespace App\Service;
use App\Libs\MQTTClient;
use App\Model\Order;
use App\Model\Store;
use Hyperf\Utils\ApplicationContext;
class MqttSpeakerService implements MqttServiceInterface
{
const TOPIC = 'test01';
/**
* @inheritDoc
*/
public function speakToStore($orderId, $isMain = true)
{
// 获取订单
$orders = Order::query()->select(['id','order_num','money', 'pay_type', 'store_id', 'type']);
if ($isMain) {
$orders = $orders->where(['order_main_id' => $orderId])->get()->toArray();
} else {
$orders = $orders->where(['id' => $orderId])->get()->toArray();
}
if(empty($orders)) return;
// 循环发送
foreach ($orders as $k => &$order) {
$order['template'] = $order['type']==1 ? "您有新的懒族外卖订单" : "微信到账".floatval($order['money'])."";
// 获取终端ID
$order['to_client_id'] = Store::query()->where(['id' => $order['store_id']])->value('loudspeaker_imei');
// 发布订阅消息
$res = $this->publish($order['template'], self::TOPIC, $order['to_client_id']);
}
}
/**
* @inheritDoc
*/
public function publish(
$message,
$topic,
$toClientId = '',
$type = '',
$payId = '',
$curClientId = ''
) {
$client = new MQTTClient(env('MQTT_HOST'), env('MQTT_PORT'));
$client->setAuthentication(env('MQTT_NAME'), env('MQTT_PASS'));
$client->setDebug(true);
if (env('MQTT_CERT')) {
$client->setEncryption(env('MQTT_CERT'));
}
$msgArr = [];
if ( (empty($type)&&is_numeric($message)) || 'cash' === $type ) {
$msgArr['cash'] = $message;
$payId AND $msgArr['payid'] = $payId;
} else {
$msgArr['message'] = $message;
}
if (!empty($toClientId)) {
$topic .= '/'.$toClientId;
}
$curClientId OR $curClientId = (string)rand(1,999999999);
$success = $client->sendConnect($curClientId);
if ($success) {
$client->sendPublish($topic, json_encode($msgArr), MQTTClient::MQTT_QOS2);
$client->sendDisconnect();
}
$client->close();
}
}

536
app/Service/OrderService.php

@ -0,0 +1,536 @@
<?php
namespace App\Service;
use App\Commons\Log;
use App\Constants\LogLabel;
use App\Model\Coupon;
use App\Model\CouponUserRec;
use App\Model\CouponUserUse;
use App\Model\Goods;
use App\Model\Order;
use App\Model\OrderGoods;
use App\Model\OrderMain;
use App\Model\SpecCombination;
use App\Model\Users;
use Exception;
use Hyperf\DbConnection\Db;
use Hyperf\Snowflake\IdGeneratorInterface;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Di\Annotation\Inject;
class OrderService implements OrderServiceInterface
{
/**
* @Inject
* @var Log
*/
protected $log;
/**
* @Inject
* @var CouponServiceInterface
*/
protected $couponService;
/**
* @inheritDoc
*/
public function addOnlineOrder($data)
{
bcscale(6);
// 订单判重
$dataMain = $data;
if ($orderMainId = $this->existsByOrderNum($data['order_num'])) {
return $orderMainId;
}
Db::beginTransaction();
try {
// 计算当前订单可用红包优惠金额
$couponMoney = 0;
$receiveCouponIds = [];
if (isset($data['receive_coupon_ids'])&&$data['receive_coupon_ids']) {
$receiveCouponIds = explode(',', str_replace(',',',',$data['receive_coupon_ids']));
$couponMoney = $this->getCouponAmount($receiveCouponIds, $data['money'], $data['user_id'], $data['market_id']);
}
$dataMain['yhq_money2'] = $couponMoney;
// 获取分布式全局ID
$generator = ApplicationContext::getContainer()->get(IdGeneratorInterface::class);
$dataMain['global_order_id'] = $generator->generate();
// 店铺IDs
$dataMain['store_ids'] = '';
$storeList = json_decode(html_entity_decode($data['store_list']), true);
if (!is_array($storeList)||empty($storeList)) {
Db::rollBack();
return '订单中商品不存在或已失效';
}
// 获取商户IDs
foreach ($storeList as &$item) {
$dataMain['store_ids'] .= empty($dataMain['store_ids']) ? $item['store_id'] : ','.$item['store_id'];
}
// 主订单插入数据
$currentTime = time();
$dataMain['time'] = date('Y-m-d H:i:s', $currentTime);
$dataMain['time_add'] = $currentTime;
$dataMain['pay_time'] = '';
$dataMain['state'] = OrderMain::ORDER_STATE_UNPAY;
$dataMain['code'] = $dataMain['global_order_id'];
$dataMain['jj_note'] = '';
// 主订单模型保存
$orderMain = OrderMain::create($dataMain);
$orderMainId = $orderMain->id;
// 统计订单中所有店铺当日订单数,做店铺订单序号
$countsArr = Order::query()
->selectRaw('id, COUNT(*) AS count')
->whereIn('store_id', explode(',', $dataMain['store_ids']))
->where(['type' => OrderMain::ORDER_TYPE_ONLINE])
->whereBetween('time', [date('Y-m-d 00:00:00'), date('Y-m-d 23:59:59')])
->get()
->toArray();
$storeOrderCounts = [];
foreach ($countsArr as $key => &$row) {
$storeOrderCounts[$row['id']] = $row['count'];
}
// 循环处理订单总额、子订单总额、商品、商户订单等信息
$orderAmountTotal = 0; # 总订单金额
$orderGoods = [];
foreach ($storeList as $key => &$item) {
// 子订单数据处理
$dataChild = [
'uniacid' => $data['uniacid'],
'order_num' => 's'.date('YmdHis', time()) . rand(1111, 9999),
'user_id' => $orderMain->user_id,
'store_id' => $item['store_id'],
'order_main_id' => $orderMainId,
'state' => OrderMain::ORDER_STATE_UNPAY,
'tel' => $orderMain->tel,
'name' => $orderMain->name,
'address' => $orderMain->address,
'area' => $orderMain->area,
'time' => date("Y-m-d H:i:s"),
'note' => $item['note'] ?? '',
'delivery_time' => $orderMain->delivery_time,
'type' => $orderMain->type,
'lat' => $orderMain->lat,
'lng' => $orderMain->lng,
'pay_type' => $orderMain->pay_type,
'order_type' => $orderMain->order_type,
'money' => floatval($item['subtotal']),
'box_money' => floatval($item['box_money']),
'mj_money' => floatval($item['mj_money']),
'yhq_money' => floatval($item['yhq_money']),
'yhq_money2' => floatval($item['yhq_money2']),
'zk_money' => floatval($item['zk_money']),
'coupon_id' => $item['coupon_id'],
'coupon_id2' => $item['coupon_id2'],
'xyh_money' => floatval($item['xyh_money']),
'oid' => (isset($storeOrderCounts[$item['store_id']]) ? $item['store_id'] : 0) + 1,
'time_add' => date("Y-m-d H:i:s"),
'jj_note' => '',
'form_id' => '',
'form_id2' => '',
'code' => '',
];
$orderChildId = Order::query()->insertGetId($dataChild);
// 子订单内商品处理
$goodsAmountTotal = 0;
if (!is_array($item['good_list'])||empty($item['good_list'])) {
Db::rollBack();
return '订单商品异常';
}
foreach ($item['good_list'] as &$goods) {
$goodsAmount = bcadd(floatval($goods['money']), floatval($goods['box_money']));
$goodsAmount = bcmul($goodsAmount, $goods['num']);
$goodsAmountTotal = bcadd($goodsAmountTotal, $goodsAmount);
$orderGoods[$goods['id']] = $goods;
$orderGoods[$goods['id']]['uniacid'] = $data['uniacid'];
$orderGoods[$goods['id']]['order_id'] = $orderChildId;
$orderGoods[$goods['id']]['user_id'] = $dataMain['user_id'];
$orderGoods[$goods['id']]['store_id'] = $item['store_id'];
}
// 子订单优惠总额
$discountAmountTotal = bcadd($dataChild['mj_money'], $dataChild['yhq_money']);
$discountAmountTotal = bcadd($discountAmountTotal, $dataChild['yhq_money2']);
$discountAmountTotal = bcadd($discountAmountTotal, $dataChild['zk_money']);
$discountAmountTotal = bcadd($discountAmountTotal, $dataChild['xyh_money']);
$goodsAmountTotal = bcsub($goodsAmountTotal, $discountAmountTotal, 2);
$orderAmountTotal = bcadd($orderAmountTotal, $goodsAmountTotal, 2);
// 校验子订单金额
if ($goodsAmountTotal != $dataChild['money']) {
Db::rollBack();
return '店铺订单总金额错误';
}
}
// 校验库存
foreach ($orderGoods as $Key => &$goodsItem) {
$goodsItem['combination_id'] = intval($goodsItem['combination_id']);
// 存在规格,则去规格处查库存
$goods = [];
if ($goodsItem['combination_id'] > 0) {
$combination = SpecCombination::query()
->select(['good_id AS id', 'number AS inventory'])
->where(['id' => $goodsItem['combination_id']])
->first()
->toArray();
$goods = Goods::query()
->select(['id', 'name', 'is_max'])
->where(['id' => $combination['id']])
->first()
->toArray();
$goods['inventory'] = $combination['inventory'];
} else {
$goods = Goods::query()
->select(['id', 'name', 'is_max', 'inventory'])
->where(['id' => $goodsItem['good_id']])
->first()
->toArray();
}
if (!$goods) {
Db::rollBack();
return '缺少商品';
}
if($goodsItem['num'] > $goods['inventory'] && $goods['is_max'] != Goods::INVENTORY_NOLIMIT){
Db::rollBack();
return '商品 '.$goods->name.' 库存不足!';
}
}
// 校验总订单金额
$deliveryAmount = 0; # 配送费用
if($dataMain['order_type'] == OrderMain::ORDER_TYPE_ONLINE){
$deliveryAmount = $dataMain['dada_fee'];
}
$orderAmountTotal = bcadd($orderAmountTotal, $deliveryAmount);
# 总订单优惠总额
$discountAmountTotal = bcadd($dataMain['mj_money'], $dataMain['yhq_money']);
$discountAmountTotal = bcadd($discountAmountTotal, $dataMain['yhq_money2']);
$discountAmountTotal = bcadd($discountAmountTotal, $dataMain['zk_money']);
$discountAmountTotal = bcadd($discountAmountTotal, $dataMain['xyh_money']);
$orderAmountTotal = bcsub($orderAmountTotal, $discountAmountTotal, 2);
if ($orderAmountTotal != bcsub(bcadd($dataMain['money'], $deliveryAmount), $discountAmountTotal, 2)) {
Db::rollBack();
return '订单总金额错误';
}
// 添加订单商品
$tempGoods = $orderGoods;
$orderGoods = [];
foreach ($tempGoods as $key => &$value) {
$goodsTemp['good_id'] = $value['good_id'];
$goodsTemp['img'] = $value['logo'];
$goodsTemp['number'] = $value['num'];
$goodsTemp['order_id'] = $value['order_id'];
$goodsTemp['name'] = $value['name'];
$goodsTemp['money'] = $value['money'];
$goodsTemp['dishes_id'] = $value['dishes_id'];
$goodsTemp['spec'] = $value['spec'];
$goodsTemp['is_qg'] = $value['is_qg'];
$goodsTemp['good_unit'] = $value['good_unit'];
$goodsTemp['uniacid'] = $value['uniacid'];
$goodsTemp['combination_id'] = $value['combination_id'];
$orderGoods[] = $goodsTemp;
}
$addOrderGoods = OrderGoods::query()->insert($orderGoods);
if (!$addOrderGoods) {
Db::rollBack();
return '订单商品异常';
}
// 修改总订单金额,金额是计算来的
// TODO 这部分其实可以结合处理优化一下,循环前后关联处理太多
$updateOrderMain = OrderMain::query()->where(['id' => $orderMainId])->update(['money' => $orderAmountTotal, 'total_money' => $dataMain['money']]);
if (!$updateOrderMain) {
Db::rollBack();
return '订单总金额记录失败';
}
// 处理红包的使用
$canUseCoupons = CouponUserRec::select(['id', 'user_id', 'number', 'number_remain', 'system_coupon_user_id'])
->whereIn('id', $receiveCouponIds)
->get()->toArray();
if (is_array($canUseCoupons)&&!empty($canUseCoupons)) {
# 使用记录、更新当前优惠券
foreach ($canUseCoupons as $key => &$coupon) {
$couponUse = [
'user_id' => $coupon['user_id'],
'user_receive_id' => $coupon['id'],
'system_coupon_id' => $coupon['system_coupon_user_id'],
'order_main_id' => $orderMainId,
'use_time' => $currentTime,
'return_time' => 0,
'number' => 1,
'status' => 1,
'update_time' => 0,
];
var_dump('$couponUse',$couponUse);
$insertRes = CouponUserUse::query()->insert($couponUse);
if ($insertRes) {
$numberRemain = $coupon['number_remain'] - 1;
if ($numberRemain == 0) {
$status = 2;
} elseif ($numberRemain > 0 && $numberRemain < $coupon['number']) {
$status = 1;
} elseif ($numberRemain == $coupon['number']) {
$status = 0;
}
$upRes = CouponUserRec::query()->where(['id' => $coupon['id']])->update(['number_remain' => $numberRemain, 'status' => $status]);
if (!$upRes) {
Db::rollBack();
return '优惠券使用失败';
}
// 缓存使用记录
$usedRes = $this->couponService->cacheTodayCouponUsed($coupon['user_id'], $coupon['system_coupon_user_id'], $coupon['id']);
if (!$usedRes) {
Db::rollBack();
return '优惠券使用失败';
}
} else {
Db::rollBack();
return '优惠券使用失败';
}
}
}
Db::commit();
return $orderMainId;
} catch (Exception $e) {
$this->log->event(
LogLabel::ORDER_LOG,
['message' => $e->getMessage()]
);
Db::rollBack();
return $e->getMessage();
}
}
/**
* @inheritDoc
*/
public function addOfflineOrder($data)
{
Db::beginTransaction();
try {
// 主订单数据
$dataMain = [];
// 获取分布式全局ID
$generator = ApplicationContext::getContainer()->get(IdGeneratorInterface::class);
$globalRrderId = $generator->generate();
// 主订单插入数据
$currentTime = time();
$dataMain = [
'delivery_no' => '',
'dada_fee' => 0,
'market_id' => 0,
'box_money' => 0,
'ps_money' => 0,
'mj_money' => 0,
'xyh_money' => 0,
'yhq_money' => 0,
'yhq_money2' => 0,
'zk_money' => 0,
'tel' => '',
'name' => '',
'address' => '',
'area' => '',
'lat' => '',
'lng' => '',
'note' => '',
'form_id' => '',
'form_id2' => '',
'delivery_time' => '',
'order_type' => 0,
'coupon_id' => 0,
'coupon_id2' => 0,
'store_list' => '',
'receive_coupon_ids' => '',
'type' => OrderMain::ORDER_TYPE_OFFLINE,
'time' => date('Y-m-d H:i:s', $currentTime),
'time_add' => $currentTime,
'pay_time' => '',
'pay_type' => OrderMain::ORDER_PAY_WX,
'state' => OrderMain::ORDER_STATE_UNPAY,
'dm_state' => OrderMain::ORDER_STATE_UNPAY,
'code' => $globalRrderId,
'jj_note' => '',
'uniacid' => 2,
'order_num' => 'dm'.date('YmdHis', time()) . rand(1111, 9999),
'money' => $data['money'],
'user_id' => $data['user_id'],
'store_ids' => $data['store_id'],
'global_order_id' => $globalRrderId,
];
// 主订单模型保存
$orderMain = OrderMain::create($dataMain);
$orderMainId = $orderMain->id;
// 子订单模型保存
$dataChild = [
'uniacid' => 1,
'order_num' => 's'.date('YmdHis', time()) . rand(1111, 9999),
'user_id' => $orderMain->user_id,
'store_id' => $data['store_id'],
'order_main_id' => $orderMainId,
'state' => OrderMain::ORDER_STATE_UNPAY,
'dm_state' => OrderMain::ORDER_STATE_UNPAY,
'tel' => $orderMain->tel,
'name' => $orderMain->name,
'address' => $orderMain->address,
'area' => $orderMain->area,
'time' => date("Y-m-d H:i:s"),
'note' => '',
'delivery_time' => $orderMain->delivery_time,
'type' => $orderMain->type,
'lat' => $orderMain->lat,
'lng' => $orderMain->lng,
'pay_type' => $orderMain->pay_type,
'order_type' => $orderMain->order_type,
'money' => $data['money'],
'box_money' => 0,
'mj_money' => 0,
'yhq_money' => 0,
'yhq_money2' => 0,
'zk_money' => 0,
'coupon_id' => 0,
'coupon_id2' => 0,
'xyh_money' => 0,
'time_add' => date("Y-m-d H:i:s"),
'jj_note' => '',
'form_id' => '',
'form_id2' => '',
'code' => '',
];
$orderChildId = Order::query()->insertGetId($dataChild);
Db::commit();
return $orderMainId;
} catch (Exception $e) {
$this->log->event(
LogLabel::ORDER_LOG,
['message' => $e->getMessage()]
);
Db::rollBack();
return '购买失败';
}
}
/**
* 计算和校验当前订单可用红包及金额
* @param $couponIds
* @param $orderAmount
* @param $userId
* @param $marketId
* @throws Exception
*/
protected function getCouponAmount($couponIds, $orderAmount, $userId, $marketId)
{
// 用户当前订单可用优惠券
$couponsCanUse = $this->couponService->getOrderCanUseCoupons(
$orderAmount,
$marketId,
$userId,
[
'receive.id',
'receive.user_id',
'receive.number',
'receive.number_remain',
'receive.system_coupon_user_id',
'coupon.discounts',
'coupon.discount_type',
]
);
$couponCanUseIds = array_column($couponsCanUse, 'id');
$couponCanUseIds = array_intersect($couponCanUseIds, $couponIds);
$couponCannotUseIds = array_diff($couponIds, $couponCanUseIds);
if (empty($couponCanUseIds)||!empty($couponCannotUseIds)) {
throw new Exception('您的订单中有优惠券已经失效');
}
// 计算红包折扣金额
$couponMoney = 0;
foreach ($couponsCanUse as $key => $coupon) {
if (!in_array($coupon->id, $couponIds)) {
continue;
}
if ($coupon->discount_type == Coupon::DISCOUNT_TYPE_CASH) {
$couponMoney = bcadd($couponMoney, $coupon->discounts, 2);
} elseif ($coupon->discount_type == Coupon::DISCOUNT_TYPE_RATE) {
$discountRate = bcdiv($coupon->discounts,10);
$discountRate = bcsub(1,$discountRate);
$discountMoney = bcmul($orderAmount, $discountRate);
$couponMoney = bcadd($couponMoney, $discountMoney, 2);
}
}
return $couponMoney;
}
/**
* 订单是否存在
* @param $orderNum
* @return \Hyperf\Utils\HigherOrderTapProxy|mixed|void|null
*/
public function existsByOrderNum($orderNum)
{
return OrderMain::query()->where(['order_num' => $orderNum])->value('id');
}
}

29
app/Service/OrderServiceInterface.php

@ -0,0 +1,29 @@
<?php
namespace App\Service;
interface OrderServiceInterface
{
/**
* 线上订单下单
* 外卖
* @param $data
* @return mixed
*/
public function addOnlineOrder($data);
/**
* 线下订单下单
* 扫码支付
* @return mixed
*/
public function addOfflineOrder($data);
/**
* 订单是否已经存在
* @param $orderNum
* @return mixed
*/
public function existsByOrderNum($orderNum);
}

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;
}
}

79
app/Service/UserService.php

@ -0,0 +1,79 @@
<?php
namespace App\Service;
use App\Model\Order;
use App\Model\OrderMain;
use App\Model\Users;
class UserService implements UserServiceInterface
{
/**
* 是否平台新用户
* 在很多奖励的地方会需要用到这个查询
* 判定条件:
* 没有在平台下过单(包括线上和线下)
* @param $user_id
* @param $order_main_id
* @return mixed|void
*/
public function isStageNewUser($user_id, $order_main_id): bool
{
$exist = OrderMain::query()
->where(['user_id' => $user_id])
->where('id', '!=', $order_main_id)
->where(function ($query){
$query->whereIn('state', [OrderMain::ORDER_STATE_COMPLETE,OrderMain::ORDER_STATE_EVALUATED,OrderMain::ORDER_STATE_UNREFUND])
->orWhereIn('dm_state', [OrderMain::ORDER_STATE_UNTAKE,OrderMain::ORDER_STATE_DELIVERY]);
})
->exists();
return !$exist;
}
/**
* 根据用户的openid更新unionid信息
* 如果没有找到用户,则不做任何处理
* @param $openid
* @param $unionid
* @return array
*/
public function saveUserUnionid($openid,$unionid)
{
$result = [
'status' => false,
'msg' => '用户不存在或者已存在相同unionid'
];
// 查询用户是否存在
$userinfo = Users::select('id','unionid')->where('openid',$openid)->first();
if($userinfo && $userinfo->unionid != $unionid){
$userinfo->unionid = $unionid;
if($res = $userinfo->save()){
$result['status'] = true;
$result['msg'] = '更改用户unionid信息成功';
$result['res'] = $res;
}else{
$result['msg'] = '更改用户unionid信息失败';
}
}
return $result;
}
/**
* @inheritDoc
*/
public function isStoreFirstOrderToday($user_id, $store_id, $current_order_id, $limit_amount = 3)
{
return !Order::query()
->where(['user_id' => $user_id, 'store_id' => $store_id])
->whereIn('dm_state', [OrderMain::ORDER_STATE_UNTAKE,OrderMain::ORDER_STATE_DELIVERY])
->where('time_add', '>=', date('Y-m-d 00:00:00'))
->where('time_add', '<=', date('Y-m-d 23:59:59'))
->where('money', '>=', $limit_amount)
->where('id', '!=', $current_order_id)
->exists();
}
}

29
app/Service/UserServiceInterface.php

@ -0,0 +1,29 @@
<?php
namespace App\Service;
interface UserServiceInterface
{
/**
* 是否平台新用户
* @param $user_id
* @param $order_main_id
* @return mixed
*/
public function isStageNewUser($user_id, $order_main_id): bool;
public function saveUserUnionid($openid,$unionid);
/**
* 是否店铺当日首单
* @param $user_id
* @param $store_id
* @param $current_order_id
* @param int $limit_amount
* @return mixed
*/
public function isStoreFirstOrderToday($user_id, $store_id, $current_order_id, $limit_amount = 3);
}

62
app/TaskWorker/AliIotTask.php

@ -0,0 +1,62 @@
<?php
namespace App\TaskWorker;
use App\Commons\Log;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Task\Annotation\Task;
use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;
use Hyperf\Di\Annotation\Inject;
class AliIotTask
{
/**
* @Inject
* @var Log
*/
protected $log;
/**
* @var DefaultAcsClient
*/
public $client = null;
/**
* @Task
*/
public function exec($device_name, $msg)
{
AlibabaCloud::accessKeyClient('LTAI4GJEWrN6dVh7HmPKHMyF', 'wMae4ckfVGwMQPVw5ZlVDDpihVeUap')
->regionId('cn-shanghai')
->asDefaultClient();
try {
AlibabaCloud::rpc()
->product('Iot')
->version('2018-01-20')
->action('Pub')
->method('POST')
->host('iot.cn-shanghai.aliyuncs.com')
->options([
'query' => [
'RegionId' => "cn-shanghai",
'TopicFullName' => "/a1ZSurIJmO0/".$device_name."/user/get",
'MessageContent' => base64_encode($msg),
'ProductKey' => "a1ZSurIJmO0",
],
])
->request();
} catch (ClientException $e) {
echo $e->getErrorMessage() . PHP_EOL;
} catch (ServerException $e) {
echo $e->getErrorMessage() . PHP_EOL;
}
return true;
}
}

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;
}
}

14
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,8 +27,16 @@
"hyperf/redis": "~2.0.0",
"hyperf/constants": "~2.0.0",
"hyperf/model-cache": "~2.0.0",
"hyperf/validation": "^2.0",
"hyperf/paginator": "^2.0"
"hyperf/filesystem": "^2.0",
"xxtime/flysystem-aliyun-oss": "^1.5",
"hyperf/validation": "^2.0",
"hyperf/task": "^2.0",
"hyperf/paginator": "^2.0",
"hyperf/amqp": "^2.0",
"alibabacloud/iot": "^1.8",
"hyperf/snowflake": "^2.0",
"ext-bcmath": "*",
"overtrue/wechat": "~4.0"
},
"require-dev": {
"swoole/ide-helper": "^4.5",

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,
],
]
];

15
config/autoload/dependencies.php

@ -9,7 +9,22 @@ declare(strict_types=1);
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
return [
\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,
\App\Service\DeviceServiceInterface::class =>\App\Service\DeviceServiceImp::class,
\App\Service\IOTServiceInterface::class => \App\Service\IOTAliService::class,
\App\Service\OrderServiceInterface::class => \App\Service\OrderService::class,
\App\Service\MqttServiceInterface::class => \App\Service\MqttSpeakerService::class,
\App\Service\FeiePrintServiceInterface::class => \App\Service\FeiePrintService::class,
\App\Service\MiniprogramServiceInterface::class => \App\Service\MiniprogramService::class,
\App\Service\UserServiceInterface::class => \App\Service\UserService::class,
\App\Service\OrderListServiceInterface::class => \App\Service\OrderListService::class,
];

4
config/autoload/exceptions.php

@ -14,7 +14,9 @@ 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,
\App\Exception\Handler\FilesystemExceptionHandler::class,
],
],
];

94
config/autoload/file.php

@ -0,0 +1,94 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
return [
'default' => 'oss',
'storage' => [
'local' => [
'driver' => \Hyperf\Filesystem\Adapter\LocalAdapterFactory::class,
'root' => BASE_PATH . '/attachment',
],
'ftp' => [
'driver' => \Hyperf\Filesystem\Adapter\FtpAdapterFactory::class,
'host' => 'ftp.example.com',
'username' => 'username',
'password' => 'password',
// 'port' => 21,
// 'root' => '/path/to/root',
// 'passive' => true,
// 'ssl' => true,
// 'timeout' => 30,
// 'ignorePassiveAddress' => false,
],
'memory' => [
'driver' => \Hyperf\Filesystem\Adapter\MemoryAdapterFactory::class,
],
's3' => [
'driver' => \Hyperf\Filesystem\Adapter\S3AdapterFactory::class,
'credentials' => [
'key' => env('S3_KEY'),
'secret' => env('S3_SECRET'),
],
'region' => env('S3_REGION'),
'version' => 'latest',
'bucket_endpoint' => false,
'use_path_style_endpoint' => false,
'endpoint' => env('S3_ENDPOINT'),
'bucket_name' => env('S3_BUCKET'),
],
'minio' => [
'driver' => \Hyperf\Filesystem\Adapter\S3AdapterFactory::class,
'credentials' => [
'key' => env('S3_KEY'),
'secret' => env('S3_SECRET'),
],
'region' => env('S3_REGION'),
'version' => 'latest',
'bucket_endpoint' => false,
'use_path_style_endpoint' => true,
'endpoint' => env('S3_ENDPOINT'),
'bucket_name' => env('S3_BUCKET'),
],
'oss' => [
'driver' => \Hyperf\Filesystem\Adapter\AliyunOssAdapterFactory::class,
'accessId' => env('OSS_ACCESS_ID'),
'accessSecret' => env('OSS_ACCESS_SECRET'),
'bucket' => env('OSS_BUCKET'),
'endpoint' => env('OSS_ENDPOINT'),
// 'timeout' => 3600,
// 'connectTimeout' => 10,
// 'isCName' => false,
// 'token' => '',
],
'qiniu' => [
'driver' => \Hyperf\Filesystem\Adapter\QiniuAdapterFactory::class,
'accessKey' => env('QINIU_ACCESS_KEY'),
'secretKey' => env('QINIU_SECRET_KEY'),
'bucket' => env('QINIU_BUCKET'),
'domain' => env('QINBIU_DOMAIN'),
],
'cos' => [
'driver' => \Hyperf\Filesystem\Adapter\CosAdapterFactory::class,
'region' => env('COS_REGION'),
'credentials' => [
'appId' => env('COS_APPID'),
'secretId' => env('COS_SECRET_ID'),
'secretKey' => env('COS_SECRET_KEY'),
],
'bucket' => env('COS_BUCKET'),
'read_from_cdn' => false,
// 'timeout' => 60,
// 'connect_timeout' => 60,
// 'cdn' => '',
// 'scheme' => 'https',
],
],
];

2
config/autoload/middlewares.php

@ -11,7 +11,7 @@ declare(strict_types=1);
*/
return [
'http' => [
\App\Middleware\Auth\ApiMiddleware::class,
\App\Middleware\CorsMiddleware::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'],
],

24
config/autoload/snowflake.php

@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
use Hyperf\Snowflake\MetaGenerator\RedisMilliSecondMetaGenerator;
use Hyperf\Snowflake\MetaGenerator\RedisSecondMetaGenerator;
use Hyperf\Snowflake\MetaGeneratorInterface;
return [
'begin_second' => MetaGeneratorInterface::DEFAULT_BEGIN_SECOND,
RedisMilliSecondMetaGenerator::class => [
'pool' => 'default',
],
RedisSecondMetaGenerator::class => [
'pool' => 'default',
],
];

13
config/config.php

@ -28,4 +28,17 @@ return [
LogLevel::WARNING,
],
],
'site_host'=> env('SITE_HOST', ''),
'wxpay' => [
'app_id' => env('APP_ID',''),
'mch_id' => env('MCH_ID',''),
'key' => env('MCH_KEY',''),
'cert_path' => env('CERT_PATH',''),
'key_path' => env('KEY_PATH',''),
'notify_url' => env('NOTIFY_URL',''),
],
'wxtempmsg' => [
'app_id' => env('APP_ID',''),
'secret' => env('APP_SECRET',''),
]
];

37
config/routes.php

@ -23,6 +23,43 @@ Router::addGroup('/v1/',function (){
Router::post('ServiceEvaluate/isPersonnel', 'App\Controller\ServiceEvaluateController@isPersonnel');
Router::post('ServiceEvaluate/getPersonnelInfo', 'App\Controller\ServiceEvaluateController@getPersonnelInfo');
Router::post('ServiceEvaluate/getEvaluateList', 'App\Controller\ServiceEvaluateController@getEvaluateList');
Router::post('Attachment/uploadImage', 'App\Controller\AttachmentController@uploadImage');
Router::post('Attachment/uploadImageByBase64', 'App\Controller\AttachmentController@uploadImageByBase64');
Router::post('Attachment/upload', 'App\Controller\AttachmentController@upload');
Router::post('ParamsToken/generate', 'App\Controller\ParamsTokenController@generate');
Router::post('ParamsToken/analyze', 'App\Controller\ParamsTokenController@analyze');
Router::post('Ad/banners', 'App\Controller\AdController@banners');
Router::post('CouponRebate/isCouponRebate', 'App\Controller\CouponRebateController@isCouponRebate');
Router::post('CouponRebate/userReceiveCoupon', 'App\Controller\CouponRebateController@userReceiveCoupon');
Router::post('CouponRebate/getActiveInfo', 'App\Controller\CouponRebateController@getActiveInfo');
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');
Router::post('Community/bind', 'App\Controller\CommunityController@bind');
Router::post('user/saveUserUnionid', 'App\Controller\UserController@saveUserUnionid');
//订单相关
Router::post('Order/addOnline', 'App\Controller\OrderController@addOnlineOrder');
Router::post('Order/addOffline', 'App\Controller\OrderController@addOfflineOrder');
//小程序支付相关
Router::post('wxminipay/online', 'App\Controller\PaymentController@wxminiPayOnline');
Router::post('wxminipay/offline', 'App\Controller\PaymentController@wxminiPayOffline');
Router::post('OrderList/storeOrderList', 'App\Controller\OrderListController@storeOrderList');
Router::post('OrderList/userOrderList', 'App\Controller\OrderListController@userOrderList');
},['middleware' => [\App\Middleware\Auth\ApiMiddleware::class]]);
Router::addGroup('/wechat/',function () {
Router::post('notify/wxminionline', 'App\Controller\NotifyController@wxminiOnline');
Router::post('notify/wxminioffline', 'App\Controller\NotifyController@wxminiOffline');
});
Loading…
Cancel
Save