Bladeren bron

解决冲突

zqwang 1 jaar geleden
bovenliggende
commit
6f964fb476
36 gewijzigde bestanden met toevoegingen van 1021 en 168 verwijderingen
  1. 62 0
      app/Console/Commands/Video/WechatCheckGetTask.php
  2. 35 0
      app/Jobs/Video/WechatCheck.php
  3. 11 0
      app/Libs/Helpers.php
  4. 7 1
      config/database.php
  5. 7 0
      config/queue.php
  6. 3 2
      modules/Callback/Http/Controllers/CallbackLogController.php
  7. 96 2
      modules/Callback/Http/Controllers/JuliangAccountController.php
  8. 1 0
      modules/Callback/routes/route.php
  9. 75 51
      modules/Channel/Services/Order/OrderService.php
  10. 6 2
      modules/Common/Errors/Errors.php
  11. 53 0
      modules/Common/Services/CommonConfigService.php
  12. 16 16
      modules/Common/config/common.php
  13. 2 1
      modules/Common/routes/route.php
  14. 48 0
      modules/Manage/Http/Controllers/MiniprogramController.php
  15. 5 4
      modules/Manage/Http/Controllers/PayConfigController.php
  16. 4 2
      modules/Manage/Http/Requests/MiniprogramUpdateRequest.php
  17. 2 2
      modules/Manage/Models/Miniprogram.php
  18. 31 0
      modules/Manage/Services/WechatMiniprogramService.php
  19. 7 2
      modules/Manage/config/miniprogram.php
  20. 44 5
      modules/Operation/Http/Controllers/FirstPageController.php
  21. 1 0
      modules/Operation/routes/route.php
  22. 1 1
      modules/OrderRefund/Models/OrdersRefundVerify.php
  23. 84 67
      modules/OrderRefund/Services/RefundOrderService.php
  24. 4 2
      modules/Tuiguang/Http/Controllers/PromotionController.php
  25. 2 2
      modules/Tuiguang/config/tuiguang.php
  26. 10 3
      modules/Video/Http/Controllers/VideoController.php
  27. 80 0
      modules/Video/Http/Controllers/VideoSeriesWechatCheckController.php
  28. 119 0
      modules/Video/Http/Controllers/WechatCheckController.php
  29. 103 0
      modules/Video/Services/WechatCheckSyncService.php
  30. 12 0
      modules/Video/routes/route.php
  31. 10 0
      tests/Callback/Http/Controllers/JuliangAccountControllerTest.php
  32. 17 0
      tests/Common/Services/CommonConfigServiceTest.php
  33. 2 2
      tests/UsedTestCase.php
  34. 2 1
      tests/Video/Http/Controllers/VideoControllerTest.php
  35. 22 0
      tests/Video/Http/Controllers/VideoSeriesWechatCheckControllerTest.php
  36. 37 0
      tests/Video/Http/Controllers/WechatCheckControllerTest.php

+ 62 - 0
app/Console/Commands/Video/WechatCheckGetTask.php

@@ -0,0 +1,62 @@
+<?php
+
+namespace App\Console\Commands\Video;
+
+use Illuminate\Console\Command;
+use Illuminate\Support\Facades\DB;
+use Modules\Video\Services\WechatCheckSyncService;
+
+class WechatCheckGetTask extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'Video:WechatCheckGetTask {--task_ids= : 英文逗号分割的任务id}';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = '查询短剧同步到微信的任务状态';
+
+    /**
+     * Execute the console command.
+     */
+    public function handle(): void
+    {
+        $task_ids = $this->option('task_ids');
+        $taskIdArr = null;
+        if($task_ids) {
+            $taskIdArr = explode(',', trim($task_ids, ','));
+        }
+        DB::table('video_series_wechat_check')
+            ->whereIn('sync_status', [1,2])
+            ->where('sync_task_id', '<>', '')
+            ->where('is_enabled', 1)
+            ->when($taskIdArr, function ($query, $taskIdArr) {
+                return $query->whereIn('task_id', $taskIdArr);
+            })->orderBy('id', 'asc')
+            ->chunk(100, function ($items) {
+                $now = date('Y-m-d H:i:s');
+                foreach ($items as $item) {
+                    $taskInfo = WechatCheckSyncService::getTask($item);
+                    if($taskInfo && 1 == $taskInfo['task_type']) {
+                        if(in_array($taskInfo['status'], [3,4])) {
+                            DB::table('video_series_wechat_check')
+                                ->where(['id' => $item->id])
+                                ->update([
+                                    'status' => $taskInfo['status'],
+                                    'remark' => $taskInfo['errmsg'] ?? '',
+                                    'media_id' => $taskInfo['media_id'] ?? '',
+                                    'updated_at' => $now,
+                                    'sync_task_info' => \json_encode($taskInfo),
+                                ]);
+                        }
+                    }
+                }
+            });
+    }
+}

+ 35 - 0
app/Jobs/Video/WechatCheck.php

@@ -0,0 +1,35 @@
+<?php
+
+namespace App\Jobs\Video;
+
+use Illuminate\Bus\Queueable;
+use Illuminate\Contracts\Queue\ShouldBeUnique;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Foundation\Bus\Dispatchable;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Queue\SerializesModels;
+
+/**
+ * 剧目提审,真实处理逻辑在 duanju_crontab_script 项目
+ */
+class WechatCheck implements ShouldQueue
+{
+    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+
+    private $info;
+    /**
+     * Create a new job instance.
+     */
+    public function __construct($info)
+    {
+        $this->info = $info;
+    }
+
+    /**
+     * Execute the job.
+     */
+    public function handle(): void
+    {
+        //
+    }
+}

+ 11 - 0
app/Libs/Helpers.php

@@ -3,6 +3,7 @@
 
 use Illuminate\Http\UploadedFile;
 use Illuminate\Support\Facades\DB;
+use Modules\Common\Support\Trace\TraceContext;
 use Modules\Common\Support\Upload\Uploader;
 use PhpOffice\PhpSpreadsheet\IOFactory;
 use PhpOffice\PhpSpreadsheet\Spreadsheet;
@@ -404,3 +405,13 @@ if (!function_exists('print_sql')) {
         });
     }
 }
+
+if(!function_exists('getTraceContext')) {
+
+    /**
+     * @return TraceContext
+     */
+    function getTraceContext() {
+        return app(TraceContext::class);
+    }
+}

+ 7 - 1
config/database.php

@@ -145,7 +145,13 @@ return [
             'port' => env('REDIS_PORT', '6379'),
             'database' => env('REDIS_CACHE_DB', '1'),
         ],
-
+        // 普通redis队列
+        'queue-redis' => [
+            'host' => env('COMMON_QUEUE_REDIS_HOST', 'localhost'),
+            'password' => env('COMMON_QUEUE_REDIS_PASSWORD', null),
+            'port' => env('COMMON_QUEUE_REDIS_PORT', 6379),
+            'database' => 2,
+        ],
     ],
 
 ];

+ 7 - 0
config/queue.php

@@ -71,6 +71,13 @@ return [
             'after_commit' => false,
         ],
 
+        'queue-redis' => [
+            'driver' => 'redis',
+            'connection' => 'queue-redis',
+            'queue' => 'default',
+            'expire' => 60,
+        ]
+
     ],
 
     /*

+ 3 - 2
modules/Callback/Http/Controllers/CallbackLogController.php

@@ -42,15 +42,16 @@ class CallbackLogController extends CatchController
             })->when($userRanseStartAtBeginTime, function ($query, $userRanseStartAtBeginTime){
                 return $query->where('user_ranse_start_at', '>=', $userRanseStartAtBeginTime);
             })->when($userRanseStartAtEndTime, function ($query, $userRanseStartAtEndTime){
-                return $query->where('user_ranse_start_at', '<=', $userRanseStartAtEndTime);
+                return $query->where('user_ranse_start_at', '<=', $userRanseStartAtEndTime . ' 23:59:59');
             })->when($orderCreatedAtBeginTime, function ($query, $orderCreatedAtBeginTime){
                 return $query->where('order_created_at', '>=', $orderCreatedAtBeginTime);
             })->when($miniprogramId, function ($query, $miniprogramId){
                 return $query->where('miniprogram_id', $miniprogramId);
             })
             ->when($orderCreatedAtEndTime, function ($query, $orderCreatedAtEndTime) {
-                return $query->where('order_created_at', '<=', $orderCreatedAtEndTime);
+                return $query->where('order_created_at', '<=', $orderCreatedAtEndTime. ' 23:59:59');
             })->orderBy('created_at', 'desc');
+   
         if($isExport) {
             $result = $sql->get();
         } else {

+ 96 - 2
modules/Callback/Http/Controllers/JuliangAccountController.php

@@ -18,15 +18,48 @@ class JuliangAccountController extends CatchController
     public function list(Request $request) {
         $advAccountId = $request->input('account_id');
         $advAccountName = $request->input('account_name');
+        $unBind = $request->input('unbind', 0);
+        $alreadyBindConfigIds = null;
+        if($unBind) {
+            $alreadyBindConfigIds = DB::table('promotions')
+                ->where([
+                    'uid' => $this->getOptimizerUid(),
+                    'callback_type' => 1,
+                    'status' => 1,
+                    'is_enabled' => 1,
+                ])->where('callback_config_id' , '<>', 0)
+                ->distinct()
+                ->select('callback_config_id')
+                ->get()->pluck('callback_config_id')->toArray();
+        }
 
-        return DB::table('juliang_account_callback_config')
+        $list =  DB::table('juliang_account_callback_config')
             ->where(['company_uid' => $this->getOptimizerUid()])
             ->when($advAccountId, function ($query, $advAccountId) {
                 return $query->where('adv_account_id' , $advAccountId);
             })->when($advAccountName, function ($query, $advAccountName) {
                 return $query->where('adv_account_name', 'like', '%'. $advAccountName. '%');
-            })->orderBy('id', 'desc')
+            })->when($alreadyBindConfigIds, function ($query, $alreadyBindConfigIds) {
+                return $query->whereNotIn('id', $alreadyBindConfigIds);
+            })
+            ->orderBy('id', 'desc')
             ->paginate($request->input('limit', 30));
+        $ids = collect($list->items())->pluck('id');
+        $promotions = DB::table('promotions')
+            ->where([
+                'uid' => $this->getOptimizerUid(),
+                'callback_type' => 1,
+                'status' => 1,
+                'is_enabled' => 1,
+            ])->whereIn('callback_config_id', $ids)
+            ->select('name', 'id', 'callback_config_id')
+            ->get()->keyBy('callback_config_id');
+        foreach ($list as $item) {
+            $item->promotion_name = $promotions->get($item->id)->name ?? '';
+            $item->promotion_id = $promotions->get($item->id)->id ?? '';
+        }
+
+        return $list;
     }
 
     public function addAccount(Request $request) {
@@ -270,4 +303,65 @@ class JuliangAccountController extends CatchController
 
         return 'ok';
     }
+
+    /**
+     * 解绑推广
+     * @param Request $request
+     */
+    public function unbindPromotion(Request $request) {
+        $this->validate($request, [
+            'id' => 'required'
+        ]);
+
+        $config = DB::table('juliang_account_callback_config')
+            ->where([
+                'id' => $request->input('id'),
+                'company_uid' => $this->getOptimizerUid(),
+            ])->first();
+
+        if(!$config) {
+            CommonBusinessException::throwError(Errors::JULIANG_ACCOUNT_CONFIG_NOT_EXISTS);
+        }
+        $now = date('Y-m-d H:i:s');
+        $affected = DB::table('promotions')
+            ->where([
+                'callback_type' => 1,
+                'callback_config_id' => $request->input('id'),
+                'is_enabled' => 1,
+                'status' => 1,
+            ])->update([
+                'status' => 0,
+                'updated_at' => $now,
+            ]);
+        if($affected) {
+            DB::table('juliang_account_rate_config_log')
+                ->where('company_uid', $this->getOptimizerUid())
+                ->where('account_id', $config->adv_account_id)
+                ->where('is_enabled', 1)
+                ->update(['is_enabled' => 0, 'updated_at' => $now]);
+            DB::table('juliang_account_promotion_protect_record')
+                ->where('optimizer_uid', $this->getOptimizerUid())
+                ->where('advertiser_id', $config->adv_account_id)
+                ->where('is_enabled', 1)
+                ->update(['is_enabled' => 0, 'updated_at' => $now]);
+            DB::table('juliang_account_rate_config_log')
+                ->insert([
+                    'company_uid' => $this->getOptimizerUid(),
+                    'account_id' => $config->adv_account_id,
+                    'config_per' => $config->default_rate,
+                    'created_at' => $now,
+                    'updated_at' => $now,
+                ]);
+            // 让所有的时间区间比例配置,在定时任务中,重新执行一遍
+            DB::table('juliang_account_promotion_config_time')
+                ->where('is_enable',1)
+                ->where('company_uid',$this->getOptimizerUid())
+                ->where('account_id',$config->adv_account_id)
+                ->update(['next_exec_time' => date('Y-m-d'), 'updated_at' => $now]);
+        }
+
+
+        return 'ok';
+    }
+
 }

+ 1 - 0
modules/Callback/routes/route.php

@@ -10,6 +10,7 @@ Route::prefix('callback')->group(function () {
         Route::post('addAccount', [JuliangAccountController::class, 'addAccount']);
         Route::post('updateCallbackConfig', [JuliangAccountController::class, 'updateCallbackConfig']);
         Route::post('turnCallbackState', [JuliangAccountController::class, 'turnCallbackState']);
+        Route::post('unbindPromotion', [JuliangAccountController::class, 'unbindPromotion']);
         Route::get('log/list', [CallbackLogController::class, 'list']);
         Route::post('log/callbackAgain', [CallbackLogController::class, 'callbackAgain']);
     });

+ 75 - 51
modules/Channel/Services/Order/OrderService.php

@@ -26,7 +26,7 @@ class OrderService
      */
     public static function getOrderList(array $param, $isAll = false)
     {
-        $list = self::getOrderQuerySql($param)->orderBy("orders.id",'desc');
+        $list = self::getOrderQuerySql($param)->select("orders.*", 'pay_merchants.name as pay_merchant_name', 'pay_merchants.payee_name', 'pay_merchants.pay_appid', 'miniprogram.play_name', "miniprogram.name as xcx_name", 'promotions.name as promotion_title')->orderBy("orders.id", 'desc');
 
         if ($isAll) {
             $list = $list->get();
@@ -35,20 +35,11 @@ class OrderService
         }
 
         if (!$list->isEmpty()) {
-
             $status = array_column(self::getOrderPayType(), null, 'value');
             $types = array_column(self::getOrderType(), null, 'value');
             foreach ($list as $val) {
                 $val->username = $val->user_id > 0 ? User::where('id', $val->user_id)->value('username') : "";
-                $val->company_name = "-";
-                $val->play_name = '-';
-                $company = Miniprogram::where('id', $val->miniprogram_id)->first();
-                if ($company) {
-                    $val->company_name = $val->puser_id >  0 ? DB::table('users')->where('id',$val->puser_id)->value("username") : "-"; 
-                    $val->play_name = $company->play_name;
-                    $val->xcx_name = $company->name;
-                }
-                $val->promotion_title = $val->promotion_id > 0 ? DB::table('promotions')->where('id', $val->promotion_id)->value('name') : "";
+                $val->company_name = $val->puser_id > 0 ? DB::table('users')->where('id', $val->puser_id)->value("username") : "-";
                 $val->total_count = Order::where('uid', $val->uid)->where('id', "<=", $val->id)->count();
                 if ($val->user_id > 0) {
                     $val->caompany_count = Order::where('uid', $val->uid)->where('puser_id', '>', 0)->where('puser_id', $val->puser_id)->where('id', "<=", $val->id)->count();
@@ -57,6 +48,12 @@ class OrderService
                     $val->caompany_count = Order::where('uid', $val->uid)->where('puser_id', '>', 0)->count();
                     $val->promotion_count = Order::where('uid', $val->uid)->where('user_id', '>', 0)->count();
                 }
+                $val->pay_appid = $val->pay_appid ?: '-';
+                $val->pay_merchant_name = $val->pay_merchant_name ?: '-';
+                $val->payee_name = $val->payee_name ?: '-';
+                $val->xcx_name = $val->xcx_name ?: '-';
+                $val->play_name = $val->play_name ?: '-';
+                $val->promotion_title = $val->promotion_title ?: '-';
                 $val->tip_text = $types[$val->order_type]['name'] ?? "-";
                 $val->status_txt = $status[$val->status]['name'] ?? "-";
                 $val->pay_name = '微信支付';
@@ -66,6 +63,13 @@ class OrderService
         return $list;
     }
 
+
+    /**
+     *  充值类型
+     * name: getOrderType
+     * @return \string[][]
+     * date 2023/06/02 09:56
+     */
     public static function getOrderType()
     {
         return [
@@ -77,6 +81,12 @@ class OrderService
         ];
     }
 
+    /**
+     *  订单状态
+     * name: getOrderPayType
+     * @return \string[][]
+     * date 2023/06/02 09:57
+     */
     public static function getOrderPayType()
     {
         return [
@@ -88,68 +98,82 @@ class OrderService
 
     private static function getOrderQuerySql(array $param)
     {
-        $sql = DB::table('orders');
+        $sql = DB::table('orders')->leftJoin('miniprogram', 'miniprogram.id', '=', 'orders.miniprogram_id')->leftJoin('promotions', 'promotions.id', '=', 'orders.promotion_id')->leftJoin('pay_merchants', 'pay_merchants.id', '=', 'orders.pay_merchant_id');
         // 优化师查询
         if (!empty(getProp($param, 'user_id'))) {
-            $sql->where('user_id', $param['user_id']);
+            $sql->where('orders.user_id', $param['user_id']);
         }
         // 公司查询
         if (!empty(getProp($param, 'puser_id'))) {
-            $sql->where('puser_id', $param['puser_id']);
+            $sql->where('orders.puser_id', $param['puser_id']);
         }
         // 小程序
         if (!empty(getProp($param, 'miniprogram_id'))) {
-            $sql->where('miniprogram_id', $param['miniprogram_id']);
+            $sql->where('orders.miniprogram_id', $param['miniprogram_id']);
         }
 
         // 推广id
         if (!empty(getProp($param, 'promotion_id'))) {
-            $sql->where('promotion_id', $param['promotion_id']);
+            $sql->where('orders.promotion_id', $param['promotion_id']);
         }
         // 订单状态查询
         if (!empty(getProp($param, 'status'))) {
-            $sql->where('status', $param['status']);
+            $sql->where('orders.status', $param['status']);
         }
 
         // 充值项类型
         if (!empty(getProp($param, 'order_type'))) {
-            $sql->where('order_type', $param['order_type']);
+            $sql->where('orders.order_type', $param['order_type']);
         }
         // 用户
         if (!empty(getProp($param, 'uid'))) {
-            $sql->where('uid', $param['uid']);
+            $sql->where('orders.uid', $param['uid']);
         }
         // 订单号查询
         if (!empty(getProp($param, 'trade_no'))) {
-            $sql->where('trade_no', "like", "%" . $param['trade_no'] . "%");
-            // $sql->where('trade_no',  $param['trade_no']);
+            $sql->where('orders.trade_no', "like", "%" . $param['trade_no'] . "%");
+            // $sql->where('orders.trade_no',  $param['trade_no']);
         }
         if (!empty(getProp($param, 'trade_no'))) {
-            // $sql->where('trade_no', "like", "%" . $param['trade_no'] . "%");
-            $sql->where('trade_no', $param['trade_no']);
+            // $sql->where('orders.trade_no', "like", "%" . $param['trade_no'] . "%");
+            $sql->where('orders.trade_no', $param['trade_no']);
         }
         // 支付时间
         if (!empty(getProp($param, 'pay_end_at_start'))) {
-            $sql->where('pay_end_at', ">=",$param['pay_end_at_start']);
+            $sql->where('orders.pay_end_at', ">=", $param['pay_end_at_start']);
         }
         if (!empty(getProp($param, 'pay_end_at_end'))) {
-            $end =$param['pay_end_at_end'];
-            if ($end == getProp($param,'pay_end_at_start','')){
-                $end = date("Y-m-d",strtotime($end)) . " 23:59:59";
+            $end = $param['pay_end_at_end'];
+            if ($end == getProp($param, 'pay_end_at_start', '')) {
+                $end = date("Y-m-d", strtotime($end)) . " 23:59:59";
             }
-            $sql->where('pay_end_at', "<=", $end);
+            $sql->where('orders.pay_end_at', "<=", $end);
         }
         // 创建时间
         if (!empty(getProp($param, 'created_at_start'))) {
-            $sql->where('created_at', '>=',$param['created_at_start']);
+            $sql->where('orders.created_at', '>=', $param['created_at_start']);
         }
 
         if (!empty(getProp($param, 'created_at_end'))) {
-            $end =$param['created_at_end'];
-            if ($end == getProp($param,'created_at_start','')){
-                $end = date("Y-m-d",strtotime($end)) . " 23:59:59";
+            $end = $param['created_at_end'];
+            if ($end == getProp($param, 'created_at_start', '')) {
+                $end = date("Y-m-d", strtotime($end)) . " 23:59:59";
             }
-            $sql->where('created_at', "<=", $end);
+            $sql->where('orders.created_at', "<=", $end);
+        }
+
+        // 支付配置信息查询
+        if (getProp($param, 'pay_merchant_name', '')) {
+            // 支付名称
+            $sql->where("pay_merchants.name", $param['pay_merchant_name']);
+        }
+        if (getProp($param, 'payee_name', '')) {
+            // 收款主体
+            $sql->where("pay_merchants.payee_name", "like", "%" . $param['payee_name'] . "%");
+        }
+        if (getProp($param, 'pay_appid', '')) {
+            // 商户号
+            $sql->where("pay_merchants.pay_appid", $param['pay_appid']);
         }
         return $sql;
     }
@@ -193,14 +217,14 @@ class OrderService
      * @return \Illuminate\Support\Collection
      * date 2023/05/23 18:13
      */
-    public static function promotionsOptions(mixed $uid, mixed $title,mixed $miniprogram_id,mixed $limit = 10)
+    public static function promotionsOptions(mixed $uid, mixed $title, mixed $miniprogram_id, mixed $limit = 10)
     {
         $operateUser = User::find($uid);
         $operateUserRoles = $operateUser->roles->pluck('identify');
         $list = DB::table('promotions')->select('id as promotion_id', 'name');
         if ($operateUserRoles->contains('optimizer')) {
-            if ($miniprogram_id){
-                $list->where('miniprogram_id',$miniprogram_id);
+            if ($miniprogram_id) {
+                $list->where('miniprogram_id', $miniprogram_id);
             }
             if ($title) {
                 $list->where('name', 'like', "%" . $title . "%");
@@ -213,14 +237,14 @@ class OrderService
             if ($title) {
                 $list->where('promotions.name', 'like', "%" . $title . "%");
             }
-            if ($miniprogram_id){
-                $list->where('promotions.miniprogram_id',$miniprogram_id);
+            if ($miniprogram_id) {
+                $list->where('promotions.miniprogram_id', $miniprogram_id);
             }
-            return $list->orderBy('promotions.id','desc')->limit($limit)->get();
+            return $list->orderBy('promotions.id', 'desc')->limit($limit)->get();
 
         } else {
-            if ($miniprogram_id){
-                $list->where('miniprogram_id',$miniprogram_id);
+            if ($miniprogram_id) {
+                $list->where('miniprogram_id', $miniprogram_id);
             }
             if ($title) {
                 $list->where('name', 'like', "%" . $title . "%");
@@ -237,28 +261,28 @@ class OrderService
      * @param mixed $limit
      * date 2023/05/26 09:22
      */
-    public static function promotionsUsers(mixed $pid, mixed $name,mixed $miniprogram_id, mixed $limit = 10)
+    public static function promotionsUsers(mixed $pid, mixed $name, mixed $miniprogram_id, mixed $limit = 10)
     {
         if ($pid > 0) {
             $list = DB::table('users')->where('pid', $pid)->select('users.id as user_id', 'users.username as  name');
             if ($name) {
                 $list->where('username', 'like', "%" . $name . "%");
             }
-            if ($miniprogram_id >  0){
-                $list->join('user_has_miniprograms','user_has_miniprograms.uid','users.id')
-                    ->where('user_has_miniprograms.miniprogram_id',$miniprogram_id);
+            if ($miniprogram_id > 0) {
+                $list->join('user_has_miniprograms', 'user_has_miniprograms.uid', 'users.id')
+                    ->where('user_has_miniprograms.miniprogram_id', $miniprogram_id);
             }
 
             return $list->orderBy('users.id', 'desc')->limit($limit)->get();
         }
 
-        $list = DB::table('users')->join('user_has_roles','users.id',"user_has_roles.user_id")->join('roles','roles.id','user_has_roles.role_id')
-            ->select('users.id as user_id', 'users.username as  name')->where('roles.identify','optimizer');
-        if ($miniprogram_id >  0){
-            $list->join('user_has_miniprograms','user_has_miniprograms.uid','users.id')
-                ->where('user_has_miniprograms.miniprogram_id',$miniprogram_id);
+        $list = DB::table('users')->join('user_has_roles', 'users.id', "user_has_roles.user_id")->join('roles', 'roles.id', 'user_has_roles.role_id')
+            ->select('users.id as user_id', 'users.username as  name')->where('roles.identify', 'optimizer');
+        if ($miniprogram_id > 0) {
+            $list->join('user_has_miniprograms', 'user_has_miniprograms.uid', 'users.id')
+                ->where('user_has_miniprograms.miniprogram_id', $miniprogram_id);
         }
-        if ($name){
+        if ($name) {
             $list->where('users.username', 'like', "%" . $name . "%");
         }
         return $list->orderBy('users.id', 'desc')->limit($limit)->get();

+ 6 - 2
modules/Common/Errors/Errors.php

@@ -10,7 +10,7 @@ class Errors
     public const  PARAM_ERROR= [500004, '参数错误'];
     public const  NO_OPERATE_PERMISSION= [500007, '用户无操作权限'];
     public const  VIDEO_NOT_EXISTS= [500008, '视频不存在'];
-    public const  MINIPROGRAM_STATUS_ERROR= [500005, '小程序未启用'];
+    public const  MINIPROGRAM_STATUS_ERROR= [50005, '小程序未启用'];
     public const  PAY_TEMPLATE_EXISTS_ERROR= [500006, '充值模板已经存在'];
     public const  PAY_TEMPLATE_GIVEN_TOO_MUCH= [500007, '赠送不能超过金额3倍'];
     public const  PAY_TEMPLATE_NOT_EXISTS_ERROR= [500008, '充值模板不存在'];
@@ -21,11 +21,15 @@ class Errors
     public const  CALLBACK_RATE_TIME_RANGE_ERROR= [500102, '回传比例时间区间不合法'];
     public const  CALLBACK_RECORD_NOT_EXISTS= [500103, '回传日志不存在'];
     public const  CALLBACK_RECORD_LOG_ERROR= [500104, '回传日志补传信息缺失'];
-    public const  JULIANG_ACCOUNT_PROMOTION_UNIQUE = [500105, '巨量广告账户只允许绑定一个推广'];
+    public const  JULIANG_ACCOUNT_PROMOTION_UNIQUE = [500105, '巨量广告账户只允许绑定一个推广,请先解绑'];
     public const  JULIANG_ACCOUNT_CONFIG_NOT_EXISTS = [500106, '回传配置不存在'];
     public const  TIXIAN_YUE_BUZU = [500201, '提现余额不足'];
     public const  BANK_CARD_STATUS_ERROR = [500202, '银行卡不存在或当前状态不可提现'];
     public const  TIXIAN_RECORD_NOT_EXISTS = [500203, '提现记录不存在'];
     public const  TIXIAN_ONLY_ONCE_EVERY_DAY = [500204, '每天只能提现一次'];
     public const  OPERATION_FIRST_PAGE_LIST_NOT_EXISTS = [500301, '首页列表配置项不存在'];
+    public const  VIDEO_SERIES_NOT_EXISTS = [500302, '剧集不存在'];
+    public const REQUEST_HTTP_STATUS_ERROR = [500401, '请求上游接口返回http状态码有误'];
+    public const REQUEST_CODE_STATUS_ERROR = [500402, '请求上游接口返回code状态码有误'];
+    public const SYNC_WECHAT_NOT_OK = [500302, '剧集没有成功同步到微信'];
 }

+ 53 - 0
modules/Common/Services/CommonConfigService.php

@@ -0,0 +1,53 @@
+<?php
+
+namespace Modules\Common\Services;
+
+class CommonConfigService
+{
+    /**
+     * 获取首页列表类型映射
+     * @return mixed[]
+     * <pre>
+     * [
+     *   1 => [
+     *      'label' => 'xxx',
+     *      'value' => 1,
+     *   ],
+     * ]
+     * </pre>
+     */
+    public static function getFirstPageListTypeMap() {
+        return collect(config('common.common.firstPageListType'))->keyBy('value')->toArray();
+    }
+    /**
+     * 获取小程序类型映射
+     * @return mixed[]
+     * <pre>
+     * [
+     *   1 => [
+     *      'label' => 'xxx',
+     *      'value' => 1,
+     *   ],
+     * ]
+     * </pre>
+     */
+    public static function getMiniprogramTypeMap() {
+        return collect(config('common.common.miniprogramType'))->keyBy('value')->toArray();
+    }
+
+    /**
+     * 获取支付类型映射
+     * @return mixed[]
+     * <pre>
+     * [
+     *   1 => [
+     *      'label' => 'xxx',
+     *      'value' => 1,
+     *   ],
+     * ]
+     * </pre>
+     */
+    public static function getPayTypeMap() {
+        return collect(config('common.common.payType'))->keyBy('value')->toArray();
+    }
+}

+ 16 - 16
modules/Common/config/common.php

@@ -2,14 +2,14 @@
 
 return [
     'logos' => [
-        '2' => 'https://zhuishuyun.oss-cn-hangzhou.aliyuncs.com/channel/logo/DOUYIN.png',
-        '1' => 'https://zhuishuyun.oss-cn-hangzhou.aliyuncs.com/channel/logo/WEIXIN.png',
-        'QQ' => 'https://zhuishuyun.oss-cn-hangzhou.aliyuncs.com/channel/logo/QQ.png',
+        '2' => 'https://minifile-cdn.zvyhjkx.com/logo/DOUYIN.png',
+        '1' => 'https://minifile-cdn.zvyhjkx.com/logo/WEIXIN.png',
+        'QQ' => 'https://minifile-cdn.zvyhjkx.com/logo/QQ.png',
     ],
     /**
      * 短剧管理后台的域名
      */
-    'duanjuManageDomain' => env('COMMON_DUANJU_MANAGE_DOMAIN', 'http://m.test.duanju.dududus.com'),
+    'duanjuManageDomain' => env('COMMON_DUANJU_MANAGE_DOMAIN', 'https://manage.zhiyupa.com'),
     /**
      * 模块和小程序type值的映射
      */
@@ -22,16 +22,16 @@ return [
      */
     'payType' => [
         [
-            'key' => 1,
-            'val' => '易宝支付',
+            'label' => '易宝支付',
+            'value' => 1,
         ],
         [
-            'key' => 2,
-            'val' => '微信原生支付',
+            'label' => '微信原生支付',
+            'value' => 2,
         ],
         [
-            'key' => 3,
-            'val' => '抖音支付'
+            'label' => '抖音支付',
+            'value' => 2,
         ],
     ],
     /**
@@ -39,12 +39,12 @@ return [
      */
     'miniprogramType' => [
         [
-            'key' => 1,
-            'val' => '微信'
+            'value' => 1,
+            'label' => '微信'
         ],
         [
-            'key' => 2,
-            'val' => '抖音'
+            'value' => 2,
+            'label' => '抖音'
         ]
     ],
     /**
@@ -53,11 +53,11 @@ return [
     'firstPageListType' => [
         [
             'label' => '本周精选',
-            'val' => 1
+            'value' => 1
         ],
         [
             'label' => '优选好剧',
-            'val' => 2
+            'value' => 2
         ],
     ],
 ];

+ 2 - 1
modules/Common/routes/route.php

@@ -6,6 +6,7 @@ use Modules\Common\Http\Controllers\OptionController;
 use Modules\Common\Http\Controllers\Qiniu\CallbackController;
 use Modules\Common\Http\Controllers\Qiniu\ImageUploadController;
 use Modules\Common\Http\Controllers\UploadController;
+use Modules\Permissions\Middlewares\PermissionGate;
 
 /*
 |--------------------------------------------------------------------------
@@ -33,7 +34,7 @@ Route::prefix('qiniu')->group(function() {
     Route::get('upload/token', [CallbackController::class, 'uploadToken']);
     Route::get('downloadUrl', [CallbackController::class, 'downloadUrl']);
     Route::post('upload/callback', [CallbackController::class, 'callback'])->withoutMiddleware(config('catch.route.middlewares'));
-    Route::post('upload/image', [ImageUploadController::class, 'uploadImage']);
+    Route::post('upload/image', [ImageUploadController::class, 'uploadImage'])->withoutMiddleware([PermissionGate::class]);
 });
 
 

+ 48 - 0
modules/Manage/Http/Controllers/MiniprogramController.php

@@ -2,6 +2,8 @@
 
 namespace Modules\Manage\Http\Controllers;
 
+use Catch\Exceptions\FailedException;
+use Illuminate\Routing\Controller;
 use Catch\Base\CatchController;
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\DB;
@@ -70,6 +72,8 @@ class MiniprogramController extends CatchController
         foreach($result as $item){
             $item->type_name = MiniprogramType::from($item->type)->name();
             $item->status_name = $item->status == 1 ?'启用':'禁用';
+            $item->pay_merchant_name = getProp($item->pay_merchant_info,'name','-');
+            unset($item->pay_merchant_info);
         }
         return $result;
     }
@@ -84,6 +88,29 @@ class MiniprogramController extends CatchController
     {
         $validate_result = $request->validated();
         $validate_result['remark'] = $request->post('remark','') ?? '';
+        $validate_result['pay_merchant_id'] = $request->post('pay_merchant_id',0);
+        if (getProp($validate_result,'pay_merchant_id',0)){
+            $info = DB::table('pay_merchants')->where('id',$validate_result['pay_merchant_id'])->first();
+            if (empty($info)){
+                throw  new  FailedException("支付方式不存在");
+            }
+            if ($info->miniprogram_type != $validate_result['type']){
+                throw  new  FailedException("小程序类型和支付的小程序类型不匹配");
+            }
+            $validate_result['pay_merchant_info'] = [
+                'pay_merchant_id' => $info->id,
+                'name' => $info->name,
+                'pay_type' => $info->pay_type,
+                'payee_name' => $info->payee_name,
+                'miniprogram_type' => $info->miniprogram_type,
+                'pay_appid' => $info->pay_appid,
+            ];
+
+        }else{
+            $validate_result['pay_merchant_id'] = 0;
+            $validate_result['pay_merchant_info'] = [];
+        }
+
         return $this->miniprogram->create($validate_result)->toArray();
 
     }
@@ -112,6 +139,27 @@ class MiniprogramController extends CatchController
         if($request->post('remark','')){
             $validate_result['remark'] = $request->post('remark','');
         }
+        if (getProp($validate_result,'pay_merchant_id',0)){
+            $info = DB::table('pay_merchants')->where('id',$validate_result['pay_merchant_id'])->first();
+            if (empty($info)){
+                throw  new  FailedException("支付方式不存在");
+            }
+            if ($info->miniprogram_type != $validate_result['type']){
+                throw  new  FailedException("小程序类型和支付的小程序类型不匹配");
+            }
+            $validate_result['pay_merchant_info'] = [
+                'pay_merchant_id' => $info->id,
+                'name' => $info->name,
+                'pay_type' => $info->pay_type,
+                'payee_name' => $info->payee_name,
+                'miniprogram_type' => $info->miniprogram_type,
+                'pay_appid' => $info->pay_appid,
+            ];
+
+        }else{
+            $validate_result['pay_merchant_id'] = 0;
+            $validate_result['pay_merchant_info'] = [];
+        }
         $this->miniprogram->where('id',$id)->update($validate_result);
         return [];
     }

+ 5 - 4
modules/Manage/Http/Controllers/PayConfigController.php

@@ -6,6 +6,7 @@ use Catch\Base\CatchController;
 use Illuminate\Foundation\Validation\ValidatesRequests;
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\DB;
+use Modules\Common\Services\CommonConfigService;
 
 /**
  * 支付配置管理
@@ -53,11 +54,11 @@ class PayConfigController extends CatchController
             $result =  $sql->paginate($request->input('limit', 15));
         }
 
-        $payTypeMap = collect($commonConfig['payType'])->keyBy('key');
-        $miniprogramTypeMap = collect($commonConfig['miniprogramType'])->keyBy('key');
+        $payTypeMap = CommonConfigService::getPayTypeMap();
+        $miniprogramTypeMap = CommonConfigService::getMiniprogramTypeMap();
         foreach ($result as $item) {
-            $item->pay_type_str = $payTypeMap[$item->pay_type]['val'] ?? '';
-            $item->miniprogram_type_str = $miniprogramTypeMap[$item->miniprogram_type]['val'] ?? '';
+            $item->pay_type_str = $payTypeMap[$item->pay_type]['label'] ?? '';
+            $item->miniprogram_type_str = $miniprogramTypeMap[$item->miniprogram_type]['label'] ?? '';
         }
 
         return $result;

+ 4 - 2
modules/Manage/Http/Requests/MiniprogramUpdateRequest.php

@@ -33,7 +33,8 @@ class MiniprogramUpdateRequest extends FormRequest
             ],
             'appsecret'=>'required|min:30|max:64',
             'appid'=>'required|min:18|max:32',
-            'status'=>'in:0,1'
+            'status'=>'in:0,1',
+            'pay_merchant_id' => "Integer|gt:0"
         ];
     }
 
@@ -45,7 +46,8 @@ class MiniprogramUpdateRequest extends FormRequest
             'appid.min'=>'appid太短',
             'appid.max'=>'appid过长',
             'appsecret.min'=>'appsecret太短',
-            'appsecret.max'=>'appsecret过长'
+            'appsecret.max'=>'appsecret过长',
+            "pay_merchant_id" => "支付配置不正确",
         ];
     }
 }

+ 2 - 2
modules/Manage/Models/Miniprogram.php

@@ -14,7 +14,7 @@ class Miniprogram extends BaseModel
     protected $table = 'miniprogram';
 
     protected $fillable = [
-        'id', 'name', 'company', 'type', 'appid', 'appsecret', 'status', 'remark', 'play_name','created_at', 'updated_at'
+        'id', 'name', 'company', 'type', 'appid', 'appsecret',"pay_merchant_id","pay_merchant_info", 'status', 'remark', 'play_name','created_at', 'updated_at'
     ];
-
+    protected $casts = ['pay_merchant_info' =>'array'];
 }

+ 31 - 0
modules/Manage/Services/WechatMiniprogramService.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace Modules\Manage\Services;
+
+use Illuminate\Support\Facades\Redis;
+
+class WechatMiniprogramService
+{
+    /**
+     * 微信短剧提审appid
+     * @return string
+     */
+    public static function getDuanjuCheckAppid() {
+        return config('manage.miniprogram.duanjuWechatCheck.appid');
+    }
+
+    /**
+     * 微信短剧提审小程序 accessToken
+     * @param string|null $appid
+     * @return string
+     */
+    public static function getDuanjuCheckAccessToken($appid=null) {
+        $checkAppid = $appid ?: self::getDuanjuCheckAppid();
+
+        return Redis::get(self::getAccessTokenRedisKey($checkAppid));
+    }
+
+    private static function getAccessTokenRedisKey($appid) {
+        return 'dj.miniWechat.at.' . $appid;
+    }
+}

+ 7 - 2
modules/Manage/config/miniprogram.php

@@ -4,9 +4,14 @@
  * 小程序配置
  */
 return [
-    
+
     'typelist'=>[
         'WEIXIN','BYTECODE'
     ],
-    
+    /**
+     * 微信短剧提审小程序
+     */
+    'duanjuWechatCheck' => [
+        'appid' => env('MINIPROGRAM_DUANJU_WECHATCHEECK_APPID', 'wx86822355ccd03a78')
+    ]
 ];

+ 44 - 5
modules/Operation/Http/Controllers/FirstPageController.php

@@ -8,6 +8,7 @@ use Illuminate\Http\Request;
 use Illuminate\Support\Facades\DB;
 use Modules\Common\Errors\Errors;
 use Modules\Common\Exceptions\CommonBusinessException;
+use Modules\Common\Services\CommonConfigService;
 use Modules\User\Http\Controllers\UserTrait;
 
 class FirstPageController extends CatchController
@@ -19,13 +20,23 @@ class FirstPageController extends CatchController
      *  首页列表
      */
     public function list(Request $request) {
-        $firstPageListTypeMap = collect(config('common.common.firstPageListType'))->keyBy('val')->toArray();
+        $firstPageListTypeMap = CommonConfigService::getFirstPageListTypeMap();
+        $miniprogramTypeMap = CommonConfigService::getMiniprogramTypeMap();
+        $miniprogramType = $request->input('miniprogram_type');
+        $firstPageListType = $request->input('type');
         $result = DB::table('first_pages')
+            ->where('is_enabled', 1)
+            ->when($miniprogramType, function ($query, $miniprogramType){
+                return $query->where('miniprogram_type', $miniprogramType);
+            })->when($firstPageListType, function ($query, $firstPageListType){
+                return $query->where('type', $firstPageListType);
+            })->orderBy('status', 'desc')
             ->orderBy('id', 'desc')
             ->paginate($request->input('limit', 15));
         foreach ($result as $item) {
             $item->type_str = $firstPageListTypeMap[$item->type]['label'] ?? '';
-            $item->duanjus = collect(\json_decode($item->duanjus, true))->sortBy('sort');
+            $item->duanjus = collect(\json_decode($item->duanjus, true))->sortBy('sort')->values();
+            $item->miniprogram_type_str = $miniprogramTypeMap[$item->miniprogram_type]['label'] ?? '';
         }
         return $result;
     }
@@ -39,13 +50,17 @@ class FirstPageController extends CatchController
     public function add(Request $request) {
         $this->validate($request, [
             'type' => 'required|in:1,2',
-            'status' => 'required|in:0,1'
+            'status' => 'required|in:0,1',
+            'miniprogram_type' => 'required|in:1,2'
         ]);
 
         $now = date('Y-m-d H:i:s');
         if(1 == $request->input('status')) {
             DB::table('first_pages')
-                ->where('type', $request->input('type'))
+                ->where([
+                    'type' => $request->input('type'),
+                    'miniprogram_type' => $request->input('miniprogram_type')
+                ])
                 ->update(['status' => 0, 'updated_at' => $now]);
         }
 
@@ -53,6 +68,7 @@ class FirstPageController extends CatchController
             ->insert([
                 'type' => $request->input('type'),
                 'status' => $request->input('status'),
+                'miniprogram_type' => $request->input('miniprogram_type'),
                 'created_at' => $now,
                 'updated_at' => $now,
             ]);
@@ -76,7 +92,10 @@ class FirstPageController extends CatchController
 
         $now = date('Y-m-d H:i:s');
         DB::table('first_pages')
-            ->where('type', $info->type)
+            ->where([
+                'type' => $info->type,
+                'miniprogram_type' => $info->miniprogram_type,
+            ])
             ->update(['status' => 0, 'updated_at' => $now]);
         DB::table('first_pages')
             ->where('id', $request->input('id'))
@@ -104,5 +123,25 @@ class FirstPageController extends CatchController
 
         return 'ok';
     }
+
+    /**
+     * 删除
+     * @param Request $request
+     * @return string
+     * @throws \Illuminate\Validation\ValidationException
+     */
+    public function delete(Request $request) {
+        $this->validate($request, [
+            'id' => 'required',
+        ]);
+        $now = date('Y-m-d H:i:s');
+        DB::table('first_pages')
+            ->where('id', $request->input('id'))
+            ->where('is_enabled', 1)
+            ->update(['is_enabled' => 0,
+                'updated_at' => $now]);
+
+        return 'ok';
+    }
 }
 

+ 1 - 0
modules/Operation/routes/route.php

@@ -8,6 +8,7 @@ Route::prefix('operationManage')->group(function () {
         Route::post('add', [FirstPageController::class, 'add']);
         Route::post('enableStatus', [FirstPageController::class, 'enableStatus']);
         Route::post('setConfig', [FirstPageController::class, 'setConfig']);
+        Route::post('delete', [FirstPageController::class, 'delete']);
         Route::get('list', [FirstPageController::class, 'list']);
     });
 

+ 1 - 1
modules/OrderRefund/Models/OrdersRefundVerify.php

@@ -10,7 +10,7 @@ class OrdersRefundVerify extends BaseModel
     protected $table = 'orders_refund_verify';
 
     protected $fillable = [
-        'id','third_orderid', 'create_user_id', 'order_id', 'puser_id', 'user_id', 'uid', 'order_price', 'refund_price', 'trade_no', 'refund_no', 'refund_status', 'pay_at', 'pay_op_user', 'pt_verify_status', 'pt_verifty_user', 'pt_verify_at', 'pt_verify_remark', 'sh_verify_status', 'sh_verifty_user', 'sh_verify_remark', 'sh_verify_at', 'created_at', 'updated_at',
+        'id','third_orderid', 'create_user_id',"pay_merchant_id", 'order_id', 'puser_id', 'user_id', 'uid', 'order_price', 'refund_price', 'trade_no', 'refund_no', 'refund_status', 'pay_at', 'pay_op_user', 'pt_verify_status', 'pt_verifty_user', 'pt_verify_at', 'pt_verify_remark', 'sh_verify_status', 'sh_verifty_user', 'sh_verify_remark', 'sh_verify_at', 'created_at', 'updated_at',
     ];
     protected $casts = ['sh_verifty_user' => 'array','pt_verifty_user' => 'array','pay_op_user' => 'array'];
 

File diff suppressed because it is too large
+ 84 - 67
modules/OrderRefund/Services/RefundOrderService.php


+ 4 - 2
modules/Tuiguang/Http/Controllers/PromotionController.php

@@ -54,9 +54,10 @@ class PromotionController extends CatchController
             })->orderBy('created_at', 'desc')
             ->select('promotions.id', 'promotions.name', 'promotions.created_at',
             'videos.name as video_name', 'promotions.series_sequence', 'promotions.callback_type',
-                'promotions.callback_config_id', 'promotions.video_id', 'promotions.remark')
+                'promotions.callback_config_id', 'promotions.video_id', 'promotions.remark', 'promotions.status')
             ->paginate($request->input('limit', 15));
         foreach ($result as $item) {
+            $item->status_str = $item->status ? '启用':'禁用';
             $item->series_sequence_name = '第'. $item->series_sequence . '集';
             $item->callback_type_str = $callbackTypeMap[$item->callback_type] ?? '';
             $item->promotion_path = config('tuiguang.tuiguang.url') . DIRECTORY_SEPARATOR . 'api/promotion/index?ranse_id='. $item->id;
@@ -131,7 +132,8 @@ class PromotionController extends CatchController
         if(1 == $request->input('callback_type')) {
             $exist = DB::table('promotions')
                 ->where(['is_enabled' => 1, 'callback_type' => $request->input('callback_type'),
-                    'callback_config_id' => $request->input('callback_config_id')])
+                    'callback_config_id' => $request->input('callback_config_id'),
+                    'status' => 1])
                 ->first();
             if($exist && $exist->id != $request->input('id')) {
                 CommonBusinessException::throwError(Errors::JULIANG_ACCOUNT_PROMOTION_UNIQUE);

+ 2 - 2
modules/Tuiguang/config/tuiguang.php

@@ -4,9 +4,9 @@ return [
     /**
      * 推广链接地址
      */
-    'url' => env('TUIGUAGN_URL', 'https://api.dududus.com'),
+    'url' => env('TUIGUAGN_URL', 'https://api.zhiyupa.com'),
     /**
      * 监测链接地址
      */
-    'trackUrl' => env('TUIGUAGN_TRACK_URL', 'https://track.dududus.com')
+    'trackUrl' => env('TUIGUAGN_TRACK_URL', 'https://track.zhiyupa.com')
 ];

+ 10 - 3
modules/Video/Http/Controllers/VideoController.php

@@ -28,6 +28,7 @@ class VideoController extends CatchController
         $categoryId = $request->input('categoryId');
         $videoId = $request->input('videoId');
         $shelfType = $request->input('shelfType');
+        $wechatPass = $request->input('wechatPass');
 
         $videos = DB::table('videos')
             ->when($videoId, function ($query, $videoId){
@@ -41,7 +42,10 @@ class VideoController extends CatchController
                 return $query->where('update_type', $updateType);
             })->when($categoryId, function ($query, $categoryId){
                 return $query->where('category_id', $categoryId);
-            })->orderBy('id', 'desc')
+            })->when(!is_null($wechatPass), function ($query) use ($wechatPass) {
+                return $query->where('wechat_pass', $wechatPass);
+            })
+            ->orderBy('id', 'desc')
             ->paginate($request->integer('limit', 15));
         $userContext = $this->getUserContext($request->input('operateUserId'));
         $allVideoCategory =  DB::table('video_category')
@@ -53,6 +57,7 @@ class VideoController extends CatchController
             $video->update_type_str = $video->update_type == 1 ? '连载中' : '完结';
             $video->cp_share_type_str = ([1 => '分成', 2=>'保底', 3=>'买断'])[$video->cp_share_type] ?? '';
             $video->channel = $allVideoCategory->get($video->category_id)->pid;
+            $video->wechat_pass_img = $video->wechat_pass ? config('common.common.logos.1') : '';
         }
 
         return $videos;
@@ -122,7 +127,8 @@ class VideoController extends CatchController
             'd_charge_coin' => 'required|integer|min:1',
             'cp_name' => 'required|string',
             'cp_share_type' => 'required|integer|in:1,2,3',
-            'cover_image' => 'required|string'
+            'cover_image' => 'required|string',
+            'note' => 'required',
         ]);
         $data = $request->all();
         $now = date('Y-m-d H:i:s');
@@ -155,7 +161,8 @@ class VideoController extends CatchController
             'd_charge_coin' => 'required|integer|min:1',
             'cp_name' => 'required|string',
             'cp_share_type' => 'required|integer|in:1,2,3',
-            'cover_image' => 'required|string'
+            'cover_image' => 'required|string',
+            'note' => 'required',
         ]);
         $id = $request->input('id');
         $data = $request->except('id', 'shelf_at');

+ 80 - 0
modules/Video/Http/Controllers/VideoSeriesWechatCheckController.php

@@ -0,0 +1,80 @@
+<?php
+
+namespace Modules\Video\Http\Controllers;
+
+use Catch\Base\CatchController;
+use Illuminate\Foundation\Validation\ValidatesRequests;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Redis;
+use Modules\Common\Errors\Errors;
+use Modules\Common\Exceptions\CommonBusinessException;
+use Modules\Manage\Services\WechatMiniprogramService;
+use Modules\Video\Services\WechatCheckSyncService;
+
+class VideoSeriesWechatCheckController extends CatchController
+{
+    use ValidatesRequests;
+    /**
+     * 剧集同步到微信
+     * @param Request $request
+     */
+    public function syncWechat(Request $request) {
+        $this->validate($request, [
+            'series_ids' => 'required|array'
+        ]);
+        $series_ids = $request->input('series_ids');
+        $series = DB::table('video_series')
+            ->join('videos', 'video_series.video_id', 'videos.id')
+            ->whereIn('video_series.id', $series_ids)
+            ->where(['video_series.is_enabled' => 1])
+            ->select('videos.name', 'video_series.series_sequence','video_series.id', 'video_series.video_key')
+            ->get();
+        if(collect($series_ids)->count() != $series->count()) {
+            CommonBusinessException::throwError(Errors::VIDEO_SERIES_NOT_EXISTS);
+        }
+        $appid = WechatMiniprogramService::getDuanjuCheckAppid();
+        $accessToken = WechatMiniprogramService::getDuanjuCheckAccessToken($appid);
+        $now = date('Y-m-d H:i:s');
+        foreach ($series as $item) {
+            $item->video_url = config('common.qiniu.publicVideoLinkDomain') . DIRECTORY_SEPARATOR . $item->video_key;
+            $item->media_name = sprintf('%s - 第%s集', $item->name, $item->series_sequence);
+            $taskId = WechatCheckSyncService::pullupload($item, $accessToken);
+            DB::table('video_series_wechat_check')
+                ->where(['series_id' => $item->id, 'is_enabled' => 1])
+                ->update(['is_enabled' => 0, 'updated_at' => $now]);
+            DB::table('video_series_wechat_check')
+                ->insert([
+                    'series_id' => $item->id,
+                    'sync_task_id' => $taskId, 'appid' => $appid,
+                    'created_at' => $now, 'updated_at' => $now
+                ]);
+        }
+
+        return 'ok';
+    }
+
+    /**
+     * 获取微信那边的剧集播放链接
+     * @param Request $request
+     * @return mixed
+     * @throws \Illuminate\Validation\ValidationException
+     */
+    public function medialink(Request $request) {
+        $this->validate($request, [
+            'series_id' => 'required'
+        ]);
+
+        $seriesId = $request->input('series_id');
+        $redisKey = WechatCheckSyncService::getWechatMediaLinkRedisKey($seriesId);
+        $link = Redis::get($redisKey);
+        if($link) {
+            return $link;
+        }
+
+        $medialinkInfo = WechatCheckSyncService::getMedialinkInfo($seriesId);
+        $link = $medialinkInfo['mp4_url'];
+        Redis::setex($redisKey, 6000, $link);
+        return $link;
+    }
+}

+ 119 - 0
modules/Video/Http/Controllers/WechatCheckController.php

@@ -0,0 +1,119 @@
+<?php
+
+namespace Modules\Video\Http\Controllers;
+
+use App\Jobs\Video\WechatCheck;
+use Catch\Base\CatchController;
+use Illuminate\Foundation\Validation\ValidatesRequests;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\DB;
+
+/**
+ * 微信提审
+ */
+class WechatCheckController extends CatchController
+{
+    use ValidatesRequests;
+    /**
+     * 添加提审
+     * @param Request $request
+     */
+    public function add(Request $request) {
+        $this->validate($request, [
+            'video_id'=>'required',
+            'producer' => 'required|string|max:256',
+            'playwright' => 'required|string|max:256',
+            'production_license_img' => 'required|url',
+            'authorized_img' => 'required|url'
+        ]);
+
+        $data = $request->all();
+        $data['created_at'] = $data['updated_at'] = date('Y-m-d H:i:s');
+        DB::table('video_wechat_check')
+            ->insert($data);
+
+        return 'ok';
+    }
+
+    /**
+     * 修改
+     * @param Request $request
+     */
+    public function update(Request $request) {}
+
+    /**
+     * 删除
+     * @param Request $request
+     */
+    public function delete(Request $request) {
+        $this->validate($request, ['id' => 'required']);
+        DB::table('video_wechat_check')
+            ->where([
+                'id' => $request->input('id'),
+                'is_enabled' => 1,
+            ])->update([
+                'is_enabled' => 0,
+                'updated_at' => date('Y-m-d H:i:s')
+            ]);
+
+        return 'ok';
+    }
+    /**
+     * 提审记录列表
+     * @param Request $request
+     */
+    public function list(Request $request) {
+        $videoId = $request->input('video_id');
+        $producer = $request->input('producer');
+        $playwright = $request->input('playwright');
+        $status = $request->input('status',0);
+
+        return DB::table('video_wechat_check as check')
+            ->join('videos', 'videos.id', 'check.video_id')
+            ->where([
+                'check.status' => $status,
+                'check.is_enabled' => 1,
+            ])->when($videoId, function ($query, $videoId) {
+                return $query->where('check.video_id', $videoId);
+            })->when($producer, function ($query, $producer){
+                return $query->where('check.producer', 'like', '%'. $producer. '%');
+            })->when($playwright, function ($query, $playwright){
+                return $query->where('check.playwright', 'like', '%'. $playwright. '%');
+            })->select('check.id', 'videos.name', 'videos.note', 'videos.total_episode_num',
+                'videos.cover_image','check.status','check.producer',
+            'check.playwright', 'check.production_license_img', 'check.authorized_img', 'check.apply_at',
+            'check.check_at', 'check.check_reason')
+            ->orderBy('check.id','desc')
+            ->paginate($request->input('limit', 10));
+
+    }
+
+    /**
+     * 微信提审
+     * @param Request $request
+     */
+    public function wechatCheck(Request $request) {
+        $this->validate($request, [
+            'ids' => 'required|array'
+        ]);
+        $ids = $request->input('ids');
+        $now = date('Y-m-d H:i:s');
+        DB::table('video_wechat_check')
+            ->whereIn('id', $ids)
+            ->whereIn('status', [0, 4])
+            ->update([
+                'status' => 5,
+                'updated_at' => $now,
+                'apply_at' => $now,
+            ]);
+        $traceContext = getTraceContext();
+        foreach ($ids as  $id) {
+            WechatCheck::dispatch([
+                'id' => $id,
+                'traceInfo' => $traceContext->getTraceInfo()
+            ])->onQueue('{duanju_manage}.video.wechatCheck')->onConnection('queue-redis');
+        }
+
+        return 'ok';
+    }
+}

+ 103 - 0
modules/Video/Services/WechatCheckSyncService.php

@@ -0,0 +1,103 @@
+<?php
+
+namespace Modules\Video\Services;
+
+use GuzzleHttp\Client;
+use Illuminate\Support\Facades\DB;
+use Modules\Common\Errors\Errors;
+use Modules\Common\Exceptions\CommonBusinessException;
+use Modules\Manage\Services\WechatMiniprogramService;
+
+
+class WechatCheckSyncService
+{
+    /**
+     * 拉取上传
+     * @param $item 剧集信息
+     * @param $accessToken 小程序accessToken
+     * @return  string task_id
+     * @throws \GuzzleHttp\Exception\GuzzleException
+     */
+    public static function pullupload($item, $accessToken) {
+        $url = 'https://api.weixin.qq.com/wxa/sec/vod/pullupload?access_token='.$accessToken;
+        $parsedContent = self::postWechat($url, [
+            'media_name' => $item->media_name,
+            'media_url' => $item->video_url
+        ]);
+        return $parsedContent['task_id'];
+    }
+
+    /**
+     * 获取微信短剧剧集的播放链接信息
+     * @param $seriesId
+     * @return mixed
+     * @throws \GuzzleHttp\Exception\GuzzleException
+     */
+    public static function getMedialinkInfo($seriesId) {
+        $syncInfo = DB::table('video_series_wechat_check')
+            ->where([
+                'series_id'=> $seriesId,
+                'sync_status' => 3,
+                'is_enabled' => 1,
+            ])->first();
+
+        if(!$syncInfo || !$syncInfo->media_id) {
+            CommonBusinessException::throwError(Errors::SYNC_WECHAT_NOT_OK);
+        }
+        $mediaId = $syncInfo->media_id;
+        $accessToken = WechatMiniprogramService::getDuanjuCheckAccessToken($syncInfo->appid);
+        $url = 'https://api.weixin.qq.com/wxa/sec/vod/getmedialink?access_token='.$accessToken;
+
+        $parsedContent = self::postWechat($url, [
+            'media_id' => $mediaId,
+            't' => time() + 7200,
+        ]);
+        return $parsedContent['media_info'];
+    }
+
+    public static function getWechatMediaLinkRedisKey($seriesId) {
+        return 'wechat.medialink.'.$seriesId;
+    }
+
+    public static function getTask($syncInfo) {
+        try {
+            $accessToken = WechatMiniprogramService::getDuanjuCheckAccessToken($syncInfo->appid);
+            $url = 'https://api.weixin.qq.com/wxa/sec/vod/gettask?access_token='.$accessToken;
+            $parsedContent = self::postWechat($url, [
+                'task_id' => $syncInfo->sync_task_id
+            ]);
+            return $parsedContent['task_info'];
+        } catch (\Exception $exception) {
+            return [];
+        }
+
+    }
+
+    /**
+     *  post 请求微信上游
+     * @param $url
+     * @param $data
+     * @throws \GuzzleHttp\Exception\GuzzleException
+     */
+    public static function postWechat($url, $data) {
+        $client = new Client(['timeout' => 3]);
+        $httpResult = $client->post($url, $data);
+
+        $httpStatus = $httpResult->getStatusCode();
+        if(200 != $httpStatus) {
+            CommonBusinessException::throwError(Errors::REQUEST_HTTP_STATUS_ERROR);
+        }
+        $httpContent = $httpResult->getBody()->getContents();
+        $parsedContent = \json_decode($httpContent, true);
+        if(0 != ($parsedContent['errcode'] ?? 0)) {
+            myLog('WechatCheckSync')->error('请求微信异常', [
+                'url' => $url,
+                'data' => $data,
+                'errMsg' => $httpContent
+            ]);
+            CommonBusinessException::throwError(Errors::REQUEST_CODE_STATUS_ERROR);
+        }
+
+        return $parsedContent;
+    }
+}

+ 12 - 0
modules/Video/routes/route.php

@@ -4,6 +4,8 @@ use Illuminate\Support\Facades\Route;
 use Modules\Video\Http\Controllers\EpisodeController;
 use Modules\Video\Http\Controllers\VideoCategoryController;
 use Modules\Video\Http\Controllers\VideoController;
+use Modules\Video\Http\Controllers\VideoSeriesWechatCheckController;
+use Modules\Video\Http\Controllers\WechatCheckController;
 
 Route::prefix('videoStock')->group(function () {
     Route::get('video/list', [VideoController::class, 'list']);
@@ -16,5 +18,15 @@ Route::prefix('videoStock')->group(function () {
     Route::post('video/add', [VideoController::class, 'add']);
     Route::post('video/setChargeConfig', [VideoController::class, 'setChargeConfig']);
     Route::post('episode/add', [EpisodeController::class, 'add']);
+
+    Route::prefix('wechatCheck')->group(function(){
+        Route::post('add', [WechatCheckController::class, 'add']);
+        Route::get('list', [WechatCheckController::class, 'list']);
+        Route::post('delete', [WechatCheckController::class, 'delete']);
+        Route::prefix('videoSeries')->group(function(){
+            Route::post('syncWechat', [VideoSeriesWechatCheckController::class, 'syncWechat']);
+        });
+    });
+
 });
 

+ 10 - 0
tests/Callback/Http/Controllers/JuliangAccountControllerTest.php

@@ -54,6 +54,7 @@ class JuliangAccountControllerTest extends UsedTestCase
             'Authorization' => 'Bearer '. $this->token,
         ])->json('get','http://localhost/api/callback/juliangAccount/list');
 
+        $res->dump();
         $this->dumpJson($res);
     }
 
@@ -66,4 +67,13 @@ class JuliangAccountControllerTest extends UsedTestCase
         ]);
         $res->dump();
     }
+
+    public function testunbindPromotion() {
+        $res = $this->withHeaders([
+            'Authorization' => 'Bearer '. $this->token,
+        ])->json('post','http://localhost/api/callback/juliangAccount/unbindPromotion', [
+            'id' => 5,
+        ]);
+        $res->dump();
+    }
 }

+ 17 - 0
tests/Common/Services/CommonConfigServiceTest.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace Tests\Common\Services;
+
+use Modules\Common\Services\CommonConfigService;
+use PHPUnit\Framework\TestCase;
+use Tests\UsedTestCase;
+
+class CommonConfigServiceTest extends UsedTestCase
+{
+
+    public function testGetFirstPageListTypeMap()
+    {
+        $res  = CommonConfigService::getFirstPageListTypeMap();
+        dump($res);
+    }
+}

+ 2 - 2
tests/UsedTestCase.php

@@ -13,11 +13,11 @@ abstract class UsedTestCase extends BaseTestCase
     {
         parent::setUp(); // TODO: Change the autogenerated stub
         $tokenInfo = $this->post('http://localhost/api/login', [
-            'email' => 'catch@admin.com',
+//            'email' => 'catch@admin.com',
             'remember' => false,
 //            'email' => 'xiaoli@qq.com',
             'password' => 'catchadmin',
-//            'email' => 'aa4@test.com',
+            'email' => 'aa4@test.com',
         ])->json();
         $this->token = $tokenInfo['data']['token'];
     }

+ 2 - 1
tests/Video/Http/Controllers/VideoControllerTest.php

@@ -62,7 +62,8 @@ class VideoControllerTest extends UsedTestCase
 //            'videoName' => '112',
 //        'updateType' => 2,
 //        'categoryId' => 4,
-            'operateUserId' =>10
+//            'operateUserId' =>10
+            'wechatPass' => ''
         ]);
 //        $this->dumpJson($res);
         $res->dump();

+ 22 - 0
tests/Video/Http/Controllers/VideoSeriesWechatCheckControllerTest.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace Tests\Video\Http\Controllers;
+
+use Modules\Video\Http\Controllers\VideoSeriesWechatCheckController;
+use PHPUnit\Framework\TestCase;
+use Tests\UsedTestCase;
+
+class VideoSeriesWechatCheckControllerTest extends UsedTestCase
+{
+
+    public function testSyncWechat()
+    {
+        $res = $this->withHeaders([
+            'Authorization' => 'Bearer '. $this->token,
+        ])->json('post','http://localhost/api/videoStock/wechatCheck/videoSeries/syncWechat', [
+            'series_ids' => [81,82,83,84,85],
+        ]);
+        $res->dump();
+        $this->dumpJson($res);
+    }
+}

+ 37 - 0
tests/Video/Http/Controllers/WechatCheckControllerTest.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace Tests\Video\Http\Controllers;
+
+use Modules\Video\Http\Controllers\WechatCheckController;
+use PHPUnit\Framework\TestCase;
+use Tests\UsedTestCase;
+
+class WechatCheckControllerTest extends UsedTestCase
+{
+
+    public function testAdd()
+    {
+        $res = $this->withHeaders([
+            'Authorization' => 'Bearer '. $this->token,
+        ])->json('post','http://localhost/api/videoStock/wechatCheck/add', [
+            'video_id' => 12,
+            'producer' => 'zzz',
+            'playwright' =>  'xxxx',
+            'production_license_img' => 'https://minifile-cdn.zvyhjkx.com/uploads/images/20230531/9NUcrj2Dfz1685513143.png',
+            'authorized_img' => 'https://minifile-cdn.zvyhjkx.com/uploads/images/20230531/9NUcrj2Dfz1685513143.png'
+        ]);
+        $res->dump();
+    }
+
+    public function testList()
+    {
+        $res = $this->withHeaders([
+            'Authorization' => 'Bearer '. $this->token,
+        ])->json('get','http://localhost/api/videoStock/wechatCheck/list', [
+            'video_id' => 12,
+            'producer' => 'zzz',
+            'playwright' =>  'xxxx',
+        ]);
+        $res->dump();
+    }
+}