Compare commits

..

1 Commits

Author SHA1 Message Date
06104d9f2f fix: 创建返回antomid 2026-02-27 09:26:51 +08:00
42 changed files with 5185 additions and 11973 deletions

2
.gitignore vendored
View File

@ -31,5 +31,3 @@
/cmd/logs/*.log /cmd/logs/*.log
/cmd/runtime/log/*.log /cmd/runtime/log/*.log
/build/* /build/*
CLAUDE.md
.claude/settings.local.json

File diff suppressed because it is too large Load Diff

View File

@ -1096,61 +1096,3 @@ func (this *UpdataInvoiceInfoReq) Validate() error {
func (this *UpdataInvoiceInfoResp) Validate() error { func (this *UpdataInvoiceInfoResp) Validate() error {
return nil return nil
} }
func (this *SendQuestionnaireSurveyRequest) Validate() error {
return nil
}
func (this *SendQuestionnaireSurveyResponse) Validate() error {
return nil
}
func (this *GetQuestionnaireSurveyInfoRequest) Validate() error {
return nil
}
func (this *SurveyBundleInfo) Validate() error {
return nil
}
func (this *GetQuestionnaireSurveyInfoResponse) Validate() error {
if this.BundleInfo != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.BundleInfo); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("BundleInfo", err)
}
}
return nil
}
func (this *SurveyAnswer) Validate() error {
return nil
}
func (this *SurveyFeedback) Validate() error {
return nil
}
func (this *CreateQuestionnaireSurveyAnswerRequest) Validate() error {
if this.SurveyAnswer != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.SurveyAnswer); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("SurveyAnswer", err)
}
}
if this.SurveyFeedback != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.SurveyFeedback); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("SurveyFeedback", err)
}
}
return nil
}
func (this *CreateQuestionnaireSurveyAnswerResponse) Validate() error {
return nil
}
func (this *GetQuestionnaireSurveyListRequest) Validate() error {
return nil
}
func (this *SurveyListInfo) Validate() error {
return nil
}
func (this *GetQuestionnaireSurveyListResponse) Validate() error {
for _, item := range this.SurveyList {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("SurveyList", err)
}
}
}
return nil
}

View File

@ -1,7 +1,7 @@
// Code generated by protoc-gen-go-triple. DO NOT EDIT. // Code generated by protoc-gen-go-triple. DO NOT EDIT.
// versions: // versions:
// - protoc-gen-go-triple v1.0.5 // - protoc-gen-go-triple v1.0.8
// - protoc v5.26.0 // - protoc v3.21.1
// source: pb/bundle.proto // source: pb/bundle.proto
package bundle package bundle
@ -147,11 +147,6 @@ type BundleClient interface {
GetPaymentCyclesByContractUUID(ctx context.Context, in *GetPaymentCyclesByContractUUIDRequest, opts ...grpc_go.CallOption) (*GetPaymentCyclesByContractUUIDResponse, common.ErrorWithAttachment) GetPaymentCyclesByContractUUID(ctx context.Context, in *GetPaymentCyclesByContractUUIDRequest, opts ...grpc_go.CallOption) (*GetPaymentCyclesByContractUUIDResponse, common.ErrorWithAttachment)
UpdateOrderRecordByOrderUuid(ctx context.Context, in *OrderRecord, opts ...grpc_go.CallOption) (*CommonResponse, common.ErrorWithAttachment) UpdateOrderRecordByOrderUuid(ctx context.Context, in *OrderRecord, opts ...grpc_go.CallOption) (*CommonResponse, common.ErrorWithAttachment)
OrderListByOrderUuid(ctx context.Context, in *OrderInfoByOrderUuidRequest, opts ...grpc_go.CallOption) (*OrderInfoByOrderNoResp, common.ErrorWithAttachment) OrderListByOrderUuid(ctx context.Context, in *OrderInfoByOrderUuidRequest, opts ...grpc_go.CallOption) (*OrderInfoByOrderNoResp, common.ErrorWithAttachment)
// 问卷调查
SendQuestionnaireSurvey(ctx context.Context, in *SendQuestionnaireSurveyRequest, opts ...grpc_go.CallOption) (*SendQuestionnaireSurveyResponse, common.ErrorWithAttachment)
GetQuestionnaireSurveyInfo(ctx context.Context, in *GetQuestionnaireSurveyInfoRequest, opts ...grpc_go.CallOption) (*GetQuestionnaireSurveyInfoResponse, common.ErrorWithAttachment)
CreateQuestionnaireSurveyAnswer(ctx context.Context, in *CreateQuestionnaireSurveyAnswerRequest, opts ...grpc_go.CallOption) (*CreateQuestionnaireSurveyAnswerResponse, common.ErrorWithAttachment)
GetQuestionnaireSurveyList(ctx context.Context, in *GetQuestionnaireSurveyListRequest, opts ...grpc_go.CallOption) (*GetQuestionnaireSurveyListResponse, common.ErrorWithAttachment)
} }
type bundleClient struct { type bundleClient struct {
@ -266,10 +261,6 @@ type BundleClientImpl struct {
GetPaymentCyclesByContractUUID func(ctx context.Context, in *GetPaymentCyclesByContractUUIDRequest) (*GetPaymentCyclesByContractUUIDResponse, error) GetPaymentCyclesByContractUUID func(ctx context.Context, in *GetPaymentCyclesByContractUUIDRequest) (*GetPaymentCyclesByContractUUIDResponse, error)
UpdateOrderRecordByOrderUuid func(ctx context.Context, in *OrderRecord) (*CommonResponse, error) UpdateOrderRecordByOrderUuid func(ctx context.Context, in *OrderRecord) (*CommonResponse, error)
OrderListByOrderUuid func(ctx context.Context, in *OrderInfoByOrderUuidRequest) (*OrderInfoByOrderNoResp, error) OrderListByOrderUuid func(ctx context.Context, in *OrderInfoByOrderUuidRequest) (*OrderInfoByOrderNoResp, error)
SendQuestionnaireSurvey func(ctx context.Context, in *SendQuestionnaireSurveyRequest) (*SendQuestionnaireSurveyResponse, error)
GetQuestionnaireSurveyInfo func(ctx context.Context, in *GetQuestionnaireSurveyInfoRequest) (*GetQuestionnaireSurveyInfoResponse, error)
CreateQuestionnaireSurveyAnswer func(ctx context.Context, in *CreateQuestionnaireSurveyAnswerRequest) (*CreateQuestionnaireSurveyAnswerResponse, error)
GetQuestionnaireSurveyList func(ctx context.Context, in *GetQuestionnaireSurveyListRequest) (*GetQuestionnaireSurveyListResponse, error)
} }
func (c *BundleClientImpl) GetDubboStub(cc *triple.TripleConn) BundleClient { func (c *BundleClientImpl) GetDubboStub(cc *triple.TripleConn) BundleClient {
@ -926,30 +917,6 @@ func (c *bundleClient) OrderListByOrderUuid(ctx context.Context, in *OrderInfoBy
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/OrderListByOrderUuid", in, out) return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/OrderListByOrderUuid", in, out)
} }
func (c *bundleClient) SendQuestionnaireSurvey(ctx context.Context, in *SendQuestionnaireSurveyRequest, opts ...grpc_go.CallOption) (*SendQuestionnaireSurveyResponse, common.ErrorWithAttachment) {
out := new(SendQuestionnaireSurveyResponse)
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/SendQuestionnaireSurvey", in, out)
}
func (c *bundleClient) GetQuestionnaireSurveyInfo(ctx context.Context, in *GetQuestionnaireSurveyInfoRequest, opts ...grpc_go.CallOption) (*GetQuestionnaireSurveyInfoResponse, common.ErrorWithAttachment) {
out := new(GetQuestionnaireSurveyInfoResponse)
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/GetQuestionnaireSurveyInfo", in, out)
}
func (c *bundleClient) CreateQuestionnaireSurveyAnswer(ctx context.Context, in *CreateQuestionnaireSurveyAnswerRequest, opts ...grpc_go.CallOption) (*CreateQuestionnaireSurveyAnswerResponse, common.ErrorWithAttachment) {
out := new(CreateQuestionnaireSurveyAnswerResponse)
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/CreateQuestionnaireSurveyAnswer", in, out)
}
func (c *bundleClient) GetQuestionnaireSurveyList(ctx context.Context, in *GetQuestionnaireSurveyListRequest, opts ...grpc_go.CallOption) (*GetQuestionnaireSurveyListResponse, common.ErrorWithAttachment) {
out := new(GetQuestionnaireSurveyListResponse)
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/GetQuestionnaireSurveyList", in, out)
}
// BundleServer is the server API for Bundle service. // BundleServer is the server API for Bundle service.
// All implementations must embed UnimplementedBundleServer // All implementations must embed UnimplementedBundleServer
// for forward compatibility // for forward compatibility
@ -1073,11 +1040,6 @@ type BundleServer interface {
GetPaymentCyclesByContractUUID(context.Context, *GetPaymentCyclesByContractUUIDRequest) (*GetPaymentCyclesByContractUUIDResponse, error) GetPaymentCyclesByContractUUID(context.Context, *GetPaymentCyclesByContractUUIDRequest) (*GetPaymentCyclesByContractUUIDResponse, error)
UpdateOrderRecordByOrderUuid(context.Context, *OrderRecord) (*CommonResponse, error) UpdateOrderRecordByOrderUuid(context.Context, *OrderRecord) (*CommonResponse, error)
OrderListByOrderUuid(context.Context, *OrderInfoByOrderUuidRequest) (*OrderInfoByOrderNoResp, error) OrderListByOrderUuid(context.Context, *OrderInfoByOrderUuidRequest) (*OrderInfoByOrderNoResp, error)
// 问卷调查
SendQuestionnaireSurvey(context.Context, *SendQuestionnaireSurveyRequest) (*SendQuestionnaireSurveyResponse, error)
GetQuestionnaireSurveyInfo(context.Context, *GetQuestionnaireSurveyInfoRequest) (*GetQuestionnaireSurveyInfoResponse, error)
CreateQuestionnaireSurveyAnswer(context.Context, *CreateQuestionnaireSurveyAnswerRequest) (*CreateQuestionnaireSurveyAnswerResponse, error)
GetQuestionnaireSurveyList(context.Context, *GetQuestionnaireSurveyListRequest) (*GetQuestionnaireSurveyListResponse, error)
mustEmbedUnimplementedBundleServer() mustEmbedUnimplementedBundleServer()
} }
@ -1407,18 +1369,6 @@ func (UnimplementedBundleServer) UpdateOrderRecordByOrderUuid(context.Context, *
func (UnimplementedBundleServer) OrderListByOrderUuid(context.Context, *OrderInfoByOrderUuidRequest) (*OrderInfoByOrderNoResp, error) { func (UnimplementedBundleServer) OrderListByOrderUuid(context.Context, *OrderInfoByOrderUuidRequest) (*OrderInfoByOrderNoResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method OrderListByOrderUuid not implemented") return nil, status.Errorf(codes.Unimplemented, "method OrderListByOrderUuid not implemented")
} }
func (UnimplementedBundleServer) SendQuestionnaireSurvey(context.Context, *SendQuestionnaireSurveyRequest) (*SendQuestionnaireSurveyResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method SendQuestionnaireSurvey not implemented")
}
func (UnimplementedBundleServer) GetQuestionnaireSurveyInfo(context.Context, *GetQuestionnaireSurveyInfoRequest) (*GetQuestionnaireSurveyInfoResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetQuestionnaireSurveyInfo not implemented")
}
func (UnimplementedBundleServer) CreateQuestionnaireSurveyAnswer(context.Context, *CreateQuestionnaireSurveyAnswerRequest) (*CreateQuestionnaireSurveyAnswerResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateQuestionnaireSurveyAnswer not implemented")
}
func (UnimplementedBundleServer) GetQuestionnaireSurveyList(context.Context, *GetQuestionnaireSurveyListRequest) (*GetQuestionnaireSurveyListResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetQuestionnaireSurveyList not implemented")
}
func (s *UnimplementedBundleServer) XXX_SetProxyImpl(impl protocol.Invoker) { func (s *UnimplementedBundleServer) XXX_SetProxyImpl(impl protocol.Invoker) {
s.proxyImpl = impl s.proxyImpl = impl
} }
@ -4550,122 +4500,6 @@ func _Bundle_OrderListByOrderUuid_Handler(srv interface{}, ctx context.Context,
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _Bundle_SendQuestionnaireSurvey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(SendQuestionnaireSurveyRequest)
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("SendQuestionnaireSurvey", 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 _Bundle_GetQuestionnaireSurveyInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(GetQuestionnaireSurveyInfoRequest)
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("GetQuestionnaireSurveyInfo", 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 _Bundle_CreateQuestionnaireSurveyAnswer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(CreateQuestionnaireSurveyAnswerRequest)
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("CreateQuestionnaireSurveyAnswer", 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 _Bundle_GetQuestionnaireSurveyList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(GetQuestionnaireSurveyListRequest)
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("GetQuestionnaireSurveyList", 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)
}
// Bundle_ServiceDesc is the grpc_go.ServiceDesc for Bundle service. // Bundle_ServiceDesc is the grpc_go.ServiceDesc for Bundle service.
// It's only intended for direct use with grpc_go.RegisterService, // It's only intended for direct use with grpc_go.RegisterService,
// and not to be introspected or modified (even as a copy) // and not to be introspected or modified (even as a copy)
@ -5101,22 +4935,6 @@ var Bundle_ServiceDesc = grpc_go.ServiceDesc{
MethodName: "OrderListByOrderUuid", MethodName: "OrderListByOrderUuid",
Handler: _Bundle_OrderListByOrderUuid_Handler, Handler: _Bundle_OrderListByOrderUuid_Handler,
}, },
{
MethodName: "SendQuestionnaireSurvey",
Handler: _Bundle_SendQuestionnaireSurvey_Handler,
},
{
MethodName: "GetQuestionnaireSurveyInfo",
Handler: _Bundle_GetQuestionnaireSurveyInfo_Handler,
},
{
MethodName: "CreateQuestionnaireSurveyAnswer",
Handler: _Bundle_CreateQuestionnaireSurveyAnswer_Handler,
},
{
MethodName: "GetQuestionnaireSurveyList",
Handler: _Bundle_GetQuestionnaireSurveyList_Handler,
},
}, },
Streams: []grpc_go.StreamDesc{}, Streams: []grpc_go.StreamDesc{},
Metadata: "pb/bundle.proto", Metadata: "pb/bundle.proto",

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -85,7 +85,6 @@ type CastClient interface {
GetArtist(ctx context.Context, in *GetArtistReq, opts ...grpc_go.CallOption) (*GetArtistResp, common.ErrorWithAttachment) GetArtist(ctx context.Context, in *GetArtistReq, opts ...grpc_go.CallOption) (*GetArtistResp, common.ErrorWithAttachment)
// 作品分析相关接口 // 作品分析相关接口
CreateWorkAnalysis(ctx context.Context, in *CreateWorkAnalysisReq, opts ...grpc_go.CallOption) (*CreateWorkAnalysisResp, common.ErrorWithAttachment) CreateWorkAnalysis(ctx context.Context, in *CreateWorkAnalysisReq, opts ...grpc_go.CallOption) (*CreateWorkAnalysisResp, common.ErrorWithAttachment)
ImportWorkAnalysis(ctx context.Context, in *ImportWorkAnalysisReq, opts ...grpc_go.CallOption) (*ImportWorkAnalysisResp, common.ErrorWithAttachment)
UpdateWorkAnalysis(ctx context.Context, in *UpdateWorkAnalysisReq, opts ...grpc_go.CallOption) (*emptypb.Empty, common.ErrorWithAttachment) UpdateWorkAnalysis(ctx context.Context, in *UpdateWorkAnalysisReq, opts ...grpc_go.CallOption) (*emptypb.Empty, common.ErrorWithAttachment)
UpdateWorkAnalysisStatus(ctx context.Context, in *UpdateWorkAnalysisStatusReq, opts ...grpc_go.CallOption) (*emptypb.Empty, common.ErrorWithAttachment) UpdateWorkAnalysisStatus(ctx context.Context, in *UpdateWorkAnalysisStatusReq, opts ...grpc_go.CallOption) (*emptypb.Empty, common.ErrorWithAttachment)
GetWorkAnalysis(ctx context.Context, in *GetWorkAnalysisDetailReq, opts ...grpc_go.CallOption) (*GetWorkAnalysisDetailResp, common.ErrorWithAttachment) GetWorkAnalysis(ctx context.Context, in *GetWorkAnalysisDetailReq, opts ...grpc_go.CallOption) (*GetWorkAnalysisDetailResp, common.ErrorWithAttachment)
@ -93,7 +92,6 @@ type CastClient interface {
ListWorkAnalysis(ctx context.Context, in *ListWorkAnalysisReq, opts ...grpc_go.CallOption) (*ListWorkAnalysisResp, common.ErrorWithAttachment) ListWorkAnalysis(ctx context.Context, in *ListWorkAnalysisReq, opts ...grpc_go.CallOption) (*ListWorkAnalysisResp, common.ErrorWithAttachment)
DeleteWorkAnalysis(ctx context.Context, in *DeleteWorkAnalysisReq, opts ...grpc_go.CallOption) (*emptypb.Empty, common.ErrorWithAttachment) DeleteWorkAnalysis(ctx context.Context, in *DeleteWorkAnalysisReq, opts ...grpc_go.CallOption) (*emptypb.Empty, common.ErrorWithAttachment)
UpdateWorkAnalysisApprovalID(ctx context.Context, in *UpdateWorkAnalysisApprovalIDReq, opts ...grpc_go.CallOption) (*emptypb.Empty, common.ErrorWithAttachment) UpdateWorkAnalysisApprovalID(ctx context.Context, in *UpdateWorkAnalysisApprovalIDReq, opts ...grpc_go.CallOption) (*emptypb.Empty, common.ErrorWithAttachment)
UpdateWorkAnalysisPdfUrl(ctx context.Context, in *UpdateWorkAnalysisReq, opts ...grpc_go.CallOption) (*emptypb.Empty, common.ErrorWithAttachment)
// 数据列表相关接口 // 数据列表相关接口
ArtistDataList(ctx context.Context, in *ArtistDataListReq, opts ...grpc_go.CallOption) (*ArtistDataListResp, common.ErrorWithAttachment) ArtistDataList(ctx context.Context, in *ArtistDataListReq, opts ...grpc_go.CallOption) (*ArtistDataListResp, common.ErrorWithAttachment)
MediaDataList(ctx context.Context, in *MediaDataListReq, opts ...grpc_go.CallOption) (*MediaDataListResp, common.ErrorWithAttachment) MediaDataList(ctx context.Context, in *MediaDataListReq, opts ...grpc_go.CallOption) (*MediaDataListResp, common.ErrorWithAttachment)
@ -138,11 +136,6 @@ type CastClient interface {
DeleteCompetitiveReport(ctx context.Context, in *DeleteCompetitiveReportReq, opts ...grpc_go.CallOption) (*emptypb.Empty, common.ErrorWithAttachment) 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) 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) 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)
// 艺人作品统计快照接口
GetArtistWorkStats(ctx context.Context, in *GetArtistWorkStatsReq, opts ...grpc_go.CallOption) (*GetArtistWorkStatsResp, common.ErrorWithAttachment)
} }
type castClient struct { type castClient struct {
@ -202,7 +195,6 @@ type CastClientImpl struct {
UpdateArtist func(ctx context.Context, in *UpdateArtistReq) (*UpdateArtistResp, error) UpdateArtist func(ctx context.Context, in *UpdateArtistReq) (*UpdateArtistResp, error)
GetArtist func(ctx context.Context, in *GetArtistReq) (*GetArtistResp, error) GetArtist func(ctx context.Context, in *GetArtistReq) (*GetArtistResp, error)
CreateWorkAnalysis func(ctx context.Context, in *CreateWorkAnalysisReq) (*CreateWorkAnalysisResp, error) CreateWorkAnalysis func(ctx context.Context, in *CreateWorkAnalysisReq) (*CreateWorkAnalysisResp, error)
ImportWorkAnalysis func(ctx context.Context, in *ImportWorkAnalysisReq) (*ImportWorkAnalysisResp, error)
UpdateWorkAnalysis func(ctx context.Context, in *UpdateWorkAnalysisReq) (*emptypb.Empty, error) UpdateWorkAnalysis func(ctx context.Context, in *UpdateWorkAnalysisReq) (*emptypb.Empty, error)
UpdateWorkAnalysisStatus func(ctx context.Context, in *UpdateWorkAnalysisStatusReq) (*emptypb.Empty, error) UpdateWorkAnalysisStatus func(ctx context.Context, in *UpdateWorkAnalysisStatusReq) (*emptypb.Empty, error)
GetWorkAnalysis func(ctx context.Context, in *GetWorkAnalysisDetailReq) (*GetWorkAnalysisDetailResp, error) GetWorkAnalysis func(ctx context.Context, in *GetWorkAnalysisDetailReq) (*GetWorkAnalysisDetailResp, error)
@ -210,7 +202,6 @@ type CastClientImpl struct {
ListWorkAnalysis func(ctx context.Context, in *ListWorkAnalysisReq) (*ListWorkAnalysisResp, error) ListWorkAnalysis func(ctx context.Context, in *ListWorkAnalysisReq) (*ListWorkAnalysisResp, error)
DeleteWorkAnalysis func(ctx context.Context, in *DeleteWorkAnalysisReq) (*emptypb.Empty, error) DeleteWorkAnalysis func(ctx context.Context, in *DeleteWorkAnalysisReq) (*emptypb.Empty, error)
UpdateWorkAnalysisApprovalID func(ctx context.Context, in *UpdateWorkAnalysisApprovalIDReq) (*emptypb.Empty, error) UpdateWorkAnalysisApprovalID func(ctx context.Context, in *UpdateWorkAnalysisApprovalIDReq) (*emptypb.Empty, error)
UpdateWorkAnalysisPdfUrl func(ctx context.Context, in *UpdateWorkAnalysisReq) (*emptypb.Empty, error)
ArtistDataList func(ctx context.Context, in *ArtistDataListReq) (*ArtistDataListResp, error) ArtistDataList func(ctx context.Context, in *ArtistDataListReq) (*ArtistDataListResp, error)
MediaDataList func(ctx context.Context, in *MediaDataListReq) (*MediaDataListResp, error) MediaDataList func(ctx context.Context, in *MediaDataListReq) (*MediaDataListResp, error)
DataOverview func(ctx context.Context, in *DataOverviewReq) (*DataOverviewResp, error) DataOverview func(ctx context.Context, in *DataOverviewReq) (*DataOverviewResp, error)
@ -244,9 +235,6 @@ type CastClientImpl struct {
DeleteCompetitiveReport func(ctx context.Context, in *DeleteCompetitiveReportReq) (*emptypb.Empty, error) DeleteCompetitiveReport func(ctx context.Context, in *DeleteCompetitiveReportReq) (*emptypb.Empty, error)
UpdateCompetitiveReportApprovalID func(ctx context.Context, in *UpdateCompetitiveReportApprovalIDReq) (*emptypb.Empty, error) UpdateCompetitiveReportApprovalID func(ctx context.Context, in *UpdateCompetitiveReportApprovalIDReq) (*emptypb.Empty, error)
CountCompetitiveReportByWorkUuids func(ctx context.Context, in *CountCompetitiveReportByWorkUuidsReq) (*CountCompetitiveReportByWorkUuidsResp, 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)
} }
func (c *CastClientImpl) GetDubboStub(cc *triple.TripleConn) CastClient { func (c *CastClientImpl) GetDubboStub(cc *triple.TripleConn) CastClient {
@ -573,12 +561,6 @@ func (c *castClient) CreateWorkAnalysis(ctx context.Context, in *CreateWorkAnaly
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/CreateWorkAnalysis", in, out) return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/CreateWorkAnalysis", in, out)
} }
func (c *castClient) ImportWorkAnalysis(ctx context.Context, in *ImportWorkAnalysisReq, opts ...grpc_go.CallOption) (*ImportWorkAnalysisResp, common.ErrorWithAttachment) {
out := new(ImportWorkAnalysisResp)
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/ImportWorkAnalysis", in, out)
}
func (c *castClient) UpdateWorkAnalysis(ctx context.Context, in *UpdateWorkAnalysisReq, opts ...grpc_go.CallOption) (*emptypb.Empty, common.ErrorWithAttachment) { func (c *castClient) UpdateWorkAnalysis(ctx context.Context, in *UpdateWorkAnalysisReq, opts ...grpc_go.CallOption) (*emptypb.Empty, common.ErrorWithAttachment) {
out := new(emptypb.Empty) out := new(emptypb.Empty)
interfaceKey := ctx.Value(constant.InterfaceKey).(string) interfaceKey := ctx.Value(constant.InterfaceKey).(string)
@ -621,12 +603,6 @@ func (c *castClient) UpdateWorkAnalysisApprovalID(ctx context.Context, in *Updat
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/UpdateWorkAnalysisApprovalID", in, out) return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/UpdateWorkAnalysisApprovalID", in, out)
} }
func (c *castClient) UpdateWorkAnalysisPdfUrl(ctx context.Context, in *UpdateWorkAnalysisReq, opts ...grpc_go.CallOption) (*emptypb.Empty, common.ErrorWithAttachment) {
out := new(emptypb.Empty)
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/UpdateWorkAnalysisPdfUrl", in, out)
}
func (c *castClient) ArtistDataList(ctx context.Context, in *ArtistDataListReq, opts ...grpc_go.CallOption) (*ArtistDataListResp, common.ErrorWithAttachment) { func (c *castClient) ArtistDataList(ctx context.Context, in *ArtistDataListReq, opts ...grpc_go.CallOption) (*ArtistDataListResp, common.ErrorWithAttachment) {
out := new(ArtistDataListResp) out := new(ArtistDataListResp)
interfaceKey := ctx.Value(constant.InterfaceKey).(string) interfaceKey := ctx.Value(constant.InterfaceKey).(string)
@ -825,24 +801,6 @@ func (c *castClient) CountCompetitiveReportByWorkUuids(ctx context.Context, in *
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/CountCompetitiveReportByWorkUuids", in, out) 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)
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/ListPublishLog", in, out)
}
func (c *castClient) GetArtistWorkStats(ctx context.Context, in *GetArtistWorkStatsReq, opts ...grpc_go.CallOption) (*GetArtistWorkStatsResp, common.ErrorWithAttachment) {
out := new(GetArtistWorkStatsResp)
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/GetArtistWorkStats", in, out)
}
// CastServer is the server API for Cast service. // CastServer is the server API for Cast service.
// All implementations must embed UnimplementedCastServer // All implementations must embed UnimplementedCastServer
// for forward compatibility // for forward compatibility
@ -903,7 +861,6 @@ type CastServer interface {
GetArtist(context.Context, *GetArtistReq) (*GetArtistResp, error) GetArtist(context.Context, *GetArtistReq) (*GetArtistResp, error)
// 作品分析相关接口 // 作品分析相关接口
CreateWorkAnalysis(context.Context, *CreateWorkAnalysisReq) (*CreateWorkAnalysisResp, error) CreateWorkAnalysis(context.Context, *CreateWorkAnalysisReq) (*CreateWorkAnalysisResp, error)
ImportWorkAnalysis(context.Context, *ImportWorkAnalysisReq) (*ImportWorkAnalysisResp, error)
UpdateWorkAnalysis(context.Context, *UpdateWorkAnalysisReq) (*emptypb.Empty, error) UpdateWorkAnalysis(context.Context, *UpdateWorkAnalysisReq) (*emptypb.Empty, error)
UpdateWorkAnalysisStatus(context.Context, *UpdateWorkAnalysisStatusReq) (*emptypb.Empty, error) UpdateWorkAnalysisStatus(context.Context, *UpdateWorkAnalysisStatusReq) (*emptypb.Empty, error)
GetWorkAnalysis(context.Context, *GetWorkAnalysisDetailReq) (*GetWorkAnalysisDetailResp, error) GetWorkAnalysis(context.Context, *GetWorkAnalysisDetailReq) (*GetWorkAnalysisDetailResp, error)
@ -911,7 +868,6 @@ type CastServer interface {
ListWorkAnalysis(context.Context, *ListWorkAnalysisReq) (*ListWorkAnalysisResp, error) ListWorkAnalysis(context.Context, *ListWorkAnalysisReq) (*ListWorkAnalysisResp, error)
DeleteWorkAnalysis(context.Context, *DeleteWorkAnalysisReq) (*emptypb.Empty, error) DeleteWorkAnalysis(context.Context, *DeleteWorkAnalysisReq) (*emptypb.Empty, error)
UpdateWorkAnalysisApprovalID(context.Context, *UpdateWorkAnalysisApprovalIDReq) (*emptypb.Empty, error) UpdateWorkAnalysisApprovalID(context.Context, *UpdateWorkAnalysisApprovalIDReq) (*emptypb.Empty, error)
UpdateWorkAnalysisPdfUrl(context.Context, *UpdateWorkAnalysisReq) (*emptypb.Empty, error)
// 数据列表相关接口 // 数据列表相关接口
ArtistDataList(context.Context, *ArtistDataListReq) (*ArtistDataListResp, error) ArtistDataList(context.Context, *ArtistDataListReq) (*ArtistDataListResp, error)
MediaDataList(context.Context, *MediaDataListReq) (*MediaDataListResp, error) MediaDataList(context.Context, *MediaDataListReq) (*MediaDataListResp, error)
@ -956,11 +912,6 @@ type CastServer interface {
DeleteCompetitiveReport(context.Context, *DeleteCompetitiveReportReq) (*emptypb.Empty, error) DeleteCompetitiveReport(context.Context, *DeleteCompetitiveReportReq) (*emptypb.Empty, error)
UpdateCompetitiveReportApprovalID(context.Context, *UpdateCompetitiveReportApprovalIDReq) (*emptypb.Empty, error) UpdateCompetitiveReportApprovalID(context.Context, *UpdateCompetitiveReportApprovalIDReq) (*emptypb.Empty, error)
CountCompetitiveReportByWorkUuids(context.Context, *CountCompetitiveReportByWorkUuidsReq) (*CountCompetitiveReportByWorkUuidsResp, error) CountCompetitiveReportByWorkUuids(context.Context, *CountCompetitiveReportByWorkUuidsReq) (*CountCompetitiveReportByWorkUuidsResp, error)
ImportCompetitiveReportHistory(context.Context, *ImportCompetitiveReportHistoryReq) (*ImportCompetitiveReportHistoryResp, error)
// 发布记录相关接口
ListPublishLog(context.Context, *ListPublishLogReq) (*ListPublishLogResp, error)
// 艺人作品统计快照接口
GetArtistWorkStats(context.Context, *GetArtistWorkStatsReq) (*GetArtistWorkStatsResp, error)
mustEmbedUnimplementedCastServer() mustEmbedUnimplementedCastServer()
} }
@ -1125,9 +1076,6 @@ func (UnimplementedCastServer) GetArtist(context.Context, *GetArtistReq) (*GetAr
func (UnimplementedCastServer) CreateWorkAnalysis(context.Context, *CreateWorkAnalysisReq) (*CreateWorkAnalysisResp, error) { func (UnimplementedCastServer) CreateWorkAnalysis(context.Context, *CreateWorkAnalysisReq) (*CreateWorkAnalysisResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateWorkAnalysis not implemented") return nil, status.Errorf(codes.Unimplemented, "method CreateWorkAnalysis not implemented")
} }
func (UnimplementedCastServer) ImportWorkAnalysis(context.Context, *ImportWorkAnalysisReq) (*ImportWorkAnalysisResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method ImportWorkAnalysis not implemented")
}
func (UnimplementedCastServer) UpdateWorkAnalysis(context.Context, *UpdateWorkAnalysisReq) (*emptypb.Empty, error) { func (UnimplementedCastServer) UpdateWorkAnalysis(context.Context, *UpdateWorkAnalysisReq) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdateWorkAnalysis not implemented") return nil, status.Errorf(codes.Unimplemented, "method UpdateWorkAnalysis not implemented")
} }
@ -1149,9 +1097,6 @@ func (UnimplementedCastServer) DeleteWorkAnalysis(context.Context, *DeleteWorkAn
func (UnimplementedCastServer) UpdateWorkAnalysisApprovalID(context.Context, *UpdateWorkAnalysisApprovalIDReq) (*emptypb.Empty, error) { func (UnimplementedCastServer) UpdateWorkAnalysisApprovalID(context.Context, *UpdateWorkAnalysisApprovalIDReq) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdateWorkAnalysisApprovalID not implemented") return nil, status.Errorf(codes.Unimplemented, "method UpdateWorkAnalysisApprovalID not implemented")
} }
func (UnimplementedCastServer) UpdateWorkAnalysisPdfUrl(context.Context, *UpdateWorkAnalysisReq) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdateWorkAnalysisPdfUrl not implemented")
}
func (UnimplementedCastServer) ArtistDataList(context.Context, *ArtistDataListReq) (*ArtistDataListResp, error) { func (UnimplementedCastServer) ArtistDataList(context.Context, *ArtistDataListReq) (*ArtistDataListResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method ArtistDataList not implemented") return nil, status.Errorf(codes.Unimplemented, "method ArtistDataList not implemented")
} }
@ -1251,15 +1196,6 @@ func (UnimplementedCastServer) UpdateCompetitiveReportApprovalID(context.Context
func (UnimplementedCastServer) CountCompetitiveReportByWorkUuids(context.Context, *CountCompetitiveReportByWorkUuidsReq) (*CountCompetitiveReportByWorkUuidsResp, error) { func (UnimplementedCastServer) CountCompetitiveReportByWorkUuids(context.Context, *CountCompetitiveReportByWorkUuidsReq) (*CountCompetitiveReportByWorkUuidsResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method CountCompetitiveReportByWorkUuids not implemented") 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")
}
func (UnimplementedCastServer) GetArtistWorkStats(context.Context, *GetArtistWorkStatsReq) (*GetArtistWorkStatsResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetArtistWorkStats not implemented")
}
func (s *UnimplementedCastServer) XXX_SetProxyImpl(impl protocol.Invoker) { func (s *UnimplementedCastServer) XXX_SetProxyImpl(impl protocol.Invoker) {
s.proxyImpl = impl s.proxyImpl = impl
} }
@ -2796,35 +2732,6 @@ func _Cast_CreateWorkAnalysis_Handler(srv interface{}, ctx context.Context, dec
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _Cast_ImportWorkAnalysis_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(ImportWorkAnalysisReq)
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("ImportWorkAnalysis", 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_UpdateWorkAnalysis_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) { func _Cast_UpdateWorkAnalysis_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdateWorkAnalysisReq) in := new(UpdateWorkAnalysisReq)
if err := dec(in); err != nil { if err := dec(in); err != nil {
@ -3028,35 +2935,6 @@ func _Cast_UpdateWorkAnalysisApprovalID_Handler(srv interface{}, ctx context.Con
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _Cast_UpdateWorkAnalysisPdfUrl_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdateWorkAnalysisReq)
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("UpdateWorkAnalysisPdfUrl", 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_ArtistDataList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) { func _Cast_ArtistDataList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(ArtistDataListReq) in := new(ArtistDataListReq)
if err := dec(in); err != nil { if err := dec(in); err != nil {
@ -4014,93 +3892,6 @@ func _Cast_CountCompetitiveReportByWorkUuids_Handler(srv interface{}, ctx contex
return interceptor(ctx, in, info, handler) 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 {
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("ListPublishLog", 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_GetArtistWorkStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(GetArtistWorkStatsReq)
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("GetArtistWorkStats", 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)
}
// Cast_ServiceDesc is the grpc_go.ServiceDesc for Cast service. // Cast_ServiceDesc is the grpc_go.ServiceDesc for Cast service.
// It's only intended for direct use with grpc_go.RegisterService, // It's only intended for direct use with grpc_go.RegisterService,
// and not to be introspected or modified (even as a copy) // and not to be introspected or modified (even as a copy)
@ -4316,10 +4107,6 @@ var Cast_ServiceDesc = grpc_go.ServiceDesc{
MethodName: "CreateWorkAnalysis", MethodName: "CreateWorkAnalysis",
Handler: _Cast_CreateWorkAnalysis_Handler, Handler: _Cast_CreateWorkAnalysis_Handler,
}, },
{
MethodName: "ImportWorkAnalysis",
Handler: _Cast_ImportWorkAnalysis_Handler,
},
{ {
MethodName: "UpdateWorkAnalysis", MethodName: "UpdateWorkAnalysis",
Handler: _Cast_UpdateWorkAnalysis_Handler, Handler: _Cast_UpdateWorkAnalysis_Handler,
@ -4348,10 +4135,6 @@ var Cast_ServiceDesc = grpc_go.ServiceDesc{
MethodName: "UpdateWorkAnalysisApprovalID", MethodName: "UpdateWorkAnalysisApprovalID",
Handler: _Cast_UpdateWorkAnalysisApprovalID_Handler, Handler: _Cast_UpdateWorkAnalysisApprovalID_Handler,
}, },
{
MethodName: "UpdateWorkAnalysisPdfUrl",
Handler: _Cast_UpdateWorkAnalysisPdfUrl_Handler,
},
{ {
MethodName: "ArtistDataList", MethodName: "ArtistDataList",
Handler: _Cast_ArtistDataList_Handler, Handler: _Cast_ArtistDataList_Handler,
@ -4484,18 +4267,6 @@ var Cast_ServiceDesc = grpc_go.ServiceDesc{
MethodName: "CountCompetitiveReportByWorkUuids", MethodName: "CountCompetitiveReportByWorkUuids",
Handler: _Cast_CountCompetitiveReportByWorkUuids_Handler, Handler: _Cast_CountCompetitiveReportByWorkUuids_Handler,
}, },
{
MethodName: "ImportCompetitiveReportHistory",
Handler: _Cast_ImportCompetitiveReportHistory_Handler,
},
{
MethodName: "ListPublishLog",
Handler: _Cast_ListPublishLog_Handler,
},
{
MethodName: "GetArtistWorkStats",
Handler: _Cast_GetArtistWorkStats_Handler,
},
}, },
Streams: []grpc_go.StreamDesc{}, Streams: []grpc_go.StreamDesc{},
Metadata: "pb/fiee/cast.proto", Metadata: "pb/fiee/cast.proto",

File diff suppressed because it is too large Load Diff

View File

@ -14,12 +14,14 @@ service PaymentCent{
rpc CreateRefund(CreateRefundRequest) returns (CreateRefundResponse); // 退 rpc CreateRefund(CreateRefundRequest) returns (CreateRefundResponse); // 退
rpc StripeGermanyWebhook(GetCheckoutWebhookRequest) returns(GetCheckoutWebhookResponse){};// stripe支付回调, rpc StripeGermanyWebhook(GetCheckoutWebhookRequest) returns(GetCheckoutWebhookResponse){};// stripe支付回调,
rpc StripeJapanWebhook(GetCheckoutWebhookRequest) returns(GetCheckoutWebhookResponse){};// stripe支付回调,
rpc AliCommonWebhook(NotifyPayRequest) returns (NotifyPayResponse){}; // rpc AliCommonWebhook(NotifyPayRequest) returns (NotifyPayResponse){}; //
rpc WechatFengLianWebhook(NotifyPayRequest) returns (NotifyPayResponse){}; // rpc WechatFengLianWebhook(NotifyPayRequest) returns (NotifyPayResponse){}; //
rpc AntomWebhook(AntomNotifyPayRequest) returns (AntomNotifyPayResponse){}; // Antom支付回调 rpc AntomWebhook(AntomNotifyPayRequest) returns (AntomNotifyPayResponse){}; // Antom支付回调
rpc QueryAntomPayByCheckoutSessionId(AntomPayQueryRequest) returns (AntomPayQueryResponse){}; // checkoutSessionIds查询支付情况 rpc QueryAntomPayByCheckoutSessionId(AntomPayQueryRequest) returns (AntomPayQueryResponse){}; // checkoutSessionIds查询支付情况
rpc ExpireStripePayByCheckoutSessionId(ExpireRequest) returns (CommonResponse){}; // checkoutSessionId
@ -127,6 +129,7 @@ message CreatePayResponse {
string partnerId = 11 [json_name = "partnerId"]; string partnerId = 11 [json_name = "partnerId"];
string checkoutSessionId = 12 [json_name = "checkoutSessionId"]; string checkoutSessionId = 12 [json_name = "checkoutSessionId"];
string antomId = 13 [json_name = "antomId"];
} }
message CreateRefundRequest { message CreateRefundRequest {
@ -633,6 +636,7 @@ message WechatPayOkRequest {
message CommonResponse { message CommonResponse {
bool Success = 1 [json_name = "success"]; bool Success = 1 [json_name = "success"];
uint32 ID = 2 ; uint32 ID = 2 ;
string Message = 3 ;
} }
message PayQueryRequest { message PayQueryRequest {
@ -711,6 +715,7 @@ message OrderDetail {
string productName = 19; string productName = 19;
string productImg = 20; string productImg = 20;
string productDescription = 21; string productDescription = 21;
string antomId = 22;
} }
message BusinessInfo { message BusinessInfo {
@ -741,3 +746,8 @@ message ChannelIncome {
int64 totalRefundAmount = 6; // 退 int64 totalRefundAmount = 6; // 退
int64 netIncome = 7; // int64 netIncome = 7; //
} }
message ExpireRequest {
string checkoutSessionId = 1;
string payee = 2; //
}

View File

@ -299,3 +299,6 @@ func (this *Overview) Validate() error {
func (this *ChannelIncome) Validate() error { func (this *ChannelIncome) Validate() error {
return nil return nil
} }
func (this *ExpireRequest) Validate() error {
return nil
}

View File

@ -35,10 +35,12 @@ type PaymentCentClient interface {
QueryExportPay(ctx context.Context, in *ExportPayRequest, opts ...grpc_go.CallOption) (*ExportPayResponse, common.ErrorWithAttachment) QueryExportPay(ctx context.Context, in *ExportPayRequest, opts ...grpc_go.CallOption) (*ExportPayResponse, common.ErrorWithAttachment)
CreateRefund(ctx context.Context, in *CreateRefundRequest, opts ...grpc_go.CallOption) (*CreateRefundResponse, common.ErrorWithAttachment) CreateRefund(ctx context.Context, in *CreateRefundRequest, opts ...grpc_go.CallOption) (*CreateRefundResponse, common.ErrorWithAttachment)
StripeGermanyWebhook(ctx context.Context, in *GetCheckoutWebhookRequest, opts ...grpc_go.CallOption) (*GetCheckoutWebhookResponse, common.ErrorWithAttachment) StripeGermanyWebhook(ctx context.Context, in *GetCheckoutWebhookRequest, opts ...grpc_go.CallOption) (*GetCheckoutWebhookResponse, common.ErrorWithAttachment)
StripeJapanWebhook(ctx context.Context, in *GetCheckoutWebhookRequest, opts ...grpc_go.CallOption) (*GetCheckoutWebhookResponse, common.ErrorWithAttachment)
AliCommonWebhook(ctx context.Context, in *NotifyPayRequest, opts ...grpc_go.CallOption) (*NotifyPayResponse, common.ErrorWithAttachment) AliCommonWebhook(ctx context.Context, in *NotifyPayRequest, opts ...grpc_go.CallOption) (*NotifyPayResponse, common.ErrorWithAttachment)
WechatFengLianWebhook(ctx context.Context, in *NotifyPayRequest, opts ...grpc_go.CallOption) (*NotifyPayResponse, common.ErrorWithAttachment) WechatFengLianWebhook(ctx context.Context, in *NotifyPayRequest, opts ...grpc_go.CallOption) (*NotifyPayResponse, common.ErrorWithAttachment)
AntomWebhook(ctx context.Context, in *AntomNotifyPayRequest, opts ...grpc_go.CallOption) (*AntomNotifyPayResponse, common.ErrorWithAttachment) AntomWebhook(ctx context.Context, in *AntomNotifyPayRequest, opts ...grpc_go.CallOption) (*AntomNotifyPayResponse, common.ErrorWithAttachment)
QueryAntomPayByCheckoutSessionId(ctx context.Context, in *AntomPayQueryRequest, opts ...grpc_go.CallOption) (*AntomPayQueryResponse, common.ErrorWithAttachment) QueryAntomPayByCheckoutSessionId(ctx context.Context, in *AntomPayQueryRequest, opts ...grpc_go.CallOption) (*AntomPayQueryResponse, common.ErrorWithAttachment)
ExpireStripePayByCheckoutSessionId(ctx context.Context, in *ExpireRequest, opts ...grpc_go.CallOption) (*CommonResponse, common.ErrorWithAttachment)
// stripe支付 // stripe支付
CreateStripeCheckoutSession(ctx context.Context, in *CreateStripeCheckoutSessionRequest, opts ...grpc_go.CallOption) (*CreateStripeCheckoutSessionResponse, common.ErrorWithAttachment) CreateStripeCheckoutSession(ctx context.Context, in *CreateStripeCheckoutSessionRequest, opts ...grpc_go.CallOption) (*CreateStripeCheckoutSessionResponse, common.ErrorWithAttachment)
// 支付宝支付 // 支付宝支付
@ -70,37 +72,39 @@ type paymentCentClient struct {
} }
type PaymentCentClientImpl struct { type PaymentCentClientImpl struct {
CreatePay func(ctx context.Context, in *CreatePayRequest) (*CreatePayResponse, error) CreatePay func(ctx context.Context, in *CreatePayRequest) (*CreatePayResponse, error)
NotifyPay func(ctx context.Context, in *NotifyPayRequest) (*NotifyPayResponse, error) NotifyPay func(ctx context.Context, in *NotifyPayRequest) (*NotifyPayResponse, error)
QueryPayByOutTradeNo func(ctx context.Context, in *PayQueryRequest) (*PayQueryResponse, error) QueryPayByOutTradeNo func(ctx context.Context, in *PayQueryRequest) (*PayQueryResponse, error)
QueryExportPay func(ctx context.Context, in *ExportPayRequest) (*ExportPayResponse, error) QueryExportPay func(ctx context.Context, in *ExportPayRequest) (*ExportPayResponse, error)
CreateRefund func(ctx context.Context, in *CreateRefundRequest) (*CreateRefundResponse, error) CreateRefund func(ctx context.Context, in *CreateRefundRequest) (*CreateRefundResponse, error)
StripeGermanyWebhook func(ctx context.Context, in *GetCheckoutWebhookRequest) (*GetCheckoutWebhookResponse, error) StripeGermanyWebhook func(ctx context.Context, in *GetCheckoutWebhookRequest) (*GetCheckoutWebhookResponse, error)
AliCommonWebhook func(ctx context.Context, in *NotifyPayRequest) (*NotifyPayResponse, error) StripeJapanWebhook func(ctx context.Context, in *GetCheckoutWebhookRequest) (*GetCheckoutWebhookResponse, error)
WechatFengLianWebhook func(ctx context.Context, in *NotifyPayRequest) (*NotifyPayResponse, error) AliCommonWebhook func(ctx context.Context, in *NotifyPayRequest) (*NotifyPayResponse, error)
AntomWebhook func(ctx context.Context, in *AntomNotifyPayRequest) (*AntomNotifyPayResponse, error) WechatFengLianWebhook func(ctx context.Context, in *NotifyPayRequest) (*NotifyPayResponse, error)
QueryAntomPayByCheckoutSessionId func(ctx context.Context, in *AntomPayQueryRequest) (*AntomPayQueryResponse, error) AntomWebhook func(ctx context.Context, in *AntomNotifyPayRequest) (*AntomNotifyPayResponse, error)
CreateStripeCheckoutSession func(ctx context.Context, in *CreateStripeCheckoutSessionRequest) (*CreateStripeCheckoutSessionResponse, error) QueryAntomPayByCheckoutSessionId func(ctx context.Context, in *AntomPayQueryRequest) (*AntomPayQueryResponse, error)
AliWapPay func(ctx context.Context, in *AliWapPayRequest) (*AliWapPayResponse, error) ExpireStripePayByCheckoutSessionId func(ctx context.Context, in *ExpireRequest) (*CommonResponse, error)
AliAppPay func(ctx context.Context, in *AliAppPayRequest) (*AliAppPayResponse, error) CreateStripeCheckoutSession func(ctx context.Context, in *CreateStripeCheckoutSessionRequest) (*CreateStripeCheckoutSessionResponse, error)
AliNativePay func(ctx context.Context, in *AliNativePayRequest) (*AliNativePayResponse, error) AliWapPay func(ctx context.Context, in *AliWapPayRequest) (*AliWapPayResponse, error)
AliPcWabPay func(ctx context.Context, in *AliPcWabPayRequest) (*AliPcWabPayResponse, error) AliAppPay func(ctx context.Context, in *AliAppPayRequest) (*AliAppPayResponse, error)
AliReFund func(ctx context.Context, in *AliReFundRequest) (*AliReFundResponse, error) AliNativePay func(ctx context.Context, in *AliNativePayRequest) (*AliNativePayResponse, error)
AliNotify func(ctx context.Context, in *AliNotifyRequest) (*AliNotifyResponse, error) AliPcWabPay func(ctx context.Context, in *AliPcWabPayRequest) (*AliPcWabPayResponse, error)
AliQueryByOutTradeNo func(ctx context.Context, in *AliQueryByOutTradeNoRequest) (*AliQueryByOutTradeNoResponse, error) AliReFund func(ctx context.Context, in *AliReFundRequest) (*AliReFundResponse, error)
AliRefundQueryByOutTradeNo func(ctx context.Context, in *AliRefundQueryByOutTradeNoRequest) (*AliRefundQueryByOutTradeNoResponse, error) AliNotify func(ctx context.Context, in *AliNotifyRequest) (*AliNotifyResponse, error)
WechatJsApiPay func(ctx context.Context, in *WechatJsApiPayRequest) (*WechatJsApiPayResponse, error) AliQueryByOutTradeNo func(ctx context.Context, in *AliQueryByOutTradeNoRequest) (*AliQueryByOutTradeNoResponse, error)
WechatJsApiQueryByOutTradeNo func(ctx context.Context, in *WechatJsApiQueryByOutTradeNoRequest) (*WechatJsApiQueryByOutTradeNoResponse, error) AliRefundQueryByOutTradeNo func(ctx context.Context, in *AliRefundQueryByOutTradeNoRequest) (*AliRefundQueryByOutTradeNoResponse, error)
GetPayByOutTradeNo func(ctx context.Context, in *GetPayByOutTradeNoRequest) (*GetPayByOutTradeNoResponse, error) WechatJsApiPay func(ctx context.Context, in *WechatJsApiPayRequest) (*WechatJsApiPayResponse, error)
WechatJsApiRefunds func(ctx context.Context, in *WechatJsApiRefundsRequest) (*WechatJsApiRefundsResponse, error) WechatJsApiQueryByOutTradeNo func(ctx context.Context, in *WechatJsApiQueryByOutTradeNoRequest) (*WechatJsApiQueryByOutTradeNoResponse, error)
SetPayOk func(ctx context.Context, in *WechatPayOkRequest) (*CommonResponse, error) GetPayByOutTradeNo func(ctx context.Context, in *GetPayByOutTradeNoRequest) (*GetPayByOutTradeNoResponse, error)
WechatAppPay func(ctx context.Context, in *WechatAppPayRequest) (*WechatAppPayResponse, error) WechatJsApiRefunds func(ctx context.Context, in *WechatJsApiRefundsRequest) (*WechatJsApiRefundsResponse, error)
WechatAppQueryByOutTradeNo func(ctx context.Context, in *WechatAppQueryByOutTradeNoRequest) (*WechatAppQueryByOutTradeNoResponse, error) SetPayOk func(ctx context.Context, in *WechatPayOkRequest) (*CommonResponse, error)
WechatNativePay func(ctx context.Context, in *WechatNativePayRequest) (*WechatNativePayResponse, error) WechatAppPay func(ctx context.Context, in *WechatAppPayRequest) (*WechatAppPayResponse, error)
WechatNativeQueryByOutTradeNo func(ctx context.Context, in *WechatNativeQueryByOutTradeNoRequest) (*WechatNativeQueryByOutTradeNoResponse, error) WechatAppQueryByOutTradeNo func(ctx context.Context, in *WechatAppQueryByOutTradeNoRequest) (*WechatAppQueryByOutTradeNoResponse, error)
WechatRefundQueryByOutRefundNo func(ctx context.Context, in *WechatRefundQueryByOutRefundNoRequest) (*WechatRefundQueryByOutRefundNoResponse, error) WechatNativePay func(ctx context.Context, in *WechatNativePayRequest) (*WechatNativePayResponse, error)
WechatH5Pay func(ctx context.Context, in *WechatH5PayRequest) (*WechatH5PayResponse, error) WechatNativeQueryByOutTradeNo func(ctx context.Context, in *WechatNativeQueryByOutTradeNoRequest) (*WechatNativeQueryByOutTradeNoResponse, error)
WechatH5QueryByOutTradeNo func(ctx context.Context, in *WechatH5QueryByOutTradeNoRequest) (*WechatH5QueryByOutTradeNoResponse, error) WechatRefundQueryByOutRefundNo func(ctx context.Context, in *WechatRefundQueryByOutRefundNoRequest) (*WechatRefundQueryByOutRefundNoResponse, error)
WechatH5Pay func(ctx context.Context, in *WechatH5PayRequest) (*WechatH5PayResponse, error)
WechatH5QueryByOutTradeNo func(ctx context.Context, in *WechatH5QueryByOutTradeNoRequest) (*WechatH5QueryByOutTradeNoResponse, error)
} }
func (c *PaymentCentClientImpl) GetDubboStub(cc *triple.TripleConn) PaymentCentClient { func (c *PaymentCentClientImpl) GetDubboStub(cc *triple.TripleConn) PaymentCentClient {
@ -151,6 +155,12 @@ func (c *paymentCentClient) StripeGermanyWebhook(ctx context.Context, in *GetChe
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/StripeGermanyWebhook", in, out) return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/StripeGermanyWebhook", in, out)
} }
func (c *paymentCentClient) StripeJapanWebhook(ctx context.Context, in *GetCheckoutWebhookRequest, opts ...grpc_go.CallOption) (*GetCheckoutWebhookResponse, common.ErrorWithAttachment) {
out := new(GetCheckoutWebhookResponse)
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/StripeJapanWebhook", in, out)
}
func (c *paymentCentClient) AliCommonWebhook(ctx context.Context, in *NotifyPayRequest, opts ...grpc_go.CallOption) (*NotifyPayResponse, common.ErrorWithAttachment) { func (c *paymentCentClient) AliCommonWebhook(ctx context.Context, in *NotifyPayRequest, opts ...grpc_go.CallOption) (*NotifyPayResponse, common.ErrorWithAttachment) {
out := new(NotifyPayResponse) out := new(NotifyPayResponse)
interfaceKey := ctx.Value(constant.InterfaceKey).(string) interfaceKey := ctx.Value(constant.InterfaceKey).(string)
@ -175,6 +185,12 @@ func (c *paymentCentClient) QueryAntomPayByCheckoutSessionId(ctx context.Context
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/QueryAntomPayByCheckoutSessionId", in, out) return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/QueryAntomPayByCheckoutSessionId", in, out)
} }
func (c *paymentCentClient) ExpireStripePayByCheckoutSessionId(ctx context.Context, in *ExpireRequest, opts ...grpc_go.CallOption) (*CommonResponse, common.ErrorWithAttachment) {
out := new(CommonResponse)
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/ExpireStripePayByCheckoutSessionId", in, out)
}
func (c *paymentCentClient) CreateStripeCheckoutSession(ctx context.Context, in *CreateStripeCheckoutSessionRequest, opts ...grpc_go.CallOption) (*CreateStripeCheckoutSessionResponse, common.ErrorWithAttachment) { func (c *paymentCentClient) CreateStripeCheckoutSession(ctx context.Context, in *CreateStripeCheckoutSessionRequest, opts ...grpc_go.CallOption) (*CreateStripeCheckoutSessionResponse, common.ErrorWithAttachment) {
out := new(CreateStripeCheckoutSessionResponse) out := new(CreateStripeCheckoutSessionResponse)
interfaceKey := ctx.Value(constant.InterfaceKey).(string) interfaceKey := ctx.Value(constant.InterfaceKey).(string)
@ -312,10 +328,12 @@ type PaymentCentServer interface {
QueryExportPay(context.Context, *ExportPayRequest) (*ExportPayResponse, error) QueryExportPay(context.Context, *ExportPayRequest) (*ExportPayResponse, error)
CreateRefund(context.Context, *CreateRefundRequest) (*CreateRefundResponse, error) CreateRefund(context.Context, *CreateRefundRequest) (*CreateRefundResponse, error)
StripeGermanyWebhook(context.Context, *GetCheckoutWebhookRequest) (*GetCheckoutWebhookResponse, error) StripeGermanyWebhook(context.Context, *GetCheckoutWebhookRequest) (*GetCheckoutWebhookResponse, error)
StripeJapanWebhook(context.Context, *GetCheckoutWebhookRequest) (*GetCheckoutWebhookResponse, error)
AliCommonWebhook(context.Context, *NotifyPayRequest) (*NotifyPayResponse, error) AliCommonWebhook(context.Context, *NotifyPayRequest) (*NotifyPayResponse, error)
WechatFengLianWebhook(context.Context, *NotifyPayRequest) (*NotifyPayResponse, error) WechatFengLianWebhook(context.Context, *NotifyPayRequest) (*NotifyPayResponse, error)
AntomWebhook(context.Context, *AntomNotifyPayRequest) (*AntomNotifyPayResponse, error) AntomWebhook(context.Context, *AntomNotifyPayRequest) (*AntomNotifyPayResponse, error)
QueryAntomPayByCheckoutSessionId(context.Context, *AntomPayQueryRequest) (*AntomPayQueryResponse, error) QueryAntomPayByCheckoutSessionId(context.Context, *AntomPayQueryRequest) (*AntomPayQueryResponse, error)
ExpireStripePayByCheckoutSessionId(context.Context, *ExpireRequest) (*CommonResponse, error)
// stripe支付 // stripe支付
CreateStripeCheckoutSession(context.Context, *CreateStripeCheckoutSessionRequest) (*CreateStripeCheckoutSessionResponse, error) CreateStripeCheckoutSession(context.Context, *CreateStripeCheckoutSessionRequest) (*CreateStripeCheckoutSessionResponse, error)
// 支付宝支付 // 支付宝支付
@ -366,6 +384,9 @@ func (UnimplementedPaymentCentServer) CreateRefund(context.Context, *CreateRefun
func (UnimplementedPaymentCentServer) StripeGermanyWebhook(context.Context, *GetCheckoutWebhookRequest) (*GetCheckoutWebhookResponse, error) { func (UnimplementedPaymentCentServer) StripeGermanyWebhook(context.Context, *GetCheckoutWebhookRequest) (*GetCheckoutWebhookResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method StripeGermanyWebhook not implemented") return nil, status.Errorf(codes.Unimplemented, "method StripeGermanyWebhook not implemented")
} }
func (UnimplementedPaymentCentServer) StripeJapanWebhook(context.Context, *GetCheckoutWebhookRequest) (*GetCheckoutWebhookResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method StripeJapanWebhook not implemented")
}
func (UnimplementedPaymentCentServer) AliCommonWebhook(context.Context, *NotifyPayRequest) (*NotifyPayResponse, error) { func (UnimplementedPaymentCentServer) AliCommonWebhook(context.Context, *NotifyPayRequest) (*NotifyPayResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method AliCommonWebhook not implemented") return nil, status.Errorf(codes.Unimplemented, "method AliCommonWebhook not implemented")
} }
@ -378,6 +399,9 @@ func (UnimplementedPaymentCentServer) AntomWebhook(context.Context, *AntomNotify
func (UnimplementedPaymentCentServer) QueryAntomPayByCheckoutSessionId(context.Context, *AntomPayQueryRequest) (*AntomPayQueryResponse, error) { func (UnimplementedPaymentCentServer) QueryAntomPayByCheckoutSessionId(context.Context, *AntomPayQueryRequest) (*AntomPayQueryResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method QueryAntomPayByCheckoutSessionId not implemented") return nil, status.Errorf(codes.Unimplemented, "method QueryAntomPayByCheckoutSessionId not implemented")
} }
func (UnimplementedPaymentCentServer) ExpireStripePayByCheckoutSessionId(context.Context, *ExpireRequest) (*CommonResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ExpireStripePayByCheckoutSessionId not implemented")
}
func (UnimplementedPaymentCentServer) CreateStripeCheckoutSession(context.Context, *CreateStripeCheckoutSessionRequest) (*CreateStripeCheckoutSessionResponse, error) { func (UnimplementedPaymentCentServer) CreateStripeCheckoutSession(context.Context, *CreateStripeCheckoutSessionRequest) (*CreateStripeCheckoutSessionResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateStripeCheckoutSession not implemented") return nil, status.Errorf(codes.Unimplemented, "method CreateStripeCheckoutSession not implemented")
} }
@ -643,6 +667,35 @@ func _PaymentCent_StripeGermanyWebhook_Handler(srv interface{}, ctx context.Cont
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _PaymentCent_StripeJapanWebhook_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(GetCheckoutWebhookRequest)
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("StripeJapanWebhook", 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 _PaymentCent_AliCommonWebhook_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) { func _PaymentCent_AliCommonWebhook_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(NotifyPayRequest) in := new(NotifyPayRequest)
if err := dec(in); err != nil { if err := dec(in); err != nil {
@ -759,6 +812,35 @@ func _PaymentCent_QueryAntomPayByCheckoutSessionId_Handler(srv interface{}, ctx
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _PaymentCent_ExpireStripePayByCheckoutSessionId_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(ExpireRequest)
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("ExpireStripePayByCheckoutSessionId", 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 _PaymentCent_CreateStripeCheckoutSession_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) { func _PaymentCent_CreateStripeCheckoutSession_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(CreateStripeCheckoutSessionRequest) in := new(CreateStripeCheckoutSessionRequest)
if err := dec(in); err != nil { if err := dec(in); err != nil {
@ -1399,6 +1481,10 @@ var PaymentCent_ServiceDesc = grpc_go.ServiceDesc{
MethodName: "StripeGermanyWebhook", MethodName: "StripeGermanyWebhook",
Handler: _PaymentCent_StripeGermanyWebhook_Handler, Handler: _PaymentCent_StripeGermanyWebhook_Handler,
}, },
{
MethodName: "StripeJapanWebhook",
Handler: _PaymentCent_StripeJapanWebhook_Handler,
},
{ {
MethodName: "AliCommonWebhook", MethodName: "AliCommonWebhook",
Handler: _PaymentCent_AliCommonWebhook_Handler, Handler: _PaymentCent_AliCommonWebhook_Handler,
@ -1415,6 +1501,10 @@ var PaymentCent_ServiceDesc = grpc_go.ServiceDesc{
MethodName: "QueryAntomPayByCheckoutSessionId", MethodName: "QueryAntomPayByCheckoutSessionId",
Handler: _PaymentCent_QueryAntomPayByCheckoutSessionId_Handler, Handler: _PaymentCent_QueryAntomPayByCheckoutSessionId_Handler,
}, },
{
MethodName: "ExpireStripePayByCheckoutSessionId",
Handler: _PaymentCent_ExpireStripePayByCheckoutSessionId_Handler,
},
{ {
MethodName: "CreateStripeCheckoutSession", MethodName: "CreateStripeCheckoutSession",
Handler: _PaymentCent_CreateStripeCheckoutSession_Handler, Handler: _PaymentCent_CreateStripeCheckoutSession_Handler,

View File

@ -38,11 +38,4 @@ TelNum = "18021272627"
Password = "Gy.123456" Password = "Gy.123456"
[service] [service]
IsHTTPS = false IsHTTPS = false
[zapLog]
level = "info"
filename = "logs/fiee_zap.log"
maxsize = 5
maxage = 30
maxbackups = 30

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -43,6 +43,6 @@ Webhookkey = "whsec_uOQpG6IZTqtfLuePIDtfLCGJPqedSCCN"
[zapLog] [zapLog]
level = "info" level = "info"
filename = "logs/fiee_zap.log" filename = "logs/fiee_zap.log"
maxsize = 5 max_size = 5
maxage = 30 max_age = 30
maxbackups = 30 max_backups = 30

View File

@ -43,6 +43,6 @@ Webhookkey = "whsec_Mol32WD1KcKHUdYsSwap0LR03q2g9qNY"
[zapLog] [zapLog]
level = "info" level = "info"
filename = "logs/fiee_zap.log" filename = "logs/fiee_zap.log"
maxsize = 5 max_size = 5
maxage = 30 max_age = 30
maxbackups = 30 max_backups = 30

View File

@ -44,6 +44,6 @@ Webhookkey = "whsec_uOQpG6IZTqtfLuePIDtfLCGJPqedSCCN"
[zapLog] [zapLog]
level = "info" level = "info"
filename = "logs/fiee_zap.log" filename = "logs/fiee_zap.log"
maxsize = 5 max_size = 5
maxage = 30 max_age = 30
maxbackups = 30 max_backups = 30

1
go.mod
View File

@ -106,6 +106,7 @@ require (
github.com/BurntSushi/toml v1.2.1 github.com/BurntSushi/toml v1.2.1
github.com/PuerkitoBio/goquery v1.8.1 github.com/PuerkitoBio/goquery v1.8.1
github.com/disintegration/imaging v1.6.2 github.com/disintegration/imaging v1.6.2
github.com/duke-git/lancet/v2 v2.3.8
github.com/envoyproxy/protoc-gen-validate v0.1.0 github.com/envoyproxy/protoc-gen-validate v0.1.0
github.com/fonchain/utils/security v0.0.0-00010101000000-000000000000 github.com/fonchain/utils/security v0.0.0-00010101000000-000000000000
github.com/fonchain/utils/voice v0.0.0-00010101000000-000000000000 github.com/fonchain/utils/voice v0.0.0-00010101000000-000000000000

2
go.sum
View File

@ -258,6 +258,8 @@ github.com/dubbogo/net v0.0.4/go.mod h1:1CGOnM7X3he+qgGNqjeADuE5vKZQx/eMSeUkpU3u
github.com/dubbogo/triple v1.0.9/go.mod h1:1t9me4j4CTvNDcsMZy6/OGarbRyAUSY0tFXGXHCp7Iw= github.com/dubbogo/triple v1.0.9/go.mod h1:1t9me4j4CTvNDcsMZy6/OGarbRyAUSY0tFXGXHCp7Iw=
github.com/dubbogo/triple v1.1.8 h1:yE+J3W1NTZCEPa1FoX+VWZH6UF1c0+A2MGfERlU2zbI= github.com/dubbogo/triple v1.1.8 h1:yE+J3W1NTZCEPa1FoX+VWZH6UF1c0+A2MGfERlU2zbI=
github.com/dubbogo/triple v1.1.8/go.mod h1:9pgEahtmsY/avYJp3dzUQE8CMMVe1NtGBmUhfICKLJk= github.com/dubbogo/triple v1.1.8/go.mod h1:9pgEahtmsY/avYJp3dzUQE8CMMVe1NtGBmUhfICKLJk=
github.com/duke-git/lancet/v2 v2.3.8 h1:dlkqn6Nj2LRWFuObNxttkMHxrFeaV6T26JR8jbEVbPg=
github.com/duke-git/lancet/v2 v2.3.8/go.mod h1:zGa2R4xswg6EG9I6WnyubDbFO/+A/RROxIbXcwryTsc=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=

View File

@ -31,7 +31,7 @@ func InitTasks() error {
err := cm.AddTask("refreshWorkApprovalStatus", "0 */5 * * * *", RefreshApprovalStatusTask) err := cm.AddTask("refreshWorkApprovalStatus", "0 */5 * * * *", RefreshApprovalStatusTask)
err = cm.AddTask("artistAutoConfirm", "0 */1 * * * *", ArtistAutoConfirmTask) err = cm.AddTask("artistAutoConfirm", "0 */1 * * * *", ArtistAutoConfirmTask)
err = cm.AddTask("refreshPublishStatus", "0 */5 * * * *", PublishTask) err = cm.AddTask("refreshPublishStatus", "0 */5 * * * *", PublishTask)
err = cm.AddTask("scheduledPublish", "0 */1 * * * *", ScheduledPublishTask) //FIXME err = cm.AddTask("scheduledPublish", "0 */30 * * * *", ScheduledPublishTask)
err = cm.AddTask("artistAutoConfirmAnalysis", "0 */1 * * * *", ArtistAutoConfirmAnalysisTask) err = cm.AddTask("artistAutoConfirmAnalysis", "0 */1 * * * *", ArtistAutoConfirmAnalysisTask)
err = cm.AddTask("refreshWorkAnalysisApprovalStatus", "0 */5 * * * *", RefreshWorkAnalysisApprovalStatusTask) err = cm.AddTask("refreshWorkAnalysisApprovalStatus", "0 */5 * * * *", RefreshWorkAnalysisApprovalStatusTask)

View File

@ -1,7 +1,6 @@
package cast package cast
import ( import (
"fmt"
"fonchain-fiee/api/cast" "fonchain-fiee/api/cast"
modelCast "fonchain-fiee/pkg/model/cast" modelCast "fonchain-fiee/pkg/model/cast"
"strings" "strings"
@ -103,44 +102,3 @@ func (w *Work) ExportExcelWorkList(data []*cast.WorkListResp_Info) (*excelize.Fi
return f, nil return f, nil
} }
func (w *Work) ExportPublishLogList(data []*cast.PublishLogInfo, savePath string) error {
f := excelize.NewFile()
defer f.Close()
sheetName := "Sheet1"
f.SetSheetName("Sheet1", sheetName)
headers := []string{
"状态", "失败原因", "提交发布时间", "发布平台", "发布方式", "作品类型", "作品标题", "艺人", "用户编号",
}
for col, h := range headers {
cell, _ := excelize.CoordinatesToCellName(col+1, 1)
f.SetCellValue(sheetName, cell, h)
}
for rowIndex, info := range data {
row := rowIndex + 2
platformName := modelCast.PlatformNameKv[info.PlatformID]
if platformName == "" {
platformName = fmt.Sprintf("%d", info.PlatformID)
}
values := []interface{}{
modelCast.PublishStatusMM[int(info.PublishMediaStatus)],
info.Detail,
info.CreatedAt,
modelCast.PlatformNameKv[info.PlatformID],
modelCast.PublishSourceMM[int(info.PublishSource)],
modelCast.WorkCategoryMM[int(info.WorkCategory)],
info.Title,
info.ArtistName,
info.ArtistSubNum,
}
for col, v := range values {
cell, _ := excelize.CoordinatesToCellName(col+1, row)
f.SetCellValue(sheetName, cell, v)
}
}
return f.SaveAs(savePath)
}

View File

@ -32,18 +32,6 @@ var WorkCategoryMM = map[int]string{
1: "图文", 1: "图文",
2: "视频", 2: "视频",
} }
var PublishSourceMM = map[int]string{
1: "手动发布",
2: "定时任务",
3: "手动发布",
}
var PublishStatusMM = map[int]string{
1: "进行中",
2: "发布成功",
3: "发布失败",
4: "发布异常",
}
var WorkCostTypeMM = map[int]string{ var WorkCostTypeMM = map[int]string{
1: "套餐", 1: "套餐",

View File

@ -31,10 +31,6 @@ func AnalysisRouter(r *gin.RouterGroup) {
analysis.POST("artist-metrics-single", serviceCast.ArtistMetricsDailyWindow) // 艺人指标日窗口 analysis.POST("artist-metrics-single", serviceCast.ArtistMetricsDailyWindow) // 艺人指标日窗口
analysis.POST("tobe-confirmed-list", serviceCast.TobeConfirmedList) // 待确认数据列表 analysis.POST("tobe-confirmed-list", serviceCast.TobeConfirmedList) // 待确认数据列表
analysis.POST("update-approval-id", serviceCast.UpdateWorkAnalysisApprovalID) // 更新作品分析审批ID analysis.POST("update-approval-id", serviceCast.UpdateWorkAnalysisApprovalID) // 更新作品分析审批ID
analysis.POST("update-pdf-url", serviceCast.UpdateWorkAnalysisPdfUrl) // 更新作品分析PDF链接
// 刷数据专用的导入接口
analysis.POST("import-batch", serviceCast.ImportWorkAnalysisBatch) // Excel 批量导入数据分析
analysis.POST("trigger-ayrshare-metrics", serviceCast.TriggerAyrshareMetricsCollector) // 手动触发 Ayrshare 指标采集任务 analysis.POST("trigger-ayrshare-metrics", serviceCast.TriggerAyrshareMetricsCollector) // 手动触发 Ayrshare 指标采集任务
} }
@ -53,10 +49,6 @@ func AnalysisRouter(r *gin.RouterGroup) {
competitiveReport.POST("count-by-work-uuids", serviceCast.CountCompetitiveReportByWorkUuids) // 根据作品UUID统计竞品报告数量 competitiveReport.POST("count-by-work-uuids", serviceCast.CountCompetitiveReportByWorkUuids) // 根据作品UUID统计竞品报告数量
competitiveReport.POST("export-list", serviceCast.ListCompetitiveReportExport) // 竞品报告列表导出 competitiveReport.POST("export-list", serviceCast.ListCompetitiveReportExport) // 竞品报告列表导出
competitiveReport.POST("export-single-list", serviceCast.ListCompetitiveReportSingleExport) // 竞品报告单个列表导出 competitiveReport.POST("export-single-list", serviceCast.ListCompetitiveReportSingleExport) // 竞品报告单个列表导出
competitiveReport.POST("import-pdf-batch", serviceCast.ImportPdfBatch) // 批量导入PDF下载、重命名、上传
// 刷竞品报告专用的导入接口
competitiveReport.POST("import-history-batch", serviceCast.ImportCompetitiveReportHistoryBatch) // Excel 批量刷写竞品报告历史数据
} }
// 员工任务相关路由需要App登录验证 // 员工任务相关路由需要App登录验证

View File

@ -20,9 +20,6 @@ func BundleRouter(r *gin.RouterGroup) {
{ {
bundleClientNoAuthRoute.POST("export/work-cast-info", bundle.ExportWorkCastInfo) bundleClientNoAuthRoute.POST("export/work-cast-info", bundle.ExportWorkCastInfo)
bundleClientNoAuthRoute.POST("export/bundle-price-info", bundle.ExportBundlePriceInfo) bundleClientNoAuthRoute.POST("export/bundle-price-info", bundle.ExportBundlePriceInfo)
bundleClientNoAuthRoute.POST("survey/is-send", bundle.IsSendSurvey)
bundleClientNoAuthRoute.POST("survey/bundleInfo", bundle.QuestionnaireSurveyBundleInfo)
bundleClientNoAuthRoute.POST("survey/create", bundle.QuestionnaireSurveyCreate)
} }
bundleClientRoute := bundleRoute.Group("system") bundleClientRoute := bundleRoute.Group("system")
{ {
@ -58,10 +55,6 @@ func BundleRouter(r *gin.RouterGroup) {
metrics.POST("export/balance-detail", bundle.MetricsBalanceDetailExport) metrics.POST("export/balance-detail", bundle.MetricsBalanceDetailExport)
metrics.POST("export/balance-metrics", bundle.BalanceMetricsExport) metrics.POST("export/balance-metrics", bundle.BalanceMetricsExport)
} }
survey := bundleClientRoute.Group("survey")
{
survey.POST("list", bundle.QuestionnaireSurveyList)
}
} }
bundleClientRouteV2 := bundleRoute.Group("system/v2") bundleClientRouteV2 := bundleRoute.Group("system/v2")

View File

@ -50,12 +50,11 @@ func MediaRouter(r *gin.RouterGroup) {
work.POST("import-batch", serviceCast.ImportWorkBatch) work.POST("import-batch", serviceCast.ImportWorkBatch)
work.POST("list-published", serviceCast.WorkListPublished) work.POST("list-published", serviceCast.WorkListPublished)
work.POST("update-work-script", serviceCast.UpdateWorkScript) work.POST("update-work-script", serviceCast.UpdateWorkScript)
work.POST("publish-log-list", serviceCast.PublishLogList)
work.Any("publish-log-list-export", serviceCast.PublishLogListExport)
} }
workNoAuth := noAuth.Group("work") workNoAuth := noAuth.Group("work")
{ {
workNoAuth.POST("cron-republish", serviceCast.CronRePublish) workNoAuth.POST("cron-republish", serviceCast.CronRePublish)
} }

View File

@ -68,15 +68,14 @@ func NewRouter() *gin.Engine {
} }
//账号模块 //账号模块
{ {
privateGroup.POST("user/register", account.UserRegister) //h5注册登录 privateGroup.POST("user/register", account.UserRegister) //h5注册登录
privateGroup.POST("user/login", account.UserLogin) //后台登录 privateGroup.POST("user/login", account.UserLogin) //后台登录
privateGroup.POST("user/send", account.SendMsg) //发送验证码 privateGroup.POST("user/send", account.SendMsg) //发送验证码
privateGroup.POST("user/send/no-slider", account.SendMsgNoSlider) //发送验证码(不验证滑块) privateGroup.POST("user/logout", account.UserLogout) //登出
privateGroup.POST("user/logout", account.UserLogout) //登出 privateGroup.POST("user/check/msg", account.CheckMsg) //校验验证码
privateGroup.POST("user/check/msg", account.CheckMsg) //校验验证码 privateGroup.POST("generate/captcha", account.GenerateCaptcha) //生成滑块验证码
privateGroup.POST("generate/captcha", account.GenerateCaptcha) //生成滑块验证码 privateGroup.POST("validate/captcha", account.ValidateCaptcha) //验证滑块验证码
privateGroup.POST("validate/captcha", account.ValidateCaptcha) //验证滑块验证码 privateGroup.POST("check/register", account.CheckRegister) //校验是否注册
privateGroup.POST("check/register", account.CheckRegister) //校验是否注册
acRoute := privateGroup.Group("/user") acRoute := privateGroup.Group("/user")
acRoute.Use(middleware.CheckLogin(service.AccountFieeProvider)) acRoute.Use(middleware.CheckLogin(service.AccountFieeProvider))
{ {

View File

@ -15,7 +15,6 @@ import (
"fonchain-fiee/pkg/utils" "fonchain-fiee/pkg/utils"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"strings"
"time" "time"
"github.com/fonchain_enterprise/utils/baidu" "github.com/fonchain_enterprise/utils/baidu"
@ -278,40 +277,6 @@ func dd(dateStr string) string {
} }
func isValidMainlandID(id string) bool {
id = strings.TrimSpace(strings.ToUpper(id))
if len(id) != 18 {
return false
}
for i := 0; i < 17; i++ {
if id[i] < '0' || id[i] > '9' {
return false
}
}
last := id[17]
if (last < '0' || last > '9') && last != 'X' {
return false
}
birthday := id[6:14]
birthTime, err := time.Parse("20060102", birthday)
if err != nil {
return false
}
if birthTime.After(time.Now()) {
return false
}
weights := []int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}
checkMap := "10X98765432"
sum := 0
for i := 0; i < 17; i++ {
sum += int(id[i]-'0') * weights[i]
}
checkCode := checkMap[sum%11]
return byte(checkCode) == last
}
// SendMsg 用户发送验证码 // SendMsg 用户发送验证码
func SendMsg(c *gin.Context) { func SendMsg(c *gin.Context) {
var req account.SendMsgRequest var req account.SendMsgRequest
@ -413,54 +378,6 @@ func SendMsg(c *gin.Context) {
//} //}
} }
// 用户发送验证码(不验证滑块)
func SendMsgNoSlider(c *gin.Context) {
var req account.SendMsgRequest
if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil {
service.Error(c, err)
return
}
req.Project = "fiee"
req.TelNum = req.Zone + req.TelNum
//todo 审核使用账号
if req.TelNum == "8618888888888" {
service.Success1(c, "发送成功", &account.SendMsgStatusResponse{})
return
}
if req.Zone != e.ZoneCn && req.Zone != "" {
// ============================== redis检查ip开始
ip := c.ClientIP()
fmt.Println("当前ip", ip, ";手机号:", req.TelNum, ";domain", req.Domain)
tempReq := &account.SendNationMsgRequest{
Domain: req.Domain,
TelNum: req.TelNum,
Project: req.Project,
SignNo: req.SignNo,
MId: req.MId,
Scope: req.Scope,
}
res, err := service.AccountFieeProvider.SendNationMsg(context.Background(), tempReq)
if err != nil {
service.Error(c, err)
return
}
service.Success1(c, "发送成功", res)
return
} else {
res, err := service.AccountFieeProvider.SendMsg(context.Background(), &req)
if err != nil {
service.Error(c, err)
return
}
service.Success1(c, "发送成功", res)
return
}
}
func RealName(c *gin.Context) { func RealName(c *gin.Context) {
var req account.RealNameRequest var req account.RealNameRequest
@ -471,14 +388,12 @@ func RealName(c *gin.Context) {
user := login.GetUserInfoFromC(c) user := login.GetUserInfoFromC(c)
req.Id = user.ID req.Id = user.ID
if req.DocumentType == 2 { if req.DocumentType == 2 {
if req.Nationality == "中国大陆" { if len(req.IdNumber) != 18 {
if !isValidMainlandID(req.IdNumber) { service.Error(c, errors.New("身份证号格式错误"))
service.Error(c, errors.New("身份证号格式错误")) return
return
}
} }
} else { } else {
if strings.TrimSpace(req.IdNumber) == "" { if req.IdNumber == "" {
service.Error(c, errors.New("证件号码不能为空")) service.Error(c, errors.New("证件号码不能为空"))
return return
} }
@ -505,8 +420,7 @@ func CheckMsg(c *gin.Context) {
req.TelNum = req.Zone + req.TelNum req.TelNum = req.Zone + req.TelNum
res, err := service.AccountFieeProvider.CheckMsg(context.Background(), &req) res, err := service.AccountFieeProvider.CheckMsg(context.Background(), &req)
if err != nil { if err != nil {
fmt.Println("CheckMsg error:", err) service.Error(c, err)
service.Error(c, errors.New("验证码错误"))
return return
} }

View File

@ -1,7 +1,6 @@
package ai package ai
import ( import (
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"fonchain-fiee/pkg/common/qwen" "fonchain-fiee/pkg/common/qwen"
@ -38,7 +37,7 @@ func AIVideoVL(ctx *gin.Context) {
return return
} }
Prompt := "请你详细描述视频和图片中的内容分别是什么,包括画面内容、人物动作、场景等。如果有配乐或背景音乐,请详细描述配乐的节奏、风格和情感特点" Prompt := "请你详细描述视频和图片中的内容分别是什么"
// 调用VL函数进行AI理解 // 调用VL函数进行AI理解
result, err := qwen.VL(req.Videos, req.Images, Prompt, req.Model) result, err := qwen.VL(req.Videos, req.Images, Prompt, req.Model)
@ -71,183 +70,10 @@ type CompetitorReportRequest struct {
Model string `json:"model"` // 可选的模型名称,默认使用 qwen3-vl-plus Model string `json:"model"` // 可选的模型名称,默认使用 qwen3-vl-plus
} }
// CompetitorReportData 竞品报告数据(用于返回给前端)
type CompetitorReportData struct {
HighlightAnalysis HighlightAnalysisData `json:"highlight_analysis"`
DataPerformance DataPerformanceData `json:"data_performance_analysis"`
OverallSummary string `json:"overall_summary_and_optimization"`
}
type HighlightAnalysisData struct {
Summary string `json:"summary"`
Points PointsData `json:"points"`
}
type PointsData struct {
Theme string `json:"theme"`
Narrative string `json:"narrative"`
Content string `json:"content"`
Copywriting string `json:"copywriting"`
Data string `json:"data"`
Music string `json:"music,omitempty"`
}
type DataPerformanceData struct {
Views string `json:"views"`
Completion string `json:"completion_rate,omitempty"`
Engagement string `json:"engagement"`
}
// CompetitorReportResponse 竞品报告响应数据 // CompetitorReportResponse 竞品报告响应数据
type CompetitorReportResponse struct { type CompetitorReportResponse struct {
ImageURL string `json:"image_url,omitempty"` // 生成的图片URL1024*1024非必须返回 ImageURL string `json:"image_url,omitempty"` // 生成的图片URL1024*1024非必须返回
Text string `json:"text,omitempty"` // 竞品报告文本内容,非必须返回 Text string `json:"text,omitempty"` // 竞品报告文本内容,非必须返回
JsonData *CompetitorReportData `json:"json_data,omitempty"` // 竞品报告JSON数据
}
// CompetitorReportJSON AI返回的JSON结构
type CompetitorReportJSON struct {
HighlightAnalysis HighlightAnalysis `json:"highlight_analysis"`
DataPerformance DataPerformance `json:"data_performance_analysis"`
OverallSummary string `json:"overall_summary_and_optimization"`
}
type HighlightAnalysis struct {
Summary string `json:"summary"`
Points Points `json:"points"`
}
type Points struct {
Theme string `json:"theme"`
Narrative string `json:"narrative"`
Content string `json:"content"`
Copywriting string `json:"copywriting"`
Data string `json:"data"`
Music string `json:"music,omitempty"`
}
type DataPerformance struct {
Views string `json:"views"`
Completion string `json:"completion_rate,omitempty"`
Engagement string `json:"engagement"`
}
// convertJSONToText 将 JSON 转换为纯文本格式
func convertJSONToText(data CompetitorReportJSON, isVideo bool) string {
var sb strings.Builder
// 一、亮点表现分析
sb.WriteString("一、亮点表现分析\n")
sb.WriteString(data.HighlightAnalysis.Summary)
sb.WriteString("\n\n")
sb.WriteString("1. 标题亮点:")
sb.WriteString(data.HighlightAnalysis.Points.Theme)
sb.WriteString("\n")
sb.WriteString("2. 题材亮点:")
sb.WriteString(data.HighlightAnalysis.Points.Narrative)
sb.WriteString("\n")
sb.WriteString("3. 内容亮点:")
sb.WriteString(data.HighlightAnalysis.Points.Content)
sb.WriteString("\n")
sb.WriteString("4. 文案亮点:")
sb.WriteString(data.HighlightAnalysis.Points.Copywriting)
sb.WriteString("\n")
sb.WriteString("5. 数据亮点:")
sb.WriteString(data.HighlightAnalysis.Points.Data)
sb.WriteString("\n")
if isVideo && data.HighlightAnalysis.Points.Music != "" {
sb.WriteString("6. 配乐亮点:")
sb.WriteString(data.HighlightAnalysis.Points.Music)
sb.WriteString("\n")
}
// 二、数据表现分析
sb.WriteString("\n二、数据表现分析\n")
sb.WriteString("1. 浏览量表现:")
sb.WriteString(data.DataPerformance.Views)
sb.WriteString("\n")
if isVideo && data.DataPerformance.Completion != "" {
sb.WriteString("2. 完播率表现:")
sb.WriteString(data.DataPerformance.Completion)
sb.WriteString("\n")
sb.WriteString("3. 点赞/分享/评论表现:")
} else {
sb.WriteString("2. 点赞/分享/评论表现:")
}
sb.WriteString(data.DataPerformance.Engagement)
sb.WriteString("\n")
// 三、整体总结及可优化建议
sb.WriteString("\n三、整体总结及可优化建议\n")
sb.WriteString(data.OverallSummary)
return sb.String()
}
// convertJSONToTextFromData 将 JSON 转换为纯文本格式(使用新的 CompetitorReportData 结构)
func convertJSONToTextFromData(data CompetitorReportData, isVideo bool) string {
var sb strings.Builder
// 一、亮点表现分析
sb.WriteString("一、亮点表现分析\n")
sb.WriteString(data.HighlightAnalysis.Summary)
sb.WriteString("\n\n")
sb.WriteString("1. 标题亮点:")
sb.WriteString(data.HighlightAnalysis.Points.Theme)
sb.WriteString("\n")
sb.WriteString("2. 题材亮点:")
sb.WriteString(data.HighlightAnalysis.Points.Narrative)
sb.WriteString("\n")
sb.WriteString("3. 内容亮点:")
sb.WriteString(data.HighlightAnalysis.Points.Content)
sb.WriteString("\n")
sb.WriteString("4. 文案亮点:")
sb.WriteString(data.HighlightAnalysis.Points.Copywriting)
sb.WriteString("\n")
sb.WriteString("5. 数据亮点:")
sb.WriteString(data.HighlightAnalysis.Points.Data)
sb.WriteString("\n")
if isVideo && data.HighlightAnalysis.Points.Music != "" {
sb.WriteString("6. 配乐亮点:")
sb.WriteString(data.HighlightAnalysis.Points.Music)
sb.WriteString("\n")
}
// 二、数据表现分析
sb.WriteString("\n二、数据表现分析\n")
sb.WriteString("1. 浏览量表现:")
sb.WriteString(data.DataPerformance.Views)
sb.WriteString("\n")
if isVideo && data.DataPerformance.Completion != "" {
sb.WriteString("2. 完播率表现:")
sb.WriteString(data.DataPerformance.Completion)
sb.WriteString("\n")
sb.WriteString("3. 点赞/分享/评论表现:")
} else {
sb.WriteString("2. 点赞/分享/评论表现:")
}
sb.WriteString(data.DataPerformance.Engagement)
sb.WriteString("\n")
// 三、整体总结及可优化建议
sb.WriteString("\n三、整体总结及可优化建议\n")
sb.WriteString(data.OverallSummary)
return sb.String()
} }
// AICompetitorReport 生成竞品报告接口 // AICompetitorReport 生成竞品报告接口
@ -275,7 +101,7 @@ func AICompetitorReport(ctx *gin.Context) {
} }
// 第一步调用AI理解视频/图片内容 // 第一步调用AI理解视频/图片内容
vlPrompt := "请你详细描述这些视频或者这些图片中的内容分别是什么,请详细描述,不要遗漏任何细节。如果有配乐或背景音乐,请详细描述配乐的节奏、风格和情感特点" vlPrompt := "请你详细描述这些视频或者这些图片中的内容分别是什么,请详细描述,不要遗漏任何细节"
vlResult, err := qwen.VL(req.Videos, req.Images, vlPrompt, req.Model) vlResult, err := qwen.VL(req.Videos, req.Images, vlPrompt, req.Model)
if err != nil { if err != nil {
// 检查是否是文件下载超时错误(内容过大) // 检查是否是文件下载超时错误(内容过大)
@ -317,43 +143,8 @@ func AICompetitorReport(ctx *gin.Context) {
if needText { if needText {
textChan = make(chan textResult, 1) textChan = make(chan textResult, 1)
go func() { go func() {
// 根据是否有视频来判断作品类型 // 构建文本生成提示词:理解内容 + 用户要求
isVideo := len(req.Videos) > 0 textPrompt := fmt.Sprintf("基于以下视频和图片的内容描述:\n%s\n\n请根据以下要求生成竞品报告注意不要输出markdown格式来进行排版请直接输出纯文本。只需要回复竞品报告的内容其他无关的内容不要输出输出的内容第一行不要标题直接输出竞品报告的正文即可\n我的要求是\n%s", vlContent, req.TextPrompt)
// 构建文本生成提示词:理解内容 + 用户要求JSON格式
// 重要必须明确要求使用英文标点符号确保返回的JSON符合规范
// 重要:必须基于内容给出分析性回复,即使没有提供具体数据
var textPrompt string
if isVideo {
textPrompt = fmt.Sprintf(`你必须严格输出以下JSON格式不要输出任何其他内容输出必须以 { 开头并以 } 结束
重要提示
1. 所有字符串值必须使用英文标点符号包括英文逗号, 英文句号. 英文冒号: 英文引号" 禁止使用中文标点符号
2. 即使没有提供具体数据也要基于视频和图片内容给出分析性回复禁止回复"未提供数据""暂无数据"等类似内容而应该根据内容分析数据表现如根据时长分析完播率潜力根据内容质量分析互动潜力等
3. 配乐亮点(music字段)禁止回复"未提供配乐信息""没有配乐信息"等类似内容即使没有识别到配乐也要根据视频整体风格和内容特点编写合理的配乐分析根据视频风格推断适合的配乐类型根据内容节奏分析配乐潜力等
基于以下视频和图片的内容描述
%s
用户要求仅作为内容参考不会改变JSON结构
%s
JSON结构是固定的请将内容填充到对应的value中禁止修改key禁止添加额外字段禁止输出任何说明文字
{"highlight_analysis":{"summary":"[78字以内的概述]","points":{"theme":"[标题亮点最多60字]","narrative":"[题材亮点最多60字]","content":"[内容亮点最多60字]","copywriting":"[文案亮点最多60字]","data":"[数据亮点最多60字]","music":"[配乐亮点仅视频最多60字]"}},"data_performance_analysis":{"views":"[浏览量表现最多60字]","completion_rate":"[完播率表现仅视频最多60字]","engagement":"[点赞/分享/评论表现最多60字]"},"overall_summary_and_optimization":"[整体总结及可优化建议最多300字]"}`, vlContent, req.TextPrompt)
} else {
textPrompt = fmt.Sprintf(`你必须严格输出以下JSON格式不要输出任何其他内容输出开头并以 }必须以 { 结束
重要提示
1. 所有字符串值必须使用英文标点符号包括英文逗号, 英文句号. 英文冒号: 英文引号" 禁止使用中文标点符号
2. 即使没有提供具体数据也要基于视频和图片内容给出分析性回复禁止回复"未提供数据""暂无数据"等类似内容而应该根据内容分析数据表现如根据内容质量分析互动潜力等
基于以下视频和图片的内容描述
%s
用户要求仅作为内容参考不会改变JSON结构
%s
JSON结构是固定的请将内容填充到对应的value中禁止修改key禁止添加额外字段禁止输出任何说明文字
{"highlight_analysis":{"summary":"[100字以内的概述]","points":{"theme":"[标题亮点最多60字]","narrative":"[题材亮点最多60字]","content":"[内容亮点最多60字]","copywriting":"[文案亮点最多60字]","data":"[数据亮点最多60字]"}},"data_performance_analysis":{"views":"[浏览量表现最多60字]","engagement":"[点赞/分享/评论表现最多60字]"},"overall_summary_and_optimization":"[整体总结及可优化建议最多300字]"}`, vlContent, req.TextPrompt)
}
chatReq, err := buildChatRequest(textPrompt, nil) chatReq, err := buildChatRequest(textPrompt, nil)
if err != nil { if err != nil {
@ -372,13 +163,7 @@ JSON结构是固定的请将内容填充到对应的value中禁止修改ke
return return
} }
// 打印 AI 返回的原始内容(用于调试) textChan <- textResult{text: chatResp.Choices[0].Message.Content}
aiText := chatResp.Choices[0].Message.Content
fmt.Println("========== AI 返回的原始内容 ==========")
fmt.Println(aiText)
fmt.Println("=========================================")
textChan <- textResult{text: aiText}
}() }()
} }
@ -387,7 +172,7 @@ JSON结构是固定的请将内容填充到对应的value中禁止修改ke
imageChan = make(chan imageResult, 1) imageChan = make(chan imageResult, 1)
go func() { go func() {
// 先请求聊天获取图片提示词 // 先请求聊天获取图片提示词
imagePromptText := fmt.Sprintf("基于以下视频和图片的内容描述:\n%s\n\n请根据以下要求生成竞品报告图片的提示词\n%s\n\n重要提示生成的图片内容中不要包含任何文字仅仅是根据内容生成一张配图即可", vlContent, req.ImagePrompt) imagePromptText := fmt.Sprintf("基于以下视频和图片的内容描述:\n%s\n\n请根据以下要求生成竞品报告图片的提示词\n%s", vlContent, req.ImagePrompt)
chatReq, err := buildChatRequest(imagePromptText, nil) chatReq, err := buildChatRequest(imagePromptText, nil)
if err != nil { if err != nil {
@ -482,29 +267,7 @@ JSON结构是固定的请将内容填充到对应的value中禁止修改ke
// 返回结果(只返回实际生成的内容) // 返回结果(只返回实际生成的内容)
result := CompetitorReportResponse{} result := CompetitorReportResponse{}
if needText { if needText {
// 将 JSON 解析为结构化数据 result.Text = textRes.text
fmt.Println("========== 开始解析 JSON ==========")
fmt.Println("原始内容是否以 { 开头:", strings.HasPrefix(strings.TrimSpace(textRes.text), "{"))
fmt.Println("原始内容前100字符:", strings.TrimSpace(textRes.text)[:min(100, len(strings.TrimSpace(textRes.text)))])
var jsonData CompetitorReportData
if err := json.Unmarshal([]byte(textRes.text), &jsonData); err != nil {
// 如果解析失败,直接报错
fmt.Println("========== JSON 解析失败 ==========")
fmt.Println("解析错误:", err)
fmt.Println("===================================")
service.Error(ctx, errors.New("AI生成格式错误请重试"))
return
} else {
fmt.Println("========== JSON 解析成功 ==========")
fmt.Println("Summary:", jsonData.HighlightAnalysis.Summary)
fmt.Println("==================================")
// 赋值结构体到 JsonData 中
result.JsonData = &jsonData
result.Text = convertJSONToTextFromData(jsonData, len(req.Videos) > 0)
}
} }
if needImage { if needImage {
result.ImageURL = imageRes.imageURL result.ImageURL = imageRes.imageURL

View File

@ -1,35 +0,0 @@
package model
type QuestionnairePDFData struct {
// 基本信息
CustomerNum string `json:"customerNum"`
CustomerName string `json:"customerName"`
BundleName string `json:"bundleName"`
BundleStartDate string `json:"bundleStartDate"`
BundleEndDate string `json:"bundleEndDate"`
VideoNum string `json:"videoNum"`
AccountNum string `json:"accountNum"`
ImagesNum string `json:"imagesNum"`
DataAnalysisNum string `json:"dataAnalysisNum"`
CompetitiveNum string `json:"competitiveNum"`
ValueAddVideoNum string `json:"valueAddVideoNum"`
// 评分1-5
Score1 int `json:"score1"`
Score2 int `json:"score2"`
Score3 int `json:"score3"`
Score4 int `json:"score4"`
Score5 int `json:"score5"`
Score6 int `json:"score6"`
Score7 int `json:"score7"`
// 意见
Opinion1 string `json:"opinion1"`
Opinion2 string `json:"opinion2"`
Opinion3 string `json:"opinion3"`
// 提交信息
Submitter string `json:"submitter"`
SubmissionDate string `json:"submissionDate"`
Address string `json:"address"`
}

View File

@ -1,136 +0,0 @@
package bundle
import (
"context"
"errors"
"fonchain-fiee/api/bundle"
"fonchain-fiee/pkg/service"
"fonchain-fiee/pkg/service/bundle/model"
"fonchain-fiee/pkg/service/upload"
"fonchain-fiee/pkg/utils"
"strconv"
"time"
m "fonchain-fiee/pkg/model"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
func IsSendSurvey(c *gin.Context) {
var req bundle.SendQuestionnaireSurveyRequest
if err := c.ShouldBindJSON(&req); err != nil {
service.Error(c, err)
return
}
res, err := service.BundleProvider.SendQuestionnaireSurvey(context.Background(), &req)
if err != nil {
service.Error(c, err)
return
}
service.Success(c, res)
}
func QuestionnaireSurveyList(c *gin.Context) {
var req bundle.GetQuestionnaireSurveyListRequest
if err := c.ShouldBindJSON(&req); err != nil {
service.Error(c, err)
return
}
res, err := service.BundleProvider.GetQuestionnaireSurveyList(context.Background(), &req)
if err != nil {
service.Error(c, err)
return
}
service.Success(c, res)
}
func QuestionnaireSurveyBundleInfo(c *gin.Context) {
var req bundle.GetQuestionnaireSurveyInfoRequest
if err := c.ShouldBindJSON(&req); err != nil {
service.Error(c, err)
return
}
res, err := service.BundleProvider.GetQuestionnaireSurveyInfo(context.Background(), &req)
if err != nil {
service.Error(c, err)
return
}
service.Success(c, res)
}
func QuestionnaireSurveyCreate(c *gin.Context) {
var req bundle.CreateQuestionnaireSurveyAnswerRequest
if err := c.ShouldBindJSON(&req); err != nil {
service.Error(c, err)
return
}
ip := c.ClientIP()
address, err := utils.GetAddressByIP(ip)
if err != nil {
service.Error(c, errors.New("获取地址失败"))
return
}
//if req.Longitude == "" || req.Latitude == "" {
// service.Error(c, errors.New("获取定位失败"))
// return
//}
//address, err := utils.ReverseGeo(req.Longitude, req.Latitude, "ZhCN")
//if err != nil {
// service.Error(c, errors.New("获取地址失败"))
// return
//}
surveyInfo, err := service.BundleProvider.GetQuestionnaireSurveyInfo(c, &bundle.GetQuestionnaireSurveyInfoRequest{UserTel: req.UserTel})
if err != nil {
service.Error(c, err)
return
}
templateDir := "./data/满意度调成报告模板.pdf"
outputPath := m.MediaPath + "questionnaire_" + uuid.NewString() + ".pdf"
err = utils.QuestionnaireSurveyPDF(templateDir, outputPath, &model.QuestionnairePDFData{
//CustomerNum: surveyInfo.BundleInfo.,
CustomerName: surveyInfo.UserName,
BundleName: surveyInfo.BundleInfo.BundleName,
BundleStartDate: surveyInfo.BundleInfo.StartAt,
BundleEndDate: surveyInfo.BundleInfo.ExpiredAt,
VideoNum: strconv.FormatInt(int64(surveyInfo.BundleInfo.BundleVideoNumber), 10),
AccountNum: strconv.FormatInt(int64(surveyInfo.BundleInfo.BundleAccountNumber), 10),
ImagesNum: strconv.FormatInt(int64(surveyInfo.BundleInfo.BundleImageNumber), 10),
DataAnalysisNum: strconv.FormatInt(int64(surveyInfo.BundleInfo.BundleDataNumber), 10),
CompetitiveNum: strconv.FormatInt(int64(surveyInfo.BundleInfo.BundleCompetitiveNumber), 10),
ValueAddVideoNum: strconv.FormatInt(int64(surveyInfo.BundleInfo.IncreaseVideoNumber), 10),
Score1: int(req.SurveyAnswer.BundleAccountScore),
Score2: int(req.SurveyAnswer.BundleAccountScore),
Score3: int(req.SurveyAnswer.BundleImageScore),
Score4: int(req.SurveyAnswer.BundleDataScore),
Score5: int(req.SurveyAnswer.IncreaseVideoScore),
Score6: int(req.SurveyAnswer.ServiceResponseSpeed),
Score7: int(req.SurveyAnswer.ServiceStaffProfessionalism),
Opinion1: req.SurveyFeedback.MeritsReview,
Opinion2: req.SurveyFeedback.SuggestionsorImprovements,
Opinion3: req.SurveyFeedback.AdditionalComments,
Submitter: surveyInfo.UserName,
SubmissionDate: time.Now().Format(time.DateOnly),
Address: address,
})
if err != nil {
service.Error(c, err)
return
}
outputUrl, ossErr := upload.PutBos(outputPath, upload.PdfType, true)
if ossErr != nil {
service.Error(c, err)
return
}
//service.Success(c, outputUrl)
//return
req.SurveyUrl = outputUrl
res, err := service.BundleProvider.CreateQuestionnaireSurveyAnswer(context.Background(), &req)
if err != nil {
service.Error(c, err)
return
}
service.Success(c, res)
}

View File

@ -492,26 +492,6 @@ func AutoCreateUserAndOrder(c *gin.Context) {
return return
} }
//生成发票
orderRecord, err := service.BundleProvider.GetOrderInfoByOrderNo(context.Background(), &bundle.GetOrderInfoByOrderNoReq{
OrderNo: unfinishInfo.OrderNo, //因为需求更新实际传入的是订单的uuid
})
if err != nil {
service.Error(c, err)
return
}
amountType := strconv.FormatInt(orderRecord.AmountType, 10)
applyTime := unfinishInfo.PayTime
payTime, _ := time.Parse("2006-01-02 15:04:05", applyTime)
payTimeString := payTime.Format("20060102")
fmt.Println("发票payTimeString :", payTimeString, "发票applyTime :", applyTime, "发票payTime :", payTime)
fmt.Println("发票时间数据获取完成")
err = createInvoice(orderRecord.UserId, orderRecord.UserNum, orderRecord.UserName, orderRecord.Address, orderRecord.Phone, orderRecord.BundleName, orderRecord.OrderNo, "1", amountType, orderRecord.TotalAmount, payTimeString, payTimeString, applyTime)
if err != nil {
service.Error(c, errors.New("生成发票失败"))
return
}
//如果是购买套餐 1:创建新的余量信息CreateBundleBalance 2 添加扩展记录BundleExtend //如果是购买套餐 1:创建新的余量信息CreateBundleBalance 2 添加扩展记录BundleExtend
_, err = service.BundleProvider.CreateBundleBalance(context.Background(), &bundle.CreateBundleBalanceReq{ _, err = service.BundleProvider.CreateBundleBalance(context.Background(), &bundle.CreateBundleBalanceReq{
UserId: int32(userResp.UserId), UserId: int32(userResp.UserId),

View File

@ -1,7 +1,6 @@
package cast package cast
import ( import (
"bytes"
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
@ -11,27 +10,21 @@ import (
"fonchain-fiee/api/bundle" "fonchain-fiee/api/bundle"
"fonchain-fiee/api/cast" "fonchain-fiee/api/cast"
"fonchain-fiee/pkg/cache" "fonchain-fiee/pkg/cache"
"fonchain-fiee/pkg/common/qwen"
"fonchain-fiee/pkg/e" "fonchain-fiee/pkg/e"
modelCast "fonchain-fiee/pkg/model/cast" modelCast "fonchain-fiee/pkg/model/cast"
"fonchain-fiee/pkg/model/login" "fonchain-fiee/pkg/model/login"
modelQwen "fonchain-fiee/pkg/model/qwen"
"fonchain-fiee/pkg/service" "fonchain-fiee/pkg/service"
"fonchain-fiee/pkg/service/bundle/common" "fonchain-fiee/pkg/service/bundle/common"
"fonchain-fiee/pkg/utils" "fonchain-fiee/pkg/utils"
"fonchain-fiee/pkg/utils/stime" "fonchain-fiee/pkg/utils/stime"
"path/filepath"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"time" "time"
"math/rand"
"dubbo.apache.org/dubbo-go/v3/common/constant" "dubbo.apache.org/dubbo-go/v3/common/constant"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/xuri/excelize/v2"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -97,305 +90,6 @@ func CreateWorkAnalysisCore(ctx *gin.Context, req *cast.CreateWorkAnalysisReq) (
return resp, nil return resp, nil
} }
// ImportWorkAnalysisBatch 通过 Excel 批量导入数据分析
// Excel 列顺序SubNum | ArtistName | SubmitTime | PeriodTypeFans | PeriodTypeViews | PeriodTypeLikes | PeriodTypeComments | PeriodTypeShares | IsRefreshData(1=false,2=true)
func ImportWorkAnalysisBatch(ctx *gin.Context) {
excelFile, err := ctx.FormFile("file")
if err != nil {
service.Error(ctx, err)
return
}
loginInfo := login.GetUserInfoFromC(ctx)
lockKey := fmt.Sprintf("import_work_analysis_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_work_analysis.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)
// 写入表头
_ = excelData.SetCellValue("Sheet1", "J1", "DateInt")
_ = excelData.SetCellValue("Sheet1", "K1", "ConfirmType")
_ = excelData.SetCellValue("Sheet1", "L1", "结果")
successCount := 0
for line, row := range rows {
if line == 0 {
continue // 跳过表头
}
if len(row) == 0 {
continue
}
// Excel 行号1-basedline=1 → 行号 2
cellL := fmt.Sprintf("L%d", line+1)
// 第一列SubNum
subNum := ""
if len(row) > 0 {
subNum = utils.CleanString(row[0])
}
if subNum == "" {
_ = excelData.SetCellValue("Sheet1", cellL, "SubNum 不能为空")
continue
}
// 第二列ArtistName
artistName := ""
if len(row) > 1 {
artistName = utils.CleanString(row[1])
}
// 第三列SubmitTime
submitTime := ""
if len(row) > 2 {
submitTime = row[2]
}
// 第四列PeriodTypeFans
var periodTypeFans uint32
if len(row) > 3 && utils.CleanString(row[3]) != "" {
v, _ := strconv.ParseUint(utils.CleanString(row[3]), 10, 32)
periodTypeFans = uint32(v)
}
// 第五列PeriodTypeViews
var periodTypeViews uint32
if len(row) > 4 && utils.CleanString(row[4]) != "" {
v, _ := strconv.ParseUint(utils.CleanString(row[4]), 10, 32)
periodTypeViews = uint32(v)
}
// 第六列PeriodTypeLikes
var periodTypeLikes uint32
if len(row) > 5 && utils.CleanString(row[5]) != "" {
v, _ := strconv.ParseUint(utils.CleanString(row[5]), 10, 32)
periodTypeLikes = uint32(v)
}
// 第七列PeriodTypeComments
var periodTypeComments uint32
if len(row) > 6 && utils.CleanString(row[6]) != "" {
v, _ := strconv.ParseUint(utils.CleanString(row[6]), 10, 32)
periodTypeComments = uint32(v)
}
// 第八列PeriodTypeShares
var periodTypeShares uint32
if len(row) > 7 && utils.CleanString(row[7]) != "" {
v, _ := strconv.ParseUint(utils.CleanString(row[7]), 10, 32)
periodTypeShares = uint32(v)
}
// 第九列IsRefreshData1 → false, 2 → true
isRefreshData := false
if len(row) > 8 && utils.CleanString(row[8]) == "2" {
isRefreshData = true
}
// 第十列DateIntYYYYMMDD 格式,直接从 Excel 读取)
var dateInt int32
if len(row) > 9 && utils.CleanString(row[9]) != "" {
v, _ := strconv.ParseInt(utils.CleanString(row[9]), 10, 32)
dateInt = int32(v)
}
// 第十一列ConfirmType1 艺人确认2 系统自动确认)
var confirmType int32
if len(row) > 10 && utils.CleanString(row[10]) != "" {
v, _ := strconv.ParseInt(utils.CleanString(row[10]), 10, 32)
confirmType = int32(v)
}
// 根据 subNum 查询艺人信息
subInfoResp, err := service.AccountFieeProvider.SubNumGetInfo(context.Background(), &accountFiee.SubNumGetInfoRequest{
SubNum: subNum,
Domain: "app",
})
if err != nil {
zap.L().Error("ImportWorkAnalysisBatch SubNumGetInfo", zap.Error(err), zap.String("subNum", subNum))
_ = excelData.SetCellValue("Sheet1", cellL, fmt.Sprintf("自媒体用户查询失败:%s", err.Error()))
continue
}
if subInfoResp == nil || subInfoResp.Id == 0 {
_ = excelData.SetCellValue("Sheet1", cellL, "自媒体用户不存在")
continue
}
artistID := uint64(subInfoResp.Id)
// 查询艺人套餐订单
balanceResp, err := service.BundleProvider.GetBundleBalanceByUserId(context.Background(), &bundle.GetBundleBalanceByUserIdReq{
UserId: int32(artistID),
})
if err != nil {
zap.L().Error("ImportWorkAnalysisBatch GetBundleBalanceByUserId", zap.Error(err), zap.Uint64("artistID", artistID))
_ = excelData.SetCellValue("Sheet1", cellL, fmt.Sprintf("获取套餐订单失败:%s", err.Error()))
continue
}
if balanceResp.OrderUUID == "" {
_ = excelData.SetCellValue("Sheet1", cellL, "订单不存在")
continue
}
// 若 artistName 为空则使用账号服务中的姓名
if artistName == "" {
artistName = subInfoResp.Name
}
// 将 submitTimeYYYY-MM-DD 00:00:00加随机 9~15 小时、0~59 分钟、0~59 秒,使提交时间更真实
if submitTime != "" {
if parsedTime, parseErr := time.Parse("2006-01-02 15:04:05", submitTime); parseErr == nil {
randomDuration := time.Duration(rand.Intn(7)+9)*time.Hour +
time.Duration(rand.Intn(60))*time.Minute +
time.Duration(rand.Intn(60))*time.Second
submitTime = parsedTime.Add(randomDuration).Format("2006-01-02 15:04:05")
}
}
// 提升到外部作用域,供 importReq 使用
var aiAnalysis string
var mediaAccountCount int32
var workVideoCount, workImageCount int32
// 调用 ArtistMetricsSeries 获取艺人指标数据并写入 Analysis
metricsReq := &cast.ArtistMetricsSeriesReq{
ArtistUUID: fmt.Sprint(subInfoResp.Id),
Date: dateInt,
PeriodTypeFans: periodTypeFans,
PeriodTypeViews: periodTypeViews,
PeriodTypeLikes: periodTypeLikes,
PeriodTypeComments: periodTypeComments,
PeriodTypeShares: periodTypeShares,
}
// 并行调用 ArtistMetricsSeries 和 GetArtistWorkStats
var metricsResp *cast.ArtistMetricsSeriesResp
var workStatsResp *cast.GetArtistWorkStatsResp
var metricsErr, workStatsErr error
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
metricsResp, metricsErr = service.CastProvider.ArtistMetricsSeries(context.Background(), metricsReq)
}()
go func() {
defer wg.Done()
workStatsResp, workStatsErr = service.CastProvider.GetArtistWorkStats(newCtx, &cast.GetArtistWorkStatsReq{
ArtistUuid: fmt.Sprint(subInfoResp.Id),
StatusUpdateTime: submitTime,
})
}()
wg.Wait()
if workStatsErr == nil && workStatsResp != nil {
mediaAccountCount = int32(workStatsResp.AccountCount)
workVideoCount = int32(workStatsResp.VideoCount)
workImageCount = int32(workStatsResp.ImageCount)
} else if workStatsErr != nil {
zap.L().Warn("ImportWorkAnalysisBatch GetArtistWorkStats failed", zap.Error(workStatsErr), zap.String("subNum", subNum))
}
if metricsErr != nil {
zap.L().Warn("ImportWorkAnalysisBatch ArtistMetricsSeries failed", zap.Error(metricsErr), zap.String("subNum", subNum))
} else if metricsResp != nil {
// 构建与 ArtistMetricsSeries HTTP 接口相同的 respMap
raw, _ := json.Marshal(metricsResp)
respMap := make(map[string]interface{})
_ = json.Unmarshal(raw, &respMap)
respMap["accountConsumptionNumber"] = mediaAccountCount
respMap["videoCount"] = workVideoCount
respMap["imageCount"] = workImageCount
// 调用 AI 生成分析文本
aiAnalysis, _ = generateArtistMetricsAnalysis(metricsResp)
if aiAnalysis == "" {
zap.L().Warn("ImportWorkAnalysisBatch generateArtistMetricsAnalysis returned empty", zap.String("subNum", subNum))
}
respMap["analysis"] = aiAnalysis
}
importReq := &cast.ImportWorkAnalysisReq{
SubNum: subNum,
ArtistID: fmt.Sprint(subInfoResp.Id),
ArtistName: artistName,
ArtistPhone: subInfoResp.TelNum,
BundleOrderUuid: balanceResp.OrderUUID,
SubmitTime: submitTime,
PeriodTypeFans: periodTypeFans,
PeriodTypeViews: periodTypeViews,
PeriodTypeLikes: periodTypeLikes,
PeriodTypeComments: periodTypeComments,
PeriodTypeShares: periodTypeShares,
IsRefreshData: isRefreshData,
Analysis: aiAnalysis,
MediaAccountCount: mediaAccountCount,
WorkVideoCount: workVideoCount,
WorkImageCount: workImageCount,
Views: 1,
Likes: 1,
Comments: 1,
Shares: 1,
FansCount: 1,
MostActiveDay: 1,
BestPostTime: 1,
Date: dateInt,
ConfirmType: confirmType,
}
importResp, err := service.CastProvider.ImportWorkAnalysis(newCtx, importReq)
if err != nil {
zap.L().Error("ImportWorkAnalysisBatch ImportWorkAnalysis", zap.Error(err), zap.String("subNum", subNum))
_ = excelData.SetCellValue("Sheet1", cellL, fmt.Sprintf("导入失败:%s", err.Error()))
continue
}
// 导入成功,将返回的 UUID 写入 L 列
_ = excelData.SetCellValue("Sheet1", cellL, importResp.Uuid)
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))
}
// UpdateWorkAnalysis 更新作品分析 // UpdateWorkAnalysis 更新作品分析
func UpdateWorkAnalysis(ctx *gin.Context) { func UpdateWorkAnalysis(ctx *gin.Context) {
var req *cast.UpdateWorkAnalysisReq var req *cast.UpdateWorkAnalysisReq
@ -867,72 +561,44 @@ func ArtistMetricsSeries(ctx *gin.Context) {
subNum = infoResp.SubNum subNum = infoResp.SubNum
} }
var subInfoResp *accountFiee.UserInfoResponse subInfoResp, err1 := service.AccountFieeProvider.SubNumGetInfo(context.Background(), &accountFiee.SubNumGetInfoRequest{
var subInfoErr error SubNum: subNum,
var workStatsResp *cast.GetArtistWorkStatsResp Domain: "app",
var metricsResp *cast.ArtistMetricsSeriesResp })
var workStatsErr, metricsErr error
wg := sync.WaitGroup{} if err1 != nil {
wg.Add(2) err1 = errors.New("自媒体用户查询失败")
service.Error(ctx, err1)
// 并行调用 SubNumGetInfo、ArtistMetricsSeries
go func() {
defer wg.Done()
subInfoResp, subInfoErr = service.AccountFieeProvider.SubNumGetInfo(context.Background(), &accountFiee.SubNumGetInfoRequest{
SubNum: subNum,
Domain: "app",
})
}()
go func() {
defer wg.Done()
metricsResp, metricsErr = service.CastProvider.ArtistMetricsSeries(context.Background(), req)
}()
wg.Wait()
if subInfoErr != nil {
service.Error(ctx, errors.New("自媒体用户查询失败"))
return return
} }
if subInfoResp == nil || subInfoResp.Id == 0 { if subInfoResp == nil || subInfoResp.Id == 0 {
service.Error(ctx, errors.New("自媒体用户不存在")) err1 = errors.New("自媒体用户不存在")
service.Error(ctx, err1)
return return
} }
req.ArtistUUID = fmt.Sprint(subInfoResp.Id) req.ArtistUUID = fmt.Sprint(subInfoResp.Id)
// 将 ArtistMetricsSeriesReq 中 int 类型日期YYYYMMDD格式化为时间字符串作为快照截止时间
statusUpdateTime := ""
if req.Date > 0 {
parsedDate, parseErr := time.Parse("20060102", strconv.Itoa(int(req.Date)))
if parseErr == nil {
statusUpdateTime = parsedDate.Add(17 * time.Hour).Format("2006-01-02 15:04:05")
}
}
newCtx := NewCtxWithUserInfo(ctx) newCtx := NewCtxWithUserInfo(ctx)
workStatsResp, workStatsErr = service.CastProvider.GetArtistWorkStats(newCtx, &cast.GetArtistWorkStatsReq{
ArtistUuid: req.ArtistUUID,
StatusUpdateTime: statusUpdateTime,
})
var accountConsumptionNumber int32 var accountConsumptionNumber int32
var videoCount int64 var videoCount int64
var imageCount int64 var imageCount int64
if workStatsErr == nil && workStatsResp != nil { dataListResp, err := service.CastProvider.ArtistDataList(newCtx, &cast.ArtistDataListReq{
accountConsumptionNumber = int32(workStatsResp.AccountCount) SubNum: subNum,
videoCount = workStatsResp.VideoCount Page: 1,
imageCount = workStatsResp.ImageCount PageSize: 1,
} else if workStatsErr != nil { })
zap.L().Warn("GetArtistWorkStats failed", zap.Error(workStatsErr), zap.String("artistUUID", req.ArtistUUID), zap.String("statusUpdateTime", statusUpdateTime)) if err == nil && dataListResp != nil && len(dataListResp.Data) > 0 && dataListResp.Data[0] != nil {
accountConsumptionNumber = dataListResp.Data[0].AccountConsumptionNumber
videoCount = dataListResp.Data[0].VideoCount
imageCount = dataListResp.Data[0].ImageCount
} }
if metricsErr != nil { resp, err := service.CastProvider.ArtistMetricsSeries(newCtx, req)
service.Error(ctx, errors.New("查询失败")) if err != nil {
err = errors.New("查询失败")
service.Error(ctx, err)
return return
} }
resp := metricsResp
raw, _ := json.Marshal(resp) raw, _ := json.Marshal(resp)
respMap := make(map[string]interface{}) respMap := make(map[string]interface{})
@ -941,101 +607,10 @@ func ArtistMetricsSeries(ctx *gin.Context) {
respMap["videoCount"] = videoCount respMap["videoCount"] = videoCount
respMap["imageCount"] = imageCount respMap["imageCount"] = imageCount
// 调用 AI 分析数据
analysis, err := generateArtistMetricsAnalysis(resp)
if err != nil {
zap.L().Error("生成艺人指标分析失败", zap.Error(err))
// AI 分析失败不影响主业务,返回空字符串
respMap["analysis"] = ""
} else {
respMap["analysis"] = analysis
}
service.Success(ctx, respMap) service.Success(ctx, respMap)
return return
} }
// generateArtistMetricsAnalysis 调用 AI 分析艺人指标数据
func generateArtistMetricsAnalysis(resp *cast.ArtistMetricsSeriesResp) (string, error) {
if resp == nil {
return "", errors.New("数据为空")
}
// 构建分析用的数据摘要
var dataSummary strings.Builder
dataSummary.WriteString("艺人各平台数据表现如下:\n")
// 粉丝数
if resp.FansSeries != nil {
dataSummary.WriteString(fmt.Sprintf("粉丝数总数: %d (周期类型: %d, 开始日期: %d, 结束日期: %d)\n",
resp.FansSeries.FansCount, resp.FansSeries.PeriodType, resp.FansSeries.StartDate, resp.FansSeries.EndDate))
}
// 播放量
if resp.ViewsSeries != nil {
dataSummary.WriteString(fmt.Sprintf("播放量总数: %d (周期类型: %d, 开始日期: %d, 结束日期: %d)\n",
resp.ViewsSeries.ViewsCount, resp.ViewsSeries.PeriodType, resp.ViewsSeries.StartDate, resp.ViewsSeries.EndDate))
}
// 点赞数
if resp.LikesSeries != nil {
dataSummary.WriteString(fmt.Sprintf("点赞数总数: %d (周期类型: %d, 开始日期: %d, 结束日期: %d)\n",
resp.LikesSeries.LikesCount, resp.LikesSeries.PeriodType, resp.LikesSeries.StartDate, resp.LikesSeries.EndDate))
}
// 评论数
if resp.CommentsSeries != nil {
dataSummary.WriteString(fmt.Sprintf("评论数总数: %d (周期类型: %d, 开始日期: %d, 结束日期: %d)\n",
resp.CommentsSeries.CommentsCount, resp.CommentsSeries.PeriodType, resp.CommentsSeries.StartDate, resp.CommentsSeries.EndDate))
}
// 分享数
if resp.SharesSeries != nil {
dataSummary.WriteString(fmt.Sprintf("分享数总数: %d (周期类型: %d, 开始日期: %d, 结束日期: %d)\n",
resp.SharesSeries.SharesCount, resp.SharesSeries.PeriodType, resp.SharesSeries.StartDate, resp.SharesSeries.EndDate))
}
// 最佳发布时间
if resp.BestPostTime != nil {
dataSummary.WriteString(fmt.Sprintf("最佳发布时间: %s\n", resp.BestPostTime.DetailJSON))
}
// 最活跃日期
if resp.MostActiveDay != nil {
dataSummary.WriteString(fmt.Sprintf("最活跃日期: %s\n", resp.MostActiveDay.DetailJSON))
}
// 构建 prompt
prompt := fmt.Sprintf(`根据以下艺人各平台运营数据分析各平台数据表现结合相关数据简要表述优点文字内容在150-200字之间标点符号不计入字数回复时不需要返回具体字数。注意回复时请使用平台名称如TIKTOK、INS等而非数字。重要不要逐一列举所有平台名称只需提及有亮点的平台即可\n%s`, dataSummary.String())
// 调用 AI
req := modelQwen.ChatRequest{
Model: "qwen-plus",
Messages: []modelQwen.Message{
{
Role: "user",
Content: []modelQwen.Content{
{
Type: "text",
Text: prompt,
},
},
},
},
}
respAI, err := qwen.Chat(req)
if err != nil {
return "", err
}
if respAI == nil || len(respAI.Choices) == 0 {
return "", errors.New("AI 返回结果为空")
}
return respAI.Choices[0].Message.Content, nil
}
// ArtistMetricsDailyWindow 艺人指标日窗口 // ArtistMetricsDailyWindow 艺人指标日窗口
func ArtistMetricsDailyWindow(ctx *gin.Context) { func ArtistMetricsDailyWindow(ctx *gin.Context) {
var req *cast.ArtistMetricsDailyWindowReq var req *cast.ArtistMetricsDailyWindowReq
@ -1125,24 +700,6 @@ func UpdateWorkAnalysisApprovalID(ctx *gin.Context) {
return return
} }
// UpdateWorkAnalysisPdfUrl 更新作品分析PDF链接
func UpdateWorkAnalysisPdfUrl(ctx *gin.Context) {
var req *cast.UpdateWorkAnalysisReq
var err error
if err = ctx.ShouldBind(&req); err != nil {
service.Error(ctx, err)
return
}
newCtx := NewCtxWithUserInfo(ctx)
_, err = service.CastProvider.UpdateWorkAnalysisPdfUrl(newCtx, req)
if err != nil {
service.Error(ctx, err)
return
}
service.Success(ctx, nil)
return
}
type CheckBundleBalanceReq struct { type CheckBundleBalanceReq struct {
ArtistID string `protobuf:"bytes,4,opt,name=artistID,proto3" json:"artistID"` // 艺人ID ArtistID string `protobuf:"bytes,4,opt,name=artistID,proto3" json:"artistID"` // 艺人ID
BalanceType modelCast.BalanceTypeEnum `json:"balanceType"` // 套餐类型 BalanceType modelCast.BalanceTypeEnum `json:"balanceType"` // 套餐类型

View File

@ -1,126 +0,0 @@
package cast
import (
"context"
"errors"
"fmt"
"strings"
"time"
"fonchain-fiee/api/cast"
"fonchain-fiee/pkg/cache"
logicCast "fonchain-fiee/pkg/logic/cast"
"fonchain-fiee/pkg/model/login"
"fonchain-fiee/pkg/service"
"fonchain-fiee/pkg/utils"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// PublishLogList 查询发布记录列表
func PublishLogList(ctx *gin.Context) {
var req cast.ListPublishLogReq
if err := ctx.ShouldBind(&req); err != nil {
service.Error(ctx, err)
return
}
resp, err := service.CastProvider.ListPublishLog(context.Background(), &req)
if err != nil {
service.Error(ctx, err)
return
}
service.Success(ctx, resp)
}
// PublishLogListExport 导出发布记录列表 Excel
func PublishLogListExport(ctx *gin.Context) {
var req cast.ListPublishLogReq
if err := ctx.ShouldBind(&req); err != nil {
service.Error(ctx, errors.New("绑定参数失败"))
return
}
loginInfo := login.GetUserInfoFromC(ctx)
newCtx := NewCtxWithUserInfo(ctx)
lockKey := "PublishLogListExport" + fmt.Sprint(loginInfo.ID)
replay := cache.RedisClient.SetNX(lockKey, time.Now().Unix(), time.Minute*30)
if !replay.Val() {
service.Error(ctx, errors.New("已有导出任务在进行中,请稍后再试"))
return
}
defer cache.RedisClient.Del(lockKey)
const batchSize = 5000
var allData []*cast.PublishLogInfo
page := int32(1)
if req.Page > 0 {
page = req.Page
}
originalPageSize := req.PageSize
req.PageSize = batchSize
zap.L().Info("开始分批导出发布记录列表", zap.Int32("batchSize", batchSize))
for {
req.Page = page
zap.L().Info("获取第 N 页数据", zap.Int32("page", page), zap.Int32("pageSize", req.PageSize))
resp, err := service.CastProvider.ListPublishLog(newCtx, &req)
if err != nil {
zap.L().Error("获取发布记录失败", zap.Error(err), zap.Int32("page", page))
service.Error(ctx, errors.New("获取发布记录失败"))
return
}
if resp == nil || len(resp.Data) == 0 {
zap.L().Info("没有更多数据", zap.Int32("page", page))
break
}
allData = append(allData, resp.Data...)
zap.L().Info("获取数据成功",
zap.Int32("page", page),
zap.Int("本批次数量", len(resp.Data)),
zap.Int("累计总数", len(allData)))
if len(resp.Data) < batchSize {
zap.L().Info("已到最后一页", zap.Int32("page", page))
break
}
page++
}
req.PageSize = originalPageSize
zap.L().Info("数据获取完成开始生成Excel", zap.Int("总数据量", len(allData)))
if len(allData) == 0 {
service.Error(ctx, errors.New("没有数据可导出"))
return
}
fileName := fmt.Sprintf("发布记录_%s.xlsx", time.Now().Format("20060102150405"))
filePath := fmt.Sprintf("./runtime/%d/%s", loginInfo.ID, fileName)
utils.CheckDirPath("./runtime/"+fmt.Sprint(loginInfo.ID), true)
var logicWork = new(logicCast.Work)
if err := logicWork.ExportPublishLogList(allData, filePath); err != nil {
zap.L().Error("生成Excel失败", zap.Error(err))
service.Error(ctx, err)
return
}
scheme := "http"
if ctx.GetHeader("X-Forwarded-Proto") == "https" {
scheme = "https"
}
exportUrl := fmt.Sprintf("%s://%s/api/fiee/static/%s", scheme, ctx.Request.Host, strings.Replace(filePath, "./runtime/", "", 1))
zap.L().Info("Excel导出成功", zap.String("文件名", fileName), zap.Int("记录数", len(allData)))
service.Success(ctx, map[string]interface{}{
"url": exportUrl,
})
}

View File

@ -1,7 +1,6 @@
package cast package cast
import ( import (
"bytes"
"context" "context"
"errors" "errors"
"fmt" "fmt"
@ -18,14 +17,12 @@ import (
"fonchain-fiee/pkg/service/upload" "fonchain-fiee/pkg/service/upload"
"fonchain-fiee/pkg/utils" "fonchain-fiee/pkg/utils"
"fonchain-fiee/pkg/utils/stime" "fonchain-fiee/pkg/utils/stime"
"math/rand"
"net/url" "net/url"
"os" "os"
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"unicode/utf8"
"github.com/google/uuid" "github.com/google/uuid"
@ -35,23 +32,15 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
) )
// CreateCompetitiveReportReqEx 扩展的竞品报告请求包含AI生成的JSON数据
type CreateCompetitiveReportReqEx struct {
*cast.CreateCompetitiveReportReq // 嵌入原有请求
ReportData utils.CompetitorReportData `json:"json_data"` // AI生成的竞品报告数据支持 reportData 和 json_data 两种字段名)
}
// CreateCompetitiveReport 创建竞品报告 // CreateCompetitiveReport 创建竞品报告
func CreateCompetitiveReport(ctx *gin.Context) { func CreateCompetitiveReport(ctx *gin.Context) {
var reqEx CreateCompetitiveReportReqEx var req *cast.CreateCompetitiveReportReq
var err error var err error
if err = ctx.ShouldBindJSON(&reqEx); err != nil { if err = ctx.ShouldBind(&req); err != nil {
service.Error(ctx, err) service.Error(ctx, err)
return return
} }
// 转换为原有类型 resp, err := CreateCompetitiveReportCore(ctx, req)
req := reqEx.CreateCompetitiveReportReq
resp, err := CreateCompetitiveReportCore(ctx, req, reqEx.ReportData)
if err != nil { if err != nil {
service.Error(ctx, err) service.Error(ctx, err)
return return
@ -60,7 +49,7 @@ func CreateCompetitiveReport(ctx *gin.Context) {
return return
} }
func CreateCompetitiveReportCore(ctx *gin.Context, req *cast.CreateCompetitiveReportReq, reportData utils.CompetitorReportData) (*cast.CreateCompetitiveReportResp, error) { func CreateCompetitiveReportCore(ctx *gin.Context, req *cast.CreateCompetitiveReportReq) (*cast.CreateCompetitiveReportResp, error) {
loginInfo := login.GetUserInfoFromC(ctx) loginInfo := login.GetUserInfoFromC(ctx)
lockKey := fmt.Sprintf("lock_create_competitive_report_%d", loginInfo.ID) lockKey := fmt.Sprintf("lock_create_competitive_report_%d", loginInfo.ID)
reply := cache.RedisClient.SetNX(lockKey, time.Now().Format("2006-01-02 15:04:05"), time.Second*5) reply := cache.RedisClient.SetNX(lockKey, time.Now().Format("2006-01-02 15:04:05"), time.Second*5)
@ -114,10 +103,8 @@ func CreateCompetitiveReportCore(ctx *gin.Context, req *cast.CreateCompetitiveRe
} }
req.BundleOrderUuid = resp1.OrderUUID req.BundleOrderUuid = resp1.OrderUUID
// 验证:必须传入 json_data使用模板方式生成PDF if req.ReportContent == "" && req.ImageUrl == "" {
hasReportData := reportData.OverallSummary != "" || reportData.HighlightAnalysis.Summary != "" return nil, errors.New("报告内容和图片不能同时为空")
if !hasReportData {
return nil, errors.New("参数错误")
} }
if req.ImageUrl != "" { if req.ImageUrl != "" {
@ -129,58 +116,43 @@ func CreateCompetitiveReportCore(ctx *gin.Context, req *cast.CreateCompetitiveRe
req.ImageUrl = newImageUrl req.ImageUrl = newImageUrl
} }
// 使用模板方式生成PDF if req.ReportContent != "" {
zap.L().Info("reportData内容", zap.Any("reportData", reportData)) today := time.Now().Format("20060102")
fmt.Println(reportData) timestamp := time.Now().UnixMicro()
pdfFileName := fmt.Sprintf("%s%s老师的竞品报告%d.pdf", today, req.ArtistName, timestamp)
pdfFilePath := "./runtime/report_pdf/" + pdfFileName
// 直接使用传入的结构体数据 _, err = utils.CheckDirPath("./runtime/report_pdf/", true)
competitorReportData := reportData if err != nil {
return nil, fmt.Errorf("创建PDF目录失败: %v", err)
// 如果有图片URL设置到reportData中
if req.ImageUrl != "" {
competitorReportData.ImageURL = req.ImageUrl
}
// 截断超长字段按AI生成的字段长度要求
competitorReportData = truncateCompetitorReportData(competitorReportData)
zap.L().Info("解析成功", zap.Any("competitorReportData", competitorReportData))
// 生成PDF文件名使用报告标题命名
pdfFileName := generateReportFileName(req.Title, req.ArtistName) + ".pdf"
pdfFilePath := "./runtime/report_pdf/" + pdfFileName
_, err = utils.CheckDirPath("./runtime/report_pdf/", true)
if err != nil {
return nil, fmt.Errorf("创建PDF目录失败: %v", err)
}
// 模板路径
templatePath := "./data/竞品报告pdf模板.pdf"
// 调用 GenerateCompetitorReportPDF
err = utils.GenerateCompetitorReportPDF(templatePath, pdfFilePath, competitorReportData)
if err != nil {
zap.L().Error("生成PDF失败", zap.Error(err))
return nil, errors.New("生成PDF失败")
}
defer func() {
if _, err := os.Stat(pdfFilePath); err == nil {
if err := os.Remove(pdfFilePath); err != nil {
zap.L().Warn("删除临时PDF文件失败", zap.String("path", pdfFilePath), zap.Error(err))
} else {
zap.L().Info("删除临时PDF文件成功", zap.String("path", pdfFilePath))
}
} }
}()
pdfUrl, uploadErr := upload.PutBos(pdfFilePath, upload.PdfType, true) fontPath := "./data/simfang.ttf"
if uploadErr != nil { err = utils.GeneratePDF(req.ReportContent, req.ImageUrl, pdfFilePath, fontPath)
zap.L().Error("上传PDF失败: %v", zap.Error(uploadErr)) if err != nil {
return nil, errors.New("上传PDF失败") zap.L().Error("生成PDF失败", zap.Error(err))
return nil, errors.New("生成PDF失败")
}
defer func() {
if _, err := os.Stat(pdfFilePath); err == nil {
if err := os.Remove(pdfFilePath); err != nil {
zap.L().Warn("删除临时PDF文件失败", zap.String("path", pdfFilePath), zap.Error(err))
} else {
zap.L().Info("删除临时PDF文件成功", zap.String("path", pdfFilePath))
}
}
}()
pdfUrl, uploadErr := upload.PutBos(pdfFilePath, upload.PdfType, true)
if uploadErr != nil {
zap.L().Error("上传PDF失败: %v", zap.Error(uploadErr))
return nil, errors.New("上传PDF失败")
}
req.PdfUrl = pdfUrl
} else {
req.PdfUrl = req.ImageUrl
} }
req.PdfUrl = pdfUrl
resp, err := service.CastProvider.CreateCompetitiveReport(newCtx, req) resp, err := service.CastProvider.CreateCompetitiveReport(newCtx, req)
if err != nil { if err != nil {
@ -336,94 +308,14 @@ func ImportCompetitiveReportBatch(ctx *gin.Context) {
temp.Title = nowDate + temp.ArtistName + "老师竞品报告" temp.Title = nowDate + temp.ArtistName + "老师竞品报告"
} }
} }
// 解析报告内容D列row[3]
// 构建竞品报告数据(新模板格式)
// D列row[3]):亮点表现分析 - 对应Summary字段
// E列row[4]):标题亮点
// F列row[5]):题材亮点
// G列row[6]):内容亮点
// H列row[7]):文案亮点
// I列row[8]):数据亮点
// J列row[9]):配乐亮点
// K列row[10]):浏览量
// L列row[11]):完播率
// M列row[12]):点赞/分享/评论
// N列row[13]):整体总结及可优化建议
// O列row[14]):图片
var competitorReportData utils.CompetitorReportData
// 解析亮点表现分析
highlightAnalysis := utils.HighlightAnalysisData{
Points: utils.PointsData{},
}
// 亮点表现分析摘要D列row[3]
if len(row) > 3 { if len(row) > 3 {
highlightAnalysis.Summary = utils.CleanString(row[3]) temp.ReportContent = row[3]
} }
// 标题亮点E列row[4] // 解析图片URLE列row[4]
if len(row) > 4 { if len(row) > 4 && utils.CleanString(row[4]) != "" {
highlightAnalysis.Points.Theme = utils.CleanString(row[4]) temp.ImageUrl = utils.CleanString(row[4])
}
// 题材亮点F列row[5]
if len(row) > 5 {
highlightAnalysis.Points.Narrative = utils.CleanString(row[5])
}
// 内容亮点G列row[6]
if len(row) > 6 {
highlightAnalysis.Points.Content = utils.CleanString(row[6])
}
// 文案亮点H列row[7]
if len(row) > 7 {
highlightAnalysis.Points.Copywriting = utils.CleanString(row[7])
}
// 数据亮点I列row[8]
if len(row) > 8 {
highlightAnalysis.Points.Data = utils.CleanString(row[8])
}
// 配乐亮点J列row[9]
if len(row) > 9 {
highlightAnalysis.Points.Music = utils.CleanString(row[9])
}
// 解析数据表现
dataPerformance := utils.DataPerformanceData{}
// 浏览量K列row[10]
if len(row) > 10 {
dataPerformance.Views = utils.CleanString(row[10])
}
// 完播率L列row[11]
if len(row) > 11 {
dataPerformance.Completion = utils.CleanString(row[11])
}
// 点赞/分享/评论M列row[12]
if len(row) > 12 {
dataPerformance.Engagement = utils.CleanString(row[12])
}
// 整体总结及可优化建议N列row[13]
if len(row) > 13 {
competitorReportData.OverallSummary = utils.CleanString(row[13])
}
// 图片URLO列row[14]
if len(row) > 14 && utils.CleanString(row[14]) != "" {
competitorReportData.ImageURL = utils.CleanString(row[14])
}
competitorReportData.HighlightAnalysis = highlightAnalysis
competitorReportData.DataPerformance = dataPerformance
// 截断超长字段按AI生成的字段长度要求
competitorReportData = truncateCompetitorReportData(competitorReportData)
// 验证标题长度数据库字段为varchar(50),按字符数计算)
if utf8.RuneCountInString(temp.Title) > 50 {
temp.Remark = "标题长度超出限制"
req.Reports = append(req.Reports, temp)
continue
} }
// 验证必填字段 // 验证必填字段
@ -433,133 +325,82 @@ func ImportCompetitiveReportBatch(ctx *gin.Context) {
continue continue
} }
// 验证亮点表现分析D列Summary // 验证报告内容和图片不能同时为空
if highlightAnalysis.Summary == "" { if temp.ReportContent == "" && temp.ImageUrl == "" {
temp.Remark = "亮点表现分析摘要不能为空" temp.Remark = "报告内容和图片不能同时为空"
req.Reports = append(req.Reports, temp) req.Reports = append(req.Reports, temp)
continue continue
} }
// 验证标题亮点E列 // 如果已经有错误信息跳过PDF生成
if highlightAnalysis.Points.Theme == "" { if temp.Remark != "" {
temp.Remark = "标题亮点不能为空"
req.Reports = append(req.Reports, temp) req.Reports = append(req.Reports, temp)
continue continue
} }
// 验证题材亮点F列 // 检查图片URL是否包含阿里云如果包含则下载并重新上传到OSS
if highlightAnalysis.Points.Narrative == "" { if temp.ImageUrl != "" {
temp.Remark = "题材亮点不能为空" newImageUrl, err := checkAndReuploadImageForReport(temp.ImageUrl)
req.Reports = append(req.Reports, temp)
continue
}
// 验证内容亮点G列
if highlightAnalysis.Points.Content == "" {
temp.Remark = "内容亮点不能为空"
req.Reports = append(req.Reports, temp)
continue
}
// 验证文案亮点H列
if highlightAnalysis.Points.Copywriting == "" {
temp.Remark = "文案亮点不能为空"
req.Reports = append(req.Reports, temp)
continue
}
// 验证数据亮点I列
if highlightAnalysis.Points.Data == "" {
temp.Remark = "数据亮点不能为空"
req.Reports = append(req.Reports, temp)
continue
}
// 验证浏览量K列
if dataPerformance.Views == "" {
temp.Remark = "浏览量不能为空"
req.Reports = append(req.Reports, temp)
continue
}
// 验证点赞/分享/评论M列
if dataPerformance.Engagement == "" {
temp.Remark = "点赞/分享/评论不能为空"
req.Reports = append(req.Reports, temp)
continue
}
// 验证整体总结及可优化建议N列
if competitorReportData.OverallSummary == "" {
temp.Remark = "整体总结及可优化建议不能为空"
req.Reports = append(req.Reports, temp)
continue
}
// 处理图片URL
if competitorReportData.ImageURL != "" {
newImageUrl, err := checkAndReuploadImageForReport(competitorReportData.ImageURL)
if err != nil { if err != nil {
temp.Remark = fmt.Sprintf("图片处理失败: %v", err) temp.Remark = fmt.Sprintf("图片处理失败: %v", err)
zap.L().Error("图片重新上传失败", zap.String("imageUrl", competitorReportData.ImageURL), zap.Error(err)) zap.L().Error("图片重新上传失败", zap.String("imageUrl", temp.ImageUrl), zap.Error(err))
req.Reports = append(req.Reports, temp) req.Reports = append(req.Reports, temp)
continue continue
} }
competitorReportData.ImageURL = newImageUrl
temp.ImageUrl = newImageUrl temp.ImageUrl = newImageUrl
} }
// 生成PDF并上传 // 如果提供了报告内容则生成PDF并上传
// 生成临时PDF文件路径使用报告标题命名 if temp.ReportContent != "" {
pdfFileName := generateReportFileName(temp.Title, temp.ArtistName) + ".pdf" // 生成临时PDF文件路径
pdfFilePath := "./runtime/report_pdf/" + pdfFileName today := time.Now().Format("20060102")
timestamp := time.Now().UnixMicro()
pdfFileName := fmt.Sprintf("%s%s老师的竞品报告%d.pdf", today, temp.ArtistName, timestamp)
pdfFilePath := "./runtime/report_pdf/" + pdfFileName
// 确保目录存在 // 确保目录存在
_, err = utils.CheckDirPath("./runtime/report_pdf/", true) _, err = utils.CheckDirPath("./runtime/report_pdf/", true)
if err != nil { if err != nil {
temp.Remark = fmt.Sprintf("创建PDF目录失败: %v", err) temp.Remark = fmt.Sprintf("创建PDF目录失败: %v", err)
req.Reports = append(req.Reports, temp) req.Reports = append(req.Reports, temp)
continue continue
} }
// 模板路径 // 生成PDF文件
templatePath := "./data/竞品报告pdf模板.pdf" fontPath := "./data/simfang.ttf"
err = utils.GeneratePDF(temp.ReportContent, temp.ImageUrl, pdfFilePath, fontPath)
if err != nil {
zap.L().Error("生成PDF失败", zap.Error(err))
temp.Remark = "生成PDF失败"
req.Reports = append(req.Reports, temp)
continue
}
// 使用新的 GenerateCompetitorReportPDF 生成PDF // 上传PDF到OSS
err = utils.GenerateCompetitorReportPDF(templatePath, pdfFilePath, competitorReportData) pdfUrl, uploadErr := upload.PutBos(pdfFilePath, upload.PdfType, true)
if err != nil { if uploadErr != nil {
zap.L().Error("生成PDF失败", zap.Error(err)) zap.L().Error("上传PDF失败", zap.Error(uploadErr))
temp.Remark = "生成PDF失败" temp.Remark = "上传PDF失败"
req.Reports = append(req.Reports, temp) req.Reports = append(req.Reports, temp)
continue // 清理临时PDF文件
} if _, err := os.Stat(pdfFilePath); err == nil {
os.Remove(pdfFilePath)
}
continue
}
// 将上传后的PDF链接设置到请求中
temp.PdfUrl = pdfUrl
// 上传PDF到OSS
pdfUrl, uploadErr := upload.PutBos(pdfFilePath, upload.PdfType, true)
if uploadErr != nil {
zap.L().Error("上传PDF失败", zap.Error(uploadErr))
temp.Remark = "上传PDF失败"
req.Reports = append(req.Reports, temp)
// 清理临时PDF文件 // 清理临时PDF文件
if _, err := os.Stat(pdfFilePath); err == nil { if _, err := os.Stat(pdfFilePath); err == nil {
os.Remove(pdfFilePath) if err := os.Remove(pdfFilePath); err != nil {
} zap.L().Warn("删除临时PDF文件失败", zap.String("path", pdfFilePath), zap.Error(err))
continue }
}
// 将上传后的PDF链接设置到请求中
temp.PdfUrl = pdfUrl
// 生成竞品报告正文
// 判断是否为视频如果有图片URL则为图片否则根据配乐亮点和完播率是否有值来判断
isVideo := competitorReportData.HighlightAnalysis.Points.Music != "" || competitorReportData.DataPerformance.Completion != ""
temp.ReportContent = utils.ConvertCompetitorReportToText(competitorReportData, isVideo)
// 清理临时PDF文件
if _, err := os.Stat(pdfFilePath); err == nil {
if err := os.Remove(pdfFilePath); err != nil {
zap.L().Warn("删除临时PDF文件失败", zap.String("path", pdfFilePath), zap.Error(err))
} }
} else {
// 如果没有报告内容则将图片URL设置为PDF URL
temp.PdfUrl = temp.ImageUrl
} }
req.Reports = append(req.Reports, temp) req.Reports = append(req.Reports, temp)
@ -592,7 +433,7 @@ func ImportCompetitiveReportBatch(ctx *gin.Context) {
// 通过请求对象找到对应的Excel行号 // 通过请求对象找到对应的Excel行号
if excelRowNum, ok := reportRowMap[reqReport]; ok { if excelRowNum, ok := reportRowMap[reqReport]; ok {
// 将错误信息写入最后一列F列 // 将错误信息写入最后一列F列
excelData.SetCellValue("Sheet1", fmt.Sprintf("P%d", excelRowNum), v.Remark) excelData.SetCellValue("Sheet1", fmt.Sprintf("F%d", excelRowNum), v.Remark)
hasValueRows[excelRowNum] = true hasValueRows[excelRowNum] = true
} }
} }
@ -1323,340 +1164,3 @@ func checkAndReuploadImageForReport(imageUrl string) (string, error) {
return compressUrl, nil return compressUrl, nil
} }
// generateReportFileName 生成竞品报告PDF文件名
// 始终使用标题+时间戳格式避免文件名冲突导致OSS覆盖
func generateReportFileName(title, artistName string) string {
timestamp := time.Now().UnixMicro()
// 如果有标题,使用标题+时间戳
if title != "" {
// 替换标题中的特殊字符为合法字符
fileName := strings.NewReplacer(
"/", "",
"\\", "",
":", "",
"*", "",
"?", "",
"\"", "",
"<", "",
">", "",
"|", "",
" ", "_",
).Replace(title)
// 限制文件名长度,避免过长(预留时间戳的空间)
if len(fileName) > 80 {
fileName = fileName[:80]
}
return fmt.Sprintf("%s_%d", fileName, timestamp)
}
// 没有标题时使用默认格式
today := time.Now().Format("20060102")
return fmt.Sprintf("%s%s老师的竞品报告%d", today, artistName, timestamp)
}
// ImportPdfBatch 批量导入 PDF下载、重命名、上传
func ImportPdfBatch(ctx *gin.Context) {
// 获取上传的Excel文件
excelFile, err := ctx.FormFile("file")
if err != nil {
service.Error(ctx, err)
return
}
loginInfo := login.GetUserInfoFromC(ctx)
lockKey := fmt.Sprintf("import_pdf_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/pdf_import"
_, err = utils.CheckDirPath(tempDir, true)
if err != nil {
service.Error(ctx, err)
return
}
// 生成文件名并保存文件
fileName := fmt.Sprintf("%d_pdf_import.xlsx", time.Now().UnixMicro())
excelPath := filepath.Join(tempDir, fileName)
if err = ctx.SaveUploadedFile(excelFile, excelPath); err != nil {
service.Error(ctx, err)
return
}
// 打开Excel文件
excelData, err := excelize.OpenFile(excelPath)
if err != nil {
service.Error(ctx, err)
return
}
defer excelData.Close()
// 解析Excel中的数据
rows, err := excelData.GetRows("Sheet1")
if err != nil {
service.Error(ctx, err)
return
}
// 生成结果文件URL
urlHost := config.AppConfig.System.FieeHost
urlResult := fmt.Sprintf("%s/api/fiee/static/pdf_import/%s", urlHost, fileName)
// 确保临时目录存在
_, err = utils.CheckDirPath("./runtime/pdf_import/", true)
if err != nil {
service.Error(ctx, err)
return
}
// 记录处理结果
successCount := 0
failCount := 0
for line, row := range rows {
// 跳过表头
if line == 0 {
continue
}
// 跳过空行
if len(row) == 0 {
continue
}
// A列PDF URL
pdfUrl := utils.CleanString(row[0])
// B列新文件名
newFileName := utils.CleanString(row[1])
// 验证必填字段
if pdfUrl == "" {
excelData.SetCellValue("Sheet1", fmt.Sprintf("D%d", line+1), "PDF URL不能为空")
failCount++
continue
}
if newFileName == "" {
excelData.SetCellValue("Sheet1", fmt.Sprintf("D%d", line+1), "新文件名不能为空")
failCount++
continue
}
// 下载 PDF保存到 runtime 目录,加入时间戳避免文件名冲突,上传后 URL 不包含 pdf_import 路径)
timestamp := time.Now().UnixMicro()
fullPath, err := utils.SaveUrlFileDisk(pdfUrl, "runtime", fmt.Sprintf("%s_%d.pdf", newFileName, timestamp))
if err != nil {
zap.L().Error("下载PDF失败", zap.String("pdfUrl", pdfUrl), zap.Error(err))
excelData.SetCellValue("Sheet1", fmt.Sprintf("D%d", line+1), fmt.Sprintf("下载PDF失败: %s", err.Error()))
failCount++
continue
}
// 上传到 OSS
uploadUrl, uploadErr := upload.PutBos(fullPath, upload.PdfType, true)
if uploadErr != nil {
zap.L().Error("上传PDF失败", zap.Error(uploadErr))
excelData.SetCellValue("Sheet1", fmt.Sprintf("D%d", line+1), fmt.Sprintf("上传PDF失败: %s", uploadErr.Error()))
failCount++
// 清理临时文件
if _, err := os.Stat(fullPath); err == nil {
os.Remove(fullPath)
}
continue
}
// 写入新URL到C列
excelData.SetCellValue("Sheet1", fmt.Sprintf("C%d", line+1), uploadUrl)
successCount++
zap.L().Info("PDF处理成功", zap.String("pdfUrl", pdfUrl), zap.String("newUrl", uploadUrl))
}
// 保存结果文件
resultPath := fmt.Sprintf("./runtime/pdf_import/%s", fileName)
if err = excelData.SaveAs(resultPath); err != nil {
service.Error(ctx, err)
return
}
// 返回结果
service.Success(ctx, map[string]interface{}{
"successCount": successCount,
"failCount": failCount,
"resultUrl": urlResult,
})
return
}
// ImportCompetitiveReportHistoryBatch 通过 Excel 批量刷写竞品报告历史数据
// Excel 列顺序ReportUuid | Title可为空| SubmitTime | ConfirmType | 结果(空,由接口写入)
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 列 ConfirmType第 5 列 结果)
_ = excelData.SetCellValue("Sheet1", "D1", "ConfirmType")
_ = excelData.SetCellValue("Sheet1", "E1", "结果")
successCount := 0
for line, row := range rows {
if line == 0 {
continue // 跳过表头
}
if len(row) == 0 {
continue
}
// Excel 行号1-basedline=1 → 行号 2
cellE := fmt.Sprintf("E%d", line+1)
// 第一列ReportUuid
reportUuid := ""
if len(row) > 0 {
reportUuid = utils.CleanString(row[0])
}
if reportUuid == "" {
_ = excelData.SetCellValue("Sheet1", cellE, "ReportUuid 不能为空")
continue
}
// 第二列Title可为空
title := ""
if len(row) > 1 {
title = utils.CleanString(row[1])
}
// 第三列SubmitTime
submitTime := ""
if len(row) > 2 {
submitTime = row[2]
}
// 第四列ConfirmType1 艺人确认2 系统自动确认)
var confirmType int32
if len(row) > 3 && utils.CleanString(row[3]) != "" {
v, _ := strconv.ParseInt(utils.CleanString(row[3]), 10, 32)
confirmType = int32(v)
}
// 将 submitTimeYYYY-MM-DD 00:00:00加随机 9~15 小时、0~59 分钟、0~59 秒,使提交时间更真实
if submitTime != "" {
if parsedTime, parseErr := time.Parse("2006-01-02 15:04:05", submitTime); parseErr == nil {
randomDuration := time.Duration(rand.Intn(7)+9)*time.Hour +
time.Duration(rand.Intn(60))*time.Minute +
time.Duration(rand.Intn(60))*time.Second
submitTime = parsedTime.Add(randomDuration).Format("2006-01-02 15:04:05")
}
}
// 构造请求
importReq := &cast.ImportCompetitiveReportHistoryReq{
ReportUuid: reportUuid,
SubmitTime: submitTime,
ConfirmType: confirmType,
}
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", cellE, fmt.Sprintf("导入失败:%s", err.Error()))
continue
}
// 导入成功,将返回的 report_uuid 写入第 5 列
_ = excelData.SetCellValue("Sheet1", cellE, 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 {
// 字段长度限制
const (
MaxSummary = 100 // 概述
MaxPointField = 60 // 标题/题材/内容/文案/数据/配乐亮点
MaxViews = 60 // 浏览量
MaxCompletion = 60 // 完播率
MaxEngagement = 60 // 点赞/分享/评论
MaxOverallSummary = 300 // 整体总结及可优化建议
)
// 截断亮点分析摘要
data.HighlightAnalysis.Summary = utils.TruncateTextByRune(data.HighlightAnalysis.Summary, MaxSummary)
// 截断各亮点字段
data.HighlightAnalysis.Points.Theme = utils.TruncateTextByRune(data.HighlightAnalysis.Points.Theme, MaxPointField)
data.HighlightAnalysis.Points.Narrative = utils.TruncateTextByRune(data.HighlightAnalysis.Points.Narrative, MaxPointField)
data.HighlightAnalysis.Points.Content = utils.TruncateTextByRune(data.HighlightAnalysis.Points.Content, MaxPointField)
data.HighlightAnalysis.Points.Copywriting = utils.TruncateTextByRune(data.HighlightAnalysis.Points.Copywriting, MaxPointField)
data.HighlightAnalysis.Points.Data = utils.TruncateTextByRune(data.HighlightAnalysis.Points.Data, MaxPointField)
data.HighlightAnalysis.Points.Music = utils.TruncateTextByRune(data.HighlightAnalysis.Points.Music, MaxPointField)
// 截断数据表现字段
data.DataPerformance.Views = utils.TruncateTextByRune(data.DataPerformance.Views, MaxViews)
data.DataPerformance.Completion = utils.TruncateTextByRune(data.DataPerformance.Completion, MaxCompletion)
data.DataPerformance.Engagement = utils.TruncateTextByRune(data.DataPerformance.Engagement, MaxEngagement)
// 截断整体总结
data.OverallSummary = utils.TruncateTextByRune(data.OverallSummary, MaxOverallSummary)
return data
}

View File

@ -189,14 +189,6 @@ func Test(ctx *gin.Context) {
return return
} }
if action == "addDecodoProxies" {
service.CastProvider.Tools(context.Background(), &cast.ToolsReq{Action: action, CfgLinks: []string{
"http://spd7b09ho0:sqx_1MlQ1rN5gfm2Dx@isp.decodo.com:10001",
"http://spd7b09ho0:sqx_1MlQ1rN5gfm2Dx@isp.decodo.com:10002",
"http://spd7b09ho0:sqx_1MlQ1rN5gfm2Dx@isp.decodo.com:10003",
}})
}
service.Success(ctx, "unknow") service.Success(ctx, "unknow")
return return
} }

View File

@ -710,7 +710,7 @@ func PostAS(ctx context.Context, workUuid string, publishSource cast.PublishSour
var err error var err error
//检查封面 //检查封面
_ = CheckImage(workUuid) _ = CheckImage(workUuid)
_, err = service.CastProvider.Publish(ctx, &cast.PublishReq{WorkUuids: []string{workUuid}, PublishSource: publishSource}) _, err = service.CastProvider.Publish(ctx, &cast.PublishReq{WorkUuids: []string{workUuid}})
if err != nil { if err != nil {
zap.L().Error("Publish err", zap.String("workUuid", workUuid), zap.Error(err)) zap.L().Error("Publish err", zap.String("workUuid", workUuid), zap.Error(err))
return err return err
@ -735,7 +735,7 @@ func PostAS(ctx context.Context, workUuid string, publishSource cast.PublishSour
return nil return nil
//return errors.New("作品无发布平台") //return errors.New("作品无发布平台")
} }
zap.L().Info("post 2", zap.Any("workUuid", workUuid), zap.Any("needPlatformIDs", needPlatformIDs)) zap.L().Info("post 2", zap.Any("workUuid", workUuid))
var mediaUrls []string var mediaUrls []string
var isVideo bool var isVideo bool
//var urlResp *UploadMediaResponse //var urlResp *UploadMediaResponse
@ -893,12 +893,11 @@ func PostAS(ctx context.Context, workUuid string, publishSource cast.PublishSour
} }
if _err != nil { if _err != nil {
_, errS := service.CastProvider.UpdateWorkPublishLog(context.Background(), &cast.UpdateWorkPublishLogReq{ _, errS := service.CastProvider.UpdateWorkPublishLog(context.Background(), &cast.UpdateWorkPublishLogReq{
WorkUuid: workUuid, WorkUuid: workUuid,
PlatformID: cast.PlatformIDENUM(platformID), PlatformID: cast.PlatformIDENUM(platformID),
Action: "post", Action: "post",
Detail: _err.Error(), Detail: _err.Error(),
PublishSource: publishSource, PublishSource: publishSource,
PublishMediaStatus: cast.PublishStatusENUM_PublishMediaStatus_EXCEPTION,
}) })
if errS != nil { if errS != nil {
zap.L().Error("PostAs UpdateWorkPublishLog err", zap.Error(errS), zap.Any("WorkUuid", workDetail.WorkUuid)) zap.L().Error("PostAs UpdateWorkPublishLog err", zap.Error(errS), zap.Any("WorkUuid", workDetail.WorkUuid))
@ -979,22 +978,12 @@ func PostAS(ctx context.Context, workUuid string, publishSource cast.PublishSour
Remark: string(postData), Remark: string(postData),
PublishSource: publishSource, PublishSource: publishSource,
}) })
_, _ = service.CastProvider.UpdateWorkPublishLog(context.Background(), &cast.UpdateWorkPublishLogReq{
PlatformID: cast.PlatformIDENUM(platformID),
WorkUuid: workUuid,
Action: "post",
Detail: string(postData),
PublishSource: publishSource,
PublishMediaStatus: publishStatus,
PublishMediaID: postResp.Posts[0].Id,
})
} }
zap.L().Info("post 10", zap.Any("workUuid", workUuid), zap.Any("platformID", platformID)) zap.L().Info("post 10", zap.Any("workUuid", workUuid), zap.Any("platformID", platformID))
_, err = service.CastProvider.UpdateWorkPlatformInfo(context.Background(), infoReq) _, err = service.CastProvider.UpdateWorkPlatformInfo(context.Background(), infoReq)
if err != nil { if err != nil {
zap.L().Error("Publish UpdateWorkPlatformInfo failed", zap.String("workUuid", workUuid), zap.Error(err)) zap.L().Error("Publish UpdateWorkPlatformInfo failed", zap.String("workUuid", workUuid), zap.Error(err))
} }
zap.L().Info("Publish Ayrshare PostResp", zap.Any("postResp", postResp)) zap.L().Info("Publish Ayrshare PostResp", zap.Any("postResp", postResp))
} }
zap.L().Info("post 5.1", zap.Any("workUuid", workUuid)) zap.L().Info("post 5.1", zap.Any("workUuid", workUuid))
@ -1025,7 +1014,6 @@ func RePublish(ctx *gin.Context) {
} }
func republishCore(gCtx *gin.Context, newCtx context.Context, req *cast.RePublishReq) error { func republishCore(gCtx *gin.Context, newCtx context.Context, req *cast.RePublishReq) error {
zap.L().Info("republishCore", zap.Any("req", req))
var resp *cast.RePublishResp var resp *cast.RePublishResp
var err error var err error
if len(req.PlatformIDs) == 0 && len(req.MediaAccountUuids) == 0 { if len(req.PlatformIDs) == 0 && len(req.MediaAccountUuids) == 0 {
@ -1985,15 +1973,6 @@ func RefreshPublish() error {
PlatformUuid: platformInfo.PlatformUuid, PlatformUuid: platformInfo.PlatformUuid,
}) })
_, _ = service.CastProvider.UpdateWorkPlatformInfo(context.Background(), infoReq) _, _ = service.CastProvider.UpdateWorkPlatformInfo(context.Background(), infoReq)
go func(work *cast.RefreshWorkListResp_Info, platform *cast.RefreshWorkListResp_Info_PlatformInfo, postResult string) {
_, _ = service.CastProvider.UpdateWorkPublishLog(context.Background(), &cast.UpdateWorkPublishLogReq{
PlatformID: platform.PlatformID,
WorkUuid: work.WorkUuid,
Action: "getPost",
Detail: postResult,
PublishMediaID: platform.PublishMediaID,
})
}(workInfo, platformInfo, string(dmData))
} else { } else {
// 未发布的先不管,不能标记失败 // 未发布的先不管,不能标记失败
/*infoReq.PlatformInfoData = append(infoReq.PlatformInfoData, &cast.PlatformInfo{ /*infoReq.PlatformInfoData = append(infoReq.PlatformInfoData, &cast.PlatformInfo{
@ -2016,16 +1995,15 @@ func RefreshPublish() error {
ProfileKey: workInfo.ProfileKey, ProfileKey: workInfo.ProfileKey,
}) })
go func(work *cast.RefreshWorkListResp_Info, platform *cast.RefreshWorkListResp_Info_PlatformInfo, post *aryshare.GetPostResponse) { go func() {
postBytes, _ := json.Marshal(post) postBytes, _ := json.Marshal(postResp)
_, _ = service.CastProvider.UpdateWorkPublishLog(context.Background(), &cast.UpdateWorkPublishLogReq{ _, _ = service.CastProvider.UpdateWorkPublishLog(context.Background(), &cast.UpdateWorkPublishLogReq{
PlatformID: platform.PlatformID, PlatformID: platformInfo.PlatformID,
WorkUuid: work.WorkUuid, WorkUuid: workInfo.WorkUuid,
Action: "getPost", Action: "getPost",
Detail: string(postBytes), Detail: string(postBytes),
PublishMediaID: platform.PublishMediaID,
}) })
}(workInfo, platformInfo, postResp) }()
if _err != nil { if _err != nil {
zap.L().Error("GetPost err", zap.Error(_err)) zap.L().Error("GetPost err", zap.Error(_err))

View File

@ -383,8 +383,7 @@ type CreateWorkAnalysisWithTaskUUIDReq struct {
type CreateCompetitiveReportWithTaskUUIDReq struct { type CreateCompetitiveReportWithTaskUUIDReq struct {
*cast.CreateCompetitiveReportReq *cast.CreateCompetitiveReportReq
AssignRecordsUUID string `json:"assignRecordsUUID"` AssignRecordsUUID string `json:"assignRecordsUUID"`
ReportData utils.CompetitorReportData `json:"json_data"` // AI生成的竞品报告数据
} }
func UpdateWorkImageWithTaskUUID(ctx *gin.Context) { func UpdateWorkImageWithTaskUUID(ctx *gin.Context) {
@ -576,7 +575,7 @@ func CreateCompetitiveReportWithTaskUUID(ctx *gin.Context) {
service.Error(ctx, errors.New("任务已中止")) service.Error(ctx, errors.New("任务已中止"))
return return
} }
resp, err := castService.CreateCompetitiveReportCore(ctx, req.CreateCompetitiveReportReq, req.ReportData) resp, err := castService.CreateCompetitiveReportCore(ctx, req.CreateCompetitiveReportReq)
if err != nil { if err != nil {
service.Error(ctx, err) service.Error(ctx, err)
return return

View File

@ -1,152 +0,0 @@
package utils
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strings"
"time"
)
const baiduIPLocationAPI = "https://api.map.baidu.com/location/ip"
// 建议把 ak 放配置;这里先保留你给的 key后续可改为从配置读取。
const baiduMapAK = "T8DGBYxbZ1iAeXx1J57McKigyHJHulPQ"
type baiduIPResp struct {
Status int `json:"status"`
Address string `json:"address"`
Content struct {
Address string `json:"address"`
} `json:"content"`
Message string `json:"message"`
}
type ReverseGeocodingReq struct {
Ak string `json:"ak"`
Coordtype string `json:"coordtype"`
RetCoordtype string `json:"retCoordtype"`
Location string `json:"location"`
Output string `json:"output"`
Language string `json:"language"`
}
type ReverseGeocodingRes struct {
Status int `json:"status"`
Result struct {
Location struct {
Lng float64 `json:"lng"`
Lat float64 `json:"lat"`
} `json:"location"`
FormattedAddress string `json:"formatted_address"`
Edz struct {
Name string `json:"name"`
} `json:"edz"`
Business string `json:"business"`
AddressComponent struct {
Country string `json:"country"`
CountryCodeIso string `json:"country_code_iso"`
CountryCodeIso2 string `json:"country_code_iso2"`
CountryCode int `json:"country_code"`
Province string `json:"province"`
City string `json:"city"`
CityLevel int `json:"city_level"`
District string `json:"district"`
Town string `json:"town"`
TownCode string `json:"town_code"`
Distance string `json:"distance"`
Direction string `json:"direction"`
Adcode string `json:"adcode"`
Street string `json:"street"`
StreetNumber string `json:"street_number"`
} `json:"addressComponent"`
} `json:"result"`
}
// ReverseGeo 经纬度逆编码
func ReverseGeo(longitude, latitude string, language string) (address string, err error) {
var reverseGeocodingReq ReverseGeocodingReq
reverseGeocodingReq.Ak = "3bAjKGA0pv7qvszGe98RsVZ04Ob5r4ZZ"
reverseGeocodingReq.Coordtype = "gcj02ll"
reverseGeocodingReq.Output = "json"
reverseGeocodingReq.RetCoordtype = "gcj02ll"
reverseGeocodingReq.Location = strings.Join([]string{latitude, longitude}, ",")
reverseGeocodingReq.Language = language
url := "https://api.map.baidu.com/reverse_geocoding/v3/?ak=" + reverseGeocodingReq.Ak + "&output=" + reverseGeocodingReq.Output + "&coordtype=" + reverseGeocodingReq.Coordtype + "&location=" + reverseGeocodingReq.Location + "&ret_coordtype=" + reverseGeocodingReq.RetCoordtype + "&language=" + reverseGeocodingReq.Language
resp, err := http.Get(url)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
var results ReverseGeocodingRes
err = json.Unmarshal(body, &results)
if err != nil {
return "", err
}
if results.Status != 0 {
address = "未知地址"
return address, err
}
address = results.Result.FormattedAddress
return address, nil
}
func GetAddressByIP(ip string) (string, error) {
ip = strings.TrimSpace(ip)
if ip == "" {
return "", fmt.Errorf("ip is empty")
}
q := url.Values{}
q.Set("ip", ip)
q.Set("coor", "bd09ll")
q.Set("ak", baiduMapAK)
reqURL := baiduIPLocationAPI + "?" + q.Encode()
client := &http.Client{Timeout: 5 * time.Second}
resp, err := client.Get(reqURL)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("baidu api status: %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
var r baiduIPResp
if err := json.Unmarshal(body, &r); err != nil {
return "", err
}
if r.Status != 0 {
if r.Message == "" {
r.Message = "baidu api error"
}
return "", fmt.Errorf("%s", r.Message)
}
if strings.TrimSpace(r.Content.Address) != "" {
return r.Content.Address, nil
}
if strings.TrimSpace(r.Address) != "" {
return r.Address, nil
}
return "", nil
}

View File

@ -3,21 +3,14 @@ package utils
import ( import (
"errors" "errors"
"fmt" "fmt"
"fonchain-fiee/pkg/service/bundle/model"
"image"
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"time"
"unicode" "unicode"
"unicode/utf8"
"github.com/phpdave11/gofpdf" "github.com/phpdave11/gofpdf"
"github.com/signintech/gopdf"
"go.uber.org/zap"
) )
// cleanTextForPDF 清理文本移除PDF不支持的字符如emoji // cleanTextForPDF 清理文本移除PDF不支持的字符如emoji
@ -179,715 +172,3 @@ func GeneratePDF(text, imageURL, outputPath, fontPath string) error {
return nil return nil
} }
// CompetitorReportData 竞品报告数据
type CompetitorReportData struct {
HighlightAnalysis HighlightAnalysisData `json:"highlight_analysis"`
DataPerformance DataPerformanceData `json:"data_performance_analysis"`
OverallSummary string `json:"overall_summary_and_optimization"`
ImageURL string `json:"image_url"` // 图片URL如果有图片则生成单独一页PDF
}
type HighlightAnalysisData struct {
Summary string `json:"summary"`
Points PointsData `json:"points"`
}
type PointsData struct {
Theme string `json:"theme"`
Narrative string `json:"narrative"`
Content string `json:"content"`
Copywriting string `json:"copywriting"`
Data string `json:"data"`
Music string `json:"music,omitempty"`
}
type DataPerformanceData struct {
Views string `json:"views"`
Completion string `json:"completion_rate,omitempty"`
Engagement string `json:"engagement"`
}
// GenerateCompetitorReportPDF 生成竞品报告PDF
// 参数:
// - templatePath: 模板文件路径(保留参数以兼容现有调用,传空则不使用模板)
// - outputPath: 输出PDF路径
// - data: 竞品报告数据
//
// 返回: 错误信息
func GenerateCompetitorReportPDF(templatePath, outputPath string, data CompetitorReportData) error {
fmt.Println("================================templatePath:", templatePath)
fmt.Println("================================outputPath:", outputPath)
pdf := gopdf.GoPdf{}
pdf.Start(gopdf.Config{PageSize: *gopdf.PageSizeA4})
// 如果有模板路径,则导入模板
if templatePath != "" {
err := pdf.ImportPagesFromSource(templatePath, "/MediaBox")
if err != nil {
return fmt.Errorf("无法导入页面: %v", err)
}
}
// 获取模板文件的总页数(如果有模板)
totalPages := pdf.GetNumberOfPages()
fmt.Printf("模板文件的总页数: %d\n", totalPages)
// 确定字体路径
var fontPath string
if templatePath != "" {
dir := filepath.Dir(templatePath)
fontPath = filepath.Join(dir, "simfang.ttf")
if _, err := os.Stat(fontPath); err != nil {
fontPath = filepath.Join("data", "simfang.ttf")
}
} else {
fontPath = filepath.Join("data", "simfang.ttf")
}
fmt.Printf("字体文件路径: %s\n", fontPath)
// 加载中文字体
ttfErr := pdf.AddTTFFont("simfang", fontPath)
if ttfErr != nil {
zap.L().Error("加载字体失败", zap.String("fontPath", fontPath), zap.Error(ttfErr))
return fmt.Errorf("加载中文字体失败: %v", ttfErr)
}
// 设置字体和字号
err := pdf.SetFont("simfang", "", 10)
if err != nil {
return fmt.Errorf("设置字体失败: %v", err)
}
// 行高15pt
lineHeight := 15.0
// 如果有内容要写入,确保在第一页
if totalPages > 0 || (data.HighlightAnalysis.Summary != "" || data.OverallSummary != "") {
pdf.SetPage(1)
// 概述 - 使用逐行写入一行最多35个字
pdf.SetXY(200, 104)
summaryLines := splitTextByRune(cleanTextForPDF(data.HighlightAnalysis.Summary), 35.0)
for i, line := range summaryLines {
pdf.SetXY(200, 104+float64(i)*lineHeight)
pdf.Cell(nil, line)
}
// 标题亮点 - 一行最多9个字
pdf.SetXY(200, 184)
themeLines := splitTextByRune(cleanTextForPDF(data.HighlightAnalysis.Points.Theme), 9.0)
for i, line := range themeLines {
pdf.SetXY(200, 184+float64(i)*lineHeight)
pdf.Cell(nil, line)
}
// 题材亮点 - 一行最多9个字
pdf.SetXY(330, 184)
narrativeLines := splitTextByRune(cleanTextForPDF(data.HighlightAnalysis.Points.Narrative), 9.0)
for i, line := range narrativeLines {
pdf.SetXY(330, 184+float64(i)*lineHeight)
pdf.Cell(nil, line)
}
// 内容亮点 - 一行最多9个字
pdf.SetXY(460, 184)
contentLines := splitTextByRune(cleanTextForPDF(data.HighlightAnalysis.Points.Content), 9.0)
for i, line := range contentLines {
pdf.SetXY(460, 184+float64(i)*lineHeight)
pdf.Cell(nil, line)
}
// 文案亮点 - 一行最多9个字
pdf.SetXY(200, 323)
copywritingLines := splitTextByRune(cleanTextForPDF(data.HighlightAnalysis.Points.Copywriting), 9.0)
for i, line := range copywritingLines {
pdf.SetXY(200, 323+float64(i)*lineHeight)
pdf.Cell(nil, line)
}
// 数据亮点 - 一行最多9个字
pdf.SetXY(330, 323)
dataLines := splitTextByRune(cleanTextForPDF(data.HighlightAnalysis.Points.Data), 9.0)
for i, line := range dataLines {
pdf.SetXY(330, 323+float64(i)*lineHeight)
pdf.Cell(nil, line)
}
// 配乐亮点(仅视频) - 一行最多9个字
if data.HighlightAnalysis.Points.Music != "" {
pdf.SetXY(460, 323)
musicLines := splitTextByRune(cleanTextForPDF(data.HighlightAnalysis.Points.Music), 9.0)
for i, line := range musicLines {
pdf.SetXY(460, 323+float64(i)*lineHeight)
pdf.Cell(nil, line)
}
}
// 浏览量 - 一行最多35个字
pdf.SetXY(200, 474)
viewsLines := splitTextByRune(cleanTextForPDF(data.DataPerformance.Views), 35.0)
for i, line := range viewsLines {
pdf.SetXY(200, 474+float64(i)*lineHeight)
pdf.Cell(nil, line)
}
// 完播率 - 一行最多35个字
pdf.SetXY(200, 539)
if data.DataPerformance.Completion != "" {
completionLines := splitTextByRune(cleanTextForPDF(data.DataPerformance.Completion), 35.0)
for i, line := range completionLines {
pdf.SetXY(200, 539+float64(i)*lineHeight)
pdf.Cell(nil, line)
}
}
// 点赞/分享/评论 - 一行最多35个字
pdf.SetXY(200, 600)
engagementLines := splitTextByRune(cleanTextForPDF(data.DataPerformance.Engagement), 35.0)
for i, line := range engagementLines {
pdf.SetXY(200, 600+float64(i)*lineHeight)
pdf.Cell(nil, line)
}
// 整体总结及可优化建议 - 一行最多35个字
pdf.SetXY(200, 676)
overallSummaryLines := splitTextByRune(cleanTextForPDF(data.OverallSummary), 35.0)
for i, line := range overallSummaryLines {
pdf.SetXY(200, 676+float64(i)*lineHeight)
pdf.Cell(nil, line)
}
}
// 如果有图片URL添加新页面并居中显示图片
if data.ImageURL != "" {
// 添加新页面
pdf.AddPage()
// 下载图片
resp, err := http.Get(data.ImageURL)
if err != nil {
return fmt.Errorf("下载图片失败: %v", err)
}
defer resp.Body.Close()
imageData, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("读取图片数据失败: %v", err)
}
// 解析URL获取文件扩展名
u, err := url.Parse(data.ImageURL)
if err != nil {
return fmt.Errorf("图片链接解析错误: %v", err)
}
fileExt := filepath.Ext(u.Path)
if fileExt == "" {
fileExt = ".jpg"
}
// 保存到临时文件
tmpFile, err := os.CreateTemp("", "pdf_image_*"+fileExt)
if err != nil {
return fmt.Errorf("创建临时文件失败: %v", err)
}
defer os.Remove(tmpFile.Name())
defer tmpFile.Close()
_, err = tmpFile.Write(imageData)
if err != nil {
return fmt.Errorf("写入临时文件失败: %v", err)
}
tmpFile.Close()
// 使用 image 包获取图片原始尺寸
imgFile, err := os.Open(tmpFile.Name())
if err != nil {
return fmt.Errorf("打开图片文件失败: %v", err)
}
defer imgFile.Close()
config, format, err := image.DecodeConfig(imgFile)
if err != nil {
return fmt.Errorf("获取图片尺寸失败: %v", err)
}
_ = format // 忽略格式
// A4页面宽度595pt210mm高度842pt297mm
pageWidth := 595.0
pageHeight := 842.0
margin := 20.0
// 计算可用宽度
availableWidth := pageWidth - 2*margin
// 计算缩放后的图片尺寸保持宽高比宽度为可用宽度的80%
imageWidth := availableWidth * 0.8
originalWidth := float64(config.Width)
originalHeight := float64(config.Height)
imageHeight := (imageWidth / originalWidth) * originalHeight
// 计算居中位置
imageX := (pageWidth - imageWidth) / 2
imageY := (pageHeight - imageHeight) / 2
// 使用 ImageHolderByBytes 添加图片
imgH1, err := gopdf.ImageHolderByBytes(imageData)
if err != nil {
return fmt.Errorf("创建图片Holder失败: %v", err)
}
// 绘制图片
err = pdf.ImageByHolder(imgH1, imageX, imageY, &gopdf.Rect{W: imageWidth, H: imageHeight})
if err != nil {
return fmt.Errorf("绘制图片失败: %v", err)
}
}
// 生成新的 PDF
if err := pdf.WritePdf(outputPath); err != nil {
return fmt.Errorf("error writing final PDF: %v", err)
}
return nil
}
// getCharWidth 获取字符的宽度权重
// 英文字母、数字、英文符号返回 0.5,其他字符返回 1.0
func getCharWidth(r rune) float64 {
// 英文字母 (A-Z, a-z)
if (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') {
return 0.5
}
// 数字 (0-9)
if r >= '0' && r <= '9' {
return 0.5
}
// 英文符号
if (r >= 0x21 && r <= 0x2F) || // ! " # $ % & ' ( ) * + , - . /
(r >= 0x3A && r <= 0x40) || // : ; < = > ? @
(r >= 0x5B && r <= 0x60) || // [ \ ] ^ _ `
(r >= 0x7B && r <= 0x7E) { // { | } ~
return 0.5
}
return 1.0
}
// splitTextByRune 将文本按指定字符宽度拆分成多行
// 按每行最大宽度拆分,英文字母/数字/英文符号按0.5计算其他按1计算
func splitTextByRune(text string, maxWidth float64) []string {
if text == "" {
return []string{}
}
runes := []rune(text)
var lines []string
currentLine := ""
currentWidth := 0.0
for _, r := range runes {
charWidth := getCharWidth(r)
// 检查加上这个字符是否会超过最大宽度
if currentWidth+charWidth > maxWidth {
// 超过最大宽度,保存当前行并开始新行
if currentLine != "" {
lines = append(lines, currentLine)
}
currentLine = string(r)
currentWidth = charWidth
} else {
currentLine += string(r)
currentWidth += charWidth
}
}
// 添加最后一行
if currentLine != "" {
lines = append(lines, currentLine)
}
return lines
}
// TruncateTextByRune 按字符权重截断文本
// 中文字符算1.0,英文字母/数字/英文符号算0.5
// 返回截断后的文本确保总权重不超过maxWidth
func TruncateTextByRune(text string, maxWidth float64) string {
if text == "" {
return ""
}
runes := []rune(text)
var result []rune
currentWidth := 0.0
for _, r := range runes {
charWidth := getCharWidth(r)
if currentWidth+charWidth > maxWidth {
break
}
result = append(result, r)
currentWidth += charWidth
}
return string(result)
}
// ConvertCompetitorReportToText 将竞品报告数据转换为文本格式
// 参数:
// - data: 竞品报告数据
// - isVideo: 是否为视频(视频需要包含完播率和配乐亮点)
//
// 返回: 转换后的文本内容
func ConvertCompetitorReportToText(data CompetitorReportData, isVideo bool) string {
var sb strings.Builder
// 一、亮点表现分析
sb.WriteString("一、亮点表现分析\n")
sb.WriteString(data.HighlightAnalysis.Summary)
sb.WriteString("\n\n")
sb.WriteString("1. 标题亮点:")
sb.WriteString(data.HighlightAnalysis.Points.Theme)
sb.WriteString("\n")
sb.WriteString("2. 题材亮点:")
sb.WriteString(data.HighlightAnalysis.Points.Narrative)
sb.WriteString("\n")
sb.WriteString("3. 内容亮点:")
sb.WriteString(data.HighlightAnalysis.Points.Content)
sb.WriteString("\n")
sb.WriteString("4. 文案亮点:")
sb.WriteString(data.HighlightAnalysis.Points.Copywriting)
sb.WriteString("\n")
sb.WriteString("5. 数据亮点:")
sb.WriteString(data.HighlightAnalysis.Points.Data)
sb.WriteString("\n")
if isVideo && data.HighlightAnalysis.Points.Music != "" {
sb.WriteString("6. 配乐亮点:")
sb.WriteString(data.HighlightAnalysis.Points.Music)
sb.WriteString("\n")
}
// 二、数据表现分析
sb.WriteString("\n二、数据表现分析\n")
sb.WriteString("1. 浏览量表现:")
sb.WriteString(data.DataPerformance.Views)
sb.WriteString("\n")
if isVideo && data.DataPerformance.Completion != "" {
sb.WriteString("2. 完播率表现:")
sb.WriteString(data.DataPerformance.Completion)
sb.WriteString("\n")
sb.WriteString("3. 点赞/分享/评论表现:")
} else {
sb.WriteString("2. 点赞/分享/评论表现:")
}
sb.WriteString(data.DataPerformance.Engagement)
sb.WriteString("\n")
// 三、整体总结及可优化建议
sb.WriteString("\n三、整体总结及可优化建议\n")
sb.WriteString(data.OverallSummary)
return sb.String()
}
//生成问卷调查pdf
func QuestionnaireSurveyPDF(templatePath, outputPath string, data *model.QuestionnairePDFData) error {
pdf := gopdf.GoPdf{}
pdf.Start(gopdf.Config{PageSize: *gopdf.PageSizeA4})
if err := pdf.ImportPagesFromSource(templatePath, "/MediaBox"); err != nil {
return fmt.Errorf("导入模板失败: %w", err)
}
if err := pdf.AddTTFFont("simfang", "./data/simfang.ttf"); err != nil {
return fmt.Errorf("加载字体失败: %w", err)
}
if err := pdf.SetFont("simfang", "", 12); err != nil {
return fmt.Errorf("设置字体失败: %w", err)
}
startTime, err := parseFlexibleDate(data.BundleStartDate)
if err != nil {
return fmt.Errorf("BundleStartDate格式错误: %w", err)
}
endTime, err := parseFlexibleDate(data.BundleEndDate)
if err != nil {
return fmt.Errorf("BundleEndDate格式错误: %w", err)
}
submissionDate, err := parseFlexibleDate(data.SubmissionDate)
if err != nil {
return fmt.Errorf("SubmissionDate格式错误: %w", err)
}
nowTime := time.Now().Format(time.DateTime)
onePage := 1
twoPage := 2
threePage := 3
fourPage := 4
// 第1页客户基本信息
pdf.SetPage(onePage)
//姓名
pdf.SetX(165)
pdf.SetY(420)
pdf.Cell(nil, data.CustomerName)
//套餐名称
pdf.SetX(205)
pdf.SetY(443)
pdf.Cell(nil, data.BundleName)
//开始日期
pdf.SetX(205)
pdf.SetY(467)
pdf.Cell(nil, startTime.Format("2006"))
pdf.SetX(260)
pdf.SetY(467)
pdf.Cell(nil, startTime.Format("01"))
pdf.SetX(300)
pdf.SetY(467)
pdf.Cell(nil, startTime.Format("02"))
//结束日期
pdf.SetX(350)
pdf.SetY(467)
pdf.Cell(nil, endTime.Format("2006"))
pdf.SetX(398)
pdf.SetY(467)
pdf.Cell(nil, endTime.Format("01"))
pdf.SetX(437)
pdf.SetY(467)
pdf.Cell(nil, endTime.Format("02"))
//视频数
pdf.SetX(220)
pdf.SetY(583)
pdf.Cell(nil, data.VideoNum)
//"账号数: "+
pdf.SetX(230)
pdf.SetY(625)
pdf.Cell(nil, data.AccountNum)
// "图文数: "+
pdf.SetX(253)
pdf.SetY(667)
pdf.Cell(nil, data.ImagesNum)
//"数据分析数: "+
pdf.SetX(280)
pdf.SetY(727)
pdf.Cell(nil, data.DataAnalysisNum)
// 第1页内容写完后
if err = addWatermark(&pdf, "确认地址:"+data.Address+"\n确认时间"+nowTime); err != nil {
return err
}
// 第2页服务数量
pdf.SetPage(twoPage)
//"竞品分析数: "+
pdf.SetX(205)
pdf.SetY(72)
pdf.Cell(nil, data.CompetitiveNum)
//"增值视频数: "+
pdf.SetX(270)
pdf.SetY(156)
pdf.Cell(nil, data.ValueAddVideoNum)
//"评分1: "+
pdf.SetX(123)
pdf.SetY(485)
pdf.Cell(nil, scoreStars(data.Score1))
//"评分2: "+
pdf.SetX(343)
pdf.SetY(526)
pdf.Cell(nil, scoreStars(data.Score2))
//"评分3: "+
pdf.SetX(230)
pdf.SetY(568)
pdf.Cell(nil, scoreStars(data.Score3))
//"评分4: "+
pdf.SetX(362)
pdf.SetY(610)
pdf.Cell(nil, scoreStars(data.Score4))
//"评分5: "+
pdf.SetX(220)
pdf.SetY(652)
pdf.Cell(nil, scoreStars(data.Score5))
//"评分6: "+
pdf.SetX(164)
pdf.SetY(694)
pdf.Cell(nil, scoreStars(data.Score6))
//"评分7: "+
pdf.SetX(197)
pdf.SetY(735)
pdf.Cell(nil, scoreStars(data.Score7))
//水印
if err = addWatermark(&pdf, "确认地址:"+data.Address+"\n确认时间"+nowTime); err != nil {
return err
}
// 第3页评分与意见
pdf.SetPage(threePage)
// Opinion 超过100字符时自动换行每行约20个中文字符行高18pt
drawWrappedText(&pdf, data.Opinion1, 90, 145, 24, 34)
drawWrappedText(&pdf, data.Opinion2, 90, 377, 24, 34)
drawWrappedText(&pdf, data.Opinion3, 90, 574, 24, 34)
//水印
if err = addWatermark(&pdf, "确认地址:"+data.Address+"\n确认时间"+nowTime); err != nil {
return err
}
// 第4页提交信息
pdf.SetPage(fourPage)
//"提交人: "+
pdf.SetX(135)
pdf.SetY(103)
pdf.Cell(nil, data.Submitter)
//提交时间: "
pdf.SetX(148)
pdf.SetY(128)
pdf.Cell(nil, submissionDate.Format("2006"))
pdf.SetX(207)
pdf.SetY(128)
pdf.Cell(nil, submissionDate.Format("01"))
pdf.SetX(260)
pdf.SetY(128)
pdf.Cell(nil, submissionDate.Format("02"))
//水印
if err = addWatermark(&pdf, "确认地址:"+data.Address+"\n确认时间"+nowTime); err != nil {
return err
}
if err := pdf.WritePdf(outputPath); err != nil {
return fmt.Errorf("写入PDF失败: %w", err)
}
return nil
}
// addWatermark 在当前页叠加浅色斜向双行水印,并在结束后恢复样式
func addWatermark(pdf *gopdf.GoPdf, text string) error {
const normalFontSize = 12
const watermarkFontSize = 22
const lineHeight = 32.0 // 水印行间距
// 设置水印样式
pdf.SetGrayFill(0.85)
if err := pdf.SetFont("simfang", "", watermarkFontSize); err != nil {
return fmt.Errorf("设置水印字体失败: %w", err)
}
// 按换行拆分逐行绘制Cell 不负责自动换行)
lines := strings.Split(text, "\n")
if len(lines) == 0 {
lines = []string{text}
}
drawBlock := func(x, y, cx, cy float64) {
pdf.Rotate(35, cx, cy)
for i, line := range lines {
pdf.SetX(x)
pdf.SetY(y + float64(i)*lineHeight)
pdf.Cell(nil, line)
}
pdf.RotateReset()
}
// 两处重复水印
drawBlock(90, 420, 300, 420)
drawBlock(130, 620, 300, 420)
// 恢复样式,避免影响后续正文
pdf.SetGrayFill(0)
if err := pdf.SetFont("simfang", "", normalFontSize); err != nil {
return fmt.Errorf("恢复字体失败: %w", err)
}
return nil
}
// drawWrappedText 在 PDF 上绘制自动换行的文字
// pdf: GoPdf 实例, text: 文字内容, startX/startY: 起始坐标
// maxWidth: 最大宽度pt, lineHeight: 行高pt, charsPerLine: 每行最多字符数(按中文字符计)
func drawWrappedText(pdf *gopdf.GoPdf, text string, startX, startY, lineHeight float64, charsPerLine int) {
runes := []rune(text)
total := len(runes)
if total == 0 {
return
}
lineStart := 0
currentLine := 0
for lineStart < total {
end := lineStart + charsPerLine
if end > total {
end = total
}
// 计算实际宽度以决定换行点按字节估算ASCII=0.5中文字符宽)
charCount := 0
splitAt := lineStart
for i := lineStart; i < total; i++ {
r := runes[i]
runeBytes := utf8.RuneLen(r)
if runeBytes > 1 {
charCount += 2 // 中文等宽字符算2个单位
} else {
charCount += 1 // ASCII 算1个单位
}
if charCount > charsPerLine*2 {
break
}
splitAt = i + 1
}
if splitAt == lineStart {
splitAt = lineStart + 1
}
line := string(runes[lineStart:splitAt])
pdf.SetX(startX)
pdf.SetY(startY + float64(currentLine)*lineHeight)
pdf.Cell(nil, line)
lineStart = splitAt
currentLine++
}
}
func scoreStars(score int) string {
switch {
case score <= 1:
return "★☆☆☆☆"
case score == 2:
return "★★☆☆☆"
case score == 3:
return "★★★☆☆"
case score == 4:
return "★★★★☆"
default:
return "★★★★★"
}
}
func parseFlexibleDate(value string) (time.Time, error) {
v := strings.TrimSpace(value)
if v == "" {
return time.Time{}, fmt.Errorf("日期为空")
}
layouts := []string{
"2006-01-02",
time.RFC3339,
"2006-01-02 15:04:05",
"2006-01-02 15:04",
}
var lastErr error
for _, layout := range layouts {
t, err := time.Parse(layout, v)
if err == nil {
return t, nil
}
lastErr = err
}
return time.Time{}, fmt.Errorf("不支持的日期格式: %s, %w", v, lastErr)
}

View File

@ -1,304 +0,0 @@
package utils
import (
"fmt"
"os"
"path/filepath"
"testing"
)
// getProjectRoot 获取项目根目录
func getProjectRoot() string {
// 假设测试从项目根目录运行
dir, _ := os.Getwd()
// 向上查找 go.mod 确定项目根目录
for {
if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil {
return dir
}
parent := filepath.Dir(dir)
if parent == dir {
break
}
dir = parent
}
return ""
}
// TestGenerateCompetitorReportPDF 测试生成竞品报告PDF
func TestGenerateCompetitorReportPDF1(t *testing.T) {
// 获取项目根目录
root := getProjectRoot()
fmt.Printf("项目根目录: %s\n", root)
// 准备测试数据
data := CompetitorReportData{
HighlightAnalysis: HighlightAnalysisData{
Summary: "本视频通过展示产品使用的真实场景,突出用户产品优势和痛点,内容详实且具有吸引力。",
Points: PointsData{
Theme: "标题简洁有力,突出核心卖点'省时省力',引发用户好奇心",
Narrative: "采用情景剧形式展示产品使用场景,剧情贴近生活,易引发共鸣",
Content: "通过前后对比展示产品效果,直观呈现产品价值",
Copywriting: "文案简洁明了,突出用户痛点解决方案,语气亲切自然",
Data: "点赞量10万+评论5000+分享2万+,数据表现优异",
Music: "背景音乐节奏轻快,与视频内容匹配度高,增强观看体验",
},
},
DataPerformance: DataPerformanceData{
Views: "播放量突破500万推荐流量占比60%,自然流量表现优秀",
Completion: "完播率45%高于同类视频平均值30%前3秒吸引力强",
Engagement: "点赞率2%评论率0.1%分享率0.4%,互动数据表现优秀",
},
OverallSummary: "整体来看该竞品视频在内容策划、表现形式和互动数据方面都表现优秀。优势在于1内容真实可信通过实际使用场景展示产品效果2剧情设计合理前3秒抓住用户注意力3文案简洁有力直击用户痛点。建议优化方向1可以增加更多用户评价内容增强可信度2适当增加福利引导提高转化率3结尾可以增加引导关注话术提升粉丝沉淀。",
}
// 模板路径
templatePath := filepath.Join(root, "data", "竞品报告pdf模板.pdf")
// 输出路径
outputPath := filepath.Join(root, "data", "output", "竞品报告测试_multicell.pdf")
// 确保输出目录存在
outputDir := filepath.Dir(outputPath)
if err := os.MkdirAll(outputDir, 0755); err != nil {
t.Errorf("创建输出目录失败: %v", err)
return
}
// 调用函数生成PDF
err := GenerateCompetitorReportPDF(templatePath, outputPath, data)
if err != nil {
t.Errorf("生成竞品报告PDF失败: %v", err)
return
}
fmt.Printf("PDF生成成功: %s\n", outputPath)
}
// TestGenerateCompetitorReportPDFImageOnly 测试仅图片的竞品报告PDF无配乐和完播率
func TestGenerateCompetitorReportPDFImageOnly(t *testing.T) {
// 获取项目根目录
root := getProjectRoot()
// 准备测试数据(仅图片,没有视频的配乐和完播率)
data := CompetitorReportData{
HighlightAnalysis: HighlightAnalysisData{
Summary: "该图文内容通过精美的视觉设计和精准的标签定位,成功吸引目标用户关注。",
Points: PointsData{
Theme: "标题设置悬念,引发用户点击欲望",
Narrative: "采用九宫格形式展示产品特点,视觉冲击力强",
Content: "内容排版清晰,重点突出,便于用户快速获取信息",
Copywriting: "文案简洁,配合表情符号增加趣味性",
Data: "收藏量5万+评论1000+分享8000+",
Music: "", // 图片无配乐
},
},
DataPerformance: DataPerformanceData{
Views: "曝光量100万+点击率3%,表现良好",
Completion: "", // 图文无完播率
Engagement: "收藏率5%评论率0.1%分享率0.8%",
},
OverallSummary: "该图文内容整体表现优秀特别是在视觉设计和内容排版方面。亮点1九宫格形式统一视觉效果好2标签设置精准触达目标用户3发布时间合理获得更多曝光。优化建议1可以增加更多用户案例展示2适当加入互动话题提高评论量。",
}
// 模板路径
templatePath := filepath.Join(root, "data", "竞品报告pdf模板.pdf")
// 输出路径
outputPath := filepath.Join(root, "data", "output", "竞品报告测试_图文11.pdf")
// 确保输出目录存在
outputDir := filepath.Dir(outputPath)
if err := os.MkdirAll(outputDir, 0755); err != nil {
t.Errorf("创建输出目录失败: %v", err)
return
}
// 调用函数生成PDF
err := GenerateCompetitorReportPDF(templatePath, outputPath, data)
if err != nil {
t.Errorf("生成竞品报告PDF失败: %v", err)
return
}
fmt.Printf("PDF生成成功: %s\n", outputPath)
}
// TestGenerateCompetitorReportPDFWithImage 测试带图片的竞品报告PDF
// 注意:此测试需要网络连接来下载图片,如果网络不可用会被跳过
func TestGenerateCompetitorReportPDFWithImage1(t *testing.T) {
// 获取项目根目录
root := getProjectRoot()
// 准备测试数据(带图片)
// 使用一个已知可用的测试图片URL
data := CompetitorReportData{
HighlightAnalysis: HighlightAnalysisData{
Summary: "本视频通过展示产品使用的真实场景,突出用户产品优势和痛点,内容详实且具有吸引力。",
Points: PointsData{
Theme: "标题简洁有力,突出核心卖点'省时省力',引发用户好奇心",
Narrative: "采用情景剧形式展示产品使用场景,剧情贴近生活,易引发共鸣",
Content: "通过前后对比展示产品效果,直观呈现产品价值",
Copywriting: "文案简洁明了,突出用户痛点解决方案,语气亲切自然",
Data: "点赞量10万+评论5000+分享2万+,数据表现优异",
Music: "背景音乐节奏轻快,与视频内容匹配度高,增强观看体验",
},
},
DataPerformance: DataPerformanceData{
Views: "播放量突破500万推荐流量占比60%,自然流量表现优秀",
Completion: "完播率45%高于同类视频平均值30%前3秒吸引力强",
Engagement: "点赞率2%评论率0.1%分享率0.4%,互动数据表现优秀",
},
OverallSummary: "整体来看,该竞品视频在内容策划、表现形式和互动数据方面都表现优秀。",
ImageURL: "https://cdn-test.szjixun.cn/fonchain-main/test/image/12345/artwork/0.png", // 测试用图片URL
}
// 模板路径
templatePath := filepath.Join(root, "data", "竞品报告pdf模板.pdf")
// 输出路径
outputPath := filepath.Join(root, "data", "output", "竞品报告测试_带图片.pdf")
// 确保输出目录存在
outputDir := filepath.Dir(outputPath)
if err := os.MkdirAll(outputDir, 0755); err != nil {
t.Errorf("创建输出目录失败: %v", err)
return
}
// 调用函数生成PDF
err := GenerateCompetitorReportPDF(templatePath, outputPath, data)
if err != nil {
t.Logf("图片下载测试跳过(网络问题): %v", err)
t.Skip("网络不可用,跳过图片测试")
return
}
fmt.Printf("PDF生成成功: %s\n", outputPath)
}
// TestGenerateCompetitorReportPDFMixedContent 测试中英混合、数字、符号的复杂情况
func TestGenerateCompetitorReportPDFMixedContent(t *testing.T) {
root := getProjectRoot()
// 准备包含中英混合、数字、符号的复杂测试数据
data := CompetitorReportData{
HighlightAnalysis: HighlightAnalysisData{
Summary: "这是一个关于2024年短视频创作的爆款分析报告视频总播放量达到1.2亿次点赞率8.5%远超行业平均3.2%。内容包括①生活技巧类占比40% ②知识科普类30% ③娱乐搞笑类30%。推荐算法推荐流量占比85%搜索流量10%其他渠道5%。",
Points: PointsData{
Theme: "标题【逆袭】3个月从0到100万粉丝我是如何做到的必看🔥",
Narrative: "采用问题-解决叙事结构前3秒抛出痛点你还在为XX发愁吗然后展示解决方案ABC",
Content: "内容分为3个板块①前置干货预告15秒 ②核心内容展示30秒 ③互动引导15秒",
Copywriting: "文案使用了大量emoji表情🔥💯👍增加年轻化气息结尾一句评论区见强化互动",
Data: "点赞率8.5%高于同类平均3.2%转发率2.1%评论数2.3万条评论区活跃度TOP10%",
Music: "使用热门BGM孤勇者前奏3秒配合画面节奏卡点音量为Original-3dB",
},
},
DataPerformance: DataPerformanceData{
Views: "发布24小时内播放量突破500万48小时达到1200万72小时稳定在1500万。推荐流量占比85%搜索流量占比10%其他渠道5%。数据表现PV=15000000UV=8500000。",
Completion: "平均完播率45.2%高于行业均值28%3秒留存率72%5秒完播率58%10秒完播率35%属于高质量流量。平均观看时长18.5秒视频总时长42秒。",
Engagement: "点赞数128000点赞率0.85%评论数23000其中神评论占比15%高赞评论TOP3①学到了 ②太棒了 ③收藏了分享数56000。评论区@相关账号12个引发二次传播。",
},
OverallSummary: "该视频成功因素:①标题使用数字热门词激发点击逆袭必看 ②内容结构清晰每15秒一个高潮点 ③BGM选择契合内容情绪孤勇者 ④评论区运营到位。建议优化1可增加合集功能将同类内容串联 2提升粉丝粘性到10%以上 3适当增加直播预告。整体来看这是一条典型的爆款体质视频值得借鉴学习数据支撑ROI=3.5CPM=25元CPC=0.8元。",
ImageURL: "",
}
// 模板路径
templatePath := filepath.Join(root, "data", "竞品报告pdf模板.pdf")
// 输出路径
outputPath := filepath.Join(root, "data", "output", "竞品报告测试_中英混合.pdf")
// 确保输出目录存在
outputDir := filepath.Dir(outputPath)
if err := os.MkdirAll(outputDir, 0755); err != nil {
t.Errorf("创建输出目录失败: %v", err)
return
}
// 调用函数生成PDF
err := GenerateCompetitorReportPDF(templatePath, outputPath, data)
if err != nil {
t.Errorf("生成PDF失败: %v", err)
return
}
fmt.Printf("PDF生成成功中英混合测试: %s\n", outputPath)
}
// TestTruncateTextByRune 测试按字符权重截断文本
func TestTruncateTextByRune(t *testing.T) {
tests := []struct {
name string
text string
maxWidth float64
want string
}{
{
name: "空文本",
text: "",
maxWidth: 10,
want: "",
},
{
name: "纯中文截断",
text: "这是一段很长的中文内容需要被截断",
maxWidth: 10,
want: "这是一段很长的中文内", // 10个中文字=10正好
},
{
name: "纯英文截断按0.5计算)",
text: "abcdefghijklmnop",
maxWidth: 5,
want: "abcdefghij", // 10个字母=5.0,正好
},
{
name: "数字截断按0.5计算)",
text: "1234567890",
maxWidth: 3,
want: "123456", // 6个数字=3.0,正好
},
{
name: "中英混合截断",
text: "hello你好world世界",
maxWidth: 6,
// h(0.5)+e(0.5)+l(0.5)+l(0.5)+o(0.5)=2.5
// +你(1)+好(1)=4.5
// +w(0.5)+o(0.5)+r(0.5)+l(0.5)=2再加就超过6了
// 所以应该是 hello你好wor
want: "hello你好wor",
},
{
name: "符号截断按0.5计算)",
text: "hello,world!",
maxWidth: 5,
// h(0.5)+e(0.5)+l(0.5)+l(0.5)+o(0.5)+,(0.5)=3
// +w(0.5)+o(0.5)+r(0.5)+l(0.5)+d(0.5)+!(0.5)=6超过5
// 所以保留 hello,worl
want: "hello,worl",
},
{
name: "截断到正好边界",
text: "中文字符",
maxWidth: 4,
want: "中文字符", // 4个中文字=4.0,正好
},
{
name: "宽度为0",
text: "hello",
maxWidth: 0,
want: "",
},
{
name: "宽度小于单个字符",
text: "hello",
maxWidth: 0.3,
want: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := TruncateTextByRune(tt.text, tt.maxWidth)
if got != tt.want {
t.Errorf("TruncateTextByRune(%q, %v) = %q, want %q", tt.text, tt.maxWidth, got, tt.want)
}
})
}
}