页面树结构

版本比较

标识

  • 该行被添加。
  • 该行被删除。
  • 格式已经改变。


注意

该宏示例在V10.1上验证通过

该文档为仪表盘宏示例文档,无需写新特性

jiraSMS-29246 【自助仪表盘】筛选器筛选不同范围的日期数据,组件能展示不同区间的日期 【自助仪表盘】根据时间频度动态展示该频度下指定时间段的数据

文档新增位置基础宏示例

新增文档:【自助仪表盘】通过筛选不同范围的日期数据来展示不同日期区间的数据:【自助仪表盘】根据时间频度动态展示该频度下指定时间段的数据


注意

提示:本文档的示例代码仅适用于本文档中的示例报表/场景。若实际报表/场景与示例代码无法完全适配(如使用功能不一致,或多个宏代码冲突等),需根据实际需求开发代码。


目录

1. 示例效果

筛选器选择"年月日",图表的数据范围发生改变。

  • 选择“日”:数据区间选取 “当前设置日期” 至 往前40天。
  • 选择“月”:数据区间选取 当前设置月份 至 往前12个月,且根据所选日期的日(如30号),每个月选取 月的第1天 至 当日(如2月则是1-28号),展示为所选日期对应每月的当日(如选2020-03-30,展示2020-02-29,2020-01-30),根据月汇总。
  • 选择“年”:数据区间选取 “当前设置日期 至 前一年,且根据当前所选的日,每年选取 年的第一天 至 当日(如2020-02-29,2019-02-28),展示所选日期对应每年的当月日,根据年汇总。

    ,图表的数据范围发生改变。当前月份 至 往前12个月

    • 当选择频度为“日”时,图表显示区间为 [ "当前设置的'日期'往前 num 天" , "当前设置的'日期'" ]。例如宏代码内“num”的预设值为40,设置“日期”筛选器的值为“2017-05-06”(截止日期),则图表显示区间为[ "2017-03-27", "2017-05-06" ]
    • 当选择频度为“月”时,图表显示区间为 [ "当前设置的'日期'往前 num 月" , "当前设置的'日期'" ],数据根据月汇总。例如宏代码内“num”的预设值为12,设置“日期”筛选器的值为“2017-05-06”(截止日期),则图表显示区间为[ "2016-05-06", "2017-05-06" ]
    • 当选择频度为“年”时,图表显示区间为 [ "当前设置的'日期'往前 num 年" , "当前设置的'日期'" ],数据根据年汇总。例如宏代码内“num”的预设值为1,设置“日期”筛选器的值为“2017-05-06”(截止日期),则图表显示区间为[ "2016-05-06", "2017-05-06" ]
    注意

    由于当前所使用的“订单日期”字段的数据截止到2017年5月6日,因此预设的日期为“2017-05-06”

    2. 操作步骤

    2.1. 新建空白仪表盘

    2.2. 设计图形

    • 拖入一个图形到画布中,图表类型选择“线图”,接着选择数据模型“销售综合数据”

    • 从数据区内拖拽相应字段到指定区域,如下图所示

    • 通过自定义属性给线图图表添加dataZoom控制条

    自定义属性配置如下:

    代码块
    languagejs
    themeRDark
    linenumberstrue
    {
    	"color": [
    		"#bc8b2a"
    	],
    	"legend": {
    		"show": false
    	},
    	"tooltip": {
    		"trigger": "axis",
    		"axisPointer": {
    			"type": "cross",
    			"label": {
    				"show": "true",
    				"backgroundColor": "#000000",
    				"textStyle": {
    					"color": "#e9e900"
    				}
    			}
    		}
    	},
    	"xAxis": {
    		"axisTick": {
    			"show": false
    		},
    		"axisLabel": {
    			"margin": 15
    		}
    	},
    	"yAxis": {
    		"axisTick": {
    			"show": false
    		},
    		"axisLabel": {
    			"margin": 15
    		}
    	},
    	"dataZoom": [
    		{
    			"minSpan": 50,
    			"maxSpan": 50,
    			"start": 50,
    			"end": 100,
    			"zoomLock": true,
    			"zoomOnMouseWheel": false
    		}
    	]
    }

    2.3. 添加筛选器

    • 在数据区内的维度内的拖拽四次字段“OrderDate”到线图的筛选框内,分别对其组件标题进行重命名为“日期”、“年”、“月”、“日”,并应用于图表2。
    • 拖拽数据区内的维度内的字段“OrderDate”到线图的筛选框内,一共需要拖拽四个,四个筛选器应用于图表2。接着拖拽“接着拖拽“参数”到画布上,该参数控件不作用于任何组件。”筛选器到画布上,修改组件标题为“选择器”,该参数控件不作用于任何组件。

    • 接着右键选中筛选器“日期”,点击“筛选器设置
    • 修改筛选器组件标题名称,具体如下。

    Image Removed

    • 接着右键选中筛选器,点击“筛选器设置”,各筛选器配置如下:

    Image RemovedImage Added

    • 修改 筛选器“日期” 的操作符为“小于等于”,设置默认值为“2017-05-06”

    Image Added

    • 其它筛选器的操作同理,各筛选器的详细配置如下:
    筛选器标题筛选器设置是否显示组件
    日期设置操作符为“小于等于”,默认值为“2017年5月6日”显示组件
    设置操作符为“大于等于”隐藏组件
    设置操作符为“大于等于”隐藏组件
    设置操作符为“大于等于”隐藏组件

    2.4. 编写宏代码

    • 选中名为“选择器”的筛选器,右键进入“宏管理”页面

    • 在筛选器组件上新建宏,事件为“onBeforeRender(组件渲染前)”,把下面宏代码复制到代码区域,接着保存该宏代码。
    代码块
    languagejs
    themeRDark
    linenumberstrue
    collapsetrue
    function main(page: IPage, portlet: IFilterPortlet) {
        init(page, portlet)
    }
    
    /**
     * 场景:通过点击时间粒度选择器,刷新图形数据
     * 实现:
     * 1、添加一个echarts的曲线图:"图表",用于展示数据,并通过【组件设置-自定义属性】添加dataZoom控制条(具体请看资源)。
     * 2、数据模型添加一个无用的参数,作为筛选器:”选择器“(列表单选:日、月、年),用于选择时间粒度,并通过宏设置样式、监听选择器值变化函数,触发时间范围变化,且不作用于任何组件;
     * 3、拖拽一个时间字段作为筛选器:”日期“,用于作为当前日期即时间粒度中的结束日期,并通过宏添加监听值变化函数,触发时间范围变化,且作用于echarts图形组件;
     * 4、拖拽上面的那个时间字段三个,分别作为筛选器:”日“、”月“、”年“,用于作为时间粒度范围中的开始日期,且作用于echarts图形组件。
     * (由于只是为了让图形组件请求数据,所以这三个筛选器最终作图后可以选择隐藏组件,不展示在仪表盘中。)
     */
    
    // 初始化选中
    function init(page: IPage, portlet: IFilterPortlet) {
        // 修改选择器样式
        method.doRenderStyle(portlet)
        // 选择器点击修改日期的开始时间
        doSelectTime(page, portlet)
        // 初始化选择器第一次选中
        let selectorValue: any = portlet.getValue()
        method.doAction(page, selectorValue[0])
    }
    // 点击选择器时更新年月日的值
    function doSelectTime(page: IPage, startDatePortlet: IFilterPortlet) {
        startDatePortlet.setFilterValueChangeHandler(value => {
            if (value && value[0]) {
                method.doAction(page, value[0])
            }
            return value
        })
        // 日期选择器修改日期时也需要更新开始时间
        let endDateFilter: IFilterPortlet = method.getPortlet(page, method.dc.endDatePortletTitle)
        if (!endDateFilter) return
        endDateFilter.setFilterValueChangeHandler(value => {
            let selectorValue = startDatePortlet.getValue()
            if (value && value[0]) {
                method.doAction(page, selectorValue[0])
            }
            return value
        })
    }
    
    var method = {
        // 字段信息常量
        fc: {
            DATEINDEX: 0,
            VALUEINDEX: 1
        },
        // 组件标题常量
        dc: {
            endDatePortletTitle: '日期',
            chartPortletTitle: '图表',
            textSelectorPortlet: '选择器'
        },
        // 定义选择器
        getSelectors() {
            return [
                { label: '年', calc: method.calcYear, total: method.calcTotalYear },
                { label: '月', calc: method.calcMonth, total: method.calcTotalMonth },
                { label: '日', calc: method.calcDate, total: method.calcTotalDay, checked: true /**默认高亮 */ }
            ]
        },
        // 点击事件处理
        doAction(page: IPage, type: string | any) {
            let selectors: any = method.getSelectors()
            let selector = selectors.find((el: any) => el.label === type)
            if (!selector) return
            let endDateValue = method.getBaseDateValue(page)
            let endDate: Date = new Date(endDateValue)
            let beginDate: Date = selector.calc(new Date(endDateValue))
            method.setValues(page, beginDate, selector.label)
            let bdate = SmartbiXMacro.utils.formatDate(beginDate, 'yyyy-MM-dd')
            let edate = SmartbiXMacro.utils.formatDate(endDate, 'yyyy-MM-dd')
            // ECharts图形
            let portlet: IEChartsPortlet = method.getPortlet(page, method.dc.chartPortletTitle)
            if (!portlet) return
            let flag = false
            page.doPortletRendered(portlet.getId(), () => {
                if (flag) return
                flag = true
                let options = portlet.getChartOptions()
                if (!options) return
                options = method.updateSeries(options, bdate, edate, selector)
                portlet.setChartOptions(options)
            })
        },
        // 更新Series(做合计)
        updateSeries(options: object | any, bdate: string, edate: string, selector: any) {
            selector.total(options, bdate, edate)
            return options
        },
        // 不足两位补全0
        zeroFn(num: number | string) {
            return num < 10 ? '0' + num : num + ''
        },
        // 计算合计:年
        calcTotalYear(options: any, bdate: string, edate: string) {
            let { tooltipInfos } = options
            let keys = Object.keys(tooltipInfos) || []
            let da = { start: new Date(bdate), end: new Date(edate) }
            let y = { start: da.start.getFullYear(), end: da.end.getFullYear() }
            let m = { start: da.start.getMonth() + 1, end: da.end.getMonth() + 1 }
            let d = { start: da.start.getDate(), end: da.end.getDate() }
    
            let zeroFn = method.zeroFn
    
            let dataObj: any = {}
            let curTotal = 0 // 合计
            let newAxisData: string[] = [] // 新的Axis的data
            let newTooltipInfos: any = {} // 新的tooltipInfos
            let newSeriesData: any = [] // 新的series的data
    
            keys.forEach((key, index) => {
                let item = tooltipInfos[key]
                let dateValue = item[method.fc.DATEINDEX].value
                let dataValue = item[method.fc.VALUEINDEX].realValue
                let date = new Date(dateValue)
                let year = date.getFullYear()
                let startDateValue = `${year}-01-01`
                let startDate = new Date(startDateValue)
                let endDateValue = `${year}-${zeroFn(m.end)}-${zeroFn(d.end)}`
                let endDate = new Date(endDateValue)
                let isInDate = date >= startDate && date <= endDate // 一年中指定的[开始时间(year-01-01),结束时间]
                
                if (!dataObj[year]) {
                    dataObj[year] = true
                    curTotal = dataValue
                    // xAsix的data数据
                    newAxisData.push(endDateValue)
                } else if (isInDate) {
                    curTotal += dataValue
                }
                let parseD = SmartbiXMacro.utils.formatDate(date, 'yyyy-MM-dd')
                let parseEndD = SmartbiXMacro.utils.formatDate(endDate, 'yyyy-MM-dd')
                // if (isInDate) { 
                // console.warn('isInDate', isInDate, date, startDate, endDate)
                // console.log(parseD === parseEndD, (isInDate && index === keys.length - 1))
                // }
                if (parseD === parseEndD || (isInDate && index === keys.length - 1)) {
                    let newIndex = newAxisData.indexOf(parseD)
                    let find = newSeriesData.find(el => el.displayValue[0] === endDateValue)
                    // console.warn(date, curTotal, newIndex, newAxisData)
                    if (!find) {
                        // series的data数据
                        newSeriesData.push({
                            value: [newIndex, curTotal],
                            displayValue: [endDateValue, curTotal],
                            rowIndex: [newIndex, newIndex],
                            colIndex: 1
                        })
                        // tooltip的数据
                        item[method.fc.DATEINDEX].value = endDateValue
                        item[method.fc.DATEINDEX].realValue = new Date(endDateValue).getTime()
                        item[method.fc.VALUEINDEX].value = curTotal + ''
                        item[method.fc.VALUEINDEX].realValue = curTotal
                        let newTooltipInfosKey = newIndex + '_1'
                        if (!newTooltipInfos[newTooltipInfosKey]) {
                            newTooltipInfos[newTooltipInfosKey] = []
                        }
                        newTooltipInfos[newTooltipInfosKey][method.fc.DATEINDEX] = item[method.fc.DATEINDEX]
                        newTooltipInfos[newTooltipInfosKey][method.fc.VALUEINDEX] = item[method.fc.VALUEINDEX]
                    }
                }
    
            })
    
            options.xAxis[0].data = newAxisData
            options.series[0].data = newSeriesData
            options.tooltipInfos = newTooltipInfos
            // console.warn('newAxisData', newAxisData)
            // console.warn('newSeriesData', newSeriesData)
            // console.warn('tooltipInfos', tooltipInfos)
            return options
        },
        // 计算合计:月
        calcTotalMonth(options: any, bdate: string, edate: string) {
            let { tooltipInfos } = options
            let keys = Object.keys(tooltipInfos) || []
            let startMonth = new Date(bdate).getMonth()
            let endDay = new Date(edate).getDate()
    
            let zeroFn = method.zeroFn
    
            let dataObj: any = {}
            let newAxisData: string[] = []
            let newTooltipInfos: any = {}
            let newSeriesData: any = []
    
            let curTotal = 0 // 合计
            keys.forEach((key) => {
                let item = tooltipInfos[key]
                let dateValue = item[method.fc.DATEINDEX].value
                let dataValue = item[method.fc.VALUEINDEX].realValue
                let date = new Date(dateValue)
                let year = date.getFullYear()
                let month: number | string = zeroFn(date.getMonth() + 1)
                let axisKey = `${year}-${month}`
                let endDateValue = axisKey + '-' + zeroFn(endDay) // 每个月的同一天为合计截止日期
                let isEndDay = method.isEndDay(dateValue, endDateValue) // 获取指定每个月的最后一天
                // 月份总计total
                if (!dataObj[axisKey]) {
                    dataObj[axisKey] = true
                    curTotal = dataValue
                } else {
                    if (isEndDay || !(new Date(dateValue) > new Date(endDateValue))) {
                        curTotal += dataValue
                    }
                }
                // 结束时间(每个月最后一天不一样,所以要做判断,如果不一致需要更新endDateValue)
                if (isEndDay) {
                    endDateValue = dateValue
                    // xAsix的data数据
                    let flag = newAxisData.indexOf(endDateValue) !== -1
                    if (flag) return
                    newAxisData.push(endDateValue)
    
                    // tooltip的数据
                    item[method.fc.DATEINDEX].value = endDateValue
                    item[method.fc.DATEINDEX].realValue = new Date(endDateValue).getTime()
                    item[method.fc.VALUEINDEX].value = curTotal + ''
                    item[method.fc.VALUEINDEX].realValue = curTotal
                    let newIndex = newAxisData.length - 1
                    let newTooltipInfosKey = newIndex + '_1'
                    if (!newTooltipInfos[newTooltipInfosKey]) {
                        newTooltipInfos[newTooltipInfosKey] = []
                    }
                    newTooltipInfos[newTooltipInfosKey][method.fc.DATEINDEX] = item[method.fc.DATEINDEX]
                    newTooltipInfos[newTooltipInfosKey][method.fc.VALUEINDEX] = item[method.fc.VALUEINDEX]
                    // series的data数据
                    newSeriesData.push({
                        value: [newIndex, curTotal],
                        displayValue: [item[method.fc.DATEINDEX].value, item[method.fc.VALUEINDEX].value],
                        rowIndex: [newIndex, newIndex],
                        colIndex: 1
                    })
                }
            })
    
            options.xAxis[0].data = newAxisData
            options.series[0].data = newSeriesData
            options.tooltipInfos = newTooltipInfos
            // console.warn('newAxisData', newAxisData)
            // console.warn('newSeriesData', newSeriesData)
            // console.warn('tooltipInfos', tooltipInfos)
            return options
        },
        // 计算合计:日,这里不需要计算,写个空方法直接返回options
        calcTotalDay(options: any, bdate: string, edate: string) {
            return options
        },
        isEndDay(currentDate: string, endDate: string) {
            let monthLastDay = method.getMonthEndDay(currentDate)
            if (currentDate === endDate) return true
            let cdate = new Date(currentDate)
            let edate = new Date(endDate)
            if (cdate > edate) {
                return false
            }
            // 当前判断的日期
            let cDay = cdate.getDate()
            if (cDay === monthLastDay) return true
            return false
        },
        // 根据标题获取组件
        getPortlet<T>(page: IPage, title: string): T {
            let portlets: T[] = page.getPortletsByTitle(title)
            let portlet: T = portlets[0]
            return portlet
        },
        // 获取自定义当前时间筛选器的值
        getBaseDateValue(page: IPage) {
            let filter: IFilterPortlet = method.getPortlet(page, method.dc.endDatePortletTitle)
            if (!filter) return ''
            let value = filter.getValue()
            if (!value || !value.length) return ''
            return value[0]
        },
        /**
         * 选择“年”:
         * 数据区间选取 当前日期 至 前一年,且根据当前所选的日,
         * 每年选取年的第一天 至 当日(如2020-02-29,2019-02-28),
         * 展示所选日期对应每年的当月日,根据年汇总。
         */
        calcYear(baseDate: Date) {
            let year = baseDate.getFullYear();
    		let num = 1;
            year -= 1num;
            let resultDate = new Date(`${year}-01-01`)
            return resultDate
        },
        /**
         * 选择“月”:
         * 数据区间选取 当前月份 至 往前12个月,
         * 且根据所选日期的日(如30号),
         * 每个月选取 月的第1天 至 当日(如2月则是1-28号),
         * 展示为所选日期对应每月的当日(如选2020-03-30,展示2020-02-29,2020-01-30),
         * 根据月汇总。
         */
        calcMonth(baseDate: Date) {
            let month = baseDate.getMonth();
            let num = 12;
            month -= num;
            method.setMonth(baseDate, month, num)
            baseDate.setDate(1);
            return baseDate
        },
        /**
         * 选择“日”:
         * 数据区间选取 当前日期 至 往前40天。
         */
        calcDate(baseDate: Date) {
            let date = baseDate.getDate();
    		let num = 40;
            date -= 40num;
            baseDate.setDate(date)
            return baseDate
        },
        setMonth(currentDate: Date, month: number, num: number) {
            let day = currentDate.getDate();
            currentDate.setMonth(month);
            if (num && day !== currentDate.getDate()) {
                let currentMonthLastDay = new Date(currentDate.getTime() - 1000 * 60 * 60 * 24 * currentDate.getDate());
                currentDate.setYear(currentMonthLastDay.getFullYear());
                currentDate.setMonth(currentMonthLastDay.getMonth());
                currentDate.setDate(currentMonthLastDay.getDate());
            }
        },
        // 获取每个月最后一天
        getMonthEndDay(currentDate: string) {
            let clastdate = new Date(currentDate)
            let year = clastdate.getFullYear()
            let month = clastdate.getMonth() + 1
            if (month > 12) {
                month -= 1
                year += 1
            }
            let lateDate = new Date(year, month, 1);
            let lastDay = (new Date(lateDate.getTime() - 1000 * 60 * 60 * 24)).getDate();
            return lastDay
        },
        // 单选设置值
        setValues(page: IPage, currentDate: Date, selectorLabel: any) {
            let selectors = method.getSelectors()
            let value = SmartbiXMacro.utils.formatDate(currentDate, 'yyyy-MM-dd') + ' 00:00:00'
            selectors.forEach(el => {
                let portlet: IFilterPortlet = method.getPortlet(page, el.label)
                if (!portlet) return
                if (el.label === selectorLabel) {
                    setTimeout(() => { portlet.setValue([value]) }, 0)
                } else {
                    setTimeout(() => { portlet.setValue([]) }, 0)
                }
            })
        },
        /**
         * 调整筛选器样式
         */
        doRenderStyle(portlet: IFilterPortlet) {
            portlet.appendCss('.el-radio-group table', `{display: inline-flex;}`)
            portlet.appendCss('.filter-list__td', `{padding: 0px;}`)
            portlet.appendCss(`.filter-wrapper .el-radio-group .el-radio`, `{
                background-color: #eeeeee;
                width: 30px;
                height: 30px;
                justify-content: center;
                padding: 0px;
            }`)
            portlet.appendCss('.filter-wrapper .el-radio-group .el-radio.is-checked', `{background-color: rgb(188, 139, 42);}`)
            portlet.appendCss('.filter-wrapper .el-radio-group .el-radio.is-checked .el-radio__label', `{color: #fff;}`)
            portlet.appendCss('.el-radio .el-radio__input', `{display: none; }`)
            portlet.appendCss('.el-radio__label', `{padding-left: 0px;}`)
        }
    }
    
    

    • 点击 保存 保存该宏代码重新访问报表,可看到效果已实现

    3. 下载资源

    通过筛选不同范围的日期数据来展示不同日期区间的数据.xml