diff --git a/README.md b/README.md index 625757c..0d8bbdf 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +# 彩票门店管理 + composer install php artisan g:k php artisan storage:link diff --git a/app/Admin/Controllers/EmployeeController.php b/app/Admin/Controllers/EmployeeController.php new file mode 100644 index 0000000..98b3f18 --- /dev/null +++ b/app/Admin/Controllers/EmployeeController.php @@ -0,0 +1,65 @@ +baseCRUD() + ->tableLayout('fixed') + ->headerToolbar([ + $this->createButton(true), + ...$this->baseHeaderToolBar(), + ]) + ->filter($this->baseFilter()->body([ + amis()->GroupControl()->mode('horizontal')->body([ + amisMake()->TextControl()->name('name')->label(__('employee.name'))->columnRatio(3)->clearable(), + amisMake()->TextControl()->name('phone')->label(__('employee.phone'))->columnRatio(3)->clearable(), + amisMake()->SelectControl()->name('employee_status')->label(__('employee.employee_status'))->columnRatio(3)->clearable()->options(EmployeeStatus::options()), + ]), + ])) + ->columns([ + amisMake()->TableColumn()->name('id')->label(__('employee.id')), + amisMake()->TableColumn()->name('name')->label(__('employee.name')), + amisMake()->TableColumn()->name('phone')->label(__('employee.phone')), + amisMake()->TableColumn()->name('employee_status_text')->label(__('employee.employee_status')), + amisMake()->TableColumn()->name('created_at')->label(__('employee.created_at')), + $this->rowActions([ + $this->rowShowButton(), + $this->rowEditButton(true), + $this->rowDeleteButton(), + ]), + ]); + + return $this->baseList($crud); + } + + public function form($edit): Form + { + return $this->baseForm()->title('')->body([ + amisMake()->TextControl()->name('name')->label(__('employee.name'))->required(), + amisMake()->TextControl()->name('phone')->label(__('employee.phone'))->required(), + + amisMake()->TextControl()->name('username')->label(__('admin.username'))->value('${admin_user.username}')->required(!$edit), + amisMake()->TextControl()->name('password')->set('type', 'input-password')->label(__('admin.password'))->required(!$edit), + amisMake()->TextControl()->name('confirm_password')->set('type', 'input-password')->label(__('admin.confirm_password'))->required(!$edit), + ]); + } + + public function detail(): Form + { + return $this->baseDetail()->title('')->body(amisMake()->Property()->items([ + ['label' => __('employee.name'), 'content' => '${name}'], + ['label' => __('employee.phone'), 'content' => '${phone}'], + ])); + } +} diff --git a/app/Admin/routes.php b/app/Admin/routes.php index b080bf1..4fb384e 100644 --- a/app/Admin/routes.php +++ b/app/Admin/routes.php @@ -40,4 +40,7 @@ Route::group([ $router->post('start_chunk_upload_file', [\App\Admin\Controllers\IndexController::class, 'startChunk']); $router->post('save_chunk_upload_file', [\App\Admin\Controllers\IndexController::class, 'saveChunk']); $router->post('finish_chunk_upload_file', [\App\Admin\Controllers\IndexController::class, 'finishChunk']); + + // 员工管理 + $router->resource('employees', \App\Admin\Controllers\EmployeeController::class); }); diff --git a/app/Console/Commands/ModelFillable.php b/app/Console/Commands/ModelFillable.php new file mode 100644 index 0000000..c193e33 --- /dev/null +++ b/app/Console/Commands/ModelFillable.php @@ -0,0 +1,54 @@ +argument('table'); + $ignore = ['id', 'created_at', 'updated_at', 'deleted_at']; + $connection = $this->option('connection'); + if (! $connection) { + $connection = config('database.default'); + } + + if (Schema::connection($connection)->hasTable($table)) { + $list = Schema::connection($connection)->getColumnListing($table); + $list = array_filter($list, function ($value) use ($ignore) { + return ! in_array($value, $ignore); + }); + $this->info("protected \$fillable = ['".implode('\', \'', $list)."'];"); + } + } +} diff --git a/app/Enums/EmployeeStatus.php b/app/Enums/EmployeeStatus.php new file mode 100644 index 0000000..6c6a123 --- /dev/null +++ b/app/Enums/EmployeeStatus.php @@ -0,0 +1,31 @@ +value => '在职', + self::Offline->value => '离职', + ]; + } + + public static function options() + { + $list = []; + foreach (static::map() as $key => $value) { + array_push($list, ['label' => $value, 'value' => $key]); + } + return $list; + } + + public function text() + { + return data_get(self::map(), $this->value); + } +} diff --git a/app/Models/Employee.php b/app/Models/Employee.php new file mode 100644 index 0000000..ff246f9 --- /dev/null +++ b/app/Models/Employee.php @@ -0,0 +1,53 @@ + EmployeeStatus::class, + 'prize_images' => 'json', + 'skill_images' => 'json', + ]; + + protected $attributes = [ + 'employee_status' => EmployeeStatus::Online, + ]; + + protected $appends = ['employee_status_text']; + + // 拥有的职位 + public function jobs() + { + return $this->belongsToMany(Keyword::class, 'emplyee_jobs', 'employee_id', 'job'); + } + + // 关联登录账户 + public function adminUser() + { + return $this->belongsTo(AdminUser::class, 'admin_user_id'); + } + + protected function employeeStatusText(): Attribute + { + return new Attribute( + get: fn () => $this->employee_status ? $this->employee_status->text() : '', + ); + } +} diff --git a/app/Models/Filters/EmployeeFilter.php b/app/Models/Filters/EmployeeFilter.php new file mode 100644 index 0000000..21a2ee7 --- /dev/null +++ b/app/Models/Filters/EmployeeFilter.php @@ -0,0 +1,31 @@ +where(fn($q) => $q->where('name', 'like', $condition)->orWhere('phone', 'like', $condition)); + } + + public function name($key) + { + $condition = '%'.$key.'%'; + $this->whereLike('name', $condition); + } + + public function phone($key) + { + $condition = '%'.$key.'%'; + $this->whereLike('phone', $condition); + } + + public function employeeStatus($key) + { + $this->whereIn('employee_status', is_array($key) ? $key : explode(',', $key)); + } +} diff --git a/app/Services/Admin/BaseService.php b/app/Services/Admin/BaseService.php index 4fa0ecd..09da6e7 100644 --- a/app/Services/Admin/BaseService.php +++ b/app/Services/Admin/BaseService.php @@ -55,4 +55,91 @@ class BaseService extends AdminService { return $this->query()->with($this->withRelationships)->find($id); } + + public function store($data): bool + { + $data = $this->resloveData($data); + + $validate = $this->validate($data); + if ($validate !== true) { + $this->setError($validate); + return false; + } + + $this->modelName::create($data); + + return true; + } + + public function update($primaryKey, $data): bool + { + $model = $this->query()->whereKey($primaryKey)->firstOrFail(); + $data = $this->resloveData($data, $model); + $validate = $this->validate($data, $model); + if ($validate !== true) { + $this->setError($validate); + return false; + } + + return $model->update($data); + } + + public function delete(string $ids): mixed + { + $id = explode(',', $ids); + $result = $this->preDelete($id); + if ($result !== true) { + $this->setError($result); + return false; + } + return $this->query()->whereIn($this->primaryKey(), $id)->delete(); + } + + /** + * 处理表单数据 + * + * @param array $data + * @param Model $model 空 : 添加, 非空: 修改 + * @return array + */ + public function resloveData($data, $model = null) + { + return $data; + } + + /** + * 表单验证 + * + * @param array $data + * @param Model $model 空: 添加, 非空: 修改 + * @return mixed true: 验证通过, string: 错误提示 + */ + public function validate($data, $model = null) + { + // $createRules = [ + // 'key' => ['required', Rule::unique('keywords', 'key')], + // 'name' => ['required'], + // ]; + // $updateRules = [ + // 'key' => [Rule::unique('keywords', 'key')->ignore($model->id)] + // ]; + // $validator = Validator::make($data, $model ? $updateRules : $createRules, [ + // 'key.unique' => ':input 已经存在' + // ]); + // if ($validator->fails()) { + // return $validator->errors()->first(); + // } + return true; + } + + /** + * 删除的前置方法 + * + * @param array $ids 主键id + * @return mixed true: 继续后续操作, string: 中断操作, 返回错误提示 + */ + public function preDelete(array $ids) + { + return true; + } } diff --git a/app/Services/Admin/EmployeeService.php b/app/Services/Admin/EmployeeService.php new file mode 100644 index 0000000..178ebb4 --- /dev/null +++ b/app/Services/Admin/EmployeeService.php @@ -0,0 +1,85 @@ +getModel(); + + $hidden = collect([$model->getCreatedAtColumn(), $model->getUpdatedAtColumn()]) + ->filter(fn($item) => $item !== null) + ->toArray(); + + return $this->query()->with(['adminUser'])->find($id)->makeHidden($hidden); + } + + public function resloveData($data, $model = null) + { + // 管理员信息 + $adminUserService = AdminUserService::make(); + if ($model) { + // 修改管理员信息 + if (Arr::hasAny($data, ['username', 'password', 'confirm_password'])) { + if (!$adminUserService->update($model->admin_user_id, Arr::only($data, ['username', 'password', 'confirm_password']))) { + $this->setError($adminUserService->getError()); + return false; + } + } + } else { + // 添加管理员信息 + if (!$adminUserService->store(Arr::only($data, ['username', 'password', 'confirm_password']))) { + $this->setError($adminUserService->getError()); + return false; + } + $adminUser = AdminUser::where('username', $data['username'])->first(); + $data['admin_user_id'] = $adminUser->id; + } + return $data; + } + + public function preDelete(array $ids) + { + // 删除管理员 + $adminUserIds = Employee::whereIn('id', $ids)->pluck('admin_user_id')->implode(','); + $adminUserService = AdminUserService::make(); + if (!$adminUserService->delete($adminUserIds)) { + $this->setError($adminUserService->getError()); + return false; + } + return true; + } + + public function validate($data, $model = null) + { + $createRules = [ + 'name' => ['required'], + 'phone' => ['required'], + ]; + $updateRules = []; + $validator = Validator::make($data, $model ? $updateRules : $createRules, [ + 'name.required' => __('employee.name') . '必填', + 'phone.required' => __('employee.phone') . '必填', + ]); + if ($validator->fails()) { + return $validator->errors()->first(); + } + return true; + } +} diff --git a/app/Traits/HasDateTimeFormatter.php b/app/Traits/HasDateTimeFormatter.php new file mode 100644 index 0000000..4ab96cb --- /dev/null +++ b/app/Traits/HasDateTimeFormatter.php @@ -0,0 +1,12 @@ +format($this->getDateFormat()); + } +} diff --git a/database/migrations/2024_03_22_091409_create_employees_table.php b/database/migrations/2024_03_22_091409_create_employees_table.php new file mode 100644 index 0000000..c4d6da3 --- /dev/null +++ b/database/migrations/2024_03_22_091409_create_employees_table.php @@ -0,0 +1,42 @@ +id(); + $table->string('name')->comment('姓名'); + $table->string('phone')->comment('电话'); + $table->json('prize_images')->nullable()->comment('荣誉证书'); + $table->json('skill_images')->nullable()->comment('专业证书'); + $table->unsignedInteger('employee_status')->default(1)->comment('员工状态{1: 在职, 2: 离职}'); + $table->foreignId('admin_user_id')->comment('登录信息, 关联 admin_users.id'); + + $table->timestamps(); + + $table->comment('员工'); + }); + + Schema::create('emplyee_jobs', function (Blueprint $table) { + $table->foreignId('employee_id'); + $table->string('job')->comment('职位, 字典表: keywords.job'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('employees'); + Schema::dropIfExists('emplyee_jobs'); + } +}; diff --git a/lang/zh_CN/employee.php b/lang/zh_CN/employee.php new file mode 100644 index 0000000..b2f8ad7 --- /dev/null +++ b/lang/zh_CN/employee.php @@ -0,0 +1,15 @@ + 'ID', + 'created_at' => '创建时间', + 'updated_at' => '更新时间', + + 'name' => '姓名', + 'phone' => '电话', + 'prize_images' => '荣誉证书', + 'skill_images' => '专业证书', + 'employee_status' => '状态', + 'admin_user_id' => '关联账户', + 'jobs' => '职位', +]; diff --git a/routes/web.php b/routes/web.php index d259f33..cc576f9 100644 --- a/routes/web.php +++ b/routes/web.php @@ -13,6 +13,4 @@ use Illuminate\Support\Facades\Route; | */ -Route::get('/', function () { - return view('welcome'); -}); +Route::redirect('/', '/admin');