feat: 第五轮开发 - 14项未来路线图功能完整实现
W1-W14 全部完成: - W1: 消息搜索 (ILIKE全文检索 + SearchModal) - W2: 对话导出 (JSON/Markdown/TXT三格式) - W3: 记忆时间线 DevTools 可视化 - W4: 通知推送系统 (WebSocket + Browser Notification API) - W5: 定时提醒 (30s轮询 + 重复提醒 + WebSocket推送) - W6: 每日简报 (08:00自动生成: 天气+新闻+提醒+AI摘要) - W7: IoT场景自动化 (规则引擎 10s轮询 + 条件评估 + 场景执行) - W8: 语音输入 (浏览器 Speech Recognition API) - W9: STT服务 (voice-service + whisper.cpp) - W10: TTS服务 (浏览器 Speech Synthesis + edge-tts三档回退) - W11: 文件管理 (上传/下载/缩略图/纯Go bilinear缩放) - W12: 知识库RAG (PostgreSQL tsvector + 文档分块 + 检索) - W13: 多模态 (图片上传+分析: Vision API + 本地Go分析回退) - W14: PWA (Service Worker + 离线页 + install prompt) 总计: 6个Go微服务 + 10+前端组件 + 10+ PostgreSQL表 + 4个后台调度器
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Reminder 提醒模型
|
||||
type Reminder struct {
|
||||
ID string `json:"id"`
|
||||
UserID string `json:"user_id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
RemindAt time.Time `json:"remind_at"`
|
||||
Status string `json:"status"` // pending, completed, cancelled
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
CompletedAt *time.Time `json:"completed_at,omitempty"`
|
||||
RepeatType string `json:"repeat_type"` // none, daily, weekly, monthly
|
||||
SessionID string `json:"session_id"`
|
||||
Notified bool `json:"notified"`
|
||||
}
|
||||
|
||||
// ReminderStore 提醒持久化存储
|
||||
type ReminderStore struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
// NewReminderStore 使用已有数据库连接初始化提醒存储并自动建表
|
||||
func NewReminderStore(db *sql.DB) (*ReminderStore, error) {
|
||||
store := &ReminderStore{db: db}
|
||||
|
||||
if err := store.migrate(); err != nil {
|
||||
return nil, fmt.Errorf("提醒表迁移失败: %w", err)
|
||||
}
|
||||
|
||||
log.Println("[ReminderStore] 提醒持久化存储已初始化")
|
||||
return store, nil
|
||||
}
|
||||
|
||||
// migrate 自动创建提醒表结构
|
||||
func (s *ReminderStore) migrate() error {
|
||||
queries := []string{
|
||||
`CREATE TABLE IF NOT EXISTS reminders (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
user_id VARCHAR(255) NOT NULL,
|
||||
title VARCHAR(500) NOT NULL,
|
||||
description TEXT DEFAULT '',
|
||||
remind_at TIMESTAMPTZ NOT NULL,
|
||||
status VARCHAR(20) DEFAULT 'pending',
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
completed_at TIMESTAMPTZ,
|
||||
repeat_type VARCHAR(20) DEFAULT '',
|
||||
session_id VARCHAR(36) DEFAULT '',
|
||||
notified BOOLEAN DEFAULT FALSE
|
||||
)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_reminders_user_id ON reminders(user_id)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_reminders_remind_at ON reminders(remind_at)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_reminders_status ON reminders(status)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_reminders_due ON reminders(remind_at, status, notified)`,
|
||||
}
|
||||
|
||||
for _, q := range queries {
|
||||
if _, err := s.db.Exec(q); err != nil {
|
||||
return fmt.Errorf("迁移SQL执行失败: %w\nSQL: %s", err, q)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateReminder 创建新提醒
|
||||
func (s *ReminderStore) CreateReminder(r *Reminder) error {
|
||||
_, err := s.db.Exec(
|
||||
`INSERT INTO reminders (id, user_id, title, description, remind_at, status, repeat_type, session_id)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,
|
||||
r.ID, r.UserID, r.Title, r.Description, r.RemindAt, r.Status, r.RepeatType, r.SessionID,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("创建提醒失败: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetRemindersByUser 获取用户的提醒列表(可按状态筛选,按 remind_at 升序)
|
||||
func (s *ReminderStore) GetRemindersByUser(userID, status string, limit, offset int) ([]Reminder, error) {
|
||||
if limit <= 0 {
|
||||
limit = 50
|
||||
}
|
||||
if offset < 0 {
|
||||
offset = 0
|
||||
}
|
||||
|
||||
var rows *sql.Rows
|
||||
var err error
|
||||
|
||||
if status != "" {
|
||||
rows, err = s.db.Query(
|
||||
`SELECT id, user_id, title, description, remind_at, status, created_at, completed_at, repeat_type, session_id, notified
|
||||
FROM reminders WHERE user_id = $1 AND status = $2
|
||||
ORDER BY remind_at ASC LIMIT $3 OFFSET $4`,
|
||||
userID, status, limit, offset,
|
||||
)
|
||||
} else {
|
||||
rows, err = s.db.Query(
|
||||
`SELECT id, user_id, title, description, remind_at, status, created_at, completed_at, repeat_type, session_id, notified
|
||||
FROM reminders WHERE user_id = $1
|
||||
ORDER BY remind_at ASC LIMIT $2 OFFSET $3`,
|
||||
userID, limit, offset,
|
||||
)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询提醒列表失败: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var reminders []Reminder
|
||||
for rows.Next() {
|
||||
var r Reminder
|
||||
if err := rows.Scan(&r.ID, &r.UserID, &r.Title, &r.Description, &r.RemindAt,
|
||||
&r.Status, &r.CreatedAt, &r.CompletedAt, &r.RepeatType, &r.SessionID, &r.Notified); err != nil {
|
||||
return nil, fmt.Errorf("扫描提醒行失败: %w", err)
|
||||
}
|
||||
reminders = append(reminders, r)
|
||||
}
|
||||
|
||||
if reminders == nil {
|
||||
reminders = []Reminder{}
|
||||
}
|
||||
return reminders, rows.Err()
|
||||
}
|
||||
|
||||
// GetDueReminders 获取所有到期且未通知的提醒
|
||||
func (s *ReminderStore) GetDueReminders() ([]Reminder, error) {
|
||||
rows, err := s.db.Query(
|
||||
`SELECT id, user_id, title, description, remind_at, status, created_at, completed_at, repeat_type, session_id, notified
|
||||
FROM reminders
|
||||
WHERE remind_at <= NOW() AND status = 'pending' AND notified = FALSE
|
||||
ORDER BY remind_at ASC`,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询到期提醒失败: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var reminders []Reminder
|
||||
for rows.Next() {
|
||||
var r Reminder
|
||||
if err := rows.Scan(&r.ID, &r.UserID, &r.Title, &r.Description, &r.RemindAt,
|
||||
&r.Status, &r.CreatedAt, &r.CompletedAt, &r.RepeatType, &r.SessionID, &r.Notified); err != nil {
|
||||
return nil, fmt.Errorf("扫描到期提醒行失败: %w", err)
|
||||
}
|
||||
reminders = append(reminders, r)
|
||||
}
|
||||
|
||||
if reminders == nil {
|
||||
reminders = []Reminder{}
|
||||
}
|
||||
return reminders, rows.Err()
|
||||
}
|
||||
|
||||
// MarkNotified 标记提醒为已通知
|
||||
func (s *ReminderStore) MarkNotified(id string) error {
|
||||
_, err := s.db.Exec(
|
||||
`UPDATE reminders SET notified = TRUE WHERE id = $1`,
|
||||
id,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("标记提醒已通知失败: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateReminder 更新提醒字段
|
||||
func (s *ReminderStore) UpdateReminder(id string, r *Reminder) error {
|
||||
_, err := s.db.Exec(
|
||||
`UPDATE reminders SET title = $1, description = $2, remind_at = $3, status = $4,
|
||||
completed_at = $5, repeat_type = $6, session_id = $7, notified = $8
|
||||
WHERE id = $9`,
|
||||
r.Title, r.Description, r.RemindAt, r.Status, r.CompletedAt, r.RepeatType, r.SessionID, r.Notified, id,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("更新提醒失败: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteReminder 删除提醒
|
||||
func (s *ReminderStore) DeleteReminder(id string) error {
|
||||
_, err := s.db.Exec(`DELETE FROM reminders WHERE id = $1`, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("删除提醒失败: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user