All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bklab.flow.dialog.timerange.TimeRangeDialog Maven / Gradle / Ivy

There is a newer version: 22.0.1
Show newest version
package org.bklab.flow.dialog.timerange;

import com.vaadin.flow.component.ClickEvent;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.datetimepicker.DateTimePicker;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.server.VaadinSession;
import dev.mett.vaadin.tooltip.Tooltips;
import org.apache.commons.collections4.map.UnmodifiableMap;
import org.bklab.flow.components.button.FluentButton;
import org.bklab.flow.dialog.ErrorDialog;
import org.bklab.flow.dialog.ModalDialog;
import org.bklab.flow.factory.*;
import org.bklab.flow.layout.ToolBar;
import org.bklab.flow.util.element.HasSaveListeners;
import org.bklab.flow.util.url.QueryParameterBuilder;
import org.bklab.flow.util.url.QueryParameterUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

import static com.vaadin.flow.component.button.ButtonVariant.LUMO_PRIMARY;

public class TimeRangeDialog extends ModalDialog implements ITimeRangeSupplier, HasSaveListeners {

    private static final Logger logger = LoggerFactory.getLogger(TimeRangeDialog.class);
    private final DateTimePicker minDatetimePicker;
    private final DateTimePicker maxDatetimePicker;
    private final TextField statusField;
    private final Map buttonMap = new LinkedHashMap<>();
    private final Map timeRangeSupplierMap = new LinkedHashMap<>();
    private final List> saveListeners = new ArrayList<>();
    private ITimeRangeSupplier timeRangeSupplier;
    private ITimeRangeSupplier globalTimeRangeSupplier;
    private boolean memoryMode = true;

    private int defaultMaxDurationDay = Integer.MAX_VALUE;
    private Supplier globalMinDateTime = () -> LocalDateTime.MIN;
    private Supplier globalMaxDateTime = () -> LocalDateTime.MAX;
    private String defaultSelectName;

    private ITimeRangeSupplier[] initTimeRangeSupplier;

    {
        this.minDatetimePicker = new DateTimePickerFactory().startTimePlaceholder().lumoSmall()
                .widthFull().clearButtonVisible(false).step(Duration.ofMinutes(5)).get();
        this.maxDatetimePicker = new DateTimePickerFactory().endTimePlaceholder().lumoSmall()
                .widthFull().clearButtonVisible(false).step(Duration.ofMinutes(5)).get();
        this.statusField = new TextFieldFactory().lumoSmall().width("12em").readOnly()
                .suffixComponent(new ButtonFactory().clickListener(e -> {
                    if (!isOpened()) open();
                }).icon(VaadinIcon.CLOCK).lumoIcon().lumoSmall().lumoTertiaryInline().get()).get();
    }

    public TimeRangeDialog() {
    }

    public TimeRangeDialog(ITimeRangeSupplier... initTimeRangeSupplier) {
        initTimeRangeSupplier(initTimeRangeSupplier);
    }

    public TimeRangeDialog initTimeRangeSupplier(ITimeRangeSupplier... initTimeRangeSupplier) {
        this.initTimeRangeSupplier = initTimeRangeSupplier;
        return this;
    }

    public static ITimeRangeSupplier createTimeRangeSupplier(QueryParameterUtil util) {
        long minDatetime = util.getLong("minDatetime");
        long maxDatetime = util.getLong("maxDatetime");

        return TimeRangeSupplier.appoint(
                LocalDateTime.ofEpochSecond(minDatetime, 0, ZoneOffset.ofHours(8)),
                LocalDateTime.ofEpochSecond(maxDatetime, 0, ZoneOffset.ofHours(8))
        );
    }

    public static ITimeRangeSupplier createTimeRangeSupplier(int maxDuration, QueryParameterUtil util) {
        long minDatetime = util.getLong("minDatetime");
        long maxDatetime = util.getLong("maxDatetime");
        if (maxDatetime > 0 && minDatetime <= 0 || maxDatetime - minDatetime > maxDuration)
            minDatetime = maxDatetime - maxDuration;
        if (minDatetime > 0 && maxDatetime <= 0 || maxDatetime > minDatetime + maxDuration)
            maxDatetime = minDatetime + maxDuration;

        return TimeRangeSupplier.appoint(
                LocalDateTime.ofEpochSecond(minDatetime, 0, ZoneOffset.ofHours(8)),
                LocalDateTime.ofEpochSecond(maxDatetime, 0, ZoneOffset.ofHours(8))
        );
    }

    public int getDefaultMaxDurationDay() {
        return defaultMaxDurationDay;
    }

    public TimeRangeDialog setDefaultMaxDurationDay(int defaultMaxDurationDay) {
        this.defaultMaxDurationDay = defaultMaxDurationDay;
        return this;
    }

    public Supplier getGlobalMinDateTime() {
        return globalMinDateTime;
    }

    public TimeRangeDialog setGlobalMinDateTime(Supplier globalMinDateTime) {
        this.globalMinDateTime = globalMinDateTime;
        return this;
    }

    public Supplier getGlobalMaxDateTime() {
        return globalMaxDateTime;
    }

    public TimeRangeDialog setGlobalMaxDateTime(Supplier globalMaxDateTime) {
        this.globalMaxDateTime = globalMaxDateTime;
        return this;
    }

    public TimeRangeDialog defaultInitTimeRangeSupplier() {
        return this.initTimeRangeSupplier(
                TimeRangeSupplier.lastMinutes(5),
                TimeRangeSupplier.lastMinutes(15),
                TimeRangeSupplier.lastMinutes(30),
                TimeRangeSupplier.lastHours(1),
                TimeRangeSupplier.lastHours(6),
                TimeRangeSupplier.lastHours(12),
                TimeRangeSupplier.lastDays(1),
                TimeRangeSupplier.lastDays(3),
                TimeRangeSupplier.lastDays(7),
                TimeRangeSupplier.lastDays(15),
                TimeRangeSupplier.lastDays(30)
        );
    }

    public TimeRangeDialog globalTimeRangeSupplier(ITimeRangeSupplier globalTimeRangeSupplier) {
        this.globalTimeRangeSupplier = globalTimeRangeSupplier;
        return this;
    }

    public TimeRangeDialog globalTimeRangeSupplierToday() {
        this.globalTimeRangeSupplier = new ITimeRangeSupplier() {
            @Override
            public String getName() {
                return "今天";
            }

            @Override
            public LocalDateTime getMin() {
                return LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
            }

            @Override
            public LocalDateTime getMax() {
                return LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
            }
        };
        return this;
    }

    public String getDefaultSelectName() {
        return defaultSelectName;
    }

    public TimeRangeDialog setDefaultSelectName(String defaultSelectName) {
        this.defaultSelectName = defaultSelectName;
        return this;
    }

    public static String extend(QueryParameterUtil util, Map> map) {
        ITimeRangeSupplier timeRangeSupplier = createTimeRangeSupplier(util);
        if (map != null && !(map instanceof UnmodifiableMap)) {
            map.put("minDatetime", timeRangeSupplier::getMin);
            map.put("maxDatetime", timeRangeSupplier::getMax);
        }
        return timeRangeSupplier.getLabel();
    }

    public static void write(Map> parameterMap, QueryParameterBuilder builder) {
        Optional.ofNullable(parameterMap.get("minDatetime")).map(Supplier::get)
                .map(d -> ((LocalDateTime) d).toEpochSecond(ZoneOffset.ofHours(8)))
                .ifPresent(s -> builder.add("minDatetime", s));
        Optional.ofNullable(parameterMap.get("maxDatetime")).map(Supplier::get)
                .map(d -> ((LocalDateTime) d).toEpochSecond(ZoneOffset.ofHours(8)))
                .ifPresent(s -> builder.add("maxDatetime", s));
    }

    public ITimeRangeSupplier getDefaultGlobalTimeRangeSupplier() {
        return new ITimeRangeSupplier() {
            private LocalDateTime globalMin = null;

            @Override
            public String getName() {
                return "全部时间";
            }

            @Override
            public LocalDateTime getMin() {
                if (globalMin == null) {
                    globalMin = globalMinDateTime.get();
                }
                return globalMin;
            }

            @Override
            public LocalDateTime getMax() {
                return globalMaxDateTime.get();
            }
        };
    }

    public TimeRangeDialog build() {
        if (this.timeRangeSupplier == null) this.timeRangeSupplier = TimeRangeSupplier.lastDays(30);
        if (this.globalTimeRangeSupplier == null) this.globalTimeRangeSupplier = getDefaultGlobalTimeRangeSupplier();
        if (initTimeRangeSupplier == null) defaultInitTimeRangeSupplier();

        minDatetimePicker.setMin(globalTimeRangeSupplier.getMin());
        maxDatetimePicker.setMin(globalTimeRangeSupplier.getMin());
        minDatetimePicker.setMax(globalTimeRangeSupplier.getMax());
        maxDatetimePicker.setMax(globalTimeRangeSupplier.getMax());

        minDatetimePicker.addValueChangeListener(e -> {
            if (defaultMaxDurationDay == Integer.MAX_VALUE) return;
            LocalDateTime minDateTime = e.getValue();
            if (minDateTime == null) return;
            LocalDateTime maxDateTime = minDateTime.plusDays(defaultMaxDurationDay);
            maxDatetimePicker.getOptionalValue().ifPresent(value -> {
                if (maxDateTime.isBefore(value)) {
                    maxDatetimePicker.setValue(maxDateTime);
                }
            });
        });

        maxDatetimePicker.addValueChangeListener(e -> {
            if (defaultMaxDurationDay == Integer.MAX_VALUE) return;
            LocalDateTime maxDateTime = e.getValue();
            if (maxDateTime == null) return;
            LocalDateTime minDateTime = maxDateTime.minusDays(defaultMaxDurationDay);
            minDatetimePicker.getOptionalValue().ifPresent(value -> {
                if (minDateTime.isAfter(value)) {
                    minDatetimePicker.setValue(minDateTime);
                }
            });
        });

        FormLayout appointForm = new FormLayoutFactory().visible(false).style("padding-top", "1em")
                .formItem(minDatetimePicker, "开始时间:").formItem(maxDatetimePicker, "结束时间:")
                .widthFull().componentFullWidth().formItemAlignEnd().formItemAlignVerticalCenter().get();

        content(createTimeSelector(appointForm), appointForm);

        Optional.ofNullable(defaultSelectName).ifPresent(value -> {
            Optional.ofNullable(buttonMap.get(value)).ifPresent(Button::clickInClient);
            Optional.ofNullable(timeRangeSupplierMap.get(value)).ifPresent(this::setTimeRangeSupplier);
        });


        AtomicReference lastSelectRangeSupplier = new AtomicReference<>(timeRangeSupplier);

        addButton(FluentButton.cancelButton().asFactory().clickListener(event -> {
            close();
            ITimeRangeSupplier timeRangeSupplier = lastSelectRangeSupplier.get();
            minDatetimePicker.setValue(timeRangeSupplier.getMin());
            maxDatetimePicker.setValue(timeRangeSupplier.getMax());
            selectButton(timeRangeSupplier.getName());
            appointForm.setVisible("自定义".equals(timeRangeSupplier.getName()));
        }).get());
        addButton(new FluentButton(VaadinIcon.CHECK, "确定", this::processSave).primary());

        title("选择时间").width("720px", "720px", "90vw").setMinHeight("350px");

        addSaveListeners(e -> doMemory());
        addSaveListeners(e -> lastSelectRangeSupplier.set(getTimeRangeSupplier()));
        doRestore();

        refreshStatusField();

        return this;
    }

    public TimeRangeDialog write(QueryParameterBuilder builder) {
        Function function = d -> d.toEpochSecond(ZoneOffset.ofHours(8));
        builder.add("minDatetime", function.apply(getMin()));
        builder.add("maxDatetime", function.apply(getMax()));
        builder.add("time-range", URLEncoder.encode(getTimeRangeSupplier().getName(), StandardCharsets.UTF_8));
        return this;
    }

    public TimeRangeDialog read(QueryParameterUtil util) {
        if (util.decode("time-range") != null || (util.get("minDatetime") != null && util.get("maxDatetime") != null)) {
            setValue(Optional.ofNullable(util.decode("time-range"))
                    .map(timeRange -> "自定义".equals(timeRange) ? null : timeRange)
                    .map(timeRangeSupplierMap::get).orElse(createTimeRangeSupplier(util)));
        }
        refreshStatusField();
        return this;
    }

    public TimeRangeDialog setValue(ITimeRangeSupplier timeRangeSupplier) {
        if (timeRangeSupplier == null) return this;
        this.timeRangeSupplier = timeRangeSupplier;
        refreshStatusField();
        selectButton(timeRangeSupplier.getName());
        return this;
    }

    public TimeRangeDialog setValue(String timeRangeSupplier) {
        try {
            timeRangeSupplier = URLDecoder.decode(timeRangeSupplier, StandardCharsets.UTF_8);
        } catch (Exception ignore) {
        }
        return this.setValue(timeRangeSupplierMap.get(timeRangeSupplier));
    }

    private void selectButton(String name) {
        buttonMap.values().forEach(a -> a.removeThemeVariants(LUMO_PRIMARY));
        Optional.ofNullable(buttonMap.getOrDefault(name, buttonMap.get("自定义")))
                .ifPresent(a -> a.addThemeVariants(LUMO_PRIMARY));
    }

    public TimeRangeDialog today() {
        this.timeRangeSupplier = TimeRangeSupplier.appoint(
                LocalDateTime.of(LocalDate.now(), LocalTime.MIN),
                LocalDateTime.of(LocalDate.now(), LocalTime.MAX), "今天");
        minDatetimePicker.setValue(timeRangeSupplier.getMin());
        maxDatetimePicker.setValue(timeRangeSupplier.getMax());
        refreshStatusField();
        return this;
    }

    public TimeRangeDialog recentOneDay() {
        Optional.ofNullable(buttonMap.get("最近一天")).ifPresent(Button::clickInClient);
        return this;
    }

    public TimeRangeDialog init(QueryParameterUtil util) {
        this.timeRangeSupplier = createTimeRangeSupplier(util);
        refreshStatusField();
        return this;
    }

    private void processSave(ClickEvent




© 2015 - 2025 Weber Informatics LLC | Privacy Policy