Merge branch 'main' of ssh://18.167.251.121:10002/aidlab/FiDA_Front
This commit is contained in:
@@ -15,7 +15,7 @@
|
|||||||
import { computed, ref, markRaw, onMounted, reactive, nextTick } from 'vue'
|
import { computed, ref, markRaw, onMounted, reactive, nextTick } from 'vue'
|
||||||
const dialogVisible = ref(true)
|
const dialogVisible = ref(true)
|
||||||
const config = ref({
|
const config = ref({
|
||||||
url: '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__'
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|||||||
@@ -15,13 +15,13 @@
|
|||||||
<span class="icon"><svg-icon name="export" size="12" /></span>
|
<span class="icon"><svg-icon name="export" size="12" /></span>
|
||||||
<span class="text">Export</span>
|
<span class="text">Export</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="export" @click="emit('export-local')">
|
<!-- <button class="export" @click="emit('export-local')">
|
||||||
<span class="text">保存本地</span>
|
<span class="text">保存本地</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="export" @click="emit('import-local')">
|
<button class="export" @click="emit('import-local')">
|
||||||
<span class="text">本地导入</span>
|
<span class="text">本地导入</span>
|
||||||
</button>
|
</button> -->
|
||||||
<button class="workbench" @click="emit('export-close')">
|
<button class="workbench" @click="onWorkbench">
|
||||||
<span class="icon"><svg-icon name="dc-workbench" size="20" /></span>
|
<span class="icon"><svg-icon name="dc-workbench" size="20" /></span>
|
||||||
<span class="text">Workbench</span>
|
<span class="text">Workbench</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -30,16 +30,18 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, inject, computed } from 'vue'
|
import { ref, inject, computed } from 'vue'
|
||||||
|
import { exportCanvasToImage } from '../tools/exportMethod'
|
||||||
import { OperationType } from '../tools/layerHelper'
|
import { OperationType } from '../tools/layerHelper'
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
zoom: { default: 1, type: Number },
|
zoom: { default: 1, type: Number },
|
||||||
step: { default: 0.1, type: Number }
|
step: { default: 0.1, type: Number }
|
||||||
})
|
})
|
||||||
const emit = defineEmits(['export', 'export-local', 'import-local', 'export-close'])
|
const emit = defineEmits(['export', 'export-local', 'import-local', 'export-close', 'workbench'])
|
||||||
const importLocalImage = inject('importLocalImage') as (isRecord?: boolean) => void
|
const importLocalImage = inject('importLocalImage') as (isRecord?: boolean) => void
|
||||||
const stateManager = inject('stateManager') as any
|
const stateManager = inject('stateManager') as any
|
||||||
const toolManager = inject('toolManager') as any
|
const toolManager = inject('toolManager') as any
|
||||||
const objectManager = inject('objectManager') as any
|
const objectManager = inject('objectManager') as any
|
||||||
|
const canvasManager = inject('canvasManager') as any
|
||||||
const tool = computed(() => toolManager.currentTool.value)
|
const tool = computed(() => toolManager.currentTool.value)
|
||||||
const historyIndex = computed(() => stateManager.historyIndex.value)
|
const historyIndex = computed(() => stateManager.historyIndex.value)
|
||||||
const historyList = computed(() => stateManager.historyList.value)
|
const historyList = computed(() => stateManager.historyList.value)
|
||||||
@@ -87,6 +89,11 @@
|
|||||||
const layer = await importLocalImage(false)
|
const layer = await importLocalImage(false)
|
||||||
objectManager.setFillRepeat(layer?.info?.id)
|
objectManager.setFillRepeat(layer?.info?.id)
|
||||||
}
|
}
|
||||||
|
const onWorkbench = async () => {
|
||||||
|
exportCanvasToImage(canvasManager.canvas).then((url) => {
|
||||||
|
emit('workbench', { url })
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
@export="exportCanvas"
|
@export="exportCanvas"
|
||||||
@export-local="exportCanvasToLocalStorage"
|
@export-local="exportCanvasToLocalStorage"
|
||||||
@import-local="importCanvasFromLocalStorage"
|
@import-local="importCanvasFromLocalStorage"
|
||||||
@export-close="exportCanvasAndClose"
|
@workbench="(v) => emit('workbench', v)"
|
||||||
/>
|
/>
|
||||||
<brush-control-panel :currentTool="toolManager.currentTool.value" />
|
<brush-control-panel :currentTool="toolManager.currentTool.value" />
|
||||||
<zoom
|
<zoom
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
import { KeyEventManager } from './manager/events/KeyEventManager'
|
import { KeyEventManager } from './manager/events/KeyEventManager'
|
||||||
import { ObjectManager } from './manager/ObjectManager'
|
import { ObjectManager } from './manager/ObjectManager'
|
||||||
|
|
||||||
const emit = defineEmits(['close'])
|
const emit = defineEmits(['workbench', 'close'])
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
config: {
|
config: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -87,13 +87,15 @@
|
|||||||
provide('objectManager', objectManager)
|
provide('objectManager', objectManager)
|
||||||
|
|
||||||
const observer = ref(null)
|
const observer = ref(null)
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
canvasManager.initCanvas({
|
keyEventManager.registerEvents()
|
||||||
|
await canvasManager.initCanvas({
|
||||||
canvasRef,
|
canvasRef,
|
||||||
canvasViewWidth: canvasContainerRef.value.clientWidth,
|
canvasViewWidth: canvasContainerRef.value.clientWidth,
|
||||||
canvasViewHeight: canvasContainerRef.value.clientHeight,
|
canvasViewHeight: canvasContainerRef.value.clientHeight,
|
||||||
canvasWidth: 750,
|
canvasWidth: props.config.width || 750,
|
||||||
canvasHeight: 600
|
canvasHeight: props.config.height || 600,
|
||||||
|
url: props.config.url || ''
|
||||||
})
|
})
|
||||||
stateManager.onMounted()
|
stateManager.onMounted()
|
||||||
canvasManager.onMounted()
|
canvasManager.onMounted()
|
||||||
@@ -128,7 +130,7 @@
|
|||||||
canvasViewWidth: canvasContainerRef.value.clientWidth,
|
canvasViewWidth: canvasContainerRef.value.clientWidth,
|
||||||
canvasViewHeight: canvasContainerRef.value.clientHeight
|
canvasViewHeight: canvasContainerRef.value.clientHeight
|
||||||
})
|
})
|
||||||
canvasManager.resetZoom()
|
canvasManager.resetZoom(true, true)
|
||||||
}
|
}
|
||||||
/** 导入本地图片 */
|
/** 导入本地图片 */
|
||||||
const importLocalImage = (isRecord = true) => {
|
const importLocalImage = (isRecord = true) => {
|
||||||
@@ -181,10 +183,6 @@
|
|||||||
stateManager.clearState(true)
|
stateManager.clearState(true)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 导出画布并关闭
|
|
||||||
const exportCanvasAndClose = () => {
|
|
||||||
emit('close')
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@import '@vue-flow/core/dist/style.css';
|
@import '@vue-flow/core/dist/style.css';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<fullscreen-dialog v-model="dialogVisible" hide-destroy>
|
<fullscreen-dialog v-model="dialogVisible" @close="onClose" hide-destroy>
|
||||||
<div class="canvas-box">
|
<div class="canvas-box">
|
||||||
<depth-canvas :config="config" @close="close" />
|
<depth-canvas :config="config" @workbench="onWorkbench" @close="onClose" />
|
||||||
</div>
|
</div>
|
||||||
</fullscreen-dialog>
|
</fullscreen-dialog>
|
||||||
</template>
|
</template>
|
||||||
@@ -11,14 +11,26 @@
|
|||||||
import depthCanvas from './depth-canvas.vue'
|
import depthCanvas from './depth-canvas.vue'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
const dialogVisible = ref(false)
|
const dialogVisible = ref(false)
|
||||||
const config = ref({})
|
const config = ref({
|
||||||
|
id: '',
|
||||||
|
url: ''
|
||||||
|
})
|
||||||
|
|
||||||
const open = (options) => {
|
const open = (options) => {
|
||||||
|
config.value = options
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
config.value = options || {}
|
|
||||||
}
|
}
|
||||||
const close = () => {
|
// 工作区
|
||||||
|
const onWorkbench = (options) => {
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
|
config.value.onWorkbench?.(options)
|
||||||
}
|
}
|
||||||
|
// 关闭
|
||||||
|
const onClose = () => {
|
||||||
|
dialogVisible.value = false
|
||||||
|
config.value.onClose?.()
|
||||||
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
open,
|
open,
|
||||||
close
|
close
|
||||||
|
|||||||
@@ -286,14 +286,19 @@ export class AnimationManager {
|
|||||||
/**
|
/**
|
||||||
* 重置缩放(带平滑动画)
|
* 重置缩放(带平滑动画)
|
||||||
* @param {Boolean} animated 是否使用动画
|
* @param {Boolean} animated 是否使用动画
|
||||||
|
* @param {Boolean} adaptive 是否自适应缩放
|
||||||
*/
|
*/
|
||||||
async resetZoom(animated = true) {
|
async resetZoom(animated = true, adaptive = false) {
|
||||||
const canvasViewWidth = this.canvasManager.canvasViewWidth;
|
const canvasViewWidth = this.canvasManager.canvasViewWidth;
|
||||||
const canvasViewHeight = this.canvasManager.canvasViewHeight;
|
const canvasViewHeight = this.canvasManager.canvasViewHeight;
|
||||||
const canvasWidth = this.canvasManager.canvasWidth;
|
const canvasWidth = this.canvasManager.canvasWidth;
|
||||||
const canvasHeight = this.canvasManager.canvasHeight;
|
const canvasHeight = this.canvasManager.canvasHeight;
|
||||||
const panX = canvasViewWidth / 2 - canvasWidth / 2
|
const scaleX = canvasViewWidth / canvasWidth * 0.8
|
||||||
const panY = canvasViewHeight / 2 - canvasHeight / 2
|
const scaleY = canvasViewHeight / canvasHeight * 0.8
|
||||||
|
const scale = Math.min(scaleX, scaleY, 1)
|
||||||
|
const panX = canvasViewWidth / 2 - canvasWidth * scale / 2
|
||||||
|
const panY = canvasViewHeight / 2 - canvasHeight * scale / 2
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
if (animated) {
|
if (animated) {
|
||||||
// 停止任何进行中的动画
|
// 停止任何进行中的动画
|
||||||
@@ -322,7 +327,7 @@ export class AnimationManager {
|
|||||||
|
|
||||||
// 使用GSAP同时动画缩放和平移
|
// 使用GSAP同时动画缩放和平移
|
||||||
gsap.to(viewTransform, {
|
gsap.to(viewTransform, {
|
||||||
zoom: 1,
|
zoom: scale,
|
||||||
panX: panX,
|
panX: panX,
|
||||||
panY: panY,
|
panY: panY,
|
||||||
duration: 0.5,
|
duration: 0.5,
|
||||||
@@ -342,16 +347,16 @@ export class AnimationManager {
|
|||||||
},
|
},
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
// 确保最终状态准确
|
// 确保最终状态准确
|
||||||
this.canvas.setViewportTransform([1, 0, 0, 1, panX, panY]);
|
this.canvas.setViewportTransform([scale, 0, 0, scale, panX, panY]);
|
||||||
this.currentZoom.value = 100;
|
this.currentZoom.value = scale * 100;
|
||||||
this._zoomAnimation = null;
|
this._zoomAnimation = null;
|
||||||
this._panAnimation = null;
|
this._panAnimation = null;
|
||||||
resolve();
|
resolve();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.canvas.setViewportTransform([1, 0, 0, 1, panX, panY]);
|
this.canvas.setViewportTransform([scale, 0, 0, scale, panX, panY]);
|
||||||
this.currentZoom.value = 100;
|
this.currentZoom.value = scale * 100;
|
||||||
resolve();
|
resolve();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { AnimationManager } from './AnimationManager'
|
|||||||
import { detectDeviceType } from '../tools/index'
|
import { detectDeviceType } from '../tools/index'
|
||||||
import { CanvasEventManager } from "./events/CanvasEventManager";
|
import { CanvasEventManager } from "./events/CanvasEventManager";
|
||||||
import { OperationType } from '../tools/layerHelper'
|
import { OperationType } from '../tools/layerHelper'
|
||||||
|
import { createId } from '../../tools/tools'
|
||||||
|
|
||||||
// 自定义画布转对象属性
|
// 自定义画布转对象属性
|
||||||
fabric.Object.prototype.customProperties = ["top", "left", "width", "height", "scaleX", "scaleY", "info", "thumbnail"];
|
fabric.Object.prototype.customProperties = ["top", "left", "width", "height", "scaleX", "scaleY", "info", "thumbnail"];
|
||||||
@@ -28,6 +29,7 @@ interface CanvasInitOptions {
|
|||||||
canvasViewHeight?: number
|
canvasViewHeight?: number
|
||||||
canvasWidth?: number
|
canvasWidth?: number
|
||||||
canvasHeight?: number
|
canvasHeight?: number
|
||||||
|
url?: string
|
||||||
}
|
}
|
||||||
export class CanvasManager {
|
export class CanvasManager {
|
||||||
stateManager: any
|
stateManager: any
|
||||||
@@ -63,17 +65,36 @@ export class CanvasManager {
|
|||||||
enableRetinaScaling: true,
|
enableRetinaScaling: true,
|
||||||
backgroundColor: '#fff',
|
backgroundColor: '#fff',
|
||||||
})
|
})
|
||||||
|
if (options.url) {
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
fabric.Image.fromURL(options.url, async (img) => {
|
||||||
|
this.canvasWidth = img.width
|
||||||
|
this.canvasHeight = img.height
|
||||||
this.setCanvasViewSize(options)
|
this.setCanvasViewSize(options)
|
||||||
|
img.set({
|
||||||
|
left: 0,
|
||||||
|
top: 0,
|
||||||
|
scaleX: 1,
|
||||||
|
scaleY: 1,
|
||||||
|
info: {
|
||||||
|
id: createId("image"),
|
||||||
|
name: "图片图层",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.canvas.add(img)
|
||||||
|
await this.layerManager.updateLayerThumbnailsById(img.info.id)
|
||||||
|
resolve(img)
|
||||||
|
}, { crossOrigin: 'anonymous' })
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.setCanvasViewSize(options)
|
||||||
|
}
|
||||||
this.canvas.clipPath = new fabric.Rect({
|
this.canvas.clipPath = new fabric.Rect({
|
||||||
left: 0,
|
left: 0,
|
||||||
top: 0,
|
top: 0,
|
||||||
width: this.canvasWidth,
|
width: this.canvasWidth,
|
||||||
height: this.canvasHeight
|
height: this.canvasHeight
|
||||||
})
|
})
|
||||||
// 画布居中
|
|
||||||
const canvasX = this.canvasViewWidth / 2 - this.canvasWidth / 2
|
|
||||||
const canvasY = this.canvasViewHeight / 2 - this.canvasHeight / 2
|
|
||||||
this.canvas.viewportTransform = [1, 0, 0, 1, canvasX, canvasY]
|
|
||||||
|
|
||||||
// 动画管理器
|
// 动画管理器
|
||||||
this.animationManager = new AnimationManager(this.canvas, {
|
this.animationManager = new AnimationManager(this.canvas, {
|
||||||
@@ -83,26 +104,31 @@ export class CanvasManager {
|
|||||||
defaultEase: "power2.lin",
|
defaultEase: "power2.lin",
|
||||||
defaultDuration: 0.3, // 缩短默认动画时间
|
defaultDuration: 0.3, // 缩短默认动画时间
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setupCanvasEvents()
|
this.setupCanvasEvents()
|
||||||
this.setupBrushEvents()
|
this.setupBrushEvents()
|
||||||
|
|
||||||
|
/** 测试-开始 */
|
||||||
|
// this.stateManager.setIsRecord(false)
|
||||||
|
// // 创建矩形
|
||||||
|
// const rect = await this.layerManager.createRectLayer({
|
||||||
|
// left: 400,
|
||||||
|
// top: 100,
|
||||||
|
// })
|
||||||
|
// //创建圆形
|
||||||
|
// const circle = await this.layerManager.createCircleLayer({
|
||||||
|
// left: 200,
|
||||||
|
// top: 200,
|
||||||
|
// })
|
||||||
|
// // 文字
|
||||||
|
// const text = await this.layerManager.createTextLayer('Hello World');
|
||||||
|
// this.layerManager.setActiveID(text.info.id)
|
||||||
|
// this.stateManager.setIsRecord(true)
|
||||||
|
/** 测试-结束 */
|
||||||
|
|
||||||
|
this.resetZoom(false, true)// 画布居中
|
||||||
|
|
||||||
this.stateManager.setIsRecord(false)
|
|
||||||
// 创建矩形
|
|
||||||
const rect = await this.layerManager.createRectLayer({
|
|
||||||
left: 400,
|
|
||||||
top: 100,
|
|
||||||
})
|
|
||||||
//创建圆形
|
|
||||||
const circle = await this.layerManager.createCircleLayer({
|
|
||||||
left: 200,
|
|
||||||
top: 200,
|
|
||||||
})
|
|
||||||
// 文字
|
|
||||||
const text = await this.layerManager.createTextLayer('Hello World');
|
|
||||||
this.layerManager.updateLayers()
|
this.layerManager.updateLayers()
|
||||||
this.layerManager.setActiveID(text.info.id)
|
|
||||||
this.stateManager.setIsRecord(true)
|
|
||||||
this.stateManager.recordState()
|
this.stateManager.recordState()
|
||||||
// this.stateManager.toolManager.setTool(OperationType.RECTANGLE)
|
// this.stateManager.toolManager.setTool(OperationType.RECTANGLE)
|
||||||
}
|
}
|
||||||
@@ -145,8 +171,8 @@ export class CanvasManager {
|
|||||||
if (obj) this.canvas.setActiveObject(obj)
|
if (obj) this.canvas.setActiveObject(obj)
|
||||||
this.renderAll()
|
this.renderAll()
|
||||||
}
|
}
|
||||||
resetZoom() {
|
resetZoom(animated = true, adaptive = true) {
|
||||||
this.animationManager.resetZoom()
|
this.animationManager.resetZoom(animated, adaptive)
|
||||||
}
|
}
|
||||||
// 使用动画管理器的缩放方法
|
// 使用动画管理器的缩放方法
|
||||||
animateZoom(point, targetZoom, options = {}) {
|
animateZoom(point, targetZoom, options = {}) {
|
||||||
@@ -245,7 +271,6 @@ export class CanvasManager {
|
|||||||
this.renderAll()
|
this.renderAll()
|
||||||
callback?.(true)
|
callback?.(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
dispose() {
|
dispose() {
|
||||||
this.animationManager?.dispose()
|
this.animationManager?.dispose()
|
||||||
|
|||||||
@@ -2,11 +2,12 @@ export class KeyEventManager {
|
|||||||
stateManager: any
|
stateManager: any
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
this.stateManager = options.stateManager;
|
this.stateManager = options.stateManager;
|
||||||
this.registerEvents()
|
this._handleKeyDown = this.handleKeyDown.bind(this)
|
||||||
}
|
}
|
||||||
onMounted() { }
|
onMounted() { }
|
||||||
|
|
||||||
/** 处理键盘事件 */
|
/** 处理键盘事件 */
|
||||||
|
_handleKeyDown: any
|
||||||
handleKeyDown(event: any) {
|
handleKeyDown(event: any) {
|
||||||
const ctrl = event.ctrlKey ? 'ctrl-' : "";
|
const ctrl = event.ctrlKey ? 'ctrl-' : "";
|
||||||
const shift = event.shiftKey ? 'shift-' : "";
|
const shift = event.shiftKey ? 'shift-' : "";
|
||||||
@@ -24,11 +25,11 @@ export class KeyEventManager {
|
|||||||
}
|
}
|
||||||
/** 注册事件 */
|
/** 注册事件 */
|
||||||
registerEvents() {
|
registerEvents() {
|
||||||
document.addEventListener('keydown', this.handleKeyDown.bind(this))
|
document.addEventListener('keydown', this._handleKeyDown)
|
||||||
}
|
}
|
||||||
/** 删除事件 */
|
/** 删除事件 */
|
||||||
removeEvents() {
|
removeEvents() {
|
||||||
document.removeEventListener('keydown', this.handleKeyDown.bind(this))
|
document.removeEventListener('keydown', this._handleKeyDown)
|
||||||
}
|
}
|
||||||
dispose() {
|
dispose() {
|
||||||
this.removeEvents()
|
this.removeEvents()
|
||||||
|
|||||||
@@ -15,9 +15,9 @@
|
|||||||
<span class="icon"><svg-icon name="export" size="11" /></span>
|
<span class="icon"><svg-icon name="export" size="11" /></span>
|
||||||
<span class="text">Export</span>
|
<span class="text">Export</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="import" @click="emit('import')">
|
<!-- <button class="import" @click="emit('import')">
|
||||||
<span class="text">Import</span>
|
<span class="text">Import</span>
|
||||||
</button>
|
</button> -->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -153,6 +153,7 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
stateManager.recordState()
|
||||||
// } else {
|
// } else {
|
||||||
// subordNode.data.data.url =
|
// subordNode.data.data.url =
|
||||||
// 'https://s3-alpha-sig.figma.com/img/8ce2/f1a4/12b93da90e5f17109e7430f14837fd14?Expires=1773619200&Key-Pair-Id=APKAQ4GOSFWCW27IBOMQ&Signature=kmLsTFtXJqfvuxj6husWlDkRDMOIRDjzUUjb7zh79GkBKihUHc0f59k5OAImHTPdaiEREUCCpn~8sQ-si5lenuauJpApCmAU~NsxjfQhuh9m5O~GiHenr2fKu0DIJ75-oCE3859fyxoSFXQgZ9PRmeb98kikMR6uRX9nI5TPUHgKO8ZgkhDBTW~iyaDT~1ybnoK7elPa6T2VzfO-bpIyY-MZ71VRq3RxwmZRxduqHEb3Dh-jjrHyh2SoQsHmUjSJOf-uYilfvpGUResZAjAq8ZVLEjvhzKC2bmCNZIp3RmhYO8ctU7pd5t91J6Xaa6jBLtGfMxbqIm652EC79K0RoA__'
|
// 'https://s3-alpha-sig.figma.com/img/8ce2/f1a4/12b93da90e5f17109e7430f14837fd14?Expires=1773619200&Key-Pair-Id=APKAQ4GOSFWCW27IBOMQ&Signature=kmLsTFtXJqfvuxj6husWlDkRDMOIRDjzUUjb7zh79GkBKihUHc0f59k5OAImHTPdaiEREUCCpn~8sQ-si5lenuauJpApCmAU~NsxjfQhuh9m5O~GiHenr2fKu0DIJ75-oCE3859fyxoSFXQgZ9PRmeb98kikMR6uRX9nI5TPUHgKO8ZgkhDBTW~iyaDT~1ybnoK7elPa6T2VzfO-bpIyY-MZ71VRq3RxwmZRxduqHEb3Dh-jjrHyh2SoQsHmUjSJOf-uYilfvpGUResZAjAq8ZVLEjvhzKC2bmCNZIp3RmhYO8ctU7pd5t91J6Xaa6jBLtGfMxbqIm652EC79K0RoA__'
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<span class="icon" @click="onDownload(item?.url)">
|
<span class="icon" @click="onDownload(item?.url)">
|
||||||
<svg-icon name="download" size="20" size-unit="px" />
|
<svg-icon name="download" size="20" size-unit="px" />
|
||||||
</span>
|
</span>
|
||||||
<button class="edit" @click="onEdit(item?.url)">
|
<button class="edit" @click="onEdit(item)">
|
||||||
<span class="icon"><svg-icon name="edit" size="13" /></span>
|
<span class="icon"><svg-icon name="edit" size="13" /></span>
|
||||||
<span class="text">Edit</span>
|
<span class="text">Edit</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -90,6 +90,7 @@
|
|||||||
const showMenu = ref(false)
|
const showMenu = ref(false)
|
||||||
const clickTaskId = ref('')
|
const clickTaskId = ref('')
|
||||||
const generateManager = inject('generateManager') as any
|
const generateManager = inject('generateManager') as any
|
||||||
|
const stateManager = inject('stateManager') as any
|
||||||
const clickimageProcessTaskItem = (taskId: string) => {
|
const clickimageProcessTaskItem = (taskId: string) => {
|
||||||
if(clickTaskId.value == taskId){
|
if(clickTaskId.value == taskId){
|
||||||
showMenu.value = !showMenu.value
|
showMenu.value = !showMenu.value
|
||||||
@@ -158,6 +159,7 @@
|
|||||||
}
|
}
|
||||||
item.scale.x = -item.scale.x
|
item.scale.x = -item.scale.x
|
||||||
})
|
})
|
||||||
|
stateManager.recordState()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -170,10 +172,12 @@
|
|||||||
}
|
}
|
||||||
item.scale.y = -item.scale.y
|
item.scale.y = -item.scale.y
|
||||||
})
|
})
|
||||||
|
stateManager.recordState()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
const onPreview = (url: string) => {
|
const onPreview = (url: string) => {
|
||||||
|
console.log(data.superiorNodeType == NODE_DATATYPE.TO_3D_MODEL)
|
||||||
if(data.superiorNodeType == NODE_DATATYPE.TO_3D_MODEL){
|
if(data.superiorNodeType == NODE_DATATYPE.TO_3D_MODEL){
|
||||||
openThreeModelPreview(url)
|
openThreeModelPreview(url)
|
||||||
}else{
|
}else{
|
||||||
@@ -192,8 +196,8 @@
|
|||||||
showMenu.value = false
|
showMenu.value = false
|
||||||
clickTaskId.value = ''
|
clickTaskId.value = ''
|
||||||
}
|
}
|
||||||
const onEdit = (url: string) => {
|
const onEdit = (item: any) => {
|
||||||
myEvent.emit('openDepthCanvas', { url })
|
myEvent.emit('openDepthCanvas', { url:item.url,id: item.taskId })
|
||||||
}
|
}
|
||||||
document.addEventListener('mousedown', hideMenu)
|
document.addEventListener('mousedown', hideMenu)
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
@@ -269,6 +273,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
cursor: pointer;
|
||||||
&:active {
|
&:active {
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { VueFlow, useVueFlow } from '@vue-flow/core'
|
import { VueFlow, useVueFlow } from '@vue-flow/core'
|
||||||
import { computed, ref, watch, onMounted, nextTick, provide, onBeforeMount } from 'vue'
|
import { computed, ref, watch, onMounted, nextTick, provide, onBeforeUnmount } from 'vue'
|
||||||
import { useLayout } from '@/utils/treeDiagram'
|
import { useLayout } from '@/utils/treeDiagram'
|
||||||
import { NODE_TYPE, NODE_COMPONENT } from './tools/index.d'
|
import { NODE_TYPE, NODE_COMPONENT } from './tools/index.d'
|
||||||
// 组件
|
// 组件
|
||||||
@@ -146,7 +146,7 @@
|
|||||||
const { layout } = useLayout()
|
const { layout } = useLayout()
|
||||||
const index = ref(0)
|
const index = ref(0)
|
||||||
async function layoutGraph(direction) {
|
async function layoutGraph(direction) {
|
||||||
if (props.config.json > 0) return
|
if (props.config.json.length > 0) return
|
||||||
if (index.value > 0) return
|
if (index.value > 0) return
|
||||||
index.value++
|
index.value++
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -187,10 +187,14 @@
|
|||||||
stateManager.sendToBack(id)
|
stateManager.sendToBack(id)
|
||||||
}
|
}
|
||||||
// 导出流程
|
// 导出流程
|
||||||
|
const getFlowJson = () => {
|
||||||
|
if(!stateManager.isSave.value)return ''
|
||||||
|
return JSON.stringify(stateManager.nodes.value)
|
||||||
|
}
|
||||||
const exportFlow = () => {
|
const exportFlow = () => {
|
||||||
// flowManager.exportFlow()
|
// flowManager.exportFlow()
|
||||||
|
const str = getFlowJson()
|
||||||
const str = JSON.stringify(stateManager.nodes.value)
|
stateManager.isSave.value = false
|
||||||
emit('exportFlow', str)
|
emit('exportFlow', str)
|
||||||
// localStorage.setItem('flow_json', str)
|
// localStorage.setItem('flow_json', str)
|
||||||
}
|
}
|
||||||
@@ -227,7 +231,7 @@
|
|||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
// window['vueFlow'] = vueFlow
|
// window['vueFlow'] = vueFlow
|
||||||
// window['nodes'] = nodes
|
// window['nodes'] = nodes
|
||||||
|
eventManager.registerEvents()
|
||||||
if (props.config.json.length > 0) {
|
if (props.config.json.length > 0) {
|
||||||
importFlow(props.config.json)
|
importFlow(props.config.json)
|
||||||
} else {
|
} else {
|
||||||
@@ -252,13 +256,16 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
onBeforeMount(() => {
|
onBeforeUnmount(() => {
|
||||||
stateManager.dispose()
|
stateManager.dispose()
|
||||||
eventManager.dispose()
|
eventManager.dispose()
|
||||||
flowManager.dispose()
|
flowManager.dispose()
|
||||||
nodeManager.dispose()
|
nodeManager.dispose()
|
||||||
toolManager.dispose()
|
toolManager.dispose()
|
||||||
})
|
})
|
||||||
|
defineExpose({
|
||||||
|
getFlowJson
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@import '@vue-flow/core/dist/style.css';
|
@import '@vue-flow/core/dist/style.css';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<fullscreen-dialog v-model="dialogVisible" hide-destroy>
|
<fullscreen-dialog v-model="dialogVisible" @close="close" hide-destroy>
|
||||||
<flow-canvas :config="config" @exportFlow="exportFlow" />
|
<flow-canvas ref="flowCanvasRef" :config="config" @exportFlow="exportFlow" />
|
||||||
</fullscreen-dialog>
|
</fullscreen-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
const dialogVisible = ref(false)
|
const dialogVisible = ref(false)
|
||||||
const config = ref({}) as any
|
const config = ref({}) as any
|
||||||
|
const flowCanvasRef = ref<any>()
|
||||||
const open = async (options) => {
|
const open = async (options) => {
|
||||||
let json = []
|
let json = []
|
||||||
await new Promise((resolve) => {
|
await new Promise((resolve) => {
|
||||||
@@ -29,7 +30,7 @@
|
|||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
}
|
}
|
||||||
const exportFlow = async (str) => {
|
const exportFlow = async (str) => {
|
||||||
if(!config.value.imgId)return
|
if(!config.value.imgId || !str)return
|
||||||
await new Promise((resolve) => {
|
await new Promise((resolve) => {
|
||||||
putSketchFlowCanvas({
|
putSketchFlowCanvas({
|
||||||
id: config.value.imgId,
|
id: config.value.imgId,
|
||||||
@@ -41,7 +42,9 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const close = () => {
|
const close = async () => {
|
||||||
|
const str = flowCanvasRef.value?.getFlowJson()
|
||||||
|
await exportFlow(str)
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
}
|
}
|
||||||
defineExpose({
|
defineExpose({
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export class EventManager {
|
|||||||
this.stateManager = options.stateManager;
|
this.stateManager = options.stateManager;
|
||||||
this.vueFlow = options.vueFlow
|
this.vueFlow = options.vueFlow
|
||||||
this.zoom = this.stateManager.zoom
|
this.zoom = this.stateManager.zoom
|
||||||
this.registerEvents()
|
this._handleKeyDown = this.handleKeyDown.bind(this)
|
||||||
}
|
}
|
||||||
/** 处理视口变化 */
|
/** 处理视口变化 */
|
||||||
handleViewportChange(e: any) {
|
handleViewportChange(e: any) {
|
||||||
@@ -54,6 +54,7 @@ export class EventManager {
|
|||||||
this.stateManager.deleteNode(activeNodeID, { isElMessageBox: true })
|
this.stateManager.deleteNode(activeNodeID, { isElMessageBox: true })
|
||||||
}
|
}
|
||||||
/** 处理键盘事件 */
|
/** 处理键盘事件 */
|
||||||
|
_handleKeyDown: any
|
||||||
handleKeyDown(event: any) {
|
handleKeyDown(event: any) {
|
||||||
const activeNodeID = this.stateManager.activeNodeID.value;
|
const activeNodeID = this.stateManager.activeNodeID.value;
|
||||||
// const shiftKey
|
// const shiftKey
|
||||||
@@ -74,12 +75,12 @@ export class EventManager {
|
|||||||
/** 注册事件 */
|
/** 注册事件 */
|
||||||
registerEvents() {
|
registerEvents() {
|
||||||
// document.addEventListener('copy', this.handleCopy.bind(this))
|
// document.addEventListener('copy', this.handleCopy.bind(this))
|
||||||
document.addEventListener('keydown', this.handleKeyDown.bind(this))
|
document.addEventListener('keydown', this._handleKeyDown)
|
||||||
}
|
}
|
||||||
/** 删除事件 */
|
/** 删除事件 */
|
||||||
removeEvents() {
|
removeEvents() {
|
||||||
// document.removeEventListener('copy', this.handleCopy.bind(this))
|
// document.removeEventListener('copy', this.handleCopy.bind(this))
|
||||||
document.removeEventListener('keydown', this.handleKeyDown.bind(this))
|
document.removeEventListener('keydown', this._handleKeyDown)
|
||||||
}
|
}
|
||||||
dispose() {
|
dispose() {
|
||||||
this.removeEvents()
|
this.removeEvents()
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ export class StateManager {
|
|||||||
nodeManager: any
|
nodeManager: any
|
||||||
toolManager: any
|
toolManager: any
|
||||||
generateManager: any
|
generateManager: any
|
||||||
|
|
||||||
|
// 是否有数据没保存
|
||||||
|
isSave: any
|
||||||
// 设置管理器
|
// 设置管理器
|
||||||
setManager(options) {
|
setManager(options) {
|
||||||
options.eventManager && (this.eventManager = options.eventManager)
|
options.eventManager && (this.eventManager = options.eventManager)
|
||||||
@@ -54,6 +57,7 @@ export class StateManager {
|
|||||||
this.mxHistory = ref(50)
|
this.mxHistory = ref(50)
|
||||||
this.historyList = ref([])
|
this.historyList = ref([])
|
||||||
this.historyIndex = ref(0)
|
this.historyIndex = ref(0)
|
||||||
|
this.isSave = ref(false)
|
||||||
|
|
||||||
this.activeNodeID = ref("")
|
this.activeNodeID = ref("")
|
||||||
this.nodes = ref<NodesItem[]>([]);
|
this.nodes = ref<NodesItem[]>([]);
|
||||||
@@ -172,6 +176,8 @@ export class StateManager {
|
|||||||
const size = this.historyList.value.length - this.mxHistory.value
|
const size = this.historyList.value.length - this.mxHistory.value
|
||||||
if (size > 0) this.historyList.value.splice(0, size)
|
if (size > 0) this.historyList.value.splice(0, size)
|
||||||
this.historyIndex.value = this.historyList.value.length - 1
|
this.historyIndex.value = this.historyList.value.length - 1
|
||||||
|
|
||||||
|
this.isSave.value = true
|
||||||
}
|
}
|
||||||
/** 撤回状态 */
|
/** 撤回状态 */
|
||||||
undoState() {
|
undoState() {
|
||||||
@@ -205,6 +211,7 @@ export class StateManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dispose() {
|
dispose() {
|
||||||
|
this.isSave.value = false
|
||||||
this.historyList.value = []
|
this.historyList.value = []
|
||||||
this.historyIndex.value = 0
|
this.historyIndex.value = 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
transitionTime: { default: 300, type: Number },
|
transitionTime: { default: 300, type: Number },
|
||||||
hideDestroy: { default: false, type: Boolean }
|
hideDestroy: { default: false, type: Boolean }
|
||||||
})
|
})
|
||||||
const emit = defineEmits(['update:modelValue', 'closed'])
|
const emit = defineEmits(['close', 'closed'])
|
||||||
const show = ref(props.modelValue)
|
const show = ref(props.modelValue)
|
||||||
const show_ = ref(props.modelValue)
|
const show_ = ref(props.modelValue)
|
||||||
const timeout = ref(null)
|
const timeout = ref(null)
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
const close = () => {
|
const close = () => {
|
||||||
emit('update:modelValue', false)
|
emit('close', false)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 70vh;
|
height: 70vh;
|
||||||
padding: 67px;
|
padding: 67px;
|
||||||
|
display: flex;
|
||||||
> .image-box {
|
> .image-box {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
max-width: 90%;
|
max-width: 90%;
|
||||||
|
|||||||
@@ -10,8 +10,7 @@
|
|||||||
import { computed, onMounted } from 'vue'
|
import { computed, onMounted } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const url =
|
const url = ''
|
||||||
'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__'
|
|
||||||
const openCanvas = () => {
|
const openCanvas = () => {
|
||||||
myEvent.emit('openFlowCanvas', { url })
|
myEvent.emit('openFlowCanvas', { url })
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user