From ff8047c8b3b487291b3731aaccadcadef2456749 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=96=8C?= <259278618@qq.com> Date: Fri, 31 Jul 2026 13:23:17 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E4=BB=98=E8=AE=A2=E5=8D=95/?= =?UTF-8?q?=E4=BC=9A=E5=91=98/=E5=9B=9E=E8=B0=83=E6=97=A5=E5=BF=97=20DAO?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- styleagent/dao/pay_notify_log_dao.go | 38 +++++++++++++++ styleagent/dao/payment_order_dao.go | 72 ++++++++++++++++++++++++++++ styleagent/dao/user_member_dao.go | 53 ++++++++++++++++++++ 3 files changed, 163 insertions(+) create mode 100644 styleagent/dao/pay_notify_log_dao.go create mode 100644 styleagent/dao/payment_order_dao.go create mode 100644 styleagent/dao/user_member_dao.go diff --git a/styleagent/dao/pay_notify_log_dao.go b/styleagent/dao/pay_notify_log_dao.go new file mode 100644 index 0000000..f70b115 --- /dev/null +++ b/styleagent/dao/pay_notify_log_dao.go @@ -0,0 +1,38 @@ +package dao + +import ( + "context" + + "slogan-agent/styleagent/consts" + "slogan-agent/styleagent/model/entity" + + "github.com/gogf/gf/v2/frame/g" +) + +var PayNotifyLog = &payNotifyLogDao{} + +type payNotifyLogDao struct{} + +func init() { + ctx := context.Background() + _, err := g.DB().Exec(ctx, `CREATE TABLE IF NOT EXISTS `+consts.TableNamePayNotifyLog+` ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + order_no TEXT NOT NULL DEFAULT '', + body TEXT NOT NULL DEFAULT '', + sign TEXT NOT NULL DEFAULT '', + remote_ip TEXT NOT NULL DEFAULT '', + status TEXT NOT NULL DEFAULT 'ok', + created_at DATETIME DEFAULT (datetime('now','localtime')) + )`) + if err != nil { + g.Log().Warningf(ctx, "create pay_notify_log table failed: %v", err) + } +} + +func (d *payNotifyLogDao) Insert(ctx context.Context, log *entity.PayNotifyLog) error { + _, err := g.DB().Model(consts.TableNamePayNotifyLog).Ctx(ctx).Data(g.Map{ + "order_no": log.OrderNo, "body": log.Body, "sign": log.Sign, + "remote_ip": log.RemoteIp, "status": log.Status, + }).Insert() + return err +} diff --git a/styleagent/dao/payment_order_dao.go b/styleagent/dao/payment_order_dao.go new file mode 100644 index 0000000..0c06fc8 --- /dev/null +++ b/styleagent/dao/payment_order_dao.go @@ -0,0 +1,72 @@ +package dao + +import ( + "context" + + "slogan-agent/styleagent/consts" + "slogan-agent/styleagent/model/entity" + + "github.com/gogf/gf/v2/frame/g" +) + +var PaymentOrder = &paymentOrderDao{} + +type paymentOrderDao struct{} + +func init() { + ctx := context.Background() + _, err := g.DB().Exec(ctx, `CREATE TABLE IF NOT EXISTS `+consts.TableNamePaymentOrder+` ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + order_no TEXT NOT NULL UNIQUE, + user_id INTEGER NOT NULL DEFAULT 0, + plan_id INTEGER NOT NULL DEFAULT 0, + amount_fen INTEGER NOT NULL DEFAULT 0, + channel TEXT NOT NULL DEFAULT '', + status TEXT NOT NULL DEFAULT 'pending', + trade_no TEXT NOT NULL DEFAULT '', + notify_raw TEXT NOT NULL DEFAULT '', + paid_at DATETIME, + created_at DATETIME DEFAULT (datetime('now','localtime')) + )`) + if err != nil { + g.Log().Warningf(ctx, "create payment_order table failed: %v", err) + } + _, _ = g.DB().Exec(ctx, `CREATE INDEX IF NOT EXISTS idx_payment_order_user ON `+consts.TableNamePaymentOrder+`(user_id, created_at)`) +} + +func (d *paymentOrderDao) Insert(ctx context.Context, order *entity.PaymentOrder) (int64, error) { + r, err := g.DB().Model(consts.TableNamePaymentOrder).Ctx(ctx).Data(g.Map{ + "order_no": order.OrderNo, "user_id": order.UserId, "plan_id": order.PlanId, + "amount_fen": order.AmountFen, "channel": order.Channel, "status": order.Status, + }).Insert() + if err != nil { + return 0, err + } + return r.LastInsertId() +} + +func (d *paymentOrderDao) GetByOrderNo(ctx context.Context, orderNo string) (*entity.PaymentOrder, error) { + var o *entity.PaymentOrder + err := g.DB().Model(consts.TableNamePaymentOrder).Ctx(ctx). + Where("order_no", orderNo).Scan(&o) + return o, err +} + +// MarkPaid 状态机 pending→paid(只更新 pending 行,返回是否成功,回调并发安全) +func (d *paymentOrderDao) MarkPaid(ctx context.Context, orderNo, tradeNo, notifyRaw string) (bool, error) { + r, err := g.DB().Exec(ctx, + "UPDATE "+consts.TableNamePaymentOrder+" SET status=?, trade_no=?, notify_raw=?, paid_at=datetime('now','localtime') WHERE order_no=? AND status=?", + consts.PayStatusPaid, tradeNo, notifyRaw, orderNo, consts.PayStatusPending) + if err != nil { + return false, err + } + n, _ := r.RowsAffected() + return n > 0, nil +} + +func (d *paymentOrderDao) GetByUser(ctx context.Context, userId int64) ([]*entity.PaymentOrder, error) { + var list []*entity.PaymentOrder + err := g.DB().Model(consts.TableNamePaymentOrder).Ctx(ctx). + Where("user_id", userId).OrderDesc("id").Limit(20).Scan(&list) + return list, err +} diff --git a/styleagent/dao/user_member_dao.go b/styleagent/dao/user_member_dao.go new file mode 100644 index 0000000..aa42150 --- /dev/null +++ b/styleagent/dao/user_member_dao.go @@ -0,0 +1,53 @@ +package dao + +import ( + "context" + + "slogan-agent/styleagent/consts" + "slogan-agent/styleagent/model/entity" + + "github.com/gogf/gf/v2/frame/g" +) + +var UserMember = &userMemberDao{} + +type userMemberDao struct{} + +func init() { + ctx := context.Background() + _, err := g.DB().Exec(ctx, `CREATE TABLE IF NOT EXISTS `+consts.TableNameUserMember+` ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL UNIQUE, + plan_id INTEGER NOT NULL DEFAULT 0, + expire_at DATETIME, + source TEXT NOT NULL DEFAULT 'vip_pay', + created_at DATETIME DEFAULT (datetime('now','localtime')), + updated_at DATETIME + )`) + if err != nil { + g.Log().Warningf(ctx, "create user_member table failed: %v", err) + } +} + +func (d *userMemberDao) GetByUser(ctx context.Context, userId int64) (*entity.UserMember, error) { + var m *entity.UserMember + err := g.DB().Model(consts.TableNameUserMember).Ctx(ctx). + Where("user_id", userId).Scan(&m) + return m, err +} + +// Upsert 无则插入有则整体覆盖(expire_at 由 Service 算好传入) +func (d *userMemberDao) Upsert(ctx context.Context, userId, planId int64, expireAt, source string) error { + _, err := g.DB().Exec(ctx, + "INSERT INTO "+consts.TableNameUserMember+" (user_id, plan_id, expire_at, source, created_at, updated_at) VALUES (?, ?, ?, ?, datetime('now','localtime'), datetime('now','localtime')) "+ + "ON CONFLICT(user_id) DO UPDATE SET plan_id=excluded.plan_id, expire_at=excluded.expire_at, source=excluded.source, updated_at=datetime('now','localtime')", + userId, planId, expireAt, source) + return err +} + +// IsVip 当前是否会员(未过期) +func (d *userMemberDao) IsVip(ctx context.Context, userId int64) bool { + n, err := g.DB().Model(consts.TableNameUserMember).Ctx(ctx). + Where("user_id", userId).Where("expire_at > datetime('now','localtime')").Count() + return err == nil && n > 0 +}