工具完成
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing

This commit is contained in:
2025-06-28 22:38:49 +08:00
parent 2c668fedd0
commit 8400dbfab9
60 changed files with 23197 additions and 144 deletions

View File

@ -0,0 +1,550 @@
<template>
<div class="space-y-6">
<!-- 模式切换 -->
<div class="flex flex-wrap gap-4 justify-between items-center">
<div class="flex items-center bg-card rounded-md p-1 border">
<button
:class="[
'px-4 py-2 text-sm font-medium transition-all rounded-l-md',
mode === 'diff' ? 'bg-primary text-white shadow-sm' : 'text-secondary hover:text-primary'
]"
@click="mode = 'diff'"
>
日期差值计算
</button>
<button
:class="[
'px-4 py-2 text-sm font-medium transition-all rounded-r-md',
mode === 'add' ? 'bg-primary text-white shadow-sm' : 'text-secondary hover:text-primary'
]"
@click="mode = 'add'"
>
日期加减计算
</button>
</div>
</div>
<!-- 日期差值计算 -->
<div v-if="mode === 'diff'" class="card p-6">
<h2 class="text-lg font-medium text-primary mb-4">日期差值计算器</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- 输入部分 -->
<div class="space-y-6">
<div>
<label class="block text-sm font-medium text-secondary mb-2">开始日期</label>
<div class="flex items-center gap-2">
<input
v-model="startDate"
type="datetime-local"
class="input-field flex-1"
@input="calculateDateDiff"
/>
<button
class="btn-secondary text-sm px-3 py-2"
@click="setStartDateToCurrent"
>
当前时间
</button>
</div>
</div>
<div class="flex justify-center">
<button
class="btn-secondary text-sm px-4 py-2"
@click="swapDates"
>
<FontAwesomeIcon :icon="['fas', 'calendar-alt']" class="mr-2" />
交换日期
</button>
</div>
<div>
<label class="block text-sm font-medium text-secondary mb-2">结束日期</label>
<div class="flex items-center gap-2">
<input
v-model="endDate"
type="datetime-local"
class="input-field flex-1"
@input="calculateDateDiff"
/>
<button
class="btn-secondary text-sm px-3 py-2"
@click="setEndDateToCurrent"
>
当前时间
</button>
</div>
</div>
</div>
<!-- 结果部分 -->
<div class="bg-block rounded-md p-4 border">
<h3 class="text-primary font-medium mb-3">计算结果</h3>
<div class="space-y-2">
<div
v-for="(result, key) in diffResults"
:key="key"
class="flex justify-between items-center py-2 border-b border-primary/10 last:border-0"
>
<span class="text-sm text-secondary">{{ getTimeUnitLabel(key) }}</span>
<div class="flex items-center gap-2">
<span class="text-sm text-primary font-semibold">
{{ result }} {{ getTimeUnitName(key) }}
</span>
<button
@click="() => copyToClipboard(result.toString(), key)"
class="text-tertiary hover:text-primary transition-colors"
>
<FontAwesomeIcon :icon="copied === key ? ['fas', 'check'] : ['fas', 'copy']" />
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 日期加减计算 -->
<div v-if="mode === 'add'" class="card p-6">
<h2 class="text-lg font-medium text-primary mb-4">日期加减计算器</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- 输入部分 -->
<div class="space-y-6">
<div>
<label class="block text-sm font-medium text-secondary mb-2">基准日期</label>
<div class="flex items-center gap-2">
<input
v-model="baseDate"
type="datetime-local"
class="input-field flex-1"
@input="calculateDateAddition"
/>
<button
class="btn-secondary text-sm px-3 py-2"
@click="setBaseDateToCurrent"
>
当前时间
</button>
</div>
</div>
<div>
<label class="block text-sm font-medium text-secondary mb-2">操作类型</label>
<div class="flex gap-2">
<button
:class="[
'flex-1 px-4 py-2 text-sm font-medium rounded transition-all',
operation === 'add' ? 'bg-primary text-white' : 'bg-block text-secondary border'
]"
@click="() => setOperation('add')"
>
<FontAwesomeIcon :icon="['fas', 'plus']" class="mr-2" />
加上
</button>
<button
:class="[
'flex-1 px-4 py-2 text-sm font-medium rounded transition-all',
operation === 'subtract' ? 'bg-primary text-white' : 'bg-block text-secondary border'
]"
@click="() => setOperation('subtract')"
>
<FontAwesomeIcon :icon="['fas', 'minus']" class="mr-2" />
减去
</button>
</div>
</div>
<div>
<label class="block text-sm font-medium text-secondary mb-2">时间数量</label>
<input
v-model.number="timeAmount"
type="number"
min="0"
step="1"
class="input-field w-full"
@input="calculateDateAddition"
/>
</div>
<div>
<label class="block text-sm font-medium text-secondary mb-2">时间单位</label>
<div class="grid grid-cols-2 sm:grid-cols-3 gap-2">
<button
v-for="unit in timeUnits"
:key="unit.value"
:class="[
'px-3 py-2 text-xs rounded transition-all',
timeUnit === unit.value ? 'bg-primary text-white' : 'btn-secondary'
]"
@click="() => setTimeUnit(unit.value)"
>
{{ unit.label }}
</button>
</div>
</div>
</div>
<!-- 结果部分 -->
<div class="bg-block rounded-md p-4 border">
<h3 class="text-primary font-medium mb-3">计算结果</h3>
<div v-if="addResult" class="space-y-3">
<div class="text-center">
<div class="text-lg text-primary font-bold">{{ addResult }}</div>
<button
@click="() => copyToClipboard(addResult, 'result')"
class="mt-2 btn-secondary text-sm"
>
<FontAwesomeIcon :icon="copied === 'result' ? ['fas', 'check'] : ['fas', 'copy']" class="mr-1" />
{{ copied === 'result' ? '已复制' : '复制结果' }}
</button>
</div>
<!-- 详细信息 -->
<div class="text-xs text-tertiary text-center">
{{ formatCalculationDescription() }}
</div>
</div>
<div v-else class="text-tertiary text-center py-4">
请填写有效的基准日期和时间数量
</div>
</div>
</div>
</div>
<!-- 快速操作面板 -->
<div class="card p-4">
<h3 class="text-md font-medium text-primary mb-3">快速操作</h3>
<div class="grid grid-cols-2 md:grid-cols-4 gap-2">
<button
v-for="quick in quickOperations"
:key="quick.label"
@click="() => applyQuickOperation(quick)"
class="btn-secondary text-sm"
>
{{ quick.label }}
</button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
// 时间单位枚举
enum TimeUnit {
YEARS = 'years',
MONTHS = 'months',
WEEKS = 'weeks',
DAYS = 'days',
HOURS = 'hours',
MINUTES = 'minutes'
}
// 响应式状态
const mode = ref<'diff' | 'add'>('diff')
// 日期差值计算状态
const startDate = ref('')
const endDate = ref('')
const diffResults = ref<Record<string, number>>({})
// 日期加减计算状态
const baseDate = ref('')
const timeAmount = ref(1)
const timeUnit = ref<TimeUnit>(TimeUnit.DAYS)
const operation = ref<'add' | 'subtract'>('add')
const addResult = ref('')
// 复制状态
const copied = ref<string | null>(null)
// 时间单位选项
const timeUnits = [
{ value: TimeUnit.YEARS, label: '年' },
{ value: TimeUnit.MONTHS, label: '月' },
{ value: TimeUnit.WEEKS, label: '周' },
{ value: TimeUnit.DAYS, label: '天' },
{ value: TimeUnit.HOURS, label: '小时' },
{ value: TimeUnit.MINUTES, label: '分钟' }
]
// 快速操作选项
const quickOperations = [
{ label: '距今一周', action: () => setQuickDiff(-7, 'days') },
{ label: '距今一月', action: () => setQuickDiff(-1, 'months') },
{ label: '一周后', action: () => setQuickAdd(7, 'days') },
{ label: '一月后', action: () => setQuickAdd(1, 'months') }
]
// 格式化日期为显示格式
const formatDateForDisplay = (date: Date): string => {
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}`
}
// 格式化日期为输入框格式
const formatDateForInput = (date: Date): string => {
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
return `${year}-${month}-${day}T${hours}:${minutes}`
}
// 获取时间单位标签
const getTimeUnitLabel = (key: string): string => {
const labels: Record<string, string> = {
years: '相差年数',
months: '相差月数',
weeks: '相差周数',
days: '相差天数',
hours: '相差小时',
minutes: '相差分钟',
seconds: '相差秒数',
milliseconds: '相差毫秒'
}
return labels[key] || key
}
// 获取时间单位名称
const getTimeUnitName = (key: string): string => {
const names: Record<string, string> = {
years: '年',
months: '月',
weeks: '周',
days: '天',
hours: '小时',
minutes: '分钟',
seconds: '秒',
milliseconds: '毫秒'
}
return names[key] || ''
}
// 计算日期差值
const calculateDateDiff = () => {
if (!startDate.value || !endDate.value) {
diffResults.value = {}
return
}
try {
const startDateTime = new Date(startDate.value)
const endDateTime = new Date(endDate.value)
if (isNaN(startDateTime.getTime()) || isNaN(endDateTime.getTime())) {
return
}
// 计算毫秒差值
const diffMs = endDateTime.getTime() - startDateTime.getTime()
// 计算各个单位的差值
const diffSeconds = Math.floor(diffMs / 1000)
const diffMinutes = Math.floor(diffSeconds / 60)
const diffHours = Math.floor(diffMinutes / 60)
const diffDays = Math.floor(diffHours / 24)
const diffWeeks = Math.floor(diffDays / 7)
// 计算月份差
let months = (endDateTime.getFullYear() - startDateTime.getFullYear()) * 12
months += endDateTime.getMonth() - startDateTime.getMonth()
// 计算年份差
const diffYears = Math.floor(months / 12)
// 设置结果
diffResults.value = {
years: diffYears,
months: months,
weeks: diffWeeks,
days: diffDays,
hours: diffHours,
minutes: diffMinutes,
seconds: diffSeconds,
milliseconds: diffMs
}
} catch (error) {
console.error('计算错误:', error)
}
}
// 计算日期加减
const calculateDateAddition = () => {
if (!baseDate.value || isNaN(timeAmount.value)) {
addResult.value = ''
return
}
try {
const baseDateTime = new Date(baseDate.value)
if (isNaN(baseDateTime.getTime())) {
return
}
const resultDate = new Date(baseDateTime)
const sign = operation.value === 'add' ? 1 : -1
switch (timeUnit.value) {
case TimeUnit.YEARS:
resultDate.setFullYear(resultDate.getFullYear() + sign * timeAmount.value)
break
case TimeUnit.MONTHS:
resultDate.setMonth(resultDate.getMonth() + sign * timeAmount.value)
break
case TimeUnit.WEEKS:
resultDate.setDate(resultDate.getDate() + sign * timeAmount.value * 7)
break
case TimeUnit.DAYS:
resultDate.setDate(resultDate.getDate() + sign * timeAmount.value)
break
case TimeUnit.HOURS:
resultDate.setHours(resultDate.getHours() + sign * timeAmount.value)
break
case TimeUnit.MINUTES:
resultDate.setMinutes(resultDate.getMinutes() + sign * timeAmount.value)
break
}
// 格式化结果
addResult.value = formatDateForDisplay(resultDate)
} catch (error) {
console.error('计算错误:', error)
}
}
// 格式化计算描述
const formatCalculationDescription = (): string => {
const unitName = timeUnits.find(unit => unit.value === timeUnit.value)?.label || ''
const op = operation.value === 'add' ? '加上' : '减去'
return `${formatDateForDisplay(new Date(baseDate.value))} ${op} ${timeAmount.value} ${unitName}`
}
// 设置开始日期为当前时间
const setStartDateToCurrent = () => {
const now = formatDateForInput(new Date())
startDate.value = now
calculateDateDiff()
}
// 设置结束日期为当前时间
const setEndDateToCurrent = () => {
const now = formatDateForInput(new Date())
endDate.value = now
calculateDateDiff()
}
// 设置基准日期为当前时间
const setBaseDateToCurrent = () => {
const now = formatDateForInput(new Date())
baseDate.value = now
calculateDateAddition()
}
// 交换开始和结束日期
const swapDates = () => {
const temp = startDate.value
startDate.value = endDate.value
endDate.value = temp
calculateDateDiff()
}
// 设置时间单位
const setTimeUnit = (unit: TimeUnit) => {
timeUnit.value = unit
calculateDateAddition()
}
// 设置操作类型
const setOperation = (op: 'add' | 'subtract') => {
operation.value = op
calculateDateAddition()
}
// 复制到剪贴板
const copyToClipboard = async (text: string, type: string) => {
try {
await navigator.clipboard.writeText(text)
copied.value = type
setTimeout(() => {
copied.value = null
}, 2000)
} catch (error) {
console.error('复制失败:', error)
}
}
// 设置快速日期差值
const setQuickDiff = (amount: number, unit: string) => {
const now = new Date()
const past = new Date(now)
switch (unit) {
case 'days':
past.setDate(past.getDate() + amount)
break
case 'months':
past.setMonth(past.getMonth() + amount)
break
}
startDate.value = formatDateForInput(past)
endDate.value = formatDateForInput(now)
mode.value = 'diff'
calculateDateDiff()
}
// 设置快速日期加减
const setQuickAdd = (amount: number, unit: string) => {
const now = new Date()
baseDate.value = formatDateForInput(now)
timeAmount.value = amount
switch (unit) {
case 'days':
timeUnit.value = TimeUnit.DAYS
break
case 'months':
timeUnit.value = TimeUnit.MONTHS
break
}
operation.value = 'add'
mode.value = 'add'
calculateDateAddition()
}
// 应用快速操作
const applyQuickOperation = (quick: any) => {
quick.action()
}
// 初始化
onMounted(() => {
const now = new Date()
const oneWeekAgo = new Date(now)
oneWeekAgo.setDate(oneWeekAgo.getDate() - 7)
startDate.value = formatDateForInput(oneWeekAgo)
endDate.value = formatDateForInput(now)
baseDate.value = formatDateForInput(now)
// 初始化时计算一次
calculateDateDiff()
calculateDateAddition()
})
</script>