Compare commits
2 Commits
main
...
feat-cjy-o
| Author | SHA1 | Date | |
|---|---|---|---|
| cd051d97bf | |||
| 0ca94abf70 |
File diff suppressed because it is too large
Load Diff
@ -1096,61 +1096,3 @@ func (this *UpdataInvoiceInfoReq) Validate() error {
|
||||
func (this *UpdataInvoiceInfoResp) Validate() error {
|
||||
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
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go-triple. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-triple v1.0.5
|
||||
// - protoc v5.26.0
|
||||
// - protoc-gen-go-triple v1.0.8
|
||||
// - protoc v3.21.1
|
||||
// source: pb/bundle.proto
|
||||
|
||||
package bundle
|
||||
@ -147,11 +147,6 @@ type BundleClient interface {
|
||||
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)
|
||||
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 {
|
||||
@ -266,10 +261,6 @@ type BundleClientImpl struct {
|
||||
GetPaymentCyclesByContractUUID func(ctx context.Context, in *GetPaymentCyclesByContractUUIDRequest) (*GetPaymentCyclesByContractUUIDResponse, error)
|
||||
UpdateOrderRecordByOrderUuid func(ctx context.Context, in *OrderRecord) (*CommonResponse, 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 {
|
||||
@ -926,30 +917,6 @@ func (c *bundleClient) OrderListByOrderUuid(ctx context.Context, in *OrderInfoBy
|
||||
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.
|
||||
// All implementations must embed UnimplementedBundleServer
|
||||
// for forward compatibility
|
||||
@ -1073,11 +1040,6 @@ type BundleServer interface {
|
||||
GetPaymentCyclesByContractUUID(context.Context, *GetPaymentCyclesByContractUUIDRequest) (*GetPaymentCyclesByContractUUIDResponse, error)
|
||||
UpdateOrderRecordByOrderUuid(context.Context, *OrderRecord) (*CommonResponse, 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()
|
||||
}
|
||||
|
||||
@ -1407,18 +1369,6 @@ func (UnimplementedBundleServer) UpdateOrderRecordByOrderUuid(context.Context, *
|
||||
func (UnimplementedBundleServer) OrderListByOrderUuid(context.Context, *OrderInfoByOrderUuidRequest) (*OrderInfoByOrderNoResp, error) {
|
||||
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) {
|
||||
s.proxyImpl = impl
|
||||
}
|
||||
@ -4550,122 +4500,6 @@ func _Bundle_OrderListByOrderUuid_Handler(srv interface{}, ctx context.Context,
|
||||
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.
|
||||
// It's only intended for direct use with grpc_go.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
@ -5101,22 +4935,6 @@ var Bundle_ServiceDesc = grpc_go.ServiceDesc{
|
||||
MethodName: "OrderListByOrderUuid",
|
||||
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{},
|
||||
Metadata: "pb/bundle.proto",
|
||||
|
||||
5646
api/cast/cast.pb.go
5646
api/cast/cast.pb.go
File diff suppressed because it is too large
Load Diff
@ -27001,6 +27001,8 @@ func (m *WorkListPublishedResp_Info) validate(all bool) error {
|
||||
|
||||
// no validation rules for SharesCount
|
||||
|
||||
// no validation rules for PublishTime
|
||||
|
||||
if len(errors) > 0 {
|
||||
return WorkListPublishedResp_InfoMultiError(errors)
|
||||
}
|
||||
|
||||
Binary file not shown.
@ -31,10 +31,6 @@ func AnalysisRouter(r *gin.RouterGroup) {
|
||||
analysis.POST("artist-metrics-single", serviceCast.ArtistMetricsDailyWindow) // 艺人指标日窗口
|
||||
analysis.POST("tobe-confirmed-list", serviceCast.TobeConfirmedList) // 待确认数据列表
|
||||
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 指标采集任务
|
||||
}
|
||||
@ -53,10 +49,6 @@ func AnalysisRouter(r *gin.RouterGroup) {
|
||||
competitiveReport.POST("count-by-work-uuids", serviceCast.CountCompetitiveReportByWorkUuids) // 根据作品UUID统计竞品报告数量
|
||||
competitiveReport.POST("export-list", serviceCast.ListCompetitiveReportExport) // 竞品报告列表导出
|
||||
competitiveReport.POST("export-single-list", serviceCast.ListCompetitiveReportSingleExport) // 竞品报告单个列表导出
|
||||
competitiveReport.POST("import-pdf-batch", serviceCast.ImportPdfBatch) // 批量导入PDF(下载、重命名、上传)
|
||||
|
||||
// 刷竞品报告专用的导入接口
|
||||
competitiveReport.POST("import-history-batch", serviceCast.ImportCompetitiveReportHistoryBatch) // Excel 批量刷写竞品报告历史数据
|
||||
}
|
||||
|
||||
// 员工任务相关路由(需要App登录验证
|
||||
|
||||
@ -20,9 +20,6 @@ func BundleRouter(r *gin.RouterGroup) {
|
||||
{
|
||||
bundleClientNoAuthRoute.POST("export/work-cast-info", bundle.ExportWorkCastInfo)
|
||||
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")
|
||||
{
|
||||
@ -58,10 +55,6 @@ func BundleRouter(r *gin.RouterGroup) {
|
||||
metrics.POST("export/balance-detail", bundle.MetricsBalanceDetailExport)
|
||||
metrics.POST("export/balance-metrics", bundle.BalanceMetricsExport)
|
||||
}
|
||||
survey := bundleClientRoute.Group("survey")
|
||||
{
|
||||
survey.POST("list", bundle.QuestionnaireSurveyList)
|
||||
}
|
||||
|
||||
}
|
||||
bundleClientRouteV2 := bundleRoute.Group("system/v2")
|
||||
|
||||
@ -68,15 +68,14 @@ func NewRouter() *gin.Engine {
|
||||
}
|
||||
//账号模块
|
||||
{
|
||||
privateGroup.POST("user/register", account.UserRegister) //h5注册登录
|
||||
privateGroup.POST("user/login", account.UserLogin) //后台登录
|
||||
privateGroup.POST("user/send", account.SendMsg) //发送验证码
|
||||
privateGroup.POST("user/send/no-slider", account.SendMsgNoSlider) //发送验证码(不验证滑块)
|
||||
privateGroup.POST("user/logout", account.UserLogout) //登出
|
||||
privateGroup.POST("user/check/msg", account.CheckMsg) //校验验证码
|
||||
privateGroup.POST("generate/captcha", account.GenerateCaptcha) //生成滑块验证码
|
||||
privateGroup.POST("validate/captcha", account.ValidateCaptcha) //验证滑块验证码
|
||||
privateGroup.POST("check/register", account.CheckRegister) //校验是否注册
|
||||
privateGroup.POST("user/register", account.UserRegister) //h5注册登录
|
||||
privateGroup.POST("user/login", account.UserLogin) //后台登录
|
||||
privateGroup.POST("user/send", account.SendMsg) //发送验证码
|
||||
privateGroup.POST("user/logout", account.UserLogout) //登出
|
||||
privateGroup.POST("user/check/msg", account.CheckMsg) //校验验证码
|
||||
privateGroup.POST("generate/captcha", account.GenerateCaptcha) //生成滑块验证码
|
||||
privateGroup.POST("validate/captcha", account.ValidateCaptcha) //验证滑块验证码
|
||||
privateGroup.POST("check/register", account.CheckRegister) //校验是否注册
|
||||
acRoute := privateGroup.Group("/user")
|
||||
acRoute.Use(middleware.CheckLogin(service.AccountFieeProvider))
|
||||
{
|
||||
|
||||
@ -413,54 +413,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) {
|
||||
var req account.RealNameRequest
|
||||
|
||||
@ -505,8 +457,7 @@ func CheckMsg(c *gin.Context) {
|
||||
req.TelNum = req.Zone + req.TelNum
|
||||
res, err := service.AccountFieeProvider.CheckMsg(context.Background(), &req)
|
||||
if err != nil {
|
||||
fmt.Println("CheckMsg error:", err)
|
||||
service.Error(c, errors.New("验证码错误"))
|
||||
service.Error(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -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"`
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -494,14 +494,14 @@ func AutoCreateUserAndOrder(c *gin.Context) {
|
||||
|
||||
//生成发票
|
||||
orderRecord, err := service.BundleProvider.GetOrderInfoByOrderNo(context.Background(), &bundle.GetOrderInfoByOrderNoReq{
|
||||
OrderNo: unfinishInfo.OrderNo, //因为需求更新,实际传入的是订单的uuid
|
||||
Uuid: unfinishInfo.OrderNo, //因为需求更新,实际传入的是订单的uuid
|
||||
})
|
||||
if err != nil {
|
||||
service.Error(c, err)
|
||||
return
|
||||
}
|
||||
amountType := strconv.FormatInt(orderRecord.AmountType, 10)
|
||||
applyTime := unfinishInfo.PayTime
|
||||
applyTime := common.GetBeijingTime()
|
||||
payTime, _ := time.Parse("2006-01-02 15:04:05", applyTime)
|
||||
payTimeString := payTime.Format("20060102")
|
||||
fmt.Println("发票payTimeString :", payTimeString, "发票applyTime :", applyTime, "发票payTime :", payTime)
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package cast
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
@ -20,18 +19,14 @@ import (
|
||||
"fonchain-fiee/pkg/service/bundle/common"
|
||||
"fonchain-fiee/pkg/utils"
|
||||
"fonchain-fiee/pkg/utils/stime"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"math/rand"
|
||||
|
||||
"dubbo.apache.org/dubbo-go/v3/common/constant"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"github.com/xuri/excelize/v2"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@ -97,305 +92,6 @@ func CreateWorkAnalysisCore(ctx *gin.Context, req *cast.CreateWorkAnalysisReq) (
|
||||
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-based),line=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)
|
||||
}
|
||||
|
||||
// 第九列:IsRefreshData(1 → false, 2 → true)
|
||||
isRefreshData := false
|
||||
if len(row) > 8 && utils.CleanString(row[8]) == "2" {
|
||||
isRefreshData = true
|
||||
}
|
||||
|
||||
// 第十列:DateInt(YYYYMMDD 格式,直接从 Excel 读取)
|
||||
var dateInt int32
|
||||
if len(row) > 9 && utils.CleanString(row[9]) != "" {
|
||||
v, _ := strconv.ParseInt(utils.CleanString(row[9]), 10, 32)
|
||||
dateInt = int32(v)
|
||||
}
|
||||
|
||||
// 第十一列:ConfirmType(1 艺人确认,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
|
||||
}
|
||||
|
||||
// 将 submitTime(YYYY-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 更新作品分析
|
||||
func UpdateWorkAnalysis(ctx *gin.Context) {
|
||||
var req *cast.UpdateWorkAnalysisReq
|
||||
@ -869,14 +565,14 @@ func ArtistMetricsSeries(ctx *gin.Context) {
|
||||
|
||||
var subInfoResp *accountFiee.UserInfoResponse
|
||||
var subInfoErr error
|
||||
var workStatsResp *cast.GetArtistWorkStatsResp
|
||||
var dataListResp *cast.ArtistDataListResp
|
||||
var metricsResp *cast.ArtistMetricsSeriesResp
|
||||
var workStatsErr, metricsErr error
|
||||
var dataListErr, metricsErr error
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(2)
|
||||
wg.Add(3)
|
||||
|
||||
// 并行调用 SubNumGetInfo、ArtistMetricsSeries
|
||||
// 并行调用 SubNumGetInfo、ArtistDataList、ArtistMetricsSeries
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
subInfoResp, subInfoErr = service.AccountFieeProvider.SubNumGetInfo(context.Background(), &accountFiee.SubNumGetInfoRequest{
|
||||
@ -885,6 +581,15 @@ func ArtistMetricsSeries(ctx *gin.Context) {
|
||||
})
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
dataListResp, dataListErr = service.CastProvider.ArtistDataList(context.Background(), &cast.ArtistDataListReq{
|
||||
SubNum: subNum,
|
||||
Page: 1,
|
||||
PageSize: 1,
|
||||
})
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
metricsResp, metricsErr = service.CastProvider.ArtistMetricsSeries(context.Background(), req)
|
||||
@ -902,30 +607,13 @@ func ArtistMetricsSeries(ctx *gin.Context) {
|
||||
}
|
||||
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)
|
||||
workStatsResp, workStatsErr = service.CastProvider.GetArtistWorkStats(newCtx, &cast.GetArtistWorkStatsReq{
|
||||
ArtistUuid: req.ArtistUUID,
|
||||
StatusUpdateTime: statusUpdateTime,
|
||||
})
|
||||
|
||||
var accountConsumptionNumber int32
|
||||
var videoCount int64
|
||||
var imageCount int64
|
||||
if workStatsErr == nil && workStatsResp != nil {
|
||||
accountConsumptionNumber = int32(workStatsResp.AccountCount)
|
||||
videoCount = workStatsResp.VideoCount
|
||||
imageCount = workStatsResp.ImageCount
|
||||
} else if workStatsErr != nil {
|
||||
zap.L().Warn("GetArtistWorkStats failed", zap.Error(workStatsErr), zap.String("artistUUID", req.ArtistUUID), zap.String("statusUpdateTime", statusUpdateTime))
|
||||
if dataListErr == 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 {
|
||||
@ -1125,24 +813,6 @@ func UpdateWorkAnalysisApprovalID(ctx *gin.Context) {
|
||||
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 {
|
||||
ArtistID string `protobuf:"bytes,4,opt,name=artistID,proto3" json:"artistID"` // 艺人ID
|
||||
BalanceType modelCast.BalanceTypeEnum `json:"balanceType"` // 套餐类型
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package cast
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -18,14 +17,13 @@ import (
|
||||
"fonchain-fiee/pkg/service/upload"
|
||||
"fonchain-fiee/pkg/utils"
|
||||
"fonchain-fiee/pkg/utils/stime"
|
||||
"math/rand"
|
||||
"net/url"
|
||||
"os"
|
||||
"unicode/utf8"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
@ -1356,276 +1354,6 @@ func generateReportFileName(title, artistName string) string {
|
||||
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-based),line=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]
|
||||
}
|
||||
|
||||
// 第四列:ConfirmType(1 艺人确认,2 系统自动确认)
|
||||
var confirmType int32
|
||||
if len(row) > 3 && utils.CleanString(row[3]) != "" {
|
||||
v, _ := strconv.ParseInt(utils.CleanString(row[3]), 10, 32)
|
||||
confirmType = int32(v)
|
||||
}
|
||||
|
||||
// 将 submitTime(YYYY-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 {
|
||||
|
||||
152
pkg/utils/map.go
152
pkg/utils/map.go
@ -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
|
||||
}
|
||||
296
pkg/utils/pdf.go
296
pkg/utils/pdf.go
@ -3,7 +3,6 @@ package utils
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"fonchain-fiee/pkg/service/bundle/model"
|
||||
"image"
|
||||
"io"
|
||||
"net/http"
|
||||
@ -11,9 +10,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/phpdave11/gofpdf"
|
||||
"github.com/signintech/gopdf"
|
||||
@ -598,296 +595,3 @@ func ConvertCompetitorReportToText(data CompetitorReportData, isVideo bool) stri
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user