This commit is contained in:
2024-09-24 00:40:35 +08:00
parent 27f487c48f
commit d53c18606e
8 changed files with 289 additions and 97 deletions

View File

@@ -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 (

View File

@@ -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;
};

View File

@@ -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<Store>((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';

30
src/modules/query.ts Normal file
View File

@@ -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<Store>((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');
};

View File

@@ -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: '',

View File

@@ -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<HTMLDivElement>(null);
const containerRef = useRef<any>(null);
const [data, setData] = useState<any>({});
const containerRef = useRef<ContainerEdit | null>(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,
});