- 由 黎灏锋创建, 最终由 邹承坤修改于 五月 06, 2024
该宏示例在 V10.5上 验证通过
本文档的示例代码仅适用于本文档中的示例报表/场景。若实际报表/场景与示例代码无法完全适配(如使用功能不一致,或多个宏代码冲突等),需根据实际需求开发代码。
1. 示例效果
筛选器选择"年月日",图表的数据范围发生改变。
- 当选择频度为“日”时,图表显示区间为 [ "当前设置的'日期'往前 num 天" , "当前设置的'日期'" ]。例如宏代码内“num”的预设值为40,则显示当前日期前40天内的数据。设置“日期”筛选器的值为“2017-05-06”(截止日期),则图表显示区间为[ "2017-03-27", "2017-05-06" ] 。
- 当选择频度为“月”时,图表显示区间为 [ "当前设置的'日期'往前 num 月" , "当前设置的'日期'" ],数据根据月汇总。例如宏代码内“num”的预设值为12,即显示当前日期前12个月内的数据。设置“日期”筛选器的值为“2017-05-06”(截止日期),则图表显示区间为[ "2016-05-06", "2017-05-06" ] 。
- 当选择频度为“年”时,图表显示区间为 [ "当前设置的'日期'往前 num 年" , "当前设置的'日期'" ],数据根据年汇总。例如宏代码内“num”的预设值为1,即显示当前日期前1年内的数据。设置“日期”筛选器的值为“2017-05-06”(截止日期),则图表显示区间为[ "2016-05-06", "2017-05-06" ] 。
由于当前所使用的“订单日期”字段的数据截止到2017年5月6日,因此预设的日期为“2017-05-06”
2. 操作步骤
2.1. 新建空白仪表盘
2.2. 设计图形
- 选择数据模型“销售综合数据”,接着拖入一个线图组件到画布中
- 从数据区内拖拽相应字段到指定区域,如下图所示
- 右键选择该图表,点击“组件设置”
- 在【坐标轴】>【分类轴】下,开启显示“缩略轴”
2.3. 添加筛选器
- 在数据区内的维度内的拖拽四次字段“OrderDate”到线图的筛选框内,分别对其组件标题进行重命名为“日期”、“年”、“月”、“日”,并应用于图表2。
- 接着拖拽“参数”筛选器到画布上,修改组件标题为“选择器”,该参数控件不作用于任何组件。
- 接着右键选中筛选器“日期”,点击“筛选器设置”
- 修改 筛选器“日期” 的操作符为“小于等于”,设置默认值为“2017-05-06”
- 其它筛选器的操作同理,各筛选器的详细配置如下:
筛选器标题 | 筛选器设置 | 是否显示组件 |
---|---|---|
日期 | 设置操作符为“小于等于”,默认值为“2017年5月6日” | 显示组件 |
年 | 设置操作符为“大于等于” | 隐藏组件 |
月 | 设置操作符为“大于等于” | 隐藏组件 |
日 | 设置操作符为“大于等于” | 隐藏组件 |
2.4. 编写宏代码
- 选中名为“选择器”的筛选器,右键进入“宏管理”页面
- ①:通过点击时间粒度选择器,刷新图形数据。在该名为“选择器”组件上新建宏,事件为“onBeforeRender(组件渲染前)”,把下面宏代码复制到代码区域,接着保存该宏代码。
展开源码
function main(page: IPage, portlet: IFilterPortlet) { init(page, portlet) } /** * 场景:通过点击时间粒度选择器,刷新图形数据 * 实现: * 1、添加一个echarts的曲线图:"图表",用于展示数据,并通过【组件设置-自定义属性】添加dataZoom控制条(具体请看资源)。 * 2、数据模型添加一个无用的参数,作为筛选器:”选择器“(列表单选:日、月、年),用于选择时间粒度,并通过宏设置样式、监听选择器值变化函数,触发时间范围变化,且不作用于任何组件; * 3、拖拽一个时间字段作为筛选器:”日期“,用于作为当前日期即时间粒度中的结束日期,并通过宏添加监听值变化函数,触发时间范围变化,且作用于echarts图形组件; * 4、拖拽上面的那个时间字段三个,分别作为筛选器:”日“、”月“、”年“,用于作为时间粒度范围中的开始日期,且作用于echarts图形组件。 * (由于只是为了让图形组件请求数据,所以这三个筛选器最终作图后可以选择隐藏组件,不展示在仪表盘中。) */ // 初始化选中 function init(page: IPage, portlet: IFilterPortlet) { // 选择器点击修改日期的开始时间 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 => { setTimeout(() => { let selectorValue = startDatePortlet.getValue() if (value && value[0]) { method.doAction(page, selectorValue[0]) } }, 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(); year -= 1 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(); date -= 40; 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) } }) } }
- ②:修改选择器样式。在该名为“选择器”组件上新建宏,事件为“onAfterRender(组件渲染后)”,把下面宏代码复制到代码区域,接着保存该宏代码。
展开源码
function main(page: IPage, portlet: IFilterPortlet) { // 修改选择器样式 setTimeout(() => { doRenderStyle(portlet) }, 800) } function doRenderStyle(portlet: IFilterPortlet) { // 水平布局 portlet.appendCss('.filter-list__table>div.ps', `{display: inline-flex; width: 100%;}`) // 隐藏参数默认显示的“全部”选项 portlet.appendCss('.filter-list__table > tr:nth-child(1)', `{display: none;}`) // // 去除选项之间的边距 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. 下载资源
- 无标签