Files
fire_goal/app/src/pages/progress/progress.vue
T

136 lines
4.3 KiB
Vue
Raw Normal View History

<script lang="ts" setup>
import { useProgressStore } from '@/store/progress'
defineOptions({ name: 'Progress' })
definePage({
style: { navigationBarTitleText: '目标进度' },
})
const store = useProgressStore()
const TARGET = 710000
const percent = computed(() => Math.min(100, Math.round((store.netAssets / TARGET) * 100)))
const remaining = computed(() => Math.max(0, TARGET - store.netAssets))
const showForm = ref(false)
const inputVal = ref('')
function saveSnapshot() {
const val = Number(inputVal.value)
if (!val || val < 0)
return
store.addSnapshot(val)
showForm.value = false
inputVal.value = ''
}
</script>
<template>
<view class="min-h-screen bg-gray-50 px-4 pt-12 pb-24">
<view class="mb-6 text-2xl font-bold text-gray-800">
目标进度
</view>
<!-- 目标进度卡片 -->
<view class="mb-4 rounded-2xl bg-white p-5 shadow-sm">
<view class="mb-1 flex justify-between text-sm text-gray-500">
<text>当前净资产</text>
<text>Barista FIRE 目标 71 万</text>
</view>
<!-- 进度条 -->
<view class="my-3 h-4 rounded-full bg-gray-100 overflow-hidden">
<view
class="h-full rounded-full bg-green-500 transition-all"
:style="{ width: `${percent}%` }"
/>
</view>
<view class="flex justify-between">
<view class="text-2xl font-bold text-gray-800">
¥{{ store.netAssets.toLocaleString() }}
</view>
<view class="text-xl font-bold text-green-600">
{{ percent }}%
</view>
</view>
<view class="mt-1 text-sm text-gray-400">
距目标还差 ¥{{ remaining.toLocaleString() }}
</view>
</view>
<!-- 统计卡片 -->
<view class="mb-4 grid grid-cols-2 gap-3">
<view class="rounded-2xl bg-white p-4 shadow-sm">
<view class="text-sm text-gray-500">
储蓄率
</view>
<view class="mt-1 text-2xl font-bold text-blue-500">
{{ store.savingsRate }}%
</view>
</view>
<view class="rounded-2xl bg-white p-4 shadow-sm">
<view class="text-sm text-gray-500">
累计记录次数
</view>
<view class="mt-1 text-2xl font-bold text-purple-500">
{{ store.snapshots.length }}
</view>
</view>
</view>
<!-- 净资产曲线(简单列表,图表后续加) -->
<view class="mb-4 rounded-2xl bg-white shadow-sm overflow-hidden">
<view class="px-5 py-3 border-b border-gray-100 font-medium text-gray-700">
历史记录
</view>
<view v-if="store.snapshots.length === 0" class="px-5 py-8 text-center text-gray-400">
暂无记录,点击下方按钮录入
</view>
<view
v-for="s in [...store.snapshots].reverse().slice(0, 10)"
:key="s.date"
class="flex justify-between px-5 py-3 border-b border-gray-100 last:border-none"
>
<text class="text-gray-500 text-sm">{{ s.date }}</text>
<text class="font-medium text-gray-800">¥{{ s.amount.toLocaleString() }}</text>
</view>
</view>
<!-- 录入按钮 -->
<view
class="fixed bottom-20 right-5 h-14 w-14 rounded-full bg-green-500 shadow-lg flex items-center justify-center"
@tap="showForm = true"
>
<text class="text-white text-2xl leading-none">+</text>
</view>
<!-- 录入弹窗 -->
<view v-if="showForm" class="fixed inset-0 bg-black/40 flex items-end" @tap.self="showForm = false">
<view class="w-full rounded-t-3xl bg-white p-6">
<view class="mb-4 text-lg font-medium text-gray-800">
录入当前净资产
</view>
<input
v-model="inputVal"
type="digit"
placeholder="请输入金额(元)"
class="w-full rounded-xl border border-gray-200 px-4 py-3 text-base"
/>
<view class="mt-4 flex gap-3">
<view
class="flex-1 rounded-xl border border-gray-200 py-3 text-center text-gray-500"
@tap="showForm = false"
>
取消
</view>
<view
class="flex-1 rounded-xl bg-green-500 py-3 text-center text-white font-medium"
@tap="saveSnapshot"
>
保存
</view>
</view>
</view>
</view>
</view>
</template>