feat: 引入环境变量配置,统一管理接口路径

- 新增 .env 文件,配置 VUE_APP_PROXY_TARGET(开发模式代理目标)和 VUE_APP_API_BASE(接口根路径)
- vue.config.js 的 devServer proxy 目标改用 VUE_APP_PROXY_TARGET 环境变量
- src/utils/http.ts 的 axios 实例配置 baseURL 为 VUE_APP_API_BASE,所有请求自动加前缀
- 所有页面中 http 接口调用去掉 /api/v2 前缀,由 axios baseURL 自动补全
- 文件上传的 el-upload action 属性改用动态绑定,引用 VUE_APP_API_BASE 环境变量
- 涉及文件:Login.vue、Home.vue、Article.vue、Hitokoto.vue、Music.vue、PhotoWall.vue、SourceImage.vue、Statistics.vue、SystemUser.vue、SystemConfig.vue、SystemConfigAdd.vue、SystemRole.vue

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-04-01 15:21:39 +08:00
co-authored by Copilot
parent 98d2852604
commit 86c7d75963
15 changed files with 63 additions and 58 deletions
+4 -4
View File
@@ -106,7 +106,7 @@ async function loadData() {
endDate.setHours(23, 59, 59, 999)
params.createdAt[1] = endDate
}
const data = await http.get<HitokotoPage, any>('/api/v2/hitokoto/list', {params})
const data = await http.get<HitokotoPage, any>('/hitokoto/list', {params})
selectedData = []
loading.value = false
total.value = data.total
@@ -118,7 +118,7 @@ async function save() {
addForm.value?.hitokotoForm?.validate(async (valid: boolean) => {
if (!valid) return
modalLoading.value = true
const data = await http.post<any, any>('/api/v2/hitokoto/save', formData)
const data = await http.post<any, any>('/hitokoto/save', formData)
modalLoading.value = false
addModal.value = false
ElMessage.success('保存成功')
@@ -132,7 +132,7 @@ function deleteAll() {
return
}
ElMessageBox.confirm(`是否确认删除选中的${selectedData.length}条数据?`, '确认删除', {type: 'warning'}).then(async () => {
await http.delete<any, any>('/api/v2/hitokoto/delete', {params: {ids: selectedData}})
await http.delete<any, any>('/hitokoto/delete', {params: {ids: selectedData}})
ElMessage.success('删除成功')
loadData()
}).catch(() => {})
@@ -147,7 +147,7 @@ function findTypeText(value: string): string | null {
// created
loadData()
http.get<never, any>('/api/v2/common/config/hitokoto_type').then(data => {
http.get<never, any>('/common/config/hitokoto_type').then(data => {
typeList.value = data
})
</script>
+16 -16
View File
@@ -116,7 +116,7 @@
</el-form-item>
<el-upload
ref="musicUpload"
action="/api/v2/music/upload"
:action="`${apiBase}/music/upload`"
name="file"
accept=".mp3,.flac"
:headers="{token: store.state.loginInfo.token}"
@@ -210,8 +210,8 @@ class MusicPage extends Page {
}
const store = useStore()
const apiBase = process.env.VUE_APP_API_BASE as string
const { loading, modalLoading, total, search, setLoadData, loadDataBase, reset, pageChange, pageSizeChange } = useBaseList(new MusicPage())
const currentRow = ref<MusicModel | null>(null)
const libIdSelected = ref<string | null>(null)
const exts = ref<string[]>([])
@@ -247,7 +247,7 @@ let selectedIds: string[] = []
async function loadData() {
loading.value = true
const data = await http.get<MusicPage, any>('/api/v2/music/list', {params: search})
const data = await http.get<MusicPage, any>('/music/list', {params: search})
selectedIds = []
loading.value = false
total.value = data.total
@@ -264,18 +264,18 @@ function findMusicLib(value: string): string | null {
}
async function playMusic() {
try {
const data = await http.get<any, any>('/api/v2/music/list/all', {params: selectedIds.length ? {ids: selectedIds} : search})
const data = await http.get<any, any>('/music/list/all', {params: selectedIds.length ? {ids: selectedIds} : search})
musicList.value = data.map((item: MusicModel, index: number) => {
const musicItem: MusicPlayerItem = {
id: index,
title: item.title || item.name,
artist: item.artist,
album: item.album,
src: `/api/v2/common/music/load/${item._id}`,
pic: `/api/v2/common/music/album/${item._id}`,
src: `${apiBase}/common/music/load/${item._id}`,
pic: `${apiBase}/common/music/album/${item._id}`,
}
if (item.lyricId) {
musicItem.lrc = `${location.origin}/api/v2/common/music/lyric/${item.lyricId}`
musicItem.lrc = `${apiBase}/common/music/lyric/${item.lyricId}`
}
return musicItem
})
@@ -292,14 +292,14 @@ function updateLib(row: MusicModel) {
}
function download(row: MusicModel) {
const link = document.createElement('a')
link.setAttribute('href', `/api/v2/common/music/load/${row._id}`)
link.setAttribute('href', `${apiBase}/common/music/load/${row._id}`)
link.setAttribute('download', row.name)
link.setAttribute('target', '_blank')
link.click()
}
function remove(row: MusicModel) {
ElMessageBox.confirm(`是否确认删除 ${row.name} `, '确认删除', {type: 'warning'}).then(async () => {
await http.delete<{params: {id: string}}, any>('/api/v2/music/delete', {params: {id: row._id}})
await http.delete<{params: {id: string}}, any>('/music/delete', {params: {id: row._id}})
ElMessage.success("删除成功")
loadData()
}).catch(() => {})
@@ -311,7 +311,7 @@ async function updateLyric(row: MusicModel) {
if (row.lyricId) {
lyricLoading.value = true
try {
const data = await http.get<any, any>('/api/v2/music/lyric/get', {params: {lyricId: row.lyricId}})
const data = await http.get<any, any>('/music/lyric/get', {params: {lyricId: row.lyricId}})
data.cloudId = data.cloudId ? data.cloudId.toString() : null
lyricFormData.value = data
} finally {
@@ -323,7 +323,7 @@ async function saveLyric() {
lyricForm.value?.validate(async (valid: boolean) => {
if (!valid) return
modalLoading.value = true
await http.post<MusicLyricModel, any>(`/api/v2/music/lyric/save?musicId=${currentRow.value ? currentRow.value._id : ''}`, lyricFormData.value)
await http.post<MusicLyricModel, any>(`/music/lyric/save?musicId=${currentRow.value ? currentRow.value._id : ''}`, lyricFormData.value)
modalLoading.value = false
modifyLyricModal.value = false
ElMessage.success("歌词保存成功")
@@ -333,7 +333,7 @@ async function saveLyric() {
}
async function saveMusicLib(row: MusicModel) {
if (!currentRow.value) return
await http.post<{id: string, libId: string}, any>('/api/v2/music/lib/update', {id: currentRow.value._id, libId: currentRow.value.libId})
await http.post<{id: string, libId: string}, any>('/music/lib/update', {id: currentRow.value._id, libId: currentRow.value.libId})
ElMessage.success("歌单更新成功")
row.libId = currentRow.value.libId
row.isEditing = false
@@ -395,7 +395,7 @@ function musicPlay() {
}
function loadLibs() {
return http.get<never, any>('/api/v2/music/lib/list').then(data => {
return http.get<never, any>('/music/lib/list').then(data => {
musicLibs.value = data
libTableData.value = data.map((item: MusicLibModel) => ({ ...item }))
})
@@ -414,7 +414,7 @@ async function saveLib(row: MusicLibModel & { _isNew?: boolean }) {
}
libSaving.value = true
try {
await http.post<any, any>('/api/v2/music/lib/add', { name: row.name, path: row.path })
await http.post<any, any>('/music/lib/add', { name: row.name, path: row.path })
ElMessage.success('歌单创建成功')
await loadLibs()
} finally {
@@ -423,7 +423,7 @@ async function saveLib(row: MusicLibModel & { _isNew?: boolean }) {
}
function removeLib(row: MusicLibModel) {
ElMessageBox.confirm(`是否确认删除歌单「${row.name}」?`, '确认删除', { type: 'warning' }).then(async () => {
await http.delete<any, any>('/api/v2/music/lib/delete', { params: { id: row._id } })
await http.delete<any, any>('/music/lib/delete', { params: { id: row._id } })
ElMessage.success('歌单删除成功')
await loadLibs()
}).catch(() => {})
@@ -433,7 +433,7 @@ function removeLib(row: MusicLibModel) {
loadLibs().then(() => {
loadData()
})
http.get<never, any>('/api/v2/music/listExts').then(data => {
http.get<never, any>('/music/listExts').then(data => {
exts.value = data
})
</script>
+5 -4
View File
@@ -31,7 +31,7 @@
</el-form>
<div class="btn-container">
<el-upload
action="/api/v2/photoWall/upload"
:action="`${apiBase}/photoWall/upload`"
accept="image/jpeg,image/png"
name="image"
:headers="{token: store.state.loginInfo.token}"
@@ -107,6 +107,7 @@ class PhotoWallPage extends Page {
}
const store = useStore()
const apiBase = process.env.VUE_APP_API_BASE as string
const { loading, total, search, setLoadData, loadDataBase, reset, pageChange, pageSizeChange } = useBaseList(new PhotoWallPage())
const allowUploadExt = ['jpg', 'jpeg', 'png']
@@ -120,7 +121,7 @@ let selectedData: string[] = []
async function loadData() {
loading.value = true
const data = await http.get<PhotoWallPage, any>('/api/v2/photoWall/list', {params: search})
const data = await http.get<PhotoWallPage, any>('/photoWall/list', {params: search})
selectedData = []
loading.value = false
total.value = data.total
@@ -134,7 +135,7 @@ function deleteAll() {
return
}
ElMessageBox.confirm(`是否确认删除选中的${selectedData.length}条数据?`, '确认删除', {type: 'warning'}).then(async () => {
await http.delete('/api/v2/photoWall/delete', {params: {ids: selectedData}})
await http.delete('/photoWall/delete', {params: {ids: selectedData}})
ElMessage.success('删除成功')
loadData()
}).catch(() => {})
@@ -164,7 +165,7 @@ function uploadError(error: Error) {
ElMessage.error(error.message)
}
async function preview(row: PhotoWallModel) {
const pictureCdn = await http.get('/api/v2/common/config/picture_cdn')
const pictureCdn = await http.get('/common/config/picture_cdn')
const index = photowallData.value.findIndex(item => item._id === row._id)
previewUrlList.value = photowallData.value.map(item => `${pictureCdn}/${item.name}`)
previewIndex.value = index >= 0 ? index : 0
+7 -6
View File
@@ -6,7 +6,7 @@
</el-alert>
<div class="btn-container" style="margin-top:10px;">
<el-upload
action="/api/source-image/upload"
:action="`${apiBase}/source-image/upload`"
accept="image/jpeg,image/png,image/svg+xml,image/x-icon"
name="image"
:headers="{token: store.state.loginInfo.token}"
@@ -89,6 +89,7 @@ import { SourceImageModel } from '@/model/api/source-image'
import http from '@/utils/http'
const store = useStore()
const apiBase = process.env.VUE_APP_API_BASE as string
const { loading, total, search, setLoadData, pageChange, pageSizeChange, datetimeFormat } = useBaseList(new Page())
const allowUploadExt = ['jpg', 'jpeg', 'png', 'svg', 'ico']
@@ -115,7 +116,7 @@ let selectedData: string[] = []
async function loadData(): Promise<void> {
loading.value = true
const data = await http.get<Page, any>('/api/v2/source-image/list', {params: search})
const data = await http.get<Page, any>('/source-image/list', {params: search})
selectedData = []
loading.value = false
total.value = data.total
@@ -129,7 +130,7 @@ function deleteAll(): void {
return
}
ElMessageBox.confirm(`是否确认删除选中的${selectedData.length}条数据?`, '确认删除', {type: 'warning'}).then(async () => {
await http.delete('/api/v2/source-image/delete', {params: {ids: selectedData}})
await http.delete('/source-image/delete', {params: {ids: selectedData}})
ElMessage.success('删除成功')
loadData()
}).catch(() => {})
@@ -160,7 +161,7 @@ function uploadError(error: Error): void {
}
function preview(row: SourceImageModel): void {
const index = sourceImageData.value.findIndex(item => item._id === row._id)
previewUrlList.value = sourceImageData.value.map(item => `/api/v2/common/randomBg?id=${item._id}`)
previewUrlList.value = sourceImageData.value.map(item => `${apiBase}/common/randomBg?id=${item._id}`)
previewIndex.value = index >= 0 ? index : 0
previewVisible.value = true
}
@@ -173,11 +174,11 @@ function modifyTags(item: SourceImageModel): void {
modifyModal.value = true
}
async function tarnsferChange(newTargetKeys: string[], direction: 'right' | 'left', moveKeys: string[]) {
await http.post('/api/v2/source-image/updateLabel', {id: curId.value, labels: newTargetKeys})
await http.post('/source-image/updateLabel', {id: curId.value, labels: newTargetKeys})
}
// created
http.get<never, any>('/api/v2/common/config/image_label').then(data => {
http.get<never, any>('/common/config/image_label').then(data => {
labelList.value.push(...data)
loadData()
})