diff --git a/app/admin/apis/migumanage/migu_admin.go b/app/admin/apis/migumanage/migu_admin.go index cc479db..5db1b01 100644 --- a/app/admin/apis/migumanage/migu_admin.go +++ b/app/admin/apis/migumanage/migu_admin.go @@ -315,13 +315,31 @@ func (e MiGuDeployService) OrderList(c *gin.Context) { } var orderList []models.MgOrder - err = qs.Order("created_at desc").Offset(pageNum * req.PageSize).Limit(req.PageSize).Find(&orderList).Error + if req.IsExport == 1 { + err = qs.Order("created_at desc").Find(&orderList).Error + } else { + err = qs.Order("created_at desc").Offset(pageNum * req.PageSize).Limit(req.PageSize).Find(&orderList).Error + } if err != nil { logger.Errorf("OrderList err:%#v", err) response.Error(c, http.StatusInternalServerError, err, "查询失败") return } + // 判断是否导出Excel + if req.IsExport == 1 { + // 调用导出Excel函数 + url, err := models.ExportOrderListToExcel(orderList, e.Orm) + if err != nil { + response.Error(c, http.StatusInternalServerError, err, "导出失败") + return + } + + // 返回导出文件的URL地址 + response.OK(c, map[string]string{"export_url": url}, "导出成功") + return + } + resp.List = orderList resp.Count = int(count) @@ -430,6 +448,20 @@ func (e MiGuDeployService) HistoricalSummaryList(c *gin.Context) { return } + // 判断是否导出Excel + if req.IsExport == 1 { + // 调用导出Excel函数 + url, err := models.ExportHistoricalSummaryToExcel(historicalSummaryList, e.Orm) + if err != nil { + response.Error(c, http.StatusInternalServerError, err, "导出失败") + return + } + + // 返回导出文件的URL地址 + response.OK(c, map[string]string{"export_url": url}, "导出成功") + return + } + // 返回结果 resp.List = historicalSummaryList resp.Count = int(count) @@ -527,7 +559,26 @@ func (e MiGuDeployService) RealtimeSummaryList(c *gin.Context) { } // 查询总记录数 - err = e.Orm.Model(&models.MgOrder{}).Count(&count).Error + es := e.Orm.Model(&models.MgOrder{}). + Select(`product_id, channel_code, + (SELECT COUNT(*) + FROM mg_transaction_log + WHERE verification_code != '' + AND channel_code = mg_order.channel_code + AND created_at >= ? + AND created_at <= ?) AS submission_count, + COUNT(CASE WHEN mg_order.is_one_hour_cancel = 1 THEN 1 END) AS new_user_unsub_within_hour, + COUNT(CASE WHEN mg_order.state = 2 THEN 1 END) AS new_user_unsub_on_day, + COUNT(CASE WHEN mg_order.created_at >= ? AND mg_order.created_at <= ? THEN 1 END) AS new_user_count, + CONCAT(ROUND(COUNT(CASE WHEN mg_order.is_one_hour_cancel = 1 THEN 1 END) * 100.0 / + NULLIF(COUNT(CASE WHEN mg_order.created_at >= ? AND mg_order.created_at <= ? THEN 1 END), 0), 2), '%') AS new_user_unsub_within_hour_rate, + CONCAT(ROUND(COUNT(CASE WHEN mg_order.state = 2 THEN 1 END) * 100.0 / + NULLIF(COUNT(CASE WHEN mg_order.created_at >= ? AND mg_order.created_at <= ? THEN 1 END), 0), 2), '%') AS new_user_unsub_on_day_rate`, + startDate, endDate, startDate, endDate, startDate, endDate, startDate, endDate). + Where("mg_order.created_at >= ? AND mg_order.created_at <= ?", startDate, endDate). + Group("product_id, channel_code"). + Order("product_id, channel_code") + err = es.Count(&count).Error if err != nil { logger.Errorf("count err: %#v", err) response.Error(c, http.StatusInternalServerError, err, "查询失败") diff --git a/app/admin/models/migu.go b/app/admin/models/migu.go index 3f0fac2..403410e 100644 --- a/app/admin/models/migu.go +++ b/app/admin/models/migu.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "github.com/go-admin-team/go-admin-core/logger" + "github.com/xuri/excelize/v2" "go-admin/common/database" "go-admin/tools" "gorm.io/gorm" @@ -13,6 +14,7 @@ import ( "math/rand" "net/http" "net/url" + "strconv" "sync" "time" ) @@ -32,6 +34,10 @@ const ( UnsubscribeOK = 2 // 退订 SKUCODE = "miguyouxizuanshihuiyuan-yy" + + ExportFile = "/www/server/images/export/" + MiGuExportUrl = "https://migu.admin.deovo.com/load/export/" + //MiGuExportUrl = "/Users/max/Documents/" // 本地环境 ) // 以下是数据库表结构 @@ -340,6 +346,7 @@ type HistoricalSummaryListReq struct { Channel string `json:"channel"` // 渠道号 PageNum int `json:"page_num"` // 页码 PageSize int `json:"page_size"` // 每页条数 + IsExport uint32 `json:"is_export"` // 1-导出 //Province string `json:"province"` // 省份 } @@ -997,3 +1004,197 @@ func CheckAllOrderState() { } } } + +// ExportHistoricalSummaryToExcel 历史汇总数据导出excel +func ExportHistoricalSummaryToExcel(data []MgHistoricalSummary, db *gorm.DB) (string, error) { + // 创建一个新的Excel文件 + file := excelize.NewFile() + sheet := "Sheet1" + + // 设置标题栏 + titles := []string{"日期", "产品ID", "渠道编码", "提交数", "新用户数", "1小时内退订数", "1小时内退订率", "当日退订数", "当日退订率"} + for i, title := range titles { + cell, _ := excelize.CoordinatesToCellName(i+1, 1) + file.SetCellValue(sheet, cell, title) + } + + // 设置所有单元格的样式: 居中、加边框 + style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"}, + "border":[{"type":"left","color":"000000","style":1}, + {"type":"top","color":"000000","style":1}, + {"type":"right","color":"000000","style":1}, + {"type":"bottom","color":"000000","style":1}]}`) + + // 设置单元格高度 + file.SetRowHeight(sheet, 1, 20) + + // 设置列宽 + file.SetColWidth(sheet, "A", "A", 15) + file.SetColWidth(sheet, "B", "B", 18) + file.SetColWidth(sheet, "C", "C", 18) + file.SetColWidth(sheet, "F", "F", 15) + file.SetColWidth(sheet, "G", "G", 15) + file.SetColWidth(sheet, "H", "H", 15) + file.SetColWidth(sheet, "I", "I", 15) + + // 创建一个产品ID到名称的映射 + productMap := make(map[int64]string) + for _, order := range data { + if _, exists := productMap[order.ProductID]; !exists { + var product MgProduct + // 查询产品信息 + if err := db.First(&product, order.ProductID).Error; err == nil { + productMap[order.ProductID] = product.Name + } else { + productMap[order.ProductID] = "未知产品" + } + } + } + + // 填充数据 + for i, record := range data { + row := i + 2 + productName := productMap[record.ProductID] // 获取产品名称 + file.SetCellValue(sheet, "A"+strconv.Itoa(row), record.Date) + file.SetCellValue(sheet, "B"+strconv.Itoa(row), productName) + file.SetCellValue(sheet, "C"+strconv.Itoa(row), record.ChannelCode) + file.SetCellValue(sheet, "D"+strconv.Itoa(row), record.SubmissionCount) + file.SetCellValue(sheet, "E"+strconv.Itoa(row), record.NewUserCount) + file.SetCellValue(sheet, "F"+strconv.Itoa(row), record.NewUserUnsubWithinHour) + file.SetCellValue(sheet, "G"+strconv.Itoa(row), record.NewUserUnsubWithinHourRate) + file.SetCellValue(sheet, "H"+strconv.Itoa(row), record.NewUserUnsubOnDay) + file.SetCellValue(sheet, "I"+strconv.Itoa(row), record.NewUserUnsubOnDayRate) + } + + endRow := fmt.Sprintf("I%d", len(data)+1) + // 应用样式到整个表格 + _ = file.SetCellStyle(sheet, "A1", endRow, style) + + // 从配置文件读取保存路径和URL前缀 + fileName := time.Now().Format("20060102150405") + "_历史汇总数据.xlsx" + url := MiGuExportUrl + fileName + + // 保存Excel文件 + if err := file.SaveAs(ExportFile + fileName); err != nil { + logger.Errorf("Failed to save Excel file: %v", err) + return "", err + } + + return url, nil +} + +// ExportOrderListToExcel 订单表导出excel +func ExportOrderListToExcel(orderList []MgOrder, db *gorm.DB) (string, error) { + // 创建一个新的Excel文件 + file := excelize.NewFile() + sheet := "Sheet1" + + // 设置标题栏 + titles := []string{"产品", "渠道", "订单流水号", "手机号", "SM4手机号", "外部订单号", "渠道订单号", "是否1小时内退订", "用户订购状态", "订购时间", "退订时间"} + for i, title := range titles { + cell, _ := excelize.CoordinatesToCellName(i+1, 1) + file.SetCellValue(sheet, cell, title) + } + + // 设置所有单元格的样式: 居中、加边框 + style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"}, + "border":[{"type":"left","color":"000000","style":1}, + {"type":"top","color":"000000","style":1}, + {"type":"right","color":"000000","style":1}, + {"type":"bottom","color":"000000","style":1}]}`) + + // 设置单元格高度 + file.SetRowHeight(sheet, 1, 20) + + // 设置列宽 + file.SetColWidth(sheet, "A", "A", 18) // 产品 + file.SetColWidth(sheet, "B", "B", 15) // 渠道 + file.SetColWidth(sheet, "C", "C", 20) // 订单流水号 + file.SetColWidth(sheet, "D", "D", 15) // 手机号 + file.SetColWidth(sheet, "E", "E", 30) // SM4手机号 + file.SetColWidth(sheet, "F", "F", 20) // 外部订单号 + file.SetColWidth(sheet, "G", "G", 23) // 渠道订单号 + file.SetColWidth(sheet, "H", "H", 15) // 是否1小时内退订 + file.SetColWidth(sheet, "I", "I", 15) // 用户订购状态 + file.SetColWidth(sheet, "J", "J", 20) // 订购时间 + file.SetColWidth(sheet, "K", "K", 20) // 退订时间 + + // 创建一个产品ID到名称的映射 + productMap := make(map[int64]string) + for _, order := range orderList { + if _, exists := productMap[order.ProductID]; !exists { + var product MgProduct + // 查询产品信息 + if err := db.First(&product, order.ProductID).Error; err == nil { + productMap[order.ProductID] = product.Name + } else { + productMap[order.ProductID] = "未知产品" + } + } + } + + // 填充数据 + for i, order := range orderList { + row := i + 2 + productName := productMap[order.ProductID] // 获取产品名称 + file.SetCellValue(sheet, "A"+strconv.Itoa(row), productName) + file.SetCellValue(sheet, "B"+strconv.Itoa(row), order.ChannelCode) + file.SetCellValue(sheet, "C"+strconv.Itoa(row), order.OrderSerial) + file.SetCellValue(sheet, "D"+strconv.Itoa(row), order.PhoneNumber) + file.SetCellValue(sheet, "E"+strconv.Itoa(row), order.SM4PhoneNumber) + file.SetCellValue(sheet, "F"+strconv.Itoa(row), order.ExternalOrderID) + file.SetCellValue(sheet, "G"+strconv.Itoa(row), order.ChannelTradeNo) + + // 判断时间是否为空,若为空则设置为"" + if order.SubscribeTime != nil { + file.SetCellValue(sheet, "J"+strconv.Itoa(row), order.SubscribeTime.Format("2006-01-02 15:04:05")) + } else { + file.SetCellValue(sheet, "J"+strconv.Itoa(row), "") + } + + // 判断退订时间是否为空,若为空则设置为"" + if order.UnsubscribeTime != nil { + file.SetCellValue(sheet, "K"+strconv.Itoa(row), order.UnsubscribeTime.Format("2006-01-02 15:04:05")) + } else { + file.SetCellValue(sheet, "K"+strconv.Itoa(row), "") + } + + // 退订状态转换为中文 + subscriptionStatus := "未知状态" + if order.State == 1 { + subscriptionStatus = "订购成功" + } else if order.State == 2 { + subscriptionStatus = "已退订" + } + file.SetCellValue(sheet, "I"+strconv.Itoa(row), subscriptionStatus) + + // 是否1小时内退订转换为中文 + isOneHourCancel := "否" + if order.IsOneHourCancel == 1 { + isOneHourCancel = "是" + } + file.SetCellValue(sheet, "H"+strconv.Itoa(row), isOneHourCancel) + + // 设置当前行的单元格样式 + for col := 'A'; col <= 'K'; col++ { + cell, _ := excelize.CoordinatesToCellName(int(col-'A'+1), row) + file.SetCellStyle(sheet, cell, cell, style) + } + } + + endRow := fmt.Sprintf("K%d", len(orderList)+1) + // 应用样式到整个表格 + _ = file.SetCellStyle(sheet, "A1", endRow, style) + + // 从配置文件读取保存路径和URL前缀 + fileName := time.Now().Format("20060102150405") + "_订单列表.xlsx" + url := MiGuExportUrl + fileName + + // 保存Excel文件 + if err := file.SaveAs(ExportFile + fileName); err != nil { + logger.Errorf("Failed to save Excel file: %v", err) + return "", err + } + + return url, nil +} diff --git a/go.mod b/go.mod index f81c5ad..90f4eeb 100644 --- a/go.mod +++ b/go.mod @@ -46,7 +46,7 @@ require ( github.com/jasonlvhit/gocron v0.0.1 github.com/spf13/cast v1.6.0 github.com/tjfoc/gmsm v1.4.1 - github.com/xuri/excelize/v2 v2.8.1 + github.com/xuri/excelize/v2 v2.6.0 go.uber.org/zap v1.15.0 // indirect golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect ) diff --git a/go.sum b/go.sum index 742b566..20a0ede 100644 --- a/go.sum +++ b/go.sum @@ -682,9 +682,8 @@ github.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM= github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk= +github.com/richardlehane/msoleps v1.0.1 h1:RfrALnSNXzmXLbGct/P2b4xkFz4e8Gmj/0Vj9M9xC1o= github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= -github.com/richardlehane/msoleps v1.0.3 h1:aznSZzrwYRl3rLKRT3gUk9am7T/mLNSnJINvN0AQoVM= -github.com/richardlehane/msoleps v1.0.3/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/robinjoseph08/redisqueue/v2 v2.1.0 h1:GactHlrxS8YSCJc4CbP1KbTObo14pieNmNWSUlquTGI= @@ -764,9 +763,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w= github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a h1:kAe4YSu0O0UFn1DowNo2MY5p6xzqtJ/wQ7LZynSvGaY= github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w= @@ -812,12 +810,12 @@ github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPU github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/xuri/efp v0.0.0-20231025114914-d1ff6096ae53 h1:Chd9DkqERQQuHpXjR/HSV1jLZA6uaoiwwH3vSuF3IW0= -github.com/xuri/efp v0.0.0-20231025114914-d1ff6096ae53/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI= -github.com/xuri/excelize/v2 v2.8.1 h1:pZLMEwK8ep+CLIUWpWmvW8IWE/yxqG0I1xcN6cVMGuQ= -github.com/xuri/excelize/v2 v2.8.1/go.mod h1:oli1E4C3Pa5RXg1TBXn4ENCXDV5JUMlBluUhG7c+CEE= -github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05 h1:qhbILQo1K3mphbwKh1vNm4oGezE1eF9fQWmNiIpSfI4= -github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ= +github.com/xuri/efp v0.0.0-20220407160117-ad0f7a785be8 h1:3X7aE0iLKJ5j+tz58BpvIZkXNV7Yq4jC93Z/rbN2Fxk= +github.com/xuri/efp v0.0.0-20220407160117-ad0f7a785be8/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI= +github.com/xuri/excelize/v2 v2.6.0 h1:m/aXAzSAqxgt74Nfd+sNzpzVKhTGl7+S9nbG4A57mF4= +github.com/xuri/excelize/v2 v2.6.0/go.mod h1:Q1YetlHesXEKwGFfeJn7PfEZz2IvHb6wdOeYjBxVcVs= +github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 h1:OAmKAfT06//esDdpi/DZ8Qsdt4+M5+ltca05dA5bG2M= +github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -875,6 +873,7 @@ golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220408190544-5352b0902921/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= @@ -885,8 +884,8 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/image v0.0.0-20190501045829-6d32002ffd75/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4= -golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= +golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ= +golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -938,6 +937,7 @@ golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= @@ -945,9 +945,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=