2026-05-15 16:36:50 +08:00
|
|
|
<template>
|
|
|
|
|
<div class="time-period-search">
|
|
|
|
|
<el-select class="time-period-search__unit" :model-value="unit" @update:model-value="handleUnitChange">
|
2026-05-27 08:06:12 +08:00
|
|
|
<el-option
|
|
|
|
|
v-for="item in visibleTimePeriodUnitOptions"
|
|
|
|
|
:key="item.value"
|
|
|
|
|
:label="item.label"
|
|
|
|
|
:value="item.value"
|
|
|
|
|
/>
|
2026-05-15 16:36:50 +08:00
|
|
|
</el-select>
|
|
|
|
|
|
|
|
|
|
<el-button
|
2026-05-27 08:06:12 +08:00
|
|
|
v-if="!isCustomUnit"
|
2026-05-15 16:36:50 +08:00
|
|
|
class="time-period-search__button"
|
|
|
|
|
:icon="ArrowLeft"
|
|
|
|
|
:title="`上一个${unitLabel}`"
|
|
|
|
|
@click="shiftPeriod(-1)"
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<el-date-picker
|
2026-05-27 08:06:12 +08:00
|
|
|
v-if="!isCustomUnit"
|
2026-05-15 16:36:50 +08:00
|
|
|
class="time-period-search__picker"
|
|
|
|
|
:model-value="baseDate"
|
|
|
|
|
:type="getTimePeriodPickerType(props.unit)"
|
|
|
|
|
:format="getTimePeriodPickerFormat(props.unit)"
|
|
|
|
|
:clearable="false"
|
|
|
|
|
:editable="false"
|
|
|
|
|
:placeholder="`选择${unitLabel}`"
|
|
|
|
|
@update:model-value="handleDateChange"
|
|
|
|
|
/>
|
|
|
|
|
|
2026-05-27 08:06:12 +08:00
|
|
|
<el-date-picker
|
|
|
|
|
v-else
|
|
|
|
|
class="time-period-search__range-picker"
|
|
|
|
|
:model-value="rangeValue"
|
|
|
|
|
type="datetimerange"
|
|
|
|
|
format="YYYY-MM-DD HH:mm:ss"
|
|
|
|
|
value-format="YYYY-MM-DD HH:mm:ss.SSS"
|
|
|
|
|
range-separator="至"
|
|
|
|
|
start-placeholder="开始时间"
|
|
|
|
|
end-placeholder="结束时间"
|
|
|
|
|
:clearable="false"
|
|
|
|
|
:editable="false"
|
|
|
|
|
@update:model-value="handleRangeChange"
|
|
|
|
|
/>
|
|
|
|
|
|
2026-05-15 16:36:50 +08:00
|
|
|
<el-button
|
2026-05-27 08:06:12 +08:00
|
|
|
v-if="!isCustomUnit"
|
2026-05-15 16:36:50 +08:00
|
|
|
class="time-period-search__button"
|
|
|
|
|
:icon="ArrowRight"
|
|
|
|
|
:title="`下一个${unitLabel}`"
|
|
|
|
|
@click="shiftPeriod(1)"
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<el-button
|
2026-05-27 08:06:12 +08:00
|
|
|
v-if="!isCustomUnit"
|
2026-05-15 16:36:50 +08:00
|
|
|
class="time-period-search__button"
|
|
|
|
|
:icon="Clock"
|
|
|
|
|
:title="`当前${unitLabel}`"
|
|
|
|
|
@click="setCurrentPeriod"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { computed } from 'vue'
|
|
|
|
|
import { ArrowLeft, ArrowRight, Clock } from '@element-plus/icons-vue'
|
|
|
|
|
import {
|
|
|
|
|
getTimePeriodPickerFormat,
|
|
|
|
|
getTimePeriodPickerType,
|
|
|
|
|
resolveTimePeriodUnitLabel,
|
|
|
|
|
shiftTimePeriod,
|
|
|
|
|
timePeriodUnitOptions,
|
|
|
|
|
type TimePeriodUnit
|
|
|
|
|
} from './timePeriod'
|
|
|
|
|
|
|
|
|
|
defineOptions({
|
|
|
|
|
name: 'TimePeriodSearch'
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const props = defineProps<{
|
|
|
|
|
unit: TimePeriodUnit
|
|
|
|
|
modelValue: Date | string | number
|
2026-05-27 08:06:12 +08:00
|
|
|
rangeValue?: string[]
|
|
|
|
|
visibleUnits?: TimePeriodUnit[]
|
2026-05-15 16:36:50 +08:00
|
|
|
}>()
|
|
|
|
|
|
|
|
|
|
const emit = defineEmits<{
|
|
|
|
|
'update:unit': [value: TimePeriodUnit]
|
|
|
|
|
'update:modelValue': [value: Date]
|
2026-05-27 08:06:12 +08:00
|
|
|
'update:rangeValue': [value: string[]]
|
2026-05-15 16:36:50 +08:00
|
|
|
}>()
|
|
|
|
|
|
|
|
|
|
const baseDate = computed(() => new Date(props.modelValue))
|
|
|
|
|
const unitLabel = computed(() => resolveTimePeriodUnitLabel(props.unit))
|
2026-05-27 08:06:12 +08:00
|
|
|
const isCustomUnit = computed(() => props.unit === 'custom')
|
|
|
|
|
const visibleTimePeriodUnitOptions = computed(() => {
|
|
|
|
|
if (!props.visibleUnits?.length) return timePeriodUnitOptions
|
|
|
|
|
|
|
|
|
|
return timePeriodUnitOptions.filter(item => props.visibleUnits?.includes(item.value))
|
|
|
|
|
})
|
|
|
|
|
const rangeValue = computed(() => props.rangeValue || [])
|
2026-05-15 16:36:50 +08:00
|
|
|
|
|
|
|
|
const handleUnitChange = (value: TimePeriodUnit) => {
|
|
|
|
|
emit('update:unit', value)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleDateChange = (value: Date | string | number | null) => {
|
|
|
|
|
if (!value) return
|
|
|
|
|
emit('update:modelValue', new Date(value))
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-27 08:06:12 +08:00
|
|
|
const handleRangeChange = (value: string[] | null) => {
|
|
|
|
|
if (!value?.length) return
|
|
|
|
|
emit('update:rangeValue', value)
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-15 16:36:50 +08:00
|
|
|
const shiftPeriod = (offset: number) => {
|
|
|
|
|
emit('update:modelValue', shiftTimePeriod(props.unit, baseDate.value, offset))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const setCurrentPeriod = () => {
|
|
|
|
|
emit('update:modelValue', new Date())
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
|
.time-period-search {
|
|
|
|
|
display: flex;
|
|
|
|
|
width: 100%;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 4px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.time-period-search__unit {
|
|
|
|
|
width: 56px;
|
|
|
|
|
flex: 0 0 56px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.time-period-search__picker {
|
|
|
|
|
width: 112px;
|
|
|
|
|
flex: 0 0 112px;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-27 08:06:12 +08:00
|
|
|
.time-period-search__range-picker {
|
|
|
|
|
width: 360px;
|
|
|
|
|
flex: 1 1 360px;
|
|
|
|
|
min-width: 280px;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-15 16:36:50 +08:00
|
|
|
.time-period-search__button {
|
|
|
|
|
width: 28px;
|
|
|
|
|
flex: 0 0 28px;
|
|
|
|
|
padding: 8px 6px;
|
|
|
|
|
}
|
|
|
|
|
</style>
|