This commit is contained in:
2026-02-24 13:53:05 +08:00
14 changed files with 313 additions and 57 deletions

3
src/assets/icons/dui.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.5369 3.30968C10.8031 3.49116 10.8718 3.85407 10.6903 4.12025L6.3153 10.5369C6.21745 10.6804 6.06073 10.7729 5.88779 10.7891C5.71485 10.8053 5.54368 10.7436 5.42085 10.6208L2.79585 7.99579C2.56805 7.76798 2.56805 7.39864 2.79585 7.17083C3.02366 6.94302 3.39301 6.94302 3.62081 7.17083L5.74798 9.298L9.72637 3.46303C9.90786 3.19685 10.2708 3.12819 10.5369 3.30968Z" fill="#0D0D0D" stroke="black" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 578 B

View File

@@ -11,9 +11,13 @@
:key="item.value"
:disabled="item.value === modelValue"
@click="onItemClick(item.value)"
style="--el-font-size-base: 1.4rem; --el-text-color-regular: #000"
>
<span>{{ item.label }}</span>
<div class="menu-item">
<span class="label">{{ item.label }}</span>
<span class="icon" v-show="item.value === modelValue">
<svg-icon name="dui" size="14" color="#000" />
</span>
</div>
</el-dropdown-item>
</el-dropdown-menu>
</template>
@@ -61,4 +65,17 @@
margin-left: 1.6rem;
}
}
.menu-item {
display: flex;
align-items: center;
width: 100%;
font-size: 1.4rem;
color: #000;
> .label {
margin-right: auto;
}
> .icon {
margin-left: 1.6rem;
}
}
</style>

View File

@@ -7,3 +7,4 @@ store.use(createPersistedState())
export default store
export * from './global'
export * from './userInfo'
export * from './projectData'

20
src/stores/projectData.ts Normal file
View File

@@ -0,0 +1,20 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useProjectStore = defineStore('project', () => {
const state = ref({// 项目参数
id: '',
})
const setProject = (obj: any) => {
for (const key in obj) {
if(state.value[key]){
state.value[key] = obj[key]
}
}
}
return {
state,
setProject,
}
})

View File

@@ -1,24 +1,64 @@
<template>
<div class="canvas">
<card type="to-real-style" />
<card type="scene-composition" />
<card type="color-palette" />
<card type="to-video" />
<card type="to-3d-model" />
<card type="to-cad" />
<card type="add-print" />
<card type="edit-material" />
<div class="canvas-main" ref="canvasMain" @mousedown="onMouseDown" @wheel="onMouseWheel">
<div
class="canvas-content"
:style="{
top: `${data.y}px`,
left: `${data.x}px`,
transform: `scale(${data.scale})`
}"
>
<card type="to-real-style" />
<card type="scene-composition" />
<card type="color-palette" />
<card type="to-video" />
<card type="to-3d-model" />
<card type="to-cad" />
<card type="add-print" />
<card type="edit-material" />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import card from './components/cards/index.vue'
import { computed, ref, markRaw, onMounted } from 'vue'
import { computed, ref, markRaw, onMounted, reactive } from 'vue'
import { useGlobalStore } from '@/stores'
import { useRouter, useRoute } from 'vue-router'
const router = useRouter()
const route = useRoute()
const globalStore = useGlobalStore()
const data = reactive({
x: 100,
y: 200,
scale: 1
})
const canvasMain = ref<HTMLDivElement>()
const onMouseDown = (e: MouseEvent) => {
if (e.button !== 1) return
const ox = data.x
const oy = data.y
const X = e.clientX
const Y = e.clientY
const onMouseMove = (e: MouseEvent) => {
const dx = e.clientX - X
const dy = e.clientY - Y
data.x = ox + dx
data.y = oy + dy
}
const onMouseUp = (e: MouseEvent) => {
document.removeEventListener('mousemove', onMouseMove)
document.removeEventListener('mouseup', onMouseUp)
}
document.addEventListener('mousemove', onMouseMove)
document.addEventListener('mouseup', onMouseUp)
}
const onMouseWheel = (e: WheelEvent) => {
var delta = e.deltaY
var scale = data.scale - delta / 1000
if (scale < 0.2) scale = 0.2
if (scale > 10) scale = 10
data.scale = scale
}
onMounted(() => {
globalStore.setHomeLeftNavCollapse(true)
})
@@ -26,13 +66,29 @@
<style lang="less" scoped>
.canvas {
overflow-y: auto;
// overflow-y: auto;
// display: flex;
// flex-wrap: wrap;
// align-content: flex-start;
// align-items: flex-start;
// padding: 2rem;
// gap: 2rem;
background-color: #fcf8f1;
display: flex;
flex-wrap: wrap;
align-content: flex-start;
align-items: flex-start;
padding: 2rem;
gap: 2rem;
position: relative;
overflow: hidden;
> .canvas-main {
width: 100%;
height: 100%;
position: relative;
> .canvas-content {
position: absolute;
width: auto;
height: auto;
display: flex;
align-items: flex-start;
gap: 5rem;
transform-origin: top left;
}
}
}
</style>

View File

@@ -19,9 +19,6 @@
<img :src="reportNull" alt="" />
</div>
<div v-else class="report-content">
<div class="">
</div>
<div class="downBtnBox">
<div class="downBtn">
<div class="icon">
@@ -32,6 +29,81 @@
</div>
<div class="content">
# 一级标题
<br />
# 一级标题
<br />
# 一级标题
<br />
# 一级标题
<br />
# 一级标题
<br />
# 一级标题
<br />
# 一级标题
<br />
# 一级标题
<br />
# 一级标题
<br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题
</div>
</div>
</div>
@@ -113,6 +185,8 @@
justify-content: center;
--border-width: 3px;
flex: 1;
overflow: hidden;
height: 100%;
&::before {
content: '';
position: absolute;
@@ -141,6 +215,7 @@
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
.downBtnBox{
padding: 2.2rem 5.2rem 0;
.downBtn{
@@ -165,6 +240,8 @@
.content{
word-break: break-word;
white-space: pre-wrap;
overflow-y: auto;
margin: 2rem;
}
}
}

View File

@@ -1,9 +1,11 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive, toRefs } from 'vue'
import { ref, onMounted, onUnmounted, reactive, toRefs, watch } from 'vue'
import Tree from './tree/index.vue'
import Detail from './detail/index.vue'
import { versionsList } from './tools/versionsData'
// import { versionsList } from './tools/versionsData'
import { findAndAddChild, findAndRemoveChild } from './tools/tools'
import { useProjectStore } from '@/stores'
import { versionTree, getChatNodeDetail } from '@/api/versitonTree'
const props = defineProps({
versionTreeData: {
@@ -11,14 +13,79 @@ const props = defineProps({
default: () => {
return {
drawer: false,
list: []
// list: []
}
}
}
})
//const emit = defineEmits([
//])
const versionsList = ref([])
const projectStore = useProjectStore()
watch(()=>projectStore.state.id, (newVal, oldVal) => {
if(newVal){
versionTree({
projectId: projectStore.state.id
}).then(res => {
console.log(res)
// versionsList.value = res.data
})
}
})
const setVersionsList = (res)=>{
versionsList.value = [{
"id": "node_001",
"url": "https://example.com/images/cover_001.jpg",
"children": [
{
"id": "node_002",
"url": "https://example.com/images/cover_002.jpg",
"children": [
{
"id": "node_003",
"url": "https://example.com/images/cover_003.jpg",
"children": []
},
{
"id": "node_004",
"url": "https://example.com/images/cover_004.jpg",
"children": []
}
]
},
{
"id": "node_005",
"url": "https://example.com/images/cover_005.jpg",
"children": [
{
"id": "node_006",
"url": "https://example.com/images/cover_006.jpg",
"children": []
}
]
}
]
}]
//设置versionId
function traverseArray(items,father, callback) {
for (let i = 0; i < items.length; i++) {
const item = items[i]
callback(item, i,father)
if (item.children && Array.isArray(item.children) && item.children.length > 0) {
traverseArray(item.children, item, callback)
}
}
}
traverseArray(versionsList.value,'',(item,i,father)=>{
item.versionId = father?`${father.versionId}-${i+1}`:'1'
})
}
const treeRef = ref(null)
const treeKey = ref(0)
const treeState = ref(true)//
@@ -31,13 +98,13 @@ const openTree = (state)=>{
const versionRestore = ()=>{
let id = ''
if(selectItem.value?.child?.length > 0){
if(selectItem.value?.children?.length > 0){
function findMaxForYourFormat(items) {
let max = 0
for (const item of items) {
// 直接分割并取最后一部分
const parts = item.id.split('-')
const parts = item?.versionId.split('-')
const lastNumber = parseInt(parts[parts.length - 1], 10)
if (lastNumber > max) {
@@ -47,26 +114,26 @@ const versionRestore = ()=>{
return max
}
id = `${selectItem.value?.id}-${findMaxForYourFormat(selectItem.value?.child) + 1}`
id = `${selectItem.value?.versionId}-${findMaxForYourFormat(selectItem.value?.children) + 1}`
}else{
id = `${selectItem.value?.id}-1`
id = `${selectItem.value?.versionId}-1`
}
let addObj = {
id,
name:`V${id}`
}
findAndAddChild(versionsList, selectItem.value?.id, addObj)
findAndAddChild(versionsList.value, selectItem.value?.versionId, addObj)
selectItem.value = {...addObj}
treeKey.value++
}
const versionDelete = (versionDetail)=>{
if(!selectItem.value.id)return
findAndRemoveChild(versionsList, selectItem.value.id)
if(!selectItem.value?.versionId)return
findAndRemoveChild(versionsList.value, selectItem.value?.versionId)
treeKey.value++
}
let data = reactive({})
onMounted(() => {})
onMounted(() => {setVersionsList('')})
onUnmounted(() => {})
defineExpose({})
const {} = toRefs(data)

View File

@@ -101,17 +101,17 @@ export function findAndAddChild(items, targetId, newChild) {
// 如果找到目标节点
if (item.id === targetId) {
// 初始化child数组如果不存在
if (!item.child) {
item.child = []
if (!item.children) {
item.children = []
}
// 添加新子节点
item.child.push(newChild)
item.children.push(newChild)
return true
}
// 递归搜索子节点
if (item.child && item.child.length > 0) {
const found = findAndAddChild(item.child, targetId, newChild)
if (item.children && item.children.length > 0) {
const found = findAndAddChild(item.children, targetId, newChild)
if (found) return true
}
}
@@ -135,8 +135,8 @@ export function findAndRemoveChild(items, targetId) {
}
// 递归搜索子节点
if (item.child && item.child.length > 0) {
const found = findAndRemoveChild(item.child, targetId)
if (item.children && item.children.length > 0) {
const found = findAndRemoveChild(item.children, targetId)
if (found) return true
}
}

View File

@@ -49,24 +49,25 @@ function traverseArray(items, callback) {
for (let i = 0; i < items.length; i++) {
const item = items[i]
callback(item, i)
if (item.child && Array.isArray(item.child) && item.child.length > 0) {
traverseArray(item.child, callback)
if (item.children && Array.isArray(item.children) && item.children.length > 0) {
traverseArray(item.children, callback)
}
}
}
const initialize = ()=>{
isLoad.value = false
treeList.value = []
treeList.value.push({id: null,name:'index',})
treeList.value.push({versionId: null,name:'index',})
traverseArray(props.versionsList, (item, index) => {
treeList.value.push(item)
})
console.log(treeList)
isLoad.value = true
if(!props.selectItem?.id)setSelectItem(treeList.value[treeList.value.length - 1])
if(!props.selectItem?.versionId)setSelectItem(treeList.value[treeList.value.length - 1])
}
const setSelectItem = (item)=>{
if(!item.id)return
if(!item.versionId)return
emit('update:selectItem', {...item})
}

View File

@@ -55,12 +55,12 @@ async function layoutGraph(direction) {
}
const push = (item)=>{
if(!item.id){
if(!item.versionId){
nodes.value.push({ id: '0', type: 'InputNode', class: 'custom-node', position })
}else{
let className = `custom-node item${item.id.replace(/-/g, "_")}`
let id = item.id
let source = edges.value.length == 0?'0':item.id.slice(0, -2)
let className = `custom-node item${item.versionId.replace(/-/g, "_")}`
let id = item.versionId
let source = edges.value.length == 0?'0':item.versionId.slice(0, -2)
nodes.value.push({id,type:'SecondaryNode',class:className,position,data:item})
edges.value.push({ id, target:id, source, type: 'smoothstep' })
}
@@ -77,7 +77,7 @@ const toggleNodesDraggable = () => {
}
const handleVueFlowNodeClick = ({node}) => {
if(node.data.id)emit('setSelectItem', node.data)
if(node.data.versionId)emit('setSelectItem', node.data)
}
watch(()=>props.treeList.length, (newVal, oldVal) => {
@@ -87,7 +87,7 @@ watch(()=>props.treeList.length, (newVal, oldVal) => {
push(item)
})
},{immediate:true})
watch(()=>props.selectItem.id, (newVal, oldVal) => {
watch(()=>props.selectItem.versionId, (newVal, oldVal) => {
})
const versionRestore = ()=>{

View File

@@ -22,10 +22,24 @@ const props = defineProps<{
<Handle type="source" id="Bottom" :position="Position.Bottom" />
<!-- <Handle type="source" id="Right" :position="Position.Right" />
<Handle type="target" id="Left" :position="Position.Left" /> -->
<div>{{ props.data.id }}</div>
<!-- <div>{{ props.data.id }}</div> -->
<div class="item">
<!-- {{ props.data.url }} -->
<img :src="props.data.url" />
</div>
</div>
</template>
<style lang="less" scoped>
.node{
.item{
width: 100%;
height: 100%;
img{
width: 100%;
height: 100%;
object-fit: contain;
}
}
}
</style>

View File

@@ -68,7 +68,7 @@
display: flex;
flex: 1;
justify-content: space-between;
// overflow: hidden;
overflow: hidden;
}
.c-svg {

View File

@@ -85,6 +85,7 @@
> div {
width: 16.4rem;
height: 3.4rem;
margin-bottom: 0.3rem;
display: flex;
align-items: center;
// justify-content: center;

View File

@@ -102,7 +102,6 @@
verificationCode: code
})
.then((res) => {
console.log(res)
if (res) {
userInfoStore.setToken(res)
userInfoStore.setUserInfo({