diff --git a/pages/home/home.wxss b/pages/home/home.wxss index d6272e0..ec7ec7b 100644 --- a/pages/home/home.wxss +++ b/pages/home/home.wxss @@ -15,7 +15,7 @@ page { .home-scroll { height: 100%; box-sizing: border-box; - padding-bottom: calc(24rpx + env(safe-area-inset-bottom)); + /* padding-bottom: calc( env(safe-area-inset-bottom)); */ } .banner { diff --git a/pages/mine/mine.js b/pages/mine/mine.js index c8280c3..f426687 100644 --- a/pages/mine/mine.js +++ b/pages/mine/mine.js @@ -6,29 +6,26 @@ function authStatusText(status) { 1: '已认证', 2: '审核中' }; - return map[status] || `状态${status}`; + return map[status] || '未认证'; +} + +function maskPhone(phone) { + if (!phone || phone.length < 7) return phone || ''; + return phone.substring(0, 3) + '****' + phone.substring(7); } Page({ data: { loggedIn: false, - profile: null, - authStatusText: '-', - - showAuthForm: false, - - authForm: { - name: '', - mobile: '', - idCardNumber: '' - } - + profile: {}, + maskedPhone: '', + authStatusText: '未认证' }, onShow() { const accessToken = wx.getStorageSync('accessToken') || ''; if (!accessToken) { - this.setData({ loggedIn: false, profile: null, authStatusText: '-' }); + this.setData({ loggedIn: false, profile: {}, maskedPhone: '', authStatusText: '未认证' }); return; } this.setData({ loggedIn: true }); @@ -44,9 +41,11 @@ Page({ .fetchMyProfile() .then((profile) => { const p = profile || {}; - const st = p && typeof p.authStatus === 'number' ? p.authStatus : 0; + const st = typeof p.authStatus === 'number' ? p.authStatus : 0; + const phone = p.mobile || p.phone || ''; this.setData({ profile: p, + maskedPhone: maskPhone(phone), authStatusText: authStatusText(st) }); }) @@ -69,38 +68,32 @@ Page({ wx.navigateTo({ url: '/subpackages/mine/records/records' }); }, - toggleAuthForm() { - this.setData({ showAuthForm: !this.data.showAuthForm }); + goToAuth() { + // 跳转到实名认证页面(可按需调整) + wx.showToast({ title: '身份认证功能开发中', icon: 'none' }); }, - onAuthInput(e) { - const key = e.currentTarget.dataset.key; - this.setData({ - authForm: { - ...this.data.authForm, - [key]: e.detail.value + goToOrders() { + wx.showToast({ title: '我的订单功能开发中', icon: 'none' }); + }, + + goToTeam() { + wx.showToast({ title: '我的团队功能开发中', icon: 'none' }); + }, + + onChooseAvatar() { + wx.chooseMedia({ + count: 1, + mediaType: ['image'], + sourceType: ['album', 'camera'], + success: (res) => { + const tempFilePath = res.tempFiles[0].tempFilePath; + this.setData({ + 'profile.avatar': tempFilePath + }); + // TODO: 上传头像到服务器 } }); - }, - - submitAuth() { - const { name, mobile, idCardNumber } = this.data.authForm; - if (!name) return wx.showToast({ title: '请输入姓名', icon: 'none' }); - if (!mobile) return wx.showToast({ title: '请输入手机号', icon: 'none' }); - if (!idCardNumber) return wx.showToast({ title: '请输入身份证号', icon: 'none' }); - - wx.showLoading({ title: '提交中...' }); - auth - .submitMyAuth({ name, mobile, idCardNumber }) - .then(() => { - wx.showToast({ title: '提交成功', icon: 'success' }); - this.setData({ showAuthForm: false }); - return this.loadProfile(); - }) - .catch(() => { - wx.showToast({ title: '提交失败', icon: 'none' }); - }) - .finally(() => wx.hideLoading()); } }); diff --git a/pages/mine/mine.json b/pages/mine/mine.json new file mode 100644 index 0000000..68522ed --- /dev/null +++ b/pages/mine/mine.json @@ -0,0 +1,4 @@ +{ + "navigationStyle": "custom", + "enablePullDownRefresh": true +} diff --git a/pages/mine/mine.wxml b/pages/mine/mine.wxml index 3df5ec4..6e246f9 100644 --- a/pages/mine/mine.wxml +++ b/pages/mine/mine.wxml @@ -1,50 +1,83 @@ - - - - 登录后可查看我的信息与实名认证状态 - - - - - - - 头像 - - {{profile && profile.nickName ? profile.nickName : '用户'}} - 积分:{{profile && profile.points != null ? profile.points : '-'}} - 证书:{{profile && profile.certificateCount != null ? profile.certificateCount : '-'}} - 实名认证:{{authStatusText}} - - - - - - - - - - - - - 实名认证提交 - - 姓名 - - - - 手机号 - - - - 身份证号 - - - - - - + + + + 登录后可查看我的信息与参赛记录 + + + + + + + + + + + + 我的 + + + + + + + 📷 + + + {{maskedPhone}} + + + + + + + + + + {{profile.points || 0}} + 我的积分 + + + + + + {{profile.certificateCount || 0}} + 我的证书 + + + + + + + + + 身份认证 + 点击进行身份认证 + + + 🛡 + {{authStatusText}} + + + + + + + + 我的订单 + + + + 参赛记录 + + + + 我的团队 + + diff --git a/pages/mine/mine.wxss b/pages/mine/mine.wxss index 4a4e8c9..8940134 100644 --- a/pages/mine/mine.wxss +++ b/pages/mine/mine.wxss @@ -1,153 +1,252 @@ -.container { - padding: 16rpx; +/* ====== 未登录 ====== */ +.not-logged { + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + background: #f5f7fa; } -.center { - padding: 40rpx 0; +.not-logged-inner { display: flex; flex-direction: column; align-items: center; - gap: 18rpx; + gap: 32rpx; } -.login-btn { +.not-logged-tip { + font-size: 28rpx; + color: #999; +} + +.go-login-btn { + width: 400rpx !important; + height: 88rpx; + line-height: 88rpx; + background: #1a56db; + color: #fff; + font-size: 30rpx; + font-weight: 600; + border-radius: 12rpx; + border: none; +} + +.go-login-btn::after { + border: none; +} + +/* ====== 已登录页面 ====== */ +.mine-page { + min-height: 100vh; + background: #f0f2f5; +} + +/* ====== 蓝色头部 ====== */ +.header { + position: relative; width: 100%; - max-width: 420rpx; + overflow: visible; } -.hint { - color: #888; - font-size: 24rpx; - text-align: center; +.header-bg { + position: absolute; + top: 0; + left: 0; + right: 0; + height: 520rpx; + background: linear-gradient(180deg, #1a3a8a 0%, #1a56db 100%); + border-radius: 0 0 40rpx 40rpx; } -.card { - background: #ffffff; - border-radius: 18rpx; - padding: 16rpx; - box-shadow: 0 8rpx 22rpx rgba(0, 0, 0, 0.04); +.status-bar { + height: env(safe-area-inset-top, 44px); + position: relative; } -.profile-card { - margin-top: 8rpx; -} - -.row { +.nav-bar { + position: relative; + height: 88rpx; display: flex; - gap: 16rpx; align-items: center; + justify-content: center; +} + +.nav-title { + font-size: 34rpx; + font-weight: 600; + color: #ffffff; +} + +/* ====== 头像区 ====== */ +.profile-section { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + padding: 20rpx 0 40rpx; +} + +.avatar-wrap { + position: relative; + width: 160rpx; + height: 160rpx; } .avatar { - width: 110rpx; - height: 110rpx; + width: 160rpx; + height: 160rpx; border-radius: 50%; - background: #f2f2f2; + border: 6rpx solid rgba(255, 255, 255, 0.4); } -.avatar.placeholder { +.camera-icon { + position: absolute; + right: 4rpx; + bottom: 4rpx; + width: 48rpx; + height: 48rpx; + background: #1a56db; + border: 4rpx solid #fff; + border-radius: 50%; display: flex; - justify-content: center; align-items: center; - color: #aaa; + justify-content: center; +} + +.camera-text { font-size: 24rpx; - font-weight: 700; } -.profile-main { - flex: 1; -} - -.nick { +.phone-text { + margin-top: 16rpx; font-size: 32rpx; - font-weight: 900; - color: #222; - margin-bottom: 10rpx; + font-weight: 600; + color: #ffffff; + letter-spacing: 2rpx; } -.sub { - color: #666; - font-size: 26rpx; +/* ====== 内容区 ====== */ +.content { + position: relative; + margin-top: -20rpx; + padding: 0 28rpx; + padding-bottom: 40rpx; +} + +/* ====== 积分 & 证书双卡 ====== */ +.stat-row { + display: flex; + gap: 20rpx; +} + +.stat-card { + flex: 1; + background: #ffffff; + border-radius: 16rpx; + padding: 28rpx 24rpx; + display: flex; + align-items: center; + justify-content: space-between; + box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05); +} + +.stat-left { + display: flex; + flex-direction: column; +} + +.stat-num { + font-size: 48rpx; + font-weight: 800; + color: #1a1a1a; + line-height: 1.1; +} + +.stat-label { + font-size: 24rpx; + color: #999; margin-top: 8rpx; } -.actions { - margin-top: 12rpx; +.stat-icon { + width: 80rpx; + height: 80rpx; + flex-shrink: 0; } -.section-title { - margin-top: 18rpx; - margin-bottom: 14rpx; - font-size: 28rpx; - font-weight: 900; - color: #222; +/* ====== 身份认证条 ====== */ +.auth-bar { + margin-top: 20rpx; + background: linear-gradient(135deg, #1a3a8a 0%, #1a56db 100%); + border-radius: 16rpx; + padding: 28rpx 30rpx; + display: flex; + align-items: center; + justify-content: space-between; } -.main-title { - margin-top: 22rpx; -} - -.form-item { +.auth-left { display: flex; flex-direction: column; - gap: 10rpx; - margin-top: 16rpx; } -.label { - color: #666; - font-size: 24rpx; +.auth-title { + font-size: 32rpx; + font-weight: 700; + color: #ffffff; } -.input { - height: 72rpx; - background: #f6f7fb; - border-radius: 14rpx; - padding: 0 16rpx; - font-size: 26rpx; -} - -.submit-btn { - margin-top: 22rpx; - width: 100%; - height: 84rpx; -} - -.list { - height: calc(100vh - 420rpx); -} - -.empty { - text-align: center; - padding: 40rpx 0; - color: #888; - font-size: 24rpx; -} - -.loading { - text-align: center; - padding: 24rpx 0; - color: #888; -} - -.reg-card { - padding: 16rpx; - background: #ffffff; - border-radius: 16rpx; - box-shadow: 0 8rpx 22rpx rgba(0, 0, 0, 0.03); - margin-bottom: 14rpx; -} - -.r-title { - font-size: 30rpx; - font-weight: 900; - color: #222; - margin-bottom: 10rpx; -} - -.r-sub { - color: #666; - font-size: 26rpx; +.auth-desc { + font-size: 22rpx; + color: rgba(255, 255, 255, 0.7); margin-top: 6rpx; } +.auth-badge { + display: flex; + align-items: center; + gap: 8rpx; + background: rgba(255, 255, 255, 0.2); + border-radius: 30rpx; + padding: 10rpx 24rpx; +} + +.auth-badge-icon { + font-size: 28rpx; +} + +.auth-badge-text { + font-size: 24rpx; + color: #ffffff; + white-space: nowrap; +} + +/* ====== 功能入口卡 ====== */ +.func-card { + margin-top: 20rpx; + background: #ffffff; + border-radius: 16rpx; + padding: 36rpx 0; + display: flex; + align-items: center; + box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05); +} + +.func-item { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + gap: 14rpx; +} + +.func-icon { + width: 64rpx; + height: 64rpx; +} + +.func-text { + font-size: 24rpx; + color: #333; +} + diff --git a/project.config.json b/project.config.json index 7624f3a..3b36453 100644 --- a/project.config.json +++ b/project.config.json @@ -34,5 +34,6 @@ "ignore": [], "include": [] }, - "editorSetting": {} + "editorSetting": {}, + "libVersion": "3.15.1" } \ No newline at end of file diff --git a/project.private.config.json b/project.private.config.json index f7b13e7..4f6b17d 100644 --- a/project.private.config.json +++ b/project.private.config.json @@ -1,8 +1,8 @@ { - "libVersion": "3.15.1", + "libVersion": "3.15.0", "projectname": "YD_Event.miniApp", "setting": { - "urlCheck": true, + "urlCheck": false, "coverView": false, "lazyloadPlaceholderEnable": false, "skylineRenderEnable": false, diff --git a/subpackages/mine/login/login.js b/subpackages/mine/login/login.js index f6f9346..3a40ae7 100644 --- a/subpackages/mine/login/login.js +++ b/subpackages/mine/login/login.js @@ -1,14 +1,26 @@ const auth = require('../../../utils/auth'); const PHONE_RE = /^1[3456789]\d{9}$/; +const CODE_COUNTDOWN = 60; Page({ data: { + loginMode: 'password', // 'code' | 'password' mobile: '', password: '', - logging: false + verificationCode: '', + showPassword: false, + logging: false, + agreed: false, + + // 验证码倒计时 + codeText: '发送验证码', + codeBtnDisabled: false, + countdown: 0 }, + _timer: null, + onShow() { const accessToken = wx.getStorageSync('accessToken') || ''; if (accessToken) { @@ -16,43 +28,165 @@ Page({ } }, + onUnload() { + this._clearTimer(); + }, + + // ========= 事件处理 ========= + + /** 切换登录方式 */ + onSwitchMode(e) { + const mode = e.currentTarget.dataset.mode; + if (mode === this.data.loginMode) return; + this.setData({ + loginMode: mode, + verificationCode: '', + password: '' + }); + }, + + /** 手机号输入 */ onMobileInput(e) { this.setData({ mobile: (e.detail.value || '').trim() }); }, + /** 清除手机号 */ + onClearMobile() { + this.setData({ mobile: '' }); + }, + + /** 验证码输入 */ + onCodeInput(e) { + this.setData({ verificationCode: (e.detail.value || '').trim() }); + }, + + /** 密码输入 */ onPasswordInput(e) { this.setData({ password: e.detail.value || '' }); }, - onLoginTap() { - if (this.data.logging) return; - const { mobile, password } = this.data; + /** 显示/隐藏密码 */ + onTogglePassword() { + this.setData({ showPassword: !this.data.showPassword }); + }, + + /** 勾选协议 */ + onToggleAgreement() { + this.setData({ agreed: !this.data.agreed }); + }, + + /** 忘记密码 */ + onForgetPassword() { + wx.navigateTo({ url: '/subpackages/mine/register/register' }); + }, + + // ========= 发送验证码 ========= + + onSendCode() { + if (this.data.codeBtnDisabled) return; + const { mobile } = this.data; if (!PHONE_RE.test(mobile)) { - wx.showToast({ title: '请输入正确手机号', icon: 'none' }); + wx.showToast({ title: '请输入正确的手机号', icon: 'none' }); return; } - if (!password) { + + this.setData({ codeBtnDisabled: true, codeText: '发送中...' }); + + auth + .sendVerificationCode(mobile) + .then(() => { + wx.showToast({ title: '验证码已发送', icon: 'success' }); + this._startCountdown(); + }) + .catch((err) => { + wx.showToast({ title: err.message || '发送失败', icon: 'none' }); + this.setData({ codeBtnDisabled: false, codeText: '发送验证码' }); + }); + }, + + // ========= 登录 ========= + + onLoginTap() { + if (this.data.logging) return; + + if (!this.data.agreed) { + wx.showToast({ title: '请先同意用户协议与隐私政策', icon: 'none' }); + return; + } + + const { mobile, loginMode, password, verificationCode } = this.data; + + if (!PHONE_RE.test(mobile)) { + wx.showToast({ title: '请输入正确的手机号', icon: 'none' }); + return; + } + + if (loginMode === 'password' && !password) { wx.showToast({ title: '请输入密码', icon: 'none' }); return; } + if (loginMode === 'code' && !verificationCode) { + wx.showToast({ title: '请输入验证码', icon: 'none' }); + return; + } + this.setData({ logging: true }); wx.showLoading({ title: '登录中...' }); - auth - .loginWithMobilePassword({ mobile, password }) + const loginPromise = + loginMode === 'code' + ? auth.loginWithMobileCode({ mobile, verificationCode }) + : auth.loginWithMobilePassword({ mobile, password }); + + loginPromise .then(() => { wx.showToast({ title: '登录成功', icon: 'success' }); setTimeout(() => { wx.redirectTo({ url: '/pages/mine/mine' }); }, 400); }) - .catch(() => { - wx.showToast({ title: '登录失败', icon: 'none' }); + .catch((err) => { + wx.showToast({ title: err.message || '登录失败', icon: 'none' }); }) .finally(() => { this.setData({ logging: false }); wx.hideLoading(); }); + }, + + // ========= 内部方法 ========= + + _startCountdown() { + let seconds = CODE_COUNTDOWN; + this.setData({ + countdown: seconds, + codeText: `${seconds}s`, + codeBtnDisabled: true + }); + + this._timer = setInterval(() => { + seconds -= 1; + if (seconds <= 0) { + this._clearTimer(); + this.setData({ + countdown: 0, + codeText: '发送验证码', + codeBtnDisabled: false + }); + } else { + this.setData({ + countdown: seconds, + codeText: `${seconds}s` + }); + } + }, 1000); + }, + + _clearTimer() { + if (this._timer) { + clearInterval(this._timer); + this._timer = null; + } } }); diff --git a/subpackages/mine/login/login.json b/subpackages/mine/login/login.json index eb54ca5..8f6679d 100644 --- a/subpackages/mine/login/login.json +++ b/subpackages/mine/login/login.json @@ -1,4 +1,6 @@ { - "navigationBarTitleText": "登录" + "navigationBarTitleText": "登录", + "navigationBarBackgroundColor": "#ffffff", + "navigationBarTextStyle": "black" } diff --git a/subpackages/mine/login/login.wxml b/subpackages/mine/login/login.wxml index e163d63..82c4045 100644 --- a/subpackages/mine/login/login.wxml +++ b/subpackages/mine/login/login.wxml @@ -1,32 +1,101 @@ - - - - 手机号 - +