feat:增加接口调用

This commit is contained in:
2026-07-27 23:01:16 +08:00
parent 875350cc56
commit 0d196edd28
3 changed files with 224 additions and 21 deletions

View File

@@ -9,6 +9,7 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"axios": "^1.18.1",
"element-plus": "^2.14.3", "element-plus": "^2.14.3",
"pinia": "^4.0.2", "pinia": "^4.0.2",
"vue": "^3.5.39", "vue": "^3.5.39",

99
pnpm-lock.yaml generated
View File

@@ -8,6 +8,9 @@ importers:
.: .:
dependencies: dependencies:
axios:
specifier: ^1.18.1
version: 1.18.1
element-plus: element-plus:
specifier: ^2.14.3 specifier: ^2.14.3
version: 2.14.3(vue@3.5.40(typescript@6.0.3)) version: 2.14.3(vue@3.5.40(typescript@6.0.3))
@@ -557,6 +560,10 @@ packages:
engines: {node: '>=0.4.0'} engines: {node: '>=0.4.0'}
hasBin: true hasBin: true
agent-base@6.0.2:
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
engines: {node: '>= 6.0.0'}
ajv@6.15.0: ajv@6.15.0:
resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==}
@@ -632,10 +639,16 @@ packages:
async-validator@4.2.5: async-validator@4.2.5:
resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==} resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==}
asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
available-typed-arrays@1.0.7: available-typed-arrays@1.0.7:
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
axios@1.18.1:
resolution: {integrity: sha512-3nTvFlvpn9Zu/RkHUqtc7/+al4UpRW5az71ap5zccp6e8RAYEzhMTecX8Dz1wWDYrPpUoB1HAQEGEAEvUr7S9g==}
balanced-match@1.0.2: balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
@@ -696,6 +709,10 @@ packages:
colorjs.io@0.5.2: colorjs.io@0.5.2:
resolution: {integrity: sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==} resolution: {integrity: sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==}
combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
concat-map@0.0.1: concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
@@ -760,6 +777,10 @@ packages:
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
detect-libc@2.1.2: detect-libc@2.1.2:
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
engines: {node: '>=8'} engines: {node: '>=8'}
@@ -1020,10 +1041,23 @@ packages:
flatted@3.4.3: flatted@3.4.3:
resolution: {integrity: sha512-/zipXxyO6rGvuNGDiULY9MvEGSkb2gaG4GGH4ygMi0ZZzyMHdUZBmntJmx5x1G2VuPytCwGN4xsJP6cw+sK+vQ==} resolution: {integrity: sha512-/zipXxyO6rGvuNGDiULY9MvEGSkb2gaG4GGH4ygMi0ZZzyMHdUZBmntJmx5x1G2VuPytCwGN4xsJP6cw+sK+vQ==}
follow-redirects@1.16.0:
resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==}
engines: {node: '>=4.0'}
peerDependencies:
debug: '*'
peerDependenciesMeta:
debug:
optional: true
for-each@0.3.5: for-each@0.3.5:
resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
form-data@4.0.6:
resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==}
engines: {node: '>= 6'}
fs.realpath@1.0.0: fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
@@ -1122,6 +1156,10 @@ packages:
hookable@5.5.3: hookable@5.5.3:
resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
https-proxy-agent@5.0.1:
resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
engines: {node: '>= 6'}
ignore@4.0.6: ignore@4.0.6:
resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==}
engines: {node: '>= 4'} engines: {node: '>= 4'}
@@ -1425,6 +1463,14 @@ packages:
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
engines: {node: '>=8.6'} engines: {node: '>=8.6'}
mime-db@1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
mime-types@2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
minimatch@3.1.5: minimatch@3.1.5:
resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==}
@@ -1581,6 +1627,10 @@ packages:
resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==}
engines: {node: '>=0.4.0'} engines: {node: '>=0.4.0'}
proxy-from-env@2.1.0:
resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==}
engines: {node: '>=10'}
punycode@2.3.1: punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'} engines: {node: '>=6'}
@@ -2668,6 +2718,12 @@ snapshots:
acorn@8.17.0: {} acorn@8.17.0: {}
agent-base@6.0.2:
dependencies:
debug: 4.4.3
transitivePeerDependencies:
- supports-color
ajv@6.15.0: ajv@6.15.0:
dependencies: dependencies:
fast-deep-equal: 3.1.3 fast-deep-equal: 3.1.3
@@ -2769,10 +2825,22 @@ snapshots:
async-validator@4.2.5: {} async-validator@4.2.5: {}
asynckit@0.4.0: {}
available-typed-arrays@1.0.7: available-typed-arrays@1.0.7:
dependencies: dependencies:
possible-typed-array-names: 1.1.0 possible-typed-array-names: 1.1.0
axios@1.18.1:
dependencies:
follow-redirects: 1.16.0
form-data: 4.0.6
https-proxy-agent: 5.0.1
proxy-from-env: 2.1.0
transitivePeerDependencies:
- debug
- supports-color
balanced-match@1.0.2: {} balanced-match@1.0.2: {}
birpc@2.9.0: {} birpc@2.9.0: {}
@@ -2837,6 +2905,10 @@ snapshots:
colorjs.io@0.5.2: colorjs.io@0.5.2:
optional: true optional: true
combined-stream@1.0.8:
dependencies:
delayed-stream: 1.0.0
concat-map@0.0.1: {} concat-map@0.0.1: {}
confbox@0.1.8: {} confbox@0.1.8: {}
@@ -2895,6 +2967,8 @@ snapshots:
has-property-descriptors: 1.0.2 has-property-descriptors: 1.0.2
object-keys: 1.1.1 object-keys: 1.1.1
delayed-stream@1.0.0: {}
detect-libc@2.1.2: {} detect-libc@2.1.2: {}
dir-glob@3.0.1: dir-glob@3.0.1:
@@ -3267,10 +3341,20 @@ snapshots:
flatted@3.4.3: {} flatted@3.4.3: {}
follow-redirects@1.16.0: {}
for-each@0.3.5: for-each@0.3.5:
dependencies: dependencies:
is-callable: 1.2.7 is-callable: 1.2.7
form-data@4.0.6:
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
es-set-tostringtag: 2.1.0
hasown: 2.0.4
mime-types: 2.1.35
fs.realpath@1.0.0: {} fs.realpath@1.0.0: {}
fsevents@2.3.3: fsevents@2.3.3:
@@ -3381,6 +3465,13 @@ snapshots:
hookable@5.5.3: {} hookable@5.5.3: {}
https-proxy-agent@5.0.1:
dependencies:
agent-base: 6.0.2
debug: 4.4.3
transitivePeerDependencies:
- supports-color
ignore@4.0.6: {} ignore@4.0.6: {}
ignore@5.3.2: {} ignore@5.3.2: {}
@@ -3645,6 +3736,12 @@ snapshots:
braces: 3.0.3 braces: 3.0.3
picomatch: 2.3.2 picomatch: 2.3.2
mime-db@1.52.0: {}
mime-types@2.1.35:
dependencies:
mime-db: 1.52.0
minimatch@3.1.5: minimatch@3.1.5:
dependencies: dependencies:
brace-expansion: 1.1.16 brace-expansion: 1.1.16
@@ -3807,6 +3904,8 @@ snapshots:
progress@2.0.3: {} progress@2.0.3: {}
proxy-from-env@2.1.0: {}
punycode@2.3.1: {} punycode@2.3.1: {}
quansync@0.2.11: {} quansync@0.2.11: {}

View File

@@ -1,26 +1,65 @@
<template> <template>
<el-dialog v-model="libraryStore.fileDialogVisible" <el-dialog v-model="libraryStore.fileDialogVisible"
title="新增资料" center destroy-on-close> title="新增资料" width="80%" center destroy-on-close>
<el-form ref="ruleFormRef" :model="libraryStore.currentFile" <el-splitter>
:rules="rules" label-width="auto"> <el-splitter-panel>
<el-form-item label="学科" prop="subject"> <el-form ref="ruleFormRef" :model="libraryStore.currentFile"
<el-select v-model="libraryStore.currentFile.subject" :rules="rules" label-width="auto">
multiple filterable allow-create <el-form-item label="学科" prop="subject">
placeholder="请输入或选择学科名称" style="width: 240px"> <el-select v-model="libraryStore.currentFile.subject"
<el-option v-for="(item, index) in subjectOptions" multiple filterable allow-create
:key="index" :label="item" :value="item"/> placeholder="请输入或选择学科名称" style="width: 240px">
</el-select> <el-option v-for="(item, index) in subjectOptions"
</el-form-item> :key="index" :label="item" :value="item"/>
</el-select>
</el-form-item>
<el-form-item label="模块" prop="module"> <el-form-item label="模块" prop="module">
<el-select v-model="libraryStore.currentFile.module" <el-select v-model="libraryStore.currentFile.module"
multiple filterable allow-create multiple filterable allow-create
placeholder="请输入或选择模块名称" style="width: 240px"> placeholder="请输入或选择模块名称" style="width: 240px">
<el-option v-for="(item, index) in subjectOptions" <el-option v-for="(item, index) in subjectOptions"
:key="index" :label="item" :value="item"/> :key="index" :label="item" :value="item"/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-form>
<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-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>
<template #footer> <template #footer>
<el-button @click="libraryStore.fileDialogVisible = false">取消</el-button> <el-button @click="libraryStore.fileDialogVisible = false">取消</el-button>
@@ -32,7 +71,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue' import { ref } from 'vue'
import { useLibraryStore } from '@/stores/library.ts' import { useLibraryStore } from '@/stores/library.ts'
import type { FormInstance } from 'element-plus' import { ElMessage, type FormInstance, type UploadRequestOptions } from 'element-plus'
import { UploadFilled } from '@element-plus/icons-vue'
import axios from 'axios'
const libraryStore = useLibraryStore() const libraryStore = useLibraryStore()
@@ -40,6 +81,9 @@ const ruleFormRef = ref<FormInstance>()
const subjectOptions = ['中医学', '公务员'] const subjectOptions = ['中医学', '公务员']
const fileContent = ref<string>()
const questionContent = ref<string>()
const rules = { const rules = {
subject: [ subject: [
{ required: true, message: '请输入学科名称', trigger: 'blur' } { required: true, message: '请输入学科名称', trigger: 'blur' }
@@ -49,6 +93,65 @@ const rules = {
] ]
} }
const upload = async (options: UploadRequestOptions) => {
const { file } = options
const formData = new FormData()
formData.append('file', file)
try {
const res = await axios.post('http://127.0.0.1:8000/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
ElMessage.success('上传成功')
fileContent.value = res.data.text
} catch (err) {
ElMessage.error('上传失败')
console.error(err)
}
}
const generate = async () => {
if (!fileContent.value) {
ElMessage.error('请先上传资料')
return
}
questionContent.value = ''
try {
const response = await fetch('http://127.0.0.1:8000/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
message: fileContent.value
})
})
if (!response.body) {
throw new Error('未获取到响应流')
}
const reader = response.body.getReader()
const decoder = new TextDecoder('utf-8')
while (true) {
const { value, done } = await reader.read()
if (done) break
questionContent.value += decoder.decode(value, { stream: true })
}
ElMessage.success('生成完成')
} catch (err) {
ElMessage.error('生成失败')
console.error(err)
}
}
const submitForm = async (formEl: FormInstance | undefined) => { const submitForm = async (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
await formEl.validate((valid, fields) => { await formEl.validate((valid, fields) => {