文章目录[隐藏]
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');
}
}
/**
* 链接库存数据
*/
