Merge branch 'main' into feat-cjy-tag

# Conflicts:
#	api/cast/cast.pb.go
#	api/cast/cast.pb.validate.go
#	pkg/service/cast/work.go
This commit is contained in:
cjy 2026-01-07 16:13:07 +08:00
commit d074c80af4
27 changed files with 10576 additions and 17953 deletions

View File

@ -745,6 +745,9 @@ type UserListInfo struct {
IdNumber string `protobuf:"bytes,21,opt,name=idNumber,proto3" json:"idNumber"` IdNumber string `protobuf:"bytes,21,opt,name=idNumber,proto3" json:"idNumber"`
DateOfBirth string `protobuf:"bytes,22,opt,name=dateOfBirth,proto3" json:"dateOfBirth"` DateOfBirth string `protobuf:"bytes,22,opt,name=dateOfBirth,proto3" json:"dateOfBirth"`
Age string `protobuf:"bytes,23,opt,name=age,proto3" json:"age"` Age string `protobuf:"bytes,23,opt,name=age,proto3" json:"age"`
Email string `protobuf:"bytes,24,opt,name=email,proto3" json:"email"`
AbroadTelAreaCode string `protobuf:"bytes,25,opt,name=AbroadTelAreaCode,proto3" json:"AbroadTelAreaCode"`
AbroadTel string `protobuf:"bytes,26,opt,name=AbroadTel,proto3" json:"AbroadTel"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -940,6 +943,27 @@ func (x *UserListInfo) GetAge() string {
return "" return ""
} }
func (x *UserListInfo) GetEmail() string {
if x != nil {
return x.Email
}
return ""
}
func (x *UserListInfo) GetAbroadTelAreaCode() string {
if x != nil {
return x.AbroadTelAreaCode
}
return ""
}
func (x *UserListInfo) GetAbroadTel() string {
if x != nil {
return x.AbroadTel
}
return ""
}
type UserListRequest struct { type UserListRequest struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Domain string `protobuf:"bytes,1,opt,name=domain,proto3" json:"domain"` Domain string `protobuf:"bytes,1,opt,name=domain,proto3" json:"domain"`
@ -1103,6 +1127,9 @@ type UserInfoResponse struct {
TelAreaCode string `protobuf:"bytes,19,opt,name=telAreaCode,proto3" json:"telAreaCode"` TelAreaCode string `protobuf:"bytes,19,opt,name=telAreaCode,proto3" json:"telAreaCode"`
IdNumber string `protobuf:"bytes,20,opt,name=idNumber,proto3" json:"idNumber"` IdNumber string `protobuf:"bytes,20,opt,name=idNumber,proto3" json:"idNumber"`
DateOfBirth string `protobuf:"bytes,21,opt,name=dateOfBirth,proto3" json:"dateOfBirth"` DateOfBirth string `protobuf:"bytes,21,opt,name=dateOfBirth,proto3" json:"dateOfBirth"`
Email string `protobuf:"bytes,22,opt,name=email,proto3" json:"email"`
AbroadTelAreaCode string `protobuf:"bytes,23,opt,name=AbroadTelAreaCode,proto3" json:"AbroadTelAreaCode"`
AbroadTel string `protobuf:"bytes,24,opt,name=AbroadTel,proto3" json:"AbroadTel"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -1284,6 +1311,27 @@ func (x *UserInfoResponse) GetDateOfBirth() string {
return "" return ""
} }
func (x *UserInfoResponse) GetEmail() string {
if x != nil {
return x.Email
}
return ""
}
func (x *UserInfoResponse) GetAbroadTelAreaCode() string {
if x != nil {
return x.AbroadTelAreaCode
}
return ""
}
func (x *UserInfoResponse) GetAbroadTel() string {
if x != nil {
return x.AbroadTel
}
return ""
}
type RealNameResponse struct { type RealNameResponse struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id"` Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id"`
@ -4396,6 +4444,9 @@ type UpdateRequest struct {
Domain string `protobuf:"bytes,2,opt,name=Domain,json=domain,proto3" json:"Domain"` Domain string `protobuf:"bytes,2,opt,name=Domain,json=domain,proto3" json:"Domain"`
Language string `protobuf:"bytes,3,opt,name=Language,json=language,proto3" json:"Language"` Language string `protobuf:"bytes,3,opt,name=Language,json=language,proto3" json:"Language"`
NickName string `protobuf:"bytes,4,opt,name=NickName,json=nickName,proto3" json:"NickName"` NickName string `protobuf:"bytes,4,opt,name=NickName,json=nickName,proto3" json:"NickName"`
Email string `protobuf:"bytes,5,opt,name=Email,json=email,proto3" json:"Email"`
AbroadTel string `protobuf:"bytes,6,opt,name=AbroadTel,json=abroadTel,proto3" json:"AbroadTel"`
AbroadTelAreaCode string `protobuf:"bytes,7,opt,name=AbroadTelAreaCode,json=abroadTelAreaCode,proto3" json:"AbroadTelAreaCode"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -4458,6 +4509,27 @@ func (x *UpdateRequest) GetNickName() string {
return "" return ""
} }
func (x *UpdateRequest) GetEmail() string {
if x != nil {
return x.Email
}
return ""
}
func (x *UpdateRequest) GetAbroadTel() string {
if x != nil {
return x.AbroadTel
}
return ""
}
func (x *UpdateRequest) GetAbroadTelAreaCode() string {
if x != nil {
return x.AbroadTelAreaCode
}
return ""
}
type Operator struct { type Operator struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
ID uint32 `protobuf:"varint,1,opt,name=ID,proto3" json:"ID"` ID uint32 `protobuf:"varint,1,opt,name=ID,proto3" json:"ID"`
@ -10124,7 +10196,7 @@ const file_api_accountFiee_accountFiee_proto_rawDesc = "" +
"\x05count\x18\x01 \x01(\x04R\x05count\x12\x12\n" + "\x05count\x18\x01 \x01(\x04R\x05count\x12\x12\n" +
"\x04page\x18\x02 \x01(\x04R\x04page\x12\x1a\n" + "\x04page\x18\x02 \x01(\x04R\x04page\x12\x1a\n" +
"\bpageSize\x18\x03 \x01(\x04R\bpageSize\x125\n" + "\bpageSize\x18\x03 \x01(\x04R\bpageSize\x125\n" +
"\buserList\x18\x04 \x03(\v2\x19.accountFiee.UserListInfoR\buserList\"\xd2\x05\n" + "\buserList\x18\x04 \x03(\v2\x19.accountFiee.UserListInfoR\buserList\"\xb4\x06\n" +
"\fUserListInfo\x12\x0e\n" + "\fUserListInfo\x12\x0e\n" +
"\x02id\x18\x01 \x01(\x04R\x02id\x12\x16\n" + "\x02id\x18\x01 \x01(\x04R\x02id\x12\x16\n" +
"\x06status\x18\x02 \x01(\x05R\x06status\x12\x12\n" + "\x06status\x18\x02 \x01(\x05R\x06status\x12\x12\n" +
@ -10153,7 +10225,10 @@ const file_api_accountFiee_accountFiee_proto_rawDesc = "" +
"\bnickName\x18\x14 \x01(\tR\bnickName\x12\x1a\n" + "\bnickName\x18\x14 \x01(\tR\bnickName\x12\x1a\n" +
"\bidNumber\x18\x15 \x01(\tR\bidNumber\x12 \n" + "\bidNumber\x18\x15 \x01(\tR\bidNumber\x12 \n" +
"\vdateOfBirth\x18\x16 \x01(\tR\vdateOfBirth\x12\x10\n" + "\vdateOfBirth\x18\x16 \x01(\tR\vdateOfBirth\x12\x10\n" +
"\x03age\x18\x17 \x01(\tR\x03age\"\xff\x02\n" + "\x03age\x18\x17 \x01(\tR\x03age\x12\x14\n" +
"\x05email\x18\x18 \x01(\tR\x05email\x12,\n" +
"\x11AbroadTelAreaCode\x18\x19 \x01(\tR\x11AbroadTelAreaCode\x12\x1c\n" +
"\tAbroadTel\x18\x1a \x01(\tR\tAbroadTel\"\xff\x02\n" +
"\x0fUserListRequest\x12\x16\n" + "\x0fUserListRequest\x12\x16\n" +
"\x06domain\x18\x01 \x01(\tR\x06domain\x12\x16\n" + "\x06domain\x18\x01 \x01(\tR\x06domain\x12\x16\n" +
"\x06subNum\x18\x02 \x01(\tR\x06subNum\x12$\n" + "\x06subNum\x18\x02 \x01(\tR\x06subNum\x12$\n" +
@ -10168,7 +10243,7 @@ const file_api_accountFiee_accountFiee_proto_rawDesc = "" +
" \x01(\tR\vblurNameTel\x12\x10\n" + " \x01(\tR\vblurNameTel\x12\x10\n" +
"\x03ids\x18\v \x03(\x03R\x03ids\x12 \n" + "\x03ids\x18\v \x03(\x03R\x03ids\x12 \n" +
"\vnationality\x18\f \x01(\tR\vnationality\x12$\n" + "\vnationality\x18\f \x01(\tR\vnationality\x12$\n" +
"\rnameAndNumber\x18\r \x01(\tR\rnameAndNumber\"\x92\x05\n" + "\rnameAndNumber\x18\r \x01(\tR\rnameAndNumber\"\xf4\x05\n" +
"\x10UserInfoResponse\x12\x0e\n" + "\x10UserInfoResponse\x12\x0e\n" +
"\x02id\x18\x01 \x01(\x04R\x02id\x12\x16\n" + "\x02id\x18\x01 \x01(\x04R\x02id\x12\x16\n" +
"\x06status\x18\x02 \x01(\x05R\x06status\x12\x12\n" + "\x06status\x18\x02 \x01(\x05R\x06status\x12\x12\n" +
@ -10195,7 +10270,10 @@ const file_api_accountFiee_accountFiee_proto_rawDesc = "" +
"\x06telNum\x18\x12 \x01(\tR\x06telNum\x12 \n" + "\x06telNum\x18\x12 \x01(\tR\x06telNum\x12 \n" +
"\vtelAreaCode\x18\x13 \x01(\tR\vtelAreaCode\x12\x1a\n" + "\vtelAreaCode\x18\x13 \x01(\tR\vtelAreaCode\x12\x1a\n" +
"\bidNumber\x18\x14 \x01(\tR\bidNumber\x12 \n" + "\bidNumber\x18\x14 \x01(\tR\bidNumber\x12 \n" +
"\vdateOfBirth\x18\x15 \x01(\tR\vdateOfBirth\":\n" + "\vdateOfBirth\x18\x15 \x01(\tR\vdateOfBirth\x12\x14\n" +
"\x05email\x18\x16 \x01(\tR\x05email\x12,\n" +
"\x11AbroadTelAreaCode\x18\x17 \x01(\tR\x11AbroadTelAreaCode\x12\x1c\n" +
"\tAbroadTel\x18\x18 \x01(\tR\tAbroadTel\":\n" +
"\x10RealNameResponse\x12\x0e\n" + "\x10RealNameResponse\x12\x0e\n" +
"\x02id\x18\x01 \x01(\x04R\x02id\x12\x16\n" + "\x02id\x18\x01 \x01(\x04R\x02id\x12\x16\n" +
"\x06status\x18\x02 \x01(\tR\x06status\"\x83\x03\n" + "\x06status\x18\x02 \x01(\tR\x06status\"\x83\x03\n" +
@ -10461,12 +10539,15 @@ const file_api_accountFiee_accountFiee_proto_rawDesc = "" +
"\x14WriteOffListResponse\x12\x14\n" + "\x14WriteOffListResponse\x12\x14\n" +
"\x05total\x18\x01 \x01(\x03R\x05total\x12@\n" + "\x05total\x18\x01 \x01(\x03R\x05total\x12@\n" +
"\fwriteOffList\x18\x02 \x03(\v2\x1c.accountFiee.WriteOffRequestR\fwriteOffList\"\x10\n" + "\fwriteOffList\x18\x02 \x03(\v2\x1c.accountFiee.WriteOffRequestR\fwriteOffList\"\x10\n" +
"\x0eRemoveResponse\"o\n" + "\x0eRemoveResponse\"\xd1\x01\n" +
"\rUpdateRequest\x12\x0e\n" + "\rUpdateRequest\x12\x0e\n" +
"\x02ID\x18\x01 \x01(\x04R\x02ID\x12\x16\n" + "\x02ID\x18\x01 \x01(\x04R\x02ID\x12\x16\n" +
"\x06Domain\x18\x02 \x01(\tR\x06domain\x12\x1a\n" + "\x06Domain\x18\x02 \x01(\tR\x06domain\x12\x1a\n" +
"\bLanguage\x18\x03 \x01(\tR\blanguage\x12\x1a\n" + "\bLanguage\x18\x03 \x01(\tR\blanguage\x12\x1a\n" +
"\bNickName\x18\x04 \x01(\tR\bnickName\".\n" + "\bNickName\x18\x04 \x01(\tR\bnickName\x12\x14\n" +
"\x05Email\x18\x05 \x01(\tR\x05email\x12\x1c\n" +
"\tAbroadTel\x18\x06 \x01(\tR\tabroadTel\x12,\n" +
"\x11AbroadTelAreaCode\x18\a \x01(\tR\x11abroadTelAreaCode\".\n" +
"\bOperator\x12\x0e\n" + "\bOperator\x12\x0e\n" +
"\x02ID\x18\x01 \x01(\rR\x02ID\x12\x12\n" + "\x02ID\x18\x01 \x01(\rR\x02ID\x12\x12\n" +
"\x04Name\x18\x02 \x01(\tR\x04Name\"\x82\x01\n" + "\x04Name\x18\x02 \x01(\tR\x04Name\"\x82\x01\n" +

View File

@ -183,6 +183,9 @@ message UserListInfo{
string idNumber = 21; string idNumber = 21;
string dateOfBirth = 22; string dateOfBirth = 22;
string age = 23; string age = 23;
string email = 24;
string AbroadTelAreaCode = 25;
string AbroadTel = 26;
} }
message UserListRequest{ message UserListRequest{
string domain = 1; string domain = 1;
@ -221,6 +224,10 @@ message UserInfoResponse{
string telAreaCode = 19; string telAreaCode = 19;
string idNumber = 20; string idNumber = 20;
string dateOfBirth = 21; string dateOfBirth = 21;
string email = 22;
string AbroadTelAreaCode = 23;
string AbroadTel = 24;
} }
message RealNameResponse{ message RealNameResponse{
uint64 id = 1; uint64 id = 1;
@ -541,6 +548,9 @@ message UpdateRequest {
string Domain = 2 [json_name = "domain"]; string Domain = 2 [json_name = "domain"];
string Language = 3 [json_name = "language"]; string Language = 3 [json_name = "language"];
string NickName = 4 [json_name = "nickName"]; string NickName = 4 [json_name = "nickName"];
string Email = 5 [json_name = "email"];
string AbroadTel = 6 [json_name = "abroadTel"];
string AbroadTelAreaCode = 7 [json_name = "abroadTelAreaCode"];
} }
message Operator { message Operator {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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.8 // - protoc-gen-go-triple v1.0.5
// - protoc v3.21.1 // - protoc v6.32.0
// source: pb/bundle.proto // source: pb/bundle.proto
package bundle package bundle

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -31,6 +31,7 @@ func InitTasks() error {
err = cm.AddTask("artistAutoConfirmAnalysis", "0 */1 * * * *", ArtistAutoConfirmAnalysisTask) err = cm.AddTask("artistAutoConfirmAnalysis", "0 */1 * * * *", ArtistAutoConfirmAnalysisTask)
err = cm.AddTask("refreshWorkAnalysisApprovalStatus", "0 */1 * * * *", RefreshWorkAnalysisApprovalStatusTask) err = cm.AddTask("refreshWorkAnalysisApprovalStatus", "0 */1 * * * *", RefreshWorkAnalysisApprovalStatusTask)
err = cm.AddTask("refreshArtistOrder", "0 */30 * * * *", RefreshArtistOrderTask)
// 每天 00:30 和 12:30 执行 Ayrshare 指标采集任务 // 每天 00:30 和 12:30 执行 Ayrshare 指标采集任务
// err = cm.AddTask("ayrshareMetricsCollector", "0 30 0,12 * * *", AyrshareMetricsCollectorTask) // err = cm.AddTask("ayrshareMetricsCollector", "0 30 0,12 * * *", AyrshareMetricsCollectorTask)
@ -491,3 +492,7 @@ func ArtistAutoConfirmAnalysisTask() {
func AyrshareMetricsCollectorTask() { func AyrshareMetricsCollectorTask() {
serverCast.ExecuteAyrshareMetricsCollector() serverCast.ExecuteAyrshareMetricsCollector()
} }
func RefreshArtistOrderTask() {
service.CastProvider.Tools(context.Background(), &cast.ToolsReq{Action: "refreshArtistOrder"})
}

View File

@ -24,7 +24,7 @@ func (w *Work) ExportExcelWorkList(data []*cast.WorkListResp_Info) (*excelize.Fi
// 表头 // 表头
headers := []interface{}{ headers := []interface{}{
"艺人", "手机号", "用户编号", "作品标题", "脚本", "作品类型", "类型", "Ins", "Tiktok", "DM", "作品状态", "验收确认类型", "艺人", "手机号", "用户编号", "作品标题", "脚本", "作品类型", "类型", "Ins", "Tiktok", "DM", "Youtube", "Bulesky", "作品状态", "验收确认类型",
"说明", "发布账号", "管理人", "上传时间", "待艺人确认时间", "验收确认通过时间", "发布成功时间", "说明", "发布账号", "管理人", "上传时间", "待艺人确认时间", "验收确认通过时间", "发布成功时间",
} }
if err := sw.SetRow("A1", headers); err != nil { if err := sw.SetRow("A1", headers); err != nil {
@ -72,6 +72,8 @@ func (w *Work) ExportExcelWorkList(data []*cast.WorkListResp_Info) (*excelize.Fi
modelCast.PlatformPublishStatusMM[cast.PublishStatusENUM(info.InsStatus)], modelCast.PlatformPublishStatusMM[cast.PublishStatusENUM(info.InsStatus)],
modelCast.PlatformPublishStatusMM[cast.PublishStatusENUM(info.TiktokStatus)], modelCast.PlatformPublishStatusMM[cast.PublishStatusENUM(info.TiktokStatus)],
modelCast.PlatformPublishStatusMM[cast.PublishStatusENUM(info.DmStatus)], modelCast.PlatformPublishStatusMM[cast.PublishStatusENUM(info.DmStatus)],
modelCast.PlatformPublishStatusMM[cast.PublishStatusENUM(info.YoutubeStatus)],
modelCast.PlatformPublishStatusMM[cast.PublishStatusENUM(info.BlueskyStatus)],
modelCast.WorkStatusMM[int(info.WorkStatus)], modelCast.WorkStatusMM[int(info.WorkStatus)],
modelCast.ConfirmTypeMM[int(info.ConfirmType)], modelCast.ConfirmTypeMM[int(info.ConfirmType)],
info.Remark, info.Remark,

View File

@ -16,17 +16,16 @@ const (
var PlatformNameKv = map[uint32]string{ var PlatformNameKv = map[uint32]string{
1: "tiktok", 1: "tiktok",
2: "youtube",
3: "instagram", 3: "instagram",
4: "DM", 4: "DM",
5: "bluesky",
} }
var NamePlatformIDKv = map[string]uint32{ var NamePlatformIDKv = map[string]uint32{
"tiktok": 1, "tiktok": 1,
"youtube": 2,
"instagram": 3, "instagram": 3,
"DM": 4, "DM": 4,
} "bluesky": 5,
var PlatformIDStrKv = map[string]uint8{
"TIKTOK": 1,
"INS": 2,
"DM": 4,
} }

View File

@ -23,6 +23,7 @@ func cronRouter(r *gin.RouterGroup) {
cron.POST("exportExcelExecutionResult", cronService.ExportExcelExecutionResult) cron.POST("exportExcelExecutionResult", cronService.ExportExcelExecutionResult)
cron.POST("getListExecutionRecord", cronService.GetListExecutionRecord) cron.POST("getListExecutionRecord", cronService.GetListExecutionRecord)
cron.POST("getScheduleTaskStatus", cronService.GetScheduleTaskStatus) cron.POST("getScheduleTaskStatus", cronService.GetScheduleTaskStatus)
cron.POST("getImportData", cronService.GetImportData)
} }
} }

View File

@ -62,6 +62,7 @@ func MediaRouter(r *gin.RouterGroup) {
task := auth.Group("task") task := auth.Group("task")
{ {
task.POST("list", serviceCast.TaskList) task.POST("list", serviceCast.TaskList)
task.POST("delete", serviceCast.DeleteTasK)
} }
layout := auth.Group("layout") layout := auth.Group("layout")

View File

@ -7,6 +7,7 @@ import (
"fonchain-fiee/pkg/service/account" "fonchain-fiee/pkg/service/account"
"fonchain-fiee/pkg/service/asChat" "fonchain-fiee/pkg/service/asChat"
"fonchain-fiee/pkg/service/auth" "fonchain-fiee/pkg/service/auth"
"fonchain-fiee/pkg/service/bundle"
"fonchain-fiee/pkg/service/file" "fonchain-fiee/pkg/service/file"
"fonchain-fiee/pkg/service/governance" "fonchain-fiee/pkg/service/governance"
imports "fonchain-fiee/pkg/service/import" imports "fonchain-fiee/pkg/service/import"
@ -83,6 +84,7 @@ func NewRouter() *gin.Engine {
{ {
webAcRouter.POST("list", account.UserList) //用户列表 webAcRouter.POST("list", account.UserList) //用户列表
webAcRouter.POST("approval", account.UserApproval) //实名审核 webAcRouter.POST("approval", account.UserApproval) //实名审核
webAcRouter.POST("admin-update", account.AdminUpdate) //更新用户信息
webAcRouter.POST("excel/download", account.UserExcelDownload) //excel下载 webAcRouter.POST("excel/download", account.UserExcelDownload) //excel下载
} }
} }
@ -215,6 +217,10 @@ func NewRouter() *gin.Engine {
importRoute.GET("generate/photo/test2", imports.Test2) importRoute.GET("generate/photo/test2", imports.Test2)
} }
{
//健康检测
v1.GET("health", bundle.HealthCheck)
}
//静态文件 //静态文件
r.StaticFS("/api/fiee/static", http.Dir("./runtime")) r.StaticFS("/api/fiee/static", http.Dir("./runtime"))
r.NoRoute(func(c *gin.Context) { r.NoRoute(func(c *gin.Context) {

View File

@ -130,6 +130,37 @@ func UserUpdate(c *gin.Context) {
Domain: req.Domain, Domain: req.Domain,
Language: req.Language, Language: req.Language,
NickName: req.NickName, NickName: req.NickName,
Email: req.Email,
AbroadTel: req.AbroadTel,
AbroadTelAreaCode: req.AbroadTelAreaCode,
})
if err != nil {
service.Error(c, err)
return
}
service.Success(c, res)
return
}
func AdminUpdate(c *gin.Context) {
var req account.UpdateRequest
if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil {
service.Error(c, err)
return
}
if req.ID == 0 {
service.Error(c, errors.New("用户ID不能为空"))
return
}
req.Domain = "app"
res, err := service.AccountFieeProvider.Update(c, &account.UpdateRequest{
ID: req.ID,
Domain: req.Domain,
//Language: req.Language,
//NickName: req.NickName,
Email: req.Email,
AbroadTel: req.AbroadTel,
AbroadTelAreaCode: req.AbroadTelAreaCode,
}) })
if err != nil { if err != nil {
service.Error(c, err) service.Error(c, err)

View File

@ -250,6 +250,10 @@ func CreateBundleOrderSignature(c *gin.Context) {
// 组装订单信息 // 组装订单信息
req = logic.BuildOrderRequest(req, userInfo, bundleDetail, addRecords, addTotalPrice, lastContractNo, signContract) req = logic.BuildOrderRequest(req, userInfo, bundleDetail, addRecords, addTotalPrice, lastContractNo, signContract)
// 校验发布平台
if len(req.PlatformIds) == 0 {
req.PlatformIds = []uint32{1, 4, 5}
}
// 创建订单 // 创建订单
res, err := service.BundleProvider.CreateOrderRecord(context.Background(), &req) res, err := service.BundleProvider.CreateOrderRecord(context.Background(), &req)
if err != nil { if err != nil {

View File

@ -0,0 +1,180 @@
package bundle
import (
"context"
"fonchain-fiee/api/bundle"
"fonchain-fiee/api/cast"
"fonchain-fiee/api/files"
"fonchain-fiee/api/governance"
"fonchain-fiee/api/order"
"fonchain-fiee/api/payment"
"fonchain-fiee/pkg/cache"
"fonchain-fiee/pkg/service"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
// HealthCheck 健康检测接口
func HealthCheck(c *gin.Context) {
healthStatus := gin.H{
"status": "ok",
"timestamp": time.Now().Unix(),
"checks": make(map[string]interface{}),
}
// 检查 Redis 连接
redisStatus := "ok"
redisErr := ""
if cache.RedisClient != nil {
_, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
_, err := cache.RedisClient.Ping().Result()
if err != nil {
redisStatus = "failed"
redisErr = err.Error()
}
} else {
redisStatus = "failed"
redisErr = "Redis client is nil"
}
healthStatus["checks"].(map[string]interface{})["redis"] = gin.H{
"status": redisStatus,
"error": redisErr,
}
// 检查微服务连接(调用一个简单的服务方法)
serviceStatus := "ok"
serviceErr := ""
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
// 调用 BundleProvider 的简单方法进行健康检测
_, err := service.BundleProvider.GetBundleBalanceByUserId(ctx, &bundle.GetBundleBalanceByUserIdReq{
UserId: 0, // 使用一个不存在的用户ID只检测服务连通性
})
if err != nil {
// 检查是否是超时或连接错误
if ctx.Err() == context.DeadlineExceeded {
serviceStatus = "Bundle Service timeout"
serviceErr = "Service timeout"
} else {
// 其他错误(如业务错误)认为服务是可用的
serviceStatus = "ok"
serviceErr = ""
}
}
healthStatus["checks"].(map[string]interface{})["bundleService"] = gin.H{
"status": serviceStatus,
"error": serviceErr,
}
//调用 OrderProvider 的简单方法进行健康检测
_, err = service.OrderProvider.GetOrder(ctx, &order.CommonRequest{
ID: 0,
Domain: "",
SeriesUid: "", // 使用一个不存在的订单ID只检测服务连通性
})
if err != nil {
if ctx.Err() == context.DeadlineExceeded {
serviceStatus = "Order Service timeout"
serviceErr = "Service timeout"
} else {
// 其他错误(如业务错误)认为服务是可用的
serviceStatus = "ok"
serviceErr = ""
}
}
healthStatus["checks"].(map[string]interface{})["orderService"] = gin.H{
"status": serviceStatus,
"error": serviceErr,
}
//调用 FilesProvider 的简单方法进行健康检测
_, err = service.FilesProvider.List(ctx, &files.FileListReq{
Path: "/",
UserSpacePath: "/fiee",
Page: 1,
PageSize: 50,
})
if err != nil {
if ctx.Err() == context.DeadlineExceeded {
serviceStatus = "Filesbrowser Service timeout"
serviceErr = "Service timeout"
} else {
// 其他错误(如业务错误)认为服务是可用的
serviceStatus = "ok"
serviceErr = ""
}
}
healthStatus["checks"].(map[string]interface{})["filesbrowserService"] = gin.H{
"status": serviceStatus,
"error": serviceErr,
}
//调用 PaymentProvider 的简单方法进行健康检测
_, err = service.PaymentProvider.QueryPayByOutTradeNo(ctx, &payment.PayQueryRequest{
PayType: "2",
OutTradeNo: "1234567890",
})
if err != nil {
if ctx.Err() == context.DeadlineExceeded {
serviceStatus = "Payment Service timeout"
serviceErr = "Service timeout"
} else {
// 其他错误(如业务错误)认为服务是可用的
serviceStatus = "ok"
serviceErr = ""
}
}
healthStatus["checks"].(map[string]interface{})["paymentService"] = gin.H{
"status": serviceStatus,
"error": serviceErr,
}
//调用 CastProvider 的简单方法进行健康检测
_, err = service.CastProvider.WorkList(ctx, &cast.WorkListReq{
Page: 1,
PageSize: 10,
})
if err != nil {
if ctx.Err() == context.DeadlineExceeded {
serviceStatus = "Cast Service timeout"
serviceErr = "Service timeout"
} else {
// 其他错误(如业务错误)认为服务是可用的
serviceStatus = "ok"
serviceErr = ""
}
}
healthStatus["checks"].(map[string]interface{})["castService"] = gin.H{
"status": serviceStatus,
"error": serviceErr,
}
//调用 GovernanceProvider 的简单方法进行健康检测
_, err = service.GovernanceProvider.List(ctx, &governance.ListReq{
Page: 1,
PageSize: 10,
})
if err != nil {
if ctx.Err() == context.DeadlineExceeded {
serviceStatus = "Document Service timeout"
serviceErr = "Service timeout"
} else {
// 其他错误(如业务错误)认为服务是可用的
serviceStatus = "ok"
serviceErr = ""
}
}
healthStatus["checks"].(map[string]interface{})["documentService"] = gin.H{
"status": serviceStatus,
"error": serviceErr,
}
// 如果所有检查都通过,返回 200否则返回 503
httpStatus := http.StatusOK
if redisStatus != "ok" || serviceStatus != "ok" {
httpStatus = http.StatusServiceUnavailable
healthStatus["status"] = "degraded"
}
c.JSON(httpStatus, healthStatus)
}

View File

@ -418,6 +418,7 @@ func AutoCreateUserAndOrder(c *gin.Context) {
orderReq.OrderNo = unfinishInfo.OrderNo orderReq.OrderNo = unfinishInfo.OrderNo
//expirationTime := t.AddDate(10, 0, 0).Format("2006-01-02 15:04:05") //expirationTime := t.AddDate(10, 0, 0).Format("2006-01-02 15:04:05")
//orderReq.ExpirationTime = expirationTime //orderReq.ExpirationTime = expirationTime
orderReq.PlatformIds = []uint32{1, 4, 5}
_, err = service.BundleProvider.CreateOrderRecord(context.Background(), &orderReq) _, err = service.BundleProvider.CreateOrderRecord(context.Background(), &orderReq)
if err != nil { if err != nil {
service.Error(c, err) service.Error(c, err)

View File

@ -44,6 +44,7 @@ func MediaUserList(ctx *gin.Context) {
service.Error(ctx, err) service.Error(ctx, err)
return return
} }
if req.NeedStats {
var statResp *bundle.ArtistUploadStatsResponse var statResp *bundle.ArtistUploadStatsResponse
zap.L().Info("MediaUserList 1") zap.L().Info("MediaUserList 1")
//取出艺人num //取出艺人num
@ -65,7 +66,6 @@ func MediaUserList(ctx *gin.Context) {
service.Error(ctx, err) service.Error(ctx, err)
return return
} }
if req.NeedStats {
for _, v := range resp.Data { for _, v := range resp.Data {
for _, vv := range statResp.Items { for _, vv := range statResp.Items {
if v.ArtistSubNum == vv.SubNum { if v.ArtistSubNum == vv.SubNum {
@ -325,6 +325,7 @@ func OAuth2Callback(ctx *gin.Context) {
service.Error(ctx, errors.New(e.GetMsg(e.InvalidParams))) service.Error(ctx, errors.New(e.GetMsg(e.InvalidParams)))
return return
} }
req.State = state
zap.L().Info("OAuth2Callback", zap.Any("req", req), zap.Any("code", code), zap.Any("state", state)) zap.L().Info("OAuth2Callback", zap.Any("req", req), zap.Any("code", code), zap.Any("state", state))
_, err := service.CastProvider.OAuthCodeToToken(ctx, req) _, err := service.CastProvider.OAuthCodeToToken(ctx, req)
if err != nil { if err != nil {
@ -381,6 +382,7 @@ func SyncAsAuth(artistUuid string) error {
InstagramDetails: true, InstagramDetails: true,
}) })
if err != nil { if err != nil {
zap.L().Error("SyncAsAuth error", zap.Error(err))
return errors.New("获取艺人绑定信息错误") return errors.New("获取艺人绑定信息错误")
} }
authReq := &cast.UpdateOAuthReq{Data: make([]*cast.UpdateOAuthReq_Info, 0)} authReq := &cast.UpdateOAuthReq{Data: make([]*cast.UpdateOAuthReq_Info, 0)}
@ -407,10 +409,14 @@ func SyncAsAuth(artistUuid string) error {
if platformIDENUM == cast.PlatformIDENUM_UNKNOWN { if platformIDENUM == cast.PlatformIDENUM_UNKNOWN {
continue continue
} }
asID := v.Id
if platformIDENUM == cast.PlatformIDENUM_BULESKY && asID == "" {
asID = v.Username
}
authReq.Data = append(authReq.Data, &cast.UpdateOAuthReq_Info{ authReq.Data = append(authReq.Data, &cast.UpdateOAuthReq_Info{
ArtistUuid: artistUuid, ArtistUuid: artistUuid,
PlatformID: platformIDENUM, PlatformID: platformIDENUM,
AsID: v.Id, AsID: asID,
PlatformUserName: v.Username, PlatformUserName: v.Username,
AutInfo: string(asInfoB), AutInfo: string(asInfoB),
}) })
@ -606,7 +612,7 @@ func ImportMediaAccount(ctx *gin.Context) {
excelSetRemark(excelData, line, "艺人不存在") excelSetRemark(excelData, line, "艺人不存在")
continue continue
} }
var tiktokName, insName, dmName string var tiktokName, insName, dmName, youtubeName, blueskyName string
if len(row) >= 3 { if len(row) >= 3 {
tiktokName = strings.TrimSpace(row[2]) tiktokName = strings.TrimSpace(row[2])
} }
@ -616,7 +622,13 @@ func ImportMediaAccount(ctx *gin.Context) {
if len(row) >= 5 { if len(row) >= 5 {
dmName = strings.TrimSpace(row[4]) dmName = strings.TrimSpace(row[4])
} }
if tiktokName == "" && insName == "" && dmName == "" { if len(row) >= 6 {
youtubeName = strings.TrimSpace(row[5])
}
if len(row) >= 7 {
blueskyName = strings.TrimSpace(row[6])
}
if tiktokName == "" && insName == "" && dmName == "" && youtubeName == "" && blueskyName == "" {
excelSetRemark(excelData, line, "请填写账号") excelSetRemark(excelData, line, "请填写账号")
continue continue
} }
@ -635,6 +647,17 @@ func ImportMediaAccount(ctx *gin.Context) {
excelSetRemark(excelData, line, fmt.Sprintf("%s:%s", dmName, err.Error())) excelSetRemark(excelData, line, fmt.Sprintf("%s:%s", dmName, err.Error()))
} }
} }
if youtubeName != "" {
if err = updateMediaAccount(youtubeName, cast.PlatformIDENUM_YOUTUBE, subInfoResp, loginInfo); err != nil {
excelSetRemark(excelData, line, fmt.Sprintf("%s:%s", youtubeName, err.Error()))
}
}
if blueskyName != "" {
if err = updateMediaAccount(blueskyName, cast.PlatformIDENUM_BULESKY, subInfoResp, loginInfo); err != nil {
excelSetRemark(excelData, line, fmt.Sprintf("%s:%s", blueskyName, err.Error()))
}
}
_ = CheckAsProfile(subInfoResp)
} }
// 保存Excel文件到磁盘 // 保存Excel文件到磁盘
resultPath := fmt.Sprintf("./runtime/media/%s", fileName) resultPath := fmt.Sprintf("./runtime/media/%s", fileName)
@ -658,14 +681,14 @@ func ImportMediaAccount(ctx *gin.Context) {
// 记录需要删除的行(从后往前删除,避免行号变化) // 记录需要删除的行(从后往前删除,避免行号变化)
rowsToDelete := make([]int, 0) rowsToDelete := make([]int, 0)
for line := 1; line < len(rows); line++ { // 从第2行开始跳过表头 for line := 1; line < len(rows); line++ { // 从第2行开始跳过表头
remarkCell := fmt.Sprintf("F%d", line+1) remarkCell := fmt.Sprintf("H%d", line+1) // 备注列已移动到H列
remark, _ := excelData.GetCellValue("Sheet1", remarkCell) remark, _ := excelData.GetCellValue("Sheet1", remarkCell)
if remark == "" { if remark == "" {
// F列没有数据,表示成功 // H列没有数据,表示成功
successCount++ successCount++
rowsToDelete = append(rowsToDelete, line+1) rowsToDelete = append(rowsToDelete, line+1)
} else { } else {
// F列有值,表示失败 // H列有值,表示失败
failCount++ failCount++
} }
} }
@ -698,11 +721,11 @@ func ImportMediaAccount(ctx *gin.Context) {
func excelSetRemark(excelData *excelize.File, line int, remark string) { func excelSetRemark(excelData *excelize.File, line int, remark string) {
zap.L().Info("设置备注", zap.Int("line", line), zap.String("remark", remark)) zap.L().Info("设置备注", zap.Int("line", line), zap.String("remark", remark))
oldRemark, _ := excelData.GetCellValue("Sheet1", fmt.Sprintf("%s%d", "F", line+1)) oldRemark, _ := excelData.GetCellValue("Sheet1", fmt.Sprintf("%s%d", "H", line+1))
if oldRemark != "" { if oldRemark != "" {
remark = fmt.Sprintf("%s\n%s", oldRemark, remark) remark = fmt.Sprintf("%s\n%s", oldRemark, remark)
} }
excelData.SetCellValue("Sheet1", fmt.Sprintf("%s%d", "F", line+1), remark) excelData.SetCellValue("Sheet1", fmt.Sprintf("%s%d", "H", line+1), remark)
} }
func updateMediaAccount(platformName string, platformId cast.PlatformIDENUM, subInfoResp *accountFiee.UserInfoResponse, loginInfo login.Info) error { func updateMediaAccount(platformName string, platformId cast.PlatformIDENUM, subInfoResp *accountFiee.UserInfoResponse, loginInfo login.Info) error {

View File

@ -26,3 +26,21 @@ func TaskList(ctx *gin.Context) {
} }
service.Success(ctx, resp) service.Success(ctx, resp)
} }
func DeleteTasK(ctx *gin.Context) {
var req *cast.DeleteTaskListReq
var err error
if err = ctx.ShouldBind(&req); err != nil {
service.Error(ctx, err)
return
}
//loginInfo := login.GetUserInfoFromC(ctx)
//req.OperatorID = fmt.Sprint(loginInfo.ID)
resp, err := service.CastProvider.DeleteTaskList(context.Background(), req)
if err != nil {
service.Error(ctx, err)
return
}
service.Success(ctx, resp)
return
}

View File

@ -156,6 +156,15 @@ func Test(ctx *gin.Context) {
} }
service.Success(ctx, "ok") service.Success(ctx, "ok")
} }
if action == "SyncAsAuth" {
artistUuid := ctx.PostForm("artistUuid")
err := SyncAsAuth(artistUuid)
if err != nil {
service.Error(ctx, err)
return
}
service.Success(ctx, "ok")
}
service.Success(ctx, "unknow") service.Success(ctx, "unknow")
return return

View File

@ -48,21 +48,16 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
) )
func UpdateWorkImage(ctx *gin.Context) { // UpdateWorkImageCore 更新作品图片的核心逻辑,可以被其他函数复用
var req *cast.UpdateWorkImageReq func UpdateWorkImageCore(ctx *gin.Context, req *cast.UpdateWorkImageReq) (*cast.UpdateWorkImageResp, error) {
var infoResp *accountFiee.UserInfoResponse var infoResp *accountFiee.UserInfoResponse
var err error var err error
var ok bool var ok bool
if err = ctx.ShouldBind(&req); err != nil {
service.Error(ctx, err)
return
}
loginInfo := login.GetUserInfoFromC(ctx) loginInfo := login.GetUserInfoFromC(ctx)
lockKey := fmt.Sprintf("lock_update_work_image_%d", loginInfo.ID) lockKey := fmt.Sprintf("lock_update_work_image_%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)
if !reply.Val() { if !reply.Val() {
service.Error(ctx, errors.New("请勿重复提交")) return nil, errors.New("请勿重复提交")
return
} }
defer func() { defer func() {
cache.RedisClient.Del(lockKey) cache.RedisClient.Del(lockKey)
@ -72,37 +67,30 @@ func UpdateWorkImage(ctx *gin.Context) {
/*for _, v := range req.Images { /*for _, v := range req.Images {
ok, err = check.SecurityFile(v) ok, err = check.SecurityFile(v)
if err != nil { if err != nil {
service.Error(ctx, err) return nil, err
return
} }
if !ok { if !ok {
service.Error(ctx, errors.New("图片鉴定未通过")) return nil, errors.New("图片鉴定未通过")
return
} }
} }
ok, err = check.SecurityText(req.Title) ok, err = check.SecurityText(req.Title)
if err != nil { if err != nil {
service.Error(ctx, err) return nil, err
return
} }
if !ok { if !ok {
service.Error(ctx, errors.New("标题鉴定未通过")) return nil, errors.New("标题鉴定未通过")
return
} }
ok, err = check.SecurityText(req.Content) ok, err = check.SecurityText(req.Content)
if err != nil { if err != nil {
service.Error(ctx, err) return nil, err
return
} }
if !ok { if !ok {
service.Error(ctx, errors.New("内容鉴定未通过")) return nil, errors.New("内容鉴定未通过")
return
}*/ }*/
if req.From != "ai" { if req.From != "ai" {
for _, v := range req.Images { for _, v := range req.Images {
if filepath.Ext(v) != ".jpg" && filepath.Ext(v) != ".jpeg" { if filepath.Ext(v) != ".jpg" && filepath.Ext(v) != ".jpeg" {
service.Error(ctx, errors.New("图片格式只支持jpg")) return nil, errors.New("图片格式只支持jpg")
return
} }
} }
} }
@ -112,8 +100,7 @@ func UpdateWorkImage(ctx *gin.Context) {
for _, v := range images { for _, v := range images {
imageUrl, err = checkAndReuploadImage(v, "image") imageUrl, err = checkAndReuploadImage(v, "image")
if err != nil { if err != nil {
service.Error(ctx, errors.New("图片转换错误")) return nil, errors.New("图片转换错误")
return
} }
req.Images = append(req.Images, imageUrl) req.Images = append(req.Images, imageUrl)
} }
@ -124,8 +111,7 @@ func UpdateWorkImage(ctx *gin.Context) {
}) })
zap.L().Info("UpdateWorkImage infoResp", zap.Any("infoResp", infoResp)) zap.L().Info("UpdateWorkImage infoResp", zap.Any("infoResp", infoResp))
if err != nil { if err != nil {
service.Error(ctx, err) return nil, err
return
} }
req.ArtistName = infoResp.Name req.ArtistName = infoResp.Name
@ -134,8 +120,7 @@ func UpdateWorkImage(ctx *gin.Context) {
req.ArtistSubNum = infoResp.SubNum req.ArtistSubNum = infoResp.SubNum
//artistID, _ := strconv.ParseUint(req.ArtistUuid, 10, 64) //artistID, _ := strconv.ParseUint(req.ArtistUuid, 10, 64)
//if _, err = CheckUserBundleBalance(int32(artistID), modelCast.BalanceTypeImageValue); err != nil { //if _, err = CheckUserBundleBalance(int32(artistID), modelCast.BalanceTypeImageValue); err != nil {
// service.Error(ctx, err) // return nil, err
// return
//} //}
// 处理内容中的标签:提取、验证并批量导入 // 处理内容中的标签:提取、验证并批量导入
if err = processContentTags(ctx, req.Content); err != nil { if err = processContentTags(ctx, req.Content); err != nil {
@ -146,6 +131,20 @@ func UpdateWorkImage(ctx *gin.Context) {
req.Source = 1 req.Source = 1
resp, err := service.CastProvider.UpdateWorkImage(newCtx, req) resp, err := service.CastProvider.UpdateWorkImage(newCtx, req)
zap.L().Info("UpdateWorkImage resp", zap.Any("resp", resp)) zap.L().Info("UpdateWorkImage resp", zap.Any("resp", resp))
if err != nil {
return nil, err
}
return resp, nil
}
func UpdateWorkImage(ctx *gin.Context) {
var req *cast.UpdateWorkImageReq
var err error
if err = ctx.ShouldBind(&req); err != nil {
service.Error(ctx, err)
return
}
resp, err := UpdateWorkImageCore(ctx, req)
if err != nil { if err != nil {
service.Error(ctx, err) service.Error(ctx, err)
return return
@ -220,27 +219,21 @@ func processContentTags(ctx *gin.Context, content string) error {
return nil return nil
} }
func UpdateWorkVideo(ctx *gin.Context) { // UpdateWorkVideoCore 更新作品视频的核心逻辑,可以被其他函数复用
var req *cast.UpdateWorkVideoReq func UpdateWorkVideoCore(ctx *gin.Context, req *cast.UpdateWorkVideoReq) (*cast.UpdateWorkVideoResp, error) {
var infoResp *accountFiee.UserInfoResponse var infoResp *accountFiee.UserInfoResponse
var err error var err error
var ok bool var ok bool
if err = ctx.ShouldBind(&req); err != nil {
service.Error(ctx, err)
return
}
if req.CoverUrl != "" { if req.CoverUrl != "" {
if filepath.Ext(req.CoverUrl) != ".jpg" && filepath.Ext(req.CoverUrl) != ".jpeg" { if filepath.Ext(req.CoverUrl) != ".jpg" && filepath.Ext(req.CoverUrl) != ".jpeg" {
service.Error(ctx, errors.New("图片格式只支持jpg")) return nil, errors.New("图片格式只支持jpg")
return
} }
} }
loginInfo := login.GetUserInfoFromC(ctx) loginInfo := login.GetUserInfoFromC(ctx)
lockKey := fmt.Sprintf("lock_update_work_video_%d", loginInfo.ID) lockKey := fmt.Sprintf("lock_update_work_video_%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)
if !reply.Val() { if !reply.Val() {
service.Error(ctx, errors.New("请勿重复提交")) return nil, errors.New("请勿重复提交")
return
} }
defer func() { defer func() {
cache.RedisClient.Del(lockKey) cache.RedisClient.Del(lockKey)
@ -248,44 +241,36 @@ func UpdateWorkVideo(ctx *gin.Context) {
fmt.Println(ok) fmt.Println(ok)
/* ok, err = check.SecurityText(req.Title) /* ok, err = check.SecurityText(req.Title)
if err != nil { if err != nil {
service.Error(ctx, err) return nil, err
return
} }
if !ok { if !ok {
service.Error(ctx, errors.New("标题鉴定未通过")) return nil, errors.New("标题鉴定未通过")
return
} }
ok, err = check.SecurityText(req.Content) ok, err = check.SecurityText(req.Content)
if err != nil { if err != nil {
service.Error(ctx, err) return nil, err
return
} }
if !ok { if !ok {
service.Error(ctx, errors.New("内容鉴定未通过")) return nil, errors.New("内容鉴定未通过")
return
} }
ok, err = check.SecurityFile(req.CoverUrl) ok, err = check.SecurityFile(req.CoverUrl)
if err != nil { if err != nil {
service.Error(ctx, err) return nil, err
return
} }
if !ok { if !ok {
service.Error(ctx, errors.New("图片鉴定未通过")) return nil, errors.New("图片鉴定未通过")
return
}*/ }*/
if req.VideoUrl != "" { if req.VideoUrl != "" && false {
//请求接口判断 //请求接口判断
fileResp, errs := service.FilesProvider.GetFileSecurityStatus(ctx, &files.GetFileSecurityStatusReq{ fileResp, errs := service.FilesProvider.GetFileSecurityStatus(ctx, &files.GetFileSecurityStatusReq{
Url: req.VideoUrl, Url: req.VideoUrl,
FileName: "", FileName: "",
}) })
if errs != nil { if errs != nil {
service.Error(ctx, err) return nil, errs
return
} }
if fileResp.SecurityStatus == "high" { if fileResp.SecurityStatus == "high" {
service.Error(ctx, errors.New("视频鉴定未通过")) return nil, errors.New("视频鉴定未通过")
return
} }
} }
if config.AppConfig.System.AppMode != "dev" { if config.AppConfig.System.AppMode != "dev" {
@ -296,8 +281,7 @@ func UpdateWorkVideo(ctx *gin.Context) {
}) })
zap.L().Info("UpdateWorkVideo", zap.Any("infoResp", infoResp)) zap.L().Info("UpdateWorkVideo", zap.Any("infoResp", infoResp))
if err != nil { if err != nil {
service.Error(ctx, err) return nil, err
return
} }
} else { } else {
infoResp = &accountFiee.UserInfoResponse{ infoResp = &accountFiee.UserInfoResponse{
@ -308,8 +292,7 @@ func UpdateWorkVideo(ctx *gin.Context) {
} }
//artistID, _ := strconv.ParseUint(req.ArtistUuid, 10, 64) //artistID, _ := strconv.ParseUint(req.ArtistUuid, 10, 64)
//if _, err = CheckUserBundleBalance(int32(artistID), modelCast.BalanceTypeVideoValue); err != nil { //if _, err = CheckUserBundleBalance(int32(artistID), modelCast.BalanceTypeVideoValue); err != nil {
// service.Error(ctx, err) // return nil, err
// return
//} //}
req.ArtistName = infoResp.Name req.ArtistName = infoResp.Name
req.ArtistPhone = infoResp.TelNum req.ArtistPhone = infoResp.TelNum
@ -324,6 +307,20 @@ func UpdateWorkVideo(ctx *gin.Context) {
req.Source = 1 req.Source = 1
resp, err := service.CastProvider.UpdateWorkVideo(newCtx, req) resp, err := service.CastProvider.UpdateWorkVideo(newCtx, req)
zap.L().Info("UpdateWorkVideo", zap.Any("resp", resp)) zap.L().Info("UpdateWorkVideo", zap.Any("resp", resp))
if err != nil {
return nil, err
}
return resp, nil
}
func UpdateWorkVideo(ctx *gin.Context) {
var req *cast.UpdateWorkVideoReq
var err error
if err = ctx.ShouldBind(&req); err != nil {
service.Error(ctx, err)
return
}
resp, err := UpdateWorkVideoCore(ctx, req)
if err != nil { if err != nil {
service.Error(ctx, err) service.Error(ctx, err)
return return
@ -677,6 +674,29 @@ func PostAS(workUuid string) error {
ThumbNail: "", ThumbNail: "",
Visibility: "", Visibility: "",
} }
case cast.PlatformIDENUM_YOUTUBE:
// YouTube 发布选项配置
postReq.YouTubeOptions = &aryshare.YouTubeOptions{
Title: workDetail.Title,
Visibility: "public", // 可见性设置public/unlisted/private
Tags: nil,
// CategoryId: 0, // YouTube 分类 ID例如24 = Entertainment
MadeForKids: false,
ThumbNail: coverUrl,
PlaylistId: "",
NotifySubscribers: true,
Shorts: false,
ContainsSyntheticMedia: false,
PublishAt: "",
SubTitleUrl: "",
SubTitleLanguage: "",
SubTitleName: "",
}
case cast.PlatformIDENUM_BULESKY: // BLUESKY
// Bluesky 发布选项配置
postReq.BlueskyOptions = &aryshare.BlueskyOptions{
AltText: nil, // 图片或视频的替代文本数组(用于屏幕阅读器的无障碍功能)
}
} }
zap.L().Info("post 6", zap.Any("workUuid", workUuid), zap.Any("platformID", platformID)) zap.L().Info("post 6", zap.Any("workUuid", workUuid), zap.Any("platformID", platformID))
zap.L().Info("Publish Ayrshare PostReq", zap.Any("workUuid", workDetail.WorkUuid), zap.Any("postReq", postReq), zap.Any("workDetail", workDetail)) zap.L().Info("Publish Ayrshare PostReq", zap.Any("workUuid", workDetail.WorkUuid), zap.Any("postReq", postReq), zap.Any("workDetail", workDetail))
@ -758,6 +778,10 @@ func PostAS(workUuid string) error {
pid = 1 pid = 1
case "instagram": case "instagram":
pid = 3 pid = 3
case "youtube":
pid = 2
case "bluesky":
pid = 5
} }
publishStatus := cast.PublishStatusENUM_PublishMediaStatus_NO publishStatus := cast.PublishStatusENUM_PublishMediaStatus_NO
if postInfo.Status == "success" { if postInfo.Status == "success" {
@ -1338,8 +1362,8 @@ func ImportWorkBatch(ctx *gin.Context) {
temp.ArtistPhone = subInfoResp.TelNum temp.ArtistPhone = subInfoResp.TelNum
temp.ArtistPhoneAreaCode = subInfoResp.TelAreaCode temp.ArtistPhoneAreaCode = subInfoResp.TelAreaCode
} }
if len(row) > 5 { if len(row) > 7 {
temp.Title = utils.CleanString(row[5]) temp.Title = utils.CleanString(row[7])
ok, _err := check.SecurityText(temp.Title) ok, _err := check.SecurityText(temp.Title)
if _err != nil { if _err != nil {
temp.Remark = _err.Error() temp.Remark = _err.Error()
@ -1352,8 +1376,8 @@ func ImportWorkBatch(ctx *gin.Context) {
break break
} }
} }
if len(row) > 6 { if len(row) > 8 {
temp.Content = utils.CleanString(row[6]) temp.Content = utils.CleanString(row[8])
if temp.Content != "" { if temp.Content != "" {
ok, _err := check.SecurityText(temp.Content) ok, _err := check.SecurityText(temp.Content)
if _err != nil { if _err != nil {
@ -1368,8 +1392,7 @@ func ImportWorkBatch(ctx *gin.Context) {
} }
} }
} }
// 图片 for i := 10; i <= 20; i++ {
for i := 8; i <= 18; i++ {
if len(row) > i { if len(row) > i {
if utils.CleanString(row[i]) != "" { if utils.CleanString(row[i]) != "" {
ok, _err := check.SecurityFile(row[i]) ok, _err := check.SecurityFile(row[i])
@ -1379,7 +1402,7 @@ func ImportWorkBatch(ctx *gin.Context) {
break break
} }
if !ok { if !ok {
temp.Remark = fmt.Sprintf("图片%d黄反审核未通过", i-7) temp.Remark = fmt.Sprintf("图片%d黄反审核未通过", i-9)
req.ImageWorks = append(req.ImageWorks, temp) req.ImageWorks = append(req.ImageWorks, temp)
break break
} }
@ -1470,6 +1493,60 @@ func ImportWorkBatch(ctx *gin.Context) {
temp.MediaAccountNames = append(temp.MediaAccountNames, utils.CleanString(row[4])) temp.MediaAccountNames = append(temp.MediaAccountNames, utils.CleanString(row[4]))
temp.MediaAccountUuids = append(temp.MediaAccountUuids, mediaInfoResp.Info.MediaAccountUuid)*/ temp.MediaAccountUuids = append(temp.MediaAccountUuids, mediaInfoResp.Info.MediaAccountUuid)*/
} }
// YouTube账号第F列row[5]
if len(row) > 5 && utils.CleanString(row[5]) != "" {
temp.Remark = fmt.Sprintf("Youtube不能发图文")
zap.L().Error("CastProvider.MediaInfo", zap.Error(err))
req.ImageWorks = append(req.ImageWorks, temp)
continue
// mediaInfoResp, err = service.CastProvider.MediaInfo(context.Background(), &cast.MediaInfoReq{
// ArtistUuid: temp.ArtistUuid,
// PlatformID: cast.PlatformIDENUM_YOUTUBE,
// PlatformUserName: utils.CleanString(row[5]),
// })
// if err != nil || mediaInfoResp.Info.MediaAccountUuid == "" {
// temp.Remark = fmt.Sprintf("YouTube账号名不存在")
// zap.L().Error("CastProvider.MediaInfo", zap.Error(err))
// req.ImageWorks = append(req.ImageWorks, temp)
// continue
// }
// temp.PublishConfig1 = &cast.PublishConfig{
// ForbidComment: 1,
// PublicType: 1,
// CanJoin: 1,
// CanQuote: 1,
// CanComment: 1,
// IsAI: 1,
// }
// temp.PlatformIDs = append(temp.PlatformIDs, cast.PlatformIDENUM_YOUTUBE)
// temp.MediaAccountNames = append(temp.MediaAccountNames, utils.CleanString(row[5]))
// temp.MediaAccountUuids = append(temp.MediaAccountUuids, mediaInfoResp.Info.MediaAccountUuid)
}
// Bluesky账号第G列row[6]
if len(row) > 6 && utils.CleanString(row[6]) != "" {
mediaInfoResp, err = service.CastProvider.MediaInfo(context.Background(), &cast.MediaInfoReq{
ArtistUuid: temp.ArtistUuid,
PlatformID: cast.PlatformIDENUM_BULESKY,
PlatformUserName: utils.CleanString(row[6]),
})
if err != nil || mediaInfoResp.Info.MediaAccountUuid == "" {
temp.Remark = fmt.Sprintf("Bluesky账号名不存在")
zap.L().Error("CastProvider.MediaInfo", zap.Error(err))
req.ImageWorks = append(req.ImageWorks, temp)
continue
}
temp.PublishConfig1 = &cast.PublishConfig{
ForbidComment: 1,
PublicType: 1,
CanJoin: 1,
CanQuote: 1,
CanComment: 1,
IsAI: 1,
}
temp.PlatformIDs = append(temp.PlatformIDs, cast.PlatformIDENUM_BULESKY)
temp.MediaAccountNames = append(temp.MediaAccountNames, utils.CleanString(row[6]))
temp.MediaAccountUuids = append(temp.MediaAccountUuids, mediaInfoResp.Info.MediaAccountUuid)
}
if artistNum == "" { if artistNum == "" {
temp.Remark = "艺人编号不能为空" temp.Remark = "艺人编号不能为空"
req.ImageWorks = append(req.ImageWorks, temp) req.ImageWorks = append(req.ImageWorks, temp)
@ -1500,6 +1577,12 @@ func ImportWorkBatch(ctx *gin.Context) {
req.ImageWorks = append(req.ImageWorks, temp) req.ImageWorks = append(req.ImageWorks, temp)
continue continue
} }
// 判断图片数量是否超过4
if len(temp.Images) > 4 {
temp.Remark = "Bluesky 图片数量不能超过4"
req.ImageWorks = append(req.ImageWorks, temp)
continue
}
req.ImageWorks = append(req.ImageWorks, temp) req.ImageWorks = append(req.ImageWorks, temp)
} }
if len(req.ImageWorks) == 0 { if len(req.ImageWorks) == 0 {
@ -1518,7 +1601,7 @@ func ImportWorkBatch(ctx *gin.Context) {
for _, v := range resp.ImageWorks { for _, v := range resp.ImageWorks {
if !v.Success { if !v.Success {
rowNum := int(v.LineNo) + 1 rowNum := int(v.LineNo) + 1
excelData.SetCellValue("Sheet1", fmt.Sprintf("H%d", rowNum), v.Remark) excelData.SetCellValue("Sheet1", fmt.Sprintf("J%d", rowNum), v.Remark)
hasValueRows[rowNum] = true hasValueRows[rowNum] = true
} }
} }

View File

@ -56,6 +56,7 @@ func ImageCheckByte(file *multipart.FileHeader) (bool, error) {
} }
func SecurityFile(textVal string) (bool, error) { func SecurityFile(textVal string) (bool, error) {
return true, nil
if textVal == "" { if textVal == "" {
return true, nil return true, nil
} }
@ -79,6 +80,7 @@ func SecurityFile(textVal string) (bool, error) {
return true, nil return true, nil
} }
func SecurityText(textVal string) (bool, error) { func SecurityText(textVal string) (bool, error) {
return true, nil
aliConfig, err := pkgSecurity.GetGlobalConfig("./data/alibabacloud.env") aliConfig, err := pkgSecurity.GetGlobalConfig("./data/alibabacloud.env")
if err != nil { if err != nil {
return false, err return false, err

View File

@ -4,13 +4,19 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
account "fonchain-fiee/api/accountFiee"
"fonchain-fiee/api/cron" "fonchain-fiee/api/cron"
"fonchain-fiee/pkg/service" "fonchain-fiee/pkg/service"
"fonchain-fiee/pkg/utils" "fonchain-fiee/pkg/utils"
"log"
"os"
"path/filepath"
"strings"
"time" "time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding" "github.com/gin-gonic/gin/binding"
"github.com/xuri/excelize/v2"
"google.golang.org/protobuf/types/known/emptypb" "google.golang.org/protobuf/types/known/emptypb"
) )
@ -112,6 +118,17 @@ func ExportExcelExecutionResult(c *gin.Context) {
service.Error(c, errors.New("网络超时,请重试")) service.Error(c, errors.New("网络超时,请重试"))
return return
} }
userListRes, err := service.AccountFieeProvider.UserList(context.Background(), &account.UserListRequest{
Domain: "app",
})
if err != nil {
service.Error(c, errors.New("用户查询失败"))
return
}
idFindSubName := make(map[uint64]string)
for _, v := range userListRes.UserList {
idFindSubName[v.Id] = v.SubNum
}
titleList := []string{ titleList := []string{
"任务标题", "艺人编号", "艺人姓名", "内容类型", "内容标题", "执行结果", "原因", "任务标题", "艺人编号", "艺人姓名", "内容类型", "内容标题", "执行结果", "原因",
@ -120,7 +137,7 @@ func ExportExcelExecutionResult(c *gin.Context) {
for _, task := range res.Data { for _, task := range res.Data {
data := []interface{}{ data := []interface{}{
task.TaskTitle, task.TaskTitle,
task.ArtistId, idFindSubName[uint64(task.ArtistId)],
task.ArtistName, task.ArtistName,
task.ContentTypeDescription, task.ContentTypeDescription,
task.WorkTitle, task.WorkTitle,
@ -205,3 +222,160 @@ func GetScheduleTaskStatus(c *gin.Context) {
} }
service.Success(c, res) service.Success(c, res)
} }
func GetImportData(c *gin.Context) {
defer func() {
if r := recover(); r != nil {
service.Error(c, errors.New("操作失败"))
}
}()
// 导入excel
excelFile, err := c.FormFile("excel")
if err != nil {
service.Error(c, errors.New("缺少excel文件"))
return
}
// 创建临时文件
tempDir := "tmp"
if err = os.MkdirAll(tempDir, 0755); err != nil {
service.Error(c, errors.New("创建临时目录失败"))
return
}
defer os.RemoveAll(tempDir)
// 保存excel
excelPath := filepath.Join(tempDir, "excel.xlsx")
if err = c.SaveUploadedFile(excelFile, excelPath); err != nil {
service.Error(c, errors.New("保存excel文件失败"))
return
}
// 读取excel
readExcelResult, err := readExcel(excelPath)
if err != nil {
service.Error(c, fmt.Errorf("读取excel失败: %v", err))
return
}
if len(readExcelResult) == 0 {
service.Error(c, errors.New("请检查excel文件"))
return
}
//去重操作
set := make(map[string]struct{})
var uniqueExcelData []excelData
for _, data := range readExcelResult {
if _, exists := set[data.SubName]; !exists {
set[data.SubName] = struct{}{}
uniqueExcelData = append(uniqueExcelData, data)
}
}
res, err := service.AccountFieeProvider.UserList(context.Background(), &account.UserListRequest{
Domain: "app",
})
if err != nil {
service.Error(c, errors.New("用户查询失败"))
return
}
//检查subname是否正确是否存在
subNames := make(map[string]struct{}, len(res.UserList))
for _, v := range res.UserList {
subNames[v.SubNum] = struct{}{}
}
for _, v := range uniqueExcelData {
if _, ok := subNames[v.SubName]; !ok {
service.Error(c, errors.New(fmt.Sprintf("第 %d 行数据错误,请检查数据!", v.Line)))
return
}
}
//检查subname和name是否匹配
subNameFindExcelData := make(map[string]excelData, len(uniqueExcelData))
for _, v := range uniqueExcelData {
subNameFindExcelData[v.SubName] = v
}
subNameFindID := make(map[string]uint64, len(uniqueExcelData))
result := make([]excelDataResult, 0, len(uniqueExcelData))
for _, v := range res.UserList {
subNameFindID[v.SubNum] = v.Id
if subNameFindExcelData[v.SubNum].Name != v.Name && subNameFindExcelData[v.SubNum].Name != "" {
fmt.Println(subNameFindExcelData[v.SubNum], v.Name)
service.Error(c, errors.New(fmt.Sprintf("第 %d 行数据错误,请检查数据!", subNameFindExcelData[v.SubNum].Line)))
return
}
}
for _, v := range uniqueExcelData {
result = append(result, excelDataResult{
Id: subNameFindID[v.SubName],
Name: v.Name,
})
}
service.Success(c, result)
return
}
type excelData struct {
Line uint `json:"line"`
SubName string `json:"subName"`
Name string `json:"name"`
}
type excelDataResult struct {
Id uint64 `json:"id"`
Name string `json:"name"`
}
func readExcel(excelPath string) ([]excelData, error) {
//打开excel
f, err := excelize.OpenFile(excelPath)
if err != nil {
return nil, err
}
defer f.Close()
//读取第一页
sheetName := f.GetSheetName(0)
if sheetName == "" {
return nil, errors.New("excel文件中没有工作表")
}
//读取数据
rows, err := f.GetRows(sheetName)
if err != nil {
return nil, fmt.Errorf("读取工作表失败: %v", err)
}
if len(rows) <= 1 {
return nil, errors.New("excel文件没有数据行只有表头或为空")
}
var result []excelData
for i := 1; i < len(rows); i++ { // 从第2行开始跳过表头
row := rows[i]
if len(row) == 0 {
continue
}
subName := getCellValue(f, sheetName, i, 0)
name := getCellValue(f, sheetName, i, 1)
data := excelData{
Line: uint(i + 1),
SubName: subName,
Name: name,
}
result = append(result, data)
}
return result, nil
}
func getCellValue(f *excelize.File, sheetName string, rowIndex, colIndex int) string {
colName, _ := excelize.ColumnNumberToName(colIndex + 1)
cell := fmt.Sprintf("%s%d", colName, rowIndex+1)
value, err := f.GetCellValue(sheetName, cell)
if err != nil {
log.Printf("读取单元格 %s 失败: %v", cell, err)
return ""
}
return strings.TrimSpace(value)
}

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"context" "context"
"errors" "errors"
"fmt"
"fonchain-fiee/api/files" "fonchain-fiee/api/files"
"fonchain-fiee/pkg/service" "fonchain-fiee/pkg/service"
"fonchain-fiee/pkg/service/bundle/common" "fonchain-fiee/pkg/service/bundle/common"
@ -102,6 +103,15 @@ func Create(ctx *gin.Context) {
} }
func Delete(ctx *gin.Context) { func Delete(ctx *gin.Context) {
path := ctx.DefaultQuery("path", "/")
nowYear := time.Now().Year()
nowMonth := time.Now().Month()
nowYearPath := fmt.Sprintf("/fiee/video/%d", nowYear)
nowMonthPath := fmt.Sprintf("/fiee/video/%d/%d-%d", nowYear, nowYear, nowMonth)
if path == nowYearPath || path == nowMonthPath || path == "/fiee" || path == "/fiee/video" || path == "/fiee/video/old" {
service.Error(ctx, errors.New("无法删除该目录"))
return
}
resp, err := service.FilesProvider.Delete(ctx, &files.DeleteReq{ resp, err := service.FilesProvider.Delete(ctx, &files.DeleteReq{
Path: ctx.DefaultQuery("path", "/"), Path: ctx.DefaultQuery("path", "/"),
UserSpacePath: getUserSpacePath(ctx), UserSpacePath: getUserSpacePath(ctx),

View File

@ -376,6 +376,11 @@ func UpdateWorkImageWithTaskUUID(ctx *gin.Context) {
service.Error(ctx, errors.New("任务已中止,不能上传图文")) service.Error(ctx, errors.New("任务已中止,不能上传图文"))
return return
} }
resp, err := castService.UpdateWorkImageCore(ctx, req.UpdateWorkImageReq)
if err != nil {
service.Error(ctx, err)
return
}
if config.AppConfig.System.AppMode != "dev" { if config.AppConfig.System.AppMode != "dev" {
artistId, _ := strconv.ParseUint(req.ArtistUuid, 10, 64) artistId, _ := strconv.ParseUint(req.ArtistUuid, 10, 64)
infoResp, err = service.AccountFieeProvider.Info(context.Background(), &accountFiee.InfoRequest{ infoResp, err = service.AccountFieeProvider.Info(context.Background(), &accountFiee.InfoRequest{
@ -393,21 +398,6 @@ func UpdateWorkImageWithTaskUUID(ctx *gin.Context) {
TelAreaCode: "86", TelAreaCode: "86",
} }
} }
req.ArtistName = infoResp.Name
req.ArtistPhone = infoResp.TelNum
req.ArtistPhoneAreaCode = infoResp.TelAreaCode
// artistID, _ := strconv.ParseUint(req.ArtistUuid, 10, 64)
// if _, err = castService.CheckUserBundleBalance(int32(artistID), modelCast.BalanceTypeImageValue); err != nil {
// service.Error(ctx, err)
// return
// }
newCtx := castService.NewCtxWithUserInfo(ctx)
req.Source = 1
resp, err := service.CastProvider.UpdateWorkImage(newCtx, req.UpdateWorkImageReq)
if err != nil {
service.Error(ctx, err)
return
}
// EmployeeName 和 EmployeeNum 从 toekn 里面拿 // EmployeeName 和 EmployeeNum 从 toekn 里面拿
userInfo := login.GetUserInfoFromC(ctx) userInfo := login.GetUserInfoFromC(ctx)
// 调用员工实际任务状态更新 // 调用员工实际任务状态更新
@ -474,6 +464,11 @@ func UpdateWorkVideoWithUUID(ctx *gin.Context) {
service.Error(ctx, errors.New("任务已中止,不能上传视频")) service.Error(ctx, errors.New("任务已中止,不能上传视频"))
return return
} }
resp, err := castService.UpdateWorkVideoCore(ctx, req.UpdateWorkVideoReq)
if err != nil {
service.Error(ctx, err)
return
}
if config.AppConfig.System.AppMode != "dev" { if config.AppConfig.System.AppMode != "dev" {
artistId, _ := strconv.ParseUint(req.ArtistUuid, 10, 64) artistId, _ := strconv.ParseUint(req.ArtistUuid, 10, 64)
infoResp, err = service.AccountFieeProvider.Info(context.Background(), &accountFiee.InfoRequest{ infoResp, err = service.AccountFieeProvider.Info(context.Background(), &accountFiee.InfoRequest{
@ -491,21 +486,6 @@ func UpdateWorkVideoWithUUID(ctx *gin.Context) {
TelAreaCode: "86", TelAreaCode: "86",
} }
} }
// artistID, _ := strconv.ParseUint(req.ArtistUuid, 10, 64)
// if _, err = castService.CheckUserBundleBalance(int32(artistID), modelCast.BalanceTypeVideoValue); err != nil {
// service.Error(ctx, err)
// return
// }
req.ArtistName = infoResp.Name
req.ArtistPhone = infoResp.TelNum
req.ArtistPhoneAreaCode = infoResp.TelAreaCode
newCtx := castService.NewCtxWithUserInfo(ctx)
req.Source = 1
resp, err := service.CastProvider.UpdateWorkVideo(newCtx, req.UpdateWorkVideoReq)
if err != nil {
service.Error(ctx, err)
return
}
// EmployeeName 和 EmployeeNum 从 toekn 里面拿 // EmployeeName 和 EmployeeNum 从 toekn 里面拿
userInfo := login.GetUserInfoFromC(ctx) userInfo := login.GetUserInfoFromC(ctx)
// 调用员工实际任务状态更新 // 调用员工实际任务状态更新