Files
xiaocai/client/src/stores/user.ts
wangxiaogang e110cd5c5d fix: 全面修复 22 项问题
严重 Bug:
- NaN 金额校验绕过(add 页面 parseFloat 空字符串)
- 4 个页面补充 waitForReady(add/budget/category-manage/group-manage)
- 导出 Loading 遮罩不消失(profile exportData 缺 hideLoading)
- Store 吞掉请求错误不 re-throw(transaction/stats/budget/user)
- 分类排序 SQL 拼接改参数化查询(category PUT /sort)
- 备份接口添加管理员权限检查(backup requireAdmin)

中等问题:
- 群组加入竞态条件改为 INSERT IGNORE
- 统计页切月/切Tab添加 loadSeq 防竞态
- stats store 补全 loading 状态 + Overview 初始值补全 7 字段
- 保存成功后返回不再弹「放弃修改」确认框
- 群组管理创建/加入添加 saving 双重提交保护
- 预算页添加 onShow 刷新
- 服务端输入校验(name/color/invite_code/微信code)

UI/样式:
- 触摸目标: bell/nav-back/nav-save→88rpx, avatar-badge→64rpx, action-btn→80rpx
- :active 反馈: bell/profile-card/identity-card/id-manage/arrow/action-btn/group-btn/cat-info
- 内联样式改动态绑定(4处 spacer 使用 capsuleRight)
- FAB 文字+改用 Icon 组件
- prefers-reduced-motion 动画降级(Skeleton/profile/budget/add)
- 胶囊适配(add/category-manage/group-manage)
- CategoryIcon !important 改为 iconStyle 计算属性

文档:
- CLAUDE.md 补充 SaveSuccess/ChartWrapper 组件 + category/budget/index API
2026-06-04 17:06:02 +08:00

54 lines
1.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import * as api from '@/api/user'
import { API_BASE } from '@/config'
export const useUserStore = defineStore('user', () => {
const userInfo = ref<api.UserInfo | null>(null)
const loading = ref(false)
const nickname = computed(() => {
return userInfo.value?.nickname || uni.getStorageSync('xc:nickname') || '小菜'
})
const avatarUrl = computed(() => {
const filename = userInfo.value?.avatar_url || uni.getStorageSync('xc:avatar_url') || ''
if (!filename) return ''
// 已是完整 URLhttp/blob直接返回
if (filename.startsWith('http') || filename.startsWith('blob:')) return filename
// 拼接API_BASE + /user/avatar/ + 文件名
return `${API_BASE}/user/avatar/${filename}`
})
async function fetchUserInfo() {
loading.value = true
try {
userInfo.value = await api.getUserInfo()
if (userInfo.value) {
uni.setStorageSync('xc:nickname', userInfo.value.nickname)
uni.setStorageSync('xc:avatar_url', userInfo.value.avatar_url)
}
} catch (e) {
console.error('[UserStore] fetchUserInfo error:', e)
throw e
} finally {
loading.value = false
}
}
async function updateProfile(nickname: string) {
await api.updateNickname(nickname)
if (userInfo.value) userInfo.value.nickname = nickname
uni.setStorageSync('xc:nickname', nickname)
}
async function uploadAvatar(filePath: string) {
const result = await api.uploadAvatar(filePath)
if (userInfo.value) userInfo.value.avatar_url = result.avatar_url
uni.setStorageSync('xc:avatar_url', result.avatar_url)
return avatarUrl.value
}
return { userInfo, loading, nickname, avatarUrl, fetchUserInfo, updateProfile, uploadAvatar }
})