mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-09-17 16:56:38 +08:00
使用 Element UI 实现会话界面
This commit is contained in:
parent
e2c3f50c8a
commit
aa3a38348f
27
web/package-lock.json
generated
27
web/package-lock.json
generated
@ -8,6 +8,7 @@
|
|||||||
"name": "yycloud-webssh",
|
"name": "yycloud-webssh",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@element-plus/icons-vue": "^2.1.0",
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"core-js": "^3.8.3",
|
"core-js": "^3.8.3",
|
||||||
"element-plus": "^2.1.11",
|
"element-plus": "^2.1.11",
|
||||||
@ -1689,9 +1690,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@element-plus/icons-vue": {
|
"node_modules/@element-plus/icons-vue": {
|
||||||
"version": "1.1.4",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-1.1.4.tgz",
|
"resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.1.0.tgz",
|
||||||
"integrity": "sha512-Iz/nHqdp1sFPmdzRwHkEQQA3lKvoObk8azgABZ81QUOpW9s/lUyQVUSh0tNtEPZXQlKwlSh7SPgoVxzrE0uuVQ==",
|
"integrity": "sha512-PSBn3elNoanENc1vnCfh+3WA9fimRC7n+fWkf3rE5jvv+aBohNHABC/KAR5KWPecxWxDTVT1ERpRbOMRcOV/vA==",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"vue": "^3.2.0"
|
"vue": "^3.2.0"
|
||||||
}
|
}
|
||||||
@ -4997,6 +4998,14 @@
|
|||||||
"vue": "^3.2.0"
|
"vue": "^3.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/element-plus/node_modules/@element-plus/icons-vue": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-Iz/nHqdp1sFPmdzRwHkEQQA3lKvoObk8azgABZ81QUOpW9s/lUyQVUSh0tNtEPZXQlKwlSh7SPgoVxzrE0uuVQ==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^3.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/element-plus/node_modules/@popperjs/core": {
|
"node_modules/element-plus/node_modules/@popperjs/core": {
|
||||||
"name": "@sxzz/popperjs-es",
|
"name": "@sxzz/popperjs-es",
|
||||||
"version": "2.11.7",
|
"version": "2.11.7",
|
||||||
@ -12206,9 +12215,9 @@
|
|||||||
"integrity": "sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw=="
|
"integrity": "sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw=="
|
||||||
},
|
},
|
||||||
"@element-plus/icons-vue": {
|
"@element-plus/icons-vue": {
|
||||||
"version": "1.1.4",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-1.1.4.tgz",
|
"resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.1.0.tgz",
|
||||||
"integrity": "sha512-Iz/nHqdp1sFPmdzRwHkEQQA3lKvoObk8azgABZ81QUOpW9s/lUyQVUSh0tNtEPZXQlKwlSh7SPgoVxzrE0uuVQ==",
|
"integrity": "sha512-PSBn3elNoanENc1vnCfh+3WA9fimRC7n+fWkf3rE5jvv+aBohNHABC/KAR5KWPecxWxDTVT1ERpRbOMRcOV/vA==",
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
"@eslint/eslintrc": {
|
"@eslint/eslintrc": {
|
||||||
@ -14932,6 +14941,12 @@
|
|||||||
"normalize-wheel-es": "^1.1.2"
|
"normalize-wheel-es": "^1.1.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@element-plus/icons-vue": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-Iz/nHqdp1sFPmdzRwHkEQQA3lKvoObk8azgABZ81QUOpW9s/lUyQVUSh0tNtEPZXQlKwlSh7SPgoVxzrE0uuVQ==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"@popperjs/core": {
|
"@popperjs/core": {
|
||||||
"version": "npm:@sxzz/popperjs-es@2.11.7",
|
"version": "npm:@sxzz/popperjs-es@2.11.7",
|
||||||
"resolved": "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
|
"resolved": "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
"lint": "vue-cli-service lint"
|
"lint": "vue-cli-service lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@element-plus/icons-vue": "^2.1.0",
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"core-js": "^3.8.3",
|
"core-js": "^3.8.3",
|
||||||
"element-plus": "^2.1.11",
|
"element-plus": "^2.1.11",
|
||||||
|
42
web/src/components/ConfigDialog.vue
Normal file
42
web/src/components/ConfigDialog.vue
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-dialog
|
||||||
|
v-show="show"
|
||||||
|
title="聊天配置"
|
||||||
|
width="30%"
|
||||||
|
:before-close="beforeClose"
|
||||||
|
>
|
||||||
|
<span>正在努力开发中...</span>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="show = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="show = false">
|
||||||
|
保存
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {defineComponent} from "vue"
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'ConfigDialog',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
show: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
beforeClose: function () {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
|
||||||
|
</style>
|
@ -15,26 +15,33 @@
|
|||||||
|
|
||||||
</div><!-- end chat box -->
|
</div><!-- end chat box -->
|
||||||
|
|
||||||
<div class="input-box" :style="{width: inputBoxWidth+'px'}" id="input-box">
|
<div class="input-box">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
<textarea class="input-text" id="input-text" rows="1" :style="{minHeight:'24px', height: textHeight+'px'}"
|
<el-input
|
||||||
v-on:keydown="inputKeyDown"
|
|
||||||
v-model="inputValue"
|
v-model="inputValue"
|
||||||
|
:autosize="{ minRows: 1, maxRows: 10 }"
|
||||||
|
v-on:keydown="inputKeyDown"
|
||||||
|
v-on:focus="focus"
|
||||||
|
type="textarea"
|
||||||
placeholder="Input any thing here..."
|
placeholder="Input any thing here..."
|
||||||
v-on:focus="focus"></textarea>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="btn-container">
|
<div class="btn-container">
|
||||||
<button type="button"
|
<el-row>
|
||||||
class="btn btn-success"
|
<el-button type="success" class="send" :disabled="sending" v-on:click="sendMessage">发送</el-button>
|
||||||
:disabled="sending"
|
<el-button type="danger" class="config" circle @click="showDialog = true">
|
||||||
v-on:click="sendMessage">发送
|
<el-icon>
|
||||||
</button>
|
<Tools/>
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div><!-- end input box -->
|
</div><!-- end input box -->
|
||||||
</div><!-- end container -->
|
</div><!-- end container -->
|
||||||
|
|
||||||
|
<config-dialog v-model="showDialog"></config-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -44,21 +51,19 @@ import ChatPrompt from "@/components/ChatPrompt.vue";
|
|||||||
import ChatReply from "@/components/ChatReply.vue";
|
import ChatReply from "@/components/ChatReply.vue";
|
||||||
import {randString} from "@/utils/libs";
|
import {randString} from "@/utils/libs";
|
||||||
import {ElMessage} from 'element-plus'
|
import {ElMessage} from 'element-plus'
|
||||||
|
import {Tools} from '@element-plus/icons-vue'
|
||||||
|
import ConfigDialog from '@/components/ConfigDialog.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "XChat",
|
name: "XChat",
|
||||||
components: {ChatPrompt, ChatReply},
|
components: {ChatPrompt, ChatReply, Tools, ConfigDialog},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
title: "ChatGPT 控制台",
|
title: "ChatGPT 控制台",
|
||||||
chatData: [],
|
chatData: [],
|
||||||
inputBoxHeight: 63,
|
|
||||||
inputBoxWidth: 0,
|
|
||||||
inputValue: '',
|
inputValue: '',
|
||||||
textHeight: 24,
|
|
||||||
textWidth: 0,
|
|
||||||
chatBoxHeight: 0,
|
chatBoxHeight: 0,
|
||||||
isMobile: false,
|
showDialog: false,
|
||||||
|
|
||||||
socket: null,
|
socket: null,
|
||||||
sending: false
|
sending: false
|
||||||
@ -69,24 +74,9 @@ export default defineComponent({
|
|||||||
|
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
this.inputBoxHeight = document.getElementById("input-box").offsetHeight;
|
this.chatBoxHeight = window.innerHeight - 61;
|
||||||
this.textWidth = document.getElementById("input-text").offsetWidth;
|
|
||||||
this.chatBoxHeight = window.innerHeight - this.inputBoxHeight - 40;
|
|
||||||
})
|
})
|
||||||
|
|
||||||
//判断是否手机端访问
|
|
||||||
const userAgentInfo = navigator.userAgent.toLowerCase();
|
|
||||||
const Agents = ["android", "iphone", "windows phone", "ipad", "ipod"];
|
|
||||||
for (let v = 0; v < Agents.length; v++) {
|
|
||||||
if (userAgentInfo.toLowerCase().indexOf(Agents[v]) >= 0) {
|
|
||||||
this.isMobile = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.inputBoxWidth = window.innerWidth;
|
|
||||||
|
|
||||||
window.addEventListener('resize', this.windowResize);
|
|
||||||
|
|
||||||
// 初始化 WebSocket 对象
|
// 初始化 WebSocket 对象
|
||||||
const socket = new WebSocket(process.env.VUE_APP_WS_HOST + '/api/chat');
|
const socket = new WebSocket(process.env.VUE_APP_WS_HOST + '/api/chat');
|
||||||
socket.addEventListener('open', () => {
|
socket.addEventListener('open', () => {
|
||||||
@ -135,23 +125,15 @@ export default defineComponent({
|
|||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeUnmount() {
|
|
||||||
window.removeEventListener("resize", this.windowResize);
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
inputKeyDown: function (e) {
|
inputKeyDown: function (e) {
|
||||||
|
|
||||||
if (e.keyCode === 13) {
|
if (e.keyCode === 13) {
|
||||||
if (!this.isMobile) { // PC 端按回车键直接提交数据
|
if (this.sending) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
return this.sendMessage();
|
|
||||||
} else {
|
} else {
|
||||||
return this.inputResize(true);
|
this.sendMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
this.inputResize(false);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// 发送消息
|
// 发送消息
|
||||||
@ -172,55 +154,16 @@ export default defineComponent({
|
|||||||
this.sending = true;
|
this.sending = true;
|
||||||
this.socket.send(this.inputValue);
|
this.socket.send(this.inputValue);
|
||||||
this.inputValue = '';
|
this.inputValue = '';
|
||||||
this.inputResize(false);
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据输入内容的多少动态调整输入框的大小
|
|
||||||
* @param flag 是否输入回车键,如果输入了回车键则需要增加一行
|
|
||||||
*/
|
|
||||||
inputResize: function (flag) {
|
|
||||||
let line = 1;
|
|
||||||
if (flag) {
|
|
||||||
line++;
|
|
||||||
}
|
|
||||||
|
|
||||||
let textWidth = 0;
|
|
||||||
for (let i in this.inputValue) {
|
|
||||||
if (this.inputValue[i] === '\n') {
|
|
||||||
line++;
|
|
||||||
textWidth = 0; // 换行之后前面字数清零
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (this.inputValue.charCodeAt(Number(i)) < 128) {
|
|
||||||
textWidth += 8; // 英文字符宽度
|
|
||||||
} else {
|
|
||||||
textWidth += 16; // 中文字符宽度
|
|
||||||
}
|
|
||||||
|
|
||||||
if (textWidth >= this.textWidth) { // 另起一行
|
|
||||||
textWidth = textWidth - this.textWidth;
|
|
||||||
line++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.inputBoxHeight = 63 + (line - 1) * 24;
|
|
||||||
this.textHeight = line * 24;
|
|
||||||
},
|
|
||||||
|
|
||||||
windowResize: function () {
|
|
||||||
this.inputResize(false);
|
|
||||||
this.chatBoxHeight = window.innerHeight - this.inputBoxHeight - 40;
|
|
||||||
this.inputBoxWidth = window.innerWidth;
|
|
||||||
},
|
|
||||||
|
|
||||||
// 获取焦点
|
// 获取焦点
|
||||||
focus: function () {
|
focus: function () {
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
document.getElementById('container').scrollTo(0, document.getElementById('container').scrollHeight)
|
document.getElementById('container').scrollTo(0, document.getElementById('container').scrollHeight)
|
||||||
}, 200)
|
}, 200)
|
||||||
}
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
})
|
})
|
||||||
@ -267,12 +210,13 @@ export default defineComponent({
|
|||||||
|
|
||||||
.input-box {
|
.input-box {
|
||||||
padding 10px;
|
padding 10px;
|
||||||
|
width 100%;
|
||||||
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0
|
bottom: 0
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: start;
|
||||||
align-items: flex-start;
|
align-items: center;
|
||||||
|
|
||||||
.input-container {
|
.input-container {
|
||||||
overflow hidden
|
overflow hidden
|
||||||
@ -306,8 +250,15 @@ export default defineComponent({
|
|||||||
.btn-container {
|
.btn-container {
|
||||||
margin-left 10px;
|
margin-left 10px;
|
||||||
|
|
||||||
button {
|
.el-row {
|
||||||
width 70px;
|
flex-wrap nowrap
|
||||||
|
width 106px;
|
||||||
|
align-items center
|
||||||
|
}
|
||||||
|
|
||||||
|
.send {
|
||||||
|
width 60px;
|
||||||
|
height 40px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user