From e4ab98dc017b18bd3493ed5e8ee94e626e6c3a33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Chuailei000=E2=80=9D?= <2280131253@qq.com> Date: Tue, 26 Dec 2023 17:53:55 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E5=A2=9E=E5=8A=A0=E6=99=BA=E8=83=BD?= =?UTF-8?q?=E9=97=AE=E7=AD=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- proxy.conf.json | 5 + src/app/elements/chat/chat.component.html | 27 +++++ src/app/elements/chat/chat.component.scss | 107 ++++++++++++++++++++ src/app/elements/chat/chat.component.ts | 116 ++++++++++++++++++++++ src/app/elements/elements.component.ts | 3 +- src/app/model.ts | 1 + src/app/pages/main/main.component.html | 2 + src/app/pages/main/main.component.ts | 4 + src/app/services/view.ts | 10 ++ src/assets/i18n/en.json | 1 + src/assets/i18n/ja.json | 1 + src/assets/i18n/zh.json | 1 + src/assets/icons/robot-assistant.png | Bin 0 -> 4024 bytes 13 files changed, 277 insertions(+), 1 deletion(-) create mode 100644 src/app/elements/chat/chat.component.html create mode 100644 src/app/elements/chat/chat.component.scss create mode 100644 src/app/elements/chat/chat.component.ts create mode 100644 src/assets/icons/robot-assistant.png diff --git a/proxy.conf.json b/proxy.conf.json index f4cb5046..f53d9620 100644 --- a/proxy.conf.json +++ b/proxy.conf.json @@ -56,5 +56,10 @@ "secure": false, "ws": true, "changeOrigin": true + }, + "/ui/": { + "target": "http://localhost:9528", + "secure": false, + "changeOrigin": true } } diff --git a/src/app/elements/chat/chat.component.html b/src/app/elements/chat/chat.component.html new file mode 100644 index 00000000..f058956a --- /dev/null +++ b/src/app/elements/chat/chat.component.html @@ -0,0 +1,27 @@ +
+ +
+
+
+ +
+
+ +
+
+
+ +
+
+
\ No newline at end of file diff --git a/src/app/elements/chat/chat.component.scss b/src/app/elements/chat/chat.component.scss new file mode 100644 index 00000000..4a5db55f --- /dev/null +++ b/src/app/elements/chat/chat.component.scss @@ -0,0 +1,107 @@ +.chat-container { + overflow: hidden; + .content { + height: 100%; + iframe { + border: none; + } + } +} + +.drawer-panel { + position: fixed; + top: 0; + right: 0; + width: 100%; + width: 440px; + min-width: 260px; + height: 100vh; + user-select: none; + border-radius: 10px 0 0 10px; + transition: transform .25s cubic-bezier(.7, .3, .1, 1); + box-shadow: 0 0 8px 4px #00000014; + transform: translate(100%); + background: #FFFFFF; + z-index: 1200; +} + +#dragBox { + position: absolute; + top: 30%; + left: -48px; +} + +.drag-button { + // position: absolute; + // top: 30%; + // left: -48px; + width: 48px; + height: 45px; + line-height: 45px; + box-sizing: border-box; + text-align: center; + font-size: 24px; + border-radius: 20px 0 0 20px; + z-index: 0; + pointer-events: auto; + color: #fff; + background-color: #FFFFFF; + box-shadow: 0 0 8px 4px #00000014; + cursor: pointer; + + &:hover { + left: -50px !important; + width: 50px !important; + transform: translateZ(0) scale(1.06); + transform-style: preserve-3d; + backface-visibility: hidden; + } + i { + font-size: 20px; + line-height: 45px; + } + img { + width: 22px; + height: 22px; + transform: translateY(10%); + margin-left: 3px; + } +} + +.drag-setting { + width: 36px; + height: 36px; + line-height: 38px; + margin-bottom: 10px; + text-align: center; + border-radius: 50%; + cursor: pointer; + transform: translateX(20%); + background-color: #FFFFFF; + border: 1px solid transparent; + transition: border-color 0.3s ease; + &:hover { + background-color: #f0f1f5; + border-color: #1d271f; + } + i { + font-size: 18px; + } +} + +.show { + transition: all .3s cubic-bezier(.7, .3, .1, 1); +} + +.show .modal { + position: fixed; + top: 0; + width: 100%; + height: 100%; + z-index: 999; + opacity: 1; +} + +.show .drawer-panel { + transform: translate(0); +} \ No newline at end of file diff --git a/src/app/elements/chat/chat.component.ts b/src/app/elements/chat/chat.component.ts new file mode 100644 index 00000000..a81ab3b3 --- /dev/null +++ b/src/app/elements/chat/chat.component.ts @@ -0,0 +1,116 @@ +import {OnInit, OnDestroy, Component} from '@angular/core'; +import {ViewService} from '@app/services'; +import {View} from '@app/model'; + +@Component({ + selector: 'elements-chat', + templateUrl: './chat.component.html', + styleUrls: ['./chat.component.scss'], +}) + +export class ElementChatComponent implements OnInit, OnDestroy { + isShow = true; + element: any; + iframeURL: String; + currentView: View; + + constructor( + public viewSrv: ViewService + ) {} + + get isShowSetting() { + const componentType = ['koko', 'lion']; + return ( + this.currentView.hasOwnProperty('connectMethod') + && componentType.includes(this.currentView.connectMethod.component) + ); + } + + ngOnInit() { + this.viewSrv.currentView$.subscribe((state: View) => { + this.currentView = state; + }); + this.iframeURL = '/ui/#/chat/chat-ai'; + this.init(); + this.insertToBody(); + } + + ngOnDestroy() { + this.element.remove(); + this.viewSrv.currentView$.unsubscribe(); + } + + init() { + const clientOffset: any = {}; + const dragBox = document.getElementById('dragBox'); + const dragSetting = document.querySelector('.drag-setting'); + dragBox.addEventListener('mousedown', (event) => { + event.stopPropagation(); + const offsetX = dragBox.getBoundingClientRect().left; + const offsetY = dragBox.getBoundingClientRect().top; + const innerX = event.clientX - offsetX; + const innerY = event.clientY - offsetY; + + clientOffset.clientX = event.clientX; + clientOffset.clientY = event.clientY; + document.onmousemove = function(ev: any) { + dragBox.style.left = ev.clientX - innerX + 'px'; + dragBox.style.top = ev.clientY - innerY + 'px'; + const dragDivTop = window.innerHeight - dragBox.getBoundingClientRect().height; + const dragDivLeft = window.innerWidth - dragBox.getBoundingClientRect().width; + dragBox.style.left = dragDivLeft + 'px'; + dragBox.style.left = '-48px'; + if (dragBox.getBoundingClientRect().top <= 0) { + dragBox.style.top = '0px'; + } + if (dragBox.getBoundingClientRect().top >= dragDivTop) { + dragBox.style.top = dragDivTop + 'px'; + } + ev.preventDefault(); + ev.stopPropagation(); + }; + document.onmouseup = function() { + document.onmousemove = null; + document.onmouseup = null; + }; + }, false); + dragBox.addEventListener('mouseup', (event) => { + const clientX = event.clientX; + const clientY = event.clientY; + if ( + this.isDifferenceWithinThreshold(clientX, clientOffset.clientX) + && this.isDifferenceWithinThreshold(clientY, clientOffset.clientY) + && event.target !== dragSetting + && this.isDescendant(event.target, dragSetting) + ) { + this.isShow = !this.isShow; + } + }); + } + + isDescendant(element, ancestor) { + if (element.parentNode === ancestor) { + return false; + } + return true; + } + + insertToBody() { + this.element = document.getElementById('chatContainer'); + const body = document.querySelector('body'); + body.insertBefore(this.element, body.firstChild); + } + + onOpenDrawer() { + window.postMessage({name: 'OPEN'}, '*'); + } + + isDifferenceWithinThreshold(num1, num2, threshold = 5) { + const difference = Math.abs(num1 - num2); + return difference <= threshold; + } + + toggle() { + this.isShow = !this.isShow; + } +} diff --git a/src/app/elements/elements.component.ts b/src/app/elements/elements.component.ts index 387b95ca..77baaaa1 100644 --- a/src/app/elements/elements.component.ts +++ b/src/app/elements/elements.component.ts @@ -30,7 +30,7 @@ import {ElementsReplayMp4Component} from './replay/mp4/mp4.component'; import {ElementConnectorGuideComponent} from '@app/elements/content/content-window/guide/guide.component'; import {ElementCommandDialogComponent} from '@app/elements/content/command-dialog/command-dialog.component'; import {ElementSendCommandDialogComponent} from '@app/elements/content/send-command-dialog/send-command-dialog.component'; - +import {ElementChatComponent} from '@app/elements/chat/chat.component'; export const ElementComponents = [ ElementLeftBarComponent, @@ -43,6 +43,7 @@ export const ElementComponents = [ ElementUserFileComponent, ElementTermComponent, ElementNavComponent, + ElementChatComponent, ElementIframeComponent, ElementDialogAlertComponent, ElementAssetTreeComponent, diff --git a/src/app/model.ts b/src/app/model.ts index 2f970d36..f4695087 100644 --- a/src/app/model.ts +++ b/src/app/model.ts @@ -271,6 +271,7 @@ export class GlobalSetting { INTERFACE: any; TERMINAL_GRAPHICAL_RESOLUTION: string; CONNECTION_TOKEN_REUSABLE: boolean; + CHAT_AI_ENABLED: boolean; } export class Setting { diff --git a/src/app/pages/main/main.component.html b/src/app/pages/main/main.component.html index dd9797b1..b3e4f39e 100644 --- a/src/app/pages/main/main.component.html +++ b/src/app/pages/main/main.component.html @@ -57,3 +57,5 @@ + + diff --git a/src/app/pages/main/main.component.ts b/src/app/pages/main/main.component.ts index 4b3d1d9c..6fb446f7 100644 --- a/src/app/pages/main/main.component.ts +++ b/src/app/pages/main/main.component.ts @@ -35,6 +35,10 @@ export class PageMainComponent implements OnInit { return this._isMobile; } + get chatAiEnabled() { + return this._settingSvc.globalSetting.CHAT_AI_ENABLED; + } + set isMobile(value) { this._isMobile = value; let settings: any = {}; diff --git a/src/app/services/view.ts b/src/app/services/view.ts index fe2e8bac..e4909e32 100644 --- a/src/app/services/view.ts +++ b/src/app/services/view.ts @@ -1,5 +1,6 @@ import {Injectable} from '@angular/core'; import {View} from '@app/model'; +import {BehaviorSubject} from 'rxjs'; @Injectable() export class ViewService { @@ -7,6 +8,7 @@ export class ViewService { currentView: View; num = 0; viewIds: Array = []; + public currentView$ = new BehaviorSubject<{}>({}); addView(view: View) { this.num += 1; @@ -35,6 +37,7 @@ export class ViewService { } }, 100); this.currentView = view; + this.setCurrentView(); } removeView(view: View) { @@ -48,12 +51,14 @@ export class ViewService { this.currentView.subViews.push(view); const index = this.currentView.subViews.length; this.setCurrentViewTitle(view, index + 1, 'concat'); + this.setCurrentView(); } clearSubViewOfCurrentView(view: View) { const index = this.currentView.subViews.indexOf(view); this.currentView.subViews.splice(index, 1); this.setCurrentViewTitle(view, index + 1, 'delete'); + this.setCurrentView(); } setCurrentViewTitle(view, index, status) { @@ -70,6 +75,7 @@ export class ViewService { this.currentView.name = names.join('|'); break; } + this.setCurrentView(); } keyboardSwitchTab(key) { @@ -97,4 +103,8 @@ export class ViewService { this.activeView(nextActiveView); } } + + setCurrentView() { + this.currentView$.next(this.currentView); + } } diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index a31c9b2c..9e2ed3ee 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -141,6 +141,7 @@ "Run it by client": "Run it by client", "Name": "Name", "Tips": "Tips", + "Question answer": "Question answer", "Asset not found or You have no permission to access it, please refresh asset tree": "Asset not found or You have no permission to access it, please refresh asset tree", "With secret accounts": "With secret accounts", "Close": "Close", diff --git a/src/assets/i18n/ja.json b/src/assets/i18n/ja.json index 3308134e..1632da88 100644 --- a/src/assets/i18n/ja.json +++ b/src/assets/i18n/ja.json @@ -145,6 +145,7 @@ "General": "基本構成", "GUI": "グラフィカル", "CLI": "コマンドライン", + "Question answer": "質問-答え", "Asset not found or You have no permission to access it, please refresh asset tree": "アセットが見つからないか、アクセスする権限がありません。アセット ツリーを更新してください", "Run it by client": "クライアントで実行する", "Name": "めいしょう", diff --git a/src/assets/i18n/zh.json b/src/assets/i18n/zh.json index 6b64e3b7..bacd53db 100644 --- a/src/assets/i18n/zh.json +++ b/src/assets/i18n/zh.json @@ -149,6 +149,7 @@ "Applet": "远程应用", "GUI": "图形化", "Tips": "提示", + "Question answer": "智能问答", "Asset not found or You have no permission to access it, please refresh asset tree": "未找到资产或您无权访问它,请刷新资产树", "CLI": "命令行", "Close": "关闭", diff --git a/src/assets/icons/robot-assistant.png b/src/assets/icons/robot-assistant.png new file mode 100644 index 0000000000000000000000000000000000000000..4a3bd44cf1dd622291868c322debed6248dd035a GIT binary patch literal 4024 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 eV1a!xkLT0000