Files
hhrs/pages/index/index.vue
T
jacobxu666 745f4bf5f1 fix: 修复登录失败被当成功、列表假分页与首页裁切等隐患
1. 登录/验证码改判业务码 data.code(外层 errcode 恒为0),失败不再写入 phone 造成假登录态,并透出后端真实原因;倒计时改为发送成功后才启动;token 按 accessToken 兜底读取,不再写入 undefined

2. 权益包三 Tab 由 pageSize=1000 的假分页改为真实分页 + 页面级触底加载,各 Tab 独立游标与请求序号,合并去重兜底;中奖名单页码改为按期维护,修复切期后重复追加

3. 首页去掉整页 overflow:hidden,小屏不再裁切活动指南卡片;接口表去重并清理 7 个废弃端点;基址/客服电话集中到 common/config.js;删除权益详情不可达的假成功分支
2026-09-14 23:38:13 +08:00

278 lines
6.9 KiB
Vue

<template>
<view class="page">
<!-- 顶部 Banner -->
<view class="banner">
<image class="banner-img" src="https://aliyunoss.hn12301.net/hhrs/hhrs_header.png" mode="widthFix"></image>
</view>
<!-- 金刚区 -->
<view class="king-area">
<view class="king-item" v-for="(item, index) in kingList" :key="index" @click="item.isRights ? goRights() : goPage(item.url)">
<image class="king-icon" :src="item.icon" mode="widthFix"></image>
<text class="king-text">{{ item.text }}</text>
</view>
</view>
<!-- 活动指南 -->
<view class="guide-section">
<view class="section-title">
<view class="title-line"></view>
<text class="title-text">活动指南</text>
</view>
<view class="guide-list">
<view class="guide-card" v-for="(item, index) in guideList" :key="index" @click="goPage(item.url)">
<image class="guide-bg" :src="item.bg" mode="scaleToFill"></image>
<view class="guide-info">
<text class="guide-title">{{ item.title }}</text>
<text class="guide-sub">{{ item.sub }}</text>
<view class="guide-tag">官方指南</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
kingList: [
{ icon: 'https://aliyunoss.hn12301.net/hhrs/hhrs_wlcg.png', text: '文旅场馆', url: '/pages/venue/venue' },
{ icon: 'https://aliyunoss.hn12301.net/hhrs/hhrs_shzk.png', text: '商户折扣', url: '/pages/discount/discount' },
{ icon: 'https://aliyunoss.hn12301.net/hhrs/hhrs_qyb.png', text: '权益包', url: '/pages/rights/rights', isRights: true },
{ icon: 'https://aliyunoss.hn12301.net/hhrs/hhrs_zjmd.png', text: '中奖名单', url: '/pages/winners/winners' }
],
guideList: [
{
title: '怀化社保卡惠民活动参加指南',
sub: '本地文旅场馆、商户惠民福利',
bg: 'https://aliyunoss.hn12301.net/hhrs/hhrs_cjzn.png',
url: '/pages/guide/join'
},
{
title: '社保卡领取及使用指南',
sub: '全流程办理及激活指引',
bg: 'https://aliyunoss.hn12301.net/hhrs/hhrs_syzn.png',
url: '/pages/guide/use'
}
]
}
},
onLoad(options) {
if (options.token) {
this.handleTokenLogin(options.token)
}
this.getLocation()
},
methods: {
// xuchao: 云闪付入口 token 自动登录
handleTokenLogin(token) {
this.$u.api.tokenDecode({ token }).then(res => {
if (res.errcode === 0 && res.data && res.data.mobile) {
uni.setStorageSync('phone', res.data.mobile)
this.$u.api.getEligibility({ phone: res.data.mobile, identityNo: res.data.idNo || '', name: res.data.name || '' }).then(eRes => {
if (eRes.errcode === 0) {
uni.setStorageSync('isAuth', eRes.data.isAuth)
uni.setStorageSync('hasWin', eRes.data.hasWin)
uni.setStorageSync('cardNumber', eRes.data.cardNumber)
uni.setStorageSync('expiresTime', eRes.data.expiresTime)
}
})
// xuchao: 清除地址栏 token,防止分享泄露
this.clearUrlToken()
} else {
this.degradeToPhoneLogin()
}
}).catch(() => {
this.degradeToPhoneLogin()
})
},
// xuchao: 解码失败兜底,提示并跳手机号登录
degradeToPhoneLogin() {
uni.showToast({ title: '登录凭证已失效,请使用手机号登录', icon: 'none' })
setTimeout(() => {
uni.navigateTo({ url: '/pages/index/login' })
}, 800)
},
// xuchao: 从 URL hash 中移除 token 参数
clearUrlToken() {
try {
const hash = window.location.hash || ''
const qIndex = hash.indexOf('?')
if (qIndex === -1) return
const params = new URLSearchParams(hash.substring(qIndex + 1))
if (!params.has('token')) return
params.delete('token')
const rest = params.toString()
const base = hash.substring(0, qIndex)
window.history.replaceState(null, '', rest ? `${base}?${rest}` : base)
} catch (e) {}
},
getLocation() {
import('@/common/location.js').then(module => {
module.default.getLocation().then(({ lng, lat }) => {
console.log('定位成功:', lng, lat)
}).catch(err => {
console.log('定位失败:', err)
})
})
},
goPage(url) {
uni.navigateTo({ url })
},
goRights() {
const phone = uni.getStorageSync('phone')
if (!phone) {
uni.navigateTo({ url: '/pages/index/login?redirect=rights' })
return
}
const isAuth = uni.getStorageSync('isAuth')
const hasWin = uni.getStorageSync('hasWin')
// xuchao: 最近发起过认证流程(含取消)时忽略旧认证缓存,一律回认证页
const authFlowStarted = uni.getStorageSync('authFlowStarted')
let status = 'auth'
if (isAuth && !authFlowStarted) {
status = hasWin ? 'info' : 'noWin'
}
uni.navigateTo({ url: `/pages/rights/rights?status=${status}` })
}
}
}
</script>
<style>
/* xuchao: 原 page/.page 固定 100vh + overflow:hidden,小屏下活动指南第二张卡片会被裁掉且无法滚动;
改为 min-height 撑满、超出可滚动,视觉在正常屏上保持不变 */
.page {
min-height: 100vh;
background-color: #f5f5f5;
display: flex;
flex-direction: column;
}
.banner-img {
width: 100%;
display: block;
}
/* 金刚区 */
.king-area {
width: 100%;
display: flex;
justify-content: space-between;
align-items: flex-start;
background-color: #ffffff;
padding: 24rpx;
box-sizing: border-box;
}
.king-item {
width: 25%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.king-icon {
width: 100rpx;
height: 132rpx;
margin-bottom: 12rpx;
}
.king-text {
font-size: 24rpx;
color: #333333;
text-align: center;
}
/* 活动指南 */
.guide-section {
flex: 1;
background-color: #ffffff;
margin-top: 10rpx;
display: flex;
flex-direction: column;
}
.section-title {
display: flex;
align-items: center;
margin-bottom: 20rpx;
padding: 24rpx 20rpx 0 24px;
}
.title-line {
width: 6rpx;
height: 32rpx;
background-color: #1890ff;
border-radius: 3rpx;
margin-right: 12rpx;
}
.title-text {
font-size: 14px;
font-weight: 600;
color: #333333;
}
.guide-list {
display: flex;
flex-direction: column;
gap: 12px;
padding: 0 20rpx 30rpx;
}
.guide-card {
position: relative;
width: 100%;
height: 252rpx;
border-radius: 16rpx;
overflow: hidden;
}
.guide-bg {
width: 100%;
height: 252rpx;
border-radius: 16rpx;
}
.guide-info {
position: absolute;
top: 0;
left: 0;
display: flex;
flex-direction: column;
justify-content: center;
width: 100%;
height: 100%;
padding: 0 30rpx;
}
.guide-title {
font-size: 16px;
font-weight: 600;
color: #0088FF;
margin-bottom: 10rpx;
}
.guide-sub {
font-size: 12px;
color: #949AA0;
margin-bottom: 16rpx;
}
.guide-tag {
display: inline-block;
width: fit-content;
padding: 4px 10px;
background-color: #e6f2ff;
color: #0088FF;
font-size: 12px;
border-radius: 6rpx;
}
</style>