refactor code

This commit is contained in:
hjlarry 2025-07-23 10:04:16 +08:00
parent f4438b0a08
commit 41372168b6
4 changed files with 59 additions and 97 deletions

View File

@ -21,7 +21,6 @@ import {
import { useStore, useWorkflowStore } from '@/app/components/workflow/store'
import { useWebSocketStore } from '@/app/components/workflow/store/websocket-store'
import { useCollaborativeCursors } from '../hooks'
import { connectOnlineUserWebSocket } from '@/service/demo/online-user'
import type { OnlineUser } from '@/service/demo/online-user'
type WorkflowMainProps = Pick<WorkflowProps, 'nodes' | 'edges' | 'viewport'>
@ -37,8 +36,7 @@ const WorkflowMain = ({
const lastEmitTimeRef = useRef<number>(0)
const lastPositionRef = useRef<{ x: number; y: number } | null>(null)
// WebSocket connection for collaboration
const { emit } = useWebSocketStore()
const { emit, getSocket } = useWebSocketStore()
const handleWorkflowDataUpdate = useCallback((payload: any) => {
const {
@ -61,7 +59,6 @@ const WorkflowMain = ({
}
}, [featuresStore, workflowStore])
// Handle mouse movement for collaboration with throttling (1 second)
const handleMouseMove = useCallback((event: MouseEvent) => {
if (!containerRef.current) return
@ -74,8 +71,7 @@ const WorkflowMain = ({
const now = Date.now()
const timeSinceLastEmit = now - lastEmitTimeRef.current
// Throttle to 1 second (1000ms)
if (timeSinceLastEmit >= 1000) {
if (timeSinceLastEmit >= 300) {
lastEmitTimeRef.current = now
lastPositionRef.current = { x, y }
@ -84,7 +80,7 @@ const WorkflowMain = ({
y,
})
}
else {
else {
// Update position for potential future emit
lastPositionRef.current = { x, y }
}
@ -126,7 +122,7 @@ const WorkflowMain = ({
useEffect(() => {
if (!appId) return
const socket = connectOnlineUserWebSocket(appId)
const socket = getSocket(appId)
const handleOnlineUsersUpdate = (data: { users: OnlineUser[] }) => {
const usersMap = data.users.reduce((acc, user) => {
@ -227,7 +223,7 @@ const WorkflowMain = ({
return (
<div
ref={containerRef}
style={{ position: 'relative', width: '100%', height: '100%' }}
className="relative h-full w-full"
>
<WorkflowWithInnerContext
nodes={nodes}
@ -261,14 +257,10 @@ const WorkflowMain = ({
return (
<div
key={userId}
className="pointer-events-none absolute z-[10000] -translate-x-0.5 -translate-y-0.5 transition-all duration-150 ease-out"
style={{
position: 'absolute',
left: cursor.x,
top: cursor.y,
pointerEvents: 'none',
zIndex: 10000,
transform: 'translate(-2px, -2px)',
transition: 'left 0.15s ease-out, top 0.15s ease-out',
}}
>
<svg
@ -277,9 +269,7 @@ const WorkflowMain = ({
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
style={{
filter: 'drop-shadow(0 2px 4px rgba(0,0,0,0.2))',
}}
className="drop-shadow-md"
>
<path
d="M3 3L16 8L9 10L7 17L3 3Z"
@ -291,21 +281,9 @@ const WorkflowMain = ({
</svg>
<div
className="absolute -top-0.5 left-[18px] max-w-[120px] overflow-hidden text-ellipsis whitespace-nowrap rounded px-1.5 py-0.5 text-[11px] font-medium text-white shadow-sm"
style={{
position: 'absolute',
left: '18px',
top: '-2px',
backgroundColor: userColor,
color: 'white',
padding: '2px 6px',
borderRadius: '4px',
fontSize: '11px',
fontWeight: '500',
whiteSpace: 'nowrap',
boxShadow: '0 1px 3px rgba(0,0,0,0.2)',
maxWidth: '120px',
overflow: 'hidden',
textOverflow: 'ellipsis',
}}
>
{userName}

View File

@ -2,47 +2,43 @@ import { useEffect, useState } from 'react'
import { useWebSocketStore } from '@/app/components/workflow/store/websocket-store'
export function useCollaborativeCursors(appId: string) {
const { on, connect, disconnect } = useWebSocketStore()
const [cursors, setCursors] = useState<Record<string, any>>({})
const [myUserId, setMyUserId] = useState<string | null>(null)
const { getSocket, on } = useWebSocketStore()
useEffect(() => {
if (!appId) return
connect(appId)
return () => {
disconnect()
const socket = getSocket(appId)
const handleConnect = () => {
setMyUserId(socket.id || 'unknown')
}
}, [appId, connect, disconnect])
useEffect(() => {
const unsubscribe = on('mouseMove', (update) => {
const userId = update.userId || update.user_id
const data = update.data || update
if (userId && data) {
const unsubscribeMouseMove = on('mouseMove', (update: any) => {
if (update.userId !== myUserId) {
setCursors(prev => ({
...prev,
[userId]: {
x: data.x,
y: data.y,
userId,
[update.userId]: {
x: update.data.x,
y: update.data.y,
userId: update.userId,
timestamp: update.timestamp,
},
}))
}
})
return unsubscribe
}, [on])
if (socket.connected)
handleConnect()
else
socket.on('connect', handleConnect)
useEffect(() => {
const unsubscribe = on('connected', (data) => {
if (data.userId || data.user_id)
setMyUserId(data.userId || data.user_id)
})
return unsubscribe
}, [on])
return () => {
unsubscribeMouseMove()
socket.off('connect', handleConnect)
}
}, [appId, getSocket, on, myUserId])
return { cursors, myUserId }
}

View File

@ -1,63 +1,55 @@
import { create } from 'zustand'
import { connectOnlineUserWebSocket, disconnectOnlineUserWebSocket } from '@/service/demo/online-user'
import { connectOnlineUserWebSocket } from '@/service/demo/online-user'
type WebSocketInstance = ReturnType<typeof connectOnlineUserWebSocket>
type WebSocketStore = {
socket: WebSocketInstance | null
isConnected: boolean
listeners: Map<string, Set<(data: any) => void>>
// Actions
connect: (appId: string) => void
disconnect: () => void
isConnected: () => boolean
getSocket: (appId: string) => WebSocketInstance
emit: (eventType: string, data: any) => void
on: (eventType: string, handler: (data: any) => void) => () => void
}
export const useWebSocketStore = create<WebSocketStore>((set, get) => ({
socket: null,
isConnected: false,
listeners: new Map(),
connect: (appId: string) => {
const socket = connectOnlineUserWebSocket(appId)
socket.on('collaboration_update', (update: {
type: string
userId: string
data: any
timestamp: number
}) => {
const { listeners } = get()
const eventListeners = listeners.get(update.type)
if (eventListeners) {
eventListeners.forEach((handler) => {
try {
handler(update)
}
catch (error) {
console.error(`Error in collaboration event handler for ${update.type}:`, error)
}
})
}
})
set({ socket, isConnected: true })
isConnected: () => {
const { socket } = get()
return socket?.connected || false
},
disconnect: () => {
const { socket } = get()
if (socket) {
socket.off('collaboration_update')
disconnectOnlineUserWebSocket()
getSocket: (appId: string) => {
let { socket } = get()
if (!socket) {
socket = connectOnlineUserWebSocket(appId)
socket.on('collaboration_update', (update) => {
const { listeners } = get()
const eventListeners = listeners.get(update.type)
if (eventListeners) {
eventListeners.forEach((handler) => {
try {
handler(update)
}
catch (error) {
console.error(`Error in collaboration event handler for ${update.type}:`, error)
}
})
}
})
set({ socket })
}
set({ socket: null, isConnected: false, listeners: new Map() })
return socket
},
emit: (eventType: string, data: any) => {
const { socket, isConnected } = get()
if (socket && isConnected) {
const { socket } = get()
if (socket?.connected) {
socket.emit('collaboration_event', {
type: eventType,
data,

View File

@ -34,10 +34,6 @@ export function connectOnlineUserWebSocket(appId: string): Socket {
console.log('WebSocket disconnected')
})
socket.on('online_users', (data) => {
console.log('Online users:', data)
})
socket.on('connect_error', (err) => {
console.error('WebSocket connection error:', err)
})