回调
CI / changes (push) Successful in 37s
CI / ad (push) Successful in 30s
CI / admin (push) Successful in 22s
CI / bff (push) Successful in 39s
CI / chore (push) Successful in 20s
CI / equipment (push) Successful in 19s
CI / express (push) Successful in 17s
CI / product (push) Successful in 16s
CI / record (push) Successful in 17s
CI / sale (push) Successful in 16s
CI / task (push) Successful in 16s
CI / user (push) Successful in 17s
CI / wecom (push) Successful in 18s

This commit is contained in:
2026-09-05 13:41:13 +08:00
parent be18a48148
commit 462d142a4c
9 changed files with 254 additions and 83 deletions
+13 -25
View File
@@ -1,7 +1,6 @@
package request package request
import ( import (
"bytes"
"context" "context"
"io" "io"
"lone-services/pkg/utils" "lone-services/pkg/utils"
@@ -32,9 +31,7 @@ const (
CtxGroupId ctxKey = "X-Group-Id" CtxGroupId ctxKey = "X-Group-Id"
CtxGroupName ctxKey = "X-Group-Name" CtxGroupName ctxKey = "X-Group-Name"
CtxUserType ctxKey = "X-User-Type" CtxUserType ctxKey = "X-User-Type"
CtxCallbackRawBody ctxKey = "callback_raw_body" CtxRawBody ctxKey = "X-Raw-Body"
CtxCallbackHeaders ctxKey = "callback_headers"
CtxCallbackErr ctxKey = "callback_read_err"
) )
var callbackPrefixes = []string{ var callbackPrefixes = []string{
@@ -60,6 +57,7 @@ type UserInfo struct {
StoreName string StoreName string
GroupId string GroupId string
GroupName string GroupName string
RawBody string
Valid bool Valid bool
} }
@@ -79,6 +77,7 @@ func GetUserInfo(ctx context.Context) UserInfo {
storeName, _ := ctx.Value(CtxStoreName).(string) storeName, _ := ctx.Value(CtxStoreName).(string)
groupId, _ := ctx.Value(CtxGroupId).(string) groupId, _ := ctx.Value(CtxGroupId).(string)
groupName, _ := ctx.Value(CtxGroupName).(string) groupName, _ := ctx.Value(CtxGroupName).(string)
rawBody, _ := ctx.Value(CtxRawBody).(string)
info := UserInfo{ info := UserInfo{
RawUID: rawUID, RawUID: rawUID,
@@ -96,6 +95,7 @@ func GetUserInfo(ctx context.Context) UserInfo {
StoreName: storeName, StoreName: storeName,
GroupId: groupId, GroupId: groupId,
GroupName: groupName, GroupName: groupName,
RawBody: rawBody,
} }
if rawUID == "" { if rawUID == "" {
return info return info
@@ -122,29 +122,17 @@ func getRealClientIP(r *http.Request) string {
return r.RemoteAddr return r.RemoteAddr
} }
// UserReadMiddleware
/** 增加透传的方法
* 1、这里加上代码
* 2、UserClientInterceptor这个方法里也要写相应的代码对可以
*/
func UserReadMiddleware(next http.HandlerFunc) http.HandlerFunc { func UserReadMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
newCtx := r.Context()
if isCallbackPath(r.URL.Path) {
body, err := io.ReadAll(r.Body)
if err != nil {
newCtx = context.WithValue(newCtx, CtxCallbackRawBody, []byte(nil))
newCtx = context.WithValue(newCtx, CtxCallbackHeaders, http.Header(nil))
newCtx = context.WithValue(newCtx, CtxCallbackErr, err)
} else {
r.Body = io.NopCloser(bytes.NewBuffer(body))
header := make(http.Header)
for k, vv := range r.Header {
header[k] = vv
}
newCtx = context.WithValue(newCtx, CtxCallbackRawBody, body)
newCtx = context.WithValue(newCtx, CtxCallbackHeaders, header)
newCtx = context.WithValue(newCtx, CtxCallbackErr, error(nil))
}
next(w, r.WithContext(newCtx))
return
}
newCtx := r.Context()
body, _ := io.ReadAll(r.Body)
newCtx = context.WithValue(newCtx, CtxRawBody, string(body))
newCtx = context.WithValue(newCtx, CtxUserId, r.Header.Get("X-User-Id")) newCtx = context.WithValue(newCtx, CtxUserId, r.Header.Get("X-User-Id"))
newCtx = context.WithValue(newCtx, CtxUserName, r.Header.Get("X-User-Name")) newCtx = context.WithValue(newCtx, CtxUserName, r.Header.Get("X-User-Name"))
newCtx = context.WithValue(newCtx, CtxRefresh, r.Header.Get("X-Refresh")) newCtx = context.WithValue(newCtx, CtxRefresh, r.Header.Get("X-Refresh"))
@@ -160,7 +148,6 @@ func UserReadMiddleware(next http.HandlerFunc) http.HandlerFunc {
newCtx = context.WithValue(newCtx, CtxStoreName, r.Header.Get("X-Store-Name")) newCtx = context.WithValue(newCtx, CtxStoreName, r.Header.Get("X-Store-Name"))
newCtx = context.WithValue(newCtx, CtxGroupId, r.Header.Get("X-Group-Id")) newCtx = context.WithValue(newCtx, CtxGroupId, r.Header.Get("X-Group-Id"))
newCtx = context.WithValue(newCtx, CtxGroupName, r.Header.Get("X-Group-Name")) newCtx = context.WithValue(newCtx, CtxGroupName, r.Header.Get("X-Group-Name"))
next(w, r.WithContext(newCtx)) next(w, r.WithContext(newCtx))
} }
} }
@@ -189,6 +176,7 @@ func UserClientInterceptor(ctx context.Context, method string, req, reply any, c
md.Set("x-user-name", url.QueryEscape(user.Name)) md.Set("x-user-name", url.QueryEscape(user.Name))
} }
setMDIfNotEmpty(md, "x-raw-body", user.RawBody)
setMDIfNotEmpty(md, "x-refresh", user.Refresh) setMDIfNotEmpty(md, "x-refresh", user.Refresh)
setMDIfNotEmpty(md, "x-client-ip", user.ClientIP) setMDIfNotEmpty(md, "x-client-ip", user.ClientIP)
if user.UserAgent != utils.StringEmpty { if user.UserAgent != utils.StringEmpty {
+20
View File
@@ -2,6 +2,7 @@ package response
import ( import (
"bytes" "bytes"
"lone-services/pkg/utils"
"net/http" "net/http"
"strings" "strings"
@@ -16,6 +17,11 @@ type bodyWriter struct {
buf bytes.Buffer buf bytes.Buffer
} }
type responseDataBack struct {
ReturnCode string `json:"returnCode"`
ReturnMsg string `json:"returnMsg"`
}
type responseData struct { type responseData struct {
Code int32 `json:"code"` Code int32 `json:"code"`
Data any `json:"data"` Data any `json:"data"`
@@ -48,8 +54,22 @@ func Wrap(next http.HandlerFunc) http.HandlerFunc {
return return
} }
} }
if data.Code < utils.NumberOne {
var back responseDataBack
if err := jsoniter.Unmarshal(raw, &back); err != nil {
ctrl.Fail(w)
return
}
if len(back.ReturnCode) < utils.NumberOne {
ctrl.Fail(w)
return
}
ctrl.OutPutBack(w, back)
} else {
ctrl.OutPut(w, data.Code, unwrapJSONData(data.Data), data.Msg) ctrl.OutPut(w, data.Code, unwrapJSONData(data.Data), data.Msg)
} }
}
} }
func unwrapJSONData(v any) any { func unwrapJSONData(v any) any {
+7
View File
@@ -53,3 +53,10 @@ func (b *BaseController) OutPut(w http.ResponseWriter, code int32, data any, msg
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
_ = jsoniter.NewEncoder(w).Encode(out) _ = jsoniter.NewEncoder(w).Encode(out)
} }
func (b *BaseController) OutPutBack(w http.ResponseWriter, back responseDataBack) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(http.StatusOK)
_ = jsoniter.NewEncoder(w).Encode(back)
}
+6 -20
View File
@@ -2,7 +2,6 @@ package utils
import ( import (
"context" "context"
"net/http"
"net/url" "net/url"
"strconv" "strconv"
@@ -10,12 +9,6 @@ import (
"google.golang.org/grpc/metadata" "google.golang.org/grpc/metadata"
) )
const (
CtxCallbackRawBody string = "callback_raw_body"
CtxCallbackHeaders string = "callback_headers"
CtxCallbackErr string = "callback_read_err"
)
type UserInfo struct { type UserInfo struct {
ID int64 ID int64
Name string Name string
@@ -38,11 +31,6 @@ type UserInfo struct {
Valid bool Valid bool
} }
type HeaderAndBody struct {
Header http.Header
Body []byte
}
func firstMD(md metadata.MD, keys ...string) string { func firstMD(md metadata.MD, keys ...string) string {
for _, key := range keys { for _, key := range keys {
vals := md.Get(key) vals := md.Get(key)
@@ -122,13 +110,11 @@ func GetUserFromCtx(ctx context.Context) UserInfo {
return userInfo return userInfo
} }
// GetHeaderAndBody 只从ctx拿数据,不写http响应,Err交给handler处理 // GetBody 只从ctx拿数据,不写http响应,Err交给handler处理
func GetHeaderAndBody(ctx context.Context) HeaderAndBody { func GetBody(ctx context.Context) string {
rawBody, _ := ctx.Value(CtxCallbackRawBody).([]byte) md, ok := metadata.FromIncomingContext(ctx)
headers, _ := ctx.Value(CtxCallbackHeaders).(http.Header) if !ok {
return StringEmpty
return HeaderAndBody{
Header: headers,
Body: rawBody,
} }
return firstMD(md, "x-raw-body")
} }
+7 -6
View File
@@ -14,6 +14,7 @@ import (
"time" "time"
jsoniter "github.com/json-iterator/go" jsoniter "github.com/json-iterator/go"
"github.com/zeromicro/go-zero/core/logx"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/xuri/excelize/v2" "github.com/xuri/excelize/v2"
@@ -245,7 +246,7 @@ func RoundMoney(amount float64) float64 {
func Decrypt(str string) (string, Error) { func Decrypt(str string) (string, Error) {
str, err := Crypto{}.AESDecryptECB(str) str, err := Crypto{}.AESDecryptECB(str)
if err != nil { if err != nil {
Logger.Error("decrypt str error", str, err) logx.Error("decrypt str error", str, err)
return str, err return str, err
} }
@@ -259,7 +260,7 @@ func DecryptMobile(mobile string) string {
mobile, err := Decrypt(mobile) mobile, err := Decrypt(mobile)
if err != nil { if err != nil {
Logger.Error("decrypt mobile error", mobile, err) logx.Error("decrypt mobile error", mobile, err)
return mobile return mobile
} }
@@ -488,12 +489,12 @@ func Unique(s []string) []string {
func MapToStruct(data map[string]interface{}, target interface{}) error { func MapToStruct(data map[string]interface{}, target interface{}) error {
jsonData, err := jsoniter.Marshal(data) // 将 map 转换为 JSON 字节切片 jsonData, err := jsoniter.Marshal(data) // 将 map 转换为 JSON 字节切片
if err != nil { if err != nil {
Logger.Error("Error marshalling map to JSON:", err) logx.Error("Error marshalling map to JSON:", err)
return err return err
} }
err = jsoniter.Unmarshal(jsonData, &target) // 将 JSON 字节切片解析到结构体中 err = jsoniter.Unmarshal(jsonData, &target) // 将 JSON 字节切片解析到结构体中
if err != nil { if err != nil {
Logger.Error("Error unmarshalling JSON:", err) logx.Error("Error unmarshalling JSON:", err)
return err return err
} }
@@ -503,14 +504,14 @@ func MapToStruct(data map[string]interface{}, target interface{}) error {
func JsonStringToStruct(jsonStr string, v interface{}) bool { func JsonStringToStruct(jsonStr string, v interface{}) bool {
// 1. 校验入参:确保v是指针类型(否则json.Unmarshal无法工作) // 1. 校验入参:确保v是指针类型(否则json.Unmarshal无法工作)
if v == nil { if v == nil {
Logger.Error("传入的结构体指针不能为nil") logx.Error("传入的结构体指针不能为nil")
return false return false
} }
// 2. 将JSON字符串转为字节数组,执行解析 // 2. 将JSON字符串转为字节数组,执行解析
err := jsoniter.Unmarshal([]byte(jsonStr), v) err := jsoniter.Unmarshal([]byte(jsonStr), v)
if err != nil { if err != nil {
Logger.Error("JSON解析失败: ", err, jsonStr) logx.Error("JSON解析失败: ", err, jsonStr)
return false return false
} }
Binary file not shown.
-1
View File
@@ -14,7 +14,6 @@ message Response {
message SfResponse { message SfResponse {
string return_code = 1; string return_code = 1;
string return_msg = 2; string return_msg = 2;
string return_status = 3;
} }
message IdResponse { message IdResponse {
+2 -11
View File
@@ -86,7 +86,6 @@ type SfResponse struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
ReturnCode string `protobuf:"bytes,1,opt,name=return_code,json=returnCode,proto3" json:"return_code,omitempty"` ReturnCode string `protobuf:"bytes,1,opt,name=return_code,json=returnCode,proto3" json:"return_code,omitempty"`
ReturnMsg string `protobuf:"bytes,2,opt,name=return_msg,json=returnMsg,proto3" json:"return_msg,omitempty"` ReturnMsg string `protobuf:"bytes,2,opt,name=return_msg,json=returnMsg,proto3" json:"return_msg,omitempty"`
ReturnStatus string `protobuf:"bytes,3,opt,name=return_status,json=returnStatus,proto3" json:"return_status,omitempty"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@@ -135,13 +134,6 @@ func (x *SfResponse) GetReturnMsg() string {
return "" return ""
} }
func (x *SfResponse) GetReturnStatus() string {
if x != nil {
return x.ReturnStatus
}
return ""
}
type IdResponse struct { type IdResponse struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
@@ -854,14 +846,13 @@ const file_express_express_proto_rawDesc = "" +
"\bResponse\x12\x12\n" + "\bResponse\x12\x12\n" +
"\x04code\x18\x01 \x01(\x05R\x04code\x12\x10\n" + "\x04code\x18\x01 \x01(\x05R\x04code\x12\x10\n" +
"\x03msg\x18\x02 \x01(\tR\x03msg\x12\x12\n" + "\x03msg\x18\x02 \x01(\tR\x03msg\x12\x12\n" +
"\x04data\x18\x03 \x01(\tR\x04data\"q\n" + "\x04data\x18\x03 \x01(\tR\x04data\"L\n" +
"\n" + "\n" +
"SfResponse\x12\x1f\n" + "SfResponse\x12\x1f\n" +
"\vreturn_code\x18\x01 \x01(\tR\n" + "\vreturn_code\x18\x01 \x01(\tR\n" +
"returnCode\x12\x1d\n" + "returnCode\x12\x1d\n" +
"\n" + "\n" +
"return_msg\x18\x02 \x01(\tR\treturnMsg\x12#\n" + "return_msg\x18\x02 \x01(\tR\treturnMsg\"\x1c\n" +
"\rreturn_status\x18\x03 \x01(\tR\freturnStatus\"\x1c\n" +
"\n" + "\n" +
"IdResponse\x12\x0e\n" + "IdResponse\x12\x0e\n" +
"\x02id\x18\x01 \x01(\x03R\x02id\"\x0e\n" + "\x02id\x18\x01 \x01(\x03R\x02id\"\x0e\n" +
@@ -2,10 +2,15 @@ package logic
import ( import (
"context" "context"
"lone-services/pkg/modelbase"
"lone-services/pkg/utils" "lone-services/pkg/utils"
"lone-services/rpc/express/pb" "lone-services/rpc/express/pb"
order "lone-services/rpc/order/pb"
"lone-services/services/express/internal/dao"
"lone-services/services/express/internal/model"
"lone-services/services/express/internal/svc" "lone-services/services/express/internal/svc"
"lone-services/services/express/internal/transit"
"strconv"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
) )
@@ -26,7 +31,181 @@ func NewExpressSfBackLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Exp
} }
func (l *ExpressSfBackLogic) ExpressSfBack(in *express.EmtpyRequest) (*express.SfResponse, error) { func (l *ExpressSfBackLogic) ExpressSfBack(in *express.EmtpyRequest) (*express.SfResponse, error) {
info := utils.GetHeaderAndBody(l.ctx) body := utils.GetBody(l.ctx)
l.Logger.Error("ExpressSfBack", "info", string(info.Body)) ret := express.SfResponse{
return &express.SfResponse{}, nil ReturnCode: "1000",
ReturnMsg: "系统异常",
}
if body == utils.StringEmpty {
return &ret, nil
}
l.Logger.Info("SF back data:", body)
ok := l.Back(body)
if ok {
ret.ReturnCode = "000"
ret.ReturnMsg = "成功"
}
return &ret, nil
}
func (l *ExpressSfBackLogic) Back(body string) bool {
var result map[string]interface{}
ok := utils.JsonStringToStruct(body, &result)
if !ok {
return false
}
bodyData, ok := result["Body"].(map[string]interface{})
if !ok {
l.Logger.Error("back Body interface error ")
return false
}
waybillRoute, ok := bodyData["WaybillRoute"].([]interface{})
if !ok || len(waybillRoute) < utils.NumberOne {
l.Logger.Error("back body WaybillRoute error empty")
return false
}
items := make(map[string][]dao.ExpressQueryItems)
var orderIds []string
end := make(map[string]bool)
for i := utils.NumberZero; i < len(waybillRoute); i++ {
route := waybillRoute[i].(map[string]interface{})
if _, ok := route["orderid"].(string); !ok {
l.Logger.Error("back body WaybillRoute error empty")
continue
}
orderId := route["orderid"].(string)
orderIds = append(orderIds, orderId)
tmp := dao.ExpressQueryItems{
AcceptAddress: route["acceptAddress"].(string),
AcceptTime: route["acceptTime"].(string),
OpCode: route["opCode"].(string),
Remark: route["remark"].(string),
}
tmp.LastMd5 = utils.MD5Encrypt(tmp.OpCode + tmp.AcceptTime + tmp.Remark)
if _, okk := route["secondaryStatusCode"]; okk {
tmp.SecondaryStatusCode = route["secondaryStatusCode"].(string)
}
if _, okk := route["secondaryStatusName"]; okk {
tmp.SecondaryStatusName = route["secondaryStatusName"].(string)
}
if _, okk := route["firstStatusCode"]; okk {
tmp.FirstStatusCode = route["firstStatusCode"].(string)
}
if _, okk := route["firstStatusName"]; okk {
tmp.FirstStatusName = route["firstStatusName"].(string)
}
items[orderId] = append(items[orderId], tmp)
end[orderId] = false
if ok := transit.SfSingedCodeMap[tmp.OpCode]; ok {
end[orderId] = true
}
}
if len(orderIds) < utils.NumberOne {
l.Logger.Error("no ", orderIds)
return false
}
orderIds = utils.UniqueStr(orderIds)
modelObj := model.DeliveryOrderModel{}.Init()
w := modelbase.Params{In: map[string][]string{
"order_sn": orderIds,
}}
var info []dao.DeliveryOrderUpTransit
err := modelObj.Items(w, &info)
if err != nil {
utils.Logger.Error("get deliverGoods error ", err)
return false
}
if len(info) < utils.NumberOne {
return false
}
modelObj.Begin()
for _, item := range info {
if item.Status == dao.SendStatusOver {
continue
}
if end[item.OrderSn] {
item.Status = dao.SendStatusOver
item.ChangeEstimatedTime = utils.StatusFail
w = modelbase.Params{Eq: map[string]string{"delivery_order_id": strconv.Itoa(item.Id)}}
expEdit := dao.DeliveryExpStatus{
Status: utils.StatusOk,
}
_, err = model.DeliveryOrderExpModel{}.Init().Edit(w, &expEdit)
if err != nil {
l.Logger.Error("back set deliver exp error ", err)
modelObj.Rollback()
return false
}
}
if v, iOk := items[item.OrderSn]; iOk {
var old []dao.ExpressQueryItems
if utils.JsonStringToStruct(item.TransitQuery, &old) {
l.Logger.Error("back set deliver transit error: ", item.TransitQuery)
}
oldMap := l.getSfMap(old)
for i := len(v) - 1; i >= utils.NumberZero; i-- {
if cOk := oldMap[v[i].LastMd5]; !cOk {
old = append(old, v[i])
}
}
item.TransitQuery = utils.StructToJson(old)
w := modelbase.Params{Eq: map[string]string{"id": strconv.Itoa(item.Id)}}
if end[item.OrderSn] {
item.SignTime = utils.Now()
}
_, err = modelObj.Edit(w, &item)
if err != nil {
l.Logger.Error("back set deliver info error ", err)
modelObj.Rollback()
return false
}
}
if end[item.OrderSn] {
if item.Type == dao.DeliveryTypeOrder {
cli, err := svc.GetRpcClient(l.svcCtx.OrderSvcName)
if err != nil {
modelObj.Rollback()
logx.Errorf("get order err: %v", err)
return false
}
client := order.NewOrderClient(cli.Conn())
update := order.UpdateOrderDeliverStatusRequest{
Id: item.ObjId,
DeliverStatus: int32(item.Status),
SignTime: utils.Now().GoString(),
}
_, err = client.UpdateOrderDeliverStatus(l.ctx, &update)
if err != nil {
modelObj.Rollback()
logx.Errorf("get order err: %v", err)
return false
}
}
}
}
modelObj.Commit()
return true
}
func (l *ExpressSfBackLogic) getSfMap(items []dao.ExpressQueryItems) map[string]bool {
ret := make(map[string]bool)
for _, item := range items {
ret[item.LastMd5] = true
}
return ret
} }