admin 审核流程-审核按钮

main
panliang 2024-04-01 15:38:16 +08:00
parent 2a9af8a8b0
commit 474e9a4364
10 changed files with 360 additions and 56 deletions

View File

@ -9,12 +9,15 @@ use Slowlyo\OwlAdmin\Renderers\Page;
use Slowlyo\OwlAdmin\Admin;
use App\Enums\{EmployeeStatus, SignTime, CheckStatus};
use App\Models\EmployeeSignRepair;
use App\Traits\HasCheckActions;
/**
* 补卡申请
*/
class SignRepairController extends AdminController
{
use HasCheckActions;
protected string $serviceName = EmployeeSignRepairService::class;
public function list(): Page
@ -40,6 +43,15 @@ class SignRepairController extends AdminController
->placeholder(__('employee.name').'/'.__('employee.phone'))
->columnRatio(3)
->clearable(),
amisMake()->DateRangeControl()->name('date_range')->label(__('employee_sign_repair.date'))
->columnRatio(3)
->clearable(),
]),
amis()->GroupControl()->mode('horizontal')->body([
amisMake()->SelectControl()->name('check_status')->label(__('employee_sign_repair.check_status'))
->options(CheckStatus::options())
->columnRatio(3)
->clearable()
]),
]))
->columns([
@ -55,27 +67,14 @@ class SignRepairController extends AdminController
->map(CheckStatus::options()),
$this->rowActions([
$this->rowShowButton()->visible(Admin::user()->can('admin.hr.repairs.view')),
$this->rowEditTypeButton('drawer', 'xl')->visible(Admin::user()->can('admin.hr.repairs.update')),
$this->rowDeleteButton()->visible(Admin::user()->can('admin.hr.repairs.delete')),
amisMake()->AjaxAction()
->label('发起审核')
->level('link')
->api(amisMake()->BaseApi()->url(admin_url('api/workflow/apply'))->method('post')->data([
'subject_type' => $subjectType,
'subject_id' => '${id}',
'user' => '${employee_id}'
]))
->confirmText(__('admin.confirm'))
$this->rowEditTypeButton('drawer', 'xl')
->visible(Admin::user()->can('admin.hr.repairs.update'))
->visibleOn('${OR(check_status == '.CheckStatus::None->value.', check_status == '.CheckStatus::Cancel->value.', check_status == '.CheckStatus::Fail->value.')}'),
amisMake()->AjaxAction()
->label('取消审核')
->level('link')
->api(amisMake()->BaseApi()->url(admin_url('api/workflow/cancel'))->method('post')->data([
'subject_type' => $subjectType,
'subject_id' => '${id}',
]))
->confirmText(__('admin.confirm'))
->visibleOn('${check_status == '.CheckStatus::Processing->value.'}'),
$this->rowDeleteButton()
->visible(Admin::user()->can('admin.hr.repairs.delete'))
->visibleOn('${OR(check_status == '.CheckStatus::None->value.', check_status == '.CheckStatus::Cancel->value.', check_status == '.CheckStatus::Fail->value.')}'),
$this->applyAction(),
$this->cancelAction(),
])
]);
@ -93,7 +92,12 @@ class SignRepairController extends AdminController
->joinValues(false)
->extractValue()
->required(),
amisMake()->DateControl()->format('YYYY-MM-DD HH:mm:ss')->name('date')->label(__('employee_sign_repair.date'))->required(),
amisMake()->DateControl()
->format('YYYY-MM-DD HH:mm:ss')
->name('date')
->label(__('employee_sign_repair.date'))
->maxDate('now')
->required(),
amisMake()->SelectControl()->options(SignTime::options())->name('repair_type')->label(__('employee_sign_repair.repair_type'))->required(),
amisMake()->TextControl()->name('reason')->label(__('employee_sign_repair.reason'))->required(),
]);
@ -124,23 +128,8 @@ class SignRepairController extends AdminController
)
->body(
amisMake()->Table()->columnsTogglable(false)->itemActions([
amisMake()->AjaxAction()
->label('审核通过')
->level('link')
->api('post:' . admin_url('api/workflow/success?id=${id}'))
->confirmText(__('admin.confirm'))
->visibleOn('${check_status == '.CheckStatus::Processing->value.'}')
->reload('sign-repair-detail'),
amisMake()->DialogAction()
->label('审核不通过')
->level('link')
->dialog(amisMake()->Dialog()->title('审核不通过')->body(
amisMake()->Form()->title('')->api('post:'.admin_url('api/workflow/fail'))->body([
amisMake()->HiddenControl()->name('id'),
amisMake()->TextControl()->name('remarks')->label(__('workflow_log.remarks'))->required(),
])->reload('sign-repair-detail')
))
->visibleOn('${check_status == '.CheckStatus::Processing->value.'}'),
$this->succesAction()->reload('sign-repair-detail'),
$this->failAction()->reload('sign-repair-detail'),
])->columns([
amisMake()->TableColumn()->name('batch_id')->label(__('workflow_log.batch_id')),
amisMake()->TableColumn()->name('check_name')->label(__('workflow_log.check_name')),
@ -158,4 +147,9 @@ class SignRepairController extends AdminController
]
])->body([$detail, amisMake()->Divider(), $table]);
}
public function getMorphAlias()
{
return (new EmployeeSignRepair)->getMorphClass();
}
}

View File

@ -22,6 +22,14 @@ class EmployeeSignRepairFilter extends ModelFilter
public function date($key)
{
$date = Carbon::createFromFormat('Y-m-d', $key);
$this->whereBetween('time', [$date->copy()->startOfDay(), $date->copy()->endOfDay()]);
$this->whereBetween('date', [$date->copy()->startOfDay(), $date->copy()->endOfDay()]);
}
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

@ -74,7 +74,7 @@ class EmployeeService extends BaseService
$adminUserService = AdminUserService::make();
if (!$model) {
// 添加管理员信息
if (! $adminUserService->store(Arr::only($data, ['username', 'password', 'confirm_password']))) {
if (! $adminUserService->store(Arr::only($data, ['username', 'password', 'confirm_password', 'name']))) {
$this->setError($adminUserService->getError());
return false;

View File

@ -3,11 +3,12 @@
namespace App\Admin\Services;
use App\Admin\Filters\EmployeeSignRepairFilter;
use App\Models\EmployeeSignRepair;
use App\Models\{EmployeeSignRepair, WorkflowLog};
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use App\Models\Employee;
use App\Enums\CheckStatus;
class EmployeeSignRepairService extends BaseService
{
@ -42,22 +43,36 @@ class EmployeeSignRepairService extends BaseService
return $data;
}
public function preDelete(array $ids)
{
// 删除审核流程记录
WorkflowLog::where('subject_type', (new WorkflowLog)->getMorphClass())->whereIn('subject_id', $ids)->delete();
return true;
}
public function validate($data, $model = null)
{
$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))
->whereIn('check_status', [CheckStatus::Success, CheckStatus::Processing, CheckStatus::None]);
$createRules = [
'date' => ['required'],
'store_id' => ['required'],
'employee_id' => ['required'],
'reason' => ['required'],
'repair_type' => ['required'],
'date' => ['required', $unique],
'store_id' => ['required'],
'reason' => ['required'],
];
$updateRules = [
'date' => [$unique->ignore($model?->id)]
];
$updateRules = [];
$message = [
'date.required' => __('employee_sign.date') . '必填',
'store_id.required' => __('employee_sign.store_id') . '必填',
'employee_id.required' => __('employee_sign.employee_id') . '必填',
'reason.required' => __('employee_sign.reason') . '必填',
'repair_type.required' => __('employee_sign.repair_type') . '必填',
'date.required' => __('employee_sign_repair.date') . '必填',
'store_id.required' => __('employee_sign_repair.store_id') . '必填',
'employee_id.required' => __('employee_sign_repair.employee_id') . '必填',
'reason.required' => __('employee_sign_repair.reason') . '必填',
'repair_type.required' => __('employee_sign_repair.repair_type') . '必填',
'date.unique' => __('employee_sign_repair.date') . ' 已经申请过了'
];
$validator = Validator::make($data, $model ? $updateRules : $createRules, $message);
if ($validator->fails()) {

View File

@ -145,7 +145,7 @@ class WorkFlowService extends BaseService
$log->update(['check_status' => CheckStatus::Processing]);
// 申请人自动审核通过
if ($this->authCheck($subject->employee, $log)) {
return $this->check($subject->employee, $log, true);
return $this->check($subject->employee, $log, true, ['remarks' => '自动审核通过']);
}
} else {
// 没有审核流程了
@ -160,9 +160,9 @@ class WorkFlowService extends BaseService
*/
public function authCheck(Employee $user, WorkflowLog $log)
{
if ($user->adminUser?->isAdministrator()) {
return true;
}
// if ($user->adminUser?->isAdministrator()) {
// return true;
// }
if ($log->check_type == CheckType::User && $log->check_value == $user->id) {
return true;
} else if ($log->check_type == CheckType::Job) {

View File

@ -0,0 +1,68 @@
<?php
namespace App\Traits;
use App\Enums\{CheckStatus};
trait HasCheckActions
{
public function getMorphAlias()
{
// return (new EmployeeSignRepair)->getMorphClass();
return '';
}
public function applyAction()
{
return amisMake()
->AjaxAction()
->label('发起审核')
->level('link')
->api(amisMake()->BaseApi()->url(admin_url('api/workflow/apply'))->method('post')->data([
'subject_type' => $this->getMorphAlias(),
'subject_id' => '${id}'
]))
->confirmText(__('admin.confirm'))
->visibleOn('${OR(check_status == '.CheckStatus::None->value.', check_status == '.CheckStatus::Cancel->value.', check_status == '.CheckStatus::Fail->value.')}');
}
public function cancelAction()
{
return amisMake()
->AjaxAction()
->label('取消审核')
->level('link')
->api(amisMake()->BaseApi()->url(admin_url('api/workflow/cancel'))->method('post')->data([
'subject_type' => $this->getMorphAlias(),
'subject_id' => '${id}',
]))
->confirmText(__('admin.confirm'))
->visibleOn('${check_status == '.CheckStatus::Processing->value.'}');
}
public function succesAction()
{
return amisMake()
->AjaxAction()
->label('审核通过')
->level('link')
->api('post:' . admin_url('api/workflow/success?id=${id}'))
->confirmText(__('admin.confirm'))
->visibleOn('${check_status == '.CheckStatus::Processing->value.'}');
}
public function failAction()
{
return amisMake()
->DialogAction()
->label('审核不通过')
->level('link')
->dialog(amisMake()->Dialog()->title('审核不通过')->body(
amisMake()->Form()->title('')->api('post:'.admin_url('api/workflow/fail'))->body([
amisMake()->HiddenControl()->name('id'),
amisMake()->TextControl()->name('remarks')->label(__('workflow_log.remarks'))->required(),
])
))
->visibleOn('${check_status == '.CheckStatus::Processing->value.'}');
}
}

View File

@ -27,7 +27,7 @@ class EmployeeFactory extends Factory
$adminUser = AdminUser::create([
'username' => $phone,
// 123456
'password' => '$12$exmmsMLDmZO4aNug/a4CquCU8237FNrwMa4S9EawhvO0XaIqZSD9i',
'password' => AdminUser::where('id', 1)->value('password'),
'name' => $name,
]);
return [

View File

@ -16,6 +16,7 @@ class DatabaseSeeder extends Seeder
AdminSeeder::class,
KeywordSeeder::class,
AdminPermissionSeeder::class,
WorkflowSeeder::class,
]);
}
}

View File

@ -0,0 +1,218 @@
<?php
declare(strict_types=1);
return [
'accepted' => '您必须接受 :attribute。',
'accepted_if' => '当 :other 为 :value 时,必须接受 :attribute。',
'active_url' => ':Attribute 不是一个有效的网址。',
'after' => ':Attribute 必须要晚于 :date。',
'after_or_equal' => ':Attribute 必须要等于 :date 或更晚。',
'alpha' => ':Attribute 只能由字母组成。',
'alpha_dash' => ':Attribute 只能由字母、数字、短划线(-)和下划线(_)组成。',
'alpha_num' => ':Attribute 只能由字母和数字组成。',
'array' => ':Attribute 必须是一个数组。',
'ascii' => ':Attribute 必须仅包含单字节字母数字字符和符号。',
'before' => ':Attribute 必须要早于 :date。',
'before_or_equal' => ':Attribute 必须要等于 :date 或更早。',
'between' => [
'array' => ':Attribute 必须只有 :min - :max 个单元。',
'file' => ':Attribute 必须介于 :min - :max KB 之间。',
'numeric' => ':Attribute 必须介于 :min - :max 之间。',
'string' => ':Attribute 必须介于 :min - :max 个字符之间。',
],
'boolean' => ':Attribute 必须为布尔值。',
'can' => ':Attribute 字段包含未经授权的值。',
'confirmed' => ':Attribute 两次输入不一致。',
'current_password' => '密码错误。',
'date' => ':Attribute 不是一个有效的日期。',
'date_equals' => ':Attribute 必须要等于 :date。',
'date_format' => ':Attribute 的格式必须为 :format。',
'decimal' => ':Attribute 必须有 :decimal 位小数。',
'declined' => ':Attribute 必须是拒绝的。',
'declined_if' => '当 :other 为 :value 时字段 :attribute 必须是拒绝的。',
'different' => ':Attribute 和 :other 必须不同。',
'digits' => ':Attribute 必须是 :digits 位数字。',
'digits_between' => ':Attribute 必须是介于 :min 和 :max 位的数字。',
'dimensions' => ':Attribute 图片尺寸不正确。',
'distinct' => ':Attribute 已经存在。',
'doesnt_end_with' => ':Attribute 不能以以下之一结尾: :values。',
'doesnt_start_with' => ':Attribute 不能以下列之一开头: :values。',
'email' => ':Attribute 不是一个合法的邮箱。',
'ends_with' => ':Attribute 必须以 :values 为结尾。',
'enum' => ':Attribute 值不正确。',
'exists' => ':Attribute 不存在。',
'file' => ':Attribute 必须是文件。',
'filled' => ':Attribute 不能为空。',
'gt' => [
'array' => ':Attribute 必须多于 :value 个元素。',
'file' => ':Attribute 必须大于 :value KB。',
'numeric' => ':Attribute 必须大于 :value。',
'string' => ':Attribute 必须多于 :value 个字符。',
],
'gte' => [
'array' => ':Attribute 必须多于或等于 :value 个元素。',
'file' => ':Attribute 必须大于或等于 :value KB。',
'numeric' => ':Attribute 必须大于或等于 :value。',
'string' => ':Attribute 必须多于或等于 :value 个字符。',
],
'image' => ':Attribute 必须是图片。',
'in' => '已选的属性 :attribute 无效。',
'in_array' => ':Attribute 必须在 :other 中。',
'integer' => ':Attribute 必须是整数。',
'ip' => ':Attribute 必须是有效的 IP 地址。',
'ipv4' => ':Attribute 必须是有效的 IPv4 地址。',
'ipv6' => ':Attribute 必须是有效的 IPv6 地址。',
'json' => ':Attribute 必须是正确的 JSON 格式。',
'lowercase' => ':Attribute 必须小写。',
'lt' => [
'array' => ':Attribute 必须少于 :value 个元素。',
'file' => ':Attribute 必须小于 :value KB。',
'numeric' => ':Attribute 必须小于 :value。',
'string' => ':Attribute 必须少于 :value 个字符。',
],
'lte' => [
'array' => ':Attribute 必须少于或等于 :value 个元素。',
'file' => ':Attribute 必须小于或等于 :value KB。',
'numeric' => ':Attribute 必须小于或等于 :value。',
'string' => ':Attribute 必须少于或等于 :value 个字符。',
],
'mac_address' => ':Attribute 必须是一个有效的 MAC 地址。',
'max' => [
'array' => ':Attribute 最多只有 :max 个单元。',
'file' => ':Attribute 不能大于 :max KB。',
'numeric' => ':Attribute 不能大于 :max。',
'string' => ':Attribute 不能大于 :max 个字符。',
],
'max_digits' => ':Attribute 不能超过 :max 位数。',
'mimes' => ':Attribute 必须是一个 :values 类型的文件。',
'mimetypes' => ':Attribute 必须是一个 :values 类型的文件。',
'min' => [
'array' => ':Attribute 至少有 :min 个单元。',
'file' => ':Attribute 大小不能小于 :min KB。',
'numeric' => ':Attribute 必须大于等于 :min。',
'string' => ':Attribute 至少为 :min 个字符。',
],
'min_digits' => ':Attribute 必须至少有 :min 位数。',
'missing' => '必须缺少 :attribute 字段。',
'missing_if' => '当 :other 为 :value 时,必须缺少 :attribute 字段。',
'missing_unless' => '必须缺少 :attribute 字段,除非 :other 是 :value。',
'missing_with' => '存在 :values 时,必须缺少 :attribute 字段。',
'missing_with_all' => '存在 :values 时,必须缺少 :attribute 字段。',
'multiple_of' => ':Attribute 必须是 :value 中的多个值。',
'not_in' => '已选的属性 :attribute 非法。',
'not_regex' => ':Attribute 的格式错误。',
'numeric' => ':Attribute 必须是一个数字。',
'password' => [
'letters' => ':Attribute 必须至少包含一个字母。',
'mixed' => ':Attribute 必须至少包含一个大写字母和一个小写字母。',
'numbers' => ':Attribute 必须至少包含一个数字。',
'symbols' => ':Attribute 必须至少包含一个符号。',
'uncompromised' => '给定的 :attribute 出现在已经泄漏的密码中。请选择不同的 :attribute。',
],
'present' => ':Attribute 必须存在。',
'prohibited' => ':Attribute 字段被禁止。',
'prohibited_if' => '当 :other 为 :value 时,禁止 :attribute 字段。',
'prohibited_unless' => ':Attribute 字段被禁止,除非 :other 位于 :values 中。',
'prohibits' => ':Attribute 字段禁止出现 :other。',
'regex' => ':Attribute 格式不正确。',
'required' => ':Attribute 不能为空。',
'required_array_keys' => ':Attribute 至少包含指定的键::values.',
'required_if' => '当 :other 为 :value 时 :attribute 不能为空。',
'required_if_accepted' => '当 :other 存在时,:attribute 不能为空。',
'required_unless' => '当 :other 不为 :values 时 :attribute 不能为空。',
'required_with' => '当 :values 存在时 :attribute 不能为空。',
'required_with_all' => '当 :values 存在时 :attribute 不能为空。',
'required_without' => '当 :values 不存在时 :attribute 不能为空。',
'required_without_all' => '当 :values 都不存在时 :attribute 不能为空。',
'same' => ':Attribute 和 :other 必须相同。',
'size' => [
'array' => ':Attribute 必须为 :size 个单元。',
'file' => ':Attribute 大小必须为 :size KB。',
'numeric' => ':Attribute 大小必须为 :size。',
'string' => ':Attribute 必须是 :size 个字符。',
],
'starts_with' => ':Attribute 必须以 :values 为开头。',
'string' => ':Attribute 必须是一个字符串。',
'timezone' => ':Attribute 必须是一个合法的时区值。',
'ulid' => ':Attribute 必须是有效的 ULID。',
'unique' => ':Attribute 已经存在。',
'uploaded' => ':Attribute 上传失败。',
'uppercase' => ':Attribute 必须大写',
'url' => ':Attribute 格式不正确。',
'uuid' => ':Attribute 必须是有效的 UUID。',
'attributes' => [
'address' => '地址',
'age' => '年龄',
'amount' => '数额',
'area' => '区域',
'available' => '可用的',
'birthday' => '生日',
'body' => '身体',
'city' => '城市',
'content' => '内容',
'country' => '国家',
'created_at' => '创建于',
'creator' => '创建者',
'current_password' => '当前密码',
'date' => '日期',
'date_of_birth' => '出生日期',
'day' => '天',
'deleted_at' => '删除于',
'description' => '描述',
'district' => '地区',
'duration' => '期间',
'email' => '邮箱',
'excerpt' => '摘要',
'filter' => '过滤',
'first_name' => '名',
'gender' => '性别',
'group' => '组',
'hour' => '时',
'image' => '图像',
'last_name' => '姓',
'lesson' => '课程',
'line_address_1' => '线路地址 1',
'line_address_2' => '线路地址 2',
'message' => '信息',
'middle_name' => '中间名字',
'minute' => '分',
'mobile' => '手机',
'month' => '月',
'name' => '名称',
'national_code' => '国家代码',
'number' => '数字',
'password' => '密码',
'password_confirmation' => '确认密码',
'phone' => '电话',
'photo' => '照片',
'postal_code' => '邮政编码',
'price' => '价格',
'province' => '省',
'recaptcha_response_field' => '重复验证码响应字段',
'remember' => '记住',
'restored_at' => '恢复于',
'result_text_under_image' => '图像下的结果文本',
'role' => '角色',
'second' => '秒',
'sex' => '性别',
'short_text' => '短文本',
'size' => '大小',
'state' => '状态',
'street' => '街道',
'student' => '学生',
'subject' => '主题',
'teacher' => '教师',
'terms' => '条款',
'test_description' => '测试说明',
'test_locale' => '测试语言环境',
'test_name' => '测试名称',
'text' => '文本',
'time' => '时间',
'title' => '标题',
'updated_at' => '更新于',
'username' => '用户名',
'year' => '年',
],
'phone' => '不是一个有效的手机号',
];

View File

@ -11,7 +11,7 @@ return [
'subject_data' => '基本信息',
'check_user_id' => '实际审核人',
'checked_at' => '审核时间',
'remarks' => '未通过原因',
'remarks' => '备注',
'check_status' => '审核状态',
'sort' => '顺序号',
];