mirror of
				https://github.com/Tencent/tmagic-editor.git
				synced 2025-11-04 02:28:04 +08:00 
			
		
		
		
	feat(editor): 数据源抽屉切floatbox
This commit is contained in:
		
							parent
							
								
									e2326ff4f6
								
							
						
					
					
						commit
						96149bd2ae
					
				@ -9,59 +9,57 @@
 | 
				
			|||||||
    :before-close="beforeClose"
 | 
					    :before-close="beforeClose"
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <template #body>
 | 
					    <template #body>
 | 
				
			||||||
      <div ref="floatingBoxBody" style="height: 100%"></div>
 | 
					      <MFormBox
 | 
				
			||||||
 | 
					        class="m-editor-code-block-editor"
 | 
				
			||||||
 | 
					        ref="formBox"
 | 
				
			||||||
 | 
					        label-width="80px"
 | 
				
			||||||
 | 
					        :close-on-press-escape="false"
 | 
				
			||||||
 | 
					        :title="content.name"
 | 
				
			||||||
 | 
					        :config="functionConfig"
 | 
				
			||||||
 | 
					        :values="content"
 | 
				
			||||||
 | 
					        :disabled="disabled"
 | 
				
			||||||
 | 
					        style="height: 100%"
 | 
				
			||||||
 | 
					        @change="changeHandler"
 | 
				
			||||||
 | 
					        @submit="submitForm"
 | 
				
			||||||
 | 
					        @error="errorHandler"
 | 
				
			||||||
 | 
					        @closed="closedHandler"
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <template #left>
 | 
				
			||||||
 | 
					          <TMagicButton v-if="!disabled" type="primary" link @click="difVisible = true">查看修改</TMagicButton>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					      </MFormBox>
 | 
				
			||||||
    </template>
 | 
					    </template>
 | 
				
			||||||
  </FloatingBox>
 | 
					  </FloatingBox>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <Teleport :to="floatingBoxBody" :disabled="slideType === 'box'" v-if="editVisible">
 | 
					  <Teleport to="body">
 | 
				
			||||||
    <MFormBox
 | 
					    <TMagicDialog title="查看修改" v-model="difVisible" fullscreen>
 | 
				
			||||||
      class="m-editor-code-block-editor"
 | 
					      <div style="display: flex; margin-bottom: 10px">
 | 
				
			||||||
      ref="formBox"
 | 
					        <div style="flex: 1"><TMagicTag size="small" type="info">修改前</TMagicTag></div>
 | 
				
			||||||
      label-width="80px"
 | 
					        <div style="flex: 1"><TMagicTag size="small" type="success">修改后</TMagicTag></div>
 | 
				
			||||||
      :close-on-press-escape="false"
 | 
					      </div>
 | 
				
			||||||
      :title="content.name"
 | 
					
 | 
				
			||||||
      :config="functionConfig"
 | 
					      <CodeEditor
 | 
				
			||||||
      :values="content"
 | 
					        v-if="difVisible"
 | 
				
			||||||
      :disabled="disabled"
 | 
					        ref="magicVsEditor"
 | 
				
			||||||
      :height="floatingBoxBody?.clientHeight"
 | 
					        type="diff"
 | 
				
			||||||
      @change="changeHandler"
 | 
					        language="json"
 | 
				
			||||||
      @submit="submitForm"
 | 
					        :initValues="content.content"
 | 
				
			||||||
      @error="errorHandler"
 | 
					        :modifiedValues="formBox?.form?.values.content"
 | 
				
			||||||
      @closed="closedHandler"
 | 
					        :style="`height: ${windowRect.height - 150}px`"
 | 
				
			||||||
    >
 | 
					      ></CodeEditor>
 | 
				
			||||||
      <template #left>
 | 
					
 | 
				
			||||||
        <TMagicButton v-if="!disabled" type="primary" link @click="difVisible = true">查看修改</TMagicButton>
 | 
					      <template #footer>
 | 
				
			||||||
 | 
					        <span class="dialog-footer">
 | 
				
			||||||
 | 
					          <TMagicButton size="small" @click="difVisible = false">取消</TMagicButton>
 | 
				
			||||||
 | 
					          <TMagicButton size="small" type="primary" @click="diffChange">确定</TMagicButton>
 | 
				
			||||||
 | 
					        </span>
 | 
				
			||||||
      </template>
 | 
					      </template>
 | 
				
			||||||
    </MFormBox>
 | 
					    </TMagicDialog>
 | 
				
			||||||
  </Teleport>
 | 
					  </Teleport>
 | 
				
			||||||
 | 
					 | 
				
			||||||
  <TMagicDialog v-model="difVisible" title="查看修改" fullscreen>
 | 
					 | 
				
			||||||
    <div style="display: flex; margin-bottom: 10px">
 | 
					 | 
				
			||||||
      <div style="flex: 1"><TMagicTag size="small" type="info">修改前</TMagicTag></div>
 | 
					 | 
				
			||||||
      <div style="flex: 1"><TMagicTag size="small" type="success">修改后</TMagicTag></div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <CodeEditor
 | 
					 | 
				
			||||||
      v-if="difVisible"
 | 
					 | 
				
			||||||
      ref="magicVsEditor"
 | 
					 | 
				
			||||||
      type="diff"
 | 
					 | 
				
			||||||
      language="json"
 | 
					 | 
				
			||||||
      :initValues="content.content"
 | 
					 | 
				
			||||||
      :modifiedValues="formBox?.form?.values.content"
 | 
					 | 
				
			||||||
      :style="`height: ${windowRect.height - 150}px`"
 | 
					 | 
				
			||||||
    ></CodeEditor>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <template #footer>
 | 
					 | 
				
			||||||
      <span class="dialog-footer">
 | 
					 | 
				
			||||||
        <TMagicButton size="small" @click="difVisible = false">取消</TMagicButton>
 | 
					 | 
				
			||||||
        <TMagicButton size="small" type="primary" @click="diffChange">确定</TMagicButton>
 | 
					 | 
				
			||||||
      </span>
 | 
					 | 
				
			||||||
    </template>
 | 
					 | 
				
			||||||
  </TMagicDialog>
 | 
					 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script lang="ts" setup>
 | 
					<script lang="ts" setup>
 | 
				
			||||||
import { computed, inject, nextTick, ref } from 'vue';
 | 
					import { computed, inject, Ref, ref } from 'vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { TMagicButton, TMagicDialog, tMagicMessage, tMagicMessageBox, TMagicTag } from '@tmagic/design';
 | 
					import { TMagicButton, TMagicDialog, tMagicMessage, tMagicMessageBox, TMagicTag } from '@tmagic/design';
 | 
				
			||||||
import { ColumnConfig, FormConfig, FormState, MFormBox } from '@tmagic/form';
 | 
					import { ColumnConfig, FormConfig, FormState, MFormBox } from '@tmagic/form';
 | 
				
			||||||
@ -69,9 +67,10 @@ import type { CodeBlockContent } from '@tmagic/schema';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import FloatingBox from '@editor/components/FloatingBox.vue';
 | 
					import FloatingBox from '@editor/components/FloatingBox.vue';
 | 
				
			||||||
import { useEditorContentHeight } from '@editor/hooks/use-editor-content-height';
 | 
					import { useEditorContentHeight } from '@editor/hooks/use-editor-content-height';
 | 
				
			||||||
 | 
					import { useNextFloatBoxPosition } from '@editor/hooks/use-next-float-box-position';
 | 
				
			||||||
import { useWindowRect } from '@editor/hooks/use-window-rect';
 | 
					import { useWindowRect } from '@editor/hooks/use-window-rect';
 | 
				
			||||||
import CodeEditor from '@editor/layouts/CodeEditor.vue';
 | 
					import CodeEditor from '@editor/layouts/CodeEditor.vue';
 | 
				
			||||||
import type { Services, SlideType } from '@editor/type';
 | 
					import type { Services } from '@editor/type';
 | 
				
			||||||
import { getConfig } from '@editor/utils/config';
 | 
					import { getConfig } from '@editor/utils/config';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
defineOptions({
 | 
					defineOptions({
 | 
				
			||||||
@ -86,7 +85,6 @@ const props = defineProps<{
 | 
				
			|||||||
  disabled?: boolean;
 | 
					  disabled?: boolean;
 | 
				
			||||||
  isDataSource?: boolean;
 | 
					  isDataSource?: boolean;
 | 
				
			||||||
  dataSourceType?: string;
 | 
					  dataSourceType?: string;
 | 
				
			||||||
  slideType?: SlideType;
 | 
					 | 
				
			||||||
}>();
 | 
					}>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const emit = defineEmits<{
 | 
					const emit = defineEmits<{
 | 
				
			||||||
@ -229,7 +227,6 @@ const changeHandler = (values: CodeBlockContent) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const beforeClose = (done: (cancel?: boolean) => void) => {
 | 
					const beforeClose = (done: (cancel?: boolean) => void) => {
 | 
				
			||||||
  if (!changedValue.value) {
 | 
					  if (!changedValue.value) {
 | 
				
			||||||
    editVisible.value = false;
 | 
					 | 
				
			||||||
    done();
 | 
					    done();
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -242,12 +239,10 @@ const beforeClose = (done: (cancel?: boolean) => void) => {
 | 
				
			|||||||
    })
 | 
					    })
 | 
				
			||||||
    .then(() => {
 | 
					    .then(() => {
 | 
				
			||||||
      changedValue.value && submitForm(changedValue.value);
 | 
					      changedValue.value && submitForm(changedValue.value);
 | 
				
			||||||
      editVisible.value = false;
 | 
					 | 
				
			||||||
      done();
 | 
					      done();
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    .catch((action: string) => {
 | 
					    .catch((action: string) => {
 | 
				
			||||||
      if (action === 'cancel') {
 | 
					      if (action === 'cancel') {
 | 
				
			||||||
        editVisible.value = false;
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      done(action === 'cancel');
 | 
					      done(action === 'cancel');
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
@ -257,35 +252,17 @@ const closedHandler = () => {
 | 
				
			|||||||
  changedValue.value = undefined;
 | 
					  changedValue.value = undefined;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const editVisible = ref<boolean>(false);
 | 
					const parentFloating = inject<Ref<HTMLDivElement>>('parentFloating');
 | 
				
			||||||
const floatingBoxBody = ref<HTMLDivElement>();
 | 
					const { boxPosition, calcBoxPosition } = useNextFloatBoxPosition(services?.uiService, parentFloating);
 | 
				
			||||||
 | 
					 | 
				
			||||||
const boxPosition = computed(() => {
 | 
					 | 
				
			||||||
  const columnWidth = services?.uiService?.get('columnWidth');
 | 
					 | 
				
			||||||
  const navMenuRect = services?.uiService?.get('navMenuRect');
 | 
					 | 
				
			||||||
  return {
 | 
					 | 
				
			||||||
    left: columnWidth?.left ?? 0,
 | 
					 | 
				
			||||||
    top: (navMenuRect?.top ?? 0) + (navMenuRect?.height ?? 0),
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
defineExpose({
 | 
					defineExpose({
 | 
				
			||||||
  async show() {
 | 
					  async show() {
 | 
				
			||||||
    if (props.slideType !== 'box') {
 | 
					    calcBoxPosition();
 | 
				
			||||||
      boxVisible.value = true;
 | 
					    boxVisible.value = true;
 | 
				
			||||||
      await nextTick();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    editVisible.value = true;
 | 
					 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async hide() {
 | 
					  async hide() {
 | 
				
			||||||
    editVisible.value = false;
 | 
					    boxVisible.value = false;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (props.slideType !== 'box') {
 | 
					 | 
				
			||||||
      await nextTick();
 | 
					 | 
				
			||||||
      boxVisible.value = false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
				
			|||||||
@ -17,13 +17,14 @@
 | 
				
			|||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue';
 | 
					import { computed, inject, nextTick, onBeforeUnmount, provide, ref, watch } from 'vue';
 | 
				
			||||||
import { Close } from '@element-plus/icons-vue';
 | 
					import { Close } from '@element-plus/icons-vue';
 | 
				
			||||||
import VanillaMoveable from 'moveable';
 | 
					import VanillaMoveable from 'moveable';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { TMagicButton, useZIndex } from '@tmagic/design';
 | 
					import { TMagicButton, useZIndex } from '@tmagic/design';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import MIcon from '@editor/components/Icon.vue';
 | 
					import MIcon from '@editor/components/Icon.vue';
 | 
				
			||||||
 | 
					import type { Services } from '@editor/type';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface Position {
 | 
					interface Position {
 | 
				
			||||||
  left: number;
 | 
					  left: number;
 | 
				
			||||||
@ -50,7 +51,7 @@ const target = ref<HTMLDivElement>();
 | 
				
			|||||||
const titleEl = ref<HTMLDivElement>();
 | 
					const titleEl = ref<HTMLDivElement>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const zIndex = useZIndex();
 | 
					const zIndex = useZIndex();
 | 
				
			||||||
const curZIndex = ref<number>(zIndex.nextZIndex());
 | 
					const curZIndex = ref<number>(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const titleHeight = ref(0);
 | 
					const titleHeight = ref(0);
 | 
				
			||||||
const bodyHeight = computed(() => {
 | 
					const bodyHeight = computed(() => {
 | 
				
			||||||
@ -65,12 +66,21 @@ const bodyHeight = computed(() => {
 | 
				
			|||||||
  return 'auto';
 | 
					  return 'auto';
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const style = computed(() => ({
 | 
					const services = inject<Services>('services');
 | 
				
			||||||
  left: `${props.position.left}px`,
 | 
					const frameworkWidth = computed(() => services?.uiService.get('frameworkRect').width || 0);
 | 
				
			||||||
  top: `${props.position.top}px`,
 | 
					const style = computed(() => {
 | 
				
			||||||
  width: width.value ? `${width.value}px` : 'auto',
 | 
					  let { left } = props.position;
 | 
				
			||||||
  height: height.value ? `${height.value}px` : 'auto',
 | 
					  if (width.value) {
 | 
				
			||||||
}));
 | 
					    left = left + width.value > frameworkWidth.value ? frameworkWidth.value - width.value : left;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    left: `${left}px`,
 | 
				
			||||||
 | 
					    top: `${props.position.top}px`,
 | 
				
			||||||
 | 
					    width: width.value ? `${width.value}px` : 'auto',
 | 
				
			||||||
 | 
					    height: height.value ? `${height.value}px` : 'auto',
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let moveable: VanillaMoveable | null = null;
 | 
					let moveable: VanillaMoveable | null = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -114,6 +124,7 @@ watch(
 | 
				
			|||||||
  async (visible) => {
 | 
					  async (visible) => {
 | 
				
			||||||
    if (visible) {
 | 
					    if (visible) {
 | 
				
			||||||
      await nextTick();
 | 
					      await nextTick();
 | 
				
			||||||
 | 
					      curZIndex.value = zIndex.nextZIndex();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const targetRect = target.value?.getBoundingClientRect();
 | 
					      const targetRect = target.value?.getBoundingClientRect();
 | 
				
			||||||
      if (targetRect) {
 | 
					      if (targetRect) {
 | 
				
			||||||
@ -157,6 +168,8 @@ const nextZIndex = () => {
 | 
				
			|||||||
  curZIndex.value = zIndex.nextZIndex();
 | 
					  curZIndex.value = zIndex.nextZIndex();
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					provide('parentFloating', target);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
defineExpose({
 | 
					defineExpose({
 | 
				
			||||||
  bodyHeight,
 | 
					  bodyHeight,
 | 
				
			||||||
  target,
 | 
					  target,
 | 
				
			||||||
 | 
				
			|||||||
@ -7,39 +7,57 @@
 | 
				
			|||||||
      <TMagicButton size="small" type="primary" :disabled="disabled" plain @click="newHandler()">添加</TMagicButton>
 | 
					      <TMagicButton size="small" type="primary" :disabled="disabled" plain @click="newHandler()">添加</TMagicButton>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <MFormDrawer
 | 
					    <FloatingBox
 | 
				
			||||||
      ref="addDialog"
 | 
					      v-model:visible="addDialogVisible"
 | 
				
			||||||
      label-width="80px"
 | 
					      v-model:width="width"
 | 
				
			||||||
 | 
					      v-model:height="editorHeight"
 | 
				
			||||||
      :title="fieldTitle"
 | 
					      :title="fieldTitle"
 | 
				
			||||||
      :config="dataSourceFieldsConfig"
 | 
					      :position="boxPosition"
 | 
				
			||||||
      :values="fieldValues"
 | 
					    >
 | 
				
			||||||
      :parentValues="model[name]"
 | 
					      <template #body>
 | 
				
			||||||
      :disabled="disabled"
 | 
					        <MFormBox
 | 
				
			||||||
      :width="width"
 | 
					          label-width="80px"
 | 
				
			||||||
      @submit="fieldChange"
 | 
					          :title="fieldTitle"
 | 
				
			||||||
    ></MFormDrawer>
 | 
					          :config="dataSourceFieldsConfig"
 | 
				
			||||||
 | 
					          :values="fieldValues"
 | 
				
			||||||
 | 
					          :parentValues="model[name]"
 | 
				
			||||||
 | 
					          :disabled="disabled"
 | 
				
			||||||
 | 
					          @submit="fieldChange"
 | 
				
			||||||
 | 
					        ></MFormBox>
 | 
				
			||||||
 | 
					      </template>
 | 
				
			||||||
 | 
					    </FloatingBox>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <MFormDrawer
 | 
					    <FloatingBox
 | 
				
			||||||
      ref="addFromJsonDialog"
 | 
					      v-model:visible="addFromJsonDialogVisible"
 | 
				
			||||||
 | 
					      v-model:width="width"
 | 
				
			||||||
 | 
					      v-model:height="editorHeight"
 | 
				
			||||||
      title="快速添加数据定义"
 | 
					      title="快速添加数据定义"
 | 
				
			||||||
      :config="jsonFromConfig"
 | 
					      :position="boxPosition"
 | 
				
			||||||
      :values="jsonFromValues"
 | 
					    >
 | 
				
			||||||
      :disabled="disabled"
 | 
					      <template #body>
 | 
				
			||||||
      :width="width"
 | 
					        <MFormBox
 | 
				
			||||||
      @submit="addFromJsonFromChange"
 | 
					          :config="jsonFromConfig"
 | 
				
			||||||
    ></MFormDrawer>
 | 
					          :values="jsonFromValues"
 | 
				
			||||||
 | 
					          :disabled="disabled"
 | 
				
			||||||
 | 
					          @submit="addFromJsonFromChange"
 | 
				
			||||||
 | 
					        ></MFormBox>
 | 
				
			||||||
 | 
					      </template>
 | 
				
			||||||
 | 
					    </FloatingBox>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import { computed, inject, ref } from 'vue';
 | 
					import { inject, Ref, ref } from 'vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { TMagicButton, tMagicMessage, tMagicMessageBox } from '@tmagic/design';
 | 
					import { TMagicButton, tMagicMessage, tMagicMessageBox } from '@tmagic/design';
 | 
				
			||||||
import { type FieldProps, type FormConfig, type FormState, MFormDrawer } from '@tmagic/form';
 | 
					import { type FieldProps, type FormConfig, type FormState, MFormBox } from '@tmagic/form';
 | 
				
			||||||
import type { DataSchema } from '@tmagic/schema';
 | 
					import type { DataSchema } from '@tmagic/schema';
 | 
				
			||||||
import { type ColumnConfig, MagicTable } from '@tmagic/table';
 | 
					import { type ColumnConfig, MagicTable } from '@tmagic/table';
 | 
				
			||||||
import { getDefaultValueFromFields } from '@tmagic/utils';
 | 
					import { getDefaultValueFromFields } from '@tmagic/utils';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import FloatingBox from '@editor/components/FloatingBox.vue';
 | 
				
			||||||
 | 
					import { useEditorContentHeight } from '@editor/hooks';
 | 
				
			||||||
 | 
					import { useNextFloatBoxPosition } from '@editor/hooks/use-next-float-box-position';
 | 
				
			||||||
import type { Services } from '@editor/type';
 | 
					import type { Services } from '@editor/type';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
defineOptions({
 | 
					defineOptions({
 | 
				
			||||||
@ -61,17 +79,16 @@ const emit = defineEmits(['change']);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const services = inject<Services>('services');
 | 
					const services = inject<Services>('services');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const addDialog = ref<InstanceType<typeof MFormDrawer>>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const fieldValues = ref<Record<string, any>>({});
 | 
					const fieldValues = ref<Record<string, any>>({});
 | 
				
			||||||
const fieldTitle = ref('');
 | 
					const fieldTitle = ref('');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const width = computed(() => globalThis.document.body.clientWidth - (services?.uiService.get('columnWidth').left || 0));
 | 
					const width = defineModel<number>('width', { default: 670 });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const newHandler = () => {
 | 
					const newHandler = () => {
 | 
				
			||||||
  fieldValues.value = {};
 | 
					  fieldValues.value = {};
 | 
				
			||||||
  fieldTitle.value = '新增属性';
 | 
					  fieldTitle.value = '新增属性';
 | 
				
			||||||
  addDialog.value?.show();
 | 
					  calcBoxPosition();
 | 
				
			||||||
 | 
					  addDialogVisible.value = true;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const fieldChange = ({ index, ...value }: Record<string, any>) => {
 | 
					const fieldChange = ({ index, ...value }: Record<string, any>) => {
 | 
				
			||||||
@ -81,7 +98,7 @@ const fieldChange = ({ index, ...value }: Record<string, any>) => {
 | 
				
			|||||||
    props.model[props.name].push(value);
 | 
					    props.model[props.name].push(value);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  addDialog.value?.hide();
 | 
					  addDialogVisible.value = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  emit('change', props.model[props.name]);
 | 
					  emit('change', props.model[props.name]);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -122,7 +139,8 @@ const fieldColumns: ColumnConfig[] = [
 | 
				
			|||||||
            index,
 | 
					            index,
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
          fieldTitle.value = `编辑${row.title}`;
 | 
					          fieldTitle.value = `编辑${row.title}`;
 | 
				
			||||||
          addDialog.value?.show();
 | 
					          calcBoxPosition();
 | 
				
			||||||
 | 
					          addDialogVisible.value = true;
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
@ -220,7 +238,6 @@ const dataSourceFieldsConfig: FormConfig = [
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const addFromJsonDialog = ref<InstanceType<typeof MFormDrawer>>();
 | 
					 | 
				
			||||||
const jsonFromConfig: FormConfig = [
 | 
					const jsonFromConfig: FormConfig = [
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: 'data',
 | 
					    name: 'data',
 | 
				
			||||||
@ -238,7 +255,8 @@ const jsonFromValues = ref({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const newFromJsonHandler = () => {
 | 
					const newFromJsonHandler = () => {
 | 
				
			||||||
  jsonFromValues.value.data = getDefaultValueFromFields(props.model[props.name]);
 | 
					  jsonFromValues.value.data = getDefaultValueFromFields(props.model[props.name]);
 | 
				
			||||||
  addFromJsonDialog.value?.show();
 | 
					  calcBoxPosition();
 | 
				
			||||||
 | 
					  addFromJsonDialogVisible.value = true;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const getValueType = (value: any) => {
 | 
					const getValueType = (value: any) => {
 | 
				
			||||||
@ -288,11 +306,18 @@ const addFromJsonFromChange = ({ data }: { data: string }) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    props.model[props.name] = getFieldsConfig(value, props.model[props.name]);
 | 
					    props.model[props.name] = getFieldsConfig(value, props.model[props.name]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    addFromJsonDialog.value?.hide();
 | 
					    addFromJsonDialogVisible.value = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    emit('change', props.model[props.name]);
 | 
					    emit('change', props.model[props.name]);
 | 
				
			||||||
  } catch (e: any) {
 | 
					  } catch (e: any) {
 | 
				
			||||||
    tMagicMessage.error(e.message);
 | 
					    tMagicMessage.error(e.message);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const addDialogVisible = defineModel<boolean>('visible', { default: false });
 | 
				
			||||||
 | 
					const addFromJsonDialogVisible = defineModel<boolean>('visible1', { default: false });
 | 
				
			||||||
 | 
					const { height: editorHeight } = useEditorContentHeight();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const parentFloating = inject<Ref<HTMLDivElement>>('parentFloating');
 | 
				
			||||||
 | 
					const { boxPosition, calcBoxPosition } = useNextFloatBoxPosition(services?.uiService, parentFloating);
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
				
			|||||||
@ -6,32 +6,44 @@
 | 
				
			|||||||
      <TMagicButton size="small" type="primary" :disabled="disabled" plain @click="newHandler()">添加</TMagicButton>
 | 
					      <TMagicButton size="small" type="primary" :disabled="disabled" plain @click="newHandler()">添加</TMagicButton>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <MFormDrawer
 | 
					    <FloatingBox
 | 
				
			||||||
      ref="addDialog"
 | 
					      v-model:visible="addDialogVisible"
 | 
				
			||||||
      label-width="120px"
 | 
					      v-model:width="width"
 | 
				
			||||||
 | 
					      v-model:height="editorHeight"
 | 
				
			||||||
      :title="drawerTitle"
 | 
					      :title="drawerTitle"
 | 
				
			||||||
      :config="formConfig"
 | 
					      :position="boxPosition"
 | 
				
			||||||
      :values="formValues"
 | 
					    >
 | 
				
			||||||
      :parentValues="model[name]"
 | 
					      <template #body>
 | 
				
			||||||
      :disabled="disabled"
 | 
					        <MFormBox
 | 
				
			||||||
      :width="width"
 | 
					          ref="addDialog"
 | 
				
			||||||
      @submit="formChangeHandler"
 | 
					          label-width="120px"
 | 
				
			||||||
    ></MFormDrawer>
 | 
					          :config="formConfig"
 | 
				
			||||||
 | 
					          :values="formValues"
 | 
				
			||||||
 | 
					          :parentValues="model[name]"
 | 
				
			||||||
 | 
					          :disabled="disabled"
 | 
				
			||||||
 | 
					          @submit="formChangeHandler"
 | 
				
			||||||
 | 
					        ></MFormBox>
 | 
				
			||||||
 | 
					      </template>
 | 
				
			||||||
 | 
					    </FloatingBox>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import { computed, inject, ref } from 'vue';
 | 
					import { inject, Ref, ref } from 'vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { TMagicButton, tMagicMessageBox, TMagicSwitch } from '@tmagic/design';
 | 
					import { TMagicButton, tMagicMessageBox, TMagicSwitch } from '@tmagic/design';
 | 
				
			||||||
import { type FieldProps, type FormConfig, type FormState, MFormDrawer } from '@tmagic/form';
 | 
					import { type FieldProps, type FormConfig, type FormState, MFormBox } from '@tmagic/form';
 | 
				
			||||||
import type { MockSchema } from '@tmagic/schema';
 | 
					import type { MockSchema } from '@tmagic/schema';
 | 
				
			||||||
import { type ColumnConfig, MagicTable } from '@tmagic/table';
 | 
					import { type ColumnConfig, MagicTable } from '@tmagic/table';
 | 
				
			||||||
import { getDefaultValueFromFields } from '@tmagic/utils';
 | 
					import { getDefaultValueFromFields } from '@tmagic/utils';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import FloatingBox from '@editor/components/FloatingBox.vue';
 | 
				
			||||||
 | 
					import { useNextFloatBoxPosition } from '@editor/hooks/use-next-float-box-position';
 | 
				
			||||||
import CodeEditor from '@editor/layouts/CodeEditor.vue';
 | 
					import CodeEditor from '@editor/layouts/CodeEditor.vue';
 | 
				
			||||||
import { Services } from '@editor/type';
 | 
					import { Services } from '@editor/type';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { useEditorContentHeight } from '..';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
defineOptions({
 | 
					defineOptions({
 | 
				
			||||||
  name: 'MFieldsDataSourceMocks',
 | 
					  name: 'MFieldsDataSourceMocks',
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
@ -50,9 +62,8 @@ const props = withDefaults(
 | 
				
			|||||||
const emit = defineEmits(['change']);
 | 
					const emit = defineEmits(['change']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const services = inject<Services>('services');
 | 
					const services = inject<Services>('services');
 | 
				
			||||||
const width = computed(() => globalThis.document.body.clientWidth - (services?.uiService.get('columnWidth').left || 0));
 | 
					const width = defineModel<number>('width', { default: 670 });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const addDialog = ref<InstanceType<typeof MFormDrawer>>();
 | 
					 | 
				
			||||||
const drawerTitle = ref('');
 | 
					const drawerTitle = ref('');
 | 
				
			||||||
const formValues = ref<Record<string, any>>({});
 | 
					const formValues = ref<Record<string, any>>({});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -182,7 +193,8 @@ const columns: ColumnConfig[] = [
 | 
				
			|||||||
            index,
 | 
					            index,
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
          drawerTitle.value = `编辑${row.title}`;
 | 
					          drawerTitle.value = `编辑${row.title}`;
 | 
				
			||||||
          addDialog.value?.show();
 | 
					          calcBoxPosition();
 | 
				
			||||||
 | 
					          addDialogVisible.value = true;
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
@ -206,7 +218,8 @@ const newHandler = () => {
 | 
				
			|||||||
    enable: isFirstRow,
 | 
					    enable: isFirstRow,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  drawerTitle.value = '新增Mock';
 | 
					  drawerTitle.value = '新增Mock';
 | 
				
			||||||
  addDialog.value?.show();
 | 
					  calcBoxPosition();
 | 
				
			||||||
 | 
					  addDialogVisible.value = true;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const formChangeHandler = ({ index, ...value }: Record<string, any>) => {
 | 
					const formChangeHandler = ({ index, ...value }: Record<string, any>) => {
 | 
				
			||||||
@ -216,7 +229,7 @@ const formChangeHandler = ({ index, ...value }: Record<string, any>) => {
 | 
				
			|||||||
    props.model[props.name].push(value);
 | 
					    props.model[props.name].push(value);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  addDialog.value?.hide();
 | 
					  addDialogVisible.value = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  emit('change', props.model[props.name]);
 | 
					  emit('change', props.model[props.name]);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -234,4 +247,9 @@ const toggleValue = (row: MockSchema, key: 'enable' | 'useInEditor', value: bool
 | 
				
			|||||||
    index,
 | 
					    index,
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const addDialogVisible = defineModel<boolean>('visible', { default: false });
 | 
				
			||||||
 | 
					const { height: editorHeight } = useEditorContentHeight();
 | 
				
			||||||
 | 
					const parentFloating = inject<Ref<HTMLDivElement>>('parentFloating');
 | 
				
			||||||
 | 
					const { boxPosition, calcBoxPosition } = useNextFloatBoxPosition(services?.uiService, parentFloating);
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
				
			|||||||
@ -10,7 +10,7 @@ export const useEditorContentHeight = () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  const height = ref(0);
 | 
					  const height = ref(0);
 | 
				
			||||||
  watchEffect(() => {
 | 
					  watchEffect(() => {
 | 
				
			||||||
    if (height.value > 0) return;
 | 
					    if (height.value > 0 && height.value === editorContentHeight.value) return;
 | 
				
			||||||
    height.value = editorContentHeight.value;
 | 
					    height.value = editorContentHeight.value;
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,6 @@
 | 
				
			|||||||
import { computed, ComputedRef, ref, watch } from 'vue';
 | 
					import { computed, ComputedRef, inject, ref, watch } from 'vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import type { Services } from '@editor/type';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface State {
 | 
					interface State {
 | 
				
			||||||
  status: boolean;
 | 
					  status: boolean;
 | 
				
			||||||
@ -7,6 +9,8 @@ interface State {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const useFloatBox = (slideKeys: ComputedRef<string[]>) => {
 | 
					export const useFloatBox = (slideKeys: ComputedRef<string[]>) => {
 | 
				
			||||||
 | 
					  const services = inject<Services>('services');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const floatBoxStates = ref<{
 | 
					  const floatBoxStates = ref<{
 | 
				
			||||||
    [key in (typeof slideKeys.value)[number]]: State;
 | 
					    [key in (typeof slideKeys.value)[number]]: State;
 | 
				
			||||||
  }>(
 | 
					  }>(
 | 
				
			||||||
@ -30,9 +34,10 @@ export const useFloatBox = (slideKeys: ComputedRef<string[]>) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  const dragstartHandler = () => (isDragging.value = true);
 | 
					  const dragstartHandler = () => (isDragging.value = true);
 | 
				
			||||||
  const dragendHandler = (key: string, e: DragEvent) => {
 | 
					  const dragendHandler = (key: string, e: DragEvent) => {
 | 
				
			||||||
 | 
					    const navMenuRect = services?.uiService?.get('navMenuRect');
 | 
				
			||||||
    floatBoxStates.value[key] = {
 | 
					    floatBoxStates.value[key] = {
 | 
				
			||||||
      left: e.clientX,
 | 
					      left: e.clientX,
 | 
				
			||||||
      top: e.clientY,
 | 
					      top: (navMenuRect?.top ?? 0) + (navMenuRect?.height ?? 0),
 | 
				
			||||||
      status: true,
 | 
					      status: true,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    isDragging.value = false;
 | 
					    isDragging.value = false;
 | 
				
			||||||
@ -47,12 +52,13 @@ export const useFloatBox = (slideKeys: ComputedRef<string[]>) => {
 | 
				
			|||||||
    () => slideKeys.value,
 | 
					    () => slideKeys.value,
 | 
				
			||||||
    (slideKeys) => {
 | 
					    (slideKeys) => {
 | 
				
			||||||
      slideKeys.forEach((key) => {
 | 
					      slideKeys.forEach((key) => {
 | 
				
			||||||
        if (floatBoxStates.value[key]) return;
 | 
					        if (!floatBoxStates.value[key]) {
 | 
				
			||||||
        floatBoxStates.value[key] = {
 | 
					          floatBoxStates.value[key] = {
 | 
				
			||||||
          status: false,
 | 
					            status: false,
 | 
				
			||||||
          top: 0,
 | 
					            top: 0,
 | 
				
			||||||
          left: 0,
 | 
					            left: 0,
 | 
				
			||||||
        };
 | 
					          };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										29
									
								
								packages/editor/src/hooks/use-next-float-box-position.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								packages/editor/src/hooks/use-next-float-box-position.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					import { Ref, ref } from 'vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { UiService } from '@editor/services/ui';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useNextFloatBoxPosition = (uiService?: UiService, parent?: Ref<HTMLDivElement>) => {
 | 
				
			||||||
 | 
					  const boxPosition = ref({
 | 
				
			||||||
 | 
					    left: 0,
 | 
				
			||||||
 | 
					    top: 0,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const calcBoxPosition = () => {
 | 
				
			||||||
 | 
					    const columnWidth = uiService?.get('columnWidth');
 | 
				
			||||||
 | 
					    const navMenuRect = uiService?.get('navMenuRect');
 | 
				
			||||||
 | 
					    let left = columnWidth?.left ?? 0;
 | 
				
			||||||
 | 
					    if (parent?.value) {
 | 
				
			||||||
 | 
					      const rect = parent?.value?.getBoundingClientRect();
 | 
				
			||||||
 | 
					      left = (rect?.left ?? 0) + (rect?.width ?? 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    boxPosition.value = {
 | 
				
			||||||
 | 
					      left,
 | 
				
			||||||
 | 
					      top: (navMenuRect?.top ?? 0) + (navMenuRect?.height ?? 0),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    boxPosition,
 | 
				
			||||||
 | 
					    calcBoxPosition,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -111,8 +111,8 @@
 | 
				
			|||||||
        :key="config.$key ?? index"
 | 
					        :key="config.$key ?? index"
 | 
				
			||||||
        v-if="floatBoxStates[config.$key]?.status"
 | 
					        v-if="floatBoxStates[config.$key]?.status"
 | 
				
			||||||
        v-model:visible="floatBoxStates[config.$key].status"
 | 
					        v-model:visible="floatBoxStates[config.$key].status"
 | 
				
			||||||
        :width="columnLeftWitch"
 | 
					        v-model:width="columnLeftWidth"
 | 
				
			||||||
        :height="600"
 | 
					        v-model:height="columnLeftHeight"
 | 
				
			||||||
        :title="config.text"
 | 
					        :title="config.text"
 | 
				
			||||||
        :position="{
 | 
					        :position="{
 | 
				
			||||||
          left: floatBoxStates[config.$key].left,
 | 
					          left: floatBoxStates[config.$key].left,
 | 
				
			||||||
@ -123,8 +123,8 @@
 | 
				
			|||||||
          <div class="m-editor-slide-list-box">
 | 
					          <div class="m-editor-slide-list-box">
 | 
				
			||||||
            <component
 | 
					            <component
 | 
				
			||||||
              v-if="config && floatBoxStates[config.$key].status"
 | 
					              v-if="config && floatBoxStates[config.$key].status"
 | 
				
			||||||
              :is="config.boxComponentConfig?.component || config.component"
 | 
					              :is="config.component"
 | 
				
			||||||
              v-bind="config.boxComponentConfig?.props || config.props || {}"
 | 
					              v-bind="config.props || {}"
 | 
				
			||||||
              v-on="config?.listeners || {}"
 | 
					              v-on="config?.listeners || {}"
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
@ -140,6 +140,7 @@ import { Coin, EditPen, Goods, List } from '@element-plus/icons-vue';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import FloatingBox from '@editor/components/FloatingBox.vue';
 | 
					import FloatingBox from '@editor/components/FloatingBox.vue';
 | 
				
			||||||
import MIcon from '@editor/components/Icon.vue';
 | 
					import MIcon from '@editor/components/Icon.vue';
 | 
				
			||||||
 | 
					import { useEditorContentHeight } from '@editor/hooks/use-editor-content-height';
 | 
				
			||||||
import { useFloatBox } from '@editor/hooks/use-float-box';
 | 
					import { useFloatBox } from '@editor/hooks/use-float-box';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  ColumnLayout,
 | 
					  ColumnLayout,
 | 
				
			||||||
@ -176,7 +177,8 @@ const props = withDefaults(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const services = inject<Services>('services');
 | 
					const services = inject<Services>('services');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const columnLeftWitch = computed(() => services?.uiService.get('columnWidth')[ColumnLayout.LEFT] || 0);
 | 
					const columnLeftWidth = computed(() => services?.uiService.get('columnWidth')[ColumnLayout.LEFT] || 0);
 | 
				
			||||||
 | 
					const { height: columnLeftHeight } = useEditorContentHeight();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const activeTabName = ref(props.data?.status);
 | 
					const activeTabName = ref(props.data?.status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -209,11 +211,6 @@ const getItemConfig = (data: SideItem): SideComponent => {
 | 
				
			|||||||
      text: '代码编辑',
 | 
					      text: '代码编辑',
 | 
				
			||||||
      component: CodeBlockListPanel,
 | 
					      component: CodeBlockListPanel,
 | 
				
			||||||
      slots: {},
 | 
					      slots: {},
 | 
				
			||||||
      boxComponentConfig: {
 | 
					 | 
				
			||||||
        props: {
 | 
					 | 
				
			||||||
          slideType: 'box',
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    'data-source': {
 | 
					    'data-source': {
 | 
				
			||||||
      $key: 'data-source',
 | 
					      $key: 'data-source',
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,6 @@
 | 
				
			|||||||
    ref="codeBlockEditor"
 | 
					    ref="codeBlockEditor"
 | 
				
			||||||
    :disabled="!editable"
 | 
					    :disabled="!editable"
 | 
				
			||||||
    :content="codeConfig"
 | 
					    :content="codeConfig"
 | 
				
			||||||
    :slideType="slideType"
 | 
					 | 
				
			||||||
    @submit="submitCodeBlockHandler"
 | 
					    @submit="submitCodeBlockHandler"
 | 
				
			||||||
  ></CodeBlockEditor>
 | 
					  ></CodeBlockEditor>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
@ -37,7 +36,7 @@ import type { Id } from '@tmagic/schema';
 | 
				
			|||||||
import CodeBlockEditor from '@editor/components/CodeBlockEditor.vue';
 | 
					import CodeBlockEditor from '@editor/components/CodeBlockEditor.vue';
 | 
				
			||||||
import SearchInput from '@editor/components/SearchInput.vue';
 | 
					import SearchInput from '@editor/components/SearchInput.vue';
 | 
				
			||||||
import { useCodeBlockEdit } from '@editor/hooks/use-code-block-edit';
 | 
					import { useCodeBlockEdit } from '@editor/hooks/use-code-block-edit';
 | 
				
			||||||
import type { CodeBlockListPanelSlots, CodeDeleteErrorType, Services, SlideType } from '@editor/type';
 | 
					import type { CodeBlockListPanelSlots, CodeDeleteErrorType, Services } from '@editor/type';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import CodeBlockList from './CodeBlockList.vue';
 | 
					import CodeBlockList from './CodeBlockList.vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -49,7 +48,6 @@ defineOptions({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
defineProps<{
 | 
					defineProps<{
 | 
				
			||||||
  customError?: (id: Id, errorType: CodeDeleteErrorType) => any;
 | 
					  customError?: (id: Id, errorType: CodeDeleteErrorType) => any;
 | 
				
			||||||
  slideType?: SlideType;
 | 
					 | 
				
			||||||
}>();
 | 
					}>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const { codeBlockService } = inject<Services>('services') || {};
 | 
					const { codeBlockService } = inject<Services>('services') || {};
 | 
				
			||||||
 | 
				
			|||||||
@ -1,27 +1,37 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <component
 | 
					  <FloatingBox
 | 
				
			||||||
    :is="slideType === 'box' ? MFormBox : MFormDrawer"
 | 
					    v-model:visible="boxVisible"
 | 
				
			||||||
    ref="fomDrawer"
 | 
					    v-model:width="width"
 | 
				
			||||||
    label-width="80px"
 | 
					    v-model:height="editorHeight"
 | 
				
			||||||
    :close-on-press-escape="false"
 | 
					 | 
				
			||||||
    :title="title"
 | 
					    :title="title"
 | 
				
			||||||
    :width="size"
 | 
					    :position="boxPosition"
 | 
				
			||||||
    :config="dataSourceConfig"
 | 
					  >
 | 
				
			||||||
    :values="initValues"
 | 
					    <template #body>
 | 
				
			||||||
    :disabled="disabled"
 | 
					      <MFormBox
 | 
				
			||||||
    @submit="submitHandler"
 | 
					        label-width="80px"
 | 
				
			||||||
    @error="errorHandler"
 | 
					        :title="title"
 | 
				
			||||||
  ></component>
 | 
					        :config="dataSourceConfig"
 | 
				
			||||||
 | 
					        :values="initValues"
 | 
				
			||||||
 | 
					        :disabled="disabled"
 | 
				
			||||||
 | 
					        style="height: 100%"
 | 
				
			||||||
 | 
					        @submit="submitHandler"
 | 
				
			||||||
 | 
					        @error="errorHandler"
 | 
				
			||||||
 | 
					      ></MFormBox>
 | 
				
			||||||
 | 
					    </template>
 | 
				
			||||||
 | 
					  </FloatingBox>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import { computed, inject, ref, watchEffect } from 'vue';
 | 
					import { inject, Ref, ref, watchEffect } from 'vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { tMagicMessage } from '@tmagic/design';
 | 
					import { tMagicMessage } from '@tmagic/design';
 | 
				
			||||||
import { FormConfig, MFormBox, MFormDrawer } from '@tmagic/form';
 | 
					import { FormConfig, MFormBox } from '@tmagic/form';
 | 
				
			||||||
import { DataSourceSchema } from '@tmagic/schema';
 | 
					import { DataSourceSchema } from '@tmagic/schema';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import type { Services, SlideType } from '@editor/type';
 | 
					import FloatingBox from '@editor/components/FloatingBox.vue';
 | 
				
			||||||
 | 
					import { useEditorContentHeight } from '@editor/hooks';
 | 
				
			||||||
 | 
					import { useNextFloatBoxPosition } from '@editor/hooks/use-next-float-box-position';
 | 
				
			||||||
 | 
					import type { Services } from '@editor/type';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
defineOptions({
 | 
					defineOptions({
 | 
				
			||||||
  name: 'MEditorDataSourceConfigPanel',
 | 
					  name: 'MEditorDataSourceConfigPanel',
 | 
				
			||||||
@ -31,23 +41,27 @@ const props = defineProps<{
 | 
				
			|||||||
  title?: string;
 | 
					  title?: string;
 | 
				
			||||||
  values: any;
 | 
					  values: any;
 | 
				
			||||||
  disabled: boolean;
 | 
					  disabled: boolean;
 | 
				
			||||||
  slideType?: SlideType;
 | 
					 | 
				
			||||||
}>();
 | 
					}>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const boxVisible = defineModel<boolean>('visible', { default: false });
 | 
				
			||||||
 | 
					const width = defineModel<number>('width', { default: 670 });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const emit = defineEmits(['submit']);
 | 
					const emit = defineEmits(['submit']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const services = inject<Services>('services');
 | 
					const services = inject<Services>('services');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const size = computed(() => globalThis.document.body.clientWidth - (services?.uiService.get('columnWidth').left || 0));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const fomDrawer = ref<InstanceType<typeof MFormDrawer>>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const initValues = ref<Partial<DataSourceSchema>>({});
 | 
					const initValues = ref<Partial<DataSourceSchema>>({});
 | 
				
			||||||
const dataSourceConfig = ref<FormConfig>([]);
 | 
					const dataSourceConfig = ref<FormConfig>([]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const { height: editorHeight } = useEditorContentHeight();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const parentFloating = inject<Ref<HTMLDivElement>>('parentFloating');
 | 
				
			||||||
 | 
					const { boxPosition, calcBoxPosition } = useNextFloatBoxPosition(services?.uiService, parentFloating);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
watchEffect(() => {
 | 
					watchEffect(() => {
 | 
				
			||||||
  initValues.value = props.values;
 | 
					  initValues.value = props.values;
 | 
				
			||||||
  dataSourceConfig.value = services?.dataSourceService.getFormConfig(initValues.value.type) || [];
 | 
					  dataSourceConfig.value = services?.dataSourceService.getFormConfig(initValues.value.type) || [];
 | 
				
			||||||
 | 
					  console.log(dataSourceConfig.value);
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const submitHandler = (values: any) => {
 | 
					const submitHandler = (values: any) => {
 | 
				
			||||||
@ -60,11 +74,12 @@ const errorHandler = (error: any) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
defineExpose({
 | 
					defineExpose({
 | 
				
			||||||
  show() {
 | 
					  show() {
 | 
				
			||||||
    fomDrawer.value?.show();
 | 
					    calcBoxPosition();
 | 
				
			||||||
 | 
					    boxVisible.value = true;
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  hide() {
 | 
					  hide() {
 | 
				
			||||||
    fomDrawer.value?.hide();
 | 
					    boxVisible.value = false;
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
				
			|||||||
@ -33,7 +33,6 @@
 | 
				
			|||||||
    :disabled="!editable"
 | 
					    :disabled="!editable"
 | 
				
			||||||
    :values="dataSourceValues"
 | 
					    :values="dataSourceValues"
 | 
				
			||||||
    :title="dialogTitle"
 | 
					    :title="dialogTitle"
 | 
				
			||||||
    :slideType="slideType"
 | 
					 | 
				
			||||||
    @submit="submitDataSourceHandler"
 | 
					    @submit="submitDataSourceHandler"
 | 
				
			||||||
  ></DataSourceConfigPanel>
 | 
					  ></DataSourceConfigPanel>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
@ -47,7 +46,7 @@ import type { DataSourceSchema } from '@tmagic/schema';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import SearchInput from '@editor/components/SearchInput.vue';
 | 
					import SearchInput from '@editor/components/SearchInput.vue';
 | 
				
			||||||
import ToolButton from '@editor/components/ToolButton.vue';
 | 
					import ToolButton from '@editor/components/ToolButton.vue';
 | 
				
			||||||
import type { DataSourceListSlots, Services, SlideType } from '@editor/type';
 | 
					import type { DataSourceListSlots, Services } from '@editor/type';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import DataSourceConfigPanel from './DataSourceConfigPanel.vue';
 | 
					import DataSourceConfigPanel from './DataSourceConfigPanel.vue';
 | 
				
			||||||
import DataSourceList from './DataSourceList.vue';
 | 
					import DataSourceList from './DataSourceList.vue';
 | 
				
			||||||
@ -58,10 +57,6 @@ defineOptions({
 | 
				
			|||||||
  name: 'MEditorDataSourceListPanel',
 | 
					  name: 'MEditorDataSourceListPanel',
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
defineProps<{
 | 
					 | 
				
			||||||
  slideType?: SlideType;
 | 
					 | 
				
			||||||
}>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const { dataSourceService } = inject<Services>('services') || {};
 | 
					const { dataSourceService } = inject<Services>('services') || {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const editDialog = ref<InstanceType<typeof DataSourceConfigPanel>>();
 | 
					const editDialog = ref<InstanceType<typeof DataSourceConfigPanel>>();
 | 
				
			||||||
 | 
				
			|||||||
@ -4,13 +4,3 @@
 | 
				
			|||||||
    display: none;
 | 
					    display: none;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
.m-editor-code-block-editor {
 | 
					 | 
				
			||||||
  .tmagic-design-table {
 | 
					 | 
				
			||||||
    height: 180px;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  .el-drawer__body {
 | 
					 | 
				
			||||||
    padding: 10px 20px;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -401,12 +401,6 @@ export interface SideBarData {
 | 
				
			|||||||
  items: SideItem[];
 | 
					  items: SideItem[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * drawer 抽屉
 | 
					 | 
				
			||||||
 * box 悬浮窗
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
export type SlideType = 'drawer' | 'box';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export interface ComponentItem {
 | 
					export interface ComponentItem {
 | 
				
			||||||
  /** 显示文案 */
 | 
					  /** 显示文案 */
 | 
				
			||||||
  text: string;
 | 
					  text: string;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user