This commit is contained in:
aaron 2026-02-15 20:25:29 +08:00
parent 92c1a6cbd2
commit b6cc275d24

View File

@ -674,6 +674,263 @@
font-size: 16px;
}
}
/* 分享按钮 */
.action-btn.share {
background: transparent;
border: 1px solid var(--accent);
color: var(--accent);
padding: 4px 8px;
margin-right: 4px;
font-size: 12px;
}
.action-btn.share:hover {
background: rgba(0, 212, 170, 0.1);
}
/* 分享模态框 */
.share-modal-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.share-modal {
background: var(--bg-secondary);
border-radius: 12px;
padding: 20px;
max-width: 400px;
width: 90%;
}
.share-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.share-modal-header h3 {
margin: 0;
color: var(--text-primary);
font-weight: 400;
}
.close-btn {
background: none;
border: none;
color: var(--text-secondary);
font-size: 24px;
cursor: pointer;
}
.close-btn:hover {
color: var(--text-primary);
}
/* 分享卡片 */
.share-card {
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
border-radius: 16px;
padding: 24px;
color: #fff;
}
.share-card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.share-logo {
font-size: 18px;
font-weight: 700;
letter-spacing: 2px;
color: var(--accent);
}
.share-time {
font-size: 12px;
color: rgba(255, 255, 255, 0.6);
}
.share-card-body {
text-align: center;
}
.share-symbol {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
margin-bottom: 16px;
}
.symbol-name {
font-size: 24px;
font-weight: 600;
}
.side-tag {
padding: 4px 12px;
border-radius: 4px;
font-size: 14px;
font-weight: 500;
}
.side-tag.long {
background: rgba(0, 200, 150, 0.2);
color: #00c896;
}
.side-tag.short {
background: rgba(255, 99, 99, 0.2);
color: #ff6363;
}
.share-pnl {
font-size: 48px;
font-weight: 700;
margin-bottom: 8px;
}
.share-pnl.positive {
color: #00c896;
}
.share-pnl.negative {
color: #ff6363;
}
.share-pnl-amount {
font-size: 20px;
margin-bottom: 24px;
}
.share-pnl-amount.positive {
color: #00c896;
}
.share-pnl-amount.negative {
color: #ff6363;
}
.share-prices {
display: flex;
justify-content: center;
gap: 40px;
margin-bottom: 24px;
padding: 16px;
background: rgba(255, 255, 255, 0.05);
border-radius: 8px;
}
.share-prices .price-item {
text-align: center;
}
.share-prices .price-label {
display: block;
font-size: 12px;
color: rgba(255, 255, 255, 0.6);
margin-bottom: 4px;
}
.share-prices .price-value {
font-size: 18px;
font-weight: 500;
}
.share-footer {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 16px;
border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.share-grade {
display: flex;
align-items: center;
gap: 8px;
}
.share-grade .grade-badge {
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 600;
}
.share-grade .grade-badge.A {
background: linear-gradient(135deg, #ffd700, #ffb300);
color: #1a1a2e;
}
.share-grade .grade-badge.B {
background: linear-gradient(135deg, #c0c0c0, #a0a0a0);
color: #1a1a2e;
}
.share-grade .grade-badge.C {
background: linear-gradient(135deg, #cd7f32, #a0522d);
color: #fff;
}
.share-grade .grade-text {
font-size: 12px;
color: rgba(255, 255, 255, 0.6);
}
.share-slogan {
font-size: 12px;
color: rgba(255, 255, 255, 0.4);
font-style: italic;
}
/* 分享按钮 */
.share-modal-actions {
display: flex;
gap: 12px;
margin-top: 16px;
}
.share-btn {
flex: 1;
padding: 12px;
border: none;
border-radius: 8px;
font-size: 14px;
cursor: pointer;
transition: all 0.2s;
}
.share-btn.download {
background: var(--accent);
color: #1a1a2e;
}
.share-btn.download:hover {
background: #00b894;
}
.share-btn.copy {
background: rgba(255, 255, 255, 0.1);
color: var(--text-primary);
}
.share-btn.copy:hover {
background: rgba(255, 255, 255, 0.2);
}
</style>
</head>
<body>
@ -848,6 +1105,9 @@
<td>${{ order.quantity }}</td>
<td>{{ formatTime(order.status === 'open' ? order.opened_at : order.created_at) }}</td>
<td>
<button v-if="order.status === 'open'" class="action-btn share" @click="shareOrder(order)" title="分享">
📤
</button>
<button class="action-btn danger" @click="closeOrder(order)">
{{ order.status === 'pending' ? '取消' : '平仓' }}
</button>
@ -960,9 +1220,65 @@
</div>
</div>
</div>
<!-- 分享卡片模态框 -->
<div v-if="showShareModal" class="share-modal-overlay" @click="closeShareModal">
<div class="share-modal" @click.stop>
<div class="share-modal-header">
<h3>分享持仓</h3>
<button class="close-btn" @click="closeShareModal">×</button>
</div>
<div class="share-card" ref="shareCard">
<div class="share-card-header">
<div class="share-logo">TRADUS</div>
<div class="share-time">{{ formatShareTime() }}</div>
</div>
<div class="share-card-body">
<div class="share-symbol">
<span class="symbol-name">{{ shareOrderData.symbol }}</span>
<span class="side-tag" :class="shareOrderData.side">
{{ shareOrderData.side === 'long' ? '做多' : '做空' }}
</span>
</div>
<div class="share-pnl" :class="shareOrderData.pnlPercent >= 0 ? 'positive' : 'negative'">
{{ shareOrderData.pnlPercent >= 0 ? '+' : '' }}{{ shareOrderData.pnlPercent.toFixed(2) }}%
</div>
<div class="share-pnl-amount" :class="shareOrderData.pnlAmount >= 0 ? 'positive' : 'negative'">
{{ shareOrderData.pnlAmount >= 0 ? '+' : '' }}${{ shareOrderData.pnlAmount.toFixed(2) }}
</div>
<div class="share-prices">
<div class="price-item">
<span class="price-label">开仓价</span>
<span class="price-value">${{ shareOrderData.entryPrice?.toLocaleString() }}</span>
</div>
<div class="price-item">
<span class="price-label">现价</span>
<span class="price-value">${{ shareOrderData.currentPrice?.toLocaleString() }}</span>
</div>
</div>
<div class="share-footer">
<div class="share-grade">
<span class="grade-badge" :class="shareOrderData.grade">{{ shareOrderData.grade }}</span>
<span class="grade-text">信号等级</span>
</div>
<div class="share-slogan">AI Agent Trading System</div>
</div>
</div>
</div>
<div class="share-modal-actions">
<button class="share-btn download" @click="downloadShareImage">
📥 下载图片
</button>
<button class="share-btn copy" @click="copyShareImage">
📋 复制图片
</button>
</div>
</div>
</div>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
<script>
const { createApp } = Vue;
@ -1005,7 +1321,17 @@
isFirstLoad: true,
sendingReport: false,
showAdminMenu: false,
adminPassword: '223388'
adminPassword: '223388',
showShareModal: false,
shareOrderData: {
symbol: '',
side: 'long',
entryPrice: 0,
currentPrice: 0,
pnlPercent: 0,
pnlAmount: 0,
grade: 'B'
}
};
},
mounted() {
@ -1063,6 +1389,90 @@
await this.resetData();
},
// 分享订单
shareOrder(order) {
const currentPrice = this.getCurrentPrice(order.symbol);
const pnl = this.getUnrealizedPnl(order);
this.shareOrderData = {
symbol: order.symbol,
side: order.side,
entryPrice: order.entry_price,
currentPrice: currentPrice,
pnlPercent: pnl.percent,
pnlAmount: pnl.pnl,
grade: order.signal_grade
};
this.showShareModal = true;
},
// 关闭分享模态框
closeShareModal() {
this.showShareModal = false;
},
// 格式化分享时间
formatShareTime() {
return new Date().toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
});
},
// 下载分享图片
async downloadShareImage() {
const card = this.$refs.shareCard;
if (!card) return;
try {
const canvas = await html2canvas(card, {
backgroundColor: null,
scale: 2,
useCORS: true
});
const link = document.createElement('a');
link.download = `tradus-${this.shareOrderData.symbol}-${Date.now()}.png`;
link.href = canvas.toDataURL('image/png');
link.click();
} catch (e) {
console.error('生成图片失败:', e);
alert('生成图片失败,请重试');
}
},
// 复制分享图片
async copyShareImage() {
const card = this.$refs.shareCard;
if (!card) return;
try {
const canvas = await html2canvas(card, {
backgroundColor: null,
scale: 2,
useCORS: true
});
canvas.toBlob(async (blob) => {
try {
await navigator.clipboard.write([
new ClipboardItem({ 'image/png': blob })
]);
alert('图片已复制到剪贴板');
} catch (e) {
console.error('复制失败:', e);
alert('复制失败,请使用下载功能');
}
}, 'image/png');
} catch (e) {
console.error('生成图片失败:', e);
alert('生成图片失败,请重试');
}
},
// 静默刷新(不显示 loading
async silentRefresh() {
await this.refreshData();