feat: 支持从小程序获取微信头像和昵称同步到 H5
- 后端 UserProfileUpdate 新增 avatar_url 字段 - LoginPage 检测 URL 参数 name/avatar 并调用 updateUserProfile - ProfilePage 头像卡片显示真实头像(有 avatar_url 时) - ProfilePage 增加 基本信息-姓名 编辑字段
This commit is contained in:
@@ -27,6 +27,7 @@ class UserProfileUpdate(BaseModel):
|
||||
multiple_pregnancy: Optional[str] = None
|
||||
pregnancy_count: Optional[int] = None
|
||||
emergency_contact: Optional[EmergencyContactSchema] = None
|
||||
avatar_url: Optional[str] = None
|
||||
|
||||
|
||||
class OnboardingRequest(BaseModel):
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useNavigate } from "react-router";
|
||||
import { motion } from "motion/react";
|
||||
import { Heart } from "lucide-react";
|
||||
import { useUser } from "../context/UserContext";
|
||||
import { devLogin, createDummyToken } from "../services/api";
|
||||
import { devLogin, createDummyToken, updateUserProfile } from "../services/api";
|
||||
import { debugLog, clearDebugLogs } from "../services/debug";
|
||||
|
||||
export function LoginPage() {
|
||||
@@ -35,6 +35,18 @@ export function LoginPage() {
|
||||
setTokenAndUser(token, { id: String(uid), openid: openidParam, phone });
|
||||
debugLog(`setTokenAndUser: id=${uid}, openid=${openidParam}, phone=${phone}`);
|
||||
|
||||
// 同步昵称和头像到后端
|
||||
const nameParam = params.get('name');
|
||||
const avatarParam = params.get('avatar');
|
||||
if (nameParam || avatarParam) {
|
||||
const updateData: Record<string, unknown> = {};
|
||||
if (nameParam) updateData.name = decodeURIComponent(nameParam);
|
||||
if (avatarParam) updateData.avatar_url = decodeURIComponent(avatarParam);
|
||||
updateUserProfile(updateData).then(() => {
|
||||
debugLog(`synced: name=${nameParam}, avatar=${(avatarParam || '').substring(0, 30)}...`);
|
||||
}).catch((e) => debugLog(`sync error: ${e.message}`));
|
||||
}
|
||||
|
||||
fetchProfile().then((dto) => {
|
||||
if (dto) debugLog(`fetchProfile: name=${dto.name}, phone=${dto.phone}, onboarded=${dto.is_onboarded}`);
|
||||
navigate(dto?.is_onboarded ? "/home" : "/onboarding", { replace: true });
|
||||
|
||||
@@ -32,6 +32,7 @@ interface UserInfo {
|
||||
phone: string;
|
||||
email: string;
|
||||
address: string;
|
||||
avatar_url: string | null;
|
||||
lastPeriod: string;
|
||||
dueDate: string;
|
||||
currentWeek: number;
|
||||
@@ -59,6 +60,7 @@ export function ProfilePage() {
|
||||
phone: user.phone || "未设置",
|
||||
email: "",
|
||||
address: "",
|
||||
avatar_url: user.avatar_url || null,
|
||||
lastPeriod: user.lastPeriodDate || "",
|
||||
dueDate: user.dueDate || "",
|
||||
currentWeek: user.currentWeek,
|
||||
@@ -232,9 +234,13 @@ export function ProfilePage() {
|
||||
<Card className="bg-gradient-to-br from-morandi-400 to-morandi-500 border-0 text-white p-6 rounded-3xl shadow-sm">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="relative">
|
||||
<div className="w-20 h-20 bg-white/20 backdrop-blur-sm rounded-full flex items-center justify-center">
|
||||
<User className="w-10 h-10 text-white" />
|
||||
</div>
|
||||
{userInfo.avatar_url ? (
|
||||
<img src={userInfo.avatar_url} alt="头像" className="w-20 h-20 rounded-full object-cover" />
|
||||
) : (
|
||||
<div className="w-20 h-20 bg-white/20 backdrop-blur-sm rounded-full flex items-center justify-center">
|
||||
<User className="w-10 h-10 text-white" />
|
||||
</div>
|
||||
)}
|
||||
<button className="absolute bottom-0 right-0 w-6 h-6 bg-white rounded-full flex items-center justify-center shadow-sm">
|
||||
<Camera className="w-3 h-3 text-morandi-500" />
|
||||
</button>
|
||||
@@ -252,6 +258,26 @@ export function ProfilePage() {
|
||||
</Card>
|
||||
</motion.div>
|
||||
|
||||
{/* 基本信息 */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.05 }}
|
||||
>
|
||||
<h2 className="text-base font-semibold text-gray-800 mb-3 flex items-center gap-2">
|
||||
<User className="w-5 h-5 text-morandi-500" />
|
||||
基本信息
|
||||
</h2>
|
||||
<Card className="bg-white rounded-2xl p-5 shadow-sm border-0">
|
||||
<InfoItem
|
||||
label="姓名"
|
||||
value={userInfo.name}
|
||||
field="name"
|
||||
icon={User}
|
||||
/>
|
||||
</Card>
|
||||
</motion.div>
|
||||
|
||||
{/* 孕期信息 */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
|
||||
Reference in New Issue
Block a user