aiBox2.vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894
  1. <template>
  2. <div class="ai_body">
  3. <div class="ai_body_dialog" v-loading="loading" ref="chatDialog">
  4. <div
  5. class="dialog_content"
  6. v-for="(item, index) in array"
  7. :key="item.uid"
  8. >
  9. <div v-if="item.content">
  10. <div class="content content2" v-html="item.content"></div>
  11. <div class="role">
  12. <img src="../../../assets/icon/new/role2.png" />
  13. </div>
  14. </div>
  15. <div style="margin-top:10px ;">
  16. <div class="role">
  17. <img src="../../../assets/icon/new/role1.png" />
  18. </div>
  19. <div
  20. class="content"
  21. v-loading="item.loading"
  22. v-html="item.aiContent"
  23. ></div>
  24. </div>
  25. <!-- <div class="role">
  26. <img src="../../../assets/icon/new/role1.png"/>
  27. <img src="../../../assets/icon/new/role2.png"/>
  28. </div>
  29. <div class="content content2" :class="{ content2: item.role == 2 }">
  30. {{ item.text }}
  31. </div>
  32. <div class="role">
  33. <img src="../../../assets/icon/new/role1.png"/>
  34. </div>
  35. <div class="content">
  36. {{ item.text }}
  37. </div> -->
  38. </div>
  39. </div>
  40. <div class="ai_body_select">
  41. <div class="checkBox" v-if="checkBool">
  42. <div class="task">
  43. <div class="title">选择需要优化的任务:</div>
  44. <div class="content">
  45. <div class="span" @click="addAllTask()">
  46. <div class="check">
  47. <img
  48. :src="checkImg"
  49. alt=""
  50. v-if="checkArray.length !== course.length"
  51. />
  52. <img :src="checkIsImg" alt="" v-else />
  53. </div>
  54. <span>全选</span>
  55. </div>
  56. <div
  57. class="span"
  58. v-for="(item, index) in course"
  59. :key="index"
  60. @click="addTask(index)"
  61. >
  62. <div class="check">
  63. <img
  64. :src="checkImg"
  65. alt=""
  66. v-if="checkArray.indexOf(index) === -1"
  67. />
  68. <img :src="checkIsImg" alt="" v-else />
  69. </div>
  70. <span>任务{{ index + 1 }}</span>
  71. </div>
  72. </div>
  73. </div>
  74. <div class="part">
  75. <div class="title">选择优化的部分:</div>
  76. <div class="content">
  77. <div
  78. class="span"
  79. v-for="(item, index) in partArray"
  80. :key="index"
  81. :class="{ active: part == item.name }"
  82. @click="checkPart(item.name)"
  83. >
  84. {{ item.name }}
  85. </div>
  86. </div>
  87. </div>
  88. </div>
  89. <span
  90. class="check"
  91. :class="{ isCheck: checkBool }"
  92. v-if="!checkArray.length && !part"
  93. @click="checkBool = !checkBool"
  94. >选择优化内容</span
  95. >
  96. <span
  97. class="check"
  98. :class="{ isCheck: checkBool }"
  99. @click="checkBool = !checkBool"
  100. v-else
  101. >
  102. <el-tooltip :content="taskName" placement="top" effect="dark">
  103. <!-- content to trigger tooltip here -->
  104. <span>{{ taskName }}</span>
  105. </el-tooltip>
  106. </span>
  107. </div>
  108. <div class="ai_body_input">
  109. <textarea
  110. rows="3"
  111. @keyup.enter="addContent"
  112. class="binfo_input binfo_textarea"
  113. cols
  114. v-model.trim="courseText"
  115. placeholder="在此输入您想了解的内容"
  116. ></textarea>
  117. <div
  118. class="c_pub_button_confirm"
  119. v-if="!loading && courseText"
  120. @click="addContent"
  121. >
  122. 发送
  123. </div>
  124. <div class="c_pub_button_confirm" @click="promptTit" v-else>发送</div>
  125. </div>
  126. </div>
  127. </template>
  128. <script>
  129. import checkImg from "../../../assets/icon/sourceFile/check.png";
  130. import checkIsImg from "../../../assets/icon/sourceFile/check_is.png";
  131. import { v4 as uuidv4 } from "uuid";
  132. import MarkdownIt from "markdown-it";
  133. export default {
  134. props: {
  135. unitJson: {
  136. type: Array
  137. },
  138. courseId:{
  139. type:String,
  140. default:""
  141. },
  142. },
  143. data() {
  144. return {
  145. array: [],
  146. courseText: "",
  147. checkImg: checkImg,
  148. checkIsImg: checkIsImg,
  149. userid: this.$route.query.userid,
  150. checkArray: [],
  151. course: [{ title: "任务1" }, { title: "任务2" }, { title: "任务3" }],
  152. partArray: [
  153. { name: "全部内容" },
  154. { name: "任务设计" },
  155. { name: "评价设计" }
  156. ],
  157. part: "全部内容",
  158. checkBool: false,
  159. loading: false,
  160. username: "",
  161. };
  162. },
  163. watch: {
  164. unitJson: {
  165. immediate: true,
  166. deep: true,
  167. handler(newValue, oldValue) {
  168. this.course = this.unitJson[0].chapterInfo[0].taskJson;
  169. }
  170. }
  171. },
  172. methods: {
  173. promptTit() {
  174. if (!this.loading && !this.courseText) {
  175. this.$message({
  176. message: "请输入您想要了解的内容",
  177. type: "warning"
  178. });
  179. } else {
  180. this.$message({
  181. message: "请回答完毕后再次发送",
  182. type: "warning"
  183. });
  184. }
  185. },
  186. addContent() {
  187. let message = this.courseText
  188. if (this.courseText) {
  189. let msg = `
  190. ATTENTION: Use '##' to SPLIT SECTIONS, not '#'.Output format carefully referenced "Format example".`
  191. if(this.checkArray.length){
  192. let task = []
  193. if(this.part == "全部内容"){
  194. // msg += `--------
  195. // ## 示例
  196. // [
  197. // {
  198. // detail: "面向学生的任务描述",
  199. // elist:[
  200. // {"value":"评价名字1","detail":"评价维度1", "score": 5},
  201. // {"value":"评价名字2","detail":"评价维度2", "score": 5},
  202. // {"value":"评价名字3","detail":"评价维度3", "score": 5}
  203. // ],
  204. // toolChoose: [
  205. // {
  206. // tool:"电子白板",
  207. // detail: "工具描述"
  208. // },
  209. // {
  210. // tool:"思维大图",
  211. // detail: "工具描述"
  212. // }
  213. // ]
  214. // },
  215. // {
  216. // detail: "面向学生的任务描述",
  217. // elist:[
  218. // {"value":"评价名字1","detail":"评价维度1", "score": 5},
  219. // {"value":"评价名字2","detail":"评价维度2", "score": 5},
  220. // {"value":"评价名字3","detail":"评价维度3", "score": 5}
  221. // ],
  222. // toolChoose: []
  223. // },
  224. // {
  225. // detail: "面向学生的任务描述",
  226. // elist:[
  227. // {"value":"评价名字1","detail":"评价维度1", "score": 5},
  228. // {"value":"评价名字2","detail":"评价维度2", "score": 5},
  229. // {"value":"评价名字3","detail":"评价维度3", "score": 5}
  230. // ],
  231. // toolChoose: [
  232. // {
  233. // tool:"文档",
  234. // detail: "工具描述"
  235. // }
  236. // ]
  237. // }
  238. // ]
  239. // --------
  240. // ## 输出格式与要求
  241. // [
  242. // {
  243. // detail: "面向学生的任务描述",
  244. // elist:[
  245. // {"value":"评价名字1","detail":"评价维度1","score":5},
  246. // {"value":"评价名字2","detail":"评价维度2","score":5},
  247. // {"value":"评价名字3","detail":"评价维度3","score":5}
  248. // ],//至少3条评价标准,这个评价是教师用来评价学生表现的,需要包含评价维度,以及该维度中教师期待学生的表现,句式为学生应该能....
  249. // toolChoose: [
  250. // {
  251. // tool: "工具", //电子白板,文档,思维导图,表格,作业提交中选择其中一个工具
  252. // detail: "工具描述"
  253. // }
  254. // ] //可0~2个工具
  255. // }
  256. // ]
  257. // `
  258. for(var i = 0; i < this.checkArray.length; i++){
  259. let _index = this.checkArray[i]
  260. task.push(this.course[_index])
  261. }
  262. }else if(this.part == "任务设计"){
  263. // msg += `
  264. // --------
  265. // ## 示例
  266. // [
  267. // {
  268. // detail: "面向学生的任务描述",
  269. // toolChoose: [
  270. // {
  271. // tool:"电子白板",
  272. // detail: "工具描述"
  273. // },
  274. // {
  275. // tool:"思维大图",
  276. // detail: "工具描述"
  277. // }
  278. // ]
  279. // },
  280. // {
  281. // detail: "面向学生的任务描述",
  282. // toolChoose: []
  283. // },
  284. // {
  285. // detail: "面向学生的任务描述",
  286. // toolChoose: [
  287. // {
  288. // tool:"文档",
  289. // detail: "工具描述"
  290. // }
  291. // ]
  292. // }
  293. // ]
  294. // --------
  295. // ## 输出格式与要求
  296. // [
  297. // {
  298. // detail: "面向学生的任务描述",
  299. // toolChoose: [
  300. // {
  301. // tool: "工具", //电子白板,文档,思维导图,表格,作业提交中选择其中一个工具
  302. // detail: "工具描述"
  303. // }
  304. // ] //可0~2个工具
  305. // }
  306. // ]
  307. // `
  308. for(var i = 0; i < this.checkArray.length; i++){
  309. let _index = this.checkArray[i]
  310. task.push(this.course[_index])
  311. }
  312. }else if(this.part == "评价设计"){
  313. // msg += `
  314. // --------
  315. // ## 示例
  316. // [
  317. // {
  318. // elist:[
  319. // {"value":"评价名字1","detail":"评价维度1", "score": 5},
  320. // {"value":"评价名字2","detail":"评价维度2", "score": 5},
  321. // {"value":"评价名字3","detail":"评价维度3", "score": 5}
  322. // ],
  323. // },
  324. // {
  325. // elist:[
  326. // {"value":"评价名字1","detail":"评价维度1", "score": 5},
  327. // {"value":"评价名字2","detail":"评价维度2", "score": 5},
  328. // {"value":"评价名字3","detail":"评价维度3", "score": 5}
  329. // ],
  330. // },
  331. // {
  332. // elist:[
  333. // {"value":"评价名字1","detail":"评价维度1", "score": 5},
  334. // {"value":"评价名字2","detail":"评价维度2", "score": 5},
  335. // {"value":"评价名字3","detail":"评价维度3", "score": 5}
  336. // ],
  337. // }
  338. // ]
  339. // --------
  340. // ## 输出格式与要求
  341. // [
  342. // {
  343. // elist:[
  344. // {"value":"评价名字1","detail":"评价维度1","score":5},
  345. // {"value":"评价名字2","detail":"评价维度2","score":5},
  346. // {"value":"评价名字3","detail":"评价维度3","score":5}
  347. // ],//至少3条评价标准,这个评价是教师用来评价学生表现的,需要包含评价维度,以及该维度中教师期待学生的表现,句式为学生应该能....
  348. // }
  349. // ]
  350. // `
  351. for(var i = 0; i < this.checkArray.length; i++){
  352. let _index = this.checkArray[i]
  353. task.push(this.course[_index].eList)
  354. }
  355. }
  356. msg += `
  357. --------
  358. ## 修改内容
  359. ${JSON.stringify(task)}
  360. `
  361. msg += `
  362. --------
  363. ## 要求
  364. ${this.courseText}
  365. `
  366. message = msg
  367. }
  368. let _uuid = uuidv4();
  369. this.array.push({
  370. role: "user",
  371. content: `${this.courseText}`,
  372. uid: _uuid,
  373. AI: "AI",
  374. aiContent: "",
  375. oldContent: "",
  376. isShowSynchronization: false,
  377. filename: "",
  378. index: this.array.length,
  379. is_mind_map: false,
  380. loading: true
  381. });
  382. this.$nextTick(() => {
  383. this.$refs.chatDialog.scrollTop = this.$refs.chatDialog.scrollHeight;
  384. });
  385. let params = JSON.stringify({
  386. model: "gpt-3.5-turbo",
  387. temperature: 0,
  388. max_tokens: 4096,
  389. top_p: 1,
  390. frequency_penalty: 0,
  391. presence_penalty: 0,
  392. messages: [{ role: "user", content: message }],
  393. uid: _uuid,
  394. mind_map_question: ""
  395. });
  396. this.courseText = "";
  397. this.ajax
  398. .post("https://gpt4.cocorobo.cn/chat", params)
  399. .then(res => {
  400. if (res.data.FunctionResponse.result == "发送成功") {
  401. } else {
  402. this.$message.warning(res.data.FunctionResponse.result);
  403. }
  404. })
  405. .catch(e => {
  406. console.log(e);
  407. });
  408. this.getAiContent(_uuid);
  409. }
  410. },
  411. getAiContent(_uid) {
  412. let _source = new EventSource(`https://gpt4.cocorobo.cn/stream/${_uid}`); //http://gpt4.cocorobo.cn:8011/stream/ https://gpt4.cocorobo.cn/stream/
  413. let _allText = "";
  414. let _mdText = "";
  415. const md = new MarkdownIt();
  416. _source.onmessage = _e => {
  417. if (_e.data.replace("'", "").replace("'", "") == "[DONE]") {
  418. //对话已经完成
  419. _mdText = _mdText.replace("_", "");
  420. _source.close();
  421. this.$nextTick(() => {
  422. this.$refs.chatDialog.scrollTop = this.$refs.chatDialog.scrollHeight;
  423. });
  424. this.array.find(i => i.uid == _uid).aiContent = _mdText;
  425. this.array.find(i => i.uid == _uid).isalltext = true;
  426. this.array.find(i => i.uid == _uid).isShowSynchronization = true;
  427. this.array.find(i => i.uid == _uid).loading = false;
  428. // 这里保存对话
  429. this.insertChat(_uid);
  430. return;
  431. } else {
  432. //对话还在继续
  433. let _text = "";
  434. _text = _e.data.replaceAll("'", "");
  435. if (_allText == "") {
  436. _allText = _text.replace(/^\n+/, ""); //去掉回复消息中偶尔开头就存在的连续换行符
  437. } else {
  438. _allText += _text;
  439. }
  440. _mdText = _allText + "_";
  441. _mdText = _mdText.replace(/\\n/g, "\n");
  442. _mdText = _mdText.replace(/\\/g, "");
  443. if (_allText.split("```").length % 2 == 0) _mdText += "\n```\n";
  444. //转化返回的回复流数据
  445. _mdText = md.render(_mdText);
  446. this.array.find(i => i.uid == _uid).aiContent = _mdText;
  447. this.array.find(i => i.uid == _uid).loading = false;
  448. this.$nextTick(() => {
  449. this.$refs.chatDialog.scrollTop = this.$refs.chatDialog.scrollHeight;
  450. });
  451. // 处理流数据
  452. }
  453. };
  454. },
  455. async getUserName() {
  456. let params = { uid: this.userid };
  457. try {
  458. let res = await this.ajax.get(this.$store.state.api + "getUser", params);
  459. this.username = res.data[0][0].name;
  460. } catch (err) {
  461. console.error(err);
  462. }
  463. },
  464. //保存消息
  465. async insertChat(_uid) {
  466. let _data = this.array.find(i => i.uid == _uid);
  467. if (!_data) return;
  468. if(!this.username){
  469. await this.getUserName()
  470. }
  471. let params = {
  472. userId: this.userid,
  473. userName: this.username,
  474. groupId: "602def61-005d-11ee-91d8-005056b8q12w",
  475. answer: _data.aiContent,
  476. problem: _data.content,
  477. file_id: _data.fileid ? _data.fileid : "",
  478. alltext: _data.aiContent,
  479. type: "chat",
  480. filename: _data.filename,
  481. session_name: `${this.courseId}-addCourse` //这是对话记录位置
  482. };
  483. this.ajax
  484. .post("https://gpt4.cocorobo.cn/insert_chat", params)
  485. .then(res => {});
  486. },
  487. // 获取对应的聊天记录
  488. getChatList() {
  489. return new Promise((resolve, reject) => {
  490. if (this.loading) return this.$message.info("请稍等...");
  491. this.array = [];
  492. this.loading = true;
  493. let params = {
  494. userid: this.userid,
  495. groupid: "602def61-005d-11ee-91d8-005056b8q12w",
  496. // session_name:``
  497. session_name: `${this.courseId}-addCourse`
  498. };
  499. this.ajax
  500. .post("https://gpt4.cocorobo.cn/get_agent_park_chat", params)
  501. .then(res => {
  502. let _data = JSON.parse(res.data.FunctionResponse).response;
  503. if (_data.length > 0) {
  504. let _chatList = [];
  505. for (let i = 0; i < _data.length; i++) {
  506. _chatList.push({
  507. loading: false,
  508. role: "user",
  509. content: _data[i].problem,
  510. uid: _data[i].id,
  511. AI: "AI",
  512. aiContent: _data[i].answer,
  513. oldContent: _data[i].answer,
  514. isShowSynchronization: false,
  515. filename: _data[i].filename,
  516. index: i,
  517. is_mind_map: false,
  518. fileid: _data[i].fileid
  519. });
  520. }
  521. this.array = _chatList;
  522. this.loading = false;
  523. } else {
  524. //没有对话记录
  525. this.loading = false;
  526. }
  527. resolve();
  528. })
  529. .catch(err => {
  530. console.log(err);
  531. this.$message.error("获取对话记录失败");
  532. this.loading = false;
  533. resolve();
  534. });
  535. });
  536. },
  537. addTask(index) {
  538. if (this.checkArray.indexOf(index) !== -1) {
  539. this.checkArray.splice(this.checkArray.indexOf(index), 1);
  540. } else {
  541. this.checkArray.push(index);
  542. }
  543. console.log(index);
  544. },
  545. addAllTask() {
  546. if (this.checkArray.length === this.course.length) {
  547. this.checkArray = [];
  548. } else {
  549. this.checkArray = [];
  550. this.course.forEach((item, index) => {
  551. this.checkArray.push(index);
  552. });
  553. }
  554. },
  555. checkPart(name) {
  556. this.part = name;
  557. }
  558. },
  559. computed: {
  560. courseTextLength() {
  561. return this.courseText.length;
  562. },
  563. taskName() {
  564. let task = "";
  565. if (this.checkArray.length) {
  566. task = "任务";
  567. this.checkArray = this.checkArray.sort((a, b) => a - b);
  568. let a = JSON.parse(JSON.stringify(this.checkArray));
  569. for (let index = 0; index < a.length; index++) {
  570. a[index]++;
  571. }
  572. task += a.join("/");
  573. }
  574. return task + " " + this.part;
  575. }
  576. },
  577. mounted() {
  578. this.getChatList().then(_ => {
  579. this.$nextTick(() => {
  580. console.log(this.$refs.chatDialog.scrollHeight)
  581. this.$refs.chatDialog.scrollTop = this.$refs.chatDialog.scrollHeight;
  582. });
  583. });
  584. }
  585. };
  586. </script>
  587. <style scoped>
  588. .ai_body {
  589. height: 100%;
  590. width: calc(100% - 20px);
  591. margin: 0 auto;
  592. }
  593. .binfo_input {
  594. width: 100%;
  595. margin: 0;
  596. padding: 12px 14px;
  597. display: block;
  598. min-width: 0;
  599. outline: none;
  600. box-sizing: border-box;
  601. background: none;
  602. border: none;
  603. border-radius: 4px;
  604. background: #fff;
  605. font-size: 14px;
  606. resize: none;
  607. font-family: "Microsoft YaHei";
  608. min-height: 48px;
  609. /* border: 1px solid #3682fc00; */
  610. border: 1.5px solid #cad1dc;
  611. }
  612. .binfo_textarea {
  613. border: 1.5px solid #cad1dc;
  614. font-size: 14px;
  615. resize: none;
  616. /* background: #f6f6f6; */
  617. font-family: "Microsoft YaHei";
  618. }
  619. .binfo_textarea::-webkit-scrollbar {
  620. /*滚动条整体样式*/
  621. width: 6px;
  622. /*高宽分别对应横竖滚动条的尺寸*/
  623. height: 6px;
  624. }
  625. /*定义滚动条轨道 内阴影+圆角*/
  626. .binfo_textarea::-webkit-scrollbar-track {
  627. border-radius: 10px;
  628. background-color: rgba(0, 0, 0, 0.1);
  629. }
  630. /*定义滑块 内阴影+圆角*/
  631. .binfo_textarea::-webkit-scrollbar-thumb {
  632. border-radius: 10px;
  633. -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
  634. background-color: rgba(0, 0, 0, 0.1);
  635. }
  636. .binfo_input:focus-visible {
  637. border: 1.5px solid #3681fc !important;
  638. }
  639. .ai_body_input {
  640. /* position: relative; */
  641. display: flex;
  642. flex-direction: column;
  643. justify-content: center;
  644. align-items: end;
  645. }
  646. .c_pub_button_confirm {
  647. /* position: absolute;
  648. bottom: 13px;
  649. right: 13px; */
  650. margin-top: 10px;
  651. width: 80px;
  652. display: flex;
  653. justify-content: center;
  654. }
  655. .ai_body_dialog {
  656. padding: 10px 0;
  657. box-sizing: border-box;
  658. height: calc(100% - 180px);
  659. overflow: auto;
  660. margin-bottom: 10px;
  661. }
  662. .dialog_content {
  663. width: 100%;
  664. display: flex;
  665. flex-direction: column;
  666. }
  667. .dialog_content > div {
  668. display: flex;
  669. align-items: flex-start;
  670. }
  671. .dialog_content + .dialog_content {
  672. margin: 15px 0;
  673. }
  674. .dialog_content > div .right {
  675. flex-direction: row-reverse;
  676. }
  677. .dialog_content > div .right .role {
  678. margin-right: 0;
  679. margin-left: 10px;
  680. }
  681. .dialog_content > div .role {
  682. min-width: 30px;
  683. width: 30px;
  684. height: 30px;
  685. margin-right: 10px;
  686. border-radius: 50%;
  687. }
  688. .dialog_content > div .role > img {
  689. height: 100%;
  690. width: 100%;
  691. }
  692. .dialog_content > div .content {
  693. padding: 10px 5px;
  694. border-radius: 5px;
  695. width: 100%;
  696. word-break: break-word;
  697. box-sizing: border-box;
  698. /* white-space: pre-line; */
  699. max-width: 100%;
  700. background: #f7f7f7;
  701. overflow: hidden;
  702. margin: 0 10px;
  703. }
  704. .dialog_content > div .content2 {
  705. background: #3681fc;
  706. color: #fff;
  707. }
  708. .ai_body_select {
  709. position: relative;
  710. }
  711. .ai_body_select > .check {
  712. background: #e7e7e7;
  713. display: flex;
  714. width: fit-content;
  715. padding: 0 10px;
  716. height: 30px;
  717. border-radius: 21px;
  718. font-size: 14px;
  719. align-items: center;
  720. justify-content: center;
  721. color: #0061ff;
  722. font-weight: 700;
  723. margin: 10px 0;
  724. cursor: pointer;
  725. }
  726. .ai_body_select > .check::before {
  727. content: "";
  728. width: 15px;
  729. height: 15px;
  730. display: block;
  731. background-image: url("../../../assets/icon/course/aiPart.png");
  732. background-size: 100% 100%;
  733. margin-right: 5px;
  734. }
  735. .ai_body_select > .check::after {
  736. content: "";
  737. width: 15px;
  738. height: 15px;
  739. display: block;
  740. background-image: url("../../../assets/icon/course/aiPart_arrow.png");
  741. background-size: 100% 100%;
  742. margin-right: 5px;
  743. }
  744. .ai_body_select > .isCheck {
  745. background: #0061ff;
  746. display: flex;
  747. width: fit-content;
  748. padding: 0 10px;
  749. height: 30px;
  750. border-radius: 21px;
  751. font-size: 14px;
  752. align-items: center;
  753. justify-content: center;
  754. color: #fff;
  755. font-weight: 700;
  756. margin: 10px 0;
  757. cursor: pointer;
  758. max-width: 100%;
  759. box-sizing: border-box;
  760. }
  761. .ai_body_select > .isCheck > span {
  762. width: calc(100% - 40px);
  763. display: block;
  764. overflow: hidden;
  765. white-space: nowrap;
  766. text-overflow: ellipsis;
  767. }
  768. .ai_body_select > .isCheck::before {
  769. content: "";
  770. width: 15px;
  771. height: 15px;
  772. display: block;
  773. background-image: url("../../../assets/icon/course/aiPart_active.png");
  774. background-size: 100% 100%;
  775. margin-right: 5px;
  776. }
  777. .ai_body_select > .isCheck::after {
  778. content: "";
  779. width: 15px;
  780. height: 15px;
  781. display: block;
  782. background-image: url("../../../assets/icon/course/aiPart_arrow_active.png");
  783. background-size: 100% 100%;
  784. margin-right: 5px;
  785. }
  786. .ai_body_select > .checkBox {
  787. position: absolute;
  788. bottom: 40px;
  789. border: 1px solid #e0eafb;
  790. width: 100%;
  791. height: 300px;
  792. background: #fff;
  793. border-radius: 5px;
  794. padding: 10px;
  795. box-sizing: border-box;
  796. }
  797. .ai_body_select > .checkBox > .task > .title,
  798. .ai_body_select > .checkBox > .part > .title {
  799. font-size: 14px;
  800. font-weight: 700;
  801. margin-bottom: 5px;
  802. }
  803. .ai_body_select > .checkBox > .task {
  804. height: calc(100% - 60px);
  805. }
  806. .ai_body_select > .checkBox > .part {
  807. }
  808. .ai_body_select > .checkBox > .task > .content {
  809. height: calc(100% - 40px);
  810. overflow: auto;
  811. }
  812. .ai_body_select > .checkBox > .task > .content > .span + .span {
  813. margin-top: 5px;
  814. }
  815. .ai_body_select > .checkBox > .task > .content > .span {
  816. display: flex;
  817. align-items: center;
  818. font-size: 14px;
  819. cursor: pointer;
  820. }
  821. .ai_body_select > .checkBox > .task > .content > .span > .check {
  822. width: 13px;
  823. height: 13px;
  824. display: flex;
  825. align-items: center;
  826. margin-right: 5px;
  827. }
  828. .ai_body_select > .checkBox > .task > .content > .span > .check > img {
  829. width: 100%;
  830. height: 100%;
  831. }
  832. .ai_body_select > .checkBox > .part > .content {
  833. display: flex;
  834. align-items: center;
  835. font-size: 14px;
  836. justify-content: space-between;
  837. }
  838. .ai_body_select > .checkBox > .part > .content > .span {
  839. padding: 3px 6px;
  840. border: 1px solid #e0eafb;
  841. border-radius: 40px;
  842. cursor: pointer;
  843. }
  844. .ai_body_select > .checkBox > .part > .content > .span.active {
  845. color: #0061ff;
  846. border-color: #0061ff;
  847. }
  848. </style>