Merge pull request #8571 from dataease/pr@dev_time_filter

feat(过滤组件): 日期筛选组件可设置查询的起始日期 #6005
This commit is contained in:
dataeaseShu 2024-03-18 18:19:25 +08:00 committed by GitHub
commit 25936258d3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 635 additions and 3 deletions

View File

@ -41,6 +41,7 @@
"@tinymce/tinymce-vue": "^3.2.8",
"axios": "^1.6.1",
"core-js": "^2.6.5",
"dayjs": "^1.11.10",
"echarts": "^5.0.1",
"element-resize-detector": "^1.2.3",
"element-ui": "2.15.7",

View File

@ -70,12 +70,32 @@
<el-col :span="16">
<div class="filter-options-right">
<span style="padding-right: 10px;">
<span v-if="widget.name && ['textSelectWidget', 'textSelectGridWidget'].includes(widget.name)" style="padding-right: 10px;">
<el-popover :visible-arrow="false" placement="bottom-start" :width="180" trigger="click">
<template #reference>
<div class="more-select-btn icon iconfont icon-icon-more">
{{ $t('panel.more') }}
</div>
</template>
<el-checkbox
v-if="widget.name && ['textSelectWidget', 'textSelectGridWidget'].includes(widget.name)"
v-model="attrs.showEmpty"
>{{ $t('panel.show_empty') }}
</el-checkbox>
</span>
<el-checkbox
v-if="widget.name && ['timeDateRangeWidget'].includes(widget.name)"
v-model="attrs.showEmpty"
>设置时间筛选范围
</el-checkbox>
<el-popover :visible-arrow="false" :offset="-452" placement="bottom-start" :width="452" trigger="click">
<template #reference>
<svg-icon
icon-class="icon-setting"
/>
</template>
<RangeFilterTime :timeRangeData="attrs.timeRange" />
</el-popover>
</el-popover>
<el-checkbox
v-model="attrs.showTitle"
@change="showTitleChange"
@ -261,9 +281,10 @@
<script>
import FilterSort from './FilterSort'
import RangeFilterTime from '@/views/panel/filter/filterMain/RangeFilterTime.vue'
export default {
name: 'FilterControl',
components: { FilterSort },
components: { FilterSort, RangeFilterTime },
props: {
widget: {
type: Object,
@ -370,6 +391,22 @@ export default {
created() {
this.attrs = this.controlAttrs
if (!this.attrs.timeRange) {
this.$set(this.attrs, 'timeRange', {
intervalType: "none",
dynamicWindow: false,
maximumSingleQuery: 0,
regularOrTrends: "fixed",
regularOrTrendsValue: "",
relativeToCurrent: "custom",
timeNum: 0,
relativeToCurrentType: "year",
around: "f",
timeNumRange: 0,
relativeToCurrentTypeRange: "year",
aroundRange: "f",
})
}
if (this.widget.isTimeWidget) {
this.showParams = true
this.isRangeParamWidget = this.widget.isRangeParamWidget && this.widget.isRangeParamWidget()
@ -461,6 +498,25 @@ export default {
justify-content: flex-end;
flex-wrap: nowrap;
height: 50px;
.more-select-btn {
display: inline-flex;
width: 56px;
height: 26px;
border-radius: 4px;
color: #3370FF;
font-size: 14px;
font-weight: 400;
line-height: 22px;
align-items: center;
justify-content: center;
&:hover {
background: #3370FF1A;
}
&.icon-icon-more::before {
margin-right: 4px;
}
}
}
.i-filter {

View File

@ -0,0 +1,553 @@
<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">
<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">
<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'">
<el-date-picker
:disabled="timeRange.regularOrTrends !== 'fixed'"
v-model="timeRange.regularOrTrendsValue"
:key="timeInterval"
:type="timeInterval"
:start-placeholder="$t('dataset.start_time')"
:end-placeholder="$t('dataset.end_time')"
/>
</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"
/>
{{ relativeToCurrentTypeListTips }}
</div>
</div>
</div>
</template>
<script>
import { getThisStart, getLastStart, getAround } from "./time-format-dayjs";
const intervalTypeList = [
{
label: "无",
value: "none",
},
{
label: "开始于",
value: "start",
},
{
label: "结束于",
value: "end",
},
{
label: "时间区间",
value: "timeInterval",
},
];
const aroundList = [
{
label: "前",
value: "f",
},
{
label: "后",
value: "b",
},
];
const relativeToCurrentTypeList = [
{
label: "年",
value: "year",
},
{
label: "月",
value: "month",
},
{
label: "日",
value: "day",
},
];
const relativeToCurrentList = [
{
label: "今天",
value: "today",
},
{
label: "昨天",
value: "yesterday",
},
{
label: "月初",
value: "monthBeginning",
},
{
label: "年初",
value: "yearBeginning",
},
{
label: "自定义",
value: "custom",
},
];
export default {
props: {
timeRangeData: {
type: Object,
defalut: () => ({
intervalType: "none",
dynamicWindow: false,
maximumSingleQuery: 0,
regularOrTrends: "fixed",
regularOrTrendsValue: "",
relativeToCurrent: "custom",
timeNum: 0,
relativeToCurrentType: "year",
around: "f",
timeNumRange: 0,
relativeToCurrentTypeRange: "year",
aroundRange: "f",
}),
},
},
data() {
return {
intervalTypeList,
relativeToCurrentTypeList,
aroundList,
relativeToCurrentList,
timeRange: {
intervalType: "none",
dynamicWindow: false,
maximumSingleQuery: 0,
regularOrTrends: "fixed",
regularOrTrendsValue: "",
relativeToCurrent: "custom",
timeNum: 0,
relativeToCurrentType: "year",
around: "f",
timeNumRange: 0,
relativeToCurrentTypeRange: "year",
aroundRange: "f",
},
};
},
created() {
this.timeRange = this.timeRangeData;
},
computed: {
timeConfig() {
const {
timeNum,
relativeToCurrentType,
around,
intervalType,
timeNumRange,
relativeToCurrentTypeRange,
aroundRange,
} = this.timeRange;
return {
timeNum,
relativeToCurrentType,
around,
intervalType,
timeNumRange,
relativeToCurrentTypeRange,
aroundRange,
};
},
regularOrTrendsTitle() {
return intervalTypeList.find(
(ele) => ele.value === this.timeRange.intervalType,
).label;
},
dynamicTime() {
return this.timeRange.regularOrTrends !== "fixed";
},
timeInterval() {
return this.timeRange.intervalType === "timeInterval"
? "daterange"
: "date";
},
},
watch: {
timeConfig: {
handler() {
this.init();
},
deep: true,
},
},
methods: {
init() {
const {
timeNum,
relativeToCurrentType,
around,
relativeToCurrent,
intervalType,
timeNumRange,
relativeToCurrentTypeRange,
aroundRange,
} = this.timeRange;
if (intervalType === "timeInterval") {
const startTime = getAround(
relativeToCurrentType,
around === "f" ? "subtract" : "add",
timeNum,
);
const endTime = getAround(
relativeToCurrentTypeRange,
aroundRange === "f" ? "subtract" : "add",
timeNumRange,
);
this.timeRange.regularOrTrendsValue = [startTime, endTime];
return;
}
if (relativeToCurrent === "custom") {
this.timeRange.regularOrTrendsValue = getAround(
relativeToCurrentType,
around === "f" ? "subtract" : "add",
timeNum,
);
} else {
switch (relativeToCurrent) {
case "thisYear":
this.timeRange.regularOrTrendsValue = getThisStart("year");
break;
case "lastYear":
this.timeRange.regularOrTrendsValue = getLastStart("year");
break;
case "thisMonth":
this.timeRange.regularOrTrendsValue = getThisStart("month");
break;
case "lastMonth":
this.timeRange.regularOrTrendsValue = getLastStart("month");
break;
case "today":
this.timeRange.regularOrTrendsValue = getThisStart("day");
break;
case "yesterday":
this.timeRange.regularOrTrendsValue = getLastStart("day");
break;
case "monthBeginning":
this.timeRange.regularOrTrendsValue = getThisStart("month");
break;
case "yearBeginning":
this.timeRange.regularOrTrendsValue = getThisStart("year");
break;
default:
break;
}
}
},
},
};
</script>
<style lang="less">
.set-time-filtering-range {
.el-radio,
.el-checkbox.el-checkbox--default {
height: 22px;
margin-right: 24px;
--el-radio-input-height: 16px;
--el-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;
.el-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;
}
}
.el-select {
width: 321px;
}
}
.parameters {
width: 100%;
margin-top: 8px;
.w100 {
width: 100%;
}
.el-date-editor,
.el-date-editor--datetime .el-input__wrapper,
.el-select-v2 {
width: 415px;
}
.el-date-editor {
.el-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;
.el-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;
}
.el-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 {
.el-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 {
.el-date-editor.el-input {
display: none;
}
}
}
}
}
}
</style>
<style>
.range-filter-time {
padding: 15px !important;
}
</style>

View File

@ -0,0 +1,22 @@
import dayjs from 'dayjs'
function getThisStart(val = 'month') {
return new Date(dayjs().startOf(val).format('YYYY/MM/DD HH:mm:ss'))
}
function getThisEnd(val = 'month') {
return new Date(dayjs().endOf(val).format('YYYY/MM/DD HH:mm:ss'))
}
function getLastStart(val = 'month') {
return new Date(dayjs().subtract(1, val).startOf(val).format('YYYY/MM/DD HH:mm:ss'))
}
function getLastEnd(val = 'month') {
return new Date(dayjs().subtract(1, val).endOf(val).format('YYYY/MM/DD HH:mm:ss'))
}
function getAround(val = 'month', type = 'add', num = 0) {
return new Date(dayjs()[type](num, val).startOf('day').format('YYYY/MM/DD HH:mm:ss'))
}
export { getThisStart, getThisEnd, getLastStart, getLastEnd, getAround }