Files
platforms/backend/api/internal/logic/client/user/delivery_track.go
czl231 3ef33b531d 已完成用户APP首期功能开发
交付用户端首期页面、配套接口、后台资源及测试文档。用户APP构建、静态分析和三个管理后台构建通过;完整测试仍有2项失败,后端模型注释检查未通过,详见交付记录。
2026-09-13 00:57:32 +08:00

122 lines
5.0 KiB
Go
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.
// 功能描述向用户本人提供隐私化配送轨迹与履约时间线版本1.0.0。
package user
import (
"math"
"strconv"
"git.apinb.com/bsm-sdk/core/infra"
"git.apinb.com/heqiapp/platforms/backend/api/internal/impl"
common "git.apinb.com/heqiapp/platforms/backend/api/internal/logic/common"
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
"github.com/gin-gonic/gin"
)
// GetGasOrderDeliveryTrack 先限定本人订单,再将定位点约化到约百米精度后下发。
func GetGasOrderDeliveryTrack(ctx *gin.Context) {
account, ok := common.UserAccount(ctx)
if !ok {
return
}
var order models.GasorderBasic
if err := impl.DBService.Where("identity = ? AND user_account_id = ? AND status <> ?", ctx.Param("identity"), account.ID, common.StatusArchived).First(&order).Error; err != nil {
gasDetailError(ctx, err)
return
}
var station models.GasBasic
if order.GasBasicID != 0 {
if err := impl.DBService.Where("id = ? AND status = ?", order.GasBasicID, common.StatusEnable).Find(&station).Error; err != nil {
gasDetailError(ctx, err)
return
}
}
var staff models.StaffAccount
if order.StaffAccountID != 0 {
if err := impl.DBService.Where("id = ? AND role_code = ? AND status = ?", order.StaffAccountID, "delivery", common.StatusEnable).Find(&staff).Error; err != nil {
gasDetailError(ctx, err)
return
}
}
var track models.GasorderTrack
if err := impl.DBService.Where("gasorder_basic_id = ? AND status <> ?", order.ID, common.StatusArchived).Order("attempt_no desc, id desc").Limit(1).Find(&track).Error; err != nil {
gasDetailError(ctx, err)
return
}
var points []models.GasorderTrackPoint
if track.ID != 0 {
if err := impl.DBService.Where("gasorder_track_id = ? AND status = ?", track.ID, common.StatusEnable).Order("occurred_at asc, id asc").Limit(200).Find(&points).Error; err != nil {
gasDetailError(ctx, err)
return
}
}
var histories []models.GasorderStatus
if err := impl.DBService.Where("gasorder_basic_id = ? AND status <> ?", order.ID, common.StatusArchived).Order("occurred_at asc, id asc").Find(&histories).Error; err != nil {
gasDetailError(ctx, err)
return
}
publicPoints := make([]gin.H, 0, len(points))
for _, point := range points {
longitude, longitudeOK := approximateCoordinate(point.Longitude, -180, 180)
latitude, latitudeOK := approximateCoordinate(point.Latitude, -90, 90)
if longitudeOK && latitudeOK {
publicPoints = append(publicPoints, gin.H{"longitude": longitude, "latitude": latitude, "occurred_at": point.OccurredAt})
}
}
publicTimeline := make([]gin.H, 0, len(histories))
for _, history := range histories {
if title, detail, visible := deliveryTimelineText(history.ToStatus, station.Name); visible {
publicTimeline = append(publicTimeline, gin.H{
"status_code": history.ToStatus, "title": title, "detail": detail, "occurred_at": history.OccurredAt,
})
}
}
destinationLongitude, destinationLongitudeOK := approximateCoordinate(order.Longitude, -180, 180)
destinationLatitude, destinationLatitudeOK := approximateCoordinate(order.Latitude, -90, 90)
infra.Response.Success(ctx, gin.H{
"identity": order.Identity, "status_code": order.OrderStatus, "status_name": gasOrderStatusName(order.OrderStatus),
"status_message": deliveryStatusMessage(order.OrderStatus), "appointment_at": order.AppointmentAt,
"updated_at": nullableTrackTime(track.ID != 0, track.UpdatedAt), "station_name": station.Name,
"staff_name": staff.Name, "staff_avatar": "", "staff_phone_masked": common.MaskPhone(staff.Phone),
"controlled_call_available": false, "route_available": len(publicPoints) > 0,
"destination_available": destinationLongitudeOK && destinationLatitudeOK,
"destination_longitude": destinationLongitude, "destination_latitude": destinationLatitude,
"points": publicPoints, "timeline": publicTimeline,
})
}
// approximateCoordinate 仅返回三位小数,避免用户接口暴露服务人员的精确实时位置。
func approximateCoordinate(value string, min, max float64) (float64, bool) {
parsed, err := strconv.ParseFloat(value, 64)
if err != nil || parsed < min || parsed > max {
return 0, false
}
return math.Round(parsed*1000) / 1000, true
}
// deliveryTimelineText 将不可变订单状态转换为用户可理解的履约节点。
func deliveryTimelineText(status int, stationName string) (string, string, bool) {
switch status {
case 18:
return "气站已接单", namedStation(stationName) + "已接收您的订单", true
case 20:
return "商品装车完成", "商品已装车,准备出发", true
case 33:
return "配送员已出发", "配送员已从" + namedStation(stationName) + "出发", true
case 34:
return "商品已送达", "请核对商品并确认签收", true
case 23:
return "配送已完成", "本次配送已完成", true
case 21:
return "配送出现异常", "平台正在处理本次配送异常", true
default:
return "", "", false
}
}
func namedStation(name string) string {
if name == "" {
return "供气站"
}
return name
}