Merge branch 'main' of http://18.167.251.121:10003/aidlab/FiDA_Front
This commit is contained in:
@@ -21,7 +21,7 @@
|
||||
import { Handle, Position } from '@vue-flow/core'
|
||||
import { NODE_TYPE } from '../tools/index.d'
|
||||
import { NODE_DATATYPE, NODE_DATATIER } from '../tools/index.d'
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed, ref, inject } from 'vue'
|
||||
const handles = ref({
|
||||
[NODE_TYPE.INPUT]: [{ id: 'Right', type: 'source', position: Position.Right }],
|
||||
[NODE_TYPE.SECONDARY]: [
|
||||
@@ -49,14 +49,19 @@
|
||||
default: false
|
||||
}
|
||||
})
|
||||
const stateManager = inject('stateManager') as any
|
||||
const nodes = computed(() => props.stateManager.nodes.value)
|
||||
const isSubord = computed(() => nodes.value.some((v) => v.data.superiorID === props.node.id))
|
||||
const tier = computed(() => Number(props.node?.data?.tier || 0))
|
||||
const isReturned = computed(() => {
|
||||
return props.node.data.type == 'result-image' && props.node.data.data.imageProcessTasks[0].status == 'RETURNED'
|
||||
})
|
||||
const isAdd = computed(
|
||||
() =>
|
||||
!isSubord.value &&
|
||||
NODE_DATATYPE.RESULT_IMAGE === props.node.data.type &&
|
||||
!(tier.value === NODE_DATATIER.TO_3VIEW)
|
||||
!(tier.value === NODE_DATATIER.TO_3VIEW) &&
|
||||
isReturned.value
|
||||
)
|
||||
const onAdd = () => {
|
||||
const tier_ = tier.value + 1
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
const data = reactive({
|
||||
colors: []
|
||||
})
|
||||
const emit = defineEmits(['update-data'])
|
||||
const maxColor = 5
|
||||
const delColor = (i: number) => {
|
||||
data.colors.splice(i, 1)
|
||||
@@ -41,7 +42,17 @@
|
||||
data.colors.push(target.value)
|
||||
}
|
||||
|
||||
defineExpose({ data })
|
||||
const getApiData = ()=>{
|
||||
return {
|
||||
variantCount: '2',
|
||||
colors: data.colors
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(()=>{
|
||||
})
|
||||
|
||||
defineExpose({ data, getApiData })
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
import To3View from './to-3view.vue'
|
||||
import To3DModel from './to-3d-model.vue'
|
||||
|
||||
import { toRealStyleApi } from '@/api/flow-canvas'
|
||||
import { toRealStyleApi, toColorPaletteApi, toSceneCompositionApi } from '@/api/flow-canvas'
|
||||
|
||||
// import ToVideo from './to-video.vue'
|
||||
// import AddPrint from './add-print.vue'
|
||||
@@ -67,13 +67,15 @@
|
||||
tier: NODE_DATATIER.SCENE_COMPOSITION,
|
||||
type: NODE_DATATYPE.SCENE_COMPOSITION,
|
||||
title: 'Scene Composition',
|
||||
component: SceneComposition
|
||||
component: SceneComposition,
|
||||
api: toSceneCompositionApi
|
||||
},
|
||||
{
|
||||
tier: NODE_DATATIER.COLOR_PALETTE,
|
||||
type: NODE_DATATYPE.COLOR_PALETTE,
|
||||
title: 'Color Palette',
|
||||
component: ColorPalette
|
||||
component: ColorPalette,
|
||||
api: toColorPaletteApi
|
||||
},
|
||||
{
|
||||
tier: NODE_DATATIER.TO_3D_MODEL,
|
||||
@@ -119,32 +121,36 @@
|
||||
const componentRef = ref(null)
|
||||
|
||||
const onGenerateClick = async () => {
|
||||
const data = componentRef.value.data
|
||||
const subordNode = stateManager.getSubordNodeById(attrs.node.id)
|
||||
emit('update-data', data)
|
||||
console.log(attrs.node,data)
|
||||
const data = componentRef.value?.getApiData?.() || {}
|
||||
const subordNode = stateManager.getSubordNodeByID(attrs.node.id)
|
||||
emit('update-data', componentRef.value?.data)
|
||||
if(!attrs.node?.data?.originalImage)console.log('originalImage 找不到原始图片')
|
||||
|
||||
const apiData = {
|
||||
sketchId: props.sketchId,
|
||||
mode: data.mode,
|
||||
size: data.pixelRatio,
|
||||
imageUrl: attrs.node?.data?.originalImage,
|
||||
userPrompt: data.prompt,
|
||||
...data,
|
||||
}
|
||||
const taskList = await currentComponent.value.api(apiData).then((rv)=>{
|
||||
return rv
|
||||
}) || []
|
||||
// const taskList = [{taskId:'123'}]
|
||||
console.log(taskList)
|
||||
if (!subordNode) {
|
||||
nodeManager.createResultNode({
|
||||
data: {
|
||||
superiorID: attrs.node.id,
|
||||
tier: currentComponent.value.tier,
|
||||
taskList.forEach((item,index) => {
|
||||
nodeManager.createResultNode({
|
||||
positionY: index * (50 + 250),
|
||||
data: {
|
||||
imageProcessTasks:taskList,
|
||||
selectTaskId:taskList[0].taskId,
|
||||
superiorID: attrs.node.id,
|
||||
createIndexPosition: index,
|
||||
tier: currentComponent.value.tier,
|
||||
isActive: index == 0,
|
||||
data: {
|
||||
imageProcessTasks:[item],
|
||||
selectTaskId:item.taskId,
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
} else {
|
||||
subordNode.data.data.url =
|
||||
|
||||
@@ -56,7 +56,13 @@
|
||||
data.styles.push(value)
|
||||
}
|
||||
}
|
||||
defineExpose({ data })
|
||||
const getApiData = ()=>{
|
||||
return {
|
||||
styles: data.styles,
|
||||
userPrompt: data.prompt,
|
||||
}
|
||||
}
|
||||
defineExpose({ data, getApiData })
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
@@ -54,10 +54,18 @@
|
||||
const data = reactive({
|
||||
prompt: '',
|
||||
pixelRatio: '1:1',
|
||||
mode: 'Normal'
|
||||
mode: 'Normal',
|
||||
})
|
||||
|
||||
defineExpose({ data })
|
||||
const getApiData = ()=>{
|
||||
return {
|
||||
mode: data.mode,
|
||||
size: data.pixelRatio,
|
||||
userPrompt: data.prompt,
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({ data, getApiData })
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
<div class="result-image"
|
||||
v-for="(item, i) in data.imageProcessTasks"
|
||||
:key="item.taskId"
|
||||
:class="{'active': item.taskId === data.selectTaskId}"
|
||||
:class="{'active': config.isActive}"
|
||||
@click="setSelectTaskId(item.taskId)"
|
||||
>
|
||||
<div class="header" v-show="showHeader && item.taskId === data.selectTaskId" @mousedown.stop>
|
||||
<div class="header" v-if="item.status == 'RETURNED'" v-show="showHeader && item.taskId === data.selectTaskId" @mousedown.stop>
|
||||
<span class="icon">
|
||||
<svg-icon name="chat-compose" size="20" size-unit="px" />
|
||||
</span>
|
||||
@@ -24,10 +24,19 @@
|
||||
</div>
|
||||
<img
|
||||
class="image"
|
||||
v-if="item.status == 'RETURNED'"
|
||||
:src="item?.url"
|
||||
:style="{ transform: `scale(${item?.scale?.x || 1}, ${item?.scale?.y || 1})` }"
|
||||
/>
|
||||
<div class="more" @click="clickimageProcessTaskItem(item.taskId)" @mousedown.stop>
|
||||
<div class="status" v-else>
|
||||
<div class="content">
|
||||
<HighlightAdmin>
|
||||
<img src="@/assets/images/generateLoading.png" alt="">
|
||||
<div class="mask"></div>
|
||||
</HighlightAdmin>
|
||||
</div>
|
||||
</div>
|
||||
<div class="more" v-if="item.status == 'RETURNED'" @click="clickimageProcessTaskItem(item.taskId)" @mousedown.stop>
|
||||
<svg-icon name="more" size="24" size-unit="px" color="#C9C9C9" />
|
||||
</div>
|
||||
<div class="menu" v-show="showMenu && item.taskId === clickTaskId" @mousedown.stop>
|
||||
@@ -50,9 +59,14 @@
|
||||
<script setup lang="ts">
|
||||
import myEvent from '@/utils/myEvent'
|
||||
import { downloadImage } from '../../../tools/tools'
|
||||
import { reactive, ref, onBeforeUnmount, useAttrs, inject, watch, } from 'vue'
|
||||
import { reactive, ref, onBeforeUnmount, useAttrs, inject, watch, computed, onMounted } from 'vue'
|
||||
import HighlightAdmin from '@/components/highlightAdmin.vue'
|
||||
const openImagePreview = inject('openImagePreview') as (url: string) => void
|
||||
const props = defineProps({
|
||||
node: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
@@ -73,25 +87,30 @@
|
||||
const showHeader = ref(!!attrs.node?.data?.isHeader)
|
||||
const showMenu = ref(false)
|
||||
const clickTaskId = ref('')
|
||||
const generateManager = inject('generateManager') as any
|
||||
const clickimageProcessTaskItem = (taskId: string) => {
|
||||
if(clickTaskId.value == taskId){
|
||||
showMenu.value = !showMenu.value
|
||||
}
|
||||
clickTaskId.value = taskId
|
||||
}
|
||||
}
|
||||
const data = reactive({
|
||||
selectTaskId: props.data?.selectTaskId || '',
|
||||
imageProcessTasks: props.data?.imageProcessTasks || [],
|
||||
imageProcessTasks: props.data?.imageProcessTasks,
|
||||
isActive: props.data?.isActive || false,
|
||||
})
|
||||
const setSelectTaskId = (taskId: string) => {
|
||||
data.selectTaskId = taskId
|
||||
emit('update-data', data)
|
||||
}
|
||||
watch(
|
||||
() => props.data.url,
|
||||
() => props.data.status,
|
||||
(newVal) => {
|
||||
data.url = newVal
|
||||
}
|
||||
let selectNode = data.imageProcessTasks.find((item) => item.taskId === data.selectTaskId)
|
||||
if(selectNode.status !== 'RETURNED'){
|
||||
generateManager.addTaskId(selectNode,props.node.id)
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
const menus = ref([
|
||||
{ label: 'Copy', tip: 'Ctrl+C', on: () => emit('copy-node', clickTaskId.value) },
|
||||
@@ -103,10 +122,9 @@
|
||||
if(clickTaskId.value){
|
||||
data.imageProcessTasks = data.imageProcessTasks.filter((item) => item.taskId !== clickTaskId.value)
|
||||
clickTaskId.value = ''
|
||||
emit('update-data', data)
|
||||
}
|
||||
}else{
|
||||
emit('delete-node')
|
||||
emit('delete-node', props.node.id)
|
||||
}
|
||||
},
|
||||
disabled: !!props.config?.disableDelete
|
||||
@@ -137,7 +155,6 @@
|
||||
}
|
||||
item.scale.x = -item.scale.x
|
||||
})
|
||||
emit('update-data', data)
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -150,7 +167,6 @@
|
||||
}
|
||||
item.scale.y = -item.scale.y
|
||||
})
|
||||
emit('update-data', data)
|
||||
}
|
||||
}
|
||||
])
|
||||
@@ -176,6 +192,9 @@
|
||||
onBeforeUnmount(() => {
|
||||
document.removeEventListener('mousedown', hideMenu)
|
||||
})
|
||||
onMounted(()=>{
|
||||
emit('update-data', data)
|
||||
})
|
||||
defineExpose({ data })
|
||||
</script>
|
||||
|
||||
@@ -253,6 +272,30 @@
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
> .status{
|
||||
width: 100%;
|
||||
height: 140px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
> .content{
|
||||
width: 86px;
|
||||
height: 60px;
|
||||
position: relative;
|
||||
.mask{
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
img{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
position: relative;
|
||||
|
||||
> .more {
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
const onInput = () => {
|
||||
const text = inputRef.value.innerHTML
|
||||
data.text = text
|
||||
emit('update-data', data)
|
||||
}
|
||||
// watch(
|
||||
// () => props.active,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<VueFlow
|
||||
ref="vueFlow"
|
||||
:nodes="nodes"
|
||||
:edges="edges"
|
||||
:edges="edges_"
|
||||
:min-zoom="0.1"
|
||||
:max-zoom="10"
|
||||
:nodes-draggable="nodesDraggable"
|
||||
@@ -12,6 +12,7 @@
|
||||
@node-drag-stop="(e) => eventManager.handleNodeDragStop(e)"
|
||||
@viewport-change="(e) => eventManager.handleViewportChange(e)"
|
||||
@pane-click="(e) => eventManager.handleClick(e)"
|
||||
@node-click="(e) => clickNode(e)"
|
||||
:class="{ 'custom-cursor': !!stateManager.cursor.value }"
|
||||
:style="{ '--custom-cursor': stateManager.cursor.value }"
|
||||
>
|
||||
@@ -61,7 +62,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { VueFlow, useVueFlow } from '@vue-flow/core'
|
||||
import { computed, ref, markRaw, onMounted, nextTick, provide, onBeforeMount } from 'vue'
|
||||
import { computed, ref, watch, onMounted, nextTick, provide, onBeforeMount } from 'vue'
|
||||
import { useLayout } from '@/utils/treeDiagram'
|
||||
import { NODE_TYPE, NODE_COMPONENT } from './tools/index.d'
|
||||
// 组件
|
||||
@@ -91,6 +92,7 @@
|
||||
import { FlowManager } from './manager/FlowManager'
|
||||
import { NodeManager } from './manager/NodeManager'
|
||||
import { ToolManager, TOOLS } from './manager/ToolManager'
|
||||
import { GenerateManager } from './manager/GenerateManager'
|
||||
|
||||
const props = defineProps({
|
||||
config: {
|
||||
@@ -126,8 +128,17 @@
|
||||
stateManager.setManager({ toolManager })
|
||||
provide('toolManager', toolManager)
|
||||
|
||||
// 生成管理器
|
||||
const generateManager = new GenerateManager({ stateManager })
|
||||
stateManager.setManager({ generateManager })
|
||||
provide('generateManager', generateManager)
|
||||
|
||||
const nodes = computed(() => stateManager.nodes_.value)
|
||||
const edges = computed(() => stateManager.edges.value)
|
||||
const edges_ = computed(() => {
|
||||
console.log(123)
|
||||
return edges.value.filter((v) => v.visible)
|
||||
})
|
||||
const nodesDraggable = computed(() => stateManager.nodesDraggable.value)
|
||||
const panOnDrag = computed(() => stateManager.panOnDrag.value)
|
||||
|
||||
@@ -153,6 +164,11 @@
|
||||
}, 0)
|
||||
}
|
||||
|
||||
/** 点击节点 */
|
||||
const clickNode = (event) => {
|
||||
let node = event.node
|
||||
stateManager.showNodeConnections(node.id)
|
||||
}
|
||||
/** 删除节点 */
|
||||
const deleteNode = (id) => {
|
||||
nodeManager.deleteNode(id)
|
||||
@@ -233,11 +249,12 @@
|
||||
disableDelete: true,
|
||||
isHeader: false,
|
||||
data: {
|
||||
selectable: false,
|
||||
imageProcessTasks:[
|
||||
{
|
||||
id: props.config.imgId,
|
||||
url: props.config.url,
|
||||
state:'success',
|
||||
status:'RETURNED',
|
||||
taskId: timestamp + '',
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
import { getTaskidResult } from '@/api/flow-canvas'
|
||||
interface NodeOptions {
|
||||
id?: string
|
||||
position?: { x: number, y: number }
|
||||
positionX?: number
|
||||
positionY?: number
|
||||
component?: any
|
||||
}
|
||||
|
||||
import { ElMessage } from 'element-plus'
|
||||
// interface NodeOptions {
|
||||
// }
|
||||
export class GenerateManager {
|
||||
stateManager: any
|
||||
taskIds: string[] = []
|
||||
getTaskIdsImgTime: any
|
||||
constructor(options) {
|
||||
this.stateManager = options.stateManager;
|
||||
}
|
||||
@@ -19,19 +15,63 @@ export class GenerateManager {
|
||||
|
||||
}
|
||||
/** 添加taskId */
|
||||
addTaskId(TaskId: any) {
|
||||
this.stateManager.addTaskId(TaskId)
|
||||
addTaskId(generateData: any,nodeId: string) {
|
||||
this.taskIds.push({
|
||||
...generateData,
|
||||
nodeId,
|
||||
})
|
||||
this.getTasksIdImg()
|
||||
}
|
||||
/** 添加taskId */
|
||||
async getTasksIdImg(list) {
|
||||
let taskIds = list.map((item)=>item.taskId)
|
||||
getTaskidResult({taskIds}).then((rv)=>{
|
||||
console.log(rv)
|
||||
})
|
||||
async getTasksIdImg() {
|
||||
clearInterval(this.getTaskIdsImgTime)
|
||||
this.getTaskIdsImgTime = setInterval(()=>{
|
||||
let taskIds = this.taskIds.map((item)=>item.taskId)
|
||||
getTaskidResult({taskIds}).then((rv:any)=>{
|
||||
//找出成功和失败的任务
|
||||
let returnedTasks = rv.filter((item)=>item.status == 'RETURNED' || item.status == 'FAILED')
|
||||
if(returnedTasks.length == 0)return
|
||||
//剔除调成功的
|
||||
let taskIds_ = JSON.parse(JSON.stringify(this.taskIds))
|
||||
this.taskIds = taskIds_.filter(itemA =>
|
||||
!returnedTasks.some(itemB => itemB.taskId === itemA.taskId)
|
||||
)
|
||||
//把成功的提取出来并且更新到node中
|
||||
const result = returnedTasks.filter(itemA =>
|
||||
taskIds_.some(itemB => {
|
||||
itemA.nodeId = itemB.nodeId
|
||||
return itemB.taskId === itemA.taskId
|
||||
})
|
||||
)
|
||||
result.forEach(item => {
|
||||
this.stateManager.getNodeById(item.nodeId).data.data.imageProcessTasks.forEach((nodeDataItem:any)=>{
|
||||
if(item.taskId == nodeDataItem.taskId){
|
||||
if(item.status == 'FAILED'){
|
||||
this.stateManager.deleteNode(item.nodeId)
|
||||
ElMessage.error(item.errorMessage)
|
||||
}else if(item.status == 'RETURNED'){
|
||||
nodeDataItem.url = item.url
|
||||
nodeDataItem.createTime = item.createTime
|
||||
nodeDataItem.status = item.status
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
if(this.taskIds.length == 0)clearInterval(this.getTaskIdsImgTime)
|
||||
}).catch(()=>{
|
||||
clearInterval(this.getTaskIdsImgTime)
|
||||
console.warn('获取taskId图片失败')
|
||||
})
|
||||
}, 3000)
|
||||
}
|
||||
/** 更新taskId */
|
||||
updateTaskId(taskId: string) {
|
||||
this.stateManager.getNodeById()
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.taskIds = []
|
||||
|
||||
clearInterval(this.getTaskIdsImgTime)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ interface NodeData {
|
||||
disableDelete?: boolean// 是否禁用删除
|
||||
disableCopy?: boolean// 是否禁用复制
|
||||
originalImage?: string// 要进行生成的图片
|
||||
createIndexPosition?: number// 创建索引位置
|
||||
isActive?: boolean// 是否激活
|
||||
}
|
||||
interface NodeOptions {
|
||||
id?: string
|
||||
@@ -68,9 +70,11 @@ export class NodeManager {
|
||||
const options_ = {
|
||||
...(options ? options : {}),
|
||||
component: NODE_COMPONENT.RESULT_IMAGE,
|
||||
positionY: options?.positionY || 0,
|
||||
data: {
|
||||
tier: NODE_DATATIER.RESULT_IMAGE,
|
||||
type: NODE_DATATYPE.RESULT_IMAGE,
|
||||
createIndexPosition: options?.data?.createIndexPosition || 1,
|
||||
isHeader: true,
|
||||
...(options?.data || {}),
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ref, computed } from "vue";
|
||||
import { NODE_TYPE } from '../tools/index.d'
|
||||
import { NODE_TYPE, NODE_DATATYPE } from '../tools/index.d'
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import i18n from '@/lang'
|
||||
const t = i18n.global.t
|
||||
@@ -35,12 +35,14 @@ export class StateManager {
|
||||
flowManager: any
|
||||
nodeManager: any
|
||||
toolManager: any
|
||||
generateManager: any
|
||||
// 设置管理器
|
||||
setManager(options) {
|
||||
options.eventManager && (this.eventManager = options.eventManager)
|
||||
options.flowManager && (this.flowManager = options.flowManager)
|
||||
options.nodeManager && (this.nodeManager = options.nodeManager)
|
||||
options.toolManager && (this.toolManager = options.toolManager)
|
||||
options.generateManager && (this.generateManager = options.generateManager)
|
||||
}
|
||||
constructor(options) {
|
||||
this.vueFlow = options.vueFlow
|
||||
@@ -87,12 +89,14 @@ export class StateManager {
|
||||
source: source,
|
||||
target: target,
|
||||
selectable: false,
|
||||
visible: (node.data.type !== NODE_DATATYPE.RESULT_IMAGE || node.data.isActive),
|
||||
type: 'default'
|
||||
})
|
||||
}
|
||||
})
|
||||
return arr
|
||||
})
|
||||
window.nodes = this.nodes
|
||||
|
||||
}
|
||||
/** 设置激活节点 */
|
||||
@@ -131,8 +135,8 @@ export class StateManager {
|
||||
/** 获取节点 */
|
||||
getNodeById(id: string) { return this.nodes.value.find((node: NodesItem) => node.id === id) }
|
||||
/** 获取下级节点 */
|
||||
getSubordNodeById(id: string) { return this.nodes.value.find((node: NodesItem) => node.data.superiorID === id) }
|
||||
getLastNode() { return this.nodes.value[this.nodes.value.length - 1] }
|
||||
getSubordNodeByID(id: string) { return this.nodes.value.find((node: NodesItem) => node.data.superiorID === id) }
|
||||
getLastNode() { console.log(this.nodes.value); return this.nodes.value[this.nodes.value.length - 1] }
|
||||
/** 设置工具 */
|
||||
setTool(tool: string) { this.tool.value = tool }
|
||||
/** 设置光标 */
|
||||
@@ -183,6 +187,20 @@ export class StateManager {
|
||||
this.nodes.value = JSON.parse(state.nodes)
|
||||
}
|
||||
|
||||
/** 显示指定子节点和父节点连接线,隐藏父节点和其他子节点链接线, */
|
||||
showNodeConnections(id: string) {
|
||||
const node = this.getNodeById(id)
|
||||
if(node.data.component != NODE_DATATYPE.RESULT_IMAGE && node.data.superiorID) return
|
||||
let edges_ = JSON.parse(JSON.stringify(this.edges.value))
|
||||
this.nodes.value.forEach((nodeItem) => {
|
||||
if(node.data.superiorID === nodeItem.data.superiorID && nodeItem.id == id) {
|
||||
nodeItem.data.isActive = true
|
||||
}else if(node.data.superiorID == nodeItem.data.superiorID){
|
||||
nodeItem.data.isActive = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.historyList.value = []
|
||||
this.historyIndex.value = 0
|
||||
|
||||
61
src/components/highlightAdmin.vue
Normal file
61
src/components/highlightAdmin.vue
Normal file
@@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<div class="loading" ref="textBox">
|
||||
<slot></slot>
|
||||
<div class="loading-dot" ref="dotBox"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, nextTick, ref } from "vue";
|
||||
import { gsap } from "gsap";
|
||||
|
||||
const dotBox = ref(null)
|
||||
let tl1 = null;
|
||||
const setTl1 = () => {
|
||||
nextTick(() => {
|
||||
let el = dotBox.value
|
||||
let width = el.offsetWidth + el.parentElement.offsetWidth
|
||||
let time = el.parentElement.offsetWidth / el.offsetWidth
|
||||
tl1 = gsap.timeline();
|
||||
tl1.to(el, time,
|
||||
{
|
||||
ease: "power1.in",
|
||||
left: width * 1.5,
|
||||
onComplete: () => {
|
||||
setTimeout(() => {
|
||||
tl1.restart()
|
||||
}, 1000)
|
||||
}
|
||||
},
|
||||
)
|
||||
tl1.progress(0);
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
setTl1()
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.loading {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
}
|
||||
.loading-dot {
|
||||
height: 200%;
|
||||
aspect-ratio: .2/1;
|
||||
background: radial-gradient(ellipse 150% 150% at center, #ffffff, rgba(255, 255, 255, .2), transparent);
|
||||
box-shadow: 0 0 20px rgba(255, 255, 255, 1);
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
transform: translate(-175%, -50%) rotate(-45deg);
|
||||
}
|
||||
|
||||
</style>
|
||||
Reference in New Issue
Block a user