1、营收分析、用户留存记录、交易流水记录等接口增加excel导出功能;
2、订单列表、交易流水记录导出excel时增加时间限制;
This commit is contained in:
parent
962802d54f
commit
401eaaaaba
|
@ -46,6 +46,15 @@ func (e MiGuDeployService) TransactionList(c *gin.Context) {
|
||||||
PageNum: req.PageNum,
|
PageNum: req.PageNum,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 导出excel时检查时间范围
|
||||||
|
if req.IsExport == 1 {
|
||||||
|
err = models.CheckDateRange(req.StartTime, req.EndTime, 7)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, http.StatusBadRequest, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pageNum := req.PageNum - 1
|
pageNum := req.PageNum - 1
|
||||||
if pageNum < 0 {
|
if pageNum < 0 {
|
||||||
pageNum = 0
|
pageNum = 0
|
||||||
|
@ -93,7 +102,11 @@ func (e MiGuDeployService) TransactionList(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var transactionLogs []models.MgTransactionLog
|
var transactionLogs []models.MgTransactionLog
|
||||||
err = qs.Order("created_at desc").Offset(pageNum * req.PageSize).Limit(req.PageSize).Find(&transactionLogs).Error
|
if req.IsExport == 1 {
|
||||||
|
err = qs.Order("created_at desc").Find(&transactionLogs).Error
|
||||||
|
} else {
|
||||||
|
err = qs.Order("created_at desc").Offset(pageNum * req.PageSize).Limit(req.PageSize).Find(&transactionLogs).Error
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("TransactionList err:%#v", err)
|
logger.Errorf("TransactionList err:%#v", err)
|
||||||
response.Error(c, http.StatusInternalServerError, err, "查询失败")
|
response.Error(c, http.StatusInternalServerError, err, "查询失败")
|
||||||
|
@ -103,6 +116,16 @@ func (e MiGuDeployService) TransactionList(c *gin.Context) {
|
||||||
resp.List = transactionLogs
|
resp.List = transactionLogs
|
||||||
resp.Count = int(count)
|
resp.Count = int(count)
|
||||||
|
|
||||||
|
if req.IsExport == 1 {
|
||||||
|
url, err := models.ExportTransactionToExcel(transactionLogs, e.Orm)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, http.StatusInternalServerError, err, "导出失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OK(c, map[string]string{"export_url": url}, "导出成功")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
e.OK(resp, "")
|
e.OK(resp, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,6 +291,15 @@ func (e MiGuDeployService) OrderList(c *gin.Context) {
|
||||||
fmt.Println("Orm is nil")
|
fmt.Println("Orm is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 导出excel时检查时间范围
|
||||||
|
if req.IsExport == 1 {
|
||||||
|
err = models.CheckDateRange(req.StartTime, req.EndTime, 31)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, http.StatusBadRequest, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
qs := e.Orm.Model(&models.MgOrder{})
|
qs := e.Orm.Model(&models.MgOrder{})
|
||||||
// 产品编号
|
// 产品编号
|
||||||
if req.SkuCode != 0 {
|
if req.SkuCode != 0 {
|
||||||
|
@ -1419,6 +1451,16 @@ func (e MiGuDeployService) UserRetentionList(c *gin.Context) {
|
||||||
resp.List = retentionList
|
resp.List = retentionList
|
||||||
resp.Count = len(retentionList) // Count should reflect the actual number of entries
|
resp.Count = len(retentionList) // Count should reflect the actual number of entries
|
||||||
|
|
||||||
|
if req.IsExport == 1 {
|
||||||
|
url, err := models.ExportUserRetentionToExcel(retentionList, e.Orm)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, http.StatusInternalServerError, err, "导出失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OK(c, map[string]string{"export_url": url}, "导出成功")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 返回结果
|
// 返回结果
|
||||||
response.OK(c, resp, "成功")
|
response.OK(c, resp, "成功")
|
||||||
}
|
}
|
||||||
|
@ -2039,21 +2081,32 @@ func (e MiGuDeployService) CalculateRevenueAnalysis(c *gin.Context) {
|
||||||
query = query.Where("channel_code = ?", req.Channel)
|
query = query.Where("channel_code = ?", req.Channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取每个月的新用户数和有效用户数
|
// 获取每个月的新用户数和有效用户数,以下代码是按退订时间超过1天来统计数据
|
||||||
var result []models.MonthlyRetention
|
var result []models.MonthlyRetention
|
||||||
err = query.
|
err = query.
|
||||||
Select(`DATE_FORMAT(subscribe_time, '%Y-%m') AS month,
|
Select(`DATE_FORMAT(subscribe_time, '%Y-%m') AS month,
|
||||||
COUNT(DISTINCT phone_number) AS new_user_count,
|
COUNT(DISTINCT phone_number) AS new_user_count,
|
||||||
COUNT(DISTINCT CASE
|
COUNT(DISTINCT CASE
|
||||||
WHEN unsubscribe_time IS NULL OR TIMESTAMPDIFF(HOUR, subscribe_time, unsubscribe_time) > 24
|
WHEN unsubscribe_time IS NULL OR TIMESTAMPDIFF(HOUR, subscribe_time, unsubscribe_time) > 24
|
||||||
THEN phone_number END) AS valid_users_count`).
|
THEN phone_number END) AS valid_users_count`).
|
||||||
Group("month").
|
Group("month").
|
||||||
Order("month").
|
Order("month").
|
||||||
Find(&result).Error
|
Find(&result).Error
|
||||||
if err != nil {
|
|
||||||
response.Error(c, http.StatusInternalServerError, err, "查询失败")
|
// 以下代码是按非1小时退订来统计数据
|
||||||
return
|
//err = query.
|
||||||
}
|
// Select(`DATE_FORMAT(subscribe_time, '%Y-%m') AS month,
|
||||||
|
// COUNT(DISTINCT phone_number) AS new_user_count,
|
||||||
|
// COUNT(DISTINCT CASE
|
||||||
|
// WHEN is_one_hour_cancel != 1
|
||||||
|
// THEN phone_number END) AS valid_users_count`).
|
||||||
|
// Group("month").
|
||||||
|
// Order("month").
|
||||||
|
// Find(&result).Error
|
||||||
|
//if err != nil {
|
||||||
|
// response.Error(c, http.StatusInternalServerError, err, "查询失败")
|
||||||
|
// return
|
||||||
|
//}
|
||||||
|
|
||||||
// 查询每个月的上个月未退订用户数
|
// 查询每个月的上个月未退订用户数
|
||||||
for i := 0; i < len(result); i++ {
|
for i := 0; i < len(result); i++ {
|
||||||
|
@ -2073,7 +2126,9 @@ func (e MiGuDeployService) CalculateRevenueAnalysis(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
result[i].ValidUsersCount += totalValidUsers + totalUnsubscribedUsers
|
result[i].RetainedUsersCount += totalValidUsers + totalUnsubscribedUsers
|
||||||
|
|
||||||
|
result[i].TotalValidUsersCount = result[i].RetainedUsersCount + result[i].ValidUsersCount
|
||||||
|
|
||||||
//// 获取当前记录的月份
|
//// 获取当前记录的月份
|
||||||
//currentMonth := result[i].Month
|
//currentMonth := result[i].Month
|
||||||
|
@ -2102,7 +2157,7 @@ func (e MiGuDeployService) CalculateRevenueAnalysis(c *gin.Context) {
|
||||||
totalValidUsers := 0
|
totalValidUsers := 0
|
||||||
for _, data := range result {
|
for _, data := range result {
|
||||||
totalNewUserCount += data.NewUserCount
|
totalNewUserCount += data.NewUserCount
|
||||||
totalValidUsers += data.ValidUsersCount
|
totalValidUsers += data.TotalValidUsersCount
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回结果
|
// 返回结果
|
||||||
|
@ -2111,6 +2166,17 @@ func (e MiGuDeployService) CalculateRevenueAnalysis(c *gin.Context) {
|
||||||
TotalValidUsers: totalValidUsers, // 添加有效用户数
|
TotalValidUsers: totalValidUsers, // 添加有效用户数
|
||||||
MonthlyRetentionData: result,
|
MonthlyRetentionData: result,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.IsExport == 1 {
|
||||||
|
url, err := models.ExportRevenueAnalysisToExcel(resp, e.Orm)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, http.StatusInternalServerError, err, "导出失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OK(c, map[string]string{"export_url": url}, "导出成功")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
response.OK(c, resp, "查询成功")
|
response.OK(c, resp, "查询成功")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package models
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/go-admin-team/go-admin-core/logger"
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
"github.com/xuri/excelize/v2"
|
"github.com/xuri/excelize/v2"
|
||||||
|
@ -344,6 +345,7 @@ type TransactionListReq struct {
|
||||||
EndTime string `json:"end_time"` // 结束时间
|
EndTime string `json:"end_time"` // 结束时间
|
||||||
PageNum int `json:"page_num"` // 页码
|
PageNum int `json:"page_num"` // 页码
|
||||||
PageSize int `json:"page_size"` // 每页条数
|
PageSize int `json:"page_size"` // 每页条数
|
||||||
|
IsExport uint32 `json:"is_export"` // 1-导出
|
||||||
}
|
}
|
||||||
|
|
||||||
// TransactionListResp 查询交易流水记录-出参
|
// TransactionListResp 查询交易流水记录-出参
|
||||||
|
@ -628,13 +630,16 @@ type RetentionMonthsReq struct {
|
||||||
EndTime string `json:"end_time"` // 查询结束时间
|
EndTime string `json:"end_time"` // 查询结束时间
|
||||||
ProductID int `json:"product_id"` // 产品ID
|
ProductID int `json:"product_id"` // 产品ID
|
||||||
Channel string `json:"channel"` // 渠道名称
|
Channel string `json:"channel"` // 渠道名称
|
||||||
|
IsExport uint32 `json:"is_export"` // 1-导出
|
||||||
}
|
}
|
||||||
|
|
||||||
// MonthlyRetention 表示每月留存数据
|
// MonthlyRetention 表示每月留存数据
|
||||||
type MonthlyRetention struct {
|
type MonthlyRetention struct {
|
||||||
Month string `json:"month"` // 年月
|
Month string `json:"month"` // 年月
|
||||||
NewUserCount int `json:"new_user_count"` // 新用户数
|
NewUserCount int `json:"new_user_count"` // 新用户数
|
||||||
ValidUsersCount int `json:"valid_users_count"` // 当月有效用户数
|
ValidUsersCount int `json:"valid_users_count"` // 当月新增有效用户数
|
||||||
|
RetainedUsersCount int `json:"retained_users_count"` // 历史推广用户本月留存数
|
||||||
|
TotalValidUsersCount int `json:"total_valid_users_count"` // 总有效用户数
|
||||||
}
|
}
|
||||||
|
|
||||||
// RetentionMonthsResp 表示响应参数结构体
|
// RetentionMonthsResp 表示响应参数结构体
|
||||||
|
@ -1781,3 +1786,272 @@ func ExportHourSummaryToExcel(data []MgHourSummary, sumData TotalHourSummary, db
|
||||||
|
|
||||||
return url, nil
|
return url, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExportRevenueAnalysisToExcel 营收分析数据导出excel
|
||||||
|
func ExportRevenueAnalysisToExcel(data RetentionMonthsResp, db *gorm.DB) (string, error) {
|
||||||
|
// 创建一个新的Excel文件
|
||||||
|
file := excelize.NewFile()
|
||||||
|
sheet := "Sheet1"
|
||||||
|
|
||||||
|
// 设置标题栏
|
||||||
|
titles := []string{"年月", "新用户数", "当月新增有效用户数", "历史推广用户本月留存数", "总有效用户数"}
|
||||||
|
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", 15)
|
||||||
|
file.SetColWidth(sheet, "C", "C", 20)
|
||||||
|
file.SetColWidth(sheet, "D", "D", 20)
|
||||||
|
file.SetColWidth(sheet, "E", "E", 18)
|
||||||
|
|
||||||
|
// 填充数据
|
||||||
|
for i, record := range data.MonthlyRetentionData {
|
||||||
|
row := i + 2
|
||||||
|
file.SetCellValue(sheet, "A"+strconv.Itoa(row), record.Month)
|
||||||
|
file.SetCellValue(sheet, "B"+strconv.Itoa(row), record.NewUserCount)
|
||||||
|
file.SetCellValue(sheet, "C"+strconv.Itoa(row), record.ValidUsersCount)
|
||||||
|
file.SetCellValue(sheet, "D"+strconv.Itoa(row), record.RetainedUsersCount)
|
||||||
|
file.SetCellValue(sheet, "E"+strconv.Itoa(row), record.TotalValidUsersCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 填充合计行数据
|
||||||
|
file.SetCellValue(sheet, "A"+strconv.Itoa(len(data.MonthlyRetentionData)+2), "合计:")
|
||||||
|
file.SetCellValue(sheet, "B"+strconv.Itoa(len(data.MonthlyRetentionData)+2), data.TotalNewUsers)
|
||||||
|
file.SetCellValue(sheet, "C"+strconv.Itoa(len(data.MonthlyRetentionData)+2), "--")
|
||||||
|
file.SetCellValue(sheet, "D"+strconv.Itoa(len(data.MonthlyRetentionData)+2), "--")
|
||||||
|
file.SetCellValue(sheet, "E"+strconv.Itoa(len(data.MonthlyRetentionData)+2), data.TotalValidUsers)
|
||||||
|
|
||||||
|
endRow := fmt.Sprintf("E%d", len(data.MonthlyRetentionData)+2)
|
||||||
|
// 应用样式到整个表格
|
||||||
|
_ = 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckDateRange 检查时间间隔是否超过 n 天
|
||||||
|
func CheckDateRange(start, end string, nDay int) error {
|
||||||
|
if start == "" || end == "" {
|
||||||
|
return errors.New("导出失败,时间不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析时间,假设时间格式为 "2006-01-02"
|
||||||
|
startTime, err := time.Parse(MiGuTimeFormat, start)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("开始时间格式错误")
|
||||||
|
}
|
||||||
|
endTime, err := time.Parse(MiGuTimeFormat, end)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("结束时间格式错误")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算时间间隔
|
||||||
|
if endTime.Sub(startTime).Hours() > float64(nDay*24) {
|
||||||
|
return errors.New(fmt.Sprintf("导出时间间隔不能超过 %d 天", nDay))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExportUserRetentionToExcel 用户留存记录导出excel
|
||||||
|
func ExportUserRetentionToExcel(data []MgUserRetention, db *gorm.DB) (string, error) {
|
||||||
|
// 创建一个新的Excel文件
|
||||||
|
file := excelize.NewFile()
|
||||||
|
sheet := "Sheet1"
|
||||||
|
|
||||||
|
lastMonthFirstDay := time.Date(time.Now().Year(), time.Now().Month(), 1, 0, 0, 0, 0, time.Local) // 当前月1号
|
||||||
|
lastTwoMonthFirstDay := lastMonthFirstDay.AddDate(0, -1, 0) // 上个月1号
|
||||||
|
|
||||||
|
lastMonthCountTitle := lastMonthFirstDay.Format("2006-01-02") + "留存数"
|
||||||
|
lastMonthRateTitle := lastMonthFirstDay.Format("2006-01-02") + "留存率"
|
||||||
|
|
||||||
|
lastTwoMonthCountTitle := lastTwoMonthFirstDay.Format("2006-01-02") + "留存数"
|
||||||
|
lastTwoMonthRateTitle := lastTwoMonthFirstDay.Format("2006-01-02") + "留存率"
|
||||||
|
|
||||||
|
// 设置标题栏
|
||||||
|
titles := []string{"留存月份", "渠道", "产品", "新增数", "留存数", "留存率", lastTwoMonthCountTitle, lastTwoMonthRateTitle,
|
||||||
|
lastMonthCountTitle, lastMonthRateTitle}
|
||||||
|
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", 15)
|
||||||
|
file.SetColWidth(sheet, "C", "C", 18)
|
||||||
|
file.SetColWidth(sheet, "D", "D", 15)
|
||||||
|
file.SetColWidth(sheet, "E", "E", 15)
|
||||||
|
file.SetColWidth(sheet, "F", "F", 15)
|
||||||
|
file.SetColWidth(sheet, "G", "G", 18)
|
||||||
|
file.SetColWidth(sheet, "H", "H", 18)
|
||||||
|
file.SetColWidth(sheet, "I", "I", 18)
|
||||||
|
file.SetColWidth(sheet, "J", "J", 18)
|
||||||
|
|
||||||
|
// 创建一个产品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.RetentionMonth)
|
||||||
|
file.SetCellValue(sheet, "B"+strconv.Itoa(row), record.ChannelCode)
|
||||||
|
file.SetCellValue(sheet, "C"+strconv.Itoa(row), productName)
|
||||||
|
file.SetCellValue(sheet, "D"+strconv.Itoa(row), record.NewUserCount)
|
||||||
|
file.SetCellValue(sheet, "E"+strconv.Itoa(row), record.RetainedUserCount)
|
||||||
|
file.SetCellValue(sheet, "F"+strconv.Itoa(row), record.RetentionRate)
|
||||||
|
file.SetCellValue(sheet, "G"+strconv.Itoa(row), record.LastTwoMonthRetentionCount)
|
||||||
|
file.SetCellValue(sheet, "H"+strconv.Itoa(row), record.LastTwoMonthRetentionRate)
|
||||||
|
file.SetCellValue(sheet, "I"+strconv.Itoa(row), record.LastMonthRetentionCount)
|
||||||
|
file.SetCellValue(sheet, "J"+strconv.Itoa(row), record.LastMonthRetentionRate)
|
||||||
|
}
|
||||||
|
|
||||||
|
endRow := fmt.Sprintf("J%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
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExportTransactionToExcel 交易流水记录导出excel
|
||||||
|
func ExportTransactionToExcel(data []MgTransactionLog, db *gorm.DB) (string, error) {
|
||||||
|
// 创建一个新的Excel文件
|
||||||
|
file := excelize.NewFile()
|
||||||
|
sheet := "Sheet1"
|
||||||
|
|
||||||
|
// 设置标题栏
|
||||||
|
titles := []string{"调用时间", "产品", "渠道", "手机号", "平台订单号", "外部平台订单号", "渠道订单号", "结果", "原因",
|
||||||
|
"验证码", "订单时间"}
|
||||||
|
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", 18)
|
||||||
|
file.SetColWidth(sheet, "C", "C", 15)
|
||||||
|
file.SetColWidth(sheet, "D", "D", 15)
|
||||||
|
file.SetColWidth(sheet, "E", "E", 20)
|
||||||
|
file.SetColWidth(sheet, "F", "F", 20)
|
||||||
|
file.SetColWidth(sheet, "G", "G", 28)
|
||||||
|
file.SetColWidth(sheet, "I", "I", 28)
|
||||||
|
file.SetColWidth(sheet, "K", "K", 18)
|
||||||
|
|
||||||
|
// 创建一个产品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
|
||||||
|
var orderTime string
|
||||||
|
if record.OrderTime == nil {
|
||||||
|
orderTime = ""
|
||||||
|
} else {
|
||||||
|
orderTime = record.OrderTime.Format(MiGuTimeFormat)
|
||||||
|
}
|
||||||
|
productName := productMap[record.ProductID] // 获取产品名称
|
||||||
|
file.SetCellValue(sheet, "A"+strconv.Itoa(row), record.CreatedAt.Format(MiGuTimeFormat))
|
||||||
|
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.PhoneNumber)
|
||||||
|
file.SetCellValue(sheet, "E"+strconv.Itoa(row), record.OutTradeNo)
|
||||||
|
file.SetCellValue(sheet, "F"+strconv.Itoa(row), record.LinkId)
|
||||||
|
file.SetCellValue(sheet, "G"+strconv.Itoa(row), record.ChannelTradeNo)
|
||||||
|
file.SetCellValue(sheet, "H"+strconv.Itoa(row), record.Result)
|
||||||
|
file.SetCellValue(sheet, "I"+strconv.Itoa(row), record.Reason)
|
||||||
|
file.SetCellValue(sheet, "J"+strconv.Itoa(row), record.VerificationCode)
|
||||||
|
file.SetCellValue(sheet, "K"+strconv.Itoa(row), orderTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
endRow := fmt.Sprintf("K%d", len(data)+2)
|
||||||
|
// 应用样式到整个表格
|
||||||
|
_ = 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
|
||||||
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ func registerMiGuControlManageRouter(v1 *gin.RouterGroup, authMiddleware *jwt.Gi
|
||||||
api.POST("user_day_retention/list", apiMiGu.UserDayRetentionList) // 用户留存记录(按天)
|
api.POST("user_day_retention/list", apiMiGu.UserDayRetentionList) // 用户留存记录(按天)
|
||||||
api.POST("sys_channel/list", apiMiGu.SysChannelList) // 查询系统所有渠道编码
|
api.POST("sys_channel/list", apiMiGu.SysChannelList) // 查询系统所有渠道编码
|
||||||
api.POST("home/data", apiMiGu.HomepageDataSummary) // 查询首页汇总数据
|
api.POST("home/data", apiMiGu.HomepageDataSummary) // 查询首页汇总数据
|
||||||
api.POST("home/revenue_analysis", apiMiGu.CalculateRevenueAnalysis) // 查询不同日期的留存月份
|
api.POST("home/revenue_analysis", apiMiGu.CalculateRevenueAnalysis) // 营收分析
|
||||||
|
|
||||||
api.POST("historical_summary/list", apiMiGu.HistoricalSummaryListOld) // 历史汇总查询
|
api.POST("historical_summary/list", apiMiGu.HistoricalSummaryListOld) // 历史汇总查询
|
||||||
//api.POST("order/import", apiMiGu.ImportExcelToMgOrderHandler) // 通过excel导入订单数据
|
//api.POST("order/import", apiMiGu.ImportExcelToMgOrderHandler) // 通过excel导入订单数据
|
||||||
|
|
|
@ -5408,8 +5408,16 @@ const docTemplateadmin = `{
|
||||||
"description": "新用户数",
|
"description": "新用户数",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"retained_users_count": {
|
||||||
|
"description": "历史推广用户本月留存数",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"total_valid_users_count": {
|
||||||
|
"description": "总有效用户数",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"valid_users_count": {
|
"valid_users_count": {
|
||||||
"description": "当月有效用户数",
|
"description": "当月新增有效用户数",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5969,6 +5977,10 @@ const docTemplateadmin = `{
|
||||||
"description": "渠道号",
|
"description": "渠道号",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"is_export": {
|
||||||
|
"description": "1-导出",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"only_first_day": {
|
"only_first_day": {
|
||||||
"description": "是否只查询每个月1号的数据",
|
"description": "是否只查询每个月1号的数据",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
@ -6018,6 +6030,10 @@ const docTemplateadmin = `{
|
||||||
"description": "渠道号",
|
"description": "渠道号",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"is_export": {
|
||||||
|
"description": "1-导出",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"page_num": {
|
"page_num": {
|
||||||
"description": "页码",
|
"description": "页码",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
|
|
|
@ -5400,8 +5400,16 @@
|
||||||
"description": "新用户数",
|
"description": "新用户数",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"retained_users_count": {
|
||||||
|
"description": "历史推广用户本月留存数",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"total_valid_users_count": {
|
||||||
|
"description": "总有效用户数",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"valid_users_count": {
|
"valid_users_count": {
|
||||||
"description": "当月有效用户数",
|
"description": "当月新增有效用户数",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5961,6 +5969,10 @@
|
||||||
"description": "渠道号",
|
"description": "渠道号",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"is_export": {
|
||||||
|
"description": "1-导出",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"only_first_day": {
|
"only_first_day": {
|
||||||
"description": "是否只查询每个月1号的数据",
|
"description": "是否只查询每个月1号的数据",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
@ -6010,6 +6022,10 @@
|
||||||
"description": "渠道号",
|
"description": "渠道号",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"is_export": {
|
||||||
|
"description": "1-导出",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"page_num": {
|
"page_num": {
|
||||||
"description": "页码",
|
"description": "页码",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
|
|
|
@ -1402,8 +1402,14 @@ definitions:
|
||||||
new_user_count:
|
new_user_count:
|
||||||
description: 新用户数
|
description: 新用户数
|
||||||
type: integer
|
type: integer
|
||||||
|
retained_users_count:
|
||||||
|
description: 历史推广用户本月留存数
|
||||||
|
type: integer
|
||||||
|
total_valid_users_count:
|
||||||
|
description: 总有效用户数
|
||||||
|
type: integer
|
||||||
valid_users_count:
|
valid_users_count:
|
||||||
description: 当月有效用户数
|
description: 当月新增有效用户数
|
||||||
type: integer
|
type: integer
|
||||||
type: object
|
type: object
|
||||||
models.OrderListReq:
|
models.OrderListReq:
|
||||||
|
@ -1789,6 +1795,9 @@ definitions:
|
||||||
channel:
|
channel:
|
||||||
description: 渠道号
|
description: 渠道号
|
||||||
type: string
|
type: string
|
||||||
|
is_export:
|
||||||
|
description: 1-导出
|
||||||
|
type: integer
|
||||||
only_first_day:
|
only_first_day:
|
||||||
description: 是否只查询每个月1号的数据
|
description: 是否只查询每个月1号的数据
|
||||||
type: boolean
|
type: boolean
|
||||||
|
@ -1827,6 +1836,9 @@ definitions:
|
||||||
channel:
|
channel:
|
||||||
description: 渠道号
|
description: 渠道号
|
||||||
type: string
|
type: string
|
||||||
|
is_export:
|
||||||
|
description: 1-导出
|
||||||
|
type: integer
|
||||||
page_num:
|
page_num:
|
||||||
description: 页码
|
description: 页码
|
||||||
type: integer
|
type: integer
|
||||||
|
|
Loading…
Reference in New Issue
Block a user