taskArea.vue 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570
  1. <template>
  2. <div class="task">
  3. <div class="taskTop">
  4. <div class="tt_title">任务时间分配</div>
  5. <div class="tt_item">
  6. <div class="tt_i_title">
  7. <span>课程时间轴</span>
  8. </div>
  9. <div class="tt_i_box">
  10. <div class="tt_i_b_step" v-if="navList.length == 1">
  11. <!-- 只有一个阶段 -->
  12. <span
  13. :style="{
  14. background: taskCount >= index ? '#3681FC' : '#E0EAFB'
  15. }"
  16. v-for="(item, index) in navList[courseType].task"
  17. ></span>
  18. </div>
  19. <div class="tt_i_b_step" v-if="navList.length > 1">
  20. <!-- 多个阶段 -->
  21. <span
  22. :style="{
  23. background: courseType >= index ? '#3681FC' : '#E0EAFB'
  24. }"
  25. v-for="(item, index) in navList"
  26. ></span>
  27. </div>
  28. <!-- <img :src="require('../../../assets/icon/course/group.png')" /> -->
  29. </div>
  30. </div>
  31. <div class="tt_item">
  32. <div class="tt_i_title">
  33. <span>任务状态</span>
  34. <span>学生活动中...</span>
  35. </div>
  36. <div class="tt_i_box">
  37. <div class="tt_i_b_item">
  38. <div class="tt_i_b_title">作业提交</div>
  39. <div class="tt_i_b_box">
  40. <div class="tt_i_b_b_item">
  41. <div>提交人数</div>
  42. <span>{{ isWorkStudent }}<span>人</span></span>
  43. </div>
  44. <div
  45. class="tt_i_b_b_item"
  46. v-if="
  47. (this.$route.query.tcid || courseDetail.juri) &&
  48. allStudent &&
  49. complete != '-'
  50. "
  51. >
  52. <div>完成率</div>
  53. <span>{{ complete }}<span>%</span></span>
  54. </div>
  55. </div>
  56. </div>
  57. <div class="tt_i_b_item">
  58. <div class="tt_i_b_title">交流互动</div>
  59. <div class="tt_i_b_box">
  60. <div class="tt_i_b_b_item">
  61. <div>参与人数</div>
  62. <span>{{ isWorkAll }}<span>人</span></span>
  63. </div>
  64. <div class="tt_i_b_b_item">
  65. <div>点赞数</div>
  66. <span>{{ likeNum }}<span>个</span></span>
  67. </div>
  68. <div class="tt_i_b_b_item">
  69. <div>评论数</div>
  70. <span>{{ commentNum }}<span>条</span></span>
  71. </div>
  72. </div>
  73. </div>
  74. </div>
  75. </div>
  76. </div>
  77. <div class="t_top" ref="chatRef">
  78. <div class="t_t_chat" v-for="(item, index) in chatList" :key="index">
  79. <div class="t_t_c_user" v-if="item.content && item.content != 'addAsk'">
  80. <div class="t_t_c_u_left">
  81. <div class="t_t_c_u_l_content">{{ item.content }}</div>
  82. <div class="t_t_c_u_l_time">{{ item.createtime }}</div>
  83. </div>
  84. <div class="t_t_c_u_right">
  85. <span>我</span>
  86. </div>
  87. </div>
  88. <div class="t_t_c_ai" v-if="item.content != 'addAsk'">
  89. <div class="t_t_c_a_left">
  90. <el-avatar v-if="item.filename" :src="item.filename"></el-avatar>
  91. <span v-else>Ai</span>
  92. </div>
  93. <div class="t_t_c_a_right">
  94. <div
  95. class="t_t_c_a_r_content"
  96. style="display: flex;justify-content: space-between;flex-wrap: wrap;"
  97. v-if="pan(item.aiContent).length"
  98. >
  99. <div
  100. v-if="!pan(item.aiContent).length"
  101. class="d_t_c_a_r_content"
  102. v-loading="item.loading"
  103. v-html="item.aiContent"
  104. ></div>
  105. <div
  106. v-else
  107. v-for="i in pan(item.aiContent)"
  108. style="position: relative;"
  109. class="d_t_c_a_r_c_img"
  110. >
  111. <img
  112. style="width: 130px;height: 130px;object-fit: cover;"
  113. :src="i.image"
  114. alt=""
  115. @click="previewImg(i.image)"
  116. />
  117. <span class="download_image" @click.stop="download(i.image)">
  118. <img
  119. :src="require('../../../assets/icon/fileIcon/download.png')"
  120. />
  121. </span>
  122. </div>
  123. </div>
  124. <div
  125. v-else
  126. class="t_t_c_a_r_content"
  127. v-loading="item.loading"
  128. v-html="htmlContent(item.aiContent)"
  129. ></div>
  130. <div v-if="!pan(item.aiContent).length" class="aiCopy">
  131. <img
  132. @click="onCopy(item.aiContent)"
  133. style="width: 30px;"
  134. src="../../../assets/icon/course/copyTxt.png"
  135. alt=""
  136. />
  137. </div>
  138. <div class="t_t_c_a_r_time">{{ item.createtime }}</div>
  139. </div>
  140. </div>
  141. <div class="s_t_addAsk" v-if="item.content == 'addAsk' && !item.aiContent.questions && item.aiContent.length && !item.loading">
  142. <span v-for="item2 in item.aiContent" :key="item2.index" @click.stop="send(item2.label)">{{item2.label}}</span>
  143. </div>
  144. <div class="s_t_addAsk" v-if="item.content == 'addAsk' && item.aiContent.questions && !item.loading">
  145. <span v-for="(item2,index2) in item.aiContent.questions" :key="index2" @click.stop="send(item2.question?item2.question:item2)">{{item2.question?item2.question:item2}}</span>
  146. </div>
  147. <div class="s_t_addAsk" v-if="item.content == 'addAsk' && item.loading">
  148. <span style="width:50px;height:50px" v-loading="true"></span>
  149. </div>
  150. </div>
  151. </div>
  152. <div class="t_bottom">
  153. <div class="t_b_btnArea">
  154. <!-- <div class="s_b_ba-item" @click.stop="choiceRole()">选择角色</div> -->
  155. <div class="t_b_ba_item" @click="sendType('智能总结')">智能总结</div>
  156. <div class="t_b_ba_item" @click="sendType('智能出题')">智能出题</div>
  157. <!-- <div class="t_b_ba_item" @click="sendType('优秀标兵')">优秀标兵</div> -->
  158. <div class="t_b_ba_item" @click="sendType('扩展知识')">扩展知识</div>
  159. <div class="t_b_ba_item" @click="clear()">清空聊天记录</div>
  160. </div>
  161. <div class="t_b_inputArea">
  162. <!-- <div class="t_b_tape" @click="goTape()"></div> -->
  163. <div class="t_b_input">
  164. <el-input
  165. :disabled="loading || chatLoading"
  166. v-loading="loading || chatLoading"
  167. @keyup.enter.native="send()"
  168. placeholder="请在此输入您想了解的内容"
  169. class="t_b_i_left"
  170. v-model="text"
  171. ></el-input>
  172. <!-- <div class="t_b_i_right" @click="sendFile()">
  173. <span></span>
  174. </div> -->
  175. </div>
  176. <div class="t_b_btn" @click="send()">
  177. <span v-if="!loading && !chatLoading"></span>
  178. <div v-else @click.stop="stopSend()">停止</div>
  179. </div>
  180. </div>
  181. </div>
  182. </div>
  183. </template>
  184. <script>
  185. // import { Loading } from 'element-ui';
  186. import { v4 as uuidv4 } from "uuid";
  187. import MarkdownIt from "markdown-it";
  188. import { tools } from "../../../common/tools";
  189. export default {
  190. props: {
  191. courseDetail: {
  192. type: Object,
  193. default: () => {}
  194. },
  195. navList: {
  196. type: Array,
  197. default: () => []
  198. },
  199. courseType: {
  200. type: Number,
  201. default: 0
  202. },
  203. taskCount: {
  204. type: Number,
  205. default: 0
  206. },
  207. worksStudent: {
  208. type: Array,
  209. default: () => []
  210. },
  211. fileId:{
  212. type:Array,
  213. default:()=>[]
  214. }
  215. },
  216. data() {
  217. return {
  218. userid: this.$route.query.userid,
  219. courseId: this.$route.query.courseId,
  220. text: "",
  221. loading: false,
  222. chatLoading: false,
  223. chatList: [],
  224. nowChatList: [],
  225. source: null,
  226. saveUid: "",
  227. allStudent: [],
  228. tcid: this.$route.query.tcid,
  229. oid: this.$route.query.oid
  230. };
  231. },
  232. computed: {
  233. isWorkAll() {
  234. let _userList = [];
  235. if (this.worksStudent.length) {
  236. this.worksStudent.forEach(i => {
  237. if (i.length) {
  238. i.forEach(i2 => {
  239. if (i2.commentJson) {
  240. i2.commentJson.forEach(i3 => {
  241. if (
  242. i3.userid &&
  243. !_userList.find(i5 => i5.userid == i3.userid)
  244. ) {
  245. _userList.push(i3);
  246. }
  247. });
  248. }
  249. if (i2.likeJson) {
  250. i2.likeJson.forEach(i4 => {
  251. if (
  252. i4.likesId &&
  253. !_userList.find(i5 => i5.userid == i4.likesId)
  254. ) {
  255. _userList.push({ ...i4, userid: i4.likesId });
  256. }
  257. });
  258. }
  259. });
  260. }
  261. });
  262. }
  263. return _userList.length;
  264. },
  265. complete() {
  266. let _result = 0;
  267. let _all = this.allStudent ? this.allStudent.length : 0;
  268. if (_all == 0) return "-";
  269. _result = ((this.isWorkStudent / _all) * 100).toFixed(2);
  270. return _result;
  271. },
  272. likeNum() {
  273. let _result = 0;
  274. if (this.worksStudent.length) {
  275. this.worksStudent.forEach(i => {
  276. if (i.length) {
  277. i.forEach(i2 => {
  278. if (i2.likesCount) {
  279. _result += i2.likesCount;
  280. }
  281. });
  282. }
  283. });
  284. }
  285. return _result;
  286. },
  287. commentNum() {
  288. let _result = 0;
  289. if (this.worksStudent.length) {
  290. this.worksStudent.forEach(i => {
  291. if (i.length) {
  292. i.forEach(i2 => {
  293. if (i2.commentCount) {
  294. _result += i2.commentCount;
  295. }
  296. });
  297. }
  298. });
  299. }
  300. return _result;
  301. },
  302. isWorkStudent() {
  303. let _userList = [];
  304. if (this.worksStudent.length) {
  305. this.worksStudent.forEach(i => {
  306. if (i.length) {
  307. i.forEach(i2 => {
  308. if (
  309. i2.ttype == 2 &&
  310. !_userList.find(i3 => i3.userid == i2.userid)
  311. ) {
  312. _userList.push(i2);
  313. }
  314. });
  315. }
  316. });
  317. }
  318. return _userList.length;
  319. },
  320. pan() {
  321. return content => {
  322. try {
  323. return JSON.parse(content);
  324. } catch (error) {
  325. return [];
  326. }
  327. };
  328. },
  329. htmlContent() {
  330. const md = new MarkdownIt();
  331. return _md => {
  332. return md.render(_md);
  333. };
  334. }
  335. },
  336. methods: {
  337. stopSend() {
  338. if (this.source) {
  339. this.source.close();
  340. if (this.chatList[this.chatList.length - 1].content == "wanSearch") {
  341. this.chatList.pop();
  342. }
  343. this.loading = false;
  344. this.chatLoading = false;
  345. this.source = null;
  346. this.insertChat(this.saveUid);
  347. }
  348. },
  349. onCopy(content) {
  350. // 创建临时textarea元素
  351. const tempInput = document.createElement("textarea");
  352. tempInput.value = content; // 设置要复制的内容
  353. // 隐藏元素
  354. tempInput.style.position = "absolute";
  355. tempInput.style.left = "-9999px";
  356. // 将元素添加到DOM中
  357. document.body.appendChild(tempInput);
  358. // 选中元素内容
  359. tempInput.select();
  360. // 执行复制操作
  361. document.execCommand("copy");
  362. // 移除临时元素
  363. document.body.removeChild(tempInput);
  364. this.$message({
  365. message: "复制成功",
  366. type: "success"
  367. });
  368. },
  369. exportCourse() {
  370. let _user = `<div style="font-size:30px;margin-top:10px;"><span style="color: rgb(113, 124, 141); font-weight: 400;">创建者:</span><span>${this.courseDetail.username}</span></div>`;
  371. const _chapInfo = JSON.parse(this.courseDetail.chapters);
  372. let _chap = "";
  373. for (let i = 0; i < _chapInfo.length; i++) {
  374. _chap += `<div style="font-size:40px;margin-top:70px;"><span>第${i +
  375. 1}阶段:${_chapInfo[i].dyName}</span></div>`;
  376. let _task = _chapInfo[i].chapterInfo[0].taskJson;
  377. for (let j = 0; j < _task.length; j++) {
  378. _chap += `<div style="font-size:30px;margin-top:50px;"><span>任务${j +
  379. 1}:${_task[j].task}</span></div>`;
  380. if (_task[j].taskDetail) {
  381. _chap += `<div style="font-size:25px;margin-top:40px;">任务描述</div>`;
  382. _chap += `<div style="font-size:25px;margin-top:10px;">${_task[j].taskDetail}</div>`;
  383. }
  384. let _tool = _task[j].toolChoose;
  385. if (_tool[0].tool.length) {
  386. for (let z = 0; z < _tool.length; z++) {
  387. _chap += `<div style="font-size:23px;margin-top:30px;"><span>步骤${z +
  388. 1}:</span><span>${
  389. tools[_tool[z].tool[0]] ? tools[_tool[z].tool[0]].name : ""
  390. }</span></div>`;
  391. if (_tool[z].toolDetail) {
  392. _chap += `<div style="font-size:23px;margin-top:20px;">工具描述</div>`;
  393. _chap += `<div style="font-size:23px;margin-top:10px;">${_tool[z].toolDetail}</div>`;
  394. }
  395. }
  396. }
  397. }
  398. }
  399. let _html = _user + _chap;
  400. return _html;
  401. },
  402. previewImg(url) {
  403. this.$hevueImgPreview(url);
  404. },
  405. clear() {
  406. this.chatList = [];
  407. },
  408. // 获取ai对话
  409. getAiContent(_uid) {
  410. // this.source = new EventSource(
  411. // `https://claude3.cocorobo.cn/streamChat/${_uid}`
  412. // );
  413. this.source = new EventSource(`https://gpt4.cocorobo.cn/stream/${_uid}`); //http://gpt4.cocorobo.cn:8011/stream/ https://gpt4.cocorobo.cn/stream/
  414. let _allText = "";
  415. let _mdText = "";
  416. // const md = new MarkdownIt();
  417. this.source.onmessage = _e => {
  418. if (_e.data.replace("'", "").replace("'", "") == "[DONE]") {
  419. //对话已经完成
  420. _mdText = _mdText.replace("_", "");
  421. this.source.close();
  422. this.chatLoading = false;
  423. this.scrollBottom();
  424. this.chatList.find(i => i.uid == _uid).aiContent = _mdText;
  425. this.chatList.find(i => i.uid == _uid).isalltext = true;
  426. this.chatList.find(i => i.uid == _uid).isShowSynchronization = true;
  427. this.chatList.find(i => i.uid == _uid).loading = false;
  428. this.nowChatList.push(this.chatList.find(i => i.uid == _uid));
  429. let _content = this.chatList.find(i => i.uid == _uid).content;
  430. if (!["智能总结", "智能出题", "扩展知识"].includes(_content)) {
  431. this.addAsk(this.chatList.find(i => i.uid == _uid).content);
  432. }
  433. // 这里保存对话
  434. this.insertChat(_uid);
  435. return;
  436. } else {
  437. //对话还在继续
  438. let _text = "";
  439. _text = _e.data.replaceAll("'", "");
  440. if (_allText == "") {
  441. _allText = _text.replace(/^\n+/, ""); //去掉回复消息中偶尔开头就存在的连续换行符
  442. } else {
  443. _allText += _text;
  444. }
  445. _mdText = _allText + "_";
  446. _mdText = _mdText.replace(/\\n/g, "\n");
  447. _mdText = _mdText.replace(/\\/g, "");
  448. if (_allText.split("```").length % 2 == 0) _mdText += "\n```\n";
  449. //转化返回的回复流数据
  450. // _mdText = md.render(_mdText);
  451. this.chatList.find(i => i.uid == _uid).aiContent = _mdText;
  452. this.chatList.find(i => i.uid == _uid).loading = false;
  453. this.scrollBottom();
  454. // 处理流数据
  455. }
  456. };
  457. },
  458. getAtAuContent(_uid) {
  459. this.source = new EventSource(`https://gpt4.cocorobo.cn/question/${_uid}`);
  460. //http://gpt4.cocorobo.cn:8011/question/ https://gpt4.cocorobo.cn/question/
  461. let _allText = "";
  462. let _mdText = "";
  463. // const md = new MarkdownIt();
  464. this.source.onmessage = _e => {
  465. let _eData = JSON.parse(_e.data);
  466. if (_eData.content.replace("'", "").replace("'", "") == "[DONE]") {
  467. let _result = [];
  468. if ("result" in _eData) {
  469. _result = _eData.result;
  470. for (let i = 0; i < _result.length; i++) {
  471. _mdText = _mdText.replace(_result[i].text, _result[i].fileName);
  472. }
  473. }
  474. _mdText = _mdText.replace("_", "");
  475. this.chatLoading = false;
  476. this.chatList.find(i => i.uid == _uid).aiContent = _mdText;
  477. this.chatList.find(i => i.uid == _uid).isalltext = true;
  478. this.chatList.find(i => i.uid == _uid).isShowSynchronization = true;
  479. this.chatList.find(i => i.uid == _uid).loading = false;
  480. this.nowChatList.push(this.chatList.find(i => i.uid == _uid));
  481. this.addAsk(this.chatList.find(i => i.uid == _uid).content)
  482. this.source.close();
  483. this.insertChat(_uid);
  484. } else {
  485. let _text = _eData.content.replace("'", "").replace("'", "");
  486. if (_allText == "") {
  487. _allText = _text.replace(/^\n+/, ""); //去掉回复消息中偶尔开头就存在的连续换行符
  488. } else {
  489. _allText += _text;
  490. }
  491. _mdText = _allText + "_";
  492. _mdText = _mdText.replace(/\\n/g, "\n");
  493. _mdText = _mdText.replace(/\\/g, "");
  494. if (_allText.split("```").length % 2 == 0) _mdText += "\n```\n";
  495. //转化返回的回复流数据
  496. // _mdText = md.render(_mdText);
  497. this.chatList.find(i => i.uid == _uid).aiContent = _mdText;
  498. this.chatList.find(i => i.uid == _uid).loading = false;
  499. this.$nextTick(() => {
  500. this.$refs.chatRef.scrollTop = this.$refs.chatRef.scrollHeight;
  501. });
  502. // 处理流数据
  503. }
  504. };
  505. },
  506. //保存消息
  507. insertChat(_uid) {
  508. if (_uid == "") return;
  509. let _data = this.chatList.find(i => i.uid == _uid);
  510. if (!_data) return;
  511. let params = {
  512. userId: this.userid,
  513. userName: "qgt",
  514. groupId: "602def61-005d-11ee-91d8-005056b8q12w",
  515. answer: _data.aiContent,
  516. problem: _data.content,
  517. file_id: _data.fileid ? _data.fileid : "",
  518. alltext: _data.aiContent,
  519. type: "chat",
  520. filename: _data.filename,
  521. session_name: `${this.courseId}-studyStudent-md` //这是对话记录位置
  522. };
  523. this.saveUid = "";
  524. this.ajax
  525. .post("https://gpt4.cocorobo.cn/insert_chat", params)
  526. .then(res => {});
  527. },
  528. // 获取对应的聊天记录
  529. getChatList() {
  530. return new Promise((resolve, reject) => {
  531. if (this.loading) return this.$message.info("请稍等...");
  532. this.chatList = [];
  533. this.loading = true;
  534. this.chatLoading = true;
  535. let params = {
  536. userid: this.userid,
  537. groupid: "602def61-005d-11ee-91d8-005056b8q12w",
  538. // session_name:``
  539. session_name: `${this.courseId}-studyStudent-md`
  540. };
  541. this.ajax
  542. .post("https://gpt4.cocorobo.cn/get_agent_park_chat", params)
  543. .then(res => {
  544. let _data = JSON.parse(res.data.FunctionResponse);
  545. if (_data.length > 0) {
  546. let _chatList = [];
  547. for (let i = 0; i < _data.length; i++) {
  548. _chatList.push({
  549. loading: false,
  550. role: "user",
  551. content: _data[i].problem,
  552. uid: _data[i].id,
  553. AI: "AI",
  554. aiContent: _data[i].answer,
  555. oldContent: _data[i].answer,
  556. isShowSynchronization: false,
  557. filename: _data[i].filename,
  558. index: i,
  559. is_mind_map: false,
  560. fileid: _data[i].fileid
  561. });
  562. }
  563. this.chatList = _chatList;
  564. this.loading = false;
  565. this.chatLoading = false;
  566. } else {
  567. //没有对话记录
  568. this.loading = false;
  569. this.chatLoading = false;
  570. }
  571. resolve();
  572. })
  573. .catch(err => {
  574. console.log(err);
  575. this.$message.error("获取对话记录失败");
  576. this.loading = false;
  577. this.chatLoading = false;
  578. resolve();
  579. });
  580. });
  581. },
  582. // choiceRole() {
  583. // this.cardType = 1;
  584. // },
  585. // sendFile() {
  586. // if (this.loading) return this.$message.info("请稍等");
  587. // this.$message.info("点击了附件");
  588. // },
  589. // goTape() {
  590. // if (this.loading) return this.$message.info("请稍等");
  591. // this.$message.info(`点击了语音`);
  592. // },
  593. send(_text = this.text) {
  594. if (this.loading || this.chatLoading) return this.$message.info("请稍等");
  595. if (_text.trim().length == 0) return this.$message.info("请输入内容");
  596. this.chatLoading = true;
  597. let _uuid = uuidv4();
  598. this.chatList.push({
  599. role: "user",
  600. content: `${_text}`,
  601. uid: _uuid,
  602. AI: "AI",
  603. aiContent: "",
  604. oldContent: "",
  605. isShowSynchronization: false,
  606. filename: "",
  607. index: this.chatList.length,
  608. is_mind_map: false,
  609. loading: true
  610. });
  611. this.scrollBottom();
  612. let history = [];
  613. this.nowChatList.forEach(i => {
  614. if (i.content == "wanSearch") {
  615. // history.push({
  616. // role: "assistant",
  617. // content: i.aiContent
  618. // });
  619. return;
  620. } else if (i.content == "getImage") {
  621. return history.push({
  622. role: "assistant",
  623. content: i.aiContent
  624. });
  625. }
  626. if (i.content) {
  627. history.push({
  628. role: "user",
  629. content: i.content
  630. });
  631. }
  632. if (i.aiContent) {
  633. history.push({
  634. role: "assistant",
  635. content: i.aiContent
  636. });
  637. }
  638. });
  639. history.push({ role: "user", content: _text });
  640. // history.pop();
  641. let params = {
  642. assistant_id: 'f8e1ebb2-2e0d-11ef-8bf4-12e77c4cb76b',
  643. userId: this.userid,
  644. message: _text,
  645. session_name: `${this.courseId}-studyStudent-md`,
  646. uid: _uuid,
  647. file_ids: this.fileId
  648. };
  649. // let params = {
  650. // model: "gpt-3.5-turbo",
  651. // temperature: 0,
  652. // max_tokens: 4096,
  653. // top_p: 1,
  654. // frequency_penalty: 0,
  655. // presence_penalty: 0,
  656. // messages: history,
  657. // uid: _uuid,
  658. // mind_map_question: _text
  659. // };
  660. // let params = {
  661. // message: {
  662. // anthropic_version: "bedrock-2023-05-31",
  663. // max_tokens: 4096,
  664. // temperature: 0,
  665. // top_p: 1,
  666. // messages: history
  667. // },
  668. // uid: _uuid,
  669. // model: "Claude 3 Sonnet" // Claude 3 Sonnet或者Claude 3 Haiku
  670. // };
  671. this.text = "";
  672. this.ajax
  673. // .post("https://claude3.cocorobo.cn/chat", params)
  674. // .post("https://gpt4.cocorobo.cn/chat", params)
  675. .post("https://gpt4.cocorobo.cn/ai_agent_park_chat_new", params)
  676. .then(res => {
  677. if (res.data.FunctionResponse.result == "发送成功") {
  678. } else {
  679. // this.$message.warning(res.data.FunctionResponse.result);
  680. console.log(res.data.FunctionResponse.result)
  681. this.chatLoading = false;
  682. }
  683. })
  684. .catch(e => {
  685. console.log(e);
  686. this.chatLoading = false;
  687. });
  688. this.saveUid = _uuid;
  689. // this.getAiContent(_uuid);
  690. this.getAtAuContent(_uuid)
  691. },
  692. sendType(_text) {
  693. if (this.loading || this.chatLoading) return this.$message.info("请稍等");
  694. let _msg = ``;
  695. if (_text == "扩展知识") {
  696. // return console.log(this.courseDetail);
  697. _msg = `
  698. NOTICE
  699. 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.
  700. ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenced "Format example".
  701. Instruction: Based on the context, follow "Format example", write content.
  702. # Context
  703. ## 任务
  704. 你的任务是根据用户的请求,结合以下“课程信息”包含的子条目(“课程标题”,“分类”以及“年级”),向用户输出相关的扩展知识点,将结果以有序列表的形式返回给用户。
  705. 课程信息
  706. 课程标题:${this.courseDetail.title}
  707. 分类:${this.courseDetail.name ? this.courseDetail.name : "无"}
  708. 学生年级:${this.courseDetail.classname ? this.courseDetail.classname : "无"}
  709. ## 规则
  710. 1. 内容应该与“课程信息”相关,避免提供无关的信息。
  711. 2. 当课程信息中的子条目内容为“无”时,无视这些条目进行即可。
  712. 3. 搜索建议的结果应该符合伦理规范。
  713. 4. 一步步思考如何根据“课程信息”来输出“扩展知识点”,但是你不需要“扩展知识点”以外的内容。
  714. ## 格式要求
  715. 1. 应包括5个相关的“扩展知识点”。
  716. 2. 搜索建议应以有序列表形式呈现,每个建议包括关键词和简短描述。
  717. # Format example
  718. ## 课程标题:垃圾回收
  719. 分类:无
  720. 年级:无
  721. 1. 垃圾分类标准:不同国家的垃圾分类标准和方法。
  722. 2. 可回收垃圾处理:可回收垃圾的处理流程和再利用方法。
  723. 3. 有害垃圾的影响:有害垃圾对环境和人体健康的潜在影响。
  724. 4. 垃圾减量化策略:减少垃圾产生的有效策略和实践。
  725. 5. 环保教育活动:在学校中推广环保意识的活动和资源。
  726. `;
  727. } else if (_text == "智能出题") {
  728. // console.log("👇")
  729. // return console.log(this.navList[this.courseType].task[this.taskCount].taskName)
  730. _msg = `
  731. NOTICE
  732. 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.
  733. ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenced "Format example".
  734. Instruction: Based on the context, follow "Format example", write content.
  735. # Context
  736. ## 任务
  737. 你的任务是根据用户的请求,结合以下“课程信息”包含的子条目(“课程标题”,“分类”以及“年级”),向用户输出当前任务相关的练习题目,将结果以有序列表的形式返回给用户。
  738. 课程信息
  739. 课程标题:${this.courseDetail.title}
  740. 分类:${this.courseDetail.name ? this.courseDetail.name : "无"}
  741. 学生年级:${this.courseDetail.classname ? this.courseDetail.classname : "无"}
  742. 当前任务名称:${this.navList[this.courseType].task[this.taskCount].taskName}
  743. ## 规则
  744. 1. 练习题目内容应该与“课程信息”相关,避免提供无关的信息。
  745. 2. 当课程信息中的子条目内容为“无”时,无视这些条目进行输出即可。
  746. 3. 一步步思考如何根据“课程信息”输出“练习题目”,但是你不需要输出“练习题目”以外的内容。
  747. 4.输出练习题目后,提示用户“希望这些题目能帮到你,如果需要其他类型题目或者更多题目,可以随时向我输入你的需求”
  748. ## 格式要求
  749. 1. 输出应包括3道相关的“练习题目”。
  750. 2. 练习题目默认只包含3道4选1的单选题,除非用户在提示词中更具体地指明了题目类型和数量。
  751. 3. 练习题目应以有序列表形式呈现,每个建议包括关键词和简短描述。
  752. # Format example
  753. ## 课程标题:垃圾回收
  754. 分类:无
  755. 年级:无
  756. 1. 垃圾回收的主要目的是: a) 增加垃圾的数量 b) 减少垃圾的数量 c) 提高垃圾的质量 d) 增加垃圾的种类
  757. 2. 以下哪种垃圾是可以回收的? a) 食物残渣 b) 塑料瓶 c) 湿纸巾 d) 动物粪便
  758. 3. 垃圾分类中,玻璃瓶通常属于哪一类? a) 可回收垃圾 b) 厨余垃圾 c) 有害垃圾 d) 其他垃圾
  759. `;
  760. console.log(_msg);
  761. } else if (_text == "智能总结") {
  762. _msg = `
  763. NOTICE
  764. 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.
  765. ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenced "Format example".
  766. Instruction: Based on the context, follow "Format example", write content.
  767. # Context
  768. ## 任务
  769. 你的任务是根据用户的请求,结合以下“课程信息”包含的子条目(“课程标题”,“主题”,“学科”,“年级”以及“学习内容”),对课程进行课程总结,请根据输出格式将内容输出给用户。
  770. 课程信息
  771. 课程标题:${this.courseDetail.title}
  772. 分类:${this.courseDetail.name ? this.courseDetail.name : "无"}
  773. 学生年级:${this.courseDetail.classname ? this.courseDetail.classname : "无"}
  774. 学习内容:${this.exportCourse()}
  775. ## 规则
  776. 1. “课程总结”内容应该与“课程信息”相关,避免提供无关的信息。
  777. 2. 当课程信息中的子条目内容为“无”时,无视这些条目进行输出即可。
  778. 3. 一步步思考如何根据“课程信息”输出“课程总结”。
  779. ## 格式要求
  780. 1. 以无序列表的形式输出“课程信息”中的“课程标题”,“主题”,“学科”以及“年级”,若这些条目中的内容为“无”,则不需要输出
  781. ## 示例
  782. 课程标题:垃圾回收
  783. 分类:自然科学 语文 数学
  784. 年级:无
  785. 学习内容:垃圾回收是指将废弃物重新加工利用的过程,这不仅有助于减少环境污染,还能节约资源。首先,垃圾回收可以减少填埋场的压力,避免土地资源的浪费和地下水的污染。其次,通过回收纸张、塑料、金属等材料,我们可以减少对原材料的需求,从而保护森林、矿产等自然资源。此外,垃圾回收还能减少温室气体的排放,缓解气候变化。引导学生思考垃圾回收的意义,可以从以下几个方面入手:一是环境保护,垃圾回收能有效减少污染,保护生态系统;二是资源节约,通过回收利用,我们可以减少对自然资源的消耗;三是经济效益,垃圾回收产业可以创造就业机会,促进经济发展。通过这些思考,学生们可以更深刻地理解垃圾回收的重要性,并在日常生活中积极参与到垃圾分类和回收的行动中来,共同为可持续发展贡献力量。
  786. # Format example
  787. ## 课程标题:垃圾回收
  788. 分类:自然科学 语文 数学
  789. 年级:无
  790. 学习内容:学习内容包含一份引导学生思考为何要进行垃圾回收的文档材料
  791. `;
  792. }
  793. if (!_msg) return;
  794. // console.log(_msg)
  795. this.chatLoading = true;
  796. let _uuid = uuidv4();
  797. this.chatList.push({
  798. role: "user",
  799. content: `${_text}`,
  800. uid: _uuid,
  801. AI: "AI",
  802. aiContent: "",
  803. oldContent: "",
  804. isShowSynchronization: false,
  805. filename: "",
  806. index: this.chatList.length,
  807. is_mind_map: false,
  808. loading: true
  809. });
  810. let history = [];
  811. this.nowChatList.forEach(i => {
  812. if (i.content == "wanSearch") {
  813. // history.push({
  814. // role: "assistant",
  815. // content: JSON.stringify(i.aiContent)
  816. // });
  817. return;
  818. } else if (i.content == "getImage") {
  819. return history.push({
  820. role: "assistant",
  821. content: i.aiContent
  822. });
  823. }
  824. if (i.content) {
  825. history.push({
  826. role: "user",
  827. content: i.content
  828. });
  829. }
  830. if (i.aiContent) {
  831. history.push({
  832. role: "assistant",
  833. content: i.aiContent
  834. });
  835. }
  836. });
  837. // history.pop();
  838. if (_msg) {
  839. history.push({ role: "user", content: _msg });
  840. }
  841. // history.push({ role: "user", content: _text });
  842. this.scrollBottom();
  843. let params = {
  844. assistant_id: 'f8e1ebb2-2e0d-11ef-8bf4-12e77c4cb76b',
  845. userId: this.userid,
  846. message: _msg,
  847. session_name: `${this.courseId}-studyStudent-md`,
  848. uid: _uuid,
  849. file_ids: this.fileId
  850. };
  851. // let params = {
  852. // model: "gpt-3.5-turbo",
  853. // temperature: 0,
  854. // max_tokens: 4096,
  855. // top_p: 1,
  856. // frequency_penalty: 0,
  857. // presence_penalty: 0,
  858. // messages: history,
  859. // uid: _uuid,
  860. // mind_map_question: _text
  861. // };
  862. // let params = {
  863. // message: {
  864. // anthropic_version: "bedrock-2023-05-31",
  865. // max_tokens: 4096,
  866. // temperature: 0,
  867. // top_p: 1,
  868. // messages: history
  869. // },
  870. // uid: _uuid,
  871. // model: "Claude 3 Sonnet" // Claude 3 Sonnet或者Claude 3 Haiku
  872. // };
  873. this.text = "";
  874. this.ajax
  875. // .post("https://claude3.cocorobo.cn/chat", params)
  876. .post("https://gpt4.cocorobo.cn/ai_agent_park_chat_new", params)
  877. // .post("https://gpt4.cocorobo.cn/chat", params)
  878. .then(res => {
  879. if (res.data.FunctionResponse.result == "发送成功") {
  880. } else {
  881. //this.$message.warning(res.data.FunctionResponse.result);
  882. console.log(res.data.FunctionResponse.result)
  883. this.chatLoading = false;
  884. }
  885. })
  886. .catch(e => {
  887. console.log(e);
  888. this.chatLoading = false;
  889. });
  890. this.saveUid = _uuid;
  891. // this.getAiContent(_uuid);
  892. this.getAtAuContent(_uuid)
  893. // this.send(text);
  894. },
  895. addAsk(_text){
  896. // this.chatLoading = true;
  897. let _uuid = uuidv4();
  898. let _msg = `NOTICERole: 你是一个多功能的AI助手,能够根据学生的文本内容判断其情感状态,并提供相应的支持和引导。Output: Provide your output in json format.ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenced \"Format example\".Instruction: Based on the context, follow \"Format example\", write content.# Context## 任务1.学生文本内容,执行以下任务。首先,请你判断学生是否进行情感倾诉,比如心情不好、遭遇校园暴力、对他人进行人身攻击等。如果是,请扮演一个心理咨询师的角色,坚持人本主义的立场,善良、温柔地引导对方,安抚对方的情绪,为对方提供心理支持。剩下的其它情况,请你扮演提问引导者的角色,延续学生的提问,围绕问题本身,提出3个问题,激发学生的深度思考、创造性思考。2.人本主义心理学人本主义心理学强调个体的主观体验和自我实现,认为每个人都有内在的潜力和价值。心理咨询师应当以同理心、无条件积极关注和真诚的态度对待来访者,帮助他们发现自身的力量和解决问题的能力。3.提问引导技巧提问引导技巧包括开放性问题、反思性问题和假设性问题等,旨在通过提问激发对方的思考和探索,帮助他们深入理解问题并找到解决方案。## 工作流程1. 仔细阅读并分析学生提供的文本内容。2. 判断学生是否进行情感倾诉。3. 如果是情感倾诉,扮演心理咨询师的角色,提供情感支持和引导。4. 如果不是情感倾诉,扮演提问引导者的角色,围绕问题本身提出3个问题。## 限制/注意事项 1.在回答时应保持专业性和权威性,确保信息的准确性和可靠性。2.避免生成与问题无关或不恰当的回答,确保回答的相关性和实用性。3.在提供情感支持时,注意用词温柔,避免引起对方的负面情绪。## 要求1. 内容包含情感支持或追加问题。2. 情感支持部分应体现同理心和积极关注。3. 追加问题应具有启发性和深度。## 学生文本内容${_text}# Format example [{\"index\": 1,\"label\": \"不同国家的垃圾分类标准和方法?\"},{\"index\": 2, \"label\": \"可回收垃圾的处理流程和再利用方法?\"},{\"index\": 3,\"label\": \"有害垃圾对环境和人体健康的潜在影响?\"}]`;
  899. _msg = _msg.replace(/[\r\n]/g, "");
  900. this.chatList.push({
  901. role: "user",
  902. content: `addAsk`,
  903. uid: _uuid,
  904. AI: "AI",
  905. aiContent: "",
  906. oldContent: "",
  907. isShowSynchronization: false,
  908. filename: "",
  909. index: this.chatList.length,
  910. is_mind_map: false,
  911. loading: true
  912. });
  913. this.scrollBottom();
  914. let history = [];
  915. // this.nowChatList.forEach(i => {
  916. // if (i.content == "wanSearch") {
  917. // // history.push({
  918. // // role:"assistant",
  919. // // content: JSON.stringify(i.aiContent)
  920. // // })
  921. // return;
  922. // } else if (i.content == "getImage") {
  923. // return history.push({
  924. // role: "assistant",
  925. // content: i.aiContent
  926. // });
  927. // }else if(i.content == "addAsk"){
  928. // }
  929. // if (i.content) {
  930. // history.push({
  931. // role: "user",
  932. // content: i.content
  933. // });
  934. // }
  935. // if (i.aiContent) {
  936. // history.push({
  937. // role: "assistant",
  938. // content: i.aiContent
  939. // });
  940. // }
  941. // });
  942. history.push({ type: "text", text: _msg });
  943. console.log(history)
  944. // let params = {
  945. // model: "gpt-3.5-turbo",
  946. // temperature: 0,
  947. // max_tokens: 4096,
  948. // top_p: 1,
  949. // frequency_penalty: 0,
  950. // presence_penalty: 0,
  951. // messages:history,
  952. // stream: false,
  953. // uid: _uuid,
  954. // mind_map_question: ""
  955. // };
  956. let params = {
  957. assistant_id: '6063369f-289a-11ef-8bf4-12e77c4cb76b',
  958. userId: this.userid,
  959. message: history,
  960. session_name:_uuid,
  961. // uid: _uuid,
  962. file_ids: this.fileId
  963. };
  964. // let params = {
  965. // message: {
  966. // anthropic_version: "bedrock-2023-05-31",
  967. // max_tokens: 4096,
  968. // temperature: 0,
  969. // top_p: 1,
  970. // messages: [{ role: "user", content: _msg }]
  971. // },
  972. // uid: _uuid,
  973. // model: "Claude 3 Sonnet" // Claude 3 Sonnet或者Claude 3 Haiku
  974. // };
  975. this.text = "";
  976. this.ajax
  977. // .post("https://gpt4.cocorobo.cn/chat", params)
  978. // .post("https://claude3.cocorobo.cn/chat", params)
  979. .post("https://gpt4.cocorobo.cn/ai_agent_park_chat", params)
  980. .then(res => {
  981. console.log(res)
  982. let _data = res.data.FunctionResponse.message;
  983. console.log(_data);
  984. _data = _data.replaceAll("```json", "").replaceAll("```", "");
  985. this.chatList.find(i => i.uid == _uuid).aiContent =JSON.parse(_data);
  986. this.chatList.find(i => i.uid == _uuid).isalltext = true;
  987. this.chatList.find(i => i.uid == _uuid).isShowSynchronization = true;
  988. this.chatList.find(i => i.uid == _uuid).loading = false;
  989. this.scrollBottom();
  990. // this.chatLoading = false;
  991. })
  992. .catch(e => {
  993. this.chatLoading = false;
  994. this.chatList.find(i => i.uid == _uuid).loading = false;
  995. console.log(e);
  996. });
  997. },
  998. getAllStudent() {
  999. let params = {
  1000. oid: this.oid,
  1001. cid: this.tcid ? this.tcid : this.courseDetail.juri
  1002. };
  1003. this.allStudent = [];
  1004. this.ajax
  1005. .get(this.$store.state.api + "selectWorksStudent", params)
  1006. .then(res => {
  1007. this.allStudent = res.data[0];
  1008. });
  1009. },
  1010. scrollBottom() {
  1011. this.$nextTick(() => {
  1012. this.$refs.chatRef.scrollTop = this.$refs.chatRef.scrollHeight;
  1013. });
  1014. },
  1015. download(_url) {
  1016. let xhr = new XMLHttpRequest();
  1017. xhr.open("GET", _url, true);
  1018. xhr.responseType = "blob";
  1019. xhr.onload = () => {
  1020. if (xhr.status === 200) {
  1021. let blob = xhr.response;
  1022. // const _blob = new Blob([blob], { type: fileType });
  1023. const downloadElement = document.createElement("a");
  1024. const url = window.URL.createObjectURL(blob);
  1025. downloadElement.href = url;
  1026. downloadElement.download = "Image.jpg";
  1027. downloadElement.click();
  1028. window.URL.revokeObjectURL(url); // 释放内存
  1029. }else{
  1030. this.$message.error("此图片不支持下载");
  1031. }
  1032. };
  1033. xhr.onerror = (e)=>{
  1034. console.log(e)
  1035. this.$message.error("此图片不支持下载");
  1036. }
  1037. xhr.send();
  1038. }
  1039. },
  1040. mounted() {
  1041. this.getChatList().then(_ => {
  1042. this.scrollBottom();
  1043. });
  1044. this.getAllStudent();
  1045. this.nowChatList = [];
  1046. }
  1047. };
  1048. </script>
  1049. <style scoped>
  1050. .task {
  1051. width: 100%;
  1052. height: 100%;
  1053. box-sizing: border-box;
  1054. }
  1055. .aiCopy {
  1056. position: absolute;
  1057. right: 5px;
  1058. bottom: 0%;
  1059. /* transform: translate(0, -30%); */
  1060. cursor: pointer;
  1061. }
  1062. .taskTop {
  1063. width: 100%;
  1064. height: 280px;
  1065. box-sizing: border-box;
  1066. padding: 10px;
  1067. overflow-x: hidden;
  1068. }
  1069. .tt_title {
  1070. font-size: 18px;
  1071. font-weight: bold;
  1072. margin-bottom: 5px;
  1073. }
  1074. .tt_item {
  1075. width: 100%;
  1076. height: auto;
  1077. margin-top: 10px;
  1078. }
  1079. .tt_i_title {
  1080. display: flex;
  1081. justify-content: space-between;
  1082. align-items: center;
  1083. }
  1084. .tt_i_title > span:nth-of-type(2) {
  1085. box-sizing: border-box;
  1086. padding: 0 10px;
  1087. height: 25px;
  1088. background-color: #effcf5;
  1089. color: #83e0af;
  1090. }
  1091. .tt_i_box {
  1092. width: 100%;
  1093. height: auto;
  1094. display: flex;
  1095. margin-top: 10px;
  1096. justify-content: space-between;
  1097. }
  1098. .tt_i_b_step {
  1099. display: flex;
  1100. width: 100%;
  1101. height: auto;
  1102. margin: 10px 0;
  1103. }
  1104. .tt_i_b_step > span {
  1105. height: 5px;
  1106. background-color: #e0eafb;
  1107. flex: 1;
  1108. border-left: 2px solid #fff;
  1109. }
  1110. .tt_i_b_step > span:nth-child(-1) {
  1111. border: none;
  1112. }
  1113. .tt_i_box > img {
  1114. width: 100%;
  1115. height: 50px;
  1116. }
  1117. .tt_i_b_item {
  1118. width: auto;
  1119. height: 90px;
  1120. background-color: #f6f9ff;
  1121. }
  1122. .tt_i_b_title {
  1123. width: 100%;
  1124. height: 30px;
  1125. display: flex;
  1126. justify-content: center;
  1127. align-items: center;
  1128. box-sizing: border-box;
  1129. border: solid 1px #e0eafb;
  1130. color: #626466;
  1131. }
  1132. .tt_i_b_box {
  1133. width: auto;
  1134. min-width: 140px;
  1135. height: 60px;
  1136. box-sizing: border-box;
  1137. border: solid 1px #e0eafb;
  1138. border-top: none;
  1139. display: flex;
  1140. }
  1141. .tt_i_b_b_item {
  1142. width: 70px;
  1143. min-width: 70px;
  1144. flex: 1;
  1145. height: 100%;
  1146. display: flex;
  1147. flex-direction: column;
  1148. justify-content: center;
  1149. align-items: center;
  1150. border-left: solid 1px #e0eafb;
  1151. }
  1152. .tt_i_b_box > .tt_i_b_b_item:nth-of-type(1) {
  1153. border-left: none;
  1154. }
  1155. .tt_i_b_b_item > div {
  1156. font-size: 14px;
  1157. color: #949599;
  1158. }
  1159. .tt_i_b_b_item > span {
  1160. font-weight: bold;
  1161. }
  1162. .tt_i_b_b_item > span > span {
  1163. font-size: 12px;
  1164. font-weight: 200;
  1165. }
  1166. .t_top {
  1167. width: 100%;
  1168. /* height: calc(100% - 90px); */
  1169. height: calc(100% - 370px);
  1170. overflow: auto;
  1171. box-sizing: border-box;
  1172. padding: 20px 0;
  1173. }
  1174. .t_t_chat {
  1175. width: 100%;
  1176. display: flex;
  1177. box-sizing: border-box;
  1178. padding: 10px;
  1179. flex-direction: column;
  1180. }
  1181. .t_t_chat > div {
  1182. display: flex;
  1183. align-items: flex-start;
  1184. width: 100%;
  1185. }
  1186. .t_t_c_user {
  1187. box-sizing: border-box;
  1188. padding-left: 35px;
  1189. }
  1190. .t_t_c_u_left {
  1191. width: 90%;
  1192. height: auto;
  1193. }
  1194. .t_t_c_u_l_content {
  1195. width: auto;
  1196. max-width: 100%;
  1197. height: auto;
  1198. box-sizing: border-box;
  1199. padding: 10px;
  1200. color: white;
  1201. background-color: #3681fc;
  1202. border-radius: 8px 2px 8px 8px;
  1203. white-space: pre-line;
  1204. }
  1205. .t_t_c_u_l_time {
  1206. width: 100%;
  1207. display: flex;
  1208. justify-content: flex-end;
  1209. font-size: 12px;
  1210. color: #9f9f9f;
  1211. margin-top: 5px;
  1212. }
  1213. .t_t_c_u_right {
  1214. width: 35px;
  1215. height: 35px;
  1216. display: flex;
  1217. justify-content: center;
  1218. margin-left: 5px;
  1219. }
  1220. .t_t_c_u_right > span {
  1221. width: 32px;
  1222. height: 32px;
  1223. display: flex;
  1224. justify-content: center;
  1225. align-items: center;
  1226. color: white;
  1227. background-color: #3681fc;
  1228. border-radius: 50%;
  1229. }
  1230. .t_t_c_ai {
  1231. margin-top: 10px;
  1232. box-sizing: border-box;
  1233. padding-right: 35px;
  1234. position: relative;
  1235. }
  1236. .t_t_c_a_right {
  1237. min-width: 90%;
  1238. height: auto;
  1239. }
  1240. .t_t_c_a_r_content {
  1241. width: auto;
  1242. max-width: 100%;
  1243. height: auto;
  1244. box-sizing: border-box;
  1245. padding: 10px;
  1246. background-color: #f6f8ff;
  1247. border-radius: 2px 8px 8px 8px;
  1248. white-space: pre-line;
  1249. word-break: break-all;
  1250. }
  1251. .t_t_c_a_r_content2 {
  1252. background-color: #f6f8ff;
  1253. width: 100%;
  1254. height: auto;
  1255. box-sizing: border-box;
  1256. padding: 10px;
  1257. border-radius: 2px 8px 8px 8px;
  1258. white-space: pre-line;
  1259. box-shadow: 0 0px 10px #c5cbee;
  1260. }
  1261. .t_t_c_a_r_c_title {
  1262. display: flex;
  1263. align-items: center;
  1264. }
  1265. .t_t_c_a_r_c_title > img {
  1266. width: 16px;
  1267. height: 16px;
  1268. }
  1269. .t_t_c_a_r_c_item {
  1270. width: 100%;
  1271. height: auto;
  1272. box-sizing: border-box;
  1273. padding: 10px;
  1274. background-color: #ffffff;
  1275. border-radius: 5px;
  1276. margin-top: 5px;
  1277. color: #666666;
  1278. font-size: 14px;
  1279. cursor: pointer;
  1280. }
  1281. .t_t_c_a_r_c_item:hover {
  1282. border: solid #b8d2fe 1px;
  1283. box-shadow: 0 0 5px 2px #b8d2fe;
  1284. }
  1285. .t_t_c_a_r_c_title > span {
  1286. font-weight: bold;
  1287. }
  1288. .t_t_c_a_r_time {
  1289. width: 100%;
  1290. display: flex;
  1291. justify-content: flex-start;
  1292. font-size: 12px;
  1293. color: #9f9f9f;
  1294. margin-top: 5px;
  1295. }
  1296. .t_t_c_a_left {
  1297. width: 35px;
  1298. height: 35px;
  1299. display: flex;
  1300. justify-content: center;
  1301. margin-right: 5px;
  1302. }
  1303. .t_t_c_a_left > span {
  1304. width: 32px;
  1305. height: 32px;
  1306. display: flex;
  1307. justify-content: center;
  1308. align-items: center;
  1309. color: white;
  1310. background-color: #3681fc;
  1311. border-radius: 50%;
  1312. }
  1313. .t_bottom {
  1314. width: 100%;
  1315. height: 90px;
  1316. display: flex;
  1317. flex-direction: column;
  1318. justify-content: space-between;
  1319. }
  1320. .t_b_btnArea {
  1321. width: 100%;
  1322. height: 30px;
  1323. display: flex;
  1324. align-items: center;
  1325. box-sizing: border-box;
  1326. padding: 0 10px;
  1327. overflow-y: hidden;
  1328. }
  1329. .t_b_ba_item {
  1330. width: auto;
  1331. box-sizing: border-box;
  1332. padding: 0 10px;
  1333. height: 25px;
  1334. background-color: white;
  1335. display: flex;
  1336. justify-content: center;
  1337. align-items: center;
  1338. /* 阴影 */
  1339. box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.363);
  1340. border-radius: 15px;
  1341. font-size: 14px;
  1342. cursor: pointer;
  1343. margin-right: 10px;
  1344. white-space: nowrap;
  1345. transition: 0.3s;
  1346. }
  1347. .t_b_ba_item:hover {
  1348. background-color: rgb(236, 236, 236);
  1349. }
  1350. .t_b_inputArea {
  1351. width: 100%;
  1352. height: 55px;
  1353. box-sizing: border-box;
  1354. border-top: solid 1px #ededed;
  1355. display: flex;
  1356. justify-content: space-between;
  1357. align-items: center;
  1358. padding-right: 10px;
  1359. }
  1360. .t_b_tape {
  1361. width: 35px;
  1362. height: 35px;
  1363. background: url("../../../assets/icon/course/tape.png") no-repeat;
  1364. background-size: 50% 60%;
  1365. background-position: center;
  1366. cursor: pointer;
  1367. }
  1368. .t_b_input {
  1369. /* width: 75%; */
  1370. flex: 1;
  1371. height: 45px;
  1372. background-color: #f3f3f3;
  1373. border-radius: 50px;
  1374. margin: 0 10px;
  1375. display: flex;
  1376. overflow: hidden;
  1377. align-items: center;
  1378. }
  1379. .t_b_i_left {
  1380. /* width: calc(100% - 45px); */
  1381. width: 100%;
  1382. line-height: 45px;
  1383. height: 100%;
  1384. }
  1385. .t_b_i_left >>> .el-input__inner {
  1386. border: none;
  1387. background-color: #f3f3f3;
  1388. outline: none;
  1389. border-radius: 50px 0 0 50px;
  1390. }
  1391. .t_b_i_right {
  1392. width: 45px;
  1393. height: 45px;
  1394. display: flex;
  1395. justify-content: center;
  1396. align-items: center;
  1397. }
  1398. .t_b_i_right > span {
  1399. width: 35px;
  1400. height: 35px;
  1401. background: url("../../../assets/icon/course/file.png") no-repeat;
  1402. background-size: 50% 60%;
  1403. background-position: center;
  1404. cursor: pointer;
  1405. }
  1406. .t_b_btn {
  1407. width: 40px;
  1408. height: 40px;
  1409. background-color: #3681fc;
  1410. display: flex;
  1411. justify-content: center;
  1412. align-items: center;
  1413. border-radius: 50%;
  1414. cursor: pointer;
  1415. }
  1416. .t_b_btn > div {
  1417. width: 100%;
  1418. height: 100%;
  1419. display: flex;
  1420. justify-content: center;
  1421. align-items: center;
  1422. color: #fff;
  1423. }
  1424. .t_b_btn > span {
  1425. width: 30px;
  1426. height: 30px;
  1427. background: url("../../../assets/icon/course/send.png") no-repeat;
  1428. background-size: 70% 70%;
  1429. background-position: center;
  1430. }
  1431. td,
  1432. th {
  1433. padding: 10px;
  1434. }
  1435. .s_t_addAsk {
  1436. width: 100%;
  1437. height: auto;
  1438. padding: 10px 20px;
  1439. display: flex;
  1440. flex-direction: column;
  1441. justify-content: center;
  1442. align-items: center;
  1443. box-sizing: border-box;
  1444. }
  1445. .s_t_addAsk > span {
  1446. box-sizing: border-box;
  1447. width: auto;
  1448. height: auto;
  1449. padding: 15px;
  1450. margin-bottom: 10px;
  1451. background-color: #f5f6f7;
  1452. border-radius: 10px;
  1453. cursor: pointer;
  1454. border: solid 1px #e8e9ec;
  1455. transition: 0.3s;
  1456. }
  1457. .s_t_addAsk > span:hover {
  1458. background-color: #e8e9ec;
  1459. }
  1460. .d_t_c_a_r_c_img:hover .download_image {
  1461. display: block;
  1462. }
  1463. .download_image {
  1464. position: absolute;
  1465. display: none;
  1466. right: 5px;
  1467. bottom: 5px;
  1468. width: 30px;
  1469. height: 30px;
  1470. cursor: pointer;
  1471. }
  1472. .download_image > img {
  1473. width: 100%;
  1474. height: 100%;
  1475. }
  1476. </style>