This commit is contained in:
2026-02-26 16:55:25 +08:00
parent e741d50761
commit dfdf2400c1
17 changed files with 287 additions and 55 deletions

View File

@@ -11,7 +11,7 @@
>
<result-image />
<card type="cards-select" />
<card type="to-real-style" />
@@ -36,7 +36,7 @@
scale: 1
})
const onMouseDown = (e: MouseEvent) => {
if (e.button !== 1) return
// if (e.button !== 1) return
const ox = data.x
const oy = data.y
const X = e.clientX

View File

@@ -135,6 +135,7 @@
align-items: center;
padding-left: 16px;
position: relative;
user-select: none;
> .c-svg {
width: auto;
height: auto;

View File

@@ -65,7 +65,9 @@
display: flex;
flex-wrap: wrap;
gap: 8.29px 5.5px;
user-select: none;
> .item {
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;

View File

@@ -66,6 +66,7 @@
display: flex;
flex-wrap: wrap;
gap: 10px 4px;
user-select: none;
> .item {
display: flex;
align-items: center;
@@ -75,6 +76,7 @@
font-size: 10px;
border: 1px solid #e4e4e7;
background: #f0f0f0;
cursor: pointer;
}
}
}

View File

@@ -1,32 +1,207 @@
<template>
<!-- 转3-View -->
<div class="to-3view">
<p class="label">3D Model</p>
<div class="image">
<img
src="https://s3-alpha-sig.figma.com/img/ea2f/590e/9638f62a2fc91e31f33db0022db1642c?Expires=1773014400&Key-Pair-Id=APKAQ4GOSFWCW27IBOMQ&Signature=M0B8oJJOk~dGG0aZAqOIocAp7T0LFdJ9FYmCrEZVTCRzYxM6SJRNtYMTX-rTO3Z~s14QINh~o-S41XiZnBv-0zcKjuWot~VVaNHfd0~1LesfNe2KwvCinT~72btFut1pheLnKE-wWCX5ewtonxU77bnw386YPMTqv7DBZzksf2udsJA7NmOYD6~TUG3Q2dWSt~zPH~lkaidscPqpCnCbqzljCEi4RiHY4U3A45l5XypcX2umqn1UaYUFCTqV9471J4qdB6Dg2pcKocdp-7-3s1De6Q~2SmBOrSgDQ~KEADCB2lhKfhxgWmy0lwMvhTd4l90ygVZDWZRABgjHNrGUvg__"
alt=""
/>
<!-- 结果图片 -->
<div class="result-image">
<div class="header" v-show="showHeader">
<span class="icon">
<svg-icon name="chat-compose" size="24" size-unit="px" />
</span>
<span class="icon">
<svg-icon name="expand-lg" size="24" size-unit="px" />
</span>
<span class="icon">
<svg-icon name="download" size="24" size-unit="px" />
</span>
<button class="edit">
<span class="icon"><svg-icon name="edit" size="11" /></span>
<span class="text">Edit</span>
</button>
</div>
<img
class="image"
src="https://s3-alpha-sig.figma.com/img/ea2f/590e/9638f62a2fc91e31f33db0022db1642c?Expires=1773014400&Key-Pair-Id=APKAQ4GOSFWCW27IBOMQ&Signature=M0B8oJJOk~dGG0aZAqOIocAp7T0LFdJ9FYmCrEZVTCRzYxM6SJRNtYMTX-rTO3Z~s14QINh~o-S41XiZnBv-0zcKjuWot~VVaNHfd0~1LesfNe2KwvCinT~72btFut1pheLnKE-wWCX5ewtonxU77bnw386YPMTqv7DBZzksf2udsJA7NmOYD6~TUG3Q2dWSt~zPH~lkaidscPqpCnCbqzljCEi4RiHY4U3A45l5XypcX2umqn1UaYUFCTqV9471J4qdB6Dg2pcKocdp-7-3s1De6Q~2SmBOrSgDQ~KEADCB2lhKfhxgWmy0lwMvhTd4l90ygVZDWZRABgjHNrGUvg__"
/>
<div class="add" @mousedown.stop>
<svg-icon name="add" size="14" size-unit="px" />
</div>
<div class="more" @click="showMenu = !showMenu" @mousedown.stop>
<svg-icon name="more" size="24" size-unit="px" color="#C9C9C9" />
</div>
<div class="menu" v-show="showMenu" @mousedown.stop>
<div
v-for="(v, i) in menus"
:key="i"
:class="[v.isDivide ? 'divide' : 'item']"
@click="onMenuItem(v)"
>
<template v-if="!v.isDivide">
<span class="label">{{ v.label }}</span>
<span class="tip">{{ v.tip }}</span>
</template>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { reactive, onMounted } from 'vue'
import { reactive, ref, onBeforeUnmount } from 'vue'
const showHeader = ref(true)
const showMenu = ref(false)
const data = reactive({})
const menus = ref([
{ label: 'Copy', tip: 'Ctrl+C', on: () => {} },
{ label: 'Paste', tip: 'Ctrl+V', on: () => {} },
{ label: 'Duplicate', tip: 'Ctrl+D', on: () => {} },
{ label: 'Delete', tip: 'Del', on: () => {} },
{ isDivide: true },
{ label: 'Bring to font', tip: 'Del', on: () => {} },
{ label: 'Send to back', tip: 'Del', on: () => {} },
{ isDivide: true },
{ label: 'Flip horizontal', tip: '', on: () => {} },
{ label: 'Flip vertical', tip: '', on: () => {} }
])
const onMenuItem = (v) => {
v.on && v.on()
hideMenu()
}
const hideMenu = () => {
showMenu.value = false
}
document.addEventListener('mousedown', hideMenu)
onBeforeUnmount(() => {
document.removeEventListener('mousedown', hideMenu)
})
defineExpose({ data })
</script>
<style lang="less" scoped>
.to-3view {
> .image {
padding: 18px;
.result-image {
width: 244px;
border-radius: 16px;
border: 3px solid #d9d9d9;
box-shadow: 0px 15px 21px 0px #0000000d;
padding: 25px 6px;
user-select: none;
> .header {
position: absolute;
top: -20px;
left: 50%;
transform: translate(-50%, -100%);
width: auto;
height: 50px;
border-radius: 10px;
background-color: #f0f0f0;
> img {
border: 2px solid #ebebeb;
box-shadow: 0px 15px 21px 0px #0000000d;
display: flex;
align-items: center;
justify-content: center;
user-select: none;
padding: 0 19px;
gap: 12px;
> .icon {
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
width: 30px;
height: 30px;
--svg-icon-color: #000;
border-radius: 4px;
&:hover {
background-color: #dfdfdf;
}
}
> .edit {
width: 80px;
height: 30px;
border-radius: 4px;
border: none;
background-color: #ff7a51;
color: #fff;
font-size: 12px;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
&:active {
opacity: 0.8;
}
}
}
> .image {
width: 100%;
height: auto;
}
position: relative;
> .add {
position: absolute;
width: 32px;
height: 32px;
border: 2px solid #fff;
// bottom: -16px;
right: -16px;
top: 50%;
transform: translateY(-50%);
background-color: #ed8936;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 25px;
box-shadow: 0 8px 20px 0 #71809633;
cursor: pointer;
z-index: 20;
}
> .more {
position: absolute;
top: 5px;
right: 9px;
width: 24px;
height: 24px;
cursor: pointer;
}
> .menu {
position: absolute;
width: 244px;
height: auto;
top: 0;
right: -10px;
transform: translate(100%, 0);
border-radius: 16px;
padding: 16px 14px;
box-shadow: 0px 15px 21px 0px rgba(0, 0, 0, 0.05);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 12px;
background-color: #fff;
z-index: 50;
> .item {
width: 100%;
height: auto;
height: 27px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 8px;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
&:hover {
background: #f3f3f3;
}
> .label {
color: #000;
}
> .tip {
color: rgba(0, 0, 0, 0.3);
}
}
> .divide {
width: 100%;
height: 0;
border-bottom: 1px solid #e5e5e5;
}
}
}

View File

@@ -40,8 +40,10 @@
align-items: center;
justify-content: center;
padding: 0 17px;
user-select: none;
> div {
text-align: center;
cursor: pointer;
font-size: 12px;
color: #7c7c7c;
height: 21px;

View File

@@ -82,22 +82,22 @@
onMounted(() => {
window.vueFlow = vueFlow
window.nodes = nodes
window.addaaaaa = () => {
const lastNode = vueFlow.value.getNode(nodes.value[nodes.value.length - 1].id)
const width = lastNode.dimensions.width
const x = lastNode.position.x
const y = lastNode.position.y
nodes.value.push({
id: nodes.value.length + 1 + '',
type: 'SecondaryNode',
class: 'custom-node',
data: { component: card, type_: 'to-3d-model' },
position: {
x: width + x + 50,
y: y
}
})
}
// window.addaaaaa = () => {
// const lastNode = vueFlow.value.getNode(nodes.value[nodes.value.length - 1].id)
// const width = lastNode.dimensions.width
// const x = lastNode.position.x
// const y = lastNode.position.y
// nodes.value.push({
// id: nodes.value.length + 1 + '',
// type: 'SecondaryNode',
// class: 'custom-node',
// data: { component: card, type_: 'to-3d-model' },
// position: {
// x: width + x + 50,
// y: y
// }
// })
// }
})
</script>
<style lang="less">

View File

@@ -0,0 +1,11 @@
export class NodeManager {
stateManager: any
vueFlow: any
constructor(options) {
this.stateManager = options.stateManager;
this.vueFlow = options.vueFlow
}
nodes: [
]
}