|
@@ -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
|
|
|
+}
|