1、历史汇总查询新增24小时退订数和退订率,对应excel调整;

2、订单表新增状态4-24小时退订查询;
This commit is contained in:
chenlin 2025-04-14 17:06:07 +08:00
parent 2863174547
commit 2eb326eb0a
6 changed files with 303 additions and 232 deletions

View File

@ -1,16 +1,13 @@
package migumanage
import (
"encoding/csv"
"errors"
"fmt"
"github.com/gin-gonic/gin"
"github.com/go-admin-team/go-admin-core/logger"
"github.com/go-admin-team/go-admin-core/sdk/pkg/response"
"go-admin/app/admin/models"
"go-admin/tools"
"gorm.io/gorm"
"io"
"net/http"
"sort"
"strconv"
@ -336,6 +333,10 @@ func (e MiGuDeployService) OrderList(c *gin.Context) {
if req.State != 0 {
if req.State == 3 { // 1小时内退订
qs = qs.Where("is_one_hour_cancel = ?", 1)
} else if req.State == 4 {
// 查询退订状态为2且退订时间与订购时间在24小时内
qs = qs.Where("state = ?", 2)
qs = qs.Where("TIMESTAMPDIFF(HOUR, subscribe_time, unsubscribe_time) <= 24")
} else {
state := 1 // 订阅
if req.State == 1 {
@ -508,10 +509,12 @@ func (e MiGuDeployService) HistoricalSummaryListOld(c *gin.Context) {
IFNULL(submission_count.submission_count, 0) 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 AND DATE(mg_order.unsubscribe_time) = DATE(mg_order.subscribe_time) THEN 1 END) AS new_user_unsub_on_day,
COUNT(CASE WHEN mg_order.state = 2 AND TIMESTAMPDIFF(HOUR, mg_order.subscribe_time, mg_order.unsubscribe_time) <= 24 THEN 1 END) AS new_user_unsub_within_24h,
COUNT(*) AS new_user_count,
SUM(CASE WHEN mg_order.state = 2 THEN 1 ELSE 0 END) AS total_new_user_unsub,
CONCAT(ROUND(COUNT(CASE WHEN mg_order.is_one_hour_cancel = 1 THEN 1 END) * 100.0 / NULLIF(COUNT(*), 0), 2), '%') AS new_user_unsub_within_hour_rate,
CONCAT(ROUND(COUNT(CASE WHEN mg_order.state = 2 AND DATE(mg_order.unsubscribe_time) = DATE(mg_order.subscribe_time) THEN 1 END) * 100.0 / NULLIF(COUNT(*), 0), 2), '%') AS new_user_unsub_on_day_rate,
CONCAT(ROUND(COUNT(CASE WHEN mg_order.state = 2 AND TIMESTAMPDIFF(HOUR, mg_order.subscribe_time, mg_order.unsubscribe_time) <= 24 THEN 1 END) * 100.0 / NULLIF(COUNT(*), 0), 2), '%') AS new_user_unsub_within_24h_rate,
CONCAT(ROUND(SUM(CASE WHEN mg_order.state = 2 THEN 1 ELSE 0 END) * 100.0 / NULLIF(COUNT(*), 0), 2), '%') AS total_new_user_unsub_rate,
IFNULL(
CONCAT(
@ -2667,215 +2670,215 @@ func (e MiGuDeployService) AddProduct(c *gin.Context) {
// e.OK("", "删除成功")
//}
// ImportExcelToMgOrderHandler 处理Excel文件导入请求
// @Summary 导入订单Excel文件
// @Tags 2024-咪咕-管理后台
// @Accept multipart/form-data
// @Produce json
// @Param file formData file true "Excel文件"
// @Success 200 {object} map[string]string{"message": "导入成功"}
// @Router /api/v1/admin/order/import [post]
func (e MiGuDeployService) ImportExcelToMgOrderHandler(c *gin.Context) {
err := e.MakeContext(c).MakeOrm().Errors
if err != nil {
e.Logger.Error(err)
response.Error(c, http.StatusInternalServerError, err, "创建上下文失败")
return
}
// 从请求中获取文件
file, err := c.FormFile("file")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "无法读取文件"})
return
}
// 打开上传的文件
fileStream, err := file.Open()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "无法打开文件"})
return
}
defer fileStream.Close()
// 创建 CSV 阅读器
reader := csv.NewReader(fileStream)
reader.LazyQuotes = true
// 跳过 CSV 文件的标题行
if _, err := reader.Read(); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "无法读取CSV标题行"})
return
}
//nRow := 0
// 逐行读取 CSV 并插入数据库
for {
//nRow++
row, err := reader.Read()
if err == io.EOF {
break
}
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "读取CSV文件失败"})
return
}
// 检查数据是否齐全
if len(row) < 3 {
continue // 跳过数据不全的行
}
// 解析订阅时间
subscribeTime, err := time.Parse("2006-01-02 15:04:05", row[1])
if err != nil {
fmt.Printf("解析时间错误: %v\n", err)
continue
}
//const cutoffTimeStr = "2024-10-18 18:58:00"
//cutoffTime, _ := time.Parse("2006-01-02 15:04:05", cutoffTimeStr)
//// 判断是否超过截止时间
//if subscribeTime.After(cutoffTime) {
// fmt.Printf("跳过超过截止时间的记录: %v\n", subscribeTime)
// continue
//}
// 将时间转换为 UTC+08:00
// 将时间往前推8小时
localTime := subscribeTime.Add(-8 * time.Hour)
tempOrderNo := models.GetExcelOrderSerial(e.Orm, subscribeTime)
// 创建MgOrder对象
order := models.MgOrderCopy{
ProductID: 2,
ChannelCode: "00211NV",
OrderSerial: tempOrderNo,
SubscribeTime: &localTime,
PhoneNumber: row[0],
ChannelTradeNo: tempOrderNo,
ExternalOrderID: tempOrderNo,
State: 1,
}
if row[2] == "未包月" { // 1小时内退订
order.IsOneHourCancel = 1
order.State = 2
unsubscribeTime := localTime.Add(30 * time.Minute)
order.UnsubscribeTime = &unsubscribeTime
}
order.CreatedAt = localTime
order.UpdatedAt = localTime
order.SM4PhoneNumber, _ = tools.SM4Encrypt(models.SM4KEy, order.PhoneNumber)
// 插入到数据库
if err := e.Orm.Create(&order).Error; err != nil {
fmt.Printf("插入订单数据失败: %v\n", err)
continue
}
fmt.Println("order is:", order)
//if nRow > 4 {
// break
//}
}
// 返回成功消息
c.JSON(http.StatusOK, gin.H{"message": "导入成功"})
}
// ImportExcelToMgOrderHandlerUpdate 处理Excel文件导入请求
// @Summary 导入订单Excel退订文件
// @Tags 2024-咪咕-管理后台
// @Accept multipart/form-data
// @Produce json
// @Param file formData file true "Excel文件"
// @Success 200 {object} map[string]string{"message": "导入成功"}
// @Router /api/v1/admin/order/import_update [post]
func (e MiGuDeployService) ImportExcelToMgOrderHandlerUpdate(c *gin.Context) {
err := e.MakeContext(c).MakeOrm().Errors
if err != nil {
e.Logger.Error(err)
response.Error(c, http.StatusInternalServerError, err, "创建上下文失败")
return
}
// 从请求中获取文件
file, err := c.FormFile("file")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "无法读取文件"})
return
}
// 打开上传的文件
fileStream, err := file.Open()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "无法打开文件"})
return
}
defer fileStream.Close()
// 创建 CSV 阅读器
reader := csv.NewReader(fileStream)
reader.LazyQuotes = true
// 跳过 CSV 文件的标题行
if _, err := reader.Read(); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "无法读取CSV标题行"})
return
}
//nRow := 0
// 逐行读取 CSV 并插入数据库
for {
//nRow++
row, err := reader.Read()
if err == io.EOF {
break
}
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "读取CSV文件失败"})
return
}
// 检查数据是否齐全
if len(row) < 3 {
continue // 跳过数据不全的行
}
// 将时间往前推8小时
//localTime := subscribeTime.Add(-8 * time.Hour)
if !(row[0] != "" && len(row[0]) == 11) {
continue
}
if row[0] == "15812800163" {
fmt.Println("found phone number: 15812800163")
break
}
unsubscribeTime, _ := models.ConvertStringToTime(row[2])
err = e.Orm.Table("mg_order_copy").Where("phone_number = ?", row[0]).Updates(map[string]interface{}{
"state": models.UnsubscribeOK,
"unsubscribe_time": unsubscribeTime,
"updated_at": unsubscribeTime,
}).Error
if err != nil {
fmt.Println("CheckOrderState update mg_order err:", err.Error())
continue
}
//if nRow > 4 {
// break
//}
}
// 返回成功消息
c.JSON(http.StatusOK, gin.H{"message": "导入成功"})
}
//// ImportExcelToMgOrderHandler 处理Excel文件导入请求
//// @Summary 导入订单Excel文件
//// @Tags 2024-咪咕-管理后台
//// @Accept multipart/form-data
//// @Produce json
//// @Param file formData file true "Excel文件"
//// @Success 200 {object} map[string]string{"message": "导入成功"}
//// @Router /api/v1/admin/order/import [post]
//func (e MiGuDeployService) ImportExcelToMgOrderHandler(c *gin.Context) {
// err := e.MakeContext(c).MakeOrm().Errors
// if err != nil {
// e.Logger.Error(err)
// response.Error(c, http.StatusInternalServerError, err, "创建上下文失败")
// return
// }
//
// // 从请求中获取文件
// file, err := c.FormFile("file")
// if err != nil {
// c.JSON(http.StatusBadRequest, gin.H{"error": "无法读取文件"})
// return
// }
//
// // 打开上传的文件
// fileStream, err := file.Open()
// if err != nil {
// c.JSON(http.StatusInternalServerError, gin.H{"error": "无法打开文件"})
// return
// }
// defer fileStream.Close()
//
// // 创建 CSV 阅读器
// reader := csv.NewReader(fileStream)
// reader.LazyQuotes = true
//
// // 跳过 CSV 文件的标题行
// if _, err := reader.Read(); err != nil {
// c.JSON(http.StatusInternalServerError, gin.H{"error": "无法读取CSV标题行"})
// return
// }
//
// //nRow := 0
// // 逐行读取 CSV 并插入数据库
// for {
// //nRow++
// row, err := reader.Read()
// if err == io.EOF {
// break
// }
// if err != nil {
// c.JSON(http.StatusInternalServerError, gin.H{"error": "读取CSV文件失败"})
// return
// }
//
// // 检查数据是否齐全
// if len(row) < 3 {
// continue // 跳过数据不全的行
// }
//
// // 解析订阅时间
// subscribeTime, err := time.Parse("2006-01-02 15:04:05", row[1])
// if err != nil {
// fmt.Printf("解析时间错误: %v\n", err)
// continue
// }
//
// //const cutoffTimeStr = "2024-10-18 18:58:00"
// //cutoffTime, _ := time.Parse("2006-01-02 15:04:05", cutoffTimeStr)
// //// 判断是否超过截止时间
// //if subscribeTime.After(cutoffTime) {
// // fmt.Printf("跳过超过截止时间的记录: %v\n", subscribeTime)
// // continue
// //}
//
// // 将时间转换为 UTC+08:00
// // 将时间往前推8小时
// localTime := subscribeTime.Add(-8 * time.Hour)
//
// tempOrderNo := models.GetExcelOrderSerial(e.Orm, subscribeTime)
//
// // 创建MgOrder对象
// order := models.MgOrderCopy{
// ProductID: 2,
// ChannelCode: "00211NV",
// OrderSerial: tempOrderNo,
// SubscribeTime: &localTime,
// PhoneNumber: row[0],
// ChannelTradeNo: tempOrderNo,
// ExternalOrderID: tempOrderNo,
// State: 1,
// }
//
// if row[2] == "未包月" { // 1小时内退订
// order.IsOneHourCancel = 1
// order.State = 2
// unsubscribeTime := localTime.Add(30 * time.Minute)
// order.UnsubscribeTime = &unsubscribeTime
// }
//
// order.CreatedAt = localTime
// order.UpdatedAt = localTime
// order.SM4PhoneNumber, _ = tools.SM4Encrypt(models.SM4KEy, order.PhoneNumber)
//
// // 插入到数据库
// if err := e.Orm.Create(&order).Error; err != nil {
// fmt.Printf("插入订单数据失败: %v\n", err)
// continue
// }
//
// fmt.Println("order is:", order)
// //if nRow > 4 {
// // break
// //}
// }
//
// // 返回成功消息
// c.JSON(http.StatusOK, gin.H{"message": "导入成功"})
//}
//
//// ImportExcelToMgOrderHandlerUpdate 处理Excel文件导入请求
//// @Summary 导入订单Excel退订文件
//// @Tags 2024-咪咕-管理后台
//// @Accept multipart/form-data
//// @Produce json
//// @Param file formData file true "Excel文件"
//// @Success 200 {object} map[string]string{"message": "导入成功"}
//// @Router /api/v1/admin/order/import_update [post]
//func (e MiGuDeployService) ImportExcelToMgOrderHandlerUpdate(c *gin.Context) {
// err := e.MakeContext(c).MakeOrm().Errors
// if err != nil {
// e.Logger.Error(err)
// response.Error(c, http.StatusInternalServerError, err, "创建上下文失败")
// return
// }
//
// // 从请求中获取文件
// file, err := c.FormFile("file")
// if err != nil {
// c.JSON(http.StatusBadRequest, gin.H{"error": "无法读取文件"})
// return
// }
//
// // 打开上传的文件
// fileStream, err := file.Open()
// if err != nil {
// c.JSON(http.StatusInternalServerError, gin.H{"error": "无法打开文件"})
// return
// }
// defer fileStream.Close()
//
// // 创建 CSV 阅读器
// reader := csv.NewReader(fileStream)
// reader.LazyQuotes = true
//
// // 跳过 CSV 文件的标题行
// if _, err := reader.Read(); err != nil {
// c.JSON(http.StatusInternalServerError, gin.H{"error": "无法读取CSV标题行"})
// return
// }
//
// //nRow := 0
// // 逐行读取 CSV 并插入数据库
// for {
// //nRow++
// row, err := reader.Read()
// if err == io.EOF {
// break
// }
// if err != nil {
// c.JSON(http.StatusInternalServerError, gin.H{"error": "读取CSV文件失败"})
// return
// }
//
// // 检查数据是否齐全
// if len(row) < 3 {
// continue // 跳过数据不全的行
// }
//
// // 将时间往前推8小时
// //localTime := subscribeTime.Add(-8 * time.Hour)
//
// if !(row[0] != "" && len(row[0]) == 11) {
// continue
// }
//
// if row[0] == "15812800163" {
// fmt.Println("found phone number: 15812800163")
// break
// }
//
// unsubscribeTime, _ := models.ConvertStringToTime(row[2])
//
// err = e.Orm.Table("mg_order_copy").Where("phone_number = ?", row[0]).Updates(map[string]interface{}{
// "state": models.UnsubscribeOK,
// "unsubscribe_time": unsubscribeTime,
// "updated_at": unsubscribeTime,
// }).Error
// if err != nil {
// fmt.Println("CheckOrderState update mg_order err:", err.Error())
// continue
// }
// //if nRow > 4 {
// // break
// //}
// }
//
// // 返回成功消息
// c.JSON(http.StatusOK, gin.H{"message": "导入成功"})
//}
// HourSummaryList 历史汇总(按小时)
// @Summary 历史汇总(按小时)
@ -3086,15 +3089,33 @@ func (e MiGuDeployService) queryHistoricalDataByHour(startTime, endTime string,
// 拆分小时数据与汇总数据
var filteredData []models.MgHourSummary
var summaryData *models.MgHourSummary
summaryData := &models.MgHourSummary{}
for _, item := range data {
if item.Hour == "Total" {
summaryData = &item
// 累积汇总数据
summaryData.SubmissionCount += item.SubmissionCount
summaryData.NewUserCount += item.NewUserCount
summaryData.NewUserUnsubWithinHour += item.NewUserUnsubWithinHour
summaryData.NewUserUnsubOnDay += item.NewUserUnsubOnDay
summaryData.TotalNewUserUnsub += item.TotalNewUserUnsub
} else {
filteredData = append(filteredData, item)
}
}
// 汇总数据比率重新计算
if summaryData.NewUserCount > 0 {
summaryData.SubmissionSuccessRate = fmt.Sprintf("%.2f%%", float64(summaryData.NewUserCount)*100/float64(summaryData.SubmissionCount))
summaryData.NewUserUnsubWithinHourRate = fmt.Sprintf("%.2f%%", float64(summaryData.NewUserUnsubWithinHour)*100/float64(summaryData.NewUserCount))
summaryData.NewUserUnsubOnDayRate = fmt.Sprintf("%.2f%%", float64(summaryData.NewUserUnsubOnDay)*100/float64(summaryData.NewUserCount))
summaryData.TotalNewUserUnsubRate = fmt.Sprintf("%.2f%%", float64(summaryData.TotalNewUserUnsub)*100/float64(summaryData.NewUserCount))
} else {
summaryData.SubmissionSuccessRate = "0.00%"
summaryData.NewUserUnsubWithinHourRate = "0.00%"
summaryData.NewUserUnsubOnDayRate = "0.00%"
summaryData.TotalNewUserUnsubRate = "0.00%"
}
// 按小时降序排序
sort.Slice(filteredData, func(i, j int) bool {
hourI, errI := strconv.Atoi(filteredData[i].Hour)

View File

@ -139,18 +139,20 @@ type MgHourSummary struct {
// MgHistoricalSummary 历史汇总查询表对应的结构体
type MgHistoricalSummary struct {
Date string `json:"date"` // 日期
ProductID int64 `json:"product_id"` // 产品ID
ChannelCode string `gorm:"size:255" json:"channel_code"` // 渠道编码
SubmissionCount int `json:"submission_count"` // 提交数
NewUserCount int `json:"new_user_count"` // 新用户数
SubmissionSuccessRate string `json:"submission_success_rate"` // 提交成功率
NewUserUnsubWithinHour int `json:"new_user_unsub_within_hour"` // 当日新用户退订数1小时以内
NewUserUnsubWithinHourRate string `json:"new_user_unsub_within_hour_rate"` // 当日新用户退订率1小时以内
NewUserUnsubOnDay int `json:"new_user_unsub_on_day"` // 当日新用户退订数
NewUserUnsubOnDayRate string `json:"new_user_unsub_on_day_rate"` // 当日新用户退订率
TotalNewUserUnsub int `json:"total_new_user_unsub"` // 累计新用户退订数
TotalNewUserUnsubRate string `json:"total_new_user_unsub_rate"` // 累计新用户退订率
Date string `json:"date"` // 日期
ProductID int64 `json:"product_id"` // 产品ID
ChannelCode string `gorm:"size:255" json:"channel_code"` // 渠道编码
SubmissionCount int `json:"submission_count"` // 提交数
NewUserCount int `json:"new_user_count"` // 新用户数
SubmissionSuccessRate string `json:"submission_success_rate"` // 提交成功率
NewUserUnsubWithinHour int `json:"new_user_unsub_within_hour"` // 当日新用户退订数1小时以内
NewUserUnsubWithinHourRate string `json:"new_user_unsub_within_hour_rate"` // 当日新用户退订率1小时以内
NewUserUnsubOnDay int `json:"new_user_unsub_on_day"` // 当日新用户退订数
NewUserUnsubOnDayRate string `json:"new_user_unsub_on_day_rate"` // 当日新用户退订率
NewUserUnsubWithin24H int `gorm:"column:new_user_unsub_within_24h" json:"new_user_unsub_within_24h"` // 当日新用户24小时退订数
NewUserUnsubWithin24HRate string `gorm:"column:new_user_unsub_within_24h_rate" json:"new_user_unsub_within_24h_rate"` // 当日新用户24小时退订率
TotalNewUserUnsub int `json:"total_new_user_unsub"` // 累计新用户退订数
TotalNewUserUnsubRate string `json:"total_new_user_unsub_rate"` // 累计新用户退订率
//Province string `gorm:"size:255" json:"province"` // 省份
}
@ -398,7 +400,7 @@ type OrderListReq struct {
ChannelTradeNo string `json:"channelTradeNo"` // 渠道订单号
Phone string `json:"phone"` // 手机号码
SM4PhoneNumber string `json:"sm4_phone_number"` // SM4加密手机号
State int `json:"state"` // 退订状态 0-查所有 1-未退订 2-已退订 3-1小时内退订
State int `json:"state"` // 退订状态 0-查所有 1-已退订 2-未退订 3-1小时内退订 4-24小时退订
PageNum int `json:"page_num"` // 页码
PageSize int `json:"page_size"` // 每页条数
IsExport uint32 `json:"is_export"` // 1-导出
@ -1397,7 +1399,7 @@ func ExportHistoricalSummaryToExcel(data []MgHistoricalSummary, db *gorm.DB) (st
// 设置标题栏
titles := []string{"日期", "产品ID", "渠道编码", "提交数", "新用户数", "提交成功率", "1小时退订数", "1小时退订率",
"当日退订数", "当日退订率", "累计退订数", "累计退订率"}
"当日退订数", "当日退订率", "24小时退订数", "24小时退订率", "累计退订数", "累计退订率"}
for i, title := range titles {
cell, _ := excelize.CoordinatesToCellName(i+1, 1)
file.SetCellValue(sheet, cell, title)
@ -1424,6 +1426,8 @@ func ExportHistoricalSummaryToExcel(data []MgHistoricalSummary, db *gorm.DB) (st
file.SetColWidth(sheet, "J", "J", 15)
file.SetColWidth(sheet, "K", "K", 15)
file.SetColWidth(sheet, "L", "L", 15)
file.SetColWidth(sheet, "M", "M", 15)
file.SetColWidth(sheet, "N", "N", 15)
// 创建一个产品ID到名称的映射
productMap := make(map[int64]string)
@ -1453,11 +1457,13 @@ func ExportHistoricalSummaryToExcel(data []MgHistoricalSummary, db *gorm.DB) (st
file.SetCellValue(sheet, "H"+strconv.Itoa(row), record.NewUserUnsubWithinHourRate)
file.SetCellValue(sheet, "I"+strconv.Itoa(row), record.NewUserUnsubOnDay)
file.SetCellValue(sheet, "J"+strconv.Itoa(row), record.NewUserUnsubOnDayRate)
file.SetCellValue(sheet, "K"+strconv.Itoa(row), record.TotalNewUserUnsub)
file.SetCellValue(sheet, "L"+strconv.Itoa(row), record.TotalNewUserUnsubRate)
file.SetCellValue(sheet, "K"+strconv.Itoa(row), record.NewUserUnsubWithin24H)
file.SetCellValue(sheet, "L"+strconv.Itoa(row), record.NewUserUnsubWithin24HRate)
file.SetCellValue(sheet, "M"+strconv.Itoa(row), record.TotalNewUserUnsub)
file.SetCellValue(sheet, "N"+strconv.Itoa(row), record.TotalNewUserUnsubRate)
}
endRow := fmt.Sprintf("L%d", len(data)+1)
endRow := fmt.Sprintf("N%d", len(data)+1)
// 应用样式到整个表格
_ = file.SetCellStyle(sheet, "A1", endRow, style)

View File

@ -33,7 +33,7 @@ func registerMiGuControlManageRouter(v1 *gin.RouterGroup, authMiddleware *jwt.Gi
api.POST("home/revenue_analysis", apiMiGu.CalculateRevenueAnalysis) // 营收分析
api.POST("historical_summary/list", apiMiGu.HistoricalSummaryListOld) // 历史汇总查询
api.POST("order/import", apiMiGu.ImportExcelToMgOrderHandler) // 通过excel导入订单数据
//api.POST("order/import", apiMiGu.ImportExcelToMgOrderHandler) // 通过excel导入订单数据
//api.POST("order/import_update", apiMiGu.ImportExcelToMgOrderHandlerUpdate) // 通过excel导入订单退订数据
}
}

View File

@ -5046,6 +5046,14 @@ const docTemplateadmin = `{
"description": "当日新用户退订率",
"type": "string"
},
"new_user_unsub_within_24h": {
"description": "当日新用户24小时退订数",
"type": "integer"
},
"new_user_unsub_within_24h_rate": {
"description": "当日新用户24小时退订率",
"type": "string"
},
"new_user_unsub_within_hour": {
"description": "当日新用户退订数1小时以内",
"type": "integer"
@ -5677,6 +5685,10 @@ const docTemplateadmin = `{
"description": "查询结束时间",
"type": "string"
},
"is_export": {
"description": "1-导出",
"type": "integer"
},
"product_id": {
"description": "产品ID",
"type": "integer"
@ -5919,6 +5931,10 @@ const docTemplateadmin = `{
"description": "结束时间",
"type": "string"
},
"is_export": {
"description": "1-导出",
"type": "integer"
},
"page_num": {
"description": "页码",
"type": "integer"

View File

@ -5038,6 +5038,14 @@
"description": "当日新用户退订率",
"type": "string"
},
"new_user_unsub_within_24h": {
"description": "当日新用户24小时退订数",
"type": "integer"
},
"new_user_unsub_within_24h_rate": {
"description": "当日新用户24小时退订率",
"type": "string"
},
"new_user_unsub_within_hour": {
"description": "当日新用户退订数1小时以内",
"type": "integer"
@ -5669,6 +5677,10 @@
"description": "查询结束时间",
"type": "string"
},
"is_export": {
"description": "1-导出",
"type": "integer"
},
"product_id": {
"description": "产品ID",
"type": "integer"
@ -5911,6 +5923,10 @@
"description": "结束时间",
"type": "string"
},
"is_export": {
"description": "1-导出",
"type": "integer"
},
"page_num": {
"description": "页码",
"type": "integer"

View File

@ -1138,6 +1138,12 @@ definitions:
new_user_unsub_on_day_rate:
description: 当日新用户退订率
type: string
new_user_unsub_within_24h:
description: 当日新用户24小时退订数
type: integer
new_user_unsub_within_24h_rate:
description: 当日新用户24小时退订率
type: string
new_user_unsub_within_hour:
description: 当日新用户退订数1小时以内
type: integer
@ -1589,6 +1595,9 @@ definitions:
end_time:
description: 查询结束时间
type: string
is_export:
description: 1-导出
type: integer
product_id:
description: 产品ID
type: integer
@ -1758,6 +1767,9 @@ definitions:
end_time:
description: 结束时间
type: string
is_export:
description: 1-导出
type: integer
page_num:
description: 页码
type: integer