首页 / 教程文章 / WordPress柔性供应链中的实时协同编辑功能开发教程

WordPress柔性供应链中的实时协同编辑功能开发教程

WordPress柔性供应链中的实时协同编辑功能开发教程

引言:柔性供应链与协同编辑的融合

在当今快速变化的商业环境中,柔性供应链已成为企业保持竞争力的关键。WordPress作为全球最流行的内容管理系统,在供应链管理中扮演着重要角色。本文将详细介绍如何在WordPress中开发实时协同编辑功能,使供应链各环节参与者能够同步协作,提高工作效率和响应速度。

技术架构设计

系统架构概览

我们的实时协同编辑系统将采用以下技术栈:

  • 前端:JavaScript + React.js
  • 实时通信:WebSocket (Socket.io)
  • 后端:WordPress REST API + 自定义PHP插件
  • 数据同步:Operational Transformation (OT)算法
  • 数据库:MySQL (WordPress默认)

环境准备

在开始开发前,请确保您的WordPress环境满足以下要求:

  • WordPress 5.0+
  • PHP 7.4+
  • MySQL 5.6+
  • SSL证书(用于安全的WebSocket连接)

核心功能模块开发

1. WebSocket服务器集成

<?php
/**
 * WordPress实时协同编辑插件 - WebSocket服务器集成
 * 文件名:ws-supplychain-collab.php
 */

// 防止直接访问
if (!defined('ABSPATH')) {
    exit;
}

class SupplyChain_WebSocket_Server {
    
    private $server;
    private $clients;
    private $document_states;
    
    public function __construct() {
        $this->clients = new SplObjectStorage();
        $this->document_states = [];
        
        // 初始化WebSocket服务器
        add_action('init', [$this, 'init_websocket_server']);
    }
    
    /**
     * 初始化WebSocket服务器
     */
    public function init_websocket_server() {
        // 检查是否在CLI模式下运行
        if (php_sapi_name() === 'cli') {
            $this->start_server();
        }
    }
    
    /**
     * 启动WebSocket服务器
     */
    private function start_server() {
        // 创建WebSocket服务器实例
        $this->server = new RatchetApp('localhost', 8080, '0.0.0.0');
        
        // 注册消息处理类
        $this->server->route('/supplychain', new SupplyChain_Collaboration_Handler(), ['*']);
        
        echo "WebSocket服务器启动在端口 8080n";
        $this->server->run();
    }
}

/**
 * WebSocket消息处理器
 */
class SupplyChain_Collaboration_Handler implements RatchetMessageComponentInterface {
    
    public function onOpen(RatchetConnectionInterface $conn) {
        // 新客户端连接
        global $clients;
        $clients->attach($conn);
        echo "新客户端连接: {$conn->resourceId}n";
    }
    
    public function onMessage(RatchetConnectionInterface $from, $msg) {
        // 处理客户端消息
        $data = json_decode($msg, true);
        
        switch ($data['type']) {
            case 'join_document':
                $this->handleJoinDocument($from, $data);
                break;
            case 'edit_operation':
                $this->handleEditOperation($from, $data);
                break;
            case 'cursor_update':
                $this->handleCursorUpdate($from, $data);
                break;
        }
    }
    
    /**
     * 处理加入文档请求
     */
    private function handleJoinDocument($conn, $data) {
        $document_id = $data['document_id'];
        $user_id = $data['user_id'];
        
        // 发送当前文档状态给新用户
        $response = [
            'type' => 'document_state',
            'content' => $this->getDocumentState($document_id),
            'users' => $this->getDocumentUsers($document_id)
        ];
        
        $conn->send(json_encode($response));
        
        // 通知其他用户有新成员加入
        $this->broadcastToDocument($document_id, [
            'type' => 'user_joined',
            'user_id' => $user_id,
            'username' => get_userdata($user_id)->display_name
        ], $conn);
    }
    
    public function onClose(RatchetConnectionInterface $conn) {
        // 客户端断开连接
        global $clients;
        $clients->detach($conn);
        echo "客户端断开: {$conn->resourceId}n";
    }
    
    public function onError(RatchetConnectionInterface $conn, Exception $e) {
        echo "错误: {$e->getMessage()}n";
        $conn->close();
    }
}

// 初始化插件
new SupplyChain_WebSocket_Server();
?>

2. 前端实时编辑器组件

/**
 * WordPress实时协同编辑器 - 前端组件
 * 文件名:supplychain-editor.js
 */

import React, { useState, useEffect, useRef } from 'react';
import { io } from 'socket.io-client';
import { Editor, EditorState, ContentState, convertToRaw } from 'draft-js';
import 'draft-js/dist/Draft.css';

const SupplyChainEditor = ({ documentId, userId }) => {
    const [editorState, setEditorState] = useState(EditorState.createEmpty());
    const [connectedUsers, setConnectedUsers] = useState([]);
    const [socket, setSocket] = useState(null);
    const editorRef = useRef(null);
    
    // 初始化WebSocket连接
    useEffect(() => {
        const newSocket = io('wss://your-domain.com:8080/supplychain', {
            transports: ['websocket'],
            secure: true
        });
        
        setSocket(newSocket);
        
        // 加入文档
        newSocket.emit('join_document', {
            document_id: documentId,
            user_id: userId
        });
        
        // 监听文档状态更新
        newSocket.on('document_state', (data) => {
            const contentState = ContentState.createFromText(data.content);
            setEditorState(EditorState.createWithContent(contentState));
            setConnectedUsers(data.users);
        });
        
        // 监听编辑操作
        newSocket.on('edit_operation', (operation) => {
            applyRemoteOperation(operation);
        });
        
        // 监听用户加入/离开
        newSocket.on('user_joined', (user) => {
            setConnectedUsers(prev => [...prev, user]);
        });
        
        newSocket.on('user_left', (userId) => {
            setConnectedUsers(prev => prev.filter(u => u.id !== userId));
        });
        
        return () => newSocket.close();
    }, [documentId, userId]);
    
    /**
     * 处理本地编辑操作
     */
    const handleEditorChange = (newEditorState) => {
        const oldContent = editorState.getCurrentContent();
        const newContent = newEditorState.getCurrentContent();
        
        // 检测变化并生成操作
        const operation = generateOperation(oldContent, newContent);
        
        if (operation && socket) {
            // 发送操作到服务器
            socket.emit('edit_operation', {
                document_id: documentId,
                operation: operation,
                user_id: userId,
                timestamp: Date.now()
            });
        }
        
        setEditorState(newEditorState);
    };
    
    /**
     * 生成编辑操作
     */
    const generateOperation = (oldContent, newContent) => {
        const oldText = oldContent.getPlainText();
        const newText = newContent.getPlainText();
        
        // 简化实现:实际应使用OT算法
        if (oldText !== newText) {
            return {
                type: 'text_change',
                oldText: oldText,
                newText: newText,
                selection: editorState.getSelection()
            };
        }
        
        return null;
    };
    
    /**
     * 应用远程操作
     */
    const applyRemoteOperation = (operation) => {
        if (operation.type === 'text_change') {
            const contentState = ContentState.createFromText(operation.newText);
            const newEditorState = EditorState.createWithContent(contentState);
            
            // 保留当前选择状态
            const selectionState = editorState.getSelection();
            const finalEditorState = EditorState.forceSelection(
                newEditorState,
                selectionState
            );
            
            setEditorState(finalEditorState);
        }
    };
    
    /**
     * 发送光标位置更新
     */
    const sendCursorUpdate = (selection) => {
        if (socket) {
            socket.emit('cursor_update', {
                document_id: documentId,
                user_id: userId,
                cursor_position: selection.getStartOffset(),
                selection_range: {
                    start: selection.getStartOffset(),
                    end: selection.getEndOffset()
                }
            });
        }
    };
    
    return (
        <div className="supplychain-editor-container">
            <div className="editor-header">
                <h3>供应链协同编辑器</h3>
                <div className="user-list">
                    <span>在线用户: </span>
                    {connectedUsers.map(user => (
                        <span key={user.id} className="user-badge">
                            {user.username}
                        </span>
                    ))}
                </div>
            </div>
            
            <div className="editor-wrapper">
                <Editor
                    ref={editorRef}
                    editorState={editorState}
                    onChange={handleEditorChange}
                    onFocus={() => sendCursorUpdate(editorState.getSelection())}
                    placeholder="开始协同编辑供应链文档..."
                />
            </div>
            
            <div className="editor-footer">
                <div className="document-info">
                    文档ID: {documentId} | 自动保存已启用
                </div>
                <div className="editor-tools">
                    <button className="btn-save" onClick={handleSave}>
                        保存版本
                    </button>
                    <button className="btn-history" onClick={showHistory}>
                        查看历史
                    </button>
                </div>
            </div>
        </div>
    );
};

export default SupplyChainEditor;

3. WordPress插件集成

<?php
/**
 * WordPress实时协同编辑插件主文件
 * 文件名:supplychain-collaboration.php
 */

/*
Plugin Name: 供应链协同编辑系统
Description: 为WordPress添加实时协同编辑功能,特别适用于柔性供应链管理
Version: 1.0.0
Author: 您的名称
*/

// 防止直接访问
if (!defined('ABSPATH')) {
    exit;
}

class SupplyChain_Collaboration_Plugin {
    
    private static $instance = null;
    
    public static function get_instance() {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    private function __construct() {
        // 初始化钩子
        $this->init_hooks();
    }
    
    /**
     * 初始化WordPress钩子
     */
    private function init_hooks() {
        // 添加管理菜单
        add_action('admin_menu', [$this, 'add_admin_menu']);
        
        // 注册短代码
        add_shortcode('supplychain_editor', [$this, 'render_editor_shortcode']);
        
        // 注册REST API端点
        add_action('rest_api_init', [$this, 'register_rest_endpoints']);
        
        // 加载脚本和样式
        add_action('wp_enqueue_scripts', [$this, 'enqueue_scripts']);
        add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_scripts']);
    }
    
    /**
     * 添加管理菜单
     */
    public function add_admin_menu() {
        add_menu_page(
            '供应链协同编辑',
            '供应链协同',
            'manage_options',
            'supplychain-collab',
            [$this, 'render_admin_page'],
            'dashicons-edit',
            30
        );
    }
    
    /**
     * 渲染编辑器短代码
     */
    public function render_editor_shortcode($atts) {
        $atts = shortcode_atts([
            'document_id' => 'default',
            'title' => '供应链文档'
        ], $atts);
        
        // 检查用户权限
        if (!is_user_logged_in()) {
            return '<p>请先登录以使用协同编辑功能</p>';
        }
        
        $user_id = get_current_user_id();
        
        ob_start();
        ?>
        <div id="supplychain-editor-root" 
             data-document-id="<?php echo esc_attr($atts['document_id']); ?>"
             data-user-id="<?php echo esc_attr($user_id); ?>">
            <!-- React组件将在这里渲染 -->
        </div>
        
        <script>
            document.addEventListener('DOMContentLoaded', function() {
                const rootElement = document.getElementById('supplychain-editor-root');
                const documentId = rootElement.dataset.documentId;
                const userId = parseInt(rootElement.dataset.userId);
                
                // 这里应该初始化React应用
                console.log('初始化协同编辑器:', documentId, userId);
            });
        </script>
        <?php
        
        return ob_get_clean();
    }
    
    /**
     * 注册REST API端点
     */
    public function register_rest_endpoints() {
        // 获取文档历史记录
        register_rest_route('supplychain/v1', '/document/(?P<id>d+)/history', [
            'methods' => 'GET',
            'callback' => [$this, 'get_document_history'],
            'permission_callback' => [$this, 'check_api_permission']
        ]);
        
        // 保存文档版本
        register_rest_route('supplychain/v1', '/document/(?P<id>d+)/save', [
            'methods' => 'POST',
            'callback' => [$this, 'save_document_version'],
            'permission_callback' => [$this, 'check_api_permission']
        ]);
    }
    
    /**
     * 获取文档历史记录
     */
    public function get_document_history($request) {
        $document_id = $request->get_param('id');
        
        global $wpdb;
        $table_name = $wpdb->prefix . 'supplychain_document_history';
        
        $history = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM $table_name WHERE document_id = %d ORDER BY created_at DESC LIMIT 50",
                $document_id
            )
        );
        
        return rest_ensure_response($history);
    }
    
    /**
     * 检查API权限
     */
    public function check_api_permission($request) {
        return current_user_can('edit_posts');
    }
    
    /**
     * 加载前端脚本
     */
    public function enqueue_scripts() {
        wp_enqueue_script(
            'supplychain-editor',
            plugin_dir_url(__FILE__) . 'js/supplychain-editor.js',
            ['wp-element', 'wp-components'],
            '1.0.0',
            true
        );
        
        wp_enqueue_style(
            'supplychain-editor-style',
            plugin_dir_url(__FILE__) . 'css/editor-style.css'
        );
    }
}

// 初始化插件
SupplyChain_Collaboration_Plugin::get_instance();

/**
 * 插件激活时创建数据库表
 */
register_activation_hook(__FILE__, 'supplychain_collab_activate');

function supplychain_collab_activate() {
    global $wpdb;
    $charset_collate = $wpdb->get_charset_collate();
    
    // 创建文档历史表
    $table_name = $wpdb->prefix . 'supplychain_document_history';
    
    $sql = "CREATE TABLE IF NOT EXISTS $table_name (
        id bigint(20) NOT NULL AUTO_INCREMENT,
        document_id varchar(100) NOT NULL,
        content longtext NOT NULL,
        user_id bigint(20) NOT NULL,
        created_at datetime DEFAULT CURRENT_TIMESTAMP,
        PRIMARY KEY (id),
        KEY document_id (document_id),
        KEY user_id (user_id)
    ) $charset_collate;";
    
    require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    dbDelta($sql);
}
?>

部署与优化建议

1. 服务器配置优化

  • 使用Nginx作为WebSocket代理
  • 配置SSL证书确保安全连接
  • 设置适当的WebSocket超时和心跳机制

2. 性能优化策略

  • 实现操作压缩和批量处理
  • 添加离线编辑支持
  • 使用Redis缓存频繁访问的文档状态

3. 安全考虑

  • 实现文档级别的权限控制
  • 添加操作验证和冲突解决机制
  • 记录完整的操作日志用于审计

结论

通过本文的教程,您已经学会了如何在WordPress中开发一个完整的实时协同编辑系统,特别适用于柔性供应链管理场景。这个系统允许供应链中的不同参与者(供应商、制造商、分销商)实时协作编辑文档,大大提高供应链的响应速度和协作效率。

系统采用了现代化的技术栈,包括WebSocket实时通信、React前端框架和WordPress REST API,确保了系统的可扩展性和性能。您可以根据实际需求进一步扩展功能,如添加版本控制、冲突解决算法或与现有供应链管理系统的集成。

记住,实时协同编辑系统的成功不仅取决于技术实现,还需要考虑用户体验、培训支持和组织流程的配合。建议从小规模试点开始,逐步推广到整个供应链网络。

高级功能扩展与优化

4. 操作转换(OT)算法实现

/**
 * 操作转换(OT)算法核心实现
 * 文件名:ot-algorithm.js
 */

class OperationTransformer {
    constructor() {
        this.operations = [];
        this.revision = 0;
    }

    /**
     * 生成基本操作对象
     * @param {string} type - 操作类型: insert/delete/retain
     * @param {*} value - 操作值
     * @param {number} position - 位置
     * @returns {Object} 操作对象
     */
    static createOperation(type, value, position) {
        return {
            type,
            value,
            position,
            revision: Date.now(),
            clientId: this.clientId
        };
    }

    /**
     * 转换操作以解决冲突
     * @param {Object} op1 - 第一个操作
     * @param {Object} op2 - 第二个操作
     * @returns {Array} 转换后的操作对
     */
    transform(op1, op2) {
        if (op1.type === 'retain' && op2.type === 'retain') {
            return this.transformRetainRetain(op1, op2);
        } else if (op1.type === 'insert' && op2.type === 'insert') {
            return this.transformInsertInsert(op1, op2);
        } else if (op1.type === 'delete' && op2.type === 'delete') {
            return this.transformDeleteDelete(op1, op2);
        } else if (op1.type === 'insert' && op2.type === 'delete') {
            return this.transformInsertDelete(op1, op2);
        } else if (op1.type === 'delete' && op2.type === 'insert') {
            return this.transformDeleteInsert(op1, op2);
        }
        
        return [op1, op2];
    }

    /**
     * 转换 retain-retain 操作
     */
    transformRetainRetain(op1, op2) {
        if (op1.position === op2.position) {
            return [op1, op2];
        }
        
        if (op1.position < op2.position) {
            return [
                op1,
                { ...op2, position: op2.position - 1 }
            ];
        } else {
            return [
                { ...op1, position: op1.position - 1 },
                op2
            ];
        }
    }

    /**
     * 转换 insert-insert 操作
     */
    transformInsertInsert(op1, op2) {
        if (op1.position <= op2.position) {
            return [
                op1,
                { ...op2, position: op2.position + op1.value.length }
            ];
        } else {
            return [
                { ...op1, position: op1.position + op2.value.length },
                op2
            ];
        }
    }

    /**
     * 应用操作到文本
     * @param {string} text - 原始文本
     * @param {Object} operation - 要应用的操作
     * @returns {string} 应用后的文本
     */
    applyOperation(text, operation) {
        switch (operation.type) {
            case 'insert':
                return this.applyInsert(text, operation);
            case 'delete':
                return this.applyDelete(text, operation);
            case 'retain':
                return text;
            default:
                return text;
        }
    }

    applyInsert(text, operation) {
        const before = text.slice(0, operation.position);
        const after = text.slice(operation.position);
        return before + operation.value + after;
    }

    applyDelete(text, operation) {
        const before = text.slice(0, operation.position);
        const after = text.slice(operation.position + operation.value.length);
        return before + after;
    }

    /**
     * 批量应用操作
     * @param {string} text - 原始文本
     * @param {Array} operations - 操作数组
     * @returns {string} 应用所有操作后的文本
     */
    applyOperations(text, operations) {
        let result = text;
        operations.forEach(op => {
            result = this.applyOperation(result, op);
        });
        return result;
    }
}

// 导出供其他模块使用
export default OperationTransformer;

5. 冲突解决与版本控制

<?php
/**
 * 冲突解决与版本控制系统
 * 文件名:conflict-resolver.php
 */

class ConflictResolver {
    private $wpdb;
    private $table_name;
    
    public function __construct() {
        global $wpdb;
        $this->wpdb = $wpdb;
        $this->table_name = $wpdb->prefix . 'supplychain_operations';
    }
    
    /**
     * 保存操作记录
     */
    public function save_operation($document_id, $operation, $user_id, $parent_revision) {
        $data = [
            'document_id' => $document_id,
            'operation' => json_encode($operation),
            'user_id' => $user_id,
            'parent_revision' => $parent_revision,
            'revision' => $this->get_next_revision($document_id),
            'created_at' => current_time('mysql'),
            'applied' => 0
        ];
        
        $result = $this->wpdb->insert($this->table_name, $data);
        
        if ($result) {
            return $this->wpdb->insert_id;
        }
        
        return false;
    }
    
    /**
     * 获取下一个版本号
     */
    private function get_next_revision($document_id) {
        $max_revision = $this->wpdb->get_var(
            $this->wpdb->prepare(
                "SELECT MAX(revision) FROM {$this->table_name} WHERE document_id = %s",
                $document_id
            )
        );
        
        return $max_revision ? $max_revision + 1 : 1;
    }
    
    /**
     * 解决操作冲突
     */
    public function resolve_conflicts($document_id, $new_operation, $client_revision) {
        // 获取未应用的操作
        $pending_operations = $this->get_pending_operations($document_id, $client_revision);
        
        if (empty($pending_operations)) {
            return [$new_operation];
        }
        
        $transformed_operations = [];
        $current_op = $new_operation;
        
        // 依次转换操作
        foreach ($pending_operations as $pending_op) {
            $operation_data = json_decode($pending_op->operation, true);
            list($transformed_current, $transformed_pending) = $this->transform_operations(
                $current_op,
                $operation_data
            );
            
            $current_op = $transformed_current;
            $transformed_operations[] = $transformed_pending;
        }
        
        // 标记已解决的操作为已应用
        $this->mark_operations_applied($pending_operations);
        
        return array_merge($transformed_operations, [$current_op]);
    }
    
    /**
     * 获取待处理操作
     */
    private function get_pending_operations($document_id, $since_revision) {
        return $this->wpdb->get_results(
            $this->wpdb->prepare(
                "SELECT * FROM {$this->table_name} 
                 WHERE document_id = %s 
                 AND revision > %d 
                 AND applied = 0 
                 ORDER BY revision ASC",
                $document_id,
                $since_revision
            )
        );
    }
    
    /**
     * 标记操作为已应用
     */
    private function mark_operations_applied($operations) {
        $ids = array_map(function($op) {
            return $op->id;
        }, $operations);
        
        if (!empty($ids)) {
            $ids_string = implode(',', array_map('intval', $ids));
            $this->wpdb->query(
                "UPDATE {$this->table_name} SET applied = 1 WHERE id IN ({$ids_string})"
            );
        }
    }
    
    /**
     * 获取文档完整历史
     */
    public function get_document_history($document_id, $limit = 100) {
        return $this->wpdb->get_results(
            $this->wpdb->prepare(
                "SELECT o.*, u.display_name as user_name 
                 FROM {$this->table_name} o
                 LEFT JOIN {$this->wpdb->users} u ON o.user_id = u.ID
                 WHERE o.document_id = %s 
                 ORDER BY o.revision DESC 
                 LIMIT %d",
                $document_id,
                $limit
            )
        );
    }
    
    /**
     * 回滚到指定版本
     */
    public function rollback_to_revision($document_id, $target_revision) {
        // 获取当前内容
        $current_content = $this->get_document_content($document_id);
        
        // 获取从目标版本到当前版本的所有操作
        $operations = $this->wpdb->get_results(
            $this->wpdb->prepare(
                "SELECT operation FROM {$this->table_name} 
                 WHERE document_id = %s 
                 AND revision > %d 
                 ORDER BY revision ASC",
                $document_id,
                $target_revision
            )
        );
        
        // 反向应用操作以回滚
        $reversed_operations = array_reverse($operations);
        $rolled_back_content = $current_content;
        
        foreach ($reversed_operations as $op) {
            $operation = json_decode($op->operation, true);
            $inverse_op = $this->inverse_operation($operation);
            $rolled_back_content = $this->apply_single_operation(
                $rolled_back_content,
                $inverse_op
            );
        }
        
        return $rolled_back_content;
    }
    
    /**
     * 生成逆操作
     */
    private function inverse_operation($operation) {
        switch ($operation['type']) {
            case 'insert':
                return [
                    'type' => 'delete',
                    'position' => $operation['position'],
                    'value' => $operation['value']
                ];
            case 'delete':
                return [
                    'type' => 'insert',
                    'position' => $operation['position'],
                    'value' => $operation['value']
                ];
            default:
                return $operation;
        }
    }
}

6. 实时协同状态管理

/**
 * 实时协同状态管理器
 * 文件名:collaboration-state.js
 */

class CollaborationStateManager {
    constructor(documentId, userId) {
        this.documentId = documentId;
        this.userId = userId;
        this.connectedUsers = new Map();
        this.cursorPositions = new Map();
        this.selectionRanges = new Map();
        this.presenceTimeout = 30000; // 30秒超时
        
        // 初始化心跳检测
        this.initHeartbeat();
    }
    
    /**
     * 初始化心跳检测
     */
    initHeartbeat() {
        this.heartbeatInterval = setInterval(() => {
            this.sendHeartbeat();
        }, 10000);
        
        // 清理超时用户
        this.cleanupInterval = setInterval(() => {
            this.cleanupInactiveUsers();
        }, 5000);
    }
    
    /**
     * 发送心跳
     */
    sendHeartbeat() {
        if (this.socket && this.socket.connected) {
            this.socket.emit('heartbeat', {
                document_id: this.documentId,
                user_id: this.userId,
                timestamp: Date.now()
            });
        }
    }
    
    /**
     * 更新用户状态
     */
    updateUserPresence(userId, data) {
        const userState = this.connectedUsers.get(userId) || {
            id: userId,
            lastSeen: Date.now(),
            active: true
        };
        
        userState.lastSeen = Date.now();
        userState.active = true;
        userState.name = data.name || userState.name;
        userState.color = data.color || this.generateUserColor(userId);
        
        this.connectedUsers.set(userId, userState);
        
        // 触发状态更新事件
        this.emitStateChange();
    }
    
    /**
     * 更新光标位置
     */
    updateCursorPosition(userId, position, selection) {
        this.cursorPositions.set(userId, {
            position,
            timestamp: Date.now()
        });
        
        if (selection) {
            this.selectionRanges.set(userId, selection);
        }
        
        // 广播光标更新
        this.broadcastCursorUpdate(userId, position, selection);
    }
    
    /**
     * 广播光标更新
     */
    broadcastCursorUpdate(userId, position, selection) {
        if (this.socket) {
            this.socket.emit('cursor_update', {
                document_id: this.documentId,
                user_id: userId,
                cursor_position: position,
                selection_range: selection,
                timestamp: Date.now()
            });
        }
    }
    
    /**
     * 清理不活跃用户
     */
    cleanupInactiveUsers() {
        const now = Date.now();
        const inactiveUsers = [];
        
        this.connectedUsers.forEach((user, userId) => {
            if (now - user.lastSeen > this.presenceTimeout) {
                user.active = false;
                inactiveUsers.push(userId);
            }
        });
        
        // 移除长时间不活跃的用户
        inactiveUsers.forEach(userId => {
            if (userId !== this.userId) {
                this.connectedUsers.delete(userId);
                this.cursorPositions.delete(userId);
                this.selectionRanges.delete(userId);
            }
        });
        
        if (inactiveUsers.length > 0) {
            this.emitStateChange();
        }
    }
    
    /**
     * 生成用户颜色
     */
    generateUserColor(userId) {
        const colors = [
            '#FF6B6B', '#4ECDC4', '#FFD166', '#06D6A0',
            '#118AB2', '#073B4C', '#EF476F', '#7209B7'
        ];
        
        const hash = userId.toString().split('').reduce((acc, char) => {
            return char.charCodeAt(0) + ((acc << 5) - acc);
        }, 0);
        
        return colors[Math.abs(hash) % colors.length];
    }
    
    /**
     * 获取用户光标位置
     */
    getUserCursor(userId) {
        return this.cursorPositions.get(userId);
    }
    
    /**
     * 获取所有活跃用户
     */
    getActiveUsers() {
        const activeUsers = [];
        
        this.connectedUsers.forEach(user => {
            if (user.active) {
                activeUsers.push(user);
            }
        });
        
        return activeUsers;
    }
    
    /**
     * 获取用户选择范围
     */
    getUserSelection(userId) {
        return this.selectionRanges.get(userId);
    }
    
    /**
     * 触发状态变化事件
     */
    emitStateChange() {
        const event = new CustomEvent('collaborationStateChange', {
            detail: {
                users: this.getActiveUsers(),
                cursors: Array.from(this.cursorPositions.entries()),
                selections: Array.from(this.selectionRanges.entries())
            }
        });
        
        window.dispatchEvent(event);
    }
    
    /**
     * 销毁清理
     */
    destroy() {
        if (this.heartbeatInterval) {
            clearInterval(this.heartbeatInterval);
        }
        
        if (this.cleanupInterval) {
            clearInterval(this.cleanupInterval);
        }
        
        // 发送离开通知
        if (this.socket) {
            this.socket.emit('user_left', {
                document_id: this.documentId,
                user_id: this.userId
            });
        }
    }
}

// 导出状态管理器
export default CollaborationStateManager;

7. 供应链特定功能模块

<?php
/**
 * 供应链特定功能模块
 * 文件名:supplychain-features.php
 */

class SupplyChainFeatures {
    
    /**
     * 初始化供应链功能
     */
    public function init() {
        // 添加上下文感知功能
        add_filter('supplychain_document_context', [$this, 'add_supplychain_context']);
        
        // 添加审批工作流
        add_action('supplychain_document_updated', [$this, 'trigger_approval_workflow']);
        
        // 添加库存关联
        add_action('supplychain_item_mentioned', [$this, 'link_inventory_data']);
    }
    
    /**
     * 添加上下文感知数据
     */
    public function add_supplychain_context($document) {
        global $wpdb;
        
        // 获取相关订单信息
        $order_data = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT * FROM {$wpdb->prefix}supplychain_orders 
                 WHERE document_id = %s",
                $document['id']
            )
        );
        
        // 获取供应商信息
        $supplier_data = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT * FROM {$wpdb->prefix}supplychain_suppliers 
                 WHERE id = %d",
                $order_data->supplier_id ?? 0
            )
        );
        
        // 获取库存状态
        $inventory_status = $this->get_inventory_status($document['items']);
        
        return array_merge($document, [
            'order_info' => $order_data,
            'supplier_info' => $supplier_data,
            'inventory_status' => $inventory_status,
            'lead_time' => $this->calculate_lead_time($order_data),
            'risk_level' => $this->assess_risk_level($document)
        ]);
    }
    
    /**
     * 触发审批工作流
     */
    public function trigger_approval_workflow($document_id, $changes) {
        $document = $this->get_document($document_id);
        
        // 检查是否需要审批
        if ($this->requires_approval($document, $changes)) {
            $approvers = $this->get_approvers($document);
            
            foreach ($approvers as $approver) {
                $this->send_approval_request($approver, $document, $changes);
            }
            
            // 更新文档状态为待审批
            $this->update_document_status($document_id, 'pending_approval');
        }
    }
    
    /**
     * 链接库存数据
     */
本文来自网络,不代表柔性供应链服务中心立场,转载请注明出处:https://mall.org.cn/6052.html

EXCHANGES®作者

上一篇
下一篇

为您推荐

发表回复

联系我们

联系我们

18559313275

在线咨询: QQ交谈

邮箱: vip@exchanges.center

工作时间:周一至周五,9:00-17:30,节假日休息
返回顶部