feat:更新知识库对话框
This commit is contained in:
@@ -7,4 +7,5 @@
|
||||
|
||||
<style lang="scss">
|
||||
@use '@/styles/index.module.scss';
|
||||
</style>
|
||||
@use "@/styles/common.module.scss";
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-dialog v-model="libraryStore.fileDetailDialogVisible"
|
||||
:title="libraryStore.currentFile.name" center
|
||||
width="90%" destroy-on-close class="file-dialog">
|
||||
width="90%" destroy-on-close class="file-detail-dialog">
|
||||
<el-splitter>
|
||||
<el-splitter-panel size="50%">
|
||||
<div class="raw-file">
|
||||
@@ -24,7 +24,7 @@
|
||||
<span class="q-num">Q{{ i + 1 }}</span>
|
||||
<el-tag size="small" type="primary" effect="dark">{{ q.type }}</el-tag>
|
||||
</div>
|
||||
<div class="q-body">{{ q.stem }}</div>
|
||||
<div class="q-body">{{ q.question }}</div>
|
||||
<ul v-if="q.options" class="q-options">
|
||||
<li v-for="opt in q.options" :key="opt">{{ opt }}</li>
|
||||
</ul>
|
||||
@@ -51,7 +51,7 @@ const libraryStore = useLibraryStore()
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.file-dialog {
|
||||
.file-detail-dialog {
|
||||
.raw-file {
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
|
||||
@@ -1,69 +1,98 @@
|
||||
<template>
|
||||
<el-dialog v-model="libraryStore.fileDialogVisible"
|
||||
title="新增资料" width="80%" center destroy-on-close>
|
||||
<el-splitter>
|
||||
<el-splitter-panel>
|
||||
<el-form ref="ruleFormRef" :model="libraryStore.currentFile"
|
||||
:rules="rules" label-width="auto">
|
||||
<el-form-item label="学科" prop="subject">
|
||||
<el-select v-model="libraryStore.currentFile.subject"
|
||||
multiple filterable allow-create
|
||||
placeholder="请输入或选择学科名称" style="width: 240px">
|
||||
<el-option v-for="(item, index) in subjectOptions"
|
||||
:key="index" :label="item" :value="item"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
title="新增资料" width="80%"
|
||||
center destroy-on-close
|
||||
class="file-dialog common-dialog">
|
||||
<el-steps :active="activeStep" align-center>
|
||||
<el-step title="上传资料" :icon="Upload" />
|
||||
<el-step title="确认资料" :icon="Document " />
|
||||
<el-step title="生成题库" :icon="MagicStick" />
|
||||
</el-steps>
|
||||
|
||||
<el-form-item label="模块" prop="module">
|
||||
<el-select v-model="libraryStore.currentFile.module"
|
||||
multiple filterable allow-create
|
||||
placeholder="请输入或选择模块名称" style="width: 240px">
|
||||
<el-option v-for="(item, index) in subjectOptions"
|
||||
:key="index" :label="item" :value="item"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form ref="libraryFileFormRef" v-if="activeStep === 1"
|
||||
:model="libraryStore.currentFile"
|
||||
:rules="rules" label-width="auto">
|
||||
<el-form-item label="学科" prop="subject">
|
||||
<el-select v-model="libraryStore.currentFile.subject"
|
||||
filterable allow-create placeholder="请输入或选择学科名称">
|
||||
<el-option v-for="(item, index) in subjectOptions"
|
||||
:key="index" :label="item" :value="item"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="文件">
|
||||
<el-upload class="upload-demo"
|
||||
drag
|
||||
:http-request="upload">
|
||||
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
|
||||
<div class="el-upload__text">
|
||||
Drop file here or <em>click to upload</em>
|
||||
</div>
|
||||
<template #tip>
|
||||
<div class="el-upload__tip">
|
||||
jpg/png files with a size less than 500kb
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-splitter-panel>
|
||||
<el-splitter-panel>
|
||||
<el-input
|
||||
v-model="fileContent"
|
||||
style="width: 100%;padding: 10px;"
|
||||
:rows="20"
|
||||
type="textarea"
|
||||
placeholder="Please input"
|
||||
/>
|
||||
</el-splitter-panel>
|
||||
<el-splitter-panel>
|
||||
<el-form-item label="模块" prop="module">
|
||||
<el-select v-model="libraryStore.currentFile.module"
|
||||
filterable allow-create placeholder="请输入或选择模块名称">
|
||||
<el-option v-for="(item, index) in subjectOptions"
|
||||
:key="index" :label="item" :value="item"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="libraryStore.currentFile.name"
|
||||
show-word-limit :maxlength="20"
|
||||
placeholder="请输入资料名称">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="文件">
|
||||
<el-upload class="upload-demo" drag :http-request="upload">
|
||||
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
|
||||
<div class="el-upload__text">
|
||||
拖拽文件至此或 <em>点击上传</em>
|
||||
</div>
|
||||
<template #tip>
|
||||
<div class="el-upload__tip">
|
||||
请上传小于10M的图片
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<QuillEditor v-if="activeStep === 2" :content="fileContent" contentType="html" theme="snow"/>
|
||||
|
||||
<div v-if="activeStep === 3" class="generate-question">
|
||||
<div>
|
||||
<el-button type="primary" @click="generate">生成题库</el-button>
|
||||
<el-input
|
||||
v-model="questionContent"
|
||||
style="width: 100%;padding: 10px;"
|
||||
:rows="20"
|
||||
type="textarea"
|
||||
placeholder="Please input"
|
||||
/>
|
||||
</el-splitter-panel>
|
||||
</el-splitter>
|
||||
</div>
|
||||
|
||||
<div v-if="hasGenerate" class="question-list">
|
||||
<el-card v-for="(q, index) in libraryStore.currentFile.questions"
|
||||
:key="q.id" class="question-card">
|
||||
<div class="question-title">
|
||||
{{ index + 1 }}.
|
||||
【{{ q.type === 'single' ? '单选' : '多选' }}】
|
||||
{{ q.question }}
|
||||
</div>
|
||||
|
||||
<div class="question-options">
|
||||
<div v-for="(opt, i) in q.options" :key="i" style="line-height: 1.8">
|
||||
{{ String.fromCharCode(65 + i) }}. {{ opt }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="question-answer">
|
||||
正确答案:{{ q.answer.join('、') }}
|
||||
</div>
|
||||
|
||||
<div class="question-action">
|
||||
<el-button type="danger" size="small"
|
||||
@click="libraryStore.currentFile.questions.splice(index, 1)">
|
||||
删除
|
||||
</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<div v-else v-html="questionContent" />
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="libraryStore.fileDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitForm(ruleFormRef)">确认</el-button>
|
||||
<el-button type="primary" @click="previousClick" :disabled="activeStep === 1">上一步</el-button>
|
||||
<el-button type="primary" @click="nextClick" :disabled="activeStep === 3">下一步</el-button>
|
||||
<el-button type="primary" @click="submitForm()" :disabled="activeStep !== 3">确认</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
@@ -71,13 +100,17 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { useLibraryStore } from '@/stores/library.ts'
|
||||
import { ElMessage, type FormInstance, type UploadRequestOptions } from 'element-plus'
|
||||
import { UploadFilled } from '@element-plus/icons-vue'
|
||||
import { ElLoading, ElMessage, type FormInstance, type UploadRequestOptions } from 'element-plus'
|
||||
import { Document, MagicStick, Upload, UploadFilled } from '@element-plus/icons-vue'
|
||||
import axios from 'axios'
|
||||
import { QuillEditor } from '@vueup/vue-quill'
|
||||
import '@vueup/vue-quill/dist/vue-quill.snow.css'
|
||||
|
||||
const libraryStore = useLibraryStore()
|
||||
|
||||
const ruleFormRef = ref<FormInstance>()
|
||||
const libraryFileFormRef = ref<FormInstance>()
|
||||
const activeStep = ref(1)
|
||||
const hasGenerate = ref(false)
|
||||
|
||||
const subjectOptions = ['中医学', '公务员']
|
||||
|
||||
@@ -90,15 +123,47 @@ const rules = {
|
||||
],
|
||||
module: [
|
||||
{ required: true, message: '请输入模块名称', trigger: 'blur' }
|
||||
],
|
||||
name: [
|
||||
{ required: true, message: '请输入资料名称', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
|
||||
const previousClick = () => {
|
||||
if (activeStep.value > 1) {
|
||||
activeStep.value--
|
||||
}
|
||||
}
|
||||
|
||||
const nextClick = async () => {
|
||||
if (activeStep.value === 1) {
|
||||
try {
|
||||
await libraryFileFormRef.value?.validate()
|
||||
} catch {
|
||||
ElMessage.error('请先输入信息')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (activeStep.value < 3) {
|
||||
activeStep.value++
|
||||
}
|
||||
}
|
||||
|
||||
const upload = async (options: UploadRequestOptions) => {
|
||||
const { file } = options
|
||||
libraryStore.currentFile.size = file.size
|
||||
libraryStore.currentFile.type = 'image'
|
||||
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
|
||||
const loading = ElLoading.service({
|
||||
lock: true,
|
||||
text: '文件上传中 请等待',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
|
||||
try {
|
||||
const res = await axios.post('http://127.0.0.1:8000/upload', formData, {
|
||||
headers: {
|
||||
@@ -107,9 +172,11 @@ const upload = async (options: UploadRequestOptions) => {
|
||||
})
|
||||
ElMessage.success('上传成功')
|
||||
fileContent.value = res.data.text
|
||||
} catch (err) {
|
||||
ElMessage.error('上传失败')
|
||||
console.error(err)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
ElMessage.error('上传失败 请联系管理员')
|
||||
} finally {
|
||||
loading.close()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,6 +187,13 @@ const generate = async () => {
|
||||
}
|
||||
|
||||
questionContent.value = ''
|
||||
hasGenerate.value = false
|
||||
|
||||
const loading = ElLoading.service({
|
||||
lock: true,
|
||||
text: '题库生成中 请等待',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
|
||||
try {
|
||||
const response = await fetch('http://127.0.0.1:8000/generate', {
|
||||
@@ -146,24 +220,77 @@ const generate = async () => {
|
||||
}
|
||||
|
||||
ElMessage.success('生成完成')
|
||||
} catch (err) {
|
||||
ElMessage.error('生成失败')
|
||||
console.error(err)
|
||||
hasGenerate.value = true
|
||||
|
||||
libraryStore.currentFile.questions = JSON.parse(questionContent.value)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
ElMessage.error('生成失败 请联系管理员')
|
||||
} finally {
|
||||
loading.close()
|
||||
}
|
||||
}
|
||||
|
||||
const submitForm = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
libraryStore.fileDialogVisible = false
|
||||
} else {
|
||||
console.log('请先输入信息')
|
||||
}
|
||||
})
|
||||
const submitForm = async () => {
|
||||
if (libraryStore.currentFile.questions.length > 0) {
|
||||
const res = await axios.post('http://127.0.0.1:8000/files', libraryStore.currentFile, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
} else {
|
||||
ElMessage.error('请先生成题库')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.file-dialog {
|
||||
.el-dialog__body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
|
||||
.ql-container {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.generate-question {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.question-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
|
||||
.question-card {
|
||||
.el-card__body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.question-title {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.question-options {
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.question-answer {
|
||||
color: #67c23a;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.question-action {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
</div>
|
||||
<div class="file-text">
|
||||
<div class="file-name">{{ file.name }}</div>
|
||||
<div class="file-meta">{{ file.size }} · {{ file.time }}</div>
|
||||
<div class="file-meta">{{ file.size }} · {{ file.uploadTime }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -21,4 +21,4 @@ app.use(createPinia())
|
||||
// 使用Element UI Plus
|
||||
app.use(ElementPlus, { locale: zhCn })
|
||||
// 挂载到根组件上
|
||||
app.mount('#app')
|
||||
app.mount('#app')
|
||||
|
||||
@@ -59,13 +59,11 @@ export const useLibraryStore = defineStore('library', {
|
||||
subject: '中医学',
|
||||
module: '中医基础理疗',
|
||||
name: '向量代数.pdf',
|
||||
size: '2.4 MB',
|
||||
time: '2分钟前',
|
||||
size: 2.4,
|
||||
uploadTime: '2分钟前',
|
||||
type: 'pdf',
|
||||
iconClass: 'icon-pdf',
|
||||
questions: [
|
||||
{ type: '选择题', stem: '设 a=(1,2,3), b=(2,-1,1),求 a·b = ?', options: ['A. 3', 'B. 5', 'C. 7', 'D. 9'], answer: 'A' },
|
||||
{ type: '计算题', stem: '求过点 P(1,0,2) 且法向量为 n=(2,1,-1) 的平面方程', answer: '2x + y - z = 0' }
|
||||
{ id: 1, type: 'single', question: '设 a=(1,2,3), b=(2,-1,1),求 a·b = ?', options: ['A. 3', 'B. 5', 'C. 7', 'D. 9'], answer: ['A'] }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -73,23 +71,23 @@ export const useLibraryStore = defineStore('library', {
|
||||
subject: '中医学',
|
||||
module: '中医基础理疗',
|
||||
name: '向量代数精讲.png',
|
||||
size: '156 MB',
|
||||
time: '3小时前',
|
||||
size: 156,
|
||||
uploadTime: '3小时前',
|
||||
type: 'image',
|
||||
iconClass: 'icon-image'
|
||||
questions: []
|
||||
}
|
||||
]
|
||||
},
|
||||
getEmptyFile(): ILibraryFile {
|
||||
return {
|
||||
iconClass: '',
|
||||
id: 0,
|
||||
module: '',
|
||||
name: '',
|
||||
size: '',
|
||||
size: 0,
|
||||
subject: '',
|
||||
time: '',
|
||||
type: ''
|
||||
uploadTime: '',
|
||||
type: '',
|
||||
questions: []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
17
src/styles/common.module.scss
Normal file
17
src/styles/common.module.scss
Normal file
@@ -0,0 +1,17 @@
|
||||
.common-view {
|
||||
|
||||
}
|
||||
|
||||
.common-dialog {
|
||||
--el-dialog-margin-top: 0 !important;
|
||||
margin: 0 auto !important;
|
||||
height: 100vh;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.el-dialog__body {
|
||||
flex-grow: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,11 @@ export interface ITreeNode {
|
||||
}
|
||||
|
||||
export interface ILibraryFileQuestion {
|
||||
id: number;
|
||||
type: string;
|
||||
stem: string;
|
||||
options?: string[];
|
||||
answer: string;
|
||||
question: string;
|
||||
options: string[];
|
||||
answer: string[];
|
||||
}
|
||||
|
||||
export interface ILibraryFile {
|
||||
@@ -16,9 +17,8 @@ export interface ILibraryFile {
|
||||
subject: string;
|
||||
module: string;
|
||||
name: string;
|
||||
size: string;
|
||||
time: string;
|
||||
size: number;
|
||||
uploadTime: string;
|
||||
type: string;
|
||||
iconClass: string;
|
||||
questions?: ILibraryFileQuestion[];
|
||||
questions: ILibraryFileQuestion[];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user