Skip to content

Commit 83e0559

Browse files
authored
Merge pull request #20 from codeacme17/feat-dev
feat: completed the development of signle-choice feature
2 parents 89a49e3 + 754eaee commit 83e0559

21 files changed

+320
-90
lines changed

app/src/components/blocks/ExamineBlock.vue

+44-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@
2222

2323
<!-- Answer tab connent -->
2424
<section v-show="currentTab === 'answer'">
25-
<!-- Answer block -->
25+
<!-- Short answer input -->
2626
<v-textarea
27+
v-if="props.questionType === 'short' || props.questionType === ''"
2728
v-model="currentData.answer"
2829
variant="solo"
2930
auto-grow
@@ -37,6 +38,22 @@
3738
@keyup="handleKeyup"
3839
/>
3940

41+
<!-- Single choice -->
42+
<v-card
43+
class="pt-5 pb-0 px-4 mb-5"
44+
:elevation="0"
45+
:color="defaultBgColor"
46+
>
47+
<v-radio-group v-model="currentData.answer" :disabled="isShowExamine">
48+
<v-radio
49+
v-for="item in options"
50+
:key="item"
51+
:label="item"
52+
:value="item"
53+
/>
54+
</v-radio-group>
55+
</v-card>
56+
4057
<!-- Examine block -->
4158
<Transition name="scroll-x-reverse-transition">
4259
<v-card
@@ -115,7 +132,11 @@ import { ErrorResponse } from '@/constant'
115132
116133
const { locale, t } = useI18n()
117134
const PROFILE_STORE = useProfileStore()
118-
const props = defineProps(['id'])
135+
const props = defineProps<{
136+
id: string
137+
questionContent: string
138+
questionType: 'short' | 'choice' | 'blank' | ''
139+
}>()
119140
const currentTab = ref<'answer' | 'lastAnswer' | 'document'>('answer')
120141
121142
// Get data cache
@@ -214,13 +235,34 @@ const handleGetDocument = async () => {
214235
document_content.value = data
215236
}
216237
238+
const options = ref<string[]>([])
239+
const splitQuestionToOptions = () => {
240+
if (props.questionType !== 'choice') return
241+
const questionLines = props.questionContent.trim().split('\n')
242+
243+
for (let i = 1; i < questionLines.length; i++) {
244+
const optionLine = questionLines[i].trim()
245+
if (
246+
optionLine.startsWith('A.') ||
247+
optionLine.startsWith('B.') ||
248+
optionLine.startsWith('C.') ||
249+
optionLine.startsWith('D.')
250+
) {
251+
options.value.push(optionLine)
252+
}
253+
}
254+
console.log(options.value)
255+
}
256+
217257
// Watching if current question id is changed
218258
watch(
219259
() => props.id,
220260
async () => {
221261
await handleGetLastAnswer()
222262
await handleGetDocument()
223263
264+
if (props.questionType === 'choice') splitQuestionToOptions()
265+
224266
if (currentData.value.examine) {
225267
isShowExamine.value = true
226268
isFinishExaming.value = true

app/src/components/blocks/QuestionBlock.vue

+4-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@
4242
</h3>
4343
<div class="ml-2">{{ switchRoleEmoji }}</div>
4444
</div>
45-
<p class="mb-6 text-body-1" v-html="toMarkdown(props.content)" />
45+
<p
46+
class="mb-6 text-body-1"
47+
v-html="toMarkdown(props.content.split('\n')[0])"
48+
/>
4649

4750
<!-- Memory progress -->
4851
<v-tooltip

app/src/components/forms/UploadForm.vue

+29-10
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,32 @@
11
<template>
22
<form>
3+
<!-- Choose question type radio -->
4+
<t-radio-group
5+
v-model="formData.questionType"
6+
variant="default-filled"
7+
class="mb-5"
8+
>
9+
<t-radio-button value="short">📝 {{ $t('button.short') }}</t-radio-button>
10+
<t-radio-button value="choice">
11+
🔠 {{ $t('button.choice') }}
12+
</t-radio-button>
13+
<!-- TODO -->
14+
<t-radio-button value="blank" disabled="true">
15+
⬜ {{ $t('button.blank') }}
16+
</t-radio-button>
17+
</t-radio-group>
18+
19+
<!-- TODO -->
320
<!-- <v-select
4-
v-model="formData.noteType"
5-
class="mt-4"
6-
variant="outlined"
7-
density="compact"
8-
item-title="label"
9-
item-value="value"
10-
:label="$t('label.selectNoteType')"
11-
:items="noteTypeOptions"
12-
@update:model-value="handleSelectChange"
13-
/> -->
21+
v-model="formData.noteType"
22+
class="mt-4"
23+
variant="outlined"
24+
density="compact"
25+
item-title="label"
26+
item-value="value"
27+
:label="$t('label.selectNoteType')"
28+
:items="noteTypeOptions"
29+
/> -->
1430

1531
<!-- File upload component -->
1632
<t-config-provider :global-config="locale === 'en' ? enConfig : cnConfig">
@@ -67,6 +83,7 @@ import cnConfig from 'tdesign-vue-next/es/locale/zh_CN'
6783
6884
type FormData = {
6985
noteType: 'files' | 'notion' | null
86+
questionType: 'short' | 'choice' | 'blank'
7087
files: any[]
7188
notion: string
7289
}
@@ -79,6 +96,7 @@ const emits = defineEmits(['success'])
7996
8097
const formData = reactive<FormData>({
8198
noteType: 'files',
99+
questionType: 'short',
82100
files: [],
83101
notion: '',
84102
})
@@ -116,6 +134,7 @@ const handleConfirm = async () => {
116134
117135
const _formData = new FormData()
118136
_formData.append('language', locale.value)
137+
_formData.append('questionType', formData.questionType)
119138
_formData.append('noteName', props.noteName)
120139
_formData.append('notionId', formData.notion)
121140
formData.files.forEach((item) => {

app/src/components/tables/QuestionTable.vue

+9-1
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,15 @@
2222
/>
2323
</td>
2424

25+
<!-- Quesiton type emoji -->
26+
<td style="width: 20px">
27+
<div v-if="item.question_type === 'short'">📝</div>
28+
<div v-if="item.question_type === 'choice'">🔠</div>
29+
<div v-if="item.question_type === 'blank'">⬜</div>
30+
</td>
31+
2532
<!-- Question content td -->
26-
<td style="overflow: hidden" v-html="toMarkdown(item.content)" />
33+
<td v-html="toMarkdown(item.content.split('\n')[0])" />
2734

2835
<!-- Action buttons td -->
2936
<td style="width: 145px">
@@ -74,6 +81,7 @@ export type TableItem = {
7481
id: number
7582
content: string
7683
designated_role: string
84+
question_type: 'short' | 'choice' | 'blank' | ''
7785
document_id?: number
7886
is_pushed?: string
7987
is_answered_today?: string

app/src/plugins/i18n/en.ts

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ export const en = {
2323
examiner: 'Examiner',
2424
export: 'Export configuration and notes',
2525
import: 'Import file',
26+
short: 'Short Answer',
27+
choice: 'Single Choice',
28+
blank: 'Fill in the blank'
2629
},
2730

2831
// the title & subtitle on each page

app/src/plugins/i18n/zh-CN.ts

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ export const zhCN = {
2323
examiner: '考官',
2424
export: '导出配置及笔记',
2525
import: '文件导入',
26+
short: '简答题',
27+
choice: '单选题',
28+
blank: '填空题',
2629
},
2730

2831
title: {

app/src/views/Note.vue

+7-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,11 @@
5151
/>
5252

5353
<!-- Examine block -->
54-
<examine-block :id="pickedQuestion.id" />
54+
<examine-block
55+
:id="pickedQuestion.id"
56+
:questionContent="pickedQuestion.content"
57+
:questionType="pickedQuestion.question_type"
58+
/>
5559
</section>
5660
</Transition>
5761
</v-container>
@@ -103,6 +107,7 @@ const pickedQuestion = reactive<TableItem>({
103107
content: '',
104108
designated_role: '',
105109
progress: 0,
110+
question_type: '',
106111
})
107112
const isShowAnswer = ref(false)
108113
const handlePickQuestion = (item: TableItem) => {
@@ -111,5 +116,6 @@ const handlePickQuestion = (item: TableItem) => {
111116
pickedQuestion.content = item.content
112117
pickedQuestion.designated_role = item.designated_role
113118
pickedQuestion.progress = item.progress
119+
pickedQuestion.question_type = item.question_type
114120
}
115121
</script>

app/src/views/Random.vue

+7-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@
1515
/>
1616

1717
<!-- Enswer block -->
18-
<examine-block :id="questionInfo.id" v-if="trigger" />
18+
<examine-block
19+
v-if="trigger"
20+
:id="questionInfo.id"
21+
:questionType="questionInfo.question_type"
22+
:questionContent="questionInfo.content"
23+
/>
1924
</section>
2025
</v-container>
2126
</template>
@@ -41,6 +46,7 @@ const [_getRandomQuestion, getRQLoading] = useFetch(
4146
const getRandomQuestion = async () => {
4247
const { data } = await _getRandomQuestion()
4348
questionInfo.value = data
49+
console.log(questionInfo.value)
4450
trigger.value = false
4551
nextTick(() => {
4652
trigger.value = true

database/database.sql

+2-1
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ COLLATE=utf8_general_ci;
3838

3939
CREATE TABLE t_question (
4040
id int(12) auto_increment NOT NULL COMMENT 'question id',
41-
content varchar(500) NOT NULL COMMENT 'question content',
41+
content varchar(1000) NOT NULL COMMENT 'question content',
4242
document_id int(12) NOT NULL COMMENT 'document id',
43+
question_type char(20) COMMENT 'the type of the question',
4344
designated_role char(20) NOT NULL COMMENT 'role when generating this question',
4445
push_date DATE DEFAULT NULL COMMENT 'date the question needs to be asked',
4546
is_pushed_today char(1) DEFAULT '0' NOT NULL COMMENT 'has pushed this quesiton at today to user 0-No 1-Yes',

server/apis/note.py

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import db_services as _dbs_
33

44
from fastapi import File, Form, UploadFile
5+
56
from utils import api_result, types, upload_file
67

78

@@ -50,6 +51,7 @@ def get_questions_by_note_id(note_id: int):
5051
# Add new note
5152
async def add_note(
5253
language: str,
54+
questionType: str,
5355
noteName: str = Form(),
5456
files: list[UploadFile] = File(default=None),
5557
notionId: str = Form(default=None),
@@ -64,13 +66,15 @@ async def add_note(
6466
try:
6567
await upload_file(
6668
language=language,
69+
questionType=questionType,
6770
noteId=_dbs_.note.get_inserted_note_id(noteName),
6871
noteName=noteName,
6972
files=files
7073
)
7174
except Exception as e:
7275
return api_result.error(str(e))
7376

77+
# TODO notion databse
7478
if (notionId is not None):
7579
pass
7680

server/apis/question.py

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ def examine_question(data: types.AnswerQuestion):
2020
context=document_info["document"],
2121
question=question_info["content"],
2222
role=question_info["designated_role"],
23+
question_type=question_info["question_type"],
2324
answer=data.answer
2425
)
2526

@@ -50,6 +51,7 @@ def get_random_question():
5051
"id": question_info["id"],
5152
"content": question_info["content"],
5253
"designated_role": question_info["designated_role"],
54+
"question_type": question_info["question_type"],
5355
"progress": question_info["progress"],
5456
"note_name": note_info["name"]
5557
})

server/db_services/question.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,19 @@ def get_question_by_id(id: int):
1818
def save_question_to_db(
1919
question_content: str,
2020
document_id: int,
21+
question_type: str
2122
):
2223
question_content = remove_prefix_numbers(question_content)
2324
query = """
24-
INSERT INTO t_question (content, document_id, designated_role)
25-
VALUES (%s, %s, %s)
25+
INSERT INTO t_question (content, document_id, designated_role, question_type)
26+
VALUES (%s, %s, %s, %s)
2627
"""
27-
data = (question_content, document_id, os.environ.get("CURRENT_ROLE"), )
28+
data = (
29+
question_content,
30+
document_id,
31+
os.environ.get("CURRENT_ROLE"),
32+
question_type,
33+
)
2834
MySQLHandler().insert_table_data(query, data)
2935

3036

0 commit comments

Comments
 (0)