admin 休息日管理

main
panliang 2024-03-27 16:22:07 +08:00
parent afaa14d58d
commit b722b53f6f
14 changed files with 419 additions and 0 deletions

View File

@ -0,0 +1,63 @@
<?php
namespace App\Admin\Controllers\Hr;
use Slowlyo\OwlAdmin\Renderers\Form;
use Slowlyo\OwlAdmin\Renderers\Page;
use App\Admin\Controllers\AdminController;
use App\Admin\Services\EmployeeRestService;
use App\Enums\EmployeeStatus;
/**
* 休息日管理
*/
class RestController extends AdminController
{
protected string $serviceName = EmployeeRestService::class;
public function list(): Page
{
$crud = $this->baseCRUD()
->tableLayout('fixed')
->headerToolbar([
$this->createButton(true, 'lg'),
...$this->baseHeaderToolBar(),
])
->bulkActions([])
->filter($this->baseFilter()->body([
amis()->GroupControl()->mode('horizontal')->body([
amisMake()->TextControl()->name('employee_name')->label(__('employee_sign.employee_id'))->placeholder(__('employee.name') .'/'. __('employee.phone'))->columnRatio(3)->clearable(),
amisMake()->DateRangeControl()->name('date_range')->label(__('employee_sign.date'))->columnRatio(3)->clearable(),
]),
]))
->columns([
amisMake()->TableColumn()->name('employee.name')->label(__('employee.name')),
// amisMake()->TableColumn()->name('employee.phone')->label(__('employee.phone')),
amisMake()->TableColumn()->name('date')->label(__('employee_sign.date')),
$this->rowActions([
$this->rowDeleteButton(),
]),
]);
return $this->baseList($crud);
}
public function form($edit): Form
{
return $this->baseForm()->title('')->body([
amisMake()->SelectControl()->name('employees')->label(__('employee_sign.employee_id'))
->source(admin_url('hr/employees?_action=getData&_all=1&employee_status=' . EmployeeStatus::Online->value))
->labelField('name')
->valueField('id')
->searchable()
->multiple()
->joinValues(false)
->extractValue()
->required(),
amisMake()->ArrayControl()->name('dates')->label(__('employee_sign.date'))->items([
amisMake()->DateControl()->name('date')->label('')->valueFormat('YYYY-MM-DD'),
])->required(),
// amisMake()->DateControl()->name('dates')->label(__('employee_sign.date'))->set('embed', true)->required(),
]);
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace App\Admin\Filters;
use EloquentFilter\ModelFilter;
use Carbon\Carbon;
class EmployeeRestFilter 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 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('date', [$start, $end]);
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace App\Admin\Services;
use App\Models\{EmployeeRest, Employee};
use App\Admin\Filters\EmployeeRestFilter;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
class EmployeeRestService extends BaseService
{
protected array $withRelationships = ['employee'];
protected string $modelName = EmployeeRest::class;
protected string $modelFilterName = EmployeeRestFilter::class;
public function store($data): bool
{
$data = $this->resloveData($data);
$validate = $this->validate($data);
if ($validate !== true) {
$this->setError($validate);
return false;
}
if (isset($data['employees']) && isset($data['dates'])) {
$dates = array_unique($data['dates']);
$employees = Employee::whereIn('id', $data['employees'])->enable()->get();
$list = [];
$now = now();
foreach($employees as $employee) {
foreach ($dates as $date) {
array_push($list, [
'date' => $date,
'employee_id' => $employee->id,
]);
}
}
EmployeeRest::insert($list);
} else {
$this->modelName::create($data);
}
return true;
}
}

View File

@ -1,6 +1,7 @@
<?php
use App\Admin\Controllers\Hr\EmployeeController;
use App\Admin\Controllers\Hr\RestController;
use App\Admin\Controllers\Store\StoreController;
use App\Admin\Controllers\Store\EmployeeController as StoreEmployeeController;
use App\Admin\Controllers\Store\DeviceController;
@ -65,6 +66,7 @@ Route::group([
$router->post('employees/{id}/leave', [EmployeeController::class, 'leave'])->name('employees.leave');
// 职位管理
$router->resource('jobs', BaseKeywordController::class);
$router->resource('rests', RestController::class);
});

View File

@ -0,0 +1,24 @@
<?php
namespace App\Enums;
enum SignStatus: int
{
case Normal = 1;
case Absent = 2;
case Lose = 3;
public static function options()
{
return [
self::Normal->value => '正常',
self::Absent->value => '旷工',
self::Lose->value => '缺卡',
];
}
public function text()
{
return data_get(self::options(), $this->value);
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace App\Enums;
enum SignType: int
{
case Normal = 1;
case Outside = 2;
public static function options()
{
return [
self::Normal->value => '正常打卡',
self::Outside->value => '外勤打卡',
];
}
public function text()
{
return data_get(self::options(), $this->value);
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use EloquentFilter\Filterable;
/**
* 员工-休息日
*/
class EmployeeRest extends Model
{
use Filterable;
protected $table = 'employee_rest_days';
protected $fillable = ['date', 'employee_id'];
protected $casts = [
'date' => 'date:Y-m-d',
];
public $timestamps = false;
public function employee()
{
return $this->belongsTo(Employee::class, 'employee_id');
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Enums\{SignType, SignStatus};
use App\Traits\HasDateTimeFormatter;
/**
* 员工-打卡情况
*/
class EmployeeSign extends Model
{
use HasDateTimeFormatter;
protected $table = 'employee_sign_dates';
protected $fillable = ['date', 'store_id', 'employee_id', 'sign_type', 'first_time', 'last_time', 'sign_status'];
protected $casts = [
'date' => 'date:Y-m-d',
'sign_type' => SignType::class,
'sign_status' => SignStatus::class,
'first_time' => 'datetime',
'last_time' => 'datetime',
];
public function store()
{
return $this->belongsTo(Store::class, 'store_id');
}
public function employee()
{
return $this->belongsTo(Employee::class, 'employee_id');
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Enums\SignType;
/**
* 员工-打卡流水
*/
class EmployeeSignLog extends Model
{
protected $table = 'employee_sign_logs';
protected $fillable = ['store_id', 'employee_id', 'sign_type', 'remarks', 'position'];
protected $casts = [
'sign_type' => SignType::class,
'position' => 'json',
];
public function store()
{
return $this->belongsTo(Store::class, 'store_id');
}
public function employee()
{
return $this->belongsTo(Employee::class, 'employee_id');
}
}

View File

@ -2,10 +2,38 @@
namespace App\Models;
use App\Enums\CheckStatus;
use App\Enums\CheckType;
use Illuminate\Database\Eloquent\Model;
/**
* 审核流水
*/
class WorkflowLog extends Model
{
protected $fillable = ['batch_id', 'check_type', 'check_value', 'check_name', 'user_id', 'subject_type', 'subject_id', 'subject_data', 'is_enable', 'check_user_id', 'checked_at', 'remarks', 'check_status', 'sort'];
protected $casts = [
'check_type' => CheckType::class,
'check_status' => CheckStatus::class,
'is_enable' => 'boolean',
'subject_data' => 'json',
];
public function user()
{
return $this->belongsTo(Employee::class, 'user_id');
}
public function checkUser()
{
return $this->belongsTo(Employee::class, 'check_user_id');
}
public function subject()
{
// 定义反向关联
// $this->morphMany(WorkflowLog::class, 'subject');
return $this->morphTo();
}
}

View File

@ -48,5 +48,6 @@ return new class extends Migration
public function down(): void
{
Schema::dropIfExists('workflows');
Schema::dropIfExists('workflow_logs');
}
};

View File

@ -0,0 +1,75 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('employee_sign_dates', function (Blueprint $table) {
$table->id();
$table->date('date')->comment('日期');
$table->foreignId('store_id')->comment('门店, stores.id');
$table->foreignId('employee_id')->comment('员工, employees.id');
$table->unsignedInteger('sign_type')->default(1)->comment('类别(1: 正常打卡, 2: 外勤)');
$table->timestamp('first_time')->nullable()->comment('上班打卡时间');
$table->timestamp('last_time')->nullable()->comment('下班打卡时间');
$table->unsignedInteger('sign_status')->default(1)->comment('考勤状态(1: 正常, 2: 旷工, 3: 缺卡)');
$table->timestamps();
$table->comment('员工-考勤记录');
});
Schema::create('employee_sign_logs', function (Blueprint $table) {
$table->id();
$table->foreignId('store_id')->comment('门店, stores.id');
$table->foreignId('employee_id')->comment('员工, employees.id');
$table->unsignedInteger('sign_type')->default(1)->comment('类别(1: 正常打卡, 2: 外勤)');
$table->string('remarks')->nullable()->comment('备注');
$table->json('position')->comment('打卡位置');
$table->timestamps();
$table->comment('员工-打卡流水');
});
Schema::create('employee_rest_days', function (Blueprint $table) {
$table->id();
$table->date('date')->comment('日期');
$table->foreignId('employee_id')->comment('员工, employees.id');
$table->comment('员工-休息日');
});
Schema::create('employee_sign_repairs', function (Blueprint $table) {
$table->id();
$table->date('date')->comment('补卡日期');
$table->foreignId('store_id')->comment('门店, stores.id');
$table->foreignId('employee_id')->comment('员工, employees.id');
$table->string('reason')->comment('补卡原因');
$table->unsignedInteger('repair_type')->default(1)->comment('上班/下班 补卡');
$table->unsignedInteger('check_status')->default(0)->comment('审核状态');
$table->timestamp('checked_at')->nullable()->comment('审核通过时间');
$table->timestamps();
$table->comment('员工-补卡申请');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('employee_sign_dates');
Schema::dropIfExists('employee_sign_logs');
Schema::dropIfExists('employee_rest_days');
Schema::dropIfExists('employee_sign_repairs');
}
};

View File

@ -110,6 +110,12 @@ class AdminPermissionSeeder extends Seeder
'uri' => '/hr/jobs?parent_key=job',
'resource' => false
],
'rests' => [
'name' => '休息管理',
'icon' => '',
'uri' => '/hr/rests',
'resource' => true
],
],
],

View File

@ -0,0 +1,17 @@
<?php
return [
'id' => 'ID',
'created_at' => '创建时间',
'updated_at' => '更新时间',
'rest' => '休息日',
'date' => '日期',
'store_id' => '门店',
'employee_id' => '员工',
'sign_type' => '打卡类型',
'first_time' => '上班时间',
'last_time' => '下班时间',
'sign_status' => '打卡状态',
];