201 lines
4.9 KiB
JavaScript
201 lines
4.9 KiB
JavaScript
const { createApp } = Vue;
|
|
|
|
const app = createApp({
|
|
data() {
|
|
return {
|
|
loading: false,
|
|
activeTab: 'trades',
|
|
serverTime: '',
|
|
currentTrade: null,
|
|
tradeHistory: {
|
|
data: [],
|
|
page: 1,
|
|
limit: 10,
|
|
total: 0,
|
|
total_pages: 0,
|
|
},
|
|
tradeFilter: {
|
|
month: '',
|
|
day: '',
|
|
},
|
|
accuracyFilter: {
|
|
month: '',
|
|
},
|
|
monthlyStats: {},
|
|
dailyStats: {
|
|
data: [],
|
|
page: 1,
|
|
limit: 10,
|
|
total: 0,
|
|
total_pages: 0,
|
|
},
|
|
hourlyModal: {
|
|
date: '',
|
|
data: [],
|
|
},
|
|
};
|
|
},
|
|
|
|
mounted() {
|
|
this.accuracyFilter.month = this.getCurrentMonth();
|
|
this.loadCurrentTrade();
|
|
this.loadTradeHistory(1);
|
|
this.updateServerTime();
|
|
setInterval(() => this.updateServerTime(), 60000);
|
|
},
|
|
|
|
methods: {
|
|
getCurrentMonth() {
|
|
const now = new Date();
|
|
return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
|
|
},
|
|
|
|
updateServerTime() {
|
|
const now = new Date();
|
|
this.serverTime = now.toLocaleString('zh-CN', {
|
|
year: 'numeric',
|
|
month: '2-digit',
|
|
day: '2-digit',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
});
|
|
},
|
|
|
|
formatTime(timestamp) {
|
|
if (!timestamp) return '-';
|
|
return String(timestamp).slice(0, 19);
|
|
},
|
|
|
|
formatPercent(value) {
|
|
if (value === null || value === undefined) return '-';
|
|
return `${(Number(value) * 100).toFixed(1)}%`;
|
|
},
|
|
|
|
getPredictionClass(prediction) {
|
|
if (prediction === 'UP') return 'text-success fw-bold';
|
|
if (prediction === 'DOWN') return 'text-danger fw-bold';
|
|
return '';
|
|
},
|
|
|
|
getStatusClass(status) {
|
|
switch (status) {
|
|
case 'success': return 'text-success';
|
|
case 'test': return 'text-info';
|
|
case 'failure': return 'text-danger';
|
|
case 'in_progress': return 'text-warning';
|
|
default: return 'text-muted';
|
|
}
|
|
},
|
|
|
|
getStatusText(status) {
|
|
switch (status) {
|
|
case 'success': return '成功';
|
|
case 'test': return '测试';
|
|
case 'failure': return '失败';
|
|
case 'in_progress': return '进行中';
|
|
default: return status || '-';
|
|
}
|
|
},
|
|
|
|
getAccuracyClass(accuracy) {
|
|
if (accuracy >= 60) return 'text-success fw-bold';
|
|
if (accuracy >= 50) return 'text-warning';
|
|
return 'text-danger';
|
|
},
|
|
|
|
async fetchAPI(url) {
|
|
try {
|
|
const response = await fetch(url);
|
|
return await response.json();
|
|
} catch (error) {
|
|
return { success: false, error: String(error) };
|
|
}
|
|
},
|
|
|
|
async loadCurrentTrade() {
|
|
const data = await this.fetchAPI('/api/trades/current');
|
|
if (data.success) {
|
|
this.currentTrade = data.data;
|
|
}
|
|
},
|
|
|
|
async loadTradeHistory(page) {
|
|
if (page < 1) return;
|
|
this.loading = true;
|
|
|
|
let url = `/api/trades/history?page=${page}&limit=${this.tradeHistory.limit}`;
|
|
if (this.tradeFilter.month) {
|
|
url += `&month=${this.tradeFilter.month}`;
|
|
}
|
|
if (this.tradeFilter.day) {
|
|
url += `&day=${this.tradeFilter.day}`;
|
|
}
|
|
|
|
const data = await this.fetchAPI(url);
|
|
if (data.success) {
|
|
this.tradeHistory = {
|
|
data: data.data,
|
|
page: data.page,
|
|
limit: data.limit,
|
|
total: data.total,
|
|
total_pages: data.total_pages,
|
|
};
|
|
}
|
|
|
|
this.loading = false;
|
|
},
|
|
|
|
clearTradeFilter() {
|
|
this.tradeFilter.month = '';
|
|
this.tradeFilter.day = '';
|
|
this.loadTradeHistory(1);
|
|
},
|
|
|
|
async loadAccuracyData() {
|
|
this.loading = true;
|
|
const monthlyData = await this.fetchAPI(`/api/accuracy/monthly?month=${this.accuracyFilter.month}`);
|
|
if (monthlyData.success) {
|
|
this.monthlyStats = monthlyData.data || {};
|
|
}
|
|
await this.loadDailyStats(1);
|
|
this.loading = false;
|
|
},
|
|
|
|
async loadDailyStats(page) {
|
|
if (page < 1) return;
|
|
const data = await this.fetchAPI(`/api/accuracy/daily?month=${this.accuracyFilter.month}&page=${page}&limit=10`);
|
|
if (data.success) {
|
|
this.dailyStats = {
|
|
data: data.data,
|
|
page: data.page,
|
|
limit: data.limit,
|
|
total: data.total,
|
|
total_pages: data.total_pages,
|
|
};
|
|
}
|
|
},
|
|
|
|
async showHourlyDetails(date) {
|
|
this.loading = true;
|
|
this.hourlyModal.date = date;
|
|
const data = await this.fetchAPI(`/api/accuracy/hourly/${date}`);
|
|
if (data.success) {
|
|
this.hourlyModal.data = data.data || [];
|
|
}
|
|
this.loading = false;
|
|
const modal = new bootstrap.Modal(document.getElementById('hourlyModal'));
|
|
modal.show();
|
|
},
|
|
},
|
|
|
|
watch: {
|
|
activeTab(newTab) {
|
|
if (newTab === 'accuracy' && !this.dailyStats.data.length) {
|
|
this.loadAccuracyData();
|
|
}
|
|
},
|
|
},
|
|
});
|
|
|
|
app.mount('#app');
|