From fbcfef4ff00f7ae6d75da9ed27aad1b4afa69226 Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Fri, 14 Mar 2025 09:27:29 +0800 Subject: [PATCH] =?UTF-8?q?OA=E5=AE=A1=E6=A0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/controller/Approval.php | 93 ++++++++++ .../src/controller/Ticket.php | 166 +++++++++++++++++- .../src/model/ApprovalInstance.php | 53 ++++++ .../src/model/ApprovalLog.php | 46 +++++ .../src/model/ApprovalProcess.php | 34 ++++ .../src/model/ApprovalStep.php | 46 +++++ .../src/model/TicketTicket.php | 5 + .../src/view/approval/form.html | 133 ++++++++++++++ .../src/view/approval/index.html | 51 ++++++ .../src/view/approval/index_search.html | 16 ++ .../src/view/ticket/approve.html | 104 +++++++++++ .../src/view/ticket/index.html | 26 ++- 12 files changed, 768 insertions(+), 5 deletions(-) create mode 100644 plugs/think-plugs-ticket/src/controller/Approval.php create mode 100644 plugs/think-plugs-ticket/src/model/ApprovalInstance.php create mode 100644 plugs/think-plugs-ticket/src/model/ApprovalLog.php create mode 100644 plugs/think-plugs-ticket/src/model/ApprovalProcess.php create mode 100644 plugs/think-plugs-ticket/src/model/ApprovalStep.php create mode 100644 plugs/think-plugs-ticket/src/view/approval/form.html create mode 100644 plugs/think-plugs-ticket/src/view/approval/index.html create mode 100644 plugs/think-plugs-ticket/src/view/approval/index_search.html create mode 100644 plugs/think-plugs-ticket/src/view/ticket/approve.html diff --git a/plugs/think-plugs-ticket/src/controller/Approval.php b/plugs/think-plugs-ticket/src/controller/Approval.php new file mode 100644 index 0000000..f44c266 --- /dev/null +++ b/plugs/think-plugs-ticket/src/controller/Approval.php @@ -0,0 +1,93 @@ +title = '审批流程管理'; + ApprovalProcess::mQuery()->layTable(function () { + $this->types = [ + 0 => '待提交', + 1 => '进行中', + 2 => '已通过', + 3 => '已驳回', + 4 => '已取消' + ]; + }, function (QueryHelper $query) { + $query->like('name')->equal('status'); + $query->dateBetween('create_time'); + }); + } + + /** + * 添加审批流程 + * @auth true + * @menu true + */ + public function add() + { + $this->title = '添加审批流程'; + $this->users = SystemUser::query()->field('id,username,nickname')->select(); + ApprovalProcess::mForm('form'); + } + + /** + * 编辑审批流程 + * @auth true + * @menu true + */ + public function edit() + { + $this->title = '编辑审批流程'; + $this->id = $this->request->param('id'); + $this->users = SystemUser::query()->field('id,username,nickname')->select(); + ApprovalProcess::mForm('form', 'id'); + } + + /** + * 删除审批流程 + * @auth true + * @menu true + */ + public function remove() + { + ApprovalProcess::mDelete('id'); + } + + /** + * 表单数据处理 + * @param array $data + */ + protected function _form_filter(array &$data) + { + if ($this->request->isPost()) { + // 解析步骤数据 + $steps = json_decode($data['steps'], true); + foreach ($steps as &$step) { + $step['approver_type'] = intval($step['approver_type']); + } + $data['steps'] = json_encode($steps); + // 检查是否存在相同类型的审批流程,排除当前编辑的记录 + $type = $this->request->post('type'); + $id = $this->request->post('id'); + if (ApprovalProcess::where('type', $type)->where('id', '<>', $id)->find()) { + $this->error('该类型的审批流程已经存在'); + } + } + } +} \ No newline at end of file diff --git a/plugs/think-plugs-ticket/src/controller/Ticket.php b/plugs/think-plugs-ticket/src/controller/Ticket.php index 99ebc45..7edc50b 100644 --- a/plugs/think-plugs-ticket/src/controller/Ticket.php +++ b/plugs/think-plugs-ticket/src/controller/Ticket.php @@ -3,6 +3,9 @@ namespace plugin\ticket\controller; use plugin\inspection\model\InspectionStaff; +use plugin\ticket\model\ApprovalInstance; +use plugin\ticket\model\ApprovalProcess; +use plugin\ticket\model\ApprovalStep; use plugin\ticket\model\TicketDept; use plugin\ticket\model\TicketReply; use plugin\ticket\model\TicketTicket; @@ -10,6 +13,7 @@ use plugin\ticket\model\TicketType; use think\admin\Controller; use think\admin\helper\QueryHelper; use think\admin\model\SystemUser; +use think\exception\HttpResponseException; /** * 工单管理 @@ -36,7 +40,7 @@ class Ticket extends Controller $query->like(['title|content|contact_name|ticket_address|contact_phone#keyword']) ->dateBetween(['create_at']) ->equal(['status', 'type_id']); - $query->append(['imgs_arr', 'source_type_name', 'status_text', 'type_name', 'last_reply']); + $query->append(['imgs_arr', 'source_type_name', 'status_text', 'type_name', 'last_reply'])->with('approval'); }); } @@ -61,7 +65,8 @@ class Ticket extends Controller if ($this->request->isPost()) { $data['user_id'] = 0; } - $data['status'] = 0; + ApprovalInstance::query()->where('oid', '=', $data['id'])->delete(); + $data['status'] = -1; } /** @@ -90,6 +95,7 @@ class Ticket extends Controller public function edit() { $this->title = '编辑工单'; + $this->id = $this->request->get('id'); $this->types = TicketType::mk()->scope('active')->select(); TicketTicket::mForm('form'); } @@ -162,4 +168,160 @@ class Ticket extends Controller $this->fetch(); } } + + /** + * 审核页面 + * @auth true + * @menu true + */ + public function approve() + { + $this->title = '审核流程'; + [ + 'id'=>$id + ] = $this->_vali([ + 'id.require'=>'请指定回复ID!' + ]); + $this->vo = TicketTicket::query()->with(['user', 'type'])->append(['imgs_arr', 'status_text', 'type_name'])->find($id); + $process = ApprovalProcess::where('type', '=', 'GDSH')->order('id', 'asc')->findOrEmpty(); + if ($process->isEmpty()) { + $this->error('未找到可用的审核流程'); + } + $this->process = $process; + $instance = ApprovalInstance::query()->with(['steps', 'logs'])->where('process_id', '=', $process->id)->where('oid', '=', $id)->findOrEmpty(); + $this->instance = $instance; + if ($instance->isEmpty()) { + $this->step_index = -1; + $this->current_step = $process->steps[0]; + } else { + $this->step_index = $instance->current_step; + if (sizeof($instance->steps) <= ($instance->current_step + 1)) { + $this->current_step = ['approver_type' => 0]; + } else { + $this->current_step = $instance->steps[$instance->current_step + 1]; + } + } + $this->users = SystemUser::query()->field('id,username,nickname')->select(); + $this->fetch(); + } + + public function create_approval() + { + $data = $this->_vali([ + 'id.require'=>'请指定工单ID!', + 'title.default'=>'工单审核', + 'content.default'=>'', + ]); + $process = ApprovalProcess::where('type', '=', 'GDSH')->order('id', 'asc')->findOrEmpty(); + if ($process->isEmpty()) { + $this->error('未找到可用的审核流程'); + } + $adminInfo = $this->request->session('user'); + ApprovalInstance::mk()->startTrans(); + try { + $instance = ApprovalInstance::create([ + 'process_id' => $process->id, + 'oid' => $data['id'], + 'title' => $data['title'], + 'content' => $data['content'], + 'status' => 0, + 'current_step' => 0, + 'create_time' => date('Y-m-d H:i:s'), + 'create_by' => $adminInfo['id'], + 'create_name' => $adminInfo['username'], + ]); + foreach ($process->steps as $index => $step) { + $approver_id = $step['approver_id'] ?? 0; + if ($index == 0) { + if ($step['approver_type'] == 3) { + $approve_data = $this->_vali([ + 'approver_id.require' => '请指定审核人!', + ]); + $approver_id = $approve_data['approver_id']; + } + } + ApprovalStep::create([ + 'instance_id' => $instance->id, + 'step_number' => $index, + 'approver_type' => $step['approver_type'], + 'approver_id' => $approver_id, + 'status' => 0, + ]); + } + ApprovalInstance::mk()->commit(); + } catch (HttpResponseException $e) { + ApprovalInstance::mk()->rollback(); + throw $e; + } catch (\Exception $e) { + ApprovalInstance::mk()->rollback(); +// $this->error("创建失败"); + throw $e; + } + $this->success('创建成功!'); + } + + public function do_approve() + { + $data = $this->_vali([ + 'id.require'=>'请指定工单ID!', + 'instance_id.require'=>'请指定当前审核ID!', + 'step_index.require'=>'请指定当前步骤!', + 'status.require'=>'请指定审核结果!', + 'content.default'=>'', + ]); + $ticket = TicketTicket::query()->findOrEmpty($data['id']); + if ($ticket->isEmpty()) { + $this->error('工单不存在!'); + } + $adminInfo = $this->request->session('user'); + $instance = ApprovalInstance::query()->with('steps')->findOrEmpty($data['instance_id']); + if ($instance->isEmpty()) { + $this->error('审核流程不存在!'); + } + if ($instance->status == 1) { + $this->error('工单已通过,请勿重复操作!'); + } else if ($instance->status == 2) { + $this->error('工单已驳回,请勿重复操作!'); + } + if ($instance->current_step != $data['step_index']) { + $this->error('当前步骤不正确!'); + } + if ($instance->current->approver_id != $adminInfo['id']) { + $this->error('您不是当前审核人,请勿操作!'); + } + ApprovalInstance::mk()->startTrans(); + try { + $instance->current->status = $data['status']; + $instance->current->content = $data['content']; + $instance->current->save(); + if ($data['status'] == 2) { + $instance->status = 2; + } else { + $instance->current_step++; + if ($instance->current_step >= count($instance->steps)) { + $instance->status = 1; + $ticket->status = 0; + } else { + $step = $instance->steps[$instance->current_step]; + if ($step['approver_type'] == 3) { + $approve_data = $this->_vali([ + 'approver_id.require' => '请指定审核人!', + ]); + $step->approver_id = $approve_data['approver_id']; + $step->save(); + } + } + } + $instance->save(); + ApprovalInstance::mk()->commit(); + } catch (HttpResponseException $e) { + ApprovalInstance::mk()->rollback(); + throw $e; + } catch (\Exception $e) { + ApprovalInstance::mk()->rollback(); +// $this->error("审核失败"); + throw $e; + } + $this->success('审核成功!'); + } } \ No newline at end of file diff --git a/plugs/think-plugs-ticket/src/model/ApprovalInstance.php b/plugs/think-plugs-ticket/src/model/ApprovalInstance.php new file mode 100644 index 0000000..791872c --- /dev/null +++ b/plugs/think-plugs-ticket/src/model/ApprovalInstance.php @@ -0,0 +1,53 @@ +belongsTo(ApprovalProcess::class, 'process_id', 'id'); + } + + // 关联审批步骤 + public function steps() + { + return $this->hasMany(ApprovalStep::class, 'instance_id', 'id'); + } + + public function getCurrentAttr($value, $data) + { + return $this->steps[$data['current_step']] ?? []; + } + + // 关联审批日志 + public function logs() + { + return $this->hasMany(ApprovalLog::class, 'instance_id', 'id'); + } + + // 格式化流程状态 + public function getStatusTextAttr($value, $data) + { + $statusMap = [ + 0 => '待提交', + 1 => '进行中', + 2 => '已通过', + 3 => '已驳回', + 4 => '已取消' + ]; + return $statusMap[$data['status']] ?? '未知'; + } +} \ No newline at end of file diff --git a/plugs/think-plugs-ticket/src/model/ApprovalLog.php b/plugs/think-plugs-ticket/src/model/ApprovalLog.php new file mode 100644 index 0000000..0ff7b9c --- /dev/null +++ b/plugs/think-plugs-ticket/src/model/ApprovalLog.php @@ -0,0 +1,46 @@ +belongsTo(ApprovalInstance::class, 'instance_id', 'id'); + } + + // 关联审批步骤 + public function step() + { + return $this->belongsTo(ApprovalStep::class, 'step_id', 'id'); + } + + // 关联操作用户(示例:关联现有用户表) + public function operator() + { + return $this->belongsTo(SystemUser::class, 'user_id', 'id'); + } + + // 格式化操作类型 + public function getActionTextAttr($value, $data) + { + $actionMap = [ + 'approve' => '审批通过', + 'reject' => '驳回', + 'transfer' => '转交审批' + ]; + return $actionMap[$data['action']] ?? '未知操作'; + } +} \ No newline at end of file diff --git a/plugs/think-plugs-ticket/src/model/ApprovalProcess.php b/plugs/think-plugs-ticket/src/model/ApprovalProcess.php new file mode 100644 index 0000000..1007dd2 --- /dev/null +++ b/plugs/think-plugs-ticket/src/model/ApprovalProcess.php @@ -0,0 +1,34 @@ +hasMany(ApprovalInstance::class, 'process_id', 'id'); + } + + // 过滤有效流程 + public function scopeAvail($query) + { + return $query->where('status', 1); + } + + // 流程步骤解析 + public function getStepsAttr($value) + { + return json_decode($value, true); + } +} \ No newline at end of file diff --git a/plugs/think-plugs-ticket/src/model/ApprovalStep.php b/plugs/think-plugs-ticket/src/model/ApprovalStep.php new file mode 100644 index 0000000..77981a7 --- /dev/null +++ b/plugs/think-plugs-ticket/src/model/ApprovalStep.php @@ -0,0 +1,46 @@ +belongsTo(ApprovalInstance::class, 'instance_id', 'id'); + } + + // 关联审批人(示例:关联现有用户表) + public function approver() + { + return $this->belongsTo(SystemUser::class, 'approver_id', 'id'); + } + + // 格式化审批类型 + public function getApproverTypeTextAttr($value, $data) + { + $typeMap = [ + 0 => '指定用户', +// 1 => '指定部门', +// 2 => '角色审批' + ]; + return $typeMap[$data['approver_type']] ?? '未知'; + } + + // 校验步骤有效性 + public function scopeAvail($query) + { + return $query->where('status', 0); + } +} \ No newline at end of file diff --git a/plugs/think-plugs-ticket/src/model/TicketTicket.php b/plugs/think-plugs-ticket/src/model/TicketTicket.php index 0da2d5e..b7251f2 100644 --- a/plugs/think-plugs-ticket/src/model/TicketTicket.php +++ b/plugs/think-plugs-ticket/src/model/TicketTicket.php @@ -15,6 +15,11 @@ class TicketTicket extends Model return $this->belongsTo(TicketType::class, 'type_id'); } + public function approval() + { + return $this->belongsTo(ApprovalInstance::class, 'id', 'oid'); + } + public function user() { return $this->morphTo('user'); diff --git a/plugs/think-plugs-ticket/src/view/approval/form.html b/plugs/think-plugs-ticket/src/view/approval/form.html new file mode 100644 index 0000000..2e02e72 --- /dev/null +++ b/plugs/think-plugs-ticket/src/view/approval/form.html @@ -0,0 +1,133 @@ +
+
+
+ +
+ +
+
+ +
+ +
+ +
+
+
+ +
+
+ +
+
+ + {notempty name='vo.id'}{/notempty} +
+
+ + +
+
+ + + + + + diff --git a/plugs/think-plugs-ticket/src/view/approval/index.html b/plugs/think-plugs-ticket/src/view/approval/index.html new file mode 100644 index 0000000..337f34b --- /dev/null +++ b/plugs/think-plugs-ticket/src/view/approval/index.html @@ -0,0 +1,51 @@ +{extend name="table"} + +{block name="button"} + +添加流程 + +{/block} + +{block name="content"} +
+
+
+ {include file='approval/index_search'} +
+
+
+
+ + +{/block} + + +{block name='style'} + +{/block} + +{block name='script'} + +{/block} \ No newline at end of file diff --git a/plugs/think-plugs-ticket/src/view/approval/index_search.html b/plugs/think-plugs-ticket/src/view/approval/index_search.html new file mode 100644 index 0000000..698e903 --- /dev/null +++ b/plugs/think-plugs-ticket/src/view/approval/index_search.html @@ -0,0 +1,16 @@ +
+ 条件搜索 + + +
diff --git a/plugs/think-plugs-ticket/src/view/ticket/approve.html b/plugs/think-plugs-ticket/src/view/ticket/approve.html new file mode 100644 index 0000000..dce9c04 --- /dev/null +++ b/plugs/think-plugs-ticket/src/view/ticket/approve.html @@ -0,0 +1,104 @@ +
+
+
审核流程
+
+
+
+ +
+

提交审核

+
+
+ {foreach $process.steps as $index=>$step} +
+ +
+

第{$index+1}步{if $step_index == $index}(当前步骤){/if}

+

+ {$step.title} +

+
+
+ {/foreach} +
+
+
+
+{if $instance->isEmpty()} +
+
创建审核单
+
+
+ +
+ +
+ +
+
+ {if $current_step.approver_type == 3} +
+ +
+ +
+
+ {/if} +
+
+ + +
+
+
+
+
+{else} +
+
工单审核
+
+
+ + + +
+ +
+ + +
+
+
+ +
+ +
+
+ {if $current_step.approver_type == 3} +
+ +
+ +
+
+ {/if} +
+
+ + +
+
+
+
+
+{/if} \ No newline at end of file diff --git a/plugs/think-plugs-ticket/src/view/ticket/index.html b/plugs/think-plugs-ticket/src/view/ticket/index.html index 9ca4e43..bdd4430 100644 --- a/plugs/think-plugs-ticket/src/view/ticket/index.html +++ b/plugs/think-plugs-ticket/src/view/ticket/index.html @@ -22,12 +22,25 @@ 详情 + {{# if (d.status == 0) { }} 分配 + {{# } }} + {{# if (d.status == -1) { }} + + {{# if (d.approval == null) { }} + 审核 + {{# } else if (d.approval.status == 0 && d.approval.current.approver_id == {$user_id}) { }} + 去审核 + {{# } }} + {{# } }} + + {{# if (d.approval == null || d.approval.status != 1) { }} 修改 + {{# } }} {/block} @@ -66,11 +79,18 @@ } }}, {field:'status', title:'状态', width:80, templet:function(item){ - if(item.status == 0){ - return '正在处理'; + if (item.approval != null) { + if (item.approval.status != 1) { + return item.approval.status == 2 ? '审核不通过' : '审核中'; + } + } + if(item.status < 0){ + return '待提交审核'; + }else if(item.status == 0){ + return '待分配'; }else if(item.status == 1){ return '已处理'; - }else{ + }else if(item.status == 2){ return '已关闭'; } }},