- store/settings.ts: target 71万, withdraw rate 3.5%, monthly invest 1500, etc. (persist) - progress.vue: read target from settings store instead of hardcoded value - index/index.vue: remove type:home conflict so checkin page is the entry Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
137 lines
4.4 KiB
Vue
137 lines
4.4 KiB
Vue
<script lang="ts" setup>
|
||
import { useProgressStore } from '@/store/progress'
|
||
import { useSettingsStore } from '@/store/settings'
|
||
|
||
defineOptions({ name: 'Progress' })
|
||
definePage({
|
||
style: { navigationBarTitleText: '目标进度' },
|
||
})
|
||
|
||
const store = useProgressStore()
|
||
const settings = useSettingsStore()
|
||
|
||
const percent = computed(() => Math.min(100, Math.round((store.netAssets / settings.target) * 100)))
|
||
const remaining = computed(() => Math.max(0, settings.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>
|