483 lines
9.5 KiB
Vue
483 lines
9.5 KiB
Vue
<template>
|
|
<view class="page-container">
|
|
|
|
<view class="header-section">
|
|
<view class="asset-card">
|
|
|
|
|
|
<view class="card-row top-row">
|
|
<view class="row-left">
|
|
<text class="label-text">总指标估值 (CNY)</text>
|
|
<view class="eye-btn">
|
|
<uni-icons type="eye-filled" size="18" color="rgba(255,255,255,0.7)"></uni-icons>
|
|
</view>
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
<view class="card-row main-row">
|
|
<text class="currency-symbol">¥</text>
|
|
<text class="big-number">{{ assetData.totalValue.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) }}</text>
|
|
</view>
|
|
|
|
<view class="card-row bottom-row">
|
|
<view class="stat-col">
|
|
<text class="stat-label">日内波动</text>
|
|
<text class="stat-value">{{ assetData.todayProfit >= 0 ? '+' : '' }}¥{{ assetData.todayProfit.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) }}</text>
|
|
</view>
|
|
<view class="stat-col align-right">
|
|
<text class="stat-label">累计变化</text>
|
|
<text class="stat-value">{{ assetData.totalReturnRate >= 0 ? '+' : '' }}{{ assetData.totalReturnRate }}%</text>
|
|
</view>
|
|
</view>
|
|
|
|
</view>
|
|
</view>
|
|
|
|
<view class="part-add-portfolio">
|
|
<view class="dashed-btn" @click="goConfig">
|
|
<uni-icons type="plus" size="20" color="#9CA3AF"></uni-icons>
|
|
<text class="btn-text">新建逻辑模型</text>
|
|
</view>
|
|
</view>
|
|
|
|
|
|
<view class="part-holdings-list">
|
|
|
|
<view class="section-header">
|
|
<text class="section-title">当前记录组合</text>
|
|
</view>
|
|
|
|
<view
|
|
v-for="holding in holdings"
|
|
:key="holding.id"
|
|
class="holding-card"
|
|
@click="goDetail(holding.id)"
|
|
>
|
|
<view class="card-top">
|
|
<view class="flex-row items-center gap-2">
|
|
<view class="strategy-icon" :class="holding.iconBgClass">
|
|
<text class="icon-text" :class="holding.iconTextClass">{{ holding.iconChar }}</text>
|
|
</view>
|
|
<view class="flex-col">
|
|
<text class="card-name">{{ holding.name }}</text>
|
|
<text class="card-tags">{{ holding.tags }}</text>
|
|
</view>
|
|
</view>
|
|
<view class="status-badge" :class="holding.statusType === 'green' ? 'bg-green-50' : 'bg-gray-100'">
|
|
<text class="status-text" :class="holding.statusType === 'green' ? 'text-green-600' : 'text-gray-500'">● {{ holding.status }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="card-divider"></view>
|
|
|
|
<view class="card-bottom">
|
|
<view class="data-col">
|
|
<text class="data-label">当前分值</text>
|
|
<text class="data-val">¥ {{ holding.value.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) }}</text>
|
|
</view>
|
|
<view class="data-col align-right">
|
|
<text class="data-label">累计变化</text>
|
|
<text class="data-val" :class="holding.returnType === 'positive' ? 'text-red' : 'text-green'">{{ holding.returnRate >= 0 ? '+' : '' }}{{ holding.returnRate }}%</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view style="height: 100rpx;"></view>
|
|
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, onMounted } from 'vue';
|
|
import { api } from '../../utils/api';
|
|
|
|
// 资产数据
|
|
const assetData = ref({
|
|
totalValue: 0,
|
|
todayProfit: 0,
|
|
totalReturnRate: 0
|
|
});
|
|
|
|
// 持仓组合数据
|
|
const holdings = ref([]);
|
|
|
|
// 从后端API获取资产数据的函数
|
|
const fetchAssetData = async () => {
|
|
try {
|
|
const response = await api.assets.getAssetData();
|
|
if (response.code === 200) {
|
|
assetData.value = response.data;
|
|
}
|
|
} catch (error) {
|
|
console.error('获取资产数据失败:', error);
|
|
}
|
|
};
|
|
|
|
// 从后端API获取持仓组合数据的函数
|
|
const fetchHoldingsData = async () => {
|
|
try {
|
|
const response = await api.assets.getHoldings();
|
|
if (response.code === 200) {
|
|
holdings.value = response.data;
|
|
}
|
|
} catch (error) {
|
|
console.error('获取持仓数据失败:', error);
|
|
}
|
|
};
|
|
|
|
// 页面加载时获取数据
|
|
onMounted(async () => {
|
|
await Promise.all([
|
|
fetchAssetData(),
|
|
fetchHoldingsData()
|
|
]);
|
|
});
|
|
|
|
const goConfig = () => {
|
|
uni.navigateTo({ url: '/pages/config/config' });
|
|
};
|
|
|
|
const goDetail = (holdingId) => {
|
|
uni.navigateTo({ url: `/pages/detail/detail?id=${holdingId}` });
|
|
};
|
|
|
|
const goStrategies = () => {
|
|
uni.switchTab({ url: '/pages/strategies/strategies' });
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
/* 通用布局 */
|
|
.page-container {
|
|
min-height: 100vh;
|
|
background-color: #F9FAFB;
|
|
/* 浅灰色背景,与添加按钮背景一致 */
|
|
}
|
|
|
|
.flex-row {
|
|
display: flex;
|
|
flex-direction: row;
|
|
}
|
|
|
|
.flex-col {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.items-center {
|
|
align-items: center;
|
|
}
|
|
|
|
.gap-2 {
|
|
gap: 16rpx;
|
|
}
|
|
|
|
.mt-2 {
|
|
margin-top: 16rpx;
|
|
}
|
|
|
|
/* 字体颜色工具类 */
|
|
.text-white {
|
|
color: #fff;
|
|
}
|
|
|
|
.text-gray-500 {
|
|
color: #6B7280;
|
|
}
|
|
|
|
.text-green-600 {
|
|
color: #059669;
|
|
}
|
|
|
|
.text-green-700 {
|
|
color: #047857;
|
|
}
|
|
|
|
.text-blue-700 {
|
|
color: #1D4ED8;
|
|
}
|
|
|
|
.text-red {
|
|
color: #EF4444;
|
|
}
|
|
|
|
/* 涨 */
|
|
.text-green {
|
|
color: #10B981;
|
|
}
|
|
|
|
/* 跌 */
|
|
|
|
/* ============================ */
|
|
/* Part 1: 资产卡片样式 (精修版) */
|
|
/* ============================ */
|
|
.header-section {
|
|
padding: 20rpx 32rpx;
|
|
background-color: #F9FAFB;
|
|
/* 浅灰色背景,与页面背景一致 */
|
|
}
|
|
|
|
.asset-card {
|
|
background-color: #064E3B;
|
|
/* 深墨绿色 */
|
|
border-radius: 40rpx;
|
|
padding: 40rpx 48rpx;
|
|
position: relative;
|
|
overflow: hidden;
|
|
box-shadow: 0 10rpx 30rpx rgba(6, 78, 59, 0.25);
|
|
min-height: 320rpx;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
|
|
/* 内容行通用设置 */
|
|
.card-row {
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
|
|
/* 第一行:顶部布局 (关键修复:两端对齐) */
|
|
.top-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
/* 让铃铛靠右 */
|
|
align-items: center;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.row-left {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.label-text {
|
|
font-size: 26rpx;
|
|
color: rgba(255, 255, 255, 0.7);
|
|
font-weight: 400;
|
|
}
|
|
|
|
.eye-btn {
|
|
margin-left: 12rpx;
|
|
opacity: 0.8;
|
|
}
|
|
|
|
|
|
/* 第二行:大数字 */
|
|
.main-row {
|
|
display: flex;
|
|
align-items: baseline;
|
|
margin-bottom: 30rpx;
|
|
}
|
|
|
|
.currency-symbol {
|
|
font-size: 40rpx;
|
|
color: #FFFFFF;
|
|
font-weight: bold;
|
|
margin-right: 8rpx;
|
|
font-family: 'DIN Alternate', sans-serif;
|
|
}
|
|
|
|
.big-number {
|
|
font-size: 68rpx;
|
|
color: #FFFFFF;
|
|
font-weight: 800;
|
|
letter-spacing: 1rpx;
|
|
font-family: 'DIN Alternate', sans-serif;
|
|
}
|
|
|
|
/* 第三行:底部数据 */
|
|
.bottom-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: flex-end;
|
|
}
|
|
|
|
.stat-col {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8rpx;
|
|
}
|
|
|
|
.align-right {
|
|
align-items: flex-end;
|
|
}
|
|
|
|
.stat-label {
|
|
font-size: 24rpx;
|
|
color: rgba(255, 255, 255, 0.6);
|
|
}
|
|
|
|
.stat-value {
|
|
font-size: 36rpx;
|
|
color: #FFFFFF;
|
|
font-weight: 700;
|
|
font-family: 'DIN Alternate', sans-serif;
|
|
}
|
|
|
|
/* ============================ */
|
|
/* Part 2: 添加组合按钮样式 */
|
|
/* ============================ */
|
|
.part-add-portfolio {
|
|
padding: 10rpx 32rpx 30rpx 32rpx;
|
|
}
|
|
|
|
.dashed-btn {
|
|
width: 100%;
|
|
height: 96rpx;
|
|
background-color: #F9FAFB;
|
|
border: 2rpx dashed #D1D5DB;
|
|
border-radius: 24rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 12rpx;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.dashed-btn:active {
|
|
background-color: #F3F4F6;
|
|
border-color: #9CA3AF;
|
|
}
|
|
|
|
.btn-text {
|
|
font-size: 28rpx;
|
|
color: #6B7280;
|
|
font-weight: 500;
|
|
}
|
|
|
|
/* ============================ */
|
|
/* Part 3: 持仓列表样式 */
|
|
/* ============================ */
|
|
.part-holdings-list {
|
|
padding: 0 32rpx;
|
|
}
|
|
|
|
.section-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 24rpx;
|
|
padding-left: 8rpx;
|
|
}
|
|
|
|
.section-title {
|
|
font-size: 32rpx;
|
|
font-weight: 800;
|
|
color: #1F2937;
|
|
}
|
|
|
|
.view-all {
|
|
font-size: 24rpx;
|
|
color: #064E3B;
|
|
font-weight: 600;
|
|
margin-right: 4rpx;
|
|
}
|
|
|
|
/* 卡片样式 */
|
|
.holding-card {
|
|
background-color: #FFFFFF;
|
|
border: 1rpx solid #E5E7EB;
|
|
border-radius: 32rpx;
|
|
padding: 32rpx;
|
|
margin-bottom: 24rpx;
|
|
box-shadow: 0 12rpx 32rpx rgba(0, 0, 0, 0.06);
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.holding-card:active {
|
|
transform: translateY(2rpx);
|
|
box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.04);
|
|
}
|
|
|
|
.card-top {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: flex-start;
|
|
}
|
|
|
|
.strategy-icon {
|
|
width: 80rpx;
|
|
height: 80rpx;
|
|
border-radius: 20rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.bg-green-100 {
|
|
background-color: #D1FAE5;
|
|
}
|
|
|
|
.bg-blue-100 {
|
|
background-color: #DBEAFE;
|
|
}
|
|
|
|
.bg-green-50 {
|
|
background-color: #ECFDF5;
|
|
}
|
|
|
|
.bg-gray-100 {
|
|
background-color: #F3F4F6;
|
|
}
|
|
|
|
.icon-text {
|
|
font-size: 36rpx;
|
|
font-weight: 800;
|
|
}
|
|
|
|
.card-name {
|
|
font-size: 30rpx;
|
|
font-weight: 700;
|
|
color: #1F2937;
|
|
margin-bottom: 6rpx;
|
|
}
|
|
|
|
.card-tags {
|
|
font-size: 22rpx;
|
|
color: #9CA3AF;
|
|
}
|
|
|
|
.status-badge {
|
|
padding: 6rpx 16rpx;
|
|
border-radius: 100rpx;
|
|
}
|
|
|
|
.status-text {
|
|
font-size: 20rpx;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.card-divider {
|
|
height: 1rpx;
|
|
background-color: #F3F4F6;
|
|
margin: 24rpx 0;
|
|
}
|
|
|
|
.card-bottom {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.data-col {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.data-label {
|
|
font-size: 22rpx;
|
|
color: #9CA3AF;
|
|
margin-bottom: 8rpx;
|
|
}
|
|
|
|
.data-val {
|
|
font-size: 32rpx;
|
|
font-weight: 700;
|
|
font-family: 'DIN Alternate', sans-serif;
|
|
color: #1F2937;
|
|
}
|
|
</style> |