This commit is contained in:
2026-10-27 23:44:33 +08:00
parent 035bb089af
commit 0a61e57f9d
10 changed files with 40 additions and 38 deletions
+3 -3
View File
@@ -4,13 +4,13 @@ VITE_APP_TITLE = 'Portal 管理后台'
# 部署基础路径 # 部署基础路径
VITE_APP_BASE_URL = '/' VITE_APP_BASE_URL = '/'
# 接口前缀(本地走 Vite proxy) # 接口前缀留空:请求直接以 /api/... 发起,由 Vite proxy 的 /api 规则转发到后端
VITE_APP_BASE_API = '/' VITE_APP_BASE_API = ''
# 后端真实地址 # 后端真实地址
VITE_APP_API_URL = 'http://localhost:8080' VITE_APP_API_URL = 'http://localhost:8080'
# 是否启用本地 mock(true 时拦截全部 /api/v1 请求;false 时仅命中标记 alwaysMock 的接口) # 是否启用本地 mock(true 时拦截 /api 请求)
VITE_USE_MOCK = 'false' VITE_USE_MOCK = 'false'
# 开发端口 # 开发端口
+1 -1
View File
@@ -1,6 +1,6 @@
VITE_APP_TITLE = 'Portal 管理后台' VITE_APP_TITLE = 'Portal 管理后台'
VITE_APP_BASE_URL = '/' VITE_APP_BASE_URL = '/'
VITE_APP_BASE_API = '/api/v1' VITE_APP_BASE_API = ''
VITE_APP_API_URL = 'https://api.example.com' VITE_APP_API_URL = 'https://api.example.com'
VITE_USE_MOCK = 'false' VITE_USE_MOCK = 'false'
VITE_APP_PORT = '3000' VITE_APP_PORT = '3000'
+19 -19
View File
@@ -33,7 +33,7 @@ const pickString = (value: unknown, fallback = '') => (typeof value === 'string'
export const mockRules: MockRule[] = [ export const mockRules: MockRule[] = [
{ {
method: 'POST', method: 'POST',
pattern: /^\/api\/v1\/auth\/login$/, pattern: /^\/api\/auth\/login$/,
handler: (ctx) => ({ handler: (ctx) => ({
accessToken: 'mock-access-token', accessToken: 'mock-access-token',
refreshToken: 'mock-refresh-token', refreshToken: 'mock-refresh-token',
@@ -44,12 +44,12 @@ export const mockRules: MockRule[] = [
}, },
{ {
method: 'POST', method: 'POST',
pattern: /^\/api\/v1\/auth\/logout$/, pattern: /^\/api\/auth\/logout$/,
handler: () => true, handler: () => true,
}, },
{ {
method: 'GET', method: 'GET',
pattern: /^\/api\/v1\/auth\/me$/, pattern: /^\/api\/auth\/me$/,
handler: () => ({ handler: () => ({
userId: 1, userId: 1,
username: 'admin', username: 'admin',
@@ -70,12 +70,12 @@ export const mockRules: MockRule[] = [
}, },
{ {
method: 'GET', method: 'GET',
pattern: /^\/api\/v1\/auth\/routes$/, pattern: /^\/api\/auth\/routes$/,
handler: () => menuRoutes, handler: () => menuRoutes,
}, },
{ {
method: 'GET', method: 'GET',
pattern: /^\/api\/v1\/api\/admin\/users$/, pattern: /^\/api\/api\/admin\/users$/,
handler: (ctx) => { handler: (ctx) => {
const page = toNumber(ctx.query.page, 1) const page = toNumber(ctx.query.page, 1)
const size = toNumber(ctx.query.size, 20) const size = toNumber(ctx.query.size, 20)
@@ -94,12 +94,12 @@ export const mockRules: MockRule[] = [
}, },
{ {
method: 'GET', method: 'GET',
pattern: /^\/api\/v1\/api\/admin\/users\/(\d+)$/, pattern: /^\/api\/api\/admin\/users\/(\d+)$/,
handler: (ctx) => users.find((item) => item.id === toNumber(ctx.params[0])) ?? null, handler: (ctx) => users.find((item) => item.id === toNumber(ctx.params[0])) ?? null,
}, },
{ {
method: 'PUT', method: 'PUT',
pattern: /^\/api\/v1\/api\/admin\/users\/(\d+)$/, pattern: /^\/api\/api\/admin\/users\/(\d+)$/,
handler: (ctx) => { handler: (ctx) => {
const target = users.find((item) => item.id === toNumber(ctx.params[0])) const target = users.find((item) => item.id === toNumber(ctx.params[0]))
if (!target) return false if (!target) return false
@@ -113,7 +113,7 @@ export const mockRules: MockRule[] = [
}, },
{ {
method: 'POST', method: 'POST',
pattern: /^\/api\/v1\/api\/admin\/users\/(\d+)\/status$/, pattern: /^\/api\/api\/admin\/users\/(\d+)\/status$/,
handler: (ctx) => { handler: (ctx) => {
const target = users.find((item) => item.id === toNumber(ctx.params[0])) const target = users.find((item) => item.id === toNumber(ctx.params[0]))
if (!target) return false if (!target) return false
@@ -125,7 +125,7 @@ export const mockRules: MockRule[] = [
}, },
{ {
method: 'GET', method: 'GET',
pattern: /^\/api\/v1\/api\/admin\/miniapps$/, pattern: /^\/api\/api\/admin\/miniapps$/,
handler: (ctx) => { handler: (ctx) => {
const { status } = ctx.query const { status } = ctx.query
const pageNum = toNumber(ctx.query.pageNum, 1) const pageNum = toNumber(ctx.query.pageNum, 1)
@@ -142,7 +142,7 @@ export const mockRules: MockRule[] = [
}, },
{ {
method: 'GET', method: 'GET',
pattern: /^\/api\/v1\/api\/admin\/miniapps\/(\d+)$/, pattern: /^\/api\/api\/admin\/miniapps\/(\d+)$/,
handler: (ctx) => { handler: (ctx) => {
const target = miniApps.find((item) => item.id === toNumber(ctx.params[0])) const target = miniApps.find((item) => item.id === toNumber(ctx.params[0]))
if (!target) return null if (!target) return null
@@ -152,7 +152,7 @@ export const mockRules: MockRule[] = [
}, },
{ {
method: 'POST', method: 'POST',
pattern: /^\/api\/v1\/api\/admin\/miniapps$/, pattern: /^\/api\/api\/admin\/miniapps$/,
handler: (ctx) => { handler: (ctx) => {
const id = miniApps.length + 1 const id = miniApps.length + 1
const created: MockMiniApp = { const created: MockMiniApp = {
@@ -172,7 +172,7 @@ export const mockRules: MockRule[] = [
}, },
{ {
method: 'PUT', method: 'PUT',
pattern: /^\/api\/v1\/api\/admin\/miniapps\/(\d+)$/, pattern: /^\/api\/api\/admin\/miniapps\/(\d+)$/,
handler: (ctx) => { handler: (ctx) => {
const target = miniApps.find((item) => item.id === toNumber(ctx.params[0])) const target = miniApps.find((item) => item.id === toNumber(ctx.params[0]))
if (!target) return false if (!target) return false
@@ -189,7 +189,7 @@ export const mockRules: MockRule[] = [
}, },
{ {
method: 'DELETE', method: 'DELETE',
pattern: /^\/api\/v1\/api\/admin\/miniapps\/([\d,]+)$/, pattern: /^\/api\/api\/admin\/miniapps\/([\d,]+)$/,
handler: (ctx) => { handler: (ctx) => {
const ids = ctx.params[0].split(',').map((id) => toNumber(id)) const ids = ctx.params[0].split(',').map((id) => toNumber(id))
ids.forEach((id) => { ids.forEach((id) => {
@@ -201,7 +201,7 @@ export const mockRules: MockRule[] = [
}, },
{ {
method: 'GET', method: 'GET',
pattern: /^\/api\/v1\/api\/admin\/files$/, pattern: /^\/api\/api\/admin\/files$/,
handler: (ctx) => { handler: (ctx) => {
const { keyword, uploader_type, page, size } = ctx.query const { keyword, uploader_type, page, size } = ctx.query
const pageNum = toNumber(page, 1) const pageNum = toNumber(page, 1)
@@ -221,7 +221,7 @@ export const mockRules: MockRule[] = [
}, },
{ {
method: 'POST', method: 'POST',
pattern: /^\/api\/v1\/api\/admin\/files\/upload$/, pattern: /^\/api\/api\/admin\/files\/upload$/,
handler: () => { handler: () => {
const id = files.length + 1 const id = files.length + 1
const rand = Math.random().toString(36).slice(2, 10) const rand = Math.random().toString(36).slice(2, 10)
@@ -251,7 +251,7 @@ export const mockRules: MockRule[] = [
}, },
{ {
method: 'DELETE', method: 'DELETE',
pattern: /^\/api\/v1\/api\/admin\/files\/(\d+)$/, pattern: /^\/api\/api\/admin\/files\/(\d+)$/,
handler: (ctx) => { handler: (ctx) => {
const id = toNumber(ctx.params[0]) const id = toNumber(ctx.params[0])
const index = files.findIndex((item) => item.id === id) const index = files.findIndex((item) => item.id === id)
@@ -262,7 +262,7 @@ export const mockRules: MockRule[] = [
{ {
// 统计每个小程序的用户数(有真实用户的取真实值,其余返回稳定模拟值) // 统计每个小程序的用户数(有真实用户的取真实值,其余返回稳定模拟值)
method: 'GET', method: 'GET',
pattern: /^\/api\/v1\/api\/admin\/dashboard\/user-count-by-miniapp$/, pattern: /^\/api\/api\/admin\/dashboard\/user-count-by-miniapp$/,
alwaysMock: true, alwaysMock: true,
handler: () => handler: () =>
miniApps.map((app) => { miniApps.map((app) => {
@@ -276,7 +276,7 @@ export const mockRules: MockRule[] = [
}, },
{ {
method: 'GET', method: 'GET',
pattern: /^\/api\/v1\/api\/admin\/monitor\/server-info$/, pattern: /^\/api\/api\/admin\/monitor\/server-info$/,
alwaysMock: true, alwaysMock: true,
handler: () => ({ handler: () => ({
hostname: 'portal-server-01', hostname: 'portal-server-01',
@@ -293,7 +293,7 @@ export const mockRules: MockRule[] = [
{ {
// 实时状态:每次请求生成浮动指标,模拟监控采集中 // 实时状态:每次请求生成浮动指标,模拟监控采集中
method: 'GET', method: 'GET',
pattern: /^\/api\/v1\/api\/admin\/monitor\/server-status$/, pattern: /^\/api\/api\/admin\/monitor\/server-status$/,
alwaysMock: true, alwaysMock: true,
handler: () => { handler: () => {
const cpuUsage = Math.round((20 + Math.random() * 60) * 10) / 10 const cpuUsage = Math.round((20 + Math.random() * 60) * 10) / 10
+1 -1
View File
@@ -1,7 +1,7 @@
import type { Plugin } from 'vite' import type { Plugin } from 'vite'
import { mockRules, type MockContext } from './index' import { mockRules, type MockContext } from './index'
const MOCK_PREFIX = '/api/v1' const MOCK_PREFIX = '/api'
function readBody(req: NodeJS.ReadableStream): Promise<string> { function readBody(req: NodeJS.ReadableStream): Promise<string> {
return new Promise((resolve) => { return new Promise((resolve) => {
+1 -1
View File
@@ -3,7 +3,7 @@ import type { LoginForm, LoginResult, UserInfo } from '@/types/auth'
import type { RouteVO } from '@/types/router' import type { RouteVO } from '@/types/router'
import { staticMenuRoutes } from '@/config/static-routes' import { staticMenuRoutes } from '@/config/static-routes'
// 叠加在 VITE_APP_BASE_API(/api/v1) 之上,经 Vite proxy 剥离 /api/v1 后命中后端 /api/admin // 请求直接以 /api/admin 发起,由 Vite proxy 的 /api 规则转发到后端
const ADMIN_BASE = '/api/admin' const ADMIN_BASE = '/api/admin'
export const AuthAPI = { export const AuthAPI = {
+1 -1
View File
@@ -2,7 +2,7 @@ import request from '@/utils/request'
import type { PageResult } from '@/types/common' import type { PageResult } from '@/types/common'
import type { FileQuery, FileUploadVO, FileVO } from '@/types/file' import type { FileQuery, FileUploadVO, FileVO } from '@/types/file'
// 叠加在 VITE_APP_BASE_API(/api/v1) 之上,经 Vite proxy 剥离 /api/v1 后命中后端 /api/admin/files // 请求直接以 /api/admin/files 发起,由 Vite proxy 的 /api 规则转发到后端
const BASE_URL = '/api/admin/files' const BASE_URL = '/api/admin/files'
export const FileAPI = { export const FileAPI = {
+2 -2
View File
@@ -2,8 +2,8 @@ import request from '@/utils/request'
import type { PageResult } from '@/types/common' import type { PageResult } from '@/types/common'
import type { MiniAppForm, MiniAppQuery, MiniAppStatus, MiniAppVO } from '@/types/miniapp' import type { MiniAppForm, MiniAppQuery, MiniAppStatus, MiniAppVO } from '@/types/miniapp'
// 前端基础路径 VITE_APP_BASE_API 为 /api/v1,经 Vite proxy 整体剥离后转发到 Go 后端; // 请求直接以 /api/admin/miniapps 发起,由 Vite proxy 的 /api 规则转发到 Go 后端;
// 此处拼接 /api/admin/miniapps,剥离 /api/v1 后即可精确命中后端 /api/admin/miniapps // 精确命中后端 /api/admin/miniapps
const BASE_URL = '/api/admin/miniapps' const BASE_URL = '/api/admin/miniapps'
export const MiniAppAPI = { export const MiniAppAPI = {
+1 -1
View File
@@ -2,7 +2,7 @@ import request from '@/utils/request'
import type { PageResult } from '@/types/common' import type { PageResult } from '@/types/common'
import type { UserForm, UserQuery, UserStatus, UserVO } from '@/types/system/user' import type { UserForm, UserQuery, UserStatus, UserVO } from '@/types/system/user'
// 叠加在 VITE_APP_BASE_API(/api/v1) 上,经 Vite proxy 剥离 /api/v1 后命中后端 /api/admin/users // 请求直接以 /api/admin/users 发起,由 Vite proxy 的 /api 规则转发到后端
const BASE_URL = '/api/admin/users' const BASE_URL = '/api/admin/users'
export const UserAPI = { export const UserAPI = {
+4 -7
View File
@@ -8,9 +8,6 @@
defineOptions({ name: 'File' }) defineOptions({ name: 'File' })
/** 经 Vite proxy 拼接前缀,使本地静态访问也走后端代理(避免硬编码域名/端口) */
const previewUrl = (url: string) => `${import.meta.env.VITE_APP_BASE_API}${url}`
const loading = ref(false) const loading = ref(false)
const total = ref(0) const total = ref(0)
const list = ref<FileVO[]>([]) const list = ref<FileVO[]>([])
@@ -79,12 +76,12 @@
} }
function handlePreview(row: FileVO) { function handlePreview(row: FileVO) {
window.open(previewUrl(row.url), '_blank') window.open(row.url, '_blank')
} }
function handleDownload(row: FileVO) { function handleDownload(row: FileVO) {
const link = document.createElement('a') const link = document.createElement('a')
link.href = previewUrl(row.url) link.href = row.url
link.download = row.origin_name || row.filename link.download = row.origin_name || row.filename
link.click() link.click()
} }
@@ -163,8 +160,8 @@
<template #default="{ row }"> <template #default="{ row }">
<el-image <el-image
v-if="isImage(row as FileVO)" v-if="isImage(row as FileVO)"
:src="previewUrl((row as FileVO).url)" :src="(row as FileVO).url"
:preview-src-list="[previewUrl((row as FileVO).url)]" :preview-src-list="[(row as FileVO).url]"
:initial-index="0" :initial-index="0"
fit="cover" fit="cover"
class="thumb" class="thumb"
+7 -2
View File
@@ -43,10 +43,15 @@ export default defineConfig(({ mode }) => {
port: Number(env.VITE_APP_PORT) || 3000, port: Number(env.VITE_APP_PORT) || 3000,
open: true, open: true,
proxy: { proxy: {
[env.VITE_APP_BASE_API]: { // 接口:请求以 /api/... 发起,直接转发到后端(后端以 /api 提供服务,无需重写路径)
'/api': {
target: env.VITE_APP_API_URL,
changeOrigin: true,
},
// 文件静态资源由后端 r.Static 提供,dev 下直连后端
'/files': {
target: env.VITE_APP_API_URL, target: env.VITE_APP_API_URL,
changeOrigin: true, changeOrigin: true,
rewrite: (path: string) => path.replace(new RegExp(`^${env.VITE_APP_BASE_API}`), ''),
}, },
}, },
}, },