diff --git a/package.json b/package.json index 1c9d983..2105c9d 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,10 @@ "prettier --parser=typescript --write" ] }, - "dependencies": {}, + "dependencies": { + "xterm": "^5.3.0", + "xterm-addon-fit": "^0.8.0" + }, "devDependencies": { "@changesets/cli": "^2.27.1", "@commitlint/cli": "^17.1.2", diff --git a/packages/material/src/index.tsx b/packages/material/src/index.tsx index 8f16ac8..e7a57e6 100644 --- a/packages/material/src/index.tsx +++ b/packages/material/src/index.tsx @@ -3,5 +3,6 @@ export { default as AlgorithmConfig } from './algorithmConfig'; export type { AlgorithmConfigRef, AlgorithmConfigProps } from './algorithmConfig'; export { default as Login } from './login'; export { default as Password } from './password'; +export { default as Terminal } from './terminal'; export { default as SchemaFormModal } from './algorithmConfig/components/schemaFormModal'; export * from 'rc-util' diff --git a/packages/material/src/terminal/Terminal.tsx b/packages/material/src/terminal/Terminal.tsx new file mode 100644 index 0000000..2743f95 --- /dev/null +++ b/packages/material/src/terminal/Terminal.tsx @@ -0,0 +1,63 @@ +import { Button, Form, Input,FormProps } from '@zhst/meta'; +import React from 'react'; +import WebTerminal from './components/WebTerminal'; + +interface TerminalProps{ + onFinish:FormProps['onFinish'] +} + +const Terminal: React.FC = (props:TerminalProps) => { + const {onFinish}=props; + const [form] = Form.useForm(); + + const handleCenterConnect = async () => { + const values = await form.validateFields(); + onFinish&&onFinish(values); + }; + + return ( +
+

连接中心服务器

+
+ + + + + + +
+
+ +
+
+ ); +}; + +export default Terminal; diff --git a/packages/material/src/terminal/components/WebTerminal.tsx b/packages/material/src/terminal/components/WebTerminal.tsx new file mode 100644 index 0000000..b2d316c --- /dev/null +++ b/packages/material/src/terminal/components/WebTerminal.tsx @@ -0,0 +1,114 @@ +// import { getToken } from '@libs/auth'; +import React, { Component } from 'react'; +import { Terminal } from 'xterm'; +import { FitAddon } from 'xterm-addon-fit'; +import 'xterm/css/xterm.css'; + +// TODO:引入xterm 后续需要和后端在建立websocket连接再次调试 +export default class WebTerminal extends Component { + term = null; + websocket = null; + curr_line = ''; + componentDidMount() { + let term = this.term; + this.term = new Terminal({ + fontFamily: 'Menlo, Monaco, "Courier New", monospace', + fontWeight: 400, + fontSize: 14, + rows: Math.ceil( + (document.getElementsByClassName('container-children')[0].clientHeight - + 150) / + 14, + ), + }); + this.term.open(document.getElementById('terminal')); + this.term.focus(); + this.term.prompt = (_) => { + this.term.write('\r\n\x1b[33m$\x1b[0m '); + }; + this.term.prompt(); + const fitAddon = new FitAddon(); + this.term.loadAddon(fitAddon); + fitAddon.fit(); + this.term.prompt(); + // this.term.attachCustomKeyEventHandler((e) => { + // console.log({ e }); + // // e = e.target; + // var keyCode = e.keyCode || e.which || e.charCode; + // const moveKey = [37, 38, 39, 40].includes(keyCode); + // if (moveKey) return false; + // }); + // 添加事件监听器,支持输入方法 + this.term.onKey((e) => { + const printable = + !e.domEvent.altKey && + !e.domEvent.altGraphKey && + !e.domEvent.ctrlKey && + !e.domEvent.metaKey; + if (e.domEvent.keyCode === 13) { + this.Send(term, this.curr_line); + this.term.prompt(); + this.curr_line = ''; + } else if (e.domEvent.keyCode === 8) { + // back 删除的情况 + if (this.term._core.buffer.x > 2) { + if (this.curr_line.length) { + this.curr_line = this.curr_line.slice(0, this.curr_line.length - 1); + this.term.write('\b \b'); + } else { + } + } + } else if (printable) { + this.curr_line += e.key; + this.term.write(e.key); + } + this.term.focus(); + console.log(1, 'print', e.key); + }); + this.term.onData((key) => { + // 粘贴的情况 + if (key.length > 1) { + this.term.write(key); + this.curr_line += key; + } + }); + this.initWebsock(); + } + componentWillUnmount() { + this.term.dispose(); + this.websocket.close(); + } + initWebsock = () => { + // let websocket = this.websocket; + let term = this.term; + let token = 'aaaa'; + this.websocket = new WebSocket('ws://' + window?._CONFIG?.WsSsh!, token); + this.websocket.onopen = function (evt) { + term.write('connect'); + }; + this.websocket.onclose = function (evt) { + term.write('exit'); + }; + this.websocket.onmessage = function (evt) { + term.write(evt.data); + }; + this.websocket.onerror = function (evt) { + term.write('connect fail err:' + evt.data); + }; + }; + // prompt = (term) => { + // this.term.write('\r\n~$ '); + // }; + + Send = (term, message) => { + this.websocket.send(message); + }; + + render() { + return ( +
+
+
+ ); + } +} diff --git a/packages/material/src/terminal/demo/basic.tsx b/packages/material/src/terminal/demo/basic.tsx new file mode 100644 index 0000000..514a7a6 --- /dev/null +++ b/packages/material/src/terminal/demo/basic.tsx @@ -0,0 +1,15 @@ +import React, { useState } from 'react'; +import { Terminal } from '@zhst/material'; + +const demo = () => { + + return ( +
+ console.log('val', val)} + /> +
+ ); +}; + +export default demo; diff --git a/packages/material/src/terminal/index.md b/packages/material/src/terminal/index.md new file mode 100644 index 0000000..1e2c5ea --- /dev/null +++ b/packages/material/src/terminal/index.md @@ -0,0 +1,20 @@ +--- +category: Components +title: Terminal 中心对接 +toc: content +group: + title: 通用 + order: 2 +--- + +中心对接 + +## 代码演示 + +基本用法 + +## API + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| onFinish | 提交事件 | FormProps['onFinish'] | - | - | diff --git a/packages/material/src/terminal/index.tsx b/packages/material/src/terminal/index.tsx new file mode 100644 index 0000000..6f61da8 --- /dev/null +++ b/packages/material/src/terminal/index.tsx @@ -0,0 +1,3 @@ +import Terminal from './Terminal' + +export default Terminal; \ No newline at end of file