| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- <?php
- namespace App\Module\AppMessage\Services;
- use App\Module\AppMessage\Enums\AppMessageStatus;
- use App\Module\AppMessage\Enums\AppMessageType;
- use App\Module\AppMessage\Enums\AppSenderType;
- use App\Module\AppMessage\Models\AppMessage;
- use App\Module\AppMessage\Models\AppMessageRecipient;
- use App\Module\AppMessage\Models\AppMessageTemplate;
- use App\Module\AppMessage\Queues\SendAppMessageQueue;
- use Illuminate\Support\Facades\DB;
- use Illuminate\Support\Facades\Log;
- use Illuminate\Support\Collection;
- use Carbon\Carbon;
- /**
- * 应用消息服务类
- *
- * 该服务类提供了消息的发送、模板管理、消息状态管理等功能
- */
- class AppMessageService
- {
- /**
- * 发送消息
- *
- * @param array $data [
- * 'template_id' => 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();
- }
- }
|