| 1 | import { useEffect, useState } from 'react'; |
| 2 | import { Card, Descriptions, Spin, Typography, Space, Avatar, Switch, Slider, Button, Alert, InputNumber, Form, Tooltip } from 'antd'; |
| 3 | import { userApi } from '@/api/user'; |
| 4 | import styles from './userProfile.module.scss'; |
| 5 | import { UserOutlined, PhoneOutlined, IdcardOutlined, QrcodeOutlined, ClockCircleOutlined, SafetyOutlined, WechatOutlined, QuestionCircleOutlined } from '@ant-design/icons'; |
| 6 | import { message } from 'antd'; |
| 7 | |
| 8 | const { Title, Text } = Typography; |
| 9 | |
| 10 | interface UserInfo { |
| 11 | createTime: string; |
| 12 | id: string; |
| 13 | inviteCode: string; |
| 14 | name: string; |
| 15 | phone: string; |
| 16 | status: number; |
| 17 | updateTime: string; |
| 18 | wxOpenid: string; |
| 19 | _id: string; |
| 20 | earnInfo?: { |
| 21 | status: number; |
| 22 | cycleInterval: number; |
| 23 | }; |
| 24 | } |
| 25 | |
| 26 | const UserProfile = () => { |
| 27 | const [loading, setLoading] = useState(false); |
| 28 | const [userInfo, setUserInfo] = useState<UserInfo | null>(null); |
| 29 | const [popularizeCode, setPopularizeCode] = useState<string>(''); |
| 30 | const [earnStatus, setEarnStatus] = useState<boolean>(false); |
| 31 | const [cycleInterval, setCycleInterval] = useState<number>(30); |
| 32 | const [earnLoading, setEarnLoading] = useState<boolean>(false); |
| 33 | const [form] = Form.useForm(); |
| 34 | |
| 35 | const fetchUserInfo = async () => { |
| 36 | try { |
| 37 | setLoading(true); |
| 38 | const res:any = await userApi.getUserInfo(); |
| 39 | setUserInfo(res); |
| 40 | // 如果没有邀请码,则获取 |
| 41 | if (!res.popularizeCode) { |
| 42 | const code = await userApi.getMinePopularizeCode(); |
| 43 | setPopularizeCode(code); |
| 44 | } else { |
| 45 | setPopularizeCode(res.popularizeCode); |
| 46 | } |
| 47 | if (res.earnInfo) { |
| 48 | setEarnStatus(res.earnInfo.status === 1); |
| 49 | setCycleInterval(res.earnInfo.cycleInterval || 30); |
| 50 | form.setFieldsValue({ |
| 51 | cycleInterval: res.earnInfo.cycleInterval || 30 |
| 52 | }); |
| 53 | } else { |
| 54 | setEarnStatus(false); |
| 55 | setCycleInterval(30); |
| 56 | } |
| 57 | } catch (error) { |
| 58 | console.error('获取用户信息失败:', error); |
| 59 | } finally { |
| 60 | setLoading(false); |
| 61 | } |
| 62 | }; |
| 63 | |
| 64 | useEffect(() => { |
| 65 | fetchUserInfo(); |
| 66 | }, []); |
| 67 | |
| 68 | const handleSaveEarn = async () => { |
| 69 | setEarnLoading(true); |
| 70 | try { |
| 71 | await userApi.updateUserInfo({ |
| 72 | earnInfo: { |
| 73 | status: earnStatus ? 1 : 0, |
| 74 | cycleInterval, |
| 75 | }, |
| 76 | }); |
| 77 | message.success('设置已保存'); |
| 78 | fetchUserInfo(); |
| 79 | } catch (e) { |
| 80 | message.error('保存失败'); |
| 81 | } finally { |
| 82 | setEarnLoading(false); |
| 83 | } |
| 84 | }; |
| 85 | |
| 86 | const handleEarnStatusChange = async (checked: boolean) => { |
| 87 | setLoading(true); |
| 88 | try { |
| 89 | await userApi.setUserEarnInfo({ |
| 90 | status: checked ? 1 : 0, |
| 91 | cycleInterval: cycleInterval |
| 92 | }); |
| 93 | setEarnStatus(checked); |
| 94 | message.success(`赚钱模式已${checked ? '开启' : '关闭'}`); |
| 95 | } catch (error) { |
| 96 | console.error('更新赚钱模式状态失败:', error); |
| 97 | message.error('操作失败,请稍后重试'); |
| 98 | // 恢复原状态 |
| 99 | setEarnStatus(!checked); |
| 100 | } finally { |
| 101 | setLoading(false); |
| 102 | } |
| 103 | }; |
| 104 | |
| 105 | const handleCycleIntervalChange = async (value: number) => { |
| 106 | setCycleInterval(value); |
| 107 | }; |
| 108 | |
| 109 | const handleAfterChangeInterval = async (value: number) => { |
| 110 | if (!value || value < 5) return; |
| 111 | |
| 112 | setLoading(true); |
| 113 | try { |
| 114 | await userApi.setUserEarnInfo({ |
| 115 | status: earnStatus ? 1 : 0, |
| 116 | cycleInterval: value |
| 117 | }); |
| 118 | message.success('检查频率已更新'); |
| 119 | } catch (error) { |
| 120 | console.error('更新检查频率失败:', error); |
| 121 | message.error('操作失败,请稍后重试'); |
| 122 | // 恢复原值 |
| 123 | setCycleInterval(cycleInterval); |
| 124 | } finally { |
| 125 | setLoading(false); |
| 126 | } |
| 127 | }; |
| 128 | |
| 129 | const getIntervalLabel = (val: number) => { |
| 130 | if (val < 60) return `${val} 分钟`; |
| 131 | if (val % 60 === 0) return `${val / 60} 小时`; |
| 132 | return `${Math.floor(val / 60)} 小时${val % 60} 分钟`; |
| 133 | }; |
| 134 | |
| 135 | return ( |
| 136 | <div className={styles.profileContainer}> |
| 137 | <Spin spinning={loading}> |
| 138 | <div className={styles.profileHeader}> |
| 139 | <div className={styles.profileAvatar}> |
| 140 | <Avatar size={120} icon={<UserOutlined />} /> |
| 141 | <Title level={3} className={styles.profileName}> |
| 142 | {userInfo?.name || '未设置用户名'} |
| 143 | </Title> |
| 144 | </div> |
| 145 | </div> |
| 146 | |
| 147 | <div className={styles.profileContent}> |
| 148 | |
| 149 | <Card className={styles.profileCard}> |
| 150 | <Space direction="vertical" size="large" className={styles.infoSection}> |
| 151 | <div className={styles.infoGroup}> |
| 152 | <div className={styles.infoItem}> |
| 153 | <IdcardOutlined className={styles.infoIcon} /> |
| 154 | <div className={styles.infoContent}> |
| 155 | <span className={styles.infoLabel}>用户ID</span> |
| 156 | <span className={styles.infoValue}>{userInfo?.id || '-'}</span> |
| 157 | </div> |
| 158 | </div> |
| 159 | |
| 160 | <div className={styles.infoItem}> |
| 161 | <PhoneOutlined className={styles.infoIcon} /> |
| 162 | <div className={styles.infoContent}> |
| 163 | <span className={styles.infoLabel}>手机号</span> |
| 164 | <span className={styles.infoValue}>{userInfo?.phone || '-'}</span> |
| 165 | </div> |
| 166 | </div> |
| 167 | |
| 168 | |
| 169 | |
| 170 | <div className={styles.infoItem}> |
| 171 | <QrcodeOutlined className={styles.infoIcon} /> |
| 172 | <div className={styles.infoContent}> |
| 173 | <span className={styles.infoLabel}>我的邀请码</span> |
| 174 | <span className={styles.infoValue}>{popularizeCode || '-'}</span> |
| 175 | </div> |
| 176 | </div> |
| 177 | |
| 178 | {userInfo?.inviteCode && ( |
| 179 | <div className={styles.infoItem}> |
| 180 | <QrcodeOutlined className={styles.infoIcon} /> |
| 181 | <div className={styles.infoContent}> |
| 182 | <span className={styles.infoLabel}>邀请者邀请码</span> |
| 183 | <span className={styles.infoValue}>{userInfo.inviteCode}</span> |
| 184 | </div> |
| 185 | </div> |
| 186 | )} |
| 187 | |
| 188 | {/* <div className={styles.infoItem}> |
| 189 | <ClockCircleOutlined className={styles.infoIcon} /> |
| 190 | <div className={styles.infoContent}> |
| 191 | <span className={styles.infoLabel}>创建时间</span> |
| 192 | <span className={styles.infoValue}> |
| 193 | {userInfo?.createTime ? new Date(userInfo.createTime).toLocaleString() : '-'} |
| 194 | </span> |
| 195 | </div> |
| 196 | </div> */} |
| 197 | |
| 198 | {/* <div className={styles.infoItem}> |
| 199 | <ClockCircleOutlined className={styles.infoIcon} /> |
| 200 | <div className={styles.infoContent}> |
| 201 | <span className={styles.infoLabel}>更新时间</span> |
| 202 | <span className={styles.infoValue}> |
| 203 | {userInfo?.updateTime ? new Date(userInfo.updateTime).toLocaleString() : '-'} |
| 204 | </span> |
| 205 | </div> |
| 206 | </div> */} |
| 207 | |
| 208 | {/* <div className={styles.infoItem}> |
| 209 | <WechatOutlined className={styles.infoIcon} /> |
| 210 | <div className={styles.infoContent}> |
| 211 | <span className={styles.infoLabel}>微信OpenID</span> |
| 212 | <span className={styles.infoValue}>{userInfo?.wxOpenid || '-'}</span> |
| 213 | </div> |
| 214 | </div> */} |
| 215 | |
| 216 | {/* <div className={styles.infoItem}> |
| 217 | <SafetyOutlined className={styles.infoIcon} /> |
| 218 | <div className={styles.infoContent}> |
| 219 | <span className={styles.infoLabel}>账号状态</span> |
| 220 | <span className={`${styles.infoValue} ${userInfo?.status === 1 ? styles.statusNormal : styles.statusAbnormal}`}> |
| 221 | {userInfo?.status === 1 ? '正常' : '异常'} |
| 222 | </span> |
| 223 | </div> |
| 224 | </div> */} |
| 225 | </div> |
| 226 | </Space> |
| 227 | </Card> |
| 228 | |
| 229 | <Card className={styles.profileCard} style={{ marginTop: 24 }}> |
| 230 | <Title level={5} style={{ marginBottom: 16 }}>赚钱模式设置</Title> |
| 231 | <div style={{ marginBottom: 16 }}> |
| 232 | <div style={{ marginBottom: 16, display: 'flex', alignItems: 'center', gap: 16 }}> |
| 233 | <span>赚钱模式</span> |
| 234 | <Switch |
| 235 | checked={earnStatus} |
| 236 | onChange={handleEarnStatusChange} |
| 237 | loading={loading} |
| 238 | /> |
| 239 | <Tooltip title="开启后系统将自动为您寻找并完成任务"> |
| 240 | <QuestionCircleOutlined style={{ color: '#999' }} /> |
| 241 | </Tooltip> |
| 242 | </div> |
| 243 | |
| 244 | <div style={{ marginBottom: 8, display: 'flex', alignItems: 'center', gap: 16 }}> |
| 245 | <span>检查频率</span> |
| 246 | <Slider |
| 247 | min={5} |
| 248 | max={120} |
| 249 | step={1} |
| 250 | value={cycleInterval} |
| 251 | onChange={handleCycleIntervalChange} |
| 252 | onAfterChange={handleAfterChangeInterval} |
| 253 | style={{ flex: 1, marginRight: 16 }} |
| 254 | disabled={!earnStatus || loading} |
| 255 | /> |
| 256 | <span style={{ minWidth: 70, textAlign: 'right' }}>{getIntervalLabel(cycleInterval)}</span> |
| 257 | </div> |
| 258 | </div> |
| 259 | <div style={{ color: '#999', fontSize: 12, marginBottom: 12 }}> |
| 260 | 可设置 5分钟~24小时 区间 |
| 261 | </div> |
| 262 | <Alert |
| 263 | type="info" |
| 264 | showIcon |
| 265 | style={{ background: '#fafaff', border: 'none', marginBottom: 16 }} |
| 266 | message={ |
| 267 | <span> |
| 268 | 开启赚钱模式后,系统将自动接取并完成互动需求,确保您能获得最大收益。 |
| 269 | </span> |
| 270 | } |
| 271 | /> |
| 272 | </Card> |
| 273 | |
| 274 | </div> |
| 275 | </Spin> |
| 276 | </div> |
| 277 | ); |
| 278 | }; |
| 279 | |
| 280 | export default UserProfile; |