forked from zguiy/utils
工具完成
This commit is contained in:
654
src/components/tools/TimezoneConverter.vue
Normal file
654
src/components/tools/TimezoneConverter.vue
Normal file
@ -0,0 +1,654 @@
|
||||
<template>
|
||||
<div class="space-y-6">
|
||||
<!-- 工具栏 -->
|
||||
<div class="card p-4">
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<button
|
||||
@click="updateCurrentTime"
|
||||
class="btn-primary"
|
||||
>
|
||||
<FontAwesomeIcon :icon="['fas', 'sync']" class="mr-2" />
|
||||
刷新时间
|
||||
</button>
|
||||
|
||||
<button
|
||||
@click="copyResult"
|
||||
:disabled="!selectedTime"
|
||||
class="btn-secondary"
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
:icon="copied ? ['fas', 'check'] : ['fas', 'copy']"
|
||||
:class="['mr-2', copied && 'text-success']"
|
||||
/>
|
||||
复制时间
|
||||
</button>
|
||||
|
||||
<button
|
||||
@click="resetToNow"
|
||||
class="btn-secondary"
|
||||
>
|
||||
<FontAwesomeIcon :icon="['fas', 'clock']" class="mr-2" />
|
||||
当前时间
|
||||
</button>
|
||||
|
||||
<button
|
||||
@click="addCustomTimezone"
|
||||
class="btn-secondary"
|
||||
>
|
||||
<FontAwesomeIcon :icon="['fas', 'plus']" class="mr-2" />
|
||||
添加时区
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
<!-- 输入区域 -->
|
||||
<div class="space-y-4">
|
||||
<!-- 时间输入 -->
|
||||
<div class="card p-4">
|
||||
<h3 class="text-lg font-semibold text-primary mb-3">输入时间</h3>
|
||||
|
||||
<div class="space-y-4">
|
||||
<!-- 日期时间输入 -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-secondary mb-2">选择日期时间</label>
|
||||
<input
|
||||
v-model="inputDateTime"
|
||||
type="datetime-local"
|
||||
class="input-field"
|
||||
@change="convertTimezones"
|
||||
>
|
||||
</div>
|
||||
|
||||
<!-- 源时区 -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-secondary mb-2">源时区</label>
|
||||
<select v-model="sourceTimezone" class="select-field" @change="convertTimezones">
|
||||
<option v-for="timezone in commonTimezones" :key="timezone.value" :value="timezone.value">
|
||||
{{ timezone.label }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 快速时间选择 -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-secondary mb-2">快速选择</label>
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<button
|
||||
v-for="quickTime in quickTimes"
|
||||
:key="quickTime.label"
|
||||
@click="setQuickTime(quickTime)"
|
||||
class="btn-sm btn-secondary text-xs"
|
||||
>
|
||||
{{ quickTime.label }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 常用时区 -->
|
||||
<div class="card p-4">
|
||||
<h3 class="text-lg font-semibold text-primary mb-3">常用时区</h3>
|
||||
|
||||
<div class="space-y-2">
|
||||
<div
|
||||
v-for="timezone in commonTimezones.slice(0, 8)"
|
||||
:key="timezone.value"
|
||||
class="flex items-center justify-between p-2 bg-block rounded"
|
||||
>
|
||||
<div>
|
||||
<div class="font-medium text-primary">{{ timezone.name }}</div>
|
||||
<div class="text-sm text-secondary">{{ timezone.value }}</div>
|
||||
</div>
|
||||
<div class="text-sm text-primary font-mono">
|
||||
{{ getTimezoneTime(timezone.value) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 时区偏移计算 -->
|
||||
<div class="card p-4">
|
||||
<h3 class="text-lg font-semibold text-primary mb-3">时差计算</h3>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div class="flex space-x-2">
|
||||
<select v-model="timezone1" class="select-field flex-1">
|
||||
<option v-for="timezone in commonTimezones" :key="timezone.value" :value="timezone.value">
|
||||
{{ timezone.name }}
|
||||
</option>
|
||||
</select>
|
||||
<span class="self-center text-secondary">vs</span>
|
||||
<select v-model="timezone2" class="select-field flex-1">
|
||||
<option v-for="timezone in commonTimezones" :key="timezone.value" :value="timezone.value">
|
||||
{{ timezone.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="bg-block rounded p-3 text-center">
|
||||
<div class="text-sm text-secondary">时差</div>
|
||||
<div class="text-lg font-medium text-primary">{{ getTimeDifference() }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 结果区域 -->
|
||||
<div class="lg:col-span-2 space-y-4">
|
||||
<!-- 世界时钟 -->
|
||||
<div class="card p-4">
|
||||
<h3 class="text-lg font-semibold text-primary mb-3">世界时钟</h3>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div
|
||||
v-for="timezone in displayTimezones"
|
||||
:key="timezone.value"
|
||||
class="bg-block rounded-lg p-4"
|
||||
>
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div>
|
||||
<div class="font-medium text-primary">{{ timezone.name }}</div>
|
||||
<div class="text-xs text-tertiary">{{ timezone.value }}</div>
|
||||
</div>
|
||||
<button
|
||||
@click="removeTimezone(timezone.value)"
|
||||
class="text-error hover:bg-error hover:bg-opacity-10 p-1 rounded"
|
||||
>
|
||||
<FontAwesomeIcon :icon="['fas', 'times']" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="text-center">
|
||||
<div class="text-2xl font-mono font-bold text-primary mb-1">
|
||||
{{ getTimezoneTime(timezone.value, 'HH:mm:ss') }}
|
||||
</div>
|
||||
<div class="text-sm text-secondary">
|
||||
{{ getTimezoneTime(timezone.value, 'yyyy-MM-dd EEEE') }}
|
||||
</div>
|
||||
<div class="text-xs text-tertiary mt-1">
|
||||
UTC{{ getTimezoneOffset(timezone.value) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 转换结果 -->
|
||||
<div v-if="conversionResults.length > 0" class="card p-4">
|
||||
<h3 class="text-lg font-semibold text-primary mb-3">转换结果</h3>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div
|
||||
v-for="result in conversionResults"
|
||||
:key="result.timezone"
|
||||
class="flex items-center justify-between p-3 bg-block rounded-lg"
|
||||
>
|
||||
<div class="flex-1">
|
||||
<div class="font-medium text-primary">{{ result.name }}</div>
|
||||
<div class="text-sm text-secondary">{{ result.timezone }}</div>
|
||||
</div>
|
||||
|
||||
<div class="text-right">
|
||||
<div class="text-lg font-mono text-primary">{{ result.time }}</div>
|
||||
<div class="text-xs text-secondary">{{ result.date }}</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
@click="copySpecificTime(result)"
|
||||
class="ml-3 p-2 text-secondary hover:text-primary transition-colors"
|
||||
:title="'复制 ' + result.name + ' 时间'"
|
||||
>
|
||||
<FontAwesomeIcon :icon="['fas', 'copy']" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 时区信息 -->
|
||||
<div class="card p-4">
|
||||
<h3 class="text-lg font-semibold text-primary mb-3">时区信息</h3>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<!-- UTC时间 -->
|
||||
<div class="bg-block rounded-lg p-4">
|
||||
<div class="text-sm text-secondary mb-1">协调世界时 (UTC)</div>
|
||||
<div class="text-xl font-mono text-primary">{{ utcTime }}</div>
|
||||
<div class="text-xs text-tertiary mt-1">Coordinated Universal Time</div>
|
||||
</div>
|
||||
|
||||
<!-- 本地时间 -->
|
||||
<div class="bg-block rounded-lg p-4">
|
||||
<div class="text-sm text-secondary mb-1">本地时间</div>
|
||||
<div class="text-xl font-mono text-primary">{{ localTime }}</div>
|
||||
<div class="text-xs text-tertiary mt-1">{{ localTimezone }}</div>
|
||||
</div>
|
||||
|
||||
<!-- Unix时间戳 -->
|
||||
<div class="bg-block rounded-lg p-4">
|
||||
<div class="text-sm text-secondary mb-1">Unix时间戳</div>
|
||||
<div class="text-lg font-mono text-primary">{{ unixTimestamp }}</div>
|
||||
<div class="text-xs text-tertiary mt-1">秒 / 毫秒</div>
|
||||
</div>
|
||||
|
||||
<!-- ISO 8601 -->
|
||||
<div class="bg-block rounded-lg p-4">
|
||||
<div class="text-sm text-secondary mb-1">ISO 8601</div>
|
||||
<div class="text-sm font-mono text-primary break-all">{{ isoTime }}</div>
|
||||
<div class="text-xs text-tertiary mt-1">国际标准时间格式</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 日程助手 -->
|
||||
<div class="card p-4">
|
||||
<h3 class="text-lg font-semibold text-primary mb-3">会议时间建议</h3>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div class="flex space-x-2">
|
||||
<select v-model="meetingTimezone1" class="select-field flex-1">
|
||||
<option v-for="timezone in commonTimezones" :key="timezone.value" :value="timezone.value">
|
||||
{{ timezone.name }}
|
||||
</option>
|
||||
</select>
|
||||
<select v-model="meetingTimezone2" class="select-field flex-1">
|
||||
<option v-for="timezone in commonTimezones" :key="timezone.value" :value="timezone.value">
|
||||
{{ timezone.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="bg-block rounded p-4">
|
||||
<div class="text-sm text-secondary mb-2">最佳会议时间段 (工作时间 9:00-18:00)</div>
|
||||
<div class="space-y-2">
|
||||
<div
|
||||
v-for="suggestion in getMeetingSuggestions()"
|
||||
:key="suggestion.time"
|
||||
class="flex justify-between items-center text-sm"
|
||||
>
|
||||
<span class="text-primary">{{ suggestion.time }}</span>
|
||||
<span class="text-secondary">{{ suggestion.zones }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 状态消息 -->
|
||||
<div v-if="statusMessage" class="card p-4">
|
||||
<div :class="[
|
||||
'flex items-center space-x-2',
|
||||
statusType === 'success' ? 'text-success' : 'text-error'
|
||||
]">
|
||||
<FontAwesomeIcon
|
||||
:icon="statusType === 'success' ? ['fas', 'check'] : ['fas', 'times']"
|
||||
/>
|
||||
<span>{{ statusMessage }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { useLanguage } from '@/composables/useLanguage'
|
||||
|
||||
const { t } = useLanguage()
|
||||
|
||||
// 响应式状态
|
||||
const inputDateTime = ref('')
|
||||
const sourceTimezone = ref('Asia/Shanghai')
|
||||
const selectedTime = ref('')
|
||||
const copied = ref(false)
|
||||
const statusMessage = ref('')
|
||||
const statusType = ref<'success' | 'error'>('success')
|
||||
const currentTime = ref(new Date())
|
||||
|
||||
// 时区比较
|
||||
const timezone1 = ref('Asia/Shanghai')
|
||||
const timezone2 = ref('America/New_York')
|
||||
|
||||
// 会议时间建议
|
||||
const meetingTimezone1 = ref('Asia/Shanghai')
|
||||
const meetingTimezone2 = ref('America/New_York')
|
||||
|
||||
// 显示的时区列表
|
||||
const displayTimezones = ref([
|
||||
{ name: '北京', value: 'Asia/Shanghai' },
|
||||
{ name: '纽约', value: 'America/New_York' },
|
||||
{ name: '伦敦', value: 'Europe/London' },
|
||||
{ name: '东京', value: 'Asia/Tokyo' }
|
||||
])
|
||||
|
||||
// 转换结果
|
||||
const conversionResults = ref<Array<{
|
||||
name: string
|
||||
timezone: string
|
||||
time: string
|
||||
date: string
|
||||
fullTime: string
|
||||
}>>([])
|
||||
|
||||
// 常用时区
|
||||
const commonTimezones = [
|
||||
{ name: '北京 (CST)', value: 'Asia/Shanghai', label: 'Asia/Shanghai (UTC+8)' },
|
||||
{ name: '东京 (JST)', value: 'Asia/Tokyo', label: 'Asia/Tokyo (UTC+9)' },
|
||||
{ name: '首尔 (KST)', value: 'Asia/Seoul', label: 'Asia/Seoul (UTC+9)' },
|
||||
{ name: '新加坡 (SGT)', value: 'Asia/Singapore', label: 'Asia/Singapore (UTC+8)' },
|
||||
{ name: '香港 (HKT)', value: 'Asia/Hong_Kong', label: 'Asia/Hong_Kong (UTC+8)' },
|
||||
{ name: '悉尼 (AEDT)', value: 'Australia/Sydney', label: 'Australia/Sydney (UTC+11)' },
|
||||
{ name: '伦敦 (GMT)', value: 'Europe/London', label: 'Europe/London (UTC+0)' },
|
||||
{ name: '巴黎 (CET)', value: 'Europe/Paris', label: 'Europe/Paris (UTC+1)' },
|
||||
{ name: '莫斯科 (MSK)', value: 'Europe/Moscow', label: 'Europe/Moscow (UTC+3)' },
|
||||
{ name: '纽约 (EST)', value: 'America/New_York', label: 'America/New_York (UTC-5)' },
|
||||
{ name: '洛杉矶 (PST)', value: 'America/Los_Angeles', label: 'America/Los_Angeles (UTC-8)' },
|
||||
{ name: '芝加哥 (CST)', value: 'America/Chicago', label: 'America/Chicago (UTC-6)' },
|
||||
{ name: '丹佛 (MST)', value: 'America/Denver', label: 'America/Denver (UTC-7)' },
|
||||
{ name: 'UTC', value: 'UTC', label: 'UTC (UTC+0)' }
|
||||
]
|
||||
|
||||
// 快速时间选择
|
||||
const quickTimes = [
|
||||
{ label: '现在', offset: 0 },
|
||||
{ label: '1小时后', offset: 1 },
|
||||
{ label: '明天此时', offset: 24 },
|
||||
{ label: '下周此时', offset: 24 * 7 }
|
||||
]
|
||||
|
||||
// 计算属性
|
||||
const utcTime = computed(() => {
|
||||
return formatTime(currentTime.value, 'UTC', 'yyyy-MM-dd HH:mm:ss')
|
||||
})
|
||||
|
||||
const localTime = computed(() => {
|
||||
return formatTime(currentTime.value, Intl.DateTimeFormat().resolvedOptions().timeZone, 'yyyy-MM-dd HH:mm:ss')
|
||||
})
|
||||
|
||||
const localTimezone = computed(() => {
|
||||
return Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||
})
|
||||
|
||||
const unixTimestamp = computed(() => {
|
||||
const seconds = Math.floor(currentTime.value.getTime() / 1000)
|
||||
const milliseconds = currentTime.value.getTime()
|
||||
return `${seconds} / ${milliseconds}`
|
||||
})
|
||||
|
||||
const isoTime = computed(() => {
|
||||
return currentTime.value.toISOString()
|
||||
})
|
||||
|
||||
// 定时器
|
||||
let timeInterval: number | undefined
|
||||
|
||||
// 格式化时间
|
||||
const formatTime = (date: Date, timezone: string, format: string): string => {
|
||||
try {
|
||||
const options: Intl.DateTimeFormatOptions = {
|
||||
timeZone: timezone
|
||||
}
|
||||
|
||||
if (format.includes('yyyy')) {
|
||||
options.year = 'numeric'
|
||||
}
|
||||
if (format.includes('MM')) {
|
||||
options.month = '2-digit'
|
||||
}
|
||||
if (format.includes('dd')) {
|
||||
options.day = '2-digit'
|
||||
}
|
||||
if (format.includes('HH')) {
|
||||
options.hour = '2-digit'
|
||||
options.hour12 = false
|
||||
}
|
||||
if (format.includes('mm')) {
|
||||
options.minute = '2-digit'
|
||||
}
|
||||
if (format.includes('ss')) {
|
||||
options.second = '2-digit'
|
||||
}
|
||||
if (format.includes('EEEE')) {
|
||||
options.weekday = 'long'
|
||||
}
|
||||
|
||||
const formatter = new Intl.DateTimeFormat('zh-CN', options)
|
||||
|
||||
if (format === 'HH:mm:ss') {
|
||||
return date.toLocaleTimeString('zh-CN', {
|
||||
timeZone: timezone,
|
||||
hour12: false,
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit'
|
||||
})
|
||||
} else if (format === 'yyyy-MM-dd EEEE') {
|
||||
return date.toLocaleDateString('zh-CN', {
|
||||
timeZone: timezone,
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
weekday: 'long'
|
||||
})
|
||||
} else {
|
||||
return formatter.format(date)
|
||||
}
|
||||
} catch (error) {
|
||||
return date.toISOString()
|
||||
}
|
||||
}
|
||||
|
||||
// 获取时区时间
|
||||
const getTimezoneTime = (timezone: string, format: string = 'yyyy-MM-dd HH:mm:ss'): string => {
|
||||
return formatTime(currentTime.value, timezone, format)
|
||||
}
|
||||
|
||||
// 获取时区偏移
|
||||
const getTimezoneOffset = (timezone: string): string => {
|
||||
try {
|
||||
const date = new Date()
|
||||
const utc = date.getTime() + (date.getTimezoneOffset() * 60000)
|
||||
const targetTime = new Date(utc + getTimezoneOffsetMinutes(timezone) * 60000)
|
||||
const offset = getTimezoneOffsetMinutes(timezone) / 60
|
||||
return offset >= 0 ? `+${offset}` : `${offset}`
|
||||
} catch {
|
||||
return '+0'
|
||||
}
|
||||
}
|
||||
|
||||
// 获取时区偏移分钟数
|
||||
const getTimezoneOffsetMinutes = (timezone: string): number => {
|
||||
try {
|
||||
const date = new Date()
|
||||
const utcDate = new Date(date.toLocaleString('en-US', { timeZone: 'UTC' }))
|
||||
const targetDate = new Date(date.toLocaleString('en-US', { timeZone: timezone }))
|
||||
return (targetDate.getTime() - utcDate.getTime()) / (1000 * 60)
|
||||
} catch {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// 获取时差
|
||||
const getTimeDifference = (): string => {
|
||||
const offset1 = getTimezoneOffsetMinutes(timezone1.value)
|
||||
const offset2 = getTimezoneOffsetMinutes(timezone2.value)
|
||||
const diffMinutes = Math.abs(offset1 - offset2)
|
||||
const hours = Math.floor(diffMinutes / 60)
|
||||
const minutes = diffMinutes % 60
|
||||
|
||||
if (hours === 0) {
|
||||
return `${minutes} 分钟`
|
||||
} else if (minutes === 0) {
|
||||
return `${hours} 小时`
|
||||
} else {
|
||||
return `${hours} 小时 ${minutes} 分钟`
|
||||
}
|
||||
}
|
||||
|
||||
// 获取会议建议
|
||||
const getMeetingSuggestions = (): Array<{ time: string; zones: string }> => {
|
||||
const suggestions = []
|
||||
|
||||
for (let hour = 9; hour <= 18; hour++) {
|
||||
const time1 = `${hour.toString().padStart(2, '0')}:00`
|
||||
const date = new Date()
|
||||
date.setHours(hour, 0, 0, 0)
|
||||
|
||||
const time2 = formatTime(date, meetingTimezone2.value, 'HH:mm')
|
||||
const hour2 = parseInt(time2.split(':')[0])
|
||||
|
||||
if (hour2 >= 9 && hour2 <= 18) {
|
||||
suggestions.push({
|
||||
time: `${time1} - ${time2}`,
|
||||
zones: `${getTimezoneName(meetingTimezone1.value)} - ${getTimezoneName(meetingTimezone2.value)}`
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return suggestions.slice(0, 3)
|
||||
}
|
||||
|
||||
// 获取时区名称
|
||||
const getTimezoneName = (timezone: string): string => {
|
||||
const found = commonTimezones.find(tz => tz.value === timezone)
|
||||
return found ? found.name : timezone
|
||||
}
|
||||
|
||||
// 设置快速时间
|
||||
const setQuickTime = (quickTime: any) => {
|
||||
const date = new Date()
|
||||
date.setHours(date.getHours() + quickTime.offset)
|
||||
|
||||
const year = date.getFullYear()
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, '0')
|
||||
const day = date.getDate().toString().padStart(2, '0')
|
||||
const hours = date.getHours().toString().padStart(2, '0')
|
||||
const minutes = date.getMinutes().toString().padStart(2, '0')
|
||||
|
||||
inputDateTime.value = `${year}-${month}-${day}T${hours}:${minutes}`
|
||||
convertTimezones()
|
||||
}
|
||||
|
||||
// 转换时区
|
||||
const convertTimezones = () => {
|
||||
if (!inputDateTime.value) return
|
||||
|
||||
const inputDate = new Date(inputDateTime.value)
|
||||
if (isNaN(inputDate.getTime())) return
|
||||
|
||||
conversionResults.value = displayTimezones.value.map(timezone => {
|
||||
const time = formatTime(inputDate, timezone.value, 'HH:mm:ss')
|
||||
const date = formatTime(inputDate, timezone.value, 'yyyy-MM-dd EEEE')
|
||||
const fullTime = formatTime(inputDate, timezone.value, 'yyyy-MM-dd HH:mm:ss')
|
||||
|
||||
return {
|
||||
name: timezone.name,
|
||||
timezone: timezone.value,
|
||||
time,
|
||||
date,
|
||||
fullTime
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 添加自定义时区
|
||||
const addCustomTimezone = () => {
|
||||
const timezone = prompt('请输入时区标识符 (如: Asia/Shanghai):')
|
||||
if (!timezone) return
|
||||
|
||||
try {
|
||||
// 验证时区是否有效
|
||||
formatTime(new Date(), timezone, 'HH:mm:ss')
|
||||
|
||||
const name = prompt('请输入时区显示名称:', timezone) || timezone
|
||||
|
||||
displayTimezones.value.push({
|
||||
name,
|
||||
value: timezone
|
||||
})
|
||||
|
||||
convertTimezones()
|
||||
showStatus('时区添加成功', 'success')
|
||||
} catch (error) {
|
||||
showStatus('无效的时区标识符', 'error')
|
||||
}
|
||||
}
|
||||
|
||||
// 移除时区
|
||||
const removeTimezone = (timezone: string) => {
|
||||
displayTimezones.value = displayTimezones.value.filter(tz => tz.value !== timezone)
|
||||
convertTimezones()
|
||||
}
|
||||
|
||||
// 更新当前时间
|
||||
const updateCurrentTime = () => {
|
||||
currentTime.value = new Date()
|
||||
}
|
||||
|
||||
// 重置到现在
|
||||
const resetToNow = () => {
|
||||
const now = new Date()
|
||||
const year = now.getFullYear()
|
||||
const month = (now.getMonth() + 1).toString().padStart(2, '0')
|
||||
const day = now.getDate().toString().padStart(2, '0')
|
||||
const hours = now.getHours().toString().padStart(2, '0')
|
||||
const minutes = now.getMinutes().toString().padStart(2, '0')
|
||||
|
||||
inputDateTime.value = `${year}-${month}-${day}T${hours}:${minutes}`
|
||||
convertTimezones()
|
||||
}
|
||||
|
||||
// 复制结果
|
||||
const copyResult = async () => {
|
||||
if (!selectedTime.value) return
|
||||
|
||||
try {
|
||||
await navigator.clipboard.writeText(selectedTime.value)
|
||||
copied.value = true
|
||||
setTimeout(() => {
|
||||
copied.value = false
|
||||
}, 2000)
|
||||
} catch (error) {
|
||||
showStatus('复制失败', 'error')
|
||||
}
|
||||
}
|
||||
|
||||
// 复制特定时间
|
||||
const copySpecificTime = async (result: any) => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(result.fullTime)
|
||||
showStatus(`已复制 ${result.name} 时间`, 'success')
|
||||
} catch (error) {
|
||||
showStatus('复制失败', 'error')
|
||||
}
|
||||
}
|
||||
|
||||
// 显示状态消息
|
||||
const showStatus = (message: string, type: 'success' | 'error') => {
|
||||
statusMessage.value = message
|
||||
statusType.value = type
|
||||
setTimeout(() => {
|
||||
statusMessage.value = ''
|
||||
}, 3000)
|
||||
}
|
||||
|
||||
// 组件挂载
|
||||
onMounted(() => {
|
||||
resetToNow()
|
||||
updateCurrentTime()
|
||||
|
||||
// 每秒更新时间
|
||||
timeInterval = setInterval(() => {
|
||||
updateCurrentTime()
|
||||
}, 1000)
|
||||
})
|
||||
|
||||
// 组件卸载
|
||||
onUnmounted(() => {
|
||||
if (timeInterval) {
|
||||
clearInterval(timeInterval)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user