choiceQuestionDetailDialog.vue 89 KB

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