From d53c18606ee73dc72ac8a6b3905d2f424752c6f7 Mon Sep 17 00:00:00 2001 From: xion Date: Tue, 24 Sep 2024 00:40:35 +0800 Subject: [PATCH] temp --- package.json | 4 +- pnpm-lock.yaml | 38 +++---- src/App.tsx | 1 + src/modules/deck-to-flow/deck.ts | 142 ++++++++++++++++++++++++++ src/modules/index.ts | 32 +----- src/modules/query.ts | 30 ++++++ src/pages/container/preview/index.tsx | 4 +- src/pages/panel/deck/index.tsx | 135 ++++++++++++++++-------- 8 files changed, 289 insertions(+), 97 deletions(-) create mode 100644 src/modules/deck-to-flow/deck.ts create mode 100644 src/modules/query.ts diff --git a/package.json b/package.json index 7ff2c32..78d24fb 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "deploy": "rsync -avz --delete ./dist/ light:/root/apps/envision/web" }, "dependencies": { - "@abearxiong/container": "0.0.1-alpha.6", + "@abearxiong/container": "0.0.1-alpha.8", "@abearxiong/flows": "0.0.1-alpha.9", "@abearxiong/ui": "0.0.1-alpha.0", "@ant-design/icons": "^5.5.1", @@ -52,7 +52,7 @@ "globals": "^15.9.0", "react-is": "^18.3.1", "tailwind-merge": "^2.5.2", - "tailwindcss": "^3.4.12", + "tailwindcss": "^3.4.13", "tailwindcss-animate": "^1.0.7", "typescript": "^5.6.2", "typescript-eslint": "^8.6.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0030ac8..860df0f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@abearxiong/container': - specifier: 0.0.1-alpha.6 - version: 0.0.1-alpha.6(@emotion/css@11.13.0)(crypto-js@4.2.0)(eventemitter3@5.0.1) + specifier: 0.0.1-alpha.8 + version: 0.0.1-alpha.8(@emotion/css@11.13.0)(crypto-js@4.2.0)(eventemitter3@5.0.1) '@abearxiong/flows': specifier: 0.0.1-alpha.9 version: 0.0.1-alpha.9(@xyflow/react@12.3.0(@types/react@18.3.8)(immer@10.1.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(immer@10.1.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(zustand@4.5.5(@types/react@18.3.8)(immer@10.1.1)(react@18.3.1)) @@ -86,10 +86,10 @@ importers: version: 9.11.0 '@tailwindcss/aspect-ratio': specifier: ^0.4.2 - version: 0.4.2(tailwindcss@3.4.12) + version: 0.4.2(tailwindcss@3.4.13) '@tailwindcss/typography': specifier: ^0.5.15 - version: 0.5.15(tailwindcss@3.4.12) + version: 0.5.15(tailwindcss@3.4.13) '@types/node': specifier: ^22.5.5 version: 22.5.5 @@ -124,11 +124,11 @@ importers: specifier: ^2.5.2 version: 2.5.2 tailwindcss: - specifier: ^3.4.12 - version: 3.4.12 + specifier: ^3.4.13 + version: 3.4.13 tailwindcss-animate: specifier: ^1.0.7 - version: 1.0.7(tailwindcss@3.4.12) + version: 1.0.7(tailwindcss@3.4.13) typescript: specifier: ^5.6.2 version: 5.6.2 @@ -141,8 +141,8 @@ importers: packages: - '@abearxiong/container@0.0.1-alpha.6': - resolution: {integrity: sha512-rhEPkVWGOxn8o7kVSgkHOpc+/PybOQTYt/V9BQpVzM6nXw5Sl1fDCaQux2Nn06bz54bU1O38wGfk6y46S0weSw==, tarball: https://npm.pkg.github.com/download/@abearxiong/container/0.0.1-alpha.6/77e190e08005b8eb0f2a5ca5a6778ae727bdc263} + '@abearxiong/container@0.0.1-alpha.8': + resolution: {integrity: sha512-7DNio7j1YYGIQ1tVLD8p49spwmY1zf+PeX+M5VRw9dQXnKWlFr3FLAWoEJH2Lk7ODEMkRfzwsLMAh1vXFossfQ==, tarball: https://npm.pkg.github.com/download/@abearxiong/container/0.0.1-alpha.8/6191afd30d2b3040a41596d4bf96a319d15ee664} peerDependencies: '@emotion/css': ^11.13.0 crypto-js: ^4.2.0 @@ -2136,8 +2136,8 @@ packages: peerDependencies: tailwindcss: '>=3.0.0 || insiders' - tailwindcss@3.4.12: - resolution: {integrity: sha512-Htf/gHj2+soPb9UayUNci/Ja3d8pTmu9ONTfh4QY8r3MATTZOzmv6UYWF7ZwikEIC8okpfqmGqrmDehua8mF8w==} + tailwindcss@3.4.13: + resolution: {integrity: sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw==} engines: {node: '>=14.0.0'} hasBin: true @@ -2370,7 +2370,7 @@ packages: snapshots: - '@abearxiong/container@0.0.1-alpha.6(@emotion/css@11.13.0)(crypto-js@4.2.0)(eventemitter3@5.0.1)': + '@abearxiong/container@0.0.1-alpha.8(@emotion/css@11.13.0)(crypto-js@4.2.0)(eventemitter3@5.0.1)': dependencies: '@emotion/css': 11.13.0 crypto-js: 4.2.0 @@ -2933,17 +2933,17 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.22.0': optional: true - '@tailwindcss/aspect-ratio@0.4.2(tailwindcss@3.4.12)': + '@tailwindcss/aspect-ratio@0.4.2(tailwindcss@3.4.13)': dependencies: - tailwindcss: 3.4.12 + tailwindcss: 3.4.13 - '@tailwindcss/typography@0.5.15(tailwindcss@3.4.12)': + '@tailwindcss/typography@0.5.15(tailwindcss@3.4.13)': dependencies: lodash.castarray: 4.4.0 lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 postcss-selector-parser: 6.0.10 - tailwindcss: 3.4.12 + tailwindcss: 3.4.13 '@types/babel__core@7.20.5': dependencies: @@ -4571,11 +4571,11 @@ snapshots: tailwind-merge@2.5.2: {} - tailwindcss-animate@1.0.7(tailwindcss@3.4.12): + tailwindcss-animate@1.0.7(tailwindcss@3.4.13): dependencies: - tailwindcss: 3.4.12 + tailwindcss: 3.4.13 - tailwindcss@3.4.12: + tailwindcss@3.4.13: dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 diff --git a/src/App.tsx b/src/App.tsx index e895a7e..513d96c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,6 +4,7 @@ import { App as ContainerApp } from './pages/container'; import { App as PanelApp } from './pages/panel'; import { App as PublishApp } from './pages/publish'; import { App as CodeEditorApp } from './pages/code-editor'; +import '@abearxiong/container/dist/container.css'; export const App = () => { return ( diff --git a/src/modules/deck-to-flow/deck.ts b/src/modules/deck-to-flow/deck.ts new file mode 100644 index 0000000..d5e7301 --- /dev/null +++ b/src/modules/deck-to-flow/deck.ts @@ -0,0 +1,142 @@ +import { RenderData } from '@abearxiong/container'; + +type Page = { + data: { + edges: { id: string; source: string; target: string }[]; + nodes: { id: string; type: string; position: { x: number; y: number }; data: any }[]; + }; + id: string; + type: string; + [key: string]: any; +}; +type Container = { + code: string; + id: string; + [key: string]: any; +}; +type PageEditData = { + page: Page; + containerList: Container[]; +}; +export const getContainerData = (pageEditData: PageEditData) => { + const { page, containerList } = pageEditData; + const containerObj = containerList.reduce((acc, container) => { + acc[container.id] = container; + return acc; + }, {}); + + const { edges, nodes } = page.data; + const nodesObj = nodes.reduce((acc, node) => { + acc[node.id] = node; + return acc; + }, {}); + const treeArray = getTreeFromEdges(edges); + const floatNodes = nodes.filter((node) => !treeArray.find((item) => item.id === node.id)); + const treeNodes = nodes.filter((node) => treeArray.find((item) => item.id === node.id)); + const renderData: RenderData[] = []; + for (let tree of treeArray) { + const node = nodesObj[tree.id]; + const container = containerObj[node.data?.cid]; + const style = node.data?.style ?? { + position: 'absolute', + width: 100, + height: 100, + }; + const data = { + node: { ...node }, + container: { ...container }, + }; + renderData.push({ + id: node.id, + children: tree.children, + parents: tree.parents, + code: container?.code || '', + codeId: container?.id, + data: data || {}, + className: node.data?.className, + shadowRoot: node.data?.shadowRoot, + showChild: node.data?.showChild, + style, + }); + } + for (let node of floatNodes) { + const container = containerObj[node.data?.cid]; + const style = node.data?.style ?? { + position: 'absolute', + width: 100, + height: 100, + }; + const data = { + node: { ...node }, + container: { ...container }, + }; + renderData.push({ + id: node.id, + children: [], + parents: [], + code: container?.code || '', + codeId: container?.id, + data: data || {}, + className: node.data?.className, + shadowRoot: node.data?.shadowRoot, + showChild: node.data?.showChild, + style, + }); + } + return renderData; +}; +const getTreeFromEdges = ( + edges: { id: string; source: string; target: string }[], +): { + id: string; + parents: string[]; + children: string[]; +}[] => { + // 构建树形结构 + function buildNodeTree(edges) { + const nodeMap = {}; + + // 初始化每个节点的子节点列表和父节点列表 + edges.forEach((edge) => { + if (!nodeMap[edge.source]) { + nodeMap[edge.source] = { id: edge.source, parents: [], children: [] }; + } + if (!nodeMap[edge.target]) { + nodeMap[edge.target] = { id: edge.target, parents: [], children: [] }; + } + + // 连接父节点和子节点 + nodeMap[edge.source].children.push(nodeMap[edge.target]); + nodeMap[edge.target].parents.push(nodeMap[edge.source]); + }); + + return nodeMap; + } + + const nodeTree = buildNodeTree(edges); + + // 递归获取所有父节点,按顺序 + function getAllParents(node) { + const parents: string[] = []; + function traverseParents(currentNode) { + if (currentNode.parents.length > 0) { + currentNode.parents.forEach((parent: any) => { + parents.push(parent.id); + traverseParents(parent); + }); + } + } + traverseParents(node); + return parents.reverse(); // 确保顺序从最顶层到直接父节点 + } + + function getNodeInfo(nodeMap) { + return Object.values(nodeMap).map((node: any) => ({ + id: node.id, + parents: getAllParents(node), + children: node.children.map((child) => child.id), + })); + } + const result = getNodeInfo(nodeTree); + return result; +}; diff --git a/src/modules/index.ts b/src/modules/index.ts index e1e0783..1416ff0 100644 --- a/src/modules/index.ts +++ b/src/modules/index.ts @@ -1,30 +1,2 @@ -import { Query } from '@kevisual/query'; -export const query = new Query({}); -export const request = query.post; -export const ws = new WebSocket('ws://localhost:6010/api/router'); -import { create } from 'zustand'; - -type Store = { - connected: boolean; - setConnected: (connected: boolean) => void; -}; -export const useStore = create((set) => ({ - connected: false, - setConnected: (connected) => set({ connected }), -})); - -// 当连接成功时 -ws.onopen = () => { - console.log('Connected to WebSocket server'); - useStore.getState().setConnected(true); -}; -// 接收服务器的消息 -ws.onmessage = (event) => { - console.log('Received message:', event.data); - // const message = JSON.parse(event.data); -}; - -// 处理 WebSocket 关闭 -ws.onclose = () => { - console.log('Disconnected from WebSocket server'); -}; +export * from './query'; +export * from './deck-to-flow/deck'; diff --git a/src/modules/query.ts b/src/modules/query.ts new file mode 100644 index 0000000..a12bf2e --- /dev/null +++ b/src/modules/query.ts @@ -0,0 +1,30 @@ +import { Query } from '@kevisual/query'; +export const query = new Query({}); +export const request = query.post; +export const ws = new WebSocket('ws://localhost:6010/api/router'); +import { create } from 'zustand'; + +type Store = { + connected: boolean; + setConnected: (connected: boolean) => void; +}; +export const useStore = create((set) => ({ + connected: false, + setConnected: (connected) => set({ connected }), +})); + +// 当连接成功时 +ws.onopen = () => { + console.log('Connected to WebSocket server'); + useStore.getState().setConnected(true); +}; +// 接收服务器的消息 +ws.onmessage = (event) => { + // console.log('Received message:', event.data); + // const message = JSON.parse(event.data); +}; + +// 处理 WebSocket 关闭 +ws.onclose = () => { + console.log('Disconnected from WebSocket server'); +}; diff --git a/src/pages/container/preview/index.tsx b/src/pages/container/preview/index.tsx index 131b438..b841b85 100644 --- a/src/pages/container/preview/index.tsx +++ b/src/pages/container/preview/index.tsx @@ -74,7 +74,7 @@ export const Preview = () => { const code = { id: data.id, title: data.title, - codeId: data.Id, + codeId: data.id, code: data.code, data: data.data, }; @@ -88,7 +88,7 @@ export const Preview = () => { const code = { id: data.id, title: data.title, - codeId: data.Id, + codeId: data.id, code: data.code, data: data.data, hash: '', diff --git a/src/pages/panel/deck/index.tsx b/src/pages/panel/deck/index.tsx index 5b8033f..eb4be81 100644 --- a/src/pages/panel/deck/index.tsx +++ b/src/pages/panel/deck/index.tsx @@ -1,16 +1,70 @@ import { Container, ContainerEdit } from '@abearxiong/container'; import { useEffect, useRef, useState } from 'react'; import { useParams } from 'react-router'; -import { query } from '@/modules'; +import { query, useStore, ws } from '@/modules'; import { message } from 'antd'; -import '@abearxiong/container/dist/container.css'; - +import { getContainerData } from '@/modules/deck-to-flow/deck'; +export const useListener = (id?: string, opts?: any) => { + const { refresh } = opts || {}; + const connected = useStore((state) => state.connected); + // 监听服务器的消息 + useEffect(() => { + if (!id) return; + if (!connected) return; + ws.send( + JSON.stringify({ + type: 'subscribe', + data: { + type: 'pageEdit', + data: { + pid: id, + cids: ['170c0b55-8c13-4d6e-bf35-3f935d979a0d'], + }, + }, + }), + ); + ws.addEventListener('message', listener); + return () => { + if (!id) return; + if (!connected) return; + ws.removeEventListener('message', listener); + }; + }, [id, connected]); + const listener = (event) => { + const parseIfJson = (data: string) => { + try { + return JSON.parse(data); + } catch (e) { + return data; + } + }; + const receivedData = parseIfJson(event.data); + if (typeof receivedData === 'string') return; + if (receivedData.type === 'pageEdit' && receivedData.source === 'container') { + const { data: containerData, pid } = receivedData; + if (pid !== id) return; + if (refresh) { + refresh(containerData); + } + } + }; +}; +const getParent = (data: { children?: string[]; [key: string]: any }[], id: string, list: string[]) => { + for (let item of data) { + if (item.children?.includes(id)) { + // 找到了当前的父亲节点 + list.unshift(item.id); + getParent(data, item.id, list); + return; + } + } + return; +}; export const Deck = () => { const params = useParams<{ id: string }>(); const id = params.id; const ref = useRef(null); - const containerRef = useRef(null); - const [data, setData] = useState({}); + const containerRef = useRef(null); useEffect(() => { if (!id) return; @@ -26,44 +80,8 @@ export const Deck = () => { const data = res.data; console.log('data', data); const { page, containerList } = data; - const { edges, nodes } = page.data; - for (let edge of edges) { - const { source, target } = edge; - const node = nodes.find((node: any) => node.id === source); - if (!node) continue; - node.children = node.children || []; - node.children.push(target); - } - for (let node of nodes) { - const container = containerList.find((container: any) => container.id === node.data?.cid); - if (container) { - node.container = container; - } - } - const codes = nodes.map((node: any) => { - const container = node.container; - const data = container?.data || {}; - const nodeData = node.data || {}; - let style = nodeData.style ?? { - position: 'absolute', - width: 100, - height: 100, - }; - return { - id: node.id, - title: node.title, - code: container?.code || '', - data: data, - children: node.children, - // TODO: style className shadowRoot showChild - className: nodeData.className, - shadowRoot: nodeData.shadowRoot, - showChild: nodeData.showChild, - style, - }; - }); - init(codes); - console.log('codes', codes); + const result = getContainerData({ page, containerList }); + init(result); } // if (res.code === 200) { // const data = res.data; @@ -80,11 +98,40 @@ export const Deck = () => { // message.error(res.msg || 'Failed to fetch data'); // } }; + const refresh = async (data: any) => { + console.log('refresh', data); + if (!data.id) return; + const code = { + codeId: data.id, + code: data.code, + hash: '', + }; + const container = containerRef.current!; + // @ts-ignore + await container.updateDataCode([code]); + const containerList = container.data.filter((item) => item.codeId === data.id); + await new Promise((resolve) => { + setTimeout(resolve, 2000); + }); + console.log('containerList update', containerList); + // container.reRender(); + containerList.forEach((item) => { + container.hotReload(item.id); + }); + // @ts-ignore + window.c = container; + }; + useListener(id, { refresh }); + const init = async (data: any[]) => { + console.log( + 'init', + data.filter((item) => item.codeId), + ); // console.log('data', data, ref.current); const container = new ContainerEdit({ root: ref.current!, - data: data as any, + data: data.filter((item) => item.codeId), showChild: true, // edit: false, });