feat: v1.3 交互增强

新增功能:
- 账单左滑删除(替代长按,更符合移动端习惯)
- 输入震动反馈(Numpad 按键时调用 uni.vibrateShort)
- 保存成功动画(Checkmark 弹出动画)
- 分类图标滚动到选中项(编辑记录时自动定位)

组件更新:
- TransactionItem 支持左滑露出删除按钮
- Numpad 添加震动反馈
- SaveSuccess 新增保存成功动画组件
This commit is contained in:
2026-05-29 16:35:31 +08:00
parent 7f8b301f95
commit 35bfe8293a
5 changed files with 196 additions and 16 deletions

View File

@@ -22,9 +22,9 @@
<text class="digits">{{ displayAmount }}</text>
</view>
<scroll-view class="category-scroll" scroll-y>
<scroll-view class="category-scroll" scroll-y :scroll-into-view="scrollToCat">
<view class="category-grid">
<view v-for="cat in currentCategories" :key="cat.id" class="cat-item" @tap="selectedCat = cat.id">
<view v-for="cat in currentCategories" :key="cat.id" :id="'cat-' + cat.id" class="cat-item" @tap="selectedCat = cat.id">
<CategoryIcon :label="cat.name[0]" :color="cat.color" :bg-color="cat.color + '15'" size="md" :selected="selectedCat === cat.id" />
<text class="cat-name" :class="{ active: selectedCat === cat.id }">{{ cat.name }}</text>
</view>
@@ -45,6 +45,8 @@
</view>
<Numpad @input="onInput" @delete="onDelete" @confirm="save" />
<SaveSuccess v-model:visible="showSuccess" :text="editId ? '修改成功' : '记账成功'" />
</view>
</template>
@@ -55,6 +57,7 @@ import { useTransactionStore } from '@/stores/transaction'
import Numpad from '@/components/Numpad/Numpad.vue'
import CategoryIcon from '@/components/CategoryIcon/CategoryIcon.vue'
import SvgIcon from '@/components/SvgIcon/SvgIcon.vue'
import SaveSuccess from '@/components/SaveSuccess/SaveSuccess.vue'
import { statusBarHeight } from '@/utils/system'
const catStore = useCategoryStore()
@@ -67,6 +70,8 @@ const note = ref('')
const selectedDate = ref(new Date().toISOString().slice(0, 10))
const saving = ref(false)
const editId = ref<number | null>(null)
const showSuccess = ref(false)
const scrollToCat = ref('')
const todayStr = new Date().toISOString().slice(0, 10)
// Remember last selected category per type
const lastCatByType: Record<string, number | null> = { expense: null, income: null }
@@ -124,6 +129,8 @@ onMounted(async () => {
lastCatByType[existing.type] = existing.category_id
note.value = existing.note || ''
selectedDate.value = existing.date.slice(0, 10)
// Scroll to selected category
setTimeout(() => { scrollToCat.value = 'cat-' + existing.category_id }, 100)
} else {
uni.showToast({ title: '记录不存在', icon: 'none' })
setTimeout(() => uni.navigateBack(), 1500)
@@ -188,12 +195,11 @@ async function save() {
}
if (editId.value) {
await txStore.updateTransaction(editId.value, data)
uni.showToast({ title: '修改成功', icon: 'success' })
} else {
await txStore.addTransaction(data)
uni.showToast({ title: '记账成功', icon: 'success' })
}
setTimeout(() => uni.navigateBack(), 1500)
showSuccess.value = true
setTimeout(() => uni.navigateBack(), 2500)
} catch (e) {
uni.showToast({ title: '保存失败', icon: 'none' })
} finally {