import { IPSControl, IPSDEToolbar, IPSPanelButton, IPSPanelContainer, IPSPanelItem, IPSPanelRawItem, IPSPanelTabPage, IPSPanelTabPanel, IPSSysPanelButton, IPSSysPanelField, IPSViewLayoutPanel } from '@ibiz/dynamic-model-api';
import { appEngineService, AppServiceBase, debounce, ModelTool, PanelButtonModel, PanelContainerModel, PanelControlModel, PanelCtrlPosModel, PanelFieldModel, PanelRawitemModel, PanelTabPageModel, PanelTabPanelModel, PanelUserControlModel, PluginService, throttle, Util } from 'ibiz-core';
import { Subject } from 'rxjs';
import { Prop, Component } from 'vue-property-decorator';
import { AppViewLogicService, ContainerLoadingService } from '../../../../app-service';
import { ControlContainer } from '../../../../control-container/control-container';

/**
 * 视图基础布局
 *
 * @export
 * @class AppDefaultViewLayout
 * @extends {Vue}
 */
@Component({})
export class AppDefaultViewLayout extends ControlContainer {

    /**
     * 视图模型数据
     * 
     * @memberof AppDefaultViewLayout
     */
    @Prop() public viewInstance!: any;

    /**
     * 模型服务对象
     * 
     * @memberof AppDefaultViewLayout
     */
    @Prop() public modelService!: any;

    /**
     * 视图模型数据
     * 
     * @memberof AppDefaultViewLayout
     */
    @Prop() public model!: any;

    /**
     * 状态传递对象
     *
     * @type {(Subject<any> | undefined)}
     * @memberof AppDefaultViewLayout
     */
    public viewState: Subject<any> | undefined = undefined;

    /**
     * 视图标识
     *
     * @type {string}
     * @memberof AppDefaultViewLayout
     */
    public viewtag: string = '';

    /**
     * 视图名称
     *
     * @type {string}
     * @memberof AppDefaultViewLayout
     */
    public viewCodeName: string = '';

    /**
     * 视图布局面板
     * 
     * @memberof AppDefaultViewLayout
     */
    public viewLayoutPanel?: IPSViewLayoutPanel | null;

    /**
     * 视图代理模式（默认为false）
     *
     * @type {boolean}
     * @memberof AppDefaultViewLayout
     */
    public viewProxyMode: boolean = false;

    /**
     * 视图布局模型
     *
     * @type {*}
     * @memberof AppDefaultViewLayout
     */
    public layoutDetailsModel: any = {};

    /**
     * 面板数据
     *
     * @type {*}
     * @memberof AppDefaultViewLayout
     */
    public layoutData: any = {};

    /**
     * 是否展示视图工具栏
     * 
     * @memberof AppDefaultViewLayout
     */
    public viewIsshowToolbar: boolean = false;

    /**
     * 初始化完成
     *
     * @type {boolean}
     * @memberof AppDefaultViewLayout
     */
    public viewIsInit: boolean = false;

    /**
     * 绘制参数
     *
     * @readonly
     * @memberof AppDefaultViewLayout
     */
    public renderOptions: any = {
        viewClassNames: {}
    };

    /**
     * 是否显示标题栏
     *
     * @readonly
     * @memberof AppDefaultViewLayout
     */
    get showCaption() {
        if (this.viewInstance && this.$parent) {
            return this.viewInstance.showCaptionBar && !(this.$parent as any).noViewCaption
        } else {
            return true;
        }
    }

    /**
     * 视图默认使用(路由：true,非路由：false)
     *
     * @readonly
     * @type {boolean}
     * @memberof AppDefaultViewLayout
     */
    get viewDefaultUsage(): boolean {
        if (this.$parent) {
            return (this.$parent as any).viewDefaultUsage;
        }
        return true;
    }

    /**
     * 初始化视图的绘制参数
     *
     * @memberof AppDefaultViewLayout
     */
    public initRenderOptions(opts: any = {}) {
        this.renderOptions = {};
        const { viewType, viewStyle, codeName } = this.viewInstance;
        const viewClassNames: any = {
            'view-container': true
        };
        if (viewType) {
            Object.assign(viewClassNames, { [viewType?.toLowerCase()]: true });
        }
        if (viewStyle) {
            Object.assign(viewClassNames, { [`view-style-${viewStyle.toLowerCase()}`]: true });
        } else {
            Object.assign(viewClassNames, { [`view-style-default`]: true });
        }
        if (codeName) {
            Object.assign(viewClassNames, { [Util.srfFilePath2(codeName)]: true });
        }
        if (this.viewInstance?.getPSSysCss?.()?.cssName) {
            Object.assign(viewClassNames, { [this.viewInstance.getPSSysCss()?.cssName]: true });
        }
        if (this.viewProxyMode) {
            Object.assign(viewClassNames, { 'isproxy': true });
        }
        if (!this.showCaption) {
            Object.assign(viewClassNames, { 'nocaption': true });
        }
        if (!this.viewIsshowToolbar) {
            Object.assign(viewClassNames, { 'notoolbar': true });
        }
        Object.assign(viewClassNames, opts);
        this.$set(this.renderOptions, 'viewClassNames', viewClassNames);
    }

    /**
     * Vue生命周期，实例创建完成
     *
     * @memberof AppDefaultViewLayout
     */
    public created() {
        this.initViewSpecificData();
        this.initViewLayOutContainer();
    }

    /**
     * Vue生命周期，实例销毁完成
     *
     * @memberof AppDefaultViewLayout
     */
    public destroyed() {
        if (this.viewProxyMode) {
            this.handleContainerPreEvent('onViewDestroyed').then((result: boolean) => {
                if (!result) {
                    return;
                }
                const parentRef: any = this.$parent;
                if (parentRef.viewDefaultUsage) {
                    let localStoreLength = Object.keys(localStorage);
                    if (localStoreLength.length > 0) {
                        localStoreLength.forEach((item: string) => {
                            if (item.startsWith(this.context.srfsessionid)) {
                                localStorage.removeItem(item);
                            }
                        })
                    }
                    if (AppServiceBase.getInstance() && AppServiceBase.getInstance().getAppStore()) {
                        // 清除顶层路由参数
                        AppServiceBase.getInstance().getAppStore().commit('removeRouteViewGlobal', this.context.srfsessionid);
                        // 清除顶层视图
                        AppServiceBase.getInstance().getAppStore().commit('removeView', this.context.srfsessionid);
                    }
                }
                // 清除当前视图
                if (AppServiceBase.getInstance() && AppServiceBase.getInstance().getAppStore()) {
                    if (this.viewInstance && this.viewInstance.modelPath) {
                        AppServiceBase.getInstance().getAppStore().commit('removeView', this.viewInstance.modelPath);
                    }
                }
            })
        }
        this.containerDestroyed();
        this.destroyUIContainer();
    }

    /**
     * 初始化视图特有参数
     *
     * @memberof AppDefaultViewLayout
     */
    public initViewSpecificData() { }

    /**
     * 初始化面板容器
     *
     * @memberof AppDefaultViewLayout
     */
    public async initViewLayOutContainer() {
        this.viewLayoutPanel = this.viewInstance?.getPSViewLayoutPanel();
        if (this.viewLayoutPanel && this.viewLayoutPanel.viewProxyMode) {
            this.viewProxyMode = this.viewLayoutPanel.viewProxyMode;
        }
        // 初始化容器
        this.initUIContainerModel('VIEWLAYOUT', this.viewLayoutPanel);
        // 初始化基础数据
        if (this.viewProxyMode) {
            const parentRef: any = this.$parent;
            this.viewState = parentRef.viewState;
            this.viewtag = parentRef.viewtag;
            this.viewCodeName = parentRef.viewCodeName;
            this.opendata = this.opendata.bind(this);
            this.newdata = this.newdata.bind(this);
            this.engine = appEngineService.getEngine(this.viewInstance.viewType);
        }
        await this.initUIContainerBeforeCtx();
        this.initViewLayoutCtx();
        await this.initUIContainerAfterCtx();
        await this.initViewLayOut();
        // 初始化视图容器样式
        this.initRenderOptions();
        if (this.viewProxyMode) {
            setTimeout(() => {
                this.setContainerIsMounted();
            }, 0);
        }
    }

    /**
     * 容器挂载完成(重写)
     *
     * @memberof AppDefaultViewLayout
     */
    public containerMounted() {
        if (this.viewProxyMode) {
            const _this: any = this;
            super.containerMounted();
            this.$emit('view-event', { viewname: this.viewInstance.name, action: 'viewIsMounted', data: true })
            this.handleContainerPreEvent('onViewMounted').then((result: boolean) => {
                if (!result) {
                    return;
                }
                if (this.engine) {
                    this.engineInit();
                    if (this.engine.loadModel instanceof Function) {
                        this.engine.loadModel();
                    }
                }
                this.$emit('view-event', { viewName: this.viewInstance.codeName, action: 'viewIsInited', data: null });
            })
        }
    }

    /**
     * 执行挂载部件事件拦截（重写）
     *
     * @param {string} eventName 事件名称
     * @param {*} data 数据
     * @memberof ControlContainer
     */
    public exeMountedCtrlEvent(eventName: string, data: any) {
        // 识别导航区占位
        if (eventName && Object.is(eventName, 'selectionchange') && data && data.srfnavdata) {
            const navPos: any = Object.values(this.layoutDetailsModel).find((item: any) => {
                return item.panelItemModel.M?.getPSRawItem?.predefinedType === "NAV_POS";
            })
            if (navPos && navPos.setNavData instanceof Function) {
                navPos.setNavData(data.srfnavdata);
                this.$forceUpdate();
            }
        }
    }

    /**
     * 计算目标部件所需参数(重写)
     *
     * @memberof AppDefaultViewLayout
     */
    public computeTargetCtrlData(controlInstance: any, args?: any) {
        let { targetCtrlName, targetCtrlParam, targetCtrlEvent } = super.computeTargetCtrlData(controlInstance, args);
        Object.assign(targetCtrlParam.staticProps, {
            viewState: this.viewState,
            viewtag: this.viewtag,
            viewIsProxyMode: this.viewProxyMode,
            layoutLoadingService: this.layoutLoadingService
        });
        Object.assign(targetCtrlEvent, {
            closeView: ($event: any) => {
                this.$emit('view-event', { viewName: this.viewInstance.codeName, action: 'viewClosed', data: $event });
            }
        })
        return { targetCtrlName, targetCtrlParam, targetCtrlEvent };
    }

    /**
     * 初始化视图面板应用上下文、视图参数和ctx
     *
     * @memberof AppDefaultViewLayout
     */
    public initViewLayoutCtx() {
        const parentRef: any = this.$parent;
        // 处理应用上下文
        this.context = parentRef?.context ? parentRef.context : {};
        // 处理视图参数
        this.viewparams = parentRef?.viewparams ? parentRef.viewparams : {};
        if (this.viewProxyMode) {
            // 处理ctx
            const tempViewCtx = parentRef?.viewCtx ? parentRef?.viewCtx : {};
            tempViewCtx['view'] = this;
            // 顶层路由视图
            if (parentRef.viewDefaultUsage) {
                if (AppServiceBase.getInstance() && AppServiceBase.getInstance().getAppStore()) {
                    AppServiceBase.getInstance().getAppStore().commit('addView', { tag: this.context.srfsessionid, param: this });
                }
                tempViewCtx['topview'] = this;
            }
            // 处理父级视图
            if (this.viewInstance && this.viewInstance.modelPath) {
                if (AppServiceBase.getInstance() && AppServiceBase.getInstance().getAppStore()) {
                    AppServiceBase.getInstance().getAppStore().commit('addView', { tag: this.viewInstance.modelPath, param: this });
                }
            }
            this.viewCtx = tempViewCtx;
        }
    }

    /**
     * 初始化视图布局
     *
     * @memberof AppDefaultViewLayout
     */
    public async initViewLayOut() {
        const viewToolBar: IPSDEToolbar = ModelTool.findPSControlByType("TOOLBAR", this.viewInstance?.getPSControls());
        if (viewToolBar && viewToolBar.getPSDEToolbarItems()) {
            this.viewIsshowToolbar = true;
        } else {
            this.viewIsshowToolbar = false;
        }
        if (this.viewLayoutPanel && !this.viewLayoutPanel.useDefaultLayout) {
            await this.initDetailsModel(null, this.viewLayoutPanel?.getRootPSPanelItems());
            this.viewIsInit = true;
        } else {
            this.viewIsInit = true;
        }
    }

    /**
     * 初始化面板集合
     *
     * @param {*} parentItem 父容器
     * @param {(IPSPanelItem[] | undefined | null)} [panelItems] 面板项集合
     * @param {number} [_index=0] 下标
     * @param {boolean} [hasMulParent=false] 是否存在多数据容器父成员
     * @memberof AppDefaultViewLayout
     */
    public async initDetailsModel(parentItem: any, panelItems?: IPSPanelItem[] | undefined | null, dataIndex: number = 0, hasMulParent: boolean = false) {
        if (panelItems && panelItems.length > 0) {
            //  父面板成员为多项数据容器时，构建多份子面板成员
            if (parentItem && parentItem.dataRegionType === 'MULTIDATA' && parentItem.getData()?.length > 0) {
                for (let index = 0; index <= parentItem.getData().length - 1; index++) {
                    await this.initDetailsModelItem(parentItem, panelItems, index, true);
                }
            } else {
                await this.initDetailsModelItem(parentItem, panelItems, dataIndex, hasMulParent);
            }
        }
    }

    /**
     * 初始化面板项成员 
     *
     * @param {*} parentItem 父面板项成员
     * @param {any[]} [panelItems=[]] 面板项集合
     * @param {number} [index=0] 标识
     * @param {boolean} [hasMulParent=false] 是否存在多容器父面板项
     * @memberof AppDefaultViewLayout
     */
    public async initDetailsModelItem(parentItem: any, panelItems: any[] = [], index: number = 0, hasMulParent: boolean = false) {
        for (let i = 0; i < panelItems.length; i++) {
            const panelItem: IPSPanelItem = panelItems[i];
            let detailModel: any = {
                context: Util.deepCopy(this.context),
                viewparams: Util.deepCopy(this.viewparams),
                panel: this,
                disabled: false,
                name: panelItem.name,
                caption: panelItem.caption,
                itemType: panelItem.itemType,
                visible: true,
                model: panelItem,
                parentItem: parentItem,
                $index: index,
                hasMulParent: hasMulParent
            };
            let panelItemModel: any;
            switch (panelItem.itemType) {
                case 'BUTTON':
                    const panelButtomItem = panelItem as IPSSysPanelButton
                    Object.assign(detailModel, {
                        uiaction: {
                            type: panelButtomItem.getPSUIAction()?.uIActionType,
                            tag: panelButtomItem.getPSUIAction()?.uIActionTag,
                            actiontarget: panelButtomItem.getPSUIAction()?.actionTarget,
                            noprivdisplaymode: panelButtomItem.getPSUIAction()?.uIActionMode,
                            dataaccaction: panelButtomItem.getPSUIAction()?.dataAccessAction,
                            visible: true,
                            disabled: false
                        }
                    });
                    panelItemModel = new PanelButtonModel(detailModel);
                    break;
                case 'TABPANEL':
                    const tabPages: IPSPanelTabPage[] = (panelItem as IPSPanelTabPanel).getPSPanelTabPages() || [];
                    const pageNames: any[] = [];
                    if (tabPages.length > 0) {
                        tabPages.forEach((page: IPSPanelTabPage) => {
                            pageNames.push({ name: page.name });
                        })
                    }
                    Object.assign(detailModel, {
                        tabPages: pageNames
                    });
                    panelItemModel = new PanelTabPanelModel(detailModel);
                    break;
                case 'TABPAGE':
                    panelItemModel = new PanelTabPageModel(detailModel);
                    break;
                case 'CONTAINER':
                    const dataRegionType = (panelItem as IPSPanelContainer).dataRegionType;
                    if (dataRegionType === 'MULTIDATA' || dataRegionType === 'SINGLEDATA') {
                        new ContainerLoadingService(hasMulParent ? `${panelItem.name}_${index}` : panelItem.name, this.layoutLoadingService);
                    }
                    panelItemModel = new PanelContainerModel(detailModel);
                    break;
                case 'FIELD':
                    panelItemModel = new PanelFieldModel(detailModel);
                    break;
                case 'RAWITEM':
                    panelItemModel = new PanelRawitemModel(detailModel);
                    break;
                case 'CONTROL':
                    panelItemModel = new PanelControlModel(detailModel);
                    break;
                case 'CTRLPOS':
                    panelItemModel = new PanelCtrlPosModel(detailModel);
                    break;
                case 'USERCONTROL':
                    panelItemModel = new PanelUserControlModel(detailModel);
                    break;
            }
            await panelItemModel.loaded();
            // 设置面板模型 （父成员存在多数据容器时拼接下标）
            if (hasMulParent) {
                this.$set(this.layoutDetailsModel, `${panelItem.name}_${index}`, panelItemModel);
            } else {
                this.$set(this.layoutDetailsModel, panelItem.name, panelItemModel);
            }
            // 设置面板数据 （父成员存在多数据容器时拼接下标）
            if (hasMulParent) {
                this.$set(this.layoutData, `${panelItem.name}_${index}`, this.layoutDetailsModel[`${panelItem.name}_${index}`].getData());
            } else {
                this.$set(this.layoutData, panelItem.name, this.layoutDetailsModel[panelItem.name].getData());
            }
            if ((panelItem as any).getPSPanelItems?.()?.length > 0) {
                await this.initDetailsModel(panelItemModel, (panelItem as any)?.getPSPanelItems?.(), index, hasMulParent);
            }
            if ((panelItem as any).getPSPanelTabPages?.()?.length > 0) {
                await this.initDetailsModel(panelItemModel, (panelItem as any)?.getPSPanelTabPages?.(), index, hasMulParent);
            }
        }
    }

    /**
     * @description 切换容器展开状态
     * @param {PanelContainerModel} container 容器类对象
     * @memberof AppDefaultViewLayout
     */
    public switchExtendState(container: PanelContainerModel) {
        if (container.titleBarClose) {
            container.extendState = !container.extendState;
        }
    }

    /**
     * 绘制头部内容
     * 
     * @memberof AppDefaultViewLayout
     */
    public renderViewHeader(): any {
        return [
            <div class="view-header__left">
                {this.showCaption ? <div class="view-header__left__caption">{this.renderViewCaption()}</div> : null}
            </div>,
            this.viewIsshowToolbar && this.$slots.toolbar ? <div class="view-header__right">
                <div class="view-header__right__toolbar">{this.$slots.toolbar}</div>
            </div> : null
        ]
    }

    /**
     * 绘制正文内容
     * 
     * @memberof AppDefaultViewLayout
     */
    public renderViewContent(): any {
        return [
            this.$slots.topMessage ? <div class="view-content__top">
                {this.$slots.topMessage}
            </div> : null,
            <div class="view-content__body">
                {this.$slots.bodyMessage}
                {this.$slots.default}
            </div>,
            this.$slots.bottomMessage ? <div class="view-content__bottom">
                {this.$slots.bottomMessage}
            </div> : null
        ]
    }

    /**
     * 绘制底部内容
     * 
     * @memberof AppDefaultViewLayout
     */
    public renderViewFooter(): any {
        return this.$slots.footer;
    }

    /**
     * 绘制文本绘制模式
     * @param renderMode 文本绘制模式
     * @return {*}  {*}
     * @memberof AppDefaultViewLayout
     */
    public renderViewCaption(renderMode?: any): any {
        const content = this.viewLayoutPanel && !this.viewLayoutPanel.useDefaultLayout ?
            [this.renderCaptionBar(), this.renderDataInfoBar()] :
            [
                this.$slots['layout-captionbar'] ? this.$slots['layout-captionbar'] : this.model?.srfCaption,
                this.$slots['layout-datainfobar'] ? [<span class="view__caption__separate">-</span>, this.$slots['layout-datainfobar']] : this.model.dataInfo ? [<span class="view__caption__separate">-</span>, this.model.dataInfo] : null
            ];
        switch (renderMode) {
            case 'TEXT':
                return <span class="view__caption__info">{content}</span>
            case 'HEADING1':
            case 'HEADING2':
            case 'HEADING3':
            case 'HEADING4':
            case 'HEADING5':
            case 'HEADING6':
                return this.$createElement(`h${renderMode.charAt(renderMode.length - 1)}`,
                    {},
                    content
                );
            case 'PARAGRAPH':
                return <p class="view__caption__info">{content}</p>
            default:
                return <div class="view__caption__info">{content}</div>
        }
    }

    /**
     * 绘制标题栏
     *
     * @return {*} 
     * @memberof AppDefaultViewLayout
     */
    public renderCaptionBar() {
        const captionBar: any = ModelTool.findPSControlByName('captionbar', this.containerModel.getPSControls());
        if (this.containerModel.showCaptionBar && captionBar) {
            return (
                <app-default-captionbar
                    viewModelData={this.containerModel}
                    modelData={captionBar}
                    context={this.context}
                    viewparam={this.viewparams}
                ></app-default-captionbar>
            );
        } else {
            return this.model?.srfCaption;
        }
    }

    /**
     * 绘制信息栏
     *
     * @return {*} 
     * @memberof AppDefaultViewLayout
     */
    public renderDataInfoBar() {
        const datainfoBar: any = ModelTool.findPSControlByName('datainfobar', this.containerModel.getPSControls());
        if (datainfoBar) {
            return [
                <span class="view__caption__separate">-</span>,
                <app-default-datainfobar
                    modelData={datainfoBar}
                    viewInfo={this.model}
                    context={this.context}
                    viewparam={this.viewparams}
                ></app-default-datainfobar>
            ]
        } else {
            return this.model.dataInfo ? [<span class="view__caption__separate">-</span>, this.model.dataInfo] : null
        }
    }

    /**
     * 绘制内容
     * 
     * @memberof AppDefaultViewLayout
     */
    public renderContent() {
        return [
            (this.showCaption || (this.viewIsshowToolbar && this.$slots.toolbar) || this.$slots.quickSearch) && (
                <div class='view-header'>
                    {this.renderViewHeader()}
                </div>
            ),
            <div class='view-content'>
                {this.renderViewContent()}
            </div>,
           this.$slots.footer && (
            <div class="view-footer">
                {this.renderViewFooter()}
            </div>
        )
        ]
    }

    /**
     * 绘制布局
     * 
     * @memberof AppDefaultViewLayout
     */
    public render(h: any) {
        const { viewClassNames } = this.renderOptions;
        return (
            <div class={viewClassNames}>
                <app-studioaction
                    viewInstance={this.viewInstance}
                    context={this.context}
                    viewparams={this.viewparams}
                    viewName={this.viewInstance.codeName.toLowerCase()}
                    viewTitle={this.model?.srfCaption} />
                {this.viewIsInit ? (this.viewLayoutPanel && this.viewLayoutPanel.useDefaultLayout) ? this.renderContent() : this.renderViewLayoutPanel() : this.renderInitLoading()}
            </div>
        );
    }

    /**
     * 渲染初始化loading效果
     *
     * @return {*} 
     * @memberof AppDefaultViewLayout
     */
    public renderInitLoading() {
        return <app-loading></app-loading>
    }

    /**
     * 绘制视图布局面板
     *
     * @memberof AppDefaultViewLayout
     */
    public renderViewLayoutPanel() {
        if ((this.viewLayoutPanel as any)?.layoutBodyOnly) {
            return this.renderLayouBodyOnly();
        } else {
            return this.renderRootPSPanelItems();
        }

    }

    /**
     * 绘制顶级面板成员集合
     *
     * @memberof AppDefaultViewLayout
     */
    public renderRootPSPanelItems() {
        let rootStyle = { height: '100%', width: '100%' };
        let layoutMode = this.viewLayoutPanel?.getPSLayout()?.layout;
        if (layoutMode && layoutMode == 'FLEX') {
            Object.assign(rootStyle, { 'display': 'flex', 'flex-direction': 'column' });
        } else {
            Object.assign(rootStyle, { overflow: 'auto' });
        }
        return <div class="app-view-layout" style={rootStyle}>
            {this.viewLayoutPanel?.getRootPSPanelItems()?.map((panelItem: any) => {
                return this.renderByDetailType(panelItem);
            })}
        </div>
    }

    /**
    * 仅布局内容区模式绘制
    *
    * @memberof AppDefaultViewLayout
    */
    public renderLayouBodyOnly() {
        return [
            (this.showCaption || (this.viewIsshowToolbar && this.$slots.toolbar) || this.$slots.quickSearch) && (
                <div class='view-header'>
                    {this.renderViewHeader()}
                </div>
            ),
            <div class='view-content'>
                {this.$slots.topMessage ? <div class="view-content__top">
                    {this.$slots.topMessage}
                </div> : null}
                <div class="view-content__body">
                    {this.$slots.bodyMessage}
                    {this.renderRootPSPanelItems()}
                </div>
                {this.$slots.bottomMessage ? <div class="view-content__bottom">
                    {this.$slots.bottomMessage}
                </div> : null}
            </div>
        ];
    }

    /**
     * 根据detailType绘制对应detail
     *
     * @param {*} modelJson
     * @memberof AppDefaultViewLayout
     */
    public renderByDetailType(modelJson: any, parent?: any, index?: number) {
        if (modelJson.getPSSysPFPlugin()) {
            const pluginInstance: any = PluginService.getInstance().getPluginInstance("CONTROLITEM", modelJson.getPSSysPFPlugin().pluginCode);
            if (pluginInstance) {
                return pluginInstance.renderCtrlItem(this.$createElement, modelJson, this, this.context);
            }
        }
        switch (modelJson.itemType) {
            case 'CONTAINER':
                return this.renderContainer(modelJson, parent, index);
            case 'TABPANEL':
                return this.renderTabPanel(modelJson, parent, index);
            case 'TABPAGE':
                return this.renderTabPage(modelJson, index);
            case 'FIELD':
                return this.renderField(modelJson, index);
            case 'RAWITEM':
                return this.renderRawItem(modelJson, index);
            case 'BUTTON':
                return this.renderButton(modelJson, index);
            case 'CTRLPOS':
                return this.renderCtrlPos(modelJson, parent, index);
            case 'USERCONTROL':
                return this.renderUserControl(modelJson, parent, index);
            default:
                return <span>{`${modelJson.itemType} 类型未支持`}</span>
        }
    }

    /**
     * 绘制面板Container
     *
     * @memberof AppDefaultViewLayout
     */
    public renderContainer(container: IPSPanelContainer, parent?: any, index?: number) {
        const panelItems: IPSPanelItem[] = container.getPSPanelItems() || [];
        let name: string = `${container.name}${index === undefined || index === null ? '' : '_' + index}`;
        //  父容器为多数据容器
        let hasMulParent: boolean = false;
        if (index !== undefined || index !== null) {
            hasMulParent = true;
        }
        if (!this.layoutDetailsModel[name]) {
            return null;
        }
        const layout = container.getPSLayout()?.layout;
        // 盒子自身应有样式
        const detailStyle = {};
        // 获取布局设置(约束子,如：flex布局及相关设置)
        const boxLayoutStyle = this.layoutDetailsModel[name].getBoxLayoutStyle();
        Object.assign(detailStyle, boxLayoutStyle);
        // 获取盒子宽高/间隔模式
        const boxStyle = this.layoutDetailsModel[name].getBoxStyle();
        Object.assign(detailStyle, boxStyle);
        // 获取盒子样式表
        const detailClass = this.layoutDetailsModel[name]?.getDetailClass();
        // 合并盒子动态样式表
        if(container.dynaClass){
            const context = this.context;
            const viewparams = this.viewparams;
            const data = this.layoutData[name];
            detailClass.push(...eval(container.dynaClass))
        }
        if (layout && Object.is(layout, 'BORDER')) {
            //  存在三种情况(1：该容器为多数据容器; 2: 父容器为多数据容器; 3: 正常容器)
            return (
                <div style={detailStyle} class={[detailClass, "app-view-layout__container"]} onClick={(event: any) => { this.handlePanelItemEvent(container.name, name, 'onclick', { hasMulParent, index, event }) }}>
                    {container.dataRegionType === 'MULTIDATA' && this.layoutDetailsModel[name]?.getData()?.length > 0 ?
                        // this.layoutDetailsModel[name]?.getData().map((data: any, index: number) => {
                        //     return <app-scroll-container panelItems={panelItems}>{this.renderChildItems(container, panelItems, index)}</app-scroll-container>;
                        // })
                        <div>多数据容器下不能嵌入边缘布局容器</div> : hasMulParent ?
                            <app-scroll-container panelItems={panelItems}>{this.renderChildItems(container, panelItems, index)}</app-scroll-container> :
                            <app-scroll-container panelItems={panelItems}>{this.renderChildItems(container, panelItems)}</app-scroll-container>}
                </div>
            )
        } else if (layout && Object.is(layout, 'FLEX')) {
            //  存在三种情况(1：该容器为多数据容器; 2: 父容器为多数据容器; 3: 正常容器)
            return (
                <div style={container.showCaption ? '' : detailStyle} class={[detailClass, "app-view-layout__container"]} onClick={(event: any) => { this.handlePanelItemEvent(container.name, name, 'onclick', { hasMulParent, index, event }) }} >
                    {container.showCaption ? <row class="app-view-layout__container__header">
                        <span>{this.$tl(container.getCapPSLanguageRes?.()?.lanResTag, container.caption)}</span>
                        {this.layoutDetailsModel[name].titleBarClose ? <i class={{ 'header__caption': true, 'el-icon-arrow-down': this.layoutDetailsModel[name].extendState, 'el-icon-arrow-right': !this.layoutDetailsModel[name].extendState }} on-click={() => this.switchExtendState(this.layoutDetailsModel[name])}></i> : null}
                    </row> : null}
                    {
                        container.showCaption ?
                            <div style={{ ...detailStyle, 'display': !this.layoutDetailsModel[name].titleBarClose || (this.layoutDetailsModel[name].titleBarClose && this.layoutDetailsModel[name].extendState) ? 'block' : 'none' }} class="layout__content">
                                {container.dataRegionType === 'MULTIDATA' && this.layoutDetailsModel[name]?.getData()?.length > 0 ?
                                    this.layoutDetailsModel[name]?.getData().map((data: any, index: number) => {
                                        return this.renderChildItems(container, panelItems, index);
                                    }) : hasMulParent ? this.renderChildItems(container, panelItems, index) : this.renderChildItems(container, panelItems)}
                            </div> :
                            container.dataRegionType === 'MULTIDATA' && this.layoutDetailsModel[name]?.getData()?.length > 0 ?
                                this.layoutDetailsModel[name]?.getData().map((data: any, index: number) => {
                                    return this.renderChildItems(container, panelItems, index);
                                }) : hasMulParent ? this.renderChildItems(container, panelItems, index) : this.renderChildItems(container, panelItems)
                    }
                </div>
            );
        } else if (layout && Object.is(layout, 'SIMPLEFLEX')) {
            //  存在三种情况(1：该容器为多数据容器; 2: 父容器为多数据容器; 3: 正常容器)
            return (
                <div style={container.showCaption ? '' : detailStyle} class={[detailClass, "app-view-layout__container"]} onClick={(event: any) => { this.handlePanelItemEvent(container.name, name, 'onclick', { hasMulParent, index, event }) }} >
                    {container.showCaption ? <row class="app-view-layout__container__header">
                        <span>{this.$tl(container.getCapPSLanguageRes?.()?.lanResTag, container.caption)}</span>
                        {this.layoutDetailsModel[name].titleBarClose ? <i class={{ 'header__caption': true, 'el-icon-arrow-down': this.layoutDetailsModel[name].extendState, 'el-icon-arrow-right': !this.layoutDetailsModel[name].extendState }} on-click={() => this.switchExtendState(this.layoutDetailsModel[name])}></i> : null}
                    </row> : null}
                    {
                        container.showCaption ?
                            <div style={{ ...detailStyle, 'display': !this.layoutDetailsModel[name].titleBarClose || (this.layoutDetailsModel[name].titleBarClose && this.layoutDetailsModel[name].extendState) ? 'block' : 'none' }} class="app-view-layout__container__content">
                                {container.dataRegionType === 'MULTIDATA' && this.layoutDetailsModel[name]?.getData()?.length > 0 ?
                                    this.layoutDetailsModel[name]?.getData().map((data: any, index: number) => {
                                        return <app-simpleflex-container inMulParent={true} panelItems={panelItems} index={index} renderCallBack={this.renderByDetailType.bind(this)}></app-simpleflex-container>;
                                    }) : hasMulParent ? <app-simpleflex-container panelItems={panelItems} index={index} renderCallBack={this.renderByDetailType.bind(this)}></app-simpleflex-container> : <app-simpleflex-container panelItems={panelItems} renderCallBack={this.renderByDetailType.bind(this)}></app-simpleflex-container>
                                }
                            </div> :
                            container.dataRegionType === 'MULTIDATA' && this.layoutDetailsModel[name]?.getData()?.length > 0 ?
                                this.layoutDetailsModel[name]?.getData().map((data: any, index: number) => {
                                    return <app-simpleflex-container inMulParent={true} panelItems={panelItems} index={index} renderCallBack={this.renderByDetailType.bind(this)}></app-simpleflex-container>
                                }) : hasMulParent ? <app-simpleflex-container panelItems={panelItems} index={index} renderCallBack={this.renderByDetailType.bind(this)}></app-simpleflex-container> : <app-simpleflex-container panelItems={panelItems} renderCallBack={this.renderByDetailType.bind(this)}></app-simpleflex-container>
                    }
                </div>
            );
        } else {
            //  存在三种情况(1：该容器为多数据容器; 2: 父容器为多数据容器; 3: 正常容器)
            return (
                <row style={detailStyle} class={[detailClass, "app-view-layout__container"]} nativeOn={{ 'click': (event: any) => { this.handlePanelItemEvent(container.name, name, 'onclick', { hasMulParent, index, event }) } }}>
                    {container.showCaption ? <row class="app-view-layout__container__header">
                        <span>{this.$tl(container.getCapPSLanguageRes?.()?.lanResTag, container.caption)}</span>
                        {this.layoutDetailsModel[name].titleBarClose ? <i class={{ 'header__caption': true, 'el-icon-arrow-down': this.layoutDetailsModel[name].extendState, 'el-icon-arrow-right': !this.layoutDetailsModel[name].extendState }} on-click={() => this.switchExtendState(this.layoutDetailsModel[name])}></i> : null}
                    </row> : null}
                    <div style={{ ...detailStyle, 'display': !this.layoutDetailsModel[name].titleBarClose || (this.layoutDetailsModel[name].titleBarClose && this.layoutDetailsModel[name].extendState) ? 'block' : 'none' }} class="app-view-layout__container__content">
                        {
                            container.dataRegionType === 'MULTIDATA' && this.layoutDetailsModel[name]?.getData()?.length > 0 ?
                                this.layoutDetailsModel[name]?.getData().map((data: any, index: number) => {
                                    return this.renderChildItems(container, panelItems, index);
                                }) : hasMulParent ? this.renderChildItems(container, panelItems, index) : this.renderChildItems(container, panelItems)
                        }
                    </div>
                </row>
            );
        }
    }

    /**
     * 渲染子项
     *
     * @param {IPSPanelContainer} parent 父容器模型
     * @param {IPSPanelItem[]} panelItems 父容器下所有子项
     * @param {number} [index] 多数据域下标
     * @return {*} 
     * @memberof AppDefaultViewLayout
     */
    public renderChildItems(parent: IPSPanelContainer, panelItems: IPSPanelItem[], index?: number) {
        if (!parent || !panelItems || (panelItems.length === 0)) {
            return null;
        }
        const layout = parent.getPSLayout()?.layout;
        return panelItems.map((item: any) => {
            const name = `${item.name}${index === undefined || index === null ? '' : '_' + index}`;
            const childDetailStyle: any = {};
            if (Object.is(layout, 'BORDER')) {
                Object.assign(childDetailStyle, this.layoutDetailsModel[name]?.getBorderLayoutStyle());
            } else {
                Object.assign(childDetailStyle, this.layoutDetailsModel[name]?.getBoxLayoutPosStyle());
            }
            // 多数据容器下多数据部件只绘制一个
            if (this.layoutDetailsModel[name]?.isEnableMount === false) {
                return null;
            }
            // 隐藏属性项不绘制
            if (Object.is(item.itemType, 'FIELD') && (item as IPSSysPanelField).hidden) {
                return null;
            }
            if (Object.is(layout, 'BORDER')) {
                return (
                    <div style={childDetailStyle} slot={item.name} class={'app-view-layout__container__item'}>
                        {this.renderByDetailType(item, parent, index)}
                    </div>
                );
            } else if (Object.is(layout, 'FLEX')) {
                return (
                    <div style={childDetailStyle} class={'app-view-layout__container__item'} >
                        {this.renderByDetailType(item, parent, index)}
                    </div>
                );
            } else if (Object.is(layout, 'TABLE_12COL') || Object.is(layout, 'TABLE_24COL')) {
                const attrs = this.layoutDetailsModel[name]?.getGridLayoutProps(item, layout);
                return (
                    <i-col {...{ props: attrs }} style={childDetailStyle} class={'app-view-layout__container__item'}>
                        {this.renderByDetailType(item, parent, index)}
                    </i-col>
                );
            }
        })
    }

    /**
     * 绘制面板TabPanel
     *
     * @memberof AppDefaultViewLayout
     */
    public renderTabPanel(modelJson: IPSPanelTabPanel, parent?: any, index?: number) {
        const name: string = !this.layoutDetailsModel[`${modelJson.name}_${index}`] ? modelJson.name : `${modelJson.name}_${index}`;
        if (!this.layoutDetailsModel[name]) {
            return null;
        }
        const tabPages: IPSPanelTabPage[] = modelJson.getPSPanelTabPages() || [];
        const activedTabPage: any = this.layoutDetailsModel[name]?.activatedPage;
        const detailClass = this.layoutDetailsModel[name]?.getDetailClass();
        const detailStyle = this.layoutDetailsModel[name].getBoxStyle();
        return (
            <el-tabs
                value={activedTabPage}
                class={detailClass}
                style={parent ? {} : detailStyle}
                on-tab-click={(event: any) => { this.handlePanelItemEvent(modelJson.name, name, 'onclick', { index, event }) }}
            >
                {tabPages.length > 0 ?
                    tabPages.map((item: IPSPanelTabPage) => {
                        return this.renderTabPage(item, index);
                    }) : null}
            </el-tabs>
        );
    }

    /**
     * 绘制面板TabPage
     *
     * @memberof AppDefaultViewLayout
     */

    public renderTabPage(modelJson: IPSPanelTabPage, index?: number) {
        let name: string = !this.layoutDetailsModel[`${modelJson.name}_${index}`] ? modelJson.name : `${modelJson.name}_${index}`;
        if (!this.layoutDetailsModel[name]) {
            return null;
        }
        let detailClass = this.layoutDetailsModel[name]?.getDetailClass();
        let label = this.$tl(modelJson.getCapPSLanguageRes?.()?.lanResTag, modelJson.caption);
        const panelItems: IPSPanelItem[] = modelJson.getPSPanelItems() || [];
        return (
            <el-tab-pane label={label} name={modelJson.name} class={detailClass}>
                {this.renderChildItems(modelJson, panelItems, index)}
            </el-tab-pane>
        );
    }

    /**
     * 绘制面板Field
     *
     * @memberof AppDefaultViewLayout
     */
    public renderField(modelJson: IPSSysPanelField, index?: number) {
        const { caption, hidden, showCaption } = modelJson;
        //  存在多份属性模型时根据下标获取对应 name
        const name: string = !this.layoutDetailsModel[`${modelJson.name}_${index}`] ? modelJson.name : `${modelJson.name}_${index}`;
        if (!this.layoutDetailsModel[name]) {
            return null;
        }
        const detailClass = this.layoutDetailsModel[name]?.getDetailClass();
        const detailStyle = this.layoutDetailsModel[name].getBoxStyle();
        const editor: any = modelJson.getPSEditor();
        const labelPos = 'LEFT';
        return (
            !hidden && (
                <app-panel-field
                    name={name}
                    labelPos={labelPos}
                    caption={this.$tl(modelJson.getCapPSLanguageRes()?.lanResTag, caption)}
                    isEmptyCaption={!showCaption}
                    class={detailClass}
                    style={detailStyle}
                    data={this.layoutData}
                    value={this.layoutData[name]}
                >
                    {editor && (
                        <app-default-editor
                            value={this.layoutData[name]}
                            editorInstance={editor}
                            containerCtrl={this.viewInstance}
                            containerComponent={this}
                            parentItem={modelJson}
                            contextData={this.layoutData}
                            context={this.context}
                            viewparams={this.viewparams}
                            disabled={false}
                            on-change={(event: any) => {
                                this.onValueChange(modelJson.name, event);
                            }}
                            on-enter={(event: any) => {
                                this.onEnter(modelJson.name, event);
                            }}
                            on-blur={(event: any) => {
                                this.onLeave(modelJson.name, event);
                            }}
                            on-error={(event: string) => {
                                this.onError(event);
                            }}
                        />
                    )}
                </app-panel-field>
            )
        );
    }

    /**
     * 值变化
     *
     * @param {*} $event
     * @memberof AppDefaultViewLayout
     */
    public async onValueChange(tag: string, event: any) {
        const { name, value } = event;
        const result = await this.handlePanelItemEvent(tag, name, 'onvaluechange', { oldvalue: this.layoutData[name], value });
        if (result && result?.hasOwnProperty('srfret') && !result.srfret) {
            return;
        }
        this.layoutData[name] = value;
        if (this.layoutDetailsModel && this.layoutDetailsModel[name]) {
            this.layoutDetailsModel[name].setData(value);
        }
    }

    /**
     * 回车事件
     *
     * @param {string} tag
     * @param {*} event
     * @return {*} 
     * @memberof AppDefaultViewLayout
     */
    public async onEnter(tag: string, enterEvent: any) {
        const { name, event, value } = enterEvent;
        const result = await this.handlePanelItemEvent(tag, name, 'onenter', { event, value });
        if (result && result?.hasOwnProperty('srfret') && !result.srfret) {
            return;
        }
    }

    /**
     * 失去焦点事件
     *
     * @param {string} tag
     * @param {*} event
     * @return {*} 
     * @memberof AppDefaultViewLayout
     */
    public async onLeave(tag: string, leaveEvent: any) {
        const { name, event, value } = leaveEvent;
        const result = await this.handlePanelItemEvent(tag, name, 'onleave', { event, value });
        if (result && result?.hasOwnProperty('srfret') && !result.srfret) {
            return;
        }
    }

    /**
     * 处理错误信息事件
     *
     * @param {*} $event
     * @memberof AppDefaultViewLayout
     */
    public onError(errorMsg: string) {
        let errorMsgItemName = '';
        Object.keys(this.layoutDetailsModel).forEach((key: string) => {
            if (this.layoutDetailsModel[key]?.itemType === 'FIELD' && this.layoutDetailsModel[key]?.isErrorMsgItem) {
                errorMsgItemName = this.layoutDetailsModel[key].name;
            }
        })
        if (errorMsgItemName) {
            this.onValueChange(errorMsgItemName, { name: errorMsgItemName, value: errorMsg });
            return;
        }
        this.$throw(errorMsg)
    }

    /**
     * 绘制面板Rawitem
     *
     * @memberof AppDefaultViewLayout
     */
    public renderRawItem(modelJson: IPSPanelRawItem, index?: number) {
        const { contentType } = modelJson;
        const name: string = !this.layoutDetailsModel[`${modelJson.name}_${index}`] ? modelJson.name : `${modelJson.name}_${index}`;
        if (!this.layoutDetailsModel[name]) {
            return null;
        }
        const rawItemDetail = modelJson.M.getPSRawItem;
        if (rawItemDetail.predefinedType) {
            return this.renderPredefinedRawItem(name, modelJson, index);
        }
        const detailClass = this.layoutDetailsModel[name]?.getDetailClass();
        const detailStyle = this.layoutDetailsModel[name]?.getBoxStyle();
        const sysImage = modelJson.getPSSysImage()?.cssClass;
        let sysImgurl = modelJson.getPSSysImage()?.imagePath;
        if (modelJson.getPSSysImage()?.rawContent) {
            sysImgurl = modelJson.getPSSysImage()?.rawContent;
        }
        const content = this.layoutData[name];
        return (
            <app-rawitem
                style={detailStyle}
                class={detailClass}
                rawItemDetail={rawItemDetail}
                viewparams={this.viewparams}
                context={this.context}
                contentType={contentType}
                imageClass={sysImage}
                imgUrl={sysImgurl}
                content={content}
                modelService={this.modelService}
                nativeOn={{ 'click': (event: any) => { this.handlePanelItemEvent(modelJson.name, name, 'onclick', { index, event }) } }}
            >
            </app-rawitem>
        );
    }

    /**
     *  渲染预定义直接内容
     *
     * @param {string} name
     * @param {IPSPanelRawItem} modelJson
     * @param {number} [index]
     * @return {*} 
     * @memberof AppDefaultViewLayout
     */
    public renderPredefinedRawItem(name: string, modelJson: IPSPanelRawItem, index?: number) {
        const detailClass = this.layoutDetailsModel[name]?.getDetailClass();
        const detailStyle = this.layoutDetailsModel[name]?.getBoxStyle();
        return (
            <app-preset-rawitem
                key={name}
                class={detailClass}
                style={detailStyle}
                detailModel={this.layoutDetailsModel[name]}
                context={this.context}
                viewparams={this.viewparams}
                rawItemDetail={modelJson.M.getPSRawItem}
                navData={this.layoutDetailsModel[name]?.getNavData()}
                type={modelJson.M.getPSRawItem.predefinedType}
                value={this.layoutData[name]}
                nativeOn={{ 'click': (event: any) => { this.handlePanelItemEvent(modelJson.name, name, 'onclick', { index, event }) } }}
            ></app-preset-rawitem>
        )
    }

    /**
     * 渲染容器默认工具栏(重写)
     *
     * @memberof AppDefaultViewLayout
     */
    public renderToolBar() {
        if (!(this.toolbarModels && this.toolbarModels.length > 0)) {
            return null;
        }
        return (
            <view-toolbar
                mode={this.viewInstance?.viewStyle || 'DEFAULT'}
                counterServiceArray={this.counterServiceArray}
                isViewLoading={this.layoutLoadingService?.isLoading}
                toolbarModels={this.toolbarModels}
                on-item-click={(data: any, $event: any) => {
                    throttle(this.handleItemClick, [data, $event], this);
                }}
            ></view-toolbar>
        );
    }

    /**
     * 绘制按钮
     *
     * @param {IPSPanelButton} modelJson
     * @return {*} 
     * @memberof AppDefaultViewLayout
     */
    public renderButton(modelJson: IPSPanelButton, index?: number) {
        const name: string = !this.layoutDetailsModel[`${modelJson.name}_${index}`] ? modelJson.name : `${modelJson.name}_${index}`;
        if (!this.layoutDetailsModel[name]) {
            return null;
        }
        const detailClass = this.layoutDetailsModel[name]?.getDetailClass();
        const detailStyle = this.layoutDetailsModel[name].getBoxStyle();
        return (
            <app-model-button
                id={name}
                data={this.layoutData}
                modelJson={modelJson}
                dynaStyle={detailStyle}
                dynaClass={detailClass}
                disabled={this.layoutDetailsModel[name]?.disabled}
                loading={this.layoutLoadingService.getIsLoading(this.layoutDetailsModel[name].parentDataContainerName)}
                on-onClick={(event: any) => {
                    debounce(this.handleButtonClick, [{ tag: modelJson.name, name, event }], 300);
                }}
            >
            </app-model-button>
        );
    }

    /**
     * 处理按钮点击
     *
     * @memberof AppDefaultViewLayout
     */
    public async handleButtonClick(inputParam: any) {
        const { tag, name, event } = inputParam;
        const data = this.layoutDetailsModel[name].getData() ? this.layoutDetailsModel[name].getData() : {};
        const result = await this.handlePanelItemEvent(tag, name, 'onclick', { value: data, event });
        if (result && result?.hasOwnProperty('srfret') && !result.srfret) {
            return;
        }
        AppViewLogicService.getInstance().executeViewLogic(`layoutpanel_${tag}_click`, event, this, data, (this.viewLayoutPanel as any)?.getPSAppViewLogics());

    }

    /**
     * 绘制控件占位
     *
     * @memberof AppDefaultViewLayout
     */
    public renderCtrlPos(modelJson: any, parent?: any, index?: any) {
        const tag = modelJson.name;
        const name: string = !this.layoutDetailsModel[`${modelJson.name}_${index}`] ? modelJson.name : `${modelJson.name}_${index}`;
        if (!this.layoutDetailsModel[name] || (this.layoutDetailsModel[name]?.isEnableMount === false)) {
            return null;
        }
        const detailClass = this.layoutDetailsModel[name]?.getDetailClass();
        const detailStyle = this.layoutDetailsModel[name].getBoxStyle();
        if (this.viewProxyMode) {
            const appControls = this.viewLayoutPanel?.getPSControls() as (IPSControl[] | null);
            const targetControl = ModelTool.findPSControlByName(tag, appControls);
            const args = { staticProps: { localSourceTag: this.layoutDetailsModel[name].dataSourceTag }, dynamicProps: { context: this.layoutDetailsModel[name].context } };
            if (targetControl) {
                return <div class={detailClass} style={detailStyle}>
                    {this.renderTargetControl(targetControl, false, args)}
                </div>
            }
        } else {
            return <div class={detailClass} style={detailStyle}>
                {this.$slots[`layout-${tag}`]}
            </div>
        }
    }

    /**
    * 绘制用户部件
    *
    * @param {*} modelJson 模型
    * @memberof AppDefaultViewLayout
    */
    public renderUserControl(modelJson: any, parent?: any, index?: any) {
        const name: string = !this.layoutDetailsModel[`${modelJson.name}_${index}`] ? modelJson.name : `${modelJson.name}_${index}`;
        const detailClass = this.layoutDetailsModel[name]?.getDetailClass();
        const detailStyle = this.layoutDetailsModel[name].getBoxStyle();
        return <app-user-control style={detailStyle} class={detailClass} modelJson={modelJson} parent={parent} index={index} on-valueChange={(event: any) => {
            this.onValueChange(modelJson.name, event);
        }} />
    }

    /**
     * 处理面板项事件
     *
     * @param {string} tag 标识
     * @param {string} name 项名称
     * @param {string} eventName 事件名称
     * @param {*} args 附加参数
     * @memberof AppDefaultViewLayout
     */
    public async handlePanelItemEvent(tag: string, name: string, eventName: string, args?: any) {
        const tempTag: string = `${tag.toLowerCase()}-${eventName.toLowerCase()}`;
        if (this.containerTriggerLogicMap.get(tempTag)) {
            if (args?.event) {
                args.event.stopPropagation();
            }
            const data = { value: this.layoutDetailsModel[name].getData(), data: this.layoutData };
            if (args && (Object.keys(args).length > 0)) {
                Object.assign(data, args);
            }
            const result = await this.containerTriggerLogicMap.get(tempTag).executeAsyncUILogic({ arg: { sender: this, navContext: this.context, navParam: this.viewparams, navData: this.navdatas, data: data, args: args }, utils: this.viewCtx, app: this.viewCtx.app, view: this });
            return result;
        }
    }

    /**
     * 强制刷新
     * 
     * @memberof AppDefaultViewLayout
     */
    public async forceRefresh() {
        await this.initDetailsModel(null, this.viewLayoutPanel?.getRootPSPanelItems());
        this.$forceUpdate();
    }
}