187 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			QML
		
	
	
	
			
		
		
	
	
			187 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			QML
		
	
	
	
| import QtQuick 2.15
 | ||
| import QtQuick.Window 2.15
 | ||
| import QtQuick.Controls 2.15
 | ||
| import HuskarUI.Basic 1.0
 | ||
| import "../MyGlobals" 1.0
 | ||
| import SSHManager 1.0
 | ||
| 
 | ||
| 
 | ||
| Item {
 | ||
|     visible: true
 | ||
| 
 | ||
|     // SSH控制台输出显示区域
 | ||
|     Item {
 | ||
|         id:consolearea
 | ||
|         anchors {
 | ||
|             fill: parent
 | ||
|             margins: 10
 | ||
|             bottomMargin: 46
 | ||
|         }
 | ||
| 
 | ||
|         ScrollView {
 | ||
|             id: scrollView
 | ||
|             anchors.fill: parent
 | ||
|             clip: true
 | ||
| 
 | ||
|             TextArea {
 | ||
|                 id: consoleOutput
 | ||
|                 selectByMouse: true
 | ||
|                 textFormat: Text.RichText
 | ||
|                 readOnly: true
 | ||
|                 wrapMode: Text.WrapAnywhere
 | ||
|                 font {
 | ||
|                     pixelSize: 14
 | ||
|                     family: HusTheme.Primary.fontPrimaryFamily
 | ||
|                 }
 | ||
|                 color: HusTheme.Primary.colorTextBase
 | ||
|                 background: Rectangle {
 | ||
|                     color: HusTheme.isDark ? "#2d2d2d" : "#f5f5f5"
 | ||
|                     radius: 4
 | ||
|                 }
 | ||
| 
 | ||
|                 // 自动滚动到底部
 | ||
|                 onTextChanged: {
 | ||
|                     if (length > 0) {
 | ||
|                         cursorPosition = length
 | ||
|                     }
 | ||
|                 }
 | ||
|             }
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     HusInput {
 | ||
|         id: inputField
 | ||
|         width: consolearea.width
 | ||
|         iconPosition: HusInput.Position_Left
 | ||
|         iconSource: HusIcon.ForwardOutlined
 | ||
|         placeholderText: qsTr("这里可以输入服务器命令")
 | ||
|         anchors {
 | ||
|             top: consolearea.bottom
 | ||
|             topMargin: 6
 | ||
|             horizontalCenter: parent.horizontalCenter
 | ||
|         }
 | ||
| 
 | ||
|         // 添加回车键事件
 | ||
|         onAccepted: {
 | ||
|             SSHManager.sendInput(text)
 | ||
|             text = ""
 | ||
|         }
 | ||
| 
 | ||
|         // 监听 Ctrl+C
 | ||
|         Keys.onPressed: (event) => {
 | ||
|                             if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_C) {
 | ||
|                                 SSHManager.sendInput("\x03")
 | ||
|                             }
 | ||
|                         }
 | ||
|     }
 | ||
| 
 | ||
| 
 | ||
|     // ANSI转HTML的转换逻辑
 | ||
|     function ansiToHtml(text) {
 | ||
|         // 第一步:处理颜色代码
 | ||
|         let colored = text.replace(/\x1B\[([0-9;]*)m/g, function(match, codes) {
 | ||
|             let styles = [];
 | ||
|             for (let code of codes.split(';')) {
 | ||
|                 switch (parseInt(code)) {
 | ||
|                 case 0:
 | ||
|                     return "</span>";
 | ||
|                 case 1:
 | ||
|                     styles.push("font-weight:bold");
 | ||
|                     break;
 | ||
|                 case 3:
 | ||
|                     styles.push("font-style:italic");
 | ||
|                     break;
 | ||
|                 case 4:
 | ||
|                     styles.push("text-decoration:underline");
 | ||
|                     break;
 | ||
|                 case 30:
 | ||
|                     styles.push("color:black");
 | ||
|                     break;
 | ||
|                 case 31:
 | ||
|                     styles.push("color:red");
 | ||
|                     break;
 | ||
|                 case 32:
 | ||
|                     styles.push("color:green");
 | ||
|                     break;
 | ||
|                 case 33:
 | ||
|                     styles.push("color:yellow");
 | ||
|                     break;
 | ||
|                 case 34:
 | ||
|                     styles.push("color:blue");
 | ||
|                     break;
 | ||
|                 case 35:
 | ||
|                     styles.push("color:magenta");
 | ||
|                     break;
 | ||
|                 case 36:
 | ||
|                     styles.push("color:cyan");
 | ||
|                     break;
 | ||
|                 case 37:
 | ||
|                     styles.push("color:white");
 | ||
|                     break;
 | ||
|                 case 40:
 | ||
|                     styles.push("background-color:black");
 | ||
|                     break;
 | ||
|                     // 其他颜色代码...
 | ||
|                 }
 | ||
|             }
 | ||
|             return styles.length ? `<span style="${styles.join(';')}">` : "";
 | ||
|         });
 | ||
| 
 | ||
|         // 第二步:清除所有 ANSI 转义序列(包括 XTerm 标题、控制序列等)
 | ||
|         let cleaned = colored
 | ||
|         //删除 XTerm 窗口标题序列(格式:\x1B]0;标题\x07 或 \x1B]0;标题\x1B\)
 | ||
|         .replace(/\x1B\][^\x07]*(?:\x07|\x1B\\)/g, '')
 | ||
|         //删除其他 ANSI 控制序列(包括以 ? 开头的模式设置,如 ?1034h)
 | ||
|         .replace(/\x1B\[[1034h;?]*[A-Za-z]/g, '');
 | ||
| 
 | ||
|         return cleaned;
 | ||
|     }
 | ||
| 
 | ||
|     function connectionSuccess(){
 | ||
| 
 | ||
|     }
 | ||
| 
 | ||
|     function connectionFailed(error){
 | ||
|         consoleOutput.text += "连接服务器失败"  + error + "\n"
 | ||
|     }
 | ||
| 
 | ||
|     function disconnected(){
 | ||
|         consoleOutput.text += "服务器断开连接\n"
 | ||
|     }
 | ||
| 
 | ||
|     function updateStatus(msg) {
 | ||
|         consoleOutput.text += (msg + "\n")
 | ||
|     }
 | ||
| 
 | ||
|     function appendOutput(msg) {
 | ||
|         // 转义 HTML 特殊字符
 | ||
|         const safeMsg = msg.replace(/</g, "<").replace(/>/g, ">").replace(/\n/g, "<br>"); // 新增换行符转换
 | ||
|         const zemsg = ansiToHtml("> " + safeMsg)
 | ||
|         consoleOutput.text += zemsg;
 | ||
|     }
 | ||
| 
 | ||
| 
 | ||
|     // 初始化后自动连接示例(可选)
 | ||
|     Component.onCompleted: {
 | ||
|         SSHManager.connectionSuccess.connect(connectionSuccess)
 | ||
|         SSHManager.connectionFailed.connect(connectionFailed)
 | ||
|         SSHManager.statusMessage.connect(updateStatus)
 | ||
|         SSHManager.disconnected.connect(disconnected)
 | ||
| 
 | ||
|         SSHManager.shellOutput.connect(appendOutput)
 | ||
|         consoleOutput.text = "控制台已就绪...\n"
 | ||
|     }
 | ||
| 
 | ||
|     // 窗口关闭时自动触发清理
 | ||
|     Component.onDestruction: {
 | ||
|         // 断开所有信号连接
 | ||
|         SSHManager.connectionSuccess.disconnect(connectionSuccess);
 | ||
|         SSHManager.connectionFailed.disconnect(connectionFailed);
 | ||
|         SSHManager.statusMessage.disconnect(updateStatus);
 | ||
|         SSHManager.disconnected.disconnect(disconnected);
 | ||
|         SSHManager.shellOutput.disconnect(appendOutput);
 | ||
|         console.log("窗口关闭,已断开所有信号连接并清理资源。");
 | ||
|     }
 | ||
| 
 | ||
| }
 |