👔 完成历史记录功能优化多语言

This commit is contained in:
7836246 2024-03-03 07:17:26 +08:00
parent f9693bd560
commit 0ea2d2a3df
12 changed files with 257 additions and 16 deletions

View File

@ -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>

View 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) + " 秒前";
};

View File

@ -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!',

View File

@ -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: '您提交的查詢信息不會被記錄!',

View File

@ -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查询接口',
},

View File

@ -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"

View File

@ -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",

View File

@ -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>

View File

@ -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
View File

@ -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)

View File

@ -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
View 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: []
}