admin 加班申请

main
panliang 2024-04-02 11:25:02 +08:00
parent a013b50bcf
commit 73b3f4342b
10 changed files with 345 additions and 1 deletions

View File

@ -0,0 +1,147 @@
<?php
namespace App\Admin\Controllers\Hr;
use App\Admin\Controllers\AdminController;
use App\Admin\Services\OvertimeApplyService;
use Slowlyo\OwlAdmin\Renderers\Form;
use Slowlyo\OwlAdmin\Renderers\Page;
use Slowlyo\OwlAdmin\Admin;
use App\Enums\{CheckStatus, EmployeeStatus};
use App\Models\OvertimeApply;
use App\Traits\HasCheckActions;
/**
* 加班管理
*/
class OvertimeController extends AdminController
{
use HasCheckActions;
protected string $serviceName = OvertimeApplyService::class;
public function list(): Page
{
$crud = $this->baseCRUD()
->tableLayout('fixed')
->headerToolbar([
$this->createTypeButton('drawer', 'xl')->visible(Admin::user()->can('admin.hr.overtime.create')),
...$this->baseHeaderToolBar(),
])
->bulkActions([])
->filter($this->baseFilter()->body([
amis()->GroupControl()->mode('horizontal')->body([
amisMake()->SelectControl()->name('store_id')->label(__('overtime_apply.store_id'))
->source(admin_url('api/stores?_all=1'))
->labelField('title')
->valueField('id')
->searchable()
->columnRatio(3)
->clearable(),
amisMake()->TextControl()->name('employee_name')->label(__('overtime_apply.employee_id'))
->placeholder(__('employee.name').'/'.__('employee.phone'))
->columnRatio(3)
->clearable(),
amisMake()->DateRangeControl()->name('date_range')->label(__('overtime_apply.date'))
->columnRatio(3)
->clearable(),
amisMake()->SelectControl()->name('check_status')->label(__('overtime_apply.check_status'))
->options(CheckStatus::options())
->columnRatio(3)
->clearable(),
]),
]))
->columns([
amisMake()->TableColumn()->name('store.title')->label(__('overtime_apply.store_id')),
amisMake()->TableColumn()->name('employee.name')->label(__('overtime_apply.employee_id')),
amisMake()->TableColumn()->name('date')->label(__('overtime_apply.date')),
amisMake()->TableColumn()->name('hours')->label(__('overtime_apply.hours')),
amisMake()->TableColumn()->name('check_status')->label(__('overtime_apply.check_status'))->set('type', 'mapping')->map(CheckStatus::options()),
amisMake()->TableColumn()->name('created_at')->label(__('overtime_apply.created_at')),
$this->rowActions([
$this->rowShowButton()->visible(Admin::user()->can('admin.hr.overtime.view')),
$this->rowEditTypeButton('drawer', 'xl')
->visible(Admin::user()->can('admin.hr.overtime.update'))
->visibleOn('${OR(check_status == '.CheckStatus::None->value.', check_status == '.CheckStatus::Cancel->value.', check_status == '.CheckStatus::Fail->value.')}'),
$this->rowDeleteButton()
->visible(Admin::user()->can('admin.hr.overtime.delete'))
->visibleOn('${OR(check_status == '.CheckStatus::None->value.', check_status == '.CheckStatus::Cancel->value.', check_status == '.CheckStatus::Fail->value.')}'),
$this->applyAction(),
$this->cancelAction(),
]),
]);
return $this->baseList($crud);
}
public function form($edit): Form
{
return $this->baseForm()->title('')->body([
amisMake()->SelectControl()->name('employee_id')->label(__('overtime_apply.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()->InputDatetimeRange()
->name('datetime_range')
->label(__('overtime_apply.date'))
->required(),
amisMake()->TextControl()->name('reason')->label(__('overtime_apply.reason')),
]);
}
public function detail(): Form
{
$subjectType = $this->getMorphAlias();
$detail = amisMake()->Property()->items([
['label' => __('overtime_apply.store_id'), 'content' => '${store.title}'],
['label' => __('overtime_apply.employee_id'), 'content' => '${employee.name}'],
['label' => __('overtime_apply.date'), 'content' => '${date}'],
['label' => __('overtime_apply.start_at'), 'content' => '${start_at}'],
['label' => __('overtime_apply.end_at'), 'content' => '${end_at}'],
['label' => __('overtime_apply.hours'), 'content' => '${hours}'],
['label' => __('overtime_apply.created_at'), 'content' => '${created_at}'],
['label' => __('overtime_apply.reason'), 'content' => '${reason}', 'span' => 2],
['label' => __('overtime_apply.check_status'), 'content' => amisMake()->Mapping()->name('check_status')->map(CheckStatus::options())],
['label' => __('overtime_apply.checked_at'), 'content' => '${checked_at}'],
['label' => __('overtime_apply.check_remarks'), 'content' => '${check_remarks}'],
]);
$table = amisMake()->Service()
->id('overtime-checklog-table')
->initFetch(false)
->api(
amisMake()->BaseApi()->method('get')->url(admin_url('api/workflow/logs'))->data([
'subject_type' => $subjectType,
'subject_id' => '${id}',
])
)
->body(
amisMake()->Table()->columnsTogglable(false)->itemActions([
$this->succesAction()->reload('overtime-detail'),
$this->failAction()->reload('overtime-detail'),
])->columns([
amisMake()->TableColumn()->name('batch_id')->label(__('workflow_log.batch_id')),
amisMake()->TableColumn()->name('check_name')->label(__('workflow_log.check_name')),
amisMake()->TableColumn()->name('check_user.name')->label(__('workflow_log.check_user_id')),
amisMake()->TableColumn()->name('check_status')->label(__('workflow_log.check_status'))->set('type', 'mapping')->map(CheckStatus::options()),
amisMake()->TableColumn()->name('checked_at')->label(__('workflow_log.checked_at')),
amisMake()->TableColumn()->name('remarks')->label(__('workflow_log.remarks')),
])
);
return $this->baseDetail()->id('overtime-detail')->title('')->onEvent([
'inited' => [
'actions' => [
['actionType' => 'reload', 'componentId' => 'overtime-checklog-table'],
]
]
])->body([$detail, amisMake()->Divider(), $table]);
}
public function getMorphAlias()
{
return (new OvertimeApply)->getMorphClass();
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace App\Admin\Filters;
use EloquentFilter\ModelFilter;
use Carbon\Carbon;
class OvertimeApplyFilter extends ModelFilter
{
protected $drop_id = false;
public $relations = [
'store' => [
'store_title' => 'title',
],
'employee' => [
'employee_name' => 'name',
'employee_search' => 'search',
],
];
public function employeeId($key)
{
$this->where('employee_id', $key);
}
public function checkStatus($key)
{
$this->where('check_status', $key);
}
public function dateRange($key)
{
$dates = explode(',', $key);
$start = Carbon::createFromTimestamp(data_get($dates, 0, time()))->startOfDay();
$end = Carbon::createFromTimestamp(data_get($dates, 1, time()))->endOfDay();
$this->whereBetween('date', [$start, $end]);
}
}

View File

@ -0,0 +1,52 @@
<?php
namespace App\Admin\Services;
use App\Admin\Filters\OvertimeApplyFilter;
use App\Models\{OvertimeApply, Employee};
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Carbon\Carbon;
class OvertimeApplyService extends BaseService
{
protected array $withRelationships = ['store', 'employee'];
protected string $modelName = OvertimeApply::class;
protected string $modelFilterName = OvertimeApplyFilter::class;
public function resloveData($data, $model = null)
{
// 获取员工所在的门店
if (!isset($data['store_id']) && isset($data['employee_id'])) {
$data['store_id'] = Employee::where('id', $data['employee_id'])->value('store_id');
}
if (isset($data['datetime_range'])) {
$time = explode(',', $data['datetime_range']);
$start = Carbon::createFromTimestamp(data_get($time, 0));
$end = Carbon::createFromTimestamp(data_get($time, 1));
$data['start_at'] = $start;
$data['end_at'] = $end;
$data['date'] = $start->format('Y-m-d');
$data['hours'] = $start->diffInHours($end);
}
return $data;
}
public function validate($data, $model = null)
{
$createRules = [
'employee_id' => ['required'],
'start_at' => ['required'],
'end_at' => ['required'],
];
$updateRules = [];
$validator = Validator::make($data, $model ? $updateRules : $createRules, []);
if ($validator->fails()) {
return $validator->errors()->first();
}
return true;
}
}

View File

@ -12,6 +12,7 @@ use App\Admin\Controllers\Hr\SignController;
use App\Admin\Controllers\Hr\SignLogController;
use App\Admin\Controllers\Hr\SignRepairController;
use App\Admin\Controllers\Hr\HolidayController;
use App\Admin\Controllers\Hr\OvertimeController;
use App\Admin\Controllers\Store\DeviceController;
use App\Admin\Controllers\Store\EmployeeController as StoreEmployeeController;
use App\Admin\Controllers\Store\StoreController;
@ -84,6 +85,8 @@ Route::group([
$router->resource('repairs', SignRepairController::class);
// 请假申请
$router->resource('holiday', HolidayController::class);
// 加班申请
$router->resource('overtime', OvertimeController::class);
});
/*

View File

@ -0,0 +1,37 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Contracts\Checkable;
use App\Traits\HasCheckable;
use App\Traits\HasDateTimeFormatter;
use EloquentFilter\Filterable;
use App\Enums\{CheckStatus};
/**
* 加班申请
*/
class OvertimeApply extends Model implements Checkable
{
use Filterable, HasDateTimeFormatter, HasCheckable;
protected $fillable = ['store_id', 'employee_id', 'date', 'start_at', 'end_at', 'hours', 'reason', 'check_status', 'checked_at', 'check_remarks'];
protected $casts = [
'date' => 'date:Y-m-d',
'start_at' => 'datetime',
'end_at' => 'datetime',
'check_status' => CheckStatus::class,
];
public function modelFilter()
{
return App\Admin\Filters\HolidayApplyFilter::class;
}
public function store()
{
return $this->belongsTo(Store::class, 'store_id');
}
}

View File

@ -33,6 +33,7 @@ class AppServiceProvider extends ServiceProvider
\App\Models\AdminUser::class,
\App\Models\EmployeeSignRepair::class,
\App\Models\HolidayApply::class,
\App\Models\OvertimeApply::class,
])->mapWithKeys(fn ($model) => [(new $model)->getTable() => $model])->all()
);
}

View File

@ -0,0 +1,39 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use App\Enums\CheckStatus;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('overtime_applies', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->comment('门店, stores.id');
$table->foreignId('employee_id')->comment('申请人, employees.id');
$table->date('date')->comment('加班日期');
$table->timestamp('start_at')->comment('结束时间');
$table->timestamp('end_at')->comment('开始时间');
$table->unsignedInteger('hours')->comment('时长');
$table->string('reason')->nullable()->comment('事由');
$table->unsignedInteger('check_status')->default(CheckStatus::None->value)->comment('审核状态');
$table->timestamp('checked_at')->nullable()->comment('审核通过时间');
$table->string('check_remarks')->nullable()->comment('审核未通过原因');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('overtime_applies');
}
};

View File

@ -133,7 +133,13 @@ class AdminPermissionSeeder extends Seeder
'icon' => '',
'uri' => '/hr/holiday',
'resource' => true,
]
],
'overtime' => [
'name' => '加班申请',
'icon' => '',
'uri' => '/hr/overtime',
'resource' => true,
],
],
],

View File

@ -20,6 +20,7 @@ class WorkflowSeeder extends Seeder
Workflow::insert([
['key' => 'employee_sign_repair', 'name' => '补卡申请', 'config' => $config, 'created_at' => now(), 'updated_at' => now()],
['key' => 'holiday_apply', 'name' => '请假申请', 'config' => $config, 'created_at' => now(), 'updated_at' => now()],
['key' => 'overtime_apply', 'name' => '加班申请', 'config' => $config, 'created_at' => now(), 'updated_at' => now()],
]);
}
}

View File

@ -0,0 +1,19 @@
<?php
return [
'id' => 'ID',
'created_at' => '提交日期',
'updated_at' => '更新时间',
'check_status' => '审核状态',
'checked_at' => '审核通过时间',
'check_remarks' => '审核未通过原因',
'start_at' => '开始时间',
'end_at' => '结束时间',
'date' => '加班日期',
'hours' => '时长',
'store_id' => '门店',
'employee_id' => '员工',
'reason' => '加班事由',
];