|
@@ -49,20 +49,32 @@
|
|
|
class="s_t_c_ai"
|
|
|
v-if="item.content != 'wanSearch' && item.content != 'getImage'"
|
|
|
>
|
|
|
-
|
|
|
<div class="s_t_c_a_left">
|
|
|
<span>Ai</span>
|
|
|
</div>
|
|
|
<div class="s_t_c_a_right">
|
|
|
- <div class="s_t_c_a_r_content" v-if="item.content.includes('图片')" style="display: flex;justify-content: space-between;flex-wrap: wrap;" >
|
|
|
+ <div
|
|
|
+ class="s_t_c_a_r_content"
|
|
|
+ v-if="item.content.includes('图片')"
|
|
|
+ style="display: flex;justify-content: space-between;flex-wrap: wrap;"
|
|
|
+ >
|
|
|
<div
|
|
|
- v-if="!pan(item.aiContent).length"
|
|
|
- class="d_t_c_a_r_content"
|
|
|
- v-loading="item.loading"
|
|
|
- v-html="item.aiContent"
|
|
|
- ></div>
|
|
|
- <div v-else v-for="(i,index) in pan(item.aiContent)" :key=index>
|
|
|
- <img style="width: 130px;height: 130px;" :src="i.image" alt="" @click="previewImg(i.image)">
|
|
|
+ v-if="!pan(item.aiContent).length"
|
|
|
+ class="d_t_c_a_r_content"
|
|
|
+ v-loading="item.loading"
|
|
|
+ v-html="item.aiContent"
|
|
|
+ ></div>
|
|
|
+ <div
|
|
|
+ v-else
|
|
|
+ v-for="(i, index) in pan(item.aiContent)"
|
|
|
+ :key="index"
|
|
|
+ >
|
|
|
+ <img
|
|
|
+ style="width: 130px;height: 130px;"
|
|
|
+ :src="i.image"
|
|
|
+ alt=""
|
|
|
+ @click="previewImg(i.image)"
|
|
|
+ />
|
|
|
</div>
|
|
|
</div>
|
|
|
<div
|
|
@@ -72,7 +84,7 @@
|
|
|
v-html="htmlContent(item.aiContent)"
|
|
|
></div>
|
|
|
<div v-if="!item.content.includes('图片')" class="aiCopy">
|
|
|
- <img
|
|
|
+ <img
|
|
|
@click="onCopy(item.aiContent)"
|
|
|
style="width: 30px;"
|
|
|
src="https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/%E5%A4%8D%E5%88%B6%E5%9B%BE%E6%A0%871715569581741.png"
|
|
@@ -86,14 +98,14 @@
|
|
|
>
|
|
|
|
|
|
<span style="margin-bottom: 10px;">为您找到以下图片: {{ item.content }}</span> -->
|
|
|
- <!-- {{ item.aiContent }} -->
|
|
|
- <!-- <img
|
|
|
+ <!-- {{ item.aiContent }} -->
|
|
|
+ <!-- <img
|
|
|
v-for="(i, index) in item.aiContent"
|
|
|
@click.stop="$hevueImgPreview(item)"
|
|
|
:key="index"
|
|
|
:src="i.image"
|
|
|
/> -->
|
|
|
- <!-- <div class="imgNumberBlock">
|
|
|
+ <!-- <div class="imgNumberBlock">
|
|
|
<div class="imgNumber" v-for="(i,index) in imgNumList" :key="index+'b'">
|
|
|
{{ i }}
|
|
|
</div>
|
|
@@ -137,10 +149,148 @@
|
|
|
<!-- <div class="s_b_ba-item" @click.stop="choiceRole()">选择角色</div> -->
|
|
|
|
|
|
<div class="s_b_btnArea">
|
|
|
- <div class="s_b_ba-item" @click="clear()">
|
|
|
+ <div class="s_b_ba-item" @click="clear()" v-if="!openAtBox">
|
|
|
清空聊天记录
|
|
|
</div>
|
|
|
</div>
|
|
|
+
|
|
|
+ <div class="s_b_atBox" v-if="openAtBox">
|
|
|
+ <div class="s_b_at_tag">
|
|
|
+ <span
|
|
|
+ :class="[atTagIndex == 0 ? 's_b_at_tag_active' : '']"
|
|
|
+ @click.stop="atTagIndex = 0"
|
|
|
+ >任务</span
|
|
|
+ >
|
|
|
+ <span
|
|
|
+ :class="[[1, 2].includes(atTagIndex) ? 's_b_at_tag_active' : '']"
|
|
|
+ @click.stop="atTagIndex = 1"
|
|
|
+ >成员</span
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ <div class="s_b_at_list">
|
|
|
+ <template v-if="atTagIndex == 0">
|
|
|
+ <div v-for="(item1, index1) in taskList" :key="index1">
|
|
|
+ <div
|
|
|
+ class="s_b_at_l_top"
|
|
|
+ v-if="item1.dyName"
|
|
|
+ @click="
|
|
|
+ atTask(`阶段${index1 + 1} ${item1.dyName} `, index1, 0, item1)
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <span>阶段{{ index1 + 1 }} {{ item1.dyName }}</span>
|
|
|
+ <span
|
|
|
+ class="s_b_at_l_i_h_icon1"
|
|
|
+ :style="
|
|
|
+ `${!item1.isOpen ? 'transform: rotate(-90deg);' : ''}'`
|
|
|
+ "
|
|
|
+ @click.stop="item1.isOpen = !item1.isOpen"
|
|
|
+ ></span>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="s_b_at_l_item"
|
|
|
+ v-for="(item2, index2) in item1.task"
|
|
|
+ :key="index1 + '-' + index2"
|
|
|
+ v-if="item1.isOpen"
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ class="s_b_at_l_i_header"
|
|
|
+ v-if="item2.tool[0].tool != undefined"
|
|
|
+ @click="
|
|
|
+ atTask(
|
|
|
+ `阶段${index1 + 1} ${item1.dyName}-任务${index2 + 1}:${
|
|
|
+ item2.taskName
|
|
|
+ } `,
|
|
|
+ index2,
|
|
|
+ 1,
|
|
|
+ item2
|
|
|
+ )
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <span
|
|
|
+ class="s_b_at_l_i_h_icon1"
|
|
|
+ :style="
|
|
|
+ `${!item2.isOpen ? 'transform: rotate(-90deg);' : ''}'`
|
|
|
+ "
|
|
|
+ @click.stop="item2.isOpen = !item2.isOpen"
|
|
|
+ ></span>
|
|
|
+ <span>任务{{ index2 + 1 }}:{{ item2.taskName }}</span>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="s_b_at_l_i_header"
|
|
|
+ v-else
|
|
|
+ @click="
|
|
|
+ atTask(
|
|
|
+ `阶段${index1 + 1} ${item1.dyName}-任务${index2 + 1}:${
|
|
|
+ item2.taskName
|
|
|
+ } `,
|
|
|
+ index2,
|
|
|
+ 1,
|
|
|
+ item2
|
|
|
+ )
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <span
|
|
|
+ class="s_b_at_l_i_h_icon2"
|
|
|
+ :style="
|
|
|
+ `${!item2.isOpen ? 'transform: rotate(-90deg);' : ''}'`
|
|
|
+ "
|
|
|
+ @click.stop="item2.isOpen = !item2.isOpen"
|
|
|
+ ></span>
|
|
|
+ <span>任务{{ index2 + 1 }}:{{ item2.taskName }}</span>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="s_b_at_l_i_content"
|
|
|
+ v-if="item2.tool[0].tool != undefined && item2.isOpen"
|
|
|
+ v-for="(item3, index3) in item2.tool"
|
|
|
+ :key="index1 + '-' + index2 + '-' + index3"
|
|
|
+ @click="
|
|
|
+ atTask(
|
|
|
+ `阶段${index1 + 1} ${item1.dyName}-任务${index2 + 1}:${
|
|
|
+ item2.taskName
|
|
|
+ }-工具${index3 + 1}:${toolsList[item3.tool]} `,
|
|
|
+ index3,
|
|
|
+ 2,
|
|
|
+ item3
|
|
|
+ )
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <span>工具{{ index3 + 1 }}:{{ toolsList[item3.tool] }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <template v-if="atTagIndex == 1">
|
|
|
+ <div
|
|
|
+ class="s_b_ab_user"
|
|
|
+ v-for="(item, index) in userList"
|
|
|
+ :key="item.id"
|
|
|
+ >
|
|
|
+ <div class="s_b_ab_u_name">
|
|
|
+ <el-tooltip
|
|
|
+ class="item"
|
|
|
+ effect="light:"
|
|
|
+ :content="item.userName"
|
|
|
+ placement="top"
|
|
|
+ >
|
|
|
+ <span>{{ item.userName }}</span>
|
|
|
+ </el-tooltip>
|
|
|
+ </div>
|
|
|
+ <div class="s_b_ab_u_message">
|
|
|
+ <span>作业提交情况</span>
|
|
|
+ <div>
|
|
|
+ <span>已提交:{{ item.isSubmit }}</span>
|
|
|
+ <span>未提交:{{ item.noSubmit }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="s_b_ab_u_btnArea">
|
|
|
+ <span>总结分析</span>
|
|
|
+ <span>作业详细</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
<div class="s_b_inputArea">
|
|
|
<!-- <div class="s_b_tape" @click="goTape()"></div> -->
|
|
|
<div class="s_b_input">
|
|
@@ -150,13 +300,15 @@
|
|
|
@keyup.enter.native="send()"
|
|
|
class="s_b_i_left"
|
|
|
v-model="text"
|
|
|
+ ref="textRef"
|
|
|
></el-input>
|
|
|
<!-- <div class="s_b_i_right" @click="sendFile()">
|
|
|
<span></span>
|
|
|
</div> -->
|
|
|
</div>
|
|
|
<div class="s_b_btn" @click="send()">
|
|
|
- <span></span>
|
|
|
+ <span v-if="!loading && !chatLoading"></span>
|
|
|
+ <div v-else @click.stop="stopSend()">停止</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -166,11 +318,16 @@
|
|
|
<script>
|
|
|
import { v4 as uuidv4 } from "uuid";
|
|
|
import MarkdownIt from "markdown-it";
|
|
|
+import { tools } from "../../../common/tools";
|
|
|
export default {
|
|
|
props: {
|
|
|
courseDetail: {
|
|
|
type: Object,
|
|
|
default: () => {}
|
|
|
+ },
|
|
|
+ navList: {
|
|
|
+ type: Array,
|
|
|
+ default: () => []
|
|
|
}
|
|
|
},
|
|
|
data() {
|
|
@@ -184,46 +341,196 @@ export default {
|
|
|
courseId: this.$route.query.courseId,
|
|
|
imgNumList: ["U1", "U2", "U3", "U4"],
|
|
|
chatList: [],
|
|
|
- nowChatList:[],
|
|
|
+ nowChatList: [],
|
|
|
+ atTagIndex: 0,
|
|
|
+ source: null,
|
|
|
+ saveUid: "",
|
|
|
+ toolsList: {
|
|
|
+ "58": "模拟驾驶",
|
|
|
+ "59": "路径搜索",
|
|
|
+ "60": "深度学习",
|
|
|
+ "10": "倒计时",
|
|
|
+ "65": "挑人",
|
|
|
+ "7": "思维网格",
|
|
|
+ "1": "电子白板",
|
|
|
+ "52": "文档",
|
|
|
+ "3": "思维导图",
|
|
|
+ "48": "表格",
|
|
|
+ "49": "学生分组",
|
|
|
+ "4": "问卷调查",
|
|
|
+ "45": "选择题",
|
|
|
+ "15": "问答",
|
|
|
+ "16": "作业提交",
|
|
|
+ "50": "批量上传",
|
|
|
+ "41": "选择匹配",
|
|
|
+ "47": "排序",
|
|
|
+ "40": "个人评价",
|
|
|
+ "18": "训练平台",
|
|
|
+ "21": "AIoT Blockly",
|
|
|
+ "23": "AI Python",
|
|
|
+ "24": "AI Blockly",
|
|
|
+ "32": "源码编辑",
|
|
|
+ "57": "CocoPi",
|
|
|
+ "63": "海龟编程",
|
|
|
+ "28": "翻译",
|
|
|
+ "31": "数字画板",
|
|
|
+ "39": "GeoGebra",
|
|
|
+ "66": "公式编辑",
|
|
|
+ "67": "分子结构",
|
|
|
+ "68": "时间轴",
|
|
|
+ "69": "英语写作",
|
|
|
+ "70": "英语口语",
|
|
|
+ "25": "目标管理",
|
|
|
+ "26": "课程设计",
|
|
|
+ "62": "交互视频",
|
|
|
+ "71": "AI智能体"
|
|
|
+ },
|
|
|
+ lookStudentData: {},
|
|
|
+ taskList: [],
|
|
|
+ userList: [
|
|
|
+ {
|
|
|
+ id: 0,
|
|
|
+ userName: "wufantest1",
|
|
|
+ isSubmit: 2,
|
|
|
+ noSubmit: 2
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 1,
|
|
|
+ userName: "Chen",
|
|
|
+ isSubmit: 4,
|
|
|
+ noSubmit: 0
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 2,
|
|
|
+ userName: "student04",
|
|
|
+ isSubmit: 1,
|
|
|
+ noSubmit: 3
|
|
|
+ }
|
|
|
+ ]
|
|
|
};
|
|
|
},
|
|
|
computed: {
|
|
|
+ openAtBox() {
|
|
|
+ return false;
|
|
|
+ if (this.text.length == 0) return false;
|
|
|
+ if (this.text.lastIndexOf("@") == this.text.length - 1) {
|
|
|
+ return true;
|
|
|
+ } else {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ atTaskList() {
|
|
|
+ let _result = [];
|
|
|
+ this.taskList.forEach((item1, index1) => {
|
|
|
+ if (item1.dyName) {
|
|
|
+ _result.push({
|
|
|
+ name: `阶段${index1 + 1} ${item1.dyName}`,
|
|
|
+ type: 0
|
|
|
+ });
|
|
|
+ }
|
|
|
+ item1.task.forEach((item2, index2) => {
|
|
|
+ if (item2.taskName) {
|
|
|
+ _result.push({
|
|
|
+ name: `任务${index2 + 1}:${item2.taskName}`,
|
|
|
+ type: 1,
|
|
|
+ superiors: {
|
|
|
+ name: `阶段${index1 + 1} ${item1.dyName}`,
|
|
|
+ type: 0
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ item2.tool.forEach((item3, index3) => {
|
|
|
+ if (item3.tool != undefined) {
|
|
|
+ _result.push({
|
|
|
+ name: `工具${index3 + 1}:${this.toolsList[item3.tool]}`,
|
|
|
+ type: 2,
|
|
|
+ superiors: {
|
|
|
+ name: `任务${index2 + 1}:${item2.taskName}`,
|
|
|
+ type: 1,
|
|
|
+ superiors: {
|
|
|
+ name: `阶段${index1 + 1} ${item1.dyName}`,
|
|
|
+ type: 0
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ return _result;
|
|
|
+ },
|
|
|
pan() {
|
|
|
- return (content) => {
|
|
|
+ return content => {
|
|
|
try {
|
|
|
- return JSON.parse(content)
|
|
|
- } catch (error) {
|
|
|
- return []
|
|
|
- }
|
|
|
+ return JSON.parse(content);
|
|
|
+ } catch (error) {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
};
|
|
|
},
|
|
|
- htmlContent(){
|
|
|
- const md = new MarkdownIt()
|
|
|
- return (_md)=>{
|
|
|
- return md.render(_md);
|
|
|
- }
|
|
|
- },
|
|
|
+ htmlContent() {
|
|
|
+ const md = new MarkdownIt();
|
|
|
+ return _md => {
|
|
|
+ return md.render(_md);
|
|
|
+ };
|
|
|
+ }
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ navList() {
|
|
|
+ this.initTaskList();
|
|
|
+ },
|
|
|
+ atTagIndex(newValue) {
|
|
|
+ if (newValue != 2) {
|
|
|
+ this.lookStudentData = {};
|
|
|
+ } else {
|
|
|
+ this.lookStudentData = {
|
|
|
+ userName: "qgt",
|
|
|
+ list: [
|
|
|
+ {
|
|
|
+ title: "题目题目题目题目题目题目题目题目题目",
|
|
|
+ phase: "阶段一/任务一/工具1"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: "题目题目题目题目题目题目题目题目题目",
|
|
|
+ phase: "阶段一/任务一/工具2"
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
},
|
|
|
methods: {
|
|
|
- onCopy(content){
|
|
|
+ stopSend() {
|
|
|
+ if (this.source) {
|
|
|
+ this.source.close();
|
|
|
+ if (this.chatList[this.chatList.length - 1].content == "wanSearch") {
|
|
|
+ this.chatList.pop();
|
|
|
+ }
|
|
|
+ this.loading = false;
|
|
|
+ this.chatLoading = false;
|
|
|
+ this.source = null;
|
|
|
+ this.insertChat(this.saveUid);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onCopy(content) {
|
|
|
// 创建临时textarea元素
|
|
|
- const tempInput = document.createElement('textarea');
|
|
|
+ const tempInput = document.createElement("textarea");
|
|
|
tempInput.value = content; // 设置要复制的内容
|
|
|
// 隐藏元素
|
|
|
- tempInput.style.position = 'absolute';
|
|
|
- tempInput.style.left = '-9999px';
|
|
|
+ tempInput.style.position = "absolute";
|
|
|
+ tempInput.style.left = "-9999px";
|
|
|
// 将元素添加到DOM中
|
|
|
document.body.appendChild(tempInput);
|
|
|
// 选中元素内容
|
|
|
tempInput.select();
|
|
|
// 执行复制操作
|
|
|
- document.execCommand('copy');
|
|
|
+ document.execCommand("copy");
|
|
|
// 移除临时元素
|
|
|
document.body.removeChild(tempInput);
|
|
|
this.$message({
|
|
|
- message: '复制成功',
|
|
|
- type: 'success'
|
|
|
- });
|
|
|
+ message: "复制成功",
|
|
|
+ type: "success"
|
|
|
+ });
|
|
|
},
|
|
|
previewImg(url) {
|
|
|
this.$hevueImgPreview(url);
|
|
@@ -231,6 +538,18 @@ export default {
|
|
|
clear() {
|
|
|
this.chatList = [];
|
|
|
},
|
|
|
+ atTask(name, index, type, data) {
|
|
|
+ let _result = name;
|
|
|
+ // if(type == 1){
|
|
|
+ // _result=`任务${index+1}:${name} `
|
|
|
+ // }else if(type==2){
|
|
|
+ // _result=`工具${index+1}:${name} `
|
|
|
+ // }else if(type==0){
|
|
|
+ // _result=`阶段${index+1} ${name} `
|
|
|
+ // }
|
|
|
+ this.text += _result;
|
|
|
+ this.$refs.textRef.focus();
|
|
|
+ },
|
|
|
// choiceRole() {
|
|
|
// this.cardType = 1;
|
|
|
// },
|
|
@@ -245,6 +564,23 @@ export default {
|
|
|
send(_text = this.text) {
|
|
|
if (this.loading || this.chatLoading) return this.$message.info("请稍等");
|
|
|
if (_text.trim().length == 0) return this.$message.info("请输入内容");
|
|
|
+ let _atRoleList = [];
|
|
|
+ this.atTaskList.forEach(i => {
|
|
|
+ let _result = ``;
|
|
|
+ if (i.type == 0) {
|
|
|
+ _result = `${i.name} `;
|
|
|
+ } else if (i.type == 1) {
|
|
|
+ _result = `${i.superiors.name}-${i.name} `;
|
|
|
+ } else if (i.type == 2) {
|
|
|
+ _result = `${i.superiors.superiors.name}-${i.superiors.name}-${i.name} `;
|
|
|
+ }
|
|
|
+ if (_text.indexOf(`@${_result}`) != -1) {
|
|
|
+ _atRoleList.push(i);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (_atRoleList.length > 0) {
|
|
|
+ return this.atSend(_text, _atRoleList);
|
|
|
+ }
|
|
|
let _msg = ``;
|
|
|
this.chatLoading = true;
|
|
|
let _uuid = uuidv4();
|
|
@@ -317,7 +653,9 @@ Instruction: Based on the context, follow "Format example", write content.
|
|
|
.then(res => {
|
|
|
let data = res.data.FunctionResponse.result;
|
|
|
// console.log('res',res.data.FunctionResponse.result);
|
|
|
- this.chatList.find(i => i.uid == _uuid).aiContent = JSON.stringify(data);
|
|
|
+ this.chatList.find(i => i.uid == _uuid).aiContent = JSON.stringify(
|
|
|
+ data
|
|
|
+ );
|
|
|
this.chatList.find(i => i.uid == _uuid).loading = false;
|
|
|
this.chatLoading = false;
|
|
|
this.insertChat(_uuid);
|
|
@@ -357,53 +695,64 @@ Instruction: Based on the context, follow "Format example", write content.
|
|
|
// `
|
|
|
// }
|
|
|
let history = [];
|
|
|
- this.nowChatList.forEach(i=>{
|
|
|
- if(i.content=='wanSearch'){
|
|
|
- // history.push({
|
|
|
- // role:"assistant",
|
|
|
- // content: JSON.stringify(i.aiContent)
|
|
|
- // })
|
|
|
- return
|
|
|
-
|
|
|
- }else if(i.content == 'getImage'){
|
|
|
- return history.push({
|
|
|
- role:"assistant",
|
|
|
- content:i.aiContent
|
|
|
- })
|
|
|
- }
|
|
|
- if(i.content){
|
|
|
- history.push({
|
|
|
- role:"user",
|
|
|
- content:i.content,
|
|
|
- })
|
|
|
- }
|
|
|
- if(i.aiContent){
|
|
|
- history.push({
|
|
|
- role:"assistant",
|
|
|
- content:i.aiContent
|
|
|
- })
|
|
|
- }
|
|
|
- })
|
|
|
- // history.pop();
|
|
|
- if (_msg) {
|
|
|
+ this.nowChatList.forEach(i => {
|
|
|
+ if (i.content == "wanSearch") {
|
|
|
+ // history.push({
|
|
|
+ // role:"assistant",
|
|
|
+ // content: JSON.stringify(i.aiContent)
|
|
|
+ // })
|
|
|
+ return;
|
|
|
+ } else if (i.content == "getImage") {
|
|
|
+ return history.push({
|
|
|
+ role: "assistant",
|
|
|
+ content: i.aiContent
|
|
|
+ });
|
|
|
+ }
|
|
|
+ if (i.content) {
|
|
|
+ history.push({
|
|
|
+ role: "user",
|
|
|
+ content: i.content
|
|
|
+ });
|
|
|
+ }
|
|
|
+ if (i.aiContent) {
|
|
|
+ history.push({
|
|
|
+ role: "assistant",
|
|
|
+ content: i.aiContent
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ // history.pop();
|
|
|
+ if (_msg) {
|
|
|
history.push({ role: "user", content: _msg });
|
|
|
}
|
|
|
history.push({ role: "user", content: _text });
|
|
|
+ // let params = {
|
|
|
+ // model: "gpt-3.5-turbo",
|
|
|
+ // temperature: 0,
|
|
|
+ // max_tokens: 4096,
|
|
|
+ // top_p: 1,
|
|
|
+ // frequency_penalty: 0,
|
|
|
+ // presence_penalty: 0,
|
|
|
+ // messages: history,
|
|
|
+ // uid: _uuid,
|
|
|
+ // mind_map_question: _text
|
|
|
+ // };
|
|
|
let params = {
|
|
|
- model: "gpt-3.5-turbo",
|
|
|
- temperature: 0,
|
|
|
- max_tokens: 4096,
|
|
|
- top_p: 1,
|
|
|
- frequency_penalty: 0,
|
|
|
- presence_penalty: 0,
|
|
|
- messages: history,
|
|
|
+ message: {
|
|
|
+ anthropic_version: "bedrock-2023-05-31",
|
|
|
+ max_tokens: 4096,
|
|
|
+ temperature: 0,
|
|
|
+ top_p: 1,
|
|
|
+ messages: history
|
|
|
+ },
|
|
|
uid: _uuid,
|
|
|
- mind_map_question: _text
|
|
|
+ model: "Claude 3 Sonnet" // Claude 3 Sonnet或者Claude 3 Haiku
|
|
|
};
|
|
|
this.text = "";
|
|
|
|
|
|
this.ajax
|
|
|
- .post("https://gpt4.cocorobo.cn/chat", params)
|
|
|
+ .post("https://claude3.cocorobo.cn/chat", params)
|
|
|
+ // .post("https://gpt4.cocorobo.cn/chat", params)
|
|
|
.then(res => {
|
|
|
if (res.data.FunctionResponse.result == "发送成功") {
|
|
|
} else {
|
|
@@ -415,26 +764,221 @@ Instruction: Based on the context, follow "Format example", write content.
|
|
|
console.log(e);
|
|
|
this.chatLoading = false;
|
|
|
});
|
|
|
+ this.saveUid = _uuid;
|
|
|
this.getAiContent(_uuid);
|
|
|
},
|
|
|
+ atSend(_text, _atList) {
|
|
|
+ let _msg = ``;
|
|
|
+ let noAtText = _text;
|
|
|
+ _atList.forEach(i => {
|
|
|
+ let _result = ``;
|
|
|
+ if (i.type == 0) {
|
|
|
+ _result = `${i.name} `;
|
|
|
+ } else if (i.type == 1) {
|
|
|
+ _result = `${i.superiors.name}-${i.name} `;
|
|
|
+ } else if (i.type == 2) {
|
|
|
+ _result = `${i.superiors.superiors.name}-${i.superiors.name}-${i.name} `;
|
|
|
+ }
|
|
|
+ if (_text.indexOf(`@${_result}`) != -1) {
|
|
|
+ noAtText = noAtText.replaceAll(`@${_result}`, "");
|
|
|
+ }
|
|
|
+ });
|
|
|
+ this.chatLoading = true;
|
|
|
+ let _uuid = uuidv4();
|
|
|
+ this.chatList.push({
|
|
|
+ role: "user",
|
|
|
+ content: `${_text}`,
|
|
|
+ uid: _uuid,
|
|
|
+ AI: "AI",
|
|
|
+ aiContent: "",
|
|
|
+ oldContent: "",
|
|
|
+ isShowSynchronization: false,
|
|
|
+ filename: "",
|
|
|
+ index: this.chatList.length,
|
|
|
+ is_mind_map: false,
|
|
|
+ loading: true
|
|
|
+ });
|
|
|
+ this.scrollBottom();
|
|
|
+
|
|
|
+ _msg = `
|
|
|
+NOTICE
|
|
|
+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.
|
|
|
+
|
|
|
+## 目的
|
|
|
+你是用户的课堂助手,你需要基于提供给你的课程相关信息,对用户的提问进行回答。
|
|
|
+---
|
|
|
+## 定义
|
|
|
+给你提供的课程发生在一个网络教学平台上,各元素存在以下的关系:课程⊇阶段⊇任务⊇工具。
|
|
|
+【课程】:课程通常是一个完整的项目,有一个或多个阶段。
|
|
|
+【阶段】:阶段表示课程的某一单独部分,通常包含一个或多个任务。
|
|
|
+【任务】:任务是课程的基本单元,包含一个或多个工具,通常写明了学生要具体完成的事项。
|
|
|
+【工具】:工具通常是指学生要完成任务的手段。比如“提交作业”表示学生需要提交一份文件;又比如“问答”,表示学生需要输入一个回答;再比如“选择题”,表示学生需要根据题目要求选择正确的答案。
|
|
|
+---
|
|
|
+## 工作流程
|
|
|
+ 1. 读取【课程信息】中的内容,了解课程说明、课程结构以及【任务】详情。
|
|
|
+ 2. 用户会询问你某个【任务】的具体信息,你需要总结该任务信息,并就用户的问题进行回答。
|
|
|
+ 3. 你的总结包括以下要点:
|
|
|
+ 3.1 任务从属于哪个阶段。
|
|
|
+ 3.2 任务包含哪些工具。
|
|
|
+ 3.3 该任务目标是什么,以及该任务的工具如何达成它的目标。
|
|
|
+---
|
|
|
+## 规则
|
|
|
+ 1.你和用户讨论的范围应当仅局限于课程相关内容。
|
|
|
+ 2.当用户的提问需要你对课程拥有完整的信息、而你又缺乏部分信息时,你应当向客户询问你缺少的信息,再回答用户的提问。
|
|
|
+ 3.你通常可以在【任务描述】中了解任务目标,但当【任务描述】不包含此内容的时候,你不需要总结这部分内容。
|
|
|
+---
|
|
|
+## 课程信息
|
|
|
+
|
|
|
+###课程说明与课程结构
|
|
|
+课程标题:${this.courseDetail.title}
|
|
|
+分类:${this.courseDetail.name ? this.courseDetail.name : "无"}
|
|
|
+学生年级:${this.courseDetail.classname ? this.courseDetail.classname : "无"}
|
|
|
+学习内容:${this.exportCourse()}
|
|
|
+
|
|
|
+## 要求
|
|
|
+${_atList
|
|
|
+ .map(i => {
|
|
|
+ let _result = ``;
|
|
|
+ if (i.type == 0) {
|
|
|
+ _result = `${i.name}`;
|
|
|
+ } else if (i.type == 1) {
|
|
|
+ _result = `${i.superiors.name}-${i.name}`;
|
|
|
+ } else if (i.type == 2) {
|
|
|
+ _result = `${i.superiors.superiors.name}-${i.superiors.name}-${i.name}`;
|
|
|
+ }
|
|
|
+ console.log(_result);
|
|
|
+ return _result;
|
|
|
+ })
|
|
|
+ .join(",")} ${noAtText}
|
|
|
+`;
|
|
|
+ // this.chatLoading = false;
|
|
|
+ // console.log(_msg)
|
|
|
+ // return
|
|
|
+ // ${this._atList.map(i=>i.name).join(',')} ${noAtText}
|
|
|
+ let history = [];
|
|
|
+ this.nowChatList.forEach(i => {
|
|
|
+ if (i.content == "wanSearch") {
|
|
|
+ return;
|
|
|
+ } else if (i.content == "getImage") {
|
|
|
+ return history.push({
|
|
|
+ role: "assistant",
|
|
|
+ content: i.aiContent
|
|
|
+ });
|
|
|
+ }
|
|
|
+ if (i.content) {
|
|
|
+ history.push({
|
|
|
+ role: "user",
|
|
|
+ content: i.content
|
|
|
+ });
|
|
|
+ }
|
|
|
+ if (i.aiContent) {
|
|
|
+ history.push({
|
|
|
+ role: "assistant",
|
|
|
+ content: i.aiContent
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // if (_msg) {
|
|
|
+ history.push({ role: "user", content: _msg });
|
|
|
+ // }
|
|
|
+ // history.push({ role: "user", content: _text });
|
|
|
+ // let params = {
|
|
|
+ // model: "gpt-3.5-turbo",
|
|
|
+ // temperature: 0,
|
|
|
+ // max_tokens: 4096,
|
|
|
+ // top_p: 1,
|
|
|
+ // frequency_penalty: 0,
|
|
|
+ // presence_penalty: 0,
|
|
|
+ // messages: history,
|
|
|
+ // uid: _uuid,
|
|
|
+ // mind_map_question: noAtText
|
|
|
+ // };
|
|
|
+ let params = {
|
|
|
+ message: {
|
|
|
+ anthropic_version: "bedrock-2023-05-31",
|
|
|
+ max_tokens: 4096,
|
|
|
+ temperature: 0,
|
|
|
+ top_p: 1,
|
|
|
+ messages: history
|
|
|
+ },
|
|
|
+ uid: _uuid,
|
|
|
+ model: "Claude 3 Sonnet" // Claude 3 Sonnet或者Claude 3 Haiku
|
|
|
+ };
|
|
|
+ this.text = "";
|
|
|
+
|
|
|
+ this.ajax
|
|
|
+ // .post("https://gpt4.cocorobo.cn/chat", params)
|
|
|
+ .post("https://claude3.cocorobo.cn/chat", params)
|
|
|
+ .then(res => {
|
|
|
+ if (res.data.FunctionResponse.result == "发送成功") {
|
|
|
+ } else {
|
|
|
+ this.$message.warning(res.data.FunctionResponse.result);
|
|
|
+ this.chatLoading = false;
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch(e => {
|
|
|
+ console.log(e);
|
|
|
+ this.chatLoading = false;
|
|
|
+ });
|
|
|
+ this.saveUid = _uuid;
|
|
|
+ this.getAiContent(_uuid);
|
|
|
+ },
|
|
|
+ exportCourse() {
|
|
|
+ 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>`;
|
|
|
+ const _chapInfo = JSON.parse(this.courseDetail.chapters);
|
|
|
+ let _chap = "";
|
|
|
+
|
|
|
+ for (let i = 0; i < _chapInfo.length; i++) {
|
|
|
+ _chap += `<div style="font-size:40px;margin-top:70px;"><span>第${i +
|
|
|
+ 1}阶段:${_chapInfo[i].dyName}</span></div>`;
|
|
|
+ let _task = _chapInfo[i].chapterInfo[0].taskJson;
|
|
|
+ for (let j = 0; j < _task.length; j++) {
|
|
|
+ _chap += `<div style="font-size:30px;margin-top:50px;"><span>任务${j +
|
|
|
+ 1}:${_task[j].task}</span></div>`;
|
|
|
+ if (_task[j].taskDetail) {
|
|
|
+ _chap += `<div style="font-size:25px;margin-top:40px;">任务描述</div>`;
|
|
|
+ _chap += `<div style="font-size:25px;margin-top:10px;">${_task[j].taskDetail}</div>`;
|
|
|
+ }
|
|
|
+ let _tool = _task[j].toolChoose;
|
|
|
+ if (_tool[0].tool.length) {
|
|
|
+ for (let z = 0; z < _tool.length; z++) {
|
|
|
+ _chap += `<div style="font-size:23px;margin-top:30px;"><span>步骤${z +
|
|
|
+ 1}:</span><span>${
|
|
|
+ tools[_tool[z].tool[0]] ? tools[_tool[z].tool[0]].name : ""
|
|
|
+ }</span></div>`;
|
|
|
+
|
|
|
+ if (_tool[z].toolDetail) {
|
|
|
+ _chap += `<div style="font-size:23px;margin-top:20px;">工具描述</div>`;
|
|
|
+ _chap += `<div style="font-size:23px;margin-top:10px;">${_tool[z].toolDetail}</div>`;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let _html = _user + _chap;
|
|
|
+ return _html;
|
|
|
+ },
|
|
|
// 获取ai对话
|
|
|
getAiContent(_uid) {
|
|
|
- let _source = new EventSource(`https://gpt4.cocorobo.cn/stream/${_uid}`); //http://gpt4.cocorobo.cn:8011/stream/ https://gpt4.cocorobo.cn/stream/
|
|
|
+ this.source = new EventSource(`https://claude3.cocorobo.cn/streamChat/${_uid}`);
|
|
|
+ // this.source = new EventSource(`https://gpt4.cocorobo.cn/stream/${_uid}`); //http://gpt4.cocorobo.cn:8011/stream/ https://gpt4.cocorobo.cn/stream/
|
|
|
let _allText = "";
|
|
|
let _mdText = "";
|
|
|
// const md = new MarkdownIt();
|
|
|
- _source.onmessage = _e => {
|
|
|
+ this.source.onmessage = _e => {
|
|
|
if (_e.data.replace("'", "").replace("'", "") == "[DONE]") {
|
|
|
//对话已经完成
|
|
|
_mdText = _mdText.replace("_", "");
|
|
|
- _source.close();
|
|
|
+ this.source.close();
|
|
|
this.chatLoading = false;
|
|
|
this.scrollBottom();
|
|
|
this.chatList.find(i => i.uid == _uid).aiContent = _mdText;
|
|
|
this.chatList.find(i => i.uid == _uid).isalltext = true;
|
|
|
this.chatList.find(i => i.uid == _uid).isShowSynchronization = true;
|
|
|
this.chatList.find(i => i.uid == _uid).loading = false;
|
|
|
- this.nowChatList.push(this.chatList.find(i=>i.uid==_uid));
|
|
|
+ this.nowChatList.push(this.chatList.find(i => i.uid == _uid));
|
|
|
// 这里保存对话
|
|
|
this.insertChat(_uid);
|
|
|
return;
|
|
@@ -462,17 +1006,18 @@ Instruction: Based on the context, follow "Format example", write content.
|
|
|
};
|
|
|
},
|
|
|
getWAntSearchContent(_uid) {
|
|
|
- let _source = new EventSource(`https://gpt4.cocorobo.cn/stream/${_uid}`); //http://gpt4.cocorobo.cn:8011/stream/ https://gpt4.cocorobo.cn/stream/
|
|
|
+ this.source = new EventSource(`https://claude3.cocorobo.cn/streamChat/${_uid}`);
|
|
|
+ // this.source = new EventSource(`https://gpt4.cocorobo.cn/stream/${_uid}`); //http://gpt4.cocorobo.cn:8011/stream/ https://gpt4.cocorobo.cn/stream/
|
|
|
let _allText = "";
|
|
|
let _mdText = "";
|
|
|
this.scrollBottom();
|
|
|
- _source.onmessage = _e => {
|
|
|
+ this.source.onmessage = _e => {
|
|
|
if (_e.data.replace("'", "").replace("'", "") == "[DONE]") {
|
|
|
//对话已经完成
|
|
|
_mdText = _mdText.replace("_", "");
|
|
|
_mdText = _mdText.replace("```json", "");
|
|
|
_mdText = _mdText.replace("```", "");
|
|
|
- _source.close();
|
|
|
+ this.source.close();
|
|
|
this.chatLoading = false;
|
|
|
this.chatList.find(i => i.uid == _uid).aiContent = JSON.parse(
|
|
|
_mdText
|
|
@@ -480,7 +1025,7 @@ Instruction: Based on the context, follow "Format example", write content.
|
|
|
this.chatList.find(i => i.uid == _uid).isalltext = true;
|
|
|
this.chatList.find(i => i.uid == _uid).isShowSynchronization = true;
|
|
|
this.chatList.find(i => i.uid == _uid).loading = false;
|
|
|
- this.nowChatList.push(this.chatList.find(i=>i.uid==_uid));
|
|
|
+ this.nowChatList.push(this.chatList.find(i => i.uid == _uid));
|
|
|
this.scrollBottom();
|
|
|
// 这里保存对话
|
|
|
return;
|
|
@@ -504,6 +1049,7 @@ Instruction: Based on the context, follow "Format example", write content.
|
|
|
},
|
|
|
//保存消息
|
|
|
insertChat(_uid) {
|
|
|
+ if (_uid == "") return;
|
|
|
let _data = this.chatList.find(i => i.uid == _uid);
|
|
|
if (!_data) return;
|
|
|
let params = {
|
|
@@ -518,6 +1064,7 @@ Instruction: Based on the context, follow "Format example", write content.
|
|
|
filename: _data.filename,
|
|
|
session_name: `${this.courseId}-studyStudent-md` //这是对话记录位置
|
|
|
};
|
|
|
+ this.saveUid = "";
|
|
|
this.ajax
|
|
|
.post("https://gpt4.cocorobo.cn/insert_chat", params)
|
|
|
.then(res => {});
|
|
@@ -646,21 +1193,33 @@ Instruction: Based on the context, follow "Format example", write content.
|
|
|
|
|
|
this.scrollBottom();
|
|
|
|
|
|
- let params = {
|
|
|
- model: "gpt-3.5-turbo",
|
|
|
- temperature: 0,
|
|
|
- max_tokens: 4096,
|
|
|
- top_p: 1,
|
|
|
- frequency_penalty: 0,
|
|
|
- presence_penalty: 0,
|
|
|
- messages: [{ role: "user", content: _msg }],
|
|
|
+ // let params = {
|
|
|
+ // model: "gpt-3.5-turbo",
|
|
|
+ // temperature: 0,
|
|
|
+ // max_tokens: 4096,
|
|
|
+ // top_p: 1,
|
|
|
+ // frequency_penalty: 0,
|
|
|
+ // presence_penalty: 0,
|
|
|
+ // messages: [{ role: "user", content: _msg }],
|
|
|
+ // uid: _uuid,
|
|
|
+ // mind_map_question: ""
|
|
|
+ // };
|
|
|
+ let params = {
|
|
|
+ message: {
|
|
|
+ anthropic_version: "bedrock-2023-05-31",
|
|
|
+ max_tokens: 4096,
|
|
|
+ temperature: 0,
|
|
|
+ top_p: 1,
|
|
|
+ messages: [{ role: "user", content: _msg }]
|
|
|
+ },
|
|
|
uid: _uuid,
|
|
|
- mind_map_question: ""
|
|
|
+ model: "Claude 3 Sonnet" // Claude 3 Sonnet或者Claude 3 Haiku
|
|
|
};
|
|
|
this.text = "";
|
|
|
|
|
|
this.ajax
|
|
|
- .post("https://gpt4.cocorobo.cn/chat", params)
|
|
|
+ // .post("https://gpt4.cocorobo.cn/chat", params)
|
|
|
+ .post("https://claude3.cocorobo.cn/chat", params)
|
|
|
.then(res => {
|
|
|
if (res.data.FunctionResponse.result == "发送成功") {
|
|
|
} else {
|
|
@@ -678,6 +1237,19 @@ Instruction: Based on the context, follow "Format example", write content.
|
|
|
this.$nextTick(() => {
|
|
|
this.$refs.chatRef.scrollTop = this.$refs.chatRef.scrollHeight;
|
|
|
});
|
|
|
+ },
|
|
|
+ initTaskList() {
|
|
|
+ this.taskList = [];
|
|
|
+ this.taskList = JSON.parse(JSON.stringify(this.navList));
|
|
|
+ this.taskList.forEach(i1 => {
|
|
|
+ i1.isOpen = true;
|
|
|
+ i1.task.forEach(i2 => {
|
|
|
+ i2.isOpen = true;
|
|
|
+ i2.tool.forEach(i3 => {
|
|
|
+ i3.isOpen = true;
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
}
|
|
|
},
|
|
|
mounted() {
|
|
@@ -685,7 +1257,8 @@ Instruction: Based on the context, follow "Format example", write content.
|
|
|
this.scrollBottom();
|
|
|
this.getWantSearch();
|
|
|
});
|
|
|
- this.nowChatList = [];
|
|
|
+ this.nowChatList = [];
|
|
|
+ this.initTaskList();
|
|
|
}
|
|
|
};
|
|
|
</script>
|
|
@@ -922,6 +1495,7 @@ Instruction: Based on the context, follow "Format example", write content.
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
justify-content: space-between;
|
|
|
+ position: relative;
|
|
|
}
|
|
|
|
|
|
.s_b_btnArea {
|
|
@@ -1023,6 +1597,15 @@ Instruction: Based on the context, follow "Format example", write content.
|
|
|
cursor: pointer;
|
|
|
}
|
|
|
|
|
|
+.s_b_btn > div {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
.s_b_btn > span {
|
|
|
width: 30px;
|
|
|
height: 30px;
|
|
@@ -1030,4 +1613,236 @@ Instruction: Based on the context, follow "Format example", write content.
|
|
|
background-size: 70% 70%;
|
|
|
background-position: center;
|
|
|
}
|
|
|
+
|
|
|
+.s_b_atBox {
|
|
|
+ width: 95%;
|
|
|
+ height: 450px;
|
|
|
+ position: absolute;
|
|
|
+ bottom: calc(100% - 30px);
|
|
|
+ left: 0;
|
|
|
+ max-height: 450px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ border: solid 1px #d8d8d8;
|
|
|
+ box-shadow: 0 4px 4px 0 #00000040;
|
|
|
+ margin-left: 1.5%;
|
|
|
+ background-color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_at_tag {
|
|
|
+ width: 100%;
|
|
|
+ height: 35px;
|
|
|
+ border-bottom: 1px solid #d8d8d8;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 0 10px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_at_tag > span {
|
|
|
+ margin: 0 10px;
|
|
|
+ font-weight: bold;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: 0.1s;
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_at_tag_active {
|
|
|
+ color: #3681fc;
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_at_tag_active::after {
|
|
|
+ content: "";
|
|
|
+ width: 100%;
|
|
|
+ height: 3px;
|
|
|
+ border-radius: 3px;
|
|
|
+ bottom: -8px;
|
|
|
+ left: 0px;
|
|
|
+ background-color: #3681fc;
|
|
|
+ position: absolute;
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_at_list {
|
|
|
+ width: 100%;
|
|
|
+ max-height: calc(100% - 35px);
|
|
|
+ overflow: auto;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_at_l_top {
|
|
|
+ width: 100%;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 12px 10px;
|
|
|
+ height: 30px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ margin: 10px 0;
|
|
|
+ border-radius: 5px;
|
|
|
+ cursor: pointer;
|
|
|
+ font-size: 16px;
|
|
|
+ border-bottom: solid 1px #e2f5fc;
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_at_l_i_header {
|
|
|
+ width: 100%;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 10px 10px;
|
|
|
+ height: 30px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin: 10px 0;
|
|
|
+ border-radius: 5px;
|
|
|
+ cursor: pointer;
|
|
|
+ font-size: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_at_l_top > hover {
|
|
|
+ background-color: #3781fc;
|
|
|
+ color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_at_l_top > hover > .s_b_at_l_i_h_icon1 {
|
|
|
+ background-image: url("../../../assets/icon/course/bDown2.png");
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_at_l_i_header:hover {
|
|
|
+ background-color: #3781fc;
|
|
|
+ color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_at_l_i_header:hover > .s_b_at_l_i_h_icon1 {
|
|
|
+ background-image: url("../../../assets/icon/course/bDown2.png");
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_at_l_i_header:hover > .s_b_at_l_i_h_icon2 {
|
|
|
+ background-color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_at_l_i_h_icon1 {
|
|
|
+ min-width: 15px;
|
|
|
+ min-height: 15px;
|
|
|
+ background-image: url("../../../assets/icon/course/down.png");
|
|
|
+ background-repeat: no-repeat;
|
|
|
+ background-size: 100% 100%;
|
|
|
+ /* transform: rotate(90deg); */
|
|
|
+ margin-right: 10px;
|
|
|
+ transition: 0.2s;
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_at_l_i_h_icon2 {
|
|
|
+ min-width: 10px;
|
|
|
+ min-height: 10px;
|
|
|
+ background-color: #3681fc;
|
|
|
+ border-radius: 50%;
|
|
|
+ margin-right: 15px;
|
|
|
+ transition: 0.2s;
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_at_l_i_content {
|
|
|
+ width: 100%;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 8px 35px;
|
|
|
+ height: 25;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin: 5px 0;
|
|
|
+ border-radius: 5px;
|
|
|
+ cursor: pointer;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_at_l_i_content:hover {
|
|
|
+ background-color: #3781fc;
|
|
|
+ color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_ab_user {
|
|
|
+ width: 100%;
|
|
|
+ height: 100px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ border: solid 1px #3781fc;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ position: relative;
|
|
|
+ margin-bottom: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_ab_u_name {
|
|
|
+ width: 25%;
|
|
|
+ max-width: 25%;
|
|
|
+ box-sizing: border-box;
|
|
|
+ margin: 0 20px;
|
|
|
+ padding: 5px 10px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ border: solid 1px #3781fc;
|
|
|
+ border-radius: 2px;
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_ab_u_name > span {
|
|
|
+ max-width: 100%;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+ display: block;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #3681fc;
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_ab_u_message {
|
|
|
+ flex: 1;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: center;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding-top: 10px;
|
|
|
+ padding-right: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_ab_u_message > span {
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: bold;
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-end;
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_ab_u_message > div {
|
|
|
+ width: 100%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: bold;
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_ab_u_btnArea {
|
|
|
+ width: auto;
|
|
|
+ height: auto;
|
|
|
+ position: absolute;
|
|
|
+ right: 0;
|
|
|
+ top: 5px;
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_ab_u_btnArea > span {
|
|
|
+ box-sizing: border-box;
|
|
|
+ color: #3681fc;
|
|
|
+ border: solid 1px #3681fc;
|
|
|
+ padding: 2px;
|
|
|
+ margin-left: 2px;
|
|
|
+ font-size: 14px;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+.s_b_ab_u_btnArea > span:hover {
|
|
|
+ color: #fff;
|
|
|
+ border: solid 1px #fff;
|
|
|
+ background-color: #3681fc;
|
|
|
+}
|
|
|
</style>
|