generated from liutk/owl-admin-base
api 审核流程
parent
b3177862bc
commit
77205d7fa9
|
|
@ -37,6 +37,14 @@ class EmployeeSignFilter extends ModelFilter
|
||||||
$this->whereBetween('date', [$start, $end]);
|
$this->whereBetween('date', [$start, $end]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function month($key)
|
||||||
|
{
|
||||||
|
$time = Carbon::createFromFormat('Y-m', $key);
|
||||||
|
$start = $time->copy()->startOfMonth();
|
||||||
|
$end = $time->copy()->endOfMonth();
|
||||||
|
$this->whereBetween('date', [$start, $end]);
|
||||||
|
}
|
||||||
|
|
||||||
public function signType($key)
|
public function signType($key)
|
||||||
{
|
{
|
||||||
$this->whereIn('sign_type', is_array($key) ? $key : explode(',', $key));
|
$this->whereIn('sign_type', is_array($key) ? $key : explode(',', $key));
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ namespace App\Admin\Services;
|
||||||
|
|
||||||
use App\Admin\Filters\EmployeeSignRepairFilter;
|
use App\Admin\Filters\EmployeeSignRepairFilter;
|
||||||
use App\Models\Employee;
|
use App\Models\Employee;
|
||||||
use App\Models\EmployeeSignRepair;
|
use App\Models\{EmployeeSignRepair, EmployeeSign};
|
||||||
use App\Models\WorkflowCheck;
|
use App\Models\WorkflowCheck;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
|
|
@ -17,22 +17,6 @@ class EmployeeSignRepairService extends BaseService
|
||||||
|
|
||||||
protected string $modelFilterName = EmployeeSignRepairFilter::class;
|
protected string $modelFilterName = EmployeeSignRepairFilter::class;
|
||||||
|
|
||||||
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 resloveData($data, $model = null)
|
public function resloveData($data, $model = null)
|
||||||
{
|
{
|
||||||
// 获取员工所在的门店
|
// 获取员工所在的门店
|
||||||
|
|
@ -43,28 +27,16 @@ class EmployeeSignRepairService extends BaseService
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function preDelete(array $ids): void
|
|
||||||
{
|
|
||||||
// 删除审核流程记录
|
|
||||||
WorkflowCheck::where('subject_type', (new WorkflowLog)->getMorphClass())->whereIn('subject_id', $ids)->delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function validate($data, $model = null)
|
public function validate($data, $model = null)
|
||||||
{
|
{
|
||||||
// 验证申请时间是否重叠
|
|
||||||
// todo
|
|
||||||
$unique = Rule::unique('employee_sign_repairs', 'date')
|
|
||||||
->where('employee_id', data_get($data, 'employee_id', $model?->employee_id))
|
|
||||||
->where('repair_type', data_get($data, 'repair_type', $model?->repair_type));
|
|
||||||
$createRules = [
|
$createRules = [
|
||||||
'employee_id' => ['required'],
|
'employee_id' => ['required'],
|
||||||
'repair_type' => ['required'],
|
'repair_type' => ['required'],
|
||||||
'date' => ['required', $unique],
|
'date' => ['required'],
|
||||||
'store_id' => ['required'],
|
'store_id' => ['required'],
|
||||||
'reason' => ['required'],
|
'reason' => ['required'],
|
||||||
];
|
];
|
||||||
$updateRules = [
|
$updateRules = [
|
||||||
'date' => [$unique->ignore($model?->id)],
|
|
||||||
];
|
];
|
||||||
$message = [
|
$message = [
|
||||||
'date.required' => __('employee_sign_repair.date').'必填',
|
'date.required' => __('employee_sign_repair.date').'必填',
|
||||||
|
|
@ -78,6 +50,8 @@ class EmployeeSignRepairService extends BaseService
|
||||||
if ($validator->fails()) {
|
if ($validator->fails()) {
|
||||||
return $validator->errors()->first();
|
return $validator->errors()->first();
|
||||||
}
|
}
|
||||||
|
// todo 已经打卡不能申请
|
||||||
|
// todo 验证申请时间是否重复
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ use App\Models\Employee;
|
||||||
use App\Models\EmployeeRest;
|
use App\Models\EmployeeRest;
|
||||||
use App\Models\EmployeeSign;
|
use App\Models\EmployeeSign;
|
||||||
use App\Models\EmployeeSignLog;
|
use App\Models\EmployeeSignLog;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
class EmployeeSignService extends BaseService
|
class EmployeeSignService extends BaseService
|
||||||
{
|
{
|
||||||
|
|
@ -63,8 +64,6 @@ class EmployeeSignService extends BaseService
|
||||||
$type = $logs->where('sign_type', SignType::Outside)->count() > 0 ? SignType::Outside : SignType::Normal;
|
$type = $logs->where('sign_type', SignType::Outside)->count() > 0 ? SignType::Outside : SignType::Normal;
|
||||||
}
|
}
|
||||||
$attributes = [
|
$attributes = [
|
||||||
'date' => $date,
|
|
||||||
'store_id' => $employee->store_id,
|
|
||||||
'sign_type' => $type,
|
'sign_type' => $type,
|
||||||
'first_time' => $firstTime,
|
'first_time' => $firstTime,
|
||||||
'last_time' => $lastTime,
|
'last_time' => $lastTime,
|
||||||
|
|
@ -75,7 +74,60 @@ class EmployeeSignService extends BaseService
|
||||||
},
|
},
|
||||||
'remarks' => $remarks,
|
'remarks' => $remarks,
|
||||||
];
|
];
|
||||||
$employee->signs()->create($attributes);
|
$employee->signs()->updateOrCreate([
|
||||||
|
'date' => $date,
|
||||||
|
'store_id' => $employee->store_id,
|
||||||
|
], $attributes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打卡
|
||||||
|
*
|
||||||
|
* @param Employee $user 用户
|
||||||
|
* @param SignTime $time 上班/下班 打卡
|
||||||
|
* @param mixed $date 打卡时间
|
||||||
|
* @param array $options {type: 正常/外勤 打卡, remarks: 备注, position: 位置}
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function signDay(Employee $user, SignTime $time, $date = '', array $options = [])
|
||||||
|
{
|
||||||
|
$date = $date ?: now();
|
||||||
|
$log = EmployeeSignLog::create([
|
||||||
|
'store_id' => $user->store_id,
|
||||||
|
'employee_id' => $user->id,
|
||||||
|
'sign_time' => $time,
|
||||||
|
'time' => $date,
|
||||||
|
'sign_type' => data_get($options, 'type'),
|
||||||
|
'remarks' => data_get($options, 'remarks'),
|
||||||
|
'position' => data_get($options, 'position'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 更新打卡情况
|
||||||
|
$sign = EmployeeSign::firstOrCreate([
|
||||||
|
'date' => $date->format('Y-m-d'),
|
||||||
|
'store_id' => $user->store_id,
|
||||||
|
'employee_id' => $user->id,
|
||||||
|
]);
|
||||||
|
$sign->sign_type = $log->sign_type;
|
||||||
|
if ($time == SignTime::Morning) {
|
||||||
|
$sign->first_time = $log->time;
|
||||||
|
} else if ($time == SignTime::Afternoon) {
|
||||||
|
$sign->last_time = $log->time;
|
||||||
|
}
|
||||||
|
$sign->sign_status = SignStatus::Lose;
|
||||||
|
if ($sign->first_time && $sign->last_time) {
|
||||||
|
$sign->sign_status = SignStatus::Normal;
|
||||||
|
}
|
||||||
|
$sign->remarks = $log->remarks;
|
||||||
|
|
||||||
|
$sign->save();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasRest(Employee $user, $date)
|
||||||
|
{
|
||||||
|
return EmployeeRest::where('employee_id', $user->id)->where('date', $date)->exists();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,8 @@ class WorkFlowService extends BaseService
|
||||||
'check_remarks' => data_get($options, 'remarks'),
|
'check_remarks' => data_get($options, 'remarks'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$check->subject->checkSuccess();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,22 @@
|
||||||
|
|
||||||
namespace App\Enums;
|
namespace App\Enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打卡状态
|
||||||
|
*/
|
||||||
enum SignStatus: int
|
enum SignStatus: int
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* 正常打卡
|
||||||
|
*/
|
||||||
case Normal = 1;
|
case Normal = 1;
|
||||||
|
/**
|
||||||
|
* 缺卡
|
||||||
|
*/
|
||||||
case Lose = 2;
|
case Lose = 2;
|
||||||
|
/**
|
||||||
|
* 旷工
|
||||||
|
*/
|
||||||
case Absent = 3;
|
case Absent = 3;
|
||||||
|
|
||||||
public static function options()
|
public static function options()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api\Hr;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Api\Controller;
|
||||||
|
use App\Models\{EmployeeSign};
|
||||||
|
use Illuminate\Http\{Request, Response};
|
||||||
|
use App\Exceptions\RuntimeException;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use App\Admin\Services\EmployeeSignService;
|
||||||
|
use App\Enums\{SignTime, SignType, SignStatus};
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 考勤打卡
|
||||||
|
*/
|
||||||
|
class SignController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$user = $this->guard()->user();
|
||||||
|
$time = $request->filled('time') ? Carbon::createFromFormat('Y-m', $request->input('time')) : now();
|
||||||
|
$list = EmployeeSign::where('employee_id', $user->id)->filter(['month' => $time->format('Y-m')])->get();
|
||||||
|
$data = [];
|
||||||
|
$start = $time->copy()->startOfMonth();
|
||||||
|
$end = $time->copy()->endOfMonth();
|
||||||
|
do {
|
||||||
|
$info = $list->where(fn($item) => $item->date->format('Y-m-d') == $start->format('Y-m-d'))->first();
|
||||||
|
array_push($data, [
|
||||||
|
'date' => $start->format('Y-m-d'),
|
||||||
|
'sign_status' => $info ? $info->sign_status : null,
|
||||||
|
'first_time' => $info?->first_time->format('H:i'),
|
||||||
|
'last_time' => $info?->last_time->format('H:i'),
|
||||||
|
]);
|
||||||
|
$start->addDay();
|
||||||
|
} while(!$end->isSameDay($start));
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function info(Request $request, EmployeeSignService $service)
|
||||||
|
{
|
||||||
|
$user = $this->guard()->user();
|
||||||
|
$date = now();
|
||||||
|
// 上午: 上班打卡, 下午: 下班打卡
|
||||||
|
$time = $date->format('H') <= 12 ? SignTime::Morning : SignTime::Afternoon;
|
||||||
|
// 根据定位的距离判断, 是否外勤
|
||||||
|
$type = SignType::Normal;
|
||||||
|
// 当前位置不在考勤范围内,请选择外勤打卡
|
||||||
|
$description = '已进入考勤范围xx店';
|
||||||
|
|
||||||
|
return compact('time', 'type', 'description');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(Request $request, EmployeeSignService $service)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'type' => ['required'],
|
||||||
|
'time' => ['required'],
|
||||||
|
]);
|
||||||
|
$user = $this->guard()->user();
|
||||||
|
$time = SignTime::from($request->input('time'));
|
||||||
|
try {
|
||||||
|
DB::beginTransaction();
|
||||||
|
if (!$service->signDay($user, $time, now(), $request->only(['remarks', 'position', 'type']))) {
|
||||||
|
throw new RuntimeException($service->getError());
|
||||||
|
}
|
||||||
|
DB::commit();
|
||||||
|
return response('', Response::HTTP_OK);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
DB::rollBack();
|
||||||
|
throw new RuntimeException($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,114 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api\Hr;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Api\Controller;
|
||||||
|
use Illuminate\Http\{Request, Response};
|
||||||
|
use App\Models\EmployeeSignRepair;
|
||||||
|
use App\Http\Resources\{EmployeeSignRepairResource, WorkflowLogResource};
|
||||||
|
use App\Admin\Services\{EmployeeSignRepairService, WorkFlowService};
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use App\Exceptions\RuntimeException;
|
||||||
|
use App\Enums\{CheckStatus};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 补卡申请
|
||||||
|
*/
|
||||||
|
class SignRepairController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$user = $this->guard()->user();
|
||||||
|
$list = EmployeeSignRepair::with(['workflow'])
|
||||||
|
->where('employee_id', $user->id)
|
||||||
|
->filter($request->all())
|
||||||
|
->orderBy('id', 'desc')
|
||||||
|
->paginate($request->input('per_page'));
|
||||||
|
return EmployeeSignRepairResource::collection($list);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(Request $request, EmployeeSignRepairService $service)
|
||||||
|
{
|
||||||
|
$user = $this->guard()->user();
|
||||||
|
$data = $request->all();
|
||||||
|
$data['employee_id'] = $user->id;
|
||||||
|
|
||||||
|
try {
|
||||||
|
DB::beginTransaction();
|
||||||
|
$data = $service->resloveData($data);
|
||||||
|
$result = $service->validate($data);
|
||||||
|
if ($result !== true) {
|
||||||
|
throw new RuntimeException($result);
|
||||||
|
}
|
||||||
|
$model = EmployeeSignRepair::create($data);
|
||||||
|
$workflow = WorkFlowService::make();
|
||||||
|
if (!$workflow->apply($model->workflow, $user)) {
|
||||||
|
throw new RuntimeException($workflow->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::commit();
|
||||||
|
return response('', Response::HTTP_OK);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
DB::rollBack();
|
||||||
|
throw new RuntimeException($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show($id)
|
||||||
|
{
|
||||||
|
$info = EmployeeSignRepair::with(['workflow', 'employee', 'store'])->findOrFail($id);
|
||||||
|
|
||||||
|
return EmployeeSignRepairResource::make($info);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update($id, Request $request, EmployeeSignRepairService $service)
|
||||||
|
{
|
||||||
|
$user = $this->guard()->user();
|
||||||
|
$model = EmployeeSignRepair::with(['workflow'])->where('employee_id', $user->id)->findOrFail($id);
|
||||||
|
if (!$model->canUpdate()) {
|
||||||
|
throw new RuntimeException('审核中, 无法修改');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
DB::beginTransaction();
|
||||||
|
$data = $service->resloveData($data, $model);
|
||||||
|
$result = $service->validate($data, $model);
|
||||||
|
if ($result !== true) {
|
||||||
|
throw new RuntimeException($result);
|
||||||
|
}
|
||||||
|
$model->update($data);
|
||||||
|
$workflow = WorkFlowService::make();
|
||||||
|
if (!$workflow->apply($model->workflow, $user)) {
|
||||||
|
throw new RuntimeException($workflow->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::commit();
|
||||||
|
return response('', Response::HTTP_OK);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
DB::rollBack();
|
||||||
|
throw new RuntimeException($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy($id, EmployeeSignRepairService $service)
|
||||||
|
{
|
||||||
|
$user = $this->guard()->user();
|
||||||
|
$model = EmployeeSignRepair::with(['workflow'])->where('employee_id', $user->id)->findOrFail($id);
|
||||||
|
if (!$model->canUpdate()) {
|
||||||
|
throw new RuntimeException('审核中, 无法删除');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
DB::beginTransaction();
|
||||||
|
if (!$service->delete($id)) {
|
||||||
|
throw new RuntimeException($service->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::commit();
|
||||||
|
return response('', Response::HTTP_OK);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
DB::rollBack();
|
||||||
|
throw new RuntimeException($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use Illuminate\Http\{Request, Response};
|
||||||
|
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||||
|
use App\Http\Resources\{ReimbursementResource, WorkflowLogResource, EmployeeSignRepairResource};
|
||||||
|
use App\Enums\CheckStatus;
|
||||||
|
use App\Models\{WorkflowLog, WorkflowCheck};
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
use App\Admin\Services\WorkFlowService;
|
||||||
|
use App\Exceptions\RuntimeException;
|
||||||
|
|
||||||
|
class WorkflowController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'subject_type' => 'required',
|
||||||
|
]);
|
||||||
|
$subjectType = $request->input('subject_type');
|
||||||
|
$model = Relation::getMorphedModel($subjectType);
|
||||||
|
$resource = $this->mapResource($subjectType);
|
||||||
|
|
||||||
|
$user = $request->user();
|
||||||
|
$query = $model::query()->with(['workflow'])
|
||||||
|
->whereHas('workflow', fn($q) => $q->where('check_status', CheckStatus::Processing))
|
||||||
|
->whereHas('workflow.logs', fn($q) => $q->own($user))
|
||||||
|
->orderBy('created_at', 'desc');
|
||||||
|
|
||||||
|
$list = $query->paginate($request->input('per_page'));
|
||||||
|
|
||||||
|
return $resource::collection($list);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show($id, Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'subject_type' => 'required',
|
||||||
|
]);
|
||||||
|
$subjectType = $request->input('subject_type');
|
||||||
|
$model = Relation::getMorphedModel($subjectType);
|
||||||
|
$resource = $this->mapResource($subjectType);
|
||||||
|
|
||||||
|
$include = ['workflow'];
|
||||||
|
if ($request->input('include')) {
|
||||||
|
$explodes = explode(',', $request->input('include'));
|
||||||
|
$include = array_merge($include, $explodes);
|
||||||
|
}
|
||||||
|
$info = $model::query()->with($include)->findOrFail($id);
|
||||||
|
|
||||||
|
return $resource::make($info);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function logs($id, Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'subject_type' => 'required',
|
||||||
|
]);
|
||||||
|
$check = WorkflowCheck::where('subject_type', $request->input('subject_type'))->where('subject_id', $id)->firstOrFail();
|
||||||
|
$logs = $check->logs()->sort()->get();
|
||||||
|
|
||||||
|
return WorkflowLogResource::collection($logs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function check($id, Request $request, WorkFlowService $workFlowService)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'subject_type' => 'required',
|
||||||
|
'status' => ['required'],
|
||||||
|
'remarks' => [Rule::requiredIf(fn() => !$request->input('status'))]
|
||||||
|
], [
|
||||||
|
'remarks.required_if' => '未通过原因必填',
|
||||||
|
]);
|
||||||
|
$check = WorkflowCheck::where('subject_type', $request->input('subject_type'))->where('subject_id', $id)->firstOrFail();
|
||||||
|
$user = $request->user();
|
||||||
|
try {
|
||||||
|
DB::beginTransaction();
|
||||||
|
$log = $check->logs()->where('check_status', CheckStatus::Processing)->first();
|
||||||
|
if (!$log) {
|
||||||
|
throw new RuntimeException('审核已经完成');
|
||||||
|
}
|
||||||
|
if (!$workFlowService->check($user, $log, !!$request->input('status'), ['remarks' => $request->input('remarks')])) {
|
||||||
|
throw new RuntimeException($workFlowService->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::commit();
|
||||||
|
return response('', Response::HTTP_OK);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
DB::rollBack();
|
||||||
|
throw new RuntimeException($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function mapResource($key)
|
||||||
|
{
|
||||||
|
$map = [
|
||||||
|
'reimbursements' => ReimbursementResource::class,
|
||||||
|
'employee_sign_repairs' => EmployeeSignRepairResource::class,
|
||||||
|
];
|
||||||
|
return data_get($map, $key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
class EmployeeSignRepairResource extends JsonResource
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Transform the resource into an array.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(Request $request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
|
'date' => $this->date->timestamp,
|
||||||
|
|
||||||
|
'employee_id' => $this->employee_id,
|
||||||
|
'employee' => EmployeeResource::make($this->whenLoaded('employee')),
|
||||||
|
'store_id' => $this->store_id,
|
||||||
|
'store' => StoreResource::make($this->whenLoaded('store')),
|
||||||
|
|
||||||
|
'reason' => $this->reason,
|
||||||
|
'repair_type' => $this->repair_type,
|
||||||
|
'sign_type' => $this->sign_type,
|
||||||
|
'outside_remarks' => $this->outside_remarks,
|
||||||
|
'created_at' => $this->created_at->timestamp,
|
||||||
|
|
||||||
|
'workflow_check' => WorkflowCheckResource::make($this->whenLoaded('workflow')),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,22 +14,12 @@ class WorkflowCheckResource extends JsonResource
|
||||||
*/
|
*/
|
||||||
public function toArray(Request $request): array
|
public function toArray(Request $request): array
|
||||||
{
|
{
|
||||||
$resource = $this->mapResource($this->subject_type);
|
|
||||||
return [
|
return [
|
||||||
'check_status' => $this->check_status,
|
'check_status' => $this->check_status,
|
||||||
'check_status_text' => $this->check_status?->text(),
|
'check_status_text' => $this->check_status?->text(),
|
||||||
'checked_at' => $this->checked_at?->getTimestamp(),
|
'checked_at' => $this->checked_at?->getTimestamp(),
|
||||||
'check_remarks' => (string) $this->check_remarks,
|
'check_remarks' => (string) $this->check_remarks,
|
||||||
'subject' => $resource ? $resource::make($this->whenLoaded('subject')) : '',
|
|
||||||
'logs' => WorkflowLogResource::collection($this->whenLoaded('logs')),
|
'logs' => WorkflowLogResource::collection($this->whenLoaded('logs')),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function mapResource($key)
|
|
||||||
{
|
|
||||||
$map = [
|
|
||||||
'reimbursements' => ReimbursementResource::class,
|
|
||||||
];
|
|
||||||
return data_get($map, $key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,11 @@ class EmployeeSign extends Model
|
||||||
'last_time' => 'datetime',
|
'last_time' => 'datetime',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function modelFilter()
|
||||||
|
{
|
||||||
|
return \App\Admin\Filters\EmployeeSignFilter::class;
|
||||||
|
}
|
||||||
|
|
||||||
public function store()
|
public function store()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Store::class, 'store_id');
|
return $this->belongsTo(Store::class, 'store_id');
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ class EmployeeSignLog extends Model
|
||||||
|
|
||||||
protected $table = 'employee_sign_logs';
|
protected $table = 'employee_sign_logs';
|
||||||
|
|
||||||
protected $fillable = ['store_id', 'employee_id', 'sign_type', 'sign_time', 'remarks', 'position', 'time'];
|
protected $guarded = [];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'sign_type' => SignType::class,
|
'sign_type' => SignType::class,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\{SignTime};
|
use App\Enums\{SignTime, SignType, CheckStatus};
|
||||||
use App\Traits\HasCheckable;
|
use App\Traits\HasCheckable;
|
||||||
use App\Traits\HasDateTimeFormatter;
|
use App\Traits\HasDateTimeFormatter;
|
||||||
use EloquentFilter\Filterable;
|
use EloquentFilter\Filterable;
|
||||||
|
|
@ -17,14 +17,19 @@ class EmployeeSignRepair extends Model
|
||||||
|
|
||||||
protected $table = 'employee_sign_repairs';
|
protected $table = 'employee_sign_repairs';
|
||||||
|
|
||||||
protected $fillable = ['date', 'store_id', 'employee_id', 'reason', 'repair_type'];
|
protected $guarded = [];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'date' => 'date:Y-m-d',
|
'date' => 'datetime',
|
||||||
'checked_at' => 'datetime',
|
|
||||||
'repair_type' => SignTime::class,
|
'repair_type' => SignTime::class,
|
||||||
|
'sign_type' => SignType::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function canUpdate(): bool
|
||||||
|
{
|
||||||
|
return in_array($this->workflow?->check_status, [CheckStatus::None, CheckStatus::Fail, CheckStatus::Cancel]);
|
||||||
|
}
|
||||||
|
|
||||||
public function modelFilter()
|
public function modelFilter()
|
||||||
{
|
{
|
||||||
return \App\Admin\Filters\EmployeeSignRepairFilter::class;
|
return \App\Admin\Filters\EmployeeSignRepairFilter::class;
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,11 @@ trait HasCheckable
|
||||||
return Str::snake(class_basename(__CLASS__));
|
return Str::snake(class_basename(__CLASS__));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function checkSuccess()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 关联审核流水
|
* 关联审核流水
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
use Illuminate\Database\Migrations\Migration;
|
use Illuminate\Database\Migrations\Migration;
|
||||||
use Illuminate\Database\Schema\Blueprint;
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
use Illuminate\Support\Facades\Schema;
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use App\Enums\{SignType, SignTime, SignStatus};
|
||||||
|
|
||||||
return new class extends Migration
|
return new class extends Migration
|
||||||
{
|
{
|
||||||
|
|
@ -16,10 +17,10 @@ return new class extends Migration
|
||||||
$table->date('date')->comment('日期');
|
$table->date('date')->comment('日期');
|
||||||
$table->foreignId('store_id')->comment('门店, stores.id');
|
$table->foreignId('store_id')->comment('门店, stores.id');
|
||||||
$table->foreignId('employee_id')->comment('员工, employees.id');
|
$table->foreignId('employee_id')->comment('员工, employees.id');
|
||||||
$table->unsignedInteger('sign_type')->default(1)->comment('类别(1: 正常打卡, 2: 外勤)');
|
$table->unsignedInteger('sign_type')->default(SignType::Normal)->comment('类别(1: 正常打卡, 2: 外勤)');
|
||||||
$table->timestamp('first_time')->nullable()->comment('上班打卡时间');
|
$table->timestamp('first_time')->nullable()->comment('上班打卡时间');
|
||||||
$table->timestamp('last_time')->nullable()->comment('下班打卡时间');
|
$table->timestamp('last_time')->nullable()->comment('下班打卡时间');
|
||||||
$table->unsignedInteger('sign_status')->default(1)->comment('考勤状态(1: 正常, 2: 旷工, 3: 缺卡)');
|
$table->unsignedInteger('sign_status')->default(SignStatus::Normal)->comment('考勤状态(1: 正常, 2: 旷工, 3: 缺卡)');
|
||||||
$table->string('remarks')->nullable()->comment('备注');
|
$table->string('remarks')->nullable()->comment('备注');
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
|
|
||||||
|
|
@ -30,9 +31,12 @@ return new class extends Migration
|
||||||
$table->id();
|
$table->id();
|
||||||
$table->foreignId('store_id')->comment('门店, stores.id');
|
$table->foreignId('store_id')->comment('门店, stores.id');
|
||||||
$table->foreignId('employee_id')->comment('员工, employees.id');
|
$table->foreignId('employee_id')->comment('员工, employees.id');
|
||||||
$table->unsignedInteger('sign_type')->default(1)->comment('类别(1: 正常打卡, 2: 外勤)');
|
$table->unsignedInteger('sign_type')->default(SignType::Normal)->comment('类别(1: 正常打卡, 2: 外勤)');
|
||||||
$table->unsignedInteger('sign_time')->default(1)->comment('打卡时间(1: 上班, 2: 下班)');
|
$table->unsignedInteger('sign_time')->default(SignTime::Morning)->comment('打卡时间(1: 上班, 2: 下班)');
|
||||||
$table->string('remarks')->nullable()->comment('备注');
|
$table->string('remarks')->nullable()->comment('备注');
|
||||||
|
$table->string('outside_remarks')->nullable()->comment('外勤备注');
|
||||||
|
$table->unsignedInteger('is_repair')->default(0)->comment('是否补卡');
|
||||||
|
$table->foreignId('repair_id')->nullable()->comment('补卡记录');
|
||||||
$table->json('position')->comment('打卡位置');
|
$table->json('position')->comment('打卡位置');
|
||||||
$table->timestamp('time')->comment('打卡时间');
|
$table->timestamp('time')->comment('打卡时间');
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
|
|
@ -50,11 +54,13 @@ return new class extends Migration
|
||||||
|
|
||||||
Schema::create('employee_sign_repairs', function (Blueprint $table) {
|
Schema::create('employee_sign_repairs', function (Blueprint $table) {
|
||||||
$table->id();
|
$table->id();
|
||||||
$table->date('date')->comment('补卡日期');
|
$table->datetime('date')->comment('补卡日期');
|
||||||
$table->foreignId('store_id')->comment('门店, stores.id');
|
$table->foreignId('store_id')->comment('门店, stores.id');
|
||||||
$table->foreignId('employee_id')->comment('员工, employees.id');
|
$table->foreignId('employee_id')->comment('员工, employees.id');
|
||||||
$table->string('reason')->comment('补卡原因');
|
$table->string('reason')->comment('补卡原因');
|
||||||
$table->unsignedInteger('repair_type')->default(1)->comment('上班/下班');
|
$table->unsignedInteger('repair_type')->default(SignTime::Morning)->comment('上班/下班');
|
||||||
|
$table->unsignedInteger('sign_type')->default(SignType::Normal)->comment('类别(1: 正常打卡, 2: 外勤)');
|
||||||
|
$table->string('outside_remarks')->nullable()->comment('外勤备注');
|
||||||
|
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,9 +54,20 @@ Route::group([
|
||||||
Route::apiResource('hr/employee', \App\Http\Controllers\Api\Hr\EmployeeController::class);
|
Route::apiResource('hr/employee', \App\Http\Controllers\Api\Hr\EmployeeController::class);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 考勤打卡
|
||||||
|
Route::get('hr/sign/info', [\App\Http\Controllers\Api\Hr\SignController::class, 'info']);
|
||||||
|
Route::get('hr/sign', [\App\Http\Controllers\Api\Hr\SignController::class, 'index']);
|
||||||
|
Route::post('hr/sign', [\App\Http\Controllers\Api\Hr\SignController::class, 'store']);
|
||||||
|
|
||||||
|
// 补卡申请
|
||||||
|
Route::apiResource('hr/sign-repairs', \App\Http\Controllers\Api\Hr\SignRepairController::class);
|
||||||
|
|
||||||
// 报销管理
|
// 报销管理
|
||||||
Route::get('reimbursements/check', [\App\Http\Controllers\Api\ReimbursementController::class, 'checkList']);
|
|
||||||
Route::post('reimbursements/{id}/check', [\App\Http\Controllers\Api\ReimbursementController::class, 'check']);
|
|
||||||
Route::get('reimbursements/{id}/logs', [\App\Http\Controllers\Api\ReimbursementController::class, 'logs']);
|
|
||||||
Route::apiResource('reimbursements', \App\Http\Controllers\Api\ReimbursementController::class);
|
Route::apiResource('reimbursements', \App\Http\Controllers\Api\ReimbursementController::class);
|
||||||
|
|
||||||
|
// 审核流程
|
||||||
|
Route::get('workflow', [\App\Http\Controllers\Api\WorkflowController::class, 'index']);
|
||||||
|
Route::get('workflow/{id}', [\App\Http\Controllers\Api\WorkflowController::class, 'show']);
|
||||||
|
Route::get('workflow/{id}/logs', [\App\Http\Controllers\Api\WorkflowController::class, 'logs']);
|
||||||
|
Route::post('workflow/{id}/check', [\App\Http\Controllers\Api\WorkflowController::class, 'check']);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue