智慧教务系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

421 lines
15 KiB

<?php
declare(strict_types=1);
namespace app\service\school_approval;
use app\model\personnel\Personnel;
use app\model\school_approval\SchoolApprovalConfig;
use app\model\school_approval\SchoolApprovalConfigNode;
use app\model\school_approval\SchoolApprovalParticipants;
use app\model\school_approval\SchoolApprovalProcess;
use think\Exception;
use think\facade\Db;
/**
* 审批流程服务
* Class SchoolApprovalProcessService
* @package app\service\school_approval
*/
class SchoolApprovalProcessService
{
/**
* 获取审批流程列表
* @param array $where
* @param int $page
* @param int $limit
* @return array
*/
public function getList(array $where = [], int $page = 1, int $limit = 10): array
{
$field = 'a.*,b.name as applicant_name,c.name as current_approver_name';
$order = 'a.id desc';
$list = (new SchoolApprovalProcess())
->alias("a")
->join(['school_personnel' => 'b'],'a.applicant_id = b.id','left')
->join(['school_personnel' => 'c'],'a.current_approver_id = c.id','left')
->where($where)
->field($field)
->order($order)
->page($page, $limit)
->select()
->toArray();
$count = (new SchoolApprovalProcess())->where($where)->count();
return [
'list' => $list,
'count' => $count
];
}
/**
* 获取审批流程详情
* @param int $id
* @return array
*/
public function getInfo(int $id): array
{
$info = (new SchoolApprovalProcess())
->alias("a")
->join(['school_personnel' => 'b'],'a.applicant_id = b.id','left')
->join(['school_personnel' => 'c'],'a.current_approver_id = c.id','left')
->with(['participants'])
->where(['a.id' => $id])
->field('a.*,b.name as applicant_name,c.name as current_approver_name')
->find();
if (empty($info)) {
return [];
}
$info = $info->toArray();
$Personnel = new Personnel();
foreach ($info['participants'] as $key => $value) {
$info['participants'][$key]['name'] = $Personnel->where(['id' => $value['participant_id']])->value('name');
}
return $info;
}
/**
* 创建审批流程
* @param array $data
* @param int $config_id 审批配置ID
* @return int
* @throws \Exception
*/
public function create(array $data, int $config_id): int
{
Db::startTrans();
try {
// 获取审批配置详情
$config_info = (new SchoolApprovalConfigService())->getInfo($config_id);
if (empty($config_info)) {
throw new Exception('审批配置不存在');
}
// 创建审批流程
$process = [
'process_name' => $data['process_name'],
'applicant_id' => $data['applicant_id'],
'application_time' => date("Y-m-d H:i:s"),
'current_approver_id' => 0, // 初始时为0,后面会更新
'approval_status' => SchoolApprovalProcess::STATUS_PENDING,
'remarks' => $data['remarks'] ?? '',
'business_type' => $data['business_type'] ?? '',
'business_id' => $data['business_id'] ?? 0,
'business_data' => isset($data['business_data']) ? json_encode($data['business_data']) : ''
];
$process_id = (new SchoolApprovalProcess())->insertGetId($process);
// 创建审批参与人
$participants = [];
foreach ($config_info['nodes'] as $sequence => $node) {
$approver_ids = explode(',', $node['approver_ids']);
foreach ($approver_ids as $approver_id) {
$participants[] = [
'process_id' => $process_id,
'participant_id' => $approver_id,
'sequence' => $node['sequence'],
'status' => SchoolApprovalParticipants::STATUS_PENDING,
'sign_type' => $node['sign_type']
];
}
}
if (!empty($participants)) {
(new SchoolApprovalParticipants())->insertAll($participants);
// 更新当前审批人为第一个审批人
$first_participant = (new SchoolApprovalParticipants())
->where(['process_id' => $process_id])
->order('sequence', 'asc')
->find();
if (!empty($first_participant)) {
(new SchoolApprovalProcess())->where(['id' => $process_id])
->update(['current_approver_id' => $first_participant['participant_id']]);
}
}
Db::commit();
return $process_id;
} catch (\Exception $e) {
Db::rollback();
throw new Exception($e->getMessage());
}
}
/**
* 创建人员添加审批流程
* @param array $personnelData 人员数据
* @param int $applicantId 申请人ID
* @param int $configId 审批配置ID
* @return int
* @throws \Exception
*/
public function createPersonnelApproval(array $personnelData, int $applicantId, int $configId): int
{
// 创建审批流程数据
$processData = [
'process_name' => '人员添加申请 - ' . $personnelData['name'],
'applicant_id' => $applicantId,
'remarks' => '申请添加新员工:' . $personnelData['name'] . ',职位:' . ($personnelData['position'] ?? '未指定'),
'business_type' => 'personnel_add',
'business_id' => 0, // 暂时为0,等人员创建后更新
'business_data' => $personnelData
];
return $this->create($processData, $configId);
}
/**
* 审批
* @param int $process_id 流程ID
* @param int $approver_id 审批人ID
* @param string $status 审批状态
* @param string $remarks 备注
* @return bool
* @throws \Exception
*/
public function approve(int $process_id, int $approver_id, string $status, string $remarks = ''): bool
{
Db::startTrans();
try {
// 获取审批流程
$process_info = (new SchoolApprovalProcess())->where(['id' => $process_id])->find();
if (empty($process_info)) {
throw new Exception('审批流程不存在');
}
// 检查是否当前审批人
if ($process_info['current_approver_id'] != $approver_id) {
throw new Exception('您不是当前审批人');
}
// 检查流程状态
if ($process_info['approval_status'] != SchoolApprovalProcess::STATUS_PENDING) {
throw new Exception('该审批流程已完成');
}
// 获取当前审批节点
$current_participant = (new SchoolApprovalParticipants())
->where([
'process_id' => $process_id,
'participant_id' => $approver_id,
'status' => SchoolApprovalParticipants::STATUS_PENDING
])
->find();
if (empty($current_participant)) {
throw new Exception('审批节点信息错误');
}
// 更新当前审批人状态
(new SchoolApprovalParticipants())->where(['id' => $current_participant['id']])
->update([
'status' => $status,
'remarks' => $remarks
]);
// 如果拒绝,直接更新整个流程状态为拒绝
if ($status == SchoolApprovalParticipants::STATUS_REJECTED) {
(new SchoolApprovalProcess())->where(['id' => $process_id])
->update([
'approval_status' => SchoolApprovalProcess::STATUS_REJECTED,
'approval_time' => time(),
'remarks' => $remarks
]);
// 处理拒绝后的业务逻辑
$this->handleApprovalRejected($process_id);
Db::commit();
return true;
}
// 检查当前节点是否需要会签
$same_sequence_participants = (new SchoolApprovalParticipants())
->where([
'process_id' => $process_id,
'sequence' => $current_participant['sequence'],
'status' => SchoolApprovalParticipants::STATUS_PENDING
])
->select();
// 如果是会签且还有其他人未审批,则等待
if ($current_participant['sign_type'] == SchoolApprovalParticipants::SIGN_TYPE_AND && !$same_sequence_participants->isEmpty()) {
// 不做任何处理,等待其他人审批
Db::commit();
return true;
}
// 获取下一个审批节点
$next_participant = (new SchoolApprovalParticipants())
->where([
'process_id' => $process_id,
'status' => SchoolApprovalParticipants::STATUS_PENDING
])
->order('sequence', 'asc')
->find();
if (empty($next_participant)) {
// 没有下一个审批人,流程结束,标记为已通过
(new SchoolApprovalProcess())->where(['id' => $process_id])
->update([
'approval_status' => SchoolApprovalProcess::STATUS_APPROVED,
'approval_time' => time()
]);
// 处理业务逻辑
$this->handleApprovalCompleted($process_id);
} else {
// 更新当前审批人为下一个审批人
(new SchoolApprovalProcess())->where(['id' => $process_id])
->update(['current_approver_id' => $next_participant['participant_id']]);
}
Db::commit();
return true;
} catch (\Exception $e) {
Db::rollback();
throw new Exception($e->getMessage());
}
}
/**
* 撤销审批流程
* @param int $process_id 流程ID
* @param int $applicant_id 申请人ID
* @return bool
* @throws \Exception
*/
public function cancel(int $process_id, int $applicant_id): bool
{
Db::startTrans();
try {
// 获取审批流程
$process_info = (new SchoolApprovalProcess())->where(['id' => $process_id])->find();
if (empty($process_info)) {
throw new Exception('审批流程不存在');
}
// 检查是否申请人
if ($process_info['applicant_id'] != $applicant_id) {
throw new Exception('您不是该流程的申请人');
}
// 检查流程状态
if ($process_info['approval_status'] != SchoolApprovalProcess::STATUS_PENDING) {
throw new Exception('该审批流程已完成,无法撤销');
}
// 更新流程状态为已拒绝(撤销)
(new SchoolApprovalProcess())->where(['id' => $process_id])
->update([
'approval_status' => SchoolApprovalProcess::STATUS_REJECTED,
'approval_time' => time(),
'remarks' => '申请人撤销'
]);
// 更新所有待审批节点为已拒绝
(new SchoolApprovalParticipants())->where([
'process_id' => $process_id,
'status' => SchoolApprovalParticipants::STATUS_PENDING
])->update([
'status' => SchoolApprovalParticipants::STATUS_REJECTED,
'remarks' => '申请人撤销'
]);
Db::commit();
return true;
} catch (\Exception $e) {
Db::rollback();
throw new Exception($e->getMessage());
}
}
/**
* 处理审批完成后的业务逻辑
* @param int $process_id
* @throws \Exception
*/
private function handleApprovalCompleted(int $process_id): void
{
// 获取流程信息
$process = (new SchoolApprovalProcess())->where(['id' => $process_id])->find();
if (empty($process)) {
throw new Exception('流程信息不存在');
}
// 根据业务类型处理
switch ($process['business_type']) {
case 'personnel_add':
$this->handlePersonnelAddApproval($process);
break;
default:
// 其他业务类型的处理逻辑
break;
}
}
/**
* 处理人员添加审批完成
* @param $process
* @throws \Exception
*/
private function handlePersonnelAddApproval($process): void
{
if (empty($process['business_data'])) {
throw new Exception('人员数据不存在');
}
$personnelData = json_decode($process['business_data'], true);
if (empty($personnelData)) {
throw new Exception('人员数据格式错误');
}
try {
// 调用人员服务创建正式人员记录
$personnelService = new \app\service\admin\personnel\PersonnelService();
// 准备人员数据
$createData = $personnelData;
$createData['status'] = 1; // 设置为正常状态
// 创建人员记录
$personnelId = $personnelService->add($createData);
// 更新流程的business_id为实际创建的人员ID
(new SchoolApprovalProcess())->where(['id' => $process['id']])
->update(['business_id' => $personnelId]);
} catch (\Exception $e) {
throw new Exception('创建人员记录失败:' . $e->getMessage());
}
}
/**
* 处理审批拒绝后的业务逻辑
* @param int $process_id
* @throws \Exception
*/
private function handleApprovalRejected(int $process_id): void
{
// 获取流程信息
$process = (new SchoolApprovalProcess())->where(['id' => $process_id])->find();
if (empty($process)) {
return;
}
// 根据业务类型处理
switch ($process['business_type']) {
case 'personnel_add':
// 人员添加被拒绝,不需要特殊处理
break;
default:
// 其他业务类型的处理逻辑
break;
}
}
}