import { View, Text, Image, Button, Checkbox, CheckboxGroup, RichText } from '@tarojs/components' import Taro, { useDidShow, usePullDownRefresh } from '@tarojs/taro' import { useState } from 'react' import { login as silentLogin } from '../../utils/request' import './index.scss' export default function UserIndex() { const [userInfo, setUserInfo] = useState(null) const [showLoginModal, setShowLoginModal] = useState(false) const [isAgreed, setIsAgreed] = useState(false) const [showAgreement, setShowAgreement] = useState(false) // For showing agreement content useDidShow(() => { const info = Taro.getStorageSync('userInfo') if (info) setUserInfo(info) }) usePullDownRefresh(async () => { try { const res = await silentLogin() if (res) { setUserInfo(res) } Taro.stopPullDownRefresh() } catch (e) { Taro.stopPullDownRefresh() Taro.showToast({ title: '刷新失败', icon: 'none' }) } }) const goOrders = () => Taro.navigateTo({ url: '/pages/order/list' }) const goDistributor = () => Taro.navigateTo({ url: '/subpackages/distributor/index' }) const goInvite = () => Taro.navigateTo({ url: '/subpackages/distributor/invite' }) const goWithdraw = () => Taro.navigateTo({ url: '/subpackages/distributor/withdraw' }) const goActivityList = (tab = 'all') => Taro.navigateTo({ url: `/subpackages/forum/activity/index?tab=${tab}` }) const handleAddress = async () => { try { const res = await Taro.chooseAddress() // 同步地址信息到后端 const token = Taro.getStorageSync('token') if (token) { await Taro.request({ url: 'https://market.quant-speed.com/api/wechat/update/', method: 'POST', header: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, data: { province: res.provinceName, city: res.cityName, country: '中国' // 默认中国,chooseAddress通常返回国内地址 } }) // 更新本地 userInfo const updatedInfo = { ...userInfo, province: res.provinceName, city: res.cityName, country: '中国' } setUserInfo(updatedInfo) Taro.setStorageSync('userInfo', updatedInfo) Taro.showToast({ title: '地址信息已同步', icon: 'success' }) } } catch(e) { // 用户取消或其他错误,忽略 } } const handleAvatarClick = async () => { if (!userInfo) return try { const { tempFilePaths } = await Taro.chooseImage({ count: 1, sizeType: ['compressed'], sourceType: ['album', 'camera'] }) if (!tempFilePaths.length) return Taro.showLoading({ title: '上传中...' }) const token = Taro.getStorageSync('token') const uploadRes = await Taro.uploadFile({ url: 'https://market.quant-speed.com/api/upload/image/', filePath: tempFilePaths[0], name: 'file', header: { 'Authorization': `Bearer ${token}` } }) if (uploadRes.statusCode !== 200) { throw new Error('上传失败') } const data = JSON.parse(uploadRes.data) const newAvatarUrl = data.url // 更新后端用户信息 await Taro.request({ url: 'https://market.quant-speed.com/api/wechat/update/', method: 'POST', header: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, data: { avatar_url: newAvatarUrl } }) // 更新本地 userInfo const updatedInfo = { ...userInfo, avatar_url: newAvatarUrl } setUserInfo(updatedInfo) Taro.setStorageSync('userInfo', updatedInfo) Taro.hideLoading() Taro.showToast({ title: '头像更新成功', icon: 'success' }) } catch (e) { Taro.hideLoading() Taro.showToast({ title: '头像更新失败', icon: 'none' }) console.error(e) } } const handleNicknameClick = () => { if (!userInfo) return Taro.showModal({ title: '修改昵称', content: userInfo.nickname || '', // @ts-ignore editable: true, placeholderText: '请输入新昵称', success: async function (res) { if (res.confirm && (res as any).content) { const newNickname = (res as any).content if (newNickname === userInfo.nickname) return try { Taro.showLoading({ title: '更新中...' }) const token = Taro.getStorageSync('token') await Taro.request({ url: 'https://market.quant-speed.com/api/wechat/update/', method: 'POST', header: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, data: { nickname: newNickname } }) // 更新本地 userInfo const updatedInfo = { ...userInfo, nickname: newNickname } setUserInfo(updatedInfo) Taro.setStorageSync('userInfo', updatedInfo) Taro.hideLoading() Taro.showToast({ title: '昵称已更新', icon: 'success' }) } catch (e) { Taro.hideLoading() Taro.showToast({ title: '更新失败', icon: 'none' }) console.error(e) } } } }) } const handleLogout = () => { Taro.showModal({ title: '提示', content: '确定要退出登录吗?', success: function (res) { if (res.confirm) { Taro.removeStorageSync('token') Taro.removeStorageSync('userInfo') setUserInfo(null) Taro.showToast({ title: '已退出登录', icon: 'success' }) } } }) } const login = async () => { try { // 1. 获取微信登录 Code const { code } = await Taro.login() if (!code) throw new Error('登录失败:无法获取 Code') // 2. 调用后端登录 (仅 Code) const res = await Taro.request({ url: 'https://market.quant-speed.com/api/wechat/login/', method: 'POST', data: { code } }) console.log('code:', code) if (res.statusCode === 200 && res.data.token) { console.log('登录成功,后端返回用户信息:', res.data) Taro.setStorageSync('token', res.data.token) Taro.setStorageSync('userInfo', res.data) setUserInfo(res.data) Taro.showToast({ title: '登录成功', icon: 'success' }) } else { throw new Error(res.data.error || '登录请求失败') } } catch (e) { Taro.showToast({ title: e.message || '登录失败', icon: 'none' }) } } const getPhoneNumber = async (e) => { const { code: phoneCode, errMsg } = e.detail if (errMsg !== "getPhoneNumber:ok") { Taro.showToast({ title: '获取手机号失败', icon: 'none' }) return } try { Taro.showLoading({ title: '登录中...' }) // 1. 获取登录 Code const { code: loginCode } = await Taro.login() // 2. 调用后端登录 (Code + PhoneCode) console.log('loginCode:', loginCode) console.log('phoneCode:', phoneCode) const res = await Taro.request({ url: 'https://market.quant-speed.com/api/wechat/login/', method: 'POST', data: { code: loginCode, phone_code: phoneCode } }) Taro.hideLoading() if (res.statusCode === 200 && res.data.token) { console.log('手机号登录成功,后端返回用户信息:', res.data) Taro.setStorageSync('token', res.data.token) Taro.setStorageSync('userInfo', res.data) setUserInfo(res.data) setShowLoginModal(false) // Close modal on success Taro.showToast({ title: '授权登录成功', icon: 'success' }) } else { throw new Error(res.data.error || '登录失败') } } catch(err) { Taro.hideLoading() Taro.showToast({ title: err.message || '系统异常', icon: 'none' }) } } const serviceGroups = [ { title: '基础服务', items: [ { title: '我的订单', icon: '📦', action: goOrders }, { title: '地址管理', icon: '📝', action: handleAddress }, { title: '活动管理', icon: '⌚️', action: () => goActivityList('mine') }, ] }, { title: '分销中心', items: [ { title: '分销首页', icon: '⚡', action: goDistributor }, { title: '推广邀请', icon: '🤝', action: goInvite }, { title: '佣金提现', icon: '💰', action: goWithdraw }, ] }, { title: '其他', items: [ { title: '联系客服', icon: '🎧', isContact: true }, ...(userInfo ? [{ title: '退出登录', icon: '🚪', action: handleLogout }] : []) ] } ] const stats = [ { label: '余额', value: '0.00' }, { label: '积分', value: '0' }, { label: '优惠券', value: '0' } ] const handleAgreementCheck = (e) => { setIsAgreed(!!e.detail.value.length) } const handleShowAgreement = (e) => { e.stopPropagation() setShowAgreement(true) } const handleLoginBtnClick = () => { if (!isAgreed) { Taro.showToast({ title: '请先阅读并同意用户协议', icon: 'none' }) return } // If agreed, the button openType='getPhoneNumber' handles it. } return ( {/* Profile Card */} {userInfo && } {userInfo?.nickname || '未登录用户'} {userInfo && ( {/* 明星技术用户 */} {userInfo.is_star && ( 🌟 技术专家 )} {/* 管理员 */} {userInfo.is_admin && ( 🛡️ 管理员 )} {/* 网页用户徽章 - 仅在 has_web_badge 为 true 时显示 */} {userInfo.has_web_badge && ( 🌐 网页用户 )} )} ID: {userInfo ? (userInfo.phone_number || userInfo.id || '----') : '----'} {!userInfo?.phone_number && ( )} {/* Stats Row */} {stats.map((item, idx) => ( {item.value} {item.label} ))} {/* Service Groups */} {serviceGroups.map((group, gIdx) => ( {group.title} {group.items.map((item, idx) => ( {item.icon} {item.title} {item.isContact && 我已阅读并同意 《用户协议》《隐私政策》 )} {/* Agreement Detail Modal */} {showAgreement && ( 用户协议与隐私政策 1. 特别提示 在此特别提醒您(用户)在注册成为用户之前,请认真阅读本《用户协议》(以下简称“协议”),确保您充分理解本协议中各条款。请您审慎阅读并选择接受或不接受本协议。除非您接受本协议所有条款,否则您无权注册、登录或使用本协议所涉服务。您的注册、登录、使用等行为将视为对本协议的接受,并同意接受本协议各项条款的约束。 2. 账号注册 2.1 鉴于“Quant Speed”账号的绑定注册方式,您同意在注册时将您的手机号码及微信账号信息提供给“Quant Speed”用于注册。 3. 隐私保护 3.1 本小程序将严格保护您的个人信息安全。我们使用各种安全技术和程序来保护您的个人信息不被未经授权的访问、使用或泄漏。 )} ) }