diff --git a/react-ui/package.json b/react-ui/package.json
index cab066e..e7651de 100644
--- a/react-ui/package.json
+++ b/react-ui/package.json
@@ -76,6 +76,7 @@
"react-cropper": "^2.3.3",
"react-dev-inspector": "^1.8.1",
"react-dom": "^18.2.0",
+ "react-draggable": "^4.4.6",
"react-helmet-async": "^1.3.0",
"react-highlight": "^0.15.0"
},
diff --git a/react-ui/src/assets/img/robot.png b/react-ui/src/assets/img/robot.png
new file mode 100644
index 0000000..e91be9a
Binary files /dev/null and b/react-ui/src/assets/img/robot.png differ
diff --git a/react-ui/src/components/RobotFrame/index.less b/react-ui/src/components/RobotFrame/index.less
new file mode 100644
index 0000000..e3e5662
--- /dev/null
+++ b/react-ui/src/components/RobotFrame/index.less
@@ -0,0 +1,34 @@
+.robot-frame {
+ position: fixed;
+ top: 55px;
+ right: -610px;
+ z-index: 100;
+ width: 600px;
+ height: calc(100% - 55px);
+ background-color: #fff;
+ box-shadow: -6px 0 16px 0 rgba(0, 0, 0, 0.08), -3px 0 6px -4px rgba(0, 0, 0, 0.12),
+ -9px 0 28px 8px rgba(0, 0, 0, 0.05);
+ transition: right 0.3s ease-in-out;
+
+ // 增加优先级
+ &&--visible {
+ right: 0;
+ }
+
+ &__header {
+ display: flex;
+ gap: 10px;
+ align-items: center;
+ justify-content: flex-end;
+ width: 100%;
+ height: 60px;
+ padding: 0 15px;
+ border-bottom: 1px solid #e8e8e8;
+ }
+
+ &__iframe {
+ width: 100%;
+ height: calc(100% - 60px);
+ border: 0;
+ }
+}
diff --git a/react-ui/src/components/RobotFrame/index.tsx b/react-ui/src/components/RobotFrame/index.tsx
new file mode 100644
index 0000000..7905265
--- /dev/null
+++ b/react-ui/src/components/RobotFrame/index.tsx
@@ -0,0 +1,30 @@
+import { CloseOutlined, ExpandOutlined } from '@ant-design/icons';
+import { Button } from 'antd';
+import classNames from 'classnames';
+import styles from './index.less';
+
+type RobotFrameProps = {
+ onClose: () => void;
+ visible: boolean;
+};
+
+function RobotFrame({ onClose, visible }: RobotFrameProps) {
+ const url = 'http://172.20.32.181:30080/chat/EruwZfxVgDkWdLYs';
+ const openUrl = () => {
+ window.open(url, '_blank');
+ };
+
+ return (
+
+
+ } type="text" onClick={openUrl}>
+ } type="text" onClick={onClose}>
+
+
+
+ );
+}
+
+export default RobotFrame;
diff --git a/react-ui/src/hooks/draggable.ts b/react-ui/src/hooks/draggable.ts
new file mode 100644
index 0000000..b093ea6
--- /dev/null
+++ b/react-ui/src/hooks/draggable.ts
@@ -0,0 +1,37 @@
+// 处理 react-draggable 组件拖动结束时,响应了点击事件的
+import { useState } from 'react';
+
+export const useDraggable = (onClick: () => void) => {
+ const [isDragging, setIsDragging] = useState(false);
+
+ const handleStart = () => {
+ setIsDragging(false);
+ };
+
+ const handleDrag = () => {
+ if (!isDragging) {
+ setIsDragging(true);
+ }
+ };
+
+ const handleStop = () => {
+ // 延迟设置 isDragging 为 false 是为了确保在点击事件触发之前它仍然为 true
+ setTimeout(() => setIsDragging(false), 0);
+ };
+
+ const handleClick = (e: React.MouseEvent) => {
+ if (isDragging) {
+ e.preventDefault();
+ e.stopPropagation();
+ } else {
+ onClick();
+ }
+ };
+
+ return {
+ handleStart,
+ handleDrag,
+ handleStop,
+ handleClick,
+ };
+};
diff --git a/react-ui/src/pages/Experiment/components/LogGroup/index.tsx b/react-ui/src/pages/Experiment/components/LogGroup/index.tsx
index a232b30..b6d45ce 100644
--- a/react-ui/src/pages/Experiment/components/LogGroup/index.tsx
+++ b/react-ui/src/pages/Experiment/components/LogGroup/index.tsx
@@ -134,7 +134,6 @@ function LogGroup({
// 建立 socket 连接
const setupSockect = () => {
let { host } = location;
-
if (process.env.NODE_ENV === 'development') {
host = '172.20.32.181:31213';
}
diff --git a/react-ui/src/pages/Workspace/index.less b/react-ui/src/pages/Workspace/index.less
index f7f95a2..3c7bd42 100644
--- a/react-ui/src/pages/Workspace/index.less
+++ b/react-ui/src/pages/Workspace/index.less
@@ -1,4 +1,5 @@
.workspace {
+ position: relative;
height: 100%;
padding: 20px 30px 10px;
overflow-y: auto;
@@ -43,4 +44,14 @@
min-width: 326px;
height: 700px;
}
+
+ &__robot-img {
+ position: fixed;
+ right: 30px;
+ bottom: 20px;
+ width: 64px;
+ height: 64px;
+ background-color: white;
+ cursor: pointer;
+ }
}
diff --git a/react-ui/src/pages/Workspace/index.tsx b/react-ui/src/pages/Workspace/index.tsx
index 55acd26..f5e6fe9 100644
--- a/react-ui/src/pages/Workspace/index.tsx
+++ b/react-ui/src/pages/Workspace/index.tsx
@@ -1,7 +1,10 @@
+import RobotFrame from '@/components/RobotFrame';
+import { useDraggable } from '@/hooks/draggable';
import { getWorkspaceOverviewReq } from '@/services/workspace';
import { ExperimentInstance } from '@/types';
import { to } from '@/utils/promise';
import { useEffect, useState } from 'react';
+import Draggable from 'react-draggable';
import AssetsManagement from './components/AssetsManagement';
import ExperimentChart, { type ExperimentStatistics } from './components/ExperimentChart';
import ExperitableTable from './components/ExperimentTable';
@@ -20,6 +23,10 @@ type OverviewData = {
function Workspace() {
const [overviewData, setOverviewData] = useState();
+ const [robotFrameVisible, setRobotFrameVisible] = useState(false);
+ const { handleStart, handleStop, handleDrag, handleClick } = useDraggable(() =>
+ setRobotFrameVisible((prev) => !prev),
+ );
const users: number[] = new Array(8).fill(0);
useEffect(() => {
getWorkspaceOverview();
@@ -64,6 +71,19 @@ function Workspace() {
+
+ e.preventDefault()}
+ >
+
+
+ setRobotFrameVisible(false)}
+ >
);
}