Files
WXProgram/dist/services/apiService.js

884 lines
29 KiB
JavaScript
Raw Permalink Normal View History

2025-10-26 13:15:04 +08:00
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const roleUtils_1 = require("../utils/roleUtils");
const locationTrackingService_1 = __importDefault(require("./locationTrackingService"));
/**
* API服务基类
* 提供与后端API交互的核心功能
*/
// API基础URL配置
const IS_LOCAL_DEV = true; // 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 {
/**
* 构造函数
*/
constructor() {
this.locationWebSocket = null;
}
/**
* 基础请求方法
* @param endpoint API端点路径
* @param options 请求配置选项
* @returns Promise<T> 返回泛型类型的响应数据
*/
async request(endpoint, options = {}) {
const requestUrl = `${API_BASE_URL}${endpoint}`;
// 获取全局token
const app = getApp();
const token = app.globalData.token;
// 构建请求头自动添加Authorization头如果存在token
const headers = {
'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,
data: requestOptions.data,
header: requestOptions.header,
success: (res) => {
// 打印响应信息
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 {
// 优先使用服务器返回的具体错误信息,如果没有则使用默认错误信息
const errorMessage = res.data || res.errMsg || '请求失败';
console.error(`API Error: HTTP ${res.statusCode}: ${errorMessage}`);
reject(new Error(`HTTP ${res.statusCode}: ${errorMessage}`));
}
},
fail: (err) => {
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) {
console.log('API wxLogin调用参数code:', code);
return await this.request('/user/wxlogin', {
method: 'POST',
data: { code: code },
});
}
/**
* 签到接口
* @param userId 用户ID
* @param initialLocation 初始位置数据必须
* @returns 签到结果和员工信息
*/
async userSignIn(userId, initialLocation) {
console.log('API userSignIn调用参数userId:', userId, 'initialLocation:', initialLocation);
// 构建请求数据,必须包含位置数据
const requestData = {
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 || roleUtils_1.Role.DELIVERY_PERSON
},
message: response.message
};
}
/**
* 绑定接口
* @param userInfo 绑定用户信息
* @returns 绑定结果和员工信息
*/
async userRegister(userInfo) {
console.log('API userRegister调用参数userInfo:', userInfo);
// 服务器返回直接的用户信息格式:{id, name, phone, role, openid}
const response = await this.request('/user/register', {
method: 'POST',
data: userInfo,
});
// 检查响应格式,兼容不同的返回格式
if (response.id) {
// 直接返回用户信息格式
return {
success: true,
employeeInfo: {
id: response.id,
name: response.name || userInfo.name,
phone: response.phone || userInfo.phone,
role: response.role || roleUtils_1.Role.DELIVERY_PERSON
},
message: '绑定成功'
};
}
else if (response.userInfo && response.userInfo.id) {
// 包装格式:{success, userInfo, message}
return {
success: response.success !== false,
employeeInfo: {
id: response.userInfo.id,
name: response.userInfo.name || userInfo.name,
phone: response.userInfo.phone || userInfo.phone,
role: response.userInfo.role || roleUtils_1.Role.DELIVERY_PERSON
},
message: response.message
};
}
else {
// 未知格式,返回错误
console.error('未知的绑定响应格式:', response);
return {
success: false,
employeeInfo: {
id: 0,
name: userInfo.name,
phone: userInfo.phone,
role: roleUtils_1.Role.DELIVERY_PERSON
},
message: '绑定响应格式错误'
};
}
}
/**
* 用户登出
*/
async logout() {
return await this.request('/user/logout', { method: 'POST' });
}
/**
* 解绑微信接口
* 清除当前用户的openid绑定允许重新注册其他账号
* @returns 解绑结果
*/
async unbindWechat() {
console.log('API unbindWechat调用');
const response = await this.request('/user/unbind', {
method: 'POST',
data: {}
});
return {
success: response.success,
message: response.message
};
}
/**
* 签退接口
* @param userId 用户ID
* @returns 签退结果
*/
async userSignOut(userId) {
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() {
return await this.request('/user/status', { method: 'GET' });
}
// ====== 信息相关 ======
/**
* 获取当前用户信息
* @returns 用户详细信息
*/
async getUserInfo() {
return await this.request('/user/info');
}
/**
* 更新用户信息
* @param userInfo 待更新的用户信息
* @returns 更新后的用户信息
*/
async updateUserInfo(userInfo) {
return await this.request('/user/update', {
method: 'PUT',
data: userInfo,
});
}
/**
* 获取用户权限列表
* @returns 权限字符串数组
*/
async getUserPermissions() {
return await this.request('/user/permissions');
}
/**
* 检查用户是否在线
* @returns 在线状态
*/
async checkUserOnline() {
return await this.request('/user/online');
}
/**
* 获取用户会话信息
* @returns 会话详细信息
*/
async getSessionInfo() {
return await this.request('/user/session');
}
/**
* 刷新用户令牌
* @param oldToken 旧令牌
* @returns 新令牌及过期时间
*/
async refreshToken(oldToken) {
return await this.request('/user/refresh-token', {
method: 'POST',
data: { token: oldToken },
});
}
/**
* 验证用户权限
* @param permission 待验证的权限
* @returns 是否拥有该权限
*/
async verifyPermission(permission) {
return await this.request(`/user/verify-permission?permission=${permission}`);
}
// ====== 管理相关 ======
/**
* 搜索用户
* @param query 搜索关键词
* @param page 页码
* @param pageSize 每页数量
* @returns 用户列表及分页信息
*/
async searchUsers(query, page = 1, pageSize = 20) {
return await this.request(`/user/search?query=${query}&page=${page}&pageSize=${pageSize}`);
}
/**
* 批量操作用户状态
* @param userIds 用户ID列表
* @param status 目标状态
*/
async batchUpdateUserStatus(userIds, status) {
return await this.request('/user/batch-update-status', {
method: 'POST',
data: { userIds, status },
});
}
// ====== 员工管理接口 ======
/**
* 获取所有员工列表
* @returns 员工信息数组
*/
async getEmployees() {
return await this.request('/employees');
}
/**
* 添加新员工
* @param employeeInfo 员工信息
* @returns 添加结果
*/
async addEmployee(employeeInfo) {
return await this.request('/employees', {
method: 'POST',
data: employeeInfo,
});
}
/**
* 删除员工
* @param employeeId 员工ID
* @returns 删除结果
*/
async deleteEmployee(employeeId) {
return await this.request(`/employees/${employeeId}`, {
method: 'DELETE',
});
}
/**
* 更新员工信息
* @param employeeId 员工ID
* @param employeeInfo 员工信息
* @returns 更新结果
*/
async updateEmployee(employeeId, employeeInfo) {
return await this.request(`/employees/${employeeId}`, {
method: 'PUT',
data: employeeInfo,
});
}
/**
* 上传员工头像
* @param employeeId 员工ID
* @param filePath 头像文件路径
* @returns 上传结果
*/
async uploadEmployeeAvatar(employeeId, filePath) {
return new Promise((resolve, reject) => {
// 使用微信小程序的文件上传API
wx.uploadFile({
url: `${API_BASE_URL}/employees/${employeeId}/avatar`,
filePath: filePath,
name: 'avatar',
header: {
'Authorization': `Bearer ${getApp().globalData.token}`
},
success: (res) => {
if (res.statusCode >= 200 && res.statusCode < 300) {
try {
const data = JSON.parse(res.data);
resolve({
success: true,
avatarUrl: data.avatarUrl
});
}
catch (error) {
resolve({
success: true,
avatarUrl: `${API_BASE_URL}/avatars/${employeeId}.jpg`
});
}
}
else {
reject(new Error(`上传失败: HTTP ${res.statusCode}`));
}
},
fail: (err) => {
reject(new Error(`上传失败: ${err.errMsg}`));
}
});
});
}
/**
* 获取员工头像
* @param employeeId 员工ID
* @returns 头像URL
*/
async getEmployeeAvatar(employeeId) {
try {
// 尝试获取头像信息
const response = await this.request(`/employees/${employeeId}/avatar`);
return response.avatarUrl || `${API_BASE_URL}/avatars/${employeeId}.jpg`;
}
catch (error) {
// 如果获取失败返回默认头像URL
return `${API_BASE_URL}/avatars/${employeeId}.jpg`;
}
}
// ==================== 仓库相关接口 ====================
/**
* 获取所有仓库列表
* @returns 仓库信息数组
*/
async getWarehouses() {
return await this.request('/warehouses');
}
/**
* 获取指定仓库详情
* @param id 仓库ID
* @returns 仓库详细信息
*/
async getWarehouseById(id) {
return await this.request(`/warehouses/${id}`);
}
/**
* 获取仓库相关订单
* @param warehouseId 仓库ID
* @returns 订单列表
*/
async getWarehouseOrders(warehouseId) {
return await this.request(`/warehouses/${warehouseId}/orders`);
}
/**
* 创建仓库
* @param warehouseData 仓库数据
* @returns 创建结果
*/
async createWarehouse(warehouseData) {
return await this.request('/warehouses', {
method: 'POST',
data: warehouseData
});
}
/**
* 更新仓库信息
* @param warehouseId 仓库ID
* @param warehouseInfo 仓库信息
* @returns 更新结果
*/
async updateWarehouse(warehouseId, warehouseInfo) {
return await this.request(`/warehouses/${warehouseId}`, {
method: 'PUT',
data: warehouseInfo
});
}
/**
* 删除仓库
* @param warehouseId 仓库ID
* @returns 删除结果
*/
async deleteWarehouse(warehouseId) {
return await this.request(`/warehouses/${warehouseId}`, {
method: 'DELETE',
});
}
// ==================== 货运人员接口 ====================
/**
* 获取所有货运人员
* @returns 货运人员列表
*/
async getDeliveryPersons() {
return await this.request('/delivery-persons');
}
/**
* 获取所有配送员实时位置
* @returns 所有配送员实时位置信息
*/
async getAllDeliveryPersonLocations() {
return await this.request('/location-sync/delivery-persons/locations');
}
/**
* 获取指定货运人员详情
* @param id 货运人员ID
* @returns 货运人员详细信息
*/
async getDeliveryPersonById(id) {
return await this.request(`/delivery-persons/${id}`);
}
/**
* 更新货运人员位置
* @param id 货运人员ID
* @param location 位置信息
*/
async updateDeliveryPersonLocation(id, location) {
return await this.request(`/delivery-persons/${id}/location`, {
method: 'PUT',
data: location,
});
}
// 地图相关接口支持
/**
* 批量更新货运人员位置兼容mapService参数
* @param locations 位置信息数组
*/
async batchUpdateDeliveryPersonLocations(locations) {
// 转换参数格式以匹配原有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() {
return await this.request('/delivery-persons/idle');
}
/**
* 获取忙碌的货运人员
* @returns 忙碌货运人员列表
*/
async getBusyDeliveryPersons() {
return await this.request('/delivery-persons/busy');
}
/**
* 获取位置历史记录
* @param deliveryPersonId 货运人员ID
* @param limit 记录数量
* @returns 位置历史记录
*/
async getLocationHistory(deliveryPersonId, limit = 50) {
return await this.request(`/delivery-persons/${deliveryPersonId}/location-history?limit=${limit}`);
}
/**
* 订阅实时位置更新接收货运人员ID列表
* @param deliveryPersonIds 货运人员ID列表
* @returns 订阅信息
*/
async subscribeToRealTimeLocations(deliveryPersonIds) {
// 真实环境中调用API
try {
return await this.request('/locations/subscribe', {
method: 'POST',
data: { deliveryPersonIds }
});
}
catch (error) {
console.error('订阅实时位置更新失败:', error);
throw error;
}
}
/**
* 取消订阅实时位置更新
* @param subscriptionId 订阅ID
*/
async unsubscribeFromRealTimeLocations(subscriptionId) {
// 真实环境中调用API
try {
await this.request('/locations/unsubscribe', {
method: 'POST',
data: { subscriptionId }
});
}
catch (error) {
console.error('取消订阅实时位置更新失败:', error);
throw error;
}
}
// ===== 私有属性和方法 =====
/**
* 初始化位置更新WebSocket连接
*/
async initLocationWebSocket() {
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连接是否已建立
*/
isWebSocketConnected() {
return this.locationWebSocket !== null && this.locationWebSocket !== undefined;
}
/**
* 关闭位置更新WebSocket连接
*/
async closeLocationWebSocket() {
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 接收到的消息
*/
handleWebSocketMessage(message) {
if (!message || typeof message.type !== 'string') {
console.warn('收到无效的WebSocket消息:', message);
return;
}
locationTrackingService_1.default.handleWebSocketMessage(message);
}
/**
* 发送WebSocket消息
* @param message 要发送的消息对象
*/
sendWebSocketMessage(message) {
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() {
// 确保WebSocket连接已建立
if (!this.locationWebSocket) {
this.initLocationWebSocket();
}
// 服务器会自动处理订阅逻辑,无需发送订阅消息
console.log('位置订阅已初始化,服务器将自动处理订阅逻辑');
}
/**
* 取消订阅位置更新服务器自动处理无需发送消息
* @param userId 用户ID
*/
async unsubscribeFromLocationUpdates(_userId) {
// 服务器会自动处理取消订阅逻辑,无需发送取消订阅消息
console.log('位置取消订阅已初始化,服务器将自动处理取消订阅逻辑');
}
/**
* 发送位置更新
* @param userId 用户ID
* @param latitude 纬度
* @param longitude 经度
*/
async sendLocationUpdate(userId, latitude, longitude) {
// 确保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() {
return await this.request('/orders/pending');
}
/**
* 指派订单给货运人员
* @param orderId 订单ID
* @param deliveryPersonId 货运人员ID
*/
async assignOrder(orderId, deliveryPersonId) {
return await this.request(`/orders/${orderId}/assign`, {
method: 'POST',
data: { deliveryPersonId },
});
}
/**
* 获取货运人员当前订单
* @param deliveryPersonId 货运人员ID
* @returns 订单列表
*/
async getDeliveryPersonOrders(deliveryPersonId) {
return await this.request(`/delivery-persons/${deliveryPersonId}/orders`);
}
/**
* 根据ID获取订单
* @param id 订单ID
* @returns 订单详细信息
*/
async getOrderById(id) {
return await this.request(`/orders/${id}`);
}
/**
* 更新订单状态
* @param orderId 订单ID
* @param status 目标状态
*/
async updateOrderStatus(orderId, status) {
return await this.request(`/orders/${orderId}/status`, {
method: 'PUT',
data: { status },
});
}
/**
* 创建新订单
* @param orderData 订单数据
* @returns 创建的订单信息
*/
async createOrder(orderData) {
return await this.request('/orders', {
method: 'POST',
data: orderData,
});
}
/**
* 删除订单
* @param orderId 订单ID
*/
async deleteOrder(orderId) {
return await this.request(`/orders/${orderId}`, {
method: 'DELETE',
});
}
// ==================== 统计和日志接口 ====================
/**
* 获取系统统计信息
* @returns 系统统计数据
*/
async getSystemStats() {
return await this.request('/stats/system');
}
/**
* 获取订单统计信息
* @param timeRange 时间范围
* @returns 订单统计数据
*/
async getOrderStats(timeRange) {
return await this.request(`/stats/orders?timeRange=${timeRange}`);
}
/**
* 获取用户统计信息
* @returns 用户统计数据
*/
async getUserStats() {
return await this.request('/user/stats');
}
/**
* 获取用户活动日志
* @param userId 用户ID
* @param limit 日志数量
* @returns 活动日志列表
*/
async getUserActivityLogs(userId, limit = 20) {
return await this.request(`/user/${userId}/activity-logs?limit=${limit}`);
}
/**
* 上传错误日志
* @param error 错误信息
*/
async uploadErrorLog(error) {
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() {
return await this.request('/health');
}
}
/**
* API服务单例实例
* 导出供应用程序全局使用
*/
exports.default = new ApiService();