feat(题库生成): 重构参数配置为教材、知识点和题型
This commit is contained in:
parent
18ca189d56
commit
b993a94385
|
|
@ -24,25 +24,81 @@ const rawContent = ref("");
|
|||
const cancelTokenSource = ref(null);
|
||||
|
||||
// ── 参数配置 ──
|
||||
const questionType = ref("choice"); // 'choice' | 'fillBlank' | 'translation' | 'reading'
|
||||
const difficulty = ref("medium"); // 'easy' | 'medium' | 'hard'
|
||||
const questionCount = ref(5);
|
||||
const topicInput = ref("");
|
||||
|
||||
// 新增维度:教材章节、知识点、题型
|
||||
const textbookChapter = ref(""); // 教材章节(预设)
|
||||
const customTextbookChapter = ref(""); // 自定义教材章节输入
|
||||
const selectedKnowledgePoints = ref([]); // 选中的知识点
|
||||
const customKnowledgePoint = ref(""); // 自定义知识点输入
|
||||
const questionFormat = ref("单项选择"); // 题型(预设)
|
||||
const customQuestionFormat = ref(""); // 自定义题型输入
|
||||
|
||||
// ── 配置选项 ──
|
||||
const TYPE_OPTIONS = [
|
||||
{ value: "choice", label: "选择题", desc: "单项选择题" },
|
||||
{ value: "fillBlank", label: "填空题", desc: "根据语境填空" },
|
||||
{ value: "translation", label: "翻译题", desc: "英汉互译" },
|
||||
{ value: "reading", label: "阅读理解", desc: "阅读文章并回答问题" },
|
||||
const DIFFICULTY_OPTIONS = [
|
||||
{ value: "very_easy", label: "容易", color: "#10b981" },
|
||||
{ value: "easy", label: "较易", color: "#34d399" },
|
||||
{ value: "medium", label: "适中", color: "#f59e0b" },
|
||||
{ value: "hard", label: "较难", color: "#f97316" },
|
||||
{ value: "very_hard", label: "困难", color: "#ef4444" },
|
||||
];
|
||||
|
||||
const DIFFICULTY_OPTIONS = [
|
||||
{ value: "easy", label: "简单", color: "#10b981" },
|
||||
{ value: "medium", label: "中等", color: "#f59e0b" },
|
||||
{ value: "hard", label: "困难", color: "#ef4444" },
|
||||
// 教材章节预设选项
|
||||
const CHAPTER_OPTIONS = [
|
||||
{ value: "Starter Unit1 You and Me", label: "Starter Unit1 You and Me" },
|
||||
{ value: "Starter Unit2 Keep Tidy", label: "Starter Unit2 Keep Tidy" },
|
||||
{ value: "Starter Unit3 Welcome!", label: "Starter Unit3 Welcome!" },
|
||||
{ value: "Unit 1 You and Me", label: "Unit 1 You and Me" },
|
||||
{ value: "Unit 2 We're Family!", label: "Unit 2 We're Family!" },
|
||||
{ value: "Unit 3 My School", label: "Unit 3 My School" },
|
||||
];
|
||||
|
||||
// 知识点预设选项
|
||||
const KNOWLEDGE_POINT_OPTIONS = [
|
||||
{ value: "语法", label: "语法" },
|
||||
{ value: "词汇", label: "词汇" },
|
||||
{ value: "冠词", label: "冠词" },
|
||||
{ value: "不定冠词", label: "不定冠词" },
|
||||
{ value: "定冠词", label: "定冠词" },
|
||||
{ value: "名词", label: "名词" },
|
||||
{ value: "动词", label: "动词" },
|
||||
{ value: "形容词", label: "形容词" },
|
||||
{ value: "代词", label: "代词" },
|
||||
{ value: "介词", label: "介词" },
|
||||
{ value: "时态", label: "时态" },
|
||||
{ value: "一般现在时", label: "一般现在时" },
|
||||
{ value: "现在进行时", label: "现在进行时" },
|
||||
{ value: "一般过去时", label: "一般过去时" },
|
||||
{ value: "句型结构", label: "句型结构" },
|
||||
{ value: "阅读理解", label: "阅读理解" },
|
||||
{ value: "写作", label: "写作" },
|
||||
];
|
||||
|
||||
// 题型预设选项
|
||||
const FORMAT_OPTIONS = [
|
||||
{ value: "单项选择", label: "单项选择" },
|
||||
{ value: "完形填空", label: "完形填空" },
|
||||
{ value: "句型转换", label: "句型转换" },
|
||||
{ value: "词汇运用", label: "词汇运用" },
|
||||
{ value: "翻译句子", label: "翻译句子" },
|
||||
{ value: "阅读理解", label: "阅读理解" },
|
||||
{ value: "书面表达", label: "书面表达" },
|
||||
{ value: "短文填空", label: "短文填空" },
|
||||
{ value: "语法填空", label: "语法填空" },
|
||||
{ value: "选词填空", label: "选词填空" },
|
||||
];
|
||||
|
||||
// 切换知识点选中状态
|
||||
const toggleKnowledgePoint = (value) => {
|
||||
const index = selectedKnowledgePoints.value.indexOf(value);
|
||||
if (index > -1) {
|
||||
selectedKnowledgePoints.value.splice(index, 1);
|
||||
} else {
|
||||
selectedKnowledgePoints.value.push(value);
|
||||
}
|
||||
};
|
||||
|
||||
// ── 解析试题内容 ──
|
||||
const parsedQuestions = computed(() => {
|
||||
const raw = rawContent.value;
|
||||
|
|
@ -111,19 +167,30 @@ function extractOptions(text) {
|
|||
|
||||
// ── 构建请求体 ──
|
||||
const buildRequestBody = () => {
|
||||
const typeLabel = TYPE_OPTIONS.find((t) => t.value === questionType.value)?.label || "选择题";
|
||||
const difficultyLabel =
|
||||
DIFFICULTY_OPTIONS.find((d) => d.value === difficulty.value)?.label || "中等";
|
||||
|
||||
const userPrompt = `请生成 ${questionCount.value} 道${difficultyLabel}难度的英语${typeLabel}${
|
||||
topicInput.value ? `,主题为:${topicInput.value}` : ""
|
||||
}。
|
||||
// 构建知识点字符串:预设选项 + 自定义输入
|
||||
const allKnowledgePoints = [
|
||||
...selectedKnowledgePoints.value,
|
||||
...(customKnowledgePoint.value ? [customKnowledgePoint.value] : []),
|
||||
];
|
||||
const knowledgePointStr = allKnowledgePoints.length > 0 ? allKnowledgePoints.join("、") : "";
|
||||
|
||||
// 教材章节:优先使用自定义输入,否则使用预设选择
|
||||
const chapterStr = customTextbookChapter.value || textbookChapter.value || "";
|
||||
|
||||
// 题型:优先使用自定义输入,否则使用预设选择
|
||||
const formatStr = customQuestionFormat.value || questionFormat.value || "";
|
||||
|
||||
const userPrompt = `请生成 ${questionCount.value} 道${difficultyLabel}难度的英语试题。
|
||||
|
||||
要求:
|
||||
1. 题目类型:${typeLabel}
|
||||
1. 题型:${formatStr}
|
||||
2. 难度等级:${difficultyLabel}
|
||||
3. 题目数量:${questionCount.value} 道
|
||||
${topicInput.value ? `4. 主题/知识点:${topicInput.value}` : ""}
|
||||
${chapterStr ? `4. 教材章节:${chapterStr}` : ""}
|
||||
${knowledgePointStr ? `5. 知识点:${knowledgePointStr}` : ""}
|
||||
|
||||
请严格按照指定的输出格式生成试题。`;
|
||||
|
||||
|
|
@ -218,10 +285,14 @@ const resetAll = () => {
|
|||
};
|
||||
|
||||
const loadExample = () => {
|
||||
questionType.value = "choice";
|
||||
difficulty.value = "medium";
|
||||
questionCount.value = 3;
|
||||
topicInput.value = "一般现在时";
|
||||
textbookChapter.value = "Starter Unit2 Keep Tidy";
|
||||
customTextbookChapter.value = "";
|
||||
selectedKnowledgePoints.value = ["语法", "冠词", "不定冠词"];
|
||||
customKnowledgePoint.value = "";
|
||||
questionFormat.value = "句型转换";
|
||||
customQuestionFormat.value = "";
|
||||
};
|
||||
|
||||
const goBack = () => router.back();
|
||||
|
|
@ -287,24 +358,6 @@ onUnmounted(() => {
|
|||
</div>
|
||||
|
||||
<div class="config-body">
|
||||
<!-- 题目类型 -->
|
||||
<div class="config-item">
|
||||
<label class="config-label">题目类型</label>
|
||||
<div class="type-grid">
|
||||
<button
|
||||
v-for="opt in TYPE_OPTIONS"
|
||||
:key="opt.value"
|
||||
class="type-btn"
|
||||
:class="{ active: questionType === opt.value }"
|
||||
@click="questionType = opt.value"
|
||||
:disabled="status === 'generating'"
|
||||
>
|
||||
<div class="type-label">{{ opt.label }}</div>
|
||||
<div class="type-desc">{{ opt.desc }}</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 难度等级 -->
|
||||
<div class="config-item">
|
||||
<label class="config-label">难度等级</label>
|
||||
|
|
@ -344,14 +397,77 @@ onUnmounted(() => {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 知识点/主题 -->
|
||||
<!-- 教材章节 -->
|
||||
<div class="config-item">
|
||||
<label class="config-label">知识点/主题(可选)</label>
|
||||
<label class="config-label">教材章节(可选)</label>
|
||||
<select
|
||||
v-model="textbookChapter"
|
||||
class="select-input"
|
||||
:disabled="status === 'generating'"
|
||||
>
|
||||
<option value="">请选择教材章节</option>
|
||||
<option
|
||||
v-for="opt in CHAPTER_OPTIONS"
|
||||
:key="opt.value"
|
||||
:value="opt.value"
|
||||
>
|
||||
{{ opt.label }}
|
||||
</option>
|
||||
</select>
|
||||
<input
|
||||
type="text"
|
||||
v-model="topicInput"
|
||||
class="topic-input"
|
||||
placeholder="例如:一般现在时、定语从句、商务英语..."
|
||||
v-model="customTextbookChapter"
|
||||
class="topic-input mt-2"
|
||||
placeholder="或输入自定义教材章节..."
|
||||
:disabled="status === 'generating'"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 知识点 -->
|
||||
<div class="config-item">
|
||||
<label class="config-label">知识点(可多选)</label>
|
||||
<div class="knowledge-grid">
|
||||
<button
|
||||
v-for="opt in KNOWLEDGE_POINT_OPTIONS"
|
||||
:key="opt.value"
|
||||
class="knowledge-btn"
|
||||
:class="{ active: selectedKnowledgePoints.includes(opt.value) }"
|
||||
@click="toggleKnowledgePoint(opt.value)"
|
||||
:disabled="status === 'generating'"
|
||||
>
|
||||
{{ opt.label }}
|
||||
</button>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
v-model="customKnowledgePoint"
|
||||
class="topic-input mt-2"
|
||||
placeholder="或输入自定义知识点..."
|
||||
:disabled="status === 'generating'"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 题型 -->
|
||||
<div class="config-item">
|
||||
<label class="config-label">题型</label>
|
||||
<select
|
||||
v-model="questionFormat"
|
||||
class="select-input"
|
||||
:disabled="status === 'generating'"
|
||||
>
|
||||
<option
|
||||
v-for="opt in FORMAT_OPTIONS"
|
||||
:key="opt.value"
|
||||
:value="opt.value"
|
||||
>
|
||||
{{ opt.label }}
|
||||
</option>
|
||||
</select>
|
||||
<input
|
||||
type="text"
|
||||
v-model="customQuestionFormat"
|
||||
class="topic-input mt-2"
|
||||
placeholder="或输入自定义题型..."
|
||||
:disabled="status === 'generating'"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -750,6 +866,27 @@ onUnmounted(() => {
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
overflow-y: auto;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.config-body::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.config-body::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.config-body::-webkit-scrollbar-thumb {
|
||||
background: rgba(16, 185, 129, 0.3);
|
||||
border-radius: 3px;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.config-body::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(16, 185, 129, 0.5);
|
||||
}
|
||||
|
||||
.config-item {
|
||||
|
|
@ -773,50 +910,6 @@ onUnmounted(() => {
|
|||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Type Selection */
|
||||
.type-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.type-btn {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
padding: 1rem;
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.type-btn:hover:not(:disabled) {
|
||||
background: rgba(16, 185, 129, 0.06);
|
||||
border-color: rgba(16, 185, 129, 0.3);
|
||||
}
|
||||
.type-btn.active {
|
||||
background: rgba(16, 185, 129, 0.12);
|
||||
border-color: #10b981;
|
||||
}
|
||||
.type-btn:disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.type-label {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
.type-desc {
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.type-btn.active .type-label {
|
||||
color: #10b981;
|
||||
}
|
||||
|
||||
/* Difficulty Selection */
|
||||
.difficulty-group {
|
||||
display: flex;
|
||||
|
|
@ -858,6 +951,7 @@ onUnmounted(() => {
|
|||
outline: none;
|
||||
cursor: pointer;
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
.range-slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
|
|
@ -910,6 +1004,74 @@ onUnmounted(() => {
|
|||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* Select Input */
|
||||
.select-input {
|
||||
width: 100%;
|
||||
padding: 0.875rem 1rem;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-radius: 10px;
|
||||
color: var(--text-primary);
|
||||
font-size: 0.9rem;
|
||||
outline: none;
|
||||
transition: border-color 0.2s, box-shadow 0.2s;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2310b981' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 1rem center;
|
||||
padding-right: 2.5rem;
|
||||
}
|
||||
.select-input:focus {
|
||||
border-color: rgba(16, 185, 129, 0.5);
|
||||
box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.1);
|
||||
}
|
||||
.select-input:disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.select-input option {
|
||||
background: #1a1a2e;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
/* Knowledge Points Grid */
|
||||
.knowledge-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.knowledge-btn {
|
||||
padding: 0.5rem 0.875rem;
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-radius: 8px;
|
||||
color: var(--text-secondary);
|
||||
font-size: 0.8rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.knowledge-btn:hover:not(:disabled) {
|
||||
background: rgba(16, 185, 129, 0.1);
|
||||
border-color: rgba(16, 185, 129, 0.3);
|
||||
color: #10b981;
|
||||
}
|
||||
.knowledge-btn.active {
|
||||
background: rgba(16, 185, 129, 0.15);
|
||||
border-color: #10b981;
|
||||
color: #10b981;
|
||||
}
|
||||
.knowledge-btn:disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.mt-2 {
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
|
||||
/* Example Button */
|
||||
.example-btn {
|
||||
display: flex;
|
||||
|
|
@ -1275,9 +1437,6 @@ onUnmounted(() => {
|
|||
.right-panel {
|
||||
padding: 1.25rem 1rem;
|
||||
}
|
||||
.type-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.options-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue