1
This commit is contained in:
parent
e84fd312f4
commit
9b29e19d78
@ -150,6 +150,49 @@
|
|||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Admin Dropdown */
|
||||||
|
.admin-dropdown {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-menu {
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
right: 0;
|
||||||
|
margin-top: 8px;
|
||||||
|
background: var(--bg-primary);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
box-shadow: var(--shadow-lg);
|
||||||
|
min-width: 200px;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-menu-item {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px 16px;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
text-align: left;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-menu-item:hover {
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-menu-item:first-child {
|
||||||
|
border-radius: var(--radius-md) var(--radius-md) 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-menu-item:last-child {
|
||||||
|
border-radius: 0 0 var(--radius-md) var(--radius-md);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@ -158,7 +201,7 @@
|
|||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<div>
|
<div>
|
||||||
<div class="page-title">
|
<div class="page-title" @click="handleTitleClick" style="cursor: pointer;">
|
||||||
XClaw
|
XClaw
|
||||||
<span class="paper-badge">AI</span>
|
<span class="paper-badge">AI</span>
|
||||||
</div>
|
</div>
|
||||||
@ -166,12 +209,18 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
<button class="btn btn-secondary" @click="refreshData">刷新</button>
|
<button class="btn btn-secondary" @click="refreshData">刷新</button>
|
||||||
<button class="btn btn-primary" @click="sendReport" :disabled="sendingReport">
|
|
||||||
{{ sendingReport ? '发送中...' : '发送报告' }}
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-danger" @click="resetAccount" v-if="currentTab === 'positions' && openPositions.length > 0">
|
<button class="btn btn-danger" @click="resetAccount" v-if="currentTab === 'positions' && openPositions.length > 0">
|
||||||
重置账户
|
重置账户
|
||||||
</button>
|
</button>
|
||||||
|
<!-- 管理员菜单 -->
|
||||||
|
<div class="admin-dropdown" v-if="adminMode">
|
||||||
|
<button class="btn btn-secondary" @click="toggleAdminMenu">管理 ▾</button>
|
||||||
|
<div class="admin-menu" v-if="showAdminMenu">
|
||||||
|
<button class="admin-menu-item" @click="toggleAdminMode">
|
||||||
|
🔓 关闭管理员模式
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -182,21 +231,24 @@
|
|||||||
<div class="metric-value">${{ account.current_balance ? account.current_balance.toLocaleString() : '0' }}</div>
|
<div class="metric-value">${{ account.current_balance ? account.current_balance.toLocaleString() : '0' }}</div>
|
||||||
<div class="metric-sub">可用: ${{ account.available_margin ? account.available_margin.toLocaleString() : '0' }}</div>
|
<div class="metric-sub">可用: ${{ account.available_margin ? account.available_margin.toLocaleString() : '0' }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="metric-card">
|
|
||||||
<div class="metric-label">已用保证金</div>
|
|
||||||
<div class="metric-value">${{ account.used_margin ? account.used_margin.toLocaleString() : '0' }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="metric-card">
|
<div class="metric-card">
|
||||||
<div class="metric-label">持仓价值</div>
|
<div class="metric-label">持仓价值</div>
|
||||||
<div class="metric-value">${{ account.total_position_value ? account.total_position_value.toLocaleString() : '0' }}</div>
|
<div class="metric-value">${{ account.total_position_value ? account.total_position_value.toLocaleString() : '0' }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="metric-card">
|
<div class="metric-card">
|
||||||
<div class="metric-label">已实现盈亏</div>
|
<div class="metric-label">已实现盈亏</div>
|
||||||
<div class="metric-value" :class="account.realized_pnl >= 0 ? 'positive' : 'negative'">
|
<div class="metric-value" :class="stats.total_pnl >= 0 ? 'positive' : 'negative'">
|
||||||
${{ account.realized_pnl ? account.realized_pnl.toLocaleString() : '0' }}
|
${{ stats.total_pnl ? stats.total_pnl.toLocaleString() : '0' }}
|
||||||
</div>
|
</div>
|
||||||
<div class="metric-sub">{{ stats.total_trades || 0 }} 笔交易</div>
|
<div class="metric-sub">{{ stats.total_trades || 0 }} 笔交易</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-label">收益率</div>
|
||||||
|
<div class="metric-value" :class="stats.total_pnl_percent >= 0 ? 'positive' : 'negative'">
|
||||||
|
{{ stats.total_pnl_percent >= 0 ? '+' : '' }}{{ stats.total_pnl_percent ? stats.total_pnl_percent.toFixed(2) : '0.00' }}%
|
||||||
|
</div>
|
||||||
|
<div class="metric-sub">初始资金: $10,000</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Stats Grid -->
|
<!-- Stats Grid -->
|
||||||
@ -472,7 +524,12 @@
|
|||||||
current_total_leverage: 0,
|
current_total_leverage: 0,
|
||||||
max_total_leverage: 10
|
max_total_leverage: 10
|
||||||
},
|
},
|
||||||
orders: []
|
orders: [],
|
||||||
|
adminMode: false,
|
||||||
|
showAdminMenu: false,
|
||||||
|
adminPassword: '223388',
|
||||||
|
titleClickCount: 0,
|
||||||
|
titleClickTimer: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -483,7 +540,10 @@
|
|||||||
return this.orders.filter(o => o.status === 'pending');
|
return this.orders.filter(o => o.status === 'pending');
|
||||||
},
|
},
|
||||||
orderHistory() {
|
orderHistory() {
|
||||||
return this.orders.filter(o => o.status === 'closed');
|
// 包含所有已关闭的订单:closed_tp, closed_sl, closed_be, closed_ts, closed_manual, cancelled
|
||||||
|
return this.orders.filter(o =>
|
||||||
|
o.status.startsWith('closed') || o.status === 'cancelled'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -633,10 +693,56 @@
|
|||||||
'signal': '信号'
|
'signal': '信号'
|
||||||
};
|
};
|
||||||
return map[reason] || reason || '-';
|
return map[reason] || reason || '-';
|
||||||
|
},
|
||||||
|
|
||||||
|
handleTitleClick() {
|
||||||
|
this.titleClickCount++;
|
||||||
|
if (this.titleClickTimer) {
|
||||||
|
clearTimeout(this.titleClickTimer);
|
||||||
|
}
|
||||||
|
this.titleClickTimer = setTimeout(() => {
|
||||||
|
this.titleClickCount = 0;
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
if (this.titleClickCount === 3) {
|
||||||
|
this.titleClickCount = 0;
|
||||||
|
this.promptAdminMode();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
promptAdminMode() {
|
||||||
|
if (this.adminMode) {
|
||||||
|
this.adminMode = false;
|
||||||
|
this.showAdminMenu = false;
|
||||||
|
alert('管理员模式已关闭');
|
||||||
|
} else {
|
||||||
|
const password = prompt('请输入管理员密码:');
|
||||||
|
if (password === this.adminPassword) {
|
||||||
|
this.adminMode = true;
|
||||||
|
alert('管理员模式已开启');
|
||||||
|
} else if (password !== null) {
|
||||||
|
alert('密码错误');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleAdminMenu() {
|
||||||
|
this.showAdminMenu = !this.showAdminMenu;
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleAdminMode() {
|
||||||
|
this.promptAdminMode();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.refreshData();
|
this.refreshData();
|
||||||
|
|
||||||
|
// 点击外部关闭管理菜单
|
||||||
|
document.addEventListener('click', (e) => {
|
||||||
|
if (this.showAdminMenu && !e.target.closest('.admin-dropdown')) {
|
||||||
|
this.showAdminMenu = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}).mount('#app');
|
}).mount('#app');
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user