import { WarehouseInfo, UserInfo, DeliveryPerson, Order, EmployeeInfo } from '../types'; /** * API服务基类 * 提供与后端API交互的核心功能 */ // API基础URL配置 const IS_LOCAL_DEV = false; // true: 本地开发环境, false: 生产环境 const API_BASE_URL = IS_LOCAL_DEV ? 'http://localhost:8080' : 'https://www.doubleyin.cn'; console.log(`当前API地址: ${API_BASE_URL} (${IS_LOCAL_DEV ? '本地开发环境' : '生产环境'})`); /** * 是否启用模拟模式 * 该配置控制是否使用模拟数据进行开发测试 */ export const isMockMode = false; /** * API服务类 * 封装了所有与后端API交互的方法,并按照功能模块进行组织 */ class ApiService { /** * 位置更新回调函数集合 */ private locationUpdateCallbacks: Set<(location: any) => void> | null; /** * 位置更新WebSocket连接 */ private locationWebSocket: any | null; /** * 构造函数 */ constructor() { this.locationUpdateCallbacks = null; this.locationWebSocket = null; } /** * 基础请求方法 * @param endpoint API端点路径 * @param options 请求配置选项 * @returns Promise 返回泛型类型的响应数据 */ private async request(endpoint: string, options: { method?: string; data?: any; headers?: Record } = {}): Promise { const requestUrl = `${API_BASE_URL}${endpoint}`; // 获取全局token const app = getApp(); const token = app.globalData.token; // 构建请求头,自动添加Authorization头(如果存在token) const headers: Record = { 'Content-Type': 'application/json', ...options.headers, }; if (token) { headers['Authorization'] = `Bearer ${token}`; } const requestOptions = { method: options.method || 'GET', data: options.data, header: headers, }; // 打印请求信息 console.log('\n========== API Request =========='); console.log(`Method: ${requestOptions.method}`); console.log(`URL: ${requestUrl}`); console.log(`Headers:`, requestOptions.header); console.log(`Data:`, requestOptions.data); console.log('================================'); return new Promise((resolve, reject) => { wx.request({ url: requestUrl, method: requestOptions.method as any, data: requestOptions.data, header: requestOptions.header, success: (res: any) => { // 打印响应信息 console.log('\n========== API Response =========='); console.log(`URL: ${requestUrl}`); console.log(`Status: ${res.statusCode}`); console.log(`Response Data:`, res.data); console.log('=================================='); if (res.statusCode >= 200 && res.statusCode < 300) { resolve(res.data); } else { console.error(`API Error: HTTP ${res.statusCode}: ${res.errMsg}`); reject(new Error(`HTTP ${res.statusCode}: ${res.errMsg}`)); } }, fail: (err: any) => { console.error('\n========== API Request Failed =========='); console.error(`URL: ${requestUrl}`); console.error(`Error: ${err.errMsg}`); console.error('======================================='); reject(new Error(`Request failed: ${err.errMsg}`)); } }); }); } // ==================== 用户模块 ==================== // ====== 认证相关 ====== /** * 微信登录接口 * @param code 微信登录授权码 * @returns 用户信息及认证令牌 */ async ServerLogin(code: string) { console.log('API wxLogin调用,参数code:', code); return await this.request<{ user: UserInfo; token: string; openid: string; session_key: string }>('/user/wxlogin', { method: 'POST', data: { code: code }, }); } /** * 签到接口 * @param userId 用户ID * @returns 签到结果和员工信息 */ async userSignIn(userId: number): Promise<{ success: boolean; employeeInfo: EmployeeInfo; message?: string }> { console.log('API userSignIn调用,参数userId:', userId); // 服务器返回的是用户对象,需要转换为前端期望的格式 const response = await this.request('/user/signin', { method: 'POST', data: { userId }, }); // 转换响应格式 return { success: true, employeeInfo: { id: response.id, name: response.name, phone: response.phone, role: response.role || 'DELIVERY_PERSON' }, message: '签到成功' }; } /** * 注册接口 * @param userInfo 注册用户信息 * @returns 注册结果和员工信息 */ async userRegister(userInfo: { name: string; phone: string }): Promise<{ success: boolean; employeeInfo: EmployeeInfo; message?: string }> { console.log('API userRegister调用,参数userInfo:', userInfo); // 服务器返回的是用户对象,需要转换为前端期望的格式 const response = await this.request('/user/register', { method: 'POST', data: userInfo, }); // 转换响应格式 return { success: true, employeeInfo: { id: response.id, name: response.name || userInfo.name, // 如果服务器返回null,使用用户输入的值 phone: response.phone || userInfo.phone, // 如果服务器返回null,使用用户输入的值 role: response.role || 'DELIVERY_PERSON' }, message: '注册成功' }; } /** * 用户登出 */ async logout(): Promise { return await this.request('/user/logout', { method: 'POST' }); } /** * 获取用户签到状态 * @returns 用户状态信息 */ async getUserStatus(): Promise<{ status: 'signed_in' | 'signed_out' | 'registered' | 'unregistered'; lastSignInTime?: string; lastSignOutTime?: string }> { return await this.request('/user/status', { method: 'GET' }); } // ====== 信息相关 ====== /** * 获取当前用户信息 * @returns 用户详细信息 */ async getUserInfo() { return await this.request('/user/info'); } /** * 更新用户信息 * @param userInfo 待更新的用户信息 * @returns 更新后的用户信息 */ async updateUserInfo(userInfo: Partial): Promise { return await this.request('/user/update', { method: 'PUT', data: userInfo, }); } /** * 获取用户权限列表 * @returns 权限字符串数组 */ async getUserPermissions(): Promise { return await this.request('/user/permissions'); } /** * 检查用户是否在线 * @returns 在线状态 */ async checkUserOnline(): Promise { return await this.request('/user/online'); } /** * 获取用户会话信息 * @returns 会话详细信息 */ async getSessionInfo(): Promise<{ userId: number; sessionId: string; expiresAt: number; permissions: string[]; }> { return await this.request<{ userId: number; sessionId: string; expiresAt: number; permissions: string[]; }>('/user/session'); } /** * 刷新用户令牌 * @param oldToken 旧令牌 * @returns 新令牌及过期时间 */ async refreshToken(oldToken: string): Promise<{ token: string; expiresAt: number }> { return await this.request<{ token: string; expiresAt: number }>('/user/refresh-token', { method: 'POST', data: { token: oldToken }, }); } /** * 验证用户权限 * @param permission 待验证的权限 * @returns 是否拥有该权限 */ async verifyPermission(permission: string): Promise { return await this.request(`/user/verify-permission?permission=${permission}`); } // ====== 管理相关 ====== /** * 搜索用户 * @param query 搜索关键词 * @param page 页码 * @param pageSize 每页数量 * @returns 用户列表及分页信息 */ async searchUsers(query: string, page: number = 1, pageSize: number = 20): Promise<{ users: UserInfo[]; total: number; page: number; pageSize: number; }> { return await this.request<{ users: UserInfo[]; total: number; page: number; pageSize: number }>( `/user/search?query=${query}&page=${page}&pageSize=${pageSize}` ); } /** * 批量操作用户状态 * @param userIds 用户ID列表 * @param status 目标状态 */ async batchUpdateUserStatus(userIds: number[], status: 'active' | 'inactive' | 'suspended'): Promise { return await this.request('/user/batch-update-status', { method: 'POST', data: { userIds, status }, }); } // ==================== 仓库相关接口 ==================== /** * 获取所有仓库列表 * @returns 仓库信息数组 */ async getWarehouses(): Promise { return await this.request('/warehouses'); } /** * 获取指定仓库详情 * @param id 仓库ID * @returns 仓库详细信息 */ async getWarehouseById(id: number): Promise { return await this.request(`/warehouses/${id}`); } /** * 获取仓库相关订单 * @param warehouseId 仓库ID * @returns 订单列表 */ async getWarehouseOrders(warehouseId: number): Promise { return await this.request(`/warehouses/${warehouseId}/orders`); } // ==================== 货运人员接口 ==================== /** * 获取所有货运人员 * @returns 货运人员列表 */ async getDeliveryPersons(): Promise { return await this.request('/delivery-persons'); } /** * 获取所有配送员实时位置 * @returns 所有配送员实时位置信息 */ async getAllDeliveryPersonLocations(): Promise> { return await this.request>('/location-sync/delivery-persons/locations'); } /** * 获取指定货运人员详情 * @param id 货运人员ID * @returns 货运人员详细信息 */ async getDeliveryPersonById(id: number): Promise { return await this.request(`/delivery-persons/${id}`); } /** * 更新货运人员位置 * @param id 货运人员ID * @param location 位置信息 */ async updateDeliveryPersonLocation(id: number, location: { longitude: number; latitude: number }): Promise { return await this.request(`/delivery-persons/${id}/location`, { method: 'PUT', data: location, }); } // 地图相关接口支持 /** * 批量更新货运人员位置(兼容mapService参数) * @param locations 位置信息数组 */ async batchUpdateDeliveryPersonLocations(locations: Array<{ userId: number; latitude: number; longitude: number; timestamp: number; }>): Promise { // 转换参数格式以匹配原有API const formattedLocations = locations.map(loc => ({ deliveryPersonId: loc.userId, longitude: loc.longitude, latitude: loc.latitude, timestamp: loc.timestamp })); await this.request('/delivery-persons/locations/batch', { method: 'POST', data: { locations: formattedLocations } }); } /** * 获取空闲的货运人员 * @returns 空闲货运人员列表 */ async getIdleDeliveryPersons(): Promise { return await this.request('/delivery-persons/idle'); } /** * 获取忙碌的货运人员 * @returns 忙碌货运人员列表 */ async getBusyDeliveryPersons(): Promise { return await this.request('/delivery-persons/busy'); } /** * 获取位置历史记录 * @param deliveryPersonId 货运人员ID * @param limit 记录数量 * @returns 位置历史记录 */ async getLocationHistory(deliveryPersonId: number, limit: number = 50): Promise> { return await this.request>(`/delivery-persons/${deliveryPersonId}/location-history?limit=${limit}`); } /** * 订阅实时位置更新(接收货运人员ID列表) * @param deliveryPersonIds 货运人员ID列表 * @returns 订阅信息 */ async subscribeToRealTimeLocations(deliveryPersonIds: number[]): Promise<{ subscriptionId: string; expiresAt: number; }> { if (isMockMode) { // 模拟数据 - 返回模拟的订阅信息 console.log('[MOCK] 订阅实时位置更新,货运人员ID列表:', deliveryPersonIds); return { subscriptionId: `mock-subscription-${Date.now()}`, expiresAt: Date.now() + 3600000 // 1小时后过期 }; } // 真实环境中调用API try { return await this.request<{ subscriptionId: string; expiresAt: number; }>('/locations/subscribe', { method: 'POST', data: { deliveryPersonIds } }); } catch (error) { console.error('订阅实时位置更新失败:', error); throw error; } } /** * 取消订阅实时位置更新 * @param subscriptionId 订阅ID */ async unsubscribeFromRealTimeLocations(subscriptionId: string): Promise { if (isMockMode) { // 模拟数据 - 记录取消订阅操作 console.log('[MOCK] 取消订阅实时位置更新,订阅ID:', subscriptionId); return; } // 真实环境中调用API try { await this.request('/locations/unsubscribe', { method: 'POST', data: { subscriptionId } }); } catch (error) { console.error('取消订阅实时位置更新失败:', error); throw error; } } /** * 注册位置更新回调函数 * @param callback 位置更新回调函数 * @returns 取消订阅函数 */ onLocationUpdate(callback: (location: any) => void): () => void { // 添加回调到集合 if (!this.locationUpdateCallbacks) { this.locationUpdateCallbacks = new Set(); } this.locationUpdateCallbacks.add(callback); // 返回取消订阅函数 return () => { if (this.locationUpdateCallbacks) { this.locationUpdateCallbacks.delete(callback); // 如果没有回调了,可以关闭WebSocket连接 if (this.locationUpdateCallbacks.size === 0 && this.locationWebSocket) { this.locationWebSocket.close(); this.locationWebSocket = null; } } }; } // ===== 私有属性和方法 ===== /** * 初始化位置更新WebSocket连接 */ public async initLocationWebSocket(): Promise { if (this.locationWebSocket) { console.log('WebSocket连接已存在'); return; } try { if (typeof wx !== 'undefined' && typeof wx.connectSocket === 'function') { console.log('初始化位置更新WebSocket连接(小程序环境)'); // 连接到服务端的WebSocket地址,使用配置的服务器地址 const serverUrl = API_BASE_URL.replace('http', 'ws'); const wsUrl = `${serverUrl}/ws/location`; this.locationWebSocket = wx.connectSocket({ url: wsUrl, header: { 'content-type': 'application/json' } }); // WebSocket连接打开事件 wx.onSocketOpen(() => { console.log('WebSocket连接已打开'); }); // WebSocket消息接收事件 wx.onSocketMessage((res) => { try { const message = JSON.parse(typeof res.data === 'string' ? res.data : String(res.data)); this.handleWebSocketMessage(message); } catch (error) { console.error('解析WebSocket消息失败:', error); } }); // WebSocket连接关闭事件 wx.onSocketClose(() => { console.log('WebSocket连接已关闭'); this.locationWebSocket = null; }); // WebSocket错误事件 wx.onSocketError((error) => { console.error('WebSocket连接错误:', error); this.locationWebSocket = null; }); } else { console.warn('当前环境不支持WebSocket连接'); } } catch (error) { console.error('初始化位置更新WebSocket连接失败:', error); this.locationWebSocket = null; } } /** * 关闭位置更新WebSocket连接 */ public async closeLocationWebSocket(): Promise { if (this.locationWebSocket && typeof wx !== 'undefined' && typeof wx.closeSocket === 'function') { wx.closeSocket(); this.locationWebSocket = null; console.log('WebSocket连接已关闭'); } } /** * 处理WebSocket消息 * @param message 接收到的消息 */ private handleWebSocketMessage(message: any): void { if (!message || typeof message.type !== 'string') { console.warn('收到无效的WebSocket消息:', message); return; } switch (message.type) { case 'updateLocation': // 处理位置更新消息 this.onLocationUpdate(message); break; default: console.warn('收到未知类型的WebSocket消息:', message); break; } } /** * 发送WebSocket消息 * @param message 要发送的消息 */ private sendWebSocketMessage(message: any): void { if (!this.locationWebSocket) { console.warn('WebSocket连接未建立,无法发送消息'); return; } try { const messageStr = JSON.stringify(message); if (typeof wx !== 'undefined' && typeof wx.sendSocketMessage === 'function') { wx.sendSocketMessage({ data: messageStr }); } } catch (error) { console.error('发送WebSocket消息失败:', error); } } /** * 订阅位置更新 * @param deliveryPersonId 配送员ID */ async subscribeToLocationUpdates(deliveryPersonId: number): Promise { if (isMockMode) { console.log('[MOCK] 订阅位置更新'); return; } // 确保WebSocket连接已建立 if (!this.locationWebSocket) { this.initLocationWebSocket(); } // 发送订阅消息 const subscribeMessage = { type: 'subscribe', deliveryPersonId: deliveryPersonId, timestamp: Date.now() }; this.sendWebSocketMessage(subscribeMessage); } /** * 取消订阅位置更新 * @param deliveryPersonId 配送员ID */ async unsubscribeFromLocationUpdates(deliveryPersonId: number): Promise { if (isMockMode) { console.log('[MOCK] 取消订阅位置更新'); return; } // 发送取消订阅消息 const unsubscribeMessage = { type: 'unsubscribe', deliveryPersonId: deliveryPersonId, timestamp: Date.now() }; this.sendWebSocketMessage(unsubscribeMessage); } /** * 发送位置更新 * @param deliveryPersonId 配送员ID * @param latitude 纬度 * @param longitude 经度 */ async sendLocationUpdate(deliveryPersonId: number, latitude: number, longitude: number): Promise { if (isMockMode) { console.log('[MOCK] 发送位置更新'); return; } // 确保WebSocket连接已建立 if (!this.locationWebSocket) { this.initLocationWebSocket(); } // 发送位置更新消息 const locationMessage = { type: 'updateLocation', deliveryPersonId: deliveryPersonId, latitude: latitude, longitude: longitude, timestamp: Date.now() }; this.sendWebSocketMessage(locationMessage); } // ==================== 订单接口 ==================== /** * 获取待指派订单 * @returns 待指派订单列表 */ async getPendingOrders(): Promise { return await this.request('/orders/pending'); } /** * 指派订单给货运人员 * @param orderId 订单ID * @param deliveryPersonId 货运人员ID */ async assignOrder(orderId: number, deliveryPersonId: number): Promise<{ success: boolean; message?: string }> { return await this.request<{ success: boolean; message?: string }>(`/orders/${orderId}/assign`, { method: 'POST', data: { deliveryPersonId }, }); } /** * 获取货运人员当前订单 * @param deliveryPersonId 货运人员ID * @returns 订单列表 */ async getDeliveryPersonOrders(deliveryPersonId: number): Promise { return await this.request(`/delivery-persons/${deliveryPersonId}/orders`); } /** * 根据ID获取订单 * @param id 订单ID * @returns 订单详细信息 */ async getOrderById(id: number): Promise { return await this.request(`/orders/${id}`); } /** * 更新订单状态 * @param orderId 订单ID * @param status 目标状态 */ async updateOrderStatus(orderId: number, status: Order['status']): Promise<{ success: boolean; message?: string }> { return await this.request<{ success: boolean; message?: string }>(`/orders/${orderId}/status`, { method: 'PUT', data: { status }, }); } /** * 创建新订单 * @param orderData 订单数据 * @returns 创建的订单信息 */ async createOrder(orderData: Omit): Promise { return await this.request('/orders', { method: 'POST', data: orderData, }); } /** * 删除订单 * @param orderId 订单ID */ async deleteOrder(orderId: number): Promise { return await this.request(`/orders/${orderId}`, { method: 'DELETE', }); } // ==================== 统计和日志接口 ==================== /** * 获取系统统计信息 * @returns 系统统计数据 */ async getSystemStats(): Promise<{ totalWarehouses: number; totalDeliveryPersons: number; pendingOrders: number; activeOrders: number; }> { return await this.request<{ totalWarehouses: number; totalDeliveryPersons: number; pendingOrders: number; activeOrders: number; }>('/stats/system'); } /** * 获取订单统计信息 * @param timeRange 时间范围 * @returns 订单统计数据 */ async getOrderStats(timeRange: 'today' | 'week' | 'month'): Promise<{ totalOrders: number; completedOrders: number; inProgressOrders: number; averageDeliveryTime: number; }> { return await this.request<{ totalOrders: number; completedOrders: number; inProgressOrders: number; averageDeliveryTime: number; }>(`/stats/orders?timeRange=${timeRange}`); } /** * 获取用户统计信息 * @returns 用户统计数据 */ async getUserStats(): Promise<{ totalUsers: number; activeUsers: number; onlineUsers: number; newUsersToday: number; }> { return await this.request<{ totalUsers: number; activeUsers: number; onlineUsers: number; newUsersToday: number; }>('/user/stats'); } /** * 获取用户活动日志 * @param userId 用户ID * @param limit 日志数量 * @returns 活动日志列表 */ async getUserActivityLogs(userId: number, limit: number = 20): Promise> { return await this.request>( `/user/${userId}/activity-logs?limit=${limit}` ); } /** * 上传错误日志 * @param error 错误信息 */ async uploadErrorLog(error: any): Promise { await this.request('/logs/error', { method: 'POST', data: { error: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : undefined, timestamp: Date.now(), userAgent: 'miniprogram/' + (typeof wx !== 'undefined' ? wx.getSystemInfoSync().platform : 'unknown') } }); } // ==================== 系统接口 ==================== /** * 健康检查 * @returns 系统健康状态 */ async healthCheck(): Promise<{ status: 'ok' | 'degraded' | 'down'; message: string; timestamp: number; }> { return await this.request<{ status: 'ok' | 'degraded' | 'down'; message: string; timestamp: number; }>('/health'); } } /** * API服务单例实例 * 导出供应用程序全局使用 */ export default new ApiService();