- ✅ 创建了4个P1优先级Hook(搜索、导航、个人资料、订阅) - ✅ 将其中3个Hook集成到5个组件中 - ✅ 在个人资料、设置、搜索、订阅流程中添加了15+个追踪点 - ✅ 覆盖了完整的收入漏斗(支付发起 → 成功 → 订阅创建) - ✅ 添加了留存追踪(个人资料更新、设置修改、搜索查询) 影响: - 完整的用户订阅旅程可见性 - 个人资料/设置参与度追踪 - 搜索行为分析 - 完整的支付漏斗追踪(微信支付)
683 lines
37 KiB
JavaScript
683 lines
37 KiB
JavaScript
// src/views/Profile/ProfilePage.js
|
||
import React, { useState, useRef } from 'react';
|
||
import {
|
||
Box,
|
||
Container,
|
||
VStack,
|
||
HStack,
|
||
Text,
|
||
Heading,
|
||
Avatar,
|
||
Button,
|
||
Input,
|
||
Textarea,
|
||
FormControl,
|
||
FormLabel,
|
||
SimpleGrid,
|
||
Card,
|
||
CardBody,
|
||
CardHeader,
|
||
Stat,
|
||
StatLabel,
|
||
StatNumber,
|
||
StatHelpText,
|
||
Badge,
|
||
Divider,
|
||
Select,
|
||
useToast,
|
||
IconButton,
|
||
Flex,
|
||
Progress,
|
||
Tag,
|
||
TagLabel,
|
||
TagCloseButton,
|
||
Wrap,
|
||
WrapItem,
|
||
Modal,
|
||
ModalOverlay,
|
||
ModalContent,
|
||
ModalHeader,
|
||
ModalBody,
|
||
ModalCloseButton,
|
||
useDisclosure
|
||
} from '@chakra-ui/react';
|
||
import { EditIcon, CheckIcon, CloseIcon, AddIcon } from '@chakra-ui/icons';
|
||
import { useAuth } from '../../contexts/AuthContext';
|
||
import { logger } from '../../utils/logger';
|
||
import { useProfileEvents } from '../../hooks/useProfileEvents';
|
||
|
||
export default function ProfilePage() {
|
||
const { user, updateUser } = useAuth();
|
||
const [isEditing, setIsEditing] = useState(false);
|
||
const [isLoading, setIsLoading] = useState(false);
|
||
|
||
// 🎯 初始化个人资料埋点Hook
|
||
const profileEvents = useProfileEvents({ pageType: 'profile' });
|
||
const [newTag, setNewTag] = useState('');
|
||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||
const fileInputRef = useRef();
|
||
const toast = useToast();
|
||
|
||
// 表单数据状态
|
||
const [formData, setFormData] = useState({
|
||
nickname: user?.nickname || '',
|
||
bio: user?.bio || '',
|
||
location: user?.location || '',
|
||
gender: user?.gender || '',
|
||
birth_date: user?.birth_date || '',
|
||
trading_experience: user?.trading_experience || '',
|
||
investment_style: user?.investment_style || '',
|
||
risk_preference: user?.risk_preference || '',
|
||
investment_amount: user?.investment_amount || '',
|
||
preferred_markets: user?.preferred_markets ? user.preferred_markets.split(',') : [],
|
||
creator_tags: user?.creator_tags ? user.creator_tags.split(',') : []
|
||
});
|
||
|
||
const handleInputChange = (e) => {
|
||
const { name, value } = e.target;
|
||
setFormData(prev => ({
|
||
...prev,
|
||
[name]: value
|
||
}));
|
||
};
|
||
|
||
const handleSaveProfile = async () => {
|
||
setIsLoading(true);
|
||
try {
|
||
// 这里应该调用后端API更新用户信息
|
||
const updatedData = {
|
||
...formData,
|
||
preferred_markets: formData.preferred_markets.join(','),
|
||
creator_tags: formData.creator_tags.join(',')
|
||
};
|
||
|
||
logger.debug('ProfilePage', '保存个人资料', { userId: user?.id });
|
||
|
||
// 模拟API调用
|
||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||
|
||
updateUser(updatedData);
|
||
setIsEditing(false);
|
||
|
||
// 🎯 追踪个人资料更新成功
|
||
const updatedFields = Object.keys(formData).filter(
|
||
key => user?.[key] !== formData[key]
|
||
);
|
||
profileEvents.trackProfileUpdated(updatedFields, updatedData);
|
||
|
||
// ✅ 保留关键操作提示
|
||
toast({
|
||
title: "个人资料更新成功",
|
||
status: "success",
|
||
duration: 3000,
|
||
isClosable: true,
|
||
});
|
||
} catch (error) {
|
||
logger.error('ProfilePage', 'handleSaveProfile', error, { userId: user?.id });
|
||
|
||
// 🎯 追踪个人资料更新失败
|
||
const attemptedFields = Object.keys(formData);
|
||
profileEvents.trackProfileUpdateFailed(attemptedFields, error.message);
|
||
|
||
// ✅ 保留错误提示
|
||
toast({
|
||
title: "更新失败",
|
||
description: error.message,
|
||
status: "error",
|
||
duration: 3000,
|
||
isClosable: true,
|
||
});
|
||
} finally {
|
||
setIsLoading(false);
|
||
}
|
||
};
|
||
|
||
const handleAvatarUpload = (event) => {
|
||
const file = event.target.files[0];
|
||
if (file) {
|
||
logger.debug('ProfilePage', '上传头像', { fileName: file.name, fileSize: file.size });
|
||
|
||
// 这里应该上传文件到服务器
|
||
const reader = new FileReader();
|
||
reader.onload = (e) => {
|
||
updateUser({ avatar_url: e.target.result });
|
||
|
||
// 🎯 追踪头像上传
|
||
profileEvents.trackAvatarUploaded('file_upload', file.size);
|
||
|
||
// ✅ 保留关键操作提示
|
||
toast({
|
||
title: "头像更新成功",
|
||
status: "success",
|
||
duration: 3000,
|
||
isClosable: true,
|
||
});
|
||
};
|
||
reader.readAsDataURL(file);
|
||
}
|
||
};
|
||
|
||
const addMarketTag = () => {
|
||
if (newTag && !formData.preferred_markets.includes(newTag)) {
|
||
setFormData(prev => ({
|
||
...prev,
|
||
preferred_markets: [...prev.preferred_markets, newTag]
|
||
}));
|
||
setNewTag('');
|
||
}
|
||
};
|
||
|
||
const removeMarketTag = (tagToRemove) => {
|
||
setFormData(prev => ({
|
||
...prev,
|
||
preferred_markets: prev.preferred_markets.filter(tag => tag !== tagToRemove)
|
||
}));
|
||
};
|
||
|
||
const getProgressColor = (score) => {
|
||
if (score >= 800) return 'green';
|
||
if (score >= 500) return 'blue';
|
||
if (score >= 200) return 'yellow';
|
||
return 'red';
|
||
};
|
||
|
||
return (
|
||
<Container maxW="container.xl" py={8}>
|
||
<VStack spacing={8} align="stretch">
|
||
{/* 页面标题 */}
|
||
<HStack justify="space-between">
|
||
<Heading size="lg" color="gray.800">个人资料</Heading>
|
||
{!isEditing ? (
|
||
<Button
|
||
leftIcon={<EditIcon />}
|
||
colorScheme="blue"
|
||
onClick={() => setIsEditing(true)}
|
||
>
|
||
编辑资料
|
||
</Button>
|
||
) : (
|
||
<HStack>
|
||
<Button
|
||
leftIcon={<CheckIcon />}
|
||
colorScheme="green"
|
||
onClick={handleSaveProfile}
|
||
isLoading={isLoading}
|
||
>
|
||
保存
|
||
</Button>
|
||
<Button
|
||
leftIcon={<CloseIcon />}
|
||
variant="outline"
|
||
onClick={() => {
|
||
setIsEditing(false);
|
||
setFormData({
|
||
nickname: user?.nickname || '',
|
||
bio: user?.bio || '',
|
||
location: user?.location || '',
|
||
gender: user?.gender || '',
|
||
birth_date: user?.birth_date || '',
|
||
trading_experience: user?.trading_experience || '',
|
||
investment_style: user?.investment_style || '',
|
||
risk_preference: user?.risk_preference || '',
|
||
investment_amount: user?.investment_amount || '',
|
||
preferred_markets: user?.preferred_markets ? user.preferred_markets.split(',') : [],
|
||
creator_tags: user?.creator_tags ? user.creator_tags.split(',') : []
|
||
});
|
||
}}
|
||
>
|
||
取消
|
||
</Button>
|
||
</HStack>
|
||
)}
|
||
</HStack>
|
||
|
||
<SimpleGrid columns={{ base: 1, lg: 3 }} spacing={8}>
|
||
{/* 左侧:基本信息 */}
|
||
<Box gridColumn={{ base: "1", lg: "1 / 3" }}>
|
||
<Card>
|
||
<CardHeader>
|
||
<Heading size="md">基本信息</Heading>
|
||
</CardHeader>
|
||
<CardBody>
|
||
<VStack spacing={6}>
|
||
{/* 头像和基本信息 */}
|
||
<HStack spacing={6} align="start" w="full">
|
||
<VStack>
|
||
<Avatar
|
||
size="2xl"
|
||
src={user?.avatar_url}
|
||
name={user?.nickname || user?.username}
|
||
/>
|
||
{isEditing && (
|
||
<Button
|
||
size="sm"
|
||
onClick={() => fileInputRef.current?.click()}
|
||
>
|
||
更换头像
|
||
</Button>
|
||
)}
|
||
<input
|
||
ref={fileInputRef}
|
||
type="file"
|
||
accept="image/*"
|
||
style={{ display: 'none' }}
|
||
onChange={handleAvatarUpload}
|
||
/>
|
||
</VStack>
|
||
|
||
<VStack flex="1" align="start" spacing={4}>
|
||
<HStack w="full">
|
||
<Badge colorScheme="blue" variant="subtle">
|
||
用户名: {user?.username}
|
||
</Badge>
|
||
{user?.is_verified && (
|
||
<Badge colorScheme="green">已实名认证</Badge>
|
||
)}
|
||
{user?.has_wechat && (
|
||
<Badge colorScheme="green">微信已绑定</Badge>
|
||
)}
|
||
{user?.is_creator && (
|
||
<Badge colorScheme="purple">创作者</Badge>
|
||
)}
|
||
</HStack>
|
||
|
||
<SimpleGrid columns={2} spacing={4} w="full">
|
||
<FormControl>
|
||
<FormLabel>昵称</FormLabel>
|
||
{isEditing ? (
|
||
<Input
|
||
name="nickname"
|
||
value={formData.nickname}
|
||
onChange={handleInputChange}
|
||
placeholder="请输入昵称"
|
||
/>
|
||
) : (
|
||
<Text>{user?.nickname || '未设置'}</Text>
|
||
)}
|
||
</FormControl>
|
||
|
||
<FormControl>
|
||
<FormLabel>性别</FormLabel>
|
||
{isEditing ? (
|
||
<Select
|
||
name="gender"
|
||
value={formData.gender}
|
||
onChange={handleInputChange}
|
||
>
|
||
<option value="">请选择</option>
|
||
<option value="male">男</option>
|
||
<option value="female">女</option>
|
||
<option value="other">其他</option>
|
||
</Select>
|
||
) : (
|
||
<Text>
|
||
{user?.gender === 'male' ? '男' :
|
||
user?.gender === 'female' ? '女' :
|
||
user?.gender === 'other' ? '其他' : '未设置'}
|
||
</Text>
|
||
)}
|
||
</FormControl>
|
||
|
||
<FormControl>
|
||
<FormLabel>所在地</FormLabel>
|
||
{isEditing ? (
|
||
<Input
|
||
name="location"
|
||
value={formData.location}
|
||
onChange={handleInputChange}
|
||
placeholder="请输入所在地"
|
||
/>
|
||
) : (
|
||
<Text>{user?.location || '未设置'}</Text>
|
||
)}
|
||
</FormControl>
|
||
|
||
<FormControl>
|
||
<FormLabel>生日</FormLabel>
|
||
{isEditing ? (
|
||
<Input
|
||
name="birth_date"
|
||
type="date"
|
||
value={formData.birth_date}
|
||
onChange={handleInputChange}
|
||
/>
|
||
) : (
|
||
<Text>{user?.birth_date || '未设置'}</Text>
|
||
)}
|
||
</FormControl>
|
||
</SimpleGrid>
|
||
|
||
<FormControl>
|
||
<FormLabel>个人简介</FormLabel>
|
||
{isEditing ? (
|
||
<Textarea
|
||
name="bio"
|
||
value={formData.bio}
|
||
onChange={handleInputChange}
|
||
placeholder="介绍一下自己..."
|
||
rows={3}
|
||
/>
|
||
) : (
|
||
<Text color="gray.600">
|
||
{user?.bio || '这个人很懒,什么都没留下...'}
|
||
</Text>
|
||
)}
|
||
</FormControl>
|
||
</VStack>
|
||
</HStack>
|
||
|
||
<Divider />
|
||
|
||
{/* 投资偏好 */}
|
||
<Box w="full">
|
||
<Heading size="sm" mb={4}>投资偏好</Heading>
|
||
<SimpleGrid columns={{ base: 1, md: 2 }} spacing={4}>
|
||
<FormControl>
|
||
<FormLabel>交易经验</FormLabel>
|
||
{isEditing ? (
|
||
<Select
|
||
name="trading_experience"
|
||
value={formData.trading_experience}
|
||
onChange={handleInputChange}
|
||
>
|
||
<option value="">请选择</option>
|
||
<option value="beginner">新手 (0-1年)</option>
|
||
<option value="intermediate">中级 (1-3年)</option>
|
||
<option value="advanced">高级 (3-5年)</option>
|
||
<option value="expert">专家 (5年以上)</option>
|
||
</Select>
|
||
) : (
|
||
<Text>
|
||
{user?.trading_experience === 'beginner' ? '新手 (0-1年)' :
|
||
user?.trading_experience === 'intermediate' ? '中级 (1-3年)' :
|
||
user?.trading_experience === 'advanced' ? '高级 (3-5年)' :
|
||
user?.trading_experience === 'expert' ? '专家 (5年以上)' : '未设置'}
|
||
</Text>
|
||
)}
|
||
</FormControl>
|
||
|
||
<FormControl>
|
||
<FormLabel>投资风格</FormLabel>
|
||
{isEditing ? (
|
||
<Select
|
||
name="investment_style"
|
||
value={formData.investment_style}
|
||
onChange={handleInputChange}
|
||
>
|
||
<option value="">请选择</option>
|
||
<option value="conservative">保守型</option>
|
||
<option value="moderate">稳健型</option>
|
||
<option value="aggressive">积极型</option>
|
||
<option value="speculative">投机型</option>
|
||
</Select>
|
||
) : (
|
||
<Text>
|
||
{user?.investment_style === 'conservative' ? '保守型' :
|
||
user?.investment_style === 'moderate' ? '稳健型' :
|
||
user?.investment_style === 'aggressive' ? '积极型' :
|
||
user?.investment_style === 'speculative' ? '投机型' : '未设置'}
|
||
</Text>
|
||
)}
|
||
</FormControl>
|
||
|
||
<FormControl>
|
||
<FormLabel>风险偏好</FormLabel>
|
||
{isEditing ? (
|
||
<Select
|
||
name="risk_preference"
|
||
value={formData.risk_preference}
|
||
onChange={handleInputChange}
|
||
>
|
||
<option value="">请选择</option>
|
||
<option value="low">低风险</option>
|
||
<option value="medium">中等风险</option>
|
||
<option value="high">高风险</option>
|
||
</Select>
|
||
) : (
|
||
<Text>
|
||
{user?.risk_preference === 'low' ? '低风险' :
|
||
user?.risk_preference === 'medium' ? '中等风险' :
|
||
user?.risk_preference === 'high' ? '高风险' : '未设置'}
|
||
</Text>
|
||
)}
|
||
</FormControl>
|
||
|
||
<FormControl>
|
||
<FormLabel>投资金额</FormLabel>
|
||
{isEditing ? (
|
||
<Select
|
||
name="investment_amount"
|
||
value={formData.investment_amount}
|
||
onChange={handleInputChange}
|
||
>
|
||
<option value="">请选择</option>
|
||
<option value="under_10k">1万以下</option>
|
||
<option value="10k_50k">1-5万</option>
|
||
<option value="50k_100k">5-10万</option>
|
||
<option value="100k_500k">10-50万</option>
|
||
<option value="over_500k">50万以上</option>
|
||
</Select>
|
||
) : (
|
||
<Text>
|
||
{user?.investment_amount === 'under_10k' ? '1万以下' :
|
||
user?.investment_amount === '10k_50k' ? '1-5万' :
|
||
user?.investment_amount === '50k_100k' ? '5-10万' :
|
||
user?.investment_amount === '100k_500k' ? '10-50万' :
|
||
user?.investment_amount === 'over_500k' ? '50万以上' : '未设置'}
|
||
</Text>
|
||
)}
|
||
</FormControl>
|
||
</SimpleGrid>
|
||
|
||
{/* 偏好市场标签 */}
|
||
<FormControl mt={4}>
|
||
<FormLabel>偏好市场</FormLabel>
|
||
<Wrap>
|
||
{formData.preferred_markets.map((market, index) => (
|
||
<WrapItem key={index}>
|
||
<Tag size="md" variant="solid" colorScheme="blue">
|
||
<TagLabel>{market}</TagLabel>
|
||
{isEditing && (
|
||
<TagCloseButton onClick={() => removeMarketTag(market)} />
|
||
)}
|
||
</Tag>
|
||
</WrapItem>
|
||
))}
|
||
{isEditing && (
|
||
<WrapItem>
|
||
<HStack>
|
||
<Input
|
||
size="sm"
|
||
placeholder="添加市场"
|
||
value={newTag}
|
||
onChange={(e) => setNewTag(e.target.value)}
|
||
onKeyPress={(e) => e.key === 'Enter' && addMarketTag()}
|
||
/>
|
||
<IconButton
|
||
size="sm"
|
||
icon={<AddIcon />}
|
||
onClick={addMarketTag}
|
||
/>
|
||
</HStack>
|
||
</WrapItem>
|
||
)}
|
||
</Wrap>
|
||
{formData.preferred_markets.length === 0 && !isEditing && (
|
||
<Text color="gray.500" fontSize="sm">暂未设置偏好市场</Text>
|
||
)}
|
||
</FormControl>
|
||
</Box>
|
||
</VStack>
|
||
</CardBody>
|
||
</Card>
|
||
</Box>
|
||
|
||
{/* 右侧:统计数据 */}
|
||
<VStack spacing={6}>
|
||
{/* 社区统计 */}
|
||
<Card w="full">
|
||
<CardHeader>
|
||
<Heading size="md">社区统计</Heading>
|
||
</CardHeader>
|
||
<CardBody>
|
||
<VStack spacing={4}>
|
||
<Stat textAlign="center">
|
||
<StatLabel>用户等级</StatLabel>
|
||
<StatNumber color="blue.500">Lv.{user?.user_level || 1}</StatNumber>
|
||
</Stat>
|
||
|
||
<SimpleGrid columns={2} spacing={4} w="full">
|
||
<Stat textAlign="center">
|
||
<StatLabel>声誉分数</StatLabel>
|
||
<StatNumber fontSize="lg">{user?.reputation_score || 0}</StatNumber>
|
||
</Stat>
|
||
<Stat textAlign="center">
|
||
<StatLabel>贡献点数</StatLabel>
|
||
<StatNumber fontSize="lg">{user?.contribution_point || 0}</StatNumber>
|
||
</Stat>
|
||
<Stat textAlign="center">
|
||
<StatLabel>发帖数</StatLabel>
|
||
<StatNumber fontSize="lg">{user?.post_count || 0}</StatNumber>
|
||
</Stat>
|
||
<Stat textAlign="center">
|
||
<StatLabel>评论数</StatLabel>
|
||
<StatNumber fontSize="lg">{user?.comment_count || 0}</StatNumber>
|
||
</Stat>
|
||
<Stat textAlign="center">
|
||
<StatLabel>关注者</StatLabel>
|
||
<StatNumber fontSize="lg">{user?.follower_count || 0}</StatNumber>
|
||
</Stat>
|
||
<Stat textAlign="center">
|
||
<StatLabel>关注中</StatLabel>
|
||
<StatNumber fontSize="lg">{user?.following_count || 0}</StatNumber>
|
||
</Stat>
|
||
</SimpleGrid>
|
||
|
||
<Box w="full">
|
||
<Text fontSize="sm" color="gray.600" mb={2}>声誉等级</Text>
|
||
<Progress
|
||
value={(user?.reputation_score || 0) / 10}
|
||
colorScheme={getProgressColor(user?.reputation_score || 0)}
|
||
borderRadius="md"
|
||
/>
|
||
<Text fontSize="xs" color="gray.500" mt={1}>
|
||
{user?.reputation_score || 0} / 1000
|
||
</Text>
|
||
</Box>
|
||
</VStack>
|
||
</CardBody>
|
||
</Card>
|
||
|
||
{/* 账户信息 */}
|
||
<Card w="full">
|
||
<CardHeader>
|
||
<Heading size="md">账户信息</Heading>
|
||
</CardHeader>
|
||
<CardBody>
|
||
<VStack spacing={3} align="start">
|
||
<HStack justify="space-between" w="full">
|
||
<Text fontSize="sm" color="gray.600">邮箱</Text>
|
||
<VStack align="end" spacing={0}>
|
||
<Text fontSize="sm">{user?.email}</Text>
|
||
{user?.email_confirmed && (
|
||
<Badge size="xs" colorScheme="green">已验证</Badge>
|
||
)}
|
||
</VStack>
|
||
</HStack>
|
||
|
||
{user?.phone && (
|
||
<HStack justify="space-between" w="full">
|
||
<Text fontSize="sm" color="gray.600">手机号</Text>
|
||
<VStack align="end" spacing={0}>
|
||
<Text fontSize="sm">{user.phone}</Text>
|
||
{user?.phone_confirmed && (
|
||
<Badge size="xs" colorScheme="green">已验证</Badge>
|
||
)}
|
||
</VStack>
|
||
</HStack>
|
||
)}
|
||
|
||
<HStack justify="space-between" w="full">
|
||
<Text fontSize="sm" color="gray.600">微信</Text>
|
||
{user?.has_wechat ? (
|
||
<Badge size="xs" colorScheme="green">已绑定</Badge>
|
||
) : (
|
||
<Badge size="xs" colorScheme="gray">未绑定</Badge>
|
||
)}
|
||
</HStack>
|
||
|
||
<HStack justify="space-between" w="full">
|
||
<Text fontSize="sm" color="gray.600">注册时间</Text>
|
||
<Text fontSize="sm">
|
||
{user?.created_at ? new Date(user.created_at).toLocaleDateString() : '未知'}
|
||
</Text>
|
||
</HStack>
|
||
|
||
<HStack justify="space-between" w="full">
|
||
<Text fontSize="sm" color="gray.600">最后活跃</Text>
|
||
<Text fontSize="sm">
|
||
{user?.last_seen ? new Date(user.last_seen).toLocaleDateString() : '未知'}
|
||
</Text>
|
||
</HStack>
|
||
|
||
<HStack justify="space-between" w="full">
|
||
<Text fontSize="sm" color="gray.600">账户状态</Text>
|
||
<Badge colorScheme={user?.status === 'active' ? 'green' : 'gray'}>
|
||
{user?.status === 'active' ? '正常' : '未激活'}
|
||
</Badge>
|
||
</HStack>
|
||
</VStack>
|
||
</CardBody>
|
||
</Card>
|
||
|
||
{/* 实名认证 */}
|
||
{!user?.is_verified && (
|
||
<Card w="full">
|
||
<CardHeader>
|
||
<Heading size="md">实名认证</Heading>
|
||
</CardHeader>
|
||
<CardBody>
|
||
<VStack spacing={4}>
|
||
<Text fontSize="sm" color="gray.600" textAlign="center">
|
||
完成实名认证,获得更高权限和信任度
|
||
</Text>
|
||
<Button colorScheme="orange" size="sm" onClick={onOpen}>
|
||
立即认证
|
||
</Button>
|
||
</VStack>
|
||
</CardBody>
|
||
</Card>
|
||
)}
|
||
</VStack>
|
||
</SimpleGrid>
|
||
</VStack>
|
||
|
||
{/* 实名认证模态框 */}
|
||
<Modal isOpen={isOpen} onClose={onClose}>
|
||
<ModalOverlay />
|
||
<ModalContent>
|
||
<ModalHeader>实名认证</ModalHeader>
|
||
<ModalCloseButton />
|
||
<ModalBody pb={6}>
|
||
<VStack spacing={4}>
|
||
<FormControl>
|
||
<FormLabel>真实姓名</FormLabel>
|
||
<Input placeholder="请输入真实姓名" />
|
||
</FormControl>
|
||
<FormControl>
|
||
<FormLabel>身份证号</FormLabel>
|
||
<Input placeholder="请输入身份证号" />
|
||
</FormControl>
|
||
<Text fontSize="sm" color="gray.500">
|
||
您的个人信息将严格保密,仅用于身份验证
|
||
</Text>
|
||
<Button colorScheme="blue" w="full">
|
||
提交认证
|
||
</Button>
|
||
</VStack>
|
||
</ModalBody>
|
||
</ModalContent>
|
||
</Modal>
|
||
</Container>
|
||
);
|
||
} |