Files
Wormhole/web/src/components/RankDialog.vue
T
rose_cat707 612d68f56f feat: Wormhole 内网穿透与反向代理网关
Go + Vue 管理台,SQLite 持久化;支持隧道/域名穿透、域名转发插件链、访客认证、
IP 规则、API Key、Docker 单镜像部署;配置通过 Web 系统设置管理,无需 YAML 文件。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-23 12:15:02 +08:00

76 lines
2.7 KiB
Vue

<template>
<el-dialog v-model="visible" :title="displayTitle" width="720px" destroy-on-close @open="load">
<el-table :data="items" v-loading="loading" size="small" class="table-scroll--lg">
<template v-if="type === 'tunnels'">
<el-table-column prop="name" :label="t('common.name')" />
<el-table-column prop="listen_port" :label="t('dashboard.listenPort')" width="80" />
<el-table-column :label="t('common.traffic')">
<template #default="{ row }">{{ formatBytes((row.inlet_flow || 0) + (row.export_flow || 0)) }}</template>
</el-table-column>
</template>
<template v-else-if="type === 'hosts'">
<el-table-column prop="host" :label="t('dashboard.host')" />
<el-table-column prop="target_addr" :label="t('common.target')" />
<el-table-column :label="t('common.traffic')">
<template #default="{ row }">{{ formatBytes((row.inlet_flow || 0) + (row.export_flow || 0)) }}</template>
</el-table-column>
</template>
<template v-else>
<el-table-column prop="ip" :label="t('dashboard.visitorIp')" min-width="120" />
<el-table-column prop="direct_ip" :label="t('dashboard.directIp')" min-width="120" />
<el-table-column prop="hit_count" :label="t('dashboard.hitCount')" width="80" />
<el-table-column prop="resource_type" :label="t('common.resource')" width="80" />
</template>
</el-table>
<div class="card-pager">
<el-pagination
v-model:current-page="page"
v-model:page-size="pageSize"
:total="total"
layout="total, prev, pager, next"
@current-change="load"
/>
</div>
</el-dialog>
</template>
<script setup>
import { ref, watch, computed } from 'vue'
import { useI18n } from 'vue-i18n'
import api from '@/api'
import { formatBytes } from '@/utils/format'
const { t } = useI18n()
const props = defineProps({
modelValue: Boolean,
type: { type: String, required: true },
title: { type: String, default: '' },
})
const emit = defineEmits(['update:modelValue'])
const visible = ref(false)
const items = ref([])
const total = ref(0)
const page = ref(1)
const pageSize = ref(50)
const loading = ref(false)
const displayTitle = computed(() => props.title || t('rank.defaultTitle'))
watch(() => props.modelValue, (v) => { visible.value = v })
watch(visible, (v) => emit('update:modelValue', v))
async function load() {
loading.value = true
try {
const { data } = await api.get('/dashboard/rankings', {
params: { type: props.type, page: page.value, page_size: pageSize.value },
})
items.value = data.items || []
total.value = data.total || 0
} finally {
loading.value = false
}
}
</script>