package bundle import ( "context" "encoding/json" "errors" "fmt" "fonchain-fiee/api/bundle" "fonchain-fiee/api/cast" "fonchain-fiee/pkg/service" "fonchain-fiee/pkg/utils" "io" "log" "strconv" "strings" "time" bundleModel "fonchain-fiee/pkg/model/bundle" "fonchain-fiee/pkg/model/login" "github.com/gin-gonic/gin" "github.com/xuri/excelize/v2" ) func BundleExtend(c *gin.Context) { var req bundle.BundleExtendRequest userInfo := login.GetUserInfoFromC(c) req.Type = 1 // 设置未手动扩展' req.OperatorName = userInfo.Name req.OperatorPhoneNumber = userInfo.TelNum req.OperatorId = userInfo.ID if err := c.ShouldBindJSON(&req); err != nil { service.Error(c, err) return } res, err := service.BundleProvider.BundleExtend(context.Background(), &req) if err != nil { service.Error(c, err) return } service.Success(c, res) } func BundleExtendRecordsList(c *gin.Context) { var req bundle.BundleExtendRecordsListRequest if err := c.ShouldBindJSON(&req); err != nil { service.Error(c, err) return } res, err := service.BundleProvider.BundleExtendRecordsList(context.Background(), &req) if err != nil { service.Error(c, err) return } service.Success(c, res) } func GetBundleBalance(c *gin.Context) { var req bundle.GetBundleBalanceListReq if err := c.ShouldBindJSON(&req); err != nil { service.Error(c, err) return } res, err := service.BundleProvider.GetBundleBalanceList(context.Background(), &req) if err != nil { service.Error(c, err) return } service.Success(c, res) } func GetUsedRecordList(c *gin.Context) { var req bundle.GetUsedRecordListReq if err := c.ShouldBindJSON(&req); err != nil { service.Error(c, err) return } res, err := service.BundleProvider.GetUsedRecordList(context.Background(), &req) if err != nil { service.Error(c, err) return } service.Success(c, res) } func GetWorkDetail(c *gin.Context) { var req cast.WorkDetailReq if err := c.ShouldBindJSON(&req); err != nil { service.Error(c, err) return } // userInfo := login.GetUserInfoFromC(c) // res, err := service.BundleProvider.GetBundleBalanceByUserId(context.TODO(), &bundle.GetBundleBalanceByUserIdReq{ // UserId: int32(userInfo.ID), // }) // if err != nil { // service.Error(c, err) // return // } // if res.ExpiredTime <= time.Now().UnixMilli() { // service.Success(c, gin.H{ // "status": 1, // "message": "套餐过期请重新购买", // }) // return // } workRes, err := service.CastProvider.WorkDetail(context.Background(), &req) if err != nil { service.Error(c, err) return } // if len(workRes.Images) > 0 && res.ImageConsumptionNumber >= res.ImageNumber { // 图片用尽 // service.Success(c, gin.H{ // "status": 2, // "message": "增值服务已用尽", // }) // return // } else { // if res.VideoConsumptionNumber >= res.VideoNumber { // 视频用尽 // service.Success(c, gin.H{ // "status": 2, // "message": "增值服务已用尽", // }) // return // } // } service.Success(c, workRes) } func GetToBeComfirmedWorks(c *gin.Context) { var req bundle.ToBeComfirmedWorksReq if err := c.ShouldBindJSON(&req); err != nil { service.Error(c, err) return } userInfo := login.GetUserInfoFromC(c) req.ArtistUuid = strconv.Itoa(int(userInfo.ID)) res, err := service.BundleProvider.ToBeComfirmedWorks(context.Background(), &req) if err != nil { service.Error(c, err) return } service.Success(c, res) } func GetUserBalance(c *gin.Context) { userInfo := login.GetUserInfoFromC(c) res, err := service.BundleProvider.GetBundleBalanceByUserId(context.Background(), &bundle.GetBundleBalanceByUserIdReq{ UserId: int32(userInfo.ID), }) if err != nil { service.Error(c, err) return } service.Success(c, res) } func WorkConfirm(c *gin.Context) { // 确认作品并扣除余量 var req bundleModel.UserWorkConfirmReq if err := c.ShouldBindJSON(&req); err != nil { service.Error(c, err) return } log.Print("req.ConfirmRemark:", req.ConfirmRemark) if req.ConfirmStatus == 2 { // 驳回完直接结束 res, err := service.CastProvider.UpdateStatus(c, &cast.UpdateStatusReq{ WorkAction: cast.WorkActionENUM_CONFIRM, WorkUuid: req.WorkUuid, ConfirmRemark: req.ConfirmRemark, ConfirmStatus: 2, }) if err != nil { service.Error(c, err) return } service.Success(c, res) return } userInfo := login.GetUserInfoFromC(c) balanceInfoRes, err := service.BundleProvider.GetBundleBalanceByUserId(context.Background(), &bundle.GetBundleBalanceByUserIdReq{ UserId: int32(userInfo.ID), }) if err != nil { service.Error(c, err) return } wordInfoRes, err := service.CastProvider.WorkDetail(c, &cast.WorkDetailReq{ WorkUuid: req.WorkUuid, }) if err != nil { service.Error(c, err) return } if wordInfoRes.WorkStatus != 4 { service.Error(c, errors.New("作品不是待确认状态")) return } var workCategory = wordInfoRes.WorkCategory var addBalanceReq bundle.AddBundleBalanceReq addBalanceReq.UserId = int32(userInfo.ID) switch workCategory { case 1: { if balanceInfoRes.ImageConsumptionNumber >= balanceInfoRes.ImageNumber { // 图文余量不足 service.Error(c, errors.New("图文余量不足")) return } addBalanceReq.ImageConsumptionNumber = 1 } case 2: { if balanceInfoRes.VideoConsumptionNumber >= balanceInfoRes.VideoNumber { // 视频余量不足 service.Error(c, errors.New("视频余量不足")) return } addBalanceReq.VideoConsumptionNumber = 1 } default: service.Error(c, errors.New("不支持的类型")) return } _, err = service.BundleProvider.AddBundleBalance(c, &addBalanceReq) if err != nil { service.Error(c, err) return } res, err := service.CastProvider.UpdateStatus(c, &cast.UpdateStatusReq{ WorkAction: cast.WorkActionENUM_CONFIRM, WorkUuid: req.WorkUuid, ConfirmRemark: req.ConfirmRemark, ConfirmStatus: 1, }) if err != nil { service.Error(c, err) return } service.Success(c, res) } func CastLogConfirm(ctx *gin.Context) { var req bundle.ConfirmWorkReq if err := ctx.ShouldBindJSON(&req); err != nil { service.Error(ctx, err) return } res, err := service.BundleProvider.ConfirmWork(context.Background(), &req) if err != nil { service.Error(ctx, err) return } service.Success(ctx, res) } func BundleActivate(ctx *gin.Context) { var req bundle.BundleActivateReq if err := ctx.ShouldBindJSON(&req); err != nil { service.Error(ctx, err) return } res, err := service.BundleProvider.BundleActivate(context.Background(), &req) if err != nil { service.Error(ctx, err) return } service.Success(ctx, res) } func BundleExport(ctx *gin.Context) { var req bundle.BundleBalanceExportReq if err := ctx.ShouldBindJSON(&req); err != nil { service.Error(ctx, err) return } userInfo := login.GetUserInfoFromC(ctx) exportFileName := fmt.Sprintf("%d月份余量信息.xlsx", time.Now().Month()) filePath := fmt.Sprintf("./runtime/%d/%s", userInfo.ID, exportFileName) utils.CheckDirPath("./runtime/"+fmt.Sprint(userInfo.ID), true) res, err := service.BundleProvider.BundleBalanceExport(context.Background(), &req) if err != nil { service.Error(ctx, err) return } if err := writeToExcel(filePath, res.Data); err != nil { service.Error(ctx, err) return } var scheme string if ctx.GetHeader("X-Forwarded-Proto") == "https" { scheme = "https" } else { scheme = "http" } var exportUrl string = fmt.Sprintf("%s:%s/api/fiee/static/%s", scheme, ctx.Request.Host, strings.Replace(filePath, "./runtime/", "", 1)) service.Success(ctx, gin.H{ "url": exportUrl, }) } func SetBalanceLayout(ctx *gin.Context) { b, _ := io.ReadAll(ctx.Request.Body) userInfo := login.GetUserInfoFromC(ctx) var req = bundle.SetBundleBalanceLayoutReq{ Data: string(b), UserId: uint32(userInfo.ID), } res, err := service.BundleProvider.SetBundleBalanceLayout(context.Background(), &req) if err != nil { service.Error(ctx, err) return } service.Success(ctx, res) } func GetBalanceLayout(ctx *gin.Context) { userInfo := login.GetUserInfoFromC(ctx) var req = bundle.GetBundleBalanceLayoutReq{ UserId: uint32(userInfo.ID), } res, err := service.BundleProvider.GetBundleBalanceLayout(context.Background(), &req) if err != nil { service.Error(ctx, err) return } var j any json.Unmarshal([]byte(res.Data), &j) service.Success(ctx, j) } func writeToExcel(filename string, items []*bundle.BundleBalanceExportItem) error { f := excelize.NewFile() sheet := "Sheet1" // 手动表头(顺序与写入字段顺序必须一致) headers := []string{ "所属月份", "用户编号", "名字", "手机号", "支付时间", "套餐金额", "增值服务金额", "支付金额", "币种", "手续费", "套餐视频单价", "增值视频单价", "套餐账号总数", "增值账号总数", "套餐账号使用数", "增值账号使用数", "当前可用套餐视频数", "当前可用增值视频数", "当前已用套餐视频数", "当前已用增值视频数", "当前作废套餐视频数", "当前作废增值视频数", "当月新增套餐视频数", "当月新增增值视频数", "当月作废套餐视频数", "当月作废增值视频数", "当前可用套餐图文数", "当前可用增值图文数", "当前已用套餐图文数", "当前已用增值图文数", "当前作废套餐图文数", "当前作废增值图文数", "当月新增套餐图文数", "当月新增增值图文数", "当月作废套餐图文数", "当月作废增值图文数", "当前可用套餐数据分析数", "当前可用增值数据分析数", "当前已用套餐数据分析数", "当前已用增值数据分析数", "当前作废套餐数据分析数", "当前作废增值数据分析数", "当月新增套餐数据分析数", "当月新增增值数据分析数", "当月作废套餐数据分析数", "当月作废增值数据分析数", "当月手动扩展账号新增数", "当月手动扩展视频新增数", "当月手动扩展图文新增数", "当月手动扩展数据分析新增数", "当月新增手动扩展时长(天)", "当月手动扩展账号使用数", "当月手动扩展视频使用数", "当月手动扩展图文使用数", "当月手动扩展数据分析使用数", } // 写表头 for i, h := range headers { col, _ := excelize.ColumnNumberToName(i + 1) cell := col + "1" if err := f.SetCellValue(sheet, cell, h); err != nil { return err } } // 从第2行开始写数据 for r, it := range items { row := r + 2 // 逐列写入(注意顺序必须和 headers 一致) write := func(colIdx int, v interface{}) error { col, _ := excelize.ColumnNumberToName(colIdx) cell := fmt.Sprintf("%s%d", col, row) return f.SetCellValue(sheet, cell, v) } // 基本信息 _ = write(1, it.Month) _ = write(2, it.CustomerNum) _ = write(3, it.UserName) _ = write(4, it.UserPhoneNumber) _ = write(5, it.PayTime) _ = write(6, float64(it.BundleAmount)) _ = write(7, float64(it.IncreaseAmount)) _ = write(8, float64(it.TotalPayAmount)) _ = write(9, it.Currency) _ = write(10, it.Fee) _ = write(11, float64(it.BundleVideoUnitPrice)) _ = write(12, float64(it.IncreaseVideoUnitPrice)) // 账号类 _ = write(13, int(it.BundleAccountNumber)) _ = write(14, int(it.IncreaseAccountNumber)) _ = write(15, int(it.BundleAccountConsumptionNumber)) _ = write(16, int(it.IncreaseAccountConsumptionNumber)) // 视频类 _ = write(17, int(it.BundleVideoNumber)) _ = write(18, int(it.IncreaseVideoNumber)) _ = write(19, int(it.BundleVideoConsumptionNumber)) _ = write(20, int(it.IncreaseVideoConsumptionNumber)) _ = write(21, int(it.InvalidBundleVideoNumber)) _ = write(22, int(it.InvalidIncreaseVideoNumber)) _ = write(23, int(it.MonthlyNewBundleVideoNumber)) _ = write(24, int(it.MonthlyNewIncreaseVideoNumber)) _ = write(25, int(it.MonthlyInvalidBundleVideoNumber)) _ = write(26, int(it.MonthlyInvalidIncreaseVideoNumber)) // 图文类 _ = write(27, int(it.BundleImageNumber)) _ = write(28, int(it.IncreaseImageNumber)) _ = write(29, int(it.BundleImageConsumptionNumber)) _ = write(30, int(it.IncreaseImageConsumptionNumber)) _ = write(31, int(it.InvalidBundleImageNumber)) _ = write(32, int(it.InvalidIncreaseImageNumber)) _ = write(33, int(it.MonthlyNewBundleImageNumber)) _ = write(34, int(it.MonthlyNewIncreaseImageNumber)) _ = write(35, int(it.MonthlyInvalidBundleImageNumber)) _ = write(36, int(it.MonthlyInvalidIncreaseImageNumber)) // 数据分析类 _ = write(37, int(it.BundleDataAnalysisNumber)) _ = write(38, int(it.IncreaseDataAnalysisNumber)) _ = write(39, int(it.BundleDataAnalysisConsumptionNumber)) _ = write(40, int(it.IncreaseDataAnalysisConsumptionNumber)) _ = write(41, int(it.InvalidBundleDataAnalysisNumber)) _ = write(42, int(it.InvalidIncreaseDataAnalysisNumber)) _ = write(43, int(it.MonthlyNewBundleDataAnalysisNumber)) _ = write(44, int(it.MonthlyNewIncreaseDataAnalysisNumber)) _ = write(45, int(it.MonthlyInvalidBundleDataAnalysisNumber)) _ = write(46, int(it.MonthlyInvalidIncreaseDataAnalysisNumber)) // 手动扩展类 _ = write(47, int(it.MonthlyNewManualAccountNumber)) _ = write(48, int(it.MonthlyNewManualVideoNumber)) _ = write(49, int(it.MonthlyNewManualImageNumber)) _ = write(50, int(it.MonthlyNewManualDataAnalysisNumber)) _ = write(51, int(it.MonthlyNewDurationNumber)) _ = write(52, int(it.MonthlyManualAccountConsumptionNumber)) _ = write(53, int(it.MonthlyManualVideoConsumptionNumber)) _ = write(54, int(it.MonthlyManualImageConsumptionNumber)) _ = write(55, int(it.MonthlyManualDataAnalysisConsumptionNumber)) } // 可选:设置列宽,使表格更美观 _ = f.SetColWidth(sheet, "A", "AZ", 15) // 保存文件 if err := f.SaveAs(filename); err != nil { return err } return nil }