SelectDrag.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. <!-- 选择 -> 拖拽 -->
  2. <template>
  3. <div
  4. class="select-drag select-drag-phone"
  5. v-if="curQue && judgeAnswer == 'standardAnswer' ? IsError : true"
  6. >
  7. <!-- 选项 -->
  8. <div class="select-drag-options">
  9. <draggable
  10. v-model="curQue.options"
  11. group="option"
  12. animation="300"
  13. class="draggable-options"
  14. :sort="false"
  15. :disabled="isAnswerMode"
  16. :move="onMove"
  17. >
  18. <span
  19. v-for="(item, i) in curQue.options"
  20. :key="`option-${i}`"
  21. class="drag-option"
  22. :style="{
  23. cursor: `${isAnswerMode ? 'default' : 'pointer'}`
  24. }"
  25. >
  26. <template v-if="item.wordsList.length > 0">
  27. <div>
  28. <span
  29. v-for="({ chs, pinyin }, j) in item.wordsList"
  30. :key="`${isPyTop ? 'pinyin' : 'chs'}-${j}`"
  31. :class="[`${isPyTop ? 'pinyin' : 'chs'}`]"
  32. v-text="`${isPyTop ? pinyin : chs}`"
  33. />
  34. </div>
  35. <div>
  36. <span
  37. v-for="({ chs, pinyin }, j) in item.wordsList"
  38. :key="`${isPyTop ? 'chs' : 'pinyin'}-${j}`"
  39. :class="[`${isPyTop ? 'chs' : 'pinyin'}`]"
  40. v-text="`${isPyTop ? chs : pinyin}`"
  41. />
  42. </div>
  43. </template>
  44. <div v-else>
  45. <span
  46. :key="`${isPyTop ? 'chs' : 'pinyin'}-${j}`"
  47. :class="['chs']"
  48. v-text="`${item.sentence}`"
  49. />
  50. </div>
  51. </span>
  52. </draggable>
  53. </div>
  54. <!-- 句子 -->
  55. <div class="select-drag-sentences">
  56. <div
  57. v-for="(sentence, i) in judgeAnswer == 'standardAnswer'
  58. ? CorrectData.sentences
  59. : curQue.sentences"
  60. :key="`sentence-${i}`"
  61. :data-serial="judgeAnswer == 'standardAnswer' ? changeNumber(i) : i + 1"
  62. class="drag-sentence"
  63. >
  64. <span
  65. v-for="(item, j) in sentence"
  66. :key="`sentence-item-${j}`"
  67. :class="[
  68. 'drag-sentence-item',
  69. `${item.isSpace && item.dragList.length <= 0 ? 'space' : ''}`,
  70. changeClass(i, item.index, j),
  71. hasPy ? 'drag-sentence-item-hasPy' : ''
  72. ]"
  73. :style="{
  74. 'grid-template': item.isSpace
  75. ? ''
  76. : `repeat(${item.wordsList.length}, auto) / repeat(${item.wordsList.length}, auto)`,
  77. fontSize: baseSizePhone + 2 + 'px'
  78. }"
  79. >
  80. <!-- 空格 -> 拖拽 -->
  81. <template v-if="item.isSpace">
  82. <draggable
  83. v-model="item.dragList"
  84. class="draggable-space"
  85. :data-sentence="i"
  86. :data-subsection="j"
  87. :sort="false"
  88. :disabled="isAnswerMode"
  89. group="option"
  90. animation="300"
  91. :move="onMoveTo"
  92. @change="change({ ...arguments }, i)"
  93. >
  94. <div
  95. :class="[`${item.dragList.length > 0 ? 'drag-list' : ''}`]"
  96. :style="{
  97. 'grid-template':
  98. item.dragList.length > 0
  99. ? `repeat(${item.dragList[0].wordsList.length}, auto) / repeat(${item.dragList[0].wordsList.length}, auto)`
  100. : '',
  101. cursor: `${isAnswerMode ? 'default' : 'pointer'}`
  102. }"
  103. >
  104. <template v-if="item.dragList.length > 0">
  105. <template v-if="item.dragList[0].wordsList.length > 0">
  106. <span
  107. v-for="({ chs, pinyin }, k) in item.dragList[0].wordsList"
  108. :key="`${isPyTop ? 'pinyin' : 'chs'}-${k}`"
  109. :class="[`${isPyTop ? 'pinyin' : 'chs'}`]"
  110. v-text="isPyTop ? pinyin : chs"
  111. :style="{
  112. fontSize: isPyTop
  113. ? baseSizePhone + 'px'
  114. : baseSizePhone + 2 + 'px'
  115. }"
  116. />
  117. <span
  118. v-for="({ chs, pinyin }, k) in item.dragList[0].wordsList"
  119. :key="`${isPyTop ? 'chs' : 'pinyin'}-${k}`"
  120. :class="[`${isPyTop ? 'chs' : 'pinyin'}`]"
  121. v-text="isPyTop ? chs : pinyin"
  122. :style="{
  123. fontSize: isPyTop
  124. ? baseSizePhone + 2 + 'px'
  125. : baseSizePhone + 'px'
  126. }"
  127. />
  128. </template>
  129. <span
  130. v-else
  131. :class="['chs']"
  132. v-text="item.dragList[0].sentence"
  133. :style="{
  134. fontSize: baseSizePhone + 2 + 'px'
  135. }"
  136. />
  137. </template>
  138. </div>
  139. </draggable>
  140. </template>
  141. <template v-else-if="item.wordsList.length > 0">
  142. <span
  143. v-for="({ chs, pinyin }, k) in item.wordsList"
  144. :key="`${isPyTop ? 'pinyin' : 'chs'}-${k}`"
  145. :class="[`${isPyTop ? 'pinyin' : 'chs'}`]"
  146. :style="{
  147. fontSize: isPyTop
  148. ? baseSizePhone + 'px'
  149. : baseSizePhone + 2 + 'px'
  150. }"
  151. >
  152. {{ isPyTop ? pinyin : chs }}
  153. </span>
  154. <span
  155. v-for="({ chs, pinyin }, k) in item.wordsList"
  156. :key="`${isPyTop ? 'chs' : 'pinyin'}-${k}`"
  157. :class="[`${isPyTop ? 'chs' : 'pinyin'}`]"
  158. :style="{
  159. fontSize: isPyTop
  160. ? baseSizePhone + 2 + 'px'
  161. : baseSizePhone + 'px'
  162. }"
  163. >
  164. {{ isPyTop ? chs : pinyin }}
  165. </span>
  166. </template>
  167. <span
  168. :class="['chs']"
  169. v-else
  170. :style="{
  171. fontSize: baseSizePhone + 2 + 'px'
  172. }"
  173. >
  174. {{ item.sentence }}
  175. </span>
  176. </span>
  177. </div>
  178. </div>
  179. </div>
  180. </template>
  181. <script>
  182. import draggable from "vuedraggable";
  183. export default {
  184. components: { draggable },
  185. props: {
  186. curQue: {
  187. type: Object,
  188. required: true
  189. },
  190. themeColor: {
  191. type: String,
  192. required: true
  193. },
  194. TaskModel: {
  195. type: String,
  196. required: true
  197. },
  198. judgeAnswer: {
  199. type: String,
  200. required: true
  201. },
  202. baseSizePhone: {
  203. type: Number
  204. }
  205. },
  206. data() {
  207. return {
  208. isAnswerMode: false,
  209. curDrag: {
  210. sentenceIndex: 0,
  211. subsectionIndex: 0
  212. },
  213. IsError: false,
  214. CorrectData: null,
  215. hasPy: false
  216. };
  217. },
  218. computed: {
  219. isPyTop() {
  220. return this.curQue.pyPosition === "top";
  221. }
  222. },
  223. created() {
  224. const Bookanswer = this.curQue.Bookanswer;
  225. if (Bookanswer) {
  226. this.isAnswerMode = true;
  227. if (this.judgeAnswer == "userAnswer") {
  228. } else if (this.judgeAnswer == "standardAnswer") {
  229. let data = JSON.parse(JSON.stringify(this.curQue));
  230. let arr = [];
  231. data.sentences.forEach((item, index) => {
  232. let flag = false;
  233. item.forEach((items, indexs) => {
  234. if (items.isSpace) {
  235. if (
  236. this.curQue.Bookanswer.answerList[index][items.index]
  237. .userAnswerJudge == "[JUDGE##F##JUDGE]"
  238. ) {
  239. if (!flag) {
  240. flag = true;
  241. }
  242. }
  243. }
  244. });
  245. arr.push(flag);
  246. });
  247. arr.forEach((item, index) => {
  248. if (!item) {
  249. data.sentences.splice(index, 1);
  250. }
  251. });
  252. data.sentences.forEach((item, index) => {
  253. item.forEach((items, indexs) => {
  254. if (items.isSpace) {
  255. items.dragList = [];
  256. this.curQue.oldOptions.forEach(op => {
  257. if (items.answer == op.sentence) {
  258. items.dragList.push(op);
  259. }
  260. });
  261. }
  262. });
  263. });
  264. this.CorrectData = data;
  265. }
  266. this.iSErrorEvent();
  267. } else {
  268. let Bookanswer = {
  269. dragList: [],
  270. answerList: []
  271. };
  272. this.curQue.oldOptions = JSON.parse(JSON.stringify(this.curQue.options));
  273. this.curQue.sentences.forEach(item => {
  274. let arr = [];
  275. let index = 0;
  276. item.forEach((items, i) => {
  277. if (items.isSpace) {
  278. let obj = {
  279. userAnswerJudge: "",
  280. answer: items.answer,
  281. index: index
  282. };
  283. items.index = index;
  284. if (items.answer) {
  285. obj.userAnswerJudge = "[JUDGE##F##JUDGE]";
  286. }
  287. arr.push(obj);
  288. index++;
  289. }
  290. });
  291. Bookanswer.dragList.push([]);
  292. Bookanswer.answerList.push(arr);
  293. });
  294. this.$set(this.curQue, "Bookanswer", Bookanswer);
  295. }
  296. this.curQue.sentences.forEach(item => {
  297. item.forEach((items, i) => {
  298. if (!items.isSpace) {
  299. items.wordsList.forEach(itemw => {
  300. if (itemw.pinyin) {
  301. this.hasPy = true;
  302. }
  303. });
  304. }
  305. });
  306. });
  307. },
  308. methods: {
  309. // 计算序号
  310. changeNumber(i) {
  311. let index = null;
  312. this.curQue.sentences.forEach((item, indexs) => {
  313. let flag = true;
  314. if (this.CorrectData.sentences[i].length == item.length) {
  315. item.forEach((items, indexss) => {
  316. if (items.isSpace) {
  317. if (
  318. this.CorrectData.sentences[i][indexss].answer != items.answer
  319. ) {
  320. flag = false;
  321. }
  322. } else {
  323. if (
  324. this.CorrectData.sentences[i][indexss].sentence !=
  325. items.sentence
  326. ) {
  327. flag = false;
  328. }
  329. }
  330. });
  331. } else {
  332. flag = false;
  333. }
  334. if (flag) {
  335. index = indexs;
  336. }
  337. });
  338. return index + 1;
  339. },
  340. changeClass(index, indexs, indexss) {
  341. let className = "";
  342. if (Object.prototype.toString.call(index).indexOf("Number") != -1) {
  343. if (
  344. this.judgeAnswer == "studentAnswer" ||
  345. this.judgeAnswer == "userAnswer"
  346. ) {
  347. if (this.curQue.Bookanswer.answerList[index][indexs]) {
  348. if (
  349. this.curQue.Bookanswer.answerList[index][indexs].userAnswerJudge
  350. ) {
  351. if (
  352. this.curQue.Bookanswer.answerList[index][indexs]
  353. .userAnswerJudge == "[JUDGE##T##JUDGE]"
  354. ) {
  355. className = "correct";
  356. } else {
  357. className = "error";
  358. }
  359. }
  360. }
  361. } else if (this.judgeAnswer == "standardAnswer") {
  362. if (this.CorrectData.sentences[index][indexss].isSpace) {
  363. if (
  364. this.CorrectData.sentences[index][indexss].dragList.length > 0
  365. ) {
  366. className = "correct";
  367. }
  368. }
  369. }
  370. }
  371. return className;
  372. },
  373. onMove(e) {
  374. if (e.relatedContext.component.realList.length > 0) return false;
  375. let { sentence, subsection } = e.to.dataset;
  376. this.curDrag = {
  377. sentenceIndex: sentence,
  378. subsectionIndex: subsection
  379. };
  380. return true;
  381. },
  382. onMoveTo(e) {
  383. if (
  384. e.to.classList.contains("draggable-space") &&
  385. e.relatedContext.component.realList.length > 0
  386. ) {
  387. return false;
  388. }
  389. let { sentence, subsection } = e.from.dataset;
  390. this.curDrag = {
  391. sentenceIndex: sentence,
  392. subsectionIndex: subsection
  393. };
  394. },
  395. change(obj, i) {
  396. if (obj[0].added) {
  397. this.curQue.Bookanswer.dragList[i].push({
  398. ...this.curDrag,
  399. ...obj[0].added.element
  400. });
  401. }
  402. if (obj[0].removed) {
  403. this.curQue.Bookanswer.dragList[i] = this.curQue.Bookanswer.dragList[
  404. i
  405. ].filter(({ sentenceIndex, subsectionIndex }) => {
  406. let {
  407. sentenceIndex: senIndex,
  408. subsectionIndex: subIndex
  409. } = this.curDrag;
  410. if (sentenceIndex === senIndex && subsectionIndex === subIndex) {
  411. return false;
  412. }
  413. return true;
  414. });
  415. }
  416. this.changeuserAnswerJudge();
  417. },
  418. // 判断对错
  419. changeuserAnswerJudge() {
  420. this.curQue.sentences.forEach((item, index) => {
  421. item.forEach((items, indexs) => {
  422. if (items.isSpace) {
  423. if (items.answer) {
  424. if (items.dragList) {
  425. if (items.dragList.length > 0) {
  426. if (items.answer == items.dragList[0].sentence) {
  427. this.curQue.Bookanswer.answerList[index][
  428. items.index
  429. ].userAnswerJudge = "[JUDGE##T##JUDGE]";
  430. } else {
  431. this.curQue.Bookanswer.answerList[index][
  432. items.index
  433. ].userAnswerJudge = "[JUDGE##F##JUDGE]";
  434. }
  435. } else {
  436. this.curQue.Bookanswer.answerList[index][
  437. items.index
  438. ].userAnswerJudge = "[JUDGE##F##JUDGE]";
  439. }
  440. }
  441. }
  442. }
  443. });
  444. });
  445. },
  446. // 判断是否有错的
  447. iSErrorEvent() {
  448. let flag = false;
  449. this.curQue.Bookanswer.answerList.forEach(item => {
  450. item.forEach(items => {
  451. if (items.userAnswerJudge == "[JUDGE##F##JUDGE]") {
  452. flag = true;
  453. }
  454. });
  455. });
  456. if (flag) {
  457. this.IsError = true;
  458. } else {
  459. this.IsError = false;
  460. }
  461. }
  462. }
  463. };
  464. </script>
  465. <style lang="scss" scoped>
  466. .select-drag {
  467. width: 100%;
  468. color: #000;
  469. margin-bottom: 16px;
  470. .pinyin {
  471. font-family: "GB-PINYINOK-B";
  472. font-size: 14px;
  473. line-height: 1.3;
  474. }
  475. .chs {
  476. font-family: "FZJCGFKTK";
  477. font-size: 16px;
  478. line-height: 1.5;
  479. }
  480. &-options {
  481. width: 100%;
  482. // background-color: #f7f7f7;
  483. border: 1px solid #dedede;
  484. border-radius: 8px;
  485. padding: 24px;
  486. .draggable-options {
  487. display: flex;
  488. flex-wrap: wrap;
  489. column-gap: 6px;
  490. row-gap: 6px;
  491. .drag-option {
  492. min-width: 66px;
  493. // height: 58px;
  494. text-align: center;
  495. padding: 4px 10px;
  496. // background-color: #fff;
  497. border: 1px solid #dedede;
  498. border-radius: 8px;
  499. }
  500. }
  501. }
  502. &-phone {
  503. .select-drag-options {
  504. padding: 10px;
  505. .draggable-options {
  506. gap: 6px;
  507. }
  508. }
  509. }
  510. &-sentences {
  511. .drag-sentence {
  512. margin-top: 10px;
  513. display: flex;
  514. align-items: center;
  515. flex-flow: wrap;
  516. row-gap: 5px;
  517. .correct {
  518. background: rgba(44, 167, 103, 0.1);
  519. /* 正确答案 */
  520. border: 1px solid #2ca767;
  521. }
  522. .error {
  523. background: rgba(237, 52, 45, 0.1);
  524. /* 错误颜色 */
  525. border: 1px solid #ed342d;
  526. }
  527. &::before {
  528. content: attr(data-serial);
  529. display: inline-block;
  530. text-align: center;
  531. color: #fff;
  532. font-size: 16px;
  533. line-height: 1.5;
  534. width: 24px;
  535. height: 24px;
  536. border-radius: 50%;
  537. background-color: #32a5d8;
  538. margin-right: 12px;
  539. flex-shrink: 0;
  540. }
  541. &-item {
  542. padding: 4px 10px;
  543. // height: 58px;
  544. min-height: 34px;
  545. // background-color: #fff;
  546. border: 1px solid #dedede;
  547. border-radius: 8px;
  548. margin-left: 4px;
  549. display: grid;
  550. column-gap: 4px;
  551. &-hasPy {
  552. height: 58px;
  553. }
  554. > :not(:first-child) {
  555. text-align: center;
  556. }
  557. &.space {
  558. min-width: 96px;
  559. // background-color: #f1f1f1;
  560. }
  561. .drag-list {
  562. display: grid;
  563. column-gap: 4px;
  564. > :not(:first-child) {
  565. text-align: center;
  566. }
  567. }
  568. }
  569. }
  570. }
  571. }
  572. </style>