zhaoyang 1 年間 前
コミット
7b4b35d465
42 ファイル変更1073 行追加236 行削除
  1. 83 0
      app/Console/Commands/Callback/JuliangAccountRateConfigRefresh.php
  2. 1 25
      app/Console/Kernel.php
  3. 2 1
      composer.json
  4. 215 0
      modules/Callback/Http/Controllers/JuliangAccountController.php
  5. 32 0
      modules/Callback/Installer.php
  6. 29 0
      modules/Callback/Providers/CallbackServiceProvider.php
  7. 10 0
      modules/Callback/README.md
  8. 13 0
      modules/Callback/routes/route.php
  9. 17 5
      modules/Channel/Http/Controllers/AdvertiserController.php
  10. 0 56
      modules/Channel/Http/Controllers/UserTrait.php
  11. 5 2
      modules/Common/Errors/Errors.php
  12. 38 0
      modules/Common/Http/Controllers/Qiniu/CallbackController.php
  13. 33 0
      modules/Common/Http/Controllers/Qiniu/ImageUploadController.php
  14. 25 0
      modules/Common/Services/Qiniu/QiniuTokenService.php
  15. 13 2
      modules/Common/config/common.php
  16. 24 0
      modules/Common/config/qiniu.php
  17. 9 0
      modules/Common/routes/route.php
  18. 2 1
      modules/ContentManage/Http/Controllers/CpSubscribeStatisticDataController.php
  19. 0 56
      modules/ContentManage/Http/Controllers/UserTrait.php
  20. 0 1
      modules/ContentManage/Middlewares/ContentManageGate.php
  21. 0 1
      modules/Permissions/Middlewares/PermissionGate.php
  22. 0 56
      modules/System/Http/Controllers/UserTrait.php
  23. 121 0
      modules/Tuiguang/Http/Controllers/PromotionController.php
  24. 32 0
      modules/Tuiguang/Installer.php
  25. 29 0
      modules/Tuiguang/Providers/TuiguangServiceProvider.php
  26. 10 0
      modules/Tuiguang/README.md
  27. 16 0
      modules/Tuiguang/routes/route.php
  28. 3 1
      modules/User/Http/Controllers/AuthController.php
  29. 11 3
      modules/Video/Http/Controllers/UserTrait.php
  30. 29 5
      modules/Video/Http/Controllers/EpisodeController.php
  31. 35 0
      modules/Video/Http/Controllers/VideoCategoryController.php
  32. 10 5
      modules/Video/Http/Controllers/VideoController.php
  33. 3 0
      modules/Video/routes/route.php
  34. 57 0
      tests/Callback/Http/Controllers/JuliangAccountControllerTest.php
  35. 1 1
      tests/Channel/Http/Controllers/AdvertiserControllerTest.php
  36. 27 0
      tests/Common/Http/Controllers/Qiniu/CallbackControllerTest.php
  37. 28 0
      tests/Common/Http/Controllers/Qiniu/ImageUploadControllerTest.php
  38. 75 0
      tests/Tuiguang/Http/Controllers/PromotionControllerTest.php
  39. 3 5
      tests/UsedTestCase.php
  40. 9 7
      tests/Video/Http/Controllers/EpisodeControllerTest.php
  41. 20 0
      tests/Video/Http/Controllers/VideoCategoryControllerTest.php
  42. 3 3
      tests/Video/Http/Controllers/VideoControllerTest.php

+ 83 - 0
app/Console/Commands/Callback/JuliangAccountRateConfigRefresh.php

@@ -0,0 +1,83 @@
+<?php
+
+namespace App\Console\Commands\Callback;
+
+use App\Modules\Advertiser\Models\AdvertiserPromotionConfigTime;
+use App\Modules\Advertiser\Models\TiktokAdvertiser;
+use App\Modules\Advertiser\Services\AdvertiserService;
+use App\Modules\Advertiser\Services\TimeConfigService;
+use Illuminate\Console\Command;
+use Illuminate\Support\Facades\DB;
+
+class JuliangAccountRateConfigRefresh extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'Callback:JuliangAccountRateConfigRefresh';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = '巨量账户级回传比例自动刷新';
+
+    /**
+     * Execute the console command.
+     */
+    public function handle(): void
+    {
+        $this->start();
+    }
+
+    public function start(){
+        $list = DB::table('juliang_account_promotion_config_time')
+            ->where('is_enable',1)->orderBy('id')->get();
+        foreach ($list as  $item) {
+            $is_exec = $this->timeThan($item->config_time);
+            if (!$is_exec || $item->next_exec_time != date("Y-m-d")) {
+                continue;
+            }
+            $this->setReportType($item);
+        }
+    }
+
+    /**
+     * 判断任务时间点和 当前的时间点比对
+     * @param  [type] $str [description]
+     * @return [type]      [description]
+     */
+    private function timeThan($str)
+    {
+        $config_time = strtotime(date('Y-m-d').' '.$str);
+        if (time() >= $config_time) {
+            return true;
+        }
+        return false;
+    }
+
+
+    public  function setReportType($item){
+        $now = date('Y-m-d H:i:s');
+        $res = DB::table('juliang_account_promotion_config_time')->where('id',$item->id)
+            ->update(['latest_exec_time'=> date('Y-m-d H:i:s',time()),
+                'next_exec_time'=>date("Y-m-d",strtotime('+1 day')),
+                'updated_at'  => $now]);
+        if ($res) {
+            DB::table('juliang_account_rate_config_log')
+                ->where(['company_uid' => $item->company_uid, 'account_id' => $item->account_id, 'is_enabled' => 1])
+                ->update(['is_enabled' => 0, 'updated_at' => $now]);
+            DB::table('juliang_account_rate_config_log')
+                ->insert([
+                    'company_uid' => $item->company_uid,
+                    'account_id' => $item->account_id,
+                    'config_per' => $item->config_per,
+                    'created_at' => $now,
+                    'updated_at' => $now,
+                ]);
+        }
+    }
+}

+ 1 - 25
app/Console/Kernel.php

@@ -15,31 +15,7 @@ class Kernel extends ConsoleKernel
      */
     protected function schedule(Schedule $schedule)
     {
-        // $schedule->command('inspire')->hourly();
-        /**
-         * 从掌维同步cp订阅统计数据
-         */
-        $schedule->command('ContentManage:SyncCpSubscribeStatisticDataFromZW')->dailyAt('13:00');
-        /**
-         * cp结算月统计
-         */
-        $schedule->command('ContentManage:CpSubscribeMonthStatisticData', [
-            '--month' => date_sub(date_create(), date_interval_create_from_date_string('1 month'))->format('Y-m')
-        ])->monthlyOn(1, '15:00');
-        /**
-         * 版权到期通知,每周一上午9点执行.
-         */
-        $schedule->command('ContentManage:BookCopyrightAlert')->weekly()->mondays()->at('09:00');
-        /**
-         * 新的cp方书籍进入内容中台, 通知
-         */
-        $schedule->command('ContentManage:NewCpBookComeIn')->dailyAt("08:30");
-        /**
-         * 保存书籍结算模式
-         */
-        $schedule->command('ContentManage:SaveBookSettlementMode')->daily();
-
-        $schedule->command('ContentManage:cpcollection')->everyMinute();
+        $schedule->command('Callback:JuliangAccountRateConfigRefresh')->everyMinute();
     }
 
     /**

+ 2 - 1
composer.json

@@ -20,6 +20,7 @@
         "phpoffice/phpexcel": "^1.8",
         "phpoffice/phpspreadsheet": "^1.28",
         "predis/predis": "^2.1",
+        "qiniu/php-sdk": "^7.4",
         "vinkla/hashids": "*"
     },
     "require-dev": {
@@ -76,4 +77,4 @@
     },
     "minimum-stability": "dev",
     "prefer-stable": true
-}
+}

+ 215 - 0
modules/Callback/Http/Controllers/JuliangAccountController.php

@@ -0,0 +1,215 @@
+<?php
+
+namespace Modules\Callback\Http\Controllers;
+
+use Catch\Base\CatchController;
+use Illuminate\Foundation\Validation\ValidatesRequests;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\DB;
+use Modules\Common\Errors\Errors;
+use Modules\Common\Exceptions\CommonBusinessException;
+use Modules\User\Http\Controllers\UserTrait;
+
+class JuliangAccountController extends CatchController
+{
+    use UserTrait;
+    use ValidatesRequests;
+
+    public function list(Request $request) {
+        $advAccountId = $request->input('account_id');
+        $advAccountName = $request->input('account_name');
+
+        return DB::table('juliang_account_callback_config')
+            ->where(['company_uid' => $this->getCompanyUid()])
+            ->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. '%');
+            })
+            ->paginate($request->input('limit', 30));
+    }
+
+    public function addAccount(Request $request) {
+        $this->validate($request, [
+            'account_id' => 'required',
+            'account_name' => 'required|string|max:64',
+            'callback_state' => 'required|integer|in:0,1',
+            'protect_num' => 'required|integer|min:0',
+            'default_rate' => 'required|min:0|max:100',
+            'rate_time_config' => 'nullable|array',
+            'min_money' => 'required|min:0',
+            'max_money' => 'required|min:0'
+        ]);
+
+        if(DB::table('juliang_account_callback_config')
+            ->where(['company_uid' => $this->getCompanyUid(), 'adv_account_id' => $request->input('account_id')])
+            ->exists()) {
+            CommonBusinessException::throwError(Errors::JULIANG_ACCOUNT_EXISTS);
+        }
+        if($request->input('rate_time_config') &&
+            !$this->is_time_cross($request->input('rate_time_config'))) {
+            CommonBusinessException::throwError(Errors::CALLBACK_RATE_TIME_RANGE_ERROR);
+        }
+        $now = date('Y-m-d H:i:s');
+        DB::table('juliang_account_callback_config')
+            ->insert([
+                'adv_account_id' => $request->input('account_id'),
+                'adv_account_name' => $request->input('account_name'),
+                'state' => $request->input('state'),
+                'protect_num' => $request->input('protect_num'),
+                'default_rate' => $request->input('default_rate'),
+                'rate_time_config' => \json_encode($request->input('rate_time_config', [])),
+                'min_money' => $request->input('min_money'),
+                'max_money' => $request->input('max_money'),
+                'company_uid' => $this->getCompanyUid(),
+                'created_at' => $now,
+                'updated_at' => $now,
+            ]);
+        DB::table('juliang_account_rate_config_log')
+            ->insert([
+                'company_uid' => $this->getCompanyUid(),
+                'account_id' => $request->input('account_id'),
+                'config_per' => $request->input('default_rate'),
+                'created_at' => $now,
+                'updated_at' => $now,
+            ]);
+        if($request->input('rate_time_config')) {
+            $this->saveTimeConfig($this->getCompanyUid(), $request->input('account_id'), $request);
+        }
+        return 'ok';
+    }
+
+    public function updateCallbackConfig(Request $request) {
+        $this->validate($request, [
+            'ids' => 'required|array',
+            'state' => 'required|integer|in:0,1',
+            'protect_num' => 'required|integer|min:0',
+            'default_rate' => 'required|min:0|max:100',
+            'rate_time_config' => 'nullable|array',
+            'min_money' => 'required|min:0',
+            'max_money' => 'required|min:0'
+        ]);
+        if($request->input('callback_rate_time_config') &&
+            !$this->is_time_cross($request->input('rate_time_config'))) {
+            CommonBusinessException::throwError(Errors::CALLBACK_RATE_TIME_RANGE_ERROR);
+        }
+        $now = date('Y-m-d H:i:s');
+        foreach ($request->input('ids') as $id) {
+            DB::table('juliang_account_callback_config')
+                ->where(['id' => $id, 'company_uid' => $this->getCompanyUid()])
+                ->update([
+                    'state' => $request->input('state'),
+                    'protect_num' => $request->input('protect_num'),
+                    'default_rate' => $request->input('default_rate'),
+                    'rate_time_config' => \json_encode($request->input('rate_time_config', [])),
+                    'min_money' => $request->input('min_money'),
+                    'max_money' => $request->input('max_money'),
+                    'updated_at' => $now,
+                ]);
+        }
+        $advAccountIds = DB::table('juliang_account_callback_config')
+            ->whereIn('id', $request->input('ids'))
+            ->where('company_uid', $this->getCompanyUid())
+            ->select('adv_account_id')->get()->pluck('adv_account_id');
+        if($advAccountIds->isNotEmpty()) {
+            DB::table('juliang_account_rate_config_log')
+                ->where('company_uid', $this->getCompanyUid())
+                ->whereIn('account_id', $advAccountIds)
+                ->where('is_enabled', 1)
+                ->update(['is_enabled' => 0, 'updated_at' => $now]);
+            foreach ($advAccountIds as $accountId) {
+                DB::table('juliang_account_rate_config_log')
+                    ->insert([
+                        'company_uid' => $this->getCompanyUid(),
+                        'account_id' => $accountId,
+                        'config_per' => $request->input('default_rate'),
+                        'created_at' => $now,
+                        'updated_at' => $now,
+                    ]);
+                $this->saveTimeConfig($this->getCompanyUid(), $accountId, $request);
+            }
+        }
+
+        return 'ok';
+    }
+
+    /**
+     * 判断时 设置的时间范围是否有交集
+     *
+     * @param string $config_time 开始时间1
+     * @return bool
+     */
+    protected  function is_time_cross($config_time) {
+        $timeline = [];
+        foreach ($config_time as $key => $value) {
+            $start_time = $value['start_time'];
+            $start = explode(':', $start_time);
+            $cur_start = (int)$start[0] * 60 + $start[1];
+            $end_time = $value['end_time'];
+
+            $end = explode(':', $end_time);
+            $cur_end = (int)$end[0] * 60 + $end[1];
+            if ($cur_end <= $cur_start) {
+                return false;
+            }
+
+            if ($timeline) {
+                foreach ($timeline as $k => $v) {
+                    if ($cur_start >= $v['start'] && $cur_start <= $v['end']) {
+                        return false;
+                    }
+                    if ($cur_end >= $v['start'] && $cur_end <= $v['end']) {
+                        return false;
+                    }
+                }
+            }
+            $timeline[] = ['start'=>$cur_start,'end'=>$cur_end];
+        }
+        return true;
+    }
+
+
+    public  function saveTimeConfig($companyUid, $accountId, $configInfo )
+    {
+        DB::table('juliang_account_promotion_config_time')
+            ->where('is_enable',1)
+            ->where('company_uid',$companyUid)
+            ->where('account_id',$accountId)->update(['is_enable'=>0]);
+        $time_config = $configInfo['rate_time_config'];
+        if (empty($time_config)) {
+            return false;
+        }
+        $is = $this->is_time_cross($time_config);
+        if (!$is) {
+            return false;
+        }
+        $data = [];
+        $temp['company_uid'] = $companyUid;
+
+        $temp['account_id'] = $accountId;
+        $temp['other_data']['default_rate'] = $configInfo['default_rate'];
+        $temp['other_data']['min_money'] = $configInfo['min_money'];
+        $temp['other_data']['max_money'] = $configInfo['max_money'];
+        $temp['other_data']['protect_num'] = $configInfo['protect_num'];
+        $temp['other_data']['state'] = $configInfo['state'];
+        $temp['other_data'] = json_encode($temp['other_data']);
+        $temp['next_exec_time'] = date('Y-m-d');
+
+        $temp['is_enable'] = 1;
+        $temp['created_at'] = date('Y-m-d H:i:s',time());
+
+        foreach ($time_config as $value) {
+            $start_time = $value['start_time'];
+            $end_time = $value['end_time'];
+            $temp['config_time'] = $start_time;
+            $temp['config_per'] = $value['config_per'];
+            $data[] = $temp;
+            //结束后 百分比改为默认的
+            $temp['config_time'] = $end_time;
+            $temp['config_per'] = $configInfo['default_rate'];
+            $data[] = $temp;
+        }
+        //插入设置最新的时间段百分比
+        DB::table('juliang_account_promotion_config_time')->insert($data);
+    }
+}

+ 32 - 0
modules/Callback/Installer.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace Modules\ContentManage;
+
+use Catch\Support\Module\Installer as ModuleInstaller;
+use Modules\ContentManage\Providers\ContentManageServiceProvider;
+
+class Installer extends ModuleInstaller
+{
+    protected function info(): array
+    {
+        // TODO: Implement info() method.
+        return [
+            'title' => '内容中台',
+            'name' => 'contentManage',
+            'path' => 'contentManage',
+            'keywords' => '内容中台',
+            'description' => '内容中台管理模块',
+            'provider' => ContentManageServiceProvider::class
+        ];
+    }
+
+    protected function requirePackages(): void
+    {
+        // TODO: Implement requirePackages() method.
+    }
+
+    protected function removePackages(): void
+    {
+        // TODO: Implement removePackages() method.
+    }
+}

+ 29 - 0
modules/Callback/Providers/CallbackServiceProvider.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace Modules\Callback\Providers;
+
+use Catch\Providers\CatchModuleServiceProvider;
+
+class CallbackServiceProvider extends CatchModuleServiceProvider
+{
+    /**
+     * middlewares
+     *
+     * @return string[]
+     */
+    protected function middlewares(): array
+    {
+       return [];
+    }
+
+    /**
+     * route path
+     *
+     * @return string|array
+     */
+    public function moduleName(): string|array
+    {
+        // TODO: Implement path() method.
+        return 'callback';
+    }
+}

+ 10 - 0
modules/Callback/README.md

@@ -0,0 +1,10 @@
+#内容中台管理模块
+关于内容中台 相关的后台接口,对外api接口,都写在这里
+配置文件放在: config目录下,读取配置文件示例:config('contentManage.zhushuyunpublicapi.public_domain');
+config("模块名.配置文件名.配置项");
+
+数据库模型文件放在:Models 目录下面
+服务层文件放在:Services 目录下面
+控制器放在:modules/ContentManage/Http/Controllers 目录下面
+中间件放在:modules/ContentManage/Middlewares 目录下面
+路由只能现在 modules/ContentManage/rout/route.php 文件里

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

@@ -0,0 +1,13 @@
+<?php
+
+use Illuminate\Support\Facades\Route;
+use Modules\Callback\Http\Controllers\JuliangAccountController;
+
+Route::prefix('callback')->group(function () {
+    Route::prefix('juliangAccount')->group(function(){
+        Route::get('list', [JuliangAccountController::class, 'list']);
+        Route::post('addAccount', [JuliangAccountController::class, 'addAccount']);
+        Route::post('updateCallbackConfig', [JuliangAccountController::class, 'updateCallbackConfig']);
+    });
+});
+

+ 17 - 5
modules/Channel/Http/Controllers/AdvertiserController.php

@@ -8,11 +8,13 @@ use Illuminate\Http\Request;
 use Illuminate\Support\Facades\DB;
 use Modules\Channel\Exceptions\ChannelBusinessException;
 use Modules\Common\Errors\Errors;
+use Modules\User\Http\Controllers\UserTrait;
 use Modules\User\Models\User;
 
 class AdvertiserController extends CatchController
 {
     use ValidatesRequests;
+    use UserTrait;
     public function __construct(
         protected readonly User $user
     ) {
@@ -70,13 +72,19 @@ class AdvertiserController extends CatchController
         $miniProgramId = $request->input('miniProgramId');
         $email = $request->input('email');
         $username = $request->input('username');
+        $userContext = $this->getUserContext(null);
         $res =   DB::table('users')
             ->join('user_has_miniprograms', 'users.id', 'user_has_miniprograms.uid')
             ->where([
                 'user_has_miniprograms.is_enabled' => 1,
                 'users.deleted_at' => 0,
-                'users.pid' => $this->getLoginUserId()
-            ])->when($email, function ($query, $email) {
+            ])->when($userContext['loginUserRoles']->contains('company'), function ($query) use($userContext){
+                return $query->where('users.pid' , $userContext['loginUser']->id);
+            })
+            ->when($userContext['loginUserRoles']->contains('optimizer'), function ($query) use ($userContext){
+                return $query->where('users.id', $userContext['loginUser']->id);
+            })
+            ->when($email, function ($query, $email) {
                 return $query->where('users.email', $email);
             })->when($miniProgramId, function ($query, $miniProgramId){
                 return $query->where('user_has_miniprograms.miniprogram_id', $miniProgramId);
@@ -90,12 +98,13 @@ class AdvertiserController extends CatchController
                 DB::raw("NULL as miniPrograms")
             )->groupBy('users.id')
             ->orderBy('users.id','desc')
-            ->paginate($request->input('per_page', 15));
+            ->paginate($request->input('limit', 15));
         $miniProgramIds = collect();
         collect($res->items())->pluck('miniProgramIds')->each(function ($item) use (&$miniProgramIds) {
             $miniProgramIds = $miniProgramIds->merge(explode(',', $item));
         });
         $logos = config('common.common.logos');
+        $moduleMap = config('common.common.moduleMap');
         if($miniProgramIds->count()) {
             $miniPrograms = DB::table('miniprogram')->whereIn('id', $miniProgramIds->unique())
                 ->select('id', 'name', 'type')
@@ -104,8 +113,11 @@ class AdvertiserController extends CatchController
                 $item->miniPrograms = [];
                 foreach (explode(',', $item->miniProgramIds) as $miniProgramId) {
                     $miniProgram = $miniPrograms->get($miniProgramId);
-                    $miniProgram->type_logo = $logos[$miniProgram->type] ?? '';
-                    $item->miniPrograms[] = $miniProgram;
+                    if($miniProgram) {
+                        $miniProgram->type_logo = $logos[$miniProgram->type ?? -1] ?? '';
+                        $miniProgram->app_name = $moduleMap[$miniProgram->type ?? -1] ?? '';
+                        $item->miniPrograms[] = $miniProgram;
+                    }
                 }
             }
         }

+ 0 - 56
modules/Channel/Http/Controllers/UserTrait.php

@@ -1,56 +0,0 @@
-<?php
-
-namespace Modules\ContentManage\Http\Controllers;
-
-use Catch\Base\CatchController;
-use Illuminate\Support\Collection;
-use Illuminate\Support\Facades\DB;
-use Modules\User\Models\User;
-
-trait UserTrait
-{
-    // 当前登录用户
-    protected $currentUser;
-
-    /**
-     * 获取当前登录用户
-     * @return User
-     */
-    protected function getCurrentUser(): User {
-        if(!$this->currentUser) {
-            $this->currentUser = $this->getLoginUser();
-        }
-        return $this->currentUser;
-    }
-    /**
-     * 当前用户的所有的角色标识的结合
-     * @return Collection
-     */
-    protected function listUserRoles():Collection {
-        return $this->getCurrentUser()->roles->pluck('identify');
-    }
-
-    /**
-     * 当前用户是否是cp角色
-     * @return bool
-     */
-    public function userIsCp():bool {
-        return $this->listUserRoles()->contains('cp');
-    }
-
-    /**
-     * 如果当前用户是cp角色,返回cp_name,否则返回null
-     * @return string
-     */
-    public function getUserCpName():string|null {
-        if($this->userIsCp()) {
-            return DB::table('user_belong_to_cp')
-                ->where([
-                    'is_enabled' => 1,
-                    'user_id' => $this->getCurrentUser()->id,
-                ])->value('cp_name');
-        } else {
-            return null;
-        }
-    }
-}

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

@@ -8,12 +8,15 @@ class Errors
     public const  USER_NOT_FOUND= [500002, '用户不存在'];
     public const  PARAM_EMPTY= [500003, '缺少参数'];
     public const  PARAM_ERROR= [500004, '参数错误'];
-    public const  NO_OPERATE_PERMISSION= [500003, '用户无操作权限'];
-    public const  VIDEO_NOT_EXISTS= [500004, '视频不存在'];
+    public const  NO_OPERATE_PERMISSION= [500007, '用户无操作权限'];
+    public const  VIDEO_NOT_EXISTS= [500008, '视频不存在'];
     public const  MINIPROGRAM_STATUS_ERROR= [500005, '小程序未启用'];
     public const  PAY_TEMPLATE_EXISTS_ERROR= [500006, '充值模板已经存在'];
     public const  PAY_TEMPLATE_GIVEN_TOO_MUCH= [500007, '赠送不能超过金额3倍'];
     public const  PAY_TEMPLATE_NOT_EXISTS_ERROR= [500008, '充值模板不存在'];
     public const  PAY_TEMPLATE_CONFLICT= [500008, '该档位已存在'];
     public const  PAY_TEMPLATE_OPTIONS_ERROR= [500009, '类型不存在'];
+    public const  UPLOAD_IMAGE_ERROR= [500006, '上传图片不成功'];
+    public const  JULIANG_ACCOUNT_EXISTS= [500101, '巨量广告账户已经存在'];
+    public const  CALLBACK_RATE_TIME_RANGE_ERROR= [500102, '回传比例时间区间不合法'];
 }

+ 38 - 0
modules/Common/Http/Controllers/Qiniu/CallbackController.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace Modules\Common\Http\Controllers\Qiniu;
+
+use Illuminate\Http\Request;
+use Modules\Common\Services\Qiniu\QiniuTokenService;
+use Qiniu\Auth;
+
+class CallbackController
+{
+    public function uploadToken(Request $request) {
+        $qiniuConfig = config('common.qiniu');
+
+        $auth = new Auth($qiniuConfig['accessKey'], $qiniuConfig['secretKey']);
+        $expires = 7200;
+        $policy  = [
+            'scope' => $qiniuConfig['bucket'],
+            'callbackUrl' => config('common.common.duanjuManageDomain') . '/api/qiniu/upload/callback',
+            'callbackBody' => '{"hash":"$(etag)","key":"$(key)", "fname":"$(fname)", "fprefix":"$(fprefix)" ,"duration":"$(avinfo.video.duration)"}',
+            'callbackBodyType' => 'application/json',
+            'forceSaveKey' => true,
+            'saveKey' => 'duanju/$(x:video_id)/$(etag)$(ext)',
+        ];
+        $upToken = $auth->uploadToken($qiniuConfig['bucket'], null, $expires, $policy, true);
+        return $upToken;
+    }
+
+    public function callback(Request $request) {
+        $allInfo = $request->only(['duration', 'fname', 'hash', 'key', 'fprefix']);
+        $videoUrl = config('common.qiniu.publicVideoLinkDomain') . DIRECTORY_SEPARATOR . $allInfo['key'];
+        $publicVideoUrl = QiniuTokenService::getPrivateSourceDownloadUrl($videoUrl);
+        $allInfo['public_video_url'] = $publicVideoUrl;
+        $allInfo['url'] = $videoUrl;
+        $allInfo['name'] = $allInfo['fprefix'];
+
+        return $allInfo;
+    }
+}

+ 33 - 0
modules/Common/Http/Controllers/Qiniu/ImageUploadController.php

@@ -0,0 +1,33 @@
+<?php
+
+namespace Modules\Common\Http\Controllers\Qiniu;
+
+use Catch\Base\CatchController;
+use Illuminate\Http\Request;
+use Illuminate\Support\Str;
+use Modules\Common\Errors\Errors;
+use Modules\Common\Exceptions\CommonBusinessException;
+use Qiniu\Auth;
+use Qiniu\Storage\UploadManager;
+
+class ImageUploadController extends CatchController
+{
+    public function uploadImage(Request $request) {
+        $file = $request->photo;
+        $qiniuConfig = config('common.qiniu');
+
+        $auth = new Auth($qiniuConfig['accessKey'], $qiniuConfig['secretKey']);
+        $token = $auth->uploadToken(config('common.qiniu.publicBucket'));
+        $filePath = $file->path();
+        $key = 'uploads'.DIRECTORY_SEPARATOR.'images'. DIRECTORY_SEPARATOR . date('Ymd') .
+            DIRECTORY_SEPARATOR. Str::random(10) . time() . '.'. $file->extension();
+        $uploadMgr = new UploadManager();
+        list($ret, $err) =  $uploadMgr->putFile($token, $key, $filePath, null, 'application/octet-stream',
+            true, null, 'v2');
+        if($err !== null) {
+            CommonBusinessException::throwError(Errors::UPLOAD_IMAGE_ERROR);
+        } else {
+            return $qiniuConfig['publicLinkDomain']. DIRECTORY_SEPARATOR . $key;
+        }
+    }
+}

+ 25 - 0
modules/Common/Services/Qiniu/QiniuTokenService.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace Modules\Common\Services\Qiniu;
+
+use Qiniu\Auth;
+
+class QiniuTokenService
+{
+    /**
+     * 获取私有资源的公开访问链接
+     * ----说明-----
+     * 如果将一个资源,例如一张图片存在七牛云的私有空间中,是没有办法直接通过公网访问的.
+     * 将一个域名绑定到这个私有空间后,那么空间中的资源便有了对应的私有资源链接,但此时还是需要通过生成token
+     * 追加到私有资源链接后面的形式才可以对私有资源进行有限制时间的访问
+     * @param $url 私有资源链接
+     * @param int $expires 公开访问链接有效时间
+     * @return string 公开访问链接
+     */
+    public static function getPrivateSourceDownloadUrl($url, $expires = 3600) {
+        $qiniuConfig = config('common.qiniu');
+        $auth = new Auth($qiniuConfig['accessKey'], $qiniuConfig['secretKey']);
+        $url = $auth->privateDownloadUrl($url, $expires);
+        return $url;
+    }
+}

+ 13 - 2
modules/Common/config/common.php

@@ -2,8 +2,19 @@
 
 return [
     'logos' => [
-        'BYTECODE' => 'https://zhuishuyun.oss-cn-hangzhou.aliyuncs.com/channel/logo/DOUYIN.png',
-        'WEIXIN' => 'https://zhuishuyun.oss-cn-hangzhou.aliyuncs.com/channel/logo/WEIXIN.png',
+        '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',
+    ],
+    /**
+     * 短剧管理后台的域名
+     */
+    'duanjuManageDomain' => env('COMMON_DUANJU_MANAGE_DOMAIN', 'http://m.test.duanju.dududus.com'),
+    /**
+     * 模块和小程序type值的映射
+     */
+    'moduleMap' => [
+        '1' => 'weixin',
+        '2' => 'douyin',
     ]
 ];

+ 24 - 0
modules/Common/config/qiniu.php

@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * 七牛云相关配置
+ */
+return [
+    'accessKey' => env('QINIU_ACCESS_KEY', '0KPbNSpF0svREUWzxYn33FydQpcDCiYun2HLdtQ7'),
+    'secretKey' => env('QINIU_SECRET_KEY', 'VkA1ej1bFzPK-N-B-H_IHt6I0Z2RYRU_ivvn7ObR'),
+    'bucket' => env('QINIU_BUCKET', 'zyduanju'),
+    'publicBucket' => env('QINIU_PUBLIC_BUCKET', 'zyduanju-public'),
+    /**
+     * 资源链接域名
+     */
+    'linkDomain' => env('QINIU_LINK_DOMAIN', 'http://video-cdn.zvyhjkx.com'),
+    'publicLinkDomain' => env('QINIU_PUBLIC_LINK_DOMAIN', 'http://rufar0l49.hd-bkt.clouddn.com'),
+    /**
+     * 公开视频资源域名
+     */
+    'publicVideoLinkDomain' => env('QINIU_PUBLIC_VIDEO_LINK_DOMAIN', 'http://video-cdn.zvyhjkx.com'),
+    /**
+     * 下载使用的资源域名
+     */
+    'downloadVideoLinkDomain' => env('QINIU_DOWNLOAD_VIDEO_LINK_DOMINA', 'http://video-cdn.zvyhjkx.com'),
+];

+ 9 - 0
modules/Common/routes/route.php

@@ -3,6 +3,8 @@
 use Illuminate\Support\Facades\Route;
 use Modules\Common\Http\Controllers\ModuleController;
 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;
 
 /*
@@ -27,4 +29,11 @@ Route::controller(UploadController::class)->group(function (){
 
 Route::get('modules/listApp', [ModuleController::class, 'listApp']);
 
+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']);
+});
+
 

+ 2 - 1
modules/ContentManage/Http/Controllers/CpSubscribeStatisticDataController.php

@@ -10,7 +10,8 @@ use Illuminate\Support\Facades\DB;
 
 class CpSubscribeStatisticDataController extends CatchController
 {
-    use ValidatesRequests, UserTrait;
+    use ValidatesRequests;
+    use \Modules\User\Http\Controllers\UserTrait;
 
 
     /**

+ 0 - 56
modules/ContentManage/Http/Controllers/UserTrait.php

@@ -1,56 +0,0 @@
-<?php
-
-namespace Modules\ContentManage\Http\Controllers;
-
-use Catch\Base\CatchController;
-use Illuminate\Support\Collection;
-use Illuminate\Support\Facades\DB;
-use Modules\User\Models\User;
-
-trait UserTrait
-{
-    // 当前登录用户
-    protected $currentUser;
-
-    /**
-     * 获取当前登录用户
-     * @return User
-     */
-    protected function getCurrentUser(): User {
-        if(!$this->currentUser) {
-            $this->currentUser = $this->getLoginUser();
-        }
-        return $this->currentUser;
-    }
-    /**
-     * 当前用户的所有的角色标识的结合
-     * @return Collection
-     */
-    protected function listUserRoles():Collection {
-        return $this->getCurrentUser()->roles->pluck('identify');
-    }
-
-    /**
-     * 当前用户是否是cp角色
-     * @return bool
-     */
-    public function userIsCp():bool {
-        return $this->listUserRoles()->contains('cp');
-    }
-
-    /**
-     * 如果当前用户是cp角色,返回cp_name,否则返回null
-     * @return string
-     */
-    public function getUserCpName():string|null {
-        if($this->userIsCp()) {
-            return DB::table('user_belong_to_cp')
-                ->where([
-                    'is_enabled' => 1,
-                    'user_id' => $this->getCurrentUser()->id,
-                ])->value('cp_name');
-        } else {
-            return null;
-        }
-    }
-}

+ 0 - 1
modules/ContentManage/Middlewares/ContentManageGate.php

@@ -20,7 +20,6 @@ class ContentManageGate
         if (! $user->can()) {
             throw new PermissionForbidden();
         }
-
         return $next($request);
     }
 }

+ 0 - 1
modules/Permissions/Middlewares/PermissionGate.php

@@ -20,7 +20,6 @@ class PermissionGate
         if (! $user->can()) {
             throw new PermissionForbidden();
         }
-
         return $next($request);
     }
 }

+ 0 - 56
modules/System/Http/Controllers/UserTrait.php

@@ -1,56 +0,0 @@
-<?php
-
-namespace Modules\ContentManage\Http\Controllers;
-
-use Catch\Base\CatchController;
-use Illuminate\Support\Collection;
-use Illuminate\Support\Facades\DB;
-use Modules\User\Models\User;
-
-trait UserTrait
-{
-    // 当前登录用户
-    protected $currentUser;
-
-    /**
-     * 获取当前登录用户
-     * @return User
-     */
-    protected function getCurrentUser(): User {
-        if(!$this->currentUser) {
-            $this->currentUser = $this->getLoginUser();
-        }
-        return $this->currentUser;
-    }
-    /**
-     * 当前用户的所有的角色标识的结合
-     * @return Collection
-     */
-    protected function listUserRoles():Collection {
-        return $this->getCurrentUser()->roles->pluck('identify');
-    }
-
-    /**
-     * 当前用户是否是cp角色
-     * @return bool
-     */
-    public function userIsCp():bool {
-        return $this->listUserRoles()->contains('cp');
-    }
-
-    /**
-     * 如果当前用户是cp角色,返回cp_name,否则返回null
-     * @return string
-     */
-    public function getUserCpName():string|null {
-        if($this->userIsCp()) {
-            return DB::table('user_belong_to_cp')
-                ->where([
-                    'is_enabled' => 1,
-                    'user_id' => $this->getCurrentUser()->id,
-                ])->value('cp_name');
-        } else {
-            return null;
-        }
-    }
-}

+ 121 - 0
modules/Tuiguang/Http/Controllers/PromotionController.php

@@ -0,0 +1,121 @@
+<?php
+
+namespace Modules\Tuiguang\Http\Controllers;
+
+use Catch\Base\CatchController;
+use Illuminate\Foundation\Validation\ValidatesRequests;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\DB;
+use Modules\Common\Errors\Errors;
+use Modules\Common\Exceptions\CommonBusinessException;
+use Modules\User\Http\Controllers\UserTrait;
+
+class PromotionController extends CatchController
+{
+    use UserTrait;
+    use ValidatesRequests;
+
+    public function list(Request $request) {
+        $callbackTypeMap = [
+            '0' => '无',
+            '1' => '巨量账户级回传',
+        ];
+        $name = $request->input('name');
+        $isConfig = $request->input('is_config', 1);
+        $id = $request->input('id');
+        $videoName = $request->input('video_name');
+        $starTime = $request->input('start_time');
+        $endTime = $request->input('endTime');
+        $miniprogramId = $request->input('miniprogram_id');
+        $result = DB::table('promotions')
+            ->leftJoin('videos', 'videos.id', '=', 'promotions.video_id')
+            ->where(['promotions.is_enabled' => 1, 'promotions.uid' => $this->getLoginUserId()])
+            ->when($miniprogramId, function ($query, $miniprogramId) {
+                return $query->where('promotions.miniprogram_id', $miniprogramId);
+            })
+            ->when($isConfig, function ($query) {
+                return $query->where('promotions.callback_config_id', '<>', 0);
+            }, function ($query) {
+                return $query->where('promotions.callback_config_id', 0);
+            })->when($name, function ($query, $name){
+                return $query->where('promotions.name', 'like', '%'. $name . '%');
+            })->when($id, function ($query, $id) {
+                return $query->where('promotions.id', $id);
+            })->when($videoName, function ($query, $videoName) {
+                return $query->where('videos.name', 'like', '%'. $videoName . '%');
+            })->when($starTime, function ($query, $startTime) {
+                return $query->where('promotions.created_at', '>=', $startTime);
+            })->when($endTime, function ($query, $endTime){
+                return $query->where('promotions.created_at', '<=', $endTime);
+            })->select('promotions.id', 'promotions.name', 'promotions.created_at',
+            'videos.name as video_name', 'promotions.series_sequence', 'promotions.callback_type', 'promotions.callback_config_id')
+            ->paginate($request->input('limit', 15));
+        foreach ($result as $item) {
+            $item->callback_type_str = $callbackTypeMap[$item->callback_type] ?? '';
+            // todo: 待完善
+            $item->promotion_path = '';
+            $item->track_url = '';
+        }
+
+        return $result;
+
+    }
+
+    public function delete(Request $request) {
+        $this->validate($request, ['id' => 'required']);
+
+        DB::table('promotions')
+            ->where(['id' => $request->input('id'), 'uid' => $this->getLoginUserId(), 'is_enabled' => 1])
+            ->update(['is_enabled' => 0, 'updated_at' => date('Y-m-d H:i:s')]);
+
+        return 'ok';
+    }
+
+    public function updateSeriesSequence(Request $request) {
+        $this->validate($request, ['id' => 'required', 'series_sequence' => 'required']);
+
+        DB::table('promotions')
+            ->where(['id' => $request->input('id'), 'uid' => $this->getLoginUserId(), 'is_enabled' => 1])
+            ->update(['series_sequence' => $request->input('series_sequence')
+                , 'updated_at' => date('Y-m-d H:i:s')]);
+
+        return 'ok';
+    }
+
+    public function add(Request $request) {
+        $this->validate($request, [
+            'video_id' => 'required',
+            'series_sequence' => 'required',
+            'name' => 'required',
+            'miniprogram_id' => 'required',
+        ]);
+        $now = date('Y-m-d H:i:s');
+        DB::table('promotions')
+            ->insert([
+                'uid' => $this->getLoginUserId(),
+                'miniprogram_id' => $request->input('miniprogram_id'),
+                'name' => $request->input('name'),
+                'video_id' => $request->input('video_id'),
+                'series_sequence' =>  $request->input('series_sequence'),
+                'created_at' => $now,
+                'updated_at' => $now,
+            ]);
+        return 'ok';
+    }
+
+    public function updateCallbackConfig(Request $request) {
+        $this->validate($request, [
+            'id' => 'required',
+            'callback_type' => 'required|in:1',
+            'callback_config_id' => 'required'
+        ]);
+        DB::table('promotions')
+            ->where(['id' => $request->input('id'), 'uid' => $this->getLoginUserId(), 'is_enabled' => 1])
+            ->update([
+                'callback_type' => $request->input('callback_type'),
+                'callback_config_id' => $request->input('callback_config_id'),
+                'updated_at' => date('Y-m-d')
+            ]);
+        return 'ok';
+    }
+}

+ 32 - 0
modules/Tuiguang/Installer.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace Modules\ContentManage;
+
+use Catch\Support\Module\Installer as ModuleInstaller;
+use Modules\ContentManage\Providers\ContentManageServiceProvider;
+
+class Installer extends ModuleInstaller
+{
+    protected function info(): array
+    {
+        // TODO: Implement info() method.
+        return [
+            'title' => '内容中台',
+            'name' => 'contentManage',
+            'path' => 'contentManage',
+            'keywords' => '内容中台',
+            'description' => '内容中台管理模块',
+            'provider' => ContentManageServiceProvider::class
+        ];
+    }
+
+    protected function requirePackages(): void
+    {
+        // TODO: Implement requirePackages() method.
+    }
+
+    protected function removePackages(): void
+    {
+        // TODO: Implement removePackages() method.
+    }
+}

+ 29 - 0
modules/Tuiguang/Providers/TuiguangServiceProvider.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace Modules\Tuiguang\Providers;
+
+use Catch\Providers\CatchModuleServiceProvider;
+
+class TuiguangServiceProvider extends CatchModuleServiceProvider
+{
+    /**
+     * middlewares
+     *
+     * @return string[]
+     */
+    protected function middlewares(): array
+    {
+       return [];
+    }
+
+    /**
+     * route path
+     *
+     * @return string|array
+     */
+    public function moduleName(): string|array
+    {
+        // TODO: Implement path() method.
+        return 'tuiguang';
+    }
+}

+ 10 - 0
modules/Tuiguang/README.md

@@ -0,0 +1,10 @@
+#内容中台管理模块
+关于内容中台 相关的后台接口,对外api接口,都写在这里
+配置文件放在: config目录下,读取配置文件示例:config('contentManage.zhushuyunpublicapi.public_domain');
+config("模块名.配置文件名.配置项");
+
+数据库模型文件放在:Models 目录下面
+服务层文件放在:Services 目录下面
+控制器放在:modules/ContentManage/Http/Controllers 目录下面
+中间件放在:modules/ContentManage/Middlewares 目录下面
+路由只能现在 modules/ContentManage/rout/route.php 文件里

+ 16 - 0
modules/Tuiguang/routes/route.php

@@ -0,0 +1,16 @@
+<?php
+
+use Illuminate\Support\Facades\Route;
+use Modules\Callback\Http\Controllers\JuliangAccountController;
+use Modules\Tuiguang\Http\Controllers\PromotionController;
+
+Route::prefix('tuiguang')->group(function () {
+    Route::prefix('promotion')->group(function(){
+        Route::get('list', [PromotionController::class, 'list']);
+        Route::post('updateSeriesSequence', [PromotionController::class, 'updateSeriesSequence']);
+        Route::post('delete', [PromotionController::class, 'delete']);
+        Route::post('add', [PromotionController::class, 'add']);
+        Route::post('updateCallbackConfig', [PromotionController::class, 'updateCallbackConfig']);
+    });
+});
+

+ 3 - 1
modules/User/Http/Controllers/AuthController.php

@@ -25,7 +25,9 @@ class AuthController extends Controller
         $user = User::query()->where('email', $request->get('email'))->first();
 
         Event::dispatch(new Login($request, $user));
-
+        if ($user && $user->status != 1){
+            throw new FailedException('账号不存在或已停用!');
+        }
         if ($user && Hash::check($request->get('password'), $user->password)) {
             $token = $user->createToken('token')->plainTextToken;
             return compact('token');

+ 11 - 3
modules/Video/Http/Controllers/UserTrait.php

@@ -1,9 +1,7 @@
 <?php
 
-namespace Modules\Video\Http\Controllers;
+namespace Modules\User\Http\Controllers;
 
-use Catch\Base\CatchController;
-use Illuminate\Http\Request;
 use Illuminate\Support\Collection;
 use Illuminate\Support\Facades\DB;
 use Modules\Common\Errors\Errors;
@@ -78,4 +76,14 @@ trait UserTrait
         return compact('loginUser', 'loginUserRoles', 'operateUserRoles', 'operateUser');
     }
 
+    public function getCompanyUid() {
+        $currentUserRoles = $this->listUserRoles();
+        if($currentUserRoles->contains('company')) {
+            return $this->getCurrentUser()->id;
+        }
+        if($currentUserRoles->contains('optimizer')) {
+            return $this->getCurrentUser()->pid;
+        }
+        return null;
+    }
 }

+ 29 - 5
modules/Video/Http/Controllers/EpisodeController.php

@@ -8,6 +8,8 @@ use Illuminate\Http\Request;
 use Illuminate\Support\Facades\DB;
 use Modules\Common\Errors\Errors;
 use Modules\Common\Exceptions\CommonBusinessException;
+use Modules\Common\Services\Qiniu\QiniuTokenService;
+use Modules\User\Http\Controllers\UserTrait;
 use Modules\User\Models\User;
 use Modules\Video\Services\VideoService;
 
@@ -29,25 +31,33 @@ class EpisodeController extends CatchController
             ->where([
                 'video_id' => $request->integer('video_id'),
                 'is_enabled' => 1
-            ])->select('series_name', 'series_sequence', 'video_url', 'duration')
+            ])->select('series_name', 'series_sequence', 'video_key', 'duration')
             ->orderBy('series_sequence', 'asc')
-            ->paginate($request->integer('per_page', 15));
+            ->paginate($request->integer('limit', 15));
         foreach ($videoSeries as $series) {
             $series->series_name = sprintf('第%s集', $series->series_sequence);
             $series->is_charge = $series->series_sequence >= $video->charge_sequence;
             $series->duration_str = gmdate('H:i:s', $series->duration);
+            $series->public_video_url = QiniuTokenService::getPrivateSourceDownloadUrl(
+                config('common.qiniu.publicVideoLinkDomain') . DIRECTORY_SEPARATOR . $series->video_key);
+            $series->download_video_url = QiniuTokenService::getPrivateSourceDownloadUrl(
+                config('common.qiniu.downloadVideoLinkDomain') . DIRECTORY_SEPARATOR .
+                $series->video_key.'?attname='.urlencode($series->series_name).'.mp4');
         }
 
         return $videoSeries;
     }
 
+    public function downloadList(Request $request) {
+        return $this->list($request);
+    }
     public function add(Request $request) {
         $this->validate($request, [
             'video_id' => 'required',
             'videos' => 'required|array|min:1',
-            'videos.*.url' => 'required',
             'videos.*.name' => 'required',
-            'videos.*.duration' => 'required|integer|min:1'
+            'videos.*.duration' => 'required|integer|min:1',
+            'videos.*.key' => 'required',
         ]);
         VideoService::getVideoByIdOrException($request->input('video_id'));
         $videos = $request->input('videos');
@@ -56,7 +66,7 @@ class EpisodeController extends CatchController
         foreach ($videos as $item) {
             $data[] = [
                 'video_id' => $request->input('video_id'),
-                'video_url' => $item['url'],
+                'video_key' => $item['key'],
                 'series_name' => $item['name'],
                 'series_sequence' => intval(explode('_', $item['name'])[0]),
                 'duration' => $item['duration'],
@@ -64,7 +74,21 @@ class EpisodeController extends CatchController
                 'updated_at' => $now,
             ];
         }
+
+        $allSequence = DB::table('video_series')->where(['video_id' => $request->input('video_id')])
+            ->select('series_sequence')->get()->pluck('series_sequence');
+        $alreadySeries = collect($data)->pluck('series_sequence')->intersect($allSequence)->map(function ($item) use ($data) {
+            return collect($data)->keyBy('series_sequence')->get($item)['series_name'];
+        });
+        if($alreadySeries->isNotEmpty()) {
+            CommonBusinessException::throwError([-1, $alreadySeries->join(', ') . ' 已经存在']);
+        }
+
         DB::table('video_series')->insert($data);
+        DB::table('videos')
+            ->where(['id' => $request->input('video_id')])
+            ->update(['updated_episode_num' => DB::table('video_series')
+                ->where(['video_id' => $request->input('video_id')])->count(),'updated_at' => $now]);
         return 1;
     }
 }

+ 35 - 0
modules/Video/Http/Controllers/VideoCategoryController.php

@@ -0,0 +1,35 @@
+<?php
+
+namespace Modules\Video\Http\Controllers;
+
+use Catch\Base\CatchController;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\DB;
+
+class VideoCategoryController extends CatchController
+{
+    /**
+     * 视频分类
+     * @param Request $request
+     * @return array
+     */
+    public function list(Request $request) {
+        $videoCategorys = DB::table('video_category')
+            ->get();
+        $pCategory = $videoCategorys->where('pid', '=', 0)->all();
+        $data = [];
+        foreach ($pCategory as $item) {
+            $data[$item->id] = [
+                'value' => $item->id,
+                'label' => $item->category_name,
+            ];
+        }
+        foreach ($videoCategorys->where('pid', '!=', 0)->all() as $item) {
+            $data[$item->pid]['children'][] = [
+                'value' => $item->id, 'label' => $item->category_name,
+            ];
+        }
+
+        return array_values($data);
+    }
+}

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

@@ -8,13 +8,14 @@ use Illuminate\Http\Request;
 use Illuminate\Support\Facades\DB;
 use Modules\Common\Errors\Errors;
 use Modules\Common\Exceptions\CommonBusinessException;
+use Modules\User\Http\Controllers\UserTrait;
 use Modules\User\Models\User;
 use Modules\Video\Services\VideoService;
 
 class VideoController extends CatchController
 {
-    use UserTrait;
     use ValidatesRequests;
+    use UserTrait;
 
     /**
      * 短剧列表
@@ -40,12 +41,16 @@ class VideoController extends CatchController
                 return $query->where('category_id', $categoryId);
             })->orderBy('id', 'desc')
             ->paginate($request->integer('per_page', 15));
-        $userContext = $this->getUserContext($request->input('operateUserIdßßß'));
+        $userContext = $this->getUserContext($request->input('operateUserId'));
         $allVideoCategory =  DB::table('video_category')
             ->get()->keyBy('id');
         foreach ($videos as $video) {
             $this->updateVideoInfo($video, $userContext);
             $video->category_str = $this->getCategoryStr($allVideoCategory, $video->category_id);
+            $video->shelf_type_str = $video->shelf_type == 1 ? '未上架':'上架';
+            $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;
         }
 
         return $videos;
@@ -59,13 +64,13 @@ class VideoController extends CatchController
     public function setChargeConfig(Request $request) {
         $this->validate($request, [
             'id' => 'required',
-            'chargeCoin' => 'required|integer|min:50|max:100',
+            'chargeCoin' => 'required|integer|min:50|max:300',
             'chargeType' => 'required|integer|in:1',
             'chargeSequence' => 'required|integer|min:1|max:30'
         ]);
         $userContext = $this->getUserContext($request->input('operateUserId'));
-        if(!(1 == $userContext['loginUser']->id ||
-            $userContext['loginUserRoles']->diff(['administrator', 'optimizer'])->isNotEmpty())) {
+        if(!(1 == $userContext['loginUser']->id || $userContext['loginUserRoles']->contains('administrator') ||
+            $userContext['loginUserRoles']->contains('optimizer'))) {
             CommonBusinessException::throwError(Errors::NO_OPERATE_PERMISSION);
         }
         $now = date('Y-m-d H:i:s');

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

@@ -4,11 +4,14 @@ use Illuminate\Support\Facades\Route;
 use Modules\System\Http\Controllers\NoticesController;
 use Modules\System\Http\Controllers\NoticeTypesController;
 use Modules\Video\Http\Controllers\EpisodeController;
+use Modules\Video\Http\Controllers\VideoCategoryController;
 use Modules\Video\Http\Controllers\VideoController;
 
 Route::prefix('videoStock')->group(function () {
     Route::get('video/list', [VideoController::class, 'list']);
     Route::get('episode/list', [EpisodeController::class, 'list']);
+    Route::get('episode/downloadList', [EpisodeController::class, 'downloadList']);
+    Route::get('videoCategory/list', [VideoCategoryController::class, 'list']);
 
 
     Route::post('video/update', [VideoController::class, 'update']);

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

@@ -0,0 +1,57 @@
+<?php
+
+namespace Tests\Callback\Http\Controllers;
+
+use Modules\Callback\Http\Controllers\JuliangAccountController;
+use PHPUnit\Framework\TestCase;
+use Tests\UsedTestCase;
+
+class JuliangAccountControllerTest extends UsedTestCase
+{
+
+    public function testAddAccount()
+    {
+        $res = $this->withHeaders([
+            'Authorization' => 'Bearer '. $this->token,
+        ])->json('post','http://localhost/api/callback/juliangAccount/addAccount', [
+            'account_id' => 1234568,
+            'account_name' => 'jkljlkj',
+            'state' => 1,
+            'protect_num' => 3,
+            'default_rate' => 50,
+            'rate_time_config' => [
+                ['start_time' => '00:35', 'end_time' => '12:34', 'config_per' => 20],
+                ['start_time' => '13:39', 'end_time' => '19:34', 'config_per' => 30],
+            ],
+            'min_money' => 20,
+            'max_money' => 50,
+        ]);
+
+        $res->dump();
+    }
+
+    public function testupdateCallbackConfig() {
+        $res = $this->withHeaders([
+            'Authorization' => 'Bearer '. $this->token,
+        ])->json('post','http://localhost/api/callback/juliangAccount/updateCallbackConfig', [
+            'ids' => [4],
+            'state' => 0,
+            'protect_num' => 3,
+            'default_rate' => 44,
+            'rate_time_config' => [
+                ['start_time' => '15:00', 'end_time' => '15:10', 'config_per' => 40],
+                ['start_time' => '15:20', 'end_time' => '15:30', 'config_per' => 56],
+            ],
+            'min_money' => 40,
+            'max_money' => 60,
+        ]);
+        $res->dump();
+    }
+    public function testList() {
+        $res = $this->withHeaders([
+            'Authorization' => 'Bearer '. $this->token,
+        ])->json('get','http://localhost/api/callback/juliangAccount/list');
+
+        $this->dumpJson($res);
+    }
+}

+ 1 - 1
tests/Channel/Http/Controllers/AdvertiserControllerTest.php

@@ -33,7 +33,7 @@ class AdvertiserControllerTest extends UsedTestCase
 //                'miniProgramId' => 3,
             'username' => 'aa'
             ]));
-        dump(\json_encode($res->json()));
+        $res->dump();
     }
 
     public function testgetAdvertiser() {

+ 27 - 0
tests/Common/Http/Controllers/Qiniu/CallbackControllerTest.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace Tests\Common\Http\Controllers\Qiniu;
+
+use Modules\Common\Http\Controllers\Qiniu\CallbackController;
+use PHPUnit\Framework\TestCase;
+use Tests\UsedTestCase;
+
+class CallbackControllerTest extends UsedTestCase
+{
+
+    public function testUploadToken()
+    {
+        $res = $this->withHeaders([
+            'Authorization' => 'Bearer '. $this->token,
+        ])->json('get','http://localhost/api/qiniu/upload/token');
+        $res->dump();
+    }
+
+    public function testdownloadUrl() {
+        $res = $this->withHeaders([
+            'Authorization' => 'Bearer '. $this->token,
+        ])->json('get','http://localhost/api/qiniu/downloadUrl');
+        $res->dump();
+    }
+
+}

+ 28 - 0
tests/Common/Http/Controllers/Qiniu/ImageUploadControllerTest.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace Tests\Common\Http\Controllers\Qiniu;
+
+use Illuminate\Http\UploadedFile;
+use Illuminate\Support\Facades\Storage;
+use Modules\Common\Http\Controllers\Qiniu\ImageUploadController;
+use PHPUnit\Framework\TestCase;
+use Tests\UsedTestCase;
+
+class ImageUploadControllerTest extends UsedTestCase
+{
+
+    public function testUpload()
+    {
+        Storage::fake('avatars');
+
+        $file = UploadedFile::fake()->image('avatar.jpg');
+
+        $response = $this->withHeaders([
+            'Authorization' => 'Bearer '. $this->token,
+        ])->post('/api/qiniu/upload/image', [
+            'photo' => $file,
+        ]);
+
+        $response->dump();
+    }
+}

+ 75 - 0
tests/Tuiguang/Http/Controllers/PromotionControllerTest.php

@@ -0,0 +1,75 @@
+<?php
+
+namespace Tests\Tuiguang\Http\Controllers;
+
+use Modules\Tuiguang\Http\Controllers\PromotionController;
+use PHPUnit\Framework\TestCase;
+use Tests\UsedTestCase;
+
+class PromotionControllerTest extends UsedTestCase
+{
+
+    public function testAdd()
+    {
+        $res = $this->withHeaders([
+            'Authorization' => 'Bearer '. $this->token,
+        ])->json('post','http://localhost/api/tuiguang/promotion/add', [
+            'video_id' => 6,
+            'series_sequence'  => 4,
+            'name' => 'kkkkddd',
+            'miniprogram_id' => 2,
+        ]);
+
+        $res->dump();
+    }
+
+    public function testDelete()
+    {
+        $res = $this->withHeaders([
+            'Authorization' => 'Bearer '. $this->token,
+        ])->json('post','http://localhost/api/tuiguang/promotion/delete', [
+            'id' => 1
+        ]);
+
+        $res->dump();
+    }
+
+
+    public function testupdateSeriesSequence()
+    {
+        $res = $this->withHeaders([
+            'Authorization' => 'Bearer '. $this->token,
+        ])->json('post','http://localhost/api/tuiguang/promotion/updateSeriesSequence', [
+            'id' => 2,
+            'series_sequence' => 5
+        ]);
+
+        $res->dump();
+    }
+
+    public function testList()
+    {
+        $res = $this->withHeaders([
+            'Authorization' => 'Bearer '. $this->token,
+        ])->json('get','http://localhost/api/tuiguang/promotion/list', [
+//            'is_config' => 0,
+//            'name' => 'kkk'
+        ]);
+
+//        $res->dump();
+        $this->dumpJson($res);
+    }
+
+    public function testupdateCallbackConfig() {
+        $res = $this->withHeaders([
+            'Authorization' => 'Bearer '. $this->token,
+        ])->json('post','http://localhost/api/tuiguang/promotion/updateCallbackConfig', [
+            'id' => 2,
+            'callback_type' => 1,
+            'callback_config_id' => 4
+        ]);
+
+        $res->dump();
+
+    }
+}

+ 3 - 5
tests/UsedTestCase.php

@@ -13,13 +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',
-            'password' => 'catchadmin',
+//            'email' => 'catch@admin.com',
             'remember' => false,
 //            'email' => 'xiaoli@qq.com',
-//            'password' => 'Qaz123',
-//        'email' => 'aa4@test.com',
-//            'password' => '123',
+            'password' => 'catchadmin',
+            'email' => 'aa@test.com',
         ])->json();
         $this->token = $tokenInfo['data']['token'];
     }

+ 9 - 7
tests/Video/Http/Controllers/EpisodeControllerTest.php

@@ -13,8 +13,8 @@ class EpisodeControllerTest extends UsedTestCase
     {
         $res = $this->withHeaders([
             'Authorization' => 'Bearer '. $this->token,
-        ])->json('get','http://localhost/api/videoStock/episode/list', [
-            'video_id' => 1
+        ])->json('get','http://localhost/api/videoStock/episode/downloadList', [
+            'video_id' => 3
         ]);
         $this->dumpJson($res);
     }
@@ -24,13 +24,15 @@ class EpisodeControllerTest extends UsedTestCase
         $res = $this->withHeaders([
             'Authorization' => 'Bearer '. $this->token,
         ])->json('post','http://localhost/api/videoStock/episode/add', [
-            'video_id' => 2,
+            'video_id' => 3,
             'videos' => [
-                ['name' => '01_xxx', 'duration' => 12342, 'url' => 'url1'],
-                ['name' => '02_xxx', 'duration' => 1222, 'url' => 'url2'],
-                ['name' => '03_xxx', 'duration' => 3342, 'url' => 'url3'],
+                ['name' => '01_xxx', 'duration' => 12342, 'key' => 'url1'],
+                ['name' => '02_xxx', 'duration' => 1222, 'key' => 'url2'],
+                ['name' => '03_xxx', 'duration' => 3342, 'key' => 'url3'],
+                ['name' => '04_xxx', 'duration' => 3342, 'key' => 'url3'],
             ]
         ]);
-        $this->dumpJson($res);
+//        $this->dumpJson($res);
+        $res->dump();
     }
 }

+ 20 - 0
tests/Video/Http/Controllers/VideoCategoryControllerTest.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace Tests\Video\Http\Controllers;
+
+use Modules\Video\Http\Controllers\VideoCategoryController;
+use PHPUnit\Framework\TestCase;
+use Tests\UsedTestCase;
+
+class VideoCategoryControllerTest extends UsedTestCase
+{
+
+    public function testList()
+    {
+        $res = $this->withHeaders([
+            'Authorization' => 'Bearer '. $this->token,
+        ])->json('get','http://localhost/api/videoStock/videoCategory/list');
+
+        $this->dumpJson($res);
+    }
+}

+ 3 - 3
tests/Video/Http/Controllers/VideoControllerTest.php

@@ -2,7 +2,7 @@
 
 namespace Tests\Video\Http\Controllers;
 
-use Modules\Video\Http\Controllers\VideoController;
+use Modules\Video\Http\Controllers\JuliangAccountController;
 use PHPUnit\Framework\TestCase;
 use Tests\UsedTestCase;
 
@@ -64,8 +64,8 @@ class VideoControllerTest extends UsedTestCase
 //        'categoryId' => 4,
             'operateUserId' =>10
         ]);
-        $this->dumpJson($res);
-//        $res->dump();
+//        $this->dumpJson($res);
+        $res->dump();
     }
 
     public function testsetChargeConfig() {