From 403e8e7dd69b791ed5bbe2e7abade433733010dc Mon Sep 17 00:00:00 2001 From: zhf <1204297681@qq.com> Date: Fri, 14 Jun 2024 20:58:03 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A4=9A=E6=95=B0=E6=8D=AE=E9=83=A8?= =?UTF-8?q?=E4=BB=B6=E8=A1=A8=E5=8D=95=E8=A1=A5=E5=85=85style2=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F=E5=91=88=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../form-mdctrl-form/form-mdctrl-form.tsx | 31 ++ .../form/form-detail/form-mdctrl/index.ts | 2 + .../mdctrl-container2/icon/index.tsx | 99 ++++++ .../mdctrl-container2/mdctrl-container2.scss | 144 +++++++++ .../mdctrl-container2/mdctrl-container2.tsx | 294 ++++++++++++++++++ 5 files changed, 570 insertions(+) create mode 100644 src/control/form/form-detail/form-mdctrl/mdctrl-container2/icon/index.tsx create mode 100644 src/control/form/form-detail/form-mdctrl/mdctrl-container2/mdctrl-container2.scss create mode 100644 src/control/form/form-detail/form-mdctrl/mdctrl-container2/mdctrl-container2.tsx diff --git a/src/control/form/form-detail/form-mdctrl/form-mdctrl-form/form-mdctrl-form.tsx b/src/control/form/form-detail/form-mdctrl/form-mdctrl-form/form-mdctrl-form.tsx index 083809cf..43401b06 100644 --- a/src/control/form/form-detail/form-mdctrl/form-mdctrl-form/form-mdctrl-form.tsx +++ b/src/control/form/form-detail/form-mdctrl/form-mdctrl-form/form-mdctrl-form.tsx @@ -46,6 +46,37 @@ export const FormMDCtrlForm = defineComponent({ render() { const { state, formProvider, model } = this.controller; + if ((model as IData).userTag === 'style2') { + return ( + + {{ + item: ({ data }: { data: IData }) => { + if (!formProvider) { + return ( + + {ibiz.i18n.t('control.form.formMDctrlForm.noFindProvider')} + + ); + } + const formComponent = h( + resolveComponent(formProvider.component), + { + class: this.ns.be('item', 'form'), + key: data.id, + modelData: model.contentControl!, + context: data.context, + params: data.params, + onCreated: (event: EventBase) => { + this.onCreated(data.id, event); + }, + }, + ); + return formComponent; + }, + }} + + ); + } return ( new FormMDCtrlProvider()); }); diff --git a/src/control/form/form-detail/form-mdctrl/mdctrl-container2/icon/index.tsx b/src/control/form/form-detail/form-mdctrl/mdctrl-container2/icon/index.tsx new file mode 100644 index 00000000..daa50020 --- /dev/null +++ b/src/control/form/form-detail/form-mdctrl/mdctrl-container2/icon/index.tsx @@ -0,0 +1,99 @@ +import { VNode } from 'vue'; + +/** + * 拖拽图标 + */ +export const dragIcon = (): VNode => ( + + + + + + + +); + +/** + * 删除图标 + */ +export const removeIcon = (): VNode => ( + + + + + +); + +/** + * 添加图标 + */ +export const addIcon = (): VNode => ( + + + + + +); + +/** + * 左箭头图标 + */ +export const leftArrowIcon = (): VNode => ( + + + + + +); + +/** + * 右箭头图标 + */ +export const rightArrowIcon = (): VNode => ( + + + + + +); diff --git a/src/control/form/form-detail/form-mdctrl/mdctrl-container2/mdctrl-container2.scss b/src/control/form/form-detail/form-mdctrl/mdctrl-container2/mdctrl-container2.scss new file mode 100644 index 00000000..f292876a --- /dev/null +++ b/src/control/form/form-detail/form-mdctrl/mdctrl-container2/mdctrl-container2.scss @@ -0,0 +1,144 @@ +@include b(mdctrl-container2-header) { + position: relative; + display: flex; + overflow: hidden; +} + +@include b(mdctrl-container2-header-content) { + display: flex; + flex: 1; + height: getCssVar('height-control', 'large'); + overflow: auto hidden; + background: getCssVar(color, bg, 0); + border: 1px solid getCssVar(color, border); + scrollbar-width: none; + -ms-overflow-style: none; + + &::-webkit-scrollbar { + display: none; + width: 0; + height: 0; + } +} + +@include b(mdctrl-container2-header-left-arrow) { + position: absolute; + top: 0; + bottom: 0; + left: 0; + display: flex; + align-items: center; + justify-content: center; + width: getCssVar('spacing', 'base-loose'); + cursor: pointer; + background: getCssVar(color, disabled, border); + + > svg { + fill: getCssVar(color, text, 3); + } +} + +@include b(mdctrl-container2-header-right-arrow) { + position: absolute; + top: 0; + right: 0; + bottom: 0; + display: flex; + align-items: center; + justify-content: center; + width: getCssVar('spacing', 'base-loose'); + cursor: pointer; + background: getCssVar(color, disabled, border); + + > svg { + fill: getCssVar(color, text, 3); + } +} + + +@include b(mdctrl-container2-header-item) { + position: relative; + display: flex; + flex: 0 0 auto; + align-items: center; + justify-content: center; + width: calc((100% - #{getCssVar('height-control', 'large')}) / 5); + height: getCssVar('height-control', 'large'); + padding: 0 getCssVar('spacing', 'base-loose'); + line-height: getCssVar('height-control', 'large'); + text-align: center; + cursor: pointer; + border-right: 1px solid getCssVar(color, border); + + @include e(drag-icon) { + position: absolute; + left: 0; + display: none; + + > svg { + fill: getCssVar(color, text, 3); + } + } + + @include e(icon) { + display: flex; + flex: 0 0 auto; + align-items: center; + justify-content: center; + margin-right: getCssVar('spacing', 'extra-tight'); + } + + @include e(text) { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + @include e(btn) { + position: absolute; + top: 0; + right: getCssVar('spacing', 'extra-tight'); + display: none; + + > svg { + fill: getCssVar(color, text, 3); + } + + &:hover { + > svg { + fill: getCssVar(color, danger); + } + } + } + + @include m(hidden-border) { + border-right: none; + } + + @include m(active) { + background: getCssVar(color, bg, 1); + } + + @include m(drag) { + background: getCssVar(color, bg, 1); + border: 1px solid getCssVar(color, border); + } + + @include m(ghost) { + background: getCssVar(color, border); + border: none; + + @include e(text) { + opacity: 0; + } + } + + &:hover:not(.#{bem('mdctrl-container2-header-item', '', 'dragging')}):not(.#{bem('mdctrl-container2-header-item', '', 'drag')}):not(.#{bem('mdctrl-container2-header-item', '', 'ghost')}) { + background: getCssVar(color, bg, 1); + + .#{bem('mdctrl-container2-header-item', 'drag-icon')}, + .#{bem('mdctrl-container2-header-item', 'btn')}{ + display: block; + } + } +} \ No newline at end of file diff --git a/src/control/form/form-detail/form-mdctrl/mdctrl-container2/mdctrl-container2.tsx b/src/control/form/form-detail/form-mdctrl/mdctrl-container2/mdctrl-container2.tsx new file mode 100644 index 00000000..65fb1dac --- /dev/null +++ b/src/control/form/form-detail/form-mdctrl/mdctrl-container2/mdctrl-container2.tsx @@ -0,0 +1,294 @@ +import { FormMDCtrlFormController } from '@ibiz-template/runtime'; +import { useNamespace } from '@ibiz-template/vue3-util'; +import { + PropType, + defineComponent, + onMounted, + onUnmounted, + ref, + watch, +} from 'vue'; +import draggable from 'vuedraggable'; +import './mdctrl-container2.scss'; +import { + addIcon, + dragIcon, + leftArrowIcon, + removeIcon, + rightArrowIcon, +} from './icon'; + +export const MDCtrlContainer2 = defineComponent({ + name: 'IBizMDCtrlContainer2', + components: { + draggable, + }, + props: { + controller: { + type: FormMDCtrlFormController, + required: true, + }, + items: { + type: Array as PropType, + default: () => [], + }, + }, + setup(props) { + const ns = useNamespace('mdctrl-container2'); + + // 当前选中项 + const currentItem = ref(''); + + watch( + () => props.items, + () => { + if (!currentItem.value) { + currentItem.value = props.items[0]?.id || ''; + } + }, + { + immediate: true, + }, + ); + + // 拖拽中的项 + const draggingKey = ref(''); + + // 容器组件 + const container = ref(); + + // 是否展示左箭头 + const isShowLeftArrow = ref(false); + + // 是否展示右箭头 + const isShowRightArrow = ref(false); + + // 是否展示border + const isShowBorder = ref(true); + + // 元素大小变化监视器 + let resizeObserver: ResizeObserver; + + // 更新箭头可视性 + const updateArrowVisible = () => { + if (container.value) { + const el = container.value.$el as HTMLElement; + if (el) { + isShowLeftArrow.value = el.scrollLeft > 0; + isShowRightArrow.value = + el.scrollLeft < el.scrollWidth - el.offsetWidth; + isShowBorder.value = el.offsetWidth > el.scrollWidth; + } + } + }; + + onMounted(() => { + if (container.value && container.value.$el) { + resizeObserver = new ResizeObserver(entries => { + entries.forEach(() => { + updateArrowVisible(); + }); + }); + resizeObserver.observe(container.value.$el); + } + }); + + onUnmounted(() => { + if (resizeObserver) { + resizeObserver.disconnect(); + } + }); + + // 处理项选中 + const handleSelect = (e: MouseEvent, item: IData) => { + e.stopPropagation(); + currentItem.value = item.id; + }; + + // 处理项添加 + const handleAdd = (e: MouseEvent) => { + e.stopPropagation(); + props.controller.create(); + currentItem.value = props.items[props.items.length - 1]?.id || ''; + }; + + // 处理项删除 + const handleRemove = async (e: MouseEvent, item: IData) => { + e.stopPropagation(); + await props.controller.remove(item.id); + if (currentItem.value === item.id) { + currentItem.value = props.items[0]?.id || ''; + } + updateArrowVisible(); + }; + + // 处理箭头点击 + const handleArrowClick = (e: MouseEvent, direction: 'left' | 'right') => { + e.stopPropagation(); + if (container.value) { + const el = container.value.$el as HTMLElement; + if (el) { + const children = Array.from(el.children || []) as HTMLElement[]; + const child = children.find(item => + item.classList.contains(ns.b('header-item')), + ); + if (child) { + const width = child.offsetWidth; + if (direction === 'right') { + el.scrollLeft += width; + } + if (direction === 'left') { + el.scrollLeft -= width; + } + } + updateArrowVisible(); + } + } + }; + + // 处理拖拽开始 + const handleDragStart = (item: IData) => { + draggingKey.value = item.id; + }; + + // 处理拖拽结束 + const handleDragEnd = () => { + draggingKey.value = ''; + updateArrowVisible(); + }; + + return { + ns, + currentItem, + draggingKey, + container, + isShowLeftArrow, + isShowRightArrow, + isShowBorder, + handleSelect, + handleAdd, + handleRemove, + handleArrowClick, + handleDragStart, + handleDragEnd, + }; + }, + render() { + return ( + + + + {{ + item: ({ element }: { element: IData }) => { + return ( + { + this.handleDragStart(element); + }} + onDragend={() => { + this.handleDragEnd(); + }} + onClick={(e: MouseEvent) => { + this.handleSelect(e, element); + }} + > + + {dragIcon()} + + + {element.title} + + {this.controller.enableDelete && ( + { + this.handleRemove(e, element); + }} + > + {removeIcon()} + + )} + + ); + }, + footer: () => { + return [ + this.controller.enableCreate && ( + { + this.handleAdd(e); + }} + > + + {addIcon()} + + + {ibiz.i18n.t('app.add')} + + + ), + this.isShowLeftArrow && ( + { + this.handleArrowClick(e, 'left'); + }} + > + {leftArrowIcon()} + + ), + this.isShowRightArrow && ( + { + this.handleArrowClick(e, 'right'); + }} + > + {rightArrowIcon()} + + ), + ]; + }, + }} + + + + + {this.items.map(item => { + return ( + + {this.$slots.item?.({ data: item })} + + ); + })} + + + ); + }, +}); -- Gitee