choiceQuestionDetailDialog.vue 84 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476
  1. <template>
  2. <div class="choiceQuestionDetailDialog">
  3. <div class="content" @click="clickContent(true)" :style="{
  4. width: slideWidth + 'px',
  5. height: slideHeight + 'px',
  6. }">
  7. <span v-show="false" class="closeIcon" @click.stop="closeSlideIndex()">
  8. <img src="../../../assets/img/close.png" />
  9. </span>
  10. <!-- 选择题 -->
  11. <div class="c_t45" v-if="workDetail && workDetail.type === '45' && props.showData">
  12. <div class="c_t45_title">
  13. <div v-if="props.showData.choiceQuestionListData[props.showData.workIndex]">{{
  14. props.showData.choiceQuestionListData[props.showData.workIndex]
  15. .teststitle
  16. }}</div>
  17. <div class="c_t45_msg">
  18. <div>{{ lang.ssAnswerCount }} {{ props.showData.workArray.length }}<span
  19. v-if="props.showData.unsubmittedStudents.length > 0">/{{ props.showData.workArray.length +
  20. props.showData.unsubmittedStudents.length
  21. }}</span></div>
  22. <span v-if="props.showData.unsubmittedStudents.length > 0" @click.stop="viewUnsubmittedStudents()">{{
  23. lang.ssViewSubmitStatus2 }}</span>
  24. </div>
  25. <!--<span class="c_t45_t_btn" :class="{'c_t45_t_btn_noActive': props.showData.workIndex <= 0}" @click="changeWorkIndex(0)">{{ lang.ssPrevQ }}</span>-->
  26. <!--<span class="c_t45_t_btn" :class="{'c_t45_t_btn_noActive': props.showData.workIndex >= props.showData.choiceQuestionListData.length - 1}" @click="changeWorkIndex(1)">{{ lang.ssNextQ }}</span>-->
  27. </div>
  28. <img class="c_t45_img" :src="props.showData.choiceQuestionListData[props.showData.workIndex]
  29. .timuList[0].src
  30. " v-if="props.showData.choiceQuestionListData[props.showData.workIndex] &&
  31. props.showData.choiceQuestionListData[props.showData.workIndex]
  32. .timuList.length > 0
  33. " @click.stop="previewImageToolRef.previewImage(props.showData.choiceQuestionListData[props.showData.workIndex]
  34. .timuList[0].src)" />
  35. <!-- <span class="c_t45_type" v-if="
  36. props.showData.choiceQuestionListData[props.showData.workIndex]
  37. .type === '1'
  38. ">{{ lang.ssSingleSel }}</span>
  39. <span class="c_t45_type" v-if="
  40. props.showData.choiceQuestionListData[props.showData.workIndex]
  41. .type === '2'
  42. ">{{ lang.ssMultiOpt }}</span> -->
  43. <!-- <span class="c_t45_type">{{ lang.ssChoiceQuestion }}</span> -->
  44. <div class="c_t45_echarts" :style="{
  45. width: slideWidth - 40 + 'px',
  46. }">
  47. <div id="echartsArea1" ref="echartsArea1"></div>
  48. </div>
  49. <div class="aiAnalysis" v-if="props.workArray.length > 0">
  50. <div class="ai_header">
  51. <div class="ai_title">
  52. <svg viewBox="0 0 1024 1024" width="200" height="200">
  53. <path
  54. d="M512 170.666667C323.477333 170.666667 170.666667 323.477333 170.666667 512s152.810667 341.333333 341.333333 341.333333 341.333333-152.810667 341.333333-341.333333S700.522667 170.666667 512 170.666667zM85.333333 512C85.333333 276.352 276.352 85.333333 512 85.333333s426.666667 191.018667 426.666667 426.666667-191.018667 426.666667-426.666667 426.666667S85.333333 747.648 85.333333 512z">
  55. </path>
  56. <path
  57. d="M693.013333 330.986667a42.666667 42.666667 0 0 1 10.304 43.648l-75.413333 226.282666a42.666667 42.666667 0 0 1-26.986667 26.986667l-226.282666 75.413333a42.666667 42.666667 0 0 1-53.973334-53.973333l75.434667-226.261333a42.666667 42.666667 0 0 1 26.986667-26.986667l226.282666-75.413333a42.666667 42.666667 0 0 1 43.648 10.304z m-222.72 139.306666l-41.685333 125.098667 125.077333-41.706667 41.706667-125.077333-125.077333 41.706667z">
  58. </path>
  59. </svg>{{ lang.ssAnalysis }}
  60. </div>
  61. <div class="ai_refresh" :class="{ 'disabled': currentAnalysis && currentAnalysis.loading }"
  62. @click.stop="aiAnalysisRefresh45()">
  63. {{ lang.ssAIGenerate }}
  64. <svg viewBox="0 0 1024 1024" width="200" height="200">
  65. <path
  66. d="M875 483c-33.4 0-60.5 27.1-60.5 60.5v0.1C814.4 710.3 678.8 846 512 846S209.5 710.3 209.5 543.5 345.2 241 512 241c36.8 0 71.7 7.6 104.4 19.7-32 3-57.4 29.1-57.4 61.9 0 34.8 28.2 63 63 63h201.9c34.8 0 63-28.2 63-63V120c0-34.8-28.2-63-63-63s-63 28.2-63 63v81.4C691 150.5 605.2 120 512 120 278.1 120 88.5 309.6 88.5 543.5S278.1 967 512 967s423.5-189.6 423.5-423.5c0-33.4-27.1-60.5-60.5-60.5z">
  67. </path>
  68. </svg>
  69. </div>
  70. </div>
  71. <div class="ai_content" v-if="currentAnalysis && currentAnalysis.json">
  72. {{ currentAnalysis.json.text }}
  73. </div>
  74. <div class="ai_echartsData" v-if="currentAnalysis && currentAnalysis.json.keyword">
  75. {{ currentAnalysis.json.keyword }}
  76. </div>
  77. <div class="generatingContent" v-if="currentAnalysis && currentAnalysis.loading">
  78. {{ lang.ssGeneratingContent }}...</div>
  79. <div class="ai_updateTime" v-if="currentAnalysis">{{ lang.ssUpdateTime }}:{{ currentAnalysis.update_at }}
  80. </div>
  81. </div>
  82. <div class="cq_changeBtn" v-if="props.showData.choiceQuestionListData.length > 1">
  83. <div :class="{ cq_cb_disabled: props.showData.workIndex <= 0 }" @click.stop="changeWorkIndex(0)">
  84. <svg style="transform: rotate(-90deg);" viewBox="0 0 1024 1024" version="1.1" width="200" height="200">
  85. <path
  86. d="M512 330.666667c14.933333 0 29.866667 4.266667 40.533333 14.933333l277.33333399 234.666667c27.733333 23.466667 29.866667 64 8.53333301 89.6-23.466667 27.733333-64 29.866667-89.6 8.53333299L512 477.866667l-236.8 200.53333299c-27.733333 23.466667-68.266667 19.19999999-89.6-8.53333299-23.466667-27.733333-19.19999999-68.266667 8.53333301-89.6l277.33333399-234.666667c10.666667-10.666667 25.6-14.933333 40.533333-14.933333z"
  87. fill=""></path>
  88. </svg>
  89. </div>
  90. <span>{{ props.showData.workIndex + 1 }}/{{ props.showData.choiceQuestionListData.length }}</span>
  91. <div :class="{ cq_cb_disabled: props.showData.workIndex >= props.showData.choiceQuestionListData.length - 1 }"
  92. @click.stop="changeWorkIndex(1)">
  93. <svg style="transform: rotate(90deg);" viewBox="0 0 1024 1024" version="1.1" width="200" height="200">
  94. <path
  95. d="M512 330.666667c14.933333 0 29.866667 4.266667 40.533333 14.933333l277.33333399 234.666667c27.733333 23.466667 29.866667 64 8.53333301 89.6-23.466667 27.733333-64 29.866667-89.6 8.53333299L512 477.866667l-236.8 200.53333299c-27.733333 23.466667-68.266667 19.19999999-89.6-8.53333299-23.466667-27.733333-19.19999999-68.266667 8.53333301-89.6l277.33333399-234.666667c10.666667-10.666667 25.6-14.933333 40.533333-14.933333z"
  96. fill=""></path>
  97. </svg>
  98. </div>
  99. </div>
  100. </div>
  101. <!-- 投票 -->
  102. <div class="c_t45" v-if="workDetail && workDetail.type === '78' && props.showData">
  103. <div class="c_t45_title">
  104. <div v-if="props.showData.choiceQuestionListData[props.showData.workIndex]">{{
  105. props.showData.choiceQuestionListData[props.showData.workIndex]
  106. .teststitle
  107. }}</div>
  108. <div class="c_t45_msg">
  109. <div>{{ lang.ssAnswerCount }} {{ props.showData.workArray.length }}<span
  110. v-if="props.showData.unsubmittedStudents.length > 0">/{{ props.showData.workArray.length +
  111. props.showData.unsubmittedStudents.length
  112. }}</span></div>
  113. <span v-if="props.showData.unsubmittedStudents.length > 0" @click.stop="viewUnsubmittedStudents()">{{
  114. lang.ssViewSubmitStatus2 }}</span>
  115. </div>
  116. <!--<span class="c_t45_t_btn" :class="{'c_t45_t_btn_noActive': props.showData.workIndex <= 0}" @click="changeWorkIndex(0)">{{ lang.ssPrevQ }}</span>-->
  117. <!--<span class="c_t45_t_btn" :class="{'c_t45_t_btn_noActive': props.showData.workIndex >= props.showData.choiceQuestionListData.length - 1}" @click="changeWorkIndex(1)">{{ lang.ssNextQ }}</span>-->
  118. </div>
  119. <img class="c_t45_img" :src="props.showData.choiceQuestionListData[props.showData.workIndex]
  120. .timuList[0].src
  121. " v-if="props.showData.choiceQuestionListData[props.showData.workIndex] &&
  122. props.showData.choiceQuestionListData[props.showData.workIndex]
  123. .timuList.length > 0
  124. " @click.stop="previewImageToolRef.previewImage(props.showData.choiceQuestionListData[props.showData.workIndex]
  125. .timuList[0].src)" />
  126. <!-- <span class="c_t45_type" v-if="
  127. props.showData.choiceQuestionListData[props.showData.workIndex]
  128. .type === '1'
  129. ">{{ lang.ssSingleSel }}</span>
  130. <span class="c_t45_type" v-if="
  131. props.showData.choiceQuestionListData[props.showData.workIndex]
  132. .type === '2'
  133. ">{{ lang.ssMultiOpt }}</span> -->
  134. <!-- <span class="c_t45_type">{{ lang.ssChoiceQuestion }}</span> -->
  135. <div class="c_t45_echarts" :style="{
  136. width: slideWidth - 40 + 'px',
  137. }">
  138. <div id="echartsArea1" ref="echartsArea1"></div>
  139. </div>
  140. <div class="aiAnalysis" v-if="props.workArray.length > 0">
  141. <div class="ai_header">
  142. <div class="ai_title">
  143. <svg viewBox="0 0 1024 1024" width="200" height="200">
  144. <path
  145. d="M512 170.666667C323.477333 170.666667 170.666667 323.477333 170.666667 512s152.810667 341.333333 341.333333 341.333333 341.333333-152.810667 341.333333-341.333333S700.522667 170.666667 512 170.666667zM85.333333 512C85.333333 276.352 276.352 85.333333 512 85.333333s426.666667 191.018667 426.666667 426.666667-191.018667 426.666667-426.666667 426.666667S85.333333 747.648 85.333333 512z">
  146. </path>
  147. <path
  148. d="M693.013333 330.986667a42.666667 42.666667 0 0 1 10.304 43.648l-75.413333 226.282666a42.666667 42.666667 0 0 1-26.986667 26.986667l-226.282666 75.413333a42.666667 42.666667 0 0 1-53.973334-53.973333l75.434667-226.261333a42.666667 42.666667 0 0 1 26.986667-26.986667l226.282666-75.413333a42.666667 42.666667 0 0 1 43.648 10.304z m-222.72 139.306666l-41.685333 125.098667 125.077333-41.706667 41.706667-125.077333-125.077333 41.706667z">
  149. </path>
  150. </svg>{{ lang.ssAnalysis }}
  151. </div>
  152. <div class="ai_refresh" :class="{ 'disabled': currentAnalysis && currentAnalysis.loading }"
  153. @click.stop="aiAnalysisRefresh78()">
  154. {{ lang.ssAIGenerate }}
  155. <svg viewBox="0 0 1024 1024" width="200" height="200">
  156. <path
  157. d="M875 483c-33.4 0-60.5 27.1-60.5 60.5v0.1C814.4 710.3 678.8 846 512 846S209.5 710.3 209.5 543.5 345.2 241 512 241c36.8 0 71.7 7.6 104.4 19.7-32 3-57.4 29.1-57.4 61.9 0 34.8 28.2 63 63 63h201.9c34.8 0 63-28.2 63-63V120c0-34.8-28.2-63-63-63s-63 28.2-63 63v81.4C691 150.5 605.2 120 512 120 278.1 120 88.5 309.6 88.5 543.5S278.1 967 512 967s423.5-189.6 423.5-423.5c0-33.4-27.1-60.5-60.5-60.5z">
  158. </path>
  159. </svg>
  160. </div>
  161. </div>
  162. <div class="ai_content" v-if="currentAnalysis && currentAnalysis.json">
  163. {{ currentAnalysis.json.text }}
  164. </div>
  165. <div class="ai_echartsData" v-if="currentAnalysis && currentAnalysis.json.keyword">
  166. {{ currentAnalysis.json.keyword }}
  167. </div>
  168. <div class="generatingContent" v-if="currentAnalysis && currentAnalysis.loading">
  169. {{ lang.ssGeneratingContent }}...</div>
  170. <div class="ai_updateTime" v-if="currentAnalysis">{{ lang.ssUpdateTime }}:{{ currentAnalysis.update_at }}
  171. </div>
  172. </div>
  173. <div class="cq_changeBtn" v-if="props.showData.choiceQuestionListData.length > 1">
  174. <div :class="{ cq_cb_disabled: props.showData.workIndex <= 0 }" @click.stop="changeWorkIndex(0)">
  175. <svg style="transform: rotate(-90deg);" viewBox="0 0 1024 1024" version="1.1" width="200" height="200">
  176. <path
  177. d="M512 330.666667c14.933333 0 29.866667 4.266667 40.533333 14.933333l277.33333399 234.666667c27.733333 23.466667 29.866667 64 8.53333301 89.6-23.466667 27.733333-64 29.866667-89.6 8.53333299L512 477.866667l-236.8 200.53333299c-27.733333 23.466667-68.266667 19.19999999-89.6-8.53333299-23.466667-27.733333-19.19999999-68.266667 8.53333301-89.6l277.33333399-234.666667c10.666667-10.666667 25.6-14.933333 40.533333-14.933333z"
  178. fill=""></path>
  179. </svg>
  180. </div>
  181. <span>{{ props.showData.workIndex + 1 }}/{{ props.showData.choiceQuestionListData.length }}</span>
  182. <div :class="{ cq_cb_disabled: props.showData.workIndex >= props.showData.choiceQuestionListData.length - 1 }"
  183. @click.stop="changeWorkIndex(1)">
  184. <svg style="transform: rotate(90deg);" viewBox="0 0 1024 1024" version="1.1" width="200" height="200">
  185. <path
  186. d="M512 330.666667c14.933333 0 29.866667 4.266667 40.533333 14.933333l277.33333399 234.666667c27.733333 23.466667 29.866667 64 8.53333301 89.6-23.466667 27.733333-64 29.866667-89.6 8.53333299L512 477.866667l-236.8 200.53333299c-27.733333 23.466667-68.266667 19.19999999-89.6-8.53333299-23.466667-27.733333-19.19999999-68.266667 8.53333301-89.6l277.33333399-234.666667c10.666667-10.666667 25.6-14.933333 40.533333-14.933333z"
  187. fill=""></path>
  188. </svg>
  189. </div>
  190. </div>
  191. </div>
  192. <!-- 问答题 -->
  193. <div class="c_t15" v-if="workDetail && workDetail.type === '15' && props.showData">
  194. <div class="c_t15_title">{{ workDetail.json.answerQ }}</div>
  195. <span class="c_t15_type">{{ lang.ssQATest }}</span>
  196. <div class="c_t15_content" v-show="!lookWorkData">
  197. <div class="c_t15_c_item" v-for="item in processedWorkArray" :key="item.id" @click.stop="lookWork(item.id)">
  198. <div class="c_t15_c_i_top">
  199. <span>S</span>
  200. <div>{{ item.name }}</div>
  201. </div>
  202. <div class="c_t15_c_i_bottom">
  203. <span v-html="item.content.answer"></span>
  204. </div>
  205. </div>
  206. </div>
  207. <div class="aiAnalysis" style="margin-top:1rem ;"
  208. v-if="processedWorkArray.length > 0 && lookWorkData === null && workDetail.type === '15'"
  209. @click.stop="clickContent(false)">
  210. <div class="ai_header">
  211. <div class="ai_title">
  212. <svg viewBox="0 0 1024 1024" width="200" height="200">
  213. <path
  214. d="M512 170.666667C323.477333 170.666667 170.666667 323.477333 170.666667 512s152.810667 341.333333 341.333333 341.333333 341.333333-152.810667 341.333333-341.333333S700.522667 170.666667 512 170.666667zM85.333333 512C85.333333 276.352 276.352 85.333333 512 85.333333s426.666667 191.018667 426.666667 426.666667-191.018667 426.666667-426.666667 426.666667S85.333333 747.648 85.333333 512z">
  215. </path>
  216. <path
  217. d="M693.013333 330.986667a42.666667 42.666667 0 0 1 10.304 43.648l-75.413333 226.282666a42.666667 42.666667 0 0 1-26.986667 26.986667l-226.282666 75.413333a42.666667 42.666667 0 0 1-53.973334-53.973333l75.434667-226.261333a42.666667 42.666667 0 0 1 26.986667-26.986667l226.282666-75.413333a42.666667 42.666667 0 0 1 43.648 10.304z m-222.72 139.306666l-41.685333 125.098667 125.077333-41.706667 41.706667-125.077333-125.077333 41.706667z">
  218. </path>
  219. </svg>{{ lang.ssAnalysis }}
  220. </div>
  221. <div class="ai_refresh" :class="{ 'disabled': currentAnalysis && currentAnalysis.loading }"
  222. @click.stop="aiAnalysisRefresh15()">
  223. {{ lang.ssAIGenerate }}
  224. <svg viewBox="0 0 1024 1024" width="200" height="200">
  225. <path
  226. d="M875 483c-33.4 0-60.5 27.1-60.5 60.5v0.1C814.4 710.3 678.8 846 512 846S209.5 710.3 209.5 543.5 345.2 241 512 241c36.8 0 71.7 7.6 104.4 19.7-32 3-57.4 29.1-57.4 61.9 0 34.8 28.2 63 63 63h201.9c34.8 0 63-28.2 63-63V120c0-34.8-28.2-63-63-63s-63 28.2-63 63v81.4C691 150.5 605.2 120 512 120 278.1 120 88.5 309.6 88.5 543.5S278.1 967 512 967s423.5-189.6 423.5-423.5c0-33.4-27.1-60.5-60.5-60.5z">
  227. </path>
  228. </svg>
  229. </div>
  230. </div>
  231. <div class="ai_content" v-if="currentAnalysis && currentAnalysis.json">
  232. {{ currentAnalysis.json.text }}
  233. </div>
  234. <div class="ai_echartsData" v-if="currentAnalysis && currentAnalysis.json.keyword">
  235. <div class="title">{{ lang.ssKeyword }}:</div>
  236. <span v-for="(item, index) in currentAnalysis.json.keyword" :key="index">{{ item }}</span>
  237. <div class="btn" @click.stop="openEchatsDialog()">{{ lang.ssViewKeywordCloud }}</div>
  238. </div>
  239. <div class="generatingContent" v-if="currentAnalysis && currentAnalysis.generatingContent">{{
  240. lang.ssGeneratingContent }}...</div>
  241. <div class="ai_updateTime" v-if="currentAnalysis">{{ lang.ssUpdateTime }}:{{ currentAnalysis.update_at }}
  242. </div>
  243. </div>
  244. <div class="c_t15_workDetail" v-if="lookWorkData" @click.stop="clickContent(false)">
  245. <div class="c_t15_wd_top">
  246. <img src="../../../assets/img/arrow_left.png" @click.stop="lookWork('')" />
  247. <span>S</span>
  248. <div>{{ lookWorkData.name }}</div>
  249. </div>
  250. <div class="c_t15_wd_content">
  251. <span v-html="lookWorkData.content.answer"></span>
  252. <div class="c_t15_wd_c_imageList" v-if="lookWorkData.content.fileList.length > 0">
  253. <img v-for="item in lookWorkData.content.fileList" :src="item.url" :key="item.uploadTime"
  254. @click.stop="lookImage(item.url)" />
  255. </div>
  256. </div>
  257. </div>
  258. </div>
  259. <!-- 拍照 -->
  260. <div class="c_t15" v-if="workDetail && workDetail.type === '79' && props.showData">
  261. <div class="c_t15_title">{{ workDetail.json.answerQ }}</div>
  262. <span class="c_t15_type">{{ lang.ssPhoto }}</span>
  263. <div class="c_t15_content" v-show="!lookWorkData">
  264. <div class="c_t15_c_item" v-for="item in processedWorkArray" :key="item.id"
  265. @click.stop="item.content && item.content.fileList.length > 0 ? lookWork(item.id) : ''">
  266. <div class="c_t15_c_i_top">
  267. <span>S</span>
  268. <div>{{ item.name }}</div>
  269. </div>
  270. <div class="c_t73_c_i_bottom" v-if="item.content && item.content.fileList.length > 0">
  271. <img :src="item.content.fileList[0].url" />
  272. </div>
  273. <div class="c_t73_c_i_bottom" v-else>
  274. <span>{{ lang.ssNoPhoto }}</span>
  275. </div>
  276. </div>
  277. </div>
  278. <div class="c_t79_workDetail" v-if="lookWorkData" @click.stop="clickContent(false)">
  279. <div class="c_t79_wd_top">
  280. <img src="../../../assets/img/arrow_left.png" @click.stop="lookWork('')" />
  281. <span>S</span>
  282. <div>{{ lookWorkData.name }}</div>
  283. </div>
  284. <div class="c_t79_wd_content">
  285. <img :src="lookWorkData.content.fileList[lookWorkIndex].url"
  286. @click.stop="lookImage(lookWorkData.content.fileList[lookWorkIndex].url)" />
  287. </div>
  288. <!-- <div class="nextAndUpBtn" v-if="lookWorkData.content.fileList.length>1">
  289. <span :class="{no_active:lookWorkIndex==0}" @click="changelookWorkIndex(0)">{{ lang.ssPrevP }}</span>
  290. <span :class="{no_active:lookWorkData.content.fileList.length-1<=lookWorkIndex}" @click="changelookWorkIndex(1)">{{ lang.ssNextP }}</span>
  291. </div> -->
  292. <div class="cq_changeBtn" v-if="lookWorkData.content.fileList.length > 1">
  293. <div :class="{ cq_cb_disabled: lookWorkIndex <= 0 }" @click.stop="changelookWorkIndex(0)">
  294. <svg style="transform: rotate(-90deg);" viewBox="0 0 1024 1024" version="1.1" width="200" height="200">
  295. <path
  296. d="M512 330.666667c14.933333 0 29.866667 4.266667 40.533333 14.933333l277.33333399 234.666667c27.733333 23.466667 29.866667 64 8.53333301 89.6-23.466667 27.733333-64 29.866667-89.6 8.53333299L512 477.866667l-236.8 200.53333299c-27.733333 23.466667-68.266667 19.19999999-89.6-8.53333299-23.466667-27.733333-19.19999999-68.266667 8.53333301-89.6l277.33333399-234.666667c10.666667-10.666667 25.6-14.933333 40.533333-14.933333z"
  297. fill=""></path>
  298. </svg>
  299. </div>
  300. <span>{{ lookWorkIndex + 1 }}/{{ lookWorkData.content.fileList.length }}</span>
  301. <div :class="{ cq_cb_disabled: lookWorkIndex >= lookWorkData.content.fileList.length - 1 }"
  302. @click.stop="changelookWorkIndex(1)">
  303. <svg style="transform: rotate(90deg);" viewBox="0 0 1024 1024" version="1.1" width="200" height="200">
  304. <path
  305. d="M512 330.666667c14.933333 0 29.866667 4.266667 40.533333 14.933333l277.33333399 234.666667c27.733333 23.466667 29.866667 64 8.53333301 89.6-23.466667 27.733333-64 29.866667-89.6 8.53333299L512 477.866667l-236.8 200.53333299c-27.733333 23.466667-68.266667 19.19999999-89.6-8.53333299-23.466667-27.733333-19.19999999-68.266667 8.53333301-89.6l277.33333399-234.666667c10.666667-10.666667 25.6-14.933333 40.533333-14.933333z"
  306. fill=""></path>
  307. </svg>
  308. </div>
  309. </div>
  310. </div>
  311. </div>
  312. <!-- AI应用 -->
  313. <div class="c_t72" v-if="props.showData && props.showData.toolType === 72">
  314. <div class="c_t72_title">{{ lang.ssAiApp }}</div>
  315. <span class="c_t72_type">{{ lang.ssAiApp }}</span>
  316. <div class="c_t72_content" v-show="!lookWorkData">
  317. <div class="c_t72_c_item" v-for="item in processedWorkArray" :key="item.id" @click.stop="lookWork(item.id)">
  318. <div class="c_t72_c_i_top">
  319. <span>S</span>
  320. <div>{{ item.name }}</div>
  321. </div>
  322. </div>
  323. </div>
  324. <div class="aiAnalysis" style="margin-top:1rem ;"
  325. v-if="processedWorkArray.length > 0 && lookWorkData === null && props.showData.toolType === 72"
  326. @click.stop="clickContent(false)">
  327. <div class="ai_header">
  328. <div class="ai_title">
  329. <svg viewBox="0 0 1024 1024" width="200" height="200">
  330. <path
  331. d="M512 170.666667C323.477333 170.666667 170.666667 323.477333 170.666667 512s152.810667 341.333333 341.333333 341.333333 341.333333-152.810667 341.333333-341.333333S700.522667 170.666667 512 170.666667zM85.333333 512C85.333333 276.352 276.352 85.333333 512 85.333333s426.666667 191.018667 426.666667 426.666667-191.018667 426.666667-426.666667 426.666667S85.333333 747.648 85.333333 512z">
  332. </path>
  333. <path
  334. d="M693.013333 330.986667a42.666667 42.666667 0 0 1 10.304 43.648l-75.413333 226.282666a42.666667 42.666667 0 0 1-26.986667 26.986667l-226.282666 75.413333a42.666667 42.666667 0 0 1-53.973334-53.973333l75.434667-226.261333a42.666667 42.666667 0 0 1 26.986667-26.986667l226.282666-75.413333a42.666667 42.666667 0 0 1 43.648 10.304z m-222.72 139.306666l-41.685333 125.098667 125.077333-41.706667 41.706667-125.077333-125.077333 41.706667z">
  335. </path>
  336. </svg>{{ lang.ssAnalysis }}
  337. </div>
  338. <div class="ai_refresh" :class="{ 'disabled': currentAnalysis && currentAnalysis.loading }"
  339. @click.stop="aiAnalysisRefresh72()">
  340. {{ lang.ssAIGenerate }}
  341. <svg viewBox="0 0 1024 1024" width="200" height="200">
  342. <path
  343. d="M875 483c-33.4 0-60.5 27.1-60.5 60.5v0.1C814.4 710.3 678.8 846 512 846S209.5 710.3 209.5 543.5 345.2 241 512 241c36.8 0 71.7 7.6 104.4 19.7-32 3-57.4 29.1-57.4 61.9 0 34.8 28.2 63 63 63h201.9c34.8 0 63-28.2 63-63V120c0-34.8-28.2-63-63-63s-63 28.2-63 63v81.4C691 150.5 605.2 120 512 120 278.1 120 88.5 309.6 88.5 543.5S278.1 967 512 967s423.5-189.6 423.5-423.5c0-33.4-27.1-60.5-60.5-60.5z">
  344. </path>
  345. </svg>
  346. </div>
  347. </div>
  348. <div class="ai_content" v-if="currentAnalysis && currentAnalysis.json">
  349. {{ currentAnalysis.json.text }}
  350. </div>
  351. <div class="ai_updateTime" v-if="currentAnalysis">{{ lang.ssUpdateTime }}:{{ currentAnalysis.update_at }}
  352. </div>
  353. </div>
  354. <div class="c_t72_workDetail" v-if="lookWorkData" @click.stop="clickContent(false)">
  355. <div class="c_t72_wd_top">
  356. <img src="../../../assets/img/arrow_left.png" @click.stop="lookWork('')" />
  357. <span>S</span>
  358. <div>{{ lookWorkData.name }}</div>
  359. </div>
  360. <div class="c_t72_wd_content">
  361. <template v-for="(item, index) in lookWorkData.content" :key="item.id">
  362. <div class="messageNodeArea" v-if="item.messages || item.imageUrls">
  363. <div class="messageNode">
  364. <div class="mn_title">{{ lang.ssNodeTitle.replace(/\*/g, String(index + 1)) }}</div>
  365. <div class="mn_content">
  366. <template v-for="(item2, index2) in item.messages" :key="`${index}-${index2}`">
  367. <div>
  368. <div class="na_m_item" v-if="item2.role == 'user' && item2.content">
  369. <div class="na_m_i_name">
  370. {{ item2.sender }}
  371. </div>
  372. <div class="na_m_i_content" v-html="item2.content"></div>
  373. </div>
  374. <div class="na_m_item" v-if="item2.role == 'assistant' && item2.content">
  375. <div class="na_m_i_name aiName">
  376. {{ item2.sender }}
  377. </div>
  378. <div class="na_m_i_content" v-html="item2.content"></div>
  379. </div>
  380. </div>
  381. </template>
  382. <template v-if="item.imageUrls" v-for="(item3, index3) in item.imageUrls"
  383. :key="`${index}-${index3}`">
  384. <div class="na_m_item">
  385. <div class="na_m_i_name">
  386. {{ item.type }}
  387. </div>
  388. <div class="na_m_i_content">
  389. <img @click.stop="lookImage(item3)" style="height: 100px;width: auto;cursor: pointer;"
  390. :src="item3" />
  391. </div>
  392. </div>
  393. </template>
  394. </div>
  395. </div>
  396. </div>
  397. </template>
  398. </div>
  399. </div>
  400. </div>
  401. <!-- H5页面 -->
  402. <div class="c_t73" v-if="props.showData && props.showData.toolType === 73">
  403. <div class="c_t73_title">{{ lang.ssPageImage }}</div>
  404. <span class="c_t73_type">{{ lang.ssHPage }}</span>
  405. <div class="c_t73_content" v-show="!lookWorkData">
  406. <div class="c_t73_c_item" v-for="item in processedWorkArray" :key="item.id" @click.stop="lookWork(item.id)">
  407. <div class="c_t73_c_i_top">
  408. <span>S</span>
  409. <div>{{ item.name }}</div>
  410. </div>
  411. <div class="c_t73_c_i_bottom">
  412. <img :src="item.content" />
  413. </div>
  414. </div>
  415. </div>
  416. <div class="c_t73_workDetail" v-if="lookWorkData" @click.stop="clickContent(false)">
  417. <div class="c_t73_wd_top">
  418. <img src="../../../assets/img/arrow_left.png" @click.stop="lookWork('')" />
  419. <span>S</span>
  420. <div>{{ lookWorkData.name }}</div>
  421. </div>
  422. <div class="c_t73_wd_content">
  423. <img :src="lookWorkData.content" />
  424. </div>
  425. </div>
  426. </div>
  427. </div>
  428. <previewImageTool ref="previewImageToolRef" />
  429. <selectUserDialog ref="selectUserDialogRef" />
  430. <echartsDialog ref="echartsDialogRef" />
  431. </div>
  432. </template>
  433. <script setup lang="ts">
  434. import { computed, ref, watch, onUnmounted, nextTick, onMounted } from 'vue'
  435. import * as echarts from 'echarts'
  436. import previewImageTool from '../../components/tool/previewImageTool.vue'
  437. import MarkdownIt from 'markdown-it'
  438. import useImport from '@/hooks/useImport'
  439. import { lang } from '@/main'
  440. import selectUserDialog from './selectUserDialog.vue'
  441. import echartsDialog from './echartsDialog.vue'
  442. import { chat_stream, chat_no_stream } from '@/tools/aiChat'
  443. import axios from '@/services/config'
  444. const props = defineProps<{
  445. visible: number[];
  446. workIndex: number;
  447. slideWidth: number;
  448. slideHeight: number;
  449. slideIndex: number;
  450. showData: any;
  451. workArray: any[];
  452. courseDetail: any;
  453. userId: string;
  454. workId: string;
  455. cid: string;
  456. }>()
  457. const emit = defineEmits<{
  458. (e: 'update:visible', v: number[]): void;
  459. (e: 'changeWorkIndex', v: number): void;
  460. }>()
  461. const visible = computed({
  462. get: () => props.visible,
  463. set: (v: number[]) => emit('update:visible', v),
  464. })
  465. const workDetail = computed(() => {
  466. if (props.showData) {
  467. return props.showData.workDetail
  468. }
  469. return null
  470. })
  471. // 预览图片组件
  472. const previewImageToolRef = ref<any>(null)
  473. // 选择用户组件
  474. const selectUserDialogRef = ref<any>(null)
  475. // 词云图组件
  476. const echartsDialogRef = ref<any>(null)
  477. // ai分析数据
  478. const aiAnalysisData = ref<Array<any>>([])
  479. const md = new MarkdownIt()
  480. const { getFile } = useImport()
  481. // 判断是否是 URL 链接
  482. const isUrl = (str: string): boolean => {
  483. try {
  484. const url = new URL(str)
  485. return (url.protocol === 'http:' || url.protocol === 'https:') && str.includes('json')
  486. }
  487. catch {
  488. return false
  489. }
  490. }
  491. // 从链接获取文件内容
  492. const loadContentFromUrl = async (url: string): Promise<string> => {
  493. try {
  494. const fileData = await getFile(url)
  495. if (fileData && fileData.data) {
  496. // 将 ArrayBuffer 转为字符串
  497. const uint8Array = new Uint8Array(fileData.data)
  498. const jsonStr = new TextDecoder('utf-8').decode(uint8Array)
  499. return jsonStr
  500. }
  501. return ''
  502. }
  503. catch (error) {
  504. console.error('获取文件内容失败:', error)
  505. return ''
  506. }
  507. }
  508. // 处理单个作业内容
  509. const processWorkContent = async (content: string, toolType: number): Promise<any> => {
  510. let contentToParse = content
  511. // 如果是链接,先获取文件内容
  512. if (isUrl(content)) {
  513. contentToParse = await loadContentFromUrl(content)
  514. }
  515. if (!contentToParse) {
  516. return null
  517. }
  518. try {
  519. if ([45, 15, 78, 79].includes(toolType)) {
  520. return JSON.parse(decodeURIComponent(contentToParse))
  521. }
  522. else if (toolType === 72) {
  523. const parsed = JSON.parse(contentToParse)
  524. if (Array.isArray(parsed)) {
  525. parsed.forEach((item: any) => {
  526. if (item.messages && item.messages.length) {
  527. item.messages.forEach((item2: any) => {
  528. // 如果已经包含html标签则不再渲染
  529. if (
  530. !/^(\s*<[^>]+>.*<\/[^>]+>\s*|<[^>]+\/>\s*)$/s.test(
  531. item2.content.trim()
  532. )
  533. ) {
  534. item2.content = item2.content.replace(/&lt;/g, '<').replace(/&quot;/g, '"').replace(/&gt;/g, '>')
  535. item2.content = md.render(item2.content)
  536. }
  537. })
  538. }
  539. })
  540. }
  541. return parsed
  542. }
  543. return contentToParse
  544. }
  545. catch (error) {
  546. console.error('解析内容失败:', error)
  547. return null
  548. }
  549. }
  550. const processedWorkArray = ref<any[]>([])
  551. // 监听 workArray 和 showData 变化
  552. watch(
  553. () => [props.workArray, props.showData?.toolType],
  554. async () => {
  555. if (props.workArray && props.showData) {
  556. const _workArray = JSON.parse(JSON.stringify(props.workArray))
  557. // 处理每个作业内容
  558. for (const i of _workArray) {
  559. if (i.content) {
  560. const processedContent = await processWorkContent(i.content, props.showData.toolType)
  561. if (processedContent !== null) {
  562. i.content = processedContent
  563. }
  564. }
  565. }
  566. processedWorkArray.value = _workArray
  567. }
  568. else {
  569. processedWorkArray.value = []
  570. }
  571. },
  572. { immediate: true, deep: true }
  573. )
  574. // 关闭对应的作业详细页面
  575. const closeSlideIndex = () => {
  576. visible.value = visible.value.filter((v) => v !== props.slideIndex)
  577. }
  578. // 切换题目
  579. const changeWorkIndex = (type: number) => {
  580. emit('changeWorkIndex', type)
  581. // console.log(props.workIndex, props.showData.choiceQuestionListData.length)
  582. // if (type === 0 && props.workIndex > 0) {
  583. // emit('changeWorkIndex', 0)
  584. // }
  585. // else if (type === 1 && props.workIndex < props.showData.choiceQuestionListData.length) {
  586. // emit('changeWorkIndex', props.workIndex + 1)
  587. // }
  588. }
  589. // 选择题图表div
  590. const echartsArea1 = ref<any>(null)
  591. // 查看的作业详细id
  592. const lookWorkDetail = ref<string>('')
  593. // 查看作业详细的数据
  594. const lookWorkData = computed(() => {
  595. let _result = null
  596. if (lookWorkDetail.value && processedWorkArray.value.length > 0) {
  597. const _workFind = processedWorkArray.value.find(
  598. (i: any) => i.id === lookWorkDetail.value
  599. )
  600. if (_workFind) {
  601. _result = _workFind
  602. }
  603. }
  604. return _result
  605. })
  606. // 查看图片
  607. const lookImage = (url: string) => {
  608. if (previewImageToolRef.value) {
  609. previewImageToolRef.value.previewImage(url)
  610. }
  611. }
  612. const lookWorkIndex = ref<number>(0)
  613. // 查看作业
  614. const lookWork = (id: string) => {
  615. lookWorkIndex.value = 0
  616. lookWorkDetail.value = id
  617. }
  618. // 切换查看作业图片
  619. const changelookWorkIndex = (type: number) => {
  620. if (type === 0 && lookWorkIndex.value > 0) {
  621. lookWorkIndex.value = lookWorkIndex.value - 1
  622. }
  623. else if (type === 1 && lookWorkIndex.value < lookWorkData.value.content.fileList.length - 1) {
  624. lookWorkIndex.value = lookWorkIndex.value + 1
  625. }
  626. }
  627. // 选择题图表实例
  628. const myChart = ref<any>(null)
  629. // resize防抖定时器
  630. let resizeTimer: ReturnType<typeof setTimeout> | null = null
  631. // 处理ECharts resize
  632. const handleChartResize = () => {
  633. // 清除之前的定时器
  634. if (resizeTimer) {
  635. clearTimeout(resizeTimer)
  636. }
  637. resizeTimer = setTimeout(() => {
  638. nextTick(() => {
  639. if (
  640. myChart.value &&
  641. typeof myChart.value.resize === 'function' &&
  642. !myChart.value.isDisposed()
  643. ) {
  644. try {
  645. myChart.value.resize()
  646. }
  647. catch (e) {
  648. // console.error('myChart resize error:', e)
  649. // 如果resize失败,重新初始化图表
  650. if (
  651. props.showData &&
  652. props.showData.workDetail &&
  653. (props.showData.workDetail.type === '45' || props.showData.workDetail.type === '78')
  654. ) {
  655. setEchartsArea1()
  656. }
  657. }
  658. }
  659. })
  660. }, 200) // 防抖延迟200ms
  661. }
  662. // 设置选择题图表
  663. const setEchartsArea1 = () => {
  664. // 如果已有实例且未销毁,先销毁
  665. if (myChart.value && !myChart.value.isDisposed()) {
  666. myChart.value.dispose()
  667. }
  668. if (echartsArea1.value) {
  669. myChart.value = echarts.init(echartsArea1.value)
  670. }
  671. else {
  672. myChart.value = null
  673. }
  674. if (myChart.value) {
  675. const _work =
  676. props.showData.choiceQuestionListData[props.showData.workIndex]
  677. console.log('_work', _work)
  678. // 修正版,处理xAxis.data内为图片对象的case,formatter始终只拿到src或自定义label,保证无[object Object]问题
  679. const option = {
  680. tooltip: {
  681. show: false, // 禁用鼠标移动到柱体时的内容显示
  682. },
  683. yAxis: {
  684. show: false, // 不显示最左边的y轴
  685. },
  686. xAxis: {
  687. data: [],
  688. axisLabel: {
  689. color: 'rgba(0, 0, 0, 0.9)',
  690. fontWeight: 600,
  691. fontSize: 17,
  692. lineHeight: 20,
  693. interval: 0,
  694. formatter: function (value: any, idx: number) {
  695. // 如果是字符串且格式为JSON(图片),则解析处理
  696. if (typeof value === 'string') {
  697. try {
  698. const obj = JSON.parse(value)
  699. if (obj && typeof obj === 'object' && obj.imgType && obj.src) {
  700. return '{img' + idx + '|}'
  701. }
  702. }
  703. catch (e) {
  704. // 非JSON字符串,直接返回
  705. // 如果文本文字超过8个字,换行
  706. if (typeof value === 'string') {
  707. // 判断value是否全是英文
  708. const isAllEnglish = /^[a-zA-Z0-9\s\p{P}]+$/u.test(value)
  709. let displayValue = value
  710. const maxLength = isAllEnglish ? 30 : 20
  711. const lineLength = isAllEnglish ? 16 : 8
  712. if (value.length > maxLength) {
  713. displayValue = value.substr(0, maxLength) + '...'
  714. }
  715. // 换行处理
  716. let output = ''
  717. for (let i = 0; i < displayValue.length; i += lineLength) {
  718. output += displayValue.substr(i, lineLength)
  719. if (i + lineLength < displayValue.length) {
  720. output += '\n'
  721. }
  722. }
  723. return output
  724. }
  725. return value
  726. }
  727. return value
  728. }
  729. // 兼容老格式(容错):value本身是对象,并有图片信息
  730. if (
  731. value &&
  732. typeof value === 'object' &&
  733. value.imgType &&
  734. value.src
  735. ) {
  736. return '{img' + idx + '|}'
  737. }
  738. // 其他类型直接空
  739. return ''
  740. },
  741. rich: (() => {
  742. // 动态生成所有图片的 rich 格式
  743. const richObj: any = {}
  744. _work.choiceUser.forEach((op: any, idx: number) => {
  745. if (
  746. op.option &&
  747. typeof op.option === 'object' &&
  748. op.option.imgType &&
  749. op.option.src
  750. ) {
  751. richObj['img' + idx] = {
  752. height: 40,
  753. width: 40,
  754. align: 'center',
  755. backgroundColor: {
  756. image: op.option.src,
  757. },
  758. }
  759. }
  760. })
  761. return richObj
  762. })(),
  763. },
  764. },
  765. series: [
  766. {
  767. name: '',
  768. type: 'bar',
  769. data: [],
  770. barMaxWidth: 80, // 柱体最宽80px,数量多则自适应
  771. itemStyle: {
  772. color: 'rgba(252, 207, 0, 1)',
  773. },
  774. label: {
  775. show: true,
  776. position: 'top',
  777. color: 'rgba(116, 139, 115, 1)',
  778. fontSize: 22,
  779. fontWeight: 500,
  780. lineHeight: 24,
  781. },
  782. },
  783. ],
  784. }
  785. _work.choiceUser.forEach((i: any, idx: number) => {
  786. // 如果是图片,存src对象,否则为字符串
  787. if (
  788. i.option &&
  789. typeof i.option === 'object' &&
  790. i.option.imgType &&
  791. i.option.src
  792. ) {
  793. (option.xAxis.data as any[]).push(
  794. JSON.stringify({ imgType: i.option.imgType, src: i.option.src })
  795. ) // 仅保留相关字段
  796. }
  797. else if (typeof i.option === 'string') {
  798. (option.xAxis.data as any[]).push(i.option)
  799. }
  800. else {
  801. (option.xAxis.data as any[]).push('')
  802. }
  803. (option.series[0].data as any[]).push(i.user.length)
  804. })
  805. // console.log(option)
  806. // {
  807. // title: {
  808. // text: 'ECharts 入门示例'
  809. // },
  810. // tooltip: {},
  811. // xAxis: {
  812. // data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
  813. // },
  814. // yAxis: {},
  815. // series: [
  816. // {
  817. // name: '销量',
  818. // type: 'bar',
  819. // data: [5, 20, 36, 10, 10, 20]
  820. // }
  821. // ]
  822. // }
  823. myChart.value.setOption(option)
  824. myChart.value.off('click')
  825. myChart.value.on('click', (params: any) => {
  826. const idx = params.dataIndex
  827. const selectedOption = _work.choiceUser[idx]
  828. if (selectedOption && selectUserDialogRef.value) {
  829. // console.log(selectedOption)
  830. console.log('selectedOption', selectedOption)
  831. selectUserDialogRef.value.open(`${lang.ssSelectUser.replace('{a}', '<span>' + selectedOption.index + '</span>')}`, selectedOption)
  832. }
  833. })
  834. }
  835. }
  836. // 获取分析
  837. const getAnalysis = () => {
  838. if (!props.workId) {
  839. return
  840. }
  841. console.log('props.workId', props.workId)
  842. const params = {
  843. pid: props.workId + (props.cid ? ',' + props.cid : ''),
  844. }
  845. axios.get('https://pbl.cocorobo.cn/api/pbl/select_pptAnalysisByPid?pid=' + params.pid).then(res => {
  846. const data = res[0]
  847. if (data.length) {
  848. data.forEach((item: any) => {
  849. try {
  850. item.json = JSON.parse(item.json)
  851. }
  852. catch (error) {
  853. item.json = { text: item.json, echartsData: '' }
  854. }
  855. })
  856. aiAnalysisData.value = data
  857. }
  858. else {
  859. aiAnalysisData.value = []
  860. }
  861. }).catch(err => {
  862. console.log('get_pptAnalysis_err', err)
  863. })
  864. }
  865. // 监听选择题数据变化
  866. watch(
  867. () => props.showData,
  868. (newVal, oldVal) => {
  869. console.log('发生变化,showData')
  870. if (
  871. newVal &&
  872. newVal.choiceQuestionListData[newVal.workIndex] &&
  873. (props.showData.workDetail.type === '45' || props.showData.workDetail.type === '78')
  874. ) {
  875. if (
  876. oldVal &&
  877. newVal.choiceQuestionListData[newVal.workIndex] &&
  878. oldVal.choiceQuestionListData[oldVal.workIndex]
  879. ) {
  880. if (
  881. JSON.stringify(newVal.choiceQuestionListData[newVal.workIndex]) !==
  882. JSON.stringify(oldVal.choiceQuestionListData[oldVal.workIndex])
  883. ) {
  884. setEchartsArea1()
  885. }
  886. }
  887. }
  888. else {
  889. myChart.value = null
  890. }
  891. // console.log('newVal', newVal)
  892. // if(newVal && newVal.workDetail && newVal.workDetail.id){
  893. // getAnalysis()
  894. // }
  895. // getAnalysis()
  896. },
  897. { immediate: true, deep: true }
  898. )
  899. // 监听作业变化
  900. watch(
  901. () => props.showData?.choiceQuestionListData,
  902. (newVal, oldVal) => {
  903. console.log('choiceQuestionListData变化了')
  904. if (
  905. (newVal || newVal === 0) &&
  906. props.showData.workDetail &&
  907. (props.showData.workDetail.type === '45' || props.showData.workDetail.type === '78')
  908. ) {
  909. if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
  910. setEchartsArea1()
  911. }
  912. else {
  913. console.log('choiceQuestionListData没有变化')
  914. }
  915. }
  916. else {
  917. myChart.value = null
  918. }
  919. },
  920. { deep: true }
  921. )
  922. // 监听作业变化
  923. watch(
  924. () => props.showData?.workIndex,
  925. (newVal) => {
  926. if (
  927. (newVal || newVal === 0) &&
  928. props.showData.workDetail &&
  929. (props.showData.workDetail.type === '45' || props.showData.workDetail.type === '78')
  930. ) {
  931. setEchartsArea1()
  932. }
  933. else {
  934. myChart.value = null
  935. }
  936. }
  937. )
  938. // 监听echartsArea1变化
  939. watch(
  940. () => echartsArea1.value,
  941. (newVal) => {
  942. if (
  943. newVal &&
  944. props.showData &&
  945. props.showData.workDetail &&
  946. (props.showData.workDetail.type === '45' || props.showData.workDetail.type === '78')
  947. ) {
  948. setEchartsArea1()
  949. }
  950. else {
  951. myChart.value = null
  952. }
  953. }
  954. )
  955. // 监听页面宽度变化
  956. watch(
  957. () => props.slideWidth,
  958. (newVal) => {
  959. if (
  960. newVal &&
  961. props.showData &&
  962. props.showData.workDetail &&
  963. (props.showData.workDetail.type === '45' || props.showData.workDetail.type === '78')
  964. ) {
  965. handleChartResize()
  966. }
  967. }
  968. )
  969. // 查看未提交学生
  970. const viewUnsubmittedStudents = () => {
  971. selectUserDialogRef.value.open(lang.ssSubmitStatus, { user: props.showData.unsubmittedStudents.map((item: any) => item.name), notFiledUser: props.showData.unsubmittedStudents.map((item: any) => item.name), isSubmitUser: props.workArray.map((item: any) => item.name) })
  972. // if (props.unsubmittedStudents.length > 0) {
  973. // unsubmittedStudentsDialogRef.value.open(props.unsubmittedStudents)
  974. // }
  975. }
  976. // ai生成选择题分析 选择题
  977. const aiAnalysisRefresh45 = () => {
  978. const _work = props.showData.choiceQuestionListData[props.showData.workIndex]
  979. const msg = `# CONTEXT #
  980. 你是K-12阶段的AI教育课堂分析助手,基于上传的课件、逐字稿,以及当页的学生答题数据(选择题/问答题/智能体对话)进行智能分析。
  981. # OBJECTIVE #
  982. 输出当前学生答题的分析报告:整体表现、核心发现(共性问题/误区)、教学优化(改进方向),为教师提供教学策略的建议和支持。
  983. #INPUT#
  984. 课程数据:
  985. - 课程名称:${props.courseDetail.title}
  986. - 课程学科:${props.courseDetail.name}
  987. 当前页面答题数据(选择题):【分析重点】
  988. - 选择题题目:${_work.teststitle}
  989. - 选项数据:${JSON.stringify(_work.choiceUser)}
  990. - 题目图片:${_work.timuList.lenght ? _work.timuList[0].src : ''}
  991. - 未提交学生:${JSON.stringify(props.showData.unsubmittedStudents.map((item: any) => item.name))}
  992. # ANALYSIS RULES #
  993. 1. **问题定位**:明确指出哪个知识点/概念/步骤掌握不佳
  994. 2. **建议具体**:给出可执行的教学动作(如“增加XX实例演练”“补充XX对比图”)
  995. # RESPONSE #
  996. 采用段落叙述,数据量化呈现,突出可操作建议,严格控制输出为80词内。采用三段式论述:
  997. 1. 整体表现-1句话
  998. 2. 核心发现-1-2句,指出共性问题+典型案例
  999. 3. 改进建议-1句话,提出具体教学动作
  1000. # EXAMPLES #
  1001. 样例:
  1002. 选择题正确率62%,核心概念“机器学习三步骤”(输入数据→训练模型→预测结果)掌握尚可,但“训练与预测区分”混淆率达38%;建议强化训练vs预测对比教学。`
  1003. if (!currentAnalysis.value) {
  1004. aiAnalysisData.value.push({
  1005. pid: props.workId + (props.cid ? ',' + props.cid : ''),
  1006. index: props.showData.workIndex,
  1007. loading: true,
  1008. generatingContent: true,
  1009. json: { text: '', echartsData: '' },
  1010. noEnd: true,
  1011. update_at: '',
  1012. create_at: '',
  1013. })
  1014. }
  1015. else {
  1016. aiAnalysisData.value.find((item: any) => {
  1017. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1018. }).loading = true
  1019. aiAnalysisData.value.find((item: any) => {
  1020. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1021. }).json = { text: '', echartsData: '' }
  1022. }
  1023. chat_stream(msg, 'a7741704-ba56-40b7-a6b8-62a423ef9376', props.userId, lang.lang, (event) => {
  1024. if (event.type === 'message') {
  1025. aiAnalysisData.value.find((item: any) => {
  1026. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1027. }).json.text = event.data
  1028. aiAnalysisData.value.find((item: any) => {
  1029. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1030. }).loading = false
  1031. }
  1032. else if (event.type === 'messageEnd') {
  1033. aiAnalysisData.value.find((item: any) => {
  1034. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1035. }).json.text = event.data
  1036. aiAnalysisData.value.find((item: any) => {
  1037. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1038. }).noEnd = false
  1039. aiAnalysisData.value.find((item: any) => {
  1040. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1041. }).update_at = new Date().toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }).replace(/\//g, '-')
  1042. saveAnalysis()
  1043. }
  1044. }).catch(err => {
  1045. console.log('err', err)
  1046. })
  1047. }
  1048. // ai生成投票分析 投票
  1049. const aiAnalysisRefresh78 = () => {
  1050. const _work = props.showData.choiceQuestionListData[props.showData.workIndex]
  1051. const msg = `# CONTEXT #
  1052. 你是K-12阶段的AI教育课堂分析助手,基于上传的课件、逐字稿,以及当页的学生答题数据(选择题/问答题/智能体对话/投票)进行智能分析。
  1053. # OBJECTIVE #
  1054. 输出当前学生答题的分析报告:整体表现、核心发现(共性问题/误区)、教学优化(改进方向),为教师提供教学策略的建议和支持。
  1055. #INPUT#
  1056. 课程数据:
  1057. - 课程名称:${props.courseDetail.title}
  1058. - 课程学科:${props.courseDetail.name}
  1059. 当前页面答题数据(投票):【分析重点】
  1060. - 投票题目:${_work.teststitle}
  1061. - 选项数据:${JSON.stringify(_work.choiceUser)}
  1062. - 题目图片:${_work.timuList.lenght ? _work.timuList[0].src : ''}
  1063. - 未提交学生:${JSON.stringify(props.showData.unsubmittedStudents.map((item: any) => item.name))}
  1064. # ANALYSIS RULES #
  1065. 1. **问题定位**:明确指出哪个知识点/概念/步骤掌握不佳
  1066. 2. **建议具体**:给出可执行的教学动作(如“增加XX实例演练”“补充XX对比图”)
  1067. # RESPONSE #
  1068. 采用段落叙述,数据量化呈现,突出可操作建议,严格控制输出为80词内。采用三段式论述:
  1069. 1. 整体表现-1句话
  1070. 2. 核心发现-1-2句,指出共性问题+典型案例
  1071. 3. 改进建议-1句话,提出具体教学动作
  1072. # EXAMPLES #
  1073. 样例:
  1074. 选择题正确率62%,核心概念“机器学习三步骤”(输入数据→训练模型→预测结果)掌握尚可,但“训练与预测区分”混淆率达38%;建议强化训练vs预测对比教学。`
  1075. if (!currentAnalysis.value) {
  1076. aiAnalysisData.value.push({
  1077. pid: props.workId + (props.cid ? ',' + props.cid : ''),
  1078. index: props.showData.workIndex,
  1079. loading: true,
  1080. generatingContent: true,
  1081. json: { text: '', echartsData: '' },
  1082. noEnd: true,
  1083. update_at: '',
  1084. create_at: '',
  1085. })
  1086. }
  1087. else {
  1088. aiAnalysisData.value.find((item: any) => {
  1089. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1090. }).loading = true
  1091. aiAnalysisData.value.find((item: any) => {
  1092. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1093. }).json = { text: '', echartsData: '' }
  1094. }
  1095. chat_stream(msg, 'a7741704-ba56-40b7-a6b8-62a423ef9376', props.userId, lang.lang, (event) => {
  1096. if (event.type === 'message') {
  1097. aiAnalysisData.value.find((item: any) => {
  1098. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1099. }).json.text = event.data
  1100. aiAnalysisData.value.find((item: any) => {
  1101. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1102. }).loading = false
  1103. }
  1104. else if (event.type === 'messageEnd') {
  1105. aiAnalysisData.value.find((item: any) => {
  1106. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1107. }).json.text = event.data
  1108. aiAnalysisData.value.find((item: any) => {
  1109. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1110. }).noEnd = false
  1111. aiAnalysisData.value.find((item: any) => {
  1112. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1113. }).update_at = new Date().toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }).replace(/\//g, '-')
  1114. saveAnalysis()
  1115. }
  1116. }).catch(err => {
  1117. console.log('err', err)
  1118. })
  1119. }
  1120. // 问答题
  1121. const aiAnalysisRefresh15 = () => {
  1122. let flag = 0
  1123. const msg = `# CONTEXT #
  1124. 你是K-12阶段的AI教育课堂分析助手,基于上传的课件、逐字稿,以及当页的学生答题数据(选择题/问答题/智能体对话)进行智能分析。
  1125. # OBJECTIVE #
  1126. 输出当前学生答题的分析报告:整体表现、核心发现(共性问题/误区)、教学优化(改进方向),为教师提供教学策略的建议和支持。
  1127. #INPUT#
  1128. 课程数据:
  1129. - 课程名称:${props.courseDetail.title}
  1130. - 课程学科:${props.courseDetail.name}
  1131. 当前页面答题数据(问答题):【分析重点】
  1132. - 问答题题目:${props.showData.workDetail.json.answerQ}
  1133. - 回答数据:${JSON.stringify(processedWorkArray.value.map((i) => ({ user: i.name, answer: i.content.answer })))}
  1134. - 未提交学生:${JSON.stringify(props.showData.unsubmittedStudents.map((item: any) => item.name))}
  1135. # ANALYSIS RULES #
  1136. 1. **问题定位**:明确指出哪个知识点/概念/步骤掌握不佳
  1137. 2. **建议具体**:给出可执行的教学动作(如“增加XX实例演练”“补充XX对比图”)
  1138. # RESPONSE #
  1139. 采用段落叙述,数据量化呈现,突出可操作建议,严格控制输出为80词内。采用三段式论述:
  1140. 1. 整体表现-1句话
  1141. 2. 核心发现-1-2句,指出共性问题+典型案例
  1142. 3. 改进建议-1句话,提出具体教学动作
  1143. # EXAMPLES #
  1144. 样例:
  1145. 30人中15人提交问答题(参与率50%),核心概念“同理心地图”掌握薄弱。发现学生13在智能体对话中6次答“不知道”,需单独辅导设计思维基础概念。建议课程增加POV框架实例演练,强化痛点识别能力训练。`
  1146. if (!currentAnalysis.value) {
  1147. aiAnalysisData.value.push({
  1148. pid: props.workId + (props.cid ? ',' + props.cid : ''),
  1149. index: props.showData.workIndex,
  1150. loading: true,
  1151. generatingContent: true,
  1152. json: { text: '', echartsData: '' },
  1153. noEnd: true,
  1154. update_at: '',
  1155. create_at: '',
  1156. })
  1157. }
  1158. else {
  1159. aiAnalysisData.value.find((item: any) => {
  1160. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1161. }).loading = true
  1162. aiAnalysisData.value.find((item: any) => {
  1163. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1164. }).json = { text: '', echartsData: '' }
  1165. aiAnalysisData.value.find((item: any) => {
  1166. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1167. }).generatingContent = true
  1168. }
  1169. getWordCloud15().then((res) => {
  1170. flag += 1
  1171. aiAnalysisData.value.find((item: any) => {
  1172. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1173. }).generatingContent = false
  1174. if (flag == 2) {
  1175. saveAnalysis()
  1176. }
  1177. })
  1178. chat_stream(msg, 'a7741704-ba56-40b7-a6b8-62a423ef9376', props.userId, lang.lang, (event) => {
  1179. console.log(event)
  1180. if (event.type === 'message') {
  1181. aiAnalysisData.value.find((item: any) => {
  1182. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1183. }).json.text = event.data
  1184. aiAnalysisData.value.find((item: any) => {
  1185. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1186. }).loading = false
  1187. }
  1188. else if (event.type === 'messageEnd') {
  1189. aiAnalysisData.value.find((item: any) => {
  1190. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1191. }).json.text = event.data
  1192. aiAnalysisData.value.find((item: any) => {
  1193. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1194. }).noEnd = false
  1195. aiAnalysisData.value.find((item: any) => {
  1196. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1197. }).update_at = new Date().toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }).replace(/\//g, '-')
  1198. flag += 1
  1199. if (flag == 2) {
  1200. saveAnalysis()
  1201. }
  1202. }
  1203. }).catch(err => {
  1204. console.log('err', err)
  1205. })
  1206. }
  1207. // 打开词云图弹窗
  1208. const openEchatsDialog = () => {
  1209. if (echartsDialogRef.value && currentAnalysis.value.json.echartsData) {
  1210. echartsDialogRef.value.open(lang.ssKeywordCloud, currentAnalysis.value.json.echartsData)
  1211. }
  1212. }
  1213. // 问答题获取词云图与关键词
  1214. const getWordCloud15 = () => {
  1215. return new Promise((resolve,) => {
  1216. const msg = `## 任务
  1217. 请针对文本中学生提交的问答题回答内容进行深度分析,提炼出 10 - 30 个核心关键词,用于绘制词云图。
  1218. ## 提取准则
  1219. 1. 聚焦内容主体:仅从学生的具体回答文本中提取关键词。
  1220. 2. 严格排除杂质:禁止提取任何属于系统元数据或固定格式的词汇,包括但不限于:“课程数据”、“学生姓名”、“回答结果”、“课程标题”、“提交时间”、“作业名称”、“分数”等。
  1221. 3. 语义去重:将意思相近的词进行合并(例如“高效”与“效率高”),保留最具代表性的词条。
  1222. 4. 涵盖核心:关键词应准确反映学生回答中的核心观点、关键知识点、高频论据或情感倾向。
  1223. ## 任务要求
  1224. 1. 词频统计:计算每个有效关键字在回答内容中出现的频率。
  1225. 2. 词汇大小:根据词频,确定每个关键字在词云中的权重。词频越高,数值越大,范围 1 - 100。
  1226. 3. 输出格式:请严格按照 JSON 格式输出,包含关键词、词频及对应的词汇大小。
  1227. ## 文本
  1228. 课程数据:
  1229. - 课程名称:${props.courseDetail.title}
  1230. - 课程学科:${props.courseDetail.name}
  1231. 当前页面答题数据(问答题):【分析重点】
  1232. - 问答题题目:${props.showData.workDetail.json.answerQ}
  1233. - 回答数据:${JSON.stringify(processedWorkArray.value.map((i) => ({ answer: i.content.answer })))}
  1234. ## 输出示例
  1235. {"tooltip":{"show":false},"series":[{"type":"wordCloud","sizeRange":[14,38],"rotationRange":[0,0],"keepAspect":false,"shape":"circle","left":"center","top":"center","right":null,"bottom":null,"width":"100%","height":"100%","rotationStep":20,"data":[{"value":"词汇大小,数值范围1-100","name":"词汇","textStyle":{"color":"词汇颜色(16进制)"}},{"value":"词汇大小,数值范围1-100","name":"词汇","textStyle":{"color":"(16进制)"}}]}]}`
  1236. chat_no_stream(msg, 'a7741704-ba56-40b7-a6b8-62a423ef9376', props.userId, lang.lang).promise.then((res) => {
  1237. aiAnalysisData.value.find((item: any) => {
  1238. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1239. }).json.echartsData = JSON.parse(res)
  1240. resolve(1)
  1241. }).catch(err => {
  1242. console.log('err', err)
  1243. resolve(0)
  1244. })
  1245. })
  1246. }
  1247. // ai应用
  1248. const aiAnalysisRefresh72 = async () => {
  1249. let chatMsg = ``
  1250. console.log('processedWorkArray.value', processedWorkArray.value)
  1251. processedWorkArray.value.forEach((i) => {
  1252. if (typeof i.content === 'object') {
  1253. i.content.forEach(j => {
  1254. if (j.messages) {
  1255. j.messages.forEach((a) => {
  1256. chatMsg += `\n${a.sender}:
  1257. ${a.content}\n`
  1258. })
  1259. }
  1260. if (j.imageUrls) {
  1261. j.imageUrls.forEach((a) => {
  1262. chatMsg += `\n${a}\n`
  1263. })
  1264. }
  1265. })
  1266. }
  1267. })
  1268. // - 未提交学生:${JSON.stringify(props.showData.unsubmittedStudents.map((item: any) => item.name))}
  1269. const msg = `# CONTEXT #
  1270. 你是K-12阶段的AI教育课堂分析助手,基于上传的课件、逐字稿,以及当页的学生答题数据(选择题/问答题/智能体对话)进行智能分析。
  1271. # OBJECTIVE #
  1272. 输出当前学生答题的分析报告:整体表现、核心发现(共性问题/误区)、教学优化(改进方向),为教师提供教学策略的建议和支持。
  1273. #INPUT#
  1274. 课程数据:
  1275. - 课程名称:${props.courseDetail.title}
  1276. - 课程学科:${props.courseDetail.name}
  1277. 当前页面答题数据(问答题):【分析重点】
  1278. - AI应用
  1279. - 对话数据:${chatMsg}
  1280. # ANALYSIS RULES #
  1281. 1. **问题定位**:明确指出哪个知识点/概念/步骤掌握不佳
  1282. 2. **建议具体**:给出可执行的教学动作(如“增加XX实例演练”“补充XX对比图”)
  1283. # RESPONSE #
  1284. 采用段落叙述,数据量化呈现,突出可操作建议,严格控制输出为80词内。采用三段式论述:
  1285. 1. 整体表现-1句话
  1286. 2. 核心发现-1-2句,指出共性问题+典型案例
  1287. 3. 改进建议-1句话,提出具体教学动作
  1288. # EXAMPLES #
  1289. 样例:
  1290. 智能体对话显示学生对“模型训练”概念模糊,多次询问“为什么不能直接告诉机器答案”。针对概念混淆学生,补充“人类学习类比”相关解释,巩固“从数据中学习规律”核心认知。`
  1291. console.log('cs', msg)
  1292. if (!currentAnalysis.value) {
  1293. aiAnalysisData.value.push({
  1294. pid: props.workId + (props.cid ? ',' + props.cid : ''),
  1295. index: props.showData.workIndex,
  1296. loading: true,
  1297. json: { text: '', echartsData: '' },
  1298. noEnd: true,
  1299. update_at: '',
  1300. create_at: '',
  1301. })
  1302. }
  1303. else {
  1304. aiAnalysisData.value.find((item: any) => {
  1305. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1306. }).loading = true
  1307. aiAnalysisData.value.find((item: any) => {
  1308. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1309. }).json = { text: '', echartsData: '' }
  1310. }
  1311. chat_stream(msg, 'a7741704-ba56-40b7-a6b8-62a423ef9376', props.userId, lang.lang, (event) => {
  1312. if (event.type === 'message') {
  1313. aiAnalysisData.value.find((item: any) => {
  1314. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1315. }).json.text = event.data
  1316. aiAnalysisData.value.find((item: any) => {
  1317. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1318. }).loading = false
  1319. }
  1320. else if (event.type === 'messageEnd') {
  1321. aiAnalysisData.value.find((item: any) => {
  1322. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1323. }).json.text = event.data
  1324. aiAnalysisData.value.find((item: any) => {
  1325. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1326. }).noEnd = false
  1327. aiAnalysisData.value.find((item: any) => {
  1328. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1329. }).update_at = new Date().toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }).replace(/\//g, '-')
  1330. saveAnalysis()
  1331. }
  1332. }).catch(err => {
  1333. console.log('err', err)
  1334. })
  1335. }
  1336. // 当前分析
  1337. const currentAnalysis = computed(() => {
  1338. const _result = aiAnalysisData.value.find((item: any) => {
  1339. return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
  1340. })
  1341. if (_result?.json?.echartsData) {
  1342. _result.json.keyword = _result.json.echartsData?.series?.[0]?.data?.slice(0, 5).map((item: any) => item.name)
  1343. }
  1344. if (_result) {
  1345. return _result
  1346. }
  1347. return null
  1348. })
  1349. // 保存分析
  1350. const saveAnalysis = () => {
  1351. if (!currentAnalysis.value) {
  1352. return
  1353. }
  1354. const params = [{
  1355. pid: props.workId + (props.cid ? ',' + props.cid : ''),
  1356. idx: props.showData.workIndex,
  1357. json: JSON.stringify(currentAnalysis.value.json),
  1358. }]
  1359. console.log(params)
  1360. axios.post('https://pbl.cocorobo.cn/api/pbl/insert_pptAnalysis', params).then(res => {
  1361. if (res == 1) {
  1362. console.log('保存成功')
  1363. }
  1364. }).catch(err => {
  1365. console.log('insert_pptAnalysis_err', err)
  1366. })
  1367. }
  1368. // 点击边框
  1369. const clickContent = (flag: boolean) => {
  1370. if (flag && lookWorkDetail.value && workDetail.value?.type !== '45' && workDetail.value?.type !== '78') {
  1371. lookWork('')
  1372. }
  1373. }
  1374. // 监听 props.showData.workDetail.id 变化
  1375. watch(
  1376. () => props.showData?.workDetail,
  1377. (newId, oldId) => {
  1378. getAnalysis()
  1379. },
  1380. { immediate: true }
  1381. )
  1382. // 组件卸载时清理ECharts实例
  1383. onUnmounted(() => {
  1384. // 清除定时器
  1385. if (resizeTimer) {
  1386. clearTimeout(resizeTimer)
  1387. resizeTimer = null
  1388. }
  1389. // 销毁ECharts实例
  1390. if (myChart.value && !myChart.value.isDisposed()) {
  1391. myChart.value.dispose()
  1392. myChart.value = null
  1393. }
  1394. })
  1395. </script>
  1396. <style lang="scss" scoped>
  1397. .choiceQuestionDetailDialog {
  1398. background: none;
  1399. position: relative;
  1400. width: 100%;
  1401. height: 100%;
  1402. z-index: 1;
  1403. .content {
  1404. width: 100%;
  1405. height: 100%;
  1406. position: relative;
  1407. background: #fff;
  1408. box-sizing: border-box;
  1409. padding: 40px;
  1410. overflow: auto;
  1411. .closeIcon {
  1412. position: absolute;
  1413. right: 20px;
  1414. top: 20px;
  1415. cursor: pointer;
  1416. width: 20px;
  1417. height: 20px;
  1418. img {
  1419. width: 100%;
  1420. height: 100%;
  1421. }
  1422. }
  1423. .c_t45 {
  1424. width: 100%;
  1425. min-height: 100%;
  1426. display: flex;
  1427. // align-items: center;
  1428. flex-direction: column;
  1429. height: auto;
  1430. .c_t45_title {
  1431. color: rgba(0, 0, 0, 0.9);
  1432. font-weight: 600;
  1433. font-size: 24px;
  1434. line-height: 24px;
  1435. position: relative;
  1436. width: 100%;
  1437. display: flex;
  1438. flex-direction: column;
  1439. // align-items: center;
  1440. // justify-content: center;
  1441. user-select: none;
  1442. gap: .4rem;
  1443. &>div {
  1444. max-width: calc(100%);
  1445. }
  1446. &>span {
  1447. position: absolute;
  1448. top: 20px;
  1449. cursor: pointer;
  1450. &:nth-of-type(1) {
  1451. left: 0;
  1452. }
  1453. &:nth-of-type(2) {
  1454. right: 0;
  1455. }
  1456. }
  1457. .c_t45_t_btn_noActive {
  1458. color: #CCCCCC;
  1459. }
  1460. .c_t45_msg {
  1461. display: flex;
  1462. align-items: center;
  1463. font-size: .9rem;
  1464. font-weight: 400;
  1465. gap: 1rem;
  1466. &>span {
  1467. text-decoration: underline;
  1468. cursor: pointer;
  1469. }
  1470. }
  1471. }
  1472. .c_t45_img {
  1473. max-width: 200px;
  1474. max-height: 200px;
  1475. object-fit: cover;
  1476. margin-top: 20px;
  1477. }
  1478. .c_t45_type {
  1479. font-weight: 400;
  1480. font-size: 15px;
  1481. line-height: 21px;
  1482. letter-spacing: 0.5px;
  1483. color: rgba(0, 0, 0, 1);
  1484. opacity: 0.5;
  1485. margin-top: 20px;
  1486. }
  1487. .c_t45_echarts {
  1488. width: 100%;
  1489. max-width: 100%;
  1490. flex: 1;
  1491. min-height: 400px;
  1492. display: flex;
  1493. align-items: center;
  1494. box-sizing: border-box;
  1495. &>div {
  1496. width: 100%;
  1497. height: 400px;
  1498. }
  1499. }
  1500. .cq_changeBtn {
  1501. display: flex;
  1502. align-items: center;
  1503. gap: 1.5rem;
  1504. margin: 1rem auto;
  1505. &>div {
  1506. padding: .6rem;
  1507. border-radius: .5rem;
  1508. border: solid 2px #F6C82B;
  1509. display: flex;
  1510. justify-content: center;
  1511. align-items: center;
  1512. cursor: pointer;
  1513. &>svg {
  1514. fill: #F6C82D;
  1515. width: 1rem;
  1516. height: 1rem;
  1517. }
  1518. &.cq_cb_disabled {
  1519. cursor: not-allowed !important;
  1520. border-color: #FEF8E9 !important;
  1521. }
  1522. &.cq_cb_disabled>svg {
  1523. fill: #A3A3A3 !important;
  1524. }
  1525. }
  1526. &>span {
  1527. font-weight: 500;
  1528. }
  1529. }
  1530. }
  1531. .c_t15 {
  1532. width: 100%;
  1533. min-height: 100%;
  1534. display: flex;
  1535. align-items: center;
  1536. flex-direction: column;
  1537. height: auto;
  1538. padding: 40px;
  1539. .c_t15_title {
  1540. color: rgba(0, 0, 0, 0.9);
  1541. font-weight: 600;
  1542. font-size: 24px;
  1543. line-height: 24px;
  1544. }
  1545. .c_t15_type {
  1546. font-weight: 400;
  1547. font-size: 15px;
  1548. line-height: 21px;
  1549. letter-spacing: 0.5px;
  1550. color: rgba(0, 0, 0, 1);
  1551. opacity: 0.5;
  1552. margin-top: 20px;
  1553. }
  1554. .c_t15_content {
  1555. width: 100%;
  1556. height: auto;
  1557. display: grid;
  1558. grid-template-columns: repeat(3, 1fr);
  1559. gap: 20px;
  1560. margin-top: 40px;
  1561. .c_t15_c_item {
  1562. width: 100%;
  1563. height: auto;
  1564. box-shadow: 2px 4px 20px 0px rgba(0, 0, 0, 0.2);
  1565. box-sizing: border-box;
  1566. border-radius: 12px;
  1567. padding: 16px;
  1568. background: rgba(255, 255, 255, 0.6);
  1569. transition: 0.3s;
  1570. cursor: pointer;
  1571. &:hover {
  1572. box-shadow: 4px 4px 14px 0px rgba(252, 207, 0, 0.5);
  1573. background: rgba(255, 255, 255, 0.6);
  1574. }
  1575. .c_t15_c_i_top {
  1576. display: flex;
  1577. align-items: center;
  1578. gap: 10px;
  1579. &>span {
  1580. display: block;
  1581. width: 25px;
  1582. height: 25px;
  1583. display: flex;
  1584. align-items: center;
  1585. justify-content: center;
  1586. background: rgba(252, 207, 0, 1);
  1587. border-radius: 4px;
  1588. color: rgba(255, 255, 255, 1);
  1589. font-weight: bold;
  1590. font-size: 14px;
  1591. }
  1592. &>div {
  1593. color: rgba(0, 0, 0, 0.7);
  1594. font-weight: 800;
  1595. }
  1596. }
  1597. .c_t15_c_i_bottom {
  1598. margin-top: 15px;
  1599. font-weight: 300;
  1600. font-size: 14px;
  1601. height: 40px;
  1602. max-width: 100%;
  1603. overflow: hidden;
  1604. text-overflow: ellipsis;
  1605. display: -webkit-box;
  1606. -webkit-line-clamp: 2;
  1607. -webkit-box-orient: vertical;
  1608. }
  1609. .c_t73_c_i_bottom {
  1610. margin-top: 15px;
  1611. font-weight: 300;
  1612. font-size: 14px;
  1613. // height: 40px;
  1614. max-width: 100%;
  1615. overflow: hidden;
  1616. text-overflow: ellipsis;
  1617. display: -webkit-box;
  1618. -webkit-line-clamp: 2;
  1619. -webkit-box-orient: vertical;
  1620. img {
  1621. width: 100%;
  1622. height: 200px;
  1623. object-fit: cover;
  1624. }
  1625. span {
  1626. width: 100%;
  1627. height: 200px;
  1628. display: flex;
  1629. align-items: center;
  1630. justify-content: center;
  1631. }
  1632. }
  1633. }
  1634. }
  1635. .c_t15_workDetail {
  1636. width: 100%;
  1637. height: auto;
  1638. margin-top: 40px;
  1639. box-shadow: 4px 4px 14px 0px rgba(252, 207, 0, 0.5);
  1640. box-sizing: border-box;
  1641. padding: 16px;
  1642. border-radius: 12px;
  1643. display: flex;
  1644. flex-direction: column;
  1645. .c_t15_wd_top {
  1646. width: 100%;
  1647. display: flex;
  1648. align-items: center;
  1649. gap: 15px;
  1650. &>img {
  1651. width: 25px;
  1652. height: 25px;
  1653. cursor: pointer;
  1654. }
  1655. &>span {
  1656. display: block;
  1657. width: 30px;
  1658. height: 30px;
  1659. display: flex;
  1660. align-items: center;
  1661. justify-content: center;
  1662. background: rgba(252, 207, 0, 1);
  1663. border-radius: 4px;
  1664. color: rgba(255, 255, 255, 1);
  1665. font-weight: bold;
  1666. font-size: 16px;
  1667. }
  1668. &>div {
  1669. color: rgba(0, 0, 0, 0.7);
  1670. font-weight: 800;
  1671. font-size: 18px;
  1672. }
  1673. }
  1674. .c_t15_wd_content {
  1675. width: 100%;
  1676. margin-top: 20px;
  1677. max-height: 100%;
  1678. overflow: auto;
  1679. flex-wrap: wrap;
  1680. .c_t15_wd_c_imageList {
  1681. width: 100%;
  1682. gap: 20px;
  1683. margin-top: 20px;
  1684. &>img {
  1685. width: 100px;
  1686. height: auto;
  1687. cursor: pointer;
  1688. margin-right: 20px;
  1689. object-fit: cover;
  1690. }
  1691. }
  1692. }
  1693. }
  1694. .c_t79_workDetail {
  1695. width: 100%;
  1696. height: auto;
  1697. margin-top: 40px;
  1698. box-shadow: 4px 4px 14px 0px rgba(252, 207, 0, 0.5);
  1699. box-sizing: border-box;
  1700. padding: 16px;
  1701. border-radius: 12px;
  1702. display: flex;
  1703. flex-direction: column;
  1704. .c_t79_wd_top {
  1705. width: 100%;
  1706. display: flex;
  1707. align-items: center;
  1708. gap: 15px;
  1709. &>img {
  1710. width: 25px;
  1711. height: 25px;
  1712. cursor: pointer;
  1713. }
  1714. &>span {
  1715. display: block;
  1716. width: 30px;
  1717. height: 30px;
  1718. display: flex;
  1719. align-items: center;
  1720. justify-content: center;
  1721. background: rgba(252, 207, 0, 1);
  1722. border-radius: 4px;
  1723. color: rgba(255, 255, 255, 1);
  1724. font-weight: bold;
  1725. font-size: 16px;
  1726. }
  1727. &>div {
  1728. color: rgba(0, 0, 0, 0.7);
  1729. font-weight: 800;
  1730. font-size: 18px;
  1731. }
  1732. }
  1733. .c_t79_wd_content {
  1734. width: 100%;
  1735. margin-top: 20px;
  1736. max-height: 100%;
  1737. overflow: auto;
  1738. flex-wrap: wrap;
  1739. display: flex;
  1740. align-items: center;
  1741. justify-content: center;
  1742. &>img {
  1743. max-width: 100%;
  1744. height: 300px;
  1745. object-fit: cover;
  1746. }
  1747. }
  1748. }
  1749. .cq_changeBtn {
  1750. display: flex;
  1751. align-items: center;
  1752. gap: 1.5rem;
  1753. margin: 1rem auto;
  1754. &>div {
  1755. padding: .6rem;
  1756. border-radius: .5rem;
  1757. border: solid 2px #F6C82B;
  1758. display: flex;
  1759. justify-content: center;
  1760. align-items: center;
  1761. cursor: pointer;
  1762. &>svg {
  1763. fill: #F6C82D;
  1764. width: 1rem;
  1765. height: 1rem;
  1766. }
  1767. &.cq_cb_disabled {
  1768. cursor: not-allowed !important;
  1769. border-color: #FEF8E9 !important;
  1770. }
  1771. &.cq_cb_disabled>svg {
  1772. fill: #A3A3A3 !important;
  1773. }
  1774. }
  1775. &>span {
  1776. font-weight: 500;
  1777. }
  1778. }
  1779. }
  1780. .c_t72 {
  1781. width: 100%;
  1782. min-height: 100%;
  1783. display: flex;
  1784. align-items: center;
  1785. flex-direction: column;
  1786. height: auto;
  1787. padding: 40px;
  1788. .c_t72_title {
  1789. color: rgba(0, 0, 0, 0.9);
  1790. font-weight: 600;
  1791. font-size: 24px;
  1792. line-height: 24px;
  1793. }
  1794. .c_t72_type {
  1795. font-weight: 400;
  1796. font-size: 15px;
  1797. line-height: 21px;
  1798. letter-spacing: 0.5px;
  1799. color: rgba(0, 0, 0, 1);
  1800. opacity: 0.5;
  1801. margin-top: 20px;
  1802. }
  1803. .c_t72_content {
  1804. width: 100%;
  1805. height: auto;
  1806. display: grid;
  1807. grid-template-columns: repeat(4, 1fr);
  1808. gap: 20px;
  1809. margin-top: 40px;
  1810. .c_t72_c_item {
  1811. width: 100%;
  1812. height: auto;
  1813. box-shadow: 2px 4px 20px 0px rgba(0, 0, 0, 0.2);
  1814. box-sizing: border-box;
  1815. border-radius: 12px;
  1816. padding: 16px;
  1817. background: rgba(255, 255, 255, 0.6);
  1818. transition: 0.3s;
  1819. cursor: pointer;
  1820. &:hover {
  1821. box-shadow: 4px 4px 14px 0px rgba(252, 207, 0, 0.5);
  1822. background: rgba(255, 255, 255, 0.6);
  1823. }
  1824. .c_t72_c_i_top {
  1825. display: flex;
  1826. align-items: center;
  1827. gap: 10px;
  1828. &>span {
  1829. display: block;
  1830. width: 25px;
  1831. height: 25px;
  1832. display: flex;
  1833. align-items: center;
  1834. justify-content: center;
  1835. background: rgba(252, 207, 0, 1);
  1836. border-radius: 4px;
  1837. color: rgba(255, 255, 255, 1);
  1838. font-weight: bold;
  1839. font-size: 14px;
  1840. }
  1841. &>div {
  1842. color: rgba(0, 0, 0, 0.7);
  1843. font-weight: 800;
  1844. }
  1845. }
  1846. .c_t72_c_i_bottom {
  1847. margin-top: 15px;
  1848. font-weight: 300;
  1849. font-size: 14px;
  1850. // height: 40px;
  1851. max-width: 100%;
  1852. overflow: hidden;
  1853. text-overflow: ellipsis;
  1854. display: -webkit-box;
  1855. -webkit-line-clamp: 2;
  1856. -webkit-box-orient: vertical;
  1857. img {
  1858. width: 100%;
  1859. max-height: 200px;
  1860. object-fit: cover;
  1861. }
  1862. }
  1863. }
  1864. }
  1865. .c_t72_workDetail {
  1866. width: 100%;
  1867. height: auto;
  1868. margin-top: 40px;
  1869. box-shadow: 4px 4px 14px 0px rgba(252, 207, 0, 0.5);
  1870. box-sizing: border-box;
  1871. padding: 16px;
  1872. border-radius: 12px;
  1873. display: flex;
  1874. flex-direction: column;
  1875. .c_t72_wd_top {
  1876. width: 100%;
  1877. display: flex;
  1878. align-items: center;
  1879. gap: 15px;
  1880. &>img {
  1881. width: 25px;
  1882. height: 25px;
  1883. cursor: pointer;
  1884. }
  1885. &>span {
  1886. display: block;
  1887. width: 30px;
  1888. height: 30px;
  1889. display: flex;
  1890. align-items: center;
  1891. justify-content: center;
  1892. background: rgba(252, 207, 0, 1);
  1893. border-radius: 4px;
  1894. color: rgba(255, 255, 255, 1);
  1895. font-weight: bold;
  1896. font-size: 16px;
  1897. }
  1898. &>div {
  1899. color: rgba(0, 0, 0, 0.7);
  1900. font-weight: 800;
  1901. font-size: 18px;
  1902. }
  1903. }
  1904. .c_t72_wd_content {
  1905. width: 100%;
  1906. margin-top: 20px;
  1907. max-height: 100%;
  1908. overflow: auto;
  1909. flex-wrap: wrap;
  1910. display: flex;
  1911. align-items: center;
  1912. justify-content: center;
  1913. .na_m_item {
  1914. width: 100%;
  1915. height: auto;
  1916. margin: 10px 0;
  1917. }
  1918. .na_m_i_name {
  1919. width: fit-content;
  1920. max-width: 100%;
  1921. height: auto;
  1922. box-sizing: border-box;
  1923. padding: 10px 10px;
  1924. display: flex;
  1925. align-items: center;
  1926. border-radius: 10px 10px 0 0;
  1927. background-color: #9747ff;
  1928. color: #fff;
  1929. text-overflow: ellipsis;
  1930. overflow: hidden;
  1931. white-space: nowrap;
  1932. }
  1933. .aiName {
  1934. background-color: #0560fc;
  1935. }
  1936. .na_m_i_content {
  1937. padding: 10px;
  1938. border: solid 1px #e7e7e7;
  1939. box-shadow: 0 4px 20px 0 rgba(0, 0, 0, 0.1);
  1940. border-radius: 0 0 12px 12px;
  1941. background-color: #fff;
  1942. :deep(img) {
  1943. max-width: 100%;
  1944. }
  1945. }
  1946. .messageNode {
  1947. width: 100%;
  1948. height: auto;
  1949. box-sizing: border-box;
  1950. padding: 10px 10px;
  1951. border: 0.5px solid #e7e7e7;
  1952. border-radius: 12px;
  1953. gap: 10px;
  1954. margin-top: 20px;
  1955. }
  1956. .messageNodeArea {
  1957. width: 100%;
  1958. height: auto;
  1959. }
  1960. }
  1961. }
  1962. }
  1963. .c_t73 {
  1964. width: 100%;
  1965. min-height: 100%;
  1966. display: flex;
  1967. align-items: center;
  1968. flex-direction: column;
  1969. height: auto;
  1970. padding: 40px;
  1971. .c_t73_title {
  1972. color: rgba(0, 0, 0, 0.9);
  1973. font-weight: 600;
  1974. font-size: 24px;
  1975. line-height: 24px;
  1976. }
  1977. .c_t73_type {
  1978. font-weight: 400;
  1979. font-size: 15px;
  1980. line-height: 21px;
  1981. letter-spacing: 0.5px;
  1982. color: rgba(0, 0, 0, 1);
  1983. opacity: 0.5;
  1984. margin-top: 20px;
  1985. }
  1986. .c_t73_content {
  1987. width: 100%;
  1988. height: auto;
  1989. display: grid;
  1990. grid-template-columns: repeat(4, 1fr);
  1991. gap: 20px;
  1992. margin-top: 40px;
  1993. .c_t73_c_item {
  1994. width: 100%;
  1995. height: auto;
  1996. box-shadow: 2px 4px 20px 0px rgba(0, 0, 0, 0.2);
  1997. box-sizing: border-box;
  1998. border-radius: 12px;
  1999. padding: 16px;
  2000. background: rgba(255, 255, 255, 0.6);
  2001. transition: 0.3s;
  2002. cursor: pointer;
  2003. &:hover {
  2004. box-shadow: 4px 4px 14px 0px rgba(252, 207, 0, 0.5);
  2005. background: rgba(255, 255, 255, 0.6);
  2006. }
  2007. .c_t73_c_i_top {
  2008. display: flex;
  2009. width: 100%;
  2010. align-items: center;
  2011. gap: 10px;
  2012. &>span {
  2013. display: block;
  2014. width: 25px;
  2015. height: 25px;
  2016. display: flex;
  2017. align-items: center;
  2018. justify-content: center;
  2019. background: rgba(252, 207, 0, 1);
  2020. border-radius: 4px;
  2021. color: rgba(255, 255, 255, 1);
  2022. font-weight: bold;
  2023. font-size: 14px;
  2024. }
  2025. &>div {
  2026. color: rgba(0, 0, 0, 0.7);
  2027. font-weight: 800;
  2028. }
  2029. }
  2030. .c_t73_c_i_bottom {
  2031. margin-top: 15px;
  2032. font-weight: 300;
  2033. font-size: 14px;
  2034. // height: 40px;
  2035. max-width: 100%;
  2036. overflow: hidden;
  2037. text-overflow: ellipsis;
  2038. display: -webkit-box;
  2039. -webkit-line-clamp: 2;
  2040. -webkit-box-orient: vertical;
  2041. img {
  2042. width: 100%;
  2043. max-height: 200px;
  2044. object-fit: cover;
  2045. }
  2046. }
  2047. }
  2048. }
  2049. .c_t73_workDetail {
  2050. width: 100%;
  2051. height: auto;
  2052. margin-top: 40px;
  2053. box-shadow: 4px 4px 14px 0px rgba(252, 207, 0, 0.5);
  2054. box-sizing: border-box;
  2055. padding: 16px;
  2056. border-radius: 12px;
  2057. display: flex;
  2058. flex-direction: column;
  2059. .c_t73_wd_top {
  2060. width: 100%;
  2061. display: flex;
  2062. align-items: center;
  2063. gap: 15px;
  2064. &>img {
  2065. width: 25px;
  2066. height: 25px;
  2067. cursor: pointer;
  2068. }
  2069. &>span {
  2070. display: block;
  2071. width: 30px;
  2072. height: 30px;
  2073. display: flex;
  2074. align-items: center;
  2075. justify-content: center;
  2076. background: rgba(252, 207, 0, 1);
  2077. border-radius: 4px;
  2078. color: rgba(255, 255, 255, 1);
  2079. font-weight: bold;
  2080. font-size: 16px;
  2081. }
  2082. &>div {
  2083. color: rgba(0, 0, 0, 0.7);
  2084. font-weight: 800;
  2085. font-size: 18px;
  2086. }
  2087. }
  2088. .c_t73_wd_content {
  2089. width: 100%;
  2090. margin-top: 20px;
  2091. max-height: 100%;
  2092. overflow: auto;
  2093. flex-wrap: wrap;
  2094. display: flex;
  2095. align-items: center;
  2096. justify-content: center;
  2097. &>img {
  2098. max-width: 100%;
  2099. object-fit: cover;
  2100. }
  2101. }
  2102. }
  2103. }
  2104. }
  2105. }
  2106. .aiAnalysis {
  2107. width: 100%;
  2108. height: auto;
  2109. display: flex;
  2110. flex-direction: column;
  2111. padding: 1rem;
  2112. border: solid 1px #F6C82B;
  2113. border-left-width: 4px;
  2114. border-radius: 1rem;
  2115. gap: 1rem;
  2116. &>.ai_header {
  2117. display: flex;
  2118. align-items: center;
  2119. justify-content: space-between;
  2120. gap: 1rem;
  2121. &>div {
  2122. display: flex;
  2123. align-items: center;
  2124. gap: .5rem;
  2125. &>svg {
  2126. width: 1rem;
  2127. height: 1rem;
  2128. }
  2129. }
  2130. &>.ai_title {
  2131. color: #F7CD49;
  2132. font-weight: 500;
  2133. &>svg {
  2134. fill: #F7CD49;
  2135. width: 1.2rem;
  2136. height: 1.2rem;
  2137. }
  2138. }
  2139. &>.ai_refresh {
  2140. padding: .5rem 1rem;
  2141. border-radius: .5rem;
  2142. background: #F6C82B;
  2143. display: flex;
  2144. justify-content: center;
  2145. align-items: center;
  2146. cursor: pointer;
  2147. color: #000;
  2148. font-weight: bold;
  2149. font-size: .8rem;
  2150. gap: .5rem;
  2151. &>svg {
  2152. fill: #000;
  2153. width: .8rem;
  2154. height: .8rem;
  2155. }
  2156. &.disabled {
  2157. cursor: not-allowed !important;
  2158. background: #FEF8E9 !important;
  2159. }
  2160. }
  2161. }
  2162. &>.ai_content {
  2163. font-size: 1rem;
  2164. font-weight: 500;
  2165. }
  2166. &>.ai_echartsData {
  2167. display: flex;
  2168. flex-wrap: wrap;
  2169. gap: .5rem;
  2170. &>span {
  2171. padding: .2rem .5rem;
  2172. border-radius: .25rem;
  2173. background: #E6F4FF;
  2174. display: flex;
  2175. justify-content: center;
  2176. align-items: center;
  2177. color: #141517;
  2178. font-size: .75rem;
  2179. }
  2180. &>.title {
  2181. font-weight: 600;
  2182. }
  2183. &>.btn {
  2184. font-size: .9rem;
  2185. text-decoration: underline;
  2186. color: #F6C82B;
  2187. cursor: pointer;
  2188. }
  2189. }
  2190. &>.ai_updateTime {
  2191. font-size: .8rem;
  2192. font-weight: 500;
  2193. }
  2194. }
  2195. .nextAndUpBtn {
  2196. width: 100%;
  2197. height: auto;
  2198. display: grid;
  2199. grid-template-columns: 1fr 1fr;
  2200. margin-top: 20px;
  2201. gap: 15px;
  2202. &>span {
  2203. display: flex;
  2204. justify-content: center;
  2205. align-items: center;
  2206. width: 100%;
  2207. height: 40px;
  2208. border-radius: 5px;
  2209. font-size: 14px;
  2210. font-weight: 500;
  2211. color: #fff;
  2212. background: #f6c82b;
  2213. cursor: pointer;
  2214. }
  2215. &>.no_active {
  2216. background: #cccccc !important;
  2217. color: #999999 !important;
  2218. cursor: not-allowed !important;
  2219. pointer-events: none !important;
  2220. }
  2221. }
  2222. </style>