-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
341 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,58 @@ | ||
<template> | ||
<div class="p-32 space-y-2"> | ||
<div>Default Value: {{ checked }}</div> | ||
<ShadcnSwitch v-model="checked"> | ||
<template #open>ON</template> | ||
<template #close>OFF</template> | ||
</ShadcnSwitch> | ||
|
||
<div>Null Value: {{ checked2 }}</div> | ||
<ShadcnSwitch v-model="checked2" true-value="ON" false-value="OFF"> | ||
<template #open>OFF</template> | ||
<template #close>ON</template> | ||
</ShadcnSwitch> | ||
<div class="flex h-screen bg-gray-100"> | ||
<slot name="panel"> | ||
<BigScreenPanel :items="panels"/> | ||
</slot> | ||
|
||
<!-- 中间编辑区域 --> | ||
<BigScreenEditor ref="editorRef" | ||
:grid-size="20" | ||
:selected-id="selectedId" | ||
@select="handleSelect" | ||
@update:components="handleComponentsUpdate"/> | ||
|
||
<!-- 右侧配置面板 --> | ||
<BigScreenConfigure :selected-component="selectedComponent" @update="handleConfigUpdate"/> | ||
</div> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import { ref } from 'vue' | ||
<script setup> | ||
import { computed, ref } from 'vue' | ||
import BigScreenPanel from "@/ui/bigscreen/BigScreenPanel.vue"; | ||
import BigScreenEditor from "@/ui/bigscreen/BigScreenEditor.vue"; | ||
import BigScreenConfigure from "@/ui/bigscreen/BigScreenConfigure.vue"; | ||
const panels = ref([ | ||
{ | ||
group: 'Basic Components', | ||
children: [ | ||
{type: 'text', label: '文本'}, | ||
{type: 'image', label: '图片'}, | ||
{type: 'chart', label: '图表'}, | ||
] | ||
} | ||
]) | ||
const editorRef = ref(null) | ||
const components = ref([]) | ||
const selectedId = ref(null) | ||
// 计算选中的组件 | ||
const selectedComponent = computed(() => | ||
components.value.find(item => item.id === selectedId.value) | ||
) | ||
// 选择组件 | ||
const handleSelect = (component) => { | ||
selectedId.value = component.id | ||
} | ||
// 更新组件列表 | ||
const handleComponentsUpdate = (newComponents) => { | ||
components.value = newComponents | ||
} | ||
const checked = ref(false) | ||
const checked2 = ref(null) | ||
// 更新组件配置 | ||
const handleConfigUpdate = (updatedComponent) => { | ||
editorRef.value?.updateComponent(updatedComponent) | ||
} | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
# BigScreenConfigure.vue | ||
<template> | ||
<div class="w-64 bg-white border-l border-gray-200 p-4"> | ||
<div class="text-lg font-medium mb-4">配置面板</div> | ||
<template v-if="selectedComponent"> | ||
<div class="space-y-4"> | ||
<!-- 位置配置 --> | ||
<div class="space-y-2"> | ||
<div class="text-sm font-medium text-gray-600">位置</div> | ||
<div class="grid grid-cols-2 gap-2"> | ||
<div> | ||
<div class="text-xs text-gray-500 mb-1">X 坐标</div> | ||
<input | ||
type="number" | ||
v-model="componentConfig.x" | ||
@input="handleUpdate" | ||
class="w-full px-2 py-1 border border-gray-200 rounded text-sm focus:outline-none focus:border-blue-500" | ||
> | ||
</div> | ||
<div> | ||
<div class="text-xs text-gray-500 mb-1">Y 坐标</div> | ||
<input | ||
type="number" | ||
v-model="componentConfig.y" | ||
@input="handleUpdate" | ||
class="w-full px-2 py-1 border border-gray-200 rounded text-sm focus:outline-none focus:border-blue-500" | ||
> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
<!-- 大小配置 --> | ||
<div class="space-y-2"> | ||
<div class="text-sm font-medium text-gray-600">大小</div> | ||
<div class="grid grid-cols-2 gap-2"> | ||
<div> | ||
<div class="text-xs text-gray-500 mb-1">宽度</div> | ||
<input | ||
type="number" | ||
v-model="componentConfig.width" | ||
@input="handleUpdate" | ||
class="w-full px-2 py-1 border border-gray-200 rounded text-sm focus:outline-none focus:border-blue-500" | ||
> | ||
</div> | ||
<div> | ||
<div class="text-xs text-gray-500 mb-1">高度</div> | ||
<input | ||
type="number" | ||
v-model="componentConfig.height" | ||
@input="handleUpdate" | ||
class="w-full px-2 py-1 border border-gray-200 rounded text-sm focus:outline-none focus:border-blue-500" | ||
> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</template> | ||
<div v-else class="text-gray-400 text-center py-4"> | ||
请选择组件进行配置 | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script setup> | ||
import { ref, watch } from 'vue' | ||
const props = defineProps({ | ||
selectedComponent: { | ||
type: Object, | ||
default: null | ||
} | ||
}) | ||
const emit = defineEmits(['update']) | ||
// 组件配置 | ||
const componentConfig = ref({ | ||
x: 0, | ||
y: 0, | ||
width: 0, | ||
height: 0 | ||
}) | ||
// 监听选中组件变化 | ||
watch(() => props.selectedComponent, (newVal) => { | ||
if (newVal) { | ||
componentConfig.value = { | ||
x: newVal.x, | ||
y: newVal.y, | ||
width: newVal.width, | ||
height: newVal.height | ||
} | ||
} | ||
}, { deep: true }) | ||
// 更新组件 | ||
const handleUpdate = () => { | ||
if (!props.selectedComponent) return | ||
emit('update', { | ||
...props.selectedComponent, | ||
...componentConfig.value | ||
}) | ||
} | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
<template> | ||
<div class="flex-1 relative overflow-auto" | ||
@dragover.prevent | ||
@drop="handleDrop" | ||
:style="gridStyle"> | ||
<!-- 已添加的组件 --> | ||
<div v-for="item in components" | ||
:key="item.id" | ||
class="absolute bg-white border-2 flex items-center justify-center cursor-move transition-all" | ||
:class="[ | ||
selectedId === item.id | ||
? 'border-blue-500 shadow-lg' | ||
: 'border-gray-200 hover:border-gray-300' | ||
]" | ||
:style="getPosition(item)" | ||
@click.stop="handleSelect(item)" | ||
> | ||
{{ item.label }} | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script setup> | ||
import { defineEmits, ref } from 'vue' | ||
const props = defineProps({ | ||
gridSize: { | ||
type: Number, | ||
default: 20 | ||
}, | ||
selectedId: { | ||
type: [Number, null], | ||
default: null | ||
} | ||
}) | ||
const emit = defineEmits(['update:components', 'select']) | ||
// 编辑区网格配置 | ||
const gridStyle = { | ||
backgroundSize: `${props.gridSize}px ${props.gridSize}px`, | ||
backgroundImage: 'linear-gradient(#f0f0f0 1px, transparent 1px), linear-gradient(90deg, #f0f0f0 1px, transparent 1px)' | ||
} | ||
// 画布中的组件 | ||
const components = ref([]) | ||
// 处理放置 | ||
const handleDrop = (e) => { | ||
const type = e.dataTransfer.getData('componentType') | ||
const label = e.dataTransfer.getData('componentLabel') | ||
// 获取放置位置 | ||
const rect = e.target.getBoundingClientRect() | ||
const x = e.clientX - rect.left | ||
const y = e.clientY - rect.top | ||
// 对齐到网格 | ||
const alignedX = Math.round(x / props.gridSize) * props.gridSize | ||
const alignedY = Math.round(y / props.gridSize) * props.gridSize | ||
// 添加新组件 | ||
const newComponents = [...components.value, { | ||
id: Date.now(), | ||
type, | ||
label, | ||
x: alignedX, | ||
y: alignedY, | ||
width: props.gridSize * 5, | ||
height: props.gridSize * 3 | ||
}] | ||
components.value = newComponents | ||
emit('update:components', newComponents) | ||
} | ||
// 选择组件 | ||
const handleSelect = (component) => { | ||
emit('select', component) | ||
} | ||
// 获取组件位置样式 | ||
const getPosition = (component) => { | ||
return { | ||
left: component.x + 'px', | ||
top: component.y + 'px', | ||
width: component.width + 'px', | ||
height: component.height + 'px' | ||
} | ||
} | ||
// 暴露方法给父组件 | ||
defineExpose({ | ||
updateComponent: (updatedComponent) => { | ||
const index = components.value.findIndex(item => item.id === updatedComponent.id) | ||
if (index > -1) { | ||
const newComponents = [...components.value] | ||
newComponents[index] = updatedComponent | ||
components.value = newComponents | ||
emit('update:components', newComponents) | ||
} | ||
} | ||
}) | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<template> | ||
<div class="w-64 bg-white border-r border-gray-200 p-4"> | ||
<div v-for="item in items" class="text-lg font-medium mb-4"> | ||
<ShadcnCard :title="item.group"> | ||
<div class="space-y-2 p-1"> | ||
<div v-for="item in item.children" | ||
draggable="true" | ||
class="p-3 bg-gray-50 border border-gray-200 rounded cursor-move text-center hover:bg-gray-100 transition-colors" | ||
:key="item.type" | ||
@dragstart="onDragStart($event, item)"> | ||
{{ item.label }} | ||
</div> | ||
</div> | ||
</ShadcnCard> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import { BigScreenPanelItemProps, BigScreenPanelProps } from '@/ui/bigscreen/types.ts' | ||
withDefaults(defineProps<BigScreenPanelProps>(), { | ||
items: () => Array<BigScreenPanelItemProps> | ||
}) | ||
const onDragStart = (e, component) => { | ||
e.dataTransfer.setData('componentType', component.type) | ||
e.dataTransfer.setData('componentLabel', component.label) | ||
} | ||
</script> |
Oops, something went wrong.