【仅供内部供应商使用,不提供对外解答和培训】

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

第一步,注入组件接口

实现如下图所示效果

在插件中配置自定义控件的属性,代码如下:

public class FilterProvider extends AbstractCustomFilterWidgetProvider {
    /**
     * 配置自定义控件的名称
     */
    @Override
    public String getName() {
        try {
            Locale currentLocale = null;
            // 加载资源文件(使用 base name,不带语言后缀和 .properties)
            // LocaleFinder 已经配置了基础路径,这里只需要添加 base name
            String resourceBaseName = "ru/soundbi/filters/datesliderfilter/resource/locale/locale";
            try {
                InterProviderFactory.getProvider().addResource(resourceBaseName);
            } catch (Exception e) {
            };
            HttpServletRequest req = null;
            try {
                if (RequestContextHolder.getRequestAttributes() != null) {
                    req = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
                }
            } catch (Exception e) {
                // 忽略异常,继续尝试其他方式
            }
            if (req != null) {
                currentLocale = ProviderFactory.INSTANCE.getInternationalProvider().getClientLocale(req);
            }
            // 如果无法获取语言,返回键值
            if (currentLocale == null) {
                return "Plugin-Xml-I18n-Custom-Date-Slider-Plugin-Name";
            }
            
            // 使用 getLocText(String text, Locale locale) 方法获取国际化文本
            String key = "Plugin-Xml-I18n-Custom-Date-Slider-Plugin-Name";
            String localizedText = InterProviderFactory.getProvider().getLocText(key, currentLocale);
            return localizedText;
        } catch (Exception e) {
            // 如果无法加载国际化资源,返回键值作为后备
        }
        return "Plugin-Xml-I18n-Custom-Date-Slider-Plugin-Name";
    }

    /**
     * 配置该自定义控件的xType
     */
    @Override
    public String getType() {
        return "bi.custom.date.dateslider";
    }

    /**
     * 配置该自定义组件的展示图标
     */
    @Override
    public String getIcon() {
        return "http://webapi.amap.com/theme/v1.3/mapinfo_05.png";
    }

    /**
     * 配置该自定义控件的配置 (可以为空)
     */
    @Override
    public String getCustomTool() {
        return "";//"bi.plugin.testwidget";
    }

    /**
     * 配置该自定义控件的预览html (可以为空)
     */
    @Override
    public String getPreviewPageHTML(OperationContext context) {
        return "<link rel=\"stylesheet\" type=\"text/css\" href=\"https://fanruan.design/fineui/2.0/fineui.min.css\" />" +
                "<script src=\"https://fanruan.design/fineui/2.0/fineui.min.js\"></script>" +
                "<div>context: </div>" + context.getSystemInfo() + context.getUserInfo() +
                "<div id=\"container\">这是预览</div>";
    }

    /**
     * 配置该自定义控件的编辑html (可以为空)
     */
    @Override
    public String getEditPageHTML(OperationContext context) {
        return "<link rel=\"stylesheet\" type=\"text/css\" href=\"https://fanruan.design/fineui/2.0/fineui.min.css\" />" +
                "<script src=\"https://fanruan.design/fineui/2.0/fineui.min.js\"></script>" +
                "<div>context: </div>" + context.getSystemInfo().getServletURL() + context.getUserInfo().getDisplayName() +
                "<div id=\"container\">这是编辑</div>";
    }

    @Override
    public AssembleComponent previewClient(OperationContext context) {
        return FilterComponent.KEY;
    }

    /**
     * 配置该自定义控件的类型,默认支持创建字符类型的控件,日期类型的控件和数值类型的控件
     * For custom text filter widget, use BICommonConstants.COLUMN.STRING
     * For custom date range filter widget, use BICommonConstants.COLUMN.DATE
     * For custom number filter widget, use BICommonConstants.COLUMN.NUMBER
     */
    @Override
    public int getFilterFieldType() {
        return BICommonConstants.COLUMN.DATE;
    }
}

第二步 构造自定义过滤控件的处理逻辑

在插件中定义自定义过滤控件的逻辑代码,该自定义过滤控件可以去控制自定义控件编辑时的效果

以及自定义过滤控件预览时的效果

这里给出了一个自定义滑块过滤组件的组件代码:

import { shortcut, store, extend } from '../../core';
import { ControlFilterModel } from './control.filter.model';
import './HTMLComponents/date-picker.js';
import './HTMLComponents/scale-selector.js';
import './HTMLComponents/date-range-picker.js';
import './HTMLComponents/date-range-scale-selector.js';
import { ErrorCode, RES_STATUS } from '../../contsant/index';

import { formatDate, getControlUsedMeasuresAndTableNames, setCssScale, setTransformScale } from '../../utils';

export interface ControlStringSingleProps {
    baseCls: string;
    $testId: string;
    height: number;
    width?: number;
    isPreviewMode: boolean;
    cssScaleGetter: () => number;
}

@shortcut()
@store(ControlFilterModel)
export class ControlDateIntervalFilter extends BI.Widget  {
    static xtype = 'bi.custom.date.dateslider';

    static EVENT = {
        EVENT_CHANGE: 'EVENT_CHANGE',
    };

    props: ControlStringSingleProps = {
        baseCls: 'bi-date-interval-control',
        $testId: 'bi-date-interval-control',
        isPreviewMode: false, // 是否是预览
        cssScaleGetter: () => 1,
    };

    model: ControlFilterModel['model'];
    store: ControlFilterModel['store'];



    watch = {
        disabled: () => {},
    };
    setMinMaxDate() {
        this.element[0].setAttribute('min-date',this.minData||'2022-01-01');
        this.element[0].setAttribute('max-date',this.maxData||'2022-12-01');

        console.log("setting minmax",this.minData,this.maxData);
    }

    mounted() {
        console.log('hello world1234',this);

        this.getMinMaxDate();
        //this.setValue(this.model.widgetHelper?.getResultWidgetValue(true, this.model.value) ?? this.model.value);
        try{
          this.element[0].closest('.bi-show-widget-factory.bi-control-widget,.bi-abs.bi-control-widget.bi-card').style.setProperty("overflow","visible");
        }catch(e){}
        try{
          this.element[0].closest('.bi-fit-widget.bi-export-widget').style.setProperty("z-index","100");
        }catch(e){}
        this.element[0].style.setProperty('height','24px');
        setTimeout(()=>{
       // this.element[0].style.setProperty('position',"absolute");
        this.element[0].style.setProperty('top',"0");
        this.element[0].style.setProperty('left',"0");
        this.element[0].style.setProperty('right',"0");
        this.element[0].style.setProperty('bottom',"0");
        this.element[0].style.setProperty('height','100%');

        this.element[0].style.setProperty('--scale-text-color','#2c60db');
        this.element[0].style.setProperty('--scale-border-color', '#2c60db');
        this.element[0].style.setProperty('--scale-tick-color', '#2c60db');
        this.element[0].style.setProperty('--collapse-btn-color', '#2c60db');
        this.element[0].style.setProperty('--collapse-icon-color', '#2c60db');
        this.element[0].style.setProperty('--collapse-btn-color-hover', '#2c60db');
        this.element[0].style.setProperty('--background-item-color', '#f2f7fe');
        this.element[0].style.setProperty('--higher-periods-active-color', '#cde1fc');
        },200)


    }

    _defaultConfig() {
        console.log('default config 4');
        const conf = super._defaultConfig(...arguments);
        return extend(conf, {
            baseCls: ``,
            el: null,
            tagName: 'date-range-scale-selector',

            listeners: [
            {
                eventName: 'range-changed',
                action(e) {
                  //  console.log("here we got message from ",e);
                  //  this.fireEvent(ControlDateInterval.EVENT.EVENT_CHANGE, {start:e.startDate,end:e.endDate});
                },
            }
            ],
        });
    }
    date_value_to_str(v){
        if(v==undefined)return undefined;
        let p0=(x)=>`${x<10?'0':''}${x}`;
        return `${p0(v.year)}-${p0(v.month)}-${p0(v.day)}`;
    }

    // 获取最早最晚日期
    private getMinMaxDate(): Promise<{minData: any, maxData: any}> {
        console.log('test', this.model)

        return BI.Utils.getControlDefaultValueByWidgetInfo([
            {...this.getRequestParams(), originDefaultValue: 1, measuresConfig: []}
        ], this.model.templateHelper).then((minRes) => {
            const minData = minRes.data;
            console.log('最早日期', minData);

            // 返回第二个请求的Promise
            return BI.Utils.getControlDefaultValueByWidgetInfo(
                [{...this.getRequestParams(), originDefaultValue: 2, measuresConfig: []}], this.model.templateHelper).then((maxRes) => {
                const maxData = maxRes.data;
                this.minData=this.date_value_to_str(minData[Object.keys(minData)[0]].value);
                this.maxData=this.date_value_to_str(maxData[Object.keys(maxData)[0]].value);
                //console.log('min-max',this.date_value_to_str,this.date_value_to_str(minData[Object.keys(minData)[0]].value),  this.model,   this.model.minData,  maxData[Object.keys(maxData)[0]],maxData[Object.keys(maxData)[0]].value, this.model.maxData,Object.keys(minData)[0],minData);
                if(this.element){
                    this.element[0].setAttribute('min-date', this.minData);
                    this.element[0].setAttribute('max-date', this.maxData);
                }
                return { minData, maxData };
            });
        }).catch((error) => {
            console.error('获取日期范围失败:', error);
        });
    }

    // 获取请求参数
    private getRequestParams () {
        const measurePoolHelper = this.model.templateHelper.getMeasurePoolHelper();
        const measureHelper = measurePoolHelper.getMeasureHelper();
        // 未保存时 dimensions 和 widget 不一样
        let fieldIds: string[] = [];
        BI.each(this.model.dimensions, (_, dimension) => {
        const { fieldId, sort } = dimension;

        fieldIds = [...fieldIds, fieldId, ...measureHelper.getAllUsedCalTargets(fieldId)];

        if (sort?.targetFieldId) {
            fieldIds = [
                ...fieldIds,
                sort.targetFieldId,
                ...measureHelper.getAllUsedCalTargets(sort.targetFieldId),
            ];
        }
        });

        const { measures, generaTableNames } = getControlUsedMeasuresAndTableNames(fieldIds, measureHelper);
        console.log('test11', measures, this.model);
        const tableNames = this.model.selectedTable;
        const relationTableNames = BI.flatten(
            this.model.templateHelper.getPoolHelper().getRelationModelByTableNames(tableNames)
        );

        return {
            wId: this.model.wId,
            dimensions: this.model.dimensions,
            view: this.model.view,
            value: this.model.value,
            type: this.model.type,
            tableName: BI.uniq(
                BI.concat(
                    tableNames,
                    generaTableNames.filter(tableName => relationTableNames.includes(tableName))
                )
            ),
            measuresConfig: [],
            dateIntervalValue: this.model.dateIntervalValue,
            useDateInterval: this.model.useDateInterval,
            showTime: this.model.showTime,
        };
    }
    render() {
        // const { width, height, isPreviewMode } = this.options;
      //  super.render();
        console.log("   this.element",this.element,JSON.stringify(this.model.value));

        this.element.attr({"min-date":'2020-01-01',
                "max-date":'2026-01-01',
                'granularity':"month",
                "start-date":this.date_value_to_str(this.model.value?.start?.value)||'2022-01-01',
                "end-date":this.date_value_to_str(this.model.value?.end?.value)||'2022-12-01',
                'week-numbering':'ISO', 'first-day-of-week':'1'});
        this.element.on("range-changed",(e:any)=>{
            console.log("got event e",e);
            let ev={start:e.originalEvent.detail.startDate,end:e.originalEvent.detail.endDate,};
            ev.start=ev.start.split("T")[0];
            ev.end=ev.end.split("T")[0];
            if((ev.start=="")||(ev.end=="")){
                console.log("fire null");
                this.fireEvent(ControlDateIntervalFilter.EVENT.EVENT_CHANGE, null);
                return;
            }
            ev.start={
                type:1,value:{
                day:parseInt(ev.start.split("-")[2]),
                month:parseInt(ev.start.split("-")[1]),
                year:parseInt(ev.start.split("-")[0])}
            }
            ev.end={
                type:1,value:{
                day:parseInt(ev.end.split("-")[2]),
                month:parseInt(ev.end.split("-")[1]),
                year:parseInt(ev.end.split("-")[0])}
            }
             this.model.collapse=e.originalEvent.detail.collapse;
             this.model.granularity=e.originalEvent.detail.granularity;
            console.log("fire ",ev);
             this.fireEvent(ControlDateIntervalFilter.EVENT.EVENT_CHANGE, ev);

        }) ;
        console.log("-------------------------->",this.element,this.options);

          this.element[0].style.overflow="visible";
          this.element[0].style.height="24px";

    }

    setValue(v?: any) {
        console.log("Somebody wants from us to set Value",v);
        if(v.start){
         this.element[0].setAttribute('start-date',this.date_value_to_str(v.start.value));
        }
        if(v.end){
         this.element[0].setAttribute('end-date',this.date_value_to_str(v.end.value));
        }
    }

    getValue() {}

    reset() {
        this.setValue();
    }

    _itemsCreator(options: { type: number }, callback: Function) {
        console.log('hello this.model', this.model);

        if (this.model?.useCustom && BI.isNotEmptyArray(this.model?.customValue)) {
            // 使用自定义值列表时
            callback({
                items: this.createItemsByData(this.model?.customValue, options, true),
            });
        } else if (BI.size(this.model?.dimensions) === 0) {
            callback([]);
        } else {
            console.log('hello data');
            BI.Utils.getControlWidgetDataByWidgetConfig(
                this.model?.widgetConfig,
                (res: any) => {
                    const { data = { value: [], hasNext: false }, errorCode } = res;
                    console.log('data11@@', data, res);
                    if (errorCode === ErrorCode.STRING_SEARCH_OUT_OF_LIMIT) {
                        callback({
                            tipText: BI.i18nText('BI-Design_Search_Result_More_Than_10000'),
                        });

                        return;
                    }
                    if (errorCode === RES_STATUS.CACHE_MISS) {
                        callback({
                            tipText: BI.i18nText('BI-Conf_Cache_Loading_Retry_Later'),
                        });

                        return;
                    }
                    if (options.type === BI.MultiSelectCombo.REQ_GET_ALL_DATA) {
                        callback({
                            items: this.createItemsByData(data.value, options),
                        });

                        return;
                    }

                    if (options.type === BI.MultiSelectCombo.REQ_GET_DATA_LENGTH) {
                        callback({ count: data.value });

                        return;
                    }

                    callback({
                        items: this.createItemsByData(data.value, options),
                        hasNext: data.hasNext,
                    });
                },
                { textOptions: options },
                null,
                this.model.templateHelper
            );
        }
    }

    private setScale(el: any) {
        /*const { cssScaleGetter } = this.options;

        setCssScale(el, cssScaleGetter());
        setTransformScale(el, this.model.templateHelper.getReportScale());*/
    }

    private createItemsByData(valueArray: string[], options: Obj, isCustomValue = false) {
        console.log('valurArray', valueArray, options, isCustomValue);
        return createControlWidgetItemsByData(
            valueArray,
            options.keywords || [],
            options.selectedValues || [],
            isCustomValue
        );
    }

}

在这里,如果还有任何的问题,欢迎参考浏览David.Feng-冯存 / plugin-bi-custom-filter-widget - 代码管理 以及对应的文档 自定义过滤控件整体介绍 - 3.2 研发测试组 - 知识管理。这里提供了示例的自定义过滤控件的完整代码和对应的说明。




  • No labels