👔 完成历史记录功能优化多语言
This commit is contained in:
parent
f9693bd560
commit
0ea2d2a3df
@ -1,5 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import {useStyleStore} from "~/stores/style";
|
||||
import {formatTimeAgo} from "~/composables/useFormatTime";
|
||||
|
||||
const isOpen = ref(false)
|
||||
|
||||
const styleStore = useStyleStore()
|
||||
|
||||
const slideoverConfig = {
|
||||
// 其他配置保持不变
|
||||
width: 'w-screen max-w-2xl', // 更新这里的值
|
||||
// 其余的配置...
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -7,10 +19,80 @@
|
||||
<div title="Change Color">
|
||||
<div
|
||||
class="cursor-pointer flex h-10 w-10 items-center justify-center rounded-lg bg-gray-100 dark:bg-gray-700"
|
||||
@click="isOpen = true"
|
||||
>
|
||||
<Icon name="ic:baseline-history" class=" text-lg dark:text-white" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<USlideover
|
||||
v-model="isOpen"
|
||||
side="right"
|
||||
:ui="slideoverConfig"
|
||||
>
|
||||
<button>
|
||||
<Icon name="lets-icons:close-ring-light" class="absolute top-2 right-2 text-gray-500 cursor-pointer" @click="isOpen = false" />
|
||||
</button>
|
||||
<div class="w-full min-h-screen bg-gray-100 p-5 overflow-y-auto max-h-[95vh]">
|
||||
<div class="max-w-6xl mx-auto">
|
||||
<h1 class="text-2xl font-bold text-gray-800 mb-5 flex items-center justify-between">
|
||||
查询历史
|
||||
<span class="text-sm text-gray-500 bg-gray-100 py-1 px-3 rounded-full">
|
||||
只保留最近 30/{{ styleStore.getHistory.length }} 条记录
|
||||
</span>
|
||||
</h1>
|
||||
<div class="bg-white shadow-md rounded-lg">
|
||||
<!-- 条件渲染,如果有历史记录则显示表格,否则显示提示 -->
|
||||
<div v-if="styleStore.getHistory.length">
|
||||
<table class="min-w-full leading-normal">
|
||||
<!-- 表格头部和内容 -->
|
||||
<table class="min-w-full leading-normal">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="px-5 py-3 border-b-2 border-gray-200 bg-gray-100 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">
|
||||
域名
|
||||
</th>
|
||||
<th class="px-5 py-3 border-b-2 border-gray-200 bg-gray-100 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">
|
||||
查询类型
|
||||
</th>
|
||||
<th class="px-5 py-3 border-b-2 border-gray-200 bg-gray-100 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">
|
||||
查询时间
|
||||
</th>
|
||||
<th class="px-5 py-3 border-b-2 border-gray-200 bg-gray-100 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">
|
||||
动作
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- 这里将使用循环来动态展示查询历史 -->
|
||||
<tr v-for="item in styleStore.getHistory" :key="item.id" class="border-b border-gray-200">
|
||||
<td class="px-5 py-5 text-sm bg-white">
|
||||
<NuxtLink :to="item.path">{{ item.domain }}</NuxtLink>
|
||||
</td>
|
||||
<td class="px-5 py-5 text-sm bg-white">
|
||||
{{ item.type }}
|
||||
</td>
|
||||
<td class="px-5 py-5 text-sm bg-white">
|
||||
{{ item.date }}
|
||||
</td>
|
||||
<td class="px-5 py-5 text-sm bg-white">
|
||||
<UButton
|
||||
@click="styleStore.deleteHistory(item.id)"
|
||||
color="sky"
|
||||
>删除</UButton>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</table>
|
||||
</div>
|
||||
<div v-else class="text-center py-5">
|
||||
<p class="text-gray-500">当前没有查询历史记录。</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</USlideover>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
28
composables/useFormatTime.ts
Normal file
28
composables/useFormatTime.ts
Normal file
@ -0,0 +1,28 @@
|
||||
export const formatTimeAgo = (dateString: string) => {
|
||||
const now = new Date();
|
||||
const date = new Date(dateString);
|
||||
const seconds = Math.floor((now.getTime() - date.getTime()) / 1000);
|
||||
|
||||
let interval = seconds / 31536000;
|
||||
|
||||
if (interval > 1) {
|
||||
return Math.floor(interval) + " 年前";
|
||||
}
|
||||
interval = seconds / 2592000;
|
||||
if (interval > 1) {
|
||||
return Math.floor(interval) + " 月前";
|
||||
}
|
||||
interval = seconds / 86400;
|
||||
if (interval > 1) {
|
||||
return Math.floor(interval) + " 天前";
|
||||
}
|
||||
interval = seconds / 3600;
|
||||
if (interval > 1) {
|
||||
return Math.floor(interval) + " 小时前";
|
||||
}
|
||||
interval = seconds / 60;
|
||||
if (interval > 1) {
|
||||
return Math.floor(interval) + " 分钟前";
|
||||
}
|
||||
return Math.floor(seconds) + " 秒前";
|
||||
};
|
10
lang/en.ts
10
lang/en.ts
@ -11,7 +11,15 @@ export default defineI18nLocale(async locale => {
|
||||
dns:{
|
||||
title: 'DNS Query',
|
||||
description: 'Query the DNS records of {domain}, including A records, AAAA records, CNAME records, MX records, NS records, TXT records, etc.',
|
||||
keywords: 'DNS query, {domain}, domain resolution, domain resolution record'
|
||||
keywords: 'DNS query, {domain}, domain resolution, domain resolution record',
|
||||
//DNS query result
|
||||
dnsResult: 'DNS query result',
|
||||
//A record
|
||||
aRecord: 'A record',
|
||||
//NS record
|
||||
nsRecord: 'NS record',
|
||||
//SOA record
|
||||
soaRecord: 'SOA record',
|
||||
},
|
||||
index: {
|
||||
tips: 'The information you submit for your query will not be recorded!',
|
||||
|
10
lang/tw.ts
10
lang/tw.ts
@ -11,7 +11,15 @@ export default defineI18nLocale(async locale => {
|
||||
dns: {
|
||||
title: 'DNS查詢',
|
||||
description: '查詢{domain}的DNS記錄,包括A記錄、AAAA記錄、CNAME記錄、MX記錄、NS記錄、TXT記錄等。',
|
||||
keywords: 'DNS查詢, {domain}, 域名解析, 域名解析記錄'
|
||||
keywords: 'DNS查詢, {domain}, 域名解析, 域名解析記錄',
|
||||
//DNS查詢結果
|
||||
dnsResult: 'DNS查詢結果',
|
||||
//A記錄
|
||||
aRecord: 'A記錄',
|
||||
//NS記錄
|
||||
nsRecord: 'NS記錄',
|
||||
//SOA記錄
|
||||
soaRecord: 'SOA記錄',
|
||||
},
|
||||
index: {
|
||||
tips: '您提交的查詢信息不會被記錄!',
|
||||
|
12
lang/zh.ts
12
lang/zh.ts
@ -11,13 +11,21 @@ export default defineI18nLocale(async locale => {
|
||||
dns:{
|
||||
title: 'DNS查询',
|
||||
description: '查询{domain}的DNS记录,包括A记录、AAAA记录、CNAME记录、MX记录、NS记录、TXT记录等。',
|
||||
keywords: 'DNS查询, {domain}, 域名解析, 域名解析记录'
|
||||
keywords: 'DNS查询, {domain}, 域名解析, 域名解析记录',
|
||||
//DNS查询结果
|
||||
dnsResult: 'DNS查询结果',
|
||||
//A记录
|
||||
aRecord: 'A记录',
|
||||
//NS记录
|
||||
nsRecord: 'NS记录',
|
||||
//SOA记录
|
||||
soaRecord: 'SOA记录',
|
||||
},
|
||||
index: {
|
||||
tips: '您提交的查询信息不会被记录!',
|
||||
placeholder: '请输入域名',
|
||||
onSubmit: '提交',
|
||||
title: 'WHOIS与Dns查询工具网站',
|
||||
title: 'Whois与Dns查询工具网站',
|
||||
description: '提供域名WHOIS查询、域名DNS查询、域名注册商查询、域名注册信息查询等服务',
|
||||
keywords: '域名whois查询,whois查询,whois信息查询,whois查询工具,whois查询网站,whois查询api,whois查询接口',
|
||||
},
|
||||
|
@ -78,11 +78,11 @@ onMounted(() => {
|
||||
<template>
|
||||
<div
|
||||
class="w-full text-xs bg-[#F1F3F4] dark:bg-transparent"
|
||||
:class="{ 'h-[90vh]': !styleStore.isPage && clientMounted }"
|
||||
:class="{ 'h-[90vh]': !styleStore.getIsPage && clientMounted }"
|
||||
>
|
||||
<div
|
||||
class=" max-w-screen-lg mx-auto px-[1em] pb-[10vh] "
|
||||
:class="{ 'pt-[25vh]': !styleStore.isPage && clientMounted, 'pt-[5vh]': styleStore.isPage || !clientMounted }"
|
||||
:class="{ 'pt-[25vh]': !styleStore.getIsPage && clientMounted, 'pt-[5vh]': styleStore.getIsPage || !clientMounted }"
|
||||
>
|
||||
<nav class=" w-full text-[#464747] h-5 dark:bg-gray-700">
|
||||
<NuxtLink class="mb-3 font-bold text-2xl inline-block text-current no-underline dark:text-white"
|
||||
|
@ -11,6 +11,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxt/ui": "^2.14.1",
|
||||
"@nuxtjs/tailwindcss": "^6.11.4",
|
||||
"@pinia/nuxt": "^0.5.1",
|
||||
"nuxt": "^3.10.3",
|
||||
"vue": "^3.4.21",
|
||||
|
@ -1,5 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import {useStyleStore} from "~/stores/style";
|
||||
import {AdjustTimeToUTCOffset} from "~/utils/utc";
|
||||
import {useTimeStore} from "~/stores/time";
|
||||
|
||||
const {t} = useI18n()
|
||||
|
||||
@ -15,9 +17,25 @@ const {data, pending, error, refresh} = await useAsyncData(
|
||||
})
|
||||
)
|
||||
|
||||
const timeStore = useTimeStore()
|
||||
const styleStore = useStyleStore()
|
||||
|
||||
styleStore.setIsPage(true)
|
||||
|
||||
const localePath = useLocalePath()
|
||||
|
||||
if (!error.value) {
|
||||
styleStore.addOrUpdateHistory(
|
||||
{
|
||||
id: domainData,
|
||||
type: 'dns',
|
||||
domain: domainData,
|
||||
path: localePath(`/dns/${domain}.html`),
|
||||
date: AdjustTimeToUTCOffset(new Date().toString(), timeStore.timeZones)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
useHead({
|
||||
title: `${domainData} - ${t('dns.title')}`,
|
||||
meta: [
|
||||
@ -36,10 +54,10 @@ useHead({
|
||||
<div class="mt-5">
|
||||
<div class="bg-white shadow-lg rounded-lg overflow-hidden">
|
||||
<div class="p-6">
|
||||
<h2 class="text-2xl font-bold text-gray-800 mb-6">DNS查询结果</h2>
|
||||
<h2 class="text-2xl font-bold text-gray-800 mb-6">{{ t('dns.dnsResult') }}</h2>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<h3 class="font-semibold text-lg text-blue-600 mb-2">A记录</h3>
|
||||
<h3 class="font-semibold text-lg text-blue-600 mb-2">{{ t('dns.aRecord') }}</h3>
|
||||
<div class="border rounded-lg p-4 bg-blue-50">
|
||||
<ul class="list-none space-y-2">
|
||||
<li v-for="(record, index) in data.A" :key="'a-record-' + index" class="flex justify-between items-center">
|
||||
@ -51,7 +69,7 @@ useHead({
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-semibold text-lg text-green-600 mb-2">NS记录</h3>
|
||||
<h3 class="font-semibold text-lg text-green-600 mb-2">{{ t('dns.nsRecord') }}</h3>
|
||||
<div class="border rounded-lg p-4 bg-green-50">
|
||||
<ul class="list-none space-y-2">
|
||||
<li v-for="(record, index) in data.NS" :key="'ns-record-' + index" class="flex justify-between items-center">
|
||||
@ -62,7 +80,7 @@ useHead({
|
||||
</div>
|
||||
</div>
|
||||
<div class="md:col-span-2">
|
||||
<h3 class="font-semibold text-lg text-purple-600 mb-2">SOA记录</h3>
|
||||
<h3 class="font-semibold text-lg text-purple-600 mb-2">{{ t('dns.soaRecord') }}</h3>
|
||||
<div class="border rounded-lg p-4 bg-purple-50">
|
||||
<ul class="list-none space-y-2">
|
||||
<li><span class="font-medium text-gray-700">MName:</span> <span class="font-normal text-gray-600">{{ data.SOA.MName }}</span></li>
|
||||
|
@ -11,6 +11,12 @@ const {t} = useI18n()
|
||||
|
||||
const domainData = domain.replace(/_/g, '.')
|
||||
|
||||
const showRawData = ref(false);
|
||||
const timeStore = useTimeStore()
|
||||
const styleStore = useStyleStore()
|
||||
|
||||
const localePath = useLocalePath()
|
||||
|
||||
const {data, pending, error, refresh} = await useAsyncData(
|
||||
'mountains',
|
||||
() => $fetch('/api/whois', {
|
||||
@ -19,12 +25,20 @@ const {data, pending, error, refresh} = await useAsyncData(
|
||||
})
|
||||
)
|
||||
|
||||
const parsedInfo = ParseWhois(data.value);
|
||||
const showRawData = ref(false);
|
||||
const timeStore = useTimeStore()
|
||||
const styleStore = useStyleStore()
|
||||
styleStore.setIsPage(true)
|
||||
if (!error.value) {
|
||||
styleStore.addOrUpdateHistory(
|
||||
{
|
||||
id: domainData,
|
||||
type: 'whois',
|
||||
domain: domainData,
|
||||
path: localePath(`/whois/${domain}.html`),
|
||||
date: AdjustTimeToUTCOffset(new Date().toString(), timeStore.timeZones)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const parsedInfo = ParseWhois(data.value);
|
||||
styleStore.setIsPage(true)
|
||||
useHead({
|
||||
title: `${domainData} - ${t('whois.title')}`,
|
||||
meta: [
|
||||
@ -37,7 +51,6 @@ useHead({
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@ -8,6 +8,9 @@ dependencies:
|
||||
'@nuxt/ui':
|
||||
specifier: ^2.14.1
|
||||
version: 2.14.1(nuxt@3.10.3)(rollup@4.12.0)(vite@5.1.4)(vue@3.4.21)
|
||||
'@nuxtjs/tailwindcss':
|
||||
specifier: ^6.11.4
|
||||
version: 6.11.4(rollup@4.12.0)
|
||||
'@pinia/nuxt':
|
||||
specifier: ^0.5.1
|
||||
version: 0.5.1(rollup@4.12.0)(typescript@5.3.3)(vue@3.4.21)
|
||||
|
@ -1,14 +1,78 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
interface HistoryRecord {
|
||||
id: number;
|
||||
type: string;
|
||||
domain: string;
|
||||
path: string;
|
||||
date: string;
|
||||
}
|
||||
|
||||
export const useStyleStore = defineStore('style', {
|
||||
state: () => {
|
||||
return {
|
||||
isPage: true,
|
||||
history: [] as HistoryRecord[],
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
setIsPage(isPage: boolean) {
|
||||
this.isPage = isPage
|
||||
},
|
||||
setHistory(history: any) {
|
||||
this.history = history
|
||||
},
|
||||
addOrUpdateHistory(newHistory: {
|
||||
date: string;
|
||||
path: any;
|
||||
domain: any;
|
||||
id: any;
|
||||
type: string
|
||||
}) {
|
||||
const existingIndex = this.history.findIndex(history => history.domain === newHistory.domain && history.type === newHistory.type);
|
||||
|
||||
if (existingIndex !== -1) {
|
||||
// 更新存在的记录的时间戳
|
||||
this.history[existingIndex].date = new Date().toISOString();
|
||||
} else {
|
||||
// 添加新记录之前,检查是否已达到保存记录的最大数量
|
||||
if (this.history.length >= 30) {
|
||||
// 确保历史记录按时间降序排列
|
||||
this.history.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
|
||||
// 移除最旧的记录
|
||||
this.history.pop();
|
||||
}
|
||||
|
||||
// 添加新的记录
|
||||
const record: HistoryRecord = {
|
||||
...newHistory,
|
||||
id: Date.now(),
|
||||
date: new Date().toISOString(),
|
||||
};
|
||||
this.history.unshift(record); // 添加到数组的开头
|
||||
}
|
||||
|
||||
// 再次确保历史记录按时间降序排列
|
||||
this.history.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
|
||||
},
|
||||
deleteHistory(id: number) {
|
||||
const index = this.history.findIndex(history => history.id === id);
|
||||
if (index !== -1) {
|
||||
this.history.splice(index, 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
getIsPage(state) {
|
||||
return state.isPage
|
||||
},
|
||||
getHistory(state) {
|
||||
return state.history
|
||||
}
|
||||
},
|
||||
persist: {
|
||||
storage: persistedState.cookiesWithOptions({
|
||||
sameSite: 'strict',
|
||||
}),
|
||||
},
|
||||
})
|
||||
|
8
tailwind.config.ts
Normal file
8
tailwind.config.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import type { Config } from 'tailwindcss'
|
||||
|
||||
// Default are on https://tailwindcss.nuxtjs.org/tailwind/config#default-configuration
|
||||
export default <Partial<Config>>{
|
||||
theme: {},
|
||||
plugins: [],
|
||||
content: []
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user