diff --git a/CHANGELOG.md b/CHANGELOG.md index 9735a466864f5d03041760864cfbfa7321e7a790..b01fadba7dd66a72977dabf19d55a70235ca51d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ ## [Unreleased] +### Changed + +- 甘特部件适配滑块粘性布局样式及调整滑块飘窗打开方式 +- 分页搜索视图中快捷搜索提示根据当前激活的关系视图显示 + ## [0.7.38-alpha.23] - 2024-11-08 ### Changed diff --git a/src/control/gantt/gantt.scss b/src/control/gantt/gantt.scss index e432b2b9c0d1006e0d42a9b5b147814c1cccffa6..55c3fa330c8080ff37850abc26d91026e568ee04 100644 --- a/src/control/gantt/gantt.scss +++ b/src/control/gantt/gantt.scss @@ -49,6 +49,46 @@ height: 100%; } } + + // 适配滑块粘性布局 + .xg-row.xg-gantt-row { + overflow: visible; + + .xg-slider{ + &.xg-slider-drag.xg-slider-level0 { + overflow: visible; + } + + .xg-slider-block { + overflow: visible; + } + + // 任务滑块宽度为0时不显示 + &.is-no-width { + display: none; + } + } + } + .#{bem('control-gantt__slider--caption')} { + position: sticky; + left: 8px; + } + + // 滑块超出结束时间的总范围时 + .is-exceeds-range { + .#{bem('control-gantt__slider')} { + &::after { + position: absolute; + right: 0; + z-index: 99; + display: block; + width: 16px; + height: 100%; + content: ''; + background-color: var(--ibiz-color-primary); + } + } + } } @include m(empty) { .xg-table-body { @@ -56,6 +96,8 @@ } } @include e(slider) { + display: flex; + align-items: center; height: 100%; padding: getCssVar(spacing,none) getCssVar(spacing,base-tight); cursor: pointer; @@ -93,6 +135,13 @@ align-items: center; } } + + @include m(caption) { + overflow: hidden; + color: getCssVar(color, 'primary', 'text'); + text-overflow: ellipsis; + white-space: nowrap; + } } @include e('setting') { display: flex; @@ -102,6 +151,15 @@ fill: getCssVar('color','primary'); } } + + @include e('slider-popover') { + z-index: 300; + width: auto; + min-width: 300px; + padding: 12px; + border: none; + box-shadow: getCssVar('shadow', 'elevated'); + } .#{bem('tree-grid-ex-field-column','','ellipsis')} { .#{bem('tree-grid-ex-field-column-text-container')} { min-width: 0; diff --git a/src/control/gantt/gantt.tsx b/src/control/gantt/gantt.tsx index 215c2ea504c9263bffe8a3517b7d332d6d1985f4..d6abd0326d42b452fac9c1353417fa9ffedfcfad 100644 --- a/src/control/gantt/gantt.tsx +++ b/src/control/gantt/gantt.tsx @@ -5,6 +5,7 @@ import { useControlController, useNamespace, useUIStore, + IBizControlShell, } from '@ibiz-template/vue3-util'; import { computed, @@ -37,6 +38,7 @@ import { IModal, IModalData, IColumnState, + IOverlayPopoverContainer, } from '@ibiz-template/runtime'; import { showTitle } from '@ibiz-template/core'; import { MenuItem } from '@imengyu/vue3-context-menu'; @@ -70,6 +72,9 @@ export const GanttControl = defineComponent({ const isInited: Ref = ref(false); const ns = useNamespace(`control-${c.model.controlType!.toLowerCase()}`); + // 滑块模态 + let overlay: null | IOverlayPopoverContainer = null; + // 滑块移动 const sliderMove = ref(false); @@ -559,14 +564,12 @@ export const GanttControl = defineComponent({ * @return {*} */ const renderNodePanel = (modelData: IPanel, item: IData) => { - return ( - - ); + return h(IBizControlShell, { + data: item, + modelData, + context: c.context, + params: c.params, + }); }; /** @@ -591,6 +594,47 @@ export const GanttControl = defineComponent({ ); }; + /** + * 打开 popover + * + * @param {IGanttNodeData} item + * @param {MouseEvent} evt + * @return {*} + */ + const openPopover = (row: IGanttNodeData, evt: MouseEvent): void => { + if (overlay) { + return; + } + const panel = findNodeLayoutPanel(row._nodeId); + const component = panel + ? renderNodePanel(panel, row._deData!) + : renderNodeInfo(row); + overlay = ibiz.overlay.createPopover( + (modal: IModal): VNode => { + return h(component, { modal }); + }, + undefined, + { + width: 'auto', + height: 'auto', + noArrow: true, + placement: 'bottom', + modalClass: ns.e('slider-popover'), + }, + ); + overlay?.present((evt.target as IParams).children[0] as HTMLElement); + }; + + /** + * 关闭 popover + * + * @return {*} + */ + const closePopover = (): void => { + overlay?.dismiss(); + overlay = null; + }; + /** * 绘制滑块 * @@ -605,35 +649,33 @@ export const GanttControl = defineComponent({ resize-right={c.state.sliderDraggable} > {{ - content: ({ row }: { row: IGanttNodeData }): VNode => { + content: ({ + row, + left, + }: { + row: IGanttNodeData; + left: number; + }): JSX.Element => { const { sysCss } = c.getNodeModel(row._nodeId)!; const sysCssName = sysCss?.cssName || ''; - + const marginLeft = left < 0 ? `${-left}px` : ''; + const caption = row?._text; return ( - onNodeClick(row, evt)} + onDblclick={() => onNodeDbClick(row)} + onContextmenu={evt => onNodeContextmenu(row, evt)} + onMouseenter={evt => openPopover(row, evt)} + onMouseleave={closePopover} > - {{ - reference: () => { - return ( -
onNodeClick(row, evt)} - onDblclick={() => onNodeDbClick(row)} - onContextmenu={evt => onNodeContextmenu(row, evt)} - >
- ); - }, - default: () => { - const panel = findNodeLayoutPanel(row._nodeId); - return panel - ? renderNodePanel(panel, row._deData!) - : renderNodeInfo(row); - }, - }} -
+
+ ); }, }} diff --git a/src/view-engine/tab-search-view.engine.ts b/src/view-engine/tab-search-view.engine.ts index 9a3b2603d6c8fa0b3c1c62931cf6ee2ee1995222..529c8e4c206c599b85d725e8fc02c357656cf67b 100644 --- a/src/view-engine/tab-search-view.engine.ts +++ b/src/view-engine/tab-search-view.engine.ts @@ -7,7 +7,7 @@ import { SysUIActionTag, ViewController, } from '@ibiz-template/runtime'; -import { IAppDETabSearchView } from '@ibiz/model-core'; +import { IAppDETabSearchView, IDETabViewPanel } from '@ibiz/model-core'; import { TabExpViewEngine } from './tab-exp-view.engine'; /** @@ -112,10 +112,68 @@ export class TabSearchViewEngine extends TabExpViewEngine { } // 分页导航面板切换 if (this.tabExpPanel) { - this.tabExpPanel.evt.on('onTabChange', () => { - this.calcViewParams(); + this.tabExpPanel.evt.on( + 'onTabChange', + ({ tab }: { tab: IDETabViewPanel }) => { + this.calcViewParams(); + this.onQuickSearchPlaceHolder(tab); + }, + ); + + // 适配onTabChange第一次抛值时onMouted没有执行完毕 + const { activeTabViewPanelModel } = this.tabExpPanel as IParams; + if (activeTabViewPanelModel) { + this.onQuickSearchPlaceHolder(activeTabViewPanelModel); + } + } + } + + /** + * 给快捷搜索赋默认提示值 + * @author ljx + * @date 2024-11-12 10:56:25 + * @readonly + */ + async onQuickSearchPlaceHolder(tab: IDETabViewPanel): Promise { + let { caption } = tab; + const viewConfig = await ibiz.hub.config.view.get( + tab.embeddedAppDEViewId || '', + ); + const appDataEntity = await ibiz.hub.getAppDataEntity( + viewConfig.appDataEntityId!, + viewConfig.appId, + ); + + if (appDataEntity) { + const searchFields = appDataEntity.appDEFields!.filter(field => { + return field.enableQuickSearch; }); + if (searchFields.length) { + const placeHolders: string[] = []; + searchFields.forEach(searchField => { + if ( + searchField.lnlanguageRes && + searchField.lnlanguageRes.lanResTag + ) { + placeHolders.push( + ibiz.i18n.t( + searchField.lnlanguageRes.lanResTag, + searchField.logicName, + ), + ); + } else if (searchField.logicName) { + placeHolders.push(searchField.logicName); + } + }); + if (placeHolders.length > 0) { + caption = placeHolders.join('、'); + } + } } + + // 直接赋值 caption + (this.searchBar as IParams).placeHolder = caption || ''; + this.searchBar.state.quickSearchPlaceHolder = caption || ''; } // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types