Files
wxapp_escort/pages/mine/mine.js
T
2026-10-06 17:58:18 +08:00

262 lines
8.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const API = require('../../utils/api.js')
Page({
data: {
userInfo: {
// 留空表示"没有真头像",模板据此渲染暖橙实心底 + 白色 user 线标的默认头像
// (与首页 .brand-mark 同源)。默认头像不走位图:位图着色读不到 CSS 变量,
// 改主色时须整图重上色(见 DESIGN.md §7.3),用 t-icon + 令牌则自动跟随
avatar: '',
name: '用户',
// 身份行副行,loadUserInfo 时由手机号脱敏填入
account: '',
phone: '',
sex: '',
birth: '',
email: '',
idnumber: '',
ssn: '',
isLoggedIn: false
},
// 菜单分组:按"用途"而非"是不是陪诊"分,三组才立得住。
// 图标与首页同目的地同图形(同一含义只对应一个表达,从色值延伸到图标):
// 预约记录 calendar-1、就诊人 user-checked、联系我们 call 均与首页一致。
// requiresLogin 的组在未登录时整组隐藏——这些入口都依赖用户身份
menuGroups: [{
groupName: '我的服务',
requiresLogin: true,
items: [{
// 陪诊产品的「我的」页核心是订单,故排全页第一项
name: '预约记录',
icon: 'calendar-1',
bindtap: 'onTapEscortRecord'
}, {
name: '就诊人',
icon: 'user-checked',
bindtap: 'onTapHealth'
}, {
name: '邮寄地址',
icon: 'location',
bindtap: 'onTapAddress'
}]
}, {
groupName: '帮助与支持',
requiresLogin: false,
items: [{
name: '联系我们',
icon: 'call',
bindtap: 'onTapContact'
}, {
// 口径统一为「服务指南」(首页区块标题行、列表页说明卡都用此名),
// 不另起「陪诊指南」这一第三叫法;与列表页「服务指南 │ 用户协议」同一配对
name: '服务指南',
icon: 'book-open',
bindtap: 'onTapGuide'
}, {
name: '用户协议',
icon: 'secured',
bindtap: 'onTapAgreement'
}]
}, {
groupName: '其他',
requiresLogin: false,
items: [{
name: '关于我们',
icon: 'info-circle',
bindtap: 'onTapAboutUs'
}]
}]
},
onLoad() {
this.loadUserInfo()
},
onShow() {
this.loadUserInfo()
// 同步自定义 tabBar 选中态(我的为第 2 项)
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
this.getTabBar().setData({
selected: 2
})
}
},
loadUserInfo() {
const app = getApp()
if (app.globalData.user && app.globalData.user.profile) {
const profile = app.globalData.user.profile
this.setData({
'userInfo.isLoggedIn': true,
'userInfo.name': profile.name || '用户',
// 头像补读后端返回值;取不到留空,由模板渲染暖橙默认头像。
// 注:profileedit 页里新选的图目前不会落库——utils/api.js 没有文件上传接口,
// 微信返回的是本地临时路径,存进库里也会失效,所以这里只修"显示"这一半
'userInfo.avatar': profile.avatar || '',
'userInfo.phone': profile.mobile || '',
// 身份行副行(微信那行是微信号):本应用没有账号体系,
// 等价标识是手机号,脱敏成 138****1234 后再上屏
'userInfo.account': this.maskMobile(profile.mobile || ''),
'userInfo.sex': profile.sex || '',
'userInfo.birth': profile.birth ? this.formatDate(profile.birth) : '',
'userInfo.email': profile.email || '',
'userInfo.idnumber': profile.idnumber || '',
'userInfo.ssn': profile.ssn || ''
})
} else {
// 未登录(含刚退出登录):身份行收敛回默认态。
// 少了这个分支,globalData.user 被清空后页面仍停在"已登录"的样子——
// 「我的服务」组和退出块都不会消失
this.setData({
'userInfo.isLoggedIn': false,
'userInfo.avatar': '',
'userInfo.name': '用户',
'userInfo.account': '',
'userInfo.phone': ''
})
}
},
// 手机号脱敏:11 位取前三后四;位数不符时原样返回,不制造错位星号
maskMobile(mobile) {
const digits = String(mobile).replace(/\D/g, '')
if (digits.length !== 11) return mobile || ''
return `${digits.slice(0, 3)}****${digits.slice(7)}`
},
formatDate(date) {
if (!date) return ''
const d = new Date(date)
const year = d.getFullYear()
const month = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
},
// 顶部身份行整行可点,但未登录时不该跳进"填完才被拦"的资料页
// (个人信息与邮寄地址改真页面后系统返回键归页面栈管,
// 不再像原来的浮层那样被系统返回键直接退出小程序)
onTapProfile() {
if (!this.data.userInfo.isLoggedIn) return
wx.navigateTo({
url: '/pages/mine/profileedit'
})
},
onTapAddress() {
wx.navigateTo({
url: '/pages/mine/addressedit'
})
},
onTapHealth() {
wx.navigateTo({
url: '/pages/health/profilelist'
})
},
onTapEscortRecord() {
wx.navigateTo({
url: '/pages/escort/recordlist'
})
},
// 帮助与支持:联系我们(页面已存在,与首页「常用功能」同目的地)
onTapContact() {
wx.navigateTo({
url: '/pages/mine/contact'
})
},
// 帮助与支持:服务指南(与首页区块标题行、列表页说明卡同一页面)
onTapGuide() {
wx.navigateTo({
url: '/pages/escort/guide'
})
},
// 帮助与支持:用户协议(与陪诊服务列表页的「用户协议」同一页面)
onTapAgreement() {
wx.navigateTo({
url: '/pages/escort/agreement'
})
},
onTapAboutUs() {
wx.navigateTo({
url: '/pages/mine/about'
})
},
// 页脚 B 端合作链接:暂无独立页面,统一转接人工客服
onFooterTap() {
wx.makePhoneCall({
phoneNumber: '18618162956'
})
},
// 退出登录:二次确认 → 调后端登出 → 清全局与本地缓存
onLogout() {
wx.showModal({
title: '退出登录',
content: '退出后需要重新授权手机号,才能查看预约记录与就诊人',
confirmText: '退出',
// confirmColor 是属性值,读不到 CSS 变量,取值须与令牌同步(DESIGN.md §5.1)
confirmColor: '#B8520A',
success: (res) => {
if (!res.confirm) return
wx.showLoading({ title: '退出中...' })
// 必须先调接口:token 由 request.js 从 globalData.user 里取,
// 先清全局对象就带不上 token 了
API.user.signout({})
.then(() => this.doLogout())
// 接口失败也要把本地退干净,不把用户卡在"已登录"的假象里
.catch(() => this.doLogout())
.finally(() => wx.hideLoading())
}
})
},
doLogout() {
const app = getApp()
app.globalData.user = null
wx.removeStorageSync('user_phonenumber')
// 落一个"已主动退出"标记:app.js 的 onShow 每次都会静默重登
// (wxsignin 只凭 code 换 openid 即可重新签发 token),不拦这一下,
// 退出就形同虚设——切后台再回来又变成登录态
wx.setStorageSync('has_logout', true)
this.loadUserInfo()
wx.showToast({ title: '已退出登录', icon: 'success' })
},
handleLogin(e) {
const phoneCode = e.detail.code ? e.detail.code : ''
API.user.wxGetPhoneNumber({ code: phoneCode })
.then((data) => {
const phoneNumber = data.data.phoneNumber
wx.setStorageSync('user_phonenumber', phoneNumber)
wx.login({
success: (res) => {
if (res.code) {
API.user.wxSignin({ phoneNumber, phoneCode, code: res.code })
.then((data) => {
if (data.code == 0) {
const app = getApp()
app.globalData.user = data.data.user
// 用户重新授权登录,解除对静默重登的拦截
wx.removeStorageSync('has_logout')
this.loadUserInfo()
}
})
} else {
console.log('登录失败!' + res.errMsg)
}
}
})
})
.catch((err) => {
wx.showToast({ title: '网络请求失败', icon: 'none' })
console.log('请求失败', err)
})
}
})