diff --git a/src/common/index.ts b/src/common/index.ts index eddffebdf5d8c5b0ad2abe486492ea277692983c..8ba5c534ae9773ab3c166588a8196a8d332d28ab 100644 --- a/src/common/index.ts +++ b/src/common/index.ts @@ -33,6 +33,7 @@ import { IBizMdAdvanedSearchfrom } from './md-advaned-searchform/md-advaned-sear import { IBizAddBtn } from './add-btn/add-btn'; import { IBizAddMore } from './add-more/add-more'; import { FloatButton } from './float-button/float-button'; +import { IBizInfoItem } from './info-item/info-item'; export * from './col/col'; export * from './row/row'; @@ -46,6 +47,7 @@ export const IBizCommonComponents = { install: (v: App): void => { v.component(IBizAddBtn.name!, IBizAddBtn); v.component(FloatButton.name!, FloatButton); + v.component(IBizInfoItem.name!, IBizInfoItem); v.component(IBizAddMore.name!, IBizAddMore); v.component(IBizMdAdvanedSearchfrom.name!, IBizMdAdvanedSearchfrom); v.component(IBizSplit.name!, IBizSplit); diff --git a/src/common/info-item/info-item.scss b/src/common/info-item/info-item.scss new file mode 100644 index 0000000000000000000000000000000000000000..a26df956cc905017a4823d63ef470189d4288588 --- /dev/null +++ b/src/common/info-item/info-item.scss @@ -0,0 +1,76 @@ +$info-item: ( + // Width/Height + height-icon-line-height: 1em, + height-label-line-height: 1em, + // Spacing + spacing-label-margin: 0 0 0 getCssVar('spacing', 'extra-tight'), + spacing-badge-margin: 0 0 0 getCssVar('spacing', 'tight'), + spacing-vertical-icon-wrapper-margin: 0 0 getCssVar('spacing', 'extra-tight') + 0, + // Font + font-icon-font-size: inherit, + font-label-font-size: inherit, + // Other + icon-size: 1em, + position-badge-top: 0px, + position-badge-left-offset: getCssVar('spacing', 'extra-tight'), + position-badge-left: calc( + 100% - #{getCssVar(info-item, position-badge-left-offset)} + ), + transform-badge: translateY(-50%) +); + +// 组件布局样式,字体与图标大小继承上层组件文本大小 +@include b(info-item) { + @include set-component-css-var('info-item', $info-item); + + position: relative; + display: flex; + align-items: center; + @include e('icon') { + &.#{bem(icon)}, + &.#{bem(icon)} svg, + &.#{bem(icon)} img { + display: inline-flex; + align-items: center; + width: getCssVar(info-item, icon-size); + height: getCssVar(info-item, icon-size); + font-size: getCssVar(info-item, font-icon-font-size); + line-height: getCssVar(info-item, height-icon-line-height); + } + &.#{bem(icon)} + .#{bem(info-item, label)} { + margin: getCssVar(info-item, spacing-label-margin); + } + } + + @include e('label') { + font-size: getCssVar(info-item, font-label-font-size); + line-height: getCssVar(info-item, height-label-line-height); + & + .#{bem(info-item, badge)} { + margin: getCssVar(info-item, spacing-badge-margin); + } + } + + @include when('badge-float') { + @include e('badge') { + position: absolute; + top: getCssVar(info-item, position-badge-top); + left: getCssVar(info-item, position-badge-left); + margin: 0; + transform: getCssVar(info-item, transform-badge); + } + } + + // 垂直布局样式 + @include when('vertical') { + flex-direction: column; + @include e('icon-wrapper') { + &:has(.#{bem(icon)}) { + position: relative; + display: flex; + align-items: center; + margin: getCssVar(info-item, spacing-vertical-icon-wrapper-margin); + } + } + } +} diff --git a/src/common/info-item/info-item.tsx b/src/common/info-item/info-item.tsx new file mode 100644 index 0000000000000000000000000000000000000000..60cd8b5ae6cca46653cb3a0b4b4e6fc7208f460a --- /dev/null +++ b/src/common/info-item/info-item.tsx @@ -0,0 +1,96 @@ +import { defineComponent, PropType, VNode } from 'vue'; +import { useNamespace } from '@ibiz-template/vue3-util'; +import { isNil } from 'ramda'; +import { ISysImage } from '@ibiz/model-core'; +import './info-item.scss'; + +/** + * @description 通用信息项组件,用于展示「图标 + 文本 + 计数器」组合结构 + */ +export const IBizInfoItem = defineComponent({ + name: 'IBizInfoItem', + props: { + /** + * @description 文本值 + */ + label: { + type: String, + default: '', + }, + /** + * @description 计数器数值 + */ + badge: { + type: Number, + default: null, + }, + /** + * @description 图标资源信息 + */ + icon: { + type: Object as PropType, + }, + /** + * @description 布局模式,vertical为垂直布局,horizontal为水平布局 + */ + layoutMode: { + type: String as PropType<'vertical' | 'horizontal'>, + default: 'horizontal', + }, + /** + * @description 计数器是否浮动显示 + */ + badgeFloat: { + type: Boolean, + default: true, + }, + }, + setup(props) { + const ns = useNamespace('info-item'); + + const renderBadge = (): VNode | void => { + if (!isNil(props.badge)) { + return ; + } + }; + + const renderIcon = (): VNode | void => { + if (!isNil(props.icon)) { + return ; + } + }; + const renderLabel = (): VNode | void => { + if (!isNil(props.label)) { + return {props.label}; + } + }; + + const renderIconWarapper = (): VNode | void => { + return ( +
+ {renderIcon()} + {renderBadge()} +
+ ); + }; + + return { ns, renderBadge, renderIcon, renderLabel, renderIconWarapper }; + }, + render() { + let content = [this.renderIcon(), this.renderLabel(), this.renderBadge()]; + if (this.layoutMode === 'vertical') { + content = [this.renderIconWarapper(), this.renderLabel()]; + } + return ( +
+ {content} +
+ ); + }, +}); diff --git a/src/control/tab-exp-panel/layout-render-util.tsx b/src/control/tab-exp-panel/layout-render-util.tsx new file mode 100644 index 0000000000000000000000000000000000000000..f1ac1e1ffbbfb72b60a0735f752897738265357d --- /dev/null +++ b/src/control/tab-exp-panel/layout-render-util.tsx @@ -0,0 +1,90 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +import { Namespace } from '@ibiz-template/core'; +import { IApiTabExpPanelPagesState } from '@ibiz-template/runtime'; +import { PropType } from 'vue'; + +export type LayoutMode = + | 'top' + | 'bottom' + | 'left' + | 'right' + | 'flow' + | 'flow_noheader'; + +interface ILayoutProps { + // 分页绘制数据集合 + tabPages: IApiTabExpPanelPagesState[]; + // 计数器数据 + counterData: IData; + // 分页标识激活名称 + activeName: string; + // 布局模式 + layoutMode: LayoutMode; +} + +/** + * 布局组件通用props + * + * @export + * @return {*} {IData} + */ +export const layoutProps = { + // 分页绘制数据集合 + tabPages: { + type: Array as PropType, + default: () => [], + }, + // 计数器数据 + counterData: { + type: Object as PropType, + default: () => ({}), + }, + // 分页标识激活名称 + activeName: { + type: String, + default: '', + }, + // 布局模式 + layoutMode: { + type: String as PropType, + default: 'top', + }, +}; + +/** + * 布局组件通用emits + * + * @export + * @return {*} {IData} + */ +export const layoutEmits = { + /** + * @description 分页标识变更事件 + */ + tabChange: (_tabTag: string) => true, +}; + +/** + * 布局组件通用方法 + * + * @export + * @param {ILayoutProps} props + */ +export function useLayoutRender( + props: ILayoutProps, + emit: (event: 'tabChange', _tabTag: string) => void, + _ns: Namespace, +): { + getCounterValue: (page: IApiTabExpPanelPagesState) => string | number | null; + onTabChange: (_tabTag: string) => void; +} { + // 获取计数器值 + const getCounterValue = (page: IApiTabExpPanelPagesState) => { + return page.counterId ? props.counterData[page.counterId] : null; + }; + + const onTabChange = (_tabTag: string) => { + emit('tabChange', _tabTag); + }; + return { getCounterValue, onTabChange }; +} diff --git a/src/control/tab-exp-panel/tab-default-layout/tab-default-layout.scss b/src/control/tab-exp-panel/tab-default-layout/tab-default-layout.scss new file mode 100644 index 0000000000000000000000000000000000000000..b7c94788947ffb2cc85cc088dff2dd1b67d70654 --- /dev/null +++ b/src/control/tab-exp-panel/tab-default-layout/tab-default-layout.scss @@ -0,0 +1,39 @@ +$tab-default-layout: ( + // Color + color-item-text: getCssVar('control-tabexppanel', 'color-tab-text'), + color-border: getCssVar('color', 'border'), + // Width/Height + height: rem(50px), + // Font + font-tab-font-size: getCssVar('control-tabexppanel', 'font-tab-font-size') +); + +@include b(tab-default-layout) { + @include set-component-css-var('tab-default-layout', $tab-default-layout); + + @include e('tab-item') { + color: getCssVar(tab-default-layout, color-item-text); + font-size: getCssVar(tab-default-layout, font-tab-font-size); + } + + @include when('top') { + .van-tabs--line .van-tabs__wrap { + height: getCssVar(tab-default-layout, height); + } + + .van-tab__text { + overflow: unset; + } + } + + @include when('bottom') { + .van-tabbar { + height: getCssVar(tab-default-layout, height); + border-top: 1px solid getCssVar(tab-default-layout, color-border); + } + + .van-tabs__line { + display: none; + } + } +} diff --git a/src/control/tab-exp-panel/tab-default-layout/tab-default-layout.tsx b/src/control/tab-exp-panel/tab-default-layout/tab-default-layout.tsx new file mode 100644 index 0000000000000000000000000000000000000000..fb05f887932e4258b8ba590e0865c523ac2c80e6 --- /dev/null +++ b/src/control/tab-exp-panel/tab-default-layout/tab-default-layout.tsx @@ -0,0 +1,73 @@ +import { defineComponent } from 'vue'; +import { useNamespace } from '@ibiz-template/vue3-util'; +import { + layoutEmits, + layoutProps, + useLayoutRender, +} from '../layout-render-util'; +import './tab-default-layout.scss'; + +export const TabDefaultLayout = defineComponent({ + name: 'IBizTabDefaultLayout', + props: layoutProps, + emits: layoutEmits, + setup(props, { emit }) { + const ns = useNamespace('tab-default-layout'); + + const { getCounterValue, onTabChange } = useLayoutRender(props, emit, ns); + + return { ns, getCounterValue, onTabChange }; + }, + render() { + let content = ( + + {this.tabPages.map(tab => { + return ( + + {{ + title: () => ( + + ), + }} + + ); + })} + + ); + if (this.layoutMode === 'bottom') { + content = ( + + {this.tabPages.map(tab => { + return ( + + {{ + default: () => ( + + ), + }} + + ); + })} + + ); + } + return ( +
+ {content} +
+ ); + }, +}); diff --git a/src/control/tab-exp-panel/tab-exp-panel.scss b/src/control/tab-exp-panel/tab-exp-panel.scss index e223643ff7bc391a29d26bb2f95f4c5dc717188d..adc33184a4bfa0460b7b03292e8232f8a419697a 100644 --- a/src/control/tab-exp-panel/tab-exp-panel.scss +++ b/src/control/tab-exp-panel/tab-exp-panel.scss @@ -1,35 +1,12 @@ $control-tabexppanel: ( - 'side-padding': getCssVar(spacing, base), + // Color + color-tab-text: getCssVar('color', 'text', 0), + // Font + font-tab-font-size: getCssVar('font-size', 'regular') ); - -$control-tabexppanel-flow: ( - 'header-padding': getCssVar(spacing, tight) getCssVar(spacing, base), - 'font-size': getCssVar(font-size, regular), - 'line-height': getCssVar(height-control, small), - 'header-color': getCssVar(color, text, 2), - 'header-bg': getCssVar(color, bg, 0), -); - -@include b(control-tabexppanel-tab-item-header) { - @include set-component-css-var('control-tabexppanel-flow', $control-tabexppanel-flow); - padding: getCssVar(control-tabexppanel-flow, header-padding); - font-size: getCssVar(control-tabexppanel-flow, font-size); - line-height: getCssVar(control-tabexppanel-flow, line-height); - color: getCssVar(control-tabexppanel-flow, header-color); - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - background: getCssVar(control-tabexppanel-flow, header-bg); -} - @include b(control-tabexppanel) { @include set-component-css-var('control-tabexppanel', $control-tabexppanel); - @include e(sidebar) { - @include m(left) { - margin-left: getCssVar(control-tabexppanel, side-padding); - } - @include m(right) { - margin-right: getCssVar(control-tabexppanel, side-padding); - } - } + + width: 100%; + height: 100%; } diff --git a/src/control/tab-exp-panel/tab-exp-panel.tsx b/src/control/tab-exp-panel/tab-exp-panel.tsx index 7d53f25279822306966ced8b1eeba5ace5bb6f48..df7f04d00219d5db418f3892b209e74eec821e22 100644 --- a/src/control/tab-exp-panel/tab-exp-panel.tsx +++ b/src/control/tab-exp-panel/tab-exp-panel.tsx @@ -1,15 +1,20 @@ import { useControlController, useNamespace } from '@ibiz-template/vue3-util'; -import { defineComponent, h, PropType, Ref, ref, resolveComponent } from 'vue'; +import { defineComponent, h, PropType, resolveComponent } from 'vue'; import { IAppDETabExplorerView, IDETabViewPanel, ITabExpPanel, } from '@ibiz/model-core'; import { + IApiTabExpPanelPagesState, IControlProvider, TabExpPanelController, } from '@ibiz-template/runtime'; import './tab-exp-panel.scss'; +import { TabFlowLayout } from './tab-flow-layout/tab-flow-layout'; +import { TabSidebarLayout } from './tab-sidebar-layout/tab-sidebar-layout'; +import { TabDefaultLayout } from './tab-default-layout/tab-default-layout'; +import { LayoutMode } from './layout-render-util'; export const TabExpPanelControl = defineComponent({ name: 'IBizTabExpPanelControl', @@ -45,117 +50,58 @@ export const TabExpPanelControl = defineComponent({ // 视图模型 const model = c.view?.model as IAppDETabExplorerView; // 布局模式 - const tabPosition = model?.tabLayout?.toLowerCase() || 'top'; - - const counterData: Ref = ref({}); - - // 激活下标,侧边栏使用 - const activeIndex = ref(0); - - const fn = (counter: IData) => { - counterData.value = counter; - }; - - c.evt.on('onCreated', () => { - if (c.counter) { - c.counter.onChange(fn, true); - } - }); + const layoutMode = model?.tabLayout?.toLowerCase() || 'top'; const onTabChange = (value: string) => { c.state.activeName = value; c.handleTabChange(); }; - const onSidebarChange = (index: number) => { - activeIndex.value = index; - const value = c.state.tabPages[index].tabTag; - c.state.activeName = value; - c.handleTabChange(); - }; - return { c, ns, - activeIndex, - tabPosition, - counterData, + layoutMode, onTabChange, - onSidebarChange, }; }, render() { - const { isCreated, tabPages } = this.c.state; - if (this.tabPosition === 'flow' || this.tabPosition === 'flow_noheader') { - if (!isCreated) { - return; - } - return ( -
- {tabPages.map(page => { - const target = this.c.model.controls?.find( - tab => tab.id === page.tabTag, - ) as IDETabViewPanel; - return ( -
-
{page.caption}
-
- {h(resolveComponent('IBizViewShell'), { - context: this.context, - params: this.params, - viewId: target?.embeddedAppDEViewId, - })} -
-
- ); - })} -
- ); + const { isCreated, tabPages, counterData, activeName } = this.c.state; + if (!isCreated) { + return; } - if (['left', 'right'].includes(this.tabPosition)) { - return ( - - {tabPages.map(page => { - return ( - - ); - })} - + const attrs = { + tabPages, + counterData, + activeName, + layoutMode: this.layoutMode as LayoutMode, + onTabChange: this.onTabChange, + }; + + let content = ; + + if (this.layoutMode === 'flow' || this.layoutMode === 'flow_noheader') { + content = ( + + {{ + groupContent: (page: IApiTabExpPanelPagesState) => { + const target = this.c.model.controls?.find( + tab => tab.id === page.tabTag, + ) as IDETabViewPanel; + return h(resolveComponent('IBizViewShell'), { + context: this.context, + params: this.params, + viewId: target?.embeddedAppDEViewId, + }); + }, + }} + ); } - return ( - isCreated && ( - - {tabPages.map(page => { - return ( - - ); - })} - - ) - ); + + if (['left', 'right'].includes(this.layoutMode)) { + content = ; + } + + return
{content}
; }, }); diff --git a/src/control/tab-exp-panel/tab-flow-layout/tab-flow-layout.scss b/src/control/tab-exp-panel/tab-flow-layout/tab-flow-layout.scss new file mode 100644 index 0000000000000000000000000000000000000000..0807cb8554afe213e6197be049e3d46bbdf3ba3a --- /dev/null +++ b/src/control/tab-exp-panel/tab-flow-layout/tab-flow-layout.scss @@ -0,0 +1,46 @@ +$tab-flow-layout: ( + // Color + color-group-header-text: getCssVar('control-tabexppanel', 'color-tab-text'), + color-group-header-bg: getCssVar(color, bg, 0), + color-group-noheader-bg: getCssVar(color, bg, 0), + // Width/Height + height-group-header-content-min-height: + getCssVar('height-control', 'default'), + // Spacing + spacing-group-header-padding: getCssVar('spacing', 'tight') + getCssVar('spacing', 'base'), + spacing-group-header-ph-padding: getCssVar('spacing', 'tight'), + // Font + font-group-header-font-size: getCssVar( + 'control-tabexppanel', + 'font-tab-font-size' + ) +); +@include b(tab-flow-layout) { + @include set-component-css-var('tab-flow-layout', $tab-flow-layout); + + @include e('group-header') { + padding: getCssVar(tab-flow-layout, spacing-group-header-padding); + font-size: getCssVar(tab-flow-layout, font-group-header-font-size); + color: getCssVar(tab-flow-layout, color-group-header-text); + background-color: getCssVar(tab-flow-layout, color-group-header-bg); + + @include m('content') { + min-height: getCssVar( + tab-flow-layout, + height-group-header-content-min-height + ); + } + } + + .van-index-anchor { + padding: 0; + } + + @include when('flow_noheader') { + @include e('group-header-ph') { + padding: getCssVar(tab-flow-layout, spacing-group-header-ph-padding); + background-color: getCssVar(tab-flow-layout, color-group-noheader-bg); + } + } +} diff --git a/src/control/tab-exp-panel/tab-flow-layout/tab-flow-layout.tsx b/src/control/tab-exp-panel/tab-flow-layout/tab-flow-layout.tsx new file mode 100644 index 0000000000000000000000000000000000000000..aedfa931748fd10744c95d134f82cae19926ddca --- /dev/null +++ b/src/control/tab-exp-panel/tab-flow-layout/tab-flow-layout.tsx @@ -0,0 +1,55 @@ +import { defineComponent } from 'vue'; +import { useNamespace } from '@ibiz-template/vue3-util'; +import { + layoutEmits, + layoutProps, + useLayoutRender, +} from '../layout-render-util'; +import './tab-flow-layout.scss'; + +export const TabFlowLayout = defineComponent({ + name: 'IBizTabFlowLayout', + props: layoutProps, + emits: layoutEmits, + setup(props, { emit }) { + const ns = useNamespace('tab-flow-layout'); + const { getCounterValue } = useLayoutRender(props, emit, ns); + + return { ns, getCounterValue }; + }, + render() { + const indexList = this.tabPages.map(x => x.caption); + return ( + + {this.tabPages.map(tab => { + return ( +
+ + {this.layoutMode === 'flow_noheader' ? ( +
+ ) : ( +
+ +
+ )} +
+
+ {this.$slots.groupContent?.(tab)} +
+
+ ); + })} +
+ ); + }, +}); diff --git a/src/control/tab-exp-panel/tab-sidebar-layout/tab-sidebar-layout.scss b/src/control/tab-exp-panel/tab-sidebar-layout/tab-sidebar-layout.scss new file mode 100644 index 0000000000000000000000000000000000000000..5c03aae4af7652b1ceb1972e27c55d1351ace624 --- /dev/null +++ b/src/control/tab-exp-panel/tab-sidebar-layout/tab-sidebar-layout.scss @@ -0,0 +1,72 @@ +$tab-sidebar-layout: ( + // Color + color-bg: getCssVar(color, bg, 0), + color-item-text: getCssVar('control-tabexppanel', 'color-tab-text'), + color-item-bg: getCssVar(color, bg, 0), + color-bg-active: getCssVar(color, bg, 2), + // Width/Height + width: rem(90px), + height: 100%, + height-tab-item: getCssVar('height-control', 'default'), + width-badge-min-width: rem(20px), + // Spacing + spacing-padding: getCssVar('spacing', 'tight') 0, + spacing-sidebar-item-padding: getCssVar('spacing', 'tight') + getCssVar('spacing', 'tight'), + // Font + font-tab-font-size: getCssVar('control-tabexppanel', 'font-tab-font-size') +); +@include b(tab-sidebar-layout) { + @include set-component-css-var('tab-sidebar-layout', $tab-sidebar-layout); + + width: getCssVar(tab-sidebar-layout, width); + height: getCssVar(tab-sidebar-layout, height); + padding: getCssVar(tab-sidebar-layout, spacing-padding); + background-color: getCssVar(tab-sidebar-layout, color-bg); + + @include e('tab-item') { + display: flex; + align-items: center; + width: 100%; + min-height: getCssVar(tab-sidebar-layout, height-tab-item); + font-size: getCssVar(tab-sidebar-layout, font-tab-font-size); + color: getCssVar(tab-sidebar-layout, color-item-text); + .#{bem(info-item)} { + display: inline-flex; + max-width: 100%; + } + .#{bem(info-item, label)} { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + @include when('long-label') { + &:has(.#{bem(info-item, badge)}) { + max-width: calc( + 100% - #{getCssVar(tab-sidebar-layout, width-badge-min-width)} + ); + } + } + } + + .van-sidebar-item { + display: flex; + align-items: center; + padding: getCssVar(tab-sidebar-layout, spacing-sidebar-item-padding); + overflow: unset; + + &:not(.van-sidebar-item--select) { + background-color: getCssVar(tab-sidebar-layout, color-item-bg); + } + + &.van-sidebar-item--select { + background-color: getCssVar(tab-sidebar-layout, color-bg-active); + } + } + + .van-sidebar-item__text { + width: 100%; + height: 100%; + } +} diff --git a/src/control/tab-exp-panel/tab-sidebar-layout/tab-sidebar-layout.tsx b/src/control/tab-exp-panel/tab-sidebar-layout/tab-sidebar-layout.tsx new file mode 100644 index 0000000000000000000000000000000000000000..75b239dec620adaab8f26efb14e6e09a8b6d3d03 --- /dev/null +++ b/src/control/tab-exp-panel/tab-sidebar-layout/tab-sidebar-layout.tsx @@ -0,0 +1,62 @@ +import { defineComponent, ref } from 'vue'; +import { useNamespace } from '@ibiz-template/vue3-util'; +import { + layoutEmits, + layoutProps, + useLayoutRender, +} from '../layout-render-util'; +import './tab-sidebar-layout.scss'; + +export const TabSidebarLayout = defineComponent({ + name: 'IBizTabSidebarLayout', + props: layoutProps, + emits: layoutEmits, + setup(props, { emit }) { + const ns = useNamespace('tab-sidebar-layout'); + + // 激活下标 + const activeIndex = ref(0); + + const { getCounterValue, onTabChange } = useLayoutRender(props, emit, ns); + const onSidebarChange = (index: number) => { + activeIndex.value = index; + const tabTag = props.tabPages[index].tabTag; + onTabChange(tabTag); + }; + + return { ns, activeIndex, getCounterValue, onTabChange, onSidebarChange }; + }, + render() { + return ( + + {this.tabPages.map(tab => { + const isLongLabel = tab.caption.length > 3; + return ( + + {{ + title: () => ( +
+ +
+ ), + }} +
+ ); + })} +
+ ); + }, +}); diff --git a/src/view-engine/mob-tab-exp-view.engine.ts b/src/view-engine/mob-tab-exp-view.engine.ts index eee7f7b507cf2598d1192c6b795bcb018b66fc75..786125e9274dc2736d2abdbac8cfd517dc9ff17f 100644 --- a/src/view-engine/mob-tab-exp-view.engine.ts +++ b/src/view-engine/mob-tab-exp-view.engine.ts @@ -7,10 +7,13 @@ import { ITabExpViewState, ViewEngineBase, calcDeCodeNameById, + IApiMDViewCall, + SysUIActionTag, } from '@ibiz-template/runtime'; import { IAppDataEntity, IAppDETabExplorerView, + ILayout, IPanelContainer, IPanelItem, } from '@ibiz/model-core'; @@ -109,11 +112,20 @@ export class MobTabExpViewEngine extends ViewEngineBase { if (!tabexppanel) { return; } + // 左侧及右侧布局模式下需调整tabexppanel的flex布局, 高度需撑满 + if (['view_tabexppanel_left', 'view_tabexppanel_right'].includes(name)) { + tabexppanel.layoutPos = { + ...tabexppanel.layoutPos, + grow: 1, + } as ILayout; + } // 实际分页面板容器 const layoutContainer = findPanelItem(name); if (!layoutContainer) { return; } + // 删除原本的分页导航面板模型 + findPanelItemsAndDelete(['tabexppanel']); (layoutContainer as IPanelContainer).panelItems = [tabexppanel]; }; const { tabLayout } = this.view.model as IAppDETabExplorerView; @@ -149,13 +161,10 @@ export class MobTabExpViewEngine extends ViewEngineBase { deleteItems.splice(0, 1); break; } - // 非流式布局时进行额外处理 - if (tabLayout !== 'FLOW' && tabLayout !== 'FLOW_NOHEADER') { - // 设置分页导航面板布局 - setTabExpModelLayout(containerName); - // 删除多余布局模型 - findPanelItemsAndDelete(deleteItems); - } + // 设置分页导航面板布局 + setTabExpModelLayout(containerName); + // 删除多余布局模型 + findPanelItemsAndDelete(deleteItems); } /** @@ -197,6 +206,28 @@ export class MobTabExpViewEngine extends ViewEngineBase { await this.loadEntityData(); } + async call( + key: keyof IApiMDViewCall, + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types + _args: any, + ): Promise { + if (key === SysUIActionTag.REFRESH) { + await this.refresh(); + return null; + } + } + + /** + * 视图刷新 + * + * @protected + * @return {*} {Promise} + * @memberof MobTabExpViewEngine + */ + protected async refresh(): Promise { + this.tabExpPanel.refresh(); + } + /** * 加载实体数据 *