Browse Source

1. 增加 sop 任务发布接口。2. 更新联系人标签时,触发 sop 任务

boweniac 9 months ago
parent
commit
16931d8e99
42 changed files with 3233 additions and 540 deletions
  1. 3 3
      desc/wechat/label_relationship.api
  2. 3 3
      desc/wechat/message_records.api
  3. 2 2
      desc/wechat/sop_stage.api
  4. 4 0
      desc/wechat/sop_task.api
  5. 96 0
      ent/client.go
  6. 17 1
      ent/contact.go
  7. 30 0
      ent/contact/contact.go
  8. 23 0
      ent/contact/where.go
  9. 32 0
      ent/contact_create.go
  10. 75 1
      ent/contact_query.go
  11. 163 0
      ent/contact_update.go
  12. 73 6
      ent/messagerecords.go
  13. 72 2
      ent/messagerecords/messagerecords.go
  14. 105 65
      ent/messagerecords/where.go
  15. 184 86
      ent/messagerecords_create.go
  16. 240 11
      ent/messagerecords_query.go
  17. 373 88
      ent/messagerecords_update.go
  18. 27 4
      ent/migrate/schema.go
  19. 463 157
      ent/mutation.go
  20. 2 2
      ent/runtime/runtime.go
  21. 1 0
      ent/schema/contact.go
  22. 18 4
      ent/schema/message_records.go
  23. 2 1
      ent/schema/sop_node.go
  24. 2 1
      ent/schema/sop_stage.go
  25. 15 15
      ent/set_not_nil.go
  26. 18 2
      ent/sopnode.go
  27. 30 0
      ent/sopnode/sopnode.go
  28. 23 0
      ent/sopnode/where.go
  29. 37 5
      ent/sopnode_create.go
  30. 87 12
      ent/sopnode_query.go
  31. 173 10
      ent/sopnode_update.go
  32. 18 2
      ent/sopstage.go
  33. 30 0
      ent/sopstage/sopstage.go
  34. 23 0
      ent/sopstage/where.go
  35. 37 5
      ent/sopstage_create.go
  36. 88 14
      ent/sopstage_query.go
  37. 173 10
      ent/sopstage_update.go
  38. 5 0
      internal/handler/routes.go
  39. 44 0
      internal/handler/sop_task/publish_sop_task_handler.go
  40. 164 21
      internal/logic/label_relationship/update_label_relationships_logic.go
  41. 251 0
      internal/logic/sop_task/publish_sop_task_logic.go
  42. 7 7
      internal/types/types.go

+ 3 - 3
desc/wechat/label_relationship.api

@@ -113,8 +113,8 @@ type (
     LabelRelationshipsInfo {
         BaseIDInfo
 
-        // Status 1: normal 2: ban | 状态 1 正常 2 禁用
-        Status  *uint8 `json:"status,optional"`
+        // 更新类型:为空或“all”时表示全量更新,为 “add” 时表示仅追加
+        UpdateType *string `json:"updateType,optional"`
 
         // 标签 ID
         LabelIds  []uint64 `json:"labelIds,optional"`
@@ -168,7 +168,7 @@ service Wechat {
     @handler updateLabelRelationship
     post /label_relationship/update (LabelRelationshipInfo) returns (BaseMsgResp)
 
-    // Update label relationships information | 批量更新LabelRelationship
+    // Update label relationships information | 更新联系人所有 LabelRelationship
     @handler updateLabelRelationships
     post /label_relationship/update_contact_labels (LabelRelationshipsInfo) returns (BaseMsgResp)
 

+ 3 - 3
desc/wechat/message_records.api

@@ -12,7 +12,7 @@ type (
         BotWxid  *string `json:"botWxid,optional"`
 
         // 联系人 id 
-        ContactId  *int `json:"contactId,optional"`
+        ContactId  *uint64 `json:"contactId,optional"`
 
         // 类型:1好友,2群组,3企业微信联系人 
         ContactType  *int `json:"contactType,optional"`
@@ -36,10 +36,10 @@ type (
         SourceType  *int `json:"sourceType,optional"`
 
         // 源 ID 
-        SourceId  *int `json:"sourceId,optional"`
+        SourceId  *uint64 `json:"sourceId,optional"`
 
         // 次源 ID 
-        SubSourceId  *int `json:"subSourceId,optional"`
+        SubSourceId  *uint64 `json:"subSourceId,optional"`
     }
 
     // The response data of message records list | MessageRecords列表数据

+ 2 - 2
desc/wechat/sop_stage.api

@@ -27,7 +27,7 @@ type (
         ActionMessage  []Action `json:"actionMessage,optional"`
 
         // 命中后需要打的标签 
-        ActionLabel  []int `json:"actionLabel,optional"`
+        ActionLabel  []uint64 `json:"actionLabel,optional"`
 
         // 阶段顺序 
         IndexSort  *int `json:"indexSort,optional"`
@@ -94,7 +94,7 @@ type (
         ActionMessage  []Action `json:"actionMessage,optional"`
 
         // 命中后需要打的标签
-        ActionLabel  []int `json:"actionLabel,optional"`
+        ActionLabel  []uint64 `json:"actionLabel,optional"`
 
         // 阶段信息
         StageInfo  *SopStageInfo `json:"stageInfo,optional"`

+ 4 - 0
desc/wechat/sop_task.api

@@ -68,4 +68,8 @@ service Wechat {
     // Get sop task by ID | 通过ID获取SopTask详情
     @handler getSopTaskDetail
     post /sop_task/detail (IDReq) returns (SopTaskInfoResp)
+
+    // Publish sop task | 发布 SopTask
+    @handler publishSopTask
+    post /sop_task/publish (IDReq) returns (BaseMsgResp)
 }

+ 96 - 0
ent/client.go

@@ -406,6 +406,22 @@ func (c *ContactClient) QueryContactRelationships(co *Contact) *LabelRelationshi
 	return query
 }
 
+// QueryContactMessages queries the contact_messages edge of a Contact.
+func (c *ContactClient) QueryContactMessages(co *Contact) *MessageRecordsQuery {
+	query := (&MessageRecordsClient{config: c.config}).Query()
+	query.path = func(context.Context) (fromV *sql.Selector, _ error) {
+		id := co.ID
+		step := sqlgraph.NewStep(
+			sqlgraph.From(contact.Table, contact.FieldID, id),
+			sqlgraph.To(messagerecords.Table, messagerecords.FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, contact.ContactMessagesTable, contact.ContactMessagesColumn),
+		)
+		fromV = sqlgraph.Neighbors(co.driver.Dialect(), step)
+		return fromV, nil
+	}
+	return query
+}
+
 // Hooks returns the client hooks.
 func (c *ContactClient) Hooks() []Hook {
 	hooks := c.hooks.Contact
@@ -992,6 +1008,54 @@ func (c *MessageRecordsClient) GetX(ctx context.Context, id uint64) *MessageReco
 	return obj
 }
 
+// QuerySopStage queries the sop_stage edge of a MessageRecords.
+func (c *MessageRecordsClient) QuerySopStage(mr *MessageRecords) *SopStageQuery {
+	query := (&SopStageClient{config: c.config}).Query()
+	query.path = func(context.Context) (fromV *sql.Selector, _ error) {
+		id := mr.ID
+		step := sqlgraph.NewStep(
+			sqlgraph.From(messagerecords.Table, messagerecords.FieldID, id),
+			sqlgraph.To(sopstage.Table, sopstage.FieldID),
+			sqlgraph.Edge(sqlgraph.M2O, true, messagerecords.SopStageTable, messagerecords.SopStageColumn),
+		)
+		fromV = sqlgraph.Neighbors(mr.driver.Dialect(), step)
+		return fromV, nil
+	}
+	return query
+}
+
+// QuerySopNode queries the sop_node edge of a MessageRecords.
+func (c *MessageRecordsClient) QuerySopNode(mr *MessageRecords) *SopNodeQuery {
+	query := (&SopNodeClient{config: c.config}).Query()
+	query.path = func(context.Context) (fromV *sql.Selector, _ error) {
+		id := mr.ID
+		step := sqlgraph.NewStep(
+			sqlgraph.From(messagerecords.Table, messagerecords.FieldID, id),
+			sqlgraph.To(sopnode.Table, sopnode.FieldID),
+			sqlgraph.Edge(sqlgraph.M2O, true, messagerecords.SopNodeTable, messagerecords.SopNodeColumn),
+		)
+		fromV = sqlgraph.Neighbors(mr.driver.Dialect(), step)
+		return fromV, nil
+	}
+	return query
+}
+
+// QueryMessageContact queries the message_contact edge of a MessageRecords.
+func (c *MessageRecordsClient) QueryMessageContact(mr *MessageRecords) *ContactQuery {
+	query := (&ContactClient{config: c.config}).Query()
+	query.path = func(context.Context) (fromV *sql.Selector, _ error) {
+		id := mr.ID
+		step := sqlgraph.NewStep(
+			sqlgraph.From(messagerecords.Table, messagerecords.FieldID, id),
+			sqlgraph.To(contact.Table, contact.FieldID),
+			sqlgraph.Edge(sqlgraph.M2O, true, messagerecords.MessageContactTable, messagerecords.MessageContactColumn),
+		)
+		fromV = sqlgraph.Neighbors(mr.driver.Dialect(), step)
+		return fromV, nil
+	}
+	return query
+}
+
 // Hooks returns the client hooks.
 func (c *MessageRecordsClient) Hooks() []Hook {
 	hooks := c.hooks.MessageRecords
@@ -1294,6 +1358,22 @@ func (c *SopNodeClient) QuerySopStage(sn *SopNode) *SopStageQuery {
 	return query
 }
 
+// QueryNodeMessages queries the node_messages edge of a SopNode.
+func (c *SopNodeClient) QueryNodeMessages(sn *SopNode) *MessageRecordsQuery {
+	query := (&MessageRecordsClient{config: c.config}).Query()
+	query.path = func(context.Context) (fromV *sql.Selector, _ error) {
+		id := sn.ID
+		step := sqlgraph.NewStep(
+			sqlgraph.From(sopnode.Table, sopnode.FieldID, id),
+			sqlgraph.To(messagerecords.Table, messagerecords.FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, sopnode.NodeMessagesTable, sopnode.NodeMessagesColumn),
+		)
+		fromV = sqlgraph.Neighbors(sn.driver.Dialect(), step)
+		return fromV, nil
+	}
+	return query
+}
+
 // Hooks returns the client hooks.
 func (c *SopNodeClient) Hooks() []Hook {
 	hooks := c.hooks.SopNode
@@ -1461,6 +1541,22 @@ func (c *SopStageClient) QueryStageNodes(ss *SopStage) *SopNodeQuery {
 	return query
 }
 
+// QueryStageMessages queries the stage_messages edge of a SopStage.
+func (c *SopStageClient) QueryStageMessages(ss *SopStage) *MessageRecordsQuery {
+	query := (&MessageRecordsClient{config: c.config}).Query()
+	query.path = func(context.Context) (fromV *sql.Selector, _ error) {
+		id := ss.ID
+		step := sqlgraph.NewStep(
+			sqlgraph.From(sopstage.Table, sopstage.FieldID, id),
+			sqlgraph.To(messagerecords.Table, messagerecords.FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, sopstage.StageMessagesTable, sopstage.StageMessagesColumn),
+		)
+		fromV = sqlgraph.Neighbors(ss.driver.Dialect(), step)
+		return fromV, nil
+	}
+	return query
+}
+
 // Hooks returns the client hooks.
 func (c *SopStageClient) Hooks() []Hook {
 	hooks := c.hooks.SopStage

+ 17 - 1
ent/contact.go

@@ -65,9 +65,11 @@ type Contact struct {
 type ContactEdges struct {
 	// ContactRelationships holds the value of the contact_relationships edge.
 	ContactRelationships []*LabelRelationship `json:"contact_relationships,omitempty"`
+	// ContactMessages holds the value of the contact_messages edge.
+	ContactMessages []*MessageRecords `json:"contact_messages,omitempty"`
 	// loadedTypes holds the information for reporting if a
 	// type was loaded (or requested) in eager-loading or not.
-	loadedTypes [1]bool
+	loadedTypes [2]bool
 }
 
 // ContactRelationshipsOrErr returns the ContactRelationships value or an error if the edge
@@ -79,6 +81,15 @@ func (e ContactEdges) ContactRelationshipsOrErr() ([]*LabelRelationship, error)
 	return nil, &NotLoadedError{edge: "contact_relationships"}
 }
 
+// ContactMessagesOrErr returns the ContactMessages value or an error if the edge
+// was not loaded in eager-loading.
+func (e ContactEdges) ContactMessagesOrErr() ([]*MessageRecords, error) {
+	if e.loadedTypes[1] {
+		return e.ContactMessages, nil
+	}
+	return nil, &NotLoadedError{edge: "contact_messages"}
+}
+
 // scanValues returns the types for scanning values from sql.Rows.
 func (*Contact) scanValues(columns []string) ([]any, error) {
 	values := make([]any, len(columns))
@@ -243,6 +254,11 @@ func (c *Contact) QueryContactRelationships() *LabelRelationshipQuery {
 	return NewContactClient(c.config).QueryContactRelationships(c)
 }
 
+// QueryContactMessages queries the "contact_messages" edge of the Contact entity.
+func (c *Contact) QueryContactMessages() *MessageRecordsQuery {
+	return NewContactClient(c.config).QueryContactMessages(c)
+}
+
 // Update returns a builder for updating this Contact.
 // Note that you need to call Contact.Unwrap() before calling this method if this Contact
 // was returned from a transaction, and the transaction was committed or rolled back.

+ 30 - 0
ent/contact/contact.go

@@ -55,6 +55,8 @@ const (
 	FieldV3 = "v3"
 	// EdgeContactRelationships holds the string denoting the contact_relationships edge name in mutations.
 	EdgeContactRelationships = "contact_relationships"
+	// EdgeContactMessages holds the string denoting the contact_messages edge name in mutations.
+	EdgeContactMessages = "contact_messages"
 	// Table holds the table name of the contact in the database.
 	Table = "contact"
 	// ContactRelationshipsTable is the table that holds the contact_relationships relation/edge.
@@ -64,6 +66,13 @@ const (
 	ContactRelationshipsInverseTable = "label_relationship"
 	// ContactRelationshipsColumn is the table column denoting the contact_relationships relation/edge.
 	ContactRelationshipsColumn = "contact_id"
+	// ContactMessagesTable is the table that holds the contact_messages relation/edge.
+	ContactMessagesTable = "message_records"
+	// ContactMessagesInverseTable is the table name for the MessageRecords entity.
+	// It exists in this package in order to avoid circular dependency with the "messagerecords" package.
+	ContactMessagesInverseTable = "message_records"
+	// ContactMessagesColumn is the table column denoting the contact_messages relation/edge.
+	ContactMessagesColumn = "contact_id"
 )
 
 // Columns holds all SQL columns for contact fields.
@@ -264,6 +273,20 @@ func ByContactRelationships(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOpt
 		sqlgraph.OrderByNeighborTerms(s, newContactRelationshipsStep(), append([]sql.OrderTerm{term}, terms...)...)
 	}
 }
+
+// ByContactMessagesCount orders the results by contact_messages count.
+func ByContactMessagesCount(opts ...sql.OrderTermOption) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborsCount(s, newContactMessagesStep(), opts...)
+	}
+}
+
+// ByContactMessages orders the results by contact_messages terms.
+func ByContactMessages(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborTerms(s, newContactMessagesStep(), append([]sql.OrderTerm{term}, terms...)...)
+	}
+}
 func newContactRelationshipsStep() *sqlgraph.Step {
 	return sqlgraph.NewStep(
 		sqlgraph.From(Table, FieldID),
@@ -271,3 +294,10 @@ func newContactRelationshipsStep() *sqlgraph.Step {
 		sqlgraph.Edge(sqlgraph.O2M, false, ContactRelationshipsTable, ContactRelationshipsColumn),
 	)
 }
+func newContactMessagesStep() *sqlgraph.Step {
+	return sqlgraph.NewStep(
+		sqlgraph.From(Table, FieldID),
+		sqlgraph.To(ContactMessagesInverseTable, FieldID),
+		sqlgraph.Edge(sqlgraph.O2M, false, ContactMessagesTable, ContactMessagesColumn),
+	)
+}

+ 23 - 0
ent/contact/where.go

@@ -1248,6 +1248,29 @@ func HasContactRelationshipsWith(preds ...predicate.LabelRelationship) predicate
 	})
 }
 
+// HasContactMessages applies the HasEdge predicate on the "contact_messages" edge.
+func HasContactMessages() predicate.Contact {
+	return predicate.Contact(func(s *sql.Selector) {
+		step := sqlgraph.NewStep(
+			sqlgraph.From(Table, FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, ContactMessagesTable, ContactMessagesColumn),
+		)
+		sqlgraph.HasNeighbors(s, step)
+	})
+}
+
+// HasContactMessagesWith applies the HasEdge predicate on the "contact_messages" edge with a given conditions (other predicates).
+func HasContactMessagesWith(preds ...predicate.MessageRecords) predicate.Contact {
+	return predicate.Contact(func(s *sql.Selector) {
+		step := newContactMessagesStep()
+		sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
+			for _, p := range preds {
+				p(s)
+			}
+		})
+	})
+}
+
 // And groups predicates with the AND operator between them.
 func And(predicates ...predicate.Contact) predicate.Contact {
 	return predicate.Contact(sql.AndPredicates(predicates...))

+ 32 - 0
ent/contact_create.go

@@ -9,6 +9,7 @@ import (
 	"time"
 	"wechat-api/ent/contact"
 	"wechat-api/ent/labelrelationship"
+	"wechat-api/ent/messagerecords"
 
 	"entgo.io/ent/dialect/sql"
 	"entgo.io/ent/dialect/sql/sqlgraph"
@@ -310,6 +311,21 @@ func (cc *ContactCreate) AddContactRelationships(l ...*LabelRelationship) *Conta
 	return cc.AddContactRelationshipIDs(ids...)
 }
 
+// AddContactMessageIDs adds the "contact_messages" edge to the MessageRecords entity by IDs.
+func (cc *ContactCreate) AddContactMessageIDs(ids ...uint64) *ContactCreate {
+	cc.mutation.AddContactMessageIDs(ids...)
+	return cc
+}
+
+// AddContactMessages adds the "contact_messages" edges to the MessageRecords entity.
+func (cc *ContactCreate) AddContactMessages(m ...*MessageRecords) *ContactCreate {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return cc.AddContactMessageIDs(ids...)
+}
+
 // Mutation returns the ContactMutation object of the builder.
 func (cc *ContactCreate) Mutation() *ContactMutation {
 	return cc.mutation
@@ -600,6 +616,22 @@ func (cc *ContactCreate) createSpec() (*Contact, *sqlgraph.CreateSpec) {
 		}
 		_spec.Edges = append(_spec.Edges, edge)
 	}
+	if nodes := cc.mutation.ContactMessagesIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   contact.ContactMessagesTable,
+			Columns: []string{contact.ContactMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges = append(_spec.Edges, edge)
+	}
 	return _node, _spec
 }
 

+ 75 - 1
ent/contact_query.go

@@ -9,6 +9,7 @@ import (
 	"math"
 	"wechat-api/ent/contact"
 	"wechat-api/ent/labelrelationship"
+	"wechat-api/ent/messagerecords"
 	"wechat-api/ent/predicate"
 
 	"entgo.io/ent/dialect/sql"
@@ -24,6 +25,7 @@ type ContactQuery struct {
 	inters                   []Interceptor
 	predicates               []predicate.Contact
 	withContactRelationships *LabelRelationshipQuery
+	withContactMessages      *MessageRecordsQuery
 	// intermediate query (i.e. traversal path).
 	sql  *sql.Selector
 	path func(context.Context) (*sql.Selector, error)
@@ -82,6 +84,28 @@ func (cq *ContactQuery) QueryContactRelationships() *LabelRelationshipQuery {
 	return query
 }
 
+// QueryContactMessages chains the current query on the "contact_messages" edge.
+func (cq *ContactQuery) QueryContactMessages() *MessageRecordsQuery {
+	query := (&MessageRecordsClient{config: cq.config}).Query()
+	query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
+		if err := cq.prepareQuery(ctx); err != nil {
+			return nil, err
+		}
+		selector := cq.sqlQuery(ctx)
+		if err := selector.Err(); err != nil {
+			return nil, err
+		}
+		step := sqlgraph.NewStep(
+			sqlgraph.From(contact.Table, contact.FieldID, selector),
+			sqlgraph.To(messagerecords.Table, messagerecords.FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, contact.ContactMessagesTable, contact.ContactMessagesColumn),
+		)
+		fromU = sqlgraph.SetNeighbors(cq.driver.Dialect(), step)
+		return fromU, nil
+	}
+	return query
+}
+
 // First returns the first Contact entity from the query.
 // Returns a *NotFoundError when no Contact was found.
 func (cq *ContactQuery) First(ctx context.Context) (*Contact, error) {
@@ -275,6 +299,7 @@ func (cq *ContactQuery) Clone() *ContactQuery {
 		inters:                   append([]Interceptor{}, cq.inters...),
 		predicates:               append([]predicate.Contact{}, cq.predicates...),
 		withContactRelationships: cq.withContactRelationships.Clone(),
+		withContactMessages:      cq.withContactMessages.Clone(),
 		// clone intermediate query.
 		sql:  cq.sql.Clone(),
 		path: cq.path,
@@ -292,6 +317,17 @@ func (cq *ContactQuery) WithContactRelationships(opts ...func(*LabelRelationship
 	return cq
 }
 
+// WithContactMessages tells the query-builder to eager-load the nodes that are connected to
+// the "contact_messages" edge. The optional arguments are used to configure the query builder of the edge.
+func (cq *ContactQuery) WithContactMessages(opts ...func(*MessageRecordsQuery)) *ContactQuery {
+	query := (&MessageRecordsClient{config: cq.config}).Query()
+	for _, opt := range opts {
+		opt(query)
+	}
+	cq.withContactMessages = query
+	return cq
+}
+
 // GroupBy is used to group vertices by one or more fields/columns.
 // It is often used with aggregate functions, like: count, max, mean, min, sum.
 //
@@ -370,8 +406,9 @@ func (cq *ContactQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Cont
 	var (
 		nodes       = []*Contact{}
 		_spec       = cq.querySpec()
-		loadedTypes = [1]bool{
+		loadedTypes = [2]bool{
 			cq.withContactRelationships != nil,
+			cq.withContactMessages != nil,
 		}
 	)
 	_spec.ScanValues = func(columns []string) ([]any, error) {
@@ -401,6 +438,13 @@ func (cq *ContactQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Cont
 			return nil, err
 		}
 	}
+	if query := cq.withContactMessages; query != nil {
+		if err := cq.loadContactMessages(ctx, query, nodes,
+			func(n *Contact) { n.Edges.ContactMessages = []*MessageRecords{} },
+			func(n *Contact, e *MessageRecords) { n.Edges.ContactMessages = append(n.Edges.ContactMessages, e) }); err != nil {
+			return nil, err
+		}
+	}
 	return nodes, nil
 }
 
@@ -434,6 +478,36 @@ func (cq *ContactQuery) loadContactRelationships(ctx context.Context, query *Lab
 	}
 	return nil
 }
+func (cq *ContactQuery) loadContactMessages(ctx context.Context, query *MessageRecordsQuery, nodes []*Contact, init func(*Contact), assign func(*Contact, *MessageRecords)) error {
+	fks := make([]driver.Value, 0, len(nodes))
+	nodeids := make(map[uint64]*Contact)
+	for i := range nodes {
+		fks = append(fks, nodes[i].ID)
+		nodeids[nodes[i].ID] = nodes[i]
+		if init != nil {
+			init(nodes[i])
+		}
+	}
+	if len(query.ctx.Fields) > 0 {
+		query.ctx.AppendFieldOnce(messagerecords.FieldContactID)
+	}
+	query.Where(predicate.MessageRecords(func(s *sql.Selector) {
+		s.Where(sql.InValues(s.C(contact.ContactMessagesColumn), fks...))
+	}))
+	neighbors, err := query.All(ctx)
+	if err != nil {
+		return err
+	}
+	for _, n := range neighbors {
+		fk := n.ContactID
+		node, ok := nodeids[fk]
+		if !ok {
+			return fmt.Errorf(`unexpected referenced foreign-key "contact_id" returned %v for node %v`, fk, n.ID)
+		}
+		assign(node, n)
+	}
+	return nil
+}
 
 func (cq *ContactQuery) sqlCount(ctx context.Context) (int, error) {
 	_spec := cq.querySpec()

+ 163 - 0
ent/contact_update.go

@@ -9,6 +9,7 @@ import (
 	"time"
 	"wechat-api/ent/contact"
 	"wechat-api/ent/labelrelationship"
+	"wechat-api/ent/messagerecords"
 	"wechat-api/ent/predicate"
 
 	"entgo.io/ent/dialect/sql"
@@ -347,6 +348,21 @@ func (cu *ContactUpdate) AddContactRelationships(l ...*LabelRelationship) *Conta
 	return cu.AddContactRelationshipIDs(ids...)
 }
 
+// AddContactMessageIDs adds the "contact_messages" edge to the MessageRecords entity by IDs.
+func (cu *ContactUpdate) AddContactMessageIDs(ids ...uint64) *ContactUpdate {
+	cu.mutation.AddContactMessageIDs(ids...)
+	return cu
+}
+
+// AddContactMessages adds the "contact_messages" edges to the MessageRecords entity.
+func (cu *ContactUpdate) AddContactMessages(m ...*MessageRecords) *ContactUpdate {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return cu.AddContactMessageIDs(ids...)
+}
+
 // Mutation returns the ContactMutation object of the builder.
 func (cu *ContactUpdate) Mutation() *ContactMutation {
 	return cu.mutation
@@ -373,6 +389,27 @@ func (cu *ContactUpdate) RemoveContactRelationships(l ...*LabelRelationship) *Co
 	return cu.RemoveContactRelationshipIDs(ids...)
 }
 
+// ClearContactMessages clears all "contact_messages" edges to the MessageRecords entity.
+func (cu *ContactUpdate) ClearContactMessages() *ContactUpdate {
+	cu.mutation.ClearContactMessages()
+	return cu
+}
+
+// RemoveContactMessageIDs removes the "contact_messages" edge to MessageRecords entities by IDs.
+func (cu *ContactUpdate) RemoveContactMessageIDs(ids ...uint64) *ContactUpdate {
+	cu.mutation.RemoveContactMessageIDs(ids...)
+	return cu
+}
+
+// RemoveContactMessages removes "contact_messages" edges to MessageRecords entities.
+func (cu *ContactUpdate) RemoveContactMessages(m ...*MessageRecords) *ContactUpdate {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return cu.RemoveContactMessageIDs(ids...)
+}
+
 // Save executes the query and returns the number of nodes affected by the update operation.
 func (cu *ContactUpdate) Save(ctx context.Context) (int, error) {
 	if err := cu.defaults(); err != nil {
@@ -550,6 +587,51 @@ func (cu *ContactUpdate) sqlSave(ctx context.Context) (n int, err error) {
 		}
 		_spec.Edges.Add = append(_spec.Edges.Add, edge)
 	}
+	if cu.mutation.ContactMessagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   contact.ContactMessagesTable,
+			Columns: []string{contact.ContactMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := cu.mutation.RemovedContactMessagesIDs(); len(nodes) > 0 && !cu.mutation.ContactMessagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   contact.ContactMessagesTable,
+			Columns: []string{contact.ContactMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := cu.mutation.ContactMessagesIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   contact.ContactMessagesTable,
+			Columns: []string{contact.ContactMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
 	if n, err = sqlgraph.UpdateNodes(ctx, cu.driver, _spec); err != nil {
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{contact.Label}
@@ -888,6 +970,21 @@ func (cuo *ContactUpdateOne) AddContactRelationships(l ...*LabelRelationship) *C
 	return cuo.AddContactRelationshipIDs(ids...)
 }
 
+// AddContactMessageIDs adds the "contact_messages" edge to the MessageRecords entity by IDs.
+func (cuo *ContactUpdateOne) AddContactMessageIDs(ids ...uint64) *ContactUpdateOne {
+	cuo.mutation.AddContactMessageIDs(ids...)
+	return cuo
+}
+
+// AddContactMessages adds the "contact_messages" edges to the MessageRecords entity.
+func (cuo *ContactUpdateOne) AddContactMessages(m ...*MessageRecords) *ContactUpdateOne {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return cuo.AddContactMessageIDs(ids...)
+}
+
 // Mutation returns the ContactMutation object of the builder.
 func (cuo *ContactUpdateOne) Mutation() *ContactMutation {
 	return cuo.mutation
@@ -914,6 +1011,27 @@ func (cuo *ContactUpdateOne) RemoveContactRelationships(l ...*LabelRelationship)
 	return cuo.RemoveContactRelationshipIDs(ids...)
 }
 
+// ClearContactMessages clears all "contact_messages" edges to the MessageRecords entity.
+func (cuo *ContactUpdateOne) ClearContactMessages() *ContactUpdateOne {
+	cuo.mutation.ClearContactMessages()
+	return cuo
+}
+
+// RemoveContactMessageIDs removes the "contact_messages" edge to MessageRecords entities by IDs.
+func (cuo *ContactUpdateOne) RemoveContactMessageIDs(ids ...uint64) *ContactUpdateOne {
+	cuo.mutation.RemoveContactMessageIDs(ids...)
+	return cuo
+}
+
+// RemoveContactMessages removes "contact_messages" edges to MessageRecords entities.
+func (cuo *ContactUpdateOne) RemoveContactMessages(m ...*MessageRecords) *ContactUpdateOne {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return cuo.RemoveContactMessageIDs(ids...)
+}
+
 // Where appends a list predicates to the ContactUpdate builder.
 func (cuo *ContactUpdateOne) Where(ps ...predicate.Contact) *ContactUpdateOne {
 	cuo.mutation.Where(ps...)
@@ -1121,6 +1239,51 @@ func (cuo *ContactUpdateOne) sqlSave(ctx context.Context) (_node *Contact, err e
 		}
 		_spec.Edges.Add = append(_spec.Edges.Add, edge)
 	}
+	if cuo.mutation.ContactMessagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   contact.ContactMessagesTable,
+			Columns: []string{contact.ContactMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := cuo.mutation.RemovedContactMessagesIDs(); len(nodes) > 0 && !cuo.mutation.ContactMessagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   contact.ContactMessagesTable,
+			Columns: []string{contact.ContactMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := cuo.mutation.ContactMessagesIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   contact.ContactMessagesTable,
+			Columns: []string{contact.ContactMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
 	_node = &Contact{config: cuo.config}
 	_spec.Assign = _node.assignValues
 	_spec.ScanValues = _node.scanValues

+ 73 - 6
ent/messagerecords.go

@@ -6,7 +6,10 @@ import (
 	"fmt"
 	"strings"
 	"time"
+	"wechat-api/ent/contact"
 	"wechat-api/ent/messagerecords"
+	"wechat-api/ent/sopnode"
+	"wechat-api/ent/sopstage"
 
 	"entgo.io/ent"
 	"entgo.io/ent/dialect/sql"
@@ -28,7 +31,7 @@ type MessageRecords struct {
 	// 机器人微信 id
 	BotWxid string `json:"bot_wxid,omitempty"`
 	// 联系人 id
-	ContactID int `json:"contact_id,omitempty"`
+	ContactID uint64 `json:"contact_id,omitempty"`
 	// 类型:1好友,2群组,3企业微信联系人
 	ContactType int `json:"contact_type,omitempty"`
 	// 接收方微信 id
@@ -44,12 +47,61 @@ type MessageRecords struct {
 	// 源类型 1 点发 2 群发 3 SOP
 	SourceType int `json:"source_type,omitempty"`
 	// 源 ID
-	SourceID int `json:"source_id,omitempty"`
+	SourceID uint64 `json:"source_id,omitempty"`
 	// 次源 ID
-	SubSourceID  int `json:"sub_source_id,omitempty"`
+	SubSourceID uint64 `json:"sub_source_id,omitempty"`
+	// Edges holds the relations/edges for other nodes in the graph.
+	// The values are being populated by the MessageRecordsQuery when eager-loading is set.
+	Edges        MessageRecordsEdges `json:"edges"`
 	selectValues sql.SelectValues
 }
 
+// MessageRecordsEdges holds the relations/edges for other nodes in the graph.
+type MessageRecordsEdges struct {
+	// SopStage holds the value of the sop_stage edge.
+	SopStage *SopStage `json:"sop_stage,omitempty"`
+	// SopNode holds the value of the sop_node edge.
+	SopNode *SopNode `json:"sop_node,omitempty"`
+	// MessageContact holds the value of the message_contact edge.
+	MessageContact *Contact `json:"message_contact,omitempty"`
+	// loadedTypes holds the information for reporting if a
+	// type was loaded (or requested) in eager-loading or not.
+	loadedTypes [3]bool
+}
+
+// SopStageOrErr returns the SopStage value or an error if the edge
+// was not loaded in eager-loading, or loaded but was not found.
+func (e MessageRecordsEdges) SopStageOrErr() (*SopStage, error) {
+	if e.SopStage != nil {
+		return e.SopStage, nil
+	} else if e.loadedTypes[0] {
+		return nil, &NotFoundError{label: sopstage.Label}
+	}
+	return nil, &NotLoadedError{edge: "sop_stage"}
+}
+
+// SopNodeOrErr returns the SopNode value or an error if the edge
+// was not loaded in eager-loading, or loaded but was not found.
+func (e MessageRecordsEdges) SopNodeOrErr() (*SopNode, error) {
+	if e.SopNode != nil {
+		return e.SopNode, nil
+	} else if e.loadedTypes[1] {
+		return nil, &NotFoundError{label: sopnode.Label}
+	}
+	return nil, &NotLoadedError{edge: "sop_node"}
+}
+
+// MessageContactOrErr returns the MessageContact value or an error if the edge
+// was not loaded in eager-loading, or loaded but was not found.
+func (e MessageRecordsEdges) MessageContactOrErr() (*Contact, error) {
+	if e.MessageContact != nil {
+		return e.MessageContact, nil
+	} else if e.loadedTypes[2] {
+		return nil, &NotFoundError{label: contact.Label}
+	}
+	return nil, &NotLoadedError{edge: "message_contact"}
+}
+
 // scanValues returns the types for scanning values from sql.Rows.
 func (*MessageRecords) scanValues(columns []string) ([]any, error) {
 	values := make([]any, len(columns))
@@ -116,7 +168,7 @@ func (mr *MessageRecords) assignValues(columns []string, values []any) error {
 			if value, ok := values[i].(*sql.NullInt64); !ok {
 				return fmt.Errorf("unexpected type %T for field contact_id", values[i])
 			} else if value.Valid {
-				mr.ContactID = int(value.Int64)
+				mr.ContactID = uint64(value.Int64)
 			}
 		case messagerecords.FieldContactType:
 			if value, ok := values[i].(*sql.NullInt64); !ok {
@@ -164,13 +216,13 @@ func (mr *MessageRecords) assignValues(columns []string, values []any) error {
 			if value, ok := values[i].(*sql.NullInt64); !ok {
 				return fmt.Errorf("unexpected type %T for field source_id", values[i])
 			} else if value.Valid {
-				mr.SourceID = int(value.Int64)
+				mr.SourceID = uint64(value.Int64)
 			}
 		case messagerecords.FieldSubSourceID:
 			if value, ok := values[i].(*sql.NullInt64); !ok {
 				return fmt.Errorf("unexpected type %T for field sub_source_id", values[i])
 			} else if value.Valid {
-				mr.SubSourceID = int(value.Int64)
+				mr.SubSourceID = uint64(value.Int64)
 			}
 		default:
 			mr.selectValues.Set(columns[i], values[i])
@@ -185,6 +237,21 @@ func (mr *MessageRecords) Value(name string) (ent.Value, error) {
 	return mr.selectValues.Get(name)
 }
 
+// QuerySopStage queries the "sop_stage" edge of the MessageRecords entity.
+func (mr *MessageRecords) QuerySopStage() *SopStageQuery {
+	return NewMessageRecordsClient(mr.config).QuerySopStage(mr)
+}
+
+// QuerySopNode queries the "sop_node" edge of the MessageRecords entity.
+func (mr *MessageRecords) QuerySopNode() *SopNodeQuery {
+	return NewMessageRecordsClient(mr.config).QuerySopNode(mr)
+}
+
+// QueryMessageContact queries the "message_contact" edge of the MessageRecords entity.
+func (mr *MessageRecords) QueryMessageContact() *ContactQuery {
+	return NewMessageRecordsClient(mr.config).QueryMessageContact(mr)
+}
+
 // Update returns a builder for updating this MessageRecords.
 // Note that you need to call MessageRecords.Unwrap() before calling this method if this MessageRecords
 // was returned from a transaction, and the transaction was committed or rolled back.

+ 72 - 2
ent/messagerecords/messagerecords.go

@@ -7,6 +7,7 @@ import (
 
 	"entgo.io/ent"
 	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
 )
 
 const (
@@ -44,8 +45,35 @@ const (
 	FieldSourceID = "source_id"
 	// FieldSubSourceID holds the string denoting the sub_source_id field in the database.
 	FieldSubSourceID = "sub_source_id"
+	// EdgeSopStage holds the string denoting the sop_stage edge name in mutations.
+	EdgeSopStage = "sop_stage"
+	// EdgeSopNode holds the string denoting the sop_node edge name in mutations.
+	EdgeSopNode = "sop_node"
+	// EdgeMessageContact holds the string denoting the message_contact edge name in mutations.
+	EdgeMessageContact = "message_contact"
 	// Table holds the table name of the messagerecords in the database.
 	Table = "message_records"
+	// SopStageTable is the table that holds the sop_stage relation/edge.
+	SopStageTable = "message_records"
+	// SopStageInverseTable is the table name for the SopStage entity.
+	// It exists in this package in order to avoid circular dependency with the "sopstage" package.
+	SopStageInverseTable = "sop_stage"
+	// SopStageColumn is the table column denoting the sop_stage relation/edge.
+	SopStageColumn = "source_id"
+	// SopNodeTable is the table that holds the sop_node relation/edge.
+	SopNodeTable = "message_records"
+	// SopNodeInverseTable is the table name for the SopNode entity.
+	// It exists in this package in order to avoid circular dependency with the "sopnode" package.
+	SopNodeInverseTable = "sop_node"
+	// SopNodeColumn is the table column denoting the sop_node relation/edge.
+	SopNodeColumn = "sub_source_id"
+	// MessageContactTable is the table that holds the message_contact relation/edge.
+	MessageContactTable = "message_records"
+	// MessageContactInverseTable is the table name for the Contact entity.
+	// It exists in this package in order to avoid circular dependency with the "contact" package.
+	MessageContactInverseTable = "contact"
+	// MessageContactColumn is the table column denoting the message_contact relation/edge.
+	MessageContactColumn = "contact_id"
 )
 
 // Columns holds all SQL columns for messagerecords fields.
@@ -107,9 +135,9 @@ var (
 	// DefaultSourceType holds the default value on creation for the "source_type" field.
 	DefaultSourceType int
 	// DefaultSourceID holds the default value on creation for the "source_id" field.
-	DefaultSourceID int
+	DefaultSourceID uint64
 	// DefaultSubSourceID holds the default value on creation for the "sub_source_id" field.
-	DefaultSubSourceID int
+	DefaultSubSourceID uint64
 )
 
 // OrderOption defines the ordering options for the MessageRecords queries.
@@ -194,3 +222,45 @@ func BySourceID(opts ...sql.OrderTermOption) OrderOption {
 func BySubSourceID(opts ...sql.OrderTermOption) OrderOption {
 	return sql.OrderByField(FieldSubSourceID, opts...).ToFunc()
 }
+
+// BySopStageField orders the results by sop_stage field.
+func BySopStageField(field string, opts ...sql.OrderTermOption) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborTerms(s, newSopStageStep(), sql.OrderByField(field, opts...))
+	}
+}
+
+// BySopNodeField orders the results by sop_node field.
+func BySopNodeField(field string, opts ...sql.OrderTermOption) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborTerms(s, newSopNodeStep(), sql.OrderByField(field, opts...))
+	}
+}
+
+// ByMessageContactField orders the results by message_contact field.
+func ByMessageContactField(field string, opts ...sql.OrderTermOption) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborTerms(s, newMessageContactStep(), sql.OrderByField(field, opts...))
+	}
+}
+func newSopStageStep() *sqlgraph.Step {
+	return sqlgraph.NewStep(
+		sqlgraph.From(Table, FieldID),
+		sqlgraph.To(SopStageInverseTable, FieldID),
+		sqlgraph.Edge(sqlgraph.M2O, true, SopStageTable, SopStageColumn),
+	)
+}
+func newSopNodeStep() *sqlgraph.Step {
+	return sqlgraph.NewStep(
+		sqlgraph.From(Table, FieldID),
+		sqlgraph.To(SopNodeInverseTable, FieldID),
+		sqlgraph.Edge(sqlgraph.M2O, true, SopNodeTable, SopNodeColumn),
+	)
+}
+func newMessageContactStep() *sqlgraph.Step {
+	return sqlgraph.NewStep(
+		sqlgraph.From(Table, FieldID),
+		sqlgraph.To(MessageContactInverseTable, FieldID),
+		sqlgraph.Edge(sqlgraph.M2O, true, MessageContactTable, MessageContactColumn),
+	)
+}

+ 105 - 65
ent/messagerecords/where.go

@@ -7,6 +7,7 @@ import (
 	"wechat-api/ent/predicate"
 
 	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
 )
 
 // ID filters vertices based on their ID field.
@@ -80,7 +81,7 @@ func BotWxid(v string) predicate.MessageRecords {
 }
 
 // ContactID applies equality check predicate on the "contact_id" field. It's identical to ContactIDEQ.
-func ContactID(v int) predicate.MessageRecords {
+func ContactID(v uint64) predicate.MessageRecords {
 	return predicate.MessageRecords(sql.FieldEQ(FieldContactID, v))
 }
 
@@ -120,12 +121,12 @@ func SourceType(v int) predicate.MessageRecords {
 }
 
 // SourceID applies equality check predicate on the "source_id" field. It's identical to SourceIDEQ.
-func SourceID(v int) predicate.MessageRecords {
+func SourceID(v uint64) predicate.MessageRecords {
 	return predicate.MessageRecords(sql.FieldEQ(FieldSourceID, v))
 }
 
 // SubSourceID applies equality check predicate on the "sub_source_id" field. It's identical to SubSourceIDEQ.
-func SubSourceID(v int) predicate.MessageRecords {
+func SubSourceID(v uint64) predicate.MessageRecords {
 	return predicate.MessageRecords(sql.FieldEQ(FieldSubSourceID, v))
 }
 
@@ -375,43 +376,33 @@ func BotWxidContainsFold(v string) predicate.MessageRecords {
 }
 
 // ContactIDEQ applies the EQ predicate on the "contact_id" field.
-func ContactIDEQ(v int) predicate.MessageRecords {
+func ContactIDEQ(v uint64) predicate.MessageRecords {
 	return predicate.MessageRecords(sql.FieldEQ(FieldContactID, v))
 }
 
 // ContactIDNEQ applies the NEQ predicate on the "contact_id" field.
-func ContactIDNEQ(v int) predicate.MessageRecords {
+func ContactIDNEQ(v uint64) predicate.MessageRecords {
 	return predicate.MessageRecords(sql.FieldNEQ(FieldContactID, v))
 }
 
 // ContactIDIn applies the In predicate on the "contact_id" field.
-func ContactIDIn(vs ...int) predicate.MessageRecords {
+func ContactIDIn(vs ...uint64) predicate.MessageRecords {
 	return predicate.MessageRecords(sql.FieldIn(FieldContactID, vs...))
 }
 
 // ContactIDNotIn applies the NotIn predicate on the "contact_id" field.
-func ContactIDNotIn(vs ...int) predicate.MessageRecords {
+func ContactIDNotIn(vs ...uint64) predicate.MessageRecords {
 	return predicate.MessageRecords(sql.FieldNotIn(FieldContactID, vs...))
 }
 
-// ContactIDGT applies the GT predicate on the "contact_id" field.
-func ContactIDGT(v int) predicate.MessageRecords {
-	return predicate.MessageRecords(sql.FieldGT(FieldContactID, v))
+// ContactIDIsNil applies the IsNil predicate on the "contact_id" field.
+func ContactIDIsNil() predicate.MessageRecords {
+	return predicate.MessageRecords(sql.FieldIsNull(FieldContactID))
 }
 
-// ContactIDGTE applies the GTE predicate on the "contact_id" field.
-func ContactIDGTE(v int) predicate.MessageRecords {
-	return predicate.MessageRecords(sql.FieldGTE(FieldContactID, v))
-}
-
-// ContactIDLT applies the LT predicate on the "contact_id" field.
-func ContactIDLT(v int) predicate.MessageRecords {
-	return predicate.MessageRecords(sql.FieldLT(FieldContactID, v))
-}
-
-// ContactIDLTE applies the LTE predicate on the "contact_id" field.
-func ContactIDLTE(v int) predicate.MessageRecords {
-	return predicate.MessageRecords(sql.FieldLTE(FieldContactID, v))
+// ContactIDNotNil applies the NotNil predicate on the "contact_id" field.
+func ContactIDNotNil() predicate.MessageRecords {
+	return predicate.MessageRecords(sql.FieldNotNull(FieldContactID))
 }
 
 // ContactTypeEQ applies the EQ predicate on the "contact_type" field.
@@ -780,83 +771,132 @@ func SourceTypeLTE(v int) predicate.MessageRecords {
 }
 
 // SourceIDEQ applies the EQ predicate on the "source_id" field.
-func SourceIDEQ(v int) predicate.MessageRecords {
+func SourceIDEQ(v uint64) predicate.MessageRecords {
 	return predicate.MessageRecords(sql.FieldEQ(FieldSourceID, v))
 }
 
 // SourceIDNEQ applies the NEQ predicate on the "source_id" field.
-func SourceIDNEQ(v int) predicate.MessageRecords {
+func SourceIDNEQ(v uint64) predicate.MessageRecords {
 	return predicate.MessageRecords(sql.FieldNEQ(FieldSourceID, v))
 }
 
 // SourceIDIn applies the In predicate on the "source_id" field.
-func SourceIDIn(vs ...int) predicate.MessageRecords {
+func SourceIDIn(vs ...uint64) predicate.MessageRecords {
 	return predicate.MessageRecords(sql.FieldIn(FieldSourceID, vs...))
 }
 
 // SourceIDNotIn applies the NotIn predicate on the "source_id" field.
-func SourceIDNotIn(vs ...int) predicate.MessageRecords {
+func SourceIDNotIn(vs ...uint64) predicate.MessageRecords {
 	return predicate.MessageRecords(sql.FieldNotIn(FieldSourceID, vs...))
 }
 
-// SourceIDGT applies the GT predicate on the "source_id" field.
-func SourceIDGT(v int) predicate.MessageRecords {
-	return predicate.MessageRecords(sql.FieldGT(FieldSourceID, v))
-}
-
-// SourceIDGTE applies the GTE predicate on the "source_id" field.
-func SourceIDGTE(v int) predicate.MessageRecords {
-	return predicate.MessageRecords(sql.FieldGTE(FieldSourceID, v))
-}
-
-// SourceIDLT applies the LT predicate on the "source_id" field.
-func SourceIDLT(v int) predicate.MessageRecords {
-	return predicate.MessageRecords(sql.FieldLT(FieldSourceID, v))
+// SourceIDIsNil applies the IsNil predicate on the "source_id" field.
+func SourceIDIsNil() predicate.MessageRecords {
+	return predicate.MessageRecords(sql.FieldIsNull(FieldSourceID))
 }
 
-// SourceIDLTE applies the LTE predicate on the "source_id" field.
-func SourceIDLTE(v int) predicate.MessageRecords {
-	return predicate.MessageRecords(sql.FieldLTE(FieldSourceID, v))
+// SourceIDNotNil applies the NotNil predicate on the "source_id" field.
+func SourceIDNotNil() predicate.MessageRecords {
+	return predicate.MessageRecords(sql.FieldNotNull(FieldSourceID))
 }
 
 // SubSourceIDEQ applies the EQ predicate on the "sub_source_id" field.
-func SubSourceIDEQ(v int) predicate.MessageRecords {
+func SubSourceIDEQ(v uint64) predicate.MessageRecords {
 	return predicate.MessageRecords(sql.FieldEQ(FieldSubSourceID, v))
 }
 
 // SubSourceIDNEQ applies the NEQ predicate on the "sub_source_id" field.
-func SubSourceIDNEQ(v int) predicate.MessageRecords {
+func SubSourceIDNEQ(v uint64) predicate.MessageRecords {
 	return predicate.MessageRecords(sql.FieldNEQ(FieldSubSourceID, v))
 }
 
 // SubSourceIDIn applies the In predicate on the "sub_source_id" field.
-func SubSourceIDIn(vs ...int) predicate.MessageRecords {
+func SubSourceIDIn(vs ...uint64) predicate.MessageRecords {
 	return predicate.MessageRecords(sql.FieldIn(FieldSubSourceID, vs...))
 }
 
 // SubSourceIDNotIn applies the NotIn predicate on the "sub_source_id" field.
-func SubSourceIDNotIn(vs ...int) predicate.MessageRecords {
+func SubSourceIDNotIn(vs ...uint64) predicate.MessageRecords {
 	return predicate.MessageRecords(sql.FieldNotIn(FieldSubSourceID, vs...))
 }
 
-// SubSourceIDGT applies the GT predicate on the "sub_source_id" field.
-func SubSourceIDGT(v int) predicate.MessageRecords {
-	return predicate.MessageRecords(sql.FieldGT(FieldSubSourceID, v))
-}
-
-// SubSourceIDGTE applies the GTE predicate on the "sub_source_id" field.
-func SubSourceIDGTE(v int) predicate.MessageRecords {
-	return predicate.MessageRecords(sql.FieldGTE(FieldSubSourceID, v))
-}
-
-// SubSourceIDLT applies the LT predicate on the "sub_source_id" field.
-func SubSourceIDLT(v int) predicate.MessageRecords {
-	return predicate.MessageRecords(sql.FieldLT(FieldSubSourceID, v))
-}
-
-// SubSourceIDLTE applies the LTE predicate on the "sub_source_id" field.
-func SubSourceIDLTE(v int) predicate.MessageRecords {
-	return predicate.MessageRecords(sql.FieldLTE(FieldSubSourceID, v))
+// SubSourceIDIsNil applies the IsNil predicate on the "sub_source_id" field.
+func SubSourceIDIsNil() predicate.MessageRecords {
+	return predicate.MessageRecords(sql.FieldIsNull(FieldSubSourceID))
+}
+
+// SubSourceIDNotNil applies the NotNil predicate on the "sub_source_id" field.
+func SubSourceIDNotNil() predicate.MessageRecords {
+	return predicate.MessageRecords(sql.FieldNotNull(FieldSubSourceID))
+}
+
+// HasSopStage applies the HasEdge predicate on the "sop_stage" edge.
+func HasSopStage() predicate.MessageRecords {
+	return predicate.MessageRecords(func(s *sql.Selector) {
+		step := sqlgraph.NewStep(
+			sqlgraph.From(Table, FieldID),
+			sqlgraph.Edge(sqlgraph.M2O, true, SopStageTable, SopStageColumn),
+		)
+		sqlgraph.HasNeighbors(s, step)
+	})
+}
+
+// HasSopStageWith applies the HasEdge predicate on the "sop_stage" edge with a given conditions (other predicates).
+func HasSopStageWith(preds ...predicate.SopStage) predicate.MessageRecords {
+	return predicate.MessageRecords(func(s *sql.Selector) {
+		step := newSopStageStep()
+		sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
+			for _, p := range preds {
+				p(s)
+			}
+		})
+	})
+}
+
+// HasSopNode applies the HasEdge predicate on the "sop_node" edge.
+func HasSopNode() predicate.MessageRecords {
+	return predicate.MessageRecords(func(s *sql.Selector) {
+		step := sqlgraph.NewStep(
+			sqlgraph.From(Table, FieldID),
+			sqlgraph.Edge(sqlgraph.M2O, true, SopNodeTable, SopNodeColumn),
+		)
+		sqlgraph.HasNeighbors(s, step)
+	})
+}
+
+// HasSopNodeWith applies the HasEdge predicate on the "sop_node" edge with a given conditions (other predicates).
+func HasSopNodeWith(preds ...predicate.SopNode) predicate.MessageRecords {
+	return predicate.MessageRecords(func(s *sql.Selector) {
+		step := newSopNodeStep()
+		sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
+			for _, p := range preds {
+				p(s)
+			}
+		})
+	})
+}
+
+// HasMessageContact applies the HasEdge predicate on the "message_contact" edge.
+func HasMessageContact() predicate.MessageRecords {
+	return predicate.MessageRecords(func(s *sql.Selector) {
+		step := sqlgraph.NewStep(
+			sqlgraph.From(Table, FieldID),
+			sqlgraph.Edge(sqlgraph.M2O, true, MessageContactTable, MessageContactColumn),
+		)
+		sqlgraph.HasNeighbors(s, step)
+	})
+}
+
+// HasMessageContactWith applies the HasEdge predicate on the "message_contact" edge with a given conditions (other predicates).
+func HasMessageContactWith(preds ...predicate.Contact) predicate.MessageRecords {
+	return predicate.MessageRecords(func(s *sql.Selector) {
+		step := newMessageContactStep()
+		sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
+			for _, p := range preds {
+				p(s)
+			}
+		})
+	})
 }
 
 // And groups predicates with the AND operator between them.

+ 184 - 86
ent/messagerecords_create.go

@@ -7,7 +7,10 @@ import (
 	"errors"
 	"fmt"
 	"time"
+	"wechat-api/ent/contact"
 	"wechat-api/ent/messagerecords"
+	"wechat-api/ent/sopnode"
+	"wechat-api/ent/sopstage"
 
 	"entgo.io/ent/dialect/sql"
 	"entgo.io/ent/dialect/sql/sqlgraph"
@@ -85,8 +88,16 @@ func (mrc *MessageRecordsCreate) SetBotWxid(s string) *MessageRecordsCreate {
 }
 
 // SetContactID sets the "contact_id" field.
-func (mrc *MessageRecordsCreate) SetContactID(i int) *MessageRecordsCreate {
-	mrc.mutation.SetContactID(i)
+func (mrc *MessageRecordsCreate) SetContactID(u uint64) *MessageRecordsCreate {
+	mrc.mutation.SetContactID(u)
+	return mrc
+}
+
+// SetNillableContactID sets the "contact_id" field if the given value is not nil.
+func (mrc *MessageRecordsCreate) SetNillableContactID(u *uint64) *MessageRecordsCreate {
+	if u != nil {
+		mrc.SetContactID(*u)
+	}
 	return mrc
 }
 
@@ -189,29 +200,29 @@ func (mrc *MessageRecordsCreate) SetNillableSourceType(i *int) *MessageRecordsCr
 }
 
 // SetSourceID sets the "source_id" field.
-func (mrc *MessageRecordsCreate) SetSourceID(i int) *MessageRecordsCreate {
-	mrc.mutation.SetSourceID(i)
+func (mrc *MessageRecordsCreate) SetSourceID(u uint64) *MessageRecordsCreate {
+	mrc.mutation.SetSourceID(u)
 	return mrc
 }
 
 // SetNillableSourceID sets the "source_id" field if the given value is not nil.
-func (mrc *MessageRecordsCreate) SetNillableSourceID(i *int) *MessageRecordsCreate {
-	if i != nil {
-		mrc.SetSourceID(*i)
+func (mrc *MessageRecordsCreate) SetNillableSourceID(u *uint64) *MessageRecordsCreate {
+	if u != nil {
+		mrc.SetSourceID(*u)
 	}
 	return mrc
 }
 
 // SetSubSourceID sets the "sub_source_id" field.
-func (mrc *MessageRecordsCreate) SetSubSourceID(i int) *MessageRecordsCreate {
-	mrc.mutation.SetSubSourceID(i)
+func (mrc *MessageRecordsCreate) SetSubSourceID(u uint64) *MessageRecordsCreate {
+	mrc.mutation.SetSubSourceID(u)
 	return mrc
 }
 
 // SetNillableSubSourceID sets the "sub_source_id" field if the given value is not nil.
-func (mrc *MessageRecordsCreate) SetNillableSubSourceID(i *int) *MessageRecordsCreate {
-	if i != nil {
-		mrc.SetSubSourceID(*i)
+func (mrc *MessageRecordsCreate) SetNillableSubSourceID(u *uint64) *MessageRecordsCreate {
+	if u != nil {
+		mrc.SetSubSourceID(*u)
 	}
 	return mrc
 }
@@ -222,6 +233,63 @@ func (mrc *MessageRecordsCreate) SetID(u uint64) *MessageRecordsCreate {
 	return mrc
 }
 
+// SetSopStageID sets the "sop_stage" edge to the SopStage entity by ID.
+func (mrc *MessageRecordsCreate) SetSopStageID(id uint64) *MessageRecordsCreate {
+	mrc.mutation.SetSopStageID(id)
+	return mrc
+}
+
+// SetNillableSopStageID sets the "sop_stage" edge to the SopStage entity by ID if the given value is not nil.
+func (mrc *MessageRecordsCreate) SetNillableSopStageID(id *uint64) *MessageRecordsCreate {
+	if id != nil {
+		mrc = mrc.SetSopStageID(*id)
+	}
+	return mrc
+}
+
+// SetSopStage sets the "sop_stage" edge to the SopStage entity.
+func (mrc *MessageRecordsCreate) SetSopStage(s *SopStage) *MessageRecordsCreate {
+	return mrc.SetSopStageID(s.ID)
+}
+
+// SetSopNodeID sets the "sop_node" edge to the SopNode entity by ID.
+func (mrc *MessageRecordsCreate) SetSopNodeID(id uint64) *MessageRecordsCreate {
+	mrc.mutation.SetSopNodeID(id)
+	return mrc
+}
+
+// SetNillableSopNodeID sets the "sop_node" edge to the SopNode entity by ID if the given value is not nil.
+func (mrc *MessageRecordsCreate) SetNillableSopNodeID(id *uint64) *MessageRecordsCreate {
+	if id != nil {
+		mrc = mrc.SetSopNodeID(*id)
+	}
+	return mrc
+}
+
+// SetSopNode sets the "sop_node" edge to the SopNode entity.
+func (mrc *MessageRecordsCreate) SetSopNode(s *SopNode) *MessageRecordsCreate {
+	return mrc.SetSopNodeID(s.ID)
+}
+
+// SetMessageContactID sets the "message_contact" edge to the Contact entity by ID.
+func (mrc *MessageRecordsCreate) SetMessageContactID(id uint64) *MessageRecordsCreate {
+	mrc.mutation.SetMessageContactID(id)
+	return mrc
+}
+
+// SetNillableMessageContactID sets the "message_contact" edge to the Contact entity by ID if the given value is not nil.
+func (mrc *MessageRecordsCreate) SetNillableMessageContactID(id *uint64) *MessageRecordsCreate {
+	if id != nil {
+		mrc = mrc.SetMessageContactID(*id)
+	}
+	return mrc
+}
+
+// SetMessageContact sets the "message_contact" edge to the Contact entity.
+func (mrc *MessageRecordsCreate) SetMessageContact(c *Contact) *MessageRecordsCreate {
+	return mrc.SetMessageContactID(c.ID)
+}
+
 // Mutation returns the MessageRecordsMutation object of the builder.
 func (mrc *MessageRecordsCreate) Mutation() *MessageRecordsMutation {
 	return mrc.mutation
@@ -323,9 +391,6 @@ func (mrc *MessageRecordsCreate) check() error {
 	if _, ok := mrc.mutation.BotWxid(); !ok {
 		return &ValidationError{Name: "bot_wxid", err: errors.New(`ent: missing required field "MessageRecords.bot_wxid"`)}
 	}
-	if _, ok := mrc.mutation.ContactID(); !ok {
-		return &ValidationError{Name: "contact_id", err: errors.New(`ent: missing required field "MessageRecords.contact_id"`)}
-	}
 	if _, ok := mrc.mutation.ContactType(); !ok {
 		return &ValidationError{Name: "contact_type", err: errors.New(`ent: missing required field "MessageRecords.contact_type"`)}
 	}
@@ -344,12 +409,6 @@ func (mrc *MessageRecordsCreate) check() error {
 	if _, ok := mrc.mutation.SourceType(); !ok {
 		return &ValidationError{Name: "source_type", err: errors.New(`ent: missing required field "MessageRecords.source_type"`)}
 	}
-	if _, ok := mrc.mutation.SourceID(); !ok {
-		return &ValidationError{Name: "source_id", err: errors.New(`ent: missing required field "MessageRecords.source_id"`)}
-	}
-	if _, ok := mrc.mutation.SubSourceID(); !ok {
-		return &ValidationError{Name: "sub_source_id", err: errors.New(`ent: missing required field "MessageRecords.sub_source_id"`)}
-	}
 	return nil
 }
 
@@ -403,10 +462,6 @@ func (mrc *MessageRecordsCreate) createSpec() (*MessageRecords, *sqlgraph.Create
 		_spec.SetField(messagerecords.FieldBotWxid, field.TypeString, value)
 		_node.BotWxid = value
 	}
-	if value, ok := mrc.mutation.ContactID(); ok {
-		_spec.SetField(messagerecords.FieldContactID, field.TypeInt, value)
-		_node.ContactID = value
-	}
 	if value, ok := mrc.mutation.ContactType(); ok {
 		_spec.SetField(messagerecords.FieldContactType, field.TypeInt, value)
 		_node.ContactType = value
@@ -435,13 +490,56 @@ func (mrc *MessageRecordsCreate) createSpec() (*MessageRecords, *sqlgraph.Create
 		_spec.SetField(messagerecords.FieldSourceType, field.TypeInt, value)
 		_node.SourceType = value
 	}
-	if value, ok := mrc.mutation.SourceID(); ok {
-		_spec.SetField(messagerecords.FieldSourceID, field.TypeInt, value)
-		_node.SourceID = value
-	}
-	if value, ok := mrc.mutation.SubSourceID(); ok {
-		_spec.SetField(messagerecords.FieldSubSourceID, field.TypeInt, value)
-		_node.SubSourceID = value
+	if nodes := mrc.mutation.SopStageIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   messagerecords.SopStageTable,
+			Columns: []string{messagerecords.SopStageColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopstage.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_node.SourceID = nodes[0]
+		_spec.Edges = append(_spec.Edges, edge)
+	}
+	if nodes := mrc.mutation.SopNodeIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   messagerecords.SopNodeTable,
+			Columns: []string{messagerecords.SopNodeColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopnode.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_node.SubSourceID = nodes[0]
+		_spec.Edges = append(_spec.Edges, edge)
+	}
+	if nodes := mrc.mutation.MessageContactIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   messagerecords.MessageContactTable,
+			Columns: []string{messagerecords.MessageContactColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(contact.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_node.ContactID = nodes[0]
+		_spec.Edges = append(_spec.Edges, edge)
 	}
 	return _node, _spec
 }
@@ -562,7 +660,7 @@ func (u *MessageRecordsUpsert) UpdateBotWxid() *MessageRecordsUpsert {
 }
 
 // SetContactID sets the "contact_id" field.
-func (u *MessageRecordsUpsert) SetContactID(v int) *MessageRecordsUpsert {
+func (u *MessageRecordsUpsert) SetContactID(v uint64) *MessageRecordsUpsert {
 	u.Set(messagerecords.FieldContactID, v)
 	return u
 }
@@ -573,9 +671,9 @@ func (u *MessageRecordsUpsert) UpdateContactID() *MessageRecordsUpsert {
 	return u
 }
 
-// AddContactID adds v to the "contact_id" field.
-func (u *MessageRecordsUpsert) AddContactID(v int) *MessageRecordsUpsert {
-	u.Add(messagerecords.FieldContactID, v)
+// ClearContactID clears the value of the "contact_id" field.
+func (u *MessageRecordsUpsert) ClearContactID() *MessageRecordsUpsert {
+	u.SetNull(messagerecords.FieldContactID)
 	return u
 }
 
@@ -688,7 +786,7 @@ func (u *MessageRecordsUpsert) AddSourceType(v int) *MessageRecordsUpsert {
 }
 
 // SetSourceID sets the "source_id" field.
-func (u *MessageRecordsUpsert) SetSourceID(v int) *MessageRecordsUpsert {
+func (u *MessageRecordsUpsert) SetSourceID(v uint64) *MessageRecordsUpsert {
 	u.Set(messagerecords.FieldSourceID, v)
 	return u
 }
@@ -699,14 +797,14 @@ func (u *MessageRecordsUpsert) UpdateSourceID() *MessageRecordsUpsert {
 	return u
 }
 
-// AddSourceID adds v to the "source_id" field.
-func (u *MessageRecordsUpsert) AddSourceID(v int) *MessageRecordsUpsert {
-	u.Add(messagerecords.FieldSourceID, v)
+// ClearSourceID clears the value of the "source_id" field.
+func (u *MessageRecordsUpsert) ClearSourceID() *MessageRecordsUpsert {
+	u.SetNull(messagerecords.FieldSourceID)
 	return u
 }
 
 // SetSubSourceID sets the "sub_source_id" field.
-func (u *MessageRecordsUpsert) SetSubSourceID(v int) *MessageRecordsUpsert {
+func (u *MessageRecordsUpsert) SetSubSourceID(v uint64) *MessageRecordsUpsert {
 	u.Set(messagerecords.FieldSubSourceID, v)
 	return u
 }
@@ -717,9 +815,9 @@ func (u *MessageRecordsUpsert) UpdateSubSourceID() *MessageRecordsUpsert {
 	return u
 }
 
-// AddSubSourceID adds v to the "sub_source_id" field.
-func (u *MessageRecordsUpsert) AddSubSourceID(v int) *MessageRecordsUpsert {
-	u.Add(messagerecords.FieldSubSourceID, v)
+// ClearSubSourceID clears the value of the "sub_source_id" field.
+func (u *MessageRecordsUpsert) ClearSubSourceID() *MessageRecordsUpsert {
+	u.SetNull(messagerecords.FieldSubSourceID)
 	return u
 }
 
@@ -852,23 +950,23 @@ func (u *MessageRecordsUpsertOne) UpdateBotWxid() *MessageRecordsUpsertOne {
 }
 
 // SetContactID sets the "contact_id" field.
-func (u *MessageRecordsUpsertOne) SetContactID(v int) *MessageRecordsUpsertOne {
+func (u *MessageRecordsUpsertOne) SetContactID(v uint64) *MessageRecordsUpsertOne {
 	return u.Update(func(s *MessageRecordsUpsert) {
 		s.SetContactID(v)
 	})
 }
 
-// AddContactID adds v to the "contact_id" field.
-func (u *MessageRecordsUpsertOne) AddContactID(v int) *MessageRecordsUpsertOne {
+// UpdateContactID sets the "contact_id" field to the value that was provided on create.
+func (u *MessageRecordsUpsertOne) UpdateContactID() *MessageRecordsUpsertOne {
 	return u.Update(func(s *MessageRecordsUpsert) {
-		s.AddContactID(v)
+		s.UpdateContactID()
 	})
 }
 
-// UpdateContactID sets the "contact_id" field to the value that was provided on create.
-func (u *MessageRecordsUpsertOne) UpdateContactID() *MessageRecordsUpsertOne {
+// ClearContactID clears the value of the "contact_id" field.
+func (u *MessageRecordsUpsertOne) ClearContactID() *MessageRecordsUpsertOne {
 	return u.Update(func(s *MessageRecordsUpsert) {
-		s.UpdateContactID()
+		s.ClearContactID()
 	})
 }
 
@@ -999,19 +1097,12 @@ func (u *MessageRecordsUpsertOne) UpdateSourceType() *MessageRecordsUpsertOne {
 }
 
 // SetSourceID sets the "source_id" field.
-func (u *MessageRecordsUpsertOne) SetSourceID(v int) *MessageRecordsUpsertOne {
+func (u *MessageRecordsUpsertOne) SetSourceID(v uint64) *MessageRecordsUpsertOne {
 	return u.Update(func(s *MessageRecordsUpsert) {
 		s.SetSourceID(v)
 	})
 }
 
-// AddSourceID adds v to the "source_id" field.
-func (u *MessageRecordsUpsertOne) AddSourceID(v int) *MessageRecordsUpsertOne {
-	return u.Update(func(s *MessageRecordsUpsert) {
-		s.AddSourceID(v)
-	})
-}
-
 // UpdateSourceID sets the "source_id" field to the value that was provided on create.
 func (u *MessageRecordsUpsertOne) UpdateSourceID() *MessageRecordsUpsertOne {
 	return u.Update(func(s *MessageRecordsUpsert) {
@@ -1019,17 +1110,17 @@ func (u *MessageRecordsUpsertOne) UpdateSourceID() *MessageRecordsUpsertOne {
 	})
 }
 
-// SetSubSourceID sets the "sub_source_id" field.
-func (u *MessageRecordsUpsertOne) SetSubSourceID(v int) *MessageRecordsUpsertOne {
+// ClearSourceID clears the value of the "source_id" field.
+func (u *MessageRecordsUpsertOne) ClearSourceID() *MessageRecordsUpsertOne {
 	return u.Update(func(s *MessageRecordsUpsert) {
-		s.SetSubSourceID(v)
+		s.ClearSourceID()
 	})
 }
 
-// AddSubSourceID adds v to the "sub_source_id" field.
-func (u *MessageRecordsUpsertOne) AddSubSourceID(v int) *MessageRecordsUpsertOne {
+// SetSubSourceID sets the "sub_source_id" field.
+func (u *MessageRecordsUpsertOne) SetSubSourceID(v uint64) *MessageRecordsUpsertOne {
 	return u.Update(func(s *MessageRecordsUpsert) {
-		s.AddSubSourceID(v)
+		s.SetSubSourceID(v)
 	})
 }
 
@@ -1040,6 +1131,13 @@ func (u *MessageRecordsUpsertOne) UpdateSubSourceID() *MessageRecordsUpsertOne {
 	})
 }
 
+// ClearSubSourceID clears the value of the "sub_source_id" field.
+func (u *MessageRecordsUpsertOne) ClearSubSourceID() *MessageRecordsUpsertOne {
+	return u.Update(func(s *MessageRecordsUpsert) {
+		s.ClearSubSourceID()
+	})
+}
+
 // Exec executes the query.
 func (u *MessageRecordsUpsertOne) Exec(ctx context.Context) error {
 	if len(u.create.conflict) == 0 {
@@ -1335,23 +1433,23 @@ func (u *MessageRecordsUpsertBulk) UpdateBotWxid() *MessageRecordsUpsertBulk {
 }
 
 // SetContactID sets the "contact_id" field.
-func (u *MessageRecordsUpsertBulk) SetContactID(v int) *MessageRecordsUpsertBulk {
+func (u *MessageRecordsUpsertBulk) SetContactID(v uint64) *MessageRecordsUpsertBulk {
 	return u.Update(func(s *MessageRecordsUpsert) {
 		s.SetContactID(v)
 	})
 }
 
-// AddContactID adds v to the "contact_id" field.
-func (u *MessageRecordsUpsertBulk) AddContactID(v int) *MessageRecordsUpsertBulk {
+// UpdateContactID sets the "contact_id" field to the value that was provided on create.
+func (u *MessageRecordsUpsertBulk) UpdateContactID() *MessageRecordsUpsertBulk {
 	return u.Update(func(s *MessageRecordsUpsert) {
-		s.AddContactID(v)
+		s.UpdateContactID()
 	})
 }
 
-// UpdateContactID sets the "contact_id" field to the value that was provided on create.
-func (u *MessageRecordsUpsertBulk) UpdateContactID() *MessageRecordsUpsertBulk {
+// ClearContactID clears the value of the "contact_id" field.
+func (u *MessageRecordsUpsertBulk) ClearContactID() *MessageRecordsUpsertBulk {
 	return u.Update(func(s *MessageRecordsUpsert) {
-		s.UpdateContactID()
+		s.ClearContactID()
 	})
 }
 
@@ -1482,19 +1580,12 @@ func (u *MessageRecordsUpsertBulk) UpdateSourceType() *MessageRecordsUpsertBulk
 }
 
 // SetSourceID sets the "source_id" field.
-func (u *MessageRecordsUpsertBulk) SetSourceID(v int) *MessageRecordsUpsertBulk {
+func (u *MessageRecordsUpsertBulk) SetSourceID(v uint64) *MessageRecordsUpsertBulk {
 	return u.Update(func(s *MessageRecordsUpsert) {
 		s.SetSourceID(v)
 	})
 }
 
-// AddSourceID adds v to the "source_id" field.
-func (u *MessageRecordsUpsertBulk) AddSourceID(v int) *MessageRecordsUpsertBulk {
-	return u.Update(func(s *MessageRecordsUpsert) {
-		s.AddSourceID(v)
-	})
-}
-
 // UpdateSourceID sets the "source_id" field to the value that was provided on create.
 func (u *MessageRecordsUpsertBulk) UpdateSourceID() *MessageRecordsUpsertBulk {
 	return u.Update(func(s *MessageRecordsUpsert) {
@@ -1502,17 +1593,17 @@ func (u *MessageRecordsUpsertBulk) UpdateSourceID() *MessageRecordsUpsertBulk {
 	})
 }
 
-// SetSubSourceID sets the "sub_source_id" field.
-func (u *MessageRecordsUpsertBulk) SetSubSourceID(v int) *MessageRecordsUpsertBulk {
+// ClearSourceID clears the value of the "source_id" field.
+func (u *MessageRecordsUpsertBulk) ClearSourceID() *MessageRecordsUpsertBulk {
 	return u.Update(func(s *MessageRecordsUpsert) {
-		s.SetSubSourceID(v)
+		s.ClearSourceID()
 	})
 }
 
-// AddSubSourceID adds v to the "sub_source_id" field.
-func (u *MessageRecordsUpsertBulk) AddSubSourceID(v int) *MessageRecordsUpsertBulk {
+// SetSubSourceID sets the "sub_source_id" field.
+func (u *MessageRecordsUpsertBulk) SetSubSourceID(v uint64) *MessageRecordsUpsertBulk {
 	return u.Update(func(s *MessageRecordsUpsert) {
-		s.AddSubSourceID(v)
+		s.SetSubSourceID(v)
 	})
 }
 
@@ -1523,6 +1614,13 @@ func (u *MessageRecordsUpsertBulk) UpdateSubSourceID() *MessageRecordsUpsertBulk
 	})
 }
 
+// ClearSubSourceID clears the value of the "sub_source_id" field.
+func (u *MessageRecordsUpsertBulk) ClearSubSourceID() *MessageRecordsUpsertBulk {
+	return u.Update(func(s *MessageRecordsUpsert) {
+		s.ClearSubSourceID()
+	})
+}
+
 // Exec executes the query.
 func (u *MessageRecordsUpsertBulk) Exec(ctx context.Context) error {
 	if u.create.err != nil {

+ 240 - 11
ent/messagerecords_query.go

@@ -6,8 +6,11 @@ import (
 	"context"
 	"fmt"
 	"math"
+	"wechat-api/ent/contact"
 	"wechat-api/ent/messagerecords"
 	"wechat-api/ent/predicate"
+	"wechat-api/ent/sopnode"
+	"wechat-api/ent/sopstage"
 
 	"entgo.io/ent/dialect/sql"
 	"entgo.io/ent/dialect/sql/sqlgraph"
@@ -17,10 +20,13 @@ import (
 // MessageRecordsQuery is the builder for querying MessageRecords entities.
 type MessageRecordsQuery struct {
 	config
-	ctx        *QueryContext
-	order      []messagerecords.OrderOption
-	inters     []Interceptor
-	predicates []predicate.MessageRecords
+	ctx                *QueryContext
+	order              []messagerecords.OrderOption
+	inters             []Interceptor
+	predicates         []predicate.MessageRecords
+	withSopStage       *SopStageQuery
+	withSopNode        *SopNodeQuery
+	withMessageContact *ContactQuery
 	// intermediate query (i.e. traversal path).
 	sql  *sql.Selector
 	path func(context.Context) (*sql.Selector, error)
@@ -57,6 +63,72 @@ func (mrq *MessageRecordsQuery) Order(o ...messagerecords.OrderOption) *MessageR
 	return mrq
 }
 
+// QuerySopStage chains the current query on the "sop_stage" edge.
+func (mrq *MessageRecordsQuery) QuerySopStage() *SopStageQuery {
+	query := (&SopStageClient{config: mrq.config}).Query()
+	query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
+		if err := mrq.prepareQuery(ctx); err != nil {
+			return nil, err
+		}
+		selector := mrq.sqlQuery(ctx)
+		if err := selector.Err(); err != nil {
+			return nil, err
+		}
+		step := sqlgraph.NewStep(
+			sqlgraph.From(messagerecords.Table, messagerecords.FieldID, selector),
+			sqlgraph.To(sopstage.Table, sopstage.FieldID),
+			sqlgraph.Edge(sqlgraph.M2O, true, messagerecords.SopStageTable, messagerecords.SopStageColumn),
+		)
+		fromU = sqlgraph.SetNeighbors(mrq.driver.Dialect(), step)
+		return fromU, nil
+	}
+	return query
+}
+
+// QuerySopNode chains the current query on the "sop_node" edge.
+func (mrq *MessageRecordsQuery) QuerySopNode() *SopNodeQuery {
+	query := (&SopNodeClient{config: mrq.config}).Query()
+	query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
+		if err := mrq.prepareQuery(ctx); err != nil {
+			return nil, err
+		}
+		selector := mrq.sqlQuery(ctx)
+		if err := selector.Err(); err != nil {
+			return nil, err
+		}
+		step := sqlgraph.NewStep(
+			sqlgraph.From(messagerecords.Table, messagerecords.FieldID, selector),
+			sqlgraph.To(sopnode.Table, sopnode.FieldID),
+			sqlgraph.Edge(sqlgraph.M2O, true, messagerecords.SopNodeTable, messagerecords.SopNodeColumn),
+		)
+		fromU = sqlgraph.SetNeighbors(mrq.driver.Dialect(), step)
+		return fromU, nil
+	}
+	return query
+}
+
+// QueryMessageContact chains the current query on the "message_contact" edge.
+func (mrq *MessageRecordsQuery) QueryMessageContact() *ContactQuery {
+	query := (&ContactClient{config: mrq.config}).Query()
+	query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
+		if err := mrq.prepareQuery(ctx); err != nil {
+			return nil, err
+		}
+		selector := mrq.sqlQuery(ctx)
+		if err := selector.Err(); err != nil {
+			return nil, err
+		}
+		step := sqlgraph.NewStep(
+			sqlgraph.From(messagerecords.Table, messagerecords.FieldID, selector),
+			sqlgraph.To(contact.Table, contact.FieldID),
+			sqlgraph.Edge(sqlgraph.M2O, true, messagerecords.MessageContactTable, messagerecords.MessageContactColumn),
+		)
+		fromU = sqlgraph.SetNeighbors(mrq.driver.Dialect(), step)
+		return fromU, nil
+	}
+	return query
+}
+
 // First returns the first MessageRecords entity from the query.
 // Returns a *NotFoundError when no MessageRecords was found.
 func (mrq *MessageRecordsQuery) First(ctx context.Context) (*MessageRecords, error) {
@@ -244,17 +316,53 @@ func (mrq *MessageRecordsQuery) Clone() *MessageRecordsQuery {
 		return nil
 	}
 	return &MessageRecordsQuery{
-		config:     mrq.config,
-		ctx:        mrq.ctx.Clone(),
-		order:      append([]messagerecords.OrderOption{}, mrq.order...),
-		inters:     append([]Interceptor{}, mrq.inters...),
-		predicates: append([]predicate.MessageRecords{}, mrq.predicates...),
+		config:             mrq.config,
+		ctx:                mrq.ctx.Clone(),
+		order:              append([]messagerecords.OrderOption{}, mrq.order...),
+		inters:             append([]Interceptor{}, mrq.inters...),
+		predicates:         append([]predicate.MessageRecords{}, mrq.predicates...),
+		withSopStage:       mrq.withSopStage.Clone(),
+		withSopNode:        mrq.withSopNode.Clone(),
+		withMessageContact: mrq.withMessageContact.Clone(),
 		// clone intermediate query.
 		sql:  mrq.sql.Clone(),
 		path: mrq.path,
 	}
 }
 
+// WithSopStage tells the query-builder to eager-load the nodes that are connected to
+// the "sop_stage" edge. The optional arguments are used to configure the query builder of the edge.
+func (mrq *MessageRecordsQuery) WithSopStage(opts ...func(*SopStageQuery)) *MessageRecordsQuery {
+	query := (&SopStageClient{config: mrq.config}).Query()
+	for _, opt := range opts {
+		opt(query)
+	}
+	mrq.withSopStage = query
+	return mrq
+}
+
+// WithSopNode tells the query-builder to eager-load the nodes that are connected to
+// the "sop_node" edge. The optional arguments are used to configure the query builder of the edge.
+func (mrq *MessageRecordsQuery) WithSopNode(opts ...func(*SopNodeQuery)) *MessageRecordsQuery {
+	query := (&SopNodeClient{config: mrq.config}).Query()
+	for _, opt := range opts {
+		opt(query)
+	}
+	mrq.withSopNode = query
+	return mrq
+}
+
+// WithMessageContact tells the query-builder to eager-load the nodes that are connected to
+// the "message_contact" edge. The optional arguments are used to configure the query builder of the edge.
+func (mrq *MessageRecordsQuery) WithMessageContact(opts ...func(*ContactQuery)) *MessageRecordsQuery {
+	query := (&ContactClient{config: mrq.config}).Query()
+	for _, opt := range opts {
+		opt(query)
+	}
+	mrq.withMessageContact = query
+	return mrq
+}
+
 // GroupBy is used to group vertices by one or more fields/columns.
 // It is often used with aggregate functions, like: count, max, mean, min, sum.
 //
@@ -331,8 +439,13 @@ func (mrq *MessageRecordsQuery) prepareQuery(ctx context.Context) error {
 
 func (mrq *MessageRecordsQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*MessageRecords, error) {
 	var (
-		nodes = []*MessageRecords{}
-		_spec = mrq.querySpec()
+		nodes       = []*MessageRecords{}
+		_spec       = mrq.querySpec()
+		loadedTypes = [3]bool{
+			mrq.withSopStage != nil,
+			mrq.withSopNode != nil,
+			mrq.withMessageContact != nil,
+		}
 	)
 	_spec.ScanValues = func(columns []string) ([]any, error) {
 		return (*MessageRecords).scanValues(nil, columns)
@@ -340,6 +453,7 @@ func (mrq *MessageRecordsQuery) sqlAll(ctx context.Context, hooks ...queryHook)
 	_spec.Assign = func(columns []string, values []any) error {
 		node := &MessageRecords{config: mrq.config}
 		nodes = append(nodes, node)
+		node.Edges.loadedTypes = loadedTypes
 		return node.assignValues(columns, values)
 	}
 	for i := range hooks {
@@ -351,9 +465,115 @@ func (mrq *MessageRecordsQuery) sqlAll(ctx context.Context, hooks ...queryHook)
 	if len(nodes) == 0 {
 		return nodes, nil
 	}
+	if query := mrq.withSopStage; query != nil {
+		if err := mrq.loadSopStage(ctx, query, nodes, nil,
+			func(n *MessageRecords, e *SopStage) { n.Edges.SopStage = e }); err != nil {
+			return nil, err
+		}
+	}
+	if query := mrq.withSopNode; query != nil {
+		if err := mrq.loadSopNode(ctx, query, nodes, nil,
+			func(n *MessageRecords, e *SopNode) { n.Edges.SopNode = e }); err != nil {
+			return nil, err
+		}
+	}
+	if query := mrq.withMessageContact; query != nil {
+		if err := mrq.loadMessageContact(ctx, query, nodes, nil,
+			func(n *MessageRecords, e *Contact) { n.Edges.MessageContact = e }); err != nil {
+			return nil, err
+		}
+	}
 	return nodes, nil
 }
 
+func (mrq *MessageRecordsQuery) loadSopStage(ctx context.Context, query *SopStageQuery, nodes []*MessageRecords, init func(*MessageRecords), assign func(*MessageRecords, *SopStage)) error {
+	ids := make([]uint64, 0, len(nodes))
+	nodeids := make(map[uint64][]*MessageRecords)
+	for i := range nodes {
+		fk := nodes[i].SourceID
+		if _, ok := nodeids[fk]; !ok {
+			ids = append(ids, fk)
+		}
+		nodeids[fk] = append(nodeids[fk], nodes[i])
+	}
+	if len(ids) == 0 {
+		return nil
+	}
+	query.Where(sopstage.IDIn(ids...))
+	neighbors, err := query.All(ctx)
+	if err != nil {
+		return err
+	}
+	for _, n := range neighbors {
+		nodes, ok := nodeids[n.ID]
+		if !ok {
+			return fmt.Errorf(`unexpected foreign-key "source_id" returned %v`, n.ID)
+		}
+		for i := range nodes {
+			assign(nodes[i], n)
+		}
+	}
+	return nil
+}
+func (mrq *MessageRecordsQuery) loadSopNode(ctx context.Context, query *SopNodeQuery, nodes []*MessageRecords, init func(*MessageRecords), assign func(*MessageRecords, *SopNode)) error {
+	ids := make([]uint64, 0, len(nodes))
+	nodeids := make(map[uint64][]*MessageRecords)
+	for i := range nodes {
+		fk := nodes[i].SubSourceID
+		if _, ok := nodeids[fk]; !ok {
+			ids = append(ids, fk)
+		}
+		nodeids[fk] = append(nodeids[fk], nodes[i])
+	}
+	if len(ids) == 0 {
+		return nil
+	}
+	query.Where(sopnode.IDIn(ids...))
+	neighbors, err := query.All(ctx)
+	if err != nil {
+		return err
+	}
+	for _, n := range neighbors {
+		nodes, ok := nodeids[n.ID]
+		if !ok {
+			return fmt.Errorf(`unexpected foreign-key "sub_source_id" returned %v`, n.ID)
+		}
+		for i := range nodes {
+			assign(nodes[i], n)
+		}
+	}
+	return nil
+}
+func (mrq *MessageRecordsQuery) loadMessageContact(ctx context.Context, query *ContactQuery, nodes []*MessageRecords, init func(*MessageRecords), assign func(*MessageRecords, *Contact)) error {
+	ids := make([]uint64, 0, len(nodes))
+	nodeids := make(map[uint64][]*MessageRecords)
+	for i := range nodes {
+		fk := nodes[i].ContactID
+		if _, ok := nodeids[fk]; !ok {
+			ids = append(ids, fk)
+		}
+		nodeids[fk] = append(nodeids[fk], nodes[i])
+	}
+	if len(ids) == 0 {
+		return nil
+	}
+	query.Where(contact.IDIn(ids...))
+	neighbors, err := query.All(ctx)
+	if err != nil {
+		return err
+	}
+	for _, n := range neighbors {
+		nodes, ok := nodeids[n.ID]
+		if !ok {
+			return fmt.Errorf(`unexpected foreign-key "contact_id" returned %v`, n.ID)
+		}
+		for i := range nodes {
+			assign(nodes[i], n)
+		}
+	}
+	return nil
+}
+
 func (mrq *MessageRecordsQuery) sqlCount(ctx context.Context) (int, error) {
 	_spec := mrq.querySpec()
 	_spec.Node.Columns = mrq.ctx.Fields
@@ -379,6 +599,15 @@ func (mrq *MessageRecordsQuery) querySpec() *sqlgraph.QuerySpec {
 				_spec.Node.Columns = append(_spec.Node.Columns, fields[i])
 			}
 		}
+		if mrq.withSopStage != nil {
+			_spec.Node.AddColumnOnce(messagerecords.FieldSourceID)
+		}
+		if mrq.withSopNode != nil {
+			_spec.Node.AddColumnOnce(messagerecords.FieldSubSourceID)
+		}
+		if mrq.withMessageContact != nil {
+			_spec.Node.AddColumnOnce(messagerecords.FieldContactID)
+		}
 	}
 	if ps := mrq.predicates; len(ps) > 0 {
 		_spec.Predicate = func(selector *sql.Selector) {

+ 373 - 88
ent/messagerecords_update.go

@@ -7,8 +7,11 @@ import (
 	"errors"
 	"fmt"
 	"time"
+	"wechat-api/ent/contact"
 	"wechat-api/ent/messagerecords"
 	"wechat-api/ent/predicate"
+	"wechat-api/ent/sopnode"
+	"wechat-api/ent/sopstage"
 
 	"entgo.io/ent/dialect/sql"
 	"entgo.io/ent/dialect/sql/sqlgraph"
@@ -96,23 +99,22 @@ func (mru *MessageRecordsUpdate) SetNillableBotWxid(s *string) *MessageRecordsUp
 }
 
 // SetContactID sets the "contact_id" field.
-func (mru *MessageRecordsUpdate) SetContactID(i int) *MessageRecordsUpdate {
-	mru.mutation.ResetContactID()
-	mru.mutation.SetContactID(i)
+func (mru *MessageRecordsUpdate) SetContactID(u uint64) *MessageRecordsUpdate {
+	mru.mutation.SetContactID(u)
 	return mru
 }
 
 // SetNillableContactID sets the "contact_id" field if the given value is not nil.
-func (mru *MessageRecordsUpdate) SetNillableContactID(i *int) *MessageRecordsUpdate {
-	if i != nil {
-		mru.SetContactID(*i)
+func (mru *MessageRecordsUpdate) SetNillableContactID(u *uint64) *MessageRecordsUpdate {
+	if u != nil {
+		mru.SetContactID(*u)
 	}
 	return mru
 }
 
-// AddContactID adds i to the "contact_id" field.
-func (mru *MessageRecordsUpdate) AddContactID(i int) *MessageRecordsUpdate {
-	mru.mutation.AddContactID(i)
+// ClearContactID clears the value of the "contact_id" field.
+func (mru *MessageRecordsUpdate) ClearContactID() *MessageRecordsUpdate {
+	mru.mutation.ClearContactID()
 	return mru
 }
 
@@ -242,52 +244,125 @@ func (mru *MessageRecordsUpdate) AddSourceType(i int) *MessageRecordsUpdate {
 }
 
 // SetSourceID sets the "source_id" field.
-func (mru *MessageRecordsUpdate) SetSourceID(i int) *MessageRecordsUpdate {
-	mru.mutation.ResetSourceID()
-	mru.mutation.SetSourceID(i)
+func (mru *MessageRecordsUpdate) SetSourceID(u uint64) *MessageRecordsUpdate {
+	mru.mutation.SetSourceID(u)
 	return mru
 }
 
 // SetNillableSourceID sets the "source_id" field if the given value is not nil.
-func (mru *MessageRecordsUpdate) SetNillableSourceID(i *int) *MessageRecordsUpdate {
-	if i != nil {
-		mru.SetSourceID(*i)
+func (mru *MessageRecordsUpdate) SetNillableSourceID(u *uint64) *MessageRecordsUpdate {
+	if u != nil {
+		mru.SetSourceID(*u)
 	}
 	return mru
 }
 
-// AddSourceID adds i to the "source_id" field.
-func (mru *MessageRecordsUpdate) AddSourceID(i int) *MessageRecordsUpdate {
-	mru.mutation.AddSourceID(i)
+// ClearSourceID clears the value of the "source_id" field.
+func (mru *MessageRecordsUpdate) ClearSourceID() *MessageRecordsUpdate {
+	mru.mutation.ClearSourceID()
 	return mru
 }
 
 // SetSubSourceID sets the "sub_source_id" field.
-func (mru *MessageRecordsUpdate) SetSubSourceID(i int) *MessageRecordsUpdate {
-	mru.mutation.ResetSubSourceID()
-	mru.mutation.SetSubSourceID(i)
+func (mru *MessageRecordsUpdate) SetSubSourceID(u uint64) *MessageRecordsUpdate {
+	mru.mutation.SetSubSourceID(u)
 	return mru
 }
 
 // SetNillableSubSourceID sets the "sub_source_id" field if the given value is not nil.
-func (mru *MessageRecordsUpdate) SetNillableSubSourceID(i *int) *MessageRecordsUpdate {
-	if i != nil {
-		mru.SetSubSourceID(*i)
+func (mru *MessageRecordsUpdate) SetNillableSubSourceID(u *uint64) *MessageRecordsUpdate {
+	if u != nil {
+		mru.SetSubSourceID(*u)
+	}
+	return mru
+}
+
+// ClearSubSourceID clears the value of the "sub_source_id" field.
+func (mru *MessageRecordsUpdate) ClearSubSourceID() *MessageRecordsUpdate {
+	mru.mutation.ClearSubSourceID()
+	return mru
+}
+
+// SetSopStageID sets the "sop_stage" edge to the SopStage entity by ID.
+func (mru *MessageRecordsUpdate) SetSopStageID(id uint64) *MessageRecordsUpdate {
+	mru.mutation.SetSopStageID(id)
+	return mru
+}
+
+// SetNillableSopStageID sets the "sop_stage" edge to the SopStage entity by ID if the given value is not nil.
+func (mru *MessageRecordsUpdate) SetNillableSopStageID(id *uint64) *MessageRecordsUpdate {
+	if id != nil {
+		mru = mru.SetSopStageID(*id)
+	}
+	return mru
+}
+
+// SetSopStage sets the "sop_stage" edge to the SopStage entity.
+func (mru *MessageRecordsUpdate) SetSopStage(s *SopStage) *MessageRecordsUpdate {
+	return mru.SetSopStageID(s.ID)
+}
+
+// SetSopNodeID sets the "sop_node" edge to the SopNode entity by ID.
+func (mru *MessageRecordsUpdate) SetSopNodeID(id uint64) *MessageRecordsUpdate {
+	mru.mutation.SetSopNodeID(id)
+	return mru
+}
+
+// SetNillableSopNodeID sets the "sop_node" edge to the SopNode entity by ID if the given value is not nil.
+func (mru *MessageRecordsUpdate) SetNillableSopNodeID(id *uint64) *MessageRecordsUpdate {
+	if id != nil {
+		mru = mru.SetSopNodeID(*id)
 	}
 	return mru
 }
 
-// AddSubSourceID adds i to the "sub_source_id" field.
-func (mru *MessageRecordsUpdate) AddSubSourceID(i int) *MessageRecordsUpdate {
-	mru.mutation.AddSubSourceID(i)
+// SetSopNode sets the "sop_node" edge to the SopNode entity.
+func (mru *MessageRecordsUpdate) SetSopNode(s *SopNode) *MessageRecordsUpdate {
+	return mru.SetSopNodeID(s.ID)
+}
+
+// SetMessageContactID sets the "message_contact" edge to the Contact entity by ID.
+func (mru *MessageRecordsUpdate) SetMessageContactID(id uint64) *MessageRecordsUpdate {
+	mru.mutation.SetMessageContactID(id)
+	return mru
+}
+
+// SetNillableMessageContactID sets the "message_contact" edge to the Contact entity by ID if the given value is not nil.
+func (mru *MessageRecordsUpdate) SetNillableMessageContactID(id *uint64) *MessageRecordsUpdate {
+	if id != nil {
+		mru = mru.SetMessageContactID(*id)
+	}
 	return mru
 }
 
+// SetMessageContact sets the "message_contact" edge to the Contact entity.
+func (mru *MessageRecordsUpdate) SetMessageContact(c *Contact) *MessageRecordsUpdate {
+	return mru.SetMessageContactID(c.ID)
+}
+
 // Mutation returns the MessageRecordsMutation object of the builder.
 func (mru *MessageRecordsUpdate) Mutation() *MessageRecordsMutation {
 	return mru.mutation
 }
 
+// ClearSopStage clears the "sop_stage" edge to the SopStage entity.
+func (mru *MessageRecordsUpdate) ClearSopStage() *MessageRecordsUpdate {
+	mru.mutation.ClearSopStage()
+	return mru
+}
+
+// ClearSopNode clears the "sop_node" edge to the SopNode entity.
+func (mru *MessageRecordsUpdate) ClearSopNode() *MessageRecordsUpdate {
+	mru.mutation.ClearSopNode()
+	return mru
+}
+
+// ClearMessageContact clears the "message_contact" edge to the Contact entity.
+func (mru *MessageRecordsUpdate) ClearMessageContact() *MessageRecordsUpdate {
+	mru.mutation.ClearMessageContact()
+	return mru
+}
+
 // Save executes the query and returns the number of nodes affected by the update operation.
 func (mru *MessageRecordsUpdate) Save(ctx context.Context) (int, error) {
 	if err := mru.defaults(); err != nil {
@@ -360,12 +435,6 @@ func (mru *MessageRecordsUpdate) sqlSave(ctx context.Context) (n int, err error)
 	if value, ok := mru.mutation.BotWxid(); ok {
 		_spec.SetField(messagerecords.FieldBotWxid, field.TypeString, value)
 	}
-	if value, ok := mru.mutation.ContactID(); ok {
-		_spec.SetField(messagerecords.FieldContactID, field.TypeInt, value)
-	}
-	if value, ok := mru.mutation.AddedContactID(); ok {
-		_spec.AddField(messagerecords.FieldContactID, field.TypeInt, value)
-	}
 	if value, ok := mru.mutation.ContactType(); ok {
 		_spec.SetField(messagerecords.FieldContactType, field.TypeInt, value)
 	}
@@ -399,17 +468,92 @@ func (mru *MessageRecordsUpdate) sqlSave(ctx context.Context) (n int, err error)
 	if value, ok := mru.mutation.AddedSourceType(); ok {
 		_spec.AddField(messagerecords.FieldSourceType, field.TypeInt, value)
 	}
-	if value, ok := mru.mutation.SourceID(); ok {
-		_spec.SetField(messagerecords.FieldSourceID, field.TypeInt, value)
-	}
-	if value, ok := mru.mutation.AddedSourceID(); ok {
-		_spec.AddField(messagerecords.FieldSourceID, field.TypeInt, value)
-	}
-	if value, ok := mru.mutation.SubSourceID(); ok {
-		_spec.SetField(messagerecords.FieldSubSourceID, field.TypeInt, value)
-	}
-	if value, ok := mru.mutation.AddedSubSourceID(); ok {
-		_spec.AddField(messagerecords.FieldSubSourceID, field.TypeInt, value)
+	if mru.mutation.SopStageCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   messagerecords.SopStageTable,
+			Columns: []string{messagerecords.SopStageColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopstage.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := mru.mutation.SopStageIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   messagerecords.SopStageTable,
+			Columns: []string{messagerecords.SopStageColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopstage.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
+	if mru.mutation.SopNodeCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   messagerecords.SopNodeTable,
+			Columns: []string{messagerecords.SopNodeColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopnode.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := mru.mutation.SopNodeIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   messagerecords.SopNodeTable,
+			Columns: []string{messagerecords.SopNodeColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopnode.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
+	if mru.mutation.MessageContactCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   messagerecords.MessageContactTable,
+			Columns: []string{messagerecords.MessageContactColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(contact.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := mru.mutation.MessageContactIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   messagerecords.MessageContactTable,
+			Columns: []string{messagerecords.MessageContactColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(contact.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
 	}
 	if n, err = sqlgraph.UpdateNodes(ctx, mru.driver, _spec); err != nil {
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
@@ -499,23 +643,22 @@ func (mruo *MessageRecordsUpdateOne) SetNillableBotWxid(s *string) *MessageRecor
 }
 
 // SetContactID sets the "contact_id" field.
-func (mruo *MessageRecordsUpdateOne) SetContactID(i int) *MessageRecordsUpdateOne {
-	mruo.mutation.ResetContactID()
-	mruo.mutation.SetContactID(i)
+func (mruo *MessageRecordsUpdateOne) SetContactID(u uint64) *MessageRecordsUpdateOne {
+	mruo.mutation.SetContactID(u)
 	return mruo
 }
 
 // SetNillableContactID sets the "contact_id" field if the given value is not nil.
-func (mruo *MessageRecordsUpdateOne) SetNillableContactID(i *int) *MessageRecordsUpdateOne {
-	if i != nil {
-		mruo.SetContactID(*i)
+func (mruo *MessageRecordsUpdateOne) SetNillableContactID(u *uint64) *MessageRecordsUpdateOne {
+	if u != nil {
+		mruo.SetContactID(*u)
 	}
 	return mruo
 }
 
-// AddContactID adds i to the "contact_id" field.
-func (mruo *MessageRecordsUpdateOne) AddContactID(i int) *MessageRecordsUpdateOne {
-	mruo.mutation.AddContactID(i)
+// ClearContactID clears the value of the "contact_id" field.
+func (mruo *MessageRecordsUpdateOne) ClearContactID() *MessageRecordsUpdateOne {
+	mruo.mutation.ClearContactID()
 	return mruo
 }
 
@@ -645,52 +788,125 @@ func (mruo *MessageRecordsUpdateOne) AddSourceType(i int) *MessageRecordsUpdateO
 }
 
 // SetSourceID sets the "source_id" field.
-func (mruo *MessageRecordsUpdateOne) SetSourceID(i int) *MessageRecordsUpdateOne {
-	mruo.mutation.ResetSourceID()
-	mruo.mutation.SetSourceID(i)
+func (mruo *MessageRecordsUpdateOne) SetSourceID(u uint64) *MessageRecordsUpdateOne {
+	mruo.mutation.SetSourceID(u)
 	return mruo
 }
 
 // SetNillableSourceID sets the "source_id" field if the given value is not nil.
-func (mruo *MessageRecordsUpdateOne) SetNillableSourceID(i *int) *MessageRecordsUpdateOne {
-	if i != nil {
-		mruo.SetSourceID(*i)
+func (mruo *MessageRecordsUpdateOne) SetNillableSourceID(u *uint64) *MessageRecordsUpdateOne {
+	if u != nil {
+		mruo.SetSourceID(*u)
 	}
 	return mruo
 }
 
-// AddSourceID adds i to the "source_id" field.
-func (mruo *MessageRecordsUpdateOne) AddSourceID(i int) *MessageRecordsUpdateOne {
-	mruo.mutation.AddSourceID(i)
+// ClearSourceID clears the value of the "source_id" field.
+func (mruo *MessageRecordsUpdateOne) ClearSourceID() *MessageRecordsUpdateOne {
+	mruo.mutation.ClearSourceID()
 	return mruo
 }
 
 // SetSubSourceID sets the "sub_source_id" field.
-func (mruo *MessageRecordsUpdateOne) SetSubSourceID(i int) *MessageRecordsUpdateOne {
-	mruo.mutation.ResetSubSourceID()
-	mruo.mutation.SetSubSourceID(i)
+func (mruo *MessageRecordsUpdateOne) SetSubSourceID(u uint64) *MessageRecordsUpdateOne {
+	mruo.mutation.SetSubSourceID(u)
 	return mruo
 }
 
 // SetNillableSubSourceID sets the "sub_source_id" field if the given value is not nil.
-func (mruo *MessageRecordsUpdateOne) SetNillableSubSourceID(i *int) *MessageRecordsUpdateOne {
-	if i != nil {
-		mruo.SetSubSourceID(*i)
+func (mruo *MessageRecordsUpdateOne) SetNillableSubSourceID(u *uint64) *MessageRecordsUpdateOne {
+	if u != nil {
+		mruo.SetSubSourceID(*u)
+	}
+	return mruo
+}
+
+// ClearSubSourceID clears the value of the "sub_source_id" field.
+func (mruo *MessageRecordsUpdateOne) ClearSubSourceID() *MessageRecordsUpdateOne {
+	mruo.mutation.ClearSubSourceID()
+	return mruo
+}
+
+// SetSopStageID sets the "sop_stage" edge to the SopStage entity by ID.
+func (mruo *MessageRecordsUpdateOne) SetSopStageID(id uint64) *MessageRecordsUpdateOne {
+	mruo.mutation.SetSopStageID(id)
+	return mruo
+}
+
+// SetNillableSopStageID sets the "sop_stage" edge to the SopStage entity by ID if the given value is not nil.
+func (mruo *MessageRecordsUpdateOne) SetNillableSopStageID(id *uint64) *MessageRecordsUpdateOne {
+	if id != nil {
+		mruo = mruo.SetSopStageID(*id)
+	}
+	return mruo
+}
+
+// SetSopStage sets the "sop_stage" edge to the SopStage entity.
+func (mruo *MessageRecordsUpdateOne) SetSopStage(s *SopStage) *MessageRecordsUpdateOne {
+	return mruo.SetSopStageID(s.ID)
+}
+
+// SetSopNodeID sets the "sop_node" edge to the SopNode entity by ID.
+func (mruo *MessageRecordsUpdateOne) SetSopNodeID(id uint64) *MessageRecordsUpdateOne {
+	mruo.mutation.SetSopNodeID(id)
+	return mruo
+}
+
+// SetNillableSopNodeID sets the "sop_node" edge to the SopNode entity by ID if the given value is not nil.
+func (mruo *MessageRecordsUpdateOne) SetNillableSopNodeID(id *uint64) *MessageRecordsUpdateOne {
+	if id != nil {
+		mruo = mruo.SetSopNodeID(*id)
 	}
 	return mruo
 }
 
-// AddSubSourceID adds i to the "sub_source_id" field.
-func (mruo *MessageRecordsUpdateOne) AddSubSourceID(i int) *MessageRecordsUpdateOne {
-	mruo.mutation.AddSubSourceID(i)
+// SetSopNode sets the "sop_node" edge to the SopNode entity.
+func (mruo *MessageRecordsUpdateOne) SetSopNode(s *SopNode) *MessageRecordsUpdateOne {
+	return mruo.SetSopNodeID(s.ID)
+}
+
+// SetMessageContactID sets the "message_contact" edge to the Contact entity by ID.
+func (mruo *MessageRecordsUpdateOne) SetMessageContactID(id uint64) *MessageRecordsUpdateOne {
+	mruo.mutation.SetMessageContactID(id)
+	return mruo
+}
+
+// SetNillableMessageContactID sets the "message_contact" edge to the Contact entity by ID if the given value is not nil.
+func (mruo *MessageRecordsUpdateOne) SetNillableMessageContactID(id *uint64) *MessageRecordsUpdateOne {
+	if id != nil {
+		mruo = mruo.SetMessageContactID(*id)
+	}
 	return mruo
 }
 
+// SetMessageContact sets the "message_contact" edge to the Contact entity.
+func (mruo *MessageRecordsUpdateOne) SetMessageContact(c *Contact) *MessageRecordsUpdateOne {
+	return mruo.SetMessageContactID(c.ID)
+}
+
 // Mutation returns the MessageRecordsMutation object of the builder.
 func (mruo *MessageRecordsUpdateOne) Mutation() *MessageRecordsMutation {
 	return mruo.mutation
 }
 
+// ClearSopStage clears the "sop_stage" edge to the SopStage entity.
+func (mruo *MessageRecordsUpdateOne) ClearSopStage() *MessageRecordsUpdateOne {
+	mruo.mutation.ClearSopStage()
+	return mruo
+}
+
+// ClearSopNode clears the "sop_node" edge to the SopNode entity.
+func (mruo *MessageRecordsUpdateOne) ClearSopNode() *MessageRecordsUpdateOne {
+	mruo.mutation.ClearSopNode()
+	return mruo
+}
+
+// ClearMessageContact clears the "message_contact" edge to the Contact entity.
+func (mruo *MessageRecordsUpdateOne) ClearMessageContact() *MessageRecordsUpdateOne {
+	mruo.mutation.ClearMessageContact()
+	return mruo
+}
+
 // Where appends a list predicates to the MessageRecordsUpdate builder.
 func (mruo *MessageRecordsUpdateOne) Where(ps ...predicate.MessageRecords) *MessageRecordsUpdateOne {
 	mruo.mutation.Where(ps...)
@@ -793,12 +1009,6 @@ func (mruo *MessageRecordsUpdateOne) sqlSave(ctx context.Context) (_node *Messag
 	if value, ok := mruo.mutation.BotWxid(); ok {
 		_spec.SetField(messagerecords.FieldBotWxid, field.TypeString, value)
 	}
-	if value, ok := mruo.mutation.ContactID(); ok {
-		_spec.SetField(messagerecords.FieldContactID, field.TypeInt, value)
-	}
-	if value, ok := mruo.mutation.AddedContactID(); ok {
-		_spec.AddField(messagerecords.FieldContactID, field.TypeInt, value)
-	}
 	if value, ok := mruo.mutation.ContactType(); ok {
 		_spec.SetField(messagerecords.FieldContactType, field.TypeInt, value)
 	}
@@ -832,17 +1042,92 @@ func (mruo *MessageRecordsUpdateOne) sqlSave(ctx context.Context) (_node *Messag
 	if value, ok := mruo.mutation.AddedSourceType(); ok {
 		_spec.AddField(messagerecords.FieldSourceType, field.TypeInt, value)
 	}
-	if value, ok := mruo.mutation.SourceID(); ok {
-		_spec.SetField(messagerecords.FieldSourceID, field.TypeInt, value)
-	}
-	if value, ok := mruo.mutation.AddedSourceID(); ok {
-		_spec.AddField(messagerecords.FieldSourceID, field.TypeInt, value)
-	}
-	if value, ok := mruo.mutation.SubSourceID(); ok {
-		_spec.SetField(messagerecords.FieldSubSourceID, field.TypeInt, value)
-	}
-	if value, ok := mruo.mutation.AddedSubSourceID(); ok {
-		_spec.AddField(messagerecords.FieldSubSourceID, field.TypeInt, value)
+	if mruo.mutation.SopStageCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   messagerecords.SopStageTable,
+			Columns: []string{messagerecords.SopStageColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopstage.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := mruo.mutation.SopStageIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   messagerecords.SopStageTable,
+			Columns: []string{messagerecords.SopStageColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopstage.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
+	if mruo.mutation.SopNodeCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   messagerecords.SopNodeTable,
+			Columns: []string{messagerecords.SopNodeColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopnode.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := mruo.mutation.SopNodeIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   messagerecords.SopNodeTable,
+			Columns: []string{messagerecords.SopNodeColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopnode.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
+	if mruo.mutation.MessageContactCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   messagerecords.MessageContactTable,
+			Columns: []string{messagerecords.MessageContactColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(contact.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := mruo.mutation.MessageContactIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   messagerecords.MessageContactTable,
+			Columns: []string{messagerecords.MessageContactColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(contact.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
 	}
 	_node = &MessageRecords{config: mruo.config}
 	_spec.Assign = _node.assignValues

+ 27 - 4
ent/migrate/schema.go

@@ -149,7 +149,6 @@ var (
 		{Name: "status", Type: field.TypeUint8, Nullable: true, Comment: "Status 1: normal 2: ban | 状态 1 正常 2 禁用", Default: 1},
 		{Name: "deleted_at", Type: field.TypeTime, Nullable: true, Comment: "Delete Time | 删除日期"},
 		{Name: "bot_wxid", Type: field.TypeString, Comment: "机器人微信 id"},
-		{Name: "contact_id", Type: field.TypeInt, Comment: "联系人 id"},
 		{Name: "contact_type", Type: field.TypeInt, Comment: "类型:1好友,2群组,3企业微信联系人", Default: 1},
 		{Name: "contact_wxid", Type: field.TypeString, Comment: "接收方微信 id", Default: ""},
 		{Name: "content_type", Type: field.TypeInt, Comment: "内容类型 1 文本 2 文件", Default: 1},
@@ -157,19 +156,40 @@ var (
 		{Name: "error_detail", Type: field.TypeString, Comment: "异常原因", Default: ""},
 		{Name: "send_time", Type: field.TypeTime, Nullable: true, Comment: "发送时间"},
 		{Name: "source_type", Type: field.TypeInt, Comment: "源类型 1 点发 2 群发 3 SOP", Default: 1},
-		{Name: "source_id", Type: field.TypeInt, Comment: "源 ID", Default: 1},
-		{Name: "sub_source_id", Type: field.TypeInt, Comment: "次源 ID", Default: 1},
+		{Name: "contact_id", Type: field.TypeUint64, Nullable: true, Comment: "联系人 id"},
+		{Name: "sub_source_id", Type: field.TypeUint64, Nullable: true, Comment: "次源 ID", Default: 1},
+		{Name: "source_id", Type: field.TypeUint64, Nullable: true, Comment: "源 ID", Default: 1},
 	}
 	// MessageRecordsTable holds the schema information for the "message_records" table.
 	MessageRecordsTable = &schema.Table{
 		Name:       "message_records",
 		Columns:    MessageRecordsColumns,
 		PrimaryKey: []*schema.Column{MessageRecordsColumns[0]},
+		ForeignKeys: []*schema.ForeignKey{
+			{
+				Symbol:     "message_records_contact_contact_messages",
+				Columns:    []*schema.Column{MessageRecordsColumns[13]},
+				RefColumns: []*schema.Column{ContactColumns[0]},
+				OnDelete:   schema.SetNull,
+			},
+			{
+				Symbol:     "message_records_sop_node_node_messages",
+				Columns:    []*schema.Column{MessageRecordsColumns[14]},
+				RefColumns: []*schema.Column{SopNodeColumns[0]},
+				OnDelete:   schema.SetNull,
+			},
+			{
+				Symbol:     "message_records_sop_stage_stage_messages",
+				Columns:    []*schema.Column{MessageRecordsColumns[15]},
+				RefColumns: []*schema.Column{SopStageColumns[0]},
+				OnDelete:   schema.SetNull,
+			},
+		},
 		Indexes: []*schema.Index{
 			{
 				Name:    "messagerecords_source_type",
 				Unique:  false,
-				Columns: []*schema.Column{MessageRecordsColumns[13]},
+				Columns: []*schema.Column{MessageRecordsColumns[12]},
 			},
 		},
 	}
@@ -396,6 +416,9 @@ func init() {
 	MessageTable.Annotation = &entsql.Annotation{
 		Table: "message",
 	}
+	MessageRecordsTable.ForeignKeys[0].RefTable = ContactTable
+	MessageRecordsTable.ForeignKeys[1].RefTable = SopNodeTable
+	MessageRecordsTable.ForeignKeys[2].RefTable = SopStageTable
 	MessageRecordsTable.Annotation = &entsql.Annotation{
 		Table: "message_records",
 	}

File diff suppressed because it is too large
+ 463 - 157
ent/mutation.go


+ 2 - 2
ent/runtime/runtime.go

@@ -250,11 +250,11 @@ func init() {
 	// messagerecordsDescSourceID is the schema descriptor for source_id field.
 	messagerecordsDescSourceID := messagerecordsFields[9].Descriptor()
 	// messagerecords.DefaultSourceID holds the default value on creation for the source_id field.
-	messagerecords.DefaultSourceID = messagerecordsDescSourceID.Default.(int)
+	messagerecords.DefaultSourceID = messagerecordsDescSourceID.Default.(uint64)
 	// messagerecordsDescSubSourceID is the schema descriptor for sub_source_id field.
 	messagerecordsDescSubSourceID := messagerecordsFields[10].Descriptor()
 	// messagerecords.DefaultSubSourceID holds the default value on creation for the sub_source_id field.
-	messagerecords.DefaultSubSourceID = messagerecordsDescSubSourceID.Default.(int)
+	messagerecords.DefaultSubSourceID = messagerecordsDescSubSourceID.Default.(uint64)
 	serverMixin := schema.Server{}.Mixin()
 	serverMixinHooks2 := serverMixin[2].Hooks()
 	server.Hooks[0] = serverMixinHooks2[0]

+ 1 - 0
ent/schema/contact.go

@@ -85,6 +85,7 @@ func (Contact) Indexes() []ent.Index {
 func (Contact) Edges() []ent.Edge {
 	return []ent.Edge{
 		edge.To("contact_relationships", LabelRelationship.Type),
+		edge.To("contact_messages", MessageRecords.Type),
 	}
 }
 func (Contact) Annotations() []schema.Annotation {

+ 18 - 4
ent/schema/message_records.go

@@ -4,6 +4,7 @@ import (
 	"entgo.io/ent"
 	"entgo.io/ent/dialect/entsql"
 	"entgo.io/ent/schema"
+	"entgo.io/ent/schema/edge"
 	"entgo.io/ent/schema/field"
 	"entgo.io/ent/schema/index"
 	"github.com/suyuan32/simple-admin-common/orm/ent/mixins"
@@ -19,7 +20,7 @@ func (MessageRecords) Fields() []ent.Field {
 		field.String("bot_wxid").
 			Annotations(entsql.WithComments(true)).
 			Comment("机器人微信 id"),
-		field.Int("contact_id").
+		field.Uint64("contact_id").Optional().
 			Annotations(entsql.WithComments(true)).
 			Comment("联系人 id"),
 		field.Int("contact_type").Default(1).
@@ -43,10 +44,10 @@ func (MessageRecords) Fields() []ent.Field {
 		field.Int("source_type").Default(1).
 			Annotations(entsql.WithComments(true)).
 			Comment("源类型 1 点发 2 群发 3 SOP"),
-		field.Int("source_id").Default(1).
+		field.Uint64("source_id").Default(1).Optional().
 			Annotations(entsql.WithComments(true)).
 			Comment("源 ID"),
-		field.Int("sub_source_id").Default(1).
+		field.Uint64("sub_source_id").Default(1).Optional().
 			Annotations(entsql.WithComments(true)).
 			Comment("次源 ID"),
 	}
@@ -67,7 +68,20 @@ func (MessageRecords) Indexes() []ent.Index {
 }
 
 func (MessageRecords) Edges() []ent.Edge {
-	return nil
+	return []ent.Edge{
+		edge.From("sop_stage", SopStage.Type).
+			Ref("stage_messages").
+			Unique().
+			Field("source_id"),
+		edge.From("sop_node", SopNode.Type).
+			Ref("node_messages").
+			Unique().
+			Field("sub_source_id"),
+		edge.From("message_contact", Contact.Type).
+			Ref("contact_messages").
+			Unique().
+			Field("contact_id"),
+	}
 }
 
 func (MessageRecords) Annotations() []schema.Annotation {

+ 2 - 1
ent/schema/sop_node.go

@@ -36,7 +36,7 @@ func (SopNode) Fields() []ent.Field {
 		field.JSON("action_message", []custom_types.Action{}).Optional().
 			Annotations(entsql.WithComments(true)).
 			Comment("命中后发送的消息内容"),
-		field.JSON("action_label", []int{}).Optional().
+		field.JSON("action_label", []uint64{}).Optional().
 			Annotations(entsql.WithComments(true)).
 			Comment("命中后需要打的标签"),
 	}
@@ -63,6 +63,7 @@ func (SopNode) Edges() []ent.Edge {
 			Unique().
 			Field("stage_id").
 			Required(),
+		edge.To("node_messages", MessageRecords.Type),
 	}
 }
 

+ 2 - 1
ent/schema/sop_stage.go

@@ -36,7 +36,7 @@ func (SopStage) Fields() []ent.Field {
 		field.JSON("action_message", []custom_types.Action{}).Optional().
 			Annotations(entsql.WithComments(true)).
 			Comment("命中后发送的消息内容"),
-		field.JSON("action_label", []int{}).Optional().
+		field.JSON("action_label", []uint64{}).Optional().
 			Annotations(entsql.WithComments(true)).
 			Comment("命中后需要打的标签"),
 		field.Int("index_sort").Default(1).Optional().
@@ -67,6 +67,7 @@ func (SopStage) Edges() []ent.Edge {
 			Field("task_id").
 			Required(),
 		edge.To("stage_nodes", SopNode.Type),
+		edge.To("stage_messages", MessageRecords.Type),
 	}
 }
 func (SopStage) Annotations() []schema.Annotation {

+ 15 - 15
ent/set_not_nil.go

@@ -920,7 +920,7 @@ func (mr *MessageRecordsCreate) SetNotNilBotWxid(value *string) *MessageRecordsC
 }
 
 // set field if value's pointer is not nil.
-func (mr *MessageRecordsUpdate) SetNotNilContactID(value *int) *MessageRecordsUpdate {
+func (mr *MessageRecordsUpdate) SetNotNilContactID(value *uint64) *MessageRecordsUpdate {
 	if value != nil {
 		return mr.SetContactID(*value)
 	}
@@ -928,7 +928,7 @@ func (mr *MessageRecordsUpdate) SetNotNilContactID(value *int) *MessageRecordsUp
 }
 
 // set field if value's pointer is not nil.
-func (mr *MessageRecordsUpdateOne) SetNotNilContactID(value *int) *MessageRecordsUpdateOne {
+func (mr *MessageRecordsUpdateOne) SetNotNilContactID(value *uint64) *MessageRecordsUpdateOne {
 	if value != nil {
 		return mr.SetContactID(*value)
 	}
@@ -936,7 +936,7 @@ func (mr *MessageRecordsUpdateOne) SetNotNilContactID(value *int) *MessageRecord
 }
 
 // set field if value's pointer is not nil.
-func (mr *MessageRecordsCreate) SetNotNilContactID(value *int) *MessageRecordsCreate {
+func (mr *MessageRecordsCreate) SetNotNilContactID(value *uint64) *MessageRecordsCreate {
 	if value != nil {
 		return mr.SetContactID(*value)
 	}
@@ -1112,7 +1112,7 @@ func (mr *MessageRecordsCreate) SetNotNilSourceType(value *int) *MessageRecordsC
 }
 
 // set field if value's pointer is not nil.
-func (mr *MessageRecordsUpdate) SetNotNilSourceID(value *int) *MessageRecordsUpdate {
+func (mr *MessageRecordsUpdate) SetNotNilSourceID(value *uint64) *MessageRecordsUpdate {
 	if value != nil {
 		return mr.SetSourceID(*value)
 	}
@@ -1120,7 +1120,7 @@ func (mr *MessageRecordsUpdate) SetNotNilSourceID(value *int) *MessageRecordsUpd
 }
 
 // set field if value's pointer is not nil.
-func (mr *MessageRecordsUpdateOne) SetNotNilSourceID(value *int) *MessageRecordsUpdateOne {
+func (mr *MessageRecordsUpdateOne) SetNotNilSourceID(value *uint64) *MessageRecordsUpdateOne {
 	if value != nil {
 		return mr.SetSourceID(*value)
 	}
@@ -1128,7 +1128,7 @@ func (mr *MessageRecordsUpdateOne) SetNotNilSourceID(value *int) *MessageRecords
 }
 
 // set field if value's pointer is not nil.
-func (mr *MessageRecordsCreate) SetNotNilSourceID(value *int) *MessageRecordsCreate {
+func (mr *MessageRecordsCreate) SetNotNilSourceID(value *uint64) *MessageRecordsCreate {
 	if value != nil {
 		return mr.SetSourceID(*value)
 	}
@@ -1136,7 +1136,7 @@ func (mr *MessageRecordsCreate) SetNotNilSourceID(value *int) *MessageRecordsCre
 }
 
 // set field if value's pointer is not nil.
-func (mr *MessageRecordsUpdate) SetNotNilSubSourceID(value *int) *MessageRecordsUpdate {
+func (mr *MessageRecordsUpdate) SetNotNilSubSourceID(value *uint64) *MessageRecordsUpdate {
 	if value != nil {
 		return mr.SetSubSourceID(*value)
 	}
@@ -1144,7 +1144,7 @@ func (mr *MessageRecordsUpdate) SetNotNilSubSourceID(value *int) *MessageRecords
 }
 
 // set field if value's pointer is not nil.
-func (mr *MessageRecordsUpdateOne) SetNotNilSubSourceID(value *int) *MessageRecordsUpdateOne {
+func (mr *MessageRecordsUpdateOne) SetNotNilSubSourceID(value *uint64) *MessageRecordsUpdateOne {
 	if value != nil {
 		return mr.SetSubSourceID(*value)
 	}
@@ -1152,7 +1152,7 @@ func (mr *MessageRecordsUpdateOne) SetNotNilSubSourceID(value *int) *MessageReco
 }
 
 // set field if value's pointer is not nil.
-func (mr *MessageRecordsCreate) SetNotNilSubSourceID(value *int) *MessageRecordsCreate {
+func (mr *MessageRecordsCreate) SetNotNilSubSourceID(value *uint64) *MessageRecordsCreate {
 	if value != nil {
 		return mr.SetSubSourceID(*value)
 	}
@@ -1544,7 +1544,7 @@ func (sn *SopNodeCreate) SetNotNilActionMessage(value []custom_types.Action) *So
 }
 
 // set field if value's pointer is not nil.
-func (sn *SopNodeUpdate) SetNotNilActionLabel(value []int) *SopNodeUpdate {
+func (sn *SopNodeUpdate) SetNotNilActionLabel(value []uint64) *SopNodeUpdate {
 	if value != nil {
 		return sn.SetActionLabel(value)
 	}
@@ -1552,7 +1552,7 @@ func (sn *SopNodeUpdate) SetNotNilActionLabel(value []int) *SopNodeUpdate {
 }
 
 // set field if value's pointer is not nil.
-func (sn *SopNodeUpdateOne) SetNotNilActionLabel(value []int) *SopNodeUpdateOne {
+func (sn *SopNodeUpdateOne) SetNotNilActionLabel(value []uint64) *SopNodeUpdateOne {
 	if value != nil {
 		return sn.SetActionLabel(value)
 	}
@@ -1560,7 +1560,7 @@ func (sn *SopNodeUpdateOne) SetNotNilActionLabel(value []int) *SopNodeUpdateOne
 }
 
 // set field if value's pointer is not nil.
-func (sn *SopNodeCreate) SetNotNilActionLabel(value []int) *SopNodeCreate {
+func (sn *SopNodeCreate) SetNotNilActionLabel(value []uint64) *SopNodeCreate {
 	if value != nil {
 		return sn.SetActionLabel(value)
 	}
@@ -1784,7 +1784,7 @@ func (ss *SopStageCreate) SetNotNilActionMessage(value []custom_types.Action) *S
 }
 
 // set field if value's pointer is not nil.
-func (ss *SopStageUpdate) SetNotNilActionLabel(value []int) *SopStageUpdate {
+func (ss *SopStageUpdate) SetNotNilActionLabel(value []uint64) *SopStageUpdate {
 	if value != nil {
 		return ss.SetActionLabel(value)
 	}
@@ -1792,7 +1792,7 @@ func (ss *SopStageUpdate) SetNotNilActionLabel(value []int) *SopStageUpdate {
 }
 
 // set field if value's pointer is not nil.
-func (ss *SopStageUpdateOne) SetNotNilActionLabel(value []int) *SopStageUpdateOne {
+func (ss *SopStageUpdateOne) SetNotNilActionLabel(value []uint64) *SopStageUpdateOne {
 	if value != nil {
 		return ss.SetActionLabel(value)
 	}
@@ -1800,7 +1800,7 @@ func (ss *SopStageUpdateOne) SetNotNilActionLabel(value []int) *SopStageUpdateOn
 }
 
 // set field if value's pointer is not nil.
-func (ss *SopStageCreate) SetNotNilActionLabel(value []int) *SopStageCreate {
+func (ss *SopStageCreate) SetNotNilActionLabel(value []uint64) *SopStageCreate {
 	if value != nil {
 		return ss.SetActionLabel(value)
 	}

+ 18 - 2
ent/sopnode.go

@@ -41,7 +41,7 @@ type SopNode struct {
 	// 命中后发送的消息内容
 	ActionMessage []custom_types.Action `json:"action_message,omitempty"`
 	// 命中后需要打的标签
-	ActionLabel []int `json:"action_label,omitempty"`
+	ActionLabel []uint64 `json:"action_label,omitempty"`
 	// Edges holds the relations/edges for other nodes in the graph.
 	// The values are being populated by the SopNodeQuery when eager-loading is set.
 	Edges        SopNodeEdges `json:"edges"`
@@ -52,9 +52,11 @@ type SopNode struct {
 type SopNodeEdges struct {
 	// SopStage holds the value of the sop_stage edge.
 	SopStage *SopStage `json:"sop_stage,omitempty"`
+	// NodeMessages holds the value of the node_messages edge.
+	NodeMessages []*MessageRecords `json:"node_messages,omitempty"`
 	// loadedTypes holds the information for reporting if a
 	// type was loaded (or requested) in eager-loading or not.
-	loadedTypes [1]bool
+	loadedTypes [2]bool
 }
 
 // SopStageOrErr returns the SopStage value or an error if the edge
@@ -68,6 +70,15 @@ func (e SopNodeEdges) SopStageOrErr() (*SopStage, error) {
 	return nil, &NotLoadedError{edge: "sop_stage"}
 }
 
+// NodeMessagesOrErr returns the NodeMessages value or an error if the edge
+// was not loaded in eager-loading.
+func (e SopNodeEdges) NodeMessagesOrErr() ([]*MessageRecords, error) {
+	if e.loadedTypes[1] {
+		return e.NodeMessages, nil
+	}
+	return nil, &NotLoadedError{edge: "node_messages"}
+}
+
 // scanValues returns the types for scanning values from sql.Rows.
 func (*SopNode) scanValues(columns []string) ([]any, error) {
 	values := make([]any, len(columns))
@@ -192,6 +203,11 @@ func (sn *SopNode) QuerySopStage() *SopStageQuery {
 	return NewSopNodeClient(sn.config).QuerySopStage(sn)
 }
 
+// QueryNodeMessages queries the "node_messages" edge of the SopNode entity.
+func (sn *SopNode) QueryNodeMessages() *MessageRecordsQuery {
+	return NewSopNodeClient(sn.config).QueryNodeMessages(sn)
+}
+
 // Update returns a builder for updating this SopNode.
 // Note that you need to call SopNode.Unwrap() before calling this method if this SopNode
 // was returned from a transaction, and the transaction was committed or rolled back.

+ 30 - 0
ent/sopnode/sopnode.go

@@ -39,6 +39,8 @@ const (
 	FieldActionLabel = "action_label"
 	// EdgeSopStage holds the string denoting the sop_stage edge name in mutations.
 	EdgeSopStage = "sop_stage"
+	// EdgeNodeMessages holds the string denoting the node_messages edge name in mutations.
+	EdgeNodeMessages = "node_messages"
 	// Table holds the table name of the sopnode in the database.
 	Table = "sop_node"
 	// SopStageTable is the table that holds the sop_stage relation/edge.
@@ -48,6 +50,13 @@ const (
 	SopStageInverseTable = "sop_stage"
 	// SopStageColumn is the table column denoting the sop_stage relation/edge.
 	SopStageColumn = "stage_id"
+	// NodeMessagesTable is the table that holds the node_messages relation/edge.
+	NodeMessagesTable = "message_records"
+	// NodeMessagesInverseTable is the table name for the MessageRecords entity.
+	// It exists in this package in order to avoid circular dependency with the "messagerecords" package.
+	NodeMessagesInverseTable = "message_records"
+	// NodeMessagesColumn is the table column denoting the node_messages relation/edge.
+	NodeMessagesColumn = "sub_source_id"
 )
 
 // Columns holds all SQL columns for sopnode fields.
@@ -152,6 +161,20 @@ func BySopStageField(field string, opts ...sql.OrderTermOption) OrderOption {
 		sqlgraph.OrderByNeighborTerms(s, newSopStageStep(), sql.OrderByField(field, opts...))
 	}
 }
+
+// ByNodeMessagesCount orders the results by node_messages count.
+func ByNodeMessagesCount(opts ...sql.OrderTermOption) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborsCount(s, newNodeMessagesStep(), opts...)
+	}
+}
+
+// ByNodeMessages orders the results by node_messages terms.
+func ByNodeMessages(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborTerms(s, newNodeMessagesStep(), append([]sql.OrderTerm{term}, terms...)...)
+	}
+}
 func newSopStageStep() *sqlgraph.Step {
 	return sqlgraph.NewStep(
 		sqlgraph.From(Table, FieldID),
@@ -159,3 +182,10 @@ func newSopStageStep() *sqlgraph.Step {
 		sqlgraph.Edge(sqlgraph.M2O, true, SopStageTable, SopStageColumn),
 	)
 }
+func newNodeMessagesStep() *sqlgraph.Step {
+	return sqlgraph.NewStep(
+		sqlgraph.From(Table, FieldID),
+		sqlgraph.To(NodeMessagesInverseTable, FieldID),
+		sqlgraph.Edge(sqlgraph.O2M, false, NodeMessagesTable, NodeMessagesColumn),
+	)
+}

+ 23 - 0
ent/sopnode/where.go

@@ -493,6 +493,29 @@ func HasSopStageWith(preds ...predicate.SopStage) predicate.SopNode {
 	})
 }
 
+// HasNodeMessages applies the HasEdge predicate on the "node_messages" edge.
+func HasNodeMessages() predicate.SopNode {
+	return predicate.SopNode(func(s *sql.Selector) {
+		step := sqlgraph.NewStep(
+			sqlgraph.From(Table, FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, NodeMessagesTable, NodeMessagesColumn),
+		)
+		sqlgraph.HasNeighbors(s, step)
+	})
+}
+
+// HasNodeMessagesWith applies the HasEdge predicate on the "node_messages" edge with a given conditions (other predicates).
+func HasNodeMessagesWith(preds ...predicate.MessageRecords) predicate.SopNode {
+	return predicate.SopNode(func(s *sql.Selector) {
+		step := newNodeMessagesStep()
+		sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
+			for _, p := range preds {
+				p(s)
+			}
+		})
+	})
+}
+
 // And groups predicates with the AND operator between them.
 func And(predicates ...predicate.SopNode) predicate.SopNode {
 	return predicate.SopNode(sql.AndPredicates(predicates...))

+ 37 - 5
ent/sopnode_create.go

@@ -8,6 +8,7 @@ import (
 	"fmt"
 	"time"
 	"wechat-api/ent/custom_types"
+	"wechat-api/ent/messagerecords"
 	"wechat-api/ent/sopnode"
 	"wechat-api/ent/sopstage"
 
@@ -133,8 +134,8 @@ func (snc *SopNodeCreate) SetActionMessage(ct []custom_types.Action) *SopNodeCre
 }
 
 // SetActionLabel sets the "action_label" field.
-func (snc *SopNodeCreate) SetActionLabel(i []int) *SopNodeCreate {
-	snc.mutation.SetActionLabel(i)
+func (snc *SopNodeCreate) SetActionLabel(u []uint64) *SopNodeCreate {
+	snc.mutation.SetActionLabel(u)
 	return snc
 }
 
@@ -155,6 +156,21 @@ func (snc *SopNodeCreate) SetSopStage(s *SopStage) *SopNodeCreate {
 	return snc.SetSopStageID(s.ID)
 }
 
+// AddNodeMessageIDs adds the "node_messages" edge to the MessageRecords entity by IDs.
+func (snc *SopNodeCreate) AddNodeMessageIDs(ids ...uint64) *SopNodeCreate {
+	snc.mutation.AddNodeMessageIDs(ids...)
+	return snc
+}
+
+// AddNodeMessages adds the "node_messages" edges to the MessageRecords entity.
+func (snc *SopNodeCreate) AddNodeMessages(m ...*MessageRecords) *SopNodeCreate {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return snc.AddNodeMessageIDs(ids...)
+}
+
 // Mutation returns the SopNodeMutation object of the builder.
 func (snc *SopNodeCreate) Mutation() *SopNodeMutation {
 	return snc.mutation
@@ -334,6 +350,22 @@ func (snc *SopNodeCreate) createSpec() (*SopNode, *sqlgraph.CreateSpec) {
 		_node.StageID = nodes[0]
 		_spec.Edges = append(_spec.Edges, edge)
 	}
+	if nodes := snc.mutation.NodeMessagesIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopnode.NodeMessagesTable,
+			Columns: []string{sopnode.NodeMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges = append(_spec.Edges, edge)
+	}
 	return _node, _spec
 }
 
@@ -537,7 +569,7 @@ func (u *SopNodeUpsert) ClearActionMessage() *SopNodeUpsert {
 }
 
 // SetActionLabel sets the "action_label" field.
-func (u *SopNodeUpsert) SetActionLabel(v []int) *SopNodeUpsert {
+func (u *SopNodeUpsert) SetActionLabel(v []uint64) *SopNodeUpsert {
 	u.Set(sopnode.FieldActionLabel, v)
 	return u
 }
@@ -781,7 +813,7 @@ func (u *SopNodeUpsertOne) ClearActionMessage() *SopNodeUpsertOne {
 }
 
 // SetActionLabel sets the "action_label" field.
-func (u *SopNodeUpsertOne) SetActionLabel(v []int) *SopNodeUpsertOne {
+func (u *SopNodeUpsertOne) SetActionLabel(v []uint64) *SopNodeUpsertOne {
 	return u.Update(func(s *SopNodeUpsert) {
 		s.SetActionLabel(v)
 	})
@@ -1194,7 +1226,7 @@ func (u *SopNodeUpsertBulk) ClearActionMessage() *SopNodeUpsertBulk {
 }
 
 // SetActionLabel sets the "action_label" field.
-func (u *SopNodeUpsertBulk) SetActionLabel(v []int) *SopNodeUpsertBulk {
+func (u *SopNodeUpsertBulk) SetActionLabel(v []uint64) *SopNodeUpsertBulk {
 	return u.Update(func(s *SopNodeUpsert) {
 		s.SetActionLabel(v)
 	})

+ 87 - 12
ent/sopnode_query.go

@@ -4,8 +4,10 @@ package ent
 
 import (
 	"context"
+	"database/sql/driver"
 	"fmt"
 	"math"
+	"wechat-api/ent/messagerecords"
 	"wechat-api/ent/predicate"
 	"wechat-api/ent/sopnode"
 	"wechat-api/ent/sopstage"
@@ -18,11 +20,12 @@ import (
 // SopNodeQuery is the builder for querying SopNode entities.
 type SopNodeQuery struct {
 	config
-	ctx          *QueryContext
-	order        []sopnode.OrderOption
-	inters       []Interceptor
-	predicates   []predicate.SopNode
-	withSopStage *SopStageQuery
+	ctx              *QueryContext
+	order            []sopnode.OrderOption
+	inters           []Interceptor
+	predicates       []predicate.SopNode
+	withSopStage     *SopStageQuery
+	withNodeMessages *MessageRecordsQuery
 	// intermediate query (i.e. traversal path).
 	sql  *sql.Selector
 	path func(context.Context) (*sql.Selector, error)
@@ -81,6 +84,28 @@ func (snq *SopNodeQuery) QuerySopStage() *SopStageQuery {
 	return query
 }
 
+// QueryNodeMessages chains the current query on the "node_messages" edge.
+func (snq *SopNodeQuery) QueryNodeMessages() *MessageRecordsQuery {
+	query := (&MessageRecordsClient{config: snq.config}).Query()
+	query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
+		if err := snq.prepareQuery(ctx); err != nil {
+			return nil, err
+		}
+		selector := snq.sqlQuery(ctx)
+		if err := selector.Err(); err != nil {
+			return nil, err
+		}
+		step := sqlgraph.NewStep(
+			sqlgraph.From(sopnode.Table, sopnode.FieldID, selector),
+			sqlgraph.To(messagerecords.Table, messagerecords.FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, sopnode.NodeMessagesTable, sopnode.NodeMessagesColumn),
+		)
+		fromU = sqlgraph.SetNeighbors(snq.driver.Dialect(), step)
+		return fromU, nil
+	}
+	return query
+}
+
 // First returns the first SopNode entity from the query.
 // Returns a *NotFoundError when no SopNode was found.
 func (snq *SopNodeQuery) First(ctx context.Context) (*SopNode, error) {
@@ -268,12 +293,13 @@ func (snq *SopNodeQuery) Clone() *SopNodeQuery {
 		return nil
 	}
 	return &SopNodeQuery{
-		config:       snq.config,
-		ctx:          snq.ctx.Clone(),
-		order:        append([]sopnode.OrderOption{}, snq.order...),
-		inters:       append([]Interceptor{}, snq.inters...),
-		predicates:   append([]predicate.SopNode{}, snq.predicates...),
-		withSopStage: snq.withSopStage.Clone(),
+		config:           snq.config,
+		ctx:              snq.ctx.Clone(),
+		order:            append([]sopnode.OrderOption{}, snq.order...),
+		inters:           append([]Interceptor{}, snq.inters...),
+		predicates:       append([]predicate.SopNode{}, snq.predicates...),
+		withSopStage:     snq.withSopStage.Clone(),
+		withNodeMessages: snq.withNodeMessages.Clone(),
 		// clone intermediate query.
 		sql:  snq.sql.Clone(),
 		path: snq.path,
@@ -291,6 +317,17 @@ func (snq *SopNodeQuery) WithSopStage(opts ...func(*SopStageQuery)) *SopNodeQuer
 	return snq
 }
 
+// WithNodeMessages tells the query-builder to eager-load the nodes that are connected to
+// the "node_messages" edge. The optional arguments are used to configure the query builder of the edge.
+func (snq *SopNodeQuery) WithNodeMessages(opts ...func(*MessageRecordsQuery)) *SopNodeQuery {
+	query := (&MessageRecordsClient{config: snq.config}).Query()
+	for _, opt := range opts {
+		opt(query)
+	}
+	snq.withNodeMessages = query
+	return snq
+}
+
 // GroupBy is used to group vertices by one or more fields/columns.
 // It is often used with aggregate functions, like: count, max, mean, min, sum.
 //
@@ -369,8 +406,9 @@ func (snq *SopNodeQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Sop
 	var (
 		nodes       = []*SopNode{}
 		_spec       = snq.querySpec()
-		loadedTypes = [1]bool{
+		loadedTypes = [2]bool{
 			snq.withSopStage != nil,
+			snq.withNodeMessages != nil,
 		}
 	)
 	_spec.ScanValues = func(columns []string) ([]any, error) {
@@ -397,6 +435,13 @@ func (snq *SopNodeQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Sop
 			return nil, err
 		}
 	}
+	if query := snq.withNodeMessages; query != nil {
+		if err := snq.loadNodeMessages(ctx, query, nodes,
+			func(n *SopNode) { n.Edges.NodeMessages = []*MessageRecords{} },
+			func(n *SopNode, e *MessageRecords) { n.Edges.NodeMessages = append(n.Edges.NodeMessages, e) }); err != nil {
+			return nil, err
+		}
+	}
 	return nodes, nil
 }
 
@@ -429,6 +474,36 @@ func (snq *SopNodeQuery) loadSopStage(ctx context.Context, query *SopStageQuery,
 	}
 	return nil
 }
+func (snq *SopNodeQuery) loadNodeMessages(ctx context.Context, query *MessageRecordsQuery, nodes []*SopNode, init func(*SopNode), assign func(*SopNode, *MessageRecords)) error {
+	fks := make([]driver.Value, 0, len(nodes))
+	nodeids := make(map[uint64]*SopNode)
+	for i := range nodes {
+		fks = append(fks, nodes[i].ID)
+		nodeids[nodes[i].ID] = nodes[i]
+		if init != nil {
+			init(nodes[i])
+		}
+	}
+	if len(query.ctx.Fields) > 0 {
+		query.ctx.AppendFieldOnce(messagerecords.FieldSubSourceID)
+	}
+	query.Where(predicate.MessageRecords(func(s *sql.Selector) {
+		s.Where(sql.InValues(s.C(sopnode.NodeMessagesColumn), fks...))
+	}))
+	neighbors, err := query.All(ctx)
+	if err != nil {
+		return err
+	}
+	for _, n := range neighbors {
+		fk := n.SubSourceID
+		node, ok := nodeids[fk]
+		if !ok {
+			return fmt.Errorf(`unexpected referenced foreign-key "sub_source_id" returned %v for node %v`, fk, n.ID)
+		}
+		assign(node, n)
+	}
+	return nil
+}
 
 func (snq *SopNodeQuery) sqlCount(ctx context.Context) (int, error) {
 	_spec := snq.querySpec()

+ 173 - 10
ent/sopnode_update.go

@@ -8,6 +8,7 @@ import (
 	"fmt"
 	"time"
 	"wechat-api/ent/custom_types"
+	"wechat-api/ent/messagerecords"
 	"wechat-api/ent/predicate"
 	"wechat-api/ent/sopnode"
 	"wechat-api/ent/sopstage"
@@ -191,14 +192,14 @@ func (snu *SopNodeUpdate) ClearActionMessage() *SopNodeUpdate {
 }
 
 // SetActionLabel sets the "action_label" field.
-func (snu *SopNodeUpdate) SetActionLabel(i []int) *SopNodeUpdate {
-	snu.mutation.SetActionLabel(i)
+func (snu *SopNodeUpdate) SetActionLabel(u []uint64) *SopNodeUpdate {
+	snu.mutation.SetActionLabel(u)
 	return snu
 }
 
-// AppendActionLabel appends i to the "action_label" field.
-func (snu *SopNodeUpdate) AppendActionLabel(i []int) *SopNodeUpdate {
-	snu.mutation.AppendActionLabel(i)
+// AppendActionLabel appends u to the "action_label" field.
+func (snu *SopNodeUpdate) AppendActionLabel(u []uint64) *SopNodeUpdate {
+	snu.mutation.AppendActionLabel(u)
 	return snu
 }
 
@@ -219,6 +220,21 @@ func (snu *SopNodeUpdate) SetSopStage(s *SopStage) *SopNodeUpdate {
 	return snu.SetSopStageID(s.ID)
 }
 
+// AddNodeMessageIDs adds the "node_messages" edge to the MessageRecords entity by IDs.
+func (snu *SopNodeUpdate) AddNodeMessageIDs(ids ...uint64) *SopNodeUpdate {
+	snu.mutation.AddNodeMessageIDs(ids...)
+	return snu
+}
+
+// AddNodeMessages adds the "node_messages" edges to the MessageRecords entity.
+func (snu *SopNodeUpdate) AddNodeMessages(m ...*MessageRecords) *SopNodeUpdate {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return snu.AddNodeMessageIDs(ids...)
+}
+
 // Mutation returns the SopNodeMutation object of the builder.
 func (snu *SopNodeUpdate) Mutation() *SopNodeMutation {
 	return snu.mutation
@@ -230,6 +246,27 @@ func (snu *SopNodeUpdate) ClearSopStage() *SopNodeUpdate {
 	return snu
 }
 
+// ClearNodeMessages clears all "node_messages" edges to the MessageRecords entity.
+func (snu *SopNodeUpdate) ClearNodeMessages() *SopNodeUpdate {
+	snu.mutation.ClearNodeMessages()
+	return snu
+}
+
+// RemoveNodeMessageIDs removes the "node_messages" edge to MessageRecords entities by IDs.
+func (snu *SopNodeUpdate) RemoveNodeMessageIDs(ids ...uint64) *SopNodeUpdate {
+	snu.mutation.RemoveNodeMessageIDs(ids...)
+	return snu
+}
+
+// RemoveNodeMessages removes "node_messages" edges to MessageRecords entities.
+func (snu *SopNodeUpdate) RemoveNodeMessages(m ...*MessageRecords) *SopNodeUpdate {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return snu.RemoveNodeMessageIDs(ids...)
+}
+
 // Save executes the query and returns the number of nodes affected by the update operation.
 func (snu *SopNodeUpdate) Save(ctx context.Context) (int, error) {
 	if err := snu.defaults(); err != nil {
@@ -387,6 +424,51 @@ func (snu *SopNodeUpdate) sqlSave(ctx context.Context) (n int, err error) {
 		}
 		_spec.Edges.Add = append(_spec.Edges.Add, edge)
 	}
+	if snu.mutation.NodeMessagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopnode.NodeMessagesTable,
+			Columns: []string{sopnode.NodeMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := snu.mutation.RemovedNodeMessagesIDs(); len(nodes) > 0 && !snu.mutation.NodeMessagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopnode.NodeMessagesTable,
+			Columns: []string{sopnode.NodeMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := snu.mutation.NodeMessagesIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopnode.NodeMessagesTable,
+			Columns: []string{sopnode.NodeMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
 	if n, err = sqlgraph.UpdateNodes(ctx, snu.driver, _spec); err != nil {
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{sopnode.Label}
@@ -567,14 +649,14 @@ func (snuo *SopNodeUpdateOne) ClearActionMessage() *SopNodeUpdateOne {
 }
 
 // SetActionLabel sets the "action_label" field.
-func (snuo *SopNodeUpdateOne) SetActionLabel(i []int) *SopNodeUpdateOne {
-	snuo.mutation.SetActionLabel(i)
+func (snuo *SopNodeUpdateOne) SetActionLabel(u []uint64) *SopNodeUpdateOne {
+	snuo.mutation.SetActionLabel(u)
 	return snuo
 }
 
-// AppendActionLabel appends i to the "action_label" field.
-func (snuo *SopNodeUpdateOne) AppendActionLabel(i []int) *SopNodeUpdateOne {
-	snuo.mutation.AppendActionLabel(i)
+// AppendActionLabel appends u to the "action_label" field.
+func (snuo *SopNodeUpdateOne) AppendActionLabel(u []uint64) *SopNodeUpdateOne {
+	snuo.mutation.AppendActionLabel(u)
 	return snuo
 }
 
@@ -595,6 +677,21 @@ func (snuo *SopNodeUpdateOne) SetSopStage(s *SopStage) *SopNodeUpdateOne {
 	return snuo.SetSopStageID(s.ID)
 }
 
+// AddNodeMessageIDs adds the "node_messages" edge to the MessageRecords entity by IDs.
+func (snuo *SopNodeUpdateOne) AddNodeMessageIDs(ids ...uint64) *SopNodeUpdateOne {
+	snuo.mutation.AddNodeMessageIDs(ids...)
+	return snuo
+}
+
+// AddNodeMessages adds the "node_messages" edges to the MessageRecords entity.
+func (snuo *SopNodeUpdateOne) AddNodeMessages(m ...*MessageRecords) *SopNodeUpdateOne {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return snuo.AddNodeMessageIDs(ids...)
+}
+
 // Mutation returns the SopNodeMutation object of the builder.
 func (snuo *SopNodeUpdateOne) Mutation() *SopNodeMutation {
 	return snuo.mutation
@@ -606,6 +703,27 @@ func (snuo *SopNodeUpdateOne) ClearSopStage() *SopNodeUpdateOne {
 	return snuo
 }
 
+// ClearNodeMessages clears all "node_messages" edges to the MessageRecords entity.
+func (snuo *SopNodeUpdateOne) ClearNodeMessages() *SopNodeUpdateOne {
+	snuo.mutation.ClearNodeMessages()
+	return snuo
+}
+
+// RemoveNodeMessageIDs removes the "node_messages" edge to MessageRecords entities by IDs.
+func (snuo *SopNodeUpdateOne) RemoveNodeMessageIDs(ids ...uint64) *SopNodeUpdateOne {
+	snuo.mutation.RemoveNodeMessageIDs(ids...)
+	return snuo
+}
+
+// RemoveNodeMessages removes "node_messages" edges to MessageRecords entities.
+func (snuo *SopNodeUpdateOne) RemoveNodeMessages(m ...*MessageRecords) *SopNodeUpdateOne {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return snuo.RemoveNodeMessageIDs(ids...)
+}
+
 // Where appends a list predicates to the SopNodeUpdate builder.
 func (snuo *SopNodeUpdateOne) Where(ps ...predicate.SopNode) *SopNodeUpdateOne {
 	snuo.mutation.Where(ps...)
@@ -793,6 +911,51 @@ func (snuo *SopNodeUpdateOne) sqlSave(ctx context.Context) (_node *SopNode, err
 		}
 		_spec.Edges.Add = append(_spec.Edges.Add, edge)
 	}
+	if snuo.mutation.NodeMessagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopnode.NodeMessagesTable,
+			Columns: []string{sopnode.NodeMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := snuo.mutation.RemovedNodeMessagesIDs(); len(nodes) > 0 && !snuo.mutation.NodeMessagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopnode.NodeMessagesTable,
+			Columns: []string{sopnode.NodeMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := snuo.mutation.NodeMessagesIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopnode.NodeMessagesTable,
+			Columns: []string{sopnode.NodeMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
 	_node = &SopNode{config: snuo.config}
 	_spec.Assign = _node.assignValues
 	_spec.ScanValues = _node.scanValues

+ 18 - 2
ent/sopstage.go

@@ -41,7 +41,7 @@ type SopStage struct {
 	// 命中后发送的消息内容
 	ActionMessage []custom_types.Action `json:"action_message,omitempty"`
 	// 命中后需要打的标签
-	ActionLabel []int `json:"action_label,omitempty"`
+	ActionLabel []uint64 `json:"action_label,omitempty"`
 	// 阶段顺序
 	IndexSort int `json:"index_sort,omitempty"`
 	// Edges holds the relations/edges for other nodes in the graph.
@@ -56,9 +56,11 @@ type SopStageEdges struct {
 	SopTask *SopTask `json:"sop_task,omitempty"`
 	// StageNodes holds the value of the stage_nodes edge.
 	StageNodes []*SopNode `json:"stage_nodes,omitempty"`
+	// StageMessages holds the value of the stage_messages edge.
+	StageMessages []*MessageRecords `json:"stage_messages,omitempty"`
 	// loadedTypes holds the information for reporting if a
 	// type was loaded (or requested) in eager-loading or not.
-	loadedTypes [2]bool
+	loadedTypes [3]bool
 }
 
 // SopTaskOrErr returns the SopTask value or an error if the edge
@@ -81,6 +83,15 @@ func (e SopStageEdges) StageNodesOrErr() ([]*SopNode, error) {
 	return nil, &NotLoadedError{edge: "stage_nodes"}
 }
 
+// StageMessagesOrErr returns the StageMessages value or an error if the edge
+// was not loaded in eager-loading.
+func (e SopStageEdges) StageMessagesOrErr() ([]*MessageRecords, error) {
+	if e.loadedTypes[2] {
+		return e.StageMessages, nil
+	}
+	return nil, &NotLoadedError{edge: "stage_messages"}
+}
+
 // scanValues returns the types for scanning values from sql.Rows.
 func (*SopStage) scanValues(columns []string) ([]any, error) {
 	values := make([]any, len(columns))
@@ -216,6 +227,11 @@ func (ss *SopStage) QueryStageNodes() *SopNodeQuery {
 	return NewSopStageClient(ss.config).QueryStageNodes(ss)
 }
 
+// QueryStageMessages queries the "stage_messages" edge of the SopStage entity.
+func (ss *SopStage) QueryStageMessages() *MessageRecordsQuery {
+	return NewSopStageClient(ss.config).QueryStageMessages(ss)
+}
+
 // Update returns a builder for updating this SopStage.
 // Note that you need to call SopStage.Unwrap() before calling this method if this SopStage
 // was returned from a transaction, and the transaction was committed or rolled back.

+ 30 - 0
ent/sopstage/sopstage.go

@@ -43,6 +43,8 @@ const (
 	EdgeSopTask = "sop_task"
 	// EdgeStageNodes holds the string denoting the stage_nodes edge name in mutations.
 	EdgeStageNodes = "stage_nodes"
+	// EdgeStageMessages holds the string denoting the stage_messages edge name in mutations.
+	EdgeStageMessages = "stage_messages"
 	// Table holds the table name of the sopstage in the database.
 	Table = "sop_stage"
 	// SopTaskTable is the table that holds the sop_task relation/edge.
@@ -59,6 +61,13 @@ const (
 	StageNodesInverseTable = "sop_node"
 	// StageNodesColumn is the table column denoting the stage_nodes relation/edge.
 	StageNodesColumn = "stage_id"
+	// StageMessagesTable is the table that holds the stage_messages relation/edge.
+	StageMessagesTable = "message_records"
+	// StageMessagesInverseTable is the table name for the MessageRecords entity.
+	// It exists in this package in order to avoid circular dependency with the "messagerecords" package.
+	StageMessagesInverseTable = "message_records"
+	// StageMessagesColumn is the table column denoting the stage_messages relation/edge.
+	StageMessagesColumn = "source_id"
 )
 
 // Columns holds all SQL columns for sopstage fields.
@@ -187,6 +196,20 @@ func ByStageNodes(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
 		sqlgraph.OrderByNeighborTerms(s, newStageNodesStep(), append([]sql.OrderTerm{term}, terms...)...)
 	}
 }
+
+// ByStageMessagesCount orders the results by stage_messages count.
+func ByStageMessagesCount(opts ...sql.OrderTermOption) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborsCount(s, newStageMessagesStep(), opts...)
+	}
+}
+
+// ByStageMessages orders the results by stage_messages terms.
+func ByStageMessages(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborTerms(s, newStageMessagesStep(), append([]sql.OrderTerm{term}, terms...)...)
+	}
+}
 func newSopTaskStep() *sqlgraph.Step {
 	return sqlgraph.NewStep(
 		sqlgraph.From(Table, FieldID),
@@ -201,3 +224,10 @@ func newStageNodesStep() *sqlgraph.Step {
 		sqlgraph.Edge(sqlgraph.O2M, false, StageNodesTable, StageNodesColumn),
 	)
 }
+func newStageMessagesStep() *sqlgraph.Step {
+	return sqlgraph.NewStep(
+		sqlgraph.From(Table, FieldID),
+		sqlgraph.To(StageMessagesInverseTable, FieldID),
+		sqlgraph.Edge(sqlgraph.O2M, false, StageMessagesTable, StageMessagesColumn),
+	)
+}

+ 23 - 0
ent/sopstage/where.go

@@ -561,6 +561,29 @@ func HasStageNodesWith(preds ...predicate.SopNode) predicate.SopStage {
 	})
 }
 
+// HasStageMessages applies the HasEdge predicate on the "stage_messages" edge.
+func HasStageMessages() predicate.SopStage {
+	return predicate.SopStage(func(s *sql.Selector) {
+		step := sqlgraph.NewStep(
+			sqlgraph.From(Table, FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, StageMessagesTable, StageMessagesColumn),
+		)
+		sqlgraph.HasNeighbors(s, step)
+	})
+}
+
+// HasStageMessagesWith applies the HasEdge predicate on the "stage_messages" edge with a given conditions (other predicates).
+func HasStageMessagesWith(preds ...predicate.MessageRecords) predicate.SopStage {
+	return predicate.SopStage(func(s *sql.Selector) {
+		step := newStageMessagesStep()
+		sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
+			for _, p := range preds {
+				p(s)
+			}
+		})
+	})
+}
+
 // And groups predicates with the AND operator between them.
 func And(predicates ...predicate.SopStage) predicate.SopStage {
 	return predicate.SopStage(sql.AndPredicates(predicates...))

+ 37 - 5
ent/sopstage_create.go

@@ -8,6 +8,7 @@ import (
 	"fmt"
 	"time"
 	"wechat-api/ent/custom_types"
+	"wechat-api/ent/messagerecords"
 	"wechat-api/ent/sopnode"
 	"wechat-api/ent/sopstage"
 	"wechat-api/ent/soptask"
@@ -142,8 +143,8 @@ func (ssc *SopStageCreate) SetActionMessage(ct []custom_types.Action) *SopStageC
 }
 
 // SetActionLabel sets the "action_label" field.
-func (ssc *SopStageCreate) SetActionLabel(i []int) *SopStageCreate {
-	ssc.mutation.SetActionLabel(i)
+func (ssc *SopStageCreate) SetActionLabel(u []uint64) *SopStageCreate {
+	ssc.mutation.SetActionLabel(u)
 	return ssc
 }
 
@@ -193,6 +194,21 @@ func (ssc *SopStageCreate) AddStageNodes(s ...*SopNode) *SopStageCreate {
 	return ssc.AddStageNodeIDs(ids...)
 }
 
+// AddStageMessageIDs adds the "stage_messages" edge to the MessageRecords entity by IDs.
+func (ssc *SopStageCreate) AddStageMessageIDs(ids ...uint64) *SopStageCreate {
+	ssc.mutation.AddStageMessageIDs(ids...)
+	return ssc
+}
+
+// AddStageMessages adds the "stage_messages" edges to the MessageRecords entity.
+func (ssc *SopStageCreate) AddStageMessages(m ...*MessageRecords) *SopStageCreate {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return ssc.AddStageMessageIDs(ids...)
+}
+
 // Mutation returns the SopStageMutation object of the builder.
 func (ssc *SopStageCreate) Mutation() *SopStageMutation {
 	return ssc.mutation
@@ -403,6 +419,22 @@ func (ssc *SopStageCreate) createSpec() (*SopStage, *sqlgraph.CreateSpec) {
 		}
 		_spec.Edges = append(_spec.Edges, edge)
 	}
+	if nodes := ssc.mutation.StageMessagesIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopstage.StageMessagesTable,
+			Columns: []string{sopstage.StageMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges = append(_spec.Edges, edge)
+	}
 	return _node, _spec
 }
 
@@ -600,7 +632,7 @@ func (u *SopStageUpsert) ClearActionMessage() *SopStageUpsert {
 }
 
 // SetActionLabel sets the "action_label" field.
-func (u *SopStageUpsert) SetActionLabel(v []int) *SopStageUpsert {
+func (u *SopStageUpsert) SetActionLabel(v []uint64) *SopStageUpsert {
 	u.Set(sopstage.FieldActionLabel, v)
 	return u
 }
@@ -861,7 +893,7 @@ func (u *SopStageUpsertOne) ClearActionMessage() *SopStageUpsertOne {
 }
 
 // SetActionLabel sets the "action_label" field.
-func (u *SopStageUpsertOne) SetActionLabel(v []int) *SopStageUpsertOne {
+func (u *SopStageUpsertOne) SetActionLabel(v []uint64) *SopStageUpsertOne {
 	return u.Update(func(s *SopStageUpsert) {
 		s.SetActionLabel(v)
 	})
@@ -1295,7 +1327,7 @@ func (u *SopStageUpsertBulk) ClearActionMessage() *SopStageUpsertBulk {
 }
 
 // SetActionLabel sets the "action_label" field.
-func (u *SopStageUpsertBulk) SetActionLabel(v []int) *SopStageUpsertBulk {
+func (u *SopStageUpsertBulk) SetActionLabel(v []uint64) *SopStageUpsertBulk {
 	return u.Update(func(s *SopStageUpsert) {
 		s.SetActionLabel(v)
 	})

+ 88 - 14
ent/sopstage_query.go

@@ -7,6 +7,7 @@ import (
 	"database/sql/driver"
 	"fmt"
 	"math"
+	"wechat-api/ent/messagerecords"
 	"wechat-api/ent/predicate"
 	"wechat-api/ent/sopnode"
 	"wechat-api/ent/sopstage"
@@ -20,12 +21,13 @@ import (
 // SopStageQuery is the builder for querying SopStage entities.
 type SopStageQuery struct {
 	config
-	ctx            *QueryContext
-	order          []sopstage.OrderOption
-	inters         []Interceptor
-	predicates     []predicate.SopStage
-	withSopTask    *SopTaskQuery
-	withStageNodes *SopNodeQuery
+	ctx               *QueryContext
+	order             []sopstage.OrderOption
+	inters            []Interceptor
+	predicates        []predicate.SopStage
+	withSopTask       *SopTaskQuery
+	withStageNodes    *SopNodeQuery
+	withStageMessages *MessageRecordsQuery
 	// intermediate query (i.e. traversal path).
 	sql  *sql.Selector
 	path func(context.Context) (*sql.Selector, error)
@@ -106,6 +108,28 @@ func (ssq *SopStageQuery) QueryStageNodes() *SopNodeQuery {
 	return query
 }
 
+// QueryStageMessages chains the current query on the "stage_messages" edge.
+func (ssq *SopStageQuery) QueryStageMessages() *MessageRecordsQuery {
+	query := (&MessageRecordsClient{config: ssq.config}).Query()
+	query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
+		if err := ssq.prepareQuery(ctx); err != nil {
+			return nil, err
+		}
+		selector := ssq.sqlQuery(ctx)
+		if err := selector.Err(); err != nil {
+			return nil, err
+		}
+		step := sqlgraph.NewStep(
+			sqlgraph.From(sopstage.Table, sopstage.FieldID, selector),
+			sqlgraph.To(messagerecords.Table, messagerecords.FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, sopstage.StageMessagesTable, sopstage.StageMessagesColumn),
+		)
+		fromU = sqlgraph.SetNeighbors(ssq.driver.Dialect(), step)
+		return fromU, nil
+	}
+	return query
+}
+
 // First returns the first SopStage entity from the query.
 // Returns a *NotFoundError when no SopStage was found.
 func (ssq *SopStageQuery) First(ctx context.Context) (*SopStage, error) {
@@ -293,13 +317,14 @@ func (ssq *SopStageQuery) Clone() *SopStageQuery {
 		return nil
 	}
 	return &SopStageQuery{
-		config:         ssq.config,
-		ctx:            ssq.ctx.Clone(),
-		order:          append([]sopstage.OrderOption{}, ssq.order...),
-		inters:         append([]Interceptor{}, ssq.inters...),
-		predicates:     append([]predicate.SopStage{}, ssq.predicates...),
-		withSopTask:    ssq.withSopTask.Clone(),
-		withStageNodes: ssq.withStageNodes.Clone(),
+		config:            ssq.config,
+		ctx:               ssq.ctx.Clone(),
+		order:             append([]sopstage.OrderOption{}, ssq.order...),
+		inters:            append([]Interceptor{}, ssq.inters...),
+		predicates:        append([]predicate.SopStage{}, ssq.predicates...),
+		withSopTask:       ssq.withSopTask.Clone(),
+		withStageNodes:    ssq.withStageNodes.Clone(),
+		withStageMessages: ssq.withStageMessages.Clone(),
 		// clone intermediate query.
 		sql:  ssq.sql.Clone(),
 		path: ssq.path,
@@ -328,6 +353,17 @@ func (ssq *SopStageQuery) WithStageNodes(opts ...func(*SopNodeQuery)) *SopStageQ
 	return ssq
 }
 
+// WithStageMessages tells the query-builder to eager-load the nodes that are connected to
+// the "stage_messages" edge. The optional arguments are used to configure the query builder of the edge.
+func (ssq *SopStageQuery) WithStageMessages(opts ...func(*MessageRecordsQuery)) *SopStageQuery {
+	query := (&MessageRecordsClient{config: ssq.config}).Query()
+	for _, opt := range opts {
+		opt(query)
+	}
+	ssq.withStageMessages = query
+	return ssq
+}
+
 // GroupBy is used to group vertices by one or more fields/columns.
 // It is often used with aggregate functions, like: count, max, mean, min, sum.
 //
@@ -406,9 +442,10 @@ func (ssq *SopStageQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*So
 	var (
 		nodes       = []*SopStage{}
 		_spec       = ssq.querySpec()
-		loadedTypes = [2]bool{
+		loadedTypes = [3]bool{
 			ssq.withSopTask != nil,
 			ssq.withStageNodes != nil,
+			ssq.withStageMessages != nil,
 		}
 	)
 	_spec.ScanValues = func(columns []string) ([]any, error) {
@@ -442,6 +479,13 @@ func (ssq *SopStageQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*So
 			return nil, err
 		}
 	}
+	if query := ssq.withStageMessages; query != nil {
+		if err := ssq.loadStageMessages(ctx, query, nodes,
+			func(n *SopStage) { n.Edges.StageMessages = []*MessageRecords{} },
+			func(n *SopStage, e *MessageRecords) { n.Edges.StageMessages = append(n.Edges.StageMessages, e) }); err != nil {
+			return nil, err
+		}
+	}
 	return nodes, nil
 }
 
@@ -504,6 +548,36 @@ func (ssq *SopStageQuery) loadStageNodes(ctx context.Context, query *SopNodeQuer
 	}
 	return nil
 }
+func (ssq *SopStageQuery) loadStageMessages(ctx context.Context, query *MessageRecordsQuery, nodes []*SopStage, init func(*SopStage), assign func(*SopStage, *MessageRecords)) error {
+	fks := make([]driver.Value, 0, len(nodes))
+	nodeids := make(map[uint64]*SopStage)
+	for i := range nodes {
+		fks = append(fks, nodes[i].ID)
+		nodeids[nodes[i].ID] = nodes[i]
+		if init != nil {
+			init(nodes[i])
+		}
+	}
+	if len(query.ctx.Fields) > 0 {
+		query.ctx.AppendFieldOnce(messagerecords.FieldSourceID)
+	}
+	query.Where(predicate.MessageRecords(func(s *sql.Selector) {
+		s.Where(sql.InValues(s.C(sopstage.StageMessagesColumn), fks...))
+	}))
+	neighbors, err := query.All(ctx)
+	if err != nil {
+		return err
+	}
+	for _, n := range neighbors {
+		fk := n.SourceID
+		node, ok := nodeids[fk]
+		if !ok {
+			return fmt.Errorf(`unexpected referenced foreign-key "source_id" returned %v for node %v`, fk, n.ID)
+		}
+		assign(node, n)
+	}
+	return nil
+}
 
 func (ssq *SopStageQuery) sqlCount(ctx context.Context) (int, error) {
 	_spec := ssq.querySpec()

+ 173 - 10
ent/sopstage_update.go

@@ -8,6 +8,7 @@ import (
 	"fmt"
 	"time"
 	"wechat-api/ent/custom_types"
+	"wechat-api/ent/messagerecords"
 	"wechat-api/ent/predicate"
 	"wechat-api/ent/sopnode"
 	"wechat-api/ent/sopstage"
@@ -186,14 +187,14 @@ func (ssu *SopStageUpdate) ClearActionMessage() *SopStageUpdate {
 }
 
 // SetActionLabel sets the "action_label" field.
-func (ssu *SopStageUpdate) SetActionLabel(i []int) *SopStageUpdate {
-	ssu.mutation.SetActionLabel(i)
+func (ssu *SopStageUpdate) SetActionLabel(u []uint64) *SopStageUpdate {
+	ssu.mutation.SetActionLabel(u)
 	return ssu
 }
 
-// AppendActionLabel appends i to the "action_label" field.
-func (ssu *SopStageUpdate) AppendActionLabel(i []int) *SopStageUpdate {
-	ssu.mutation.AppendActionLabel(i)
+// AppendActionLabel appends u to the "action_label" field.
+func (ssu *SopStageUpdate) AppendActionLabel(u []uint64) *SopStageUpdate {
+	ssu.mutation.AppendActionLabel(u)
 	return ssu
 }
 
@@ -256,6 +257,21 @@ func (ssu *SopStageUpdate) AddStageNodes(s ...*SopNode) *SopStageUpdate {
 	return ssu.AddStageNodeIDs(ids...)
 }
 
+// AddStageMessageIDs adds the "stage_messages" edge to the MessageRecords entity by IDs.
+func (ssu *SopStageUpdate) AddStageMessageIDs(ids ...uint64) *SopStageUpdate {
+	ssu.mutation.AddStageMessageIDs(ids...)
+	return ssu
+}
+
+// AddStageMessages adds the "stage_messages" edges to the MessageRecords entity.
+func (ssu *SopStageUpdate) AddStageMessages(m ...*MessageRecords) *SopStageUpdate {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return ssu.AddStageMessageIDs(ids...)
+}
+
 // Mutation returns the SopStageMutation object of the builder.
 func (ssu *SopStageUpdate) Mutation() *SopStageMutation {
 	return ssu.mutation
@@ -288,6 +304,27 @@ func (ssu *SopStageUpdate) RemoveStageNodes(s ...*SopNode) *SopStageUpdate {
 	return ssu.RemoveStageNodeIDs(ids...)
 }
 
+// ClearStageMessages clears all "stage_messages" edges to the MessageRecords entity.
+func (ssu *SopStageUpdate) ClearStageMessages() *SopStageUpdate {
+	ssu.mutation.ClearStageMessages()
+	return ssu
+}
+
+// RemoveStageMessageIDs removes the "stage_messages" edge to MessageRecords entities by IDs.
+func (ssu *SopStageUpdate) RemoveStageMessageIDs(ids ...uint64) *SopStageUpdate {
+	ssu.mutation.RemoveStageMessageIDs(ids...)
+	return ssu
+}
+
+// RemoveStageMessages removes "stage_messages" edges to MessageRecords entities.
+func (ssu *SopStageUpdate) RemoveStageMessages(m ...*MessageRecords) *SopStageUpdate {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return ssu.RemoveStageMessageIDs(ids...)
+}
+
 // Save executes the query and returns the number of nodes affected by the update operation.
 func (ssu *SopStageUpdate) Save(ctx context.Context) (int, error) {
 	if err := ssu.defaults(); err != nil {
@@ -496,6 +533,51 @@ func (ssu *SopStageUpdate) sqlSave(ctx context.Context) (n int, err error) {
 		}
 		_spec.Edges.Add = append(_spec.Edges.Add, edge)
 	}
+	if ssu.mutation.StageMessagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopstage.StageMessagesTable,
+			Columns: []string{sopstage.StageMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := ssu.mutation.RemovedStageMessagesIDs(); len(nodes) > 0 && !ssu.mutation.StageMessagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopstage.StageMessagesTable,
+			Columns: []string{sopstage.StageMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := ssu.mutation.StageMessagesIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopstage.StageMessagesTable,
+			Columns: []string{sopstage.StageMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
 	if n, err = sqlgraph.UpdateNodes(ctx, ssu.driver, _spec); err != nil {
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{sopstage.Label}
@@ -670,14 +752,14 @@ func (ssuo *SopStageUpdateOne) ClearActionMessage() *SopStageUpdateOne {
 }
 
 // SetActionLabel sets the "action_label" field.
-func (ssuo *SopStageUpdateOne) SetActionLabel(i []int) *SopStageUpdateOne {
-	ssuo.mutation.SetActionLabel(i)
+func (ssuo *SopStageUpdateOne) SetActionLabel(u []uint64) *SopStageUpdateOne {
+	ssuo.mutation.SetActionLabel(u)
 	return ssuo
 }
 
-// AppendActionLabel appends i to the "action_label" field.
-func (ssuo *SopStageUpdateOne) AppendActionLabel(i []int) *SopStageUpdateOne {
-	ssuo.mutation.AppendActionLabel(i)
+// AppendActionLabel appends u to the "action_label" field.
+func (ssuo *SopStageUpdateOne) AppendActionLabel(u []uint64) *SopStageUpdateOne {
+	ssuo.mutation.AppendActionLabel(u)
 	return ssuo
 }
 
@@ -740,6 +822,21 @@ func (ssuo *SopStageUpdateOne) AddStageNodes(s ...*SopNode) *SopStageUpdateOne {
 	return ssuo.AddStageNodeIDs(ids...)
 }
 
+// AddStageMessageIDs adds the "stage_messages" edge to the MessageRecords entity by IDs.
+func (ssuo *SopStageUpdateOne) AddStageMessageIDs(ids ...uint64) *SopStageUpdateOne {
+	ssuo.mutation.AddStageMessageIDs(ids...)
+	return ssuo
+}
+
+// AddStageMessages adds the "stage_messages" edges to the MessageRecords entity.
+func (ssuo *SopStageUpdateOne) AddStageMessages(m ...*MessageRecords) *SopStageUpdateOne {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return ssuo.AddStageMessageIDs(ids...)
+}
+
 // Mutation returns the SopStageMutation object of the builder.
 func (ssuo *SopStageUpdateOne) Mutation() *SopStageMutation {
 	return ssuo.mutation
@@ -772,6 +869,27 @@ func (ssuo *SopStageUpdateOne) RemoveStageNodes(s ...*SopNode) *SopStageUpdateOn
 	return ssuo.RemoveStageNodeIDs(ids...)
 }
 
+// ClearStageMessages clears all "stage_messages" edges to the MessageRecords entity.
+func (ssuo *SopStageUpdateOne) ClearStageMessages() *SopStageUpdateOne {
+	ssuo.mutation.ClearStageMessages()
+	return ssuo
+}
+
+// RemoveStageMessageIDs removes the "stage_messages" edge to MessageRecords entities by IDs.
+func (ssuo *SopStageUpdateOne) RemoveStageMessageIDs(ids ...uint64) *SopStageUpdateOne {
+	ssuo.mutation.RemoveStageMessageIDs(ids...)
+	return ssuo
+}
+
+// RemoveStageMessages removes "stage_messages" edges to MessageRecords entities.
+func (ssuo *SopStageUpdateOne) RemoveStageMessages(m ...*MessageRecords) *SopStageUpdateOne {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return ssuo.RemoveStageMessageIDs(ids...)
+}
+
 // Where appends a list predicates to the SopStageUpdate builder.
 func (ssuo *SopStageUpdateOne) Where(ps ...predicate.SopStage) *SopStageUpdateOne {
 	ssuo.mutation.Where(ps...)
@@ -1010,6 +1128,51 @@ func (ssuo *SopStageUpdateOne) sqlSave(ctx context.Context) (_node *SopStage, er
 		}
 		_spec.Edges.Add = append(_spec.Edges.Add, edge)
 	}
+	if ssuo.mutation.StageMessagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopstage.StageMessagesTable,
+			Columns: []string{sopstage.StageMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := ssuo.mutation.RemovedStageMessagesIDs(); len(nodes) > 0 && !ssuo.mutation.StageMessagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopstage.StageMessagesTable,
+			Columns: []string{sopstage.StageMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := ssuo.mutation.StageMessagesIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopstage.StageMessagesTable,
+			Columns: []string{sopstage.StageMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
 	_node = &SopStage{config: ssuo.config}
 	_spec.Assign = _node.assignValues
 	_spec.ScanValues = _node.scanValues

+ 5 - 0
internal/handler/routes.go

@@ -324,6 +324,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
 					Path:    "/sop_task/detail",
 					Handler: sop_task.GetSopTaskDetailHandler(serverCtx),
 				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/sop_task/publish",
+					Handler: sop_task.PublishSopTaskHandler(serverCtx),
+				},
 			}...,
 		),
 		rest.WithJwt(serverCtx.Config.Auth.AccessSecret),

+ 44 - 0
internal/handler/sop_task/publish_sop_task_handler.go

@@ -0,0 +1,44 @@
+package sop_task
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/sop_task"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /sop_task/publish sop_task PublishSopTask
+//
+// Publish sop task | 发布 SopTask
+//
+// Publish sop task | 发布 SopTask
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: IDReq
+//
+// Responses:
+//  200: BaseMsgResp
+
+func PublishSopTaskHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.IDReq
+		if err := httpx.Parse(r, &req, true); err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+			return
+		}
+
+		l := sop_task.NewPublishSopTaskLogic(r.Context(), svcCtx)
+		resp, err := l.PublishSopTask(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 164 - 21
internal/logic/label_relationship/update_label_relationships_logic.go

@@ -3,7 +3,12 @@ package label_relationship
 import (
 	"context"
 	"github.com/suyuan32/simple-admin-common/msg/errormsg"
+	"wechat-api/ent"
+	"wechat-api/ent/contact"
+	"wechat-api/ent/custom_types"
 	"wechat-api/ent/labelrelationship"
+	"wechat-api/ent/messagerecords"
+	"wechat-api/ent/soptask"
 	"wechat-api/internal/svc"
 	"wechat-api/internal/types"
 	"wechat-api/internal/utils/dberrorhandler"
@@ -25,14 +30,8 @@ func NewUpdateLabelRelationshipsLogic(ctx context.Context, svcCtx *svc.ServiceCo
 }
 
 func (l *UpdateLabelRelationshipsLogic) UpdateLabelRelationships(req *types.LabelRelationshipsInfo) (resp *types.BaseMsgResp, err error) {
-	l.Logger.Info("Start processing UpdateLabelRelationships request", "request", req)
-	defer func() {
-		if err != nil {
-			l.Logger.Error("Error occurred in UpdateLabelRelationships", "error", err)
-		} else {
-			l.Logger.Info("Successfully processed UpdateLabelRelationships request")
-		}
-	}()
+	// 获取联系人信息
+	c, err := l.svcCtx.DB.Contact.Query().Where(contact.ID(*req.ContactId)).Only(l.ctx)
 	// 获取联系人当前已关联的标签
 	currentLabelRelationships, err := l.svcCtx.DB.LabelRelationship.Query().Where(labelrelationship.ContactID(*req.ContactId)).All(l.ctx)
 	if err != nil {
@@ -48,30 +47,65 @@ func (l *UpdateLabelRelationshipsLogic) UpdateLabelRelationships(req *types.Labe
 	// 对比新旧标签ID,找出需要新增和移除的标签
 	addLabelIds, removeLabelIds := compareLabelIds(req.LabelIds, currentLabelIds)
 
-	// 删除需要移除的标签关系
-	for _, id := range removeLabelIds {
-		_, err := l.svcCtx.DB.LabelRelationship.
-			Delete().
-			Where(
-				labelrelationship.ContactID(*req.ContactId),
-				labelrelationship.LabelID(id),
-			).
-			Exec(l.ctx)
-		if err != nil {
-			return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	// 如果 req.UpdateType 为空,或 req.UpdateType 的值为 “all” 时
+	if req.UpdateType == nil || *req.UpdateType == "all" {
+		// 删除需要移除的标签关系
+		for _, id := range removeLabelIds {
+			_, err := l.svcCtx.DB.LabelRelationship.
+				Delete().
+				Where(
+					labelrelationship.ContactID(*req.ContactId),
+					labelrelationship.LabelID(id),
+				).
+				Exec(l.ctx)
+			if err != nil {
+				return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+			}
 		}
 	}
 
 	// 创建需要新增的标签关系
 	for _, id := range addLabelIds {
-		_, err := l.svcCtx.DB.LabelRelationship.Create().
+		_, _ = l.svcCtx.DB.LabelRelationship.Create().
 			SetLabelID(id).
 			SetContactID(*req.ContactId).
-			SetStatus(*req.Status).
 			Save(l.ctx)
+		//if err != nil {
+		//	return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+		//}
+	}
+
+	currentLabelIds = req.LabelIds
+
+	// 获取所有 status 为 3 且 bot_wxid_list 包含 c.wx_wxid 的 sop_task
+	sopTasks, err := l.svcCtx.DB.SopTask.Query().Where(soptask.Status(3)).All(l.ctx)
+	if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+	var filteredSopTasks []*ent.SopTask
+	for _, task := range sopTasks {
+		for _, botWxid := range task.BotWxidList {
+			if botWxid == c.WxWxid {
+				filteredSopTasks = append(filteredSopTasks, task)
+				break
+			}
+		}
+	}
+
+	// 获取所有 filteredSopTasks 的 sop_stages
+	var sopStages []*ent.SopStage
+	for _, task := range filteredSopTasks {
+		stages, err := task.QueryTaskStages().All(l.ctx)
 		if err != nil {
 			return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
 		}
+		sopStages = append(sopStages, stages...)
+	}
+
+	err = l.AddLabelRelationships(sopStages, *c, currentLabelIds)
+	if err != nil {
+		return nil, err
 	}
 
 	return &types.BaseMsgResp{
@@ -80,6 +114,88 @@ func (l *UpdateLabelRelationshipsLogic) UpdateLabelRelationships(req *types.Labe
 	}, nil
 }
 
+func (l *UpdateLabelRelationshipsLogic) AddLabelRelationships(sopStages []*ent.SopStage, contact ent.Contact, currentLabelIds []uint64) (err error) {
+
+	// 遍历 sop_stages,找出满足条件的 stage
+	for _, stage := range sopStages {
+		if stage.ConditionType == 1 && isLabelIdListMatchFilter(currentLabelIds, stage.ConditionOperator, stage.ConditionList) {
+			// 判断是否有 contact_wxid、source_type、source_id、sub_source_id 相同的记录
+			_, err = l.svcCtx.DB.MessageRecords.Query().
+				Where(
+					messagerecords.ContactWxid(contact.Wxid),
+					messagerecords.SourceType(3),
+					messagerecords.SourceID(stage.ID),
+					messagerecords.SubSourceID(0),
+				).
+				Only(l.ctx)
+			if err == nil {
+				continue
+			}
+			// 判断ActionMessage是否为空
+			sourceType := 3
+			if stage.ActionMessage != nil {
+				for _, message := range stage.ActionMessage {
+					_, _ = l.svcCtx.DB.MessageRecords.Create().
+						SetNotNilBotWxid(&contact.WxWxid).
+						SetNotNilContactID(&contact.ID).
+						SetNotNilContactType(&contact.Type).
+						SetNotNilContactWxid(&contact.Wxid).
+						SetNotNilContentType(&message.Type).
+						SetNotNilContent(&message.Content).
+						SetNotNilSourceType(&sourceType).
+						SetNotNilSourceID(&stage.ID).
+						Save(l.ctx)
+
+					//if err != nil {
+					//	return dberrorhandler.DefaultEntError(l.Logger, err, nil)
+					//}
+				}
+			}
+			if stage.ActionLabel != nil {
+				// 获取 addLabelIds 中不在 currentLabelIds 中的标签ID
+				var newLabelIds []uint64
+				// 创建一个映射,用于快速查找 currentLabelIds 中的元素
+				currentLabelIdSet := make(map[uint64]struct{})
+				for _, id := range currentLabelIds {
+					currentLabelIdSet[id] = struct{}{}
+				}
+
+				// 遍历 addLabelIds,找出不在 currentLabelIds 中的元素
+				for _, id := range stage.ActionLabel {
+					if _, exists := currentLabelIdSet[id]; !exists {
+						newLabelIds = append(newLabelIds, id)
+					}
+				}
+
+				if len(newLabelIds) == 0 {
+					return nil
+				}
+
+				// 创建需要新增的标签关系
+				for _, id := range newLabelIds {
+					_, err = l.svcCtx.DB.LabelRelationship.Create().
+						SetLabelID(id).
+						SetContactID(contact.ID).
+						Save(l.ctx)
+					//if err != nil {
+					//	return dberrorhandler.DefaultEntError(l.Logger, err, nil)
+					//}
+				}
+
+				// 合并 currentLabelIds 和 newLabelIds
+				currentLabelIds = append(currentLabelIds, newLabelIds...)
+				// 递归调用 AddLabelRelationships
+				err = l.AddLabelRelationships(sopStages, contact, currentLabelIds)
+				if err != nil {
+					return err
+				}
+			}
+		}
+
+	}
+	return nil
+}
+
 // compareLabelIds compares the new label ids with the current ones and returns the ids to be added and removed
 func compareLabelIds(newLabelIds []uint64, currentLabelIds []uint64) (addLabelIds []uint64, removeLabelIds []uint64) {
 	newLabelIdSet := make(map[uint64]struct{}, len(newLabelIds))
@@ -101,3 +217,30 @@ func compareLabelIds(newLabelIds []uint64, currentLabelIds []uint64) (addLabelId
 
 	return
 }
+
+func isLabelIdListMatchFilter(labelIdList []uint64, conditionOperator int, conditionList []custom_types.Condition) bool {
+	labelIdSet := make(map[uint64]struct{})
+	for _, id := range labelIdList {
+		labelIdSet[id] = struct{}{}
+	}
+
+	for _, condition := range conditionList {
+		match := false
+		for _, id := range condition.LabelIdList {
+			if _, ok := labelIdSet[id]; ok {
+				match = true
+				break
+			}
+		}
+
+		if condition.Equal == 2 {
+			match = !match
+		}
+
+		if (conditionOperator == 1 && !match) || (conditionOperator == 2 && match) {
+			return match
+		}
+	}
+
+	return conditionOperator == 1
+}

+ 251 - 0
internal/logic/sop_task/publish_sop_task_logic.go

@@ -0,0 +1,251 @@
+package sop_task
+
+import (
+	"context"
+	"errors"
+	"github.com/suyuan32/simple-admin-common/msg/errormsg"
+	"wechat-api/ent"
+	"wechat-api/ent/contact"
+	"wechat-api/ent/custom_types"
+	"wechat-api/ent/labelrelationship"
+	"wechat-api/ent/messagerecords"
+	"wechat-api/ent/predicate"
+	"wechat-api/ent/soptask"
+	"wechat-api/internal/utils/dberrorhandler"
+
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type PublishSopTaskLogic struct {
+	logx.Logger
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+}
+
+func NewPublishSopTaskLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PublishSopTaskLogic {
+	return &PublishSopTaskLogic{
+		Logger: logx.WithContext(ctx),
+		ctx:    ctx,
+		svcCtx: svcCtx}
+}
+
+func (l *PublishSopTaskLogic) PublishSopTask(req *types.IDReq) (resp *types.BaseMsgResp, err error) {
+	// 根据 id 查询 sop_task
+	sopTask, err := l.svcCtx.DB.SopTask.Query().
+		Where(
+			soptask.ID(req.Id),
+			soptask.Status(3),
+		).
+		WithTaskStages().
+		Only(l.ctx)
+	if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+	// 判断 sop_task 是否存在
+	if sopTask != nil {
+		// 查询任务的所有 sop_stages
+		sopStages, err := l.svcCtx.DB.SopStage.Query().All(l.ctx)
+		if err != nil {
+			return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+		}
+
+		// 遍历 stage
+		for _, stage := range sopTask.Edges.TaskStages {
+			if stage.ConditionType == 1 {
+				// 构造查询条件
+				var predicates []predicate.Contact
+
+				for _, condition := range stage.ConditionList {
+					subPredicate := contact.HasContactRelationshipsWith(labelrelationship.LabelIDIn(condition.LabelIdList...))
+					if condition.Equal == 2 {
+						subPredicate = contact.Not(subPredicate)
+					}
+					predicates = append(predicates, subPredicate)
+				}
+
+				// 查询满足条件的联系人
+				var contacts []*ent.Contact
+				var err error
+				sourceType := 3
+				if stage.ConditionOperator == 1 {
+					contacts, err = l.svcCtx.DB.Contact.Query().Where(contact.And(predicates...)).All(l.ctx)
+				} else {
+					contacts, err = l.svcCtx.DB.Contact.Query().Where(contact.Or(predicates...)).All(l.ctx)
+				}
+
+				if err != nil {
+					return nil, err
+				}
+
+				// 遍历 contacts
+				for _, c := range contacts {
+					// 判断联系人所属微信是否包含在任务当中
+					if sopTask.BotWxidList == nil || (sopTask.BotWxidList != nil && valueInArray(c.WxWxid, sopTask.BotWxidList)) {
+						for _, message := range stage.ActionMessage {
+							_, _ = l.svcCtx.DB.MessageRecords.Create().
+								SetNotNilBotWxid(&c.WxWxid).
+								SetNotNilContactID(&c.ID).
+								SetNotNilContactType(&c.Type).
+								SetNotNilContactWxid(&c.Wxid).
+								SetNotNilContentType(&message.Type).
+								SetNotNilContent(&message.Content).
+								SetNotNilSourceType(&sourceType).
+								SetNotNilSourceID(&stage.ID).
+								Save(l.ctx)
+
+							//if err != nil {
+							//	return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+							//}
+						}
+
+						// 查询当前联系人的标签关系
+						currentLabelRelationships, err := l.svcCtx.DB.LabelRelationship.Query().Where(labelrelationship.ContactID(c.ID)).All(l.ctx)
+						if err != nil {
+							return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+						}
+
+						// 提取当前标签ID
+						var currentLabelIds []uint64
+						for _, relationship := range currentLabelRelationships {
+							currentLabelIds = append(currentLabelIds, relationship.LabelID)
+						}
+
+						if stage.ActionLabel != nil {
+							// 递归调用 AddLabelRelationships
+							err = l.AddLabelRelationships(sopStages, *c, currentLabelIds, stage.ActionLabel)
+							if err != nil {
+								return nil, err
+							}
+						}
+					}
+				}
+			}
+		}
+		return &types.BaseMsgResp{Msg: errormsg.Success}, nil
+	} else {
+		// 返回错误信息:任务不存在
+		return nil, errors.New(errormsg.TargetNotFound)
+	}
+}
+
+func (l *PublishSopTaskLogic) AddLabelRelationships(sopStages []*ent.SopStage, contact ent.Contact, currentLabelIds []uint64, addLabelIds []uint64) (err error) {
+	// 获取 addLabelIds 中不在 currentLabelIds 中的标签ID
+	var newLabelIds []uint64
+	// 创建一个映射,用于快速查找 currentLabelIds 中的元素
+	currentLabelIdSet := make(map[uint64]struct{})
+	for _, id := range currentLabelIds {
+		currentLabelIdSet[id] = struct{}{}
+	}
+
+	// 遍历 addLabelIds,找出不在 currentLabelIds 中的元素
+	for _, id := range addLabelIds {
+		if _, exists := currentLabelIdSet[id]; !exists {
+			newLabelIds = append(newLabelIds, id)
+		}
+	}
+
+	if len(newLabelIds) == 0 {
+		return nil
+	}
+
+	// 创建需要新增的标签关系
+	for _, id := range newLabelIds {
+		_, err = l.svcCtx.DB.LabelRelationship.Create().
+			SetLabelID(id).
+			SetContactID(contact.ID).
+			Save(l.ctx)
+		if err != nil {
+			return dberrorhandler.DefaultEntError(l.Logger, err, nil)
+		}
+	}
+
+	// 合并 currentLabelIds 和 newLabelIds
+	currentLabelIds = append(currentLabelIds, newLabelIds...)
+
+	// 遍历 sop_stages,找出满足条件的 stage
+	for _, stage := range sopStages {
+		if stage.ConditionType == 1 && isLabelIdListMatchFilter(currentLabelIds, stage.ConditionOperator, stage.ConditionList) {
+			// 判断是否有 contact_wxid、source_type、source_id、sub_source_id 相同的记录
+			_, err = l.svcCtx.DB.MessageRecords.Query().
+				Where(
+					messagerecords.ContactWxid(contact.Wxid),
+					messagerecords.SourceType(3),
+					messagerecords.SourceID(stage.ID),
+					messagerecords.SubSourceID(0),
+				).
+				Only(l.ctx)
+			if err == nil {
+				continue
+			}
+			// 判断ActionMessage是否为空
+			sourceType := 3
+			if stage.ActionMessage != nil {
+				for _, message := range stage.ActionMessage {
+					_, _ = l.svcCtx.DB.MessageRecords.Create().
+						SetNotNilBotWxid(&contact.WxWxid).
+						SetNotNilContactID(&contact.ID).
+						SetNotNilContactType(&contact.Type).
+						SetNotNilContactWxid(&contact.Wxid).
+						SetNotNilContentType(&message.Type).
+						SetNotNilContent(&message.Content).
+						SetNotNilSourceType(&sourceType).
+						SetNotNilSourceID(&stage.ID).
+						Save(l.ctx)
+
+					//if err != nil {
+					//	return dberrorhandler.DefaultEntError(l.Logger, err, nil)
+					//}
+				}
+			}
+			if stage.ActionLabel != nil {
+				// 递归调用 AddLabelRelationships
+				err = l.AddLabelRelationships(sopStages, contact, currentLabelIds, stage.ActionLabel)
+				if err != nil {
+					return err
+				}
+			}
+		}
+
+	}
+	return nil
+}
+
+func valueInArray(val string, array []string) bool {
+	for _, item := range array {
+		if item == val {
+			return true
+		}
+	}
+	return false
+}
+
+func isLabelIdListMatchFilter(labelIdList []uint64, conditionOperator int, conditionList []custom_types.Condition) bool {
+	labelIdSet := make(map[uint64]struct{})
+	for _, id := range labelIdList {
+		labelIdSet[id] = struct{}{}
+	}
+
+	for _, condition := range conditionList {
+		match := false
+		for _, id := range condition.LabelIdList {
+			if _, ok := labelIdSet[id]; ok {
+				match = true
+				break
+			}
+		}
+
+		if condition.Equal == 2 {
+			match = !match
+		}
+
+		if (conditionOperator == 1 && !match) || (conditionOperator == 2 && match) {
+			return match
+		}
+	}
+
+	return conditionOperator == 1
+}

+ 7 - 7
internal/types/types.go

@@ -533,8 +533,8 @@ type LabelRelationshipInfo struct {
 // swagger:model LabelRelationshipsInfo
 type LabelRelationshipsInfo struct {
 	BaseIDInfo
-	// Status 1: normal 2: ban | 状态 1 正常 2 禁用
-	Status *uint8 `json:"status,optional"`
+	// 更新类型:为空或“all”时表示全量更新,为 “add” 时表示仅追加
+	UpdateType *string `json:"updateType,optional"`
 	// 标签 ID
 	LabelIds []uint64 `json:"labelIds,optional"`
 	// 联系人 ID
@@ -726,7 +726,7 @@ type SopStageInfo struct {
 	// 命中后发送的消息内容
 	ActionMessage []Action `json:"actionMessage,optional"`
 	// 命中后需要打的标签
-	ActionLabel []int `json:"actionLabel,optional"`
+	ActionLabel []uint64 `json:"actionLabel,optional"`
 	// 阶段顺序
 	IndexSort *int `json:"indexSort,optional"`
 	// sop 任务信息
@@ -776,7 +776,7 @@ type SopNodeInfo struct {
 	// 命中后发送的消息内容
 	ActionMessage []Action `json:"actionMessage,optional"`
 	// 命中后需要打的标签
-	ActionLabel []int `json:"actionLabel,optional"`
+	ActionLabel []uint64 `json:"actionLabel,optional"`
 	// 阶段信息
 	StageInfo *SopStageInfo `json:"stageInfo,optional"`
 }
@@ -858,7 +858,7 @@ type MessageRecordsInfo struct {
 	// 机器人微信 id
 	BotWxid *string `json:"botWxid,optional"`
 	// 联系人 id
-	ContactId *int `json:"contactId,optional"`
+	ContactId *uint64 `json:"contactId,optional"`
 	// 类型:1好友,2群组,3企业微信联系人
 	ContactType *int `json:"contactType,optional"`
 	// 接收方微信 id
@@ -874,9 +874,9 @@ type MessageRecordsInfo struct {
 	// 源类型 1 点发 2 群发 3 SOP
 	SourceType *int `json:"sourceType,optional"`
 	// 源 ID
-	SourceId *int `json:"sourceId,optional"`
+	SourceId *uint64 `json:"sourceId,optional"`
 	// 次源 ID
-	SubSourceId *int `json:"subSourceId,optional"`
+	SubSourceId *uint64 `json:"subSourceId,optional"`
 }
 
 // The response data of message records list | MessageRecords列表数据

Some files were not shown because too many files changed in this diff