diff --git a/deploy/Dockerfile b/deploy/Dockerfile index 77b5ce8..221d031 100644 --- a/deploy/Dockerfile +++ b/deploy/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.22 AS builder +FROM golang:1.24 AS builder # 定义参数 WORKDIR /build @@ -31,10 +31,8 @@ ENV proxy="" ARG USE_PROXY #设置国内镜像源,时区 -RUN if [ "$USE_PROXY" = "1" ]; then \ - echo "https://mirrors.aliyun.com/alpine/v3.18/main/" > /etc/apk/repositories && \ - echo "https://mirrors.aliyun.com/alpine/v3.18/community/" >> /etc/apk/repositories; \ - fi && \ +RUN echo "https://mirrors.aliyun.com/alpine/v3.18/main/" > /etc/apk/repositories && \ + echo "https://mirrors.aliyun.com/alpine/v3.18/community/" >> /etc/apk/repositories && \ apk update && \ apk upgrade && \ apk add --no-cache tzdata && \ diff --git a/go.mod b/go.mod index 43cedcc..36ad810 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module merchant -go 1.22.0 +go 1.23.0 -toolchain go1.22.8 +toolchain go1.24.2 require github.com/beego/beego/v2 v2.3.2-0.20241006064559-d5830a0fc2ee @@ -11,6 +11,7 @@ require ( github.com/duke-git/lancet/v2 v2.3.5 github.com/go-redis/redis v6.14.2+incompatible github.com/go-sql-driver/mysql v1.8.1 + github.com/panjf2000/ants/v2 v2.11.3 github.com/pkg/errors v0.9.1 github.com/rs/xid v1.6.0 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e @@ -47,7 +48,9 @@ require ( github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d // indirect github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 // indirect golang.org/x/crypto v0.28.0 // indirect + golang.org/x/exp v0.0.0-20221208152030-732eee02a75a // indirect golang.org/x/net v0.30.0 // indirect + golang.org/x/sync v0.14.0 // indirect golang.org/x/sys v0.26.0 // indirect golang.org/x/text v0.19.0 // indirect google.golang.org/protobuf v1.35.1 // indirect diff --git a/go.sum b/go.sum index e3b1523..8f57555 100644 --- a/go.sum +++ b/go.sum @@ -73,6 +73,8 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/panjf2000/ants/v2 v2.11.3 h1:AfI0ngBoXJmYOpDh9m516vjqoUu2sLrIVgppI9TZVpg= +github.com/panjf2000/ants/v2 v2.11.3/go.mod h1:8u92CYMUc6gyvTIw8Ru7Mt7+/ESnJahz5EVtqfrilek= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -101,8 +103,8 @@ github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tealeg/xlsx v1.0.5 h1:+f8oFmvY8Gw1iUXzPk+kz+4GpbDZPK1FhPiQRd+ypgE= github.com/tealeg/xlsx v1.0.5/go.mod h1:btRS8dz54TDnvKNosuAqxrM1QgN1udgk9O34bDCnORM= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= @@ -136,6 +138,8 @@ golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/internal/controllers/gen_link.go b/internal/controllers/gen_link.go index 0bb574e..9ef6bcb 100644 --- a/internal/controllers/gen_link.go +++ b/internal/controllers/gen_link.go @@ -11,11 +11,10 @@ import ( "merchant/internal/sys/enum" "strconv" "strings" - "sync" "time" "github.com/beego/beego/v2/core/logs" - "github.com/duke-git/lancet/v2/convertor" + "github.com/duke-git/lancet/v2/slice" "github.com/duke-git/lancet/v2/strutil" "github.com/rs/xid" "github.com/xuri/excelize/v2" @@ -98,75 +97,65 @@ func (c *GenLink) UploadFile() { _ = excelFile.SetCellValue("Sheet1", "D1", "卡密") _ = excelFile.SetCellValue("Sheet1", "E1", "状态") _ = excelFile.SetCellValue("Sheet1", "F1", "创建时间") - _ = excelFile.SetCellValue("Sheet1", "G1", "原始返回数据") - - wg := sync.WaitGroup{} lines := strings.Split(string(content), "\n") - wg.Add(len(lines)) - channel := make(chan int, 1) - for i, line := range lines { - go func(i int, line string) { - channel <- i - defer func() { - wg.Done() - <-channel - }() - parts := strings.Split(line, "--") - if len(parts) >= 3 { - price := strutil.Trim(parts[0]) - cardNo := strutil.Trim(parts[1]) - cardPasswd := strutil.Trim(parts[2]) - orderNo := xid.New().String() - _ = excelFile.SetCellValue("Sheet1", fmt.Sprintf("A%d", i+1), orderNo) - _ = excelFile.SetCellValue("Sheet1", fmt.Sprintf("B%d", i+1), price) - _ = excelFile.SetCellValue("Sheet1", fmt.Sprintf("C%d", i+1), cardNo) - _ = excelFile.SetCellValue("Sheet1", fmt.Sprintf("D%d", i+1), cardPasswd) + slice.ForEachConcurrent(lines, func(i int, line string) { + i += 1 + parts := strings.Split(line, "--") + if len(parts) < 3 { + _ = excelFile.SetCellValue("Sheet1", fmt.Sprintf("A%d", i+1), "上传卡数据错误") + logs.Error("卡密数据错误", line) + return + } + price := strutil.Trim(parts[0]) + cardNo := strutil.Trim(parts[1]) + cardPasswd := strutil.Trim(parts[2]) - _, err = strconv.ParseFloat(price, 64) - if err != nil { - _ = excelFile.SetCellValue("Sheet1", fmt.Sprintf("E%d", i+1), "价格转换失败") - logs.Info("价格转换失败", err) - return - } + orderNo := xid.New().String() + "-" + fmt.Sprintf("%04d", i) + _ = excelFile.SetCellValue("Sheet1", fmt.Sprintf("A%d", i+1), orderNo) + _ = excelFile.SetCellValue("Sheet1", fmt.Sprintf("B%d", i+1), price) + _ = excelFile.SetCellValue("Sheet1", fmt.Sprintf("C%d", i+1), cardNo) + _ = excelFile.SetCellValue("Sheet1", fmt.Sprintf("D%d", i+1), cardPasswd) - pp := map[string]string{ - "data": cardPasswd, - "cardNo": cardNo, - } + _, err = strconv.ParseFloat(price, 64) + if err != nil { + _ = excelFile.SetCellValue("Sheet1", fmt.Sprintf("E%d", i+1), "价格转换失败") + logs.Info("价格转换失败", err) + return + } - marshal, err := json.Marshal(&pp) - if err != nil { - _ = excelFile.SetCellValue("Sheet1", fmt.Sprintf("E%d", i+1), "卡密数据解析错误") - logs.Error("卡密数据解析错误", err) - return - } + pp := map[string]string{ + "data": cardPasswd, + "cardNo": cardNo, + } - submitOrderResponse, err := service.SubmitOrder(c.Ctx.Request.Context(), &order.SubmitOrder{ - PayKey: u.MerchantKey, - OrderNo: orderNo, - OrderPrice: price, - OrderPeriod: 24, - NotifyUrl: "http://kami_shop:12305/notify/order", - ProductCode: roadCode, - ExValue: string(marshal), - Ip: c.Ctx.Input.IP(), - PaySecret: u.MerchantSecret, - }) - if err != nil { - _ = excelFile.SetCellValue("Sheet1", fmt.Sprintf("E%d", i+1), "提交订单失败") - logs.Error("提交订单失败", err) - return - } + marshal, err := json.Marshal(&pp) + if err != nil { + _ = excelFile.SetCellValue("Sheet1", fmt.Sprintf("E%d", i+1), "卡密数据解析错误") + logs.Error("卡密数据解析错误", err) + return + } - _ = excelFile.SetCellValue("Sheet1", fmt.Sprintf("E%d", i+1), submitOrderResponse.Msg) - _ = excelFile.SetCellValue("Sheet1", fmt.Sprintf("F%d", i+1), time.Now().Format("2006-01-02 15:04:05")) - _ = excelFile.SetCellValue("Sheet1", fmt.Sprintf("G%d", i+1), convertor.ToString(submitOrderResponse)) - } - }(i+1, strings.Trim(strutil.Trim(line), "\ufeff")) - } - wg.Wait() + err = service.SubmitOrderBackendTask(c.Ctx.Request.Context(), &order.SubmitOrder{ + PayKey: u.MerchantKey, + OrderNo: orderNo, + OrderPrice: price, + OrderPeriod: 24, + NotifyUrl: "http://kami_shop:12305/notify/order", + ProductCode: roadCode, + ExValue: string(marshal), + Ip: c.Ctx.Input.IP(), + PaySecret: u.MerchantSecret, + }) + if err != nil { + _ = excelFile.SetCellValue("Sheet1", fmt.Sprintf("E%d", i+1), "提交订单失败") + logs.Error("提交订单失败", err) + return + } + _ = excelFile.SetCellValue("Sheet1", fmt.Sprintf("F%d", i+1), time.Now().Format("2006-01-02 15:04:05")) + _ = excelFile.SetCellValue("Sheet1", fmt.Sprintf("E%d", i+1), "提交成功") + }, len(lines)/10) c.Ctx.ResponseWriter.Header().Set("Content-Type", "application/octet-stream") c.Ctx.ResponseWriter.Header().Set("Content-Disposition", "attachment; filename=卡密.xlsx") _ = excelFile.Write(c.Ctx.ResponseWriter) diff --git a/internal/service/enums.go b/internal/service/enums.go new file mode 100644 index 0000000..21689c4 --- /dev/null +++ b/internal/service/enums.go @@ -0,0 +1,7 @@ +package service + +import "github.com/panjf2000/ants/v2" + +var ( + pool, _ = ants.NewPool(5) +) diff --git a/internal/service/order.go b/internal/service/order.go index e2dfd1f..53d286c 100644 --- a/internal/service/order.go +++ b/internal/service/order.go @@ -48,6 +48,16 @@ func CreateOrder(ctx context.Context, input *order.CreatedOrder, paySecret strin return &createOrderResponse.Data, nil } +func SubmitOrderBackendTask(ctx context.Context, input *order.SubmitOrder) error { + return pool.Submit(func() { + resp, err := SubmitOrder(ctx, input) + if err != nil { + logs.Error("提交订单失败", err) + } + logs.Info("提交订单成功", resp) + }) +} + func SubmitOrder(ctx context.Context, input *order.SubmitOrder) (*order.SubmitOrderResponse, error) { req := httplib.NewBeegoRequestWithCtx(ctx, fmt.Sprintf("%s/gateway/scan", config.GetGatewayAddr()), "POST"). SetTimeout(30*time.Second, 30*time.Second)