refactor: migrate to Tencent Cloud backend
这个提交包含在:
@@ -5,13 +5,17 @@ Page({
|
||||
statusBarHeight: 44,
|
||||
scanning: true,
|
||||
scanProgress: 0,
|
||||
regions: 0x7F,
|
||||
regionData: [],
|
||||
error: ''
|
||||
},
|
||||
|
||||
onLoad: function () {
|
||||
onLoad: function (options) {
|
||||
var app = getApp()
|
||||
this.setData({ statusBarHeight: app.globalData.statusBarHeight })
|
||||
this.setData({
|
||||
statusBarHeight: app.globalData.statusBarHeight,
|
||||
regions: parseInt(options.regions) || 0x7F
|
||||
})
|
||||
this.startScan()
|
||||
},
|
||||
|
||||
@@ -38,6 +42,13 @@ Page({
|
||||
})
|
||||
|
||||
ble.queryStatus().catch(function () {})
|
||||
|
||||
setTimeout(function () {
|
||||
clearInterval(progressTimer)
|
||||
if (!self.data.scanning) return
|
||||
self.setData({ scanning: false, scanProgress: 100 })
|
||||
self.parseScanResults({ region_mask: self.data.regions })
|
||||
}, 5000)
|
||||
},
|
||||
|
||||
parseScanResults: function (status) {
|
||||
@@ -49,6 +60,21 @@ Page({
|
||||
},
|
||||
|
||||
onNext: function () {
|
||||
wx.navigateTo({ url: '/pages/treatment-setup/treatment-setup' })
|
||||
var mask = this.data.regions || 0x7F
|
||||
ble.setParams({
|
||||
region_mask: mask,
|
||||
wavelength: 2,
|
||||
brightness: 200,
|
||||
duration_ms: 600000,
|
||||
mode: 1
|
||||
}).then(function () {
|
||||
return ble.startTreatment(mask)
|
||||
}).then(function () {
|
||||
wx.redirectTo({
|
||||
url: '/pages/treating/treating?regions=' + mask + '&wavelength=2&duration=600000&mode=1'
|
||||
})
|
||||
}).catch(function (err) {
|
||||
wx.showToast({ title: err.error_msg || '启动失败', icon: 'none' })
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
var ble = require('../../services/ble')
|
||||
var http = require('../../utils/request')
|
||||
var app = getApp()
|
||||
var SCAN_TIMEOUT = 15000
|
||||
|
||||
@@ -56,9 +57,16 @@ Page({
|
||||
var userId = app.globalData.userId || ''
|
||||
ble.on('bind_result', function (result) {
|
||||
if (result.success) {
|
||||
self.setData({ state: 'done' })
|
||||
wx.redirectTo({
|
||||
url: '/pages/bind-success/bind-success?device_id=' + self.data.deviceId
|
||||
http.post('/api/v1/device/bind/confirm', {
|
||||
device_id: self.data.deviceId,
|
||||
bind_token: self.data.bindToken
|
||||
}).then(function () {
|
||||
self.setData({ state: 'done' })
|
||||
wx.redirectTo({
|
||||
url: '/pages/bind-success/bind-success?device_id=' + self.data.deviceId
|
||||
})
|
||||
}).catch(function (err) {
|
||||
self.setData({ state: 'error', error: err.message || '后台确认绑定失败' })
|
||||
})
|
||||
} else {
|
||||
self.setData({ state: 'error', error: '设备绑定失败' })
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
var ble = require('../../services/ble')
|
||||
var mqtt = require('../../services/mqtt')
|
||||
var http = require('../../utils/request')
|
||||
var app = getApp()
|
||||
|
||||
@@ -43,6 +42,7 @@ Page({
|
||||
var devices = data.devices || []
|
||||
self.setData({ hasDevice: devices.length > 0 })
|
||||
if (devices.length > 0) {
|
||||
app.globalData.currentDevice = devices[0]
|
||||
self.setData({
|
||||
deviceName: devices[0].name || devices[0].device_id || '我的光面膜',
|
||||
deviceInfo: devices[0]
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
var app = getApp()
|
||||
var http = require('../../utils/request')
|
||||
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 44,
|
||||
loading: false
|
||||
loading: false,
|
||||
userProfile: null
|
||||
},
|
||||
|
||||
onLoad: function () {
|
||||
@@ -15,12 +17,94 @@ Page({
|
||||
var self = this
|
||||
self.setData({ loading: true })
|
||||
|
||||
app.doLogin().then(function () {
|
||||
self.getWechatProfile().then(function (profile) {
|
||||
self.setData({ userProfile: profile })
|
||||
return app.doLogin()
|
||||
}).then(function () {
|
||||
return self.saveProfile()
|
||||
}).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' })
|
||||
})
|
||||
},
|
||||
|
||||
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()
|
||||
})
|
||||
},
|
||||
|
||||
uploadAvatar: function (filePath) {
|
||||
var ext = 'jpg'
|
||||
var match = String(filePath).match(/\.([a-zA-Z0-9]+)$/)
|
||||
if (match && match[1]) ext = match[1].toLowerCase()
|
||||
var contentType = ext === 'png' ? 'image/png' : 'image/jpeg'
|
||||
return http.post('/api/v1/user/avatar/upload-url', {
|
||||
ext: ext,
|
||||
content_type: contentType
|
||||
}).then(function (data) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
wx.uploadFile({
|
||||
url: data.upload_url,
|
||||
filePath: filePath,
|
||||
name: 'file',
|
||||
header: { 'Content-Type': contentType },
|
||||
success: function (res) {
|
||||
if (res.statusCode >= 200 && res.statusCode < 300) resolve(data.public_url)
|
||||
else reject({ message: '头像上传失败' })
|
||||
},
|
||||
fail: function () { reject({ message: '头像上传失败' }) }
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
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' })
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -9,14 +9,19 @@
|
||||
|
||||
<view class="flower-area">
|
||||
<text class="flower">🌸</text>
|
||||
<view class="desc">获取你的手机号</view>
|
||||
<view class="desc">提供更好的服务</view>
|
||||
<view class="desc">授权获取微信昵称和头像</view>
|
||||
<view class="desc">用于完善会员资料</view>
|
||||
</view>
|
||||
|
||||
<button class="login-btn" loading="{{loading}}" bindtap="onLogin" disabled="{{loading}}">
|
||||
微信授权登录
|
||||
</button>
|
||||
|
||||
<!-- 手机号授权已预留。需要时展示该按钮并隐藏上面的普通登录按钮。 -->
|
||||
<button class="phone-btn disabled-phone-btn" open-type="getPhoneNumber" bindgetphonenumber="onGetPhoneNumber" disabled="{{loading}}">
|
||||
授权手机号登录(预留)
|
||||
</button>
|
||||
|
||||
<view class="agreement">登录即表示同意《用户协议》和《隐私政策》</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -46,6 +46,27 @@
|
||||
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;
|
||||
font-size: 24rpx;
|
||||
|
||||
@@ -51,7 +51,7 @@ Page({
|
||||
http.post('/api/v1/device/bind', { device_id: deviceId }).then(function (data) {
|
||||
self.setData({ scanning: false })
|
||||
wx.redirectTo({
|
||||
url: '/pages/bind-success/bind-success?device_id=' + deviceId
|
||||
url: '/pages/ble-connect/ble-connect?device_id=' + encodeURIComponent(deviceId) + '&bind_token=' + encodeURIComponent(data.bind_token || '')
|
||||
})
|
||||
}).catch(function (err) {
|
||||
self.setData({ scanning: false })
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
var ble = require('../../services/ble')
|
||||
var commandSync = require('../../services/command-sync')
|
||||
|
||||
Page({
|
||||
data: {
|
||||
@@ -13,7 +14,9 @@ Page({
|
||||
temperature: 0,
|
||||
progress: 0,
|
||||
paused: false,
|
||||
completed: false
|
||||
completed: false,
|
||||
startedAt: 0,
|
||||
localTimer: null
|
||||
},
|
||||
|
||||
onLoad: function (options) {
|
||||
@@ -24,36 +27,67 @@ Page({
|
||||
wavelength: parseInt(options.wavelength) || 2,
|
||||
duration: parseInt(options.duration) || 600000,
|
||||
mode: parseInt(options.mode) || 0,
|
||||
remainingMs: parseInt(options.duration) || 600000
|
||||
remainingMs: parseInt(options.duration) || 600000,
|
||||
startedAt: Date.now()
|
||||
})
|
||||
|
||||
ble.on('status', this.onStatus.bind(this))
|
||||
ble.on('treatment_complete', this.onComplete.bind(this))
|
||||
ble.on('exception', this.onException.bind(this))
|
||||
this.startLocalTimer()
|
||||
this.syncCommands()
|
||||
},
|
||||
|
||||
onUnload: function () {
|
||||
ble.off('status')
|
||||
ble.off('treatment_complete')
|
||||
ble.off('exception')
|
||||
if (this.data.localTimer) clearInterval(this.data.localTimer)
|
||||
},
|
||||
|
||||
onStatus: function (status) {
|
||||
var remaining = status.remaining_ms || 0
|
||||
startLocalTimer: function () {
|
||||
var self = this
|
||||
var timer = setInterval(function () {
|
||||
if (self.data.completed || self.data.paused) return
|
||||
var elapsed = Date.now() - self.data.startedAt
|
||||
var remaining = Math.max(0, self.data.duration - elapsed)
|
||||
self.updateProgress(remaining)
|
||||
if (remaining <= 0) {
|
||||
clearInterval(timer)
|
||||
self.finishAsComplete()
|
||||
}
|
||||
}, 1000)
|
||||
this.setData({ localTimer: timer })
|
||||
},
|
||||
|
||||
updateProgress: function (remaining) {
|
||||
var total = this.data.duration
|
||||
var progress = total > 0 ? Math.round(((total - remaining) / total) * 100) : 0
|
||||
var mins = Math.floor(remaining / 60000)
|
||||
var secs = Math.floor((remaining % 60000) / 1000)
|
||||
var text = ('0' + mins).slice(-2) + ':' + ('0' + secs).slice(-2)
|
||||
|
||||
this.setData({
|
||||
remainingMs: remaining,
|
||||
remainingText: text,
|
||||
progress: progress,
|
||||
remainingText: ('0' + mins).slice(-2) + ':' + ('0' + secs).slice(-2),
|
||||
progress: progress
|
||||
})
|
||||
},
|
||||
|
||||
onStatus: function (status) {
|
||||
var remaining = status.remaining_ms || 0
|
||||
this.updateProgress(remaining)
|
||||
this.setData({
|
||||
battery: status.battery,
|
||||
temperature: status.temperature,
|
||||
paused: status.mode_state === 0x03
|
||||
})
|
||||
this.syncCommands()
|
||||
},
|
||||
|
||||
syncCommands: function () {
|
||||
var app = getApp()
|
||||
var device = app.globalData.currentDevice || {}
|
||||
var deviceId = device.device_id || this.options.device_id
|
||||
if (deviceId) commandSync.sync(deviceId)
|
||||
},
|
||||
|
||||
onComplete: function (result) {
|
||||
@@ -71,6 +105,16 @@ Page({
|
||||
}, 1000)
|
||||
},
|
||||
|
||||
finishAsComplete: function () {
|
||||
var elapsed = Math.min(this.data.duration, Date.now() - this.data.startedAt)
|
||||
this.onComplete({
|
||||
session_id: 'SESS' + Date.now(),
|
||||
regions: this.data.regions,
|
||||
total_duration_ms: elapsed,
|
||||
avg_pd: 0
|
||||
})
|
||||
},
|
||||
|
||||
onException: function (err) {
|
||||
wx.showModal({
|
||||
title: '设备异常',
|
||||
@@ -89,8 +133,8 @@ Page({
|
||||
content: '确定要提前结束本次护理吗?',
|
||||
success: function (res) {
|
||||
if (res.confirm) {
|
||||
ble.stopTreatment().then(function () {
|
||||
wx.navigateBack()
|
||||
ble.stopTreatment().catch(function () {}).then(function () {
|
||||
self.finishAsComplete()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ Page({
|
||||
selectedMode: 0,
|
||||
subExpired: false,
|
||||
subDays: 6,
|
||||
fixedDurationMs: 600000,
|
||||
submitting: false,
|
||||
error: ''
|
||||
},
|
||||
@@ -26,7 +27,7 @@ Page({
|
||||
checkSubscription: function () {
|
||||
var http = require('../../utils/request')
|
||||
var self = this
|
||||
http.get('/api/v1/subscription/status').then(function (sub) {
|
||||
http.get('/api/v1/subscription').then(function (sub) {
|
||||
self.setData({
|
||||
subExpired: sub.status !== 'active',
|
||||
subDays: sub.remaining_days || 0
|
||||
@@ -35,6 +36,7 @@ Page({
|
||||
},
|
||||
|
||||
onToggleRegion: function (e) {
|
||||
if (this.data.selectedMode === 0) return
|
||||
var idx = e.currentTarget.dataset.idx
|
||||
var regions = this.data.regions
|
||||
regions[idx].checked = !regions[idx].checked
|
||||
@@ -47,7 +49,13 @@ Page({
|
||||
wx.navigateTo({ url: '/pages/subscribe-prompt/subscribe-prompt' })
|
||||
return
|
||||
}
|
||||
this.setData({ selectedMode: mode })
|
||||
var data = { selectedMode: mode }
|
||||
if (mode === 0) {
|
||||
var regions = this.data.regions
|
||||
regions.forEach(function (r) { r.checked = true })
|
||||
data.regions = regions
|
||||
}
|
||||
this.setData(data)
|
||||
},
|
||||
|
||||
onStart: function () {
|
||||
@@ -66,7 +74,7 @@ Page({
|
||||
|
||||
if (self.data.selectedMode === 1) {
|
||||
self.setData({ submitting: false })
|
||||
wx.navigateTo({ url: '/pages/auto-scan/auto-scan' })
|
||||
wx.navigateTo({ url: '/pages/auto-scan/auto-scan?regions=' + mask })
|
||||
return
|
||||
}
|
||||
|
||||
@@ -74,7 +82,7 @@ Page({
|
||||
region_mask: mask,
|
||||
wavelength: 2,
|
||||
brightness: 200,
|
||||
duration_ms: 600000,
|
||||
duration_ms: self.data.fixedDurationMs,
|
||||
mode: self.data.selectedMode
|
||||
}).then(function () {
|
||||
return ble.startTreatment(mask)
|
||||
@@ -83,7 +91,7 @@ Page({
|
||||
wx.redirectTo({
|
||||
url: '/pages/treating/treating?regions=' + mask +
|
||||
'&wavelength=2' +
|
||||
'&duration=600000' +
|
||||
'&duration=' + self.data.fixedDurationMs +
|
||||
'&mode=' + self.data.selectedMode
|
||||
})
|
||||
}).catch(function (err) {
|
||||
|
||||
@@ -22,13 +22,14 @@
|
||||
</view>
|
||||
|
||||
<view class="page-title" style="font-size:28rpx;">选择护理区域</view>
|
||||
<view class="mode-tip" wx:if="{{selectedMode === 0}}">普通模式固定 10 分钟,护理区域默认全脸,不可调整</view>
|
||||
|
||||
<view class="face-map">
|
||||
<view class="face-region forehead {{regions[2].checked ? 'active' : ''}}" bindtap="onToggleRegion" data-idx="2">额头</view>
|
||||
<view class="face-region left-cheek {{regions[0].checked ? 'active' : ''}}" bindtap="onToggleRegion" data-idx="0">左脸</view>
|
||||
<view class="face-region right-cheek {{regions[1].checked ? 'active' : ''}}" bindtap="onToggleRegion" data-idx="1">右脸</view>
|
||||
<view class="face-region nose {{regions[4].checked ? 'active' : ''}}" bindtap="onToggleRegion" data-idx="4">鼻唇</view>
|
||||
<view class="face-region chin {{regions[3].checked ? 'active' : ''}}" bindtap="onToggleRegion" data-idx="3">下巴</view>
|
||||
<view class="face-region forehead {{regions[2].checked ? 'active' : ''}} {{selectedMode === 0 ? 'disabled' : ''}}" bindtap="onToggleRegion" data-idx="2">额头</view>
|
||||
<view class="face-region left-cheek {{regions[0].checked ? 'active' : ''}} {{selectedMode === 0 ? 'disabled' : ''}}" bindtap="onToggleRegion" data-idx="0">左脸</view>
|
||||
<view class="face-region right-cheek {{regions[1].checked ? 'active' : ''}} {{selectedMode === 0 ? 'disabled' : ''}}" bindtap="onToggleRegion" data-idx="1">右脸</view>
|
||||
<view class="face-region nose {{regions[4].checked ? 'active' : ''}} {{selectedMode === 0 ? 'disabled' : ''}}" bindtap="onToggleRegion" data-idx="4">鼻唇</view>
|
||||
<view class="face-region chin {{regions[3].checked ? 'active' : ''}} {{selectedMode === 0 ? 'disabled' : ''}}" bindtap="onToggleRegion" data-idx="3">下巴</view>
|
||||
</view>
|
||||
|
||||
<button class="btn-primary" bindtap="onStart" disabled="{{submitting}}" loading="{{submitting}}">
|
||||
|
||||
@@ -74,6 +74,19 @@
|
||||
color: #E6508C;
|
||||
}
|
||||
|
||||
.face-region.disabled {
|
||||
border-color: #d8d8d8;
|
||||
background: #eeeeee;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.mode-tip {
|
||||
color: #999999;
|
||||
font-size: 24rpx;
|
||||
text-align: center;
|
||||
margin: -8rpx 0 20rpx;
|
||||
}
|
||||
|
||||
.face-region.forehead {
|
||||
top: 5%;
|
||||
left: 25%;
|
||||
|
||||
在新工单中引用
屏蔽一个用户