Files
WXProgram/miniprogram/pages/admin/admin.ts
2025-10-16 21:32:16 +08:00

578 lines
14 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 管理员页面逻辑
import { UserInfo, Marker, Order, DeliveryPerson, WarehouseInfo } from '../../types';
import mapService from '../../services/mapService';
import warehouseService from '../../services/warehouseService';
import orderService from '../../services/orderService';
import deliveryService from '../../services/deliveryPersonService';
Page({
data: {
userInfo: null as UserInfo | null,
mapCenter: mapService.getKunmingCenter(),
markers: [] as Marker[],
polyline: {} as any,
// 订单相关
orders: [] as Order[],
filteredOrders: [] as Order[],
activeTab: 'all',
showAssignModal: false,
selectedOrderId: 0,
showAddModal: false,
// 新增订单表单数据
warehouseIndex: 0,
warehouses: [] as WarehouseInfo[],
endName: '',
goodsType: '',
goodsWeight: 0,
// 员工相关
deliveryPersons: [] as DeliveryPerson[],
availableStaff: [] as DeliveryPerson[],
// 底部页签
currentTab: 'main'
},
onLoad() {
// 模拟管理员登录状态
this.setData({
userInfo: {
id: 1,
name: '管理员',
role: 'ADMIN',
phone: '13800138000'
}
});
// 初始化数据
this.initData();
},
onShow() {
// 页面显示时刷新数据
this.refreshData();
},
// 初始化数据
initData() {
// 获取仓库数据
warehouseService.getWarehouses().then(warehouses => {
this.setData({
warehouses
});
}).catch(error => {
console.error('获取仓库数据失败:', error);
});
// 刷新数据
this.refreshData();
},
// 刷新数据
refreshData() {
// 获取订单数据 - 使用正确的getPendingOrders方法
orderService.getPendingOrders().then(orders => {
// 获取员工数据 - 使用正确的getDeliveryPersons方法
deliveryService.getDeliveryPersons().then(deliveryPersons => {
// 更新地图标记点
const markers = this.generateMarkers(orders, deliveryPersons);
this.setData({
orders,
deliveryPersons,
markers
});
// 过滤订单
this.filterOrders();
}).catch(error => {
console.error('获取货运人员数据失败:', error);
});
}).catch(error => {
console.error('获取订单数据失败:', error);
});
},
// 生成地图标记点
generateMarkers(orders: Order[], deliveryPersons: DeliveryPerson[]): Marker[] {
const markers: Marker[] = [];
// 添加订单起点标记(仓库)
const warehouseMarkers = new Map<number, Marker>();
orders.forEach(order => {
if (!warehouseMarkers.has(order.startPoint.id)) {
warehouseMarkers.set(order.startPoint.id, {
id: order.startPoint.id,
longitude: order.startPoint.longitude,
latitude: order.startPoint.latitude,
title: order.startPoint.name,
iconPath: '/images/warehouse.png',
width: 32,
height: 32,
zIndex: 10,
callout: {
content: order.startPoint.name,
color: '#333',
fontSize: 24,
borderRadius: 10,
bgColor: '#fff',
padding: 10,
display: 'BYCLICK'
}
});
}
});
// 添加订单终点标记
orders.forEach((order) => {
markers.push({
id: 10000 + order.id, // 避免ID冲突
longitude: order.endPoint.longitude,
latitude: order.endPoint.latitude,
title: order.endPoint.name,
iconPath: this.getOrderStatusIcon(order.status),
width: 32,
height: 32,
zIndex: 20,
callout: {
content: `${order.endPoint.name}\n${order.goodsType} ${order.goodsWeight}kg`,
color: '#333',
fontSize: 24,
borderRadius: 10,
bgColor: '#fff',
padding: 10,
display: 'BYCLICK'
}
});
});
// 添加员工位置标记
deliveryPersons.forEach(person => {
markers.push({
id: 20000 + person.id, // 避免ID冲突
longitude: person.currentLocation.longitude,
latitude: person.currentLocation.latitude,
title: person.name,
iconPath: this.getStaffStatusIcon(person.status),
width: 32,
height: 32,
zIndex: 30,
callout: {
content: `${person.name}\n订单数: ${person.currentOrders.length}\n状态: ${this.getStatusText(person.status)}`,
color: '#333',
fontSize: 24,
borderRadius: 10,
bgColor: '#fff',
padding: 10,
display: 'BYCLICK'
}
});
});
// 添加仓库标记
markers.push(...Array.from(warehouseMarkers.values()));
return markers;
},
// 获取订单状态对应的图标
getOrderStatusIcon(status: string): string {
switch (status) {
case 'pending':
return '/images/order-pending.png';
case 'assigned':
return '/images/order-assigned.png';
case 'in_transit':
return '/images/order-transit.png';
case 'delivered':
return '/images/order-delivered.png';
default:
return '/images/order-pending.png';
}
},
// 获取员工状态对应的图标
getStaffStatusIcon(_status: string): string {
// 统一使用trucks.png作为货运人员图标
return '/images/trucks.png';
},
// 获取状态文本
getStatusText(status: string): string {
const statusMap: Record<string, string> = {
'pending': '未分配',
'assigned': '已分配',
'in_transit': '配送中',
'delivered': '已完成',
'idle': '空闲',
'busy': '忙碌',
'offline': '离线'
};
return statusMap[status] || status;
},
// 过滤订单
filterOrders() {
const { orders, activeTab } = this.data;
let filteredOrders = orders;
if (activeTab !== 'all') {
filteredOrders = orders.filter(order => order.status === activeTab);
}
this.setData({
filteredOrders
});
},
// 切换订单标签
switchTab(e: any) {
const tab = e.currentTarget.dataset.tab;
this.setData({
activeTab: tab
});
this.filterOrders();
},
// 处理订单点击
handleOrderTap(e: any) {
const orderId = e.currentTarget.dataset.id;
const order = this.data.orders.find(o => o.id === orderId);
if (!order) return;
if (order.status === 'pending') {
// 未分配的订单,显示分配弹窗
const availableStaff = this.data.deliveryPersons.filter(person => person.status === 'idle');
this.setData({
showAssignModal: true,
selectedOrderId: orderId,
availableStaff
});
} else if (order.status === 'assigned' || order.status === 'in_transit') {
// 已分配的订单,跳转到地图并聚焦到配送员
const assignedPerson = this.data.deliveryPersons.find(person =>
person.currentOrders.some(o => o.id === orderId)
);
if (assignedPerson) {
this.setData({
mapCenter: assignedPerson.currentLocation
});
// 绘制从起点到终点的路线
this.drawRoute(order.startPoint.longitude, order.startPoint.latitude,
order.endPoint.longitude, order.endPoint.latitude);
}
}
},
// 处理员工点击
handleStaffTap(e: any) {
const staffId = e.currentTarget.dataset.id;
const staff = this.data.deliveryPersons.find(p => p.id === staffId);
if (staff) {
// 跳转到地图并聚焦到员工位置
this.setData({
mapCenter: staff.currentLocation
});
}
},
// 绘制路线
drawRoute(startLng: number, startLat: number, endLng: number, endLat: number) {
const origin = `${startLng},${startLat}`;
const destination = `${endLng},${endLat}`;
mapService.getDrivingRoute(origin, destination).then(result => {
if (result.polyline) {
// 解码polyline
const points = this.decodePolyline(result.polyline);
if (points.length > 0) {
this.setData({
polyline: {
points,
color: '#0091ff',
width: 8,
dottedLine: false
}
});
}
}
}).catch(err => {
console.error('绘制路线失败:', err);
});
},
// 解码polyline
decodePolyline(polyline: string): Array<{ longitude: number; latitude: number }> {
const points: Array<{ longitude: number; latitude: number }> = [];
let index = 0, len = polyline.length;
let lat = 0, lng = 0;
while (index < len) {
let b, shift = 0, result = 0;
do {
b = polyline.charCodeAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
const dlat = ((result & 1) !== 0 ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = polyline.charCodeAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
const dlng = ((result & 1) !== 0 ? ~(result >> 1) : (result >> 1));
lng += dlng;
points.push({
longitude: lng / 100000,
latitude: lat / 100000
});
}
return points;
},
// 显示分配弹窗
showAssignModal() {
this.setData({
showAssignModal: true
});
},
// 隐藏分配弹窗
hideAssignModal() {
this.setData({
showAssignModal: false
});
},
// 分配订单
assignOrder(e: any) {
const staffId = e.currentTarget.dataset.id;
const { selectedOrderId } = this.data;
if (!selectedOrderId || !staffId) {
wx.showToast({
title: '请选择订单和货运人员',
icon: 'none'
});
return;
}
// 修复使用正确的orderService.assignOrder方法
orderService.assignOrder(selectedOrderId, staffId).then(result => {
if (result.success) {
wx.showToast({
title: '指派成功',
icon: 'success'
});
// 刷新数据
this.refreshData();
} else {
wx.showToast({
title: result.message || '指派失败',
icon: 'none'
});
}
}).catch(error => {
console.error('指派订单失败:', error);
wx.showToast({
title: '指派失败,请重试',
icon: 'none'
});
});
this.hideAssignModal();
},
// 显示新增订单弹窗
showAddOrderModal() {
this.setData({
showAddModal: true,
endName: '',
goodsType: '',
goodsWeight: 0,
warehouseIndex: 0
});
},
// 隐藏新增订单弹窗
hideAddModal() {
this.setData({
showAddModal: false
});
},
// 仓库选择变化
onWarehouseChange(e: any) {
this.setData({
warehouseIndex: e.detail.value
});
},
// 终点名称输入
onEndNameInput(e: any) {
this.setData({
endName: e.detail.value
});
},
// 货物类型输入
onGoodsTypeInput(e: any) {
this.setData({
goodsType: e.detail.value
});
},
// 货物重量输入
onGoodsWeightInput(e: any) {
this.setData({
goodsWeight: parseFloat(e.detail.value) || 0
});
},
// 创建订单
createOrder() {
const { warehouses, warehouseIndex, endName, goodsType, goodsWeight } = this.data;
// 表单验证
if (!warehouses[warehouseIndex]) {
wx.showToast({
title: '请选择仓库',
icon: 'none'
});
return;
}
if (!endName) {
wx.showToast({
title: '请输入终点名称',
icon: 'none'
});
return;
}
if (!goodsType) {
wx.showToast({
title: '请输入货物类型',
icon: 'none'
});
return;
}
if (goodsWeight <= 0) {
wx.showToast({
title: '请输入有效的货物重量',
icon: 'none'
});
return;
}
// 获取仓库信息
const warehouse = warehouses[warehouseIndex];
// 模拟终点坐标(实际应用中应该通过地图选择或搜索获取)
// 从已有仓库中获取一个坐标作为参考点
const referenceWarehouse = this.data.warehouses[0];
const endPoint = {
name: endName,
longitude: referenceWarehouse.address ? 102.715 + (Math.random() - 0.5) * 0.1 : 102.715,
latitude: referenceWarehouse.address ? 25.045 + (Math.random() - 0.5) * 0.1 : 25.045
};
// 创建订单数据
const newOrder: Omit<Order, 'id' | 'createTime'> = {
startPoint: {
id: warehouse.id,
name: warehouse.name,
longitude: 102.715, // 临时使用固定坐标
latitude: 25.045 // 临时使用固定坐标
},
endPoint,
status: 'pending',
goodsType,
goodsWeight
};
// 调用服务创建订单 - 使用正确的orderService.createOrder方法
orderService.createOrder(newOrder).then(() => {
wx.showToast({
title: '创建成功',
icon: 'success'
});
// 刷新数据
this.refreshData();
}).catch(error => {
console.error('创建订单失败:', error);
wx.showToast({
title: '创建失败',
icon: 'error'
});
});
this.hideAddModal();
},
// 切换底部页签
switchMainTab(e: any) {
const tab = e.currentTarget.dataset.tab;
this.setData({
currentTab: tab
});
// 根据不同的页签执行不同的逻辑
switch (tab) {
case 'main':
// 管理中心,显示所有内容
break;
case 'orders':
// 订单详情,可能需要调整布局
break;
case 'staff':
// 员工管理,可能需要调整布局
break;
}
},
// 地图点击事件
onMapTap() {
// 清除路线
this.setData({
polyline: {}
});
},
// 格式化时间
formatTime(time: number): string {
const date = new Date(time);
const now = new Date();
const diff = now.getTime() - date.getTime();
if (diff < 60000) {
return '刚刚';
} else if (diff < 3600000) {
return `${Math.floor(diff / 60000)}分钟前`;
} else if (diff < 86400000) {
return `${Math.floor(diff / 3600000)}小时前`;
} else {
const month = date.getMonth() + 1;
const day = date.getDate();
const hour = date.getHours();
const minute = date.getMinutes();
return `${month}${day}${hour}:${minute < 10 ? '0' + minute : minute}`;
}
}
});