import { throttle, Util } from '@ibizstudio/runtime'; import { PanelControlBase } from '../../../widgets'; import { IPSDEViewPanel, IPSPanel, IPSPanelButton, IPSPanelContainer, IPSPanelControl, IPSPanelItem, IPSPanelRawItem, IPSPanelTabPage, IPSPanelTabPanel, IPSSysCss, IPSSysPanelField, IPSUIAction, } from '@ibizstudio/runtime'; import { Watch } from '../../../decorators'; /** * 面板部件基类 * * @export * @class AppPanelBase * @extends {PanelControlBase} */ export class AppPanelBase extends PanelControlBase { /** * 监听数据对象 * * @memberof AppPanelBase */ @Watch('data', { deep: true }) onDataChange(newVal: any, oldVal: any) { if (newVal) { this.computeButtonState(newVal); this.panelLogic({ name: '', newVal: null, oldVal: null }); this.$forceUpdate(); } } /** * FLEX布局时类名映射 * * @memberof AppPanelBase */ classObj: any = { BUTTON: 'app-viewpanel-button', FIELD: 'app-viewpanel-field', RAWITEM: 'app-viewpanel-rowitem', TABPAGE: 'app-viewpanel-tabpage', TABPANEL: 'app-viewpanel-tabpanel', }; /** * 获取FLEX布局时类名 * @param item */ renderDetailClass(item: any) { // 映射类名 let detailClass: any = this.classObj[item.itemType] || ''; detailClass += ` viewpanel-${item.itemType.toLowerCase()}-${item.name.toLowerCase()}`; if (item?.getPSSysCss?.()) { detailClass += ` ${item.getPSSysCss().cssName}`; } return detailClass; } /** * 获取栅格布局的props * * @param {*} parent 父 * @param {*} child 子 * @returns {*} * @memberof AppPanelBase */ getGridLayoutProps(parent: any, child: any): any { let layout = parent?.getPSLayout().layout; let { colXS, colSM, colMD, colLG, colXSOffset, colSMOffset, colMDOffset, colLGOffset } = child.getPSLayoutPos(); // 设置初始值 colXS = !colXS || colXS == -1 ? 24 : colXS; colSM = !colSM || colSM == -1 ? 24 : colSM; colMD = !colMD || colMD == -1 ? 24 : colMD; colLG = !colLG || colLG == -1 ? 24 : colLG; colXSOffset = !colXSOffset || colXSOffset == -1 ? 0 : colXSOffset; colSMOffset = !colSMOffset || colSMOffset == -1 ? 0 : colSMOffset; colMDOffset = !colMDOffset || colMDOffset == -1 ? 0 : colMDOffset; colLGOffset = !colLGOffset || colLGOffset == -1 ? 0 : colLGOffset; if (layout == 'TABLE_12COL') { // 重新计算12列的栅格数值 colXS = Math.min(colXS * 2, 24); colSM = Math.min(colSM * 2, 24); colMD = Math.min(colMD * 2, 24); colLG = Math.min(colXS * 2, 24); // 重新计算12列的栅格偏移 let sign = (num: number) => (num == 0 ? 0 : num / Math.abs(num)); colXSOffset = sign(colXSOffset) * Math.min(colXSOffset * 2, 24); colSMOffset = sign(colSMOffset) * Math.min(colSMOffset * 2, 24); colMDOffset = sign(colMDOffset) * Math.min(colMDOffset * 2, 24); colLGOffset = sign(colLGOffset) * Math.min(colLGOffset * 2, 24); } return { xs: { span: colXS, offset: colXSOffset }, sm: { span: colSM, offset: colSMOffset }, md: { span: colMD, offset: colMDOffset }, lg: { span: colLG, offset: colLGOffset }, }; } /** * 绘制顶级面板成员集合 * * @memberof AppPanelBase */ renderRootPSPanelItems(controlInstance: IPSPanel) { return controlInstance.getRootPSPanelItems()?.map((container: any, index: number) => { return this.renderByDetailType(container); }); } /** * 根据detailType绘制对应detail * * @param {*} modelJson * @memberof AppPanelBase */ renderByDetailType(modelJson: any) { if (modelJson.getPSSysPFPlugin()) { const pluginInstance: any = this.PluginFactory.getPluginInstance('CONTROLITEM', modelJson.getPSSysPFPlugin().pluginCode); if (pluginInstance) { return pluginInstance.renderCtrlItem(this.$createElement, modelJson, this, this.data); } } else { switch (modelJson.itemType) { case 'CONTAINER': return this.renderContainer(modelJson); case 'BUTTON': return this.renderButton(modelJson); case 'FIELD': return this.renderField(modelJson); case 'RAWITEM': return this.renderRawitem(modelJson); case 'TABPANEL': return this.renderTabPanel(modelJson); case 'TABPAGE': return this.renderTabPage(modelJson); case 'CONTROL': return this.renderControl(modelJson); } } } /** * 绘制面板Container * * @memberof AppPanelBase */ renderContainer(container: IPSPanelContainer) { const panelItems: IPSPanelItem[] = container.getPSPanelItems() || []; let layout = container.getPSLayout() as any; let layoutMode = container.getPSLayout()?.layout; let css = container.getPSSysCss() as IPSSysCss; let containerClass = { 'app-viewpanel-container': true, [`viewpanel-container-${container.name.toLowerCase()}`]: true, 'show-caption': container.showCaption, }; if (css && css.cssName) { Object.assign(containerClass, { [css.cssName]: true }); } let containerStyle = {}; if (container.width) { Object.assign(containerStyle, { width: container.width + 'px' }); } if (container.height) { Object.assign(containerStyle, { height: container.height + 'px' }); } if (this.detailsModel[container.name] && !this.detailsModel[container.name].visible) { Object.assign(containerStyle, { display: 'none' }); } // FLEX布局 if (layout && layoutMode == 'FLEX') { const containerGrow = (container.getPSLayoutPos() as any)?.grow; Object.assign(containerStyle, { overflow: 'auto', display: 'flex', 'flex-grow': containerGrow && containerGrow != -1 ? containerGrow : 0, }); const { dir, align, vAlign } = layout; if (dir) { Object.assign(containerStyle, { 'flex-direction': dir }); } if (align) { Object.assign(containerStyle, { 'justify-content': align }); } if (vAlign) { Object.assign(containerStyle, { 'align-items': vAlign }); } return ( {container.showCaption ? (
{this.$tl(container.getCapPSLanguageRes?.()?.lanResTag, container.caption)}
) : null} {panelItems.map((item: any, index: number) => { // 子样式 let { height, width, itemType } = item; let detailStyle: any = {}; if (height) { detailStyle.height = height + 'px'; } if (this.detailsModel[item.name] && !this.detailsModel[item.name].visible) { Object.assign(detailStyle, { display: 'none' }); } switch (itemType) { case 'CONTAINER': return this.renderByDetailType(item); case 'CTRLPOS': detailStyle.width = width ? width + 'px' : '100%'; break; } if (item.getPSLayoutPos()) { let grow = item.getPSLayoutPos()?.grow; detailStyle.flexGrow = grow != -1 ? grow : 0; } // 自定义类名 const controlClassName = this.renderDetailClass(item); return (
{this.renderByDetailType(item)}
); })}
); } else { let attrs = this.getGridLayoutProps(null, container); // 栅格布局 return ( {container.showCaption ? ( {this.$tl(container.getCapPSLanguageRes?.()?.lanResTag, container.caption)} ) : null} {panelItems.map((item: any, index: number) => { let { height, width, itemType } = item; let detailStyle: any = {}; if (this.detailsModel[item.name] && !this.detailsModel[item.name].visible) { Object.assign(detailStyle, { display: 'none' }); } if (height) { detailStyle.height = height + 'px'; } switch (itemType) { case 'CONTAINER': return this.renderByDetailType(item); case 'CTRLPOS': detailStyle.width = width ? width + 'px' : '100%'; break; } // 栅格布局 let attrs = this.getGridLayoutProps(container, item); // 自定义类名 const controlClassName = this.renderDetailClass(item); return ( {this.renderByDetailType(item)} ); })} ); } } /** * 绘制面板Button * * @memberof AppPanelBase */ renderButton(modelJson: IPSPanelButton) { let { caption, showCaption, name, height, tooltip, width } = modelJson; const buttonStyle = { height: height && height > 0 ? height + 'px' : '', width: width && width > 0 ? width + 'px' : '', }; const icon = modelJson.getPSSysImage(); const uiAction = modelJson.getPSUIAction() as IPSUIAction; return ( { throttle(this.buttonClick, [this.controlInstance.name, { tag: name }, $event], this); }} > ); } /** * 绘制面板Field * * @memberof AppPanelBase */ renderField(modelJson: IPSSysPanelField) { let { name, caption, hidden, showCaption } = modelJson; const editor: any = modelJson.getPSEditor(); let customCode: boolean = false; if (this.dataMap && this.dataMap.get(name)) { customCode = this.dataMap.get(name).customCode; } if (this.needFindDEField) { this.findDEFieldForPanelField(modelJson); } let labelPos = 'LEFT'; return ( !hidden && ( {editor && !customCode && ( { this.onPanelItemValueChange(this.data, value); }} /> )} {customCode && this.$createElement('div', { domProps: { innerHTML: this.data[name], }, })} ) ); } /** * 绘制面板Rawitem * * @memberof AppPanelBase */ renderRawitem(modelJson: IPSPanelRawItem) { const data: any = this.data; let { rawItemHeight, rawItemWidth, contentType, htmlContent, rawContent } = modelJson; let sysCssName = modelJson.getPSSysCss()?.cssName; let sysImage = modelJson.getPSSysImage()?.cssClass; let sysImgurl = modelJson.getPSSysImage()?.imagePath; const style: any = { width: rawItemWidth > 0 ? `${rawItemWidth}px` : '100%', height: rawItemHeight > 0 ? `${rawItemHeight}px` : '', }; 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 ( ); } /** * 绘制面板TabPanel * * @memberof AppPanelBase */ renderTabPanel(modelJson: IPSPanelTabPanel) { let activatedPage = this.detailsModel[modelJson.name]?.activatedPage; const tabPages: IPSPanelTabPage[] = modelJson.getPSPanelTabPages() || []; return ( throttle(this.handleTabPanelClick, [modelJson.name, $event], this)} class={this.renderDetailClass(modelJson)}> {tabPages.length > 0 ? tabPages.map((item: IPSPanelTabPage, index: number) => { return this.renderTabPage(item); }) : null} ); } /** * 绘制面板TabPage * * @memberof AppPanelBase */ renderTabPage(modelJson: IPSPanelTabPage) { let label = (this as any).$tl(modelJson.getCapPSLanguageRes?.()?.lanResTag, modelJson.caption) || '分页'; const panelItems: IPSPanelItem[] = modelJson.getPSPanelItems() || []; return ( {panelItems.map((item: IPSPanelItem, index: number) => { return this.renderByDetailType(item); })} ); } /** * 绘制面板Control * * @memberof AppPanelBase */ renderControl(modelJson: IPSPanelControl) { const { showCaption, caption, height, width } = modelJson; const cssName: any = modelJson.getPSSysCss()?.cssName; const controlStyle: any = { height: height ? height + 'px' : '', width: width ? width + 'px' : '100%', }; const controlModelJson: any = modelJson.getPSControl(); return (
{showCaption && caption ? (

{caption}

) : null}
{this.renderByControlType(controlModelJson)}
); } /** * 根据controlType绘制对应control * * @param {*} modelJson * @memberof AppPanelBase */ renderByControlType(modelJson: any) { switch (modelJson.controlType) { case 'VIEWPANEL': return this.renderViewPanel(modelJson); } } /** * 绘制ViewPanel * * @param {*} control * @memberof AppPanelBase */ renderViewPanel(modelJson: IPSDEViewPanel) { let controlAppView = modelJson.getEmbeddedPSAppDEView(); if (!controlAppView) { return; } const { modelFilePath, name } = controlAppView; let tempContext: any = Object.assign(Util.deepCopy(this.context), { viewpath: modelFilePath }); const appDeKeyCodeName = this.controlInstance.getPSAppDataEntity()?.codeName?.toLowerCase(); if (appDeKeyCodeName) { Object.assign(tempContext, { [appDeKeyCodeName]: this.data.srfkey }); } return this.$createElement('app-view-shell', { props: { staticProps: { portletState: this.viewState, viewDefaultUsage: false, viewModelData: controlAppView, }, dynamicProps: { viewdata: JSON.stringify(tempContext), viewparam: JSON.stringify(this.viewparams), }, }, on: { viewIsMounted: () => { this.setIsMounted(controlAppView?.name); }, }, ref: name, }); } /** * 绘制面板 * * @returns {*} * @memberof AppPanelBase */ render() { if (!this.controlIsLoaded) { return null; } let controlClassNames = { 'app-viewpanel': true, ...this.renderOptions.controlClassNames, }; let { width, height, layoutMode } = this.controlInstance; let controlStyle: any = {}; controlStyle.width = width > 0 ? width + 'px' : 'auto'; controlStyle.height = height > 0 ? height + 'px' : '100%'; if (layoutMode == 'FLEX') { controlStyle.display = 'flex'; } return ( // height为100%,适配占满
{this.renderRootPSPanelItems(this.controlInstance)}
); } }