zz hace 4 años
padre
commit
4548eeb5a8

+ 107 - 0
app/Console/Commands/Report/ReportBooks.php

@@ -0,0 +1,107 @@
+<?php
+
+
+namespace App\Console\Commands\Report;
+
+
+use App\Modules\Book\Models\Book;
+use App\Modules\Book\Models\BookConfig;
+use GuzzleHttp\Client;
+use Illuminate\Console\Command;
+use Illuminate\Support\Facades\Redis;
+use Hashids;
+
+class ReportBooks extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'report:books';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = '上报书籍';
+
+    /**
+     * Execute the console command.
+     *
+     * @return mixed
+     */
+    public function handle()
+    {
+
+        $client = new Client(['timeout' => 10, 'verify' => false]);
+
+        // 获取书籍id
+        $offset_time = 30;//min
+        $is_full_push = true;
+        $bookConfigs = BookConfig::getBooksByOffsetTime($offset_time,$is_full_push);
+        $bids        = collect($bookConfigs)->pluck('bid')->all();
+        
+        \Log::info('report:books:bids:'.json_encode($bids));
+        \Log::info('report:books:bids_all_num:'.count($bids));
+
+        // 书籍列表
+        $books = Book::getBooksByIds($bids);
+        if ($books) {
+            $reportData = [
+                'platform' => 'wangduyun',
+                'list'     => []
+            ];
+
+            $num = 1;
+            foreach ($books as $book) {
+                $bid                  = getProp($book, 'id');
+                $book_config = BookConfig::getOneByBid($bid);
+                
+                $reportData['list'][] = [
+                    'bid'           => getProp($book, 'id'),
+                    'name'          => getProp($book_config, 'book_name'),
+                    'category_id'   => getProp($book, 'category_id'),
+                    'category_name' => getProp($book, 'category_name'),
+                    'shelf_time' => !empty(getProp($book_config, 'shelf_time'))?getProp($book_config, 'shelf_time'):'1970-01-01',
+                    'shelf_status' => getProp($book_config, 'is_on_shelf'),
+                    'hash_bid' => Hashids::encode($bid),
+                    'created_at' => date("Y-m-d H:i:s", strtotime(getProp($book_config, 'created_at'))),
+                    'updated_at' => date("Y-m-d H:i:s", strtotime(getProp($book_config, 'updated_at'))),
+                ];
+                
+//                 \Log::info('$reportData:'.$num);\Log::info($reportData);
+                // 循环推,兼容全量
+                if($num >=500){
+                    // 执行上报
+                    $client->post(env('REPORT_URI') . '/api/reportBooks', [
+                        'headers' => [
+                            'x-code' => 'Mvnx1Yr3O8i!TS5u'
+                        ],
+                        'json'    => $reportData
+                    ]);
+                    
+                    $num = 1;
+                    $reportData['list'] = [];
+                }
+                
+                $num++;
+                
+            }
+            
+            // 最后一波500内的推送
+            // 执行上报
+            $client->post(env('REPORT_URI') . '/api/reportBooks', [
+                'headers' => [
+                    'x-code' => 'Mvnx1Yr3O8i!TS5u'
+                ],
+                'json'    => $reportData
+            ]);
+            
+
+
+        }
+    }
+
+}

+ 71 - 0
app/Console/Commands/Report/ReportOrders.php

@@ -0,0 +1,71 @@
+<?php
+
+
+namespace App\Console\Commands\Report;
+
+use App\Modules\Trade\Models\Order;
+use GuzzleHttp\Client;
+use Illuminate\Console\Command;
+use Illuminate\Support\Facades\Redis;
+
+class ReportOrders extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'report:orders';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = '上报成功订单';
+
+    /**
+     * Execute the console command.
+     *
+     * @return mixed
+     */
+    public function handle()
+    {
+        // 获取最新同步id
+        $key     = 'report:delivery:last:order:id';
+        $orderId = (int)Redis::get($key);
+        $client  = new Client(['timeout' => 10, 'verify' => false]);
+
+        // 获取订单
+        $orders = Order::getOrdersById($orderId);
+        if ($orders) {
+            $reportData = [
+                'platform' => 'wangduyun',
+                'list'     => []
+            ];
+
+            foreach ($orders as $order) {
+                $orderId              = getProp($order, 'id');
+                $reportData['list'][] = [
+                    'uid'        => getProp($order, 'uid'),
+                    'order_no'   => getProp($order, 'trade_no'),
+                    'price'      => getProp($order, 'price'),
+                    'channel_id' => getProp($order, 'distribution_channel_id'),
+                    'pay_time'   => getProp($order, 'pay_end_at'),
+                ];
+            }
+
+            // 执行上报
+            $client->post(env('REPORT_URI') . '/api/reportOrders', [
+                'headers' => [
+                    'x-code' => 'Mvnx1Yr3O8i!TS5u'
+                ],
+                'json'    => $reportData
+            ]);
+
+            // 更新uid
+            Redis::set($key, $orderId);
+        }
+    }
+
+}

+ 70 - 0
app/Console/Commands/Report/ReportUsers.php

@@ -0,0 +1,70 @@
+<?php
+
+
+namespace App\Console\Commands\Report;
+
+
+use GuzzleHttp\Client;
+use App\Modules\User\Models\User;
+use Illuminate\Console\Command;
+use Illuminate\Support\Facades\Redis;
+
+class ReportUsers extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'report:users';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = '上报注册用户';
+
+    /**
+     * Execute the console command.
+     *
+     * @return mixed
+     */
+    public function handle()
+    {
+        // 获取最新同步uid
+        $key    = 'report:delivery:last:uid';
+        $uid    = (int)Redis::get($key);
+        $client = new Client(['timeout' => 10, 'verify' => false]);
+
+        // 获取批量用户信息
+        $users = User::getUsersByUid($uid);
+        if ($users) {
+            $reportData = [
+                'platform' => 'wangduyun',
+                'list'     => []
+            ];
+
+            foreach ($users as $user) {
+                $uid                  = getProp($user, 'id');
+                $reportData['list'][] = [
+                    'uid'           => $uid,
+                    'channel_id'    => getProp($user, 'distribution_channel_id'),
+                    'register_time' => $user->created_at->format('Y-m-d H:i:s')
+                ];
+            }
+
+            // 执行上报
+            $client->post(env('REPORT_URI') . '/api/reportRegisters', [
+                'headers' => [
+                    'x-code' => 'Mvnx1Yr3O8i!TS5u'
+                ],
+                'json'    => $reportData
+            ]);
+
+            // 更新uid
+            Redis::set($key, $uid);
+        }
+    }
+
+}

+ 3 - 2
app/Console/Commands/Report/SyncOfficialAccounts.php

@@ -5,7 +5,6 @@
  * Date: 2021/2/22
  * Time: 11:34
  */
-
 namespace App\Console\Commands\Report;
 
 use App\Modules\OfficialAccount\Models\OfficialAccount;
@@ -35,6 +34,7 @@ class SyncOfficialAccounts extends Command
      */
     public function handle()
     {
+
         // 获取所有公众号 'id','nickname','appid','distribution_channel_id' 只获取这4个
         $accounts = OfficialAccount::getAllOfficialAccountDB();
         $accounts = $accounts ? $accounts->toArray() : [];
@@ -61,7 +61,8 @@ class SyncOfficialAccounts extends Command
             }
 
             // 执行上报
-            $url = 'https://firetrack.wd.amanbook.com/api/syncOfficialAccounts';
+
+            $url = 'https://firetrack.zhuishuyun.com/api/syncOfficialAccounts';
             $client->post($url, [
                 'headers' => [
                     'x-code' => 'Mvnx1Yr3O8i!TS5u'

+ 258 - 0
app/Console/Commands/Temp/GenAMSXmlFile.php

@@ -0,0 +1,258 @@
+<?php
+
+namespace App\Console\Commands\Temp;
+
+use App\Modules\Book\Models\BookConfig;
+use Illuminate\Console\Command;
+use Hashids;
+use Matrix\Exception;
+use OSS\OssClient;
+use OSS\Core\OssException;
+use DB;
+
+class GenAMSXmlFile extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'gen_ams_xml_file';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = '腾讯商品库xml生成';
+
+    /**
+     * Create a new command instance.
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    private $emails = [
+        'lisy@zw88.net',
+//        'songdb@iqiyoo.com',
+       'zhoulj@iqiyoo.com',
+//        'zhaoy@zw88.net'
+    ];
+
+    /**
+     * Execute the console command.
+     *
+     * @return mixed
+     */
+    public function handle()
+    {
+        $this->genProductXml();
+
+    }
+
+    /**
+     * genProductXml
+     */
+    public function genProductXml()
+    {
+        //筛选出上架状态为2的书籍上传
+        $now          = date('Y-m-d H:i:s');
+        $gdt_new_bids = DB::table('gdt_new_books')->where('is_deleted', 0)->where('start_time', '<=', $now)->where('end_time', '>=', $now)->pluck('bid')->toArray();
+        $books        = BookConfig::join('books', 'book_configs.bid', '=', 'Books.id')
+            ->leftjoin('book_categories', 'book_categories.id', 'books.category_id')
+            ->leftjoin('chapters', 'books.last_cid', 'chapters.id')
+            ->select(
+                'books.intro',
+                'books.status',
+                'books.size',
+                'books.chapter_count',
+                'books.last_chapter',
+                'book_configs.book_name',
+                'book_configs.bid',
+                'book_configs.cover',
+                'book_configs.vip_seq',
+                'book_configs.cover',
+                'book_configs.is_on_shelf',
+                'book_categories.id as second_category_id',
+                'book_categories.pid as first_category_id',
+                'book_categories.channel_name as first_category_name',
+                'book_categories.category_name as second_category_name',
+                'chapters.recent_update_at as latest_renew_time',
+                'chapters.sequence as latest_renew_chapter'
+            )
+            //->where('book_configs.is_on_shelf','2')
+            ->where(function ($query) {
+                $query->where('book_configs.is_on_shelf', '2');
+//                     ->orWhereIn('book_configs.bid', []);//豁免名单
+            })
+            ->get();
+        $string       = <<<XML
+<?xml version='1.0' encoding='utf-8'?>
+<product_set>
+</product_set>
+XML;
+
+        $xml = new \SimpleXMLElement($string);
+
+        foreach ($books as $book) {
+            //在管理后台设置为新书的书籍标记成新书
+            $is_new_book = in_array($book->bid, $gdt_new_bids) ? '是' : '否';
+            $bid         = Hashids::encode($book->bid);
+            $data        =
+                array(
+                    'product_id'           => $bid,
+                    'product_name'         => $book->book_name,
+                    'first_category_id'    => $book->first_category_id,
+                    'second_category_id'   => $book->second_category_id,
+                    'first_category_name'  => $book->first_category_name,
+                    'second_category_name' => $book->second_category_name,
+                    'expiration_time'      => '2022-05-19 23:59:59',
+                    'target_url_mobile'    => 'https://site8y1vm7kwvv850opx.wd.amanbook.com/detail?id=' . $bid,
+                    'target_url_wechat'    => 'https://site8y1vm7kwvv850opx.wd.amanbook.com/detail?id=' . $bid,
+                    'description'          => $this->special_filter(htmlspecialchars($book->intro)),
+                    'image_url'            => $book->cover,
+                    'word_count'           => $book->size,
+                    'serial_status'        => $book->status == 1 ? '完结' : '连载',
+                    'chapter_count'        => $book->chapter_count,
+                    'started_pay_chapter'  => $book->vip_seq,
+                    'latest_renew_time'    => $book->latest_renew_time,
+                    'latest_renew_chapter' => $book->latest_renew_chapter,
+                    'if_new_book'          => $is_new_book,
+                    'pay_status'           => '付费',
+                );
+            $item        = $xml->addChild('product');
+            if (is_array($data)) {
+                foreach ($data as $key => $row) {
+                    //生成子节点
+                    try {
+                        $node = $item->addChild($key, $row);
+
+                    } catch (\Exception $e) {
+                        $msg = "======腾讯商品库xml生成出错=====" . date("y-m-d H:i:s" . "\n");
+                        \Log::info($msg);
+                        \Log::info($e->getMessage());
+                        $notify = MessageNotify::mail([
+                            'to_emails'   => implode(",", $this->emails),
+                            'subject'     => $msg,
+                            'body'        => $e->getMessage(),
+                            'delay_times' => 0,
+                        ]);
+                        $notify->notify();
+                        exit();
+                    }
+
+                }
+            }
+        }
+        $file_path = 'storage/tx_product.xml';
+        echo $xml->asXML($file_path);
+
+        //上传到OSS
+        $ori_file    = DB::table('tencent_product_configs')->where('type', 'SITE_MAP_XML_URL')->first();
+        $verify_code = md5_file($file_path);
+        if ($ori_file && $ori_file->verify_code == $verify_code) {
+            \Log::info("======腾讯商品库xml已是最新=====" . date("y-m-d H:i:s" . "\n"));
+        } else {
+            $file_name = 'tx_product_wdy.xml';
+
+            //解析一遍看是否出错
+            try {
+                $load_xml = simplexml_load_file($file_path);
+
+            } catch (\Exception $e) {
+
+                $msg = "======腾讯商品库xml解析出错=====" . date("y-m-d H:i:s" . "\n");
+                \Log::info($msg);
+                \Log::info($e->getMessage());
+                $notify = MessageNotify::mail([
+                    'to_emails'   => implode(",", $this->emails),
+                    'subject'     => $msg,
+                    'body'        => $e->getMessage(),
+                    'delay_times' => 0,
+                ]);
+                $notify->notify();
+                //删除文件以防权限问题
+                if (file_exists($file_path)) unlink($file_path);
+                exit();
+            }
+            $url = $this->saveXmlToOss($file_name, $file_path);
+            DB::table('tencent_product_configs')
+                ->updateOrInsert(
+                    ['type' => 'SITE_MAP_XML_URL'],
+                    [
+                        'value'       => $url,
+                        'updated_at'  => date('Y-m-d H:i:s'),
+                        'verify_code' => $verify_code,
+                    ]
+                );
+        }
+        //上传到OSS后删除,防止权限问题
+        if (file_exists($file_path)) unlink($file_path);
+        \Log::info("======腾讯商品库xml生成=====" . date("y-m-d H:i:s" . "\n"));
+        return;
+
+
+    }
+
+
+    public function dealSpecialCharacters($char)
+    {
+        $char = preg_replace("[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]", '', $char);
+        $char = preg_replace("/&/", '&amp', $char);
+        $char = preg_replace("/'/", '&apos', $char);
+        $char = preg_replace("/\"/", '&quot', $char);
+        $char = preg_replace("/</", '&lt', $char);
+        $char = preg_replace("/>/", '&gt', $char);
+
+        return $char;
+    }
+
+    private function special_filter($string)
+    {
+        if (!$string) return '';
+
+        $new_string = '';
+        for ($i = 0; isset($string[$i]); $i++) {
+            $asc_code = ord($string[$i]);    //得到其asc码
+
+            // 以下代码旨在过滤非法字符
+            // ** 数值 8、9、10 和 13 可以分别转换为退格符、制表符、换行符和回车符。
+            // 这些字符都没有图形表示,但是对于不同的应用程序,这些字符可能会影响文本的显示效果。
+            if (in_array($asc_code, [8, 9, 10, 13], true)) {
+                $new_string .= '';
+            } else {
+                $new_string .= $string[$i];
+            }
+        }
+
+        return trim($new_string);
+    }
+
+    /**
+     * 将xml保存到oss
+     * @return string
+     */
+    function saveXmlToOss($file_name, $file)
+    {
+        $accessKeyId     = env('OSS_ACCESS_ID');
+        $accessKeySecret = env('OSS_ACCESS_KEY');
+        $endpoint        = env('OSS_END_POINT');
+        $bucket          = env('OSS_BUCKET');
+        try {
+            $ossClient  = new OssClient($accessKeyId, $accessKeySecret, $endpoint);
+            $upload_res = $ossClient->uploadFile($bucket, $file_name, $file);
+            \Log::info('saveXmlToOss:'.$bucket.' $file_name:'.$file_name.' $file:'.$file);
+            $url        = str_ireplace('wangduyun.oss-cn-hangzhou.aliyuncs.com', 'cdn-novel.wd.amanbook.com', $upload_res['oss-request-url']);
+            $url        = str_ireplace('http://', 'https://', $url);
+
+        } catch (OssException $e) {
+            \Log::info($e->getMessage());
+        }
+        return $url;
+    }
+
+}

+ 13 - 2
app/Console/Kernel.php

@@ -160,9 +160,13 @@ class Kernel extends ConsoleKernel
         // temp
         Commands\Temp\NewBookTestType::class,
         Commands\Temp\CheckCidError::class,
-        //同步服务号到fire
+        Commands\Temp\GenAMSXmlFile::class,
+        
+        //注册上报
+        Commands\Report\ReportUsers::class,
+        Commands\Report\ReportOrders::class,
+        Commands\Report\ReportBooks::class,
         Commands\Report\SyncOfficialAccounts::class,
-
     ];
 
     /**
@@ -188,6 +192,9 @@ class Kernel extends ConsoleKernel
 
         //每日商务渠道数据报表
         $schedule->command('BusinessChannelStat_task')->dailyAt("02:30");
+        
+        //腾讯商品库
+        $schedule->command('gen_ams_xml_file')->hourly()->between('6:00', '21:00');
 
         //点击率
         $schedule->command('book:clicknumupdate')->dailyAt('01:00');
@@ -402,5 +409,9 @@ class Kernel extends ConsoleKernel
 
         //同步服务号信息到fire
         $schedule->command('sync:official:accounts')->hourly();
+
+        // 同步书籍到精准投放后台
+        $schedule->command('report:books')->everyFiveMinutes();
+
     }
 }

+ 29 - 0
app/Http/Controllers/Outer/TencentAd/TencentProduct/TencentProductController.php

@@ -0,0 +1,29 @@
+<?php
+namespace App\Http\Controllers\Outer\TencentAd\TencentProduct;
+use Illuminate\Http\Request;
+use Illuminate\Routing\Controller;
+use DB;
+
+class TencentProductController extends Controller
+{
+    public function siteMapXml(Request $request)
+    {
+        $product_index_info = DB::
+        table('tencent_product_configs')
+            ->where('type','SITE_MAP_XML_URL')
+            ->first();
+        
+            \Log::info('siteMapXml:'.json_encode($product_index_info));
+         
+        $xml = <<<XML
+<?xml version='1.0' encoding='utf-8'?>
+<sitemapindex>
+    <sitemap>
+        <loc>{$product_index_info->value}</loc>
+        <lastmod>{$product_index_info->updated_at}</lastmod>
+    </sitemap>
+</sitemapindex>
+XML;
+        return response($xml,200)->header("Content-type","text/xml");
+    }
+}

+ 7 - 0
app/Http/Routes/Outer/GdtRoutes.php

@@ -0,0 +1,7 @@
+<?php
+
+Route::group(['domain'=>env('GDT_DOMAIN'),'namespace'=>'App\Http\Controllers\Outer\TencentAd\TencentProduct'],function(){
+    Route::get('tencent/siteMapXmlIndex','TencentProductController@siteMapXml');
+});
+
+

+ 11 - 0
app/Modules/Book/Models/Book.php

@@ -31,4 +31,15 @@ class Book extends Model
     	$res = self::select('*')->where('id',$bid)->first();
     	return $res;
     }
+    /**
+     * @param $bids
+     * @return mixed
+     */
+    public static function getBooksByIds($bids)
+    {
+        if (empty($bids)) {
+            return [];
+        }
+        return self::whereIn('id', $bids)->get();
+    }
 }

+ 30 - 0
app/Modules/Book/Models/BookConfig.php

@@ -1566,4 +1566,34 @@ class BookConfig extends Model
     {
         return self::select('bid')->where('book_name', 'like', '%' . $book_name . '%')->get();
     }
+    
+    
+    static function getBooksByBid($bid)
+    {
+        return self::where('id', '>', $bid)
+        ->where('is_on_shelf', 2)
+        ->where('test_status', 0)
+        ->orderBy('id', 'asc')->limit(500)->get();
+    }
+    
+    static function getOneByBid($bid)
+    {
+        return self::where('bid',  $bid)->first();
+    }
+    
+    static function getBooksByOffsetTime($offset_time=30,$is_full_push=false)
+    {
+        if($is_full_push){
+            return self::whereIn('is_on_shelf', [1,2])
+            ->orderBy('id', 'asc')->get();
+        }else{
+            $start_updated_time = date("Y-m-d H:i:s",time() - $offset_time*60);
+            return self::where('updated_at', '>=', $start_updated_time)
+            ->whereIn('is_on_shelf', [1,2])
+            ->orderBy('id', 'asc')->limit(500)->get();
+        }
+        
+    }
+    
+    
 }

+ 1 - 0
app/Modules/Order/Models/ReportUserBindRecord.php

@@ -10,6 +10,7 @@ class ReportUserBindRecord extends Model
     protected  $fillable = [
         'uid',
         'adid',
+        'aid_name',
         'platform',
         'link',
         'muid',

+ 18 - 0
app/Modules/Order/Services/OrderService.php

@@ -397,8 +397,26 @@ class OrderService
         ], $data);
     }
 
+    /**
+     * 匹配url选项
+     */
+    protected function matchItemInUrl(string $item, string $url)
+    {
+        preg_match('/&?' . $item . '=([^&\s]+)&?/i', $url, $arr);
+        return is_array($arr) && count($arr) >= 2 ? $arr[1] : '';
+    }
+
+    /**
+     * 获取链接上的广告名称
+     */
+    private function getAidName(string $link)
+    {
+        return $this->matchItemInUrl('aid_name', $link);
+    }
+
     public function saveReportUserRecord(array $data)
     {
+        $data['aid_name'] = $this->getAidName($data['link']);
         ReportUserBindRecord::updateOrCreate([
             'uid' => $data['uid'],
         ], $data);

+ 10 - 0
app/Providers/RouteServiceProvider.php

@@ -37,6 +37,7 @@ class RouteServiceProvider extends ServiceProvider
      */
     public function map(Router $router)
     {
+        $this->mapGdtRoutes($router);
         //         $this->mapFinanceRoutes($router);
         //         $this->mapBookRoutes($router);
         //         $this->mapUserRoutes($router);
@@ -62,6 +63,15 @@ class RouteServiceProvider extends ServiceProvider
         });
     }
 
+    protected function mapGdtRoutes(Router $router)
+    {
+        $router->group([
+            'middleware' => 'web',
+        ], function ($router) {
+            require app_path('Http/Routes/Outer/GdtRoutes.php');
+        });
+    }
+    
     protected function mapBookRoutes(Router $router)
     {
         $router->group([