949 lines
26 KiB
TypeScript
949 lines
26 KiB
TypeScript
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<T> 返回泛型类型的响应数据
|
||
*/
|
||
private async request<T>(endpoint: string, options: {
|
||
method?: string;
|
||
data?: any;
|
||
headers?: Record<string, string>
|
||
} = {}): Promise<T> {
|
||
const requestUrl = `${API_BASE_URL}${endpoint}`;
|
||
|
||
// 获取全局token
|
||
const app = getApp<any>();
|
||
const token = app.globalData.token;
|
||
|
||
// 构建请求头,自动添加Authorization头(如果存在token)
|
||
const headers: Record<string, string> = {
|
||
'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<any>('/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<any>('/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<void> {
|
||
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<any>('/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<UserInfo>('/user/info');
|
||
}
|
||
|
||
/**
|
||
* 更新用户信息
|
||
* @param userInfo 待更新的用户信息
|
||
* @returns 更新后的用户信息
|
||
*/
|
||
async updateUserInfo(userInfo: Partial<UserInfo>): Promise<UserInfo> {
|
||
return await this.request<UserInfo>('/user/update', {
|
||
method: 'PUT',
|
||
data: userInfo,
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 获取用户权限列表
|
||
* @returns 权限字符串数组
|
||
*/
|
||
async getUserPermissions(): Promise<string[]> {
|
||
return await this.request<string[]>('/user/permissions');
|
||
}
|
||
|
||
/**
|
||
* 检查用户是否在线
|
||
* @returns 在线状态
|
||
*/
|
||
async checkUserOnline(): Promise<boolean> {
|
||
return await this.request<boolean>('/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<boolean> {
|
||
return await this.request<boolean>(`/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<void> {
|
||
return await this.request('/user/batch-update-status', {
|
||
method: 'POST',
|
||
data: { userIds, status },
|
||
});
|
||
}
|
||
|
||
// ====== 员工管理接口 ======
|
||
|
||
/**
|
||
* 获取所有员工列表
|
||
* @returns 员工信息数组
|
||
*/
|
||
async getEmployees(): Promise<EmployeeInfo[]> {
|
||
return await this.request<EmployeeInfo[]>('/employees');
|
||
}
|
||
|
||
/**
|
||
* 添加新员工
|
||
* @param employeeInfo 员工信息
|
||
* @returns 添加结果
|
||
*/
|
||
async addEmployee(employeeInfo: { name: string; phone: string; role: string }): Promise<EmployeeInfo> {
|
||
return await this.request<EmployeeInfo>('/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<EmployeeInfo> {
|
||
return await this.request<EmployeeInfo>(`/employees/${employeeId}`, {
|
||
method: 'PUT',
|
||
data: employeeInfo,
|
||
});
|
||
}
|
||
|
||
// ==================== 仓库相关接口 ====================
|
||
|
||
/**
|
||
* 获取所有仓库列表
|
||
* @returns 仓库信息数组
|
||
*/
|
||
async getWarehouses(): Promise<WarehouseInfo[]> {
|
||
return await this.request<WarehouseInfo[]>('/warehouses');
|
||
}
|
||
|
||
/**
|
||
* 获取指定仓库详情
|
||
* @param id 仓库ID
|
||
* @returns 仓库详细信息
|
||
*/
|
||
async getWarehouseById(id: number): Promise<WarehouseInfo> {
|
||
return await this.request<WarehouseInfo>(`/warehouses/${id}`);
|
||
}
|
||
|
||
/**
|
||
* 获取仓库相关订单
|
||
* @param warehouseId 仓库ID
|
||
* @returns 订单列表
|
||
*/
|
||
async getWarehouseOrders(warehouseId: number): Promise<Order[]> {
|
||
return await this.request<Order[]>(`/warehouses/${warehouseId}/orders`);
|
||
}
|
||
|
||
// ==================== 货运人员接口 ====================
|
||
|
||
/**
|
||
* 获取所有货运人员
|
||
* @returns 货运人员列表
|
||
*/
|
||
async getDeliveryPersons(): Promise<DeliveryPerson[]> {
|
||
return await this.request<DeliveryPerson[]>('/delivery-persons');
|
||
}
|
||
|
||
/**
|
||
* 获取所有配送员实时位置
|
||
* @returns 所有配送员实时位置信息
|
||
*/
|
||
async getAllDeliveryPersonLocations(): Promise<Array<{
|
||
deliveryPersonId: number;
|
||
name: string;
|
||
latitude: number;
|
||
longitude: number;
|
||
status: string;
|
||
}>> {
|
||
return await this.request<Array<{
|
||
deliveryPersonId: number;
|
||
name: string;
|
||
latitude: number;
|
||
longitude: number;
|
||
status: string;
|
||
}>>('/location-sync/delivery-persons/locations');
|
||
}
|
||
|
||
/**
|
||
* 获取指定货运人员详情
|
||
* @param id 货运人员ID
|
||
* @returns 货运人员详细信息
|
||
*/
|
||
async getDeliveryPersonById(id: number): Promise<DeliveryPerson> {
|
||
return await this.request<DeliveryPerson>(`/delivery-persons/${id}`);
|
||
}
|
||
|
||
/**
|
||
* 更新货运人员位置
|
||
* @param id 货运人员ID
|
||
* @param location 位置信息
|
||
*/
|
||
async updateDeliveryPersonLocation(id: number, location: { longitude: number; latitude: number }): Promise<void> {
|
||
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<void> {
|
||
// 转换参数格式以匹配原有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<DeliveryPerson[]> {
|
||
return await this.request<DeliveryPerson[]>('/delivery-persons/idle');
|
||
}
|
||
|
||
/**
|
||
* 获取忙碌的货运人员
|
||
* @returns 忙碌货运人员列表
|
||
*/
|
||
async getBusyDeliveryPersons(): Promise<DeliveryPerson[]> {
|
||
return await this.request<DeliveryPerson[]>('/delivery-persons/busy');
|
||
}
|
||
|
||
/**
|
||
* 获取位置历史记录
|
||
* @param deliveryPersonId 货运人员ID
|
||
* @param limit 记录数量
|
||
* @returns 位置历史记录
|
||
*/
|
||
async getLocationHistory(deliveryPersonId: number, limit: number = 50): Promise<Array<{
|
||
timestamp: number;
|
||
longitude: number;
|
||
latitude: number;
|
||
speed?: number;
|
||
accuracy?: number;
|
||
}>> {
|
||
return await this.request<Array<{
|
||
timestamp: number;
|
||
longitude: number;
|
||
latitude: number;
|
||
speed?: number;
|
||
accuracy?: number;
|
||
}>>(`/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<void> {
|
||
// 真实环境中调用API
|
||
try {
|
||
await this.request<void>('/locations/unsubscribe', {
|
||
method: 'POST',
|
||
data: { subscriptionId }
|
||
});
|
||
} catch (error) {
|
||
console.error('取消订阅实时位置更新失败:', error);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
|
||
// ===== 私有属性和方法 =====
|
||
|
||
/**
|
||
* 初始化位置更新WebSocket连接
|
||
*/
|
||
public async initLocationWebSocket(): Promise<void> {
|
||
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<any>();
|
||
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<void> {
|
||
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<void> {
|
||
// 确保WebSocket连接已建立
|
||
if (!this.locationWebSocket) {
|
||
this.initLocationWebSocket();
|
||
}
|
||
|
||
// 服务器会自动处理订阅逻辑,无需发送订阅消息
|
||
console.log('位置订阅已初始化,服务器将自动处理订阅逻辑');
|
||
}
|
||
|
||
/**
|
||
* 取消订阅位置更新(服务器自动处理,无需发送消息)
|
||
* @param userId 用户ID
|
||
*/
|
||
async unsubscribeFromLocationUpdates(_userId: number): Promise<void> {
|
||
// 服务器会自动处理取消订阅逻辑,无需发送取消订阅消息
|
||
console.log('位置取消订阅已初始化,服务器将自动处理取消订阅逻辑');
|
||
}
|
||
|
||
/**
|
||
* 发送位置更新
|
||
* @param userId 用户ID
|
||
* @param latitude 纬度
|
||
* @param longitude 经度
|
||
*/
|
||
async sendLocationUpdate(userId: number, latitude: number, longitude: number): Promise<void> {
|
||
// 确保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<Order[]> {
|
||
return await this.request<Order[]>('/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<Order[]> {
|
||
return await this.request<Order[]>(`/delivery-persons/${deliveryPersonId}/orders`);
|
||
}
|
||
|
||
/**
|
||
* 根据ID获取订单
|
||
* @param id 订单ID
|
||
* @returns 订单详细信息
|
||
*/
|
||
async getOrderById(id: number): Promise<Order> {
|
||
return await this.request<Order>(`/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<Order, 'id' | 'createTime'>): Promise<Order> {
|
||
return await this.request<Order>('/orders', {
|
||
method: 'POST',
|
||
data: orderData,
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 删除订单
|
||
* @param orderId 订单ID
|
||
*/
|
||
async deleteOrder(orderId: number): Promise<void> {
|
||
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<Array<{
|
||
id: number;
|
||
action: string;
|
||
timestamp: number;
|
||
details?: any;
|
||
}>> {
|
||
return await this.request<Array<{ id: number; action: string; timestamp: number; details?: any }>>(
|
||
`/user/${userId}/activity-logs?limit=${limit}`
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 上传错误日志
|
||
* @param error 错误信息
|
||
*/
|
||
async uploadErrorLog(error: any): Promise<void> {
|
||
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();
|
||
|