int|null, // 模板ID * 'template_code' => string|null, // 模板代码 * 'title' => string, // 消息标题 * 'content' => string, // 消息内容 * 'content_type' => string, // 内容类型:text,html,markdown,json * 'data' => array|null, // 附加数据 * 'variables_data' => array|null, // 模板变量数据 * 'sender_id' => int, // 发送者ID * 'sender_type' => string, // 发送者类型:system,user * 'receiver_id' => int|null, // 接收者ID,为空表示群发 * 'receivers' => array|null, // 群发接收者ID数组 * 'allow_reply' => bool, // 是否允许回复 * 'parent_id' => int|null, // 父消息ID(回复时使用) * ] * @return AppMessage */ public function send(array $data): AppMessage { try { DB::beginTransaction(); // 如果提供了模板ID或代码,则获取模板 if (!empty($data['template_id']) || !empty($data['template_code'])) { $template = $this->getTemplate($data['template_id'] ?? null, $data['template_code'] ?? null); if ($template) { $data = $this->applyTemplate($template, $data); } } // 创建消息 $message = new AppMessage(); $message->type = $data['type'] ?? 'user'; $message->template_id = $data['template_id'] ?? null; $message->template_code = $data['template_code'] ?? null; $message->title = $data['title']; $message->content = $data['content']; $message->content_type = $data['content_type'] ?? 'text'; $message->data = $data['data'] ?? null; $message->variables_data = $data['variables_data'] ?? null; $message->sender_id = $data['sender_id']; $message->sender_type = $data['sender_type']; $message->receiver_id = $data['receiver_id'] ?? null; $message->parent_id = $data['parent_id'] ?? null; $message->allow_reply = $data['allow_reply'] ?? true; $message->save(); // 处理群发 if (empty($message->receiver_id) && !empty($data['receivers'])) { $this->sendToRecipients($message, $data['receivers']); } DB::commit(); return $message; } catch (\Exception $e) { DB::rollBack(); throw $e; } } /** * 批量发送消息 * * @param array $messages 消息数组 * @return Collection */ public function sendBatch(array $messages): Collection { $results = collect(); foreach ($messages as $data) { $results->push($this->send($data)); } return $results; } /** * 获取模板 * * @param int|null $id 模板ID * @param string|null $code 模板代码 * @return AppMessageTemplate|null */ public function getTemplate(?int $id = null, ?string $code = null): ?AppMessageTemplate { if ($id) { return AppMessageTemplate::find($id); } if ($code) { return AppMessageTemplate::where('code', $code)->first(); } return null; } /** * 应用模板 * * @param AppMessageTemplate $template 模板 * @param array $data 数据 * @return array */ protected function applyTemplate(AppMessageTemplate $template, array $data): array { $variables = $data['variables_data'] ?? []; $content = $template->content; // 替换模板变量 if (!empty($variables) && !empty($template->variables)) { foreach ($template->variables as $key => $info) { $value = $variables[$key] ?? ''; $content = str_replace('{{'.$key.'}}', $value, $content); } } return array_merge($data, [ 'type' => $template->type, 'title' => $template->title, 'content' => $content, 'content_type' => $template->content_type, 'allow_reply' => $template->allow_reply, ]); } /** * 发送给多个接收者 * * @param AppMessage $message 消息 * @param array $receiverIds 接收者ID数组 * @return void */ protected function sendToRecipients(AppMessage $message, array $receiverIds): void { $now = Carbon::now(); $recipients = array_map(function ($userId) use ($message, $now) { return [ 'message_id' => $message->id, 'user_id' => $userId, 'created_at' => $now, 'updated_at' => $now, ]; }, array_unique($receiverIds)); AppMessageRecipient::insert($recipients); } /** * 标记消息为已读 * * @param int $messageId 消息ID * @param int $userId 用户ID * @return bool */ public function markAsRead(int $messageId, int $userId): bool { $now = Carbon::now(); // 更新直接接收的消息 $message = AppMessage::where('id', $messageId) ->where('receiver_id', $userId) ->first(); if ($message) { $message->update([ 'is_read' => true, 'read_at' => $now ]); return true; } // 更新群发消息接收记录 $recipient = AppMessageRecipient::where('message_id', $messageId) ->where('user_id', $userId) ->first(); if ($recipient) { $recipient->update([ 'is_read' => true, 'read_at' => $now ]); return true; } return false; } /** * 获取用户未读消息数量 * * @param int $userId 用户ID * @return int */ public function getUnreadCount(int $userId): int { // 直接接收的未读消息 $directCount = AppMessage::where('receiver_id', $userId) ->where('is_read', false) ->where('status', 1) ->count(); // 群发消息的未读数量 $recipientCount = AppMessageRecipient::where('user_id', $userId) ->where('is_read', false) ->where('status', 1) ->count(); return $directCount + $recipientCount; } /** * 获取用户的消息列表 * * @param int $userId 用户ID * @param array $filters 过滤条件 * @param int $perPage 每页数量 * @return \Illuminate\Pagination\LengthAwarePaginator */ public function getUserMessages(int $userId, array $filters = [], int $perPage = 15) { $query = AppMessage::where(function ($query) use ($userId) { $query->where('receiver_id', $userId) ->orWhereExists(function ($query) use ($userId) { $query->from('app_message_recipients') ->whereColumn('app_message_recipients.message_id', 'app_messages.id') ->where('app_message_recipients.user_id', $userId) ->where('app_message_recipients.status', 1); }); })->where('status', 1); // 应用过滤条件 if (!empty($filters['type'])) { $query->where('type', $filters['type']); } if (!empty($filters['content_type'])) { $query->where('content_type', $filters['content_type']); } if (isset($filters['is_read'])) { $query->where('is_read', $filters['is_read']); } return $query->orderBy('created_at', 'desc')->paginate($perPage); } /** * 创建消息模板 * * @param array $data 模板数据,包含以下字段: * - name: string 模板名称 * - code: string 模板代码 * - type: string 模板类型 * - title: string 消息标题 * - content: string 消息内容 * - variables: array 模板变量 * - status: bool 模板状态 * @return AppMessageTemplate 返回创建的模板实例 */ public function createTemplate(array $data): AppMessageTemplate { return AppMessageTemplate::create($data); } /** * 更新消息模板 * * @param int $id 模板ID * @param array $data 更新的模板数据,字段同createTemplate方法 * @return bool 更新成功返回true,失败返回false */ public function updateTemplate(int $id, array $data): bool { $template = $this->getTemplate($id); if (!$template) { return false; } return $template->update($data); } /** * 删除消息模板 * * @param int $id 模板ID * @return bool 删除成功返回true,失败返回false */ public function deleteTemplate(int $id): bool { $template = $this->getTemplate($id); if (!$template) { return false; } return $template->delete(); } }