FillDrag.vue 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. <template>
  2. <div class="fill-drag">
  3. <!-- 选项 -->
  4. <div class="fill-drag-options">
  5. <draggable
  6. v-model="curQue.options"
  7. group="option"
  8. animation="300"
  9. class="draggable-options"
  10. :sort="false"
  11. ghost-class="draggable-options-ghost"
  12. :disabled="isAnswerMode"
  13. :move="onMove"
  14. >
  15. <span
  16. v-for="({ text, imageList }, i) in curQue.options"
  17. :key="`option-${i}`"
  18. class="drag-option"
  19. :style="{
  20. cursor: `${isAnswerMode ? 'default' : 'pointer'}`,
  21. padding: `${imageList.length > 0 ? '0px' : '8px'}`
  22. }"
  23. >
  24. <template v-if="imageList.length > 0">
  25. <el-image :src="imageList[0].url" fit="fill" />
  26. </template>
  27. <template v-else>
  28. {{ text }}
  29. </template>
  30. </span>
  31. </draggable>
  32. </div>
  33. <!-- 填空 -->
  34. <div class="fill-drag-fills">
  35. <div
  36. v-for="(fill, i) in curQue.fills"
  37. :key="`fill-${i}`"
  38. class="drag-fill"
  39. :data-serial="i + 1"
  40. >
  41. <!-- 偏旁 -->
  42. <span class="drag-fill-space active" v-text="fill.side" />
  43. <div class="drag-fill-container">
  44. <span
  45. v-for="(drag, j) in fill.dragList"
  46. :key="j"
  47. :class="[
  48. 'drag-fill-space',
  49. `${drag.fillList.length > 0 ? 'active' : ''}`
  50. ]"
  51. >
  52. <draggable
  53. v-model="drag.fillList"
  54. class="draggable-fill"
  55. group="option"
  56. animation="300"
  57. :sort="false"
  58. :data-fill="i"
  59. :data-space="j"
  60. :disabled="isAnswerMode"
  61. :move="onMoveTo"
  62. @change="changeFill"
  63. >
  64. <span
  65. v-for="{ text, imageList } in drag.fillList"
  66. :key="text"
  67. :style="{
  68. cursor: `${isAnswerMode ? 'default' : 'pointer'}`,
  69. padding: `${imageList.length > 0 ? '0px' : '8px'}`
  70. }"
  71. >
  72. <template v-if="imageList.length > 0">
  73. <el-image :src="imageList[0].url" fit="fill" />
  74. </template>
  75. <template v-else>
  76. {{ text }}
  77. </template>
  78. </span>
  79. </draggable>
  80. </span>
  81. </div>
  82. <span
  83. class="drag-delete"
  84. :style="{
  85. cursor: `${isAnswerMode ? 'default' : 'pointer'}`
  86. }"
  87. @click="emptyFill(i)"
  88. >
  89. <el-image :src="require('../../../assets/NPC/delete-24.png')" />
  90. </span>
  91. </div>
  92. </div>
  93. </div>
  94. </template>
  95. <script>
  96. import draggable from "vuedraggable";
  97. export default {
  98. components: { draggable },
  99. props: {
  100. curQue: {
  101. type: Object,
  102. required: true
  103. },
  104. themeColor: {
  105. type: String,
  106. required: true
  107. }
  108. },
  109. data() {
  110. return {
  111. isAnswerMode: false,
  112. curDrag: {
  113. fillIndex: 0,
  114. spaceIndex: 0
  115. }
  116. };
  117. },
  118. created() {
  119. const Bookanswer = this.curQue.Bookanswer;
  120. if (Bookanswer) {
  121. this.isAnswerMode = true;
  122. Bookanswer.dragList.forEach(({ fillIndex, spaceIndex, ...data }) => {
  123. this.curQue.fills[fillIndex].dragList[spaceIndex].fillList = [
  124. { ...data }
  125. ];
  126. });
  127. } else {
  128. let Bookanswer = {
  129. dragList: []
  130. };
  131. this.$set(this.curQue, "Bookanswer", Bookanswer);
  132. }
  133. },
  134. methods: {
  135. onMove(e) {
  136. if (e.relatedContext.component.realList.length > 0) return false;
  137. let { fill, space } = e.to.dataset;
  138. this.curDrag = {
  139. fillIndex: fill,
  140. spaceIndex: space
  141. };
  142. return true;
  143. },
  144. onMoveTo(e) {
  145. if (
  146. e.to.classList.contains("draggable-fill") &&
  147. e.relatedContext.component.realList.length > 0
  148. ) { return false; }
  149. let { fill, space } = e.from.dataset;
  150. this.curDrag = {
  151. fillIndex: fill,
  152. spaceIndex: space
  153. };
  154. },
  155. changeFill({ added, removed }) {
  156. if (added) {
  157. this.curQue.Bookanswer.dragList.push({
  158. ...this.curDrag,
  159. ...added.element
  160. });
  161. }
  162. if (removed) {
  163. this.curQue.Bookanswer.dragList = this.curQue.Bookanswer.dragList.filter(
  164. ({ fillIndex, spaceIndex }) => {
  165. let { fillIndex: fIndex, spaceIndex: sIndex } = this.curDrag;
  166. if (fillIndex === fIndex && spaceIndex === sIndex) return false;
  167. return true;
  168. }
  169. );
  170. }
  171. },
  172. emptyFill(i) {
  173. if (this.isAnswerMode) return;
  174. this.curQue.fills[i].dragList.forEach(({ fillList }) => {
  175. if (fillList.length > 0) {
  176. this.curQue.options.push(...fillList.splice(0, 1));
  177. }
  178. });
  179. }
  180. }
  181. };
  182. </script>
  183. <style lang="scss" scoped>
  184. $image-size: 64px;
  185. .fill-drag {
  186. width: 100%;
  187. color: #000;
  188. margin-bottom: 16px;
  189. %drag-option {
  190. width: $image-size;
  191. height: $image-size;
  192. font-size: 48px;
  193. font-family: "FZJCGFKTK";
  194. border-radius: 8px;
  195. text-align: center;
  196. background-size: $image-size $image-size;
  197. overflow: hidden;
  198. .el-image {
  199. width: $image-size;
  200. height: $image-size;
  201. }
  202. }
  203. &-options {
  204. width: 100%;
  205. background-color: #f7f7f7;
  206. border: 1px solid #dedede;
  207. border-radius: 8px;
  208. padding: 24px;
  209. .draggable-options {
  210. display: flex;
  211. flex-wrap: wrap;
  212. min-height: 64px;
  213. column-gap: 16px;
  214. row-gap: 24px;
  215. .drag-option {
  216. @extend %drag-option;
  217. background-image: url("../../../assets/NPC/tian-zige.png");
  218. }
  219. }
  220. // 拖拽插件,占位符样式,需要加 !important
  221. .draggable-options-ghost {
  222. width: $image-size !important;
  223. height: $image-size !important;
  224. font-size: 48px !important;
  225. font-family: "FZJCGFKTK" !important;
  226. border-radius: 8px !important;
  227. text-align: center !important;
  228. background-size: $image-size $image-size !important;
  229. background-image: url("../../../assets/NPC/tian-zige.png") !important;
  230. }
  231. }
  232. &-fills {
  233. margin-left: 24px;
  234. .drag-fill {
  235. margin-top: 24px;
  236. display: flex;
  237. flex-wrap: no-wrap;
  238. align-items: center;
  239. column-gap: 16px;
  240. &::before {
  241. content: attr(data-serial) ".";
  242. display: inline-block;
  243. height: 16px;
  244. width: 16px;
  245. font-size: 16px;
  246. margin-right: 16px;
  247. }
  248. .drag-fill-container {
  249. display: flex;
  250. flex-wrap: wrap;
  251. align-items: center;
  252. column-gap: 16px;
  253. row-gap: 12px;
  254. }
  255. &-space {
  256. @extend %drag-option;
  257. min-width: 64px;
  258. background-image: url("../../../assets/NPC/tian-zige-noactive.png");
  259. &.active {
  260. background-image: url("../../../assets/NPC/tian-zige.png");
  261. }
  262. }
  263. .drag-delete {
  264. flex: 1;
  265. padding-right: 16px;
  266. .el-image {
  267. float: right;
  268. width: 24px;
  269. height: 24px;
  270. }
  271. }
  272. .draggable-fill {
  273. display: flex;
  274. align-items: center;
  275. flex-wrap: wrap;
  276. column-gap: 16px;
  277. row-gap: 12px;
  278. }
  279. }
  280. }
  281. }
  282. </style>