倒计时限制
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 4m12s

This commit is contained in:
2026-06-24 15:06:05 +08:00
parent 0c3065f970
commit cfb6b52cc2
8 changed files with 191 additions and 27 deletions

View File

@@ -5,6 +5,7 @@
ref="assetSearchCardRef"
:has-card-info="!!cardInfo"
:refresh-disabled="refreshDisabled"
:refresh-remaining-text="refreshRemainingText"
@search="handleSearch"
@refresh="handleRefresh"
/>
@@ -167,11 +168,16 @@
</template>
<script setup lang="ts">
import { computed, nextTick, onMounted, ref, watch } from 'vue'
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage, ElCard, ElEmpty } from 'element-plus'
import { RoutesAlias } from '@/router/routesAlias'
import { DeviceService } from '@/api/modules'
import {
formatRemainingTime,
FrontendRateLimitError,
getAssetActionRateLimitState
} from '@/utils/business/apiRateLimit'
// 引入子组件
import AssetSearchCard from './components/AssetSearchCard.vue'
@@ -311,7 +317,34 @@
})
// ========== 刷新按钮状态 ==========
const refreshDisabled = ref(false)
const rateLimitNow = ref(Date.now())
const refreshSubmitting = ref(false)
let rateLimitTimer: ReturnType<typeof setInterval> | undefined
const refreshRateLimitState = computed(() => {
const identifier = cardInfo.value?.identifier
if (!identifier) {
return {
limited: false,
remainingMs: 0,
retryAt: 0
}
}
return getAssetActionRateLimitState('refresh', identifier, rateLimitNow.value)
})
const refreshDisabled = computed(
() => refreshSubmitting.value || refreshRateLimitState.value.limited
)
const refreshRemainingText = computed(() =>
refreshRateLimitState.value.limited
? formatRemainingTime(refreshRateLimitState.value.remainingMs)
: ''
)
const updateRateLimitNow = () => {
rateLimitNow.value = Date.now()
}
// ========== 事件处理 ==========
@@ -351,14 +384,14 @@
* 处理刷新
*/
const handleRefresh = async () => {
if (!cardInfo.value) return
const success = await refreshAsset(cardInfo.value.identifier, cardInfo.value.asset_type)
if (!success) {
// 如果刷新失败429错误禁用刷新按钮30秒
refreshDisabled.value = true
setTimeout(() => {
refreshDisabled.value = false
}, 30000)
if (!cardInfo.value || refreshDisabled.value) return
try {
refreshSubmitting.value = true
await refreshAsset(cardInfo.value.identifier, cardInfo.value.asset_type)
} finally {
refreshSubmitting.value = false
updateRateLimitNow()
}
}
@@ -524,6 +557,10 @@
if (cardInfo.value)
await loadRealtimeStatus(cardInfo.value.identifier, cardInfo.value.asset_type)
} catch (error: any) {
if (error instanceof FrontendRateLimitError) {
ElMessage.warning(`操作过于频繁,请${formatRemainingTime(error.remainingMs)}后再试`)
return
}
console.error('启用绑定卡失败:', error)
}
}
@@ -653,9 +690,16 @@
* URL参数自动加载
*/
onMounted(() => {
rateLimitTimer = setInterval(updateRateLimitNow, 1000)
autoLoadFromQuery()
})
onUnmounted(() => {
if (rateLimitTimer) {
clearInterval(rateLimitTimer)
}
})
/**
* 监听路由查询参数变化
*/