🎨 增加 Go 后端
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
<script lang="ts" setup>
|
||||
const localePath = useLocalePath()
|
||||
const router = useRouter();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="cursor-pointer flex h-10 w-10 items-center justify-center rounded-lg bg-gray-100 dark:bg-gray-700"
|
||||
@click="router.push(localePath('/settings/api'))"
|
||||
>
|
||||
<Icon name="i-eos-icons:api-outlined" class=" text-lg dark:text-white" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
full: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
showFooter: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="cus-scroll h-full flex-col flex-1 bg-#f5f6fb dark:bg-#121212">
|
||||
<transition name="fade-slide" mode="out-in" appear>
|
||||
<main :class="{ 'flex-1': full }" class="m-12"><slot /></main>
|
||||
</transition>
|
||||
<slot v-if="$slots.footer" name="footer" />
|
||||
<CommonTheFooter v-else-if="showFooter" class="mb-12 mt-auto" />
|
||||
<n-back-top :bottom="20" />
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,24 @@
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
text: String
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- 公告部分 -->
|
||||
<div class="bg-gray-200 p-3 rounded-md mb-5 dark:bg-[#000000FF]">
|
||||
<div class="flex items-center">
|
||||
<i aria-hidden="true" class="icon fas fa-bullhorn mr-3"></i>
|
||||
</div>
|
||||
<div class="flex-grow">
|
||||
<div class="text-sm text-gray-800 dark:text-white">
|
||||
{{ text }}
|
||||
<slot name="text"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,64 @@
|
||||
<script lang="ts" setup>
|
||||
const colorMode = useColorMode()
|
||||
const availableColor = ref([
|
||||
{
|
||||
id: 1,
|
||||
name: 'system',
|
||||
icon: 'ph:laptop-duotone',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'dark',
|
||||
icon: 'ph:moon-stars-duotone',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'light',
|
||||
icon: 'ph:sun-dim-duotone',
|
||||
},
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<HeadlessListbox
|
||||
v-model="$colorMode.preference"
|
||||
as="div"
|
||||
class="relative flex items-center"
|
||||
>
|
||||
<HeadlessListboxLabel class="sr-only">
|
||||
Theme
|
||||
</HeadlessListboxLabel>
|
||||
<HeadlessListboxButton type="button" title="Change Color">
|
||||
<div
|
||||
class="flex h-10 w-10 items-center justify-center rounded-lg bg-gray-100 dark:bg-gray-700"
|
||||
>
|
||||
<Icon name="ph:palette-duotone" class=" text-lg dark:text-white"/>
|
||||
</div>
|
||||
</HeadlessListboxButton>
|
||||
<HeadlessListboxOptions
|
||||
class="absolute top-full right-0 z-[999] mt-2 w-40 overflow-hidden rounded-lg bg-white text-sm font-semibold text-gray-700 shadow-lg shadow-gray-300 outline-none dark:bg-gray-800 dark:text-white dark:shadow-gray-500 dark:ring-0"
|
||||
>
|
||||
<HeadlessListboxOption
|
||||
v-for="color in availableColor"
|
||||
:key="color.id"
|
||||
:value="color.name"
|
||||
class="flex w-full cursor-pointer items-center justify-between py-2 px-3"
|
||||
:class="{
|
||||
'text-white-500 bg-gray-200 dark:bg-gray-500/50':
|
||||
colorMode.preference === color.name,
|
||||
'hover:bg-gray-200 dark:hover:bg-gray-700/30':
|
||||
colorMode.preference !== color.name,
|
||||
}"
|
||||
>
|
||||
<span class="truncate">
|
||||
{{ color.name }}
|
||||
</span>
|
||||
<span class="flex items-center justify-center text-sm">
|
||||
<Icon :name="color.icon" class="text-base"/>
|
||||
</span>
|
||||
</HeadlessListboxOption>
|
||||
</HeadlessListboxOptions>
|
||||
</HeadlessListbox>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,26 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
const emit = defineEmits(['action'])
|
||||
|
||||
const handleClick = () => {
|
||||
const urlParam = 'dns' // 这里是你想传递给handleAction方法的参数
|
||||
emit('action', urlParam)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<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="handleClick"
|
||||
>
|
||||
<Icon name="eos-icons:dns" class=" text-lg dark:text-white" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,44 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
const isOpen = ref(false)
|
||||
const {t} = useI18n()
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<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="mdi:about-circle-outline" class=" text-lg dark:text-white"/>
|
||||
</div>
|
||||
</div>
|
||||
<NDrawer
|
||||
v-model:show="isOpen"
|
||||
placement="left"
|
||||
:default-width="502"
|
||||
resizable
|
||||
>
|
||||
<NDrawerContent
|
||||
:title="t('index.support')"
|
||||
closable
|
||||
>
|
||||
<div class="flex flex-wrap mt-2 ">
|
||||
<!-- <span-->
|
||||
<!-- v-for="item in SupportedTLDs"-->
|
||||
<!-- :key="item"-->
|
||||
<!-- class="m-1 px-2 py-1 text-sm font-semibold text-gray-800 bg-gray-200 rounded hover:bg-gray-300"-->
|
||||
<!-- >-->
|
||||
<!-- {{ item }}-->
|
||||
<!-- </span>-->
|
||||
</div>
|
||||
</NDrawerContent>
|
||||
</NDrawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
const localePath = useLocalePath()
|
||||
const {t} = useI18n()
|
||||
</script>
|
||||
<template>
|
||||
<footer class="text-gray-800 h-[10vh] bg-[#F1F3F4] dark:text-white dark:bg-[#000000FF]">
|
||||
<div class="max-w-5xl mx-auto py-4 px-4 flex justify-between items-center">
|
||||
<div class="text-sm">
|
||||
{{ t('footer.text') }}
|
||||
</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<NuxtLink :to="localePath('/api.html')" class="hover:underline">{{ t('footer.api') }}</NuxtLink>
|
||||
<NuxtLink to="https://github.com/7836246/Nuxt-Whois" class="hover:underline">
|
||||
<Icon name="ant-design:github-outlined" class="h-6 w-6"/>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
@@ -0,0 +1,96 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
const isOpen = ref(false)
|
||||
const settingsStore = useSettingsStore()
|
||||
const {t} = useI18n()
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div title="Change Color">
|
||||
<div
|
||||
class="cursor-pointer flex h-10 w-10 items-center justify-center rounded-lg dark:bg-gray-700"
|
||||
@click="isOpen = true"
|
||||
>
|
||||
<Icon name="ic:baseline-history" class=" text-lg dark:text-white"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<NDrawer
|
||||
v-model:show="isOpen"
|
||||
placement="right"
|
||||
:default-width="602"
|
||||
resizable
|
||||
>
|
||||
|
||||
<NDrawerContent
|
||||
:title="t('history.title')"
|
||||
class="w-full min-h-screen overflow-y-auto dark:text-white dark:bg-[#000000FF]"
|
||||
closable
|
||||
>
|
||||
<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 py-1 px-3 rounded-full dark:text-white dark:bg-[#000000FF]">
|
||||
{{ t('history.tips', {length: settingsStore.getHistory.length}) }}
|
||||
</span>
|
||||
</h1>
|
||||
<div class=" shadow-md rounded-lg ">
|
||||
<!-- 条件渲染,如果有历史记录则显示表格,否则显示提示 -->
|
||||
<div v-if="settingsStore.getHistory.length">
|
||||
<!-- 表格头部和内容 -->
|
||||
<table class="min-w-full leading-normal ">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="px-5 py-3 border-b-2 border-gray-200 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">
|
||||
{{ t('history.domain') }}
|
||||
</th>
|
||||
<th class="px-5 py-3 border-b-2 border-gray-200 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">
|
||||
{{ t('history.type') }}
|
||||
</th>
|
||||
<th class="px-5 py-3 border-b-2 border-gray-200 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">
|
||||
{{ t('history.time') }}
|
||||
</th>
|
||||
<th class="px-5 py-3 border-b-2 border-gray-200 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">
|
||||
{{ t('history.actions') }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- 这里将使用循环来动态展示查询历史 -->
|
||||
<tr v-for="item in settingsStore.getHistory" :key="item.id"
|
||||
class="border-b border-gray-200 dark:text-white dark:bg-[#000000FF]">
|
||||
<td class="px-5 py-5 text-sm ">
|
||||
<NuxtLink :to="item.path">{{ item.domain }}</NuxtLink>
|
||||
</td>
|
||||
<td class="px-5 py-5 text-sm ">
|
||||
{{ item.type }}
|
||||
</td>
|
||||
<td class="px-5 py-5 text-sm ">
|
||||
{{ item.date }}
|
||||
</td>
|
||||
<td class="px-5 py-5 text-sm ">
|
||||
<NButton
|
||||
@click="settingsStore.deleteHistory(item.id)"
|
||||
|
||||
>{{ t('common.actions.delete') }}
|
||||
</NButton>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div v-else class="text-center py-5">
|
||||
<p class="text-gray-500">{{ t('history.empty') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</NDrawerContent>
|
||||
</NDrawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,61 @@
|
||||
<script lang="ts" setup>
|
||||
|
||||
const switchLocalePath = useSwitchLocalePath()
|
||||
|
||||
const { locale } = useI18n()
|
||||
|
||||
const local = computed(() => {
|
||||
return locale.value
|
||||
})
|
||||
|
||||
const availableLocales = [
|
||||
{ iso: 'en', name: 'English', flag: 'twemoji:flag-us-outlying-islands' },
|
||||
{ iso: 'zh', name: '中文简体', flag: 'emojione-v1:flag-for-china' },
|
||||
{ iso: 'tw', name: '中文繁体', flag: 'flag:tw-4x3' },
|
||||
// 添加更多语言...
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<HeadlessListbox
|
||||
v-model="local"
|
||||
as="div"
|
||||
class="relative flex items-center"
|
||||
>
|
||||
<HeadlessListboxLabel class="sr-only">
|
||||
Change Language
|
||||
</HeadlessListboxLabel>
|
||||
<HeadlessListboxButton type="button" title="Change Language">
|
||||
<div
|
||||
class="flex h-10 w-10 items-center justify-center rounded-lg bg-gray-100 dark:bg-gray-700"
|
||||
>
|
||||
<Icon name="i-ph:translate-bold" class=" text-lg dark:text-white" size="20" />
|
||||
</div>
|
||||
</HeadlessListboxButton>
|
||||
<HeadlessListboxOptions
|
||||
class="absolute top-full right-0 z-[999] mt-2 w-40 overflow-hidden rounded-lg bg-white text-sm font-semibold text-gray-700 shadow-lg shadow-gray-300 outline-none dark:bg-gray-800 dark:text-white dark:shadow-gray-500 dark:ring-0"
|
||||
>
|
||||
<NuxtLink
|
||||
v-for="lang in availableLocales"
|
||||
:key="lang.iso"
|
||||
:to="switchLocalePath(lang.iso)"
|
||||
class="flex w-full cursor-pointer items-center justify-between py-2 px-3"
|
||||
:class="{
|
||||
'text-white-500 bg-gray-200 dark:bg-gray-500/50':
|
||||
local === lang.iso,
|
||||
'hover:bg-gray-200 dark:hover:bg-gray-700/30':
|
||||
local !== lang.iso,
|
||||
}"
|
||||
>
|
||||
<span class="truncate">
|
||||
{{ lang.name }}
|
||||
</span>
|
||||
<span class="flex items-center justify-center text-sm">
|
||||
<Icon :name="lang.flag" class="text-base" size="20" />
|
||||
</span>
|
||||
</NuxtLink>
|
||||
</HeadlessListboxOptions>
|
||||
</HeadlessListbox>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,98 @@
|
||||
<script setup lang="ts">
|
||||
// import { MeModal } from '@/components'
|
||||
const [modalRef] = useModal()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
123
|
||||
<div>
|
||||
<n-tooltip trigger="hover" placement="left">
|
||||
<template #trigger>
|
||||
<IconSettings size="32" @click="modalRef.open()" filled class="cursor-pointer text-32 color-primary" />
|
||||
</template>
|
||||
布局设置
|
||||
</n-tooltip>
|
||||
<MeModal
|
||||
ref="modalRef"
|
||||
title="布局设置"
|
||||
:show-footer="false"
|
||||
width="600px"
|
||||
:modal-style="{ opacity: 0.85 }"
|
||||
>
|
||||
<n-space justify="space-between">
|
||||
<div class="flex-col cursor-pointer justify-center" @click="appStore.setLayout('simple')">
|
||||
<div class="flex">
|
||||
<n-skeleton :width="20" :height="60" />
|
||||
<div class="ml-4">
|
||||
<n-skeleton :width="80" :height="60" />
|
||||
</div>
|
||||
</div>
|
||||
<n-button
|
||||
class="mt-12"
|
||||
size="small"
|
||||
:type="appStore.layout === 'simple' ? 'primary' : ''"
|
||||
ghost
|
||||
>
|
||||
简约
|
||||
</n-button>
|
||||
</div>
|
||||
<div class="flex-col cursor-pointer justify-center" @click="appStore.setLayout('normal')">
|
||||
<div class="flex">
|
||||
<n-skeleton :width="20" :height="60" />
|
||||
<div class="ml-4">
|
||||
<n-skeleton :width="80" :height="10" />
|
||||
<n-skeleton class="mt-4" :width="80" :height="46" />
|
||||
</div>
|
||||
</div>
|
||||
<n-button
|
||||
class="mt-12"
|
||||
size="small"
|
||||
:type="appStore.layout === 'normal' ? 'primary' : ''"
|
||||
ghost
|
||||
>
|
||||
通用
|
||||
</n-button>
|
||||
</div>
|
||||
|
||||
<div class="flex-col cursor-pointer justify-center" @click="appStore.setLayout('full')">
|
||||
<div class="flex">
|
||||
<n-skeleton :width="20" :height="60" />
|
||||
<div class="ml-4">
|
||||
<n-skeleton :width="80" :height="6" />
|
||||
<n-skeleton class="mt-4" :width="80" :height="4" />
|
||||
<n-skeleton class="mt-4" :width="80" :height="42" />
|
||||
</div>
|
||||
</div>
|
||||
<n-button
|
||||
class="mt-12"
|
||||
size="small"
|
||||
:type="appStore.layout === 'full' ? 'primary' : ''"
|
||||
ghost
|
||||
>
|
||||
全面
|
||||
</n-button>
|
||||
</div>
|
||||
<div class="flex-col cursor-pointer justify-center" @click="appStore.setLayout('empty')">
|
||||
<div class="flex">
|
||||
<n-skeleton :width="104" :height="60" />
|
||||
</div>
|
||||
<n-button
|
||||
class="mt-12"
|
||||
size="small"
|
||||
:type="appStore.layout === 'empty' ? 'primary' : ''"
|
||||
ghost
|
||||
>
|
||||
空白
|
||||
</n-button>
|
||||
</div>
|
||||
</n-space>
|
||||
<p class="mt-16 opacity-50">
|
||||
注: 此设置仅对未设置layout或者设置成跟随系统的页面有效,菜单设置的layout优先级最高
|
||||
</p>
|
||||
</MeModal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,53 @@
|
||||
<script lang="ts" setup>
|
||||
import {useSettingsStore} from "~/stores/settings";
|
||||
|
||||
const availableTimeZones = ref([
|
||||
{ id: 1, name: 'currentWindow' },
|
||||
{ id: 2, name: 'newWindow' },
|
||||
]);
|
||||
const {t} = useI18n()
|
||||
const settingsStore = useSettingsStore()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<HeadlessListbox
|
||||
v-model="settingsStore.linkOpenType"
|
||||
as="div"
|
||||
class="relative flex items-center"
|
||||
>
|
||||
<HeadlessListboxLabel class="sr-only">
|
||||
Theme
|
||||
</HeadlessListboxLabel>
|
||||
<HeadlessListboxButton type="button" title="Change Color">
|
||||
<div
|
||||
class="flex h-10 w-10 items-center justify-center rounded-lg bg-gray-100 dark:bg-gray-700"
|
||||
>
|
||||
<Icon name="material-symbols:link" class=" text-lg dark:text-white" />
|
||||
</div>
|
||||
</HeadlessListboxButton>
|
||||
<HeadlessListboxOptions
|
||||
class="absolute top-full right-0 z-[999] mt-2 w-40 max-h-60 overflow-y-auto rounded-lg bg-white text-sm font-semibold text-gray-700 shadow-lg shadow-gray-300 outline-none dark:bg-gray-800 dark:text-white dark:shadow-gray-500 dark:ring-0"
|
||||
>
|
||||
<HeadlessListboxOption
|
||||
v-for="item in availableTimeZones"
|
||||
:key="item.id"
|
||||
:value="item.name"
|
||||
class="flex w-full cursor-pointer items-center justify-between py-2 px-3 hover:bg-gray-100 dark:hover:bg-gray-600"
|
||||
:class="{
|
||||
'text-white-500 bg-gray-200 dark:bg-gray-500/50':
|
||||
settingsStore.linkOpenType === item.name,
|
||||
'hover:bg-gray-200 dark:hover:bg-gray-700/30':
|
||||
settingsStore.linkOpenType !== item.name,
|
||||
}"
|
||||
>
|
||||
<span class="truncate">
|
||||
{{ t(`settings.${item.name}`) }}
|
||||
</span>
|
||||
<span class="flex items-center justify-center text-sm">
|
||||
</span>
|
||||
</HeadlessListboxOption>
|
||||
</HeadlessListboxOptions>
|
||||
</HeadlessListbox>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
const localePath = useLocalePath()
|
||||
const router = useRouter();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<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="router.push(localePath('/settings'))"
|
||||
>
|
||||
<Icon name="uil:setting" class=" text-lg dark:text-white" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,23 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<footer class="f-c-c text-14 text-gray-500">
|
||||
<p>
|
||||
Copyright © 2023
|
||||
<a
|
||||
href="https://github.com/zclzone"
|
||||
target="__blank"
|
||||
class="transition"
|
||||
hover="decoration-underline color-primary"
|
||||
>
|
||||
Ronnie Zhang(大脸怪)
|
||||
</a>
|
||||
</p>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,82 @@
|
||||
<script lang="ts" setup>
|
||||
|
||||
const availableTimeZones = ref([
|
||||
{id: 1, name: 'UTC-12', displayName: 'International Date Line West'},
|
||||
{id: 2, name: 'UTC-11', displayName: 'Coordinated Universal Time-11'},
|
||||
{id: 3, name: 'UTC-10', displayName: 'Hawaii'},
|
||||
{id: 4, name: 'UTC-9', displayName: 'Alaska'},
|
||||
{id: 5, name: 'UTC-8', displayName: 'Pacific Time (US & Canada)'},
|
||||
{id: 6, name: 'UTC-7', displayName: 'Mountain Time (US & Canada)'},
|
||||
{id: 7, name: 'UTC-6', displayName: 'Central Time (US & Canada), Mexico City'},
|
||||
{id: 8, name: 'UTC-5', displayName: 'Eastern Time (US & Canada), Bogota, Lima'},
|
||||
{id: 9, name: 'UTC-4', displayName: 'Atlantic Time (Canada), Caracas, La Paz'},
|
||||
{id: 10, name: 'UTC-3', displayName: 'Buenos Aires, Georgetown'},
|
||||
{id: 11, name: 'UTC-2', displayName: 'Coordinated Universal Time-02'},
|
||||
{id: 12, name: 'UTC-1', displayName: 'Azores'},
|
||||
{id: 13, name: 'UTC', displayName: 'Coordinated Universal Time'},
|
||||
{id: 14, name: 'UTC+1', displayName: 'Brussels, Copenhagen, Madrid, Paris'},
|
||||
{id: 15, name: 'UTC+2', displayName: 'Athens, Bucharest, Istanbul'},
|
||||
{id: 16, name: 'UTC+3', displayName: 'Moscow, St. Petersburg, Nairobi'},
|
||||
{id: 17, name: 'UTC+3:30', displayName: 'Tehran'},
|
||||
{id: 18, name: 'UTC+4', displayName: 'Abu Dhabi, Muscat'},
|
||||
{id: 19, name: 'UTC+4:30', displayName: 'Kabul'},
|
||||
{id: 20, name: 'UTC+5', displayName: 'Islamabad, Karachi, Tashkent'},
|
||||
{id: 21, name: 'UTC+5:30', displayName: 'Chennai, Kolkata, Mumbai, New Delhi'},
|
||||
{id: 22, name: 'UTC+5:45', displayName: 'Kathmandu'},
|
||||
{id: 23, name: 'UTC+6', displayName: 'Astana, Dhaka'},
|
||||
{id: 24, name: 'UTC+6:30', displayName: 'Yangon (Rangoon)'},
|
||||
{id: 25, name: 'UTC+7', displayName: 'Bangkok, Hanoi, Jakarta'},
|
||||
{id: 26, name: 'UTC+8', displayName: 'Beijing, Hong Kong, Singapore, Taipei'},
|
||||
{id: 27, name: 'UTC+9', displayName: 'Osaka, Sapporo, Tokyo'},
|
||||
{id: 28, name: 'UTC+9:30', displayName: 'Adelaide, Darwin'},
|
||||
{id: 29, name: 'UTC+10', displayName: 'Brisbane, Canberra, Melbourne, Sydney'},
|
||||
{id: 30, name: 'UTC+11', displayName: 'Solomon Is., New Caledonia'},
|
||||
{id: 31, name: 'UTC+12', displayName: 'Auckland, Wellington'},
|
||||
{id: 32, name: 'UTC+13', displayName: 'Nuku alofa'}
|
||||
]);
|
||||
|
||||
const settingsStore = useSettingsStore()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<HeadlessListbox
|
||||
v-model="settingsStore.timeZones"
|
||||
as="div"
|
||||
class="relative flex items-center"
|
||||
>
|
||||
<HeadlessListboxLabel class="sr-only">
|
||||
Theme
|
||||
</HeadlessListboxLabel>
|
||||
<HeadlessListboxButton type="button" title="Change Color">
|
||||
<div
|
||||
class="flex h-10 w-10 items-center justify-center rounded-lg bg-gray-100 dark:bg-gray-700"
|
||||
>
|
||||
<Icon name="ri:time-zone-line" class=" text-lg dark:text-white"/>
|
||||
</div>
|
||||
</HeadlessListboxButton>
|
||||
<HeadlessListboxOptions
|
||||
class="absolute top-full right-0 z-[999] mt-2 w-40 max-h-60 overflow-y-auto rounded-lg bg-white text-sm font-semibold text-gray-700 shadow-lg shadow-gray-300 outline-none dark:bg-gray-800 dark:text-white dark:shadow-gray-500 dark:ring-0"
|
||||
>
|
||||
<HeadlessListboxOption
|
||||
v-for="item in availableTimeZones"
|
||||
:key="item.id"
|
||||
:value="item.name"
|
||||
class="flex w-full cursor-pointer items-center justify-between py-2 px-3 hover:bg-gray-100 dark:hover:bg-gray-600"
|
||||
:class="{
|
||||
'text-white-500 bg-gray-200 dark:bg-gray-500/50':
|
||||
settingsStore.timeZones === item.name,
|
||||
'hover:bg-gray-200 dark:hover:bg-gray-700/30':
|
||||
settingsStore.timeZones !== item.name,
|
||||
}"
|
||||
>
|
||||
<span class="truncate">
|
||||
{{ item.name }}
|
||||
</span>
|
||||
<span class="flex items-center justify-center text-sm">
|
||||
</span>
|
||||
</HeadlessListboxOption>
|
||||
</HeadlessListboxOptions>
|
||||
</HeadlessListbox>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,62 @@
|
||||
<script lang="ts" setup>
|
||||
const switchLocalePath = useSwitchLocalePath()
|
||||
const settingsStore = useSettingsStore()
|
||||
|
||||
|
||||
const configStore = useConfigStore()
|
||||
const {configServer} = storeToRefs(configStore)
|
||||
|
||||
const handlePost = async (name: string) => {
|
||||
//刷新数据
|
||||
await refreshNuxtData('dns')
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<HeadlessListbox
|
||||
v-model="configServer.dnsArr"
|
||||
as="div"
|
||||
class="relative flex items-center"
|
||||
>
|
||||
<HeadlessListboxLabel class="sr-only">
|
||||
Change Language
|
||||
</HeadlessListboxLabel>
|
||||
<HeadlessListboxButton type="button" title="Change Language">
|
||||
<div
|
||||
class="flex h-10 w-10 items-center justify-center rounded-lg bg-gray-100 dark:bg-gray-700"
|
||||
>
|
||||
<Icon name="gg:select-o" class=" text-lg dark:text-white" size="20"/>
|
||||
</div>
|
||||
</HeadlessListboxButton>
|
||||
|
||||
<HeadlessListboxOptions
|
||||
class="absolute top-full right-0 z-[999] mt-2 w-40 overflow-hidden rounded-lg bg-white text-sm font-semibold text-gray-700 shadow-lg shadow-gray-300 outline-none dark:bg-gray-800 dark:text-white dark:shadow-gray-500 dark:ring-0"
|
||||
>
|
||||
<div
|
||||
v-for="lang in configServer.dnsArr"
|
||||
:key="lang.name"
|
||||
@click="handlePost(lang.name)"
|
||||
:class="{
|
||||
'flex w-full cursor-pointer items-center justify-between py-2 px-3 text-white-500 bg-gray-200 dark:bg-gray-500/50':
|
||||
dnsStore.getFirstNewDnsShown.name === lang.name && lang.show,
|
||||
'flex w-full cursor-pointer items-center justify-between py-2 px-3 hover:bg-gray-200 dark:hover:bg-gray-700/30':
|
||||
dnsStore.getFirstNewDnsShown.name !== lang.name && lang.show,
|
||||
}"
|
||||
>
|
||||
<span
|
||||
v-if="lang.show"
|
||||
class="truncate">
|
||||
{{ lang.iName }}
|
||||
</span>
|
||||
<span
|
||||
v-if="lang.show"
|
||||
class="flex items-center justify-center text-sm">
|
||||
<Icon :name="lang.flag" class="text-base" size="20"/>
|
||||
</span>
|
||||
</div>
|
||||
</HeadlessListboxOptions>
|
||||
</HeadlessListbox>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,45 @@
|
||||
<script setup lang="ts">
|
||||
const props = defineProps({
|
||||
data:{
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const {t} = useI18n()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex bg-gray-100 p-8">
|
||||
<div class="w-full mx-auto">
|
||||
<div class="bg-white shadow-lg rounded-lg p-6 mb-4" v-for="item in data.Answer">
|
||||
<h2 class="text-xl font-bold">{{ item.name }}</h2>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<p class="font-semibold">Type</p>
|
||||
<p>{{ item.type }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="font-semibold">TTL</p>
|
||||
<p>{{ item.TTL }}</p>
|
||||
</div>
|
||||
<div class="col-span-2">
|
||||
<p class="font-semibold">Data</p>
|
||||
<p>{{ item.data }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex space-x-2 mt-4">
|
||||
<span class="bg-green-200 text-green-800 px-2 py-1 rounded">RD: {{ data.RD }}</span>
|
||||
<span class="bg-green-200 text-green-800 px-2 py-1 rounded">RA: {{ data.RA }}</span>
|
||||
<span class="bg-red-200 text-red-800 px-2 py-1 rounded">TC: {{ data.TC }}</span>
|
||||
<span class="bg-red-200 text-red-800 px-2 py-1 rounded">AD: {{ data.AD }}</span>
|
||||
<span class="bg-red-200 text-red-800 px-2 py-1 rounded">CD: {{ data.CD }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,61 @@
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
const {t} = useI18n()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div v-if="data.aRecords">
|
||||
<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.aRecords" :key="'a-record-' + index" class="flex justify-between items-center">
|
||||
<span class="font-medium text-gray-700">IP:</span>
|
||||
<span class="font-normal text-gray-600">{{ record }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="data.nsRecords">
|
||||
<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.nsRecords" :key="'ns-record-' + index" class="flex justify-between items-center">
|
||||
<span class="font-normal text-gray-600">{{ record }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="data.soaRecord"
|
||||
class="md:col-span-2">
|
||||
<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">nsname:</span> <span class="font-normal text-gray-600">{{ data.soaRecord.nsname }}</span></li>
|
||||
<li><span class="font-medium text-gray-700">hostmaster:</span> <span class="font-normal text-gray-600">{{ data.soaRecord.hostmaster }}</span></li>
|
||||
<li><span class="font-medium text-gray-700">serial:</span> <span class="font-normal text-gray-600">{{ data.soaRecord.serial }}</span></li>
|
||||
<li><span class="font-medium text-gray-700">refresh:</span> <span class="font-normal text-gray-600">{{ data.soaRecord.refresh }}</span></li>
|
||||
<li><span class="font-medium text-gray-700">retry:</span> <span class="font-normal text-gray-600">{{ data.soaRecord.retry }}</span></li>
|
||||
<li><span class="font-medium text-gray-700">expire TTL:</span> <span class="font-normal text-gray-600">{{ data.soaRecord.expire }}</span></li>
|
||||
<li><span class="font-medium text-gray-700">minttl TTL:</span> <span class="font-normal text-gray-600">{{ data.soaRecord.minttl }}</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,43 @@
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex p-8">
|
||||
<div class="w-full mx-auto">
|
||||
<div class=" shadow-lg rounded-lg p-6 mb-4" v-for="item in data.Answer">
|
||||
<h2 class="text-xl font-bold">{{ item.name }}</h2>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<p class="font-semibold">Type</p>
|
||||
<p>{{ item.type }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="font-semibold">TTL</p>
|
||||
<p>{{ item.TTL }}</p>
|
||||
</div>
|
||||
<div class="col-span-2">
|
||||
<p class="font-semibold">Data</p>
|
||||
<p>{{ item.data }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex space-x-2 mt-4">
|
||||
<span class="bg-green-200 text-green-800 px-2 py-1 rounded">RD: {{ data.RD }}</span>
|
||||
<span class="bg-green-200 text-green-800 px-2 py-1 rounded">RA: {{ data.RA }}</span>
|
||||
<span class="bg-red-200 text-red-800 px-2 py-1 rounded">TC: {{ data.TC }}</span>
|
||||
<span class="bg-red-200 text-red-800 px-2 py-1 rounded">AD: {{ data.AD }}</span>
|
||||
<span class="bg-red-200 text-red-800 px-2 py-1 rounded">CD: {{ data.CD }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<div class="px-4 space-y-4">
|
||||
<div class="flex gap-2 items-center">
|
||||
<UInput v-model="newDomainSuffix" @input="searchSuffix" :placeholder="t('settings.suffixPlaceholder')" class="flex-grow rounded shadow transition duration-200 ease-in-out" />
|
||||
<UInput v-model="newWhoisServer" :placeholder="t('settings.whoisPlaceholder')" class="flex-grow border-gray-300 rounded shadow transition duration-200 ease-in-out" />
|
||||
<UButton @click="addSuffix" type="button" :disabled="suffixExists" class="p-2 bg-blue-500 text-white rounded hover:bg-blue-700 shadow disabled:bg-gray-400 disabled:cursor-not-allowed transition duration-200 ease-in-out">
|
||||
{{ t('common.actions.add') }}</UButton>
|
||||
</div>
|
||||
<div class="text-sm" v-if="suffixExists">
|
||||
<span class="text-red-500">{{ t('common.actions.suffixExist') }}</span>
|
||||
</div>
|
||||
<div class="overflow-auto h-64 mt-4 bg-gray-50 rounded shadow">
|
||||
<div v-for="(server, suffix) in domainStore.SupportedTLDs" :key="suffix" class="flex items-center justify-between p-2 border-b border-gray-200 last:border-b-0">
|
||||
<div>{{ suffix }}: {{ server }}</div>
|
||||
<UButton @click="removeSuffix(suffix)" type="button" class="bg-red-500 hover:bg-red-700 text-white p-1 rounded shadow transition duration-200 ease-in-out">
|
||||
{{ t('common.actions.delete') }}
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const domainStore = useDomainStore();
|
||||
const newDomainSuffix = ref('');
|
||||
const newWhoisServer = ref('');
|
||||
const suffixExists = computed(() => newDomainSuffix.value in domainStore.SupportedTLDs);
|
||||
|
||||
const toast = useToast()
|
||||
const {t} = useI18n();
|
||||
|
||||
const addSuffix = async () => {
|
||||
if (newDomainSuffix.value && newWhoisServer.value && !suffixExists.value) {
|
||||
await domainStore.addSuffix(newDomainSuffix.value, newWhoisServer.value);
|
||||
newDomainSuffix.value = '';
|
||||
newWhoisServer.value = '';
|
||||
toast.add(
|
||||
{ title: '`添加成功`' }
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const removeSuffix = async (suffix: string) => {
|
||||
await domainStore.removeSuffix(suffix);
|
||||
toast.add(
|
||||
{ title: '删除成功',
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const searchSuffix = () => {
|
||||
// 这个方法被@input事件触发,用于即时反馈,但实际逻辑已由suffixExists处理
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,85 @@
|
||||
<script setup lang="ts">
|
||||
const settingsStore = useSettingsStore()
|
||||
const {getIsDomainList, getIsHistory,} = storeToRefs(settingsStore)
|
||||
const {t} = useI18n()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ClientOnly>
|
||||
<div class="flex justify-between w-full">
|
||||
<div class="flex space-x-2">
|
||||
<!-- 左边的新元素 -->
|
||||
<n-tooltip
|
||||
v-if="getIsDomainList"
|
||||
trigger="hover" placement="top">
|
||||
<template #trigger>
|
||||
<CommonDomainList/>
|
||||
</template>
|
||||
<span>{{ t('popper.support') }}</span>
|
||||
</n-tooltip>
|
||||
|
||||
<n-tooltip
|
||||
v-if="getIsHistory"
|
||||
trigger="hover" placement="top">
|
||||
<template #trigger>
|
||||
<CommonHistory/>
|
||||
</template>
|
||||
<span>{{ t('popper.history') }}</span>
|
||||
</n-tooltip>
|
||||
|
||||
</div>
|
||||
<div class="flex space-x-2">
|
||||
<!-- 右边的现有元素 -->
|
||||
<n-tooltip
|
||||
trigger="hover"
|
||||
placement="top">
|
||||
<template #trigger>
|
||||
<CommonSettingsChange/>
|
||||
</template>
|
||||
<span>{{ t('popper.setting') }}</span>
|
||||
</n-tooltip>
|
||||
|
||||
<n-tooltip
|
||||
trigger="hover"
|
||||
placement="top">
|
||||
<template #trigger>
|
||||
<CommonApiChange/>
|
||||
</template>
|
||||
<span>第三方APi</span>
|
||||
</n-tooltip>
|
||||
|
||||
<n-tooltip
|
||||
trigger="hover"
|
||||
placement="top">
|
||||
<template #trigger>
|
||||
<CommonTimeZonesChange/>
|
||||
</template>
|
||||
<span>{{ settingsStore.timeZones }}</span>
|
||||
</n-tooltip>
|
||||
|
||||
<n-tooltip
|
||||
trigger="hover"
|
||||
placement="top">
|
||||
<template #trigger>
|
||||
<CommonColorChange/>
|
||||
</template>
|
||||
<span>{{ t('popper.theme') }}</span>
|
||||
</n-tooltip>
|
||||
|
||||
<n-tooltip
|
||||
trigger="hover"
|
||||
placement="top">
|
||||
<template #trigger>
|
||||
<CommonLanguageChange/>
|
||||
</template>
|
||||
<span>{{ t('popper.language') }}</span>
|
||||
</n-tooltip>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</ClientOnly>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
const props = defineProps({
|
||||
data: Object,
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
{{ data }}
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
const props = defineProps({
|
||||
data: Object,
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
{{ data }}
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
Reference in New Issue
Block a user