|
|
@@ -51,6 +51,16 @@
|
|
|
<text class="form-label">消耗卡路里(选填)</text>
|
|
|
<input class="form-input" type="number" v-model="form.caloriesBurned" placeholder="估算卡路里" />
|
|
|
</view>
|
|
|
+ <view class="form-group" v-if="isSelfCheckin">
|
|
|
+ <text class="form-label">微信步数(选填)</text>
|
|
|
+ <view class="step-sync-row">
|
|
|
+ <input class="form-input step-input" type="number" v-model="form.stepCount" placeholder="手动填写步数" />
|
|
|
+ <view class="sync-btn" :class="{'syncing': syncingSteps}" @tap="syncWechatSteps">
|
|
|
+ <text>{{ syncingSteps ? '同步中…' : '同步微信步数' }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <text class="step-hint" v-if="syncedStepText">{{ syncedStepText }}</text>
|
|
|
+ </view>
|
|
|
<view class="form-group">
|
|
|
<text class="form-label">备注(选填)</text>
|
|
|
<input class="form-input" v-model="form.remark" placeholder="运动感受..." />
|
|
|
@@ -126,7 +136,7 @@
|
|
|
<view class="history-item" v-for="item in history" :key="item.id">
|
|
|
<view class="history-left">
|
|
|
<text class="history-type">{{ exerciseTypeLabel(item.exerciseType) }}</text>
|
|
|
- <text class="history-content">{{ item.durationMinutes }}分钟{{ item.caloriesBurned ? ' · ' + item.caloriesBurned + '千卡' : '' }}</text>
|
|
|
+ <text class="history-content">{{ item.durationMinutes }}分钟{{ item.caloriesBurned ? ' · ' + item.caloriesBurned + '千卡' : '' }}{{ item.stepCount ? ' · ' + item.stepCount + '步' : '' }}</text>
|
|
|
</view>
|
|
|
<view class="history-right">
|
|
|
<text class="history-date">{{ formatDate(item.createdAt) }}</text>
|
|
|
@@ -151,7 +161,10 @@ export default {
|
|
|
data() {
|
|
|
return {
|
|
|
memberId: null,
|
|
|
+ isSelfCheckin: false,
|
|
|
submitting: false,
|
|
|
+ syncingSteps: false,
|
|
|
+ syncedStepText: '',
|
|
|
isRecording: false,
|
|
|
recordSeconds: 0,
|
|
|
recordTimer: null,
|
|
|
@@ -176,6 +189,7 @@ export default {
|
|
|
durationMinutes: '',
|
|
|
intensity: 'medium',
|
|
|
caloriesBurned: '',
|
|
|
+ stepCount: '',
|
|
|
remark: '',
|
|
|
photos: [],
|
|
|
voicePath: '',
|
|
|
@@ -195,6 +209,7 @@ export default {
|
|
|
if (role !== 'child') {
|
|
|
this.memberId = uni.getStorageSync('currentChildId') || uni.getStorageSync('currentMemberId') || uni.getStorageSync('userId') || null
|
|
|
}
|
|
|
+ this.isSelfCheckin = uni.getStorageSync('currentView') !== 'member'
|
|
|
this.recorderManager = uni.getRecorderManager()
|
|
|
this.recorderManager.onStart(() => {
|
|
|
this.isRecording = true
|
|
|
@@ -292,6 +307,77 @@ export default {
|
|
|
deleteVoice: function() {
|
|
|
this.form.voicePath = ''
|
|
|
},
|
|
|
+ syncWechatSteps: function() {
|
|
|
+ var self = this
|
|
|
+ if (self.syncingSteps) return
|
|
|
+ wx.getSetting({
|
|
|
+ success: function(res) {
|
|
|
+ var setting = res.authSetting
|
|
|
+ if (setting && setting['scope.werun'] === false) {
|
|
|
+ uni.showModal({
|
|
|
+ title: '需要授权',
|
|
|
+ content: '请去设置中开启「微信运动」授权后重试',
|
|
|
+ confirmText: '去设置',
|
|
|
+ success: function(m) {
|
|
|
+ if (m.confirm) uni.openSetting()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ self.doGetWeRunData()
|
|
|
+ },
|
|
|
+ fail: function() {
|
|
|
+ self.doGetWeRunData()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ doGetWeRunData: function() {
|
|
|
+ var self = this
|
|
|
+ self.syncingSteps = true
|
|
|
+ wx.getWeRunData({
|
|
|
+ success: function(res) {
|
|
|
+ var token = uni.getStorageSync('token')
|
|
|
+ uni.request({
|
|
|
+ url: config.API_BASE_URL + '/api/health/exercise/sync-wechat-steps',
|
|
|
+ method: 'POST',
|
|
|
+ data: { encryptedData: res.encryptedData, iv: res.iv },
|
|
|
+ header: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token },
|
|
|
+ success: function(r) {
|
|
|
+ self.syncingSteps = false
|
|
|
+ if (r.data && r.data.code === 200 && r.data.data) {
|
|
|
+ var step = r.data.data.stepCount
|
|
|
+ self.form.stepCount = step
|
|
|
+ self.syncedStepText = '已同步今日步数:' + step + ' 步'
|
|
|
+ uni.showToast({ title: '同步成功', icon: 'success' })
|
|
|
+ } else {
|
|
|
+ var msg = (r.data && r.data.message) || '同步失败'
|
|
|
+ uni.showToast({ title: msg, icon: 'none' })
|
|
|
+ }
|
|
|
+ },
|
|
|
+ fail: function() {
|
|
|
+ self.syncingSteps = false
|
|
|
+ uni.showToast({ title: '网络错误', icon: 'none' })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ fail: function(err) {
|
|
|
+ self.syncingSteps = false
|
|
|
+ var errMsg = err && err.errMsg || ''
|
|
|
+ if (errMsg.indexOf('auth') >= 0 || errMsg.indexOf('denied') >= 0) {
|
|
|
+ uni.showModal({
|
|
|
+ title: '需要授权',
|
|
|
+ content: '请在微信「设置-隐私-授权管理」中开启微信运动权限',
|
|
|
+ confirmText: '去设置',
|
|
|
+ success: function(m) {
|
|
|
+ if (m.confirm) uni.openSetting()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: '获取微信步数失败,请先开启微信运动', icon: 'none' })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
uploadFile: function(filePath) {
|
|
|
var self = this
|
|
|
return new Promise(function(resolve, reject) {
|
|
|
@@ -340,12 +426,14 @@ export default {
|
|
|
remark: self.form.remark || '',
|
|
|
photoUrls: photoUrls.join(','),
|
|
|
voiceUrl: voiceUrl,
|
|
|
- voiceText: self.form.voiceText || ''
|
|
|
+ voiceText: self.form.voiceText || '',
|
|
|
+ stepCount: self.form.stepCount ? parseInt(self.form.stepCount) : null
|
|
|
},
|
|
|
header: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token },
|
|
|
success: function(res) {
|
|
|
if (res.data && res.data.code === 200) {
|
|
|
uni.showToast({ title: '打卡成功', icon: 'success' })
|
|
|
+ self.syncedStepText = ''
|
|
|
setTimeout(function() {
|
|
|
uni.navigateBack()
|
|
|
}, 800)
|
|
|
@@ -392,6 +480,12 @@ export default {
|
|
|
.tag-btn text { font-size: 26rpx; color: #666; }
|
|
|
.tag-active text { color: #F97316; font-weight: 600; }
|
|
|
.form-input { width: 100%; height: 76rpx; border: 1rpx solid #e8e8e8; border-radius: 14rpx; padding: 0 16rpx; font-size: 26rpx; background: #FAFAFA; box-sizing: border-box; }
|
|
|
+.step-sync-row { display: flex; align-items: center; gap: 12rpx; }
|
|
|
+.step-input { flex: 1; }
|
|
|
+.sync-btn { padding: 12rpx 28rpx; border-radius: 30rpx; border: 2rpx solid #F97316; background: #FFF3E0; transition: all 0.2s ease; flex-shrink: 0; }
|
|
|
+.sync-btn text { font-size: 24rpx; color: #F97316; font-weight: 500; }
|
|
|
+.syncing { opacity: 0.5; }
|
|
|
+.step-hint { font-size: 22rpx; color: #10B981; margin-top: 6rpx; display: block; }
|
|
|
|
|
|
/* ===== 媒体工具栏 ===== */
|
|
|
.media-toolbar { display: flex; align-items: center; gap: 0; padding: 12rpx 0; }
|