/**
 * 走influxdb版本的，不抽稀通过zoom和unit传空字符串实现； 非influxdb版本的接口，使用isDilute=false实现；
 * 建议：不抽稀的时候，传isDilute=false&zoom=''&unit=''
 * @changelog
 *  2024年12月10日
 *  1. 时间选择增加简易模式。通过时间选择器后的按钮，进行模式切换；简易模式下，选择时间简便，双击即可选中某一天；常规模式下，时间会附带时分秒。
 *  2. 修改了组件代码，修复了markpoint异常渲染的问题；修改了markpoint生成、检测边距的代码。
 */
import React, {useContext, useEffect, useMemo, useState, useCallback, useRef} from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import {
    Checkbox,
    ConfigProvider,
    DatePicker,
    Radio,
    Select,
    Spin,
    Tabs,
    Tooltip,
    Button,
    message,
    Progress,
    Input,
} from 'antd';
import {
    CloseCircleFilled,
    PlusCircleOutlined,
    QuestionCircleFilled,
    DownloadOutlined,
    SwapOutlined,
} from '@ant-design/icons';
import moment from 'moment';
import _, {cloneDeep} from 'lodash';
import TimeRangePicker from '@wisdom-components/timerangepicker';
import PandaEmpty from '@wisdom-components/empty';
import {
    getHistoryInfo,
    getDeviceAlarmScheme,
    getExportDeviceHistoryUrl,
    getDictionaryInfoAll,
    getPointAddress,
    getPointAddressEntry,
    getPredicateSensor,
    searchDataDictionaryList,
    getDataDictionaryList,
} from './apis';
import SingleChart from './SingleChart';
import GridChart from './GridChart';
import BIStyles from './indexForBI.less';
import {globalConfig} from 'antd/lib/config-provider';
import {getSensorType} from './apis/index';
import {ExportExcel} from '@wisdom-components/exportexcel';

import VirtualTable from './VirtualTable';

const {RangePicker} = DatePicker;
const {Option} = Select;

const startFormat = 'YYYY-MM-DD 00:00:00';
const endFormat = 'YYYY-MM-DD 23:59:59';
const timeFormat = 'YYYY-MM-DD HH:mm:ss';
const dateFormat = 'YYYYMMDD';

const timeList = [
    {
        key: 'twelveHours',
        name: '近12小时',
    },
    {
        key: 'roundClock',
        name: '近24小时',
    },
    {
        key: 'yesterday',
        name: '昨日',
    },
    {
        key: 'oneWeek',
        name: '近1周',
    },
    {
        key: 'oneMonth',
        name: '近1月',
    },
];
const predicateMap = {
    twelveHours: 12,
    roundClock: 24,
    oneWeek: 24,
    oneMonth: 24,
};

// 同期对比 日 快捷按钮
const shortcutsForDay = [
    {
        label: '近3天',
        value: '近3天',
    },
    {
        label: '近7天',
        value: '近7天',
    } /*    {
                label: '去年同期',
                value: '去年同期',
            }*/,
];
// 同期对比 月 快捷按钮
const shortcutsForMonth = [
    {
        label: '近3月',
        value: '近3月',
    },
    {
        label: '近6月',
        value: '近6月',
    } /*    {
                label: '去年同期',
                value: '去年同期',
            }*/,
];

const CheckboxData = [
    {
        key: 'curveCenter',
        label: '曲线居中',
        checked: false,
        showInCurve: true,
        showInTable: false,
    },
    {
        key: 'chartGrid',
        label: '图表网格',
        checked: true,
        showInCurve: true,
        showInTable: false,
    },
    {
        key: 'ignoreOutliers',
        label: '去除异常值',
        type: 'updateIgnoreOutliers',
        checked: false,
        showInCurve: true,
        showInTable: true,
        tooltip: '采用递推平均滤波法（滑动平均滤波法）对采样数据中的异常离群值进行识别与去除。',
        hasSub: true,
    },
    {
        key: 'dataThin',
        label: '数据抽稀',
        type: 'updateDataThin',
        checked: true,
        showInCurve: false,
        showInTable: true,
    },
];

const timeIntervalList = [
    {
        key: '1min',
        zoom: '1',
        unit: 'min',
        name: '1分钟',
    },
    {
        key: '5',
        zoom: '5',
        unit: 'min',
        name: '5分钟',
    },
    {
        key: '10',
        zoom: '10',
        unit: 'min',
        name: '10分钟',
    },
    {
        key: '30',
        zoom: '30',
        unit: 'min',
        name: '30分钟',
    },
    {
        key: '1',
        zoom: '1',
        unit: 'h',
        name: '1小时',
    },
    {
        key: '2',
        zoom: '2',
        unit: 'h',
        name: '2小时',
    },
    {
        key: '4',
        zoom: '4',
        unit: 'h',
        name: '4小时',
    },
    {
        key: '6',
        zoom: '6',
        unit: 'h',
        name: '6小时',
    },
    {
        key: '12',
        zoom: '12',
        unit: 'h',
        name: '12小时',
    },
    {
        key: '24',
        zoom: '24',
        unit: 'h',
        name: '24小时',
    },
];

const handleTimeForPredicate = (key, start, end) => {
    let t = predicateMap[key] || 0;
    return moment(end).add(t, 'hours').format(timeFormat);
};
const updateTime = (key, predicate) => {
    let start = '';
    let end = '';

    if (Array.isArray(key)) {
        start = moment(key[0]).format(timeFormat);
        end = moment(key[1]).format(timeFormat);
    } else {
        switch (key) {
            case 'twelveHours':
                start = moment().subtract(12, 'hour').format(timeFormat);
                end = moment().format(timeFormat);
                break;
            case 'roundClock':
                start = moment().subtract(24, 'hour').format(timeFormat);
                end = moment().format(timeFormat);
                break;
            case 'yesterday':
                start = moment().subtract(1, 'days').format('YYYY-MM-DD 00:00:00');
                end = moment().subtract(1, 'days').format('YYYY-MM-DD 23:59:59');
                break;
            case 'oneWeek':
                start = moment().subtract(7, 'day').format(timeFormat);
                end = moment().format(timeFormat);
                break;
            case 'oneMonth':
                start = moment().subtract(30, 'day').format(timeFormat);
                end = moment().format(timeFormat);
                break;
        }
    }

    if (predicate) {
        end = handleTimeForPredicate(key, end);
    }
    return [
        {
            dateFrom: start,
            dateTo: end,
        },
    ];
};

const DefaultDatePicker = (value) => [
    {
        key: 1,
        value: moment(),
    },
    {
        key: 2,
        value: moment().subtract(1, value),
    },
];

const handleBatchTime = (arr, cOption) => {
    let newArr = [];
    arr.forEach((child) => {
        if (child.value) {
            newArr.push({
                dateFrom: moment(child.value).startOf(cOption).format(startFormat),
                dateTo: moment(child.value).endOf(cOption).format(endFormat),
            });
        }
    });
    newArr = _.uniqWith(newArr, _.isEqual); // 去掉重复日期时间
    return newArr;
};
const handleFakeData = (dateRange, deviceParams) => {
    if (!dateRange?.length) return;
    let dateFrom = dateRange[0].dateFrom;
    let dateTo = dateRange[0].dateTo;
    return deviceParams.reduce((final, cur) => {
        let _arr = cur.sensors.split(',');
        _arr.forEach((sensor) => {
            final.push({
                dataModel: [
                    {pt: dateFrom, pv: null},
                    {pt: dateTo, pv: null},
                ],
                dateFrom,
                dateTo,
                deviceCode: cur.deviceCode,
                deviceType: cur.deviceType,
                sensorName: sensor,
                equipmentName: '',
                stationCode: cur.deviceCode,
            });
        });
        return final;
    }, []);
};
const timeColumn = {
    title: '采集时间',
    dataIndex: 'time',
    key: 'time',
    width: 170,
    ellipsis: true,
    align: 'center',
    sorter: true, // sortOrder:['descend','ascend']
};
const OriginMaxDays = 31; // 原始曲线请求数据的最大天数
const CharacteristicMaxDays = null; // 特征曲线或者其他曲线的最大天数
const HistoryView = (props) => {
    const [completeInit, setCompleteInit] = useState(false);
    const {getPrefixCls} = useContext(ConfigProvider.ConfigContext);
    const prefixCls = getPrefixCls('history-view');
    const {
        title,
        grid,
        defaultChecked,
        tableProps,
        deviceParams,
        defaultModel,
        showModels,
        needMarkLine,
        defaultDate,
        theme = 'Normal',
        defaultDateRange = []
    } = props;
    if (theme === 'Normal') import('./index.less');
    if (theme === 'BI') import('./indexForBI.less');
    const isBoxPlots =
        deviceParams?.length === 1 && deviceParams?.[0]?.sensors?.split(',').length === 1;
    const [loading, setLoading] = useState(null);
    const [activeTabKey, setActiveTabKey] = useState(defaultModel);

    // 时间模式: 自定义模式/同期对比模式
    const [timeValue, setTimeValue] = useState('customer');

    // 自定义模式
    const [customerChecked, setCustomerChecked] = useState(defaultChecked); // 时间快速选择类型值
    const [customerTime, setCustomerTime] = useState(); // 自定义时间选择值

    // 同期对比模式
    const [contrastOption, setContrastOption] = useState('day'); // 对比时间类型: 日/月
    const [datePickerArr, setDatePickerArr] = useState(DefaultDatePicker(defaultDate)); // 对比时间段配置值
    const [checkboxData, setCheckboxData] = useState(() => [...CheckboxData]); // 曲线设置项
    const [dataThinKey, setDataThinKey] = useState(
        timeIntervalList[0].key === '1min' ? timeIntervalList[1].key : timeIntervalList[0].key,
    ); // 曲线抽稀时间设置
    const [algorithmValue, setAlgorithmValue] = useState(1);

    const [columns, setColumns] = useState([]);
    const [tableData, setTableData] = useState([]);
    const [timeOrder, setTimeOrder] = useState('descend');
    const [chartType, setChartType] = useState('lineChart');
    const [showBoxOption, setShowBoxOption] = useState(true);
    const [lineDataType, setLineDataType] = useState('特征曲线');
    // 同期对比快捷键
    // shortcutsValue
    // onShortcutsChange
    const [shortcutsValue, setShortcutsValue] = useState('');
    const [shortcutsDatePickerArr, setShortcutsDatePickerArr] = useState([]);
    const [percent, setPercent] = useState(0);
    // 频率指标特殊业务
    const [special1, setSpecial1] = useState(null);
    const [allPointAddress, setAllPointAddress] = useState([]);
    //查询所有sensorType
    const [allSensorType, setAllSensorType] = useState([]);
    const [isSingleStatusSensor, setIsSingleStatusSensor] = useState(false);
    const [predicateDevice, setPredicateDevice] = useState(null);
    const [predicateData, setPredicateData] = useState([]);
    const [predicateTime, setPredicateTime] = useState(null);

    const timePanelOpen = useRef({
        open: false,
        dateRange: []
    });
    // 需要处理默认数据，确保图表能够一直显示坐标轴。用来存储当前的请求状态。
    const emptyOrError = useRef({
        empty: true,
        error: true,
    });
    // 这部分功能有问题，等待解决后上线 2024年3月13日
    const [discreteDeviceType, setDiscreteDeviceType] = useState(['水厂']);
    const [timeFormatter, setTimeFormatter] = useState('简易模式'); // 常规模式 YYYY-MM-DD HH:mm 简易模式 YYYY-MM-DD
    // 历史数据相关的特征描述
    const deviceConfig = useRef({
        oneDevice: deviceParams.length === 1, //单设备
        oneSensor:
            [
                ...new Set(
                    deviceParams.reduce((final, cur) => {
                        let _sensors = cur.sensors.split(',');
                        return final.concat(_sensors);
                    }, []),
                ),
            ].length === 1, // 单指标
    });
    // 表格虚拟列表
    const tableRef = useRef();
    // 选择的时间范围值
    const dateRange = useMemo(() => {
        if (timeValue === 'customer') {
            return updateTime(customerChecked || customerTime, predicateDevice);
        } else {
            let _dateArr = shortcutsValue ? shortcutsDatePickerArr : datePickerArr;
            return handleBatchTime(_dateArr, contrastOption);
        }
    }, [contrastOption, customerChecked, customerTime, datePickerArr, timeValue, shortcutsValue, shortcutsDatePickerArr]);
    useEffect(() => {
        let _diffDays = moment(dateRange[0].dateTo).diff(dateRange[0].dateFrom, 'days');
        if (_diffDays > 7 && dataThinKey === '1min') {
            setDataThinKey(timeIntervalList[1].key);
        }
    }, [dateRange]);
    const [dates, setDates] = useState(null);
    const [chartDataSource, setChartDataSource] = useState(
        handleFakeData(dateRange, deviceParams) ?? [],
    );
    const configDependence = checkboxData
        .filter((item) => ['curveCenter', 'chartGrid'].indexOf(item.key) === -1)
        .map((item) => item.checked)
        .join(',');
    // 数据配置
    const dataConfig = useMemo(() => {
        const initial = {
            ignoreOutliers: false,
            dataThin: false,
            zoom: '', // 数据抽稀时间
            unit: '', // 数据抽稀时间单位
        };
        // 曲线居中，过滤异常值，数据抽稀
        const config = checkboxData.reduce(
            (pre, item) => (item.key !== 'curveCenter' && item.key !== 'chartGrid' && (pre[item.key] = item.checked), pre),
            initial,
        );
        // 数据抽稀时间单位
        const dataThin = timeIntervalList.find((item) => item.key === dataThinKey);
        config.zoom = activeTabKey === 'curve' ? '' : dataThin?.zoom ?? '';
        config.unit = activeTabKey === 'curve' ? '' : dataThin?.unit ?? '';
        config.dataThin = activeTabKey === 'curve' ? true : config.dataThin; // 曲线强制抽稀

        return config;
    }, [configDependence, dataThinKey, activeTabKey, checkboxData]);

    // 图表居中
    const [curveCenter, chartGrid] = useMemo(() => {
        const curveCenter = checkboxData.find((item) => item.key === 'curveCenter')?.checked;
        const chartGrid = checkboxData.find((item) => item.key === 'chartGrid')?.checked;
        return [curveCenter, chartGrid];
    }, [checkboxData]);
    // 导出图表canvas
    const [exportFlag, setExportFlag] = useState(null);
    // 自定义模式: 快速选择
    const onCustomerTimeChange = (key) => {
        setCustomerChecked(key);
        setPredicateTime(predicateMap[key]);
        !!customerTime && setCustomerTime(null);
    };

    // 自定义模式: 自定义时间选择
    const onCustomerRangeChange = (value) => {
        if (!value) {
            // 时间清空，回到默认时间选择
            setCustomerChecked(defaultChecked);
            setCustomerTime(value);
        } else {
            setCustomerChecked(null);
            let diffDays = moment(value[1]).diff(moment(value[0]), 'days');
            if (diffDays > OriginMaxDays && lineDataType === '原始曲线') {
                setLineDataType('特征曲线');
                message.info('时间区间超过7天，已切换为特征曲线');
            }
            setCustomerTime(value);
        }
    };

    // 同期对比模式: 选择（日/月）
    const onContrastChange = (value) => {
        if (value === 'month') {
            if (lineDataType === '原始曲线')
                message.info('月模式数据量较大，不支持原始曲线模式，已切换为特征曲线');
            setLineDataType('特征曲线');
        }
        setShortcutsValue('');
        setContrastOption(value);
        // 模式为日时，默认对比时间根据defaultDate判断 是昨天、上月、还是去年
        setDatePickerArr([...DefaultDatePicker(value === 'day' && defaultDate ? defaultDate : value)]);
    };

    // 同期对比模式: 时间段选择
    const onContrastPickerChange = (date, dateString, item) => {
        // 操作时间就清除掉快捷键选用状态
        setShortcutsValue('');
        const arr = [...datePickerArr];
        arr.forEach((child) => {
            if (child.key === item.key) {
                child.value = date;
            }
        });
        setDatePickerArr(arr);
    };

    // 同期对比模式: 新增日期选择组件
    const handleAddDatePicker = () => {
        // 操作时间就清除掉快捷键选用状态
        setShortcutsValue('');
        setDatePickerArr([
            ...datePickerArr,
            {
                key: datePickerArr[datePickerArr.length - 1].key + 1,
                value: '',
            },
        ]);
    };

    // 同期对比模式: 删除日期选择组件
    const handleDeleteDatePicker = (index) => {
        // 操作时间就清除掉快捷键选用状态
        setShortcutsValue('');
        const arr = [...datePickerArr];
        arr.splice(index, 1);
        setDatePickerArr(arr);
    };

    // 时间设置切换（自定义/同期对比）
    const onTimeSetChange = (e) => {
        // 操作时间就清除掉快捷键选用状态
        setShortcutsValue('');
        if (e.target.value === 'customer') {
            setLineDataType('特征曲线');
            setShortcutsValue('');
        }
        setTimeValue(e.target.value);
        if (e.target.value === 'contrast') {
            // 同期对比
            onContrastChange(contrastOption);
            setShowBoxOption(false);
            setChartType('lineChart');
            onCheckboxChange({target: {value: false}}, 'chartType');
            onCheckboxChange({target: {value: false}}, 'ignoreOutliers');
        } else {
            // 自定义
            // 不需要处理
            setShowBoxOption(true);
            onCheckboxChange({target: {value: true}}, 'chartType');
        }
    };
    const onShortcutsChange = (e) => {
        let _val = e.target.value;
        setShortcutsValue(_val);
        let _arr = [];
        switch (_val) {
            case '近3天':
                _arr = [
                    {key: 1, value: moment()},
                    {key: 2, value: moment().subtract(1, 'days')},
                    {
                        key: 3,
                        value: moment().subtract(2, 'days'),
                    },
                ];
                break;
            case '近7天':
                _arr = [
                    {key: 1, value: moment()},
                    {key: 2, value: moment().subtract(1, 'days')},
                    {
                        key: 3,
                        value: moment().subtract(2, 'days'),
                    },
                    {key: 4, value: moment().subtract(3, 'days')},
                    {
                        key: 5,
                        value: moment().subtract(4, 'days'),
                    },
                    {key: 6, value: moment().subtract(5, 'days')},
                    {key: 7, value: moment().subtract(6, 'days')},
                ];
                break;
            case '近3月':
                _arr = [
                    {key: 1, value: moment()},
                    {key: 2, value: moment().subtract(1, 'months')},
                    {
                        key: 3,
                        value: moment().subtract(2, 'months'),
                    },
                ];
                break;
            case '近6月':
                _arr = [
                    {key: 1, value: moment()},
                    {key: 2, value: moment().subtract(1, 'months')},
                    {
                        key: 3,
                        value: moment().subtract(2, 'months'),
                    },
                    {key: 4, value: moment().subtract(3, 'months')},
                    {
                        key: 5,
                        value: moment().subtract(4, 'months'),
                    },
                    {key: 6, value: moment().subtract(5, 'months')},
                ];
                break;
        }
        setShortcutsDatePickerArr(_arr);
    };
    // 时间选择器
    const renderTimeOption = useMemo(() => {
        return (
            <div className={classNames(`${prefixCls}-date`)}>
                <div className={classNames(`${prefixCls}-label`)}>时间选择</div>
                <Radio.Group value={timeValue} onChange={onTimeSetChange}>
                    <Radio.Button value="customer">自定义</Radio.Button>
                    {!grid ? <Radio.Button value="contrast">同期对比</Radio.Button> : ''}
                </Radio.Group>
                {timeValue === 'customer' && ( // 自定义
                    <>
                        <TimeRangePicker
                            format={'YYYY-MM-DD HH:mm'}
                            onChange={onCustomerTimeChange}
                            value={customerChecked}
                            dataSource={timeList}
                        />
                        <Input.Group compact style={{width: 'unset'}}>
                            <RangePicker
                                getPopupContainer={(trigger) => trigger.parentElement}
                                format={timeFormatter === '简易模式' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm'}
                                className={classNames(`${prefixCls}-custime-customer`)}
                                onChange={onCustomerRangeChange}
                                value={customerTime}
                                onCalendarChange={(val) => {
                                    setDates(val);
                                }}
                                onOpenChange={(open) => {
                                    timePanelOpen.current.open = open;
                                    if (open) {
                                        setDates([null, null]);
                                    } else {
                                        setDates(null);
                                    }
                                }}
                                disabledDate={(current) => {
                                    if (timeValue !== 'customer') return false;
                                    let _days = lineDataType === '原始曲线' ? OriginMaxDays : CharacteristicMaxDays;
                                    if (!dates) {
                                        return false;
                                    }
                                    if (!_days) return false;
                                    const tooLate = dates[0] && current.diff(dates[0], 'days') > _days;
                                    const tooEarly = dates[1] && dates[1].diff(current, 'days') > _days;
                                    return !!tooEarly || !!tooLate;
                                }}
                                showTime={
                                    timeFormatter === '简易模式'
                                        ? false
                                        : {
                                            format: 'YYYY-MM-DD HH:mm',
                                            minuteStep: 10,
                                        }
                                }
                            />
                            <Button
                                style={{
                                    color: '#1980ff',
                                    cursor: 'pointer',
                                    textDecoration: 'underline',
                                    lineHeight: 1
                                }}
                                onClick={() => {
                                    let _type = timeFormatter === '常规模式' ? '简易模式' : '常规模式'
                                    setTimeFormatter(_type);
                                    let _date = dateRange[0];
                                    let _dateRange = [];
                                    if (_type === '常规模式') {
                                        _dateRange = [
                                            {
                                                dateFrom: moment(_date.dateFrom).format('YYYY-MM-DD HH:mm:ss'),
                                                dateTo: moment(_date.dateTo).format('YYYY-MM-DD HH:mm:ss'),
                                            },
                                        ];
                                    }
                                    if (_type === '简易模式') {
                                        _dateRange = [
                                            {
                                                dateFrom: moment(_date.dateFrom).format('YYYY-MM-DD 00:00:00'),
                                                dateTo: moment(_date.dateTo).format('YYYY-MM-DD 23:59:59'),
                                            },
                                        ];
                                    }
                                    timePanelOpen.current.dateRange = _dateRange;
                                }}
                            >
                                <Tooltip
                                    title={`切换至 ${
                                        timeFormatter === '常规模式'
                                            ? '【简易模式】：该模式取全天数据'
                                            : '【常规模式】：该模式取值时段可精确到分'
                                    }`}
                                >
                                    <SwapOutlined/>
                                </Tooltip>
                            </Button>
                        </Input.Group>
                    </>
                )}
                {timeValue === 'contrast' && ( // 同期对比
                    <>
                        <Select
                            value={contrastOption}
                            getPopupContainer={(trigger) => trigger.parentElement}
                            style={{width: 60}}
                            onChange={onContrastChange}
                        >
                            <Option value="day">日</Option>
                            <Option value="month" disabled={lineDataType === '原始曲线'}>
                                月
                            </Option>
                        </Select>
                        {/*增加快捷日期*/}
                        {deviceParams?.length === 1 && deviceParams?.[0]?.sensors?.split(',').length === 1 ? (
                            <Radio.Group value={shortcutsValue} onChange={onShortcutsChange}>
                                {(contrastOption === 'day' ? shortcutsForDay : shortcutsForMonth).map((item) => {
                                    return <Radio.Button value={item.value}>{item.label}</Radio.Button>;
                                })}
                            </Radio.Group>
                        ) : (
                            ''
                        )}
                        {datePickerArr.map((child, index) => (
                            <div key={child.key} className={classNames(`${prefixCls}-contrast-list`)}>
                                <div className={classNames(`${prefixCls}-contrast-wrap`)}>
                                    <DatePicker
                                        allowClear={false}
                                        getPopupContainer={(trigger) => trigger.parentElement}
                                        key={child.key}
                                        picker={contrastOption === 'day' ? undefined : contrastOption}
                                        value={child.value}
                                        onChange={(date, dateString) => onContrastPickerChange(date, dateString, child)}
                                        style={{width: 130, border: !shortcutsValue ? '1px solid #1890ff' : ''}}
                                    />
                                    {datePickerArr.length > 2 && (
                                        <div
                                            className={classNames(`${prefixCls}-contrast-delete`)}
                                            onClick={() => handleDeleteDatePicker(index)}
                                        >
                                            <CloseCircleFilled/>
                                        </div>
                                    )}
                                </div>
                                {index < datePickerArr.length - 1 && (
                                    <div className={classNames(`${prefixCls}-contrast-connect`)}>与</div>
                                )}
                            </div>
                        ))}
                        {datePickerArr.length < 4 && <PlusCircleOutlined onClick={handleAddDatePicker}/>}
                    </>
                )}
            </div>
        );
    }, [
        grid,
        timeValue,
        customerChecked,
        lineDataType,
        datePickerArr,
        deviceParams,
        dates,
        customerTime,
        chartDataSource,
        timeFormatter,
    ]);

    // 曲线设置项选择/取消
    const onCheckboxChange = (e, key, showJustLine) => {
        let data = [...checkboxData];
        let _index1 = data.findIndex((item) => item.key === 'ignoreOutliers'); // 仅查看曲线会在勾选了数据滤波后展示
        data.forEach((item) => {
            if (item.key === key) {
                item.checked = e.target.checked;
            }
        });
        if (key === 'ignoreOutliers') {
            data[_index1].showInCurve = true;
        }

        if (key === 'chartType') {
            data[_index1].showInCurve = e.target.value;
            data[_index1].checked = false;
            // data[_index].showInCurve = false;
            // data[_index].checked = false;
        }
        setCheckboxData(data);
    };

    // 数据抽稀时间间隔
    const onTimeIntervalChange = (value) => {
        setDataThinKey(value);
    };
    // 切换数据类型
    const switchLineDataType = (e) => {
        let _val = e.target.value;
        let _startDate = dateRange[0]?.dateFrom;
        let _endDate = dateRange[0]?.dateTo;
        let diffDays = moment(_endDate).diff(moment(_startDate), 'days');
        if (_val === '原始曲线' && diffDays > OriginMaxDays) {
            message.info('查阅原始曲线时，需选择小于或等于31天的时间间隔，已自动切换为近一月');
            setCustomerChecked('oneMonth');
        }
        if (_val === '原始曲线') {
            setContrastOption('day');
        }
        setLineDataType(_val);
    };
    const renderCheckbox = (child, showJustLine) => {
        const curveAccess = activeTabKey === 'curve' && child.showInCurve;
        const tableAccess = activeTabKey === 'table' && child.showInTable;
        const gridOptions = ['curveCenter'];

        if (grid && curveAccess && gridOptions.indexOf(child.key) === -1) return null;
        return (
            (curveAccess || tableAccess) && (
                <>
                    <Checkbox checked={child.checked} onChange={(e) => onCheckboxChange(e, child.key)}>
                        {child.label}
                    </Checkbox>
                    {child.tooltip && (
                        <Tooltip title={child.tooltip}>
                            <QuestionCircleFilled className={`${prefixCls}-question`}/>
                        </Tooltip>
                    )}
                    {child.hasSub && child.checked && false ? (
                        <Select
                            style={{width: 80, marginLeft: 10}}
                            value={algorithmValue}
                            onChange={(e) => setAlgorithmValue(e)}
                        >
                            <Option value={1}>低</Option>
                            <Option value={5}>中</Option>
                            <Option value={10}>高</Option>
                        </Select>
                    ) : (
                        ''
                    )}
                </>
            )
        );
    };

    // 渲染曲线选择、曲线设置的控件
    const renderCurveOption = (isChart, isSingle, isStatus) => {
        return (
            <div
                className={classNames(`${prefixCls}-cover`)}
                style={isChart && isSingle ? {width: '100%'} : {}}
            >
                {isChart && !isStatus ? (
                    <>
                        <div className={classNames(`${prefixCls}-label`)}>曲线选择</div>
                        <div className={`${prefixCls}-cover-item`}>
                            <Radio.Group value={lineDataType} onChange={switchLineDataType}>
                                <Radio.Button value={'特征曲线'}>特征曲线</Radio.Button>
                                <Radio.Button value={'原始曲线'}>原始曲线</Radio.Button>
                            </Radio.Group>
                            <Tooltip title={'原始曲线数据量较大，单次查询最多展示1万条数据'}>
                                <QuestionCircleFilled
                                    style={{marginLeft: 6}}
                                    className={`${prefixCls}-question`}
                                />
                            </Tooltip>
                        </div>
                    </>
                ) : (
                    ''
                )}
                {isChart && isSingle && showBoxOption && !isStatus && !grid ? (
                    <>
                        {lineDataType !== '原始曲线' ? (
                            <>
                                <div style={{marginLeft: 7}} className={classNames(`${prefixCls}-label`)}>
                                    曲线形态
                                </div>
                                <Radio.Group
                                    value={chartType}
                                    style={{marginRight: 16}}
                                    onChange={(e) => {
                                        let _value = e.target.value;
                                        setChartType(_value);
                                        onCheckboxChange({target: {value: _value !== 'boxChart'}}, 'chartType');
                                    }}
                                >
                                    <Radio.Button value={'lineChart'}>线形图</Radio.Button>
                                    <Radio.Button value={'boxChart'}>箱线图</Radio.Button>
                                </Radio.Group>
                            </>
                        ) : (
                            ''
                        )}
                    </>
                ) : (
                    ''
                )}
                {!isStatus ? (
                    <>
                        <div className={classNames(`${prefixCls}-label`)}>
                            {activeTabKey !== 'table' ? '曲线设置' : '表格设置'}
                        </div>
                        {checkboxData.map((child) => {
                            const box = renderCheckbox(child, isChart && isSingle);
                            if (!box) return null;
                            return (
                                <div key={child.key} className={`${prefixCls}-cover-item`}>
                                    {box}
                                </div>
                            );
                        })}
                        {activeTabKey === 'table' && (
                            <Select
                                value={dataThinKey}
                                style={{width: 90}}
                                onChange={onTimeIntervalChange}
                                disabled={!dataConfig.dataThin}
                                getPopupContainer={(trigger) => trigger.parentElement}
                            >
                                {timeIntervalList
                                    .filter((item) => {
                                        let _diffDays = moment(dateRange[0].dateTo).diff(dateRange[0].dateFrom, 'days');
                                        return !(_diffDays > 7 && item.key === '1min');
                                    })
                                    .map((child) => {
                                        return (
                                            <Option key={child.key} unit={child.unit} value={child.key}>
                                                {child.name}
                                            </Option>
                                        );
                                    })}
                            </Select>
                        )}
                    </>
                ) : (
                    ''
                )}
            </div>
        );
    };

    const exportFeatureBtn = () => {
        message.info('报表生成中，请稍后~');
        let _dataSource = tableData.sort((a, b) => {
            let _a = a.time;
            let _b = b.time;
            if (timeValue === 'contrast') {
                if (contrastOption === 'day') {
                    _a = `2000-01-01 ${a.time}:00`;
                    _b = `2000-01-01 ${b.time}:00`;
                }
                if (contrastOption === 'month') {
                    _a = `2000-01-${a.time}:00`;
                    _b = `2000-01-${b.time}:00`;
                }
            }
            return timeOrder === 'ascend' ? moment(_a) - moment(_b) : moment(_b) - moment(_a);
        });
        let _columns = [...columns];
        let timeFrom = dateRange?.[0]?.dateFrom || moment().format(startFormat);
        let timeTo = dateRange?.[0]?.dateTo || moment().format(timeFormat);
        let fileName = `特征数据-${moment(timeFrom).format(dateFormat)}至${moment(timeTo).format(
            dateFormat,
        )}`;
        let _dataIndex = [];
        let _titleWidth = [];
        let _title = _columns.map((item) => {
            _dataIndex.push(item.dataIndex);
            let _titleArr = [item.name, item.title];
            if (item.title.includes(item.name)) {
                _titleArr = [item.title];
            }
            let _titleStr = _titleArr.filter((item) => item).join('-');
            _titleWidth.push(_titleStr.length * 1);
            return _titleStr;
        });
        ExportExcel({
            name: fileName,
            content: [
                {
                    sheetData: _dataSource,
                    sheetFilter: _dataIndex,
                    sheetHeader: _title,
                    columnWidths: _titleWidth,
                },
            ],
        });
    };
    const exportCanvas = () => {
        setExportFlag(Math.random());
    };
    const handleTableData = useCallback(
        (data) => {
            // eslint-disable-next-line no-param-reassign
            // data = data.filter(item => item.sensorName !== '是否在线');
            const ignoreOutliers = checkboxData.find((item) => item.key === 'ignoreOutliers').checked;
            const dataIndexAccess = (dataItem, index) => {
                const {stationCode, sensorName} = dataItem;
                return `${stationCode}-${sensorName}-${index}`;
            };

            let format = timeFormat;
            if (timeValue === 'contrast') {
                format = contrastOption === 'day' ? '2020-01-01 HH:mm:00' : '2020-01-DD HH:mm:00';
            }
            // 判断是否是单设备，单设备则不显示设备名称
            // 处理表头数据
            const columnsData = data.map((item, index) => {
                const {stationCode, equipmentName, sensorName, unit, dataModel} = item;
                const dataIndex = dataIndexAccess(item, index);
                let _title = '';
                if (deviceConfig.current.oneDevice) {
                    _title = `${sensorName}${unit ? `(${unit})` : ''}`;
                } else {
                    _title = `${equipmentName}-${sensorName}${unit ? `(${unit})` : ''}`;
                }
                let col = {
                    title: _title,
                    dataIndex: dataIndex,
                    key: dataIndex,
                    ellipsis: true,
                    align: 'center',
                    width: 200,
                    name: equipmentName,
                };
                // 同期对比
                if (timeValue === 'contrast' && dataModel[0]) {
                    const time = item.dataModel[0]?.pt
                        ?.slice(0, contrastOption === 'day' ? 10 : 7)
                        ?.replace(/-/g, '');
                    col.title = `${equipmentName}-${sensorName}-${time}`;
                }
                return col;
            });

            // 格式化时间对齐数据, 生成行数
            const timeData = {};
            const buildDefaultData = (time) => {
                const obj = {key: time, time: time};
                data.forEach((item, index) => {
                    const dataIndex = dataIndexAccess(item, index);
                    obj[dataIndex] = '';
                    obj.name = item.equipmentName;
                });
                return obj;
            };
            data.forEach((item, index) => {
                const {stationCode, sensorName, dataModel} = item;
                dataModel &&
                dataModel.forEach((data) => {
                    const formatTime = moment(data.pt).format(format);

                    let time = formatTime;
                    if (timeValue === 'contrast') {
                        time = time.slice(contrastOption === 'day' ? 11 : 8, 16);
                    }

                    timeData[formatTime] = timeData[formatTime] || buildDefaultData(time);
                });
            });
            // 处理表格数据
            data.forEach((child, index) => {
                const {dataModel} = child;
                const dataIndex = dataIndexAccess(child, index);
                dataModel &&
                dataModel.forEach((value, j) => {
                    const formatTime = moment(value.pt).format(format);
                    const dataRow = timeData[formatTime];
                    if (dataRow) {
                        dataRow[dataIndex] = value.pv === null || value.pv === undefined ? '' : value.pv;
                    }
                });
            });
            const timeSort = (a, b) => {
                let aa = a,
                    bb = b;
                if (timeValue === 'contrast') {
                    aa = a.slice(contrastOption === 'day' ? 11 : 8, 16);
                    bb = b.slice(contrastOption === 'day' ? 11 : 8, 16);
                }
                return timeOrder === 'descend' ? -aa.localeCompare(bb) : aa.localeCompare(bb);
            };
            const times = Object.keys(timeData).sort(timeSort);
            const tableData = times.map((time) => timeData[time]);
            setColumns([timeColumn, ...columnsData]);
            setTableData(tableData);
        },
        [timeOrder, timeValue, contrastOption],
    );

    const [deviceAlarmSchemes, setDeviceAlarmSchemes] = useState([]);
    const beforChangeParams = (value = {}) => {
        // 不需要报警标线 或者 多曲线、多设备时不显示报警标线
        let _lengthEqual0 = deviceParams?.length === 0;
        let _lengthEqual1 = deviceParams?.length === 1;
        let _lengthMoreThan1 = deviceParams?.length > 1;
        let returnNothing =
            !needMarkLine ||
            _lengthEqual0 ||
            _lengthMoreThan1 ||
            (_lengthEqual1 && deviceParams[0].sensors.split(',').length > 1);
        if (returnNothing) return Promise.resolve();
        return getDeviceAlarmScheme({
            data: deviceParams.map((item) => ({
                deviceType: item.deviceType,
                deviceCode: item.deviceCode,
                pointAddressID: item.pointAddressID,
                sensorName: item.sensors,
            })),
        })
            .then((res) => {
                if (res.code === 0) setDeviceAlarmSchemes(res.data || []);
                else setDeviceAlarmSchemes([]);
                return Promise.resolve();
            })
            .catch((err) => {
                setDeviceAlarmSchemes([]);
                return Promise.resolve();
            });
    };
    const handleDataThinKey = (diffYears, diffDays, diffHours, lineDataType) => {
        if (lineDataType === '原始曲线') {
            return {unit: '', zoom: ''};
        }
        // edit by zy 根据选择的时长控制抽稀频度
        if (diffYears > 0) {
            if (diffYears === 1) return {unit: 'h', zoom: '24'};
            return {unit: 'h', zoom: '48'};
        } else if (diffYears === 0 && diffDays > 0) {
            if (diffDays > 90) return {unit: 'h', zoom: '24'};
            if (diffDays > 30) return {unit: 'h', zoom: '4'};
            if (diffDays > 15) return {unit: 'h', zoom: '2'};
            if (diffDays > 7) return {unit: 'h', zoom: '1'};
            if (diffDays > 3) return {unit: 'min', zoom: '20'};
            if (diffDays > 1) return {unit: 'min', zoom: '15'};
            if (diffDays === 1) return {unit: 'min', zoom: '5'};
        } else if (diffYears === 0 && diffDays === 0 && diffHours > 0) {
            if (diffHours > 12) return {unit: 'min', zoom: '5'};
            if (diffHours > 4) return {unit: 'min', zoom: '1'};
            if (diffHours > 1) return {unit: 's', zoom: '30'};
            if (diffHours > 0) return {unit: 's', zoom: '5'};
            return {unit: 's', zoom: '5'};
        } else {
            return {unit: '', zoom: ''};
        }
    };

    // 处理接口服务参数的变化
    const onChangeParams = (value = {}) => {
        const {dateRange, isDilute, ignoreOutliers, zoom, unit} = value;
        let _diffDays = moment(dateRange[0].dateTo).diff(dateRange[0].dateFrom, 'days');
        // 查询时段大于7天时，不提供1分钟的抽稀选项。
        if (_diffDays > 7 && zoom === '1' && unit === 'min') {
            return false;
        }
        const requestArr = [];
        const acrossTables = [];
        const zoomArray = [];
        // 这部分功能有问题，等待解决后上线 2024年3月13日
        let hasDiscreteDeviceType = false;
        deviceParams
            .map((item) => {
                let _item = {...item};
                _item.sensors = item.sensors;
                // special 业务
                if (special1) {
                    _item.sensors += `,${special1.name}`;
                }
                return _item;
            })
            .forEach((i) => {
                if (i.sensors && i.deviceCode) acrossTables.push(_.omit(i, ['pointAddressID']));
                // 这部分功能有问题，等待解决后上线 2024年3月13日
                if (discreteDeviceType.includes(i.deviceType)) {
                    hasDiscreteDeviceType = true;
                }
            });
        if (!acrossTables?.length || !dateRange.length) {
            handleTableData([]);
            setChartDataSource([]);
            return;
        }
        dateRange.forEach((item) => {
            const param = {
                isDilute,
                zoom,
                unit,
                ignoreOutliers,
                dateFrom: item.dateFrom,
                dateTo: item.dateTo,
                acrossTables,
                isBoxPlots: isBoxPlots,
            };
            let diffYears = moment(item.dateTo).diff(moment(item.dateFrom), 'years');
            let diffDays = moment(item.dateTo).diff(moment(item.dateFrom), 'days');
            let diffHours = moment(item.dateTo).diff(moment(item.dateFrom), 'hours');
            let zoomParam =
                activeTabKey === 'curve'
                    ? handleDataThinKey(diffYears, diffDays, diffHours, lineDataType)
                    : !isDilute
                        ? {
                            zoom: '',
                            unit: '',
                        }
                        : {}; // 表格也支持全数据模式；
            let _finalParams = {...param, ...zoomParam};
            // 2024年1月8日 抽稀间隔大于等于12小时时，会存在线性插值导致抽稀间隔内数据条数大于预期的问题。需要增加一个额外参数处理该情况。
            if (_finalParams.zoom) {
                let _num = Number(_finalParams.zoom);
                let _isNaN = isNaN(_num);
                if (!_isNaN && _num >= 12) _finalParams.isInterpolation = false;
            }
            // 2024年1月23日 增加预测曲线，单设备单曲线
            // 同期对比不允许、多设备的不允许预测
            if (dateRange.length === 1 && predicateDevice) {
                _finalParams.acrossTables.push(predicateDevice);
            }
            // 2024年3月11日 如果设备是某些特殊设备，则采用离散型算法
            // 这部分功能有问题，等待解决后上线 2024年3月13日
            if (hasDiscreteDeviceType && ignoreOutliers) {
                _finalParams.algorithmName = 'derivative';
            }
            requestArr.push(getHistoryInfo(_finalParams));
        });
        setLoading(true);
        Promise.all(requestArr)
            .then((results) => {
                setLoading(false);
                emptyOrError.current.error = false;
                if (results.length) {
                    let data = [];
                    results.forEach((res, index) => {
                        const {dateFrom, dateTo} = dateRange?.[index] ?? {};
                        if (res.code === 0 && res.data.length) {
                            res.data.forEach((d) => {
                                d.dateFrom = dateFrom || '';
                                d.dateTo = dateTo || '';
                                /**
                                 * @date: 2023年10月25日
                                 * @description: 数据连续补点之后，首值、尾值、最大值、最小值不会补，都为null。
                                 *     为保证显示，将补点之后的数据的首值、尾值、最大值、最小值同时为null的情况变更为点的值。
                                 *
                                 *
                                 *     请注意，此项为重要变更，此变更会影响原始数据。
                                 */
                                // d.dataModel=[];
                                d.dataModel = d.dataModel.map((item) => {
                                    let {firstPV, lastPV, maxPV, minPV, pv} = item;
                                    if (
                                        pv !== null &&
                                        firstPV === null &&
                                        lastPV === null &&
                                        maxPV === null &&
                                        minPV === null
                                    ) {
                                        firstPV = pv;
                                        lastPV = pv;
                                        maxPV = pv;
                                        minPV = pv;
                                    }
                                    return {
                                        ...item,
                                        firstPV,
                                        lastPV,
                                        maxPV,
                                        minPV,
                                    };
                                });
                            });
                            // 加入预测
                            (predicateDevice ? deviceParams.concat(predicateDevice) : deviceParams).forEach(
                                (p) => {
                                    // 返回数据按查询指标顺序排序
                                    const sensors = p.sensors?.split(',') ?? [];
                                    if (sensors?.length) {
                                        sensors.push('是否在线');
                                        if (special1) {
                                            sensors.push(special1.name);
                                        }
                                    }
                                    const list = sensors
                                        .map((s) => {
                                            const dataItem = res.data.find(
                                                (d) => d.stationCode === p.deviceCode && d.sensorName === s,
                                            );
                                            if (dataItem) {
                                                dataItem.dateFrom = dateFrom || '';
                                                dataItem.dateTo = dateTo || '';
                                                dataItem.deviceType = p.deviceType;
                                                return dataItem;
                                            } else {
                                                return {};
                                            }
                                        })
                                        .filter((item) => item.sensorName);
                                    // 预测的
                                    data = data.concat(list);
                                    // _predicateData = _predicateData.concat(list.filter(item => item.deviceType === '预测'));
                                },
                            );
                        }
                    });
                    setLoading(false);

                    if (data.length !== 0) {
                        emptyOrError.current.empty = false;
                    } else {
                        data = handleFakeData(dateRange, deviceParams) ?? [];
                    }
                    handleTableData(data);
                    setChartDataSource(data);
                    // setPredicateData(_predicateData);
                }
            })
            .catch((err) => {
                let data = handleFakeData(dateRange, deviceParams) ?? [];
                handleTableData(data);
                setChartDataSource(data);
                message.info('未查询到数据，请重试~');
                setLoading(false);
            });
    };
    //
    const requestData = () => {
        const {dataThin, ignoreOutliers, zoom, unit} = dataConfig;
        // 简易模式下，在获取到时间参数后，将时间修改为 00:00:00 - 23:59:59
        let _dateRange = cloneDeep(dateRange);
        if (timeFormatter === '简易模式' && !customerChecked && timeValue === 'customer') {
            let _date = dateRange[0];
            _dateRange = [
                {
                    dateFrom: moment(_date.dateFrom).format('YYYY-MM-DD 00:00:00'),
                    dateTo: moment(_date.dateTo).format('YYYY-MM-DD 23:59:59'),
                },
            ];
        }
        beforChangeParams().finally(() => {
            onChangeParams({
                isDilute: dataThin,
                ignoreOutliers,
                zoom,
                unit,
                dateRange: _dateRange,
                isBoxPlots: isBoxPlots,
            });
        });
        // 每次请求结束后，更新dateRange.
        timePanelOpen.current.dateRange = _dateRange;
    };

    /**@impotant 切换简易模式、常规模式时：如果是自定义时间，重新请求数据，否则不进行重新请求。*/
    useEffect(() => {
        if (!completeInit || customerChecked) return;
        requestData()
    }, [timeFormatter]);

    /**@important 关闭时间选择器的弹窗时，如果开始时间或者结束时间已经变化那么则会重新请求数据*/
    useEffect(() => {
        let _dateRange = cloneDeep(dateRange);
        if (timeFormatter === '简易模式' && !customerChecked) _dateRange = _dateRange.map(item => ({
            dateFrom: moment(item.dateFrom).format('YYYY-MM-DD 00:00:00'),
            dateTo: moment(item.dateTo).format('YYYY-MM-DD 23:59:59'),
        }))
        if (!completeInit || timePanelOpen.current.open || _.isEqual(timePanelOpen.current.dateRange, _dateRange)) return;
        requestData()
    }, [timePanelOpen.current.open]);

    /**@import 监听值的变化，进行重新请求*/
    useEffect(() => {
        let _dateRange = cloneDeep(dateRange);
        if (timeFormatter === '简易模式' && !customerChecked) _dateRange = _dateRange.map(item => ({
            dateFrom: moment(item.dateFrom).format('YYYY-MM-DD 00:00:00'),
            dateTo: moment(item.dateTo).format('YYYY-MM-DD 23:59:59'),
        }))
        if (!completeInit || timePanelOpen.current.open) return;
        requestData()
    }, [lineDataType, chartType, dateRange, JSON.stringify(dataConfig), deviceParams, completeInit, algorithmValue]);

    const handleChange = (pagination, filter, sort) => {
        if (sort.field === 'time') {
            setTimeOrder(sort.order);
        }
    };
    const tablePanelMemo = useMemo(() => {
        return <div className={`${prefixCls}-options`}>
            {renderTimeOption}
            {renderCurveOption()}
        </div>
    }, [renderTimeOption, prefixCls, checkboxData, lineDataType]);
    const tableMemo = useMemo(() => {
        return (
            <>
                {tablePanelMemo}
                <div className={`${prefixCls}-content`} data-key={'table'} ref={tableRef}>
                    {chartDataSource.length > 0 ? ( // <BasicTable
                        <VirtualTable
                            className={`${prefixCls}-virtual-table`}
                            theme={theme}
                            dataSource={tableData.sort((a, b) => {
                                let _a = a.time;
                                let _b = b.time;
                                if (timeValue === 'contrast') {
                                    if (contrastOption === 'day') {
                                        _a = `2000-01-01 ${a.time}:00`;
                                        _b = `2000-01-01 ${b.time}:00`;
                                    }
                                    if (contrastOption === 'month') {
                                        _a = `2000-01-${a.time}:00`;
                                        _b = `2000-01-${b.time}:00`;
                                    }
                                }
                                return timeOrder === 'ascend' ? moment(_a) - moment(_b) : moment(_b) - moment(_a);
                            })}
                            columns={columns}
                            tableProps={tableProps}
                            pagination={false}
                            onChange={handleChange}
                            // scroll={{ x: 'max-content', y: 'calc(100% - 40px)' }}
                            scroll={{
                                x: 'max-content',
                                y: tableRef.current ? tableRef.current.getBoundingClientRect().height - 40 : 0,
                            }}
                        />
                    ) : (
                        <PandaEmpty/>
                    )}
                </div>
            </>
        );
    }, [
        timeOrder,
        chartDataSource,
        columns,
        tableProps,
        tableData,
        isSingleStatusSensor,
        dateRange,
        tableRef.current,
        timeFormatter,
        prefixCls
    ]);

    const returnLongestPeriod = (data) => {
        let _earliest = '';
        let _latest = '';
        data.forEach((item) => {
            let _length = item.dataModel.length;
            let _tempFirst = item.dataModel[0].pt;
            let _tempLast = item.dataModel[_length - 1].pt;
            if (_earliest) {
                _earliest = moment(_earliest) > moment(_tempFirst) ? _tempFirst : _earliest;
            } else {
                _earliest = _tempFirst;
            }
            if (_latest) {
                _latest = moment(_latest) < moment(_tempLast) ? _tempLast : _latest;
            } else {
                _latest = _tempLast;
            }
        });
        return `${_earliest} - ${_latest}`;
    };

    const curvePanelMemo = useMemo(() => {
        return (
            <>
                <div className={`${prefixCls}-options`}>
                    {renderTimeOption}
                    {renderCurveOption(
                        true,
                        deviceParams?.length === 1 && deviceParams?.[0]?.sensors?.split(',').length === 1,
                        isSingleStatusSensor,
                    )}
                </div>
                {lineDataType === '原始曲线' && false ? (
                    <div style={{marginTop: 10}}>展示区间：{returnLongestPeriod(chartDataSource)}</div>
                ) : (
                    ''
                )}
            </>
        );
    }, [renderTimeOption, deviceParams, isSingleStatusSensor, lineDataType, chartDataSource, checkboxData]);
    const gridMemo = useMemo(() => <div className={`${prefixCls}-content`}><GridChart
        emptyOrError={emptyOrError.current}
        curveCenter={curveCenter}
        prefixCls={prefixCls}
        dataSource={chartDataSource}
        contrast={timeValue === 'contrast'}
        contrastOption={contrastOption}
        deviceAlarmSchemes={deviceAlarmSchemes}
        dateRange={dateRange}
        allPointAddress={allPointAddress}
        allSensorType={allSensorType}
        loading={loading}
        setLoading={setLoading}
    />
    </div>, [prefixCls, grid, emptyOrError, curveCenter, chartDataSource, timeValue, contrastOption, deviceAlarmSchemes, dateRange, allPointAddress, allSensorType, loading, setLoading]);
    const singleMemo = useMemo(() => <div className={`${prefixCls}-content`}><SingleChart
        exportCanvas={{exportFlag, setExportFlag}}
        emptyOrError={emptyOrError.current}
        dateRange={dateRange}
        showBoxOption={showBoxOption}
        lineDataType={lineDataType}
        curveCenter={curveCenter}
        showGridLine={chartGrid}
        prefixCls={prefixCls}
        dataSource={chartDataSource}
        predicateData={predicateData}
        chartType={isBoxPlots ? chartType : null}
        contrast={timeValue === 'contrast'}
        contrastOption={contrastOption}
        deviceAlarmSchemes={deviceAlarmSchemes}
        theme={theme}
        special={{
            special1, // 频率业务
            allPointAddress,
            allSensorType, // 后续新增的开关量的特殊业务，用来处理开关量业务
        }}
    /></div>, [
        exportFlag, emptyOrError, dateRange, showBoxOption, lineDataType, curveCenter, chartGrid, prefixCls, chartDataSource,
        predicateData, isBoxPlots, chartType, timeValue, contrastOption, deviceAlarmSchemes,
        theme, special1, allPointAddress, allSensorType
    ]);
    const renderChartMemo = useMemo(() => {
        return <>{grid === true ? (gridMemo) : (singleMemo)}</>
    }, [grid, gridMemo, singleMemo]);
    // 获取字段配置
    const getDefaultOptions = async () => {
        let _dictionaryList = await searchDataDictionaryList({key: '组件_ec_historyview', type: 0});
        let _item = _dictionaryList?.data?.[0] ?? {};
        let _nodeID =
            _item?.nodeName === '组件_ec_historyview' ? _dictionaryList?.data?.[0]?.nodeID : null;
        // 非单曲线、单指标不执行
        if (
            deviceParams?.length !== 1 ||
            (deviceParams?.length === 1 && deviceParams?.[0]?.sensors?.split(',')?.length > 1)
        )
            return setCompleteInit(true);
        setLoading(true);
        const {deviceCode, deviceType, sensors} = deviceParams[0];
        let _id = (
            await getPointAddress({
                code: deviceCode,
            })
        )?.data?.[0]?.id;
        let _params = {};
        if (_id) _params.versionId = _id;
        // 多曲线的居中，容易导致曲线被截断，故多曲线时，不请求
        let _request0 = _nodeID
            ? getDataDictionaryList({
                nodeID: _nodeID,
            })
            : new Promise((resolve, reject) => {
                resolve();
            });
        // 以下请求为处理状态值、开关值的图表，只允许单曲线单指标情况下展示
        let _request1 = getPointAddressEntry(_params);
        let _request2 = getSensorType();
        await Promise.all([_request0, _request1, _request2]).then((result) => {
            if (result) {
                let _res0 = result[0];
                let _res1 = result[1];
                let _res2 = result[2];
                let _checkboxData = [...checkboxData];
                // 查字典配置
                if (_res0?.code === 0) {
                    let _opt = _res0.data.reduce((final, cur) => {
                        final[cur.nodeName] = cur.nodeValue;
                        return final;
                    }, {});
                    _checkboxData = _checkboxData.map((item) => {
                        let _item = {...item};
                        if (_opt[item.label] !== undefined) {
                            _item.checked = _opt[item.label] === 'true';
                        }
                        return _item;
                    });
                    setCheckboxData(_checkboxData);
                    // 大数据量设备类型，例如：水厂
                    let deviceType =
                        _res0.data.find((item) => item.nodeName === '离散算法设备类型')?.nodeValue ?? '';
                    setDiscreteDeviceType(deviceType.split(',').filter((item) => item));
                    let _timeFormatter = _res0.data.find((item) => item.nodeName === '日期模式');
                    if (_timeFormatter) {
                        setTimeFormatter(_timeFormatter.nodeValue);
                    }
                }
                // 查点表配置
                if (_res1.code === 0) {
                    let _sensorConfig = _res1.data.find((item) => item?.name.trim() === sensors.trim());
                    let _statusName = _sensorConfig?.statusName;
                    setAllPointAddress(_res1.data);
                    if (_statusName) {
                        let _statusConfig = _res1.data.find((item) => item?.name.trim() === _statusName.trim());
                        let _valDesc = _statusConfig?.valDesc || '';
                        setSpecial1({
                            name: _statusName,
                            valDesc: _valDesc.split(';').reduce((final, cur) => {
                                let _arr = cur.split(':');
                                final[_arr[0]] = _arr[1];
                                return final;
                            }, {}),
                        });
                    }
                }
                // 标记sensor是什么类型的
                if (_res2.code === 0) {
                    setAllSensorType(_res2.data);
                    let _sensorID = _res1.data?.find((item) => item.name === sensors)?.sensorTypeID;
                    let _sensor = _res2.data?.find((item) => item.id === _sensorID)?.type;
                    let _isStatusSensor = ['状态值', '开关值'].includes(_sensor);
                    setIsSingleStatusSensor(_isStatusSensor);
                }
            }
        });
        setCompleteInit(true);
    };
    useEffect(() => {
        getDefaultOptions();
    }, [deviceParams]);
    let percentTimer = useRef({
        timer: null,
    });
    //  加载动画
    useEffect(() => {
        if (loading === null) return;
        if (loading) {
            let _percent = percent;
            percentTimer.current.timer = setInterval(() => {
                _percent += 5;
                if (_percent > 95) return clearInterval(percentTimer.current.timer);
                setPercent(_percent);
            }, 100);
        } else {
            clearInterval(percentTimer.current.timer);
            setPercent(100);
            setTimeout(
                () => {
                    setPercent(0);
                },
                lineDataType === '原始曲线' ? 500 : 0,
            );
        }
    }, [loading]);
    // 初始时间
    useEffect(() => {
        if (defaultDateRange?.length === 2) {
            let _arr = defaultDateRange.reduce((final, cur) => {
                let _isDateStr = moment(cur).isValid();
                final.push(_isDateStr);
                return final
            }, []);
            if (_arr.includes(false)) return console.log('历史曲线组件：传入的默认日期格式错误，请修改');
            onCustomerRangeChange(defaultDateRange.map(item => moment(item)));
        }
    }, [defaultDateRange]);
    return (
        <div
            className={classNames(
                prefixCls,
                theme === 'BI' ? BIStyles[`${prefixCls}-historyViewComponents`] : '',
                'wkt-scroll-light',
            )}
            style={{background: theme === 'BI' ? '#282b34' : '#ffffff'}}
        >
            <div className={classNames(`${prefixCls}-spin`)} style={{position: 'relative'}}>
                {loading || percent !== 0 ? (
                    <div className={classNames(`${prefixCls}-progressWrapper`)}>
                        {lineDataType === '原始曲线' ||
                        (lineDataType === '特征曲线' &&
                            moment(dateRange?.[0]?.dateTo).diff(moment(dateRange?.[0]?.dateFrom), 'days') >=
                            30) ? (
                            <div className={classNames(`${prefixCls}-contentWrapper`)}>
                                <Progress
                                    percent={percent}
                                    steps={20}
                                    className={classNames(`${prefixCls}-progress`, `${prefixCls}-blink-2`)}
                                    showInfo={false}
                                />
                                <div className={classNames(`${prefixCls}-tip`)}>加载中...</div>
                            </div>
                        ) : (
                            <Spin
                                spinning={loading || false}
                                tip={'数据加载中...'}
                                delay={1000}
                                style={{background: 'transparent'}}
                            />
                        )}
                    </div>
                ) : (
                    ''
                )}
                {showModels.length === 1 && (
                    <div className={`${prefixCls}-single-panel`}>
                        {showModels[0] === 'curve' ? curvePanelMemo : tableMemo}
                        {showModels[0] === 'curve' ? renderChartMemo : ''}
                    </div>
                )}
                {showModels.length > 1 && (
                    <Tabs
                        activeKey={activeTabKey}
                        onChange={(key) => setActiveTabKey(key)}
                        centered
                        tabBarExtraContent={{
                            left: <h3>{title}</h3>,
                            right: (
                                <div className={`${prefixCls}-extra-right`}>
                                    {activeTabKey === 'table' && (
                                        <>
                                            <Button type="link" onClick={exportFeatureBtn}>
                                                <DownloadOutlined/>
                                                下载
                                            </Button>
                                        </>
                                    )}
                                    {activeTabKey === 'curve' && (
                                        <>
                                            <Button type="link" onClick={exportCanvas}>
                                                <DownloadOutlined/>
                                                下载
                                            </Button>
                                        </>
                                    )}
                                </div>
                            ),
                        }}
                    >
                        <Tabs.TabPane key="curve" tab="曲线" forceRender={true}>
                            {activeTabKey === 'curve' ? curvePanelMemo : ''}
                            {activeTabKey === 'curve' ? renderChartMemo : ''}
                        </Tabs.TabPane>
                        <Tabs.TabPane key="table" tab="表格">
                            {activeTabKey === 'table' ? tableMemo : ''}
                        </Tabs.TabPane>
                    </Tabs>
                )}
            </div>
        </div>
    );
};

HistoryView.propTypes = {
    grid: PropTypes.bool,
    title: PropTypes.string,
    defaultChecked: PropTypes.oneOf(['twelveHours', 'roundClock', 'oneWeek', 'oneMonth']),
    tableProps: PropTypes.object,
    deviceParams: PropTypes.arrayOf(
        PropTypes.objectOf({
            deviceCode: PropTypes.string,
            sensors: PropTypes.string,
            deviceType: PropTypes.string,
            pointAddressID: PropTypes.number, // 可选，配置了将会查询相关报警方案配置
        }),
    ),
    defaultModel: PropTypes.oneOf(['curve', 'table']),
    showModels: PropTypes.arrayOf(PropTypes.oneOf(['curve', 'table'])),
    defaultDate: PropTypes.string,
    BIMode: PropTypes.bool,
    defaultDateRange: PropTypes.array
};

HistoryView.defaultProps = {
    grid: false,
    title: '指标曲线',
    defaultChecked: 'roundClock',
    tableProps: {},
    defaultModel: 'curve',
    showModels: ['curve', 'table'],
    needMarkLine: true,
    defaultDate: 'day',
    BIMode: false,
    defaultDateRange: []
};

export default HistoryView;
