crm/internal/storage/mysql_followup_storage.go
2026-01-26 11:46:06 +08:00

250 lines
5.9 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package storage
import (
"crm-go/models"
"crypto/rand"
"database/sql"
"encoding/hex"
"fmt"
"strings"
"time"
)
type mysqlFollowUpStorage struct {
db *sql.DB
}
// NewMySQLFollowUpStorage 创建MySQL跟进存储
func NewMySQLFollowUpStorage() FollowUpStorage {
return &mysqlFollowUpStorage{
db: GetDB(),
}
}
func (fs *mysqlFollowUpStorage) GetAllFollowUps() ([]models.FollowUp, error) {
query := `
SELECT id, created_at, customer_name, deal_status, customer_level,
industry, follow_up_time, notification_sent
FROM followups
ORDER BY follow_up_time DESC
`
rows, err := fs.db.Query(query)
if err != nil {
return nil, err
}
defer rows.Close()
var followUps []models.FollowUp
for rows.Next() {
var f models.FollowUp
var dealStatus, customerLevel, industry sql.NullString
var notificationSent int
err := rows.Scan(
&f.ID, &f.CreatedAt, &f.CustomerName,
&dealStatus, &customerLevel, &industry,
&f.FollowUpTime, &notificationSent,
)
if err != nil {
return nil, err
}
f.DealStatus = dealStatus.String
f.CustomerLevel = customerLevel.String
f.Industry = industry.String
f.NotificationSent = notificationSent == 1
followUps = append(followUps, f)
}
return followUps, rows.Err()
}
func (fs *mysqlFollowUpStorage) GetFollowUpByID(id string) (*models.FollowUp, error) {
query := `
SELECT id, created_at, customer_name, deal_status, customer_level,
industry, follow_up_time, notification_sent
FROM followups
WHERE id = ?
`
var f models.FollowUp
var dealStatus, customerLevel, industry sql.NullString
var notificationSent int
err := fs.db.QueryRow(query, id).Scan(
&f.ID, &f.CreatedAt, &f.CustomerName,
&dealStatus, &customerLevel, &industry,
&f.FollowUpTime, &notificationSent,
)
if err == sql.ErrNoRows {
return nil, nil
}
if err != nil {
return nil, err
}
f.DealStatus = dealStatus.String
f.CustomerLevel = customerLevel.String
f.Industry = industry.String
f.NotificationSent = notificationSent == 1
return &f, nil
}
func (fs *mysqlFollowUpStorage) CreateFollowUp(followUp models.FollowUp) error {
if followUp.ID == "" {
followUp.ID = generateFollowUpMySQLUUID()
}
if followUp.CreatedAt.IsZero() {
followUp.CreatedAt = time.Now()
}
query := `
INSERT INTO followups (id, created_at, customer_name, deal_status, customer_level,
industry, follow_up_time, notification_sent)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`
notificationSent := 0
if followUp.NotificationSent {
notificationSent = 1
}
_, err := fs.db.Exec(query,
followUp.ID, followUp.CreatedAt, followUp.CustomerName,
followUp.DealStatus, followUp.CustomerLevel, followUp.Industry,
followUp.FollowUpTime, notificationSent,
)
return err
}
func (fs *mysqlFollowUpStorage) UpdateFollowUp(id string, updates models.UpdateFollowUpRequest) error {
// 首先获取现有记录
existing, err := fs.GetFollowUpByID(id)
if err != nil || existing == nil {
return err
}
// 应用更新
if updates.CustomerName != nil {
existing.CustomerName = *updates.CustomerName
}
if updates.DealStatus != nil {
existing.DealStatus = *updates.DealStatus
}
if updates.CustomerLevel != nil {
existing.CustomerLevel = *updates.CustomerLevel
}
if updates.Industry != nil {
existing.Industry = *updates.Industry
}
if updates.FollowUpTime != nil {
t, err := time.Parse(time.RFC3339, *updates.FollowUpTime)
if err == nil {
existing.FollowUpTime = t
}
}
if updates.NotificationSent != nil {
existing.NotificationSent = *updates.NotificationSent
}
query := `
UPDATE followups
SET customer_name = ?, deal_status = ?, customer_level = ?,
industry = ?, follow_up_time = ?, notification_sent = ?
WHERE id = ?
`
notificationSent := 0
if existing.NotificationSent {
notificationSent = 1
}
_, err = fs.db.Exec(query,
existing.CustomerName, existing.DealStatus, existing.CustomerLevel,
existing.Industry, existing.FollowUpTime, notificationSent,
id,
)
return err
}
func (fs *mysqlFollowUpStorage) DeleteFollowUp(id string) error {
query := `DELETE FROM followups WHERE id = ?`
_, err := fs.db.Exec(query, id)
if err != nil {
if strings.Contains(err.Error(), "command denied") {
return fmt.Errorf("数据库权限不足:无法执行删除操作,请联系管理员")
}
return err
}
return nil
}
func (fs *mysqlFollowUpStorage) SaveFollowUps(followUps []models.FollowUp) error {
// MySQL版本不需要使用此方法保留接口兼容
return nil
}
func (fs *mysqlFollowUpStorage) LoadFollowUps() ([]models.FollowUp, error) {
return fs.GetAllFollowUps()
}
func (fs *mysqlFollowUpStorage) GetPendingNotifications() ([]models.FollowUp, error) {
query := `
SELECT id, created_at, customer_name, deal_status, customer_level,
industry, follow_up_time, notification_sent
FROM followups
WHERE notification_sent = 0 AND follow_up_time < NOW()
`
rows, err := fs.db.Query(query)
if err != nil {
return nil, err
}
defer rows.Close()
var pending []models.FollowUp
for rows.Next() {
var f models.FollowUp
var dealStatus, customerLevel, industry sql.NullString
var notificationSent int
err := rows.Scan(
&f.ID, &f.CreatedAt, &f.CustomerName,
&dealStatus, &customerLevel, &industry,
&f.FollowUpTime, &notificationSent,
)
if err != nil {
return nil, err
}
f.DealStatus = dealStatus.String
f.CustomerLevel = customerLevel.String
f.Industry = industry.String
f.NotificationSent = notificationSent == 1
pending = append(pending, f)
}
return pending, rows.Err()
}
func (fs *mysqlFollowUpStorage) MarkNotificationSent(id string) error {
query := `UPDATE followups SET notification_sent = 1 WHERE id = ?`
_, err := fs.db.Exec(query, id)
return err
}
func generateFollowUpMySQLUUID() string {
bytes := make([]byte, 16)
rand.Read(bytes)
bytes[6] = (bytes[6] & 0x0f) | 0x40 // Version 4
bytes[8] = (bytes[8] & 0x3f) | 0x80 // Variant
return hex.EncodeToString(bytes)
}