🚩 网站设置功能完成
This commit is contained in:
parent
263ad0a4df
commit
c29c6790a1
1
.dockerignore
Normal file
1
.dockerignore
Normal file
@ -0,0 +1 @@
|
||||
node_modules
|
43
Dockerfile
Normal file
43
Dockerfile
Normal file
@ -0,0 +1,43 @@
|
||||
FROM node:lts-alpine AS base
|
||||
|
||||
# Set the working directory
|
||||
WORKDIR /usr/src/app
|
||||
# Install pnpm
|
||||
RUN apk add --no-cache curl && \
|
||||
curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm
|
||||
|
||||
################################################################################
|
||||
# Create a stage for installing dependencies
|
||||
FROM base as dependencies
|
||||
# Copy the package.json and package-lock.json (or pnpm-lock.yaml if available)
|
||||
COPY package*.json pnpm-lock.yaml* ./
|
||||
# Install dependencies
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
################################################################################
|
||||
# Create a stage for running the application in development mode
|
||||
FROM dependencies as development
|
||||
# Copy the source code
|
||||
COPY . .
|
||||
# Expose the port
|
||||
EXPOSE 3000
|
||||
# Run the application
|
||||
CMD ["pnpm", "run", "dev"]
|
||||
|
||||
################################################################################
|
||||
# Create a stage for building the application
|
||||
FROM dependencies as build
|
||||
# Copy the source code
|
||||
COPY . .
|
||||
# Build the application
|
||||
RUN pnpm run build
|
||||
# Remove extraneous packages
|
||||
RUN pnpm prune --prod
|
||||
|
||||
################################################################################
|
||||
# Create a stage for running the application in production mode
|
||||
FROM base AS production
|
||||
# Copy the built application
|
||||
COPY --from=build /usr/src/app/.output /usr/src/app/.output
|
||||
# Run the application
|
||||
CMD ["node", ".output/server/index.mjs"]
|
@ -48,6 +48,8 @@ yarn
|
||||
|
||||
pnpm dev
|
||||
|
||||
# Nuxt-Whois
|
||||
# Nuxt-Whois
|
||||
# Nuxt-Whois
|
||||
|
||||
```
|
||||
|
||||
# 免责声明
|
||||
本项目开源仅供学习使用,不得用于任何违法用途,否则后果自负,与本人无关。使用请保留项目地址谢谢。
|
||||
|
53
components/common/LinkChange.vue
Normal file
53
components/common/LinkChange.vue
Normal file
@ -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>
|
@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
const timeStore = useTimeStore()
|
||||
const settingsStore = useSettingsStore()
|
||||
const emit = defineEmits(['action'])
|
||||
|
||||
const handleActionFromDnsList = (urlParam:string) => {
|
||||
@ -17,7 +18,9 @@ const {t} = useI18n()
|
||||
<CommonDomainList />
|
||||
</UTooltip>
|
||||
|
||||
<UTooltip :text="t('popper.history')" :popper="{ placement: 'top' }">
|
||||
<UTooltip
|
||||
v-if="settingsStore.getHistory"
|
||||
:text="t('popper.history')" :popper="{ placement: 'top' }">
|
||||
<CommonHistory />
|
||||
</UTooltip>
|
||||
|
||||
|
26
lang/en.ts
26
lang/en.ts
@ -6,6 +6,8 @@ export default defineI18nLocale(async locale => {
|
||||
common: {
|
||||
actions: {
|
||||
delete: 'Delete',
|
||||
reset: 'Reset',
|
||||
confirm: 'Confirm',
|
||||
}
|
||||
},
|
||||
whois:{
|
||||
@ -123,6 +125,28 @@ export default defineI18nLocale(async locale => {
|
||||
theme: 'Theme',
|
||||
language: 'Language',
|
||||
dnsChange: 'DNS Change',
|
||||
}
|
||||
},
|
||||
settings: {
|
||||
//全局设置
|
||||
title: 'Global Settings',
|
||||
//历史记录保留
|
||||
history: 'History Retention',
|
||||
//链接跳转方式
|
||||
linkOpenType: 'Link Open Type',
|
||||
//选择榜单列表内容的跳转方式
|
||||
linkOpenTypeDesc: 'Select the jump method for the list content',
|
||||
//杂项设置
|
||||
miscellaneous: 'Miscellaneous Settings',
|
||||
//重置所有数据
|
||||
reset: 'Reset All Data',
|
||||
//重置所有数据,你的自定义设置都将会丢失
|
||||
resetDesc: 'Reset all data, your custom settings will be lost',
|
||||
//确认重置所有数据?你的自定义设置都将会丢失!
|
||||
resetConfirm: 'Confirm reset all data? Your custom settings will be lost!',
|
||||
// 当前窗口
|
||||
currentWindow: 'Current Window',
|
||||
//新窗口
|
||||
newWindow: 'New Window',
|
||||
},
|
||||
}
|
||||
})
|
||||
|
26
lang/tw.ts
26
lang/tw.ts
@ -6,6 +6,10 @@ export default defineI18nLocale(async locale => {
|
||||
common: {
|
||||
actions: {
|
||||
delete: '刪除',
|
||||
//重置
|
||||
reset: '重置',
|
||||
//確定
|
||||
confirm: '確定',
|
||||
}
|
||||
},
|
||||
whois: {
|
||||
@ -127,6 +131,28 @@ export default defineI18nLocale(async locale => {
|
||||
language: '語言設定',
|
||||
//切換DNS伺服器
|
||||
dnsChange: '切換DNS伺服器',
|
||||
},
|
||||
settings: {
|
||||
//全域性設定
|
||||
title: '全域性設定',
|
||||
//歷史記錄保留
|
||||
history: '歷史記錄保留',
|
||||
//連結跳轉方式
|
||||
linkOpenType: '連結跳轉方式',
|
||||
//選擇榜單列表內容的跳轉方式
|
||||
linkOpenTypeDesc: '選擇榜單列表內容的跳轉方式',
|
||||
//雜項設定
|
||||
miscellaneous: '雜項設定',
|
||||
//重置所有資料
|
||||
reset: '重置所有資料',
|
||||
//重置所有資料,你的自定義設定都將會丟失
|
||||
resetDesc: '重置所有資料,你的自定義設定都將會丟失',
|
||||
//確認重置所有資料?你的自定義設定都將會丟失!
|
||||
resetConfirm: '確認重置所有資料?你的自定義設定都將會丟失!',
|
||||
// 當前視窗
|
||||
currentWindow: '當前視窗',
|
||||
// 新視窗
|
||||
newWindow: '新視窗',
|
||||
}
|
||||
}
|
||||
})
|
||||
|
26
lang/zh.ts
26
lang/zh.ts
@ -7,6 +7,10 @@ export default defineI18nLocale(async locale => {
|
||||
actions: {
|
||||
//删除
|
||||
delete: '删除',
|
||||
//重置
|
||||
reset: '重置',
|
||||
//确定
|
||||
confirm: '确定',
|
||||
}
|
||||
},
|
||||
whois:{
|
||||
@ -133,6 +137,28 @@ export default defineI18nLocale(async locale => {
|
||||
language: '切换语言',
|
||||
//dnsChange
|
||||
dnsChange: '切换DNS服务器',
|
||||
},
|
||||
settings: {
|
||||
//全局设置
|
||||
title: '全局设置',
|
||||
//历史记录保留
|
||||
history: '历史记录保留',
|
||||
//链接跳转方式
|
||||
linkOpenType: '链接跳转方式',
|
||||
//选择榜单列表内容的跳转方式
|
||||
linkOpenTypeDesc: '选择榜单列表内容的跳转方式',
|
||||
//杂项设置
|
||||
miscellaneous: '杂项设置',
|
||||
//重置所有数据
|
||||
reset: '重置所有数据',
|
||||
//重置所有数据,你的自定义设置都将会丢失
|
||||
resetDesc: '重置所有数据,你的自定义设置都将会丢失',
|
||||
//确认重置所有数据?你的自定义设置都将会丢失!
|
||||
resetConfirm: '确认重置所有数据?你的自定义设置都将会丢失!',
|
||||
// 当前窗口
|
||||
currentWindow: '当前窗口',
|
||||
// 新窗口
|
||||
newWindow: '新窗口',
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -14,7 +14,7 @@ const domainData = domain.replace(/_/g, '.')
|
||||
const timeStore = useTimeStore()
|
||||
const styleStore = useStyleStore()
|
||||
const localePath = useLocalePath()
|
||||
|
||||
const settingsStore = useSettingsStore()
|
||||
styleStore.setIsPage(true)
|
||||
|
||||
const {data, pending, error, refresh} = await useAsyncData(
|
||||
@ -28,7 +28,7 @@ const {data, pending, error, refresh} = await useAsyncData(
|
||||
})
|
||||
)
|
||||
|
||||
if (!error.value) {
|
||||
if (!error.value && settingsStore.getHistory) {
|
||||
styleStore.addOrUpdateHistory(
|
||||
{
|
||||
id: domainData,
|
||||
|
@ -1,9 +1,107 @@
|
||||
<script setup lang="ts">
|
||||
import {useStyleStore} from "~/stores/style";
|
||||
import {useSettingsStore} from "~/stores/settings";
|
||||
|
||||
const styleStore = useStyleStore()
|
||||
const settingsStore = useSettingsStore()
|
||||
const {t} = useI18n()
|
||||
const timeStore = useTimeStore()
|
||||
styleStore.setIsPage(true)
|
||||
|
||||
const {isHistory} = storeToRefs(settingsStore)
|
||||
const isOpen = ref(false)
|
||||
|
||||
|
||||
const handleReset = async () => {
|
||||
settingsStore.setHistory(true)
|
||||
settingsStore.setLinkOpenType('currentWindow')
|
||||
styleStore.setHistory([])
|
||||
timeStore.setTimeZones('UTC+8')
|
||||
timeStore.setDnsServer('')
|
||||
await refreshNuxtData()
|
||||
isOpen.value = false
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="setting">
|
||||
<div class="text-2xl font-bold mt-[30px] mb-[20px]">{{ t('settings.title') }}</div>
|
||||
<UCard>
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="text-base ">{{ t('settings.history') }}</div>
|
||||
<div>
|
||||
<UToggle v-model="isHistory" />
|
||||
</div>
|
||||
</div>
|
||||
</UCard>
|
||||
</div>
|
||||
|
||||
<div class="setting">
|
||||
<div class="text-2xl font-bold mt-[30px] mb-[20px]">{{ t('settings.linkOpenType') }}</div>
|
||||
<UCard>
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="text-base "> {{ t('settings.linkOpenTypeDesc') }} </div>
|
||||
<div>
|
||||
<ClientOnly>
|
||||
<CommonLinkChange />
|
||||
</ClientOnly>
|
||||
</div>
|
||||
</div>
|
||||
</UCard>
|
||||
</div>
|
||||
|
||||
<div class="setting">
|
||||
<div class="text-2xl font-bold mt-[30px] mb-[20px]"> {{ t('settings.miscellaneous') }} </div>
|
||||
<u-card class="set-item">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="text-base">{{ t('settings.reset') }} </div>
|
||||
<div class="text-sm " >
|
||||
{{ t('settings.resetDesc') }}
|
||||
</div>
|
||||
<div>
|
||||
<u-button type="warning"
|
||||
@click="isOpen = true"
|
||||
> {{ t('common.actions.reset') }} </u-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<UModal
|
||||
v-model="isOpen"
|
||||
>
|
||||
<UCard
|
||||
:ui="{
|
||||
base: 'h-full flex flex-col',
|
||||
rounded: '',
|
||||
divide: 'divide-y divide-gray-100 dark:divide-gray-800',
|
||||
body: {
|
||||
base: 'grow'
|
||||
}
|
||||
}"
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
|
||||
Modal
|
||||
</h3>
|
||||
<UButton color="gray" variant="ghost" icon="i-heroicons-x-mark-20-solid" class="-my-1" @click="isOpen = false" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="p-4 m-auto text-center">
|
||||
{{ t('settings.resetConfirm') }}
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
<UButton
|
||||
@click="handleReset"
|
||||
class="my-1">
|
||||
{{ t('common.actions.confirm') }}
|
||||
</UButton>
|
||||
</div>
|
||||
</UCard>
|
||||
</UModal>
|
||||
</u-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
@ -14,6 +14,7 @@ const domainData = domain.replace(/_/g, '.')
|
||||
const showRawData = ref(false);
|
||||
const timeStore = useTimeStore()
|
||||
const styleStore = useStyleStore()
|
||||
const settingsStore = useSettingsStore()
|
||||
|
||||
const localePath = useLocalePath()
|
||||
|
||||
@ -25,7 +26,7 @@ const {data, pending, error, refresh} = await useAsyncData(
|
||||
})
|
||||
)
|
||||
|
||||
if (!error.value) {
|
||||
if (!error.value && settingsStore.getHistory) {
|
||||
styleStore.addOrUpdateHistory(
|
||||
{
|
||||
id: domainData,
|
||||
|
28
stores/settings.ts
Normal file
28
stores/settings.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
|
||||
export const useSettingsStore = defineStore('settings', {
|
||||
state: () => {
|
||||
const {t} = useI18n()
|
||||
return {
|
||||
isHistory: true,
|
||||
linkOpenType: 'currentWindow',
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
setHistory(value: boolean) {
|
||||
this.isHistory = value
|
||||
},
|
||||
setLinkOpenType(value: string ) {
|
||||
this.linkOpenType = value
|
||||
},
|
||||
},
|
||||
getters: {
|
||||
getHistory: (state) => state.isHistory,
|
||||
},
|
||||
persist: {
|
||||
storage: persistedState.cookiesWithOptions({
|
||||
sameSite: 'strict',
|
||||
}),
|
||||
},
|
||||
})
|
Loading…
x
Reference in New Issue
Block a user