From 399388e1582986b04c89c204075a8b500ff98865 Mon Sep 17 00:00:00 2001 From: panliang <1163816051@qq.com> Date: Sun, 7 Apr 2024 12:36:35 +0800 Subject: [PATCH] =?UTF-8?q?admin=20=E5=8D=87=E8=81=8C=E7=94=B3=E8=AF=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/BaseKeywordController.php | 2 +- .../Controllers/Hr/PromotionController.php | 136 ++++++++++++++++++ app/Admin/Filters/EmployeePromotionFilter.php | 53 +++++++ app/Admin/Services/BaseService.php | 5 + .../Services/EmployeePromotionService.php | 106 ++++++++++++++ .../Services/System/AdminUserService.php | 3 +- app/Admin/routes.php | 3 + app/Enums/PromotionStatus.php | 46 ++++++ app/Models/EmployeePromotion.php | 49 +++++++ app/Providers/AppServiceProvider.php | 1 + ...24_03_22_091409_create_employees_table.php | 2 +- ...10306_create_employee_promotions_table.php | 41 ++++++ database/seeders/AdminPermissionSeeder.php | 6 + database/seeders/WorkflowSeeder.php | 1 + lang/zh_CN/employee_promotion.php | 24 ++++ 15 files changed, 475 insertions(+), 3 deletions(-) create mode 100644 app/Admin/Controllers/Hr/PromotionController.php create mode 100644 app/Admin/Filters/EmployeePromotionFilter.php create mode 100644 app/Admin/Services/EmployeePromotionService.php create mode 100644 app/Enums/PromotionStatus.php create mode 100644 app/Models/EmployeePromotion.php create mode 100644 database/migrations/2024_04_07_110306_create_employee_promotions_table.php create mode 100644 lang/zh_CN/employee_promotion.php diff --git a/app/Admin/Controllers/BaseKeywordController.php b/app/Admin/Controllers/BaseKeywordController.php index 70f91e0..6a771fd 100644 --- a/app/Admin/Controllers/BaseKeywordController.php +++ b/app/Admin/Controllers/BaseKeywordController.php @@ -2,7 +2,7 @@ namespace App\Admin\Controllers; -use App\Admin\Services\KeywordService; +use App\Admin\Services\System\KeywordService; use Slowlyo\OwlAdmin\Renderers\Form; use Slowlyo\OwlAdmin\Renderers\Page; diff --git a/app/Admin/Controllers/Hr/PromotionController.php b/app/Admin/Controllers/Hr/PromotionController.php new file mode 100644 index 0000000..46ea0ac --- /dev/null +++ b/app/Admin/Controllers/Hr/PromotionController.php @@ -0,0 +1,136 @@ +baseCRUD() + ->tableLayout('fixed') + ->headerToolbar([ + $this->createTypeButton('drawer', 'xl')->visible(Admin::user()->can('admin.hr.promotion.create')), + ...$this->baseHeaderToolBar(), + ]) + ->bulkActions([]) + ->filter($this->baseFilter()->body([ + amis()->GroupControl()->mode('horizontal')->body([ + amisMake()->SelectControl()->name('store_id')->label(__('employee_promotion.store_id')) + ->source(admin_url('api/stores?_all=1')) + ->labelField('title') + ->valueField('id') + ->searchable() + ->columnRatio(3) + ->clearable(), + amisMake()->TextControl()->name('employee_search')->label(__('employee_promotion.employee_id')) + ->placeholder(__('employee.name').'/'.__('employee.phone')) + ->columnRatio(3) + ->clearable(), + amisMake()->SelectControl()->name('job_id')->label(__('employee_promotion.job_id')) + ->source(admin_url('api/keywords/tree-list').'?parent_key=job') + ->labelField('name') + ->valueField('key') + ->columnRatio(3) + ->clearable(), + amisMake()->TextControl()->name('invitor_search')->label(__('employee_promotion.invitor_id')) + ->placeholder(__('employee.name').'/'.__('employee.phone')) + ->columnRatio(3) + ->clearable(), + ]), + amis()->GroupControl()->mode('horizontal')->body([ + amisMake()->SelectControl()->name('promotion_status')->label(__('employee_promotion.promotion_status')) + ->options(PromotionStatus::options()) + ->columnRatio(3) + ->clearable(), + ]), + ])) + ->columns([ + amisMake()->TableColumn()->name('store.title')->label(__('employee_promotion.store_id')), + amisMake()->TableColumn()->name('employee.name')->label(__('employee_promotion.employee_id')), + amisMake()->TableColumn()->name('job.name')->label(__('employee_promotion.job_id')), + amisMake()->TableColumn()->name('invitor.name')->label(__('employee_promotion.invitor_id')), + amisMake()->TableColumn()->name('promotion_status')->label(__('employee_promotion.promotion_status'))->set('type', 'mapping')->map(PromotionStatus::options()), + amisMake()->TableColumn()->name('created_at')->label(__('employee_promotion.created_at')), + $this->rowActions([ + $this->rowShowButton()->visible(Admin::user()->can('admin.hr.promotion.view')), + $this->rowEditTypeButton('drawer', 'xl') + ->visible(Admin::user()->can('admin.hr.promotion.update')), + $this->rowDeleteButton() + ->visible(Admin::user()->can('admin.hr.promotion.delete')), + $this->cancelAction()->visibleOn('${promotion_status == '.PromotionStatus::Processing->value.'}'), + ]), + ]); + + return $this->baseList($crud); + } + + public function form($edit): Form + { + return $this->baseForm()->title('')->body([ + amisMake()->SelectControl()->name('employee_id')->label(__('employee_promotion.employee_id')) + ->source(admin_url('api/employees?_all=1&store_id_gt=0&employee_status='.EmployeeStatus::Online->value)) + ->labelField('name') + ->valueField('id') + ->searchable() + ->joinValues(false) + ->extractValue() + ->required(), + amisMake()->SelectControl()->name('invitor_id')->label(__('employee_promotion.invitor_id')) + ->source(admin_url('api/employees?_all=1&store_id_gt=0&employee_status='.EmployeeStatus::Online->value)) + ->labelField('name') + ->valueField('id') + ->searchable() + ->joinValues(false) + ->extractValue() + ->required(), + amisMake()->SelectControl()->name('job_id')->label(__('employee_promotion.job_id')) + ->source(admin_url('api/keywords/tree-list').'?parent_key=job') + ->labelField('name') + ->valueField('key'), + amisMake()->TextControl()->name('remarks')->label(__('employee_promotion.remarks')), + ]); + } + + public function detail(): Form + { + $detailId = 'promotion-detail'; + $serviceId = 'promotion-checklog-service'; + + $detail = amisMake()->Property()->items([ + ['label' => __('employee_promotion.store_id'), 'content' => '${store.title}'], + ['label' => __('employee_promotion.employee_id'), 'content' => '${employee.name}'], + ['label' => __('employee_promotion.job_id'), 'content' => '${job.name}'], + ['label' => __('employee_promotion.invitor_id'), 'content' => '${invitor.name}'], + ['label' => __('employee_promotion.promotion_status'), 'content' => amisMake()->Mapping()->name('promotion_status')->map(PromotionStatus::options())], + ['label' => __('employee_promotion.remarks'), 'content' => '${remarks}'], + ]); + + return $this->baseDetail()->id($detailId)->title('')->onEvent([ + 'inited' => [ + 'actions' => [ + ['actionType' => 'reload', 'componentId' => $serviceId], + ] + ] + ])->body([ + $detail, + amisMake()->Divider(), + $this->baseWorkflowLogService($detailId)->id($serviceId), + ]); + } +} diff --git a/app/Admin/Filters/EmployeePromotionFilter.php b/app/Admin/Filters/EmployeePromotionFilter.php new file mode 100644 index 0000000..3fb97a1 --- /dev/null +++ b/app/Admin/Filters/EmployeePromotionFilter.php @@ -0,0 +1,53 @@ + [ + 'store_title' => 'title', + ], + 'employee' => [ + 'employee_name' => 'name', + 'employee_search' => 'search', + ], + 'invitor' => [ + 'invitor_name' => 'name', + 'invitor_search' => 'search', + ], + ]; + + public function employeeId($key) + { + $this->where('employee_id', $key); + } + + public function invitorId($key) + { + $this->where('invitor_id', $key); + } + + public function storeId($key) + { + $this->where('store_id', $key); + } + + public function jobId($key) + { + $this->where('job_id', $key); + } + + public function dateRange($dates) + { + $dates = explode(',', $dates); + $start = Carbon::createFromTimestamp(data_get($dates, 0, time()))->startOfDay(); + $end = Carbon::createFromTimestamp(data_get($dates, 1, time()))->endOfDay(); + $this->whereBetween('created_at', [$start, $end]); + } +} diff --git a/app/Admin/Services/BaseService.php b/app/Admin/Services/BaseService.php index 8197a61..3759a8b 100644 --- a/app/Admin/Services/BaseService.php +++ b/app/Admin/Services/BaseService.php @@ -16,6 +16,11 @@ class BaseService extends AdminService protected bool $modelSortAble = false; + public function sortColumn() + { + return 'id'; + } + public function getTree() { $list = $this->query()->orderByDesc('sort')->get(); diff --git a/app/Admin/Services/EmployeePromotionService.php b/app/Admin/Services/EmployeePromotionService.php new file mode 100644 index 0000000..a543647 --- /dev/null +++ b/app/Admin/Services/EmployeePromotionService.php @@ -0,0 +1,106 @@ +value('store_id'); + } + return $data; + } + + /** + * 申请人完事资料 + * + * @param EmployeePromotion $model + * @param array $data + * @return bool + */ + public function apply($model, $data = []) + { + $validator = Validator::make($data, [ + 'age' => ['required'], + 'sex' => ['required'], + 'education' => ['required'], + 'first_work_time' => ['required'], + 'work_years' => ['required'], + 'work_years_in_company' => ['required'], + 'comment_self' => ['required'], + 'plans' => ['required'], + ]); + if ($validator->fails()) { + return $validator->errors()->first(); + } + + $model->update(['employee_data' => $data, 'promotion_status' => PromotionStatus::Invitor]); + + return true; + } + + /** + * 邀请人填写推荐理由 + * + * @param EmployeePromotion $model + * @param array $data + * @return bool + */ + public function invitor($model, $data = []) + { + $validator = Validator::make($data, [ + 'reason' => ['required'], + ]); + if ($validator->fails()) { + return $validator->errors()->first(); + } + + try { + DB::beginTransaction(); + $attributes = array_merge($model->employee_data, $data); + $model->update(['employee_data' => $data, 'promotion_status' => PromotionStatus::Processing]); + + // 发起审核申请 + $service = WorkflowService::make(); + if ($service->apply($model->workflow, $model->employee) !== true) { + return $this->setError($service->getError()); + } + DB::commit(); + } catch (\Exception $e) { + DB::rollBack(); + return $this->setError($e->getMessage()); + } + + return true; + } + + public function validate($data, $model = null) + { + $createRules = [ + 'store_id' => ['required'], + 'employee_id' => ['required'], + 'invitor_id' => ['required'], + 'job_id' => ['required'], + ]; + $updateRules = []; + $validator = Validator::make($data, $model ? $updateRules : $createRules); + if ($validator->fails()) { + return $validator->errors()->first(); + } + return true; + } +} diff --git a/app/Admin/Services/System/AdminUserService.php b/app/Admin/Services/System/AdminUserService.php index d626b95..2328fbc 100644 --- a/app/Admin/Services/System/AdminUserService.php +++ b/app/Admin/Services/System/AdminUserService.php @@ -84,8 +84,9 @@ class AdminUserService extends BaseService $user->save(); if (isset($data['roles'])) { + $roles = Arr::pull($data, 'roles'); $user->roles()->detach(); - $user->roles()->attach($data['roles']); + $user->roles()->attach(Arr::has($roles, '0.id') ? Arr::pluck($roles, 'id') : $roles); } return true; diff --git a/app/Admin/routes.php b/app/Admin/routes.php index 339034a..3e75162 100644 --- a/app/Admin/routes.php +++ b/app/Admin/routes.php @@ -12,6 +12,7 @@ use App\Admin\Controllers\Finance\StoreStatisticController; use App\Admin\Controllers\Hr\EmployeeController; use App\Admin\Controllers\Hr\HolidayController; use App\Admin\Controllers\Hr\OfficalBusinessController; +use App\Admin\Controllers\Hr\PromotionController; use App\Admin\Controllers\Hr\OvertimeController; use App\Admin\Controllers\Hr\RestController; use App\Admin\Controllers\Hr\SignController; @@ -93,6 +94,8 @@ Route::group([ $router->resource('overtime', OvertimeController::class); // 出差报备 $router->resource('business', OfficalBusinessController::class); + // 升职申请 + $router->resource('promotion', PromotionController::class); }); /* diff --git a/app/Enums/PromotionStatus.php b/app/Enums/PromotionStatus.php new file mode 100644 index 0000000..794867f --- /dev/null +++ b/app/Enums/PromotionStatus.php @@ -0,0 +1,46 @@ +value => '待提交', + self::Invitor->value => '待补充', + self::Processing->value => '审核中', + self::Success->value => '审核通过', + self::Fail->value => '审核不通过', + ]; + } + + public function text() + { + return data_get(self::options(), $this->value); + } +} diff --git a/app/Models/EmployeePromotion.php b/app/Models/EmployeePromotion.php new file mode 100644 index 0000000..356eef8 --- /dev/null +++ b/app/Models/EmployeePromotion.php @@ -0,0 +1,49 @@ + PromotionStatus::class, + 'employee_data' => 'json', + ]; + + public function modelFilter() + { + return \App\Admin\Filters\EmployeePromotionFilter::class; + } + + public function store() + { + return $this->belongsTo(Store::class, 'store_id'); + } + + public function employee() + { + return $this->belongsTo(Employee::class, 'employee_id'); + } + + public function invitor() + { + return $this->belongsTo(Employee::class, 'invitor_id'); + } + + public function job() + { + return $this->belongsTo(Keyword::class, 'job_id', 'key'); + } +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index c543c18..9c5b897 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -38,6 +38,7 @@ class AppServiceProvider extends ServiceProvider \App\Models\Ledger::class, \App\Models\Reimbursement::class, \App\Models\StoreMasterCommission::class, + \App\Models\EmployeePromotion::class, ])->mapWithKeys(fn ($model) => [(new $model)->getTable() => $model])->all() ); } diff --git a/database/migrations/2024_03_22_091409_create_employees_table.php b/database/migrations/2024_03_22_091409_create_employees_table.php index b694650..4e5636e 100644 --- a/database/migrations/2024_03_22_091409_create_employees_table.php +++ b/database/migrations/2024_03_22_091409_create_employees_table.php @@ -20,7 +20,7 @@ return new class extends Migration $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->foreignId('admin_user_id')->unique()->comment('登录信息, 关联 admin_users.id'); $table->timestamp('join_at')->nullable()->comment('入职时间'); $table->timestamp('leave_at')->nullable()->comment('离职时间'); $table->string('remarks')->nullable()->comment('备注'); diff --git a/database/migrations/2024_04_07_110306_create_employee_promotions_table.php b/database/migrations/2024_04_07_110306_create_employee_promotions_table.php new file mode 100644 index 0000000..3661d32 --- /dev/null +++ b/database/migrations/2024_04_07_110306_create_employee_promotions_table.php @@ -0,0 +1,41 @@ +id(); + $table->foreignId('store_id')->comment('门店, stores.id'); + $table->foreignId('employee_id')->comment('待升职员工, employees.id'); + $table->foreignId('invitor_id')->comment('推荐人, employees.id'); + $table->string('job_id')->comment('目标职位(job), keywords.key'); + // 1: 待提交, 需要升职员工填写相关资料 + // 2: 待补充, 等待推荐人填写理由 + // 3: 审核中, 等待后台审核 + // 4: 审核通过 + // 5: 审核不通过 + $table->unsignedInteger('promotion_status')->default(1)->comment('申请状态'); + $table->json('employee_data')->nullable()->comment('员工资料'); + $table->string('remarks')->nullable()->comment('备注'); + $table->timestamps(); + + $table->comment('升职申请'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('employee_promotions'); + } +}; diff --git a/database/seeders/AdminPermissionSeeder.php b/database/seeders/AdminPermissionSeeder.php index 9ffd7fa..465ac7b 100644 --- a/database/seeders/AdminPermissionSeeder.php +++ b/database/seeders/AdminPermissionSeeder.php @@ -146,6 +146,12 @@ class AdminPermissionSeeder extends Seeder 'uri' => '/hr/business', 'resource' => true, ], + 'promotion' => [ + 'name' => '升职申请', + 'icon' => '', + 'uri' => '/hr/promotion', + 'resource' => true, + ], ], ], diff --git a/database/seeders/WorkflowSeeder.php b/database/seeders/WorkflowSeeder.php index 36f48e3..695221e 100644 --- a/database/seeders/WorkflowSeeder.php +++ b/database/seeders/WorkflowSeeder.php @@ -25,6 +25,7 @@ class WorkflowSeeder extends Seeder ['key' => 'ledger', 'name' => '上报数据', 'config' => $config, 'created_at' => now(), 'updated_at' => now()], ['key' => 'reimbursement', 'name' => '收支报销', 'config' => $config, 'created_at' => now(), 'updated_at' => now()], ['key' => 'store_master_commission', 'name' => '店长提成', 'config' => $config, 'created_at' => now(), 'updated_at' => now()], + ['key' => 'employee_promotion', 'name' => '升职申请', 'config' => $config, 'created_at' => now(), 'updated_at' => now()], ]); } } diff --git a/lang/zh_CN/employee_promotion.php b/lang/zh_CN/employee_promotion.php new file mode 100644 index 0000000..2aeb823 --- /dev/null +++ b/lang/zh_CN/employee_promotion.php @@ -0,0 +1,24 @@ + 'ID', + 'created_at' => '创建时间', + 'updated_at' => '更新时间', + 'store_id' => '门店', + 'employee_id' => '申请人', + 'invitor_id' => '推荐人', + 'job_id' => '申请职位', + 'promotion_status' => '状态', + 'employee_data' => '资料', + 'remarks' => '备注', + + 'age' => '年龄', + 'sex' => '性别', + 'education' => '学历', + 'first_work_time' => '首次参加工作时间', + 'work_years' => '工作年限', + 'work_years_in_company' => '本公司工作年限', + 'comment_self' => '自我评价', + 'plans' => '未来计划', + 'reason' => '推荐理由', +];