AiAssistant.js
4.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/* eslint-disable */
import React, { useState, useContext, useEffect, useRef } from "react";
import { Button, message, Spin } from "antd-v4";
import { SendOutlined } from "@ant-design/icons";
import styles from "../index.less";
import myContext from "../utils/MyContext";
import Services from "../services";
const AiAssistant = () => {
const { props, dispatch } = useContext(myContext);
const [inputValue, setInputValue] = useState(""); // 文本框内容
const [dialogue, setDialogue] = useState([]); // 对话记录内容
const dialogueRef = useRef(null); // 对话框dom
const lastContent = useRef(""); // 最后展示的内容
const lastAnswer = useRef(null); // 最后展示内容的dom
const [loading, setLoading] = useState(false); // 回答加载状态
const [textState, setTextState] = useState(true); // 是否可输入状态
// 获取随机时间
const getRandomTime = (time = 100) => {
return Math.floor(Math.random() * time);
};
// 内容展示动画效果
const showCartoon = (content, chartIndex = 0, time = 0) => {
if (time === 0) {
setTimeout(() => {
setLoading(false);
showCartoon(content, chartIndex, 1);
}, getRandomTime(2000));
return;
}
lastContent.current += content.charAt(chartIndex);
lastAnswer.current.innerText = lastContent.current;
if (
lastAnswer.current.getBoundingClientRect().width /
dialogueRef.current.getBoundingClientRect().width >
0.7
) {
lastAnswer.current.style.display = "flow-root";
}
dialogueRef.current.scrollTop = 9999;
if (chartIndex < content.length - 1) {
let timedelay = getRandomTime(50);
if (chartIndex < 10) {
timedelay = getRandomTime(500);
}
if (chartIndex >= 5 && chartIndex < 50) {
timedelay = getRandomTime();
}
if (content.length - chartIndex < 20) {
timedelay = 20;
}
setTimeout(() => {
showCartoon(content, chartIndex + 1, 1);
}, timedelay);
} else {
setTextState(true);
}
};
// 给回答超过一行的加样式
useEffect(
() => {
if (dialogue.length) {
const oAnswer = document.querySelectorAll(".dialogue .answer");
if (oAnswer) {
oAnswer.forEach(item => {
if (
item.firstChild.getBoundingClientRect().width /
dialogueRef.current.getBoundingClientRect().width >
0.7
) {
item.firstChild.style.display = "flow-root";
}
});
}
dialogueRef.current.scrollTop = 9999;
if (dialogue[dialogue.length - 1].type === "answer") {
setTextState(false);
setLoading(true);
lastAnswer.current.style.display = "";
showCartoon(dialogue[dialogue.length - 1].content);
}
}
},
[dialogue]
);
// 问题提交事件
const handleQuestion = async () => {
if (!textState) {
message.info("请等待此次对话结束后操作");
return;
}
if (!inputValue) {
return;
}
setDialogue(preState => [
...preState,
{ type: "question", content: inputValue }
]);
setInputValue("");
const result = await Services.getRobotReply(inputValue);
lastContent.current = "";
setDialogue(preState => [...preState, { type: "answer", content: result }]);
};
return (
<div className={styles.aiAssistant}>
<div className="dialogue" ref={dialogueRef}>
{dialogue.map((item, index) => {
const { type, content } = item;
if (
index === dialogue.length - 1 &&
type === "answer" &&
lastContent.current !== content
) {
return (
<div className={type} key={index}>
{loading ? (
<Spin />
) : (
<span ref={lastAnswer} style={{ color: "#6055d3" }} />
)}
</div>
);
} else {
return (
<div className={type} key={index}>
<span>{content}</span>
</div>
);
}
})}
<div className="emptyLine" />
</div>
<div className="enter">
<input
placeholder="请输入..."
value={inputValue}
onChange={e => {
setInputValue(e.target.value);
}}
onKeyDown={e => {
if (e.keyCode === 13) {
handleQuestion();
}
}}
/>
<Button type="link" icon={<SendOutlined />} onClick={handleQuestion} />
</div>
</div>
);
};
export default AiAssistant;