瀏覽代碼

add:加桌、注册统计;

Wang Chen 4 年之前
父節點
當前提交
4b598352ef

+ 26 - 0
app/Cache/CacheKeys.php

@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * Created by PhpStorm.
+ * User: wangchen
+ * Date: 2019-05-07
+ * Time: 14:48
+ */
+
+namespace App\Cache;
+
+
+class CacheKeys
+{
+    /**
+     * 所有key的管理配置
+     * key规范:模块+功能+参数
+     *
+     * @var array
+     */
+    public static $all = [
+        'lock' => [
+            'token' => 'Lock:%s', // 锁,token
+        ]
+    ];
+}

+ 44 - 0
app/Cache/Lock/LockCache.php

@@ -0,0 +1,44 @@
+<?php
+
+
+namespace App\Cache\Lock;
+
+
+use App\Consts\BaseConst;
+use App\Libs\Utils;
+use Illuminate\Support\Facades\Redis;
+
+/**
+ * 命令参考链接: http://doc.redisfans.com/string/set.html
+ * 命令 SET resource-name anystring NX EX max-lock-time 是一种在 Redis 中实现锁的简单方法。
+ * Class LockCache
+ * @package App\Cache\Lock
+ */
+class LockCache
+{
+    /**
+     * @param     $token
+     * @param int $seconds
+     * @return mixed
+     */
+    public static function getLock($token, $seconds = BaseConst::LOCK_DEFAULT_SECONDS)
+    {
+        $cacheKey = Utils::getCacheKey('lock.token', [$token]);
+        return Redis::set($cacheKey, $token, 'nx', 'ex', $seconds);
+    }
+
+    /**
+     * @param $token
+     * @return int
+     */
+    public static function releaseLock($token)
+    {
+        $cacheKey = Utils::getCacheKey('lock.token', [$token]);
+        $result   = Redis::get($cacheKey);
+        if ($result === $token) {
+            return Redis::del($cacheKey);
+        }
+
+        return 0;
+    }
+}

+ 83 - 0
app/Consts/BaseConst.php

@@ -0,0 +1,83 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: wangchen
+ * Date: 2019-05-06
+ * Time: 17:50
+ */
+
+namespace App\Consts;
+
+
+class BaseConst
+{
+    /**
+     * 一天86400秒
+     */
+    const ONE_DAY_SECONDS = 86400;
+
+    /**
+     * 一周 86400 * 7 秒
+     */
+    const ONE_WEEK_SECONDS = 604800;
+
+    /**
+     * 一个月 86400 * 31 秒
+     */
+    const ONE_MONTH_SECONDS = 2678400;
+
+    /**
+     * 一天24*60分钟
+     */
+    const ONE_DAY_MINITUES = 1440;
+
+    /**
+     * 一分钟60秒
+     */
+    const ONE_MINUTE_SECONDS = 60;
+
+    /**
+     * 一小时3600秒
+     */
+    const ONE_HOUR = 3600;
+
+    /**
+     * 一年365天
+     */
+    const ONE_YEAR_DAYS = 365;
+
+    /**
+     * 默认锁时长
+     */
+    const LOCK_DEFAULT_SECONDS = 5;
+
+    const SPECIAL_USER_LOG = 7530391;
+
+    /**
+     * 默认分页数量
+     */
+    const DEFAULT_LENGTH = 15;
+
+    /**
+     * 长度20
+     */
+    const TWENTY_LENGTH = 20;
+
+    /**
+     * 初级vip等级
+     */
+    const JUNIOR_VIP_LEVEL = 1;
+
+    /**
+     * 高级vip登记等级
+     */
+    const SENIOR_VIP_LEVEL = 2;
+
+    /**
+     * 网站类型
+     */
+    const SITE_WAP = 'wap';
+    const SITE_WWW = 'www';
+    const SITE_APP = 'app';
+
+}

+ 18 - 0
app/Consts/QuickConst.php

@@ -0,0 +1,18 @@
+<?php
+
+
+namespace App\Consts;
+
+
+class QuickConst
+{
+    /**
+     * 注册数
+     */
+    const FIELD_REGISTER = 'register_num';
+
+    /**
+     * 加桌书
+     */
+    const FIELD_ADD_DESKTOP = 'add_desktop_num';
+}

+ 18 - 0
app/Exceptions/ApiException.php

@@ -0,0 +1,18 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: wangchen
+ * Date: 2019-05-07
+ * Time: 15:03
+ */
+
+namespace App\Exceptions;
+
+
+class ApiException extends \Exception
+{
+    public function __construct($code = 0, $message = '')
+    {
+        parent::__construct($message, $code);
+    }
+}

+ 36 - 7
app/Exceptions/Handler.php

@@ -22,6 +22,7 @@ class Handler extends ExceptionHandler
         HttpException::class,
         ModelNotFoundException::class,
         ValidationException::class,
+        ApiException::class,
     ];
 
     /**
@@ -34,6 +35,32 @@ class Handler extends ExceptionHandler
      */
     public function report(Exception $e)
     {
+        $appEnv = env('APP_ENV', 'production');
+        if ($this->shouldReport($e) && env('APP_ENV') !== 'local') {
+            $date        = date('Y-m-d H:i:s');
+            $file        = $e->getFile();
+            $line        = $e->getLine();
+            $message     = $e->getMessage();
+            $trace       = $e->getTraceAsString();
+            $traceArr    = explode('#', $trace);
+            $traceSimple = $trace;
+            if (is_array($traceArr)) {
+                $traceSub    = array_slice($traceArr, 0, 3);
+                $traceSimple = implode('#', $traceSub);
+            }
+
+            $msg = <<<EOF
+项目:quick_app [$appEnv]
+报错时间:$date
+报错文件:$file
+报错行数:line $line
+报错信息:$message
+报错跟踪:
+$traceSimple
+EOF;
+            sendNotice($msg);
+        }
+
         parent::report($e);
     }
 
@@ -53,14 +80,16 @@ class Handler extends ExceptionHandler
 
     public function render($request, Exception $e)
     {
-        return parent::render($request, $e);
-        switch ($e){
-            case ($e instanceof NotFoundHttpException):
-                return response()->json(['code'=>10004,'msg'=>'not found']);
-                break;
-            default:
-                return response()->json(['code'=>10004,'msg'=>$e->getMessage()]);
+        if ($e instanceof ApiException) {
+            $data = [
+                'code' => $e->getCode(),
+                'msg'  => $e->getMessage(),
+                'data' => []
+            ];
+
+            return response()->json($data);
         }
 
+        return parent::render($request, $e);
     }
 }

+ 173 - 0
app/Libs/ApiResponse.php

@@ -0,0 +1,173 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: wangchen
+ * Date: 2019-05-07
+ * Time: 15:52
+ */
+
+namespace App\Libs;
+
+use Symfony\Component\HttpFoundation\Response as FoundationResponse;
+use Response;
+
+trait ApiResponse
+{
+    /**
+     * @var int
+     */
+    protected $statusCode = FoundationResponse::HTTP_OK;
+
+    /**
+     * @return mixed
+     */
+    public function getStatusCode()
+    {
+        return $this->statusCode;
+    }
+
+    /**
+     * @param $statusCode
+     * @return $this
+     */
+    public function setStatusCode($statusCode, $httpCode = null)
+    {
+        $httpCode         = $httpCode ?? $statusCode;
+        $this->statusCode = $statusCode;
+        return $this;
+    }
+
+    /**
+     * @param       $data
+     * @param array $header
+     * @return mixed
+     */
+    public function respond($data, $header = [])
+    {
+        return Response::json($data, $this->getStatusCode(), $header,JSON_UNESCAPED_UNICODE);
+    }
+
+    /**
+     * @param       $status
+     * @param array $data
+     * @param null  $code
+     * @return mixed
+     */
+    public function status($status, $data, $code = null)
+    {
+        $data = object_to_array($data);
+
+        if ($code) {
+            $this->setStatusCode($code);
+        }
+        $res = [
+            'msg'  => $status,
+            'code' => 0,
+            'data' => $data
+        ];
+
+        return $this->respond($res);
+    }
+
+    /**
+     * @param        $message
+     * @param int    $code
+     * @param string $status
+     * @return mixed
+     */
+    /*
+     * 格式
+     * data:
+     *  code:422
+     *  message:xxx
+     *  status:'error'
+     */
+    public function failed($message, $code = FoundationResponse::HTTP_BAD_REQUEST, $status = 'error')
+    {
+
+        return $this->setStatusCode($code)->message($message, $status);
+    }
+
+    /**
+     * @param        $message
+     * @param string $status
+     * @return mixed
+     */
+    public function message($message, $status = 'success')
+    {
+
+        return $this->status($status, [
+            'message' => $message
+        ]);
+    }
+
+    /**
+     * @param string $message
+     * @return mixed
+     */
+    public function internalError($message = 'Internal Error!')
+    {
+
+        return $this->failed($message, FoundationResponse::HTTP_INTERNAL_SERVER_ERROR);
+    }
+
+    /**
+     * @param string $message
+     * @return mixed
+     */
+    public function created($message = 'created')
+    {
+        return $this->setStatusCode(FoundationResponse::HTTP_CREATED)
+            ->message($message);
+
+    }
+
+    /**
+     * @param $data
+     * @param $callFunc
+     * @return mixed
+     */
+    public function success($data, $callFunc = [])
+    {
+        if ($callFunc) {
+            return $this->status('', call_user_func($callFunc, $data));
+        }
+
+        return $this->status('', $data);
+    }
+
+    /**
+     * @param $errorData
+     * @param $data
+     * @return mixed
+     */
+    public function error($errorData, $data)
+    {
+        // 分解错误码、错误信息
+        $arr  = explode(':', (string)$errorData);
+        $code = (int)$arr[0];
+        $msg  = (string)$arr[1];
+
+        $res = [
+            'msg'  => $msg,
+            'code' => $code,
+            'data' => $data
+        ];
+
+        return $this->respond($res);
+    }
+
+    public function appResponse($res)
+    {
+        return $this->respond($res);
+    }
+
+    /**
+     * @param string $message
+     * @return mixed
+     */
+    public function notFond($message = 'Not Fond!')
+    {
+        return $this->failed($message, Foundationresponse::HTTP_NOT_FOUND);
+    }
+}

+ 88 - 0
app/Libs/Helpers.php

@@ -660,3 +660,91 @@ function getMillisecond()
     list($microsecond, $time) = explode(' ', microtime());
     return (float) sprintf('%.0f', (floatval($microsecond) + floatval($time)) * 1000);
 }
+
+/**
+ * CURL发送post请求
+ * @param      $url
+ * @param null $data
+ * @param bool $json
+ * @return bool|string
+ */
+function httpPostRequest($url, $data = null, $json = FALSE)
+{
+    //创建了一个curl会话资源,成功返回一个句柄;
+    $curl = curl_init();
+    //设置url
+    curl_setopt($curl, CURLOPT_URL, $url);
+    //设置为FALSE 禁止 cURL 验证对等证书(peer’s certificate)
+    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
+    //设置为 1 是检查服务器SSL证书中是否存在一个公用名(common name)
+    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
+    if (!empty($data)) {
+        //设置请求为POST
+        curl_setopt($curl, CURLOPT_POST, 1);
+        //curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 60); //最长的可忍受的连接时间
+        //设置POST的数据域
+        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
+        if ($json) {
+            curl_setopt($curl, CURLOPT_HEADER, 0);
+            curl_setopt(
+                $curl,
+                CURLOPT_HTTPHEADER,
+                array(
+                    'Content-Type: application/json; charset=utf-8',
+                    'Content-Length: ' . strlen($data)
+                )
+            );
+        }
+    }
+    //设置是否将响应结果存入变量,1是存入,0是直接输出
+    curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
+    //然后将响应结果存入变量
+    $output = curl_exec($curl);
+    //关闭这个curl会话资源
+    curl_close($curl);
+    return $output;
+}
+
+/**
+ * 获取对象或数组的属性值
+ * @param        $param
+ * @param        $key
+ * @param string $default
+ * @return mixed|string
+ */
+function getProp($param, $key, $default = '')
+{
+    $result = $default;
+    if (is_object($param) && isset($param->$key)) {
+        $result = $param->$key;
+    }
+
+    if (is_array($param) && isset($param[$key])) {
+        $result = $param[$key];
+    }
+
+    return $result;
+}
+
+/**
+ * 钉钉通知异常
+ * @param $message
+ */
+function sendNotice($message)
+{
+    $webHook = 'https://oapi.dingtalk.com/robot/send?access_token=bd4a583857c84241903aeeaf3864e8e2b776974e1f69d8ff98ed36eddbe86e1d';
+    $data    = [
+        'msgtype' => 'text',
+        'text'    => [
+            'content' => $message
+        ],
+        'at'      => [
+            //            'atMobiles' => [
+            //                '13127819373'
+            //            ],
+            'isAll' => true
+        ]
+    ];
+
+    httpPostRequest($webHook, json_encode($data), true);
+}

+ 330 - 0
app/Libs/Utils.php

@@ -0,0 +1,330 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: wangchen
+ * Date: 2019-05-07
+ * Time: 15:22
+ */
+
+namespace App\Libs;
+
+
+use App\Cache\CacheKeys;
+use Hashids;
+use App\Exceptions\ApiException;
+use PhpAmqpLib\Connection\AMQPStreamConnection;
+use PhpAmqpLib\Message\AMQPMessage;
+
+class Utils
+{
+    /**
+     * 异常报错
+     * @param       $errorData
+     * @throws ApiException
+     */
+    public static function throwError($errorData)
+    {
+        // 分解错误码、错误信息
+        $arr  = explode(':', (string)$errorData);
+        $code = (int)$arr[0];
+        $msg  = (string)$arr[1];
+
+        throw new ApiException($code, $msg);
+    }
+
+    /**
+     * 解码加密id
+     * @param $idStr
+     * @return int
+     */
+    public static function getDecodeId($idStr)
+    {
+        if (!is_numeric($idStr)) {
+            $idArr = Hashids::decode($idStr);
+            $id    = isset($idArr[0]) ? (int)$idArr[0] : 0;
+        } else {
+            $id = $idStr;
+        }
+
+        return $id;
+    }
+
+    /**
+     * 加密id
+     * @param $id
+     * @return mixed
+     */
+    public static function getEncodeId($id)
+    {
+        return Hashids::encode($id);
+    }
+
+    /**
+     * 获取redis的key
+     * @param       $keyStr // 例如:wap.rank_page
+     * @param array $args // 例如:[10, 2000]
+     *
+     * Utils::getCacheKey('wap.rank_page', [10, 2000])
+     * Utils::getCacheKey('promotion.setStatus')
+     * Utils::getCacheKey('promotion.infos', [2])
+     *
+     * @return string
+     */
+    public static function getCacheKey($keyStr, $args = [])
+    {
+        $stdStr = array_get(CacheKeys::$all, $keyStr, '');
+        if ($args) {
+            $stdStr = sprintf($stdStr, ...$args);
+        }
+
+        return $stdStr;
+    }
+
+    /**
+     * 展示友好数字
+     * @param $num
+     * @return string
+     */
+    public static function showNiceNumber($num)
+    {
+        if ($num >= 10000) {
+            $num = sprintf('%.1f', round($num / 10000 * 100) / 100) . '万';
+        } elseif ($num >= 1000) {
+            $num = sprintf('%.1f', round($num / 1000 * 100) / 100) . '千';
+        }
+        return $num;
+    }
+
+    /**
+     * 根据日期获得这周的周一
+     * @param        $date
+     * @param int    $d
+     * @param string $format
+     * @return false|string
+     */
+    public static function firstOfWeek($date, $d = 0, $format = 'Ymd')
+    {
+        $now      = strtotime($date) - $d * 86400;    //当时的时间戳
+        $number   = date("w", $now);  //当时是周几
+        $number   = $number == 0 ? 7 : $number; //如遇周末,将0换成7
+        $diff_day = $number - 1; //求到周一差几天
+        return date($format, $now - ($diff_day * 60 * 60 * 24));
+    }
+
+    /**
+     * 老原创的签名
+     * @param $time
+     * @return string
+     */
+    public static function getOldYcSign($time): string
+    {
+        $privateKey = env('EXTERNAL_PRIVATE_KEY');
+        return md5(md5($time . $privateKey) . $privateKey);
+    }
+
+    /**
+     * @param array $data
+     * @param array $colHeaders
+     * @param bool  $asString
+     * @return bool|string
+     */
+    public static function toCSV(array $data, array $colHeaders = array(), $asString = false)
+    {
+        $stream = $asString ? fopen('php://temp/maxmemory', 'wb+') : fopen('php://output', 'wb');
+
+        if (!empty($colHeaders)) {
+            fputcsv($stream, $colHeaders);
+        }
+
+        foreach ($data as $record) {
+            fputcsv($stream, $record);
+        }
+
+        if ($asString) {
+            rewind($stream);
+            $returnVal = stream_get_contents($stream);
+            fclose($stream);
+            return $returnVal;
+        }
+
+        fclose($stream);
+        return true;
+    }
+
+    /**
+     * 设备信息
+     * @return string
+     */
+    public static function getDeviceType(): string
+    {
+        //全部变成小写字母
+        $agent = strtolower(getProp($_SERVER, 'HTTP_USER_AGENT'));
+        $type  = 'other';
+        //分别进行判断
+        if (strpos($agent, 'iphone') || strpos($agent, 'ipad')) {
+            $type = 'ios';
+        }
+
+        if (strpos($agent, 'android')) {
+            $type = 'android';
+        }
+        return $type;
+    }
+
+    /**
+     * 是否在微信内打卡
+     * @return bool
+     */
+    public static function isOpenedInWechat(): bool
+    {
+        //全部变成小写字母
+        $agent = strtolower($_SERVER['HTTP_USER_AGENT']);
+
+        //判断
+        if (strpos($agent, 'micromessenger')) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * 组装meta数据
+     * @param     $page
+     * @param     $total
+     * @param int $pageSize
+     * @return array
+     */
+    public static function buildMeta($page, $total, $pageSize = 15): array
+    {
+        $lastPage = (int)ceil($total / $pageSize);
+        return [
+            'current_page'  => (int)$page,
+            'next_page'     => ++$page,
+            'last_page'     => $lastPage ?? 1,
+            'per_page'      => (int)$pageSize,
+            'total'         => (int)$total,
+            'next_page_url' => '',
+            'prev_page_url' => ''
+        ];
+    }
+
+    /**
+     * 随机书币
+     * @param $coin
+     * @param $num
+     * @return array|bool
+     * @throws \Exception
+     */
+    public static function getRandomCoin($coin, $num)
+    {
+        $result = [];
+        if ($coin < $num || $coin < 1 || $num < 1) {
+            return $result;
+        }
+
+        // 计算平均值
+        $rem  = $coin % $num;
+        $mean = ($coin - $rem) / $num;
+
+        // 水平分割
+        for ($i = 0; $i < $num; $i++) {
+            $result[$i] = $mean;
+        }
+        // 水平分割后将取模多余部分分配给第一个红包
+        $result[0] += $rem;
+
+        // 随机分配金额
+        for ($i = 0; $i < $num; $i++) {
+            $r1  = random_int(0, $num - 1);
+            $r2  = random_int(0, $num - 1);
+            $per = random_int(1, 99) / 100;
+
+            // 随机金额
+            $mon = $result[$r1] - floor($result[$r1] * $per);
+            if ($result[$r1] - $mon > 0) {
+                // 减去随机金额
+                $result[$r1] -= $mon;
+                // 添加随机金额
+                $result[$r2] += $mon;
+            }
+        }
+        return $result;
+    }
+
+    /**
+     * 将数据推送到rabbitMq
+     * 参考:https://www.vckai.com/xiao-xi-dui-lie-rabbitmq-san-phpde-shi-yong-shi-li
+     * @param        $messageBody
+     * @param string $queue
+     * @return bool
+     */
+    public static function pushDataToAppSyncMq($messageBody, $queue = 'ycsd_sync'): bool
+    {
+        $exchange    = $queue; // 交换器
+        $routing_key = $queue;
+
+        try {
+            $host       = env('RABBITMQ_HOST');
+            $port       = env('RABBITMQ_PORT');
+            $user       = env('RABBITMQ_LOGIN');
+            $passwd     = env('RABBITMQ_PASSWORD');
+            $vhost      = env('RABBITMQ_VHOST');
+            $connection = new AMQPStreamConnection($host, $port, $user, $passwd, $vhost);
+
+            // 创建通道
+            $channel = $connection->channel();
+
+            /**
+             * 创建队列(Queue)
+             * name: hello         // 队列名称
+             * passive: false      // 如果用户仅仅想查询某一个队列是否已存在,如果不存在,不想建立该队列,仍然可以调用queue.declare,
+             *                          只不过需要将参数passive设为true,传给queue.declare,如果该队列已存在,则会返回true;
+             *                          如果不存在,则会返回Error,但是不会创建新的队列。
+             * durable: true       // 是不持久化, true ,表示持久化,会存盘,服务器重启仍然存在,false,非持久化
+             * exclusive: false    // 是否排他,指定该选项为true则队列只对当前连接有效,连接断开后自动删除
+             *  auto_delete: false // 是否自动删除,当最后一个消费者断开连接之后队列是否自动被删除
+             */
+            $channel->queue_declare($queue, true, false, false, false);
+
+            /**
+             * 创建交换机(Exchange)
+             * name: vckai_exchange// 交换机名称
+             * type: direct        // 交换机类型,分别为direct/fanout/topic,参考另外文章的Exchange Type说明。
+             * passive: false      // 如果设置true存在则返回OK,否则就报错。设置false存在返回OK,不存在则自动创建
+             * durable: false      // 是否持久化,设置false是存放到内存中的,RabbitMQ重启后会丢失
+             * auto_delete: false  // 是否自动删除,当最后一个消费者断开连接之后队列是否自动被删除
+             */
+            // $channel->exchange_declare('', 'direct', true, false, false);
+
+            // 绑定消息交换机和队列
+            // $channel->queue_bind($queue, $exchange);
+
+            /**
+             * 创建AMQP消息类型
+             * delivery_mode 消息是否持久化
+             * AMQPMessage::DELIVERY_MODE_NON_PERSISTENT  不持久化
+             * AMQPMessage::DELIVERY_MODE_PERSISTENT      持久化
+             */
+            $msg = new AMQPMessage($messageBody, ['delivery_mode' => AMQPMessage::DELIVERY_MODE_NON_PERSISTENT]);
+
+            /**
+             * 发送消息
+             * msg: $msg                // AMQP消息内容
+             * exchange: vckai_exchange // 交换机名称
+             * queue: hello             // 队列名称
+             */
+            $channel->basic_publish($msg, '', $routing_key);
+
+            /**
+             * 关闭链接
+             */
+            $channel->close();
+            $connection->close();
+        } catch (\Exception $e) {
+            sendNotice('RabbitMq 连接失败 ' . $e->getMessage());
+        }
+
+        return true;
+    }
+}

+ 71 - 0
app/Modules/User/Models/QappUserAddDesktopRealStats.php

@@ -0,0 +1,71 @@
+<?php
+
+namespace App\Modules\User\Models;
+
+use DB;
+use Illuminate\Database\Eloquent\Model;
+
+class QappUserAddDesktopRealStats extends Model
+{
+    protected $table = 'qapp_user_add_desktop_real_stats';
+    protected $fillable = [
+        'send_order_id',
+        'distribution_channel_id',
+        'register_num',
+        'add_desktop_num',
+        'date',
+    ];
+
+    /**
+     * 根据日期、派单id获取统计信息
+     * @param string $date
+     * @param int    $sendOrderId
+     * @return array
+     */
+    public static function getDesktopRealStat(string $date, int $sendOrderId)
+    {
+        if (empty($date) || empty($sendOrderId)) {
+            return [];
+        }
+
+        // 读主库
+        return DB::connection('mysql::write')
+            ->table('qapp_user_add_desktop_real_stats')
+            ->where('date', $date)
+            ->where('send_order_id', $sendOrderId)
+            ->first();
+    }
+
+    /**
+     * 写入数据
+     * @param $insertData
+     * @return bool
+     */
+    public static function insertDesktopRealStat($insertData)
+    {
+        if (empty($insertData)) {
+            return false;
+        }
+
+        return self::insertGetId($insertData);
+    }
+
+    /**
+     * 增加计数
+     * @param string $date
+     * @param int    $sendOrderId
+     * @param string $field
+     * @param int    $num
+     * @return bool
+     */
+    public static function incrDesktopRealStat(string $date, int $sendOrderId, string $field, $num = 1)
+    {
+        if (empty($date) || empty($sendOrderId) || empty($field)) {
+            return false;
+        }
+
+        return self::where('date', $date)
+            ->where('send_order_id', $sendOrderId)
+            ->increment($field, $num);
+    }
+}

+ 57 - 0
app/Modules/User/Services/QappAddDeskTopService.php

@@ -0,0 +1,57 @@
+<?php
+
+
+namespace App\Modules\User\Services;
+
+
+use App\Consts\QuickConst;
+use App\Modules\SendOrder\Models\SendOrder;
+use App\Modules\User\Models\QappUserAddDesktopRealStats;
+use App\Modules\User\Models\User;
+
+class QappAddDeskTopService
+{
+    /**
+     * @param int    $uid
+     * @param string $field
+     * @param int    $num
+     * @return bool
+     */
+    public static function incrAddDeskTop(int $uid, string $field, $num = 1): bool
+    {
+        myLog('incrAddDeskTop')->info('start', compact('uid', 'field'));
+
+        // 参数判断
+        if ($uid < 1 || $num < 1 ||
+            !in_array($field, [QuickConst::FIELD_ADD_DESKTOP, QuickConst::FIELD_REGISTER], true)) {
+            return false;
+        }
+
+        // 获取用户信息
+        $user        = User::getUser($uid);
+        $sendOrderId = (int)getProp($user, 'send_order_id');
+        $channelId   = (int)getProp($user, 'distribution_channel_id');
+        myLog('incrAddDeskTop')->info('user_data', compact('uid', 'sendOrderId', 'channelId'));
+        if (empty($sendOrderId) || empty($channelId)) {
+            return false;
+        }
+
+        // 获取渠道id
+        $date     = date('Y-m-d', SERVER_TIME);
+        $realStat = QappUserAddDesktopRealStats::getDesktopRealStat($date, $sendOrderId);
+        if (!$realStat) {
+            // 初始化统计数据
+            QappUserAddDesktopRealStats::insertDesktopRealStat([
+                'send_order_id'           => $sendOrderId,
+                'distribution_channel_id' => $channelId,
+                'date'                    => $date,
+                'created_at'              => date('Y-m-d H:i:s', SERVER_TIME),
+                'updated_at'              => date('Y-m-d H:i:s', SERVER_TIME),
+            ]);
+        }
+
+        // 增加计数
+        myLog('incrAddDeskTop')->info('end', compact('date', 'sendOrderId', 'field', 'num'));
+        return QappUserAddDesktopRealStats::incrDesktopRealStat($date, $sendOrderId, $field, $num);
+    }
+}

+ 9 - 2
app/Modules/User/Services/QappUserService.php

@@ -3,6 +3,7 @@
 
 namespace App\Modules\User\Services;
 
+use App\Consts\QuickConst;
 use App\Jobs\QappTikTokUser;
 use App\Modules\BaseService;
 use App\Modules\User\Models\QappPackage;
@@ -13,7 +14,7 @@ use Illuminate\Support\Facades\DB;
 use Tymon\JWTAuth\Facades\JWTAuth;
 
 /**
- * 
+ *
  */
 class QappUserService
 {
@@ -22,11 +23,13 @@ class QappUserService
      */
     public function login(array $data)
     {
+        $isNewRegister = false;
         $device_no = $data['device_no'];
         $channel_id = $this->findChannelId($data['package']);
         $qapp_user = $this->getQAppUserByDeviceNo($device_no, $channel_id);
         if (!$qapp_user) {
-            $qapp_user = $this->createQuickAppUser($data);
+            $isNewRegister = true;
+            $qapp_user     = $this->createQuickAppUser($data);
         }
         $user = $qapp_user->user;
         $uid = $user->id;
@@ -35,6 +38,10 @@ class QappUserService
         if ($data['send_order_id']) {
             UserService::setUserSendOrder($uid, $data['send_order_id']);
         }
+        // 新注册统计
+        if ($isNewRegister && $qapp_user) {
+            QappAddDeskTopService::incrAddDeskTop($uid, QuickConst::FIELD_REGISTER);
+        }
         return compact('token', 'time', 'uid');
     }
 

+ 7 - 0
app/Modules/User/Services/UserService.php

@@ -9,6 +9,7 @@
 
 namespace App\Modules\User\Services;
 
+use App\Consts\QuickConst;
 use App\Modules\Book\Models\BookGiftsSend;
 use App\Modules\Book\Models\UserShelfBooks;
 use App\Modules\Subscribe\Models\BookOrder;
@@ -42,6 +43,7 @@ class UserService
 
     public static function qappAddDesktop(int $uid, int $status)
     {
+        myLog('incrAddDeskTop')->info('qappAddDesktop', compact('uid', 'status'));
         $log = QappUserAddDestop::where('uid', $uid)->orderBy('id', 'desc')->first();
         if ((!$log && $status == 1) || ($log && $log->status != $status)) {
             if ($status == 1) {
@@ -53,6 +55,11 @@ class UserService
                 'status' => $status
             ]);
         }
+
+        // 加桌统计
+        if (!$log && $status === 1) {
+            QappAddDeskTopService::incrAddDeskTop($uid, QuickConst::FIELD_ADD_DESKTOP);
+        }
     }
 
     /**

+ 3 - 0
public/index.php

@@ -6,6 +6,9 @@
  * @author   Taylor Otwell <taylorotwell@gmail.com>
  */
 
+date_default_timezone_set('PRC');
+define('SERVER_TIME', time());
+
 /*
 |--------------------------------------------------------------------------
 | Register The Auto Loader