您的位置:首页 > 健康 > 美食 > 平面设计去哪里学比较好_二级域名如何申请_扬州百度推广公司_搜索引擎的工作原理分为

平面设计去哪里学比较好_二级域名如何申请_扬州百度推广公司_搜索引擎的工作原理分为

2025/1/4 8:02:17 来源:https://blog.csdn.net/yf18040578780/article/details/144817109  浏览:    关键词:平面设计去哪里学比较好_二级域名如何申请_扬州百度推广公司_搜索引擎的工作原理分为
平面设计去哪里学比较好_二级域名如何申请_扬州百度推广公司_搜索引擎的工作原理分为

 xterm.js    下载插件

// xterm
npm install --save xterm// xterm-addon-fit    使终端适应包含元素
npm install --save xterm-addon-fit// xterm-addon-attach   通过websocket附加到运行中的服务器进程
npm install --save xterm-addon-attach
<template><div :class="props.type ? 'height305' : 'height160'"><el-row><el-col :span="20"><div:class="['xterm', props.type ? 'heightA' : 'heightB']"ref="terminal"v-loading="loading"element-loading-text="拼命连接中"><div class="terminal" id="terminal" ref="terminal"></div></div><div class="textarea"><textarea ref="textarea" v-model="quickCmd" /><div class="bottomOperate flexEnd"><el-button type="primary" @click="sendCmd" :disabled="!quickCmd">发送命令</el-button></div></div></el-col><el-col :span="4"><div :class="['xtermR', props.type ? 'heightA' : 'heightBR']"><el-tabsv-model="tabActiveName"class="demo-tabs"@tab-click="handleClick"><el-tab-pane label="常用命令" name="first"><div v-if="filteredGroups?.length > 0"><div class="marginBottom10"><el-buttontype="primary"size="small"@click="addCmdGroup('addGroup')">新增命令组</el-button><el-button type="primary" size="small" @click="addCmd('add')">新增命令</el-button></div><el-collapsev-loading="loadingR":class="props.type ? 'listBoxA' : 'listBoxB'"><el-collapse-itemv-for="group in filteredGroups":name="group.name":key="group.name"class="custom-collapse-item"><template #title><divclass="flexSpaceBetween"style="width: 100%"@mouseenter="showActions(group.id, true)"@mouseleave="showActions(group.id, false)"><span class="collapse-title">{{ group.name }}</span><span v-show="actionStates[group.id]"><el-buttonlinktype="primary"@click="addCmdGroup('editGroup', group, $event)">编辑</el-button><el-buttonlinktype="primary"@click="del(group.id, 'group', $event)">删除</el-button></span></div></template><template #default><divv-for="item in group.device_command":key="item.id"class="item flexSpaceBetween paddingRight20 marginBottom10"@mouseenter="showActions1(item.id, true)"@mouseleave="showActions1(item.id, false)"><spanclass="usualName"@click="getName(item.name)":title="item.name">{{ item.name }}</span><span v-show="actionStates1[item.id]" class="btns"><el-buttonlinktype="primary"@click="addCmd('edit', item, group.id)">编辑</el-button><el-button link type="primary" @click="del(item.id)">删除</el-button></span></div></template></el-collapse-item></el-collapse></div><div class="flexCenter" v-else>暂无常用命令</div></el-tab-pane><el-tab-pane label="命令记录" name="second"><div:class="props.type ? 'listBoxA' : 'listBoxB'"v-if="globalStore.cmdRecordList?.length > 0"><divv-for="item in globalStore.cmdRecordList":key="item"class="item flexSpaceBetween paddingRight20 marginBottom10"><span class="recordName" @click="getName(item)">{{item}}</span></div></div><div class="flexCenter" v-else>暂无命令记录</div></el-tab-pane></el-tabs></div></el-col></el-row></div><!-- 新增命令组 --><AddTerminalGroup ref="addTerminalGroup" /><!-- 新增命令 --><AddTerminal ref="addTerminal" />
</template>
<script setup>
import "xterm/css/xterm.css";
import { Terminal } from "xterm";
import { FitAddon } from "xterm-addon-fit";
import { debounce } from "lodash";
import { ElMessage, ElMessageBox } from "element-plus";
import {ref,reactive,onMounted,onBeforeUnmount,computed,nextTick,getCurrentInstance,
} from "vue";
import { useGlobalStore } from "@/stores/modules/global.js";
import AddTerminalGroup from "./AddTerminalGroup.vue";
import AddTerminal from "./AddTerminal.vue";
import {commandGroupIndex,commandGroupDel,commandDel,
} from "@/api/equipment";
import { WebSocketUrl } from "@/api/request";const props = defineProps({type: {type: String,default: () => {return "";},},currentPathRes: {type: String,default: () => {return "/";},},
});
const globalStore = useGlobalStore();
const { proxy } = getCurrentInstance();
const searchTerm = ref("");
const tabActiveName = ref("first");
const cmdRecordList = ref(globalStore.cmdRecordList); // 命令历史记录
const loadingR = ref(false);
const groups = ref([]);
const quickCmd = ref("");
const actionStates = ref({});
const actionStates1 = ref({});const filteredGroups = computed(() => {if (!searchTerm.value) {return groups.value;}return groups.value.map((group) => {const filteredItems = group.device_command.filter((item) =>item.includes(searchTerm.value));return {...group,device_command: filteredItems,};}).filter((group) => group.device_command.length > 0);
});const showActions = (id, show) => {actionStates.value[id] = show;
};const showActions1 = (id, show) => {actionStates1.value[id] = show;
};const addCmdGroup = (type, row, event) => {if (event) event.stopPropagation();nextTick(() => {proxy.$refs["addTerminalGroup"].showDialog({type,row,});});
};const addCmd = (type, row, group_id) => {nextTick(() => {proxy.$refs["addTerminal"].showDialog({type,groupList: groups.value,row,group_id,});});
};const getName = (val) => {quickCmd.value = val;
};// 发送命令
const sendCmd = () => {if (isWsOpen()) {terminalSocket.value.send(quickCmd.value);// 处理命令历史记录handleCmdRecordList(quickCmd.value);}
};const handleCmdRecordList = (newCmd) => {if (newCmd) {// 对新命令进行trim处理const trimmedCmd = newCmd.trim();// 检查是否有重复值并删除const index = cmdRecordList.value.indexOf(trimmedCmd);if (index !== -1) {cmdRecordList.value.splice(index, 1);}// 将新命令添加到数组最前面cmdRecordList.value.unshift(trimmedCmd);globalStore.setCmdRecordList(cmdRecordList.value);}
};const del = (id, group, event) => {if (event) event.stopPropagation();ElMessageBox.confirm("确认删除吗?", "删除", {confirmButtonText: "确定",cancelButtonText: "取消",type: "warning",}).then(() => {if (group) {commandGroupDel({ id }).then((res) => {if (res.status === 200) {ElMessage.success("删除成功");getTableData();}});} else {commandDel({ id }).then((res) => {if (res.status === 200) {ElMessage.success("删除成功");getTableData();}});}}).catch(() => {});
};//获取表格数据
const getTableData = () => {loadingR.value = true;commandGroupIndex().then((res) => {loadingR.value = false;if (res.status === 200) {groups.value = res.data?.list;}}).catch((error) => {loadingR.value = false;});
};
// 命令列表
getTableData();
//终端信息
const loading = ref(false);
const terminal = ref(null);
const fitAddon = new FitAddon();
let first = ref(true);
let terminalSocket = ref(null);
let term = ref(null);// 初始化WS
const initWS = () => {if (!terminalSocket.value) {createWS();}if (terminalSocket.value && terminalSocket.value.readyState > 1) {terminalSocket.value.close();createWS();}
};// 创建WS
const createWS = () => {loading.value = true;terminalSocket.value = new WebSocket(WebSocketUrl + globalStore.wsUrl);terminalSocket.value.onopen = runRealTerminal; //WebSocket 连接已建立terminalSocket.value.onmessage = onWSReceive; //收到服务器消息terminalSocket.value.onclose = closeRealTerminal; //WebSocket 连接已关闭terminalSocket.value.onerror = errorRealTerminal; //WebSocket 连接出错
};//WebSocket 连接已建立
const runRealTerminal = () => {loading.value = false;let sendData = JSON.stringify({t: "conn",});terminalSocket.value.send(sendData);
};
//WebSocket收到服务器消息
const onWSReceive = (event) => {// 首次接收消息,发送给后端,进行同步适配尺寸if (first.value === true) {first.value = false;resizeRemoteTerminal();if (props.type === "termDia") {autoWriteInfo();}}const blob = new Blob([event.data.toString()], {type: "text/plain",});//将Blob 对象转换成字符串const reader = new FileReader();reader.readAsText(blob, "utf-8");reader.onload = (e) => {// 可以根据返回值判断使用何种颜色或者字体,不过返回值自带了一些字体颜色writeOfColor(reader.result);};
};//WebSocket 连接出错
const errorRealTerminal = (ex) => {let message = ex.message;if (!message) message = "disconnected";term.value.write(`\x1b[31m${message}\x1b[m\r\n`);loading.value = false;
};
//WebSocket 连接已关闭
const closeRealTerminal = () => {loading.value = false;
};// 初始化Terminal
const initTerm = () => {term.value = new Terminal({rendererType: "canvas", //渲染类型// rows: 50, //行数,影响最小高度// cols: 100, // 列数,影响最小宽度convertEol: true, //启用时,光标将设置为下一行的开头// scrollback: 50, //终端中的滚动条回滚量disableStdin: false, //是否应禁用输入。cursorStyle: "underline", //光标样式cursorBlink: true, //光标闪烁theme: {foreground: "#F8F8F8",background: "#2D2E2C",cursor: "help", //设置光标lineHeight: 16,},fontFamily: '"Cascadia Code", Menlo, monospace',});// writeDefaultInfo();// 弹框自动输入term.value.open(terminal.value); //挂载dom窗口term.value.loadAddon(fitAddon); //自适应尺寸term.value.focus();termData(); //Terminal 事件挂载
};const autoWriteInfo = () => {let sendData = "\n" + "cd " + props.currentPathRes + "\n";// term.value.write(`\x1b[37m${sendData}\x1b[m`);// term.value.write("\r\n");if (isWsOpen()) {terminalSocket.value.send(sendData);}
};const writeDefaultInfo = () => {let defaultInfo = ["┌\x1b[1m terminals \x1b[0m─────────────────────────────────────────────────────────────────┐ ","│                                                                            │ ","│  \x1b[1;34m 欢迎使用XS  SSH   \x1b[0m                                                       │ ","│                                                                            │ ","└────────────────────────────────────────────────────────────────────────────┘ ",];term.value.write(defaultInfo.join("\n\r"));term.value.write("\r\n");// writeOfColor('我是加粗斜体红色的字呀', '1;3;', '31m')
};const writeOfColor = (txt, fontCss = "", bgColor = "") => {// 在Linux脚本中以 \x1B[ 开始,中间前部分是样式+内容,以 \x1B[0m 结尾// 示例 \x1B[1;3;31m 内容 \x1B[0m// fontCss// 0;-4;字体样式(0;正常 1;加粗 2;变细 3;斜体 4;下划线)// bgColor// 30m-37m字体颜色(30m:黑色 31m:红色 32m:绿色 33m:棕色字 34m:蓝色 35m:洋红色/紫色 36m:蓝绿色/浅蓝色 37m:白色)// 40m-47m背景颜色(40m:黑色 41m:红色 42m:绿色 43m:棕色字 44m:蓝色 45m:洋红色/紫色 46m:蓝绿色/浅蓝色 47m:白色)// console.log("writeOfColor", term)term.value.write(`\x1b[37m${fontCss}${bgColor}${txt}\x1b[m`);// term.value.write(`\x1B[${fontCss}${bgColor}${txt}\x1B[0m`);
};// 终端输入触发事件
const termData = () => {fitAddon.fit();// 输入与粘贴的情况,onData不能重复绑定,不然会发送多次term.value.onData((data) => {// console.log(data, "传入服务器");if (isWsOpen()) {terminalSocket.value.send(data);}});// 终端尺寸变化触发term.value.onResize(() => {resizeRemoteTerminal();});
};//尺寸同步 发送给后端,调整后端终端大小,和前端保持一致,不然前端只是范围变大了,命令还是会换行
const resizeRemoteTerminal = () => {const { cols, rows } = term.value;if (isWsOpen()) {terminalSocket.value.send(JSON.stringify({t: "resize",width: rows,height: cols,}));}
};// 是否连接中0 1 2 3 状态
const isWsOpen = () => {// console.log(terminalSocket.value, "terminalSocket.value");const readyState = terminalSocket.value && terminalSocket.value.readyState;return readyState === 1;
};// 适应浏览器尺寸变化
const fitTerm = () => {fitAddon.fit();
};
const onResize = debounce(() => fitTerm(), 500);
const onTerminalResize = () => {window.addEventListener("resize", onResize);
};
const removeResizeListener = () => {window.removeEventListener("resize", onResize);
};//*生命周期函数
onMounted(() => {initWS();initTerm();onTerminalResize();
});onBeforeUnmount(() => {removeResizeListener();let sendData = JSON.stringify({t: "close",});if (isWsOpen()) {terminalSocket.value.send(sendData);terminalSocket.value && terminalSocket.value.close();}
});// 暴露方法
defineExpose({ getTableData });
</script>
<style lang="scss" scoped>
.xterm {position: relative;width: 100%;background: rgb(45, 46, 44);
}.xtermR {position: relative;width: 100%;background: #fff;padding: 10px;position: relative;// overflow: hidden;.listBoxA {overflow-y: auto;height: calc(100vh - 450px);}.listBoxB {overflow-y: auto;height: calc(100vh - 300px);}
}.heightA {height: calc(100vh - 400px);
}
.heightB {height: calc(100vh - 235px);
}
.heightBR {height: calc(100vh - 155px);
}.usualName {width: calc(100% - 80px);display: inline-block;cursor: pointer;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;
}.btns {width: 80px;
}.textarea {overflow: hidden;position: relative;height: 80px;background: #ffffff;textarea {width: 100%;height: 90px;border: 0 none;outline: none;resize: none;font-size: 15px;overflow-y: auto;padding: 5px;background: #ffffff;}.bottomOperate {position: absolute;right: 10px;bottom: 10px;}
}
.recordName {font-size: 13px;color: #303133;cursor: pointer;margin-bottom: 10px;width: 100%;
}
.flexCenter {font-size: 14px;padding-top: 150px;
}
</style>

 此页面兼容了弹框和非弹框页面,做了两种样式处理判断

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com