feat:增加docker部署

This commit is contained in:
2026-07-29 22:38:46 +08:00
parent 4d49660b18
commit 78237984ec
13 changed files with 86 additions and 11 deletions

6
Dockerfile Normal file
View File

@@ -0,0 +1,6 @@
FROM nginx:1.27.0
COPY dist/ /usr/share/nginx/html/
COPY nginx.conf /etc/nginx/conf.d/default.conf
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' > /etc/timezone
RUN chmod -R 755 /usr/share/nginx/html/

25
nginx.conf Normal file
View File

@@ -0,0 +1,25 @@
server {
listen 80 default_server;
listen [::]:80 default_server;
root /usr/share/nginx/html;
index index.html;
server_name _;
client_max_body_size 500M;
location /study-agent/ {
alias /usr/share/nginx/html/;
try_files $uri $uri/ /study-agent/index.html;
}
location /study-api/ {
proxy_pass http://host.docker.internal:8001/;
}
location / {
try_files $uri $uri/ =404;
}
}

View File

@@ -5,12 +5,13 @@
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vue-tsc -b && vite build", "build": "vite build",
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@vueup/vue-quill": "^1.5.5", "@vueup/vue-quill": "^1.5.5",
"axios": "^1.18.1", "axios": "^1.18.1",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.21", "dayjs": "^1.11.21",
"element-plus": "^2.14.3", "element-plus": "^2.14.3",
"filesize": "^11.0.22", "filesize": "^11.0.22",

8
pnpm-lock.yaml generated
View File

@@ -14,6 +14,9 @@ importers:
axios: axios:
specifier: ^1.18.1 specifier: ^1.18.1
version: 1.18.1 version: 1.18.1
crypto-js:
specifier: ^4.2.0
version: 4.2.0
dayjs: dayjs:
specifier: ^1.11.21 specifier: ^1.11.21
version: 1.11.21 version: 1.11.21
@@ -734,6 +737,9 @@ packages:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
crypto-js@4.2.0:
resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==}
cssesc@3.0.0: cssesc@3.0.0:
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
engines: {node: '>=4'} engines: {node: '>=4'}
@@ -2817,6 +2823,8 @@ snapshots:
shebang-command: 2.0.0 shebang-command: 2.0.0
which: 2.0.2 which: 2.0.2
crypto-js@4.2.0: {}
cssesc@3.0.0: {} cssesc@3.0.0: {}
csstype@3.2.3: {} csstype@3.2.3: {}

View File

@@ -121,6 +121,7 @@ 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 { uploadLibraryFileApi } from '@/apis/library.ts'
import { getModuleOptions } from '@/utils/libraryUtil.ts' import { getModuleOptions } from '@/utils/libraryUtil.ts'
import { getFileExtension, getFileHashName } from '@/utils/file.ts'
const libraryStore = useLibraryStore() const libraryStore = useLibraryStore()
const libraryFileFormRef = ref<FormInstance>() const libraryFileFormRef = ref<FormInstance>()
@@ -166,9 +167,11 @@ const upload = async (options: UploadRequestOptions) => {
const { file } = options const { file } = options
libraryStore.currentFile.size = file.size libraryStore.currentFile.size = file.size
libraryStore.currentFile.type = 'image' libraryStore.currentFile.type = 'image'
const fileName = `${getFileHashName(file)}.${getFileExtension(file.name)}`
const formData = new FormData() const formData = new FormData()
formData.append('file', file) formData.append('file', file)
formData.append('filename', fileName)
const loading = ElLoading.service({ const loading = ElLoading.service({
lock: true, lock: true,

View File

@@ -21,7 +21,7 @@
</div> </div>
</div> </div>
<el-empty v-if="!filterLibraryFileList.length" description="暂无文件" :image-size="80" /> <el-empty v-if="!filterLibraryFileList.length" description="暂无数据"/>
</div> </div>
</template> </template>

View File

@@ -45,7 +45,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { usePracticeStore } from '@/stores/practice.ts' import { usePracticeStore } from '@/stores/practice.ts'
import { ElMessage } from 'element-plus' import { ElLoading, ElMessage } from 'element-plus'
const practiceStore = usePracticeStore() const practiceStore = usePracticeStore()
@@ -65,7 +65,20 @@ const submitAnswerClick = async () => {
return return
} }
const loading = ElLoading.service({
lock: true,
text: '答案提交中 请等待',
background: 'rgba(0, 0, 0, 0.7)'
})
try {
await practiceStore.checkQuestion() await practiceStore.checkQuestion()
ElMessage.success('提交成功')
} catch (error) {
console.log(error)
ElMessage.error('提交失败 请联系管理员')
} finally {
loading.close()
}
} }
} }
</script> </script>

View File

@@ -1,4 +1,4 @@
import { createRouter, createWebHistory } from 'vue-router' import { createRouter, createWebHashHistory } from 'vue-router'
import Layout from '../layout/index.vue' import Layout from '../layout/index.vue'
const routes = [ const routes = [
@@ -42,7 +42,7 @@ const routes = [
] ]
const router = createRouter({ const router = createRouter({
history: createWebHistory(), history: createWebHashHistory(),
routes routes
}) })

View File

@@ -42,9 +42,12 @@ export const useLibraryStore = defineStore('library', {
this.fileList = await queryLibraryFileListApi() this.fileList = await queryLibraryFileListApi()
this.subjectTree = getSubjectTree(this.fileList) this.subjectTree = getSubjectTree(this.fileList)
this.subjectOptions = getSubjectOptions(this.subjectTree) this.subjectOptions = getSubjectOptions(this.subjectTree)
if (this.subjectOptions.length > 0) {
this.selectedSubject = this.subjectOptions[0].value this.selectedSubject = this.subjectOptions[0].value
this.moduleOptions = getModuleOptions(this.subjectTree, this.selectedSubject) this.moduleOptions = getModuleOptions(this.subjectTree, this.selectedSubject)
this.selectedModule = this.moduleOptions[0].value this.selectedModule = this.moduleOptions[0].value
}
}, },
async queryFileById(id: number) { async queryFileById(id: number) {
this.currentFile = await queryLibraryFileByIdApi(id) this.currentFile = await queryLibraryFileByIdApi(id)

13
src/utils/file.ts Normal file
View File

@@ -0,0 +1,13 @@
import * as CryptoJS from 'crypto-js'
const hashSHA256 = (message: string) => {
return CryptoJS.SHA256(message).toString(CryptoJS.enc.Hex)
}
export const getFileHashName = (file: File) => {
return hashSHA256(`${file.name}_${file.lastModified}`)
}
export const getFileExtension = (name: string) => {
return name.substring(name.lastIndexOf('.') + 1).toLowerCase()
}

View File

@@ -8,7 +8,7 @@
</div> </div>
<div class="mistake-record"> <div class="mistake-record">
<div class="mistake-list"> <div v-if="mistakeStore.mistakeList.length" class="mistake-list">
<el-card <el-card
v-for="item in mistakeStore.mistakeList" v-for="item in mistakeStore.mistakeList"
:key="item.id" :key="item.id"
@@ -30,6 +30,8 @@
</div> </div>
</el-card> </el-card>
</div> </div>
<el-empty v-else description="暂无数据"></el-empty>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -12,7 +12,7 @@
</div> </div>
</div> </div>
<library-filter /> <library-filter v-if="libraryStore.fileList.length" />
<practice-question v-if="practiceStore.hasStart"/> <practice-question v-if="practiceStore.hasStart"/>

View File

@@ -14,6 +14,7 @@ export default defineConfig({
} }
} }
}, },
base: '/study-agent/',
resolve: { resolve: {
// 配置路径别名 // 配置路径别名
alias: { alias: {