diff --git a/README.md b/README.md index 30010fcdd7ef128d5ac7640a79f3a5b1aeee8810..715e20bf053ae3ba64a3e341e06707d033a6f688 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,9 @@ ## 作者 [小丑路人](https://www.cnpscy.com) +## 社区 +[小丑路人社区](https://bbs.cnpscy.com) + #### 介绍 [demo](http://laravel-vue-admin.cnpscy.com/admin) diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 48a509985bce8e4996e5feb466354cad662a6e17..e3e9edcdecde4a09c403932a51a337fa6c96fe75 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -3,7 +3,10 @@ namespace App\Exceptions; use App\Traits\Json; +use Illuminate\Validation\ValidationException; +use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Throwable; class Handler extends ExceptionHandler @@ -19,8 +22,8 @@ class Handler extends ExceptionHandler \Illuminate\Auth\AuthenticationException::class, \Illuminate\Auth\Access\AuthorizationException::class, \Symfony\Component\HttpKernel\Exception\HttpException::class, - \Illuminate\Database\Eloquent\ModelNotFoundException::class, - \Illuminate\Validation\ValidationException::class, + ModelNotFoundException::class, + ValidationException::class, ]; /** @@ -57,11 +60,30 @@ class Handler extends ExceptionHandler */ public function render($request, Throwable $exception) { + // 路由404异常监听 + if($exception instanceof NotFoundHttpException){ + $this->setHttpCode(404); + return $this->errorJson("路由{{$request->path()}}不存在!"); + } + + // 模型不存在 + if ($exception instanceof ModelNotFoundException){ + return $this->errorJson($exception->getMessage()); + } + // 验证器类的错误监听 - if($exception instanceof \Illuminate\Validation\ValidationException){ + if($exception instanceof ValidationException){ return $this->errorJson($exception->validator->errors()->first()); } + // Exception类的错误监听 + if($exception instanceof \Exception){ + return $this->errorJson($exception->getMessage(), $exception->getCode(), [], [ + 'file' => $exception->getFile(), + 'line' => $exception->getLine(), + ]); + } + return parent::render($request, $exception); } } diff --git a/app/Models/Model.php b/app/Models/Model.php index ccdea0b229cbc2d3f69a49942c9f8fa2c9ef1937..ee229d80251498e619f53753b0b5b1a1ef5ed326 100644 --- a/app/Models/Model.php +++ b/app/Models/Model.php @@ -2,7 +2,7 @@ namespace App\Models; -use App\Scopes\DeleteScope; +use App\Models\SoftDelete\SoftDelete; use App\Traits\Instance; use App\Traits\MysqlTable; use Illuminate\Database\Eloquent\Factories\HasFactory; @@ -10,6 +10,7 @@ use Illuminate\Database\Eloquent\Model as EloquentModel; class Model extends EloquentModel { + use SoftDelete; use MysqlTable; use Instance; use HasFactory; @@ -48,22 +49,6 @@ class Model extends EloquentModel return $this->attributes[self::UPDATED_AT]; } - /** - * 自定义的软删除 - */ - protected $is_delete = 1; //是否开启删除(1.开启删除,就是直接删除;0.假删除) - protected $delete_field = 'is_delete'; //删除字段 - - public function getIsDelete() - { - return $this->is_delete; - } - - public function getDeleteField() - { - return $this->delete_field; - } - /** * 不可批量赋值的属性 * @@ -71,19 +56,6 @@ class Model extends EloquentModel */ protected $guarded = []; - /** - * 模型的 "booted" 方法 - * - * 应用全局作用域 - * - * @return void - */ - protected static function booted() - { - // 假删除的作用域 - static::addGlobalScope(new DeleteScope(new static)); - } - public static function firstByWhere($where) { return self::where($where)->first(); diff --git a/app/Models/SoftDelete/DeleteScope.php b/app/Models/SoftDelete/DeleteScope.php new file mode 100644 index 0000000000000000000000000000000000000000..ff1a32bb68812e7696b6c7b0ec64684e4e44caf4 --- /dev/null +++ b/app/Models/SoftDelete/DeleteScope.php @@ -0,0 +1,143 @@ +getIsDelete() == 0) $builder->where($model->getQualifiedDeletedAtColumn(), $model->getIsDelete()); + } + + /** + * Extend the query builder with the needed functions. + * + * @param \Illuminate\Database\Eloquent\Builder $builder + * @return void + */ + public function extend(Builder $builder) + { + // 假删除时,才需要调用扩展方法与更新字段状态 + if ($builder->getModel()->getIsDelete() == 0){ + foreach ($this->extensions as $extension) { + $this->{"add{$extension}"}($builder); + } + + $builder->onDelete(function (Builder $builder) { + $column = $this->getDeletedAtColumn($builder); + + return $builder->update([ + $column => 1, + ]); + }); + } + } + + /** + * Get the "deleted at" column for the builder. + * + * @param \Illuminate\Database\Eloquent\Builder $builder + * @return string + */ + protected function getDeletedAtColumn(Builder $builder) + { + if (count((array) $builder->getQuery()->joins) > 0) { + return $builder->getModel()->getQualifiedDeletedAtColumn(); + } + + return $builder->getModel()->getDeletedAtColumn(); + } + + /** + * Add the restore extension to the builder. + * + * @param \Illuminate\Database\Eloquent\Builder $builder + * @return void + */ + protected function addRestore(Builder $builder) + { + $builder->macro('restore', function (Builder $builder) { + $builder->withTrashed(); + + return $builder->update([$builder->getModel()->getDeletedAtColumn() => 0]); + }); + } + + /** + * Add the with-trashed extension to the builder. + * + * @param \Illuminate\Database\Eloquent\Builder $builder + * @return void + */ + protected function addWithTrashed(Builder $builder) + { + $builder->macro('withTrashed', function (Builder $builder, $withTrashed = true) { + if (! $withTrashed) { + return $builder->withoutTrashed(); + } + + return $builder->withoutGlobalScope($this); + }); + } + + /** + * Add the without-trashed extension to the builder. + * + * @param \Illuminate\Database\Eloquent\Builder $builder + * @return void + */ + protected function addWithoutTrashed(Builder $builder) + { + $builder->macro('withoutTrashed', function (Builder $builder) { + $model = $builder->getModel(); + + $builder->withoutGlobalScope($this)->where($model->getQualifiedDeletedAtColumn(), 0); + + return $builder; + }); + } + + /** + * Add the only-trashed extension to the builder. + * + * @param \Illuminate\Database\Eloquent\Builder $builder + * @return void + */ + protected function addOnlyTrashed(Builder $builder) + { + $builder->macro('onlyTrashed', function (Builder $builder) { + $model = $builder->getModel(); + + $builder->withoutGlobalScope($this)->where($model->getQualifiedDeletedAtColumn(), 0); + + return $builder; + }); + } +} diff --git a/app/Models/SoftDelete/SoftDelete.php b/app/Models/SoftDelete/SoftDelete.php new file mode 100644 index 0000000000000000000000000000000000000000..09807b727039df38f0b9a4347714dd516dc55199 --- /dev/null +++ b/app/Models/SoftDelete/SoftDelete.php @@ -0,0 +1,194 @@ +is_delete; + } + + public function getDeleteField() + { + return static::DELETE_FIELD; + } + + /** + * Boot the soft deleting trait for a model. + * + * @return void + */ + public static function bootSoftDelete() + { + static::addGlobalScope(new DeleteScope()); + } + + /** + * Force a hard delete on a soft deleted model. + * + * @return bool|null + */ + public function forceDelete() + { + $this->is_delete = 1; + + return tap($this->delete(), function ($deleted) { + $this->is_delete = 0; + + if ($deleted) { + $this->fireModelEvent('forceDeleted', false); + } + }); + } + + /** + * Perform the actual delete query on this model instance. + * + * @return mixed + */ + protected function performDeleteOnModel() + { + if ($this->is_delete) { + $this->exists = false; + + return $this->setKeysForSaveQuery($this->newModelQuery())->forceDelete(); + } + + return $this->runSoftDelete(); + } + + /** + * Perform the actual delete query on this model instance. + * + * @return void + */ + protected function runSoftDelete() + { + $query = $this->setKeysForSaveQuery($this->newModelQuery()); + + $time = $this->freshTimestamp(); + + $columns = [$this->getDeletedAtColumn() => 1]; + + $this->{$this->getDeletedAtColumn()} = $time; + + if ($this->timestamps && ! is_null($this->getUpdatedAtColumn())) { + $this->{$this->getUpdatedAtColumn()} = $time; + + $columns[$this->getUpdatedAtColumn()] = $this->fromDateTime($time); + } + + $query->update($columns); + + $this->syncOriginalAttributes(array_keys($columns)); + + $this->fireModelEvent('trashed', false); + } + + /** + * Restore a soft-deleted model instance. + * + * @return bool|null + */ + public function restore() + { + // If the restoring event does not return false, we will proceed with this + // restore operation. Otherwise, we bail out so the developer will stop + // the restore totally. We will clear the deleted timestamp and save. + if ($this->fireModelEvent('restoring') === false) { + return false; + } + + $this->{$this->getDeletedAtColumn()} = null; + + // Once we have saved the model, we will fire the "restored" event so this + // developer will do anything they need to after a restore operation is + // totally finished. Then we will return the result of the save call. + $this->exists = true; + + $result = $this->save(); + + $this->fireModelEvent('restored', false); + + return $result; + } + + /** + * Determine if the model instance has been soft-deleted. + * + * @return bool + */ + public function trashed() + { + return ! is_null($this->{$this->getDeletedAtColumn()}); + } + + /** + * Register a "softDeleted" model event callback with the dispatcher. + * + * @param \Closure|string $callback + * @return void + */ + public static function softDeleted($callback) + { + static::registerModelEvent('trashed', $callback); + } + + /** + * Register a "restoring" model event callback with the dispatcher. + * + * @param \Closure|string $callback + * @return void + */ + public static function restoring($callback) + { + static::registerModelEvent('restoring', $callback); + } + + /** + * Register a "restored" model event callback with the dispatcher. + * + * @param \Closure|string $callback + * @return void + */ + public static function restored($callback) + { + static::registerModelEvent('restored', $callback); + } + + /** + * Register a "forceDeleted" model event callback with the dispatcher. + * + * @param \Closure|string $callback + * @return void + */ + public static function forceDeleted($callback) + { + static::registerModelEvent('forceDeleted', $callback); + } + + /** + * Get the name of the "deleted at" column. + * + * @return string + */ + public function getDeletedAtColumn() + { + return defined('static::DELETED_AT') ? static::DELETED_FIELD : 'is_delete'; + } + + /** + * Get the fully qualified "deleted at" column. + * + * @return string + */ + public function getQualifiedDeletedAtColumn() + { + return $this->qualifyColumn($this->getDeletedAtColumn()); + } +} diff --git a/app/Modules/Admin/Entities/Rabc/AdminMenu.php b/app/Modules/Admin/Entities/Rabc/AdminMenu.php index c599b9601398118a87945d007d47d6e4aafed20f..ebe65aa8a65b106bc394ce765d92f3428fa31cd2 100644 --- a/app/Modules/Admin/Entities/Rabc/AdminMenu.php +++ b/app/Modules/Admin/Entities/Rabc/AdminMenu.php @@ -16,7 +16,7 @@ class AdminMenu extends Model public function getSelectLists() { - return list_to_tree($this->orderBy('menu_sort', 'ASC')->get()->toArray()); + return list_to_tree($this->select(['menu_id', 'menu_name', 'parent_id'])->orderBy('menu_sort', 'ASC')->get()->toArray()); } public function getMenusByIds(array $menu_ids) diff --git a/app/Modules/Admin/Http/Controllers/UploadController.php b/app/Modules/Admin/Http/Controllers/UploadController.php index ac287ffdf8c74951d30b03d0402b906ac37c28e7..a04bf27af7940e9faeb4d2dd389a422f22c249f5 100644 --- a/app/Modules/Admin/Http/Controllers/UploadController.php +++ b/app/Modules/Admin/Http/Controllers/UploadController.php @@ -11,6 +11,7 @@ class UploadController extends BaseController * 文件上传 * * @param \Illuminate\Http\Request $request + * @param string $dir_path 文件夹 * @param string $file * * @return \Illuminate\Http\JsonResponse @@ -21,14 +22,10 @@ class UploadController extends BaseController return $this->errorJson('请上传文件!'); } - // var_dump($request->file($file)->getClientOriginalExtension()); - // var_dump($request->file($file)->getMimeType()); - // var_dump($request->file($file)->getType()); - // var_dump($request->file($file)->getClientMimeType()); - // exit; + $dir_path = (empty($request->dir_path) ? '' : ($request->dir_path . '/')) . date('Ym'); $path = $request->file($file)->storePublicly( - date('Ym'), + $dir_path, config('filesystems') ); diff --git a/app/Modules/Admin/Http/Requests/Rabc/AdminMenuRequest.php b/app/Modules/Admin/Http/Requests/Rabc/AdminMenuRequest.php index be8ffb659eef03e72fbf7d6ea8324fe46fc2c904..ed6fe3219fb6626db31dce6790be961d53c925a9 100644 --- a/app/Modules/Admin/Http/Requests/Rabc/AdminMenuRequest.php +++ b/app/Modules/Admin/Http/Requests/Rabc/AdminMenuRequest.php @@ -7,10 +7,10 @@ use App\Modules\Admin\Http\Requests\BaseRequest; class AdminMenuRequest extends BaseRequest { - public function setInstance() - { - $this->instance = AdminMenu::getInstance(); - } + // public function setInstance() + // { + // $this->instance = AdminMenu::getInstance(); + // } /** * Get the validation rules that apply to the request. @@ -23,7 +23,7 @@ class AdminMenuRequest extends BaseRequest 'menu_name' => [ 'required', 'max:256', - 'unique:' . $this->instance->getTable() . ',menu_name' . $this->validate_id + // 'unique:' . $this->instance->getTable() . ',menu_name' . $this->validate_id ], ]; } diff --git a/app/Modules/Admin/Http/Requests/Rabc/AdminRequest.php b/app/Modules/Admin/Http/Requests/Rabc/AdminRequest.php index 5b597501fd6c0babf76231f0a7cc79bf57accac0..d912f45f293aaa834fe6fe913d4cfcdc95742079 100644 --- a/app/Modules/Admin/Http/Requests/Rabc/AdminRequest.php +++ b/app/Modules/Admin/Http/Requests/Rabc/AdminRequest.php @@ -46,6 +46,7 @@ class AdminRequest extends BaseRequest { return [ 'admin_name.required' => '请输入管理员账户!', + 'admin_name.unique' => '管理员账户已存在!', 'password.confirmed' => '密码确认不匹配!', ]; } diff --git a/app/Modules/Admin/Services/AdminRoleService.php b/app/Modules/Admin/Services/AdminRoleService.php index d39de37981da970b889c965e762bb730ea93de9d..3c0285751607883780c610b7f918770ee247e899 100644 --- a/app/Modules/Admin/Services/AdminRoleService.php +++ b/app/Modules/Admin/Services/AdminRoleService.php @@ -40,7 +40,7 @@ class AdminRoleService extends BaseService if (!empty($search)){ $query->where('role_name', 'LIKE', '%' . trim($search) . '%'); } - })->with(['menus'])->orderBy($this->model->getKeyName(), 'ASC')->limit(100)->get(); + })->where('is_check', 1)->select(['role_id', 'role_name', 'role_remarks'])->orderBy($this->model->getKeyName(), 'ASC')->limit(100)->get(); } public function create(array $params) diff --git a/app/Modules/Admin/Services/BaseService.php b/app/Modules/Admin/Services/BaseService.php index 891528e5104dddeb8d85dc83ecdc390639343317..9189b67ae8e060f34f8bf2ecc5306a284178c17b 100644 --- a/app/Modules/Admin/Services/BaseService.php +++ b/app/Modules/Admin/Services/BaseService.php @@ -2,6 +2,7 @@ namespace App\Modules\Admin\Services; +use App\Exceptions\Exception; use App\Models\MonthModel; use App\Services\Service; @@ -65,6 +66,9 @@ class BaseService extends Service */ public function create(array $params) { + $this->setError('新增成功!'); + // 新增时,移除唯一标识 + unset($params[$this->model->getKeyName()]); return $this->detail = $this->model->create($this->model->setFilterFields($params)); } @@ -78,7 +82,13 @@ class BaseService extends Service public function update(array $params) { $primaryKey = $this->model->getKeyName(); + if (!isset($params[$primaryKey])){ + throw new Exception('请设置主键'); + } $this->detail = $this->model->find($params[$primaryKey]); + if (!$this->detail){ + throw new Exception('编辑信息不存在!'); + } foreach ($this->model->setFilterFields($params) as $field => $value){ $this->detail->$field = $value ?? ''; } @@ -110,11 +120,7 @@ class BaseService extends Service if ($this->model instanceof MonthModel && isset($params['month'])){ $this->model = $this->model->setMonthTable($params['month']); } - if ($this->model->getIsDelete() == 0){ - return $this->model->whereIn($primaryKey, $ids)->update([$this->model->getDeleteField() => 1]); - }else{ - return $this->model->whereIn($primaryKey, $ids)->delete(); - } + return $this->model->whereIn($primaryKey, $ids)->delete(); } /** diff --git a/app/Scopes/DeleteScope.php b/app/Scopes/DeleteScope.php deleted file mode 100644 index 6fe95f3d22e571c6385d328f3da15d6af4a467b1..0000000000000000000000000000000000000000 --- a/app/Scopes/DeleteScope.php +++ /dev/null @@ -1,31 +0,0 @@ -is_delete = $model->getIsDelete(); - $this->delete_field = $model->getDeleteField(); - } - - /** - * 把约束加到 Eloquent 查询构造中 - * - * @param \Illuminate\Database\Eloquent\Builder $builder - * @param \Illuminate\Database\Eloquent\Model $model - * @return void - */ - public function apply(Builder $builder, Model $model) - { - if ($this->is_delete == 0) $builder->where($this->delete_field, $this->is_delete); - } -}