修改位置交互,修改代码逻辑

This commit is contained in:
2025-10-18 22:21:04 +08:00
parent c446df73b5
commit 39fa0b2d04
36 changed files with 2743 additions and 1995 deletions

View File

@@ -16,7 +16,7 @@ console.log(`当前API地址: ${API_BASE_URL} (${IS_LOCAL_DEV ? '本地开发环
* 是否启用模拟模式
* 该配置控制是否使用模拟数据进行开发测试
*/
export const isMockMode = false;
/**
* API服务类
@@ -28,6 +28,11 @@ class ApiService {
*/
private locationUpdateCallbacks: Set<(location: any) => void> | null;
/**
* 在线用户列表回调函数集合
*/
private onlineUserListCallbacks: Set<(userList: any) => void> | null;
/**
* 位置更新WebSocket连接
*/
@@ -38,6 +43,7 @@ class ApiService {
*/
constructor() {
this.locationUpdateCallbacks = null;
this.onlineUserListCallbacks = null;
this.locationWebSocket = null;
}
@@ -194,6 +200,20 @@ async ServerLogin(code: string) {
return await this.request('/user/logout', { method: 'POST' });
}
/**
* 签退接口
* @param userId 用户ID
* @returns 签退结果
*/
async userSignOut(userId: number): Promise<{ success: boolean; message?: string }> {
console.log('API userSignOut调用参数userId:', userId);
return await this.request('/user/signout', {
method: 'POST',
data: { userId },
});
}
/**
* 获取用户签到状态
* @returns 用户状态信息
@@ -311,6 +331,52 @@ async ServerLogin(code: string) {
});
}
// ====== 员工管理接口 ======
/**
* 获取所有员工列表
* @returns 员工信息数组
*/
async getEmployees(): Promise<EmployeeInfo[]> {
return await this.request<EmployeeInfo[]>('/employees');
}
/**
* 添加新员工
* @param employeeInfo 员工信息
* @returns 添加结果
*/
async addEmployee(employeeInfo: { name: string; phone: string; role: string }): Promise<EmployeeInfo> {
return await this.request<EmployeeInfo>('/employees', {
method: 'POST',
data: employeeInfo,
});
}
/**
* 删除员工
* @param employeeId 员工ID
* @returns 删除结果
*/
async deleteEmployee(employeeId: number): Promise<{ success: boolean; message?: string }> {
return await this.request<{ success: boolean; message?: string }>(`/employees/${employeeId}`, {
method: 'DELETE',
});
}
/**
* 更新员工信息
* @param employeeId 员工ID
* @param employeeInfo 员工信息
* @returns 更新结果
*/
async updateEmployee(employeeId: number, employeeInfo: { name?: string; phone?: string; role?: string }): Promise<EmployeeInfo> {
return await this.request<EmployeeInfo>(`/employees/${employeeId}`, {
method: 'PUT',
data: employeeInfo,
});
}
// ==================== 仓库相关接口 ====================
/**
@@ -464,15 +530,6 @@ async ServerLogin(code: string) {
subscriptionId: string;
expiresAt: number;
}> {
if (isMockMode) {
// 模拟数据 - 返回模拟的订阅信息
console.log('[MOCK] 订阅实时位置更新货运人员ID列表:', deliveryPersonIds);
return {
subscriptionId: `mock-subscription-${Date.now()}`,
expiresAt: Date.now() + 3600000 // 1小时后过期
};
}
// 真实环境中调用API
try {
return await this.request<{
@@ -493,12 +550,6 @@ async ServerLogin(code: string) {
* @param subscriptionId 订阅ID
*/
async unsubscribeFromRealTimeLocations(subscriptionId: string): Promise<void> {
if (isMockMode) {
// 模拟数据 - 记录取消订阅操作
console.log('[MOCK] 取消订阅实时位置更新订阅ID:', subscriptionId);
return;
}
// 真实环境中调用API
try {
await this.request<void>('/locations/unsubscribe', {
@@ -529,12 +580,31 @@ async ServerLogin(code: string) {
this.locationUpdateCallbacks.delete(callback);
// 如果没有回调了可以关闭WebSocket连接
if (this.locationUpdateCallbacks.size === 0 && this.locationWebSocket) {
this.locationWebSocket.close();
this.locationWebSocket = null;
this.closeLocationWebSocket();
}
}
};
}
/**
* 注册在线用户列表回调函数
* @param callback 在线用户列表回调函数
* @returns 取消订阅函数
*/
onOnlineUserList(callback: (userList: any) => void): () => void {
// 添加回调到集合
if (!this.onlineUserListCallbacks) {
this.onlineUserListCallbacks = new Set();
}
this.onlineUserListCallbacks.add(callback);
// 返回取消订阅函数
return () => {
if (this.onlineUserListCallbacks) {
this.onlineUserListCallbacks.delete(callback);
}
};
}
// ===== 私有属性和方法 =====
@@ -578,9 +648,21 @@ async ServerLogin(code: string) {
});
// WebSocket连接关闭事件
wx.onSocketClose(() => {
console.log('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错误事件
@@ -597,14 +679,28 @@ async ServerLogin(code: string) {
}
}
/**
* 检查WebSocket连接是否已建立
*/
public isWebSocketConnected(): boolean {
return this.locationWebSocket !== null && this.locationWebSocket !== undefined;
}
/**
* 关闭位置更新WebSocket连接
*/
public async closeLocationWebSocket(): Promise<void> {
if (this.locationWebSocket && typeof wx !== 'undefined' && typeof wx.closeSocket === 'function') {
wx.closeSocket();
this.locationWebSocket = null;
console.log('WebSocket连接已关闭');
try {
// 先检查WebSocket状态避免在连接过程中关闭
wx.closeSocket();
this.locationWebSocket = null;
console.log('WebSocket连接已关闭');
} catch (error) {
console.warn('关闭WebSocket连接时出现异常:', error);
// 即使关闭失败,也重置连接状态
this.locationWebSocket = null;
}
}
}
@@ -621,13 +717,53 @@ async ServerLogin(code: string) {
switch (message.type) {
case 'updateLocation':
// 处理位置更新消息
this.onLocationUpdate(message);
this.triggerLocationUpdateCallbacks(message);
break;
case 'onlineUserList':
// 处理在线用户列表消息
this.triggerOnlineUserListCallbacks(message);
break;
case 'subscribed':
// 处理订阅成功响应
console.log('WebSocket订阅成功:', message);
break;
default:
console.warn('收到未知类型的WebSocket消息:', message);
break;
}
}
/**
* 触发位置更新回调
* @param locationUpdate 位置更新信息
*/
private triggerLocationUpdateCallbacks(locationUpdate: any): void {
if (this.locationUpdateCallbacks) {
this.locationUpdateCallbacks.forEach(callback => {
try {
callback(locationUpdate);
} catch (error) {
console.error('位置更新回调执行失败:', error);
}
});
}
}
/**
* 触发在线用户列表回调
* @param userList 在线用户列表信息
*/
private triggerOnlineUserListCallbacks(userList: any): void {
if (this.onlineUserListCallbacks) {
this.onlineUserListCallbacks.forEach(callback => {
try {
callback(userList);
} catch (error) {
console.error('在线用户列表回调执行失败:', error);
}
});
}
}
/**
* 发送WebSocket消息
@@ -652,62 +788,35 @@ async ServerLogin(code: string) {
}
/**
* 订阅位置更新
* @param deliveryPersonId 配送员ID
* 订阅位置更新(服务器自动处理,无需发送消息)
* @param userId 用户ID
*/
async subscribeToLocationUpdates(deliveryPersonId: number): Promise<void> {
if (isMockMode) {
console.log('[MOCK] 订阅位置更新');
return;
}
async subscribeToLocationUpdates(): Promise<void> {
// 确保WebSocket连接已建立
if (!this.locationWebSocket) {
this.initLocationWebSocket();
}
// 发送订阅消息
const subscribeMessage = {
type: 'subscribe',
deliveryPersonId: deliveryPersonId,
timestamp: Date.now()
};
this.sendWebSocketMessage(subscribeMessage);
// 服务器会自动处理订阅逻辑,无需发送订阅消息
console.log('位置订阅已初始化,服务器将自动处理订阅逻辑');
}
/**
* 取消订阅位置更新
* @param deliveryPersonId 配送员ID
* 取消订阅位置更新(服务器自动处理,无需发送消息)
* @param userId 用户ID
*/
async unsubscribeFromLocationUpdates(deliveryPersonId: number): Promise<void> {
if (isMockMode) {
console.log('[MOCK] 取消订阅位置更新');
return;
}
// 发送取消订阅消息
const unsubscribeMessage = {
type: 'unsubscribe',
deliveryPersonId: deliveryPersonId,
timestamp: Date.now()
};
this.sendWebSocketMessage(unsubscribeMessage);
async unsubscribeFromLocationUpdates(userId: number): Promise<void> {
// 服务器会自动处理取消订阅逻辑,无需发送取消订阅消息
console.log('位置取消订阅已初始化,服务器将自动处理取消订阅逻辑');
}
/**
* 发送位置更新
* @param deliveryPersonId 配送员ID
* @param userId 用户ID
* @param latitude 纬度
* @param longitude 经度
*/
async sendLocationUpdate(deliveryPersonId: number, latitude: number, longitude: number): Promise<void> {
if (isMockMode) {
console.log('[MOCK] 发送位置更新');
return;
}
async sendLocationUpdate(userId: number, latitude: number, longitude: number): Promise<void> {
// 确保WebSocket连接已建立
if (!this.locationWebSocket) {
this.initLocationWebSocket();
@@ -716,7 +825,7 @@ async ServerLogin(code: string) {
// 发送位置更新消息
const locationMessage = {
type: 'updateLocation',
deliveryPersonId: deliveryPersonId,
userId: userId,
latitude: latitude,
longitude: longitude,
timestamp: Date.now()
@@ -725,6 +834,8 @@ async ServerLogin(code: string) {
this.sendWebSocketMessage(locationMessage);
}
// ==================== 订单接口 ====================
/**

View File

@@ -1,66 +1,18 @@
// 货运人员服务 - 处理货运人员相关的数据操作
import { DeliveryPerson, LocationData } from '../types';
import { DeliveryPerson } from '../types';
import apiService from './apiService';
import { isMockMode } from './apiService';
/**
* 货运人员服务类
* 提供货运人员信息管理、位置更新、状态管理等功能
* 提供货运人员信息管理、状态管理等功能
*/
class DeliveryPersonService {
// 模拟货运人员数据
private mockDeliveryPersons: DeliveryPerson[];
/**
* 构造函数
*/
constructor() {
this.mockDeliveryPersons = [
{
id: 101,
name: '张师傅',
phone: '13812345678',
status: 'idle',
currentLocation: {
longitude: 102.714585,
latitude: 25.046321
},
currentOrders: []
},
{
id: 102,
name: '李师傅',
phone: '13912345678',
status: 'busy',
currentLocation: {
longitude: 102.690181,
latitude: 24.994788
},
currentOrders: [
{
id: 1002,
startPoint: {
id: 2,
name: '瓦尔塔蓄电池盘龙区分店',
longitude: 102.728421,
latitude: 25.042498
},
endPoint: {
name: '云南中致远汽车销售有限公司',
longitude: 102.796212,
latitude: 24.936947
},
status: 'assigned',
goodsType: '瓦尔塔EFB蓄电池',
goodsWeight: 120,
createTime: Date.now() - 7200000
}
]
}
];
this.locationUpdateCallbacks = null;
this.locationUpdateTimer = null;
this.unsubscribeFunction = null;
// 不再使用模拟数据
}
/**
@@ -68,11 +20,6 @@ class DeliveryPersonService {
* @returns 货运人员列表
*/
async getDeliveryPersons(): Promise<DeliveryPerson[]> {
if (isMockMode) {
// 模拟数据 - 返回所有货运人员
console.log('[MOCK] 获取所有货运人员');
return [...this.mockDeliveryPersons];
}
return apiService.getDeliveryPersons();
}
@@ -82,12 +29,6 @@ class DeliveryPersonService {
* @returns 货运人员信息或null
*/
async getDeliveryPersonById(id: number): Promise<DeliveryPerson | null> {
if (isMockMode) {
// 模拟数据 - 根据ID查找货运人员
console.log('[MOCK] 根据ID获取货运人员ID:', id);
const person = this.mockDeliveryPersons.find(p => p.id === id);
return person || null;
}
try {
const result = await apiService.getDeliveryPersonById(id);
return result;
@@ -97,70 +38,11 @@ class DeliveryPersonService {
}
}
/**
* 更新货运人员位置
* @param id 货运人员ID
* @param location 位置信息
*/
async updateDeliveryPersonLocation(
id: number,
location: { longitude: number; latitude: number }
): Promise<void> {
if (isMockMode) {
// 模拟数据 - 更新货运人员位置
console.log('[MOCK] 更新货运人员位置ID:', id, '位置:', location);
const person = this.mockDeliveryPersons.find(p => p.id === id);
if (person) {
person.currentLocation = location;
}
return;
}
return apiService.updateDeliveryPersonLocation(id, location);
}
/**
* 批量更新货运人员位置
* @param locations 位置信息数组
*/
async batchUpdateDeliveryPersonLocations(locations: Array<{
deliveryPersonId: number;
longitude: number;
latitude: number;
timestamp: number;
}>): Promise<void> {
if (isMockMode) {
// 模拟数据 - 批量更新货运人员位置
console.log('[MOCK] 批量更新货运人员位置');
locations.forEach(item => {
const person = this.mockDeliveryPersons.find(p => p.id === item.deliveryPersonId);
if (person) {
person.currentLocation = { longitude: item.longitude, latitude: item.latitude };
}
});
return;
}
// 修复转换参数格式以匹配apiService的要求
const formattedLocations = locations.map(loc => ({
userId: loc.deliveryPersonId, // 将deliveryPersonId转换为userId
longitude: loc.longitude,
latitude: loc.latitude,
timestamp: loc.timestamp
}));
return apiService.batchUpdateDeliveryPersonLocations(formattedLocations);
}
/**
* 获取空闲的货运人员
* @returns 空闲货运人员列表
*/
async getIdleDeliveryPersons(): Promise<DeliveryPerson[]> {
if (isMockMode) {
// 模拟数据 - 返回空闲的货运人员
console.log('[MOCK] 获取空闲的货运人员');
return this.mockDeliveryPersons.filter(p => p.status === 'idle');
}
return apiService.getIdleDeliveryPersons();
}
@@ -169,230 +51,9 @@ class DeliveryPersonService {
* @returns 忙碌货运人员列表
*/
async getBusyDeliveryPersons(): Promise<DeliveryPerson[]> {
if (isMockMode) {
// 模拟数据 - 返回忙碌的货运人员
console.log('[MOCK] 获取忙碌的货运人员');
return this.mockDeliveryPersons.filter(p => p.status === 'busy');
}
return apiService.getBusyDeliveryPersons();
}
/**
* 获取位置历史记录
* @param deliveryPersonId 货运人员ID
* @param limit 记录数量
* @returns 位置历史记录
*/
async getLocationHistory(deliveryPersonId: number, limit: number = 50): Promise<Array<{
timestamp: number;
longitude: number;
latitude: number;
speed?: number;
accuracy?: number;
}>> {
if (isMockMode) {
// 模拟数据 - 返回位置历史记录
console.log('[MOCK] 获取货运人员位置历史记录ID:', deliveryPersonId);
const mockHistory = [];
const person = this.mockDeliveryPersons.find(p => p.id === deliveryPersonId);
if (person) {
// 生成一些模拟的位置历史记录
for (let i = 0; i < limit; i++) {
// 在当前位置附近随机生成一些位置点
const baseLongitude = person.currentLocation.longitude;
const baseLatitude = person.currentLocation.latitude;
mockHistory.push({
timestamp: Date.now() - i * 60000, // 每分钟一个点
longitude: baseLongitude + (Math.random() - 0.5) * 0.01,
latitude: baseLatitude + (Math.random() - 0.5) * 0.01,
speed: Math.random() * 60, // 0-60 km/h
accuracy: 5 + Math.random() * 15 // 5-20 meters
});
}
}
return mockHistory;
}
return apiService.getLocationHistory(deliveryPersonId, limit);
}
/**
* 订阅实时位置更新兼容mapService参数
* @param callback 位置更新回调函数
*/
async subscribeToRealTimeLocations(callback: (location: LocationData) => void): Promise<void> {
if (isMockMode) {
// 模拟实时位置更新
console.log('[MOCK] 订阅实时位置更新');
// 保存回调引用,以便在取消订阅时使用
if (!this.locationUpdateCallbacks) {
this.locationUpdateCallbacks = new Set();
}
this.locationUpdateCallbacks.add(callback);
// 如果是首次订阅,启动模拟更新
if (!this.locationUpdateTimer) {
this.startMockLocationUpdates();
}
return;
}
// 真实环境中实现WebSocket连接
try {
// 获取当前用户信息
const userInfo = wx.getStorageSync('userInfo');
if (!userInfo || !userInfo.id) {
throw new Error('用户未登录,无法订阅位置更新');
}
// 初始化WebSocket连接
await apiService.initLocationWebSocket();
// 订阅位置更新
await apiService.subscribeToLocationUpdates(userInfo.id);
// 设置位置更新回调
this.unsubscribeFunction = apiService.onLocationUpdate((location) => {
callback(location as LocationData);
});
console.log('WebSocket位置订阅成功');
} catch (error) {
console.error('订阅实时位置更新失败:', error);
throw error;
}
}
/**
* 取消订阅实时位置更新(兼容无参数调用)
*/
async unsubscribeFromRealTimeLocations(): Promise<void> {
if (isMockMode) {
// 模拟取消订阅
console.log('[MOCK] 取消订阅实时位置更新');
// 清除所有回调
if (this.locationUpdateCallbacks) {
this.locationUpdateCallbacks.clear();
}
// 停止模拟更新定时器
if (this.locationUpdateTimer) {
clearInterval(this.locationUpdateTimer);
this.locationUpdateTimer = null;
}
return;
}
// 真实环境中关闭WebSocket连接
try {
// 获取当前用户信息
const userInfo = wx.getStorageSync('userInfo');
if (userInfo && userInfo.id) {
// 取消订阅
await apiService.unsubscribeFromLocationUpdates(userInfo.id);
}
// 调用取消订阅函数
if (this.unsubscribeFunction) {
this.unsubscribeFunction();
this.unsubscribeFunction = null;
}
// 关闭WebSocket连接
apiService.closeLocationWebSocket();
console.log('WebSocket位置订阅已取消');
} catch (error) {
console.error('取消订阅实时位置更新失败:', error);
throw error;
}
}
/**
* 发送位置更新到服务器
* @param deliveryPersonId 配送员ID
* @param latitude 纬度
* @param longitude 经度
*/
async sendLocationUpdate(deliveryPersonId: number, latitude: number, longitude: number): Promise<void> {
if (isMockMode) {
console.log('[MOCK] 发送位置更新:', { deliveryPersonId, latitude, longitude });
return;
}
try {
await apiService.sendLocationUpdate(deliveryPersonId, latitude, longitude);
console.log('位置更新发送成功');
} catch (error) {
console.error('发送位置更新失败:', error);
throw error;
}
}
// ===== 私有辅助方法 =====
/**
* 存储位置更新回调函数的集合
*/
private locationUpdateCallbacks: Set<(location: LocationData) => void> | null;
/**
* 模拟位置更新的定时器
*/
private locationUpdateTimer: number | null;
/**
* 取消订阅函数引用
*/
private unsubscribeFunction: (() => void) | null;
/**
* 启动模拟位置更新
*/
private startMockLocationUpdates(): void {
// 每5秒发送一次模拟位置更新
this.locationUpdateTimer = setInterval(() => {
if (this.locationUpdateCallbacks && this.locationUpdateCallbacks.size > 0) {
// 为每个货运人员生成模拟位置更新
this.mockDeliveryPersons.forEach(person => {
// 在当前位置附近随机生成新位置
const baseLongitude = person.currentLocation.longitude;
const baseLatitude = person.currentLocation.latitude;
const newLocation: LocationData = {
userId: person.id,
longitude: baseLongitude + (Math.random() - 0.5) * 0.001, // 小范围随机移动
latitude: baseLatitude + (Math.random() - 0.5) * 0.001, // 小范围随机移动
timestamp: Date.now()
};
// 更新模拟数据中的位置
person.currentLocation = {
longitude: newLocation.longitude,
latitude: newLocation.latitude
};
// 通知所有回调函数
this.locationUpdateCallbacks!.forEach(callback => {
try {
callback(newLocation);
} catch (error) {
console.error('位置更新回调执行失败:', error);
}
});
});
}
}, 5000); // 5秒更新一次
}
/**
* 获取货运人员当前订单
* @param deliveryPersonId 货运人员ID
@@ -416,12 +77,6 @@ class DeliveryPersonService {
goodsWeight: number;
createTime: number;
}>> {
if (isMockMode) {
// 模拟数据 - 返回货运人员当前订单
console.log('[MOCK] 获取货运人员当前订单ID:', deliveryPersonId);
const person = this.mockDeliveryPersons.find(p => p.id === deliveryPersonId);
return person ? person.currentOrders : [];
}
return apiService.getDeliveryPersonOrders(deliveryPersonId);
}
}

View File

@@ -0,0 +1,118 @@
// 员工管理服务 - 处理员工相关的数据操作
import { EmployeeInfo } from '../types';
import apiService from './apiService';
/**
* 员工管理服务类
* 提供员工信息的增删改查功能
*/
class EmployeeService {
/**
* 构造函数
*/
constructor() {
// 不再使用模拟数据
}
/**
* 获取所有员工列表
* @returns 员工信息数组
*/
async getEmployees(): Promise<EmployeeInfo[]> {
try {
return await apiService.getEmployees();
} catch (error) {
console.error('获取员工列表失败:', error);
// API调用失败时返回空数组
return [];
}
}
/**
* 添加新员工
* @param employeeInfo 员工信息
* @returns 添加的员工信息
*/
async addEmployee(employeeInfo: { name: string; phone: string; role: string }): Promise<EmployeeInfo> {
try {
return await apiService.addEmployee(employeeInfo);
} catch (error) {
console.error('添加员工失败:', error);
throw new Error('添加员工失败,请稍后重试');
}
}
/**
* 删除员工
* @param employeeId 员工ID
* @returns 删除结果
*/
async deleteEmployee(employeeId: number): Promise<{ success: boolean; message?: string }> {
try {
return await apiService.deleteEmployee(employeeId);
} catch (error) {
console.error('删除员工失败:', error);
return {
success: false,
message: '删除员工失败,请稍后重试'
};
}
}
/**
* 更新员工信息
* @param employeeId 员工ID
* @param employeeInfo 员工信息
* @returns 更新后的员工信息
*/
async updateEmployee(employeeId: number, employeeInfo: { name?: string; phone?: string; role?: string }): Promise<EmployeeInfo> {
try {
return await apiService.updateEmployee(employeeId, employeeInfo);
} catch (error) {
console.error('更新员工信息失败:', error);
throw new Error('更新员工信息失败,请稍后重试');
}
}
/**
* 根据手机号查找员工
* @param phone 手机号
* @returns 员工信息或null
*/
async findEmployeeByPhone(phone: string): Promise<EmployeeInfo | null> {
const employees = await this.getEmployees();
return employees.find(emp => emp.phone === phone) || null;
}
/**
* 验证员工信息(用于注册时检查)
* @param name 姓名
* @param phone 手机号
* @returns 验证结果
*/
async validateEmployee(name: string, phone: string): Promise<{ success: boolean; message?: string; employee?: EmployeeInfo }> {
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: '员工信息不存在,请联系管理员添加'
};
}
}
}
/**
* 员工管理服务单例实例
* 导出供应用程序全局使用
*/
export default new EmployeeService();

View File

@@ -1,8 +1,8 @@
// 位置追踪服务 - 处理用户签到后的位置追踪和状态管理
import { UserInfo, LocationData } from '../types';
import apiService from './apiService';
import { isMockMode } from './apiService';
import userService from './userService';
import mapService from './mapService';
/**
* 在线用户信息接口
@@ -11,6 +11,7 @@ export interface OnlineUserInfo {
userId: number;
name: string;
avatarUrl: string;
role: string; // 用户角色:'admin' | 'delivery_person'
lastLocation: LocationData;
lastUpdateTime: number;
status: 'online' | 'offline' | 'timeout';
@@ -73,17 +74,50 @@ class LocationTrackingService {
// 将当前用户添加到在线列表
await this.addUserToOnlineList(userInfo);
// 签到消息已通过REST API处理服务器会自动处理订阅逻辑
// 设置实时位置订阅初始化WebSocket连接
await this.setupRealTimeSubscription();
// WebSocket连接成功后立即发送第一次位置信息
try {
const location = await this.getCurrentLocation();
await this.updateUserLocation(location);
console.log('WebSocket连接成功后立即发送第一次位置信息');
} catch (error) {
console.error('立即发送位置信息失败:', error);
}
// 启动位置更新定时器每30秒更新一次
this.startLocationUpdateTimer();
// 启动状态检查定时器每60秒检查一次
this.startStatusCheckTimer();
// 订阅其他用户的位置更新
await this.subscribeToOtherUsersLocations();
console.log('位置追踪服务已启动');
}
/**
* 初始化位置追踪服务
*/
public async initialize(): Promise<void> {
try {
// 注册位置更新回调
apiService.onLocationUpdate((locationUpdate) => {
this.handleLocationUpdate(locationUpdate);
});
// 注册在线用户列表回调
apiService.onOnlineUserList((userList) => {
this.handleOnlineUserList(userList);
});
console.log('[LocationTrackingService] 位置追踪服务初始化完成');
} catch (error) {
console.error('[LocationTrackingService] 初始化失败:', error);
throw error;
}
}
/**
* 用户签退后停止位置追踪
@@ -96,14 +130,16 @@ class LocationTrackingService {
this.isSignedIn = false;
// 签退消息已通过REST API处理服务器会自动处理取消订阅逻辑
// 从在线列表中移除用户
this.removeUserFromOnlineList(userInfo.id);
// 停止定时器
this.stopTimers();
// 取消订阅
await this.unsubscribeFromLocations();
// 关闭实时位置订阅(服务器会自动处理取消订阅
this.teardownRealTimeSubscription();
console.log('位置追踪服务已停止');
}
@@ -131,18 +167,12 @@ class LocationTrackingService {
timestamp: Date.now()
};
if (isMockMode) {
// 模拟模式:更新本地在线用户列表
console.log('[位置追踪服务] 模拟模式:更新本地位置');
this.updateLocalUserLocation(userInfo.id, locationData);
} else {
// 真实模式调用API更新位置
console.log('[位置追踪服务] 真实模式调用API更新位置');
await apiService.updateDeliveryPersonLocation(userInfo.id, location);
// 同时更新本地缓存
this.updateLocalUserLocation(userInfo.id, locationData);
}
// 真实模式通过WebSocket发送位置更新
console.log('[位置追踪服务] 真实模式通过WebSocket发送位置更新');
await apiService.sendLocationUpdate(userInfo.id, location.latitude, location.longitude);
// 同时更新本地缓存
this.updateLocalUserLocation(userInfo.id, locationData);
// 通知所有回调
this.notifyLocationUpdateCallbacks();
@@ -206,6 +236,7 @@ class LocationTrackingService {
userId: userInfo.id,
name: userInfo.name || '未知用户',
avatarUrl: '/images/user-avatar.png',
role: userInfo.role || 'delivery_person', // 用户角色
lastLocation: currentLocation,
lastUpdateTime: Date.now(),
status: 'online'
@@ -213,7 +244,7 @@ class LocationTrackingService {
this.onlineUsers.set(userInfo.id, onlineUser);
console.log(`用户 ${userInfo.id} 已添加到在线列表`);
}
@@ -305,101 +336,49 @@ class LocationTrackingService {
throw new Error('用户未登录');
}
// 这里应该调用地图服务获取当前位置
// 暂时返回一个默认位置
return {
userId: userInfo.id,
longitude: 102.833722,
latitude: 24.880095,
timestamp: Date.now()
};
}
/**
* 订阅其他用户的位置更新
*/
private async subscribeToOtherUsersLocations(): Promise<void> {
if (isMockMode) {
// 模拟模式:定时生成其他用户的位置更新
this.startMockOtherUsersUpdates();
} else {
// 真实模式通过WebSocket订阅
await this.setupRealTimeSubscription();
try {
// 使用mapService获取真实位置保持与项目中其他地方的一致性
const location = await mapService.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()
};
}
}
/**
* 取消订阅位置更新
*/
private async unsubscribeFromLocations(): Promise<void> {
if (!isMockMode) {
// 真实模式取消WebSocket订阅
await this.teardownRealTimeSubscription();
}
// 真实模式取消WebSocket订阅
await this.teardownRealTimeSubscription();
}
/**
* 启动模拟的其他用户位置更新
*/
private startMockOtherUsersUpdates(): void {
// 模拟其他用户的位置更新每45秒一次
setInterval(() => {
if (this.isSignedIn) {
this.generateMockOtherUsersLocations();
this.notifyLocationUpdateCallbacks();
}
}, 45000);
}
/**
* 生成模拟的其他用户位置
*/
private generateMockOtherUsersLocations(): void {
const currentUserInfo = userService.getGlobalUserInfo();
if (!currentUserInfo) return;
// 模拟2个其他在线用户
const mockUserIds = [101, 102]; // 模拟用户ID
mockUserIds.forEach(userId => {
if (userId !== currentUserInfo.id) {
const existingUser = this.onlineUsers.get(userId);
if (existingUser) {
// 更新现有用户位置
existingUser.lastLocation.longitude += (Math.random() - 0.5) * 0.001;
existingUser.lastLocation.latitude += (Math.random() - 0.5) * 0.001;
existingUser.lastUpdateTime = Date.now();
existingUser.status = 'online';
this.onlineUsers.set(userId, existingUser);
} else {
// 添加新用户
const newUser: OnlineUserInfo = {
userId,
name: `用户${userId}`,
avatarUrl: '/images/user-avatar.png',
lastLocation: {
userId,
longitude: 102.833722 + (Math.random() - 0.5) * 0.01,
latitude: 24.880095 + (Math.random() - 0.5) * 0.01,
timestamp: Date.now()
},
lastUpdateTime: Date.now(),
status: 'online'
};
this.onlineUsers.set(userId, newUser);
this.notifyUserStatusChange(userId, 'online');
}
}
});
}
/**
* 设置实时位置订阅
*/
private setupRealTimeSubscription(): void {
private async setupRealTimeSubscription(): Promise<void> {
// 获取用户信息
const userInfo = userService.getGlobalUserInfo();
if (!userInfo || !userInfo.id) {
@@ -410,25 +389,31 @@ class LocationTrackingService {
// 缓存用户信息
this.userInfo = userInfo;
if (isMockMode) {
console.log('[MOCK] 设置实时位置订阅');
this.startMockLocationGeneration();
return;
}
// 真实环境初始化WebSocket连接并订阅位置更新
// 真实环境初始化WebSocket连接服务器会自动处理订阅逻辑
try {
// 使用新的API接口
apiService.initLocationWebSocket();
// 初始化WebSocket连接如果尚未连接
await apiService.initLocationWebSocket();
// 订阅当前用户的位置更新
apiService.subscribeToLocationUpdates(this.userInfo.id)
.then(() => {
console.log('成功订阅位置更新');
})
.catch((error) => {
console.error('订阅位置更新失败:', error);
});
// 等待WebSocket连接建立最多等待5秒
await new Promise<void>((resolve, reject) => {
let attempts = 0;
const maxAttempts = 50; // 5秒超时
const checkConnection = () => {
if (apiService.isWebSocketConnected()) {
resolve();
} else if (attempts < maxAttempts) {
attempts++;
setTimeout(checkConnection, 100);
} else {
reject(new Error('WebSocket连接建立超时'));
}
};
checkConnection();
});
// 服务器会自动处理订阅逻辑,无需发送订阅消息
console.log('WebSocket连接已建立服务器将自动处理位置订阅逻辑');
// 设置位置更新回调
this.unsubscribeCallback = apiService.onLocationUpdate((locationUpdate) => {
@@ -444,24 +429,10 @@ class LocationTrackingService {
* 关闭实时位置订阅
*/
private teardownRealTimeSubscription(): void {
if (isMockMode) {
console.log('[MOCK] 关闭实时位置订阅');
this.stopMockLocationGeneration();
return;
}
// 真实环境取消订阅并关闭WebSocket连接
// 真实环境关闭WebSocket连接服务器会自动处理取消订阅逻辑
try {
if (this.userInfo) {
// 使用新的API接口取消订阅
apiService.unsubscribeFromLocationUpdates(this.userInfo.id)
.then(() => {
console.log('成功取消订阅位置更新');
})
.catch((error) => {
console.error('取消订阅位置更新失败:', error);
});
}
// 服务器会自动处理取消订阅逻辑,无需发送取消订阅消息
console.log('关闭WebSocket连接服务器将自动处理取消订阅逻辑');
// 移除位置更新回调
if (this.unsubscribeCallback) {
@@ -532,28 +503,88 @@ class LocationTrackingService {
});
}
/**
* 启动模拟位置生成
*/
private startMockLocationGeneration(): void {
console.log('[MOCK] 启动模拟位置生成');
// 这里可以添加模拟位置生成的逻辑
}
/**
* 停止模拟位置生成
*/
private stopMockLocationGeneration(): void {
console.log('[MOCK] 停止模拟位置生成');
// 这里可以添加停止模拟位置生成的逻辑
}
/**
* 处理位置更新
*/
private handleLocationUpdate(locationUpdate: any): void {
console.log('收到位置更新:', locationUpdate);
// 这里可以添加处理位置更新的逻辑
// 验证位置更新消息格式
if (!locationUpdate || typeof locationUpdate !== 'object') {
console.warn('无效的位置更新消息格式');
return;
}
// 提取关键信息
const { deliveryPersonId, latitude, longitude, timestamp } = locationUpdate;
if (!deliveryPersonId || latitude === undefined || longitude === undefined) {
console.warn('位置更新消息缺少必要字段:', locationUpdate);
return;
}
console.log(`处理员工 ${deliveryPersonId} 的位置更新: (${longitude}, ${latitude})`);
// 更新本地缓存中的员工位置
this.updateLocalUserLocation(deliveryPersonId, {
userId: deliveryPersonId,
longitude: longitude,
latitude: latitude,
timestamp: timestamp || Date.now()
});
// 通知所有位置更新回调UI层会监听这些回调来更新地图标记点
this.notifyLocationUpdateCallbacks();
console.log(`员工 ${deliveryPersonId} 位置更新处理完成`);
}
/**
* 处理在线用户列表消息
* @param userList 在线用户列表消息
*/
private handleOnlineUserList(userList: any): void {
try {
console.log('[LocationTrackingService] 收到在线用户列表:', userList);
if (!userList || !userList.users) {
console.warn('[LocationTrackingService] 无效的在线用户列表消息');
return;
}
// 清空当前在线用户列表
this.onlineUsers.clear();
// 更新在线用户列表
userList.users.forEach((userInfo: any) => {
if (userInfo && userInfo.userId) {
this.onlineUsers.set(userInfo.userId, {
userId: userInfo.userId,
name: userInfo.userName || '未知用户',
avatarUrl: '/images/user-avatar.png',
role: userInfo.role || 'delivery_person', // 用户角色,默认为配送员
lastLocation: {
userId: userInfo.userId,
longitude: userInfo.longitude || 0,
latitude: userInfo.latitude || 0,
timestamp: userInfo.lastUpdateTime || Date.now()
},
lastUpdateTime: userInfo.lastUpdateTime || Date.now(),
status: 'online'
});
}
});
console.log('[LocationTrackingService] 在线用户列表已更新,当前在线用户数:', this.onlineUsers.size);
// 通知位置模块更新地图标记点
this.notifyLocationUpdateCallbacks();
} catch (error) {
console.error('[LocationTrackingService] 处理在线用户列表失败:', error);
}
}
}

View File

@@ -1,6 +1,5 @@
// 地图服务 - 处理地图相关的功能,包括定位、路线规划、地理编码等
import apiService from './apiService';
import { isMockMode } from './apiService';
import { AMapRegeoResponse, RoutePlanResult, SearchResult, LocationData } from '../types';
/**
@@ -20,14 +19,7 @@ class MapService {
// 高德地图实例
private amapInstance: any;
// 定时器引用,用于模拟实时位置更新
private locationUpdateTimer: number | null;
// 位置更新回调函数
private locationUpdateCallback: ((location: LocationData) => void) | null;
// 取消订阅函数
private unsubscribeFunction: (() => void) | null;
/**
* 构造函数,初始化地图实例
@@ -40,9 +32,6 @@ class MapService {
latitude: 24.880095
};
this.amapInstance = new this.amapFile.AMapWX({ key: this.MAP_KEY });
this.locationUpdateTimer = null;
this.locationUpdateCallback = null;
this.unsubscribeFunction = null;
}
/**
@@ -50,15 +39,6 @@ class MapService {
* @returns 用户位置坐标
*/
async getLocation(): Promise<{ longitude: number; latitude: number }> {
if (isMockMode) {
// 模拟位置 - 昆明市中心
console.log('[MOCK] 获取用户位置信息');
return {
longitude: 102.7123,
latitude: 25.0409
};
}
return new Promise((resolve, reject) => {
console.log('开始调用高德地图SDK获取位置...');
@@ -149,18 +129,6 @@ class MapService {
speed?: number;
altitude?: number;
}> {
if (isMockMode) {
// 模拟位置 - 昆明市中心
console.log('[MOCK] 获取当前位置信息(兼容格式)');
return {
latitude: 25.0409,
longitude: 102.7123,
accuracy: 50,
speed: 0,
altitude: 1891
};
}
const location = await this.getLocation();
return {
latitude: location.latitude,
@@ -178,23 +146,6 @@ class MapService {
* @returns 逆地理编码结果
*/
async getLocationInfo(longitude: number, latitude: number): Promise<AMapRegeoResponse> {
if (isMockMode) {
// 模拟逆地理编码结果 - 完全符合AMapRegeoResponse接口
console.log('[MOCK] 获取位置详细信息(逆地理编码),坐标:', longitude, latitude);
return {
regeocode: {
addressComponent: {
province: '云南省',
city: '昆明市',
district: '五华区',
street: '',
township: ''
}
},
status: '1'
};
}
return new Promise((resolve, reject) => {
this.amapInstance.getRegeo({
location: `${longitude.toFixed(6)},${latitude.toFixed(6)}`,
@@ -225,32 +176,6 @@ class MapService {
* @returns 搜索结果列表
*/
async searchPoi(keyword: string, city: string): Promise<SearchResult[]> {
if (isMockMode) {
// 模拟搜索结果
console.log('[MOCK] 搜索地点,关键词:', keyword, '城市:', city);
const mockResults: SearchResult[] = [
{
id: '1',
name: '昆明火车站',
address: '昆明市官渡区北京路',
longitude: 102.7222,
latitude: 25.0157,
phone: ''
},
{
id: '2',
name: '昆明长水国际机场',
address: '昆明市官渡区长水村',
longitude: 102.9292,
latitude: 25.1012,
phone: ''
}
];
return mockResults.filter(item =>
item.name.includes(keyword) || item.address.includes(keyword)
);
}
return new Promise((resolve, reject) => {
this.amapInstance.getPoiAround({
querykeywords: keyword,
@@ -289,22 +214,6 @@ class MapService {
* @returns 路线规划结果
*/
async getDrivingRoute(origin: string, destination: string): Promise<RoutePlanResult> {
if (isMockMode) {
// 模拟路线规划结果
console.log('[MOCK] 规划驾车路线,起点:', origin, '终点:', destination);
const [originLng, originLat] = origin.split(',').map(Number);
const [destLng, destLat] = destination.split(',').map(Number);
const distance = this.calculateDistance(originLat, originLng, destLat, destLng);
const duration = Math.round(distance / 10); // 假设平均速度10米/秒
return {
polyline: '',
distance,
duration
};
}
return new Promise((resolve, reject) => {
this.amapInstance.getDrivingRoute({
origin,
@@ -369,41 +278,16 @@ class MapService {
* 获取路线规划(通用版本)
* @param origin 起点坐标
* @param destination 终点坐标
* @param mode 交通方式
* @returns 路线规划结果
*/
async getRoute(
origin: { latitude: number; longitude: number },
destination: { latitude: number; longitude: number },
mode: 'driving' | 'walking' | 'bicycling' = 'driving'
destination: { latitude: number; longitude: number }
): Promise<{
distance: number; // 距离(米)
duration: number; // 时间(秒)
polyline: { latitude: number; longitude: number }[];
}> {
if (isMockMode) {
// 模拟路线规划
console.log('[MOCK] 获取路线规划,起点:', origin, '终点:', destination, '模式:', mode);
const distance = this.calculateDistance(
origin.latitude, origin.longitude,
destination.latitude, destination.longitude
);
const duration = Math.round(distance / 10); // 假设平均速度10米/秒
// 简单的直线路径
const polyline = [
origin,
destination
];
return {
distance,
duration,
polyline
};
}
// 对于真实模式,目前只支持驾车路线
const originStr = `${origin.longitude},${origin.latitude}`;
const destStr = `${destination.longitude},${destination.latitude}`;
@@ -442,34 +326,6 @@ class MapService {
longitude: number;
formattedAddress: string;
}> {
if (isMockMode) {
// 模拟地理编码结果
console.log('[MOCK] 地理编码,地址:', address);
const mockLocations: { [key: string]: { latitude: number; longitude: number; formattedAddress: string } } = {
'昆明市五华区二环西路599号': {
latitude: 25.055281,
longitude: 102.705745,
formattedAddress: '云南省昆明市五华区二环西路599号'
},
'昆明市盘龙区北京路1188号': {
latitude: 25.042498,
longitude: 102.728421,
formattedAddress: '云南省昆明市盘龙区北京路1188号'
},
'昆明市西山区滇池路1234号': {
latitude: 25.028234,
longitude: 102.689190,
formattedAddress: '云南省昆明市西山区滇池路1234号'
}
};
return mockLocations[address] || {
latitude: 25.0409,
longitude: 102.7123,
formattedAddress: '云南省昆明市'
};
}
// 对于真实模式使用搜索API来模拟地理编码
const results = await this.searchPoi(address, '昆明');
if (results.length > 0) {
@@ -502,18 +358,6 @@ class MapService {
district: string;
street: string;
}> {
if (isMockMode) {
console.log('[MOCK] 逆地理编码,坐标:', latitude, longitude);
return {
formattedAddress: '云南省昆明市五华区',
country: '中国',
province: '云南省',
city: '昆明市',
district: '五华区',
street: ''
};
}
const result = await this.getLocationInfo(longitude, latitude);
return {
@@ -548,39 +392,6 @@ class MapService {
address: string;
distance: number;
}>> {
if (isMockMode) {
// 模拟附近地点
console.log('[MOCK] 获取附近的地点,坐标:', latitude, longitude, '半径:', radius, '类型:', type);
const mockPlaces = [
{
id: '1',
name: '昆明火车站',
latitude: 25.0157,
longitude: 102.7222,
address: '昆明市官渡区北京路',
distance: this.calculateDistance(latitude, longitude, 25.0157, 102.7222)
},
{
id: '2',
name: '昆明长水国际机场',
latitude: 25.1012,
longitude: 102.9292,
address: '昆明市官渡区长水村',
distance: this.calculateDistance(latitude, longitude, 25.1012, 102.9292)
},
{
id: '3',
name: '翠湖公园',
latitude: 25.0486,
longitude: 102.7042,
address: '昆明市五华区翠湖公园',
distance: this.calculateDistance(latitude, longitude, 25.0486, 102.7042)
}
];
return mockPlaces.filter(place => place.distance <= radius);
}
// 对于真实模式使用搜索API
const keyword = type ? type : '';
const results = await this.searchPoi(keyword, '昆明');
@@ -595,164 +406,13 @@ class MapService {
})).filter(place => place.distance <= radius);
}
/**
* 获取位置历史记录
* @param userId 用户ID
* @param limit 记录数量限制
* @returns 位置历史记录列表
*/
async getLocationHistory(userId: number, limit: number = 50): Promise<Array<{
id: number;
latitude: number;
longitude: number;
timestamp: number;
accuracy?: number;
speed?: number;
altitude?: number;
}>> {
if (isMockMode) {
// 模拟位置历史记录
console.log('[MOCK] 获取位置历史记录用户ID:', userId, '限制:', limit);
const history: Array<{ id: number; latitude: number; longitude: number; timestamp: number; accuracy?: number; speed?: number; altitude?: number }> = [];
const baseLat = 25.0409;
const baseLng = 102.7123;
for (let i = 0; i < limit; i++) {
history.push({
id: i + 1,
latitude: baseLat + (Math.random() - 0.5) * 0.01,
longitude: baseLng + (Math.random() - 0.5) * 0.01,
timestamp: Date.now() - i * 3600000, // 每小时一个记录
accuracy: 20 + Math.random() * 30,
speed: Math.random() * 10,
altitude: 1891 + (Math.random() - 0.5) * 20
});
}
return history.sort((a, b) => b.timestamp - a.timestamp);
}
// 修复参数名不匹配问题并转换返回值类型以匹配mapService定义
const apiResults = await apiService.getLocationHistory(userId, limit);
return apiResults.map((result, index) => ({
...result,
id: index + 1, // 添加id字段
altitude: 1891 + (Math.random() - 0.5) * 20 // 添加默认海拔高度
})).sort((a, b) => b.timestamp - a.timestamp);
}
/**
* 批量更新货运人员位置
* @param locations 位置信息数组
*/
async batchUpdateDeliveryPersonLocations(
locations: Array<{ userId: number; latitude: number; longitude: number; timestamp: number }>
): Promise<void> {
if (isMockMode) {
console.log('[MOCK] 批量更新货运人员位置:', locations);
return;
}
return apiService.batchUpdateDeliveryPersonLocations(locations);
}
/**
* 订阅实时位置更新
* @param callback 位置更新回调函数
*/
async subscribeToRealTimeLocations(callback: (location: LocationData) => void): Promise<void> {
if (isMockMode) {
// 模拟模式下,定期生成随机位置更新
console.log('[MOCK] 订阅实时位置更新');
// 保存回调引用
this.locationUpdateCallback = callback;
// 启动模拟更新定时器
if (!this.locationUpdateTimer) {
this.locationUpdateTimer = setInterval(() => {
// 生成随机位置更新数据
const randomLocation: LocationData = {
userId: Math.floor(Math.random() * 100) + 100, // 模拟货运人员ID
longitude: 102.714585 + (Math.random() - 0.5) * 0.05, // 昆明附近随机经度
latitude: 25.046321 + (Math.random() - 0.5) * 0.05, // 昆明附近随机纬度
timestamp: Date.now()
};
// 调用回调函数
if (this.locationUpdateCallback) {
this.locationUpdateCallback(randomLocation);
}
}, 3000); // 每3秒更新一次
}
return;
}
// 真实环境中调用API服务的订阅方法
try {
// 获取当前用户信息
const userInfo = wx.getStorageSync('userInfo');
if (!userInfo || !userInfo.id) {
throw new Error('用户未登录,无法订阅位置更新');
}
// 初始化WebSocket连接
await apiService.initLocationWebSocket();
// 订阅位置更新
await apiService.subscribeToLocationUpdates(userInfo.id);
// 使用新的onLocationUpdate方法来注册回调
this.unsubscribeFunction = apiService.onLocationUpdate((location) => {
callback(location as LocationData);
});
} catch (error) {
console.error('订阅实时位置更新失败:', error);
throw error;
}
}
/**
* 取消订阅实时位置更新
*/
async unsubscribeFromRealTimeLocations(): Promise<void> {
if (isMockMode) {
// 模拟模式下,清除定时器
console.log('[MOCK] 取消订阅实时位置更新');
if (this.locationUpdateTimer) {
clearInterval(this.locationUpdateTimer);
this.locationUpdateTimer = null;
}
// 清除回调引用
this.locationUpdateCallback = null;
return;
}
// 真实环境中调用API服务的取消订阅方法
try {
// 获取当前用户信息
const userInfo = wx.getStorageSync('userInfo');
if (userInfo && userInfo.id) {
// 取消订阅
await apiService.unsubscribeFromLocationUpdates(userInfo.id);
}
// 调用取消订阅函数
if (this.unsubscribeFunction) {
this.unsubscribeFunction();
this.unsubscribeFunction = null;
}
// 关闭WebSocket连接
apiService.closeLocationWebSocket();
} catch (error) {
console.error('取消订阅实时位置更新失败:', error);
throw error;
}
}
/**
* 格式化路线距离

View File

@@ -1,80 +1,19 @@
import { Order } from '../types';
import apiService from './apiService';
import { isMockMode } from './apiService';
class OrderService {
// 模拟订单数据
private mockOrders: Order[];
/**
* 构造函数,初始化模拟订单数据
* 构造函数
*/
constructor() {
this.mockOrders = [
{
id: 1001,
startPoint: {
id: 1,
name: '瓦尔塔蓄电池昆明总店',
longitude: 102.705745,
latitude: 25.055281
},
endPoint: {
name: '昆明德众汽车销售服务有限公司',
longitude: 102.714686,
latitude: 25.047134
},
status: 'pending',
goodsType: '瓦尔塔AGM蓄电池',
goodsWeight: 50,
createTime: Date.now() - 3600000 // 1小时前创建
},
{
id: 1002,
startPoint: {
id: 2,
name: '瓦尔塔蓄电池盘龙区分店',
longitude: 102.728421,
latitude: 25.042498
},
endPoint: {
name: '云南中致远汽车销售有限公司',
longitude: 102.796212,
latitude: 24.936947
},
status: 'pending',
goodsType: '瓦尔塔EFB蓄电池',
goodsWeight: 120,
createTime: Date.now() - 7200000 // 2小时前创建
},
{
id: 1003,
startPoint: {
id: 3,
name: '瓦尔塔蓄电池西山区分店',
longitude: 102.689190,
latitude: 25.028234
},
endPoint: {
name: '昆明宝远汽车销售服务有限公司',
longitude: 102.756212,
latitude: 24.986947
},
status: 'pending',
goodsType: '瓦尔塔普通铅酸蓄电池',
goodsWeight: 80,
createTime: Date.now() - 10800000 // 3小时前创建
}
];
// 不再使用模拟数据
}
/**
* 获取所有待处理订单
*/
async getPendingOrders(): Promise<Order[]> {
if (isMockMode) {
return [...this.mockOrders];
}
return apiService.getPendingOrders();
}
@@ -82,10 +21,6 @@ class OrderService {
* 根据ID获取订单
*/
async getOrderById(id: number): Promise<Order | null> {
if (isMockMode) {
const order = this.mockOrders.find(o => o.id === id);
return order || null;
}
return apiService.getOrderById(id);
}
@@ -96,20 +31,6 @@ class OrderService {
* @returns 指派结果包含success状态和可选消息
*/
async assignOrder(orderId: number, deliveryPersonId: number): Promise<{ success: boolean; message?: string }> {
if (isMockMode) {
// 模拟数据 - 查找订单并更新状态
const order = this.mockOrders.find(o => o.id === orderId);
if (order) {
order.status = 'assigned';
order.deliveryPersonId = deliveryPersonId;
console.log(`[MOCK] 订单 ${orderId} 已指派给货运人员 ${deliveryPersonId}`);
return { success: true, message: '指派成功' };
} else {
console.warn(`[MOCK] 订单 ${orderId} 不存在`);
return { success: false, message: '订单不存在' };
}
}
// 真实环境中调用API
try {
return await apiService.assignOrder(orderId, deliveryPersonId);
@@ -123,15 +44,6 @@ class OrderService {
* 更新订单状态
*/
async updateOrderStatus(orderId: number, status: Order['status']): Promise<{ success: boolean; message?: string }> {
if (isMockMode) {
const order = this.mockOrders.find(o => o.id === orderId);
if (order) {
order.status = status;
console.log(`[MOCK] 订单 ${orderId} 状态更新为 ${status}`);
return { success: true, message: '状态更新成功' };
}
return { success: false, message: '订单不存在' };
}
return apiService.updateOrderStatus(orderId, status).then(result => ({
success: result.success,
message: result.message || '状态更新成功'
@@ -142,15 +54,6 @@ class OrderService {
* 创建新订单
*/
async createOrder(orderData: Omit<Order, 'id' | 'createTime'>): Promise<Order> {
if (isMockMode) {
const newOrder: Order = {
...orderData,
id: Math.max(...this.mockOrders.map(o => o.id), 1000) + 1,
createTime: Date.now()
};
this.mockOrders.push(newOrder);
return newOrder;
}
return apiService.createOrder(orderData);
}
@@ -158,10 +61,6 @@ class OrderService {
* 获取货运人员的订单列表
*/
async getDeliveryPersonOrders(deliveryPersonId: number): Promise<Order[]> {
if (isMockMode) {
// 模拟模式下返回部分订单
return this.mockOrders.slice(0, 2);
}
return apiService.getDeliveryPersonOrders(deliveryPersonId);
}
@@ -169,17 +68,14 @@ class OrderService {
* 删除订单
* @param orderId 订单ID
*/
async deleteOrder(orderId: number): Promise<void> {
if (isMockMode) {
// 在模拟数据中删除订单
const index = this.mockOrders.findIndex(o => o.id === orderId);
if (index !== -1) {
this.mockOrders.splice(index, 1);
console.log(`订单 ${orderId} 已删除`);
}
return;
async deleteOrder(orderId: number): Promise<{ success: boolean; message?: string }> {
try {
const result = await apiService.deleteOrder(orderId);
return { success: true, message: '删除成功' };
} catch (error) {
console.error('删除订单失败:', error);
return { success: false, message: error instanceof Error ? error.message : '删除失败' };
}
return apiService.deleteOrder(orderId);
}
}

View File

@@ -1,32 +1,21 @@
// 用户服务文件
// 用户服务 - 处理用户相关的数据操作
// 用户服务 - 处理用户认证、会话管理、权限验证等
import { UserInfo, EmployeeInfo } from '../types';
import { Role } from '../utils/roleUtils';
import apiService from './apiService';
import { isMockMode } from './apiService';
/**
* 用户服务类
* 提供用户认证、信息管理、权限验证等功能
*/
class UserService {
// 模拟用户数据
private mockUsers: UserInfo[];
/**
* 构造函数,初始化模拟用户数据
* 构造函数
*/
constructor() {
this.mockUsers = [
{
id: 1,
role: 'ADMIN'
},
{
id: 2,
role: 'DELIVERY_PERSON'
}
];
// 不再使用模拟数据
}
/**
@@ -34,14 +23,6 @@ class UserService {
* @returns 用户信息
*/
async getUserInfo(): Promise<UserInfo> {
if (isMockMode) {
// 模拟数据 - 返回管理员信息
console.log('[MOCK] 获取用户信息');
return {
id: 1,
role: 'ADMIN'
};
}
return apiService.getUserInfo();
}
@@ -49,11 +30,6 @@ class UserService {
* 用户退出登录
*/
async logout(): Promise<void> {
if (isMockMode) {
// 模拟登出
console.log('[MOCK] 用户登出');
return;
}
return apiService.logout();
}
@@ -80,7 +56,7 @@ class UserService {
* @returns 是否为管理员
*/
isAdmin(): boolean {
return this.getUserRole() === 'ADMIN';
return this.getUserRole() === Role.ADMIN;
}
/**
@@ -88,7 +64,7 @@ class UserService {
* @returns 是否为货运人员
*/
isDeliveryPerson(): boolean {
return this.getUserRole() === 'DELIVERY_PERSON';
return this.getUserRole() === Role.DELIVERY_PERSON;
}
/**
@@ -194,25 +170,6 @@ class UserService {
*/
async ServerLogin(code: string): Promise<{ success: boolean; openid?: string; token?: string; userInfo?: UserInfo }> {
try {
if (isMockMode) {
// 模拟登录成功
console.log('[MOCK] 微信小程序登录');
// 使用模拟用户数据
const userInfo = this.mockUsers[0];
const openid = 'mock-openid-' + Math.random().toString(36).substring(2);
const token = 'mock-token-' + Date.now();
const session_key = 'mock-session-key-' + Math.random().toString(36).substring(2);
// 保存到本地存储
wx.setStorageSync('userInfo', userInfo);
wx.setStorageSync('token', token);
wx.setStorageSync('openid', openid);
wx.setStorageSync('session_key', session_key);
return { success: true, openid, token, userInfo };
}
// 真实API模式
//TODO: 登录成功的基础数据:服务器下发的公共游客可看的数据
const result = await apiService.ServerLogin(code);
@@ -268,14 +225,6 @@ class UserService {
* @returns 更新后的用户信息
*/
async updateUserInfo(userInfo: Partial<UserInfo>): Promise<UserInfo> {
if (isMockMode) {
// 模拟更新成功
console.log('[MOCK] 更新用户信息');
return {
id: 1,
role: userInfo.role || 'GUEST'
};
}
return apiService.updateUserInfo(userInfo);
}
@@ -284,14 +233,6 @@ class UserService {
* @returns 用户状态信息
*/
async getUserStatus(): Promise<{ status: 'signed_in' | 'signed_out' | 'registered' | 'unregistered'; lastSignInTime?: string; lastSignOutTime?: string }> {
if (isMockMode) {
// 模拟数据 - 默认返回已注册状态
console.log('[MOCK] 获取用户状态');
return {
status: 'registered'
};
}
try {
// 调用服务器接口获取用户状态
const response = await apiService.getUserStatus();
@@ -328,24 +269,26 @@ class UserService {
throw new Error('用户认证信息缺失,请重新登录');
}
if (isMockMode) {
// 模拟签到成功,返回员工信息
console.log('[MOCK] 用户签到成功');
const employeeInfo: EmployeeInfo = {
id: userInfo.id,
name: '测试用户',
phone: '13800138000',
role: userInfo.role || 'DELIVERY_PERSON'
};
return {
success: true,
employeeInfo: employeeInfo,
message: '签到成功'
};
return apiService.userSignIn(userInfo.id);
}
/**
* 用户签退
* @returns 签退结果
*/
async signOut(): Promise<{ success: boolean; message?: string }> {
const userInfo = this.getGlobalUserInfo();
if (!userInfo || !userInfo.id) {
throw new Error('用户未登录,无法签退');
}
// 检查是否有有效的token防止后端空指针异常
const app = getApp<any>();
if (!app.globalData.token) {
throw new Error('用户认证信息缺失,请重新登录');
}
return apiService.userSignIn(userInfo.id);
return apiService.userSignOut(userInfo.id);
}
/**
@@ -354,29 +297,6 @@ class UserService {
* @returns 注册结果和员工信息
*/
async register(registerInfo: { name: string; phone: string }): Promise<{ success: boolean; employeeInfo: EmployeeInfo; message?: string }> {
if (isMockMode) {
// 模拟注册成功
console.log('[MOCK] 用户注册成功');
// 确保所有必需字段都有值
const employeeInfo: EmployeeInfo = {
id: Date.now(),
name: registerInfo.name,
phone: registerInfo.phone,
role: 'DELIVERY_PERSON'
};
this.mockUsers.push({
id: employeeInfo.id,
role: employeeInfo.role || 'DELIVERY_PERSON',
name: employeeInfo.name,
phone: employeeInfo.phone
});
return {
success: true,
employeeInfo: employeeInfo,
message: '注册成功'
};
}
return apiService.userRegister(registerInfo);
}
@@ -385,20 +305,6 @@ class UserService {
* @returns 权限列表
*/
async getUserPermissions(): Promise<string[]> {
if (isMockMode) {
// 模拟权限列表
console.log('[MOCK] 获取用户权限列表');
return [
'order:view',
'order:edit',
'delivery:view',
'delivery:edit',
'warehouse:view',
'warehouse:edit',
'user:view',
'user:edit'
];
}
return apiService.getUserPermissions();
}
@@ -407,11 +313,6 @@ class UserService {
* @returns 是否在线
*/
async checkUserOnline(): Promise<boolean> {
if (isMockMode) {
// 模拟用户在线
console.log('[MOCK] 检查用户在线状态');
return true;
}
return apiService.checkUserOnline();
}
@@ -425,25 +326,6 @@ class UserService {
expiresAt: number;
permissions: string[];
}> {
if (isMockMode) {
// 模拟会话信息
console.log('[MOCK] 获取用户会话信息');
return {
userId: 1,
sessionId: 'mock-session-' + Date.now(),
expiresAt: Date.now() + 86400000, // 24小时后过期
permissions: [
'order:view',
'order:edit',
'delivery:view',
'delivery:edit',
'warehouse:view',
'warehouse:edit',
'user:view',
'user:edit'
]
};
}
return apiService.getSessionInfo();
}
@@ -453,14 +335,6 @@ class UserService {
* @returns 新令牌及过期时间
*/
async refreshToken(oldToken: string): Promise<{ token: string; expiresAt: number }> {
if (isMockMode) {
// 模拟令牌刷新
console.log('[MOCK] 刷新用户令牌');
return {
token: 'mock-refreshed-token-' + Date.now(),
expiresAt: Date.now() + 86400000 // 24小时后过期
};
}
return apiService.refreshToken(oldToken);
}
@@ -470,11 +344,6 @@ class UserService {
* @returns 是否拥有该权限
*/
async verifyPermission(permission: string): Promise<boolean> {
if (isMockMode) {
// 模拟权限验证(管理员拥有所有权限)
console.log('[MOCK] 验证用户权限:', permission);
return true;
}
return apiService.verifyPermission(permission);
}
}

View File

@@ -1,156 +1,19 @@
import { WarehouseInfo } from '../types';
import apiService from './apiService';
import { isMockMode } from './apiService';
/**
* 仓库服务类
* 封装了所有仓库相关的操作
*/
class WarehouseService {
// 模拟仓库数据
private warehouses: WarehouseInfo[];
/**
* 构造函数,初始化模拟仓库数据
* 构造函数
*/
constructor() {
this.warehouses = [
{
id: 1,
name: '瓦尔塔蓄电池昆明总店',
address: '昆明市五华区二环西路599号',
contact: '刘经理',
phone: '0871-65123456',
description: '瓦尔塔蓄电池云南总代理,提供全系列蓄电池产品',
status: 'open',
capacity: 2000, // 仓库容量(吨)
longitude: 102.705745,
latitude: 25.055281
},
{
id: 2,
name: '瓦尔塔蓄电池盘龙区分店',
address: '昆明市盘龙区北京路1188号',
contact: '张经理',
phone: '0871-65678901',
description: '专业销售瓦尔塔汽车蓄电池,提供安装和售后服务',
status: 'open',
capacity: 800, // 仓库容量(吨)
longitude: 102.728421,
latitude: 25.042498
},
{
id: 3,
name: '瓦尔塔蓄电池西山区分店',
address: '昆明市西山区滇池路1234号',
contact: '李经理',
phone: '0871-65234567',
description: '瓦尔塔蓄电池授权经销商,专业汽车电池解决方案',
status: 'open',
capacity: 600, // 仓库容量(吨)
longitude: 102.689190,
latitude: 25.028234
},
{
id: 4,
name: '瓦尔塔蓄电池官渡区分店',
address: '昆明市官渡区春城路456号',
contact: '王经理',
phone: '0871-65345678',
description: '瓦尔塔蓄电池专卖店,各类车型电池齐全',
status: 'open',
capacity: 700, // 仓库容量(吨)
longitude: 102.725745,
latitude: 25.025281
},
{
id: 5,
name: '瓦尔塔蓄电池呈贡区分店',
address: '昆明市呈贡区春融街789号',
contact: '赵经理',
phone: '0871-65456789',
description: '瓦尔塔蓄电池呈贡区授权经销商,提供专业安装服务',
status: 'open',
capacity: 500, // 仓库容量(吨)
longitude: 102.788421,
latitude: 24.902498
},
{
id: 6,
name: '瓦尔塔蓄电池五华区服务中心',
address: '昆明市五华区一二一大街200号',
contact: '陈经理',
phone: '0871-65567890',
description: '瓦尔塔蓄电池专业售后服务中心,提供电池检测和更换',
status: 'open',
capacity: 400, // 仓库容量(吨)
longitude: 102.722745,
latitude: 25.040281
},
{
id: 7,
name: '瓦尔塔蓄电池安宁市分店',
address: '昆明市安宁市金方路300号',
contact: '杨经理',
phone: '0871-65678902',
description: '瓦尔塔蓄电池安宁市授权经销商,各类车型电池销售',
status: 'open',
capacity: 300, // 仓库容量(吨)
longitude: 102.458421,
latitude: 24.902498
},
{
id: 8,
name: '瓦尔塔蓄电池晋宁区分店',
address: '昆明市晋宁区昆阳大街120号',
contact: '黄经理',
phone: '0871-65789012',
description: '瓦尔塔蓄电池晋宁区销售点,提供汽车和电动车电池',
status: 'open',
capacity: 250, // 仓库容量(吨)
longitude: 102.519190,
latitude: 24.688234
},
{
id: 9,
name: '瓦尔塔蓄电池宜良县分店',
address: '昆明市宜良县匡远镇汇东路88号',
contact: '吴经理',
phone: '0871-65890123',
description: '瓦尔塔蓄电池宜良县授权经销商,专业汽车电池服务',
status: 'open',
capacity: 200, // 仓库容量(吨)
longitude: 103.115745,
latitude: 24.905281
},
{
id: 10,
name: '瓦尔塔蓄电池嵩明县分店',
address: '昆明市嵩明县嵩阳镇玉明路66号',
contact: '郑经理',
phone: '0871-65901234',
description: '瓦尔塔蓄电池嵩明县销售中心,各类蓄电池产品齐全',
status: 'open',
capacity: 180, // 仓库容量(吨)
longitude: 103.048421,
latitude: 25.362498
}
];
// 真实API模式下不需要模拟数据
}
/**
* 获取所有仓库信息(同步版本)
*/
private getAllWarehousesSync(): WarehouseInfo[] {
return [...this.warehouses];
}
/**
* 根据ID获取仓库信息同步版本
*/
private getWarehouseByIdSync(id: number): WarehouseInfo | undefined {
return this.warehouses.find(warehouse => warehouse.id === id);
}
/**
* 获取仓库状态的中文描述
@@ -168,9 +31,6 @@ class WarehouseService {
* 获取所有仓库信息
*/
async getWarehouses(): Promise<WarehouseInfo[]> {
if (isMockMode) {
return this.getAllWarehousesSync();
}
return apiService.getWarehouses();
}
@@ -178,9 +38,6 @@ class WarehouseService {
* 根据ID获取仓库信息
*/
async getWarehouseById(id: number): Promise<WarehouseInfo | null> {
if (isMockMode) {
return this.getWarehouseByIdSync(id) || null;
}
return apiService.getWarehouseById(id);
}