Merge pull request #13305 from dataease/pr@dev-v2_st

feat(查询组件): 时间查询组件,支持类似时间范围查询的配置项:设置时间筛选范围 #12822
This commit is contained in:
Junjun 2024-11-14 12:08:48 +08:00 committed by GitHub
commit 8c7d3e75c6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 590 additions and 2 deletions

View File

@ -3,6 +3,7 @@ import icon_admin_outlined from '@/assets/svg/icon_admin_outlined.svg'
import { ElSelect } from 'element-plus-secondary'
import { computed, ref, toRefs } from 'vue'
import RangeFilterTime from '@/custom-component/v-query/RangeFilterTime.vue'
import FilterTime from '@/custom-component/v-query/FilterTime.vue'
import { useI18n } from '@/hooks/web/useI18n'
import DynamicTime from '@/custom-component/v-query/DynamicTime.vue'
import DynamicTimeRange from '@/custom-component/v-query/DynamicTimeRange.vue'
@ -408,7 +409,7 @@ defineExpose({
</el-radio-group>
</div>
</div>
<div v-if="curComponent.displayType === '7' && showFlag" class="list-item">
<div v-if="['7', '1'].includes(curComponent.displayType) && showFlag" class="list-item">
<div class="label">
<el-checkbox v-model="curComponent.setTimeRange" :label="t('v_query.time_filter_range')" />
</div>
@ -435,9 +436,15 @@ defineExpose({
</el-button>
</template>
<RangeFilterTime
v-if="curComponent.displayType === '7'"
:timeRange="curComponent.timeRange"
:timeGranularityMultiple="curComponent.timeGranularityMultiple"
/>
<FilterTime
v-else
:timeRange="curComponent.timeRange"
:timeGranularity="curComponent.timeGranularity"
/>
</el-popover>
<span
v-if="

View File

@ -0,0 +1,579 @@
<script lang="ts" setup>
import type { DatePickType } from 'element-plus-secondary'
import { toRefs, computed } from 'vue'
import { type TimeRange } from './time-format'
import { useI18n } from '@/hooks/web/useI18n'
import DynamicTime from './DynamicTimeFiltering.vue'
import DynamicTimeRange from './DynamicTimeRangeFiltering.vue'
const props = withDefaults(
defineProps<{
timeRange: TimeRange
timeGranularity: DatePickType
}>(),
{
timeRange: () => ({
intervalType: 'none',
dynamicWindow: false,
maximumSingleQuery: 0,
regularOrTrends: 'fixed',
relativeToCurrentRange: 'custom',
regularOrTrendsValue: '',
relativeToCurrent: 'custom',
timeNum: 0,
relativeToCurrentType: 'year',
around: 'f',
timeNumRange: 0,
relativeToCurrentTypeRange: 'year',
aroundRange: 'f'
}),
timeGranularity: 'year'
}
)
const { t } = useI18n()
const intervalTypeList = [
{
label: t('chart.line_symbol_none'),
value: 'none'
},
{
label: t('v_query.start_at'),
value: 'start'
},
{
label: t('v_query.end_at'),
value: 'end'
},
{
label: t('v_query.time_interval'),
value: 'timeInterval'
}
]
const regularOrTrendsTitle = computed(() => {
return intervalTypeList.find(ele => ele.value === timeRange.value.intervalType).label
})
const { timeRange } = toRefs(props)
const dynamicTime = computed(() => {
return timeRange.value.regularOrTrends !== 'fixed'
})
const filterTypeCom = computed(() => {
const { intervalType } = timeRange.value
return intervalType === 'timeInterval' ? DynamicTimeRange : DynamicTime
})
const timeGranularityMultiple = computed<DatePickType>(() => {
return (props.timeGranularity + 'range') as DatePickType
})
const aroundList = [
{
label: t('dynamic_time.before'),
value: 'f'
},
{
label: t('dynamic_time.after'),
value: 'b'
}
]
const relativeToCurrentTypeList = computed(() => {
if (!timeRange.value) return []
let index = ['year', 'month', 'date', 'datetime'].indexOf(props.timeGranularity) + 1
return [
{
label: t('dynamic_time.year'),
value: 'year'
},
{
label: t('dynamic_time.month'),
value: 'month'
},
{
label: t('dynamic_time.date'),
value: 'day'
}
].slice(0, index)
})
const relativeToCurrentList = computed(() => {
let list = []
if (!timeRange.value) return list
switch (props.timeGranularity) {
case 'year':
list = [
{
label: t('dynamic_year.current'),
value: 'thisYear'
},
{
label: t('dynamic_year.last'),
value: 'lastYear'
}
]
break
case 'month':
list = [
{
label: t('cron.this_month'),
value: 'thisMonth'
},
{
label: t('dynamic_month.last'),
value: 'lastMonth'
}
]
break
case 'date':
list = [
{
label: t('dynamic_time.today'),
value: 'today'
},
{
label: t('dynamic_time.yesterday'),
value: 'yesterday'
},
{
label: t('dynamic_time.firstOfMonth'),
value: 'monthBeginning'
},
{
label: t('dynamic_time.firstOfYear'),
value: 'yearBeginning'
}
]
break
case 'datetime':
list = [
{
label: t('dynamic_time.today'),
value: 'today'
},
{
label: t('dynamic_time.yesterday'),
value: 'yesterday'
},
{
label: t('dynamic_time.firstOfMonth'),
value: 'monthBeginning'
},
{
label: t('dynamic_time.firstOfYear'),
value: 'yearBeginning'
}
]
break
default:
break
}
return [
...list,
{
label: t('dynamic_time.custom'),
value: 'custom'
}
]
})
const relativeToCurrentListRange = computed(() => {
let list = []
if (!timeRange.value) return list
switch (props.timeGranularity) {
case 'year':
list = [
{
label: t('dynamic_year.current'),
value: 'thisYear'
},
{
label: t('dynamic_year.last'),
value: 'lastYear'
}
]
break
case 'month':
list = [
{
label: t('cron.this_month'),
value: 'thisMonth'
},
{
label: t('dynamic_month.dynamic_month'),
value: 'lastMonth'
},
{
label: t('v_query.last_3_months'),
value: 'LastThreeMonths'
},
{
label: t('v_query.last_6_months'),
value: 'LastSixMonths'
},
{
label: t('v_query.last_12_months'),
value: 'LastTwelveMonths'
}
]
break
case 'date':
case 'datetime':
list = [
{
label: t('dynamic_time.today'),
value: 'today'
},
{
label: t('dynamic_time.yesterday'),
value: 'yesterday'
},
{
label: t('v_query.last_3_days'),
value: 'LastThreeDays'
},
{
label: t('v_query.month_to_date'),
value: 'monthBeginning'
},
{
label: t('v_query.year_to_date'),
value: 'yearBeginning'
}
]
break
default:
break
}
return [
...list,
{
label: t('dynamic_time.custom'),
value: 'custom'
}
]
})
</script>
<template>
<div class="set-time-filtering-range">
<div class="title">{{ t('v_query.time_filter_range') }}</div>
<div class="list-item">
<div class="label">{{ t('v_query.interval_type') }}</div>
<div class="setting-content">
<div class="setting">
<el-radio-group v-model="timeRange.intervalType">
<el-radio v-for="ele in intervalTypeList" :key="ele.value" :label="ele.value">{{
ele.label
}}</el-radio>
</el-radio-group>
</div>
</div>
</div>
<div class="list-item" v-if="timeRange.intervalType !== 'none'">
<div class="label">{{ regularOrTrendsTitle }}</div>
<div class="setting-content">
<div class="setting">
<el-radio-group v-model="timeRange.regularOrTrends">
<el-radio label="fixed">{{ t('dynamic_time.fix') }}</el-radio>
<el-radio label="dynamic">{{ t('dynamic_time.dynamic') }}</el-radio>
</el-radio-group>
</div>
<template v-if="dynamicTime && timeRange.intervalType !== 'timeInterval'">
<div class="setting" v-if="timeRange.intervalType !== 'timeInterval'">
<div class="setting-label">{{ t('dynamic_time.relative') }}</div>
<div class="setting-value select">
<el-select v-model="timeRange.relativeToCurrent">
<el-option
v-for="item in relativeToCurrentList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</div>
<div class="setting" v-if="timeRange.relativeToCurrent === 'custom'">
<div class="setting-input">
<el-input-number v-model="timeRange.timeNum" :min="0" controls-position="right" />
<el-select v-model="timeRange.relativeToCurrentType">
<el-option
v-for="item in relativeToCurrentTypeList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-select v-model="timeRange.around">
<el-option
v-for="item in aroundList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</div>
</template>
<template v-else-if="dynamicTime && timeRange.intervalType === 'timeInterval'">
<div class="setting">
<div class="setting-label">{{ t('dynamic_time.relative') }}</div>
<div class="setting-value select">
<el-select v-model="timeRange.relativeToCurrentRange">
<el-option
v-for="item in relativeToCurrentListRange"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</div>
<template v-if="timeRange.relativeToCurrentRange === 'custom'">
<div
class="setting"
:class="['year', 'month'].includes(timeGranularity) && 'is-year-month-range'"
>
<div class="setting-label">{{ t('datasource.start_time') }}</div>
<div class="setting-input range">
<el-input-number
step-strictly
v-model="timeRange.timeNum"
:min="0"
controls-position="right"
/>
<el-select v-model="timeRange.relativeToCurrentType">
<el-option
v-for="item in relativeToCurrentTypeList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-select v-model="timeRange.around">
<el-option
v-for="item in aroundList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</div>
<div
class="setting"
:class="['year', 'month'].includes(timeGranularity) && 'is-year-month-range'"
>
<div class="setting-label">{{ t('datasource.end_time') }}</div>
<div class="setting-input range">
<el-input-number
v-model="timeRange.timeNumRange"
:min="0"
step-strictly
controls-position="right"
/>
<el-select v-model="timeRange.relativeToCurrentTypeRange">
<el-option
v-for="item in relativeToCurrentTypeList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-select v-model="timeRange.aroundRange">
<el-option
v-for="item in aroundList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</div>
</template>
</template>
</div>
<div class="parameters" :class="dynamicTime && 'setting'">
<div class="setting-label" v-if="dynamicTime">{{ t('template_manage.preview') }}</div>
<div :class="dynamicTime ? 'setting-value' : 'w100'">
<component
:config="timeRange"
:timeGranularityMultiple="timeGranularityMultiple"
ref="inputCom"
:is="filterTypeCom"
></component>
</div>
</div>
</div>
</div>
</template>
<style lang="less">
.set-time-filtering-range {
.ed-radio,
.ed-checkbox.ed-checkbox--default {
height: 22px;
margin-right: 24px;
--ed-radio-input-height: 16px;
--ed-radio-input-width: 16px;
}
.title {
font-size: 14px;
font-weight: 500;
line-height: 22px;
margin-bottom: 16px;
}
.list-item {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
flex-wrap: wrap;
.setting-content {
width: 100%;
&.maximum-single-query {
padding-left: 24px;
display: flex;
align-items: center;
margin-top: 8px;
.ed-input-number {
width: 120px;
margin: 0 8px;
}
}
}
&.top-item {
.label {
margin-bottom: auto;
padding-top: 5.5px;
}
}
.label {
width: 100px;
color: #1f2329;
}
.value {
width: 321px;
.value {
margin-top: 8px;
&:first-child {
margin-top: -0.5px;
}
}
.ed-select {
width: 321px;
}
}
.parameters {
width: 100%;
margin-top: 8px;
.w100 {
width: 100%;
}
.ed-date-editor,
.ed-date-editor--datetime .ed-input__wrapper,
.ed-select-v2 {
width: 415px;
}
.ed-date-editor {
.ed-input__wrapper {
width: 100%;
}
}
}
.parameters-range {
width: 100%;
padding-left: 24px;
display: flex;
flex-wrap: wrap;
.range-title,
.params-start,
.params-end {
width: 50%;
}
.params-start,
.params-end {
margin-top: 8px;
.ed-select {
width: 100%;
}
}
.params-end {
padding-left: 4px;
}
.params-start {
padding-right: 4px;
}
}
.setting {
&.setting {
margin-top: 8px;
}
&.parameters {
width: 100%;
padding-left: 24px;
.setting-label {
margin-left: 0;
}
.ed-date-editor {
width: 308px !important;
}
}
margin-left: auto;
display: flex;
justify-content: space-between;
align-items: center;
.setting-label {
width: 80px;
margin: 0 8px 0 24px;
}
.setting-value {
&.select {
.ed-select {
width: 308px;
}
}
}
.setting-input {
display: flex;
padding-left: 112px;
justify-content: flex-end;
align-items: center;
&.range {
padding-left: 0px;
width: 308px;
}
& > div + div {
margin-left: 8px;
}
}
&.is-year-month-range {
.setting-input {
.ed-date-editor.ed-input {
display: none;
}
}
}
}
}
}
</style>
<style>
.range-filter-time {
padding: 15px !important;
}
</style>

View File

@ -443,6 +443,8 @@ const formatDate = computed(() => {
v-else
:key="config.timeGranularity + 1"
v-model="selectValue"
@visible-change="visibleChange"
:disabled-date="disabledDate"
:type="config.timeGranularity"
@change="handleValueChange"
:style="selectStyle"

View File

@ -240,7 +240,7 @@ interface TimeRange {
timeNumRange: number
relativeToCurrentTypeRange: ManipulateType
aroundRange: string
timeGranularityMultiple: string
timeGranularityMultiple?: string
}
export {
TimeRange,