调整,音乐模块
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onUnmounted, ref } from 'vue'
|
||||
import { Clock } from '@lucide/vue'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Separator } from '@/components/ui/separator'
|
||||
import Segmented from '../components/Segmented.vue'
|
||||
import ResultArea from '../components/ResultArea.vue'
|
||||
|
||||
type Unit = 'auto' | 's' | 'ms'
|
||||
|
||||
const unit = ref<Unit>('auto')
|
||||
const numberInput = ref('')
|
||||
const dateInput = ref('')
|
||||
|
||||
const toNumber = (v: string): number | null => {
|
||||
const n = Number(v.trim())
|
||||
return Number.isFinite(n) ? n : null
|
||||
}
|
||||
|
||||
/** 自动识别:13 位(>1e11)视为毫秒,10 位(>1e8)视为秒,其他按数值范围推断 */
|
||||
function resolveUnit(n: number): 's' | 'ms' {
|
||||
if (unit.value !== 'auto') return unit.value
|
||||
if (Math.abs(n) >= 1e11) return 'ms'
|
||||
return 's'
|
||||
}
|
||||
|
||||
const unixToDate = (n: number, u: 's' | 'ms'): Date =>
|
||||
new Date(u === 's' ? n * 1000 : n)
|
||||
|
||||
const formatLocal = (d: Date): string => {
|
||||
const pad = (x: number) => String(x).padStart(2, '0')
|
||||
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`
|
||||
}
|
||||
|
||||
const formatUtc = (d: Date): string => {
|
||||
const pad = (x: number) => String(x).padStart(2, '0')
|
||||
return `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())} ${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}:${pad(d.getUTCSeconds())} UTC`
|
||||
}
|
||||
|
||||
const fromNumber = computed<{ local: string; utc: string; iso: string; ts: string; unitUsed: 's' | 'ms' } | null>(() => {
|
||||
const n = toNumber(numberInput.value)
|
||||
if (n === null) return null
|
||||
const u = resolveUnit(n)
|
||||
const d = unixToDate(n, u)
|
||||
if (Number.isNaN(d.getTime())) return null
|
||||
return {
|
||||
local: formatLocal(d),
|
||||
utc: formatUtc(d),
|
||||
iso: d.toISOString(),
|
||||
ts: String(n),
|
||||
unitUsed: u
|
||||
}
|
||||
})
|
||||
|
||||
const fromDate = computed<string>(() => {
|
||||
if (!dateInput.value) return ''
|
||||
const d = new Date(dateInput.value)
|
||||
if (Number.isNaN(d.getTime())) return ''
|
||||
// 日期输入统一同时给出秒与毫秒
|
||||
return `${Math.floor(d.getTime() / 1000)}(秒)\n${d.getTime()}(毫秒)`
|
||||
})
|
||||
|
||||
// ===== 当前时间戳 =====
|
||||
const nowTick = ref(0)
|
||||
const timer = window.setInterval(() => (nowTick.value++), 1000)
|
||||
onUnmounted(() => window.clearInterval(timer))
|
||||
|
||||
const now = computed(() => {
|
||||
void nowTick.value
|
||||
const d = new Date()
|
||||
return {
|
||||
s: String(Math.floor(d.getTime() / 1000)),
|
||||
ms: String(d.getTime()),
|
||||
local: formatLocal(d)
|
||||
}
|
||||
})
|
||||
|
||||
function copy(text: string) {
|
||||
void navigator.clipboard.writeText(text)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col gap-4">
|
||||
<Segmented
|
||||
v-model="unit"
|
||||
label="单位"
|
||||
:options="[
|
||||
{ value: 'auto', label: '自动' },
|
||||
{ value: 's', label: '秒' },
|
||||
{ value: 'ms', label: '毫秒' }
|
||||
]"
|
||||
/>
|
||||
|
||||
<!-- 时间戳 → 时间 -->
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<Label class="text-xs">Unix 时间戳 → 日期时间</Label>
|
||||
<Input v-model="numberInput" placeholder="例如 1757419200 或 1757419200000" class="font-mono text-sm" />
|
||||
</div>
|
||||
<template v-if="fromNumber">
|
||||
<ResultArea :text="fromNumber.local" label="本地时间" placeholder="本地时间" />
|
||||
<ResultArea :text="fromNumber.utc" label="UTC 时间" placeholder="UTC 时间" />
|
||||
<ResultArea :text="fromNumber.iso" label="ISO 8601" placeholder="ISO 8601" />
|
||||
<p class="text-xs text-muted-foreground">已识别为{{ fromNumber.unitUsed === 's' ? '秒级' : '毫秒级' }}时间戳</p>
|
||||
</template>
|
||||
<p v-else-if="numberInput" class="text-xs text-destructive">请输入有效的数字时间戳</p>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<!-- 时间 → 时间戳 -->
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<Label class="text-xs">日期时间 → Unix 时间戳</Label>
|
||||
<Input v-model="dateInput" type="datetime-local" class="font-mono text-sm" />
|
||||
<ResultArea v-if="fromDate" :text="fromDate" label="结果" placeholder="结果" />
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<!-- 当前时间戳 -->
|
||||
<div class="flex flex-col gap-2">
|
||||
<Label class="text-xs">当前时间({{ now.local }})</Label>
|
||||
<div class="flex items-center gap-2 flex-wrap">
|
||||
<Button size="sm" variant="outline" class="h-8 font-mono text-xs gap-1.5" @click="copy(now.s)">
|
||||
<Clock class="size-3.5" />
|
||||
{{ now.s }}(秒,点击复制)
|
||||
</Button>
|
||||
<Button size="sm" variant="outline" class="h-8 font-mono text-xs gap-1.5" @click="copy(now.ms)">
|
||||
<Clock class="size-3.5" />
|
||||
{{ now.ms }}(毫秒,点击复制)
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user