feat: 增加竞品报告刷数据接口

This commit is contained in:
cjy 2026-03-11 09:52:18 +08:00
parent 1ac5d17915
commit 3f76eb590d
5 changed files with 1214 additions and 671 deletions

File diff suppressed because it is too large Load Diff

View File

@ -26233,6 +26233,224 @@ var _ interface {
ErrorName() string
} = GetArtistWorkStatsRespValidationError{}
// Validate checks the field values on ImportCompetitiveReportHistoryReq with
// the rules defined in the proto definition for this message. If any rules
// are violated, the first error encountered is returned, or nil if there are
// no violations.
func (m *ImportCompetitiveReportHistoryReq) Validate() error {
return m.validate(false)
}
// ValidateAll checks the field values on ImportCompetitiveReportHistoryReq
// with the rules defined in the proto definition for this message. If any
// rules are violated, the result is a list of violation errors wrapped in
// ImportCompetitiveReportHistoryReqMultiError, or nil if none found.
func (m *ImportCompetitiveReportHistoryReq) ValidateAll() error {
return m.validate(true)
}
func (m *ImportCompetitiveReportHistoryReq) validate(all bool) error {
if m == nil {
return nil
}
var errors []error
// no validation rules for ReportUuid
// no validation rules for SubmitTime
// no validation rules for Title
if len(errors) > 0 {
return ImportCompetitiveReportHistoryReqMultiError(errors)
}
return nil
}
// ImportCompetitiveReportHistoryReqMultiError is an error wrapping multiple
// validation errors returned by
// ImportCompetitiveReportHistoryReq.ValidateAll() if the designated
// constraints aren't met.
type ImportCompetitiveReportHistoryReqMultiError []error
// Error returns a concatenation of all the error messages it wraps.
func (m ImportCompetitiveReportHistoryReqMultiError) Error() string {
var msgs []string
for _, err := range m {
msgs = append(msgs, err.Error())
}
return strings.Join(msgs, "; ")
}
// AllErrors returns a list of validation violation errors.
func (m ImportCompetitiveReportHistoryReqMultiError) AllErrors() []error { return m }
// ImportCompetitiveReportHistoryReqValidationError is the validation error
// returned by ImportCompetitiveReportHistoryReq.Validate if the designated
// constraints aren't met.
type ImportCompetitiveReportHistoryReqValidationError struct {
field string
reason string
cause error
key bool
}
// Field function returns field value.
func (e ImportCompetitiveReportHistoryReqValidationError) Field() string { return e.field }
// Reason function returns reason value.
func (e ImportCompetitiveReportHistoryReqValidationError) Reason() string { return e.reason }
// Cause function returns cause value.
func (e ImportCompetitiveReportHistoryReqValidationError) Cause() error { return e.cause }
// Key function returns key value.
func (e ImportCompetitiveReportHistoryReqValidationError) Key() bool { return e.key }
// ErrorName returns error name.
func (e ImportCompetitiveReportHistoryReqValidationError) ErrorName() string {
return "ImportCompetitiveReportHistoryReqValidationError"
}
// Error satisfies the builtin error interface
func (e ImportCompetitiveReportHistoryReqValidationError) Error() string {
cause := ""
if e.cause != nil {
cause = fmt.Sprintf(" | caused by: %v", e.cause)
}
key := ""
if e.key {
key = "key for "
}
return fmt.Sprintf(
"invalid %sImportCompetitiveReportHistoryReq.%s: %s%s",
key,
e.field,
e.reason,
cause)
}
var _ error = ImportCompetitiveReportHistoryReqValidationError{}
var _ interface {
Field() string
Reason() string
Key() bool
Cause() error
ErrorName() string
} = ImportCompetitiveReportHistoryReqValidationError{}
// Validate checks the field values on ImportCompetitiveReportHistoryResp with
// the rules defined in the proto definition for this message. If any rules
// are violated, the first error encountered is returned, or nil if there are
// no violations.
func (m *ImportCompetitiveReportHistoryResp) Validate() error {
return m.validate(false)
}
// ValidateAll checks the field values on ImportCompetitiveReportHistoryResp
// with the rules defined in the proto definition for this message. If any
// rules are violated, the result is a list of violation errors wrapped in
// ImportCompetitiveReportHistoryRespMultiError, or nil if none found.
func (m *ImportCompetitiveReportHistoryResp) ValidateAll() error {
return m.validate(true)
}
func (m *ImportCompetitiveReportHistoryResp) validate(all bool) error {
if m == nil {
return nil
}
var errors []error
// no validation rules for ReportUuid
if len(errors) > 0 {
return ImportCompetitiveReportHistoryRespMultiError(errors)
}
return nil
}
// ImportCompetitiveReportHistoryRespMultiError is an error wrapping multiple
// validation errors returned by
// ImportCompetitiveReportHistoryResp.ValidateAll() if the designated
// constraints aren't met.
type ImportCompetitiveReportHistoryRespMultiError []error
// Error returns a concatenation of all the error messages it wraps.
func (m ImportCompetitiveReportHistoryRespMultiError) Error() string {
var msgs []string
for _, err := range m {
msgs = append(msgs, err.Error())
}
return strings.Join(msgs, "; ")
}
// AllErrors returns a list of validation violation errors.
func (m ImportCompetitiveReportHistoryRespMultiError) AllErrors() []error { return m }
// ImportCompetitiveReportHistoryRespValidationError is the validation error
// returned by ImportCompetitiveReportHistoryResp.Validate if the designated
// constraints aren't met.
type ImportCompetitiveReportHistoryRespValidationError struct {
field string
reason string
cause error
key bool
}
// Field function returns field value.
func (e ImportCompetitiveReportHistoryRespValidationError) Field() string { return e.field }
// Reason function returns reason value.
func (e ImportCompetitiveReportHistoryRespValidationError) Reason() string { return e.reason }
// Cause function returns cause value.
func (e ImportCompetitiveReportHistoryRespValidationError) Cause() error { return e.cause }
// Key function returns key value.
func (e ImportCompetitiveReportHistoryRespValidationError) Key() bool { return e.key }
// ErrorName returns error name.
func (e ImportCompetitiveReportHistoryRespValidationError) ErrorName() string {
return "ImportCompetitiveReportHistoryRespValidationError"
}
// Error satisfies the builtin error interface
func (e ImportCompetitiveReportHistoryRespValidationError) Error() string {
cause := ""
if e.cause != nil {
cause = fmt.Sprintf(" | caused by: %v", e.cause)
}
key := ""
if e.key {
key = "key for "
}
return fmt.Sprintf(
"invalid %sImportCompetitiveReportHistoryResp.%s: %s%s",
key,
e.field,
e.reason,
cause)
}
var _ error = ImportCompetitiveReportHistoryRespValidationError{}
var _ interface {
Field() string
Reason() string
Key() bool
Cause() error
ErrorName() string
} = ImportCompetitiveReportHistoryRespValidationError{}
// Validate checks the field values on WorkListResp_Info with the rules defined
// in the proto definition for this message. If any rules are violated, the
// first error encountered is returned, or nil if there are no violations.

View File

@ -138,6 +138,7 @@ type CastClient interface {
DeleteCompetitiveReport(ctx context.Context, in *DeleteCompetitiveReportReq, opts ...grpc_go.CallOption) (*emptypb.Empty, common.ErrorWithAttachment)
UpdateCompetitiveReportApprovalID(ctx context.Context, in *UpdateCompetitiveReportApprovalIDReq, opts ...grpc_go.CallOption) (*emptypb.Empty, common.ErrorWithAttachment)
CountCompetitiveReportByWorkUuids(ctx context.Context, in *CountCompetitiveReportByWorkUuidsReq, opts ...grpc_go.CallOption) (*CountCompetitiveReportByWorkUuidsResp, common.ErrorWithAttachment)
ImportCompetitiveReportHistory(ctx context.Context, in *ImportCompetitiveReportHistoryReq, opts ...grpc_go.CallOption) (*ImportCompetitiveReportHistoryResp, common.ErrorWithAttachment)
// 发布记录相关接口
ListPublishLog(ctx context.Context, in *ListPublishLogReq, opts ...grpc_go.CallOption) (*ListPublishLogResp, common.ErrorWithAttachment)
// 艺人作品统计快照接口
@ -243,6 +244,7 @@ type CastClientImpl struct {
DeleteCompetitiveReport func(ctx context.Context, in *DeleteCompetitiveReportReq) (*emptypb.Empty, error)
UpdateCompetitiveReportApprovalID func(ctx context.Context, in *UpdateCompetitiveReportApprovalIDReq) (*emptypb.Empty, error)
CountCompetitiveReportByWorkUuids func(ctx context.Context, in *CountCompetitiveReportByWorkUuidsReq) (*CountCompetitiveReportByWorkUuidsResp, error)
ImportCompetitiveReportHistory func(ctx context.Context, in *ImportCompetitiveReportHistoryReq) (*ImportCompetitiveReportHistoryResp, error)
ListPublishLog func(ctx context.Context, in *ListPublishLogReq) (*ListPublishLogResp, error)
GetArtistWorkStats func(ctx context.Context, in *GetArtistWorkStatsReq) (*GetArtistWorkStatsResp, error)
}
@ -823,6 +825,12 @@ func (c *castClient) CountCompetitiveReportByWorkUuids(ctx context.Context, in *
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/CountCompetitiveReportByWorkUuids", in, out)
}
func (c *castClient) ImportCompetitiveReportHistory(ctx context.Context, in *ImportCompetitiveReportHistoryReq, opts ...grpc_go.CallOption) (*ImportCompetitiveReportHistoryResp, common.ErrorWithAttachment) {
out := new(ImportCompetitiveReportHistoryResp)
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/ImportCompetitiveReportHistory", in, out)
}
func (c *castClient) ListPublishLog(ctx context.Context, in *ListPublishLogReq, opts ...grpc_go.CallOption) (*ListPublishLogResp, common.ErrorWithAttachment) {
out := new(ListPublishLogResp)
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
@ -948,6 +956,7 @@ type CastServer interface {
DeleteCompetitiveReport(context.Context, *DeleteCompetitiveReportReq) (*emptypb.Empty, error)
UpdateCompetitiveReportApprovalID(context.Context, *UpdateCompetitiveReportApprovalIDReq) (*emptypb.Empty, error)
CountCompetitiveReportByWorkUuids(context.Context, *CountCompetitiveReportByWorkUuidsReq) (*CountCompetitiveReportByWorkUuidsResp, error)
ImportCompetitiveReportHistory(context.Context, *ImportCompetitiveReportHistoryReq) (*ImportCompetitiveReportHistoryResp, error)
// 发布记录相关接口
ListPublishLog(context.Context, *ListPublishLogReq) (*ListPublishLogResp, error)
// 艺人作品统计快照接口
@ -1242,6 +1251,9 @@ func (UnimplementedCastServer) UpdateCompetitiveReportApprovalID(context.Context
func (UnimplementedCastServer) CountCompetitiveReportByWorkUuids(context.Context, *CountCompetitiveReportByWorkUuidsReq) (*CountCompetitiveReportByWorkUuidsResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method CountCompetitiveReportByWorkUuids not implemented")
}
func (UnimplementedCastServer) ImportCompetitiveReportHistory(context.Context, *ImportCompetitiveReportHistoryReq) (*ImportCompetitiveReportHistoryResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method ImportCompetitiveReportHistory not implemented")
}
func (UnimplementedCastServer) ListPublishLog(context.Context, *ListPublishLogReq) (*ListPublishLogResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListPublishLog not implemented")
}
@ -4002,6 +4014,35 @@ func _Cast_CountCompetitiveReportByWorkUuids_Handler(srv interface{}, ctx contex
return interceptor(ctx, in, info, handler)
}
func _Cast_ImportCompetitiveReportHistory_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(ImportCompetitiveReportHistoryReq)
if err := dec(in); err != nil {
return nil, err
}
base := srv.(dubbo3.Dubbo3GrpcService)
args := []interface{}{}
args = append(args, in)
md, _ := metadata.FromIncomingContext(ctx)
invAttachment := make(map[string]interface{}, len(md))
for k, v := range md {
invAttachment[k] = v
}
invo := invocation.NewRPCInvocation("ImportCompetitiveReportHistory", args, invAttachment)
if interceptor == nil {
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
return result, result.Error()
}
info := &grpc_go.UnaryServerInfo{
Server: srv,
FullMethod: ctx.Value("XXX_TRIPLE_GO_INTERFACE_NAME").(string),
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
return result, result.Error()
}
return interceptor(ctx, in, info, handler)
}
func _Cast_ListPublishLog_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(ListPublishLogReq)
if err := dec(in); err != nil {
@ -4443,6 +4484,10 @@ var Cast_ServiceDesc = grpc_go.ServiceDesc{
MethodName: "CountCompetitiveReportByWorkUuids",
Handler: _Cast_CountCompetitiveReportByWorkUuids_Handler,
},
{
MethodName: "ImportCompetitiveReportHistory",
Handler: _Cast_ImportCompetitiveReportHistory_Handler,
},
{
MethodName: "ListPublishLog",
Handler: _Cast_ListPublishLog_Handler,

View File

@ -54,6 +54,9 @@ func AnalysisRouter(r *gin.RouterGroup) {
competitiveReport.POST("export-list", serviceCast.ListCompetitiveReportExport) // 竞品报告列表导出
competitiveReport.POST("export-single-list", serviceCast.ListCompetitiveReportSingleExport) // 竞品报告单个列表导出
competitiveReport.POST("import-pdf-batch", serviceCast.ImportPdfBatch) // 批量导入PDF下载、重命名、上传
// 刷竞品报告专用的导入接口
competitiveReport.POST("import-history-batch", serviceCast.ImportCompetitiveReportHistoryBatch) // Excel 批量刷写竞品报告历史数据
}
// 员工任务相关路由需要App登录验证

View File

@ -1,6 +1,7 @@
package cast
import (
"bytes"
"context"
"errors"
"fmt"
@ -1489,6 +1490,122 @@ func ImportPdfBatch(ctx *gin.Context) {
return
}
// ImportCompetitiveReportHistoryBatch 通过 Excel 批量刷写竞品报告历史数据
// Excel 列顺序ReportUuid | Title可为空| SubmitTime | 结果(空,由接口写入)
func ImportCompetitiveReportHistoryBatch(ctx *gin.Context) {
excelFile, err := ctx.FormFile("file")
if err != nil {
service.Error(ctx, err)
return
}
loginInfo := login.GetUserInfoFromC(ctx)
lockKey := fmt.Sprintf("import_competitive_report_history_batch:%d", loginInfo.ID)
replay := cache.RedisClient.SetNX(lockKey, time.Now().Format("20060102150405"), 5*time.Minute)
if !replay.Val() {
service.Error(ctx, errors.New("有导入任务正在进行,请稍后再试"))
return
}
defer cache.RedisClient.Del(lockKey)
tempDir := "./runtime/report_pdf"
_, err = utils.CheckDirPath(tempDir, true)
if err != nil {
service.Error(ctx, err)
return
}
fileName := fmt.Sprintf("%d_competitive_report_history.xlsx", time.Now().UnixMicro())
excelPath := filepath.Join(tempDir, fileName)
if err = ctx.SaveUploadedFile(excelFile, excelPath); err != nil {
service.Error(ctx, err)
return
}
excelData, err := excelize.OpenFile(excelPath)
if err != nil {
service.Error(ctx, err)
return
}
defer excelData.Close()
rows, err := excelData.GetRows("Sheet1")
if err != nil {
service.Error(ctx, err)
return
}
newCtx := NewCtxWithUserInfo(ctx)
// 写入表头(第 4 列)
_ = excelData.SetCellValue("Sheet1", "D1", "结果")
successCount := 0
for line, row := range rows {
if line == 0 {
continue // 跳过表头
}
if len(row) == 0 {
continue
}
// Excel 行号1-basedline=1 → 行号 2
cellD := fmt.Sprintf("D%d", line+1)
// 第一列ReportUuid
reportUuid := ""
if len(row) > 0 {
reportUuid = strings.TrimSpace(row[0])
}
if reportUuid == "" {
_ = excelData.SetCellValue("Sheet1", cellD, "ReportUuid 不能为空")
continue
}
// 第二列Title可为空
title := ""
if len(row) > 1 {
title = strings.TrimSpace(row[1])
}
// 第三列SubmitTime
submitTime := ""
if len(row) > 2 {
submitTime = strings.TrimSpace(row[2])
}
// 构造请求
importReq := &cast.ImportCompetitiveReportHistoryReq{
ReportUuid: reportUuid,
SubmitTime: submitTime,
}
if title != "" {
importReq.Title = title
}
importResp, err := service.CastProvider.ImportCompetitiveReportHistory(newCtx, importReq)
if err != nil {
zap.L().Error("ImportCompetitiveReportHistoryBatch ImportCompetitiveReportHistory",
zap.Error(err), zap.String("reportUuid", reportUuid))
_ = excelData.SetCellValue("Sheet1", cellD, fmt.Sprintf("导入失败:%s", err.Error()))
continue
}
// 导入成功,将返回的 report_uuid 写入第 4 列
_ = excelData.SetCellValue("Sheet1", cellD, importResp.ReportUuid)
successCount++
}
// 将修改后的 Excel 写入 buffer 并返回给客户端下载
buf, err := excelData.WriteToBuffer()
if err != nil {
service.Error(ctx, err)
return
}
utils.ResponseXls(ctx, bytes.NewReader(buf.Bytes()), fmt.Sprintf("竞品报告历史导入结果_%d成功", successCount))
}
// truncateCompetitorReportData 截断竞品报告数据中超长的字段
// 字段长度要求参考 AI 生成竞品报告的限制
func truncateCompetitorReportData(data utils.CompetitorReportData) utils.CompetitorReportData {