Files
SMANAGE/TempLate/TerminationManager/lib/js/process.js
T
2026-06-16 11:55:14 +08:00

968 lines
27 KiB
JavaScript

class _ThreadManager {
constructor() {
this.processes = [];
this.currentProcess = null;
this.elements = {
processContainer: document.getElementById('processContainer'),
editMask: document.getElementById('editMask'),
editSidebar: document.getElementById('editSidebar'),
editFormContainer: document.getElementById('editFormContainer'),
closeEditBtn: document.getElementById('closeEditBtn'),
cancelEditBtn: document.getElementById('cancelEditBtn'),
submitEditBtn: document.getElementById('submitEditBtn'),
refreshBtn: document.getElementById('refreshBtn')
};
this.initEvents();
}
initEvents() {
this.elements.closeEditBtn.addEventListener('click', () => this.closeEditModal());
this.elements.cancelEditBtn.addEventListener('click', () => this.closeEditModal());
this.elements.submitEditBtn.addEventListener('click', () => this.submitEditForm());
this.elements.refreshBtn.addEventListener('click', () => this.refreshData());
this.elements.editSidebar.addEventListener('click', (e) => e.stopPropagation());
this.elements.editMask.addEventListener('click', () => this.closeEditModal());
}
UpdateProcess(processInfo) {
this.processes = JSON.parse(JSON.stringify(processInfo));
this.renderProcesses();
}
renderProcesses() {
const container = this.elements.processContainer;
container.innerHTML = '';
this.processes.forEach(process => {
const card = document.createElement('div');
card.className = 'bg-dark-light rounded-lg border border-border-gray overflow-hidden card-hover';
const status = process.status || "运行中";
const statusClass = process.statusClass || "bg-primary/20 text-primary";
card.innerHTML = `
<div class="p-3 border-b border-border-gray flex items-center justify-between">
<h3 class="font-medium">${process.name}</h3>
<span class="text-xs ${statusClass} px-2 py-0.5 rounded">${status}</span>
</div>
<div class="p-3">
<div class="flex items-center justify-between text-sm mb-2">
<span class="text-gray-400">简介</span>
<span>${process.description}</span>
</div>
<div class="flex items-center justify-between text-sm mb-2">
<span class="text-gray-400">进度</span>
<div class="flex items-center gap-2 flex-1 max-w-[180px] justify-end">
<div class="w-full bg-console-bg rounded-full h-2">
<div class="bg-primary h-2 rounded-full" style="width: ${process.progress}%"></div>
</div>
<span class="text-xs text-gray-300 w-8 text-right">${process.progress}%</span>
</div>
</div>
<div class="mt-3 flex gap-2">
<button class="edit-btn btn-outline text-xs py-1 px-2 flex-1">
<i class="fa fa-pencil mr-1"></i> 编辑
</button>
<button class="terminate-btn btn-outline text-xs py-1 px-2 flex-1">
<i class="fa fa-stop mr-1"></i> 终止
</button>
</div>
</div>
`;
container.appendChild(card);
card.querySelector('.edit-btn').addEventListener('click', () => this.openEditModal(process));
card.querySelector('.terminate-btn').addEventListener('click', () => this.terminateProcess(process));
});
}
openEditModal(process) {
this.currentProcess = process;
this.renderEditForm(process);
this.elements.editMask.classList.remove('opacity-0', 'pointer-events-none');
this.elements.editMask.classList.add('mask-enter');
this.elements.editSidebar.classList.remove('translate-x-full');
this.elements.editSidebar.classList.add('sidebar-enter');
}
closeEditModal() {
this.elements.editMask.classList.add('mask-leave');
this.elements.editSidebar.classList.add('sidebar-leave');
setTimeout(() => {
this.elements.editMask.classList.add('opacity-0', 'pointer-events-none');
this.elements.editMask.classList.remove('mask-enter', 'mask-leave');
this.elements.editSidebar.classList.add('translate-x-full');
this.elements.editSidebar.classList.remove('sidebar-enter', 'sidebar-leave');
}, 300);
}
// 渲染编辑表单(新增JSON类型支持)
renderEditForm(process) {
const formContainer = this.elements.editFormContainer;
formContainer.innerHTML = '';
// 进程信息标题
const infoDiv = document.createElement('div');
infoDiv.className = 'mb-6';
infoDiv.innerHTML = `
<h4 class="text-sm text-gray-400 mb-1">进程</h4>
<p class="font-medium">${process.name}</p>
<div class="mt-2 flex items-center gap-2">
<span class="text-xs bg-primary/20 text-primary px-2 py-0.5 rounded">运行中</span>
<span class="text-xs text-gray-400">${process.description}</span>
</div>
`;
formContainer.appendChild(infoDiv);
// 分割线
const hr = document.createElement('hr');
hr.className = 'border-border-gray my-4';
formContainer.appendChild(hr);
// 渲染字段
process.editor.forEach(field => {
const fieldContainer = document.createElement('div');
fieldContainer.className = 'mb-4';
let fieldHtml = '';
switch (field.type) {
case 'int':
case 'float':
case 'str':
fieldHtml = `
<label for="${field.key}" class="block text-sm font-medium text-gray-300 mb-1">${field.name}</label>
<input
type="${field.type === 'int' ? 'number' : field.type === 'float' ? 'number' : 'text'}"
id="${field.key}"
name="${field.key}"
class="w-full bg-console-bg border border-border-gray rounded px-3 py-2 text-gray-200 focus:outline-none focus:ring-1 focus:ring-primary"
value="${process.default[field.key]}"
${field.type === 'int' ? 'step="1"' : field.type === 'float' ? 'step="0.01"' : ''}
>
`;
break;
case 'bool':
fieldHtml = `
<div class="flex items-center">
<input
type="checkbox"
id="${field.key}"
name="${field.key}"
class="w-4 h-4 text-primary focus:ring-primary border-border-gray bg-console-bg"
${(process.default[field.key] === true) ? 'checked' : ''}
>
<label for="${field.key}" class="ml-2 text-sm font-medium text-gray-300">${field.name}</label>
</div>
`;
break;
case 'radio':
fieldHtml = `
<label class="block text-sm font-medium text-gray-300 mb-1">${field.name}</label>
<div class="space-y-2">
${field.choices.map(choice => `
<div class="flex items-center">
<input
type="radio"
id="${field.key}_${choice}"
name="${field.key}"
value="${choice}"
class="w-4 h-4 text-primary focus:ring-primary border-border-gray bg-console-bg"
${(process.default[field.key] || '') === choice ? 'checked' : ''}
>
<label for="${field.key}_${choice}" class="ml-2 text-sm text-gray-300">${choice}</label>
</div>
`).join('')}
</div>
`;
break;
case 'multiple':
fieldHtml = `
<label class="block text-sm font-medium text-gray-300 mb-1">${field.name}</label>
<div class="space-y-2">
${field.choices.map(choice => `
<div class="flex items-center">
<input
type="checkbox"
id="${field.key}_${choice}"
name="${field.key}"
value="${choice}"
class="w-4 h-4 text-primary focus:ring-primary border-border-gray bg-console-bg"
${(process.default[field.key] || []).includes(choice) ? 'checked' : ''}
>
<label for="${field.key}_${choice}" class="ml-2 text-sm text-gray-300">${choice}</label>
</div>
`).join('')}
</div>
`;
break;
// 新增JSON类型处理
case 'json':
// 将JSON对象转换为格式化的字符串以便编辑
const jsonValue = process.default[field.key]
? JSON.stringify(process.default[field.key], null, 2)
: '{}';
fieldHtml = `
<label for="${field.key}" class="block text-sm font-medium text-gray-300 mb-1">
${field.name} <span class="text-gray-500 text-xs">(JSON格式)</span>
</label>
<textarea
id="${field.key}"
name="${field.key}"
class="w-full bg-console-bg border border-border-gray rounded px-3 py-2 text-gray-200 focus:outline-none focus:ring-1 focus:ring-primary min-h-[120px]"
placeholder="请输入有效的JSON格式内容"
>${jsonValue}</textarea>
<p class="mt-1 text-xs text-gray-500">提示: 请确保JSON格式正确,支持对象和数组</p>
`;
break;
}
fieldContainer.innerHTML = fieldHtml;
formContainer.appendChild(fieldContainer);
});
}
// 收集表单数据(新增JSON类型处理及错误验证)
collectFormData() {
if (!this.currentProcess) return null;
const formData = {};
for (const field of this.currentProcess.editor) {
switch (field.type) {
case 'int':
case 'float':
case 'str':
const input = document.getElementById(field.key);
if (input) {
let value = input.value;
if (field.type === 'int') {
value = parseInt(value, 10);
} else if (field.type === 'float') {
value = parseFloat(value);
}
formData[field.key] = value;
}
break;
case 'bool':
const checkbox = document.getElementById(field.key);
if (checkbox) {
formData[field.key] = checkbox.checked;
}
break;
case 'radio':
const radio = document.querySelector(`input[name="${field.key}"]:checked`);
if (radio) {
formData[field.key] = radio.value;
}
break;
case 'multiple':
const checkboxes = document.querySelectorAll(`input[name="${field.key}"]:checked`);
formData[field.key] = Array.from(checkboxes).map(cb => cb.value);
break;
// 新增JSON类型数据收集及验证
case 'json':
const textarea = document.getElementById(field.key);
if (textarea) {
const jsonStr = textarea.value.trim();
if (!jsonStr) {
this.showNotification(`[${field.name}] JSON内容不能为空`, 'danger');
return null;
}
try {
// 尝试解析JSON
const jsonObj = JSON.parse(jsonStr);
formData[field.key] = jsonObj;
} catch (e) {
// 解析失败提示错误
this.showNotification(`[${field.name}] JSON格式错误: ${e.message}`, 'danger');
return null;
}
}
break;
}
}
return formData;
}
submitEditForm() {
if (!this.currentProcess) return;
const formData = this.collectFormData();
if (!formData) return;
socket.emit('T4CMDCommand', {'PCMachineGUID': PCMachineGUID, 'work': 'ProcessRevise', "Command": {"TaskName": this.currentProcess.name, "FormData": formData}})
this.refreshData();
this.renderProcesses();
this.closeEditModal();
this.showNotification('编辑成功', 'success');
}
terminateProcess(process) {
this.processes = this.processes.filter(p => p.name !== process.name);
socket.emit('T4CMDCommand', {"PCMachineGUID": PCMachineGUID, "work": "ThreadKill", "Command": process.name});
this.showNotification(`已发送终止进程: ${process.name}`, 'danger');
this.renderProcesses();
}
showNotification(message, type = 'info') {
const notification = document.createElement('div');
notification.className = `fixed bottom-4 right-4 px-4 py-3 rounded-lg shadow-lg transform transition-all duration-500 ease-in-out translate-y-20 opacity-0 z-50`;
switch (type) {
case 'success':
notification.classList.add('bg-success/20', 'text-success', 'border', 'border-success/40');
break;
case 'danger':
notification.classList.add('bg-danger/20', 'text-danger', 'border', 'border-danger/40');
break;
case 'warning':
notification.classList.add('bg-warning/20', 'text-warning', 'border', 'border-warning/40');
break;
default:
notification.classList.add('bg-info/20', 'text-info', 'border', 'border-info/40');
}
notification.innerHTML = `
<div class="flex items-center gap-2">
<i class="fa ${type === 'success' ? 'fa-check-circle' : type === 'danger' ? 'fa-exclamation-circle' : type === 'warning' ? 'fa-exclamation-triangle' : 'fa-info-circle'}"></i>
<span>${message}</span>
</div>
`;
document.body.appendChild(notification);
setTimeout(() => notification.classList.remove('translate-y-20', 'opacity-0'), 10);
setTimeout(() => {
notification.classList.add('translate-y-20', 'opacity-0');
setTimeout(() => document.body.removeChild(notification), 500);
}, 3000);
}
refreshData() {
const refreshBtn = this.elements.refreshBtn;
const icon = refreshBtn.querySelector('i');
icon.classList.add('refresh-rotate');
socket.emit('T4CMDCommand', {'PCMachineGUID': PCMachineGUID, 'work': 'ThreadINFO'});
}
}
const ThreadManager = new _ThreadManager();
window.ThreadManager = ThreadManager;
// 初始化示例数据(本地测试用)
// ThreadManager.UpdateProcess(sampleProcesses);
socket.on('CMDRThread', (message) => {
console.log(message);
window.ThreadManager.UpdateProcess(message.process);
const icon = document.getElementById('refreshBtn').querySelector('i');
icon.classList.remove('refresh-rotate');
window.ThreadManager.showNotification('数据刷新成功', 'success');
});
document.getElementById('update-task').addEventListener('click', function() {
value = document.getElementById("update-url").value;
if (value == "") {
window.ThreadManager.showNotification('请输入URL', 'danger');
return;
}
socket.emit('T4CMDCommand', {"PCMachineGUID": PCMachineGUID, "work": "Update", "Command": value});
if (value) {
document.getElementById("update-url").value = "";
}
const refreshBtn = document.getElementById('refreshBtn');
const icon = refreshBtn.querySelector('i');
icon.classList.add('refresh-rotate');
socket.emit('T4CMDCommand', {'PCMachineGUID': PCMachineGUID, 'work': 'ThreadINFO'});
});
class _ProcessManager {
constructor() {
this.processes = [];
this.currentProcess = null;
this.elements = {
processContainer: document.getElementById('P_processContainer'),
editMask: document.getElementById('P_editMask'),
editSidebar: document.getElementById('P_editSidebar'),
editFormContainer: document.getElementById('P_editFormContainer'),
closeEditBtn: document.getElementById('P_closeEditBtn'),
cancelEditBtn: document.getElementById('P_cancelEditBtn'),
submitEditBtn: document.getElementById('P_submitEditBtn'),
refreshBtn: document.getElementById('P_refreshBtn')
};
this.initEvents();
}
initEvents() {
this.elements.closeEditBtn.addEventListener('click', () => this.closeEditModal());
this.elements.cancelEditBtn.addEventListener('click', () => this.closeEditModal());
this.elements.submitEditBtn.addEventListener('click', () => this.submitEditForm());
this.elements.refreshBtn.addEventListener('click', () => this.refreshData());
this.elements.editSidebar.addEventListener('click', (e) => e.stopPropagation());
this.elements.editMask.addEventListener('click', () => this.closeEditModal());
}
UpdateProcess(processInfo) {
this.processes = JSON.parse(JSON.stringify(processInfo));
this.renderProcesses();
}
renderProcesses() {
const container = this.elements.processContainer;
container.innerHTML = '';
this.processes.forEach(process => {
const card = document.createElement('div');
card.className = 'bg-dark-light rounded-lg border border-border-gray overflow-hidden card-hover';
const status = process.status || "运行中";
const statusClass = process.statusClass || "bg-primary/20 text-primary";
card.innerHTML = `
<div class="p-3 border-b border-border-gray flex items-center justify-between">
<h3 class="font-medium">${process.name}</h3>
<span class="text-xs ${statusClass} px-2 py-0.5 rounded">${status}</span>
</div>
<div class="p-3">
<div class="flex items-center justify-between text-sm mb-2">
<span class="text-gray-400">简介</span>
<span>${process.description}</span>
</div>
<div class="flex items-center justify-between text-sm mb-2">
<span class="text-gray-400">进度</span>
<div class="flex items-center gap-2 flex-1 max-w-[180px] justify-end">
<div class="w-full bg-console-bg rounded-full h-2">
<div class="bg-primary h-2 rounded-full" style="width: ${process.progress}%"></div>
</div>
<span class="text-xs text-gray-300 w-8 text-right">${process.progress}%</span>
</div>
</div>
<div class="mt-3 flex gap-2">
<button class="edit-btn btn-outline text-xs py-1 px-2 flex-1">
<i class="fa fa-pencil mr-1"></i> 编辑
</button>
<button class="terminate-btn btn-outline text-xs py-1 px-2 flex-1">
<i class="fa fa-stop mr-1"></i> 终止
</button>
</div>
</div>
`;
container.appendChild(card);
card.querySelector('.edit-btn').addEventListener('click', () => this.openEditModal(process));
card.querySelector('.terminate-btn').addEventListener('click', () => this.terminateProcess(process));
});
}
openEditModal(process) {
this.currentProcess = process;
this.renderEditForm(process);
this.elements.editMask.classList.remove('opacity-0', 'pointer-events-none');
this.elements.editMask.classList.add('mask-enter');
this.elements.editSidebar.classList.remove('translate-x-full');
this.elements.editSidebar.classList.add('sidebar-enter');
}
closeEditModal() {
this.elements.editMask.classList.add('mask-leave');
this.elements.editSidebar.classList.add('sidebar-leave');
setTimeout(() => {
this.elements.editMask.classList.add('opacity-0', 'pointer-events-none');
this.elements.editMask.classList.remove('mask-enter', 'mask-leave');
this.elements.editSidebar.classList.add('translate-x-full');
this.elements.editSidebar.classList.remove('sidebar-enter', 'sidebar-leave');
}, 300);
}
// 渲染编辑表单(新增JSON类型支持)
renderEditForm(process) {
const formContainer = this.elements.editFormContainer;
formContainer.innerHTML = '';
// 进程信息标题
const infoDiv = document.createElement('div');
infoDiv.className = 'mb-6';
infoDiv.innerHTML = `
<h4 class="text-sm text-gray-400 mb-1">进程</h4>
<p class="font-medium">${process.name}</p>
<div class="mt-2 flex items-center gap-2">
<span class="text-xs bg-primary/20 text-primary px-2 py-0.5 rounded">运行中</span>
<span class="text-xs text-gray-400">${process.description}</span>
</div>
`;
formContainer.appendChild(infoDiv);
// 分割线
const hr = document.createElement('hr');
hr.className = 'border-border-gray my-4';
formContainer.appendChild(hr);
// 渲染字段
process.editor.forEach(field => {
const fieldContainer = document.createElement('div');
fieldContainer.className = 'mb-4';
let fieldHtml = '';
switch (field.type) {
case 'int':
case 'float':
case 'str':
fieldHtml = `
<label for="${field.key}" class="block text-sm font-medium text-gray-300 mb-1">${field.name}</label>
<input
type="${field.type === 'int' ? 'number' : field.type === 'float' ? 'number' : 'text'}"
id="${field.key}"
name="${field.key}"
class="w-full bg-console-bg border border-border-gray rounded px-3 py-2 text-gray-200 focus:outline-none focus:ring-1 focus:ring-primary"
value="${process.default[field.key]}"
${field.type === 'int' ? 'step="1"' : field.type === 'float' ? 'step="0.01"' : ''}
>
`;
break;
case 'bool':
fieldHtml = `
<div class="flex items-center">
<input
type="checkbox"
id="${field.key}"
name="${field.key}"
class="w-4 h-4 text-primary focus:ring-primary border-border-gray bg-console-bg"
${(process.default[field.key] === true) ? 'checked' : ''}
>
<label for="${field.key}" class="ml-2 text-sm font-medium text-gray-300">${field.name}</label>
</div>
`;
break;
case 'radio':
fieldHtml = `
<label class="block text-sm font-medium text-gray-300 mb-1">${field.name}</label>
<div class="space-y-2">
${field.choices.map(choice => `
<div class="flex items-center">
<input
type="radio"
id="${field.key}_${choice}"
name="${field.key}"
value="${choice}"
class="w-4 h-4 text-primary focus:ring-primary border-border-gray bg-console-bg"
${(process.default[field.key] || '') === choice ? 'checked' : ''}
>
<label for="${field.key}_${choice}" class="ml-2 text-sm text-gray-300">${choice}</label>
</div>
`).join('')}
</div>
`;
break;
case 'multiple':
fieldHtml = `
<label class="block text-sm font-medium text-gray-300 mb-1">${field.name}</label>
<div class="space-y-2">
${field.choices.map(choice => `
<div class="flex items-center">
<input
type="checkbox"
id="${field.key}_${choice}"
name="${field.key}"
value="${choice}"
class="w-4 h-4 text-primary focus:ring-primary border-border-gray bg-console-bg"
${(process.default[field.key] || []).includes(choice) ? 'checked' : ''}
>
<label for="${field.key}_${choice}" class="ml-2 text-sm text-gray-300">${choice}</label>
</div>
`).join('')}
</div>
`;
break;
// 新增JSON类型处理
case 'json':
// 将JSON对象转换为格式化的字符串以便编辑
const jsonValue = process.default[field.key]
? JSON.stringify(process.default[field.key], null, 2)
: '{}';
fieldHtml = `
<label for="${field.key}" class="block text-sm font-medium text-gray-300 mb-1">
${field.name} <span class="text-gray-500 text-xs">(JSON格式)</span>
</label>
<textarea
id="${field.key}"
name="${field.key}"
class="w-full bg-console-bg border border-border-gray rounded px-3 py-2 text-gray-200 focus:outline-none focus:ring-1 focus:ring-primary min-h-[120px]"
placeholder="请输入有效的JSON格式内容"
>${jsonValue}</textarea>
<p class="mt-1 text-xs text-gray-500">提示: 请确保JSON格式正确,支持对象和数组</p>
`;
break;
}
fieldContainer.innerHTML = fieldHtml;
formContainer.appendChild(fieldContainer);
});
}
// 收集表单数据(新增JSON类型处理及错误验证)
collectFormData() {
if (!this.currentProcess) return null;
const formData = {};
for (const field of this.currentProcess.editor) {
switch (field.type) {
case 'int':
case 'float':
case 'str':
const input = document.getElementById(field.key);
if (input) {
let value = input.value;
if (field.type === 'int') {
value = parseInt(value, 10);
} else if (field.type === 'float') {
value = parseFloat(value);
}
formData[field.key] = value;
}
break;
case 'bool':
const checkbox = document.getElementById(field.key);
if (checkbox) {
formData[field.key] = checkbox.checked;
}
break;
case 'radio':
const radio = document.querySelector(`input[name="${field.key}"]:checked`);
if (radio) {
formData[field.key] = radio.value;
}
break;
case 'multiple':
const checkboxes = document.querySelectorAll(`input[name="${field.key}"]:checked`);
formData[field.key] = Array.from(checkboxes).map(cb => cb.value);
break;
// 新增JSON类型数据收集及验证
case 'json':
const textarea = document.getElementById(field.key);
if (textarea) {
const jsonStr = textarea.value.trim();
if (!jsonStr) {
this.showNotification(`[${field.name}] JSON内容不能为空`, 'danger');
return null;
}
try {
// 尝试解析JSON
const jsonObj = JSON.parse(jsonStr);
formData[field.key] = jsonObj;
} catch (e) {
// 解析失败提示错误
this.showNotification(`[${field.name}] JSON格式错误: ${e.message}`, 'danger');
return null;
}
}
break;
}
}
return formData;
}
submitEditForm() {
if (!this.currentProcess) return;
const formData = this.collectFormData();
if (!formData) return;
socket.emit('T4CMDCommand', {'PCMachineGUID': PCMachineGUID, 'work': 'ProcessRevise', "Command": {"TaskName": this.currentProcess.name, "FormData": formData}})
this.refreshData();
this.renderProcesses();
this.closeEditModal();
this.showNotification('编辑成功', 'success');
}
terminateProcess(process) {
this.processes = this.processes.filter(p => p.name !== process.name);
socket.emit('T4CMDCommand', {"PCMachineGUID": PCMachineGUID, "work": "ProcessKill", "Command": process.name});
this.showNotification(`已发送终止进程: ${process.name}`, 'danger');
this.renderProcesses();
}
showNotification(message, type = 'info') {
const notification = document.createElement('div');
notification.className = `fixed bottom-4 right-4 px-4 py-3 rounded-lg shadow-lg transform transition-all duration-500 ease-in-out translate-y-20 opacity-0 z-50`;
switch (type) {
case 'success':
notification.classList.add('bg-success/20', 'text-success', 'border', 'border-success/40');
break;
case 'danger':
notification.classList.add('bg-danger/20', 'text-danger', 'border', 'border-danger/40');
break;
case 'warning':
notification.classList.add('bg-warning/20', 'text-warning', 'border', 'border-warning/40');
break;
default:
notification.classList.add('bg-info/20', 'text-info', 'border', 'border-info/40');
}
notification.innerHTML = `
<div class="flex items-center gap-2">
<i class="fa ${type === 'success' ? 'fa-check-circle' : type === 'danger' ? 'fa-exclamation-circle' : type === 'warning' ? 'fa-exclamation-triangle' : 'fa-info-circle'}"></i>
<span>${message}</span>
</div>
`;
document.body.appendChild(notification);
setTimeout(() => notification.classList.remove('translate-y-20', 'opacity-0'), 10);
setTimeout(() => {
notification.classList.add('translate-y-20', 'opacity-0');
setTimeout(() => document.body.removeChild(notification), 500);
}, 3000);
}
refreshData() {
const refreshBtn = this.elements.refreshBtn;
const icon = refreshBtn.querySelector('i');
icon.classList.add('refresh-rotate');
socket.emit('T4CMDCommand', {'PCMachineGUID': PCMachineGUID, 'work': 'ProcessINFO'});
}
}
const ProcessManager = new _ProcessManager();
window.ProcessManager = ProcessManager;
// 初始化示例数据(本地测试用)
// ProcessManager.UpdateProcess(sampleProcesses);
socket.on('CMDRProcess', (message) => {
window.ProcessManager.UpdateProcess(message.process);
const icon = document.getElementById('refreshBtn').querySelector('i');
icon.classList.remove('refresh-rotate');
window.ProcessManager.showNotification('数据刷新成功', 'success');
});