123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- <template>
- <scoring-panel-container
- v-model="modalVisible"
- title="键盘给分"
- modal-class="no-mask"
- :width="'388px'"
- :modal="false"
- :can-resize="'can-resize'"
- class="keybord-dialog"
- @close="onToggleClick"
- >
- <div v-loading="props.loading" class="scoring-panel-box" :class="getClass('modal-box')">
- <template v-for="(question, index) in questionList" :key="question.mainNumber + question.subNumber">
- <div v-if="dialogMode" class="flex dialog-name items-center">
- <p>{{ question.mainNumber }} - {{ question.subNumber }}</p>
- <p class="main-title">{{ question.mainTitle }}</p>
- </div>
- <scoring-panel-item
- :id="props.id"
- v-model:score="scoreValues[index]"
- v-model:scoreValidFail="scoreValidFail[index]"
- :active="activeIndex === index"
- :modal="dialogMode"
- :toggle-modal="props.toggleModal && index === questionList.length - 1"
- :show-confirm-btn="index == questionList.length - 1"
- :show-all-paper-btn="props.showAllPaperBtn"
- :question="question"
- :large="props.large"
- :allow-submit="allowSubmit"
- :cannot-toggle="props.cannotToggle"
- :loading="props.loading"
- @blur="() => onBlur(index)"
- @enter="() => onEnter(index)"
- @focused="() => onFocused(index)"
- @toggle-click="onToggleClick"
- @view-papers="() => onViewPapers()"
- ></scoring-panel-item>
- </template>
- </div>
- <template #footer>
- <el-button type="primary" class="full-w" :disabled="buttonDisabled" @click="onEnter(0)">{{
- buttonText
- }}</el-button>
- </template>
- </scoring-panel-container>
- </template>
- <script setup lang="ts" name="ScoringPanel">
- import { watch, withDefaults, ref, defineComponent, useSlots, computed, nextTick, onMounted, onUnmounted } from 'vue'
- import { ElButton } from 'element-plus'
- import BaseDialog from '@/components/element/BaseDialog.vue'
- import ScoringPanelItem from './ScoringPanelItem.vue'
- import useVModel from '@/hooks/useVModel'
- import useVW from '@/hooks/useVW'
- import useFetch from '@/hooks/useFetch'
- import { sessionStorage } from '@/plugins/storage'
- import bus from '@/utils/bus'
- import useMarkStore from '@/store/mark'
- const markStore = useMarkStore()
- const props = withDefaults(
- defineProps<{
- /** 弹窗模式? */
- modal?: boolean
- /** 是否可以切换显示模式 */
- toggleModal?: boolean
- /** 显示隐藏 */
- visible?: boolean
- /** 分值 */
- score: (number | string)[]
- // mainNumber?: number | null
- mainNumber?: any
- subjectCode?: any
- id?: any
- autoVisible?: boolean | undefined
- large?: boolean
- cannotToggle?: boolean
- loading?: boolean
- showAllPaperBtn?: boolean
- }>(),
- {
- modal: false,
- toggleModal: true,
- score: () => [],
- mainNumber: null,
- subjectCode: null,
- id: null,
- autoVisible: true,
- large: true,
- cannotToggle: false,
- loading: false,
- showAllPaperBtn: false,
- }
- )
- const emits = defineEmits(['submit', 'update:score', 'update:visible', 'update:modal', 'view-papers'])
- const dialogModeBeforeSubmit = ref<boolean>(false)
- const dialogMode = ref<boolean>(props.modal)
- const LessRenderComponent = defineComponent({
- name: 'LessRender',
- inheritAttrs: false,
- props: {
- modelValue: {
- type: Boolean,
- default: false,
- },
- },
- render() {
- return this.modelValue ? useSlots()?.default?.() : null
- },
- })
- const ScoringPanelContainer = computed(() => {
- return dialogMode.value ? BaseDialog : LessRenderComponent
- })
- const modalVisible = useVModel(props, 'visible')
- const scoreValues = useVModel(props, 'score')
- const activeIndex = ref<number | null>(0)
- const scoreValidFail = ref<boolean[]>([])
- watch(modalVisible, (val) => {
- activeIndex.value = 0
- let sessionKeyboardShowType = sessionStorage.get('dialogModeBeforeSubmit')
- dialogMode.value =
- typeof sessionKeyboardShowType === 'boolean' ? sessionKeyboardShowType : dialogModeBeforeSubmit.value
- })
- onMounted(() => {
- let sessionKeyboardShowType = sessionStorage.get('dialogModeBeforeSubmit')
- dialogMode.value =
- typeof sessionKeyboardShowType === 'boolean' ? sessionKeyboardShowType : dialogModeBeforeSubmit.value
- })
- const { fetch: getQuestionStruct, reset: resetQuestionStruct, result: questionStruct } = useFetch('getQuestionStruct')
- watch([() => props.id, () => props.autoVisible], () => {
- if (props.autoVisible) {
- modalVisible.value = !!props.id
- }
- scoreValues.value = []
- })
- watch(
- () => props.mainNumber,
- () => {
- /** reset scores */
- scoreValues.value = []
- if (props.mainNumber) {
- resetQuestionStruct()
- getQuestionStruct({ mainNumber: props.mainNumber, subjectCode: props.subjectCode })
- }
- },
- { immediate: true }
- )
- const questionList = computed(() => {
- if (!questionStruct.value) {
- return []
- }
- const { mainNumber, mainTitle, questionList = [] } = questionStruct.value
- // 更新分数端评卷时间
- const markDelay = questionStruct.value.markDelay ? JSON.parse(questionStruct.value.markDelay) : []
- const getMarkLevelSpeedLimit = (score: number): number => {
- if (markDelay.length) {
- const speedLimit = markDelay.find((limit) => {
- return limit.endScore >= score && limit.startScore <= score
- })
- return speedLimit?.minMarkTime || 0
- } else {
- return 0
- }
- }
- return questionList.map((q) => ({
- ...q,
- mainNumber,
- mainTitle,
- markSpeedLimit: getMarkLevelSpeedLimit(q.totalScore),
- }))
- })
- const allowSubmit = computed(() => {
- let filterArr = scoreValues.value.filter((score) => score != undefined && score !== '')
- // return scoreValues.value?.length === questionList.value?.length
- return filterArr.length === questionList.value?.length
- })
- // 倒计时相关计算属性
- const isCountingDown = computed(() => markStore.isCountingDown)
- const buttonText = computed(() => markStore.buttonText)
- const buttonDisabled = computed(() => {
- return isCountingDown.value || !allowSubmit.value
- })
- // 启动倒计时
- const startCountdown = () => {
- const markSpeedLimit = questionList.value[activeIndex.value]?.markSpeedLimit
- markStore.startCountdown(markSpeedLimit)
- }
- const currentQuestion = computed(() => {
- return questionList.value[activeIndex.value]
- })
- // 监听questionList变化,启动倒计时
- watch(
- () => currentQuestion.value,
- () => {
- startCountdown()
- },
- { immediate: true, deep: true }
- )
- const getClass = (val: string, callback?: string) => {
- return dialogMode.value ? val : callback || ''
- }
- const onSubmit = () => {
- if (!scoreValidFail.value.some((valid) => valid)) {
- emits('submit', questionStruct.value)
- }
- }
- const onEnter = (index: number) => {
- dialogModeBeforeSubmit.value = dialogMode.value
- sessionStorage.set('dialogModeBeforeSubmit', dialogModeBeforeSubmit.value)
- nextTick(() => {
- // console.log('index:', index)
- // console.log('scoreValues.value.length:', scoreValues.value.length)
- // console.log('questionList.value?.length:', questionList.value?.length)
- let filterArr = scoreValues.value.filter((score) => score != undefined)
- // if (scoreValues.value.length >= questionList.value?.length) {
- if (filterArr.length >= questionList.value?.length) {
- const nullScoreIndex = scoreValues.value?.findIndex((v) => !`${v}`)
- const validFailIndexIndex = scoreValidFail.value?.findIndex((v) => !!v)
- if (nullScoreIndex >= 0) {
- activeIndex.value = nullScoreIndex
- } else if (validFailIndexIndex >= 0) {
- activeIndex.value = validFailIndexIndex
- } else {
- onSubmit()
- }
- } else {
- activeIndex.value = index + 1
- }
- })
- }
- const onFocused = (index: number) => {
- activeIndex.value = index
- }
- const onBlur = (index: number) => {
- if (activeIndex.value === index) {
- // activeIndex.value = null
- }
- }
- const onViewPapers = () => {
- emits('view-papers')
- }
- const onToggleClick = () => {
- if (modalVisible.value) {
- dialogModeBeforeSubmit.value = dialogMode.value ? false : true
- sessionStorage.set('dialogModeBeforeSubmit', dialogModeBeforeSubmit.value)
- }
- dialogMode.value = props.toggleModal ? !dialogMode.value : dialogMode.value
- if (!props.toggleModal) {
- modalVisible.value = false
- }
- }
- bus.on('mark-method-toggle', () => {
- onToggleClick()
- })
- bus.on('openScoreDialogByMouseRight', () => {
- if (!dialogMode.value) {
- onToggleClick()
- }
- })
- // 组件卸载时清除倒计时
- onUnmounted(() => {
- markStore.clearCountdown()
- })
- </script>
- <style scoped lang="scss">
- .scoring-panel-box {
- padding-bottom: 4px;
- background-color: #fff;
- }
- .modal-box {
- max-height: 50vh;
- min-height: 8vw;
- .dialog-name {
- color: $color--primary;
- font-weight: bold;
- padding-left: 10px;
- }
- }
- </style>
|