Преглед изворни кода

Merge branch 'yhg_200228' into debug

jimmyyem пре 1 месец
родитељ
комит
3780fa3524
37 измењених фајлова са 6667 додато и 107 уклоњено
  1. 2 1
      desc/all.api
  2. 104 0
      desc/wechat/xunji.api
  3. 147 4
      ent/client.go
  4. 2 0
      ent/ent.go
  5. 12 0
      ent/hook/hook.go
  6. 30 0
      ent/intercept/intercept.go
  7. 39 0
      ent/migrate/schema.go
  8. 1164 0
      ent/mutation.go
  9. 82 0
      ent/pagination.go
  10. 3 0
      ent/predicate/predicate.go
  11. 38 0
      ent/runtime/runtime.go
  12. 56 0
      ent/schema/xunji.go
  13. 288 0
      ent/set_not_nil.go
  14. 3 0
      ent/tx.go
  15. 238 0
      ent/xunji.go
  16. 870 0
      ent/xunji/where.go
  17. 170 0
      ent/xunji/xunji.go
  18. 1303 0
      ent/xunji_create.go
  19. 88 0
      ent/xunji_delete.go
  20. 526 0
      ent/xunji_query.go
  21. 756 0
      ent/xunji_update.go
  22. 36 0
      internal/handler/routes.go
  23. 44 0
      internal/handler/xunji/create_xunji_handler.go
  24. 44 0
      internal/handler/xunji/delete_xunji_handler.go
  25. 44 0
      internal/handler/xunji/get_xunji_by_id_handler.go
  26. 44 0
      internal/handler/xunji/get_xunji_list_handler.go
  27. 44 0
      internal/handler/xunji/update_xunji_handler.go
  28. 2 79
      internal/logic/agent/upload_agent_data_logic.go
  29. 62 0
      internal/logic/base/init_api_data.go
  30. 11 23
      internal/logic/contact/import_whatsapp_contact_logic.go
  31. 50 0
      internal/logic/xunji/create_xunji_logic.go
  32. 37 0
      internal/logic/xunji/delete_xunji_logic.go
  33. 60 0
      internal/logic/xunji/get_xunji_by_id_logic.go
  34. 75 0
      internal/logic/xunji/get_xunji_list_logic.go
  35. 46 0
      internal/logic/xunji/update_xunji_logic.go
  36. 62 0
      internal/types/types.go
  37. 85 0
      internal/utils/charset.go

+ 2 - 1
desc/all.api

@@ -42,4 +42,5 @@ import "./wechat/credit_usage.api"
 import "./wechat/pay_recharge.api"
 import "./wechat/whatsapp.api"
 import "./wechat/whatsapp_channel.api"
-import "./wp_wecom/send_msg.api"
+import "./wp_wecom/send_msg.api"
+import "./wechat/xunji.api"

+ 104 - 0
desc/wechat/xunji.api

@@ -0,0 +1,104 @@
+import "../base.api"
+
+type (
+    // The data of xunji information | Xunji信息
+    XunjiInfo {
+        BaseIDInfo
+
+        // Status 1: normal 2: ban | 状态 1 正常 2 禁用 
+        Status  *uint8 `json:"status,optional"`
+
+        // AppKey 
+        AppKey  *string `json:"appKey,optional"`
+
+        // AppSecret 
+        AppSecret  *string `json:"appSecret,optional"`
+
+        // Token 
+        Token  *string `json:"token,optional"`
+
+        // 加密key 
+        EncodingKey  *string `json:"encodingKey,optional"`
+
+        // 角色ID 
+        AgentId  *uint64 `json:"agentId,optional"`
+
+        // organization_id | 租户ID 
+        OrganizationId  *uint64 `json:"organizationId,optional"`
+
+        // 微信ID 
+        Wxid  *string `json:"wxid,optional"`
+
+        // 大模型服务地址 
+        ApiBase  *string `json:"apiBase,optional"`
+
+        // 大模型服务密钥 
+        ApiKey  *string `json:"apiKey,optional"`
+    }
+
+    // The response data of xunji list | Xunji列表数据
+    XunjiListResp {
+        BaseDataInfo
+
+        // Xunji list data | Xunji列表数据
+        Data XunjiListInfo `json:"data"`
+    }
+
+    // Xunji list data | Xunji列表数据
+    XunjiListInfo {
+        BaseListInfo
+
+        // The API list data | Xunji列表数据
+        Data  []XunjiInfo  `json:"data"`
+    }
+
+    // Get xunji list request params | Xunji列表请求参数
+    XunjiListReq {
+        PageInfo
+
+        // AppKey 
+        AppKey  *string `json:"appKey,optional"`
+
+        // AppSecret 
+        AppSecret  *string `json:"appSecret,optional"`
+
+        // Token 
+        Token  *string `json:"token,optional"`
+    }
+
+    // Xunji information response | Xunji信息返回体
+    XunjiInfoResp {
+        BaseDataInfo
+
+        // Xunji information | Xunji数据
+        Data XunjiInfo `json:"data"`
+    }
+)
+
+@server(
+    jwt: Auth
+    group: xunji
+    middleware: Authority
+)
+
+service Wechat {
+    // Create xunji information | 创建Xunji
+    @handler createXunji
+    post /xunji/create (XunjiInfo) returns (BaseMsgResp)
+
+    // Update xunji information | 更新Xunji
+    @handler updateXunji
+    post /xunji/update (XunjiInfo) returns (BaseMsgResp)
+
+    // Delete xunji information | 删除Xunji信息
+    @handler deleteXunji
+    post /xunji/delete (IDsReq) returns (BaseMsgResp)
+
+    // Get xunji list | 获取Xunji列表
+    @handler getXunjiList
+    post /xunji/list (XunjiListReq) returns (XunjiListResp)
+
+    // Get xunji by ID | 通过ID获取Xunji
+    @handler getXunjiById
+    post /xunji (IDReq) returns (XunjiInfoResp)
+}

+ 147 - 4
ent/client.go

@@ -51,6 +51,7 @@ import (
 	"wechat-api/ent/wxcard"
 	"wechat-api/ent/wxcarduser"
 	"wechat-api/ent/wxcardvisit"
+	"wechat-api/ent/xunji"
 
 	"entgo.io/ent"
 	"entgo.io/ent/dialect"
@@ -145,6 +146,8 @@ type Client struct {
 	WxCardUser *WxCardUserClient
 	// WxCardVisit is the client for interacting with the WxCardVisit builders.
 	WxCardVisit *WxCardVisitClient
+	// Xunji is the client for interacting with the Xunji builders.
+	Xunji *XunjiClient
 }
 
 // NewClient creates a new client configured with the given options.
@@ -196,6 +199,7 @@ func (c *Client) init() {
 	c.WxCard = NewWxCardClient(c.config)
 	c.WxCardUser = NewWxCardUserClient(c.config)
 	c.WxCardVisit = NewWxCardVisitClient(c.config)
+	c.Xunji = NewXunjiClient(c.config)
 }
 
 type (
@@ -328,6 +332,7 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) {
 		WxCard:              NewWxCardClient(cfg),
 		WxCardUser:          NewWxCardUserClient(cfg),
 		WxCardVisit:         NewWxCardVisitClient(cfg),
+		Xunji:               NewXunjiClient(cfg),
 	}, nil
 }
 
@@ -387,6 +392,7 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error)
 		WxCard:              NewWxCardClient(cfg),
 		WxCardUser:          NewWxCardUserClient(cfg),
 		WxCardVisit:         NewWxCardVisitClient(cfg),
+		Xunji:               NewXunjiClient(cfg),
 	}, nil
 }
 
@@ -423,7 +429,7 @@ func (c *Client) Use(hooks ...Hook) {
 		c.SopStage, c.SopTask, c.Token, c.Tutorial, c.UsageDetail, c.UsageStatisticDay,
 		c.UsageStatisticHour, c.UsageStatisticMonth, c.UsageTotal, c.Whatsapp,
 		c.WhatsappChannel, c.WorkExperience, c.WpChatroom, c.WpChatroomMember, c.Wx,
-		c.WxCard, c.WxCardUser, c.WxCardVisit,
+		c.WxCard, c.WxCardUser, c.WxCardVisit, c.Xunji,
 	} {
 		n.Use(hooks...)
 	}
@@ -440,7 +446,7 @@ func (c *Client) Intercept(interceptors ...Interceptor) {
 		c.SopStage, c.SopTask, c.Token, c.Tutorial, c.UsageDetail, c.UsageStatisticDay,
 		c.UsageStatisticHour, c.UsageStatisticMonth, c.UsageTotal, c.Whatsapp,
 		c.WhatsappChannel, c.WorkExperience, c.WpChatroom, c.WpChatroomMember, c.Wx,
-		c.WxCard, c.WxCardUser, c.WxCardVisit,
+		c.WxCard, c.WxCardUser, c.WxCardVisit, c.Xunji,
 	} {
 		n.Intercept(interceptors...)
 	}
@@ -529,6 +535,8 @@ func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) {
 		return c.WxCardUser.mutate(ctx, m)
 	case *WxCardVisitMutation:
 		return c.WxCardVisit.mutate(ctx, m)
+	case *XunjiMutation:
+		return c.Xunji.mutate(ctx, m)
 	default:
 		return nil, fmt.Errorf("ent: unknown mutation type %T", m)
 	}
@@ -6348,6 +6356,141 @@ func (c *WxCardVisitClient) mutate(ctx context.Context, m *WxCardVisitMutation)
 	}
 }
 
+// XunjiClient is a client for the Xunji schema.
+type XunjiClient struct {
+	config
+}
+
+// NewXunjiClient returns a client for the Xunji from the given config.
+func NewXunjiClient(c config) *XunjiClient {
+	return &XunjiClient{config: c}
+}
+
+// Use adds a list of mutation hooks to the hooks stack.
+// A call to `Use(f, g, h)` equals to `xunji.Hooks(f(g(h())))`.
+func (c *XunjiClient) Use(hooks ...Hook) {
+	c.hooks.Xunji = append(c.hooks.Xunji, hooks...)
+}
+
+// Intercept adds a list of query interceptors to the interceptors stack.
+// A call to `Intercept(f, g, h)` equals to `xunji.Intercept(f(g(h())))`.
+func (c *XunjiClient) Intercept(interceptors ...Interceptor) {
+	c.inters.Xunji = append(c.inters.Xunji, interceptors...)
+}
+
+// Create returns a builder for creating a Xunji entity.
+func (c *XunjiClient) Create() *XunjiCreate {
+	mutation := newXunjiMutation(c.config, OpCreate)
+	return &XunjiCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// CreateBulk returns a builder for creating a bulk of Xunji entities.
+func (c *XunjiClient) CreateBulk(builders ...*XunjiCreate) *XunjiCreateBulk {
+	return &XunjiCreateBulk{config: c.config, builders: builders}
+}
+
+// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
+// a builder and applies setFunc on it.
+func (c *XunjiClient) MapCreateBulk(slice any, setFunc func(*XunjiCreate, int)) *XunjiCreateBulk {
+	rv := reflect.ValueOf(slice)
+	if rv.Kind() != reflect.Slice {
+		return &XunjiCreateBulk{err: fmt.Errorf("calling to XunjiClient.MapCreateBulk with wrong type %T, need slice", slice)}
+	}
+	builders := make([]*XunjiCreate, rv.Len())
+	for i := 0; i < rv.Len(); i++ {
+		builders[i] = c.Create()
+		setFunc(builders[i], i)
+	}
+	return &XunjiCreateBulk{config: c.config, builders: builders}
+}
+
+// Update returns an update builder for Xunji.
+func (c *XunjiClient) Update() *XunjiUpdate {
+	mutation := newXunjiMutation(c.config, OpUpdate)
+	return &XunjiUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// UpdateOne returns an update builder for the given entity.
+func (c *XunjiClient) UpdateOne(x *Xunji) *XunjiUpdateOne {
+	mutation := newXunjiMutation(c.config, OpUpdateOne, withXunji(x))
+	return &XunjiUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// UpdateOneID returns an update builder for the given id.
+func (c *XunjiClient) UpdateOneID(id uint64) *XunjiUpdateOne {
+	mutation := newXunjiMutation(c.config, OpUpdateOne, withXunjiID(id))
+	return &XunjiUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// Delete returns a delete builder for Xunji.
+func (c *XunjiClient) Delete() *XunjiDelete {
+	mutation := newXunjiMutation(c.config, OpDelete)
+	return &XunjiDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// DeleteOne returns a builder for deleting the given entity.
+func (c *XunjiClient) DeleteOne(x *Xunji) *XunjiDeleteOne {
+	return c.DeleteOneID(x.ID)
+}
+
+// DeleteOneID returns a builder for deleting the given entity by its id.
+func (c *XunjiClient) DeleteOneID(id uint64) *XunjiDeleteOne {
+	builder := c.Delete().Where(xunji.ID(id))
+	builder.mutation.id = &id
+	builder.mutation.op = OpDeleteOne
+	return &XunjiDeleteOne{builder}
+}
+
+// Query returns a query builder for Xunji.
+func (c *XunjiClient) Query() *XunjiQuery {
+	return &XunjiQuery{
+		config: c.config,
+		ctx:    &QueryContext{Type: TypeXunji},
+		inters: c.Interceptors(),
+	}
+}
+
+// Get returns a Xunji entity by its id.
+func (c *XunjiClient) Get(ctx context.Context, id uint64) (*Xunji, error) {
+	return c.Query().Where(xunji.ID(id)).Only(ctx)
+}
+
+// GetX is like Get, but panics if an error occurs.
+func (c *XunjiClient) GetX(ctx context.Context, id uint64) *Xunji {
+	obj, err := c.Get(ctx, id)
+	if err != nil {
+		panic(err)
+	}
+	return obj
+}
+
+// Hooks returns the client hooks.
+func (c *XunjiClient) Hooks() []Hook {
+	hooks := c.hooks.Xunji
+	return append(hooks[:len(hooks):len(hooks)], xunji.Hooks[:]...)
+}
+
+// Interceptors returns the client interceptors.
+func (c *XunjiClient) Interceptors() []Interceptor {
+	inters := c.inters.Xunji
+	return append(inters[:len(inters):len(inters)], xunji.Interceptors[:]...)
+}
+
+func (c *XunjiClient) mutate(ctx context.Context, m *XunjiMutation) (Value, error) {
+	switch m.Op() {
+	case OpCreate:
+		return (&XunjiCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpUpdate:
+		return (&XunjiUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpUpdateOne:
+		return (&XunjiUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpDelete, OpDeleteOne:
+		return (&XunjiDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
+	default:
+		return nil, fmt.Errorf("ent: unknown Xunji mutation op: %q", m.Op())
+	}
+}
+
 // hooks and interceptors per client, for fast access.
 type (
 	hooks struct {
@@ -6357,7 +6500,7 @@ type (
 		PayRecharge, Server, SopNode, SopStage, SopTask, Token, Tutorial, UsageDetail,
 		UsageStatisticDay, UsageStatisticHour, UsageStatisticMonth, UsageTotal,
 		Whatsapp, WhatsappChannel, WorkExperience, WpChatroom, WpChatroomMember, Wx,
-		WxCard, WxCardUser, WxCardVisit []ent.Hook
+		WxCard, WxCardUser, WxCardVisit, Xunji []ent.Hook
 	}
 	inters struct {
 		Agent, AgentBase, AliyunAvatar, AllocAgent, BatchMsg, Category, ChatRecords,
@@ -6366,7 +6509,7 @@ type (
 		PayRecharge, Server, SopNode, SopStage, SopTask, Token, Tutorial, UsageDetail,
 		UsageStatisticDay, UsageStatisticHour, UsageStatisticMonth, UsageTotal,
 		Whatsapp, WhatsappChannel, WorkExperience, WpChatroom, WpChatroomMember, Wx,
-		WxCard, WxCardUser, WxCardVisit []ent.Interceptor
+		WxCard, WxCardUser, WxCardVisit, Xunji []ent.Interceptor
 	}
 )
 

+ 2 - 0
ent/ent.go

@@ -48,6 +48,7 @@ import (
 	"wechat-api/ent/wxcard"
 	"wechat-api/ent/wxcarduser"
 	"wechat-api/ent/wxcardvisit"
+	"wechat-api/ent/xunji"
 
 	"entgo.io/ent"
 	"entgo.io/ent/dialect/sql"
@@ -152,6 +153,7 @@ func checkColumn(table, column string) error {
 			wxcard.Table:              wxcard.ValidColumn,
 			wxcarduser.Table:          wxcarduser.ValidColumn,
 			wxcardvisit.Table:         wxcardvisit.ValidColumn,
+			xunji.Table:               xunji.ValidColumn,
 		})
 	})
 	return columnCheck(table, column)

+ 12 - 0
ent/hook/hook.go

@@ -488,6 +488,18 @@ func (f WxCardVisitFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value,
 	return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.WxCardVisitMutation", m)
 }
 
+// The XunjiFunc type is an adapter to allow the use of ordinary
+// function as Xunji mutator.
+type XunjiFunc func(context.Context, *ent.XunjiMutation) (ent.Value, error)
+
+// Mutate calls f(ctx, m).
+func (f XunjiFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
+	if mv, ok := m.(*ent.XunjiMutation); ok {
+		return f(ctx, mv)
+	}
+	return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.XunjiMutation", m)
+}
+
 // Condition is a hook condition function.
 type Condition func(context.Context, ent.Mutation) bool
 

+ 30 - 0
ent/intercept/intercept.go

@@ -47,6 +47,7 @@ import (
 	"wechat-api/ent/wxcard"
 	"wechat-api/ent/wxcarduser"
 	"wechat-api/ent/wxcardvisit"
+	"wechat-api/ent/xunji"
 
 	"entgo.io/ent/dialect/sql"
 )
@@ -1187,6 +1188,33 @@ func (f TraverseWxCardVisit) Traverse(ctx context.Context, q ent.Query) error {
 	return fmt.Errorf("unexpected query type %T. expect *ent.WxCardVisitQuery", q)
 }
 
+// The XunjiFunc type is an adapter to allow the use of ordinary function as a Querier.
+type XunjiFunc func(context.Context, *ent.XunjiQuery) (ent.Value, error)
+
+// Query calls f(ctx, q).
+func (f XunjiFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) {
+	if q, ok := q.(*ent.XunjiQuery); ok {
+		return f(ctx, q)
+	}
+	return nil, fmt.Errorf("unexpected query type %T. expect *ent.XunjiQuery", q)
+}
+
+// The TraverseXunji type is an adapter to allow the use of ordinary function as Traverser.
+type TraverseXunji func(context.Context, *ent.XunjiQuery) error
+
+// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline.
+func (f TraverseXunji) Intercept(next ent.Querier) ent.Querier {
+	return next
+}
+
+// Traverse calls f(ctx, q).
+func (f TraverseXunji) Traverse(ctx context.Context, q ent.Query) error {
+	if q, ok := q.(*ent.XunjiQuery); ok {
+		return f(ctx, q)
+	}
+	return fmt.Errorf("unexpected query type %T. expect *ent.XunjiQuery", q)
+}
+
 // NewQuery returns the generic Query interface for the given typed query.
 func NewQuery(q ent.Query) (Query, error) {
 	switch q := q.(type) {
@@ -1270,6 +1298,8 @@ func NewQuery(q ent.Query) (Query, error) {
 		return &query[*ent.WxCardUserQuery, predicate.WxCardUser, wxcarduser.OrderOption]{typ: ent.TypeWxCardUser, tq: q}, nil
 	case *ent.WxCardVisitQuery:
 		return &query[*ent.WxCardVisitQuery, predicate.WxCardVisit, wxcardvisit.OrderOption]{typ: ent.TypeWxCardVisit, tq: q}, nil
+	case *ent.XunjiQuery:
+		return &query[*ent.XunjiQuery, predicate.Xunji, xunji.OrderOption]{typ: ent.TypeXunji, tq: q}, nil
 	default:
 		return nil, fmt.Errorf("unknown query type %T", q)
 	}

+ 39 - 0
ent/migrate/schema.go

@@ -1376,6 +1376,41 @@ var (
 			},
 		},
 	}
+	// XunjiColumns holds the columns for the "xunji" table.
+	XunjiColumns = []*schema.Column{
+		{Name: "id", Type: field.TypeUint64, Increment: true},
+		{Name: "created_at", Type: field.TypeTime, Comment: "Create Time | 创建日期"},
+		{Name: "updated_at", Type: field.TypeTime, Comment: "Update Time | 修改日期"},
+		{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: "app_key", Type: field.TypeString, Comment: "AppKey"},
+		{Name: "app_secret", Type: field.TypeString, Comment: "AppSecret"},
+		{Name: "token", Type: field.TypeString, Comment: "Token"},
+		{Name: "encoding_key", Type: field.TypeString, Comment: "加密key"},
+		{Name: "agent_id", Type: field.TypeUint64, Comment: "角色ID"},
+		{Name: "organization_id", Type: field.TypeUint64, Comment: "organization_id | 租户ID"},
+		{Name: "wxid", Type: field.TypeString, Comment: "微信ID"},
+		{Name: "api_base", Type: field.TypeString, Nullable: true, Comment: "大模型服务地址", Default: ""},
+		{Name: "api_key", Type: field.TypeString, Nullable: true, Comment: "大模型服务密钥", Default: ""},
+	}
+	// XunjiTable holds the schema information for the "xunji" table.
+	XunjiTable = &schema.Table{
+		Name:       "xunji",
+		Columns:    XunjiColumns,
+		PrimaryKey: []*schema.Column{XunjiColumns[0]},
+		Indexes: []*schema.Index{
+			{
+				Name:    "xunji_app_key_token",
+				Unique:  false,
+				Columns: []*schema.Column{XunjiColumns[5], XunjiColumns[7]},
+			},
+			{
+				Name:    "xunji_wxid",
+				Unique:  false,
+				Columns: []*schema.Column{XunjiColumns[11]},
+			},
+		},
+	}
 	// Tables holds all the tables in the schema.
 	Tables = []*schema.Table{
 		AgentTable,
@@ -1418,6 +1453,7 @@ var (
 		WxCardTable,
 		WxCardUserTable,
 		WxCardVisitTable,
+		XunjiTable,
 	}
 )
 
@@ -1556,4 +1592,7 @@ func init() {
 	WxCardVisitTable.Annotation = &entsql.Annotation{
 		Table: "wx_card_visit",
 	}
+	XunjiTable.Annotation = &entsql.Annotation{
+		Table: "xunji",
+	}
 }

+ 1164 - 0
ent/mutation.go

@@ -50,6 +50,7 @@ import (
 	"wechat-api/ent/wxcard"
 	"wechat-api/ent/wxcarduser"
 	"wechat-api/ent/wxcardvisit"
+	"wechat-api/ent/xunji"
 
 	"entgo.io/ent"
 	"entgo.io/ent/dialect/sql"
@@ -104,6 +105,7 @@ const (
 	TypeWxCard              = "WxCard"
 	TypeWxCardUser          = "WxCardUser"
 	TypeWxCardVisit         = "WxCardVisit"
+	TypeXunji               = "Xunji"
 )
 
 // AgentMutation represents an operation that mutates the Agent nodes in the graph.
@@ -48761,3 +48763,1165 @@ func (m *WxCardVisitMutation) ClearEdge(name string) error {
 func (m *WxCardVisitMutation) ResetEdge(name string) error {
 	return fmt.Errorf("unknown WxCardVisit edge %s", name)
 }
+
+// XunjiMutation represents an operation that mutates the Xunji nodes in the graph.
+type XunjiMutation struct {
+	config
+	op                 Op
+	typ                string
+	id                 *uint64
+	created_at         *time.Time
+	updated_at         *time.Time
+	status             *uint8
+	addstatus          *int8
+	deleted_at         *time.Time
+	app_key            *string
+	app_secret         *string
+	token              *string
+	encoding_key       *string
+	agent_id           *uint64
+	addagent_id        *int64
+	organization_id    *uint64
+	addorganization_id *int64
+	wxid               *string
+	api_base           *string
+	api_key            *string
+	clearedFields      map[string]struct{}
+	done               bool
+	oldValue           func(context.Context) (*Xunji, error)
+	predicates         []predicate.Xunji
+}
+
+var _ ent.Mutation = (*XunjiMutation)(nil)
+
+// xunjiOption allows management of the mutation configuration using functional options.
+type xunjiOption func(*XunjiMutation)
+
+// newXunjiMutation creates new mutation for the Xunji entity.
+func newXunjiMutation(c config, op Op, opts ...xunjiOption) *XunjiMutation {
+	m := &XunjiMutation{
+		config:        c,
+		op:            op,
+		typ:           TypeXunji,
+		clearedFields: make(map[string]struct{}),
+	}
+	for _, opt := range opts {
+		opt(m)
+	}
+	return m
+}
+
+// withXunjiID sets the ID field of the mutation.
+func withXunjiID(id uint64) xunjiOption {
+	return func(m *XunjiMutation) {
+		var (
+			err   error
+			once  sync.Once
+			value *Xunji
+		)
+		m.oldValue = func(ctx context.Context) (*Xunji, error) {
+			once.Do(func() {
+				if m.done {
+					err = errors.New("querying old values post mutation is not allowed")
+				} else {
+					value, err = m.Client().Xunji.Get(ctx, id)
+				}
+			})
+			return value, err
+		}
+		m.id = &id
+	}
+}
+
+// withXunji sets the old Xunji of the mutation.
+func withXunji(node *Xunji) xunjiOption {
+	return func(m *XunjiMutation) {
+		m.oldValue = func(context.Context) (*Xunji, error) {
+			return node, nil
+		}
+		m.id = &node.ID
+	}
+}
+
+// Client returns a new `ent.Client` from the mutation. If the mutation was
+// executed in a transaction (ent.Tx), a transactional client is returned.
+func (m XunjiMutation) Client() *Client {
+	client := &Client{config: m.config}
+	client.init()
+	return client
+}
+
+// Tx returns an `ent.Tx` for mutations that were executed in transactions;
+// it returns an error otherwise.
+func (m XunjiMutation) Tx() (*Tx, error) {
+	if _, ok := m.driver.(*txDriver); !ok {
+		return nil, errors.New("ent: mutation is not running in a transaction")
+	}
+	tx := &Tx{config: m.config}
+	tx.init()
+	return tx, nil
+}
+
+// SetID sets the value of the id field. Note that this
+// operation is only accepted on creation of Xunji entities.
+func (m *XunjiMutation) SetID(id uint64) {
+	m.id = &id
+}
+
+// ID returns the ID value in the mutation. Note that the ID is only available
+// if it was provided to the builder or after it was returned from the database.
+func (m *XunjiMutation) ID() (id uint64, exists bool) {
+	if m.id == nil {
+		return
+	}
+	return *m.id, true
+}
+
+// IDs queries the database and returns the entity ids that match the mutation's predicate.
+// That means, if the mutation is applied within a transaction with an isolation level such
+// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated
+// or updated by the mutation.
+func (m *XunjiMutation) IDs(ctx context.Context) ([]uint64, error) {
+	switch {
+	case m.op.Is(OpUpdateOne | OpDeleteOne):
+		id, exists := m.ID()
+		if exists {
+			return []uint64{id}, nil
+		}
+		fallthrough
+	case m.op.Is(OpUpdate | OpDelete):
+		return m.Client().Xunji.Query().Where(m.predicates...).IDs(ctx)
+	default:
+		return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op)
+	}
+}
+
+// SetCreatedAt sets the "created_at" field.
+func (m *XunjiMutation) SetCreatedAt(t time.Time) {
+	m.created_at = &t
+}
+
+// CreatedAt returns the value of the "created_at" field in the mutation.
+func (m *XunjiMutation) CreatedAt() (r time.Time, exists bool) {
+	v := m.created_at
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldCreatedAt returns the old "created_at" field's value of the Xunji entity.
+// If the Xunji 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 *XunjiMutation) OldCreatedAt(ctx context.Context) (v time.Time, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldCreatedAt is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldCreatedAt requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldCreatedAt: %w", err)
+	}
+	return oldValue.CreatedAt, nil
+}
+
+// ResetCreatedAt resets all changes to the "created_at" field.
+func (m *XunjiMutation) ResetCreatedAt() {
+	m.created_at = nil
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (m *XunjiMutation) SetUpdatedAt(t time.Time) {
+	m.updated_at = &t
+}
+
+// UpdatedAt returns the value of the "updated_at" field in the mutation.
+func (m *XunjiMutation) UpdatedAt() (r time.Time, exists bool) {
+	v := m.updated_at
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldUpdatedAt returns the old "updated_at" field's value of the Xunji entity.
+// If the Xunji 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 *XunjiMutation) OldUpdatedAt(ctx context.Context) (v time.Time, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldUpdatedAt is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldUpdatedAt requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldUpdatedAt: %w", err)
+	}
+	return oldValue.UpdatedAt, nil
+}
+
+// ResetUpdatedAt resets all changes to the "updated_at" field.
+func (m *XunjiMutation) ResetUpdatedAt() {
+	m.updated_at = nil
+}
+
+// SetStatus sets the "status" field.
+func (m *XunjiMutation) SetStatus(u uint8) {
+	m.status = &u
+	m.addstatus = nil
+}
+
+// Status returns the value of the "status" field in the mutation.
+func (m *XunjiMutation) Status() (r uint8, exists bool) {
+	v := m.status
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldStatus returns the old "status" field's value of the Xunji entity.
+// If the Xunji 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 *XunjiMutation) OldStatus(ctx context.Context) (v uint8, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldStatus is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldStatus requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldStatus: %w", err)
+	}
+	return oldValue.Status, nil
+}
+
+// AddStatus adds u to the "status" field.
+func (m *XunjiMutation) AddStatus(u int8) {
+	if m.addstatus != nil {
+		*m.addstatus += u
+	} else {
+		m.addstatus = &u
+	}
+}
+
+// AddedStatus returns the value that was added to the "status" field in this mutation.
+func (m *XunjiMutation) AddedStatus() (r int8, exists bool) {
+	v := m.addstatus
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// ClearStatus clears the value of the "status" field.
+func (m *XunjiMutation) ClearStatus() {
+	m.status = nil
+	m.addstatus = nil
+	m.clearedFields[xunji.FieldStatus] = struct{}{}
+}
+
+// StatusCleared returns if the "status" field was cleared in this mutation.
+func (m *XunjiMutation) StatusCleared() bool {
+	_, ok := m.clearedFields[xunji.FieldStatus]
+	return ok
+}
+
+// ResetStatus resets all changes to the "status" field.
+func (m *XunjiMutation) ResetStatus() {
+	m.status = nil
+	m.addstatus = nil
+	delete(m.clearedFields, xunji.FieldStatus)
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (m *XunjiMutation) SetDeletedAt(t time.Time) {
+	m.deleted_at = &t
+}
+
+// DeletedAt returns the value of the "deleted_at" field in the mutation.
+func (m *XunjiMutation) DeletedAt() (r time.Time, exists bool) {
+	v := m.deleted_at
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldDeletedAt returns the old "deleted_at" field's value of the Xunji entity.
+// If the Xunji 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 *XunjiMutation) OldDeletedAt(ctx context.Context) (v time.Time, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldDeletedAt is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldDeletedAt requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldDeletedAt: %w", err)
+	}
+	return oldValue.DeletedAt, nil
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (m *XunjiMutation) ClearDeletedAt() {
+	m.deleted_at = nil
+	m.clearedFields[xunji.FieldDeletedAt] = struct{}{}
+}
+
+// DeletedAtCleared returns if the "deleted_at" field was cleared in this mutation.
+func (m *XunjiMutation) DeletedAtCleared() bool {
+	_, ok := m.clearedFields[xunji.FieldDeletedAt]
+	return ok
+}
+
+// ResetDeletedAt resets all changes to the "deleted_at" field.
+func (m *XunjiMutation) ResetDeletedAt() {
+	m.deleted_at = nil
+	delete(m.clearedFields, xunji.FieldDeletedAt)
+}
+
+// SetAppKey sets the "app_key" field.
+func (m *XunjiMutation) SetAppKey(s string) {
+	m.app_key = &s
+}
+
+// AppKey returns the value of the "app_key" field in the mutation.
+func (m *XunjiMutation) AppKey() (r string, exists bool) {
+	v := m.app_key
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldAppKey returns the old "app_key" field's value of the Xunji entity.
+// If the Xunji 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 *XunjiMutation) OldAppKey(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldAppKey is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldAppKey requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldAppKey: %w", err)
+	}
+	return oldValue.AppKey, nil
+}
+
+// ResetAppKey resets all changes to the "app_key" field.
+func (m *XunjiMutation) ResetAppKey() {
+	m.app_key = nil
+}
+
+// SetAppSecret sets the "app_secret" field.
+func (m *XunjiMutation) SetAppSecret(s string) {
+	m.app_secret = &s
+}
+
+// AppSecret returns the value of the "app_secret" field in the mutation.
+func (m *XunjiMutation) AppSecret() (r string, exists bool) {
+	v := m.app_secret
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldAppSecret returns the old "app_secret" field's value of the Xunji entity.
+// If the Xunji 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 *XunjiMutation) OldAppSecret(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldAppSecret is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldAppSecret requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldAppSecret: %w", err)
+	}
+	return oldValue.AppSecret, nil
+}
+
+// ResetAppSecret resets all changes to the "app_secret" field.
+func (m *XunjiMutation) ResetAppSecret() {
+	m.app_secret = nil
+}
+
+// SetToken sets the "token" field.
+func (m *XunjiMutation) SetToken(s string) {
+	m.token = &s
+}
+
+// Token returns the value of the "token" field in the mutation.
+func (m *XunjiMutation) Token() (r string, exists bool) {
+	v := m.token
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldToken returns the old "token" field's value of the Xunji entity.
+// If the Xunji 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 *XunjiMutation) OldToken(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldToken is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldToken requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldToken: %w", err)
+	}
+	return oldValue.Token, nil
+}
+
+// ResetToken resets all changes to the "token" field.
+func (m *XunjiMutation) ResetToken() {
+	m.token = nil
+}
+
+// SetEncodingKey sets the "encoding_key" field.
+func (m *XunjiMutation) SetEncodingKey(s string) {
+	m.encoding_key = &s
+}
+
+// EncodingKey returns the value of the "encoding_key" field in the mutation.
+func (m *XunjiMutation) EncodingKey() (r string, exists bool) {
+	v := m.encoding_key
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldEncodingKey returns the old "encoding_key" field's value of the Xunji entity.
+// If the Xunji 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 *XunjiMutation) OldEncodingKey(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldEncodingKey is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldEncodingKey requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldEncodingKey: %w", err)
+	}
+	return oldValue.EncodingKey, nil
+}
+
+// ResetEncodingKey resets all changes to the "encoding_key" field.
+func (m *XunjiMutation) ResetEncodingKey() {
+	m.encoding_key = nil
+}
+
+// SetAgentID sets the "agent_id" field.
+func (m *XunjiMutation) SetAgentID(u uint64) {
+	m.agent_id = &u
+	m.addagent_id = nil
+}
+
+// AgentID returns the value of the "agent_id" field in the mutation.
+func (m *XunjiMutation) AgentID() (r uint64, exists bool) {
+	v := m.agent_id
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldAgentID returns the old "agent_id" field's value of the Xunji entity.
+// If the Xunji 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 *XunjiMutation) OldAgentID(ctx context.Context) (v uint64, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldAgentID is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldAgentID requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldAgentID: %w", err)
+	}
+	return oldValue.AgentID, nil
+}
+
+// AddAgentID adds u to the "agent_id" field.
+func (m *XunjiMutation) AddAgentID(u int64) {
+	if m.addagent_id != nil {
+		*m.addagent_id += u
+	} else {
+		m.addagent_id = &u
+	}
+}
+
+// AddedAgentID returns the value that was added to the "agent_id" field in this mutation.
+func (m *XunjiMutation) AddedAgentID() (r int64, exists bool) {
+	v := m.addagent_id
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// ResetAgentID resets all changes to the "agent_id" field.
+func (m *XunjiMutation) ResetAgentID() {
+	m.agent_id = nil
+	m.addagent_id = nil
+}
+
+// SetOrganizationID sets the "organization_id" field.
+func (m *XunjiMutation) SetOrganizationID(u uint64) {
+	m.organization_id = &u
+	m.addorganization_id = nil
+}
+
+// OrganizationID returns the value of the "organization_id" field in the mutation.
+func (m *XunjiMutation) OrganizationID() (r uint64, exists bool) {
+	v := m.organization_id
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldOrganizationID returns the old "organization_id" field's value of the Xunji entity.
+// If the Xunji 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 *XunjiMutation) OldOrganizationID(ctx context.Context) (v uint64, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldOrganizationID is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldOrganizationID requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldOrganizationID: %w", err)
+	}
+	return oldValue.OrganizationID, nil
+}
+
+// AddOrganizationID adds u to the "organization_id" field.
+func (m *XunjiMutation) AddOrganizationID(u int64) {
+	if m.addorganization_id != nil {
+		*m.addorganization_id += u
+	} else {
+		m.addorganization_id = &u
+	}
+}
+
+// AddedOrganizationID returns the value that was added to the "organization_id" field in this mutation.
+func (m *XunjiMutation) AddedOrganizationID() (r int64, exists bool) {
+	v := m.addorganization_id
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// ResetOrganizationID resets all changes to the "organization_id" field.
+func (m *XunjiMutation) ResetOrganizationID() {
+	m.organization_id = nil
+	m.addorganization_id = nil
+}
+
+// SetWxid sets the "wxid" field.
+func (m *XunjiMutation) SetWxid(s string) {
+	m.wxid = &s
+}
+
+// Wxid returns the value of the "wxid" field in the mutation.
+func (m *XunjiMutation) Wxid() (r string, exists bool) {
+	v := m.wxid
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldWxid returns the old "wxid" field's value of the Xunji entity.
+// If the Xunji 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 *XunjiMutation) OldWxid(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldWxid is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldWxid requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldWxid: %w", err)
+	}
+	return oldValue.Wxid, nil
+}
+
+// ResetWxid resets all changes to the "wxid" field.
+func (m *XunjiMutation) ResetWxid() {
+	m.wxid = nil
+}
+
+// SetAPIBase sets the "api_base" field.
+func (m *XunjiMutation) SetAPIBase(s string) {
+	m.api_base = &s
+}
+
+// APIBase returns the value of the "api_base" field in the mutation.
+func (m *XunjiMutation) APIBase() (r string, exists bool) {
+	v := m.api_base
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldAPIBase returns the old "api_base" field's value of the Xunji entity.
+// If the Xunji 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 *XunjiMutation) OldAPIBase(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldAPIBase is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldAPIBase requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldAPIBase: %w", err)
+	}
+	return oldValue.APIBase, nil
+}
+
+// ClearAPIBase clears the value of the "api_base" field.
+func (m *XunjiMutation) ClearAPIBase() {
+	m.api_base = nil
+	m.clearedFields[xunji.FieldAPIBase] = struct{}{}
+}
+
+// APIBaseCleared returns if the "api_base" field was cleared in this mutation.
+func (m *XunjiMutation) APIBaseCleared() bool {
+	_, ok := m.clearedFields[xunji.FieldAPIBase]
+	return ok
+}
+
+// ResetAPIBase resets all changes to the "api_base" field.
+func (m *XunjiMutation) ResetAPIBase() {
+	m.api_base = nil
+	delete(m.clearedFields, xunji.FieldAPIBase)
+}
+
+// SetAPIKey sets the "api_key" field.
+func (m *XunjiMutation) SetAPIKey(s string) {
+	m.api_key = &s
+}
+
+// APIKey returns the value of the "api_key" field in the mutation.
+func (m *XunjiMutation) APIKey() (r string, exists bool) {
+	v := m.api_key
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldAPIKey returns the old "api_key" field's value of the Xunji entity.
+// If the Xunji 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 *XunjiMutation) OldAPIKey(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldAPIKey is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldAPIKey requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldAPIKey: %w", err)
+	}
+	return oldValue.APIKey, nil
+}
+
+// ClearAPIKey clears the value of the "api_key" field.
+func (m *XunjiMutation) ClearAPIKey() {
+	m.api_key = nil
+	m.clearedFields[xunji.FieldAPIKey] = struct{}{}
+}
+
+// APIKeyCleared returns if the "api_key" field was cleared in this mutation.
+func (m *XunjiMutation) APIKeyCleared() bool {
+	_, ok := m.clearedFields[xunji.FieldAPIKey]
+	return ok
+}
+
+// ResetAPIKey resets all changes to the "api_key" field.
+func (m *XunjiMutation) ResetAPIKey() {
+	m.api_key = nil
+	delete(m.clearedFields, xunji.FieldAPIKey)
+}
+
+// Where appends a list predicates to the XunjiMutation builder.
+func (m *XunjiMutation) Where(ps ...predicate.Xunji) {
+	m.predicates = append(m.predicates, ps...)
+}
+
+// WhereP appends storage-level predicates to the XunjiMutation builder. Using this method,
+// users can use type-assertion to append predicates that do not depend on any generated package.
+func (m *XunjiMutation) WhereP(ps ...func(*sql.Selector)) {
+	p := make([]predicate.Xunji, len(ps))
+	for i := range ps {
+		p[i] = ps[i]
+	}
+	m.Where(p...)
+}
+
+// Op returns the operation name.
+func (m *XunjiMutation) Op() Op {
+	return m.op
+}
+
+// SetOp allows setting the mutation operation.
+func (m *XunjiMutation) SetOp(op Op) {
+	m.op = op
+}
+
+// Type returns the node type of this mutation (Xunji).
+func (m *XunjiMutation) Type() string {
+	return m.typ
+}
+
+// Fields returns all fields that were changed during this mutation. Note that in
+// order to get all numeric fields that were incremented/decremented, call
+// AddedFields().
+func (m *XunjiMutation) Fields() []string {
+	fields := make([]string, 0, 13)
+	if m.created_at != nil {
+		fields = append(fields, xunji.FieldCreatedAt)
+	}
+	if m.updated_at != nil {
+		fields = append(fields, xunji.FieldUpdatedAt)
+	}
+	if m.status != nil {
+		fields = append(fields, xunji.FieldStatus)
+	}
+	if m.deleted_at != nil {
+		fields = append(fields, xunji.FieldDeletedAt)
+	}
+	if m.app_key != nil {
+		fields = append(fields, xunji.FieldAppKey)
+	}
+	if m.app_secret != nil {
+		fields = append(fields, xunji.FieldAppSecret)
+	}
+	if m.token != nil {
+		fields = append(fields, xunji.FieldToken)
+	}
+	if m.encoding_key != nil {
+		fields = append(fields, xunji.FieldEncodingKey)
+	}
+	if m.agent_id != nil {
+		fields = append(fields, xunji.FieldAgentID)
+	}
+	if m.organization_id != nil {
+		fields = append(fields, xunji.FieldOrganizationID)
+	}
+	if m.wxid != nil {
+		fields = append(fields, xunji.FieldWxid)
+	}
+	if m.api_base != nil {
+		fields = append(fields, xunji.FieldAPIBase)
+	}
+	if m.api_key != nil {
+		fields = append(fields, xunji.FieldAPIKey)
+	}
+	return fields
+}
+
+// Field returns the value of a field with the given name. The second boolean
+// return value indicates that this field was not set, or was not defined in the
+// schema.
+func (m *XunjiMutation) Field(name string) (ent.Value, bool) {
+	switch name {
+	case xunji.FieldCreatedAt:
+		return m.CreatedAt()
+	case xunji.FieldUpdatedAt:
+		return m.UpdatedAt()
+	case xunji.FieldStatus:
+		return m.Status()
+	case xunji.FieldDeletedAt:
+		return m.DeletedAt()
+	case xunji.FieldAppKey:
+		return m.AppKey()
+	case xunji.FieldAppSecret:
+		return m.AppSecret()
+	case xunji.FieldToken:
+		return m.Token()
+	case xunji.FieldEncodingKey:
+		return m.EncodingKey()
+	case xunji.FieldAgentID:
+		return m.AgentID()
+	case xunji.FieldOrganizationID:
+		return m.OrganizationID()
+	case xunji.FieldWxid:
+		return m.Wxid()
+	case xunji.FieldAPIBase:
+		return m.APIBase()
+	case xunji.FieldAPIKey:
+		return m.APIKey()
+	}
+	return nil, false
+}
+
+// OldField returns the old value of the field from the database. An error is
+// returned if the mutation operation is not UpdateOne, or the query to the
+// database failed.
+func (m *XunjiMutation) OldField(ctx context.Context, name string) (ent.Value, error) {
+	switch name {
+	case xunji.FieldCreatedAt:
+		return m.OldCreatedAt(ctx)
+	case xunji.FieldUpdatedAt:
+		return m.OldUpdatedAt(ctx)
+	case xunji.FieldStatus:
+		return m.OldStatus(ctx)
+	case xunji.FieldDeletedAt:
+		return m.OldDeletedAt(ctx)
+	case xunji.FieldAppKey:
+		return m.OldAppKey(ctx)
+	case xunji.FieldAppSecret:
+		return m.OldAppSecret(ctx)
+	case xunji.FieldToken:
+		return m.OldToken(ctx)
+	case xunji.FieldEncodingKey:
+		return m.OldEncodingKey(ctx)
+	case xunji.FieldAgentID:
+		return m.OldAgentID(ctx)
+	case xunji.FieldOrganizationID:
+		return m.OldOrganizationID(ctx)
+	case xunji.FieldWxid:
+		return m.OldWxid(ctx)
+	case xunji.FieldAPIBase:
+		return m.OldAPIBase(ctx)
+	case xunji.FieldAPIKey:
+		return m.OldAPIKey(ctx)
+	}
+	return nil, fmt.Errorf("unknown Xunji field %s", name)
+}
+
+// SetField sets the value of a field with the given name. It returns an error if
+// the field is not defined in the schema, or if the type mismatched the field
+// type.
+func (m *XunjiMutation) SetField(name string, value ent.Value) error {
+	switch name {
+	case xunji.FieldCreatedAt:
+		v, ok := value.(time.Time)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetCreatedAt(v)
+		return nil
+	case xunji.FieldUpdatedAt:
+		v, ok := value.(time.Time)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetUpdatedAt(v)
+		return nil
+	case xunji.FieldStatus:
+		v, ok := value.(uint8)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetStatus(v)
+		return nil
+	case xunji.FieldDeletedAt:
+		v, ok := value.(time.Time)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetDeletedAt(v)
+		return nil
+	case xunji.FieldAppKey:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetAppKey(v)
+		return nil
+	case xunji.FieldAppSecret:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetAppSecret(v)
+		return nil
+	case xunji.FieldToken:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetToken(v)
+		return nil
+	case xunji.FieldEncodingKey:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetEncodingKey(v)
+		return nil
+	case xunji.FieldAgentID:
+		v, ok := value.(uint64)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetAgentID(v)
+		return nil
+	case xunji.FieldOrganizationID:
+		v, ok := value.(uint64)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetOrganizationID(v)
+		return nil
+	case xunji.FieldWxid:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetWxid(v)
+		return nil
+	case xunji.FieldAPIBase:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetAPIBase(v)
+		return nil
+	case xunji.FieldAPIKey:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetAPIKey(v)
+		return nil
+	}
+	return fmt.Errorf("unknown Xunji field %s", name)
+}
+
+// AddedFields returns all numeric fields that were incremented/decremented during
+// this mutation.
+func (m *XunjiMutation) AddedFields() []string {
+	var fields []string
+	if m.addstatus != nil {
+		fields = append(fields, xunji.FieldStatus)
+	}
+	if m.addagent_id != nil {
+		fields = append(fields, xunji.FieldAgentID)
+	}
+	if m.addorganization_id != nil {
+		fields = append(fields, xunji.FieldOrganizationID)
+	}
+	return fields
+}
+
+// AddedField returns the numeric value that was incremented/decremented on a field
+// with the given name. The second boolean return value indicates that this field
+// was not set, or was not defined in the schema.
+func (m *XunjiMutation) AddedField(name string) (ent.Value, bool) {
+	switch name {
+	case xunji.FieldStatus:
+		return m.AddedStatus()
+	case xunji.FieldAgentID:
+		return m.AddedAgentID()
+	case xunji.FieldOrganizationID:
+		return m.AddedOrganizationID()
+	}
+	return nil, false
+}
+
+// AddField adds the value to the field with the given name. It returns an error if
+// the field is not defined in the schema, or if the type mismatched the field
+// type.
+func (m *XunjiMutation) AddField(name string, value ent.Value) error {
+	switch name {
+	case xunji.FieldStatus:
+		v, ok := value.(int8)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddStatus(v)
+		return nil
+	case xunji.FieldAgentID:
+		v, ok := value.(int64)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddAgentID(v)
+		return nil
+	case xunji.FieldOrganizationID:
+		v, ok := value.(int64)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddOrganizationID(v)
+		return nil
+	}
+	return fmt.Errorf("unknown Xunji numeric field %s", name)
+}
+
+// ClearedFields returns all nullable fields that were cleared during this
+// mutation.
+func (m *XunjiMutation) ClearedFields() []string {
+	var fields []string
+	if m.FieldCleared(xunji.FieldStatus) {
+		fields = append(fields, xunji.FieldStatus)
+	}
+	if m.FieldCleared(xunji.FieldDeletedAt) {
+		fields = append(fields, xunji.FieldDeletedAt)
+	}
+	if m.FieldCleared(xunji.FieldAPIBase) {
+		fields = append(fields, xunji.FieldAPIBase)
+	}
+	if m.FieldCleared(xunji.FieldAPIKey) {
+		fields = append(fields, xunji.FieldAPIKey)
+	}
+	return fields
+}
+
+// FieldCleared returns a boolean indicating if a field with the given name was
+// cleared in this mutation.
+func (m *XunjiMutation) FieldCleared(name string) bool {
+	_, ok := m.clearedFields[name]
+	return ok
+}
+
+// ClearField clears the value of the field with the given name. It returns an
+// error if the field is not defined in the schema.
+func (m *XunjiMutation) ClearField(name string) error {
+	switch name {
+	case xunji.FieldStatus:
+		m.ClearStatus()
+		return nil
+	case xunji.FieldDeletedAt:
+		m.ClearDeletedAt()
+		return nil
+	case xunji.FieldAPIBase:
+		m.ClearAPIBase()
+		return nil
+	case xunji.FieldAPIKey:
+		m.ClearAPIKey()
+		return nil
+	}
+	return fmt.Errorf("unknown Xunji nullable field %s", name)
+}
+
+// ResetField resets all changes in the mutation for the field with the given name.
+// It returns an error if the field is not defined in the schema.
+func (m *XunjiMutation) ResetField(name string) error {
+	switch name {
+	case xunji.FieldCreatedAt:
+		m.ResetCreatedAt()
+		return nil
+	case xunji.FieldUpdatedAt:
+		m.ResetUpdatedAt()
+		return nil
+	case xunji.FieldStatus:
+		m.ResetStatus()
+		return nil
+	case xunji.FieldDeletedAt:
+		m.ResetDeletedAt()
+		return nil
+	case xunji.FieldAppKey:
+		m.ResetAppKey()
+		return nil
+	case xunji.FieldAppSecret:
+		m.ResetAppSecret()
+		return nil
+	case xunji.FieldToken:
+		m.ResetToken()
+		return nil
+	case xunji.FieldEncodingKey:
+		m.ResetEncodingKey()
+		return nil
+	case xunji.FieldAgentID:
+		m.ResetAgentID()
+		return nil
+	case xunji.FieldOrganizationID:
+		m.ResetOrganizationID()
+		return nil
+	case xunji.FieldWxid:
+		m.ResetWxid()
+		return nil
+	case xunji.FieldAPIBase:
+		m.ResetAPIBase()
+		return nil
+	case xunji.FieldAPIKey:
+		m.ResetAPIKey()
+		return nil
+	}
+	return fmt.Errorf("unknown Xunji field %s", name)
+}
+
+// AddedEdges returns all edge names that were set/added in this mutation.
+func (m *XunjiMutation) AddedEdges() []string {
+	edges := make([]string, 0, 0)
+	return edges
+}
+
+// AddedIDs returns all IDs (to other nodes) that were added for the given edge
+// name in this mutation.
+func (m *XunjiMutation) AddedIDs(name string) []ent.Value {
+	return nil
+}
+
+// RemovedEdges returns all edge names that were removed in this mutation.
+func (m *XunjiMutation) RemovedEdges() []string {
+	edges := make([]string, 0, 0)
+	return edges
+}
+
+// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with
+// the given name in this mutation.
+func (m *XunjiMutation) RemovedIDs(name string) []ent.Value {
+	return nil
+}
+
+// ClearedEdges returns all edge names that were cleared in this mutation.
+func (m *XunjiMutation) ClearedEdges() []string {
+	edges := make([]string, 0, 0)
+	return edges
+}
+
+// EdgeCleared returns a boolean which indicates if the edge with the given name
+// was cleared in this mutation.
+func (m *XunjiMutation) EdgeCleared(name string) bool {
+	return false
+}
+
+// ClearEdge clears the value of the edge with the given name. It returns an error
+// if that edge is not defined in the schema.
+func (m *XunjiMutation) ClearEdge(name string) error {
+	return fmt.Errorf("unknown Xunji unique edge %s", name)
+}
+
+// ResetEdge resets all changes to the edge with the given name in this mutation.
+// It returns an error if the edge is not defined in the schema.
+func (m *XunjiMutation) ResetEdge(name string) error {
+	return fmt.Errorf("unknown Xunji edge %s", name)
+}

+ 82 - 0
ent/pagination.go

@@ -45,6 +45,7 @@ import (
 	"wechat-api/ent/wxcard"
 	"wechat-api/ent/wxcarduser"
 	"wechat-api/ent/wxcardvisit"
+	"wechat-api/ent/xunji"
 )
 
 const errInvalidPage = "INVALID_PAGE"
@@ -3332,3 +3333,84 @@ func (wcv *WxCardVisitQuery) Page(
 
 	return ret, nil
 }
+
+type XunjiPager struct {
+	Order  xunji.OrderOption
+	Filter func(*XunjiQuery) (*XunjiQuery, error)
+}
+
+// XunjiPaginateOption enables pagination customization.
+type XunjiPaginateOption func(*XunjiPager)
+
+// DefaultXunjiOrder is the default ordering of Xunji.
+var DefaultXunjiOrder = Desc(xunji.FieldID)
+
+func newXunjiPager(opts []XunjiPaginateOption) (*XunjiPager, error) {
+	pager := &XunjiPager{}
+	for _, opt := range opts {
+		opt(pager)
+	}
+	if pager.Order == nil {
+		pager.Order = DefaultXunjiOrder
+	}
+	return pager, nil
+}
+
+func (p *XunjiPager) ApplyFilter(query *XunjiQuery) (*XunjiQuery, error) {
+	if p.Filter != nil {
+		return p.Filter(query)
+	}
+	return query, nil
+}
+
+// XunjiPageList is Xunji PageList result.
+type XunjiPageList struct {
+	List        []*Xunji     `json:"list"`
+	PageDetails *PageDetails `json:"pageDetails"`
+}
+
+func (x *XunjiQuery) Page(
+	ctx context.Context, pageNum uint64, pageSize uint64, opts ...XunjiPaginateOption,
+) (*XunjiPageList, error) {
+
+	pager, err := newXunjiPager(opts)
+	if err != nil {
+		return nil, err
+	}
+
+	if x, err = pager.ApplyFilter(x); err != nil {
+		return nil, err
+	}
+
+	ret := &XunjiPageList{}
+
+	ret.PageDetails = &PageDetails{
+		Page: pageNum,
+		Size: pageSize,
+	}
+
+	query := x.Clone()
+	query.ctx.Fields = nil
+	count, err := query.Count(ctx)
+
+	if err != nil {
+		return nil, err
+	}
+
+	ret.PageDetails.Total = uint64(count)
+
+	if pager.Order != nil {
+		x = x.Order(pager.Order)
+	} else {
+		x = x.Order(DefaultXunjiOrder)
+	}
+
+	x = x.Offset(int((pageNum - 1) * pageSize)).Limit(int(pageSize))
+	list, err := x.All(ctx)
+	if err != nil {
+		return nil, err
+	}
+	ret.List = list
+
+	return ret, nil
+}

+ 3 - 0
ent/predicate/predicate.go

@@ -125,3 +125,6 @@ type WxCardUser func(*sql.Selector)
 
 // WxCardVisit is the predicate function for wxcardvisit builders.
 type WxCardVisit func(*sql.Selector)
+
+// Xunji is the predicate function for xunji builders.
+type Xunji func(*sql.Selector)

+ 38 - 0
ent/runtime/runtime.go

@@ -45,6 +45,7 @@ import (
 	"wechat-api/ent/wxcard"
 	"wechat-api/ent/wxcarduser"
 	"wechat-api/ent/wxcardvisit"
+	"wechat-api/ent/xunji"
 )
 
 // The init function reads all schema descriptors with runtime code
@@ -1793,6 +1794,43 @@ func init() {
 	wxcardvisitDescBotType := wxcardvisitFields[2].Descriptor()
 	// wxcardvisit.DefaultBotType holds the default value on creation for the bot_type field.
 	wxcardvisit.DefaultBotType = wxcardvisitDescBotType.Default.(uint8)
+	xunjiMixin := schema.Xunji{}.Mixin()
+	xunjiMixinHooks2 := xunjiMixin[2].Hooks()
+	xunji.Hooks[0] = xunjiMixinHooks2[0]
+	xunjiMixinInters2 := xunjiMixin[2].Interceptors()
+	xunji.Interceptors[0] = xunjiMixinInters2[0]
+	xunjiMixinFields0 := xunjiMixin[0].Fields()
+	_ = xunjiMixinFields0
+	xunjiMixinFields1 := xunjiMixin[1].Fields()
+	_ = xunjiMixinFields1
+	xunjiFields := schema.Xunji{}.Fields()
+	_ = xunjiFields
+	// xunjiDescCreatedAt is the schema descriptor for created_at field.
+	xunjiDescCreatedAt := xunjiMixinFields0[1].Descriptor()
+	// xunji.DefaultCreatedAt holds the default value on creation for the created_at field.
+	xunji.DefaultCreatedAt = xunjiDescCreatedAt.Default.(func() time.Time)
+	// xunjiDescUpdatedAt is the schema descriptor for updated_at field.
+	xunjiDescUpdatedAt := xunjiMixinFields0[2].Descriptor()
+	// xunji.DefaultUpdatedAt holds the default value on creation for the updated_at field.
+	xunji.DefaultUpdatedAt = xunjiDescUpdatedAt.Default.(func() time.Time)
+	// xunji.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
+	xunji.UpdateDefaultUpdatedAt = xunjiDescUpdatedAt.UpdateDefault.(func() time.Time)
+	// xunjiDescStatus is the schema descriptor for status field.
+	xunjiDescStatus := xunjiMixinFields1[0].Descriptor()
+	// xunji.DefaultStatus holds the default value on creation for the status field.
+	xunji.DefaultStatus = xunjiDescStatus.Default.(uint8)
+	// xunjiDescOrganizationID is the schema descriptor for organization_id field.
+	xunjiDescOrganizationID := xunjiFields[5].Descriptor()
+	// xunji.OrganizationIDValidator is a validator for the "organization_id" field. It is called by the builders before save.
+	xunji.OrganizationIDValidator = xunjiDescOrganizationID.Validators[0].(func(uint64) error)
+	// xunjiDescAPIBase is the schema descriptor for api_base field.
+	xunjiDescAPIBase := xunjiFields[7].Descriptor()
+	// xunji.DefaultAPIBase holds the default value on creation for the api_base field.
+	xunji.DefaultAPIBase = xunjiDescAPIBase.Default.(string)
+	// xunjiDescAPIKey is the schema descriptor for api_key field.
+	xunjiDescAPIKey := xunjiFields[8].Descriptor()
+	// xunji.DefaultAPIKey holds the default value on creation for the api_key field.
+	xunji.DefaultAPIKey = xunjiDescAPIKey.Default.(string)
 }
 
 const (

+ 56 - 0
ent/schema/xunji.go

@@ -0,0 +1,56 @@
+package schema
+
+import (
+	"wechat-api/ent/schema/localmixin"
+
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/entsql"
+	"entgo.io/ent/schema"
+	"entgo.io/ent/schema/field"
+	"entgo.io/ent/schema/index"
+	"github.com/suyuan32/simple-admin-common/orm/ent/mixins"
+)
+
+type Xunji struct {
+	ent.Schema
+}
+
+func (Xunji) Fields() []ent.Field {
+	return []ent.Field{
+		field.String("app_key").Comment("AppKey"),
+		field.String("app_secret").Comment("AppSecret"),
+		field.String("token").Comment("Token"),
+		field.String("encoding_key").Comment("加密key"),
+		field.Uint64("agent_id").Comment("角色ID"),
+		field.Uint64("organization_id").Positive().Comment("organization_id | 租户ID"),
+		field.String("wxid").Comment("微信ID"),
+		field.String("api_base").Optional().Default("").Comment("大模型服务地址"),
+		field.String("api_key").Optional().Default("").Comment("大模型服务密钥"),
+	}
+}
+
+func (Xunji) Mixin() []ent.Mixin {
+	return []ent.Mixin{
+		mixins.IDMixin{},
+		mixins.StatusMixin{},
+		localmixin.SoftDeleteMixin{},
+	}
+}
+
+func (Xunji) Indexes() []ent.Index {
+	return []ent.Index{
+		index.Fields("app_key", "token"),
+		index.Fields("wxid"),
+	}
+}
+
+func (Xunji) Edges() []ent.Edge {
+	return []ent.Edge{}
+}
+
+func (Xunji) Annotations() []schema.Annotation {
+	return []schema.Annotation{
+		entsql.WithComments(true),
+		entsql.Annotation{Table: "xunji"},
+	}
+}

+ 288 - 0
ent/set_not_nil.go

@@ -10782,3 +10782,291 @@ func (wcv *WxCardVisitCreate) SetNotNilBotType(value *uint8) *WxCardVisitCreate
 	}
 	return wcv
 }
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdate) SetNotNilUpdatedAt(value *time.Time) *XunjiUpdate {
+	if value != nil {
+		return x.SetUpdatedAt(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdateOne) SetNotNilUpdatedAt(value *time.Time) *XunjiUpdateOne {
+	if value != nil {
+		return x.SetUpdatedAt(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiCreate) SetNotNilUpdatedAt(value *time.Time) *XunjiCreate {
+	if value != nil {
+		return x.SetUpdatedAt(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdate) SetNotNilStatus(value *uint8) *XunjiUpdate {
+	if value != nil {
+		return x.SetStatus(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdateOne) SetNotNilStatus(value *uint8) *XunjiUpdateOne {
+	if value != nil {
+		return x.SetStatus(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiCreate) SetNotNilStatus(value *uint8) *XunjiCreate {
+	if value != nil {
+		return x.SetStatus(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdate) SetNotNilDeletedAt(value *time.Time) *XunjiUpdate {
+	if value != nil {
+		return x.SetDeletedAt(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdateOne) SetNotNilDeletedAt(value *time.Time) *XunjiUpdateOne {
+	if value != nil {
+		return x.SetDeletedAt(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiCreate) SetNotNilDeletedAt(value *time.Time) *XunjiCreate {
+	if value != nil {
+		return x.SetDeletedAt(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdate) SetNotNilAppKey(value *string) *XunjiUpdate {
+	if value != nil {
+		return x.SetAppKey(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdateOne) SetNotNilAppKey(value *string) *XunjiUpdateOne {
+	if value != nil {
+		return x.SetAppKey(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiCreate) SetNotNilAppKey(value *string) *XunjiCreate {
+	if value != nil {
+		return x.SetAppKey(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdate) SetNotNilAppSecret(value *string) *XunjiUpdate {
+	if value != nil {
+		return x.SetAppSecret(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdateOne) SetNotNilAppSecret(value *string) *XunjiUpdateOne {
+	if value != nil {
+		return x.SetAppSecret(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiCreate) SetNotNilAppSecret(value *string) *XunjiCreate {
+	if value != nil {
+		return x.SetAppSecret(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdate) SetNotNilToken(value *string) *XunjiUpdate {
+	if value != nil {
+		return x.SetToken(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdateOne) SetNotNilToken(value *string) *XunjiUpdateOne {
+	if value != nil {
+		return x.SetToken(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiCreate) SetNotNilToken(value *string) *XunjiCreate {
+	if value != nil {
+		return x.SetToken(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdate) SetNotNilEncodingKey(value *string) *XunjiUpdate {
+	if value != nil {
+		return x.SetEncodingKey(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdateOne) SetNotNilEncodingKey(value *string) *XunjiUpdateOne {
+	if value != nil {
+		return x.SetEncodingKey(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiCreate) SetNotNilEncodingKey(value *string) *XunjiCreate {
+	if value != nil {
+		return x.SetEncodingKey(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdate) SetNotNilAgentID(value *uint64) *XunjiUpdate {
+	if value != nil {
+		return x.SetAgentID(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdateOne) SetNotNilAgentID(value *uint64) *XunjiUpdateOne {
+	if value != nil {
+		return x.SetAgentID(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiCreate) SetNotNilAgentID(value *uint64) *XunjiCreate {
+	if value != nil {
+		return x.SetAgentID(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdate) SetNotNilOrganizationID(value *uint64) *XunjiUpdate {
+	if value != nil {
+		return x.SetOrganizationID(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdateOne) SetNotNilOrganizationID(value *uint64) *XunjiUpdateOne {
+	if value != nil {
+		return x.SetOrganizationID(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiCreate) SetNotNilOrganizationID(value *uint64) *XunjiCreate {
+	if value != nil {
+		return x.SetOrganizationID(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdate) SetNotNilWxid(value *string) *XunjiUpdate {
+	if value != nil {
+		return x.SetWxid(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdateOne) SetNotNilWxid(value *string) *XunjiUpdateOne {
+	if value != nil {
+		return x.SetWxid(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiCreate) SetNotNilWxid(value *string) *XunjiCreate {
+	if value != nil {
+		return x.SetWxid(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdate) SetNotNilAPIBase(value *string) *XunjiUpdate {
+	if value != nil {
+		return x.SetAPIBase(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdateOne) SetNotNilAPIBase(value *string) *XunjiUpdateOne {
+	if value != nil {
+		return x.SetAPIBase(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiCreate) SetNotNilAPIBase(value *string) *XunjiCreate {
+	if value != nil {
+		return x.SetAPIBase(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdate) SetNotNilAPIKey(value *string) *XunjiUpdate {
+	if value != nil {
+		return x.SetAPIKey(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiUpdateOne) SetNotNilAPIKey(value *string) *XunjiUpdateOne {
+	if value != nil {
+		return x.SetAPIKey(*value)
+	}
+	return x
+}
+
+// set field if value's pointer is not nil.
+func (x *XunjiCreate) SetNotNilAPIKey(value *string) *XunjiCreate {
+	if value != nil {
+		return x.SetAPIKey(*value)
+	}
+	return x
+}

+ 3 - 0
ent/tx.go

@@ -94,6 +94,8 @@ type Tx struct {
 	WxCardUser *WxCardUserClient
 	// WxCardVisit is the client for interacting with the WxCardVisit builders.
 	WxCardVisit *WxCardVisitClient
+	// Xunji is the client for interacting with the Xunji builders.
+	Xunji *XunjiClient
 
 	// lazily loaded.
 	client     *Client
@@ -265,6 +267,7 @@ func (tx *Tx) init() {
 	tx.WxCard = NewWxCardClient(tx.config)
 	tx.WxCardUser = NewWxCardUserClient(tx.config)
 	tx.WxCardVisit = NewWxCardVisitClient(tx.config)
+	tx.Xunji = NewXunjiClient(tx.config)
 }
 
 // txDriver wraps the given dialect.Tx with a nop dialect.Driver implementation.

+ 238 - 0
ent/xunji.go

@@ -0,0 +1,238 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"fmt"
+	"strings"
+	"time"
+	"wechat-api/ent/xunji"
+
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/sql"
+)
+
+// Xunji is the model entity for the Xunji schema.
+type Xunji struct {
+	config `json:"-"`
+	// ID of the ent.
+	ID uint64 `json:"id,omitempty"`
+	// Create Time | 创建日期
+	CreatedAt time.Time `json:"created_at,omitempty"`
+	// Update Time | 修改日期
+	UpdatedAt time.Time `json:"updated_at,omitempty"`
+	// Status 1: normal 2: ban | 状态 1 正常 2 禁用
+	Status uint8 `json:"status,omitempty"`
+	// Delete Time | 删除日期
+	DeletedAt time.Time `json:"deleted_at,omitempty"`
+	// AppKey
+	AppKey string `json:"app_key,omitempty"`
+	// AppSecret
+	AppSecret string `json:"app_secret,omitempty"`
+	// Token
+	Token string `json:"token,omitempty"`
+	// 加密key
+	EncodingKey string `json:"encoding_key,omitempty"`
+	// 角色ID
+	AgentID uint64 `json:"agent_id,omitempty"`
+	// organization_id | 租户ID
+	OrganizationID uint64 `json:"organization_id,omitempty"`
+	// 微信ID
+	Wxid string `json:"wxid,omitempty"`
+	// 大模型服务地址
+	APIBase string `json:"api_base,omitempty"`
+	// 大模型服务密钥
+	APIKey       string `json:"api_key,omitempty"`
+	selectValues sql.SelectValues
+}
+
+// scanValues returns the types for scanning values from sql.Rows.
+func (*Xunji) scanValues(columns []string) ([]any, error) {
+	values := make([]any, len(columns))
+	for i := range columns {
+		switch columns[i] {
+		case xunji.FieldID, xunji.FieldStatus, xunji.FieldAgentID, xunji.FieldOrganizationID:
+			values[i] = new(sql.NullInt64)
+		case xunji.FieldAppKey, xunji.FieldAppSecret, xunji.FieldToken, xunji.FieldEncodingKey, xunji.FieldWxid, xunji.FieldAPIBase, xunji.FieldAPIKey:
+			values[i] = new(sql.NullString)
+		case xunji.FieldCreatedAt, xunji.FieldUpdatedAt, xunji.FieldDeletedAt:
+			values[i] = new(sql.NullTime)
+		default:
+			values[i] = new(sql.UnknownType)
+		}
+	}
+	return values, nil
+}
+
+// assignValues assigns the values that were returned from sql.Rows (after scanning)
+// to the Xunji fields.
+func (x *Xunji) assignValues(columns []string, values []any) error {
+	if m, n := len(values), len(columns); m < n {
+		return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
+	}
+	for i := range columns {
+		switch columns[i] {
+		case xunji.FieldID:
+			value, ok := values[i].(*sql.NullInt64)
+			if !ok {
+				return fmt.Errorf("unexpected type %T for field id", value)
+			}
+			x.ID = uint64(value.Int64)
+		case xunji.FieldCreatedAt:
+			if value, ok := values[i].(*sql.NullTime); !ok {
+				return fmt.Errorf("unexpected type %T for field created_at", values[i])
+			} else if value.Valid {
+				x.CreatedAt = value.Time
+			}
+		case xunji.FieldUpdatedAt:
+			if value, ok := values[i].(*sql.NullTime); !ok {
+				return fmt.Errorf("unexpected type %T for field updated_at", values[i])
+			} else if value.Valid {
+				x.UpdatedAt = value.Time
+			}
+		case xunji.FieldStatus:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field status", values[i])
+			} else if value.Valid {
+				x.Status = uint8(value.Int64)
+			}
+		case xunji.FieldDeletedAt:
+			if value, ok := values[i].(*sql.NullTime); !ok {
+				return fmt.Errorf("unexpected type %T for field deleted_at", values[i])
+			} else if value.Valid {
+				x.DeletedAt = value.Time
+			}
+		case xunji.FieldAppKey:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field app_key", values[i])
+			} else if value.Valid {
+				x.AppKey = value.String
+			}
+		case xunji.FieldAppSecret:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field app_secret", values[i])
+			} else if value.Valid {
+				x.AppSecret = value.String
+			}
+		case xunji.FieldToken:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field token", values[i])
+			} else if value.Valid {
+				x.Token = value.String
+			}
+		case xunji.FieldEncodingKey:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field encoding_key", values[i])
+			} else if value.Valid {
+				x.EncodingKey = value.String
+			}
+		case xunji.FieldAgentID:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field agent_id", values[i])
+			} else if value.Valid {
+				x.AgentID = uint64(value.Int64)
+			}
+		case xunji.FieldOrganizationID:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field organization_id", values[i])
+			} else if value.Valid {
+				x.OrganizationID = uint64(value.Int64)
+			}
+		case xunji.FieldWxid:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field wxid", values[i])
+			} else if value.Valid {
+				x.Wxid = value.String
+			}
+		case xunji.FieldAPIBase:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field api_base", values[i])
+			} else if value.Valid {
+				x.APIBase = value.String
+			}
+		case xunji.FieldAPIKey:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field api_key", values[i])
+			} else if value.Valid {
+				x.APIKey = value.String
+			}
+		default:
+			x.selectValues.Set(columns[i], values[i])
+		}
+	}
+	return nil
+}
+
+// Value returns the ent.Value that was dynamically selected and assigned to the Xunji.
+// This includes values selected through modifiers, order, etc.
+func (x *Xunji) Value(name string) (ent.Value, error) {
+	return x.selectValues.Get(name)
+}
+
+// Update returns a builder for updating this Xunji.
+// Note that you need to call Xunji.Unwrap() before calling this method if this Xunji
+// was returned from a transaction, and the transaction was committed or rolled back.
+func (x *Xunji) Update() *XunjiUpdateOne {
+	return NewXunjiClient(x.config).UpdateOne(x)
+}
+
+// Unwrap unwraps the Xunji entity that was returned from a transaction after it was closed,
+// so that all future queries will be executed through the driver which created the transaction.
+func (x *Xunji) Unwrap() *Xunji {
+	_tx, ok := x.config.driver.(*txDriver)
+	if !ok {
+		panic("ent: Xunji is not a transactional entity")
+	}
+	x.config.driver = _tx.drv
+	return x
+}
+
+// String implements the fmt.Stringer.
+func (x *Xunji) String() string {
+	var builder strings.Builder
+	builder.WriteString("Xunji(")
+	builder.WriteString(fmt.Sprintf("id=%v, ", x.ID))
+	builder.WriteString("created_at=")
+	builder.WriteString(x.CreatedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("updated_at=")
+	builder.WriteString(x.UpdatedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("status=")
+	builder.WriteString(fmt.Sprintf("%v", x.Status))
+	builder.WriteString(", ")
+	builder.WriteString("deleted_at=")
+	builder.WriteString(x.DeletedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("app_key=")
+	builder.WriteString(x.AppKey)
+	builder.WriteString(", ")
+	builder.WriteString("app_secret=")
+	builder.WriteString(x.AppSecret)
+	builder.WriteString(", ")
+	builder.WriteString("token=")
+	builder.WriteString(x.Token)
+	builder.WriteString(", ")
+	builder.WriteString("encoding_key=")
+	builder.WriteString(x.EncodingKey)
+	builder.WriteString(", ")
+	builder.WriteString("agent_id=")
+	builder.WriteString(fmt.Sprintf("%v", x.AgentID))
+	builder.WriteString(", ")
+	builder.WriteString("organization_id=")
+	builder.WriteString(fmt.Sprintf("%v", x.OrganizationID))
+	builder.WriteString(", ")
+	builder.WriteString("wxid=")
+	builder.WriteString(x.Wxid)
+	builder.WriteString(", ")
+	builder.WriteString("api_base=")
+	builder.WriteString(x.APIBase)
+	builder.WriteString(", ")
+	builder.WriteString("api_key=")
+	builder.WriteString(x.APIKey)
+	builder.WriteByte(')')
+	return builder.String()
+}
+
+// Xunjis is a parsable slice of Xunji.
+type Xunjis []*Xunji

+ 870 - 0
ent/xunji/where.go

@@ -0,0 +1,870 @@
+// Code generated by ent, DO NOT EDIT.
+
+package xunji
+
+import (
+	"time"
+	"wechat-api/ent/predicate"
+
+	"entgo.io/ent/dialect/sql"
+)
+
+// ID filters vertices based on their ID field.
+func ID(id uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldID, id))
+}
+
+// IDEQ applies the EQ predicate on the ID field.
+func IDEQ(id uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldID, id))
+}
+
+// IDNEQ applies the NEQ predicate on the ID field.
+func IDNEQ(id uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNEQ(FieldID, id))
+}
+
+// IDIn applies the In predicate on the ID field.
+func IDIn(ids ...uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldIn(FieldID, ids...))
+}
+
+// IDNotIn applies the NotIn predicate on the ID field.
+func IDNotIn(ids ...uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNotIn(FieldID, ids...))
+}
+
+// IDGT applies the GT predicate on the ID field.
+func IDGT(id uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGT(FieldID, id))
+}
+
+// IDGTE applies the GTE predicate on the ID field.
+func IDGTE(id uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGTE(FieldID, id))
+}
+
+// IDLT applies the LT predicate on the ID field.
+func IDLT(id uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLT(FieldID, id))
+}
+
+// IDLTE applies the LTE predicate on the ID field.
+func IDLTE(id uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLTE(FieldID, id))
+}
+
+// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
+func CreatedAt(v time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldCreatedAt, v))
+}
+
+// UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ.
+func UpdatedAt(v time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldUpdatedAt, v))
+}
+
+// Status applies equality check predicate on the "status" field. It's identical to StatusEQ.
+func Status(v uint8) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldStatus, v))
+}
+
+// DeletedAt applies equality check predicate on the "deleted_at" field. It's identical to DeletedAtEQ.
+func DeletedAt(v time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldDeletedAt, v))
+}
+
+// AppKey applies equality check predicate on the "app_key" field. It's identical to AppKeyEQ.
+func AppKey(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldAppKey, v))
+}
+
+// AppSecret applies equality check predicate on the "app_secret" field. It's identical to AppSecretEQ.
+func AppSecret(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldAppSecret, v))
+}
+
+// Token applies equality check predicate on the "token" field. It's identical to TokenEQ.
+func Token(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldToken, v))
+}
+
+// EncodingKey applies equality check predicate on the "encoding_key" field. It's identical to EncodingKeyEQ.
+func EncodingKey(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldEncodingKey, v))
+}
+
+// AgentID applies equality check predicate on the "agent_id" field. It's identical to AgentIDEQ.
+func AgentID(v uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldAgentID, v))
+}
+
+// OrganizationID applies equality check predicate on the "organization_id" field. It's identical to OrganizationIDEQ.
+func OrganizationID(v uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldOrganizationID, v))
+}
+
+// Wxid applies equality check predicate on the "wxid" field. It's identical to WxidEQ.
+func Wxid(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldWxid, v))
+}
+
+// APIBase applies equality check predicate on the "api_base" field. It's identical to APIBaseEQ.
+func APIBase(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldAPIBase, v))
+}
+
+// APIKey applies equality check predicate on the "api_key" field. It's identical to APIKeyEQ.
+func APIKey(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldAPIKey, v))
+}
+
+// CreatedAtEQ applies the EQ predicate on the "created_at" field.
+func CreatedAtEQ(v time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldCreatedAt, v))
+}
+
+// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
+func CreatedAtNEQ(v time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNEQ(FieldCreatedAt, v))
+}
+
+// CreatedAtIn applies the In predicate on the "created_at" field.
+func CreatedAtIn(vs ...time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldIn(FieldCreatedAt, vs...))
+}
+
+// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
+func CreatedAtNotIn(vs ...time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNotIn(FieldCreatedAt, vs...))
+}
+
+// CreatedAtGT applies the GT predicate on the "created_at" field.
+func CreatedAtGT(v time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGT(FieldCreatedAt, v))
+}
+
+// CreatedAtGTE applies the GTE predicate on the "created_at" field.
+func CreatedAtGTE(v time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGTE(FieldCreatedAt, v))
+}
+
+// CreatedAtLT applies the LT predicate on the "created_at" field.
+func CreatedAtLT(v time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLT(FieldCreatedAt, v))
+}
+
+// CreatedAtLTE applies the LTE predicate on the "created_at" field.
+func CreatedAtLTE(v time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLTE(FieldCreatedAt, v))
+}
+
+// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
+func UpdatedAtEQ(v time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldUpdatedAt, v))
+}
+
+// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
+func UpdatedAtNEQ(v time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNEQ(FieldUpdatedAt, v))
+}
+
+// UpdatedAtIn applies the In predicate on the "updated_at" field.
+func UpdatedAtIn(vs ...time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldIn(FieldUpdatedAt, vs...))
+}
+
+// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
+func UpdatedAtNotIn(vs ...time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNotIn(FieldUpdatedAt, vs...))
+}
+
+// UpdatedAtGT applies the GT predicate on the "updated_at" field.
+func UpdatedAtGT(v time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGT(FieldUpdatedAt, v))
+}
+
+// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
+func UpdatedAtGTE(v time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGTE(FieldUpdatedAt, v))
+}
+
+// UpdatedAtLT applies the LT predicate on the "updated_at" field.
+func UpdatedAtLT(v time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLT(FieldUpdatedAt, v))
+}
+
+// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
+func UpdatedAtLTE(v time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLTE(FieldUpdatedAt, v))
+}
+
+// StatusEQ applies the EQ predicate on the "status" field.
+func StatusEQ(v uint8) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldStatus, v))
+}
+
+// StatusNEQ applies the NEQ predicate on the "status" field.
+func StatusNEQ(v uint8) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNEQ(FieldStatus, v))
+}
+
+// StatusIn applies the In predicate on the "status" field.
+func StatusIn(vs ...uint8) predicate.Xunji {
+	return predicate.Xunji(sql.FieldIn(FieldStatus, vs...))
+}
+
+// StatusNotIn applies the NotIn predicate on the "status" field.
+func StatusNotIn(vs ...uint8) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNotIn(FieldStatus, vs...))
+}
+
+// StatusGT applies the GT predicate on the "status" field.
+func StatusGT(v uint8) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGT(FieldStatus, v))
+}
+
+// StatusGTE applies the GTE predicate on the "status" field.
+func StatusGTE(v uint8) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGTE(FieldStatus, v))
+}
+
+// StatusLT applies the LT predicate on the "status" field.
+func StatusLT(v uint8) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLT(FieldStatus, v))
+}
+
+// StatusLTE applies the LTE predicate on the "status" field.
+func StatusLTE(v uint8) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLTE(FieldStatus, v))
+}
+
+// StatusIsNil applies the IsNil predicate on the "status" field.
+func StatusIsNil() predicate.Xunji {
+	return predicate.Xunji(sql.FieldIsNull(FieldStatus))
+}
+
+// StatusNotNil applies the NotNil predicate on the "status" field.
+func StatusNotNil() predicate.Xunji {
+	return predicate.Xunji(sql.FieldNotNull(FieldStatus))
+}
+
+// DeletedAtEQ applies the EQ predicate on the "deleted_at" field.
+func DeletedAtEQ(v time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldDeletedAt, v))
+}
+
+// DeletedAtNEQ applies the NEQ predicate on the "deleted_at" field.
+func DeletedAtNEQ(v time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNEQ(FieldDeletedAt, v))
+}
+
+// DeletedAtIn applies the In predicate on the "deleted_at" field.
+func DeletedAtIn(vs ...time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldIn(FieldDeletedAt, vs...))
+}
+
+// DeletedAtNotIn applies the NotIn predicate on the "deleted_at" field.
+func DeletedAtNotIn(vs ...time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNotIn(FieldDeletedAt, vs...))
+}
+
+// DeletedAtGT applies the GT predicate on the "deleted_at" field.
+func DeletedAtGT(v time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGT(FieldDeletedAt, v))
+}
+
+// DeletedAtGTE applies the GTE predicate on the "deleted_at" field.
+func DeletedAtGTE(v time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGTE(FieldDeletedAt, v))
+}
+
+// DeletedAtLT applies the LT predicate on the "deleted_at" field.
+func DeletedAtLT(v time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLT(FieldDeletedAt, v))
+}
+
+// DeletedAtLTE applies the LTE predicate on the "deleted_at" field.
+func DeletedAtLTE(v time.Time) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLTE(FieldDeletedAt, v))
+}
+
+// DeletedAtIsNil applies the IsNil predicate on the "deleted_at" field.
+func DeletedAtIsNil() predicate.Xunji {
+	return predicate.Xunji(sql.FieldIsNull(FieldDeletedAt))
+}
+
+// DeletedAtNotNil applies the NotNil predicate on the "deleted_at" field.
+func DeletedAtNotNil() predicate.Xunji {
+	return predicate.Xunji(sql.FieldNotNull(FieldDeletedAt))
+}
+
+// AppKeyEQ applies the EQ predicate on the "app_key" field.
+func AppKeyEQ(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldAppKey, v))
+}
+
+// AppKeyNEQ applies the NEQ predicate on the "app_key" field.
+func AppKeyNEQ(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNEQ(FieldAppKey, v))
+}
+
+// AppKeyIn applies the In predicate on the "app_key" field.
+func AppKeyIn(vs ...string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldIn(FieldAppKey, vs...))
+}
+
+// AppKeyNotIn applies the NotIn predicate on the "app_key" field.
+func AppKeyNotIn(vs ...string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNotIn(FieldAppKey, vs...))
+}
+
+// AppKeyGT applies the GT predicate on the "app_key" field.
+func AppKeyGT(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGT(FieldAppKey, v))
+}
+
+// AppKeyGTE applies the GTE predicate on the "app_key" field.
+func AppKeyGTE(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGTE(FieldAppKey, v))
+}
+
+// AppKeyLT applies the LT predicate on the "app_key" field.
+func AppKeyLT(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLT(FieldAppKey, v))
+}
+
+// AppKeyLTE applies the LTE predicate on the "app_key" field.
+func AppKeyLTE(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLTE(FieldAppKey, v))
+}
+
+// AppKeyContains applies the Contains predicate on the "app_key" field.
+func AppKeyContains(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldContains(FieldAppKey, v))
+}
+
+// AppKeyHasPrefix applies the HasPrefix predicate on the "app_key" field.
+func AppKeyHasPrefix(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldHasPrefix(FieldAppKey, v))
+}
+
+// AppKeyHasSuffix applies the HasSuffix predicate on the "app_key" field.
+func AppKeyHasSuffix(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldHasSuffix(FieldAppKey, v))
+}
+
+// AppKeyEqualFold applies the EqualFold predicate on the "app_key" field.
+func AppKeyEqualFold(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEqualFold(FieldAppKey, v))
+}
+
+// AppKeyContainsFold applies the ContainsFold predicate on the "app_key" field.
+func AppKeyContainsFold(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldContainsFold(FieldAppKey, v))
+}
+
+// AppSecretEQ applies the EQ predicate on the "app_secret" field.
+func AppSecretEQ(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldAppSecret, v))
+}
+
+// AppSecretNEQ applies the NEQ predicate on the "app_secret" field.
+func AppSecretNEQ(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNEQ(FieldAppSecret, v))
+}
+
+// AppSecretIn applies the In predicate on the "app_secret" field.
+func AppSecretIn(vs ...string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldIn(FieldAppSecret, vs...))
+}
+
+// AppSecretNotIn applies the NotIn predicate on the "app_secret" field.
+func AppSecretNotIn(vs ...string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNotIn(FieldAppSecret, vs...))
+}
+
+// AppSecretGT applies the GT predicate on the "app_secret" field.
+func AppSecretGT(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGT(FieldAppSecret, v))
+}
+
+// AppSecretGTE applies the GTE predicate on the "app_secret" field.
+func AppSecretGTE(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGTE(FieldAppSecret, v))
+}
+
+// AppSecretLT applies the LT predicate on the "app_secret" field.
+func AppSecretLT(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLT(FieldAppSecret, v))
+}
+
+// AppSecretLTE applies the LTE predicate on the "app_secret" field.
+func AppSecretLTE(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLTE(FieldAppSecret, v))
+}
+
+// AppSecretContains applies the Contains predicate on the "app_secret" field.
+func AppSecretContains(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldContains(FieldAppSecret, v))
+}
+
+// AppSecretHasPrefix applies the HasPrefix predicate on the "app_secret" field.
+func AppSecretHasPrefix(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldHasPrefix(FieldAppSecret, v))
+}
+
+// AppSecretHasSuffix applies the HasSuffix predicate on the "app_secret" field.
+func AppSecretHasSuffix(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldHasSuffix(FieldAppSecret, v))
+}
+
+// AppSecretEqualFold applies the EqualFold predicate on the "app_secret" field.
+func AppSecretEqualFold(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEqualFold(FieldAppSecret, v))
+}
+
+// AppSecretContainsFold applies the ContainsFold predicate on the "app_secret" field.
+func AppSecretContainsFold(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldContainsFold(FieldAppSecret, v))
+}
+
+// TokenEQ applies the EQ predicate on the "token" field.
+func TokenEQ(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldToken, v))
+}
+
+// TokenNEQ applies the NEQ predicate on the "token" field.
+func TokenNEQ(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNEQ(FieldToken, v))
+}
+
+// TokenIn applies the In predicate on the "token" field.
+func TokenIn(vs ...string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldIn(FieldToken, vs...))
+}
+
+// TokenNotIn applies the NotIn predicate on the "token" field.
+func TokenNotIn(vs ...string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNotIn(FieldToken, vs...))
+}
+
+// TokenGT applies the GT predicate on the "token" field.
+func TokenGT(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGT(FieldToken, v))
+}
+
+// TokenGTE applies the GTE predicate on the "token" field.
+func TokenGTE(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGTE(FieldToken, v))
+}
+
+// TokenLT applies the LT predicate on the "token" field.
+func TokenLT(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLT(FieldToken, v))
+}
+
+// TokenLTE applies the LTE predicate on the "token" field.
+func TokenLTE(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLTE(FieldToken, v))
+}
+
+// TokenContains applies the Contains predicate on the "token" field.
+func TokenContains(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldContains(FieldToken, v))
+}
+
+// TokenHasPrefix applies the HasPrefix predicate on the "token" field.
+func TokenHasPrefix(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldHasPrefix(FieldToken, v))
+}
+
+// TokenHasSuffix applies the HasSuffix predicate on the "token" field.
+func TokenHasSuffix(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldHasSuffix(FieldToken, v))
+}
+
+// TokenEqualFold applies the EqualFold predicate on the "token" field.
+func TokenEqualFold(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEqualFold(FieldToken, v))
+}
+
+// TokenContainsFold applies the ContainsFold predicate on the "token" field.
+func TokenContainsFold(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldContainsFold(FieldToken, v))
+}
+
+// EncodingKeyEQ applies the EQ predicate on the "encoding_key" field.
+func EncodingKeyEQ(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldEncodingKey, v))
+}
+
+// EncodingKeyNEQ applies the NEQ predicate on the "encoding_key" field.
+func EncodingKeyNEQ(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNEQ(FieldEncodingKey, v))
+}
+
+// EncodingKeyIn applies the In predicate on the "encoding_key" field.
+func EncodingKeyIn(vs ...string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldIn(FieldEncodingKey, vs...))
+}
+
+// EncodingKeyNotIn applies the NotIn predicate on the "encoding_key" field.
+func EncodingKeyNotIn(vs ...string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNotIn(FieldEncodingKey, vs...))
+}
+
+// EncodingKeyGT applies the GT predicate on the "encoding_key" field.
+func EncodingKeyGT(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGT(FieldEncodingKey, v))
+}
+
+// EncodingKeyGTE applies the GTE predicate on the "encoding_key" field.
+func EncodingKeyGTE(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGTE(FieldEncodingKey, v))
+}
+
+// EncodingKeyLT applies the LT predicate on the "encoding_key" field.
+func EncodingKeyLT(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLT(FieldEncodingKey, v))
+}
+
+// EncodingKeyLTE applies the LTE predicate on the "encoding_key" field.
+func EncodingKeyLTE(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLTE(FieldEncodingKey, v))
+}
+
+// EncodingKeyContains applies the Contains predicate on the "encoding_key" field.
+func EncodingKeyContains(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldContains(FieldEncodingKey, v))
+}
+
+// EncodingKeyHasPrefix applies the HasPrefix predicate on the "encoding_key" field.
+func EncodingKeyHasPrefix(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldHasPrefix(FieldEncodingKey, v))
+}
+
+// EncodingKeyHasSuffix applies the HasSuffix predicate on the "encoding_key" field.
+func EncodingKeyHasSuffix(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldHasSuffix(FieldEncodingKey, v))
+}
+
+// EncodingKeyEqualFold applies the EqualFold predicate on the "encoding_key" field.
+func EncodingKeyEqualFold(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEqualFold(FieldEncodingKey, v))
+}
+
+// EncodingKeyContainsFold applies the ContainsFold predicate on the "encoding_key" field.
+func EncodingKeyContainsFold(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldContainsFold(FieldEncodingKey, v))
+}
+
+// AgentIDEQ applies the EQ predicate on the "agent_id" field.
+func AgentIDEQ(v uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldAgentID, v))
+}
+
+// AgentIDNEQ applies the NEQ predicate on the "agent_id" field.
+func AgentIDNEQ(v uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNEQ(FieldAgentID, v))
+}
+
+// AgentIDIn applies the In predicate on the "agent_id" field.
+func AgentIDIn(vs ...uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldIn(FieldAgentID, vs...))
+}
+
+// AgentIDNotIn applies the NotIn predicate on the "agent_id" field.
+func AgentIDNotIn(vs ...uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNotIn(FieldAgentID, vs...))
+}
+
+// AgentIDGT applies the GT predicate on the "agent_id" field.
+func AgentIDGT(v uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGT(FieldAgentID, v))
+}
+
+// AgentIDGTE applies the GTE predicate on the "agent_id" field.
+func AgentIDGTE(v uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGTE(FieldAgentID, v))
+}
+
+// AgentIDLT applies the LT predicate on the "agent_id" field.
+func AgentIDLT(v uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLT(FieldAgentID, v))
+}
+
+// AgentIDLTE applies the LTE predicate on the "agent_id" field.
+func AgentIDLTE(v uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLTE(FieldAgentID, v))
+}
+
+// OrganizationIDEQ applies the EQ predicate on the "organization_id" field.
+func OrganizationIDEQ(v uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldOrganizationID, v))
+}
+
+// OrganizationIDNEQ applies the NEQ predicate on the "organization_id" field.
+func OrganizationIDNEQ(v uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNEQ(FieldOrganizationID, v))
+}
+
+// OrganizationIDIn applies the In predicate on the "organization_id" field.
+func OrganizationIDIn(vs ...uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldIn(FieldOrganizationID, vs...))
+}
+
+// OrganizationIDNotIn applies the NotIn predicate on the "organization_id" field.
+func OrganizationIDNotIn(vs ...uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNotIn(FieldOrganizationID, vs...))
+}
+
+// OrganizationIDGT applies the GT predicate on the "organization_id" field.
+func OrganizationIDGT(v uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGT(FieldOrganizationID, v))
+}
+
+// OrganizationIDGTE applies the GTE predicate on the "organization_id" field.
+func OrganizationIDGTE(v uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGTE(FieldOrganizationID, v))
+}
+
+// OrganizationIDLT applies the LT predicate on the "organization_id" field.
+func OrganizationIDLT(v uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLT(FieldOrganizationID, v))
+}
+
+// OrganizationIDLTE applies the LTE predicate on the "organization_id" field.
+func OrganizationIDLTE(v uint64) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLTE(FieldOrganizationID, v))
+}
+
+// WxidEQ applies the EQ predicate on the "wxid" field.
+func WxidEQ(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldWxid, v))
+}
+
+// WxidNEQ applies the NEQ predicate on the "wxid" field.
+func WxidNEQ(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNEQ(FieldWxid, v))
+}
+
+// WxidIn applies the In predicate on the "wxid" field.
+func WxidIn(vs ...string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldIn(FieldWxid, vs...))
+}
+
+// WxidNotIn applies the NotIn predicate on the "wxid" field.
+func WxidNotIn(vs ...string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNotIn(FieldWxid, vs...))
+}
+
+// WxidGT applies the GT predicate on the "wxid" field.
+func WxidGT(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGT(FieldWxid, v))
+}
+
+// WxidGTE applies the GTE predicate on the "wxid" field.
+func WxidGTE(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGTE(FieldWxid, v))
+}
+
+// WxidLT applies the LT predicate on the "wxid" field.
+func WxidLT(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLT(FieldWxid, v))
+}
+
+// WxidLTE applies the LTE predicate on the "wxid" field.
+func WxidLTE(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLTE(FieldWxid, v))
+}
+
+// WxidContains applies the Contains predicate on the "wxid" field.
+func WxidContains(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldContains(FieldWxid, v))
+}
+
+// WxidHasPrefix applies the HasPrefix predicate on the "wxid" field.
+func WxidHasPrefix(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldHasPrefix(FieldWxid, v))
+}
+
+// WxidHasSuffix applies the HasSuffix predicate on the "wxid" field.
+func WxidHasSuffix(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldHasSuffix(FieldWxid, v))
+}
+
+// WxidEqualFold applies the EqualFold predicate on the "wxid" field.
+func WxidEqualFold(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEqualFold(FieldWxid, v))
+}
+
+// WxidContainsFold applies the ContainsFold predicate on the "wxid" field.
+func WxidContainsFold(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldContainsFold(FieldWxid, v))
+}
+
+// APIBaseEQ applies the EQ predicate on the "api_base" field.
+func APIBaseEQ(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldAPIBase, v))
+}
+
+// APIBaseNEQ applies the NEQ predicate on the "api_base" field.
+func APIBaseNEQ(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNEQ(FieldAPIBase, v))
+}
+
+// APIBaseIn applies the In predicate on the "api_base" field.
+func APIBaseIn(vs ...string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldIn(FieldAPIBase, vs...))
+}
+
+// APIBaseNotIn applies the NotIn predicate on the "api_base" field.
+func APIBaseNotIn(vs ...string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNotIn(FieldAPIBase, vs...))
+}
+
+// APIBaseGT applies the GT predicate on the "api_base" field.
+func APIBaseGT(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGT(FieldAPIBase, v))
+}
+
+// APIBaseGTE applies the GTE predicate on the "api_base" field.
+func APIBaseGTE(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGTE(FieldAPIBase, v))
+}
+
+// APIBaseLT applies the LT predicate on the "api_base" field.
+func APIBaseLT(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLT(FieldAPIBase, v))
+}
+
+// APIBaseLTE applies the LTE predicate on the "api_base" field.
+func APIBaseLTE(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLTE(FieldAPIBase, v))
+}
+
+// APIBaseContains applies the Contains predicate on the "api_base" field.
+func APIBaseContains(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldContains(FieldAPIBase, v))
+}
+
+// APIBaseHasPrefix applies the HasPrefix predicate on the "api_base" field.
+func APIBaseHasPrefix(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldHasPrefix(FieldAPIBase, v))
+}
+
+// APIBaseHasSuffix applies the HasSuffix predicate on the "api_base" field.
+func APIBaseHasSuffix(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldHasSuffix(FieldAPIBase, v))
+}
+
+// APIBaseIsNil applies the IsNil predicate on the "api_base" field.
+func APIBaseIsNil() predicate.Xunji {
+	return predicate.Xunji(sql.FieldIsNull(FieldAPIBase))
+}
+
+// APIBaseNotNil applies the NotNil predicate on the "api_base" field.
+func APIBaseNotNil() predicate.Xunji {
+	return predicate.Xunji(sql.FieldNotNull(FieldAPIBase))
+}
+
+// APIBaseEqualFold applies the EqualFold predicate on the "api_base" field.
+func APIBaseEqualFold(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEqualFold(FieldAPIBase, v))
+}
+
+// APIBaseContainsFold applies the ContainsFold predicate on the "api_base" field.
+func APIBaseContainsFold(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldContainsFold(FieldAPIBase, v))
+}
+
+// APIKeyEQ applies the EQ predicate on the "api_key" field.
+func APIKeyEQ(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEQ(FieldAPIKey, v))
+}
+
+// APIKeyNEQ applies the NEQ predicate on the "api_key" field.
+func APIKeyNEQ(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNEQ(FieldAPIKey, v))
+}
+
+// APIKeyIn applies the In predicate on the "api_key" field.
+func APIKeyIn(vs ...string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldIn(FieldAPIKey, vs...))
+}
+
+// APIKeyNotIn applies the NotIn predicate on the "api_key" field.
+func APIKeyNotIn(vs ...string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldNotIn(FieldAPIKey, vs...))
+}
+
+// APIKeyGT applies the GT predicate on the "api_key" field.
+func APIKeyGT(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGT(FieldAPIKey, v))
+}
+
+// APIKeyGTE applies the GTE predicate on the "api_key" field.
+func APIKeyGTE(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldGTE(FieldAPIKey, v))
+}
+
+// APIKeyLT applies the LT predicate on the "api_key" field.
+func APIKeyLT(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLT(FieldAPIKey, v))
+}
+
+// APIKeyLTE applies the LTE predicate on the "api_key" field.
+func APIKeyLTE(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldLTE(FieldAPIKey, v))
+}
+
+// APIKeyContains applies the Contains predicate on the "api_key" field.
+func APIKeyContains(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldContains(FieldAPIKey, v))
+}
+
+// APIKeyHasPrefix applies the HasPrefix predicate on the "api_key" field.
+func APIKeyHasPrefix(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldHasPrefix(FieldAPIKey, v))
+}
+
+// APIKeyHasSuffix applies the HasSuffix predicate on the "api_key" field.
+func APIKeyHasSuffix(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldHasSuffix(FieldAPIKey, v))
+}
+
+// APIKeyIsNil applies the IsNil predicate on the "api_key" field.
+func APIKeyIsNil() predicate.Xunji {
+	return predicate.Xunji(sql.FieldIsNull(FieldAPIKey))
+}
+
+// APIKeyNotNil applies the NotNil predicate on the "api_key" field.
+func APIKeyNotNil() predicate.Xunji {
+	return predicate.Xunji(sql.FieldNotNull(FieldAPIKey))
+}
+
+// APIKeyEqualFold applies the EqualFold predicate on the "api_key" field.
+func APIKeyEqualFold(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldEqualFold(FieldAPIKey, v))
+}
+
+// APIKeyContainsFold applies the ContainsFold predicate on the "api_key" field.
+func APIKeyContainsFold(v string) predicate.Xunji {
+	return predicate.Xunji(sql.FieldContainsFold(FieldAPIKey, v))
+}
+
+// And groups predicates with the AND operator between them.
+func And(predicates ...predicate.Xunji) predicate.Xunji {
+	return predicate.Xunji(sql.AndPredicates(predicates...))
+}
+
+// Or groups predicates with the OR operator between them.
+func Or(predicates ...predicate.Xunji) predicate.Xunji {
+	return predicate.Xunji(sql.OrPredicates(predicates...))
+}
+
+// Not applies the not operator on the given predicate.
+func Not(p predicate.Xunji) predicate.Xunji {
+	return predicate.Xunji(sql.NotPredicates(p))
+}

+ 170 - 0
ent/xunji/xunji.go

@@ -0,0 +1,170 @@
+// Code generated by ent, DO NOT EDIT.
+
+package xunji
+
+import (
+	"time"
+
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/sql"
+)
+
+const (
+	// Label holds the string label denoting the xunji type in the database.
+	Label = "xunji"
+	// FieldID holds the string denoting the id field in the database.
+	FieldID = "id"
+	// FieldCreatedAt holds the string denoting the created_at field in the database.
+	FieldCreatedAt = "created_at"
+	// FieldUpdatedAt holds the string denoting the updated_at field in the database.
+	FieldUpdatedAt = "updated_at"
+	// FieldStatus holds the string denoting the status field in the database.
+	FieldStatus = "status"
+	// FieldDeletedAt holds the string denoting the deleted_at field in the database.
+	FieldDeletedAt = "deleted_at"
+	// FieldAppKey holds the string denoting the app_key field in the database.
+	FieldAppKey = "app_key"
+	// FieldAppSecret holds the string denoting the app_secret field in the database.
+	FieldAppSecret = "app_secret"
+	// FieldToken holds the string denoting the token field in the database.
+	FieldToken = "token"
+	// FieldEncodingKey holds the string denoting the encoding_key field in the database.
+	FieldEncodingKey = "encoding_key"
+	// FieldAgentID holds the string denoting the agent_id field in the database.
+	FieldAgentID = "agent_id"
+	// FieldOrganizationID holds the string denoting the organization_id field in the database.
+	FieldOrganizationID = "organization_id"
+	// FieldWxid holds the string denoting the wxid field in the database.
+	FieldWxid = "wxid"
+	// FieldAPIBase holds the string denoting the api_base field in the database.
+	FieldAPIBase = "api_base"
+	// FieldAPIKey holds the string denoting the api_key field in the database.
+	FieldAPIKey = "api_key"
+	// Table holds the table name of the xunji in the database.
+	Table = "xunji"
+)
+
+// Columns holds all SQL columns for xunji fields.
+var Columns = []string{
+	FieldID,
+	FieldCreatedAt,
+	FieldUpdatedAt,
+	FieldStatus,
+	FieldDeletedAt,
+	FieldAppKey,
+	FieldAppSecret,
+	FieldToken,
+	FieldEncodingKey,
+	FieldAgentID,
+	FieldOrganizationID,
+	FieldWxid,
+	FieldAPIBase,
+	FieldAPIKey,
+}
+
+// ValidColumn reports if the column name is valid (part of the table columns).
+func ValidColumn(column string) bool {
+	for i := range Columns {
+		if column == Columns[i] {
+			return true
+		}
+	}
+	return false
+}
+
+// Note that the variables below are initialized by the runtime
+// package on the initialization of the application. Therefore,
+// it should be imported in the main as follows:
+//
+//	import _ "wechat-api/ent/runtime"
+var (
+	Hooks        [1]ent.Hook
+	Interceptors [1]ent.Interceptor
+	// DefaultCreatedAt holds the default value on creation for the "created_at" field.
+	DefaultCreatedAt func() time.Time
+	// DefaultUpdatedAt holds the default value on creation for the "updated_at" field.
+	DefaultUpdatedAt func() time.Time
+	// UpdateDefaultUpdatedAt holds the default value on update for the "updated_at" field.
+	UpdateDefaultUpdatedAt func() time.Time
+	// DefaultStatus holds the default value on creation for the "status" field.
+	DefaultStatus uint8
+	// OrganizationIDValidator is a validator for the "organization_id" field. It is called by the builders before save.
+	OrganizationIDValidator func(uint64) error
+	// DefaultAPIBase holds the default value on creation for the "api_base" field.
+	DefaultAPIBase string
+	// DefaultAPIKey holds the default value on creation for the "api_key" field.
+	DefaultAPIKey string
+)
+
+// OrderOption defines the ordering options for the Xunji queries.
+type OrderOption func(*sql.Selector)
+
+// ByID orders the results by the id field.
+func ByID(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldID, opts...).ToFunc()
+}
+
+// ByCreatedAt orders the results by the created_at field.
+func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldCreatedAt, opts...).ToFunc()
+}
+
+// ByUpdatedAt orders the results by the updated_at field.
+func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc()
+}
+
+// ByStatus orders the results by the status field.
+func ByStatus(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldStatus, opts...).ToFunc()
+}
+
+// ByDeletedAt orders the results by the deleted_at field.
+func ByDeletedAt(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldDeletedAt, opts...).ToFunc()
+}
+
+// ByAppKey orders the results by the app_key field.
+func ByAppKey(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldAppKey, opts...).ToFunc()
+}
+
+// ByAppSecret orders the results by the app_secret field.
+func ByAppSecret(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldAppSecret, opts...).ToFunc()
+}
+
+// ByToken orders the results by the token field.
+func ByToken(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldToken, opts...).ToFunc()
+}
+
+// ByEncodingKey orders the results by the encoding_key field.
+func ByEncodingKey(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldEncodingKey, opts...).ToFunc()
+}
+
+// ByAgentID orders the results by the agent_id field.
+func ByAgentID(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldAgentID, opts...).ToFunc()
+}
+
+// ByOrganizationID orders the results by the organization_id field.
+func ByOrganizationID(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldOrganizationID, opts...).ToFunc()
+}
+
+// ByWxid orders the results by the wxid field.
+func ByWxid(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldWxid, opts...).ToFunc()
+}
+
+// ByAPIBase orders the results by the api_base field.
+func ByAPIBase(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldAPIBase, opts...).ToFunc()
+}
+
+// ByAPIKey orders the results by the api_key field.
+func ByAPIKey(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldAPIKey, opts...).ToFunc()
+}

+ 1303 - 0
ent/xunji_create.go

@@ -0,0 +1,1303 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"time"
+	"wechat-api/ent/xunji"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+)
+
+// XunjiCreate is the builder for creating a Xunji entity.
+type XunjiCreate struct {
+	config
+	mutation *XunjiMutation
+	hooks    []Hook
+	conflict []sql.ConflictOption
+}
+
+// SetCreatedAt sets the "created_at" field.
+func (xc *XunjiCreate) SetCreatedAt(t time.Time) *XunjiCreate {
+	xc.mutation.SetCreatedAt(t)
+	return xc
+}
+
+// SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
+func (xc *XunjiCreate) SetNillableCreatedAt(t *time.Time) *XunjiCreate {
+	if t != nil {
+		xc.SetCreatedAt(*t)
+	}
+	return xc
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (xc *XunjiCreate) SetUpdatedAt(t time.Time) *XunjiCreate {
+	xc.mutation.SetUpdatedAt(t)
+	return xc
+}
+
+// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil.
+func (xc *XunjiCreate) SetNillableUpdatedAt(t *time.Time) *XunjiCreate {
+	if t != nil {
+		xc.SetUpdatedAt(*t)
+	}
+	return xc
+}
+
+// SetStatus sets the "status" field.
+func (xc *XunjiCreate) SetStatus(u uint8) *XunjiCreate {
+	xc.mutation.SetStatus(u)
+	return xc
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (xc *XunjiCreate) SetNillableStatus(u *uint8) *XunjiCreate {
+	if u != nil {
+		xc.SetStatus(*u)
+	}
+	return xc
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (xc *XunjiCreate) SetDeletedAt(t time.Time) *XunjiCreate {
+	xc.mutation.SetDeletedAt(t)
+	return xc
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (xc *XunjiCreate) SetNillableDeletedAt(t *time.Time) *XunjiCreate {
+	if t != nil {
+		xc.SetDeletedAt(*t)
+	}
+	return xc
+}
+
+// SetAppKey sets the "app_key" field.
+func (xc *XunjiCreate) SetAppKey(s string) *XunjiCreate {
+	xc.mutation.SetAppKey(s)
+	return xc
+}
+
+// SetAppSecret sets the "app_secret" field.
+func (xc *XunjiCreate) SetAppSecret(s string) *XunjiCreate {
+	xc.mutation.SetAppSecret(s)
+	return xc
+}
+
+// SetToken sets the "token" field.
+func (xc *XunjiCreate) SetToken(s string) *XunjiCreate {
+	xc.mutation.SetToken(s)
+	return xc
+}
+
+// SetEncodingKey sets the "encoding_key" field.
+func (xc *XunjiCreate) SetEncodingKey(s string) *XunjiCreate {
+	xc.mutation.SetEncodingKey(s)
+	return xc
+}
+
+// SetAgentID sets the "agent_id" field.
+func (xc *XunjiCreate) SetAgentID(u uint64) *XunjiCreate {
+	xc.mutation.SetAgentID(u)
+	return xc
+}
+
+// SetOrganizationID sets the "organization_id" field.
+func (xc *XunjiCreate) SetOrganizationID(u uint64) *XunjiCreate {
+	xc.mutation.SetOrganizationID(u)
+	return xc
+}
+
+// SetWxid sets the "wxid" field.
+func (xc *XunjiCreate) SetWxid(s string) *XunjiCreate {
+	xc.mutation.SetWxid(s)
+	return xc
+}
+
+// SetAPIBase sets the "api_base" field.
+func (xc *XunjiCreate) SetAPIBase(s string) *XunjiCreate {
+	xc.mutation.SetAPIBase(s)
+	return xc
+}
+
+// SetNillableAPIBase sets the "api_base" field if the given value is not nil.
+func (xc *XunjiCreate) SetNillableAPIBase(s *string) *XunjiCreate {
+	if s != nil {
+		xc.SetAPIBase(*s)
+	}
+	return xc
+}
+
+// SetAPIKey sets the "api_key" field.
+func (xc *XunjiCreate) SetAPIKey(s string) *XunjiCreate {
+	xc.mutation.SetAPIKey(s)
+	return xc
+}
+
+// SetNillableAPIKey sets the "api_key" field if the given value is not nil.
+func (xc *XunjiCreate) SetNillableAPIKey(s *string) *XunjiCreate {
+	if s != nil {
+		xc.SetAPIKey(*s)
+	}
+	return xc
+}
+
+// SetID sets the "id" field.
+func (xc *XunjiCreate) SetID(u uint64) *XunjiCreate {
+	xc.mutation.SetID(u)
+	return xc
+}
+
+// Mutation returns the XunjiMutation object of the builder.
+func (xc *XunjiCreate) Mutation() *XunjiMutation {
+	return xc.mutation
+}
+
+// Save creates the Xunji in the database.
+func (xc *XunjiCreate) Save(ctx context.Context) (*Xunji, error) {
+	if err := xc.defaults(); err != nil {
+		return nil, err
+	}
+	return withHooks(ctx, xc.sqlSave, xc.mutation, xc.hooks)
+}
+
+// SaveX calls Save and panics if Save returns an error.
+func (xc *XunjiCreate) SaveX(ctx context.Context) *Xunji {
+	v, err := xc.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Exec executes the query.
+func (xc *XunjiCreate) Exec(ctx context.Context) error {
+	_, err := xc.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (xc *XunjiCreate) ExecX(ctx context.Context) {
+	if err := xc.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (xc *XunjiCreate) defaults() error {
+	if _, ok := xc.mutation.CreatedAt(); !ok {
+		if xunji.DefaultCreatedAt == nil {
+			return fmt.Errorf("ent: uninitialized xunji.DefaultCreatedAt (forgotten import ent/runtime?)")
+		}
+		v := xunji.DefaultCreatedAt()
+		xc.mutation.SetCreatedAt(v)
+	}
+	if _, ok := xc.mutation.UpdatedAt(); !ok {
+		if xunji.DefaultUpdatedAt == nil {
+			return fmt.Errorf("ent: uninitialized xunji.DefaultUpdatedAt (forgotten import ent/runtime?)")
+		}
+		v := xunji.DefaultUpdatedAt()
+		xc.mutation.SetUpdatedAt(v)
+	}
+	if _, ok := xc.mutation.Status(); !ok {
+		v := xunji.DefaultStatus
+		xc.mutation.SetStatus(v)
+	}
+	if _, ok := xc.mutation.APIBase(); !ok {
+		v := xunji.DefaultAPIBase
+		xc.mutation.SetAPIBase(v)
+	}
+	if _, ok := xc.mutation.APIKey(); !ok {
+		v := xunji.DefaultAPIKey
+		xc.mutation.SetAPIKey(v)
+	}
+	return nil
+}
+
+// check runs all checks and user-defined validators on the builder.
+func (xc *XunjiCreate) check() error {
+	if _, ok := xc.mutation.CreatedAt(); !ok {
+		return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "Xunji.created_at"`)}
+	}
+	if _, ok := xc.mutation.UpdatedAt(); !ok {
+		return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "Xunji.updated_at"`)}
+	}
+	if _, ok := xc.mutation.AppKey(); !ok {
+		return &ValidationError{Name: "app_key", err: errors.New(`ent: missing required field "Xunji.app_key"`)}
+	}
+	if _, ok := xc.mutation.AppSecret(); !ok {
+		return &ValidationError{Name: "app_secret", err: errors.New(`ent: missing required field "Xunji.app_secret"`)}
+	}
+	if _, ok := xc.mutation.Token(); !ok {
+		return &ValidationError{Name: "token", err: errors.New(`ent: missing required field "Xunji.token"`)}
+	}
+	if _, ok := xc.mutation.EncodingKey(); !ok {
+		return &ValidationError{Name: "encoding_key", err: errors.New(`ent: missing required field "Xunji.encoding_key"`)}
+	}
+	if _, ok := xc.mutation.AgentID(); !ok {
+		return &ValidationError{Name: "agent_id", err: errors.New(`ent: missing required field "Xunji.agent_id"`)}
+	}
+	if _, ok := xc.mutation.OrganizationID(); !ok {
+		return &ValidationError{Name: "organization_id", err: errors.New(`ent: missing required field "Xunji.organization_id"`)}
+	}
+	if v, ok := xc.mutation.OrganizationID(); ok {
+		if err := xunji.OrganizationIDValidator(v); err != nil {
+			return &ValidationError{Name: "organization_id", err: fmt.Errorf(`ent: validator failed for field "Xunji.organization_id": %w`, err)}
+		}
+	}
+	if _, ok := xc.mutation.Wxid(); !ok {
+		return &ValidationError{Name: "wxid", err: errors.New(`ent: missing required field "Xunji.wxid"`)}
+	}
+	return nil
+}
+
+func (xc *XunjiCreate) sqlSave(ctx context.Context) (*Xunji, error) {
+	if err := xc.check(); err != nil {
+		return nil, err
+	}
+	_node, _spec := xc.createSpec()
+	if err := sqlgraph.CreateNode(ctx, xc.driver, _spec); err != nil {
+		if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return nil, err
+	}
+	if _spec.ID.Value != _node.ID {
+		id := _spec.ID.Value.(int64)
+		_node.ID = uint64(id)
+	}
+	xc.mutation.id = &_node.ID
+	xc.mutation.done = true
+	return _node, nil
+}
+
+func (xc *XunjiCreate) createSpec() (*Xunji, *sqlgraph.CreateSpec) {
+	var (
+		_node = &Xunji{config: xc.config}
+		_spec = sqlgraph.NewCreateSpec(xunji.Table, sqlgraph.NewFieldSpec(xunji.FieldID, field.TypeUint64))
+	)
+	_spec.OnConflict = xc.conflict
+	if id, ok := xc.mutation.ID(); ok {
+		_node.ID = id
+		_spec.ID.Value = id
+	}
+	if value, ok := xc.mutation.CreatedAt(); ok {
+		_spec.SetField(xunji.FieldCreatedAt, field.TypeTime, value)
+		_node.CreatedAt = value
+	}
+	if value, ok := xc.mutation.UpdatedAt(); ok {
+		_spec.SetField(xunji.FieldUpdatedAt, field.TypeTime, value)
+		_node.UpdatedAt = value
+	}
+	if value, ok := xc.mutation.Status(); ok {
+		_spec.SetField(xunji.FieldStatus, field.TypeUint8, value)
+		_node.Status = value
+	}
+	if value, ok := xc.mutation.DeletedAt(); ok {
+		_spec.SetField(xunji.FieldDeletedAt, field.TypeTime, value)
+		_node.DeletedAt = value
+	}
+	if value, ok := xc.mutation.AppKey(); ok {
+		_spec.SetField(xunji.FieldAppKey, field.TypeString, value)
+		_node.AppKey = value
+	}
+	if value, ok := xc.mutation.AppSecret(); ok {
+		_spec.SetField(xunji.FieldAppSecret, field.TypeString, value)
+		_node.AppSecret = value
+	}
+	if value, ok := xc.mutation.Token(); ok {
+		_spec.SetField(xunji.FieldToken, field.TypeString, value)
+		_node.Token = value
+	}
+	if value, ok := xc.mutation.EncodingKey(); ok {
+		_spec.SetField(xunji.FieldEncodingKey, field.TypeString, value)
+		_node.EncodingKey = value
+	}
+	if value, ok := xc.mutation.AgentID(); ok {
+		_spec.SetField(xunji.FieldAgentID, field.TypeUint64, value)
+		_node.AgentID = value
+	}
+	if value, ok := xc.mutation.OrganizationID(); ok {
+		_spec.SetField(xunji.FieldOrganizationID, field.TypeUint64, value)
+		_node.OrganizationID = value
+	}
+	if value, ok := xc.mutation.Wxid(); ok {
+		_spec.SetField(xunji.FieldWxid, field.TypeString, value)
+		_node.Wxid = value
+	}
+	if value, ok := xc.mutation.APIBase(); ok {
+		_spec.SetField(xunji.FieldAPIBase, field.TypeString, value)
+		_node.APIBase = value
+	}
+	if value, ok := xc.mutation.APIKey(); ok {
+		_spec.SetField(xunji.FieldAPIKey, field.TypeString, value)
+		_node.APIKey = value
+	}
+	return _node, _spec
+}
+
+// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
+// of the `INSERT` statement. For example:
+//
+//	client.Xunji.Create().
+//		SetCreatedAt(v).
+//		OnConflict(
+//			// Update the row with the new values
+//			// the was proposed for insertion.
+//			sql.ResolveWithNewValues(),
+//		).
+//		// Override some of the fields with custom
+//		// update values.
+//		Update(func(u *ent.XunjiUpsert) {
+//			SetCreatedAt(v+v).
+//		}).
+//		Exec(ctx)
+func (xc *XunjiCreate) OnConflict(opts ...sql.ConflictOption) *XunjiUpsertOne {
+	xc.conflict = opts
+	return &XunjiUpsertOne{
+		create: xc,
+	}
+}
+
+// OnConflictColumns calls `OnConflict` and configures the columns
+// as conflict target. Using this option is equivalent to using:
+//
+//	client.Xunji.Create().
+//		OnConflict(sql.ConflictColumns(columns...)).
+//		Exec(ctx)
+func (xc *XunjiCreate) OnConflictColumns(columns ...string) *XunjiUpsertOne {
+	xc.conflict = append(xc.conflict, sql.ConflictColumns(columns...))
+	return &XunjiUpsertOne{
+		create: xc,
+	}
+}
+
+type (
+	// XunjiUpsertOne is the builder for "upsert"-ing
+	//  one Xunji node.
+	XunjiUpsertOne struct {
+		create *XunjiCreate
+	}
+
+	// XunjiUpsert is the "OnConflict" setter.
+	XunjiUpsert struct {
+		*sql.UpdateSet
+	}
+)
+
+// SetUpdatedAt sets the "updated_at" field.
+func (u *XunjiUpsert) SetUpdatedAt(v time.Time) *XunjiUpsert {
+	u.Set(xunji.FieldUpdatedAt, v)
+	return u
+}
+
+// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
+func (u *XunjiUpsert) UpdateUpdatedAt() *XunjiUpsert {
+	u.SetExcluded(xunji.FieldUpdatedAt)
+	return u
+}
+
+// SetStatus sets the "status" field.
+func (u *XunjiUpsert) SetStatus(v uint8) *XunjiUpsert {
+	u.Set(xunji.FieldStatus, v)
+	return u
+}
+
+// UpdateStatus sets the "status" field to the value that was provided on create.
+func (u *XunjiUpsert) UpdateStatus() *XunjiUpsert {
+	u.SetExcluded(xunji.FieldStatus)
+	return u
+}
+
+// AddStatus adds v to the "status" field.
+func (u *XunjiUpsert) AddStatus(v uint8) *XunjiUpsert {
+	u.Add(xunji.FieldStatus, v)
+	return u
+}
+
+// ClearStatus clears the value of the "status" field.
+func (u *XunjiUpsert) ClearStatus() *XunjiUpsert {
+	u.SetNull(xunji.FieldStatus)
+	return u
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (u *XunjiUpsert) SetDeletedAt(v time.Time) *XunjiUpsert {
+	u.Set(xunji.FieldDeletedAt, v)
+	return u
+}
+
+// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
+func (u *XunjiUpsert) UpdateDeletedAt() *XunjiUpsert {
+	u.SetExcluded(xunji.FieldDeletedAt)
+	return u
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (u *XunjiUpsert) ClearDeletedAt() *XunjiUpsert {
+	u.SetNull(xunji.FieldDeletedAt)
+	return u
+}
+
+// SetAppKey sets the "app_key" field.
+func (u *XunjiUpsert) SetAppKey(v string) *XunjiUpsert {
+	u.Set(xunji.FieldAppKey, v)
+	return u
+}
+
+// UpdateAppKey sets the "app_key" field to the value that was provided on create.
+func (u *XunjiUpsert) UpdateAppKey() *XunjiUpsert {
+	u.SetExcluded(xunji.FieldAppKey)
+	return u
+}
+
+// SetAppSecret sets the "app_secret" field.
+func (u *XunjiUpsert) SetAppSecret(v string) *XunjiUpsert {
+	u.Set(xunji.FieldAppSecret, v)
+	return u
+}
+
+// UpdateAppSecret sets the "app_secret" field to the value that was provided on create.
+func (u *XunjiUpsert) UpdateAppSecret() *XunjiUpsert {
+	u.SetExcluded(xunji.FieldAppSecret)
+	return u
+}
+
+// SetToken sets the "token" field.
+func (u *XunjiUpsert) SetToken(v string) *XunjiUpsert {
+	u.Set(xunji.FieldToken, v)
+	return u
+}
+
+// UpdateToken sets the "token" field to the value that was provided on create.
+func (u *XunjiUpsert) UpdateToken() *XunjiUpsert {
+	u.SetExcluded(xunji.FieldToken)
+	return u
+}
+
+// SetEncodingKey sets the "encoding_key" field.
+func (u *XunjiUpsert) SetEncodingKey(v string) *XunjiUpsert {
+	u.Set(xunji.FieldEncodingKey, v)
+	return u
+}
+
+// UpdateEncodingKey sets the "encoding_key" field to the value that was provided on create.
+func (u *XunjiUpsert) UpdateEncodingKey() *XunjiUpsert {
+	u.SetExcluded(xunji.FieldEncodingKey)
+	return u
+}
+
+// SetAgentID sets the "agent_id" field.
+func (u *XunjiUpsert) SetAgentID(v uint64) *XunjiUpsert {
+	u.Set(xunji.FieldAgentID, v)
+	return u
+}
+
+// UpdateAgentID sets the "agent_id" field to the value that was provided on create.
+func (u *XunjiUpsert) UpdateAgentID() *XunjiUpsert {
+	u.SetExcluded(xunji.FieldAgentID)
+	return u
+}
+
+// AddAgentID adds v to the "agent_id" field.
+func (u *XunjiUpsert) AddAgentID(v uint64) *XunjiUpsert {
+	u.Add(xunji.FieldAgentID, v)
+	return u
+}
+
+// SetOrganizationID sets the "organization_id" field.
+func (u *XunjiUpsert) SetOrganizationID(v uint64) *XunjiUpsert {
+	u.Set(xunji.FieldOrganizationID, v)
+	return u
+}
+
+// UpdateOrganizationID sets the "organization_id" field to the value that was provided on create.
+func (u *XunjiUpsert) UpdateOrganizationID() *XunjiUpsert {
+	u.SetExcluded(xunji.FieldOrganizationID)
+	return u
+}
+
+// AddOrganizationID adds v to the "organization_id" field.
+func (u *XunjiUpsert) AddOrganizationID(v uint64) *XunjiUpsert {
+	u.Add(xunji.FieldOrganizationID, v)
+	return u
+}
+
+// SetWxid sets the "wxid" field.
+func (u *XunjiUpsert) SetWxid(v string) *XunjiUpsert {
+	u.Set(xunji.FieldWxid, v)
+	return u
+}
+
+// UpdateWxid sets the "wxid" field to the value that was provided on create.
+func (u *XunjiUpsert) UpdateWxid() *XunjiUpsert {
+	u.SetExcluded(xunji.FieldWxid)
+	return u
+}
+
+// SetAPIBase sets the "api_base" field.
+func (u *XunjiUpsert) SetAPIBase(v string) *XunjiUpsert {
+	u.Set(xunji.FieldAPIBase, v)
+	return u
+}
+
+// UpdateAPIBase sets the "api_base" field to the value that was provided on create.
+func (u *XunjiUpsert) UpdateAPIBase() *XunjiUpsert {
+	u.SetExcluded(xunji.FieldAPIBase)
+	return u
+}
+
+// ClearAPIBase clears the value of the "api_base" field.
+func (u *XunjiUpsert) ClearAPIBase() *XunjiUpsert {
+	u.SetNull(xunji.FieldAPIBase)
+	return u
+}
+
+// SetAPIKey sets the "api_key" field.
+func (u *XunjiUpsert) SetAPIKey(v string) *XunjiUpsert {
+	u.Set(xunji.FieldAPIKey, v)
+	return u
+}
+
+// UpdateAPIKey sets the "api_key" field to the value that was provided on create.
+func (u *XunjiUpsert) UpdateAPIKey() *XunjiUpsert {
+	u.SetExcluded(xunji.FieldAPIKey)
+	return u
+}
+
+// ClearAPIKey clears the value of the "api_key" field.
+func (u *XunjiUpsert) ClearAPIKey() *XunjiUpsert {
+	u.SetNull(xunji.FieldAPIKey)
+	return u
+}
+
+// UpdateNewValues updates the mutable fields using the new values that were set on create except the ID field.
+// Using this option is equivalent to using:
+//
+//	client.Xunji.Create().
+//		OnConflict(
+//			sql.ResolveWithNewValues(),
+//			sql.ResolveWith(func(u *sql.UpdateSet) {
+//				u.SetIgnore(xunji.FieldID)
+//			}),
+//		).
+//		Exec(ctx)
+func (u *XunjiUpsertOne) UpdateNewValues() *XunjiUpsertOne {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues())
+	u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) {
+		if _, exists := u.create.mutation.ID(); exists {
+			s.SetIgnore(xunji.FieldID)
+		}
+		if _, exists := u.create.mutation.CreatedAt(); exists {
+			s.SetIgnore(xunji.FieldCreatedAt)
+		}
+	}))
+	return u
+}
+
+// Ignore sets each column to itself in case of conflict.
+// Using this option is equivalent to using:
+//
+//	client.Xunji.Create().
+//	    OnConflict(sql.ResolveWithIgnore()).
+//	    Exec(ctx)
+func (u *XunjiUpsertOne) Ignore() *XunjiUpsertOne {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore())
+	return u
+}
+
+// DoNothing configures the conflict_action to `DO NOTHING`.
+// Supported only by SQLite and PostgreSQL.
+func (u *XunjiUpsertOne) DoNothing() *XunjiUpsertOne {
+	u.create.conflict = append(u.create.conflict, sql.DoNothing())
+	return u
+}
+
+// Update allows overriding fields `UPDATE` values. See the XunjiCreate.OnConflict
+// documentation for more info.
+func (u *XunjiUpsertOne) Update(set func(*XunjiUpsert)) *XunjiUpsertOne {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
+		set(&XunjiUpsert{UpdateSet: update})
+	}))
+	return u
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (u *XunjiUpsertOne) SetUpdatedAt(v time.Time) *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetUpdatedAt(v)
+	})
+}
+
+// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
+func (u *XunjiUpsertOne) UpdateUpdatedAt() *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateUpdatedAt()
+	})
+}
+
+// SetStatus sets the "status" field.
+func (u *XunjiUpsertOne) SetStatus(v uint8) *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetStatus(v)
+	})
+}
+
+// AddStatus adds v to the "status" field.
+func (u *XunjiUpsertOne) AddStatus(v uint8) *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.AddStatus(v)
+	})
+}
+
+// UpdateStatus sets the "status" field to the value that was provided on create.
+func (u *XunjiUpsertOne) UpdateStatus() *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateStatus()
+	})
+}
+
+// ClearStatus clears the value of the "status" field.
+func (u *XunjiUpsertOne) ClearStatus() *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.ClearStatus()
+	})
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (u *XunjiUpsertOne) SetDeletedAt(v time.Time) *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetDeletedAt(v)
+	})
+}
+
+// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
+func (u *XunjiUpsertOne) UpdateDeletedAt() *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateDeletedAt()
+	})
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (u *XunjiUpsertOne) ClearDeletedAt() *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.ClearDeletedAt()
+	})
+}
+
+// SetAppKey sets the "app_key" field.
+func (u *XunjiUpsertOne) SetAppKey(v string) *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetAppKey(v)
+	})
+}
+
+// UpdateAppKey sets the "app_key" field to the value that was provided on create.
+func (u *XunjiUpsertOne) UpdateAppKey() *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateAppKey()
+	})
+}
+
+// SetAppSecret sets the "app_secret" field.
+func (u *XunjiUpsertOne) SetAppSecret(v string) *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetAppSecret(v)
+	})
+}
+
+// UpdateAppSecret sets the "app_secret" field to the value that was provided on create.
+func (u *XunjiUpsertOne) UpdateAppSecret() *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateAppSecret()
+	})
+}
+
+// SetToken sets the "token" field.
+func (u *XunjiUpsertOne) SetToken(v string) *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetToken(v)
+	})
+}
+
+// UpdateToken sets the "token" field to the value that was provided on create.
+func (u *XunjiUpsertOne) UpdateToken() *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateToken()
+	})
+}
+
+// SetEncodingKey sets the "encoding_key" field.
+func (u *XunjiUpsertOne) SetEncodingKey(v string) *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetEncodingKey(v)
+	})
+}
+
+// UpdateEncodingKey sets the "encoding_key" field to the value that was provided on create.
+func (u *XunjiUpsertOne) UpdateEncodingKey() *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateEncodingKey()
+	})
+}
+
+// SetAgentID sets the "agent_id" field.
+func (u *XunjiUpsertOne) SetAgentID(v uint64) *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetAgentID(v)
+	})
+}
+
+// AddAgentID adds v to the "agent_id" field.
+func (u *XunjiUpsertOne) AddAgentID(v uint64) *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.AddAgentID(v)
+	})
+}
+
+// UpdateAgentID sets the "agent_id" field to the value that was provided on create.
+func (u *XunjiUpsertOne) UpdateAgentID() *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateAgentID()
+	})
+}
+
+// SetOrganizationID sets the "organization_id" field.
+func (u *XunjiUpsertOne) SetOrganizationID(v uint64) *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetOrganizationID(v)
+	})
+}
+
+// AddOrganizationID adds v to the "organization_id" field.
+func (u *XunjiUpsertOne) AddOrganizationID(v uint64) *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.AddOrganizationID(v)
+	})
+}
+
+// UpdateOrganizationID sets the "organization_id" field to the value that was provided on create.
+func (u *XunjiUpsertOne) UpdateOrganizationID() *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateOrganizationID()
+	})
+}
+
+// SetWxid sets the "wxid" field.
+func (u *XunjiUpsertOne) SetWxid(v string) *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetWxid(v)
+	})
+}
+
+// UpdateWxid sets the "wxid" field to the value that was provided on create.
+func (u *XunjiUpsertOne) UpdateWxid() *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateWxid()
+	})
+}
+
+// SetAPIBase sets the "api_base" field.
+func (u *XunjiUpsertOne) SetAPIBase(v string) *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetAPIBase(v)
+	})
+}
+
+// UpdateAPIBase sets the "api_base" field to the value that was provided on create.
+func (u *XunjiUpsertOne) UpdateAPIBase() *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateAPIBase()
+	})
+}
+
+// ClearAPIBase clears the value of the "api_base" field.
+func (u *XunjiUpsertOne) ClearAPIBase() *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.ClearAPIBase()
+	})
+}
+
+// SetAPIKey sets the "api_key" field.
+func (u *XunjiUpsertOne) SetAPIKey(v string) *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetAPIKey(v)
+	})
+}
+
+// UpdateAPIKey sets the "api_key" field to the value that was provided on create.
+func (u *XunjiUpsertOne) UpdateAPIKey() *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateAPIKey()
+	})
+}
+
+// ClearAPIKey clears the value of the "api_key" field.
+func (u *XunjiUpsertOne) ClearAPIKey() *XunjiUpsertOne {
+	return u.Update(func(s *XunjiUpsert) {
+		s.ClearAPIKey()
+	})
+}
+
+// Exec executes the query.
+func (u *XunjiUpsertOne) Exec(ctx context.Context) error {
+	if len(u.create.conflict) == 0 {
+		return errors.New("ent: missing options for XunjiCreate.OnConflict")
+	}
+	return u.create.Exec(ctx)
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (u *XunjiUpsertOne) ExecX(ctx context.Context) {
+	if err := u.create.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// Exec executes the UPSERT query and returns the inserted/updated ID.
+func (u *XunjiUpsertOne) ID(ctx context.Context) (id uint64, err error) {
+	node, err := u.create.Save(ctx)
+	if err != nil {
+		return id, err
+	}
+	return node.ID, nil
+}
+
+// IDX is like ID, but panics if an error occurs.
+func (u *XunjiUpsertOne) IDX(ctx context.Context) uint64 {
+	id, err := u.ID(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return id
+}
+
+// XunjiCreateBulk is the builder for creating many Xunji entities in bulk.
+type XunjiCreateBulk struct {
+	config
+	err      error
+	builders []*XunjiCreate
+	conflict []sql.ConflictOption
+}
+
+// Save creates the Xunji entities in the database.
+func (xcb *XunjiCreateBulk) Save(ctx context.Context) ([]*Xunji, error) {
+	if xcb.err != nil {
+		return nil, xcb.err
+	}
+	specs := make([]*sqlgraph.CreateSpec, len(xcb.builders))
+	nodes := make([]*Xunji, len(xcb.builders))
+	mutators := make([]Mutator, len(xcb.builders))
+	for i := range xcb.builders {
+		func(i int, root context.Context) {
+			builder := xcb.builders[i]
+			builder.defaults()
+			var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
+				mutation, ok := m.(*XunjiMutation)
+				if !ok {
+					return nil, fmt.Errorf("unexpected mutation type %T", m)
+				}
+				if err := builder.check(); err != nil {
+					return nil, err
+				}
+				builder.mutation = mutation
+				var err error
+				nodes[i], specs[i] = builder.createSpec()
+				if i < len(mutators)-1 {
+					_, err = mutators[i+1].Mutate(root, xcb.builders[i+1].mutation)
+				} else {
+					spec := &sqlgraph.BatchCreateSpec{Nodes: specs}
+					spec.OnConflict = xcb.conflict
+					// Invoke the actual operation on the latest mutation in the chain.
+					if err = sqlgraph.BatchCreate(ctx, xcb.driver, spec); err != nil {
+						if sqlgraph.IsConstraintError(err) {
+							err = &ConstraintError{msg: err.Error(), wrap: err}
+						}
+					}
+				}
+				if err != nil {
+					return nil, err
+				}
+				mutation.id = &nodes[i].ID
+				if specs[i].ID.Value != nil && nodes[i].ID == 0 {
+					id := specs[i].ID.Value.(int64)
+					nodes[i].ID = uint64(id)
+				}
+				mutation.done = true
+				return nodes[i], nil
+			})
+			for i := len(builder.hooks) - 1; i >= 0; i-- {
+				mut = builder.hooks[i](mut)
+			}
+			mutators[i] = mut
+		}(i, ctx)
+	}
+	if len(mutators) > 0 {
+		if _, err := mutators[0].Mutate(ctx, xcb.builders[0].mutation); err != nil {
+			return nil, err
+		}
+	}
+	return nodes, nil
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (xcb *XunjiCreateBulk) SaveX(ctx context.Context) []*Xunji {
+	v, err := xcb.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Exec executes the query.
+func (xcb *XunjiCreateBulk) Exec(ctx context.Context) error {
+	_, err := xcb.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (xcb *XunjiCreateBulk) ExecX(ctx context.Context) {
+	if err := xcb.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
+// of the `INSERT` statement. For example:
+//
+//	client.Xunji.CreateBulk(builders...).
+//		OnConflict(
+//			// Update the row with the new values
+//			// the was proposed for insertion.
+//			sql.ResolveWithNewValues(),
+//		).
+//		// Override some of the fields with custom
+//		// update values.
+//		Update(func(u *ent.XunjiUpsert) {
+//			SetCreatedAt(v+v).
+//		}).
+//		Exec(ctx)
+func (xcb *XunjiCreateBulk) OnConflict(opts ...sql.ConflictOption) *XunjiUpsertBulk {
+	xcb.conflict = opts
+	return &XunjiUpsertBulk{
+		create: xcb,
+	}
+}
+
+// OnConflictColumns calls `OnConflict` and configures the columns
+// as conflict target. Using this option is equivalent to using:
+//
+//	client.Xunji.Create().
+//		OnConflict(sql.ConflictColumns(columns...)).
+//		Exec(ctx)
+func (xcb *XunjiCreateBulk) OnConflictColumns(columns ...string) *XunjiUpsertBulk {
+	xcb.conflict = append(xcb.conflict, sql.ConflictColumns(columns...))
+	return &XunjiUpsertBulk{
+		create: xcb,
+	}
+}
+
+// XunjiUpsertBulk is the builder for "upsert"-ing
+// a bulk of Xunji nodes.
+type XunjiUpsertBulk struct {
+	create *XunjiCreateBulk
+}
+
+// UpdateNewValues updates the mutable fields using the new values that
+// were set on create. Using this option is equivalent to using:
+//
+//	client.Xunji.Create().
+//		OnConflict(
+//			sql.ResolveWithNewValues(),
+//			sql.ResolveWith(func(u *sql.UpdateSet) {
+//				u.SetIgnore(xunji.FieldID)
+//			}),
+//		).
+//		Exec(ctx)
+func (u *XunjiUpsertBulk) UpdateNewValues() *XunjiUpsertBulk {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues())
+	u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) {
+		for _, b := range u.create.builders {
+			if _, exists := b.mutation.ID(); exists {
+				s.SetIgnore(xunji.FieldID)
+			}
+			if _, exists := b.mutation.CreatedAt(); exists {
+				s.SetIgnore(xunji.FieldCreatedAt)
+			}
+		}
+	}))
+	return u
+}
+
+// Ignore sets each column to itself in case of conflict.
+// Using this option is equivalent to using:
+//
+//	client.Xunji.Create().
+//		OnConflict(sql.ResolveWithIgnore()).
+//		Exec(ctx)
+func (u *XunjiUpsertBulk) Ignore() *XunjiUpsertBulk {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore())
+	return u
+}
+
+// DoNothing configures the conflict_action to `DO NOTHING`.
+// Supported only by SQLite and PostgreSQL.
+func (u *XunjiUpsertBulk) DoNothing() *XunjiUpsertBulk {
+	u.create.conflict = append(u.create.conflict, sql.DoNothing())
+	return u
+}
+
+// Update allows overriding fields `UPDATE` values. See the XunjiCreateBulk.OnConflict
+// documentation for more info.
+func (u *XunjiUpsertBulk) Update(set func(*XunjiUpsert)) *XunjiUpsertBulk {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
+		set(&XunjiUpsert{UpdateSet: update})
+	}))
+	return u
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (u *XunjiUpsertBulk) SetUpdatedAt(v time.Time) *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetUpdatedAt(v)
+	})
+}
+
+// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
+func (u *XunjiUpsertBulk) UpdateUpdatedAt() *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateUpdatedAt()
+	})
+}
+
+// SetStatus sets the "status" field.
+func (u *XunjiUpsertBulk) SetStatus(v uint8) *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetStatus(v)
+	})
+}
+
+// AddStatus adds v to the "status" field.
+func (u *XunjiUpsertBulk) AddStatus(v uint8) *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.AddStatus(v)
+	})
+}
+
+// UpdateStatus sets the "status" field to the value that was provided on create.
+func (u *XunjiUpsertBulk) UpdateStatus() *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateStatus()
+	})
+}
+
+// ClearStatus clears the value of the "status" field.
+func (u *XunjiUpsertBulk) ClearStatus() *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.ClearStatus()
+	})
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (u *XunjiUpsertBulk) SetDeletedAt(v time.Time) *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetDeletedAt(v)
+	})
+}
+
+// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
+func (u *XunjiUpsertBulk) UpdateDeletedAt() *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateDeletedAt()
+	})
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (u *XunjiUpsertBulk) ClearDeletedAt() *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.ClearDeletedAt()
+	})
+}
+
+// SetAppKey sets the "app_key" field.
+func (u *XunjiUpsertBulk) SetAppKey(v string) *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetAppKey(v)
+	})
+}
+
+// UpdateAppKey sets the "app_key" field to the value that was provided on create.
+func (u *XunjiUpsertBulk) UpdateAppKey() *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateAppKey()
+	})
+}
+
+// SetAppSecret sets the "app_secret" field.
+func (u *XunjiUpsertBulk) SetAppSecret(v string) *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetAppSecret(v)
+	})
+}
+
+// UpdateAppSecret sets the "app_secret" field to the value that was provided on create.
+func (u *XunjiUpsertBulk) UpdateAppSecret() *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateAppSecret()
+	})
+}
+
+// SetToken sets the "token" field.
+func (u *XunjiUpsertBulk) SetToken(v string) *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetToken(v)
+	})
+}
+
+// UpdateToken sets the "token" field to the value that was provided on create.
+func (u *XunjiUpsertBulk) UpdateToken() *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateToken()
+	})
+}
+
+// SetEncodingKey sets the "encoding_key" field.
+func (u *XunjiUpsertBulk) SetEncodingKey(v string) *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetEncodingKey(v)
+	})
+}
+
+// UpdateEncodingKey sets the "encoding_key" field to the value that was provided on create.
+func (u *XunjiUpsertBulk) UpdateEncodingKey() *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateEncodingKey()
+	})
+}
+
+// SetAgentID sets the "agent_id" field.
+func (u *XunjiUpsertBulk) SetAgentID(v uint64) *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetAgentID(v)
+	})
+}
+
+// AddAgentID adds v to the "agent_id" field.
+func (u *XunjiUpsertBulk) AddAgentID(v uint64) *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.AddAgentID(v)
+	})
+}
+
+// UpdateAgentID sets the "agent_id" field to the value that was provided on create.
+func (u *XunjiUpsertBulk) UpdateAgentID() *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateAgentID()
+	})
+}
+
+// SetOrganizationID sets the "organization_id" field.
+func (u *XunjiUpsertBulk) SetOrganizationID(v uint64) *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetOrganizationID(v)
+	})
+}
+
+// AddOrganizationID adds v to the "organization_id" field.
+func (u *XunjiUpsertBulk) AddOrganizationID(v uint64) *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.AddOrganizationID(v)
+	})
+}
+
+// UpdateOrganizationID sets the "organization_id" field to the value that was provided on create.
+func (u *XunjiUpsertBulk) UpdateOrganizationID() *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateOrganizationID()
+	})
+}
+
+// SetWxid sets the "wxid" field.
+func (u *XunjiUpsertBulk) SetWxid(v string) *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetWxid(v)
+	})
+}
+
+// UpdateWxid sets the "wxid" field to the value that was provided on create.
+func (u *XunjiUpsertBulk) UpdateWxid() *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateWxid()
+	})
+}
+
+// SetAPIBase sets the "api_base" field.
+func (u *XunjiUpsertBulk) SetAPIBase(v string) *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetAPIBase(v)
+	})
+}
+
+// UpdateAPIBase sets the "api_base" field to the value that was provided on create.
+func (u *XunjiUpsertBulk) UpdateAPIBase() *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateAPIBase()
+	})
+}
+
+// ClearAPIBase clears the value of the "api_base" field.
+func (u *XunjiUpsertBulk) ClearAPIBase() *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.ClearAPIBase()
+	})
+}
+
+// SetAPIKey sets the "api_key" field.
+func (u *XunjiUpsertBulk) SetAPIKey(v string) *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.SetAPIKey(v)
+	})
+}
+
+// UpdateAPIKey sets the "api_key" field to the value that was provided on create.
+func (u *XunjiUpsertBulk) UpdateAPIKey() *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.UpdateAPIKey()
+	})
+}
+
+// ClearAPIKey clears the value of the "api_key" field.
+func (u *XunjiUpsertBulk) ClearAPIKey() *XunjiUpsertBulk {
+	return u.Update(func(s *XunjiUpsert) {
+		s.ClearAPIKey()
+	})
+}
+
+// Exec executes the query.
+func (u *XunjiUpsertBulk) Exec(ctx context.Context) error {
+	if u.create.err != nil {
+		return u.create.err
+	}
+	for i, b := range u.create.builders {
+		if len(b.conflict) != 0 {
+			return fmt.Errorf("ent: OnConflict was set for builder %d. Set it on the XunjiCreateBulk instead", i)
+		}
+	}
+	if len(u.create.conflict) == 0 {
+		return errors.New("ent: missing options for XunjiCreateBulk.OnConflict")
+	}
+	return u.create.Exec(ctx)
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (u *XunjiUpsertBulk) ExecX(ctx context.Context) {
+	if err := u.create.Exec(ctx); err != nil {
+		panic(err)
+	}
+}

+ 88 - 0
ent/xunji_delete.go

@@ -0,0 +1,88 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"wechat-api/ent/predicate"
+	"wechat-api/ent/xunji"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+)
+
+// XunjiDelete is the builder for deleting a Xunji entity.
+type XunjiDelete struct {
+	config
+	hooks    []Hook
+	mutation *XunjiMutation
+}
+
+// Where appends a list predicates to the XunjiDelete builder.
+func (xd *XunjiDelete) Where(ps ...predicate.Xunji) *XunjiDelete {
+	xd.mutation.Where(ps...)
+	return xd
+}
+
+// Exec executes the deletion query and returns how many vertices were deleted.
+func (xd *XunjiDelete) Exec(ctx context.Context) (int, error) {
+	return withHooks(ctx, xd.sqlExec, xd.mutation, xd.hooks)
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (xd *XunjiDelete) ExecX(ctx context.Context) int {
+	n, err := xd.Exec(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return n
+}
+
+func (xd *XunjiDelete) sqlExec(ctx context.Context) (int, error) {
+	_spec := sqlgraph.NewDeleteSpec(xunji.Table, sqlgraph.NewFieldSpec(xunji.FieldID, field.TypeUint64))
+	if ps := xd.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	affected, err := sqlgraph.DeleteNodes(ctx, xd.driver, _spec)
+	if err != nil && sqlgraph.IsConstraintError(err) {
+		err = &ConstraintError{msg: err.Error(), wrap: err}
+	}
+	xd.mutation.done = true
+	return affected, err
+}
+
+// XunjiDeleteOne is the builder for deleting a single Xunji entity.
+type XunjiDeleteOne struct {
+	xd *XunjiDelete
+}
+
+// Where appends a list predicates to the XunjiDelete builder.
+func (xdo *XunjiDeleteOne) Where(ps ...predicate.Xunji) *XunjiDeleteOne {
+	xdo.xd.mutation.Where(ps...)
+	return xdo
+}
+
+// Exec executes the deletion query.
+func (xdo *XunjiDeleteOne) Exec(ctx context.Context) error {
+	n, err := xdo.xd.Exec(ctx)
+	switch {
+	case err != nil:
+		return err
+	case n == 0:
+		return &NotFoundError{xunji.Label}
+	default:
+		return nil
+	}
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (xdo *XunjiDeleteOne) ExecX(ctx context.Context) {
+	if err := xdo.Exec(ctx); err != nil {
+		panic(err)
+	}
+}

+ 526 - 0
ent/xunji_query.go

@@ -0,0 +1,526 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"fmt"
+	"math"
+	"wechat-api/ent/predicate"
+	"wechat-api/ent/xunji"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+)
+
+// XunjiQuery is the builder for querying Xunji entities.
+type XunjiQuery struct {
+	config
+	ctx        *QueryContext
+	order      []xunji.OrderOption
+	inters     []Interceptor
+	predicates []predicate.Xunji
+	// intermediate query (i.e. traversal path).
+	sql  *sql.Selector
+	path func(context.Context) (*sql.Selector, error)
+}
+
+// Where adds a new predicate for the XunjiQuery builder.
+func (xq *XunjiQuery) Where(ps ...predicate.Xunji) *XunjiQuery {
+	xq.predicates = append(xq.predicates, ps...)
+	return xq
+}
+
+// Limit the number of records to be returned by this query.
+func (xq *XunjiQuery) Limit(limit int) *XunjiQuery {
+	xq.ctx.Limit = &limit
+	return xq
+}
+
+// Offset to start from.
+func (xq *XunjiQuery) Offset(offset int) *XunjiQuery {
+	xq.ctx.Offset = &offset
+	return xq
+}
+
+// Unique configures the query builder to filter duplicate records on query.
+// By default, unique is set to true, and can be disabled using this method.
+func (xq *XunjiQuery) Unique(unique bool) *XunjiQuery {
+	xq.ctx.Unique = &unique
+	return xq
+}
+
+// Order specifies how the records should be ordered.
+func (xq *XunjiQuery) Order(o ...xunji.OrderOption) *XunjiQuery {
+	xq.order = append(xq.order, o...)
+	return xq
+}
+
+// First returns the first Xunji entity from the query.
+// Returns a *NotFoundError when no Xunji was found.
+func (xq *XunjiQuery) First(ctx context.Context) (*Xunji, error) {
+	nodes, err := xq.Limit(1).All(setContextOp(ctx, xq.ctx, "First"))
+	if err != nil {
+		return nil, err
+	}
+	if len(nodes) == 0 {
+		return nil, &NotFoundError{xunji.Label}
+	}
+	return nodes[0], nil
+}
+
+// FirstX is like First, but panics if an error occurs.
+func (xq *XunjiQuery) FirstX(ctx context.Context) *Xunji {
+	node, err := xq.First(ctx)
+	if err != nil && !IsNotFound(err) {
+		panic(err)
+	}
+	return node
+}
+
+// FirstID returns the first Xunji ID from the query.
+// Returns a *NotFoundError when no Xunji ID was found.
+func (xq *XunjiQuery) FirstID(ctx context.Context) (id uint64, err error) {
+	var ids []uint64
+	if ids, err = xq.Limit(1).IDs(setContextOp(ctx, xq.ctx, "FirstID")); err != nil {
+		return
+	}
+	if len(ids) == 0 {
+		err = &NotFoundError{xunji.Label}
+		return
+	}
+	return ids[0], nil
+}
+
+// FirstIDX is like FirstID, but panics if an error occurs.
+func (xq *XunjiQuery) FirstIDX(ctx context.Context) uint64 {
+	id, err := xq.FirstID(ctx)
+	if err != nil && !IsNotFound(err) {
+		panic(err)
+	}
+	return id
+}
+
+// Only returns a single Xunji entity found by the query, ensuring it only returns one.
+// Returns a *NotSingularError when more than one Xunji entity is found.
+// Returns a *NotFoundError when no Xunji entities are found.
+func (xq *XunjiQuery) Only(ctx context.Context) (*Xunji, error) {
+	nodes, err := xq.Limit(2).All(setContextOp(ctx, xq.ctx, "Only"))
+	if err != nil {
+		return nil, err
+	}
+	switch len(nodes) {
+	case 1:
+		return nodes[0], nil
+	case 0:
+		return nil, &NotFoundError{xunji.Label}
+	default:
+		return nil, &NotSingularError{xunji.Label}
+	}
+}
+
+// OnlyX is like Only, but panics if an error occurs.
+func (xq *XunjiQuery) OnlyX(ctx context.Context) *Xunji {
+	node, err := xq.Only(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return node
+}
+
+// OnlyID is like Only, but returns the only Xunji ID in the query.
+// Returns a *NotSingularError when more than one Xunji ID is found.
+// Returns a *NotFoundError when no entities are found.
+func (xq *XunjiQuery) OnlyID(ctx context.Context) (id uint64, err error) {
+	var ids []uint64
+	if ids, err = xq.Limit(2).IDs(setContextOp(ctx, xq.ctx, "OnlyID")); err != nil {
+		return
+	}
+	switch len(ids) {
+	case 1:
+		id = ids[0]
+	case 0:
+		err = &NotFoundError{xunji.Label}
+	default:
+		err = &NotSingularError{xunji.Label}
+	}
+	return
+}
+
+// OnlyIDX is like OnlyID, but panics if an error occurs.
+func (xq *XunjiQuery) OnlyIDX(ctx context.Context) uint64 {
+	id, err := xq.OnlyID(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return id
+}
+
+// All executes the query and returns a list of Xunjis.
+func (xq *XunjiQuery) All(ctx context.Context) ([]*Xunji, error) {
+	ctx = setContextOp(ctx, xq.ctx, "All")
+	if err := xq.prepareQuery(ctx); err != nil {
+		return nil, err
+	}
+	qr := querierAll[[]*Xunji, *XunjiQuery]()
+	return withInterceptors[[]*Xunji](ctx, xq, qr, xq.inters)
+}
+
+// AllX is like All, but panics if an error occurs.
+func (xq *XunjiQuery) AllX(ctx context.Context) []*Xunji {
+	nodes, err := xq.All(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return nodes
+}
+
+// IDs executes the query and returns a list of Xunji IDs.
+func (xq *XunjiQuery) IDs(ctx context.Context) (ids []uint64, err error) {
+	if xq.ctx.Unique == nil && xq.path != nil {
+		xq.Unique(true)
+	}
+	ctx = setContextOp(ctx, xq.ctx, "IDs")
+	if err = xq.Select(xunji.FieldID).Scan(ctx, &ids); err != nil {
+		return nil, err
+	}
+	return ids, nil
+}
+
+// IDsX is like IDs, but panics if an error occurs.
+func (xq *XunjiQuery) IDsX(ctx context.Context) []uint64 {
+	ids, err := xq.IDs(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return ids
+}
+
+// Count returns the count of the given query.
+func (xq *XunjiQuery) Count(ctx context.Context) (int, error) {
+	ctx = setContextOp(ctx, xq.ctx, "Count")
+	if err := xq.prepareQuery(ctx); err != nil {
+		return 0, err
+	}
+	return withInterceptors[int](ctx, xq, querierCount[*XunjiQuery](), xq.inters)
+}
+
+// CountX is like Count, but panics if an error occurs.
+func (xq *XunjiQuery) CountX(ctx context.Context) int {
+	count, err := xq.Count(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return count
+}
+
+// Exist returns true if the query has elements in the graph.
+func (xq *XunjiQuery) Exist(ctx context.Context) (bool, error) {
+	ctx = setContextOp(ctx, xq.ctx, "Exist")
+	switch _, err := xq.FirstID(ctx); {
+	case IsNotFound(err):
+		return false, nil
+	case err != nil:
+		return false, fmt.Errorf("ent: check existence: %w", err)
+	default:
+		return true, nil
+	}
+}
+
+// ExistX is like Exist, but panics if an error occurs.
+func (xq *XunjiQuery) ExistX(ctx context.Context) bool {
+	exist, err := xq.Exist(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return exist
+}
+
+// Clone returns a duplicate of the XunjiQuery builder, including all associated steps. It can be
+// used to prepare common query builders and use them differently after the clone is made.
+func (xq *XunjiQuery) Clone() *XunjiQuery {
+	if xq == nil {
+		return nil
+	}
+	return &XunjiQuery{
+		config:     xq.config,
+		ctx:        xq.ctx.Clone(),
+		order:      append([]xunji.OrderOption{}, xq.order...),
+		inters:     append([]Interceptor{}, xq.inters...),
+		predicates: append([]predicate.Xunji{}, xq.predicates...),
+		// clone intermediate query.
+		sql:  xq.sql.Clone(),
+		path: xq.path,
+	}
+}
+
+// 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.
+//
+// Example:
+//
+//	var v []struct {
+//		CreatedAt time.Time `json:"created_at,omitempty"`
+//		Count int `json:"count,omitempty"`
+//	}
+//
+//	client.Xunji.Query().
+//		GroupBy(xunji.FieldCreatedAt).
+//		Aggregate(ent.Count()).
+//		Scan(ctx, &v)
+func (xq *XunjiQuery) GroupBy(field string, fields ...string) *XunjiGroupBy {
+	xq.ctx.Fields = append([]string{field}, fields...)
+	grbuild := &XunjiGroupBy{build: xq}
+	grbuild.flds = &xq.ctx.Fields
+	grbuild.label = xunji.Label
+	grbuild.scan = grbuild.Scan
+	return grbuild
+}
+
+// Select allows the selection one or more fields/columns for the given query,
+// instead of selecting all fields in the entity.
+//
+// Example:
+//
+//	var v []struct {
+//		CreatedAt time.Time `json:"created_at,omitempty"`
+//	}
+//
+//	client.Xunji.Query().
+//		Select(xunji.FieldCreatedAt).
+//		Scan(ctx, &v)
+func (xq *XunjiQuery) Select(fields ...string) *XunjiSelect {
+	xq.ctx.Fields = append(xq.ctx.Fields, fields...)
+	sbuild := &XunjiSelect{XunjiQuery: xq}
+	sbuild.label = xunji.Label
+	sbuild.flds, sbuild.scan = &xq.ctx.Fields, sbuild.Scan
+	return sbuild
+}
+
+// Aggregate returns a XunjiSelect configured with the given aggregations.
+func (xq *XunjiQuery) Aggregate(fns ...AggregateFunc) *XunjiSelect {
+	return xq.Select().Aggregate(fns...)
+}
+
+func (xq *XunjiQuery) prepareQuery(ctx context.Context) error {
+	for _, inter := range xq.inters {
+		if inter == nil {
+			return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)")
+		}
+		if trv, ok := inter.(Traverser); ok {
+			if err := trv.Traverse(ctx, xq); err != nil {
+				return err
+			}
+		}
+	}
+	for _, f := range xq.ctx.Fields {
+		if !xunji.ValidColumn(f) {
+			return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
+		}
+	}
+	if xq.path != nil {
+		prev, err := xq.path(ctx)
+		if err != nil {
+			return err
+		}
+		xq.sql = prev
+	}
+	return nil
+}
+
+func (xq *XunjiQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Xunji, error) {
+	var (
+		nodes = []*Xunji{}
+		_spec = xq.querySpec()
+	)
+	_spec.ScanValues = func(columns []string) ([]any, error) {
+		return (*Xunji).scanValues(nil, columns)
+	}
+	_spec.Assign = func(columns []string, values []any) error {
+		node := &Xunji{config: xq.config}
+		nodes = append(nodes, node)
+		return node.assignValues(columns, values)
+	}
+	for i := range hooks {
+		hooks[i](ctx, _spec)
+	}
+	if err := sqlgraph.QueryNodes(ctx, xq.driver, _spec); err != nil {
+		return nil, err
+	}
+	if len(nodes) == 0 {
+		return nodes, nil
+	}
+	return nodes, nil
+}
+
+func (xq *XunjiQuery) sqlCount(ctx context.Context) (int, error) {
+	_spec := xq.querySpec()
+	_spec.Node.Columns = xq.ctx.Fields
+	if len(xq.ctx.Fields) > 0 {
+		_spec.Unique = xq.ctx.Unique != nil && *xq.ctx.Unique
+	}
+	return sqlgraph.CountNodes(ctx, xq.driver, _spec)
+}
+
+func (xq *XunjiQuery) querySpec() *sqlgraph.QuerySpec {
+	_spec := sqlgraph.NewQuerySpec(xunji.Table, xunji.Columns, sqlgraph.NewFieldSpec(xunji.FieldID, field.TypeUint64))
+	_spec.From = xq.sql
+	if unique := xq.ctx.Unique; unique != nil {
+		_spec.Unique = *unique
+	} else if xq.path != nil {
+		_spec.Unique = true
+	}
+	if fields := xq.ctx.Fields; len(fields) > 0 {
+		_spec.Node.Columns = make([]string, 0, len(fields))
+		_spec.Node.Columns = append(_spec.Node.Columns, xunji.FieldID)
+		for i := range fields {
+			if fields[i] != xunji.FieldID {
+				_spec.Node.Columns = append(_spec.Node.Columns, fields[i])
+			}
+		}
+	}
+	if ps := xq.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if limit := xq.ctx.Limit; limit != nil {
+		_spec.Limit = *limit
+	}
+	if offset := xq.ctx.Offset; offset != nil {
+		_spec.Offset = *offset
+	}
+	if ps := xq.order; len(ps) > 0 {
+		_spec.Order = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	return _spec
+}
+
+func (xq *XunjiQuery) sqlQuery(ctx context.Context) *sql.Selector {
+	builder := sql.Dialect(xq.driver.Dialect())
+	t1 := builder.Table(xunji.Table)
+	columns := xq.ctx.Fields
+	if len(columns) == 0 {
+		columns = xunji.Columns
+	}
+	selector := builder.Select(t1.Columns(columns...)...).From(t1)
+	if xq.sql != nil {
+		selector = xq.sql
+		selector.Select(selector.Columns(columns...)...)
+	}
+	if xq.ctx.Unique != nil && *xq.ctx.Unique {
+		selector.Distinct()
+	}
+	for _, p := range xq.predicates {
+		p(selector)
+	}
+	for _, p := range xq.order {
+		p(selector)
+	}
+	if offset := xq.ctx.Offset; offset != nil {
+		// limit is mandatory for offset clause. We start
+		// with default value, and override it below if needed.
+		selector.Offset(*offset).Limit(math.MaxInt32)
+	}
+	if limit := xq.ctx.Limit; limit != nil {
+		selector.Limit(*limit)
+	}
+	return selector
+}
+
+// XunjiGroupBy is the group-by builder for Xunji entities.
+type XunjiGroupBy struct {
+	selector
+	build *XunjiQuery
+}
+
+// Aggregate adds the given aggregation functions to the group-by query.
+func (xgb *XunjiGroupBy) Aggregate(fns ...AggregateFunc) *XunjiGroupBy {
+	xgb.fns = append(xgb.fns, fns...)
+	return xgb
+}
+
+// Scan applies the selector query and scans the result into the given value.
+func (xgb *XunjiGroupBy) Scan(ctx context.Context, v any) error {
+	ctx = setContextOp(ctx, xgb.build.ctx, "GroupBy")
+	if err := xgb.build.prepareQuery(ctx); err != nil {
+		return err
+	}
+	return scanWithInterceptors[*XunjiQuery, *XunjiGroupBy](ctx, xgb.build, xgb, xgb.build.inters, v)
+}
+
+func (xgb *XunjiGroupBy) sqlScan(ctx context.Context, root *XunjiQuery, v any) error {
+	selector := root.sqlQuery(ctx).Select()
+	aggregation := make([]string, 0, len(xgb.fns))
+	for _, fn := range xgb.fns {
+		aggregation = append(aggregation, fn(selector))
+	}
+	if len(selector.SelectedColumns()) == 0 {
+		columns := make([]string, 0, len(*xgb.flds)+len(xgb.fns))
+		for _, f := range *xgb.flds {
+			columns = append(columns, selector.C(f))
+		}
+		columns = append(columns, aggregation...)
+		selector.Select(columns...)
+	}
+	selector.GroupBy(selector.Columns(*xgb.flds...)...)
+	if err := selector.Err(); err != nil {
+		return err
+	}
+	rows := &sql.Rows{}
+	query, args := selector.Query()
+	if err := xgb.build.driver.Query(ctx, query, args, rows); err != nil {
+		return err
+	}
+	defer rows.Close()
+	return sql.ScanSlice(rows, v)
+}
+
+// XunjiSelect is the builder for selecting fields of Xunji entities.
+type XunjiSelect struct {
+	*XunjiQuery
+	selector
+}
+
+// Aggregate adds the given aggregation functions to the selector query.
+func (xs *XunjiSelect) Aggregate(fns ...AggregateFunc) *XunjiSelect {
+	xs.fns = append(xs.fns, fns...)
+	return xs
+}
+
+// Scan applies the selector query and scans the result into the given value.
+func (xs *XunjiSelect) Scan(ctx context.Context, v any) error {
+	ctx = setContextOp(ctx, xs.ctx, "Select")
+	if err := xs.prepareQuery(ctx); err != nil {
+		return err
+	}
+	return scanWithInterceptors[*XunjiQuery, *XunjiSelect](ctx, xs.XunjiQuery, xs, xs.inters, v)
+}
+
+func (xs *XunjiSelect) sqlScan(ctx context.Context, root *XunjiQuery, v any) error {
+	selector := root.sqlQuery(ctx)
+	aggregation := make([]string, 0, len(xs.fns))
+	for _, fn := range xs.fns {
+		aggregation = append(aggregation, fn(selector))
+	}
+	switch n := len(*xs.selector.flds); {
+	case n == 0 && len(aggregation) > 0:
+		selector.Select(aggregation...)
+	case n != 0 && len(aggregation) > 0:
+		selector.AppendSelect(aggregation...)
+	}
+	rows := &sql.Rows{}
+	query, args := selector.Query()
+	if err := xs.driver.Query(ctx, query, args, rows); err != nil {
+		return err
+	}
+	defer rows.Close()
+	return sql.ScanSlice(rows, v)
+}

+ 756 - 0
ent/xunji_update.go

@@ -0,0 +1,756 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"time"
+	"wechat-api/ent/predicate"
+	"wechat-api/ent/xunji"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+)
+
+// XunjiUpdate is the builder for updating Xunji entities.
+type XunjiUpdate struct {
+	config
+	hooks    []Hook
+	mutation *XunjiMutation
+}
+
+// Where appends a list predicates to the XunjiUpdate builder.
+func (xu *XunjiUpdate) Where(ps ...predicate.Xunji) *XunjiUpdate {
+	xu.mutation.Where(ps...)
+	return xu
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (xu *XunjiUpdate) SetUpdatedAt(t time.Time) *XunjiUpdate {
+	xu.mutation.SetUpdatedAt(t)
+	return xu
+}
+
+// SetStatus sets the "status" field.
+func (xu *XunjiUpdate) SetStatus(u uint8) *XunjiUpdate {
+	xu.mutation.ResetStatus()
+	xu.mutation.SetStatus(u)
+	return xu
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (xu *XunjiUpdate) SetNillableStatus(u *uint8) *XunjiUpdate {
+	if u != nil {
+		xu.SetStatus(*u)
+	}
+	return xu
+}
+
+// AddStatus adds u to the "status" field.
+func (xu *XunjiUpdate) AddStatus(u int8) *XunjiUpdate {
+	xu.mutation.AddStatus(u)
+	return xu
+}
+
+// ClearStatus clears the value of the "status" field.
+func (xu *XunjiUpdate) ClearStatus() *XunjiUpdate {
+	xu.mutation.ClearStatus()
+	return xu
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (xu *XunjiUpdate) SetDeletedAt(t time.Time) *XunjiUpdate {
+	xu.mutation.SetDeletedAt(t)
+	return xu
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (xu *XunjiUpdate) SetNillableDeletedAt(t *time.Time) *XunjiUpdate {
+	if t != nil {
+		xu.SetDeletedAt(*t)
+	}
+	return xu
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (xu *XunjiUpdate) ClearDeletedAt() *XunjiUpdate {
+	xu.mutation.ClearDeletedAt()
+	return xu
+}
+
+// SetAppKey sets the "app_key" field.
+func (xu *XunjiUpdate) SetAppKey(s string) *XunjiUpdate {
+	xu.mutation.SetAppKey(s)
+	return xu
+}
+
+// SetNillableAppKey sets the "app_key" field if the given value is not nil.
+func (xu *XunjiUpdate) SetNillableAppKey(s *string) *XunjiUpdate {
+	if s != nil {
+		xu.SetAppKey(*s)
+	}
+	return xu
+}
+
+// SetAppSecret sets the "app_secret" field.
+func (xu *XunjiUpdate) SetAppSecret(s string) *XunjiUpdate {
+	xu.mutation.SetAppSecret(s)
+	return xu
+}
+
+// SetNillableAppSecret sets the "app_secret" field if the given value is not nil.
+func (xu *XunjiUpdate) SetNillableAppSecret(s *string) *XunjiUpdate {
+	if s != nil {
+		xu.SetAppSecret(*s)
+	}
+	return xu
+}
+
+// SetToken sets the "token" field.
+func (xu *XunjiUpdate) SetToken(s string) *XunjiUpdate {
+	xu.mutation.SetToken(s)
+	return xu
+}
+
+// SetNillableToken sets the "token" field if the given value is not nil.
+func (xu *XunjiUpdate) SetNillableToken(s *string) *XunjiUpdate {
+	if s != nil {
+		xu.SetToken(*s)
+	}
+	return xu
+}
+
+// SetEncodingKey sets the "encoding_key" field.
+func (xu *XunjiUpdate) SetEncodingKey(s string) *XunjiUpdate {
+	xu.mutation.SetEncodingKey(s)
+	return xu
+}
+
+// SetNillableEncodingKey sets the "encoding_key" field if the given value is not nil.
+func (xu *XunjiUpdate) SetNillableEncodingKey(s *string) *XunjiUpdate {
+	if s != nil {
+		xu.SetEncodingKey(*s)
+	}
+	return xu
+}
+
+// SetAgentID sets the "agent_id" field.
+func (xu *XunjiUpdate) SetAgentID(u uint64) *XunjiUpdate {
+	xu.mutation.ResetAgentID()
+	xu.mutation.SetAgentID(u)
+	return xu
+}
+
+// SetNillableAgentID sets the "agent_id" field if the given value is not nil.
+func (xu *XunjiUpdate) SetNillableAgentID(u *uint64) *XunjiUpdate {
+	if u != nil {
+		xu.SetAgentID(*u)
+	}
+	return xu
+}
+
+// AddAgentID adds u to the "agent_id" field.
+func (xu *XunjiUpdate) AddAgentID(u int64) *XunjiUpdate {
+	xu.mutation.AddAgentID(u)
+	return xu
+}
+
+// SetOrganizationID sets the "organization_id" field.
+func (xu *XunjiUpdate) SetOrganizationID(u uint64) *XunjiUpdate {
+	xu.mutation.ResetOrganizationID()
+	xu.mutation.SetOrganizationID(u)
+	return xu
+}
+
+// SetNillableOrganizationID sets the "organization_id" field if the given value is not nil.
+func (xu *XunjiUpdate) SetNillableOrganizationID(u *uint64) *XunjiUpdate {
+	if u != nil {
+		xu.SetOrganizationID(*u)
+	}
+	return xu
+}
+
+// AddOrganizationID adds u to the "organization_id" field.
+func (xu *XunjiUpdate) AddOrganizationID(u int64) *XunjiUpdate {
+	xu.mutation.AddOrganizationID(u)
+	return xu
+}
+
+// SetWxid sets the "wxid" field.
+func (xu *XunjiUpdate) SetWxid(s string) *XunjiUpdate {
+	xu.mutation.SetWxid(s)
+	return xu
+}
+
+// SetNillableWxid sets the "wxid" field if the given value is not nil.
+func (xu *XunjiUpdate) SetNillableWxid(s *string) *XunjiUpdate {
+	if s != nil {
+		xu.SetWxid(*s)
+	}
+	return xu
+}
+
+// SetAPIBase sets the "api_base" field.
+func (xu *XunjiUpdate) SetAPIBase(s string) *XunjiUpdate {
+	xu.mutation.SetAPIBase(s)
+	return xu
+}
+
+// SetNillableAPIBase sets the "api_base" field if the given value is not nil.
+func (xu *XunjiUpdate) SetNillableAPIBase(s *string) *XunjiUpdate {
+	if s != nil {
+		xu.SetAPIBase(*s)
+	}
+	return xu
+}
+
+// ClearAPIBase clears the value of the "api_base" field.
+func (xu *XunjiUpdate) ClearAPIBase() *XunjiUpdate {
+	xu.mutation.ClearAPIBase()
+	return xu
+}
+
+// SetAPIKey sets the "api_key" field.
+func (xu *XunjiUpdate) SetAPIKey(s string) *XunjiUpdate {
+	xu.mutation.SetAPIKey(s)
+	return xu
+}
+
+// SetNillableAPIKey sets the "api_key" field if the given value is not nil.
+func (xu *XunjiUpdate) SetNillableAPIKey(s *string) *XunjiUpdate {
+	if s != nil {
+		xu.SetAPIKey(*s)
+	}
+	return xu
+}
+
+// ClearAPIKey clears the value of the "api_key" field.
+func (xu *XunjiUpdate) ClearAPIKey() *XunjiUpdate {
+	xu.mutation.ClearAPIKey()
+	return xu
+}
+
+// Mutation returns the XunjiMutation object of the builder.
+func (xu *XunjiUpdate) Mutation() *XunjiMutation {
+	return xu.mutation
+}
+
+// Save executes the query and returns the number of nodes affected by the update operation.
+func (xu *XunjiUpdate) Save(ctx context.Context) (int, error) {
+	if err := xu.defaults(); err != nil {
+		return 0, err
+	}
+	return withHooks(ctx, xu.sqlSave, xu.mutation, xu.hooks)
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (xu *XunjiUpdate) SaveX(ctx context.Context) int {
+	affected, err := xu.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return affected
+}
+
+// Exec executes the query.
+func (xu *XunjiUpdate) Exec(ctx context.Context) error {
+	_, err := xu.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (xu *XunjiUpdate) ExecX(ctx context.Context) {
+	if err := xu.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (xu *XunjiUpdate) defaults() error {
+	if _, ok := xu.mutation.UpdatedAt(); !ok {
+		if xunji.UpdateDefaultUpdatedAt == nil {
+			return fmt.Errorf("ent: uninitialized xunji.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)")
+		}
+		v := xunji.UpdateDefaultUpdatedAt()
+		xu.mutation.SetUpdatedAt(v)
+	}
+	return nil
+}
+
+// check runs all checks and user-defined validators on the builder.
+func (xu *XunjiUpdate) check() error {
+	if v, ok := xu.mutation.OrganizationID(); ok {
+		if err := xunji.OrganizationIDValidator(v); err != nil {
+			return &ValidationError{Name: "organization_id", err: fmt.Errorf(`ent: validator failed for field "Xunji.organization_id": %w`, err)}
+		}
+	}
+	return nil
+}
+
+func (xu *XunjiUpdate) sqlSave(ctx context.Context) (n int, err error) {
+	if err := xu.check(); err != nil {
+		return n, err
+	}
+	_spec := sqlgraph.NewUpdateSpec(xunji.Table, xunji.Columns, sqlgraph.NewFieldSpec(xunji.FieldID, field.TypeUint64))
+	if ps := xu.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if value, ok := xu.mutation.UpdatedAt(); ok {
+		_spec.SetField(xunji.FieldUpdatedAt, field.TypeTime, value)
+	}
+	if value, ok := xu.mutation.Status(); ok {
+		_spec.SetField(xunji.FieldStatus, field.TypeUint8, value)
+	}
+	if value, ok := xu.mutation.AddedStatus(); ok {
+		_spec.AddField(xunji.FieldStatus, field.TypeUint8, value)
+	}
+	if xu.mutation.StatusCleared() {
+		_spec.ClearField(xunji.FieldStatus, field.TypeUint8)
+	}
+	if value, ok := xu.mutation.DeletedAt(); ok {
+		_spec.SetField(xunji.FieldDeletedAt, field.TypeTime, value)
+	}
+	if xu.mutation.DeletedAtCleared() {
+		_spec.ClearField(xunji.FieldDeletedAt, field.TypeTime)
+	}
+	if value, ok := xu.mutation.AppKey(); ok {
+		_spec.SetField(xunji.FieldAppKey, field.TypeString, value)
+	}
+	if value, ok := xu.mutation.AppSecret(); ok {
+		_spec.SetField(xunji.FieldAppSecret, field.TypeString, value)
+	}
+	if value, ok := xu.mutation.Token(); ok {
+		_spec.SetField(xunji.FieldToken, field.TypeString, value)
+	}
+	if value, ok := xu.mutation.EncodingKey(); ok {
+		_spec.SetField(xunji.FieldEncodingKey, field.TypeString, value)
+	}
+	if value, ok := xu.mutation.AgentID(); ok {
+		_spec.SetField(xunji.FieldAgentID, field.TypeUint64, value)
+	}
+	if value, ok := xu.mutation.AddedAgentID(); ok {
+		_spec.AddField(xunji.FieldAgentID, field.TypeUint64, value)
+	}
+	if value, ok := xu.mutation.OrganizationID(); ok {
+		_spec.SetField(xunji.FieldOrganizationID, field.TypeUint64, value)
+	}
+	if value, ok := xu.mutation.AddedOrganizationID(); ok {
+		_spec.AddField(xunji.FieldOrganizationID, field.TypeUint64, value)
+	}
+	if value, ok := xu.mutation.Wxid(); ok {
+		_spec.SetField(xunji.FieldWxid, field.TypeString, value)
+	}
+	if value, ok := xu.mutation.APIBase(); ok {
+		_spec.SetField(xunji.FieldAPIBase, field.TypeString, value)
+	}
+	if xu.mutation.APIBaseCleared() {
+		_spec.ClearField(xunji.FieldAPIBase, field.TypeString)
+	}
+	if value, ok := xu.mutation.APIKey(); ok {
+		_spec.SetField(xunji.FieldAPIKey, field.TypeString, value)
+	}
+	if xu.mutation.APIKeyCleared() {
+		_spec.ClearField(xunji.FieldAPIKey, field.TypeString)
+	}
+	if n, err = sqlgraph.UpdateNodes(ctx, xu.driver, _spec); err != nil {
+		if _, ok := err.(*sqlgraph.NotFoundError); ok {
+			err = &NotFoundError{xunji.Label}
+		} else if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return 0, err
+	}
+	xu.mutation.done = true
+	return n, nil
+}
+
+// XunjiUpdateOne is the builder for updating a single Xunji entity.
+type XunjiUpdateOne struct {
+	config
+	fields   []string
+	hooks    []Hook
+	mutation *XunjiMutation
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (xuo *XunjiUpdateOne) SetUpdatedAt(t time.Time) *XunjiUpdateOne {
+	xuo.mutation.SetUpdatedAt(t)
+	return xuo
+}
+
+// SetStatus sets the "status" field.
+func (xuo *XunjiUpdateOne) SetStatus(u uint8) *XunjiUpdateOne {
+	xuo.mutation.ResetStatus()
+	xuo.mutation.SetStatus(u)
+	return xuo
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (xuo *XunjiUpdateOne) SetNillableStatus(u *uint8) *XunjiUpdateOne {
+	if u != nil {
+		xuo.SetStatus(*u)
+	}
+	return xuo
+}
+
+// AddStatus adds u to the "status" field.
+func (xuo *XunjiUpdateOne) AddStatus(u int8) *XunjiUpdateOne {
+	xuo.mutation.AddStatus(u)
+	return xuo
+}
+
+// ClearStatus clears the value of the "status" field.
+func (xuo *XunjiUpdateOne) ClearStatus() *XunjiUpdateOne {
+	xuo.mutation.ClearStatus()
+	return xuo
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (xuo *XunjiUpdateOne) SetDeletedAt(t time.Time) *XunjiUpdateOne {
+	xuo.mutation.SetDeletedAt(t)
+	return xuo
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (xuo *XunjiUpdateOne) SetNillableDeletedAt(t *time.Time) *XunjiUpdateOne {
+	if t != nil {
+		xuo.SetDeletedAt(*t)
+	}
+	return xuo
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (xuo *XunjiUpdateOne) ClearDeletedAt() *XunjiUpdateOne {
+	xuo.mutation.ClearDeletedAt()
+	return xuo
+}
+
+// SetAppKey sets the "app_key" field.
+func (xuo *XunjiUpdateOne) SetAppKey(s string) *XunjiUpdateOne {
+	xuo.mutation.SetAppKey(s)
+	return xuo
+}
+
+// SetNillableAppKey sets the "app_key" field if the given value is not nil.
+func (xuo *XunjiUpdateOne) SetNillableAppKey(s *string) *XunjiUpdateOne {
+	if s != nil {
+		xuo.SetAppKey(*s)
+	}
+	return xuo
+}
+
+// SetAppSecret sets the "app_secret" field.
+func (xuo *XunjiUpdateOne) SetAppSecret(s string) *XunjiUpdateOne {
+	xuo.mutation.SetAppSecret(s)
+	return xuo
+}
+
+// SetNillableAppSecret sets the "app_secret" field if the given value is not nil.
+func (xuo *XunjiUpdateOne) SetNillableAppSecret(s *string) *XunjiUpdateOne {
+	if s != nil {
+		xuo.SetAppSecret(*s)
+	}
+	return xuo
+}
+
+// SetToken sets the "token" field.
+func (xuo *XunjiUpdateOne) SetToken(s string) *XunjiUpdateOne {
+	xuo.mutation.SetToken(s)
+	return xuo
+}
+
+// SetNillableToken sets the "token" field if the given value is not nil.
+func (xuo *XunjiUpdateOne) SetNillableToken(s *string) *XunjiUpdateOne {
+	if s != nil {
+		xuo.SetToken(*s)
+	}
+	return xuo
+}
+
+// SetEncodingKey sets the "encoding_key" field.
+func (xuo *XunjiUpdateOne) SetEncodingKey(s string) *XunjiUpdateOne {
+	xuo.mutation.SetEncodingKey(s)
+	return xuo
+}
+
+// SetNillableEncodingKey sets the "encoding_key" field if the given value is not nil.
+func (xuo *XunjiUpdateOne) SetNillableEncodingKey(s *string) *XunjiUpdateOne {
+	if s != nil {
+		xuo.SetEncodingKey(*s)
+	}
+	return xuo
+}
+
+// SetAgentID sets the "agent_id" field.
+func (xuo *XunjiUpdateOne) SetAgentID(u uint64) *XunjiUpdateOne {
+	xuo.mutation.ResetAgentID()
+	xuo.mutation.SetAgentID(u)
+	return xuo
+}
+
+// SetNillableAgentID sets the "agent_id" field if the given value is not nil.
+func (xuo *XunjiUpdateOne) SetNillableAgentID(u *uint64) *XunjiUpdateOne {
+	if u != nil {
+		xuo.SetAgentID(*u)
+	}
+	return xuo
+}
+
+// AddAgentID adds u to the "agent_id" field.
+func (xuo *XunjiUpdateOne) AddAgentID(u int64) *XunjiUpdateOne {
+	xuo.mutation.AddAgentID(u)
+	return xuo
+}
+
+// SetOrganizationID sets the "organization_id" field.
+func (xuo *XunjiUpdateOne) SetOrganizationID(u uint64) *XunjiUpdateOne {
+	xuo.mutation.ResetOrganizationID()
+	xuo.mutation.SetOrganizationID(u)
+	return xuo
+}
+
+// SetNillableOrganizationID sets the "organization_id" field if the given value is not nil.
+func (xuo *XunjiUpdateOne) SetNillableOrganizationID(u *uint64) *XunjiUpdateOne {
+	if u != nil {
+		xuo.SetOrganizationID(*u)
+	}
+	return xuo
+}
+
+// AddOrganizationID adds u to the "organization_id" field.
+func (xuo *XunjiUpdateOne) AddOrganizationID(u int64) *XunjiUpdateOne {
+	xuo.mutation.AddOrganizationID(u)
+	return xuo
+}
+
+// SetWxid sets the "wxid" field.
+func (xuo *XunjiUpdateOne) SetWxid(s string) *XunjiUpdateOne {
+	xuo.mutation.SetWxid(s)
+	return xuo
+}
+
+// SetNillableWxid sets the "wxid" field if the given value is not nil.
+func (xuo *XunjiUpdateOne) SetNillableWxid(s *string) *XunjiUpdateOne {
+	if s != nil {
+		xuo.SetWxid(*s)
+	}
+	return xuo
+}
+
+// SetAPIBase sets the "api_base" field.
+func (xuo *XunjiUpdateOne) SetAPIBase(s string) *XunjiUpdateOne {
+	xuo.mutation.SetAPIBase(s)
+	return xuo
+}
+
+// SetNillableAPIBase sets the "api_base" field if the given value is not nil.
+func (xuo *XunjiUpdateOne) SetNillableAPIBase(s *string) *XunjiUpdateOne {
+	if s != nil {
+		xuo.SetAPIBase(*s)
+	}
+	return xuo
+}
+
+// ClearAPIBase clears the value of the "api_base" field.
+func (xuo *XunjiUpdateOne) ClearAPIBase() *XunjiUpdateOne {
+	xuo.mutation.ClearAPIBase()
+	return xuo
+}
+
+// SetAPIKey sets the "api_key" field.
+func (xuo *XunjiUpdateOne) SetAPIKey(s string) *XunjiUpdateOne {
+	xuo.mutation.SetAPIKey(s)
+	return xuo
+}
+
+// SetNillableAPIKey sets the "api_key" field if the given value is not nil.
+func (xuo *XunjiUpdateOne) SetNillableAPIKey(s *string) *XunjiUpdateOne {
+	if s != nil {
+		xuo.SetAPIKey(*s)
+	}
+	return xuo
+}
+
+// ClearAPIKey clears the value of the "api_key" field.
+func (xuo *XunjiUpdateOne) ClearAPIKey() *XunjiUpdateOne {
+	xuo.mutation.ClearAPIKey()
+	return xuo
+}
+
+// Mutation returns the XunjiMutation object of the builder.
+func (xuo *XunjiUpdateOne) Mutation() *XunjiMutation {
+	return xuo.mutation
+}
+
+// Where appends a list predicates to the XunjiUpdate builder.
+func (xuo *XunjiUpdateOne) Where(ps ...predicate.Xunji) *XunjiUpdateOne {
+	xuo.mutation.Where(ps...)
+	return xuo
+}
+
+// Select allows selecting one or more fields (columns) of the returned entity.
+// The default is selecting all fields defined in the entity schema.
+func (xuo *XunjiUpdateOne) Select(field string, fields ...string) *XunjiUpdateOne {
+	xuo.fields = append([]string{field}, fields...)
+	return xuo
+}
+
+// Save executes the query and returns the updated Xunji entity.
+func (xuo *XunjiUpdateOne) Save(ctx context.Context) (*Xunji, error) {
+	if err := xuo.defaults(); err != nil {
+		return nil, err
+	}
+	return withHooks(ctx, xuo.sqlSave, xuo.mutation, xuo.hooks)
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (xuo *XunjiUpdateOne) SaveX(ctx context.Context) *Xunji {
+	node, err := xuo.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return node
+}
+
+// Exec executes the query on the entity.
+func (xuo *XunjiUpdateOne) Exec(ctx context.Context) error {
+	_, err := xuo.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (xuo *XunjiUpdateOne) ExecX(ctx context.Context) {
+	if err := xuo.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (xuo *XunjiUpdateOne) defaults() error {
+	if _, ok := xuo.mutation.UpdatedAt(); !ok {
+		if xunji.UpdateDefaultUpdatedAt == nil {
+			return fmt.Errorf("ent: uninitialized xunji.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)")
+		}
+		v := xunji.UpdateDefaultUpdatedAt()
+		xuo.mutation.SetUpdatedAt(v)
+	}
+	return nil
+}
+
+// check runs all checks and user-defined validators on the builder.
+func (xuo *XunjiUpdateOne) check() error {
+	if v, ok := xuo.mutation.OrganizationID(); ok {
+		if err := xunji.OrganizationIDValidator(v); err != nil {
+			return &ValidationError{Name: "organization_id", err: fmt.Errorf(`ent: validator failed for field "Xunji.organization_id": %w`, err)}
+		}
+	}
+	return nil
+}
+
+func (xuo *XunjiUpdateOne) sqlSave(ctx context.Context) (_node *Xunji, err error) {
+	if err := xuo.check(); err != nil {
+		return _node, err
+	}
+	_spec := sqlgraph.NewUpdateSpec(xunji.Table, xunji.Columns, sqlgraph.NewFieldSpec(xunji.FieldID, field.TypeUint64))
+	id, ok := xuo.mutation.ID()
+	if !ok {
+		return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "Xunji.id" for update`)}
+	}
+	_spec.Node.ID.Value = id
+	if fields := xuo.fields; len(fields) > 0 {
+		_spec.Node.Columns = make([]string, 0, len(fields))
+		_spec.Node.Columns = append(_spec.Node.Columns, xunji.FieldID)
+		for _, f := range fields {
+			if !xunji.ValidColumn(f) {
+				return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
+			}
+			if f != xunji.FieldID {
+				_spec.Node.Columns = append(_spec.Node.Columns, f)
+			}
+		}
+	}
+	if ps := xuo.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if value, ok := xuo.mutation.UpdatedAt(); ok {
+		_spec.SetField(xunji.FieldUpdatedAt, field.TypeTime, value)
+	}
+	if value, ok := xuo.mutation.Status(); ok {
+		_spec.SetField(xunji.FieldStatus, field.TypeUint8, value)
+	}
+	if value, ok := xuo.mutation.AddedStatus(); ok {
+		_spec.AddField(xunji.FieldStatus, field.TypeUint8, value)
+	}
+	if xuo.mutation.StatusCleared() {
+		_spec.ClearField(xunji.FieldStatus, field.TypeUint8)
+	}
+	if value, ok := xuo.mutation.DeletedAt(); ok {
+		_spec.SetField(xunji.FieldDeletedAt, field.TypeTime, value)
+	}
+	if xuo.mutation.DeletedAtCleared() {
+		_spec.ClearField(xunji.FieldDeletedAt, field.TypeTime)
+	}
+	if value, ok := xuo.mutation.AppKey(); ok {
+		_spec.SetField(xunji.FieldAppKey, field.TypeString, value)
+	}
+	if value, ok := xuo.mutation.AppSecret(); ok {
+		_spec.SetField(xunji.FieldAppSecret, field.TypeString, value)
+	}
+	if value, ok := xuo.mutation.Token(); ok {
+		_spec.SetField(xunji.FieldToken, field.TypeString, value)
+	}
+	if value, ok := xuo.mutation.EncodingKey(); ok {
+		_spec.SetField(xunji.FieldEncodingKey, field.TypeString, value)
+	}
+	if value, ok := xuo.mutation.AgentID(); ok {
+		_spec.SetField(xunji.FieldAgentID, field.TypeUint64, value)
+	}
+	if value, ok := xuo.mutation.AddedAgentID(); ok {
+		_spec.AddField(xunji.FieldAgentID, field.TypeUint64, value)
+	}
+	if value, ok := xuo.mutation.OrganizationID(); ok {
+		_spec.SetField(xunji.FieldOrganizationID, field.TypeUint64, value)
+	}
+	if value, ok := xuo.mutation.AddedOrganizationID(); ok {
+		_spec.AddField(xunji.FieldOrganizationID, field.TypeUint64, value)
+	}
+	if value, ok := xuo.mutation.Wxid(); ok {
+		_spec.SetField(xunji.FieldWxid, field.TypeString, value)
+	}
+	if value, ok := xuo.mutation.APIBase(); ok {
+		_spec.SetField(xunji.FieldAPIBase, field.TypeString, value)
+	}
+	if xuo.mutation.APIBaseCleared() {
+		_spec.ClearField(xunji.FieldAPIBase, field.TypeString)
+	}
+	if value, ok := xuo.mutation.APIKey(); ok {
+		_spec.SetField(xunji.FieldAPIKey, field.TypeString, value)
+	}
+	if xuo.mutation.APIKeyCleared() {
+		_spec.ClearField(xunji.FieldAPIKey, field.TypeString)
+	}
+	_node = &Xunji{config: xuo.config}
+	_spec.Assign = _node.assignValues
+	_spec.ScanValues = _node.scanValues
+	if err = sqlgraph.UpdateNode(ctx, xuo.driver, _spec); err != nil {
+		if _, ok := err.(*sqlgraph.NotFoundError); ok {
+			err = &NotFoundError{xunji.Label}
+		} else if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return nil, err
+	}
+	xuo.mutation.done = true
+	return _node, nil
+}

+ 36 - 0
internal/handler/routes.go

@@ -49,6 +49,7 @@ import (
 	wxcarduser "wechat-api/internal/handler/wxcarduser"
 	wxcardvisit "wechat-api/internal/handler/wxcardvisit"
 	xiaoice "wechat-api/internal/handler/xiaoice"
+	xunji "wechat-api/internal/handler/xunji"
 	"wechat-api/internal/svc"
 
 	"github.com/zeromicro/go-zero/rest"
@@ -2052,5 +2053,40 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
 				Handler: wp_wecom.SendMsgByChanHandler(serverCtx),
 			},
 		},
+		rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
+	)
+
+	server.AddRoutes(
+		rest.WithMiddlewares(
+			[]rest.Middleware{serverCtx.Authority},
+			[]rest.Route{
+				{
+					Method:  http.MethodPost,
+					Path:    "/xunji/create",
+					Handler: xunji.CreateXunjiHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/xunji/update",
+					Handler: xunji.UpdateXunjiHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/xunji/delete",
+					Handler: xunji.DeleteXunjiHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/xunji/list",
+					Handler: xunji.GetXunjiListHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/xunji",
+					Handler: xunji.GetXunjiByIdHandler(serverCtx),
+				},
+			}...,
+		),
+		rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
 	)
 }

+ 44 - 0
internal/handler/xunji/create_xunji_handler.go

@@ -0,0 +1,44 @@
+package xunji
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/xunji"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /xunji/create xunji CreateXunji
+//
+// Create xunji information | 创建Xunji
+//
+// Create xunji information | 创建Xunji
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: XunjiInfo
+//
+// Responses:
+//  200: BaseMsgResp
+
+func CreateXunjiHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.XunjiInfo
+		if err := httpx.Parse(r, &req, true); err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+			return
+		}
+
+		l := xunji.NewCreateXunjiLogic(r.Context(), svcCtx)
+		resp, err := l.CreateXunji(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/xunji/delete_xunji_handler.go

@@ -0,0 +1,44 @@
+package xunji
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/xunji"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /xunji/delete xunji DeleteXunji
+//
+// Delete xunji information | 删除Xunji信息
+//
+// Delete xunji information | 删除Xunji信息
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: IDsReq
+//
+// Responses:
+//  200: BaseMsgResp
+
+func DeleteXunjiHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.IDsReq
+		if err := httpx.Parse(r, &req, true); err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+			return
+		}
+
+		l := xunji.NewDeleteXunjiLogic(r.Context(), svcCtx)
+		resp, err := l.DeleteXunji(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/xunji/get_xunji_by_id_handler.go

@@ -0,0 +1,44 @@
+package xunji
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/xunji"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /xunji xunji GetXunjiById
+//
+// Get xunji by ID | 通过ID获取Xunji
+//
+// Get xunji by ID | 通过ID获取Xunji
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: IDReq
+//
+// Responses:
+//  200: XunjiInfoResp
+
+func GetXunjiByIdHandler(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 := xunji.NewGetXunjiByIdLogic(r.Context(), svcCtx)
+		resp, err := l.GetXunjiById(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/xunji/get_xunji_list_handler.go

@@ -0,0 +1,44 @@
+package xunji
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/xunji"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /xunji/list xunji GetXunjiList
+//
+// Get xunji list | 获取Xunji列表
+//
+// Get xunji list | 获取Xunji列表
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: XunjiListReq
+//
+// Responses:
+//  200: XunjiListResp
+
+func GetXunjiListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.XunjiListReq
+		if err := httpx.Parse(r, &req, true); err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+			return
+		}
+
+		l := xunji.NewGetXunjiListLogic(r.Context(), svcCtx)
+		resp, err := l.GetXunjiList(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/xunji/update_xunji_handler.go

@@ -0,0 +1,44 @@
+package xunji
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/xunji"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /xunji/update xunji UpdateXunji
+//
+// Update xunji information | 更新Xunji
+//
+// Update xunji information | 更新Xunji
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: XunjiInfo
+//
+// Responses:
+//  200: BaseMsgResp
+
+func UpdateXunjiHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.XunjiInfo
+		if err := httpx.Parse(r, &req, true); err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+			return
+		}
+
+		l := xunji.NewUpdateXunjiLogic(r.Context(), svcCtx)
+		resp, err := l.UpdateXunji(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 2 - 79
internal/logic/agent/upload_agent_data_logic.go

@@ -1,32 +1,20 @@
 package agent
 
 import (
-	"bytes"
 	"context"
 	"encoding/csv"
 	"fmt"
-	"github.com/saintfish/chardet"
 	"github.com/suyuan32/simple-admin-common/msg/errormsg"
-	"golang.org/x/text/encoding"
-	"golang.org/x/text/encoding/charmap"
-	"golang.org/x/text/encoding/japanese"
-	"golang.org/x/text/encoding/korean"
-	"golang.org/x/text/encoding/traditionalchinese"
-	"golang.org/x/text/encoding/unicode"
-	"io"
 	"mime/multipart"
-	"strings"
 	agentModel "wechat-api/ent/agent"
 	"wechat-api/hook/fastgpt"
+	"wechat-api/internal/utils"
 	"wechat-api/internal/utils/dberrorhandler"
 
 	"wechat-api/internal/svc"
 	"wechat-api/internal/types"
 
 	"github.com/zeromicro/go-zero/core/logx"
-
-	"golang.org/x/text/encoding/simplifiedchinese"
-	"golang.org/x/text/transform"
 )
 
 type UploadAgentDataLogic struct {
@@ -116,72 +104,7 @@ func (l *UploadAgentDataLogic) UploadAgentData(req *types.UploadDataReq, file mu
 	return resp, nil
 }
 
-func trim(s string) string {
-	s = strings.TrimLeft(s, " \r\n\t")
-	s = strings.TrimRight(s, " \r\n\t")
-	return s
-}
-
 // transCharset 自动检测编码并转换为 UTF-8
 func transCharset(s string) string {
-	// 1. 自动检测编码
-	detector := chardet.NewTextDetector()
-	result, err := detector.DetectBest([]byte(s))
-	if err != nil {
-		fmt.Println("Encoding detection failed:", err)
-		return s
-	}
-
-	// 2. 找到相应的编码
-	fmt.Println("result.Charset:", result.Charset)
-	enc := getEncoding(result.Charset)
-	fmt.Println("enc:", enc)
-	if enc == nil {
-		// 直接返回原始字符串
-		fmt.Println("Unsupported charset:", result.Charset)
-		return s
-	}
-
-	// 3. 转换为 UTF-8
-	rd := transform.NewReader(bytes.NewReader([]byte(s)), enc.NewDecoder())
-	utf8Bytes, err := io.ReadAll(rd)
-	if err != nil {
-		fmt.Println("Encoding conversion failed:", err)
-		return s
-	}
-
-	// 4. 返回转换后的 UTF-8 字符串
-	return string(utf8Bytes)
-}
-
-// 根据字符集名称获取 `encoding.Encoding`
-func getEncoding(charset string) encoding.Encoding {
-	switch charset {
-	case "UTF-8", "ASCII":
-		return encoding.Nop // 无需转换
-	case "ISO-8859-1":
-		return charmap.ISO8859_1
-	case "ISO-8859-2":
-		return charmap.ISO8859_2
-	case "ISO-8859-15":
-		return charmap.ISO8859_15
-	case "Windows-1252":
-		return charmap.Windows1252
-	case "Big5":
-		return traditionalchinese.Big5
-	case "GB-2312", "GBK", "GB-18030":
-		return simplifiedchinese.GBK
-	case "Shift_JIS":
-		return japanese.ShiftJIS
-	case "EUC-JP":
-		return japanese.EUCJP
-	case "EUC-KR":
-		return korean.EUCKR
-	case "UTF-16LE":
-		return unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM)
-	case "UTF-16BE":
-		return unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM)
-	default:
-		return nil
-	}
+	return utils.TransCharset(s)
 }

+ 62 - 0
internal/logic/base/init_api_data.go

@@ -6,6 +6,68 @@ import (
 )
 
 func (l *InitDatabaseLogic) insertApiData() (err error) {
+	// Xunji
+
+	_, err = l.svcCtx.CoreRpc.CreateApi(l.ctx, &core.ApiInfo{
+		ServiceName: pointy.GetPointer("Wechat"),
+		Path:        pointy.GetPointer("/xunji/create"),
+		Description: pointy.GetPointer("apiDesc.createXunji"),
+		ApiGroup:    pointy.GetPointer("xunji"),
+		Method:      pointy.GetPointer("POST"),
+	})
+
+	if err != nil {
+		return err
+	}
+
+	_, err = l.svcCtx.CoreRpc.CreateApi(l.ctx, &core.ApiInfo{
+		ServiceName: pointy.GetPointer("Wechat"),
+		Path:        pointy.GetPointer("/xunji/update"),
+		Description: pointy.GetPointer("apiDesc.updateXunji"),
+		ApiGroup:    pointy.GetPointer("xunji"),
+		Method:      pointy.GetPointer("POST"),
+	})
+
+	if err != nil {
+		return err
+	}
+
+	_, err = l.svcCtx.CoreRpc.CreateApi(l.ctx, &core.ApiInfo{
+		ServiceName: pointy.GetPointer("Wechat"),
+		Path:        pointy.GetPointer("/xunji/delete"),
+		Description: pointy.GetPointer("apiDesc.deleteXunji"),
+		ApiGroup:    pointy.GetPointer("xunji"),
+		Method:      pointy.GetPointer("POST"),
+	})
+
+	if err != nil {
+		return err
+	}
+
+	_, err = l.svcCtx.CoreRpc.CreateApi(l.ctx, &core.ApiInfo{
+		ServiceName: pointy.GetPointer("Wechat"),
+		Path:        pointy.GetPointer("/xunji/list"),
+		Description: pointy.GetPointer("apiDesc.getXunjiList"),
+		ApiGroup:    pointy.GetPointer("xunji"),
+		Method:      pointy.GetPointer("POST"),
+	})
+
+	if err != nil {
+		return err
+	}
+
+	_, err = l.svcCtx.CoreRpc.CreateApi(l.ctx, &core.ApiInfo{
+		ServiceName: pointy.GetPointer("Wechat"),
+		Path:        pointy.GetPointer("/xunji"),
+		Description: pointy.GetPointer("apiDesc.getXunjiById"),
+		ApiGroup:    pointy.GetPointer("xunji"),
+		Method:      pointy.GetPointer("POST"),
+	})
+
+	if err != nil {
+		return err
+	}
+
 	// WhatsappChannel
 
 	_, err = l.svcCtx.CoreRpc.CreateApi(l.ctx, &core.ApiInfo{

+ 11 - 23
internal/logic/contact/import_whatsapp_contact_logic.go

@@ -1,15 +1,11 @@
 package contact
 
 import (
-	"bytes"
 	"context"
 	"encoding/csv"
 	"fmt"
 	"github.com/suyuan32/simple-admin-common/msg/errormsg"
 	"github.com/suyuan32/simple-admin-common/utils/uuidx"
-	"golang.org/x/text/encoding/simplifiedchinese"
-	"golang.org/x/text/transform"
-	"io"
 	"mime/multipart"
 	"strconv"
 	"strings"
@@ -19,6 +15,7 @@ import (
 	"wechat-api/ent/label"
 	"wechat-api/internal/svc"
 	"wechat-api/internal/types"
+	"wechat-api/internal/utils"
 
 	"github.com/zeromicro/go-zero/core/logx"
 )
@@ -59,8 +56,8 @@ func (l *ImportWhatsappContactLogic) ImportWhatsappContact(req *types.ImportWhat
 		_, err := l.svcCtx.DB.Contact.Query().Where(
 			contact.OrganizationID(organizationId),
 			contact.Ctype(2),
-			contact.Cc(trim(record[0])),
-			contact.Phone(trim(record[1])),
+			contact.Cc(utils.Trim(record[0])),
+			contact.Phone(utils.Trim(record[1])),
 		).First(l.ctx)
 		if err == nil || !ent.IsNotFound(err) {
 			fail++
@@ -68,16 +65,16 @@ func (l *ImportWhatsappContactLogic) ImportWhatsappContact(req *types.ImportWhat
 		}
 
 		uuidstr := uuidx.NewUUID().String()
-		sex, _ := strconv.Atoi(trim(record[5]))
-		cage, _ := strconv.Atoi(trim(record[7]))
+		sex, _ := strconv.Atoi(utils.Trim(record[5]))
+		cage, _ := strconv.Atoi(utils.Trim(record[7]))
 		var cbirthday string
-		t, err := time.Parse("2006/01/02", trim(record[8]))
+		t, err := time.Parse("2006/01/02", utils.Trim(record[8]))
 		if err == nil {
 			cbirthday = t.Format("2006-01-02")
 		}
 		newContact, err := l.svcCtx.DB.Contact.Create().SetCtype(2).
-			SetCc(trim(record[0])).
-			SetPhone(trim(record[1])).
+			SetCc(utils.Trim(record[0])).
+			SetPhone(utils.Trim(record[1])).
 			SetType(5).
 			SetWxWxid(uuidstr).
 			SetWxid(uuidstr).
@@ -89,7 +86,7 @@ func (l *ImportWhatsappContactLogic) ImportWhatsappContact(req *types.ImportWhat
 			SetCarea(transCharset(record[9])).
 			SetCbirthday(cbirthday).
 			SetCbirtharea(transCharset(record[10])).
-			SetCidcardNo(trim(record[11])).
+			SetCidcardNo(utils.Trim(record[11])).
 			SetOrganizationID(organizationId).
 			Save(l.ctx)
 		if err != nil {
@@ -100,7 +97,7 @@ func (l *ImportWhatsappContactLogic) ImportWhatsappContact(req *types.ImportWhat
 			success++
 		}
 
-		labels := trim(record[4])
+		labels := utils.Trim(record[4])
 		if labels != "" {
 			for _, value := range strings.Split(labels, "+") {
 				_, err = l.svcCtx.DB.Label.Query().Where(
@@ -140,15 +137,6 @@ func (l *ImportWhatsappContactLogic) ImportWhatsappContact(req *types.ImportWhat
 	return &resp, nil
 }
 
-func trim(s string) string {
-	return strings.Trim(s, " \r\n\t")
-}
-
 func transCharset(s string) string {
-	s = trim(s)
-	return s
-	rd := transform.NewReader(bytes.NewReader([]byte(s)), simplifiedchinese.GBK.NewDecoder())
-	bytes, err := io.ReadAll(rd)
-	fmt.Printf("bytes=%s err=%v\n", bytes, err)
-	return string(bytes)
+	return utils.TransCharset(s)
 }

+ 50 - 0
internal/logic/xunji/create_xunji_logic.go

@@ -0,0 +1,50 @@
+package xunji
+
+import (
+	"context"
+
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+	"wechat-api/internal/utils/dberrorhandler"
+
+	"github.com/suyuan32/simple-admin-common/msg/errormsg"
+
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type CreateXunjiLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewCreateXunjiLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateXunjiLogic {
+	return &CreateXunjiLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *CreateXunjiLogic) CreateXunji(req *types.XunjiInfo) (*types.BaseMsgResp, error) {
+	organizationId := l.ctx.Value("organizationId").(uint64)
+
+	_, err := l.svcCtx.DB.Xunji.Create().
+		SetStatus(1).
+		SetNotNilAppKey(req.AppKey).
+		SetNotNilAppSecret(req.AppSecret).
+		SetNotNilToken(req.Token).
+		SetNotNilEncodingKey(req.EncodingKey).
+		SetNotNilAgentID(req.AgentId).
+		SetOrganizationID(organizationId).
+		SetNotNilWxid(req.Wxid).
+		SetNotNilAPIBase(req.ApiBase).
+		SetNotNilAPIKey(req.ApiKey).
+		Save(l.ctx)
+
+	if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+	return &types.BaseMsgResp{Msg: errormsg.CreateSuccess}, nil
+}

+ 37 - 0
internal/logic/xunji/delete_xunji_logic.go

@@ -0,0 +1,37 @@
+package xunji
+
+import (
+	"context"
+
+    "wechat-api/ent/xunji"
+    "wechat-api/internal/svc"
+    "wechat-api/internal/types"
+    "wechat-api/internal/utils/dberrorhandler"
+
+    "github.com/suyuan32/simple-admin-common/msg/errormsg"
+    "github.com/zeromicro/go-zero/core/logx"
+)
+
+type DeleteXunjiLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewDeleteXunjiLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteXunjiLogic {
+	return &DeleteXunjiLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *DeleteXunjiLogic) DeleteXunji(req *types.IDsReq) (*types.BaseMsgResp, error) {
+	_, err := l.svcCtx.DB.Xunji.Delete().Where(xunji.IDIn(req.Ids...)).Exec(l.ctx)
+
+    if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+    return &types.BaseMsgResp{Msg: errormsg.DeleteSuccess}, nil
+}

+ 60 - 0
internal/logic/xunji/get_xunji_by_id_logic.go

@@ -0,0 +1,60 @@
+package xunji
+
+import (
+	"context"
+
+	"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/zeromicro/go-zero/core/logx"
+)
+
+type GetXunjiByIdLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewGetXunjiByIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetXunjiByIdLogic {
+	return &GetXunjiByIdLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *GetXunjiByIdLogic) GetXunjiById(req *types.IDReq) (*types.XunjiInfoResp, error) {
+	data, err := l.svcCtx.DB.Xunji.Get(l.ctx, req.Id)
+	if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+	return &types.XunjiInfoResp{
+	    BaseDataInfo: types.BaseDataInfo{
+            Code: 0,
+            Msg:  errormsg.Success,
+        },
+        Data: types.XunjiInfo{
+            BaseIDInfo:    types.BaseIDInfo{
+				Id:          &data.ID,
+				CreatedAt:    pointy.GetPointer(data.CreatedAt.UnixMilli()),
+				UpdatedAt:    pointy.GetPointer(data.UpdatedAt.UnixMilli()),
+            },
+			Status:	&data.Status,
+			AppKey:	&data.AppKey,
+			AppSecret:	&data.AppSecret,
+			Token:	&data.Token,
+			EncodingKey:	&data.EncodingKey,
+			AgentId:	&data.AgentID,
+			OrganizationId:	&data.OrganizationID,
+			Wxid:	&data.Wxid,
+			ApiBase:	&data.APIBase,
+			ApiKey:	&data.APIKey,
+        },
+	}, nil
+}
+

+ 75 - 0
internal/logic/xunji/get_xunji_list_logic.go

@@ -0,0 +1,75 @@
+package xunji
+
+import (
+	"context"
+
+	"wechat-api/ent/xunji"
+	"wechat-api/ent/predicate"
+	"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/zeromicro/go-zero/core/logx"
+)
+
+type GetXunjiListLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewGetXunjiListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetXunjiListLogic {
+	return &GetXunjiListLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *GetXunjiListLogic) GetXunjiList(req *types.XunjiListReq) (*types.XunjiListResp, error) {
+	var predicates []predicate.Xunji
+	if req.AppKey != nil {
+		predicates = append(predicates, xunji.AppKeyContains(*req.AppKey))
+	}
+	if req.AppSecret != nil {
+		predicates = append(predicates, xunji.AppSecretContains(*req.AppSecret))
+	}
+	if req.Token != nil {
+		predicates = append(predicates, xunji.TokenContains(*req.Token))
+	}
+	data, err := l.svcCtx.DB.Xunji.Query().Where(predicates...).Page(l.ctx, req.Page, req.PageSize)
+
+	if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+	resp := &types.XunjiListResp{}
+	resp.Msg = errormsg.Success
+	resp.Data.Total = data.PageDetails.Total
+
+	for _, v := range data.List {
+		resp.Data.Data = append(resp.Data.Data,
+		types.XunjiInfo{
+			BaseIDInfo:    types.BaseIDInfo{
+				Id:          &v.ID,
+				CreatedAt:    pointy.GetPointer(v.CreatedAt.UnixMilli()),
+				UpdatedAt:    pointy.GetPointer(v.UpdatedAt.UnixMilli()),
+            },
+			Status:	&v.Status,
+			AppKey:	&v.AppKey,
+			AppSecret:	&v.AppSecret,
+			Token:	&v.Token,
+			EncodingKey:	&v.EncodingKey,
+			AgentId:	&v.AgentID,
+			OrganizationId:	&v.OrganizationID,
+			Wxid:	&v.Wxid,
+			ApiBase:	&v.APIBase,
+			ApiKey:	&v.APIKey,
+		})
+	}
+
+	return resp, nil
+}

+ 46 - 0
internal/logic/xunji/update_xunji_logic.go

@@ -0,0 +1,46 @@
+package xunji
+
+import (
+	"context"
+
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+	"wechat-api/internal/utils/dberrorhandler"
+
+	"github.com/suyuan32/simple-admin-common/msg/errormsg"
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type UpdateXunjiLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewUpdateXunjiLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateXunjiLogic {
+	return &UpdateXunjiLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *UpdateXunjiLogic) UpdateXunji(req *types.XunjiInfo) (*types.BaseMsgResp, error) {
+	err := l.svcCtx.DB.Xunji.UpdateOneID(*req.Id).
+		SetNotNilStatus(req.Status).
+		SetNotNilAppKey(req.AppKey).
+		SetNotNilAppSecret(req.AppSecret).
+		SetNotNilToken(req.Token).
+		SetNotNilEncodingKey(req.EncodingKey).
+		SetNotNilAgentID(req.AgentId).
+		//SetNotNilOrganizationID(req.OrganizationId).
+		SetNotNilAPIBase(req.ApiBase).
+		SetNotNilAPIKey(req.ApiKey).
+		Exec(l.ctx)
+
+	if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+	return &types.BaseMsgResp{Msg: errormsg.UpdateSuccess}, nil
+}

+ 62 - 0
internal/types/types.go

@@ -4029,3 +4029,65 @@ type WpWecomMsgReq struct {
 	// 消息内容
 	Content *string `json:"content"`
 }
+
+// The data of xunji information | Xunji信息
+// swagger:model XunjiInfo
+type XunjiInfo struct {
+	BaseIDInfo
+	// Status 1: normal 2: ban | 状态 1 正常 2 禁用
+	Status *uint8 `json:"status,optional"`
+	// AppKey
+	AppKey *string `json:"appKey,optional"`
+	// AppSecret
+	AppSecret *string `json:"appSecret,optional"`
+	// Token
+	Token *string `json:"token,optional"`
+	// 加密key
+	EncodingKey *string `json:"encodingKey,optional"`
+	// 角色ID
+	AgentId *uint64 `json:"agentId,optional"`
+	// organization_id | 租户ID
+	OrganizationId *uint64 `json:"organizationId,optional"`
+	// 微信ID
+	Wxid *string `json:"wxid,optional"`
+	// 大模型服务地址
+	ApiBase *string `json:"apiBase,optional"`
+	// 大模型服务密钥
+	ApiKey *string `json:"apiKey,optional"`
+}
+
+// The response data of xunji list | Xunji列表数据
+// swagger:model XunjiListResp
+type XunjiListResp struct {
+	BaseDataInfo
+	// Xunji list data | Xunji列表数据
+	Data XunjiListInfo `json:"data"`
+}
+
+// Xunji list data | Xunji列表数据
+// swagger:model XunjiListInfo
+type XunjiListInfo struct {
+	BaseListInfo
+	// The API list data | Xunji列表数据
+	Data []XunjiInfo `json:"data"`
+}
+
+// Get xunji list request params | Xunji列表请求参数
+// swagger:model XunjiListReq
+type XunjiListReq struct {
+	PageInfo
+	// AppKey
+	AppKey *string `json:"appKey,optional"`
+	// AppSecret
+	AppSecret *string `json:"appSecret,optional"`
+	// Token
+	Token *string `json:"token,optional"`
+}
+
+// Xunji information response | Xunji信息返回体
+// swagger:model XunjiInfoResp
+type XunjiInfoResp struct {
+	BaseDataInfo
+	// Xunji information | Xunji数据
+	Data XunjiInfo `json:"data"`
+}

+ 85 - 0
internal/utils/charset.go

@@ -0,0 +1,85 @@
+package utils
+
+import (
+	"bytes"
+	"fmt"
+	"github.com/saintfish/chardet"
+	"golang.org/x/text/encoding"
+	"golang.org/x/text/encoding/charmap"
+	"golang.org/x/text/encoding/japanese"
+	"golang.org/x/text/encoding/korean"
+	"golang.org/x/text/encoding/simplifiedchinese"
+	"golang.org/x/text/encoding/traditionalchinese"
+	"golang.org/x/text/encoding/unicode"
+	"golang.org/x/text/transform"
+	"io"
+	"strings"
+)
+
+// TransCharset 自动检测编码并转换为 UTF-8
+func TransCharset(s string) string {
+	// 1. 自动检测编码
+	detector := chardet.NewTextDetector()
+	result, err := detector.DetectBest([]byte(s))
+	if err != nil {
+		fmt.Println("Encoding detection failed:", err)
+		return s
+	}
+
+	// 2. 找到相应的编码
+	fmt.Println("result.Charset:", result.Charset)
+	enc := getEncoding(result.Charset)
+	fmt.Println("enc:", enc)
+	if enc == nil {
+		// 直接返回原始字符串
+		fmt.Println("Unsupported charset:", result.Charset)
+		return s
+	}
+
+	// 3. 转换为 UTF-8
+	rd := transform.NewReader(bytes.NewReader([]byte(s)), enc.NewDecoder())
+	utf8Bytes, err := io.ReadAll(rd)
+	if err != nil {
+		fmt.Println("Encoding conversion failed:", err)
+		return s
+	}
+
+	// 4. 返回转换后的 UTF-8 字符串
+	return string(utf8Bytes)
+}
+
+// 根据字符集名称获取 `encoding.Encoding`
+func getEncoding(charset string) encoding.Encoding {
+	switch charset {
+	case "UTF-8", "ASCII":
+		return encoding.Nop // 无需转换
+	case "ISO-8859-1":
+		return charmap.ISO8859_1
+	case "ISO-8859-2":
+		return charmap.ISO8859_2
+	case "ISO-8859-15":
+		return charmap.ISO8859_15
+	case "Windows-1252":
+		return charmap.Windows1252
+	case "Big5":
+		return traditionalchinese.Big5
+	case "GB-2312", "GBK", "GB-18030":
+		return simplifiedchinese.GBK
+	case "Shift_JIS":
+		return japanese.ShiftJIS
+	case "EUC-JP":
+		return japanese.EUCJP
+	case "EUC-KR":
+		return korean.EUCKR
+	case "UTF-16LE":
+		return unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM)
+	case "UTF-16BE":
+		return unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM)
+	default:
+		return nil
+	}
+}
+
+func Trim(s string) string {
+	return strings.Trim(s, " \r\n\t")
+}