store-manage/app/Admin/Services/WorkFlowService.php

285 lines
9.0 KiB
PHP

<?php
namespace App\Admin\Services;
use App\Enums\CheckStatus;
use App\Enums\CheckType;
use App\Events\WorkflowCheckFailed;
use App\Events\WorkflowCheckNext;
use App\Events\WorkflowCheckSuccess;
use App\Models\Employee;
use App\Models\Keyword;
use App\Models\Store;
use App\Models\Workflow;
use App\Models\WorkflowCheck;
use App\Models\WorkflowLog;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
class WorkFlowService extends BaseService
{
protected array $withRelationships = [];
protected string $modelName = Workflow::class;
protected string $modelFilterName = '';
/**
* 发起审核申请
* 1. 待审核 Model 实现 Checkable
* 2. 生成全部的审核流程
*
* @param WorkflowCheck $check 待审核记录
* @param Employee $user 申请人
* @return bool true: 成功, false: 失败, $this->getError(): 错误消息
*/
public function apply(WorkflowCheck $check, Employee $user)
{
if ($check->check_status === CheckStatus::Success) {
admin_abort('已经审核通过');
}
if ($check->check_status === CheckStatus::Processing) {
admin_abort('正在审核中');
}
$check->update([
'apply_at' => now(),
]);
$workflow = Workflow::where('key', $check->key)->first();
// 没有配置审核流程, 直接通过
if (! $workflow || ! $workflow->config) {
$this->success($check);
return true;
}
$jobs = Keyword::where('parent_key', 'job')->get();
$config = collect($workflow->config)->sortBy('sort');
$batchId = $check->logs()->max('batch_id') + 1;
$check->update([
'subject_data' => $check->subject->toArray(),
'check_status' => CheckStatus::Processing,
'employee_id' => $user->id,
]);
foreach ($config as $item) {
$checkValue = '';
$checkName = '';
// 职位审核
if ($item['type'] == CheckType::Job->value) {
// 没有门店, 则跳过
if (! $user->store_id) {
continue;
}
// 所属门店的职位审核
$store = Store::findOrFail($user->store_id);
$job = $jobs->firstWhere('key', $item['value']);
$checkValue = $store->id.'-'.$job->key;
$checkName = $store->title.'-'.$job->name;
}
// 指定用户审核
elseif ($item['type'] == CheckType::User->value) {
$checkUser = Employee::findOrFail($item['value']);
$checkValue = $checkUser->id;
$checkName = $checkUser->name;
} else {
admin_abort('未知的审核类型: '.$item['type']);
}
$check->logs()->create([
'batch_id' => $batchId,
'check_type' => $item['type'],
'check_value' => $checkValue,
'check_name' => $checkName,
'sort' => $item['sort'],
]);
}
// 开启第一个审核流程
$this->next($check);
return true;
}
public function success(WorkflowCheck $check, array $options = [])
{
$check->update([
'check_status' => CheckStatus::Success,
'checked_at' => data_get($options, 'checked_at', now()),
'check_remarks' => data_get($options, 'remarks'),
]);
$check->subject->checkSuccess();
WorkflowCheckSuccess::dispatch($check->withoutRelations());
return true;
}
public function fail(WorkflowCheck $check, array $options = [])
{
$check->update([
'check_status' => CheckStatus::Fail,
'check_remarks' => data_get($options, 'remarks'),
'checked_at' => data_get($options, 'checked_at', now()),
]);
// 删除未审核的流程
$check->logs()->where('check_status', CheckStatus::None)->delete();
$check->subject->checkFail();
WorkflowCheckFailed::dispatch($check->withoutRelations());
return true;
}
/**
* 取消审核
* 1. 删除审核的流程
* 2. 更新申请记录的状态
*/
public function cancel(WorkflowCheck $check)
{
$check->logs()->delete();
$check->update([
'check_status' => CheckStatus::Cancel,
'check_value' => null,
'check_name' => null,
'check_type' => null,
]);
$check->subject->checkCancel();
return true;
}
/**
* 审核单个流程
*
* @param Employee $user 审核人
* @param WorkflowLog $log 审核流水记录
* @param bool $status 通过/不通过
* @param array $options {remarks: 不通过原因, time: 审核时间(默认当前时间)}
* @return bool
*/
public function check(Employee $user, WorkflowLog $log, $status, $options = [])
{
if ($log->check_status != CheckStatus::Processing) {
admin_abort('不可操作, 等待前面的审核完成');
}
if (! $this->authCheck($user, $log)) {
admin_abort('没有权限');
}
$attributes = ['check_status' => $status ? CheckStatus::Success : CheckStatus::Fail];
$attributes['checked_at'] = data_get($options, 'time', now());
$attributes['remarks'] = data_get($options, 'remarks');
$attributes['check_user_id'] = $user->id;
$log->update($attributes);
$check = $log->check;
$check->update(['check_name' => $user->name]);
if ($status) {
return $this->next($check);
} else {
return $this->fail($check, $options);
}
}
/**
* 开启下一个审核流程
*
* @return bool
*/
public function next(WorkflowCheck $check)
{
$log = $check->logs()->where('check_status', CheckStatus::None)->orderBy('sort')->first();
if ($log) {
$check->update([
'check_value' => $log->check_value,
'check_name' => $log->check_name,
'check_type' => $log->check_type,
]);
$log->update(['check_status' => CheckStatus::Processing]);
WorkflowCheckNext::dispatch($log->withoutRelations());
// 自动审核通过
if ($this->authCheck($check->employee, $log)) {
return $this->check($check->employee, $log, true, ['remarks' => '自动审核通过']);
}
} else {
// 没有审核流程了, 审核完成
return $this->success($check);
}
return true;
}
/**
* 是否有权限审核
* 1. 申请人 == 审核人
* 2. 申请人的 门店+职位 = 审核 门店+职位
*/
public function authCheck(Employee $user, WorkflowLog $log)
{
if ($user->adminUser?->isAdministrator()) {
return true;
}
$checkValue = [$user->id];
if ($user->jobs && $user->jobs->count() > 0) {
foreach ($user->jobs as $item) {
array_push($checkValue, $user->store_id.'-'.$item->key);
}
}
return in_array($log->check_value, $checkValue);
}
public function resloveData($data, $model = null)
{
if (isset($data['config'])) {
foreach ($data['config'] as $key => &$item) {
if (! $item) {
$data['config'] = null;
break;
}
if (! isset($item['value'])) {
$item['value'] = match ($item['type']) {
CheckType::Job->value => $item['job'],
CheckType::User->value => $item['user'],
};
}
$item['title'] = match ($item['type']) {
CheckType::Job->value => CheckType::Job->text(),
CheckType::User->value => CheckType::User->text(),
};
$item['subTitle'] = match ($item['type']) {
CheckType::Job->value => Keyword::where('key', $item['value'])->value('name'),
CheckType::User->value => Employee::where('id', $item['value'])->value('name'),
};
$item['sort'] = $key + 1;
}
}
return $data;
}
public function validate($data, $model = null)
{
$createRules = [
'key' => ['required', Rule::unique('workflows', 'key')],
'name' => ['required'],
'config' => ['required', 'array'],
];
$updateRules = [
'key' => [Rule::unique('workflows', 'key')->ignore($model?->id)],
];
$validator = Validator::make($data, $model ? $updateRules : $createRules, [
'key.unique' => ':input 已经存在',
]);
if ($validator->fails()) {
return $validator->errors()->first();
}
return true;
}
}