124 lines
3.4 KiB
Go
124 lines
3.4 KiB
Go
package usecase
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"strings"
|
||
|
||
"apps/backend/internal/module/appnotif/domain"
|
||
|
||
"github.com/google/uuid"
|
||
)
|
||
|
||
type Service struct {
|
||
Repo domain.Repository
|
||
}
|
||
|
||
func New(repo domain.Repository) *Service {
|
||
return &Service{Repo: repo}
|
||
}
|
||
|
||
func (s *Service) List(ctx context.Context, ownerUID int64) ([]*domain.Notification, error) {
|
||
return s.Repo.ListByOwner(ctx, ownerUID)
|
||
}
|
||
|
||
func (s *Service) UnreadCount(ctx context.Context, ownerUID int64) (int64, error) {
|
||
return s.Repo.UnreadCount(ctx, ownerUID)
|
||
}
|
||
|
||
func (s *Service) MarkRead(ctx context.Context, ownerUID int64, id string) error {
|
||
return s.Repo.MarkRead(ctx, ownerUID, id)
|
||
}
|
||
|
||
func (s *Service) MarkAllRead(ctx context.Context, ownerUID int64) error {
|
||
return s.Repo.MarkAllRead(ctx, ownerUID)
|
||
}
|
||
|
||
// NotifyJobTerminal — 相容舊介面;改走 NotifyJobState(upsert 同一 job 一則)
|
||
func (s *Service) NotifyJobTerminal(ctx context.Context, ownerUID int64, jobID, status, summary string) error {
|
||
return s.NotifyJobState(ctx, ownerUID, jobID, "", status, summary, 100)
|
||
}
|
||
|
||
// NotifyJobState — 同一 job 只保留一則通知,進度更新時改寫 title/body(鈴鐺即時有進度)
|
||
func (s *Service) NotifyJobState(ctx context.Context, ownerUID int64, jobID, templateType, status, summary string, percent int) error {
|
||
if ownerUID <= 0 || jobID == "" {
|
||
return nil
|
||
}
|
||
title := jobNotifyTitle(templateType, status, percent)
|
||
body := strings.TrimSpace(summary)
|
||
if body == "" {
|
||
body = fmt.Sprintf("%s · %s", title, jobID)
|
||
}
|
||
// 進度摘要裡若已含 % 就不再重複;否則附上 percent
|
||
if percent > 0 && percent < 100 && !strings.Contains(body, "%") {
|
||
body = fmt.Sprintf("%s · %d%%", body, percent)
|
||
}
|
||
|
||
existing, err := s.Repo.FindLatestByJobRef(ctx, ownerUID, jobID)
|
||
now := domain.NowNano()
|
||
if err == nil && existing != nil {
|
||
existing.Title = title
|
||
existing.Body = body
|
||
existing.Kind = domain.KindJob
|
||
existing.RefType = domain.RefJob
|
||
existing.RefID = jobID
|
||
// 每次有進度/終態都標未讀,鈴鐺才會跳
|
||
existing.ReadAt = 0
|
||
// 用 created_at 排序時把最新活動頂到前面
|
||
existing.CreatedAt = now
|
||
return s.Repo.Replace(ctx, existing)
|
||
}
|
||
|
||
n := &domain.Notification{
|
||
ID: uuid.NewString(), OwnerUID: ownerUID,
|
||
Title: title, Body: body, Kind: domain.KindJob,
|
||
RefType: domain.RefJob, RefID: jobID,
|
||
CreatedAt: now,
|
||
}
|
||
return s.Repo.Insert(ctx, n)
|
||
}
|
||
|
||
func jobNotifyTitle(templateType, status string, percent int) string {
|
||
name := templateLabelZH(templateType)
|
||
switch status {
|
||
case "succeeded":
|
||
return name + " · 已完成"
|
||
case "failed":
|
||
return name + " · 失敗"
|
||
case "cancelled":
|
||
return name + " · 已取消"
|
||
case "running":
|
||
if percent > 0 {
|
||
return fmt.Sprintf("%s · 進行中 %d%%", name, percent)
|
||
}
|
||
return name + " · 進行中"
|
||
case "queued", "pending":
|
||
return name + " · 已排程"
|
||
default:
|
||
if percent > 0 {
|
||
return fmt.Sprintf("%s · %d%%", name, percent)
|
||
}
|
||
return name + " · 更新"
|
||
}
|
||
}
|
||
|
||
func templateLabelZH(templateType string) string {
|
||
switch templateType {
|
||
case "persona_analyze_account":
|
||
return "人設分析(爬公開貼文)"
|
||
case "persona_analyze_text":
|
||
return "人設分析(文字)"
|
||
case "compose_mimic":
|
||
return "仿寫貼文"
|
||
case "threads_token_renew":
|
||
return "Threads Token 延長"
|
||
case "demo":
|
||
return "Demo 測試任務"
|
||
default:
|
||
if strings.TrimSpace(templateType) == "" {
|
||
return "背景任務"
|
||
}
|
||
return "背景任務"
|
||
}
|
||
}
|