feat: 增加记录类型弹窗

This commit is contained in:
2026-08-21 15:48:35 +08:00
parent b5217ade67
commit 33192361be
11 changed files with 885 additions and 148 deletions

View File

@@ -0,0 +1,119 @@
<template>
<wd-popup
v-model="recordStore.showBpPopup"
position="bottom"
:safe-area-inset-bottom="true"
:close-on-click-modal="true"
custom-style="border-radius: 32rpx 32rpx 0 0; padding: 40rpx 32rpx 150rpx;"
@close="handeClosePopup"
>
<view class="mb-5 text-center text-base text-gray-700 font-semibold">
🩺 记录血压
</view>
<wd-form
ref="form"
:model="recordStore.bpForm"
layout="horizontal"
title-width="80"
size="large"
border
>
<!-- 收缩压高压 -->
<wd-form-item title="收缩压" prop="systolic">
<view class="flex items-center gap-2">
<wd-input-number
v-model="recordStore.bpForm.systolic"
:min="60"
:max="250"
:step="1"
:decimal-length="0"
/>
<text class="shrink-0 text-sm text-gray-400">mmHg</text>
</view>
</wd-form-item>
<!-- 舒张压低压 -->
<wd-form-item title="舒张压" prop="diastolic">
<view class="flex items-center gap-2">
<wd-input-number
v-model="recordStore.bpForm.diastolic"
:min="40"
:max="180"
:step="1"
:decimal-length="0"
/>
<text class="shrink-0 text-sm text-gray-400">mmHg</text>
</view>
</wd-form-item>
<wd-form-item title="心率" prop="heartRate">
<view class="flex items-center gap-2">
<wd-input-number
v-model="recordStore.bpForm.heartRate"
:min="30"
:max="220"
:step="1"
:decimal-length="0"
/>
<text class="shrink-0 text-sm text-gray-400">bpm</text>
</view>
</wd-form-item>
<!-- 备注 -->
<wd-form-item title="备注" prop="note">
<wd-input
v-model="recordStore.bpForm.note"
:maxlength="20"
show-word-limit
placeholder="请输入备注信息"
/>
</wd-form-item>
<wd-button type="success" class="mt-10 w-full" @click="saveBp">
保存
</wd-button>
</wd-form>
</wd-popup>
</template>
<script setup lang="ts">
import { useRecordStore } from '@/store/record'
const recordStore = useRecordStore()
function handeClosePopup() {
setTimeout(() => {
recordStore.showFab = true
}, 300)
}
function saveBp() {
const { systolic, diastolic, time } = recordStore.bpForm
if (!systolic) {
uni.showToast({ title: '请输入收缩压', icon: 'none' })
return
}
if (!diastolic) {
uni.showToast({ title: '请输入舒张压', icon: 'none' })
return
}
if (systolic <= diastolic) {
uni.showToast({ title: '收缩压应高于舒张压', icon: 'none' })
return
}
if (!time) {
uni.showToast({ title: '请选择记录时间', icon: 'none' })
return
}
// TODO: 接接口保存
console.log('保存血压:', recordStore.bpForm)
uni.showToast({ title: '血压记录已保存 ✅', icon: 'success' })
recordStore.showBpPopup = false
handeClosePopup()
}
</script>

View File

@@ -0,0 +1,114 @@
<template>
<wd-popup
v-model="recordStore.showGlucosePopup"
position="bottom"
:safe-area-inset-bottom="true"
:close-on-click-modal="true"
custom-style="border-radius: 32rpx 32rpx 0 0; padding: 40rpx 32rpx 150rpx;"
@close="handeClosePopup"
>
<view class="mb-5 text-center text-base text-gray-700 font-semibold">
💉 记录血糖
</view>
<wd-form
ref="form"
:model="recordStore.glucoseForm"
layout="horizontal"
title-width="80"
size="large"
border
>
<!-- 血糖值 -->
<wd-form-item title="血糖值" prop="value">
<view class="flex items-center gap-2">
<wd-input-number
v-model="recordStore.glucoseForm.value"
:min="1"
:max="30"
:step="0.1"
:precision="1"
/>
<text class="shrink-0 text-sm text-gray-400">mmol/L</text>
</view>
</wd-form-item>
<!-- 测量时段 -->
<wd-form-item title="时段" prop="period">
<wd-radio-group v-model="recordStore.glucoseForm.period" type="button">
<wd-radio
v-for="item in periodColumns"
:key="item.value"
:value="item.value"
>
{{ item.label }}
</wd-radio>
</wd-radio-group>
</wd-form-item>
<!-- 备注 -->
<wd-form-item title="备注" prop="note">
<wd-input
v-model="recordStore.glucoseForm.note"
:maxlength="20"
show-word-limit
placeholder="请输入备注信息"
/>
</wd-form-item>
<wd-button type="success" class="mt-10 w-full" @click="saveGlucose">
保存
</wd-button>
</wd-form>
</wd-popup>
</template>
<script setup lang="ts">
import { useRecordStore } from '@/store/record'
const recordStore = useRecordStore()
const periodColumns = [
{ label: '空腹', value: '空腹' },
{ label: '餐后1h', value: '餐后1h' },
{ label: '餐后2h', value: '餐后2h' },
{ label: '睡前', value: '睡前' },
{ label: '随机', value: '随机' },
]
function handeClosePopup() {
setTimeout(() => {
recordStore.showFab = true
}, 300)
}
// ========== 保存 ==========
function saveGlucose() {
const { value, period, time } = recordStore.glucoseForm
if (!value) {
uni.showToast({ title: '请输入血糖值', icon: 'none' })
return
}
if (value < 1 || value > 30) {
uni.showToast({ title: '血糖值范围异常,请确认', icon: 'none' })
return
}
if (!period) {
uni.showToast({ title: '请选择测量时段', icon: 'none' })
return
}
if (!time) {
uni.showToast({ title: '请选择记录时间', icon: 'none' })
return
}
// TODO: 接接口保存
console.log('保存血糖:', recordStore.glucoseForm)
uni.showToast({ title: '血糖记录已保存 ✅', icon: 'success' })
recordStore.showGlucosePopup = false
handeClosePopup()
}
</script>

View File

@@ -0,0 +1,115 @@
<template>
<wd-popup
v-model="recordStore.showRecordPopup"
position="bottom"
:safe-area-inset-bottom="true"
:close-on-click-modal="true"
custom-style="border-radius: 32rpx 32rpx 0 0; padding: 40rpx 32rpx 200rpx;"
@close="handeClosePopup"
>
<view class="mb-5 text-center text-base text-gray-700 font-semibold">
选择记录类型
</view>
<view class="grid grid-cols-3 gap-5">
<view
v-for="item in recordTypes"
:key="item.key"
class="flex flex-col items-center gap-2"
@click="onSelect(item)"
>
<view
class="h-14 w-14 flex items-center justify-center rounded-2xl text-xl"
:class="item.bg"
>
<text>{{ item.icon }}</text>
</view>
<text class="text-xs text-gray-600">{{ item.label }}</text>
</view>
</view>
</wd-popup>
</template>
<script lang="ts" setup>
import { useRecordStore } from '@/store/record'
const recordStore = useRecordStore()
const recordTypes = [
{ key: 'weight', icon: '⚖️', label: '体重', bg: 'bg-[#fff3e0]' },
{ key: 'sleep', icon: '😴', label: '睡眠', bg: 'bg-[#e3f2fd]' },
{ key: 'sport', icon: '🏃', label: '运动', bg: 'bg-[#e8f5e9]' },
{ key: 'bp', icon: '❤️', label: '血压', bg: 'bg-[#fce4ec]' },
{ key: 'glucose', icon: '🩸', label: '血糖', bg: 'bg-[#f3e5f5]' },
{ key: 'temp', icon: '🌡️', label: '体温', bg: 'bg-[#fbe9e7]' },
]
function onSelect(item: { key: string, label: string }) {
recordStore.showRecordPopup = false
if (item.key === 'weight') {
recordStore.weightForm.value = 70
recordStore.weightForm.time = Date.now()
recordStore.weightForm.note = ''
setTimeout(() => {
recordStore.showWeightPopup = true
}, 300)
}
else if (item.key === 'sleep') {
recordStore.sleepForm.startTime = Date.now() - 8 * 60 * 60 * 1000
recordStore.sleepForm.endTime = Date.now()
recordStore.sleepForm.time = Date.now()
recordStore.sleepForm.note = ''
setTimeout(() => {
recordStore.showSleepPopup = true
}, 300)
}
else if (item.key === 'sport') {
recordStore.sportForm.type = '跑步'
recordStore.sportForm.duration = 30
recordStore.sportForm.time = Date.now()
recordStore.sportForm.note = ''
setTimeout(() => {
recordStore.showSportPopup = true
}, 300)
}
else if (item.key === 'bp') {
recordStore.bpForm.systolic = 120
recordStore.bpForm.diastolic = 80
recordStore.bpForm.heartRate = 80
recordStore.bpForm.time = Date.now()
recordStore.bpForm.note = ''
setTimeout(() => {
recordStore.showBpPopup = true
}, 300)
}
else if (item.key === 'glucose') {
recordStore.glucoseForm.value = 5.4
recordStore.glucoseForm.period = '空腹'
recordStore.glucoseForm.time = Date.now()
recordStore.glucoseForm.note = ''
setTimeout(() => {
recordStore.showGlucosePopup = true
}, 300)
}
else if (item.key === 'temp') {
recordStore.tempForm.value = 36.5
recordStore.tempForm.location = '腋下'
recordStore.tempForm.time = Date.now()
recordStore.tempForm.note = ''
setTimeout(() => {
recordStore.showTempPopup = true
}, 300)
}
else {
// 其他类型暂时提示
uni.showToast({ title: `暂未开放:${item.label}`, icon: 'none' })
handeClosePopup()
}
}
function handeClosePopup() {
setTimeout(() => {
recordStore.showFab = true
}, 300)
}
</script>

View File

@@ -0,0 +1,146 @@
<template>
<wd-popup
v-model="recordStore.showSleepPopup"
position="bottom"
:safe-area-inset-bottom="true"
:close-on-click-modal="true"
custom-style="border-radius: 32rpx 32rpx 0 0; padding: 40rpx 32rpx 150rpx;"
@close="handeClosePopup"
>
<view class="mb-5 text-center text-base text-gray-700 font-semibold">
💤 记录睡眠
</view>
<wd-form
ref="form"
:model="recordStore.sleepForm"
layout="horizontal"
title-width="80"
size="large"
border
>
<wd-form-item
title="开始"
prop="startTime"
is-link
:value="formatTime(recordStore.sleepForm.startTime)"
placeholder="请选择开始时间"
@click="showStartPicker = true"
/>
<wd-form-item
title="结束"
prop="endTime"
is-link
:value="formatTime(recordStore.sleepForm.endTime)"
placeholder="请选择结束时间"
@click="showEndPicker = true"
/>
<wd-form-item title="时长">
<view class="py-1 text-gray-800">
{{ sleepDuration }}
</view>
</wd-form-item>
<wd-form-item title="备注" prop="note">
<wd-input
v-model="recordStore.sleepForm.note"
:maxlength="20"
show-word-limit
placeholder="请输入备注信息"
/>
</wd-form-item>
<wd-button type="success" class="mt-10 w-full" @click="saveSleep">
保存
</wd-button>
</wd-form>
</wd-popup>
<!-- 开始时间选择器 -->
<wd-datetime-picker
v-model="recordStore.sleepForm.startTime"
v-model:visible="showStartPicker"
placeholder="请选择开始时间"
/>
<!-- 结束时间选择器 -->
<wd-datetime-picker
v-model="recordStore.sleepForm.endTime"
v-model:visible="showEndPicker"
placeholder="请选择结束时间"
/>
</template>
<script setup lang="ts">
import { useRecordStore } from '@/store/record'
import { formatTime } from '@/utils'
import { computed, ref } from 'vue'
const recordStore = useRecordStore()
const showStartPicker = ref(false)
const showEndPicker = ref(false)
const sleepDuration = computed(() => {
const start = recordStore.sleepForm.startTime
const end = recordStore.sleepForm.endTime
if (!start || !end)
return '请选择开始和结束时间'
const diffMs = new Date(end).getTime() - new Date(start).getTime()
if (diffMs <= 0)
return '结束时间需晚于开始时间'
const totalMinutes = Math.floor(diffMs / 60000)
const hours = Math.floor(totalMinutes / 60)
const minutes = totalMinutes % 60
if (hours > 0 && minutes > 0)
return `${hours}小时${minutes}分钟`
if (hours > 0)
return `${hours}小时`
return `${minutes}分钟`
})
function handeClosePopup() {
setTimeout(() => {
recordStore.showFab = true
}, 300)
}
function saveSleep() {
const { startTime, endTime, time, note } = recordStore.sleepForm
if (!startTime) {
uni.showToast({ title: '请选择开始时间', icon: 'none' })
return
}
if (!endTime) {
uni.showToast({ title: '请选择结束时间', icon: 'none' })
return
}
if (new Date(endTime).getTime() <= new Date(startTime).getTime()) {
uni.showToast({ title: '结束时间需晚于开始时间', icon: 'none' })
return
}
if (!time) {
uni.showToast({ title: '请选择记录时间', icon: 'none' })
return
}
// TODO: 接接口保存
console.log('保存睡眠:', {
...recordStore.sleepForm,
duration: sleepDuration.value,
})
uni.showToast({ title: '睡眠记录已保存 ✅', icon: 'success' })
recordStore.showSleepPopup = false
handeClosePopup()
}
</script>

View File

@@ -0,0 +1,109 @@
<template>
<wd-popup
v-model="recordStore.showSportPopup"
position="bottom"
:safe-area-inset-bottom="true"
:close-on-click-modal="true"
custom-style="border-radius: 32rpx 32rpx 0 0; padding: 40rpx 32rpx 150rpx;"
@close="handeClosePopup"
>
<view class="mb-5 text-center text-base text-gray-700 font-semibold">
🏃 记录运动
</view>
<wd-form
ref="form"
:model="recordStore.sportForm"
layout="horizontal"
title-width="80"
size="large"
border
>
<!-- 运动类型 -->
<wd-form-item title="类型" prop="type">
<wd-radio-group v-model="recordStore.sportForm.type" type="button">
<wd-radio
v-for="item in sportTypeColumns"
:key="item.value"
:value="item.value"
>
{{ item.label }}
</wd-radio>
</wd-radio-group>
</wd-form-item>
<!-- 运动时长 -->
<wd-form-item title="时长" prop="duration">
<view class="flex items-center gap-2">
<wd-input-number
v-model="recordStore.sportForm.duration"
:min="1"
:max="600"
:step="5"
:decimal-length="0"
/>
<text class="shrink-0 text-sm text-gray-400">分钟</text>
</view>
</wd-form-item>
<wd-form-item title="备注" prop="note">
<wd-input
v-model="recordStore.sportForm.note"
:maxlength="20"
show-word-limit
placeholder="请输入备注信息"
/>
</wd-form-item>
<wd-button type="success" class="mt-10 w-full" @click="saveSport">
保存
</wd-button>
</wd-form>
</wd-popup>
</template>
<script setup lang="ts">
import { useRecordStore } from '@/store/record'
const recordStore = useRecordStore()
const sportTypeColumns = [
{ label: '🏃 跑步', value: '跑步' },
{ label: '🏊 游泳', value: '游泳' },
{ label: '🏋️ 力量', value: '力量' },
{ label: '⚽ 球类', value: '球类' },
{ label: '🏊 跳绳', value: '跳绳' },
{ label: '其他', value: '其他' },
]
function handeClosePopup() {
setTimeout(() => {
recordStore.showFab = true
}, 300)
}
function saveSport() {
const { type, duration, time } = recordStore.sportForm
if (!type) {
uni.showToast({ title: '请选择运动类型', icon: 'none' })
return
}
if (!duration || duration <= 0) {
uni.showToast({ title: '请输入运动时长', icon: 'none' })
return
}
if (!time) {
uni.showToast({ title: '请选择记录时间', icon: 'none' })
return
}
// TODO: 接接口保存
console.log('保存运动:', recordStore.sportForm)
uni.showToast({ title: '运动记录已保存 ✅', icon: 'success' })
recordStore.showSportPopup = false
handeClosePopup()
}
</script>

View File

@@ -0,0 +1,112 @@
<template>
<wd-popup
v-model="recordStore.showTempPopup"
position="bottom"
:safe-area-inset-bottom="true"
:close-on-click-modal="true"
custom-style="border-radius: 32rpx 32rpx 0 0; padding: 40rpx 32rpx 150rpx;"
@close="handeClosePopup"
>
<view class="mb-5 text-center text-base text-gray-700 font-semibold">
🌡 记录体温
</view>
<wd-form
ref="form"
:model="recordStore.tempForm"
layout="horizontal"
title-width="80"
size="large"
border
>
<!-- 体温值 -->
<wd-form-item title="体温" prop="value">
<view class="flex items-center gap-2">
<wd-input-number
v-model="recordStore.tempForm.value"
:min="35"
:max="42"
:step="0.1"
:precision="1"
/>
<text class="shrink-0 text-sm text-gray-400"></text>
</view>
</wd-form-item>
<!-- 测量部位 -->
<wd-form-item title="部位" prop="location">
<wd-radio-group v-model="recordStore.tempForm.location" type="button">
<wd-radio
v-for="item in locationColumns"
:key="item.value"
:value="item.value"
>
{{ item.label }}
</wd-radio>
</wd-radio-group>
</wd-form-item>
<!-- 备注 -->
<wd-form-item title="备注" prop="note">
<wd-input
v-model="recordStore.tempForm.note"
:maxlength="20"
show-word-limit
placeholder="请输入备注信息"
/>
</wd-form-item>
<wd-button type="success" class="mt-10 w-full" @click="saveTemp">
保存
</wd-button>
</wd-form>
</wd-popup>
</template>
<script setup lang="ts">
import { useRecordStore } from '@/store/record'
const recordStore = useRecordStore()
const locationColumns = [
{ label: '腋下', value: '腋下' },
{ label: '口腔', value: '口腔' },
{ label: '耳温', value: '耳温' },
{ label: '额温', value: '额温' },
]
function handeClosePopup() {
setTimeout(() => {
recordStore.showFab = true
}, 300)
}
function saveTemp() {
const { value, location, time } = recordStore.tempForm
if (!value) {
uni.showToast({ title: '请输入体温', icon: 'none' })
return
}
if (value < 35 || value > 42) {
uni.showToast({ title: '体温范围异常,请确认', icon: 'none' })
return
}
if (!location) {
uni.showToast({ title: '请选择测量部位', icon: 'none' })
return
}
if (!time) {
uni.showToast({ title: '请选择记录时间', icon: 'none' })
return
}
// TODO: 接接口保存
console.log('保存体温:', recordStore.tempForm)
uni.showToast({ title: '体温记录已保存 ✅', icon: 'success' })
recordStore.showTempPopup = false
handeClosePopup()
}
</script>

View File

@@ -0,0 +1,69 @@
<template>
<wd-popup
v-model="recordStore.showWeightPopup"
position="bottom"
:safe-area-inset-bottom="true"
:close-on-click-modal="true"
custom-style="border-radius: 32rpx 32rpx 0 0; padding: 40rpx 32rpx 150rpx;"
@close="handeClosePopup"
>
<view class="mb-5 text-center text-base text-gray-700 font-semibold">
记录体重
</view>
<wd-form ref="form" :model="recordStore.weightForm" layout="horizontal" title-width="80" size="large" border>
<wd-form-item title="体重">
<view class="flex items-center gap-2">
<wd-input-number v-model="recordStore.weightForm.value" :min="1" :max="200" />
<text class="shrink-0 text-sm text-gray-400">Kg</text>
</view>
</wd-form-item>
<wd-form-item title="备注" prop="budget">
<wd-input
v-model="recordStore.weightForm.note"
:maxlength="20"
show-word-limit
placeholder="请输入备注信息"
/>
</wd-form-item>
<wd-button type="success" class="mt-10 w-full" @click="saveWeight">
保存
</wd-button>
</wd-form>
</wd-popup>
</template>
<script setup lang="ts">
import { useRecordStore } from '@/store/record'
const recordStore = useRecordStore()
function handeClosePopup() {
setTimeout(() => {
recordStore.showFab = true
}, 300)
}
function saveWeight() {
if (!recordStore.weightForm) {
uni.showToast({ title: '请输入体重', icon: 'none' })
}
else {
// TODO: 这里接接口保存
console.log('保存体重:', recordStore.weightForm)
uni.showToast({ title: '体重已保存 ✅', icon: 'success' })
recordStore.showWeightPopup = false
// 保存后刷新首页概览TODO: 接真实数据后打开)
// overviewItems[0].value = weightForm.value + 'kg'
}
handeClosePopup()
}
</script>
<style scoped lang="scss">
</style>

View File

@@ -64,85 +64,21 @@
</view>
</wd-card>
<wd-popup
v-model="showPopup"
position="bottom"
:safe-area-inset-bottom="true"
:close-on-click-modal="true"
custom-style="border-radius: 32rpx 32rpx 0 0; padding: 40rpx 32rpx 200rpx;"
@close="handeClosePopup"
>
<view class="mb-5 text-center text-base text-gray-700 font-semibold">
选择记录类型
</view>
<view class="grid grid-cols-4 gap-5">
<view
v-for="item in recordTypes"
:key="item.key"
class="flex flex-col items-center gap-2"
@click="onSelect(item)"
>
<view
class="h-14 w-14 flex items-center justify-center rounded-2xl text-xl"
:class="item.bg"
>
<text>{{ item.icon }}</text>
</view>
<text class="text-xs text-gray-600">{{ item.label }}</text>
</view>
</view>
</wd-popup>
<record-popup />
<wd-popup
v-model="showWeightPopup"
position="bottom"
:safe-area-inset-bottom="true"
:close-on-click-modal="true"
custom-style="border-radius: 32rpx 32rpx 0 0; padding: 40rpx 32rpx 150rpx;"
@close="handeClosePopup"
>
<view class="mb-5 text-center text-base text-gray-700 font-semibold">
记录体重Kg
</view>
<weight-popup />
<sleep-popup />
<sport-popup />
<bp-popup />
<glucose-popup />
<temp-popup />
<wd-form ref="form" :model="weightForm" layout="horizontal" title-width="60" size="large" border>
<wd-form-item title="体重">
<wd-slider
ref="sliderRef" v-model="weightForm.value"
:marks="[40, 60, 80, 100]"
:min="40" :max="100"
/>
</wd-form-item>
<wd-form-item
title="时间"
prop="time"
is-link
:value="formatTime(weightForm.time)"
placeholder="请选择时间"
@click="showTimePicker = true"
/>
<wd-form-item title="备注" prop="budget">
<wd-input
v-model="weightForm.note"
:maxlength="20"
show-word-limit
placeholder="请输入备注信息"
/>
</wd-form-item>
<wd-button type="success" class="mt-10 w-full" @click="saveWeight">
保存
</wd-button>
</wd-form>
</wd-popup>
<wd-datetime-picker v-model="weightForm.time" v-model:visible="showTimePicker" placeholder="请选择时间" />
<wd-fab v-if="showFab" type="success" :gap="{ bottom: 60 }" :expandable="false" @click="handelFabClick" />
<wd-fab v-if="recordStore.showFab" type="success" :gap="{ bottom: 60 }" :expandable="false" @click="handelFabClick" />
</view>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { useRecordStore } from '@/store/record'
defineOptions({
name: 'Home',
@@ -155,10 +91,7 @@ definePage({
},
})
const showFab = ref(true)
const showPopup = ref(false)
const showWeightPopup = ref(false)
const showTimePicker = ref(false)
const recordStore = useRecordStore()
const greeting = '下午好,小明 👋'
const today = '8月19日 周三'
@@ -177,73 +110,8 @@ const plans = [
{ icon: '🛏️', label: '23:00 前入睡', done: false },
]
const recordTypes = [
{ key: 'weight', icon: '⚖️', label: '体重', bg: 'bg-[#fff3e0]' },
{ key: 'sleep', icon: '😴', label: '睡眠', bg: 'bg-[#e3f2fd]' },
{ key: 'exercise', icon: '🏃', label: '运动', bg: 'bg-[#e8f5e9]' },
{ key: 'bp', icon: '❤️', label: '血压', bg: 'bg-[#fce4ec]' },
{ key: 'glucose', icon: '🩸', label: '血糖', bg: 'bg-[#f3e5f5]' },
{ key: 'hr', icon: '💓', label: '心率', bg: 'bg-[#ffebee]' },
{ key: 'temp', icon: '🌡️', label: '体温', bg: 'bg-[#fbe9e7]' },
]
const weightForm = reactive({
value: 70,
time: '' as number | string,
note: '',
})
function handelFabClick() {
showPopup.value = true
showFab.value = false
}
function onSelect(item: { key: string, label: string }) {
showPopup.value = false
if (item.key === 'weight') {
weightForm.value = 70
weightForm.time = Date.now()
weightForm.note = ''
setTimeout(() => {
showWeightPopup.value = true
}, 300)
}
else {
// 其他类型暂时提示
uni.showToast({ title: `暂未开放:${item.label}`, icon: 'none' })
}
}
function formatTime(ts: string | number) {
if (!ts)
return ''
const d = new Date(ts)
const pad = (n: number) => String(n).padStart(2, '0')
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`
}
function handeClosePopup() {
setTimeout(() => {
showFab.value = true
}, 300)
}
function saveWeight() {
if (!weightForm.value) {
uni.showToast({ title: '请输入体重', icon: 'none' })
}
else {
// TODO: 这里接接口保存
console.log('保存体重:', weightForm.value, 'kg', weightForm.note)
uni.showToast({ title: '体重已保存 ✅', icon: 'success' })
showWeightPopup.value = false
// 保存后刷新首页概览TODO: 接真实数据后打开)
// overviewItems[0].value = weightForm.value + 'kg'
}
handeClosePopup()
recordStore.showRecordPopup = true
recordStore.showFab = false
}
</script>

View File

@@ -1,8 +1,6 @@
<template>
<!-- 页面容器 -->
<view class="min-h-screen bg-[#f2f4f3]">
<!-- 顶部日期栏左右箭头 + 日期居中 + 回到今天 -->
<view class="sticky top-0 z-10 bg-white p-2 shadow-sm">
<view class="sticky top-0 z-10 bg-white p-2">
<view class="flex items-center justify-evenly">
<wd-button icon="caret-left" type="success" :round="true" size="small" @click="changeDay(-1)" />
<view class="flex flex-col items-center" @click="openDatePicker">
@@ -17,7 +15,7 @@
</view>
<!-- 时间轴区域 -->
<view class="px-5 py-6">
<view class="px-5 py-2">
<!-- 时间轴容器 -->
<view class="relative pl-6">
<view

79
src/store/record.ts Normal file
View File

@@ -0,0 +1,79 @@
import { defineStore } from 'pinia'
export const useRecordStore = defineStore('record', {
state: () => ({
list: [] as any[],
loading: false,
showFab: true,
showRecordPopup: false,
showWeightPopup: false,
weightForm: {
value: 1,
note: '',
time: '' as number | string,
},
showSleepPopup: false,
sleepForm: {
startTime: '' as number | string,
endTime: '' as number | string,
note: '',
time: '' as number | string,
},
showSportPopup: false,
sportForm: {
type: '',
duration: 0,
note: '',
time: '' as number | string,
},
showBpPopup: false,
bpForm: {
systolic: 0,
diastolic: 0,
heartRate: 0,
time: Date.now(),
note: '',
},
showGlucosePopup: false,
glucoseForm: {
value: 0,
period: '' as string,
time: Date.now(),
note: '',
},
showTempPopup: false,
tempForm: {
value: 36.5,
location: '' as string,
time: Date.now(),
note: '',
},
}),
actions: {
setLoading(val: boolean) {
this.loading = val
},
async fetchList() {
this.loading = true
try {
const res = await fetch('/api/record/list')
this.list = await res.json()
}
finally {
this.loading = false
}
},
addRecord(item: any) {
this.list.push(item)
},
removeRecord(id: string) {
this.list = this.list.filter(item => item.id !== id)
},
reset() {
},
},
})

View File

@@ -149,3 +149,11 @@ export const isDoubleTokenMode = import.meta.env.VITE_AUTH_MODE === 'double'
* 通常为 /pages/index/index
*/
export const HOME_PAGE = `/${(pages as PageMetaDatum[]).find(page => page.type === 'home')?.path || (pages as PageMetaDatum[])[0].path}`
export function formatTime(ts: string | number) {
if (!ts)
return ''
const d = new Date(ts)
const pad = (n: number) => String(n).padStart(2, '0')
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`
}