地址路径修改
This commit is contained in:
883
dist/services/apiService.js
vendored
Normal file
883
dist/services/apiService.js
vendored
Normal file
@@ -0,0 +1,883 @@
|
||||
"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();
|
||||
88
dist/services/deliveryPersonService.js
vendored
Normal file
88
dist/services/deliveryPersonService.js
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const apiService_1 = __importDefault(require("./apiService"));
|
||||
/**
|
||||
* 货运人员服务类
|
||||
* 提供货运人员信息管理、状态管理等功能
|
||||
*/
|
||||
class DeliveryPersonService {
|
||||
/**
|
||||
* 构造函数
|
||||
*/
|
||||
constructor() {
|
||||
// 不再使用模拟数据
|
||||
}
|
||||
/**
|
||||
* 获取所有货运人员
|
||||
* @returns 货运人员列表
|
||||
*/
|
||||
async getDeliveryPersons() {
|
||||
return apiService_1.default.getDeliveryPersons();
|
||||
}
|
||||
/**
|
||||
* 根据ID获取货运人员
|
||||
* @param id 货运人员ID
|
||||
* @returns 货运人员信息或null
|
||||
*/
|
||||
async getDeliveryPersonById(id) {
|
||||
try {
|
||||
const result = await apiService_1.default.getDeliveryPersonById(id);
|
||||
return result;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('获取货运人员失败:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取空闲的货运人员
|
||||
* @returns 空闲货运人员列表
|
||||
*/
|
||||
async getIdleDeliveryPersons() {
|
||||
return apiService_1.default.getIdleDeliveryPersons();
|
||||
}
|
||||
/**
|
||||
* 获取忙碌的货运人员
|
||||
* @returns 忙碌货运人员列表
|
||||
*/
|
||||
async getBusyDeliveryPersons() {
|
||||
return apiService_1.default.getBusyDeliveryPersons();
|
||||
}
|
||||
/**
|
||||
* 获取货运人员当前订单
|
||||
* @param deliveryPersonId 货运人员ID
|
||||
* @returns 订单列表
|
||||
*/
|
||||
async getDeliveryPersonOrders(deliveryPersonId) {
|
||||
return apiService_1.default.getDeliveryPersonOrders(deliveryPersonId);
|
||||
}
|
||||
/**
|
||||
* 获取货运人员头像URL
|
||||
* @param deliveryPersonId 货运人员ID
|
||||
* @returns 头像URL
|
||||
*/
|
||||
async getAvatarUrl(deliveryPersonId) {
|
||||
try {
|
||||
// 首先尝试获取货运人员详细信息
|
||||
const deliveryPerson = await this.getDeliveryPersonById(deliveryPersonId);
|
||||
if (deliveryPerson && deliveryPerson.avatarUrl) {
|
||||
return deliveryPerson.avatarUrl;
|
||||
}
|
||||
// 如果货运人员信息中没有头像URL,尝试使用员工服务获取
|
||||
const employeeService = require('./employeeService').default;
|
||||
return await employeeService.getAvatarUrl(deliveryPersonId);
|
||||
}
|
||||
catch (error) {
|
||||
console.error('获取货运人员头像失败:', error);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 货运人员服务单例实例
|
||||
* 导出供应用程序全局使用
|
||||
*/
|
||||
exports.default = new DeliveryPersonService();
|
||||
147
dist/services/employeeService.js
vendored
Normal file
147
dist/services/employeeService.js
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const apiService_1 = __importDefault(require("./apiService"));
|
||||
/**
|
||||
* 员工管理服务类
|
||||
* 提供员工信息的增删改查功能
|
||||
*/
|
||||
class EmployeeService {
|
||||
/**
|
||||
* 构造函数
|
||||
*/
|
||||
constructor() {
|
||||
// 不再使用模拟数据
|
||||
}
|
||||
/**
|
||||
* 获取所有员工列表
|
||||
* @returns 员工信息数组
|
||||
*/
|
||||
async getEmployees() {
|
||||
try {
|
||||
return await apiService_1.default.getEmployees();
|
||||
}
|
||||
catch (error) {
|
||||
console.error('获取员工列表失败:', error);
|
||||
// API调用失败时返回空数组
|
||||
return [];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 添加新员工
|
||||
* @param employeeInfo 员工信息
|
||||
* @returns 添加的员工信息
|
||||
*/
|
||||
async addEmployee(employeeInfo) {
|
||||
try {
|
||||
return await apiService_1.default.addEmployee(employeeInfo);
|
||||
}
|
||||
catch (error) {
|
||||
console.error('添加员工失败:', error);
|
||||
throw new Error('添加员工失败,请稍后重试');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 删除员工
|
||||
* @param employeeId 员工ID
|
||||
* @returns 删除结果
|
||||
*/
|
||||
async deleteEmployee(employeeId) {
|
||||
try {
|
||||
return await apiService_1.default.deleteEmployee(employeeId);
|
||||
}
|
||||
catch (error) {
|
||||
console.error('删除员工失败:', error);
|
||||
return {
|
||||
success: false,
|
||||
message: '删除员工失败,请稍后重试'
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 更新员工信息
|
||||
* @param employeeId 员工ID
|
||||
* @param employeeInfo 员工信息
|
||||
* @returns 更新后的员工信息
|
||||
*/
|
||||
async updateEmployee(employeeId, employeeInfo) {
|
||||
try {
|
||||
return await apiService_1.default.updateEmployee(employeeId, employeeInfo);
|
||||
}
|
||||
catch (error) {
|
||||
console.error('更新员工信息失败:', error);
|
||||
throw new Error('更新员工信息失败,请稍后重试');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 根据工号查找员工
|
||||
* @param phone 工号
|
||||
* @returns 员工信息或null
|
||||
*/
|
||||
async findEmployeeByPhone(phone) {
|
||||
const employees = await this.getEmployees();
|
||||
return employees.find(emp => emp.phone === phone) || null;
|
||||
}
|
||||
/**
|
||||
* 验证员工信息(用于绑定时检查)
|
||||
* @param name 姓名
|
||||
* @param phone 工号
|
||||
* @returns 验证结果
|
||||
*/
|
||||
async validateEmployee(name, phone) {
|
||||
const employees = await this.getEmployees();
|
||||
const employee = employees.find(emp => emp.name === name && emp.phone === phone);
|
||||
if (employee) {
|
||||
return {
|
||||
success: true,
|
||||
message: '员工信息验证成功',
|
||||
employee
|
||||
};
|
||||
}
|
||||
else {
|
||||
return {
|
||||
success: false,
|
||||
message: '员工信息不存在,请联系管理员添加'
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 上传员工头像
|
||||
* @param employeeId 员工ID
|
||||
* @param filePath 头像文件路径
|
||||
* @returns 上传结果
|
||||
*/
|
||||
async uploadAvatar(employeeId, filePath) {
|
||||
try {
|
||||
return await apiService_1.default.uploadEmployeeAvatar(employeeId, filePath);
|
||||
}
|
||||
catch (error) {
|
||||
console.error('上传头像失败:', error);
|
||||
return {
|
||||
success: false,
|
||||
message: '上传头像失败,请稍后重试'
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取员工头像URL
|
||||
* @param employeeId 员工ID
|
||||
* @returns 头像URL
|
||||
*/
|
||||
async getAvatarUrl(employeeId) {
|
||||
try {
|
||||
return await apiService_1.default.getEmployeeAvatar(employeeId);
|
||||
}
|
||||
catch (error) {
|
||||
console.error('获取头像失败:', error);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 员工管理服务单例实例
|
||||
* 导出供应用程序全局使用
|
||||
*/
|
||||
exports.default = new EmployeeService();
|
||||
482
dist/services/locationTrackingService.js
vendored
Normal file
482
dist/services/locationTrackingService.js
vendored
Normal file
@@ -0,0 +1,482 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const apiService_1 = __importDefault(require("./apiService"));
|
||||
const userService_1 = __importDefault(require("./userService"));
|
||||
const mapService_1 = __importDefault(require("./mapService"));
|
||||
/**
|
||||
* 位置追踪服务类
|
||||
* 提供用户签到后的位置追踪、状态管理和位置分发功能
|
||||
*/
|
||||
class LocationTrackingService {
|
||||
/**
|
||||
* 构造函数
|
||||
*/
|
||||
constructor() {
|
||||
// 取消订阅回调函数
|
||||
this.unsubscribeCallback = null;
|
||||
this.onlineUsers = new Map();
|
||||
this.locationUpdateTimer = null;
|
||||
this.userStatusCallback = null;
|
||||
this.locationUpdateCallback = null;
|
||||
this.isSignedIn = false;
|
||||
this.unsubscribeCallback = null;
|
||||
}
|
||||
/**
|
||||
* 启动位置追踪服务(WebSocket连接)
|
||||
*/
|
||||
async startTracking() {
|
||||
const userInfo = userService_1.default.getGlobalUserInfo();
|
||||
if (!userInfo || !userInfo.id) {
|
||||
throw new Error('用户未登录,无法启动位置追踪');
|
||||
}
|
||||
this.isSignedIn = true;
|
||||
// 设置实时位置订阅(初始化WebSocket连接)
|
||||
await this.setupRealTimeSubscription();
|
||||
// 启动位置更新定时器(每30秒向服务器发送位置信息)
|
||||
this.startLocationUpdateTimer();
|
||||
console.log('位置追踪服务已启动');
|
||||
}
|
||||
/**
|
||||
* 初始化位置追踪服务
|
||||
*/
|
||||
async initialize() {
|
||||
}
|
||||
/**
|
||||
* 停止位置追踪服务(WebSocket断开时调用)
|
||||
*/
|
||||
async stopTracking() {
|
||||
const userInfo = userService_1.default.getGlobalUserInfo();
|
||||
if (!userInfo || !userInfo.id) {
|
||||
return;
|
||||
}
|
||||
this.isSignedIn = false;
|
||||
// 停止位置更新定时器
|
||||
this.stopLocationUpdateTimer();
|
||||
// 关闭WebSocket连接
|
||||
try {
|
||||
await this.teardownRealTimeSubscription();
|
||||
console.log('调试信息 - WebSocket连接已关闭');
|
||||
}
|
||||
catch (error) {
|
||||
console.warn('调试信息 - 关闭WebSocket连接失败:', error);
|
||||
}
|
||||
// 清空在线用户列表(WebSocket断开时清空所有数据)
|
||||
this.onlineUsers.clear();
|
||||
// 通知所有位置更新回调,清空地图标记点
|
||||
this.notifyLocationUpdateCallbacks();
|
||||
console.log('位置追踪服务已停止,在线用户列表已清空');
|
||||
}
|
||||
/**
|
||||
* 向服务器发送位置更新(仅发送,不更新本地缓存)
|
||||
*/
|
||||
async updateUserLocation(location) {
|
||||
const userInfo = userService_1.default.getGlobalUserInfo();
|
||||
if (!userInfo || !userInfo.id || !this.isSignedIn) {
|
||||
console.warn('[位置追踪服务] 用户未登录或未签到,无法更新位置');
|
||||
return;
|
||||
}
|
||||
console.log('[位置追踪服务] 向服务器发送位置信息:');
|
||||
console.log(`- 用户ID: ${userInfo.id}`);
|
||||
console.log(`- 经度: ${location.longitude}`);
|
||||
console.log(`- 纬度: ${location.latitude}`);
|
||||
// 通过WebSocket发送位置更新给服务器
|
||||
await apiService_1.default.sendLocationUpdate(userInfo.id, location.latitude, location.longitude);
|
||||
console.log('[位置追踪服务] 位置信息已发送到服务器');
|
||||
}
|
||||
/**
|
||||
* 获取所有在线用户信息
|
||||
*/
|
||||
getOnlineUsers() {
|
||||
return Array.from(this.onlineUsers.values()).filter(user => user.status === 'online');
|
||||
}
|
||||
/**
|
||||
* 订阅用户状态变化(单一方法赋值)
|
||||
* @param callback 用户状态变化回调函数
|
||||
* @returns 取消订阅函数
|
||||
*/
|
||||
subscribeToUserStatusChanges(callback) {
|
||||
console.log('📝 [LocationTrackingService] 注册用户状态变化回调函数');
|
||||
// 直接赋值,覆盖之前的回调
|
||||
this.userStatusCallback = callback;
|
||||
console.log('✅ [LocationTrackingService] 用户状态变化回调注册完成');
|
||||
// 返回取消订阅函数
|
||||
return () => {
|
||||
if (this.userStatusCallback === callback) {
|
||||
this.userStatusCallback = null;
|
||||
console.log('✅ [LocationTrackingService] 用户状态变化回调已取消');
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* 检查用户是否在线
|
||||
*/
|
||||
isUserOnline(userId) {
|
||||
const userInfo = this.onlineUsers.get(userId);
|
||||
return userInfo ? userInfo.status === 'online' : false;
|
||||
}
|
||||
// ===== 私有方法 =====
|
||||
/**
|
||||
* 启动位置更新定时器
|
||||
*/
|
||||
startLocationUpdateTimer() {
|
||||
this.stopLocationUpdateTimer();
|
||||
this.locationUpdateTimer = setInterval(async () => {
|
||||
if (this.isSignedIn) {
|
||||
try {
|
||||
const location = await this.getCurrentLocation();
|
||||
await this.updateUserLocation(location);
|
||||
}
|
||||
catch (error) {
|
||||
console.error('自动位置更新失败:', error);
|
||||
}
|
||||
}
|
||||
}, 30000); // 每30秒更新一次
|
||||
}
|
||||
/**
|
||||
* 获取当前位置
|
||||
*/
|
||||
async getCurrentLocation() {
|
||||
const userInfo = userService_1.default.getGlobalUserInfo();
|
||||
if (!userInfo || !userInfo.id) {
|
||||
throw new Error('用户未登录');
|
||||
}
|
||||
try {
|
||||
// 使用mapService获取真实位置,保持与项目中其他地方的一致性
|
||||
const location = await mapService_1.default.getLocation();
|
||||
console.log('[位置追踪服务] 获取真实位置成功:', location);
|
||||
return {
|
||||
userId: userInfo.id,
|
||||
longitude: location.longitude,
|
||||
latitude: location.latitude,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
console.error('[位置追踪服务] 获取真实位置失败,使用默认位置:', error);
|
||||
// 定位失败时返回默认位置作为降级方案
|
||||
return {
|
||||
userId: userInfo.id,
|
||||
longitude: 102.833722,
|
||||
latitude: 24.880095,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 设置实时位置订阅
|
||||
*/
|
||||
async setupRealTimeSubscription() {
|
||||
// 获取用户信息
|
||||
const userInfo = userService_1.default.getGlobalUserInfo();
|
||||
if (!userInfo || !userInfo.id) {
|
||||
console.warn('用户未登录,无法设置实时位置订阅');
|
||||
return;
|
||||
}
|
||||
// 缓存用户信息(已移除)
|
||||
// 真实环境:初始化WebSocket连接(服务器会自动处理订阅逻辑)
|
||||
try {
|
||||
// 初始化WebSocket连接(如果尚未连接)
|
||||
await apiService_1.default.initLocationWebSocket();
|
||||
// 等待WebSocket连接建立(最多等待5秒)
|
||||
await new Promise((resolve, reject) => {
|
||||
let attempts = 0;
|
||||
const maxAttempts = 50; // 5秒超时
|
||||
const checkConnection = () => {
|
||||
if (apiService_1.default.isWebSocketConnected()) {
|
||||
resolve();
|
||||
}
|
||||
else if (attempts < maxAttempts) {
|
||||
attempts++;
|
||||
setTimeout(checkConnection, 100);
|
||||
}
|
||||
else {
|
||||
reject(new Error('WebSocket连接建立超时'));
|
||||
}
|
||||
};
|
||||
checkConnection();
|
||||
});
|
||||
// 服务器会自动处理订阅逻辑,无需发送订阅消息
|
||||
console.log('WebSocket连接已建立,服务器将自动处理位置订阅逻辑');
|
||||
}
|
||||
catch (error) {
|
||||
console.error('设置实时位置订阅失败:', error);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 关闭实时位置订阅
|
||||
*/
|
||||
teardownRealTimeSubscription() {
|
||||
// 真实环境:关闭WebSocket连接(服务器会自动处理取消订阅逻辑)
|
||||
try {
|
||||
// 服务器会自动处理取消订阅逻辑,无需发送取消订阅消息
|
||||
console.log('关闭WebSocket连接,服务器将自动处理取消订阅逻辑');
|
||||
// 移除位置更新回调
|
||||
if (this.unsubscribeCallback) {
|
||||
this.unsubscribeCallback();
|
||||
this.unsubscribeCallback = null;
|
||||
}
|
||||
// 关闭WebSocket连接
|
||||
apiService_1.default.closeLocationWebSocket();
|
||||
}
|
||||
catch (error) {
|
||||
console.error('关闭实时位置订阅失败:', error);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 停止位置更新定时器
|
||||
*/
|
||||
stopLocationUpdateTimer() {
|
||||
if (this.locationUpdateTimer) {
|
||||
clearInterval(this.locationUpdateTimer);
|
||||
this.locationUpdateTimer = null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 通知位置更新回调
|
||||
*/
|
||||
notifyLocationUpdateCallbacks() {
|
||||
const onlineUsers = this.getOnlineUsers();
|
||||
console.log('🔔 [LocationTrackingService] 开始通知位置更新回调');
|
||||
console.log('👥 [LocationTrackingService] 在线用户数量:', onlineUsers.length);
|
||||
// 触发位置更新回调
|
||||
if (this.locationUpdateCallback) {
|
||||
try {
|
||||
console.log('🔄 [LocationTrackingService] 执行位置更新回调');
|
||||
this.locationUpdateCallback(onlineUsers);
|
||||
console.log('✅ [LocationTrackingService] 位置更新回调执行成功');
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ [LocationTrackingService] 位置更新回调执行失败:', error);
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log('⚠️ [LocationTrackingService] 没有注册位置更新回调');
|
||||
}
|
||||
console.log('🏁 [LocationTrackingService] 位置更新回调通知完成');
|
||||
}
|
||||
/**
|
||||
* 手动触发位置更新(公共方法,可从外部调用)
|
||||
* 用于手动刷新地图上的用户标记
|
||||
*/
|
||||
triggerLocationUpdate() {
|
||||
console.log('🔔 [LocationTrackingService] 手动触发位置更新');
|
||||
this.notifyLocationUpdateCallbacks();
|
||||
}
|
||||
/**
|
||||
* 订阅位置更新(用于locationModule注册回调)
|
||||
* @param callback 位置更新回调函数
|
||||
* @returns 取消订阅函数
|
||||
*/
|
||||
subscribeToLocationUpdates(callback) {
|
||||
console.log('📝 [LocationTrackingService] 注册位置更新回调函数');
|
||||
// 直接赋值,覆盖之前的回调
|
||||
this.locationUpdateCallback = callback;
|
||||
console.log('✅ [LocationTrackingService] 位置更新回调注册完成');
|
||||
// 返回取消订阅函数
|
||||
return () => {
|
||||
if (this.locationUpdateCallback === callback) {
|
||||
this.locationUpdateCallback = null;
|
||||
console.log('✅ [LocationTrackingService] 位置更新回调已取消');
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* 通知用户状态变化回调
|
||||
*/
|
||||
notifyUserStatusChange(userId, status) {
|
||||
console.log(`🔔 [LocationTrackingService] 开始通知用户状态变化回调: 用户 ${userId} 状态变为 ${status}`);
|
||||
if (this.userStatusCallback) {
|
||||
try {
|
||||
console.log('🔄 [LocationTrackingService] 执行用户状态变化回调');
|
||||
this.userStatusCallback(userId, status);
|
||||
console.log('✅ [LocationTrackingService] 用户状态变化回调执行成功');
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ [LocationTrackingService] 用户状态变化回调执行失败:', error);
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log('⚠️ [LocationTrackingService] 没有注册用户状态变化回调');
|
||||
}
|
||||
console.log('🏁 [LocationTrackingService] 用户状态变化回调通知完成');
|
||||
}
|
||||
/**
|
||||
* 处理WebSocket消息
|
||||
* @param message 服务器下发的消息
|
||||
*/
|
||||
handleWebSocketMessage(message) {
|
||||
console.log(`📡 收到WebSocket消息类型: ${message.type}`, message);
|
||||
switch (message.type) {
|
||||
case 'onlineUserList':
|
||||
// 处理在线用户列表消息(服务器发送当前在线用户列表)
|
||||
console.log('👥 处理在线用户列表,用户数量:', message.users ? message.users.length : 0);
|
||||
if (message.users && Array.isArray(message.users)) {
|
||||
this.triggerOnlineUserListCallbacks({
|
||||
type: 'onlineUserList',
|
||||
users: message.users.map((user) => ({
|
||||
userId: user.userId,
|
||||
name: user.name,
|
||||
role: user.role,
|
||||
userStatus: user.userStatus,
|
||||
lastUpdateTime: user.lastUpdateTime,
|
||||
latitude: user.locationData?.latitude || user.latitude,
|
||||
longitude: user.locationData?.longitude || user.longitude,
|
||||
timestamp: user.locationData?.timestamp || user.timestamp
|
||||
}))
|
||||
});
|
||||
}
|
||||
else {
|
||||
console.warn('❌ onlineUserList消息格式错误,users字段不存在或不是数组');
|
||||
}
|
||||
break;
|
||||
case 'userLocationList':
|
||||
// 处理用户位置列表消息(服务器每30秒发送所有在线用户的位置列表)
|
||||
console.log('👥 处理用户位置列表,用户数量:', message.users ? message.users.length : 0);
|
||||
// 确保用户列表存在且是数组
|
||||
if (message.users && Array.isArray(message.users)) {
|
||||
// 转换用户数据格式,确保与位置追踪服务兼容
|
||||
const formattedUsers = message.users.map((user) => {
|
||||
// 支持多种数据格式:locationData字段或直接字段
|
||||
const locationData = user.locationData || user;
|
||||
// 验证必需字段是否存在
|
||||
if (!user.userId && !locationData.userId) {
|
||||
console.error('❌ 用户数据缺少userId字段:', user);
|
||||
return null;
|
||||
}
|
||||
if (locationData.latitude === undefined || locationData.longitude === undefined) {
|
||||
console.error('❌ 用户数据缺少位置信息:', user);
|
||||
return null;
|
||||
}
|
||||
// 对于位置更新消息,允许缺少name和role字段,从本地缓存中获取
|
||||
const existingUser = this.onlineUsers.get(user.userId || locationData.userId);
|
||||
const formattedUser = {
|
||||
userId: user.userId || locationData.userId,
|
||||
name: user.name || user.userName || (existingUser ? existingUser.name : `用户${user.userId || locationData.userId}`),
|
||||
role: user.role || (existingUser ? existingUser.role : 'DRIVER'),
|
||||
userStatus: user.userStatus !== false, // 转换为布尔值
|
||||
lastUpdateTime: user.lastUpdateTime || locationData.timestamp || Date.now(),
|
||||
latitude: locationData.latitude,
|
||||
longitude: locationData.longitude,
|
||||
timestamp: locationData.timestamp || user.timestamp || Date.now()
|
||||
};
|
||||
// 验证必需字段
|
||||
if (!formattedUser.userId) {
|
||||
console.error('❌ 用户数据缺少userId字段:', formattedUser);
|
||||
return null;
|
||||
}
|
||||
return formattedUser;
|
||||
}).filter((user) => user !== null); // 过滤掉无效数据
|
||||
console.log('📊 转换后的用户位置数据:', formattedUsers);
|
||||
this.triggerOnlineUserListCallbacks({
|
||||
type: 'userLocationList',
|
||||
users: formattedUsers
|
||||
});
|
||||
}
|
||||
else {
|
||||
console.warn('❌ userLocationList消息格式错误,users字段不存在或不是数组');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.warn('收到未知类型的WebSocket消息:', message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 触发在线用户列表回调函数
|
||||
* @param userList 在线用户列表数据
|
||||
*/
|
||||
triggerOnlineUserListCallbacks(userList) {
|
||||
console.log('🔔 [apiService] 开始触发在线用户列表回调,消息类型:', userList.type);
|
||||
console.log('📊 [apiService] 回调数据内容:', JSON.stringify(userList, null, 2));
|
||||
try {
|
||||
console.log('🔄 [apiService] 执行在线用户列表回调函数');
|
||||
// 传递正确的数据格式:只传递users数组,而不是整个消息对象
|
||||
this.handleOnlineUserList(userList.users);
|
||||
console.log('✅ [apiService] 在线用户列表回调函数执行成功');
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ [apiService] 在线用户列表回调函数执行失败:', error);
|
||||
}
|
||||
console.log('🏁 [apiService] 在线用户列表回调触发完成');
|
||||
}
|
||||
/**
|
||||
* 处理在线用户列表
|
||||
* @param userList 服务器下发的在线用户列表
|
||||
*/
|
||||
handleOnlineUserList(userList) {
|
||||
try {
|
||||
// 验证数据格式
|
||||
if (!Array.isArray(userList)) {
|
||||
console.warn('[LocationTrackingService] 无效的在线用户列表数据格式');
|
||||
return;
|
||||
}
|
||||
console.log(`[LocationTrackingService] 开始处理在线用户列表,用户数量: ${userList.length}`);
|
||||
// 获取当前本地用户列表的userId集合
|
||||
const currentUserIds = new Set(this.onlineUsers.keys());
|
||||
// 处理服务器下发的用户列表
|
||||
const newUserIds = new Set();
|
||||
userList.forEach(user => {
|
||||
if (user && user.userId && user.latitude !== undefined && user.longitude !== undefined) {
|
||||
newUserIds.add(user.userId);
|
||||
// 提取位置数据(支持多种数据格式)
|
||||
const latitude = user.latitude;
|
||||
const longitude = user.longitude;
|
||||
const timestamp = user.timestamp || user.lastUpdateTime || Date.now();
|
||||
// 对于位置更新消息,允许缺少name和role字段,从本地缓存中获取
|
||||
const existingUser = this.onlineUsers.get(user.userId);
|
||||
// 更新或添加用户信息
|
||||
this.onlineUsers.set(user.userId, {
|
||||
userId: user.userId,
|
||||
name: user.name || user.userName || (existingUser ? existingUser.name : `用户${user.userId}`),
|
||||
avatarUrl: '/images/user-avatar.png',
|
||||
role: user.role || (existingUser ? existingUser.role : 'DRIVER'),
|
||||
lastLocation: {
|
||||
userId: user.userId,
|
||||
longitude: longitude,
|
||||
latitude: latitude,
|
||||
timestamp: timestamp
|
||||
},
|
||||
lastUpdateTime: timestamp,
|
||||
status: user.userStatus === false ? 'offline' : 'online'
|
||||
});
|
||||
console.log(`[LocationTrackingService] 更新用户 ${user.userId} 位置: (${latitude}, ${longitude})`);
|
||||
// 如果用户是新上线的,触发用户状态回调
|
||||
if (!currentUserIds.has(user.userId)) {
|
||||
this.notifyUserStatusChange(user.userId, 'online');
|
||||
console.log(`[LocationTrackingService] 新用户上线: ${user.userId}`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.warn(`[LocationTrackingService] 跳过无效用户数据:`, user);
|
||||
}
|
||||
});
|
||||
// 删除本地列表中不在服务器列表中的用户
|
||||
let removedCount = 0;
|
||||
currentUserIds.forEach(userId => {
|
||||
if (!newUserIds.has(userId)) {
|
||||
// 删除离线用户
|
||||
this.onlineUsers.delete(userId);
|
||||
removedCount++;
|
||||
// 触发用户状态回调(离线)
|
||||
this.notifyUserStatusChange(userId, 'offline');
|
||||
console.log(`[LocationTrackingService] 用户离线: ${userId}`);
|
||||
}
|
||||
});
|
||||
console.log(`[LocationTrackingService] 在线用户列表更新完成: 新增 ${newUserIds.size - (currentUserIds.size - removedCount)} 个用户,删除 ${removedCount} 个用户`);
|
||||
// 通知位置模块更新地图标记点(无论是否有变化都通知,确保地图标记点同步)
|
||||
this.notifyLocationUpdateCallbacks();
|
||||
console.log('[LocationTrackingService] 已通知位置模块更新地图标记点');
|
||||
}
|
||||
catch (error) {
|
||||
console.error('[LocationTrackingService] 处理在线用户列表失败:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 位置追踪服务单例实例
|
||||
* 导出供应用程序全局使用
|
||||
*/
|
||||
exports.default = new LocationTrackingService();
|
||||
350
dist/services/mapService.js
vendored
Normal file
350
dist/services/mapService.js
vendored
Normal file
@@ -0,0 +1,350 @@
|
||||
"use strict";
|
||||
// 地图服务 - 处理地图相关的功能,包括定位、路线规划、地理编码等
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
/**
|
||||
* 地图服务类
|
||||
* 提供地图相关功能,包括定位、路线规划、地理编码等
|
||||
*/
|
||||
class MapService {
|
||||
/**
|
||||
* 构造函数,初始化地图实例
|
||||
*/
|
||||
constructor() {
|
||||
this.amapFile = require('../libs/amap-wx.js');
|
||||
this.MAP_KEY = '1fc5cafd570d9fbfd14c39359d41823d';
|
||||
this.KUNMING_CENTER = {
|
||||
longitude: 102.833722,
|
||||
latitude: 24.880095
|
||||
};
|
||||
this.amapInstance = new this.amapFile.AMapWX({ key: this.MAP_KEY });
|
||||
}
|
||||
/**
|
||||
* 获取用户位置信息
|
||||
* @returns 用户位置坐标
|
||||
*/
|
||||
async getLocation() {
|
||||
return new Promise((resolve, reject) => {
|
||||
console.log('开始调用高德地图SDK获取位置...');
|
||||
// 添加超时机制
|
||||
const timeout = setTimeout(() => {
|
||||
console.error('高德地图SDK调用超时,使用模拟位置');
|
||||
resolve({
|
||||
longitude: 102.7123,
|
||||
latitude: 25.0409
|
||||
});
|
||||
}, 10000); // 10秒超时
|
||||
try {
|
||||
// 高德地图SDK的getWxLocation方法需要两个参数:配置对象和回调函数
|
||||
this.amapInstance.getWxLocation({
|
||||
type: 'gcj02', // 使用国测局坐标系
|
||||
success: (res) => {
|
||||
clearTimeout(timeout);
|
||||
console.log('高德地图SDK定位成功:', res);
|
||||
resolve(res);
|
||||
},
|
||||
fail: (err) => {
|
||||
clearTimeout(timeout);
|
||||
console.error('高德地图SDK定位失败:', err);
|
||||
// 注释:高德SDK失败后,直接使用模拟位置,不调用微信原生API
|
||||
// 原因:微信小程序可能没有位置权限,避免权限错误
|
||||
console.log('高德地图SDK定位失败,使用模拟位置');
|
||||
resolve({
|
||||
longitude: 102.7123,
|
||||
latitude: 25.0409
|
||||
});
|
||||
}
|
||||
}, (locationString) => {
|
||||
// 这是高德地图SDK的回调函数,参数是格式化的位置字符串
|
||||
console.log('高德地图SDK格式化位置:', locationString);
|
||||
// 如果格式化位置回调被调用,说明SDK已经获取到位置
|
||||
// 尝试从格式化字符串中解析经纬度
|
||||
if (locationString) {
|
||||
const coords = locationString.split(',');
|
||||
if (coords.length === 2) {
|
||||
const longitude = parseFloat(coords[0]);
|
||||
const latitude = parseFloat(coords[1]);
|
||||
if (!isNaN(longitude) && !isNaN(latitude)) {
|
||||
clearTimeout(timeout);
|
||||
console.log('从格式化位置解析成功,使用解析的位置:', { longitude, latitude });
|
||||
resolve({ longitude, latitude });
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 如果无法解析,继续等待success回调
|
||||
console.log('格式化位置回调被调用,但无法解析位置,继续等待success回调...');
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
clearTimeout(timeout);
|
||||
console.error('高德地图SDK调用异常:', error);
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 获取当前位置信息(兼容格式)
|
||||
* @returns 当前位置的详细信息
|
||||
*/
|
||||
async getCurrentLocation() {
|
||||
const location = await this.getLocation();
|
||||
return {
|
||||
latitude: location.latitude,
|
||||
longitude: location.longitude,
|
||||
accuracy: 50,
|
||||
speed: 0,
|
||||
altitude: 1891
|
||||
};
|
||||
}
|
||||
/**
|
||||
* 获取位置详细信息(逆地理编码)
|
||||
* @param longitude 经度
|
||||
* @param latitude 纬度
|
||||
* @returns 逆地理编码结果
|
||||
*/
|
||||
async getLocationInfo(longitude, latitude) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.amapInstance.getRegeo({
|
||||
location: `${longitude.toFixed(6)},${latitude.toFixed(6)}`,
|
||||
success: (res) => {
|
||||
console.log('逆地理编码成功:', res);
|
||||
resolve(res);
|
||||
},
|
||||
fail: (err) => {
|
||||
console.log('逆地理编码失败:', err);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 获取昆明中心点坐标
|
||||
* @returns 昆明中心点坐标
|
||||
*/
|
||||
getKunmingCenter() {
|
||||
return this.KUNMING_CENTER;
|
||||
}
|
||||
/**
|
||||
* 搜索地点
|
||||
* @param keyword 搜索关键词
|
||||
* @param city 城市名称
|
||||
* @returns 搜索结果列表
|
||||
*/
|
||||
async searchPoi(keyword, city) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.amapInstance.getPoiAround({
|
||||
querykeywords: keyword,
|
||||
city: city,
|
||||
radius: 50000, // 搜索半径50公里
|
||||
offset: 20, // 返回20条结果
|
||||
success: (res) => {
|
||||
console.log('搜索POI成功:', res);
|
||||
if (res.pois && res.pois.length > 0) {
|
||||
const results = res.pois.map((poi) => ({
|
||||
id: poi.id,
|
||||
name: poi.name,
|
||||
address: poi.address,
|
||||
longitude: parseFloat(poi.location.split(',')[0]),
|
||||
latitude: parseFloat(poi.location.split(',')[1]),
|
||||
phone: poi.tel || ''
|
||||
}));
|
||||
resolve(results);
|
||||
}
|
||||
else {
|
||||
resolve([]);
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('搜索POI失败:', err);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 规划驾车路线
|
||||
* @param origin 起点坐标字符串 (经度,纬度)
|
||||
* @param destination 终点坐标字符串 (经度,纬度)
|
||||
* @returns 路线规划结果
|
||||
*/
|
||||
async getDrivingRoute(origin, destination) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.amapInstance.getDrivingRoute({
|
||||
origin,
|
||||
destination,
|
||||
strategy: '0', // 推荐路线策略
|
||||
showtraffic: false, // 不显示交通状况
|
||||
success: (res) => {
|
||||
console.log('高德地图路线规划API调用成功');
|
||||
if (res.paths && res.paths.length > 0) {
|
||||
const path = res.paths[0];
|
||||
const result = {
|
||||
polyline: path.polyline || '',
|
||||
distance: path.distance || 0,
|
||||
duration: path.duration || 0
|
||||
};
|
||||
console.log(`路线规划完成: 距离${result.distance}米, 预计${result.duration}秒`);
|
||||
resolve(result);
|
||||
}
|
||||
else {
|
||||
resolve({
|
||||
polyline: '',
|
||||
distance: 0,
|
||||
duration: 0
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('高德地图路线规划API调用失败:', err);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 计算两点之间的距离(米)
|
||||
* @param lat1 第一个点的纬度
|
||||
* @param lng1 第一个点的经度
|
||||
* @param lat2 第二个点的纬度
|
||||
* @param lng2 第二个点的经度
|
||||
* @returns 两点之间的距离(米)
|
||||
*/
|
||||
calculateDistance(lat1, lng1, lat2, lng2) {
|
||||
const R = 6371000; // 地球半径(米)
|
||||
const dLat = (lat2 - lat1) * Math.PI / 180;
|
||||
const dLng = (lng2 - lng1) * Math.PI / 180;
|
||||
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
||||
Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
|
||||
Math.sin(dLng / 2) * Math.sin(dLng / 2);
|
||||
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||||
return R * c;
|
||||
}
|
||||
/**
|
||||
* 获取路线规划(通用版本)
|
||||
* @param origin 起点坐标
|
||||
* @param destination 终点坐标
|
||||
* @returns 路线规划结果
|
||||
*/
|
||||
async getRoute(origin, destination) {
|
||||
// 对于真实模式,目前只支持驾车路线
|
||||
const originStr = `${origin.longitude},${origin.latitude}`;
|
||||
const destStr = `${destination.longitude},${destination.latitude}`;
|
||||
const result = await this.getDrivingRoute(originStr, destStr);
|
||||
// 转换polyline格式
|
||||
const polylinePoints = [];
|
||||
if (result.polyline) {
|
||||
const points = result.polyline.split(';');
|
||||
for (const point of points) {
|
||||
const [lng, lat] = point.split(',');
|
||||
if (lng && lat) {
|
||||
polylinePoints.push({
|
||||
latitude: parseFloat(lat),
|
||||
longitude: parseFloat(lng)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
distance: result.distance,
|
||||
duration: result.duration,
|
||||
polyline: polylinePoints
|
||||
};
|
||||
}
|
||||
/**
|
||||
* 地理编码 - 地址转坐标
|
||||
* @param address 地址字符串
|
||||
* @returns 坐标信息
|
||||
*/
|
||||
async geocode(address) {
|
||||
// 对于真实模式,使用搜索API来模拟地理编码
|
||||
const results = await this.searchPoi(address, '昆明');
|
||||
if (results.length > 0) {
|
||||
return {
|
||||
latitude: results[0].latitude,
|
||||
longitude: results[0].longitude,
|
||||
formattedAddress: results[0].address
|
||||
};
|
||||
}
|
||||
// 如果没有找到结果,返回默认位置
|
||||
return {
|
||||
latitude: 25.0409,
|
||||
longitude: 102.7123,
|
||||
formattedAddress: '云南省昆明市'
|
||||
};
|
||||
}
|
||||
/**
|
||||
* 逆地理编码 - 坐标转地址
|
||||
* @param latitude 纬度
|
||||
* @param longitude 经度
|
||||
* @returns 地址信息
|
||||
*/
|
||||
async reverseGeocode(latitude, longitude) {
|
||||
const result = await this.getLocationInfo(longitude, latitude);
|
||||
return {
|
||||
// 修复:不再使用不存在的formatted_address字段,而是根据已有的addressComponent字段构建格式化地址
|
||||
formattedAddress: `${(result.regeocode && result.regeocode.addressComponent && result.regeocode.addressComponent.province) || '云南省'}${(result.regeocode && result.regeocode.addressComponent && result.regeocode.addressComponent.city) || '昆明市'}${(result.regeocode && result.regeocode.addressComponent && result.regeocode.addressComponent.district) || '五华区'}` || '未知地址',
|
||||
country: '中国',
|
||||
province: (result.regeocode && result.regeocode.addressComponent && result.regeocode.addressComponent.province) || '云南省',
|
||||
city: (result.regeocode && result.regeocode.addressComponent && result.regeocode.addressComponent.city) || '昆明市',
|
||||
district: (result.regeocode && result.regeocode.addressComponent && result.regeocode.addressComponent.district) || '五华区',
|
||||
street: (result.regeocode && result.regeocode.addressComponent && result.regeocode.addressComponent.township) || ''
|
||||
};
|
||||
}
|
||||
/**
|
||||
* 获取附近的地点
|
||||
* @param latitude 纬度
|
||||
* @param longitude 经度
|
||||
* @param radius 搜索半径
|
||||
* @param type 地点类型
|
||||
* @returns 附近地点列表
|
||||
*/
|
||||
async getNearbyPlaces(latitude, longitude, radius, type) {
|
||||
// 对于真实模式,使用搜索API
|
||||
const keyword = type ? type : '';
|
||||
const results = await this.searchPoi(keyword, '昆明');
|
||||
return results.map(place => ({
|
||||
id: place.id,
|
||||
name: place.name,
|
||||
latitude: place.latitude,
|
||||
longitude: place.longitude,
|
||||
address: place.address,
|
||||
distance: this.calculateDistance(latitude, longitude, place.latitude, place.longitude)
|
||||
})).filter(place => place.distance <= radius);
|
||||
}
|
||||
/**
|
||||
* 格式化路线距离
|
||||
* @param distance 距离(米)
|
||||
* @returns 格式化后的距离字符串
|
||||
*/
|
||||
formatRouteDistance(distance) {
|
||||
if (distance < 1000) {
|
||||
return `${distance}米`;
|
||||
}
|
||||
else {
|
||||
return `${(distance / 1000).toFixed(1)}公里`;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 格式化路线时间
|
||||
* @param duration 时间(秒)
|
||||
* @returns 格式化后的时间字符串
|
||||
*/
|
||||
formatRouteDuration(duration) {
|
||||
if (duration < 60) {
|
||||
return `${Math.round(duration)} 秒`;
|
||||
}
|
||||
else if (duration < 3600) {
|
||||
return `${Math.round(duration / 60)} 分钟`;
|
||||
}
|
||||
else {
|
||||
const hours = Math.floor(duration / 3600);
|
||||
const minutes = Math.round((duration % 3600) / 60);
|
||||
return `${hours}小时${minutes}分钟`;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 地图服务单例实例
|
||||
* 导出供应用程序全局使用
|
||||
*/
|
||||
exports.default = new MapService();
|
||||
78
dist/services/orderService.js
vendored
Normal file
78
dist/services/orderService.js
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const apiService_1 = __importDefault(require("./apiService"));
|
||||
class OrderService {
|
||||
/**
|
||||
* 构造函数
|
||||
*/
|
||||
constructor() {
|
||||
// 不再使用模拟数据
|
||||
}
|
||||
/**
|
||||
* 获取所有待处理订单
|
||||
*/
|
||||
async getPendingOrders() {
|
||||
return apiService_1.default.getPendingOrders();
|
||||
}
|
||||
/**
|
||||
* 根据ID获取订单
|
||||
*/
|
||||
async getOrderById(id) {
|
||||
return apiService_1.default.getOrderById(id);
|
||||
}
|
||||
/**
|
||||
* 指派订单给货运人员
|
||||
* @param orderId 订单ID
|
||||
* @param deliveryPersonId 货运人员ID
|
||||
* @returns 指派结果,包含success状态和可选消息
|
||||
*/
|
||||
async assignOrder(orderId, deliveryPersonId) {
|
||||
// 真实环境中调用API
|
||||
try {
|
||||
return await apiService_1.default.assignOrder(orderId, deliveryPersonId);
|
||||
}
|
||||
catch (error) {
|
||||
console.error('指派订单失败:', error);
|
||||
return { success: false, message: error instanceof Error ? error.message : '指派失败' };
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 更新订单状态
|
||||
*/
|
||||
async updateOrderStatus(orderId, status) {
|
||||
return apiService_1.default.updateOrderStatus(orderId, status).then(result => ({
|
||||
success: result.success,
|
||||
message: result.message || '状态更新成功'
|
||||
}));
|
||||
}
|
||||
/**
|
||||
* 创建新订单
|
||||
*/
|
||||
async createOrder(orderData) {
|
||||
return apiService_1.default.createOrder(orderData);
|
||||
}
|
||||
/**
|
||||
* 获取货运人员的订单列表
|
||||
*/
|
||||
async getDeliveryPersonOrders(deliveryPersonId) {
|
||||
return apiService_1.default.getDeliveryPersonOrders(deliveryPersonId);
|
||||
}
|
||||
/**
|
||||
* 删除订单
|
||||
* @param orderId 订单ID
|
||||
*/
|
||||
async deleteOrder(orderId) {
|
||||
try {
|
||||
await apiService_1.default.deleteOrder(orderId);
|
||||
return { success: true, message: '删除成功' };
|
||||
}
|
||||
catch (error) {
|
||||
console.error('删除订单失败:', error);
|
||||
return { success: false, message: error instanceof Error ? error.message : '删除失败' };
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.default = new OrderService();
|
||||
133
dist/services/statisticsService.js
vendored
Normal file
133
dist/services/statisticsService.js
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
// 统计服务 - 处理系统统计数据获取和缓存
|
||||
const apiService_1 = __importDefault(require("./apiService"));
|
||||
/**
|
||||
* 统计服务类
|
||||
* 提供系统统计数据的获取和缓存功能
|
||||
*/
|
||||
class StatisticsService {
|
||||
constructor() {
|
||||
// 数据缓存
|
||||
this.cache = null;
|
||||
// 缓存超时时间(5分钟)
|
||||
this.cacheTimeout = 5 * 60 * 1000;
|
||||
}
|
||||
/**
|
||||
* 获取系统统计数据
|
||||
* 采用一个API请求获取三个统计数据,后续操作客户端自行统计
|
||||
* @param forceRefresh 是否强制刷新,不使用缓存
|
||||
*/
|
||||
async getSystemStats(forceRefresh = false) {
|
||||
// 检查缓存是否有效,且不强制刷新
|
||||
if (!forceRefresh && this.cache && Date.now() - this.cache.timestamp < this.cacheTimeout) {
|
||||
console.log('使用缓存的统计数据');
|
||||
return this.cache;
|
||||
}
|
||||
console.log('重新获取统计数据');
|
||||
try {
|
||||
// 使用系统统计API获取三个统计数据
|
||||
const systemStats = await this.getSystemStatsFromAPI();
|
||||
this.cache = {
|
||||
...systemStats,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
return this.cache;
|
||||
}
|
||||
catch (error) {
|
||||
console.warn('系统统计API不可用,使用默认值:', error);
|
||||
// 如果API不可用,返回默认值
|
||||
this.cache = {
|
||||
employeeCount: 0,
|
||||
orderCount: 0,
|
||||
warehouseCount: 0,
|
||||
pendingOrders: 0,
|
||||
activeOrders: 0,
|
||||
completedOrders: 0,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
return this.cache;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 从API获取系统统计数据
|
||||
*/
|
||||
async getSystemStatsFromAPI() {
|
||||
try {
|
||||
// 调用系统统计API
|
||||
const response = await apiService_1.default.getSystemStats();
|
||||
console.log('API返回的统计数据:', response);
|
||||
// API返回的数据结构是 { data: { ... }, success: true }
|
||||
// 需要提取data字段中的数据
|
||||
const stats = response.data || response;
|
||||
console.log('提取的统计数据:', stats);
|
||||
// 转换API响应格式为StatisticsData格式
|
||||
// 根据API实际返回的字段进行映射
|
||||
const result = {
|
||||
employeeCount: stats.totalEmployees || stats.totalDeliveryPersons || 0,
|
||||
orderCount: stats.totalOrders || (stats.pendingOrders || 0) + (stats.activeOrders || 0),
|
||||
warehouseCount: stats.totalWarehouses || 0,
|
||||
pendingOrders: stats.pendingOrders || 0,
|
||||
activeOrders: stats.activeOrders || 0,
|
||||
completedOrders: 0, // 需要从其他接口获取
|
||||
timestamp: Date.now()
|
||||
};
|
||||
console.log('转换后的统计数据:', result);
|
||||
return result;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('获取系统统计数据失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 手动刷新统计数据(清除缓存)
|
||||
*/
|
||||
refreshStats() {
|
||||
this.cache = null;
|
||||
console.log('统计数据缓存已清除');
|
||||
}
|
||||
/**
|
||||
* 获取缓存状态
|
||||
*/
|
||||
getCacheStatus() {
|
||||
if (!this.cache) {
|
||||
return { hasCache: false, isExpired: true, age: 0 };
|
||||
}
|
||||
const age = Date.now() - this.cache.timestamp;
|
||||
const isExpired = age > this.cacheTimeout;
|
||||
return { hasCache: true, isExpired, age };
|
||||
}
|
||||
/**
|
||||
* 客户端更新统计数据(直接传值更新)
|
||||
* @param type 数据类型:'employee' | 'order' | 'warehouse'
|
||||
* @param count 对应的数量值
|
||||
*/
|
||||
updateStats(type, count) {
|
||||
if (!this.cache) {
|
||||
console.warn('没有缓存数据,无法更新统计');
|
||||
return;
|
||||
}
|
||||
switch (type) {
|
||||
case 'employee':
|
||||
this.cache.employeeCount = Math.max(0, count);
|
||||
break;
|
||||
case 'order':
|
||||
this.cache.orderCount = Math.max(0, count);
|
||||
break;
|
||||
case 'warehouse':
|
||||
this.cache.warehouseCount = Math.max(0, count);
|
||||
break;
|
||||
}
|
||||
this.cache.timestamp = Date.now();
|
||||
console.log(`统计数据已更新: ${type} = ${count}`);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 统计服务单例实例
|
||||
* 导出供应用程序全局使用
|
||||
*/
|
||||
exports.default = new StatisticsService();
|
||||
357
dist/services/userService.js
vendored
Normal file
357
dist/services/userService.js
vendored
Normal file
@@ -0,0 +1,357 @@
|
||||
"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 apiService_1 = __importDefault(require("./apiService"));
|
||||
/**
|
||||
* 用户服务类
|
||||
* 提供用户认证、信息管理、权限验证等功能
|
||||
*/
|
||||
class UserService {
|
||||
/**
|
||||
* 构造函数
|
||||
*/
|
||||
constructor() {
|
||||
// 不再使用模拟数据
|
||||
}
|
||||
/**
|
||||
* 获取用户信息
|
||||
* @returns 用户信息
|
||||
*/
|
||||
async getUserInfo() {
|
||||
return apiService_1.default.getUserInfo();
|
||||
}
|
||||
/**
|
||||
* 用户退出登录
|
||||
*/
|
||||
async logout() {
|
||||
return apiService_1.default.logout();
|
||||
}
|
||||
/**
|
||||
* 检查用户是否已登录
|
||||
* @returns 是否已登录
|
||||
*/
|
||||
isLoggedIn() {
|
||||
const app = getApp();
|
||||
return app.globalData.isLoggedIn && !!app.globalData.userInfo;
|
||||
}
|
||||
/**
|
||||
* 获取用户角色
|
||||
* @returns 用户角色或null
|
||||
*/
|
||||
getUserRole() {
|
||||
const app = getApp();
|
||||
return app.globalData.userInfo && app.globalData.userInfo.role || null;
|
||||
}
|
||||
/**
|
||||
* 检查用户是否为管理员
|
||||
* @returns 是否为管理员
|
||||
*/
|
||||
isAdmin() {
|
||||
return this.getUserRole() === roleUtils_1.Role.ADMIN;
|
||||
}
|
||||
/**
|
||||
* 检查用户是否为货运人员
|
||||
* @returns 是否为货运人员
|
||||
*/
|
||||
isDeliveryPerson() {
|
||||
return this.getUserRole() === roleUtils_1.Role.DELIVERY_PERSON;
|
||||
}
|
||||
/**
|
||||
* 检查位置权限
|
||||
* @returns 是否拥有位置权限
|
||||
*/
|
||||
checkLocationPermission() {
|
||||
return new Promise((resolve) => {
|
||||
wx.getSetting({
|
||||
success: (res) => {
|
||||
const hasPermission = res.authSetting && res.authSetting['scope.userLocation'];
|
||||
resolve(!!hasPermission);
|
||||
},
|
||||
fail: () => {
|
||||
resolve(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 请求位置权限
|
||||
* @returns 请求是否成功
|
||||
*/
|
||||
requestLocationPermission() {
|
||||
return new Promise((resolve) => {
|
||||
wx.authorize({
|
||||
scope: 'scope.userLocation',
|
||||
success: () => {
|
||||
resolve(true);
|
||||
},
|
||||
fail: () => {
|
||||
resolve(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 获取全局用户信息
|
||||
* @returns 全局用户信息或null
|
||||
*/
|
||||
getGlobalUserInfo() {
|
||||
const app = getApp();
|
||||
return app.globalData.userInfo;
|
||||
}
|
||||
/**
|
||||
* 执行静默登录流程:微信登录->个人服务器登录->进入基础界面->签到/绑定
|
||||
* @returns 登录结果
|
||||
*/
|
||||
async wxLogin() {
|
||||
try {
|
||||
// 获取微信登录code
|
||||
console.log('步骤1: 获取微信登录code');
|
||||
const code = await this.getWxLoginCode();
|
||||
if (!code) {
|
||||
console.error('步骤1失败: 获取微信登录code失败');
|
||||
throw new Error('获取微信登录code失败');
|
||||
}
|
||||
console.log('步骤1成功: 获取到微信登录code');
|
||||
// 调用微信登录API
|
||||
console.log('步骤2: 调用微信登录API');
|
||||
const wxLoginResult = await this.ServerLogin(code);
|
||||
if (wxLoginResult.success) {
|
||||
console.log('步骤2成功: 微信登录API调用成功');
|
||||
// 静默登录模式下,不主动获取用户信息
|
||||
let userInfo = wxLoginResult.userInfo;
|
||||
return {
|
||||
success: true,
|
||||
userInfo,
|
||||
openid: wxLoginResult.openid,
|
||||
session_key: wx.getStorageSync('session_key'), //TODO:服务器已经下发
|
||||
token: wxLoginResult.token
|
||||
};
|
||||
}
|
||||
else {
|
||||
console.error('步骤2失败: 微信登录API返回失败');
|
||||
return {
|
||||
success: false,
|
||||
openid: wxLoginResult.openid
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error('登录流程异常:', error);
|
||||
return { success: false };
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 微信登录成功后调用个人服务器登录消息
|
||||
* @param code 微信登录授权码
|
||||
* @returns 登录结果
|
||||
*/
|
||||
async ServerLogin(code) {
|
||||
try {
|
||||
// 真实API模式
|
||||
//TODO: 登录成功的基础数据:服务器下发的公共游客可看的数据
|
||||
const result = await apiService_1.default.ServerLogin(code);
|
||||
// 确保用户信息包含头像URL,如果为空则设置默认头像
|
||||
const userInfoWithAvatar = {
|
||||
...result.user,
|
||||
avatarUrl: result.user.avatarUrl || '/images/truck.png'
|
||||
};
|
||||
// 保存到本地存储
|
||||
wx.setStorageSync('userInfo', userInfoWithAvatar);
|
||||
wx.setStorageSync('token', result.token);
|
||||
wx.setStorageSync('openid', result.openid);
|
||||
wx.setStorageSync('session_key', result.session_key);
|
||||
// 同时保存到全局数据,确保后续API调用能正确获取token
|
||||
const app = getApp();
|
||||
app.globalData.token = result.token;
|
||||
return {
|
||||
success: true,
|
||||
openid: result.openid,
|
||||
token: result.token,
|
||||
userInfo: userInfoWithAvatar
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
console.error('微信登录失败:', error);
|
||||
return { success: false };
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取微信登录code
|
||||
*/
|
||||
async getWxLoginCode() {
|
||||
return new Promise((resolve) => {
|
||||
wx.login({
|
||||
success: (res) => {
|
||||
if (res.code) {
|
||||
console.log('成功获取到登录code');
|
||||
resolve(res.code);
|
||||
}
|
||||
else {
|
||||
console.error('获取登录code失败,返回值为空');
|
||||
resolve(null);
|
||||
}
|
||||
},
|
||||
fail: (error) => {
|
||||
console.error('wx.login调用失败:', error);
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 更新用户信息
|
||||
* @param userInfo 待更新的用户信息
|
||||
* @returns 更新后的用户信息
|
||||
*/
|
||||
async updateUserInfo(userInfo) {
|
||||
return apiService_1.default.updateUserInfo(userInfo);
|
||||
}
|
||||
/**
|
||||
* 获取用户签到状态
|
||||
* @returns 用户状态信息
|
||||
*/
|
||||
async getUserStatus() {
|
||||
try {
|
||||
// 调用服务器接口获取用户状态
|
||||
const response = await apiService_1.default.getUserStatus();
|
||||
return response;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('获取用户状态失败:', error);
|
||||
// 如果是404错误(接口不存在),返回null让前端使用本地逻辑
|
||||
if (error.message && error.message.includes('404')) {
|
||||
console.log('服务器状态接口不存在,使用本地逻辑');
|
||||
return null; // 返回null表示服务器接口不可用
|
||||
}
|
||||
// 其他网络错误时返回默认状态
|
||||
return {
|
||||
status: 'registered'
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 用户签到
|
||||
* @param initialLocation 初始位置数据(必须)
|
||||
* @returns 签到结果和更新后的用户信息
|
||||
*/
|
||||
async signIn(initialLocation) {
|
||||
const userInfo = this.getGlobalUserInfo();
|
||||
if (!userInfo || !userInfo.id) {
|
||||
throw new Error('用户未登录,无法签到');
|
||||
}
|
||||
// 检查是否有有效的token(防止后端空指针异常)
|
||||
const app = getApp();
|
||||
if (!app.globalData.token) {
|
||||
throw new Error('用户认证信息缺失,请重新登录');
|
||||
}
|
||||
return apiService_1.default.userSignIn(userInfo.id, initialLocation);
|
||||
}
|
||||
/**
|
||||
* 用户签退
|
||||
* @returns 签退结果
|
||||
*/
|
||||
async signOut() {
|
||||
const userInfo = this.getGlobalUserInfo();
|
||||
if (!userInfo || !userInfo.id) {
|
||||
throw new Error('用户未登录,无法签退');
|
||||
}
|
||||
// 检查是否有有效的token(防止后端空指针异常)
|
||||
const app = getApp();
|
||||
if (!app.globalData.token) {
|
||||
throw new Error('用户认证信息缺失,请重新登录');
|
||||
}
|
||||
return apiService_1.default.userSignOut(userInfo.id);
|
||||
}
|
||||
/**
|
||||
* 用户绑定
|
||||
* @param registerInfo 绑定信息
|
||||
* @returns 绑定结果和员工信息
|
||||
*/
|
||||
async register(registerInfo) {
|
||||
return apiService_1.default.userRegister(registerInfo);
|
||||
}
|
||||
/**
|
||||
* 解绑微信
|
||||
* 清除当前用户的openid绑定,允许重新注册其他账号
|
||||
* @returns 解绑结果
|
||||
*/
|
||||
async unbindWechat() {
|
||||
try {
|
||||
console.log('开始解绑微信流程');
|
||||
// 调用API解绑
|
||||
const result = await apiService_1.default.unbindWechat();
|
||||
if (result.success) {
|
||||
console.log('微信解绑成功');
|
||||
// 清除本地存储的登录信息
|
||||
wx.removeStorageSync('userInfo');
|
||||
wx.removeStorageSync('token');
|
||||
wx.removeStorageSync('openid');
|
||||
wx.removeStorageSync('session_key');
|
||||
// 清除全局数据
|
||||
const app = getApp();
|
||||
app.globalData.userInfo = null;
|
||||
app.globalData.token = null;
|
||||
app.globalData.openid = null;
|
||||
app.globalData.isLoggedIn = false;
|
||||
console.log('本地登录信息已清除');
|
||||
// 解绑成功后跳转到主界面
|
||||
setTimeout(() => {
|
||||
wx.reLaunch({
|
||||
url: '/pages/index/index'
|
||||
});
|
||||
}, 500);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('解绑微信失败:', error);
|
||||
return { success: false, message: '解绑微信失败,请重试' };
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取用户权限列表
|
||||
* @returns 权限列表
|
||||
*/
|
||||
async getUserPermissions() {
|
||||
return apiService_1.default.getUserPermissions();
|
||||
}
|
||||
/**
|
||||
* 检查用户是否在线
|
||||
* @returns 是否在线
|
||||
*/
|
||||
async checkUserOnline() {
|
||||
return apiService_1.default.checkUserOnline();
|
||||
}
|
||||
/**
|
||||
* 获取用户会话信息
|
||||
* @returns 会话信息
|
||||
*/
|
||||
async getSessionInfo() {
|
||||
return apiService_1.default.getSessionInfo();
|
||||
}
|
||||
/**
|
||||
* 刷新用户令牌
|
||||
* @param oldToken 旧令牌
|
||||
* @returns 新令牌及过期时间
|
||||
*/
|
||||
async refreshToken(oldToken) {
|
||||
return apiService_1.default.refreshToken(oldToken);
|
||||
}
|
||||
/**
|
||||
* 验证用户权限
|
||||
* @param permission 待验证的权限
|
||||
* @returns 是否拥有该权限
|
||||
*/
|
||||
async verifyPermission(permission) {
|
||||
return apiService_1.default.verifyPermission(permission);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 用户服务单例实例
|
||||
* 导出供应用程序全局使用
|
||||
*/
|
||||
exports.default = new UserService();
|
||||
95
dist/services/warehouseService.js
vendored
Normal file
95
dist/services/warehouseService.js
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const apiService_1 = __importDefault(require("./apiService"));
|
||||
/**
|
||||
* 仓库服务类
|
||||
* 封装了所有仓库相关的操作
|
||||
*/
|
||||
class WarehouseService {
|
||||
/**
|
||||
* 构造函数
|
||||
*/
|
||||
constructor() {
|
||||
// 真实API模式下不需要模拟数据
|
||||
}
|
||||
/**
|
||||
* 获取仓库状态的中文描述
|
||||
*/
|
||||
getWarehouseStatusText(status) {
|
||||
const statusMap = {
|
||||
'open': '营业中',
|
||||
'closed': '已关闭',
|
||||
'maintenance': '维护中'
|
||||
};
|
||||
return statusMap[status || 'open'] || '未知状态';
|
||||
}
|
||||
/**
|
||||
* 获取所有仓库信息
|
||||
*/
|
||||
async getWarehouses() {
|
||||
return apiService_1.default.getWarehouses();
|
||||
}
|
||||
/**
|
||||
* 根据ID获取仓库信息
|
||||
*/
|
||||
async getWarehouseById(id) {
|
||||
return apiService_1.default.getWarehouseById(id);
|
||||
}
|
||||
/**
|
||||
* 创建仓库
|
||||
*/
|
||||
async createWarehouse(warehouseData) {
|
||||
try {
|
||||
const result = await apiService_1.default.createWarehouse(warehouseData);
|
||||
console.log('创建仓库结果:', result);
|
||||
if (result.success && result.data) {
|
||||
return result.data;
|
||||
}
|
||||
else {
|
||||
throw new Error(result.message || '创建仓库失败');
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error('创建仓库失败:', error);
|
||||
throw new Error('创建仓库失败');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 更新仓库信息
|
||||
*/
|
||||
async updateWarehouse(warehouseId, warehouseInfo) {
|
||||
try {
|
||||
const result = await apiService_1.default.updateWarehouse(warehouseId, warehouseInfo);
|
||||
console.log(`更新仓库 ${warehouseId} 结果:`, result);
|
||||
if (result.success && result.data) {
|
||||
return result.data;
|
||||
}
|
||||
else {
|
||||
throw new Error(result.message || '更新仓库失败');
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error('更新仓库失败:', error);
|
||||
throw new Error('更新仓库失败');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 删除仓库
|
||||
*/
|
||||
async deleteWarehouse(warehouseId) {
|
||||
try {
|
||||
const result = await apiService_1.default.deleteWarehouse(warehouseId);
|
||||
console.log(`删除仓库 ${warehouseId} 结果:`, result);
|
||||
return result.success;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('删除仓库失败:', error);
|
||||
throw new Error('删除仓库失败');
|
||||
}
|
||||
}
|
||||
}
|
||||
// 导出单例实例
|
||||
exports.default = new WarehouseService();
|
||||
Reference in New Issue
Block a user