Fix: 浏览器不再负责历史记录
This commit is contained in:
57
main.go
57
main.go
@@ -26,6 +26,7 @@ type Task struct {
|
|||||||
LastCheck time.Time `json:"last_check"`
|
LastCheck time.Time `json:"last_check"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Notified bool `json:"notified"`
|
Notified bool `json:"notified"`
|
||||||
|
History []HistoryItem `json:"history"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@@ -36,6 +37,11 @@ type Config struct {
|
|||||||
NotifyEnabled bool `json:"notify_enabled"`
|
NotifyEnabled bool `json:"notify_enabled"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type HistoryItem struct {
|
||||||
|
State string `json:"state"`
|
||||||
|
Time time.Time `json:"time"`
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
tasks = make(map[string]*Task)
|
tasks = make(map[string]*Task)
|
||||||
config = &Config{Interval: 60, Timeout: 20, NotifyEnabled: true}
|
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('请输入访问令牌:');
|
const token = localStorage.getItem('token') || prompt('请输入访问令牌:');
|
||||||
if(token) localStorage.setItem('token', token);
|
if(token) localStorage.setItem('token', token);
|
||||||
const headers = {'Authorization': 'Bearer ' + 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() {
|
function loadTasks() {
|
||||||
fetch('/api/tasks', {headers})
|
fetch('/api/tasks', {headers})
|
||||||
.then(r => r.json())
|
.then(r => r.json())
|
||||||
.then(tasks => {
|
.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');
|
const tbody = document.querySelector('#taskTable tbody');
|
||||||
tbody.innerHTML = tasks.map(t => {
|
tbody.innerHTML = tasks.map(t => {
|
||||||
const statusClass = t.status || 'checking';
|
const statusClass = t.status || 'checking';
|
||||||
const stockText = t.in_stock ? '<span class="stock-yes">有货</span>' : '<span class="stock-no">无货</span>';
|
const stockText = t.in_stock ? '<span class="stock-yes">有货</span>' : '<span class="stock-no">无货</span>';
|
||||||
const lastCheck = t.last_check ? new Date(t.last_check).toLocaleString('zh-CN') : '-';
|
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 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' ? '错误' : '未知';
|
const label = h.state === 'stock' ? '有货' : h.state === 'no-stock' ? '无货' : h.state === 'error' ? '错误' : '未知';
|
||||||
return '<div class="uptime-item ' + h.state + '"><span class="uptime-tooltip">' + time + '<br>' + label + '</span></div>';
|
return '<div class="uptime-item ' + h.state + '"><span class="uptime-tooltip">' + time + '<br>' + label + '</span></div>';
|
||||||
}).join('');
|
}).join('');
|
||||||
|
|
||||||
return '<tr>' +
|
return '<tr>' +
|
||||||
'<td class="status-cell"><span class="status ' + statusClass + '"></span></td>' +
|
'<td class="status-cell"><span class="status ' + statusClass + '"></span></td>' +
|
||||||
'<td>' + t.name + '</td>' +
|
'<td>' + t.name + '</td>' +
|
||||||
@@ -359,7 +343,6 @@ func handleIndex(w http.ResponseWriter, r *http.Request) {
|
|||||||
if(!confirm('确认删除?')) return;
|
if(!confirm('确认删除?')) return;
|
||||||
fetch('/api/task?id=' + id, {method: 'DELETE', headers})
|
fetch('/api/task?id=' + id, {method: 'DELETE', headers})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
delete historyData[id];
|
|
||||||
loadTasks();
|
loadTasks();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -490,8 +473,6 @@ func checker(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkTask(task *Task) {
|
func checkTask(task *Task) {
|
||||||
task.Status = "checking"
|
|
||||||
|
|
||||||
body, err := fetch(task.URL)
|
body, err := fetch(task.URL)
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|
||||||
@@ -504,6 +485,16 @@ func checkTask(task *Task) {
|
|||||||
inStock = !strings.Contains(body, task.OutOfStock)
|
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()
|
mu.Lock()
|
||||||
wasInStock := task.InStock
|
wasInStock := task.InStock
|
||||||
wasNotified := task.Notified
|
wasNotified := task.Notified
|
||||||
@@ -511,11 +502,19 @@ func checkTask(task *Task) {
|
|||||||
task.InStock = inStock
|
task.InStock = inStock
|
||||||
task.LastCheck = now
|
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 {
|
if !inStock {
|
||||||
task.Notified = false
|
task.Notified = false
|
||||||
}
|
}
|
||||||
mu.Unlock()
|
mu.Unlock()
|
||||||
saveTasks()
|
saveTasks()
|
||||||
|
|
||||||
configMu.RLock()
|
configMu.RLock()
|
||||||
notifyEnabled := config.NotifyEnabled
|
notifyEnabled := config.NotifyEnabled
|
||||||
|
|||||||
Reference in New Issue
Block a user