lucky-loster's picture
Upload folder using huggingface_hub
590a501 verified
Raw
History Blame Contribute Delete
7.77 kB
<template>
<div style="min-height: 100vh; background: var(--bg-body);" @click="openMenu = ''">
<!-- Top Navbar -->
<nav class="top-navbar">
<div class="nav-inner">
<!-- Brand -->
<a class="nav-brand" @click.prevent="go('/')">
<div class="brand-icon">P</div>
<span class="brand-text">PTS V1</span>
</a>
<!-- Nav Items -->
<div class="nav-links">
<!-- 行情 -->
<div class="nav-dropdown">
<a class="nav-link" @click.stop="toggleMenu('market')">
<el-icon><TrendCharts /></el-icon>
行情
<span class="nav-arrow" :class="{ open: openMenu === 'market' }"></span>
</a>
<div class="dropdown-panel" v-show="openMenu === 'market'" @click.stop>
<a class="dd-item" @click="go('/')"><el-icon><Monitor /></el-icon> 仪表盘</a>
<a class="dd-item" @click="go('/market')"><el-icon><TrendCharts /></el-icon> 行情中心</a>
</div>
</div>
<!-- 交易 -->
<div class="nav-dropdown">
<a class="nav-link" @click.stop="toggleMenu('trade')">
<el-icon><Sell /></el-icon>
交易
<span class="nav-arrow" :class="{ open: openMenu === 'trade' }"></span>
</a>
<div class="dropdown-panel" v-show="openMenu === 'trade'" @click.stop>
<a class="dd-item" @click="go('/trading')"><el-icon><Sell /></el-icon> 交易下单</a>
<a class="dd-item" @click="go('/positions')"><el-icon><Wallet /></el-icon> 持仓管理</a>
</div>
</div>
<!-- 策略 -->
<div class="nav-dropdown">
<a class="nav-link" @click.stop="toggleMenu('strategy')">
<el-icon><DataAnalysis /></el-icon>
策略
<span class="nav-arrow" :class="{ open: openMenu === 'strategy' }"></span>
</a>
<div class="dropdown-panel" v-show="openMenu === 'strategy'" @click.stop>
<a class="dd-item" @click="go('/strategies')"><el-icon><DataAnalysis /></el-icon> 量化策略</a>
<a class="dd-item" @click="go('/backtest')"><el-icon><DataLine /></el-icon> 策略回测</a>
<a class="dd-item" @click="go('/opportunities')"><el-icon><Aim /></el-icon> 寻找机会</a>
</div>
</div>
<!-- 风控 -->
<a class="nav-link" @click.prevent="go('/risk')">
<el-icon><Warning /></el-icon>
风控中心
</a>
<!-- 平台 -->
<div class="nav-dropdown">
<a class="nav-link" @click.stop="toggleMenu('platform')">
<el-icon><Setting /></el-icon>
平台
<span class="nav-arrow" :class="{ open: openMenu === 'platform' }"></span>
</a>
<div class="dropdown-panel" v-show="openMenu === 'platform'" @click.stop>
<a class="dd-item" @click="go('/services')"><el-icon><Setting /></el-icon> 服务控制台</a>
<a class="dd-item" @click="go('/research')"><el-icon><Cpu /></el-icon> 因子研究</a>
</div>
</div>
</div>
<!-- Right -->
<div class="nav-right">
<span class="badge-pill green" style="margin-right: 12px;">{{ store.marketMode === 'realtime' ? '实时' : '模拟' }}</span>
<div class="nav-account">
<span class="account-label">总资产</span>
<span class="account-value">¥{{ fmt(store.account.total_balance) }}</span>
</div>
<div class="nav-divider"></div>
<div class="nav-account">
<span class="account-label">盈亏</span>
<span class="account-value" :style="{ color: store.account.unrealized_pnl >= 0 ? 'var(--green)' : 'var(--red)' }">
{{ store.account.unrealized_pnl >= 0 ? '+' : '' }{{ fmt(store.account.unrealized_pnl) }}
</span>
</div>
</div>
</div>
</nav>
<!-- Main -->
<main style="padding: 24px 32px; max-width: 1600px; margin: 0 auto;">
<router-view />
</main>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import { useRouter } from 'vue-router'
import { useTradingStore } from './stores/trading'
const router = useRouter()
const store = useTradingStore()
const openMenu = ref('')
function toggleMenu(name) {
openMenu.value = openMenu.value === name ? '' : name
}
function go(path) {
openMenu.value = ''
router.push(path)
}
function fmt(n) { return (n || 0).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) }
let iv
onMounted(() => {
store.fetchCategories(); store.fetchContracts(); store.fetchQuotes()
store.fetchAccount(); store.fetchMarketMode(); store.connectWebSocket()
iv = setInterval(() => { store.fetchAccount(); store.fetchQuotes() }, 3000)
})
onUnmounted(() => { store.disconnectWebSocket(); clearInterval(iv) })
</script>
<style scoped>
.top-navbar {
background: rgba(255,255,255,0.95);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
box-shadow: 0 2px 12px rgba(0,0,0,0.06);
position: sticky; top: 0; z-index: 100;
border-bottom: 1px solid rgba(0,0,0,0.05);
}
.nav-inner {
max-width: 1600px; margin: 0 auto;
display: flex; align-items: center; justify-content: space-between;
padding: 0 32px; height: 60px;
}
.nav-brand {
display: flex; align-items: center; gap: 10px; text-decoration: none; cursor: pointer;
}
.brand-icon {
width: 34px; height: 34px; border-radius: 8px;
background: var(--green-gradient); color: white;
display: flex; align-items: center; justify-content: center;
font-weight: 700; font-size: 15px;
box-shadow: 0 3px 5px -1px rgba(76,175,80,0.4);
}
.brand-text { font-size: 15px; font-weight: 700; color: var(--text-dark); letter-spacing: 0.5px; }
.nav-links { display: flex; align-items: center; gap: 4px; }
.nav-dropdown { position: relative; }
.nav-link {
display: flex; align-items: center; gap: 6px;
padding: 8px 16px; border-radius: 8px;
font-size: 14px; font-weight: 500; color: var(--text-body);
cursor: pointer; text-decoration: none; transition: all 0.15s;
user-select: none;
}
.nav-link:hover { color: var(--text-dark); background: var(--bg-light); }
.nav-arrow {
font-size: 10px; opacity: 0.5; margin-left: 2px;
transition: transform 0.2s; display: inline-block;
}
.nav-arrow.open { transform: rotate(180deg); }
.dropdown-panel {
position: absolute; top: 100%; left: 0; padding-top: 6px;
}
.dropdown-panel::before {
content: ''; position: absolute; top: 6px; left: 0; right: 0; bottom: 0;
background: white; border-radius: 12px;
box-shadow: 0 10px 40px rgba(0,0,0,0.1), 0 2px 10px rgba(0,0,0,0.06);
border: 1px solid rgba(0,0,0,0.05);
}
.dd-item {
position: relative; display: flex; align-items: center; gap: 8px;
padding: 10px 14px; margin: 8px; border-radius: 8px;
font-size: 13px; font-weight: 500; color: var(--text-body);
text-decoration: none; transition: all 0.15s; cursor: pointer; min-width: 160px;
}
.dd-item:first-child { margin-top: 12px; }
.dd-item:last-child { margin-bottom: 12px; }
.dd-item:hover { background: var(--green-light); color: var(--green); }
.nav-right { display: flex; align-items: center; gap: 8px; }
.nav-account { text-align: right; }
.account-label { display: block; font-size: 10px; color: var(--text-light); font-weight: 500; text-transform: uppercase; letter-spacing: 0.5px; }
.account-value { font-size: 14px; font-weight: 700; color: var(--text-dark); }
.nav-divider { width: 1px; height: 28px; background: var(--border); margin: 0 8px; }
</style>