fly před 4 roky
rodič
revize
3508b453b9
58 změnil soubory, kde provedl 3662 přidání a 0 odebrání
  1. 18 0
      composer.json
  2. 998 0
      src/Controllers/CompanyAuth/AppController.php
  3. 230 0
      src/Controllers/CompanyAuth/BaiDuAccountController.php
  4. 48 0
      src/Controllers/CompanyAuth/Transformers/ActivityTransformer.php
  5. 21 0
      src/Controllers/CompanyAuth/Transformers/BaiDuAdAccountTransformer.php
  6. 20 0
      src/Controllers/CompanyAuth/Transformers/ChannelTransformer.php
  7. 25 0
      src/Controllers/CompanyAuth/Transformers/CustomSendMsgsTransformers.php
  8. 31 0
      src/Controllers/CompanyAuth/Transformers/DelaySendMsgsTransformers.php
  9. 22 0
      src/Controllers/CompanyAuth/Transformers/OfficialAccountTransformer.php
  10. 27 0
      src/Controllers/CompanyAuth/Transformers/OrderDayStatsTransformer.php
  11. 69 0
      src/Controllers/CompanyAuth/Transformers/OrderTransformer.php
  12. 35 0
      src/Controllers/CompanyAuth/Transformers/SendOrderTransformer.php
  13. 27 0
      src/Controllers/CompanyAuth/Transformers/UserTransformer.php
  14. 117 0
      src/Helpers/CommonHelper.php
  15. 46 0
      src/Middleware/CompanyAuth.php
  16. 30 0
      src/Models/Activity/Activity.php
  17. 19 0
      src/Models/Activity/ActivitySwitch.php
  18. 36 0
      src/Models/Book/BookConfig.php
  19. 22 0
      src/Models/Book/Chapter.php
  20. 37 0
      src/Models/Channel/Channel.php
  21. 33 0
      src/Models/Channel/ChannelUser.php
  22. 23 0
      src/Models/ChargeReport/BaiDuAdAccount.php
  23. 16 0
      src/Models/Config/CompanyAuthConfig.php
  24. 39 0
      src/Models/OfficialAccount/CustomSendMsgs.php
  25. 32 0
      src/Models/OfficialAccount/ForceSubscribeDelayMsg.php
  26. 30 0
      src/Models/OfficialAccount/ForceSubscribeUsers.php
  27. 34 0
      src/Models/OfficialAccount/OfficialAccount.php
  28. 26 0
      src/Models/OfficialAccount/WechatKeywordMsgs.php
  29. 35 0
      src/Models/OfficialAccount/WechatTemplateMsgs.php
  30. 69 0
      src/Models/Order/Order.php
  31. 21 0
      src/Models/Order/Product.php
  32. 50 0
      src/Models/SendOrder/SendOrder.php
  33. 56 0
      src/Models/Statistic/OrderDayStats.php
  34. 18 0
      src/Models/Statistic/WapVisitStat.php
  35. 51 0
      src/Models/User/User.php
  36. 20 0
      src/Models/User/UserEvn.php
  37. 23 0
      src/Requests/ChargeReport/BaiDuAccountQueryRequest.php
  38. 25 0
      src/Requests/ChargeReport/BaiDuAccountRequest.php
  39. 24 0
      src/Requests/ChargeReport/DelBaiDuAccountRequest.php
  40. 21 0
      src/Requests/CompanyAuth/BookQueryRequest.php
  41. 34 0
      src/Requests/CompanyAuth/ChannelQueryRequest.php
  42. 36 0
      src/Requests/CompanyAuth/CustomSendMsgRequest.php
  43. 21 0
      src/Requests/CompanyAuth/SingleSendOrderRequest.php
  44. 30 0
      src/Requests/CompanyAuthRequest.php
  45. 86 0
      src/Requests/Request.php
  46. 32 0
      src/Requests/Rules/BidRule.php
  47. 160 0
      src/Services/Activity/ActivityService.php
  48. 62 0
      src/Services/BaseAuthConfig.php
  49. 36 0
      src/Services/BaseChannelEncode.php
  50. 31 0
      src/Services/Book/BookConfigService.php
  51. 20 0
      src/Services/Channel/ChannelService.php
  52. 60 0
      src/Services/ChargeReport/BaiDuAccountService.php
  53. 46 0
      src/Services/Config/ConfigService.php
  54. 196 0
      src/Services/OfficialAccount/OfficialAccountService.php
  55. 50 0
      src/Services/Order/OrderService.php
  56. 28 0
      src/Services/SendOrder/SendOrderService.php
  57. 179 0
      src/Services/SendOrder/SendOrderStatistic.php
  58. 31 0
      src/Services/User/UserService.php

+ 18 - 0
composer.json

@@ -0,0 +1,18 @@
+{
+    "name": "general/out_api",
+    "description": "公共对外输出接口",
+    "type": "library",
+    "authors": [
+        {
+            "name": "fly",
+            "email": "flyingstarsan.yu@gmail.com"
+        }
+    ],
+    "minimum-stability": "dev",
+    "require": {},
+    "autoload": {
+        "psr-4": {
+            "General\\": "src"
+        }
+    }
+}

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 998 - 0
src/Controllers/CompanyAuth/AppController.php


+ 230 - 0
src/Controllers/CompanyAuth/BaiDuAccountController.php

@@ -0,0 +1,230 @@
+<?php
+
+namespace General\Controllers\CompanyAuth;
+
+
+use App\Http\Controllers\Controller;
+use General\Controllers\CompanyAuth\Transformers\BaiDuAdAccountTransformer;
+use General\Requests\ChargeReport\BaiDuAccountQueryRequest;
+use General\Requests\ChargeReport\BaiDuAccountRequest;
+use General\Requests\ChargeReport\DelBaiDuAccountRequest;
+use General\Services\BaseAuthConfig;
+use General\Services\ChargeReport\BaiDuAccountService;
+
+/**
+ * 
+ */
+class BaiDuAccountController extends Controller
+{
+    /**
+     * @apiDefine BaiDuAdAccount 百度广告账号
+     */
+
+    use BaseAuthConfig;
+
+    private $service;
+
+    public function __construct()
+    {
+        $this->service = new BaiDuAccountService;
+    }
+
+    /**
+     * @api {post} company/auth/baiduAdAccount/add 添加百度广告账号
+     * @apiVersion 1.0.0
+     * @apiName addBaiDuAdAccount
+     * @apiGroup BaiDuAdAccount
+     * @apiParam {String} app_id 分配好的{app_id}
+     * @apiParam {String} nonce_str 随机字符串
+     * @apiParam {String} timestamp 时间戳
+     * @apiParam {String} sign 签名 规则同微信支付签名MD5(排序好的请求字符串&key=分配好的{app_secret})
+     * @apiParam {String} phone 手机号
+     * @apiParam {String} account_name 百度广告账号名称
+     * @apiParam {String} token 百度广告账号授权token
+     * @apiError {int}         code 状态码
+     * @apiError {String}      msg  信息
+     * @apiErrorExample {json} Error-Response:
+     * HTTP/1.1 200 OK
+     * [
+     *   {
+     *        'code' : 10030,
+     *        'msg' : '未授权!'
+     *   },
+     *   {
+     *        'code' : 10031,
+     *        'msg' : 'IP未授权!'
+     *   },
+     *   {
+     *        'code' : 10032,
+     *        'msg' : '授权时间已过期!'
+     *   },
+     *   {
+     *        'code' : 10033,
+     *        'msg' : '授权签名错误!'
+     *   },
+     *   {
+     *        'code' : 10034,
+     *        'msg' : '查询数据为空!'
+     *   },
+     *   {
+     *        'code' : 10035,
+     *        'msg' : '查询数据时间长度不能超过30天!'
+     *   },
+     *   {
+     *        'code' : 1002,
+     *        'msg' : '查询参数错误!'
+     *   },
+     * ]
+     * @apiSuccess {int}         code 状态码
+     * @apiSuccess {String}      msg  信息
+     * @apiSuccess {Object}      data 结果集
+     * @apiSuccess {Int}         id 账号ID
+     * @apiSuccessExample {json} Success-Response:
+     * HTTP/1.1 200 OK
+     *   {
+     *       "code": 0,
+     *       "msg": "",
+     *       "data": [
+     *           {
+     *               "id": 130,
+     *           }
+     *       ]
+     *   }
+     */
+    public function addBaiDuAdAccount(BaiDuAccountRequest $request)
+    {
+        $result = $this->service->addBaiduAdAccount($request->all());
+        return response()->success([
+            'id' => $result->id,
+        ]);
+    }
+
+    /**
+     * @api {post} company/auth/baiduAdAccount/del 删除百度广告账号
+     * @apiVersion 1.0.0
+     * @apiName delBaiDuAdAccount
+     * @apiGroup BaiDuAdAccount
+     * @apiParam {String} app_id 分配好的{app_id}
+     * @apiParam {String} nonce_str 随机字符串
+     * @apiParam {String} timestamp 时间戳
+     * @apiParam {String} sign 签名 规则同微信支付签名MD5(排序好的请求字符串&key=分配好的{app_secret})
+     * @apiParam {String} phone 手机号
+     * @apiParam {Int} id 账号ID
+     * @apiError {int}         code 状态码
+     * @apiError {String}      msg  信息
+     * @apiErrorExample {json} Error-Response:
+     * HTTP/1.1 200 OK
+     * [
+     *   {
+     *        'code' : 10030,
+     *        'msg' : '未授权!'
+     *   },
+     *   {
+     *        'code' : 10031,
+     *        'msg' : 'IP未授权!'
+     *   },
+     *   {
+     *        'code' : 10032,
+     *        'msg' : '授权时间已过期!'
+     *   },
+     *   {
+     *        'code' : 10033,
+     *        'msg' : '授权签名错误!'
+     *   },
+     *   {
+     *        'code' : 10034,
+     *        'msg' : '查询数据为空!'
+     *   },
+     *   {
+     *        'code' : 10035,
+     *        'msg' : '查询数据时间长度不能超过30天!'
+     *   },
+     *   {
+     *        'code' : 1002,
+     *        'msg' : '查询参数错误!'
+     *   },
+     * ]
+     * @apiSuccess {int}         code 状态码
+     * @apiSuccess {String}      msg  信息
+     * @apiSuccess {Object}      data 结果集
+     * @apiSuccess {Int}         id 账号ID
+     * @apiSuccessExample {json} Success-Response:
+     * HTTP/1.1 200 OK
+     *   {
+     *       "code": 0,
+     *       "msg": "",
+     *       "data": [
+     *       ]
+     *   }
+     */
+    public function delBaiDuAdAccount(DelBaiDuAccountRequest $request)
+    {
+        $this->service->delBaiduAdAccount($request->all());
+        return response()->success();
+    }
+
+    /**
+     * @api {post} company/auth/baiDuAdAccount 获取百度广告账号
+     * @apiVersion 1.0.0
+     * @apiName baiDuAdAccount
+     * @apiGroup BaiDuAdAccount
+     * @apiParam {String} app_id 分配好的{app_id}
+     * @apiParam {String} nonce_str 随机字符串
+     * @apiParam {String} timestamp 时间戳
+     * @apiParam {String} sign 签名 规则同微信支付签名MD5(排序好的请求字符串&key=分配好的{app_secret})
+     * @apiParam {String} phone 手机号
+     * @apiError {int}         code 状态码
+     * @apiError {String}      msg  信息
+     * @apiErrorExample {json} Error-Response:
+     * HTTP/1.1 200 OK
+     * [
+     *   {
+     *        'code' : 10030,
+     *        'msg' : '未授权!'
+     *   },
+     *   {
+     *        'code' : 10031,
+     *        'msg' : 'IP未授权!'
+     *   },
+     *   {
+     *        'code' : 10032,
+     *        'msg' : '授权时间已过期!'
+     *   },
+     *   {
+     *        'code' : 10033,
+     *        'msg' : '授权签名错误!'
+     *   },
+     *   {
+     *        'code' : 10034,
+     *        'msg' : '查询数据为空!'
+     *   },
+     *   {
+     *        'code' : 10035,
+     *        'msg' : '查询数据时间长度不能超过30天!'
+     *   },
+     *   {
+     *        'code' : 1002,
+     *        'msg' : '查询参数错误!'
+     *   },
+     * ]
+     * @apiSuccess {int}         code 状态码
+     * @apiSuccess {String}      msg  信息
+     * @apiSuccess {Object}      data 结果集
+     * @apiSuccess {Int}         id 账号ID
+     * @apiSuccess {String} account_name 百度广告账号名称
+     * @apiSuccess {String} token 百度广告账号授权token
+     * @apiSuccessExample {json} Success-Response:
+     * HTTP/1.1 200 OK
+     *   {
+     *       "code": 0,
+     *       "msg": "",
+     *       "data": [
+     *       ]
+     *   }
+     */
+    public function baiDuAdAccount(BaiDuAccountQueryRequest $request)
+    {
+        $result = $this->service->findBaiduAdAccounts($request->get('phone'));
+        return response()->success(collectionTransform(new BaiDuAdAccountTransformer, $result));
+    }
+}

+ 48 - 0
src/Controllers/CompanyAuth/Transformers/ActivityTransformer.php

@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * Created by PhpStorm.
+ * Date: 2017/3/31
+ * Time: 14:02
+ */
+
+namespace General\Controllers\CompanyAuth\Transformers;
+
+use General\Helpers\CommonHelper;
+use General\Models\Activity\ActivitySwitch;
+
+class ActivityTransformer
+{
+    public function transform($item)
+    {
+        return [
+            'id' => $item->id,
+            'name' => $item->name,
+            'activity_page' => CommonHelper::getActivityUrl($item->distribution_channel_id, $item->activity_page),
+            'created_at' => (string) $item->created_at,
+            'start_time' => (string)$item->start_time,
+            'end_time' => (string)$item->end_time,
+            'price' => $item->price,
+            'orderCount' => $item->orderCount,
+            'totalChargeAmount' => $item->totalChargeAmount,
+            'successOrderCount' => $item->successOrderCount,
+            'pageUserNum' => $item->pageUserNum,
+            'is_reader_page_show' => $this->isShowInPage($item->id, $item->distribution_channel_id),
+            'is_sign_message_show' => $this->isShowInPage($item->id, $item->distribution_channel_id, 'sign'),
+            'successrate' => $item->successrate,
+            'is_over' => $item->end_time < date('Y-m-d H:i:s')
+        ];
+    }
+
+    public function isShowInPage(int $activity_id, int $channel_id, $type = 'reader')
+    {
+        $info = ActivitySwitch::where('activity_id', $activity_id)->where('distribution_channel_id', $channel_id)->first();;
+        if ($type == 'reader') {
+            return $info->is_reader_page_show;
+        }
+        if ($type == 'sign') {
+            return $info->is_sign_message_show;
+        }
+        return 1;
+    }
+}

+ 21 - 0
src/Controllers/CompanyAuth/Transformers/BaiDuAdAccountTransformer.php

@@ -0,0 +1,21 @@
+<?php
+
+/**
+ * Created by PhpStorm.
+ * Date: 2017/3/31
+ * Time: 14:02
+ */
+
+namespace General\Controllers\CompanyAuth\Transformers;
+
+class BaiDuAdAccountTransformer
+{
+    public function transform($item)
+    {
+        return [
+            'id' => $item->id,
+            'account_name' => $item->account_name,
+            'token' => $item->token,
+        ];
+    }
+}

+ 20 - 0
src/Controllers/CompanyAuth/Transformers/ChannelTransformer.php

@@ -0,0 +1,20 @@
+<?php
+
+/**
+ * Created by PhpStorm.
+ * Date: 2017/3/31
+ * Time: 14:02
+ */
+namespace General\Controllers\CompanyAuth\Transformers;
+
+class ChannelTransformer
+{
+    public function transform($item)
+    {
+        return [
+            'id' => $item->id,
+            'name' => $item->nickname,
+            'created_at' => date('Y-m-d H:i:s', strtotime($item->created_at)),
+        ];
+    }
+}

+ 25 - 0
src/Controllers/CompanyAuth/Transformers/CustomSendMsgsTransformers.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace General\Controllers\CompanyAuth\Transformers;
+
+class CustomSendMsgsTransformers
+{
+    public function transform($item)
+    {
+        return [
+            'id'       =>  $item->id,
+            'appid'       =>  $item->appid,
+            'name'       =>  $item->name,
+            'user_num' => $item->user_num,
+            'send_time'       =>  $item->send_time,
+            'uv'       =>  isset($item->uv) ? $item->uv : 0,
+            'pv'       =>  isset($item->pv) ? $item->pv : 0,
+            'channel_id'       =>  $item->distribution_channel_id ? $item->distribution_channel_id : 0,
+            'pay_user_num'       =>  isset($item->pay_user_num) ? $item->pay_user_num : 0,
+            'charge_amount'       =>  isset($item->charge_amount) ? $item->charge_amount : 0,
+            'book_name'       =>  isset($item->book_name) ? $item->book_name : '',
+            'chapter_name'       =>  isset($item->chapter_name) ? $item->chapter_name : '',
+            'create_at' => $item->created_at->toDateTimeString()
+        ];
+    }
+}

+ 31 - 0
src/Controllers/CompanyAuth/Transformers/DelaySendMsgsTransformers.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace General\Controllers\CompanyAuth\Transformers;
+
+class DelaySendMsgsTransformers
+{
+    public function transform($item)
+    {
+        return [
+            'id' => $item->id,
+            'title' => $item->title,
+            'link' => $item->link,
+            'desc' => $item->desc,
+            'time_delay' => $item->time_delay,
+            'user_type' => $item->user_type,
+            'chapter_name' => $this->getLabel($item->chapter_name),
+            'book_name' => $this->getLabel($item->book_name),
+            'type' => $item->link_type,
+            'uv'       =>  isset($item->uv) ? $item->uv : 0,
+            'pv'       =>  isset($item->pv) ? $item->pv : 0,
+            'pay_user_num'       =>  isset($item->pay_user_num) ? $item->pay_user_num : 0,
+            'charge_amount'       =>  isset($item->charge_amount) ? $item->charge_amount : 0,
+        ];
+    }
+
+    public function getLabel(string $str)
+    {
+        $obj = json_decode($str);
+        return isset($obj->label) ? $obj->label : "";
+    }
+}

+ 22 - 0
src/Controllers/CompanyAuth/Transformers/OfficialAccountTransformer.php

@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * Created by PhpStorm.
+ * Date: 2017/3/31
+ * Time: 14:02
+ */
+namespace General\Controllers\CompanyAuth\Transformers;
+
+class OfficialAccountTransformer
+{
+    public function transform($item)
+    {
+        return [
+            'channel_id' => $item->distribution_channel_id,
+            'appid' => $item->appid,
+            'name' => $item->nickname,
+            'created_at' => date('Y-m-d H:i:s', strtotime($item->created_at)),
+            'sort_no' => $item->sort_no,
+        ];
+    }
+}

+ 27 - 0
src/Controllers/CompanyAuth/Transformers/OrderDayStatsTransformer.php

@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * Created by PhpStorm.
+ * Date: 2017/3/31
+ * Time: 14:02
+ */
+namespace General\Controllers\CompanyAuth\Transformers;
+
+class OrderDayStatsTransformer
+{
+    public function transform($item)
+    {
+        return [
+            'date' => $item->date,
+            'channel_id' => $item->distribution_channel_id,
+            'pay_number' => $item->pay_success_user_num,
+            'charge_amount' => $item->total_recharge_amount,
+            'first_pay_number' => $item->first_recharge_user_num,
+            'first_charge_amount' => $item->first_recharge_amount,
+            'read_uv' => $item->whole_site_uv,
+            'register_number' => $item->register_user_num,
+            'register_pay_number' => $item->reg_user_first_recharge_user_num,
+            'register_charge_amount' => $item->reg_user_first_recharge_amount
+        ];
+    }
+}

+ 69 - 0
src/Controllers/CompanyAuth/Transformers/OrderTransformer.php

@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * Created by PhpStorm.
+ * Date: 2017/3/31
+ * Time: 14:02
+ */
+
+namespace General\Controllers\CompanyAuth\Transformers;
+
+use App\Services\ChannelEncode;
+use General\Helpers\CommonHelper;
+use General\Models\OfficialAccount\WechatKeywordMsgs;
+use General\Models\Order\Order;
+use General\Models\SendOrder\SendOrder;
+
+class OrderTransformer
+{
+    public function transform($item)
+    {
+        return [
+            'uid' => $item->uid,
+            'price' => (float) $item->price,
+            'trade_no' => $item->trade_no,
+            'status' => $item->status,
+            'created_at' => (string)$item->created_at,
+            'pay_end_at' => $item->pay_end_at,
+            'send_order_id' => $item->send_order_id,
+            'send_order_name' => $item->send_order_name,
+            'order_type' => $this->getOrderType($item->order_type),
+            'activity_name' => ($item->pay_merchant_source == 'MONTH') ? '包月' : ($item->activity ? (string) $item->activity->name : ''),
+            'keyword' => $this->getKeyword($item),
+            'user_charge_times' => (isset($item->pay_type)  && $item->status == 'PAID') ? $item->pay_type : 0,
+            'bid' => CommonHelper::book_hash_encode($item->from_bid),
+            'register_time' => $item->user ? (string)$item->user->created_at : '',
+            'book_name' => $item->book ? $item->book->book_name : '',
+            'promotion_url' => $item->send_order ? CommonHelper::getPromotionUrl($item->send_order) : '',
+            'app_id' => $item->user && $item->user->force_subscribe_user ? $item->$item->user->force_subscribe_user->appid : '',
+            'opend_id' => $item->user && $item->user->force_subscribe_user ? $item->$item->user->force_subscribe_user->opend_id : '',
+            'subscribe_time' => $item->user && $item->user->force_subscribe_user ? $item->$item->user->force_subscribe_user->ubscribe_time : '',
+            'wechat_name' => $item->user && $item->user->force_subscribe_user && $item->user->force_subscribe_user->official_account ? $item->$item->user->force_subscribe_user->official_account->nickname : '',
+        ];
+    }
+
+    protected function getOrderType(string $type)
+    {
+        switch ($type) {
+            case 'RECHARGE':
+                return '普通充值';
+            case 'MONTH':
+                return '包月';
+            case 'QUARTER':
+                return '包季';
+            case 'YEAR':
+                return '包年';
+        }
+    }
+
+    protected function getKeyword(Order $order)
+    {
+        if ($order->from_type && starts_with($order->from_type, 'keyword')) {
+            $key_array = explode('_', $order->from_type);
+            if (isset($key_array[1]) && !empty($key_array[1])) {
+                $keyword_info = WechatKeywordMsgs::find($key_array[1]);
+                $order->keyword = sprintf('%s(%s)', $keyword_info->keyword, $keyword_info->book_name);
+            }
+        }
+    }
+}

+ 35 - 0
src/Controllers/CompanyAuth/Transformers/SendOrderTransformer.php

@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * Created by PhpStorm.
+ * Date: 2017/3/31
+ * Time: 14:02
+ */
+
+namespace General\Controllers\CompanyAuth\Transformers;
+
+use General\Helpers\CommonHelper;
+
+class SendOrderTransformer
+{
+    public function transform($item)
+    {
+        return [
+            'id' => $item->id,
+            'channel_id' => $item->distribution_channel_id,
+            'name' => $item->name,
+            'registerNum' => $item->registerNum,
+            'chapter_id' => $item->chapter_id,
+            'chapter_name' => $item->chapter_name,
+            'subscribe_chapter_name' => $item->subscribe_chapter_name,
+            'totalChargeAmount' => $item->totalChargeAmount,
+            'fansNum' => $item->fansNum,
+            'cost' => $item->cost,
+            'payUserNum' => $item->payUserNum,
+            'PV' => $item->clickNum,
+            'UV' => $item->clickNumUV,
+            'promotion_url' => CommonHelper::getPromotionUrl($item),
+            'created_at' => (string)$item->created_at
+        ];
+    }
+}

+ 27 - 0
src/Controllers/CompanyAuth/Transformers/UserTransformer.php

@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * Created by PhpStorm.
+ * Date: 2017/3/31
+ * Time: 14:02
+ */
+
+namespace General\Controllers\CompanyAuth\Transformers;
+
+class UserTransformer
+{
+    public function transform($item)
+    {
+        return [
+            'id' => $item->id,
+            'channel_id' => $item->distribution_channel_id,
+            'register_openid' => $item->register_openid,
+            'register_ip' => $item->register_ip,
+            'register_time' =>  (string)$item->created_at,
+            'ua' => $item->user_env ? $item->user_env->ua : '',
+            'app_id' => $item->force_subscribe_user ? $item->force_subscribe_user->appid : '',
+            'opend_id' => $item->force_subscribe_user ? $item->force_subscribe_user->openid : '',
+            'subscribe_time' => $item->force_subscribe_user ? (string)$item->force_subscribe_user->subscribe_time : '',
+        ];
+    }
+}

+ 117 - 0
src/Helpers/CommonHelper.php

@@ -0,0 +1,117 @@
+<?php
+
+namespace General\Helpers;
+
+use App\Services\ChannelEncode;
+use General\Models\SendOrder\SendOrder;
+use Illuminate\Log\Writer;
+use Monolog\Logger;
+use Vinkla\Hashids\Facades\Hashids;
+
+class CommonHelper
+{
+    /**
+     * 获取真实IP
+     */
+    public static function GetClientIp()
+    {
+        if (getenv('HTTP_X_FORWARDED_FOR')) {
+            $ip = getenv('HTTP_X_FORWARDED_FOR');
+        } else if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "unknown"))
+            $ip = getenv("HTTP_CLIENT_IP");
+        else if (getenv("HTTP_X_FORWARD_FOR") && strcasecmp(getenv("HTTP_X_FORWARD_FOR"), "unknown"))
+            $ip = getenv("HTTP_X_FORWARD_FOR");
+        else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "unknown"))
+            $ip = getenv("REMOTE_ADDR");
+        else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown"))
+            $ip = $_SERVER['REMOTE_ADDR'];
+        else
+            $ip = "unknown";
+        return ($ip);
+    }
+
+    /**
+     * 微信签名
+     */
+    public static function sign($params, $key)
+    {
+        $data = $params;
+        //签名步骤一:按字典序排序参数
+        ksort($data);
+        $buff = "";
+        foreach ($data as $k => $v) {
+            if ($v != null && $k !== "sign" && $v !== "" && !is_array($v)) {
+                $buff .= $k . "=" . $v . "&";
+            }
+        }
+        $buff = trim($buff, "&");
+        //签名步骤二:在string后加入KEY
+        $string = $buff . "&key=" . $key;
+        //签名步骤三:MD5加密
+        $string = md5($string);
+        //签名步骤四:所有字符转为大写
+        $result = strtoupper($string);
+        return $result;
+    }
+
+    /**
+     * 自定义日志
+     */
+    public static function myLog($name, $filename = '')
+    {
+        if (!$filename) {
+            $filename = $name;
+        }
+        $filename = $filename . '.log';
+        $logger   = new Logger(storage_path('logs/' . $filename));
+        $writer   = new Writer($logger);
+        $writer->useDailyFiles(storage_path('logs/' . $filename));
+        return $writer;
+    }
+
+    /**
+     * 获取推广链接
+     */
+    public static function getPromotionUrl(SendOrder $send_order): string
+    {
+        if ($send_order->promotion_point == 2) {
+            $domain = 'https://bsite';
+        } else {
+            $domain = 'https://site';
+        }
+        $service = new ChannelEncode;
+        return $domain . $service->encodeChannelId($send_order->distribution_channel_id) . '.' . env('PROMOTION_DOMAIN') . '/yun/' . $send_order->id;
+    }
+
+    /**
+     * bid 加密
+     */
+    public static function book_hash_encode($bid)
+    {
+        return Hashids::encode($bid);
+    }
+
+    /**
+     * bid 解密
+     */
+    public static function book_hash_decode($encrypt_bid)
+    {
+        $decode_infos = Hashids::decode($encrypt_bid);
+        return $decode_infos ? $decode_infos[0] : '';
+    }
+
+    /**
+     * 
+     */
+    public static function getActivityUrl(int $channel_id, string $path): string
+    {
+        return env('PROTOCOL') . '://site' . encodeZsyDistributionChannelId($channel_id) . '.' . env('CUSTOM_HOST') . '.com' . $path;
+    }
+
+    public static function isInnerSites(int $distribution_channel_id)
+    {
+        $site = redisEnv('INNER_SITE');
+        if (!$site) return false;
+        return in_array($distribution_channel_id, explode(',', $site));
+    }
+}

+ 46 - 0
src/Middleware/CompanyAuth.php

@@ -0,0 +1,46 @@
+<?php
+
+namespace General\Middleware;
+
+use App\Consts\SysConsts;
+use Closure;
+use General\Helpers\CommonHelper;
+use General\Requests\CompanyAuthRequest;
+use General\Services\BaseAuthConfig;
+use General\Services\Config\ConfigService;
+
+class CompanyAuth
+{
+    use BaseAuthConfig;
+    /**
+     * Handle an incoming request.
+     *
+     */
+    public function handle(CompanyAuthRequest $request, Closure $next)
+    {
+        $app_id = $request->get('app_id', '');
+        $service = new ConfigService;
+        $client_ip = CommonHelper::GetClientIp();
+        if (in_array($client_ip, $service->CompanyAuthIps($app_id))) {
+            $params = $request->except('_url');
+            $timestamp = (int) $params['timestamp'];
+            $diff = time() - $timestamp;
+            if ($diff < SysConsts::ONE_MINUTE_SECONDS * 60) {
+                $config = $service->findCompanyAuthConfig($params['app_id']);
+                if (isset($params['sign']) && strcasecmp(CommonHelper::sign($params, $config->app_secret), $params['sign']) == 0) {
+                    $this->setGlobalConfig($config);
+                    return $next($request);
+                } else {
+                    CommonHelper::myLog('test')->info(CommonHelper::sign($params, $config->app_secret));
+                    return response()->error('COMPANY_AUTH_SIGN_ERROR');
+                }
+            } else {
+                return response()->error('COMPANY_AUTH_EXPIRED');
+            }
+        } else {
+            return response()->error('COMPANY_AUTH_IP_NOT_EXISTS', [
+                'ip' => $client_ip
+            ]);
+        }
+    }
+}

+ 30 - 0
src/Models/Activity/Activity.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace General\Models\Activity;
+
+use General\Models\Order\Product;
+use Illuminate\Database\Eloquent\Model;
+
+class Activity extends Model
+{
+    protected $table = 'activity';
+    protected $fillable = [
+        'id',
+        'name',
+        'start_time',
+        'end_time',
+        'activity_page',
+        'product_id',
+        'token',
+        'default_template_id',
+        'customer_msg',
+        'distribution_channel_id',
+        'setting',
+        'type'
+    ];
+
+    protected function product()
+    {
+        return $this->hasOne(Product::class, 'id', 'product_id');
+    }
+}

+ 19 - 0
src/Models/Activity/ActivitySwitch.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace General\Models\Activity;
+
+use Illuminate\Database\Eloquent\Model;
+
+class ActivitySwitch extends Model
+{
+    protected $table = 'activity_show_switch';
+    protected $fillable = [
+        'id',
+        'activity_id',
+        'distribution_channel_id',
+        'is_reader_page_show',
+        'is_sign_message_show',
+        'created_at',
+        'updated_at'
+    ];
+}

+ 36 - 0
src/Models/Book/BookConfig.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace General\Models\Book;
+
+use Illuminate\Database\Eloquent\Model;
+
+class BookConfig extends Model
+{
+    protected $table = 'book_configs';
+    protected $fillable = [
+        'bid',
+        'force_subscribe_chapter_seq',
+        'price',
+        'cover',
+        'book_name',
+        'copyright',
+        'charge_type',
+        'hot',
+        'is_on_shelf',
+        'source_domain',
+        'recommend_index',
+        'roles',
+        'test_status',
+        'plan_push_user_num',
+        'test_update_time',
+        'is_show_index_content',
+        'click_count',
+        'promotion_domain',
+        'copyright_limit_data',
+        'recommend_cid',
+        'is_high_quality',
+        'vip_seq',
+        'editor_recommend',
+        'is_current_week_promotion'
+    ];
+}

+ 22 - 0
src/Models/Book/Chapter.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace General\Models\Book;
+
+use Illuminate\Database\Eloquent\Model;
+
+class Chapter extends Model
+{
+    protected $table = 'chapters';
+    protected $fillable = [
+        'bid',
+        'name',
+        'sequence',
+        'size',
+        'is_vip',
+        'prev_cid',
+        'next_cid',
+        'recent_update_at',
+        'content',
+        'ly_chapter_id',
+    ];
+}

+ 37 - 0
src/Models/Channel/Channel.php

@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * Created by PhpStorm.
+ * User: hp
+ * Date: 2017/11/21
+ * Time: 8:59
+ */
+
+namespace General\Models\Channel;
+
+use Illuminate\Database\Eloquent\Model;
+
+class Channel extends Model
+{
+    protected $table = 'distribution_channels';
+    protected $fillable = [
+        'id',
+        'name',
+        'pay_merchant_id',
+        'phone',
+        'nickname',
+        'person_in_charge_name',
+        'latest_login_time',
+        'remark',
+        'latest_login_ip',
+        'password',
+        'register_ip',
+        'is_enabled',
+        'distribution_manages_id',
+        'channel_user_id',
+        'site_nick_name',
+        'is_outer_site',
+        'is_old_user_site',
+        'is_yq_move'
+    ];
+}

+ 33 - 0
src/Models/Channel/ChannelUser.php

@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * Created by PhpStorm.
+ * User: hp
+ * Date: 2017/11/21
+ * Time: 8:59
+ */
+
+namespace General\Models\Channel;
+
+use Illuminate\Database\Eloquent\Model;
+
+class ChannelUser extends Model
+{
+    protected $table = 'channel_users';
+    protected $fillable = [
+        'name',
+        'pay_merchant_id',
+        'phone',
+        'nickname',
+        'person_in_charge_name',
+        'latest_login_time',
+        'remark',
+        'latest_login_ip',
+        'password',
+        'register_ip',
+        'is_enabled',
+        'distribution_manages_id',
+        'company_id',
+        'company_name'
+    ];
+}

+ 23 - 0
src/Models/ChargeReport/BaiDuAdAccount.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace General\Models\ChargeReport;
+
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * @property int $id
+ * @property string $account_name
+ * @property string $token
+ * @property int $channel_user_id
+ * @property int $is_enabled
+ */
+class BaiDuAdAccount extends Model
+{
+    protected  $table = 'baidu_ad_accounts';
+    protected  $fillable = [
+        'account_name',
+        'token',
+        'channel_user_id',
+        'is_enabled',
+    ];
+}

+ 16 - 0
src/Models/Config/CompanyAuthConfig.php

@@ -0,0 +1,16 @@
+<?php
+
+namespace General\Models\Config;
+
+use Illuminate\Database\Eloquent\Model;
+
+class CompanyAuthConfig extends Model
+{
+    protected $table = 'company_auth_configs';
+    protected $fillable = [
+        'app_id',
+        'app_secret',
+        'company_id',
+        'ip_list'
+    ];
+}

+ 39 - 0
src/Models/OfficialAccount/CustomSendMsgs.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace General\Models\OfficialAccount;
+
+use Illuminate\Database\Eloquent\Model;
+
+class CustomSendMsgs extends Model
+{
+    protected $tables = 'custom_send_msgs';
+
+    protected $fillable = [
+        'task_id',
+        'user_num',
+        'appid',
+        'name',
+        'send_time',
+        'content',
+        'redirect_url',
+        'status',
+        'distribution_channel_id',
+        'subscribe_time',
+        'sex',
+        'balance',
+        'order_type',
+        'category_id',
+        'del_flag',
+        'is_full_send',
+        'trusteeship',
+        'batch_no',
+        'batch_order_sn',
+        'is_show_list',
+        'description',
+        'custom_type',
+        'book_name',
+        'chapter_name',
+        'is_activity',
+        'subscribe_time_attach'
+    ];
+}

+ 32 - 0
src/Models/OfficialAccount/ForceSubscribeDelayMsg.php

@@ -0,0 +1,32 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: z-yang
+ * Date: 2020/2/6
+ * Time: 22:06
+ */
+
+namespace General\Models\OfficialAccount;
+
+use Illuminate\Database\Eloquent\Model;
+
+class ForceSubscribeDelayMsg extends Model
+{
+    protected $table = 'force_subscribe_delay_msg';
+
+    protected  $fillable = [
+        'id',
+        'distribution_channel_id',
+        'title',
+        'link',
+        'icon',
+        'desc',
+        'time_delay',
+        'is_enable',
+        'is_show',
+        'user_type',
+        'chapter_name',
+        'book_name',
+        'link_type'
+    ];
+}

+ 30 - 0
src/Models/OfficialAccount/ForceSubscribeUsers.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace General\Models\OfficialAccount;
+
+use Illuminate\Database\Eloquent\Model;
+
+
+class ForceSubscribeUsers extends Model
+{
+    protected $tables = 'force_subscribe_users';
+
+    protected $fillable = [
+        'uid',
+        'official_account_id',
+        'distribution_channel_id',
+        'appid',
+        'openid',
+        'is_subscribed',
+        'subscribe_time',
+        'unsubscribe_time',
+        'last_interactive_time',
+        'bid',
+        'send_order_id'
+    ];
+
+    protected function official_account()
+    {
+        return $this->hasOne(OfficialAccount::class, 'appid', 'appid');
+    }
+}

+ 34 - 0
src/Models/OfficialAccount/OfficialAccount.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace General\Models\OfficialAccount;
+
+use Illuminate\Database\Eloquent\Model;
+
+class OfficialAccount extends Model
+{
+    protected $tables = 'official_accounts';
+
+    protected $fillable = [
+        'distribution_channel_id',
+        'nickname',
+        'name',
+        'head_img',
+        'appid',
+        'appsecret',
+        'verify_txt',
+        'alias',
+        'qrcode_url',
+        'principal_name',
+        'service_type_info',
+        'func_info',
+        'authorizer_refresh_token',
+        'is_auth',
+        'cancel_auth_time',
+        'official_account_type',
+        'verify_type_info',
+        'subscribe_top_num',
+        'subscribe_day_maximum',
+        'sort_no',
+        'is_enabled'
+    ];
+}

+ 26 - 0
src/Models/OfficialAccount/WechatKeywordMsgs.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace General\Models\OfficialAccount;
+
+use Illuminate\Database\Eloquent\Model;
+
+class WechatKeywordMsgs extends Model
+{
+    protected $tables = 'wechat_keyword_msgs';
+    protected $fillable = [
+        'appids',
+        'keyword',
+        'distribution_channel_id',
+        'bid',
+        'cid',
+        'book_name',
+        'chapter_name',
+        'appid',
+        'status',
+        'send_title',
+        'send_cover',
+        'send_order_id',
+        'created_at',
+        'updated_at'
+    ];
+}

+ 35 - 0
src/Models/OfficialAccount/WechatTemplateMsgs.php

@@ -0,0 +1,35 @@
+<?php
+
+namespace General\Models\OfficialAccount;
+
+use Illuminate\Database\Eloquent\Model;
+
+class WechatTemplateMsgs extends Model
+{
+    protected $tables = 'wechat_template_msgs';
+
+    protected $fillable = [
+        'template_id',
+        'name',
+        'send_time',
+        'appid',
+        'template_content',
+        'redirect_url',
+        'status',
+        'remark',
+        'distribution_channel_id',
+        'subscribe_time',
+        'sex',
+        'balance',
+        'order_type',
+        'category_id',
+        'user_num',
+        'del_flag',
+        'is_full_send',
+        'is_show_list',
+        'description',
+        'book_name',
+        'chapter_name',
+        'is_activity'
+    ];
+}

+ 69 - 0
src/Models/Order/Order.php

@@ -0,0 +1,69 @@
+<?php
+
+namespace General\Models\Order;
+
+use DB;
+use General\Models\Activity\Activity;
+use General\Models\Book\BookConfig;
+use General\Models\SendOrder\SendOrder;
+use General\Models\User\User;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * @property Activity $activity
+ * @property User $user
+ * @property BookConfig $book_config
+ */
+class Order extends Model
+{
+    protected $table = 'orders';
+    protected $connection = 'mysql';
+    protected $fillable = [
+        'distribution_channel_id',
+        'uid',
+        'created_at',
+        'product_id',
+        'price',
+        'status',
+        'pay_type',
+        'trade_no',
+        'pay_merchant_id',
+        'servicer',
+        'transaction_id',
+        'pay_end_at',
+        'order_type',
+        'create_ip',
+        'send_order_id',
+        'send_order_name',
+        'activity_id',
+        'from_bid',
+        'from_type',
+    ];
+
+    public static function IndexRaw($index_raw)
+    {
+        $model = new static();
+        $model->setTable(DB::raw($model->getTable() . ' ' . $index_raw));
+        return $model;
+    }
+
+    protected function user()
+    {
+        return $this->hasOne(User::class, 'id', 'uid');
+    }
+
+    protected function book_config()
+    {
+        return $this->hasOne(BookConfig::class, 'bid', 'from_bid');
+    }
+
+    protected function activity()
+    {
+        return $this->hasOne(Activity::class, 'id', 'activity_id');
+    }
+
+    protected function send_order()
+    {
+        return $this->hasOne(SendOrder::class, 'send_order_id', 'id');
+    }
+}

+ 21 - 0
src/Models/Order/Product.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace General\Models\Order;
+
+use Illuminate\Database\Eloquent\Model;
+
+class Product extends Model
+{
+    protected $table = 'products';
+    protected $fillable = [
+        'template_id',
+        'price',
+        'type',
+        'given',
+        'is_default',
+        'is_enabled',
+        'sequence',
+        'template_type',
+        'switch_to',
+    ];
+}

+ 50 - 0
src/Models/SendOrder/SendOrder.php

@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * Created by PhpStorm.
+ * User: hp
+ * Date: 2017/11/22
+ * Time: 14:15
+ */
+
+namespace General\Models\SendOrder;
+
+use Illuminate\Database\Eloquent\Model;
+
+class SendOrder extends Model
+{
+    protected $table = 'send_orders';
+    protected $fillable = [
+        'name',
+        'channel_type',
+        'promotion_type',
+        'distribution_channel_id',
+        'book_id',
+        'book_name',
+        'chapter_id',
+        'chapter_name',
+        'headline_id',
+        'body_template_id',
+        'document_cover_id',
+        'original_guide_id',
+        'subscribe_chapter_id',
+        'import_company_name',
+        'fan_num',
+        'subscribe_chapter_name',
+        'qr_code_id',
+        'subscribe_chapter_seq',
+        'cost',
+        'sex_preference',
+        'is_enable',
+        'entrance',
+        'domain',
+        'remark',
+        'redirect_url',
+        'send_time',
+        'charge_type',
+        'pre_send_date',
+        'promotion_point',
+        'force_show_qrcode'
+    ];
+    protected $connection = 'mysql';
+}

+ 56 - 0
src/Models/Statistic/OrderDayStats.php

@@ -0,0 +1,56 @@
+<?php
+
+namespace General\Models\Statistic;
+
+use Illuminate\Database\Eloquent\Model;
+
+class OrderDayStats extends Model
+{
+    protected $table = 'order_day_stats';
+    protected $fillable = [
+        'distribution_channel_id',
+        'date',
+        'pay_success_user_num',
+        'total_recharge_amount',
+        'unpaid_num',
+        'paid_num',
+        'promotion_total_uv',
+        'promotion_total_pv',
+        'force_user_num',
+        'ticket_recharge_user_num',
+        'ticket_recharge_paid_num',
+        'ticket_recharge_unpaid_num',
+        'ticket_recharge_amount',
+        'year_recharge_user_num',
+        'year_recharge_paid_num',
+        'year_recharge_unpaid_num',
+        'year_recharge_amount',
+        'created_at',
+        'updated_at',
+        'whole_site_uv',
+        'whole_site_pv',
+        'auto_force_sub_num',
+        'self_force_sub_num',
+        'subscribe_user_num',
+        'subscribe_amount',
+        'send_order_num',
+        'real_send_order_num',
+        'register_user_num',
+        'first_recharge_user_num',
+        'first_recharge_amount',
+        'distribution_channel_name',
+        'month',
+        'sign_num',
+        'reg_user_first_recharge_amount',
+        'reg_user_first_recharge_user_num',
+        'fee',
+        'charge_balance',
+        'reward_balance',
+        'real_register_user_num',
+        'channel_merchant_recharge_amount',
+        'channel_user_id',
+        'old_user_subscribe_num',
+        'male_channel_recharge',
+        'female_channel_recharge',
+    ];
+}

+ 18 - 0
src/Models/Statistic/WapVisitStat.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace General\Models\Statistic;
+
+use Illuminate\Database\Eloquent\Model;
+
+class WapVisitStat extends Model
+{
+    protected $table = 'wap_visit_stats';
+    protected $fillable = [
+        'day',
+        'key',
+        'from_type',
+        'pv',
+        'uv',
+        'type'
+    ];
+}

+ 51 - 0
src/Models/User/User.php

@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * Created by PhpStorm.
+ * User: hp
+ * Date: 2017/11/21
+ * Time: 10:42
+ */
+
+namespace General\Models\User;
+
+use General\Models\OfficialAccount\ForceSubscribeUsers;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * @property ForceSubscribeUsers $force_subscribe_user
+ */
+class User extends Model
+{
+    protected $table = 'users';
+
+    protected $fillable =
+    [
+        'id',
+        'openid',
+        'unionid',
+        'distribution_channel_id',
+        'head_img',
+        'register_ip',
+        'send_order_id',
+        'balance',
+        'sex',
+        'country',
+        'city',
+        'province',
+        'nickname',
+        'charge_balance',
+        'reward_balance',
+        'is_new'
+    ];
+
+    protected function force_subscribe_user()
+    {
+        return $this->hasOne(ForceSubscribeUsers::class, 'uid', 'id');
+    }
+
+    protected function user_env()
+    {
+        return $this->hasOne(UserEvn::class, 'uid', 'id');
+    }
+}

+ 20 - 0
src/Models/User/UserEvn.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace General\Models\User;
+
+use Illuminate\Database\Eloquent\Model;
+
+class UserEvn extends Model
+{
+    protected $table = 'user_envs';
+
+    protected $fillable =
+    [
+        'uid',
+        'ua',
+        'm',
+        'model',
+        'sys',
+        'is_done',
+    ];
+}

+ 23 - 0
src/Requests/ChargeReport/BaiDuAccountQueryRequest.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace General\Requests\ChargeReport;
+
+use General\Services\BaseAuthConfig;
+use General\Requests\Request;
+use Illuminate\Validation\Rule;
+
+class BaiDuAccountQueryRequest extends Request
+{
+    use BaseAuthConfig;
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        return [
+            'phone' => ['required', 'string', Rule::in($this->phones)],
+        ];
+    }
+}

+ 25 - 0
src/Requests/ChargeReport/BaiDuAccountRequest.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace General\Requests\ChargeReport;
+
+use General\Requests\Request;
+use General\Services\BaseAuthConfig;
+use Illuminate\Validation\Rule;
+
+class BaiDuAccountRequest extends Request
+{
+    use BaseAuthConfig;
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        return [
+            'phone' => ['required', 'string', Rule::in($this->phones)],
+            'account_name' => 'required|string',
+            'token' => 'required|string',
+        ];
+    }
+}

+ 24 - 0
src/Requests/ChargeReport/DelBaiDuAccountRequest.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace General\Requests\ChargeReport;
+
+use General\Requests\Request;
+use General\Services\BaseAuthConfig;
+use Illuminate\Validation\Rule;
+
+class DelBaiDuAccountRequest extends Request
+{
+    use BaseAuthConfig;
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        return [
+            'phone' => ['required', 'string', Rule::in($this->phones)],
+            'id' => 'required|integer',
+        ];
+    }
+}

+ 21 - 0
src/Requests/CompanyAuth/BookQueryRequest.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace General\Requests\CompanyAuth;
+
+use General\Requests\Request;
+use General\Requests\Rules\BidRule;
+
+class BookQueryRequest extends Request
+{
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        return [
+            'bid' => ['required', 'string', new BidRule],
+        ];
+    }
+}

+ 34 - 0
src/Requests/CompanyAuth/ChannelQueryRequest.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace General\Requests\CompanyAuth;
+
+use General\Requests\Request;
+use General\Services\BaseAuthConfig;
+use Illuminate\Validation\Rule;
+
+class ChannelQueryRequest extends Request
+{
+    use BaseAuthConfig;
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        return [
+            'channel_id' => ['required', 'integer', Rule::in($this->channel_ids)],
+            'start_time' => 'date',
+            'end_time' => 'date|after_or_equal:start_time',
+            'begin_date' => 'date',
+            'end_date' => 'date|after_or_equal:begin_date',
+        ];
+    }
+
+    public function messages()
+    {
+        return [
+            'channel_id.in' => '站点未授权!'
+        ];
+    }
+}

+ 36 - 0
src/Requests/CompanyAuth/CustomSendMsgRequest.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace General\Requests\CompanyAuth;
+
+use General\Requests\Request;
+use General\Services\BaseAuthConfig;
+use Illuminate\Validation\Rule;
+
+class CustomSendMsgRequest extends Request
+{
+    use BaseAuthConfig;
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        return [
+            'start_time' => 'date',
+            'end_time' => 'date|after_or_equal:start_time',
+            'send_start_time' => 'date',
+            'send_end_time' => 'date|after_or_equal:send_start_time',
+            'book_name' => 'string',
+            'name' => 'string',
+            'channel_id' => ['required', 'integer', Rule::in($this->channel_ids)],
+        ];
+    }
+
+    public function messages()
+    {
+        return [
+            'channel_id.in' => '站点未授权!'
+        ];
+    }
+}

+ 21 - 0
src/Requests/CompanyAuth/SingleSendOrderRequest.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace General\Requests\CompanyAuth;
+
+use General\Requests\Request;
+
+class SingleSendOrderRequest extends Request
+{
+    use BaseAuthConfig;
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        return [
+            'send_order_id' => 'required|integer',
+        ];
+    }
+}

+ 30 - 0
src/Requests/CompanyAuthRequest.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace General\Requests;
+
+
+class CompanyAuthRequest extends Request
+{
+    use BaseAuthConfig;
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        return [
+            'app_id' => 'required|string|exists:company_auth_configs',
+            'nonce_str' => 'required|string',
+            'timestamp' => 'required|string',
+            'sign' => 'required|string',
+        ];
+    }
+
+    public function messages()
+    {
+        return [
+            'app_id.exists' => '未授权!',
+        ];
+    }
+}

+ 86 - 0
src/Requests/Request.php

@@ -0,0 +1,86 @@
+<?php
+
+namespace General\Requests;
+
+use Illuminate\Contracts\Validation\Validator;
+use Illuminate\Foundation\Http\FormRequest;
+use Illuminate\Http\Exceptions\HttpResponseException;
+
+abstract class Request extends FormRequest
+{
+    public function authorize()
+    {
+        return true;
+    }
+
+    public function failedValidation(Validator $validator)
+    {
+        throw (new HttpResponseException(response()->json([
+            'code' => -1,
+            'msg' => $validator->errors()->first(),
+            'data' => $validator->errors()->first(),
+        ], 200)));
+    }
+
+    public function messages()
+    {
+        return [
+            'required' => '缺少参数:attribute',
+            'integer' => ':attribute 必须是整数类型',
+            'date' => ':attribute 必须是日期格式',
+            'accepted' => 'The :attribute must be accepted.',
+            'active_url' => ':attribute 是个无效链接.',
+            'after' => 'The :attribute must be a date after :date.',
+            'after_or_equal' => 'The :attribute must be a date after or equal to :date.',
+            'alpha' => 'The :attribute may only contain letters.',
+            'alpha_dash' => 'The :attribute may only contain letters, numbers, dashes and underscores.',
+            'alpha_num' => 'The :attribute may only contain letters and numbers.',
+            'array' => 'The :attribute must be an array.',
+            'before' => 'The :attribute must be a date before :date.',
+            'before_or_equal' => 'The :attribute must be a date before or equal to :date.',
+            'between' => 'The :attribute 必须处于 :min 和 :max 之间',
+            'boolean' => 'The :attribute field must be true or false.',
+            'confirmed' => 'The :attribute confirmation does not match.',
+            'date_equals' => 'The :attribute must be a date equal to :date.',
+            'date_format' => 'The :attribute does not match the format :format.',
+            'different' => 'The :attribute and :other must be different.',
+            'digits' => 'The :attribute must be :digits digits.',
+            'digits_between' => 'The :attribute must be between :min and :max digits.',
+            'dimensions' => 'The :attribute has invalid image dimensions.',
+            'distinct' => 'The :attribute field has a duplicate value.',
+            'email' => 'The :attribute must be a valid email address.',
+            'ends_with' => 'The :attribute must end with one of the following: :values',
+            'exists' => ':attribute 不存在.',
+            'file' => 'The :attribute must be a file.',
+            'filled' => 'The :attribute field must have a value.',
+            'image' => 'The :attribute 必须是一张图片.',
+            'in' => '选项 :attribute 不在给定范围中.',
+            'in_array' => 'The :attribute field does not exist in :other.',
+            'ip' => 'The :attribute must be a valid IP address.',
+            'ipv4' => 'The :attribute must be a valid IPv4 address.',
+            'ipv6' => 'The :attribute must be a valid IPv6 address.',
+            'json' => 'The :attribute must be a valid JSON string.',
+            'mimes' => 'The :attribute must be a file of type: :values.',
+            'mimetypes' => 'The :attribute must be a file of type: :values.',
+            'not_in' => 'The selected :attribute is invalid.',
+            'not_regex' => 'The :attribute format is invalid.',
+            'numeric' => 'The :attribute must be a number.',
+            'present' => 'The :attribute field must be present.',
+            'regex' => 'The :attribute format is invalid.',
+            'required_if' => 'The :attribute field is required when :other is :value.',
+            'required_unless' => 'The :attribute field is required unless :other is in :values.',
+            'required_with' => 'The :attribute field is required when :values is present.',
+            'required_with_all' => 'The :attribute field is required when :values are present.',
+            'required_without' => 'The :attribute field is required when :values is not present.',
+            'required_without_all' => 'The :attribute field is required when none of :values are present.',
+            'same' => 'The :attribute and :other must match.',
+            'starts_with' => 'The :attribute must start with one of the following: :values',
+            'string' => 'The :attribute must be a string.',
+            'timezone' => 'The :attribute must be a valid zone.',
+            'unique' => 'The :attribute has already been taken.',
+            'uploaded' => 'The :attribute failed to upload.',
+            'url' => 'The :attribute format is invalid.',
+            'uuid' => 'The :attribute must be a valid UUID.',
+        ];
+    }
+}

+ 32 - 0
src/Requests/Rules/BidRule.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace General\Requests\Rules;
+
+use General\Helpers\CommonHelper;
+use Illuminate\Contracts\Validation\Rule;
+
+class BidRule implements Rule
+{
+    /**
+     * Determine if the validation rule passes.
+     *
+     * @param  string  $attribute
+     * @param  mixed  $value
+     * @return bool
+     */
+    public function passes($attribute, $value)
+    {
+        $bid = CommonHelper::book_hash_decode($value);
+        return strlen($bid) > 0 ? true : false;
+    }
+
+    /**
+     * Get the validation error message.
+     *
+     * @return string
+     */
+    public function message()
+    {
+        return "错误的书号!";
+    }
+}

+ 160 - 0
src/Services/Activity/ActivityService.php

@@ -0,0 +1,160 @@
+<?php
+
+namespace General\Services\Activity;
+
+use General\Helpers\CommonHelper;
+use General\Models\Activity\Activity;
+use General\Models\Order\Order;
+use General\Models\Order\Product;
+use Illuminate\Support\Facades\DB;
+use Redis;
+
+class ActivityService
+{
+    public function getCommonActivitiesWithStats(int $channel_id, $is_all = false)
+    {
+        $search_obj = Activity::leftjoin('activity_statistic', function ($join) use ($channel_id) {
+            $join->on('activity.id', '=', 'activity_statistic.activity_id')
+                ->where('activity_statistic.distribution_channel_id', '=', $channel_id);
+        })
+            ->select([
+                'activity.id', 'activity.name', 'activity.created_at', 'activity.start_time', 'activity.price_title',
+                'activity.end_time', 'activity.activity_page',
+                'activity_statistic.success_order_num', 'activity_statistic.recharge_amount',
+                'activity_statistic.order_num', 'activity_statistic.pv', 'promotion_stats_created', 'merchants_stats_created'
+            ])
+            ->where('token', '!=', '')->orderBy('activity.created_at', 'desc');
+        $is_inner = CommonHelper::isInnerSites($channel_id);
+        $create_types = $is_inner ? [1, 2] : [1, 3];
+        $search_obj->where(function ($query) use ($channel_id, $create_types) {
+            $query->whereIn('create_type', $create_types)
+                ->orWhere(function ($q) use ($channel_id) {
+                    $q->Where('create_type', 4)->where('activity.distribution_channel_id', $channel_id);
+                });
+        });
+        if ($is_all) {
+            $activities = $search_obj->get();
+        } else {
+            $activities = $search_obj->paginate();
+        }
+        foreach ($activities as &$item) {
+            if ($item->promotion_stats_created || $item->merchants_stats_created) {
+                $item->totalChargeAmount = $item->recharge_amount ? $item->recharge_amount : 0;
+                $item->orderCount = $item->success_order_num ? $item->success_order_num : 0;
+            } else {
+                $order_info = Order::select(DB::raw('count(*) as order_count,sum(price) as total_charge_amount'))
+                    ->where([
+                        ['activity_id', '=', $item->id],
+                        ['status', '=', 'PAID'],
+                        ['distribution_channel_id', '=', $channel_id],
+                        ['created_at', '>=', $item->start_time]
+                    ])->first();
+                $item->totalChargeAmount = $order_info ? $order_info->total_charge_amount : 0;
+                $item->orderCount = $order_info ? $order_info->order_count : 0;
+            }
+            if ($item->price_title) {
+                $item->price = $item->price_title;
+            }
+        }
+        return $activities;
+    }
+
+    public function getChannelActivitiesWithStats(int $channel_id, $is_all = false)
+    {
+        $search_obj = Activity::leftjoin('activity_statistic', function ($join) use ($channel_id) {
+            $join->on('activity.id', '=', 'activity_statistic.activity_id');
+            $join->where('activity_statistic.distribution_channel_id', '=', $channel_id);
+        })
+            ->select([
+                'activity.id', 'activity.name', 'activity.created_at', 'activity.start_time', 'activity.price_title',
+                'activity.end_time', 'activity.activity_page', 'activity.setting',
+                'activity_statistic.success_order_num', 'activity_statistic.recharge_amount',
+                'activity_statistic.order_num', 'activity_statistic.pv', 'promotion_stats_created', 'merchants_stats_created'
+            ])->whereIn('create_type', [0, 5])->where('activity.distribution_channel_id', $channel_id);
+        if ($is_all) {
+            $activities = $search_obj->get();
+        } else {
+            $activities = $search_obj->paginate();
+        }
+        foreach ($activities as &$item) {
+            if ($item->merchants_stats_created) {
+                $item->totalChargeAmount = $item->recharge_amount;
+                $item->orderCount = $item->order_num;
+                $item->successOrderCount = $item->success_order_num;
+                $item->pageUserNum =  $item->pv;
+            } else {
+                $stats = $this->getActivityUvPv($item->id, $channel_id);
+                $item->totalChargeAmount = $stats['order_sum'];
+                $item->orderCount = $stats['button_pv'];
+                $item->successOrderCount = $stats['order_num'];
+                $item->pageUserNum = $stats['page_uv'];
+            }
+            //价格
+            $activity_setting = $item->setting;
+            if ($activity_setting) {
+                $activity_setting_list = json_decode($activity_setting, true);
+                if (isset($activity_setting_list['product_info']) && count($activity_setting_list['product_info']) > 1) {
+                    $second_product_id = $activity_setting_list['product_info'][1]['product_id'];
+                    $second_price_info = Product::find($second_product_id);
+                    $item->price = sprintf('%s、 %s', $item->product->price, $second_price_info->price);
+                }
+            }
+            $item->successrate = '0%';
+            if ($item->orderCount) {
+                $item->successrate = (string)round(($item->successOrderCount / (int)($item->orderCount)) * 100, 4) . '%';
+            }
+        }
+        return $activities;
+    }
+
+    /**
+     * 活动统计
+     * @param $activity_id
+     * @param $channel_id
+     * @return array
+     */
+    public function getActivityUvPv($activity_id, $channel_id)
+    {
+        $activity = Activity::find($activity_id);
+
+        $uv_key_format = 'activity:%s:distribution_channel_id:%s:date:%s:uv';
+        $pv_key_format = 'activity:%s:distribution_channel_id:%s:pv';
+
+        $start = strtotime($activity->start_time);
+        $end_time = strtotime($activity->end_time);
+        $end = time() > $end_time ? $end_time : time();
+        $page_pv = 0;
+        $page_uv = 0;
+        $visit_info = $this->getActivityUvAndPv($channel_id, $activity_id);
+        $page_pv = $visit_info['pv'];
+        $page_uv = $visit_info['uv'];
+        $order_info = Order::select(DB::raw("count(distinct uid) as user_num,count(1) as order_num"))->where('activity_id', $activity_id)->where('created_at', '>=', $activity->start_time)->where('distribution_channel_id', $channel_id)->first();
+        $button_uv = (int)$order_info->user_num;
+        $button_pv = (int)$order_info->order_num;
+        $paid_info = Order::select(DB::raw("sum(price) as recharge_amount,count(1) as order_num"))->where('activity_id', $activity_id)->where('status', 'PAID')->where('created_at', '>=', $activity->start_time)->where('distribution_channel_id', $channel_id)->first();
+        $order_num = (int)$paid_info->order_num;
+        $order_sum = (float)$paid_info->recharge_amount;
+        return compact('page_pv', 'page_uv', 'button_pv', 'button_uv', 'order_num', 'order_sum');
+    }
+
+    /**
+     * 获取活动的pv uv
+     * @param int $channel_id
+     * @param int $activity_id
+     * @return array
+     */
+    public function getActivityUvAndPv(int $channel_id, int $activity_id): array
+    {
+        $day = date('Y-m-d');
+        $uv_key_format = 'activity:%s:distribution_channel_id:%s:date:%s:uv';
+        $pv_key_format = 'activity:%s:distribution_channel_id:%s:pv';
+        $sql_format = "select sum(pv) as pv,sum(uv) as uv from wap_visit_stats WHERE `key`=%s and from_type='%s' and `day` >= '2018-01-10' and type=2 ";
+        $sql = sprintf($sql_format, $channel_id, $activity_id);
+        $res = DB::select($sql);
+        $today_pv = (int)Redis::hget(sprintf($pv_key_format, $activity_id, $channel_id), $day);
+        $today_uv = (int)Redis::scard(sprintf($uv_key_format, $activity_id, $channel_id, $day));
+        $uv = $res[0]->uv + $today_uv;
+        $pv = $res[0]->pv + $today_pv;
+        return compact('uv', 'pv');
+    }
+}

+ 62 - 0
src/Services/BaseAuthConfig.php

@@ -0,0 +1,62 @@
+<?php
+
+namespace General\Services;
+
+use General\Models\Channel\Channel;
+use General\Models\Channel\ChannelUser;
+use General\Models\Config\CompanyAuthConfig;
+
+/**
+ * 基础授权配置信息
+ * @property-read string $app_id;
+ * @property-read CompanyAuthConfig $config 授权配置信息
+ * @property-read int $company_id 授权公司ID
+ * @property-read array $channel_user_ids 所有渠道用户id
+ * @property-read array $channel_ids 所有渠道id
+ * @property-read array $phones 所有渠道手机号
+ */
+trait BaseAuthConfig
+{
+    protected $fields = [];
+
+    public function __get($name)
+    {
+        if (!isset($this->fields[$name])) {
+            $config = $this->getGlobalConfig();
+            switch ($name) {
+                case 'app_id':
+                    $this->fields[$name] = $config->app_id;
+                    break;
+                case 'config':
+                    $this->fields[$name] = $config->config;
+                    break;
+                case 'company_id':
+                    $this->fields[$name] = $config->company_id;
+                    break;
+                case 'channel_user_ids':
+                    $this->fields[$name] = ChannelUser::where('company_id', $this->company_id)->pluck('id')->all();
+                    break;
+                case 'phones':
+                    $this->fields[$name] = ChannelUser::where('company_id', $this->company_id)->pluck('phone')->all();
+                    break;
+                case 'channel_ids':
+                    $this->fields[$name] = Channel::whereIn('channel_user_id', $this->channel_user_ids)->pluck('id')->all();
+                    break;
+            }
+        }
+        return $this->fields[$name];
+    }
+
+    public function setGlobalConfig(CompanyAuthConfig $config)
+    {
+        $company_config = app()->make('company_config');
+        $company_config->app_id = $config->app_id;
+        $company_config->config = $config->config;
+        $company_config->company_id = $config->company_id;
+    }
+
+    public function getGlobalConfig()
+    {
+        return app()->make('company_config');
+    }
+}

+ 36 - 0
src/Services/BaseChannelEncode.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace General\Services;
+
+use Hashids\Hashids;
+
+/**
+ * @property array $ingore_pools
+ * @property string $min_hash_length
+ * @property string $salt
+ * @property string $alphabet
+ */
+trait BaseChannelEncode
+{
+    protected $ingore_pools;
+    protected $min_hash_length;
+    protected $salt;
+    protected $alphabet;
+
+    private function judgeIsIngoreKeyAndGetField($id): string
+    {
+        return array_key_exists($id, $this->ingore_pools) ? $this->ingore_pools[$id] : '';
+    }
+
+    private function hashEncodeChannelId($id): string
+    {
+        $hashids = new Hashids($this->salt, $this->min_hash_length, $this->alphabet);
+        return $hashids->encode($id);
+    }
+
+    public function encodeChannelId($id)
+    {
+        $field = $this->judgeIsIngoreKeyAndGetField($id);
+        return $field ? $field : $this->hashEncodeChannelId($id);
+    }
+}

+ 31 - 0
src/Services/Book/BookConfigService.php

@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * Created by PhpStorm.
+ * User: tandunzhao
+ * Date: 2017/12/4
+ * Time: 下午1:43
+ */
+
+namespace General\Services\Book;
+
+use General\Models\Book\BookConfig;
+use General\Models\Book\Chapter;
+
+class BookConfigService
+{
+    /**
+     * 查找书籍免费章节
+     */
+    public static function findBookFreeChapters(int $bid)
+    {
+        $exists = BookConfig::where('is_on_shelf', 2)->where('id', $bid)->exists();
+        if ($exists) {
+            return Chapter::where('bid', $bid)->where('is_vip', 0)
+                ->select('id', 'name', 'next_cid', 'content')
+                ->orderBy('sequence')
+                ->get();
+        }
+        return [];
+    }
+}

+ 20 - 0
src/Services/Channel/ChannelService.php

@@ -0,0 +1,20 @@
+<?php
+
+/**
+ * Created by PhpStorm.
+ * User: tandunzhao
+ * Date: 2017/12/4
+ * Time: 下午1:43
+ */
+
+namespace General\Services\Channel;
+
+use General\Models\Channel\Channel;
+
+class ChannelService
+{
+    public function getChannelsByChannelUserIds(array $channel_user_ids)
+    {
+        return Channel::whereIn('channel_user_id', $channel_user_ids)->get();
+    }
+}

+ 60 - 0
src/Services/ChargeReport/BaiDuAccountService.php

@@ -0,0 +1,60 @@
+<?php
+
+namespace General\Services\ChargeReport;
+
+use General\Models\ChargeReport\BaiDuAdAccount;
+use General\Models\Channel\ChannelUser;
+
+class BaiDuAccountService
+{
+    private $report;
+
+    public function __construct()
+    {
+        $this->report = new NotifyReport;
+    }
+
+    private function findChannelUser(string $phone)
+    {
+        return ChannelUser::where('phone', $phone)->first();
+    }
+
+    public function addBaiduAdAccount(array $data): BaiDuAdAccount
+    {
+        $phone = $data['phone'];
+        $channel_user = $this->findChannelUser($phone);
+        $model = BaiDuAdAccount::create(
+            [
+                'account_name' => $data['account_name'],
+                'token' => $data['token'],
+                'channel_user_id' => $channel_user->id,
+                'is_enabled' => 1,
+            ]
+        );
+        $this->report->baiDuAdAccountReport($model);
+        return $model;
+    }
+
+    private function findBaiduAdAccount(int $id, string $phone): BaiDuAdAccount
+    {
+        $channel_user = $this->findChannelUser($phone);
+        return BaiDuAdAccount::where('id', $id)->where('channel_user_id', $channel_user->id)->first();
+    }
+
+    public function delBaiduAdAccount(array $data)
+    {
+        $phone = $data['phone'];
+        $model = $this->findBaiduAdAccount($data['id'], $phone);
+        if ($model) {
+            $model->is_enabled = 0;
+            $model->save();
+            $this->report->baiDuAdAccountReport($model);
+        }
+    }
+
+    public function findBaiduAdAccounts(string $phone)
+    {
+        $channel_user = $this->findChannelUser($phone);
+        return BaiDuAdAccount::where('is_enabled', 1)->where('channel_user_id', $channel_user->id)->get();
+    }
+}

+ 46 - 0
src/Services/Config/ConfigService.php

@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * Created by PhpStorm.
+ * User: tandunzhao
+ * Date: 2017/12/4
+ * Time: 下午1:43
+ */
+
+namespace General\Services\Config;
+
+use App\Consts\SysConsts;
+use General\Models\Config\CompanyAuthConfig;
+use Illuminate\Support\Facades\Redis;
+
+class ConfigService
+{
+    /**
+     * 授权信息
+     */
+    public function findCompanyAuthConfig(string $app_id)
+    {
+        return CompanyAuthConfig::where('app_id', $app_id)->first();
+    }
+
+    /**
+     * 授权ip列表
+     * @return array
+     */
+    public function CompanyAuthIps(string $app_id)
+    {
+        $key = 'company_auth_ips_' . $app_id;
+        if (Redis::exists($key)) {
+            $ips = Redis::get($key);
+        } else {
+            $config = $this->findCompanyAuthConfig($app_id);
+            if ($config) {
+                $ips = $config->ip_list;
+                Redis::setex($key, SysConsts::ONE_DAY_SECONDS, $ips);
+            } else {
+                return array();
+            }
+        }
+        return explode(';', $ips);
+    }
+}

+ 196 - 0
src/Services/OfficialAccount/OfficialAccountService.php

@@ -0,0 +1,196 @@
+<?php
+
+/**
+ * Created by PhpStorm.
+ * User: tandunzhao
+ * Date: 2017/12/4
+ * Time: 下午1:43
+ */
+
+namespace General\Services\OfficialAccount;
+
+use General\Models\OfficialAccount\CustomSendMsgs;
+use General\Models\OfficialAccount\ForceSubscribeDelayMsg;
+use General\Models\OfficialAccount\OfficialAccount;
+use General\Models\OfficialAccount\WechatTemplateMsgs;
+use General\Models\Order\Order;
+use General\Models\Statistic\WapVisitStat;
+use Illuminate\Support\Facades\DB;
+use Redis;
+
+class OfficialAccountService
+{
+    public function getOfficialAccountsByChannelIds(array $channel_ids)
+    {
+        return OfficialAccount::whereIn('distribution_channel_id', $channel_ids)->get();
+    }
+
+    /**
+     * 查询客服消息
+     */
+    public function findCustomSendMsgs(array $params, bool $is_all = false)
+    {
+        $res = CustomSendMsgs::where('distribution_channel_id', $params['channel_id'])
+            ->select('id', 'name', 'user_num', 'created_at', 'send_time', 'book_name', 'chapter_name', 'distribution_channel_id')
+            ->where('del_flag', 0)
+            ->where('is_show_list', 1);
+        //创建时间
+        if (isset($params['start_time']) && $params['start_time']) {
+            $res->where('created_at', '>=', $params['start_time']);
+        }
+        if (isset($params['end_time']) && $params['end_time']) {
+            $res->where('created_at', '<=', $params['end_time']);
+        }
+        //发送时间
+        if (isset($params['send_start_time']) && $params['send_start_time']) {
+            $res->where('send_time', '>=', $params['send_start_time']);
+        }
+        if (isset($params['send_end_time']) && $params['send_end_time']) {
+            $res->where('send_time', '<=', $params['send_end_time']);
+        }
+        if (isset($params['book_name']) && $params['book_name']) {
+            $res->where('book_name', 'like', $params['book_name'] . '%');
+        }
+        if (isset($params['name']) && $params['name']) {
+            $res->where('name', 'like', $params['task_name'] . '%');
+        }
+        if ($is_all) {
+            $custom_send_msgs = $res->orderBy('id', 'desc')->get();
+        } else {
+            $custom_send_msgs = $res->orderBy('id', 'desc')->paginate();
+        }
+        return $this->setStatisticInfo($custom_send_msgs, 'custom_');
+    }
+
+    public function setStatisticInfo($data, string $left_str)
+    {
+        foreach ($data as $key => $item) {
+            $fromtype = $left_str . $item->id;
+            $statistics = $this->innerCustomerAllStats($fromtype);
+            $data[$key]->uv = isset($statistics['uv']) ? $statistics['uv'] : '';
+            $data[$key]->pv = isset($statistics['pv']) ? $statistics['pv'] : '';
+            $data[$key]->pay_user_num = isset($statistics['pay_user_num']) ? $statistics['pay_user_num'] : '';
+            $data[$key]->charge_amount = isset($statistics['charge_amount']) ? $statistics['charge_amount'] : '';
+        }
+        return $data;
+    }
+
+    /**
+     * 内部派单统计
+     * @param $from
+     * @return array
+     */
+    public function innerCustomerAllStats($from)
+    {
+        $uv = Redis::scard('push:inner_send_order_id:uv:' . $from);
+        $info = DB::table('wap_long_visit_stats')->where('stats_type', 'inner_send_order_id')->where('param', $from)
+            ->select(DB::raw('sum(pv) as pv,sum(uv) as uv'))->first();
+        $uv_db = 0;
+        $pv_db = 0;
+        if ($info) {
+            $pv_db = $info->pv;
+            $uv_db = $info->uv;
+        }
+        $pv = Redis::hget('push:inner_send_order_id:pv', $from) + $pv_db;
+        $order_info = $this->getInnerSendOrderStats($from);
+        $pay_user_num = 0;
+        $charge_amount = 0;
+        if ($uv_db) {
+            $uv = (int) $uv + $uv_db;
+        }
+        if ($order_info) {
+            $pay_user_num = $order_info->pay_user_num;
+            $charge_amount = $order_info->charge_amount;
+        }
+        return compact('uv', 'pv', 'pay_user_num', 'charge_amount');
+    }
+
+    public function getInnerSendOrderStats($inner_send_order_id)
+    {
+        return Order::where('inner_send_order_id', $inner_send_order_id)
+            ->select(
+                DB::raw('count(distinct uid) as pay_user_num'),
+                DB::raw('sum(price) as charge_amount')
+            )
+            ->where('status', 'PAID')
+            ->first();
+    }
+
+    /**
+     * 查询模板消息
+     */
+    public function findWechatTemplateMsgs($param, $is_all = false)
+    {
+        $res = WechatTemplateMsgs::where('distribution_channel_id', $param['channel_id'])
+            ->where('is_show_list', 1);
+        if (isset($param['is_delete']) && 1 == $param['is_delete']) {
+            $res->where('del_flag', 1);
+        } else {
+            $res->where('del_flag', 0);
+        }
+
+        if (isset($param['start_time']) && $param['start_time']) {
+            $res->where('created_at', '>=', $param['start_time']);
+        }
+        if (isset($param['end_time']) && $param['end_time']) {
+            $res->where('created_at', '<=', $param['end_time']);
+        }
+        if (isset($param['book_name']) && $param['book_name']) {
+            $res->where('book_name', 'like', '%' . $param['book_name'] . '%');
+        }
+        if (isset($param['task_name']) && $param['task_name']) {
+            $res->where('name', 'like', '%' . $param['task_name'] . '%');
+        }
+
+        if ($is_all) {
+            $wechat_template_msgs = $res->orderBy('id', 'desc')->get();
+        } else {
+            $wechat_template_msgs = $res->orderBy('id', 'desc')->paginate();
+        }
+        return $this->setStatisticInfo($wechat_template_msgs, 'template_');
+    }
+
+    /**
+     * 延时消息
+     */
+    public function findWechatDelayMsgs(array $param, $is_all = false)
+    {
+        $res = ForceSubscribeDelayMsg::where('distribution_channel_id', $param['channel_id'])
+            ->where('is_show', 1);
+        if ($is_all) {
+            $data = $res->orderBy('id', 'desc')->get();
+        } else {
+            $data = $res->orderBy('id', 'desc')->paginate();
+        }
+        foreach ($data as $key => $item) {
+            $fromtype = 'subscribe_delay_' . $item->id;
+            $statistics = $this->getSitePvAndUv($param['channel_id'], $fromtype);
+            $data[$key]->uv = isset($statistics['uv']) ? $statistics['uv'] : '';
+            $data[$key]->pv = isset($statistics['pv']) ? $statistics['pv'] : '';
+            $data[$key]->pay_user_num = isset($statistics['pay_user_num']) ? $statistics['pay_user_num'] : '';
+            $data[$key]->charge_amount = isset($statistics['charge_amount']) ? $statistics['charge_amount'] : '';
+        }
+        return $data;
+    }
+
+    /**
+     *获取site下的uv,pv
+     */
+    public function getSitePvAndUv(int $distribution_channel_id, string $from)
+    {
+        $res = WapVisitStat::where('key', $distribution_channel_id)
+            ->where('type', 1)
+            ->where('from_type', $from)
+            ->select(DB::raw('sum(uv) as uv'), DB::raw('sum(pv) as pv'))
+            ->get();
+        $temp = $res->first();
+        $pv = $temp->pv;
+        $uv = $temp->uv;
+        $charge_amount = (float)Redis::hget('push:all:paidamount', $from);
+        $pay_user_num = (int)Redis::scard('push:all:paidnum:from:' . $from);
+        $now = date('Y-m-d');
+        $pv += (int)Redis::hget('customer:push:click:distribution_channel_id:' . $distribution_channel_id . 'from:' . $from, $now);
+        $uv += (int)Redis::scard('push:distribution_channel_id:' . $distribution_channel_id . 'from:' . $from . ':date:' . $now);
+        return compact('uv', 'pv', 'pay_user_num', 'charge_amount');
+    }
+}

+ 50 - 0
src/Services/Order/OrderService.php

@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * Created by PhpStorm.
+ * User: hp
+ * Date: 2017/11/21
+ * Time: 10:42
+ */
+
+namespace General\Services\Order;
+
+use General\Models\Order\Order;
+use General\Models\Statistic\OrderDayStats;
+
+class OrderService
+{
+    /**
+     * 三方授权订单数据
+     */
+    public function companyAuthOrders(array $params)
+    {
+        return Order::IndexRaw('use index (rds_idx_0)')
+            ->where('created_at', '>=', $params['begin_date'])
+            ->where('created_at', '<=', $params['end_date'])
+            ->where('distribution_channel_id', $params['channel_id'])
+            ->orderBy('id', 'desc')
+            ->paginate(100);
+    }
+
+    public function  companyAuthDayStatistic(array $params)
+    {
+        return OrderDayStats::select(
+            'distribution_channel_id',
+            'date',
+            'pay_success_user_num',
+            'total_recharge_amount',
+            'first_recharge_user_num',
+            'first_recharge_amount',
+            'whole_site_uv',
+            'register_user_num',
+            'reg_user_first_recharge_user_num',
+            'reg_user_first_recharge_amount'
+        )
+            ->where('date', '>=', $params['begin_date'])
+            ->where('date', '<=', $params['end_date'])
+            ->where('distribution_channel_id', $params['channel_id'])
+            ->orderBy('date', 'desc')
+            ->paginate(100);
+    }
+}

+ 28 - 0
src/Services/SendOrder/SendOrderService.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace General\Services\SendOrder;
+
+use General\Models\SendOrder\SendOrder;
+
+class SendOrderService
+{
+    public function companyAuthSendOrders(array $params)
+    {
+        return SendOrder::where('created_at', '>=', $params['begin_date'])
+            ->where('created_at', '<=', $params['end_date'])
+            ->where('distribution_channel_id', $params['channel_id'])
+            ->orderBy('id', 'desc')
+            ->paginate(100);
+    }
+
+    /**
+     * 根据站点查找对应派单信息
+     */
+    public function findSendOrderByChannels(int $send_order_id, array $channel_ids)
+    {
+        return SendOrder::whereIn('distribution_channel_id', $channel_ids)
+            ->where('id', $send_order_id)
+            ->select('name', 'distribution_channel_id', 'book_id', 'book_name', 'chapter_id')
+            ->first();
+    }
+}

+ 179 - 0
src/Services/SendOrder/SendOrderStatistic.php

@@ -0,0 +1,179 @@
+<?php
+
+/**
+ * Created by PhpStorm.
+ * User: hp
+ * Date: 2017/12/2
+ * Time: 15:36
+ */
+
+namespace General\Services\SendOrder;
+
+use Redis;
+use General\Models\OfficialAccount\ForceSubscribeUsers;
+use General\Models\Order\Order;
+use General\Models\Statistic\WapVisitStat;
+use General\Models\User\User;
+use stdClass;
+
+/**
+ * 派单统计
+ * @method  uvPv(int send_order_id)
+ * @method  register(int send_order_id)
+ * @method  newFan(int send_order_id)
+ * @method  charge(int send_order_id)
+ * @method  todayUvPv(int send_order_id)
+ */
+class SendOrderStatistic
+{
+    protected $send_order_ids;
+
+    protected $book_infos;
+
+    protected $field = [];
+
+    public function __construct(array $send_order_ids)
+    {
+        $this->send_order_ids = $send_order_ids;
+    }
+
+    public function __get($name)
+    {
+        if (!isset($this->field[$name])) {
+            switch ($name) {
+                case 'todayUvPvs':
+                    $this->field[$name] = $this->getTodayUVPV();
+                    break;
+                case 'uvPvs':
+                    $this->field[$name] = $this->getUvAndPv();
+                    break;
+                case 'registers':
+                    $this->field[$name] = $this->getPromotionTotal();
+                    break;
+                case 'newFans':
+                    $this->field[$name] = $this->getNewFansNum();
+                    break;
+                case 'charges':
+                    $this->field[$name] = $this->getCharges();
+                    break;
+            }
+        }
+        return $this->field[$name];
+    }
+
+    public function __call($name, $arguments)
+    {
+        $property_name = $name . 's';
+        $send_order_id = $arguments[0];
+        return $this->$property_name->where('send_order_id', $send_order_id)->first();
+    }
+
+
+    /**
+     * 获取今日PV和UV
+     * @return \Illuminate\Support\Collection
+     */
+    public function getTodayUVPV()
+    {
+        return collect($this->send_order_ids)->map(function ($item) {
+            $obj = new stdClass;
+            $obj->send_order_id = $item;
+            $obj->today_pv = (int) Redis::hget('send_order_pv_' . $item, date('Y-m-d'));
+            $obj->today_uv = (int) Redis::hget('send_order_uv_' . $item, date('Y-m-d'));
+            return $obj;
+        });
+    }
+
+    /**
+     * 获取uv和pv
+     * @return \Illuminate\Support\Collection
+     */
+    public function getUvAndPv()
+    {
+        return WapVisitStat::whereIn('key', $this->send_order_ids)
+            ->where([
+                ['from_type', 'send_orders'],
+                ['type', 3],
+            ])->selectRaw('sum(pv) as pv,sum(uv) as uv,`key` as send_order_id')
+            ->groupBy('key')
+            ->get();
+    }
+
+    /**
+     * 获取派单直接充值数据
+     * @return \Illuminate\Support\Collection
+     */
+    public function getCharges()
+    {
+        $sql = Order::whereIn('send_order_id', $this->send_order_ids)
+            ->where('status', 'PAID')
+            ->selectRaw('count(distinct uid) as payUserNum,sum(price) as totalChargeAmount, send_order_id')
+            ->groupBy('send_order_id');
+        return $sql->get();
+    }
+
+
+    /**
+     * 获取推广用户数
+     * @return \Illuminate\Support\Collection
+     */
+    public function getPromotionTotal()
+    {
+        return User::whereIn('send_order_id', $this->send_order_ids)
+            ->selectRaw('count(*) as registerNum, send_order_id')
+            ->groupBy('send_order_id')
+            ->get();
+    }
+
+    /**
+     * 获取强关用户数
+     * @return \Illuminate\Support\Collection
+     */
+    public function getNewFansNum()
+    {
+        return ForceSubscribeUsers::whereIn('send_order_id', $this->send_order_ids)
+            ->selectRaw('count(*) as fansNum, send_order_id')
+            ->groupBy('send_order_id')
+            ->get();
+    }
+
+    /**
+     * 设置统计数据
+     */
+    protected function setStatisticData($item)
+    {
+        $todayUvPv = $this->todayUvPv($item->id);
+        $uvPv = $this->uvPv($item->id);
+        $item->clickNum += $uvPv ? $uvPv->pv + $todayUvPv->today_pv : $todayUvPv->today_pv;
+        $item->clickNumUV += $uvPv ? $uvPv->uv + $todayUvPv->today_uv : $todayUvPv->today_uv;
+        $charge = $this->charge($item->id);
+        $item->payUserNum += $charge ? $charge->payUserNum : 0;
+        $item->totalChargeAmount += $charge ? $charge->totalChargeAmount : 0;
+        $register = $this->register($item->id);
+        $item->registerNum += $register ? $register->registerNum : 0;
+        $newFan = $this->newFan($item->id);
+        $item->fansNum += $newFan ? $newFan->fansNum : 0;
+    }
+
+    /**
+     * 初始化数据
+     */
+    protected function setInitData($item)
+    {
+        $item->clickNum = 0;
+        $item->clickNumUV = 0;
+        $item->payUserNum = 0;
+        $item->totalChargeAmount = 0;
+        $item->registerNum = 0;
+        $item->fansNum = 0;
+    }
+
+    public function getDataList($datas)
+    {
+        foreach ($datas as $item) {
+            $this->setInitData($item);
+            $this->setStatisticData($item, $item->id);
+        }
+        return $datas;
+    }
+}

+ 31 - 0
src/Services/User/UserService.php

@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * Created by PhpStorm.
+ * User: hp
+ * Date: 2017/11/21
+ * Time: 10:42
+ */
+
+namespace General\Services\User;
+
+use General\Models\User\User;
+
+class UserService
+{
+    public function companyAuthUsers(int $channel_id, string $start_time = '', string $end_time = '', array $uids = [])
+    {
+        $sql = User::where('distribution_channel_id', $channel_id)
+            ->orderBy('id', 'desc');
+        if ($start_time) {
+            $sql->where('created_at', '>=', $start_time);
+        }
+        if ($end_time) {
+            $sql->where('created_at', '<=', $end_time);
+        }
+        if ($uids) {
+            $sql->whereIn('id', $uids);
+        }
+        return $sql->paginate(100);
+    }
+}