diff --git a/miniprogram/app.json b/miniprogram/app.json index 1ed0a8e..672cfdb 100644 --- a/miniprogram/app.json +++ b/miniprogram/app.json @@ -2,6 +2,7 @@ "pages": [ "pages/index/index", "pages/login/login", + "pages/register/register", "pages/scan/scan", "pages/ble-connect/ble-connect", "pages/bind-success/bind-success", diff --git a/miniprogram/pages/login/login.js b/miniprogram/pages/login/login.js index c1c078b..129f0c3 100644 --- a/miniprogram/pages/login/login.js +++ b/miniprogram/pages/login/login.js @@ -1,15 +1,12 @@ var app = getApp() -var http = require('../../utils/request') Page({ data: { statusBarHeight: 44, - loading: false, - userProfile: null + loading: false }, onLoad: function () { - var app = getApp() this.setData({ statusBarHeight: app.globalData.statusBarHeight }) }, @@ -17,73 +14,20 @@ Page({ var self = this self.setData({ loading: true }) - self.getWechatProfile().then(function (profile) { - self.setData({ userProfile: profile }) - return app.doLogin() - }).then(function () { - return self.saveProfile() - }).then(function () { + app.doLogin().then(function (data) { self.setData({ loading: false }) - wx.switchTab({ url: '/pages/index/index' }) + if (data && data.is_new_user) { + wx.redirectTo({ url: '/pages/register/register' }) + } else { + wx.switchTab({ url: '/pages/index/index' }) + } }).catch(function (err) { self.setData({ loading: false }) wx.showToast({ title: err.message || '登录失败', icon: 'none' }) }) }, - getWechatProfile: function () { - return new Promise(function (resolve) { - if (!wx.getUserProfile) { - resolve(null) - return - } - wx.getUserProfile({ - desc: '用于完善会员资料', - success: function (res) { - resolve(res.userInfo || null) - }, - fail: function () { - resolve(null) - } - }) - }) - }, - - saveProfile: function () { - var profile = this.data.userProfile || {} - if (!profile.nickName && !profile.avatarUrl) return Promise.resolve() - return this.updateProfile({ - nickname: profile.nickName || '', - avatar: profile.avatarUrl || '', - gender: profile.gender || 0 - }) - }, - - updateProfile: function (payload) { - return http.put('/api/v1/user/profile', payload).then(function () { - return app.loadProfile() - }) - }, - onAgreement: function () { wx.showModal({ title: '提示', content: '用户协议和隐私政策内容建设中', showCancel: false }) - }, - - onGetPhoneNumber: function (e) { - var self = this - if (!e.detail || !e.detail.code) { - wx.showToast({ title: '已跳过手机号授权', icon: 'none' }) - return - } - self.setData({ loading: true }) - app.doLogin().then(function () { - return http.post('/api/v1/user/phone', { code: e.detail.code }) - }).then(function () { - self.setData({ loading: false }) - wx.switchTab({ url: '/pages/index/index' }) - }).catch(function (err) { - self.setData({ loading: false }) - wx.showToast({ title: err.message || '手机号授权失败', icon: 'none' }) - }) } }) diff --git a/miniprogram/pages/login/login.wxml b/miniprogram/pages/login/login.wxml index ac7757d..24caa7f 100644 --- a/miniprogram/pages/login/login.wxml +++ b/miniprogram/pages/login/login.wxml @@ -1,7 +1,7 @@ 光子美容仪 - 微信授权登录 + 微信登录 @@ -9,17 +9,11 @@ 🌸 - 授权获取微信昵称和头像 - 用于完善会员资料 + 登录后即可使用全部功能 - - - 登录即表示同意《用户协议》和《隐私政策》 diff --git a/miniprogram/pages/login/login.wxss b/miniprogram/pages/login/login.wxss index 439b66a..87c1884 100644 --- a/miniprogram/pages/login/login.wxss +++ b/miniprogram/pages/login/login.wxss @@ -46,26 +46,6 @@ border: none; } -.phone-btn { - display: block; - width: 100%; - padding: 28rpx; - background: #ffffff; - color: #E6508C; - border: 2rpx solid #E6508C; - border-radius: 20rpx; - font-size: 30rpx; - text-align: center; - margin-top: 24rpx; -} - -.phone-btn::after { - border: none; -} - -.disabled-phone-btn { - display: none; -} .agreement { text-align: center; diff --git a/miniprogram/pages/register/register.js b/miniprogram/pages/register/register.js new file mode 100644 index 0000000..2d538c7 --- /dev/null +++ b/miniprogram/pages/register/register.js @@ -0,0 +1,102 @@ +var app = getApp() +var http = require('../../utils/request') + +var DEFAULT_AVATAR = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI9t2NHfLvvMiaiaCJQn3KP2P0vAHp1QBP0piavhGfhKCARlGd6z1EbR58ibJXKCp5WVlNnojwA/640' + +function randomNickname() { + var digits = '' + for (var i = 0; i < 4; i++) { + digits += Math.floor(Math.random() * 10) + } + return '用户' + digits +} + +Page({ + data: { + statusBarHeight: 44, + loading: false, + avatarUrl: DEFAULT_AVATAR, + nickname: '', + phone: '' + }, + + onLoad: function () { + this.setData({ + statusBarHeight: app.globalData.statusBarHeight, + nickname: randomNickname() + }) + }, + + onChooseAvatar: function (e) { + if (e.detail && e.detail.avatarUrl) { + this.setData({ avatarUrl: e.detail.avatarUrl }) + } + }, + + onNicknameInput: function (e) { + this.setData({ nickname: e.detail.value || '' }) + }, + + onNicknameBlur: function (e) { + var val = (e.detail.value || '').trim() + if (!val) { + this.setData({ nickname: randomNickname() }) + } else { + this.setData({ nickname: val }) + } + }, + + onGetPhoneNumber: function (e) { + var self = this + if (!e.detail || !e.detail.code) { + wx.showToast({ title: '需要授权手机号才能完成注册', icon: 'none' }) + return + } + self.setData({ loading: true }) + http.post('/api/v1/user/phone', { code: e.detail.code }).then(function (data) { + self.setData({ + loading: false, + phone: data.phone || data.pure_phone_number || '已授权' + }) + wx.showToast({ title: '手机号授权成功', icon: 'success' }) + }).catch(function (err) { + self.setData({ loading: false }) + wx.showToast({ title: err.message || '手机号授权失败', icon: 'none' }) + }) + }, + + onSubmit: function () { + var self = this + var nickname = (self.data.nickname || '').trim() + var avatarUrl = self.data.avatarUrl + + if (!self.data.phone) { + wx.showToast({ title: '请先授权手机号', icon: 'none' }) + return + } + + if (!nickname) { + wx.showToast({ title: '请输入昵称', icon: 'none' }) + return + } + + self.setData({ loading: true }) + + http.put('/api/v1/user/profile', { + nickname: nickname, + avatar: avatarUrl !== DEFAULT_AVATAR ? avatarUrl : '' + }).then(function () { + return app.loadProfile() + }).then(function () { + self.setData({ loading: false }) + wx.switchTab({ url: '/pages/index/index' }) + }).catch(function (err) { + self.setData({ loading: false }) + wx.showToast({ title: err.message || '保存失败', icon: 'none' }) + }) + }, + + onAgreement: function () { + wx.showModal({ title: '提示', content: '用户协议和隐私政策内容建设中', showCancel: false }) + } +}) diff --git a/miniprogram/pages/register/register.json b/miniprogram/pages/register/register.json new file mode 100644 index 0000000..30c9d0f --- /dev/null +++ b/miniprogram/pages/register/register.json @@ -0,0 +1,4 @@ +{ + "navigationBarTitleText": "完善资料", + "navigationStyle": "custom" +} diff --git a/miniprogram/pages/register/register.wxml b/miniprogram/pages/register/register.wxml new file mode 100644 index 0000000..1359309 --- /dev/null +++ b/miniprogram/pages/register/register.wxml @@ -0,0 +1,43 @@ + + + 光子美容仪 + 完善个人资料 + + + + 设置头像 + + + + + 设置昵称 + + + + + 授权手机号 + + + + + {{phone}} + + + + + 手机号用于接收服务通知,必须授权 + + + + + + 注册即表示同意《用户协议》和《隐私政策》 + + diff --git a/miniprogram/pages/register/register.wxss b/miniprogram/pages/register/register.wxss new file mode 100644 index 0000000..89b297f --- /dev/null +++ b/miniprogram/pages/register/register.wxss @@ -0,0 +1,138 @@ +.page { + min-height: 100vh; + background: #ffffff; +} + +.section-title { + font-size: 30rpx; + font-weight: 600; + color: #333333; + margin-bottom: 20rpx; + margin-top: 36rpx; +} + +.section-title:first-child { + margin-top: 0; +} + +.avatar-area { + display: flex; + justify-content: center; + margin-bottom: 12rpx; +} + +.avatar-btn { + background: none; + border: none; + padding: 0; + margin: 0; + line-height: normal; + display: flex; + flex-direction: column; + align-items: center; +} + +.avatar-btn::after { + border: none; +} + +.avatar-img { + width: 160rpx; + height: 160rpx; + border-radius: 50%; + border: 4rpx solid #f0f0f0; + background: #f5f5f5; +} + +.avatar-edit-hint { + font-size: 24rpx; + color: #999999; + margin-top: 12rpx; +} + +.input-wrap { + background: #f5f5f5; + border-radius: 16rpx; + padding: 24rpx 28rpx; + margin-bottom: 12rpx; +} + +.nickname-input { + font-size: 30rpx; + color: #333333; + height: 48rpx; + line-height: 48rpx; +} + +.phone-area { + margin-bottom: 12rpx; +} + +.phone-btn { + display: block; + width: 100%; + padding: 28rpx; + background: #ffffff; + color: #E6508C; + border: 2rpx solid #E6508C; + border-radius: 20rpx; + font-size: 30rpx; + text-align: center; +} + +.phone-btn::after { + border: none; +} + +.phone-hint { + font-size: 24rpx; + color: #999999; + text-align: center; + margin-top: 12rpx; +} + +.phone-done { + display: flex; + align-items: center; + justify-content: center; + background: #f0fff4; + border: 2rpx solid #52c41a; + border-radius: 20rpx; + padding: 28rpx; +} + +.phone-icon { + color: #52c41a; + font-size: 36rpx; + margin-right: 16rpx; +} + +.phone-text { + font-size: 30rpx; + color: #333333; +} + +.submit-btn { + display: block; + width: 100%; + padding: 32rpx; + background: #E6508C; + color: #ffffff; + border: none; + border-radius: 20rpx; + font-size: 32rpx; + font-weight: 600; + text-align: center; + margin-top: 60rpx; +} + +.submit-btn::after { + border: none; +} + +.agreement { + text-align: center; + font-size: 24rpx; + color: #999999; + margin-top: 32rpx; +} diff --git a/server/src/routes/auth.js b/server/src/routes/auth.js index 5c7d532..8faa9b8 100644 --- a/server/src/routes/auth.js +++ b/server/src/routes/auth.js @@ -16,7 +16,9 @@ router.post('/auth/login', wrap(async (req, res) => { const session = await code2Session(req.body.code || '') let user = await userDao.findByOpenid(session.openid) + let isNewUser = false if (!user) { + isNewUser = true const result = await userDao.create(session.openid) user = await userDao.findById(result.insertId) await logDao.write({ user_id: user.user_id, action: 'user_register', detail: '新用户注册', ip: req.ip }) @@ -26,6 +28,7 @@ router.post('/auth/login', wrap(async (req, res) => { res.json(ok({ token, user_id: String(user.user_id), + is_new_user: isNewUser, user_info: { user_id: String(user.user_id), nickname: user.nickname || '用户' + String(user.user_id),