diff --git a/.gitignore b/.gitignore
index 6e5335f..bfeaeff 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
unpackage/
node_modules/
.DS_Store
+.playwright-mcp/
diff --git a/App.vue b/App.vue
index 9bb63c7..2f80017 100644
--- a/App.vue
+++ b/App.vue
@@ -14,4 +14,13 @@
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000..d5544a4
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,30 @@
+# CLAUDE.md
+
+## 项目概览
+
+怀化人社 H5(hhrs)—— 基于 uni-app 构建的移动端 H5 前端,入口 `pages/`,UI 依赖 `uview-ui`。属于 12301-dscp 项目群中的「怀化人社」H5 端。
+
+## Git 规范
+
+- 独立 git 仓库,远程:`https://git.hn12301.net/xuchao/hhrs.git`,主分支 `master`
+- 提交信息使用中文
+- `.gitignore` 已忽略 `unpackage/`、`node_modules/`、`.DS_Store`;**不要**提交构建产物(unpackage 目录)
+
+## 部署信息
+
+线上为纯静态站点,位于 121.43.239.220(阿里云 ECS / CentOS 7,宿主机 Nginx 直接伺服):
+
+| 项目 | 内容 |
+| --- | --- |
+| 站点 | https://hh.hn12301.net/ |
+| 网站目录 | `/home/hh/html`(uni-app 构建产物,入口 index.html) |
+| Nginx 配置 | `/etc/nginx/conf.d/h5-site-https.conf`(80 catch-all → 301 跳 HTTPS) |
+| 证书 | Let's Encrypt ec-256,acme.sh 每月 1/7/13/19 日 01:01 自动续期,手动续期见运维手册 |
+
+**发布流程**:本地 HBuilderX 构建 → 覆盖上传产物到 `/home/hh/html/` → 静态文件即时生效,**无需重启 Nginx**。改过 Nginx 配置才需要 `nginx -t && nginx -s reload`。
+
+**关键注意**:
+- 前端 API 基地址指向 `https://dscp-uat.hn12301.net`(UAT 测试环境),**后端不在部署机上**。出现"页面能打开但数据不通"时优先排查 dscp-uat.hn12301.net 的接口
+- 页面图片走 OSS:`aliyunoss.hn12301.net/hhrs/`
+- SSH 凭据及全部运维细节见 Obsidian 工作资料《121.43.239.220(H5站点服务器)运维手册_2026-08-04.md》
+- 数据录入(商铺/资源/中奖等)操作指南见仓库根 docs 的 `hhrs-ops-guide.md`(运营向)
\ No newline at end of file
diff --git a/common/http.api.js b/common/http.api.js
index 996822e..1d02815 100644
--- a/common/http.api.js
+++ b/common/http.api.js
@@ -20,12 +20,15 @@ let StoreDetailUrl = 'mp-api/hhrsStore/detail';
let WinnerDatesUrl = 'mp-api/hhrsWinner/dates';
let WinnerListUrl = 'mp-api/hhrsWinner/list';
let AppointUrl = 'zhy-api/cardBag/appoint';
+let TokenDecodeUrl = 'open-api/hhService/tokenDecode';
// 此处第二个参数vm,就是我们在页面使用的this
const install = (Vue, vm) => {
let checkerLogin = (params = {}) => vm.$u.post(LoginUrl, params);
let sendLoginVerifyCode = (params = {}) => vm.$u.post(SendVerifyCodeUrl, params);
+ // xuchao: 云闪付入口 token 解码
+ let tokenDecode = (params = {}) => vm.$u.post(TokenDecodeUrl, params);
// 文旅场馆
let getVenueList = (params = {}) => vm.$u.get(VenueListUrl, params);
@@ -57,6 +60,7 @@ const install = (Vue, vm) => {
vm.$u.api = {
checkerLogin,
sendLoginVerifyCode,
+ tokenDecode,
getVenueList,
getVenueDetail,
getMerchantList,
diff --git a/common/http.interceptor.js b/common/http.interceptor.js
index 11bac9e..0f824c3 100644
--- a/common/http.interceptor.js
+++ b/common/http.interceptor.js
@@ -2,7 +2,7 @@
// 同时,我们也可以在此使用getApp().globalData,如果你把token放在getApp().globalData的话,也是可以使用的
const install = (Vue, vm) => {
Vue.prototype.$u.http.setConfig({
- baseUrl: 'https://dscp-dev.hn12301.net',
+ baseUrl: 'https://dscp-uat.hn12301.net',
// loadingText: '努力加载中~',
// loadingTime: 18800,
// 如果将此值设置为true,拦截回调中将会返回服务端返回的所有数据response,而不是response.data
diff --git a/pages/agreement/privacy.vue b/pages/agreement/privacy.vue
index d87ba4b..9b91b4e 100644
--- a/pages/agreement/privacy.vue
+++ b/pages/agreement/privacy.vue
@@ -1,14 +1,100 @@
-
- 隐私协议
- 请在此处填写隐私协议的具体内容。
+ 怀化社保卡惠民活动隐私协议
+ 生效日期:2026年9月1日
+
+ {{ s.h }}
+ {{ p }}
diff --git a/pages/agreement/user.vue b/pages/agreement/user.vue
index 16f317f..bf16125 100644
--- a/pages/agreement/user.vue
+++ b/pages/agreement/user.vue
@@ -1,14 +1,96 @@
-
- 用户协议
- 请在此处填写用户协议的具体内容。
+ 怀化社保卡惠民活动用户协议
+ 生效日期:2026年9月1日
+
+ {{ s.h }}
+ {{ p }}
diff --git a/pages/discount/discount.vue b/pages/discount/discount.vue
index 0c81f58..829bbe0 100644
--- a/pages/discount/discount.vue
+++ b/pages/discount/discount.vue
@@ -16,13 +16,14 @@
-
+
{{ item.name }}
{{ item.category }}
-
+
+
{{ item.address }}
@@ -32,9 +33,9 @@
-
+
-
+
@@ -51,22 +52,35 @@ export default {
lng: '',
lat: '',
loadStatus: 'loadmore',
- hasScrolled: false
+ hasScrolled: false,
+ reqSeq: 0
}
},
onLoad() {
- const loc = uni.getStorageSync('lng') && uni.getStorageSync('lat')
- ? { lng: uni.getStorageSync('lng'), lat: uni.getStorageSync('lat') }
- : null
- if (loc) {
- this.lng = loc.lng
- this.lat = loc.lat
+ const hasLoc = uni.getStorageSync('lng') && uni.getStorageSync('lat')
+ if (hasLoc) {
+ this.lng = uni.getStorageSync('lng')
+ this.lat = uni.getStorageSync('lat')
+ this.loadList()
+ } else {
+ // xuchao: 定位仅在首页触发过,直接进本页无缓存时主动获取一次,保证距离列可展示
+ import('@/common/location.js').then(module => module.default.getLocation())
+ .then(({ lng, lat }) => {
+ this.lng = lng
+ this.lat = lat
+ })
+ .catch(() => {})
+ .finally(() => this.loadList())
}
- this.loadList()
+ },
+ // xuchao: 改用页面级触底加载(scroll-view 无固定高度时 scrolltolower 永不触发)
+ onReachBottom() {
+ this.loadMore()
},
methods: {
loadList() {
- if (this.loading) return
+ // xuchao: 请求序号 —— 新请求直接取代在途请求,过期响应整体丢弃(修复搜索竞态,故不再用 loading 提前 return)
+ const seq = ++this.reqSeq
this.loading = true
this.loadStatus = 'loading'
const params = {
@@ -78,6 +92,7 @@ export default {
if (this.lng) params.lng = this.lng
if (this.lat) params.lat = this.lat
this.$u.api.getStoreList(params).then(res => {
+ if (seq !== this.reqSeq) return
if (res.errcode === 0 && res.data) {
const list = res.data.list || []
if (this.pageNo === 1) {
@@ -86,8 +101,11 @@ export default {
this.list = this.list.concat(list)
}
this.total = res.data.total || 0
+ // xuchao: 本页不足一页即已到尾部,钉住 total,防止 total 中途变大时空翻
+ if (list.length < this.pageSize) this.total = this.list.length
}
}).finally(() => {
+ if (seq !== this.reqSeq) return
this.loading = false
if (this.list.length === 0) {
this.loadStatus = 'nomore'
@@ -106,7 +124,13 @@ export default {
}
},
goBack() {
- uni.navigateBack()
+ // xuchao: 直接通过链接进入(无历史栈)时回到首页
+ const pages = getCurrentPages()
+ if (pages.length > 1) {
+ uni.navigateBack()
+ } else {
+ uni.reLaunch({ url: '/pages/index/index' })
+ }
},
goDetail(item) {
uni.navigateTo({ url: '/pages/venue/detail?id=' + item.shopId })
@@ -180,18 +204,23 @@ export default {
}
.list-area {
+ padding: 12px;
+ // xuchao: border-box 防止 padding 撑出页面横向滚动
+ box-sizing: border-box;
}
.venue-card {
display: flex;
align-items: flex-end;
+ box-sizing: border-box;
background-color: #ffffff;
border: 1px solid #f2f2f7;
border-radius: 6px;
- padding: 12px;
+ width: 702rpx;
+ padding: 24px 12px;
gap: 12px;
box-shadow: 0 2px 3px #f2f2f7;
- margin: 12px;
+ margin-bottom: 12px;
}
.card-img {
@@ -203,11 +232,11 @@ export default {
.card-info {
flex: 1;
+ // xuchao: min-width:0 允许 flex 子项收缩到内容宽度以下,配合 nowrap 文本出省略号
+ min-width: 0;
display: flex;
flex-direction: column;
gap: 0;
- width: 100%;
- min-width: 0;
}
.card-name {
@@ -226,22 +255,22 @@ export default {
margin-top: 8px;
}
-.card-bottom {
+.card-address-row {
display: flex;
align-items: center;
- justify-content: flex-end;
- margin-top: 8px;
gap: 8px;
+ width: 100%;
+ margin-top: 8px;
}
.card-address {
flex: 1;
+ min-width: 0;
font-size: 14px;
color: #727272;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
- min-width: 0;
}
.card-distance {
diff --git a/pages/index/index.vue b/pages/index/index.vue
index 6c5b779..5df3065 100644
--- a/pages/index/index.vue
+++ b/pages/index/index.vue
@@ -59,10 +59,56 @@
]
}
},
- onLoad() {
+ 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 }) => {
@@ -83,8 +129,10 @@
}
const isAuth = uni.getStorageSync('isAuth')
const hasWin = uni.getStorageSync('hasWin')
+ // xuchao: 最近发起过认证流程(含取消)时忽略旧认证缓存,一律回认证页
+ const authFlowStarted = uni.getStorageSync('authFlowStarted')
let status = 'auth'
- if (isAuth) {
+ if (isAuth && !authFlowStarted) {
status = hasWin ? 'info' : 'noWin'
}
uni.navigateTo({ url: `/pages/rights/rights?status=${status}` })
@@ -144,7 +192,6 @@
}
.king-text {
- font-family: 'Source Han Sans SC', 'Source Han Sans CN', 'Noto Sans CJK SC', 'PingFang SC', 'Microsoft YaHei', sans-serif;
font-size: 24rpx;
color: #333333;
text-align: center;
@@ -177,7 +224,7 @@
.title-text {
font-size: 14px;
- font-weight: bold;
+ font-weight: 600;
color: #333333;
}
@@ -216,7 +263,7 @@
.guide-title {
font-size: 16px;
- font-weight: bold;
+ font-weight: 600;
color: #0088FF;
margin-bottom: 10rpx;
}
diff --git a/pages/index/login.vue b/pages/index/login.vue
index 24776c5..b5efb86 100644
--- a/pages/index/login.vue
+++ b/pages/index/login.vue
@@ -1,5 +1,12 @@
+
+
+
+
+
+ 手机号登录
+
手机号登录
@@ -32,12 +39,6 @@
和
《隐私协议》
-
-
-
-
- 返回上一页
-
@@ -135,7 +136,13 @@ export default {
uni.navigateTo({ url })
},
goBack() {
- uni.navigateBack()
+ // xuchao: 直接通过链接进入(无历史栈)时回到首页,避免返回无响应
+ const pages = getCurrentPages()
+ if (pages.length > 1) {
+ uni.navigateBack()
+ } else {
+ uni.reLaunch({ url: '/pages/index/index' })
+ }
}
}
}
@@ -159,7 +166,7 @@ export default {
.title {
font-size: 44rpx;
- font-weight: bold;
+ font-weight: 700;
color: #1a1a1a;
display: block;
text-align: center;
@@ -264,24 +271,35 @@ export default {
color: #0088FF;
}
-/* 返回按钮 */
-.back-btn {
- position: fixed;
- left: 24px;
- bottom: 50px;
+/* xuchao: 顶部返回导航条(负外边距抵消页面左右 padding,通栏展示) */
+.nav-bar {
display: flex;
- flex-direction: column;
align-items: center;
- gap: 4px;
+ height: 56px;
+ background-color: #ffffff;
+ border-bottom: 1px solid #f0f0f0;
+ position: relative;
+ margin: 0 -40rpx;
}
-.back-icon {
- width: 44px;
- height: 44px;
+.nav-back {
+ position: absolute;
+ left: 12px;
+ top: 0;
+ bottom: 0;
+ display: flex;
+ align-items: center;
}
-.back-text {
- font-size: 12px;
- color: #666666;
+.nav-title {
+ flex: 1;
+ text-align: center;
+ font-size: 17px;
+ font-weight: 600;
+ color: #1a1818;
+ padding: 0 56px;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
}
diff --git a/pages/rights/detail.vue b/pages/rights/detail.vue
index 9344cb8..1899ce1 100644
--- a/pages/rights/detail.vue
+++ b/pages/rights/detail.vue
@@ -1,22 +1,23 @@
-
+
-
-
- {{ detail.shopName }}
- {{ detail.category }}
- 营业时间:{{ detail.businessTime }}
+
+
+
+ {{ detail.shopName }}
+ {{ detail.category }}
+ 营业时间:{{ detail.businessTime }}
+
-
-
-
-
- {{ detail.address }}
-
-
- {{ detail.distance < 1 ? Math.round(detail.distance * 1000) + 'm' : Math.round(detail.distance) + 'km' }}
+
+
+ {{ detail.address }}
+
+
+ {{ detail.distance < 1 ? Math.round(detail.distance * 1000) + 'm' : Math.round(detail.distance) + 'km' }}
+
@@ -180,12 +181,17 @@ export default {
}
\ No newline at end of file
diff --git a/pages/venue/detail.vue b/pages/venue/detail.vue
index 1b0dfcd..bd6adbc 100644
--- a/pages/venue/detail.vue
+++ b/pages/venue/detail.vue
@@ -1,5 +1,13 @@
-
+
+
+
+
+
+
+
+ {{ store.name }}
+
@@ -20,6 +28,31 @@
+
+
+
+
+ 商户电话
+
+
+
+ {{ i > 0 ? ',' : '' }}{{ p }}
+
+
+
+
+
+
+
+
+ 商品信息
+
+
+ {{ item }}
+
+
+
@@ -30,11 +63,18 @@
{{ item }}
-
-
-
-
- 返回上一页
+
+
+
+
+
+
+
+ 详情
+
+
+ 门店信息加载失败,该门店可能不存在或已下架
+
@@ -43,13 +83,41 @@
export default {
data() {
return {
- store: null
+ store: null,
+ loaded: false
}
},
computed: {
+ ticketInfoList() {
+ if (!this.store || !this.store.ticketInfo) return []
+ return this.store.ticketInfo.split('\n')
+ },
discountList() {
if (!this.store || !this.store.merchantDiscount) return []
return this.store.merchantDiscount.split('\n')
+ },
+ // xuchao: 客服电话列表:按常见分隔符切分;无分隔符连写的多个11位手机号也自动拆开
+ servicePhoneList() {
+ if (!this.store || !this.store.servicePhone) return []
+ const parts = String(this.store.servicePhone).split(/[,,;;、\s\n]+/).filter(Boolean)
+ const out = []
+ parts.forEach(p => {
+ if (p.length > 11 && /^1[3-9]\d{9}$/.test(p.slice(0, 11))) {
+ let rest = p
+ const segs = []
+ while (rest.length >= 11 && /^1[3-9]\d{9}$/.test(rest.slice(0, 11))) {
+ segs.push(rest.slice(0, 11))
+ rest = rest.slice(11)
+ }
+ if (rest) segs[segs.length - 1] += rest
+ if (segs.length > 1) {
+ out.push(...segs)
+ return
+ }
+ }
+ out.push(p)
+ })
+ return out
}
},
onLoad(options) {
@@ -58,6 +126,11 @@ export default {
}
},
methods: {
+ // xuchao: 点击某个商户电话唤起拨号(多个号码时逐个可点)
+ callPhone(phone) {
+ if (!phone) return
+ uni.makePhoneCall({ phoneNumber: String(phone) })
+ },
loadDetail(shopId) {
const loc = uni.getStorageSync('lng') && uni.getStorageSync('lat')
? { lng: uni.getStorageSync('lng'), lat: uni.getStorageSync('lat') }
@@ -71,10 +144,19 @@ export default {
if (res.errcode === 0 && res.data) {
this.store = res.data
}
+ this.loaded = true
+ }).catch(() => {
+ this.loaded = true
})
},
goBack() {
- uni.navigateBack()
+ // xuchao: 直接通过链接进入(无历史栈)时回到首页,避免返回无响应
+ const pages = getCurrentPages()
+ if (pages.length > 1) {
+ uni.navigateBack()
+ } else {
+ uni.reLaunch({ url: '/pages/index/index' })
+ }
}
}
}
@@ -82,9 +164,9 @@ export default {
diff --git a/pages/venue/venue.vue b/pages/venue/venue.vue
index 5b55375..a0d3bd0 100644
--- a/pages/venue/venue.vue
+++ b/pages/venue/venue.vue
@@ -16,7 +16,7 @@
-
+
@@ -32,9 +32,9 @@
-
+
-
+
@@ -51,7 +51,8 @@ export default {
lng: '',
lat: '',
loadStatus: 'loadmore',
- hasScrolled: false
+ hasScrolled: false,
+ reqSeq: 0
}
},
onLoad() {
@@ -64,9 +65,14 @@ export default {
}
this.loadList()
},
+ // xuchao: 改用页面级触底加载(scroll-view 无固定高度时 scrolltolower 永不触发)
+ onReachBottom() {
+ this.loadMore()
+ },
methods: {
loadList() {
- if (this.loading) return
+ // xuchao: 请求序号 —— 新请求直接取代在途请求,过期响应整体丢弃(修复搜索竞态,故不再用 loading 提前 return)
+ const seq = ++this.reqSeq
this.loading = true
this.loadStatus = 'loading'
const params = {
@@ -78,6 +84,7 @@ export default {
if (this.lng) params.lng = this.lng
if (this.lat) params.lat = this.lat
this.$u.api.getStoreList(params).then(res => {
+ if (seq !== this.reqSeq) return
if (res.errcode === 0 && res.data) {
const list = res.data.list || []
if (this.pageNo === 1) {
@@ -86,8 +93,11 @@ export default {
this.list = this.list.concat(list)
}
this.total = res.data.total || 0
+ // xuchao: 本页不足一页即已到尾部,钉住 total,防止 total 中途变大时空翻
+ if (list.length < this.pageSize) this.total = this.list.length
}
}).finally(() => {
+ if (seq !== this.reqSeq) return
this.loading = false
if (this.list.length === 0) {
this.loadStatus = 'nomore'
@@ -106,7 +116,13 @@ export default {
}
},
goBack() {
- uni.navigateBack()
+ // xuchao: 直接通过链接进入(无历史栈)时回到首页
+ const pages = getCurrentPages()
+ if (pages.length > 1) {
+ uni.navigateBack()
+ } else {
+ uni.reLaunch({ url: '/pages/index/index' })
+ }
},
goDetail(item) {
uni.navigateTo({ url: '/pages/venue/detail?id=' + item.shopId })
diff --git a/pages/winners/winners.vue b/pages/winners/winners.vue
index 374c50e..bbbd651 100644
--- a/pages/winners/winners.vue
+++ b/pages/winners/winners.vue
@@ -15,7 +15,7 @@
已产生
- 7,000
+ {{ totalWinners.toLocaleString() }}
名幸运持卡人
@@ -46,18 +46,26 @@
-
-
- {{ item.memberName }}
- {{ item.memberIdentityNo }}
- {{ item.memberPhone }}
-
-
-
+
+
+
+ {{ item.memberName }}
+ {{ item.memberIdentityNo }}
+ {{ item.memberPhone }}
+
+
+
+
+
+
+
+
+
+ 暂无数据
@@ -72,9 +80,10 @@ export default {
winnerData: {},
pageNo: 1,
pageSize: 10,
- total: 0,
- loading: false,
- loadStatus: 'loadmore',
+ totals: {},
+ totalWinners: 0,
+ inFlight: 0,
+ loadStatusMap: {},
keyword: ''
}
},
@@ -88,6 +97,10 @@ export default {
(item.memberName && item.memberName.toLowerCase().includes(kw)) ||
(item.memberPhone && item.memberPhone.includes(kw))
)
+ },
+ // xuchao: 各期独立的加载状态,避免并行请求互相覆盖
+ loadStatus() {
+ return this.loadStatusMap[this.currentTab] || 'nomore'
}
},
onLoad() {
@@ -110,45 +123,55 @@ export default {
data[index] = []
})
this.winnerData = data
+ // xuchao: 预置各期 key,保证 totals/loadStatusMap 的响应式
+ this.totals = {}
+ this.loadStatusMap = {}
+ dates.forEach((date, index) => {
+ this.$set(this.totals, index, 0)
+ this.$set(this.loadStatusMap, index, 'loading')
+ })
+ // xuchao: 预取各期第一页,汇总已产生总人数
if (this.tabs.length > 0) {
- this.loadWinnerList(0)
+ this.tabs.forEach((tab, index) => {
+ this.loadWinnerList(index, 1, true)
+ })
}
}
})
},
- loadWinnerList(tabIndex) {
+ loadWinnerList(tabIndex, pageNo, allowConcurrent) {
if (!this.tabs[tabIndex]) return
- if (this.loading) return
- this.loading = true
- this.loadStatus = 'loading'
+ if (this.inFlight > 0 && !allowConcurrent) return
+ this.inFlight++
+ this.$set(this.loadStatusMap, tabIndex, 'loading')
const drawDate = this.tabs[tabIndex].date
this.$u.api.getWinnerList({
- pageNo: this.pageNo,
+ pageNo: pageNo || this.pageNo,
pageSize: this.pageSize,
drawDate: drawDate
}).then(res => {
if (res.errcode === 0 && res.data) {
const list = res.data.list || []
- if (this.pageNo === 1) {
+ const page = pageNo || this.pageNo
+ if (page === 1) {
this.$set(this.winnerData, tabIndex, list)
} else {
this.winnerData[tabIndex] = this.winnerData[tabIndex].concat(list)
}
- this.total = res.data.total || 0
+ this.$set(this.totals, tabIndex, res.data.total || 0)
+ // xuchao: 各期总人数求和,用于顶部幸运持卡人数
+ this.totalWinners = Object.values(this.totals).reduce((sum, n) => sum + n, 0)
}
}).finally(() => {
- this.loading = false
- if (this.winnerData[tabIndex].length === 0) {
- this.loadStatus = 'nomore'
- } else if (this.winnerData[tabIndex].length >= this.total) {
- this.loadStatus = 'nomore'
- } else {
- this.loadStatus = 'loadmore'
- }
+ this.inFlight--
+ const len = this.winnerData[tabIndex].length
+ const total = this.totals[tabIndex] || 0
+ this.$set(this.loadStatusMap, tabIndex, len === 0 || len >= total ? 'nomore' : 'loadmore')
})
},
loadMore() {
- if (this.winnerData[this.currentTab].length < this.total && !this.loading) {
+ const total = this.totals[this.currentTab] || 0
+ if (this.winnerData[this.currentTab].length < total && this.inFlight === 0) {
this.pageNo++
this.loadWinnerList(this.currentTab)
}
@@ -157,13 +180,20 @@ export default {
this.currentTab = index
this.pageNo = 1
if (this.winnerData[index].length === 0) {
- this.loadWinnerList(index)
+ this.loadWinnerList(index, 1)
} else {
- this.loadStatus = this.winnerData[index].length >= this.total ? 'nomore' : 'loadmore'
+ const total = this.totals[index] || 0
+ this.$set(this.loadStatusMap, index, this.winnerData[index].length >= total ? 'nomore' : 'loadmore')
}
},
goBack() {
- uni.navigateBack()
+ // xuchao: 直接通过链接进入(无历史栈)时回到首页
+ const pages = getCurrentPages()
+ if (pages.length > 1) {
+ uni.navigateBack()
+ } else {
+ uni.reLaunch({ url: '/pages/index/index' })
+ }
},
onSearch() {
// 前端过滤,无需重新请求
@@ -216,8 +246,7 @@ export default {
.banner-title {
color: #0D387D;
- font-family: 'Source Han Serif SC VF', 'Source Han Serif SC', serif;
- font-weight: bold;
+ font-weight: 700;
font-size: 32px;
line-height: normal;
letter-spacing: 0px;
@@ -226,7 +255,6 @@ export default {
.banner-subtitle {
color: #8E8E93;
- font-family: 'Source Han Serif SC VF', 'Source Han Serif SC', serif;
font-weight: 600;
font-size: 14px;
line-height: normal;
@@ -251,8 +279,6 @@ export default {
.stats-label {
color: #FFFFFF;
- font-family: 'Source Han Sans CN', 'Source Han Sans SC', sans-serif;
- font-weight: 400;
font-size: 14px;
line-height: normal;
letter-spacing: 0px;
@@ -261,8 +287,7 @@ export default {
.stats-number {
flex: 1;
- font-family: 'Source Han Serif SC VF', 'Source Han Serif SC', serif;
- font-weight: 600;
+ font-weight: 700;
font-size: 36px;
line-height: normal;
letter-spacing: 0px;
@@ -293,7 +318,6 @@ export default {
.tab-label {
color: #B1B1B1;
- font-family: 'Source Han Serif SC VF', 'Source Han Serif SC', serif;
font-weight: 600;
font-size: 16px;
line-height: 22px;
@@ -408,4 +432,18 @@ export default {
padding: 24px 0;
color: #999999;
}
+
+/* 空态 */
+.empty-area {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 80px 0;
+ color: #999999;
+}
+
+.empty-text {
+ margin-top: 12px;
+ font-size: 14px;
+}