ScoringPanel.vue 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. <template>
  2. <scoring-panel-container
  3. v-model="modalVisible"
  4. draggable
  5. title="键盘给分"
  6. modal-class="no-mask"
  7. :width="useVW(550)"
  8. :modal="false"
  9. @close="onToggleClick"
  10. >
  11. <div class="scoring-panel-box" :class="getClass('modal-box')">
  12. <template v-for="(question, index) in questionList" :key="question.mainNumber + question.subNumber">
  13. <scoring-panel-item
  14. v-model:score="scoreValues[index]"
  15. :active="activeIndex === index"
  16. :modal="dialogMode"
  17. :toggle-modal="props.toggleModal && index === 0"
  18. :question="question"
  19. @enter="() => onEnter(index)"
  20. @focused="() => onFocused(index)"
  21. @toggle-click="onToggleClick"
  22. ></scoring-panel-item>
  23. </template>
  24. </div>
  25. <template #footer>
  26. <el-button type="primary" class="full-w m-t-base" :disabled="!allowSubmit" @click="onSubmit">确定</el-button>
  27. </template>
  28. </scoring-panel-container>
  29. </template>
  30. <script setup lang="ts" name="ScoringPanel">
  31. import { watch, withDefaults, ref, defineComponent, useSlots, computed } from 'vue'
  32. import { ElButton } from 'element-plus'
  33. import BaseDialog from '@/components/element/BaseDialog.vue'
  34. import ScoringPanelItem from './ScoringPanelItem.vue'
  35. import useVModel from '@/hooks/useVModel'
  36. import useVW from '@/hooks/useVW'
  37. import useFetch from '@/hooks/useFetch'
  38. const props = withDefaults(
  39. defineProps<{
  40. /** 弹窗模式? */
  41. modal?: boolean
  42. /** 是否可以切换显示模式 */
  43. toggleModal?: boolean
  44. /** 显示隐藏 */
  45. visible?: boolean
  46. /** 分值 */
  47. score: (number | string)[]
  48. mainNumber?: number | null
  49. }>(),
  50. { modal: false, toggleModal: true, score: () => [], mainNumber: null }
  51. )
  52. const emits = defineEmits(['submit', 'update:score', 'update:visible'])
  53. const dialogMode = ref<boolean>(props.modal)
  54. const LessRenderComponent = defineComponent({
  55. name: 'LessRender',
  56. inheritAttrs: false,
  57. props: {
  58. modelValue: {
  59. type: Boolean,
  60. default: false,
  61. },
  62. },
  63. render() {
  64. return this.modelValue ? useSlots()?.default?.() : null
  65. },
  66. })
  67. const ScoringPanelContainer = computed(() => {
  68. return dialogMode.value ? BaseDialog : LessRenderComponent
  69. })
  70. const modalVisible = useVModel(props, 'visible')
  71. watch(modalVisible, () => {
  72. if (!modalVisible.value) {
  73. activeIndex.value = 0
  74. }
  75. })
  76. const getClass = (val: string, callback?: string) => {
  77. return dialogMode.value ? val : callback || ''
  78. }
  79. const scoreValues = useVModel(props, 'score')
  80. const activeIndex = ref<number>(0)
  81. const { fetch: getQuestionStruct, reset: resetQuestionStruct, result: questionStruct } = useFetch('getQuestionStruct')
  82. watch(
  83. () => props.mainNumber,
  84. () => {
  85. /** reset scores */
  86. scoreValues.value = []
  87. /** auto show */
  88. modalVisible.value = !!props.mainNumber
  89. if (props.mainNumber) {
  90. resetQuestionStruct()
  91. getQuestionStruct({ mainNumber: props.mainNumber })
  92. }
  93. },
  94. { immediate: true }
  95. )
  96. const questionList = computed(() => {
  97. if (!questionStruct.value) {
  98. return []
  99. }
  100. const { mainNumber, mainTitle, questionList = [] } = questionStruct.value
  101. return questionList.map((q) => ({ ...q, mainNumber, mainTitle }))
  102. })
  103. const allowSubmit = computed(() => {
  104. return questionList.value?.length && scoreValues.value?.length === questionList.value?.length
  105. })
  106. const onSubmit = () => {
  107. emits('submit', questionStruct.value)
  108. }
  109. const onEnter = (index: number) => {
  110. activeIndex.value = index + 1
  111. if (activeIndex.value >= questionList.value?.length) {
  112. onSubmit()
  113. }
  114. }
  115. const onFocused = (index: number) => {
  116. activeIndex.value = index
  117. }
  118. const onToggleClick = () => {
  119. dialogMode.value = props.toggleModal ? !dialogMode.value : dialogMode.value
  120. if (!props.toggleModal) {
  121. modalVisible.value = false
  122. }
  123. }
  124. </script>
  125. <style scoped lang="scss">
  126. .modal-box {
  127. max-height: 50vh;
  128. min-height: 8vw;
  129. }
  130. </style>