feat: complete feature gaps across all modules

Server:
- Add settings-cache with 60s TTL for feature toggle checks
- Enforce maintenance_mode on login, enable_binding on device bind

Admin console:
- Remove dead "发送通知" button from user detail
- Firmware check calls real API and compares versions

Miniprogram:
- Wear-check: dynamic battery/connected from BLE state
- Login: hide non-functional phone auth button
- Treating: show actual selected regions instead of hardcoded "全脸"
- Index: display subscription status with tap to manage
- Auto-scan: show "待检测" instead of "--" for PD data
- Agreements: tap shows "内容建设中" modal
这个提交包含在:
Guoguo
2026-05-02 08:48:26 -07:00
父节点 1017fb5dae
当前提交 031678c03f
修改 17 个文件,包含 116 行新增12 行删除
+1 -1
查看文件
@@ -65,7 +65,7 @@ Page({
parseScanResults: function (regions) {
return regions.map(function (name) {
return { region: name, pd: '--' }
return { region: name, pd: '待检测' }
})
},
@@ -15,6 +15,7 @@
</view>
<view class="scan-hint">请将面罩对准面部</view>
<view class="scan-hint" style="font-size:24rpx;color:#999;margin-top:8rpx;">连接设备后可获取皮肤数据</view>
<view class="debug-actions" wx:if="{{devMode}}">
<view class="debug-label">🔧 调试工具</view>
+9
查看文件
@@ -23,6 +23,15 @@
</view>
</view>
<view class="sub-info" bindtap="onViewSubscription">
<view class="sub-info-left">
<text class="sub-info-icon">💳</text>
<text wx:if="{{subscription && subscription.status === 'active'}}">智能模式 · 剩余{{subRemaining}}天</text>
<text wx:else>未订阅智能模式</text>
</view>
<text class="sub-info-arrow"></text>
</view>
<button class="btn-primary" bindtap="onStartTreatment">开始护理</button>
<button class="btn-secondary" bindtap="onManageDevice">设备管理</button>
</view>
+24
查看文件
@@ -18,3 +18,27 @@
.btn-secondary::after {
border: none;
}
.sub-info {
display: flex;
justify-content: space-between;
align-items: center;
background: #fff;
border-radius: 16rpx;
padding: 24rpx;
margin-top: 20rpx;
}
.sub-info-left {
display: flex;
align-items: center;
gap: 12rpx;
font-size: 28rpx;
color: #333;
}
.sub-info-icon {
font-size: 32rpx;
}
.sub-info-arrow {
color: #999;
font-size: 32rpx;
}
+4
查看文件
@@ -65,6 +65,10 @@ Page({
})
},
onAgreement: function () {
wx.showModal({ title: '提示', content: '用户协议和隐私政策内容建设中', showCancel: false })
},
onGetPhoneNumber: function (e) {
var self = this
if (!e.detail || !e.detail.code) {
+2 -2
查看文件
@@ -18,10 +18,10 @@
</button>
<!-- 手机号授权已预留。需要时展示该按钮并隐藏上面的普通登录按钮。 -->
<button class="phone-btn disabled-phone-btn" open-type="getPhoneNumber" bindgetphonenumber="onGetPhoneNumber" disabled="{{loading}}">
<button wx:if="{{false}}" class="phone-btn disabled-phone-btn" open-type="getPhoneNumber" bindgetphonenumber="onGetPhoneNumber" disabled="{{loading}}">
授权手机号登录(预留)
</button>
<view class="agreement">登录即表示同意《用户协议》和《隐私政策》</view>
<view class="agreement" bindtap="onAgreement">登录即表示同意《用户协议》和《隐私政策》</view>
</view>
</view>
@@ -91,6 +91,10 @@ Page({
}).catch(function () {})
},
onAgreement: function () {
wx.showModal({ title: '提示', content: '订阅协议内容建设中', showCancel: false })
},
onSelect: function (e) {
this.setData({ selected: e.currentTarget.dataset.plan })
},
@@ -40,6 +40,6 @@
<button class="btn-primary btn-primary-gold" bindtap="onPurchase" disabled="{{purchasing}}" loading="{{purchasing}}">
{{subscription && subscription.status === 'active' && subRemaining > 0 ? '续费' : '确认支付'}}
</button>
<view class="agreement">支付即表示同意《订阅协议》</view>
<view class="agreement" bindtap="onAgreement">支付即表示同意《订阅协议》</view>
</view>
</view>
+15 -2
查看文件
@@ -18,19 +18,32 @@ Page({
completed: false,
startedAt: 0,
devMode: false,
regionText: '全脸护理',
},
_getRegionText: function (regionMask) {
var REGION_MAP = {1:'左脸', 2:'右脸', 4:'额头', 8:'下巴', 16:'鼻', 32:'左眼', 64:'右眼'}
if (regionMask === 0x7F) return '全脸护理'
var names = []
for (var bit in REGION_MAP) {
if (regionMask & parseInt(bit)) names.push(REGION_MAP[bit])
}
return names.length > 0 ? names.join('+') + '护理' : '全脸护理'
},
onLoad: function (options) {
var app = getApp()
this.setData({ statusBarHeight: app.globalData.statusBarHeight, devMode: config.__DEV__ || false })
this._deviceId = ble.getDeviceId() || (app.globalData.currentDevice && app.globalData.currentDevice.device_id) || ''
var regions = parseInt(options.regions) || 0x7F
this.setData({
regions: parseInt(options.regions) || 0x7F,
regions: regions,
wavelength: parseInt(options.wavelength) || 2,
duration: parseInt(options.duration) || 600000,
mode: parseInt(options.mode) || 0,
remainingMs: parseInt(options.duration) || 600000,
startedAt: Date.now()
startedAt: Date.now(),
regionText: this._getRegionText(regions)
})
this._onStatus = this.onStatus.bind(this)
+1 -1
查看文件
@@ -16,7 +16,7 @@
</view>
<view class="mode-tag-area">
<text class="mode-tag">{{mode === 1 ? '✨ 智能模式' : '🔄 普通模式'}} · 全脸护理</text>
<text class="mode-tag">{{mode === 1 ? '✨ 智能模式' : '🔄 普通模式'}} · {{regionText}}</text>
</view>
<view class="relax-card">
+11 -1
查看文件
@@ -7,7 +7,9 @@ Page({
checking: false,
result: null,
error: '',
devMode: false
devMode: false,
battery: 0,
connected: false
},
onBack: function () {
@@ -21,6 +23,11 @@ Page({
onLoad: function () {
var app = getApp()
this.setData({ statusBarHeight: app.globalData.statusBarHeight, devMode: config.__DEV__ || false })
var device = app.globalData.currentDevice || {}
this.setData({
battery: device.battery || 0,
connected: ble.isConnected()
})
},
onShow: function () {
@@ -34,6 +41,9 @@ Page({
if (this._onStatus) ble.off('status', this._onStatus)
this._onStatus = function (status) {
self.setData({ checking: false })
if (status.battery !== undefined) {
self.setData({ battery: status.battery, connected: true })
}
if (status.bind_status === 1) {
self.setData({ result: 'ok' })
} else {
+3 -2
查看文件
@@ -11,9 +11,10 @@
<view class="device-row-info">
<view class="device-row-name">
光子美容仪
<text class="status-badge status-badge-green">已连接</text>
<text class="status-badge status-badge-green" wx:if="{{connected}}">已连接</text>
<text class="status-badge" style="background:#ccc;" wx:else>未连接</text>
</view>
<view class="device-row-battery">电量 85%</view>
<view class="device-row-battery">电量 {{battery}}%</view>
</view>
</view>