From 7dc556e4d0ab95ea445ef6d706ab79895f18ee1b Mon Sep 17 00:00:00 2001 From: XOF Date: Sat, 29 Nov 2025 14:52:52 +0800 Subject: [PATCH] =?UTF-8?q?Fix:=20=E6=B5=8F=E8=A7=88=E5=99=A8=E4=B8=8D?= =?UTF-8?q?=E5=86=8D=E8=B4=9F=E8=B4=A3=E5=8E=86=E5=8F=B2=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.go | 57 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/main.go b/main.go index 602ce8c..0b7da5f 100644 --- a/main.go +++ b/main.go @@ -26,6 +26,7 @@ type Task struct { LastCheck time.Time `json:"last_check"` Status string `json:"status"` Notified bool `json:"notified"` + History []HistoryItem `json:"history"` } type Config struct { @@ -36,6 +37,11 @@ type Config struct { NotifyEnabled bool `json:"notify_enabled"` } +type HistoryItem struct { + State string `json:"state"` + Time time.Time `json:"time"` +} + var ( tasks = make(map[string]*Task) config = &Config{Interval: 60, Timeout: 20, NotifyEnabled: true} @@ -248,46 +254,24 @@ func handleIndex(w http.ResponseWriter, r *http.Request) { const token = localStorage.getItem('token') || prompt('请输入访问令牌:'); if(token) localStorage.setItem('token', token); const headers = {'Authorization': 'Bearer ' + token}; - let historyData = {}; - const MAX_BARS = 90; - function initHistory(id) { - if(!historyData[id]) { - historyData[id] = Array(MAX_BARS).fill({state: 'unknown', time: null}); - } - } - - function updateHistory(id, state, time) { - initHistory(id); - historyData[id].shift(); - historyData[id].push({state, time}); - } function loadTasks() { fetch('/api/tasks', {headers}) .then(r => r.json()) .then(tasks => { - tasks.forEach(t => { - initHistory(t.id); - const state = t.status === 'ok' ? (t.in_stock ? 'stock' : 'no-stock') : (t.status === 'error' ? 'error' : 'unknown'); - const lastState = historyData[t.id][MAX_BARS - 1]; - if(!lastState.time || lastState.time !== t.last_check) { - updateHistory(t.id, state, t.last_check || Date.now()); - } - }); - const tbody = document.querySelector('#taskTable tbody'); tbody.innerHTML = tasks.map(t => { const statusClass = t.status || 'checking'; const stockText = t.in_stock ? '有货' : '无货'; const lastCheck = t.last_check ? new Date(t.last_check).toLocaleString('zh-CN') : '-'; - const history = historyData[t.id] || []; + + const history = t.history || []; const uptimeBar = history.map(h => { - const time = h.time ? new Date(h.time).toLocaleString('zh-CN') : '等待检测'; + const time = new Date(h.time).toLocaleString('zh-CN'); const label = h.state === 'stock' ? '有货' : h.state === 'no-stock' ? '无货' : h.state === 'error' ? '错误' : '未知'; return '
' + time + '
' + label + '
'; }).join(''); - return '' + '' + '' + t.name + '' + @@ -359,7 +343,6 @@ func handleIndex(w http.ResponseWriter, r *http.Request) { if(!confirm('确认删除?')) return; fetch('/api/task?id=' + id, {method: 'DELETE', headers}) .then(() => { - delete historyData[id]; loadTasks(); }); } @@ -490,8 +473,6 @@ func checker(ctx context.Context) { } func checkTask(task *Task) { - task.Status = "checking" - body, err := fetch(task.URL) now := time.Now() @@ -504,6 +485,16 @@ func checkTask(task *Task) { inStock = !strings.Contains(body, task.OutOfStock) } + state := "unknown" + if status == "ok" { + state = "no-stock" + if inStock { + state = "stock" + } + } else if status == "error" { + state = "error" + } + mu.Lock() wasInStock := task.InStock wasNotified := task.Notified @@ -511,11 +502,19 @@ func checkTask(task *Task) { task.InStock = inStock task.LastCheck = now + if task.History == nil { + task.History = []HistoryItem{} + } + task.History = append(task.History, HistoryItem{State: state, Time: now}) + if len(task.History) > 90 { + task.History = task.History[len(task.History)-90:] + } + if !inStock { task.Notified = false } mu.Unlock() - saveTasks() + saveTasks() configMu.RLock() notifyEnabled := config.NotifyEnabled