Merge branch 'main' of http://18.167.251.121:10003/aidlab/FiDA_Front
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
# VITE_APP_URL = http://192.168.31.82:8771
|
# VITE_APP_URL = http://192.168.31.82:8771
|
||||||
VITE_APP_URL = http://18.167.251.121:10015
|
VITE_APP_URL = http://18.167.251.121:10015
|
||||||
# VITE_APP_URL = http://192.168.31.118:8080
|
# VITE_APP_URL = http://192.168.31.118:8080
|
||||||
# VITE_APP_URL = http://192.168.31.82:8755
|
VITE_APP_URL = http://192.168.31.82:8755
|
||||||
VITE_GOOGLE_CLIENT_ID = 216037134725-7q8vqp0ohtmohlosltkfg7bd2v29rm5a.apps.googleusercontent.com
|
VITE_GOOGLE_CLIENT_ID = 216037134725-7q8vqp0ohtmohlosltkfg7bd2v29rm5a.apps.googleusercontent.com
|
||||||
|
|||||||
12
package-lock.json
generated
12
package-lock.json
generated
@@ -22,6 +22,7 @@
|
|||||||
"pinia": "^2.0.32",
|
"pinia": "^2.0.32",
|
||||||
"pinia-persistedstate-plugin": "^0.1.0",
|
"pinia-persistedstate-plugin": "^0.1.0",
|
||||||
"pinia-plugin-persistedstate": "^3.1.0",
|
"pinia-plugin-persistedstate": "^3.1.0",
|
||||||
|
"three": "^0.148.0",
|
||||||
"vue": "^3.2.47",
|
"vue": "^3.2.47",
|
||||||
"vue-draggable-plus": "^0.6.1",
|
"vue-draggable-plus": "^0.6.1",
|
||||||
"vue-i18n": "^11.2.8",
|
"vue-i18n": "^11.2.8",
|
||||||
@@ -8556,6 +8557,12 @@
|
|||||||
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
|
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/three": {
|
||||||
|
"version": "0.148.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/three/-/three-0.148.0.tgz",
|
||||||
|
"integrity": "sha512-8uzVV+qhTPi0bOFs/3te3RW6hb3urL8jYEl6irjCWo/l6sr8MPNMcClFev/MMYeIxr0gmDcoXTy/8LXh/LXkfw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/through": {
|
"node_modules/through": {
|
||||||
"version": "2.3.8",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmmirror.com/through/-/through-2.3.8.tgz",
|
"resolved": "https://registry.npmmirror.com/through/-/through-2.3.8.tgz",
|
||||||
@@ -16065,6 +16072,11 @@
|
|||||||
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
|
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"three": {
|
||||||
|
"version": "0.148.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/three/-/three-0.148.0.tgz",
|
||||||
|
"integrity": "sha512-8uzVV+qhTPi0bOFs/3te3RW6hb3urL8jYEl6irjCWo/l6sr8MPNMcClFev/MMYeIxr0gmDcoXTy/8LXh/LXkfw=="
|
||||||
|
},
|
||||||
"through": {
|
"through": {
|
||||||
"version": "2.3.8",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmmirror.com/through/-/through-2.3.8.tgz",
|
"resolved": "https://registry.npmmirror.com/through/-/through-2.3.8.tgz",
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
"pinia": "^2.0.32",
|
"pinia": "^2.0.32",
|
||||||
"pinia-persistedstate-plugin": "^0.1.0",
|
"pinia-persistedstate-plugin": "^0.1.0",
|
||||||
"pinia-plugin-persistedstate": "^3.1.0",
|
"pinia-plugin-persistedstate": "^3.1.0",
|
||||||
|
"three": "^0.148.0",
|
||||||
"vue": "^3.2.47",
|
"vue": "^3.2.47",
|
||||||
"vue-draggable-plus": "^0.6.1",
|
"vue-draggable-plus": "^0.6.1",
|
||||||
"vue-i18n": "^11.2.8",
|
"vue-i18n": "^11.2.8",
|
||||||
|
|||||||
@@ -8,15 +8,10 @@ export interface AgentParamsType {
|
|||||||
imageUrlList?: string[] // 图片URL列表
|
imageUrlList?: string[] // 图片URL列表
|
||||||
configParams: Record<string, any> // 其他配置参数
|
configParams: Record<string, any> // 其他配置参数
|
||||||
token: string
|
token: string
|
||||||
|
needSuggestion?: boolean
|
||||||
|
useReport: bolean
|
||||||
}
|
}
|
||||||
export const fetchAgentReply = (data: AgentParamsType): Promise<AgentResponse> => {
|
export const chatUrl = '/api/ai-design/chat'
|
||||||
return request({
|
|
||||||
url: '/api/ai-design/chat',
|
|
||||||
method: 'get',
|
|
||||||
data,
|
|
||||||
meta: { responseAll: true }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CreateProjectParamsType {
|
export interface CreateProjectParamsType {
|
||||||
type: string
|
type: string
|
||||||
@@ -33,11 +28,11 @@ export const createProject = (data: CreateProjectParamsType): Promise<any> => {
|
|||||||
* @param data 获取项目信息参数
|
* @param data 获取项目信息参数
|
||||||
* @param data.id 项目id
|
* @param data.id 项目id
|
||||||
* @returns 获取项目信息
|
* @returns 获取项目信息
|
||||||
*/
|
*/
|
||||||
export const getProjectInfo = (data) => {
|
export const getProjectInfo = (data) => {
|
||||||
return request({
|
return request({
|
||||||
url: `/api/project/${data.id}`,
|
url: `/api/project/${data.id}`,
|
||||||
method: 'get',
|
method: 'get'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +42,7 @@ export const getProjectInfo = (data) => {
|
|||||||
* @param params.page 页码
|
* @param params.page 页码
|
||||||
* @param params.size 每页数量
|
* @param params.size 每页数量
|
||||||
* @returns 获取项目版本列表
|
* @returns 获取项目版本列表
|
||||||
*/
|
*/
|
||||||
export const getProjectList = (params) => {
|
export const getProjectList = (params) => {
|
||||||
return request({
|
return request({
|
||||||
url: `/api/project/list`,
|
url: `/api/project/list`,
|
||||||
@@ -66,7 +61,7 @@ export const getProjectList = (params) => {
|
|||||||
* @param data.style 项目风格
|
* @param data.style 项目风格
|
||||||
* @param data.temperature 项目温度
|
* @param data.temperature 项目温度
|
||||||
* @returns 修改项目信息
|
* @returns 修改项目信息
|
||||||
*/
|
*/
|
||||||
export const updateProject = (id: string, data: Object) => {
|
export const updateProject = (id: string, data: Object) => {
|
||||||
return request({
|
return request({
|
||||||
url: `/api/project/${id}`,
|
url: `/api/project/${id}`,
|
||||||
@@ -78,10 +73,10 @@ export const updateProject = (id: string, data: Object) => {
|
|||||||
* 删除项目
|
* 删除项目
|
||||||
* @param id 项目id
|
* @param id 项目id
|
||||||
* @returns 删除项目
|
* @returns 删除项目
|
||||||
*/
|
*/
|
||||||
export const deleteProject = (id: string) => {
|
export const deleteProject = (id: string) => {
|
||||||
return request({
|
return request({
|
||||||
url: `/api/project/${id}`,
|
url: `/api/project/${id}`,
|
||||||
method: 'delete',
|
method: 'delete'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
54
src/api/flow-canvas.ts
Normal file
54
src/api/flow-canvas.ts
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取sketch的画布详情
|
||||||
|
* @param data 获取sketch的画布详情的参数
|
||||||
|
* @param data.id sketch id
|
||||||
|
* @returns 获取sketch的画布详情
|
||||||
|
*/
|
||||||
|
export interface getSketchFlowCanvasData {
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
export const getSketchFlowCanvas = (data:getSketchFlowCanvasData) => {
|
||||||
|
return request({
|
||||||
|
url: `/api/canvas/detail/${data.id}`,
|
||||||
|
method: 'get',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存或者更新sketch的画布详情
|
||||||
|
* @param data 获取sketch的画布详情的参数
|
||||||
|
* @param data.id sketch id
|
||||||
|
* @param data.canvasData sketch id
|
||||||
|
* @returns 获取sketch的画布详情
|
||||||
|
*/
|
||||||
|
export interface saveSketchFlowCanvasData {
|
||||||
|
id?: string
|
||||||
|
canvasData: string
|
||||||
|
}
|
||||||
|
export const putSketchFlowCanvas = (data:saveSketchFlowCanvasData) => {
|
||||||
|
return request({
|
||||||
|
url: `/api/canvas/detail/${data.id}`,
|
||||||
|
method: 'put',
|
||||||
|
data: data.canvasData
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除sketch和画布详情
|
||||||
|
* @param data 删除sketch的画布详情的参数
|
||||||
|
* @param data.id sketch id
|
||||||
|
* @param data.versionNodeId 节点id
|
||||||
|
* @returns 获取sketch的画布详情
|
||||||
|
*/
|
||||||
|
export interface deleteSketchFlowCanvasData {
|
||||||
|
id?: string
|
||||||
|
versionNodeId?: string
|
||||||
|
}
|
||||||
|
export const deleteSketchFlowCanvas = (data:deleteSketchFlowCanvasData) => {
|
||||||
|
return request({
|
||||||
|
url: `/api/canvas/detail/${data.versionNodeId}/${data.id}`,
|
||||||
|
method: 'delete',
|
||||||
|
})
|
||||||
|
}
|
||||||
BIN
src/assets/images/delete.png
Normal file
BIN
src/assets/images/delete.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 241 B |
BIN
src/assets/images/restore-sketch.png
Normal file
BIN
src/assets/images/restore-sketch.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 468 B |
@@ -0,0 +1,123 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
|
||||||
|
//const props = defineProps({
|
||||||
|
//})
|
||||||
|
//const emit = defineEmits([
|
||||||
|
//])
|
||||||
|
let data = reactive({
|
||||||
|
})
|
||||||
|
onMounted(()=>{
|
||||||
|
})
|
||||||
|
onUnmounted(()=>{
|
||||||
|
})
|
||||||
|
defineExpose({})
|
||||||
|
const {} = toRefs(data);
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="modalDetail">
|
||||||
|
<div class="title">
|
||||||
|
Properties Information
|
||||||
|
</div>
|
||||||
|
<div class="detail">
|
||||||
|
<div class="name">
|
||||||
|
<div class="title fs18">
|
||||||
|
Sofa
|
||||||
|
</div>
|
||||||
|
<div class="fs14 c66">
|
||||||
|
Model Name
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="fs14 c18">
|
||||||
|
Transform
|
||||||
|
</div>
|
||||||
|
<div class="flex">
|
||||||
|
<div>
|
||||||
|
<div class="fs14 c18">X</div>
|
||||||
|
<div class="fs12 c66">1.0</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="fs14 c18">Y</div>
|
||||||
|
<div class="fs12 c66">1.0</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="fs14 c18">Z</div>
|
||||||
|
<div class="fs12 c66">1.0</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="fs14 c18">
|
||||||
|
Dimensions
|
||||||
|
</div>
|
||||||
|
<div class="flex">
|
||||||
|
<div>
|
||||||
|
<div class="fs14 c18">Height</div>
|
||||||
|
<div class="fs12 c66">22</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="fs14 c18">Width</div>
|
||||||
|
<div class="fs12 c66">22</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="fs14 c18">Depth</div>
|
||||||
|
<div class="fs12 c66">22</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.modalDetail{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
> .title{
|
||||||
|
margin: 2.4rem 0;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 2rem;
|
||||||
|
line-height: 2.7rem;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
> .detail{
|
||||||
|
> .name{
|
||||||
|
> .title{
|
||||||
|
margin-bottom: .4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .flex{
|
||||||
|
display: flex;
|
||||||
|
> div{
|
||||||
|
margin-right: 4.8rem;
|
||||||
|
:last-child{
|
||||||
|
margin-top: .2rem;
|
||||||
|
}
|
||||||
|
&:last-child{
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> div{
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 2.4rem;
|
||||||
|
&:last-child{
|
||||||
|
margin-bottom: 0rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.fs18{
|
||||||
|
font-size: 1.8rem;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
.fs12{
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
.fs14{
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
.c18{
|
||||||
|
color: #181818;
|
||||||
|
}
|
||||||
|
.c66{
|
||||||
|
color: #666666;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
|
||||||
|
|
||||||
|
import model from './model.vue'
|
||||||
|
import detail from './detail.vue'
|
||||||
|
|
||||||
|
//const props = defineProps({
|
||||||
|
//})
|
||||||
|
//const emit = defineEmits([
|
||||||
|
//])
|
||||||
|
let data = reactive({
|
||||||
|
})
|
||||||
|
const modelRef = ref(null)
|
||||||
|
onMounted(()=>{
|
||||||
|
modelRef.value.open()
|
||||||
|
})
|
||||||
|
onUnmounted(()=>{
|
||||||
|
})
|
||||||
|
defineExpose({})
|
||||||
|
const {} = toRefs(data);
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="three-model">
|
||||||
|
<div class="modelBox">
|
||||||
|
<model ref="modelRef" />
|
||||||
|
</div>
|
||||||
|
<div class="detailBox">
|
||||||
|
<detail ref="detailRef" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.three-model{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
padding: 6.7rem 13rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
> .modelBox{
|
||||||
|
height: 100%;
|
||||||
|
width: 65.5rem;
|
||||||
|
}
|
||||||
|
> .detailBox{
|
||||||
|
width: 22rem;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, onUnmounted, shallowRef, nextTick } from "vue";
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
import gsap from 'gsap';
|
||||||
|
import * as THREE from 'three';
|
||||||
|
import { initThree,clearModel,addModel } from './threeTool'
|
||||||
|
|
||||||
|
//const props = defineProps({
|
||||||
|
//})
|
||||||
|
//const emit = defineEmits([
|
||||||
|
//])
|
||||||
|
|
||||||
|
const threeDom = ref()//threeDom元素
|
||||||
|
|
||||||
|
let scene = shallowRef()//场景
|
||||||
|
let group = shallowRef()//组
|
||||||
|
let camera = shallowRef()//相机
|
||||||
|
let renderer = shallowRef()//渲染器
|
||||||
|
let pointLight = shallowRef();//光
|
||||||
|
let ambient = shallowRef()//环境光
|
||||||
|
let controls = shallowRef()//监听鼠标、键盘事件
|
||||||
|
|
||||||
|
const animationId = ref(null);
|
||||||
|
//加载进度
|
||||||
|
const load = ref({
|
||||||
|
state:false,
|
||||||
|
progress:0
|
||||||
|
})
|
||||||
|
// const textureLoader = ref(new THREE.TextureLoader())//材质
|
||||||
|
//初始化
|
||||||
|
const init = ()=>{
|
||||||
|
//初始化threejs
|
||||||
|
if(scene.value)return
|
||||||
|
const initResult = initThree(threeDom.value)
|
||||||
|
scene.value = initResult.scene
|
||||||
|
group.value = initResult.group
|
||||||
|
camera.value = initResult.camera
|
||||||
|
renderer.value = initResult.renderer
|
||||||
|
ambient.value = initResult.ambient
|
||||||
|
controls.value = initResult.controls
|
||||||
|
pointLight.value = initResult.pointLight
|
||||||
|
|
||||||
|
threeDom.value.ondblclick = (event:any)=>{
|
||||||
|
let intersects = openModel(event);
|
||||||
|
if(!intersects || intersects.length<=0) return
|
||||||
|
const bbox = new THREE.Box3().setFromObject(intersects[0].object);
|
||||||
|
const size = new THREE.Vector3();
|
||||||
|
let target2 = bbox.getCenter(size);//获取选中包围起来后的中心坐标
|
||||||
|
animateCamera(camera.value.position,intersects[0].point,controls.value.target,target2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let openModel = (event:any)=>{
|
||||||
|
let mouse = new THREE.Vector2();
|
||||||
|
let raycaster = new THREE.Raycaster();
|
||||||
|
mouse.x=(event.clientX/window.innerWidth)*2-1;
|
||||||
|
mouse.y=-(event.clientY/window.innerHeight)*2+1;
|
||||||
|
raycaster.setFromCamera(mouse, camera.value);
|
||||||
|
let intersects = raycaster.intersectObjects(scene.value.children);
|
||||||
|
return intersects
|
||||||
|
}
|
||||||
|
let isTweening = false;
|
||||||
|
function animateCamera(current1:any, target1:any, current2:any, target2:any){
|
||||||
|
if (isTweening) return
|
||||||
|
isTweening = true
|
||||||
|
let options = {
|
||||||
|
x1: current1.x, // 相机当前位置x
|
||||||
|
y1: current1.y, // 相机当前位置y
|
||||||
|
z1: current1.z, // 相机当前位置z
|
||||||
|
x2: current2.x, // 控制当前的中心点x
|
||||||
|
y2: current2.y, // 控制当前的中心点y
|
||||||
|
// z2: current2.z // 控制当前的中心点z
|
||||||
|
}
|
||||||
|
gsap.to(options,{
|
||||||
|
x1: 0, // 新的相机位置x
|
||||||
|
y1: target2.y, // 新的相机位置y
|
||||||
|
z1: 1000, // 新的相机位置z
|
||||||
|
x2: 0, // 新的控制中心点位置x
|
||||||
|
y2: target2.y, // 新的控制中心点位置x
|
||||||
|
duration:1,
|
||||||
|
ease:'linear',
|
||||||
|
onUpdate:()=>{
|
||||||
|
camera.value.position.x = options.x1;
|
||||||
|
camera.value.position.y = options.y1;
|
||||||
|
camera.value.position.z = options.z1;
|
||||||
|
controls.value.target.x = options.x2;
|
||||||
|
controls.value.target.y = options.y2;
|
||||||
|
// controls.value.target.z = object.z2;
|
||||||
|
controls.value.update();
|
||||||
|
},
|
||||||
|
onComplete:()=>{
|
||||||
|
isTweening = false
|
||||||
|
}
|
||||||
|
// z2: target2.z // 新的控制中心点位置x
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const setModel = async (url:any)=>{
|
||||||
|
clearModel(group,scene)
|
||||||
|
await addModel(url,controls,camera,pointLight,group,load)
|
||||||
|
// addMaterial()
|
||||||
|
}
|
||||||
|
const open = async ()=>{
|
||||||
|
load.value.state = true
|
||||||
|
await nextTick(()=>{
|
||||||
|
init()
|
||||||
|
})
|
||||||
|
controls.value.enableDamping = true;
|
||||||
|
let animate = ()=>{
|
||||||
|
animationId.value = requestAnimationFrame(animate);
|
||||||
|
// renderer.value.render(scene.value, camera.value);
|
||||||
|
// model.rotation.x += 0.01; //旋转物体
|
||||||
|
var vector = camera.value.position.clone()
|
||||||
|
controls.value.update();
|
||||||
|
renderer.value.render(scene.value, camera.value);
|
||||||
|
// point.position.set(vector.x,vector.y,vector.z);
|
||||||
|
// group.rotation.y += 0.01;
|
||||||
|
// composer.render();
|
||||||
|
};
|
||||||
|
animate();
|
||||||
|
await setModel("https://www.minio-api.aida.com.hk/aida-threed/female/glb/1%E7%9F%AD%E8%A2%96T%E6%81%A4.glb?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=admin%2F20260310%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260310T032933Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=184ec7f9ff3076dde5aca66e2d2e27f8d180add698a5b1040fe903a55cb2f85e")
|
||||||
|
load.value.state = false
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(()=>{
|
||||||
|
})
|
||||||
|
onUnmounted(()=>{
|
||||||
|
})
|
||||||
|
defineExpose({open})
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="modelBox">
|
||||||
|
<div class="model" ref="threeDom">
|
||||||
|
</div>
|
||||||
|
<div class="load" v-show="load.state">
|
||||||
|
<i class="fi fi-rr-cubes"></i>
|
||||||
|
<div class="text">Load...</div>
|
||||||
|
<div class="loadBox">
|
||||||
|
<div class="schedule" :style="{width:load.progress+'%'}"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.modelBox{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
>.model{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border-radius: 1rem;
|
||||||
|
border: 1px solid #D9D9D9;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
> .load{
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
background: rgba(0, 0, 0, .2);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
color: #fff;
|
||||||
|
> i{
|
||||||
|
font-size: 3rem;
|
||||||
|
}
|
||||||
|
> .loadBox{
|
||||||
|
width: 15rem;
|
||||||
|
height: 1rem;
|
||||||
|
border-radius: 1rem;
|
||||||
|
background: #fff;
|
||||||
|
overflow: hidden;
|
||||||
|
> .schedule{
|
||||||
|
height: 100%;
|
||||||
|
background: greenyellow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
import * as THREE from 'three';
|
||||||
|
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
|
||||||
|
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
||||||
|
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'
|
||||||
|
|
||||||
|
export const initThree = (threeDom)=>{
|
||||||
|
const scene = new THREE.Scene();
|
||||||
|
const group = new THREE.Group()
|
||||||
|
scene.add(group)
|
||||||
|
|
||||||
|
//创建相机对象
|
||||||
|
// this.camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
|
||||||
|
const camera = new THREE.PerspectiveCamera(45, threeDom.offsetWidth / threeDom.offsetHeight, 0.1, 10000);
|
||||||
|
camera.position.set(0, 90, 6); //设置相机位置
|
||||||
|
camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
|
||||||
|
/**
|
||||||
|
* 创建渲染器对象
|
||||||
|
*/
|
||||||
|
let width = threeDom.offsetWidth; //窗口宽度
|
||||||
|
let height = threeDom.offsetHeight; //窗口高度
|
||||||
|
const renderer = new THREE.WebGLRenderer({
|
||||||
|
antialias: true,
|
||||||
|
logarithmicDepthBuffer: true,//深度缓存 防止模型闪烁重影
|
||||||
|
});
|
||||||
|
|
||||||
|
renderer.toneMapping = THREE.ACESFilmicToneMapping;//设置色调
|
||||||
|
renderer.toneMappingExposure = 1.3;
|
||||||
|
|
||||||
|
renderer.shadowMap.enabled = true;
|
||||||
|
renderer.setPixelRatio(window.devicePixelRatio);
|
||||||
|
renderer.setSize(width, height); //设置渲染区域尺寸
|
||||||
|
renderer.setClearColor(0xffffff, 1); //设置背景颜色
|
||||||
|
threeDom.innerHTML = '';
|
||||||
|
threeDom.appendChild(renderer.domElement);
|
||||||
|
|
||||||
|
// 设置渲染器大小
|
||||||
|
//环境光
|
||||||
|
let ambient = new THREE.AmbientLight(0xffffff,.8);
|
||||||
|
scene.add(ambient);
|
||||||
|
let controls = new OrbitControls(camera,renderer.domElement)//监听鼠标、键盘事件;
|
||||||
|
// controls.minDistance = 500; // 设置相机与焦点的最小距离
|
||||||
|
// controls.maxDistance = 4000; // 设置相机与焦点的最大距离
|
||||||
|
controls.mouseButtons = {
|
||||||
|
// LEFT:THREE.MOUSE.PAN, // 左键 拖动(默认旋转:ROTATE)
|
||||||
|
LEFT:THREE.MOUSE.ROTATE, // 左键 拖动(默认旋转:ROTATE)
|
||||||
|
MIDDLE:THREE.MOUSE.DOLLY, // 滑轮 缩放
|
||||||
|
RIGHT:THREE.MOUSE.PAN // 右键 旋转(默认拖动:PAN)
|
||||||
|
// RIGHT:THREE.MOUSE.ROTAafTE // 右键 旋转(默认拖动:PAN)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 光源设置
|
||||||
|
*/
|
||||||
|
//点光源
|
||||||
|
/**
|
||||||
|
* AmbientLight 环境光
|
||||||
|
PointLight 点光源
|
||||||
|
DirectionalLight 平行光,比如太阳光
|
||||||
|
SpotLight 聚光源
|
||||||
|
*/
|
||||||
|
const pointLight = new THREE.DirectionalLight(0xffffff,.5);
|
||||||
|
pointLight.intensity = 1.2
|
||||||
|
pointLight.castShadow = true//开启阴影
|
||||||
|
pointLight.shadow.mapSize = new THREE.Vector2(width, height)
|
||||||
|
scene.add(pointLight); //点光源添加到场景中
|
||||||
|
// pointLight.position.set(400, 200, 300); //点光源位置
|
||||||
|
pointLight.position.y = 400;
|
||||||
|
pointLight.position.z = 200;
|
||||||
|
pointLight.position.x = 200;
|
||||||
|
let floorGeometry = new THREE.PlaneGeometry(5000, 3000)//地板大小
|
||||||
|
let floorMaterial = new THREE.MeshPhongMaterial({ color: "#7e7ab0", })
|
||||||
|
let floorMesh = new THREE.Mesh(floorGeometry, floorMaterial);
|
||||||
|
floorMesh.rotation.x = -0.5 * Math.PI;
|
||||||
|
floorMesh.receiveShadow = true;
|
||||||
|
floorMesh.position.y = -0.001;
|
||||||
|
// scene.add(floorMesh);
|
||||||
|
const textureLoader = new THREE.TextureLoader();
|
||||||
|
// const texture = textureLoader.load('/3dModel/sketch-thick.jpg');
|
||||||
|
scene.background = new THREE.Color("#fff");
|
||||||
|
return {scene,group,camera,renderer,ambient,controls,pointLight}
|
||||||
|
}
|
||||||
|
export const clearModel = (group,scene)=>{
|
||||||
|
const oldGroup:any = group.value;
|
||||||
|
group.value = new THREE.Group();
|
||||||
|
scene.value.add(group.value);
|
||||||
|
scene.value.remove(oldGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const addModel = async (
|
||||||
|
url:any,
|
||||||
|
controls:OrbitControls,
|
||||||
|
camera:THREE.PerspectiveCamera,
|
||||||
|
pointLight:THREE.DirectionalLight,
|
||||||
|
group:THREE.Group,
|
||||||
|
load:any)=>{
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
var fbxLoader = new GLTFLoader();
|
||||||
|
let drac = new DRACOLoader()
|
||||||
|
drac.setDecoderPath('/draco/')
|
||||||
|
fbxLoader.setDRACOLoader(drac)
|
||||||
|
// fbxLoader.load('/3dModel/222/1111.glb',
|
||||||
|
fbxLoader.load(url,
|
||||||
|
|
||||||
|
(obj:any) => {
|
||||||
|
let scene = obj.scene;
|
||||||
|
var box = new THREE.Box3().setFromObject(scene);
|
||||||
|
var center = box.getCenter(new THREE.Vector3());
|
||||||
|
controls.value.target.copy(center);
|
||||||
|
// controls.autoRotate = true
|
||||||
|
camera.value.position.y = center.y;
|
||||||
|
camera.value.position.z = 1000;
|
||||||
|
pointLight.value.position.y = 250;
|
||||||
|
pointLight.value.position.z = 1250;
|
||||||
|
group.value.add(scene);
|
||||||
|
resolve('')
|
||||||
|
},(xhr:any) => { // 加载进度回调
|
||||||
|
const percent = xhr.total == 0?100:(xhr.loaded / xhr.total * 100).toFixed(2);
|
||||||
|
load.value.progress = percent
|
||||||
|
// updateProgressBar(Number(percent));
|
||||||
|
},(error:any) => { // 加载失败回调
|
||||||
|
console.error('模型加载失败:', error);
|
||||||
|
reject('')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -53,6 +53,9 @@
|
|||||||
@home="() => fitView({ maxZoom: 1 })"
|
@home="() => fitView({ maxZoom: 1 })"
|
||||||
/>
|
/>
|
||||||
<image-preview ref="imagePreviewRef" />
|
<image-preview ref="imagePreviewRef" />
|
||||||
|
<baseModal ref="threeModelRef" >
|
||||||
|
<threeModel />
|
||||||
|
</baseModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@@ -64,11 +67,17 @@
|
|||||||
import headerTools from './components/header-tools.vue'
|
import headerTools from './components/header-tools.vue'
|
||||||
import zoom from '../components/zoom.vue'
|
import zoom from '../components/zoom.vue'
|
||||||
import imagePreview from '../components/image-preview.vue'
|
import imagePreview from '../components/image-preview.vue'
|
||||||
|
import baseModal from '../components/base-modal.vue'
|
||||||
|
// 工具
|
||||||
|
import threeModel from './components/tools/threeModel/index.vue'
|
||||||
// 节点
|
// 节点
|
||||||
import node from './components/node.vue'
|
import node from './components/node.vue'
|
||||||
import resultImage from './components/nodes/result-image.vue'
|
import resultImage from './components/nodes/result-image.vue'
|
||||||
import card from './components/nodes/cards/index.vue'
|
import card from './components/nodes/cards/index.vue'
|
||||||
import text from './components/nodes/text.vue'
|
import text from './components/nodes/text.vue'
|
||||||
|
|
||||||
|
// 接口
|
||||||
|
import { getSketchFlowCanvas, putSketchFlowCanvas } from '@/api/flow-canvas'
|
||||||
const components = {
|
const components = {
|
||||||
[NODE_COMPONENT.RESULT_IMAGE]: resultImage,
|
[NODE_COMPONENT.RESULT_IMAGE]: resultImage,
|
||||||
[NODE_COMPONENT.CARD]: card,
|
[NODE_COMPONENT.CARD]: card,
|
||||||
@@ -162,16 +171,25 @@
|
|||||||
// 导出流程
|
// 导出流程
|
||||||
const exportFlow = () => {
|
const exportFlow = () => {
|
||||||
// flowManager.exportFlow()
|
// flowManager.exportFlow()
|
||||||
|
|
||||||
const str = JSON.stringify(stateManager.nodes.value)
|
const str = JSON.stringify(stateManager.nodes.value)
|
||||||
const json = JSON.parse(str)
|
const json = JSON.parse(str)
|
||||||
localStorage.setItem('flow_json', str)
|
putSketchFlowCanvas({
|
||||||
|
id: props.config.id || '==========',
|
||||||
|
canvasData: str
|
||||||
|
}).then((res) => {
|
||||||
|
if (res) {
|
||||||
|
console.log(res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// localStorage.setItem('flow_json', str)
|
||||||
}
|
}
|
||||||
// 导入流程
|
// 导入流程
|
||||||
const importFlow = async () => {
|
const importFlow = async (json) => {
|
||||||
try {
|
try {
|
||||||
stateManager.nodes.value = []
|
stateManager.nodes.value = []
|
||||||
await nextTick()
|
await nextTick()
|
||||||
const json = JSON.parse(localStorage.getItem('flow_json') || '[]')
|
// const json = JSON.parse(localStorage.getItem('flow_json') || '[]')
|
||||||
stateManager.nodes.value = json
|
stateManager.nodes.value = json
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
@@ -184,24 +202,42 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const imagePreviewRef = ref<any>()
|
const imagePreviewRef = ref<any>()
|
||||||
|
const threeModelRef = ref<any>()
|
||||||
/** 打开图片预览 */
|
/** 打开图片预览 */
|
||||||
const openImagePreview = (url: string) => {
|
const openImagePreview = (url: string) => {
|
||||||
imagePreviewRef.value.open(url)
|
imagePreviewRef.value.open(url)
|
||||||
}
|
}
|
||||||
provide('openImagePreview', openImagePreview)
|
provide('openImagePreview', openImagePreview)
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
// window['vueFlow'] = vueFlow
|
// window['vueFlow'] = vueFlow
|
||||||
// window['nodes'] = nodes
|
// window['nodes'] = nodes
|
||||||
nodeManager.createResultNode({
|
let json = []
|
||||||
data: {
|
await new Promise((resolve) => {
|
||||||
disableDelete: true,
|
getSketchFlowCanvas({ id: props.config.id || '==========' }).then((res) => {
|
||||||
isHeader: false,
|
if (res) {
|
||||||
data: {
|
console.log(res)
|
||||||
url: props.config.url
|
json = res.data
|
||||||
}
|
}
|
||||||
}
|
resolve(true)
|
||||||
|
}).catch(() => {
|
||||||
|
resolve(true)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
if(json.length > 0){
|
||||||
|
importFlow(json)
|
||||||
|
}else{
|
||||||
|
nodeManager.createResultNode({
|
||||||
|
data: {
|
||||||
|
disableDelete: true,
|
||||||
|
isHeader: false,
|
||||||
|
data: {
|
||||||
|
url: props.config.url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
eventManager.removeEvents() // 移除事件
|
eventManager.removeEvents() // 移除事件
|
||||||
|
|||||||
57
src/components/Canvas/components/base-modal.vue
Normal file
57
src/components/Canvas/components/base-modal.vue
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
class="base-modal"
|
||||||
|
v-model="showDialog"
|
||||||
|
align-center
|
||||||
|
:show-close="false"
|
||||||
|
:width="modalWidth"
|
||||||
|
style="border-radius: 2.9rem; padding: 0; --el-dialog-padding-primary: 0;background-color: #f7f7f7;"
|
||||||
|
>
|
||||||
|
<template #header="{ close }">
|
||||||
|
<div class="header-close" @click="close">
|
||||||
|
<svg-icon name="close" size="23" size-unit="px" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="modal-box">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, ref, onBeforeUnmount, shallowRef } from 'vue'
|
||||||
|
const props = defineProps({
|
||||||
|
modalWidth: {
|
||||||
|
type: String,
|
||||||
|
default: '63vw'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const showDialog = ref(true)
|
||||||
|
const open = (url_: any) => {
|
||||||
|
showDialog.value = true
|
||||||
|
}
|
||||||
|
const close = () => {
|
||||||
|
showDialog.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
open,
|
||||||
|
close
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.header-close {
|
||||||
|
position: absolute;
|
||||||
|
top: 3rem;
|
||||||
|
right: 4rem;
|
||||||
|
width: 4rem;
|
||||||
|
height: 4rem;
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
.modal-box {
|
||||||
|
width: 100%;
|
||||||
|
height: 70vh;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -69,6 +69,7 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 3rem;
|
top: 3rem;
|
||||||
right: 3rem;
|
right: 3rem;
|
||||||
|
--my-info-bgColor: #fff;
|
||||||
}
|
}
|
||||||
> .close-btn {
|
> .close-btn {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|||||||
@@ -72,9 +72,9 @@
|
|||||||
min-width: 18rem;
|
min-width: 18rem;
|
||||||
height: 4.3rem;
|
height: 4.3rem;
|
||||||
margin-right: 1rem;
|
margin-right: 1rem;
|
||||||
background-color: rgba(255, 252, 244, 1);
|
|
||||||
border: 1px solid #ffcf90;
|
border: 1px solid #ffcf90;
|
||||||
border-radius: 0.8rem;
|
border-radius: 0.8rem;
|
||||||
|
background-color: var(--my-info-bgColor, rgba(255, 252, 244, 1));
|
||||||
> .credits {
|
> .credits {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
font-size: 1.3rem;
|
font-size: 1.3rem;
|
||||||
|
|||||||
@@ -7,23 +7,20 @@ import MyEvent from '@/utils/myEvent'
|
|||||||
|
|
||||||
|
|
||||||
// Agent 项目初始数据 store
|
// Agent 项目初始数据 store
|
||||||
|
type InitialProjectData = {
|
||||||
|
text: string
|
||||||
|
images: Array<{ url: string; name: string }>
|
||||||
|
type: string
|
||||||
|
area: string
|
||||||
|
style: string
|
||||||
|
useReport:boolean
|
||||||
|
needSuggestion:boolean
|
||||||
|
}
|
||||||
export const useAgentStore = defineStore('agent', () => {
|
export const useAgentStore = defineStore('agent', () => {
|
||||||
const initialProjectData = ref<{
|
const initialProjectData = ref<InitialProjectData | null>(null)
|
||||||
text: string
|
|
||||||
images: Array<{ url: string; name: string }>
|
|
||||||
type: string
|
|
||||||
area: string
|
|
||||||
style: string
|
|
||||||
} | null>(null)
|
|
||||||
|
|
||||||
// 保存项目初始数据
|
// 保存项目初始数据
|
||||||
const setInitialProjectData = (data: {
|
const setInitialProjectData = (data: InitialProjectData) => {
|
||||||
text: string
|
|
||||||
images: Array<{ url: string; name: string }>
|
|
||||||
type: string
|
|
||||||
area: string
|
|
||||||
style: string
|
|
||||||
}) => {
|
|
||||||
initialProjectData.value = data
|
initialProjectData.value = data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,10 +24,10 @@
|
|||||||
import { ref, reactive, computed, onUnmounted, onMounted, nextTick, watch } from 'vue'
|
import { ref, reactive, computed, onUnmounted, onMounted, nextTick, watch } from 'vue'
|
||||||
import List from './List.vue'
|
import List from './List.vue'
|
||||||
import Input from '../../components/Input.vue'
|
import Input from '../../components/Input.vue'
|
||||||
import { fetchAgentReply } from '@/api/agent'
|
import { chatUrl } from '@/api/agent'
|
||||||
import type { AgentParamsType } from '@/api/agent'
|
import type { AgentParamsType } from '@/api/agent'
|
||||||
import { useUserInfoStore, useProjectStore } from '@/stores'
|
import { useUserInfoStore, useProjectStore, useAgentStore } from '@/stores'
|
||||||
import { useAgentStore } from '@/stores/agent'
|
import MyEvent from '@/utils/myEvent'
|
||||||
|
|
||||||
const userStore = useUserInfoStore()
|
const userStore = useUserInfoStore()
|
||||||
const agentStore = useAgentStore()
|
const agentStore = useAgentStore()
|
||||||
@@ -54,6 +54,8 @@
|
|||||||
message: '',
|
message: '',
|
||||||
token: userStore.state.token,
|
token: userStore.state.token,
|
||||||
versionID: '',
|
versionID: '',
|
||||||
|
needSuggestion: false,
|
||||||
|
useReport: false,
|
||||||
configParams: {
|
configParams: {
|
||||||
type: '',
|
type: '',
|
||||||
region: '',
|
region: '',
|
||||||
@@ -99,6 +101,8 @@
|
|||||||
style: initialData.style,
|
style: initialData.style,
|
||||||
temperature: 0.7
|
temperature: 0.7
|
||||||
}
|
}
|
||||||
|
params.needSuggestion = initialData.needSuggestion || false
|
||||||
|
params.useReport = initialData.useReport
|
||||||
handleSendMessage({
|
handleSendMessage({
|
||||||
text: initialData.text,
|
text: initialData.text,
|
||||||
images: initialData.images,
|
images: initialData.images,
|
||||||
@@ -158,7 +162,7 @@
|
|||||||
configParams: JSON.stringify(params.configParams)
|
configParams: JSON.stringify(params.configParams)
|
||||||
})
|
})
|
||||||
const BASEURL = import.meta.env.VITE_APP_URL
|
const BASEURL = import.meta.env.VITE_APP_URL
|
||||||
const response = await fetch(`${BASEURL}/api/ai-design/chat?${urlParams.toString()}`, {
|
const response = await fetch(`${BASEURL}${chatUrl}?${urlParams.toString()}`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
signal: abortController.signal
|
signal: abortController.signal
|
||||||
})
|
})
|
||||||
@@ -232,7 +236,7 @@
|
|||||||
// 过滤掉 id: 等字段,只取 data:
|
// 过滤掉 id: 等字段,只取 data:
|
||||||
|
|
||||||
let isNodeIdEvent = false
|
let isNodeIdEvent = false
|
||||||
if (event.startsWith('event:')) {
|
if (event.includes('nodeId')) {
|
||||||
isNodeIdEvent = true
|
isNodeIdEvent = true
|
||||||
// continue
|
// continue
|
||||||
}
|
}
|
||||||
@@ -245,23 +249,30 @@
|
|||||||
flag = false
|
flag = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
if (event.includes('todo') || event.includes('webAddress')) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
const dataLines = event
|
const dataLines = event
|
||||||
.split(/\n/)
|
.split(/\n/)
|
||||||
.filter((line) => line.startsWith('data:'))
|
.filter((line) => line.startsWith('data:'))
|
||||||
.map((line) => line.replace(/^data:\s*/, '').trim())
|
.map((line) => line.replace(/^data:\s*/, '').trim())
|
||||||
|
.filter((content) => content.startsWith('{') || content.startsWith('['))
|
||||||
// console.log('dataLInes', dataLines)
|
// console.log('dataLInes', dataLines)
|
||||||
if (isNodeIdEvent) {
|
if (isNodeIdEvent) {
|
||||||
params.versionID = dataLines[0]
|
params.versionID = dataLines[0]
|
||||||
projectStore.setProject({ nodeId: dataLines[0] })
|
projectStore.setProject({ nodeId: dataLines[0] })
|
||||||
}
|
}
|
||||||
|
if (event.includes('tool')) {
|
||||||
|
MyEvent.emit('loading-sketch')
|
||||||
|
}
|
||||||
|
|
||||||
if (dataLines.length === 0) continue
|
if (dataLines.length === 0) continue
|
||||||
const jsonText = dataLines.join('\n')
|
const jsonText = dataLines.join('\n')
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const jsonData = JSON.parse(jsonText)
|
const jsonData = JSON.parse(jsonText)
|
||||||
// console.log('jsonData', jsonData)
|
console.log('jsonData', jsonData)
|
||||||
|
|
||||||
// 赋值 project_id 和 version_id
|
// 赋值 project_id 和 version_id
|
||||||
// if (jsonData.project_id) params.projectID = jsonData.project_id
|
// if (jsonData.project_id) params.projectID = jsonData.project_id
|
||||||
@@ -371,9 +382,9 @@
|
|||||||
while (i < dialogue.length) {
|
while (i < dialogue.length) {
|
||||||
const item = dialogue[i]
|
const item = dialogue[i]
|
||||||
|
|
||||||
if (item.image_url) {
|
// if (item.image_url) {
|
||||||
existingImgList.push(item.image_url)
|
// existingImgList.push(item.image_url)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (item.role === 'user') {
|
if (item.role === 'user') {
|
||||||
// user 角色直接添加
|
// user 角色直接添加
|
||||||
@@ -391,9 +402,9 @@
|
|||||||
// 继续往后找连续的 assistant 消息
|
// 继续往后找连续的 assistant 消息
|
||||||
let j = i + 1
|
let j = i + 1
|
||||||
while (j < dialogue.length && dialogue[j].role === 'assistant') {
|
while (j < dialogue.length && dialogue[j].role === 'assistant') {
|
||||||
if (dialogue[j].image_url) {
|
// if (dialogue[j].image_url) {
|
||||||
existingImgList.push(dialogue[j].image_url)
|
// existingImgList.push(dialogue[j].image_url)
|
||||||
}
|
// }
|
||||||
combinedContent += dialogue[j].content || ''
|
combinedContent += dialogue[j].content || ''
|
||||||
j++
|
j++
|
||||||
}
|
}
|
||||||
@@ -448,11 +459,14 @@
|
|||||||
|
|
||||||
const { ancestors, current } = data
|
const { ancestors, current } = data
|
||||||
|
|
||||||
const imgList = []
|
let imgList = []
|
||||||
const ancestorsList = []
|
const ancestorsList = []
|
||||||
let ancestorsIdCounter = 1
|
let ancestorsIdCounter = 1
|
||||||
if (ancestors) {
|
if (ancestors) {
|
||||||
ancestors.forEach((item) => {
|
ancestors.forEach((item) => {
|
||||||
|
if (item.sketchIDAndUrl) {
|
||||||
|
imgList = imgList.concat(item.sketchIDAndUrl)
|
||||||
|
}
|
||||||
const list = processDialogue(item.dialogue, 0, imgList)
|
const list = processDialogue(item.dialogue, 0, imgList)
|
||||||
// 重新设置 id
|
// 重新设置 id
|
||||||
list.forEach((el) => {
|
list.forEach((el) => {
|
||||||
@@ -462,18 +476,19 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
const currentList = processDialogue(current?.dialogue, 0, imgList)
|
const currentList = processDialogue(current?.dialogue, 0, imgList)
|
||||||
// 重新设置 id
|
if (current.sketchIDAndUrl) {
|
||||||
|
imgList = imgList.concat(current.sketchIDAndUrl)
|
||||||
|
}
|
||||||
|
|
||||||
currentList.forEach((el, index) => {
|
currentList.forEach((el, index) => {
|
||||||
el.id = index + 1 + ancestorsList.length
|
el.id = index + 1 + ancestorsList.length
|
||||||
})
|
})
|
||||||
|
|
||||||
// 延迟设置新数据,确保 UI 有时间响应清空操作
|
// 延迟设置新数据,确保 UI 有时间响应清空操作
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
|
|
||||||
messageList.value = [...ancestorsList, ...currentList]
|
messageList.value = [...ancestorsList, ...currentList]
|
||||||
params.versionID = current?.id
|
params.versionID = current?.id
|
||||||
sketchList.value = imgList
|
sketchList.value = imgList
|
||||||
console.log('11111111111111',params.versionID);
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,34 @@
|
|||||||
v-for="(item, index) in sketchList"
|
v-for="(item, index) in sketchList"
|
||||||
:key="'sketch-item-' + index"
|
:key="'sketch-item-' + index"
|
||||||
>
|
>
|
||||||
<Menu class="menu-btn" @click="handleClickMenu" />
|
<el-dropdown trigger="click" class="menu-btn">
|
||||||
<div class="edit-btn flex align-center space-between" @click="handleClickEdit">
|
<Menu />
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item class="sketch-item flex align-center">
|
||||||
|
<img
|
||||||
|
src="@/assets/images/restore-sketch.png"
|
||||||
|
class="dropdown-icon restore"
|
||||||
|
/>
|
||||||
|
<span>Restore</span>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
class="sketch-item flex align-center"
|
||||||
|
@click="handleClickDelete(item)"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src="@/assets/images/delete.png"
|
||||||
|
class="dropdown-icon delete"
|
||||||
|
/>
|
||||||
|
<span>Delete</span>
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
|
<div
|
||||||
|
class="edit-btn flex align-center space-between"
|
||||||
|
@click="handleClickEdit(item)"
|
||||||
|
>
|
||||||
<div>Edit</div>
|
<div>Edit</div>
|
||||||
<img src="@/assets/images/arrow-top-right.png" />
|
<img src="@/assets/images/arrow-top-right.png" />
|
||||||
</div>
|
</div>
|
||||||
@@ -20,6 +46,9 @@
|
|||||||
@load="handleImageLoad(index)"
|
@load="handleImageLoad(index)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-show="showLoading" class="sketch-item loading-gif">
|
||||||
|
<img src="@/assets/images/sketch-loading.gif" alt="loading" />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-else class="reportBorder">
|
<div v-else class="reportBorder">
|
||||||
<div class="report">
|
<div class="report">
|
||||||
@@ -120,13 +149,20 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive } from 'vue'
|
import { ref, reactive, onMounted, onUnmounted, watch } from 'vue'
|
||||||
import Menu from './Menu.vue'
|
import Menu from './Menu.vue'
|
||||||
import LoadingImg from '@/assets/images/sketch-loading.gif'
|
import LoadingImg from '@/assets/images/sketch-loading.gif'
|
||||||
import reportNull from '@/assets/images/reportNull.png'
|
import reportNull from '@/assets/images/reportNull.png'
|
||||||
|
import myEvent from '@/utils/myEvent'
|
||||||
|
import { deleteSketchFlowCanvas } from '@/api/flow-canvas'
|
||||||
|
import { useProjectStore } from '@/stores'
|
||||||
|
const projectStore = useProjectStore()
|
||||||
|
import MyEvent from '@/utils/myEvent'
|
||||||
|
|
||||||
|
const emits = defineEmits(['deleteSketch'])
|
||||||
|
|
||||||
// 存储每个图片的加载状态
|
// 存储每个图片的加载状态
|
||||||
const loadedStatus = reactive<Record<number, boolean>>({})
|
const loadedStatus = ref<boolean>(false)
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
@@ -142,21 +178,72 @@
|
|||||||
// 图片加载完成时触发
|
// 图片加载完成时触发
|
||||||
const handleImageLoad = (index: number) => {
|
const handleImageLoad = (index: number) => {
|
||||||
loadedStatus[index] = true
|
loadedStatus[index] = true
|
||||||
|
if (index === props.sketchList.length - 1) {
|
||||||
|
showLoading.value = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取当前显示的图片源
|
// 获取当前显示的图片源
|
||||||
const getImageSrc = (item: string, index: number) => {
|
const getImageSrc = (item: string, index: number) => {
|
||||||
return loadedStatus[index] ? item : LoadingImg
|
if (item === null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
if (typeof item === 'string') {
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
if (typeof item === 'object') {
|
||||||
|
return Object.values(item)[0]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleClickEdit = () => {
|
const handleClickEdit = (item: string | Object) => {
|
||||||
// 编辑按钮点击逻辑
|
let url = ''
|
||||||
console.log('Edit button clicked')
|
let imgId = ''
|
||||||
|
let nodeId = ''
|
||||||
|
if (typeof item === 'string') {
|
||||||
|
url = item
|
||||||
|
}
|
||||||
|
if (typeof item === 'object') {
|
||||||
|
url = Object.values(item)[0]
|
||||||
|
imgId = Object.keys(item)[0]
|
||||||
|
nodeId = projectStore.state.nodeId
|
||||||
|
}
|
||||||
|
myEvent.emit('openFlowCanvas', { url, imgId, nodeId })
|
||||||
}
|
}
|
||||||
const handleClickMenu = () => {
|
|
||||||
// 菜单按钮点击逻辑
|
const handleClickDelete = (item: string | Object) => {
|
||||||
console.log('Menu button clicked')
|
deleteSketchFlowCanvas({
|
||||||
|
id: Object.keys(item)[0],
|
||||||
|
versionNodeId: projectStore.state.nodeId
|
||||||
|
}).then((res) => {
|
||||||
|
if (res) {
|
||||||
|
ElMessage.success('Delete success')
|
||||||
|
emits('deleteSketch', Object.keys(item)[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const showLoading = ref(false)
|
||||||
|
const handleLoadingSketch = () => {
|
||||||
|
showLoading.value = true
|
||||||
|
}
|
||||||
|
watch(
|
||||||
|
() => props.sketchList,
|
||||||
|
(val) => {
|
||||||
|
console.log('-sketchList-', val)
|
||||||
|
|
||||||
|
if (val.length > 0) {
|
||||||
|
showLoading.value = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
)
|
||||||
|
onMounted(() => {
|
||||||
|
MyEvent.add('loading-sketch', handleLoadingSketch)
|
||||||
|
})
|
||||||
|
onUnmounted(() => {
|
||||||
|
MyEvent.remove('loading-sketch', handleLoadingSketch)
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
@@ -178,10 +265,21 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
border-radius: 1.6rem;
|
border-radius: 1.6rem;
|
||||||
}
|
}
|
||||||
.menu-btn {
|
:deep(.menu-btn) {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 2.1rem;
|
top: 2.1rem;
|
||||||
right: 1.5rem;
|
right: 1.5rem;
|
||||||
|
|
||||||
|
.dropdown-icon {
|
||||||
|
&.restore {
|
||||||
|
width: 1.4rem;
|
||||||
|
height: 1.3rem;
|
||||||
|
}
|
||||||
|
&.delete {
|
||||||
|
width: 1.2rem;
|
||||||
|
height: 1.3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.edit-btn {
|
.edit-btn {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -274,4 +372,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
:deep(.el-dropdown-menu__item) {
|
||||||
|
column-gap: 1.2rem;
|
||||||
|
padding: 1.2rem 1.4rem;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<div class="content-wrapper">
|
<div class="content-wrapper">
|
||||||
<Agent ref="agentRef" :title="agentTitle" @update:sketchList="updateSketchList" />
|
<Agent ref="agentRef" :title="agentTitle" @update:sketchList="updateSketchList" />
|
||||||
<div class="preview-wrapper">
|
<div class="preview-wrapper">
|
||||||
<Preview :type="previewType" :sketchList="sketchList" />
|
<Preview :type="previewType" :sketchList="sketchList" @deleteSketch="handleDeleteSketch" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<VersionTreeIndex
|
<VersionTreeIndex
|
||||||
@@ -41,6 +41,15 @@
|
|||||||
// VersionTreeIndexRef.value.getVersionTree()
|
// VersionTreeIndexRef.value.getVersionTree()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleDeleteSketch = (deletedId: string) => {
|
||||||
|
sketchList.value = sketchList.value.filter((item) => {
|
||||||
|
if (typeof item === 'object') {
|
||||||
|
return Object.keys(item)[0] !== deletedId
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const versionTreeData = ref({
|
const versionTreeData = ref({
|
||||||
drawer: false
|
drawer: false
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="editor-wrapper">
|
<div class="editor-wrapper">
|
||||||
<!-- 静态占位符 - 当编辑器为空时显示 -->
|
|
||||||
<div v-if="showPlaceholder" class="editor-placeholder">
|
<div v-if="showPlaceholder" class="editor-placeholder">
|
||||||
{{ $t('Input.placeholder') }}
|
{{ $t('Input.placeholder') }}
|
||||||
</div>
|
</div>
|
||||||
@@ -506,8 +505,9 @@
|
|||||||
|
|
||||||
let node: Node | null
|
let node: Node | null
|
||||||
while ((node = walker.nextNode())) {
|
while ((node = walker.nextNode())) {
|
||||||
if (node.parentElement?.classList.contains('custom-placeholder')) continue
|
// 使用 closest() 检查当前节点的祖先元素是否包含需要排除的 class
|
||||||
if (node.parentElement?.classList.contains('editor-tag')) continue
|
if (node.parentElement?.closest('.custom-placeholder')) continue
|
||||||
|
if (node.parentElement?.closest('.editor-tag')) continue
|
||||||
text += node.textContent
|
text += node.textContent
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -732,14 +732,15 @@
|
|||||||
)
|
)
|
||||||
|
|
||||||
const handleCreateProject = async () => {
|
const handleCreateProject = async () => {
|
||||||
// 这里可以添加创建项目的逻辑
|
|
||||||
if (!inputValue.value.trim()) {
|
if (!inputValue.value.trim()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
type: typeValue.value,
|
type: typeValue.value,
|
||||||
area: areaValue.value,
|
area: areaValue.value,
|
||||||
style: styleValue.value,
|
style: styleValue.value,
|
||||||
|
useReport: reportTags.value.length > 0,
|
||||||
temperature: 0.7
|
temperature: 0.7
|
||||||
}
|
}
|
||||||
const projectres = await createProject(params)
|
const projectres = await createProject(params)
|
||||||
@@ -1035,7 +1036,7 @@
|
|||||||
min-height: 5rem;
|
min-height: 5rem;
|
||||||
line-height: 1.4rem;
|
line-height: 1.4rem;
|
||||||
}
|
}
|
||||||
.editor-placeholder{
|
.editor-placeholder {
|
||||||
font-family: 'Regular';
|
font-family: 'Regular';
|
||||||
font-size: 1.4rem;
|
font-size: 1.4rem;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user