build(frontend): 添加不同环境的环境变量配置文件

添加开发、预发和生产环境的环境变量配置文件,包含端口、代理路径和API基地址等配置项
This commit is contained in:
2025-08-28 20:59:00 +08:00
parent 410f54a65e
commit 7c7adfe71a
11 changed files with 74 additions and 23 deletions

View File

@ -1,7 +1,7 @@
RUST_LOG=info,udmin=debug RUST_LOG=info,udmin=debug
APP_ENV=development APP_ENV=development
APP_HOST=0.0.0.0 APP_HOST=0.0.0.0
APP_PORT=8080 APP_PORT=9898
DB_URL=mysql://root:123456@127.0.0.1:3306/udmin DB_URL=mysql://root:123456@127.0.0.1:3306/udmin
JWT_SECRET=dev_secret_change_me JWT_SECRET=dev_secret_change_me
JWT_ISS=udmin JWT_ISS=udmin

14
frontend/.env.development Normal file
View File

@ -0,0 +1,14 @@
# port 端口号
VITE_PORT = 8888
# 浏览器自动打开
VITE_OPEN = true
# 本地环境
ENV = 'development'
# ADMIN 服务地址(开发代理目标)
VITE_ADMIN_PROXY_PATH = http://127.0.0.1:9898
# API 基地址(留空则走相对 /api经由开发代理转发
VITE_API_BASE =

14
frontend/.env.production Normal file
View File

@ -0,0 +1,14 @@
# port 端口号(生产构建无效,仅用于本地预览时生效)
VITE_PORT = 8888
# 浏览器自动打开(生产构建无效)
VITE_OPEN = false
# 生产环境
ENV = 'production'
# ADMIN 服务地址(生产一般同域反代,留空)
VITE_ADMIN_PROXY_PATH =
# API 基地址(推荐同域反代,留空则 axios 使用 /api如需直连后端填写例如 https://api.example.com
VITE_API_BASE =

14
frontend/.env.staging Normal file
View File

@ -0,0 +1,14 @@
# port 端口号staging 本地预览)
VITE_PORT = 8888
# 浏览器自动打开
VITE_OPEN = true
# 预发环境
ENV = 'staging'
# 预发 ADMIN 服务地址(仅本地预览代理使用)
VITE_ADMIN_PROXY_PATH = http://127.0.0.1:9898
# 预发 API 基地址(可填你的预发后端域名,例如 https://staging-api.example.com若留空则使用 /api
VITE_API_BASE =

View File

@ -117,7 +117,7 @@ export default function Logs() {
<PageHeader items={["系统管理","日志管理"]} title="" /> <PageHeader items={["系统管理","日志管理"]} title="" />
<Form form={form} layout="inline" onFinish={() => fetchData(1, pageSize)} style={{ marginBottom: 12 }}> <Form form={form} layout="inline" onFinish={() => fetchData(1, pageSize)} style={{ marginBottom: 12 }}>
<Form.Item label="请求路径" name="path"> <Form.Item label="请求路径" name="path">
<Input placeholder="like /users" allowClear style={{ width: 260 }} /> <Input placeholder="like /users" allowClear style={{ width: 320 }} />
</Form.Item> </Form.Item>
<Form.Item label="发起时间" name="time"> <Form.Item label="发起时间" name="time">
<DatePicker.RangePicker showTime allowClear /> <DatePicker.RangePicker showTime allowClear />

View File

@ -448,7 +448,7 @@ export default function Menus(){
<Form form={searchForm} layout="inline" onFinish={(vals: any)=>{ const kw = String(vals?.keyword ?? '').trim(); setKeyword(kw); fetchMenus(kw) }} style={{ marginBottom: 12 }}> <Form form={searchForm} layout="inline" onFinish={(vals: any)=>{ const kw = String(vals?.keyword ?? '').trim(); setKeyword(kw); fetchMenus(kw) }} style={{ marginBottom: 12 }}>
<Form.Item name="keyword"> <Form.Item name="keyword">
<Input allowClear placeholder="搜索菜单名称/路径/权限" style={{ width: 360 }} /> <Input allowClear placeholder="搜索菜单名称/路径/权限" style={{ width: 320 }} />
</Form.Item> </Form.Item>
<Form.Item> <Form.Item>
<Space> <Space>

View File

@ -346,9 +346,9 @@ export default function Users(){
columns={columns} columns={columns}
pagination={{ current: page, pageSize, total, showSizeChanger: true, onChange: (p: number, ps?: number) => fetchUsers(p, ps ?? pageSize, keyword) }} pagination={{ current: page, pageSize, total, showSizeChanger: true, onChange: (p: number, ps?: number) => fetchUsers(p, ps ?? pageSize, keyword) }}
/> />
<Typography.Paragraph type="secondary" style={{ marginTop: 12 }}> {/* <Typography.Paragraph type="secondary" style={{ marginTop: 12 }}>
提示:此页面已支持分页、创建、编辑与重置密码。 提示:此页面已支持分页、创建、编辑与重置密码。
</Typography.Paragraph> </Typography.Paragraph> */}
<Modal title="新增用户" open={createOpen} onOk={handleCreate} onCancel={() => setCreateOpen(false)} okText="创建" width={840}> <Modal title="新增用户" open={createOpen} onOk={handleCreate} onCancel={() => setCreateOpen(false)} okText="创建" width={840}>
<Form form={form} layout="horizontal" labelCol={{ span: 2 }} wrapperCol={{ span: 22 }} labelAlign="right"> <Form form={form} layout="horizontal" labelCol={{ span: 2 }} wrapperCol={{ span: 22 }} labelAlign="right">

View File

@ -7,11 +7,9 @@ export type ApiResp<T> = { code: number; message?: string; data?: T }
// 在请求配置上携带一次性重试标记 // 在请求配置上携带一次性重试标记
type RetryConfig = InternalAxiosRequestConfig & { _retry?: boolean } type RetryConfig = InternalAxiosRequestConfig & { _retry?: boolean }
// 使用 Vite 的环境变量类型 // 从 .env 读取 VITE_API_BASE若未配置则回退到相对路径 /api
const isDev = import.meta.env.DEV const configuredBase = (import.meta.env?.VITE_API_BASE as string | undefined)?.trim() || ''
const configuredBase = import.meta.env?.VITE_API_BASE || '' const api: AxiosInstance = axios.create({ baseURL: configuredBase ? `${configuredBase}/api` : '/api', withCredentials: true })
const baseURL = isDev ? '' : configuredBase
const api: AxiosInstance = axios.create({ baseURL: baseURL ? `${baseURL}/api` : '/api', withCredentials: true })
let isRefreshing = false let isRefreshing = false
let pendingQueue: { resolve: () => void; reject: (e: unknown) => void; config: RetryConfig }[] = [] let pendingQueue: { resolve: () => void; reject: (e: unknown) => void; config: RetryConfig }[] = []

View File

@ -6,5 +6,7 @@
"moduleResolution": "Bundler", "moduleResolution": "Bundler",
"allowSyntheticDefaultImports": true "allowSyntheticDefaultImports": true
}, },
"include": ["vite.config.ts"] "include": [
"vite.config.ts"
]
} }

View File

@ -1 +1 @@
{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/layouts/mainlayout.tsx","./src/pages/dashboard.tsx","./src/pages/departments.tsx","./src/pages/login.tsx","./src/pages/logs.tsx","./src/pages/menus.tsx","./src/pages/permissions.tsx","./src/pages/roles.tsx","./src/pages/users.tsx","./src/utils/axios.ts","./src/utils/datetime.ts","./src/utils/permission.tsx","./src/utils/token.ts"],"version":"5.9.2"} {"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/components/pageheader.tsx","./src/layouts/mainlayout.tsx","./src/pages/dashboard.tsx","./src/pages/departments.tsx","./src/pages/login.tsx","./src/pages/logs.tsx","./src/pages/menus.tsx","./src/pages/permissions.tsx","./src/pages/positions.tsx","./src/pages/roles.tsx","./src/pages/users.tsx","./src/utils/axios.ts","./src/utils/datetime.ts","./src/utils/permission.tsx","./src/utils/token.ts"],"version":"5.9.2"}

View File

@ -1,17 +1,26 @@
import { defineConfig } from 'vite' import { defineConfig, loadEnv } from 'vite'
import react from '@vitejs/plugin-react' import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/ // 单一配置文件 + 多环境 .env
export default defineConfig({ // - .env.development / .env.production / .env.staging 中配置变量
// - 通过 loadEnv 读取并应用到开发服务器与代理
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, '.', '')
const port = Number(env.VITE_PORT || 5173)
const open = String(env.VITE_OPEN ?? 'true').toLowerCase() === 'true' || env.VITE_OPEN === '1'
const proxyTarget = env.VITE_ADMIN_PROXY_PATH || 'http://127.0.0.1:8080'
return {
plugins: [react()], plugins: [react()],
server: { server: {
port: 5173, port,
open: true, open,
proxy: { proxy: {
'/api': { '/api': {
target: 'http://127.0.0.1:8080', target: proxyTarget,
changeOrigin: true changeOrigin: true
} }
} }
} }
}
}) })