| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692 |
- <template>
- <div class="answerTheResult">
- <div class="atr_detail">
- <div class="atr_d_btn" @click="lookDetail()">{{isShowDialog ? '查看题目' : '查看结果'}}</div>
- <div class="atr_d_msg">
- <div>参与人数</div>
- <span
- >{{ workArrayLength }}/{{
- workArrayLength + unsubmittedStudentsLength
- }}</span
- >
- </div>
- <div class="atr_d_msg" v-if="workDetail && workDetail.type === '45'">
- <div>正确率</div>
- <span v-if="choiceQuestionListData[workIndex]">{{choiceQuestionListData[workIndex].accuracyRate}}%({{choiceQuestionListData[workIndex].yes}}/{{choiceQuestionListData[workIndex].all}})</span>
- </div>
- <div class="atr_d_msg" v-if="choiceQuestionAnswer">
- <div>正确答案</div>
- <span style="color: #03ae2b">{{ choiceQuestionAnswer }}</span>
- </div>
- <span class="atr_d_line" v-if="props.unsubmittedStudents && props.unsubmittedStudents?.length > 0"></span>
- <div class="no_submit" v-if="props.unsubmittedStudents && props.unsubmittedStudents?.length > 0">
- <div>未提交人员</div>
- <img
- @click="showNoSubmitDetail = !showNoSubmitDetail"
- :class="{ no_submit_active: !showNoSubmitDetail }"
- src="../../../assets/img/arrow_up.png"
- />
- </div>
- <div
- class="no_submitList"
- v-if="props.unsubmittedStudents && props.unsubmittedStudents?.length > 0"
- :class="{ no_submitList_active: showNoSubmitDetail }"
- >
- <div
- v-for="(student, idx) in props.unsubmittedStudents"
- :key="student.id ?? idx"
- >
- {{ student.name ?? "" }}
- </div>
- </div>
- <span class="atr_d_line" v-if="props.workArray && props.workArray?.length > 0"></span>
- <div class="is_submit" v-if="props.workArray && props.workArray?.length > 0">
- <div>已提交人员</div>
- <img
- @click="showIsSubmitDetail = !showIsSubmitDetail"
- :class="{ is_submit_active: !showIsSubmitDetail }"
- src="../../../assets/img/arrow_up.png"
- />
- </div>
- <div
- class="is_submitList"
- v-if="props.workArray && props.workArray?.length > 0"
- :class="{ is_submitList_active: showIsSubmitDetail }"
- >
- <div
- v-for="(student, idx) in props.workArray"
- :key="student.id ?? idx"
- @click="emit('openWorkModal', student)"
- >
- {{ student.name ?? "" }}
- </div>
- </div>
- </div>
- <div
- class="atr_type45Area"
- v-if="
- workDetail &&
- workDetail.type === '45' &&
- choiceQuestionListData[workIndex] &&
- choiceQuestionListData[workIndex].choiceUser
- "
- >
- <!-- <div class="atr_t45a_title" >
- <span>{{ workIndex+1 }}、{{ choiceQuestionListData[workIndex].type=='1'?'单选题':'多选题' }}:</span>
- <span>{{ choiceQuestionListData[workIndex].teststitle }}</span>
- <img @click="previewImage(choiceQuestionListData[workIndex].timuList[0].src)" :src="choiceQuestionListData[workIndex].timuList[0].src" v-if="choiceQuestionListData[workIndex].timuList.length>0">
- </div> -->
- <template
- v-for="(op, idx) in choiceQuestionListData[workIndex].choiceUser"
- :key="`${workIndex}_${idx}`"
- >
- <div class="atr_t45a_item">
- <div class="atr_t45a_i_top">
- <div class="atr_t45a_i_left">
- <span>{{ serialNumber[idx] }}</span>
- <div>
- <img
- v-if="op.option.imgType"
- :src="op.option.src"
- @click="previewImage(op.option.src)"
- />
- <span v-else>{{ op.option }}</span>
-
- </div>
- <span v-if="op.isAnswer">正确</span>
- </div>
- <img
- @click="changeShow(op, idx)"
- v-if="op.user.length > 0"
- :class="{ show_active: !op.show }"
- src="../../../assets/img/arrow_up.png"
- />
- </div>
- <div
- class="atr_t45a_i_bottom"
- v-if="op.user.length > 0 && op.show"
- :class="{ atr_t45a_i_b_active: op.show }"
- >
- <div
-
- v-for="(name, uIdx) in op.user"
- :key="`${workIndex}_${idx}_${uIdx}`"
- >
- {{ name }}
- </div>
- </div>
- </div>
- </template>
- <div class="nextAndUpBtn" v-if="choiceQuestionListData.length>1">
- <span :class="{no_active:workIndex==0}" @click="changeWorkIndex(0)">上一题</span>
- <span :class="{no_active:choiceQuestionListData.length-1<=workIndex}" @click="changeWorkIndex(1)">下一题</span>
- </div>
- </div>
- </div>
- <!-- 预览放大(带缩放/拖拽/旋转/工具栏) -->
- <previewImageTool ref="previewImageToolRef"/>
- </template>
- <script lang="ts" setup>
- import { ref, computed, watch, inject, type Ref } from 'vue'
- import previewImageTool from '../../components/tool/previewImageTool.vue'
- import api from '../../../services/course'
- interface Props {
- workArray?: object[] | null;
- unsubmittedStudents?: object[] | null;
- workId?: string | null;
- slideIndex?:number
- toolType?:number
- }
- const props = withDefaults(defineProps<Props>(), {
- workArray: () => [],
- unsubmittedStudents: () => [],
- workId: '',
- toolType: 0,
- slideIndex: 0
- })
- const emit = defineEmits<{
- (e: 'openChoiceQuestionDetail', v: number): void,
- (e: 'openWorkModal', v:any):void
- }>()
- const choiceQuestionDetailDialogOpenList = inject<Ref<number[]>>('choiceQuestionDetailDialogOpenList', ref<number[]>([]))
- const isShowDialog = computed(() => {
- return choiceQuestionDetailDialogOpenList.value.includes(props.slideIndex)
- })
- // 已提交的作业数量
- const workArrayLength = computed(() => {
- let _result = 0
- if (props.workArray) {
- _result = props.workArray.length
- }
- return _result
- })
- // 未提交的作业数量
- const unsubmittedStudentsLength = computed(() => {
- let _result = 0
- if (props.unsubmittedStudents) {
- _result = props.unsubmittedStudents.length
- }
- return _result
- })
- // 选项序号
- const serialNumber = ref<string[]>([
- 'A',
- 'B',
- 'C',
- 'D',
- 'E',
- 'F',
- 'G',
- 'H',
- 'I',
- 'J',
- 'K',
- 'L',
- 'M',
- 'N',
- 'O',
- 'P',
- 'Q',
- 'R',
- 'S',
- 'T',
- 'U',
- 'V',
- 'W',
- 'X',
- 'Y',
- 'Z',
- ])
- // 第几题
- const workIndex = ref<number>(0)
- // 是否显示未提交人员
- const showNoSubmitDetail = ref<boolean>(false)
- const showIsSubmitDetail = ref<boolean>(false)
- // 作业详细
- const workDetail = ref<any>({})
- // 获取作业详细
- const getWorkDetail = async () => {
- if (props.workId) {
- const _res = await api.getWorkDetail({ id: props.workId })
- const _data = _res[0][0]
- if (_data) {
- _data.json = JSON.parse(_data.json)
- workDetail.value = _data
- choiceQuestionListData.value = choiceQuestionList()
- }
- }
- }
- // 选择题题目数组
- const choiceQuestionList = () => {
- let _result: any[] = []
- if (workDetail.value && workDetail.value.type === '45') {
- const _workData = workDetail.value.json.testJson
- _workData.forEach((item: any, index: number) => {
- // 修复 props.workArray 可能为 null 的问题
- item.choiceUser = []
- item.yes = 0
- item.no = 0
- item.checkList.forEach((op: any, oidx: number) =>
- item.choiceUser.push({
- index: serialNumber.value[oidx],
- option: op,
- user: [],
- show: false,
- isAnswer: Array.isArray(item.answer)
- ? item.answer.includes(oidx)
- : item.answer === oidx,
- })
- )
- });
- (props.workArray ?? []).forEach(
- (studentWork: any, studentIndex: number) => {
- const _studentContent: any = JSON.parse(
- decodeURIComponent(studentWork.content)
- ).testJson
- // let _studentContentCorrection = []
- // console.log(_workData)
- // console.log(_studentContent)
- // _studentContentCorrection = _workData.map((i:any) => {
- // return _studentContent.find((i2:any) => {
- // return (JSON.stringify({testtitle: i2.testtitle, checkList: i2.checkList, timuList: i2.timuList}) === JSON.stringify({testtitle: i.testtitle, checkList: i.checkList, timuList: i.timuList}))
- // })
- // })
- // console.log(_studentContentCorrection)
- _studentContent.forEach((test: any, testIndex: number) => {
- if (_workData[testIndex] && JSON.stringify({testtitle: test.testtitle, checkList: test.checkList, timuList: test.timuList}) === JSON.stringify({testtitle: _workData[testIndex].testtitle, checkList: _workData[testIndex].checkList, timuList: _workData[testIndex].timuList}) && (test.userAnswer || test.userAnswer === 0)) {
- if (Array.isArray(test.userAnswer)) {
- test.userAnswer.forEach((ch: number) => {
- _workData[testIndex].choiceUser[ch].user.push(studentWork.name)
- })
- if (
- JSON.stringify(
- test.userAnswer.sort((a: number, b: number) => a - b)
- ) === JSON.stringify(_workData[testIndex].answer.sort((a: number, b: number) => a - b))
- ) {
- _workData[testIndex].yes += 1
- }
- else {
- _workData[testIndex].no += 1
- }
- }
- else {
- _workData[testIndex].choiceUser[test.userAnswer].user.push(
- studentWork.name
- )
- if (test.userAnswer === _workData[testIndex].answer) {
- _workData[testIndex].yes += 1
- }
- else {
- _workData[testIndex].no += 1
- }
- }
- }
- })
- }
- )
- _workData.forEach((item:any) => {
- item.all = item.yes + item.no
- if (item.all === 0) {
- item.accuracyRate = 0
- }
- else {
- const rate = (item.yes / item.all) * 100
- item.accuracyRate = Number.isInteger(rate) ? rate : Number(rate.toFixed(2))
- }
- })
- _result = _workData
- }
- return _result
- }
- const choiceQuestionListData = ref<any[]>([])
- // 选择题题目正确答案
- const choiceQuestionAnswer = computed(() => {
- let _result = ''
- if (
- workDetail.value &&
- workDetail.value.type === '45' &&
- workDetail.value.json.testJson[workIndex.value]
- ) {
- const _answer = workDetail.value.json.testJson[workIndex.value].answer
- if (Array.isArray(_answer)) {
- _result = _answer.map((i: any) => serialNumber.value[i]).join('、')
- }
- else {
- _result = [serialNumber.value[_answer]].join('、')
- }
- }
- return _result
- })
- // //当前题目正确率
- // const choiceQuestionAccuracyRate = computed
- // 监听作业Id
- watch(
- () => props.workId,
- (newVal, oldVal) => {
- console.log('props.workId变化', { newVal, oldVal })
- if (newVal && newVal !== oldVal) {
- getWorkDetail()
- }
- },
- { immediate: true }
- )
- // 监听已提交的作业
- watch(() => props.workArray, (newVal, oldVal) => {
- if (newVal && newVal !== oldVal) {
- choiceQuestionListData.value = choiceQuestionList()
- // choiceQuestionAnswerData.value = choiceQuestionAnswer()
- }
- }, { immediate: true })
- // 切换题目
- const changeWorkIndex = (type:number) => {
- if (type === 0) {
- if (workIndex.value === 0) return
- workIndex.value -= 1
- }
- else if (type === 1) {
- if (choiceQuestionListData.value.length - 1 <= workIndex.value) return
- workIndex.value += 1
- }
- }
- // 切换题目展示所有人选项
- const changeShow = (op: any, idx: number) => {
- choiceQuestionListData.value[workIndex.value].choiceUser[idx].show = !choiceQuestionListData.value[workIndex.value].choiceUser[idx].show
- }
- const lookDetail = () => {
- console.log(props.toolType)
- if ([45, 15, 72, 73].includes(props.toolType)) {
- emit('openChoiceQuestionDetail', props.slideIndex)
- }
- }
- const previewImageToolRef = ref<any>(null)
- const previewImage = (url:string) => {
- previewImageToolRef.value.previewImage(url)
- }
- defineExpose({
- workDetail,
- choiceQuestionListData,
- workIndex,
- workArray: props.workArray,
- toolType: props.toolType,
- changeWorkIndex
- })
- </script>
- <style lang="scss" scoped>
- .answerTheResult {
- width: 100%;
- height: auto;
- max-height: 100%;
- overflow: auto;
- box-sizing: border-box;
- padding: 12px;
- .atr_detail {
- width: 100%;
- height: auto;
- border-radius: 4px;
- padding: 10px 15px 10px 15px;
- box-sizing: border-box;
- border: solid 1px rgba(0, 0, 0, 0.1);
- .atr_d_btn {
- width: 100%;
- height: 40px;
- display: flex;
- align-items: center;
- justify-content: center;
- background: rgba(0, 0, 0, 0.9);
- color: #fff;
- font-weight: 500;
- font-size: 14px;
- border-radius: 4px;
- cursor: pointer;
- }
- .atr_d_msg {
- width: 100%;
- display: flex;
- align-items: center;
- margin-top: 15px;
- font-size: 14px;
- color: rgba(0, 0, 0, 0.9);
- & > div {
- width: 4em;
- margin-right: 35px;
- font-weight: 500;
- }
- }
- .atr_d_line {
- width: 100%;
- height: 2px;
- display: block;
- background: rgba(242, 243, 245, 1);
- margin: 20px 0;
- border-radius: 2px;
- }
- .no_submit {
- width: 100%;
- display: flex;
- align-items: center;
- justify-content: space-between;
- font-size: 14px;
- font-weight: 500;
- margin-bottom: 20px;
- .no_submit_active {
- transform: rotate(180deg);
- }
- & > img {
- cursor: pointer;
- }
- }
- .no_submitList {
- width: 100%;
- display: flex;
- align-items: center;
- flex-wrap: nowrap;
- overflow: hidden;
- gap: 10px;
- & > div {
- padding: 5px 10px;
- background: rgba(255, 236, 232, 1);
- color: rgba(245, 63, 63, 1);
- font-size: 14px;
- font-weight: 500;
- border-radius: 10px;
- white-space: nowrap;
- }
- }
- .no_submitList_active {
- flex-wrap: wrap;
- }
- .is_submit {
- width: 100%;
- display: flex;
- align-items: center;
- justify-content: space-between;
- font-size: 14px;
- font-weight: 500;
- margin-bottom: 20px;
- .is_submit_active {
- transform: rotate(180deg);
- }
- & > img {
- cursor: pointer;
- }
- }
- .is_submitList {
- width: 100%;
- display: flex;
- align-items: center;
- flex-wrap: nowrap;
- overflow: hidden;
- gap: 10px;
- & > div {
- padding: 5px 10px;
- background: #fff;
- color: #2F80ED;
- font-size: 14px;
- font-weight: 500;
- border-radius: 10px;
- white-space: nowrap;
- box-sizing: border-box;
- border: solid 1px #2F80ED;
- cursor: pointer;
- }
- }
- .is_submitList_active {
- flex-wrap: wrap;
- }
- }
- .atr_type45Area {
- width: 100%;
- height: auto;
- .atr_t45a_title{
- width: 100%;
- height: auto;
- box-sizing: border-box;
- padding: 10px 15px 10px 15px;
- border: solid 1px #0000001a;
- border-radius: 4px;
- margin-top: 20px;
- font-size: 14px;
- font-weight: 600;
- img{
- width: auto;
- max-width: 100%;
- height: auto;
- object-fit: cover;
- cursor: pointer;
- display: block;
- }
- }
- .atr_t45a_item {
- width: 100%;
- height: auto;
- box-sizing: border-box;
- padding: 10px 15px 10px 15px;
- border: solid 1px #0000001a;
- border-radius: 4px;
- margin-top: 20px;
- .atr_t45a_i_top {
- width: 100%;
- height: auto;
- display: flex;
- align-items: center;
- justify-content: space-between;
- .atr_t45a_i_left {
- width: calc(100% - 50px);
- height: auto;
- display: flex;
- align-items: center;
- & > span:nth-child(1) {
- display: block;
- width: 20px;
- height: 20px;
- background: #fccf00;
- border-radius: 50%;
- padding: auto;
- box-sizing: border-box;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 14px;
- font-weight: 500;
- color: #fff;
- margin-right: 10px;
- }
- & > div {
- font-size: 14px;
- font-weight: bold;
- max-width: calc(100% - 20px - 10px - 45px);
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- display: block;
- position: relative;
- &>img{
- width: 20px;
- height: 20px;
- object-fit: cover;
- cursor: pointer;
- }
- }
- & > span:nth-of-type(2) {
- display: block;
- padding: 2px 4px;
- border-radius: 2px;
- background: #aff0b580;
- color: #03ae2b;
- font-size: 12px;
- font-weight: 400;
- margin-left: 10px;
- }
- }
- & > img {
- width: 16px;
- height: 16px;
- margin-left: 20px;
- cursor: pointer;
- }
- .show_active {
- transform: rotate(180deg);
- }
- }
- .atr_t45a_i_bottom {
- width: 100%;
- display: flex;
- align-items: center;
- flex-wrap: nowrap;
- overflow: hidden;
- gap: 10px;
- margin-top: 10px;
- & > div {
- padding: 5px 10px;
- background: #0000000f;
- color: #222222;
- font-size: 14px;
- font-weight: 500;
- border-radius: 10px;
- }
- }
- .atr_t45a_i_b_active {
- flex-wrap: wrap !important;
- }
- }
- .nextAndUpBtn{
- width: 100%;
- height: auto;
- display: grid;
- grid-template-columns: 1fr 1fr;
- margin-top: 20px;
- gap: 15px;
- &>span{
- display: flex;
- justify-content: center;
- align-items: center;
- width: 100%;
- height: 40px;
- border-radius: 5px;
- font-size: 14px;
- font-weight: 500;
- color: #fff;
- background: #3681FC;
- cursor: pointer;
- }
- &>.no_active{
- background: #cccccc !important;
- color: #999999 !important;
- cursor: not-allowed !important;
- pointer-events: none !important;
- }
- }
- }
- }
- </style>
|