Forráskód Böngészése

Merge branch 'liuzj-permission-dev' of 121.36.198.49:zy_duanju/duanju_manage into cp

zqwang 2 éve
szülő
commit
15c41b16d7
77 módosított fájl, 2982 hozzáadás és 149 törlés
  1. 1 0
      app/Http/Kernel.php
  2. 17 0
      modules/Channel/Exceptions/ChannelBusinessException.php
  3. 205 0
      modules/Channel/Http/Controllers/AdvertiserController.php
  4. 56 0
      modules/Channel/Http/Controllers/UserTrait.php
  5. 50 0
      modules/Channel/Http/Requests/NoticeTypeRequest.php
  6. 32 0
      modules/Channel/Installer.php
  7. 26 0
      modules/Channel/Middlewares/ContentManageGate.php
  8. 30 0
      modules/Channel/Models/BaseModel.php
  9. 15 0
      modules/Channel/Models/NoticeTypes.php
  10. 73 0
      modules/Channel/Models/Notices.php
  11. 14 0
      modules/Channel/Models/UserNotice.php
  12. 31 0
      modules/Channel/Providers/ChannelServiceProvider.php
  13. 10 0
      modules/Channel/README.md
  14. 88 0
      modules/Channel/Services/Notice/NoitceTypeService.php
  15. 248 0
      modules/Channel/Services/Notice/NoticesService.php
  16. 15 0
      modules/Channel/routes/route.php
  17. 9 0
      modules/Common/Errors/Errors.php
  18. 23 0
      modules/Common/Http/Controllers/ModuleController.php
  19. 7 0
      modules/Common/Repository/Options/Modules.php
  20. 9 0
      modules/Common/config/common.php
  21. 2 0
      modules/Common/routes/route.php
  22. 3 3
      modules/ContentManage/Services/CpManage/SyncSubscribe.php
  23. 0 139
      modules/ContentManage/routes/route.php
  24. 142 0
      modules/ContentManage/routes/route.php.1
  25. 17 0
      modules/System/Exceptions/ContentBusinessException.php
  26. 20 0
      modules/System/Exceptions/ContentManageForbidden.php
  27. 9 0
      modules/System/Exceptions/Errors.php
  28. 54 0
      modules/System/Http/Controllers/NoticeTypesController.php
  29. 163 0
      modules/System/Http/Controllers/NoticesController.php
  30. 56 0
      modules/System/Http/Controllers/UserTrait.php
  31. 61 0
      modules/System/Http/Requests/NoticeRequest.php
  32. 50 0
      modules/System/Http/Requests/NoticeTypeRequest.php
  33. 32 0
      modules/System/Installer.php
  34. 26 0
      modules/System/Middlewares/ContentManageGate.php
  35. 30 0
      modules/System/Models/BaseModel.php
  36. 15 0
      modules/System/Models/NoticeTypes.php
  37. 73 0
      modules/System/Models/Notices.php
  38. 14 0
      modules/System/Models/UserNotice.php
  39. 31 0
      modules/System/Providers/SystemServiceProvider.php
  40. 10 0
      modules/System/README.md
  41. 88 0
      modules/System/Services/Notice/NoitceTypeService.php
  42. 248 0
      modules/System/Services/Notice/NoticesService.php
  43. 56 0
      modules/System/routes/route.php
  44. 17 0
      modules/T1/Exceptions/ContentBusinessException.php
  45. 20 0
      modules/T1/Exceptions/ContentManageForbidden.php
  46. 9 0
      modules/T1/Exceptions/Errors.php
  47. 33 0
      modules/T1/Http/Controllers/T1Controller.php
  48. 32 0
      modules/T1/Installer.php
  49. 26 0
      modules/T1/Middlewares/ContentManageGate.php
  50. 30 0
      modules/T1/Models/BaseModel.php
  51. 15 0
      modules/T1/Models/NoticeTypes.php
  52. 73 0
      modules/T1/Models/Notices.php
  53. 14 0
      modules/T1/Models/UserNotice.php
  54. 29 0
      modules/T1/Providers/T1ServiceProvider.php
  55. 10 0
      modules/T1/README.md
  56. 10 0
      modules/T1/routes/route.php
  57. 17 0
      modules/T2/Exceptions/ContentBusinessException.php
  58. 20 0
      modules/T2/Exceptions/ContentManageForbidden.php
  59. 9 0
      modules/T2/Exceptions/Errors.php
  60. 29 0
      modules/T2/Http/Controllers/T2Controller.php
  61. 56 0
      modules/T2/Http/Controllers/UserTrait.php
  62. 32 0
      modules/T2/Installer.php
  63. 26 0
      modules/T2/Middlewares/ContentManageGate.php
  64. 30 0
      modules/T2/Models/BaseModel.php
  65. 15 0
      modules/T2/Models/NoticeTypes.php
  66. 73 0
      modules/T2/Models/Notices.php
  67. 14 0
      modules/T2/Models/UserNotice.php
  68. 31 0
      modules/T2/Providers/T2ServiceProvider.php
  69. 10 0
      modules/T2/README.md
  70. 10 0
      modules/T2/routes/route.php
  71. 4 1
      modules/User/Http/Controllers/UserController.php
  72. 2 2
      modules/User/Models/Traits/UserRelations.php
  73. 35 1
      modules/User/Models/User.php
  74. 61 0
      tests/Channel/Http/Controllers/AdvertiserControllerTest.php
  75. 19 0
      tests/Common/Http/Controllers/ModuleControllerTest.php
  76. 5 3
      tests/UsedTestCase.php
  77. 7 0
      tests/User/Http/Controllers/UserControllerTest.php

+ 1 - 0
app/Http/Kernel.php

@@ -2,6 +2,7 @@
 
 namespace App\Http;
 
+use App\Http\Middleware\EnableCrossRequestMiddleware;
 use Illuminate\Foundation\Http\Kernel as HttpKernel;
 
 class Kernel extends HttpKernel

+ 17 - 0
modules/Channel/Exceptions/ChannelBusinessException.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace Modules\Channel\Exceptions;
+
+use Throwable;
+
+class ChannelBusinessException extends \RuntimeException
+{
+    public function __construct($message = "", $code = 0, Throwable $previous = null)
+    {
+        parent::__construct($message, $code, $previous);
+    }
+
+    public static function throwError($error, Throwable $previous = null) {
+        throw (new static($error[1], $error[0], $previous));
+    }
+}

+ 205 - 0
modules/Channel/Http/Controllers/AdvertiserController.php

@@ -0,0 +1,205 @@
+<?php
+
+namespace Modules\Channel\Http\Controllers;
+
+use Catch\Base\CatchController;
+use Illuminate\Foundation\Validation\ValidatesRequests;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\DB;
+use Modules\Channel\Exceptions\ChannelBusinessException;
+use Modules\Common\Errors\Errors;
+use Modules\User\Models\User;
+
+class AdvertiserController extends CatchController
+{
+    use ValidatesRequests;
+    public function __construct(
+        protected readonly User $user
+    ) {
+    }
+
+    /**
+     * 添加投手
+     * @param Request $request
+     * @return int
+     * @throws \Illuminate\Validation\ValidationException
+     */
+    public function addAdvertiser(Request $request) {
+        $this->validate($request, [
+            'email' => 'required|email',
+            'username' => 'required',
+            'password' => 'required',
+            'repassword' => 'required|same:password',
+            'status' => 'required|in:1,2',
+            'remark' => 'string|max:140',
+            'miniProgramIds' => 'required|array|min:1',
+            'miniProgramIds.*' => 'required|integer'
+        ]);
+        $this->user->emailUnique($request->input('email'));
+        $request['roles'] = [(DB::table('roles')->where('identify', 'Investmenter')->value('id') ?? 0)];
+        $this->user->storeBy($request->all());
+        $this->user->pid = $this->getLoginUserId();
+        $this->user->save();
+        $insertData = [];
+        $now = date('Y-m-d H:i:s');
+        foreach ($request->input('miniProgramIds') as $miniProgramId) {
+            $insertData[] = [
+                'uid' => $this->user->id,
+                'miniprogram_id' => $miniProgramId,
+                'created_at' => $now,
+                'updated_at' => $now,
+             ];
+        }
+        DB::table('user_has_miniprograms')
+            ->insert($insertData);
+        return 1;
+    }
+
+    /**
+     * 投手账号列表
+     * @param Request $request
+     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
+     * @throws \Illuminate\Validation\ValidationException
+     */
+    public function listAdvertiser(Request $request) {
+        $this->validate($request, [
+            'email' => 'string|email',
+            'username' => 'string',
+            'miniProgramId' => 'integer',
+        ]);
+        $miniProgramId = $request->input('miniProgramId');
+        $email = $request->input('email');
+        $username = $request->input('username');
+        $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) {
+                return $query->where('users.email', $email);
+            })->when($miniProgramId, function ($query, $miniProgramId){
+                return $query->where('user_has_miniprograms.miniprogram_id', $miniProgramId);
+            })->when($username, function ($query, $username){
+                return $query->where('users.username', 'like', '%'.$username.'%');
+            })
+            ->select(
+                'users.id', 'users.username', 'users.email', 'users.status', 'users.remark',
+                DB::raw("from_unixtime(users.created_at) as created_at"),
+                DB::raw("group_concat(distinct user_has_miniprograms.miniprogram_id separator ',') as miniProgramIds"),
+                DB::raw("NULL as miniPrograms")
+            )->groupBy('users.id')
+            ->orderBy('users.id','desc')
+            ->paginate($request->input('per_page', 15));
+        $miniProgramIds = collect();
+        collect($res->items())->pluck('miniProgramIds')->each(function ($item) use (&$miniProgramIds) {
+            $miniProgramIds = $miniProgramIds->merge(explode(',', $item));
+        });
+        $logos = config('common.common.logos');
+        if($miniProgramIds->count()) {
+            $miniPrograms = DB::table('miniprogram')->whereIn('id', $miniProgramIds->unique())
+                ->select('id', 'name', 'type')
+                ->get()->keyBy('id');
+            foreach ($res as $item) {
+                $item->miniPrograms = [];
+                foreach (explode(',', $item->miniProgramIds) as $miniProgramId) {
+                    $miniProgram = $miniPrograms->get($miniProgramId);
+                    $miniProgram->type_logo = $logos[$miniProgram->type] ?? '';
+                    $item->miniPrograms[] = $miniProgram;
+                }
+            }
+        }
+        return $res;
+    }
+
+    /**
+     * 更新账号
+     * @param Request $request
+     * @return int
+     * @throws \Illuminate\Validation\ValidationException
+     */
+    public function updateAdvertiser(Request $request) {
+        $this->validate($request, [
+            'id' => 'required',
+            'username' => 'required',
+            'miniProgramIds' => 'required|array|min:1',
+            'miniProgramIds.*' => 'required|integer',
+            'status' => 'required|in:1,2',
+            'remark' => 'string|max:140',
+        ]);
+        $uid = $request->input('id');
+        $user = DB::table('users')
+            ->where([
+                'deleted_at' => 0,
+                'id' => $uid
+            ])->select('id','email', 'username', 'status', 'remark')
+            ->first();
+        if(!$user) {
+            ChannelBusinessException::throwError(Errors::USER_NOT_FOUND);
+        }
+        $this->user->updateBy($uid, $request->only(['remark', 'status', 'username']));
+        $now = date('Y-m-d H:i:s');
+        DB::table('user_has_miniprograms')
+            ->where([
+                'uid' => $uid,
+                'is_enabled' => 1
+            ])->update([
+                'is_enabled' => 0,
+                'updated_at' => $now,
+            ]);
+        $insertData = [];
+        foreach ($request->input('miniProgramIds') as $miniProgramId) {
+            $insertData[] = [
+                'uid' => $uid,
+                'miniprogram_id' => $miniProgramId,
+                'created_at' => $now,
+                'updated_at' => $now,
+            ];
+        }
+        DB::table('user_has_miniprograms')
+            ->insert($insertData);
+
+        return 1;
+    }
+
+    /**
+     * 获取投手信息
+     * @param Request $request
+     * @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Query\Builder|object|null
+     * @throws \Illuminate\Validation\ValidationException
+     */
+    public function getAdvertiser(Request $request) {
+        $this->validate($request, [
+            'id' => 'required'
+        ]);
+
+        $user = DB::table('users')
+            ->where([
+                'deleted_at' => 0,
+                'id' => $request->input('id')
+            ])->select('id','email', 'username', 'status', 'remark')
+            ->first();
+        if(!$user) {
+            ChannelBusinessException::throwError(Errors::USER_NOT_FOUND);
+        }
+        $miniProgramIds = DB::table('user_has_miniprograms')
+            ->where([
+                'is_enabled' => 1,
+                'uid' => $user->id,
+            ])->select('miniprogram_id')
+            ->get()->pluck('miniprogram_id')->toArray();
+
+        $user->miniProgramIds = $miniProgramIds;
+        $logos = config('common.common.logos');
+        $user->miniPrograms =  DB::table('miniprogram')->whereIn('id', array_unique($miniProgramIds))
+            ->select('id', 'name', 'type')->get()->map(function ($item) use ($logos){
+                return [
+                    'id' => $item->id,
+                    'name' => $item->name,
+                    'type' => $item->type,
+                    'type_logo' => $logos[$item->type] ?? ''
+                ];
+            });
+        return $user;
+    }
+}

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

@@ -0,0 +1,56 @@
+<?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;
+        }
+    }
+}

+ 50 - 0
modules/Channel/Http/Requests/NoticeTypeRequest.php

@@ -0,0 +1,50 @@
+<?php
+/**
+ * ${CARET}
+ * @file:CpRequest.php
+ * @Created by gnitif
+ * @Date: 2023/3/22
+ * @Time: 17:06
+ */
+
+
+namespace Modules\System\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+use Modules\System\Models\NoticeTypes;
+
+
+class NoticeTypeRequest extends  FormRequest
+{
+
+    /**
+     * rules
+     *
+     * @return array
+     */
+    public function rules(): array
+    {
+        return [
+                'name' => [
+                'required',
+                function ($attribute, $value, $fail) {
+                    $has = NoticeTypes::where('is_deleted', 0)->where('name', $value)->value('id');
+                    if (!empty($has)) {
+                        $fail("分类已存在!");
+                    }
+                }
+            ]
+        ];
+    }
+    /**
+     * messages
+     *
+     * @return string[]
+     */
+    public function messages(): array
+    {
+        return [
+            'name.required' => '分类名称必须填写',
+        ];
+    }
+}

+ 32 - 0
modules/Channel/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.
+    }
+}

+ 26 - 0
modules/Channel/Middlewares/ContentManageGate.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace Modules\ContentManage\Middlewares;
+
+use Illuminate\Http\Request;
+use Modules\ContentManage\Exceptions\PermissionForbidden;
+use Modules\User\Models\User;
+
+class ContentManageGate
+{
+    public function handle(Request $request, \Closure $next)
+    {
+        if ($request->isMethod('get')) {
+            return $next($request);
+        }
+
+        /* @var User $user */
+        $user = $request->user(getGuardName());
+
+        if (! $user->can()) {
+            throw new PermissionForbidden();
+        }
+
+        return $next($request);
+    }
+}

+ 30 - 0
modules/Channel/Models/BaseModel.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace Modules\System\Models;
+
+use Catch\Base\CatchModel as Model;
+use Illuminate\Database\Eloquent\Builder;
+
+
+abstract class BaseModel extends Model
+{
+
+    protected array $defaultHidden = [];
+
+    protected array $defaultCasts = [
+        'created_at' => 'datetime:Y-m-d H:i:s',
+
+        'updated_at' => 'datetime:Y-m-d H:i:s',
+    ];
+    protected $dateFormat = '';
+
+    public static function bootSoftDeletes(): void{
+
+    }
+
+
+    public function scopeActive(Builder $query): void
+    {
+        $query->where($this->table.'.is_enabled', 1);
+    }
+}

+ 15 - 0
modules/Channel/Models/NoticeTypes.php

@@ -0,0 +1,15 @@
+<?php
+
+namespace Modules\System\Models;
+
+
+
+class NoticeTypes extends BaseModel
+{
+    protected $table = 'notice_types';
+
+    protected $fillable = [
+        'id', 'name', 'is_deleted', 'created_at', 'updated_at', 'deleted_at',
+    ];
+
+}

+ 73 - 0
modules/Channel/Models/Notices.php

@@ -0,0 +1,73 @@
+<?php
+
+namespace Modules\System\Models;
+
+
+class Notices extends BaseModel
+{
+    protected $table = 'notices';
+
+    protected $fillable = [
+        'id', 'title', 'content', 'notice_type_id', "sort", 'type', 'notice_obj', 'is_popup', 'is_deleted', 'created_at', 'updated_at', 'deleted_at',
+    ];
+
+    /**
+     * @var array
+     */
+    protected array $fields = ['id', 'title', 'content', "sort", 'notice_type_id', 'type', 'notice_obj', 'is_popup', 'created_at', 'updated_at'];
+
+    /**
+     * @var array
+     */
+    protected array $form = ['title', 'content', 'notice_type_id',"sort", 'type', 'notice_obj', 'is_popup'];
+
+
+    protected $casts = ['notice_obj' => 'array'];
+
+    public array $searchable = [
+        'title' => 'like',
+        'notice_type_id' => '=',
+        'type' => '=',
+
+    ];
+
+    protected string $sortField = 'sort';
+
+
+
+    /**
+     *  添加通知
+     * @param array $data
+     * @return bool
+     * @throws \ReflectionException
+     */
+    public function storeBy(array $data): mixed
+    {
+        $result = '';
+        $this->beginTransaction();
+        try {
+            $result = $this->create($this->filterData($data));
+            if (isset($data['user_ids']) && !empty($data['user_ids'])) {
+                $this->addUserNotice($data['user_ids'], $result->id);
+            }
+            $this->commit();
+        } catch (\Exception $exception) {
+            $this->rollback();
+        }
+        return $result->id ?? 0;
+    }
+
+    private function addUserNotice(mixed $userIds, mixed $id)
+    {
+        $list = [];
+        foreach ($userIds as $val) {
+            $list[] = ['user_id' => $val, 'notice_id' => $id];
+        }
+        if (!empty($list)) {
+            UserNotice::insert($list);
+        }
+        return true;
+    }
+
+
+}

+ 14 - 0
modules/Channel/Models/UserNotice.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace Modules\System\Models;
+
+
+class UserNotice extends BaseModel
+{
+    protected $table = 'user_notice';
+
+    protected $fillable = [
+        'id', 'user_id', 'notice_id', 'is_deleted', 'is_read', 'created_at', 'updated_at', 'deleted_at',
+    ];
+
+}

+ 31 - 0
modules/Channel/Providers/ChannelServiceProvider.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace Modules\Channel\Providers;
+
+use Catch\CatchAdmin;
+use Catch\Providers\CatchModuleServiceProvider;
+use Modules\ContentManage\Middlewares\ContentManageGate;
+
+class ChannelServiceProvider 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 'channel';
+    }
+}

+ 10 - 0
modules/Channel/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 文件里

+ 88 - 0
modules/Channel/Services/Notice/NoitceTypeService.php

@@ -0,0 +1,88 @@
+<?php
+/**
+ * ${CARET}
+ * @file:NoitceTypeService.php
+ * @Created by gnitif
+ * @Date: 2023/3/27
+ * @Time: 11:54
+ */
+
+
+namespace Modules\System\Services\Notice;
+
+use Illuminate\Support\Facades\DB;
+use Modules\ContentManage\Models\NoticeTypes;
+
+class NoitceTypeService
+{
+
+    /**
+     *  添加分类
+     * name: store
+     * @param array $param
+     * $param [
+     *      'name' => "平台通知"
+     * ];
+     * date 2023/03/27 18:14
+     */
+    public static function store(array $param)
+    {
+        return self::getModel()->storeBy($param);
+    }
+
+    protected static function getModel(){
+         return new NoticeTypes();
+    }
+
+    /**
+     *  获取通知分类列表分类
+     * name: list
+     * @param mixed $param
+     *  $param = [
+     *      'name' => '系统通知', // 分类名称模糊搜索
+     *      'page' => 1, //  页码
+     *      'limit' => 15, //  每页条数
+     * ]
+     * @param mixed $isAll // 是否获取所有数据 默认否
+     * date 2023/03/28 17:05
+     */
+    public static function list($param = [], $isAll = false)
+    {
+        $where = self::getCondition($param);
+        if ($isAll){
+            return   NoticeTypes::where($where)->select('id','name')->get();
+        }else {
+            $pageSize = $param['limit'] ?? 15;
+            return   NoticeTypes::where($where)->select('id', 'name', 'created_at')->paginate($pageSize);
+        }
+
+    }
+
+    /**
+     *  拼接查询条件
+     * name: getCondition
+     * @param mixed $param
+     * @return \string[][]
+     * date 2023/03/28 17:19
+     */
+    private static function getCondition(mixed $param)
+    {
+        $where = [['is_deleted', '=', '0']];
+        if (isset($param['name']) && !empty($param['name'])) {
+            $where[] = ['name', 'like', "%" . $param['name'] . "%"];
+        }
+        return $where;
+    }
+
+    /**
+     *  删除分类,软删除
+     * name: del
+     * @param $id
+     * @return mixed
+     * date 2023/03/29 11:05
+     */
+    public static function del($id)
+    {
+        return self::getModel()->updateBy($id,['is_deleted' => 1,'deleted_at' => date("Y-m-d H:i:s")]);
+    }
+}

+ 248 - 0
modules/Channel/Services/Notice/NoticesService.php

@@ -0,0 +1,248 @@
+<?php
+/**
+ * ${CARET}
+ * @file:NoitceService.php
+ * @Created by gnitif
+ * @Date: 2023/3/27
+ * @Time: 11:54
+ */
+
+
+namespace Modules\System\Services\Notice;
+
+use Catch\Exceptions\FailedException;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\DB;
+use Modules\System\Models\Notices;
+use Modules\System\Models\UserNotice;
+use Modules\Permissions\Models\Roles;
+use Modules\User\Models\User;
+use PharIo\Manifest\Author;
+
+class NoticesService
+{
+
+    protected static function getModel()
+    {
+        return new Notices();
+    }
+
+    /**
+     *  添加通知
+     * name: addNotice
+     * @param array $param
+     *  $param = [
+     *      'title' => '测试', // 通知标题
+     *      'notice_type_id' =>  2, // 通知分类id
+     *      'type' => '2', // 通知人群 1全部 2,指定人,3指定角色
+     *      'notice_obj' => [['id' =>  1,'name' => "超管"]] , // 通知对象
+     *      'is_popup' => '1', // 是否是弹窗 1弹窗  0 普通
+     *       'content' => '312312', // 通知内容
+     * ];
+     *
+     * date 2023/03/29 14:25
+     */
+    public static function addNotice(array $param)
+    {
+
+        if ($param['type'] != 1 && (!isset($param['notice_obj']) || empty($param['notice_obj']))) {
+            throw new FailedException('通知对象不能为空!');
+        }
+
+        if ($param['type'] == 3) {
+            $roleIds = array_column($param['notice_obj'], 'id');
+            $userIds = DB::table('user_has_roles')->whereIn('role_id', $roleIds)->pluck('user_id')->toArray();
+        } else if ($param['type'] == 2) {
+            $userIds = array_column($param['notice_obj'], 'id');
+        } else {
+            $userIds = User::pluck('id')->toArray();
+            $param['notice_obj'] = [];
+        }
+        $param['user_ids'] = $userIds;
+        return self::getModel()->storeBy($param);
+    }
+
+    public static function delete($id)
+    {
+        return self::getModel()->updateBy($id, ['is_deleted' => 1, 'deleted_at' => get_date()]);
+    }
+
+    /**
+     *  获取通知详情
+     * name: getDetail
+     * @param $id
+     * @return \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|Notices[]
+     * date 2023/03/29 15:12
+     */
+    public static function getDetail($id)
+    {
+        $info = Notices::leftJoin('notice_types', 'notice_types.id', 'notices.notice_type_id')
+            ->select('notices.*', 'notice_types.name as notice_type_name')->where('notices.id', $id)->first();
+        return $info;
+    }
+
+    /**
+     *  更新
+     * name: update
+     * @param $id
+     * @param array $param
+     * date 2023/03/29 18:32
+     */
+    public static function update($id, array $param)
+    {
+       return  self::getModel()->updateBy($id, $param);
+    }
+
+    /**
+     *  管理员操作通知列表
+     * name: list
+     * @return mixed
+     * date 2023/03/29 22:49
+     */
+    public static function  list()
+    {
+        $list = self::getModel()->setBeforeGetList(function ($query) {
+            return $query->where('is_deleted', 0)->orderBy('created_at','desc');
+        })->getList();
+        if (!$list->isEmpty()) {
+            $cate = NoitceTypeService::list([], true);
+            if ($cate->isEmpty()) {
+                $cate = [];
+            } else {
+                $cate = array_column($cate->toArray(), null, 'id');
+            }
+
+            foreach ($list as $value) {
+                $value->notice_type_txt = $cate[$value->notice_type_id]['name'] ?? "";
+                $value->type_txt = $value->type == 1 ? "全部" : ($value->type == 2 ? "指定用户" : "指定角色");
+            }
+        }
+        return $list;
+    }
+
+    /**
+     * 我的通知
+     * name: myNoticesList
+     * date 2023/03/29 22:49
+     */
+    public static function myNoticesList($param = [])
+    {
+        $type = $param['type'] ?? "";
+        $noticeTypeId = $param['notice_type_id'] ?? 0;
+        $title = $param['title'] ?? "";
+        $pageSize = $param['limit'] ?? 0;
+        $pageSize = $pageSize < 1 ? 15 : $pageSize;
+        $userId = Auth::guard(getGuardName())->id();
+        $where = [
+            ['user_notice.is_deleted', '=', 0],
+            ['user_notice.user_id', '=', $userId],
+            ['notices.is_deleted', '=', 0],
+            ['user_notice.is_deleted', '=', 0],
+        ];
+        if ($type) {
+            $where[] = ['notices.type', '=', $type];
+        }
+        if ($noticeTypeId) {
+            $where[] = ['notices.notice_type_id', '=', $noticeTypeId];
+        }
+        if ($title) {
+            $where[] = ['notices.title', 'like', "%" . $title . "%"];
+        }
+
+        $list = UserNotice::leftJoin('notices', 'notices.id', "user_notice.notice_id")->where($where)->select('notices.id', 'notices.title', 'notices.is_popup', "user_notice.is_read", 'notices.created_at')
+            ->orderBy('notices.created_at', 'desc')->orderBy('sort', 'desc')->paginate($pageSize);
+        if (!$list->isEmpty()) {
+            foreach ($list as $val) {
+                $val->is_read_txt = $val->is_read == 1 ? "已读" : "未读";
+            }
+        }
+        return $list;
+    }
+
+    /**
+     *  设置已读
+     * name: setRead
+     * @param $id
+     * date 2023/03/29 23:51
+     */
+    public static function setRead($id)
+    {
+        $userId = Auth::guard(getGuardName())->id();
+        return UserNotice::where('user_id', $userId)->where('notice_id', $id)->update(['is_read' => 1, 'read_at' => get_date()]);
+    }
+
+    /**
+     *  用户删除
+     * name: userDel
+     * @param $id
+     * date 2023/03/29 23:55
+     */
+    public static function userDel($id)
+    {
+        $userId = Auth::guard(getGuardName())->id();
+        return UserNotice::where('user_id', $userId)->where('notice_id', $id)->update(['is_deleted' => 1, 'deleted_at' => get_date()]);
+    }
+
+    /**
+     *  阅读详情
+     * name: detail
+     * @param $id
+     * @return Notices
+     * date 2023/03/30 00:09
+     */
+    public static function detail($id)
+    {
+        return Notices::where('id', $id)->where('is_deleted', 0)->select('title', 'id', 'is_popup', 'content')->first();
+    }
+
+    /**
+     *  获取指定对象选择项
+     * name: objOption
+     * @param $type
+     * @param string $name
+     * @return array
+     * date 2023/03/30 10:23
+     */
+    public static function objOption($type, $name = ""): mixed
+    {
+        if ($type == 'user') {
+            if ($name) {
+                return  User::where("username", 'like', "%" . $name . "%")->without(['roles','jobs'])->select('id','username as name')->get();
+            }
+            return User::select('id','username as name')->without(['roles','jobs'])->get();
+        } else if ($type == "role") {
+            if ($name) {
+                return Roles::where("role_name", 'like', "%" . $name . "%")->select('id','role_name as name')->get();
+            }
+            return Roles::select('id','role_name as name')->get();
+        }
+        return [];
+    }
+
+    /**
+     *  一条获取弹窗信息
+     * name: getPopup
+     * @return Model|UserNotice|object|null
+     * date 2023/03/30 16:45
+     */
+    public static function getPopup()
+    {
+        $where = [
+            ['user_notice.is_deleted', '=', 0],
+            ['user_notice.user_id', '=',  Auth::guard(getGuardName())->id()],
+            ['notices.is_deleted', '=', 0],
+            ['notices.is_popup', '=', 1],
+            ['user_notice.is_read', '=', 0],
+        ];
+
+         $info =  UserNotice::leftJoin('notices', 'notices.id', "user_notice.notice_id")->where($where)->select('notices.id', 'notices.title', 'notices.content')
+             ->orderBy('notices.created_at', 'desc')->orderBy('sort', 'desc')->first();
+         if (empty($info)){
+             return  [];
+         }
+         return  $info;
+    }
+
+
+}

+ 15 - 0
modules/Channel/routes/route.php

@@ -0,0 +1,15 @@
+<?php
+
+use Illuminate\Support\Facades\Route;
+use Modules\Channel\Http\Controllers\AdvertiserController;
+use Modules\System\Http\Controllers\NoticesController;
+use Modules\System\Http\Controllers\NoticeTypesController;
+
+Route::prefix('channel')->group(function () {
+    Route::post('advertiser/add', [AdvertiserController::class, 'addAdvertiser']);
+    Route::post('advertiser/updateAdvertiser', [AdvertiserController::class, 'updateAdvertiser']);
+
+    Route::get('advertiser/listAdvertiser', [AdvertiserController::class, 'listAdvertiser']);
+    Route::get('advertiser/getAdvertiser', [AdvertiserController::class, 'getAdvertiser']);
+});
+

+ 9 - 0
modules/Common/Errors/Errors.php

@@ -0,0 +1,9 @@
+<?php
+
+namespace Modules\Common\Errors;
+
+class Errors
+{
+    public const  EMAIL_EXISTS= [500001, '邮箱已经被使用'];
+    public const  USER_NOT_FOUND= [500002, '用户不存在'];
+}

+ 23 - 0
modules/Common/Http/Controllers/ModuleController.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace Modules\Common\Http\Controllers;
+
+use Catch\Base\CatchController;
+use Illuminate\Http\Request;
+use Modules\Common\Repository\Options\Modules;
+use Modules\User\Models\User;
+
+class ModuleController extends CatchController
+{
+    public function listApp(Request $request){
+        if($this->getLoginUser()->roles->pluck('identify')->contains('channel')) {
+            return Modules::getAppModules()->map(function ($module) {
+                return [
+                    'name' => $module['name'],
+                    'title' => $module['title']
+                ];
+            });
+        }
+        return [];
+    }
+}

+ 7 - 0
modules/Common/Repository/Options/Modules.php

@@ -22,4 +22,11 @@ class Modules implements OptionInterface
 
         return $modules;
     }
+
+    public static function getAppModules() {
+        return app(ModuleRepository::class)->all([])
+            ->filter(function ($module) {
+                return 1 == ($module['isApp'] ?? 0);
+            });
+    }
 }

+ 9 - 0
modules/Common/config/common.php

@@ -0,0 +1,9 @@
+<?php
+
+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',
+        'QQ' => 'https://zhuishuyun.oss-cn-hangzhou.aliyuncs.com/channel/logo/QQ.png',
+    ]
+];

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

@@ -1,6 +1,7 @@
 <?php
 
 use Illuminate\Support\Facades\Route;
+use Modules\Common\Http\Controllers\ModuleController;
 use Modules\Common\Http\Controllers\OptionController;
 use Modules\Common\Http\Controllers\UploadController;
 
@@ -24,5 +25,6 @@ Route::controller(UploadController::class)->group(function (){
     Route::get('upload/oss', 'oss');
 });
 
+Route::get('modules/listApp', [ModuleController::class, 'listApp']);
 
 

+ 3 - 3
modules/ContentManage/Services/CpManage/SyncSubscribe.php

@@ -5,7 +5,7 @@ namespace Modules\ContentManage\Services\CpManage;
 use GuzzleHttp\Client;
 use Modules\Common\Support\Trace\CustomizeLogger;
 use Modules\Common\Support\Trace\TraceContext;
-use Modules\ContentManage\Exceptions\ContentBusinessException;
+use Modules\ContentManage\Exceptions\ChannelBusinessException;
 use Modules\ContentManage\Exceptions\Errors;
 use Modules\ContentManage\Models\Cp\CpSubscribeStatisticDataModel;
 
@@ -145,7 +145,7 @@ class SyncSubscribe
     {
         $httpStatus = $rawResult->getStatusCode();
         if (200 != $httpStatus) {
-            ContentBusinessException::throwError(Errors::REQUEST_HTTP_STATUS_ERROR);
+            ChannelBusinessException::throwError(Errors::REQUEST_HTTP_STATUS_ERROR);
         }
         $rawContent = $rawResult->getBody()->getContents();
         $parsedContent = \json_decode($rawContent, true);
@@ -157,7 +157,7 @@ class SyncSubscribe
 
         $code = $parsedContent['code'] ?? -1;
         if (0 != $code) {
-            ContentBusinessException::throwError(Errors::REQUEST_CODE_STATUS_ERROR);
+            ChannelBusinessException::throwError(Errors::REQUEST_CODE_STATUS_ERROR);
         }
 
         return [

+ 0 - 139
modules/ContentManage/routes/route.php

@@ -1,142 +1,3 @@
 <?php
 
-use Illuminate\Support\Facades\Route;
-use Modules\ContentManage\Http\Controllers\BookController;
-use Modules\ContentManage\Http\Controllers\CpListController;
-use Modules\ContentManage\Http\Controllers\OutputController;
-use Modules\ContentManage\Http\Controllers\CpSubscribeStatisticDataController;
-use Modules\ContentManage\Http\Controllers\System\NoticesController;
-use Modules\ContentManage\Http\Controllers\System\NoticeTypesController;
-use Modules\ContentManage\Http\Controllers\TestController;
-
-Route::prefix('contentManage')->group(function () {
-    Route::prefix('cp')->group(function () {
-        Route::apiResource('manage/cp_list', CpListController::class);
-        // cp选择项
-        Route::any('options',[CpListController::class,"selectOptions"]);
-        /**
-         * cp结算数据中心
-         */
-        Route::get('subscribeStatisticData/list', [CpSubscribeStatisticDataController::class, 'list']);
-        /**
-         * cp结算数据中心统计数据
-         */
-        Route::get('subscribeStatisticData/listStatistic', [CpSubscribeStatisticDataController::class, 'listStatistic']);
-        /**
-         * cp结算
-         */
-        Route::get('subscribeStatisticData/monthList', [CpSubscribeStatisticDataController::class, 'monthList']);
-        /**
-         * 导出某个cp某个月的各个书籍的应结算金额
-         */
-        Route::get('subscribeStatisticData/listCpMonthFinalAmount', [CpSubscribeStatisticDataController::class, 'listCpMonthFinalAmount']);
-        /**
-         * 修改cp结算状态
-         */
-        Route::post('subscribeStatisticData/saveFinalState',
-            [CpSubscribeStatisticDataController::class, 'saveFinalState']);
-
-        Route::post('test/test1', [TestController::class, 'test1'])->withoutMiddleware(config('catch.route.middlewares'));
-
-        Route::get('cpCollection',[CpListController::class,"cpCollection"])->withoutMiddleware(config('catch.route.middlewares'));
-	});
-
-    // 书籍管理
-    Route::prefix('book')->group(function (){
-        // 书籍列表
-        Route::any('list',[BookController::class, 'list']);
-        // 结算方式选项
-        Route::any('settlementypes',[BookController::class, 'settlementTypes']);
-        // 保存书籍版权时间,结算方式,单本和批量
-        Route::post('edit_author',[BookController::class, 'editAuthorByBid']);
-        // 书籍编辑时获取书籍信息
-        Route::get('edit_author/{bid}',[BookController::class, 'bookInfo']);
-         // 获取书籍分库权限信息
-        Route::get('distribute/{bid}',[BookController::class, 'distributeInfo']);
-         // 获取书籍分库权限信息提交
-        Route::post('distribute/{bid}',[BookController::class, 'distributeSubmit']);
-         // 导出书籍
-        Route::get('export/{bid}',[BookController::class, 'export'])->withoutMiddleware(config('catch.route.middlewares'));
-        //导入书籍
-        Route::post('import',[BookController::class, 'import'])->withoutMiddleware(config('catch.route.middlewares'));;
-        Route::post('createBook',[BookController::class, 'createBook']);
-        //分类列表
-        Route::get('categorylist',[BookController::class, 'categoryList'])->withoutMiddleware(config('catch.route.middlewares'));
-
-    });
-    // 通知管理
-    Route::prefix('notices')->group(function(){
-        // 通知分类
-        Route::prefix('types')->group(function (){
-            // 添加通知分类
-            Route::post('add',[NoticeTypesController::class, 'add']);
-            // 通知分类列表
-            Route::any('list',[NoticeTypesController::class, 'list']);
-            //  删除通知分类
-            Route::post('del/{id}',[NoticeTypesController::class, 'delete']);
-        });
-        // 通知管理
-        Route::prefix('notice')->group(function(){
-            // 添加通知
-            Route::post('add',[NoticesController::class, 'addNotice']);
-            // 通知列表
-            Route::any('list',[NoticesController::class, 'list']);
-            //  删除通知
-            Route::post('del/{id}',[NoticesController::class, 'delete']);
-            //   修改通知状态
-            Route::post('enable/{id}',[NoticesController::class, 'enable']);
-            // 获取编辑信息
-            Route::get('edit/{id}',[NoticesController::class, 'info']);
-            // 保存编辑
-            Route::post('edit/{id}',[NoticesController::class, 'edit']);
-
-            // 不判断权限
-            Route::prefix("")->group(function (){
-                // 通知对象接口
-                Route::any('obj_option',[NoticesController::class, 'objOption'])->withoutMiddleware(config('catch.route.middlewares'));
-                // 我的通知
-                Route::any('mine',[NoticesController::class, 'myNotices'])->withoutMiddleware(config('catch.route.middlewares'));
-                //  已读
-                Route::get('read/{id}',[NoticesController::class, 'setRead'])->withoutMiddleware(config('catch.route.middlewares'));
-                // 用户删除
-                Route::get('user_del/{id}',[NoticesController::class, 'userDel'])->withoutMiddleware(config('catch.route.middlewares'));
-                // 查看通知信息
-                Route::any('detail/{id}',[NoticesController::class, 'detail'])->withoutMiddleware(config('catch.route.middlewares'));
-                // 获取首页弹窗消息
-                Route::any('popup',[NoticesController::class, 'getPopup'])->withoutMiddleware(config('catch.route.middlewares'));
-
-            });
-
-        });
-
-    });
-
-});
-
-
-/**
- * 书籍输出
- */
-Route::prefix('output')->group(function () {
-
-    //书籍列表
-    Route::get('booklist',[OutputController::class,'bookList'])
-    ->withoutMiddleware(config('catch.route.middlewares'));
-
-    //书籍详情
-    Route::get('bookdetail/{bid}',[OutputController::class,'bookDetail'])
-    ->withoutMiddleware(config('catch.route.middlewares'));
-
-    //章节列表
-    Route::get('chapterlist/{bid}',[OutputController::class,'chapterList'])
-    ->withoutMiddleware(config('catch.route.middlewares'));
-    //章节内容
-    Route::get('chaptercontent/{bid}/chapterid/{chapter_id}',[OutputController::class,'chapterContent'])
-    ->withoutMiddleware(config('catch.route.middlewares'));
-
-    //分类
-    Route::get('listCategories',[OutputController::class,'listCategories'])
-    ->withoutMiddleware(config('catch.route.middlewares'));
-
-});
 

+ 142 - 0
modules/ContentManage/routes/route.php.1

@@ -0,0 +1,142 @@
+<?php
+
+use Illuminate\Support\Facades\Route;
+use Modules\ContentManage\Http\Controllers\BookController;
+use Modules\ContentManage\Http\Controllers\CpListController;
+use Modules\ContentManage\Http\Controllers\OutputController;
+use Modules\ContentManage\Http\Controllers\CpSubscribeStatisticDataController;
+use Modules\ContentManage\Http\Controllers\System\NoticesController;
+use Modules\ContentManage\Http\Controllers\System\NoticeTypesController;
+use Modules\ContentManage\Http\Controllers\TestController;
+
+Route::prefix('contentManage')->group(function () {
+    Route::prefix('cp')->group(function () {
+        Route::apiResource('manage/cp_list', CpListController::class);
+        // cp选择项
+        Route::any('options',[CpListController::class,"selectOptions"]);
+        /**
+         * cp结算数据中心
+         */
+        Route::get('subscribeStatisticData/list', [CpSubscribeStatisticDataController::class, 'list']);
+        /**
+         * cp结算数据中心统计数据
+         */
+        Route::get('subscribeStatisticData/listStatistic', [CpSubscribeStatisticDataController::class, 'listStatistic']);
+        /**
+         * cp结算
+         */
+        Route::get('subscribeStatisticData/monthList', [CpSubscribeStatisticDataController::class, 'monthList']);
+        /**
+         * 导出某个cp某个月的各个书籍的应结算金额
+         */
+        Route::get('subscribeStatisticData/listCpMonthFinalAmount', [CpSubscribeStatisticDataController::class, 'listCpMonthFinalAmount']);
+        /**
+         * 修改cp结算状态
+         */
+        Route::post('subscribeStatisticData/saveFinalState',
+            [CpSubscribeStatisticDataController::class, 'saveFinalState']);
+
+        Route::post('test/test1', [TestController::class, 'test1'])->withoutMiddleware(config('catch.route.middlewares'));
+
+        Route::get('cpCollection',[CpListController::class,"cpCollection"])->withoutMiddleware(config('catch.route.middlewares'));
+	});
+
+    // 书籍管理
+    Route::prefix('book')->group(function (){
+        // 书籍列表
+        Route::any('list',[BookController::class, 'list']);
+        // 结算方式选项
+        Route::any('settlementypes',[BookController::class, 'settlementTypes']);
+        // 保存书籍版权时间,结算方式,单本和批量
+        Route::post('edit_author',[BookController::class, 'editAuthorByBid']);
+        // 书籍编辑时获取书籍信息
+        Route::get('edit_author/{bid}',[BookController::class, 'bookInfo']);
+         // 获取书籍分库权限信息
+        Route::get('distribute/{bid}',[BookController::class, 'distributeInfo']);
+         // 获取书籍分库权限信息提交
+        Route::post('distribute/{bid}',[BookController::class, 'distributeSubmit']);
+         // 导出书籍
+        Route::get('export/{bid}',[BookController::class, 'export'])->withoutMiddleware(config('catch.route.middlewares'));
+        //导入书籍
+        Route::post('import',[BookController::class, 'import'])->withoutMiddleware(config('catch.route.middlewares'));;
+        Route::post('createBook',[BookController::class, 'createBook']);
+        //分类列表
+        Route::get('categorylist',[BookController::class, 'categoryList'])->withoutMiddleware(config('catch.route.middlewares'));
+
+    });
+    // 通知管理
+    Route::prefix('notices')->group(function(){
+        // 通知分类
+        Route::prefix('types')->group(function (){
+            // 添加通知分类
+            Route::post('add',[NoticeTypesController::class, 'add']);
+            // 通知分类列表
+            Route::any('list',[NoticeTypesController::class, 'list']);
+            //  删除通知分类
+            Route::post('del/{id}',[NoticeTypesController::class, 'delete']);
+        });
+        // 通知管理
+        Route::prefix('notice')->group(function(){
+            // 添加通知
+            Route::post('add',[NoticesController::class, 'addNotice']);
+            // 通知列表
+            Route::any('list',[NoticesController::class, 'list']);
+            //  删除通知
+            Route::post('del/{id}',[NoticesController::class, 'delete']);
+            //   修改通知状态
+            Route::post('enable/{id}',[NoticesController::class, 'enable']);
+            // 获取编辑信息
+            Route::get('edit/{id}',[NoticesController::class, 'info']);
+            // 保存编辑
+            Route::post('edit/{id}',[NoticesController::class, 'edit']);
+
+            // 不判断权限
+            Route::prefix("")->group(function (){
+                // 通知对象接口
+                Route::any('obj_option',[NoticesController::class, 'objOption'])->withoutMiddleware(config('catch.route.middlewares'));
+                // 我的通知
+                Route::any('mine',[NoticesController::class, 'myNotices'])->withoutMiddleware(config('catch.route.middlewares'));
+                //  已读
+                Route::get('read/{id}',[NoticesController::class, 'setRead'])->withoutMiddleware(config('catch.route.middlewares'));
+                // 用户删除
+                Route::get('user_del/{id}',[NoticesController::class, 'userDel'])->withoutMiddleware(config('catch.route.middlewares'));
+                // 查看通知信息
+                Route::any('detail/{id}',[NoticesController::class, 'detail'])->withoutMiddleware(config('catch.route.middlewares'));
+                // 获取首页弹窗消息
+                Route::any('popup',[NoticesController::class, 'getPopup'])->withoutMiddleware(config('catch.route.middlewares'));
+
+            });
+
+        });
+
+    });
+
+});
+
+
+/**
+ * 书籍输出
+ */
+Route::prefix('output')->group(function () {
+
+    //书籍列表
+    Route::get('booklist',[OutputController::class,'bookList'])
+    ->withoutMiddleware(config('catch.route.middlewares'));
+
+    //书籍详情
+    Route::get('bookdetail/{bid}',[OutputController::class,'bookDetail'])
+    ->withoutMiddleware(config('catch.route.middlewares'));
+
+    //章节列表
+    Route::get('chapterlist/{bid}',[OutputController::class,'chapterList'])
+    ->withoutMiddleware(config('catch.route.middlewares'));
+    //章节内容
+    Route::get('chaptercontent/{bid}/chapterid/{chapter_id}',[OutputController::class,'chapterContent'])
+    ->withoutMiddleware(config('catch.route.middlewares'));
+
+    //分类
+    Route::get('listCategories',[OutputController::class,'listCategories'])
+    ->withoutMiddleware(config('catch.route.middlewares'));
+
+});
+

+ 17 - 0
modules/System/Exceptions/ContentBusinessException.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace Modules\ContentManage\Exceptions;
+
+use Throwable;
+
+class ContentBusinessException extends \RuntimeException
+{
+    public function __construct($message = "", $code = 0, Throwable $previous = null)
+    {
+        parent::__construct($message, $code, $previous);
+    }
+
+    public static function throwError($error, Throwable $previous = null) {
+        throw (new static($error[1], $error[0], $previous));
+    }
+}

+ 20 - 0
modules/System/Exceptions/ContentManageForbidden.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace Modules\ContentManage\Exceptions;
+
+use Catch\Enums\Code;
+use Catch\Exceptions\CatchException;
+use Symfony\Component\HttpFoundation\Response;
+
+class ContentManageForbidden extends CatchException
+{
+    protected $message = 'permission forbidden';
+
+    protected $code = Code::PERMISSION_FORBIDDEN;
+
+
+    public function statusCode(): int
+    {
+        return Response::HTTP_FORBIDDEN;
+    }
+}

+ 9 - 0
modules/System/Exceptions/Errors.php

@@ -0,0 +1,9 @@
+<?php
+
+namespace Modules\ContentManage\Exceptions;
+
+class Errors
+{
+    public const REQUEST_HTTP_STATUS_ERROR = [500001, '请求上游接口返回http状态码有误'];
+    public const REQUEST_CODE_STATUS_ERROR = [500002, '请求上游接口返回code状态码有误'];
+}

+ 54 - 0
modules/System/Http/Controllers/NoticeTypesController.php

@@ -0,0 +1,54 @@
+<?php
+/**
+ * ${CARET}
+ * @file:NoticeTypesController.php
+ * @Created by gnitif
+ * @Date: 2023/3/27
+ * @Time: 11:52
+ */
+
+
+namespace Modules\System\Http\Controllers;
+
+use Catch\Base\CatchController as Controller;
+
+use Illuminate\Http\Request;
+use Modules\System\Http\Requests\NoticeTypeRequest;
+use Modules\System\Services\Notice\NoitceTypeService;
+
+class NoticeTypesController extends Controller
+{
+
+    /**
+     * 获取通知分类列表
+     * name: list
+     * @param Request $request
+     * date 2023/03/27 18:20
+     */
+    public function  list(Request $request)
+    {
+        $param  =  $request->all();
+        $list =  NoitceTypeService::list($param, $request->input('is_all',false) == true);
+        return $list;
+    }
+
+    /**
+     *  添加分类
+     * name: add
+     * @param NoticeTypeRequest $request
+     * @return mixed
+     * date 2023/03/28 18:03
+     */
+    public function  add(NoticeTypeRequest $request)
+    {
+        $param = $request->all();
+        return  NoitceTypeService::store($param);
+    }
+
+    public function  delete($id)
+    {
+        return  NoitceTypeService::del($id);
+    }
+
+
+}

+ 163 - 0
modules/System/Http/Controllers/NoticesController.php

@@ -0,0 +1,163 @@
+<?php
+/**
+ * ${CARET}
+ * @file:NoticesController.php
+ * @Created by gnitif
+ * @Date: 2023/3/27
+ * @Time: 11:18
+ */
+
+
+namespace Modules\System\Http\Controllers;
+
+
+use Catch\Base\CatchController as Controller;
+use Catch\Exceptions\FailedException;
+use Illuminate\Contracts\Pagination\LengthAwarePaginator;
+use Illuminate\Http\Request;
+use Modules\System\Http\Requests\NoticeRequest;
+use Modules\System\Models\NoticeTypes;
+use Modules\System\Services\Notice\NoticesService;
+
+class NoticesController extends Controller
+{
+    public function list(Request $request)
+    {
+        return NoticesService::list();
+
+    }
+
+    /**
+     *  添加通知
+     * name: addNotice
+     * @param NoticeRequest $request
+     * @return mixed
+     * date 2023/03/29 14:47
+     */
+    public function addNotice(NoticeRequest $request)
+    {
+        return NoticesService::addNotice($request->all());
+    }
+
+    /**
+     *  删除通知
+     * name: delete
+     * @param $id
+     * date 2023/03/29 14:48
+     */
+    public function delete($id)
+    {
+        return NoticesService::delete($id);
+    }
+
+    /**
+     *  获取通知详情
+     * name: info
+     * @param $id
+     * @return mixed
+     * date 2023/03/29 14:59
+     */
+    public function info($id)
+    {
+        return NoticesService::getDetail($id);
+    }
+
+    public function edit($id, Request $request)
+    {
+        $title = $request->input('title', '');
+        $content = $request->input('content', '');
+        $notice_type_id = $request->input('notice_type_id', 0);
+
+        if (empty($title)) {
+            throw new FailedException('通知标题不能为空!');
+        }
+        if (empty($content)) {
+            throw new FailedException('通知内容不能为空!');
+        }
+        if (empty($notice_type_id)) {
+            throw new FailedException('通知类型必填!');
+        }
+        $tye = NoticeTypes::where('id', $notice_type_id)->where('is_deleted', 0)->value('id');
+        if (empty($tye)) {
+            throw new FailedException('通知类型不正确!');
+        }
+        $param = [
+            'title' => $title,
+            'content' => $content,
+            'notice_type_id' => $notice_type_id,
+            'sort' => $request->input('sort',0),
+        ];
+        NoticesService::update($id, $param);
+    }
+
+    /**
+     *  我的通知
+     * name: myNotices
+     * @param Request $request
+     * @return LengthAwarePaginator
+     * date 2023/03/29 23:48
+     */
+    public function myNotices(Request $request)
+    {
+        return NoticesService::myNoticesList($request->all());
+    }
+
+    /**
+     *  已读
+     * name: setRead
+     * @param $id
+     * date 2023/03/29 23:51
+     */
+    public function setRead($id): mixed
+    {
+         NoticesService::setRead($id);
+         return response()->json(['code' => 10000, "message" => "操作成功",'data' => []]);
+    }
+
+    /**
+     *  用户删除
+     * name: userDel
+     * @param $id
+     * @return mixed
+     * date 2023/03/29 23:55
+     */
+    public function userDel($id): mixed
+    {
+        return NoticesService::userDel($id);
+    }
+
+    /**
+     *  阅读详情
+     * name: detail
+     * @param $id
+     * date 2023/03/30 00:06
+     */
+    public function detail($id)
+    {
+        return NoticesService::detail($id);
+    }
+
+    /**
+     *  获取通知人群选项
+     * name: objOption
+     * @param Request $request
+     * date 2023/03/30 10:20
+     */
+    public function objOption(Request $request)
+    {
+        $type = $request->input('type', '2');
+        $name = $request->input('name', '');
+        $type = $type == "3" ? "role" : "user";
+        return NoticesService::objOption($type, $name);
+    }
+
+    /**
+     *  home页弹窗公告
+     * name: getPopup
+     * date 2023/03/30 16:41
+     */
+    public function getPopup(){
+        return  NoticesService:: getPopup();
+    }
+
+}

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

@@ -0,0 +1,56 @@
+<?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;
+        }
+    }
+}

+ 61 - 0
modules/System/Http/Requests/NoticeRequest.php

@@ -0,0 +1,61 @@
+<?php
+/**
+ * ${CARET}
+ * @file:CpRequest.php
+ * @Created by gnitif
+ * @Date: 2023/3/22
+ * @Time: 17:06
+ */
+
+
+namespace Modules\System\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+use Modules\System\Models\NoticeTypes;
+
+
+class NoticeRequest extends FormRequest
+{
+
+    /**
+     * rules
+     *
+     * @return array
+     */
+    public function rules(): array
+    {
+        return [
+            'title' => "required|string",
+            'notice_type_id' => [
+                'required',
+                function ($attribute, $value, $fail) {
+                    $has = NoticeTypes::where('is_deleted', 0)->where('id', $value)->value('id');
+                    if (empty($has)) {
+                        $fail("所选分类不存在!");
+                    }
+                }
+            ],
+            'type'=> "required|Integer|in:1,2,3", // 通知人群 1全部 2,指定人,3指定角色
+            'is_popup' => "required|Integer|in:0,1",
+            'content' => "required|string",
+        ];
+    }
+
+    /**
+     * messages
+     *
+     * @return string[]
+     */
+    public function messages(): array
+    {
+        return [
+            'title' => '通知标题必填',
+            'notice_type_id.required' => '通知分类必填',
+            'type.required' => '通知展示人类型必填',
+            'type' => '通知展示人类型不正确',
+            'is_popup' => '展示类型不正确',
+            'content' => '通知内容必填',
+            'notice_obj' => "通知对象必填",
+        ];
+    }
+}

+ 50 - 0
modules/System/Http/Requests/NoticeTypeRequest.php

@@ -0,0 +1,50 @@
+<?php
+/**
+ * ${CARET}
+ * @file:CpRequest.php
+ * @Created by gnitif
+ * @Date: 2023/3/22
+ * @Time: 17:06
+ */
+
+
+namespace Modules\System\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+use Modules\System\Models\NoticeTypes;
+
+
+class NoticeTypeRequest extends  FormRequest
+{
+
+    /**
+     * rules
+     *
+     * @return array
+     */
+    public function rules(): array
+    {
+        return [
+                'name' => [
+                'required',
+                function ($attribute, $value, $fail) {
+                    $has = NoticeTypes::where('is_deleted', 0)->where('name', $value)->value('id');
+                    if (!empty($has)) {
+                        $fail("分类已存在!");
+                    }
+                }
+            ]
+        ];
+    }
+    /**
+     * messages
+     *
+     * @return string[]
+     */
+    public function messages(): array
+    {
+        return [
+            'name.required' => '分类名称必须填写',
+        ];
+    }
+}

+ 32 - 0
modules/System/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.
+    }
+}

+ 26 - 0
modules/System/Middlewares/ContentManageGate.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace Modules\ContentManage\Middlewares;
+
+use Illuminate\Http\Request;
+use Modules\ContentManage\Exceptions\PermissionForbidden;
+use Modules\User\Models\User;
+
+class ContentManageGate
+{
+    public function handle(Request $request, \Closure $next)
+    {
+        if ($request->isMethod('get')) {
+            return $next($request);
+        }
+
+        /* @var User $user */
+        $user = $request->user(getGuardName());
+
+        if (! $user->can()) {
+            throw new PermissionForbidden();
+        }
+
+        return $next($request);
+    }
+}

+ 30 - 0
modules/System/Models/BaseModel.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace Modules\System\Models;
+
+use Catch\Base\CatchModel as Model;
+use Illuminate\Database\Eloquent\Builder;
+
+
+abstract class BaseModel extends Model
+{
+
+    protected array $defaultHidden = [];
+
+    protected array $defaultCasts = [
+        'created_at' => 'datetime:Y-m-d H:i:s',
+
+        'updated_at' => 'datetime:Y-m-d H:i:s',
+    ];
+    protected $dateFormat = '';
+
+    public static function bootSoftDeletes(): void{
+
+    }
+
+
+    public function scopeActive(Builder $query): void
+    {
+        $query->where($this->table.'.is_enabled', 1);
+    }
+}

+ 15 - 0
modules/System/Models/NoticeTypes.php

@@ -0,0 +1,15 @@
+<?php
+
+namespace Modules\System\Models;
+
+
+
+class NoticeTypes extends BaseModel
+{
+    protected $table = 'notice_types';
+
+    protected $fillable = [
+        'id', 'name', 'is_deleted', 'created_at', 'updated_at', 'deleted_at',
+    ];
+
+}

+ 73 - 0
modules/System/Models/Notices.php

@@ -0,0 +1,73 @@
+<?php
+
+namespace Modules\System\Models;
+
+
+class Notices extends BaseModel
+{
+    protected $table = 'notices';
+
+    protected $fillable = [
+        'id', 'title', 'content', 'notice_type_id', "sort", 'type', 'notice_obj', 'is_popup', 'is_deleted', 'created_at', 'updated_at', 'deleted_at',
+    ];
+
+    /**
+     * @var array
+     */
+    protected array $fields = ['id', 'title', 'content', "sort", 'notice_type_id', 'type', 'notice_obj', 'is_popup', 'created_at', 'updated_at'];
+
+    /**
+     * @var array
+     */
+    protected array $form = ['title', 'content', 'notice_type_id',"sort", 'type', 'notice_obj', 'is_popup'];
+
+
+    protected $casts = ['notice_obj' => 'array'];
+
+    public array $searchable = [
+        'title' => 'like',
+        'notice_type_id' => '=',
+        'type' => '=',
+
+    ];
+
+    protected string $sortField = 'sort';
+
+
+
+    /**
+     *  添加通知
+     * @param array $data
+     * @return bool
+     * @throws \ReflectionException
+     */
+    public function storeBy(array $data): mixed
+    {
+        $result = '';
+        $this->beginTransaction();
+        try {
+            $result = $this->create($this->filterData($data));
+            if (isset($data['user_ids']) && !empty($data['user_ids'])) {
+                $this->addUserNotice($data['user_ids'], $result->id);
+            }
+            $this->commit();
+        } catch (\Exception $exception) {
+            $this->rollback();
+        }
+        return $result->id ?? 0;
+    }
+
+    private function addUserNotice(mixed $userIds, mixed $id)
+    {
+        $list = [];
+        foreach ($userIds as $val) {
+            $list[] = ['user_id' => $val, 'notice_id' => $id];
+        }
+        if (!empty($list)) {
+            UserNotice::insert($list);
+        }
+        return true;
+    }
+
+
+}

+ 14 - 0
modules/System/Models/UserNotice.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace Modules\System\Models;
+
+
+class UserNotice extends BaseModel
+{
+    protected $table = 'user_notice';
+
+    protected $fillable = [
+        'id', 'user_id', 'notice_id', 'is_deleted', 'is_read', 'created_at', 'updated_at', 'deleted_at',
+    ];
+
+}

+ 31 - 0
modules/System/Providers/SystemServiceProvider.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace Modules\System\Providers;
+
+use Catch\CatchAdmin;
+use Catch\Providers\CatchModuleServiceProvider;
+use Modules\ContentManage\Middlewares\ContentManageGate;
+
+class SystemServiceProvider 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 'system';
+    }
+}

+ 10 - 0
modules/System/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 文件里

+ 88 - 0
modules/System/Services/Notice/NoitceTypeService.php

@@ -0,0 +1,88 @@
+<?php
+/**
+ * ${CARET}
+ * @file:NoitceTypeService.php
+ * @Created by gnitif
+ * @Date: 2023/3/27
+ * @Time: 11:54
+ */
+
+
+namespace Modules\System\Services\Notice;
+
+use Illuminate\Support\Facades\DB;
+use Modules\ContentManage\Models\NoticeTypes;
+
+class NoitceTypeService
+{
+
+    /**
+     *  添加分类
+     * name: store
+     * @param array $param
+     * $param [
+     *      'name' => "平台通知"
+     * ];
+     * date 2023/03/27 18:14
+     */
+    public static function store(array $param)
+    {
+        return self::getModel()->storeBy($param);
+    }
+
+    protected static function getModel(){
+         return new NoticeTypes();
+    }
+
+    /**
+     *  获取通知分类列表分类
+     * name: list
+     * @param mixed $param
+     *  $param = [
+     *      'name' => '系统通知', // 分类名称模糊搜索
+     *      'page' => 1, //  页码
+     *      'limit' => 15, //  每页条数
+     * ]
+     * @param mixed $isAll // 是否获取所有数据 默认否
+     * date 2023/03/28 17:05
+     */
+    public static function list($param = [], $isAll = false)
+    {
+        $where = self::getCondition($param);
+        if ($isAll){
+            return   NoticeTypes::where($where)->select('id','name')->get();
+        }else {
+            $pageSize = $param['limit'] ?? 15;
+            return   NoticeTypes::where($where)->select('id', 'name', 'created_at')->paginate($pageSize);
+        }
+
+    }
+
+    /**
+     *  拼接查询条件
+     * name: getCondition
+     * @param mixed $param
+     * @return \string[][]
+     * date 2023/03/28 17:19
+     */
+    private static function getCondition(mixed $param)
+    {
+        $where = [['is_deleted', '=', '0']];
+        if (isset($param['name']) && !empty($param['name'])) {
+            $where[] = ['name', 'like', "%" . $param['name'] . "%"];
+        }
+        return $where;
+    }
+
+    /**
+     *  删除分类,软删除
+     * name: del
+     * @param $id
+     * @return mixed
+     * date 2023/03/29 11:05
+     */
+    public static function del($id)
+    {
+        return self::getModel()->updateBy($id,['is_deleted' => 1,'deleted_at' => date("Y-m-d H:i:s")]);
+    }
+}

+ 248 - 0
modules/System/Services/Notice/NoticesService.php

@@ -0,0 +1,248 @@
+<?php
+/**
+ * ${CARET}
+ * @file:NoitceService.php
+ * @Created by gnitif
+ * @Date: 2023/3/27
+ * @Time: 11:54
+ */
+
+
+namespace Modules\System\Services\Notice;
+
+use Catch\Exceptions\FailedException;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\DB;
+use Modules\System\Models\Notices;
+use Modules\System\Models\UserNotice;
+use Modules\Permissions\Models\Roles;
+use Modules\User\Models\User;
+use PharIo\Manifest\Author;
+
+class NoticesService
+{
+
+    protected static function getModel()
+    {
+        return new Notices();
+    }
+
+    /**
+     *  添加通知
+     * name: addNotice
+     * @param array $param
+     *  $param = [
+     *      'title' => '测试', // 通知标题
+     *      'notice_type_id' =>  2, // 通知分类id
+     *      'type' => '2', // 通知人群 1全部 2,指定人,3指定角色
+     *      'notice_obj' => [['id' =>  1,'name' => "超管"]] , // 通知对象
+     *      'is_popup' => '1', // 是否是弹窗 1弹窗  0 普通
+     *       'content' => '312312', // 通知内容
+     * ];
+     *
+     * date 2023/03/29 14:25
+     */
+    public static function addNotice(array $param)
+    {
+
+        if ($param['type'] != 1 && (!isset($param['notice_obj']) || empty($param['notice_obj']))) {
+            throw new FailedException('通知对象不能为空!');
+        }
+
+        if ($param['type'] == 3) {
+            $roleIds = array_column($param['notice_obj'], 'id');
+            $userIds = DB::table('user_has_roles')->whereIn('role_id', $roleIds)->pluck('user_id')->toArray();
+        } else if ($param['type'] == 2) {
+            $userIds = array_column($param['notice_obj'], 'id');
+        } else {
+            $userIds = User::pluck('id')->toArray();
+            $param['notice_obj'] = [];
+        }
+        $param['user_ids'] = $userIds;
+        return self::getModel()->storeBy($param);
+    }
+
+    public static function delete($id)
+    {
+        return self::getModel()->updateBy($id, ['is_deleted' => 1, 'deleted_at' => get_date()]);
+    }
+
+    /**
+     *  获取通知详情
+     * name: getDetail
+     * @param $id
+     * @return \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|Notices[]
+     * date 2023/03/29 15:12
+     */
+    public static function getDetail($id)
+    {
+        $info = Notices::leftJoin('notice_types', 'notice_types.id', 'notices.notice_type_id')
+            ->select('notices.*', 'notice_types.name as notice_type_name')->where('notices.id', $id)->first();
+        return $info;
+    }
+
+    /**
+     *  更新
+     * name: update
+     * @param $id
+     * @param array $param
+     * date 2023/03/29 18:32
+     */
+    public static function update($id, array $param)
+    {
+       return  self::getModel()->updateBy($id, $param);
+    }
+
+    /**
+     *  管理员操作通知列表
+     * name: list
+     * @return mixed
+     * date 2023/03/29 22:49
+     */
+    public static function  list()
+    {
+        $list = self::getModel()->setBeforeGetList(function ($query) {
+            return $query->where('is_deleted', 0)->orderBy('created_at','desc');
+        })->getList();
+        if (!$list->isEmpty()) {
+            $cate = NoitceTypeService::list([], true);
+            if ($cate->isEmpty()) {
+                $cate = [];
+            } else {
+                $cate = array_column($cate->toArray(), null, 'id');
+            }
+
+            foreach ($list as $value) {
+                $value->notice_type_txt = $cate[$value->notice_type_id]['name'] ?? "";
+                $value->type_txt = $value->type == 1 ? "全部" : ($value->type == 2 ? "指定用户" : "指定角色");
+            }
+        }
+        return $list;
+    }
+
+    /**
+     * 我的通知
+     * name: myNoticesList
+     * date 2023/03/29 22:49
+     */
+    public static function myNoticesList($param = [])
+    {
+        $type = $param['type'] ?? "";
+        $noticeTypeId = $param['notice_type_id'] ?? 0;
+        $title = $param['title'] ?? "";
+        $pageSize = $param['limit'] ?? 0;
+        $pageSize = $pageSize < 1 ? 15 : $pageSize;
+        $userId = Auth::guard(getGuardName())->id();
+        $where = [
+            ['user_notice.is_deleted', '=', 0],
+            ['user_notice.user_id', '=', $userId],
+            ['notices.is_deleted', '=', 0],
+            ['user_notice.is_deleted', '=', 0],
+        ];
+        if ($type) {
+            $where[] = ['notices.type', '=', $type];
+        }
+        if ($noticeTypeId) {
+            $where[] = ['notices.notice_type_id', '=', $noticeTypeId];
+        }
+        if ($title) {
+            $where[] = ['notices.title', 'like', "%" . $title . "%"];
+        }
+
+        $list = UserNotice::leftJoin('notices', 'notices.id', "user_notice.notice_id")->where($where)->select('notices.id', 'notices.title', 'notices.is_popup', "user_notice.is_read", 'notices.created_at')
+            ->orderBy('notices.created_at', 'desc')->orderBy('sort', 'desc')->paginate($pageSize);
+        if (!$list->isEmpty()) {
+            foreach ($list as $val) {
+                $val->is_read_txt = $val->is_read == 1 ? "已读" : "未读";
+            }
+        }
+        return $list;
+    }
+
+    /**
+     *  设置已读
+     * name: setRead
+     * @param $id
+     * date 2023/03/29 23:51
+     */
+    public static function setRead($id)
+    {
+        $userId = Auth::guard(getGuardName())->id();
+        return UserNotice::where('user_id', $userId)->where('notice_id', $id)->update(['is_read' => 1, 'read_at' => get_date()]);
+    }
+
+    /**
+     *  用户删除
+     * name: userDel
+     * @param $id
+     * date 2023/03/29 23:55
+     */
+    public static function userDel($id)
+    {
+        $userId = Auth::guard(getGuardName())->id();
+        return UserNotice::where('user_id', $userId)->where('notice_id', $id)->update(['is_deleted' => 1, 'deleted_at' => get_date()]);
+    }
+
+    /**
+     *  阅读详情
+     * name: detail
+     * @param $id
+     * @return Notices
+     * date 2023/03/30 00:09
+     */
+    public static function detail($id)
+    {
+        return Notices::where('id', $id)->where('is_deleted', 0)->select('title', 'id', 'is_popup', 'content')->first();
+    }
+
+    /**
+     *  获取指定对象选择项
+     * name: objOption
+     * @param $type
+     * @param string $name
+     * @return array
+     * date 2023/03/30 10:23
+     */
+    public static function objOption($type, $name = ""): mixed
+    {
+        if ($type == 'user') {
+            if ($name) {
+                return  User::where("username", 'like', "%" . $name . "%")->without(['roles','jobs'])->select('id','username as name')->get();
+            }
+            return User::select('id','username as name')->without(['roles','jobs'])->get();
+        } else if ($type == "role") {
+            if ($name) {
+                return Roles::where("role_name", 'like', "%" . $name . "%")->select('id','role_name as name')->get();
+            }
+            return Roles::select('id','role_name as name')->get();
+        }
+        return [];
+    }
+
+    /**
+     *  一条获取弹窗信息
+     * name: getPopup
+     * @return Model|UserNotice|object|null
+     * date 2023/03/30 16:45
+     */
+    public static function getPopup()
+    {
+        $where = [
+            ['user_notice.is_deleted', '=', 0],
+            ['user_notice.user_id', '=',  Auth::guard(getGuardName())->id()],
+            ['notices.is_deleted', '=', 0],
+            ['notices.is_popup', '=', 1],
+            ['user_notice.is_read', '=', 0],
+        ];
+
+         $info =  UserNotice::leftJoin('notices', 'notices.id', "user_notice.notice_id")->where($where)->select('notices.id', 'notices.title', 'notices.content')
+             ->orderBy('notices.created_at', 'desc')->orderBy('sort', 'desc')->first();
+         if (empty($info)){
+             return  [];
+         }
+         return  $info;
+    }
+
+
+}

+ 56 - 0
modules/System/routes/route.php

@@ -0,0 +1,56 @@
+<?php
+
+use Illuminate\Support\Facades\Route;
+use Modules\System\Http\Controllers\NoticesController;
+use Modules\System\Http\Controllers\NoticeTypesController;
+
+Route::prefix('system')->group(function () {
+    // 通知管理
+    Route::prefix('notices')->group(function(){
+        // 通知分类
+        Route::prefix('types')->group(function (){
+            // 添加通知分类
+            Route::post('add',[NoticeTypesController::class, 'add']);
+            // 通知分类列表
+            Route::any('list',[NoticeTypesController::class, 'list']);
+            //  删除通知分类
+            Route::post('del/{id}',[NoticeTypesController::class, 'delete']);
+        });
+        // 通知管理
+        Route::prefix('notice')->group(function(){
+            // 添加通知
+            Route::post('add',[NoticesController::class, 'addNotice']);
+            // 通知列表
+            Route::any('list',[NoticesController::class, 'list']);
+            //  删除通知
+            Route::post('del/{id}',[NoticesController::class, 'delete']);
+            //   修改通知状态
+            Route::post('enable/{id}',[NoticesController::class, 'enable']);
+            // 获取编辑信息
+            Route::get('edit/{id}',[NoticesController::class, 'info']);
+            // 保存编辑
+            Route::post('edit/{id}',[NoticesController::class, 'edit']);
+
+            // 不判断权限
+            Route::prefix("")->group(function (){
+                // 通知对象接口
+                Route::any('obj_option',[NoticesController::class, 'objOption'])->withoutMiddleware(config('catch.route.middlewares'));
+                // 我的通知
+                Route::any('mine',[NoticesController::class, 'myNotices'])->withoutMiddleware(config('catch.route.middlewares'));
+                //  已读
+                Route::get('read/{id}',[NoticesController::class, 'setRead'])->withoutMiddleware(config('catch.route.middlewares'));
+                // 用户删除
+                Route::get('user_del/{id}',[NoticesController::class, 'userDel'])->withoutMiddleware(config('catch.route.middlewares'));
+                // 查看通知信息
+                Route::any('detail/{id}',[NoticesController::class, 'detail'])->withoutMiddleware(config('catch.route.middlewares'));
+                // 获取首页弹窗消息
+                Route::any('popup',[NoticesController::class, 'getPopup'])->withoutMiddleware(config('catch.route.middlewares'));
+
+            });
+
+        });
+
+    });
+
+});
+

+ 17 - 0
modules/T1/Exceptions/ContentBusinessException.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace Modules\ContentManage\Exceptions;
+
+use Throwable;
+
+class ContentBusinessException extends \RuntimeException
+{
+    public function __construct($message = "", $code = 0, Throwable $previous = null)
+    {
+        parent::__construct($message, $code, $previous);
+    }
+
+    public static function throwError($error, Throwable $previous = null) {
+        throw (new static($error[1], $error[0], $previous));
+    }
+}

+ 20 - 0
modules/T1/Exceptions/ContentManageForbidden.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace Modules\ContentManage\Exceptions;
+
+use Catch\Enums\Code;
+use Catch\Exceptions\CatchException;
+use Symfony\Component\HttpFoundation\Response;
+
+class ContentManageForbidden extends CatchException
+{
+    protected $message = 'permission forbidden';
+
+    protected $code = Code::PERMISSION_FORBIDDEN;
+
+
+    public function statusCode(): int
+    {
+        return Response::HTTP_FORBIDDEN;
+    }
+}

+ 9 - 0
modules/T1/Exceptions/Errors.php

@@ -0,0 +1,9 @@
+<?php
+
+namespace Modules\ContentManage\Exceptions;
+
+class Errors
+{
+    public const REQUEST_HTTP_STATUS_ERROR = [500001, '请求上游接口返回http状态码有误'];
+    public const REQUEST_CODE_STATUS_ERROR = [500002, '请求上游接口返回code状态码有误'];
+}

+ 33 - 0
modules/T1/Http/Controllers/T1Controller.php

@@ -0,0 +1,33 @@
+<?php
+/**
+ * ${CARET}
+ * @file:NoticesController.php
+ * @Created by gnitif
+ * @Date: 2023/3/27
+ * @Time: 11:18
+ */
+
+
+namespace Modules\T1\Http\Controllers;
+
+
+use Catch\Base\CatchController as Controller;
+use Catch\Exceptions\FailedException;
+use Illuminate\Contracts\Pagination\LengthAwarePaginator;
+use Illuminate\Http\Request;
+use Modules\System\Http\Requests\NoticeRequest;
+use Modules\System\Models\NoticeTypes;
+use Modules\System\Services\Notice\NoticesService;
+
+class T1Controller extends Controller
+{
+    public function list(Request $request)
+    {
+        return ['t1', 'list'];
+    }
+
+    public function list2(Request $request)
+    {
+        return ['t2', 'list2'];
+    }
+}

+ 32 - 0
modules/T1/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.
+    }
+}

+ 26 - 0
modules/T1/Middlewares/ContentManageGate.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace Modules\ContentManage\Middlewares;
+
+use Illuminate\Http\Request;
+use Modules\ContentManage\Exceptions\PermissionForbidden;
+use Modules\User\Models\User;
+
+class ContentManageGate
+{
+    public function handle(Request $request, \Closure $next)
+    {
+        if ($request->isMethod('get')) {
+            return $next($request);
+        }
+
+        /* @var User $user */
+        $user = $request->user(getGuardName());
+
+        if (! $user->can()) {
+            throw new PermissionForbidden();
+        }
+
+        return $next($request);
+    }
+}

+ 30 - 0
modules/T1/Models/BaseModel.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace Modules\System\Models;
+
+use Catch\Base\CatchModel as Model;
+use Illuminate\Database\Eloquent\Builder;
+
+
+abstract class BaseModel extends Model
+{
+
+    protected array $defaultHidden = [];
+
+    protected array $defaultCasts = [
+        'created_at' => 'datetime:Y-m-d H:i:s',
+
+        'updated_at' => 'datetime:Y-m-d H:i:s',
+    ];
+    protected $dateFormat = '';
+
+    public static function bootSoftDeletes(): void{
+
+    }
+
+
+    public function scopeActive(Builder $query): void
+    {
+        $query->where($this->table.'.is_enabled', 1);
+    }
+}

+ 15 - 0
modules/T1/Models/NoticeTypes.php

@@ -0,0 +1,15 @@
+<?php
+
+namespace Modules\System\Models;
+
+
+
+class NoticeTypes extends BaseModel
+{
+    protected $table = 'notice_types';
+
+    protected $fillable = [
+        'id', 'name', 'is_deleted', 'created_at', 'updated_at', 'deleted_at',
+    ];
+
+}

+ 73 - 0
modules/T1/Models/Notices.php

@@ -0,0 +1,73 @@
+<?php
+
+namespace Modules\System\Models;
+
+
+class Notices extends BaseModel
+{
+    protected $table = 'notices';
+
+    protected $fillable = [
+        'id', 'title', 'content', 'notice_type_id', "sort", 'type', 'notice_obj', 'is_popup', 'is_deleted', 'created_at', 'updated_at', 'deleted_at',
+    ];
+
+    /**
+     * @var array
+     */
+    protected array $fields = ['id', 'title', 'content', "sort", 'notice_type_id', 'type', 'notice_obj', 'is_popup', 'created_at', 'updated_at'];
+
+    /**
+     * @var array
+     */
+    protected array $form = ['title', 'content', 'notice_type_id',"sort", 'type', 'notice_obj', 'is_popup'];
+
+
+    protected $casts = ['notice_obj' => 'array'];
+
+    public array $searchable = [
+        'title' => 'like',
+        'notice_type_id' => '=',
+        'type' => '=',
+
+    ];
+
+    protected string $sortField = 'sort';
+
+
+
+    /**
+     *  添加通知
+     * @param array $data
+     * @return bool
+     * @throws \ReflectionException
+     */
+    public function storeBy(array $data): mixed
+    {
+        $result = '';
+        $this->beginTransaction();
+        try {
+            $result = $this->create($this->filterData($data));
+            if (isset($data['user_ids']) && !empty($data['user_ids'])) {
+                $this->addUserNotice($data['user_ids'], $result->id);
+            }
+            $this->commit();
+        } catch (\Exception $exception) {
+            $this->rollback();
+        }
+        return $result->id ?? 0;
+    }
+
+    private function addUserNotice(mixed $userIds, mixed $id)
+    {
+        $list = [];
+        foreach ($userIds as $val) {
+            $list[] = ['user_id' => $val, 'notice_id' => $id];
+        }
+        if (!empty($list)) {
+            UserNotice::insert($list);
+        }
+        return true;
+    }
+
+
+}

+ 14 - 0
modules/T1/Models/UserNotice.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace Modules\System\Models;
+
+
+class UserNotice extends BaseModel
+{
+    protected $table = 'user_notice';
+
+    protected $fillable = [
+        'id', 'user_id', 'notice_id', 'is_deleted', 'is_read', 'created_at', 'updated_at', 'deleted_at',
+    ];
+
+}

+ 29 - 0
modules/T1/Providers/T1ServiceProvider.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace Modules\T1\Providers;
+
+use Catch\Providers\CatchModuleServiceProvider;
+
+class T1ServiceProvider 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 't1';
+    }
+}

+ 10 - 0
modules/T1/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 文件里

+ 10 - 0
modules/T1/routes/route.php

@@ -0,0 +1,10 @@
+<?php
+
+use Illuminate\Support\Facades\Route;
+use Modules\T1\Http\Controllers\T1Controller;
+
+Route::prefix('t1')->group(function () {
+    Route::get('list', [T1Controller::class,'list']);
+    Route::get('list2', [T1Controller::class,'list2']);
+});
+

+ 17 - 0
modules/T2/Exceptions/ContentBusinessException.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace Modules\ContentManage\Exceptions;
+
+use Throwable;
+
+class ContentBusinessException extends \RuntimeException
+{
+    public function __construct($message = "", $code = 0, Throwable $previous = null)
+    {
+        parent::__construct($message, $code, $previous);
+    }
+
+    public static function throwError($error, Throwable $previous = null) {
+        throw (new static($error[1], $error[0], $previous));
+    }
+}

+ 20 - 0
modules/T2/Exceptions/ContentManageForbidden.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace Modules\ContentManage\Exceptions;
+
+use Catch\Enums\Code;
+use Catch\Exceptions\CatchException;
+use Symfony\Component\HttpFoundation\Response;
+
+class ContentManageForbidden extends CatchException
+{
+    protected $message = 'permission forbidden';
+
+    protected $code = Code::PERMISSION_FORBIDDEN;
+
+
+    public function statusCode(): int
+    {
+        return Response::HTTP_FORBIDDEN;
+    }
+}

+ 9 - 0
modules/T2/Exceptions/Errors.php

@@ -0,0 +1,9 @@
+<?php
+
+namespace Modules\ContentManage\Exceptions;
+
+class Errors
+{
+    public const REQUEST_HTTP_STATUS_ERROR = [500001, '请求上游接口返回http状态码有误'];
+    public const REQUEST_CODE_STATUS_ERROR = [500002, '请求上游接口返回code状态码有误'];
+}

+ 29 - 0
modules/T2/Http/Controllers/T2Controller.php

@@ -0,0 +1,29 @@
+<?php
+/**
+ * ${CARET}
+ * @file:NoticesController.php
+ * @Created by gnitif
+ * @Date: 2023/3/27
+ * @Time: 11:18
+ */
+
+
+namespace Modules\T2\Http\Controllers;
+
+
+use Catch\Base\CatchController as Controller;
+
+use Illuminate\Http\Request;
+
+
+class T2Controller extends Controller
+{
+    public function list(Request $request)
+    {
+        return ['t2', 'list'];
+    }
+    public function list2(Request $request)
+    {
+        return ['t2', 'list2'];
+    }
+}

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

@@ -0,0 +1,56 @@
+<?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;
+        }
+    }
+}

+ 32 - 0
modules/T2/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.
+    }
+}

+ 26 - 0
modules/T2/Middlewares/ContentManageGate.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace Modules\ContentManage\Middlewares;
+
+use Illuminate\Http\Request;
+use Modules\ContentManage\Exceptions\PermissionForbidden;
+use Modules\User\Models\User;
+
+class ContentManageGate
+{
+    public function handle(Request $request, \Closure $next)
+    {
+        if ($request->isMethod('get')) {
+            return $next($request);
+        }
+
+        /* @var User $user */
+        $user = $request->user(getGuardName());
+
+        if (! $user->can()) {
+            throw new PermissionForbidden();
+        }
+
+        return $next($request);
+    }
+}

+ 30 - 0
modules/T2/Models/BaseModel.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace Modules\System\Models;
+
+use Catch\Base\CatchModel as Model;
+use Illuminate\Database\Eloquent\Builder;
+
+
+abstract class BaseModel extends Model
+{
+
+    protected array $defaultHidden = [];
+
+    protected array $defaultCasts = [
+        'created_at' => 'datetime:Y-m-d H:i:s',
+
+        'updated_at' => 'datetime:Y-m-d H:i:s',
+    ];
+    protected $dateFormat = '';
+
+    public static function bootSoftDeletes(): void{
+
+    }
+
+
+    public function scopeActive(Builder $query): void
+    {
+        $query->where($this->table.'.is_enabled', 1);
+    }
+}

+ 15 - 0
modules/T2/Models/NoticeTypes.php

@@ -0,0 +1,15 @@
+<?php
+
+namespace Modules\System\Models;
+
+
+
+class NoticeTypes extends BaseModel
+{
+    protected $table = 'notice_types';
+
+    protected $fillable = [
+        'id', 'name', 'is_deleted', 'created_at', 'updated_at', 'deleted_at',
+    ];
+
+}

+ 73 - 0
modules/T2/Models/Notices.php

@@ -0,0 +1,73 @@
+<?php
+
+namespace Modules\System\Models;
+
+
+class Notices extends BaseModel
+{
+    protected $table = 'notices';
+
+    protected $fillable = [
+        'id', 'title', 'content', 'notice_type_id', "sort", 'type', 'notice_obj', 'is_popup', 'is_deleted', 'created_at', 'updated_at', 'deleted_at',
+    ];
+
+    /**
+     * @var array
+     */
+    protected array $fields = ['id', 'title', 'content', "sort", 'notice_type_id', 'type', 'notice_obj', 'is_popup', 'created_at', 'updated_at'];
+
+    /**
+     * @var array
+     */
+    protected array $form = ['title', 'content', 'notice_type_id',"sort", 'type', 'notice_obj', 'is_popup'];
+
+
+    protected $casts = ['notice_obj' => 'array'];
+
+    public array $searchable = [
+        'title' => 'like',
+        'notice_type_id' => '=',
+        'type' => '=',
+
+    ];
+
+    protected string $sortField = 'sort';
+
+
+
+    /**
+     *  添加通知
+     * @param array $data
+     * @return bool
+     * @throws \ReflectionException
+     */
+    public function storeBy(array $data): mixed
+    {
+        $result = '';
+        $this->beginTransaction();
+        try {
+            $result = $this->create($this->filterData($data));
+            if (isset($data['user_ids']) && !empty($data['user_ids'])) {
+                $this->addUserNotice($data['user_ids'], $result->id);
+            }
+            $this->commit();
+        } catch (\Exception $exception) {
+            $this->rollback();
+        }
+        return $result->id ?? 0;
+    }
+
+    private function addUserNotice(mixed $userIds, mixed $id)
+    {
+        $list = [];
+        foreach ($userIds as $val) {
+            $list[] = ['user_id' => $val, 'notice_id' => $id];
+        }
+        if (!empty($list)) {
+            UserNotice::insert($list);
+        }
+        return true;
+    }
+
+
+}

+ 14 - 0
modules/T2/Models/UserNotice.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace Modules\System\Models;
+
+
+class UserNotice extends BaseModel
+{
+    protected $table = 'user_notice';
+
+    protected $fillable = [
+        'id', 'user_id', 'notice_id', 'is_deleted', 'is_read', 'created_at', 'updated_at', 'deleted_at',
+    ];
+
+}

+ 31 - 0
modules/T2/Providers/T2ServiceProvider.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace Modules\T2\Providers;
+
+use Catch\CatchAdmin;
+use Catch\Providers\CatchModuleServiceProvider;
+use Modules\ContentManage\Middlewares\ContentManageGate;
+
+class T2ServiceProvider 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 't2';
+    }
+}

+ 10 - 0
modules/T2/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 文件里

+ 10 - 0
modules/T2/routes/route.php

@@ -0,0 +1,10 @@
+<?php
+
+use Illuminate\Support\Facades\Route;
+use Modules\T2\Http\Controllers\T2Controller;
+
+
+Route::prefix('t2')->group(function () {
+    Route::get('list', [T2Controller::class,'list']);
+    Route::get('list', [T2Controller::class, 'list2']);
+});

+ 4 - 1
modules/User/Http/Controllers/UserController.php

@@ -8,6 +8,7 @@ use Illuminate\Contracts\Auth\Authenticatable;
 use Illuminate\Contracts\Pagination\LengthAwarePaginator;
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\DB;
+use Modules\Common\Repository\Options\Modules;
 use Modules\User\Models\LogLogin;
 use Modules\User\Models\LogOperate;
 use Modules\User\Models\User;
@@ -144,11 +145,13 @@ class UserController extends Controller
     {
         /* @var User $user */
         $user = $this->getLoginUser()->withPermissions();
+        $showApp = $request->get('app');
+        $user->showPermissions($showApp);
 
         if ($request->isMethod('post')) {
             return $user->updateBy($user->id, $request->all());
         }
-
+        unset($user->password);
         return $user;
     }
 

+ 2 - 2
modules/User/Models/Traits/UserRelations.php

@@ -64,13 +64,13 @@ trait UserRelations
         } else {
             $permissions = Collection::make();
             $roleIds = $this->roles()->pluck('role_id')->toArray();
-            app($this->getRolesModel())->where(['id' => $roleIds])->with(['permissions' => function($query){
+            app($this->getRolesModel())->whereIn('id', $roleIds)->with(['permissions' => function($query){
                 return $query->where('hidden',1)->orderByDesc('sort');
             }])->get()
                 ->each(function ($role) use (&$permissions) {
                     $permissions = $permissions->concat($role->permissions);
                 });
-            $permissions = $permissions->unique();
+            $permissions = $permissions->unique('id');
         }
 
         $this->setAttribute('permissions', $permissions->each(fn ($permission) => $permission->setAttribute('hidden', $permission->isHidden())));

+ 35 - 1
modules/User/Models/User.php

@@ -6,6 +6,9 @@ use Catch\Base\CatchModel as Model;
 use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
 use Illuminate\Database\Eloquent\Casts\Attribute;
 use Laravel\Sanctum\HasApiTokens;
+use Modules\Channel\Exceptions\ChannelBusinessException;
+use Modules\Common\Errors\Errors;
+use Modules\Common\Repository\Options\Modules;
 use Modules\User\Models\Traits\UserRelations;
 use Illuminate\Auth\Authenticatable;
 
@@ -28,7 +31,9 @@ class User extends Model implements AuthenticatableContract
     use Authenticatable, UserRelations, HasApiTokens;
 
     protected $fillable = [
-        'id', 'username', 'email', 'avatar', 'password', 'remember_token', 'creator_id', 'status', 'department_id', 'login_ip', 'login_at', 'created_at', 'updated_at', 'deleted_at'
+        'id', 'username', 'email', 'avatar', 'password', 'remember_token', 'creator_id',
+        'status', 'department_id', 'login_ip', 'login_at', 'created_at', 'updated_at', 'deleted_at',
+        'remark'
     ];
 
     /**
@@ -104,4 +109,33 @@ class User extends Model implements AuthenticatableContract
 
         return parent::updateBy($id, $data);
     }
+
+    /**
+     * 如果$showApp为空那么就不展示所有isApp为true的模块
+     * 否则展示所有isApp为false以及showApp对应的name的模块
+     * @param string $showApp
+     */
+    public function showPermissions($showApp = '') {
+        $hiddenAppModuleNames = Modules::getAppModules()->reject(function ($module) use ($showApp) {
+            return $showApp == $module['name'];
+        })->pluck('name');
+        $enablePermissions = $this->getAttribute('permissions')->reject(function ($permission) use ($hiddenAppModuleNames){
+            return $hiddenAppModuleNames->contains($permission['module']);
+        })->values()->all();
+        $this->setAttribute('permissions', $enablePermissions);
+    }
+
+    /**
+     * 保证邮箱没有被使用
+     * @param $email
+     */
+    public function emailUnique($email) {
+        $user = $this->where([
+            'email' => $email,
+            'deleted_at' => 0,
+        ])->first();
+        if($user) {
+            ChannelBusinessException::throwError(Errors::EMAIL_EXISTS);
+        }
+    }
 }

+ 61 - 0
tests/Channel/Http/Controllers/AdvertiserControllerTest.php

@@ -0,0 +1,61 @@
+<?php
+
+namespace Tests\Channel\Http\Controllers;
+
+use Modules\Channel\Http\Controllers\AdvertiserController;
+use PHPUnit\Framework\TestCase;
+use Tests\UsedTestCase;
+
+class AdvertiserControllerTest extends UsedTestCase
+{
+
+    public function testAddAdvertiser()
+    {
+        $res = $this->withHeaders([
+            'Authorization' => 'Bearer '. $this->token,
+        ])->json('post','http://localhost/api/channel/advertiser/add', [
+            'email' => 'aa4@test.com',
+            'password' => '123',
+            'repassword' => '123',
+            'status' => 1,
+            'remark' => 'kljlkjkj',
+            'miniProgramIds'=> [1,2,3],
+            'username' => 'aa1@test'
+        ]);
+        $res->dump();
+    }
+
+    public function testlistAdvertiser() {
+        $res = $this->withHeaders([
+            'Authorization' => 'Bearer '. $this->token,
+        ])->json('get','http://localhost/api/channel/advertiser/listAdvertiser?'.http_build_query([
+//                'email' => 'aa1@test.com',
+//                'miniProgramId' => 3,
+            'username' => 'aa'
+            ]));
+        dump(\json_encode($res->json()));
+    }
+
+    public function testgetAdvertiser() {
+        $res = $this->withHeaders([
+            'Authorization' => 'Bearer '. $this->token,
+        ])->json('get','http://localhost/api/channel/advertiser/getAdvertiser?'.http_build_query([
+//                'email' => 'aa1@test.com',
+//                'miniProgramId' => 3,
+                'id' => 6
+            ]));
+        $this->dumpJson($res);
+    }
+
+    public function testupdateAdvertiser() {
+        $res = $this->withHeaders([
+            'Authorization' => 'Bearer '. $this->token,
+        ])->json('post','http://localhost/api/channel/advertiser/updateAdvertiser', [
+            'id' => 6,
+            'username' => 'change@aa@test',
+            'miniProgramIds' => [1,5,6,7],
+            'status' => 0,
+            'remark' => 'first change'
+        ]);
+    }
+}

+ 19 - 0
tests/Common/Http/Controllers/ModuleControllerTest.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace Tests\Common\Http\Controllers;
+
+use Modules\Common\Http\Controllers\ModuleController;
+use PHPUnit\Framework\TestCase;
+use Tests\UsedTestCase;
+
+class ModuleControllerTest extends UsedTestCase
+{
+
+    public function testListApp()
+    {
+        $res = $this->withHeaders([
+            'Authorization' => 'Bearer '. $this->token,
+        ])->json('get','http://localhost/api/modules/listApp');
+        $res->dump();
+    }
+}

+ 5 - 3
tests/UsedTestCase.php

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

+ 7 - 0
tests/User/Http/Controllers/UserControllerTest.php

@@ -32,4 +32,11 @@ class UserControllerTest extends \Tests\UsedTestCase
         ])->json('post','http://localhost/api/users', \json_decode($jsonStr, true));
         $res->dump();
     }
+
+    public function testOnline() {
+        $res = $this->withHeaders([
+            'Authorization' => 'Bearer '. $this->token,
+        ])->json('get','http://localhost/api/user/online');
+        $res->dump();
+    }
 }