fix: onPageNotFound 兜底防空页崩溃 + 首页/记录页接入 i18n(语言切换覆盖全部3个tab)
这个提交包含在:
@@ -18,6 +18,15 @@ App({
|
|||||||
this.checkLogin()
|
this.checkLogin()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Safety net: if the framework ever tries to open an unknown/empty route
|
||||||
|
// (e.g. a stale page stack after the pages list changed), fall back to home
|
||||||
|
// instead of surfacing a hard "page not found" crash.
|
||||||
|
onPageNotFound: function (res) {
|
||||||
|
if (res && res.isEntryPage) {
|
||||||
|
wx.reLaunch({ url: '/pages/index/index', fail: function () {} })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
checkLogin: function () {
|
checkLogin: function () {
|
||||||
var token = wx.getStorageSync('token')
|
var token = wx.getStorageSync('token')
|
||||||
if (!token) {
|
if (!token) {
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// "记录" (history) page strings.
|
||||||
|
module.exports = {
|
||||||
|
zh: {
|
||||||
|
statTotal: '累计次数',
|
||||||
|
statHours: '累计时长',
|
||||||
|
statMonth: '本月次数',
|
||||||
|
recentTitle: '最近记录',
|
||||||
|
smart: '✨ 智能',
|
||||||
|
normal: '🔄 普通',
|
||||||
|
empty: '暂无使用记录',
|
||||||
|
loadingMore: '加载更多...',
|
||||||
|
durationMin: '{min}分钟',
|
||||||
|
today: '今天',
|
||||||
|
yesterday: '昨天',
|
||||||
|
dateMd: '{m}月{d}日'
|
||||||
|
},
|
||||||
|
en: {
|
||||||
|
statTotal: 'Total Sessions',
|
||||||
|
statHours: 'Total Hours',
|
||||||
|
statMonth: 'This Month',
|
||||||
|
recentTitle: 'Recent Records',
|
||||||
|
smart: '✨ Smart',
|
||||||
|
normal: '🔄 Normal',
|
||||||
|
empty: 'No records yet',
|
||||||
|
loadingMore: 'Loading more...',
|
||||||
|
durationMin: '{min} min',
|
||||||
|
today: 'Today',
|
||||||
|
yesterday: 'Yesterday',
|
||||||
|
dateMd: '{m}/{d}'
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
// "首页" (index) page strings.
|
||||||
|
module.exports = {
|
||||||
|
zh: {
|
||||||
|
noDevice: '还没有绑定设备',
|
||||||
|
addDevice: '扫码添加设备',
|
||||||
|
myDevice: '我的设备',
|
||||||
|
connected: '已连接',
|
||||||
|
disconnected: '未连接',
|
||||||
|
reconnect: '重新连接',
|
||||||
|
smartRemain: '智能模式 · 剩余{days}天',
|
||||||
|
notSubscribed: '未订阅智能模式',
|
||||||
|
smartOpen: '智能模式已开放',
|
||||||
|
start: '开始使用',
|
||||||
|
deviceManage: '设备管理',
|
||||||
|
connectFailed: '连接失败',
|
||||||
|
unbindAction: '解绑当前设备',
|
||||||
|
unbindConfirmTitle: '确认解绑',
|
||||||
|
unbindConfirmText: '解绑后将无法使用该设备,确定要解绑吗?',
|
||||||
|
unbindLoading: '解绑中...',
|
||||||
|
unbindDone: '已解绑',
|
||||||
|
unbindFailed: '解绑失败'
|
||||||
|
},
|
||||||
|
en: {
|
||||||
|
noDevice: 'No device bound yet',
|
||||||
|
addDevice: 'Scan to add device',
|
||||||
|
myDevice: 'My Device',
|
||||||
|
connected: 'Connected',
|
||||||
|
disconnected: 'Disconnected',
|
||||||
|
reconnect: 'Reconnect',
|
||||||
|
smartRemain: 'Smart Mode · {days} days left',
|
||||||
|
notSubscribed: 'Smart Mode not subscribed',
|
||||||
|
smartOpen: 'Smart Mode available',
|
||||||
|
start: 'Start',
|
||||||
|
deviceManage: 'Manage Device',
|
||||||
|
connectFailed: 'Connection failed',
|
||||||
|
unbindAction: 'Unbind current device',
|
||||||
|
unbindConfirmTitle: 'Confirm Unbind',
|
||||||
|
unbindConfirmText: 'You will not be able to use this device after unbinding. Continue?',
|
||||||
|
unbindLoading: 'Unbinding...',
|
||||||
|
unbindDone: 'Unbound',
|
||||||
|
unbindFailed: 'Unbind failed'
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,13 +7,17 @@ var profile = require('./profile')
|
|||||||
var lightInfo = require('./lightInfo')
|
var lightInfo = require('./lightInfo')
|
||||||
var manual = require('./manual')
|
var manual = require('./manual')
|
||||||
var report = require('./report')
|
var report = require('./report')
|
||||||
|
var home = require('./home')
|
||||||
|
var history = require('./history')
|
||||||
|
|
||||||
var namespaces = {
|
var namespaces = {
|
||||||
common: common,
|
common: common,
|
||||||
profile: profile,
|
profile: profile,
|
||||||
lightInfo: lightInfo,
|
lightInfo: lightInfo,
|
||||||
manual: manual,
|
manual: manual,
|
||||||
report: report
|
report: report,
|
||||||
|
home: home,
|
||||||
|
history: history
|
||||||
}
|
}
|
||||||
|
|
||||||
var zh = {}
|
var zh = {}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
var http = require('../../utils/request')
|
var http = require('../../utils/request')
|
||||||
var ble = require('../../services/ble')
|
var ble = require('../../services/ble')
|
||||||
|
var i18n = require('../../i18n/index')
|
||||||
|
|
||||||
Page({
|
Page({
|
||||||
data: {
|
data: {
|
||||||
@@ -15,6 +16,7 @@ Page({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onShow: function () {
|
onShow: function () {
|
||||||
|
i18n.bind(this)
|
||||||
this.loadRecords(true)
|
this.loadRecords(true)
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -52,7 +54,7 @@ Page({
|
|||||||
var records = (data.records || []).map(function (r) {
|
var records = (data.records || []).map(function (r) {
|
||||||
var durationMin = Math.floor((r.total_duration_ms || 0) / 60000)
|
var durationMin = Math.floor((r.total_duration_ms || 0) / 60000)
|
||||||
pageMs += (r.total_duration_ms || 0)
|
pageMs += (r.total_duration_ms || 0)
|
||||||
r.duration_text = durationMin + '分钟'
|
r.duration_text = i18n.t('history.durationMin', { min: durationMin })
|
||||||
r.region_names = ble.getRegionName(r.regions || 0).join('、')
|
r.region_names = ble.getRegionName(r.regions || 0).join('、')
|
||||||
r.wavelength_name = ble.getWavelengthName(r.wavelength || 2)
|
r.wavelength_name = ble.getWavelengthName(r.wavelength || 2)
|
||||||
r.date_text = self.formatDate(r.start_time || r.created_at)
|
r.date_text = self.formatDate(r.start_time || r.created_at)
|
||||||
@@ -89,8 +91,8 @@ Page({
|
|||||||
var h = ('0' + d.getHours()).slice(-2)
|
var h = ('0' + d.getHours()).slice(-2)
|
||||||
var m = ('0' + d.getMinutes()).slice(-2)
|
var m = ('0' + d.getMinutes()).slice(-2)
|
||||||
|
|
||||||
if (d >= today) return '今天 ' + h + ':' + m
|
if (d >= today) return i18n.t('history.today') + ' ' + h + ':' + m
|
||||||
if (d >= yesterday) return '昨天 ' + h + ':' + m
|
if (d >= yesterday) return i18n.t('history.yesterday') + ' ' + h + ':' + m
|
||||||
return (d.getMonth() + 1) + '月' + d.getDate() + '日 ' + h + ':' + m
|
return i18n.t('history.dateMd', { m: d.getMonth() + 1, d: d.getDate() }) + ' ' + h + ':' + m
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,31 +3,31 @@
|
|||||||
<view class="stats-row">
|
<view class="stats-row">
|
||||||
<view class="stat-card">
|
<view class="stat-card">
|
||||||
<view class="stat-value">{{total}}</view>
|
<view class="stat-value">{{total}}</view>
|
||||||
<view class="stat-label">累计次数</view>
|
<view class="stat-label">{{i18n.history.statTotal}}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="stat-card">
|
<view class="stat-card">
|
||||||
<view class="stat-value">{{totalHours}}h</view>
|
<view class="stat-value">{{totalHours}}h</view>
|
||||||
<view class="stat-label">累计时长</view>
|
<view class="stat-label">{{i18n.history.statHours}}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="stat-card">
|
<view class="stat-card">
|
||||||
<view class="stat-value">{{monthCount}}</view>
|
<view class="stat-value">{{monthCount}}</view>
|
||||||
<view class="stat-label">本月次数</view>
|
<view class="stat-label">{{i18n.history.statMonth}}</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="section-title">最近记录</view>
|
<view class="section-title">{{i18n.history.recentTitle}}</view>
|
||||||
|
|
||||||
<view class="record-item" wx:for="{{records}}" wx:key="session_id">
|
<view class="record-item" wx:for="{{records}}" wx:key="session_id">
|
||||||
<view class="record-date">{{item.date_text}}</view>
|
<view class="record-date">{{item.date_text}}</view>
|
||||||
<text class="record-mode {{item.mode === 1 ? 'smart' : 'normal'}}">{{item.mode === 1 ? '✨ 智能' : '🔄 普通'}}</text>
|
<text class="record-mode {{item.mode === 1 ? 'smart' : 'normal'}}">{{item.mode === 1 ? i18n.history.smart : i18n.history.normal}}</text>
|
||||||
<view class="record-details">{{item.duration_text}}</view>
|
<view class="record-details">{{item.duration_text}}</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="empty-state" wx:if="{{!loading && records.length === 0}}">
|
<view class="empty-state" wx:if="{{!loading && records.length === 0}}">
|
||||||
<text class="empty-icon">📃</text>
|
<text class="empty-icon">📃</text>
|
||||||
<view class="empty-text">暂无使用记录</view>
|
<view class="empty-text">{{i18n.history.empty}}</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="loading-more" wx:if="{{loadingMore}}">加载更多...</view>
|
<view class="loading-more" wx:if="{{loadingMore}}">{{i18n.history.loadingMore}}</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
var ble = require('../../services/ble')
|
var ble = require('../../services/ble')
|
||||||
var api = require('../../utils/api')
|
var api = require('../../utils/api')
|
||||||
|
var i18n = require('../../i18n/index')
|
||||||
var app = getApp()
|
var app = getApp()
|
||||||
|
|
||||||
Page({
|
Page({
|
||||||
@@ -17,6 +18,7 @@ Page({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onShow: function () {
|
onShow: function () {
|
||||||
|
i18n.bind(this)
|
||||||
this.checkState()
|
this.checkState()
|
||||||
this._onStatus = this.onBleStatus.bind(this)
|
this._onStatus = this.onBleStatus.bind(this)
|
||||||
this._onBattery = this.onBleBattery.bind(this)
|
this._onBattery = this.onBleBattery.bind(this)
|
||||||
@@ -69,9 +71,11 @@ Page({
|
|||||||
})
|
})
|
||||||
|
|
||||||
var p2 = api.getSubscription().then(function (sub) {
|
var p2 = api.getSubscription().then(function (sub) {
|
||||||
|
var remaining = sub.remaining_days || 0
|
||||||
self.setData({
|
self.setData({
|
||||||
subscription: sub,
|
subscription: sub,
|
||||||
subRemaining: sub.remaining_days || 0
|
subRemaining: remaining,
|
||||||
|
subRemainText: i18n.t('home.smartRemain', { days: remaining })
|
||||||
})
|
})
|
||||||
}).catch(function (err) {
|
}).catch(function (err) {
|
||||||
console.error('getSubscription failed', err)
|
console.error('getSubscription failed', err)
|
||||||
@@ -111,7 +115,7 @@ Page({
|
|||||||
},
|
},
|
||||||
onError: function (err) {
|
onError: function (err) {
|
||||||
self.setData({ connected: false, bleState: 'error' })
|
self.setData({ connected: false, bleState: 'error' })
|
||||||
wx.showToast({ title: err.msg || '连接失败', icon: 'none' })
|
wx.showToast({ title: err.msg || i18n.t('home.connectFailed'), icon: 'none' })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -123,12 +127,12 @@ Page({
|
|||||||
onManageDevice: function () {
|
onManageDevice: function () {
|
||||||
var self = this
|
var self = this
|
||||||
wx.showActionSheet({
|
wx.showActionSheet({
|
||||||
itemList: ['解绑当前设备'],
|
itemList: [i18n.t('home.unbindAction')],
|
||||||
success: function (res) {
|
success: function (res) {
|
||||||
if (res.tapIndex === 0) {
|
if (res.tapIndex === 0) {
|
||||||
wx.showModal({
|
wx.showModal({
|
||||||
title: '确认解绑',
|
title: i18n.t('home.unbindConfirmTitle'),
|
||||||
content: '解绑后将无法使用该设备,确定要解绑吗?',
|
content: i18n.t('home.unbindConfirmText'),
|
||||||
success: function (modalRes) {
|
success: function (modalRes) {
|
||||||
if (modalRes.confirm) {
|
if (modalRes.confirm) {
|
||||||
self.doUnbind()
|
self.doUnbind()
|
||||||
@@ -142,7 +146,7 @@ Page({
|
|||||||
|
|
||||||
doUnbind: function () {
|
doUnbind: function () {
|
||||||
var self = this
|
var self = this
|
||||||
wx.showLoading({ title: '解绑中...' })
|
wx.showLoading({ title: i18n.t('home.unbindLoading') })
|
||||||
ble.disconnect()
|
ble.disconnect()
|
||||||
api.unbindDevice().then(function () {
|
api.unbindDevice().then(function () {
|
||||||
wx.hideLoading()
|
wx.hideLoading()
|
||||||
@@ -152,10 +156,10 @@ Page({
|
|||||||
deviceInfo: null,
|
deviceInfo: null,
|
||||||
connected: false
|
connected: false
|
||||||
})
|
})
|
||||||
wx.showToast({ title: '已解绑', icon: 'success' })
|
wx.showToast({ title: i18n.t('home.unbindDone'), icon: 'success' })
|
||||||
}).catch(function (err) {
|
}).catch(function (err) {
|
||||||
wx.hideLoading()
|
wx.hideLoading()
|
||||||
wx.showToast({ title: err.message || '解绑失败', icon: 'none' })
|
wx.showToast({ title: err.message || i18n.t('home.unbindFailed'), icon: 'none' })
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,47 +1,47 @@
|
|||||||
<view class="page">
|
<view class="page">
|
||||||
<view class="loading-container" wx:if="{{loading}}">
|
<view class="loading-container" wx:if="{{loading}}">
|
||||||
<view class="loading-spinner"></view>
|
<view class="loading-spinner"></view>
|
||||||
<text class="loading-text">加载中...</text>
|
<text class="loading-text">{{i18n.common.loading}}</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="page-content" wx:if="{{!loading && !hasDevice}}">
|
<view class="page-content" wx:if="{{!loading && !hasDevice}}">
|
||||||
<view class="empty-device">
|
<view class="empty-device">
|
||||||
<text class="empty-icon">📱</text>
|
<text class="empty-icon">📱</text>
|
||||||
<view class="empty-text">还没有绑定设备</view>
|
<view class="empty-text">{{i18n.home.noDevice}}</view>
|
||||||
<button class="btn-primary mt-30" bindtap="onAddDevice">扫码添加设备</button>
|
<button class="btn-primary mt-30" bindtap="onAddDevice">{{i18n.home.addDevice}}</button>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="page-content" wx:if="{{!loading && hasDevice}}">
|
<view class="page-content" wx:if="{{!loading && hasDevice}}">
|
||||||
<view class="device-card">
|
<view class="device-card">
|
||||||
<view class="device-card-icon">💆</view>
|
<view class="device-card-icon">💆</view>
|
||||||
<view class="device-card-name">{{deviceName || '我的设备'}}</view>
|
<view class="device-card-name">{{deviceName || i18n.home.myDevice}}</view>
|
||||||
<view class="device-card-status">
|
<view class="device-card-status">
|
||||||
<text class="status-badge status-badge-green" wx:if="{{connected}}">已连接</text>
|
<text class="status-badge status-badge-green" wx:if="{{connected}}">{{i18n.home.connected}}</text>
|
||||||
<text class="status-badge" style="background:#ccc;" wx:else>未连接</text>
|
<text class="status-badge" style="background:#ccc;" wx:else>{{i18n.home.disconnected}}</text>
|
||||||
<text class="device-card-battery" wx:if="{{connected}}">🔋 {{battery}}%</text>
|
<text class="device-card-battery" wx:if="{{connected}}">🔋 {{battery}}%</text>
|
||||||
</view>
|
</view>
|
||||||
<button class="btn-reconnect" bindtap="onConnectBle" wx:if="{{!connected}}">重新连接</button>
|
<button class="btn-reconnect" bindtap="onConnectBle" wx:if="{{!connected}}">{{i18n.home.reconnect}}</button>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="sub-info" bindtap="onViewSubscription" wx:if="{{!subscription || subscription.plan !== 'free'}}">
|
<view class="sub-info" bindtap="onViewSubscription" wx:if="{{!subscription || subscription.plan !== 'free'}}">
|
||||||
<view class="sub-info-left">
|
<view class="sub-info-left">
|
||||||
<text class="sub-info-icon">💳</text>
|
<text class="sub-info-icon">💳</text>
|
||||||
<text wx:if="{{subscription && subscription.status === 'active'}}">智能模式 · 剩余{{subRemaining}}天</text>
|
<text wx:if="{{subscription && subscription.status === 'active'}}">{{subRemainText}}</text>
|
||||||
<text wx:else>未订阅智能模式</text>
|
<text wx:else>{{i18n.home.notSubscribed}}</text>
|
||||||
</view>
|
</view>
|
||||||
<text class="sub-info-arrow">›</text>
|
<text class="sub-info-arrow">›</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="sub-info" wx:if="{{subscription && subscription.plan === 'free'}}">
|
<view class="sub-info" wx:if="{{subscription && subscription.plan === 'free'}}">
|
||||||
<view class="sub-info-left">
|
<view class="sub-info-left">
|
||||||
<text class="sub-info-icon">✨</text>
|
<text class="sub-info-icon">✨</text>
|
||||||
<text>智能模式已开放</text>
|
<text>{{i18n.home.smartOpen}}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="action-buttons">
|
<view class="action-buttons">
|
||||||
<button class="btn-primary" bindtap="onStartTreatment">开始使用</button>
|
<button class="btn-primary" bindtap="onStartTreatment">{{i18n.home.start}}</button>
|
||||||
<button class="btn-secondary" bindtap="onManageDevice">设备管理</button>
|
<button class="btn-secondary" bindtap="onManageDevice">{{i18n.home.deviceManage}}</button>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
在新工单中引用
屏蔽一个用户