feat:封装axios接口

This commit is contained in:
2026-07-28 22:57:45 +08:00
parent efa27f126d
commit 1f88341019
13 changed files with 306 additions and 277 deletions

3
src/apis/index.ts Normal file
View File

@@ -0,0 +1,3 @@
import createService from '@/utils/axiosUtil.ts'
export const cloudService = createService('', 'study')

40
src/apis/library.ts Normal file
View File

@@ -0,0 +1,40 @@
import { cloudService } from './index'
import type { ILibraryFile } from '@/types/library.ts'
export const uploadLibraryFileApi = (formData: FormData): Promise<string> =>
cloudService({
url: '/study-api/library/upload',
method: 'post',
data: formData,
headers: {
'Content-Type': 'multipart/form-data'
}
})
export const addLibraryFileApi = (file: ILibraryFile): Promise<boolean> =>
cloudService({
url: '/study-api/library/files',
method: 'post',
data: file
})
export const updateLibraryFileApi = (id: number, file: ILibraryFile): Promise<boolean> =>
cloudService({
url: `/study-api/library/files/${id}`,
method: 'put',
data: file
})
export const queryLibraryFileListApi = (): Promise<ILibraryFile[]> =>
cloudService({
url: '/study-api/library/files',
method: 'get'
})
export const queryLibraryFileByIdApi = (id: number): Promise<ILibraryFile> =>
cloudService({
url: `/study-api/library/files/${id}`,
method: 'get'
})

View File

@@ -1,135 +0,0 @@
<template>
<el-dialog v-model="libraryStore.fileDetailDialogVisible"
:title="libraryStore.currentFile.name" center
width="90%" destroy-on-close class="file-detail-dialog">
<el-splitter>
<el-splitter-panel size="50%">
<div class="raw-file">
<div v-if="libraryStore.currentFile.type === 'pdf'" class="preview">
<p>原文预览</p>
</div>
<div v-else class="preview-box">
<p>原文预览</p>
</div>
</div>
</el-splitter-panel>
<el-splitter-panel size="50%">
<div class="section">
<div class="section-title">
<el-icon><EditPen /></el-icon>
生成题目{{ libraryStore.currentFile.questions?.length || 0 }}
</div>
<div v-for="(q, i) in libraryStore.currentFile.questions" :key="i" class="question-card">
<div class="q-header">
<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.question }}</div>
<ul v-if="q.options" class="q-options">
<li v-for="opt in q.options" :key="opt">{{ opt }}</li>
</ul>
<div class="q-answer">
<span class="label">答案</span>{{ q.answer }}
</div>
</div>
</div>
</el-splitter-panel>
</el-splitter>
<template #footer>
<el-button @click="libraryStore.fileDetailDialogVisible = false">关闭</el-button>
<el-button type="primary" @click="libraryStore.fileDetailDialogVisible = false">开始练习</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { EditPen } from '@element-plus/icons-vue'
import { useLibraryStore } from '@/stores/library.ts'
const libraryStore = useLibraryStore()
</script>
<style lang="scss">
.file-detail-dialog {
.raw-file {
height: 100%;
padding: 10px;
.preview {
height: 100%;
padding: 10px;
background: #f8fafc;
border: 2px dashed #e2e8f0;
}
}
/* 知识点 + 题目 */
.section {
padding: 10px;
display: flex;
flex-direction: column;
gap: 10px;
.section-title {
align-self: center;
display: flex;
align-items: center;
gap: 6px;
font-size: 14px;
font-weight: 600;
color: #1e293b;
}
.question-card {
background: #f8fafc;
border-radius: 8px;
padding: 10px;
display: flex;
flex-direction: column;
gap: 5px;
.q-header {
display: flex;
align-items: center;
gap: 8px;
.q-num {
font-weight: 700;
color: #14b8a6;
}
}
.q-body {
font-size: 14px;
color: #1e293b;
}
.q-options {
list-style: none;
padding: 0;
margin: 0 0 8px;
li {
padding: 3px 0;
font-size: 13px;
color: #475569;
}
}
.q-answer {
font-size: 13px;
color: #16a34a;
font-weight: 600;
.label {
color: #64748b;
font-weight: 400;
}
}
}
}
}
</style>

View File

@@ -14,17 +14,21 @@
:rules="rules" label-width="auto"> :rules="rules" label-width="auto">
<el-form-item label="学科" prop="subject"> <el-form-item label="学科" prop="subject">
<el-select v-model="libraryStore.currentFile.subject" <el-select v-model="libraryStore.currentFile.subject"
filterable allow-create placeholder="请输入或选择学科名称"> filterable allow-create
<el-option v-for="(item, index) in subjectOptions" @change="handleSubjectEvent"
:key="index" :label="item" :value="item"/> placeholder="请输入或选择学科名称">
<el-option v-for="(item, index) in libraryStore.subjectOptions"
:key="index" :label="item.label" :value="item.value"/>
</el-select> </el-select>
</el-form-item> </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"
filterable allow-create placeholder="请输入或选择模块名称"> filterable allow-create
<el-option v-for="(item, index) in subjectOptions" :disabled="!libraryStore.currentFile.subject"
:key="index" :label="item" :value="item"/> placeholder="请输入或选择模块名称">
<el-option v-for="(item, index) in libraryStore.moduleOptions"
:key="index" :label="item.label" :value="item.value"/>
</el-select> </el-select>
</el-form-item> </el-form-item>
@@ -50,14 +54,16 @@
</el-form-item> </el-form-item>
</el-form> </el-form>
<QuillEditor v-if="activeStep === 2" :content="fileContent" contentType="html" theme="snow"/> <QuillEditor v-if="activeStep === 2"
:content="libraryStore.currentFile.content"
contentType="html" theme="snow"/>
<div v-if="activeStep === 3" class="generate-question"> <div v-if="activeStep === 3" class="generate-question">
<div> <div>
<el-button type="primary" @click="generate">生成题库</el-button> <el-button type="primary" @click="generateQuestion">生成题库</el-button>
</div> </div>
<div v-if="hasGenerate" class="question-list"> <div v-if="libraryStore.hasGenerateQuestion" class="question-list">
<el-card v-for="(q, index) in libraryStore.currentFile.questions" <el-card v-for="(q, index) in libraryStore.currentFile.questions"
:key="q.id" class="question-card"> :key="q.id" class="question-card">
<div class="question-title"> <div class="question-title">
@@ -102,19 +108,15 @@ import { ref } from 'vue'
import { useLibraryStore } from '@/stores/library.ts' import { useLibraryStore } from '@/stores/library.ts'
import { ElLoading, ElMessage, type FormInstance, type UploadRequestOptions } from 'element-plus' import { ElLoading, ElMessage, type FormInstance, type UploadRequestOptions } from 'element-plus'
import { Document, MagicStick, Upload, UploadFilled } from '@element-plus/icons-vue' import { Document, MagicStick, Upload, UploadFilled } from '@element-plus/icons-vue'
import axios from 'axios'
import { QuillEditor } from '@vueup/vue-quill' import { QuillEditor } from '@vueup/vue-quill'
import '@vueup/vue-quill/dist/vue-quill.snow.css' import '@vueup/vue-quill/dist/vue-quill.snow.css'
import { uploadLibraryFileApi } from '@/apis/library.ts'
import { getModuleOptions } from '@/utils/library.ts'
const libraryStore = useLibraryStore() const libraryStore = useLibraryStore()
const libraryFileFormRef = ref<FormInstance>() const libraryFileFormRef = ref<FormInstance>()
const activeStep = ref(1) const activeStep = ref(1)
const hasGenerate = ref(false)
const subjectOptions = ['中医学', '公务员']
const fileContent = ref<string>()
const questionContent = ref<string>() const questionContent = ref<string>()
const rules = { const rules = {
@@ -150,6 +152,10 @@ const nextClick = async () => {
} }
} }
const handleSubjectEvent = (value: string) => {
libraryStore.moduleOptions = getModuleOptions(libraryStore.subjectTree, value)
}
const upload = async (options: UploadRequestOptions) => { const upload = async (options: UploadRequestOptions) => {
const { file } = options const { file } = options
libraryStore.currentFile.size = file.size libraryStore.currentFile.size = file.size
@@ -165,13 +171,8 @@ const upload = async (options: UploadRequestOptions) => {
}) })
try { try {
const res = await axios.post('http://127.0.0.1:8000/upload', formData, { libraryStore.currentFile.content = await uploadLibraryFileApi(formData)
headers: {
'Content-Type': 'multipart/form-data'
}
})
ElMessage.success('上传成功') ElMessage.success('上传成功')
fileContent.value = res.data.text
} catch (error) { } catch (error) {
console.log(error) console.log(error)
ElMessage.error('上传失败 请联系管理员') ElMessage.error('上传失败 请联系管理员')
@@ -180,14 +181,14 @@ const upload = async (options: UploadRequestOptions) => {
} }
} }
const generate = async () => { const generateQuestion = async () => {
if (!fileContent.value) { if (!libraryStore.currentFile.content) {
ElMessage.error('请先上传资料') ElMessage.error('请先上传资料')
return return
} }
questionContent.value = '' questionContent.value = ''
hasGenerate.value = false libraryStore.hasGenerateQuestion = false
const loading = ElLoading.service({ const loading = ElLoading.service({
lock: true, lock: true,
@@ -196,13 +197,13 @@ const generate = async () => {
}) })
try { try {
const response = await fetch('http://127.0.0.1:8000/generate', { const response = await fetch('/study-api/library/question', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
body: JSON.stringify({ body: JSON.stringify({
message: fileContent.value message: libraryStore.currentFile.content
}) })
}) })
@@ -220,7 +221,7 @@ const generate = async () => {
} }
ElMessage.success('生成完成') ElMessage.success('生成完成')
hasGenerate.value = true libraryStore.hasGenerateQuestion = true
libraryStore.currentFile.questions = JSON.parse(questionContent.value) libraryStore.currentFile.questions = JSON.parse(questionContent.value)
} catch (error) { } catch (error) {
@@ -233,11 +234,7 @@ const generate = async () => {
const submitForm = async () => { const submitForm = async () => {
if (libraryStore.currentFile.questions.length > 0) { if (libraryStore.currentFile.questions.length > 0) {
const res = await axios.post('http://127.0.0.1:8000/files', libraryStore.currentFile, { await libraryStore.handleFileApi(libraryStore.currentFile)
headers: {
'Content-Type': 'application/json'
}
})
} else { } else {
ElMessage.error('请先生成题库') ElMessage.error('请先生成题库')
} }

View File

@@ -1,9 +1,11 @@
<template> <template>
<div class="file-list"> <div class="file-list">
<div v-for="file in libraryStore.fileList" :key="file.id" class="file-card card-item"> <library-filter v-if="libraryStore.fileList.length"/>
<div class="file-info" @click="viewDetailClick(file)">
<div class="file-icon" :class="file.iconClass"> <div v-for="file in libraryStore.fileList" :key="file.id" class="file-card card-item">
<div class="file-info">
<div class="file-icon" :class="file.type === 'image' ? 'icon-image' : 'icon-pdf'">
<el-icon v-if="file.type === 'image'" ><Picture /></el-icon> <el-icon v-if="file.type === 'image'" ><Picture /></el-icon>
<el-icon v-else><Document /></el-icon> <el-icon v-else><Document /></el-icon>
</div> </div>
@@ -14,12 +16,12 @@
</div> </div>
<div class="card-actions"> <div class="card-actions">
<el-button type="primary" :icon="Edit">编辑</el-button> <el-button type="primary" :icon="Edit" @click="editClick(file)">编辑</el-button>
<el-button type="danger" :icon="Delete">删除</el-button> <el-button type="danger" :icon="Delete">删除</el-button>
</div> </div>
</div> </div>
<el-empty v-if="!libraryStore.fileList.length" description="该模块暂无文件" :image-size="80" /> <el-empty v-if="!libraryStore.fileList.length" description="暂无文件" :image-size="80" />
</div> </div>
</template> </template>
@@ -27,11 +29,14 @@
import { Delete, Edit, Picture, Document } from '@element-plus/icons-vue' import { Delete, Edit, Picture, Document } from '@element-plus/icons-vue'
import { useLibraryStore } from '@/stores/library.ts' import { useLibraryStore } from '@/stores/library.ts'
import type { ILibraryFile } from '@/types/library.ts' import type { ILibraryFile } from '@/types/library.ts'
import LibraryFilter from '@/components/Library/LibraryFilter.vue'
const libraryStore = useLibraryStore() const libraryStore = useLibraryStore()
const viewDetailClick = (file: ILibraryFile) => { const editClick = async (file: ILibraryFile) => {
libraryStore.currentFile = file await libraryStore.queryFileByList(file.id)
libraryStore.fileDetailDialogVisible = true libraryStore.fileApiType = 'UPDATE'
libraryStore.hasGenerateQuestion = true
libraryStore.fileDialogVisible = true
} }
</script> </script>

View File

@@ -2,30 +2,24 @@
<div class="filter-bar card-item"> <div class="filter-bar card-item">
<div class="filter-row"> <div class="filter-row">
<span class="filter-label">学科</span> <span class="filter-label">学科</span>
<el-segmented v-model="libraryStore.selectedSubject" :options="subjectOptions"/> <el-segmented v-model="libraryStore.selectedSubject"
:options="libraryStore.subjectOptions"
@change="handleSubjectEvent"/>
</div> </div>
<div class="filter-row"> <div class="filter-row">
<span class="filter-label">模块</span> <span class="filter-label">模块</span>
<el-segmented v-model="libraryStore.selectedModule" :options="moduleOptions"/> <el-segmented v-model="libraryStore.selectedModule" :options="libraryStore.moduleOptions"/>
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue'
import { useLibraryStore } from '@/stores/library.ts' import { useLibraryStore } from '@/stores/library.ts'
import { getModuleOptions } from '@/utils/library.ts'
const libraryStore = useLibraryStore() const libraryStore = useLibraryStore()
const subjectOptions = computed(() => { const handleSubjectEvent = (value: string): void => {
return libraryStore.subjectTree.map((s) => ({ label: s.name, value: s.id })) libraryStore.moduleOptions = getModuleOptions(libraryStore.subjectTree, value)
}) }
const moduleOptions = computed(() => {
const node = libraryStore.subjectTree.find((s) => s.id === libraryStore.selectedSubject)
return (node?.children || []).map((m) => ({
label: m.name,
value: m.id
}))
})
</script> </script>

View File

@@ -1,82 +1,60 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import type { ILibraryFile, ITreeNode } from '@/types/library.ts' import type { ILibraryFile } from '@/types/library.ts'
import {
addLibraryFileApi,
queryLibraryFileByIdApi,
queryLibraryFileListApi,
updateLibraryFileApi
} from '@/apis/library.ts'
import type { IHandleApi, IOptions, ITreeNode } from '@/types'
import { ElMessage } from 'element-plus'
import { getModuleOptions, getSubjectOptions, getSubjectTree } from '@/utils/library.ts'
export const useLibraryStore = defineStore('library', { export const useLibraryStore = defineStore('library', {
state: () => ({ state: () => ({
selectedSubject: 1, selectedSubject: '',
selectedModule: 101, selectedModule: '',
subjectTree: [ subjectTree: [] as ITreeNode[],
{
id: 1,
name: '中医学',
children: [
{ id: 101, name: '中医基础理论' },
{ id: 102, name: '中医诊断学' },
{ id: 103, name: '中药学' },
{ id: 104, name: '方剂学' },
{ id: 105, name: '中医内科学' },
{ id: 106, name: '中医外科学' },
{ id: 107, name: '中医妇科学' },
{ id: 108, name: '中医儿科学' },
{ id: 109, name: '针灸学' },
{ id: 110, name: '推拿学' },
{ id: 111, name: '中医骨伤科学' },
{ id: 112, name: '黄帝内经' },
{ id: 113, name: '伤寒论' },
{ id: 114, name: '金匮要略' },
{ id: 115, name: '温病学' },
{ id: 116, name: '中医养生学' }
]
},
{
id: 2,
name: '公务员',
children: [
{ id: 201, name: '言语理解与表达' },
{ id: 202, name: '数量关系' },
{ id: 203, name: '判断推理' },
{ id: 204, name: '资料分析' },
{ id: 205, name: '常识判断' },
{ id: 206, name: '申论写作' },
{ id: 207, name: '公文写作' },
{ id: 208, name: '公共基础知识' },
{ id: 209, name: '面试技巧' },
{ id: 210, name: '时政热点' },
{ id: 211, name: '法律基础' }
]
}
] as ITreeNode[],
fileList: [] as ILibraryFile[], fileList: [] as ILibraryFile[],
currentFile: {} as ILibraryFile, currentFile: {} as ILibraryFile,
fileDetailDialogVisible: false, fileDetailDialogVisible: false,
fileDialogVisible: false fileDialogVisible: false,
hasGenerateQuestion: false,
fileApiType: 'ADD' as IHandleApi,
subjectOptions: [] as IOptions[],
moduleOptions: [] as IOptions[]
}), }),
actions: { actions: {
queryFileList() { async queryFileList() {
this.fileList = [ this.fileList = []
{ this.fileList = await queryLibraryFileListApi()
id: 1, this.subjectTree = getSubjectTree(this.fileList)
subject: '中医学', this.subjectOptions = getSubjectOptions(this.subjectTree)
module: '中医基础理疗', this.selectedSubject = this.subjectOptions[0].label
name: '向量代数.pdf', this.moduleOptions = getModuleOptions(this.subjectTree, this.selectedSubject)
size: 2.4, this.selectedModule = this.moduleOptions[0].label
uploadTime: '2分钟前',
type: 'pdf',
questions: [
{ 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'] }
]
}, },
{ async queryFileByList(id: number) {
id: 2, this.currentFile = await queryLibraryFileByIdApi(id)
subject: '中医学', },
module: '中医基础理疗', async handleFileApi(file: ILibraryFile) {
name: '向量代数精讲.png', switch (this.fileApiType) {
size: 156, case 'ADD':
uploadTime: '3小时前', await addLibraryFileApi(file)
type: 'image', ElMessage.success('新增资料成功')
questions: [] break
case 'UPDATE':
await updateLibraryFileApi(file.id as number, file)
ElMessage.success('更新资料成功')
break
case 'DELETE':
ElMessage.success('删除资料成功')
break
default:
break
} }
] this.fileDialogVisible = false
await this.queryFileList()
}, },
getEmptyFile(): ILibraryFile { getEmptyFile(): ILibraryFile {
return { return {
@@ -87,6 +65,7 @@ export const useLibraryStore = defineStore('library', {
subject: '', subject: '',
uploadTime: '', uploadTime: '',
type: '', type: '',
content: '',
questions: [] questions: []
} }
} }

12
src/types/index.ts Normal file
View File

@@ -0,0 +1,12 @@
export type IHandleApi = 'ADD' | 'UPDATE' | 'DELETE';
export interface ITreeNode {
id: number;
name: string;
children?: ITreeNode[];
}
export interface IOptions {
label: string;
value: string | number;
}

View File

@@ -1,9 +1,3 @@
export interface ITreeNode {
id: number;
name: string;
children?: ITreeNode[];
}
export interface ILibraryFileQuestion { export interface ILibraryFileQuestion {
id: number; id: number;
type: string; type: string;
@@ -20,5 +14,6 @@ export interface ILibraryFile {
size: number; size: number;
uploadTime: string; uploadTime: string;
type: string; type: string;
content: string;
questions: ILibraryFileQuestion[]; questions: ILibraryFileQuestion[];
} }

91
src/utils/axiosUtil.ts Normal file
View File

@@ -0,0 +1,91 @@
import axios, { AxiosError } from 'axios'
import type { InternalAxiosRequestConfig, AxiosResponse } from 'axios'
import { ElMessage } from 'element-plus'
const createService = (baseURL = '', prefix = '', timeout = 5000) => {
const service = axios.create({
baseURL,
timeout
})
// 请求拦截器
service.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
const token = localStorage.getItem(prefix ? `${prefix}-token` : 'token')
if (token) {
config.headers.satoken = prefix ? `${prefix} ${token}` : token
}
return config
},
(error: AxiosError) => {
return Promise.reject(error)
}
)
// 响应拦截器
service.interceptors.response.use(
(response: AxiosResponse) => {
return response.data
},
(error: AxiosError) => {
const { code, message } = error
if (error.response) {
// 发送请求成功 并收到服务器的响应
handleServiceError(error.response, message)
return Promise.reject(error)
} else if (error.request) {
// 发送请求成功 未收到服务器的响应
handleHttpError(code, message)
return Promise.reject(error)
} else {
// 其他错误情况 如发送请求失败等
ElMessage.error(`前端错误 请联系管理人员:${message}`)
}
}
)
return service
}
/**
* 处理服务器响应错误
* @param response 服务器响应
* @param message 错误消息
*/
const handleServiceError = (response: AxiosResponse, message: string) => {
const { status, data, statusText } = response
switch (status) {
case 401:
ElMessage.error('账号已过期 请重新登录')
window.location.href = '/'
break
case 500:
ElMessage.error(`${data.message || statusText}`)
break
default:
ElMessage.error(`服务器错误 请联系管理人员:${status}:${message}`)
}
}
/**
* 处理Http错误
* @param code code码
* @param message 消息
*/
const handleHttpError = (code: string | undefined, message: string) => {
switch (code) {
case 'ECONNABORTED':
case 'ETIMEDOUT':
ElMessage.error('网络连接错误 请联系管理人员')
break
default:
ElMessage.error(`网络错误 请联系管理人员:${code}:${message}`)
break
}
}
export default createService

51
src/utils/library.ts Normal file
View File

@@ -0,0 +1,51 @@
import type { ILibraryFile } from '@/types/library.ts'
import type { IOptions, ITreeNode } from '@/types'
export const getSubjectTree = (files: ILibraryFile[]): ITreeNode[] => {
const subjectMap = new Map<number, ITreeNode>()
let subjectIdCounter = 1
let moduleIdCounter = 1000
files.forEach((f) => {
// 查找是否已存在该学科节点
let subjectNode = Array.from(subjectMap.values()).find(
(node) => node.name === f.subject
)
// 不存在则创建学科节点
if (!subjectNode) {
subjectNode = {
id: subjectIdCounter++,
name: f.subject,
children: []
}
subjectMap.set(subjectNode.id, subjectNode)
}
// 避免重复模块
const exists = subjectNode.children?.some(
(c) => c.name === f.module
)
if (!exists) {
subjectNode.children!.push({
id: moduleIdCounter++,
name: f.module
})
}
})
return Array.from(subjectMap.values())
}
export const getSubjectOptions = (subjectTree: ITreeNode[]): IOptions[] => {
return subjectTree.map((s) => ({ label: s.name, value: s.name }))
}
export const getModuleOptions = (subjectTree: ITreeNode[], subject: string): IOptions[] => {
const node = subjectTree.find((s) => s.name === subject)
return (node?.children || []).map((m) => ({
label: m.name,
value: m.name
}))
}

View File

@@ -1,6 +1,5 @@
<template> <template>
<div class="library-view"> <div class="library-view">
<!-- 标题行 -->
<div class="page-header"> <div class="page-header">
<div> <div>
<h2 class="page-title">知识库</h2> <h2 class="page-title">知识库</h2>
@@ -9,33 +8,29 @@
<el-button type="primary" :icon="Plus" @click="addFileClick">新增资料</el-button> <el-button type="primary" :icon="Plus" @click="addFileClick">新增资料</el-button>
</div> </div>
<library-filter />
<library-file-list /> <library-file-list />
<library-file-dialog /> <library-file-dialog />
<library-file-detail-dialog />
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import LibraryFilter from '@/components/Library/LibraryFilter.vue'
import LibraryFileList from '@/components/Library/LibraryFileList.vue' import LibraryFileList from '@/components/Library/LibraryFileList.vue'
import LibraryFileDialog from '@/components/Library/LibraryFileDialog.vue' import LibraryFileDialog from '@/components/Library/LibraryFileDialog.vue'
import LibraryFileDetailDialog from '@/components/Library/LibraryFileDetailDialog.vue'
import { useLibraryStore } from '@/stores/library.ts' import { useLibraryStore } from '@/stores/library.ts'
import { Plus } from '@element-plus/icons-vue' import { Plus } from '@element-plus/icons-vue'
import { onMounted } from 'vue' import { onMounted } from 'vue'
const libraryStore = useLibraryStore() const libraryStore = useLibraryStore()
onMounted(() => { onMounted(async () => {
libraryStore.queryFileList() await libraryStore.queryFileList()
}) })
const addFileClick = () => { const addFileClick = () => {
libraryStore.currentFile = libraryStore.getEmptyFile() libraryStore.currentFile = libraryStore.getEmptyFile()
libraryStore.fileApiType = 'ADD'
libraryStore.hasGenerateQuestion = false
libraryStore.fileDialogVisible = true libraryStore.fileDialogVisible = true
} }
</script> </script>

View File

@@ -21,10 +21,12 @@ export default defineConfig({
} }
}, },
server: { server: {
port: 5174,
// 服务器代理 服务器没有部署Nginx的情况下使用
proxy: { proxy: {
'/study-api': {
target: 'http://127.0.0.1:8000',
changeOrigin: true,
rewrite: (item) => item.replace(/^\/study-api/, '')
}
} }
} }
}) })