fix(查询组件): 日期筛选组件可设置查询的起始日期

This commit is contained in:
dataeaseShu 2024-03-11 18:38:36 +08:00
parent b82dfa43cf
commit d78351ddea
6 changed files with 850 additions and 6 deletions

View File

@ -0,0 +1,145 @@
<script lang="ts" setup>
import { toRefs, PropType, onBeforeMount, watch, computed } from 'vue'
import { Calendar } from '@element-plus/icons-vue'
import { type DatePickType } from 'element-plus-secondary'
import {
getThisYear,
getLastYear,
getThisMonth,
getLastMonth,
getToday,
getYesterday,
getMonthBeginning,
getYearBeginning,
getCustomTime
} from './time-format'
interface SelectConfig {
timeType: string
intervalType: string
regularOrTrendsValue: Date
regularOrTrends: string
relativeToCurrent: string
timeNum: number
relativeToCurrentType: string
around: string
timeGranularity: DatePickType
}
const props = defineProps({
config: {
type: Object as PropType<SelectConfig>,
default: () => {
return {
regularOrTrendsValue: '',
intervalType: 'none',
regularOrTrends: 'fixed',
relativeToCurrent: 'custom',
timeNum: 0,
relativeToCurrentType: 'year',
around: 'f'
}
}
},
timeGranularityMultiple: {
type: Object as PropType<DatePickType>,
default: () => {
return 'yearrange'
}
}
})
const { config } = toRefs(props)
const timeConfig = computed(() => {
const {
relativeToCurrent,
intervalType,
timeNum,
relativeToCurrentType,
around,
timeGranularity
} = config.value
return {
relativeToCurrent,
timeNum,
intervalType,
relativeToCurrentType,
around,
timeGranularity
}
})
watch(
() => timeConfig.value,
() => {
init()
},
{
deep: true
}
)
const timeInterval = computed<DatePickType>(() => {
return config.value.intervalType !== 'timeInterval'
? (props.timeGranularityMultiple.split('range')[0] as DatePickType)
: props.timeGranularityMultiple
})
const init = () => {
const { relativeToCurrent, timeNum, relativeToCurrentType, around, timeGranularity } =
timeConfig.value
if (relativeToCurrent === 'custom') {
config.value.regularOrTrendsValue = getCustomTime(
timeNum,
relativeToCurrentType,
timeGranularity,
around,
null
)
} else {
switch (relativeToCurrent) {
case 'thisYear':
config.value.regularOrTrendsValue = getThisYear()
break
case 'lastYear':
config.value.regularOrTrendsValue = getLastYear()
break
case 'thisMonth':
config.value.regularOrTrendsValue = getThisMonth()
break
case 'lastMonth':
config.value.regularOrTrendsValue = getLastMonth()
break
case 'today':
config.value.regularOrTrendsValue = getToday()
break
case 'yesterday':
config.value.regularOrTrendsValue = getYesterday()
break
case 'monthBeginning':
config.value.regularOrTrendsValue = getMonthBeginning()
break
case 'yearBeginning':
config.value.regularOrTrendsValue = getYearBeginning()
break
default:
break
}
}
}
onBeforeMount(() => {
init()
})
</script>
<template>
<el-date-picker
:disabled="config.regularOrTrends !== 'fixed'"
v-model="config.regularOrTrendsValue"
:type="timeInterval"
:prefix-icon="Calendar"
:placeholder="$t('commons.date.select_date_time')"
/>
</template>

View File

@ -1,5 +1,5 @@
<script lang="ts" setup>
import { toRefs, nextTick, PropType, ref, onBeforeMount, watch, computed } from 'vue'
import { toRefs, PropType, ref, onBeforeMount, watch, computed } from 'vue'
import { Calendar } from '@element-plus/icons-vue'
import { type DatePickType } from 'element-plus-secondary'
import { getCustomTime } from './time-format'

View File

@ -0,0 +1,137 @@
<script lang="ts" setup>
import { toRefs, PropType, ref, onBeforeMount, watch, computed } from 'vue'
import { Calendar } from '@element-plus/icons-vue'
import { type DatePickType } from 'element-plus-secondary'
import { getCustomTime } from './time-format'
interface SelectConfig {
regularOrTrends: string
regularOrTrendsValue: [Date, Date]
intervalType: string
timeNum: number
relativeToCurrentType: string
around: string
timeGranularity: DatePickType
timeNumRange: number
relativeToCurrentTypeRange: string
aroundRange: string
}
const props = defineProps({
config: {
type: Object as PropType<SelectConfig>,
default: () => {
return {
timeGranularityMultiple: 'datetimerange',
regularOrTrendsValue: [],
regularOrTrends: 'fixed',
timeNum: 0,
intervalType: 'none',
relativeToCurrentType: 'year',
around: 'f',
timeGranularity: 'date',
timeNumRange: 0,
relativeToCurrentTypeRange: 'year',
aroundRange: 'f'
}
}
},
timeGranularityMultiple: {
type: Object as PropType<DatePickType>,
default: () => {
return 'yearrange'
}
}
})
const { config } = toRefs(props)
const timeConfig = computed(() => {
const {
timeNum,
relativeToCurrentType,
around,
intervalType,
timeGranularity,
timeNumRange,
relativeToCurrentTypeRange,
aroundRange
} = config.value
return {
timeNum,
relativeToCurrentType,
around,
intervalType,
timeGranularity,
timeNumRange,
relativeToCurrentTypeRange,
aroundRange
}
})
const timeInterval = computed<DatePickType>(() => {
return config.value.intervalType !== 'timeInterval'
? (props.timeGranularityMultiple.split('range')[0] as DatePickType)
: props.timeGranularityMultiple
})
watch(
() => timeConfig.value,
() => {
init()
},
{
deep: true
}
)
const init = () => {
const {
timeNum,
relativeToCurrentType,
around,
timeGranularity,
timeNumRange,
relativeToCurrentTypeRange,
aroundRange
} = timeConfig.value
const startTime = getCustomTime(
timeNum,
relativeToCurrentType,
timeGranularity,
around,
null,
timeInterval.value,
'start-config'
)
const endTime = getCustomTime(
timeNumRange,
relativeToCurrentTypeRange,
timeGranularity,
aroundRange,
null,
timeInterval.value,
'end-config'
)
config.value.regularOrTrendsValue = [startTime, endTime]
}
onBeforeMount(() => {
init()
})
const formatDate = computed(() => {
return (props.timeGranularityMultiple as string) === 'yearrange' ? 'YYYY' : undefined
})
</script>
<template>
<el-date-picker
:disabled="config.regularOrTrends !== 'fixed'"
v-model="config.regularOrTrendsValue"
:type="timeInterval"
:prefix-icon="Calendar"
:format="formatDate"
:range-separator="$t('cron.to')"
:start-placeholder="$t('datasource.start_time')"
:end-placeholder="$t('datasource.end_time')"
/>
</template>

View File

@ -19,6 +19,7 @@ import DynamicTimeRange from './DynamicTimeRange.vue'
import { getDatasetTree } from '@/api/dataset'
import { Tree } from '@/views/visualized/data/dataset/form/CreatDsGroup.vue'
import draggable from 'vuedraggable'
import RangeFilterTime from './RangeFilterTime.vue'
const { t } = useI18n()
const dvMainStore = dvMainStoreWithOut()
@ -120,7 +121,11 @@ const { queryElement } = toRefs(props)
const getDetype = (id, arr) => {
return arr.find(ele => ele.id === id)?.deType
}
const visiblePopover = ref(false)
const handleVisiblePopover = ev => {
ev.stopPropagation()
visiblePopover.value = !visiblePopover.value
}
const showConfiguration = computed(() => {
if (!curComponent.value) return false
if (!curComponent.value.checkedFields?.length) return false
@ -162,6 +167,7 @@ const handleCheckAllChange = (val: boolean) => {
isIndeterminate.value = false
}
const handleCheckedFieldsChange = (value: string[]) => {
handleDialogClick()
const checkedCount = value.length
checkAll.value = checkedCount === fields.value.length
isIndeterminate.value = checkedCount > 0 && checkedCount < fields.value.length
@ -194,6 +200,7 @@ const setType = () => {
}
const setTypeChange = () => {
handleDialogClick()
nextTick(() => {
curComponent.value.field.id = ''
inputCom.value?.displayTypeChange?.()
@ -496,7 +503,21 @@ const parameterCompletion = () => {
timeNumRange: 0,
relativeToCurrentTypeRange: 'year',
aroundRange: 'f',
arbitraryTimeRange: new Date()
arbitraryTimeRange: new Date(),
timeRange: {
intervalType: 'none',
dynamicWindow: false,
maximumSingleQuery: 0,
regularOrTrends: 'fixed',
regularOrTrendsValue: '',
relativeToCurrent: 'custom',
timeNum: 0,
relativeToCurrentType: 'year',
around: 'f',
timeNumRange: 0,
relativeToCurrentTypeRange: 'year',
aroundRange: 'f'
}
}
Object.entries(attributes).forEach(([key, val]) => {
!curComponent.value[key] && (curComponent.value[key] = val)
@ -504,6 +525,7 @@ const parameterCompletion = () => {
}
const handleCondition = item => {
handleDialogClick()
if (activeConditionForRename.id) return
activeCondition.value = item.id
curComponent.value = conditions.value.find(ele => ele.id === item.id)
@ -557,7 +579,9 @@ const showError = computed(() => {
}
return (optionValueSource === 1 && !field.id) || (optionValueSource === 2 && !valueSource.length)
})
const handleDialogClick = () => {
visiblePopover.value = false
}
const relativeToCurrentList = computed(() => {
let list = []
if (!curComponent.value) return list
@ -682,6 +706,7 @@ const timeGranularityChange = (val: string) => {
}
const timeGranularityMultipleChange = (val: string) => {
handleDialogClick()
if (
['yearrange', 'monthrange', 'datetimerange'].indexOf(val) <
['year', 'month', 'date'].indexOf(curComponent.value.relativeToCurrentType)
@ -797,7 +822,7 @@ defineExpose({
@mousedown.stop
@mousedup.stop
>
<div class="container">
<div class="container" @click="handleDialogClick">
<div class="query-condition-list">
<div class="title">
查询条件
@ -1186,6 +1211,35 @@ defineExpose({
</el-radio-group>
</div>
</div>
<div v-if="curComponent.displayType === '7'" class="list-item">
<div class="label">
<el-checkbox v-model="curComponent.parametersCheck" label="设置时间筛选范围" />
</div>
<div class="setting-content">
<el-popover
:show-arrow="false"
popper-class="range-filter-time"
placement="bottom-start"
:width="452"
:visible="visiblePopover"
:offset="4"
>
<template #reference>
<el-button @click="handleVisiblePopover($event)" text style="margin-left: -4px">
<template #icon>
<Icon name="icon_admin_outlined"></Icon>
</template>
设置
</el-button>
</template>
<RangeFilterTime
:timeRange="curComponent.timeRange"
:timeGranularityMultiple="curComponent.timeGranularityMultiple"
/>
</el-popover>
<span class="config-flag range-filter-time-flag">已配置</span>
</div>
</div>
<div class="list-item">
<div class="label">
<el-checkbox v-model="curComponent.parametersCheck" label="绑定参数" />
@ -1616,6 +1670,13 @@ defineExpose({
border-radius: 2px;
background: rgba(31, 35, 41, 0.1);
margin-left: 8px;
&.range-filter-time-flag {
display: inline-block;
padding: 1px 4px;
line-height: 14px;
margin-left: 4px;
}
}
.flex-align-center {

View File

@ -0,0 +1,486 @@
<script lang="ts" setup>
import { toRefs, computed, PropType } from 'vue'
import { type TimeRange } from './time-format'
import DynamicTime from './DynamicTimeFiltering.vue'
import DynamicTimeRange from './DynamicTimeRangeFiltering.vue'
const props = defineProps({
timeRange: {
type: Object as PropType<TimeRange>,
default: () => ({
intervalType: 'none',
dynamicWindow: false,
maximumSingleQuery: 0,
regularOrTrends: 'fixed',
regularOrTrendsValue: '',
relativeToCurrent: 'custom',
timeNum: 0,
relativeToCurrentType: 'year',
around: 'f',
timeNumRange: 0,
relativeToCurrentTypeRange: 'year',
aroundRange: 'f'
})
},
timeGranularityMultiple: {
type: String,
default: 'yearrange'
}
})
const intervalTypeList = [
{
label: '无',
value: 'none'
},
{
label: '开始于',
value: 'start'
},
{
label: '结束于',
value: 'end'
},
{
label: '时间区间',
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 aroundList = [
{
label: '前',
value: 'f'
},
{
label: '后',
value: 'b'
}
]
const relativeToCurrentTypeList = computed(() => {
if (!timeRange.value) return []
let index =
['yearrange', 'monthrange', 'daterange', 'datetimerange'].indexOf(
props.timeGranularityMultiple
) + 1
return [
{
label: '年',
value: 'year'
},
{
label: '月',
value: 'month'
},
{
label: '日',
value: 'date'
}
].slice(0, index)
})
const relativeToCurrentList = computed(() => {
let list = []
if (!timeRange.value) return list
switch (props.timeGranularityMultiple) {
case 'yearrange':
list = [
{
label: '今年',
value: 'thisYear'
},
{
label: '去年',
value: 'lastYear'
}
]
break
case 'monthrange':
list = [
{
label: '本月',
value: 'thisMonth'
},
{
label: '上月',
value: 'lastMonth'
}
]
break
case 'daterange':
list = [
{
label: '今天',
value: 'today'
},
{
label: '昨天',
value: 'yesterday'
},
{
label: '月初',
value: 'monthBeginning'
},
{
label: '年初',
value: 'yearBeginning'
}
]
break
case 'datetimerange':
list = [
{
label: '今天',
value: 'today'
},
{
label: '昨天',
value: 'yesterday'
},
{
label: '月初',
value: 'monthBeginning'
},
{
label: '年初',
value: 'yearBeginning'
}
]
break
default:
break
}
return [
...list,
{
label: '自定义',
value: 'custom'
}
]
})
</script>
<template>
<div class="set-time-filtering-range">
<div class="title">设置时间筛选范围</div>
<div class="list-item">
<div class="label">区间类型</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">固定时间</el-radio>
<el-radio label="dynamic">动态时间</el-radio>
</el-radio-group>
</div>
<template v-if="dynamicTime && timeRange.intervalType !== 'timeInterval'">
<div class="setting">
<div class="setting-label">相对当前</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"
:class="
['yearrange', 'monthrange'].includes(timeGranularityMultiple) && 'is-year-month-range'
"
>
<div class="setting-label">开始时间</div>
<div class="setting-input range">
<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>
<div
class="setting"
:class="
['yearrange', 'monthrange'].includes(timeGranularityMultiple) && 'is-year-month-range'
"
>
<div class="setting-label">结束时间</div>
<div class="setting-input range">
<el-input-number
v-model="timeRange.timeNumRange"
:min="0"
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>
</div>
<div class="parameters" :class="dynamicTime && 'setting'">
<div class="setting-label" v-if="dynamicTime">预览</div>
<div :class="dynamicTime ? 'setting-value' : 'w100'">
<component :config="timeRange" isConfig ref="inputCom" :is="filterTypeCom"></component>
</div>
</div>
</div>
<div class="list-item">
<div class="label">
<el-checkbox v-model="timeRange.dynamicWindow" label="动态查询时间窗口" />
</div>
<div v-if="timeRange.dynamicWindow" class="setting-content maximum-single-query">
单次查询最多
<el-input-number
v-model="timeRange.maximumSingleQuery"
:min="1"
controls-position="right"
/>
</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;
.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

@ -219,8 +219,23 @@ function getDynamicRange({
return selectValue
}
interface TimeRange {
intervalType: string
dynamicWindow: boolean
maximumSingleQuery: number
regularOrTrends: string
regularOrTrendsValue: string
relativeToCurrent: string
timeNum: number
relativeToCurrentType: string
around: string
timeNumRange: number
relativeToCurrentTypeRange: string
aroundRange: string
timeGranularityMultiple: string
}
export {
TimeRange,
getThisYear,
getLastYear,
getThisMonth,