diff --git a/CHANGELOG.md b/CHANGELOG.md index 03fd90f8cae4e548c77ab10a01ed55c96bc94506..4e3293a1de892bc496bc9a115d929f30c5e19c47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ ### Added +- 搜索表单支持搜索按钮相关配置 +- 日历新增支持时光轴 - 新增多数据部件和卡片支持表单搜索 - 新增支持多数据部件和卡片新建数据功能 - 新增移动端分割容器组件 @@ -43,6 +45,7 @@ ### Change +- 更新多数据视图同时存在搜索表单和搜索栏时才会绘制搜索表单弹出按钮 - 更新直接内容轮播图和视频样式,更新树导航栏样式 - 更新面板组件样式变量抽取,组件内部不直接使用基础变量 - 更新视图头预置返回按钮和视图内容区返回顶部按钮显隐逻辑 @@ -81,6 +84,7 @@ ### Fixed +- 修复表单直接内容是视频类型时,未配置的参数会覆盖掉默认的参数 - 修复分割容器在统一页面内有多个可交互元素时,分割容器的pointerdown事件被浏览器忽略的问题 - 修复返回顶部按钮在无视图参数时判断异常报错的问题 - 修复面板直接内容为视频类型时,配置的参数未识别的问题 diff --git a/src/common/rawitem/rawitem.tsx b/src/common/rawitem/rawitem.tsx index a600f0d716448d2988e80b5a9579765557e1e049..eaf4af68db5d01ff36ba87c7c81dec5a9635fa0e 100644 --- a/src/common/rawitem/rawitem.tsx +++ b/src/common/rawitem/rawitem.tsx @@ -166,13 +166,23 @@ export const IBizRawItem = defineComponent({ rawConfig = func(); switch (rawItemType.value) { case 'VIDEO': - Object.assign(playerParams.value, rawConfig, { - path: getParamsValue('path'), - autoplay: getParamsValue('autoplay'), - mute: getParamsValue('mute'), - replay: getParamsValue('replay'), - showcontrols: getParamsValue('showcontrols'), - }); + Object.assign(playerParams.value, rawConfig); + if (rawItem?.rawItemParams) { + const tempConfig: IData = { + path: getParamsValue('path'), + autoplay: getParamsValue('autoplay'), + mute: getParamsValue('mute'), + replay: getParamsValue('replay'), + showcontrols: getParamsValue('showcontrols'), + }; + Object.keys(tempConfig).forEach(key => { + if (tempConfig[key] !== undefined) { + Object.assign(playerParams.value, { + [key]: tempConfig[key], + }); + } + }); + } break; case 'DIVIDER': Object.assign(dividerParams.value, rawConfig); diff --git a/src/control/calendar/calendar.scss b/src/control/calendar/calendar.scss index d68c942b4bdc2b69feac138b692e58bc1174192d..361b3e9929ab52284c97a10c919f8e7056786c93 100644 --- a/src/control/calendar/calendar.scss +++ b/src/control/calendar/calendar.scss @@ -18,6 +18,15 @@ $control-calendar: ( calendar-disabled-color: getCssVar(color, disabled, text), calendar-active-color: getCssVar(color, primary), calendar-active-bg: getCssVar(color, primary, light, default), + timeline-item-padding: getCssVar(spacing, base), + timeline-item-size: getCssVar(width-icon, small), + timeline-item-bg-color: getCssVar(color, border), + tab-bg: transparent, + timeline-item-margin: 0 0 getCssVar(spacing, base) 0, + timeline-padding: getCssVar(spacing, base), + timeline-timespan-padding: getCssVar(spacing, extra-tight) getCssVar(spacing, tight), + timeline-item-border-radius: getCssVar(spacing, tight), + timeline-item-content-margin: getCssVar(spacing, base), ); @include b(control-calendar) { @@ -120,6 +129,28 @@ $control-calendar: ( .van-list { height: 100%; } + + @include e('tab-item') { + .van-tab__text { + position: relative; + overflow: visible; + &::before { + content:''; + width: 100%; + height: rem(3px); + bottom: rem(-8px); + border-radius: rem(3px); + transform: translateY(-50%); + background-color: getCssVar(control-calendar, tab-bg); + position: absolute; + } + } + &.van-tab--active { + .van-tab__text::before { + content: unset; + } + } + } } @include b(control-calendar-header-toolbar) { @@ -140,3 +171,25 @@ $control-calendar: ( background-color: getCssVar(control-calendar, toolbar-bg); } } + +// 时间轴样式 +@include b(control-calendar-timeline) { + @include set-component-css-var(control-calendar, $control-calendar); + padding: getCssVar(control-calendar, timeline-padding); + @include e(item) { + margin: getCssVar(control-calendar, timeline-item-margin); + @include m('timespan') { + width: auto; + display: inline-block; + padding: getCssVar(control-calendar, timeline-timespan-padding); + border-radius: getCssVar(control-calendar, timeline-item-border-radius); + background-color: getCssVar(control-calendar, timeline-item-bg-color); + } + @include m('content'){ + margin-top: getCssVar(control-calendar, timeline-item-content-margin); + } + .#{bem(control-calendar-item)}{ + padding: 0; + } + } +} diff --git a/src/control/calendar/calendar.tsx b/src/control/calendar/calendar.tsx index 3a489a5cbd9d717eed746bacb6ee7439adf0921e..e1a43cebbf4b4cabdcec02fa2bc06caa511624d6 100644 --- a/src/control/calendar/calendar.tsx +++ b/src/control/calendar/calendar.tsx @@ -1,5 +1,13 @@ import { useControlController, useNamespace } from '@ibiz-template/vue3-util'; -import { computed, defineComponent, PropType, Ref, ref, VNode } from 'vue'; +import { + computed, + defineComponent, + PropType, + Ref, + ref, + VNode, + watch, +} from 'vue'; import { ILayoutPanel, ISysCalendar } from '@ibiz/model-core'; import { CalendarController, @@ -174,11 +182,6 @@ export const CalendarControl = defineComponent({ return date; }); - c.evt.on('onMounted', () => { - loadMarkerData(c.state.selectedDate || new Date()); - loadData(c.state.selectedDate || new Date()); - }); - const dateChange = (newDate: Date) => { c.state.selectedDate = newDate; loadData(c.state.selectedDate); @@ -190,6 +193,19 @@ export const CalendarControl = defineComponent({ loadMarkerData(c.state.selectedDate); }; + watch( + () => c.state.selectedDate, + (newVal: Date | undefined, oldVal: Date | undefined) => { + if (newVal && newVal !== oldVal) { + calendar.value?.reset(c.state.selectedDate); + } + }, + { + deep: true, + immediate: true, + }, + ); + // 自定义选择日期 const onCustom = () => { const temptime = dayjs(c.state.selectedDate) @@ -288,7 +304,10 @@ export const CalendarControl = defineComponent({ }; // 绘制默认列表项 - const renderDefaultItem = (item: ICalendarItemData): VNode => { + const renderDefaultItem = ( + item: ICalendarItemData, + isLink: boolean = true, + ): VNode => { // 是否选中数据 const findIndex = this.c.state.selectedData.findIndex(data => { return data.deData.srfkey === item.deData.srfkey; @@ -302,7 +321,7 @@ export const CalendarControl = defineComponent({ this.c.onRowClick(item)} > @@ -379,68 +398,148 @@ export const CalendarControl = defineComponent({ ); }; - return ( - this.c.state.isCreated && ( - - - { - this.dateChange(date); - }} - > - {{ - day: ({ date }: { extendAttr: IData; date: IData }): VNode => { + // 绘制默认日历内容 + const renderCalendarContent = (): VNode[] => { + return [ + + { + this.dateChange(date); + }} + > + {{ + day: ({ date }: { extendAttr: IData; date: IData }): VNode => { + return ( + + {date?.day} + {renderMarker(date)} + + ); + }, + action: () => { + return renderHeaderToolbar(); + }, + }} + + , + , + + + , + ]; + }; + + // 绘制时光轴 + const renderTimeLine = (): VNode | undefined => { + if (this.c.state.items.length === 0) { + return renderNoData(); + } + const groupMap = new Map(); + const groups: IData[] = []; + this.c.state.items.forEach(item => { + const value = item.beginTime; + if (value) { + if (!groupMap.has(value)) { + groupMap.set(value, []); + } + if (groupMap.has(value)) { + groupMap.get(value)!.push(item); + } + } + }); + groupMap.forEach((value, key) => { + groups.push({ + key: `${key}`, + caption: key ? dayjs(key).format(this.c.timelineCaptionFormat) : key, + children: value, + }); + }); + + return ( + + {groups.map(item => { + return ( + + + {item.caption} + + {item.children.map((child: ICalendarItemData) => { + const model = this.c.model.sysCalendarItems?.find( + (calendarItems: IData) => { + return child.itemType === calendarItems.itemType; + }, + ); + const style: IData = {}; + if (model?.bkcolor) { + Object.assign(style, { + [`--${this.ns.b()}-timeline-item-bg-color`]: + model.bkcolor, + }); + } return ( - - {date?.day} - {renderMarker(date)} + + {model?.layoutPanel + ? renderPanelItem(child, model.layoutPanel) + : renderDefaultItem(child, false)} ); - }, - action: () => { - return renderHeaderToolbar(); - }, - }} - - - - - - + })} + + ); + })} + + ); + }; + + return ( + this.c.state.isCreated && ( + + {this.c.model.calendarStyle === 'TIMELINE' + ? renderTimeLine() + : renderCalendarContent()} ) ); diff --git a/src/control/form/form/form.tsx b/src/control/form/form/form.tsx index 6a9000c48320e3bf5a88eb2971f87d2fca70a994..c5e8273483e1513aa0d72a44477f05b3d6d22c81 100644 --- a/src/control/form/form/form.tsx +++ b/src/control/form/form/form.tsx @@ -156,14 +156,20 @@ export const FormControl = defineComponent({ } else { const key = controlPanel ? model.name! : 'default'; // 树自己绘制,要传递额外的参数 - slots[key] = (): VNode => { - return ( + slots[key] = (): IData[] => { + const result: IData[] = []; + const tempForm = ( {this.c.model.deformPages?.map(page => { return this.renderByDetailType(page); })} ); + result.push(tempForm); + if (this.$slots.searchFooter) { + result.push(this.$slots.searchFooter()); + } + return result; }; } } diff --git a/src/control/form/search-form/search-form.scss b/src/control/form/search-form/search-form.scss index ea609a54e8771abbc3ab93b4d860518585b3bb32..dd08bd694cc355724b204c4ac8e6862de79f15b3 100644 --- a/src/control/form/search-form/search-form.scss +++ b/src/control/form/search-form/search-form.scss @@ -1,49 +1,24 @@ -$control-search-form: ('bg-color': transparent, - 'margin': rem(16px) 0 0 rem(24px), +$control-search-form: ( + 'bg-color': transparent, + 'padding': getCssVar(spacing, tight) getCssVar(spacing, base), + 'right-gap': getCssVar(spacing, base), + 'btn-margin': 0 0 0 getCssVar(spacing, tight), + 'form-page-item-padding-top': calc(getCssVar('padding') / 2), + 'form-item-container-padding-bottom': calc(getCssVar('padding', 'right') / 2), + 'popover-padding': getCssVar(spacing, tight) 0, + 'popover-item-padding': getCssVar(spacing, tight) getCssVar(spacing, base), + 'popover-item-margin': getCssVar(spacing, base) 0 0 0, + 'save-name-padding': getCssVar(spacing, base), + 'filter-item-gap': getCssVar(spacing, base), ); -$control-search-form-buttons: ('padding': rem(16px) rem(16px) rem(16px), - 'btn-margin': 0 0 0 rem(10px), - 'search-btn-bg-color': getCssVar('color', 'primary'), - 'search-btn-color': getCssVar(color, bg, 1), -); - -@include b(control-searchform-buttons) { - @include set-component-css-var('control-search-form-buttons', - $control-search-form-buttons); - @include flex(row, flex-end, center); - - padding: getCssVar('control-search-form-buttons', 'padding'); - - @include e(search) { - height: rem(30px); - color: getCssVar('control-search-form-buttons', 'search-btn-color'); - background-color: getCssVar('control-search-form-buttons', - 'search-btn-bg-color' - ); - - &:hover { - color: getCssVar('control-search-form-buttons', 'search-btn-color'); - background-color: getCssVar('control-search-form-buttons', - 'search-btn-bg-color' - ); - } - } - - @include e(reset) { - height: rem(30px); - margin: getCssVar('control-search-form-buttons', 'btn-margin'); - } -} - @include b(control-searchform) { @include set-component-css-var('control-search-form', $control-search-form); - margin: getCssVar('control-search-form-buttons', 'margin'); - background-color: getCssVar('control-search-form-buttons', 'bg-color'); + background-color: getCssVar('control-search-form', 'bg-color'); .#{bem(form-page-item)} { - padding-top: calc(getCssVar('padding') / 2); + padding-top: getCssVar('control-search-form', 'form-page-item-padding-top'); } .#{bem(form-page-item-child)} { @@ -51,6 +26,60 @@ $control-search-form-buttons: ('padding': rem(16px) rem(16px) rem(16px), } .#{bem(form-item-container)} { - padding-bottom: calc(getCssVar('padding', 'right') / 2); + padding-bottom: getCssVar( + 'control-search-form', + 'form-item-container-padding-bottom' + ); + } + + @include e('buttons') { + @include flex(row, flex-end, center); + + padding: getCssVar('control-search-form', 'padding'); + } + + @include e(reset) { + margin: getCssVar('control-search-form', 'btn-margin'); + } + + @include e('popover-more') { + margin: getCssVar('control-search-form', 'btn-margin'); + } + + @include e('popover-content') { + @include set-component-css-var('control-search-form', $control-search-form); + + padding: getCssVar('control-search-form', 'popover-padding'); + @include m('item') { + padding: getCssVar('control-search-form', 'popover-item-padding'); + &:first-child { + margin-top: 0; + } + } + } + + @include e('right') { + @include flex(row, flex-start, center); + + gap: getCssVar('control-search-form', 'right-gap'); + + .#{bem(control-searchform,buttons)} { + flex-shrink: 0; + padding: 0; + } + } + + @include e('save-name') { + &.van-cell { + padding: getCssVar('control-search-form', 'save-name-padding'); + } + } + + @include e('filter-item'){ + padding: getCssVar('control-search-form', 'popover-item-padding'); + display: flex; + gap: getCssVar('control-search-form', 'filter-item-gap'); + align-items: center; + justify-content: space-between; } } \ No newline at end of file diff --git a/src/control/form/search-form/search-form.tsx b/src/control/form/search-form/search-form.tsx index 526ba86db90d908c201aa8f753b5b6754eb4d165..d6da246914ee9b58e2a01a25756b47e357f0e237 100644 --- a/src/control/form/search-form/search-form.tsx +++ b/src/control/form/search-form/search-form.tsx @@ -1,7 +1,7 @@ import { IControlProvider, SearchFormController } from '@ibiz-template/runtime'; import { useControlController, useNamespace } from '@ibiz-template/vue3-util'; import { IDESearchForm } from '@ibiz/model-core'; -import { defineComponent, PropType, reactive } from 'vue'; +import { defineComponent, PropType, reactive, ref } from 'vue'; import './search-form.scss'; export const SearchFormControl = defineComponent({ @@ -34,6 +34,15 @@ export const SearchFormControl = defineComponent({ ); const ns = useNamespace(`control-${c.model.controlType!.toLowerCase()}`); + // 显示下拉气泡 + const showPopover = ref(false); + + // 显示保存弹窗 + const showSaveDialog = ref(false); + + // 保存方案名称 + const saveName = ref(''); + c.evt.on('onCreated', () => { const keys = Object.keys(c.details); keys.forEach(key => { @@ -42,7 +51,157 @@ export const SearchFormControl = defineComponent({ }); }); - return { c, ns }; + // 重置 + const onReset = () => { + showPopover.value = false; + c.reset(); + }; + + // 保存过滤条件 + const onSaveFilter = () => { + showSaveDialog.value = true; + }; + + // 点击历史保存项 + const onHistoryClick = (index: number) => { + showPopover.value = false; + c.applyStoredFilter(index); + }; + + // 移除历史保存项 + const onHistoryRemove = (index: number, event: PointerEvent) => { + event.stopPropagation(); + c.removeStoredFilter(index); + }; + + // 保存弹窗取消 + const onDialogCancel = () => { + showSaveDialog.value = false; + showPopover.value = false; + }; + + // 保存弹窗确定 + const onDialogConfirm = async () => { + await c.storeFilter(saveName.value); + showSaveDialog.value = false; + showPopover.value = false; + }; + + // 搜索按钮 + const renderSearch = () => { + return ( + c.onSearchButtonClick()} + > + {ibiz.i18n.t('control.form.searchForm.search')} + + ); + }; + + // 重置按钮 + const renderReset = () => { + return ( + c.reset()}> + {ibiz.i18n.t('control.form.searchForm.reset')} + + ); + }; + + // 绘制历史保存列表 + const renderHistorySaveList = () => { + if (c.state.storedFilters?.length > 0) { + return c.state.storedFilters.map((item: IData, index: number) => { + return ( + onHistoryClick(index)} + > + {item.name} + onHistoryRemove(index, event)} + name='close-outline' + > + + ); + }); + } + return null; + }; + + // 绘制有保存时的下拉状态按钮 + const renderDropdown = () => { + return ( + + {{ + reference: () => { + return ( + + {ibiz.i18n.t('control.form.searchForm.more')} + + ); + }, + default: () => { + return ( + + + {ibiz.i18n.t('control.form.searchForm.reset')} + + + {ibiz.i18n.t('control.form.searchForm.saveFilter')} + + {renderHistorySaveList()} + + + + + ); + }, + }} + + ); + }; + + // 更多按钮 + const renderAllBtns = () => { + let moreBtns = null; + if (c.state.enableStoredFilters) { + moreBtns = renderDropdown(); + } else { + moreBtns = renderReset(); + } + return [renderSearch(), moreBtns]; + }; + + return { c, ns, renderSearch, renderAllBtns }; }, render() { @@ -52,27 +211,24 @@ export const SearchFormControl = defineComponent({ } return ( this.c.onKeyUp(e)} > {{ ...this.$slots, searchFooter: () => { + if (this.c.model.searchButtonStyle === 'NONE') { + return null; + } return ( - - this.c.onSearchButtonClick()} - > - {ibiz.i18n.t('control.form.searchForm.search')} - - this.c.reset()} - > - {ibiz.i18n.t('control.form.searchForm.reset')} - + + {this.c.model.searchButtonStyle === 'SEARCHONLY' + ? this.renderSearch() + : this.renderAllBtns()} ); }, diff --git a/src/locale/en/index.ts b/src/locale/en/index.ts index e2d9b6f09f2efe5bbb30901058c53a79c4046afb..f1155eaf4a094fdb490d6f12e79c93e7c6cb3d64 100644 --- a/src/locale/en/index.ts +++ b/src/locale/en/index.ts @@ -119,6 +119,12 @@ export default { searchForm: { search: 'Search', reset: 'Reset', + saveFilter: 'Save Filter', + more: 'More', + saveTitle: 'Store custom queries', + saveName: 'Save name', + savePlaceholder: + 'Please enter the name of the custom query to be stored', }, }, list: { diff --git a/src/locale/zh-CN/index.ts b/src/locale/zh-CN/index.ts index 5fd7f223414294da453ddc27a111230d90416fff..c3f0a3cc236e44b064ff4c80b2b0fcb5528e3a8d 100644 --- a/src/locale/zh-CN/index.ts +++ b/src/locale/zh-CN/index.ts @@ -101,6 +101,11 @@ export default { searchForm: { search: '查询', reset: '重置', + saveFilter: '保存条件', + more: '更多', + saveTitle: '存储自定义查询', + saveName: '保存名称', + savePlaceholder: '请输入要存储的自定义查询名称', }, }, list: { diff --git a/src/panel-component/setting-container/setting-container.controller.ts b/src/panel-component/setting-container/setting-container.controller.ts index d6e5f2ce923fed68b3f07f9272a8fc8db9276116..f38fb3a39fe72011df57e3bd44eacb7f9bcbc828 100644 --- a/src/panel-component/setting-container/setting-container.controller.ts +++ b/src/panel-component/setting-container/setting-container.controller.ts @@ -1,5 +1,6 @@ import { IMobMDCtrlController, + ISearchBarController, ISearchFormController, PanelContainerController, } from '@ibiz-template/runtime'; @@ -35,6 +36,17 @@ export class SettingContainerController extends PanelContainerController 0); } + /** + * 是否有快速搜索栏 + * + * @readonly + * @type {boolean} + * @memberof SettingContainerController + */ + get searchbar(): ISearchBarController | undefined { + return this.panel.view.getController('searchbar') as ISearchBarController; + } + /** * @description 是否可见 * @readonly @@ -42,6 +54,9 @@ export class SettingContainerController extends PanelContainerController - + + + )}