feat: add login ip desc request
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import StatCard from '@/components/pages/dashboard/CardNum.vue'
|
||||
import { DatabaseIcon, BarChartIcon, SendIcon, CheckCircleIcon, XCircleIcon } from 'lucide-vue-next'
|
||||
import { InboxIcon, FileTextIcon, SendIcon, CheckCircleIcon, XCircleIcon } from 'lucide-vue-next'
|
||||
// import { LineChart } from "@/components/ui/chart-line"
|
||||
import { onMounted, reactive } from 'vue';
|
||||
import { request } from '@/api/api';
|
||||
@@ -438,14 +438,14 @@ onMounted(() => {
|
||||
title="托管消息数"
|
||||
:value="state.basicData.hosted_message_total_num"
|
||||
description=""
|
||||
:icon="BarChartIcon"
|
||||
:icon="InboxIcon"
|
||||
route-path="/hostedmessage"
|
||||
/>
|
||||
<StatCard
|
||||
title="发送日志数"
|
||||
:value="state.basicData.message_total_num"
|
||||
description=""
|
||||
:icon="DatabaseIcon"
|
||||
:icon="FileTextIcon"
|
||||
route-path="/sendlogs"
|
||||
/>
|
||||
<StatCard
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'
|
||||
import { toast } from 'vue-sonner'
|
||||
// @ts-ignore
|
||||
import { request } from '@/api/api'
|
||||
|
||||
@@ -15,6 +17,10 @@ interface LoginLog {
|
||||
|
||||
const loading = ref(false)
|
||||
const logs = ref<LoginLog[]>([])
|
||||
const ipDialogOpen = ref(false)
|
||||
const ipLoading = ref(false)
|
||||
const selectedIp = ref('')
|
||||
const ipInfo = ref<any>(null)
|
||||
|
||||
const fetchLogs = async () => {
|
||||
loading.value = true
|
||||
@@ -30,6 +36,23 @@ const fetchLogs = async () => {
|
||||
}
|
||||
|
||||
onMounted(fetchLogs)
|
||||
|
||||
const openIpInfo = async (ip: string) => {
|
||||
selectedIp.value = ip
|
||||
ipDialogOpen.value = true
|
||||
ipLoading.value = true
|
||||
ipInfo.value = null
|
||||
try {
|
||||
const rsp = await fetch(`https://api.ip.sb/geoip/${encodeURIComponent(ip)}`)
|
||||
if (!rsp.ok) throw new Error('请求失败')
|
||||
const data = await rsp.json()
|
||||
ipInfo.value = data
|
||||
} catch (e) {
|
||||
toast.error('获取IP信息失败')
|
||||
} finally {
|
||||
ipLoading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -65,7 +88,9 @@ onMounted(fetchLogs)
|
||||
</tr>
|
||||
<tr v-for="item in logs" :key="item.id" class="border-t border-border">
|
||||
<td class="px-3 py-2">{{ item.username }}</td>
|
||||
<td class="px-3 py-2">{{ item.ip }}</td>
|
||||
<td class="px-3 py-2">
|
||||
<button class="text-blue-600 dark:text-blue-400 hover:underline" @click="openIpInfo(item.ip)">{{ item.ip }}</button>
|
||||
</td>
|
||||
<td class="px-3 py-2 truncate max-w-[220px] sm:max-w-[420px]" :title="item.ua">{{ item.ua }}</td>
|
||||
<td class="px-3 py-2">{{ item.created_on }}</td>
|
||||
</tr>
|
||||
@@ -75,6 +100,44 @@ onMounted(fetchLogs)
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Dialog :open="ipDialogOpen" @update:open="val => (ipDialogOpen = val)">
|
||||
<DialogContent class="w-[90vw] max-w-[90vw] sm:max-w-lg max-h-[80vh] overflow-y-auto">
|
||||
<DialogHeader>
|
||||
<DialogTitle>IP 信息 - {{ selectedIp }}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div v-if="ipLoading" class="text-sm text-muted-foreground">加载中...</div>
|
||||
<div v-else class="space-y-3 text-sm">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-x-4 gap-y-2">
|
||||
<div class="text-muted-foreground">organization</div>
|
||||
<div class="break-all">{{ ipInfo?.organization ?? '-' }}</div>
|
||||
<div class="text-muted-foreground">timezone</div>
|
||||
<div class="break-all">{{ ipInfo?.timezone ?? '-' }}</div>
|
||||
<div class="text-muted-foreground">ip</div>
|
||||
<div class="break-all">{{ ipInfo?.ip ?? selectedIp }}</div>
|
||||
<div class="text-muted-foreground">offset</div>
|
||||
<div class="break-all">{{ ipInfo?.offset ?? '-' }}</div>
|
||||
<div class="text-muted-foreground">isp</div>
|
||||
<div class="break-all">{{ ipInfo?.isp ?? '-' }}</div>
|
||||
<div class="text-muted-foreground">continent_code</div>
|
||||
<div class="break-all">{{ ipInfo?.continent_code ?? '-' }}</div>
|
||||
<div class="text-muted-foreground">asn_organization</div>
|
||||
<div class="break-all">{{ ipInfo?.asn_organization ?? '-' }}</div>
|
||||
<div class="text-muted-foreground">country</div>
|
||||
<div class="break-all">{{ ipInfo?.country ?? '-' }}</div>
|
||||
<div class="text-muted-foreground">asn</div>
|
||||
<div class="break-all">{{ ipInfo?.asn ?? '-' }}</div>
|
||||
<div class="text-muted-foreground">country_code</div>
|
||||
<div class="break-all">{{ ipInfo?.country_code ?? '-' }}</div>
|
||||
<div class="text-muted-foreground">latitude</div>
|
||||
<div class="break-all">{{ ipInfo?.latitude ?? '-' }}</div>
|
||||
<div class="text-muted-foreground">longitude</div>
|
||||
<div class="break-all">{{ ipInfo?.longitude ?? '-' }}</div>
|
||||
</div>
|
||||
<div class="text-xs text-muted-foreground mt-2">数据来源:<a href="https://api.ip.sb/geoip/185.222.222.222" target="_blank" rel="noreferrer" class="underline">api.ip.sb</a></div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { KeyIcon, TrashIcon, SettingsIcon, InfoIcon } from 'lucide-vue-next'
|
||||
import { KeyIcon, TrashIcon, SettingsIcon, InfoIcon, HistoryIcon } from 'lucide-vue-next'
|
||||
|
||||
// 定义props
|
||||
interface Props {
|
||||
@@ -19,7 +19,7 @@ defineEmits<Emits>()
|
||||
const settingsMenu = [
|
||||
{ id: 'password', name: '重置密码', icon: KeyIcon },
|
||||
{ id: 'logs', name: '日志清理', icon: TrashIcon },
|
||||
{ id: 'loginlogs', name: '登录日志', icon: InfoIcon },
|
||||
{ id: 'loginlogs', name: '登录日志', icon: HistoryIcon },
|
||||
{ id: 'site', name: '站点设置', icon: SettingsIcon },
|
||||
{ id: 'about', name: '站点关于', icon: InfoIcon }
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user