diff --git a/app/Admin/Controllers/AdminUserController.php b/app/Admin/Controllers/AdminUserController.php new file mode 100644 index 0000000..3a5a8ba --- /dev/null +++ b/app/Admin/Controllers/AdminUserController.php @@ -0,0 +1,78 @@ +baseCRUD() + ->headerToolbar([ + $this->createButton(true), + ...$this->baseHeaderToolBar(), + ]) + ->filter($this->baseFilter()->body( + amisMake()->TextControl('keyword', __('admin.keyword')) + ->size('md') + ->placeholder(__('admin.admin_user.search_username')) + )) + ->quickSaveItemApi(admin_url('quick-edit/admin_users/$id')) + ->itemCheckableOn('${id !== 1}') + ->columns([ + amisMake()->TableColumn('id', 'ID')->sortable(), + amisMake()->TableColumn('avatar', __('admin.admin_user.avatar'))->type('avatar')->src('${avatar}'), + amisMake()->TableColumn('username', __('admin.username')), + amisMake()->TableColumn('name', __('admin.admin_user.name')), + amisMake()->TableColumn('roles', __('admin.admin_user.roles'))->type('each')->items( + amisMake()->Tag()->label('${name}')->className('my-1') + ), + amisMake()->TableColumn('lock', '锁定')->quickEdit(SwitchControl::make()->saveImmediately(true)->mode('inline')->disabledOn('${id === 1}')), + amisMake()->TableColumn('created_at', __('admin.created_at'))->type('datetime')->sortable(true), + Operation::make()->label(__('admin.actions'))->buttons([ + $this->rowEditButton(true)->visibleOn('${id != 1}'), + $this->rowDeleteButton()->visibleOn('${id != 1}'), + ]), + ]); + + return $this->baseList($crud); + } + + public function form(): Form + { + return $this->baseForm()->body([ + amisMake()->ImageControl('avatar', __('admin.admin_user.avatar'))->receiver($this->uploadImagePath()), + amisMake()->TextControl('username', __('admin.username'))->required(), + amisMake()->TextControl('name', __('admin.admin_user.name'))->required(), + amisMake()->TextControl('password', __('admin.password'))->type('input-password')->required()->validations(['minLength' => 6]), + amisMake()->TextControl('confirm_password', __('admin.confirm_password'))->type('input-password')->required()->validations(['minLength' => 6]), + amisMake()->SelectControl('roles', __('admin.admin_user.roles')) + ->searchable() + ->multiple() + ->labelField('name') + ->valueField('id') + ->joinValues(false) + ->extractValue() + ->options(AdminRoleService::make()->query()->get(['id', 'name'])), + SwitchControl::make()->name('lock')->label('锁定')->value(false), + ]); + } + + public function detail(): Form + { + return $this->baseDetail()->body([]); + } +} diff --git a/app/Services/Admin/AdminUserService.php b/app/Services/Admin/AdminUserService.php new file mode 100644 index 0000000..86935da --- /dev/null +++ b/app/Services/Admin/AdminUserService.php @@ -0,0 +1,164 @@ +modelName = Admin::adminUserModel(); + } + + public function getEditData($id): Model|\Illuminate\Database\Eloquent\Collection|Builder|array|null + { + $adminUser = parent::getEditData($id)->makeHidden('password'); + + $adminUser->load('roles'); + + return $adminUser; + } + + public function store($data): bool + { + if ($this->checkUsernameUnique($data['username'])) { + return $this->setError(__('admin.admin_user.username_already_exists')); + } + + if (!data_get($data, 'password')) { + return $this->setError(__('admin.required', ['attribute' => __('admin.password')])); + } + + if (!$this->passwordHandler($data)) { + return false; + } + + $columns = $this->getTableColumns(); + + $model = $this->getModel(); + + return $this->saveData($data, $columns, $model); + } + + public function update($primaryKey, $data): bool + { + if ($this->checkUsernameUnique($data['username'], $primaryKey)) { + return $this->setError(__('admin.admin_user.username_already_exists')); + } + + if (!$this->passwordHandler($data)) { + return false; + } + + $columns = $this->getTableColumns(); + + $model = $this->query()->whereKey($primaryKey)->first(); + + return $this->saveData($data, $columns, $model); + } + + public function checkUsernameUnique($username, $id = 0): bool + { + return $this->query() + ->where('username', $username) + ->when($id, fn($query) => $query->where('id', '<>', $id)) + ->exists(); + } + + public function updateUserSetting($primaryKey, $data): bool + { + if (!$this->passwordHandler($data, $primaryKey)) { + return false; + } + + return parent::update($primaryKey, $data); + } + + public function passwordHandler(&$data, $id = null): bool + { + $password = Arr::get($data, 'password'); + + if ($password) { + if ($password !== Arr::get($data, 'confirm_password')) { + return $this->setError(__('admin.admin_user.password_confirmation')); + } + + if ($id) { + if (!Arr::get($data, 'old_password')) { + return $this->setError(__('admin.admin_user.old_password_required')); + } + + $oldPassword = $this->query()->where('id', $id)->value('password'); + + if (!Hash::check($data['old_password'], $oldPassword)) { + return $this->setError(__('admin.admin_user.old_password_error')); + } + } + + $data['password'] = bcrypt($password); + + unset($data['confirm_password']); + unset($data['old_password']); + } + + return true; + } + + public function list() + { + $keyword = request()->keyword; + + $query = $this + ->query() + ->with('roles') + ->select(['id', 'name', 'username', 'avatar', 'created_at', 'lock']) + ->when($keyword, function ($query) use ($keyword) { + $query->where('username', 'like', "%{$keyword}%")->orWhere('name', 'like', "%{$keyword}%"); + }); + + $items = (clone $query)->paginate(request()->input('perPage', 20))->items(); + $total = (clone $query)->count(); + + return compact('items', 'total'); + } + + /** + * @param $data + * @param array $columns + * @param AdminUser $model + * + * @return bool + */ + protected function saveData($data, array $columns, AdminUser $model): bool + { + $roles = Arr::pull($data, 'roles'); + + foreach ($data as $k => $v) { + if (!in_array($k, $columns)) { + continue; + } + + $model->setAttribute($k, $v); + } + + if ($model->save()) { + $model->roles()->sync(Arr::has($roles, '0.id') ? Arr::pluck($roles, 'id') : $roles); + + return true; + } + + return false; + } +} diff --git a/database/migrations/2023_12_08_142335_add_lock_to_admin_users_table.php b/database/migrations/2023_12_08_142335_add_lock_to_admin_users_table.php new file mode 100644 index 0000000..74751fe --- /dev/null +++ b/database/migrations/2023_12_08_142335_add_lock_to_admin_users_table.php @@ -0,0 +1,30 @@ +unsignedInteger('lock')->default(0)->comment('锁定'); + $table->unsignedInteger('error_num')->default(0)->comment('错误次数'); + $table->timestamp('last_error_at')->nullable()->comment('上次错误时间'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('admin_users', function (Blueprint $table) { + $table->dropColumn(['lock', 'error_num', 'last_error_at']); + }); + } +};