165 lines
6.8 KiB
PHP
165 lines
6.8 KiB
PHP
<?php
|
||
namespace app\common\utils\approval\traits;
|
||
|
||
use support\Db;
|
||
use support\Log;
|
||
|
||
trait ApprovalNotificationTrait
|
||
{
|
||
/** 发送通知 */
|
||
private function sendNotification(array $userIds, object $instance, string $action, bool $isCC, array $extra = []): void
|
||
{
|
||
$map = [
|
||
'pending' => '待审批',
|
||
'approve' => '已通过',
|
||
'reject' => '已拒绝',
|
||
'revoked' => '已撤回',
|
||
'voided' => '已作废',
|
||
];
|
||
$prefix = $isCC ? '【抄送】' : '【审批】';
|
||
$text = $map[$action] ?? $action;
|
||
|
||
// 业务标题/内容
|
||
$approvalType = array_flip(\app\common\service\SysDictService::pluckKeyValueByCode('approval_type'));
|
||
|
||
$flowTxt = $approvalType[$instance->flow_type] ?? (string)$instance->flow_type;
|
||
$title = $prefix.'审批通知';
|
||
$content = "{$prefix}你有一条审批 {$text}:类型 {$flowTxt},业务标识 {$instance->biz_id}";
|
||
|
||
switch ($instance->flow_type) {
|
||
case 'stock_orders':
|
||
// 备货单
|
||
$stockOrder = \app\common\model\StockOrders::find($instance->biz_id);
|
||
if ($stockOrder) {
|
||
$title = $prefix."备货单:{$stockOrder->order_no}";
|
||
$flowTxt = $approvalType[$instance->flow_type] ?? $instance->flow_type;
|
||
$content = "{$prefix}你有一条审批 {$text}:类型 {$flowTxt},业务单号 {$stockOrder->order_no}";
|
||
}
|
||
break;
|
||
case 'stock_orders_nullify':
|
||
// 备货单作废
|
||
$stockOrder = \app\common\model\StockOrders::find($instance->biz_id);
|
||
if ($stockOrder) {
|
||
$title = $prefix."备货单作废:{$stockOrder->order_no}";
|
||
$flowTxt = $approvalType[$instance->flow_type] ?? '备货单作废';
|
||
$content = "{$prefix}你有一条审批 {$text}:类型 {$flowTxt},业务单号 {$stockOrder->order_no}";
|
||
// 把作废原因附带展示更清晰(也可依赖 $extra['note'])
|
||
$fd = json_decode($instance->form_data ?? '{}', true) ?: [];
|
||
if (!empty($fd['_nullify_reason'])) {
|
||
$content .= ';原因:'.(function_exists('mb_strimwidth') ? mb_strimwidth($fd['_nullify_reason'], 0, 120, '...', 'UTF-8') : $fd['_nullify_reason']);
|
||
}
|
||
}
|
||
break;
|
||
case 'purchase_orders':
|
||
// 采购单
|
||
$purchaseOrder = \app\common\model\PurchaseOrders::find($instance->biz_id);
|
||
if ($purchaseOrder) {
|
||
$title = $prefix."采购单:{$purchaseOrder->order_no}";
|
||
$flowTxt = $approvalType[$instance->flow_type] ?? $instance->flow_type;
|
||
$content = "{$prefix}你有一条审批 {$text}:类型 {$flowTxt},业务单号 {$purchaseOrder->order_no}";
|
||
}
|
||
break;
|
||
case 'purchase_order':
|
||
// 采购单
|
||
break;
|
||
case 'inv_requisition':
|
||
// 备货单
|
||
$invRequisition = \app\common\model\InvRequisition::find($instance->biz_id);
|
||
if ($invRequisition) {
|
||
$title = $prefix."物品借用:{$invRequisition->order_no}";
|
||
$flowTxt = $approvalType[$instance->flow_type] ?? $instance->flow_type;
|
||
$content = "{$prefix}你有一条审批 {$text}:类型 {$flowTxt},业务单号 {$invRequisition->order_no}";
|
||
}
|
||
break;
|
||
}
|
||
|
||
// 附加说明(提交说明/申诉/讨论摘要)
|
||
$append = $extra['appeal'] ?? ($extra['note'] ?? null);
|
||
if ($append) {
|
||
if (function_exists('mb_strimwidth')) {
|
||
$append = mb_strimwidth($append, 0, 120, '...', 'UTF-8');
|
||
}
|
||
$content .= ";说明:{$append}";
|
||
}
|
||
|
||
noticePush([
|
||
'title' => $title,
|
||
'content' => $content,
|
||
'recipient' => $userIds,
|
||
'email' => 1,
|
||
]);
|
||
}
|
||
|
||
private function notifyInitiator(object $instance, string $result): void
|
||
{
|
||
$this->sendNotification([(int)$instance->initiator_id], $instance, $result, false);
|
||
}
|
||
|
||
/** WebSocket:把一组用户的“待办数量”推送给前端(旧版) */
|
||
private function pushTodoChanged22(array $userIds): void
|
||
{
|
||
$userIds = array_values(array_unique(array_map('intval', $userIds)));
|
||
if (empty($userIds)) return;
|
||
|
||
// 统计这些用户当前的待办数量(以 approval_records.status = 'pending' 为准)
|
||
$rows = Db::table('approval_records')
|
||
->whereIn('approver_id', $userIds)
|
||
->where('status', 'pending')
|
||
->groupBy('approver_id')
|
||
->select('approver_id', Db::raw('COUNT(*) as cnt'))
|
||
->get();
|
||
|
||
// 默认都置 0,再填充真实值
|
||
$payload = array_fill_keys($userIds, 0);
|
||
foreach ($rows as $r) {
|
||
$payload[(int)$r->approver_id] = (int)$r->cnt;
|
||
}
|
||
|
||
try {
|
||
foreach ($payload as $uid => $cnt) {
|
||
$data = [
|
||
'event' => 'approval.todo.counts',
|
||
'user_id' => $uid,
|
||
'num' => $cnt,
|
||
];
|
||
\Webman\RedisQueue\Redis::send('ws-msg', $data);
|
||
}
|
||
} catch (\Throwable $e) {
|
||
Log::error('ws todo push error: '.$e->getMessage());
|
||
}
|
||
}
|
||
|
||
/** WebSocket:把一组用户的“待办数量”推送给前端(统一口径) */
|
||
private function pushTodoChanged(array $userIds): void
|
||
{
|
||
$userIds = array_values(array_unique(array_map('intval', $userIds)));
|
||
if (empty($userIds)) return;
|
||
|
||
// 只统计:实例进行中 + 当前轮次 + 当前步骤 的 pending
|
||
$rows = Db::table('approval_records as ar')
|
||
->join('approval_instances as ai', 'ai.id', '=', 'ar.instance_id')
|
||
->whereIn('ar.approver_id', $userIds)
|
||
->where('ar.status', 'pending')
|
||
->where('ai.status', 'processing')
|
||
->whereRaw('ar.round = ai.round')
|
||
->whereRaw('ar.step_index = ai.current_step')
|
||
->groupBy('ar.approver_id')
|
||
->select('ar.approver_id', Db::raw('COUNT(*) as cnt'))
|
||
->get();
|
||
|
||
// 默认置 0,再填充真实值
|
||
$payload = array_fill_keys($userIds, 0);
|
||
foreach ($rows as $r) {
|
||
$payload[(int)$r->approver_id] = (int)$r->cnt;
|
||
}
|
||
|
||
try {
|
||
foreach ($payload as $uid => $cnt) {
|
||
(new \app\common\utils\WsEvents())->todoCounts($uid, $cnt);
|
||
}
|
||
} catch (\Throwable $e) {
|
||
Log::error('ws todo push error: '.$e->getMessage());
|
||
}
|
||
}
|
||
}
|