update:add
This commit is contained in:
parent
75753df0bb
commit
a99924c229
@ -46,7 +46,8 @@ Page({
|
||||
this.setData({
|
||||
profile: p,
|
||||
maskedPhone: maskPhone(phone),
|
||||
authStatusText: authStatusText(st)
|
||||
authStatusText: authStatusText(st),
|
||||
authStatus: st
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
|
||||
@ -1,4 +1,8 @@
|
||||
{
|
||||
"navigationStyle": "custom",
|
||||
"enablePullDownRefresh": true
|
||||
"enablePullDownRefresh": true,
|
||||
"usingComponents": {
|
||||
"mp-navigation-bar": "weui-miniprogram/navigation-bar/navigation-bar",
|
||||
"mp-icon": "weui-miniprogram/icon/icon"
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,32 +5,25 @@
|
||||
<button class="go-login-btn" bindtap="goToLogin">去登录</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 已登录 -->
|
||||
<view wx:else class="mine-page">
|
||||
<!-- 蓝色头部区域 -->
|
||||
<view class="header">
|
||||
<view class="header-bg"></view>
|
||||
<view class="status-bar"></view>
|
||||
<view class="nav-bar">
|
||||
<text class="nav-title">我的</text>
|
||||
</view>
|
||||
<!-- 头像 + 手机号 -->
|
||||
<image class="header-bg" src="https://yuedong-wechatapplet.oss-cn-shanghai.aliyuncs.com/static/event_miniapp/bg.png" mode="aspectFill" />
|
||||
<view class="header-mask"></view>
|
||||
<mp-navigation-bar title="我的" background-color="transparent" color="#fff" back="{{false}}"></mp-navigation-bar>
|
||||
</view>
|
||||
<!-- 头像 + 手机号 -->
|
||||
<view class="profile-section">
|
||||
<view class="avatar-wrap" bindtap="onChooseAvatar">
|
||||
<image
|
||||
class="avatar"
|
||||
src="{{profile.avatar || '/assets/tab_mine.png'}}"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
<!-- profile.avatar || -->
|
||||
<image class="avatar" src="https://q6.itc.cn/q_70/images03/20250306/355fba6a5cb049f5b98c2ed9f03cc5e1.jpeg" mode="aspectFill" />
|
||||
<view class="camera-icon">
|
||||
<text class="camera-text">📷</text>
|
||||
<image src="https://yuedong-wechatapplet.oss-cn-shanghai.aliyuncs.com/static/event_miniapp/camera.png" mode="aspectFit" />
|
||||
</view>
|
||||
</view>
|
||||
<text class="phone-text">{{maskedPhone}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 内容区 -->
|
||||
<view class="content">
|
||||
<!-- 积分 & 证书双卡 -->
|
||||
@ -45,39 +38,39 @@
|
||||
<view class="stat-card" bindtap="goToCert">
|
||||
<view class="stat-left">
|
||||
<text class="stat-num">{{profile.certificateCount || 0}}</text>
|
||||
<text class="stat-label">我的证书</text>
|
||||
<text class="stat-label" style="color: #F4D053;">我的证书</text>
|
||||
</view>
|
||||
<image class="stat-icon" src="https://yuedong-wechatapplet.oss-cn-shanghai.aliyuncs.com/static/event_miniapp/book.png" mode="aspectFit" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 身份认证条 -->
|
||||
<view class="auth-bar" bindtap="goToAuth">
|
||||
<view class="auth-left">
|
||||
<text class="auth-title">身份认证</text>
|
||||
<text class="auth-desc">点击进行身份认证</text>
|
||||
</view>
|
||||
<view class="auth-badge">
|
||||
<text class="auth-badge-icon">🛡</text>
|
||||
<view class="auth-badge auth-badge-{{authStatus === 1 ? 'y' : 'n'}}">
|
||||
<image class="auth-badge-icon" src="https://yuedong-wechatapplet.oss-cn-shanghai.aliyuncs.com/static/event_miniapp/auth-{{authStatus === 1 ? 'y' : 'n'}}.png" mode="aspectFit" />
|
||||
<text class="auth-badge-text">{{authStatusText}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 功能入口 -->
|
||||
<view class="func-card">
|
||||
<view class="func-item" bindtap="goToOrders">
|
||||
<image class="func-icon" src="https://yuedong-wechatapplet.oss-cn-shanghai.aliyuncs.com/static/event_miniapp/order.png" mode="aspectFit" />
|
||||
<text class="func-text">我的订单</text>
|
||||
<!-- 功能入口:三个独立阴影卡片 -->
|
||||
<view class="func-list">
|
||||
<view class="func-menu-card" bindtap="goToOrders">
|
||||
<image class="func-menu-icon" src="https://yuedong-wechatapplet.oss-cn-shanghai.aliyuncs.com/static/event_miniapp/order.png" mode="aspectFit" />
|
||||
<text class="func-menu-text">我的订单</text>
|
||||
<text class="func-menu-arrow">›</text>
|
||||
</view>
|
||||
<view class="func-item" bindtap="goToRecords">
|
||||
<image class="func-icon" src="https://yuedong-wechatapplet.oss-cn-shanghai.aliyuncs.com/static/event_miniapp/history.png" mode="aspectFit" />
|
||||
<text class="func-text">参赛记录</text>
|
||||
<view class="func-menu-card" bindtap="goToRecords">
|
||||
<image class="func-menu-icon" src="https://yuedong-wechatapplet.oss-cn-shanghai.aliyuncs.com/static/event_miniapp/history.png" mode="aspectFit" />
|
||||
<text class="func-menu-text">参赛记录</text>
|
||||
<text class="func-menu-arrow">›</text>
|
||||
</view>
|
||||
<view class="func-item" bindtap="goToTeam">
|
||||
<image class="func-icon" src="https://yuedong-wechatapplet.oss-cn-shanghai.aliyuncs.com/static/event_miniapp/team.png" mode="aspectFit" />
|
||||
<text class="func-text">我的团队</text>
|
||||
<view class="func-menu-card" bindtap="goToTeam">
|
||||
<image class="func-menu-icon" src="https://yuedong-wechatapplet.oss-cn-shanghai.aliyuncs.com/static/event_miniapp/team.png" mode="aspectFit" />
|
||||
<text class="func-menu-text">我的团队</text>
|
||||
<text class="func-menu-arrow">›</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
@ -39,52 +39,44 @@
|
||||
/* ====== 已登录页面 ====== */
|
||||
.mine-page {
|
||||
min-height: 100vh;
|
||||
background: #f0f2f5;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* ====== 蓝色头部 ====== */
|
||||
.header {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
overflow: visible;
|
||||
height: 340rpx;
|
||||
overflow: hidden;
|
||||
border-radius: 0 0 100rpx 100rpx;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.header-bg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 520rpx;
|
||||
background: linear-gradient(180deg, #1a3a8a 0%, #1a57b2 100%);
|
||||
border-radius: 0 0 40rpx 40rpx;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.status-bar {
|
||||
height: env(safe-area-inset-top, 44px);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nav-bar {
|
||||
position: relative;
|
||||
height: 88rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.nav-title {
|
||||
font-size: 34rpx;
|
||||
font-weight: 600;
|
||||
color: #ffffff;
|
||||
.header-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(26, 86, 219, 0.55);
|
||||
}
|
||||
|
||||
/* ====== 头像区 ====== */
|
||||
.profile-section {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 20rpx 0 40rpx;
|
||||
/* padding: 20rpx 0 40rpx; */
|
||||
margin-bottom: 80rpx;
|
||||
margin-top: -70px;
|
||||
}
|
||||
|
||||
.avatar-wrap {
|
||||
@ -97,17 +89,17 @@
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 50%;
|
||||
border: 6rpx solid rgba(255, 255, 255, 0.4);
|
||||
border: 2rpx solid rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.camera-icon {
|
||||
position: absolute;
|
||||
right: 4rpx;
|
||||
bottom: 4rpx;
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
right: -4rpx;
|
||||
bottom: -4rpx;
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
background: #1a57b2;
|
||||
border: 4rpx solid #fff;
|
||||
/* border: 4rpx solid #fff; */
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -118,12 +110,15 @@
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.auth-badge-icon {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
.phone-text {
|
||||
margin-top: 16rpx;
|
||||
font-size: 32rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #ffffff;
|
||||
letter-spacing: 2rpx;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/* ====== 内容区 ====== */
|
||||
@ -144,13 +139,21 @@
|
||||
flex: 1;
|
||||
background: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
padding: 28rpx 24rpx;
|
||||
padding: 6rpx 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.stat-card:first-child {
|
||||
background: linear-gradient(135deg, #A6ADEF 0%, #00000000 100%);
|
||||
}
|
||||
|
||||
.stat-card:last-child {
|
||||
background: linear-gradient(135deg, #E5CD6790 0%, #00000000 100%);
|
||||
}
|
||||
|
||||
.stat-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -165,20 +168,22 @@
|
||||
|
||||
.stat-label {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
color: #313666;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
width: 154rpx;
|
||||
height: 154rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* ====== 身份认证条 ====== */
|
||||
.auth-bar {
|
||||
margin-top: 20rpx;
|
||||
background: linear-gradient(135deg, #1a3a8a 0%, #1a57b2 100%);
|
||||
/* background: linear-gradient(135deg, #1a3a8a 0%, #1a57b2 100%); */
|
||||
background: url('https://yuedong-wechatapplet.oss-cn-shanghai.aliyuncs.com/static/event_miniapp/idcard-bg.png');
|
||||
background-size: 100% 100%;
|
||||
border-radius: 16rpx;
|
||||
padding: 28rpx 30rpx;
|
||||
display: flex;
|
||||
@ -207,47 +212,65 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 30rpx;
|
||||
padding: 10rpx 24rpx;
|
||||
background: linear-gradient(135deg, #ECEBEB 0%, #AEAEAE 100%);
|
||||
border-radius: 34rpx;
|
||||
width: 180rpx;
|
||||
height: 64rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
/* padding: 10rpx 24rpx; */
|
||||
}
|
||||
|
||||
.auth-badge-icon {
|
||||
font-size: 28rpx;
|
||||
.auth-badge-y {
|
||||
background: linear-gradient(135deg, #E5A84D 0%, #CC8213 100%);
|
||||
}
|
||||
|
||||
|
||||
|
||||
.auth-badge-text {
|
||||
font-size: 24rpx;
|
||||
color: #ffffff;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* ====== 功能入口卡 ====== */
|
||||
.func-card {
|
||||
/* ====== 功能入口:三个独立阴影卡片 ====== */
|
||||
.func-list {
|
||||
margin-top: 20rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
padding: 36rpx 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.func-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.func-menu-card {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 14rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
padding: 28rpx 28rpx 28rpx 24rpx;
|
||||
box-shadow: 0 8rpx 28rpx rgba(26, 87, 178, 0.08), 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.func-icon {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
.func-menu-icon {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.func-text {
|
||||
.func-menu-text {
|
||||
flex: 1;
|
||||
margin-left: 24rpx;
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
color: #1a1a1a;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.func-menu-arrow {
|
||||
flex-shrink: 0;
|
||||
font-size: 40rpx;
|
||||
line-height: 1;
|
||||
color: #c8c8c8;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
|
||||
@ -22,16 +22,18 @@
|
||||
<view class="upload-box" bindtap="onChooseImage" data-kind="idFront">
|
||||
<image class="upload-img" wx:if="{{idCardImageUrl}}" src="{{idCardImageUrl}}" mode="aspectFill" />
|
||||
<view wx:else class="upload-placeholder">
|
||||
<view class="ph-lines"></view>
|
||||
<view class="ph-user"></view>
|
||||
<!-- <view class="ph-lines"></view>
|
||||
<view class="ph-user"></view> -->
|
||||
<image class="ph-img" src="https://yuedong-wechatapplet.oss-cn-shanghai.aliyuncs.com/static/event_miniapp/idcard-top.png" />
|
||||
</view>
|
||||
<text class="upload-text">上传身份证人像面</text>
|
||||
</view>
|
||||
<view class="upload-box" bindtap="onChooseImage" data-kind="idBack">
|
||||
<image class="upload-img" wx:if="{{idCardBackImageUrl}}" src="{{idCardBackImageUrl}}" mode="aspectFill" />
|
||||
<view wx:else class="upload-placeholder">
|
||||
<view class="ph-lines"></view>
|
||||
<view class="ph-user"></view>
|
||||
<!-- <view class="ph-lines"></view>
|
||||
<view class="ph-user"></view> -->
|
||||
<image class="ph-img" src="https://yuedong-wechatapplet.oss-cn-shanghai.aliyuncs.com/static/event_miniapp/idcard-back.png" />
|
||||
</view>
|
||||
<text class="upload-text">上传身份证国徽面</text>
|
||||
</view>
|
||||
@ -41,8 +43,7 @@
|
||||
<view class="upload-box single" bindtap="onChooseImage" data-kind="passport">
|
||||
<image class="upload-img" wx:if="{{passportImageUrl}}" src="{{passportImageUrl}}" mode="aspectFill" />
|
||||
<view wx:else class="upload-placeholder">
|
||||
<view class="ph-lines"></view>
|
||||
<view class="ph-user"></view>
|
||||
<image class="ph-img" src="https://yuedong-wechatapplet.oss-cn-shanghai.aliyuncs.com/static/event_miniapp/idcard-top.png" />
|
||||
</view>
|
||||
<text class="upload-text">上传护照</text>
|
||||
</view>
|
||||
@ -53,17 +54,17 @@
|
||||
<view class="card form-card">
|
||||
<view class="form-row">
|
||||
<text class="label">姓名</text>
|
||||
<input class="input {{readonlyName ? 'readonly' : ''}}" value="{{name}}" placeholder="自动识别 / 可手动填写" disabled="{{readonlyName}}" bindinput="onNameInput" />
|
||||
<input class="input {{readonlyName ? 'readonly' : ''}}" value="{{name}}" placeholder="自动识别 " disabled="{{true}}" bindinput="onNameInput" />
|
||||
</view>
|
||||
|
||||
<view wx:if="{{activeTab === 1}}" class="form-row">
|
||||
<text class="label">身份证号</text>
|
||||
<input class="input {{readonlyId ? 'readonly' : ''}}" value="{{idCardNumber}}" placeholder="自动识别 / 可手动填写" disabled="{{readonlyId}}" bindinput="onIdInput" />
|
||||
<input class="input {{readonlyId ? 'readonly' : ''}}" value="{{idCardNumber}}" placeholder="自动识别 " disabled="{{true}}" bindinput="onIdInput" />
|
||||
</view>
|
||||
|
||||
<view wx:if="{{activeTab === 2}}" class="form-row">
|
||||
<text class="label">出生日期</text>
|
||||
<picker mode="date" value="{{birthDate}}" bindchange="onBirthChange">
|
||||
<picker mode="date" value="{{birthDate}}" disabled="{{true}}" bindchange="onBirthChange">
|
||||
<view class="picker-value {{birthDate ? '' : 'placeholder'}}">{{birthDate || '请选择'}}</view>
|
||||
</picker>
|
||||
</view>
|
||||
@ -77,10 +78,10 @@
|
||||
|
||||
<view class="form-row">
|
||||
<text class="label">联系电话</text>
|
||||
<input class="input" value="{{mobile}}" placeholder="手机号" type="number" maxlength="11" bindinput="onMobileInput" />
|
||||
<text class="send-code {{countdown>0 || codeSending ? 'disabled' : ''}}" bindtap="onSendCodeTap">
|
||||
<input class="input" disabled="{{true}}" value="{{mobile}}" placeholder="手机号" type="number" maxlength="11" />
|
||||
<view class="send-code {{countdown>0 || codeSending ? 'disabled' : ''}}" bindtap="onSendCodeTap">
|
||||
{{countdown>0 ? countdown + 's' : '发送验证码'}}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-row">
|
||||
|
||||
@ -2,6 +2,10 @@ page {
|
||||
background: #f5f7fa;
|
||||
}
|
||||
|
||||
view{
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.auth-page {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
@ -73,6 +77,11 @@ page {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ph-img {
|
||||
width: 280rpx;
|
||||
height: 160rpx;
|
||||
}
|
||||
|
||||
.upload-card {
|
||||
padding: 22rpx;
|
||||
}
|
||||
@ -84,6 +93,8 @@ page {
|
||||
|
||||
.upload-row.single {
|
||||
justify-content: center;
|
||||
width: 70%;
|
||||
margin-left: 15%;
|
||||
}
|
||||
|
||||
.upload-box {
|
||||
@ -116,6 +127,9 @@ page {
|
||||
background: #eef2ff;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.ph-lines {
|
||||
|
||||
@ -158,7 +158,7 @@ Page({
|
||||
.then(() => {
|
||||
wx.showToast({ title: '登录成功', icon: 'success' });
|
||||
setTimeout(() => {
|
||||
wx.redirectTo({ url: '/pages/mine/mine' });
|
||||
wx.switchTab({ url: '/pages/mine/mine' });
|
||||
}, 400);
|
||||
})
|
||||
.catch((err) => {
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
.header {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 440rpx;
|
||||
height: 360rpx;
|
||||
overflow: hidden;
|
||||
border-radius: 0 0 100rpx 100rpx;
|
||||
margin-bottom: 40rpx;
|
||||
@ -28,7 +28,7 @@
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(26, 86, 219, 0.55);
|
||||
background: rgba(26, 87, 178, 0.85);
|
||||
}
|
||||
|
||||
/* 导航栏 */
|
||||
@ -80,17 +80,17 @@
|
||||
}
|
||||
|
||||
.welcome-text {
|
||||
font-size: 48rpx;
|
||||
font-size: 46rpx;
|
||||
color: #ffffff;
|
||||
/* font-weight: 700; */
|
||||
letter-spacing: 2rpx;
|
||||
margin-right: 30rpx;
|
||||
margin-right: 50rpx;
|
||||
}
|
||||
|
||||
.logo-img {
|
||||
width: 108rpx;
|
||||
height: 108rpx;
|
||||
border-radius: 20rpx;
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 40rpx;
|
||||
background: #fff;
|
||||
padding: 10rpx;
|
||||
}
|
||||
|
||||
@ -69,14 +69,12 @@ Page({
|
||||
const { pageNo, activeTab } = this.data;
|
||||
|
||||
return auth
|
||||
.fetchMyPoints({ pageNo, pageSize: PAGE_SIZE })
|
||||
.fetchMyPoints({ pageNo, pageSize: PAGE_SIZE, type: activeTab })
|
||||
.then((result) => {
|
||||
const res = result || {};
|
||||
const allRows = res.rows || [];
|
||||
// 按类型筛选: type 1=获取 2=消耗
|
||||
const filtered = allRows.filter((item) => item.type === activeTab);
|
||||
const allRows = res.rows || res.list || res.items || [];
|
||||
|
||||
const formatted = filtered.map((item) => ({
|
||||
const formatted = allRows.map((item) => ({
|
||||
...item,
|
||||
createdTimeStr: item.createdTime ? formatTime(item.createdTime) : '',
|
||||
projectInfo: item.projectInfo || item.projectName || '',
|
||||
@ -84,7 +82,7 @@ Page({
|
||||
}));
|
||||
|
||||
const newRecords = this.data.records.concat(formatted);
|
||||
const totalRows = res.total || 0;
|
||||
const totalRows = res.total || res.totalCount || 0;
|
||||
const currentTotal = pageNo * PAGE_SIZE;
|
||||
|
||||
this.setData({
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
.header {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 440rpx;
|
||||
height: 360rpx;
|
||||
overflow: hidden;
|
||||
border-radius: 0 0 100rpx 100rpx;
|
||||
margin-bottom: 40rpx;
|
||||
@ -31,7 +31,8 @@
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(26, 86, 219, 0.55);
|
||||
background: rgba(26, 87, 178, 0.85);
|
||||
|
||||
}
|
||||
|
||||
/* 导航栏 */
|
||||
@ -82,16 +83,17 @@
|
||||
}
|
||||
|
||||
.welcome-text {
|
||||
font-size: 48rpx;
|
||||
font-size: 46rpx;
|
||||
color: #ffffff;
|
||||
/* font-weight: 700; */
|
||||
letter-spacing: 2rpx;
|
||||
margin-right: 30rpx;
|
||||
margin-right: 50rpx;
|
||||
}
|
||||
|
||||
.logo-img {
|
||||
width: 108rpx;
|
||||
height: 108rpx;
|
||||
border-radius: 20rpx;
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 40rpx;
|
||||
background: #fff;
|
||||
padding: 10rpx;
|
||||
}
|
||||
|
||||
@ -5,6 +5,49 @@ function pickString(obj, key) {
|
||||
return obj && typeof obj[key] === 'string' ? obj[key] : '';
|
||||
}
|
||||
|
||||
let refreshPromise = null;
|
||||
|
||||
async function refreshAccessToken() {
|
||||
if (refreshPromise) return refreshPromise;
|
||||
|
||||
const app = getApp();
|
||||
const storedRefreshToken = wx.getStorageSync('refreshToken') || '';
|
||||
const globalRefreshToken = app && app.globalData ? app.globalData.refreshToken : '';
|
||||
const refreshToken = typeof globalRefreshToken === 'string' && globalRefreshToken.length > 0 ? globalRefreshToken : storedRefreshToken;
|
||||
|
||||
if (!refreshToken) throw new Error('refreshAccessToken: missing refreshToken');
|
||||
|
||||
refreshPromise = (async () => {
|
||||
const tokenData = await request({
|
||||
path: API.oauthRefreshToken,
|
||||
method: 'POST',
|
||||
needAuth: false,
|
||||
data: { refreshToken },
|
||||
contentType: 'application/json'
|
||||
});
|
||||
|
||||
const accessToken = pickString(tokenData, 'accessToken');
|
||||
const nextRefreshToken = pickString(tokenData, 'refreshToken') || refreshToken;
|
||||
|
||||
if (!accessToken) throw new Error('refreshAccessToken: missing accessToken');
|
||||
|
||||
app.setAuth({
|
||||
accessToken,
|
||||
refreshToken: nextRefreshToken
|
||||
});
|
||||
|
||||
return {
|
||||
accessToken,
|
||||
refreshToken: nextRefreshToken,
|
||||
tokenData
|
||||
};
|
||||
})().finally(() => {
|
||||
refreshPromise = null;
|
||||
});
|
||||
|
||||
return refreshPromise;
|
||||
}
|
||||
|
||||
async function loginWithMobilePassword({ mobile, password }) {
|
||||
const loginData = await request({
|
||||
path: API.wechatLogin,
|
||||
@ -140,7 +183,7 @@ async function resetPassword({ mobile, password, verificationCode }) {
|
||||
path: API.oauthResetPassword,
|
||||
method: 'POST',
|
||||
needAuth: false,
|
||||
data: { mobile, password, verificationCode },
|
||||
data: { mobile, newPassword: password, verificationCode },
|
||||
contentType: 'application/json'
|
||||
});
|
||||
}
|
||||
@ -187,15 +230,32 @@ async function fetchMyRegistrations({ pageNo = 1, pageSize = 10 } = {}) {
|
||||
});
|
||||
}
|
||||
|
||||
async function fetchMyPoints({ pageNo = 1, pageSize = 10 } = {}) {
|
||||
async function fetchMyPoints({
|
||||
pageNo = 1,
|
||||
pageSize = 10,
|
||||
// 新接口参数(按 swagger):1=获取,2=消耗,不传查全部
|
||||
type,
|
||||
// 单位认证ID筛选,不传查全部
|
||||
merchantCertificationId,
|
||||
// 兼容旧调用方:也可能传 Type / MerchantCertificationId
|
||||
Type,
|
||||
MerchantCertificationId
|
||||
} = {}) {
|
||||
const t = type != null ? type : Type;
|
||||
const mcId = merchantCertificationId != null ? merchantCertificationId : MerchantCertificationId;
|
||||
|
||||
const data = {
|
||||
PageNo: pageNo,
|
||||
PageSize: pageSize
|
||||
};
|
||||
if (t != null && t !== '') data.Type = t;
|
||||
if (mcId != null && mcId !== '') data.MerchantCertificationId = mcId;
|
||||
|
||||
return request({
|
||||
path: API.myPoints,
|
||||
method: 'GET',
|
||||
needAuth: true,
|
||||
data: {
|
||||
PageNo: pageNo,
|
||||
PageSize: pageSize
|
||||
}
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
@ -226,5 +286,6 @@ module.exports = {
|
||||
submitMyAuth,
|
||||
fetchMyRegistrations,
|
||||
fetchMyPoints,
|
||||
fetchMyCertificates
|
||||
fetchMyCertificates,
|
||||
refreshAccessToken
|
||||
};
|
||||
|
||||
@ -12,6 +12,8 @@ const API = {
|
||||
|
||||
wechatLogin: '/api/oauth/login',
|
||||
loginByCode: '/api/oauth/login',
|
||||
// Refresh token endpoint (请按后端实际接口路径修改)
|
||||
oauthRefreshToken: '/api/oauth/refresh-token',
|
||||
oauthRegister: '/api/oauth/register',
|
||||
oauthResetPassword: '/api/oauth/reset-password',
|
||||
sendVerificationCode: '/api/sms/sendverificationcode',
|
||||
|
||||
@ -4,9 +4,12 @@ function withAuthHeader(needAuth, header) {
|
||||
const app = getApp();
|
||||
if (!needAuth) return header;
|
||||
const token = app && app.globalData ? app.globalData.accessToken : '';
|
||||
const refreshToken = app && app.globalData ? app.globalData.refreshToken : '';
|
||||
if (typeof token === 'string' && token.length > 0) {
|
||||
header = header || {};
|
||||
header.Authorization = `Bearer ${token}`;
|
||||
header['x-access-token'] = `Bearer ${token}`;
|
||||
header['x-refresh-token'] = `Bearer ${refreshToken}`;
|
||||
}
|
||||
return header;
|
||||
}
|
||||
@ -20,12 +23,41 @@ function normalizeError(payload) {
|
||||
return new Error(JSON.stringify(payload));
|
||||
}
|
||||
|
||||
function getHeaderValue(headers, headerName) {
|
||||
if (!headers || typeof headers !== 'object') return '';
|
||||
const target = String(headerName || '').toLowerCase();
|
||||
for (const k in headers) {
|
||||
if (Object.prototype.hasOwnProperty.call(headers, k) && String(k).toLowerCase() === target) {
|
||||
const v = headers[k];
|
||||
return typeof v === 'string' ? v : '';
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function tryUpdateAccessTokenFromResponseHeaders(res) {
|
||||
// wx.request 的返回头在 res.header(部分环境也可能是 res.headers)
|
||||
const headers = (res && res.header) || (res && res.headers) || null;
|
||||
const newAccessToken = getHeaderValue(headers, 'x-access-token');
|
||||
if (!newAccessToken) return;
|
||||
|
||||
const app = getApp();
|
||||
if (app && typeof app.setAuth === 'function') {
|
||||
app.setAuth({ accessToken: newAccessToken });
|
||||
} else {
|
||||
wx.setStorageSync('accessToken', newAccessToken);
|
||||
if (app && app.globalData) app.globalData.accessToken = newAccessToken;
|
||||
}
|
||||
}
|
||||
|
||||
function request({
|
||||
path,
|
||||
method = 'GET',
|
||||
data = {},
|
||||
needAuth = false,
|
||||
contentType = 'application/json'
|
||||
contentType = 'application/json',
|
||||
// Internal flag: prevent infinite retry when refresh token也失败
|
||||
__retry = false
|
||||
}) {
|
||||
const baseUrl = getBaseUrl();
|
||||
const url = `${baseUrl}${path}`;
|
||||
@ -41,6 +73,9 @@ function request({
|
||||
data: method.toUpperCase() === 'GET' ? data : data,
|
||||
header: header,
|
||||
success(res) {
|
||||
// 如果后端在 Response Headers 下发新的 token,就替换本地 token
|
||||
tryUpdateAccessTokenFromResponseHeaders(res);
|
||||
|
||||
const payload = res && res.data !== undefined ? res.data : null;
|
||||
|
||||
// Most backend uses RESTfulResult wrapper
|
||||
@ -54,6 +89,27 @@ function request({
|
||||
resolve(payload);
|
||||
},
|
||||
fail(err) {
|
||||
if (err && err.statusCode === 401 && needAuth && !__retry) {
|
||||
// 401: try refresh token, then retry the original request once.
|
||||
const originalErr = err;
|
||||
try {
|
||||
const auth = require('./auth');
|
||||
if (auth && typeof auth.refreshAccessToken === 'function') {
|
||||
auth
|
||||
.refreshAccessToken()
|
||||
.then(() => {
|
||||
return request({ path, method, data, needAuth, contentType, __retry: true });
|
||||
})
|
||||
.then(resolve)
|
||||
.catch(() => {
|
||||
reject(originalErr);
|
||||
});
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore and fall through to rejecting original error
|
||||
}
|
||||
}
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user