searchArea.vue 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968
  1. <template>
  2. <div class="search">
  3. <div class="s_top" ref="chatRef">
  4. <!-- <div class="s_t_chat">
  5. <div class="s_t_c_ai">
  6. <div class="s_t_c_a_left">
  7. <span>Ai</span>
  8. </div>
  9. <div class="s_t_c_a_right">
  10. <div class="s_t_c_a_r_content2">
  11. <div class="s_t_c_a_r_c_title">
  12. <img :src="require('../../../assets/icon/course/idea.png')" />
  13. <span>猜你想搜:</span>
  14. </div>
  15. <div
  16. class="s_t_c_a_r_c_item"
  17. v-for="(item, index) in wantSearch"
  18. :key="index"
  19. @click="sendAiIdea(item.label)"
  20. >
  21. {{ index + 1 }}.{{ item.title }}:{{ item.label }}
  22. </div>
  23. </div>
  24. <div class="s_t_c_a_r_time">
  25. {{ new Date().toLocaleString().replace(/\//gi, "-") }}
  26. </div>
  27. </div>
  28. </div>
  29. </div> -->
  30. <div class="s_t_chat" v-for="(item, index) in chatList" :key="index">
  31. <div
  32. class="s_t_c_user"
  33. v-if="
  34. item.content &&
  35. item.content != 'wanSearch' &&
  36. item.content != 'getImage'
  37. "
  38. >
  39. <div class="s_t_c_u_left">
  40. <div class="s_t_c_u_l_content">{{ item.content }}</div>
  41. <div class="s_t_c_u_l_time">{{ item.createtime }}</div>
  42. </div>
  43. <div class="s_t_c_u_right">
  44. <span>我</span>
  45. </div>
  46. </div>
  47. <div
  48. class="s_t_c_ai"
  49. v-if="item.content != 'wanSearch' && item.content != 'getImage'"
  50. >
  51. <div class="aiCopy">
  52. <img
  53. style="width: 30px;"
  54. src="https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/%E5%A4%8D%E5%88%B6%E5%9B%BE%E6%A0%871715569581741.png"
  55. alt=""
  56. />
  57. </div>
  58. <div class="s_t_c_a_left">
  59. <span>Ai</span>
  60. </div>
  61. <div class="s_t_c_a_right">
  62. <div class="s_t_c_a_r_content" style="display: flex;justify-content: space-between;flex-wrap: wrap;" v-if="item.content.includes('图片')">
  63. <div v-for="i in pan(item.aiContent)">
  64. <img style="width: 120px;height: 120px;" :src="i.image" alt="" @click="previewImg(i.image)">
  65. </div>
  66. </div>
  67. <div
  68. v-else
  69. class="s_t_c_a_r_content"
  70. v-loading="item.loading"
  71. v-html="item.aiContent"
  72. ></div>
  73. <!-- <div
  74. class="s_t_c_a_r_contentImage"
  75. v-loading="item.loading"
  76. >
  77. <span style="margin-bottom: 10px;">为您找到以下图片: {{ item.content }}</span> -->
  78. <!-- {{ item.aiContent }} -->
  79. <!-- <img
  80. v-for="(i, index) in item.aiContent"
  81. @click.stop="$hevueImgPreview(item)"
  82. :key="index"
  83. :src="i.image"
  84. /> -->
  85. <!-- <div class="imgNumberBlock">
  86. <div class="imgNumber" v-for="(i,index) in imgNumList" :key="index+'b'">
  87. {{ i }}
  88. </div>
  89. <div class="imgNumber" style="background: none;">
  90. <img style="width: 36px;height: 30px;" src="https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/Frame%20131715569413607.png" alt="">
  91. </div>
  92. </div> -->
  93. <!-- </div> -->
  94. <!-- <div class="s_t_c_a_r_time">{{ item.createtime }}</div> -->
  95. </div>
  96. </div>
  97. <div class="s_t_chat" v-if="item.content == 'wanSearch'">
  98. <div class="s_t_c_ai">
  99. <div class="s_t_c_a_left">
  100. <el-avatar v-if="item.filename" :src="item.filename"></el-avatar>
  101. <span v-else>Ai</span>
  102. </div>
  103. <div class="s_t_c_a_right">
  104. <div class="s_t_c_a_r_content2" v-loading="item.loading">
  105. <div class="s_t_c_a_r_c_title">
  106. <img :src="require('../../../assets/icon/course/idea.png')" />
  107. <span>猜你想搜:</span>
  108. </div>
  109. <div
  110. class="s_t_c_a_r_c_item"
  111. v-for="(item, index) in item.aiContent"
  112. :key="index"
  113. @click="sendAiIdea(item.label)"
  114. >
  115. {{ index + 1 }}.{{ item.title }}:{{ item.label }}
  116. </div>
  117. </div>
  118. <div class="s_t_c_a_r_time">{{ item.createtime }}</div>
  119. </div>
  120. </div>
  121. </div>
  122. </div>
  123. </div>
  124. <div class="s_bottom">
  125. <!-- <div class="s_b_ba-item" @click.stop="choiceRole()">选择角色</div> -->
  126. <div class="s_b_btnArea">
  127. <div class="s_b_ba-item" @click="clear()">
  128. 清空聊天记录
  129. </div>
  130. </div>
  131. <div class="s_b_inputArea">
  132. <!-- <div class="s_b_tape" @click="goTape()"></div> -->
  133. <div class="s_b_input">
  134. <el-input
  135. :disabled="loading || chatLoading"
  136. v-loading="loading || chatLoading"
  137. @keyup.enter.native="send()"
  138. class="s_b_i_left"
  139. v-model="text"
  140. ></el-input>
  141. <!-- <div class="s_b_i_right" @click="sendFile()">
  142. <span></span>
  143. </div> -->
  144. </div>
  145. <div class="s_b_btn" @click="send()">
  146. <span></span>
  147. </div>
  148. </div>
  149. </div>
  150. </div>
  151. </template>
  152. <script>
  153. import { v4 as uuidv4 } from "uuid";
  154. import MarkdownIt from "markdown-it";
  155. export default {
  156. props: {
  157. courseDetail: {
  158. type: Object,
  159. default: () => {}
  160. }
  161. },
  162. data() {
  163. return {
  164. text: "",
  165. loading: false,
  166. chatLoading: false,
  167. imageCheck: false,
  168. videoCheck: false,
  169. userid: this.$route.query.userid,
  170. courseId: this.$route.query.courseId,
  171. imgNumList: ["U1", "U2", "U3", "U4"],
  172. chatList: []
  173. };
  174. },
  175. computed: {
  176. pan() {
  177. return (content) => {
  178. try {
  179. return JSON.parse(content)
  180. } catch (error) {
  181. return []
  182. }
  183. };
  184. }
  185. },
  186. methods: {
  187. previewImg(url) {
  188. this.$hevueImgPreview(url);
  189. },
  190. clear() {
  191. this.chatList = [];
  192. },
  193. choiceRole() {
  194. this.cardType = 1;
  195. },
  196. sendFile() {
  197. if (this.loading) return this.$message.info("请稍等");
  198. this.$message.info("点击了附件");
  199. },
  200. goTape() {
  201. if (this.loading) return this.$message.info("请稍等");
  202. this.$message.info(`点击了语音`);
  203. },
  204. send(_text = this.text) {
  205. if (this.loading || this.chatLoading) return this.$message.info("请稍等");
  206. if (_text.trim().length == 0) return this.$message.info("请输入内容");
  207. let _msg = ``;
  208. this.chatLoading = true;
  209. let _uuid = uuidv4();
  210. this.chatList.push({
  211. role: "user",
  212. content: `${_text}`,
  213. uid: _uuid,
  214. AI: "AI",
  215. aiContent: "",
  216. oldContent: "",
  217. isShowSynchronization: false,
  218. filename: "",
  219. index: this.chatList.length,
  220. is_mind_map: false,
  221. loading: true
  222. });
  223. this.scrollBottom();
  224. if (_text.indexOf("视频") != -1) {
  225. _msg = `
  226. NOTICE
  227. Language: Please use the same language as the user requirement, if the user speaks Chinese, the specific text of your answer should also be in Chinese.
  228. ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenced "Format example".
  229. Instruction: Based on the context, follow "Format example", write content.
  230. # Context
  231. ## 任务
  232. 你的任务是根据用户的请求,结合“课程信息”,在Ted.com等教育网站上搜索相关视频,并且按照“输出格式”将结果输出给用户。
  233. 课程信息
  234. 课程标题:${this.courseDetail.title}
  235. 分类:${this.courseDetail.name ? this.courseDetail.name : "无"}
  236. 学生年级:${this.courseDetail.classname ? this.courseDetail.classname : "无"}
  237. ## 规则
  238. 1. 输出结果必须真实有效,不要捏造无效的视频链接
  239. 2. 当课程信息中的子条目内容为“无”时,无视这些条目进行输出即可。
  240. 3. 如果没有相关内容,请跟用户表明没有找到相关视频链接内容,然后推荐搜索建议
  241. 4. 在ted.com等教育网站上搜索视频,并且以有序列表的形式将结果输出给用户
  242. 5. 请一步步思考如何根据现有信息推送视频,但是最终输出结果不需要包含你的思考过程,只需要包含视频标题+链接。
  243. # Format example
  244. 视频来源: Ted.com
  245. 视频标题:How AI could save (not destroy) education
  246. 视频内容:介绍了一款AI教育软件
  247. 视频链接https://www.ted.com/talks/sal_khan_how_ai_could_save_not_destroy_education
  248. `;
  249. } else if (_text.indexOf("图片") != -1) {
  250. console.log("图片");
  251. this.text = "";
  252. let params = {
  253. page: 1,
  254. pagesize: 4,
  255. query: _text
  256. };
  257. this.$message.info(_text);
  258. this.chatList.push({
  259. role: "user",
  260. content: `getImage`,
  261. uid: _uuid,
  262. AI: "AI",
  263. aiContent: "",
  264. oldContent: "",
  265. isShowSynchronization: false,
  266. filename: "",
  267. index: this.chatList.length,
  268. is_mind_map: false,
  269. loading: true
  270. });
  271. this.ajax
  272. .post("https://gpt.cocorobo.cn/search_image", params)
  273. .then(res => {
  274. let data = res.data.FunctionResponse.result;
  275. // console.log('res',res.data.FunctionResponse.result);
  276. this.chatList.find(i => i.uid == _uuid).aiContent = JSON.stringify(data);
  277. this.chatList.find(i => i.uid == _uuid).loading = false;
  278. this.chatLoading = false;
  279. this.insertChat(_uuid);
  280. // console.log('resresresres',res);
  281. // if (res.data.FunctionResponse.result == "发送成功") {
  282. // } else {
  283. // this.$message.warning(res.data.FunctionResponse.result);
  284. // }
  285. });
  286. return;
  287. }
  288. console.log(9999);
  289. // num=0
  290. // _msg = `
  291. // NOTICE
  292. // Language: Please use the same language as the user requirement, if the user speaks Chinese, the specific text of your answer should also be in Chinese.
  293. // ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenced "Format example".
  294. // Instruction: Based on the context, follow "Format example", write content.
  295. // # Context
  296. // ## 任务
  297. // 你的任务是根据用户的请求,结合以下“课程信息”包含的子条目(“课程标题”,“主题”,“学科”以及“年级”),向用户输出相关的4张图片,将结果2*2的形式返回给用户。
  298. // 课程信息
  299. // 课程标题:${this.courseDetail.title}
  300. // 分类:${this.courseDetail.name?this.courseDetail.name:"无"}
  301. // 学生年级:${this.courseDetail.classname?this.courseDetail.classname:"无"}
  302. // ## 规则
  303. // 1. 输出内容应该与“课程信息”相关,避免提供无关的信息。
  304. // 2. 当课程信息中的子条目内容为“无”时,无视这些条目进行输出即可。
  305. // 3. 搜索建议的结果应该符合伦理规范。
  306. // ## 输出格式
  307. // 1. 以2*2的格式输出应包括4张相关的图片。
  308. // `
  309. // }
  310. let history = [];
  311. if (_msg) {
  312. history.push({ role: "user", content: _msg });
  313. }
  314. history.push({ role: "user", content: _text });
  315. let params = {
  316. model: "gpt-3.5-turbo",
  317. temperature: 0,
  318. max_tokens: 4096,
  319. top_p: 1,
  320. frequency_penalty: 0,
  321. presence_penalty: 0,
  322. messages: history,
  323. uid: _uuid,
  324. mind_map_question: ""
  325. };
  326. this.text = "";
  327. this.ajax
  328. .post("https://gpt4.cocorobo.cn/chat", params)
  329. .then(res => {
  330. if (res.data.FunctionResponse.result == "发送成功") {
  331. } else {
  332. this.$message.warning(res.data.FunctionResponse.result);
  333. this.chatLoading = false;
  334. }
  335. })
  336. .catch(e => {
  337. console.log(e);
  338. this.chatLoading = false;
  339. });
  340. this.getAiContent(_uuid);
  341. },
  342. // 获取ai对话
  343. getAiContent(_uid) {
  344. let _source = new EventSource(`https://gpt4.cocorobo.cn/stream/${_uid}`); //http://gpt4.cocorobo.cn:8011/stream/ https://gpt4.cocorobo.cn/stream/
  345. let _allText = "";
  346. let _mdText = "";
  347. const md = new MarkdownIt();
  348. _source.onmessage = _e => {
  349. if (_e.data.replace("'", "").replace("'", "") == "[DONE]") {
  350. //对话已经完成
  351. _mdText = _mdText.replace("_", "");
  352. _source.close();
  353. this.chatLoading = false;
  354. this.scrollBottom();
  355. this.chatList.find(i => i.uid == _uid).aiContent = _mdText;
  356. this.chatList.find(i => i.uid == _uid).isalltext = true;
  357. this.chatList.find(i => i.uid == _uid).isShowSynchronization = true;
  358. this.chatList.find(i => i.uid == _uid).loading = false;
  359. // 这里保存对话
  360. this.insertChat(_uid);
  361. return;
  362. } else {
  363. //对话还在继续
  364. let _text = "";
  365. _text = _e.data.replaceAll("'", "");
  366. if (_allText == "") {
  367. _allText = _text.replace(/^\n+/, ""); //去掉回复消息中偶尔开头就存在的连续换行符
  368. } else {
  369. _allText += _text;
  370. }
  371. _mdText = _allText + "_";
  372. _mdText = _mdText.replace(/\\n/g, "\n");
  373. _mdText = _mdText.replace(/\\/g, "");
  374. if (_allText.split("```").length % 2 == 0) _mdText += "\n```\n";
  375. //转化返回的回复流数据
  376. _mdText = md.render(_mdText);
  377. this.chatList.find(i => i.uid == _uid).aiContent = _mdText;
  378. this.chatList.find(i => i.uid == _uid).loading = false;
  379. this.scrollBottom();
  380. // 处理流数据
  381. }
  382. };
  383. },
  384. getWAntSearchContent(_uid) {
  385. let _source = new EventSource(`https://gpt4.cocorobo.cn/stream/${_uid}`); //http://gpt4.cocorobo.cn:8011/stream/ https://gpt4.cocorobo.cn/stream/
  386. let _allText = "";
  387. let _mdText = "";
  388. this.scrollBottom();
  389. _source.onmessage = _e => {
  390. if (_e.data.replace("'", "").replace("'", "") == "[DONE]") {
  391. //对话已经完成
  392. _mdText = _mdText.replace("_", "");
  393. _mdText = _mdText.replace("```json", "");
  394. _mdText = _mdText.replace("```", "");
  395. _source.close();
  396. this.chatLoading = false;
  397. this.chatList.find(i => i.uid == _uid).aiContent = JSON.parse(
  398. _mdText
  399. );
  400. this.chatList.find(i => i.uid == _uid).isalltext = true;
  401. this.chatList.find(i => i.uid == _uid).isShowSynchronization = true;
  402. this.chatList.find(i => i.uid == _uid).loading = false;
  403. this.scrollBottom();
  404. // 这里保存对话
  405. return;
  406. } else {
  407. //对话还在继续
  408. let _text = "";
  409. _text = _e.data.replaceAll("'", "");
  410. if (_allText == "") {
  411. _allText = _text.replace(/^\n+/, ""); //去掉回复消息中偶尔开头就存在的连续换行符
  412. } else {
  413. _allText += _text;
  414. }
  415. _mdText = _allText + "_";
  416. _mdText = _mdText.replace(/\\n/g, "\n");
  417. _mdText = _mdText.replace(/\\/g, "");
  418. if (_allText.split("```").length % 2 == 0) _mdText += "\n```\n";
  419. //转化返回的回复流数据
  420. this.scrollBottom();
  421. }
  422. };
  423. },
  424. //保存消息
  425. insertChat(_uid) {
  426. let _data = this.chatList.find(i => i.uid == _uid);
  427. if (!_data) return;
  428. let params = {
  429. userId: this.userid,
  430. userName: "qgt",
  431. groupId: "602def61-005d-11ee-91d8-005056b8q12w",
  432. answer: _data.aiContent,
  433. problem: _data.content,
  434. file_id: _data.fileid ? _data.fileid : "",
  435. alltext: _data.aiContent,
  436. type: "chat",
  437. filename: _data.filename,
  438. session_name: `${this.courseId}-studyStudent` //这是对话记录位置
  439. };
  440. this.ajax
  441. .post("https://gpt4.cocorobo.cn/insert_chat", params)
  442. .then(res => {});
  443. },
  444. // 获取对应的聊天记录
  445. getChatList() {
  446. return new Promise((resolve, reject) => {
  447. if (this.loading) return this.$message.info("请稍等...");
  448. this.chatList = [];
  449. this.loading = true;
  450. let params = {
  451. userid: this.userid,
  452. groupid: "602def61-005d-11ee-91d8-005056b8q12w",
  453. // session_name:``
  454. session_name: `${this.courseId}-studyStudent`
  455. };
  456. this.ajax
  457. .post("https://gpt4.cocorobo.cn/get_agent_park_chat", params)
  458. .then(res => {
  459. let _data = JSON.parse(res.data.FunctionResponse);
  460. if (_data.length > 0) {
  461. let _chatList = [];
  462. for (let i = 0; i < _data.length; i++) {
  463. _chatList.push({
  464. loading: false,
  465. role: "user",
  466. content: _data[i].problem,
  467. uid: _data[i].id,
  468. AI: "AI",
  469. aiContent: _data[i].answer,
  470. oldContent: _data[i].answer,
  471. isShowSynchronization: false,
  472. filename: _data[i].filename,
  473. index: i,
  474. is_mind_map: false,
  475. fileid: _data[i].fileid
  476. });
  477. }
  478. this.chatList = _chatList;
  479. this.loading = false;
  480. } else {
  481. //没有对话记录
  482. this.loading = false;
  483. }
  484. resolve();
  485. })
  486. .catch(err => {
  487. console.log(err);
  488. this.$message.error("获取对话记录失败");
  489. this.loading = false;
  490. resolve();
  491. });
  492. });
  493. },
  494. sendAiIdea(text) {
  495. if (this.loading) return this.$message.info("请稍等");
  496. this.send(text);
  497. },
  498. sendImage() {
  499. this.$message.info("发送图片");
  500. },
  501. sendVideo() {
  502. this.$message.info("发送视频");
  503. },
  504. getWantSearch() {
  505. this.chatLoading = true;
  506. let _uuid = uuidv4();
  507. let _msg = `
  508. ATTENTION: Use '##' or '####' to SPLIT SECTIONS, not '#'.Output format carefully referenced "Format example".
  509. ## 任务
  510. 你的任务是根据“课程信息”,提供用户需要的搜索建议,将搜索建议的结果以有序列表的形式返回给用户。
  511. ## 课程信息
  512. #### 课程标题:${this.courseDetail.title}
  513. #### 分类:${this.courseDetail.name ? this.courseDetail.name : "无"}
  514. #### 学生年级:${
  515. this.courseDetail.classname ? this.courseDetail.classname : "无"
  516. }
  517. ---
  518. ## 规则
  519. - 输出结果基于“课程信息”,避免提供无关的信息。
  520. - 搜索建议的结果符合伦理规范。
  521. ---
  522. ## 输出
  523. - 输出应包括3个相关的搜索建议,每个搜索建议需要以问号的方式结束。
  524. - 请一步步思考如何根据现有信息推送搜索建议,但是不需要输出搜索建议以外的内容。
  525. ---
  526. ## 输出格式
  527. 搜索建议应以有序列表形式呈现,每个建议包括关键词和简短描述。输出JSON格式的数组
  528. ---
  529. ## Format example
  530. [{
  531. "index": 1,
  532. "title": "垃圾分类标准",
  533. "label": "不同国家的垃圾分类标准和方法?"
  534. },
  535. {
  536. "index": 2,
  537. "title": "可回收垃圾处理",
  538. "label": "可回收垃圾的处理流程和再利用方法?"
  539. },
  540. {
  541. "index": 3,
  542. "title": "有害垃圾的影响",
  543. "label": "有害垃圾对环境和人体健康的潜在影响?"
  544. }]
  545. `;
  546. this.chatList.push({
  547. role: "user",
  548. content: `wanSearch`,
  549. uid: _uuid,
  550. AI: "AI",
  551. aiContent: "",
  552. oldContent: "",
  553. isShowSynchronization: false,
  554. filename: "",
  555. index: this.chatList.length,
  556. is_mind_map: false,
  557. loading: true
  558. });
  559. this.scrollBottom();
  560. let params = {
  561. model: "gpt-3.5-turbo",
  562. temperature: 0,
  563. max_tokens: 4096,
  564. top_p: 1,
  565. frequency_penalty: 0,
  566. presence_penalty: 0,
  567. messages: [{ role: "user", content: _msg }],
  568. uid: _uuid,
  569. mind_map_question: ""
  570. };
  571. this.text = "";
  572. this.ajax
  573. .post("https://gpt4.cocorobo.cn/chat", params)
  574. .then(res => {
  575. if (res.data.FunctionResponse.result == "发送成功") {
  576. } else {
  577. this.chatLoading = false;
  578. this.$message.warning(res.data.FunctionResponse.result);
  579. }
  580. })
  581. .catch(e => {
  582. this.chatLoading = false;
  583. console.log(e);
  584. });
  585. this.getWAntSearchContent(_uuid);
  586. },
  587. scrollBottom() {
  588. this.$nextTick(() => {
  589. this.$refs.chatRef.scrollTop = this.$refs.chatRef.scrollHeight;
  590. });
  591. }
  592. },
  593. mounted() {
  594. this.getChatList().then(_ => {
  595. this.scrollBottom();
  596. this.getWantSearch();
  597. });
  598. }
  599. };
  600. </script>
  601. <style scoped>
  602. .search {
  603. width: 100%;
  604. height: 100%;
  605. box-sizing: border-box;
  606. }
  607. .imgNumberBlock {
  608. width: 100%;
  609. height: 30px;
  610. display: flex;
  611. justify-content: space-between;
  612. box-sizing: border-box;
  613. /* padding: 5px 10px; */
  614. }
  615. .imgNumberBlock > .imgNumber {
  616. width: 18%;
  617. height: 30px;
  618. white-space: initial;
  619. background: rgba(224, 234, 251, 1);
  620. border-radius: 5px;
  621. display: flex;
  622. align-items: center;
  623. cursor: pointer;
  624. justify-content: center;
  625. }
  626. .s_top {
  627. width: 100%;
  628. height: calc(100% - 90px);
  629. overflow-x: hidden;
  630. box-sizing: border-box;
  631. padding: 20px 0;
  632. }
  633. .s_t_chat {
  634. width: 100%;
  635. display: flex;
  636. box-sizing: border-box;
  637. padding: 10px;
  638. flex-direction: column;
  639. }
  640. .s_t_chat > div {
  641. display: flex;
  642. align-items: flex-start;
  643. width: 100%;
  644. }
  645. .s_t_c_user {
  646. box-sizing: border-box;
  647. padding-left: 35px;
  648. }
  649. .s_t_c_u_left {
  650. width: 90%;
  651. height: auto;
  652. }
  653. .s_t_c_u_l_content {
  654. width: auto;
  655. max-width: 100%;
  656. height: auto;
  657. box-sizing: border-box;
  658. padding: 10px;
  659. color: white;
  660. background-color: #3681fc;
  661. border-radius: 8px 2px 8px 8px;
  662. white-space: pre-line;
  663. word-break: break-all;
  664. }
  665. .s_t_c_a_r_contentImage > span {
  666. display: block;
  667. }
  668. .s_t_c_a_r_contentImage > img {
  669. width: 45%;
  670. height: 125px;
  671. margin: 1% 1.5%;
  672. border-radius: 5px;
  673. cursor: pointer;
  674. }
  675. .s_t_c_a_r_contentImage {
  676. width: auto;
  677. max-width: 100%;
  678. height: auto;
  679. box-sizing: border-box;
  680. padding: 10px;
  681. background-color: #f6f8ff;
  682. border-radius: 2px 8px 8px 8px;
  683. white-space: pre-line;
  684. word-break: break-all;
  685. }
  686. .s_t_c_u_l_time {
  687. width: 100%;
  688. display: flex;
  689. justify-content: flex-end;
  690. font-size: 12px;
  691. color: #9f9f9f;
  692. margin-top: 5px;
  693. }
  694. .s_t_c_u_right {
  695. width: 35px;
  696. height: 35px;
  697. display: flex;
  698. justify-content: center;
  699. margin-left: 5px;
  700. }
  701. .s_t_c_u_right > span {
  702. width: 32px;
  703. height: 32px;
  704. display: flex;
  705. justify-content: center;
  706. align-items: center;
  707. color: white;
  708. background-color: #3681fc;
  709. border-radius: 50%;
  710. }
  711. .s_t_c_ai {
  712. box-sizing: border-box;
  713. padding-right: 35px;
  714. position: relative;
  715. margin-top: 10px;
  716. }
  717. .aiCopy {
  718. position: absolute;
  719. right: 5px;
  720. bottom: 0%;
  721. transform: translate(0, -30%);
  722. cursor: pointer;
  723. }
  724. .s_t_c_a_right {
  725. min-width: 90%;
  726. height: auto;
  727. }
  728. .s_t_c_a_r_content {
  729. width: auto;
  730. max-width: 100%;
  731. height: auto;
  732. box-sizing: border-box;
  733. padding: 10px;
  734. background-color: #f6f8ff;
  735. border-radius: 2px 8px 8px 8px;
  736. white-space: pre-line;
  737. word-break: break-all;
  738. }
  739. .s_t_c_a_r_content2 {
  740. background-color: #f6f8ff;
  741. width: 100%;
  742. height: auto;
  743. box-sizing: border-box;
  744. padding: 10px;
  745. border-radius: 2px 8px 8px 8px;
  746. box-shadow: 0 0px 10px #c5cbee;
  747. }
  748. .s_t_c_a_r_c_title {
  749. display: flex;
  750. align-items: center;
  751. }
  752. .s_t_c_a_r_c_title > img {
  753. width: 16px;
  754. height: 16px;
  755. }
  756. .s_t_c_a_r_c_item {
  757. width: 100%;
  758. height: auto;
  759. box-sizing: border-box;
  760. padding: 10px;
  761. background-color: #ffffff;
  762. border-radius: 5px;
  763. margin-top: 10px;
  764. color: #666666;
  765. font-size: 14px;
  766. cursor: pointer;
  767. border: solid #ffffff 1px;
  768. box-shadow: 0 0 5px 2px #ffffff;
  769. }
  770. .s_t_c_a_r_c_item:hover {
  771. border: solid #b8d2fe 1px;
  772. box-shadow: 0 0 5px 2px #b8d2fe;
  773. }
  774. .s_t_c_a_r_c_title > span {
  775. font-weight: bold;
  776. }
  777. .s_t_c_a_r_time {
  778. width: 100%;
  779. display: flex;
  780. justify-content: flex-start;
  781. font-size: 12px;
  782. color: #9f9f9f;
  783. margin-top: 5px;
  784. }
  785. .s_t_c_a_left {
  786. width: 35px;
  787. height: 35px;
  788. display: flex;
  789. justify-content: center;
  790. margin-right: 5px;
  791. }
  792. .s_t_c_a_left > span {
  793. width: 32px;
  794. height: 32px;
  795. display: flex;
  796. justify-content: center;
  797. align-items: center;
  798. color: white;
  799. background-color: #3681fc;
  800. border-radius: 50%;
  801. }
  802. .s_bottom {
  803. width: 100%;
  804. height: 90px;
  805. display: flex;
  806. flex-direction: column;
  807. justify-content: space-between;
  808. }
  809. .s_b_btnArea {
  810. width: 100%;
  811. height: 30px;
  812. display: flex;
  813. align-items: center;
  814. box-sizing: border-box;
  815. padding: 0 10px;
  816. }
  817. .s_b_ba-item {
  818. width: auto;
  819. box-sizing: border-box;
  820. padding: 0 10px;
  821. height: 25px;
  822. background-color: white;
  823. display: flex;
  824. justify-content: center;
  825. align-items: center;
  826. /* 阴影 */
  827. box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.363);
  828. border-radius: 15px;
  829. font-size: 14px;
  830. cursor: pointer;
  831. margin-right: 10px;
  832. }
  833. .s_b_inputArea {
  834. width: 100%;
  835. height: 55px;
  836. box-sizing: border-box;
  837. border-top: solid 1px #ededed;
  838. display: flex;
  839. justify-content: space-between;
  840. align-items: center;
  841. padding-right: 10px;
  842. }
  843. .s_b_tape {
  844. width: 35px;
  845. height: 35px;
  846. background: url("../../../assets/icon/course/tape.png") no-repeat;
  847. background-size: 50% 60%;
  848. background-position: center;
  849. cursor: pointer;
  850. }
  851. .s_b_input {
  852. /* width: 65%; */
  853. flex: 1;
  854. height: 45px;
  855. background-color: #f3f3f3;
  856. border-radius: 50px;
  857. margin: 0 10px;
  858. display: flex;
  859. align-items: center;
  860. overflow: hidden;
  861. }
  862. .s_b_i_left {
  863. width: 100%;
  864. line-height: 45px;
  865. height: 100%;
  866. }
  867. .s_b_i_left >>> .el-input__inner {
  868. border: none;
  869. background-color: #f3f3f3;
  870. outline: none;
  871. border-radius: 50px 0 0 50px;
  872. }
  873. .s_b_i_right {
  874. width: 45px;
  875. height: 45px;
  876. display: flex;
  877. justify-content: center;
  878. align-items: center;
  879. }
  880. .s_b_i_right > span {
  881. width: 35px;
  882. height: 35px;
  883. background: url("../../../assets/icon/course/file.png") no-repeat;
  884. background-size: 50% 60%;
  885. background-position: center;
  886. cursor: pointer;
  887. }
  888. .s_b_btn {
  889. width: 40px;
  890. height: 40px;
  891. background-color: #3681fc;
  892. display: flex;
  893. justify-content: center;
  894. align-items: center;
  895. border-radius: 50%;
  896. cursor: pointer;
  897. }
  898. .s_b_btn > span {
  899. width: 30px;
  900. height: 30px;
  901. background: url("../../../assets/icon/course/send.png") no-repeat;
  902. background-size: 70% 70%;
  903. background-position: center;
  904. }
  905. </style>