diff --git a/pages/mine/mine.js b/pages/mine/mine.js
index 83467d4..a81cf29 100644
--- a/pages/mine/mine.js
+++ b/pages/mine/mine.js
@@ -46,7 +46,8 @@ Page({
this.setData({
profile: p,
maskedPhone: maskPhone(phone),
- authStatusText: authStatusText(st)
+ authStatusText: authStatusText(st),
+ authStatus: st
});
})
.catch(() => {});
diff --git a/pages/mine/mine.json b/pages/mine/mine.json
index 68522ed..4b5d0ce 100644
--- a/pages/mine/mine.json
+++ b/pages/mine/mine.json
@@ -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"
+ }
}
diff --git a/pages/mine/mine.wxml b/pages/mine/mine.wxml
index 6e246f9..41ce1b2 100644
--- a/pages/mine/mine.wxml
+++ b/pages/mine/mine.wxml
@@ -5,32 +5,25 @@
-
+
-
+
+
- 📷
+
{{maskedPhone}}
-
-
@@ -45,39 +38,39 @@
{{profile.certificateCount || 0}}
- 我的证书
+ 我的证书
-
身份认证
点击进行身份认证
-
- 🛡
+
+
{{authStatusText}}
-
-
-
-
-
- 我的订单
+
+
+
-
-
- 参赛记录
+
-
-
- 我的团队
+
-
-
+
\ No newline at end of file
diff --git a/pages/mine/mine.wxss b/pages/mine/mine.wxss
index 4820ea5..8bb332c 100644
--- a/pages/mine/mine.wxss
+++ b/pages/mine/mine.wxss
@@ -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;
}
diff --git a/subpackages/mine/auth/auth.wxml b/subpackages/mine/auth/auth.wxml
index 0b9def2..0557557 100644
--- a/subpackages/mine/auth/auth.wxml
+++ b/subpackages/mine/auth/auth.wxml
@@ -22,16 +22,18 @@
-
-
+
+
上传身份证人像面
-
-
+
+
上传身份证国徽面
@@ -41,8 +43,7 @@
-
-
+
上传护照
@@ -53,17 +54,17 @@
姓名
-
+
身份证号
-
+
出生日期
-
+
{{birthDate || '请选择'}}
@@ -77,10 +78,10 @@
联系电话
-
-
+
+
{{countdown>0 ? countdown + 's' : '发送验证码'}}
-
+
diff --git a/subpackages/mine/auth/auth.wxss b/subpackages/mine/auth/auth.wxss
index 93ec013..19b940d 100644
--- a/subpackages/mine/auth/auth.wxss
+++ b/subpackages/mine/auth/auth.wxss
@@ -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 {
diff --git a/subpackages/mine/login/login.js b/subpackages/mine/login/login.js
index ac246f8..4e80b8b 100644
--- a/subpackages/mine/login/login.js
+++ b/subpackages/mine/login/login.js
@@ -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) => {
diff --git a/subpackages/mine/login/login.wxss b/subpackages/mine/login/login.wxss
index 9312324..3132b3d 100644
--- a/subpackages/mine/login/login.wxss
+++ b/subpackages/mine/login/login.wxss
@@ -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;
}
diff --git a/subpackages/mine/points/points.js b/subpackages/mine/points/points.js
index 8c833c8..9140c0f 100644
--- a/subpackages/mine/points/points.js
+++ b/subpackages/mine/points/points.js
@@ -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({
diff --git a/subpackages/mine/register/register.wxss b/subpackages/mine/register/register.wxss
index 3fb3bc3..faa841d 100644
--- a/subpackages/mine/register/register.wxss
+++ b/subpackages/mine/register/register.wxss
@@ -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;
}
diff --git a/utils/auth.js b/utils/auth.js
index 02d0d1b..828b920 100644
--- a/utils/auth.js
+++ b/utils/auth.js
@@ -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
};
diff --git a/utils/constants.js b/utils/constants.js
index 66a279f..fdf1654 100644
--- a/utils/constants.js
+++ b/utils/constants.js
@@ -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',
diff --git a/utils/http.js b/utils/http.js
index 90e1026..14befa9 100644
--- a/utils/http.js
+++ b/utils/http.js
@@ -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);
}
});