Procházet zdrojové kódy

Merge branch 'task_612_lcd' into debug

lichangdong před 1 dnem
rodič
revize
97e1b7b394

+ 29 - 29
crontask/init.go

@@ -24,35 +24,35 @@ func NewCronTask(ctx context.Context, svcCtx *svc.ServiceContext) *CronTask {
 
 func ScheduleRun(c *cron.Cron, serverCtx *svc.ServiceContext) {
 
-	l := NewCronTask(context.Background(), serverCtx)
-	c.AddFunc("* * * * *", func() {
-		l.sendMsg()
-	})
-
-	sendWx := NewCronTask(context.Background(), serverCtx)
-	c.AddFunc("* * * * *", func() {
-		sendWx.sendWx()
-	})
-
-	sendWxOnTimeout := NewCronTask(context.Background(), serverCtx)
-	c.AddFunc("* * * * *", func() {
-		sendWxOnTimeout.sendWxOnTimeout()
-	})
-
-	computeStatistic := NewCronTask(context.Background(), serverCtx)
-	c.AddFunc("0 * * * *", func() {
-		computeStatistic.computeStatistic()
-	})
-
-	contactForm := NewCronTask(context.Background(), serverCtx)
-	c.AddFunc("10 0 * * *", func() {
-		contactForm.analyze()
-	})
-
-	l = NewCronTask(context.Background(), serverCtx)
-	c.AddFunc("*/30 * * * *", func() {
-		l.wxAddFriend()
-	})
+	//l := NewCronTask(context.Background(), serverCtx)
+	//c.AddFunc("* * * * *", func() {
+	//	l.sendMsg()
+	//})
+	//
+	//sendWx := NewCronTask(context.Background(), serverCtx)
+	//c.AddFunc("* * * * *", func() {
+	//	sendWx.sendWx()
+	//})
+	//
+	//sendWxOnTimeout := NewCronTask(context.Background(), serverCtx)
+	//c.AddFunc("* * * * *", func() {
+	//	sendWxOnTimeout.sendWxOnTimeout()
+	//})
+	//
+	//computeStatistic := NewCronTask(context.Background(), serverCtx)
+	//c.AddFunc("0 * * * *", func() {
+	//	computeStatistic.computeStatistic()
+	//})
+	//
+	//contactForm := NewCronTask(context.Background(), serverCtx)
+	//c.AddFunc("10 0 * * *", func() {
+	//	contactForm.analyze()
+	//})
+	//
+	//l = NewCronTask(context.Background(), serverCtx)
+	//c.AddFunc("*/30 * * * *", func() {
+	//	l.wxAddFriend()
+	//})
 
 	//contactForm := NewCronTask(context.Background(), serverCtx)
 	//c.AddFunc("@every 60m", func() {

+ 21 - 1
desc/wechat/label.api

@@ -10,7 +10,6 @@ type (
         // Label list data | Label列表数据
         Data []LabelSelectListInfo `json:"data"`
     }
-
     // The response data of label list | Label群发列表数据
     LabelBatchSelectListResp {
         BaseDataInfo
@@ -76,6 +75,23 @@ type (
         // value
         Value  *uint64 `json:"value,optional"`
     }
+
+    labelImportReq {
+        Type  *int `json:"type,optional" validate:"required,gt=0"`
+        // Label information | Label数据
+        Content string `json:"content,optional" validate:"required"`
+    }
+
+    LabelImportResp struct {
+        BaseDataInfo
+        Data LabelImportInfo `json:"data"`
+    }
+
+    LabelImportInfo struct {
+        Inserted []string `json:"inserted"` // 插入成功的标签
+        Existed  []string `json:"existed"`  // 已存在的标签
+        Failed   []string `json:"failed"`   // 插入失败的标签(预留)
+    }
 )
 
 @server(
@@ -116,4 +132,8 @@ service Wechat {
     // Get label by ID | 通过ID获取Label
     @handler getLabelById
     post /label (IDReq) returns (LabelInfoResp)
+
+    //label import | 导出Label
+    @handler labelImport
+    post /label/import (labelImportReq) returns (LabelImportResp)
 }

+ 44 - 0
internal/handler/label/label_import_handler.go

@@ -0,0 +1,44 @@
+package label
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/label"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /label/import label LabelImport
+//
+//label import | 导出Label
+//
+//label import | 导出Label
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: labelImportReq
+//
+// Responses:
+//  200: BaseMsgResp
+
+func LabelImportHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.LabelImportReq
+		if err := httpx.Parse(r, &req, true); err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+			return
+		}
+
+		l := label.NewLabelImportLogic(r.Context(), svcCtx)
+		resp, err := l.LabelImport(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 6 - 1
internal/handler/routes.go

@@ -1,5 +1,5 @@
 // Code generated by goctl. DO NOT EDIT.
-// goctls v1.10.1
+// goctls v1.10.4
 
 package handler
 
@@ -536,6 +536,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
 					Path:    "/label",
 					Handler: label.GetLabelByIdHandler(serverCtx),
 				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/label/import",
+					Handler: label.LabelImportHandler(serverCtx),
+				},
 			}...,
 		),
 		rest.WithJwt(serverCtx.Config.Auth.AccessSecret),

+ 127 - 0
internal/logic/label/label_import_logic.go

@@ -0,0 +1,127 @@
+package label
+
+import (
+	"context"
+	"encoding/json"
+	"entgo.io/ent/dialect/sql"
+	"strings"
+	"time"
+	"wechat-api/ent"
+	"wechat-api/ent/label"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type LabelImportLogic struct {
+	logx.Logger
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+}
+
+func NewLabelImportLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LabelImportLogic {
+	return &LabelImportLogic{
+		Logger: logx.WithContext(ctx),
+		ctx:    ctx,
+		svcCtx: svcCtx}
+}
+
+func (l *LabelImportLogic) LabelImport(req *types.LabelImportReq) (resp *types.LabelImportResp, err error) {
+	// todo: add your logic here and delete this line
+	organizationId := l.ctx.Value("organizationId").(uint64)
+	contentString := req.Content
+	contentList := splitContent(contentString)
+	existingLabels, err := l.svcCtx.DB.Label.Query().
+		Where(
+			label.NameIn(contentList...),
+			label.OrganizationID(organizationId),
+		).
+		Select(label.FieldName).
+		All(l.ctx)
+	if err != nil {
+		return nil, err
+	}
+	//var toInsert []string
+	existMap := make(map[string]bool, len(existingLabels))
+	for _, tag := range existingLabels {
+		existMap[tag.Name] = true
+	}
+	labelCreates := make([]*ent.LabelCreate, 0)
+	inserted := make([]string, 0)
+	existed := make([]string, 0)
+	failed := make([]string, 0)
+	insertNames := make([]string, 0) // 新增:用于失败时记录哪些尝试插入的标签
+	for _, tag := range contentList {
+		if existMap[tag] {
+			existed = append(existed, tag)
+			continue
+		}
+		if !existMap[tag] {
+			labelCreates = append(labelCreates, l.svcCtx.DB.Label.Create().
+				SetName(tag).
+				SetType(*req.Type).
+				SetStatus(1).
+				SetOrganizationID(organizationId).
+				SetFrom(1).
+				SetMode(1).
+				SetConditions(`{}`).
+				SetCreatedAt(time.Now()).
+				SetUpdatedAt(time.Now()),
+			)
+		}
+		inserted = append(inserted, tag)
+		insertNames = append(insertNames, tag) // 新增:记录本次尝试插入的标签
+	}
+	if len(labelCreates) > 0 {
+		err := l.svcCtx.DB.Label.CreateBulk(labelCreates...).
+			OnConflict(sql.ConflictColumns(label.FieldName, label.FieldOrganizationID)).
+			DoNothing().
+			Exec(l.ctx)
+		if err != nil {
+			failed = insertNames
+			jsonBad, _ := json.Marshal(insertNames)
+			logx.Errorf("标签批量插入失败:%v,失败数据:%s", err, string(jsonBad))
+			//return nil, err
+		}
+	}
+	return &types.LabelImportResp{
+		BaseDataInfo: types.BaseDataInfo{Code: 0, Msg: "success"},
+		Data: types.LabelImportInfo{
+			Inserted: nonEmptySlice(inserted),
+			Existed:  nonEmptySlice(existed),
+			Failed:   nonEmptySlice(failed),
+		},
+	}, nil
+}
+
+// 去重 & 切分内容:
+func splitContent(content string) []string {
+	// 先统一换行符为 \n
+	content = strings.ReplaceAll(content, "\r\n", "\n")
+	content = strings.ReplaceAll(content, "\r", "\n")
+
+	// 再按 \n 分割
+	lines := strings.Split(content, "\n")
+
+	// 去除每行空格,并过滤空行
+	unique := make(map[string]struct{})
+	for _, line := range lines {
+		tag := strings.TrimSpace(line)
+		if tag != "" {
+			unique[tag] = struct{}{}
+		}
+	}
+	result := make([]string, 0, len(unique))
+	for tag := range unique {
+		result = append(result, tag)
+	}
+	return result
+}
+
+func nonEmptySlice(s []string) []string {
+	if len(s) == 0 {
+		return []string{}
+	}
+	return s
+}

+ 23 - 0
internal/types/types.go

@@ -1272,6 +1272,29 @@ type LabelSelectListInfo struct {
 	Value *uint64 `json:"value,optional"`
 }
 
+// swagger:model labelImportReq
+type LabelImportReq struct {
+	// required : true
+	// min : 0
+	Type *int `json:"type,optional" validate:"required,gt=0"`
+	// Label information | Label数据
+	// required : true
+	Content string `json:"content,optional" validate:"required"`
+}
+
+// swagger:model LabelImportResp
+type LabelImportResp struct {
+	BaseDataInfo
+	Data LabelImportInfo `json:"data"`
+}
+
+// swagger:model LabelImportInfo
+type LabelImportInfo struct {
+	Inserted []string `json:"inserted"` // 插入成功的标签
+	Existed  []string `json:"existed"`  // 已存在的标签
+	Failed   []string `json:"failed"`   // 插入失败的标签(预留)
+}
+
 // The data of label tagging information | LabelTagging信息
 // swagger:model LabelTaggingInfo
 type LabelTaggingInfo struct {