148 lines
4.8 KiB
Vue
148 lines
4.8 KiB
Vue
<template>
|
|
<ElDialog
|
|
:model-value="true"
|
|
title="单卡轮询状态"
|
|
width="min(1100px, 96vw)"
|
|
@update:model-value="
|
|
(value) => {
|
|
if (!value) emit('close')
|
|
}
|
|
"
|
|
>
|
|
<ElButton :loading="loading" @click="load">刷新状态</ElButton>
|
|
<ElAlert v-if="error" type="error" :title="error" :closable="false" />
|
|
<template v-if="state">
|
|
<ElDescriptions :column="width < 640 ? 1 : 2" border class="state-overview"
|
|
><ElDescriptionsItem v-for="item in fields" :key="item[0]" :label="item[1]">{{
|
|
gatewayDisplayValue(state[item[0] as keyof typeof state], item[0])
|
|
}}</ElDescriptionsItem></ElDescriptions
|
|
>
|
|
<h3>各检查类型状态</h3
|
|
><ArtTable :data="state.types" row-key="check_type" :pagination="false"
|
|
><ElTableColumn v-for="item in typeFields" :key="item[0]" :label="item[1]" min-width="170"
|
|
><template #default="{ row }">{{
|
|
gatewayDisplayValue(row[item[0]], item[0])
|
|
}}</template></ElTableColumn
|
|
></ArtTable
|
|
>
|
|
<h3>停复机指令</h3
|
|
><ElDescriptions v-if="state.stop_resume_command" :column="width < 640 ? 1 : 2" border
|
|
><ElDescriptionsItem v-for="item in commandFields" :key="item[0]" :label="item[1]">{{
|
|
gatewayDisplayValue(commandValue(item[0]), item[0])
|
|
}}</ElDescriptionsItem></ElDescriptions
|
|
><ElEmpty v-else description="当前没有停复机指令" />
|
|
</template>
|
|
</ElDialog>
|
|
</template>
|
|
<script setup lang="ts">
|
|
import { ref, onMounted, onBeforeUnmount, onDeactivated, watch } from 'vue'
|
|
import { useUserStore } from '@/store/modules/user'
|
|
import {
|
|
pollingScope,
|
|
schedulerDisplayValue as gatewayDisplayValue
|
|
} from '@/utils/business/pollingScheduler'
|
|
import { useWindowSize } from '@vueuse/core'
|
|
import { PollingSchedulerService } from '@/api/modules/pollingScheduler'
|
|
import { useAuth } from '@/composables/useAuth'
|
|
import {
|
|
gatewayData,
|
|
gatewayError,
|
|
requireGatewayAccess,
|
|
validateGatewayInteger
|
|
} from '@/utils/business/gateway'
|
|
import type { CardPollingState } from '@/types/api/pollingScheduler'
|
|
const props = defineProps<{ cardId: number; permission: string }>()
|
|
const emit = defineEmits<{ close: [] }>()
|
|
const user = useUserStore()
|
|
watch(
|
|
() => pollingScope(user),
|
|
() => {
|
|
++sequence
|
|
state.value = null
|
|
emit('close')
|
|
},
|
|
{ flush: 'sync' }
|
|
)
|
|
const { width } = useWindowSize(),
|
|
{ hasAuth } = useAuth()
|
|
const loading = ref(false),
|
|
error = ref(''),
|
|
state = ref<CardPollingState | null>(null)
|
|
const fields = [
|
|
['iccid', 'ICCID'],
|
|
['carrier_id', '运营商账户 ID'],
|
|
['scheduler_mode', '调度模式'],
|
|
['enable_polling', '是否轮询'],
|
|
['queue', '所在队列'],
|
|
['queue_score_at', '下次可领取时间'],
|
|
['running', '执行中'],
|
|
['claim_expire_at', '处理中标记到期'],
|
|
['priority_mark', '优先标记'],
|
|
['stop_resume_queue_enabled', '停复机出口队列'],
|
|
['last_stop_resume_call_at', '最近停复机网关调用']
|
|
]
|
|
const typeFields = [
|
|
['check_type_name', '检查类型'],
|
|
['next_due_at', '下次到期'],
|
|
['last_success_at', '最近成功'],
|
|
['fail_count', '连续失败'],
|
|
['first_failed_at', '首次失败'],
|
|
['last_error', '最近错误'],
|
|
['pending_confirm', '待确认延迟(秒)']
|
|
]
|
|
const commandFields = [
|
|
['action', '动作'],
|
|
['reason', '原因'],
|
|
['scenes', '场景'],
|
|
['source', '来源'],
|
|
['version', '版本'],
|
|
['fail_count', '连续失败'],
|
|
['last_error', '最近错误'],
|
|
['pending', '待确认'],
|
|
['unknown', '连续未知'],
|
|
['written_at', '写入时间'],
|
|
['next_at', '下次可执行时间']
|
|
]
|
|
let sequence = 0
|
|
const commandValue = (key: string) =>
|
|
state.value?.stop_resume_command?.[
|
|
key as keyof NonNullable<CardPollingState['stop_resume_command']>
|
|
]
|
|
async function load() {
|
|
const scope = pollingScope(user)
|
|
const current = ++sequence
|
|
loading.value = true
|
|
error.value = ''
|
|
state.value = null
|
|
try {
|
|
requireGatewayAccess(hasAuth(props.permission))
|
|
validateGatewayInteger(props.cardId, 1, Number.MAX_SAFE_INTEGER, '卡 ID')
|
|
const data = gatewayData(await PollingSchedulerService.getCardState(props.cardId))
|
|
if (current === sequence && scope === pollingScope(user) && hasAuth(props.permission))
|
|
state.value = data
|
|
} catch (cause) {
|
|
if (current === sequence) error.value = gatewayError(cause)
|
|
} finally {
|
|
if (current === sequence) loading.value = false
|
|
}
|
|
}
|
|
onMounted(load)
|
|
onDeactivated(() => {
|
|
++sequence
|
|
emit('close')
|
|
})
|
|
onBeforeUnmount(() => {
|
|
++sequence
|
|
})
|
|
</script>
|
|
<style scoped>
|
|
.state-overview {
|
|
margin-top: 16px;
|
|
}
|
|
|
|
h3 {
|
|
margin: 20px 0 12px;
|
|
font-size: 16px;
|
|
}
|
|
</style>
|