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" :key="item.value"
:disabled="item.value === modelValue" :disabled="item.value === modelValue"
@click="onItemClick(item.value)" @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-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
@@ -61,4 +65,17 @@
margin-left: 1.6rem; 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> </style>

View File

@@ -7,3 +7,4 @@ store.use(createPersistedState())
export default store export default store
export * from './global' export * from './global'
export * from './userInfo' 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,5 +1,14 @@
<template> <template>
<div class="canvas"> <div class="canvas">
<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="to-real-style" />
<card type="scene-composition" /> <card type="scene-composition" />
<card type="color-palette" /> <card type="color-palette" />
@@ -9,16 +18,47 @@
<card type="add-print" /> <card type="add-print" />
<card type="edit-material" /> <card type="edit-material" />
</div> </div>
</div>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import card from './components/cards/index.vue' 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 { useGlobalStore } from '@/stores'
import { useRouter, useRoute } from 'vue-router'
const router = useRouter()
const route = useRoute()
const globalStore = useGlobalStore() 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(() => { onMounted(() => {
globalStore.setHomeLeftNavCollapse(true) globalStore.setHomeLeftNavCollapse(true)
}) })
@@ -26,13 +66,29 @@
<style lang="less" scoped> <style lang="less" scoped>
.canvas { .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; background-color: #fcf8f1;
position: relative;
overflow: hidden;
> .canvas-main {
width: 100%;
height: 100%;
position: relative;
> .canvas-content {
position: absolute;
width: auto;
height: auto;
display: flex; display: flex;
flex-wrap: wrap;
align-content: flex-start;
align-items: flex-start; align-items: flex-start;
padding: 2rem; gap: 5rem;
gap: 2rem; transform-origin: top left;
}
}
} }
</style> </style>

View File

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

View File

@@ -1,9 +1,11 @@
<script setup lang="ts"> <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 Tree from './tree/index.vue'
import Detail from './detail/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 { findAndAddChild, findAndRemoveChild } from './tools/tools'
import { useProjectStore } from '@/stores'
import { versionTree, getChatNodeDetail } from '@/api/versitonTree'
const props = defineProps({ const props = defineProps({
versionTreeData: { versionTreeData: {
@@ -11,14 +13,79 @@ const props = defineProps({
default: () => { default: () => {
return { return {
drawer: false, drawer: false,
list: [] // list: []
} }
} }
} }
}) })
//const emit = defineEmits([ //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 treeRef = ref(null)
const treeKey = ref(0) const treeKey = ref(0)
const treeState = ref(true)// const treeState = ref(true)//
@@ -31,13 +98,13 @@ const openTree = (state)=>{
const versionRestore = ()=>{ const versionRestore = ()=>{
let id = '' let id = ''
if(selectItem.value?.child?.length > 0){ if(selectItem.value?.children?.length > 0){
function findMaxForYourFormat(items) { function findMaxForYourFormat(items) {
let max = 0 let max = 0
for (const item of items) { for (const item of items) {
// 直接分割并取最后一部分 // 直接分割并取最后一部分
const parts = item.id.split('-') const parts = item?.versionId.split('-')
const lastNumber = parseInt(parts[parts.length - 1], 10) const lastNumber = parseInt(parts[parts.length - 1], 10)
if (lastNumber > max) { if (lastNumber > max) {
@@ -47,26 +114,26 @@ const versionRestore = ()=>{
return max return max
} }
id = `${selectItem.value?.id}-${findMaxForYourFormat(selectItem.value?.child) + 1}` id = `${selectItem.value?.versionId}-${findMaxForYourFormat(selectItem.value?.children) + 1}`
}else{ }else{
id = `${selectItem.value?.id}-1` id = `${selectItem.value?.versionId}-1`
} }
let addObj = { let addObj = {
id, id,
name:`V${id}` name:`V${id}`
} }
findAndAddChild(versionsList, selectItem.value?.id, addObj) findAndAddChild(versionsList.value, selectItem.value?.versionId, addObj)
selectItem.value = {...addObj} selectItem.value = {...addObj}
treeKey.value++ treeKey.value++
} }
const versionDelete = (versionDetail)=>{ const versionDelete = (versionDetail)=>{
if(!selectItem.value.id)return if(!selectItem.value?.versionId)return
findAndRemoveChild(versionsList, selectItem.value.id) findAndRemoveChild(versionsList.value, selectItem.value?.versionId)
treeKey.value++ treeKey.value++
} }
let data = reactive({}) let data = reactive({})
onMounted(() => {}) onMounted(() => {setVersionsList('')})
onUnmounted(() => {}) onUnmounted(() => {})
defineExpose({}) defineExpose({})
const {} = toRefs(data) const {} = toRefs(data)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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