index.vue 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. <template>
  2. <div style="width:1000px; margin: auto;">
  3. <el-row>
  4. <el-col :span="18">
  5. <div class="chat-window-wrapper" ref="chatWindowWrapper">
  6. <el-card class="chat-window" ref="chatWindow">
  7. <div v-for="(message, index) in messages" :key="index" class="message">
  8. <img
  9. :src="message.sender === 'user' ? require('@/assets/search/soldier.png') : require('@/assets/search/robot.png')"
  10. alt="avatar"
  11. class="avatar"
  12. />
  13. <div :class="['bubble', message.sender === 'user' ? 'user-bubble' : message.sender === 'ai' ? 'ai-bubble' : 'system-bubble']">
  14. {{ message.content }}
  15. <el-button v-if="message.sender === 'system' && requestError" size="mini" type="text" @click="retry(message.oldMsg)" style="margin-left:10px;width:80px">&nbsp;&nbsp;重&nbsp;&nbsp;试</el-button>
  16. </div>
  17. </div>
  18. <div v-show="isWaitingForResponse" class="response-indicator" ref="aiBubble">
  19. <img :src="require('@/assets/search/robot.png')" alt="avatar" class="avatar" />
  20. <div class="loader"></div>
  21. </div>
  22. </el-card>
  23. </div>
  24. <div class="input-area">
  25. <el-input v-model="inputMessage" type="textarea" placeholder="输入您的消息..." style="margin:5px" :disabled="isWaitingForResponse"
  26. @keyup.enter.native="sendMessage(null)"></el-input>
  27. </div>
  28. </el-col>
  29. <el-col :span="6">
  30. <el-card class="chat-msg">
  31. <!-- <p v-html="dict.type.show_msg[0]?dict.type.show_msg[0].raw.remark:''"/> -->
  32. <li><span style="color:red">故障原因</span>:为什么xxxxx;xxxxx是什么原因;</li>
  33. <li><span style="color:red">故障影响</span>:xxxx有什么后果;xxxx有什么影响;xxxx会怎么样;xxxx会造成什么</li>
  34. <li><span style="color:red">组成</span>:xxxx有什么零件;xxxx由什么组成;xxxx包含什么</li>
  35. <li><span style="color:red">维修方法</span>:xxxx怎么修;xxxx处理方法;xxxx怎么解决</li>
  36. <li><span style="color:red">检测工具</span>:xxxx的检测工具;xxxx的测试工具;xxxx怎么诊断;</li>
  37. <li><span style="color:red">部件故障</span>:xxxx有什么故障;xxxx会有什么问题</li>
  38. </el-card>
  39. </el-col>
  40. </el-row>
  41. </div>
  42. </template>
  43. <script>
  44. import { question } from "@/api/knowledge/search";
  45. export default {
  46. name: 'question',
  47. dicts: ['show_msg'],
  48. data() {
  49. return {
  50. inputMessage: "",
  51. messages: [],
  52. requestError: false,
  53. isWaitingForResponse: false,
  54. hint: "",
  55. };
  56. },
  57. mounted(){
  58. this.hint = this.getHint();
  59. },
  60. methods: {
  61. getHint(){
  62. let showMsgs = this.dict.type.show_msg;
  63. for(let showMsg of showMsgs) {
  64. if(showMsg.value == "qa_msg"){
  65. return showMsg.raw.remark
  66. }
  67. }
  68. },
  69. sendMessage(msg) {
  70. let inputMessage = msg ? msg :this.inputMessage.trim()
  71. if (!inputMessage) return;
  72. // this.isWaitingForResponse = true;
  73. if(!msg){
  74. this.messages.push({
  75. sender: "user",
  76. content: inputMessage,
  77. });
  78. }
  79. // 获取最后一行的焦点
  80. const aiBubbles = this.$refs.aiBubble;
  81. aiBubbles.focus();
  82. let oldMsg = inputMessage;
  83. this.scrollToBottom();
  84. question(inputMessage).then(resp => {
  85. this.messages.push({
  86. sender: "ai",
  87. content: resp.data,
  88. });
  89. this.scrollToBottom();
  90. this.isWaitingForResponse = false;
  91. }).catch(error => {
  92. console.info(error)
  93. this.requestError = true;
  94. this.messages.push({
  95. sender: "system",
  96. content: "系统异常",
  97. oldMsg,
  98. });
  99. this.scrollToBottom();
  100. this.isWaitingForResponse = false;
  101. })
  102. this.inputMessage = "";
  103. },
  104. retry(msg) {
  105. if (this.requestError) {
  106. this.requestError = false;
  107. this.messages.pop(); // 移除系统提示消息
  108. this.sendMessage(msg); // 重新发送
  109. }
  110. },
  111. scrollToBottom() {
  112. this.$nextTick(() => {
  113. const chatWindowWrapper = this.$refs.chatWindowWrapper;
  114. chatWindowWrapper.scrollTop = chatWindowWrapper.scrollHeight;
  115. });
  116. },
  117. },
  118. };
  119. </script>
  120. <style scoped>
  121. .chat-window {
  122. overflow-y: scroll;
  123. margin-bottom: 10px;
  124. border: 0px;
  125. border-radius: 5px;
  126. }
  127. .input-area {
  128. display: flex;
  129. }
  130. .message {
  131. margin-bottom: 10px;
  132. }
  133. .bubble {
  134. display: inline-block;
  135. padding: 5px 10px;
  136. border-radius: 5px;
  137. font-family: "Courier New", Courier, monospace;
  138. font-size: 14px;
  139. line-height: 1.5;
  140. margin-bottom: 5px;
  141. /* flex: 1; */
  142. }
  143. .message {
  144. display: flex;
  145. align-items: flex-start;
  146. margin-bottom: 10px;
  147. }
  148. .avatar {
  149. width: 32px;
  150. height: 32px;
  151. border-radius: 50%;
  152. margin-right: 8px;
  153. }
  154. .user-bubble {
  155. background-color: #45a1ff;
  156. color: #fff;
  157. }
  158. .ai-bubble {
  159. background-color: #1a1a1a;
  160. color: #45a1ff;
  161. border: 1px solid #45a1ff;
  162. }
  163. .el-input {
  164. flex: 1;
  165. margin-right: 10px;
  166. }
  167. .el-input__inner {
  168. background-color: #333;
  169. border-color: #45a1ff;
  170. color: #45a1ff;
  171. }
  172. .el-input__inner::placeholder {
  173. color: #45a1ff;
  174. }
  175. .el-button {
  176. background-color: #45a1ff;
  177. border-color: #45a1ff;
  178. color: #1a1a1a;
  179. }
  180. .el-textarea__inner {
  181. background-color: transparent;
  182. }
  183. .response-indicator {
  184. display: flex;
  185. align-items: center;
  186. margin-bottom: 10px;
  187. }
  188. .loader {
  189. border: 2px solid #45a1ff;
  190. border-top: 2px solid #1a1a1a;
  191. border-radius: 50%;
  192. width: 14px;
  193. height: 14px;
  194. margin-left: 5px;
  195. animation: spin 0.8s linear infinite;
  196. }
  197. @keyframes spin {
  198. 0% {
  199. transform: rotate(0deg);
  200. }
  201. 100% {
  202. transform: rotate(360deg);
  203. }
  204. }
  205. .chat-window-wrapper {
  206. border: 2px solid #45a1ff;
  207. height: calc(100vh - 200px);
  208. /* max-height: 500px; */
  209. overflow-y: auto;
  210. }
  211. .chat-window {
  212. width: 100%;
  213. /* min-height: 100%; */
  214. }
  215. .chat-msg {
  216. height: calc(100vh - 200px);
  217. white-space: pre-wrap;
  218. margin-left: 5px;
  219. font-size: 1rem;
  220. }
  221. </style>