175 lines
5.9 KiB
Go
175 lines
5.9 KiB
Go
package impl
|
||
|
||
import (
|
||
"ai_scheduler/internal/data/model"
|
||
"ai_scheduler/tmpl/dataTemp"
|
||
"ai_scheduler/utils"
|
||
"context"
|
||
"time"
|
||
)
|
||
|
||
// AdviceFollowImpl 统管两张表的数据访问:
|
||
// - ai_advice_remind_task(定时提醒)
|
||
// - ai_advice_deal_lead(成交线索)
|
||
// DataTemp 基础模型仅占位,所有方法显式 Model(&具体结构体{})。
|
||
type AdviceFollowImpl struct {
|
||
dataTemp.DataTemp
|
||
}
|
||
|
||
func NewAdviceFollowImpl(db *utils.Db) *AdviceFollowImpl {
|
||
return &AdviceFollowImpl{
|
||
DataTemp: *dataTemp.NewDataTemp(db, new(model.AiAdviceRemindTask)),
|
||
}
|
||
}
|
||
|
||
// ================= 定时提醒 ai_advice_remind_task =================
|
||
|
||
// RemindAdd 新增一条定时提醒。
|
||
func (a *AdviceFollowImpl) RemindAdd(ctx context.Context, record *model.AiAdviceRemindTask) (int64, error) {
|
||
if err := a.Db.WithContext(ctx).Create(record).Error; err != nil {
|
||
return 0, err
|
||
}
|
||
return record.Id, nil
|
||
}
|
||
|
||
// RemindExists 去重:同客户 + 到点时间 + 标题 是否已存在。
|
||
func (a *AdviceFollowImpl) RemindExists(ctx context.Context, clientId string, dueAt time.Time, title string) (bool, error) {
|
||
var count int64
|
||
err := a.Db.WithContext(ctx).Model(&model.AiAdviceRemindTask{}).
|
||
Where("client_id = ? AND due_at = ? AND title = ?", clientId, dueAt, title).
|
||
Count(&count).Error
|
||
return count > 0, err
|
||
}
|
||
|
||
// FindDueRemind 取到点且待执行的提醒(供 cron 每分钟执行)。
|
||
func (a *AdviceFollowImpl) FindDueRemind(ctx context.Context, now time.Time) ([]model.AiAdviceRemindTask, error) {
|
||
var list []model.AiAdviceRemindTask
|
||
err := a.Db.WithContext(ctx).
|
||
Where("status = ? AND due_at <= ?", model.FollowStatusPending, now).
|
||
Order("due_at asc").Limit(200).
|
||
Find(&list).Error
|
||
return list, err
|
||
}
|
||
|
||
// RemindList 定时提醒列表(按到点时间倒序,支持项目/客户/状态过滤 + 分页)。
|
||
func (a *AdviceFollowImpl) RemindList(ctx context.Context, projectId int32, clientId, wxid, status string, page, pageSize int) ([]model.AiAdviceRemindTask, error) {
|
||
query := a.Db.WithContext(ctx).Model(&model.AiAdviceRemindTask{})
|
||
if projectId != 0 {
|
||
query = query.Where("project_id = ?", projectId)
|
||
}
|
||
if clientId != "" {
|
||
query = query.Where("client_id = ?", clientId)
|
||
}
|
||
if wxid != "" {
|
||
query = query.Where("wxid = ?", wxid)
|
||
}
|
||
if status != "" {
|
||
query = query.Where("status = ?", status)
|
||
}
|
||
query = query.Order("due_at desc")
|
||
if pageSize > 0 {
|
||
if page < 1 {
|
||
page = 1
|
||
}
|
||
query = query.Offset((page - 1) * pageSize).Limit(pageSize)
|
||
} else {
|
||
query = query.Limit(200)
|
||
}
|
||
var list []model.AiAdviceRemindTask
|
||
err := query.Find(&list).Error
|
||
return list, err
|
||
}
|
||
|
||
// RemindUpdateStatusIfPending 仅当提醒仍为 pending 时更新状态(幂等),返回受影响行数。
|
||
func (a *AdviceFollowImpl) RemindUpdateStatusIfPending(ctx context.Context, id int64, status, result, errMsg string) (int64, error) {
|
||
now := time.Now()
|
||
set := map[string]interface{}{"status": status, "done_at": now, "update_at": now}
|
||
if result != "" {
|
||
set["result"] = result
|
||
}
|
||
if errMsg != "" {
|
||
set["err_msg"] = errMsg
|
||
}
|
||
res := a.Db.WithContext(ctx).Model(&model.AiAdviceRemindTask{}).
|
||
Where("id = ? AND status = ?", id, model.FollowStatusPending).
|
||
Updates(set)
|
||
return res.RowsAffected, res.Error
|
||
}
|
||
|
||
// ================= 成交线索 ai_advice_deal_lead =================
|
||
|
||
// LeadAdd 新增一条成交线索。
|
||
func (a *AdviceFollowImpl) LeadAdd(ctx context.Context, record *model.AiAdviceDealLead) (int64, error) {
|
||
if err := a.Db.WithContext(ctx).Create(record).Error; err != nil {
|
||
return 0, err
|
||
}
|
||
return record.Id, nil
|
||
}
|
||
|
||
// LeadExists 去重:同客户 + 线索类型 + 期望时间 + 标题 是否已存在。
|
||
func (a *AdviceFollowImpl) LeadExists(ctx context.Context, clientId, leadType string, expectAt time.Time, title string) (bool, error) {
|
||
var count int64
|
||
err := a.Db.WithContext(ctx).Model(&model.AiAdviceDealLead{}).
|
||
Where("client_id = ? AND lead_type = ? AND expect_at = ? AND title = ?", clientId, leadType, expectAt, title).
|
||
Count(&count).Error
|
||
return count > 0, err
|
||
}
|
||
|
||
// FindActiveLeadsByWxid 取某客户尚未闭环的成交线索(pending),供对话注入。
|
||
func (a *AdviceFollowImpl) FindActiveLeadsByWxid(ctx context.Context, wxid string) ([]model.AiAdviceDealLead, error) {
|
||
var list []model.AiAdviceDealLead
|
||
if wxid == "" {
|
||
return list, nil
|
||
}
|
||
err := a.Db.WithContext(ctx).
|
||
Where("wxid = ? AND status = ?", wxid, model.FollowStatusPending).
|
||
Order("expect_at asc").Limit(20).
|
||
Find(&list).Error
|
||
return list, err
|
||
}
|
||
|
||
// LeadList 成交线索列表(按期望时间倒序,支持项目/客户/状态/线索类型过滤 + 分页)。
|
||
func (a *AdviceFollowImpl) LeadList(ctx context.Context, projectId int32, clientId, wxid, status, leadType string, page, pageSize int) ([]model.AiAdviceDealLead, error) {
|
||
query := a.Db.WithContext(ctx).Model(&model.AiAdviceDealLead{})
|
||
if projectId != 0 {
|
||
query = query.Where("project_id = ?", projectId)
|
||
}
|
||
if clientId != "" {
|
||
query = query.Where("client_id = ?", clientId)
|
||
}
|
||
if wxid != "" {
|
||
query = query.Where("wxid = ?", wxid)
|
||
}
|
||
if status != "" {
|
||
query = query.Where("status = ?", status)
|
||
}
|
||
if leadType != "" {
|
||
query = query.Where("lead_type = ?", leadType)
|
||
}
|
||
query = query.Order("expect_at desc")
|
||
if pageSize > 0 {
|
||
if page < 1 {
|
||
page = 1
|
||
}
|
||
query = query.Offset((page - 1) * pageSize).Limit(pageSize)
|
||
} else {
|
||
query = query.Limit(200)
|
||
}
|
||
var list []model.AiAdviceDealLead
|
||
err := query.Find(&list).Error
|
||
return list, err
|
||
}
|
||
|
||
// LeadUpdateStatusIfPending 仅当线索仍为 pending 时更新状态/跟进结果(幂等),返回受影响行数。
|
||
func (a *AdviceFollowImpl) LeadUpdateStatusIfPending(ctx context.Context, id int64, status, result string) (int64, error) {
|
||
now := time.Now()
|
||
set := map[string]interface{}{"status": status, "done_at": now, "update_at": now}
|
||
if result != "" {
|
||
set["result"] = result
|
||
}
|
||
res := a.Db.WithContext(ctx).Model(&model.AiAdviceDealLead{}).
|
||
Where("id = ? AND status = ?", id, model.FollowStatusPending).
|
||
Updates(set)
|
||
return res.RowsAffected, res.Error
|
||
}
|