ScoringPanel.vue 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. <template>
  2. <scoring-panel-container
  3. v-model="modalVisible"
  4. title="键盘给分"
  5. modal-class="no-mask"
  6. :width="'388px'"
  7. :modal="false"
  8. :can-resize="'can-resize'"
  9. class="keybord-dialog"
  10. @close="onToggleClick"
  11. >
  12. <div class="scoring-panel-box" :class="getClass('modal-box')">
  13. <template v-for="(question, index) in questionList" :key="question.mainNumber + question.subNumber">
  14. <div v-if="dialogMode" class="flex dialog-name items-center">
  15. <p>{{ question.mainNumber }} - {{ question.subNumber }}</p>
  16. <p class="main-title">{{ question.mainTitle }}</p>
  17. </div>
  18. <scoring-panel-item
  19. v-model:score="scoreValues[index]"
  20. v-model:scoreValidFail="scoreValidFail[index]"
  21. :active="activeIndex === index"
  22. :modal="dialogMode"
  23. :toggle-modal="props.toggleModal && index === questionList.length - 1"
  24. :question="question"
  25. :large="props.large"
  26. :allow-submit="allowSubmit"
  27. @blur="() => onBlur(index)"
  28. @enter="() => onEnter(index)"
  29. @focused="() => onFocused(index)"
  30. @toggle-click="onToggleClick"
  31. ></scoring-panel-item>
  32. </template>
  33. </div>
  34. <template #footer>
  35. <el-button type="primary" class="full-w" :disabled="!allowSubmit" @click="onEnter(0)">确定</el-button>
  36. </template>
  37. </scoring-panel-container>
  38. </template>
  39. <script setup lang="ts" name="ScoringPanel">
  40. import { watch, withDefaults, ref, defineComponent, useSlots, computed, nextTick, onMounted } from 'vue'
  41. import { ElButton } from 'element-plus'
  42. import BaseDialog from '@/components/element/BaseDialog.vue'
  43. import ScoringPanelItem from './ScoringPanelItem.vue'
  44. import useVModel from '@/hooks/useVModel'
  45. import useVW from '@/hooks/useVW'
  46. import useFetch from '@/hooks/useFetch'
  47. import { sessionStorage } from '@/plugins/storage'
  48. import bus from '@/utils/bus'
  49. const props = withDefaults(
  50. defineProps<{
  51. /** 弹窗模式? */
  52. modal?: boolean
  53. /** 是否可以切换显示模式 */
  54. toggleModal?: boolean
  55. /** 显示隐藏 */
  56. visible?: boolean
  57. /** 分值 */
  58. score: (number | string)[]
  59. mainNumber?: number | null
  60. id?: number | null
  61. autoVisible?: boolean | undefined
  62. large?: boolean
  63. }>(),
  64. { modal: false, toggleModal: true, score: () => [], mainNumber: null, id: null, autoVisible: true, large: true }
  65. )
  66. const emits = defineEmits(['submit', 'update:score', 'update:visible', 'update:modal'])
  67. const dialogModeBeforeSubmit = ref<boolean>(false)
  68. const dialogMode = ref<boolean>(props.modal)
  69. const LessRenderComponent = defineComponent({
  70. name: 'LessRender',
  71. inheritAttrs: false,
  72. props: {
  73. modelValue: {
  74. type: Boolean,
  75. default: false,
  76. },
  77. },
  78. render() {
  79. return this.modelValue ? useSlots()?.default?.() : null
  80. },
  81. })
  82. const ScoringPanelContainer = computed(() => {
  83. return dialogMode.value ? BaseDialog : LessRenderComponent
  84. })
  85. const modalVisible = useVModel(props, 'visible')
  86. const scoreValues = useVModel(props, 'score')
  87. const activeIndex = ref<number | null>(0)
  88. const scoreValidFail = ref<boolean[]>([])
  89. watch(modalVisible, (val) => {
  90. activeIndex.value = 0
  91. let sessionKeyboardShowType = sessionStorage.get('dialogModeBeforeSubmit')
  92. dialogMode.value =
  93. typeof sessionKeyboardShowType === 'boolean' ? sessionKeyboardShowType : dialogModeBeforeSubmit.value
  94. })
  95. onMounted(() => {
  96. let sessionKeyboardShowType = sessionStorage.get('dialogModeBeforeSubmit')
  97. dialogMode.value =
  98. typeof sessionKeyboardShowType === 'boolean' ? sessionKeyboardShowType : dialogModeBeforeSubmit.value
  99. })
  100. const { fetch: getQuestionStruct, reset: resetQuestionStruct, result: questionStruct } = useFetch('getQuestionStruct')
  101. watch([() => props.id, () => props.autoVisible], () => {
  102. if (props.autoVisible) {
  103. modalVisible.value = !!props.id
  104. }
  105. scoreValues.value = []
  106. })
  107. watch(
  108. () => props.mainNumber,
  109. () => {
  110. /** reset scores */
  111. scoreValues.value = []
  112. if (props.mainNumber) {
  113. resetQuestionStruct()
  114. getQuestionStruct({ mainNumber: props.mainNumber })
  115. }
  116. },
  117. { immediate: true }
  118. )
  119. const questionList = computed(() => {
  120. if (!questionStruct.value) {
  121. return []
  122. }
  123. const { mainNumber, mainTitle, questionList = [] } = questionStruct.value
  124. return questionList.map((q) => ({ ...q, mainNumber, mainTitle }))
  125. })
  126. const allowSubmit = computed(() => {
  127. let filterArr = scoreValues.value.filter((score) => score != undefined && score !== '')
  128. // return scoreValues.value?.length === questionList.value?.length
  129. return filterArr.length === questionList.value?.length
  130. })
  131. const getClass = (val: string, callback?: string) => {
  132. return dialogMode.value ? val : callback || ''
  133. }
  134. const onSubmit = () => {
  135. if (!scoreValidFail.value.some((valid) => valid)) {
  136. emits('submit', questionStruct.value)
  137. }
  138. }
  139. const onEnter = (index: number) => {
  140. dialogModeBeforeSubmit.value = dialogMode.value
  141. sessionStorage.set('dialogModeBeforeSubmit', dialogModeBeforeSubmit.value)
  142. nextTick(() => {
  143. // console.log('index:', index)
  144. // console.log('scoreValues.value.length:', scoreValues.value.length)
  145. // console.log('questionList.value?.length:', questionList.value?.length)
  146. let filterArr = scoreValues.value.filter((score) => score != undefined)
  147. // if (scoreValues.value.length >= questionList.value?.length) {
  148. if (filterArr.length >= questionList.value?.length) {
  149. const nullScoreIndex = scoreValues.value?.findIndex((v) => !`${v}`)
  150. const validFailIndexIndex = scoreValidFail.value?.findIndex((v) => !!v)
  151. if (nullScoreIndex >= 0) {
  152. activeIndex.value = nullScoreIndex
  153. } else if (validFailIndexIndex >= 0) {
  154. activeIndex.value = validFailIndexIndex
  155. } else {
  156. onSubmit()
  157. }
  158. } else {
  159. activeIndex.value = index + 1
  160. }
  161. })
  162. }
  163. const onFocused = (index: number) => {
  164. activeIndex.value = index
  165. }
  166. const onBlur = (index: number) => {
  167. if (activeIndex.value === index) {
  168. activeIndex.value = null
  169. }
  170. }
  171. const onToggleClick = () => {
  172. if (modalVisible.value) {
  173. dialogModeBeforeSubmit.value = dialogMode.value ? false : true
  174. sessionStorage.set('dialogModeBeforeSubmit', dialogModeBeforeSubmit.value)
  175. }
  176. dialogMode.value = props.toggleModal ? !dialogMode.value : dialogMode.value
  177. if (!props.toggleModal) {
  178. modalVisible.value = false
  179. }
  180. }
  181. bus.on('mark-method-toggle', () => {
  182. onToggleClick()
  183. })
  184. </script>
  185. <style scoped lang="scss">
  186. .scoring-panel-box {
  187. padding-bottom: 4px;
  188. background-color: #fff;
  189. }
  190. .modal-box {
  191. max-height: 50vh;
  192. min-height: 8vw;
  193. .dialog-name {
  194. color: $color--primary;
  195. font-weight: bold;
  196. padding-left: 10px;
  197. }
  198. }
  199. </style>