add unibest app skeleton with checkin and progress pages
- init unibest v4.4.0 base template - tabbar: 4 tabs (打卡/进度/测算/持仓) with carbon icons - pages/checkin: daily checklist, streak counter, monthly rate - pages/progress: asset snapshot, progress bar to 71万 target - pages/calculator, holdings: placeholder pages (stage 2) - store/checkin.ts + store/progress.ts with pinia persist - vite: host 0.0.0.0 for WSL2→Windows browser access Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user