已完成用户APP首期功能开发
交付用户端首期页面、配套接口、后台资源及测试文档。用户APP构建、静态分析和三个管理后台构建通过;完整测试仍有2项失败,后端模型注释检查未通过,详见交付记录。
This commit is contained in:
121
backend/api/internal/logic/client/user/delivery_track.go
Normal file
121
backend/api/internal/logic/client/user/delivery_track.go
Normal file
@@ -0,0 +1,121 @@
|
||||
// 功能描述:向用户本人提供隐私化配送轨迹与履约时间线;版本: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
|
||||
}
|
||||
Reference in New Issue
Block a user