Browse Source

增加发送文件功能

boweniac 8 months ago
parent
commit
860545e110

+ 5 - 0
desc/base.api

@@ -214,6 +214,11 @@ type Condition struct {
 type Action struct {
 	Type    int    `json:"type"`
 	Content string `json:"content"`
+	Meta Meta `json:"meta,optional"`
+}
+
+type Meta struct {
+	Filename    string    `json:"filename,optional"`
 }
 
 @server(

+ 3 - 0
desc/wechat/message_records.api

@@ -26,6 +26,9 @@ type (
         // 发送内容 
         Content  *string `json:"content,optional"`
 
+        // 元数据
+        Meta *Meta `json:"meta,optional"`
+
         // 异常原因 
         ErrorDetail  *string `json:"errorDetail,optional"`
 

+ 3 - 0
desc/wechat/sop_stage.api

@@ -90,6 +90,9 @@ type (
         // 触发语义列表 当为空时则代表用户回复任意内容后触发
         ConditionList  []string `json:"conditionList,optional"`
 
+        // 超时触发时间(分钟)
+        NoReplyCondition  *uint64 `json:"noReplyCondition,optional"`
+
         // 命中后发送的消息内容
         ActionMessage  []Action `json:"actionMessage,optional"`
 

+ 5 - 0
ent/custom_types/types.go

@@ -8,4 +8,9 @@ type Condition struct {
 type Action struct {
 	Type    int    `json:"type"`
 	Content string `json:"content"`
+	Meta    *Meta  `json:"meta,omitempty"`
+}
+
+type Meta struct {
+	Filename string `json:"filename,omitempty"`
 }

+ 17 - 0
ent/messagerecords.go

@@ -3,10 +3,12 @@
 package ent
 
 import (
+	"encoding/json"
 	"fmt"
 	"strings"
 	"time"
 	"wechat-api/ent/contact"
+	"wechat-api/ent/custom_types"
 	"wechat-api/ent/messagerecords"
 	"wechat-api/ent/sopnode"
 	"wechat-api/ent/sopstage"
@@ -40,6 +42,8 @@ type MessageRecords struct {
 	ContentType int `json:"content_type,omitempty"`
 	// 发送内容
 	Content string `json:"content,omitempty"`
+	// 元数据
+	Meta custom_types.Meta `json:"meta,omitempty"`
 	// 异常原因
 	ErrorDetail string `json:"error_detail,omitempty"`
 	// 发送时间
@@ -107,6 +111,8 @@ func (*MessageRecords) scanValues(columns []string) ([]any, error) {
 	values := make([]any, len(columns))
 	for i := range columns {
 		switch columns[i] {
+		case messagerecords.FieldMeta:
+			values[i] = new([]byte)
 		case messagerecords.FieldID, messagerecords.FieldStatus, messagerecords.FieldContactID, messagerecords.FieldContactType, messagerecords.FieldContentType, messagerecords.FieldSourceType, messagerecords.FieldSourceID, messagerecords.FieldSubSourceID:
 			values[i] = new(sql.NullInt64)
 		case messagerecords.FieldBotWxid, messagerecords.FieldContactWxid, messagerecords.FieldContent, messagerecords.FieldErrorDetail:
@@ -194,6 +200,14 @@ func (mr *MessageRecords) assignValues(columns []string, values []any) error {
 			} else if value.Valid {
 				mr.Content = value.String
 			}
+		case messagerecords.FieldMeta:
+			if value, ok := values[i].(*[]byte); !ok {
+				return fmt.Errorf("unexpected type %T for field meta", values[i])
+			} else if value != nil && len(*value) > 0 {
+				if err := json.Unmarshal(*value, &mr.Meta); err != nil {
+					return fmt.Errorf("unmarshal field meta: %w", err)
+				}
+			}
 		case messagerecords.FieldErrorDetail:
 			if value, ok := values[i].(*sql.NullString); !ok {
 				return fmt.Errorf("unexpected type %T for field error_detail", values[i])
@@ -305,6 +319,9 @@ func (mr *MessageRecords) String() string {
 	builder.WriteString("content=")
 	builder.WriteString(mr.Content)
 	builder.WriteString(", ")
+	builder.WriteString("meta=")
+	builder.WriteString(fmt.Sprintf("%v", mr.Meta))
+	builder.WriteString(", ")
 	builder.WriteString("error_detail=")
 	builder.WriteString(mr.ErrorDetail)
 	builder.WriteString(", ")

+ 3 - 0
ent/messagerecords/messagerecords.go

@@ -35,6 +35,8 @@ const (
 	FieldContentType = "content_type"
 	// FieldContent holds the string denoting the content field in the database.
 	FieldContent = "content"
+	// FieldMeta holds the string denoting the meta field in the database.
+	FieldMeta = "meta"
 	// FieldErrorDetail holds the string denoting the error_detail field in the database.
 	FieldErrorDetail = "error_detail"
 	// FieldSendTime holds the string denoting the send_time field in the database.
@@ -89,6 +91,7 @@ var Columns = []string{
 	FieldContactWxid,
 	FieldContentType,
 	FieldContent,
+	FieldMeta,
 	FieldErrorDetail,
 	FieldSendTime,
 	FieldSourceType,

+ 10 - 0
ent/messagerecords/where.go

@@ -615,6 +615,16 @@ func ContentContainsFold(v string) predicate.MessageRecords {
 	return predicate.MessageRecords(sql.FieldContainsFold(FieldContent, v))
 }
 
+// MetaIsNil applies the IsNil predicate on the "meta" field.
+func MetaIsNil() predicate.MessageRecords {
+	return predicate.MessageRecords(sql.FieldIsNull(FieldMeta))
+}
+
+// MetaNotNil applies the NotNil predicate on the "meta" field.
+func MetaNotNil() predicate.MessageRecords {
+	return predicate.MessageRecords(sql.FieldNotNull(FieldMeta))
+}
+
 // ErrorDetailEQ applies the EQ predicate on the "error_detail" field.
 func ErrorDetailEQ(v string) predicate.MessageRecords {
 	return predicate.MessageRecords(sql.FieldEQ(FieldErrorDetail, v))

+ 79 - 0
ent/messagerecords_create.go

@@ -8,6 +8,7 @@ import (
 	"fmt"
 	"time"
 	"wechat-api/ent/contact"
+	"wechat-api/ent/custom_types"
 	"wechat-api/ent/messagerecords"
 	"wechat-api/ent/sopnode"
 	"wechat-api/ent/sopstage"
@@ -157,6 +158,20 @@ func (mrc *MessageRecordsCreate) SetNillableContent(s *string) *MessageRecordsCr
 	return mrc
 }
 
+// SetMeta sets the "meta" field.
+func (mrc *MessageRecordsCreate) SetMeta(ct custom_types.Meta) *MessageRecordsCreate {
+	mrc.mutation.SetMeta(ct)
+	return mrc
+}
+
+// SetNillableMeta sets the "meta" field if the given value is not nil.
+func (mrc *MessageRecordsCreate) SetNillableMeta(ct *custom_types.Meta) *MessageRecordsCreate {
+	if ct != nil {
+		mrc.SetMeta(*ct)
+	}
+	return mrc
+}
+
 // SetErrorDetail sets the "error_detail" field.
 func (mrc *MessageRecordsCreate) SetErrorDetail(s string) *MessageRecordsCreate {
 	mrc.mutation.SetErrorDetail(s)
@@ -478,6 +493,10 @@ func (mrc *MessageRecordsCreate) createSpec() (*MessageRecords, *sqlgraph.Create
 		_spec.SetField(messagerecords.FieldContent, field.TypeString, value)
 		_node.Content = value
 	}
+	if value, ok := mrc.mutation.Meta(); ok {
+		_spec.SetField(messagerecords.FieldMeta, field.TypeJSON, value)
+		_node.Meta = value
+	}
 	if value, ok := mrc.mutation.ErrorDetail(); ok {
 		_spec.SetField(messagerecords.FieldErrorDetail, field.TypeString, value)
 		_node.ErrorDetail = value
@@ -737,6 +756,24 @@ func (u *MessageRecordsUpsert) UpdateContent() *MessageRecordsUpsert {
 	return u
 }
 
+// SetMeta sets the "meta" field.
+func (u *MessageRecordsUpsert) SetMeta(v custom_types.Meta) *MessageRecordsUpsert {
+	u.Set(messagerecords.FieldMeta, v)
+	return u
+}
+
+// UpdateMeta sets the "meta" field to the value that was provided on create.
+func (u *MessageRecordsUpsert) UpdateMeta() *MessageRecordsUpsert {
+	u.SetExcluded(messagerecords.FieldMeta)
+	return u
+}
+
+// ClearMeta clears the value of the "meta" field.
+func (u *MessageRecordsUpsert) ClearMeta() *MessageRecordsUpsert {
+	u.SetNull(messagerecords.FieldMeta)
+	return u
+}
+
 // SetErrorDetail sets the "error_detail" field.
 func (u *MessageRecordsUpsert) SetErrorDetail(v string) *MessageRecordsUpsert {
 	u.Set(messagerecords.FieldErrorDetail, v)
@@ -1040,6 +1077,27 @@ func (u *MessageRecordsUpsertOne) UpdateContent() *MessageRecordsUpsertOne {
 	})
 }
 
+// SetMeta sets the "meta" field.
+func (u *MessageRecordsUpsertOne) SetMeta(v custom_types.Meta) *MessageRecordsUpsertOne {
+	return u.Update(func(s *MessageRecordsUpsert) {
+		s.SetMeta(v)
+	})
+}
+
+// UpdateMeta sets the "meta" field to the value that was provided on create.
+func (u *MessageRecordsUpsertOne) UpdateMeta() *MessageRecordsUpsertOne {
+	return u.Update(func(s *MessageRecordsUpsert) {
+		s.UpdateMeta()
+	})
+}
+
+// ClearMeta clears the value of the "meta" field.
+func (u *MessageRecordsUpsertOne) ClearMeta() *MessageRecordsUpsertOne {
+	return u.Update(func(s *MessageRecordsUpsert) {
+		s.ClearMeta()
+	})
+}
+
 // SetErrorDetail sets the "error_detail" field.
 func (u *MessageRecordsUpsertOne) SetErrorDetail(v string) *MessageRecordsUpsertOne {
 	return u.Update(func(s *MessageRecordsUpsert) {
@@ -1523,6 +1581,27 @@ func (u *MessageRecordsUpsertBulk) UpdateContent() *MessageRecordsUpsertBulk {
 	})
 }
 
+// SetMeta sets the "meta" field.
+func (u *MessageRecordsUpsertBulk) SetMeta(v custom_types.Meta) *MessageRecordsUpsertBulk {
+	return u.Update(func(s *MessageRecordsUpsert) {
+		s.SetMeta(v)
+	})
+}
+
+// UpdateMeta sets the "meta" field to the value that was provided on create.
+func (u *MessageRecordsUpsertBulk) UpdateMeta() *MessageRecordsUpsertBulk {
+	return u.Update(func(s *MessageRecordsUpsert) {
+		s.UpdateMeta()
+	})
+}
+
+// ClearMeta clears the value of the "meta" field.
+func (u *MessageRecordsUpsertBulk) ClearMeta() *MessageRecordsUpsertBulk {
+	return u.Update(func(s *MessageRecordsUpsert) {
+		s.ClearMeta()
+	})
+}
+
 // SetErrorDetail sets the "error_detail" field.
 func (u *MessageRecordsUpsertBulk) SetErrorDetail(v string) *MessageRecordsUpsertBulk {
 	return u.Update(func(s *MessageRecordsUpsert) {

+ 53 - 0
ent/messagerecords_update.go

@@ -8,6 +8,7 @@ import (
 	"fmt"
 	"time"
 	"wechat-api/ent/contact"
+	"wechat-api/ent/custom_types"
 	"wechat-api/ent/messagerecords"
 	"wechat-api/ent/predicate"
 	"wechat-api/ent/sopnode"
@@ -188,6 +189,26 @@ func (mru *MessageRecordsUpdate) SetNillableContent(s *string) *MessageRecordsUp
 	return mru
 }
 
+// SetMeta sets the "meta" field.
+func (mru *MessageRecordsUpdate) SetMeta(ct custom_types.Meta) *MessageRecordsUpdate {
+	mru.mutation.SetMeta(ct)
+	return mru
+}
+
+// SetNillableMeta sets the "meta" field if the given value is not nil.
+func (mru *MessageRecordsUpdate) SetNillableMeta(ct *custom_types.Meta) *MessageRecordsUpdate {
+	if ct != nil {
+		mru.SetMeta(*ct)
+	}
+	return mru
+}
+
+// ClearMeta clears the value of the "meta" field.
+func (mru *MessageRecordsUpdate) ClearMeta() *MessageRecordsUpdate {
+	mru.mutation.ClearMeta()
+	return mru
+}
+
 // SetErrorDetail sets the "error_detail" field.
 func (mru *MessageRecordsUpdate) SetErrorDetail(s string) *MessageRecordsUpdate {
 	mru.mutation.SetErrorDetail(s)
@@ -453,6 +474,12 @@ func (mru *MessageRecordsUpdate) sqlSave(ctx context.Context) (n int, err error)
 	if value, ok := mru.mutation.Content(); ok {
 		_spec.SetField(messagerecords.FieldContent, field.TypeString, value)
 	}
+	if value, ok := mru.mutation.Meta(); ok {
+		_spec.SetField(messagerecords.FieldMeta, field.TypeJSON, value)
+	}
+	if mru.mutation.MetaCleared() {
+		_spec.ClearField(messagerecords.FieldMeta, field.TypeJSON)
+	}
 	if value, ok := mru.mutation.ErrorDetail(); ok {
 		_spec.SetField(messagerecords.FieldErrorDetail, field.TypeString, value)
 	}
@@ -732,6 +759,26 @@ func (mruo *MessageRecordsUpdateOne) SetNillableContent(s *string) *MessageRecor
 	return mruo
 }
 
+// SetMeta sets the "meta" field.
+func (mruo *MessageRecordsUpdateOne) SetMeta(ct custom_types.Meta) *MessageRecordsUpdateOne {
+	mruo.mutation.SetMeta(ct)
+	return mruo
+}
+
+// SetNillableMeta sets the "meta" field if the given value is not nil.
+func (mruo *MessageRecordsUpdateOne) SetNillableMeta(ct *custom_types.Meta) *MessageRecordsUpdateOne {
+	if ct != nil {
+		mruo.SetMeta(*ct)
+	}
+	return mruo
+}
+
+// ClearMeta clears the value of the "meta" field.
+func (mruo *MessageRecordsUpdateOne) ClearMeta() *MessageRecordsUpdateOne {
+	mruo.mutation.ClearMeta()
+	return mruo
+}
+
 // SetErrorDetail sets the "error_detail" field.
 func (mruo *MessageRecordsUpdateOne) SetErrorDetail(s string) *MessageRecordsUpdateOne {
 	mruo.mutation.SetErrorDetail(s)
@@ -1027,6 +1074,12 @@ func (mruo *MessageRecordsUpdateOne) sqlSave(ctx context.Context) (_node *Messag
 	if value, ok := mruo.mutation.Content(); ok {
 		_spec.SetField(messagerecords.FieldContent, field.TypeString, value)
 	}
+	if value, ok := mruo.mutation.Meta(); ok {
+		_spec.SetField(messagerecords.FieldMeta, field.TypeJSON, value)
+	}
+	if mruo.mutation.MetaCleared() {
+		_spec.ClearField(messagerecords.FieldMeta, field.TypeJSON)
+	}
 	if value, ok := mruo.mutation.ErrorDetail(); ok {
 		_spec.SetField(messagerecords.FieldErrorDetail, field.TypeString, value)
 	}

+ 7 - 5
ent/migrate/schema.go

@@ -153,6 +153,7 @@ var (
 		{Name: "contact_wxid", Type: field.TypeString, Comment: "接收方微信 id", Default: ""},
 		{Name: "content_type", Type: field.TypeInt, Comment: "内容类型 1 文本 2 文件", Default: 1},
 		{Name: "content", Type: field.TypeString, Comment: "发送内容", Default: ""},
+		{Name: "meta", Type: field.TypeJSON, Nullable: true, Comment: "元数据"},
 		{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},
@@ -168,19 +169,19 @@ var (
 		ForeignKeys: []*schema.ForeignKey{
 			{
 				Symbol:     "message_records_contact_contact_messages",
-				Columns:    []*schema.Column{MessageRecordsColumns[13]},
+				Columns:    []*schema.Column{MessageRecordsColumns[14]},
 				RefColumns: []*schema.Column{ContactColumns[0]},
 				OnDelete:   schema.SetNull,
 			},
 			{
 				Symbol:     "message_records_sop_node_node_messages",
-				Columns:    []*schema.Column{MessageRecordsColumns[14]},
+				Columns:    []*schema.Column{MessageRecordsColumns[15]},
 				RefColumns: []*schema.Column{SopNodeColumns[0]},
 				OnDelete:   schema.SetNull,
 			},
 			{
 				Symbol:     "message_records_sop_stage_stage_messages",
-				Columns:    []*schema.Column{MessageRecordsColumns[15]},
+				Columns:    []*schema.Column{MessageRecordsColumns[16]},
 				RefColumns: []*schema.Column{SopStageColumns[0]},
 				OnDelete:   schema.SetNull,
 			},
@@ -189,7 +190,7 @@ var (
 			{
 				Name:    "messagerecords_source_type",
 				Unique:  false,
-				Columns: []*schema.Column{MessageRecordsColumns[12]},
+				Columns: []*schema.Column{MessageRecordsColumns[13]},
 			},
 		},
 	}
@@ -239,6 +240,7 @@ var (
 		{Name: "name", Type: field.TypeString, Comment: "节点名称", Default: ""},
 		{Name: "condition_type", Type: field.TypeInt, Comment: "触发条件类型 1 客户回复后触发 2 超时后触发", Default: 1},
 		{Name: "condition_list", Type: field.TypeJSON, Nullable: true, Comment: "触发语义列表 当为空时则代表用户回复任意内容后触发"},
+		{Name: "no_reply_condition", Type: field.TypeUint64, Comment: "超时触发时间(分钟)", Default: 0},
 		{Name: "action_message", Type: field.TypeJSON, Nullable: true, Comment: "命中后发送的消息内容"},
 		{Name: "action_label", Type: field.TypeJSON, Nullable: true, Comment: "命中后需要打的标签"},
 		{Name: "stage_id", Type: field.TypeUint64, Comment: "阶段 ID"},
@@ -251,7 +253,7 @@ var (
 		ForeignKeys: []*schema.ForeignKey{
 			{
 				Symbol:     "sop_node_sop_stage_stage_nodes",
-				Columns:    []*schema.Column{SopNodeColumns[11]},
+				Columns:    []*schema.Column{SopNodeColumns[12]},
 				RefColumns: []*schema.Column{SopStageColumns[0]},
 				OnDelete:   schema.NoAction,
 			},

+ 190 - 30
ent/mutation.go

@@ -4108,6 +4108,7 @@ type MessageRecordsMutation struct {
 	content_type           *int
 	addcontent_type        *int
 	content                *string
+	meta                   *custom_types.Meta
 	error_detail           *string
 	send_time              *time.Time
 	source_type            *int
@@ -4688,6 +4689,55 @@ func (m *MessageRecordsMutation) ResetContent() {
 	m.content = nil
 }
 
+// SetMeta sets the "meta" field.
+func (m *MessageRecordsMutation) SetMeta(ct custom_types.Meta) {
+	m.meta = &ct
+}
+
+// Meta returns the value of the "meta" field in the mutation.
+func (m *MessageRecordsMutation) Meta() (r custom_types.Meta, exists bool) {
+	v := m.meta
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldMeta returns the old "meta" field's value of the MessageRecords entity.
+// If the MessageRecords object wasn't provided to the builder, the object is fetched from the database.
+// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
+func (m *MessageRecordsMutation) OldMeta(ctx context.Context) (v custom_types.Meta, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldMeta is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldMeta requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldMeta: %w", err)
+	}
+	return oldValue.Meta, nil
+}
+
+// ClearMeta clears the value of the "meta" field.
+func (m *MessageRecordsMutation) ClearMeta() {
+	m.meta = nil
+	m.clearedFields[messagerecords.FieldMeta] = struct{}{}
+}
+
+// MetaCleared returns if the "meta" field was cleared in this mutation.
+func (m *MessageRecordsMutation) MetaCleared() bool {
+	_, ok := m.clearedFields[messagerecords.FieldMeta]
+	return ok
+}
+
+// ResetMeta resets all changes to the "meta" field.
+func (m *MessageRecordsMutation) ResetMeta() {
+	m.meta = nil
+	delete(m.clearedFields, messagerecords.FieldMeta)
+}
+
 // SetErrorDetail sets the "error_detail" field.
 func (m *MessageRecordsMutation) SetErrorDetail(s string) {
 	m.error_detail = &s
@@ -5081,7 +5131,7 @@ func (m *MessageRecordsMutation) Type() string {
 // order to get all numeric fields that were incremented/decremented, call
 // AddedFields().
 func (m *MessageRecordsMutation) Fields() []string {
-	fields := make([]string, 0, 15)
+	fields := make([]string, 0, 16)
 	if m.created_at != nil {
 		fields = append(fields, messagerecords.FieldCreatedAt)
 	}
@@ -5112,6 +5162,9 @@ func (m *MessageRecordsMutation) Fields() []string {
 	if m.content != nil {
 		fields = append(fields, messagerecords.FieldContent)
 	}
+	if m.meta != nil {
+		fields = append(fields, messagerecords.FieldMeta)
+	}
 	if m.error_detail != nil {
 		fields = append(fields, messagerecords.FieldErrorDetail)
 	}
@@ -5155,6 +5208,8 @@ func (m *MessageRecordsMutation) Field(name string) (ent.Value, bool) {
 		return m.ContentType()
 	case messagerecords.FieldContent:
 		return m.Content()
+	case messagerecords.FieldMeta:
+		return m.Meta()
 	case messagerecords.FieldErrorDetail:
 		return m.ErrorDetail()
 	case messagerecords.FieldSendTime:
@@ -5194,6 +5249,8 @@ func (m *MessageRecordsMutation) OldField(ctx context.Context, name string) (ent
 		return m.OldContentType(ctx)
 	case messagerecords.FieldContent:
 		return m.OldContent(ctx)
+	case messagerecords.FieldMeta:
+		return m.OldMeta(ctx)
 	case messagerecords.FieldErrorDetail:
 		return m.OldErrorDetail(ctx)
 	case messagerecords.FieldSendTime:
@@ -5283,6 +5340,13 @@ func (m *MessageRecordsMutation) SetField(name string, value ent.Value) error {
 		}
 		m.SetContent(v)
 		return nil
+	case messagerecords.FieldMeta:
+		v, ok := value.(custom_types.Meta)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetMeta(v)
+		return nil
 	case messagerecords.FieldErrorDetail:
 		v, ok := value.(string)
 		if !ok {
@@ -5408,6 +5472,9 @@ func (m *MessageRecordsMutation) ClearedFields() []string {
 	if m.FieldCleared(messagerecords.FieldContactID) {
 		fields = append(fields, messagerecords.FieldContactID)
 	}
+	if m.FieldCleared(messagerecords.FieldMeta) {
+		fields = append(fields, messagerecords.FieldMeta)
+	}
 	if m.FieldCleared(messagerecords.FieldSendTime) {
 		fields = append(fields, messagerecords.FieldSendTime)
 	}
@@ -5440,6 +5507,9 @@ func (m *MessageRecordsMutation) ClearField(name string) error {
 	case messagerecords.FieldContactID:
 		m.ClearContactID()
 		return nil
+	case messagerecords.FieldMeta:
+		m.ClearMeta()
+		return nil
 	case messagerecords.FieldSendTime:
 		m.ClearSendTime()
 		return nil
@@ -5487,6 +5557,9 @@ func (m *MessageRecordsMutation) ResetField(name string) error {
 	case messagerecords.FieldContent:
 		m.ResetContent()
 		return nil
+	case messagerecords.FieldMeta:
+		m.ResetMeta()
+		return nil
 	case messagerecords.FieldErrorDetail:
 		m.ResetErrorDetail()
 		return nil
@@ -6500,34 +6573,36 @@ func (m *ServerMutation) ResetEdge(name string) error {
 // SopNodeMutation represents an operation that mutates the SopNode nodes in the graph.
 type SopNodeMutation struct {
 	config
-	op                   Op
-	typ                  string
-	id                   *uint64
-	created_at           *time.Time
-	updated_at           *time.Time
-	status               *uint8
-	addstatus            *int8
-	deleted_at           *time.Time
-	parent_id            *uint64
-	addparent_id         *int64
-	name                 *string
-	condition_type       *int
-	addcondition_type    *int
-	condition_list       *[]string
-	appendcondition_list []string
-	action_message       *[]custom_types.Action
-	appendaction_message []custom_types.Action
-	action_label         *[]uint64
-	appendaction_label   []uint64
-	clearedFields        map[string]struct{}
-	sop_stage            *uint64
-	clearedsop_stage     bool
-	node_messages        map[uint64]struct{}
-	removednode_messages map[uint64]struct{}
-	clearednode_messages bool
-	done                 bool
-	oldValue             func(context.Context) (*SopNode, error)
-	predicates           []predicate.SopNode
+	op                    Op
+	typ                   string
+	id                    *uint64
+	created_at            *time.Time
+	updated_at            *time.Time
+	status                *uint8
+	addstatus             *int8
+	deleted_at            *time.Time
+	parent_id             *uint64
+	addparent_id          *int64
+	name                  *string
+	condition_type        *int
+	addcondition_type     *int
+	condition_list        *[]string
+	appendcondition_list  []string
+	no_reply_condition    *uint64
+	addno_reply_condition *int64
+	action_message        *[]custom_types.Action
+	appendaction_message  []custom_types.Action
+	action_label          *[]uint64
+	appendaction_label    []uint64
+	clearedFields         map[string]struct{}
+	sop_stage             *uint64
+	clearedsop_stage      bool
+	node_messages         map[uint64]struct{}
+	removednode_messages  map[uint64]struct{}
+	clearednode_messages  bool
+	done                  bool
+	oldValue              func(context.Context) (*SopNode, error)
+	predicates            []predicate.SopNode
 }
 
 var _ ent.Mutation = (*SopNodeMutation)(nil)
@@ -7074,6 +7149,62 @@ func (m *SopNodeMutation) ResetConditionList() {
 	delete(m.clearedFields, sopnode.FieldConditionList)
 }
 
+// SetNoReplyCondition sets the "no_reply_condition" field.
+func (m *SopNodeMutation) SetNoReplyCondition(u uint64) {
+	m.no_reply_condition = &u
+	m.addno_reply_condition = nil
+}
+
+// NoReplyCondition returns the value of the "no_reply_condition" field in the mutation.
+func (m *SopNodeMutation) NoReplyCondition() (r uint64, exists bool) {
+	v := m.no_reply_condition
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldNoReplyCondition returns the old "no_reply_condition" field's value of the SopNode entity.
+// If the SopNode object wasn't provided to the builder, the object is fetched from the database.
+// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
+func (m *SopNodeMutation) OldNoReplyCondition(ctx context.Context) (v uint64, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldNoReplyCondition is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldNoReplyCondition requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldNoReplyCondition: %w", err)
+	}
+	return oldValue.NoReplyCondition, nil
+}
+
+// AddNoReplyCondition adds u to the "no_reply_condition" field.
+func (m *SopNodeMutation) AddNoReplyCondition(u int64) {
+	if m.addno_reply_condition != nil {
+		*m.addno_reply_condition += u
+	} else {
+		m.addno_reply_condition = &u
+	}
+}
+
+// AddedNoReplyCondition returns the value that was added to the "no_reply_condition" field in this mutation.
+func (m *SopNodeMutation) AddedNoReplyCondition() (r int64, exists bool) {
+	v := m.addno_reply_condition
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// ResetNoReplyCondition resets all changes to the "no_reply_condition" field.
+func (m *SopNodeMutation) ResetNoReplyCondition() {
+	m.no_reply_condition = nil
+	m.addno_reply_condition = nil
+}
+
 // SetActionMessage sets the "action_message" field.
 func (m *SopNodeMutation) SetActionMessage(ct []custom_types.Action) {
 	m.action_message = &ct
@@ -7332,7 +7463,7 @@ func (m *SopNodeMutation) Type() string {
 // order to get all numeric fields that were incremented/decremented, call
 // AddedFields().
 func (m *SopNodeMutation) Fields() []string {
-	fields := make([]string, 0, 11)
+	fields := make([]string, 0, 12)
 	if m.created_at != nil {
 		fields = append(fields, sopnode.FieldCreatedAt)
 	}
@@ -7360,6 +7491,9 @@ func (m *SopNodeMutation) Fields() []string {
 	if m.condition_list != nil {
 		fields = append(fields, sopnode.FieldConditionList)
 	}
+	if m.no_reply_condition != nil {
+		fields = append(fields, sopnode.FieldNoReplyCondition)
+	}
 	if m.action_message != nil {
 		fields = append(fields, sopnode.FieldActionMessage)
 	}
@@ -7392,6 +7526,8 @@ func (m *SopNodeMutation) Field(name string) (ent.Value, bool) {
 		return m.ConditionType()
 	case sopnode.FieldConditionList:
 		return m.ConditionList()
+	case sopnode.FieldNoReplyCondition:
+		return m.NoReplyCondition()
 	case sopnode.FieldActionMessage:
 		return m.ActionMessage()
 	case sopnode.FieldActionLabel:
@@ -7423,6 +7559,8 @@ func (m *SopNodeMutation) OldField(ctx context.Context, name string) (ent.Value,
 		return m.OldConditionType(ctx)
 	case sopnode.FieldConditionList:
 		return m.OldConditionList(ctx)
+	case sopnode.FieldNoReplyCondition:
+		return m.OldNoReplyCondition(ctx)
 	case sopnode.FieldActionMessage:
 		return m.OldActionMessage(ctx)
 	case sopnode.FieldActionLabel:
@@ -7499,6 +7637,13 @@ func (m *SopNodeMutation) SetField(name string, value ent.Value) error {
 		}
 		m.SetConditionList(v)
 		return nil
+	case sopnode.FieldNoReplyCondition:
+		v, ok := value.(uint64)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetNoReplyCondition(v)
+		return nil
 	case sopnode.FieldActionMessage:
 		v, ok := value.([]custom_types.Action)
 		if !ok {
@@ -7530,6 +7675,9 @@ func (m *SopNodeMutation) AddedFields() []string {
 	if m.addcondition_type != nil {
 		fields = append(fields, sopnode.FieldConditionType)
 	}
+	if m.addno_reply_condition != nil {
+		fields = append(fields, sopnode.FieldNoReplyCondition)
+	}
 	return fields
 }
 
@@ -7544,6 +7692,8 @@ func (m *SopNodeMutation) AddedField(name string) (ent.Value, bool) {
 		return m.AddedParentID()
 	case sopnode.FieldConditionType:
 		return m.AddedConditionType()
+	case sopnode.FieldNoReplyCondition:
+		return m.AddedNoReplyCondition()
 	}
 	return nil, false
 }
@@ -7574,6 +7724,13 @@ func (m *SopNodeMutation) AddField(name string, value ent.Value) error {
 		}
 		m.AddConditionType(v)
 		return nil
+	case sopnode.FieldNoReplyCondition:
+		v, ok := value.(int64)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddNoReplyCondition(v)
+		return nil
 	}
 	return fmt.Errorf("unknown SopNode numeric field %s", name)
 }
@@ -7661,6 +7818,9 @@ func (m *SopNodeMutation) ResetField(name string) error {
 	case sopnode.FieldConditionList:
 		m.ResetConditionList()
 		return nil
+	case sopnode.FieldNoReplyCondition:
+		m.ResetNoReplyCondition()
+		return nil
 	case sopnode.FieldActionMessage:
 		m.ResetActionMessage()
 		return nil

+ 8 - 4
ent/runtime/runtime.go

@@ -240,19 +240,19 @@ func init() {
 	// messagerecords.DefaultContent holds the default value on creation for the content field.
 	messagerecords.DefaultContent = messagerecordsDescContent.Default.(string)
 	// messagerecordsDescErrorDetail is the schema descriptor for error_detail field.
-	messagerecordsDescErrorDetail := messagerecordsFields[6].Descriptor()
+	messagerecordsDescErrorDetail := messagerecordsFields[7].Descriptor()
 	// messagerecords.DefaultErrorDetail holds the default value on creation for the error_detail field.
 	messagerecords.DefaultErrorDetail = messagerecordsDescErrorDetail.Default.(string)
 	// messagerecordsDescSourceType is the schema descriptor for source_type field.
-	messagerecordsDescSourceType := messagerecordsFields[8].Descriptor()
+	messagerecordsDescSourceType := messagerecordsFields[9].Descriptor()
 	// messagerecords.DefaultSourceType holds the default value on creation for the source_type field.
 	messagerecords.DefaultSourceType = messagerecordsDescSourceType.Default.(int)
 	// messagerecordsDescSourceID is the schema descriptor for source_id field.
-	messagerecordsDescSourceID := messagerecordsFields[9].Descriptor()
+	messagerecordsDescSourceID := messagerecordsFields[10].Descriptor()
 	// messagerecords.DefaultSourceID holds the default value on creation for the source_id field.
 	messagerecords.DefaultSourceID = messagerecordsDescSourceID.Default.(uint64)
 	// messagerecordsDescSubSourceID is the schema descriptor for sub_source_id field.
-	messagerecordsDescSubSourceID := messagerecordsFields[10].Descriptor()
+	messagerecordsDescSubSourceID := messagerecordsFields[11].Descriptor()
 	// messagerecords.DefaultSubSourceID holds the default value on creation for the sub_source_id field.
 	messagerecords.DefaultSubSourceID = messagerecordsDescSubSourceID.Default.(uint64)
 	serverMixin := schema.Server{}.Mixin()
@@ -313,6 +313,10 @@ func init() {
 	sopnodeDescConditionType := sopnodeFields[3].Descriptor()
 	// sopnode.DefaultConditionType holds the default value on creation for the condition_type field.
 	sopnode.DefaultConditionType = sopnodeDescConditionType.Default.(int)
+	// sopnodeDescNoReplyCondition is the schema descriptor for no_reply_condition field.
+	sopnodeDescNoReplyCondition := sopnodeFields[5].Descriptor()
+	// sopnode.DefaultNoReplyCondition holds the default value on creation for the no_reply_condition field.
+	sopnode.DefaultNoReplyCondition = sopnodeDescNoReplyCondition.Default.(uint64)
 	sopstageMixin := schema.SopStage{}.Mixin()
 	sopstageMixinHooks2 := sopstageMixin[2].Hooks()
 	sopstage.Hooks[0] = sopstageMixinHooks2[0]

+ 4 - 0
ent/schema/message_records.go

@@ -8,6 +8,7 @@ import (
 	"entgo.io/ent/schema/field"
 	"entgo.io/ent/schema/index"
 	"github.com/suyuan32/simple-admin-common/orm/ent/mixins"
+	"wechat-api/ent/custom_types"
 	"wechat-api/ent/schema/localmixin"
 )
 
@@ -35,6 +36,9 @@ func (MessageRecords) Fields() []ent.Field {
 		field.String("content").Default("").
 			Annotations(entsql.WithComments(true)).
 			Comment("发送内容"),
+		field.JSON("meta", custom_types.Meta{}).Optional().
+			Annotations(entsql.WithComments(true)).
+			Comment("元数据"),
 		field.String("error_detail").Default("").
 			Annotations(entsql.WithComments(true)).
 			Comment("异常原因"),

+ 3 - 0
ent/schema/sop_node.go

@@ -33,6 +33,9 @@ func (SopNode) Fields() []ent.Field {
 		field.JSON("condition_list", []string{}).Optional().
 			Annotations(entsql.WithComments(true)).
 			Comment("触发语义列表 当为空时则代表用户回复任意内容后触发"),
+		field.Uint64("no_reply_condition").Default(0).
+			Annotations(entsql.WithComments(true)).
+			Comment("超时触发时间(分钟)"),
 		field.JSON("action_message", []custom_types.Action{}).Optional().
 			Annotations(entsql.WithComments(true)).
 			Comment("命中后发送的消息内容"),

+ 48 - 0
ent/set_not_nil.go

@@ -1040,6 +1040,30 @@ func (mr *MessageRecordsCreate) SetNotNilContent(value *string) *MessageRecordsC
 }
 
 // set field if value's pointer is not nil.
+func (mr *MessageRecordsUpdate) SetNotNilMeta(value *custom_types.Meta) *MessageRecordsUpdate {
+	if value != nil {
+		return mr.SetMeta(*value)
+	}
+	return mr
+}
+
+// set field if value's pointer is not nil.
+func (mr *MessageRecordsUpdateOne) SetNotNilMeta(value *custom_types.Meta) *MessageRecordsUpdateOne {
+	if value != nil {
+		return mr.SetMeta(*value)
+	}
+	return mr
+}
+
+// set field if value's pointer is not nil.
+func (mr *MessageRecordsCreate) SetNotNilMeta(value *custom_types.Meta) *MessageRecordsCreate {
+	if value != nil {
+		return mr.SetMeta(*value)
+	}
+	return mr
+}
+
+// set field if value's pointer is not nil.
 func (mr *MessageRecordsUpdate) SetNotNilErrorDetail(value *string) *MessageRecordsUpdate {
 	if value != nil {
 		return mr.SetErrorDetail(*value)
@@ -1520,6 +1544,30 @@ func (sn *SopNodeCreate) SetNotNilConditionList(value []string) *SopNodeCreate {
 }
 
 // set field if value's pointer is not nil.
+func (sn *SopNodeUpdate) SetNotNilNoReplyCondition(value *uint64) *SopNodeUpdate {
+	if value != nil {
+		return sn.SetNoReplyCondition(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeUpdateOne) SetNotNilNoReplyCondition(value *uint64) *SopNodeUpdateOne {
+	if value != nil {
+		return sn.SetNoReplyCondition(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeCreate) SetNotNilNoReplyCondition(value *uint64) *SopNodeCreate {
+	if value != nil {
+		return sn.SetNoReplyCondition(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
 func (sn *SopNodeUpdate) SetNotNilActionMessage(value []custom_types.Action) *SopNodeUpdate {
 	if value != nil {
 		return sn.SetActionMessage(value)

+ 12 - 1
ent/sopnode.go

@@ -38,6 +38,8 @@ type SopNode struct {
 	ConditionType int `json:"condition_type,omitempty"`
 	// 触发语义列表 当为空时则代表用户回复任意内容后触发
 	ConditionList []string `json:"condition_list,omitempty"`
+	// 超时触发时间(分钟)
+	NoReplyCondition uint64 `json:"no_reply_condition,omitempty"`
 	// 命中后发送的消息内容
 	ActionMessage []custom_types.Action `json:"action_message,omitempty"`
 	// 命中后需要打的标签
@@ -86,7 +88,7 @@ func (*SopNode) scanValues(columns []string) ([]any, error) {
 		switch columns[i] {
 		case sopnode.FieldConditionList, sopnode.FieldActionMessage, sopnode.FieldActionLabel:
 			values[i] = new([]byte)
-		case sopnode.FieldID, sopnode.FieldStatus, sopnode.FieldStageID, sopnode.FieldParentID, sopnode.FieldConditionType:
+		case sopnode.FieldID, sopnode.FieldStatus, sopnode.FieldStageID, sopnode.FieldParentID, sopnode.FieldConditionType, sopnode.FieldNoReplyCondition:
 			values[i] = new(sql.NullInt64)
 		case sopnode.FieldName:
 			values[i] = new(sql.NullString)
@@ -169,6 +171,12 @@ func (sn *SopNode) assignValues(columns []string, values []any) error {
 					return fmt.Errorf("unmarshal field condition_list: %w", err)
 				}
 			}
+		case sopnode.FieldNoReplyCondition:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field no_reply_condition", values[i])
+			} else if value.Valid {
+				sn.NoReplyCondition = uint64(value.Int64)
+			}
 		case sopnode.FieldActionMessage:
 			if value, ok := values[i].(*[]byte); !ok {
 				return fmt.Errorf("unexpected type %T for field action_message", values[i])
@@ -258,6 +266,9 @@ func (sn *SopNode) String() string {
 	builder.WriteString("condition_list=")
 	builder.WriteString(fmt.Sprintf("%v", sn.ConditionList))
 	builder.WriteString(", ")
+	builder.WriteString("no_reply_condition=")
+	builder.WriteString(fmt.Sprintf("%v", sn.NoReplyCondition))
+	builder.WriteString(", ")
 	builder.WriteString("action_message=")
 	builder.WriteString(fmt.Sprintf("%v", sn.ActionMessage))
 	builder.WriteString(", ")

+ 10 - 0
ent/sopnode/sopnode.go

@@ -33,6 +33,8 @@ const (
 	FieldConditionType = "condition_type"
 	// FieldConditionList holds the string denoting the condition_list field in the database.
 	FieldConditionList = "condition_list"
+	// FieldNoReplyCondition holds the string denoting the no_reply_condition field in the database.
+	FieldNoReplyCondition = "no_reply_condition"
 	// FieldActionMessage holds the string denoting the action_message field in the database.
 	FieldActionMessage = "action_message"
 	// FieldActionLabel holds the string denoting the action_label field in the database.
@@ -71,6 +73,7 @@ var Columns = []string{
 	FieldName,
 	FieldConditionType,
 	FieldConditionList,
+	FieldNoReplyCondition,
 	FieldActionMessage,
 	FieldActionLabel,
 }
@@ -105,6 +108,8 @@ var (
 	DefaultName string
 	// DefaultConditionType holds the default value on creation for the "condition_type" field.
 	DefaultConditionType int
+	// DefaultNoReplyCondition holds the default value on creation for the "no_reply_condition" field.
+	DefaultNoReplyCondition uint64
 )
 
 // OrderOption defines the ordering options for the SopNode queries.
@@ -155,6 +160,11 @@ func ByConditionType(opts ...sql.OrderTermOption) OrderOption {
 	return sql.OrderByField(FieldConditionType, opts...).ToFunc()
 }
 
+// ByNoReplyCondition orders the results by the no_reply_condition field.
+func ByNoReplyCondition(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldNoReplyCondition, opts...).ToFunc()
+}
+
 // BySopStageField orders the results by sop_stage field.
 func BySopStageField(field string, opts ...sql.OrderTermOption) OrderOption {
 	return func(s *sql.Selector) {

+ 45 - 0
ent/sopnode/where.go

@@ -95,6 +95,11 @@ func ConditionType(v int) predicate.SopNode {
 	return predicate.SopNode(sql.FieldEQ(FieldConditionType, v))
 }
 
+// NoReplyCondition applies equality check predicate on the "no_reply_condition" field. It's identical to NoReplyConditionEQ.
+func NoReplyCondition(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldEQ(FieldNoReplyCondition, v))
+}
+
 // CreatedAtEQ applies the EQ predicate on the "created_at" field.
 func CreatedAtEQ(v time.Time) predicate.SopNode {
 	return predicate.SopNode(sql.FieldEQ(FieldCreatedAt, v))
@@ -450,6 +455,46 @@ func ConditionListNotNil() predicate.SopNode {
 	return predicate.SopNode(sql.FieldNotNull(FieldConditionList))
 }
 
+// NoReplyConditionEQ applies the EQ predicate on the "no_reply_condition" field.
+func NoReplyConditionEQ(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldEQ(FieldNoReplyCondition, v))
+}
+
+// NoReplyConditionNEQ applies the NEQ predicate on the "no_reply_condition" field.
+func NoReplyConditionNEQ(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldNEQ(FieldNoReplyCondition, v))
+}
+
+// NoReplyConditionIn applies the In predicate on the "no_reply_condition" field.
+func NoReplyConditionIn(vs ...uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldIn(FieldNoReplyCondition, vs...))
+}
+
+// NoReplyConditionNotIn applies the NotIn predicate on the "no_reply_condition" field.
+func NoReplyConditionNotIn(vs ...uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldNotIn(FieldNoReplyCondition, vs...))
+}
+
+// NoReplyConditionGT applies the GT predicate on the "no_reply_condition" field.
+func NoReplyConditionGT(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldGT(FieldNoReplyCondition, v))
+}
+
+// NoReplyConditionGTE applies the GTE predicate on the "no_reply_condition" field.
+func NoReplyConditionGTE(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldGTE(FieldNoReplyCondition, v))
+}
+
+// NoReplyConditionLT applies the LT predicate on the "no_reply_condition" field.
+func NoReplyConditionLT(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldLT(FieldNoReplyCondition, v))
+}
+
+// NoReplyConditionLTE applies the LTE predicate on the "no_reply_condition" field.
+func NoReplyConditionLTE(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldLTE(FieldNoReplyCondition, v))
+}
+
 // ActionMessageIsNil applies the IsNil predicate on the "action_message" field.
 func ActionMessageIsNil() predicate.SopNode {
 	return predicate.SopNode(sql.FieldIsNull(FieldActionMessage))

+ 85 - 0
ent/sopnode_create.go

@@ -127,6 +127,20 @@ func (snc *SopNodeCreate) SetConditionList(s []string) *SopNodeCreate {
 	return snc
 }
 
+// SetNoReplyCondition sets the "no_reply_condition" field.
+func (snc *SopNodeCreate) SetNoReplyCondition(u uint64) *SopNodeCreate {
+	snc.mutation.SetNoReplyCondition(u)
+	return snc
+}
+
+// SetNillableNoReplyCondition sets the "no_reply_condition" field if the given value is not nil.
+func (snc *SopNodeCreate) SetNillableNoReplyCondition(u *uint64) *SopNodeCreate {
+	if u != nil {
+		snc.SetNoReplyCondition(*u)
+	}
+	return snc
+}
+
 // SetActionMessage sets the "action_message" field.
 func (snc *SopNodeCreate) SetActionMessage(ct []custom_types.Action) *SopNodeCreate {
 	snc.mutation.SetActionMessage(ct)
@@ -234,6 +248,10 @@ func (snc *SopNodeCreate) defaults() error {
 		v := sopnode.DefaultConditionType
 		snc.mutation.SetConditionType(v)
 	}
+	if _, ok := snc.mutation.NoReplyCondition(); !ok {
+		v := sopnode.DefaultNoReplyCondition
+		snc.mutation.SetNoReplyCondition(v)
+	}
 	return nil
 }
 
@@ -257,6 +275,9 @@ func (snc *SopNodeCreate) check() error {
 	if _, ok := snc.mutation.ConditionType(); !ok {
 		return &ValidationError{Name: "condition_type", err: errors.New(`ent: missing required field "SopNode.condition_type"`)}
 	}
+	if _, ok := snc.mutation.NoReplyCondition(); !ok {
+		return &ValidationError{Name: "no_reply_condition", err: errors.New(`ent: missing required field "SopNode.no_reply_condition"`)}
+	}
 	if _, ok := snc.mutation.SopStageID(); !ok {
 		return &ValidationError{Name: "sop_stage", err: errors.New(`ent: missing required edge "SopNode.sop_stage"`)}
 	}
@@ -325,6 +346,10 @@ func (snc *SopNodeCreate) createSpec() (*SopNode, *sqlgraph.CreateSpec) {
 		_spec.SetField(sopnode.FieldConditionList, field.TypeJSON, value)
 		_node.ConditionList = value
 	}
+	if value, ok := snc.mutation.NoReplyCondition(); ok {
+		_spec.SetField(sopnode.FieldNoReplyCondition, field.TypeUint64, value)
+		_node.NoReplyCondition = value
+	}
 	if value, ok := snc.mutation.ActionMessage(); ok {
 		_spec.SetField(sopnode.FieldActionMessage, field.TypeJSON, value)
 		_node.ActionMessage = value
@@ -550,6 +575,24 @@ func (u *SopNodeUpsert) ClearConditionList() *SopNodeUpsert {
 	return u
 }
 
+// SetNoReplyCondition sets the "no_reply_condition" field.
+func (u *SopNodeUpsert) SetNoReplyCondition(v uint64) *SopNodeUpsert {
+	u.Set(sopnode.FieldNoReplyCondition, v)
+	return u
+}
+
+// UpdateNoReplyCondition sets the "no_reply_condition" field to the value that was provided on create.
+func (u *SopNodeUpsert) UpdateNoReplyCondition() *SopNodeUpsert {
+	u.SetExcluded(sopnode.FieldNoReplyCondition)
+	return u
+}
+
+// AddNoReplyCondition adds v to the "no_reply_condition" field.
+func (u *SopNodeUpsert) AddNoReplyCondition(v uint64) *SopNodeUpsert {
+	u.Add(sopnode.FieldNoReplyCondition, v)
+	return u
+}
+
 // SetActionMessage sets the "action_message" field.
 func (u *SopNodeUpsert) SetActionMessage(v []custom_types.Action) *SopNodeUpsert {
 	u.Set(sopnode.FieldActionMessage, v)
@@ -791,6 +834,27 @@ func (u *SopNodeUpsertOne) ClearConditionList() *SopNodeUpsertOne {
 	})
 }
 
+// SetNoReplyCondition sets the "no_reply_condition" field.
+func (u *SopNodeUpsertOne) SetNoReplyCondition(v uint64) *SopNodeUpsertOne {
+	return u.Update(func(s *SopNodeUpsert) {
+		s.SetNoReplyCondition(v)
+	})
+}
+
+// AddNoReplyCondition adds v to the "no_reply_condition" field.
+func (u *SopNodeUpsertOne) AddNoReplyCondition(v uint64) *SopNodeUpsertOne {
+	return u.Update(func(s *SopNodeUpsert) {
+		s.AddNoReplyCondition(v)
+	})
+}
+
+// UpdateNoReplyCondition sets the "no_reply_condition" field to the value that was provided on create.
+func (u *SopNodeUpsertOne) UpdateNoReplyCondition() *SopNodeUpsertOne {
+	return u.Update(func(s *SopNodeUpsert) {
+		s.UpdateNoReplyCondition()
+	})
+}
+
 // SetActionMessage sets the "action_message" field.
 func (u *SopNodeUpsertOne) SetActionMessage(v []custom_types.Action) *SopNodeUpsertOne {
 	return u.Update(func(s *SopNodeUpsert) {
@@ -1204,6 +1268,27 @@ func (u *SopNodeUpsertBulk) ClearConditionList() *SopNodeUpsertBulk {
 	})
 }
 
+// SetNoReplyCondition sets the "no_reply_condition" field.
+func (u *SopNodeUpsertBulk) SetNoReplyCondition(v uint64) *SopNodeUpsertBulk {
+	return u.Update(func(s *SopNodeUpsert) {
+		s.SetNoReplyCondition(v)
+	})
+}
+
+// AddNoReplyCondition adds v to the "no_reply_condition" field.
+func (u *SopNodeUpsertBulk) AddNoReplyCondition(v uint64) *SopNodeUpsertBulk {
+	return u.Update(func(s *SopNodeUpsert) {
+		s.AddNoReplyCondition(v)
+	})
+}
+
+// UpdateNoReplyCondition sets the "no_reply_condition" field to the value that was provided on create.
+func (u *SopNodeUpsertBulk) UpdateNoReplyCondition() *SopNodeUpsertBulk {
+	return u.Update(func(s *SopNodeUpsert) {
+		s.UpdateNoReplyCondition()
+	})
+}
+
 // SetActionMessage sets the "action_message" field.
 func (u *SopNodeUpsertBulk) SetActionMessage(v []custom_types.Action) *SopNodeUpsertBulk {
 	return u.Update(func(s *SopNodeUpsert) {

+ 54 - 0
ent/sopnode_update.go

@@ -173,6 +173,27 @@ func (snu *SopNodeUpdate) ClearConditionList() *SopNodeUpdate {
 	return snu
 }
 
+// SetNoReplyCondition sets the "no_reply_condition" field.
+func (snu *SopNodeUpdate) SetNoReplyCondition(u uint64) *SopNodeUpdate {
+	snu.mutation.ResetNoReplyCondition()
+	snu.mutation.SetNoReplyCondition(u)
+	return snu
+}
+
+// SetNillableNoReplyCondition sets the "no_reply_condition" field if the given value is not nil.
+func (snu *SopNodeUpdate) SetNillableNoReplyCondition(u *uint64) *SopNodeUpdate {
+	if u != nil {
+		snu.SetNoReplyCondition(*u)
+	}
+	return snu
+}
+
+// AddNoReplyCondition adds u to the "no_reply_condition" field.
+func (snu *SopNodeUpdate) AddNoReplyCondition(u int64) *SopNodeUpdate {
+	snu.mutation.AddNoReplyCondition(u)
+	return snu
+}
+
 // SetActionMessage sets the "action_message" field.
 func (snu *SopNodeUpdate) SetActionMessage(ct []custom_types.Action) *SopNodeUpdate {
 	snu.mutation.SetActionMessage(ct)
@@ -373,6 +394,12 @@ func (snu *SopNodeUpdate) sqlSave(ctx context.Context) (n int, err error) {
 	if snu.mutation.ConditionListCleared() {
 		_spec.ClearField(sopnode.FieldConditionList, field.TypeJSON)
 	}
+	if value, ok := snu.mutation.NoReplyCondition(); ok {
+		_spec.SetField(sopnode.FieldNoReplyCondition, field.TypeUint64, value)
+	}
+	if value, ok := snu.mutation.AddedNoReplyCondition(); ok {
+		_spec.AddField(sopnode.FieldNoReplyCondition, field.TypeUint64, value)
+	}
 	if value, ok := snu.mutation.ActionMessage(); ok {
 		_spec.SetField(sopnode.FieldActionMessage, field.TypeJSON, value)
 	}
@@ -630,6 +657,27 @@ func (snuo *SopNodeUpdateOne) ClearConditionList() *SopNodeUpdateOne {
 	return snuo
 }
 
+// SetNoReplyCondition sets the "no_reply_condition" field.
+func (snuo *SopNodeUpdateOne) SetNoReplyCondition(u uint64) *SopNodeUpdateOne {
+	snuo.mutation.ResetNoReplyCondition()
+	snuo.mutation.SetNoReplyCondition(u)
+	return snuo
+}
+
+// SetNillableNoReplyCondition sets the "no_reply_condition" field if the given value is not nil.
+func (snuo *SopNodeUpdateOne) SetNillableNoReplyCondition(u *uint64) *SopNodeUpdateOne {
+	if u != nil {
+		snuo.SetNoReplyCondition(*u)
+	}
+	return snuo
+}
+
+// AddNoReplyCondition adds u to the "no_reply_condition" field.
+func (snuo *SopNodeUpdateOne) AddNoReplyCondition(u int64) *SopNodeUpdateOne {
+	snuo.mutation.AddNoReplyCondition(u)
+	return snuo
+}
+
 // SetActionMessage sets the "action_message" field.
 func (snuo *SopNodeUpdateOne) SetActionMessage(ct []custom_types.Action) *SopNodeUpdateOne {
 	snuo.mutation.SetActionMessage(ct)
@@ -860,6 +908,12 @@ func (snuo *SopNodeUpdateOne) sqlSave(ctx context.Context) (_node *SopNode, err
 	if snuo.mutation.ConditionListCleared() {
 		_spec.ClearField(sopnode.FieldConditionList, field.TypeJSON)
 	}
+	if value, ok := snuo.mutation.NoReplyCondition(); ok {
+		_spec.SetField(sopnode.FieldNoReplyCondition, field.TypeUint64, value)
+	}
+	if value, ok := snuo.mutation.AddedNoReplyCondition(); ok {
+		_spec.AddField(sopnode.FieldNoReplyCondition, field.TypeUint64, value)
+	}
 	if value, ok := snuo.mutation.ActionMessage(); ok {
 		_spec.SetField(sopnode.FieldActionMessage, field.TypeJSON, value)
 	}

+ 6 - 6
etc/wechat.yaml

@@ -13,7 +13,7 @@ CROSConf:
 Log:
   ServiceName: WechatApiLogger
   Mode: console
-  Path: D:\code\gooki\sa\logs\Wechat\api
+  Path: /Users/songbowen/development/gooki/scrm/gateway-ai
   Level: info
   Compress: false
   KeepDays: 7
@@ -21,7 +21,7 @@ Log:
 
 DatabaseConf:
   Type: mysql
-  Host: vm4
+  Host: mysql-server
   Port: 3306
   DBName: wechat
   Username: root
@@ -33,17 +33,17 @@ DatabaseConf:
 CoreRpc:
   # Target: k8s://default/core-rpc-svc:9101
   Endpoints:
-    - vm4:9101
+    - core-rpc:9101
   Enabled: true
 
 RedisConf:
-  Host: vm4:6379
+  Host: redis-server:6379
 
 CasbinDatabaseConf:
   Type: mysql
-  Host: vm4
+  Host: mysql-server
   Port: 3306
-  DBName: wechat-admin
+  DBName: simple_admin
   Username: root
   Password: simple-admin.
   MaxOpenConn: 100

+ 5 - 0
internal/logic/label_relationship/update_label_relationships_logic.go

@@ -150,6 +150,10 @@ func (l *UpdateLabelRelationshipsLogic) AddLabelRelationships(sopStages []*ent.S
 			sourceType := 3
 			if stage.ActionMessage != nil {
 				for i, message := range stage.ActionMessage {
+					meta := custom_types.Meta{}
+					if message.Meta != nil {
+						meta.Filename = message.Meta.Filename
+					}
 					_, _ = l.svcCtx.DB.MessageRecords.Create().
 						SetNotNilBotWxid(&contact.WxWxid).
 						SetNotNilContactID(&contact.ID).
@@ -157,6 +161,7 @@ func (l *UpdateLabelRelationshipsLogic) AddLabelRelationships(sopStages []*ent.S
 						SetNotNilContactWxid(&contact.Wxid).
 						SetNotNilContentType(&message.Type).
 						SetNotNilContent(&message.Content).
+						SetMeta(meta).
 						SetNotNilSourceType(&sourceType).
 						SetNotNilSourceID(&stage.ID).
 						SetSubSourceID(uint64(i)).

+ 26 - 19
internal/logic/message_records/create_message_records_logic.go

@@ -2,13 +2,14 @@ package message_records
 
 import (
 	"context"
+	"wechat-api/ent/custom_types"
 
 	"wechat-api/internal/svc"
 	"wechat-api/internal/types"
 	"wechat-api/internal/utils/dberrorhandler"
 
-    "github.com/suyuan32/simple-admin-common/msg/errormsg"
-    "github.com/suyuan32/simple-admin-common/utils/pointy"
+	"github.com/suyuan32/simple-admin-common/msg/errormsg"
+	"github.com/suyuan32/simple-admin-common/utils/pointy"
 	"github.com/zeromicro/go-zero/core/logx"
 )
 
@@ -27,24 +28,30 @@ func NewCreateMessageRecordsLogic(ctx context.Context, svcCtx *svc.ServiceContex
 }
 
 func (l *CreateMessageRecordsLogic) CreateMessageRecords(req *types.MessageRecordsInfo) (*types.BaseMsgResp, error) {
-    _, err := l.svcCtx.DB.MessageRecords.Create().
-			SetNotNilStatus(req.Status).
-			SetNotNilBotWxid(req.BotWxid).
-			SetNotNilContactID(req.ContactId).
-			SetNotNilContactType(req.ContactType).
-			SetNotNilContactWxid(req.ContactWxid).
-			SetNotNilContentType(req.ContentType).
-			SetNotNilContent(req.Content).
-			SetNotNilErrorDetail(req.ErrorDetail).
-			SetNotNilSendTime(pointy.GetTimeMilliPointer(req.SendTime)).
-			SetNotNilSourceType(req.SourceType).
-			SetNotNilSourceID(req.SourceId).
-			SetNotNilSubSourceID(req.SubSourceId).
-			Save(l.ctx)
-
-    if err != nil {
+	meta := custom_types.Meta{}
+	if req.Meta != nil {
+		meta.Filename = req.Meta.Filename
+	}
+
+	_, err := l.svcCtx.DB.MessageRecords.Create().
+		SetNotNilStatus(req.Status).
+		SetNotNilBotWxid(req.BotWxid).
+		SetNotNilContactID(req.ContactId).
+		SetNotNilContactType(req.ContactType).
+		SetNotNilContactWxid(req.ContactWxid).
+		SetNotNilContentType(req.ContentType).
+		SetNotNilContent(req.Content).
+		SetMeta(meta).
+		SetNotNilErrorDetail(req.ErrorDetail).
+		SetNotNilSendTime(pointy.GetTimeMilliPointer(req.SendTime)).
+		SetNotNilSourceType(req.SourceType).
+		SetNotNilSourceID(req.SourceId).
+		SetNotNilSubSourceID(req.SubSourceId).
+		Save(l.ctx)
+
+	if err != nil {
 		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
 	}
 
-    return &types.BaseMsgResp{Msg: errormsg.CreateSuccess}, nil
+	return &types.BaseMsgResp{Msg: errormsg.CreateSuccess}, nil
 }

+ 1 - 0
internal/logic/sop_node/create_sop_node_logic.go

@@ -59,6 +59,7 @@ func (l *CreateSopNodeLogic) CreateSopNode(req *types.SopNodeInfo) (*types.SopNo
 		SetNotNilName(req.Name).
 		SetNotNilConditionType(req.ConditionType).
 		SetNotNilConditionList(req.ConditionList).
+		SetNotNilNoReplyCondition(req.NoReplyCondition).
 		SetNotNilActionMessage(actionMessage).
 		SetNotNilActionLabel(req.ActionLabel).
 		Save(l.ctx)

+ 1 - 0
internal/logic/sop_node/update_sop_node_logic.go

@@ -63,6 +63,7 @@ func (l *UpdateSopNodeLogic) UpdateSopNode(req *types.SopNodeInfo) (*types.BaseM
 		SetNotNilName(req.Name).
 		SetNotNilConditionType(req.ConditionType).
 		SetNotNilConditionList(req.ConditionList).
+		SetNotNilNoReplyCondition(req.NoReplyCondition).
 		SetNotNilActionMessage(actionMessage).
 		SetNotNilActionLabel(req.ActionLabel).
 		Exec(l.ctx)

+ 0 - 1
internal/logic/sop_task/get_sop_task_list_logic.go

@@ -2,7 +2,6 @@ package sop_task
 
 import (
 	"context"
-
 	"wechat-api/ent/predicate"
 	"wechat-api/ent/soptask"
 	"wechat-api/internal/svc"

+ 14 - 1
internal/logic/sop_task/publish_sop_task_logic.go

@@ -81,7 +81,9 @@ func (l *PublishSopTaskLogic) PublishSopTask(req *types.IDReq) (resp *types.Base
 				var predicates []predicate.Contact
 
 				for _, condition := range stage.ConditionList {
-					subPredicate := contact.HasContactRelationshipsWith(labelrelationship.LabelIDIn(condition.LabelIdList...))
+					subPredicate := contact.HasContactRelationshipsWith(
+						labelrelationship.LabelIDIn(condition.LabelIdList...),
+						labelrelationship.DeletedAtIsNil())
 					if condition.Equal == 2 {
 						subPredicate = contact.Not(subPredicate)
 					}
@@ -108,6 +110,11 @@ func (l *PublishSopTaskLogic) PublishSopTask(req *types.IDReq) (resp *types.Base
 					// 判断联系人所属微信是否包含在任务当中
 					if sopTask.BotWxidList == nil || (sopTask.BotWxidList != nil && valueInArray(c.WxWxid, sopTask.BotWxidList)) {
 						for i, message := range stage.ActionMessage {
+							meta := custom_types.Meta{}
+							if message.Meta != nil {
+								meta.Filename = message.Meta.Filename
+							}
+
 							_, _ = l.svcCtx.DB.MessageRecords.Create().
 								SetNotNilBotWxid(&c.WxWxid).
 								SetNotNilContactID(&c.ID).
@@ -115,6 +122,7 @@ func (l *PublishSopTaskLogic) PublishSopTask(req *types.IDReq) (resp *types.Base
 								SetNotNilContactWxid(&c.Wxid).
 								SetNotNilContentType(&message.Type).
 								SetNotNilContent(&message.Content).
+								SetMeta(meta).
 								SetNotNilSourceType(&sourceType).
 								SetNotNilSourceID(&stage.ID).
 								SetSubSourceID(uint64(i)).
@@ -227,6 +235,10 @@ func (l *PublishSopTaskLogic) AddLabelRelationships(sopStages []*ent.SopStage, c
 			sourceType := 3
 			if stage.ActionMessage != nil {
 				for i, message := range stage.ActionMessage {
+					meta := custom_types.Meta{}
+					if message.Meta != nil {
+						meta.Filename = message.Meta.Filename
+					}
 					_, _ = l.svcCtx.DB.MessageRecords.Create().
 						SetNotNilBotWxid(&contact.WxWxid).
 						SetNotNilContactID(&contact.ID).
@@ -234,6 +246,7 @@ func (l *PublishSopTaskLogic) AddLabelRelationships(sopStages []*ent.SopStage, c
 						SetNotNilContactWxid(&contact.Wxid).
 						SetNotNilContentType(&message.Type).
 						SetNotNilContent(&message.Content).
+						SetMeta(meta).
 						SetNotNilSourceType(&sourceType).
 						SetNotNilSourceID(&stage.ID).
 						SetSubSourceID(uint64(i)).

+ 9 - 0
internal/types/types.go

@@ -228,6 +228,11 @@ type Condition struct {
 type Action struct {
 	Type    int    `json:"type"`
 	Content string `json:"content"`
+	Meta    Meta   `json:"meta,optional"`
+}
+
+type Meta struct {
+	Filename string `json:"filename,optional"`
 }
 
 // The response data of server information | Server信息
@@ -792,6 +797,8 @@ type SopNodeInfo struct {
 	ConditionType *int `json:"conditionType,optional"`
 	// 触发语义列表 当为空时则代表用户回复任意内容后触发
 	ConditionList []string `json:"conditionList,optional"`
+	// 超时触发时间(分钟)
+	NoReplyCondition *uint64 `json:"noReplyCondition,optional"`
 	// 命中后发送的消息内容
 	ActionMessage []Action `json:"actionMessage,optional"`
 	// 命中后需要打的标签
@@ -912,6 +919,8 @@ type MessageRecordsInfo struct {
 	ContentType *int `json:"contentType,optional"`
 	// 发送内容
 	Content *string `json:"content,optional"`
+	// 元数据
+	Meta *Meta `json:"meta,optional"`
 	// 异常原因
 	ErrorDetail *string `json:"errorDetail,optional"`
 	// 发送时间

+ 1 - 1
wechat.go

@@ -38,7 +38,7 @@ var configFile = flag.String("f", "etc/wechat.yaml", "the config file")
 
 func main() {
 	flag.Parse()
-
+	
 	var c config.Config
 	conf.MustLoad(*configFile, &c, conf.UseEnv())