import { WarehouseInfo, UserInfo, DeliveryPerson, Order, EmployeeInfo } from '../types'; import locationTrackingService from './locationTrackingService'; /** * 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 ? '本地开发环境' : '生产环境'})`); /** * 是否启用模拟模式 * 该配置控制是否使用模拟数据进行开发测试 */ /** * API服务类 * 封装了所有与后端API交互的方法,并按照功能模块进行组织 */ class ApiService { /** * 位置更新WebSocket连接 */ private locationWebSocket: any | null; /** * 构造函数 */ constructor() { 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 * @param initialLocation 初始位置数据(必须) * @returns 签到结果和员工信息 */ async userSignIn(userId: number, initialLocation: { latitude: number; longitude: number; timestamp: number }): Promise<{ success: boolean; employeeInfo: EmployeeInfo; message?: string }> { console.log('API userSignIn调用,参数userId:', userId, 'initialLocation:', initialLocation); // 构建请求数据,必须包含位置数据 const requestData: any = { latitude: initialLocation.latitude, longitude: initialLocation.longitude, timestamp: initialLocation.timestamp }; // 服务器现在返回统一的DTO格式,直接使用 const response = await this.request('/user/signin', { method: 'POST', data: requestData, }); // 服务器返回格式:{ success: boolean, userInfo: UserInfoResponse } return { success: response.success, employeeInfo: { id: response.userInfo.id, name: response.userInfo.name, phone: response.userInfo.phone, role: response.userInfo.role || 'DELIVERY_PERSON' }, message: response.message }; } /** * 注册接口 * @param userInfo 注册用户信息 * @returns 注册结果和员工信息 */ async userRegister(userInfo: { name: string; phone: string }): Promise<{ success: boolean; employeeInfo: EmployeeInfo; message?: string }> { console.log('API userRegister调用,参数userInfo:', userInfo); // 服务器现在返回统一的DTO格式:{ success: boolean, userInfo: UserInfoResponse } const response = await this.request('/user/register', { method: 'POST', data: userInfo, }); return { success: response.success, employeeInfo: { id: response.userInfo.id, name: response.userInfo.name || userInfo.name, // 如果服务器返回null,使用用户输入的值 phone: response.userInfo.phone || userInfo.phone, // 如果服务器返回null,使用用户输入的值 role: response.userInfo.role || 'DELIVERY_PERSON' }, message: response.message }; } /** * 用户登出 */ async logout(): Promise { return await this.request('/user/logout', { method: 'POST' }); } /** * 签退接口 * @param userId 用户ID * @returns 签退结果 */ async userSignOut(userId: number): Promise<{ success: boolean; message?: string }> { console.log('API userSignOut调用,参数userId:', userId); // 服务器现在返回统一的DTO格式:{ success: boolean, message: string } const response = await this.request('/user/signout', { method: 'POST', data: { userId }, }); return { success: response.success, message: response.message }; } /** * 获取用户签到状态 * @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 getEmployees(): Promise { return await this.request('/employees'); } /** * 添加新员工 * @param employeeInfo 员工信息 * @returns 添加结果 */ async addEmployee(employeeInfo: { name: string; phone: string; role: string }): Promise { return await this.request('/employees', { method: 'POST', data: employeeInfo, }); } /** * 删除员工 * @param employeeId 员工ID * @returns 删除结果 */ async deleteEmployee(employeeId: number): Promise<{ success: boolean; message?: string }> { return await this.request<{ success: boolean; message?: string }>(`/employees/${employeeId}`, { method: 'DELETE', }); } /** * 更新员工信息 * @param employeeId 员工ID * @param employeeInfo 员工信息 * @returns 更新结果 */ async updateEmployee(employeeId: number, employeeInfo: { name?: string; phone?: string; role?: string }): Promise { return await this.request(`/employees/${employeeId}`, { method: 'PUT', data: employeeInfo, }); } // ==================== 仓库相关接口 ==================== /** * 获取所有仓库列表 * @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; }> { // 真实环境中调用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 { // 真实环境中调用API try { await this.request('/locations/unsubscribe', { method: 'POST', data: { subscriptionId } }); } catch (error) { console.error('取消订阅实时位置更新失败:', error); throw error; } } // ===== 私有属性和方法 ===== /** * 初始化位置更新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`; // 获取当前用户ID(从全局应用数据中获取) const app = getApp(); const userInfo = app.globalData.userInfo; const userId = userInfo?.id; // 构建带用户ID参数的WebSocket URL const finalWsUrl = userId ? `${wsUrl}?userId=${userId}` : wsUrl; console.log(`WebSocket连接URL: ${finalWsUrl}`); this.locationWebSocket = wx.connectSocket({ url: finalWsUrl, 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((res) => { console.log('WebSocket连接已关闭', res); this.locationWebSocket = null; // 如果是非主动关闭,尝试重连 if (res.code !== 1000) { // 1000表示正常关闭 console.log('WebSocket连接异常关闭,将在3秒后尝试重连'); setTimeout(() => { if (!this.locationWebSocket) { this.initLocationWebSocket().catch(err => { console.error('WebSocket重连失败:', err); }); } }, 3000); } }); // 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 isWebSocketConnected(): boolean { return this.locationWebSocket !== null && this.locationWebSocket !== undefined; } /** * 关闭位置更新WebSocket连接 */ public async closeLocationWebSocket(): Promise { if (this.locationWebSocket && typeof wx !== 'undefined' && typeof wx.closeSocket === 'function') { try { // 先检查WebSocket状态,避免在连接过程中关闭 wx.closeSocket(); this.locationWebSocket = null; console.log('WebSocket连接已关闭'); } catch (error) { console.warn('关闭WebSocket连接时出现异常:', error); // 即使关闭失败,也重置连接状态 this.locationWebSocket = null; } } } /** * 处理WebSocket消息 * @param message 接收到的消息 */ private handleWebSocketMessage(message: any): void { if (!message || typeof message.type !== 'string') { console.warn('收到无效的WebSocket消息:', message); return; } locationTrackingService.handleWebSocketMessage(message); } /** * 发送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 userId 用户ID */ async subscribeToLocationUpdates(): Promise { // 确保WebSocket连接已建立 if (!this.locationWebSocket) { this.initLocationWebSocket(); } // 服务器会自动处理订阅逻辑,无需发送订阅消息 console.log('位置订阅已初始化,服务器将自动处理订阅逻辑'); } /** * 取消订阅位置更新(服务器自动处理,无需发送消息) * @param userId 用户ID */ async unsubscribeFromLocationUpdates(_userId: number): Promise { // 服务器会自动处理取消订阅逻辑,无需发送取消订阅消息 console.log('位置取消订阅已初始化,服务器将自动处理取消订阅逻辑'); } /** * 发送位置更新 * @param userId 用户ID * @param latitude 纬度 * @param longitude 经度 */ async sendLocationUpdate(userId: number, latitude: number, longitude: number): Promise { // 确保WebSocket连接已建立 if (!this.locationWebSocket) { this.initLocationWebSocket(); } // 发送位置更新消息 const locationMessage = { type: 'updateLocation', userId: userId, 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();