diff --git a/pages/detail/detail.vue b/pages/detail/detail.vue index e008f27..3d2bf28 100755 --- a/pages/detail/detail.vue +++ b/pages/detail/detail.vue @@ -77,6 +77,10 @@ 暂无收益数据 + 回填历史净值后可生成收益曲线 + @@ -480,6 +484,7 @@ const navLoading = ref(false); const navPeriod = ref('30d'); const navHistory = ref([]); const navStatistics = ref(null); +const backfillLoading = ref(false); // 绘制收益曲线 const drawNavChart = () => { @@ -487,7 +492,7 @@ const drawNavChart = () => { if (!data || data.length === 0) return; nextTick(() => { - const ctx = uni.createCanvasContext('navChart'); + const ctx = uni.createCanvasContext('navChart', this); // 画布尺寸 (rpx -> px) const width = 320; @@ -502,6 +507,12 @@ const drawNavChart = () => { const maxVal = Math.max(...values) * 1.02; const range = maxVal - minVal || 1; + // 判断收益正负,决定颜色 + const totalReturn = navStatistics.value?.totalReturn || 0; + const isPositive = totalReturn >= 0; + const lineColor = isPositive ? '#059669' : '#DC2626'; + const fillColor = isPositive ? 'rgba(5, 150, 105, 0.15)' : 'rgba(220, 38, 38, 0.15)'; + // 清空画布 ctx.clearRect(0, 0, width, height); @@ -541,12 +552,12 @@ const drawNavChart = () => { ctx.lineTo(points[points.length - 1].x, padding.top + chartHeight); ctx.lineTo(points[0].x, padding.top + chartHeight); ctx.closePath(); - ctx.setFillStyle('rgba(6, 78, 59, 0.15)'); + ctx.setFillStyle(fillColor); ctx.fill(); // 绘制曲线 ctx.beginPath(); - ctx.setStrokeStyle('#064E3B'); + ctx.setStrokeStyle(lineColor); ctx.setLineWidth(2); points.forEach((p, i) => { if (i === 0) ctx.moveTo(p.x, p.y); @@ -571,6 +582,32 @@ const drawNavChart = () => { }); }; +// 回填净值历史 +const handleBackfillNav = async () => { + if (!portfolioId.value) return; + + backfillLoading.value = true; + try { + const response = await api.assets.backfillNavHistory(portfolioId.value, true); + if (response.code === 200) { + uni.showToast({ + title: `成功生成 ${response.data.recordsCreated} 条记录`, + icon: 'success' + }); + // 重新获取净值历史 + await fetchNavHistory(); + } + } catch (error) { + console.error('回填净值失败:', error); + uni.showToast({ + title: '生成失败,请重试', + icon: 'none' + }); + } finally { + backfillLoading.value = false; + } +}; + // 交易表单 const showTransactionForm = ref(false); const transactionType = ref('buy'); // buy 或 sell @@ -1323,9 +1360,11 @@ const deletePortfolio = async () => { .nav-loading, .nav-empty { display: flex; + flex-direction: column; align-items: center; justify-content: center; height: 400rpx; + gap: 16rpx; } .loading-text, @@ -1334,6 +1373,26 @@ const deletePortfolio = async () => { color: #9CA3AF; } +.empty-hint { + font-size: 24rpx; + color: #D1D5DB; + margin-bottom: 8rpx; +} + +.backfill-btn { + margin-top: 16rpx; + padding: 16rpx 32rpx; + font-size: 26rpx; + color: #FFFFFF; + background-color: #059669; + border-radius: 8rpx; + border: none; +} + +.backfill-btn[disabled] { + background-color: #9CA3AF; +} + .nav-chart-wrapper { position: relative; width: 100%;