import { Emit, Prop, Watch } from 'vue-property-decorator'; import { Util } from 'ibiz-core'; import { MobPortletControlBase } from '../../../widgets'; import { AppViewLogicService } from '../../../app-service'; import { IPSDBAppViewPortletPart, IPSDBCustomPortletPart, IPSDBHtmlPortletPart, IPSDBRawItemPortletPart, IPSLanguageRes, IPSUIActionGroupDetail } from '@ibiz/dynamic-model-api'; /** * 门户部件部件基类 * * @export * @class AppMobPortletBase * @extends {MobPortletControlBase} */ export class AppMobPortletBase extends MobPortletControlBase { /** * 部件动态参数 * * @memberof AppMobPortletBase */ @Prop() public declare dynamicProps: any; /** * 部件静态参数 * * @memberof AppMobPortletBase */ @Prop() public declare staticProps: any; /** * 监听部件动态参数变化 * * @param {*} newVal * @param {*} oldVal * @memberof AppMobPortletBase */ @Watch('dynamicProps', { immediate: true, }) public onDynamicPropsChange(newVal: any, oldVal: any) { if (newVal && !Util.isFieldsSame(newVal, oldVal)) { super.onDynamicPropsChange(newVal, oldVal); } } /** * 监听部件静态参数变化 * * @param {*} newVal * @param {*} oldVal * @memberof AppMobPortletBase */ @Watch('staticProps', { immediate: true, }) public onStaticPropsChange(newVal: any, oldVal: any) { if (newVal && !Util.isFieldsSame(newVal, oldVal)) { super.onStaticPropsChange(newVal, oldVal); } } /** * 销毁视图回调 * * @memberof AppMobPortletBase */ public destroyed() { this.ctrlDestroyed(); } /** * 部件事件 * * @param {{ controlname: string; action: string; data: any }} { controlname 部件名称, action 事件名称, data 事件参数 } * @memberof AppMobPortletBase */ @Emit('ctrl-event') public ctrlEvent({ controlname, action, data }: { controlname: string; action: string; data: any }): void { } /** * 绘制其他部件 * * @returns * @memberof AppMobPortletBase */ public renderControl() { if (this.controlInstance.getPSControls()?.length) { let control = this.controlInstance.getPSControls()?.[0]; let { targetCtrlName, targetCtrlParam, targetCtrlEvent } = this.computeTargetCtrlData(control); return this.$createElement(targetCtrlName, { props: targetCtrlParam, ref: control?.name, on: targetCtrlEvent, style: this.controlStyle }) } } /** * 绘制直接内容 * * @returns * @memberof AppMobPortletBase */ public renderRawItem() { const { rawItemHeight, rawItemWidth, contentType, rawContent, htmlContent } = this.controlInstance as IPSDBRawItemPortletPart; const detailCss = this.controlInstance.getPSSysCss()?.cssName; const rawItemDetail = this.controlInstance.M?.getPSRawItem; const imageDetail = { imageClass: this.controlInstance.getPSSysImage()?.cssClass, imagePath: this.controlInstance.getPSSysImage()?.imagePath }; let content: any; if (Object.is(contentType, 'RAW')) { content = rawContent; } else if (Object.is(contentType, 'HTML')) { content = htmlContent; } if (content) { const items = content.match(/\{{(.+?)\}}/g); if (items) { items.forEach((item: string) => { content = content.replace(/\{{(.+?)\}}/, eval(item.substring(2, item.length - 2))); }); } content = content.replaceAll('<', '<'); content = content.replaceAll('>', '>'); content = content.replaceAll('&nbsp;', ' '); content = content.replaceAll(' ', ' '); } return ( <app-rawitem context={this.context} viewparams={this.viewparams} class={detailCss} style={this.controlStyle} contentType={contentType} content={content} rawItemDetail={rawItemDetail} imageDetail={imageDetail}> </app-rawitem> ); } /** * 绘制HTML * * @returns * @memberof AppMobPortletBase */ public renderHtml() { let { pageUrl, height } = this.controlInstance as IPSDBHtmlPortletPart; height = height > 0 ? height : 400; let iframeStyle = `height: ${height}px; width: 100%; border-width: 0px;`; return <iframe src={pageUrl} style={iframeStyle}></iframe>; } /** * 绘制工具栏栏 todo需支持视图内部工具栏 * * @returns * @memberof AppMobPortletBase */ public renderToolBar() { return <div>暂不支持工具栏</div> } /** * 绘制操作栏 * * @returns * @memberof AppMobPortletBase */ public renderActionBar() { return <div>暂不支持操作栏</div> } /** * 绘制自定义 * * @returns * @memberof AppMobPortletBase */ public renderCustom() { let plugin = (this.controlInstance as IPSDBCustomPortletPart)?.getPSSysPFPlugin?.(); // todo自定义绘制 if (plugin) { // todo 自定义门户部件 } else { return <div>{this.$t('app.portlet.noExtensions')}</div>; } } /** * 绘制应用菜单 * * @returns * @memberof AppMobPortletBase */ public renderAppMenu() { let menuInstance = this.controlInstance.getPSControls()?.[0]; if (menuInstance) { let { targetCtrlName, targetCtrlParam, targetCtrlEvent } = this.computeTargetCtrlData(menuInstance); Object.assign(targetCtrlParam.staticProps, { controlStyle: menuInstance.controlStyle || 'ICONVIEW' }) return this.$createElement(targetCtrlName, { props: targetCtrlParam, ref: menuInstance.name, on: targetCtrlEvent, style: this.controlStyle }); } } /** * 绘制视图 * * @returns * @memberof AppMobPortletBase */ public renderView() { let portletAppView = (this.controlInstance as IPSDBAppViewPortletPart)?.getPortletPSAppView(); if (!portletAppView) { return; } const { modelFilePath, name } = portletAppView; Object.assign(this.context, { viewpath: modelFilePath }) return this.$createElement('app-view-shell', { props: { staticProps: { inputState: this.viewState, viewDefaultUsage: 'INCLUDEDVIEW', viewModelData: portletAppView, }, dynamicProps: { _context: JSON.stringify(this.context), _viewparam: JSON.stringify(this.viewparams), }, }, on: { 'viewIsMounted': () => { this.setIsMounted(portletAppView?.name); } }, class:"view-container2", style:this.controlStyle, ref: name, }); } /** * 根据portletType绘制 * * @returns * @memberof AppMobPortletBase */ public renderByPortletType() { switch (this.controlInstance.portletType) { case 'VIEW': return this.renderView(); case 'APPMENU': return this.renderAppMenu(); case 'CUSTOM': return this.renderCustom(); case 'ACTIONBAR': return this.renderActionBar(); case 'TOOLBAR': return this.renderToolBar(); case 'HTML': return this.renderHtml(); case 'RAWITEM': return this.renderRawItem(); default: return this.renderControl(); } } /** * 绘制标题 * * @returns * @memberof AppMobPortletBase */ public renderTitle() { let labelCaption: any = this.$tl((this.controlInstance.getTitlePSLanguageRes() as IPSLanguageRes)?.lanResTag, this.controlInstance.title); return <ion-list-header class="app-control-portlet__header"> {<span >{labelCaption}</span>} {this.renderUIActionGroup()} </ion-list-header> } /** * 绘制界面行为组 * * @return {*} * @memberof AppMobPortletBase */ public renderUIActionGroup() { if (!this.actionBarModelData) { return; } return this.actionBarModelData.length > 1 ? <div class="header__right"> <app-mob-icon class="header__right__icon" name="ellipsis-horizontal-outline" on-onClick={() => { this.selectStatus = true }}></app-mob-icon> </div> : this.actionBarModelData.length > 0 ? <div class="header__right" on-click={() => { this.handleItemClick(this.actionBarModelData[0], null) }}>{this.actionBarModelData[0].name}</div> : null } /** * 绘制界面行为图标 * * @param {*} actionDetail 界面行为组成员 * @returns * @memberof AppMobPortletBase */ public renderIcon(actionDetail: IPSUIActionGroupDetail) { const { showIcon } = actionDetail; const uiAction = actionDetail.getPSUIAction(); if (showIcon && uiAction?.getPSSysImage()) { let image = uiAction.getPSSysImage(); if (image?.cssClass) { return <i class={image?.cssClass} /> } else { return <img src={image?.imagePath} /> } } } /** * 处理操作列点击 * * @memberof GridControlBase */ public handleActionClick(event: any, detail: any) { const { name } = this.controlInstance; let data = Util.deepCopy(this.context); AppViewLogicService.getInstance().executeViewLogic(`${name}_${detail.name}_click`, event, this, data, this.controlInstance?.getPSAppViewLogics()); } get controlStyle() { const { width, height } = this.controlInstance; return (width ? `width:${width}px;` : '') + (height ? `height:${height}px;` : '') + 'overflow:auto'; } /** * 绘制内容 * * @returns * @memberof AppMobPortletBase */ public render(): any { if (!this.controlIsLoaded) { return null; } const { controlClassNames } = this.renderOptions; const { width } = this.controlInstance; const style = width ? 'width:fit-content;' : ''; return ( <ion-card style={style} class={controlClassNames}> {this.controlInstance.showTitleBar ? this.renderTitle() : null} <div class="control-content app-control-portlet__content"> {this.renderByPortletType()} </div> <van-action-sheet v-model={this.selectStatus} get-container="#app" actions={this.actionBarModelData} cancel-text="取消" close-on-click-action on-select={($event: any) => { this.handleItemClick($event, null) }} on-cancel={() => { this.selectStatus = false }} /> </ion-card> ) } }