generated from liutk/owl-admin-base
admin 休息日管理
parent
afaa14d58d
commit
b722b53f6f
|
|
@ -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(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
});
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,5 +48,6 @@ return new class extends Migration
|
|||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('workflows');
|
||||
Schema::dropIfExists('workflow_logs');
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
}
|
||||
};
|
||||
|
|
@ -110,6 +110,12 @@ class AdminPermissionSeeder extends Seeder
|
|||
'uri' => '/hr/jobs?parent_key=job',
|
||||
'resource' => false
|
||||
],
|
||||
'rests' => [
|
||||
'name' => '休息管理',
|
||||
'icon' => '',
|
||||
'uri' => '/hr/rests',
|
||||
'resource' => true
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
|
|
|
|||
|
|
@ -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' => '打卡状态',
|
||||
];
|
||||
Loading…
Reference in New Issue