exportWorksDialog.vue 64 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982
  1. <template>
  2. <div class="pbl">
  3. <div class="pdfCon" ref="reportPdf" v-loading="loading">
  4. <div
  5. class="coverPage"
  6. :style="{
  7. backgroundColor: '#FFFBDC'
  8. }"
  9. >
  10. <div class="coverPageLogo">
  11. <img
  12. style="height: 50px;"
  13. :src="schoolImg.logo ? schoolImg.logo : ''"
  14. alt=""
  15. />
  16. </div>
  17. <div class="coverPageFrom" style="z-index: 10;">
  18. <div class="coverPageFromTit">{{ worksDialogCon2.course }}</div>
  19. <div
  20. style="
  21. font-size: 32px;
  22. font-weight: 600;
  23. color:rgba(176, 123, 0, 1);
  24. margin: 20px 0;
  25. "
  26. >
  27. {{ lang.ssWorkSet }}
  28. </div>
  29. <div class="termC">
  30. <div><span>{{schoolYear}}</span>{{ lang.ssSchoolYear }}</div>
  31. <div style="width: 20px;"></div>
  32. <div>{{ lang.ssSemester.replace(/\*/g, semester) }}</div>
  33. </div>
  34. <div class="fromCss">
  35. <div>
  36. <span>{{ lang.ssName }}:</span>
  37. <div class="txt">{{ worksDialogCon2.sName }}</div>
  38. </div>
  39. <div>
  40. <span>{{ lang.ssClass }}:</span>
  41. <div class="txt">
  42. {{ worksDialogCon2.class ? worksDialogCon2.class : "——" }}
  43. </div>
  44. </div>
  45. <div>
  46. <span>{{ lang.ssSchool }}:</span>
  47. <div class="txt">{{ worksDialogCon2.schName }}</div>
  48. </div>
  49. <div>
  50. <span>{{ lang.ssTeacher }}:</span>
  51. <div class="txt">
  52. <div style="transform: translate(-1em, 0px);">
  53. {{ worksDialogCon2.uname }}
  54. </div>
  55. </div>
  56. </div>
  57. </div>
  58. </div>
  59. <div class="coverPageFrom">
  60. <img
  61. style="z-index: 10;width: 70%;transform: translate(0px, -45px);"
  62. src="../../../assets/icon/exportPdfworks/ropt.svg"
  63. alt=""
  64. />
  65. </div>
  66. </div>
  67. <div
  68. class="coverPageCon"
  69. :style="{
  70. backgroundColor: '#FFFBDC'
  71. }"
  72. >
  73. <div
  74. style="
  75. font-size: 24px;
  76. font-weight: 600;
  77. color: rgba(92, 80, 70, 1);
  78. margin: 35px 0 20px;
  79. "
  80. >
  81. {{ worksDialogCon2.course }}
  82. </div>
  83. <template v-for="i in workList">
  84. <div
  85. v-if="isStage(i.taskList)"
  86. :key="i.id"
  87. class="stageCon"
  88. >
  89. <div v-if="CState != 5 && CState != 6" class="stageTit">
  90. {{ lang.ssStage.replace(/\*/g, i.id * 1 + 1) }}<span v-if="i.name">:{{ i.name }}</span>
  91. </div>
  92. <template v-for="k in i.taskList">
  93. <div
  94. :key="k.task + 'a'"
  95. style="margin-bottom: 15px"
  96. v-if="isTask(k.toolEList)"
  97. >
  98. <div
  99. style="
  100. width: 100%;
  101. display: flex;
  102. justify-content: space-between;
  103. margin-bottom: 10px;
  104. "
  105. >
  106. <div class="taskTitInd">
  107. <span>{{ lang.ssTask }}{{ k.task + 1 }}</span>
  108. <span>{{ k.taskTit }}</span>
  109. </div>
  110. <div>
  111. <!-- <span class="toolTit">文档工具</span> -->
  112. </div>
  113. </div>
  114. <div v-if="k.taskDetail" class="taskBri">
  115. <div v-html="k.taskDetail"></div>
  116. </div>
  117. <div
  118. class="WorksCon"
  119. v-for="(l, lind) in k.toolEList"
  120. :key="lind + 'l'"
  121. >
  122. <div v-if="l.content && l.content.length">
  123. <div v-if="l.tool[0] == 15">
  124. <div class="toolBlk">
  125. <img
  126. src="../../../assets/icon/thirdToolList/answer.png"
  127. alt=""
  128. />
  129. <div class="toolTit">
  130. <div>{{ lang.ssTool.replace(/\*/g, lind + 1) }}{{ lang.ssQATool }}</div>
  131. <div>{{ lang.ssQuestionT }}{{ l.content[0][0].answerTitle }}</div>
  132. </div>
  133. </div>
  134. <div class="answerTxt">{{ lang.ssAnswer }}{{ l.content[0][0].answer }}</div>
  135. </div>
  136. <div v-if="l.tool[0] == 52">
  137. <div class="toolBlk">
  138. <img
  139. src="../../../assets/icon/fourthToolList/text.png"
  140. alt=""
  141. />
  142. <div class="toolTit">
  143. <div>{{ lang.ssTool.replace(/\*/g, lind + 1) }}{{ lang.ssDocTool }}</div>
  144. <div>
  145. {{ lang.ssDefaultDesc }}
  146. </div>
  147. </div>
  148. </div>
  149. <div class="answerTxt" v-html="l.content[0].text"></div>
  150. </div>
  151. <div v-if="l.tool[0] == 72">
  152. <div class="toolBlk">
  153. <img
  154. style="width: 44px;height: 44px;object-fit: contain;"
  155. :src="l.appJson.json.icon"
  156. alt=""
  157. />
  158. <div class="toolTit">
  159. <div>{{ lang.ssTool.replace(/\*/g, lind + 1) }}{{ l.appJson.name }}</div>
  160. <div>
  161. {{ l.appJson.detail }}
  162. </div>
  163. </div>
  164. </div>
  165. <div style="margin-bottom: 20px;" v-for="(item,index) in l.content[0]" :key="index+'coco'">
  166. <div style="margin-bottom: 15px;font-size: 14px;font-weight: 600;color: #000;">{{ lang.ssStage.replace(/\*/g, index + 1) }}</div>
  167. <template v-if="item.imageUrls && item.imageUrls.length">
  168. <div style="display: flex;flex-wrap: wrap;gap: 10px;" v-for="(image,index) in item.imageUrls" :key="index+'-image'">
  169. <img style="max-width: 390px;object-fit: cover;" :src="image" alt="" />
  170. </div>
  171. </template>
  172. <template v-if="item.messages && item.messages.length">
  173. <div v-for="(po,PInd) in item.messages" :key="PInd+'PInd'">
  174. <div class="left" v-if="po.role == 'assistant'">
  175. <div class="TName">{{ lang.ssAIAssist }}</div>:
  176. <div class="con" v-html="MarkdownT(po.content)"></div>
  177. </div>
  178. <div class="left" v-if="po.role == 'user'">
  179. <div class="TName">{{ worksDialogCon2.sName }}</div>:
  180. <div class="con" v-html="po.content"></div>
  181. </div>
  182. </div>
  183. </template>
  184. </div>
  185. </div>
  186. <div v-if="l.tool[0] == 16 || l.tool[0] == 50">
  187. <div class="toolBlk">
  188. <img
  189. v-if="l.tool[0] == 16"
  190. src="../../../assets/icon/thirdToolList/work.png"
  191. alt=""
  192. />
  193. <img
  194. v-if="l.tool[0] == 50"
  195. src="../../../assets/icon/thirdToolList/plwork.png"
  196. alt=""
  197. />
  198. <div class="toolTit">
  199. <div>
  200. {{ lang.ssTool.replace(/\*/g, lind + 1) }}{{
  201. l.tool[0] == 16 ? lang.ssHomework : lang.ssBatchUp
  202. }}
  203. </div>
  204. <div>
  205. {{ lang.ssDefaultDesc }}
  206. </div>
  207. </div>
  208. </div>
  209. <div v-for="(i, codex) in l.content" :key="codex + 'co'">
  210. <div class="answerTxt" v-html="i"></div>
  211. </div>
  212. </div>
  213. <div v-if="l.tool[0] == 7 || l.tool[0] == 1 || l.tool[0] == 3">
  214. <div class="toolBlk">
  215. <img
  216. v-if="l.tool[0] == 1"
  217. src="../../../assets/icon/secondToolList/whiteBoard.png"
  218. alt=""
  219. />
  220. <img
  221. v-if="l.tool[0] == 3"
  222. src="../../../assets/icon/secondToolList/mindMapping.png"
  223. alt=""
  224. />
  225. <img
  226. v-if="l.tool[0] == 7"
  227. src="../../../assets/icon/secondToolList/mindNetwork.png"
  228. alt=""
  229. />
  230. <div class="toolTit">
  231. <div>
  232. {{ lang.ssTool.replace(/\*/g, lind + 1) }}{{
  233. l.tool[0] == 1
  234. ? lang.ssEWhite
  235. : l.tool[0] == 7
  236. ? lang.ssMindGrid
  237. : lang.ssMindMap
  238. }}
  239. </div>
  240. <div>
  241. {{ lang.ssDefaultDesc }}
  242. </div>
  243. </div>
  244. </div>
  245. <img style="max-width: 200px" :src="l.content[0]" alt="" />
  246. <div>{{ l.content[0] }}</div>
  247. </div>
  248. <div v-if="l.tool[0] == 48">
  249. <div class="toolBlk">
  250. <img
  251. src="../../../assets/icon/fourthToolList/table.png"
  252. alt=""
  253. />
  254. <div class="toolTit">
  255. <div>{{ lang.ssTool.replace(/\*/g, lind + 1) }}{{ lang.ssTable }}</div>
  256. <div>
  257. {{ lang.ssDefaultDesc }}
  258. </div>
  259. </div>
  260. </div>
  261. <el-form>
  262. <div class="cont" v-html="l.content[0].text"></div>
  263. </el-form>
  264. </div>
  265. <div v-if="l.tool[0] == 4">
  266. <div class="toolBlk">
  267. <img
  268. src="../../../assets/icon/thirdToolList/ask.png"
  269. alt=""
  270. />
  271. <div class="toolTit">
  272. <div>{{ lang.ssTool.replace(/\*/g, lind + 1) }}{{ lang.ssQuest }}</div>
  273. <div>{{ lang.ssTitle }}:{{ l.content[0][0].askJson.askTitle }}</div>
  274. </div>
  275. </div>
  276. <div
  277. style="margin-bottom: 5px"
  278. v-for="(i, index) in l.content[0][0].askJson.askJson"
  279. :key="index"
  280. >
  281. <div>{{ lang.ssQuestion3.replace(/\*/g, index + 1) }}{{ i.askstitle }}</div>
  282. <el-radio-group
  283. v-if="!i.type"
  284. v-model="l.content[0][0].anwer[index]"
  285. >
  286. <el-radio
  287. v-for="(item2, checkIndex) in i.checkList"
  288. :key="checkIndex + 'b'"
  289. :label="checkIndex"
  290. disabled
  291. >
  292. {{ item2 }}
  293. </el-radio>
  294. </el-radio-group>
  295. <el-checkbox-group
  296. v-model="l.content[0][0].anwer[index]"
  297. v-else
  298. >
  299. <div class="radioBox">
  300. <el-checkbox
  301. v-for="(item2, checkIndex) in i.checkList"
  302. :key="checkIndex + 'c'"
  303. :label="checkIndex"
  304. disabled
  305. >
  306. {{ item2 }}
  307. </el-checkbox>
  308. </div>
  309. </el-checkbox-group>
  310. </div>
  311. </div>
  312. <div v-if="l.tool[0] == 45">
  313. <div class="toolBlk">
  314. <img
  315. src="../../../assets/icon/thirdToolList/choose.png"
  316. alt=""
  317. />
  318. <div class="toolTit">
  319. <div>{{ lang.ssTool.replace(/\*/g, lind + 1) }}{{ lang.ssChoice }}</div>
  320. <div>
  321. {{ lang.ssDefaultDesc }}
  322. </div>
  323. </div>
  324. </div>
  325. <div
  326. v-for="(i, index) in l.content[0].testJson"
  327. :key="index + 'm'"
  328. >
  329. <div>
  330. {{ lang.ssQuestion3.replace(/\*/g, index + 1) }}{{ i.teststitle }}
  331. <span
  332. v-if="
  333. JSON.stringify(l.content[0].radio[index]) ==
  334. JSON.stringify(i.answer)
  335. "
  336. style="color: #868ce4"
  337. >{{ lang.ssCorrect }}</span
  338. >
  339. <span v-else style="color: red">{{ lang.ssWrong }}</span>
  340. </div>
  341. <div
  342. v-if="i.type == 1"
  343. style="display: flex; flex-direction: column"
  344. >
  345. <el-radio-group v-model="l.content[0].radio[index]">
  346. <div class="radioBox">
  347. <el-radio
  348. v-for="(item2, checkIndex) in i.checkList"
  349. :key="checkIndex + 'b'"
  350. :label="checkIndex"
  351. disabled
  352. :class="[
  353. i.answer == checkIndex
  354. ? 'redioStyle5'
  355. : 'redioStyle2'
  356. ]"
  357. >
  358. <div
  359. v-if="
  360. item2 && item2.imgType && item2.imgType == 1
  361. "
  362. >
  363. <div
  364. class="inImg"
  365. @click.stop="previewImg(item2.src)"
  366. >
  367. <img
  368. style="display: block"
  369. :src="item2.src"
  370. alt=""
  371. />
  372. </div>
  373. </div>
  374. <span v-else v-html="item2"></span>
  375. </el-radio>
  376. </div>
  377. </el-radio-group>
  378. </div>
  379. <div class="radioBox">
  380. <el-checkbox-group
  381. v-model="l.content[0].radio[index]"
  382. v-if="i.type == '2'"
  383. >
  384. <div class="radioBox">
  385. <el-checkbox
  386. v-for="(item2, checkIndex) in i.checkList"
  387. :key="checkIndex + 'c'"
  388. :label="checkIndex"
  389. disabled
  390. :class="[
  391. i.answer.includes(checkIndex)
  392. ? 'redioStyle3'
  393. : 'redioStyle4'
  394. ]"
  395. >
  396. <div style="display: flex">
  397. <div
  398. v-if="
  399. item2 && item2.imgType && item2.imgType == 1
  400. "
  401. >
  402. <div
  403. class="inImg"
  404. @click.stop="previewImg(item2.src)"
  405. >
  406. <img
  407. style="display: block"
  408. :src="item2.src"
  409. alt=""
  410. />
  411. </div>
  412. </div>
  413. <span v-else v-html="item2"></span>
  414. </div>
  415. </el-checkbox>
  416. </div>
  417. </el-checkbox-group>
  418. </div>
  419. </div>
  420. </div>
  421. <!-- 选择匹配 -->
  422. <div v-if="l.tool[0] == 41">
  423. <div class="toolBlk">
  424. <img
  425. class="toolImg"
  426. src="../../../assets/icon/thirdToolList/select.png"
  427. alt=""
  428. />
  429. <div class="toolTit">
  430. <div>{{ lang.ssTool.replace(/\*/g, lind + 1) }}{{ lang.ssSelMatch }}</div>
  431. <div>
  432. {{ lang.ssDefaultDesc }}
  433. </div>
  434. </div>
  435. </div>
  436. <img
  437. @click.stop="previewImg(l.selectJson.url)"
  438. style="max-width: 200px"
  439. :src="l.selectJson.url"
  440. alt=""
  441. />
  442. <div>
  443. <span style="margin-right: 10px">{{ lang.ssOption }}:</span
  444. ><span
  445. style="margin-right: 10px"
  446. v-for="(item, itInd) in l.selectJson.select"
  447. :key="itInd"
  448. >{{ item }}</span
  449. >
  450. </div>
  451. <div style="margin: 10px 0;">
  452. <span style="margin-right: 10px">{{ lang.ssAnswer }}:</span>
  453. <div
  454. style="margin-right: 10px"
  455. v-for="(item, itInd) in l.content[0]"
  456. :key="itInd"
  457. >
  458. {{ lang.ssOption }}{{ itInd + 1 }}:{{ l.selectJson.select[item] }}
  459. <span
  460. v-if="l.selectJson.answer[itInd] == l.content[0][itInd]"
  461. style="color: #868ce4"
  462. >{{ lang.ssCorrect }}</span
  463. >
  464. <span v-else style="color: red">{{ lang.ssWrong }}</span>
  465. </div>
  466. </div>
  467. <div>
  468. <span style="margin-right: 10px">{{ lang.ssAnswer3 }}:</span>
  469. <span
  470. style="margin-right: 10px"
  471. v-for="(item, itInd) in l.selectJson.answer"
  472. :key="itInd"
  473. >{{ lang.ssOption }}{{ itInd + 1 }}:{{
  474. l.selectJson.select[item]
  475. }}</span
  476. >
  477. </div>
  478. </div>
  479. <!-- <div v-if="l.tool[0] == 41">
  480. <div class="toolBlk">
  481. <img
  482. src="../../../assets/icon/thirdToolList/select.png"
  483. alt=""
  484. />
  485. <div class="toolTit">
  486. <div>工具{{ lind + 1 }}:选择匹配</div>
  487. <div>
  488. 根据前期的了解与实地调研对于项目的了解,进行思考与讨论提出问题。
  489. </div>
  490. </div>
  491. </div>
  492. <img
  493. @click.stop="previewImg(l.selectJson.url)"
  494. style="max-width: 200px"
  495. :src="l.selectJson.url"
  496. alt=""
  497. />
  498. <div>
  499. <span style="margin-right: 10px">选项:</span
  500. ><span
  501. style="margin-right: 10px"
  502. v-for="(item, itInd) in l.selectJson.select"
  503. :key="itInd"
  504. >{{ item }}</span
  505. >
  506. </div>
  507. <div>
  508. <span style="margin-right: 10px">学生回答:</span>
  509. <span
  510. style="margin-right: 10px"
  511. v-for="(item, itInd) in l.content[0]"
  512. :key="itInd"
  513. >{{ itInd + 1 }}、{{ l.selectJson.select[item] }}</span
  514. >
  515. </div>
  516. </div> -->
  517. <!-- 排序 -->
  518. <div v-if="l.tool[0] == 47">
  519. <div class="toolBlk">
  520. <img
  521. src="../../../assets/icon/fourthToolList/conSentences.png"
  522. alt=""
  523. />
  524. <div class="toolTit">
  525. <div>{{ lang.ssTool.replace(/\*/g, lind + 1) }}{{ lang.ssSort }}</div>
  526. <div>
  527. {{ lang.ssDefaultDesc }}
  528. </div>
  529. </div>
  530. </div>
  531. <div
  532. v-for="(i, index) in l.content[0]"
  533. :key="index"
  534. style="margin-bottom: 10px"
  535. >
  536. <div
  537. style="
  538. height: 20px;
  539. display: flex;
  540. align-items: center;
  541. flex-wrap: wrap;
  542. "
  543. >
  544. {{ lang.ssQuestion2.replace(/\*/g, index + 1) }}:
  545. <div
  546. class="sortTool"
  547. v-for="(i, index) in i.addSentence"
  548. :key="index"
  549. >
  550. {{ i }}
  551. </div>
  552. <span
  553. v-if="
  554. JSON.stringify(i.chooseSenList) ==
  555. JSON.stringify(i.addSentence)
  556. "
  557. style="color: #868ce4"
  558. >{{ lang.ssCorrect }}</span
  559. >
  560. <span v-else style="color: red">{{ lang.ssWrong }}</span>
  561. </div>
  562. <div
  563. style="
  564. margin: 10px 0;
  565. display: flex;
  566. align-items: center;
  567. flex-wrap: wrap;
  568. "
  569. >
  570. {{ lang.ssStuAnswer }}
  571. <div
  572. class="sortTool"
  573. v-for="(i, index) in i.chooseSenList"
  574. :key="index"
  575. >
  576. {{ i }}
  577. </div>
  578. </div>
  579. <div>
  580. {{ lang.ssAnswer3 }}
  581. <span style="margin: 0 5px">{{
  582. i.addSentence.join(",")
  583. }}</span>
  584. </div>
  585. </div>
  586. </div>
  587. </div>
  588. <!-- ai作业得分 -->
  589. <div
  590. v-if="
  591. l.content &&
  592. l.content.length &&
  593. l.eList &&
  594. l.eList.length &&
  595. (CState == 5 || CState == 6)
  596. "
  597. class="taskSco"
  598. >
  599. <div class="taskScoTit">
  600. <div>
  601. {{ lang.ssTaskScore }}<span style="color: rgba(242, 161, 75, 1)">{{
  602. totalScore(l.rate)
  603. }}</span>
  604. {{ lang.ssScoreUnit }}
  605. </div>
  606. <div>{{ lang.ssSubmitTime }}{{ workTime(k.toolEList) }}</div>
  607. </div>
  608. <!-- 作业评分 -->
  609. <div class="taskScoCon">
  610. <!-- 分数详情与素养 -->
  611. <div style="flex: 1; display: flex; flex-wrap: wrap">
  612. <div style="width: 315px; margin:0 20px 10px 0">
  613. <div class="taskScoConTit">{{ lang.ssScoreDetail }}</div>
  614. <div
  615. v-for="(wItem, ind) in l.eList"
  616. :key="ind + 's'"
  617. class="score_box"
  618. style="width: 100%"
  619. >
  620. <div
  621. style="
  622. display: flex;
  623. justify-content: space-between;
  624. align-items: center;
  625. width: 100%;
  626. min-width: 48%;
  627. "
  628. >
  629. <div class="RootImgBlock">
  630. {{ wItem.detail }}
  631. </div>
  632. <el-rate
  633. class="rate_size"
  634. disabled-void-color="#ccc"
  635. disabled
  636. style="width: 130px"
  637. v-model="l.rate[wItem.detail]"
  638. ></el-rate>
  639. </div>
  640. </div>
  641. </div>
  642. <div style="flex: 1">
  643. <div class="taskScoConTit">{{ lang.ssLiteracy2 }}</div>
  644. <div class="WorkConSY">
  645. <div v-for="(wItem, ind) in l.eList" :key="ind + 's'">
  646. <!-- <el-tooltip
  647. class="item"
  648. effect="dark"
  649. :content="wItem.target"
  650. placement="top-start"
  651. > -->
  652. <div class="RootImgBlockSy">
  653. {{ wItem.target }}
  654. </div>
  655. <!-- </el-tooltip> -->
  656. </div>
  657. </div>
  658. </div>
  659. </div>
  660. <!-- 评语 -->
  661. <div
  662. style="
  663. flex: 1;
  664. flex-shrink: 0;
  665. display: flex;
  666. flex-direction: column;
  667. margin-left: 10px;
  668. "
  669. v-if="l.rate.content"
  670. >
  671. <div class="taskScoConTit">{{ lang.ssComment }}</div>
  672. <div class="WorkCon">
  673. {{ l.rate.content }}
  674. </div>
  675. </div>
  676. </div>
  677. </div>
  678. <!-- 阶段 -->
  679. <div
  680. v-if="
  681. l.eList &&
  682. l.eList.length &&
  683. CState != 5 &&
  684. CState != 6 &&
  685. lind == k.toolEList.length - 1
  686. "
  687. class="taskSco"
  688. >
  689. <div class="taskScoTit">
  690. <div>
  691. {{ lang.ssTaskScore }}<span style="color: rgba(242, 161, 75, 1)">{{
  692. totalScore(k.toolEList[0].rate)
  693. }}</span>
  694. {{ lang.ssScoreUnit }}
  695. </div>
  696. <div>{{ lang.ssSubmitTime }}{{ workTime(k.toolEList) }}</div>
  697. </div>
  698. <!-- 作业评分 -->
  699. <div class="taskScoCon">
  700. <!-- 分数详情与素养 -->
  701. <div style="flex: 1; display: flex; flex-wrap: wrap">
  702. <div style="width: 315px; margin:0 20px 10px 0">
  703. <div class="taskScoConTit">{{ lang.ssScoreDetail }}</div>
  704. <div
  705. v-for="(wItem, ind) in l.eList"
  706. :key="ind + 's'"
  707. class="score_box"
  708. style="width: 100%"
  709. >
  710. <div
  711. style="
  712. display: flex;
  713. justify-content: space-between;
  714. align-items: center;
  715. width: 100%;
  716. min-width: 48%;
  717. "
  718. >
  719. <div class="RootImgBlock">
  720. {{ wItem.value }}
  721. </div>
  722. <el-rate
  723. class="rate_size"
  724. disabled-void-color="#ccc"
  725. disabled
  726. style="width: 130px"
  727. v-model="k.toolEList[0].rate[wItem.value]"
  728. ></el-rate>
  729. </div>
  730. </div>
  731. </div>
  732. <div style="flex: 1">
  733. <div class="taskScoConTit">{{ lang.ssLiteracy2 }}</div>
  734. <div class="WorkConSY">
  735. <div v-for="(wItem, ind) in l.eList" :key="ind + 's'">
  736. <!-- <el-tooltip
  737. class="item"
  738. effect="dark"
  739. :content="wItem.target[wItem.target.length - 1]"
  740. placement="top-start"
  741. > -->
  742. <div class="RootImgBlockSy">
  743. <span v-if="wItem.target && wItem.target.length">
  744. {{ wItem.target[wItem.target.length - 1] }}</span
  745. >
  746. <span v-else> {{ wItem.target }}</span>
  747. </div>
  748. <!-- </el-tooltip> -->
  749. </div>
  750. </div>
  751. </div>
  752. </div>
  753. <!-- 评语 -->
  754. <div
  755. style="
  756. flex: 1;
  757. flex-shrink: 0;
  758. display: flex;
  759. flex-direction: column;
  760. margin-left: 10px;
  761. "
  762. v-if="l.rate.content"
  763. >
  764. <div class="taskScoConTit">{{ lang.ssComment }}</div>
  765. <div class="WorkCon">
  766. {{ l.rate.content }}
  767. </div>
  768. </div>
  769. </div>
  770. </div>
  771. </div>
  772. <!-- 思维导图 -->
  773. <div v-if="CState == 5 || CState == 6" class="taskTitInd">
  774. <div></div>
  775. <span>{{ lang.ssTaskEval }}</span>
  776. </div>
  777. <exjsmind
  778. v-if="CState == 5 || CState == 6"
  779. :treeData="k.treeData"
  780. :keyL="k.task.toString()"
  781. ></exjsmind>
  782. </div>
  783. </template>
  784. </div>
  785. </template>
  786. <div style="display: flex;justify-content: flex-end;width: 100%;">
  787. <img :src="schoolImg.bjLogo ? schoolImg.bjLogo : ''" alt="" />
  788. </div>
  789. </div>
  790. </div>
  791. </div>
  792. </template>
  793. <script>
  794. import html2canvas from "html2canvas";
  795. import jspdf from "jspdf";
  796. import JSZip from "jszip";
  797. import exjsmind from "./exjsmind";
  798. import MarkdownIt from "markdown-it";
  799. import { myMixin } from "@/mixins/mixin.js";
  800. const getFile = url => {
  801. return new Promise((resolve, reject) => {
  802. var credentials = {
  803. accessKeyId: "AKIATLPEDU37QV5CHLMH",
  804. secretAccessKey: "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"
  805. }; //秘钥形式的登录上传
  806. window.AWS.config.update(credentials);
  807. window.AWS.config.region = "cn-northwest-1"; //设置区域
  808. let url2 = url;
  809. let _url2 = "";
  810. if (
  811. url2.indexOf("https://view.officeapps.live.com/op/view.aspx?src=") != -1
  812. ) {
  813. _url2 = url2.split(
  814. "https://view.officeapps.live.com/op/view.aspx?src="
  815. )[1];
  816. } else {
  817. _url2 = url2;
  818. }
  819. var s3 = new window.AWS.S3({ params: { Bucket: "ccrb" } });
  820. let name = decodeURIComponent(
  821. _url2.split("https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/")[1]
  822. );
  823. var params = {
  824. Bucket: "ccrb",
  825. Key: name
  826. };
  827. s3.getObject(params, function(err, data) {
  828. if (err) {
  829. console.log(err, err.stack);
  830. resolve({ data: 1 });
  831. } else {
  832. const fileContent = data.Body.toString("utf-8");
  833. resolve({ data: fileContent });
  834. } // sxuccessful response
  835. });
  836. // axios({
  837. });
  838. };
  839. export default {
  840. mixins: [ myMixin ],
  841. props: [
  842. "uid",
  843. "cid",
  844. "worksDialog",
  845. "worksDialogCon",
  846. "digNum",
  847. "multipleSelection"
  848. ],
  849. components: {
  850. exjsmind
  851. },
  852. data() {
  853. return {
  854. workList: [],
  855. dyList: [],
  856. workEvaList: "",
  857. elist: [],
  858. CState: 0,
  859. oid: this.$route.query.oid,
  860. org: this.$route.query.org,
  861. uid2: this.uid,
  862. worksDialogCon2: JSON.parse(JSON.stringify(this.worksDialogCon)),
  863. courseName: "",
  864. loading: false,
  865. tableData: [],
  866. imgList: [
  867. {
  868. schoolId: "45facc0a-1211-11ec-80ad-005056b86db5",
  869. logo: require("../../../assets/icon/exportPdfworks/cocoroboLogo.svg"),
  870. conImg: require("../../../assets/icon/exportPdfworks/cocoroboCon.svg"),
  871. bjLogo: require("../../../assets/icon/exportPdfworks/logo2.svg"),
  872. bkColor: "#FFFBDC"
  873. }
  874. ],
  875. schoolImg: {}
  876. };
  877. },
  878. mounted() {
  879. if (this.digNum == 0) {
  880. this.downPdf();
  881. } else if (this.digNum == 1) {
  882. this.getWorks1();
  883. } else {
  884. this.batchPdf();
  885. }
  886. },
  887. computed: {
  888. MarkdownT() {
  889. return function (c) {
  890. let md = new MarkdownIt({
  891. html: true, // 允许渲染 HTML
  892. linkify: true, // 自动将URL链接转化为可点击链接
  893. typographer: true, // 启用排版规则(如替换 `"` 为 “)
  894. });
  895. return c
  896. ? md.render(c) : "";
  897. };
  898. },
  899. isStage() {
  900. return function(val) {
  901. let isShow = false;
  902. val.forEach(e => {
  903. e.toolEList.forEach(i => {
  904. if (i.content.length) {
  905. isShow = true;
  906. }
  907. });
  908. });
  909. return isShow;
  910. };
  911. },
  912. isTask() {
  913. return function(val) {
  914. let isShow = false;
  915. val.forEach(e => {
  916. if (e.content.length) {
  917. isShow = true;
  918. }
  919. });
  920. return isShow;
  921. };
  922. },
  923. totalScore() {
  924. return function(val) {
  925. let valT = JSON.parse(JSON.stringify(val));
  926. if (!valT) return "0.0";
  927. delete valT.content;
  928. delete valT.comment;
  929. // console.log("valT", JSON.parse(JSON.stringify(val)));
  930. let data = Object.values(valT);
  931. // console.log("data", JSON.parse(JSON.stringify(data)));
  932. let new1 = data.reduce(function(pre, next, index) {
  933. return pre + next * 1;
  934. });
  935. if (new1 == 0) return "0.0";
  936. return (new1 / data.length).toFixed(1);
  937. };
  938. },
  939. workTime() {
  940. return function(val) {
  941. if (!val.length) return "";
  942. let TimeList = [];
  943. val.forEach(e => {
  944. if (e.time) {
  945. const timestamp = new Date(e.time).getTime();
  946. TimeList.push(timestamp);
  947. }
  948. });
  949. // console.log("TimeList", TimeList);
  950. TimeList.sort(function(a, b) {
  951. return a - b; //从小到大排序
  952. });
  953. return this.convertToTimestamp(TimeList[0]);
  954. };
  955. },
  956. // 计算中国学年
  957. schoolYear() {
  958. const now = new Date();
  959. const year = now.getFullYear();
  960. const month = now.getMonth() + 1; // getMonth() 返回 0-11
  961. // 中国学年:9月1日到次年8月31日
  962. // 如果当前月份是9-12月,学年是 当前年-次年
  963. // 如果当前月份是1-8月,学年是 去年-当前年
  964. if (month >= 9) {
  965. return `${year}-${year + 1}`;
  966. } else {
  967. return `${year - 1}-${year}`;
  968. }
  969. },
  970. // 计算学期:1学期或2学期
  971. semester() {
  972. const now = new Date();
  973. const month = now.getMonth() + 1; // getMonth() 返回 0-11
  974. // 第一学期:9月-次年1月
  975. // 第二学期:2月-8月
  976. if (month >= 9 || month <= 1) {
  977. return 1;
  978. } else {
  979. return 2;
  980. }
  981. }
  982. },
  983. methods: {
  984. // 时间戳转时间
  985. convertToTimestamp(val) {
  986. const date = new Date(val);
  987. // 使用Date对象的方法获取年、月、日、时、分、秒
  988. const year = date.getFullYear();
  989. const month = String(date.getMonth() + 1).padStart(2, "0"); // 月份从0开始,需要加1
  990. const day = String(date.getDate()).padStart(2, "0");
  991. const hours = String(date.getHours()).padStart(2, "0");
  992. const minutes = String(date.getMinutes()).padStart(2, "0");
  993. const seconds = String(date.getSeconds()).padStart(2, "0");
  994. // 格式化后的日期时间字符串
  995. const formattedDateTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  996. return formattedDateTime;
  997. },
  998. // 下载pdf文件
  999. getPdf() {
  1000. const content = this.$refs.reportPdf;
  1001. const dpi = 300;
  1002. html2canvas(content, {
  1003. dpi: dpi, // 设置截图的分辨率
  1004. scale: dpi / 96 // 设置截图缩放比例,以适应pdf的dpi
  1005. }).then(canvas => {
  1006. var contentWidth = canvas.width;
  1007. var contentHeight = canvas.height;
  1008. //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
  1009. var imgWidth = 595.28;
  1010. var imgHeight = (592.28 / contentWidth) * contentHeight;
  1011. var imgData = canvas.toDataURL("image/jpeg", 1.0);
  1012. const pdf = new jspdf("p", "pt", [imgWidth, imgHeight]);
  1013. pdf.addImage(imgData, "PNG", 0, 0, imgWidth, imgHeight);
  1014. pdf.save(
  1015. this.worksDialogCon2.course +
  1016. "-" + this.lang.ssWorkSet + "-" +
  1017. this.worksDialogCon2.sName +
  1018. ".pdf"
  1019. );
  1020. });
  1021. },
  1022. // 压缩pdf
  1023. async getPdf2() {
  1024. const content = this.$refs.reportPdf;
  1025. return new Promise((resolve, reject) => {
  1026. const dpi = 300;
  1027. html2canvas(content, {
  1028. dpi: dpi, // 设置截图的分辨率
  1029. scale: dpi / 96 // 设置截图缩放比例,以适应pdf的dpi
  1030. })
  1031. .then(canvas => {
  1032. var contentWidth = canvas.width;
  1033. var contentHeight = canvas.height;
  1034. //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
  1035. var imgWidth = 595.28;
  1036. var imgHeight = (592.28 / contentWidth) * contentHeight;
  1037. var imgData = canvas.toDataURL("image/jpeg", 1.0);
  1038. const pdf = new jspdf("p", "pt", [imgWidth, imgHeight]);
  1039. pdf.addImage(imgData, "PNG", 0, 0, imgWidth, imgHeight);
  1040. var pdfData = {
  1041. pdfName:
  1042. this.worksDialogCon2.course +
  1043. "-" + this.lang.ssWorkSet + "-" +
  1044. this.worksDialogCon2.sName +
  1045. ".pdf",
  1046. pdfCon: pdf.output("blob")
  1047. };
  1048. // pdfArray.push(pdfData);
  1049. return resolve(pdfData);
  1050. })
  1051. .catch(err => {
  1052. console.log(err);
  1053. });
  1054. });
  1055. },
  1056. // 图片放大查看
  1057. previewImg(url) {
  1058. this.$hevueImgPreview(url);
  1059. },
  1060. // 获取处理作业信息
  1061. async exportPdfSet() {
  1062. let params = {
  1063. uid: this.uid2,
  1064. cid: this.cid
  1065. };
  1066. const response = await this.ajax.get(this.$store.state.api + "selectAllWorksDetail", params);
  1067. const res = response;
  1068. // var worksDetail = res.data[1];
  1069. // var askInfo = res.data[3]; //问卷
  1070. // var answerInfo = res.data[4]; //问答题
  1071. // var pptInfo = res.data[5];
  1072. // var chooseInfo = res.data[6]; //选择题
  1073. // var pjInfo = res.data[7]; //个人评价作业
  1074. // var xztkInfo = res.data[8]; //选择匹配作业
  1075. // var lccjInfo = res.data[9]; //排序作业
  1076. // var bgInfo = res.data[10]; //表格作业
  1077. // var cocopiInfo = res.data[11]; //cocopi或源码编辑作业
  1078. // var wordInfo = res.data[12]; //文档作业
  1079. this.workEvaList = res.data[13];
  1080. let framework = [];
  1081. if (res.data[0].length) {
  1082. let elistData = JSON.parse(res.data[0][0].chapters);
  1083. // console.log("elistData", JSON.parse(JSON.stringify(elistData)));
  1084. elistData.forEach((e, i) => {
  1085. framework[i] = {
  1086. id: i,
  1087. name: e.dyName ? e.dyName : "",
  1088. taskList: []
  1089. };
  1090. e.chapterInfo[0].taskJson.forEach((k, kin) => {
  1091. if (k.eList && k.eList.length) {
  1092. k.toolChoose.forEach(y => {
  1093. y.eList = k.eList;
  1094. });
  1095. }
  1096. framework[i].taskList.push({
  1097. stage: i,
  1098. task: kin,
  1099. taskTit: k.task ? k.task : "",
  1100. taskDetail: k.taskDetail,
  1101. toolEList: k.toolChoose,
  1102. treeData: {
  1103. id: "0",
  1104. topic: k.task ? k.task : this.lang.ssTask + i,
  1105. children: []
  1106. }
  1107. });
  1108. });
  1109. });
  1110. }
  1111. res.data[3].forEach(e => {
  1112. e.content = JSON.parse(e.content);
  1113. });
  1114. res.data[4].forEach(e => {
  1115. e.content = JSON.parse(e.content);
  1116. });
  1117. res.data[6].forEach((k, i) => {
  1118. const element1 = JSON.parse(k.content)[0];
  1119. let t = JSON.parse(k.content)[0].testJson;
  1120. // 处理学生选择答案
  1121. let e = [];
  1122. t.testJson.forEach((i, y) => {
  1123. e.push(element1.anwer[y]);
  1124. });
  1125. t.radio = e;
  1126. // 处理选项
  1127. k.content = t;
  1128. });
  1129. res.data[8].forEach((k, i) => {
  1130. k.content = k.content.split(",");
  1131. });
  1132. res.data[9].forEach(e => {
  1133. e.content = JSON.parse(e.content);
  1134. });
  1135. res.data[12].forEach(e => {
  1136. e.content = JSON.parse(e.content);
  1137. });
  1138. res.data[10].forEach(e => {
  1139. e.content = JSON.parse(e.content);
  1140. });
  1141. for (let index = 0; index < res.data[14].length; index++) {
  1142. if (res.data[14][index].content && this.isValidURL(res.data[14][index].content)) {
  1143. await getFile(res.data[14][index].content).then((resp) => {
  1144. res.data[14][index].content = JSON.parse(resp.data);
  1145. });
  1146. }else if(res.data[14][index].content){
  1147. res.data[14][index].content = res.data[14][index].content ? JSON.parse(res.data[14][index].content) : '';
  1148. }
  1149. }
  1150. let AreaAllWork = [
  1151. ...res.data[1],
  1152. ...res.data[3],
  1153. ...res.data[4],
  1154. ...res.data[5],
  1155. ...res.data[6],
  1156. ...res.data[7],
  1157. ...res.data[8],
  1158. ...res.data[9],
  1159. ...res.data[10],
  1160. ...res.data[11],
  1161. ...res.data[12],
  1162. ...res.data[14],
  1163. ];
  1164. AreaAllWork.sort(function(a, b) {
  1165. return a.stage - b.stage; //从小到大排序
  1166. });
  1167. // console.log("AreaAllWork", JSON.parse(JSON.stringify(AreaAllWork)));
  1168. framework.forEach(e => {
  1169. e.taskList.forEach((k, kin) => {
  1170. k.toolEList.forEach((l, lIndex) => {
  1171. l.content = [];
  1172. l.rate = "";
  1173. l.time = "";
  1174. AreaAllWork.forEach((i, index) => {
  1175. i.tool = i.tool ? i.tool : 0;
  1176. if (
  1177. k.stage == i.stage &&
  1178. k.task == i.task &&
  1179. lIndex == i.tool
  1180. ) {
  1181. l.content.push(i.content);
  1182. l.time = i.tTime;
  1183. }
  1184. });
  1185. // 分数循环
  1186. this.workEvaList.forEach(p => {
  1187. p.tool = p.tool ? p.tool : 0;
  1188. if (
  1189. k.stage == p.stage &&
  1190. k.task == p.task &&
  1191. lIndex == p.tool
  1192. ) {
  1193. let rateCopy = JSON.parse(p.rate);
  1194. for (const key in rateCopy) {
  1195. if (key != "content" && key != "") {
  1196. rateCopy[key] = rateCopy[key] * 1;
  1197. }
  1198. }
  1199. l.rate = rateCopy;
  1200. }
  1201. });
  1202. // 将没有提交作业,但是有评分标准的数据填上数据,防止报错
  1203. if (
  1204. !l.rate &&
  1205. l.eList &&
  1206. l.eList.length &&
  1207. (this.CState == 5 || this.CState == 6)
  1208. ) {
  1209. l.rate = { content: "" };
  1210. l.eList.forEach(elp => {
  1211. l.rate[elp.detail] = 0;
  1212. });
  1213. } else if (
  1214. !l.rate &&
  1215. l.eList &&
  1216. l.eList.length &&
  1217. this.CState != 5 &&
  1218. this.CState != 6
  1219. ) {
  1220. l.rate = { content: "" };
  1221. l.eList.forEach(elp => {
  1222. l.rate[elp.value] = 0;
  1223. });
  1224. }
  1225. // 将素养添加进treeData中
  1226. if (l.eList && l.eList.length) {
  1227. l.eList.forEach((itemE, itemEInd) => {
  1228. let arr6 = k.treeData.children.some(
  1229. item => item.topic == itemE.target
  1230. );
  1231. if (!arr6) {
  1232. k.treeData.children.push({
  1233. id: kin + "+" + lIndex + "+" + itemEInd,
  1234. topic: itemE.target,
  1235. children: []
  1236. });
  1237. }
  1238. });
  1239. }
  1240. });
  1241. });
  1242. });
  1243. framework.forEach(e => {
  1244. e.taskList.forEach((k, kind) => {
  1245. k.treeData.children.forEach(l => {
  1246. k.toolEList.forEach((el, elind) => {
  1247. if (el.eList) {
  1248. el.eList.forEach((st, stind) => {
  1249. // console.log(l.topic, st.target, l.topic == st.target);
  1250. if (l.topic == st.target) {
  1251. let res3 = l.children.filter(function(item, index) {
  1252. return item.topic == st.detail;
  1253. });
  1254. if (!res3.length) {
  1255. l.children.push({
  1256. id: kind + "+" + elind + "+" + stind + "c",
  1257. topic: st.detail,
  1258. children: [
  1259. {
  1260. id: kind + "+" + elind + "+" + stind + "b",
  1261. topic: this.lang.ssTool.replace(/\*/g, elind * 1 + 1)
  1262. }
  1263. ]
  1264. });
  1265. } else {
  1266. l.children.forEach(lc => {
  1267. if (lc.topic == st.detail) {
  1268. lc.children.push({
  1269. id: kind + "+" + elind + "+" + stind + "b",
  1270. topic: this.lang.ssTool.replace(/\*/g, elind * 1 + 1)
  1271. });
  1272. }
  1273. });
  1274. }
  1275. }
  1276. });
  1277. }
  1278. });
  1279. });
  1280. });
  1281. });
  1282. // console.log("framework", JSON.parse(JSON.stringify(framework)));
  1283. this.Kloading = false;
  1284. this.loading = false;
  1285. this.workList = framework;
  1286. },
  1287. isValidURL(str){
  1288. try {
  1289. const url = new URL(str);
  1290. return ['http:', 'https:', 'ftp:'].includes(url.protocol) && !!url.hostname;
  1291. } catch (e) {
  1292. return false;
  1293. }
  1294. },
  1295. // 获取作业阶段人物信息
  1296. getCourseDetail() {
  1297. this.loading = true;
  1298. let params = {
  1299. cid: this.cid,
  1300. choseClass: ""
  1301. };
  1302. return new Promise((resolve, reject) => {
  1303. this.ajax
  1304. .get(this.$store.state.api + "getCourseWorksReport2", params) //getCourseWorksReport
  1305. .then(res => {
  1306. this.CState = res.data[0][0].state;
  1307. this.worksDialogCon2.uname = res.data[0][0].username;
  1308. // let dyList = [];
  1309. // for (var i = 0; i < dyJSON.length; i++) {
  1310. // dyList.push({ name: dyJSON[i].dyName, id: i, taskList: [] });
  1311. // var a = dyJSON[i].chapterInfo[0].taskJson;
  1312. // for (var j = 0; j < a.length; j++) {
  1313. // dyList[i].taskList.push({ name: a[j].task, id: j });
  1314. // }
  1315. // }
  1316. // this.dyList = dyList;
  1317. this.imgList.forEach(e => {
  1318. if (e.schoolId == this.oid) {
  1319. this.schoolImg = e;
  1320. }
  1321. });
  1322. return resolve();
  1323. })
  1324. .catch(err => {
  1325. console.error(err);
  1326. });
  1327. });
  1328. },
  1329. // 一键打包所有作业
  1330. async circulatePdf() {
  1331. let _this = this;
  1332. var zip = new JSZip();
  1333. let pdfList = [];
  1334. for (let i = 0; i < this.tableData.length; i++) {
  1335. this.uid2 = this.tableData[i].userid;
  1336. this.worksDialogCon2 = this.tableData[i];
  1337. await this.getCourseDetail();
  1338. await this.exportPdfSet();
  1339. let a = await this.getPdf2();
  1340. pdfList.push(a);
  1341. }
  1342. pdfList.forEach((e, index) => {
  1343. zip.file(e.pdfName, e.pdfCon);
  1344. });
  1345. // 生成压缩包并提供下载链接
  1346. zip.generateAsync({ type: "blob" }).then(function(content) {
  1347. // 使用FileSaver保存压缩包
  1348. saveAs(content, _this.courseName + "-" + _this.lang.ssWorkSetSummary + ".zip");
  1349. });
  1350. this.$emit("update:worksDialog", false);
  1351. // this.worksDialog = false;
  1352. },
  1353. handleClose(done) {
  1354. done();
  1355. },
  1356. // 下载单个文件
  1357. async downPdf() {
  1358. await this.getCourseDetail();
  1359. await this.exportPdfSet();
  1360. this.getPdf();
  1361. },
  1362. // 获取所有作业然后一键打包压缩包
  1363. getWorks1() {
  1364. this.loading = true;
  1365. let params = {
  1366. cid: this.cid,
  1367. uname: "",
  1368. choseClass: "",
  1369. stage: "",
  1370. task: ""
  1371. };
  1372. this.ajax
  1373. .get(this.$store.state.api + "getCourseWorks6", params) //getCourseWorks4
  1374. .then(res => {
  1375. // this.isLoading = false;
  1376. // this.total = res.data[0].length > 0 ? res.data[0][0].num : 0;
  1377. this.tableData = res.data[0];
  1378. if (!this.tableData.length) {
  1379. this.loading = false;
  1380. return this.$message.info(this.lang.ssNoWorkSubmit);
  1381. }
  1382. this.courseName = this.tableData[0].course;
  1383. this.circulatePdf();
  1384. // console.log(res.data[0]);
  1385. })
  1386. .catch(err => {
  1387. this.isLoading = false;
  1388. console.error(err);
  1389. });
  1390. },
  1391. // 批量导出作业
  1392. batchPdf() {
  1393. this.loading = true;
  1394. this.tableData = JSON.parse(JSON.stringify(this.multipleSelection));
  1395. this.courseName = this.tableData[0].course;
  1396. this.circulatePdf();
  1397. }
  1398. }
  1399. };
  1400. </script>
  1401. <style scoped>
  1402. .left{
  1403. display: flex;
  1404. justify-content: flex-start;
  1405. margin-bottom: 10px;
  1406. line-height: 25px;
  1407. flex: 1;
  1408. border-bottom: 1px #e7e7e7 solid;
  1409. }
  1410. .TName{
  1411. /* font-size: 14px; */
  1412. color: #4472C4;
  1413. margin-bottom: 5px;
  1414. font-weight: 600;
  1415. width: 80px;
  1416. flex-shrink: 0;
  1417. font-size: 14px;
  1418. overflow: hidden;
  1419. white-space: nowrap;
  1420. text-overflow: ellipsis;
  1421. }
  1422. .con{
  1423. margin-left: 10px;
  1424. font-size: 12px;
  1425. color: #000;
  1426. }
  1427. .pbl {
  1428. width: 100%;
  1429. height: 100%;
  1430. box-sizing: border-box;
  1431. margin: auto;
  1432. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  1433. /* padding: 20px;
  1434. padding-top: 10px; */
  1435. overflow: auto;
  1436. border-radius: 10px;
  1437. font-family: PingFang SC;
  1438. position: relative;
  1439. }
  1440. .pdfCon {
  1441. width: 220mm;
  1442. margin: auto;
  1443. position: relative;
  1444. }
  1445. .pageTit {
  1446. width: 100%;
  1447. text-align: left;
  1448. font-size: 28px;
  1449. padding: 10px 0;
  1450. font-weight: bold;
  1451. border-bottom: 1px solid #ccc;
  1452. margin-bottom: 10px;
  1453. }
  1454. .full_diy {
  1455. min-width: 1200px !important;
  1456. }
  1457. .full_diy >>> .el-dialog {
  1458. height: 80%;
  1459. margin-top: 10vh !important;
  1460. display: flex;
  1461. flex-direction: column;
  1462. }
  1463. .full_diy >>> .el-dialog__body {
  1464. overflow: auto;
  1465. flex: 1;
  1466. padding: 0 !important;
  1467. }
  1468. .full_diy >>> .el-dialog__title {
  1469. color: #fff !important;
  1470. }
  1471. .full_diy >>> .el-dialog__header {
  1472. padding: 9px 20px 10px;
  1473. background: #32455b !important;
  1474. }
  1475. .coverPage {
  1476. /* height: 840pt; */
  1477. padding: 150px 8% 0;
  1478. background-color: #ccc;
  1479. box-sizing: border-box;
  1480. position: relative;
  1481. background-image: url("../../../assets/icon/exportPdfworks/bcg1.svg"),
  1482. url("../../../assets/icon/exportPdfworks/bcg2.svg");
  1483. /* 设置每个背景的位置和尺寸,可以使用关键字或者具体的像素值,用逗号分隔 */
  1484. background-position: top left, bottom;
  1485. background-size: 225px, contain;
  1486. /* 设置每个背景图片的重复方式,用逗号分隔 */
  1487. background-repeat: no-repeat, no-repeat;
  1488. }
  1489. .coverPageLogo {
  1490. /* padding: 40px;
  1491. height: 120px;
  1492. width: 100%;
  1493. display: flex;
  1494. justify-content: flex-end;
  1495. box-sizing: border-box;
  1496. margin-bottom: 45px; */
  1497. position: absolute;
  1498. top: 30px;
  1499. right: 6%;
  1500. }
  1501. .coverPageFrom {
  1502. display: flex;
  1503. flex-direction: column;
  1504. align-items: center;
  1505. width: 70%;
  1506. margin: 0 auto;
  1507. }
  1508. .coverPageFromTit {
  1509. font-size: 60px;
  1510. color: rgba(92, 80, 70, 1);
  1511. font-weight: 600;
  1512. text-align: center;
  1513. }
  1514. .fromCss {
  1515. border: 1.5px dashed rgba(158, 208, 255, 1);
  1516. border-radius: 16px;
  1517. background-color: #fff;
  1518. padding: 40px 32px;
  1519. width: 70%;
  1520. font-family: PingFang SC;
  1521. margin: 8px 0;
  1522. color: rgba(35, 99, 205, 1);
  1523. }
  1524. .fromCss > div {
  1525. margin-bottom: 28px;
  1526. display: flex;
  1527. }
  1528. .fromCss > div > span {
  1529. flex-shrink: 0;
  1530. margin-right: 5px;
  1531. font-size: 16px;
  1532. font-weight: 600;
  1533. color: rgba(92, 80, 70, 1);
  1534. }
  1535. .fromCss > div:last-child {
  1536. margin-bottom: 0;
  1537. }
  1538. .txt {
  1539. width: 100%;
  1540. border-bottom: 1px solid rgba(192, 210, 229, 1);
  1541. text-align: center;
  1542. color: #000;
  1543. overflow: hidden;
  1544. white-space: nowrap;
  1545. text-overflow: ellipsis;
  1546. }
  1547. .coverPageCon {
  1548. background-color: #e3edfe;
  1549. display: flex;
  1550. flex-direction: column;
  1551. padding: 0 60px;
  1552. padding-bottom: 100px;
  1553. box-sizing: border-box;
  1554. font-family: PingFang SC;
  1555. }
  1556. .stageCon {
  1557. background-color: #fff;
  1558. padding: 15px;
  1559. box-sizing: border-box;
  1560. margin-bottom: 10px;
  1561. border-radius: 8px;
  1562. width: 100%;
  1563. }
  1564. .a_addBox {
  1565. margin: 10px 0;
  1566. background: #fff;
  1567. padding: 0 15px;
  1568. /* max-height: 400px; */
  1569. /* max-height: 160px; */
  1570. /* overflow: auto; */
  1571. }
  1572. .redioStyle >>> .el-radio__label {
  1573. font-size: 18px;
  1574. }
  1575. .redioStyle5 >>> .el-radio__label {
  1576. font-size: 14px;
  1577. color: #06a7ff !important;
  1578. }
  1579. .redioStyle2 >>> .el-radio__label {
  1580. font-size: 14px;
  1581. }
  1582. .redioStyle3 >>> .el-checkbox__label {
  1583. font-size: 14px;
  1584. color: #06a7ff !important;
  1585. }
  1586. .redioStyle4 >>> .el-checkbox__label {
  1587. font-size: 14px;
  1588. }
  1589. .WorksCon >>> .el-checkbox-group {
  1590. margin: 0 5px;
  1591. }
  1592. .sortTool {
  1593. padding: 1px 3px;
  1594. border: 2px #5d89c4 solid;
  1595. margin: 0 5px;
  1596. min-width: 20px;
  1597. border-radius: 5px;
  1598. text-align: center;
  1599. }
  1600. /* table 样式 */
  1601. .cont >>> table {
  1602. border-top: 1px solid #ccc;
  1603. border-left: 1px solid #ccc;
  1604. }
  1605. .cont >>> table td,
  1606. .cont >>> table th {
  1607. border-bottom: 1px solid #ccc;
  1608. border-right: 1px solid #ccc;
  1609. padding: 15px 5px;
  1610. max-width: 0px;
  1611. }
  1612. .cont >>> table th {
  1613. border-bottom: 2px solid #ccc;
  1614. text-align: center;
  1615. }
  1616. .taskSco {
  1617. background-color: rgba(243, 247, 253, 1);
  1618. border-radius: 8px;
  1619. padding: 8px;
  1620. box-sizing: border-box;
  1621. margin: 8px 0;
  1622. }
  1623. .score_boxTit > span {
  1624. border-left: 3px solid rgba(54, 129, 252, 1);
  1625. padding-left: 5px;
  1626. }
  1627. .score_boxTit {
  1628. /* padding: 0 30px; */
  1629. box-sizing: border-box;
  1630. font-size: 14px;
  1631. font-weight: 600;
  1632. color: rgba(0, 0, 0, 0.9);
  1633. }
  1634. .inImg {
  1635. width: 100px;
  1636. }
  1637. .inImg > img {
  1638. width: 100%;
  1639. height: 100%;
  1640. object-fit: cover;
  1641. }
  1642. .radioBox {
  1643. display: flex;
  1644. flex-direction: column;
  1645. }
  1646. .WorksCon >>> .el-radio {
  1647. display: flex;
  1648. align-items: center;
  1649. margin: 5px;
  1650. }
  1651. .WorksCon >>> .el-checkbox {
  1652. display: flex;
  1653. align-items: center;
  1654. margin: 5px;
  1655. }
  1656. .RootImgBlock {
  1657. width: 50%;
  1658. white-space: wrap;
  1659. /* overflow: hidden;
  1660. text-overflow: ellipsis; */
  1661. font-size: 12px;
  1662. }
  1663. .score_box {
  1664. display: flex;
  1665. align-items: center;
  1666. font-size: 14px !important;
  1667. /* justify-content: flex-start; */
  1668. justify-content: space-between;
  1669. margin-bottom: 15px;
  1670. /* margin: 10px 0 0 30px; */
  1671. width: 100%;
  1672. margin: 5px 0;
  1673. position: relative;
  1674. }
  1675. .score_box:last-child {
  1676. margin-bottom: 0;
  1677. }
  1678. .worksTarget {
  1679. border-left: 3px solid rgba(54, 129, 252, 1);
  1680. font-size: 14px;
  1681. font-weight: 600;
  1682. color: rgba(0, 0, 0, 0.9);
  1683. }
  1684. .worksTarget > span {
  1685. margin-left: 5px;
  1686. }
  1687. .worksTargetCon {
  1688. background-color: #fff;
  1689. padding: 10px;
  1690. margin-top: 10px;
  1691. border-radius: 8px;
  1692. box-sizing: border-box;
  1693. font-size: 12px;
  1694. }
  1695. .worksTargetCon > div {
  1696. margin-bottom: 10px;
  1697. }
  1698. .worksTargetCon > div:last-child {
  1699. margin: 0 !important;
  1700. }
  1701. .dialog_diy >>> .el-dialog__header {
  1702. padding: 9px 20px 10px;
  1703. background: #32455b !important;
  1704. }
  1705. .worksDialogCSS >>> .el-dialog__header {
  1706. /* padding: 9px 20px 10px; */
  1707. background: #32455b !important;
  1708. }
  1709. .worksDialogCSS >>> .el-dialog__body {
  1710. width: 643px !important;
  1711. }
  1712. .worksDialogCSS >>> .el-dialog {
  1713. width: 683px !important;
  1714. }
  1715. .stageTit {
  1716. text-align: left;
  1717. font-weight: 600;
  1718. font-size: 22px;
  1719. margin-bottom: 20px;
  1720. color: rgba(242, 161, 75, 1);
  1721. border-left: 5px rgba(242, 161, 75, 1) solid;
  1722. padding-left: 5px;
  1723. }
  1724. .taskTitInd {
  1725. font-size: 14px;
  1726. display: flex;
  1727. align-items: center;
  1728. }
  1729. .taskTitInd span:nth-child(1) {
  1730. background-color: rgba(242, 161, 75, 1);
  1731. color: #fff;
  1732. padding: 3px 5px;
  1733. border-radius: 4px;
  1734. margin-right: 5px;
  1735. box-sizing: border-box;
  1736. font-size: 12px;
  1737. }
  1738. .taskTitInd div {
  1739. background-color: rgba(242, 161, 75, 1);
  1740. width: 15px;
  1741. height: 15px;
  1742. border-radius: 50%;
  1743. margin-right: 10px;
  1744. }
  1745. .taskTitInd span:nth-child(2) {
  1746. color: rgba(0, 0, 0, 0.9);
  1747. font-weight: 600;
  1748. }
  1749. .taskBri {
  1750. background-color: rgba(253, 247, 243, 1);
  1751. padding: 10px 12px;
  1752. line-height: 20px;
  1753. box-sizing: border-box;
  1754. font-weight: PingFang SC;
  1755. font-size: 12px;
  1756. font-weight: 400;
  1757. border-radius: 4px;
  1758. }
  1759. .toolBlk {
  1760. display: flex;
  1761. height: 44px;
  1762. margin: 15px 0;
  1763. }
  1764. .toolBlk img {
  1765. height: 100%;
  1766. margin-right: 8px;
  1767. }
  1768. .toolTit {
  1769. display: flex;
  1770. flex-direction: column;
  1771. justify-content: space-around;
  1772. }
  1773. .toolTit div:nth-child(1) {
  1774. font-family: PingFang SC;
  1775. font-size: 14px;
  1776. font-weight: 600;
  1777. text-align: left;
  1778. color: rgba(0, 0, 0, 0.9);
  1779. margin-right: 10px;
  1780. }
  1781. .toolTit div:nth-child(2) {
  1782. font-family: PingFang SC;
  1783. font-size: 11px;
  1784. font-weight: 400;
  1785. text-align: left;
  1786. color: rgba(0, 0, 0, 0.9);
  1787. }
  1788. .answerTxt {
  1789. font-size: 12px;
  1790. color: rgba(0, 0, 0, 0.6);
  1791. font-weight: 400;
  1792. line-height: 30px;
  1793. padding: 0 10px;
  1794. }
  1795. .taskSco {
  1796. background-color: rgba(253, 247, 243, 1);
  1797. border-radius: 8px;
  1798. padding: 10px 15px;
  1799. box-sizing: border-box;
  1800. margin: 8px 0;
  1801. width: 100%;
  1802. }
  1803. .taskScoTit {
  1804. display: flex;
  1805. justify-content: space-between;
  1806. margin: 0 0 20px;
  1807. }
  1808. .taskScoTit div:nth-child(1) {
  1809. color: rgba(0, 0, 0, 0.9);
  1810. font-family: PingFang SC;
  1811. font-size: 14px;
  1812. font-weight: 600;
  1813. text-align: left;
  1814. }
  1815. .taskScoTit div:nth-child(2) {
  1816. color: rgba(0, 0, 0, 0.6);
  1817. font-family: PingFang SC;
  1818. font-size: 12px;
  1819. font-weight: 400;
  1820. }
  1821. .taskScoCon {
  1822. display: flex;
  1823. justify-content: space-between;
  1824. }
  1825. .taskScoConTit {
  1826. text-align: left;
  1827. font-weight: 600;
  1828. font-size: 14px;
  1829. margin-bottom: 10px;
  1830. color: rgba(0, 0, 0, 0.9);
  1831. border-left: 5px rgba(242, 161, 75, 1) solid;
  1832. padding-left: 5px;
  1833. }
  1834. .WorkCon {
  1835. background-color: rgba(255, 255, 255, 0.9);
  1836. padding: 8px;
  1837. box-sizing: border-box;
  1838. border-radius: 8px;
  1839. font-family: PingFang SC;
  1840. font-size: 12px;
  1841. line-height: 20px;
  1842. font-weight: 400;
  1843. flex: 1;
  1844. }
  1845. .WorkConSY {
  1846. background-color: rgba(255, 255, 255, 0.9);
  1847. padding: 8px;
  1848. box-sizing: border-box;
  1849. border-radius: 8px;
  1850. font-family: PingFang SC;
  1851. font-size: 12px;
  1852. font-weight: 400;
  1853. flex: 1;
  1854. }
  1855. .WorkConSY div {
  1856. margin-bottom: 8px;
  1857. }
  1858. .WorkConSY div:last-child {
  1859. margin-bottom: 0;
  1860. }
  1861. .RootImgBlockSy {
  1862. width: 300px;
  1863. white-space: nowrap;
  1864. overflow: hidden;
  1865. font-size: 12px;
  1866. text-overflow: ellipsis;
  1867. }
  1868. .termC {
  1869. margin: 30px 0 45px;
  1870. font-size: 18px;
  1871. color: rgba(92, 80, 70, 1);
  1872. display: flex;
  1873. justify-content: space-between;
  1874. font-weight: 600;
  1875. }
  1876. .termC > div > span {
  1877. color: rgba(176, 123, 0, 1);
  1878. border-bottom: 2px solid rgba(242, 228, 213, 1);
  1879. padding: 3px 10px;
  1880. margin: 0 8px;
  1881. }
  1882. </style>