433 lines
13 KiB
TypeScript
433 lines
13 KiB
TypeScript
// 货运人员服务 - 处理货运人员相关的数据操作
|
||
import { DeliveryPerson, LocationData } 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;
|
||
}
|
||
|
||
/**
|
||
* 获取所有货运人员
|
||
* @returns 货运人员列表
|
||
*/
|
||
async getDeliveryPersons(): Promise<DeliveryPerson[]> {
|
||
if (isMockMode) {
|
||
// 模拟数据 - 返回所有货运人员
|
||
console.log('[MOCK] 获取所有货运人员');
|
||
return [...this.mockDeliveryPersons];
|
||
}
|
||
return apiService.getDeliveryPersons();
|
||
}
|
||
|
||
/**
|
||
* 根据ID获取货运人员
|
||
* @param id 货运人员ID
|
||
* @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;
|
||
} catch (error) {
|
||
console.error('获取货运人员失败:', error);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 更新货运人员位置
|
||
* @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();
|
||
}
|
||
|
||
/**
|
||
* 获取忙碌的货运人员
|
||
* @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
|
||
* @returns 订单列表
|
||
*/
|
||
async getDeliveryPersonOrders(deliveryPersonId: number): Promise<Array<{
|
||
id: number;
|
||
startPoint: {
|
||
id: number;
|
||
name: string;
|
||
longitude: number;
|
||
latitude: number;
|
||
};
|
||
endPoint: {
|
||
name: string;
|
||
longitude: number;
|
||
latitude: number;
|
||
};
|
||
status: string;
|
||
goodsType: string;
|
||
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);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 货运人员服务单例实例
|
||
* 导出供应用程序全局使用
|
||
*/
|
||
export default new DeliveryPersonService(); |