优化:用户信息的获取
This commit is contained in:
parent
a7bbc509da
commit
41b349fd09
@ -1,11 +1,13 @@
|
||||
---
|
||||
description: 修改或新增 src/ 代码时同步更新 docs/ 技术文档
|
||||
description: 修改或新增 src/ 代码时,必须在同一轮对话中同步更新 docs/ 技术文档
|
||||
globs: src/**/*
|
||||
alwaysApply: false
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# 文档同步规则
|
||||
|
||||
**修改 src/ 后必做**:在同一轮对话中,立即更新 `docs/` 中对应的技术文档。不要等到用户提醒。
|
||||
|
||||
当你在 `src/` 下**新增或修改**任何文件时,必须同步更新 `docs/` 中对应的技术文档。
|
||||
|
||||
## 文件映射关系
|
||||
@ -35,3 +37,10 @@ API 与组件文档需补充类型说明、Props、Events 等。
|
||||
## 示例
|
||||
|
||||
修改 `src/api/event.ts` 后,需更新 `docs/api/event.md`;新增 `src/api/order.ts` 时,需新建 `docs/api/order.md`。
|
||||
|
||||
## 修改后检查清单
|
||||
|
||||
修改 `src/` 内任何文件后,在同一轮回复中完成:
|
||||
|
||||
- [ ] 根据上表找到对应的 `docs/` 路径
|
||||
- [ ] 更新或新建该文档,反映本次代码变更
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
|
||||
- Buy/Sell Tab 切换
|
||||
- Market/Limit 类型、Merge/Split 菜单
|
||||
- **Buy 模式 Amount 区**:无论余额是否充足,均显示 Amount 标签、Balance、金额输入、+$1/+$20/+$100/Max 快捷按钮(桌面端、嵌入弹窗、移动端弹窗一致)
|
||||
- 余额不足时 Buy 显示 Deposit 按钮
|
||||
- 25%/50%/Max 快捷份额
|
||||
- 调用 market API 下单、Split、Merge
|
||||
|
||||
@ -8,9 +8,10 @@
|
||||
|
||||
## 核心能力
|
||||
|
||||
- 顶部导航栏:返回、PolyMarket 标题、Login 或余额+头像菜单
|
||||
- 顶部导航栏:返回、PolyMarket 标题、Login 或余额+用户名+头像菜单
|
||||
- 登录态:`userStore.isLoggedIn` 控制展示
|
||||
- 挂载时:若已登录,拉取用户信息与余额
|
||||
- 用户名:`nickName` 或 `userName` 显示在头像左侧(有值时)
|
||||
- 挂载时与 `isLoggedIn` 变为 true 时:拉取用户信息与余额(`router.isReady()` + `nextTick` 后执行),确保钱包登录、刷新页面后头像和用户名正确显示
|
||||
- keep-alive:`include="['Home']"` 缓存首页
|
||||
|
||||
## 扩展方式
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
- `logout`:清空并清除持久化
|
||||
- `getAuthHeaders`:返回 `{ 'x-token', 'x-user-id' }`,未登录时返回 `undefined`
|
||||
- `fetchUserInfo`、`fetchUsdcBalance`:拉取并更新用户信息与余额
|
||||
- `fetchUserInfo` 兼容多种 API 字段名:`userName`/`username`、`nickName`/`nickname`、`headerImg`/`avatar`/`avatarUrl`;支持 `data` 直接为用户对象或 `data.user` 嵌套结构
|
||||
|
||||
## 使用方式
|
||||
|
||||
@ -41,3 +42,7 @@ await userStore.fetchUsdcBalance()
|
||||
1. **多端登录**:扩展 `setUser` 支持多设备 token 管理
|
||||
2. **Token 刷新**:在 `getAuthHeaders` 或请求拦截器中加入 refresh 逻辑
|
||||
3. **登出回调**:在 `logout` 中增加清理逻辑(如取消订阅、重置其他 store)
|
||||
|
||||
## 登录后刷新用户信息
|
||||
|
||||
钱包登录(Login.vue)成功后需调用 `fetchUserInfo()` 以获取完整用户信息(头像、昵称)。App.vue 在 `onMounted` 与 `watch(isLoggedIn)` 时也会调用,确保自动登录或刷新页面后能正确显示。
|
||||
|
||||
43
src/App.vue
43
src/App.vue
@ -1,21 +1,35 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { computed, onMounted, watch, nextTick } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useUserStore } from './stores/user'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const currentRoute = computed(() => {
|
||||
return route.path
|
||||
})
|
||||
const currentRoute = computed(() => route.path)
|
||||
const displayName = computed(
|
||||
() => userStore.user?.nickName || userStore.user?.userName || ''
|
||||
)
|
||||
|
||||
async function refreshUserData() {
|
||||
if (!userStore.isLoggedIn) return
|
||||
await router.isReady()
|
||||
await nextTick()
|
||||
await userStore.fetchUserInfo()
|
||||
await userStore.fetchUsdcBalance()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (userStore.isLoggedIn) {
|
||||
userStore.fetchUserInfo()
|
||||
userStore.fetchUsdcBalance()
|
||||
}
|
||||
refreshUserData()
|
||||
})
|
||||
watch(
|
||||
() => userStore.isLoggedIn,
|
||||
(loggedIn) => {
|
||||
if (loggedIn) refreshUserData()
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -51,6 +65,7 @@ onMounted(() => {
|
||||
>
|
||||
<span class="balance-text">${{ userStore.balance }}</span>
|
||||
</v-btn>
|
||||
<span v-if="displayName" class="header-username">{{ displayName }}</span>
|
||||
<v-menu location="bottom" :close-on-content-click="false">
|
||||
<template #activator="{ props }">
|
||||
<v-btn v-bind="props" icon variant="text" class="avatar-btn">
|
||||
@ -92,6 +107,16 @@ onMounted(() => {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.header-username {
|
||||
font-size: 0.9rem;
|
||||
color: rgba(255, 255, 255, 0.95);
|
||||
margin-right: 4px;
|
||||
max-width: 120px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.balance-text {
|
||||
font-weight: 500;
|
||||
font-size: 0.95rem;
|
||||
|
||||
@ -56,6 +56,24 @@
|
||||
</v-btn>
|
||||
</div>
|
||||
|
||||
<!-- Buy Market: Amount 区(余额充足时也显示) -->
|
||||
<template v-if="activeTab === 'buy'">
|
||||
<div class="input-group">
|
||||
<div class="amount-header">
|
||||
<div>
|
||||
<span class="label amount-label">Amount</span>
|
||||
<span class="balance-label">Balance ${{ balance.toFixed(2) }}</span>
|
||||
</div>
|
||||
<div class="amount-value">${{ amount.toFixed(2) }}</div>
|
||||
</div>
|
||||
<div class="amount-buttons">
|
||||
<v-btn class="amount-btn" @click="adjustAmount(1)">+$1</v-btn>
|
||||
<v-btn class="amount-btn" @click="adjustAmount(20)">+$20</v-btn>
|
||||
<v-btn class="amount-btn" @click="adjustAmount(100)">+$100</v-btn>
|
||||
<v-btn class="amount-btn" @click="setMaxAmount">Max</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- Sell Market: Shares input + 25%/50%/Max -->
|
||||
<template v-if="activeTab === 'sell'">
|
||||
<div class="input-group shares-group">
|
||||
@ -441,6 +459,24 @@
|
||||
>{{ noLabel }} {{ noPriceCents }}¢</v-btn
|
||||
>
|
||||
</div>
|
||||
<!-- Buy Market: Amount 区(余额充足时也显示) -->
|
||||
<template v-if="activeTab === 'buy'">
|
||||
<div class="input-group">
|
||||
<div class="amount-header">
|
||||
<div>
|
||||
<span class="label amount-label">Amount</span>
|
||||
<span class="balance-label">Balance ${{ balance.toFixed(2) }}</span>
|
||||
</div>
|
||||
<div class="amount-value">${{ amount.toFixed(2) }}</div>
|
||||
</div>
|
||||
<div class="amount-buttons">
|
||||
<v-btn class="amount-btn" @click="adjustAmount(1)">+$1</v-btn>
|
||||
<v-btn class="amount-btn" @click="adjustAmount(20)">+$20</v-btn>
|
||||
<v-btn class="amount-btn" @click="adjustAmount(100)">+$100</v-btn>
|
||||
<v-btn class="amount-btn" @click="setMaxAmount">Max</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- Sell Market: Shares input + 25%/50%/Max -->
|
||||
<template v-if="activeTab === 'sell'">
|
||||
<div class="input-group shares-group">
|
||||
@ -809,6 +845,24 @@
|
||||
>{{ noLabel }} {{ noPriceCents }}¢</v-btn
|
||||
>
|
||||
</div>
|
||||
<!-- Buy Market: Amount 区(余额充足时也显示) -->
|
||||
<template v-if="activeTab === 'buy'">
|
||||
<div class="input-group">
|
||||
<div class="amount-header">
|
||||
<div>
|
||||
<span class="label amount-label">Amount</span>
|
||||
<span class="balance-label">Balance ${{ balance.toFixed(2) }}</span>
|
||||
</div>
|
||||
<div class="amount-value">${{ amount.toFixed(2) }}</div>
|
||||
</div>
|
||||
<div class="amount-buttons">
|
||||
<v-btn class="amount-btn" @click="adjustAmount(1)">+$1</v-btn>
|
||||
<v-btn class="amount-btn" @click="adjustAmount(20)">+$20</v-btn>
|
||||
<v-btn class="amount-btn" @click="adjustAmount(100)">+$100</v-btn>
|
||||
<v-btn class="amount-btn" @click="setMaxAmount">Max</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- Sell Market: Shares input + 25%/50%/Max -->
|
||||
<template v-if="activeTab === 'sell'">
|
||||
<div class="input-group shares-group">
|
||||
|
||||
@ -96,14 +96,15 @@ export const useUserStore = defineStore('user', () => {
|
||||
try {
|
||||
const res = await getUserInfo(headers)
|
||||
console.log('[fetchUserInfo] 接口响应:', JSON.stringify(res, null, 2))
|
||||
if ((res.code === 0 || res.code === 200) && res.data) {
|
||||
const u = res.data
|
||||
const data = res.data as Record<string, unknown> | undefined
|
||||
const u = (data?.user ?? data) as Record<string, unknown>
|
||||
if ((res.code === 0 || res.code === 200) && u) {
|
||||
user.value = {
|
||||
id: u.ID,
|
||||
ID: u.ID,
|
||||
userName: u.userName,
|
||||
nickName: u.nickName,
|
||||
headerImg: u.headerImg,
|
||||
id: u.ID as number | string | undefined,
|
||||
ID: u.ID as number | undefined,
|
||||
userName: (u.userName ?? u.username) as string | undefined,
|
||||
nickName: (u.nickName ?? u.nickname) as string | undefined,
|
||||
headerImg: (u.headerImg ?? u.avatar ?? u.avatarUrl) as string | undefined,
|
||||
...u,
|
||||
}
|
||||
if (token.value && user.value) saveToStorage(token.value, user.value)
|
||||
|
||||
@ -184,7 +184,8 @@ const connectWithWallet = async () => {
|
||||
const { token, user } = loginData.data
|
||||
console.log('[walletLogin] 存入 store 的 user:', JSON.stringify(user, null, 2))
|
||||
userStore.setUser({ token, user })
|
||||
userStore.fetchUsdcBalance()
|
||||
await userStore.fetchUserInfo()
|
||||
await userStore.fetchUsdcBalance()
|
||||
}
|
||||
|
||||
router.push('/')
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user