feat:更新记录模块

This commit is contained in:
2026-08-09 14:01:59 +08:00
parent 8f92c55852
commit 1a63e14e82
15 changed files with 94 additions and 143 deletions

View File

@@ -1,9 +0,0 @@
import { cloudService } from './index'
import type { IExamRecord } from '@/types/exam.ts'
export const addExamRecordApi = (data: IExamRecord): Promise<boolean> =>
cloudService({
url: '/study-api/exam/record',
method: 'post',
data
})

View File

@@ -1,15 +1,15 @@
import { cloudService } from './index' import { cloudService } from './index'
import type { IMistake } from '@/types/mistake.ts' import type { IMistake } from '@/types/mistake.ts'
export const queryMistakeListApi = (): Promise<IMistake[]> => export const queryMistakeListApi = (subject: string): Promise<IMistake[]> =>
cloudService({ cloudService({
url: '/study-api/mistake', url: `/study-api/mistake/${subject}`,
method: 'get' method: 'get'
}) })
export const addMistakeListApi = (data: IMistake[]): Promise<boolean> => export const addMistakeListApi = (subject: string, data: IMistake[]): Promise<boolean> =>
cloudService({ cloudService({
url: '/study-api/mistake', url: `/study-api/mistake/${subject}`,
method: 'post', method: 'post',
data data
}) })

View File

@@ -1,15 +0,0 @@
import { cloudService } from './index'
import type { IPracticeRecord } from '@/types/practice.ts'
export const queryPracticeRecordApi = (id: number): Promise<IPracticeRecord[]> =>
cloudService({
url: `/study-api/practice/record/${id}`,
method: 'get'
})
export const addPracticeRecordApi = (data: IPracticeRecord): Promise<boolean> =>
cloudService({
url: '/study-api/practice/record',
method: 'post',
data
})

15
src/apis/record.ts Normal file
View File

@@ -0,0 +1,15 @@
import { cloudService } from './index'
import type { IRecord } from '@/types/record.ts'
export const queryRecordApi = (subject: string): Promise<IRecord[]> =>
cloudService({
url: `/study-api/record/${subject}`,
method: 'get'
})
export const addRecordApi = (subject: string, data: IRecord): Promise<boolean> =>
cloudService({
url: `/study-api/record/${subject}`,
method: 'post',
data
})

View File

@@ -42,20 +42,18 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { usePracticeStore } from '@/stores/practice.ts'
import { useLibraryStore } from '@/stores/library.ts'
import { useMistakeStore } from '@/stores/mistake.ts' import { useMistakeStore } from '@/stores/mistake.ts'
import { useQuestionStore } from '@/stores/question.ts' import { useQuestionStore } from '@/stores/question.ts'
import { useExamStore } from '@/stores/exam.ts' import { useRecordStore } from '@/stores/record.ts'
import { useLibraryStore } from '@/stores/library.ts'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { getMistakeList, isAnswerCorrect, optLetter } from '@/utils/practiceUtil.ts' import { getMistakeList, isAnswerCorrect, optLetter } from '@/utils/practiceUtil.ts'
import type { IMistake } from '@/types/mistake.ts' import type { IMistake } from '@/types/mistake.ts'
const practiceStore = usePracticeStore()
const libraryStore = useLibraryStore()
const mistakeStore = useMistakeStore() const mistakeStore = useMistakeStore()
const questionStore = useQuestionStore() const questionStore = useQuestionStore()
const examStore = useExamStore() const recordStore = useRecordStore()
const libraryStore = useLibraryStore()
const submitAnswerClick = async () => { const submitAnswerClick = async () => {
if (questionStore.questionList.find((item) => item.select.length === 0)) { if (questionStore.questionList.find((item) => item.select.length === 0)) {
@@ -70,77 +68,46 @@ const submitAnswerClick = async () => {
})) }))
await addMistakeList() await addMistakeList()
await addRecord()
}
}
const addRecord = async () => {
const totalCount = questionStore.checkList.length
const correctCount = questionStore.checkList.filter((c) => c.isCorrect).length
const wrongCount = totalCount - correctCount
recordStore.currentRecord = {
type: questionStore.type,
totalCount,
correctCount,
wrongCount
}
await recordStore.addRecord(libraryStore.currentFile.subject)
if (questionStore.type === 'Practice') {
await addPracticeRecord()
const { totalCount, correctCount, wrongCount } = practiceStore.currentRecord
await ElMessageBox.alert( await ElMessageBox.alert(
`${totalCount} 题 · 正确 ${correctCount} · 错误 ${wrongCount}`, `${totalCount} 题 · 正确 ${correctCount} · 错误 ${wrongCount}`,
'训练结果', '结果',
{ {
confirmButtonText: '确认' confirmButtonText: '确认'
} }
) )
} else {
await addExamRecord()
const { totalCount, correctCount, wrongCount } = examStore.currentRecord
await ElMessageBox.alert(
`${totalCount} 题 · 正确 ${correctCount} · 错误 ${wrongCount}`,
'考试结果',
{
confirmButtonText: '确认'
}
)
}
}
}
const addPracticeRecord = async () => {
const totalCount = questionStore.checkList.length
const correctCount = questionStore.checkList.filter((c) => c.isCorrect).length
practiceStore.currentRecord = {
libraryFileId: libraryStore.currentFile.id,
totalCount,
correctCount,
wrongCount: totalCount - correctCount
}
await practiceStore.addRecord()
}
const addExamRecord = async () => {
const totalCount = questionStore.checkList.length
const correctCount = questionStore.checkList.filter((c) => c.isCorrect).length
examStore.currentRecord = {
subject: examStore.config.subject,
totalCount,
correctCount,
wrongCount: totalCount - correctCount
}
await examStore.addRecord()
} }
const addMistakeList = async () => { const addMistakeList = async () => {
const mistakeList = getMistakeList(questionStore.questionList, questionStore.checkList) const mistakeList = getMistakeList(questionStore.questionList, questionStore.checkList)
mistakeStore.currentMistakes = [] mistakeStore.currentMistakes = []
const subject = questionStore.type === 'Practice' ? libraryStore.currentFile.subject : examStore.config.subject
const module = questionStore.type === 'Practice' ? libraryStore.currentFile.module : ''
const name = questionStore.type === 'Practice' ? libraryStore.currentFile.name : ''
mistakeList.forEach((item) => { mistakeList.forEach((item) => {
const mistake:IMistake = { const mistake: IMistake = {
answer: item.answer, answer: item.answer,
module,
name,
options: item.options, options: item.options,
question: item.question, question: item.question,
subject,
type: item.type type: item.type
} }
mistakeStore.currentMistakes.push(mistake) mistakeStore.currentMistakes.push(mistake)
}) })
await mistakeStore.addMistakeList() await mistakeStore.addMistakeList(libraryStore.currentFile.subject)
} }
</script> </script>

View File

@@ -1,12 +1,10 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import type { IExamConfig, IExamRecord } from '@/types/exam.ts' import type { IExamConfig } from '@/types/exam.ts'
import { addExamRecordApi } from '@/apis/exam.ts'
export const useExamStore = defineStore('exam', { export const useExamStore = defineStore('exam', {
state: () => ({ state: () => ({
dialogVisible: false, dialogVisible: false,
config: {} as IExamConfig, config: {} as IExamConfig
currentRecord: {} as IExamRecord
}), }),
actions: { actions: {
getEmptyConfig(): IExamConfig { getEmptyConfig(): IExamConfig {
@@ -14,9 +12,6 @@ export const useExamStore = defineStore('exam', {
subject: '', subject: '',
total: 50 total: 50
} }
},
async addRecord() {
await addExamRecordApi(this.currentRecord)
} }
} }
}) })

View File

@@ -8,11 +8,11 @@ export const useMistakeStore = defineStore('mistake', {
currentMistakes: [] as IMistake[] currentMistakes: [] as IMistake[]
}), }),
actions: { actions: {
async queryMistakeList() { async queryMistakeList(subject: string) {
this.mistakeList = await queryMistakeListApi() this.mistakeList = await queryMistakeListApi(subject)
}, },
async addMistakeList() { async addMistakeList(subject: string) {
await addMistakeListApi(this.currentMistakes) await addMistakeListApi(subject, this.currentMistakes)
}, },
async deleteMistakeById(id: number) { async deleteMistakeById(id: number) {
await deleteMistakeApi(id) await deleteMistakeApi(id)

View File

@@ -1,19 +0,0 @@
import { defineStore } from 'pinia'
import { addPracticeRecordApi, queryPracticeRecordApi } from '@/apis/practice.ts'
import type { IPracticeRecord } from '@/types/practice.ts'
export const usePracticeStore = defineStore('practice', {
state: () => ({
libraryFileId: 0,
recordList: [] as IPracticeRecord[],
currentRecord: {} as IPracticeRecord
}),
actions: {
async queryRecord() {
this.recordList = await queryPracticeRecordApi(this.libraryFileId)
},
async addRecord() {
await addPracticeRecordApi(this.currentRecord)
}
}
})

View File

@@ -1,6 +1,6 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import type { IPracticeCheck, IPracticeRecord } from '@/types/practice.ts'
import type { IQuestion } from '@/types/question.ts' import type { IQuestion } from '@/types/question.ts'
import type { IRecord, IRecordCheck } from '@/types/record.ts'
export const useQuestionStore = defineStore('question', { export const useQuestionStore = defineStore('question', {
state: () => ({ state: () => ({
@@ -8,7 +8,7 @@ export const useQuestionStore = defineStore('question', {
type: 'Practice' as 'Practice' | 'Exam', type: 'Practice' as 'Practice' | 'Exam',
questionContent: '', questionContent: '',
questionList: [] as IQuestion[], questionList: [] as IQuestion[],
recordList: [] as IPracticeRecord[], recordList: [] as IRecord[],
checkList: [] as IPracticeCheck[] checkList: [] as IRecordCheck[]
}) })
}) })

18
src/stores/record.ts Normal file
View File

@@ -0,0 +1,18 @@
import { defineStore } from 'pinia'
import { addRecordApi, queryRecordApi } from '@/apis/record.ts'
import type { IRecord } from '@/types/record.ts'
export const useRecordStore = defineStore('record', {
state: () => ({
recordList: [] as IRecord[],
currentRecord: {} as IRecord
}),
actions: {
async queryRecord(subject: string) {
this.recordList = await queryRecordApi(subject)
},
async addRecord(subject: string) {
await addRecordApi(subject, this.currentRecord)
}
}
})

View File

@@ -2,12 +2,3 @@ export interface IExamConfig {
subject: string; subject: string;
total: number; total: number;
} }
export interface IExamRecord {
id?: number;
subject: string;
totalCount: number;
correctCount: number;
wrongCount: number;
createTime?: string;
}

View File

@@ -1,8 +1,5 @@
export interface IMistake { export interface IMistake {
id?: number; id?: number;
subject: string;
module: string;
name: string;
type: string; type: string;
question: string; question: string;
options: string[]; options: string[];

View File

@@ -1,13 +1,13 @@
export interface IPracticeCheck { export interface IRecordCheck {
id: number; id: number;
answer: string[]; answer: string[];
select: string[]; select: string[];
isCorrect: boolean; isCorrect: boolean;
} }
export interface IPracticeRecord { export interface IRecord {
id?: number; id?: number;
libraryFileId:number; type: string;
totalCount: number; totalCount: number;
correctCount: number; correctCount: number;
wrongCount: number; wrongCount: number;

View File

@@ -9,6 +9,7 @@
</div> </div>
<question-list v-if="questionStore.questionList.length > 0"/> <question-list v-if="questionStore.questionList.length > 0"/>
<p v-else>请点击开始考试按钮进入考试</p>
<exam-dialog /> <exam-dialog />
</div> </div>

View File

@@ -7,13 +7,21 @@
</div> </div>
</div> </div>
<div class="filter-bar card-item">
<div class="filter-row">
<span class="filter-label">学科</span>
<el-segmented v-model="libraryStore.selectedSubject"
:options="libraryStore.subjectOptions"/>
</div>
</div>
<div class="mistake-record"> <div class="mistake-record">
<div v-if="mistakeStore.mistakeList.length" class="mistake-list"> <div v-if="mistakeStore.mistakeList.length" class="mistake-list">
<el-card v-for="item in mistakeStore.mistakeList" <el-card v-for="item in mistakeStore.mistakeList"
:key="item.id" class="mistake-card" shadow="never"> :key="item.id" class="mistake-card" shadow="never">
<div class="library"> <div class="library">
<el-tag type="primary" effect="dark">{{ item.subject }} · {{ item.module }}</el-tag> <el-tag type="primary" effect="dark">{{ libraryStore.selectedSubject }}</el-tag>
<el-button type="success" size="small" @click="deleteClick(item.id)">已掌握</el-button> <el-button type="success" size="small" @click="deleteClick(item)">已掌握</el-button>
</div> </div>
<div class="question">{{ item.question }}</div> <div class="question">{{ item.question }}</div>
@@ -38,11 +46,13 @@ import { useMistakeStore } from '@/stores/mistake.ts'
import { optLetter } from '@/utils/practiceUtil.ts' import { optLetter } from '@/utils/practiceUtil.ts'
import type { IMistake } from '@/types/mistake.ts' import type { IMistake } from '@/types/mistake.ts'
import { ElMessageBox } from 'element-plus' import { ElMessageBox } from 'element-plus'
import { useLibraryStore } from '@/stores/library.ts'
const mistakeStore = useMistakeStore() const mistakeStore = useMistakeStore()
const libraryStore = useLibraryStore()
onMounted(async () => { onMounted(async () => {
await mistakeStore.queryMistakeList() await mistakeStore.queryMistakeList(libraryStore.selectedSubject as string)
}) })
const optionClass = (item: IMistake, index: number) => { const optionClass = (item: IMistake, index: number) => {
@@ -53,14 +63,14 @@ const optionClass = (item: IMistake, index: number) => {
} }
} }
const deleteClick = (id: number) => { const deleteClick = (mistake: IMistake) => {
ElMessageBox.confirm('确定已掌握该错题?', '提示', { ElMessageBox.confirm('确定已掌握该错题?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(async () => { }).then(async () => {
await mistakeStore.deleteMistakeById(id) await mistakeStore.deleteMistakeById(mistake.id as number)
await mistakeStore.queryMistakeList() await mistakeStore.queryMistakeList(libraryStore.selectedSubject as string)
}) })
} }
</script> </script>