hookehuyr

fix(scan-checkin): 完善扫码打卡列表分页与交互细节

- ESLint comma-dangle 改为 always-multiline,允许多行尾随逗号
- ScanCheckinList 接入分页加载,增加加载中/空状态/加载更多提示
- ScanCheckinDetail 打卡成功后等用户确认再跳转列表页

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
......@@ -15,7 +15,7 @@ module.exports = {
indent: ['error', 2, { SwitchCase: 1 }], // 缩进
quotes: ['error', 'single', { avoidEscape: true }], // 单引号
semi: ['error', 'never'], // 不使用分号
'comma-dangle': ['error', 'never'], // 不使用尾随逗号
'comma-dangle': ['error', 'always-multiline'], // 多行时必须尾随逗号,单行不允许
'space-before-function-paren': [
'error',
{
......
......@@ -214,21 +214,23 @@ const handleScanCheckin = async () => {
detail.isChecked = true
detail.lastScanCode = scannedCode
await Taro.showModal({
const modalResult = await Taro.showModal({
title: '打卡成功',
content: '您已完成当前扫码打卡,可前往列表查看状态。',
showCancel: false,
confirmText: '查看列表',
})
if (modalResult.confirm) {
const params = new URLSearchParams({
activityId: detail.activityId,
})
// 扫码打卡完成后回列表页,方便用户继续处理同一活动下的其他关卡。
// 用户确认“查看列表”后回到列表页,方便继续处理同一活动下的其他关卡。
Taro.redirectTo({
url: `/pages/ScanCheckinList/index?${params.toString()}`,
})
}
return
}
......
.scan-checkin-list-page {
min-height: 100vh;
padding: 32rpx 24rpx 40rpx;
padding: 32rpx 24rpx 220rpx;
background: linear-gradient(180deg, #f6f8fb 0%, #eef2f5 100%);
box-sizing: border-box;
position: relative;
......@@ -36,6 +36,13 @@
box-shadow: 0 12rpx 40rpx rgba(15, 23, 42, 0.08);
}
.scan-checkin-list-status {
padding: 88rpx 0;
text-align: center;
font-size: 28rpx;
color: #8b98a7;
}
.scan-checkin-list-leading {
width: 68rpx;
height: 68rpx;
......@@ -80,6 +87,21 @@
flex-shrink: 0;
}
.scan-checkin-list-load-more,
.scan-checkin-list-no-more {
padding: 24rpx 0 8rpx;
text-align: center;
font-size: 26rpx;
}
.scan-checkin-list-load-more {
color: #36b5bb;
}
.scan-checkin-list-no-more {
color: #98a3af;
}
.scan-checkin-list-floating-button {
position: fixed;
right: 24rpx;
......
......@@ -11,6 +11,11 @@
<text class="scan-checkin-list-subtitle">请选择一个打卡点,进入详情后完成扫码打卡</text>
</view>
<view v-if="loading && pointList.length === 0" class="scan-checkin-list-status">
加载中...
</view>
<template v-else>
<view v-for="point in pointList" :key="point.id" class="scan-checkin-list-card">
<view class="scan-checkin-list-leading">
<IconFont size="30" name="https://cdn.ipadbiz.cn/lls_prog/icon/check_list_logo.png" />
......@@ -25,6 +30,23 @@
</view>
</view>
<view v-if="!loading && pointList.length === 0" class="scan-checkin-list-status">
暂无扫码打卡点
</view>
<view
v-if="hasMore && pointList.length > 0"
class="scan-checkin-list-load-more"
@click="loadMore"
>
{{ loadingMore ? '加载中...' : '加载更多' }}
</view>
<view v-if="!hasMore && pointList.length > 0" class="scan-checkin-list-no-more">
没有更多数据了
</view>
</template>
<view class="scan-checkin-list-floating-button" @click="handleShowBoothMap">
<IconFont
class="scan-checkin-list-floating-icon"
......@@ -45,6 +67,18 @@ import { getScanStageListAPI } from '@/api/map'
const pointList = ref([])
const activityId = ref('')
const loading = ref(false)
const loadingMore = ref(false)
const hasMore = ref(true)
const currentPage = ref(0)
const pageSize = ref(10)
const mapStageList = stageList =>
stageList.map(stage => ({
id: stage.id,
title: stage.title,
isChecked: stage.is_checked,
}))
const goToDetail = point => {
const params = new URLSearchParams({
......@@ -74,9 +108,35 @@ useLoad(options => {
loadStageList()
})
const loadStageList = async () => {
const loadStageList = async (isLoadMore = false) => {
if (!activityId.value) {
pointList.value = []
hasMore.value = false
return
}
if (isLoadMore) {
if (loading.value || loadingMore.value || !hasMore.value) {
return
}
loadingMore.value = true
} else {
if (loading.value) {
return
}
loading.value = true
currentPage.value = 0
hasMore.value = true
pointList.value = []
}
const page = currentPage.value
try {
const result = await getScanStageListAPI({
activity_id: activityId.value,
page,
limit: pageSize.value,
})
if (result?.code !== 1) {
......@@ -87,11 +147,25 @@ const loadStageList = async () => {
return
}
pointList.value = (result?.data?.stages || []).map(stage => ({
id: stage.id,
title: stage.title,
isChecked: stage.is_checked,
}))
const stageList = mapStageList(result?.data?.stages || [])
pointList.value = isLoadMore ? [...pointList.value, ...stageList] : stageList
hasMore.value = stageList.length === pageSize.value
currentPage.value = page + 1
} catch (error) {
console.error('获取扫码打卡关卡列表失败:', error)
Taro.showToast({
title: '获取关卡列表失败',
icon: 'none',
})
} finally {
loading.value = false
loadingMore.value = false
}
}
const loadMore = () => {
loadStageList(true)
}
</script>
......