setQuestionsAndAnswers.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. <template>
  2. <div class="setChoiceQuestion">
  3. <div class="testItem">
  4. <div class="ti_header">
  5. <span>{{ lang.ssTopic }}{{ 1 }}</span>
  6. </div>
  7. <div class="ti_title">
  8. <el-input class="ti_t_input" type="textarea" v-model="jsonData.answerQ" @input="setTestTitle"></el-input>
  9. <div class="uploadImage" @click="uploadImage()">
  10. <svg viewBox="0 0 1024 1024" version="1.1" p-id="15953" width="200" height="200">
  11. <path
  12. d="M368 480c-62.4 0-112-49.6-112-112s49.6-112 112-112 112 49.6 112 112-49.6 112-112 112z m0-160c-27.2 0-48 20.8-48 48s20.8 48 48 48 48-20.8 48-48-20.8-48-48-48z m464 608H192c-52.8 0-96-43.2-96-96V192c0-52.8 43.2-96 96-96h640c52.8 0 96 43.2 96 96v640c0 52.8-43.2 96-96 96zM192 160c-17.6 0-32 14.4-32 32v640c0 17.6 14.4 32 32 32h640c17.6 0 32-14.4 32-32V192c0-17.6-14.4-32-32-32H192z m259.2 556.8c-25.6 0-51.2-11.2-70.4-30.4l-38.4-40c-12.8-12.8-33.6-12.8-46.4 0l-49.6 52.8c-12.8 12.8-32 12.8-44.8 1.6s-12.8-32-1.6-44.8l49.6-52.8c17.6-19.2 43.2-30.4 68.8-30.4s51.2 11.2 70.4 30.4l38.4 40c12.8 12.8 33.6 12.8 46.4 0l160-168c17.6-19.2 43.2-30.4 70.4-30.4s51.2 11.2 70.4 30.4L920 628.8c12.8 12.8 11.2 33.6-1.6 44.8-12.8 12.8-33.6 11.2-44.8-1.6L728 518.4c-12.8-12.8-33.6-12.8-46.4 0L521.6 688c-19.2 17.6-44.8 28.8-70.4 28.8z"
  13. fill="#333333" p-id="15954"></path>
  14. </svg>
  15. </div>
  16. </div>
  17. <!-- 图片 -->
  18. <div class="imageList">
  19. <div v-for="(image, imageIndex) in jsonData.imageList" :key="imageIndex">
  20. <el-image style="width: 100px; height: 100px" :src="image.url" :preview-src-list="[image.url]"
  21. fit="cover"></el-image>
  22. <svg @click="delImage(imageIndex)" t="1774237005199" viewBox="0 0 1024 1024" width="200" height="200"><path d="M512 1024A512 512 0 1 1 512 0a512 512 0 0 1 0 1024zM305.956571 370.395429L447.488 512 305.956571 653.604571a45.568 45.568 0 1 0 64.438858 64.438858L512 576.512l141.604571 141.531429a45.568 45.568 0 0 0 64.438858-64.438858L576.512 512l141.531429-141.604571a45.568 45.568 0 1 0-64.438858-64.438858L512 447.488 370.395429 305.956571a45.568 45.568 0 0 0-64.438858 64.438858z" fill="#FF2525" p-id="4716"></path></svg>
  23. </div>
  24. </div>
  25. <!-- 选择题 -->
  26. <!-- <div class="checkList">
  27. <div class="checkItem" v-for="(check, checkIndex) in item.checkList" :key="checkIndex">
  28. <div class="check" :class="{ 'checked': item.answer.includes(checkIndex) }"
  29. @click="checkClick(item.id, checkIndex)">
  30. <svg v-if="item.answer.includes(checkIndex)" t="1773996159000" viewBox="0 0 1024 1024" version="1.1"
  31. xmlns="http://www.w3.org/2000/svg" p-id="5894" width="200" height="200">
  32. <path
  33. d="M404.352 685.354667L789.632 213.333333 853.333333 267.52 409.941333 810.666667 170.666667 566.4l58.581333-59.818667z"
  34. p-id="5895"></path>
  35. </svg>
  36. </div>
  37. <el-input v-model="item.checkList[checkIndex]" placeholder="请输入选项" @blur="setTestJson()"></el-input>
  38. <div class="btn">
  39. <div @click="delCheck(item.id, checkIndex)">
  40. <svg viewBox="0 0 1024 1024" version="1.1" p-id="12415" width="200" height="200">
  41. <path
  42. d="M902.4 282.1H117.7c-13.4 0-23.5-10.1-23.5-23.5v-3.4c0-13.4 10.1-23.5 23.5-23.5h788.1c13.4 0 23.5 10.1 23.5 23.5v3.4c0 13.4-10.1 23.5-26.9 23.5zM634.1 151.3H386c-13.4 0-26.8-10.1-23.5-23.5v-6.7c0-13.4 10.1-23.5 23.5-23.5h248.2c13.4 0 23.5 10.1 23.5 23.5v3.4c3.3 13.3-10.1 26.8-23.6 26.8z m228.1 238.1c0-13.4-10.1-26.8-26.8-26.8-16.8 0-26.8 10.1-26.8 26.8L775 798.5v13.4c0 23.5-10.1 43.6-30.2 53.7-13.4 6.7-30.2 10.1-50.3 10.1H332.3c-33.5 3.4-60.4 0-70.4-33.5-3.4-6.7-6.7-16.8-6.7-26.8l-10.1-104-36.9-322c0-13.4-10.1-23.5-23.5-23.5s-26.8 10.1-26.8 23.5l47 462.8c0 40.2 40.2 73.8 80.5 73.8h459.5c40.2 0 80.5-33.5 80.5-73.8l36.8-462.8c0 3.3 0 0 0 0z m0 0"
  43. p-id="12416"></path>
  44. </svg>
  45. </div>
  46. </div>
  47. </div>
  48. <div class="addCheck" @click="addCheck(item.id)">
  49. <svg viewBox="0 0 1024 1024" version="1.1" p-id="2732" width="200" height="200">
  50. <path
  51. d="M925.696 384q19.456 0 37.376 7.68t30.72 20.48 20.48 30.72 7.68 37.376q0 20.48-7.68 37.888t-20.48 30.208-30.72 20.48-37.376 7.68l-287.744 0 0 287.744q0 20.48-7.68 37.888t-20.48 30.208-30.72 20.48-37.376 7.68q-20.48 0-37.888-7.68t-30.208-20.48-20.48-30.208-7.68-37.888l0-287.744-287.744 0q-20.48 0-37.888-7.68t-30.208-20.48-20.48-30.208-7.68-37.888q0-19.456 7.68-37.376t20.48-30.72 30.208-20.48 37.888-7.68l287.744 0 0-287.744q0-19.456 7.68-37.376t20.48-30.72 30.208-20.48 37.888-7.68q39.936 0 68.096 28.16t28.16 68.096l0 287.744 287.744 0z"
  52. p-id="2733"></path>
  53. </svg>
  54. <span>选项</span>
  55. </div>
  56. </div> -->
  57. <!-- 解释说明 -->
  58. <div class="explanation">
  59. <div class="e_header">
  60. <span>{{ lang.ssEvaluationStandard }}</span>
  61. <div @click="generateExplanation()" :disabled="chatLoading" v-loading="messagesloading">
  62. <svg t="1774233113566" viewBox="0 0 1027 1024" width="200" height="200">
  63. <path
  64. d="M511.979521 544.586217a54.525819 54.525819 0 0 1-23.359066-5.247791L31.038758 321.427143a54.397824 54.397824 0 0 1 0-98.236071L488.620455 5.279789c14.719411-7.039718 31.99872-7.039718 46.718131 0l457.581697 217.911283a54.397824 54.397824 0 0 1 0 98.236071l-457.581697 217.911283A54.525819 54.525819 0 0 1 511.979521 544.586217zM180.984761 272.341106L511.979521 429.966801l331.058757-157.625695L511.979521 114.587417 180.984761 272.341106z m354.417823 746.402144l457.517699-217.911283a54.397824 54.397824 0 1 0-46.718131-98.236071L511.979521 909.371625l-434.158634-206.775729a54.397824 54.397824 0 0 0-46.718131 98.300068l457.581697 217.847286a54.525819 54.525819 0 0 0 46.718131 0z m0-239.73441l457.517699-217.847286a54.397824 54.397824 0 1 0-46.718131-98.300068L511.979521 669.573217l-434.158634-206.711731a54.397824 54.397824 0 0 0-46.718131 98.300068l457.581697 217.847286a54.525819 54.525819 0 0 0 46.718131 0z"
  65. p-id="9073"></path>
  66. </svg>
  67. <span>{{ chatLoading ? lang.ssGenerating : lang.ssAIGenerate }}</span>
  68. </div>
  69. </div>
  70. <el-input class="explain_textarea" type="textarea" rows="10" resize="none" v-model="jsonData.evaluationCriteria" :placeholder="lang.ssEnterEvaluationStandard"
  71. @input="setTestJson()" v-loading="messagesloading" :disabled="chatLoading"></el-input>
  72. </div>
  73. </div>
  74. </div>
  75. </template>
  76. <script>
  77. import { uploadOneFile } from '@/components/tools/uploadFile'
  78. import { myMixin } from '@/mixins/mixin'
  79. export default {
  80. mixins: [myMixin],
  81. emits: ['setTestJson', 'save'],
  82. props: {
  83. workData: {
  84. type: Object,
  85. default: () => { }
  86. }
  87. },
  88. data() {
  89. return {
  90. jsonData: {},
  91. streamController: [],
  92. chatLoading: false,
  93. messagesloading: false,
  94. userid: this.$route.query.userid,
  95. }
  96. },
  97. watch: {
  98. workData: {
  99. handler(newVal, oldVal) {
  100. if (newVal.type == 15) {
  101. if (JSON.stringify(newVal.json) != JSON.stringify(this.jsonData)) {
  102. let _data = JSON.parse(JSON.stringify(newVal.json))
  103. if(!_data.imageList){
  104. _data.imageList = [];
  105. }
  106. if(!_data.evaluationCriteria){
  107. _data.evaluationCriteria = '';
  108. }
  109. this.jsonData = _data;
  110. }
  111. }
  112. },
  113. deep: true,
  114. immediate: true
  115. }
  116. },
  117. methods: {
  118. // 更新题目
  119. setTestJson() {
  120. // console.log(this.jsonData)
  121. // this.jsonData.testCount = this.jsonData.testJson.length;
  122. this.$emit('setTestJson', this.jsonData);
  123. },
  124. //修改标题
  125. setTestTitle( title) {
  126. console.log('修改标题', title)
  127. this.jsonData.answerQ = title;
  128. // let test = this.jsonData..find(item => item.id == id);
  129. // if (test) {
  130. // test.teststitle = title;
  131. // }
  132. this.setTestJson();
  133. },
  134. // 上传图片
  135. uploadImage(id) {
  136. const input = document.createElement('input');
  137. input.type = 'file';
  138. input.accept = 'image/*';
  139. input.click();
  140. input.onchange = (e) => {
  141. if (e.target.files[0]) {
  142. uploadOneFile(e.target.files[0]).then(res => {
  143. res.src = res.url
  144. this.jsonData.imageList = [res];
  145. // this.jsonData.testJson.find(item => item.id == id).timuList = [res];
  146. this.setTestJson();
  147. })
  148. }
  149. }
  150. },
  151. // 删除图片
  152. delImage(index) {
  153. this.jsonData.imageList.splice(index, 1);
  154. // let test = this.jsonData.testJson.find(item => item.id == id);
  155. // if (test) {
  156. // test.timuList.splice(index, 1);
  157. // }
  158. this.setTestJson();
  159. },
  160. // 生成解释
  161. async generateExplanation() {
  162. if (this.chatLoading) {
  163. this.$message.warning(this.lang.ssPleaseWait);
  164. return
  165. }
  166. if (this.messagesloading) {
  167. this.$message.warning(this.lang.ssPleaseWait);
  168. return
  169. }
  170. let prompt = `- 题干:${this.jsonData.answerQ}`
  171. this.chatLoading = true
  172. this.messagesloading = true
  173. this.chat_stream(prompt, '5edc10d5-8635-4fe6-9670-8b2d9e8005aa', this.userid || this.workData.userid, this.lang.lang, (event) => {
  174. if (event.type === 'message') {
  175. this.jsonData.evaluationCriteria = event.data
  176. this.messagesloading = false
  177. }
  178. else if (event.type === 'messageEnd') {
  179. this.jsonData.evaluationCriteria = event.data
  180. this.messagesloading = false
  181. this.chatLoading = false
  182. this.setTestJson()
  183. }else if (event.type === 'error') {
  184. this.chatLoading = false
  185. this.messagesloading = false
  186. this.$message.error(event.data)
  187. }
  188. }).then(controller => {
  189. this.streamController = controller
  190. }).catch(err => {
  191. this.chatLoading = false
  192. this.messagesloading = false
  193. console.log('err', err)
  194. this.stopMessage()
  195. })
  196. },
  197. stopMessage() {
  198. if (this.streamController) {
  199. this.streamController.abort()
  200. this.streamController = null
  201. }
  202. this.chatLoading = false
  203. this.messagesloading = false
  204. }
  205. },
  206. }
  207. </script>
  208. <style scoped>
  209. .setChoiceQuestion {
  210. width: 100%;
  211. height: auto;
  212. background: #fff;
  213. display: flex;
  214. flex-direction: column;
  215. overflow: auto;
  216. padding: 4rem;
  217. box-sizing: border-box;
  218. gap: 2rem;
  219. }
  220. .addTest {
  221. border-radius: 5px;
  222. border: 1px dashed #d1d5db;
  223. padding: .5rem 1rem;
  224. height: fit-content;
  225. width: fit-content;
  226. display: flex;
  227. align-items: center;
  228. gap: .5rem;
  229. cursor: pointer;
  230. }
  231. .addTest>svg {
  232. width: .7rem;
  233. height: .7rem;
  234. fill: #6E7583;
  235. }
  236. .addTest>span {
  237. font-weight: bold;
  238. font-size: .9rem;
  239. color: #6b7280;
  240. }
  241. .testItem {
  242. width: 100%;
  243. height: auto;
  244. display: flex;
  245. align-items: center;
  246. gap: 1rem;
  247. flex-direction: column;
  248. }
  249. .ti_header {
  250. width: 100%;
  251. display: flex;
  252. align-items: center;
  253. justify-content: space-between;
  254. }
  255. .ti_header>span {
  256. font-size: 1rem;
  257. font-weight: 600;
  258. color: #ff9300;
  259. }
  260. .ti_h_edit {
  261. display: flex;
  262. align-items: center;
  263. gap: 1rem;
  264. }
  265. .ti_h_edit>span {
  266. width: 1.5rem;
  267. height: 1.5rem;
  268. display: flex;
  269. align-items: center;
  270. justify-content: center;
  271. background: #F9FAFB;
  272. border-radius: 4px;
  273. cursor: pointer;
  274. }
  275. .ti_h_edit>span>svg {
  276. width: 1rem;
  277. height: 1rem;
  278. fill: #6B7280;
  279. }
  280. .ti_title {
  281. width: 100%;
  282. height: fit-content;
  283. padding-bottom: 2rem;
  284. min-height: 4rem;
  285. background: #FAFBFC;
  286. border-radius: 8px;
  287. border: 1px solid #E5E7EB;
  288. position: relative;
  289. }
  290. .ti_t_input {
  291. width: 100%;
  292. height: 100%;
  293. padding: 1rem;
  294. box-sizing: border-box;
  295. border: none;
  296. outline: none;
  297. background: none;
  298. font-size: 1.2rem;
  299. resize: none;
  300. /* max-height: 10rem; */
  301. overflow: auto;
  302. /* padding-right: 2rem; */
  303. }
  304. .ti_t_input /deep/ .el-textarea__inner {
  305. padding: 0;
  306. width: 100%;
  307. height: 100%;
  308. box-sizing: border-box;
  309. border: none;
  310. outline: none;
  311. background: none;
  312. font-size: 1.2rem;
  313. resize: none;
  314. /* max-height: 10rem; */
  315. overflow: auto;
  316. }
  317. .uploadImage {
  318. position: absolute;
  319. bottom: 0.5rem;
  320. right: 0.5rem;
  321. background: #fff;
  322. border-radius: .5rem;
  323. display: flex;
  324. justify-content: center;
  325. align-items: center;
  326. border: 1px solid #E5E7EB;
  327. cursor: pointer;
  328. padding: .5rem;
  329. }
  330. .uploadImage>svg {
  331. width: 1rem;
  332. height: 1rem;
  333. }
  334. .checkList {
  335. width: 100%;
  336. height: auto;
  337. display: flex;
  338. flex-direction: column;
  339. gap: 1rem;
  340. padding-left: 4rem;
  341. }
  342. .checkItem {
  343. width: 100%;
  344. height: auto;
  345. display: flex;
  346. align-items: center;
  347. justify-content: flex-start;
  348. gap: .5rem;
  349. }
  350. .check {
  351. width: 1.1rem;
  352. height: 1.1rem;
  353. border: solid 1px #D1D5DB;
  354. border-radius: .25rem;
  355. cursor: pointer;
  356. display: flex;
  357. justify-content: center;
  358. align-items: center;
  359. }
  360. .checked {
  361. background: #FF9300;
  362. }
  363. .checked>svg {
  364. width: .7rem;
  365. height: .7rem;
  366. fill: #fff;
  367. }
  368. .checkItem>.el-input {
  369. width: calc(100% - 10rem);
  370. }
  371. .addCheck {
  372. border-radius: 5px;
  373. border: 1px dashed #d1d5db;
  374. padding: .3rem .8rem;
  375. height: fit-content;
  376. width: fit-content;
  377. display: flex;
  378. align-items: center;
  379. gap: .5rem;
  380. cursor: pointer;
  381. margin-left: 2.2rem;
  382. }
  383. .addCheck>svg {
  384. width: .5rem;
  385. height: .5rem;
  386. fill: #6E7583;
  387. }
  388. .addCheck>span {
  389. font-weight: bold;
  390. font-size: .8rem;
  391. color: #6b7280;
  392. }
  393. .btn {
  394. display: flex;
  395. align-items: center;
  396. gap: .25em;
  397. }
  398. .btn>div {
  399. width: 1.5rem;
  400. height: 1.5rem;
  401. display: flex;
  402. justify-content: center;
  403. align-items: center;
  404. background: #F9FAFB;
  405. border-radius: .4px;
  406. cursor: pointer;
  407. }
  408. .btn>div>svg {
  409. width: 1rem;
  410. height: 1rem;
  411. fill: #6B7280;
  412. }
  413. .explanation {
  414. width: 100%;
  415. height: auto;
  416. padding: 1rem;
  417. background: #FAFBFC;
  418. border-radius: 5px;
  419. display: flex;
  420. flex-direction: column;
  421. gap: 1rem;
  422. border-radius: .8rem;
  423. }
  424. .e_header {
  425. display: flex;
  426. align-items: center;
  427. justify-content: space-between;
  428. }
  429. .e_header>span {
  430. color: #6b7280;
  431. font-size: 1rem;
  432. font-weight: 500;
  433. }
  434. .e_header>div {
  435. display: flex;
  436. align-items: center;
  437. gap: .5rem;
  438. background: #ff9300;
  439. color: #fff;
  440. padding: .3rem .8rem;
  441. font-size: .8rem;
  442. font-weight: 500;
  443. border-radius: .5rem;
  444. cursor: pointer;
  445. }
  446. .e_header>div>svg {
  447. width: .8rem;
  448. height: .8rem;
  449. fill: #fff;
  450. }
  451. .explain_textarea {
  452. font-size: 1.2rem;
  453. }
  454. .imageList {
  455. width: 100%;
  456. height: auto;
  457. display: flex;
  458. flex-wrap: wrap;
  459. gap: 1rem;
  460. }
  461. .imageList>div{
  462. width: 100px;
  463. height: 100px;
  464. display: flex;
  465. align-items: center;
  466. justify-content: center;
  467. /* overflow: hidden; */
  468. border-radius: .5rem;
  469. position: relative;
  470. }
  471. .imageList>div:hover>svg{
  472. display: flex;
  473. }
  474. .imageList>div>svg{
  475. width: 1rem;
  476. height: 1rem;
  477. position: absolute;
  478. top: -.3rem;
  479. right: -.3rem;
  480. font-weight: 500;
  481. border-radius: .5rem;
  482. cursor: pointer;
  483. display: flex;
  484. align-items: center;
  485. justify-content: center;
  486. display: none;
  487. }
  488. </style>