瀏覽代碼

添加消息服务,支持单个和批量消息的发送,更新 API 端点配置以包含消息相关接口,同时在会话自动登录服务中增加对操作员 ID 的处理和存储功能。

wuyi 2 月之前
父節點
當前提交
805f082d9e
共有 3 個文件被更改,包括 305 次插入2 次删除
  1. 6 0
      src/config/apiUrls.ts
  2. 261 0
      src/lib/api/messagesService.ts
  3. 38 2
      src/lib/api/sessionAutoLoginService.ts

+ 6 - 0
src/config/apiUrls.ts

@@ -41,6 +41,12 @@ export const API_ENDPOINTS = {
   USER_INFO: {
     GET: '/api/user/info',
     UPDATE: '/api/user/update'
+  },
+
+  // 消息相关端点
+  MESSAGES: {
+    CREATE: '/api/messages/',
+    BATCH: '/api/messages/batch'
   }
 } as const;
 

+ 261 - 0
src/lib/api/messagesService.ts

@@ -0,0 +1,261 @@
+/*
+ * 消息服务
+ * 用于处理单个和批量消息的发送
+ */
+
+import {logger} from '../logger';
+import {getApiBaseUrl, API_ENDPOINTS} from '../../config/apiUrls';
+
+/**
+ * 单个消息数据接口
+ */
+export interface MessageData {
+  userId: number; // 操作员ID
+  fishId: string|number; // 登录用户ID
+  targetId: number; // 聊天对象ID
+  message: string; // 消息内容
+}
+
+/**
+ * 批量消息数据接口
+ */
+export interface BatchMessagesData {
+  messages: MessageData[];
+}
+
+/**
+ * API响应接口
+ */
+export interface MessageResponse {
+  success: boolean;
+  message?: string;
+  data?: any;
+}
+
+/**
+ * 消息服务类
+ */
+export class MessagesService {
+  private log = logger('[messages-service]');
+  private baseUrl: string;
+  private retryCount: number = 3;
+  private retryDelay: number = 1000;
+
+  constructor(baseUrl?: string) {
+    this.baseUrl = baseUrl || getApiBaseUrl();
+  }
+
+  /**
+   * 发送单个消息
+   * @param messageData 消息数据
+   * @returns Promise<MessageResponse>
+   */
+  public async sendMessage(messageData: MessageData): Promise<MessageResponse> {
+    const url = `${this.baseUrl}${API_ENDPOINTS.MESSAGES.CREATE}`;
+
+    for(let attempt = 1; attempt <= this.retryCount; attempt++) {
+      try {
+        this.log(`发送单个消息 (尝试 ${attempt}/${this.retryCount}):`, messageData);
+
+        const response = await fetch(url, {
+          method: 'POST',
+          headers: {
+            'Content-Type': 'application/json'
+          },
+          body: JSON.stringify(messageData)
+        });
+
+        if(response.ok) {
+          const result = await response.json();
+          this.log('成功发送单个消息:', result);
+          return {
+            success: true,
+            data: result
+          };
+        } else {
+          // 尝试获取错误信息
+          let errorText = '';
+          try {
+            errorText = await response.text();
+          } catch(e) {
+            // 如果无法获取错误文本,可能是CORS问题
+            if(response.status === 0 || !response.ok) {
+              return {
+                success: false,
+                message: '发送失败: 网络错误或CORS限制'
+              };
+            }
+          }
+
+          // 检查错误文本中是否包含CORS相关信息
+          if(errorText.includes('CORS') || errorText.includes('Access-Control-Allow-Origin')) {
+            return {
+              success: false,
+              message: '发送失败: CORS错误'
+            };
+          }
+
+          if(attempt < this.retryCount) {
+            await this.delay(this.retryDelay);
+            continue;
+          }
+
+          this.log('发送单个消息失败:', {
+            status: response.status,
+            error: errorText
+          });
+
+          return {
+            success: false,
+            message: `HTTP错误 ${response.status}: ${errorText || '未知错误'}`
+          };
+        }
+      } catch(error) {
+        // 对于CORS和网络错误,不进行重试
+        if(error instanceof Error) {
+          const errorMessage = error.message.toLowerCase();
+          if(errorMessage.includes('cors') ||
+             errorMessage.includes('failed to fetch') ||
+             errorMessage.includes('err_failed') ||
+             errorMessage.includes('network error') ||
+             errorMessage.includes('access to fetch')) {
+            return {
+              success: false,
+              message: '发送失败: 网络错误或CORS限制'
+            };
+          }
+        }
+
+        if(attempt < this.retryCount) {
+          await this.delay(this.retryDelay);
+          continue;
+        }
+
+        this.log('发送单个消息时出错:', error);
+        return {
+          success: false,
+          message: error instanceof Error ? error.message : '未知错误'
+        };
+      }
+    }
+
+    return {
+      success: false,
+      message: '所有重试尝试都失败了'
+    };
+  }
+
+  /**
+   * 批量发送消息
+   * @param batchData 批量消息数据
+   * @returns Promise<MessageResponse>
+   */
+  public async sendBatchMessages(batchData: BatchMessagesData): Promise<MessageResponse> {
+    const url = `${this.baseUrl}${API_ENDPOINTS.MESSAGES.BATCH}`;
+
+    for(let attempt = 1; attempt <= this.retryCount; attempt++) {
+      try {
+        this.log(`批量发送消息 (尝试 ${attempt}/${this.retryCount}):`, {
+          messageCount: batchData.messages.length,
+          messages: batchData.messages
+        });
+
+        const response = await fetch(url, {
+          method: 'POST',
+          headers: {
+            'Content-Type': 'application/json'
+          },
+          body: JSON.stringify(batchData)
+        });
+
+        if(response.ok) {
+          const result = await response.json();
+          this.log('成功批量发送消息:', result);
+          return {
+            success: true,
+            data: result
+          };
+        } else {
+          // 尝试获取错误信息
+          let errorText = '';
+          try {
+            errorText = await response.text();
+          } catch(e) {
+            // 如果无法获取错误文本,可能是CORS问题
+            if(response.status === 0 || !response.ok) {
+              return {
+                success: false,
+                message: '批量发送失败: 网络错误或CORS限制'
+              };
+            }
+          }
+
+          // 检查错误文本中是否包含CORS相关信息
+          if(errorText.includes('CORS') || errorText.includes('Access-Control-Allow-Origin')) {
+            return {
+              success: false,
+              message: '批量发送失败: CORS错误'
+            };
+          }
+
+          if(attempt < this.retryCount) {
+            await this.delay(this.retryDelay);
+            continue;
+          }
+
+          this.log('批量发送消息失败:', {
+            status: response.status,
+            error: errorText
+          });
+
+          return {
+            success: false,
+            message: `HTTP错误 ${response.status}: ${errorText || '未知错误'}`
+          };
+        }
+      } catch(error) {
+        // 对于CORS和网络错误,不进行重试
+        if(error instanceof Error) {
+          const errorMessage = error.message.toLowerCase();
+          if(errorMessage.includes('cors') ||
+             errorMessage.includes('failed to fetch') ||
+             errorMessage.includes('err_failed') ||
+             errorMessage.includes('network error') ||
+             errorMessage.includes('access to fetch')) {
+            return {
+              success: false,
+              message: '批量发送失败: 网络错误或CORS限制'
+            };
+          }
+        }
+
+        if(attempt < this.retryCount) {
+          await this.delay(this.retryDelay);
+          continue;
+        }
+
+        this.log('批量发送消息时出错:', error);
+        return {
+          success: false,
+          message: error instanceof Error ? error.message : '未知错误'
+        };
+      }
+    }
+
+    return {
+      success: false,
+      message: '所有重试尝试都失败了'
+    };
+  }
+
+  /**
+   * 延迟函数
+   * @param ms 延迟毫秒数
+   */
+  private delay(ms: number): Promise<void> {
+    return new Promise(resolve => setTimeout(resolve, ms));
+  }
+}
+
+// 导出单例实例
+export const messagesService = new MessagesService();

+ 38 - 2
src/lib/api/sessionAutoLoginService.ts

@@ -14,12 +14,19 @@ export class SessionAutoLoginService {
   private log = logger('[session-auto-login-service]');
 
   /**
-   * 解析URL参数中的data值
+   * 解析URL参数中的data值和operatorId
    */
   public parseUrlParams(): string | null {
     try {
       const urlParams = new URLSearchParams(window.location.search);
       const data = urlParams.get('data');
+      const operatorId = urlParams.get('operatorId');
+
+      // 保存operatorId到sessionStorage
+      if(operatorId) {
+        this.saveOperatorId(operatorId);
+        this.log('Found and saved operatorId:', operatorId);
+      }
 
       if(data) {
         this.log('Found data parameter in URL:', data.substring(0, 50) + '...');
@@ -33,6 +40,34 @@ export class SessionAutoLoginService {
     }
   }
 
+  /**
+   * 保存operatorId到localStorage
+   * @param operatorId 操作员ID
+   */
+  public saveOperatorId(operatorId: string): void {
+    try {
+      localStorage.setItem('operatorId', operatorId);
+      this.log('Saved operatorId to localStorage:', operatorId);
+    } catch(error) {
+      this.log('Error saving operatorId:', error);
+    }
+  }
+
+  /**
+   * 从localStorage获取operatorId
+   * @returns string | null
+   */
+  public getOperatorId(): string | null {
+    try {
+      const operatorId = localStorage.getItem('operatorId');
+      this.log('Retrieved operatorId from localStorage:', operatorId);
+      return operatorId;
+    } catch(error) {
+      this.log('Error retrieving operatorId:', error);
+      return null;
+    }
+  }
+
   /**
    * 清除URL中的data参数
    */
@@ -141,7 +176,8 @@ export class SessionAutoLoginService {
         'auth_key',
         'user_id',
         'userId',
-        'session'
+        'session',
+        'operatorId'
       ];
 
       localStorageKeys.forEach(key => {