AssetManager.UniApp/pages/detail/detail.vue
niannian zheng e76bd6ff76 refactor: 统一将"策略"相关术语改为"逻辑"或"模型"
将代码中所有"策略"相关术语统一修改为"逻辑"或"模型",包括页面标题、标签、按钮文字等
同时调整了相关统计指标的名称,如"胜率"改为"完整度","盈亏"改为"波动"等
2026-02-25 11:12:12 +08:00

343 lines
13 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="page-container">
<view class="header-section">
<view class="asset-card">
<view class="card-watermark">
<uni-icons type="vip-filled" size="120" color="rgba(255,255,255,0.05)"></uni-icons>
</view>
<view class="card-top">
<text class="label-text">组合进度值 (NV)</text>
<view class="status-badge">
<text class="status-text">状态记录中</text>
</view>
</view>
<view class="card-main">
<text class="currency">¥</text>
<text class="big-number">156,240.00</text>
</view>
<view class="card-bottom">
<view class="stat-item">
<text class="stat-label">历史变化</text>
<text class="stat-val text-red">+42.82%</text>
</view>
<view class="stat-item align-right">
<text class="stat-label">日内波动</text>
<text class="stat-val text-red">+¥1,240.50</text>
</view>
</view>
</view>
</view>
<view class="section-container pb-0">
<view class="section-header">
<text class="section-title">当前逻辑模型</text>
<view class="flex-row items-center" @click="goStrategyConfig">
<text class="section-sub text-brand">参数配置</text>
<uni-icons type="right" size="12" color="#064E3B"></uni-icons>
</view>
</view>
<view class="strategy-info-card">
<view class="st-left">
<view class="st-icon-box bg-green-100">
<text class="st-icon-text text-green">H</text>
</view>
<view class="flex-col gap-1">
<text class="st-name">HFEA 风险平价逻辑</text>
<view class="flex-row gap-2">
<text class="st-tag">目标权重</text>
<text class="st-tag">季度调仓</text>
</view>
</view>
</view>
<view class="st-right">
<view class="flex-row items-center gap-1">
<view class="status-dot pulsing"></view>
<text class="st-status-text">监控中</text>
</view>
</view>
</view>
</view>
<view class="section-container">
<view class="section-header">
<text class="section-title">当前记录项 (3)</text>
<text class="section-sub">占比 100%</text>
</view>
<view class="position-list">
<view class="position-card" v-for="(item, index) in positions" :key="index">
<view class="pos-top">
<view class="flex-row items-center gap-2">
<view class="stock-icon" :class="item.iconClass">
<text class="icon-char">{{ item.name.charAt(0) }}</text>
</view>
<view class="flex-col">
<text class="stock-name">{{ item.name }}</text>
<text class="stock-code">{{ item.code }} · {{ item.shares }}份</text>
</view>
</view>
<view class="flex-col align-right">
<text class="market-val">¥{{ item.marketValue }}</text>
<text class="weight-tag">比例 {{ item.weight }}%</text>
</view>
</view>
<view class="divider"></view>
<view class="pos-bottom">
<view class="pnl-item">
<text class="pnl-label">变动额</text>
<text class="pnl-val" :class="item.pnl > 0 ? 'text-red' : 'text-green'">
{{ item.pnl > 0 ? '+' : '' }}{{ item.pnl }}
</text>
</view>
<view class="pnl-item align-right">
<text class="pnl-label">偏离比例</text>
<text class="pnl-val" :class="item.pnlPercent > 0 ? 'text-red' : 'text-green'">
{{ item.pnlPercent > 0 ? '+' : '' }}{{ item.pnlPercent }}%
</text>
</view>
</view>
</view>
</view>
</view>
<view class="section-container">
<view class="section-header">
<text class="section-title">最近交易记录</text>
</view>
<view class="timeline-box">
<view class="timeline-item" v-for="(log, k) in logs" :key="k">
<view class="tl-left">
<text class="tl-date">{{ log.date }}</text>
<text class="tl-time">{{ log.time }}</text>
</view>
<view class="tl-line">
<view class="tl-dot" :class="log.type === 'buy' ? 'bg-red' : 'bg-green'"></view>
<view class="tl-dash" v-if="k !== logs.length - 1"></view>
</view>
<view class="tl-right">
<text class="tl-title">{{ log.title }}</text>
<text class="tl-desc">{{ log.type === 'buy' ? '录入增加' : '结出减少' }} {{ log.amount }}</text>
</view>
</view>
</view>
</view>
<view class="action-section fixed-bottom">
<button class="action-btn btn-buy" @click="handleBuy">
<uni-icons type="download" size="20" color="#FFFFFF"></uni-icons>
<text class="btn-text">录入增加 / 比例校准</text>
</button>
<button class="action-btn btn-sell" @click="handleSell">
<uni-icons type="upload" size="20" color="#064E3B"></uni-icons>
<text class="btn-text">结出减少 / 调减</text>
</button>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue';
const positions = ref([
{ name: 'UPRO', code: 'UPRO.US', shares: 142, marketValue: '85,932.00', weight: 55, pnl: 12400.00, pnlPercent: 16.8, iconClass: 'bg-blue-100 text-blue' },
{ name: 'TMF', code: 'TMF.US', shares: 800, marketValue: '70,308.00', weight: 45, pnl: -3200.50, pnlPercent: -4.3, iconClass: 'bg-orange-100 text-orange' }
]);
const logs = ref([
{ date: '02-14', time: '14:30', type: 'buy', title: '定期定投 UPRO', amount: '$500.00' },
{ date: '01-01', time: '09:15', type: 'sell', title: '季度再平衡 TMF', amount: '200股' },
{ date: '12-15', time: '10:00', type: 'buy', title: '建仓买入', amount: '¥100,000' },
{ date: '12-10', time: '11:20', type: 'buy', title: '建仓买入', amount: '¥50,000' } // 加一条数据撑开高度,测试滚动
]);
const goStrategyConfig = () => {
uni.navigateTo({ url: '/pages/strategy/edit?id=1' });
};
const handleBuy = () => uni.showToast({ title: '买入', icon: 'none' });
const handleSell = () => uni.showToast({ title: '卖出', icon: 'none' });
</script>
<style scoped>
/* 基础设置 */
.page-container {
min-height: 100vh;
background-color: #F9FAFB;
/* 关键:底部留出空间,防止内容被固定按钮遮挡 */
padding-bottom: 180rpx;
}
.flex-row { display: flex; flex-direction: row; }
.flex-col { display: flex; flex-direction: column; }
.items-center { align-items: center; }
.justify-between { justify-content: space-between; }
.gap-1 { gap: 8rpx; }
.gap-2 { gap: 16rpx; }
.align-right { align-items: flex-end; }
.pb-0 { padding-bottom: 0 !important; }
/* 颜色工具 */
.text-red { color: #EF4444; }
.text-green { color: #10B981; }
.text-brand { color: #064E3B; }
.bg-blue-100 { background-color: #EFF6FF; }
.text-blue { color: #2563EB; }
.bg-orange-100 { background-color: #FFF7ED; }
.text-orange { color: #EA580C; }
.bg-green-100 { background-color: #ECFDF5; }
.bg-red { background-color: #EF4444; }
.bg-green { background-color: #10B981; }
/* 1. 导航栏 */
.nav-bar {
background-color: #fff;
padding: var(--status-bar-height) 32rpx 20rpx 32rpx;
display: flex;
align-items: center;
justify-content: space-between;
position: sticky;
top: 0;
z-index: 100;
}
.page-title { font-size: 34rpx; font-weight: 700; color: #111827; }
/* 2. 头部深色卡片 */
.header-section { padding: 20rpx 32rpx; }
.asset-card {
background-color: #064E3B;
border-radius: 40rpx;
padding: 40rpx;
position: relative;
overflow: hidden;
box-shadow: 0 10rpx 30rpx rgba(6, 78, 59, 0.25);
color: #fff;
}
.card-watermark { position: absolute; right: -20rpx; top: -20rpx; opacity: 0.1; transform: rotate(15deg); }
.card-top { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20rpx; }
.label-text { font-size: 26rpx; opacity: 0.8; }
.status-badge { background-color: rgba(255,255,255,0.2); padding: 4rpx 16rpx; border-radius: 20rpx; }
.status-text { font-size: 22rpx; font-weight: 600; }
.card-main { display: flex; align-items: baseline; margin-bottom: 40rpx; }
.currency { font-size: 40rpx; font-weight: 700; margin-right: 8rpx; }
.big-number { font-size: 64rpx; font-weight: 800; font-family: 'DIN Alternate'; }
.card-bottom { display: flex; justify-content: space-between; }
.stat-item { display: flex; flex-direction: column; gap: 8rpx; }
.stat-label { font-size: 24rpx; opacity: 0.7; }
.stat-val { font-size: 32rpx; font-weight: 700; font-family: 'DIN Alternate'; }
/* 策略信息卡片 */
.strategy-info-card {
background-color: #FFFFFF;
border-radius: 24rpx;
padding: 24rpx;
border: 1rpx solid #F3F4F6;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.02);
}
.st-left { display: flex; align-items: center; gap: 20rpx; }
.st-icon-box {
width: 80rpx; height: 80rpx;
border-radius: 20rpx;
display: flex; align-items: center; justify-content: center;
}
.st-icon-text { font-size: 36rpx; font-weight: 800; }
.st-name { font-size: 28rpx; font-weight: 700; color: #1F2937; }
.st-tag {
font-size: 20rpx; color: #6B7280;
background-color: #F3F4F6; padding: 2rpx 10rpx; border-radius: 8rpx;
}
.st-status-text { font-size: 24rpx; font-weight: 600; color: #059669; }
.status-dot {
width: 12rpx; height: 12rpx; border-radius: 50%;
background-color: #10B981;
}
.pulsing { animation: pulse 2s infinite; }
@keyframes pulse {
0% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.4); }
70% { box-shadow: 0 0 0 10rpx rgba(16, 185, 129, 0); }
100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
}
/* 通用容器 */
.section-container { padding: 20rpx 32rpx; }
.section-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24rpx; }
.section-title { font-size: 30rpx; font-weight: 800; color: #1F2937; border-left: 8rpx solid #064E3B; padding-left: 16rpx; line-height: 1; }
.section-sub { font-size: 24rpx; color: #9CA3AF; margin-right: 4rpx; }
/* 持仓卡片 */
.position-card {
background-color: #fff;
border-radius: 24rpx;
padding: 32rpx;
margin-bottom: 24rpx;
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.02);
border: 1rpx solid #F3F4F6;
}
.stock-icon { width: 80rpx; height: 80rpx; border-radius: 20rpx; display: flex; align-items: center; justify-content: center; }
.icon-char { font-size: 32rpx; font-weight: 800; }
.stock-name { font-size: 30rpx; font-weight: 700; color: #1F2937; }
.stock-code { font-size: 24rpx; color: #9CA3AF; margin-top: 4rpx; }
.market-val { font-size: 32rpx; font-weight: 700; color: #1F2937; }
.weight-tag { font-size: 22rpx; color: #6B7280; background-color: #F3F4F6; padding: 2rpx 12rpx; border-radius: 8rpx; margin-top: 8rpx; }
.divider { height: 1rpx; background-color: #F3F4F6; margin: 24rpx 0; }
.pos-bottom { display: flex; justify-content: space-between; }
.pnl-label { font-size: 22rpx; color: #9CA3AF; margin-bottom: 4rpx; }
.pnl-val { font-size: 28rpx; font-weight: 700; }
/* 交易明细 */
.timeline-box { padding: 0 16rpx; }
.timeline-item { display: flex; margin-bottom: 0; min-height: 120rpx; }
.tl-left { width: 80rpx; text-align: right; padding-right: 20rpx; display: flex; flex-direction: column; }
.tl-date { font-size: 26rpx; font-weight: 600; color: #374151; }
.tl-time { font-size: 22rpx; color: #9CA3AF; margin-top: 4rpx; }
.tl-line { width: 40rpx; display: flex; flex-direction: column; align-items: center; position: relative; }
.tl-dot { width: 16rpx; height: 16rpx; border-radius: 50%; z-index: 2; margin-top: 10rpx; }
.tl-dash { width: 2rpx; flex: 1; background-color: #E5E7EB; margin-top: 8rpx; }
.tl-right { flex: 1; padding-left: 20rpx; padding-bottom: 40rpx; }
.tl-title { font-size: 28rpx; font-weight: 600; color: #1F2937; }
.tl-desc { font-size: 24rpx; color: #6B7280; margin-top: 8rpx; }
/* 底部固定操作栏 */
.fixed-bottom {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: #FFFFFF;
display: flex;
gap: 24rpx;
padding: 20rpx 32rpx 50rpx 32rpx; /* 适配 iPhone X */
box-shadow: 0 -4rpx 16rpx rgba(0,0,0,0.05);
z-index: 999;
}
.action-btn {
flex: 1;
height: 96rpx;
border-radius: 24rpx;
display: flex;
align-items: center;
justify-content: center;
gap: 12rpx;
font-size: 30rpx;
font-weight: 700;
border: none;
}
.btn-buy { background-color: #064E3B; color: #FFFFFF; box-shadow: 0 8rpx 20rpx rgba(6, 78, 59, 0.2); }
.btn-buy:active { background-color: #047857; }
.btn-sell { background-color: #FFFFFF; color: #064E3B; border: 2rpx solid #064E3B; }
.btn-sell:active { background-color: #ECFDF5; }
</style>