12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361 |
- <template>
- <div class="ch_box" ref="ch_box">
- <div class="ch_content_box" v-show="type == 1">
- <searchArea
- :courseDetail="courseDetail"
- ref="searchAreaRef"
- :navList="navList"
- :tcid="tcid"
- :openMegaphone="openMegaphone"
- :fileId="fileId"
- :recordType="recordType"
- v-if="itemType == 1"
- :canShowTips="canShowTips"
- :showTipsLoading="showTipsLoading"
- :tipsList="tipsList"
- />
- <taskArea
- :courseDetail="courseDetail"
- :navList="navList"
- :courseType="courseType"
- :taskCount="taskCount"
- :worksStudent="worksStudent"
- :openMegaphone="openMegaphone"
- ref="taskAreaRef"
- :fileId="fileId"
- v-show="itemType == 2"
- />
- <countdown
- ref="countdownRef"
- :fileId="fileId"
- :courseDetail="courseDetail"
- v-show="itemType == 3"
- />
- <languageAssistant ref="languageAssistantRef" v-if="itemType == 4" />
- <reviewArea
- ref="reviewAreaRef"
- v-if="itemType == 5"
- :courseType="courseType"
- :taskCount="taskCount"
- />
- <!-- <dialogArea
- :courseDetail="courseDetail"
- :openMegaphone="openMegaphone"
- ref="dialogAreaRef"
- :fileId="fileId"
- v-if="itemType == 3"
- /> -->
- </div>
- <div class="ch_nav_box">
- <div class="ch_nav_box_topFixed" v-if="userid===courseDetail.userid">
- <el-popover
- placement="left"
- width="200"
- trigger="hover"
- :disabled="
- !splitScreenData.isOpen ||
- splitScreenData.uid != splitScreenData.myUid
- "
- >
- <div class="ch_nav_box_topFixed_popover">
- <div
- class="ch_nav_box_topFixed_popover_item"
- @click="$emit('studentFreePreview', !IsLookOpen)"
- >
- <svg
- width="47"
- height="47"
- viewBox="0 0 47 47"
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- >
- <path
- d="M24.0331 33.0446C24.0417 33.0136 24.0519 32.9833 24.0615 32.9526H8.71767V11.2427H38.2544V24.2702C40.2717 25.0117 41.7187 27.6746 42.3823 29.7368V10.5083C42.3823 8.88588 41.0682 7.5708 39.4469 7.5708H7.52523C5.90401 7.5708 4.58984 8.88588 4.58984 10.5083V33.687C4.58984 35.3092 5.90392 36.6245 7.52523 36.6245H25.6554C24.1121 35.7167 23.7001 34.2505 24.0331 33.0446ZM24.6286 21.2716C25.6343 21.2717 26.6024 21.9111 26.9201 22.9763C26.5127 22.6633 26.0361 22.5106 25.5552 22.5106C25.068 22.5106 24.5763 22.6674 24.1476 22.9735C23.2958 23.5815 22.9191 24.6165 23.2474 25.5977C21.923 24.6485 21.9169 22.6683 23.2512 21.7158C23.6766 21.4123 24.1565 21.2716 24.6286 21.2716ZM25.7337 23.8211C26.1602 23.8211 26.5801 24.0203 26.8464 24.3943L30.17 29.0505C30.2674 29.1873 30.4212 29.2603 30.5773 29.2603C30.6778 29.2603 30.7789 29.23 30.8669 29.1672C31.0916 29.0067 31.1438 28.6946 30.9836 28.4699L30.1641 27.3202C30.5346 27.2261 30.9846 27.1134 31.4827 26.9917C31.5512 26.9748 31.6204 26.9668 31.6889 26.9668C31.9657 26.9668 32.2313 27.0993 32.3967 27.3318L33.0672 28.2723C33.1647 28.4091 33.3183 28.482 33.4746 28.482C33.5749 28.482 33.6761 28.4519 33.764 28.3891C33.9885 28.2287 34.041 27.9166 33.8807 27.6915L33.1062 26.605C33.5338 26.5062 33.9703 26.408 34.4013 26.3147C34.4626 26.3014 34.5241 26.295 34.5851 26.295C34.8624 26.295 35.128 26.4282 35.2931 26.6599L35.8626 27.459C35.9602 27.5957 36.1138 27.6687 36.27 27.6687C36.3705 27.6687 36.4717 27.6386 36.5598 27.5758C36.7841 27.4154 36.8365 27.1032 36.6762 26.8783L36.0382 25.9827C36.1675 25.9586 36.2947 25.9355 36.4188 25.914C36.5909 25.8842 36.753 25.8697 36.9061 25.8697C37.935 25.8697 38.5706 26.5222 39.2742 27.5095C41.0875 30.0538 40.5847 31.8453 42.41 34.4066C40.1118 36.0469 37.7933 37.7017 35.3731 39.4293C31.5753 36.5975 28.2964 35.6895 27.2376 35.3334C26.2286 34.994 25.5767 34.3464 25.8013 33.5335C26.0156 32.7576 26.7924 32.4959 27.4744 32.4959C27.5152 32.4959 27.5557 32.4969 27.5955 32.4986C28.664 32.5474 29.5306 32.8676 29.5306 32.8676L24.6227 25.9816C24.1847 25.367 24.3275 24.5136 24.9416 24.0753C25.182 23.9038 25.4593 23.8211 25.7337 23.8211Z"
- fill="#3F3F3F"
- />
- <line
- v-if="IsLookOpen"
- x1="5.29289"
- y1="39.2929"
- x2="40.2929"
- y2="4.29289"
- stroke="#FA5439"
- stroke-width="5"
- />
- </svg>
- <span>学生自由预览</span>
- </div>
- <div
- class="ch_nav_box_topFixed_popover_item"
- @click="$emit('OpenJobPreview', !sIsOpen)"
- >
- <svg
- width="53"
- height="53"
- viewBox="0 0 53 53"
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- >
- <path
- d="M26.129 8.50659C20.511 8.50659 15.9795 13.0646 15.9795 18.6561C15.9795 24.2741 20.5375 28.8056 26.129 28.8056C31.747 28.8056 36.2785 24.2476 36.2785 18.6561C36.2785 13.0646 31.7205 8.50659 26.129 8.50659ZM26.129 26.1821C21.995 26.1821 18.6295 22.8166 18.6295 18.6826C18.6295 14.5486 21.995 11.1831 26.129 11.1831C30.263 11.1831 33.6285 14.5486 33.6285 18.6826C33.6285 22.8166 30.263 26.1821 26.129 26.1821Z"
- fill="#363F4D"
- />
- <path
- d="M27.0035 26.1819C18.02 26.1819 11.6335 30.6339 10.971 38.5044C10.759 41.0749 12.667 43.3539 15.264 43.5659C15.3965 43.5659 15.529 43.5924 15.6615 43.5924H38.16C40.8365 43.5924 43.036 41.4194 43.0095 38.7164C43.0095 38.5574 43.0095 38.3984 42.983 38.2394C42.2145 30.4749 35.9075 26.1819 27.0035 26.1819ZM40.386 38.7164C40.386 39.9354 39.4055 40.9159 38.1865 40.9424H15.635C14.4955 40.9424 13.5945 40.0149 13.5945 38.9019V38.7429C14.1245 32.4094 19.2655 28.8319 27.0035 28.8319C34.662 28.8319 39.75 32.3034 40.386 38.5309V38.7164Z"
- fill="#363F4D"
- />
- <path
- d="M39.061 28.0371C44.2285 26.6061 47.2761 21.2531 45.8451 16.0856C45.1031 13.3826 43.248 11.1566 40.7305 9.93758C39.9885 9.59308 39.1141 9.88458 38.7696 10.6266C38.4251 11.3686 38.7165 12.2431 39.4585 12.5876C42.824 14.2306 44.2285 18.2851 42.5856 21.6506C41.7376 23.3996 40.1741 24.6981 38.2926 25.2281C37.4976 25.4401 37.0471 26.2616 37.2591 27.0301C37.4711 27.7721 38.2925 28.2491 39.061 28.0371Z"
- fill="#363F4D"
- />
- <path
- d="M52.4435 37.577C52.4435 37.418 52.4435 37.2325 52.417 37.0735C51.7015 29.9715 46.322 25.7315 38.478 25.122C37.6565 25.069 36.9675 25.652 36.888 26.4735C36.835 27.295 37.418 27.984 38.2395 28.0635C44.7585 28.567 48.919 31.8265 49.4755 37.365V37.577C49.4755 38.3985 50.138 39.061 50.9595 39.061C51.781 39.061 52.4435 38.3985 52.4435 37.577Z"
- fill="#363F4D"
- />
- <path
- d="M13.78 28.037C14.575 28.249 15.37 27.7985 15.582 27.0035C15.794 26.2085 15.3435 25.4135 14.5485 25.2015C12.667 24.6715 11.1035 23.373 10.2555 21.624C8.61254 18.2585 10.017 14.204 13.3825 12.561C14.1245 12.2165 14.416 11.3155 14.0715 10.6C13.727 9.85797 12.826 9.56647 12.1105 9.91097C9.61954 11.13 7.73804 13.3825 6.99604 16.059C5.56504 21.253 8.61253 26.606 13.78 28.037Z"
- fill="#363F4D"
- />
- <path
- d="M0.42395 37.577C0.42395 38.3985 1.08645 39.061 1.90795 39.061C2.72945 39.061 3.39195 38.3985 3.39195 37.577V37.365C3.94845 31.8265 8.10895 28.567 14.628 28.0635C15.4495 28.0105 16.0325 27.295 15.9795 26.4735C15.9265 25.652 15.211 25.069 14.3895 25.122C6.54545 25.7315 1.16595 29.9715 0.45045 37.0735C0.42395 37.259 0.42395 37.418 0.42395 37.577Z"
- fill="#363F4D"
- />
- <line
- v-if="!sIsOpen"
- x1="4.29289"
- y1="44.2929"
- x2="41.2929"
- y2="7.29289"
- stroke="#FA5439"
- stroke-width="5"
- />
- </svg>
- <span>开放作业预览</span>
- </div>
- </div>
- <div
- class="ch_nav_box_topFixed_item"
- :class="[
- splitScreenData.isOpen ? 'ch_nav_box_topFixed_item_active' : ''
- ]"
- @click="splitScreen"
- slot="reference"
- >
- <svg
- t="1730945943778"
- class="icon"
- viewBox="0 0 1024 1024"
- version="1.1"
- xmlns="http://www.w3.org/2000/svg"
- p-id="4480"
- width="200"
- height="200"
- >
- <path
- d="M213.333333 725.333333a85.333333 85.333333 0 0 1 85.333334 85.333334v85.333333a85.333333 85.333333 0 0 1-85.333334 85.333333h-85.333333a85.333333 85.333333 0 0 1-85.333333-85.333333v-85.333333a85.333333 85.333333 0 0 1 85.333333-85.333334h85.333333z m341.333334 0a85.333333 85.333333 0 0 1 85.333333 85.333334v85.333333a85.333333 85.333333 0 0 1-85.333333 85.333333h-85.333334a85.333333 85.333333 0 0 1-85.333333-85.333333v-85.333333a85.333333 85.333333 0 0 1 85.333333-85.333334h85.333334z m341.333333 0a85.333333 85.333333 0 0 1 85.333333 85.333334v85.333333a85.333333 85.333333 0 0 1-85.333333 85.333333h-85.333333a85.333333 85.333333 0 0 1-85.333334-85.333333v-85.333333a85.333333 85.333333 0 0 1 85.333334-85.333334h85.333333z m-682.666667 85.333334h-85.333333v85.333333h85.333333v-85.333333z m341.333334 0h-85.333334v85.333333h85.333334v-85.333333z m341.333333 0h-85.333333v85.333333h85.333333v-85.333333z m0-768a85.333333 85.333333 0 0 1 85.333333 85.333333v426.666667a85.333333 85.333333 0 0 1-85.333333 85.333333h-768a85.333333 85.333333 0 0 1-85.333333-85.333333v-426.666667a85.333333 85.333333 0 0 1 85.333333-85.333333h768z m0 85.333333h-768v426.666667h768v-426.666667z"
- p-id="4481"
- ></path>
- </svg>
- <span>分屏</span>
- </div>
- </el-popover>
- </div>
- <div class="ch_nav_box_top">
- <div @click.stop="changeFold(!fold)" ref="foldBtnRef">
- <el-tooltip
- class="item"
- effect="dark"
- :content="fold ? '折叠' : '展开'"
- placement="top"
- >
- <img
- :src="require('../../assets/icon/course/foldIcon.svg')"
- alt=""
- :class="[!fold ? '' : 'foldActive']"
- />
- </el-tooltip>
- </div>
- <div @click="changeItemType(5)" v-if="tType == 1">
- <el-tooltip class="item" effect="dark" content="评论" placement="top">
- <img
- :src="require('../../assets/icon/course/comment2.svg')"
- alt=""
- style="width: 22px;height: 22px;"
- />
- </el-tooltip>
- </div>
- <el-popover
- placement="left"
- width="150"
- trigger="manual"
- style="width: 100%;height: 100%;"
- v-model="uploadFileStatus.loading"
- :disabled="!uploadFileStatus.loading"
- v-if="!videoStart && (tType == 1 || tType == 4)"
- >
- <div class="drawerBox">
- <span>上传中</span>
- <el-progress
- :width="80"
- type="circle"
- :percentage="uploadFileStatus.percent"
- ></el-progress>
- </div>
- <div @click="startRecording()" class="boxItem" slot="reference">
- <el-tooltip
- class="item"
- effect="dark"
- content="录制"
- placement="top"
- >
- <img
- :src="require('../../assets/icon/course/record3.svg')"
- alt=""
- style="width: 22px;height: 22px;"
- />
- </el-tooltip>
- </div>
- </el-popover>
- <div
- @click="$emit('stopRecording')"
- v-else-if="tType == 1 || tType == 4"
- style="background:#f63564"
- >
- <el-tooltip class="item" effect="dark" content="下载" placement="top">
- <img
- :src="require('../../assets/icon/course/record4.svg')"
- alt=""
- style="width: 22px;height: 22px;"
- />
- </el-tooltip>
- </div>
- </div>
- <div class="ch_nav_box_middle">
- <div
- :class="[
- 'ch_nav_box_middle_item',
- itemType == 2 ? 'ch_nav_box_middle_item_active' : ''
- ]"
- @click.stop="changeItemType(2)"
- >
- <img
- v-if="itemType == 2"
- :src="require('../../assets/icon/course/task_active.png')"
- />
- <img
- v-if="itemType != 2"
- :src="require('../../assets/icon/course/task.png')"
- />
- <!-- <span :style="`background:url(${itemType==2?require('../../assets/icon/course/task_active.png'):require('../../assets/icon/course/task.png')});`"></span> -->
- <div>测验</div>
- </div>
- <div
- :class="[
- 'ch_nav_box_middle_item',
- itemType == 1 ? 'ch_nav_box_middle_item_active' : ''
- ]"
- @click.stop="changeItemType(1)"
- >
- <img
- v-if="itemType == 1"
- :src="require('../../assets/icon/course/up_active.png')"
- />
- <img
- v-if="itemType != 1"
- :src="require('../../assets/icon/course/up.png')"
- />
- <!-- <span :style="`background:url(${itemType==1?require('../../assets/icon/course/up_active.png'):require('../../assets/icon/course/up.png')});`"></span> -->
- <div>对话</div>
- </div>
- <div
- :class="[
- 'ch_nav_box_middle_item',
- itemType == 3 ? 'ch_nav_box_middle_item_active' : ''
- ]"
- @click.stop="changeItemType(3)"
- >
- <img
- v-if="itemType == 3"
- :src="require('../../assets/icon/course/Countdown2.svg')"
- />
- <img
- v-if="itemType != 3"
- :src="require('../../assets/icon/course/Countdown.svg')"
- />
- <div>倒计时</div>
- </div>
- </div>
- <div class="ch_nav_box_bottom">
- <div @click.stop="commentAndAnnotate()" style="z-index: 9999;">
- <el-tooltip class="item" effect="dark" content="批注" placement="top">
- <img
- :src="require('../../assets/icon/course/edit2.svg')"
- v-if="!AnnotationCanvasShow"
- />
- <img :src="require('../../assets/icon/course/edit3.svg')" v-else />
- </el-tooltip>
- </div>
- <!-- <div @click.stop="changeItemType(4)" :class="[itemType == 4?'ch_nav_box_middle_item_active':'']">
- <el-tooltip
- class="item"
- effect="dark"
- :content="itemType != 4?'开启语音助手':'关闭语音助手'"
- placement="top"
- >
- <img v-if="itemType != 4" :src="require('../../assets/icon/course/robot.svg')" />
- <img v-else :src="require('../../assets/icon/course/robot2.svg')" />
- </el-tooltip>
- </div> -->
- <div
- @click.stop="startAssistant()"
- :class="[recordType == 1 ? 'ch_nav_box_middle_item_active' : '']"
- >
- <el-tooltip
- class="item"
- effect="dark"
- :content="recordType == 0 ? '开启语音助手' : '关闭语音助手'"
- placement="top"
- >
- <img
- v-if="recordType != 1"
- :src="require('../../assets/icon/course/robot3.svg')"
- />
- <img v-else :src="require('../../assets/icon/course/robot3.svg')" />
- </el-tooltip>
- </div>
- <div @click.stop="$emit('goStep', 0)">
- <el-tooltip
- class="item"
- effect="dark"
- content="上一步"
- placement="top"
- >
- <img :src="require('../../assets/icon/course/last.png')" />
- </el-tooltip>
- </div>
- <div @click.stop="$emit('goStep', 1)">
- <el-tooltip
- class="item"
- effect="dark"
- content="下一步"
- placement="top"
- >
- <img :src="require('../../assets/icon/course/next.png')" />
- </el-tooltip>
- </div>
- <div @click="openSetting">
- <el-tooltip
- class="item"
- effect="dark"
- :content="type == 0 ? '展开' : '折叠'"
- placement="top"
- >
- <img :src="require('../../assets/icon/course/menu.png')" />
- </el-tooltip>
- </div>
- </div>
- </div>
- <div
- v-if="fold"
- class="itemFold"
- ref="itemFoldRef"
- v-click-outside="handleBlur"
- >
- <div @click="$emit('backPage')">
- <img :src="require('../../assets/icon/course/return.png')" alt="" />
- <span>返回</span>
- </div>
- <div @click="$emit('refresh')">
- <img :src="require('../../assets/icon/course/refresh.png')" alt="" />
- <span>刷新</span>
- </div>
- <div @click="$emit('authority')" v-if="tType == 1 || tType == 4">
- <img :src="require('../../assets/icon/course/setting2.svg')" alt="" />
- <span>权限</span>
- </div>
- </div>
- <levitatedSphere ref="levitatedSphereRef" @startTime="startTime" />
- <timepiece ref="timepieceRef" />
- <AnnotationCanvas
- ref="AnnotationCanvasRef"
- @close="endCommentAndAnnotate"
- @changeStatus="changeAnnotationCanvasShow"
- />
- <uploadFile
- ref="uploadFileRef"
- index="1"
- @progressUpdate="progressUpdate"
- @success="uploadSuccess"
- />
- <!-- <el-drawer
- title="我是标题"
- :visible.sync="uploadFileStatus.loading"
- :with-header="false"
- :modal="false"
- :modal-append-to-body="false"
- :close-on-press-escape="false"
- :withHeader="false"
- :wrapperClosable="false">
- <div class="drawerBox"></div>
- </el-drawer> -->
- </div>
- </template>
- <script>
- import searchArea from "./component/searchArea.vue";
- import taskArea from "./component/taskArea.vue";
- // import dialogArea from "./component/dialogArea.vue";
- import levitatedSphere from "./component/levitatedSphere.vue";
- import timepiece from "./component/timepiece.vue";
- import countdown from "./component/countdown.vue";
- import AnnotationCanvas from "./component/AnnotationCanvas.vue";
- import languageAssistant from "./component/languageAssistant.vue";
- import reviewArea from "./component/reviewArea.vue";
- import uploadFile from "./component/uploadFile.vue";
- import { v4 as uuidv4 } from "uuid";
- // 自定义指令,用于处理点击外部区域的事件
- const clickOutside = {
- bind(el, binding) {
- // 在元素上绑定一个点击事件监听器
- el.clickOutsideEvent = function(event) {
- // 检查点击事件是否发生在元素的内部
- if (!(el === event.target || el.contains(event.target))) {
- // 如果点击事件发生在元素的外部,则触发指令绑定的方法,将点击的event数据传过去
- binding.value(event);
- }
- };
- // 在文档上添加点击事件监听器
- document.addEventListener("click", el.clickOutsideEvent);
- },
- unbind(el) {
- // 在元素上解除点击事件监听器
- document.removeEventListener("click", el.clickOutsideEvent);
- }
- };
- export default {
- emits: [
- "refresh",
- "goStep",
- "backPage",
- "authority",
- "review",
- "stopRecording",
- "startRecording"
- ],
- directives: {
- "click-outside": clickOutside // 注册自定义指令
- },
- components: {
- searchArea,
- taskArea,
- // dialogArea,
- levitatedSphere,
- timepiece,
- countdown,
- AnnotationCanvas,
- languageAssistant,
- reviewArea,
- uploadFile
- },
- props: {
- courseDetail: {
- type: Object,
- default: () => {}
- },
- tType: {
- type: String,
- default: 0
- },
- navList: {
- type: Array,
- default: () => []
- },
- tcid: {
- type: String,
- default: ""
- },
- courseType: {
- type: Number,
- default: 0
- },
- taskCount: {
- type: Number,
- default: 0
- },
- worksStudent: {
- type: Array,
- default: () => []
- },
- fileList: {
- type: Array,
- default: () => []
- },
- videoStart: {
- type: Boolean,
- default: false
- },
- IsFollow: {
- type: Boolean,
- default: false
- },
- sIsOpen: {
- type: Boolean,
- default: false
- },
- IsLookOpen: {
- type: Boolean,
- default: false
- },
- splitScreenData: {
- type: Object,
- default: () => {
- return {
- isOpen: false,
- userId: "",
- uid: "",
- myUid: ""
- };
- }
- }
- },
- data() {
- return {
- userid: this.$route.query.userid,
- courseId: this.$route.query.courseId,
- tcid2: this.$route.query.tcid,
- type: 0,
- itemType: 0, //0--无 1-搜索 2-任务 3-对话
- fileId: [],
- recordType: 0,
- recordLoading: false,
- fold: false,
- openMegaphone: false, //是否打开喇叭
- getFileIdLoading: false,
- AnnotationCanvasShow: false,
- canShowTips: false,
- showTipsLoading: false,
- tipsList: [],
- firstEnterTime: null,
- canGetTips: true,
- getTipsTimer: null,
- getWangLoading: false,
- canUseWangData: false,
- wangData: "",
- languageSetting: 0,
- uploadFileStatus: {
- file: null,
- status: "",
- percent: 0,
- key: "",
- uploadid: "",
- loading: false
- }
- };
- },
- mounted() {
- let setting = this.courseDetail.setting;
- if (setting) {
- setting = JSON.parse(setting);
- if (setting.languageSetting) {
- this.languageSetting = setting.languageSetting;
- }
- }
- this.setWidth();
- this.getFileId();
- this.firstEnterTime = new Date().getTime();
- this.getWantSearch();
- this.uploadFileStatus = {
- file: null,
- status: "",
- percent: 0,
- key: "",
- uploadid: "",
- loading: false
- };
- setTimeout(() => {
- this.canGetTips = true;
- this.getTipsList();
- }, 3000);
- },
- methods: {
- getTipsListTime(time = 5000) {
- if (this.getTipsTimer) clearTimeout(this.getTipsListTime);
- this.getTipsTimer = setTimeout(() => {
- this.canGetTips = true;
- this.getTipsList();
- this.getTipsTimer = null;
- }, time);
- },
- getTipsList() {
- return new Promise(resolve => {
- if (!this.canGetTips) return;
- this.showTipsLoading = true;
- let nowTaskObj = this.navList[this.courseType].task[this.taskCount];
- let nowTask = `【任务${this.taskCount + 1}:${nowTaskObj.taskName}】`;
- let _textData = `课程名称:${this.courseDetail.title}\n分类:${this.courseDetail.name}\n\n`;
- let _chapters = JSON.parse(this.courseDetail.chapters);
- _chapters.forEach((i1, index1) => {
- if (i1.dyName) {
- _textData += `阶段${index1 + 1}:${i1.dyName}\n`;
- }
- i1.chapterInfo[0].taskJson.forEach((i2, index2) => {
- if (i2.task) {
- _textData += `任务${index2 + 1}:${i2.task}\n`;
- _textData += `${i2.taskDetail}\n`;
- }
- });
- _textData += "\n";
- });
- let _msg = `Language: ${this.getLang()}
- ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenced "Format example".
- Instruction: Based on the context, follow "Format example", write content
- #Context
- ## 任务
- 你是专业的教学评估员,擅长分析课堂动态和学生的认知状态,能够根据教师的当前思路提供有效的教学建议。
- 你需要根据我提供的信息,推测分析,之后给出3个具体的操作步骤的建议。
- ##工作流程
- 1. 仔细阅读并分析我提供的课堂信息或课堂实录内容。
- 2. 观察课堂上学生的行为和反应,推测他们的认知状态。
- 3. 通过教师的言行和教学安排,推测教师当前的思路和教学目标。
- 4. 根据教师的思路和学生的认知状态,提出一个教学建议,并给出3个具体的操作步骤。只需要描述对应的动作,不需要指出该动作的目标和作用。
- ##输出
- ###输出要求
- 1. 最终输出仅包含具体操作步骤。
- 2. 具体操作步骤以数组形式输出,包含3个步骤。
- 3. 每个步骤用一句话描述,详细一些
- ##课堂内容
- 当前进行到:${nowTask}
- ##Format example
- ["步骤的描述","步骤的描述","步骤的描述"]
- ${_textData}
- `;
- let params = {
- // assistant_id: "6063369f-289a-11ef-8bf4-12e77c4cb76b",
- // userId: this.userid,
- // message: [{ type: "text", text: _msg }],
- // session_name: uuidv4(),
- // // uid: _uuid,
- // file_ids: this.fileId,
- // model: "gpt-4o-2024-11-20",
- model: "gpt-4o-2024-11-20",
- temperature: 0,
- max_tokens: 4096,
- top_p: 1,
- frequency_penalty: 0,
- presence_penalty: 0,
- messages: [{ role: "user", content: _msg }],
- uid: uuidv4(),
- mind_map_question: "",
- stream: false
- };
- 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 => {
- let _data = res.data.FunctionResponse.choices[0].message.content;
- _data = _data.replaceAll("```json", "").replaceAll("```", "");
- console.log(_data);
- const match = _data.match(/\[\s*[^]*\s*\]/);
- let _result = JSON.parse(match[0]) || [];
- this.tipsList.push(_result);
- this.showTipsLoading = false;
- this.canShowTips = true;
- this.canGetTips = false;
- resolve();
- })
- .catch(e => {
- this.showTipsLoading = false;
- this.$message.error("获取课堂小贴士失败");
- console.log(e);
- });
- });
- },
- handleBlur() {
- // console.log(this.fold)
- this.fold = !this.fold;
- },
- changeAnnotationCanvasShow(newValue) {
- this.AnnotationCanvasShow = newValue;
- },
- startRecording() {
- if (this.uploadFileStatus.loading)
- return this.$message.error("正在上传录屏文件,请稍等...");
- this.$emit("startRecording");
- this.insertMemorandum(`使用<span class="btn">录制</span>功能,录制课堂`);
- },
- insertMemorandum(_html) {
- //保存行为操作
- //variable
- //btn
- let params = [
- {
- uid: this.userid,
- courseId: this.courseId + (this.tcid2 ? this.tcid2 : ""),
- content: _html
- }
- ];
- this.ajax
- .post(
- this.$store.state.api + "insert_systemOperation_countdownBehavior",
- params
- )
- .then(res => {
- if (res.data == 1) {
- console.log("保存操作成功");
- } else {
- console.log("保存操作失败");
- }
- })
- .catch(e => {
- console.log("保存操作失败");
- console.log(e);
- });
- },
- setWidth() {
- let w = this.$refs.ch_box;
- let w2 = w.offsetWidth + 30 + "px";
- this.$emit("setWidth", w2);
- },
- openSetting() {
- this.type = this.type == 1 ? 0 : 1;
- this.$nextTick(() => {
- if (this.type == 1) {
- this.$parent.mlDialog = false;
- }
- this.setWidth();
- });
- },
- changeItemType(type) {
- this.type = 0;
- if (this.itemType == type) {
- this.itemType = 0;
- this.type = 1;
- this.openSetting();
- return;
- }
- this.openSetting();
- // this.$message.info("切换到"+type)
- this.$nextTick(() => {
- // if (this.itemType == 1 && type != 1) {
- // this.$refs.searchAreaRef.scrollBottom();
- // this.$refs.searchAreaRef.getWantSearch();
- // } else if (this.itemType == 2) {
- // this.$refs.taskAreaRef.scrollBottom();
- // } else if (this.itemType == 3) {
- // this.$refs.dialogAreaRef.scrollBottom();
- // }
- this.itemType = type;
- if (this.itemType == 4 && this.recordType == 1) {
- //关闭悬浮语音助手
- this.$refs.levitatedSphereRef.stopRecord();
- }
- if (this.itemType == 3) {
- this.insertMemorandum(`打开<span class="btn">倒计时</span>面板`);
- }
- });
- },
- //计时
- startTime(time) {
- this.$refs.timepieceRef.startTime(time);
- },
- getFileId() {
- if (this.getFileIdLoading) return;
- this.getFileIdLoading = true;
- this.fileId = [];
- let _this = this;
- let _successFileUrl = [];
- if (this.fileList.length <= 0) return;
- let addType = ["DOCX", "DOC", "PPT", "PPTX", "MD", "TXT", "PDF"];
- this.fileList.forEach(i => {
- if (
- addType.includes(
- i.url.split(".")[i.url.split(".").length - 1].toLocaleUpperCase()
- )
- ) {
- _successFileUrl.push(i.url);
- }
- });
- let promiseList = [];
- _successFileUrl.forEach(i => {
- promiseList.push(
- new Promise((resolve, reject) => {
- _this.ajax
- .put("https://gpt4.cocorobo.cn/upload_file_knowledge", {
- url: i
- })
- .then(res => {
- let _data = res.data.FunctionResponse;
- if (_data.result && _data.result.id) {
- this.fileId.push(_data.result.id);
- }
- resolve();
- });
- })
- );
- });
- Promise.all(promiseList).then(res => {
- this.getFileIdLoading = false;
- });
- },
- startAssistant() {
- if (this.recordLoading) return this.$message.info("请稍等...");
- this.recordLoading = true;
- if (this.recordType == 0) {
- if (this.itemType == 4) {
- this.itemType = 0;
- this.type = 0;
- }
- // this.$message.info("开启")
- // this.changeRecordType(1)
- this.$refs.levitatedSphereRef.recordStart();
- } else if (this.recordType == 1) {
- // this.$message.info("关闭")
- this.$refs.levitatedSphereRef.stopTwo();
- // this.changeRecordType(0)
- }
- },
- changeMegaphone() {
- this.openMegaphone = !this.openMegaphone;
- if (this.openMegaphone) {
- this.$message.success("已开启AI语音");
- } else {
- this.$message.success("已关闭AI语音");
- }
- },
- // 展开
- changeFold(newValue) {
- // this.$message.info("展开");
- this.fold = newValue;
- this.$nextTick(() => {
- let e1 = this.$refs.foldBtnRef.getBoundingClientRect();
- let e2 = this.$refs.ch_box.getBoundingClientRect();
- console.log("👇👇");
- console.log(e1.top - e2.top);
- this.$refs.itemFoldRef.style.top = e1.top - e2.top + "px";
- });
- },
- // 收起
- changeUnfold(newValue) {
- // this.$message.info("收起");
- this.fold = newValue;
- },
- // 语音识别
- startRecord() {
- this.$refs.levitatedSphereRef.startRecord();
- },
- stopRecord() {
- this.$refs.levitatedSphereRef.stopTwo();
- },
- // 语音合成
- startSpeak() {},
- changeRecordType(type) {
- this.recordLoading = false;
- this.recordType = type;
- },
- commentAndAnnotate() {
- if (this.AnnotationCanvasShow) {
- this.$refs.AnnotationCanvasRef.close();
- } else {
- this.$refs.AnnotationCanvasRef.open();
- this.insertMemorandum(`开始使用<span class="btn">批注</span>功能`);
- }
- },
- endCommentAndAnnotate() {
- this.insertMemorandum(`结束使用<span class="btn">批注</span>功能`);
- },
- getWantSearch() {
- console.log("获取猜你想搜");
- let _uuid = uuidv4();
- this.getWangLoading = true;
- this.canUseWangData = false;
- this.wangData = "";
- let _msg = `
- Language: ${this.getLang()}
- ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenced "Format example".
- Instruction: Based on the context, follow "Format example", write content
- ## 任务
- 你的任务是根据“课程信息”,提供用户需要的搜索建议,将搜索建议的结果以有序列表的形式返回给用户。
- ## 课程信息
- #### 课程标题:${this.courseDetail.title ? this.courseDetail.title : ""}
- #### 分类:${this.courseDetail.name ? this.courseDetail.name : "无"}
- #### 学生年级:${
- this.courseDetail.classname ? this.courseDetail.classname : "无"
- }
- ## 规则
- 输出结果基于“课程信息”,避免提供无关的信息。
- 搜索建议的结果符合伦理规范。
- ## 输出
- 输出应包括6个相关的搜索建议,每个搜索建议需要以问号的方式结束。
- 请一步步思考如何根据现有信息推送搜索建议,但是不需要输出搜索建议以外的内
- ## 输出格式
- 搜索建议应以有序列表形式呈现,每个建议包括关键词和简短描述。输出JSON格式的
- ## Format example
- [{"index": 1,"title": "垃圾分类标准","label": "不同国家的垃圾分类标准和方法?"},{"index": 2,"title":"可回收垃圾处理","label": "可回收垃圾的处理流程和再利用方法?"},{ "index": 3, "title": "有害垃圾的影响", "label": "有害垃圾对环境和人体健康的潜在影响?"},{ "index": 4, "title": "垃圾分类标准", "label": "不同国家的垃圾分类标准和方法?"},{ "index": 5, "title": "可回收垃圾处理", "label": "可回收垃圾的处理流程和再利用方法?"},{ "index": 6, "title": "有害垃圾的影响", "label": "有害垃圾对环境和人体健康的潜在影响?"}]
- `;
- // 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 = {
- assistant_id: "6063369f-289a-11ef-8bf4-12e77c4cb76b",
- userId: this.userid,
- message: [{ type: "text", text: _msg }],
- session_name: _uuid,
- // uid: _uuid,
- file_ids: this.fileId,
- model: "gpt-4o-2024-11-20"
- };
- // let params = {
- // message: {
- // anthropic_version: "bedrock-2023-05-31",
- // max_tokens: 4096,
- // temperature: 0,
- // top_p: 1,
- // messages: [{ role: "user", content: _msg }]
- // },
- // 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)
- .post("https://gpt4.cocorobo.cn/ai_agent_park_chat", params)
- .then(res => {
- // console.log(res);
- let _data = res.data.FunctionResponse.message;
- _data = _data.replaceAll("```json", "").replaceAll("```", "");
- const match = _data.match(/\[\s*{[^]*}\s*\]/);
- this.wangData = match[0];
- this.canUseWangData = true;
- this.getWangLoading = false;
- // console.log(_data);
- // console.log(match);
- // this.chatList.find(i => i.uid == _uuid).aiContent = JSON.parse(
- // match[0]
- // );
- // this.chatList.find(i => i.uid == _uuid).isalltext = true;
- // this.chatList.find(i => i.uid == _uuid).isShowSynchronization = true;
- // this.chatList.find(i => i.uid == _uuid).loading = false;
- // this.scrollBottom();
- // this.chatLoading = false;
- })
- .catch(e => {
- this.chatLoading = false;
- this.canUseWangData = false;
- this.getWangLoading = false;
- console.log(e);
- });
- // this.getWAntSearchContent(_uuid);
- },
- getLang() {
- let lang = "";
- if (this.languageSetting == 0) {
- lang = "Chinese.";
- } else if (this.languageSetting == 1) {
- lang = "Traditional Chinese.";
- } else if (this.languageSetting == 2) {
- lang = "English.";
- }
- return lang;
- },
- getWanData() {
- if (this.wangData && this.canUseWangData) {
- const _result = this.wangData;
- this.wangData = "";
- this.canUseWangData = false;
- this.getWantSearch();
- return _result;
- }
- },
- splitScreen() {
- if (this.tType == 1) {
- if (this.splitScreenData.isOpen) {
- if (
- this.splitScreenData.userId == this.userid &&
- this.splitScreenData.uid == this.splitScreenData.myUid
- ) {
- // this.splitScreenData.isOpen = false;
- this.$emit("splitScreenBehavior", 0); //关闭分屏
- } else {
- if (
- this.splitScreenData.userId == this.userid &&
- this.splitScreenData.uid != this.splitScreenData.myUid
- ) {
- this.$message.error("需要在开启分屏的设备上关闭分屏");
- } else {
- this.$message.error("你不是分屏的创建者,无法关闭分屏");
- }
- }
- } else {
- this.$emit("splitScreenBehavior", 1); //打开分屏
- // this.splitScreenData.isOpen = true;
- }
- } else {
- this.$message.error("只有老师可以分屏");
- }
- },
- checkUploadFile(file) {
- this.$confirm(`是否上传${file.name}至资源库?`)
- .then(res => {
- console.log("上传👉", file);
- this.$refs.uploadFileRef.awsupload({ file: file });
- this.uploadFileStatus.file = file;
- this.uploadFileStatus.loading = true;
- this.uploadFileStatus.percent = 0;
- })
- .catch(e => {
- console.log("取消上传👉", e);
- });
- },
- progressUpdate(res) {
- this.uploadFileStatus.status = res.status;
- this.uploadFileStatus.percent = res.percent;
- this.uploadFileStatus.key = res.key;
- this.uploadFileStatus.uploadid = res.uploadid;
- this.uploadFileStatus.loading = true;
- },
- uploadSuccess(res) {
- let _data = res.data;
- this.uploadFileStatus.loading = false;
- let params = [
- {
- n: this.uploadFileStatus.file.name,
- file: _data.Location,
- type: 2,
- pid: "0",
- uid: this.userid,
- size: (this.uploadFileStatus.file.size / 1024).toFixed(2) + "kb"
- }
- ];
- this.ajax
- .post(this.$store.state.api + "addSourceFile", params)
- .then(res => {
- this.$message.success(
- `上传《${this.uploadFileStatus.file.name}》至资源库成功`
- );
- this.uploadFileStatus = {
- file: null,
- status: "",
- percent: 0,
- key: "",
- uploadid: "",
- loading: false
- };
- })
- .catch(err => {
- console.error(err);
- });
- }
- }
- };
- </script>
- <style scoped>
- .ch_box {
- width: auto;
- background: rgb(255, 255, 255);
- position: fixed;
- height: calc(100% - 40px);
- border-radius: 10px;
- box-sizing: border-box;
- right: 20px;
- display: flex;
- top: 20px;
- z-index: 1000;
- }
- .ch_nav_box {
- height: 100%;
- width: 65px;
- display: flex;
- flex-direction: column;
- align-items: center;
- overflow-y: auto !important; /* 上下溢出显示滚动条 */
- overflow-x: hidden !important; /* 左右溢出正常溢出 */
- position: relative;
- }
- .ch_content_box {
- width: 400px;
- height: 100%;
- border-right: 2px solid #e7e7e7;
- }
- .ch_nav_box_bottom {
- width: 100%;
- box-sizing: border-box;
- border-top: solid 1px #eaeaea;
- display: flex;
- flex-direction: column;
- }
- .ch_nav_box_middle {
- width: 100%;
- box-sizing: border-box;
- border-top: solid 1px #eaeaea;
- flex-direction: column;
- justify-content: space-between;
- }
- .ch_nav_box_middle_item {
- width: 100%;
- height: 80px;
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- cursor: pointer;
- transition: 0.3s;
- font-size: 14px;
- }
- .ch_nav_box_middle_item_active {
- background-color: #3681fc;
- color: white;
- }
- .ch_nav_box_middle_item > img {
- width: 24px;
- height: 24px;
- margin-bottom: 5px;
- }
- .ch_nav_box_bottom > div {
- width: 100%;
- height: 65px;
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- cursor: pointer;
- }
- .ch_nav_box_bottom > div > img {
- width: 24px;
- height: 24px;
- }
- .ch_nav_box_top {
- width: 100%;
- height: auto;
- margin-top: auto;
- }
- .ch_nav_box_top > div {
- width: 100%;
- height: 65px;
- display: flex;
- justify-content: center;
- align-items: center;
- cursor: pointer;
- position: relative;
- }
- .boxItem {
- width: 100%;
- height: 65px;
- display: flex;
- justify-content: center;
- align-items: center;
- cursor: pointer;
- position: relative;
- }
- .boxItem > img {
- width: 24px;
- height: 24px;
- transition: 0.3s;
- }
- .ch_nav_box_top > div > img {
- width: 24px;
- height: 24px;
- transition: 0.3s;
- }
- .itemFold {
- position: absolute;
- width: 130px;
- right: 65px;
- top: 0;
- background: rgb(255, 255, 255);
- box-sizing: border-box;
- border: solid 1px #eaeaea;
- /* border-top: solid 1px #eaeaea; */
- z-index: 1000; /* 确保二级菜单在主菜单上层 */
- border-radius: 10px;
- box-sizing: border-box;
- padding: 10px;
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- }
- .itemFold > div {
- width: 100%;
- height: 45px;
- display: flex;
- justify-content: center;
- align-items: center;
- cursor: pointer;
- margin: 5px 0;
- border-radius: 10px;
- }
- .itemFold > div:hover {
- background: #f3f7fd;
- }
- .itemFold > div > img {
- width: 24px;
- height: 24px;
- }
- .itemFold > div > span {
- margin-left: 10px;
- }
- @media screen and (max-height: 820px) {
- .ch_nav_box_bottom > div {
- height: auto;
- padding: 8px 0;
- }
- .ch_nav_box_middle_item {
- height: auto;
- padding: 8px 0;
- }
- .ch_nav_box_top > div {
- height: auto;
- padding: 8px 0;
- }
- }
- .foldActive {
- background-color: #f0f2f5;
- padding: 10px;
- border-radius: 10px;
- }
- .ch_nav_box_topFixed {
- width: 100%;
- height: 65px;
- position: absolute;
- top: 0;
- left: 0;
- }
- .ch_nav_box_topFixed_item {
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- width: 100%;
- height: 65px;
- padding-top: 5px;
- cursor: pointer;
- border-radius: 10px 10px 0 0;
- }
- .ch_nav_box_topFixed_item > svg {
- width: 25px;
- height: 25px;
- fill: #000;
- }
- .ch_nav_box_topFixed_item > span {
- margin-top: 5px;
- font-size: 14px;
- }
- .ch_nav_box_topFixed_item_active {
- background-color: #3681fc;
- color: #fff;
- }
- .ch_nav_box_topFixed_item_active > svg {
- fill: #fff;
- }
- .ch_nav_box_topFixed_popover {
- width: 100%;
- height: 65px;
- display: flex;
- }
- .ch_nav_box_topFixed_popover_item {
- width: 100px;
- height: 65px;
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- cursor: pointer;
- }
- .ch_nav_box_topFixed_popover_item > svg {
- width: 30px;
- height: 30px;
- fill: #000;
- }
- .ch_nav_box_topFixed_popover_item > span {
- margin-top: 5px;
- }
- .drawerBox {
- width: 100%;
- height: 100%;
- display: flex;
- justify-content: center;
- align-items: center;
- font-weight: bold;
- }
- .drawerBox > span {
- /* 字体竖着排列; */
- writing-mode: vertical-rl;
- margin-right: 10px;
- }
- </style>
|